File "editor.js"

Full Path: /home/analogde/www/private/templates/common/editor.js
File size: 37.61 KB
MIME-type: text/plain
Charset: utf-8

/*  
 * =================================================================
 * HTML Editor - A wysiwyg web based editor for Mozilla V1.4+
 *    Website  : http://gossamer-threads.com/
 *    Revision : $Id: editor.js,v 1.20 2004/04/08 17:40:46 bao Exp $
 *
 * Copyright (c) 2004 Gossamer Threads Inc. All Rights Reserved.
 * Redistribution in part or in whole strictly prohibited. Please
 * see LICENSE file for full details.
 * =================================================================
 *
 * Description: Common functions needed to display the toolbar for an
 * HTML-editing iframe, as used in Gossamer Forum.
 */

/* -- Javascript needed to write a post -- */
var iframe, editor, inner_content, outerdoc, main_form;
var pressedInterval, initializing, initialized, editorWidth, windowResized;

var inner_content_loaded = false;

var controlRange; // selection is a ControlRange collection

window.onresize = window_resize;

var unStack = new Array();
var reStack = new Array();
var unPress = false;

var input = parent.load_param();
var baseURL     = input[0];
var extraURL    = input[1];
var imageURL    = input[2];
var mainForm    = input[3];
var contentObj  = input[4];
var formTools   = input[5];
var temp_id     = input[6];
var attachments = input[7];

var dialogWindow = new Object();

var is_ie = <%if is_ie%>true<%else%>false<%endif%>;
var doc_attr = is_ie ? 'document' : 'contentDocument';

function window_resize () {
    windowResized = true;
}

var initOuterIFrameCalled = false;

function initOuterIFrame () {
    if (initOuterIFrameCalled) return;
    else initOuterIFrameCalled = true;

    if (is_ie)
        outerdoc = parent.document.frames.editor_iframe.document;
    else
        outerdoc = parent.document.getElementById('editor_iframe').contentDocument;

    setTimeout("initInnerIFrame()", 100);
}

// Somehow, initInnerIFrame is sometimes called simultaneously; this lock
// variable locks out any subsequent calls
var initInnerIFrameLocked = false;

function initInnerIFrame () {
    if (initInnerIFrameLocked) return;
    initInnerIFrameLocked = true;

    var varsOkay = false;

    if (is_ie) iframe = outerdoc.frames.editor_iframe;
    else       iframe = outerdoc.getElementById('editor_iframe');
    if ((is_ie || inner_content_loaded) && iframe) {
        main_form = parent.document[mainForm];
        if (main_form) {
            editor = iframe[doc_attr];
            if (editor) {
                inner_content = editor.getElementById('inner_content');
                if (inner_content) {
                    if (is_ie) inner_content.contentEditable = true;
                    else editor.designMode = "on";
                    varsOkay = true;
                }
            }
        }
    }

    if (!varsOkay) {
        setTimeout("initInnerIFrame()", 100);
        initInnerIFrameLocked = false;
        return;
    }

    try {
        editor.execCommand("Undo", false, null);
    } catch (e) {
        alert("The HTML editor does not appear to be supported by your browser: " + e);
    }

    //if (!is_ie) editor.execCommand("useCSS", false, null);

    initHTML();

    setTimeout("toolbarInit()", 100);
    main_form.onsubmit = retrieveHTML;

    if (!pressedInterval) pressedInterval = setInterval("calcPressed()", 150);
}

var pressLoopInit = false;
var pressButtons = {};
var pressLoop = [];

