diff --git a/locales/en-US/chrome/chatzilla.properties b/locales/en-US/chrome/chatzilla.properties --- a/locales/en-US/chrome/chatzilla.properties +++ b/locales/en-US/chrome/chatzilla.properties @@ -691,16 +691,21 @@ cmd.usermode.params = [] cmd.usermode.help = Changes or displays the current user mode. cmd.user-motif.params = [ []] cmd.user-motif.help = Sets the CSS file used for the message tab for the user . can be a URL to a .css file, or the shortcut "dark" or "light". If is a minus ('-') character, the motif will revert to the network motif. If is not provided, the current user is assumed. See the ChatZilla homepage at for more information on how to style ChatZilla. See also |motif|. cmd.user-pref.params = [ []] cmd.user-pref.help = Sets the value of the preference named to the value of on the current user. If is not provided, the current value of will be displayed. If both and are omitted, all preferences will be displayed. If is a minus ('-') character, then the preference will revert back to its default value. +cmd.websearch.help = Runs a web search for the currently-selected text. +cmd.websearch.params = +cmd.websearch.format = Search the web for "$selectedText"" +cmd.websearch.label = Search the web + cmd.version.label = Get Version Information cmd.version.params = [] cmd.version.help = Asks what irc client they're running. Their IRC client may or may not show them that you've asked for this information. ChatZilla currently does not. If you do not specify , ChatZilla will ask the server for the version of the IRCserver software it is running. cmd.voice.label = Give Voice Status cmd.voice.params = [<...>] cmd.voice.help = Gives voice status to on current channel. Requires operator (or half-operator) status. @@ -1597,16 +1602,18 @@ pref.outgoing.colorCodes.help = Allows pref.outputWindowURL.label = Output Window pref.outputWindowURL.help = You probably don't want to change this. The chat view loads this URL to display the actual messages, header, etc., and the file must correctly define certain items or you'll get JavaScript errors and a blank chat window! pref.profilePath.label = Profile path pref.profilePath.help = This is the base location for ChatZilla-related files. By default, ChatZilla loads scripts from the "scripts" subdirectory, and stores log files in the "logs" subdirectory. pref.proxy.typeOverride.label = Proxy Type pref.proxy.typeOverride.help = Override the normal proxy choice by specifying "http" to use your browser's HTTP Proxy or "none" to force no proxy to be used (not even the SOCKS proxy). Note that this usually only works when the browser is set to use a manual proxy configuration. pref.reconnect.label = Reconnect when disconnected unexpectedly pref.reconnect.help = When your connection is lost unexpectedly, ChatZilla can automatically reconnect to the server for you. +pref.websearch.url.label = Web search URL +pref.websearch.url.help = The URL to use when running a web search; your search terms will be appended to this URL. You can include the optional parameter %s to insert your search terms in a specific part of the URL instead (e.g. "http://www.searchwebsite.com/search?q=%s"). If this field is left blank, your browser's search engine will be used (or Google, if Chatzilla is not running as a browser plugin). pref.showModeSymbols.label = Show user mode symbols pref.showModeSymbols.help = The userlist can either show mode symbols ("@" for op, "%" for half-op, "+" for voice), or it can show colored dots (green for op, dark blue for half-op, cyan for voice, and black for normal). Turn this preference on to show mode symbols instead of colored dots. pref.sortUsersByMode.label = Sort users by mode pref.sortUsersByMode.help = Causes the userlist to be sorted by mode, op first, then half-op (if supported on the server), then voice, followed by everyone else. pref.sound.enabled.label = Enabled pref.sound.enabled.help = Tick this preference to allow sound, or untick to turn off all sounds. Provides nothing more than a global toggle. pref.sound.overlapDelay.label = Overlap Delay pref.sound.overlapDelay.help = Sets the period of time during which the same event will not trigger the sound to be played. For example, the default value of 2000ms (2 seconds) means if two stalk matches occur within 2 seconds of each other, only the first will cause the sound to be played. diff --git a/xul/content/commands.js b/xul/content/commands.js --- a/xul/content/commands.js +++ b/xul/content/commands.js @@ -172,16 +172,17 @@ function initCommands() ["urls", cmdURLs, CMD_CONSOLE], ["user", cmdUser, CMD_CONSOLE], ["userhost", cmdUserhost, CMD_NEED_SRV | CMD_CONSOLE], ["userip", cmdUserip, CMD_NEED_SRV | CMD_CONSOLE], ["usermode", cmdUsermode, CMD_CONSOLE], ["user-motif", cmdMotif, CMD_NEED_USER | CMD_CONSOLE], ["user-pref", cmdPref, CMD_NEED_USER | CMD_CONSOLE], ["version", cmdVersion, CMD_NEED_SRV | CMD_CONSOLE], + ["websearch", cmdWebSearch, CMD_CONSOLE], ["who", cmdWho, CMD_NEED_SRV | CMD_CONSOLE], ["whois", cmdWhoIs, CMD_NEED_SRV | CMD_CONSOLE], ["whowas", cmdWhoWas, CMD_NEED_SRV | CMD_CONSOLE], ["wii", cmdWhoIsIdle, CMD_NEED_SRV | CMD_CONSOLE], /* aliases */ ["exit", "quit", CMD_CONSOLE], ["j", "join", CMD_CONSOLE], @@ -242,17 +243,18 @@ function initCommands() client.commandManager = new CommandManager(client.defaultBundle); client.commandManager.defaultFlags = CMD_NO_HELP | CMD_CONSOLE; client.commandManager.isCommandSatisfied = isCommandSatisfied; client.commandManager.defineCommands(cmdary); var restList = ["reason", "action", "text", "message", "params", "font", "expression", "ircCommand", "prefValue", "newTopic", "file", - "password", "commandList", "commands", "description"]; + "password", "commandList", "commands", "description", + "selectedText"]; var stateList = ["connect"]; client.commandManager.argTypes.__aliasTypes__(restList, "rest"); client.commandManager.argTypes.__aliasTypes__(stateList, "state"); client.commandManager.argTypes["plugin"] = parsePlugin; } function isCommandSatisfied(e, command) @@ -4611,8 +4613,38 @@ function cmdURLs(e) display(getMsg(MSG_URLS_HEADER, num)); for (var i = 0; i < num; i++) display(getMsg(MSG_URLS_ITEM, [i + 1, urls[i]])); client.urlLogger = logger; } } + +function cmdWebSearch(e) +{ + var searchText = e.selectedText; + var searchURL; + const SEARCH_SVC = "@mozilla.org/browser/search-service;1"; + var nibss = getService(SEARCH_SVC, "nsIBrowserSearchService"); + var engine = nibss.currentEngine; + + if (client.prefs["websearch.url"]) + { + searchText = encodeURIComponent(searchText).replace(/%20/g, "+"); + var baseURL = client.prefs["websearch.url"]; + + if (baseURL.indexOf("%s") != -1) + searchURL = baseURL.replace(/%s/g, searchText); + else + searchURL = baseURL + searchText; + } + else if (engine) + { + searchURL = engine.getSubmission(searchText).uri.asciiSpec; + } + else + { + searchText = encodeURIComponent(searchText).replace(/%20/g, "+"); + searchURL = "https://www.google.com/search?q=" + searchText; + } + dispatch(client.prefs["messages.click"], {url: searchURL}); +} diff --git a/xul/content/handlers.js b/xul/content/handlers.js --- a/xul/content/handlers.js +++ b/xul/content/handlers.js @@ -637,20 +637,34 @@ function onWindowKeyPress(e) if (!e.altKey && !e.ctrlKey && !e.metaKey) { advanceKeyboardFocus(e.shiftKey ? -1 : 1); e.preventDefault(); } break; } - // Code is zero if we have an alphanumeric being given to us in the event. + // Code is zero if we have a typeable character triggering the event. if (code != 0) return; + // OS X only: Command-{ and Command-} + // Newer geckos seem to only provide these keys in charCode, not keyCode + if (isMac && e.metaKey && e.shiftKey && !e.altKey && !e.ctrlKey) + { + if (e.charCode == 123 || e.charCode == 125) + { + cycleView(e.charCode - 124); + e.preventDefault(); + return; + } + } + + // Numeric shortcuts + // The following code is copied from: // /mozilla/browser/base/content/browser.js // Revision: 1.748 // Lines: 1397-1421 // \d in a RegExp will find any Unicode character with the "decimal digit" // property (Nd) var regExp = /\d/; diff --git a/xul/content/menus.js b/xul/content/menus.js --- a/xul/content/menus.js +++ b/xul/content/menus.js @@ -365,16 +365,17 @@ function initMenus() items: [ ["goto-url", {visibleif: urlenabled}], ["goto-url-newwin", {visibleif: urlexternal + " && !" + XULRunner}], ["goto-url-newtab", {visibleif: urlexternal + " && !" + XULRunner}], ["cmd-copy-link-url", {visibleif: urlenabled}], ["cmd-copy", {visibleif: "!" + urlenabled, enabledif: textselected }], ["cmd-selectall", {visibleif: "!" + urlenabled }], + ["websearch", {visibleif: textselected}], ["-", {visibleif: "cx.nickname"}], ["label-user", {visibleif: "cx.nickname", header: true}], [">popup:opcommands", {visibleif: "cx.channel && cx.nickname", enabledif: isopish + "cx.user"}], [">popup:usercommands", {visibleif: "cx.nickname"}], ["-"], ["clear-view"], ["hide-view", {enabledif: "client.viewsArray.length > 1"}], diff --git a/xul/content/prefs.js b/xul/content/prefs.js --- a/xul/content/prefs.js +++ b/xul/content/prefs.js @@ -204,16 +204,17 @@ function initPrefs() ["nickname", defaultNick, ".ident"], ["nicknameList", [], "lists.nicknameList"], ["notify.aggressive", true, "global"], ["outgoing.colorCodes", true, "global"], ["outputWindowURL", "chrome://chatzilla/content/output-window.html", "hidden"], ["proxy.typeOverride", "", ".connect"], ["reconnect", true, ".connect"], + ["websearch.url", "", "global"], ["showModeSymbols", false, "appearance.userlist"], ["sortUsersByMode", true, "appearance.userlist"], // Chat == "Activity" activity. // Event == "Superfluous" activity. // Stalk == "Attention" activity. // Start == When view it opened. ["sound.channel.chat", "", "global.soundEvts"], ["sound.channel.event", "", "global.soundEvts"], diff --git a/xul/content/static.js b/xul/content/static.js --- a/xul/content/static.js +++ b/xul/content/static.js @@ -1610,16 +1610,18 @@ function getObjectDetails (obj, rv) rv.sourceObject = obj; rv.TYPE = obj.TYPE; rv.parent = ("parent" in obj) ? obj.parent : null; rv.user = null; rv.channel = null; rv.server = null; rv.network = null; + if (window && window.content && window.content.getSelection() != "") + rv.selectedText = window.content.getSelection(); switch (obj.TYPE) { case "IRCChannel": rv.viewType = MSG_CHANNEL; rv.channel = obj; rv.channelName = obj.unicodeName; rv.server = rv.channel.parent; @@ -3771,48 +3773,62 @@ function updateTabAttributes() tab.removeAttribute(attr); } } } // Properties getter for user list tree view function ul_getrowprops(index, properties) { - if ((index < 0) || (index >= this.childData.childData.length) || - !properties) - { - return; + if ((index < 0) || (index >= this.childData.childData.length)) + { + return ""; } // See bug 432482 - work around Gecko deficiency. if (!this.selection.isSelected(index)) + { + if (!properties) + return "unselected"; + properties.AppendElement(client.atomCache["unselected"]); + } + + return ""; } // Properties getter for user list tree view function ul_getcellprops(index, column, properties) { - if ((index < 0) || (index >= this.childData.childData.length) || - !properties) - { - return; - } + if ((index < 0) || (index >= this.childData.childData.length)) + { + return ""; + } + + var resultProps = []; // See bug 432482 - work around Gecko deficiency. if (!this.selection.isSelected(index)) - properties.AppendElement(client.atomCache["unselected"]); + resultProps.push("unselected"); var userObj = this.childData.childData[index]._userObj; - properties.AppendElement(client.atomCache["voice-" + userObj.isVoice]); - properties.AppendElement(client.atomCache["op-" + userObj.isOp]); - properties.AppendElement(client.atomCache["halfop-" + userObj.isHalfOp]); - properties.AppendElement(client.atomCache["admin-" + userObj.isAdmin]); - properties.AppendElement(client.atomCache["founder-" + userObj.isFounder]); - properties.AppendElement(client.atomCache["away-" + userObj.isAway]); + resultProps.push("voice-" + userObj.isVoice); + resultProps.push("op-" + userObj.isOp); + resultProps.push("halfop-" + userObj.isHalfOp); + resultProps.push("admin-" + userObj.isAdmin); + resultProps.push("founder-" + userObj.isFounder); + resultProps.push("away-" + userObj.isAway); + + if (!properties) + return resultProps.join(" "); + + resultProps.forEach(function (element) { + properties.AppendElement(client.atomCache[element]); + }); } var contentDropObserver = new Object(); contentDropObserver.onDragOver = function cdnd_dover(aEvent, aFlavour, aDragSession) { if (aEvent.getPreventDefault()) diff --git a/xul/lib/tree-utils.js b/xul/lib/tree-utils.js --- a/xul/lib/tree-utils.js +++ b/xul/lib/tree-utils.js @@ -140,26 +140,29 @@ function bov_setsel(i) * functions the tree will call to retrieve the list state (nsITreeView.) */ BasicOView.prototype.rowCount = 0; BasicOView.prototype.getCellProperties = function bov_cellprops (row, col, properties) { + return ""; } BasicOView.prototype.getColumnProperties = function bov_colprops (col, properties) { + return ""; } BasicOView.prototype.getRowProperties = function bov_rowprops (index, properties) { + return ""; } BasicOView.prototype.isContainer = function bov_isctr (index) { return false; } @@ -1475,27 +1478,33 @@ function xtv_getcelltxt (index, col) return row._colValues[col]; else return ""; } // @internal XULTreeView.prototype.getCellProperties = function xtv_cellprops (row, col, properties) -{} +{ + return ""; +} // @internal XULTreeView.prototype.getColumnProperties = function xtv_colprops (col, properties) -{} +{ + return ""; +} // @internal XULTreeView.prototype.getRowProperties = function xtv_rowprops (index, properties) -{} +{ + return ""; +} // @internal XULTreeView.prototype.isSorted = function xtv_issorted (index) { return false; }