Files
IPB/Development/javascript_uncompressed/jscripts/ips_text_editor_lite.js
T
2025-12-19 00:26:08 -08:00

819 lines
18 KiB
JavaScript

//------------------------------------------
// Invision Power Board v2
// Text Editor Lite
// (c) 2006 Invision Power Services, Inc.
//
// http://www.invisionboard.com
//------------------------------------------
var IPS_Lite_Editor = new Array();
/**
* Text editor lite!
*
* @param string Editor ID
*/
function ips_text_editor_lite( editor_id )
{
this.editor_id = editor_id;
this.control_obj = document.getElementById( editor_id + '-controls' );
this.initialized = false;
this.buttons = new Array();
this.fonts = new Array();
this.state = new Array();
this.text_obj = document.getElementById( this.editor_id + '_textarea' );
this.open_brace = '[';
this.close_brace = ']';
this.editor_document = this.text_obj;
this.editor_window = this.editor_document;
this._ie_cache = null;
this.is_ie = is_ie;
this.is_moz = is_moz;
this.is_opera = is_opera;
this.has_focus = false;
this.emoticon_window_id = null;
//-----------------------------------------
// Do some set up
//-----------------------------------------
this.init = function()
{
//-----------------------------------------
// INIT
//-----------------------------------------
var controls = new Array();
if ( ! this.control_obj )
{
return;
}
//-----------------------------------------
// Grab all buttons
// 2 step 'cos moz goes into infinite loop otherwise
//-----------------------------------------
var items = this.control_obj.getElementsByTagName("DIV");
for ( var i = 0 ; i < items.length ; i++ )
{
if ( ( items[i].className == 'rte-normal' || items[i].className == 'rte-menu-button' || items[i].className == 'rte-normal-menubutton' ) && items[i].id )
{
controls[ controls.length ] = items[i].id;
}
}
for ( var i = 0 ; i < controls.length ; i++ )
{
var control = document.getElementById( controls[i] );
if ( control.className == 'rte-normal' )
{
this.init_editor_button( control );
}
else if ( control.className == 'rte-menu-button' || control.className == 'rte-normal-menubutton' )
{
this.init_editor_popup_button( control );
}
}
//ipsclass.set_unselectable( this.control_obj );
//-----------------------------------------
// Set up focus
//-----------------------------------------
this.text_obj.onfocus = ips_editor_events.prototype.editor_window_onfocus;
this.text_obj.onblur = ips_editor_events.prototype.editor_window_onblur;
if ( this.editor_document.addEventListener )
{
this.editor_document.addEventListener('keypress', ips_editor_events.prototype.editor_document_onkeypress, false);
}
};
/**
* Refocus editor check
*/
this.editor_check_focus = function()
{
if ( ! this.text_obj.has_focus )
{
if ( this.is_opera )
{
this.text_obj.focus();
}
try
{
this.text_obj.focus();
}
catch(err)
{
return false;
}
}
return true;
};
/**
* INIT Editor Button
* Initialize an editor button (bold, italic, etc)
*
* @param object Button DIV object
*/
this.init_editor_button = function( obj )
{
obj.cmd = obj.id.replace( new RegExp( '^' + this.editor_id + '_cmd_(.+?)$' ), '$1' );
obj.editor_id = this.editor_id;
//-----------------------------------------
// Add to buttons array
//-----------------------------------------
this.buttons[ obj.cmd ] = obj;
//-----------------------------------------
// Set up defaults
//-----------------------------------------
obj.state = false;
obj.mode = 'normal';
obj.real_type = 'button';
obj.onclick = ips_editor_events.prototype.button_onmouse_event;
obj.onmousedown = ips_editor_events.prototype.button_onmouse_event;
obj.onmouseover = ips_editor_events.prototype.button_onmouse_event;
obj.onmouseout = ips_editor_events.prototype.button_onmouse_event;
};
/**
* Toggle button context
* Toggles the menu's class for mouseover, select, etc
*
* @param object menu object
* @param object state
* @param object type
*/
this.set_button_context = function(obj, state, type)
{
if (typeof type == 'undefined')
{
type = 'button';
}
switch (obj.state)
{
case true:
{
switch (state)
{
case 'mouseout':
{
this.editor_set_ctl_style(obj, 'button', 'selected');
break;
}
case 'mouseover':
case 'mousedown':
case 'mouseup':
{
this.editor_set_ctl_style(obj, type, 'down');
break;
}
}
break;
}
default:
{
switch (state)
{
case 'mouseout':
{
this.editor_set_ctl_style(obj, type, 'normal');
break;
}
case 'mousedown':
{
this.editor_set_ctl_style(obj, type, 'down');
break;
}
case 'mouseover':
case 'mouseup':
{
this.editor_set_ctl_style(obj, type, 'hover');
break;
}
}
break;
}
}
};
/**
* Sets the editor button control style
*
* @var object Button Object
* @var string Control Type
* @var string Control Mode
*/
this.editor_set_ctl_style = function( obj, type, mode )
{
if ( obj.mode != mode )
{
//-----------------------------------------
// Add in -menu class
//-----------------------------------------
var extra = '';
if ( type == 'menu' )
{
extra = '-menu';
}
else if ( type == 'menubutton' )
{
extra = '-menubutton';
}
//-----------------------------------------
// Add in -color if it's a color box
//-----------------------------------------
extra += obj.colorname ? '-color' : '';
//-----------------------------------------
// Add in -emo if it's an emo
//-----------------------------------------
extra += obj.emo_id ? '-emo' : '';
//-----------------------------------------
// Set mote...
//-----------------------------------------
obj.mode = mode;
try
{
switch (mode)
{
case "normal":
{
// Normal
obj.className = 'rte-normal' + extra;
}
break;
case "hover":
{
// Hover
obj.className = 'rte-hover' + extra;
}
break;
case "selected":
case "down":
{
// On
obj.className = 'rte-selected' + extra;
}
break;
}
}
catch (e)
{
}
}
};
/**
* Format Text
*
* @var event Event Object
* @var string Formatted command
* @var string Formatting command extra
*/
this.format_text = function(e, command, arg)
{
e = ipsclass.cancel_bubble( e, true );
//-----------------------------------------
// Special considerations...
//-----------------------------------------
if ( command.match( /resize_/ ) )
{
this.resize_editorbox( command.replace( /.+?resize_(up|down)/, "$1" ) );
}
//-----------------------------------------
// Special considerations...
//-----------------------------------------
if ( command.match( /emoticon/ ) )
{
this.show_all_emoticons();
}
//-----------------------------------------
// Continue...
//-----------------------------------------
this.editor_check_focus();
if ( this[ command ] )
{
var return_val = this[ command ](e);
}
else
{
try
{
var return_val = this.apply_formatting( command, false, (typeof arg == 'undefined' ? true : arg) );
}
catch(e)
{
var return_val = false;
}
}
//-----------------------------------------
// Check focus
//-----------------------------------------
this.editor_check_focus();
return return_val;
};
/**
* STD:
* Create link override
*/
this.createlink = function()
{
var _url = prompt( ipb_global_lang['editor_enter_url'], 'http://' );
if ( ! _url || _url == null || _url == 'http://' )
{
return false;
}
var _text = this.get_selection();
_text = _text ? _text : prompt( ipb_global_lang['editor_enter_title'] );
if( !_text || _text == null )
{
return false;
}
this.wrap_tags( 'url', _url, _text);
};
/**
* STD:
* Insert image override
*/
this.insertimage = function()
{
var _text = this.get_selection();
var _url = prompt( ipb_global_lang['editor_enter_image'], _text ? _text : "http://" );
if( !_url || _url == null || _url == 'http://' )
{
return false;
}
this.wrap_tags( 'img', false, _url );
};
/**
* STD:
* IPB Quote override
*/
this.ipb_quote = function()
{
var _text = this.get_selection();
this.wrap_tags( 'quote', false, _text );
};
/**
* STD:
* IPB code override
*/
this.ipb_code = function()
{
var _text = this.get_selection();
this.wrap_tags( 'code', false, _text );
};
/**
* STD:
* Apply formatting
*/
this.apply_formatting = function(cmd, dialog, argument)
{
// undo & redo array pops
switch (cmd)
{
case 'bold':
case 'italic':
case 'underline':
{
this.wrap_tags(cmd.substr(0, 1), false);
return;
}
case 'justifyleft':
case 'justifycenter':
case 'justifyright':
{
this.wrap_tags(cmd.substr(7), false);
return;
}
case 'indent':
{
this.wrap_tags(cmd, false);
return;
}
case 'createlink':
{
var sel = this.get_selection();
if (sel)
{
this.wrap_tags('url', argument);
}
else
{
this.wrap_tags('url', argument, argument);
}
return;
}
case 'fontname':
{
this.wrap_tags('font', argument);
return;
}
case 'fontsize':
{
this.wrap_tags('size', argument);
return;
}
case 'forecolor':
{
this.wrap_tags('color', argument);
return;
}
case 'backcolor':
{
this.wrap_tags('background', argument);
return;
}
case 'insertimage':
{
this.wrap_tags('img', false, argument);
return;
}
case 'strikethrough':
{
this.wrap_tags('strike', false);
return;
}
case 'superscript':
{
this.wrap_tags('sup', false);
return;
}
case 'subscript':
{
this.wrap_tags('sub', false);
return;
}
case 'removeformat':
return;
}
};
/**
* Wrap Tags
*
* @param string Tag to wrap
* @param boolean Has optional params
* @param string Selected Text
*/
this.wrap_tags = function(tag_name, has_option, selected_text)
{
//-----------------------------------------
// Fix up for HTML use
//-----------------------------------------
var tag_close = tag_name;
//-----------------------------------------
// Got selected text?
//-----------------------------------------
if ( typeof selected_text == 'undefined' )
{
selected_text = this.get_selection();
selected_text = (selected_text === false) ? '' : new String(selected_text);
}
//-----------------------------------------
// Using option?
//-----------------------------------------
if ( has_option === true )
{
var option = prompt( ips_language_array['js_rte_optionals'] ? ips_language_array['js_rte_optionals'] : "Enter the optional arguments for this tag", '');
if ( option )
{
var opentag = this.open_brace + tag_name + '="' + option + '"' + this.close_brace;
}
else
{
return false;
}
}
else if ( has_option !== false )
{
var opentag = this.open_brace + tag_name + '="' + has_option + '"' + this.close_brace;
}
else
{
var opentag = this.open_brace + tag_name + this.close_brace;
}
var closetag = this.open_brace + '/' + tag_close + this.close_brace;
var text = opentag + selected_text + closetag;
this.insert_text( text );
return false;
};
/**
* Wrap tag: Lite
* Quick method of below
*
* @param string Start text
* @param string Close text
*/
this.wrap_tags_lite = function( start_text, close_text )
{
//-----------------------------------------
// Got selected text?
//-----------------------------------------
selected_text = this.get_selection();
selected_text = (selected_text === false) ? '' : new String(selected_text);
this.insert_text( start_text + selected_text + close_text );
return false;
};
/**
* STD:
* Get Editor Contents
*/
this.editor_get_contents = function()
{
return this.editor_document.value;
};
/**
* STD:
* Get Selected Text
*/
this.get_selection = function()
{
if ( typeof(this.editor_document.selectionStart) != 'undefined' )
{
return this.editor_document.value.substr(this.editor_document.selectionStart, this.editor_document.selectionEnd - this.editor_document.selectionStart);
}
else if ( ( document.selection && document.selection.createRange ) || this._ie_cache )
{
return this._ie_cache ? this._ie_cache.text : document.selection.createRange().text;
}
else if ( window.getSelection )
{
return window.getSelection() + '';
}
else
{
return false;
}
};
/**
* STD:
* Insert HTML
*/
this.insert_text = function(text)
{
if( this.editor_check_focus() == false )
{
return false;
}
if (typeof(this.editor_document.selectionStart) != 'undefined')
{
var open = this.editor_document.selectionStart + 0;
var st = this.editor_document.scrollTop;
this.editor_document.value = this.editor_document.value.substr(0, this.editor_document.selectionStart) + text + this.editor_document.value.substr(this.editor_document.selectionEnd);
// Don't adjust selection if we're simply adding <b></b>, etc
if ( ! text.match( new RegExp( "\\" + this.open_brace + "(\\S+?)" + "\\" + this.close_brace + "\\" + this.open_brace + "/(\\S+?)" + "\\" + this.close_brace ) ) )
{
this.editor_document.selectionStart = open;
this.editor_document.selectionEnd = open + text.length;
this.editor_document.scrollTop = st;
}
}
else if ( ( document.selection && document.selection.createRange ) || this._ie_cache )
{
var sel = this._ie_cache ? this._ie_cache : document.selection.createRange();
sel.text = text.replace(/\r?\n/g, '\r\n');
sel.select();
}
else
{
this.editor_document.value += text;
}
this._ie_cache = null;
};
/**
* Show all emoticons
*
* @param string Editor ID
*/
this.show_all_emoticons = function()
{
if ( typeof( this.emoticon_window_id ) != null )
{
this.emoticon_window_id = window.open( ipb_var_base_url + "act=legends&CODE=emoticons&_lite=1&editor_id=" + editor_id,"Legends","width=250,height=500,resizable=yes,scrollbars=yes");
}
else
{
this.emoticon_window_id.focus();
}
return false;
};
/**
* STD:
* Insert an emoticon
*/
this.insert_emoticon = function( emo_id, emo_image, emo_code, event )
{
emo_code = ipsclass.un_htmlspecialchars( emo_code );
this.wrap_tags_lite( " " + emo_code, " ");
if ( this.is_ie )
{
if ( IPS_Lite_Editor[ this.editor_id ].emoticon_window_id != '' && typeof( IPS_Lite_Editor[ this.editor_id ].emoticon_window_id ) != 'undefined' )
{
IPS_Lite_Editor[ this.editor_id ].emoticon_window_id.focus();
}
}
};
/**
* Resize editor
*
* @param string Up (smaller) Down (Larger)
*/
this.resize_editorbox = function( direction )
{
var inc_value = 100;
var current_height = parseInt( this.text_obj.style.height );
var new_height = 0;
current_height = current_height ? current_height : 200;
//-----------------------------------------
// If we're not going smaller than 300...
//-----------------------------------------
if ( current_height >= 50 )
{
if ( direction == 'up' )
{
new_height = current_height - inc_value;
}
else
{
new_height = current_height + inc_value;
}
if ( new_height > 149 )
{
this.text_obj.style.height = new_height + 'px';
}
}
};
};
// =============================================================================
// Text editor event functions
// =============================================================================
/**
* Class initialization
*/
function ips_editor_events()
{
}
/**
* Handles mouse events for buttons
*
* @param event Event Object
*/
ips_editor_events.prototype.button_onmouse_event = function(e)
{
if ( is_ie )
{
e = ipsclass.cancel_bubble(e, true);
}
if ( e.type == 'click' )
{
IPS_Lite_Editor[this.editor_id].format_text(e, this.cmd, false, true);
}
IPS_Lite_Editor[this.editor_id].set_button_context(this, e.type);
};
/**
* Sets the focus for the editor window
*
* @param event Event Object
*/
ips_editor_events.prototype.editor_window_onfocus = function(e)
{
this.has_focus = true;
};
/**
* Sets unfocus for the editor window
*
* @param event Event Object
*/
ips_editor_events.prototype.editor_window_onblur = function(e)
{
this.has_focus = false;
};
/**
* Handles editor document key-press event
*
* @param event Event Object
*/
ips_editor_events.prototype.editor_document_onkeypress = function(e)
{
if ( e.ctrlKey )
{
switch (String.fromCharCode(e.charCode).toLowerCase())
{
case 'b': cmd = 'bold'; break;
case 'i': cmd = 'italic'; break;
case 'u': cmd = 'underline'; break;
default: return;
}
e.preventDefault();
IPS_Lite_Editor[this.editor_id].apply_formatting(cmd, false, null);
return false;
}
};