function calcPressed () {
    if (windowResized) {
        tb_layout();
        windowResized = false;
    }
        
    if (is_ie) controlRange = (editor.selection.type == "Control") ? true : false;

    if (!pressLoopInit) {
        pressLoop[pressLoop.length] = 'Bold';
        pressButtons['Bold'] = [outerdoc.getElementById('bold'), outerdoc.getElementById('boldImage')];

        pressLoop[pressLoop.length] = 'Italic';
        pressButtons['Italic'] = [outerdoc.getElementById('italic'), outerdoc.getElementById('italicImage')];

        pressLoop[pressLoop.length] = 'Underline';
        pressButtons['Underline'] = [outerdoc.getElementById('underline'), outerdoc.getElementById('underlineImage')];

        pressLoop[pressLoop.length] = 'JustifyLeft';
        pressButtons['JustifyLeft'] = [outerdoc.getElementById('jleft'), outerdoc.getElementById('jleftImage')];

        pressLoop[pressLoop.length] = 'JustifyCenter';
        pressButtons['JustifyCenter'] = [outerdoc.getElementById('jcenter'), outerdoc.getElementById('jcenterImage')];

        pressLoop[pressLoop.length] = 'JustifyRight';
        pressButtons['JustifyRight'] = [outerdoc.getElementById('jright'), outerdoc.getElementById('jrightImage')];

        pressLoop[pressLoop.length] = 'InsertOrderedList';
        pressButtons['InsertOrderedList'] = [outerdoc.getElementById('ol'), outerdoc.getElementById('olImage')];

        pressLoop[pressLoop.length] = 'InsertUnorderedList';
        pressButtons['InsertUnorderedList'] = [outerdoc.getElementById('ul'), outerdoc.getElementById('ulImage')];

        pressLoopInit = true;
    }

    for (var i = 0; i < pressLoop.length; i++) {
        var pressed = editor.queryCommandState(pressLoop[i]);
        var span  = pressButtons[pressLoop[i]][0];
        var image = pressButtons[pressLoop[i]][1];

        if      (pressed && !span.isPressed)   press(span, image);
        else if (!pressed && span.isPressed) unpress(span, image);
        else if (span.isPressed == null) span.isPressed = false;
    }

    var buttons = {
        'link' : 'CreateLink',
        'bold' : 'Bold',
        'italic' : 'Italic',
        'underline' : 'Underline',
        'ol' : 'InsertOrderedList',
        'ul' : 'InsertUnorderedList',
        'od' : 'Outdent',
        'id' : 'Indent',
        'font' : 'FontName',
        'fcolor' : 'ForeColor',
        'horRule' : 'InsertHorizontalRule',
        'insImage' : 'InsertImage'
    };
    if (is_ie) {
        buttons['cut'] = 'Cut';
        buttons['copy'] = 'Copy';
        buttons['paste'] = 'Paste';
    }
    if (formTools) {
        buttons['form']     = 'Bold';
        buttons['text']     = 'Bold';
        buttons['textarea'] = 'Bold';
        buttons['checkbox'] = 'Bold';
        buttons['radio']    = 'Bold';
        buttons['select']   = 'Bold';
        buttons['button']   = 'Bold';
    }

    for (var i in buttons) {
        var querycommand = buttons[i];
        var button = outerdoc.getElementById(i);
        var possible = false;
        try {
            possible = editor.queryCommandEnabled(querycommand);
        } catch (e) { }

        if      ( possible &&  button.disabled)
            enable(button);
        else if (!possible && !button.disabled)
            disable(button);
    }

    if (!is_ie) return;

    var bool_table = check_env();

    if ( bool_table ) {
        if (outerdoc.all.insCell.disabled) enable (outerdoc.all.insCell);
        if (outerdoc.all.insRow.disabled)  enable (outerdoc.all.insRow);
        if (outerdoc.all.insCol.disabled)  enable (outerdoc.all.insCol);
        if (outerdoc.all.delCell.disabled) enable (outerdoc.all.delCell);
        if (outerdoc.all.delRow.disabled)  enable (outerdoc.all.delRow);
        if (outerdoc.all.delCol.disabled)  enable (outerdoc.all.delCol);
        if (outerdoc.all.split.disabled)   enable (outerdoc.all.split);
    }
    else {
        if (!outerdoc.all.insCell.disabled) disable (outerdoc.all.insCell);
        if (!outerdoc.all.insRow.disabled)  disable (outerdoc.all.insRow);
        if (!outerdoc.all.insCol.disabled)  disable (outerdoc.all.insCol);
        if (!outerdoc.all.delCell.disabled) disable (outerdoc.all.delCell);
        if (!outerdoc.all.delRow.disabled)  disable (outerdoc.all.delRow);
        if (!outerdoc.all.delCol.disabled)  disable (outerdoc.all.delCol);
        if (!outerdoc.all.split.disabled)   disable (outerdoc.all.split);
    }
    if (check_merge()) {
        if (outerdoc.all.merge.disabled) enable(outerdoc.all.merge);
    }
    else {
        disable(outerdoc.all.merge);
    }
}

function initHTML(type) {
    var initValue = main_form.pre_content.value;
    var epos = initValue.search('<BODY');
    if (epos == -1) epos = initValue.search('<body');
    var head = initValue.substr(0,epos);
    head = head.replace('<html>','');
    parent.document[mainForm].header.value = head;

    initValue = initValue.replace(head,'');
    initValue = initValue.replace('</html>','');
    if (type) {
        inner_content.innerHTML = '';
        iframe.focus();
        var selection = editor.selection.createRange();
        var html = htmlUNESCAPE(initValue);        
        selection.pasteHTML(html);
        iframe.focus();
    }
    else {
        inner_content.innerHTML = initValue;
    }
}

