ChatZilla only. r=gijs git-svn-id: svn://10.0.0.236/trunk@257496 18797224-902f-48f8-a5cc-f745e15eee43
763 lines
25 KiB
JavaScript
763 lines
25 KiB
JavaScript
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
*
|
|
* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* 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 the Initial Developer are Copyright (C) 1999
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Robert Ginda, rginda@ndcico.com, original author
|
|
* Samuel Sieb, samuel@sieb.net, MIRC color codes
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
/* This file contains the munger functions and rules used by ChatZilla.
|
|
* It's generally a bad idea to call munger functions inside ChatZilla for
|
|
* anything but munging (chat) output.
|
|
*/
|
|
|
|
function initMunger()
|
|
{
|
|
/* linkRE: the general URL linkifier regular expression:
|
|
*
|
|
* - start with whitespace, non-word, or begining-of-line
|
|
* - then match:
|
|
* - EITHER scheme (word + hyphen), colon, then lots of non-whitespace
|
|
* - OR "www" followed by at least 2 sets of:
|
|
* - "." plus some non-whitespace, non-"." characters
|
|
* - must end match with a word-break
|
|
* - include a "/" or "=" beyond break if present
|
|
* - end with whitespace, non-word, or end-of-line
|
|
*/
|
|
client.linkRE =
|
|
/(?:\s|\W|^)((?:(\w[\w-]+):[^\s]+|www(\.[^.\s]+){2,})\b[\/=\)]?)(?=\s|\W|$)/;
|
|
|
|
// Colours: \x03, with optional foreground and background colours
|
|
client.colorRE = /(\x03((\d{1,2})(,\d{1,2}|)|))/;
|
|
|
|
client.whitespaceRE = new RegExp("(\\S{" + client.MAX_WORD_DISPLAY + ",})");
|
|
|
|
const LOW_PRIORITY = 5;
|
|
const NORMAL_PRIORITY = 10;
|
|
const HIGH_PRIORITY = 15;
|
|
const HIGHER_PRIORITY = 20;
|
|
|
|
var munger = client.munger = new CMunger(insertText);
|
|
// Special internal munger!
|
|
munger.addRule(".inline-buttons", /(\[\[.*?\]\])/, insertInlineButton,
|
|
10, 5, false);
|
|
munger.addRule("quote", /(``|'')/, insertQuote,
|
|
NORMAL_PRIORITY, NORMAL_PRIORITY);
|
|
munger.addRule("bold", /(?:[\s(\[]|^)(\*[^*()]*\*)(?:[\s\]).,;!\?]|$)/,
|
|
"chatzilla-bold", NORMAL_PRIORITY, NORMAL_PRIORITY);
|
|
munger.addRule("underline", /(?:[\s(\[]|^)(\_[^_()]*\_)(?:[\s\]).,;!\?]|$)/,
|
|
"chatzilla-underline", NORMAL_PRIORITY, NORMAL_PRIORITY);
|
|
munger.addRule("italic", /(?:\s|^)(\/[^\/()]*\/)(?:[\s.,]|$)/,
|
|
"chatzilla-italic", NORMAL_PRIORITY, NORMAL_PRIORITY);
|
|
/* allow () chars inside |code()| blocks */
|
|
munger.addRule("teletype", /(?:\s|^)(\|[^|]*\|)(?:[\s.,]|$)/,
|
|
"chatzilla-teletype", NORMAL_PRIORITY, NORMAL_PRIORITY);
|
|
munger.addRule(".mirc-colors", client.colorRE, mircChangeColor,
|
|
NORMAL_PRIORITY, NORMAL_PRIORITY);
|
|
munger.addRule(".mirc-bold", /(\x02)/, mircToggleBold,
|
|
NORMAL_PRIORITY, NORMAL_PRIORITY);
|
|
munger.addRule(".mirc-underline", /(\x1f)/, mircToggleUnder,
|
|
NORMAL_PRIORITY, NORMAL_PRIORITY);
|
|
munger.addRule(".mirc-color-reset", /(\x0f)/, mircResetColor,
|
|
NORMAL_PRIORITY, NORMAL_PRIORITY);
|
|
munger.addRule(".mirc-reverse", /(\x16)/, mircReverseColor,
|
|
NORMAL_PRIORITY, NORMAL_PRIORITY);
|
|
munger.addRule("ctrl-char", /([\x01-\x1f])/, showCtrlChar,
|
|
NORMAL_PRIORITY, NORMAL_PRIORITY);
|
|
munger.addRule("link", client.linkRE, insertLink, NORMAL_PRIORITY, HIGH_PRIORITY);
|
|
|
|
// This has a higher starting priority so as to get it to match before the
|
|
// normal link, which won't know about mailto and then fail.
|
|
munger.addRule(".mailto",
|
|
/(?:\s|\W|^)((mailto:)?[^:;\\<>\[\]()\'\"\s\u201d]+@[^.<>\[\]()\'\"\s\u201d]+\.[^<>\[\]()\'\"\s\u201d]+)/i,
|
|
insertMailToLink, NORMAL_PRIORITY, HIGHER_PRIORITY, false);
|
|
munger.addRule("bugzilla-link",
|
|
/(?:\s|\W|^)(bug\s+(?:#?\d+|#[^\s,]{1,20})(?:\s+comment\s+#?\d+)?)/i,
|
|
insertBugzillaLink, NORMAL_PRIORITY, NORMAL_PRIORITY);
|
|
munger.addRule("channel-link",
|
|
/(?:\s|\W|^)[@%+]?(#[^<>,\[\](){}\"\s\u201d]*[^:,.<>\[\](){}\'\"\s\u201d])/i,
|
|
insertChannelLink, NORMAL_PRIORITY, NORMAL_PRIORITY);
|
|
munger.addRule("talkback-link", /(?:\W|^)(TB\d{8,}[A-Z]?)(?:\W|$)/,
|
|
insertTalkbackLink, NORMAL_PRIORITY, NORMAL_PRIORITY);
|
|
|
|
munger.addRule("face",
|
|
/((^|\s)(?:[>]?[B8=:;(xX][~']?[-^v"]?(?:[)|(PpSs0oO\?\[\]\/\\]|D+)|>[-^v]?\)|[oO9][._][oO9])(\s|$))/,
|
|
insertSmiley, NORMAL_PRIORITY, NORMAL_PRIORITY);
|
|
munger.addRule("rheet", /(?:\s|\W|^)(rhee+t\!*)(?:\s|$)/i, insertRheet, 10, 10);
|
|
munger.addRule("word-hyphenator", client.whitespaceRE,
|
|
insertHyphenatedWord, LOW_PRIORITY, NORMAL_PRIORITY);
|
|
|
|
client.enableColors = client.prefs["munger.colorCodes"];
|
|
var branch = client.prefManager.prefBranch;
|
|
for (var entry in munger.entries)
|
|
{
|
|
if (!isinstance(munger.entries[entry], Object))
|
|
continue;
|
|
|
|
for (var rule in munger.entries[entry])
|
|
{
|
|
if (rule[0] == ".")
|
|
continue;
|
|
|
|
try
|
|
{
|
|
munger.entries[entry][rule].enabled =
|
|
branch.getBoolPref("munger." + rule);
|
|
}
|
|
catch (ex)
|
|
{
|
|
// nada
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function insertLink(matchText, containerTag, data, mungerEntry)
|
|
{
|
|
var href;
|
|
var linkText;
|
|
|
|
var trailing;
|
|
ary = matchText.match(/([.,?\)]+)$/);
|
|
if (ary)
|
|
{
|
|
linkText = RegExp.leftContext;
|
|
trailing = ary[1];
|
|
|
|
// We special-case links that end with (something), often found on wikis
|
|
// if "trailing" starts with ) and there's an unclosed ( in the
|
|
// "linkText"; then we put the final ) back in
|
|
if ((trailing.indexOf(")") == 0) && (linkText.match(/\([^\)]*$/)))
|
|
{
|
|
|
|
linkText += ")";
|
|
trailing = trailing.substr(1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
linkText = matchText;
|
|
}
|
|
|
|
var ary = linkText.match(/^(\w[\w-]+):/);
|
|
if (ary)
|
|
{
|
|
if (!("schemes" in client))
|
|
{
|
|
var pfx = "@mozilla.org/network/protocol;1?name=";
|
|
var len = pfx.length;
|
|
|
|
client.schemes = new Object();
|
|
for (var c in Components.classes)
|
|
{
|
|
if (c.indexOf(pfx) == 0)
|
|
client.schemes[c.substr(len)] = true;
|
|
}
|
|
}
|
|
|
|
if (!(ary[1] in client.schemes))
|
|
{
|
|
mungerEntry.enabled = false;
|
|
client.munger.munge(matchText, containerTag, data);
|
|
mungerEntry.enabled = true;
|
|
return;
|
|
}
|
|
|
|
href = linkText;
|
|
}
|
|
else
|
|
{
|
|
href = "http://" + linkText;
|
|
}
|
|
|
|
/* This gives callers to the munger control over URLs being logged; the
|
|
* channel topic munger uses this, as well as the "is important" checker.
|
|
* If either of |dontLogURLs| or |noStateChange| is present and true, we
|
|
* don't log.
|
|
*/
|
|
if ((!("dontLogURLs" in data) || !data.dontLogURLs) &&
|
|
(!("noStateChange" in data) || !data.noStateChange))
|
|
{
|
|
var max = client.prefs["urls.store.max"];
|
|
if (client.prefs["urls.list"].unshift(href) > max)
|
|
client.prefs["urls.list"].pop();
|
|
client.prefs["urls.list"].update();
|
|
}
|
|
|
|
var anchor = document.createElementNS(XHTML_NS, "html:a");
|
|
var mircRE = /\x1f|\x02|\x0f|\x16|\x03([0-9]{1,2}(,[0-9]{1,2})?)?/g;
|
|
anchor.setAttribute("href", href.replace(mircRE, ""));
|
|
|
|
// Carry over formatting.
|
|
var otherFormatting = calcClass(data);
|
|
if (otherFormatting)
|
|
anchor.setAttribute("class", "chatzilla-link " + otherFormatting);
|
|
else
|
|
anchor.setAttribute("class", "chatzilla-link");
|
|
|
|
anchor.setAttribute("target", "_content");
|
|
mungerEntry.enabled = false;
|
|
data.inLink = true;
|
|
client.munger.munge(linkText, anchor, data);
|
|
mungerEntry.enabled = true;
|
|
delete data.inLink;
|
|
containerTag.appendChild(anchor);
|
|
if (trailing)
|
|
insertText(trailing, containerTag, data);
|
|
|
|
}
|
|
|
|
function insertMailToLink(matchText, containerTag, eventData, mungerEntry)
|
|
{
|
|
if (("inLink" in eventData) && eventData.inLink)
|
|
{
|
|
mungerEntry.enabled = false;
|
|
client.munger.munge(matchText, containerTag, eventData);
|
|
mungerEntry.enabled = true;
|
|
return;
|
|
}
|
|
|
|
var href;
|
|
|
|
if (matchText.indexOf("mailto:") != 0)
|
|
href = "mailto:" + matchText;
|
|
else
|
|
href = matchText;
|
|
|
|
var anchor = document.createElementNS(XHTML_NS, "html:a");
|
|
var mircRE = /\x1f|\x02|\x0f|\x16|\x03([0-9]{1,2}(,[0-9]{1,2})?)?/g;
|
|
anchor.setAttribute("href", href.replace(mircRE, ""));
|
|
|
|
// Carry over formatting.
|
|
var otherFormatting = calcClass(eventData);
|
|
if (otherFormatting)
|
|
anchor.setAttribute("class", "chatzilla-link " + otherFormatting);
|
|
else
|
|
anchor.setAttribute("class", "chatzilla-link");
|
|
|
|
//anchor.setAttribute ("target", "_content");
|
|
mungerEntry.enabled = false;
|
|
eventData.inLink = true;
|
|
client.munger.munge(matchText, anchor, eventData);
|
|
mungerEntry.enabled = true;
|
|
delete eventData.inLink;
|
|
containerTag.appendChild(anchor);
|
|
|
|
}
|
|
|
|
function insertChannelLink(matchText, containerTag, eventData, mungerEntry)
|
|
{
|
|
if (("inLink" in eventData) && eventData.inLink)
|
|
{
|
|
mungerEntry.enabled = false;
|
|
client.munger.munge(matchText, containerTag, eventData);
|
|
mungerEntry.enabled = true;
|
|
return;
|
|
}
|
|
|
|
var bogusChannels =
|
|
/^#(include|error|define|if|ifdef|else|elsif|endif)$/i;
|
|
|
|
if (!("network" in eventData) || !eventData.network ||
|
|
matchText.search(bogusChannels) != -1)
|
|
{
|
|
containerTag.appendChild(document.createTextNode(matchText));
|
|
return;
|
|
}
|
|
|
|
var linkText = removeColorCodes(matchText);
|
|
var encodedLinkText = fromUnicode(linkText, eventData.sourceObject);
|
|
var anchor = document.createElementNS(XHTML_NS, "html:a");
|
|
anchor.setAttribute("href", eventData.network.getURL(encodedLinkText));
|
|
|
|
// Carry over formatting.
|
|
var otherFormatting = calcClass(eventData);
|
|
if (otherFormatting)
|
|
anchor.setAttribute("class", "chatzilla-link " + otherFormatting);
|
|
else
|
|
anchor.setAttribute("class", "chatzilla-link");
|
|
|
|
mungerEntry.enabled = false;
|
|
eventData.inLink = true;
|
|
client.munger.munge(matchText, anchor, eventData);
|
|
mungerEntry.enabled = true;
|
|
delete eventData.inLink;
|
|
containerTag.appendChild(anchor);
|
|
}
|
|
|
|
function insertTalkbackLink(matchText, containerTag, eventData, mungerEntry)
|
|
{
|
|
if (("inLink" in eventData) && eventData.inLink)
|
|
{
|
|
mungerEntry.enabled = false;
|
|
client.munger.munge(matchText, containerTag, eventData);
|
|
mungerEntry.enabled = true;
|
|
return;
|
|
}
|
|
|
|
var anchor = document.createElementNS(XHTML_NS, "html:a");
|
|
|
|
anchor.setAttribute("href", "http://talkback-public.mozilla.org/" +
|
|
"search/start.jsp?search=2&type=iid&id=" + matchText);
|
|
|
|
// Carry over formatting.
|
|
var otherFormatting = calcClass(eventData);
|
|
if (otherFormatting)
|
|
anchor.setAttribute("class", "chatzilla-link " + otherFormatting);
|
|
else
|
|
anchor.setAttribute("class", "chatzilla-link");
|
|
|
|
mungerEntry.enabled = false;
|
|
client.munger.munge(matchText, anchor, eventData);
|
|
mungerEntry.enabled = true;
|
|
containerTag.appendChild(anchor);
|
|
}
|
|
|
|
function insertBugzillaLink (matchText, containerTag, eventData, mungerEntry)
|
|
{
|
|
if (("inLink" in eventData) && eventData.inLink)
|
|
{
|
|
mungerEntry.enabled = false;
|
|
client.munger.munge(matchText, containerTag, eventData);
|
|
mungerEntry.enabled = true;
|
|
return;
|
|
}
|
|
|
|
var prefs = client.prefs;
|
|
if (eventData.channel)
|
|
prefs = eventData.channel.prefs;
|
|
else if (eventData.network)
|
|
prefs = eventData.network.prefs;
|
|
|
|
var bugURL = prefs["bugURL"];
|
|
var bugURLcomment = prefs["bugURL.comment"];
|
|
|
|
if (bugURL.length > 0)
|
|
{
|
|
var idOrAlias = matchText.match(/bug\s+#?(\d+|[^\s,]{1,20})/i)[1];
|
|
bugURL = bugURL.replace("%s", idOrAlias);
|
|
|
|
if (matchText.indexOf("comment") != -1)
|
|
{
|
|
var commentNum = matchText.match(/comment\s+#?(\d+)/i)[1];
|
|
/* If the comment is a complete URL, use only that, replacing %1$s
|
|
* and %2$s with the bug number and comment number, respectively.
|
|
* Otherwise, append the comment preference to the main one,
|
|
* replacing just %s in each.
|
|
*/
|
|
if (bugURLcomment.match(/^\w+:/))
|
|
{
|
|
bugURL = bugURLcomment;
|
|
bugURL = bugURL.replace("%1$s", idOrAlias);
|
|
bugURL = bugURL.replace("%2$s", commentNum);
|
|
}
|
|
else
|
|
{
|
|
bugURL += bugURLcomment.replace("%s", commentNum);
|
|
}
|
|
}
|
|
|
|
var anchor = document.createElementNS(XHTML_NS, "html:a");
|
|
anchor.setAttribute("href", bugURL);
|
|
// Carry over formatting.
|
|
var otherFormatting = calcClass(eventData);
|
|
if (otherFormatting)
|
|
anchor.setAttribute("class", "chatzilla-link " + otherFormatting);
|
|
else
|
|
anchor.setAttribute("class", "chatzilla-link");
|
|
|
|
anchor.setAttribute("target", "_content");
|
|
mungerEntry.enabled = false;
|
|
eventData.inLink = true;
|
|
client.munger.munge(matchText, anchor, eventData);
|
|
mungerEntry.enabled = true;
|
|
delete eventData.inLink;
|
|
containerTag.appendChild(anchor);
|
|
}
|
|
else
|
|
{
|
|
mungerEntry.enabled = false;
|
|
client.munger.munge(matchText, containerTag, eventData);
|
|
mungerEntry.enabled = true;
|
|
}
|
|
}
|
|
|
|
function insertRheet(matchText, containerTag, eventData, mungerEntry)
|
|
{
|
|
if (("inLink" in eventData) && eventData.inLink)
|
|
{
|
|
mungerEntry.enabled = false;
|
|
client.munger.munge(matchText, containerTag, eventData);
|
|
mungerEntry.enabled = true;
|
|
return;
|
|
}
|
|
|
|
var anchor = document.createElementNS(XHTML_NS, "html:a");
|
|
anchor.setAttribute("href",
|
|
"http://ftp.mozilla.org/pub/mozilla.org/mozilla/libraries/bonus-tracks/rheet.wav");
|
|
anchor.setAttribute("class", "chatzilla-rheet chatzilla-link");
|
|
//anchor.setAttribute ("target", "_content");
|
|
insertText(matchText, anchor, eventData);
|
|
containerTag.appendChild(anchor);
|
|
}
|
|
|
|
function insertQuote (matchText, containerTag)
|
|
{
|
|
if (matchText == "``")
|
|
containerTag.appendChild(document.createTextNode("\u201c"));
|
|
else
|
|
containerTag.appendChild(document.createTextNode("\u201d"));
|
|
containerTag.appendChild(document.createElementNS(XHTML_NS, "html:wbr"));
|
|
}
|
|
|
|
function insertSmiley(emoticon, containerTag)
|
|
{
|
|
var type = "error";
|
|
|
|
if (emoticon.search(/\>[-^v]?\)/) != -1)
|
|
type = "face-alien";
|
|
else if (emoticon.search(/\>[=:;][-^v]?[(|]/) != -1)
|
|
type = "face-angry";
|
|
else if (emoticon.search(/[=:;][-^v]?[Ss\\\/]/) != -1)
|
|
type = "face-confused";
|
|
else if (emoticon.search(/[B8][-^v]?[)\]]/) != -1)
|
|
type = "face-cool";
|
|
else if (emoticon.search(/[=:;][~'][-^v]?\(/) != -1)
|
|
type = "face-cry";
|
|
else if (emoticon.search(/o[._]O/) != -1)
|
|
type = "face-dizzy";
|
|
else if (emoticon.search(/O[._]o/) != -1)
|
|
type = "face-dizzy-back";
|
|
else if (emoticon.search(/o[._]o|O[._]O/) != -1)
|
|
type = "face-eek";
|
|
else if (emoticon.search(/\>[=:;][-^v]?D/) != -1)
|
|
type = "face-evil";
|
|
else if (emoticon.search(/[=:;][-^v]?DD/) != -1)
|
|
type = "face-lol";
|
|
else if (emoticon.search(/[=:;][-^v]?D/) != -1)
|
|
type = "face-laugh";
|
|
else if (emoticon.search(/\([-^v]?D|[xX][-^v]?D/) != -1)
|
|
type = "face-rofl";
|
|
else if (emoticon.search(/[=:;][-^v]?\|/) != -1)
|
|
type = "face-normal";
|
|
else if (emoticon.search(/[=:;][-^v]?\?/) != -1)
|
|
type = "face-question";
|
|
else if (emoticon.search(/[=:;]"[)\]]/) != -1)
|
|
type = "face-red";
|
|
else if (emoticon.search(/9[._]9/) != -1)
|
|
type = "face-rolleyes";
|
|
else if (emoticon.search(/[=:;][-^v]?[(\[]/) != -1)
|
|
type = "face-sad";
|
|
else if (emoticon.search(/[=:][-^v]?[)\]]/) != -1)
|
|
type = "face-smile";
|
|
else if (emoticon.search(/[=:;][-^v]?[0oO]/) != -1)
|
|
type = "face-surprised";
|
|
else if (emoticon.search(/[=:;][-^v]?[pP]/) != -1)
|
|
type = "face-tongue";
|
|
else if (emoticon.search(/;[-^v]?[)\]]/) != -1)
|
|
type = "face-wink";
|
|
|
|
if (type == "error")
|
|
{
|
|
// We didn't actually match anything, so it'll be a too-generic match
|
|
// from the munger RegExp.
|
|
containerTag.appendChild(document.createTextNode(emoticon));
|
|
return;
|
|
}
|
|
|
|
var span = document.createElementNS(XHTML_NS, "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(XHTML_NS, "html:span");
|
|
span.setAttribute("class", "chatzilla-emote");
|
|
span.setAttribute("type", type);
|
|
span.setAttribute("title", emoticon);
|
|
span.setAttribute("role", "image");
|
|
containerTag.appendChild(span);
|
|
|
|
}
|
|
|
|
function mircChangeColor (colorInfo, containerTag, data)
|
|
{
|
|
/* If colors are disabled, the caller doesn't want colors specifically, or
|
|
* the caller doesn't want any state-changing effects, we drop out.
|
|
*/
|
|
if (!client.enableColors ||
|
|
(("noMircColors" in data) && data.noMircColors) ||
|
|
(("noStateChange" in data) && data.noStateChange))
|
|
{
|
|
return;
|
|
}
|
|
|
|
var ary = colorInfo.match (/.(\d{1,2}|)(,(\d{1,2})|)/);
|
|
|
|
// Do we have a BG color specified...?
|
|
if (!arrayHasElementAt(ary, 1) || !ary[1])
|
|
{
|
|
// Oops, no colors.
|
|
delete data.currFgColor;
|
|
delete data.currBgColor;
|
|
return;
|
|
}
|
|
|
|
var fgColor = String(Number(ary[1]) % 16);
|
|
|
|
if (fgColor.length == 1)
|
|
data.currFgColor = "0" + fgColor;
|
|
else
|
|
data.currFgColor = fgColor;
|
|
|
|
// Do we have a BG color specified...?
|
|
if (arrayHasElementAt(ary, 3) && ary[3])
|
|
{
|
|
var bgColor = String(Number(ary[3]) % 16);
|
|
|
|
if (bgColor.length == 1)
|
|
data.currBgColor = "0" + bgColor;
|
|
else
|
|
data.currBgColor = bgColor;
|
|
}
|
|
|
|
data.hasColorInfo = true;
|
|
}
|
|
|
|
function mircToggleBold (colorInfo, containerTag, data)
|
|
{
|
|
if (!client.enableColors ||
|
|
(("noMircColors" in data) && data.noMircColors) ||
|
|
(("noStateChange" in data) && data.noStateChange))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ("isBold" in data)
|
|
delete data.isBold;
|
|
else
|
|
data.isBold = true;
|
|
data.hasColorInfo = true;
|
|
}
|
|
|
|
function mircToggleUnder (colorInfo, containerTag, data)
|
|
{
|
|
if (!client.enableColors ||
|
|
(("noMircColors" in data) && data.noMircColors) ||
|
|
(("noStateChange" in data) && data.noStateChange))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ("isUnderline" in data)
|
|
delete data.isUnderline;
|
|
else
|
|
data.isUnderline = true;
|
|
data.hasColorInfo = true;
|
|
}
|
|
|
|
function mircResetColor (text, containerTag, data)
|
|
{
|
|
if (!client.enableColors ||
|
|
(("noMircColors" in data) && data.noMircColors) ||
|
|
(("noStateChange" in data) && data.noStateChange) ||
|
|
!("hasColorInfo" in data))
|
|
{
|
|
return;
|
|
}
|
|
|
|
delete data.currFgColor;
|
|
delete data.currBgColor;
|
|
delete data.isBold;
|
|
delete data.isUnderline;
|
|
delete data.hasColorInfo;
|
|
}
|
|
|
|
function mircReverseColor (text, containerTag, data)
|
|
{
|
|
if (!client.enableColors ||
|
|
(("noMircColors" in data) && data.noMircColors) ||
|
|
(("noStateChange" in data) && data.noStateChange))
|
|
{
|
|
return;
|
|
}
|
|
|
|
var tempColor = ("currFgColor" in data ? data.currFgColor : "");
|
|
|
|
if ("currBgColor" in data)
|
|
data.currFgColor = data.currBgColor;
|
|
else
|
|
delete data.currFgColor;
|
|
if (tempColor)
|
|
data.currBgColor = tempColor;
|
|
else
|
|
delete data.currBgColor;
|
|
data.hasColorInfo = true;
|
|
}
|
|
|
|
function showCtrlChar(c, containerTag)
|
|
{
|
|
var span = document.createElementNS(XHTML_NS, "html:span");
|
|
span.setAttribute("class", "chatzilla-control-char");
|
|
if (c == "\t")
|
|
{
|
|
containerTag.appendChild(document.createTextNode(c));
|
|
return;
|
|
}
|
|
|
|
var ctrlStr = c.charCodeAt(0).toString(16);
|
|
if (ctrlStr.length < 2)
|
|
ctrlStr = "0" + ctrlStr;
|
|
span.appendChild(document.createTextNode("0x" + ctrlStr));
|
|
containerTag.appendChild(span);
|
|
containerTag.appendChild(document.createElementNS(XHTML_NS, "html:wbr"));
|
|
}
|
|
|
|
function insertText(text, containerTag, data)
|
|
{
|
|
var newClass = "";
|
|
if (data && ("hasColorInfo" in data))
|
|
newClass = calcClass(data);
|
|
if (!newClass)
|
|
delete data.hasColorInfo;
|
|
|
|
if (newClass)
|
|
{
|
|
var spanTag = document.createElementNS(XHTML_NS, "html:span");
|
|
spanTag.setAttribute("class", newClass);
|
|
containerTag.appendChild(spanTag);
|
|
containerTag = spanTag;
|
|
}
|
|
|
|
var arg;
|
|
while ((arg = text.match(client.whitespaceRE)))
|
|
{
|
|
// Find the start of the match so we can insert the preceding text.
|
|
var start = text.indexOf(arg[0]);
|
|
if (start > 0)
|
|
containerTag.appendChild(document.createTextNode(text.substr(0, start)));
|
|
|
|
// Process the long word itself.
|
|
insertHyphenatedWord(arg[1], containerTag, { dontStyleText: true });
|
|
|
|
// Continue with the rest of the text.
|
|
text = text.substr(start + arg[0].length);
|
|
}
|
|
|
|
// Insert any left-over text on the end.
|
|
if (text)
|
|
containerTag.appendChild(document.createTextNode(text));
|
|
}
|
|
|
|
function insertHyphenatedWord(longWord, containerTag, data)
|
|
{
|
|
var wordParts = splitLongWord(longWord, client.MAX_WORD_DISPLAY);
|
|
|
|
if (!data || !("dontStyleText" in data))
|
|
{
|
|
var newClass = "";
|
|
if (data && ("hasColorInfo" in data))
|
|
newClass = calcClass(data);
|
|
if (!newClass)
|
|
delete data.hasColorInfo;
|
|
|
|
if (newClass)
|
|
{
|
|
var spanTag = document.createElementNS(XHTML_NS, "html:span");
|
|
spanTag.setAttribute("class", newClass);
|
|
containerTag.appendChild(spanTag);
|
|
containerTag = spanTag;
|
|
}
|
|
}
|
|
|
|
var wbr = document.createElementNS(XHTML_NS, "html:wbr");
|
|
for (var i = 0; i < wordParts.length; ++i)
|
|
{
|
|
containerTag.appendChild(document.createTextNode(wordParts[i]));
|
|
containerTag.appendChild(wbr.cloneNode(true));
|
|
}
|
|
}
|
|
|
|
function insertInlineButton(text, containerTag, data)
|
|
{
|
|
var ary = text.match(/\[\[([^\]]+)\]\[([^\]]+)\]\[([^\]]+)\]\]/);
|
|
|
|
if (!ary)
|
|
{
|
|
containerTag.appendChild(document.createTextNode(text));
|
|
return;
|
|
}
|
|
|
|
var label = ary[1];
|
|
var title = ary[2];
|
|
var command = ary[3];
|
|
|
|
var link = document.createElementNS(XHTML_NS, "html:a");
|
|
link.setAttribute("href", "x-cz-command:" + encodeURI(command));
|
|
link.setAttribute("title", title);
|
|
link.setAttribute("class", "chatzilla-link");
|
|
link.appendChild(document.createTextNode(label));
|
|
|
|
containerTag.appendChild(document.createTextNode("["));
|
|
containerTag.appendChild(link);
|
|
containerTag.appendChild(document.createTextNode("]"));
|
|
}
|
|
|
|
function calcClass(data)
|
|
{
|
|
var className = "";
|
|
if ("hasColorInfo" in data)
|
|
{
|
|
if ("currFgColor" in data)
|
|
className += " chatzilla-fg" + data.currFgColor;
|
|
if ("currBgColor" in data)
|
|
className += " chatzilla-bg" + data.currBgColor;
|
|
if ("isBold" in data)
|
|
className += " chatzilla-bold";
|
|
if ("isUnderline" in data)
|
|
className += " chatzilla-underline";
|
|
}
|
|
return className;
|
|
}
|
|
|