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 var Galore = Galore || {};
9 create: function(settings, onload, onSettingsChange) {
10 var view = Object.create(this);
13 view.settings = settings;
15 view.onsettings = onSettingsChange;
16 chrome.app.window.create('window.html', {
19 defaultWidth: 440, minWidth: 440, maxWidth: 440,
20 defaultHeight: 640, minHeight: 640, maxHeight: 640,
22 }, function(appWindow) {
23 view.window = appWindow;
24 view.addListener_(appWindow.contentWindow, 'load', 'onLoad_');
29 addNotificationButton: function(sectionTitle,
33 var button = this.getElement_('#templates .notification').cloneNode(true);
34 var image = button.querySelector('img');
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);
43 showWindow: function() {
48 logEvent: function(message) {
49 var event = this.getElement_('#templates .event').cloneNode(true);
50 event.textContent = message;
51 this.getElement_('#events-scroll').appendChild(event).scrollIntoView();
54 logError: function(message) {
55 var events = this.getElement_('#events-scroll');
56 var error = this.getElement_('#templates .error').cloneNode(true);
57 error.textContent = message;
58 events.appendChild(error).scrollIntoView();
63 this.dataset = this.window.contentWindow.document.body.dataset;
64 this.dataset.priority = this.settings.priority || '0';
65 this.addListener_('body', 'mousedown', 'onBodyMouseDown_');
66 this.addListener_('body', 'mouseup', 'onBodyMouseUp_');
67 this.addListener_('#shadow', 'mousemove', 'onButtonMouseMove_');
68 this.addButtonListeners_('button, #shadow');
69 this.setButtonAction_('.priority', 'changePriority_');
70 this.setButtonAction_('#shadow', 'toggleMenu_');
71 this.setButtonAction_('#clear-events', 'clearEvents_');
72 this.setButtonAction_('#show-menu', 'toggleMenu_');
73 this.setButtonAction_('#close', 'close', this.window.contentWindow);
75 this.onload.call(this, this);
79 * Handling our own mouse events is fun! It also allows us to keep the cursor
80 * appropriately indicating whether a button press or window drag is happening
81 * or will happen on mousedown. As a bonus, it allows button to have a
82 * highlight-as-you-drag behavior similar to menu items.
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;
95 * See the comment for onButtonMouseDown_() above.
98 onButtonMouseMove_: function(event) {
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;
106 * See the comment for onButtonMouseDown_() above.
109 onButtonMouseOut_: function(event) {
110 // Record the fact that the mouse is not over this button any more to allow
111 // CSS rules to stop highlighting it.
112 event.currentTarget.dataset.hover = 'false';
116 * See the comment for onButtonMouseDown_() above.
119 onButtonMouseOver_: function(event) {
120 // Record the fact that the mouse is over this button to allow CSS rules to
121 // highlight it if appropriate.
122 event.currentTarget.dataset.hover = 'true';
126 * See the comment for onButtonMouseDown_() above.
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);
141 * See the comment for onButtonMouseDown_() above.
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 = '';
152 onBodyMouseDown_: function(event) {
153 // Prevents the cursor from becoming a text cursor during drags.
154 if (window.getComputedStyle(event.target).cursor != 'text')
155 event.preventDefault();
159 changePriority_: function(event) {
160 this.settings.priority = event.currentTarget.dataset.priority || '0';
161 this.dataset.priority = this.settings.priority;
163 this.onsettings.call(this, this.settings);
167 toggleMenu_: function() {
168 this.dataset.popup = String(this.dataset.popup != 'true');
172 clearEvents_: function() {
173 var events = this.getElement_('#events-scroll');
174 while (events.lastChild)
175 events.removeChild(events.lastChild);
176 this.dataset.popup = 'false';
180 getSection_: function(title) {
181 this.sections[title] = (this.sections[title] || this.makeSection_(title));
182 return this.sections[title];
186 makeSection_: function(title) {
187 var section = this.getElement_('#templates .section').cloneNode(true);
188 section.querySelector('span').textContent = title;
189 return this.getElement_('#notifications').appendChild(section);
193 addButtonListeners_: function(buttons) {
194 this.addListener_(buttons, 'mousedown', 'onButtonMouseDown_');
195 this.addListener_(buttons, 'mouseout', 'onButtonMouseOut_');
196 this.addListener_(buttons, 'mouseover', 'onButtonMouseOver_');
197 this.addListener_(buttons, 'mouseup', 'onButtonMouseUp_');
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;
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);
217 bind_: function(action, target) {
218 return (target || this)[action].bind(target || this);
222 getElement_: function(element) {
223 return this.getElements_(element)[0];
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];