зеркало из https://github.com/mozilla/gecko-dev.git
Bug 717772 - Delay autocomplete of pasted value.
r=gavin
This commit is contained in:
Родитель
432bcfeab6
Коммит
a9ec0e10f4
|
@ -88,6 +88,7 @@ _TEST_FILES = findbar_window.xul \
|
|||
test_autocomplete2.xul \
|
||||
test_autocomplete3.xul \
|
||||
test_autocomplete4.xul \
|
||||
test_autocomplete_delayOnPaste.xul \
|
||||
test_keys.xul \
|
||||
window_keys.xul \
|
||||
test_showcaret.xul \
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
|
||||
|
||||
<window title="Autocomplete Widget Test 4"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="runTest();">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://global/content/globalOverlay.js"/>
|
||||
|
||||
<textbox id="autocomplete"
|
||||
type="autocomplete"
|
||||
completedefaultindex="true"
|
||||
onsearchcomplete="searchComplete();"
|
||||
timeout="0"
|
||||
autocompletesearch="simple"/>
|
||||
|
||||
<script class="testbody" type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
function autoCompleteSimpleResult(aString) {
|
||||
this.searchString = aString;
|
||||
this.searchResult = Components.interfaces.nsIAutoCompleteResult.RESULT_SUCCESS;
|
||||
this.matchCount = 1;
|
||||
this._param = "Result";
|
||||
}
|
||||
autoCompleteSimpleResult.prototype = {
|
||||
_param: "",
|
||||
searchString: null,
|
||||
searchResult: Components.interfaces.nsIAutoCompleteResult.RESULT_FAILURE,
|
||||
defaultIndex: 0,
|
||||
errorDescription: null,
|
||||
matchCount: 0,
|
||||
getValueAt: function() { return this._param; },
|
||||
getCommentAt: function() { return null; },
|
||||
getStyleAt: function() { return null; },
|
||||
getImageAt: function() { return null; },
|
||||
getLabelAt: function() { return null; },
|
||||
removeValueAt: function() {}
|
||||
};
|
||||
|
||||
// A basic autocomplete implementation that returns one result.
|
||||
let autoCompleteSimple = {
|
||||
classID: Components.ID("0a2afbdb-f30e-47d1-9cb1-0cd160240aca"),
|
||||
contractID: "@mozilla.org/autocomplete/search;1?name=simple",
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Components.interfaces.nsIFactory,
|
||||
Components.interfaces.nsIAutoCompleteSearch
|
||||
]),
|
||||
createInstance: function (outer, iid) {
|
||||
return this.QueryInterface(iid);
|
||||
},
|
||||
|
||||
registerFactory: function () {
|
||||
let registrar =
|
||||
Components.manager.QueryInterface(Components.interfaces.nsIComponentRegistrar);
|
||||
registrar.registerFactory(this.classID, "Test Simple Autocomplete",
|
||||
this.contractID, this);
|
||||
},
|
||||
unregisterFactory: function () {
|
||||
let registrar =
|
||||
Components.manager.QueryInterface(Components.interfaces.nsIComponentRegistrar);
|
||||
registrar.unregisterFactory(this.classID, this);
|
||||
},
|
||||
|
||||
startSearch: function (aString, aParam, aResult, aListener) {
|
||||
let result = new autoCompleteSimpleResult(aString);
|
||||
aListener.onSearchResult(this, result);
|
||||
},
|
||||
stopSearch: function () {}
|
||||
};
|
||||
|
||||
let gACTimer;
|
||||
let gAutoComplete = $("autocomplete");
|
||||
|
||||
function searchComplete() {
|
||||
is(gAutoComplete.value, "result", "Value should be autocompleted now");
|
||||
ok(Date.now() - gACTimer > 500, "There should be a delay before autocomplete");
|
||||
|
||||
// Unregister the factory so that we don't get in the way of other tests
|
||||
autoCompleteSimple.unregisterFactory();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
autoCompleteSimple.registerFactory();
|
||||
const SEARCH_STRING = "res";
|
||||
|
||||
function cbCallback() {
|
||||
gAutoComplete.focus();
|
||||
synthesizeKey("v", { accelKey: true });
|
||||
is(gAutoComplete.value, SEARCH_STRING, "Value should not be autocompleted immediately");
|
||||
}
|
||||
|
||||
SimpleTest.waitForClipboard(SEARCH_STRING, function () {
|
||||
gACTimer = Date.now();
|
||||
Components.classes["@mozilla.org/widget/clipboardhelper;1"]
|
||||
.getService(Components.interfaces.nsIClipboardHelper)
|
||||
.copyStringToClipboard(SEARCH_STRING, Components.interfaces.nsIClipboard.kGlobalClipboard);
|
||||
}, cbCallback, cbCallback);
|
||||
}
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p id="display">
|
||||
</p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
|
||||
</window>
|
|
@ -94,8 +94,15 @@
|
|||
<constructor><![CDATA[
|
||||
mController = Components.classes["@mozilla.org/autocomplete/controller;1"].
|
||||
getService(Components.interfaces.nsIAutoCompleteController);
|
||||
|
||||
// For security reasons delay searches on pasted values.
|
||||
this.inputField.controllers.insertControllerAt(0, this._pasteController);
|
||||
]]></constructor>
|
||||
|
||||
<destructor><![CDATA[
|
||||
this.inputField.controllers.removeController(this._pasteController);
|
||||
]]></destructor>
|
||||
|
||||
<!-- =================== nsIAccessibleProvider =================== -->
|
||||
|
||||
<property name="accessibleType" readonly="true">
|
||||
|
@ -165,8 +172,18 @@
|
|||
onget="return this.getAttribute('showimagecolumn') == 'true';"/>
|
||||
|
||||
<property name="timeout"
|
||||
onset="this.setAttribute('timeout', val); return val;"
|
||||
onget="var t = parseInt(this.getAttribute('timeout')); return isNaN(t) ? 50 : t;"/>
|
||||
onset="this.setAttribute('timeout', val); return val;">
|
||||
<getter><![CDATA[
|
||||
// For security reasons delay searches on pasted values.
|
||||
if (this._valueIsPasted) {
|
||||
let t = parseInt(this.getAttribute('pastetimeout'));
|
||||
return isNaN(t) ? 1000 : t;
|
||||
}
|
||||
|
||||
let t = parseInt(this.getAttribute('timeout'));
|
||||
return isNaN(t) ? 50 : t;
|
||||
]]></getter>
|
||||
</property>
|
||||
|
||||
<property name="searchParam"
|
||||
onget="return this.getAttribute('autocompletesearchparam') || '';"
|
||||
|
@ -563,13 +580,31 @@
|
|||
]]></body>
|
||||
</method>
|
||||
|
||||
<field name="_valueIsPasted">false</field>
|
||||
<field name="_pasteController"><![CDATA[
|
||||
({
|
||||
_autocomplete: this,
|
||||
_kGlobalClipboard: Components.interfaces.nsIClipboard.kGlobalClipboard,
|
||||
supportsCommand: function(aCommand) aCommand == "cmd_paste",
|
||||
doCommand: function(aCommand) {
|
||||
this._autocomplete._valueIsPasted = true;
|
||||
this._autocomplete.editor.paste(this._kGlobalClipboard);
|
||||
this._autocomplete._valueIsPasted = false;
|
||||
},
|
||||
isCommandEnabled: function(aCommand) {
|
||||
return this._autocomplete.editor.isSelectionEditable &&
|
||||
this._autocomplete.editor.canPaste(this._kGlobalClipboard);
|
||||
},
|
||||
onEvent: function() {}
|
||||
})
|
||||
]]></field>
|
||||
</implementation>
|
||||
|
||||
<handlers>
|
||||
<handler event="input"><![CDATA[
|
||||
if (!this.mIgnoreInput && this.mController.input == this) {
|
||||
this.valueIsTyped = true;
|
||||
this.mController.handleText(true);
|
||||
this.mController.handleText();
|
||||
}
|
||||
this.resetActionType();
|
||||
]]></handler>
|
||||
|
@ -1127,7 +1162,7 @@
|
|||
}
|
||||
|
||||
// set these attributes before we set the class
|
||||
// so that we can use them from the contructor
|
||||
// so that we can use them from the constructor
|
||||
item.setAttribute("image", controller.getImageAt(this._currentIndex));
|
||||
item.setAttribute("url", url);
|
||||
item.setAttribute("title", controller.getCommentAt(this._currentIndex));
|
||||
|
|
Загрузка…
Ссылка в новой задаче