Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / resources / chromeos / wallpaper_manager / js / wallpaper_images_grid.js
blobb2b2a9c37c894c79d6248ec2520f7be0555d58b6
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 cr.define('wallpapers', function() {
6   /** @const */ var ArrayDataModel = cr.ui.ArrayDataModel;
7   /** @const */ var Grid = cr.ui.Grid;
8   /** @const */ var GridItem = cr.ui.GridItem;
9   /** @const */ var GridSelectionController = cr.ui.GridSelectionController;
10   /** @const */ var ListSingleSelectionModel = cr.ui.ListSingleSelectionModel;
11   /** @const */ var ThumbnailSuffix = '_thumbnail.png';
13   /**
14    * Creates a new wallpaper thumbnails grid item.
15    * @param {{baseURL: string, layout: string, source: string,
16    *          availableOffline: boolean, opt_dynamicURL: string,
17    *          opt_author: string, opt_authorWebsite: string}}
18    *     wallpaperInfo Wallpaper data item in WallpaperThumbnailsGrid's data
19    *     model.
20    * @constructor
21    * @extends {cr.ui.GridItem}
22    */
23   function WallpaperThumbnailsGridItem(wallpaperInfo) {
24     var el = new GridItem(wallpaperInfo);
25     el.__proto__ = WallpaperThumbnailsGridItem.prototype;
26     return el;
27   }
29   WallpaperThumbnailsGridItem.prototype = {
30     __proto__: GridItem.prototype,
32     /** @override */
33     decorate: function() {
34       GridItem.prototype.decorate.call(this);
35       // Removes garbage created by GridItem.
36       this.innerText = '';
37       var imageEl = cr.doc.createElement('img');
38       imageEl.classList.add('thumbnail');
39       cr.defineProperty(imageEl, 'offline', cr.PropertyKind.BOOL_ATTR);
40       imageEl.offline = this.dataItem.availableOffline;
41       this.appendChild(imageEl);
42       var self = this;
44       switch (this.dataItem.source) {
45         case Constants.WallpaperSourceEnum.AddNew:
46           this.id = 'add-new';
47           this.addEventListener('click', function(e) {
48             $('wallpaper-selection-container').hidden = false;
49           });
50           break;
51         case Constants.WallpaperSourceEnum.Custom:
52           var errorHandler = function(e) {
53             console.error('Can not access file system.');
54           };
55           var wallpaperDirectories = WallpaperDirectories.getInstance();
56           var getThumbnail = function(fileName) {
57             var setURL = function(fileEntry) {
58               imageEl.src = fileEntry.toURL();
59             };
60             var fallback = function() {
61               wallpaperDirectories.getDirectory(WallpaperDirNameEnum.ORIGINAL,
62                                           function(dirEntry) {
63                 dirEntry.getFile(fileName, {create: false}, setURL,
64                                  errorHandler);
65               }, errorHandler);
66             };
67             var success = function(dirEntry) {
68               dirEntry.getFile(fileName, {create: false}, setURL, fallback);
69             };
70             wallpaperDirectories.getDirectory(WallpaperDirNameEnum.THUMBNAIL,
71                                               success,
72                                               errorHandler);
73           }
74           getThumbnail(self.dataItem.baseURL);
75           break;
76         case Constants.WallpaperSourceEnum.OEM:
77         case Constants.WallpaperSourceEnum.Online:
78           chrome.wallpaperPrivate.getThumbnail(this.dataItem.baseURL,
79                                                this.dataItem.source,
80                                                function(data) {
81             if (data) {
82               var blob = new Blob([new Int8Array(data)],
83                                   {'type': 'image\/png'});
84               imageEl.src = window.URL.createObjectURL(blob);
85               imageEl.addEventListener('load', function(e) {
86                 window.URL.revokeObjectURL(this.src);
87               });
88             } else if (self.dataItem.source ==
89                        Constants.WallpaperSourceEnum.Online) {
90               var xhr = new XMLHttpRequest();
91               xhr.open('GET', self.dataItem.baseURL + ThumbnailSuffix, true);
92               xhr.responseType = 'arraybuffer';
93               xhr.send(null);
94               xhr.addEventListener('load', function(e) {
95                 if (xhr.status === 200) {
96                   chrome.wallpaperPrivate.saveThumbnail(self.dataItem.baseURL,
97                                                         xhr.response);
98                   var blob = new Blob([new Int8Array(xhr.response)],
99                                       {'type' : 'image\/png'});
100                   imageEl.src = window.URL.createObjectURL(blob);
101                   // TODO(bshe): We currently use empty div to reserve space for
102                   // thumbnail. Use a placeholder like "loading" image may
103                   // better.
104                   imageEl.addEventListener('load', function(e) {
105                     window.URL.revokeObjectURL(this.src);
106                   });
107                 }
108               });
109             }
110           });
111           break;
112         default:
113           console.error('Unsupported image source.');
114       }
115     },
116   };
118   /**
119    * Creates a selection controller that wraps selection on grid ends
120    * and translates Enter presses into 'activate' events.
121    * @param {cr.ui.ListSelectionModel} selectionModel The selection model to
122    *     interact with.
123    * @param {cr.ui.Grid} grid The grid to interact with.
124    * @constructor
125    * @extends {cr.ui.GridSelectionController}
126    */
127   function WallpaperThumbnailsGridSelectionController(selectionModel, grid) {
128     GridSelectionController.call(this, selectionModel, grid);
129   }
131   WallpaperThumbnailsGridSelectionController.prototype = {
132     __proto__: GridSelectionController.prototype,
134     /** @override */
135     getIndexBefore: function(index) {
136       var result =
137           GridSelectionController.prototype.getIndexBefore.call(this, index);
138       return result == -1 ? this.getLastIndex() : result;
139     },
141     /** @override */
142     getIndexAfter: function(index) {
143       var result =
144           GridSelectionController.prototype.getIndexAfter.call(this, index);
145       return result == -1 ? this.getFirstIndex() : result;
146     },
148     /** @override */
149     handleKeyDown: function(e) {
150       if (e.keyIdentifier == 'Enter')
151         cr.dispatchSimpleEvent(this.grid_, 'activate');
152       else
153         GridSelectionController.prototype.handleKeyDown.call(this, e);
154     },
155   };
157   /**
158    * Creates a new user images grid element.
159    * @param {Object=} opt_propertyBag Optional properties.
160    * @constructor
161    * @extends {cr.ui.Grid}
162    */
163   var WallpaperThumbnailsGrid = cr.ui.define('grid');
165   WallpaperThumbnailsGrid.prototype = {
166     __proto__: Grid.prototype,
168     /**
169      * The checkbox element.
170      */
171     checkmark_: undefined,
173     /**
174      * The item in data model which should have a checkmark.
175      * @type {{baseURL: string, dynamicURL: string, layout: string,
176      *         author: string, authorWebsite: string,
177      *         availableOffline: boolean}}
178      *     wallpaperInfo The information of the wallpaper to be set active.
179      */
180     activeItem_: undefined,
181     set activeItem(activeItem) {
182       if (this.activeItem_ != activeItem) {
183         this.activeItem_ = activeItem;
184         this.updateActiveThumb_();
185       }
186     },
188     /** @override */
189     createSelectionController: function(sm) {
190       return new WallpaperThumbnailsGridSelectionController(sm, this);
191     },
193     /** @override */
194     decorate: function() {
195       Grid.prototype.decorate.call(this);
196       // checkmark_ needs to be initialized before set data model. Otherwise, we
197       // may try to access checkmark before initialization in
198       // updateActiveThumb_().
199       this.checkmark_ = cr.doc.createElement('div');
200       this.checkmark_.classList.add('check');
201       this.dataModel = new ArrayDataModel([]);
202       this.itemConstructor = WallpaperThumbnailsGridItem;
203       this.selectionModel = new ListSingleSelectionModel();
204       this.inProgramSelection_ = false;
205     },
207     /**
208      * Should only be queried from the 'change' event listener, true if the
209      * change event was triggered by a programmatical selection change.
210      * @type {boolean}
211      */
212     get inProgramSelection() {
213       return this.inProgramSelection_;
214     },
216     /**
217      * Set index to the image selected.
218      * @type {number} index The index of selected image.
219      */
220     set selectedItemIndex(index) {
221       this.inProgramSelection_ = true;
222       this.selectionModel.selectedIndex = index;
223       this.inProgramSelection_ = false;
224     },
226     /**
227      * The selected item.
228      * @type {!Object} Wallpaper information inserted into the data model.
229      */
230     get selectedItem() {
231       var index = this.selectionModel.selectedIndex;
232       return index != -1 ? this.dataModel.item(index) : null;
233     },
234     set selectedItem(selectedItem) {
235       var index = this.dataModel.indexOf(selectedItem);
236       this.inProgramSelection_ = true;
237       this.selectionModel.leadIndex = index;
238       this.selectionModel.selectedIndex = index;
239       this.inProgramSelection_ = false;
240     },
242     /**
243      * Forces re-display, size re-calculation and focuses grid.
244      */
245     updateAndFocus: function() {
246       // Recalculate the measured item size.
247       this.measured_ = null;
248       this.columns = 0;
249       this.redraw();
250       this.focus();
251     },
253     /**
254      * Shows a checkmark on the active thumbnail and clears previous active one
255      * if any. Note if wallpaper was not set successfully, checkmark should not
256      * show on that thumbnail.
257      */
258     updateActiveThumb_: function() {
259       var selectedGridItem = this.getListItem(this.activeItem_);
260       if (this.checkmark_.parentNode &&
261           this.checkmark_.parentNode == selectedGridItem) {
262         return;
263       }
265       // Clears previous checkmark.
266       if (this.checkmark_.parentNode)
267         this.checkmark_.parentNode.removeChild(this.checkmark_);
269       if (!selectedGridItem)
270         return;
271       selectedGridItem.appendChild(this.checkmark_);
272     },
274     /**
275      * Redraws the viewport.
276      */
277     redraw: function() {
278       Grid.prototype.redraw.call(this);
279       // The active thumbnail maybe deleted in the above redraw(). Sets it again
280       // to make sure checkmark shows correctly.
281       this.updateActiveThumb_();
282     }
283   };
285   return {
286     WallpaperThumbnailsGrid: WallpaperThumbnailsGrid
287   };