All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.myfaces.custom.inputHtml.resource.kupubasetools.js Maven / Gradle / Ivy

Go to download

JSF components and utilities that can be used with any JSF implementation. This library is compatible with both JSF1.1 and JSF1.2; however for JSF1.2 users there is an alternative build of Tomahawk available that takes advantage of JSF1.2 features to offer some additional benefits.

There is a newer version: 1.1.14
Show newest version
/*****************************************************************************
 *
 * Copyright (c) 2003-2005 Kupu Contributors. All rights reserved.
 *
 * This software is distributed under the terms of the Kupu
 * License. See LICENSE.txt for license text. For a list of Kupu
 * Contributors see CREDITS.txt.
 *
 *****************************************************************************/

// $Id: kupubasetools.js 389458 2006-03-28 09:47:12Z svieujot $


//----------------------------------------------------------------------------
//
// Toolboxes
//
//  These are addons for Kupu, simple plugins that implement a certain 
//  interface to provide functionality and control view aspects.
//
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
// Superclasses
//----------------------------------------------------------------------------

function KupuTool() {
    /* Superclass (or actually more of an interface) for tools 
    
        Tools must implement at least an initialize method and an 
        updateState method, and can implement other methods to add 
        certain extra functionality (e.g. createContextMenuElements).
    */

    this.toolboxes = {};

    // methods
    this.initialize = function(editor) {
        /* Initialize the tool.

            Obviously this can be overriden but it will do
            for the most simple cases
        */
        this.editor = editor;
    };

    this.registerToolBox = function(id, toolbox) {
        /* register a ui box 
        
            Note that this needs to be called *after* the tool has been 
            registered to the KupuEditor
        */
        this.toolboxes[id] = toolbox;
        toolbox.initialize(this, this.editor);
    };
    
    this.updateState = function(selNode, event) {
        /* Is called when user moves cursor to other element 

            Calls the updateState for all toolboxes and may want perform
            some actions itself
        */
        for (id in this.toolboxes) {
            this.toolboxes[id].updateState(selNode, event);
        };
    };

    this.enable = function() {
        // Called when the tool is enabled after a form is dismissed.
    }

    this.disable = function() {
        // Called when the tool is disabled (e.g. for a modal form)
    }
    // private methods
    addEventHandler = addEventHandler;
    
    this._selectSelectItem = function(select, item) {
        this.editor.logMessage(_('Deprecation warning: KupuTool._selectSelectItem'));
    };
    this._fixTabIndex = function(element) {
        var tabIndex = this.editor.getDocument().getEditable().tabIndex-1;
        if (tabIndex && !element.tabIndex) {
            element.tabIndex = tabIndex;
        }
    }
}

function KupuToolBox() {
    /* Superclass for a user-interface object that controls a tool */

    this.initialize = function(tool, editor) {
        /* store a reference to the tool and the editor */
        this.tool = tool;
        this.editor = editor;
    };

    this.updateState = function(selNode, event) {
        /* update the toolbox according to the current iframe's situation */
    };
    
    this._selectSelectItem = function(select, item) {
        this.editor.logMessage(_('Deprecation warning: KupuToolBox._selectSelectItem'));
    };
};

function NoContextMenu(object) {
    /* Decorator for a tool to suppress the context menu */
    object.createContextMenuElements = function(selNode, event) {
        return [];
    }
    return object;
}

// Helper function for enabling/disabling tools
function KupuButtonDisable(button) {
    button = button || this.button;
    button.disabled = "disabled";
    button.className += ' disabled';
}
function KupuButtonEnable(button) {
    button = button || this.button;
    button.disabled = "";
    button.className = button.className.replace(/ *\bdisabled\b/g, '');
}


//----------------------------------------------------------------------------
// Implementations
//----------------------------------------------------------------------------

function KupuButton(buttonid, commandfunc, tool) {
    /* Base prototype for kupu button tools */
    this.buttonid = buttonid;
    this.button = getFromSelector(buttonid);
    this.commandfunc = commandfunc;
    this.tool = tool;

    this.initialize = function(editor) {
        this.editor = editor;
        this._fixTabIndex(this.button);
        addEventHandler(this.button, 'click', this.execCommand, this);
    };

    this.execCommand = function() {
        /* exec this button's command */
        this.commandfunc(this, this.editor, this.tool);
    };

    this.updateState = function(selNode, event) {
        /* override this in subclasses to determine whether a button should
            look 'pressed in' or not
        */
    };
    this.disable = KupuButtonDisable;
    this.enable = KupuButtonEnable;
};

