mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
257 lines
9.2 KiB
JavaScript
257 lines
9.2 KiB
JavaScript
/* 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/. */
|
|
|
|
"use strict";
|
|
|
|
const Cc = Components.classes;
|
|
const Ci = Components.interfaces;
|
|
const Cu = Components.utils;
|
|
|
|
this.EXPORTED_SYMBOLS = [ "AutoCompleteE10S" ];
|
|
|
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
Cu.import("resource://gre/modules/Services.jsm");
|
|
Cu.import("resource://gre/modules/nsFormAutoCompleteResult.jsm");
|
|
|
|
// nsITreeView implementation that feeds the autocomplete popup
|
|
// with the search data.
|
|
var AutoCompleteE10SView = {
|
|
// nsISupports
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsITreeView,
|
|
Ci.nsIAutoCompleteController]),
|
|
|
|
// Private variables
|
|
treeBox: null,
|
|
treeData: [],
|
|
properties: [],
|
|
|
|
// nsITreeView
|
|
selection: null,
|
|
|
|
get rowCount() { return this.treeData.length; },
|
|
setTree: function(treeBox) { this.treeBox = treeBox; },
|
|
getCellText: function(idx, column) { return this.treeData[idx] },
|
|
isContainer: function(idx) { return false; },
|
|
getCellValue: function(idx, column){ return false },
|
|
isContainerOpen: function(idx) { return false; },
|
|
isContainerEmpty: function(idx) { return false; },
|
|
isSeparator: function(idx) { return false; },
|
|
isSorted: function() { return false; },
|
|
isEditable: function(idx, column) { return false; },
|
|
canDrop: function(idx, orientation, dt) { return false; },
|
|
getLevel: function(idx) { return 0; },
|
|
getParentIndex: function(idx) { return -1; },
|
|
hasNextSibling: function(idx, after) { return idx < this.treeData.length - 1 },
|
|
toggleOpenState: function(idx) { },
|
|
getCellProperties: function(idx, column) { return this.properties[idx] || ""; },
|
|
getRowProperties: function(idx) { return ""; },
|
|
getImageSrc: function(idx, column) { return null; },
|
|
getProgressMode : function(idx, column) { },
|
|
cycleHeader: function(column) { },
|
|
cycleCell: function(idx, column) { },
|
|
selectionChanged: function() { },
|
|
performAction: function(action) { },
|
|
performActionOnCell: function(action, index, column) { },
|
|
getColumnProperties: function(column) { return ""; },
|
|
|
|
// nsIAutoCompleteController
|
|
get matchCount() {
|
|
return this.rowCount;
|
|
},
|
|
|
|
handleEnter: function(aIsPopupSelection) {
|
|
AutoCompleteE10S.handleEnter(aIsPopupSelection);
|
|
},
|
|
|
|
stopSearch: function(){},
|
|
|
|
// Internal JS-only API
|
|
clearResults: function() {
|
|
this.treeData = [];
|
|
this.properties = [];
|
|
},
|
|
|
|
addResult: function(text, properties) {
|
|
this.treeData.push(text);
|
|
this.properties.push(properties);
|
|
},
|
|
};
|
|
|
|
this.AutoCompleteE10S = {
|
|
init: function() {
|
|
let messageManager = Cc["@mozilla.org/globalmessagemanager;1"].
|
|
getService(Ci.nsIMessageListenerManager);
|
|
messageManager.addMessageListener("FormAutoComplete:SelectBy", this);
|
|
messageManager.addMessageListener("FormAutoComplete:GetSelectedIndex", this);
|
|
messageManager.addMessageListener("FormAutoComplete:MaybeOpenPopup", this);
|
|
messageManager.addMessageListener("FormAutoComplete:ClosePopup", this);
|
|
messageManager.addMessageListener("FormAutoComplete:RemoveEntry", this);
|
|
},
|
|
|
|
_initPopup: function(browserWindow, rect, direction) {
|
|
this._popupCache = { browserWindow, rect, direction };
|
|
|
|
this.browser = browserWindow.gBrowser.selectedBrowser;
|
|
this.popup = this.browser.autoCompletePopup;
|
|
this.popup.hidden = false;
|
|
// don't allow the popup to become overly narrow
|
|
this.popup.setAttribute("width", Math.max(100, rect.width));
|
|
this.popup.style.direction = direction;
|
|
|
|
this.x = rect.left;
|
|
this.y = rect.top;
|
|
this.width = rect.width;
|
|
this.height = rect.height;
|
|
},
|
|
|
|
_showPopup: function(results) {
|
|
AutoCompleteE10SView.clearResults();
|
|
|
|
let resultsArray = [];
|
|
let count = results.matchCount;
|
|
for (let i = 0; i < count; i++) {
|
|
// The actual result for each match in the results object is the value.
|
|
// We return that in order to submit the correct value. However, we have
|
|
// to make sure we display the label corresponding to it in the popup.
|
|
resultsArray.push(results.getValueAt(i));
|
|
AutoCompleteE10SView.addResult(results.getLabelAt(i),
|
|
results.getStyleAt(i));
|
|
}
|
|
|
|
this.popup.view = AutoCompleteE10SView;
|
|
|
|
this.popup.selectedIndex = -1;
|
|
this.popup.invalidate();
|
|
|
|
if (count > 0) {
|
|
// Reset fields that were set from the last time the search popup was open
|
|
this.popup.mInput = null;
|
|
this.popup.showCommentColumn = false;
|
|
this.popup.showImageColumn = false;
|
|
this.popup.openPopupAtScreenRect("after_start", this.x, this.y, this.width, this.height, false, false);
|
|
} else {
|
|
this.popup.closePopup();
|
|
}
|
|
|
|
this._resultCache = results;
|
|
return resultsArray;
|
|
},
|
|
|
|
// This function is used by the login manager, which uses a single message
|
|
// to fill in the autocomplete results. See
|
|
// "RemoteLogins:autoCompleteLogins".
|
|
showPopupWithResults: function(browserWindow, rect, results) {
|
|
this._initPopup(browserWindow, rect);
|
|
this._showPopup(results);
|
|
},
|
|
|
|
removeEntry(index) {
|
|
this._resultCache.removeValueAt(index, true);
|
|
|
|
let selectedIndex = this.popup.selectedIndex;
|
|
this.showPopupWithResults(this._popupCache.browserWindow,
|
|
this._popupCache.rect,
|
|
this._resultCache);
|
|
|
|
// If we removed the last result, bump the selected index back once.
|
|
if (selectedIndex >= this._resultCache.matchCount)
|
|
selectedIndex--;
|
|
this.popup.selectedIndex = selectedIndex;
|
|
},
|
|
|
|
// This function is called in response to AutoComplete requests from the
|
|
// child (received via the message manager, see
|
|
// "FormHistory:AutoCompleteSearchAsync").
|
|
search: function(message) {
|
|
let browserWindow = message.target.ownerDocument.defaultView;
|
|
let rect = message.data;
|
|
let direction = message.data.direction;
|
|
|
|
this._initPopup(browserWindow, rect, direction);
|
|
|
|
// NB: We use .wrappedJSObject here in order to pass our mock DOM object
|
|
// without being rejected by XPConnect (which attempts to enforce that DOM
|
|
// objects are implemented in C++.
|
|
let formAutoComplete = Cc["@mozilla.org/satchel/form-autocomplete;1"]
|
|
.getService(Ci.nsIFormAutoComplete).wrappedJSObject;
|
|
|
|
let values, labels;
|
|
if (message.data.datalistResult) {
|
|
// Create a full FormAutoCompleteResult from the mock one that we pass
|
|
// over IPC.
|
|
message.data.datalistResult =
|
|
new FormAutoCompleteResult(message.data.untrimmedSearchString,
|
|
Ci.nsIAutoCompleteResult.RESULT_SUCCESS,
|
|
0, "", message.data.datalistResult.values,
|
|
message.data.datalistResult.labels,
|
|
[], null);
|
|
} else {
|
|
message.data.datalistResult = null;
|
|
}
|
|
|
|
formAutoComplete.autoCompleteSearchAsync(message.data.inputName,
|
|
message.data.untrimmedSearchString,
|
|
message.data.mockField,
|
|
null,
|
|
message.data.datalistResult,
|
|
{ onSearchCompletion:
|
|
this.onSearchComplete.bind(this) });
|
|
},
|
|
|
|
// The second half of search, this fills in the popup and returns the
|
|
// results to the child.
|
|
onSearchComplete: function(results) {
|
|
let resultsArray = this._showPopup(results);
|
|
|
|
this.browser.messageManager.sendAsyncMessage(
|
|
"FormAutoComplete:AutoCompleteSearchAsyncResult",
|
|
{results: resultsArray}
|
|
);
|
|
},
|
|
|
|
receiveMessage: function(message) {
|
|
switch (message.name) {
|
|
case "FormAutoComplete:SelectBy":
|
|
this.popup.selectBy(message.data.reverse, message.data.page);
|
|
break;
|
|
|
|
case "FormAutoComplete:GetSelectedIndex":
|
|
return this.popup.selectedIndex;
|
|
|
|
case "FormAutoComplete:RemoveEntry":
|
|
this.removeEntry(message.data.index);
|
|
break;
|
|
|
|
case "FormAutoComplete:MaybeOpenPopup":
|
|
if (AutoCompleteE10SView.treeData.length > 0 &&
|
|
!this.popup.popupOpen) {
|
|
// This happens when one of the arrow keys is pressed after a search
|
|
// has already been completed. nsAutoCompleteController tries to
|
|
// re-use its own cache of the results without re-doing the search.
|
|
// Detect that and show the popup here.
|
|
this.showPopupWithResults(this._popupCache.browserWindow,
|
|
this._popupCache.rect,
|
|
this._resultCache);
|
|
}
|
|
break;
|
|
|
|
case "FormAutoComplete:ClosePopup":
|
|
this.popup.closePopup();
|
|
break;
|
|
}
|
|
},
|
|
|
|
handleEnter: function(aIsPopupSelection) {
|
|
this.browser.messageManager.sendAsyncMessage(
|
|
"FormAutoComplete:HandleEnter",
|
|
{ selectedIndex: this.popup.selectedIndex,
|
|
isPopupSelection: aIsPopupSelection }
|
|
);
|
|
},
|
|
|
|
stopSearch: function() {}
|
|
}
|
|
|
|
this.AutoCompleteE10S.init();
|