function htmlESCAPE(content) {
    content = content.replace(/\&/gi,'&amp;');
    content = content.replace(/\</gi,'&lt;');
    content = content.replace(/\>/gi,'&gt;');
    content = content.replace(/\"/gi,'&quot;');
    return content;
}

function htmlUNESCAPE(content) {    
    content = content.replace(/(\&lt\;)/gi,'<');
    content = content.replace(/(\&gt\;)/gi,'>');
    content = content.replace(/(\&quot\;)/gi,'"');
    content = content.replace(/(\&amp\;)/gi,'&');
    return content;
}

function press (button, image) { // Takes a span from the outer iframe and "presses" it.
    button.isPressed = true;
    button.className = "menu_item_mouseoverdown";
    image.className  = "icon_down";
} 

function unpress (button, image) { // Takes one of the spans from the editor_iframe page and unpresses the button
    button.isPressed = false;
    button.className = "tb_menu_item";
    image.className  = "tb_icon";
}

function disable (button) { // Disables a span
    button.className  = "tb_menu_item";
    button.disabled = true;
    if (is_ie)
        button.style.filter = "progid:DXImageTransform.Microsoft.Alpha(style=0, opacity=25)";
    else {
        var agent = navigator.userAgent;
        var ver = /Mozilla\/5\.0\s*\(X11; [^)]*; rv:(\d\.\d+)([ab]?)\)/.exec(agent);
        // GTK2 Mozilla/Firebird/etc. builds do not properly support the -moz-opacity style.  This
        // is mozilla bug 201209, which was fixed in the 1.6 trunk on 2003-11-01.  Therefore, if
        // on X11, we require >= 1.6b in order to enable the mozopacity style.
        if (!ver || (ver.index >= 0 && (ver[1] > 1.6 || (ver[1] == 1.6 && (!ver[2] || ver[2] >= 'b')))))
            button.style.MozOpacity = 0.25;
    }
}

function enable (button) { // Enables a span
    button.disabled = false;
    if (is_ie)
        button.style.filter = null;
    else
        button.style.MozOpacity = 1;
}

var pressLoopInit = false;
var pressButtons = {};
var pressLoop = [];

function retrieveHTML () {
    var body    = inner_content.innerHTML;   
    var head    = main_form.header.value
    if (body){
        var style = /style="BORDER-RIGHT: red 1px dotted; PADDING-RIGHT: 2px; BORDER-TOP: red 1px dotted; PADDING-LEFT: 2px; PADDING-BOTTOM: 2px; BORDER-LEFT: red 1px dotted; PADDING-TOP: 2px; BORDER-BOTTOM: red 1px dotted"/gi;
        body = body.replace(style,'');
        body = body.replace('id=inner_content contentEditable=true','');

        var html = '<html>' + head + body + '\n</html>';
        html = html.replace(/\n\s/gi,'');
        main_form.content.value = html;
    }    
}


function command (cmd) { 
    setFocus();
    editor.execCommand(cmd, false, null);
}

var colorCmd = 'ForeColor';
function colorDialog (id, cmd) {   
    setFocus();
    if (cmd != 'ForeColor' && is_ie ) {
        colorCmd = 'BackColor';
    }
    else {
        colorCmd = cmd;
    }
     
    if (!is_ie) dialogWindow.currentColor = editor.queryCommandValue(cmd);
    showDialog('editor_color', 345, 193, returnColor);
}

function fontLoad(fontSelect, styleSelect, sizeSelect, underlineCheckbox) {
    if (typeof(editor) == 'undefined') return;

    var name = editor.queryCommandValue('FontName').toLowerCase();
    var size = editor.queryCommandValue('FontSize');
    var bold = editor.queryCommandState('Bold');
    var italic = editor.queryCommandState('Italic');
    var underline = editor.queryCommandState('Underline');

    if (name != '') {
        for (i=0; i < fontSelect.length; i++) {
            if (fontSelect.options[i].text.toLowerCase() == name) {
                fontSelect.selectedIndex = i;
                break;
            }
        }
    }
    if (size) {
        for (i=0; i < sizeSelect.length; i++) {
            if (sizeSelect.options[i].value == size) {
                sizeSelect.selectedIndex = i;
                break;
            }
        }            
    }
    styleSelect.value = bold && italic ? 'bi' : bold ? 'b' : italic ? 'i' : 'r';
    underlineCheckbox.checked = underline;
}

function returnFont (font, size, color, bold, italic, underline) {
    var nowB = editor.queryCommandState('Bold');
    var nowI = editor.queryCommandState('Italic');
    var nowU = editor.queryCommandState('Underline');

    setFocus();
    if (font) editor.execCommand('FontName', false, font);
    if (size) editor.execCommand('FontSize', false, size);
    if (color) editor.execCommand('ForeColor', false, color);
    if (bold && !nowB || !bold && nowB) editor.execCommand('Bold', false, null);
    if (italic && !nowI || !italic && nowI) editor.execCommand('Italic', false, null);
    if (underline && !nowU || !underline && nowU) editor.execCommand('Underline', false, null);    
}

