Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3960)

Unified Diff: chrome/browser/resources/file_manager/js/photo/ribbon.js

Issue 10829421: First cut of the updated Photo Editor UI (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Small fix Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/resources/file_manager/js/photo/ribbon.js
diff --git a/chrome/browser/resources/file_manager/js/photo/ribbon.js b/chrome/browser/resources/file_manager/js/photo/ribbon.js
index 5e5b88b8d6a199fff1ecd5c0f4726aa59d7c02c9..aeda8bceb2aeaab49b168b5fe08f51b7bd755b4c 100644
--- a/chrome/browser/resources/file_manager/js/photo/ribbon.js
+++ b/chrome/browser/resources/file_manager/js/photo/ribbon.js
@@ -7,13 +7,14 @@
*
* @param {Document} document Document.
* @param {MetadataCache} metadataCache MetadataCache instance.
- * @param {function(number)} selectFunc Selection function.
+ * @param {cr.ui.ArrayDataModel} dataModel Data model.
+ * @param {cr.ui.ListSelectionModel} selectionModel Selection model.
* @return {Element} Ribbon element.
* @constructor
*/
-function Ribbon(document, metadataCache, selectFunc) {
+function Ribbon(document, metadataCache, dataModel, selectionModel) {
var self = document.createElement('div');
- Ribbon.decorate(self, metadataCache, selectFunc);
+ Ribbon.decorate(self, metadataCache, dataModel, selectionModel);
return self;
}
@@ -27,18 +28,17 @@ Ribbon.prototype.__proto__ = HTMLDivElement.prototype;
*
* @param {Ribbon} self Self pointer.
* @param {MetadataCache} metadataCache MetadataCache instance.
- * @param {function(number)} selectFunc Selection function.
+ * @param {cr.ui.ArrayDataModel} dataModel Data model.
+ * @param {cr.ui.ListSelectionModel} selectionModel Selection model.
*/
-Ribbon.decorate = function(self, metadataCache, selectFunc) {
+Ribbon.decorate = function(self, metadataCache, dataModel, selectionModel) {
self.__proto__ = Ribbon.prototype;
self.metadataCache_ = metadataCache;
- self.selectFunc_ = selectFunc;
+ self.dataModel_ = dataModel;
+ self.selectionModel_ = selectionModel;
self.className = 'ribbon';
- self.firstVisibleIndex_ = 0;
- self.lastVisibleIndex_ = -1; // Zero thumbnails
-
self.renderCache_ = {};
};
@@ -49,20 +49,104 @@ Ribbon.decorate = function(self, metadataCache, selectFunc) {
Ribbon.ITEMS_COUNT = 5;
/**
- * Update the ribbon.
- *
- * @param {Array.<Gallery.Item>} items Array of items.
- * @param {number} selectedIndex Selected index.
+ * Enable the ribbon.
+ */
+Ribbon.prototype.enable = function() {
+ this.firstVisibleIndex_ = 0;
+ this.lastVisibleIndex_ = -1; // Zero thumbnails
+
+ this.onSpliceBound_ = this.onSplice_.bind(this);
+ this.dataModel_.addEventListener('splice', this.onSpliceBound_);
+
+ this.onSelectionBound_ = this.onSelection_.bind(this);
+ this.selectionModel_.addEventListener('change', this.onSelectionBound_);
+
+ this.onSelection_();
+};
+
+/**
+ * Disable ribbon.
+ */
+Ribbon.prototype.disable = function() {
+ this.dataModel_.removeEventListener('splice', this.onSpliceBound_);
+ this.selectionModel_.removeEventListener('change', this.onSelectionBound_);
+
+ this.removeVanishing_();
+ this.textContent = '';
+};
+
+/**
+ * Data model splice handler.
+ * @param {Event} event Event.
+ * @private
*/
-Ribbon.prototype.update = function(items, selectedIndex) {
- // Never show a single thumbnail.
- if (items.length == 1)
+Ribbon.prototype.onSplice_ = function(event) {
+ if (event.removed.length == 0)
+ return;
+
+ if (event.removed.length > 1) {
+ console.error('Cannot remove multiple items');
return;
+ }
+
+ var removed = this.renderCache_[event.removed[0].getUrl()];
+ if (!removed || !removed.parentNode || !removed.hasAttribute('selected')) {
+ console.error('Can only remove the selected item');
+ return;
+ }
+
+ var persistentNodes = this.querySelectorAll('ribbon-image:not([vanishing])');
dgozman 2012/08/27 15:07:43 ribbon-image is a class, right? Forgot the dot.
Vladislav Kaznacheev 2012/08/30 09:58:45 Done.
+ if (this.lastVisibleIndex_ < this.dataModel_.length) { // Not at the end.
+ var lastNode = persistentNodes[persistentNodes.length - 1];
+ if (lastNode.nextSibling) {
+ // Pull back a vanishing node from the right.
+ lastNode.nextSibling.removeAttribute('vanishing');
+ } else {
+ // Push a new item at the right end.
+ this.appendChild(this.renderThumbnail_(this.lastVisibleIndex_));
+ }
+ } else {
+ // No items to the right, move the window to the left.
+ this.lastVisibleIndex_--;
+ if (this.firstVisibleIndex_) {
+ this.firstVisibleIndex_--;
+ var firstNode = persistentNodes[0];
+ if (firstNode.previousSibling) {
+ // Pull back a vanishing node from the left.
+ firstNode.previousSibling.removeAttribute('vanishing');
+ } else {
+ // Push a new item at the left end.
+ var newThumbnail = this.renderThumbnail_(this.firstVisibleIndex_);
+ newThumbnail.style.marginLeft = -(this.clientHeight - 2) + 'px';
+ this.insertBefore(newThumbnail, this.firstChild);
+ setTimeout(function() {
+ newThumbnail.style.marginLeft = '0';
+ }, 0);
+ }
+ }
+ }
+
+ removed.removeAttribute('selected');
+ removed.setAttribute('vanishing', 'smooth');
+ this.scheduleRemove_();
+};
+
+/**
+ * Selection change handler.
+ * @private
+ */
+Ribbon.prototype.onSelection_ = function() {
+ var indexes = this.selectionModel_.selectedIndexes;
+ if (indexes.length == 0)
+ return; // Ignore temporary empty selection.
+ var selectedIndex = indexes[0];
+
+ var length = this.dataModel_.length;
// TODO(dgozman): use margin instead of 2 here.
var itemWidth = this.clientHeight - 2;
var fullItems = Ribbon.ITEMS_COUNT;
- fullItems = Math.min(fullItems, items.length);
+ fullItems = Math.min(fullItems, length);
var right = Math.floor((fullItems - 1) / 2);
var fullWidth = fullItems * itemWidth;
@@ -70,7 +154,7 @@ Ribbon.prototype.update = function(items, selectedIndex) {
var lastIndex = selectedIndex + right;
lastIndex = Math.max(lastIndex, fullItems - 1);
- lastIndex = Math.min(lastIndex, items.length - 1);
+ lastIndex = Math.min(lastIndex, length - 1);
var firstIndex = lastIndex - fullItems + 1;
if (this.firstVisibleIndex_ != firstIndex ||
@@ -81,23 +165,31 @@ Ribbon.prototype.update = function(items, selectedIndex) {
this.lastVisibleIndex_ = lastIndex;
}
+ this.removeVanishing_();
+
this.textContent = '';
var startIndex = Math.min(firstIndex, this.firstVisibleIndex_);
- var toRemove = [];
// All the items except the first one treated equally.
for (var index = startIndex + 1;
index <= Math.max(lastIndex, this.lastVisibleIndex_);
++index) {
- var box = this.renderThumbnail_(index, items);
+ // Only add items that are in either old or the new viewport.
+ if (this.lastVisibleIndex_ < index && index < firstIndex ||
+ lastIndex < index && index < this.firstVisibleIndex_)
+ continue;
+ var box = this.renderThumbnail_(index);
box.style.marginLeft = '0';
this.appendChild(box);
if (index < firstIndex || index > lastIndex) {
- toRemove.push(box);
+ // If the node is not in the new viewport we only need it while
+ // the animation is playing out.
+ box.setAttribute('vanishing', 'slide');
}
}
- var margin = itemWidth * Math.abs(firstIndex - this.firstVisibleIndex_);
- var startBox = this.renderThumbnail_(startIndex, items);
+ var slideCount = this.childNodes.length + 1 - Ribbon.ITEMS_COUNT;
+ var margin = itemWidth * slideCount;
+ var startBox = this.renderThumbnail_(startIndex);
if (startIndex == firstIndex) {
// Sliding to the right.
startBox.style.marginLeft = -margin + 'px';
@@ -111,7 +203,7 @@ Ribbon.prototype.update = function(items, selectedIndex) {
} else {
// Sliding to the left. Start item will become invisible and should be
// removed afterwards.
- toRemove.push(startBox);
+ startBox.setAttribute('vanishing', 'slide');
startBox.style.marginLeft = '0';
if (this.firstChild)
this.insertBefore(startBox, this.firstChild);
@@ -126,41 +218,62 @@ Ribbon.prototype.update = function(items, selectedIndex) {
firstIndex > 0 && selectedIndex != firstIndex);
ImageUtil.setClass(this, 'fade-right',
- lastIndex < items.length - 1 && selectedIndex != lastIndex);
+ lastIndex < length - 1 && selectedIndex != lastIndex);
this.firstVisibleIndex_ = firstIndex;
this.lastVisibleIndex_ = lastIndex;
- if (this.removeTimeout_)
- clearTimeout(this.removeTimeout_);
-
- this.removeTimeout_ = setTimeout(function() {
- this.removeTimeout_ = null;
- for (var i = 0; i < toRemove.length; i++) {
- var box = toRemove[i];
- if (box.parentNode == this)
- this.removeChild(box);
- }
- }.bind(this), 200);
+ this.scheduleRemove_();
}
var oldSelected = this.querySelector('[selected]');
if (oldSelected) oldSelected.removeAttribute('selected');
- var newSelected = this.getThumbnail_(selectedIndex);
+ var newSelected =
+ this.renderCache_[this.dataModel_.item(selectedIndex).getUrl()];
if (newSelected) newSelected.setAttribute('selected', true);
};
/**
+ * Schedule the removal of thumbnails marked as vanishing.
+ * @private
+ */
+Ribbon.prototype.scheduleRemove_ = function() {
+ if (this.removeTimeout_)
+ clearTimeout(this.removeTimeout_);
+
+ this.removeTimeout_ = setTimeout(function() {
+ this.removeTimeout_ = null;
+ this.removeVanishing_();
+ }.bind(this), 200);
+};
+
+/**
+ * Remove all thumbnails marked as vanishing.
+ * @private
+ */
+Ribbon.prototype.removeVanishing_ = function() {
+ if (this.removeTimeout_) {
+ clearTimeout(this.removeTimeout_);
+ this.removeTimeout_ = 0;
+ }
+ var vanishingNodes = this.querySelectorAll('[vanishing]');
+ for (var i = 0; i != vanishingNodes.length; i++) {
+ vanishingNodes[i].removeAttribute('vanishing');
+ this.removeChild(vanishingNodes[i]);
+ }
+};
+
+/**
* Create a DOM element for a thumbnail.
*
* @param {number} index Item index.
- * @param {Array.<Gallery.Item>} items Items array.
* @return {Element} Newly created element.
* @private
*/
-Ribbon.prototype.renderThumbnail_ = function(index, items) {
- var url = items[index].getUrl();
+Ribbon.prototype.renderThumbnail_ = function(index) {
+ var item = this.dataModel_.item(index);
+ var url = item.getUrl();
var cached = this.renderCache_[url];
if (cached)
@@ -168,14 +281,20 @@ Ribbon.prototype.renderThumbnail_ = function(index, items) {
var thumbnail = this.ownerDocument.createElement('div');
thumbnail.className = 'ribbon-image';
- thumbnail.addEventListener('click', this.selectFunc_.bind(null, index));
- thumbnail.setAttribute('index', index);
+ thumbnail.addEventListener('click', function() {
+ var index = this.dataModel_.slice().indexOf(item);
+ this.selectionModel_.unselectAll();
+ this.selectionModel_.setIndexSelected(index, true);
+ }.bind(this));
util.createChild(thumbnail, 'image-wrapper');
this.metadataCache_.get(url, Gallery.METADATA_TYPE,
this.setThumbnailImage_.bind(this, thumbnail, url));
+ // TODO: Implement LRU eviction.
+ // Never evict the thumbnails that are currently in the DOM because we rely
+ // on this cache to find them by URL.
this.renderCache_[url] = thumbnail;
return thumbnail;
};
@@ -196,26 +315,16 @@ Ribbon.prototype.setThumbnailImage_ = function(thumbnail, url, metadata) {
/**
* Update the thumbnail image.
*
- * @param {number} index Item index.
* @param {string} url Image url.
* @param {Object} metadata Metadata.
*/
-Ribbon.prototype.updateThumbnail = function(index, url, metadata) {
- var thumbnail = this.getThumbnail_(index) || this.renderCache_[url];
+Ribbon.prototype.updateThumbnail = function(url, metadata) {
+ var thumbnail = this.renderCache_[url];
if (thumbnail)
this.setThumbnailImage_(thumbnail, url, metadata);
};
/**
- * @param {number} index Thumbnail index.
- * @return {Element} Thumbnail element or null if not rendered.
- * @private
- */
-Ribbon.prototype.getThumbnail_ = function(index) {
- return this.querySelector('[index="' + index + '"]');
-};
-
-/**
* Update the thumbnail element cache.
*
* @param {string} oldUrl Old url.

Powered by Google App Engine
This is Rietveld 408576698