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

Side by Side Diff: chrome/test/data/extensions/api_test/notifications/galore/app/view.js

Issue 315053006: Refactor Notifications Galore to simplify, amke more hackable and add 'recording'. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: cr feedback Created 6 years, 6 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
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 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 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 var Galore = Galore || {}; 5 var mainWindow;
6 var sections = [];
6 7
7 Galore.view = { 8 var settings = {}
8 /** @constructor */ 9 settings.priority = "0";
9 create: function(settings, onload, onSettingsChange) {
10 var view = Object.create(this);
11 view.actions = [];
12 view.sections = {};
13 view.settings = settings;
14 view.onload = onload;
15 view.onsettings = onSettingsChange;
16 chrome.app.window.create('window.html', {
17 id: 'window',
18 frame: 'none',
19 defaultWidth: 440, minWidth: 440, maxWidth: 440,
20 defaultHeight: 640, minHeight: 640, maxHeight: 640,
21 hidden: true
22 }, function(appWindow) {
23 view.window = appWindow;
24 view.addListener_(appWindow.contentWindow, 'load', 'onLoad_');
25 }.bind(this));
26 return view;
27 },
28 10
29 addNotificationButton: function(sectionTitle, 11 function onMainWindowClosed() {
30 buttonTitle, 12 mainWindow = null;
31 iconUrl, 13 sections = [];
32 onClick) { 14 }
33 var button = this.getElement_('#templates .notification').cloneNode(true);
34 var image = button.querySelector('img');
35 image.src = iconUrl;
36 image.alt = buttonTitle;
37 button.name = buttonTitle;
38 button.dataset.actionIndex = this.actions.push(onClick) - 1;
39 this.addButtonListeners_(button);
40 this.getSection_(sectionTitle).appendChild(button);
41 },
42 15
43 showWindow: function() { 16 function createAppWindow(onLoad) {
44 if (this.window) 17 chrome.app.window.create('window.html', {
45 this.window.show(); 18 id: 'window',
46 }, 19 defaultWidth: 440, minWidth: 440, maxWidth: 840,
20 defaultHeight: 640, minHeight: 640, maxHeight: 940,
21 hidden: true
22 }, function(w) {
23 mainWindow = w;
24 mainWindow.contentWindow.onload = function() {
25 setButtonHandlers();
26 getElement("body").dataset.priority = settings.priority;
27 onLoad();
28 };
29 mainWindow.onClosed.addListener(onMainWindowClosed)
30 });
31 }
47 32
48 logEvent: function(message) { 33 function resovleImageUrl(imageUrl, callback) {
49 var event = this.getElement_('#templates .event').cloneNode(true); 34 if (imageUrl.substr(0,4) != "http") {
50 event.textContent = message; 35 callback(imageUrl);
51 this.getElement_('#events-scroll').appendChild(event).scrollIntoView(); 36 return;
52 }, 37 }
53 38
54 logError: function(message) { 39 var xhr = new XMLHttpRequest();
55 var events = this.getElement_('#events-scroll'); 40 xhr.open("GET", imageUrl);
56 var error = this.getElement_('#templates .error').cloneNode(true); 41 xhr.responseType = "blob";
57 error.textContent = message; 42 xhr.onload = function() {
58 events.appendChild(error).scrollIntoView(); 43 callback(URL.createObjectURL(this.response));
59 }, 44 }
45 xhr.send();
46 }
60 47
61 /** @private */ 48 function addNotificationButton(sectionTitle,
62 onLoad_: function() { 49 buttonTitle,
63 this.dataset = this.window.contentWindow.document.body.dataset; 50 iconUrl,
64 this.dataset.priority = this.settings.priority || '0'; 51 onClickHandler) {
65 this.addListener_('body', 'mousedown', 'onBodyMouseDown_'); 52 var button = getElement('#templates .notification').cloneNode(true);
66 this.addListener_('body', 'mouseup', 'onBodyMouseUp_'); 53 var image = button.querySelector('img');
67 this.addListener_('#shadow', 'mousemove', 'onButtonMouseMove_'); 54 resovleImageUrl(iconUrl, function(url) { image.src = url });
68 this.addButtonListeners_('button, #shadow'); 55 image.src = iconUrl;
69 this.setButtonAction_('.priority', 'changePriority_'); 56 image.alt = buttonTitle;
70 this.setButtonAction_('#shadow', 'toggleMenu_'); 57 button.name = buttonTitle;
71 this.setButtonAction_('#clear-events', 'clearEvents_'); 58 button.onclick = onClickHandler;
72 this.setButtonAction_('#show-menu', 'toggleMenu_'); 59 getSection(sectionTitle).appendChild(button);
73 this.setButtonAction_('#close', 'close', this.window.contentWindow); 60 }
74 if (this.onload)
75 this.onload.call(this, this);
76 },
77 61
78 /** 62 function showWindow() {
79 * Handling our own mouse events is fun! It also allows us to keep the cursor 63 if (mainWindow)
80 * appropriately indicating whether a button press or window drag is happening 64 mainWindow.show();
81 * or will happen on mousedown. As a bonus, it allows button to have a 65 }
82 * highlight-as-you-drag behavior similar to menu items.
83 *
84 * @private */
85 onButtonMouseDown_: function(event) {
86 // Record the fact that a button in this button's group is active, which
87 // allows onButtonMouseUp_ to do the right thing and CSS rules to correctly
88 // set cursor types and button highlighting.
89 var element = event.currentTarget;
90 this.dataset.active = element.classList[0] || '';
91 this.dragging = false;
92 },
93 66
94 /** 67 function logEvent(message) {
95 * See the comment for onButtonMouseDown_() above. 68 var event = getElement('#templates .event').cloneNode(true);
96 * 69 event.textContent = message;
97 * @private */ 70 getElement('#events').appendChild(event).scrollIntoView();
98 onButtonMouseMove_: function(event) { 71 }
99 // Buttons that support dragging add this as a listener to their mousemove
100 // events so a flag can be set during dragging to prevent their actions from
101 // being fired by the mouseup event that completes the dragging.
102 this.dragging = true;
103 },
104 72
105 /** 73 function logError(message) {
106 * See the comment for onButtonMouseDown_() above. 74 var events = getElement('#events');
107 * 75 var error = getElement('#templates .error').cloneNode(true);
108 * @private */ 76 error.textContent = message;
109 onButtonMouseOut_: function(event) { 77 events.appendChild(error).scrollIntoView();
110 // Record the fact that the mouse is not over this button any more to allow 78 }
111 // CSS rules to stop highlighting it.
112 event.currentTarget.dataset.hover = 'false';
113 },
114 79
115 /** 80 function setButtonHandlers() {
116 * See the comment for onButtonMouseDown_() above. 81 setButtonAction('.priority', changePriority);
117 * 82 setButtonAction('#clear-events', clearEvents);
118 * @private */ 83 setButtonAction('#record', onRecord);
119 onButtonMouseOver_: function(event) { 84 setButtonAction('#pause', onPause);
120 // Record the fact that the mouse is over this button to allow CSS rules to 85 setButtonAction('#stop', onStop);
121 // highlight it if appropriate. 86 setButtonAction('#play', onPlay);
122 event.currentTarget.dataset.hover = 'true'; 87 }
123 },
124 88
125 /** 89 function setRecorderStatusText(text) {
126 * See the comment for onButtonMouseDown_() above. 90 getElement("#recording-status").innerText = text;
127 * 91 }
128 * @private */
129 onButtonMouseUp_: function(event) {
130 // Send a button action if the button in which the mouseup happened is in
131 // the same group as the one in which the mousedown happened. The regular
132 // click handling which this replaces would send the action only if the
133 // mouseup happened in the same button as the mousedown.
134 var element = event.currentTarget;
135 var group = (element.classList[0] || 'x');
136 if (group == this.dataset.active && !this.dragging)
137 this.actions[element.dataset.actionIndex].call(element, event);
138 },
139 92
140 /** 93 function updateRecordingStatsDisplay(text) {
141 * See the comment for onButtonMouseDown_() above. 94 getElement("#recording-stats").innerText = text;
142 * 95 }
143 * @private */
144 onBodyMouseUp_: function(event) {
145 // Record the fact that no button is active, which allows onButtonMouseUp_
146 // to do the right thing and CSS rules to correctly set cursor types and
147 // button highlighting.
148 this.dataset.active = '';
149 },
150 96
151 /** @private */ 97 function changePriority(event) {
152 onBodyMouseDown_: function(event) { 98 settings.priority = event.currentTarget.dataset.priority || '0';
153 // Prevents the cursor from becoming a text cursor during drags. 99 getElement("body").dataset.priority = settings.priority;
154 if (window.getComputedStyle(event.target).cursor != 'text') 100 }
155 event.preventDefault();
156 },
157 101
158 /** @private */ 102 function clearEvents() {
159 changePriority_: function(event) { 103 var events = getElement('#events');
160 this.settings.priority = event.currentTarget.dataset.priority || '0'; 104 while (events.lastChild)
161 this.dataset.priority = this.settings.priority; 105 events.removeChild(events.lastChild);
162 if (this.onsettings) 106 }
163 this.onsettings.call(this, this.settings);
164 },
165 107
166 /** @private */ 108 function getSection(title) {
167 toggleMenu_: function() { 109 sections[title] = (sections[title] || makeSection(title));
168 this.dataset.popup = String(this.dataset.popup != 'true'); 110 return sections[title];
169 }, 111 }
170 112
171 /** @private */ 113 function makeSection(title) {
172 clearEvents_: function() { 114 var section = getElement('#templates .section').cloneNode(true);
173 var events = this.getElement_('#events-scroll'); 115 section.querySelector('span').textContent = title;
174 while (events.lastChild) 116 return getElement('#notifications').appendChild(section);
175 events.removeChild(events.lastChild); 117 }
176 this.dataset.popup = 'false';
177 },
178 118
179 /** @private */ 119 function setButtonAction(elements, action) {
180 getSection_: function(title) { 120 getElements(elements).forEach(function(element) {
181 this.sections[title] = (this.sections[title] || this.makeSection_(title)); 121 element.onclick = action;
182 return this.sections[title]; 122 });
183 }, 123 }
184 124
185 /** @private */ 125 function getElement(element) {
186 makeSection_: function(title) { 126 return getElements(element)[0];
187 var section = this.getElement_('#templates .section').cloneNode(true); 127 }
188 section.querySelector('span').textContent = title;
189 return this.getElement_('#notifications').appendChild(section);
190 },
191 128
192 /** @private */ 129 function getElements(elements) {
193 addButtonListeners_: function(buttons) { 130 if (typeof elements === 'string')
194 this.addListener_(buttons, 'mousedown', 'onButtonMouseDown_'); 131 elements = mainWindow.contentWindow.document.querySelectorAll(elements);
195 this.addListener_(buttons, 'mouseout', 'onButtonMouseOut_'); 132 if (String(elements) === '[object NodeList]')
196 this.addListener_(buttons, 'mouseover', 'onButtonMouseOver_'); 133 elements = Array.prototype.slice.call(elements);
197 this.addListener_(buttons, 'mouseup', 'onButtonMouseUp_'); 134 return Array.isArray(elements) ? elements : [elements];
198 }, 135 }
199
200 /** @private */
201 setButtonAction_: function(elements, action, target) {
202 var index = this.actions.push(this.bind_(action, target)) - 1;
203 this.getElements_(elements).forEach(function(element) {
204 element.dataset.actionIndex = index;
205 });
206 },
207
208 /** @private */
209 addListener_: function(elements, event, action, target) {
210 var listener = this.bind_(action, target);
211 this.getElements_(elements).forEach(function(element) {
212 element.addEventListener(event, listener);
213 });
214 },
215
216 /** @private */
217 bind_: function(action, target) {
218 return (target || this)[action].bind(target || this);
219 },
220
221 /** @private */
222 getElement_: function(element) {
223 return this.getElements_(element)[0];
224 },
225
226 /** @private */
227 getElements_: function(elements) {
228 if (typeof elements === 'string')
229 elements = this.window.contentWindow.document.querySelectorAll(elements);
230 if (String(elements) === '[object NodeList]')
231 elements = Array.prototype.slice.call(elements);
232 return Array.isArray(elements) ? elements : [elements];
233 }
234 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698