function returnColor (color) {
    setFocus();
    if (!color) return;
    if ( colorCmd == 'ForeColor' ) {
        editor.execCommand(colorCmd, false, color);    
        return;
    }   
    
    if (is_ie) {       
        if (controlRange) {     
             var oControlRange = editor.selection.createRange();
             for (i = 0; i < oControlRange.length; i++) {
                if (oControlRange(i).tagName.toUpperCase() == "TABLE")
                    oControlRange(i).bgColor = color;
            }
        } 
        else {
            if (getSelection()) {
                editor.execCommand(colorCmd, false, color);
            }
            else inner_content.bgColor = color;
        }
    }
    else if ( getSelection() ) {        
        editor.execCommand(colorCmd, false, color);
    }
    else inner_content.bgColor = color;
}

function returnLink (url) {
    if (url == '' || url == 'http://')
        return;

    setFocus();
    editor.execCommand('CreateLink', false, url);
}

function returnImage (object) {
    if (typeof(object) == 'undefined')
        return;

    setFocus();
    insertNodeAtSelection(object);
}

function setFocus () {
    var obj;
    if (is_ie)
        obj = inner_content;
    else
        obj = document.getElementById("editor_iframe").contentWindow;
    obj.focus();
}

function showDialog (do_equals, width, height, dialogReturn) {
/*------------------------------------------------------------
 * show dialog window
 */
    var url = baseURL + ';page=' + do_equals + '.html;' + extraURL;

    if (dialogWindow.win && !dialogWindow.win.closed && dialogWindow.url == url) {
        dialogWindow.win.focus();
    }
    else {
        if (dialogWindow.win && !dialogWindow.win.closed) dialogWindow.win.close();
        dialogWindow.returnFunc = dialogReturn;
        dialogWindow.url = url;
        dialogWindow.width = width;
        dialogWindow.height = height;
        dialogWindow.name = Math.random().toString().replace(/\./, "");

        dialogWindow.left = (screen.width - width) / 2;
        dialogWindow.top = (screen.height - height) / 2;
        dialogWindow.attribs = 'left=' + dialogWindow.left + ',' +
            'top=' + dialogWindow.top + ',' +
            'resizable=no,statusbar=no,' +
            'width=' + dialogWindow.width + ',' +
            'height=' + dialogWindow.height;

        dialogWindow.win = window.open(dialogWindow.url, dialogWindow.name, dialogWindow.attribs);
        dialogWindow.win.focus();
    }
}

function getSelection () {
    var ret;
    if (is_ie) {
        ret = editor.selection.createRange().htmlText;
    }
    else {
        var span = document.createElement("span");

        var sel = document.getElementById('editor_iframe').contentWindow.getSelection();
        span.appendChild(sel.getRangeAt(sel.rangeCount-1).cloneContents());
        ret = span.innerHTML;
    }
    return ret;
}

/* Table's feature: insert table, insert/delete/merge cell, insert row/col */

function returnTable(rows, cols, width, padding, spacing, border) {
    var table = editor.createElement("TABLE");
    var tbody = editor.createElement("tbody");
    var cols = cols || 3;
    var rows = rows || 3;
    table.width        = width   || '100%';
    table.border       = border  || 1;
    table.cellPadding  = padding || 1;
    table.cellspacing  = spacing || 1;

    //create rows and cells
    if (cols > 0 && rows >0) {
        for (var i=0; i < rows; i++) {
            var tr = editor.createElement("tr");
            for (var j=0; j < cols; j++) {
                var td = editor.createElement("td");
                td.innerHTML = '&nbsp;';
                tr.appendChild(td);
            }
            tbody.appendChild(tr);
        }
        table.appendChild(tbody);        
    }
    setFocus();
    insertNodeAtSelection(table);
}

function insert_row() {
/* ------------------------------------------------------------
 * Insert new row
 */     
    var mytable = selected_table();            
    if (mytable) {      
        var currentRow = selected_tr(mytable);        
        var cols = mytable.rows[currentRow].cells.length; 
        var oRow = mytable.insertRow(currentRow);
        for (var i=0; i<cols ;i++ ) oRow.insertCell();                
    }
}

function insert_col() {
/* ------------------------------------------------------------
 * Insert a column
 */
    var mytable = selected_table();
    if (mytable) {
        var rows = mytable.rows.length;
        for (var i=0; i<rows; i++) insert_cell(i);
    }
}

function insert_cell(nrow,ncol) {
/* ------------------------------------------------------------
 * Insert a cell
 */
    var mytable = selected_table();

    if (mytable) {        
        var currentRow = (nrow >=0) ? nrow : selected_tr(mytable);
        var currentCol = (ncol >=0) ? ncol : selected_td(mytable,currentRow);
        mytable.rows[currentRow].insertCell(currentCol);
    }
}

function delete_row() {
/* ------------------------------------------------------------
 * Delete a row
 */
    var mytable = selected_table();
    if (mytable) mytable.deleteRow(selected_tr(mytable));
}

