Jx.JxUtilities

This is a utility class and provides various utility functions to dynamically load and remove JavaScript and CSS files.


/**
 * @class Jx.JxUtilities
 * Class containing Utility functions
 */

Jx.JxUtilities = function () {
    return {
        debug: false,
        heartbeatId: null,
        // select debug or regular JSON encoder.  (debug has pretty printing)
        encode: function () {
            var encode = this.debug ? Jx.JxJSON.encode : Ext.util.JSON.encode;
            return encode.apply(this, arguments);
        },
        /**
         * View related configuration property retrieval. The config needs to contain
         * xtype in order for use to figure out whats the default config value is.
         * Once config has been realized(instantiated into object), then no need to use this function.
         *
         * Return may be null or undefined.
         *
         * @param config
         * @param propName
         */
        getXTypePropValue: function (config, propName) {
            if (!config) {
                JxDebugConsole.log('JxUtilities.getPropValue: config not defined.');
                return undefined;
            }
            var propValue = config[propName];
            if (propValue) return propValue;
            if (!config.xtype) {
                JxDebugConsole.log('JxUtilities.getPropValue: config.xtype not defined.');
                return undefined;
            }
            var currentClass = Ext.ComponentMgr.types[config.xtype];
            while (currentClass) {
                var defaultConfig;
                if (Ext.isFunction(currentClass)) {
                    defaultConfig = currentClass.prototype;
                } else {
                    defaultConfig = currentClass;
                }
                propValue = defaultConfig[propName];
                if (propValue) {
                    break;
                }
                currentClass = currentClass.superclass;
            }
            return propValue;
        },
        /**
         * View related configuration processing. Clean up
         * @param config
         * @return any processing or not
         */
        processJxItems: function (config) {
            if (config == undefined) {
                return false;
            }
            if (config.jxitems == undefined) {
                return false; //
            }
            if (config.jxitems && config.items) {
                // something wrong. should be one or the other
                JxDebugConsole.log('Jx.JxUtilities.processJxItems() Error: both jxitems and items are defined.');
                return false;
            }
            if (config.jxViewRepository == undefined) {
                // something wrong. nothing in view repository for current container.
                JxDebugConsole.log('Jx.JxUtilities.processJxItems() Error: config.jxViewRepository is undefined.');
                return false;
            }
            var jxViewRepository = config.jxViewRepository;
            config.items = [];
            for (var indx = 0; indx < config.jxitems.length; indx++) {
                var viewName = config.jxitems[indx];
                if (Ext.isString(viewName)) {
                    // assume it is string always
                    viewName = jxViewRepository[viewName];
                } // else assume Object
                config.items.push(viewName);
                // for child view to use
                viewName.jxViewRepository = config.jxViewRepository;
            }
            delete config.jxitems;
            return true;
        },
        /**
         * For example:
         *   Jx.JxUtilities.findPluginByType(myPanel, Ext.ux.grid.RowExpander) will return
         *    myPanel's RowExpander plugins.
         *
         * @param comp
         * @param xtype
         */
        findPluginByType: function (comp, xtype) {
            if (!Ext.isFunction(xtype)) {
                JxDebugConsole.log('please input Plugin class instead of string');
                return null;
            }
            if (Ext.isArray(comp.plugins)) {
                for (var index = 0; index < comp.plugins.length; index++) {
                    var p = comp.plugins[index];
                    if (p.constructor === xtype) return p;
                }
            }
            return null;
        },
        /**
         * processJxActionItems:
         * @param config
         * Will Process the View Config and wrap action object as a wrapper for the various
         * button bars such as bbar, fbar and tbar if custom jxbbar, jxtbar and jxfbar are used.
         * Ext defined buttons will not be processed as they will use Ext framework.
         */
        processJxActionItems: function (config) {
            if (config == undefined) {
                return false;
            }
            //If Ext Config then skip attaching actions
            if (config.bbar || config.tbar || config.fbar) {
                JxDebugConsole.log('Jx.JxUtilities.processJxActionItems()bbar, tbar or fbar defined, nothing to do.');
                return false;
            }
            //If action is not defined then wrap action object on view config for support within framework
            if (config.action == undefined) {
                Ext.apply(config, {
                    action: {}
                });
            }
            var action = config.action;
            if (config.jxbbar) {
                Ext.apply(action, {
                    bbar: config.jxbbar
                })
            }
            if (config.jxfbar) {
                Ext.apply(action, {
                    fbar: config.jxfbar
                });
            }
            if (config.jxtbar) {
                Ext.apply(action, {
                    tbar: config.jxtbar
                });
            }
            return true;
        },
        /**
         * Clone Function to make a deep clone of an object or an array
         * @param {Object/Array} o Object or array to clone
         * @return {Object/Array} Deep copy of an object or an array
         **/
        clone: function (o) {
            if (!o || 'object' !== typeof o) {
                return o;
            }
            if ('function' === typeof o.clone) {
                return o.clone();
            }
            var c = '[object Array]' === Object.prototype.toString.call(o) ? [] : {};
            var p, v;
            for (p in o) {
                if (o.hasOwnProperty(p)) {
                    v = o[p];
                    if (v && 'object' === typeof v) {
                        c[p] = Jx.JxUtilities.clone(v);
                    } else {
                        c[p] = v;
                    }
                }
            }
            return c;
        },
        /**
         * Figure out if the gui component config is that of a JxHostContainer or its derived class.
         * Since gui config is not yet a component object, the function isXType() is not available.
         *
         * @param {Object} config  A gui component's configuration
         * @return {Boolean} true if the gui component config is a JxHostContainer.
         */
        isJxHostContainer: function (config) {
            if (config.xtype == 'jxhostcontainer') {
                return true;
            } else if (config.xtype == 'jxresthostcontainer') {
                return true;
            }
            return false;
        },
        /**
         * Find GUI component's parent container that is type of JxHostContainer
         * Ext.Component.findParentByType is a SHALLOW class hierachy comparison.
         * So we have to do a separate utility for this.
         *
         * @param {Object} comp  A gui component object.
         * @return {Object} parent JxHostContainer.
         */
        findParentHostContainer: function (comp) {
            var fn = function (parentComp) {
                    if (parentComp.isXType('jxhostcontainer')) return true;
                    return false;
                };
            return comp.findParentBy(fn);
        },
        removeSquareBracket: function (somestring) {
            return somestring.replace(/\[[^()]*\]/, "");
        },
        getStringFromLastSlash: function (somestring, rowIndex) {
            var index = somestring.lastIndexOf('/');
            if (index) {
                somestring = somestring.substring(index + 1);
            }
            return somestring + '[' + rowIndex + ']';
            //        return somestring + '[@rowId=\"' + rowIndex + '\"]';
        },
        appendRowIndexToUrl: function (decoded_url, decoded_dpath, rowIndex) {
            var pre = decoded_url.substring(0, decoded_url.lastIndexOf('dpath=') + 6);
            //pre is decoded
            if (Jx.JxUtilities.isInteger(rowIndex)) {
                decoded_dpath = Jx.JxUtilities.appendRowIndexToDPath(decoded_dpath, rowIndex);
            } else {
                var array = rowIndex.split('/');
                for (var i = 0; i < array.length; i++) {
                    var withRowId = array[i];
                    var pos = withRowId.indexOf('[@rowId=');
                    var from = withRowId.substring(0, pos);
                    var newdecoded_dpath = decoded_dpath.replace('/' + from + '/', '/' + withRowId + '/');
                    if (newdecoded_dpath == decoded_dpath) {
                        var fromstr = '/' + from;
                        if (newdecoded_dpath.lastIndexOf(fromstr) + fromstr.length == newdecoded_dpath.length) {
                            newdecoded_dpath = newdecoded_dpath.substring(0, newdecoded_dpath.lastIndexOf('/')) + '/' + withRowId;
                        }
                    }
                    decoded_dpath = newdecoded_dpath;
                }
            }
            var pos = Ext.urlEncode({
                url: decoded_dpath
            }).substring(4);
            //pos is encoded
            return pre + pos;
        },
        appendRowIndexToDPath: function (dpath, rowIndex) {
            return dpath + "[@rowId=\"" + rowIndex + "\"]";
        },
        isInteger: function (s) {
            return (s.toString().search(/^-?[0-9]+$/) == 0);
        },
        /**
         * Set preview parameters if preview flag has been set to true
         * @param caller
         * @param url
         */
        setPreviewUrl: function (caller, url) {
            if (caller.findParentByType('jxsteppanel') != null) {
                var stepPanel = caller.findParentByType('jxsteppanel');
                if (stepPanel.previewMode) {
                    url = url + '&preview=true';
                }
            }
            return url;
        },
        /**
         * @param {Object} config
         * @return {Number} heartbeat Id
         * This function performs the task of initiating an heartbeat.
         * Current active context is determined by using the selected node
         * in the ribbon. The action url attribute of the node is used to
         * generate the heartbeat.User of this utility function can provide
         * success and failure handler function as an input config to this
         * function.The user can also provide the time interval used to determine
         * how frequently the heartbeat is sent to the server. 
         */
        startHeartbeat: function (config) {
            function heartbeat() {
                var ribbon = Ext.getCmp('newribbon');
                if (ribbon) {
                    if (ribbon.treePane && ribbon.treePane.selectedNode) {
                        var actionURL = ribbon.treePane.selectedNode.attributes.action;
                        var heartbeatURL = actionURL.substring(0, actionURL.indexOf('?action'));
                        if (heartbeatURL.length > 0) {
                            new Jx.JxConnection().request({
                                url: config.url ? config.url : heartbeatURL,
                                scope: this,
                                success: config.successHandler ? config.successHandler : Ext.emptyFn,
                                failure: config.failureHandler ? config.failureHandler : Ext.emptyFn
                            });
                        }
                    }
                }
            }
            this.heartbeatId = window.setInterval(heartbeat, config.interval);
            return this.heartbeatId;
        },
        /**
         * This function serves the purpose of stopping the heartbeat
         * It does that by clearing the interval that sends the heartbeat.
         */
        stopHeartbeat: function () {
            window.clearInterval(this.heartbeatId);
        },
        /**
         * @param functionName
         * @param context
         * This utility function takes two parameters. The function name and
         * the context in which to execute the function. It then executes
         * the function in the context/scope provided.
         */
        executeFunctionByName: function (functionName, context /*, args */ ) {
            var localContext = window[context];
            var args = Array.prototype.slice.call(arguments).splice(2);
            var namespaces = functionName.split(".");
            var func = namespaces.pop();
            for (var i = 0; i < namespaces.length; i++) {
                localContext = localContext[namespaces[i]];
            }
            return localContext[func].apply(this, args);
        },
        /**
         * @param functionName
         * @param context
         * This utility function takes two parameters. The constructor function
         * name and the context.It then uses the context to locate the
         * constructor function and execute it.
         */
        executeConstructor: function (functionName, context /*, args */ ) {
            var localContext = window[context];
            var args = Array.prototype.slice.call(arguments).splice(2);
            var namespaces = functionName.split(".");
            var func = namespaces.pop();
            for (var i = 0; i < namespaces.length; i++) {
                localContext = localContext[namespaces[i]];
            }
            return new localContext[func](args);
        },
        /**
         * @param files
         * @param onLoadCallback
         * This utility function mimics the functionality provided by many
         * open source javascript frameworks to load javascript and css
         * files dynamically. The user needs to provide array of filenames
         * and the callback function that gets called once all the files
         * are loaded.Under the hood this function uses the includeMany
         * function provided by the JxNativeJxUtils.Each element within
         * the file name array needs to be an array that has two members.
         * The first member is the type of file and second is the name of the file.
         * For example:
         * this.jsFiles = [];
         * this.cssFiles = [];
         * this.jsFiles.push(['js', './js/examples/Jx/usertask/models/UserSore.js']) to load javascript file.
         * this.cssFiles.push(['css', './css/usetask-1.css']) to load css file.
         */
        require: function (files, onLoadCallback) {
            var filenames = Ext.isArray(files) ? files : new Array(files);
            JxNativeJsUtils.includeMany(files, onLoadCallback);
        },
        /**
         * @param filetype
         * @param filenames
         * This utility function serves the purpose of dynamically removing the
         * the script tags (for javascript files) and link tags (for css files)
         * for the list of filenames provided by the user.The usage is as follows:
         * Jx.JxUtilites.removeFiles('js',this.jsFiles);
         * Jx.JxUtilites.removeFiles('js',this.cssFiles);
         * where jsFiles and cssFiles are arrays that follow the convention mentioned
         * in {@link Jx.JxUtilties.require}.
         */
        removeFiles: function (filetype, filenames) {
            var tags, attribute;
            if (filetype == 'css') {
                attribute = 'href';
                tags = document.getElementsByTagName("link");
            } else if (filetype == 'js') {
                attribute = 'src';
                tags = document.getElementsByTagName("script");
            }
            for (var i = 0; i < filenames.length; i++) {
                for (var j = 0; j < tags.length; j++) {
                    var filenameInTag = tags[j].getAttribute(attribute);
                    var filenameToSearch = filenames[i][1];
                    if (filenameInTag && filenameToSearch) {
                        if (filenameInTag.search(filenameToSearch) != -1) {
                            console.log("Removing files " + filenameToSearch);
                            tags[j].parentNode.removeChild(tags[j]);
                        }
                    }
                }
            }
        },
        /**
         * @param taskId
         * This utility function calls the destroy method of
         * the previously selected task.This is done for cleanup purposes.
         * It then enables the user to jump to the task that has the task id
         * provided by the user. 
         */
        jumpToTask: function (taskId) {
            var newribbon = Ext.getCmp("newribbon");
            newribbon.navigateTo(taskId);
        }
    };
}();