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
3 // found in the LICENSE file.
5 cr
.define('options.browser_options', function() {
6 /** @const */ var AutocompleteList
= cr
.ui
.AutocompleteList
;
7 /** @const */ var InlineEditableItem
= options
.InlineEditableItem
;
8 /** @const */ var InlineEditableItemList
= options
.InlineEditableItemList
;
11 * Creates a new startup page list item.
12 * @param {Object} pageInfo The page this item represents.
14 * @extends {options.InlineEditableItem}
16 function StartupPageListItem(pageInfo
) {
17 var el
= cr
.doc
.createElement('div');
18 el
.pageInfo_
= pageInfo
;
19 StartupPageListItem
.decorate(el
);
24 * Decorates an element as a startup page list item.
25 * @param {!HTMLElement} el The element to decorate.
27 StartupPageListItem
.decorate = function(el
) {
28 el
.__proto__
= StartupPageListItem
.prototype;
32 StartupPageListItem
.prototype = {
33 __proto__
: InlineEditableItem
.prototype,
36 * Input field for editing the page url.
43 decorate: function() {
44 InlineEditableItem
.prototype.decorate
.call(this);
46 var pageInfo
= this.pageInfo_
;
48 if (pageInfo
.modelIndex
== -1) {
49 this.isPlaceholder
= true;
50 pageInfo
.title
= loadTimeData
.getString('startupAddLabel');
54 var titleEl
= this.ownerDocument
.createElement('div');
55 titleEl
.className
= 'title';
56 titleEl
.classList
.add('favicon-cell');
57 titleEl
.classList
.add('weakrtl');
58 titleEl
.textContent
= pageInfo
.title
;
59 if (!this.isPlaceholder
) {
60 titleEl
.style
.backgroundImage
= getFaviconImageSet(pageInfo
.url
);
61 titleEl
.title
= pageInfo
.tooltip
;
64 this.contentElement
.appendChild(titleEl
);
66 var urlEl
= this.createEditableTextCell(pageInfo
.url
);
67 urlEl
.className
= 'url';
68 urlEl
.classList
.add('weakrtl');
69 this.contentElement
.appendChild(urlEl
);
71 var urlField
= /** @type {HTMLElement} */(urlEl
.querySelector('input'));
72 urlField
.className
= 'weakrtl';
73 urlField
.placeholder
= loadTimeData
.getString('startupPagesPlaceholder');
74 this.urlField_
= urlField
;
76 this.addEventListener('commitedit', this.onEditCommitted_
);
79 urlField
.addEventListener('focus', function(event
) {
80 self
.parentNode
.autocompleteList
.attachToInput(urlField
);
82 urlField
.addEventListener('blur', function(event
) {
83 self
.parentNode
.autocompleteList
.detach();
86 if (!this.isPlaceholder
)
87 titleEl
.draggable
= true;
91 get currentInputIsValid() {
92 return this.urlField_
.validity
.valid
;
97 return this.urlField_
.value
!= this.pageInfo_
.url
;
101 * Called when committing an edit; updates the model.
102 * @param {Event} e The end event.
105 onEditCommitted_: function(e
) {
106 var url
= this.urlField_
.value
;
107 if (this.isPlaceholder
)
108 chrome
.send('addStartupPage', [url
]);
110 chrome
.send('editStartupPage', [this.pageInfo_
.modelIndex
, url
]);
114 var StartupPageList
= cr
.ui
.define('list');
116 StartupPageList
.prototype = {
117 __proto__
: InlineEditableItemList
.prototype,
120 * An autocomplete suggestion list for URL editing.
121 * @type {AutocompleteList}
123 autocompleteList
: null,
126 * The drop position information: "below" or "above".
131 decorate: function() {
132 InlineEditableItemList
.prototype.decorate
.call(this);
134 // Listen to drag and drop events.
135 this.addEventListener('dragstart', this.handleDragStart_
.bind(this));
136 this.addEventListener('dragenter', this.handleDragEnter_
.bind(this));
137 this.addEventListener('dragover', this.handleDragOver_
.bind(this));
138 this.addEventListener('drop', this.handleDrop_
.bind(this));
139 this.addEventListener('dragleave', this.handleDragLeave_
.bind(this));
140 this.addEventListener('dragend', this.handleDragEnd_
.bind(this));
144 createItem: function(pageInfo
) {
145 var item
= new StartupPageListItem(pageInfo
);
146 item
.urlField_
.disabled
= this.disabled
;
151 deleteItemAtIndex: function(index
) {
152 chrome
.send('removeStartupPages', [index
]);
156 * Computes the target item of drop event.
157 * @param {Event} e The drop or dragover event.
160 getTargetFromDropEvent_: function(e
) {
161 var target
= e
.target
;
162 // e.target may be an inner element of the list item
163 while (target
!= null && !(target
instanceof StartupPageListItem
)) {
164 target
= target
.parentNode
;
170 * Handles the dragstart event.
171 * @param {Event} e The dragstart event.
174 handleDragStart_: function(e
) {
175 // Prevent dragging if the list is disabled.
181 var target
= this.getTargetFromDropEvent_(e
);
182 // StartupPageListItem should be the only draggable element type in the
183 // page but let's make sure.
184 if (target
instanceof StartupPageListItem
) {
185 this.draggedItem
= target
;
186 this.draggedItem
.editable
= false;
187 e
.dataTransfer
.effectAllowed
= 'move';
188 // We need to put some kind of data in the drag or it will be
189 // ignored. Use the URL in case the user drags to a text field or the
191 e
.dataTransfer
.setData('text/plain', target
.urlField_
.value
);
196 * Handles the dragenter event.
197 * @param {Event} e The dragenter event.
200 handleDragEnter_: function(e
) {
205 * Handles the dragover event.
206 * @param {Event} e The dragover event.
209 handleDragOver_: function(e
) {
210 var dropTarget
= this.getTargetFromDropEvent_(e
);
211 // Determines whether the drop target is to accept the drop.
212 // The drop is only successful on another StartupPageListItem.
213 if (!(dropTarget
instanceof StartupPageListItem
) ||
214 dropTarget
== this.draggedItem
|| dropTarget
.isPlaceholder
) {
215 this.hideDropMarker_();
218 // Compute the drop postion. Should we move the dragged item to
219 // below or above the drop target?
220 var rect
= dropTarget
.getBoundingClientRect();
221 var dy
= e
.clientY
- rect
.top
;
222 var yRatio
= dy
/ rect
.height
;
223 var dropPos
= yRatio
<= .5 ? 'above' : 'below';
224 this.dropPos
= dropPos
;
225 this.showDropMarker_(dropTarget
, dropPos
);
230 * Handles the drop event.
231 * @param {Event} e The drop event.
234 handleDrop_: function(e
) {
235 var dropTarget
= this.getTargetFromDropEvent_(e
);
237 if (!(dropTarget
instanceof StartupPageListItem
) ||
238 dropTarget
.pageInfo_
.modelIndex
== -1) {
242 this.hideDropMarker_();
244 // Insert the selection at the new position.
245 var newIndex
= this.dataModel
.indexOf(dropTarget
.pageInfo_
);
246 if (this.dropPos
== 'below')
249 // If there are selected indexes, it was a re-order.
250 if (this.selectionModel
.selectedIndexes
.length
> 0) {
251 chrome
.send('dragDropStartupPage',
252 [newIndex
, this.selectionModel
.selectedIndexes
]);
256 // Otherwise it was potentially a drop of new data (e.g. a bookmark).
257 var url
= e
.dataTransfer
.getData('url');
260 chrome
.send('addStartupPage', [url
, newIndex
]);
265 * Handles the dragleave event.
266 * @param {Event} e The dragleave event.
269 handleDragLeave_: function(e
) {
270 this.hideDropMarker_();
274 * Handles the dragend event.
275 * @param {Event} e The dragend event.
278 handleDragEnd_: function(e
) {
279 this.draggedItem
.editable
= true;
280 this.draggedItem
.updateEditState();
284 * Shows and positions the marker to indicate the drop target.
285 * @param {HTMLElement} target The current target list item of drop.
286 * @param {string} pos 'below' or 'above'.
289 showDropMarker_: function(target
, pos
) {
290 window
.clearTimeout(this.hideDropMarkerTimer_
);
291 var marker
= $('startupPagesListDropmarker');
292 var rect
= target
.getBoundingClientRect();
293 var markerHeight
= 6;
294 if (pos
== 'above') {
295 marker
.style
.top
= (rect
.top
- markerHeight
/ 2) + 'px';
297 marker
.style
.top
= (rect
.bottom
- markerHeight
/ 2) + 'px';
299 marker
.style
.width
= rect
.width
+ 'px';
300 marker
.style
.left
= rect
.left
+ 'px';
301 marker
.style
.display
= 'block';
305 * Hides the drop marker.
308 hideDropMarker_: function() {
309 // Hide the marker in a timeout to reduce flickering as we move between
310 // valid drop targets.
311 window
.clearTimeout(this.hideDropMarkerTimer_
);
312 this.hideDropMarkerTimer_
= window
.setTimeout(function() {
313 $('startupPagesListDropmarker').style
.display
= '';
319 StartupPageList
: StartupPageList