// Phorum object. Other JavaScript code for Phorum can extend
// this one to implement functionality without risking name
// name space collissions.
Phorum = {};
/* Added by module "core", file "include/ajax/client.js.php" */
// Create the Phorum object if it's not available. It it created in the
// core javascript.php, but when loading this code from an external
// page, it might not be available.
if (!document.Phorum || Phorum == undefined) Phorum = {};
Phorum.Ajax = {};
// The version of this lib
Phorum.Ajax.version = '1.0.0';
// The URL that we use to access the Phorum Ajax layer.
Phorum.Ajax.URL = 'http://www.tigerboards.com/boards/ajax.php';
// Storage for Ajax call return data. This acts as a local cache
// for keeping track of already retrieved items.
Phorum.Ajax.cache = {};
/**
* Create an XMLHttpRequest object.
* Used internally by Phorum.Ajax.call().
* Raise an onFailure event in case no object can be created.
* Return either an object or null if the object creation failed.
*/
Phorum.Ajax.getXMLHttpRequest = function(req)
{
var xhr;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else if (window.ActiveXObject) {
var versions = [
'MSXML2.XMLHttp.5.0',
'MSXML2.XMLHttp.4.0',
'MSXML2.XMLHttp.3.0',
'MSXML2.XMLHttp',
'Microsoft.XMLHttp'
];
for (var i=0; i < versions.length; i++) {
try { xhr = new ActiveXObject(versions[i]); } catch (e) { }
}
}
if (xhr) {
return xhr;
}
if (req.onFailure) req.onFailure(
'Phorum: Unable to create an XMLHttpRequest object',
-1, null
);
return null;
};
/**
* Execute an Ajax Phorum call.
*/
Phorum.Ajax.call = function(req)
{
// If the store property is set for the request, then check
// if the data for the request is already available in the
// local cache. If yes, then return the data immediately.
if (req.store) {
if (req.store != null && Phorum.Ajax.cache[req.store]) {
if (req.onSuccess) {
// true = data retrieved from cache.
req.onSuccess(Phorum.Ajax.cache[req.store], true);
}
return;
}
}
// Check the request data.
if (! req['call']) {
if (req.onFailure) req.onFailure(
'Phorum.Ajax.call() error: missing property ' +
'"call" for the request object.',
-1, null
);
return;
}
// Check if there is an XMLHttpRequest object available.
var xhr = Phorum.Ajax.getXMLHttpRequest(req);
if (! xhr) return;
// Convert the request object to JSON.
var json = Phorum.JSON.encode(req);
// Notify the start of the request loading stage.
if (req.onRequest) req.onRequest(json);
xhr.open("post", Phorum.Ajax.URL, true);
xhr.setRequestHeader("Content-Type", "text/x-json");
xhr.onreadystatechange = function()
{
if (req.onReadStateChange) req.onReadyStateChange(req);
switch (xhr.readyState)
{
case 1:
if (req.onLoading) req.onLoading(xhr);
break;
case 2:
if (req.onLoaded) req.onLoaded(xhr);
break;
case 3:
if (req.onInteractive) req.onInteractive(xhr);
break;
case 4:
if (req.onComplete)req.onComplete(xhr);
if (req.onResponse) req.onResponse(xhr.responseText);
if (xhr.status == 200) {
// Evaluate the returned JSON code. If evaluation fails,
// then run the onFailure event for the Phorum.Ajax.call.
try {
var res = Phorum.JSON.decode(xhr.responseText);
} catch (e) {
if (req.onFailure) req.onFailure(
'Ajax Phorum API call succeeded, but the return ' +
'data could not be parsed as JSON data.',
xhr.status, xhr.responseText
);
return;
}
// If the req.store property is set, then we store
// the result data in the Phorum cache.
if (req.store) Phorum.Ajax.cache[req.store] = res;
// false = data not retrieved from store.
if (req.onSuccess) req.onSuccess(res, false);
} else {
if (req.onFailure) req.onFailure(xhr.responseText);
}
break;
}
};
xhr.send(json);
};
// Invalidate a single cache item of the full cache.
Phorum.Ajax.invalidateCache = function(key)
{
if (key) {
Phorum.Ajax.cache[key] = null;
} else {
Phorum.Ajax.cache = new Array();
}
};
// Parse out javascript blocks from the data to eval them. Adding them
// to the page using innerHTML does not invoke parsing by the browser.
Phorum.Ajax.evalJavaScript = function(data)
{
var cursor = 0;
var start = 1;
var end = 1;
while (cursor < data.length && start > 0 && end > 0) {
start = data.indexOf('<script', cursor);
end = data.indexOf('</script', cursor);
if (end >start && end > -1) {
if (start > -1) {
var res = data.substring(start, end);
start = res.indexOf('>') + 1;
res = res.substring(start);
if (res.length != 0) {
eval(res);
}
}
cursor = end + 1;
}
}
};
// ======================================================================
// JSON encoder and decoder
// Based on byteson by Andrea Giammarchi
// (http://www.devpro.it/byteson/)
// ======================================================================
Phorum.JSON = {};
Phorum.JSON.common =
{
// characters object, useful to convert some char in a JSON compatible way
c:{'\b':'b','\t':'t','\n':'n','\f':'f','\r':'r','"':'"','\\':'\\','/':'/'},
// decimal function, returns a string with length === 2 for date convertion
d:function(n){return n < 10 ? '0'.concat(n) : n},
// integer function, returns integer value from a piece of string
i:function(e, p, l){return parseInt(e.substr(p, l))},
// slash function, add a slash before a common.c char
s:function(i,d){return '\\'.concat(Phorum.JSON.common.c[d])},
// unicode function, return respective unicode string
u:function(i,d){var n = d.charCodeAt(0).toString(16);return '\\u'.concat(n.length < 2 ? '000' : '00', n)}
};
Phorum.JSON.convert = function(params, result)
{
switch(params.constructor) {
case Number:
result = isFinite(params) ? String(params) : 'null';
break;
case Boolean:
result = String(params);
break;
case Date:
result = concat(
'"',
params.getFullYear(), '-',
Phorum.JSON.common.d(params.getMonth() + 1), '-',
Phorum.JSON.common.d(params.getDate()), 'T',
Phorum.JSON.common.d(params.getHours()), ':',
Phorum.JSON.common.d(params.getMinutes()), ':',
Phorum.JSON.common.d(params.getSeconds()),
'"'
);
break;
case String:
if(/^[0-9]{4}\-[0-9]{2}\-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}$/.test(params)){
result = new Date;
result.setHours(Phorum.JSON.common.i(params, 11, 2));
result.setMinutes(Phorum.JSON.common.i(params, 14, 2));
result.setSeconds(Phorum.JSON.common.i(params, 17, 2));
result.setMonth(Phorum.JSON.common.i(params, 5, 2) - 1);
result.setDate(Phorum.JSON.common.i(params, 9, 2));
result.setFullYear(Phorum.JSON.common.i(params, 0, 4));
};
break;
default:
var n, tmp = [];
if(result) {
for(n in params) result[n] = params[n];
} else {
for(n in params) {
if(params.hasOwnProperty(n) && !!(result = Phorum.JSON.encode(params[n])))
tmp.push(Phorum.JSON.encode(n).concat(':', result));
};
result = '{'.concat(tmp.join(','), '}');
};
break;
};
return result;
};
Phorum.JSON.encode = function(params)
{
var result = '';
if(params === null)
{
result = 'null';
}
else if(!{'function':1,'undefined':1,'unknown':1}[typeof(params)])
{
switch(params.constructor)
{
case Array:
for(var i = 0, j = params.length, tmp = []; i < j; i++) {
if(!!(result = Phorum.JSON.encode(params[i])))
tmp.push(result);
};
result = '['.concat(tmp.join(','), ']');
break;
case String:
result = '"'.concat(params.replace(
/(\x5c|\x2F|\x22|[\x0c-\x0d]|[\x08-\x0a])/g, Phorum.JSON.common.s
).replace(
/([\x00-\x07]|\x0b|[\x0e-\x1f])/g, Phorum.JSON.common.u
), '"');
break;
default:
result = Phorum.JSON.convert(params);
break;
};
};
return result;
};
Phorum.JSON.decode = function(json)
{
eval('var res = '+json);
if (res === undefined) {
throw new SyntaxError('The Phorum JSON data cannot be parsed');
}
return res;
};
/* Added by module "editor_tools", file "mods/editor_tools/editor_tools.js" */
///////////////////////////////////////////////////////////////////////////////
// //
// Copyright (C) 2008 Phorum Development Team //
// http://www.phorum.org //
// //
// This program is free software. You can redistribute it and/or modify //
// it under the terms of either the current Phorum License (viewable at //
// phorum.org) or the Phorum License that was distributed with this file //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY, without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. //
// //
// You should have received a copy of the Phorum License //
// along with this program. //
// //
///////////////////////////////////////////////////////////////////////////////
// Javascript code for the Phorum editor_tools module.
// Valid object ids for textarea objects to handle. The first object
// that can be matched will be use as the object to work with.
// This is done to arrange for backward compatibility between
// Phorum versions.
var editor_tools_textarea_ids = new Array(
'phorum_textarea', // Phorum 5.1
'body', // Phorum 5.2
'message' // PM interface
);
// Valid object ids for subject text field objects to handle.
var editor_tools_subject_ids = new Array(
'phorum_subject', // Phorum 5.1
'subject' // Phorum 5.2
);
// Storage for language translation strings from the Phorum language system.
var editor_tools_lang = new Array();
// Some variables for storing objects that we need globally.
var editor_tools_textarea_obj = null;
var editor_tools_subject_obj = null;
var editor_tools_help_picker_obj = null;
// A variable for storing the current selection range of the 
// textarea. Needed for working around an MSIE problem.
var editor_tools_textarea_range = null;
// A variable for storing all popup objects that we have, so we
// can hide them all at once.
var editor_tools_popup_objects = new Array();
// Storage for the tools that have to be added to the editor tools panel.
// The array value contains the following fields:
//
// 1) the id for the tool (must be unique)
// 2) a description to use as the tooltip title for the button
// 3) the icon image to display as a button.
// 4) the javascript action to run when the user clicks the button
// 5) optional: the width of the icon image
// 6) optional: the height of the icon image (presumed 20px by default)
//
// This array will be filled from PHP-generated javascript.
var editor_tools = new Array();
// Storage for help chapters that must be put under the editor tools
// help button. The array value contains the following fields:
//
// 1) a description that will be used as the clickable link text.
// 2) the url for the help page (absolute or relative to the Phorum dir).
//
// This array will be filled from PHP-generated javascript.
var editor_tools_help_chapters = new Array();
// The dimensions of the help window.
var editor_tools_help_width = '400px';
var editor_tools_help_height = '400px';
// The default height for our icons.
// This one is filled from PHP-generated javascript.
var editor_tools_default_iconheight;
// A simple browser check. We need to know the browser version, because
// the color picker won't work on at least MacOS MSIE 5.
var OLD_MSIE =
navigator.userAgent.indexOf('MSIE')>=0 &&
navigator.appVersion.replace(/.*MSIE (\d\.\d).*/g,'$1')/1 < 6;
// ----------------------------------------------------------------------
// Uitilty functions
// ----------------------------------------------------------------------
// Find the Phorum textarea object and return it. In case of
// problems, null will be returned.
function editor_tools_get_textarea()
{
if (editor_tools_textarea_obj != null) {
return editor_tools_textarea_obj;
}
for (var i=0; editor_tools_textarea_ids[i]; i++) {
editor_tools_textarea_obj =
document.getElementById(editor_tools_textarea_ids[i]);
if (editor_tools_textarea_obj) break;
}
if (! editor_tools_textarea_obj) {
alert('editor_tools.js library reports: ' +
'no textarea found on the current page.');
return null;
}
return editor_tools_textarea_obj;
}
// Find the Phorum subject field object and return it. In case of
// problems, null will be returned.
function editor_tools_get_subjectfield()
{
if (editor_tools_subject_obj != null) {
return editor_tools_subject_obj;
}
for (var i=0; editor_tools_subject_ids[i]; i++) {
editor_tools_subject_obj =
document.getElementById(editor_tools_subject_ids[i]);
if (editor_tools_subject_obj) break;
}
if (! editor_tools_subject_obj) {
return null;
}
return editor_tools_subject_obj;
}
// Return a translated string, based on the Phorum language system.
function editor_tools_translate(str)
{
if (editor_tools_lang[str]) {
return editor_tools_lang[str];
} else {
return str;
}
}
// Strip whitespace from the start and end of a string.
function editor_tools_strip_whitespace(str, return_stripped)
{
var strip_pre = '';
var strip_post = '';
// Strip whitespace from end of string.
for (;;) {
var lastchar = str.substring(str.length-1, str.length);
if (lastchar == ' ' || lastchar == '\r' ||
lastchar == '\n' || lastchar == '\t') {
strip_post = lastchar + strip_post;
str = str.substring(0, str.length-1);
} else {
break;
}
}
// Strip whitespace from start of string.
for (;;) {
var firstchar = str.substring(0,1);
if (firstchar == ' ' || firstchar == '\r' ||
firstchar == '\n' || firstchar == '\t') {
strip_pre += firstchar;
str = str.substring(1);
} else {
break;
}
}
if (return_stripped) {
return new Array(str, strip_pre, strip_post);
} else {
return str;
}
} 
// Close all popup windows and move the focus to the textarea.
function editor_tools_focus_textarea()
{
var textarea_obj = editor_tools_get_textarea();
if (textarea_obj == null) return;
editor_tools_hide_all_popups();
textarea_obj.focus();
}
// Close all popup windows and move the focus to the subject field.
function editor_tools_focus_subjectfield()
{
var subjectfield_obj = editor_tools_get_subjectfield();
if (subjectfield_obj == null) return;
editor_tools_hide_all_popups();
subjectfield_obj.focus();
}
// ----------------------------------------------------------------------
// Construction of the editor tools
// ----------------------------------------------------------------------
// Add the editor tools panel to the page.
function editor_tools_construct()
{
var textarea_obj;
var div_obj;
var parent_obj;
var a_obj;
var img_obj;
// If the browser does not support document.getElementById,
// then the javascript code won't run. Do not display the
// editor tools at all in that case.
if (! document.getElementById) return;
// No editor tools selected to display? Then we're done.
if (editor_tools.length == 0) return;
// Find the textarea and subject field object.
textarea_obj = editor_tools_get_textarea();
if (textarea_obj == null) return; // we consider this fatal.
var subjectfield_obj = editor_tools_get_subjectfield();
// Insert a<div>for containing the buttons, just before the textarea,
// unless there is already an object with id "editor-tools". In that
// case, the existing object is used instead.
div_obj = document.getElementById('editor-tools');
if (! div_obj) {
parent_obj = textarea_obj.parentNode;
div_obj = document.createElement('div');
div_obj.id = 'editor-tools';
parent_obj.insertBefore(div_obj, textarea_obj);
}
// Add the buttons to the new<div>for the editor tools.
for (var i = 0; i < editor_tools.length; i++)
{
var toolinfo = editor_tools[i];
var tool = toolinfo[0];
var description = toolinfo[1];
var icon = toolinfo[2];
var jsaction = toolinfo[3];
var iwidth = toolinfo[4];
var iheight = toolinfo[5];
var target = toolinfo[6];
// Do not use the color picker on MSIE 5. I tested this on a
// Macintosh OS9 system and the color picker about hung MSIE.
if (tool == 'color' && OLD_MSIE) continue;
a_obj = document.createElement('a');
a_obj.id = 'editor-tools-a-' + tool;
a_obj.href = 'javascript:' + jsaction;
img_obj = document.createElement('img');
img_obj.id = 'editor-tools-img-' + tool;
img_obj.className = 'editor-tools-button';
img_obj.src = icon;
img_obj.width = iwidth;
img_obj.height = iheight;
img_obj.style.padding = '2px';
img_obj.alt = description;
img_obj.title = description;
// If an icon is added that is less high than our default icon
// height, we try to make the button the same height as the
// others by adding some dynamic padding to it.
if (iheight < editor_tools_default_iconheight) {
var fill = editor_tools_default_iconheight - iheight;
var addbottom = Math.round(fill / 2);
var addtop = fill - addbottom;
img_obj.style.paddingTop = (addtop + 2) + 'px';
img_obj.style.paddingBottom = (addbottom + 2) + 'px';
}
a_obj.appendChild(img_obj);
// Add the button to the page.
// target = subject is a feature that was added for supporting
// the subjectsmiley tool. This one is added to the subject field
// instead of the textarea. 
if (target == 'subject') {
// Find the subject text field. If we can't find one,
// then simply ignore this tool.
if (subjectfield_obj) {
img_obj.style.verticalAlign = 'top';
var parent = subjectfield_obj.parentNode;
var sibling = subjectfield_obj.nextSibling;
parent.insertBefore(a_obj, sibling);
}
} else {
div_obj.appendChild(a_obj);
}
}
// Hide any open popup when the user clicks the textarea or subject field.
textarea_obj.onclick = function() {
editor_tools_hide_all_popups();
};
if (subjectfield_obj) {
subjectfield_obj.onclick = function() {
editor_tools_hide_all_popups();
}
}
}
// ----------------------------------------------------------------------
// Popup window utilities
// ----------------------------------------------------------------------
// Create a popup window.
function editor_tools_construct_popup(create_id, anchor)
{
// Create the outer div for the popup window.
var popup_obj = document.createElement('div');
popup_obj.id = create_id;
popup_obj.className = 'editor-tools-popup';
popup_obj.style.display = 'none';
document.getElementById('editor-tools').appendChild(popup_obj);
popup_obj._anchor = anchor;
// Create the inner content div.
var content_obj = document.createElement('div');
content_obj.id = create_id + '-content';
popup_obj.appendChild(content_obj);
return new Array(popup_obj, content_obj);
}
// Toggle a popup window.
function editor_tools_toggle_popup(popup_obj, button_obj, width, leftoffset)
{
// Determine where to show the popup on screen.
var work_obj = button_obj;
var top = work_obj.offsetTop + work_obj.offsetHeight + 2;
var left = work_obj.offsetLeft;
while (work_obj.offsetParent != null) {
work_obj = work_obj.offsetParent;
left += work_obj.offsetLeft;
top += work_obj.offsetTop;
}
if (leftoffset) left -= leftoffset;
if (width) popup_obj.style.width = width;
// Move the popup window to the right place.
if (popup_obj._anchor == 'r')
{
// Determine the screen width.
var scrwidth = null;
if (document.documentElement.clientWidth) {
// Firefox screen width.
scrwidth = document.documentElement.clientWidth;
} else {
scrwidth = document.body.clientWidth;
// -16 for scrollbar that is counted in in some browsers.
if (document.getElementById && !document.all) {
scrwidth -= 16;
}
}
var right = scrwidth - left - button_obj.offsetWidth;
popup_obj.style.right = right + 'px';
popup_obj.style.top = top + 'px';
} else {
popup_obj.style.left = left + 'px';
popup_obj.style.top = top + 'px';
}
// Toggle the popup window's visibility.
if (popup_obj.style.display == 'none') {
editor_tools_hide_all_popups();
popup_obj.style.display = 'block';
} else {
popup_obj.style.display = 'none';
editor_tools_focus_textarea();
}
}
// Register an object as a popup, so editor_tools_hide_all_popups() 
// can hide it.
function editor_tools_register_popup_object(object)
{
if (! object) return;
editor_tools_popup_objects[editor_tools_popup_objects.length] = object;
}
// Hide all objects that were registered as a popup.
function editor_tools_hide_all_popups()
{
for (var i = 0; i < editor_tools_popup_objects.length; i++) {
var object = editor_tools_popup_objects[i];
object.style.display = 'none';
}
}
// Save the selection range of the textarea. This is needed because
// sometimes clicking in a popup can clear the selection in MSIE.
function editor_tools_store_range()
{
var ta = editor_tools_get_textarea();
if (ta == null || ta.setSelectionRange || ! document.selection) return;
ta.focus();
editor_tools_textarea_range = document.selection.createRange();
}
// Restored a saved textarea selection range.
function editor_tools_restore_range()
{
if (editor_tools_textarea_range != null)
{
editor_tools_textarea_range.select();
editor_tools_textarea_range = null;
}
}
// ----------------------------------------------------------------------
// Textarea manipulation
// ----------------------------------------------------------------------
// Add tags to the textarea. If some text is selected, then place the
// tags around the selected text. If no text is selected and a prompt_str
// is provided, then prompt the user for the data to place inside
// the tags.
function editor_tools_add_tags(pre, post, target, prompt_str)
{
var text;
var pretext;
var posttext;
var range;
var ta = target ? target : editor_tools_get_textarea();
if (ta == null) return;
// Store the current scroll offset, so we can restore it after
// adding the tags to its contents.
var offset = ta.scrollTop;
if (ta.setSelectionRange)
{
// Get the currently selected text.
pretext = ta.value.substring(0, ta.selectionStart);
text = ta.value.substring(ta.selectionStart, ta.selectionEnd);
posttext = ta.value.substring(ta.selectionEnd, ta.value.length);
// Prompt for input if no text was selected and a prompt is set.
if (text == '' && prompt_str) {
text = prompt(prompt_str, '');
if (text == null) return;
}
// Strip whitespace from text selection and move it to the
// pre- and post.
var res = editor_tools_strip_whitespace(text, true);
text = res[0];
pre = res[1] + pre;
post = post + res[2];
ta.value = pretext + pre + text + post + posttext;
// Reselect the selected text.
var cursorpos1 = pretext.length + pre.length;
var cursorpos2 = cursorpos1 + text.length;
ta.setSelectionRange(cursorpos1, cursorpos2);
ta.focus();
}
else if (document.selection) /* MSIE support */
{
// Get the currently selected text.
ta.focus();
range = document.selection.createRange();
// Fumbling to work around newline selections at the end of
// the text selection. MSIE does not include them in the
// range.text, but it does replace them when setting range.text
// to a new value :-/
var virtlen = range.text.length;
if (virtlen > 0) {
while (range.text.length == virtlen) {
range.moveEnd('character', -1);
}
range.moveEnd('character', +1);
}
// Prompt for input if no text was selected and a prompt is set.
text = range.text;
if (text == '' && prompt_str) {
text = prompt(prompt_str, '');
if (text == null) return;
}
// Strip whitespace from text selection and move it to the
// pre- and post.
var res = editor_tools_strip_whitespace(text, true);
text = res[0];
pre = res[1] + pre;
post = post + res[2];
// Add pre and post to the text.
range.text = pre + text + post;
// Reselect the selected text. Another MSIE anomaly has to be
// taken care of here. MSIE will include carriage returns
// in the text.length, but it does not take them into account
// when using selection range moving methods :-/
// By setting the range.text before, the cursor is now after
// the replaced code, so we will move the start and the end
// back in the text.
var mvstart = post.length + text.length -
((text + post).split('\r').length - 1);
var mvend = post.length +
(post.split('\r').length - 1);
range.moveStart('character', -mvstart);
range.moveEnd('character', -mvend);
range.select();
}
else /* Support for really limited browsers, e.g. MSIE5 on MacOS */
{
ta.value = ta.value + pre + post;
}
ta.scrollTop = offset;
}
// ----------------------------------------------------------------------
// Tool: Help
// ----------------------------------------------------------------------
function editor_tools_handle_help()
{
var c = editor_tools_help_chapters;
// Shouldn't happen.
if (c.length == 0) {
alert('No help chapters available');
return;
}
// Exactly one help chapter available. Immediately open the chapter.
if (c.length == 1) {
editor_tools_handle_help_select(c[0][1]);
return;
}
// Multiple chapters available. Show a help picker menu with some
// choices. Create the help picker on first access.
if (!editor_tools_help_picker_obj)
{
// Create a new popup.
var popup = editor_tools_construct_popup('editor-tools-help-picker','r');
editor_tools_help_picker_obj = popup[0];
var content_obj = popup[1];
// Populate the new popup.
for (var i = 0; i < editor_tools_help_chapters.length; i++) 
{
var helpinfo = editor_tools_help_chapters[i];
var a_obj = document.createElement('a');
a_obj.href = 'javascript:editor_tools_handle_help_select("' + helpinfo[1] + '")';
a_obj.innerHTML = helpinfo[0];
content_obj.appendChild(a_obj);
content_obj.appendChild(document.createElement('br'));
}
// Register the popup with the editor tools.
editor_tools_register_popup_object(editor_tools_help_picker_obj);
}
// Display the popup.
var button_obj = document.getElementById('editor-tools-img-help');
editor_tools_toggle_popup(editor_tools_help_picker_obj, button_obj);
}
function editor_tools_handle_help_select(url)
{
var help_window = window.open(
url,
'editor_tools_help',
'resizable=yes,' +
'menubar=no,' +
'directories=no,' +
'scrollbars=yes,' +
'toolbar=no,' +
'status=no,' +
'width=' + editor_tools_help_width + ',' +
'height=' + editor_tools_help_height
);
editor_tools_focus_textarea();
help_window.focus();
}
/* Added by module "hide_reply_editor", template "hide_reply_editor::javascript" */
// ----------------------------------------------------------------------
// Initialization code for the hide reply editor module.
// ----------------------------------------------------------------------
function hide_reply_editor_init()
{
// Find the hide reply editor wrapper.
var editor = document.getElementById('mod_hide_reply_editor');
if (!editor) return;
// Hide the editor in browsers that do support JavaScript.
// If we see #REPLY_SHOWEDITOR in the URL, then the user already clicked
// a Reply or Quote link (the page could be reloaded after such click,
// so we should not be hiding the editor).
if (!document.location.href.match(/#REPLY_SHOWEDITOR/)) {
editor.style.display = 'none';
}
// Add events to the "Reply" and "Quote" links to show the editor.
// The editor is shown after the click, in case the bare URL (without
// the #ANCHOR) of the clicked link matches the current page URL.
// If that is the case, then showing the reply editor is barely a
// matter of the browser jumping to the #REPLY_SHOWEDITOR anchor.
// Otherwise, the browser will simply jump to the new URL.
//
// Additionally, the anchor hash from the reply and quote URLs is
// updated to #REPLY_SHOWEDITOR to indicate the above code that one
// of these links was clicked and that the editor should not be hidden.
//
var anchors = document.getElementsByTagName('a');
for (var i = 0; i < anchors.length; i++) {
if (anchors[i].href) {
if (anchors[i].href.match(/#REPLY$/)) {
anchors[i].href += '_SHOWEDITOR';
anchors[i].onclick = function()
{
var pos;
var url1 = document.location.href;
if ((pos = url1.indexOf('#')) > 0) {
url1 = url1.substr(0, pos);
}
var url2 = this.href;
if ((pos = url2.indexOf('#')) > 0) {
url2 = url2.substr(0, pos);
}
if (url1 == url2) {
editor.style.display = 'block';
}
};
}
}
}
}
/* Added by module "quick_reply", file "mods/quick_reply/quick_reply.js.php" */
// ----------------------------------------------------------------------
// Functions for the Quick Reply module.
//
// The default implementation of these functions will work with the
// default Emerald template. For other templates, a different
// implementation could be required. Those templates can implement
// functions in mods/quick_reply/templates/<template>/javascript.tpl
// to override the default implementations.
// ----------------------------------------------------------------------
/**
* This function handles initializing the template specific code for the
* quick reply module. It needs to setup the "Quick Reply" buttons/links
* that have to fire the quick reply editor.
*
* By setting up the buttons/link from javascript, you can be sure that the
* user can actually use the quick reply editor. Since it drives on
* javascript, it is good to do it like this.
*
* The default implementation will add an Emerald template style
* "Quick Reply" button to the button bar that normally says
* "Reply Quote Report". Each message has this button bar in a<div>* with id="message-options". 
*/
function quick_reply_init()
{
// Find the quick reply editor.
var editor = quick_reply_get_editor();
if (!editor) return;
// Add a "quick reply" button to all the messages on screen.
var divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length; i++)
{
var div = divs[i];
var classname = div.getAttribute('class') ||
div.getAttribute('className');
if (classname && classname == 'message-options')
{
// Create the quick reply link in the message options.
// This creates the link in the same way as the Emerald template.
var a = document.createElement('a');
a.className = 'icon icon-comment-add';
a.innerHTML = 'Quick Reply';
a.onclick = function() { return quick_reply_handle(this); };
a.href = '#';
// Add the new link to the start of the message-option links.
div.insertBefore(a, div.firstChild);
}
}
} 
/**
* Based on the reply or quote button that was clicked, lookup the
* information for the message to which that button belongs.
*
* @param Object clicked
* The object that was clicked to open the quick reply editor
* (e.g. a "Quick Reply" link).
*
* @return Object
* An object, describing the message that was clicked.
* It must contain at least the properties "forum_id",
* "thread_id" and "message_id".
*/
function quick_reply_find_message_info(clicked)
{
// In emerald, the parent of the reply and quote links is a div
// with the class name "message-options".
var message_options = clicked.parentNode;
if (message_options.className != 'message-options') return null;
// Above that div, we find the "message-body" div.
var message_body = message_options.parentNode;
if (message_body.className != 'message-body') return null;
// Inside the message body, the quick auth module has hidden some
// info about the current message in an <a> tag. Try to fetch that tag.
var info_tag = null;
var atags = message_body.getElementsByTagName('a');
for (var i = 0; i < atags.length; i++) {
var classname = atags[i].getAttribute('class') ||
atags[i].getAttribute('className');
if (classname && classname == 'quick_reply_info') {
info_tag = atags[i];
break;
}
}
if (!info_tag) return null;
var info = info_tag.rel;
// Parse the info. The info is stored in the format
// "<forum id><thread id><message id>".
var split = info.split(/ +/);
if (split.length != 3) return null;
// We're done. By now we should have our id's and other info available.
return {
'forum_id' : split[0],
'thread_id' : split[1],
'message_id' : split[2]
};
}
// ----------------------------------------------------------------------
// Event handling functions
// ----------------------------------------------------------------------
/**
* Handle a click on a quick reply button/link.
*
* This function is called when the user clicks on "Quick Reply".
* It will setup the quick reply editor form with fields to make it a
* valid reply form for Phorum and it will show and position the quick
* reply editor on the screen.
*
* @return Boolean false
* So onclick="return quick_reply_handle()" can be used to prevent
* the button from submitting the form.
*/
function quick_reply_handle(clicked)
{
var info = quick_reply_find_message_info(clicked); 
if (info == null) return quick_reply_error('unable to find message info');
var editor = quick_reply_get_editor();
// Return if the editor is already open for the requested message.
if (editor.message_id && editor.message_id == info.message_id) {
return false;
}
Phorum.Ajax.call({
'call' : 'quick_reply_init_editor',
'store' : info.message_id, // Ajax cache Phorum 5.2
'cache_id' : info.message_id, // Ajax cache Phorum 5.3+
'message_id' : info.message_id,
'forum_id' : info.forum_id,
'onFailure' : function(data)
{
alert(data);
},
'onSuccess' : function(data)
{
// Hide the editor.
editor.style.display = 'none';
// Update the POST variables.
var p = document.getElementById('quick_post_vars');
if (!p) return quick_reply_error('unable to find #quick_post_vars');
p.innerHTML = data.post_vars;
// Add spam hurdles code.
var sh = document.getElementById('quick_spam_hurdles');
if (!sh) return quick_reply_error(
'unable to find #quick_spam_hurldes'
);
sh.innerHTML = data.spam_hurdles;
Phorum.Ajax.evalJavaScript(data.spam_hurdles);
// Update the subject text entry.
var s = document.getElementById('quick_subject');
if (!s) return quick_reply_error('unable to find #quick_subject');
s.value = data.subject;
// Update the form action parameter.
var f = document.getElementById('quick_form');
if (!f) return quick_reply_error('unable to find #quick_form');
f.action = data.url;
// Render the editor outside the screen so we can measure its size.
var pos = quick_reply_get_screenpos(clicked);
editor.style.top = '-100em';
editor.style.left = '-100em';
editor.style.display = 'block';
// Determine where to show the editor.
var left = pos.left + clicked.offsetWidth - editor.offsetWidth;
if (left < 10) left = 10;
var top = pos.top + clicked.offsetHeight;
var ci = quick_reply_get_clientinfo();
if ((top + editor.offsetHeight) > (ci[0] + ci[1])) {
top = ci[0] + ci[1] - editor.offsetHeight;
if (top < 0) top = 0;
}
// Shift the editor into place.
editor.style.left = left + 'px';
editor.style.top = top + 'px';
// Set the id for the active quick reply link, so we can use
// that one to style the link.
var link = document.getElementById('mod_quick_reply_active_link');
if (link) link.id = null;
clicked.id = 'mod_quick_reply_active_link';
// Focus the textarea.
var t = document.getElementById('quick_body');
if (t) t.focus();
// Keep track in the editor for which message id it was opened.
editor.message_id = info.message_id;
}
});
return false;
}
/**
* The user clicks "Cancel" in the editor.
*
* This is the function that is called by the default quick reply editor
* template when the user clicks the "Cancel" button. It will hide the
* #mod_quick_reply div and remove the id #mod_quick_reply_active_link
* from the active quick reply link.
*
* @return Boolean false
* So onclick="return quick_reply_cancel()" can be used to prevent
* the button from submitting the form.
*/
function quick_reply_cancel()
{
var editor = quick_reply_get_editor();
editor.style.display = 'none';
editor.message_id = null;
var link = document.getElementById('mod_quick_reply_active_link');
if (link) link.id = null;
return false;
}
// ----------------------------------------------------------------------
// Helper functions
// ----------------------------------------------------------------------
/**
* Returns the message editor wrapper object.
*
* This one possibly could require an override, but it is generally
* recommended to wrap the quick reply editor in a div with
* id="mod_quick_reply" and keep this function the same.
*
* @return object
* The quick reply editor wrapper.
*/
function quick_reply_get_editor()
{
return document.getElementById('mod_quick_reply');
}
/**
* A helper function that we can use in case something goes wrong.
*
* @param String msg
* The error message to show to the user.
*/
function quick_reply_error(msg)
{
alert('There was an error in the Quick Reply Module. Please inform ' +
'the module author about this error: ' + msg);
return false;
}
/**
* A helper function for finding the available client height and the
* document scroll offset.
*
* @return Array
* An array containing two elements:
* - The available client height or null if the client height
* could not be determined;
* - The current scroll offset or null if the scroll offset
* could not be determined.
*/
function quick_reply_get_clientinfo()
{
var heights = [
window.innerHeight ? window.innerHeight : null,
document.documentElement ? document.documentElement.clientHeight : null,
document.body ? document.body.clientHeight : null
];
var height = null;
for (var i = 0; i < heights.length; i++) {
if (height == null || (heights[i] && heights[i] < height)) {
height = heights[i];
}
}
var scroll = null;
if (document.body.scrollTop) {
scroll = document.body.scrollTop;
} else if (document.documentElement.scrollTop) {
scroll = document.documentElement.scrollTop
} else if (window.pageYOffset) {
scroll = window.pageYOffset;
}
return [ height, scroll ];
}
/**
* A helper function for finding the position of an element on screen.
*
* @param Object obj
* The object to determine the location for.
*
* @return Object
* An object containing the properties "top" and "left", containing
* the absolute pixel offsets of the provided object.
*/
function quick_reply_get_screenpos(obj)
{
var top = left = 0;
do {
top += obj.offsetTop;
left += obj.offsetLeft;
obj = obj.offsetParent;
} while (obj);
return {
'top' : top,
'left' : left
};
}
/* Added by module "quick_reply", template "quick_reply::javascript" */
/* Added by module "bbcode_spoiler", file "mods/bbcode_spoiler/bbcode_spoiler.js" */
function bbcode_spoiler_editor_tool()
{
var description = prompt(
editor_tools_translate("enter spoiler description"), ''
);
if (description == null) return; // Cancel clicked.
description = editor_tools_strip_whitespace(description);
var starttag = description == ''
? "[spoiler]\n"
: "[spoiler=" + description + "]\n";
editor_tools_add_tags(starttag, "\n[\/spoiler]\n", null, editor_tools_translate("enter spoiler content"));
editor_tools_focus_textarea();
}
function bbcode_spoiler_show(spoiler_id)
{
var s = document.getElementById('bbcode_spoiler_'+spoiler_id);
if (!s) {
alert("Internal error: can't find spoiler div");
return true;
}
// An extra id which can be used in the spoiler template and which
// will be made visible or invisible, along with the spoiler content.
// It's intended use is to add some close link at the bottom of
// the spoiler content.
var c = document.getElementById('bbcode_spoiler_close_'+spoiler_id);
// Switch visibility of the spoiler content if the spoiler's content
// was already loaded. If the display style is "block" then the
// content could have been included by loading the page through a
// "view_spoiler" URL. For that case, we set "is_loaded" explicitly
// here.
if (s.is_loaded || s.style.display == 'block')
{
var a = document.getElementById('bbcode_spoiler_link_'+spoiler_id);
if (s.style.display == 'block') {
s.style.display = 'none';
if (c) c.style.display = 'none';
s.is_loaded = 1;
if (a) a.className = 'bbcode_spoiler_link';
} else {
s.style.display = 'block';
if (c) c.style.display = 'block';
if (a) a.className = 'bbcode_spoiler_link_view';
}
return false;
}
// Create the XMLHttpRequest object that we can use to send an
// Ajax request to the server.
var xhr;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else if (window.ActiveXObject) {
var versions = [
"MSXML2.XMLHttp.5.0", "MSXML2.XMLHttp.4.0",
"MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp",
"Microsoft.XMLHttp"
];
for (var i=0; i < versions.length; i++)
try { xhr = new ActiveXObject(versions[i]); } catch (e) { }
}
if (!xhr) return true;
// Setup a loading... indicator.
var a = document.getElementById('bbcode_spoiler_link_'+spoiler_id);
if (a) a.className = 'bbcode_spoiler_link_loading';
// Send the request to the server.
xhr.open("post", bbcode_spoiler_ajax_url, true);
xhr.setRequestHeader("Content-Type", "text\/plain");
xhr.onreadystatechange = function()
{
if (xhr.readyState != 4) return;
if (xhr.status == 200) {
addToElement(s, xhr.responseText);
if (a) a.className = 'bbcode_spoiler_link_view';
if (c) c.style.display = 'block';
s.style.display = 'block';
s.is_loaded = 1;
}
}
xhr.send("retrieve "+spoiler_id);
return false;
}
function addToElement(elt, response)
{
var cursor = 0;
var start = 1;
var end = 1;
// Add the response data to the page element.
elt.innerHTML = response;
// Parse out javascript blocks to eval them. Adding them to the
// page using innerHTML does not invoke parsing by the browser.
while (cursor < response.length && start > 0 && end > 0) {
start = response.indexOf('<script', cursor);
end = response.indexOf('<\/script', cursor);
if (end >start && end > -1) {
if (start > -1) {
var res = response.substring(start, end);
start = res.indexOf('>') + 1;
res = res.substring(start);
if (res.length != 0) {
eval(res);
}
}
cursor = end + 1;
}
}
}
/* Added by module "bbcode_google", file "mods/bbcode_google/bbcode_google.js" */
function bbcode_google_editor_tool() {
editor_tools_add_tags('[google]', '[/google]');
editor_tools_focus_textarea();
}
/* Added by module "embed_mp3", file "mods/embed_mp3/audio-player/audio-player.js" */
var ap_instances = new Array();

function ap_stopAll(playerID) {
for(var i = 0;i<ap_instances.length;i++) {
try {
if(ap_instances[i] != playerID) document.getElementById("audioplayer" + ap_instances[i].toString()).SetVariable("closePlayer", 1);
else document.getElementById("audioplayer" + ap_instances[i].toString()).SetVariable("closePlayer", 0);
} catch( errorObject ) {
// stop any errors
}
}
}

function ap_registerPlayers() {
var objectID;
var objectTags = document.getElementsByTagName("object");
for(var i=0;i<objectTags.length;i++) {
objectID = objectTags[i].id;
if(objectID.indexOf("audioplayer") == 0) {
ap_instances[i] = objectID.substring(11, objectID.length);
}
}
}

var ap_clearID = setInterval( ap_registerPlayers, 100 );
/* Added by module "embed_mp3", file "mods/embed_mp3/embed_mp3.js" */
function embed_mp3_editor_tool()
{
var url = 'http://';
for (;;)
{
// Read input.
url = prompt(editor_tools_translate("enter mp3 url"), url);
if (url == null) return; // Cancel clicked.
url = editor_tools_strip_whitespace(url);
// Check the URL scheme (http, https, ftp and mailto are allowed).
var copy = url.toLowerCase();
if (copy == 'http://' || (
copy.substring(0,7) != 'http://' &&
copy.substring(0,8) != 'https://' &&
copy.substring(0,6) != 'ftp://')) {
alert(editor_tools_translate("invalid mp3 url"));
continue;
}
break;
}
editor_tools_add_tags('[mp3]' + url + '[/mp3]', '');
editor_tools_focus_textarea();
}
/* Added by module "bbcode", file "mods/bbcode/bbcode_editor_tools.js" */
///////////////////////////////////////////////////////////////////////////////
// //
// Copyright (C) 2008 Phorum Development Team //
// http://www.phorum.org //
// //
// This program is free software. You can redistribute it and/or modify //
// it under the terms of either the current Phorum License (viewable at //
// phorum.org) or the Phorum License that was distributed with this file //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY, without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. //
// //
// You should have received a copy of the Phorum License //
// along with this program. //
// //
///////////////////////////////////////////////////////////////////////////////
// Javascript code for BBcode support in the Phorum editor_tools module.
// Some variables for storing objects that we need globally.
var editor_tools_size_picker_obj = null;
var editor_tools_list_picker_obj = null;
// Valid sizes to select from for the size picker. If you add or change sizes,
// remember to change the module language file to supply some display strings.
var editor_tools_size_picker_sizes = new Array(
'x-large',
'large',
'medium',
'small',
'x-small'
);
// Valid list types to select from for the list picker. If you add or change
// types, remember to change the module language file to supply some
// display strings.
var editor_tools_list_picker_types = new Array(
'b', // bullets
'1', // numbers
'a', // letters
'A', // capital letters
'i', // roman numbers
'I' // capital roman numbers
);
// Helper function: quote a bbcode argument if needed.
function quote_bbcode_argument(str)
{
// Check if quoting is required.
if (str.indexOf(' ') != -1 ||
str.indexOf('"') != -1 ||
str.indexOf(']') != -1)
{
var quoted = '';
for (var i = 0; i < str.length; i++) {
var c = str[i];
if (c == '\\' || c == '"') {
quoted += '\\';
}
quoted += c;
}
return '"' + quoted + '"';
}
else
{
return str;
}
}
// ----------------------------------------------------------------------
// Tool: [hr] or [hline] (horizontal line)
// ----------------------------------------------------------------------
function editor_tools_handle_hr() {
editor_tools_add_tags('\n[hr]\n', '');
editor_tools_focus_textarea();
}
// ----------------------------------------------------------------------
// Tool: [b]...[/b] (bold)
// ----------------------------------------------------------------------
function editor_tools_handle_b() {
editor_tools_add_tags('[b]', '[/b]');
editor_tools_focus_textarea();
}
// ----------------------------------------------------------------------
// Tool: [s]...[/s] (strike through)
// ----------------------------------------------------------------------
function editor_tools_handle_s() {
editor_tools_add_tags('[s]', '[/s]');
editor_tools_focus_textarea();
}
// ----------------------------------------------------------------------
// Tool: [u]...[/u] (underline)
// ----------------------------------------------------------------------
function editor_tools_handle_u() {
editor_tools_add_tags('[u]', '[/u]');
editor_tools_focus_textarea();
}
// ----------------------------------------------------------------------
// Tool: [i]...[/i] (italic)
// ----------------------------------------------------------------------
function editor_tools_handle_i() {
editor_tools_add_tags('[i]', '[/i]');
editor_tools_focus_textarea();
}
// ----------------------------------------------------------------------
// Tool: [center]...[/center] (center text)
// ----------------------------------------------------------------------
function editor_tools_handle_center() {
editor_tools_add_tags('[center]', '[/center]');
editor_tools_focus_textarea();
}
// ----------------------------------------------------------------------
// Tool: [sub]...[/sub] (subscript)
// ----------------------------------------------------------------------
function editor_tools_handle_sub() {
editor_tools_add_tags('[sub]', '[/sub]');
editor_tools_focus_textarea();
}
// ----------------------------------------------------------------------
// Tool: [sup]...[/sup] (superscript)
// ----------------------------------------------------------------------
function editor_tools_handle_sup() {
editor_tools_add_tags('[sup]', '[/sup]');
editor_tools_focus_textarea();
}
// ----------------------------------------------------------------------
// Tool: [small]...[/small] (small font)
// ----------------------------------------------------------------------
function editor_tools_handle_small() {
editor_tools_add_tags('[small]', '[/small]');
editor_tools_focus_textarea();
}
// ----------------------------------------------------------------------
// Tool: [large]...[/large] (large font)
// ----------------------------------------------------------------------
function editor_tools_handle_large() {
editor_tools_add_tags('[large]', '[/large]');
editor_tools_focus_textarea();
}
// ----------------------------------------------------------------------
// Tool: [code]...[/code] (formatted code)
// ----------------------------------------------------------------------
function editor_tools_handle_code() {
editor_tools_add_tags('[code]\n', '\n[/code]\n');
editor_tools_focus_textarea();
}
// ----------------------------------------------------------------------
// Tool: [email]...[/email] (email address link)
// ----------------------------------------------------------------------
function editor_tools_handle_email()
{
var email = prompt(editor_tools_translate("enter email"), '');
if (email == null) return;
email = editor_tools_strip_whitespace(email);
var subject = prompt(editor_tools_translate("enter subject"), '');
if (subject == null) return;
subject = editor_tools_strip_whitespace(subject);
if (subject != '') {
subject = ' subject=' + quote_bbcode_argument(subject);
}
if (email == '') {
editor_tools_add_tags('[email'+subject+']', '[/email]');
} else {
editor_tools_add_tags('[email'+subject+']'+email+'[/email]', '');
}
editor_tools_focus_textarea();
}
// ----------------------------------------------------------------------
// Tool: [url=...]...[/url] (URL link)
// ----------------------------------------------------------------------
function editor_tools_handle_url()
{
var url = 'http://';
for (;;)
{
// Read input.
url = prompt(editor_tools_translate("enter url"), url);
if (url == null) return; // Cancel clicked.
url = editor_tools_strip_whitespace(url);
// Check the URL scheme (http, https, ftp and mailto are allowed).
copy = url.toLowerCase();
if (copy == 'http://' || (
copy.substring(0,7) != 'http://' &&
copy.substring(0,8) != 'https://' &&
copy.substring(0,6) != 'ftp://' &&
copy.substring(0,7) != 'mailto:')) {
alert(editor_tools_translate("invalid url"));
continue;
}
break;
}
editor_tools_add_tags('[url=' + url + ']', '[/url]', null, editor_tools_translate("enter url description"));
editor_tools_focus_textarea();
}
// ----------------------------------------------------------------------
// Tool: [color=...]...[/color] (text color)
// ----------------------------------------------------------------------
function editor_tools_handle_color()
{
editor_tools_store_range();
// Display the color picker.
var img_obj = document.getElementById('editor-tools-img-color');
showColorPicker(img_obj);
return;
}
// Called by the color picker library.
function editor_tools_handle_color_select(color)
{
editor_tools_restore_range();
editor_tools_add_tags('[color=' + color + ']', '[/color]');
editor_tools_focus_textarea();
}
// ----------------------------------------------------------------------
// Tool: [size=...]...[/size] (text size)
// ----------------------------------------------------------------------
function editor_tools_handle_size()
{
editor_tools_store_range();
// Create the size picker on first access.
if (!editor_tools_size_picker_obj)
{
// Create a new popup.
var popup = editor_tools_construct_popup('editor-tools-size-picker','l');
editor_tools_size_picker_obj = popup[0];
var content_obj = popup[1];
// Populate the new popup.
for (var i = 0; i < editor_tools_size_picker_sizes.length; i++)
{
var size = editor_tools_size_picker_sizes[i];
var a_obj = document.createElement('a');
a_obj.href = 'javascript:editor_tools_handle_size_select("' + size + '")';
a_obj.style.fontSize = size;
a_obj.innerHTML = editor_tools_translate(size);
content_obj.appendChild(a_obj);
var br_obj = document.createElement('br');
content_obj.appendChild(br_obj);
}
// Register the popup with the editor tools.
editor_tools_register_popup_object(editor_tools_size_picker_obj);
}
// Display the popup.
var button_obj = document.getElementById('editor-tools-img-size');
editor_tools_toggle_popup(editor_tools_size_picker_obj, button_obj);
}
function editor_tools_handle_size_select(size)
{
editor_tools_hide_all_popups();
editor_tools_restore_range();
size = editor_tools_strip_whitespace(size);
editor_tools_add_tags('[size=' + size + ']', '[/size]');
editor_tools_focus_textarea();
}
// ----------------------------------------------------------------------
// Tool: [img]...[/img] (Image URL)
// ----------------------------------------------------------------------
function editor_tools_handle_img()
{
var url = 'http://';
for (;;)
{
// Read input.
url = prompt(editor_tools_translate("enter image url"), url);
if (url == null) return; // Cancel clicked.
url = editor_tools_strip_whitespace(url);
// Check the URL scheme (http, https, ftp and mailto are allowed).
var copy = url.toLowerCase();
if (copy == 'http://' || (
copy.substring(0,7) != 'http://' &&
copy.substring(0,8) != 'https://' &&
copy.substring(0,6) != 'ftp://')) {
alert(editor_tools_translate("invalid image url"));
continue;
}
break;
}
editor_tools_add_tags('[img]' + url + '[/img]', '');
editor_tools_focus_textarea();
}
// ----------------------------------------------------------------------
// Tool: [quote]...[/quote] (add a quote)
// ----------------------------------------------------------------------
function editor_tools_handle_quote()
{
// Read input.
var who = prompt(editor_tools_translate("enter who you quote"), '');
if (who == null) return;
who = editor_tools_strip_whitespace(who);
if (who == '') {
editor_tools_add_tags('[quote]', '[/quote]');
}
else
{
who = quote_bbcode_argument(who);
editor_tools_add_tags('[quote=' + who + "]\n", "\n[/quote]");
}
editor_tools_focus_textarea();
}
// ----------------------------------------------------------------------
// Tool: [list] [*]item1 [*]item2 [/list]
// ----------------------------------------------------------------------
function editor_tools_handle_list()
{
// Create the list picker on first access.
if (!editor_tools_list_picker_obj)
{
// Create a new popup.
var popup = editor_tools_construct_popup('editor-tools-list-picker', 'l');
editor_tools_list_picker_obj = popup[0];
var content_obj = popup[1];
// Populate the new popup.
var wrapper = document.createElement('div');
wrapper.style.marginLeft = '1em';
for (var i = 0; i < editor_tools_list_picker_types.length; i++)
{
var type = editor_tools_list_picker_types[i];
var list;
if (type == 'b') {
list = document.createElement('ul');
} else {
list = document.createElement('ol');
list.type = type;
}
list.style.padding = 0;
list.style.margin = 0;
var item = document.createElement('li');
var a_obj = document.createElement('a');
a_obj.href = 'javascript:editor_tools_handle_list_select("' + type + '")';
a_obj.innerHTML = editor_tools_translate('list type ' + type);
item.appendChild(a_obj);
list.appendChild(item);
wrapper.appendChild(list);
}
content_obj.appendChild(wrapper);
// Register the popup with the editor tools.
editor_tools_register_popup_object(editor_tools_list_picker_obj);
}
// Display the popup.
var button_obj = document.getElementById('editor-tools-img-list');
editor_tools_toggle_popup(editor_tools_list_picker_obj, button_obj);
}
function editor_tools_handle_list_select(type)
{
editor_tools_hide_all_popups();
var items = new Array();
var idx = 0;
// Read items.
for (;;)
{
var item = prompt(editor_tools_translate('enter new list item'), '');
if (item == null) return;
item = editor_tools_strip_whitespace(item);
if (item == '') break;
items[idx++] = item;
}
if (items.length == 0) {
items = new Array(
'...',
'...'
);
}
var itemlist = '';
for (var i = 0; i < items.length; i++) {
itemlist += '[*] ' + items[i] + "\n";
}
if (type == 'b') {
type = '';
} else {
type = '='+type;
}
editor_tools_add_tags("[list"+type+"]\n"+itemlist+"[/list]\n", '');
}