KupuButton.prototype = new KupuTool;
function KupuStateButton(buttonid, commandfunc, checkfunc, offclass, onclass) {
    /* A button that can have two states (e.g. pressed and
       not-pressed) based on CSS classes */
    this.buttonid = buttonid;
    this.button = getFromSelector(buttonid);
    this.commandfunc = commandfunc;
    this.checkfunc = checkfunc;
    this.offclass = offclass;
    this.onclass = onclass;
    this.pressed = false;

    this.execCommand = function() {
        /* exec this button's command */
        this.button.className = (this.pressed ? this.offclass : this.onclass);
        this.pressed = !this.pressed;
        this.editor.focusDocument();
        this.commandfunc(this, this.editor);
    };

    this.updateState = function(selNode, event) {
        /* check if we need to be clicked or unclicked, and update accordingly 
        
            if the state of the button should be changed, we set the class
        */
        var currclass = this.button.className;
        var newclass = null;
        if (this.checkfunc(selNode, this, this.editor, event)) {
            newclass = this.onclass;
            this.pressed = true;
        } else {
            newclass = this.offclass;
            this.pressed = false;
        };
        if (currclass != newclass) {
            this.button.className = newclass;
        };
    };
};

KupuStateButton.prototype = new KupuButton;

/* Same as the state button, but the focusDocument call is delayed.
 * Mozilla&Firefox have a bug on windows which can cause a crash if you
 * change CSS positioning styles on an element which has focus.
 */
function KupuLateFocusStateButton(buttonid, commandfunc, checkfunc, offclass, onclass) {
    KupuStateButton.apply(this, [buttonid, commandfunc, checkfunc, offclass, onclass]);
    this.execCommand = function() {
        /* exec this button's command */
        this.button.className = (this.pressed ? this.offclass : this.onclass);
        this.pressed = !this.pressed;
        this.commandfunc(this, this.editor);
        this.editor.focusDocument();
    };
}
KupuLateFocusStateButton.prototype = new KupuStateButton;

function KupuRemoveElementButton(buttonid, element_name, cssclass) {
    /* A button specialized in removing elements in the current node
       context. Typical usages include removing links, images, etc. */
    this.button = getFromSelector(buttonid);
    this.onclass = 'invisible';
    this.offclass = cssclass;
    this.pressed = false;

    this.commandfunc = function(button, editor) {
        editor.removeNearestParentOfType(editor.getSelectedNode(), element_name);
    };

    this.checkfunc = function(currnode, button, editor, event) {
        var element = editor.getNearestParentOfType(currnode, element_name);
        return (element ? false : true);
    };
};

KupuRemoveElementButton.prototype = new KupuStateButton;

