Subversion Repositories SmartDukaan

Rev

Blame | Last modification | View Log | RSS feed

/* Simple JavaScript Inheritance
 * By John Resig http://ejohn.org/
 * MIT Licensed.
 */
// Inspired by base2 and Prototype
(function(){
        var initializing = false;

        // The base JQClass implementation (does nothing)
        window.JQClass = function(){};

        // Collection of derived classes
        JQClass.classes = {};
 
        // Create a new JQClass that inherits from this class
        JQClass.extend = function extender(prop) {
                var base = this.prototype;

                // Instantiate a base class (but only create the instance,
                // don't run the init constructor)
                initializing = true;
                var prototype = new this();
                initializing = false;

                // Copy the properties over onto the new prototype
                for (var name in prop) {
                        // Check if we're overwriting an existing function
                        prototype[name] = typeof prop[name] == 'function' &&
                                typeof base[name] == 'function' ?
                                (function(name, fn){
                                        return function() {
                                                var __super = this._super;

                                                // Add a new ._super() method that is the same method
                                                // but on the super-class
                                                this._super = function(args) {
                                                        return base[name].apply(this, args || []);
                                                };

                                                var ret = fn.apply(this, arguments);                            

                                                // The method only need to be bound temporarily, so we
                                                // remove it when we're done executing
                                                this._super = __super;

                                                return ret;
                                        };
                                })(name, prop[name]) :
                                prop[name];
                }

                // The dummy class constructor
                function JQClass() {
                        // All construction is actually done in the init method
                        if (!initializing && this._init) {
                                this._init.apply(this, arguments);
                        }
                }

                // Populate our constructed prototype object
                JQClass.prototype = prototype;

                // Enforce the constructor to be what we expect
                JQClass.prototype.constructor = JQClass;

                // And make this class extendable
                JQClass.extend = extender;

                return JQClass;
        };
})();