function delete_col() {
/* ------------------------------------------------------------
 * Delete a column
 */
    var mytable = selected_table();
    if (mytable) {
        var currentRow = selected_tr(mytable);
        var currentCol = selected_td(mytable,currentRow);
        var rows = mytable.rows.length;
        for (var i=0; i<rows; i++) delete_cell(i,currentCol);
    }
}

function delete_cell(nrow,ncol) {
/* ------------------------------------------------------------
 * Delete a cell
 */
    var mytable = selected_table();
    if (mytable) {        
        var currentRow = (nrow >=0)? nrow : selected_tr(mytable);
        var currentCol = (ncol >=0)? ncol : selected_td(mytable,currentRow);
        if (currentCol < mytable.rows[currentRow].cells.length)  mytable.rows[currentRow].deleteCell(currentCol);
        if (mytable.rows[currentRow].cells.length == 0)          mytable.deleteRow(currentRow);
    }
}

function split_cell() {
/* ------------------------------------------------------------
 * Split a cell
 */
    var mytable = selected_table();
    if (!mytable) return
    var currentRow = selected_tr(mytable);
    var currentCol = selected_td(mytable,currentRow);
    var rows = mytable.rows.length;
    var cols = mytable.rows[currentRow].cells.length;
    var span = mytable.rows[currentRow].cells[currentCol].colSpan;
    for (var i=0; i<rows; i++) {
        if ( i == currentRow) {
            if (mytable.rows[i].cells[currentCol].colSpan > 1) mytable.rows[i].cells[currentCol].colSpan--;
            insert_cell(currentRow,currentCol);
        }
        else {
            var ncol;
            var nlen = mytable.rows[i].cells.length;            
            if ( span == 1) {                
                var jspan = 0;
                for (var j=0; j<nlen ; j++) {
                    jspan += mytable.rows[i].cells[j].colSpan;
                    if (jspan - 1 >= currentCol) { ncol = j; break; }
                }                           
                mytable.rows[i].cells[ncol].colSpan++;
            }
            else {
                if (currentCol > 0 ) {
                    var jmax = 0;
                    var jcol = (currentCol >= nlen - 1) ? nlen - 1 : currentCol-1;

                    for (var j=0; j<rows ; j++) {
                        var mlen = mytable.rows[j].cells.length
                        var mcol = (currentCol >= mlen-1) ? mlen - 1 : currentCol-1;
                        if (mytable.rows[j].cells[mcol].colSpan > jmax) jmax = mytable.rows[j].cells[mcol].colSpan;
                    }                    
                    if (mytable.rows[i].cells[jcol].colSpan == jmax) { ncol = currentCol; }
                    else {
                        var jspan = 0;
                        for (var j=0; j<jmax ; j++ ) {
                            jspan += mytable.rows[i].cells[j].colSpan;
                            if (jspan == jmax) ncol = (j == jmax - 1) ? jmax : j;
                        }
                    }
                }
            }
        }
    }
}

function merge_cell() {
/* ------------------------------------------------------------
 * Split a cell
 */
    var mytable = selected_table();
    if (!mytable)
        return
    rows = mytable.rows.length;

//mark TD id
    for (var i=0; i<rows ; i++) {
        cols = mytable.rows[i].cells.length;
        for (var j=0; j<cols ; j++) mytable.rows[i].cells[j].ch = i + '-' + j;
    }
    htmlText = editor.selection.createRange().htmlText;                
    htmlText.toUpperCase();
    if (htmlText.search('<TR') != -1) return;

    var pos = pre_merge(htmlText);
    currentRow = parseInt(pos[0]); begCol = parseInt(pos[1]); endCol = parseInt(pos[2])
    if ( begCol <= endCol && currentRow >= 0) {
        var data = '';
        var html = '';
        var count = 0;                
        var nspan = 0;
        for (var i=begCol; i<=endCol; i++) {
            if (mytable.rows[currentRow].cells[i].hasChildNodes()) {                                
                if (mytable.rows[currentRow].cells[i].innerHTML) html += mytable.rows[currentRow].cells[i].innerHTML;
                    data += mytable.rows[currentRow].cells[i].childNodes.item(0).data + ' ';
            }
            nspan += mytable.rows[currentRow].cells[i].colSpan; 
            count++;
        }
        for (var i=begCol; i<endCol ; i++ ) { delete_cell(currentRow,begCol); }
        mytable.rows[currentRow].cells[begCol].colSpan = nspan;
        mytable.rows[currentRow].cells[begCol].childNodes.item(0).data = data;
        if (html) mytable.rows[currentRow].cells[begCol].innerHTML = html;
    }
}

function pre_merge(htmlText) {
/* ----------------------------------
 * Define currentRow, begCol, endCol in merge cell
 */
    items = htmlText.split("</TD>");
    var currentRow,begCol,endCol;
    for (i=0; i<items.length ;i++) {
        if ( items[i] != '' && items[i].search('<TR') == -1) {                        
            pos1 = items[i].indexOf(">");                        
            pos2 = items[i].indexOf("ch=");
            tmp = items[i].substr(pos2+3,pos1-pos2-3)
            
            elem = tmp.split('-');
            if (i==0) {
                currentRow = elem[0];
                begCol = elem[1];
            }
            endCol = elem[1];                        
        }
    }
    return [currentRow,begCol,endCol];
}