function KupuUI(textstyleselectid) {
    /* View 
    
        This is the main view, which controls most of the toolbar buttons.
        Even though this is probably never going to be removed from the view,
        it was easier to implement this as a plain tool (plugin) as well.
    */
    
    // attributes
    this.tsselect = getFromSelector(textstyleselectid);
    var paraoptions = [];
    var tableoptions = [];
    this.optionstate = -1;
    this.otherstyle = null;
    this.tablestyles = {};
    this.styles = {}; // use an object here so we can use the 'in' operator later on

    this.initialize = function(editor) {
        /* initialize the ui like tools */
        this.editor = editor;
        this.cleanStyles();
        this.enableOptions(false);
        this._fixTabIndex(this.tsselect);
        this._selectevent = addEventHandler(this.tsselect, 'change', this.setTextStyleHandler, this);
    };

    this.getStyles = function() {
        if (!paraoptions) {
            this.cleanStyles();
        }
        return [ paraoptions, tableoptions ];
    }

    this.setTextStyleHandler = function(event) {
        this.setTextStyle(this.tsselect.options[this.tsselect.selectedIndex].value);
    };
    
    // event handlers
    this.basicButtonHandler = function(action) {
        /* event handler for basic actions (toolbar buttons) */
        this.editor.execCommand(action);
        this.editor.updateState();
    };

    this.saveButtonHandler = function() {
        /* handler for the save button */
        this.editor.saveDocument();
    };

    this.saveAndExitButtonHandler = function(redirect_url) {
        /* save the document and, if successful, redirect */
        this.editor.saveDocument(redirect_url);
    };

    this.cutButtonHandler = function() {
        try {
            this.editor.execCommand('Cut');
        } catch (e) {
            if (this.editor.getBrowserName() == 'Mozilla') {
                alert(_('Cutting from JavaScript is disabled on your Mozilla due to security settings. For more information, read http://www.mozilla.org/editor/midasdemo/securityprefs.html'));
            } else {
                throw e;
            };
        };
        this.editor.updateState();
    };

    this.copyButtonHandler = function() {
        try {
            this.editor.execCommand('Copy');
        } catch (e) {
            if (this.editor.getBrowserName() == 'Mozilla') {
                alert(_('Copying from JavaScript is disabled on your Mozilla due to security settings. For more information, read http://www.mozilla.org/editor/midasdemo/securityprefs.html'));
            } else {
                throw e;
            };
        };
        this.editor.updateState();
    };

    this.pasteButtonHandler = function() {
        try {
            this.editor.execCommand('Paste');
        } catch (e) {
            if (this.editor.getBrowserName() == 'Mozilla') {
                alert(_('Pasting from JavaScript is disabled on your Mozilla due to security settings. For more information, read http://www.mozilla.org/editor/midasdemo/securityprefs.html'));
            } else {
                throw e;
            };
        };
        this.editor.updateState();
    };

    this.cleanStyles = function() {
        var options = this.tsselect.options;
        var parastyles = this.styles;
        var tablestyles = this.tablestyles;

        tableoptions.push([options[0].text, 'td|']);
        tablestyles['td'] = 0;
        paraoptions.push([options[0].text, 'p|']);
        parastyles['p'] = 0;
        while (options.length > 1) {
            opt = options[1];
            var v = opt.value;
            if (/^thead|tbody|table|t[rdh]\b/i.test(v)) {
                var otable = tableoptions;
                var styles = tablestyles;
            } else {
                var otable = paraoptions;
                var styles = parastyles;
            }
            if (v.indexOf('|') > -1) {
                var split = v.split('|');
                v = split[0].toLowerCase() + "|" + split[1];
            } else {
                v = v.toLowerCase()+"|";
            };
            otable.push([opt.text, v]);
            styles[v] = otable.length - 1;
            options[1] = null;
        }
        options[0] = null;
    }

    // Remove otherstyle and switch to appropriate style set.
    this.enableOptions = function(inTable) {
        var select = this.tsselect;
        var options = select.options;
        if (this.otherstyle) {
            options[options.length-1] = null;
            this.otherstyle = null;
        }
        if (this.optionstate == inTable) return; /* No change */

        var valid = inTable ? tableoptions : paraoptions;

        while (options.length) options[0] = null;
        this.otherstyle = null;

        for (var i = 0; i < valid.length; i++) {
            var opt = document.createElement('option');
            opt.text = valid[i][0];
            opt.value = valid[i][1];
            options.add(opt);
        }
        select.selectedIndex = 0;
        this.optionstate = inTable;
    }
    
    this.setIndex = function(currnode, tag, index, styles) {
        var className = currnode.className;
        this.styletag = tag;
        this.classname = className;
        var style = tag+'|'+className;

        if (style in styles) {
            return styles[style];
        } else if (!className && tag in styles) {
            return styles[tag];
        }
        return index;
    }

    this.nodeStyle = function(node) {
        var currnode = node;
        var index = -1;
        var options = this.tsselect.options;
        this.styletag = undefined;
        this.classname = '';
        this.intable = false;

        while (currnode) {
            var tag = currnode.nodeName.toLowerCase();

            if (/^body$/.test(tag)) {
                if (!this.styletag) {
                    // Force style setting
                    //this.setTextStyle(options[0].value, true);
                    // Forced style messes up in Firefox: return -1 to
                    // indicate no style 
                    return -1;
                }
                break;
            }
            if (/^(p|div|h.|ul|ol|dl|menu|dir|pre|blockquote|address|center)$/.test(tag)) {
                index = this.setIndex(currnode, tag, index, this.styles);
            }
            if (/^thead|tbody|table|t[rdh]$/.test(tag)) {
                this.intable = true;
                index = this.setIndex(currnode, tag, index, this.tablestyles);

                if (index > 0 || tag=='table') {
                    return index; // Stop processing if in a table
                }
            }
            currnode = currnode.parentNode;
        }
        return index;
    }

    this.updateState = function(selNode) {
        /* set the text-style pulldown */

        // first get the nearest style
        // search the list of nodes like in the original one, break if we encounter a match,
        // this method does some more than the original one since it can handle commands in
        // the form of '