/* Find Search Words
* nanto_vi (TOYAMA Nao), 2007-01-28
*
* Search web pages for words in the search bar.
*
* Original Extension: SearchWP
*
* Copyright (C) 2004-2006 All Rights Reserved.
* Author: Georges-Etienne Legendre (legege@legege.com)
*
* Original Icons: famfamfam.com: Silk Icons
*
*/
var gFSWPrefs = {
insertIn: "PersonalToolbar",
insertBefore: null,
insertAfter: "personal-bookmarks",
findEnabledTooltip: "このページを検索: \"%s\"",
findDisabledTooltip: "このページを検索",
findShortcutKeyCode: "VK_F4",
wrappedToTopMessage: "ページの最後まで検索しました。" +
"ページの最初から検索を続けます。",
wrappedToBottomMessage: "ページの最初まで検索しました。" +
"ページの最後から検索を続けます。",
notFoundMessage: "\"%s\" は見つかりませんでした。",
messageDisplayTime: 3000,
updateInterval: 500,
style: .toolbarbutton-icon {
-moz-margin-end: 4px !important;
}
.findsearchwords-button > .toolbarbutton-text {
display: -moz-box !important;
}
.findsearchwords-button > .toolbarbutton-menu-dropmarker {
-moz-margin-start: 3px !important;
}
.findsearchwords-empty > #findsearchwords-separator-1,
#findsearchwords-separator-3 {
display: none;
}
#findsearchwords-find-button {
list-style-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAQCAYAAABQrvyxAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH1wEYAScNzpR0GAAABIBJREFUeNrNll1sVEUUx3/37t0uLbv9oOy21G13EWkh6jZggBCNMSZEATW+UDQkmmJMjCaS+OST8dH4BKE81JgGiS8QMWiiQU2MEomFVkWw0BKQ2k+2S/ej3b337t6ZOz5sWwrZbXkwqSc5uZlJfmfmP2fOnaNRtDDQAHhY2qaAEcC9b36leZ6wbTvtOI4UQqhSbtu26urqOgJEAf1/xrPdcRyZzWZVLpdb8Ewmo1KplIrH40oIoSYnJ9WxY8dKBVlRXgO2CyGUZVkqn88ry7KUZVlqdnZWpdNpNTU1pYQQyjRNlc1mVXd393yQFee1Od8mhLggpVw4Etd1UUohhCCfz1NXV3dPygzD2AH0zQ3/ez45Bdd+Q7tyETebwa1cjR7bifH4DvT60AJvLA6q6zqaphWPRdMYHR3Fsix8Ph/AwoZCoVDJCruX1/l1RDJr6dT7DB4h9eB8KoF95jM8NdX4HmtfqGw7PoJ58hK1r751l1kcYH5xpRTxeJyamhqampoQQjA6OophGAtiStldHq7EFc21OrEmL6aj0fuP+0C8St0h+8WnVLVuxJA2hfPfYzzbgf3zWbzCJtDWRvJEFwc2tzxEqWoGGB4eprKyklwuRyaToaqqimAwSH9/P16vl+Xs/LBD3SpFMieYyAiq/RU0h/ycvJBalpeXe/HUVCPHbiH/HkS5qnilhIt99Sr29Rvoq6vp2LDu+bICstlsMZiUCCGwLAuPx0MqlcIwjGUFJGfzaBoUhCIvFDOmxGN4uJ00l+ULf5xnVUMj4tZ1XKlQwl0Q4DoS5+YQ/uYw61YZe8oK8Pv9TExMoGkaQggCgQCDg4PMzMyQTqeXFdDoh8GxLPqciGDA4OLAJKGZfuz05JKsk0wUr6FwcYWLFMUMyIKLdIpzALrrBssKiEaj5PN5dF0nEAgwNDREMpmkvr6enp4eEonEkpvYtn41ll3A64FQjcHFq7fJTt/mmYZJ+o+/RzYxUl6Ar6r4tQSOKXBMh5meI8Xx3BzAbM5MlBWgaRrt7e0MDAxw7tw5xsbGyOVyhMNhWlpaOHz4MLFYLLJUMb6wtZ5f/hzn1A9DiInfebLwJfXNG1nb0saPRw+yZ8uaknzFlqfIjYxT0bqpmAHHpfrgIVzHRQqXirZNpG4MMzxjfltWwPwvbdeuXezbt4+Ojg4A+vr6iEQiRKNRYrHYJ0tlQdd13t69ng8PPErnK7sRGNzs/45QcxvrIq28vNVfkq/c9jRmfAqtIYIeacUVLsmjHyOli691M77ow5h3pjgzcufs/QJUqZPUNA3DMNi/fz+6rtPb20s4HEYIUXsfU5b3GBVs7fgAx1PFYP9ZQuENSFEoyXuDjYTeOETyr8s4Xi/Vz+3F19TImhdfwvFVkLhyici777tfjafGAaXPga6U0irV5S16Oens7MTr9arTp08zPT19fNHCy/K64WXnax8hKwLqp6+7GU+a5fm6IHWvv0MhuJZr35zi0okuLp/5HKuuluCbh1xZvcYE5HwrAdA8187qPJjJudZ2dKX5fwEPJ3wWzuanmQAAAABJRU5ErkJggg==");
-moz-image-region: rect(0px 32px 16px 16px);
}
#findsearchwords-find-button.findsearchwords-notfound {
-moz-image-region: rect(0px 48px 16px 32px);
}
#findsearchwords-find-button[disabled] {
-moz-image-region: rect(0px 16px 16px 0px);
}
]]>.toString().replace(/\s+/g, " ")
};
var gFindSearchWords = {
init: function FSW_init() {
var sspi =
document.createProcessingInstruction(
"xml-stylesheet",
"type=\"text/css\" href=\"data:text/css," +
encodeURI(gFSWPrefs.style) + "\"")
document.insertBefore(sspi, document.documentElement);
// XXX Workaround for Firefox 2
sspi.getAttribute = new Function("name",
"return document.documentElement.getAttribute(name);");
var overlay =
;
if (gFSWPrefs.insertBefore)
overlay..kXULNS::toolbaritem.@insertbefore = gFSWPrefs.insertBefore;
if (gFSWPrefs.insertAfter)
overlay..kXULNS::toolbaritem.@insertafter = gFSWPrefs.insertAfter;
var overlayURI = "data:application/vnd.mozilla.xul+xml;charset=utf-8," +
encodeURI(overlay.toXMLString());
document.loadOverlay(overlayURI, null);
var searchBar = document.getElementById("searchbar");
searchBar.addEventListener("input", gFSWToolbar, false);
searchBar.addEventListener("input", gFSWFinder, false);
addEventListener("resize", gFSWToolbar, false);
},
handleEvent: function FSW_handleEvent(aEvent) {
switch (aEvent.type) {
case "input":
gFSWToolbar.update();
break;
case "resize":
gFSWToolbar.refresh();
break;
}
}
};
var gFSWToolbar = {
_searchString: null,
_timerId: 0,
_needsUpdate: false,
_prevWidth: 0,
_prevHeight: 0,
handleEvent: function FSWT_handleEvent(aEvent) {
switch (aEvent.type) {
case "input":
this._searchString = aEvent.target.value;
if (this._timerId)
this._needsUpdate = true;
else
this.update();
break;
case "resize":
// XXX A resize event fires not only when window size changes
// but also when toolbar size changes. So we have to check
// window size to detect window size change.
if (this._prevWidth == document.width &&
this._prevHeight == document.height)
return;
this._prevWidth = document.width;
this._prevHeight = document.height;
this._maybeUpdate(this, true);
break;
}
},
get _container() {
return document.getElementById("findsearchwords-container");
},
get _buttonBox() {
return document.getElementById("findsearchwords-button-box");
},
get _chevron() {
return document.getElementById("findsearchwords-chevron");
},
get _popup() {
return document.getElementById("findsearchwords-popup");
},
_wordsList: [],
_searchWordRE: new RegExp(
"\\s*(([()+-]?)(?:(?:" +
"allinanchor|allintext|allintitle|allinurl|author|bphonebook|cache|" +
"define|ext|filetype|group|id|inanchor|info|insubject|intext|intitle|" +
"inurl|link|location|movie|msgid|phonebook|related|rphonebook|" +
"safesearch|site|source|stocks|store|weather" +
"):)?(?:\"([^\"]*)\"|(\\S+)))", "g"
),
update: function FSWT_update() {
this._wordsList.length = 0;
var match = null;
var added = {};
while ((match = this._searchWordRE.exec(this._searchString))) {
if (match[2] == "-" || match[1] == "OR" || match[1] == "AND")
continue;
var phrase = null;
var words = [];
if (match[4]) {
phrase = match[4].replace(/[()]$/, "");
words.push(phrase);
phrase = phrase.replace(/^-+/, "").replace(/-+$/, "")
var terms = phrase.split(/-+/);
if (terms.length >= 2) {
words.push(terms.join(" "), terms.join(""));
words.push.apply(words, terms);
}
} else {
phrase = match[3];
words.push(phrase);
}
var lowerPhrase = phrase.toLowerCase();
if (!phrase || lowerPhrase in added) continue;
added[lowerPhrase] = true;
this._wordsList.push(words);
}
if (this._wordsList.length) {
this._container.className = "";
} else {
this._container.className = "findsearchwords-empty";
gFSWFinder.enable(false);
}
this.refresh();
},
_buttonCount: 0,
refresh: function FSWT_refresh() {
this._clear();
this._needsUpdate = false;
this._timerId = setTimeout(this._maybeUpdate, gFSWPrefs.updateInterval,
this, false);
var wordsCount = this._wordsList.length;
if (!wordsCount) return;
var buttonBox = this._buttonBox;
var buttons = buttonBox.childNodes;
var preparedButtonCount = buttons.length;
var parentBox = this._container.parentNode.boxObject;
var parentWidth = parentBox.width;
// XXX Hmmm... Sometimes the right edge of the rightmost box is
// 1px larger than its parent's width.
parentWidth += 2;
var [leftmostBox, rightmostBox] = this._getEdgeBoxes(parentBox);
for (var i = 0; i < wordsCount; i++) {
var words = this._wordsList[i];
var button = null;
if (i < preparedButtonCount) {
button = buttons[i];
if (button.fswWords.join("\0") != words.join("\0"))
this._updateButton(button, words);
button.hidden = false;
} else {
button = this._createButton(words);
buttonBox.appendChild(button);
}
this._buttonCount++;
if (rightmostBox.x + rightmostBox.width > parentWidth ||
leftmostBox.x < 0) {
this._chevron.hidden = false;
do {
button.hidden = true;
button = button.previousSibling;
this._buttonCount--;
} while ((rightmostBox.x + rightmostBox.width > parentWidth ||
leftmostBox.x < 0) && button);
break;
}
}
},
_clear: function FSWT__clear() {
var buttons = this._buttonBox.childNodes;
for (var i = 0; i < this._buttonCount; i++)
buttons[i].hidden = true;
this._buttonCount = 0;
var popup = this._popup
var menu = null;
while ((menu = popup.firstChild))
popup.removeChild(menu);
this._chevron.hidden = true;
},
_getEdgeBoxes: function FSWT__getEdgeBoxes(aParentBox) {
var { firstChild: firstChild, lastChild: lastChild } = aParentBox;
if (!firstChild) return [null, null];
var firstBox = firstChild.boxObject, lastBox = lastChild.boxObject;
return (firstBox.x < lastBox.x) ? [firstBox, lastBox] : [lastBox, firstBox];
},
_updateButton: function FSWT__updateButton(aButton, aWords) {
aButton.label = aWords[0];
aButton.fswWords = aWords;
if (aWords.length == 1) {
aButton.removeAttribute("type");
} else {
aButton.type = "menu";
var popup = this._createSubPopup(aWords);
if (aButton.hasChildNodes())
aButton.replaceChild(popup, aButton.firstChild);
else
aButton.appendChild(popup);
}
},
_createButton: function FSWT__createButton(aWords) {
var button = document.createElementNS(kXULNS, "toolbarbutton");
button.className = "findsearchwords-button";
button.setAttribute("label", aWords[0]);
button.setAttribute("oncommand", "gFSWToolbar.onCommand(event);");
if (aWords.length > 1) {
button.setAttribute("type", "menu");
button.appendChild(this._createSubPopup(aWords));
}
button.fswWords = aWords;
return button;
},
updatePopup: function FSWT_updatePopup(aPopup) {
if (aPopup.hasChildNodes()) return;
for (var i = this._buttonCount; i < this._wordsList.length; i++) {
var words = this._wordsList[i];
var menu = null;
if (words.length == 1) {
menu = document.createElementNS(kXULNS, "menuitem");
menu.className = "menuitem-iconic findsearchwords-menu";
} else {
menu = document.createElementNS(kXULNS, "menu");
menu.className = "menu-iconic findsearchwords-menu";
menu.appendChild(this._createSubPopup(words));
}
menu.setAttribute("label", words[0]);
aPopup.appendChild(menu);
}
},
_createSubPopup: function FSWT__createSubPopup(aWords) {
var popup = document.createElementNS(kXULNS, "menupopup");
for (var i = 0; i < aWords.length; i++) {
var menu = document.createElementNS(kXULNS, "menuitem");
menu.setAttribute("label", aWords[i]);
popup.appendChild(menu);
}
return popup;
},
_maybeUpdate: function FSWT__maybeUpdate(aThis, aForceRefresh) {
if (aThis._timerId) {
clearTimeout(aThis._timerId)
aThis._timerId = 0;
}
if (aThis._needsUpdate)
aThis.update();
else if (aForceRefresh)
aThis.refresh();
},
onCommand: function FSWT_onCommand(aEvent) {
gFSWFinder.find(aEvent.target.label, aEvent);
}
};
var gFSWFinder = {
handleEvent: function FSWF_handleEvent(aEvent) {
if (!aEvent.target.value)
this.enable(false);
},
get _command() {
return document.getElementById("cmd_fsw_find");
},
_searchString: null,
find: function FSWF_find(aSearchString, aEvent) {
this._searchString = aSearchString;
this.enable(true);
this.findAgain(aEvent);
},
findAgain: function FSWF_findAgain(aEvent) {
var finder = gBrowser.webBrowserFind;
finder.searchString = this._searchString;
finder.matchCase = aEvent.ctrlKey;
finder.findBackwards = aEvent.shiftKey;
finder.wrapFind = true;
var currentWin = document.commandDispatcher.focusedWindow;
var selection = currentWin.getSelection();
var prevRange = null;
if (selection.rangeCount) {
prevRange = selection.getRangeAt(0);
if (prevRange.toString().toLowerCase() !=
this._searchString.toLowerCase())
prevRange = null;
}
var succeed = finder.findNext();
var message = null;
if (succeed) {
this._command.className = "";
if (prevRange) {
var currentRange = currentWin.getSelection().getRangeAt(0);
var position =
currentRange.compareBoundaryPoints(Range.START_TO_START, prevRange);
if (finder.findBackwards) {
if (position >= 0) message = gFSWPrefs.wrappedToBottomMessage;
} else {
if (position <= 0) message = gFSWPrefs.wrappedToTopMessage;
}
}
} else {
this._command.className = "findsearchwords-notfound";
message = gFSWPrefs.notFoundMessage.replace("%s", this._searchString);
}
if (this._timerId) {
clearTimeout(this._timerId);
if (!message)
this._hideMessage(this, null);
}
if (message)
this._showMessage(message);
},
_timerId: 0,
_showMessage: function FSWF__showMessage(aMessage) {
XULBrowserWindow.setOverLink(aMessage);
var sound = Cc["@mozilla.org/sound;1"].createInstance(Ci.nsISound);
sound.beep();
this._timerId = setTimeout(this._hideMessage,
gFSWPrefs.messageDisplayTime,
this, aMessage);
},
_hideMessage: function FSWF__hideMessage(aThis, aMessage) {
aThis._timerId = 0;
aThis._command.className = "";
if (!aMessage || XULBrowserWindow.overLink == aMessage)
XULBrowserWindow.setOverLink("");
},
enable: function FSWF_enable(aEnable) {
var command = this._command;
command.className = "";
if (aEnable) {
command.removeAttribute("disabled");
command.tooltipText = gFSWPrefs.findEnabledTooltip
.replace("%s", this._searchString);
} else {
command.setAttribute("disabled", "true");
command.tooltipText = gFSWPrefs.findDisabledTooltip;
}
}
};
gFindSearchWords.init();