(function($) { // Ensure $, encapsulate

        /** Abstract base class for collection plugins v1.0.1.
                Written by Keith Wood (kbwood{at}iinet.com.au) December 2013.
                Licensed under the MIT (https://github.com/jquery/jquery/blob/master/MIT-LICENSE.txt) license.
                @module $.JQPlugin
                @abstract */
        JQClass.classes.JQPlugin = JQClass.extend({

                /** Name to identify this plugin.
                        @example name: 'tabs' */
                name: 'plugin',

                /** Default options for instances of this plugin (default: {}).
                        @example defaultOptions: {
        selectedClass: 'selected',
        triggers: 'click'
 } */
                defaultOptions: {},
                
                /** Options dependent on the locale.
                        Indexed by language and (optional) country code, with '' denoting the default language (English/US).
                        @example regionalOptions: {
        '': {
                greeting: 'Hi'
        }
 } */
                regionalOptions: {},
                
                /** Names of getter methods - those that can't be chained (default: []).
                        @example _getters: ['activeTab'] */
                _getters: [],

                /** Retrieve a marker class for affected elements.
                        @private
                        @return {string} The marker class. */
                _getMarker: function() {
                        return 'is-' + this.name;
                },
                
                /** Initialise the plugin.
                        Create the jQuery bridge - plugin name <code>xyz</code>
                        produces <code>$.xyz</code> and <code>$.fn.xyz</code>. */
                _init: function() {
                        // Apply default localisations
                        $.extend(this.defaultOptions, (this.regionalOptions && this.regionalOptions['']) || {});
                        // Camel-case the name
                        var jqName = camelCase(this.name);
                        // Expose jQuery singleton manager
                        $[jqName] = this;
                        // Expose jQuery collection plugin
                        $.fn[jqName] = function(options) {
                                var otherArgs = Array.prototype.slice.call(arguments, 1);
                                if ($[jqName]._isNotChained(options, otherArgs)) {
                                        return $[jqName][options].apply($[jqName], [this[0]].concat(otherArgs));
                                }
                                return this.each(function() {
                                        if (typeof options === 'string') {
                                                if (options[0] === '_' || !$[jqName][options]) {
                                                        throw 'Unknown method: ' + options;
                                                }
                                                $[jqName][options].apply($[jqName], [this].concat(otherArgs));
                                        }
                                        else {
                                                $[jqName]._attach(this, options);
                                        }
                                });
                        };
                },

                /** Set default values for all subsequent instances.
                        @param options {object} The new default options.
                        @example $.plugin.setDefauls({name: value}) */
                setDefaults: function(options) {
                        $.extend(this.defaultOptions, options || {});
                },
                
                /** Determine whether a method is a getter and doesn't permit chaining.
                        @private
                        @param name {string} The method name.
                        @param otherArgs {any[]} Any other arguments for the method.
                        @return {boolean} True if this method is a getter, false otherwise. */
                _isNotChained: function(name, otherArgs) {
                        if (name === 'option' && (otherArgs.length === 0 ||
                                        (otherArgs.length === 1 && typeof otherArgs[0] === 'string'))) {
                                return true;
                        }
                        return $.inArray(name, this._getters) > -1;
                },
                
                /** Initialise an element. Called internally only.
                        Adds an instance object as data named for the plugin.
                        @param elem {Element} The element to enhance.
                        @param options {object} Overriding settings. */
                _attach: function(elem, options) {
                        elem = $(elem);
                        if (elem.hasClass(this._getMarker())) {
                                return;
                        }
                        elem.addClass(this._getMarker());
                        options = $.extend({}, this.defaultOptions, this._getMetadata(elem), options || {});
                        var inst = $.extend({name: this.name, elem: elem, options: options},
                                this._instSettings(elem, options));
                        elem.data(this.name, inst); // Save instance against element
                        this._postAttach(elem, inst);
                        this.option(elem, options);
                },

                /** Retrieve additional instance settings.
                        Override this in a sub-class to provide extra settings.
                        @param elem {jQuery} The current jQuery element.
                        @param options {object} The instance options.
                        @return {object} Any extra instance values.
                        @example _instSettings: function(elem, options) {
        return {nav: elem.find(options.navSelector)};
 } */
                _instSettings: function(elem, options) {
                        return {};
                },

                /** Plugin specific post initialisation.
                        Override this in a sub-class to perform extra activities.
                        @param elem {jQuery} The current jQuery element.
                        @param inst {object} The instance settings.
                        @example _postAttach: function(elem, inst) {
        elem.on('click.' + this.name, function() {
                ...
        });
 } */
                _postAttach: function(elem, inst) {
                },

                /** Retrieve metadata configuration from the element.
                        Metadata is specified as an attribute:
                        <code>data-&lt;plugin name>="&lt;setting name>: '&lt;value>', ..."</code>.
                        Dates should be specified as strings in this format: 'new Date(y, m-1, d)'.
                        @private
                        @param elem {jQuery} The source element.
                        @return {object} The inline configuration or {}. */
                _getMetadata: function(elem) {
                        try {
                                var data = elem.data(this.name.toLowerCase()) || '';
                                data = data.replace(/'/g, '"');
                                data = data.replace(/([a-zA-Z0-9]+):/g, function(match, group, i) { 
                                        var count = data.substring(0, i).match(/"/g); // Handle embedded ':'
                                        return (!count || count.length % 2 === 0 ? '"' + group + '":' : group + ':');
                                });
                                data = $.parseJSON('{' + data + '}');
                                for (var name in data) { // Convert dates
                                        var value = data[name];
                                        if (typeof value === 'string' && value.match(/^new Date\((.*)\)$/)) {
                                                data[name] = eval(value);
                                        }
                                }
                                return data;
                        }
                        catch (e) {
                                return {};
                        }
                },

                /** Retrieve the instance data for element.
                        @param elem {Element} The source element.
                        @return {object} The instance data or {}. */
                _getInst: function(elem) {
                        return $(elem).data(this.name) || {};
                },
                
                /** Retrieve or reconfigure the settings for a plugin.
                        @param elem {Element} The source element.
                        @param name {object|string} The collection of new option values or the name of a single option.
                        @param [value] {any} The value for a single named option.
                        @return {any|object} If retrieving a single value or all options.
                        @example $(selector).plugin('option', 'name', value)
 $(selector).plugin('option', {name: value, ...})
 var value = $(selector).plugin('option', 'name')
 var options = $(selector).plugin('option') */
                option: function(elem, name, value) {
                        elem = $(elem);
                        var inst = elem.data(this.name);
                        if  (!name || (typeof name === 'string' && value == null)) {
                                var options = (inst || {}).options;
                                return (options && name ? options[name] : options);
                        }
                        if (!elem.hasClass(this._getMarker())) {
                                return;
                        }
                        var options = name || {};
                        if (typeof name === 'string') {
                                options = {};
                                options[name] = value;
                        }
                        this._optionsChanged(elem, inst, options);
                        $.extend(inst.options, options);
                },
                
                /** Plugin specific options processing.
                        Old value available in <code>inst.options[name]</code>, new value in <code>options[name]</code>.
                        Override this in a sub-class to perform extra activities.
                        @param elem {jQuery} The current jQuery element.
                        @param inst {object} The instance settings.
                        @param options {object} The new options.
                        @example _optionsChanged: function(elem, inst, options) {
        if (options.name != inst.options.name) {
                elem.removeClass(inst.options.name).addClass(options.name);
        }
 } */
                _optionsChanged: function(elem, inst, options) {
                },
                
                /** Remove all trace of the plugin.
                        Override <code>_preDestroy</code> for plugin-specific processing.
                        @param elem {Element} The source element.
                        @example $(selector).plugin('destroy') */
                destroy: function(elem) {
                        elem = $(elem);
                        if (!elem.hasClass(this._getMarker())) {
                                return;
                        }
                        this._preDestroy(elem, this._getInst(elem));
                        elem.removeData(this.name).removeClass(this._getMarker());
                },

                /** Plugin specific pre destruction.
                        Override this in a sub-class to perform extra activities and undo everything that was
                        done in the <code>_postAttach</code> or <code>_optionsChanged</code> functions.
                        @param elem {jQuery} The current jQuery element.
                        @param inst {object} The instance settings.
                        @example _preDestroy: function(elem, inst) {
        elem.off('.' + this.name);
 } */
                _preDestroy: function(elem, inst) {
                }
        });
        
        /** Convert names from hyphenated to camel-case.
                @private
                @param value {string} The original hyphenated name.
                @return {string} The camel-case version. */
        function camelCase(name) {
                return name.replace(/-([a-z])/g, function(match, group) {
                        return group.toUpperCase();
                });
        }
        
        /** Expose the plugin base.
                @namespace "$.JQPlugin" */
        $.JQPlugin = {
        
                /** Create a new collection plugin.
                        @memberof "$.JQPlugin"
                        @param [superClass='JQPlugin'] {string} The name of the parent class to inherit from.
                        @param overrides {object} The property/function overrides for the new class.
                        @example $.JQPlugin.createPlugin({
        name: 'tabs',
        defaultOptions: {selectedClass: 'selected'},
        _initSettings: function(elem, options) { return {...}; },
        _postAttach: function(elem, inst) { ... }
 }); */
                createPlugin: function(superClass, overrides) {
                        if (typeof superClass === 'object') {
                                overrides = superClass;
                                superClass = 'JQPlugin';
                        }
                        superClass = camelCase(superClass);
                        var className = camelCase(overrides.name);
                        JQClass.classes[className] = JQClass.classes[superClass].extend(overrides);
                        new JQClass.classes[className]();
                }
        };

})(jQuery);