function selected_table () {
/* ------------------------------------------------------------
 * Return a current table object 
 */
    if (!editor) return;
    var table = inner_content.getElementsByTagName("table");
    for (var i=table.length-1; i >= 0; i-- )   
    if (isChild(table(i))) return table(i);
}

function selected_tr (mytable) {
/*------------------------------------------------------------
 * Return a number of current row
 */
    var rows = mytable.rows;
    for (var i=0; i < rows.length; i++) 
        if (isChild(rows(i))) return i;
}

function selected_td (mytable,currentRow) {
/* ------------------------------------------------------------
 * Return a number of current column
 */
    var cols = mytable.rows[currentRow].cells;
    for (var i=0; i < cols.length; i++) 
        if (isChild(cols(i))) return i;
}

function isChild(obj) {
/* ------------------------------------------------------------
 * Return 1: if the cursor is in an object area
 */
    if (!controlRange) {
        // selection is a TextRange                
        var rcts = obj.getClientRects();
        var selection = editor.selection.createRange();
        var sel_rcts = selection.getClientRects();
        var keyCount=0;        
        if ( (sel_rcts[keyCount].top >= rcts[keyCount].top) && (sel_rcts[keyCount].bottom <= rcts[keyCount].bottom) && (sel_rcts[keyCount].left >= rcts[keyCount].left) && (sel_rcts[keyCount].right <= rcts[keyCount].right) )
            return 1;
    }    
}

function check_env() {
    var mytable = selected_table();
    if (!mytable) return;
    if ( selected_tr(mytable) >=0 ) return true;
}

function check_merge(type) {
    if (controlRange) return false;
    htmlText = editor.selection.createRange().htmlText;                
    htmlText.toUpperCase();
    var ret = (type) ? ((htmlText.search('<TR') != -1 || htmlText.search('<TD') != -1) && htmlText != '') : (htmlText.search('<TR') == -1 && htmlText != '' && htmlText.search('<TD') != -1);
    return ret;
}

/* Forms features */

function returnForm(html) {
    var span = editor.createElement("SPAN");
    span.innerHTML = html;
    setFocus();
    insertNodeAtSelection(span);
}

/* -- Toolbar initialization is below -- */

var initInterval, toolbars, tb;

// Keep track of number of images loaded.
//var imagesLoaded = 0;

function toolbarInit () {
/* ---------------------------------------------------------
 * Should be called after the outerdoc has loaded. 
 * Initializes the Toolbar for display.
 */
    if (initialized || initializing) return;
    initializing = true;
    if (!outerdoc) {
        initializing = false;
        setTimeout("toolbarInit()", 100);
        return initOuterIFrame();
    }

    var tbs = outerdoc.getElementsByTagName("DIV");
    var imgs = outerdoc.getElementsByTagName("IMG");

    // There are 3 <div>'s on Mozilla, 4 on IE, containing 20 <img>'s on
    // Mozilla, 23 on IE. If anything is added or removed, this numbers MUST be
    // updated added, this number should be incremented.
    if (tbs.length < 3 || imgs.length < 19) {
        initializing = false;
        setTimeout("toolbarInit()", 100);
        return;
    }
    if (parent.document.getElementById('load_bar')) {
      parent.document.getElementById('load_bar').innerHTML = '';
    }
    parent.document.getElementById('editor_iframe').style.visibility = "visible";
    tb = {};
    // 'toolbars' contains all the div tags
    toolbars = [];

// Go through the outerdoc and get the toolbar classes
    for (var i = 0; i < tbs.length; i++) {
        var toolbar = tbs[i];

        tb[toolbar.title] = toolbar;
        toolbars[toolbars.length] = toolbar;

        toolbar.TB_INDEX  = toolbars.length;

// Initialize the toolbar
        tb_init(toolbar);
    }

    tb_layout();

    initialized = true;
}

function tb_init (toolbar) {
/* ---------------------------------------------------------
 * Called for each toolbar DIV. Populates the toolbar and 
 * sets the width.
 */
    toolbar.TBWidth = 1;
    tb_populate(toolbar)
    
    toolbar.style.posWidth = toolbar.TBWidth;
    return true;
}

