patch by pierrechanial@netscape.net r=rginda,timeless sr=jag git-svn-id: svn://10.0.0.236/trunk@124922 18797224-902f-48f8-a5cc-f745e15eee43
2772 lines
85 KiB
JavaScript
2772 lines
85 KiB
JavaScript
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code is ChatZilla
|
|
*
|
|
* The Initial Developer of the Original Code is New Dimensions Consulting,
|
|
* Inc. Portions created by New Dimensions Consulting, Inc. are
|
|
* Copyright (C) 1999 New Dimenstions Consulting, Inc. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Robert Ginda, rginda@ndcico.com, original author
|
|
* Chiaki Koufugata chiaki@mozilla.gr.jp UI i18n
|
|
* Samuel Sieb, samuel@sieb.net, MIRC color code, munger menu, and various
|
|
*/
|
|
|
|
if (DEBUG)
|
|
dd = function (m) { dump ("-*- chatzilla: " + m + "\n"); }
|
|
else
|
|
dd = function (){};
|
|
|
|
var client = new Object();
|
|
|
|
const MSG_CSP = getMsg ("commaSpace", " ");
|
|
const MSG_NONE = getMsg ("none");
|
|
const MSG_UNKNOWN = getMsg ("unknown");
|
|
|
|
client.defaultNick = getMsg( "defaultNick" );
|
|
|
|
client.version = "0.8.8";
|
|
|
|
client.TYPE = "IRCClient";
|
|
client.COMMAND_CHAR = "/";
|
|
client.STEP_TIMEOUT = 500;
|
|
client.MAX_MESSAGES = 200;
|
|
client.MAX_HISTORY = 50;
|
|
/* longest nick to show in display before forcing the message to a block level
|
|
* element */
|
|
client.MAX_NICK_DISPLAY = 14;
|
|
/* longest word to show in display before abbreviating */
|
|
client.MAX_WORD_DISPLAY = 20;
|
|
client.PRINT_DIRECTION = 1; /*1 => new messages at bottom, -1 => at top */
|
|
client.ADDRESSED_NICK_SEP = ":";
|
|
|
|
client.MAX_MSG_PER_ROW = 3; /* default number of messages to collapse into a
|
|
* single row, max. */
|
|
client.INITIAL_COLSPAN = 5; /* MAX_MSG_PER_ROW cannot grow to greater than
|
|
* one half INITIAL_COLSPAN + 1. */
|
|
client.COLLAPSE_ROWS = false;
|
|
client.NOTIFY_TIMEOUT = 5 * 60 * 1000; /* update notify list every 5 minutes */
|
|
|
|
client.SLOPPY_NETWORKS = true; /* true if msgs from a network can be displayed
|
|
* on the current object if it is related to
|
|
* the network (ie, /whois results will appear
|
|
* on the channel you're viewing, if that channel
|
|
* is on the network that the results came from)
|
|
*/
|
|
client.DOUBLETAB_TIME = 500;
|
|
client.IMAGEDIR = "chrome://chatzilla/skin/images/";
|
|
client.HIDE_CODES = true; /* true if you'd prefer to show numeric response
|
|
* codes as some default value (ie, "===") */
|
|
client.DEFAULT_RESPONSE_CODE = "===";
|
|
|
|
|
|
/* XXX maybe move this into css */
|
|
client.responseCodeMap = new Object();
|
|
client.responseCodeMap["HELLO"] = getMsg("responseCodeMapHello");
|
|
client.responseCodeMap["HELP"] = getMsg("responseCodeMapHelp");
|
|
client.responseCodeMap["USAGE"] = getMsg("responseCodeMapUsage");
|
|
client.responseCodeMap["ERROR"] = getMsg("responseCodeMapError");
|
|
client.responseCodeMap["WARNING"] = getMsg("responseCodeMapWarning");
|
|
client.responseCodeMap["INFO"] = getMsg("responseCodeMapInfo");
|
|
client.responseCodeMap["EVAL-IN"] = getMsg("responseCodeMapEvalIn");
|
|
client.responseCodeMap["EVAL-OUT"] = getMsg("responseCodeMapEvalOut");
|
|
client.responseCodeMap["JOIN"] = "-->|";
|
|
client.responseCodeMap["PART"] = "<--|";
|
|
client.responseCodeMap["QUIT"] = "|<--";
|
|
client.responseCodeMap["NICK"] = "=-=";
|
|
client.responseCodeMap["TOPIC"] = "=-=";
|
|
client.responseCodeMap["KICK"] = "=-=";
|
|
client.responseCodeMap["MODE"] = "=-=";
|
|
client.responseCodeMap["END_STATUS"] = "---";
|
|
client.responseCodeMap["315"] = "---"; /* end of WHO */
|
|
client.responseCodeMap["318"] = "---"; /* end of WHOIS */
|
|
client.responseCodeMap["366"] = "---"; /* end of NAMES */
|
|
client.responseCodeMap["376"] = "---"; /* end of MOTD */
|
|
|
|
client.name = getMsg("clientname");
|
|
client.viewsArray = new Array();
|
|
client.activityList = new Object();
|
|
client.uiState = new Object(); /* state of ui elements (visible/collapsed) */
|
|
client.inputHistory = new Array();
|
|
client.lastHistoryReferenced = -1;
|
|
client.incompleteLine = "";
|
|
client.lastTabUp = new Date();
|
|
client.stalkingVictims = new Array();
|
|
|
|
CIRCNetwork.prototype.INITIAL_NICK = client.defaultNick;
|
|
CIRCNetwork.prototype.INITIAL_NAME = "chatzilla";
|
|
CIRCNetwork.prototype.INITIAL_DESC = getMsg("circnetworkInitialDesc");
|
|
CIRCNetwork.prototype.INITIAL_CHANNEL = "";
|
|
CIRCNetwork.prototype.MAX_MESSAGES = 100;
|
|
CIRCNetwork.prototype.IGNORE_MOTD = false;
|
|
|
|
CIRCServer.prototype.READ_TIMEOUT = 0;
|
|
CIRCServer.prototype.VERSION_RPLY = getMsg("circserverVersionRply",
|
|
[client.version,
|
|
navigator.userAgent]);
|
|
CIRCUser.prototype.MAX_MESSAGES = 200;
|
|
|
|
CIRCChannel.prototype.MAX_MESSAGES = 300;
|
|
|
|
CIRCChanUser.prototype.MAX_MESSAGES = 200;
|
|
|
|
window.onresize =
|
|
function ()
|
|
{
|
|
scrollDown();
|
|
}
|
|
|
|
function ucConvertIncomingMessage (e)
|
|
{
|
|
e.meat = toUnicode(e.meat);
|
|
return true;
|
|
}
|
|
|
|
function toUnicode (msg)
|
|
{
|
|
if (!("ucConverter" in client))
|
|
return msg;
|
|
|
|
/* XXX set charset again to force the encoder to reset, see bug 114923 */
|
|
client.ucConverter.charset = client.CHARSET;
|
|
return client.ucConverter.ConvertToUnicode(msg);
|
|
}
|
|
|
|
function fromUnicode (msg)
|
|
{
|
|
if (!("ucConverter" in client))
|
|
return msg;
|
|
|
|
/* XXX set charset again to force the encoder to reset, see bug 114923 */
|
|
client.ucConverter.charset = client.CHARSET;
|
|
return client.ucConverter.ConvertFromUnicode(msg);
|
|
}
|
|
|
|
function setCharset (charset)
|
|
{
|
|
client.CHARSET = charset;
|
|
|
|
if (!charset)
|
|
{
|
|
delete client.ucConverter;
|
|
client.eventPump.removeHookByName("uc-hook");
|
|
return true;
|
|
}
|
|
|
|
var ex;
|
|
|
|
try
|
|
{
|
|
|
|
if (!("ucConverter" in client))
|
|
{
|
|
const UC_CTRID = "@mozilla.org/intl/scriptableunicodeconverter";
|
|
const nsIUnicodeConverter =
|
|
Components.interfaces.nsIScriptableUnicodeConverter;
|
|
client.ucConverter =
|
|
Components.classes[UC_CTRID].getService(nsIUnicodeConverter);
|
|
}
|
|
|
|
client.ucConverter.charset = charset;
|
|
|
|
if (!client.eventPump.getHook("uc-hook"))
|
|
{
|
|
client.eventPump.addHook ([{type: "parseddata", set: "server"}],
|
|
ucConvertIncomingMessage, "uc-hook");
|
|
}
|
|
}
|
|
catch (ex)
|
|
{
|
|
dd ("Caught exception setting charset to " + charset + "\n" + ex);
|
|
delete client.ucConverter;
|
|
client.CHARSET = "";
|
|
client.eventPump.removeHookByName("uc-hook");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
function initStatic()
|
|
{
|
|
var obj;
|
|
|
|
const nsISound = Components.interfaces.nsISound;
|
|
client.sound =
|
|
Components.classes["@mozilla.org/sound;1"].createInstance(nsISound);
|
|
|
|
if (client.CHARSET)
|
|
setCharset(client.CHARSET);
|
|
|
|
var ary = navigator.userAgent.match (/;\s*([^;\s]+\s*)\).*\/(\d+)/);
|
|
if (ary)
|
|
client.userAgent = "ChatZilla " + client.version + " [Mozilla " +
|
|
ary[1] + "/" + ary[2] + "]";
|
|
else
|
|
client.userAgent = "ChatZilla " + client.version + " [" +
|
|
navigator.userAgent + "]";
|
|
|
|
obj = document.getElementById("input");
|
|
obj.addEventListener("keypress", onInputKeyPress, false);
|
|
obj = document.getElementById("multiline-input");
|
|
obj.addEventListener("keypress", onMultilineInputKeyPress, false);
|
|
obj = document.getElementById("channel-topicedit");
|
|
obj.addEventListener("keypress", onTopicKeyPress, false);
|
|
obj.active = false;
|
|
|
|
window.onkeypress = onWindowKeyPress;
|
|
|
|
setMenuCheck ("menu-dmessages",
|
|
client.eventPump.getHook ("event-tracer").enabled);
|
|
setMenuCheck ("menu-munger-global", !client.munger.enabled);
|
|
setMenuCheck ("menu-colors", client.enableColors);
|
|
|
|
setupMungerMenu(client.munger);
|
|
|
|
client.uiState["tabstrip"] =
|
|
setMenuCheck ("menu-view-tabstrip", isVisible("view-tabs"));
|
|
client.uiState["info"] =
|
|
setMenuCheck ("menu-view-info", isVisible("user-list-box"));
|
|
client.uiState["header"] =
|
|
setMenuCheck ("menu-view-header", isVisible("header-bar-tbox"));
|
|
client.uiState["status"] =
|
|
setMenuCheck ("menu-view-status", isVisible("status-bar"));
|
|
|
|
client.statusBar = new Object();
|
|
|
|
client.statusBar["header-url"] =
|
|
document.getElementById ("header-url");
|
|
client.statusBar["server-nick"] =
|
|
document.getElementById ("server-nick");
|
|
client.statusBar["channel-mode"] =
|
|
document.getElementById ("channel-mode");
|
|
client.statusBar["channel-users"] =
|
|
document.getElementById ("channel-users");
|
|
client.statusBar["channel-topic"] =
|
|
document.getElementById ("channel-topic");
|
|
client.statusBar["channel-topicedit"] =
|
|
document.getElementById ("channel-topicedit");
|
|
|
|
client.statusElement = document.getElementById ("status-text");
|
|
client.defaultStatus = getMsg ("defaultStatus");
|
|
|
|
onSortCol ("usercol-nick");
|
|
|
|
client.display (getMsg("welcome"), "HELLO");
|
|
setCurrentObject (client);
|
|
|
|
client.onInputNetworks();
|
|
client.onInputCommands();
|
|
|
|
ary = client.INITIAL_VICTIMS.split(/\s*;\s*/);
|
|
for (i in ary)
|
|
{
|
|
if (ary[i])
|
|
client.stalkingVictims.push (ary[i]);
|
|
}
|
|
|
|
var m = document.getElementById ("menu-settings-autosave");
|
|
m.setAttribute ("checked", String(client.SAVE_SETTINGS));
|
|
|
|
var wentSomewhere = false;
|
|
|
|
if ("arguments" in window &&
|
|
0 in window.arguments && typeof window.arguments[0] == "object" &&
|
|
"url" in window.arguments[0])
|
|
{
|
|
url = window.arguments[0].url;
|
|
if (url.search(/^irc:\/?\/?$/i) == -1)
|
|
{
|
|
/* if the url is not irc: irc:/ or irc://, then go to it. */
|
|
gotoIRCURL (url);
|
|
wentSomewhere = true;
|
|
}
|
|
}
|
|
|
|
if (!wentSomewhere)
|
|
{
|
|
/* if we had nowhere else to go, connect to any default urls */
|
|
ary = client.INITIAL_URLS.split(/\s*;\s*/).reverse();
|
|
for (var i in ary)
|
|
{
|
|
if (ary[i] && ary[i] != "irc://")
|
|
gotoIRCURL (ary[i]);
|
|
}
|
|
}
|
|
|
|
if (client.viewsArray.length > 1 && !isStartupURL("irc://"))
|
|
{
|
|
var tb = getTabForObject (client);
|
|
deleteTab(tb);
|
|
}
|
|
|
|
setInterval ("onNotifyTimeout()", client.NOTIFY_TIMEOUT);
|
|
|
|
}
|
|
|
|
function setStatus (str)
|
|
{
|
|
client.statusElement.setAttribute ("label", str);
|
|
return str;
|
|
}
|
|
|
|
client.__defineSetter__ ("status", setStatus);
|
|
|
|
function getStatus ()
|
|
{
|
|
return client.statusElement.getAttribute ("label");
|
|
}
|
|
|
|
client.__defineGetter__ ("status", getStatus);
|
|
|
|
function setMenuCheck (id, state)
|
|
{
|
|
var m = document.getElementById(id);
|
|
m.setAttribute ("checked", String(Boolean(state)));
|
|
return state;
|
|
}
|
|
|
|
function isVisible (id)
|
|
{
|
|
var e = document.getElementById(id);
|
|
|
|
if (!e)
|
|
{
|
|
dd ("** Bogus id ``" + id + "'' passed to isVisible() **");
|
|
return false;
|
|
}
|
|
|
|
return (e.getAttribute ("collapsed") != "true");
|
|
}
|
|
|
|
function initHost(obj)
|
|
{
|
|
obj.commands = new CCommandManager();
|
|
addCommands (obj.commands);
|
|
|
|
obj.networks = new Object();
|
|
obj.eventPump = new CEventPump (200);
|
|
|
|
obj.defaultCompletion = client.COMMAND_CHAR + "help ";
|
|
|
|
obj.networks["efnet"] =
|
|
new CIRCNetwork ("efnet",
|
|
[{name: "irc.mcs.net", port: 6667},
|
|
{name: "irc.prison.net", port: 6667},
|
|
{name: "irc.freei.net", port: 6667},
|
|
{name: "irc.magic.ca", port: 6667}],
|
|
obj.eventPump);
|
|
obj.networks["moznet"] =
|
|
new CIRCNetwork ("moznet", [{name: "irc.mozilla.org", port: 6667}],
|
|
obj.eventPump);
|
|
obj.networks["hybridnet"] =
|
|
new CIRCNetwork ("hybridnet", [{name: "irc.ssc.net", port: 6667}],
|
|
obj.eventPump);
|
|
obj.networks["slashnet"] =
|
|
new CIRCNetwork ("slashnet", [{name: "irc.slashnet.org", port:6667}],
|
|
obj.eventPump);
|
|
obj.networks["dalnet"] =
|
|
new CIRCNetwork ("dalnet", [{name: "irc.dal.net", port:6667}],
|
|
obj.eventPump);
|
|
obj.networks["undernet"] =
|
|
new CIRCNetwork ("undernet", [{name: "irc.undernet.org", port:6667}],
|
|
obj.eventPump);
|
|
obj.networks["webbnet"] =
|
|
new CIRCNetwork ("webbnet", [{name: "irc.webbnet.org", port:6667}],
|
|
obj.eventPump);
|
|
obj.networks["quakenet"] =
|
|
new CIRCNetwork ("quakenet", [{name: "irc.quakenet.org", port:6667}],
|
|
obj.eventPump);
|
|
obj.networks["opennet"] =
|
|
new CIRCNetwork ("opennet",
|
|
[{name: "irc.openprojects.net", port:6667},
|
|
{name: "eu.opirc.nu", port:6667},
|
|
{name: "au.opirc.nu", port:6667},
|
|
{name: "us.opirc.nu", port:6667}],
|
|
obj.eventPump);
|
|
|
|
obj.primNet = obj.networks["efnet"];
|
|
|
|
if (DEBUG)
|
|
/* hook all events EXCEPT server.poll and *.event-end types
|
|
* (the 4th param inverts the match) */
|
|
obj.eventPump.addHook ([{type: "poll", set: /^(server|dcc-chat)$/},
|
|
{type: "event-end"}], event_tracer,
|
|
"event-tracer", true /* negate */,
|
|
false /* disable */);
|
|
|
|
obj.linkRE = /((\w+):[^<>\[\]()\'\"\s]+|www(\.[^.<>\[\]()\'\"\s]+){2,})/;
|
|
|
|
obj.munger = new CMunger();
|
|
obj.munger.enabled = true;
|
|
obj.munger.addRule ("link", obj.linkRE, insertLink);
|
|
obj.munger.addRule ("mailto",
|
|
/(?:\s|\W|^)((mailto:)?[^<>\[\]()\'\"\s]+@[^.<>\[\]()\'\"\s]+\.[^<>\[\]()\'\"\s]+)/i,
|
|
insertMailToLink);
|
|
obj.munger.addRule ("bugzilla-link", /(?:\s|\W|^)(bug\s+#?\d{3,6})/i,
|
|
insertBugzillaLink);
|
|
obj.munger.addRule ("channel-link",
|
|
/(?:\s|\W|^)[@+]?(#[^<>\[\](){}\"\s]*[^:,.<>\[\](){}\'\"\s])/i,
|
|
insertChannelLink);
|
|
|
|
obj.munger.addRule ("face",
|
|
/((^|\s)[\<\>]?[\;\=\:]\~?[\-\^\v]?[\)\|\(pP\<\>oO0\[\]\/\\](\s|$))/,
|
|
insertSmiley);
|
|
obj.munger.addRule ("ear", /(?:\s|^)(\(\*)(?:\s|$)/, insertEar, false);
|
|
obj.munger.addRule ("rheet", /(?:\s|\W|^)(rhee+t\!*)(?:\s|$)/i, insertRheet);
|
|
obj.munger.addRule ("bold", /(?:\s|^)(\*[^*,.()]*\*)(?:[\s.,]|$)/,
|
|
"chatzilla-bold");
|
|
obj.munger.addRule ("italic", /(?:\s|^)(\/[^\/,.()]*\/)(?:[\s.,]|$)/,
|
|
"chatzilla-italic");
|
|
/* allow () chars inside |code()| blocks */
|
|
obj.munger.addRule ("teletype", /(?:\s|^)(\|[^|,.]*\|)(?:[\s.,]|$)/,
|
|
"chatzilla-teletype");
|
|
obj.munger.addRule ("underline", /(?:\s|^)(\_[^_,.()]*\_)(?:[\s.,]|$)/,
|
|
"chatzilla-underline");
|
|
obj.munger.addRule (".mirc-colors", /(\x03((\d{1,2})(,\d{1,2}|)|))/,
|
|
mircChangeColor);
|
|
obj.munger.addRule (".mirc-bold", /(\x02)/, mircToggleBold);
|
|
obj.munger.addRule (".mirc-underline", /(\x1f)/, mircToggleUnder);
|
|
obj.munger.addRule (".mirc-color-reset", /(\x0f)/, mircResetColor);
|
|
obj.munger.addRule (".mirc-reverse", /(\x16)/, mircReverseColor);
|
|
obj.munger.addRule ("ctrl-char", /([\x01-\x1f])/, showCtrlChar);
|
|
obj.munger.addRule ("word-hyphenator",
|
|
new RegExp ("(\\S{" + client.MAX_WORD_DISPLAY + ",})"),
|
|
insertHyphenatedWord);
|
|
|
|
obj.rdf = new RDFHelper();
|
|
|
|
obj.rdf.initTree("user-list");
|
|
obj.rdf.setTreeRoot("user-list", obj.rdf.resNullChan);
|
|
|
|
multilineInputMode(false);
|
|
}
|
|
|
|
function insertLink (matchText, containerTag)
|
|
{
|
|
|
|
var href;
|
|
|
|
if (matchText.match (/^[a-zA-Z-]+:/))
|
|
href = matchText;
|
|
else
|
|
href = "http://" + matchText;
|
|
|
|
var anchor = document.createElementNS ("http://www.w3.org/1999/xhtml",
|
|
"html:a");
|
|
anchor.setAttribute ("href", href);
|
|
anchor.setAttribute ("class", "chatzilla-link");
|
|
anchor.setAttribute ("target", "_content");
|
|
insertHyphenatedWord (matchText, anchor);
|
|
containerTag.appendChild (anchor);
|
|
|
|
}
|
|
|
|
function insertMailToLink (matchText, containerTag)
|
|
{
|
|
|
|
var href;
|
|
|
|
if (matchText.indexOf ("mailto:") != 0)
|
|
href = "mailto:" + matchText;
|
|
else
|
|
href = matchText;
|
|
|
|
var anchor = document.createElementNS ("http://www.w3.org/1999/xhtml",
|
|
"html:a");
|
|
anchor.setAttribute ("href", href);
|
|
anchor.setAttribute ("class", "chatzilla-link");
|
|
//anchor.setAttribute ("target", "_content");
|
|
insertHyphenatedWord (matchText, anchor);
|
|
containerTag.appendChild (anchor);
|
|
|
|
}
|
|
|
|
function insertChannelLink (matchText, containerTag, eventData)
|
|
{
|
|
if (!("network" in eventData) ||
|
|
matchText.search
|
|
(/^#(include|error|define|if|ifdef|else|elsif|endif|\d+)$/i) != -1)
|
|
|
|
{
|
|
containerTag.appendChild (document.createTextNode(matchText));
|
|
return;
|
|
}
|
|
|
|
var anchor = document.createElementNS ("http://www.w3.org/1999/xhtml",
|
|
"html:a");
|
|
anchor.setAttribute ("href", "irc://" + escape(eventData.network.name) +
|
|
"/" + escape (matchText));
|
|
anchor.setAttribute ("class", "chatzilla-link");
|
|
//anchor.setAttribute ("target", "_content");
|
|
insertHyphenatedWord (matchText, anchor);
|
|
containerTag.appendChild (anchor);
|
|
|
|
}
|
|
|
|
function insertBugzillaLink (matchText, containerTag)
|
|
{
|
|
|
|
var number = matchText.match (/(\d+)/)[1];
|
|
|
|
var anchor = document.createElementNS ("http://www.w3.org/1999/xhtml",
|
|
"html:a");
|
|
anchor.setAttribute ("href",
|
|
"http://bugzilla.mozilla.org/show_bug.cgi?id=" +
|
|
number);
|
|
anchor.setAttribute ("class", "chatzilla-link");
|
|
anchor.setAttribute ("target", "_content");
|
|
insertHyphenatedWord (matchText, anchor);
|
|
containerTag.appendChild (anchor);
|
|
|
|
}
|
|
|
|
function insertRheet (matchText, containerTag)
|
|
{
|
|
|
|
var anchor = document.createElementNS ("http://www.w3.org/1999/xhtml",
|
|
"html:a");
|
|
anchor.setAttribute ("href",
|
|
"ftp://ftp.mozilla.org/pub/mozilla/libraries/bonus-tracks/rheet.wav");
|
|
anchor.setAttribute ("class", "chatzilla-rheet chatzilla-link");
|
|
//anchor.setAttribute ("target", "_content");
|
|
insertHyphenatedWord (matchText, anchor);
|
|
containerTag.appendChild (anchor);
|
|
}
|
|
|
|
function insertEar (matchText, containerTag)
|
|
{
|
|
if (client.smileyText)
|
|
containerTag.appendChild (document.createTextNode (matchText));
|
|
|
|
var img = document.createElementNS ("http://www.w3.org/1999/xhtml",
|
|
"html:img");
|
|
img.setAttribute ("src", client.IMAGEDIR + "face-ear.gif");
|
|
img.setAttribute ("title", matchText);
|
|
containerTag.appendChild (img);
|
|
|
|
}
|
|
|
|
function insertSmiley (emoticon, containerTag)
|
|
{
|
|
var type = "error";
|
|
|
|
if (emoticon.search (/\;[-^v]?[\)>\]]/) != -1)
|
|
type = "face-wink";
|
|
else if (emoticon.search (/[=:;][-^v]?[\)>\]]/) != -1)
|
|
type = "face-smile";
|
|
else if (emoticon.search (/[=:;][-^v]?[\/\\]/) != -1)
|
|
type = "face-screw";
|
|
else if (emoticon.search (/[=:;]\~[-^v]?\(/) != -1)
|
|
type = "face-cry";
|
|
else if (emoticon.search (/[=:;][-^v]?[\(<\[]/) != -1)
|
|
type = "face-frown";
|
|
else if (emoticon.search (/\<?[=:;][-^v]?[0oO]/) != -1)
|
|
type = "face-surprise";
|
|
else if (emoticon.search (/[=:;][-^v]?[pP]/) != -1)
|
|
type = "face-tongue";
|
|
else if (emoticon.search (/\>?[=:;][\-\^\v]?[\(\|]/) != -1)
|
|
type = "face-angry";
|
|
|
|
var span = document.createElementNS ("http://www.w3.org/1999/xhtml",
|
|
"html:span");
|
|
|
|
/* create a span to hold the emoticon text */
|
|
span.setAttribute ("class", "chatzilla-emote-txt");
|
|
span.setAttribute ("type", type);
|
|
span.appendChild (document.createTextNode (emoticon));
|
|
containerTag.appendChild (span);
|
|
|
|
/* create an empty span after the text. this span will have an image added
|
|
* after it with a chatzilla-emote:after css rule. using
|
|
* chatzilla-emote-txt:after is not good enough because it does not allow us
|
|
* to turn off the emoticon text, but keep the image. ie.
|
|
* chatzilla-emote-txt { display: none; } turns off chatzilla-emote-txt:after
|
|
* as well.*/
|
|
span = document.createElementNS ("http://www.w3.org/1999/xhtml",
|
|
"html:span");
|
|
span.setAttribute ("class", "chatzilla-emote");
|
|
span.setAttribute ("type", type);
|
|
span.setAttribute ("title", emoticon);
|
|
containerTag.appendChild (span);
|
|
|
|
}
|
|
|
|
function mircChangeColor (colorInfo, containerTag, data)
|
|
{
|
|
if (!client.enableColors)
|
|
return;
|
|
|
|
var ary = colorInfo.match (/.(\d{1,2}|)(,(\d{1,2})|)/);
|
|
|
|
var fgColor = ary[1];
|
|
if (fgColor > 16)
|
|
fgColor &= 16;
|
|
switch (fgColor.length)
|
|
{
|
|
case 0:
|
|
delete data.currFgColor;
|
|
delete data.currBgColor;
|
|
return;
|
|
case 1:
|
|
data.currFgColor = "0" + fgColor;
|
|
break;
|
|
case 2:
|
|
data.currFgColor = fgColor;
|
|
break;
|
|
}
|
|
if (fgColor == 1)
|
|
delete data.currFgColor;
|
|
if (ary.length >= 4)
|
|
{
|
|
var bgColor = ary[3];
|
|
if (bgColor > 16)
|
|
bgColor &= 16;
|
|
if (bgColor.length == 1)
|
|
data.currBgColor = "0" + bgColor;
|
|
else
|
|
data.currBgColor = bgColor;
|
|
if (bgColor == 0)
|
|
delete data.currBgColor;
|
|
}
|
|
data.hasColorInfo = true;
|
|
}
|
|
|
|
function mircToggleBold (colorInfo, containerTag, data)
|
|
{
|
|
if (!client.enableColors)
|
|
return;
|
|
|
|
if ("isBold" in data)
|
|
delete data.isBold;
|
|
else
|
|
data.isBold = true;
|
|
data.hasColorInfo = true;
|
|
}
|
|
|
|
function mircToggleUnder (colorInfo, containerTag, data)
|
|
{
|
|
if (!client.enableColors)
|
|
return;
|
|
|
|
if ("isUnderline" in data)
|
|
delete data.isUnderline;
|
|
else
|
|
data.isUnderline = true;
|
|
data.hasColorInfo = true;
|
|
}
|
|
|
|
function mircResetColor (text, containerTag, data)
|
|
{
|
|
if (!client.enableColors || !("hasColorInfo" in data))
|
|
return;
|
|
|
|
delete data.currFgColor;
|
|
delete data.currBgColor;
|
|
delete data.isBold;
|
|
delete data.isUnder;
|
|
delete data.hasColorInfo;
|
|
}
|
|
|
|
function mircReverseColor (text, containerTag, data)
|
|
{
|
|
if (!client.enableColors)
|
|
return;
|
|
|
|
var tempColor = ("currFgColor" in data ? data.currFgColor : "01");
|
|
|
|
if ("currBgColor" in data)
|
|
data.currFgColor = data.currBgColor;
|
|
else
|
|
data.currFgColor = "00";
|
|
data.currBgColor = tempColor;
|
|
data.hasColorInfo = true;
|
|
}
|
|
|
|
function showCtrlChar(c, containerTag)
|
|
{
|
|
var span = document.createElementNS ("http://www.w3.org/1999/xhtml",
|
|
"html:span");
|
|
span.setAttribute ("class", "chatzilla-control-char");
|
|
var ctrlStr = c.charCodeAt(0).toString(16);
|
|
if (ctrlStr.length < 2)
|
|
ctrlStr = "0" + ctrlStr;
|
|
span.appendChild (document.createTextNode ("0x" + ctrlStr));
|
|
containerTag.appendChild (span);
|
|
}
|
|
|
|
function insertHyphenatedWord (longWord, containerTag)
|
|
{
|
|
var wordParts = splitLongWord (longWord, client.MAX_WORD_DISPLAY);
|
|
for (var i = 0; i < wordParts.length; ++i)
|
|
{
|
|
containerTag.appendChild (document.createTextNode (wordParts[i]));
|
|
if (i != wordParts.length)
|
|
{
|
|
var wbr = document.createElementNS ("http://www.w3.org/1999/xhtml",
|
|
"html:wbr");
|
|
containerTag.appendChild (wbr);
|
|
}
|
|
}
|
|
}
|
|
|
|
function msgIsImportant (msg, sourceNick, myNick)
|
|
{
|
|
var sv = "(" + myNick + ")";
|
|
if (client.stalkingVictims.length > 0)
|
|
sv += "|(" + client.stalkingVictims.join(")|(") + ")";
|
|
|
|
var str = "(^|[\\W\\s])" + sv + "([\\W\\s]|$)";
|
|
var re = new RegExp(str, "i");
|
|
if (msg.search(re) != -1 || sourceNick && sourceNick.search(re) != -1)
|
|
{
|
|
playSounds(client.STALK_BEEP);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function isStartupURL(url)
|
|
{
|
|
var ary = client.INITIAL_URLS.split(/\s*;\s*/);
|
|
return arrayContains(ary, url);
|
|
}
|
|
|
|
function cycleView (amount)
|
|
{
|
|
var len = client.viewsArray.length;
|
|
if (len <= 1)
|
|
return;
|
|
|
|
if (amount > len)
|
|
amount = amount % client.viewsArray.length;
|
|
|
|
var tb = getTabForObject (client.currentObject);
|
|
if (!tb)
|
|
return;
|
|
|
|
var vk = Number(tb.getAttribute("viewKey"));
|
|
var destKey = vk + amount;
|
|
if (destKey > len - 1)
|
|
{
|
|
/* wrap past max */
|
|
destKey -= client.viewsArray.length;
|
|
}
|
|
else if (destKey < 0)
|
|
{
|
|
/* wrap past 0 */
|
|
destKey += client.viewsArray.length;
|
|
}
|
|
|
|
setCurrentObject (client.viewsArray[destKey].source);
|
|
}
|
|
|
|
function playSounds (list)
|
|
{
|
|
var ary = list.split (" ");
|
|
if (ary.length == 0)
|
|
return;
|
|
|
|
playSound (ary[0]);
|
|
for (var i = 1; i < ary.length; ++i)
|
|
setTimeout (playSound, 250 * i, ary[i]);
|
|
}
|
|
|
|
function playSound (file)
|
|
{
|
|
if (!client.sound || !file)
|
|
return;
|
|
|
|
if (file == "beep")
|
|
{
|
|
client.sound.beep();
|
|
}
|
|
else
|
|
{
|
|
var uri = Components.classes["@mozilla.org/network/standard-url;1"];
|
|
uri = uri.createInstance(Components.interfaces.nsIURI);
|
|
uri.spec = file;
|
|
client.sound.play (uri);
|
|
}
|
|
}
|
|
|
|
function fillInTooltip(tipElement, id)
|
|
{
|
|
const XLinkNS = "http://www.w3.org/1999/xlink";
|
|
|
|
var retVal = false;
|
|
|
|
var titleText = null;
|
|
var XLinkTitleText = null;
|
|
|
|
while (!titleText && !XLinkTitleText && tipElement) {
|
|
if (tipElement.nodeType == Node.ELEMENT_NODE) {
|
|
titleText = tipElement.getAttribute("title");
|
|
XLinkTitleText = tipElement.getAttributeNS(XLinkNS, "title");
|
|
}
|
|
tipElement = tipElement.parentNode;
|
|
}
|
|
|
|
var texts = [titleText, XLinkTitleText];
|
|
var tipNode = document.getElementById(id);
|
|
|
|
for (var i = 0; i < texts.length; ++i) {
|
|
var t = texts[i];
|
|
if (t && t.search(/\S/) >= 0) {
|
|
tipNode.setAttribute("label", t);
|
|
retVal = true;
|
|
}
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
/* timer-based mainloop */
|
|
function mainStep()
|
|
{
|
|
if (!("initialized" in frames[0]))
|
|
{ /* voodoo required for skin switching. When the user changes a skin,
|
|
* the output document is reloaded. this document *cannot* tell us
|
|
* it has been reloaded, because the type="content" attribute used
|
|
* on the iframe (to allow selection) also keeps the iframe from getting
|
|
* to the chrome above it. Instead, we poll the document looking for
|
|
* the "initialized" variable. If it's not there, we reset the current
|
|
* object, and set initialized in the document. */
|
|
setClientOutput(frames[0].document);
|
|
if (client.output)
|
|
{
|
|
var o = client.currentObject;
|
|
client.currentObject = null;
|
|
setCurrentObject (o);
|
|
frames[0].initialized = true;
|
|
}
|
|
}
|
|
|
|
client.eventPump.stepEvents();
|
|
setTimeout ("mainStep()", client.STEP_TIMEOUT);
|
|
|
|
}
|
|
|
|
function getMsg (msgName)
|
|
{
|
|
var restCount = arguments.length - 1;
|
|
|
|
if (!("bundle" in client))
|
|
{
|
|
client.bundle =
|
|
srGetStrBundle("chrome://chatzilla/locale/chatzilla.properties");
|
|
}
|
|
|
|
try
|
|
{
|
|
if (restCount == 1 && arguments[1] instanceof Array)
|
|
{
|
|
return client.bundle.formatStringFromName (msgName, arguments[1],
|
|
arguments[1].length);
|
|
}
|
|
else if (restCount > 0)
|
|
{
|
|
var subPhrases = new Array();
|
|
for (var i = 1; i < arguments.length; ++i)
|
|
subPhrases.push(arguments[i]);
|
|
return client.bundle.formatStringFromName (msgName, subPhrases,
|
|
subPhrases.length);
|
|
}
|
|
|
|
return client.bundle.GetStringFromName (msgName);
|
|
}
|
|
catch (ex)
|
|
{
|
|
dd ("caught exception getting value for ``" + msgName + "''\n" + ex +
|
|
"\n" + getStackTrace());
|
|
return msgName;
|
|
}
|
|
}
|
|
|
|
function openQueryTab (server, nick)
|
|
{
|
|
var usr = server.addUser(nick.toLowerCase());
|
|
if (!("messages" in usr))
|
|
usr.displayHere (getMsg("cli_imsgMsg3", usr.properNick), "INFO");
|
|
server.sendData ("WHO " + nick + "\n");
|
|
return usr;
|
|
}
|
|
|
|
function arraySpeak (ary, single, plural)
|
|
{
|
|
var rv = "";
|
|
var and = getMsg ("arraySpeakAnd");
|
|
|
|
switch (ary.length)
|
|
{
|
|
case 0:
|
|
break;
|
|
|
|
case 1:
|
|
rv = ary[0];
|
|
if (single)
|
|
rv += " " + single;
|
|
break;
|
|
|
|
case 2:
|
|
rv = ary[0] + " " + and + " " + ary[1];
|
|
if (plural)
|
|
rv += " " + plural;
|
|
break;
|
|
|
|
default:
|
|
for (var i = 0; i < ary.length - 1; ++i)
|
|
rv += ary[i] + ", ";
|
|
rv += and + " " + ary[ary.length - 1];
|
|
if (plural)
|
|
rv += " " + plural;
|
|
break;
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
function quicklistCallback (element, ndx, ary)
|
|
{
|
|
/* Check whether the selected attribute == true */
|
|
if (element.getAttribute("selected") == "true")
|
|
{
|
|
/* extract the nick data from the element */
|
|
/* Hmmm, nice walk ... */
|
|
ary.push(element.childNodes[0].childNodes[2].childNodes[0].nodeValue);
|
|
}
|
|
}
|
|
|
|
function getObjectDetails (obj, rv)
|
|
{
|
|
if (!rv)
|
|
rv = new Object();
|
|
|
|
if (!obj || (typeof obj != "object"))
|
|
{
|
|
dd ("** INVALID OBJECT passed to getObjectDetails (" + obj + "). **");
|
|
dd (getStackTrace());
|
|
}
|
|
|
|
rv.orig = obj;
|
|
rv.parent = ("parent" in obj) ? obj.parent : null;
|
|
|
|
switch (obj.TYPE)
|
|
{
|
|
case "IRCChannel":
|
|
rv.channel = obj;
|
|
rv.server = rv.channel.parent;
|
|
rv.network = rv.server.parent;
|
|
break;
|
|
|
|
case "IRCUser":
|
|
rv.user = obj;
|
|
rv.server = rv.user.parent;
|
|
rv.network = rv.server.parent;
|
|
break;
|
|
|
|
case "IRCChanUser":
|
|
rv.user = obj;
|
|
rv.channel = rv.user.parent;
|
|
rv.server = rv.channel.parent;
|
|
rv.network = rv.server.parent;
|
|
break;
|
|
|
|
case "IRCNetwork":
|
|
rv.network = obj;
|
|
if ("primServ" in rv.network)
|
|
rv.server = rv.network.primServ;
|
|
break;
|
|
|
|
case "IRCClient":
|
|
if ("lastNetwork" in obj)
|
|
{
|
|
rv.network = obj.lastNetwork;
|
|
if (rv.network.isConnected())
|
|
rv.server = rv.network.primServ;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
/* no setup for unknown object */
|
|
break;
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
function findDynamicRule (selector)
|
|
{
|
|
var rules = frames[0].document.styleSheets[1].cssRules;
|
|
|
|
if (selector instanceof RegExp)
|
|
fun = "search";
|
|
else
|
|
fun = "indexOf";
|
|
|
|
for (var i = 0; i < rules.length; ++i)
|
|
{
|
|
var rule = rules.item(i);
|
|
if (rule.selectorText && rule.selectorText[fun](selector) == 0)
|
|
return {sheet: frames[0].document.styleSheets[1], rule: rule,
|
|
index: i};
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function addDynamicRule (rule)
|
|
{
|
|
var rules = frames[0].document.styleSheets[1];
|
|
|
|
var pos = rules.cssRules.length;
|
|
rules.insertRule (rule, pos);
|
|
}
|
|
|
|
function setClientOutput(doc)
|
|
{
|
|
client.output = frames[0].document.getElementById("output");
|
|
//XXXcreateHighlightMenu();
|
|
}
|
|
|
|
function createHighlightMenu()
|
|
{
|
|
/* Look for "special" highlighting rules int he motif. These special rules
|
|
* are in the format ``.chatzilla-highlight[name="<display-name>"] { ... }''
|
|
* where <display-name> is a textual description to be placed in the
|
|
* Highlight submenu of the message area context menu. The body of
|
|
* these rules can be applied by the user to different irc messages. They
|
|
* are special becaus they do not actually match an element in the content
|
|
* model. The style body is copied into a new rule that matches a pettern
|
|
* determined by the user.
|
|
*/
|
|
function processStyleRules(rules)
|
|
{
|
|
for (var i = 0; i < rules.length; ++i)
|
|
{
|
|
var rule = rules.item(i);
|
|
if (rule instanceof CSSStyleRule)
|
|
{
|
|
var ary = rule.selectorText.
|
|
match(/\.chatzilla-highlight\[name=\"?([^\"]+)\"?\]/i);
|
|
if (ary)
|
|
{
|
|
menuitem = document.createElement("menuitem");
|
|
menuitem.setAttribute ("class", "highlight-menu-item");
|
|
menuitem.setAttribute ("label", ary[1]);
|
|
menuitem.setAttribute ("oncommand", "onPopupHighlight('" +
|
|
rule.style.cssText + "');");
|
|
menuitem.setAttribute ("style", rule.style.cssText);
|
|
menu.appendChild(menuitem);
|
|
}
|
|
}
|
|
else if (rule instanceof CSSImportRule)
|
|
{
|
|
processStyleRules(rule.styleSheet.cssRules);
|
|
}
|
|
}
|
|
}
|
|
|
|
var menu = document.getElementById("highlightMenu");
|
|
while (menu.firstChild)
|
|
menu.removeChild(menu.firstChild);
|
|
|
|
var menuitem = document.createElement("menuitem");
|
|
menuitem.setAttribute ("label", getMsg("noStyle"));
|
|
menuitem.setAttribute ("class", "highlight-menu-item");
|
|
menuitem.setAttribute ("oncommand", "onPopupHighlight('');");
|
|
menu.appendChild(menuitem);
|
|
|
|
processStyleRules(frames[0].document.styleSheets[0].cssRules);
|
|
}
|
|
|
|
function setupMungerMenu(munger)
|
|
{
|
|
var menu = document.getElementById("menu-munger");
|
|
for (var entry in munger.entries)
|
|
{
|
|
if (entry[0] != ".")
|
|
{
|
|
var menuitem = document.createElement("menuitem");
|
|
menuitem.setAttribute ("label", munger.entries[entry].description);
|
|
menuitem.setAttribute ("id", "menu-munger-" + entry);
|
|
menuitem.setAttribute ("type", "checkbox");
|
|
if (munger.entries[entry].enabled)
|
|
menuitem.setAttribute ("checked", "true");
|
|
menuitem.setAttribute ("oncommand", "onToggleMungerEntry('" +
|
|
entry + "');");
|
|
menu.appendChild(menuitem);
|
|
}
|
|
}
|
|
}
|
|
|
|
var testURLs =
|
|
["irc:", "irc://", "irc:///", "irc:///help", "irc:///help,needkey",
|
|
"irc://irc.foo.org", "irc://foo:6666",
|
|
"irc://foo", "irc://irc.foo.org/", "irc://foo:6666/", "irc://foo/",
|
|
"irc://irc.foo.org/,needpass", "irc://foo/,isserver",
|
|
"irc://moznet/,isserver", "irc://moznet/",
|
|
"irc://foo/chatzilla", "irc://foo/chatzilla/",
|
|
"irc://irc.foo.org/?msg=hello%20there",
|
|
"irc://irc.foo.org/?msg=hello%20there&ignorethis",
|
|
"irc://irc.foo.org/%23mozilla,needkey?msg=hello%20there&ignorethis",
|
|
"invalids",
|
|
"irc://irc.foo.org/,isnick"];
|
|
|
|
function doURLTest()
|
|
{
|
|
for (var u in testURLs)
|
|
{
|
|
dd ("testing url \"" + testURLs[u] + "\"");
|
|
var o = parseIRCURL(testURLs[u]);
|
|
if (!o)
|
|
dd ("PARSE FAILED!");
|
|
else
|
|
dd (dumpObjectTree(o));
|
|
dd ("---");
|
|
}
|
|
}
|
|
|
|
function parseIRCURL (url)
|
|
{
|
|
var specifiedHost = "";
|
|
|
|
var rv = new Object();
|
|
rv.spec = url;
|
|
rv.host = null;
|
|
rv.target = "";
|
|
rv.port = 6667;
|
|
rv.msg = "";
|
|
rv.needpass = false;
|
|
rv.needkey = false;
|
|
rv.isnick = false;
|
|
rv.isserver = false;
|
|
|
|
if (url.search(/^(irc:\/?\/?)$/i) != -1)
|
|
return rv;
|
|
|
|
rv.host = client.DEFAULT_NETWORK;
|
|
|
|
/* split url into <host>/<everything-else> pieces */
|
|
var ary = url.match (/^irc:\/\/([^\/\s]+)?(\/.*)?\s*$/i);
|
|
if (!ary)
|
|
{
|
|
dd ("parseIRCURL: initial split failed");
|
|
return null;
|
|
}
|
|
var host = ary[1];
|
|
var rest = (2 in ary) ? ary[2] : "";
|
|
|
|
/* split <host> into server (or network) / port */
|
|
ary = host.match (/^([^\s\:]+)?(\:\d+)?$/);
|
|
if (!ary)
|
|
{
|
|
dd ("parseIRCURL: host/port split failed");
|
|
return null;
|
|
}
|
|
|
|
if (2 in ary)
|
|
{
|
|
if (!(1 in ary))
|
|
{
|
|
dd ("parseIRCURL: port with no host");
|
|
return null;
|
|
}
|
|
specifiedHost = rv.host = ary[1].toLowerCase();
|
|
rv.isserver = true;
|
|
rv.port = parseInt(ary[2].substr(1));
|
|
}
|
|
else if (1 in ary)
|
|
{
|
|
specifiedHost = rv.host = ary[1].toLowerCase();
|
|
if (specifiedHost.indexOf(".") != -1)
|
|
rv.isserver = true;
|
|
}
|
|
|
|
if (rest)
|
|
{
|
|
ary = rest.match (/^\/([^\,\?\s\/]*)?\/?(,[^\?]*)?(\?.*)?$/);
|
|
if (!ary)
|
|
{
|
|
dd ("parseIRCURL: rest split failed ``" + rest + "''");
|
|
return null;
|
|
}
|
|
|
|
rv.target = (1 in ary) ?
|
|
unescape(ary[1]).toLowerCase().replace("\n", "\\n"): "";
|
|
var params = (2 in ary) ? ary[2].toLowerCase() : "";
|
|
var query = (3 in ary) ? ary[3] : "";
|
|
|
|
if (params)
|
|
{
|
|
rv.isnick =
|
|
(params.search (/,\s*isnick\s*,|,\s*isnick\s*$/) != -1);
|
|
if (rv.isnick && !rv.target)
|
|
{
|
|
dd ("parseIRCURL: isnick w/o target");
|
|
/* isnick w/o a target is bogus */
|
|
return null;
|
|
}
|
|
|
|
rv.isserver =
|
|
(params.search (/,\s*isserver\s*,|,\s*isserver\s*$/) != -1);
|
|
if (rv.isserver && !specifiedHost)
|
|
{
|
|
dd ("parseIRCURL: isserver w/o host");
|
|
/* isserver w/o a host is bogus */
|
|
return null;
|
|
}
|
|
|
|
rv.needpass =
|
|
(params.search (/,\s*needpass\s*,|,\s*needpass\s*$/) != -1);
|
|
|
|
rv.needkey =
|
|
(params.search (/,\s*needkey\s*,|,\s*needkey\s*$/) != -1);
|
|
|
|
}
|
|
|
|
if (query)
|
|
{
|
|
ary = query.match
|
|
(/^\?msg=([^\&]*)$|^\?msg=([^\&]*)\&|\&msg=([^\&]*)\&|\&msg=([^\&]*)$/);
|
|
if (ary)
|
|
for (var i = 1; i < ary.length; i++)
|
|
if (i in ary)
|
|
{
|
|
rv.msg = unescape(ary[i]).replace ("\n", "\\n");
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
function gotoIRCURL (url)
|
|
{
|
|
if (typeof url == "string")
|
|
url = parseIRCURL(url);
|
|
|
|
if (!url)
|
|
{
|
|
window.alert (getMsg("badIRCURL",url));
|
|
return;
|
|
}
|
|
|
|
if (!url.host)
|
|
{
|
|
/* focus the *client* view for irc:, irc:/, and irc:// (the only irc
|
|
* urls that don't have a host. (irc:/// implies a connect to the
|
|
* default network.)
|
|
*/
|
|
onSimulateCommand("/client");
|
|
return;
|
|
}
|
|
|
|
var net;
|
|
var pass = "";
|
|
|
|
if (url.needpass)
|
|
pass = window.prompt (getMsg("gotoIRCURLMsg2",url.spec));
|
|
|
|
if (url.isserver)
|
|
{
|
|
var alreadyThere = false;
|
|
for (var n in client.networks)
|
|
{
|
|
if ((client.networks[n].isConnected()) &&
|
|
(client.networks[n].primServ.connection.host == url.host) &&
|
|
(client.networks[n].primServ.connection.port == url.port))
|
|
{
|
|
/* already connected to this server/port */
|
|
net = client.networks[n];
|
|
alreadyThere = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!alreadyThere)
|
|
{
|
|
/*
|
|
dd ("gotoIRCURL: not already connected to " +
|
|
"server " + url.host + " trying to connect...");
|
|
*/
|
|
client.onInputServer ({inputData: url.host + " " + url.port +
|
|
" " + pass});
|
|
net = client.networks[url.host];
|
|
if (!("pendingURLs" in net))
|
|
net.pendingURLs = new Array();
|
|
net.pendingURLs.push (url);
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
/* parsed as a network name */
|
|
{
|
|
net = client.networks[url.host];
|
|
if (!net.isConnected())
|
|
{
|
|
/*
|
|
dd ("gotoIRCURL: not already connected to " +
|
|
"network " + url.host + " trying to connect...");
|
|
*/
|
|
client.connectToNetwork (url.host, pass);
|
|
if (!("pendingURLs" in net))
|
|
net.pendingURLs = new Array();
|
|
net.pendingURLs.push (url);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* already connected, do whatever comes next in the url */
|
|
//dd ("gotoIRCURL: connected, time to finish parsing ``" + url + "''");
|
|
if (url.target)
|
|
{
|
|
var targetObject;
|
|
var ev;
|
|
if (url.isnick)
|
|
{
|
|
/* url points to a person. */
|
|
var nick = url.target;
|
|
var ary = url.target.split("!");
|
|
if (ary)
|
|
{
|
|
nick = ary[0];
|
|
}
|
|
|
|
ev = {inputData: nick, network: net, server: net.primServ};
|
|
client.onInputQuery(ev);
|
|
targetObject = ev.user;
|
|
}
|
|
else
|
|
{
|
|
/* url points to a channel */
|
|
var key = "";
|
|
if (url.needkey)
|
|
key = window.prompt (getMsg("gotoIRCURLMsg3", url.spec));
|
|
ev = {inputData: url.target + " " + key,
|
|
network: net, server: net.primServ};
|
|
client.onInputJoin (ev);
|
|
targetObject = ev.channel;
|
|
}
|
|
|
|
if (url.msg)
|
|
{
|
|
var msg;
|
|
if (url.msg.indexOf("\01ACTION") == 0)
|
|
{
|
|
msg = filterOutput (url.msg, "ACTION", "ME!");
|
|
targetObject.display (msg, "ACTION", "ME!",
|
|
client.currentObject);
|
|
}
|
|
else
|
|
{
|
|
msg = filterOutput (url.msg, "PRIVMSG", "ME!");
|
|
targetObject.display (msg, "PRIVMSG", "ME!",
|
|
client.currentObject);
|
|
}
|
|
targetObject.say (fromUnicode(msg));
|
|
setCurrentObject (targetObject);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!net.messages)
|
|
net.displayHere (getMsg("gotoIRCURLMsg4",net.name),
|
|
"INFO");
|
|
setCurrentObject (net);
|
|
}
|
|
|
|
}
|
|
|
|
function setTopicText (text)
|
|
{
|
|
var topic = client.statusBar["channel-topic"];
|
|
var span = document.createElementNS ("http://www.w3.org/1999/xhtml",
|
|
"html:span");
|
|
|
|
span.appendChild(stringToMsg(text, client.currentObject));
|
|
topic.removeChild(topic.firstChild);
|
|
topic.appendChild(span);
|
|
}
|
|
|
|
function updateNetwork(obj)
|
|
{
|
|
var o = getObjectDetails (client.currentObject);
|
|
|
|
var lag = MSG_UNKNOWN;
|
|
var nick = "";
|
|
if ("server" in o)
|
|
{
|
|
if (o.server.me)
|
|
nick = o.server.me.properNick;
|
|
lag = (o.server.lag != -1) ? o.server.lag : MSG_UNKNOWN;
|
|
}
|
|
client.statusBar["header-url"].setAttribute("value",
|
|
client.currentObject.getURL());
|
|
client.statusBar["header-url"].setAttribute("href",
|
|
client.currentObject.getURL());
|
|
client.statusBar["header-url"].setAttribute("name",
|
|
client.currentObject.name);
|
|
client.statusBar["server-nick"].setAttribute("value", nick);
|
|
}
|
|
|
|
function updateChannel (obj)
|
|
{
|
|
if (obj && obj != client.currentObject)
|
|
return;
|
|
|
|
var o = getObjectDetails (client.currentObject);
|
|
|
|
var mode = MSG_NONE, users = MSG_NONE, topic = MSG_UNKNOWN;
|
|
|
|
if ("channel" in o)
|
|
{
|
|
mode = o.channel.mode.getModeStr();
|
|
if (!mode)
|
|
mode = MSG_NONE;
|
|
users = getMsg("userCountDetails",
|
|
[o.channel.getUsersLength(), o.channel.opCount,
|
|
o.channel.voiceCount]);
|
|
topic = o.channel.topic ? o.channel.topic : MSG_NONE;
|
|
}
|
|
|
|
client.statusBar["channel-mode"].setAttribute("value", mode);
|
|
client.statusBar["channel-users"].setAttribute("value", users);
|
|
var regex = new RegExp ("(\\S{" + client.MAX_WORD_DISPLAY + ",})", "g");
|
|
var ary = topic.match(regex);
|
|
if (ary && ary.length)
|
|
{
|
|
for (var i = 0; i < ary.length; ++i)
|
|
{
|
|
var hyphenated = hyphenateWord(ary[i], client.MAX_WORD_DISPLAY);
|
|
topic = topic.replace(ary[i], hyphenated);
|
|
}
|
|
}
|
|
|
|
client.statusBar["channel-topic"].firstChild.data = topic;
|
|
|
|
}
|
|
|
|
function updateTitle (obj)
|
|
{
|
|
if (!("currentObject" in client) || (obj && obj != client.currentObject))
|
|
return;
|
|
|
|
var tstring;
|
|
var o = getObjectDetails (client.currentObject);
|
|
var net = "network" in o ? o.network.name : "";
|
|
var nick = "";
|
|
|
|
switch (client.currentObject.TYPE)
|
|
{
|
|
case "IRCNetwork":
|
|
var serv = "", port = "";
|
|
if ("server" in o)
|
|
{
|
|
serv = o.server.connection.host;
|
|
port = o.server.connection.port;
|
|
if (o.server.me)
|
|
nick = o.server.me.properNick;
|
|
tstring = getMsg("updateTitleNetwork", [nick, net, serv, port]);
|
|
}
|
|
else
|
|
{
|
|
nick = client.currentObject.INITIAL_NICK;
|
|
tstring = getMsg("updateTitleNetwork2", [nick, net]);
|
|
}
|
|
break;
|
|
|
|
case "IRCChannel":
|
|
var chan = "", mode = "", topic = "";
|
|
nick = "me" in o.parent ? o.parent.me.properNick :
|
|
getMsg ("updateTitleNoNick");
|
|
chan = o.channel.name;
|
|
mode = o.channel.mode.getModeStr();
|
|
if (!mode)
|
|
mode = getMsg("updateTitleNoMode");
|
|
topic = o.channel.topic ? o.channel.topic :
|
|
getMsg("updateTitleNoTopic");
|
|
|
|
tstring = getMsg("updateTitleChannel", [nick, chan, mode, topic]);
|
|
break;
|
|
|
|
case "IRCUser":
|
|
nick = client.currentObject.properNick;
|
|
var source = "";
|
|
if (client.currentObject.name)
|
|
{
|
|
source = client.currentObject.name + "@" +
|
|
client.currentObject.host;
|
|
}
|
|
tstring = getMsg("updateTitleUser", [nick, source]);
|
|
//client.statusBar["channel-topic"].setAttribute("value", tstring);
|
|
client.statusBar["channel-topic"].firstChild.data = tstring;
|
|
break;
|
|
|
|
default:
|
|
tstring = getMsg("updateTitleUnknown");
|
|
break;
|
|
}
|
|
|
|
if (!client.uiState["tabstrip"])
|
|
{
|
|
var actl = new Array();
|
|
for (var i in client.activityList)
|
|
actl.push ((client.activityList[i] == "!") ?
|
|
(Number(i) + 1) + "!" : (Number(i) + 1));
|
|
if (actl.length > 0)
|
|
tstring = getMsg("updateTitleWithActivity",
|
|
[tstring, actl.join (MSG_CSP)]);
|
|
}
|
|
|
|
document.title = tstring;
|
|
|
|
}
|
|
|
|
function multilineInputMode (state)
|
|
{
|
|
var multiInput = document.getElementById("multiline-input");
|
|
var singleInput = document.getElementById("input");
|
|
var splitter = document.getElementById("input-splitter");
|
|
var iw = document.getElementById("input-widgets");
|
|
var h;
|
|
|
|
client._mlMode = state;
|
|
|
|
if (state) /* turn on multiline input mode */
|
|
{
|
|
|
|
h = iw.getAttribute ("lastHeight");
|
|
if (h)
|
|
iw.setAttribute ("height", h); /* restore the slider position */
|
|
|
|
singleInput.setAttribute ("collapsed", "true");
|
|
splitter.setAttribute ("collapsed", "false");
|
|
multiInput.setAttribute ("collapsed", "false");
|
|
client.input = multiInput;
|
|
}
|
|
else /* turn off multiline input mode */
|
|
{
|
|
h = iw.getAttribute ("height");
|
|
iw.setAttribute ("lastHeight", h); /* save the slider position */
|
|
iw.removeAttribute ("height"); /* let the slider drop */
|
|
|
|
splitter.setAttribute ("collapsed", "true");
|
|
multiInput.setAttribute ("collapsed", "true");
|
|
singleInput.setAttribute ("collapsed", "false");
|
|
client.input = singleInput;
|
|
}
|
|
|
|
client.input.focus();
|
|
}
|
|
|
|
function focusInput ()
|
|
{
|
|
client.input.focus();
|
|
}
|
|
|
|
function newInlineText (data, className, tagName)
|
|
{
|
|
if (typeof tagName == "undefined")
|
|
tagName = "html:span";
|
|
|
|
var a = document.createElementNS ("http://www.w3.org/1999/xhtml",
|
|
tagName);
|
|
if (className)
|
|
a.setAttribute ("class", className);
|
|
|
|
switch (typeof data)
|
|
{
|
|
case "string":
|
|
a.appendChild (document.createTextNode (data));
|
|
break;
|
|
|
|
case "object":
|
|
for (var p in data)
|
|
if (p != "data")
|
|
a.setAttribute (p, data[p]);
|
|
else
|
|
a.appendChild (document.createTextNode (data[p]));
|
|
break;
|
|
|
|
case "undefined":
|
|
break;
|
|
|
|
default:
|
|
dd ("** INVALID TYPE ('" + typeof data + "') passed to " +
|
|
"newInlineText.");
|
|
break;
|
|
|
|
}
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
function stringToMsg (message, obj)
|
|
{
|
|
var ary = message.split ("\n");
|
|
var span = document.createElementNS ("http://www.w3.org/1999/xhtml",
|
|
"html:span");
|
|
var data = getObjectDetails(obj);
|
|
|
|
if (ary.length == 1)
|
|
client.munger.munge(ary[0], span, data);
|
|
else
|
|
{
|
|
for (var l = 0; l < ary.length - 1; ++l)
|
|
{
|
|
client.munger.munge(ary[l], span, data);
|
|
span.appendChild
|
|
(document.createElementNS ("http://www.w3.org/1999/xhtml",
|
|
"html:br"));
|
|
}
|
|
client.munger.munge(ary[l], span, data);
|
|
}
|
|
|
|
return span;
|
|
}
|
|
|
|
function setCurrentObject (obj)
|
|
{
|
|
if (!obj.messages)
|
|
{
|
|
dd ("** INVALID OBJECT passed to setCurrentObject **");
|
|
return;
|
|
}
|
|
|
|
if (("currentObject" in client && client.currentObject == obj) ||
|
|
!("output" in client) || !client.output)
|
|
return;
|
|
|
|
var tb, userList;
|
|
|
|
if ("currentObject" in client && client.currentObject)
|
|
{
|
|
tb = getTabForObject(client.currentObject);
|
|
}
|
|
if (tb)
|
|
{
|
|
tb.selected = false;
|
|
tb.setAttribute ("state", "normal");
|
|
}
|
|
|
|
if (client.output.firstChild)
|
|
client.output.removeChild (client.output.firstChild);
|
|
client.output.appendChild (obj.messages);
|
|
|
|
/* Unselect currently selected users. */
|
|
userList = document.getElementById("user-list");
|
|
if (isVisible("user-list-box"))
|
|
{
|
|
/* Remove currently selected items before this tree gets rerooted,
|
|
* because it seems to remember the selections for eternity if not. */
|
|
if (userList.treeBoxObject.selection)
|
|
userList.treeBoxObject.selection.clearSelection ();
|
|
|
|
if (obj.TYPE == "IRCChannel")
|
|
client.rdf.setTreeRoot ("user-list", obj.getGraphResource());
|
|
else
|
|
client.rdf.setTreeRoot ("user-list", client.rdf.resNullChan);
|
|
}
|
|
|
|
client.currentObject = obj;
|
|
tb = getTabForObject(obj);
|
|
if (tb)
|
|
{
|
|
tb.selected = true;
|
|
tb.setAttribute ("state", "current");
|
|
}
|
|
|
|
var vk = Number(tb.getAttribute("viewKey"));
|
|
delete client.activityList[vk];
|
|
|
|
updateNetwork();
|
|
updateChannel();
|
|
updateTitle ();
|
|
|
|
if (client.PRINT_DIRECTION == 1)
|
|
{
|
|
scrollDown();
|
|
setTimeout ("scrollDown()", 500);
|
|
setTimeout ("scrollDown()", 1000);
|
|
setTimeout ("scrollDown()", 2000);
|
|
}
|
|
|
|
onTopicEditEnd();
|
|
|
|
if (client.currentObject.TYPE == "IRCChannel")
|
|
client.statusBar["channel-topic"].setAttribute ("editable", "true");
|
|
else
|
|
client.statusBar["channel-topic"].removeAttribute ("editable");
|
|
|
|
var status = document.getElementById("offline-status");
|
|
if (client.currentObject == client)
|
|
{
|
|
status.setAttribute ("hidden", "true");
|
|
}
|
|
else
|
|
{
|
|
status.removeAttribute ("hidden");
|
|
var details = getObjectDetails(client.currentObject);
|
|
if ("network" in details && details.network.isConnected())
|
|
status.removeAttribute ("offline");
|
|
else
|
|
status.setAttribute ("offline", "true");
|
|
}
|
|
}
|
|
|
|
function scrollDown ()
|
|
{
|
|
window.frames[0].scrollTo(0, window.frames[0].document.height);
|
|
}
|
|
|
|
/* valid values for |what| are "superfluous", "activity", and "attention".
|
|
* final value for state is dependant on priority of the current state, and the
|
|
* new state. the priority is: normal < superfluous < activity < attention.
|
|
*/
|
|
function setTabState (source, what)
|
|
{
|
|
if (typeof source != "object")
|
|
source = client.viewsArray[source].source;
|
|
|
|
var tb = getTabForObject (source, true);
|
|
var vk = Number(tb.getAttribute("viewKey"));
|
|
|
|
if ("currentObject" in client && client.currentObject != source)
|
|
{
|
|
var state = tb.getAttribute ("state");
|
|
if (state == what)
|
|
{
|
|
/* if the tab state has an equal priority to what we are setting
|
|
* then blink it */
|
|
tb.setAttribute ("state", "normal");
|
|
setTimeout (setTabState, 200, vk, what);
|
|
}
|
|
else
|
|
{
|
|
if (state == "normal" || state == "superfluous" ||
|
|
(state == "activity" && what == "attention"))
|
|
{
|
|
/* if the tab state has a lower priority than what we are
|
|
* setting, change it to the new state */
|
|
tb.setAttribute ("state", what);
|
|
/* we only change the activity list if priority has increased */
|
|
if (what == "attention")
|
|
client.activityList[vk] = "!";
|
|
else if (what == "activity")
|
|
client.activityList[vk] = "+";
|
|
else
|
|
{
|
|
/* this is functionally equivalent to "+" for now */
|
|
client.activityList[vk] = "-";
|
|
}
|
|
updateTitle();
|
|
}
|
|
else
|
|
{
|
|
/* the current state of the tab has a higher priority than the
|
|
* new state.
|
|
* blink the new lower state quickly, then back to the old */
|
|
tb.setAttribute ("state", what);
|
|
setTimeout (setTabState, 200, vk, state);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function notifyAttention (source)
|
|
{
|
|
if (typeof source != "object")
|
|
source = client.viewsArray[source].source;
|
|
|
|
if (client.currentObject != source)
|
|
{
|
|
var tb = getTabForObject (source, true);
|
|
var vk = Number(tb.getAttribute("viewKey"));
|
|
|
|
tb.setAttribute ("state", "attention");
|
|
client.activityList[vk] = "!";
|
|
updateTitle();
|
|
}
|
|
|
|
if (client.FLASH_WINDOW)
|
|
window.getAttention();
|
|
|
|
}
|
|
|
|
/* gets the toolbutton associated with an object
|
|
* if |create| is present, and true, create if not found */
|
|
function getTabForObject (source, create)
|
|
{
|
|
var name;
|
|
|
|
if (!source)
|
|
{
|
|
dd ("** UNDEFINED passed to getTabForObject **");
|
|
dd (getStackTrace());
|
|
return null;
|
|
}
|
|
|
|
create = (typeof create != "undefined") ? Boolean(create) : false;
|
|
|
|
switch (source.TYPE)
|
|
{
|
|
case "IRCChanUser":
|
|
case "IRCUser":
|
|
name = source.nick;
|
|
break;
|
|
|
|
case "IRCNetwork":
|
|
case "IRCChannel":
|
|
case "IRCClient":
|
|
name = source.name;
|
|
break;
|
|
|
|
default:
|
|
dd ("** INVALID OBJECT passed to getTabForObject **");
|
|
return null;
|
|
}
|
|
|
|
var tb, id = "tb[" + name + "]";
|
|
var matches = 1;
|
|
|
|
for (var i in client.viewsArray)
|
|
{
|
|
if (client.viewsArray[i].source == source)
|
|
{
|
|
tb = client.viewsArray[i].tb;
|
|
break;
|
|
}
|
|
else
|
|
if (client.viewsArray[i].tb.getAttribute("id") == id)
|
|
id = "tb[" + name + "<" + (++matches) + ">]";
|
|
}
|
|
|
|
if (!tb && create) /* not found, create one */
|
|
{
|
|
var views = document.getElementById ("views-tbar-inner");
|
|
tb = document.createElement ("tab");
|
|
tb.setAttribute ("ondraggesture",
|
|
"nsDragAndDrop.startDrag(event, tabDNDObserver);");
|
|
tb.setAttribute ("href", source.getURL());
|
|
tb.setAttribute ("name", source.name);
|
|
tb.setAttribute ("onclick", "onTabClick(" + id.quote() + ");");
|
|
tb.setAttribute ("crop", "right");
|
|
|
|
tb.setAttribute ("class", "tab-bottom view-button");
|
|
tb.setAttribute ("id", id);
|
|
tb.setAttribute ("state", "normal");
|
|
|
|
client.viewsArray.push ({source: source, tb: tb});
|
|
tb.setAttribute ("viewKey", client.viewsArray.length - 1);
|
|
if (matches > 1)
|
|
tb.setAttribute("label", name + "<" + matches + ">");
|
|
else
|
|
tb.setAttribute("label", name);
|
|
|
|
views.appendChild (tb);
|
|
}
|
|
|
|
return tb;
|
|
|
|
}
|
|
|
|
var contentDropObserver = new Object();
|
|
|
|
contentDropObserver.onDragOver =
|
|
function tabdnd_dover (aEvent, aFlavour, aDragSession)
|
|
{
|
|
if (aEvent.getPreventDefault())
|
|
return;
|
|
|
|
if (aDragSession.sourceDocument == aEvent.view.document)
|
|
{
|
|
aDragSession.canDrop = false;
|
|
return;
|
|
}
|
|
}
|
|
|
|
contentDropObserver.onDrop =
|
|
function tabdnd_drop (aEvent, aXferData, aDragSession)
|
|
{
|
|
var url = transferUtils.retrieveURLFromData(aXferData.data, aXferData.flavour.contentType);
|
|
if (!url || url.search(client.linkRE) == -1)
|
|
return;
|
|
|
|
if (url.search(/\.css$/i) != -1 && confirm (getMsg("tabdnd_drop", url)))
|
|
{
|
|
onSimulateCommand("/css " + url);
|
|
}
|
|
else if (url.search(/^irc:\/\//i) != -1)
|
|
{
|
|
gotoIRCURL (url);
|
|
}
|
|
}
|
|
|
|
contentDropObserver.getSupportedFlavours =
|
|
function tabdnd_gsf ()
|
|
{
|
|
var flavourSet = new FlavourSet();
|
|
flavourSet.appendFlavour("text/x-moz-url");
|
|
flavourSet.appendFlavour("application/x-moz-file", "nsIFile");
|
|
flavourSet.appendFlavour("text/unicode");
|
|
return flavourSet;
|
|
}
|
|
|
|
var tabDNDObserver = new Object();
|
|
|
|
tabDNDObserver.onDragStart =
|
|
function tabdnd_dstart (aEvent, aXferData, aDragAction)
|
|
{
|
|
var tb = aEvent.currentTarget;
|
|
var href = tb.getAttribute("href");
|
|
var name = tb.getAttribute("name");
|
|
|
|
aXferData.data = new TransferData();
|
|
/* x-moz-url has the format "<url>\n<name>", goodie */
|
|
aXferData.data.addDataForFlavour("text/x-moz-url", href + "\n" + name);
|
|
aXferData.data.addDataForFlavour("text/unicode", href);
|
|
aXferData.data.addDataForFlavour("text/html", "<a href='" + href + "'>" +
|
|
name + "</a>");
|
|
}
|
|
|
|
function deleteTab (tb)
|
|
{
|
|
var i, key = Number(tb.getAttribute("viewKey"));
|
|
|
|
if (!isNaN(key))
|
|
{
|
|
if ("isPermanent" in client.viewsArray[key].source &&
|
|
client.viewsArray[key].source.isPermanent)
|
|
{
|
|
window.alert (getMsg("deleteTabMsg"));
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
/* re-index higher toolbuttons */
|
|
for (i = key + 1; i < client.viewsArray.length; i++)
|
|
{
|
|
client.viewsArray[i].tb.setAttribute ("viewKey", i - 1);
|
|
}
|
|
arrayRemoveAt(client.viewsArray, key);
|
|
var tbinner = document.getElementById("views-tbar-inner");
|
|
tbinner.removeChild(tb);
|
|
}
|
|
}
|
|
else
|
|
dd ("*** INVALID OBJECT passed to deleteTab (" + tb + ") " +
|
|
"no viewKey attribute. (" + key + ")");
|
|
|
|
return key;
|
|
|
|
}
|
|
|
|
function filterOutput (msg, msgtype)
|
|
{
|
|
if ("outputFilters" in client)
|
|
{
|
|
for (var f in client.outputFilters)
|
|
{
|
|
if (client.outputFilters[f].enabled)
|
|
msg = client.outputFilters[f].func(msg, msgtype);
|
|
}
|
|
}
|
|
|
|
return msg;
|
|
}
|
|
|
|
client.connectToNetwork =
|
|
function cli_connet (netname, pass)
|
|
{
|
|
if (!(netname in client.networks))
|
|
{
|
|
display (getMsg("cli_attachNoNet", netname), "ERROR");
|
|
return false;
|
|
}
|
|
|
|
var netobj = client.networks[netname];
|
|
|
|
if (!("messages" in netobj))
|
|
netobj.displayHere (getMsg("cli_attachOpened", netname), "INFO");
|
|
setCurrentObject(netobj);
|
|
|
|
if (netobj.isConnected())
|
|
{
|
|
netobj.display (getMsg("cli_attachAlreadyThere", netname), "ERROR");
|
|
return true;
|
|
}
|
|
|
|
if (CIRCNetwork.prototype.INITIAL_NICK == client.defaultNick)
|
|
CIRCNetwork.prototype.INITIAL_NICK =
|
|
prompt (getMsg("cli_attachGetNick"), client.defaultNick);
|
|
|
|
if (!("connecting" in netobj))
|
|
netobj.display (getMsg("cli_attachWorking",netobj.name), "INFO");
|
|
netobj.connect(pass);
|
|
return true;
|
|
}
|
|
|
|
|
|
client.getURL =
|
|
function cli_geturl ()
|
|
{
|
|
return "irc://";
|
|
}
|
|
|
|
client.load =
|
|
function cli_load(url, obj)
|
|
{
|
|
if (!client._loader)
|
|
{
|
|
const LOADER_CTRID = "@mozilla.org/moz/jssubscript-loader;1";
|
|
const mozIJSSubScriptLoader =
|
|
Components.interfaces.mozIJSSubScriptLoader;
|
|
|
|
var cls;
|
|
if ((cls = Components.classes[LOADER_CTRID]))
|
|
client._loader = cls.createInstance (mozIJSSubScriptLoader);
|
|
}
|
|
|
|
try {
|
|
client.currentObject.display (getMsg("cli_loadLoading", url));
|
|
client._loader.loadSubScript (url, obj);
|
|
}
|
|
catch (ex)
|
|
{
|
|
var msg = getMsg("cli_loadError", ex.lineNumber, ex.fileName, ex);
|
|
client.currentObject.display (msg, "ERROR");
|
|
}
|
|
}
|
|
|
|
|
|
client.sayToCurrentTarget =
|
|
function cli_say(msg)
|
|
{
|
|
switch (client.currentObject.TYPE)
|
|
{
|
|
case "IRCChannel":
|
|
case "IRCUser":
|
|
case "IRCChanUser":
|
|
msg = filterOutput (msg, "PRIVMSG");
|
|
client.currentObject.display (msg, "PRIVMSG", "ME!",
|
|
client.currentObject);
|
|
client.currentObject.say (fromUnicode(msg));
|
|
break;
|
|
|
|
case "IRCClient":
|
|
client.onInputEval ({inputData: msg});
|
|
break;
|
|
|
|
default:
|
|
if (msg != "")
|
|
client.currentObject.display
|
|
(getMsg("cli_sayMsg", client.currentObject.TYPE), "ERROR");
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
CIRCNetwork.prototype.display =
|
|
function n_display (message, msgtype, sourceObj, destObj)
|
|
{
|
|
var o = getObjectDetails(client.currentObject);
|
|
|
|
if (client.SLOPPY_NETWORKS && client.currentObject != client &&
|
|
client.currentObject != this && o.network == this &&
|
|
o.server.connection.isConnected)
|
|
client.currentObject.display (message, msgtype, sourceObj, destObj);
|
|
else
|
|
this.displayHere (message, msgtype, sourceObj, destObj);
|
|
}
|
|
|
|
CIRCUser.prototype.display =
|
|
function u_display(message, msgtype, sourceObj, destObj)
|
|
{
|
|
if ("messages" in this)
|
|
this.displayHere (message, msgtype, sourceObj, destObj);
|
|
else
|
|
{
|
|
var o = getObjectDetails(client.currentObject);
|
|
if (o.server.connection.isConnected &&
|
|
o.network == this.parent.parent &&
|
|
client.currentObject.TYPE != "IRCUser")
|
|
client.currentObject.display (message, msgtype, sourceObj, destObj);
|
|
else
|
|
this.parent.parent.displayHere (message, msgtype, sourceObj,
|
|
destObj);
|
|
}
|
|
}
|
|
|
|
function display (message, msgtype, sourceObj, destObj)
|
|
{
|
|
client.currentObject.display (message, msgtype, sourceObj, destObj);
|
|
}
|
|
|
|
client.display =
|
|
client.displayHere =
|
|
CIRCNetwork.prototype.displayHere =
|
|
CIRCChannel.prototype.display =
|
|
CIRCChannel.prototype.displayHere =
|
|
CIRCUser.prototype.displayHere =
|
|
function __display(message, msgtype, sourceObj, destObj)
|
|
{
|
|
var canMergeData = false;
|
|
var canCollapseRow = false;
|
|
|
|
function setAttribs (obj, c, attrs)
|
|
{
|
|
if (attrs)
|
|
{
|
|
for (var a in attrs)
|
|
obj.setAttribute (a, attrs[a]);
|
|
}
|
|
obj.setAttribute ("class", c);
|
|
obj.setAttribute ("msg-type", msgtype);
|
|
obj.setAttribute ("msg-dest", toAttr);
|
|
obj.setAttribute ("dest-type", toType);
|
|
obj.setAttribute ("view-type", viewType);
|
|
if (fromAttr)
|
|
if (fromUser)
|
|
obj.setAttribute ("msg-user", fromAttr);
|
|
else
|
|
obj.setAttribute ("msg-source", fromAttr);
|
|
}
|
|
|
|
var blockLevel = false; /* true if this row should be rendered at block
|
|
* level, (like, if it has a really long nickname
|
|
* that might disturb the rest of the layout) */
|
|
var o = getObjectDetails (this); /* get the skinny on |this| */
|
|
var me;
|
|
if ("server" in o && "me" in o.server)
|
|
{
|
|
me = o.server.me; /* get the object representing the user */
|
|
}
|
|
if (sourceObj == "ME!") sourceObj = me; /* if the caller to passes "ME!"*/
|
|
if (destObj == "ME!") destObj = me; /* substitute the actual object */
|
|
|
|
var fromType = (sourceObj && sourceObj.TYPE) ? sourceObj.TYPE : "unk";
|
|
var fromUser = (fromType.search(/IRC.*User/) != -1);
|
|
var fromAttr;
|
|
if (fromUser && sourceObj == me) fromAttr = me.nick + " ME!";
|
|
else if (fromUser) fromAttr = sourceObj.nick;
|
|
else if (typeof sourceObj == "object") fromAttr = sourceObj.name;
|
|
|
|
var toType = (destObj) ? destObj.TYPE : "unk";
|
|
var toAttr;
|
|
|
|
if (destObj && destObj == me)
|
|
toAttr = me.nick + " ME!";
|
|
else if (toType == "IRCUser")
|
|
toAttr = destObj.nick;
|
|
else if (typeof destObj == "object")
|
|
toAttr = destObj.name;
|
|
|
|
/* isImportant means to style the messages as important, and flash the
|
|
* window, getAttention means just flash the window. */
|
|
var isImportant = false, getAttention = false, isSuperfluous = false;
|
|
var viewType = this.TYPE;
|
|
var code;
|
|
var msgRow = document.createElementNS("http://www.w3.org/1999/xhtml",
|
|
"html:tr");
|
|
setAttribs(msgRow, "msg");
|
|
|
|
//dd ("fromType is " + fromType + ", fromAttr is " + fromAttr);
|
|
var d = new Date();
|
|
var mins = d.getMinutes();
|
|
if (mins < 10)
|
|
mins = "0" + mins;
|
|
var statusString;
|
|
|
|
if (fromUser)
|
|
{
|
|
statusString =
|
|
getMsg("cli_statusString", [d.getMonth() + 1, d.getDate(),
|
|
d.getHours(), mins,
|
|
sourceObj.nick + "!" +
|
|
sourceObj.name + "@" + sourceObj.host]);
|
|
}
|
|
else
|
|
{
|
|
statusString =
|
|
getMsg("cli_statusString", [d.getMonth() + 1, d.getDate(),
|
|
d.getHours(), mins,
|
|
sourceObj ? sourceObj.name : this.name]);
|
|
}
|
|
|
|
if (fromType.search(/IRC.*User/) != -1 &&
|
|
msgtype.search(/PRIVMSG|ACTION|NOTICE/) != -1)
|
|
{
|
|
/* do nick things here */
|
|
var nick;
|
|
var nickURL;
|
|
|
|
if (sourceObj != me)
|
|
{
|
|
nick = sourceObj.properNick;
|
|
if (!nick)
|
|
nick = sourceObj.name + "@" + sourceObj.host;
|
|
else if ("getURL" in sourceObj)
|
|
nickURL = sourceObj.getURL();
|
|
|
|
if (toType == "IRCUser") /* msg from user to me */
|
|
{
|
|
getAttention = true;
|
|
this.defaultCompletion = "/msg " + nick + " ";
|
|
}
|
|
else /* msg from user to channel */
|
|
{
|
|
if (typeof (message == "string") && me)
|
|
{
|
|
isImportant = msgIsImportant (message, nick, me.nick);
|
|
if (isImportant)
|
|
this.defaultCompletion = nick +
|
|
client.ADDRESSED_NICK_SEP + " ";
|
|
}
|
|
}
|
|
}
|
|
else if (toType == "IRCUser") /* msg from me to user */
|
|
{
|
|
if (this.TYPE == "IRCUser")
|
|
nick = sourceObj.properNick;
|
|
else
|
|
nick = destObj.properNick;
|
|
}
|
|
else /* msg from me to channel */
|
|
{
|
|
nick = sourceObj.properNick;
|
|
}
|
|
|
|
if (!("mark" in this))
|
|
this.mark = "odd";
|
|
|
|
if (!("lastNickDisplayed" in this) ||
|
|
this.lastNickDisplayed != nick)
|
|
{
|
|
this.lastNickDisplayed = nick;
|
|
this.mark = (this.mark == "even") ? "odd" : "even";
|
|
}
|
|
|
|
var msgSource = document.createElementNS("http://www.w3.org/1999/xhtml",
|
|
"html:td");
|
|
setAttribs (msgSource, "msg-user", {statusText: statusString});
|
|
if (isImportant)
|
|
msgSource.setAttribute ("important", "true");
|
|
if (nick.length > client.MAX_NICK_DISPLAY)
|
|
blockLevel = true;
|
|
if (nickURL)
|
|
{
|
|
var nick_anchor =
|
|
document.createElementNS("http://www.w3.org/1999/xhtml",
|
|
"html:a");
|
|
nick_anchor.setAttribute ("class", "chatzilla-link");
|
|
nick_anchor.setAttribute ("href", nickURL);
|
|
nick_anchor.appendChild (newInlineText (nick));
|
|
msgSource.appendChild (nick_anchor);
|
|
}
|
|
else
|
|
{
|
|
msgSource.appendChild (newInlineText (nick));
|
|
}
|
|
msgRow.appendChild (msgSource);
|
|
canMergeData = client.COLLAPSE_MSGS;
|
|
canCollapseRow = client.COLLAPSE_ROWS;
|
|
|
|
}
|
|
else
|
|
{
|
|
isSuperfluous = true;
|
|
if (!client.debugMode && msgtype in client.responseCodeMap)
|
|
{
|
|
code = client.responseCodeMap[msgtype];
|
|
}
|
|
else
|
|
{
|
|
if (!client.debugMode && client.HIDE_CODES)
|
|
code = client.DEFAULT_RESPONSE_CODE;
|
|
else
|
|
code = "[" + msgtype + "]";
|
|
}
|
|
|
|
/* Display the message code */
|
|
var msgType = document.createElementNS("http://www.w3.org/1999/xhtml",
|
|
"html:td");
|
|
setAttribs (msgType, "msg-type", {statusText: statusString});
|
|
|
|
msgType.appendChild (newInlineText (code));
|
|
msgRow.appendChild (msgType);
|
|
}
|
|
|
|
if (message)
|
|
{
|
|
var msgData = document.createElementNS("http://www.w3.org/1999/xhtml",
|
|
"html:td");
|
|
setAttribs (msgData, "msg-data", {statusText: statusString,
|
|
colspan: client.INITIAL_COLSPAN});
|
|
if (isImportant)
|
|
msgData.setAttribute ("important", "true");
|
|
|
|
if ("mark" in this)
|
|
msgData.setAttribute ("mark", this.mark);
|
|
|
|
if (typeof message == "string")
|
|
{
|
|
msgData.appendChild (stringToMsg (message, this));
|
|
}
|
|
else
|
|
msgData.appendChild (message);
|
|
|
|
msgRow.appendChild (msgData);
|
|
}
|
|
|
|
if (isImportant)
|
|
msgRow.setAttribute ("important", "true");
|
|
|
|
if (blockLevel)
|
|
{
|
|
/* putting a div here crashes mozilla, so fake it with nested tables
|
|
* for now */
|
|
var tr = document.createElementNS ("http://www.w3.org/1999/xhtml",
|
|
"html:tr");
|
|
tr.setAttribute ("class", "msg-nested-tr");
|
|
var td = document.createElementNS ("http://www.w3.org/1999/xhtml",
|
|
"html:td");
|
|
td.setAttribute ("class", "msg-nested-td");
|
|
td.setAttribute ("colspan", "2");
|
|
|
|
tr.appendChild(td);
|
|
var table = document.createElementNS ("http://www.w3.org/1999/xhtml",
|
|
"html:table");
|
|
table.setAttribute ("class", "msg-nested-table");
|
|
table.setAttribute ("cellpadding", "0");
|
|
|
|
td.appendChild (table);
|
|
var tbody = document.createElementNS ("http://www.w3.org/1999/xhtml",
|
|
"html:tbody");
|
|
|
|
tbody.appendChild (msgRow);
|
|
table.appendChild (tbody);
|
|
msgRow = tr;
|
|
canMergeData = false;
|
|
canCollapseRow = false;
|
|
}
|
|
|
|
addHistory (this, msgRow, canMergeData, canCollapseRow);
|
|
if (isImportant || getAttention)
|
|
{
|
|
setTabState(this, "attention");
|
|
if (client.FLASH_WINDOW)
|
|
window.getAttention();
|
|
}
|
|
else
|
|
{
|
|
if (isSuperfluous)
|
|
setTabState(this, "superfluous");
|
|
else
|
|
setTabState(this, "activity");
|
|
}
|
|
|
|
if (isImportant && client.COPY_MESSAGES)
|
|
{
|
|
if ("network" in o && o.network != this)
|
|
o.network.displayHere("{" + this.name + "} " + message, msgtype,
|
|
sourceObj, destObj);
|
|
}
|
|
}
|
|
|
|
function addHistory (source, obj, mergeData, collapseRow)
|
|
{
|
|
var tbody;
|
|
|
|
if (!("messages" in source) || source.messages == null)
|
|
{
|
|
source.messages =
|
|
document.createElementNS ("http://www.w3.org/1999/xhtml",
|
|
"html:table");
|
|
|
|
source.messages.setAttribute ("class", "msg-table");
|
|
source.messages.setAttribute ("view-type", source.TYPE);
|
|
tbody = document.createElementNS ("http://www.w3.org/1999/xhtml",
|
|
"html:tbody");
|
|
source.messages.appendChild (tbody);
|
|
}
|
|
else
|
|
{
|
|
tbody = source.messages.firstChild;
|
|
}
|
|
|
|
var needScroll = false;
|
|
var w = window.frames[0];
|
|
|
|
if (client.PRINT_DIRECTION == 1)
|
|
{
|
|
if (mergeData || collapseRow)
|
|
{
|
|
var thisUserCol = obj.firstChild;
|
|
var thisMessageCol = thisUserCol.nextSibling;
|
|
var ci = findPreviousColumnInfo(source.messages);
|
|
var nickColumns = ci.nickColumns;
|
|
var rowExtents = ci.extents;
|
|
var nickColumnCount = nickColumns.length;
|
|
var sameNick = (nickColumnCount > 0 &&
|
|
nickColumns[nickColumnCount - 1].
|
|
getAttribute("msg-user") ==
|
|
thisUserCol.getAttribute("msg-user"));
|
|
var lastRowSpan = (nickColumnCount > 0) ?
|
|
Number(nickColumns[0].getAttribute("rowspan")) : 0;
|
|
if (sameNick && mergeData)
|
|
{
|
|
if (obj.getAttribute("important"))
|
|
{
|
|
nickColumns[nickColumnCount - 1].setAttribute ("important",
|
|
true);
|
|
}
|
|
/* message is from the same person as last time,
|
|
* strip the nick first... */
|
|
obj.removeChild(obj.firstChild);
|
|
/* Adjust height of previous cells, maybe. */
|
|
for (i = 0; i < rowExtents.length - 1; ++i)
|
|
{
|
|
var myLastData =
|
|
rowExtents[i].childNodes[nickColumnCount - 1];
|
|
var myLastRowSpan = (myLastData) ?
|
|
myLastData.getAttribute("rowspan") : 0;
|
|
if (myLastData && myLastRowSpan > 1)
|
|
{
|
|
myLastData.removeAttribute("rowspan");
|
|
}
|
|
}
|
|
/* then add one to the colspan for the previous user columns */
|
|
if (!lastRowSpan)
|
|
lastRowSpan = 1;
|
|
for (var i = 0; i < nickColumns.length; ++i)
|
|
nickColumns[i].setAttribute ("rowspan", lastRowSpan + 1);
|
|
}
|
|
else if (!sameNick && collapseRow && nickColumnCount > 0 &&
|
|
nickColumnCount < client.MAX_MSG_PER_ROW)
|
|
{
|
|
/* message is from a different person, but is elegible to
|
|
* be contained by the previous row. */
|
|
var tr = nickColumns[0].parentNode;
|
|
for (i = 0; i < rowExtents.length; ++i)
|
|
rowExtents[i].lastChild.removeAttribute("colspan");
|
|
obj.firstChild.setAttribute ("rowspan", lastRowSpan);
|
|
tr.appendChild (obj.firstChild);
|
|
var lastColSpan =
|
|
Number(rowExtents[0].lastChild.getAttribute("colspan"));
|
|
obj.lastChild.setAttribute ("colspan", lastColSpan - 2);
|
|
obj.lastChild.setAttribute ("rowspan", lastRowSpan);
|
|
tr.appendChild (obj.lastChild);
|
|
obj = null;
|
|
}
|
|
}
|
|
|
|
if ((w.document.height - (w.innerHeight + w.pageYOffset)) <
|
|
(w.innerHeight / 3))
|
|
needScroll = true;
|
|
if (obj)
|
|
tbody.appendChild (obj);
|
|
}
|
|
else
|
|
tbody.insertBefore (obj, source.messages.firstChild);
|
|
|
|
if (source.MAX_MESSAGES)
|
|
{
|
|
if (typeof source.messageCount != "number")
|
|
source.messageCount = 1;
|
|
else
|
|
source.messageCount++;
|
|
|
|
if (source.messageCount > source.MAX_MESSAGES)
|
|
if (client.PRINT_DIRECTION == 1)
|
|
{
|
|
tbody.removeChild (tbody.firstChild);
|
|
--source.messageCount;
|
|
while (tbody.firstChild &&
|
|
tbody.firstChild.firstChild.getAttribute("class") ==
|
|
"msg-data")
|
|
{
|
|
--source.messageCount;
|
|
tbody.removeChild (tbody.firstChild);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
tbody.removeChild (tbody.lastChild);
|
|
--source.messageCount;
|
|
while (tbody.lastChild &&
|
|
tbody.lastChild.firstChild.getAttribute("class") ==
|
|
"msg-data")
|
|
{
|
|
--source.messageCount;
|
|
tbody.removeChild (tbody.lastChild);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ("currentObject" in client && client.currentObject == source &&
|
|
needScroll)
|
|
{
|
|
scrollDown();
|
|
setTimeout ("scrollDown()", 500);
|
|
setTimeout ("scrollDown()", 1000);
|
|
setTimeout ("scrollDown()", 2000);
|
|
}
|
|
|
|
}
|
|
|
|
function findPreviousColumnInfo (table)
|
|
{
|
|
var extents = new Array();
|
|
var tr = table.firstChild.lastChild;
|
|
var className = tr ? tr.firstChild.getAttribute("class") : "";
|
|
while (tr && className.search(/msg-user|msg-type|msg-nested-td/) == -1)
|
|
{
|
|
extents.push(tr);
|
|
tr = tr.previousSibling;
|
|
if (tr)
|
|
className = tr.firstChild.getAttribute("class");
|
|
}
|
|
|
|
if (!tr || className != "msg-user")
|
|
return {extents: [], nickColumns: []};
|
|
|
|
extents.push(tr);
|
|
var nickCol = tr.firstChild;
|
|
var nickCols = new Array();
|
|
while (nickCol)
|
|
{
|
|
if (nickCol.getAttribute("class") == "msg-user")
|
|
nickCols.push (nickCol);
|
|
nickCol = nickCol.nextSibling.nextSibling;
|
|
}
|
|
|
|
return {extents: extents, nickColumns: nickCols};
|
|
}
|
|
|
|
client.getConnectionCount =
|
|
function cli_gccount ()
|
|
{
|
|
var count = 0;
|
|
|
|
for (var n in client.networks)
|
|
if (client.networks[n].isConnected())
|
|
++count;
|
|
|
|
return count;
|
|
}
|
|
|
|
client.quit =
|
|
function cli_quit (reason)
|
|
{
|
|
for (var n in client.networks)
|
|
if ("primServ" in client.networks[n])
|
|
client.networks[n].quit (reason);
|
|
}
|
|
|
|
/* gets a tab-complete match for the line of text specified by |line|. wordStart
|
|
* is the position within |line| that starts the word being matched, wordEnd
|
|
* marks the end position. |cursorPos| marks the position of the caret in the
|
|
* textbox.
|
|
*/
|
|
client.performTabMatch =
|
|
function gettabmatch_usr (line, wordStart, wordEnd, word, cursorPos)
|
|
{
|
|
if (wordStart != 0 || line[0] != client.COMMAND_CHAR)
|
|
return null;
|
|
|
|
var matches = client.commands.listNames(word.substr(1));
|
|
if (matches.length == 1 && wordEnd == line.length)
|
|
{
|
|
matches[0] = client.COMMAND_CHAR + matches[0] + " ";
|
|
}
|
|
else
|
|
{
|
|
for (var i in matches)
|
|
matches[i] = client.COMMAND_CHAR + matches[i];
|
|
}
|
|
|
|
return matches;
|
|
}
|
|
|
|
CIRCChannel.prototype.performTabMatch =
|
|
CIRCNetwork.prototype.performTabMatch =
|
|
CIRCUser.prototype.performTabMatch =
|
|
function gettabmatch_usr (line, wordStart, wordEnd, word, cursorpos)
|
|
{
|
|
if (wordStart == 0 && line[0] == client.COMMAND_CHAR)
|
|
return client.performTabMatch (line, wordStart, wordEnd, word,
|
|
cursorpos);
|
|
|
|
if (!("users" in this))
|
|
return [];
|
|
|
|
var users = this.users;
|
|
var nicks = new Array();
|
|
|
|
for (var n in users)
|
|
nicks.push (users[n].nick);
|
|
|
|
var matches = matchEntry (word, nicks);
|
|
if (matches.length == 1)
|
|
{
|
|
matches[0] = this.users[matches[0]].properNick;
|
|
if (wordStart == 0)
|
|
matches[0] += client.ADDRESSED_NICK_SEP;
|
|
|
|
if (wordEnd == line.length)
|
|
{
|
|
/* add a space if the word is at the end of the line. */
|
|
matches[0] += " ";
|
|
}
|
|
}
|
|
|
|
return matches;
|
|
}
|
|
|
|
/**
|
|
* Retrieves the selected nicks from the user-list
|
|
* tree object. This grabs the tree element's
|
|
* selected items, extracts the appropriate text
|
|
* for the nick, promotes each nick to a CIRCChanUser
|
|
* instance and returns an array of these objects.
|
|
*/
|
|
CIRCChannel.prototype.getSelectedUsers =
|
|
function my_getselectedusers ()
|
|
{
|
|
|
|
/* Grab a reference to the tree element with ID = user-list . See chatzilla.xul */
|
|
var tree = document.getElementById("user-list");
|
|
var cell; /* reference to each selected cell of the tree object */
|
|
var rv_ary = new Array; /* return value arrray for CIRCChanUser objects */
|
|
|
|
var rangeCount = tree.view.selection.getRangeCount();
|
|
for (var i = 0; i < rangeCount; ++i)
|
|
{
|
|
var start = {}, end = {};
|
|
tree.view.selection.getRangeAt(i, start, end);
|
|
for (var k = start.value; k <= end.value; ++k)
|
|
{
|
|
var item = tree.contentView.getItemAtIndex(k);
|
|
|
|
/* First, set the reference to the XUL element. */
|
|
cell = item.firstChild.childNodes[2];
|
|
|
|
/* Now, create an instance of CIRCChaneUser by passing the text
|
|
* of the cell to the getUser function of this CIRCChannel instance.
|
|
*/
|
|
rv_ary[i] = this.getUser( cell.getAttribute("label") );
|
|
}
|
|
}
|
|
|
|
/*
|
|
* USAGE NOTE: If the return value is non-null, the caller
|
|
* can assume the array is valid, and NOT
|
|
* need to check the length, and vice versa.
|
|
*/
|
|
|
|
return rv_ary.length > 0 ? rv_ary : null;
|
|
|
|
}
|
|
|
|
CIRCChannel.prototype.getGraphResource =
|
|
function my_graphres ()
|
|
{
|
|
if (!("rdfRes" in this))
|
|
{
|
|
this.rdfRes =
|
|
client.rdf.GetResource(RES_PFX + "CHANNEL:" +
|
|
this.parent.parent.name +
|
|
":" + this.name);
|
|
//dd ("created channel resource " + this.rdfRes.Value);
|
|
|
|
}
|
|
|
|
return this.rdfRes;
|
|
}
|
|
|
|
CIRCUser.prototype.getGraphResource =
|
|
function usr_graphres()
|
|
{
|
|
if (this.TYPE != "IRCChanUser")
|
|
dd ("** WARNING: cuser.getGraphResource called on wrong object **");
|
|
|
|
var rdf = client.rdf;
|
|
|
|
if (!("rdfRes" in this))
|
|
{
|
|
if (!("nextResID" in CIRCUser))
|
|
CIRCUser.nextResID = 0;
|
|
|
|
this.rdfRes = rdf.GetResource (RES_PFX + "CUSER:" +
|
|
this.parent.parent.parent.name + ":" +
|
|
this.parent.name + ":" +
|
|
CIRCUser.nextResID++);
|
|
|
|
//dd ("created cuser resource " + this.rdfRes.Value);
|
|
|
|
rdf.Assert (this.rdfRes, rdf.resNick, rdf.GetLiteral(this.properNick));
|
|
if (this.name)
|
|
rdf.Assert (this.rdfRes, rdf.resUser, rdf.GetLiteral(this.name));
|
|
else
|
|
rdf.Assert (this.rdfRes, rdf.resUser, rdf.litUnk);
|
|
if (this.host)
|
|
rdf.Assert (this.rdfRes, rdf.resHost, rdf.GetLiteral(this.host));
|
|
else
|
|
rdf.Assert (this.rdfRes, rdf.resHost, rdf.litUnk);
|
|
|
|
rdf.Assert (this.rdfRes, rdf.resOp,
|
|
this.isOp ? rdf.litTrue : rdf.litFalse);
|
|
rdf.Assert (this.rdfRes, rdf.resVoice,
|
|
this.isVoice ? rdf.litTrue : rdf.litFalse);
|
|
}
|
|
|
|
return this.rdfRes;
|
|
|
|
}
|
|
|
|
CIRCUser.prototype.updateGraphResource =
|
|
function usr_updres()
|
|
{
|
|
if (this.TYPE != "IRCChanUser")
|
|
dd ("** WARNING: cuser.updateGraphResource called on wrong object **");
|
|
|
|
if (!("rdfRes" in this))
|
|
this.getGraphResource();
|
|
|
|
var rdf = client.rdf;
|
|
|
|
rdf.Change (this.rdfRes, rdf.resNick, rdf.GetLiteral(this.properNick));
|
|
if (this.name)
|
|
rdf.Change (this.rdfRes, rdf.resUser, rdf.GetLiteral(this.name));
|
|
else
|
|
rdf.Change (this.rdfRes, rdf.resUser, rdf.litUnk);
|
|
if (this.host)
|
|
rdf.Change (this.rdfRes, rdf.resHost, rdf.GetLiteral(this.host));
|
|
else
|
|
rdf.Change (this.rdfRes, rdf.resHost, rdf.litUnk);
|
|
|
|
rdf.Change (this.rdfRes, rdf.resOp,
|
|
this.isOp ? rdf.litTrue : rdf.litFalse);
|
|
rdf.Change (this.rdfRes, rdf.resVoice,
|
|
this.isVoice ? rdf.litTrue : rdf.litFalse);
|
|
}
|