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

Side by Side Diff: resources/bookmark_manager/js/bmm/bookmarklist.js

Issue 853002: Updating the Chromium reference build for Windows. The continuous... (Closed) Base URL: svn://chrome-svn/chrome/trunk/deps/reference_builds/chrome/
Patch Set: Added the symbol files back. Created 10 years, 9 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « resources/bookmark_manager/js/bmm.js ('k') | resources/bookmark_manager/js/bmm/bookmarktree.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2010 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.
4
5
6 cr.define('bmm', function() {
7 // require cr.ui.define
8 // require cr.ui.limitInputWidth.
9 // require cr.ui.contextMenuHandler
10 const List = cr.ui.List;
11 const ListItem = cr.ui.ListItem;
12
13 var listLookup = {};
14
15 /**
16 * Removes all children and appends a new child.
17 * @param {!Node} parent The node to remove all children from.
18 * @param {!Node} newChild The new child to append.
19 */
20 function replaceAllChildren(parent, newChild) {
21 var n;
22 while ((n = parent.lastChild)) {
23 parent.removeChild(n);
24 }
25 parent.appendChild(newChild);
26 }
27
28 /**
29 * Creates a new bookmark list.
30 * @param {Object=} opt_propertyBag Optional properties.
31 * @constructor
32 * @extends {HTMLButtonElement}
33 */
34 var BookmarkList = cr.ui.define('list');
35
36 BookmarkList.prototype = {
37 __proto__: List.prototype,
38
39 decorate: function() {
40 List.prototype.decorate.call(this);
41 this.addEventListener('click', this.handleClick_);
42 },
43
44 parentId_: '',
45 get parentId() {
46 return this.parentId_;
47 },
48 set parentId(parentId) {
49 if (this.parentId_ == parentId)
50 return;
51
52 var oldParentId = this.parentId_;
53 this.parentId_ = parentId;
54
55 var callback = cr.bind(this.handleBookmarkCallback, this);
56
57 if (!parentId) {
58 callback([]);
59 } else if (/^q=/.test(parentId)) {
60 chrome.bookmarks.search(parentId.slice(2), callback);
61 } else if (parentId == 'recent') {
62 chrome.bookmarks.getRecent(50, callback);
63 } else {
64 chrome.bookmarks.getChildren(parentId, callback);
65 }
66
67 cr.dispatchPropertyChange(this, 'parentId', parentId, oldParentId);
68 },
69
70 handleBookmarkCallback: function(items) {
71 if (!items) {
72 // Failed to load bookmarks. Most likely due to the bookmark beeing
73 // removed.
74 cr.dispatchSimpleEvent(this, 'invalidId');
75 return;
76 }
77 // Remove all fields without recreating the object since other code
78 // references it.
79 for (var id in listLookup){
80 delete listLookup[id];
81 }
82 this.clear();
83 var showFolder = this.showFolder();
84 items.forEach(function(item) {
85 var li = createListItem(item, showFolder);
86 this.add(li);
87 }, this);
88 cr.dispatchSimpleEvent(this, 'load');
89 },
90
91 /**
92 * The bookmark node that the list is currently displaying. If we are curren tly
93 * displaying recent or search this returns null.
94 * @type {BookmarkTreeNode}
95 */
96 get bookmarkNode() {
97 if (this.isSearch() || this.isRecent())
98 return null;
99 var treeItem = bmm.treeLookup[this.parentId];
100 return treeItem && treeItem.bookmarkNode;
101 },
102
103 showFolder: function() {
104 return this.isSearch() || this.isRecent();
105 },
106
107 isSearch: function() {
108 return this.parentId_[0] == 'q';
109 },
110
111 isRecent: function() {
112 return this.parentId_ == 'recent';
113 },
114
115 /**
116 * Handles the clicks on the list so that we can check if the user clicked
117 * on a link or an folder.
118 * @private
119 * @param {Event} e The click event object.
120 */
121 handleClick_: function(e) {
122
123 var el = e.target;
124 if (el.href) {
125 var event = this.ownerDocument.createEvent('Event');
126 event.initEvent('urlClicked', true, false);
127 event.url = el.href;
128 event.kind = e.shiftKey ? 'window' : e.button == 1 ? 'tab' : 'self';
129 this.dispatchEvent(event);
130 }
131 },
132
133 // Bookmark model update callbacks
134 handleBookmarkChanged: function(id, changeInfo) {
135 var listItem = listLookup[id];
136 if (listItem) {
137 listItem.bookmarkNode.title = changeInfo.title;
138 if ('url' in changeInfo)
139 listItem.bookmarkNode.url = changeInfo['url'];
140 updateListItem(listItem, listItem.bookmarkNode, list.showFolder());
141 }
142 },
143
144 handleChildrenReordered: function(id, reorderInfo) {
145 if (this.parentId == id) {
146 var self = this;
147 reorderInfo.childIds.forEach(function(id, i) {
148 var li = listLookup[id]
149 self.addAt(li, i);
150 // At this point we do not read the index from the bookmark node so we
151 // do not need to update it.
152 li.bookmarkNode.index = i;
153 });
154 }
155 },
156
157 handleCreated: function(id, bookmarkNode) {
158 if (this.parentId == bookmarkNode.parentId) {
159 var li = createListItem(bookmarkNode, false);
160 this.addAt(li, bookmarkNode.index);
161 }
162 },
163
164 handleMoved: function(id, moveInfo) {
165 if (moveInfo.parentId == this.parentId ||
166 moveInfo.oldParentId == this.parentId) {
167
168 if (moveInfo.oldParentId == moveInfo.parentId) {
169 var listItem = listLookup[id];
170 if (listItem) {
171 this.remove(listItem);
172 this.addAt(listItem, moveInfo.index);
173 }
174 } else {
175 if (moveInfo.oldParentId == this.parentId) {
176 var listItem = listLookup[id];
177 if (listItem) {
178 this.remove(listItem);
179 delete listLookup[id];
180 }
181 }
182
183 if (moveInfo.parentId == list.parentId) {
184 var self = this;
185 chrome.bookmarks.get(id, function(bookmarkNodes) {
186 var bookmarkNode = bookmarkNodes[0];
187 var li = createListItem(bookmarkNode, false);
188 self.addAt(li, bookmarkNode.index);
189 });
190 }
191 }
192 }
193 },
194
195 handleRemoved: function(id, removeInfo) {
196 var listItem = listLookup[id];
197 if (listItem) {
198 this.remove(listItem);
199 delete listLookup[id];
200 }
201 }
202 };
203
204 /**
205 * The contextMenu property.
206 * @type {cr.ui.Menu}
207 */
208 cr.ui.contextMenuHandler.addContextMenuProperty(BookmarkList);
209
210 /**
211 * Creates a new bookmark list item.
212 * @param {Object=} opt_propertyBag Optional properties.
213 * @constructor
214 * @extends {cr.ui.ListItem}
215 */
216 var BookmarkListItem = cr.ui.define('li');
217
218 BookmarkListItem.prototype = {
219 __proto__: ListItem.prototype,
220 /**
221 * Whether the user is currently able to edit the list item.
222 * @type {boolean}
223 */
224 get editing() {
225 return this.hasAttribute('editing');
226 },
227 set editing(editing) {
228 var oldEditing = this.editing;
229 if (oldEditing == editing)
230 return;
231
232 var url = this.bookmarkNode.url;
233 var title = this.bookmarkNode.title;
234 var isFolder = bmm.isFolder(this.bookmarkNode);
235 var listItem = this;
236 var labelEl = this.firstChild;
237 var urlEl = this.querySelector('.url');
238 var labelInput, urlInput;
239
240 // Handles enter and escape which trigger reset and commit respectively.
241 function handleKeydown(e) {
242 // Make sure that the tree does not handle the key.
243 e.stopPropagation();
244
245 // Calling list.focus blurs the input which will stop editing the list
246 // item.
247 switch (e.keyIdentifier) {
248 case 'U+001B': // Esc
249 labelInput.value = title;
250 if (!isFolder)
251 urlInput.value = url;
252 // fall through
253 cr.dispatchSimpleEvent(listItem, 'canceledit', true);
254 case 'Enter':
255 if (listItem.parentNode)
256 listItem.parentNode.focus();
257 }
258 }
259
260 function handleBlur(e) {
261 // When the blur event happens we do not know who is getting focus so we
262 // delay this a bit since we want to know if the other input got focus
263 // before deciding if we should exit edit mode.
264 var doc = e.target.ownerDocument;
265 window.setTimeout(function() {
266 var activeElement = doc.activeElement;
267 if (activeElement != urlInput && activeElement != labelInput) {
268 listItem.editing = false;
269 }
270 }, 50);
271 }
272
273 var doc = this.ownerDocument;
274 if (editing) {
275 this.setAttribute('editing', '');
276 this.draggable = false;
277
278 labelInput = doc.createElement('input');
279 labelInput.placeholder =
280 localStrings.getString('name_input_placeholder');
281 replaceAllChildren(labelEl, labelInput);
282 labelInput.value = title;
283
284 if (!isFolder) {
285 // To use :invalid we need to put the input inside a form
286 // https://bugs.webkit.org/show_bug.cgi?id=34733
287 var form = doc.createElement('form');
288 urlInput = doc.createElement('input');
289 urlInput.type = 'url';
290 urlInput.required = true;
291 urlInput.placeholder =
292 localStrings.getString('url_input_placeholder');
293
294 // We also need a name for the input for the CSS to work.
295 urlInput.name = '-url-input-' + cr.createUid();
296 form.appendChild(urlInput);
297 replaceAllChildren(urlEl, form);
298 urlInput.value = url;
299 }
300
301 function stopPropagation(e) {
302 e.stopPropagation();
303 }
304
305 var eventsToStop = ['mousedown', 'mouseup', 'contextmenu', 'dblclick'];
306 eventsToStop.forEach(function(type) {
307 labelInput.addEventListener(type, stopPropagation);
308 });
309 labelInput.addEventListener('keydown', handleKeydown);
310 labelInput.addEventListener('blur', handleBlur);
311 cr.ui.limitInputWidth(labelInput, this, 200);
312 labelInput.focus();
313 labelInput.select();
314
315 if (!isFolder) {
316 eventsToStop.forEach(function(type) {
317 urlInput.addEventListener(type, stopPropagation);
318 });
319 urlInput.addEventListener('keydown', handleKeydown);
320 urlInput.addEventListener('blur', handleBlur);
321 cr.ui.limitInputWidth(urlInput, this, 200);
322 }
323
324 } else {
325
326 // Check that we have a valid URL and if not we do not change the
327 // editing mode.
328 if (!isFolder) {
329 var urlInput = this.querySelector('.url input');
330 var newUrl = urlInput.value;
331 if (!urlInput.validity.valid) {
332 // WebKit does not do URL fix up so we manually test if prepending
333 // 'http://' would make the URL valid.
334 // https://bugs.webkit.org/show_bug.cgi?id=29235
335 urlInput.value = 'http://' + newUrl;
336 if (!urlInput.validity.valid) {
337 // still invalid
338 urlInput.value = newUrl;
339
340 // In case the item was removed before getting here we should
341 // not alert.
342 if (listItem.parentNode) {
343 alert(localStrings.getString('invalid_url'));
344 }
345 urlInput.focus();
346 urlInput.select();
347 return;
348 }
349 newUrl = 'http://' + newUrl;
350 }
351 urlEl.textContent = this.bookmarkNode.url = newUrl;
352 }
353
354 this.removeAttribute('editing');
355 this.draggable = true;
356
357 labelInput = this.querySelector('.label input');
358 var newLabel = labelInput.value;
359 labelEl.textContent = this.bookmarkNode.title = newLabel;
360
361 if (isFolder) {
362 if (newLabel != title) {
363 cr.dispatchSimpleEvent(this, 'rename', true);
364 }
365 } else if (newLabel != title || newUrl != url) {
366 cr.dispatchSimpleEvent(this, 'edit', true);
367 }
368 }
369 }
370 };
371
372 function createListItem(bookmarkNode, showFolder) {
373 var li = listItemPromo.cloneNode(true);
374 BookmarkListItem.decorate(li);
375 updateListItem(li, bookmarkNode, showFolder);
376 li.bookmarkId = bookmarkNode.id;
377 li.bookmarkNode = bookmarkNode;
378 li.draggable = true;
379 listLookup[bookmarkNode.id] = li;
380 return li;
381 }
382
383 function updateListItem(el, bookmarkNode, showFolder) {
384 var labelEl = el.firstChild;
385 labelEl.textContent = bookmarkNode.title;
386 if (!bmm.isFolder(bookmarkNode)) {
387 labelEl.style.backgroundImage = url('chrome://favicon/' +
388 bookmarkNode.url);
389 var urlEl = el.childNodes[1].firstChild;
390 urlEl.textContent = urlEl.href = bookmarkNode.url;
391 } else {
392 el.className = 'folder';
393 }
394
395 var folderEl = el.lastChild.firstChild;
396 if (showFolder) {
397 folderEl.style.display = '';
398 folderEl.textContent = getFolder(bookmarkNode.parentId);
399 folderEl.href = '#' + bookmarkNode.parentId;
400 } else {
401 folderEl.style.display = 'none';
402 }
403 }
404
405 var listItemPromo = (function() {
406 var div = cr.doc.createElement('div');
407 div.innerHTML = '<div>' +
408 '<div class=label></div>' +
409 '<div><span class=url></span></div>' +
410 '<div><span class=folder></span></div>' +
411 '</div>';
412 return div.firstChild;
413 })();
414
415 return {
416 createListItem: createListItem,
417 BookmarkList: BookmarkList,
418 listLookup: listLookup
419 };
420 });
OLDNEW
« no previous file with comments | « resources/bookmark_manager/js/bmm.js ('k') | resources/bookmark_manager/js/bmm/bookmarktree.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698