Add UI classes with empty event listeners
This is mostly boilerplate, but hopefully it's consistent boilerplate and gets out of the way of wiring up the actual meat of the app.
This commit is contained in:
Родитель
0fa934a8e6
Коммит
5aa5fac72e
|
@ -1,3 +1,4 @@
|
|||
content universalsearch chrome/content/
|
||||
content universalsearch-lib lib/
|
||||
content universalsearch-ui lib/ui/
|
||||
content universalsearch-skin chrome/skin/
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const EXPORTED_SYMBOLS = ['HighlightManager'];
|
||||
|
||||
function HighlightManager(opts) {
|
||||
this.win = opts.win;
|
||||
this.events = opts.events;
|
||||
// this is a recommendation view, because the highlight
|
||||
// class manages passing focus between it and the list of results
|
||||
this.recommendationView = opts.recommendationView;
|
||||
|
||||
this.adjustHighlight = this.adjustHighlight.bind(this);
|
||||
}
|
||||
|
||||
HighlightManager.prototype = {
|
||||
init: function() {
|
||||
this.events.subscribe('navigational-key', this.adjustHighlight);
|
||||
this.events.subscribe('recommendation-shown', this.adjustHighlight);
|
||||
|
||||
this.popup = this.win.document.getElementById('PopupAutoCompleteRichResult');
|
||||
|
||||
// TODO: maybe we can hook into the XBL mousemove handler and steal focus
|
||||
// that way instead of manually setting a mousemove listener
|
||||
this.popup.addEventListener('mousemove', this.adjustHighlight);
|
||||
},
|
||||
destroy: function() {
|
||||
this.popup.removeEventListener('mousemove', this.adjustHighlight);
|
||||
this.events.unsubscribe('recommendation-shown', this.adjustHighlight);
|
||||
this.events.unsubscribe('navigational-key', this.adjustHighlight);
|
||||
delete this.popup;
|
||||
delete this.recommendationView;
|
||||
delete this.win;
|
||||
},
|
||||
adjustHighlight: function(evt) {
|
||||
// if the recommendation isn't shown, do nothing: let the popup manage focus
|
||||
// otherwise,
|
||||
// check if the recommendation is shown + highlighted
|
||||
// check the selectedIndex of the popup
|
||||
// if it's a down key, move the focus downward, wrapping around if needed
|
||||
// if it's an up key, move the focus upward, wrapping around if needed
|
||||
}
|
||||
};
|
|
@ -0,0 +1,22 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const EXPORTED_SYMBOLS = ['Popup'];
|
||||
|
||||
function Popup(opts) {
|
||||
this.win = opts.win;
|
||||
this.events = opts.events;
|
||||
|
||||
this.beforePopupHide = this.beforePopupHide.bind(this);
|
||||
}
|
||||
|
||||
Popup.prototype = {
|
||||
init: function() {
|
||||
this.el = this.win.document.getElementById('PopupAutoCompleteRichResult');
|
||||
this.el.addEventListener('popuphiding', this.beforePopupHide);
|
||||
},
|
||||
beforePopupHide: function(evt) {
|
||||
this.events.publish('before-popup-hide');
|
||||
}
|
||||
};
|
|
@ -0,0 +1,67 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const EXPORTED_SYMBOLS = ['Recommendation'];
|
||||
|
||||
function Recommendation(opts) {
|
||||
this.win = opts.win;
|
||||
this.events = opts.events;
|
||||
this.urlbar = opts.urlbar;
|
||||
|
||||
this.navigate = this.navigate.bind(this);
|
||||
this.show = this.show.bind(this);
|
||||
this.hide = this.hide.bind(this);
|
||||
this._pollForElement = this._pollForElement.bind(this);
|
||||
}
|
||||
|
||||
Recommendation.prototype = {
|
||||
init: function() {
|
||||
// Note: there is a race between XBL modifying the XUL DOM to insert our
|
||||
// this.el, and the scripts being loaded and initialized. Rather than try
|
||||
// to fire a 'ready' event / set app state from the XBL <constructor>,
|
||||
// which is sometimes unreliable, we instead poll the XUL DOM for the el.
|
||||
this._pollForElement();
|
||||
|
||||
this.events.subscribe('recommendation', this.show);
|
||||
this.events.subscribe('enter-key', this.navigate);
|
||||
this.events.subscribe('printable-key', this.hide);
|
||||
this.events.subscribe('before-popup-hide', this.hide);
|
||||
},
|
||||
destroy: function() {
|
||||
this.el.removeEventListener('click', this.navigate);
|
||||
this.events.unsubscribe('recommendation', this.show);
|
||||
this.events.unsubscribe('enter-key', this.navigate);
|
||||
this.events.unsubscribe('printable-key', this.hide);
|
||||
this.events.unsubscribe('before-popup-hide', this.hide);
|
||||
|
||||
delete this.el;
|
||||
delete this.urlbar;
|
||||
delete this.win;
|
||||
},
|
||||
_pollForElement: function() {
|
||||
const el = this.win.document.getElementById('universal-search-recommendation');
|
||||
if (el) {
|
||||
this.el = el;
|
||||
this.el.addEventListener('click', this.navigate);
|
||||
} else {
|
||||
this.win.setTimeout(this._pollForElement, 20);
|
||||
}
|
||||
},
|
||||
show: function(data) {
|
||||
// assign the data to this.data
|
||||
// render using a simple inline template string
|
||||
// unset this.el.collapsed to show the el
|
||||
// fire 'recommendation-shown' event
|
||||
},
|
||||
hide: function() {
|
||||
// collapse the node
|
||||
// null out this.data
|
||||
},
|
||||
navigate: function(evt) {
|
||||
// if it's a click, we'll have a MouseEvent; if it's a right-click, bail.
|
||||
// else, we'll just have the (possibly null) data from the 'enter-key' event.
|
||||
// call this.urlbar.navigate to trigger navigation, passing in the URL.
|
||||
// TODO: or should we fire an event and keep all the modules maximally disconnected?
|
||||
}
|
||||
};
|
|
@ -0,0 +1,33 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const EXPORTED_SYMBOLS = ['Urlbar'];
|
||||
|
||||
function Urlbar(opts) {
|
||||
this.win = opts.win;
|
||||
this.events = opts.events;
|
||||
|
||||
this.onKeyDown = this.onKeyDown.bind(this);
|
||||
}
|
||||
|
||||
Urlbar.prototype = {
|
||||
init: function() {
|
||||
this.el = this.win.document.getElementById('urlbar');
|
||||
|
||||
this.el.addEventListener('keydown', this.onKeyDown);
|
||||
},
|
||||
destroy: function() {
|
||||
delete this.el;
|
||||
delete this.win;
|
||||
},
|
||||
onKeyDown: function(evt) {
|
||||
// check the key event:
|
||||
// if it's a printable key, fire 'printable-key'
|
||||
// if it's a navigational key, fire 'navigational-key'
|
||||
// if we don't know what to do, return true or false
|
||||
},
|
||||
navigate: function(url) {
|
||||
// set some urlbar state + navigate
|
||||
}
|
||||
};
|
|
@ -94,19 +94,28 @@ Search.prototype = {
|
|||
_loadScripts: function(win) {
|
||||
// Note that we load the scripts into the app namespace, to ease cleanup.
|
||||
// Each module's EXPORTED_SYMBOLS will be properties on win.universalSearch.
|
||||
// Example: Cu.import('chrome://universalsearch-lib/content/something-in-lib.js', win.universalSearch);
|
||||
Cu.import('resource://gre/modules/Console.jsm', win.universalSearch);
|
||||
|
||||
Cu.import('chrome://universalsearch-lib/content/events.js', win.universalSearch);
|
||||
Cu.import('chrome://universalsearch-lib/content/recommendation-server.js', win.universalSearch);
|
||||
|
||||
Cu.import('chrome://universalsearch-ui/content/highlight-manager.js', win.universalSearch);
|
||||
Cu.import('chrome://universalsearch-ui/content/popup.js', win.universalSearch);
|
||||
Cu.import('chrome://universalsearch-ui/content/recommendation.js', win.universalSearch);
|
||||
Cu.import('chrome://universalsearch-ui/content/urlbar.js', win.universalSearch);
|
||||
},
|
||||
|
||||
_unloadScripts: function(win) {
|
||||
// Unload scripts from the namespace. Not clear on whether this is necessary
|
||||
// if we just delete win.universalSearch.
|
||||
// Example: Cu.unload('chrome://universalsearch-lib/content/something-in-lib.js', win.universalSearch);
|
||||
Cu.unload('chrome://universalsearch-ui/content/highlight-manager.js', win.universalSearch);
|
||||
Cu.unload('chrome://universalsearch-ui/content/popup.js', win.universalSearch);
|
||||
Cu.unload('chrome://universalsearch-ui/content/recommendation.js', win.universalSearch);
|
||||
Cu.unload('chrome://universalsearch-ui/content/urlbar.js', win.universalSearch);
|
||||
|
||||
Cu.unload('chrome://universalsearch-lib/content/recommendation-server.js', win.universalSearch);
|
||||
Cu.unload('chrome://universalsearch-lib/content/events.js', win.universalSearch);
|
||||
|
||||
Cu.unload('resource://gre/modules/Console.jsm', win.universalSearch);
|
||||
},
|
||||
|
||||
|
@ -127,16 +136,42 @@ Search.prototype = {
|
|||
});
|
||||
app.recommendationServer.init();
|
||||
|
||||
app.urlbar = new app.Urlbar({
|
||||
win: win,
|
||||
events: app.events
|
||||
});
|
||||
app.urlbar.init();
|
||||
|
||||
app.highlightManager = new app.HighlightManager({
|
||||
win: win,
|
||||
events: app.events,
|
||||
recommendation: app.recommendation
|
||||
});
|
||||
app.highlightManager.init();
|
||||
|
||||
app.recommendation = new app.Recommendation({
|
||||
win: win,
|
||||
events: app.events,
|
||||
urlbar: app.urlbar
|
||||
});
|
||||
app.recommendation.init();
|
||||
|
||||
app.popup = new app.Popup({
|
||||
win: win,
|
||||
events: app.events
|
||||
});
|
||||
app.popup.init();
|
||||
},
|
||||
|
||||
_stopApp: function(win) {
|
||||
const app = win.universalSearch;
|
||||
|
||||
app.popup.destroy();
|
||||
app.recommendationView.destroy();
|
||||
app.highlightManager.destroy();
|
||||
app.urlbar.destroy();
|
||||
app.recommendationServer.destroy();
|
||||
delete app.recommendationServer;
|
||||
|
||||
app.events.destroy();
|
||||
delete app.events;
|
||||
|
||||
delete win.universalSearch;
|
||||
},
|
||||
|
|
Загрузка…
Ссылка в новой задаче