function tb_populate (toolbar) {
/* ---------------------------------------------------------
 * Moves all of toolbar 'toolbar's icons to the proper location on
 * the screen and sets the correct size for the toolbars.
 */

    var elements = toolbar.childNodes;
    if (!elements) return;
// Loop through all the toolbars children.

    for (var i = 0; i < elements.length; i++) {
        var element = elements[i];
        if (element.tagName == "SCRIPT" || element.tagName == "!") continue;

// Switch to see what element we are workin with.
        switch (element.className) {
            case "tb_menu_item": // A button
                if (!element.INITIALIZED)
                    tb_init_button(element)
                element.style.left = toolbar.TBWidth;
                toolbar.TBWidth += element.offsetWidth + 1;
                break;

            case "tb_general": // Not a button - most likely a form field

            case "tb_menu_text":
                element.style.left = toolbar.TBWidth;
                toolbar.TBWidth += element.offsetWidth + 5;
                break;

            case "tb_sep": // Seperator
                element.style.left = toolbar.TBWidth + 2;
                toolbar.TBWidth += 5;
                break;

            case "tb_handle": // Toolbar handle
                element.style.left = 2;
                toolbar.TBWidth += element.offsetWidth + 7;
                break;

            default: // No action
        }
    }

    toolbar.TBWidth++; // Add 1 in case the width is zero
    return true;
}

function tb_init_button (element) {
/* ---------------------------------------------------------
 * Sets up all the defaults for a button DIV. Saves any 
 * onclick and detaches the event. OnClick events are called
 * onMouseDown.
 */
    if (element.className == "tb_general") return true;

// Set events
    element.onmouseover  = tb_mouseover;
    element.onmouseout   = tb_mouseout;
    element.onmousedown  = tb_mousedown;
    element.onmouseup    = tb_mouseup;

// Save onClick event for onMouseDown
    element.YUSERONCLICK = element.onclick;

// So we don't re-initialize
    element.INITIALIZED  = true;

    return true;
}

function tb_layout () {
/* ---------------------------------------------------------
 * Layouts the toolbar on the screen based on the screen
 * width and the widths built in tb_populate().
 */

    if (!initializing && !initialized) return toolbarInit();

    var num_tb = toolbars.length;

// No toolbars
    if (num_tb == 0) return;
    var i;

// Get the screen width minus the width of the scrollbar
    var sbar = outerdoc.body.clientWidth - outerdoc.body.offsetWidth;
    editorWidth = outerdoc.body.offsetWidth;
    
    var ScrWid = (outerdoc.body.offsetWidth  - sbar) + (is_ie ? -6 : 7);
    var ScrHit = (parent.document.getElementById('editor_iframe').offsetHeight - sbar) - (is_ie ? 6 : 5);

// Go through the toolbars and find the width of the widest one.
    var TotalLen = ScrWid;
    var tb = [];
    var e = 0;
    for (i = 0; i < num_tb; i++) {
        tb[e] = toolbars[i];
        if (tb[e].TBWidth > TotalLen) TotalLen = tb[e].TBWidth;
        e++;
    }
    e--;
    if (!tb.length) { return; }
    var PrevTB;
    var LastStart = 0;
    var RelTop = 0;
    var LastWid, CurrWid;

// Position the top toolbar to the top of the screen
    var TB        = tb[0];
    TB.style.top  = 0;
    TB.style.left = 0;
    var rows      = 1;

// Go through the toolbars and update their width and position.
    var Start = TB.TBWidth;
    var wExtra = 0
    var hExtra = 0;
    
    for (i = 1; i < tb.length; i++) {
        PrevTB = TB;
        TB = tb[i];
        CurrWid = TB.TBWidth;

// Reached the end of the screen, reset to the start
        if ((Start + CurrWid) > ScrWid) { 
            Start = 0;
            rows++;
            LastWid = TotalLen - LastStart + hExtra;
        }
        else {
            LastWid = PrevTB.TBWidth;
            RelTop -= TB.offsetHeight;
        }
      
        TB.style.top = RelTop;
        TB.style.left = Start;
        PrevTB.style.width = LastWid;

        LastStart = Start;
        Start    += CurrWid;

    }    

    outerdoc.getElementById('editor_iframe').style.top        = rows * (is_ie ? 25 : 27);
    outerdoc.getElementById('editor_iframe').style.height     = ScrHit - rows * (is_ie ? 25 : 27) + wExtra;
    outerdoc.getElementById('editor_iframe').style.width      = ScrWid + wExtra;
    outerdoc.getElementById('editor_iframe').style.visibility = 'visible';
// Set the total width
    TB.style.width = TotalLen - LastStart + hExtra;

// Move the rest of the toolbars down
    TB = tb[--i];
    var TBInd = TB.sourceIndex;    
    
    var A = TB.childNodes;  
    for (var i in A) {
        var item = A.item(i);
        if (item && item.style && item.sourceIndex > TBInd && tb[item.title])
            item.style.posTop = RelTop;
    }
}

