| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // TODO(arv): Now that this is driven by a data model, implement a data model | 5 // TODO(arv): Now that this is driven by a data model, implement a data model |
| 6 // that handles the loading and the events from the bookmark backend. | 6 // that handles the loading and the events from the bookmark backend. |
| 7 | 7 |
| 8 /** | 8 /** |
| 9 * @typedef {{childIds: Array<string>}} | 9 * @typedef {{childIds: Array<string>}} |
| 10 * | 10 * |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 144 cr.dispatchSimpleEvent(this, 'invalidId'); | 144 cr.dispatchSimpleEvent(this, 'invalidId'); |
| 145 return; | 145 return; |
| 146 } | 146 } |
| 147 | 147 |
| 148 this.dataModel = new BookmarksArrayDataModel(items); | 148 this.dataModel = new BookmarksArrayDataModel(items); |
| 149 | 149 |
| 150 this.fixWidth_(); | 150 this.fixWidth_(); |
| 151 cr.dispatchSimpleEvent(this, 'load'); | 151 cr.dispatchSimpleEvent(this, 'load'); |
| 152 | 152 |
| 153 // Use the same histogram configuration as UMA_HISTOGRAM_COUNTS_1000(). | 153 // Use the same histogram configuration as UMA_HISTOGRAM_COUNTS_1000(). |
| 154 chrome.metricsPrivate.recordValue({ | 154 chrome.metricsPrivate.recordValue( |
| 155 'metricName': 'Bookmarks.BookmarksInFolder', | 155 { |
| 156 'type': chrome.metricsPrivate.MetricTypeType.HISTOGRAM_LOG, | 156 'metricName': 'Bookmarks.BookmarksInFolder', |
| 157 'min': 1, | 157 'type': chrome.metricsPrivate.MetricTypeType.HISTOGRAM_LOG, |
| 158 'max': 1000, | 158 'min': 1, |
| 159 'buckets': 50 | 159 'max': 1000, |
| 160 }, this.dataModel.length); | 160 'buckets': 50 |
| 161 }, |
| 162 this.dataModel.length); |
| 161 }, | 163 }, |
| 162 | 164 |
| 163 /** | 165 /** |
| 164 * The bookmark node that the list is currently displaying. If we are | 166 * The bookmark node that the list is currently displaying. If we are |
| 165 * currently displaying search this returns null. | 167 * currently displaying search this returns null. |
| 166 * @type {BookmarkTreeNode} | 168 * @type {BookmarkTreeNode} |
| 167 */ | 169 */ |
| 168 get bookmarkNode() { | 170 get bookmarkNode() { |
| 169 if (this.isSearch()) | 171 if (this.isSearch()) |
| 170 return null; | 172 return null; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 196 * lazily. | 198 * lazily. |
| 197 * @private | 199 * @private |
| 198 * @param {!Event} e The mouseover event object. | 200 * @param {!Event} e The mouseover event object. |
| 199 */ | 201 */ |
| 200 handleMouseOver_: function(e) { | 202 handleMouseOver_: function(e) { |
| 201 var el = e.target; | 203 var el = e.target; |
| 202 while (el && el.parentNode != this) { | 204 while (el && el.parentNode != this) { |
| 203 el = el.parentNode; | 205 el = el.parentNode; |
| 204 } | 206 } |
| 205 | 207 |
| 206 if (el && el.parentNode == this && | 208 if (el && el.parentNode == this && !el.editing && |
| 207 !el.editing && | |
| 208 !(el.lastChild instanceof ContextMenuButton)) { | 209 !(el.lastChild instanceof ContextMenuButton)) { |
| 209 el.appendChild(new ContextMenuButton); | 210 el.appendChild(new ContextMenuButton); |
| 210 } | 211 } |
| 211 }, | 212 }, |
| 212 | 213 |
| 213 /** | 214 /** |
| 214 * Dispatches an urlClicked event which is used to open URLs in new | 215 * Dispatches an urlClicked event which is used to open URLs in new |
| 215 * tabs etc. | 216 * tabs etc. |
| 216 * @private | 217 * @private |
| 217 * @param {string} url The URL that was clicked. | 218 * @param {string} url The URL that was clicked. |
| 218 * @param {!Event} originalEvent The original click event object. | 219 * @param {!Event} originalEvent The original click event object. |
| 219 */ | 220 */ |
| 220 dispatchUrlClickedEvent_: function(url, originalEvent) { | 221 dispatchUrlClickedEvent_: function(url, originalEvent) { |
| 221 var event = new Event('urlClicked', {bubbles: true}); | 222 var event = new Event('urlClicked', {bubbles: true}); |
| 222 event.url = url; | 223 event.url = url; |
| 223 event.originalEvent = originalEvent; | 224 event.originalEvent = originalEvent; |
| 224 this.dispatchEvent(event); | 225 this.dispatchEvent(event); |
| 225 }, | 226 }, |
| 226 | 227 |
| 227 /** | 228 /** |
| 228 * Handles mousedown events so that we can prevent the auto scroll as | 229 * Handles mousedown events so that we can prevent the auto scroll as |
| 229 * necessary. | 230 * necessary. |
| 230 * @private | 231 * @private |
| 231 * @param {!Event} e The mousedown event object. | 232 * @param {!Event} e The mousedown event object. |
| 232 */ | 233 */ |
| 233 handleMouseDown_: function(e) { | 234 handleMouseDown_: function(e) { |
| 234 e = /** @type {!MouseEvent} */(e); | 235 e = /** @type {!MouseEvent} */ (e); |
| 235 if (e.button == 1) { | 236 if (e.button == 1) { |
| 236 // WebKit no longer fires click events for middle clicks so we manually | 237 // WebKit no longer fires click events for middle clicks so we manually |
| 237 // listen to mouse up to dispatch a click event. | 238 // listen to mouse up to dispatch a click event. |
| 238 this.addEventListener('mouseup', this.handleMiddleMouseUp_); | 239 this.addEventListener('mouseup', this.handleMiddleMouseUp_); |
| 239 | 240 |
| 240 // When the user does a middle click we need to prevent the auto scroll | 241 // When the user does a middle click we need to prevent the auto scroll |
| 241 // in case the user is trying to middle click to open a bookmark in a | 242 // in case the user is trying to middle click to open a bookmark in a |
| 242 // background tab. | 243 // background tab. |
| 243 // We do not do this in case the target is an input since middle click | 244 // We do not do this in case the target is an input since middle click |
| 244 // is also paste on Linux and we don't want to break that. | 245 // is also paste on Linux and we don't want to break that. |
| 245 if (e.target.tagName != 'INPUT') | 246 if (e.target.tagName != 'INPUT') |
| 246 e.preventDefault(); | 247 e.preventDefault(); |
| 247 } | 248 } |
| 248 }, | 249 }, |
| 249 | 250 |
| 250 /** | 251 /** |
| 251 * WebKit no longer dispatches click events for middle clicks so we need | 252 * WebKit no longer dispatches click events for middle clicks so we need |
| 252 * to emulate it. | 253 * to emulate it. |
| 253 * @private | 254 * @private |
| 254 * @param {!Event} e The mouse up event object. | 255 * @param {!Event} e The mouse up event object. |
| 255 */ | 256 */ |
| 256 handleMiddleMouseUp_: function(e) { | 257 handleMiddleMouseUp_: function(e) { |
| 257 e = /** @type {!MouseEvent} */(e); | 258 e = /** @type {!MouseEvent} */ (e); |
| 258 this.removeEventListener('mouseup', this.handleMiddleMouseUp_); | 259 this.removeEventListener('mouseup', this.handleMiddleMouseUp_); |
| 259 if (e.button == 1) { | 260 if (e.button == 1) { |
| 260 var el = e.target; | 261 var el = e.target; |
| 261 while (el.parentNode != this) { | 262 while (el.parentNode != this) { |
| 262 el = el.parentNode; | 263 el = el.parentNode; |
| 263 } | 264 } |
| 264 var node = el.bookmarkNode; | 265 var node = el.bookmarkNode; |
| 265 if (node && !bmm.isFolder(node)) | 266 if (node && !bmm.isFolder(node)) |
| 266 this.dispatchUrlClickedEvent_(node.url, e); | 267 this.dispatchUrlClickedEvent_(node.url, e); |
| 267 } | 268 } |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 310 this.dataModel.splice(bookmarkNode.index, 0, bookmarkNode); | 311 this.dataModel.splice(bookmarkNode.index, 0, bookmarkNode); |
| 311 }, | 312 }, |
| 312 | 313 |
| 313 /** | 314 /** |
| 314 * @param {string} id | 315 * @param {string} id |
| 315 * @param {MoveInfo} moveInfo | 316 * @param {MoveInfo} moveInfo |
| 316 */ | 317 */ |
| 317 handleMoved: function(id, moveInfo) { | 318 handleMoved: function(id, moveInfo) { |
| 318 if (moveInfo.parentId == this.parentId || | 319 if (moveInfo.parentId == this.parentId || |
| 319 moveInfo.oldParentId == this.parentId) { | 320 moveInfo.oldParentId == this.parentId) { |
| 320 | |
| 321 var dataModel = this.dataModel; | 321 var dataModel = this.dataModel; |
| 322 | 322 |
| 323 if (moveInfo.oldParentId == moveInfo.parentId) { | 323 if (moveInfo.oldParentId == moveInfo.parentId) { |
| 324 // Reorder within this folder | 324 // Reorder within this folder |
| 325 | 325 |
| 326 this.startBatchUpdates(); | 326 this.startBatchUpdates(); |
| 327 | 327 |
| 328 var bookmarkNode = this.dataModel.item(moveInfo.oldIndex); | 328 var bookmarkNode = this.dataModel.item(moveInfo.oldIndex); |
| 329 this.dataModel.splice(moveInfo.oldIndex, 1); | 329 this.dataModel.splice(moveInfo.oldIndex, 1); |
| 330 this.dataModel.splice(moveInfo.index, 0, bookmarkNode); | 330 this.dataModel.splice(moveInfo.index, 0, bookmarkNode); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 362 * Workaround for http://crbug.com/40902 | 362 * Workaround for http://crbug.com/40902 |
| 363 * @private | 363 * @private |
| 364 */ | 364 */ |
| 365 fixWidth_: function() { | 365 fixWidth_: function() { |
| 366 var list = bmm.list; | 366 var list = bmm.list; |
| 367 if (this.loadCount_ || !list) | 367 if (this.loadCount_ || !list) |
| 368 return; | 368 return; |
| 369 | 369 |
| 370 // The width of the list is wrong after its content has changed. | 370 // The width of the list is wrong after its content has changed. |
| 371 // Fortunately the reported offsetWidth is correct so we can detect the | 371 // Fortunately the reported offsetWidth is correct so we can detect the |
| 372 //incorrect width. | 372 // incorrect width. |
| 373 if (list.offsetWidth != list.parentNode.clientWidth - list.offsetLeft) { | 373 if (list.offsetWidth != list.parentNode.clientWidth - list.offsetLeft) { |
| 374 // Set the width to the correct size. This causes the relayout. | 374 // Set the width to the correct size. This causes the relayout. |
| 375 list.style.width = list.parentNode.clientWidth - list.offsetLeft + 'px'; | 375 list.style.width = list.parentNode.clientWidth - list.offsetLeft + 'px'; |
| 376 // Remove the temporary style.width in a timeout. Once the timer fires | 376 // Remove the temporary style.width in a timeout. Once the timer fires |
| 377 // the size should not change since we already fixed the width. | 377 // the size should not change since we already fixed the width. |
| 378 window.setTimeout(function() { | 378 window.setTimeout(function() { |
| 379 list.style.width = ''; | 379 list.style.width = ''; |
| 380 }, 0); | 380 }, 0); |
| 381 } | 381 } |
| 382 } | 382 } |
| 383 }; | 383 }; |
| 384 | 384 |
| 385 /** | 385 /** |
| 386 * The ID of the bookmark folder we are displaying. | 386 * The ID of the bookmark folder we are displaying. |
| 387 */ | 387 */ |
| 388 cr.defineProperty(BookmarkList, 'parentId', cr.PropertyKind.JS, | 388 cr.defineProperty(BookmarkList, 'parentId', cr.PropertyKind.JS, function() { |
| 389 function() { | 389 this.reload(); |
| 390 this.reload(); | 390 }); |
| 391 }); | |
| 392 | 391 |
| 393 /** | 392 /** |
| 394 * The contextMenu property. | 393 * The contextMenu property. |
| 395 */ | 394 */ |
| 396 cr.ui.contextMenuHandler.addContextMenuProperty(BookmarkList); | 395 cr.ui.contextMenuHandler.addContextMenuProperty(BookmarkList); |
| 397 /** @type {cr.ui.Menu} */ | 396 /** @type {cr.ui.Menu} */ |
| 398 BookmarkList.prototype.contextMenu; | 397 BookmarkList.prototype.contextMenu; |
| 399 | 398 |
| 400 /** | 399 /** |
| 401 * Creates a new bookmark list item. | 400 * Creates a new bookmark list item. |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 439 labelText.className = 'label-text'; | 438 labelText.className = 'label-text'; |
| 440 labelText.textContent = bookmarkNode.title; | 439 labelText.textContent = bookmarkNode.title; |
| 441 | 440 |
| 442 var urlEl = this.ownerDocument.createElement('div'); | 441 var urlEl = this.ownerDocument.createElement('div'); |
| 443 urlEl.className = 'url'; | 442 urlEl.className = 'url'; |
| 444 | 443 |
| 445 if (bmm.isFolder(bookmarkNode)) { | 444 if (bmm.isFolder(bookmarkNode)) { |
| 446 this.className = 'folder'; | 445 this.className = 'folder'; |
| 447 // TODO(pkasting): Condense folder icon resources together. | 446 // TODO(pkasting): Condense folder icon resources together. |
| 448 labelImg.style.content = cr.icon.getImage( | 447 labelImg.style.content = cr.icon.getImage( |
| 449 cr.isMac ? | 448 cr.isMac ? 'chrome://theme/IDR_BOOKMARK_BAR_FOLDER' : |
| 450 'chrome://theme/IDR_BOOKMARK_BAR_FOLDER' : | 449 'chrome://theme/IDR_FOLDER_CLOSED'); |
| 451 'chrome://theme/IDR_FOLDER_CLOSED'); | |
| 452 } else { | 450 } else { |
| 453 labelImg.style.content = cr.icon.getFavicon(bookmarkNode.url); | 451 labelImg.style.content = cr.icon.getFavicon(bookmarkNode.url); |
| 454 urlEl.textContent = bookmarkNode.url; | 452 urlEl.textContent = bookmarkNode.url; |
| 455 } | 453 } |
| 456 | 454 |
| 457 labelImgWrapper.appendChild(labelImg); | 455 labelImgWrapper.appendChild(labelImg); |
| 458 labelEl.appendChild(labelImgWrapper); | 456 labelEl.appendChild(labelImgWrapper); |
| 459 labelEl.appendChild(labelText); | 457 labelEl.appendChild(labelText); |
| 460 this.appendChild(labelEl); | 458 this.appendChild(labelEl); |
| 461 this.appendChild(urlEl); | 459 this.appendChild(urlEl); |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 552 }, 50); | 550 }, 50); |
| 553 } | 551 } |
| 554 | 552 |
| 555 var doc = this.ownerDocument; | 553 var doc = this.ownerDocument; |
| 556 var labelTextEl = queryRequiredElement('.label-text', this); | 554 var labelTextEl = queryRequiredElement('.label-text', this); |
| 557 var urlEl = queryRequiredElement('.url', this); | 555 var urlEl = queryRequiredElement('.url', this); |
| 558 if (editing) { | 556 if (editing) { |
| 559 this.setAttribute('editing', ''); | 557 this.setAttribute('editing', ''); |
| 560 this.draggable = false; | 558 this.draggable = false; |
| 561 | 559 |
| 562 labelInput = /** @type {HTMLElement} */(doc.createElement('input')); | 560 labelInput = /** @type {HTMLElement} */ (doc.createElement('input')); |
| 563 labelInput.placeholder = | 561 labelInput.placeholder = |
| 564 loadTimeData.getString('name_input_placeholder'); | 562 loadTimeData.getString('name_input_placeholder'); |
| 565 replaceAllChildren(labelTextEl, labelInput); | 563 replaceAllChildren(labelTextEl, labelInput); |
| 566 labelInput.value = title; | 564 labelInput.value = title; |
| 567 | 565 |
| 568 if (!isFolder) { | 566 if (!isFolder) { |
| 569 urlInput = /** @type {HTMLElement} */(doc.createElement('input')); | 567 urlInput = /** @type {HTMLElement} */ (doc.createElement('input')); |
| 570 urlInput.type = 'url'; | 568 urlInput.type = 'url'; |
| 571 urlInput.required = true; | 569 urlInput.required = true; |
| 572 urlInput.placeholder = | 570 urlInput.placeholder = |
| 573 loadTimeData.getString('url_input_placeholder'); | 571 loadTimeData.getString('url_input_placeholder'); |
| 574 | 572 |
| 575 // We also need a name for the input for the CSS to work. | 573 // We also need a name for the input for the CSS to work. |
| 576 urlInput.name = '-url-input-' + cr.createUid(); | 574 urlInput.name = '-url-input-' + cr.createUid(); |
| 577 replaceAllChildren(assert(urlEl), urlInput); | 575 replaceAllChildren(assert(urlEl), urlInput); |
| 578 urlInput.value = url; | 576 urlInput.value = url; |
| 579 } | 577 } |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 646 } | 644 } |
| 647 } else if (newLabel != title || newUrl != url) { | 645 } else if (newLabel != title || newUrl != url) { |
| 648 cr.dispatchSimpleEvent(this, 'edit', true); | 646 cr.dispatchSimpleEvent(this, 'edit', true); |
| 649 } | 647 } |
| 650 } | 648 } |
| 651 } | 649 } |
| 652 }; | 650 }; |
| 653 | 651 |
| 654 return { | 652 return { |
| 655 BookmarkList: BookmarkList, | 653 BookmarkList: BookmarkList, |
| 656 list: /** @type {Element} */(null), // Set when decorated. | 654 list: /** @type {Element} */ (null), // Set when decorated. |
| 657 }; | 655 }; |
| 658 }); | 656 }); |
| OLD | NEW |