function tb_mouseover (event) {
/* ---------------------------------------------------------
 * OnMouseOver event handler function for toolbar buttons.
 */
    var image, element;
    if ( is_ie ) {
        event = parent.document.frames.editor_iframe.event;

        if (event.srcElement.tagName.toUpperCase() != "IMG") return cancel_event(event);
        image   = event.srcElement;
        element = image.parentElement;

// If we are in text mode and the button is disables for 
// text mode. cancel the mouseover.
    }
    else {
        image   = outerdoc.getElementById(this.id + 'Image');
        element = this;
    }

    if (element.disabled) return cancel_event(event);

// If the image in normal state put it in mouseover state
    if (image.className == "tb_icon") {
        element.className = "menu_item_mouseoverup";
    }
// else if it is in down state put it in mouseover
// for down states.
    else if (image.className == "icon_down") {
        element.className = "menu_item_mouseoverdown";
    }

    return cancel_event(event);
}

function tb_mouseout (event) {
/* ---------------------------------------------------------
 * MouseOut event handler function for toolbar buttons
 */
 // The source tag must be an image.
    var image, element;
    if ( is_ie ) {
        event = parent.document.frames.editor_iframe.event;     
        if (event.srcElement.tagName != "IMG") return cancel_event(event);
        var image   = event.srcElement;
        var element = image.parentElement;

        if (element.disabled) return cancel_event(event);
    }
    else {
        image   = outerdoc.getElementById(this.id + 'Image');
        element = this;
    }

// If the button is a toggle update it's state.
    if (element.isPressed) {
        element.className = "menu_item_mouseoverdown"
        image.className   = 'icon_down';
    }
// else put the image back to it's normal state.
    else {
        element.className  = "tb_menu_item";
        image.className    = "tb_icon";
    }

    return cancel_event(event);
}

function tb_mousedown () {
/* ---------------------------------------------------------
 * MouseDown event handler for toolbar buttons.
 */
    this.className = 'menu_item_mouseoverdown';
}

function tb_mouseup () {
/* ---------------------------------------------------------
 * MouseUp event handler function for toolbar buttons.
 */
   this.className = 'menu_item_mouseoverup'; 
}

function isChanged() {
/*---------------------------------------------
Return boolean, True if it's changed
*/
    var body = inner_content.innerHTML;
    if (unStack.length == 0 || !body) return false;
    else if (body != unStack[unStack.length-1]) return true;
}

function getOffsetTop(elm) {

  var mOffsetTop = elm.offsetTop;
  var mOffsetParent = elm.offsetParent;

  while(mOffsetParent){
    mOffsetTop += mOffsetParent.offsetTop;
    mOffsetParent = mOffsetParent.offsetParent;
  }
 
  return mOffsetTop;
}

function getOffsetLeft(elm) {

  var mOffsetLeft = elm.offsetLeft;
  var mOffsetParent = elm.offsetParent;

  while(mOffsetParent){
    mOffsetLeft += mOffsetParent.offsetLeft;
    mOffsetParent = mOffsetParent.offsetParent;
  }
 
  return mOffsetLeft;
}

function insertNodeAtSelection (insertNode) {
    if (is_ie) {
        editor.selection.createRange().pasteHTML(insertNode.outerHTML)
        return;
    }
    var win = document.getElementById("editor_iframe").contentWindow;
    var sel = win.getSelection();

    var range = sel.getRangeAt(0);

      // deselect everything
    if (sel != '')
      sel.removeAllRanges();

      // remove content of current selection from document
    range.deleteContents();

      // get location of current selection
    var container = range.startContainer;
    var pos = range.startOffset;

      // make a new range for the new selection
    range = document.createRange();

    if (container.nodeType==3 && insertNode.nodeType==3) {
        // if we insert text in a textnode, do optimized insertion
        container.insertData(pos, insertNode.nodeValue);

        // put cursor after inserted text
        range.setEnd(container, pos+insertNode.length);
        range.setStart(container, pos+insertNode.length);

    } 
    else {
        var afterNode;
        if (container.nodeType==3) {

          var textNode = container;
          container = textNode.parentNode;
          var text = textNode.nodeValue;

          // text before the split
          var textBefore = text.substr(0,pos);
          // text after the split
          var textAfter = text.substr(pos);

          var beforeNode = document.createTextNode(textBefore);
          var afterNode = document.createTextNode(textAfter);

          // insert the 3 new nodes before the old one
          container.insertBefore(afterNode, textNode);
          container.insertBefore(insertNode, afterNode);
          container.insertBefore(beforeNode, insertNode);

          // remove the old node
          container.removeChild(textNode);

        } 
        else {

          // else simply insert the node
          afterNode = container.childNodes[pos];
          container.insertBefore(insertNode, afterNode);
        }
        if (afterNode) {
            range.setEnd(afterNode, 0);
            range.setStart(afterNode, 0);
        }
      }
    if (typeof(afterNode) != 'undefined')
        sel.addRange(range);
}

function cancel_event (event) {
/* ---------------------------------------------------------
 * General function to cancel an event.
 */
    if (!event) return false;
    event.returnValue  = false;
    event.cancelBubble = true;
    return false;
}