<commit_before>/**
Attaches stand-alone container with editable-form to HTML element. Element is used only for positioning, value is not stored anywhere.

This method applied internally in $().editable(). You should subscribe on it's events (save / cancel) to get profit of it.

Final realization can be different: bootstrap-popover, jqueryui-tooltip, poshytip, inline-div. It depends on which js file you include.

Applied as jQuery method.

@class editableContainer
@uses editableform
**/
(function ($) {
    "use strict";

    var Popup = function (element, options) {
        this.init(element, options);
    };

    var Inline = function (element, options) {
        this.init(element, options);
    };

    //methods
    Popup.prototype = {
        containerName: null, //tbd in child class
        innerCss: null, //tbd in child class
        containerClass: 'editable-container editable-popup', //css class applied to container element
        init: function(element, options) {
            this.$element = $(element);
            //since 1.4.1 container do not use data-* directly as they already merged into options.
            this.options = $.extend({}, $.fn.editableContainer.defaults, options);
            this.splitOptions();

            //set scope of form callbacks to element
            this.formOptions.scope = this.$element[0];

            this.initContainer();

            //bind 'destroyed' listener to destroy container when element is removed from dom
            this.$element.on('destroyed', $.proxy(function(){
                this.destroy();
            }, this));

            //attach document handler to close containers on click / escape
            if(!$(document).data('editable-handlers-attached')) {
                //close all on escape
                $(document).on('keyup.editable', function (e) {
                    if (e.which === 27) {
                        $('.editable-open').editableContainer('hide');
                        //todo: return focus on element
                    }
                });

                //close containers when click outside
                //(mousedown could be better than click, it closes everything also on drag drop)
                $(document).on('click.editable', function(e) {
                    var $target = $(e.target), i,
                        exclude_classes = ['.editable-container',
                                           '.ui-datepicker-header',
                                           '.datepicker', //in inline mode datepicker is rendered into body
                                           '.modal-backdrop',
                                           '.bootstrap-wysihtml5-insert-image-modal',
                                           '.bootstrap-wysihtml5-insert-link-modal'
                                           ];

                    //check if element is detached. It occurs when clicking in bootstrap datepicker
                    if (!$.contains(document.documentElement, e.target)) {
                      return;
                    }

                    //for some reason FF 20 generates extra event (click) in select2 widget with e.target = document
                    //we need to filter it via construction below. See https://github.com/vitalets/x-editable/issues/199
                    //Possibly related to http://stackoverflow.com/questions/10119793/why-does-firefox-react-differently-from-webkit-and-ie-to-click-event-on-selec
                    if($target.is(document)) {
                       return;
                    }

                    //if click inside one of exclude classes --> no nothing
                    for(i=0; i<exclude_classes.length; i++) {
                         if($target.is(exclude_classes[i]) || $target.parents(exclude_classes[i]).length) {
                             return;
                         }
                    }

                    //close all open containers (except one - target)
                    Popup.prototype.closeOthers(e.target);
                });

                $(document).data('editable-handlers-attached', true);
            }
        },

        //split options on containerOptions and formOptions
        splitOptions: function() {
            this.containerOptions = {};
            this.formOptions = {};
            var cDef = $.fn[this.containerName].defaults;
            //keys defined in container defaults go to container, others go to form
            for(var k in this.options) {
              if(k in cDef) {
                 this.containerOptions[k] = this.options[k];
              } else {
                 this.formOptions[k] = this.options[k];
              }
            }
        },

        /*
        Returns jquery object of container
        @method tip()
        */
        tip: function() {
            return this.container() ? this.container().$tip : null;
        },

        /* returns container object */
        container: function() {
            return this.$element.data(this.containerDataName || this.containerName);
        },

        /* call native method of underlying container, e.g. this.$element.popover('method') */
        call: function() {
            this.$element[this.containerName].apply(this.$element, arguments);
        },

        initContainer: function(){
            this.call(this.containerOptions);
        },

        renderForm: function() {
            this.$form
            .editableform(this.formOptions)
            .on({
                save: $.proxy(this.save, this), //click on submit button (value changed)
                nochange: $.proxy(function(){ this.hide('nochange'); }, this), //click on submit button (value NOT changed)
                cancel: $.proxy(function(){ this.hide('cancel'); }, this), //click on calcel button
                show: $.proxy(this.setPosition, this), //re-position container every time form is shown (occurs each time after loading state)
                rendering: $.proxy(this.setPosition, this), //this allows to place container correctly when loading shown
                resize: $.proxy(this.setPosition, this), //this allows to re-position container when form size is changed
                rendered: $.proxy(function(){
                    /**
                    Fired when container is shown and form is rendered (for select will wait for loading dropdown options).
                    **Note:** Bootstrap popover has own `shown` event that now cannot be separated from x-editable's one.
                    The workaround is to check `arguments.length` that is always `2` for x-editable.

                    @event shown
                    @param {Object} event event object
                    @example
                    $('#username').on('shown', function(e, editable) {
                        editable.input.$input.val('overwriting value of input..');
                    });
                    **/
                    /*
                     TODO: added second param mainly to distinguish from bootstrap's shown event. It's a hotfix that will be solved in future versions via namespaced events.
                    */
                    this.$element.triggerHandler('shown', this);
                }, this)
            })
            .editableform('render');
        },

        /**
        Shows container with form
        @method show()
        @param {boolean} closeAll Whether to close all other editable containers when showing this one. Default true.
        **/
        /* Note: poshytip owerwrites this method totally! */
        show: function (closeAll) {
            this.$element.addClass('editable-open');
            if(closeAll !== false) {
                //close all open containers (except this)
                this.closeOthers(this.$element[0]);
            }

            //show container itself
            this.innerShow();
            this.tip().addClass(this.containerClass);

            /*
            Currently, form is re-rendered on every show.
            The main reason is that we dont know, what container will do with content when closed:
            remove(), detach() or just hide().

            Detaching form itself before hide and re-insert before show is good solution,
            but visually it looks ugly, as container changes size before hide.
            */

            //if form already exist - delete previous data
            if(this.$form) {
                //todo: destroy prev data!
                //this.$form.destroy();
            }

            this.$form = $('
');

            //insert form into container body
            if(this.tip().is(this.innerCss)) {
                //for inline container
                this.tip().append(this.$form);
            } else {
                this.tip().find(this.innerCss).append(this.$form);
            }

            //render form
            this.renderForm();
        },

        /**
        Hides container with form
        @method hide()
        @param {string} reason Reason caused hiding. Can be save|cancel|onblur|nochange|undefined (=manual)
        **/
        hide: function(reason) {
            if(!this.tip() || !this.tip().is(':visible') || !this.$element.hasClass('editable-open')) {
                return;
            }

            this.$element.removeClass('editable-open');
            this.innerHide();

            /**
            Fired when container was hidden. It occurs on both save or cancel.
            **Note:** Bootstrap popover has own `hidden` event that now cannot be separated from x-editable's one.
            The workaround is to check `arguments.length` that is always `2` for x-editable.

            @event hidden
            @param {object} event event object
            @param {string} reason Reason caused hiding. Can be save|cancel|onblur|nochange|manual
            @example
            $('#username').on('hidden', function(e, reason) {
                if(reason === 'save' || reason === 'cancel') {
                    //auto-open next editable
                    $(this).closest('tr').next().find('.editable').editable('show');
                }
            });
            **/
            this.$element.triggerHandler('hidden', reason || 'manual');
        },

        /* internal show method. To be overwritten in child classes */
        innerShow: function () {

        },

        /* internal hide method. To be overwritten in child classes */
        innerHide: function () {

        },

        /**
        Toggles container visibility (show / hide)
        @method toggle()
        @param {boolean} closeAll Whether to close all other editable containers when showing this one. Default true.
        **/
        toggle: function(closeAll) {
            if(this.container() && this.tip() && this.tip().is(':visible')) {
                this.hide();
            } else {
                this.show(closeAll);
            }
        },

        /*
        Updates the position of container when content changed.
        @method setPosition()
        */
        setPosition: function() {
            //tbd in child class
        },

        save: function(e, params) {
            /**
            Fired when new value was submitted. You can use $(this).data('editableContainer') inside handler to access to editableContainer instance

            @event save
            @param {Object} event event object
            @param {Object} params additional params
            @param {mixed} params.newValue submitted value
            @param {Object} params.response ajax response
            @example
            $('#username').on('save', function(e, params) {
                //assuming server response: '{success: true}'
                var pk = $(this).data('editableContainer').options.pk;
                if(params.response && params.response.success) {
                    alert('value: ' + params.newValue + ' with pk: ' + pk + ' saved!');
                } else {
                    alert('error!');
                }
            });
            **/
            this.$element.triggerHandler('save', params);

            //hide must be after trigger, as saving value may require methods od plugin, applied to input
            this.hide('save');
        },

        /**
        Sets new option

        @method option(key, value)
        @param {string} key
        @param {mixed} value
        **/
        option: function(key, value) {
            this.options[key] = value;
            if(key in this.containerOptions) {
                this.containerOptions[key] = value;
                this.setContainerOption(key, value);
            } else {
                this.formOptions[key] = value;
                if(this.$form) {
                    this.$form.editableform('option', key, value);
                }
            }
        },

        setContainerOption: function(key, value) {
            this.call('option', key, value);
        },

        /**
        Destroys the container instance
        @method destroy()
        **/
        destroy: function() {
            this.hide();
            this.innerDestroy();
            this.$element.off('destroyed');
            this.$element.removeData('editableContainer');
        },

        /* to be overwritten in child classes */
        innerDestroy: function() {

        },

        /*
        Closes other containers except one related to passed element.
        Other containers can be cancelled or submitted (depends on onblur option)
        */
        closeOthers: function(element) {
            $('.editable-open').each(function(i, el){
                //do nothing with passed element and it's children
                if(el === element || $(el).find(element).length) {
                    return;
                }

                //otherwise cancel or submit all open containers
                var $el = $(el),
                ec = $el.data('editableContainer');

                if(!ec) {
                    return;
                }

                if(ec.options.onblur === 'cancel') {
                    $el.data('editableContainer').hide('onblur');
                } else if(ec.options.onblur === 'submit') {
                    $el.data('editableContainer').tip().find('form').submit();
                }
            });

        },

        /**
        Activates input of visible container (e.g. set focus)
        @method activate()
        **/
        activate: function() {
            if(this.tip && this.tip().is(':visible') && this.$form) {
               this.$form.data('editableform').input.activate();
            }
        }

    };

    /**
    jQuery method to initialize editableContainer.

    @method $().editableContainer(options)
    @params {Object} options
    @example
    $('#edit').editableContainer({
        type: 'text',
        url: '/post',
        pk: 1,
        value: 'hello'
    });
    **/
    $.fn.editableContainer = function (option) {
        var args = arguments;
        return this.each(function () {
            var $this = $(this),
            dataKey = 'editableContainer',
            data = $this.data(dataKey),
            options = typeof option === 'object' && option,
            Constructor = (options.mode === 'inline') ? Inline : Popup;

            if (!data) {
                $this.data(dataKey, (data = new Constructor(this, options)));
            }

            if (typeof option === 'string') { //call method
                data[option].apply(data, Array.prototype.slice.call(args, 1));
            }
        });
    };

    //store constructors
    $.fn.editableContainer.Popup = Popup;
    $.fn.editableContainer.Inline = Inline;

    //defaults
    $.fn.editableContainer.defaults = {
        /**
        Initial value of form input

        @property value
        @type mixed
        @default null
        @private
        **/
        value: null,
        /**
        Placement of container relative to element. Can be top|right|bottom|left. Not used for inline container.

        @property placement
        @type string
        @default 'top'
        **/
        placement: 'top',
        /**
        Whether to hide container on save/cancel.

        @property autohide
        @type boolean
        @default true
        @private
        **/
        autohide: true,
        /**
        Action when user clicks outside the container. Can be cancel|submit|ignore.
        Setting ignore allows to have several containers open.

        @property onblur
        @type string
        @default 'cancel'
        @since 1.1.1
        **/
        onblur: 'cancel',

        /**
        Animation speed (inline mode)
        @property anim
        @type string
        @default false
        **/
        anim: false,

        /**
        Mode of editable, can be `popup` or `inline`

        @property mode
        @type string
        @default 'popup'
        @since 1.4.0
        **/
        mode: 'popup'
    };

    /*
    * workaround to have 'destroyed' event to destroy popover when element is destroyed
    * see http://stackoverflow.com/questions/2200494/jquery-trigger-event-when-an-element-is-removed-from-the-dom
    */
    jQuery.event.special.destroyed = {
        remove: function(o) {
            if (o.handler) {
                o.handler();
            }
        }
    };

}(window.jQuery));
<commit_msg>add verbose error when js not included, ref #103<commit_after>/**
Attaches stand-alone container with editable-form to HTML element. Element is used only for positioning, value is not stored anywhere.

This method applied internally in $().editable(). You should subscribe on it's events (save / cancel) to get profit of it.

Final realization can be different: bootstrap-popover, jqueryui-tooltip, poshytip, inline-div. It depends on which js file you include.

Applied as jQuery method.

@class editableContainer
@uses editableform
**/
(function ($) {
    "use strict";

    var Popup = function (element, options) {
        this.init(element, options);
    };

    var Inline = function (element, options) {
        this.init(element, options);
    };

    //methods
    Popup.prototype = {
        containerName: null, //tbd in child class
        innerCss: null, //tbd in child class
        containerClass: 'editable-container editable-popup', //css class applied to container element
        init: function(element, options) {
            this.$element = $(element);
            //since 1.4.1 container do not use data-* directly as they already merged into options.
            this.options = $.extend({}, $.fn.editableContainer.defaults, options);
            this.splitOptions();

            //set scope of form callbacks to element
            this.formOptions.scope = this.$element[0];

            this.initContainer();

            //bind 'destroyed' listener to destroy container when element is removed from dom
            this.$element.on('destroyed', $.proxy(function(){
                this.destroy();
            }, this));

            //attach document handler to close containers on click / escape
            if(!$(document).data('editable-handlers-attached')) {
                //close all on escape
                $(document).on('keyup.editable', function (e) {
                    if (e.which === 27) {
                        $('.editable-open').editableContainer('hide');
                        //todo: return focus on element
                    }
                });

                //close containers when click outside
                //(mousedown could be better than click, it closes everything also on drag drop)
                $(document).on('click.editable', function(e) {
                    var $target = $(e.target), i,
                        exclude_classes = ['.editable-container',
                                           '.ui-datepicker-header',
                                           '.datepicker', //in inline mode datepicker is rendered into body
                                           '.modal-backdrop',
                                           '.bootstrap-wysihtml5-insert-image-modal',
                                           '.bootstrap-wysihtml5-insert-link-modal'
                                           ];

                    //check if element is detached. It occurs when clicking in bootstrap datepicker
                    if (!$.contains(document.documentElement, e.target)) {
                      return;
                    }

                    //for some reason FF 20 generates extra event (click) in select2 widget with e.target = document
                    //we need to filter it via construction below. See https://github.com/vitalets/x-editable/issues/199
                    //Possibly related to http://stackoverflow.com/questions/10119793/why-does-firefox-react-differently-from-webkit-and-ie-to-click-event-on-selec
                    if($target.is(document)) {
                       return;
                    }

                    //if click inside one of exclude classes --> no nothing
                    for(i=0; i<exclude_classes.length; i++) {
                         if($target.is(exclude_classes[i]) || $target.parents(exclude_classes[i]).length) {
                             return;
                         }
                    }

                    //close all open containers (except one - target)
                    Popup.prototype.closeOthers(e.target);
                });

                $(document).data('editable-handlers-attached', true);
            }
        },

        //split options on containerOptions and formOptions
        splitOptions: function() {
            this.containerOptions = {};
            this.formOptions = {};

            if(!$.fn[this.containerName]) {
                throw new Error(this.containerName + ' not found. Have you included corresponding js file?');
            }

            var cDef = $.fn[this.containerName].defaults;
            //keys defined in container defaults go to container, others go to form
            for(var k in this.options) {
              if(k in cDef) {
                 this.containerOptions[k] = this.options[k];
              } else {
                 this.formOptions[k] = this.options[k];
              }
            }
        },

        /*
        Returns jquery object of container
        @method tip()
        */
        tip: function() {
            return this.container() ? this.container().$tip : null;
        },

        /* returns container object */
        container: function() {
            return this.$element.data(this.containerDataName || this.containerName);
        },

        /* call native method of underlying container, e.g. this.$element.popover('method') */
        call: function() {
            this.$element[this.containerName].apply(this.$element, arguments);
        },

        initContainer: function(){
            this.call(this.containerOptions);
        },

        renderForm: function() {
            this.$form
            .editableform(this.formOptions)
            .on({
                save: $.proxy(this.save, this), //click on submit button (value changed)
                nochange: $.proxy(function(){ this.hide('nochange'); }, this), //click on submit button (value NOT changed)
                cancel: $.proxy(function(){ this.hide('cancel'); }, this), //click on calcel button
                show: $.proxy(this.setPosition, this), //re-position container every time form is shown (occurs each time after loading state)
                rendering: $.proxy(this.setPosition, this), //this allows to place container correctly when loading shown
                resize: $.proxy(this.setPosition, this), //this allows to re-position container when form size is changed
                rendered: $.proxy(function(){
                    /**
                    Fired when container is shown and form is rendered (for select will wait for loading dropdown options).
                    **Note:** Bootstrap popover has own `shown` event that now cannot be separated from x-editable's one.
                    The workaround is to check `arguments.length` that is always `2` for x-editable.

                    @event shown
                    @param {Object} event event object
                    @example
                    $('#username').on('shown', function(e, editable) {
                        editable.input.$input.val('overwriting value of input..');
                    });
                    **/
                    /*
                     TODO: added second param mainly to distinguish from bootstrap's shown event. It's a hotfix that will be solved in future versions via namespaced events.
                    */
                    this.$element.triggerHandler('shown', this);
                }, this)
            })
            .editableform('render');
        },

        /**
        Shows container with form
        @method show()
        @param {boolean} closeAll Whether to close all other editable containers when showing this one. Default true.
        **/
        /* Note: poshytip owerwrites this method totally! */
        show: function (closeAll) {
            this.$element.addClass('editable-open');
            if(closeAll !== false) {
                //close all open containers (except this)
                this.closeOthers(this.$element[0]);
            }

            //show container itself
            this.innerShow();
            this.tip().addClass(this.containerClass);

            /*
            Currently, form is re-rendered on every show.
            The main reason is that we dont know, what container will do with content when closed:
            remove(), detach() or just hide().

            Detaching form itself before hide and re-insert before show is good solution,
            but visually it looks ugly, as container changes size before hide.
            */

            //if form already exist - delete previous data
            if(this.$form) {
                //todo: destroy prev data!
                //this.$form.destroy();
            }

            this.$form = $('
');

            //insert form into container body
            if(this.tip().is(this.innerCss)) {
                //for inline container
                this.tip().append(this.$form);
            } else {
                this.tip().find(this.innerCss).append(this.$form);
            }

            //render form
            this.renderForm();
        },

        /**
        Hides container with form
        @method hide()
        @param {string} reason Reason caused hiding. Can be save|cancel|onblur|nochange|undefined (=manual)
        **/
        hide: function(reason) {
            if(!this.tip() || !this.tip().is(':visible') || !this.$element.hasClass('editable-open')) {
                return;
            }

            this.$element.removeClass('editable-open');
            this.innerHide();

            /**
            Fired when container was hidden. It occurs on both save or cancel.
            **Note:** Bootstrap popover has own `hidden` event that now cannot be separated from x-editable's one.
            The workaround is to check `arguments.length` that is always `2` for x-editable.

            @event hidden
            @param {object} event event object
            @param {string} reason Reason caused hiding. Can be save|cancel|onblur|nochange|manual
            @example
            $('#username').on('hidden', function(e, reason) {
                if(reason === 'save' || reason === 'cancel') {
                    //auto-open next editable
                    $(this).closest('tr').next().find('.editable').editable('show');
                }
            });
            **/
            this.$element.triggerHandler('hidden', reason || 'manual');
        },

        /* internal show method. To be overwritten in child classes */
        innerShow: function () {

        },

        /* internal hide method. To be overwritten in child classes */
        innerHide: function () {

        },

        /**
        Toggles container visibility (show / hide)
        @method toggle()
        @param {boolean} closeAll Whether to close all other editable containers when showing this one. Default true.
        **/
        toggle: function(closeAll) {
            if(this.container() && this.tip() && this.tip().is(':visible')) {
                this.hide();
            } else {
                this.show(closeAll);
            }
        },

        /*
        Updates the position of container when content changed.
        @method setPosition()
        */
        setPosition: function() {
            //tbd in child class
        },

        save: function(e, params) {
            /**
            Fired when new value was submitted. You can use $(this).data('editableContainer') inside handler to access to editableContainer instance

            @event save
            @param {Object} event event object
            @param {Object} params additional params
            @param {mixed} params.newValue submitted value
            @param {Object} params.response ajax response
            @example
            $('#username').on('save', function(e, params) {
                //assuming server response: '{success: true}'
                var pk = $(this).data('editableContainer').options.pk;
                if(params.response && params.response.success) {
                    alert('value: ' + params.newValue + ' with pk: ' + pk + ' saved!');
                } else {
                    alert('error!');
                }
            });
            **/
            this.$element.triggerHandler('save', params);

            //hide must be after trigger, as saving value may require methods od plugin, applied to input
            this.hide('save');
        },

        /**
        Sets new option

        @method option(key, value)
        @param {string} key
        @param {mixed} value
        **/
        option: function(key, value) {
            this.options[key] = value;
            if(key in this.containerOptions) {
                this.containerOptions[key] = value;
                this.setContainerOption(key, value);
            } else {
                this.formOptions[key] = value;
                if(this.$form) {
                    this.$form.editableform('option', key, value);
                }
            }
        },

        setContainerOption: function(key, value) {
            this.call('option', key, value);
        },

        /**
        Destroys the container instance
        @method destroy()
        **/
        destroy: function() {
            this.hide();
            this.innerDestroy();
            this.$element.off('destroyed');
            this.$element.removeData('editableContainer');
        },

        /* to be overwritten in child classes */
        innerDestroy: function() {

        },

        /*
        Closes other containers except one related to passed element.
        Other containers can be cancelled or submitted (depends on onblur option)
        */
        closeOthers: function(element) {
            $('.editable-open').each(function(i, el){
                //do nothing with passed element and it's children
                if(el === element || $(el).find(element).length) {
                    return;
                }

                //otherwise cancel or submit all open containers
                var $el = $(el),
                ec = $el.data('editableContainer');

                if(!ec) {
                    return;
                }

                if(ec.options.onblur === 'cancel') {
                    $el.data('editableContainer').hide('onblur');
                } else if(ec.options.onblur === 'submit') {
                    $el.data('editableContainer').tip().find('form').submit();
                }
            });

        },

        /**
        Activates input of visible container (e.g. set focus)
        @method activate()
        **/
        activate: function() {
            if(this.tip && this.tip().is(':visible') && this.$form) {
               this.$form.data('editableform').input.activate();
            }
        }

    };

    /**
    jQuery method to initialize editableContainer.

    @method $().editableContainer(options)
    @params {Object} options
    @example
    $('#edit').editableContainer({
        type: 'text',
        url: '/post',
        pk: 1,
        value: 'hello'
    });
    **/
    $.fn.editableContainer = function (option) {
        var args = arguments;
        return this.each(function () {
            var $this = $(this),
            dataKey = 'editableContainer',
            data = $this.data(dataKey),
            options = typeof option === 'object' && option,
            Constructor = (options.mode === 'inline') ? Inline : Popup;

            if (!data) {
                $this.data(dataKey, (data = new Constructor(this, options)));
            }

            if (typeof option === 'string') { //call method
                data[option].apply(data, Array.prototype.slice.call(args, 1));
            }
        });
    };

    //store constructors
    $.fn.editableContainer.Popup = Popup;
    $.fn.editableContainer.Inline = Inline;

    //defaults
    $.fn.editableContainer.defaults = {
        /**
        Initial value of form input

        @property value
        @type mixed
        @default null
        @private
        **/
        value: null,
        /**
        Placement of container relative to element. Can be top|right|bottom|left. Not used for inline container.

        @property placement
        @type string
        @default 'top'
        **/
        placement: 'top',
        /**
        Whether to hide container on save/cancel.

        @property autohide
        @type boolean
        @default true
        @private
        **/
        autohide: true,
        /**
        Action when user clicks outside the container. Can be cancel|submit|ignore.
        Setting ignore allows to have several containers open.

        @property onblur
        @type string
        @default 'cancel'
        @since 1.1.1
        **/
        onblur: 'cancel',

        /**
        Animation speed (inline mode)
        @property anim
        @type string
        @default false
        **/
        anim: false,

        /**
        Mode of editable, can be `popup` or `inline`

        @property mode
        @type string
        @default 'popup'
        @since 1.4.0
        **/
        mode: 'popup'
    };

    /*
    * workaround to have 'destroyed' event to destroy popover when element is destroyed
    * see http://stackoverflow.com/questions/2200494/jquery-trigger-event-when-an-element-is-removed-from-the-dom
    */
    jQuery.event.special.destroyed = {
        remove: function(o) {
            if (o.handler) {
                o.handler();
            }
        }
    };

}(window.jQuery));
<|endoftext|>


<commit_before>// model
export { default as annotationHelpers } from './model/annotationHelpers'
export { default as Annotation } from './model/Annotation'
export { default as BlockNode } from './model/BlockNode'
export { default as Container } from './model/Container'
export { default as ContainerAnnotation } from './model/ContainerAnnotation'
export { default as Document } from './model/Document'
export { default as documentHelpers } from './model/documentHelpers'
export { default as DocumentIndex } from './model/DocumentIndex'
export { default as DocumentNode } from './model/DocumentNode'
export { default as DocumentSession } from './model/DocumentSession'
export { default as DOMExporter } from './model/DOMExporter'
export { default as DOMImporter } from './model/DOMImporter'
export { default as Fragmenter } from './model/Fragmenter'
export { default as HTMLExporter } from './model/HTMLExporter'
export { default as HTMLImporter } from './model/HTMLImporter'
export { default as InlineNode } from './model/InlineNode'
export { default as JSONConverter } from './model/JSONConverter'
export { default as TextBlock } from './model/TextBlock'
export { default as TextNode } from './model/TextNode'
export { default as Selection } from './model/Selection'
export { default as XMLExporter } from './model/XMLExporter'
export { default as XMLImporter } from './model/XMLImporter'

// transformations
export {default as breakNode} from './model/transform/breakNode'
export {default as copySelection} from './model/transform/copySelection'
export {default as createAnnotation} from './model/transform/createAnnotation'
export {default as deleteCharacter} from './model/transform/deleteCharacter'
export {default as deleteNode} from './model/transform/deleteNode'
export {default as deleteSelection} from './model/transform/deleteSelection'
export {default as expandAnnotation} from './model/transform/expandAnnotation'
export {default as fuseAnnotation} from './model/transform/fuseAnnotation'
export {default as insertInlineNode} from './model/transform/insertInlineNode'
export {default as insertNode} from './model/transform/insertNode'
export {default as insertText} from './model/transform/insertText'
export {default as mergeNodes } from './model/transform/merge'
export {default as pasteContent } from './model/transform/paste'
export {default as replaceText } from './model/transform/replaceText'
export {default as switchTextType } from './model/transform/switchTextType'
export {default as truncateAnnotation } from './model/transform/truncateAnnotation'
export {default as updateAnnotations } from './model/transform/updateAnnotations'

// packages
export { default as BasePackage } from './packages/base/BasePackage'
export { default as BlockquotePackage } from './packages/blockquote/BlockquotePackage'
export { default as CodePackage } from './packages/code/CodePackage'
export { default as EmphasisPackage } from './packages/emphasis/EmphasisPackage'
export { default as HeadingPackage } from './packages/heading/HeadingPackage'
export { default as ImagePackage } from './packages/image/ImagePackage'
export { default as InlineWrapperPackage } from './packages/inline-wrapper/InlineWrapperPackage'
export { default as LinkPackage } from './packages/link/LinkPackage'
export { default as ListPackage } from './packages/list/ListPackage'
export { default as ParagraphPackage } from './packages/paragraph/ParagraphPackage'
export { default as PersistencePackage } from './packages/persistence/PersistencePackage'
export { default as ProseEditorPackage } from './packages/prose-editor/ProseEditorPackage'
export { default as StrongPackage } from './packages/strong/StrongPackage'
export { default as SubscriptPackage } from './packages/subscript/SubscriptPackage'
export { default as SuperscriptPackage } from './packages/superscript/SuperscriptPackage'
export { default as TablePackage } from './packages/table/TablePackage'

// ui
export { default as AnnotationCommand } from './ui/AnnotationCommand'
export { default as AnnotationComponent } from './ui/AnnotationComponent'
export { default as AnnotationTool } from './ui/AnnotationTool'
export { default as Button } from './ui/Button'
export { default as Command } from './ui/Command'
export { default as Component } from './ui/Component'
export { default as ContainerEditor } from './ui/ContainerEditor'
export { default as DefaultDOMElement } from './ui/DefaultDOMElement'
export { default as FontAwesomeIcon } from './ui/FontAwesomeIcon'
export { default as InlineNodeCommand } from './ui/InlineNodeCommand'
export { default as Input } from './ui/Input'
export { default as Layout } from './ui/Layout'
export { default as Modal } from './ui/Modal'
export { default as Overlay } from './ui/DefaultOverlay'
export { default as Prompt } from './ui/Prompt'
export { default as RenderingEngine } from './ui/RenderingEngine'
export { default as Router } from './ui/Router'
export { default as ScrollPane } from './ui/ScrollPane'
export { default as SplitPane } from './ui/SplitPane'
export { default as TextBlockComponent } from './ui/TextBlockComponent'
export { default as TextPropertyComponent } from './ui/TextPropertyComponent'
export { default as TextPropertyEditor } from './ui/TextPropertyEditor'
export { default as TOC } from './ui/TOC'
export { default as TOCProvider } from './ui/TOCProvider'
export { default as Tool } from './ui/Tool'
export { default as Toolbar } from './ui/Toolbar'

// util
export { default as ArrayIterator } from './util/ArrayIterator'
export { default as Configurator } from './util/AbstractConfigurator'
export { default as EventEmitter } from './util/EventEmitter'
export { default as Factory } from './util/Factory'
export { default as inBrowser } from './util/inBrowser'
export { default as makeMap } from './util/makeMap'
export { default as keys } from './util/keys'
export { default as oo } from './util/oo'
export { default as platform } from './util/platform'
export { default as Registry } from './util/Registry'
export { default as request } from './util/request'
export { default as substanceGlobals } from './util/substanceGlobals'
export { default as uuid } from './util/uuid'
<commit_msg>Export responsive application.<commit_after>// model
export { default as annotationHelpers } from './model/annotationHelpers'
export { default as Annotation } from './model/Annotation'
export { default as BlockNode } from './model/BlockNode'
export { default as Container } from './model/Container'
export { default as ContainerAnnotation } from './model/ContainerAnnotation'
export { default as Document } from './model/Document'
export { default as documentHelpers } from './model/documentHelpers'
export { default as DocumentIndex } from './model/DocumentIndex'
export { default as DocumentNode } from './model/DocumentNode'
export { default as DocumentSession } from './model/DocumentSession'
export { default as DOMExporter } from './model/DOMExporter'
export { default as DOMImporter } from './model/DOMImporter'
export { default as Fragmenter } from './model/Fragmenter'
export { default as HTMLExporter } from './model/HTMLExporter'
export { default as HTMLImporter } from './model/HTMLImporter'
export { default as InlineNode } from './model/InlineNode'
export { default as JSONConverter } from './model/JSONConverter'
export { default as TextBlock } from './model/TextBlock'
export { default as TextNode } from './model/TextNode'
export { default as Selection } from './model/Selection'
export { default as XMLExporter } from './model/XMLExporter'
export { default as XMLImporter } from './model/XMLImporter'

// transformations
export {default as breakNode} from './model/transform/breakNode'
export {default as copySelection} from './model/transform/copySelection'
export {default as createAnnotation} from './model/transform/createAnnotation'
export {default as deleteCharacter} from './model/transform/deleteCharacter'
export {default as deleteNode} from './model/transform/deleteNode'
export {default as deleteSelection} from './model/transform/deleteSelection'
export {default as expandAnnotation} from './model/transform/expandAnnotation'
export {default as fuseAnnotation} from './model/transform/fuseAnnotation'
export {default as insertInlineNode} from './model/transform/insertInlineNode'
export {default as insertNode} from './model/transform/insertNode'
export {default as insertText} from './model/transform/insertText'
export {default as mergeNodes } from './model/transform/merge'
export {default as pasteContent } from './model/transform/paste'
export {default as replaceText } from './model/transform/replaceText'
export {default as switchTextType } from './model/transform/switchTextType'
export {default as truncateAnnotation } from './model/transform/truncateAnnotation'
export {default as updateAnnotations } from './model/transform/updateAnnotations'

// packages
export { default as BasePackage } from './packages/base/BasePackage'
export { default as BlockquotePackage } from './packages/blockquote/BlockquotePackage'
export { default as CodePackage } from './packages/code/CodePackage'
export { default as EmphasisPackage } from './packages/emphasis/EmphasisPackage'
export { default as HeadingPackage } from './packages/heading/HeadingPackage'
export { default as ImagePackage } from './packages/image/ImagePackage'
export { default as InlineWrapperPackage } from './packages/inline-wrapper/InlineWrapperPackage'
export { default as LinkPackage } from './packages/link/LinkPackage'
export { default as ListPackage } from './packages/list/ListPackage'
export { default as ParagraphPackage } from './packages/paragraph/ParagraphPackage'
export { default as PersistencePackage } from './packages/persistence/PersistencePackage'
export { default as ProseEditorPackage } from './packages/prose-editor/ProseEditorPackage'
export { default as StrongPackage } from './packages/strong/StrongPackage'
export { default as SubscriptPackage } from './packages/subscript/SubscriptPackage'
export { default as SuperscriptPackage } from './packages/superscript/SuperscriptPackage'
export { default as TablePackage } from './packages/table/TablePackage'

// ui
export { default as AnnotationCommand } from './ui/AnnotationCommand'
export { default as AnnotationComponent } from './ui/AnnotationComponent'
export { default as AnnotationTool } from './ui/AnnotationTool'
export { default as Button } from './ui/Button'
export { default as Command } from './ui/Command'
export { default as Component } from './ui/Component'
export { default as ContainerEditor } from './ui/ContainerEditor'
export { default as DefaultDOMElement } from './ui/DefaultDOMElement'
export { default as FontAwesomeIcon } from './ui/FontAwesomeIcon'
export { default as InlineNodeCommand } from './ui/InlineNodeCommand'
export { default as Input } from './ui/Input'
export { default as Layout } from './ui/Layout'
export { default as Modal } from './ui/Modal'
export { default as Overlay } from './ui/DefaultOverlay'
export { default as Prompt } from './ui/Prompt'
export { default as RenderingEngine } from './ui/RenderingEngine'
export { default as ResponsiveApplication} from './ui/ResponsiveApplication'
export { default as Router } from './ui/Router'
export { default as ScrollPane } from './ui/ScrollPane'
export { default as SplitPane } from './ui/SplitPane'
export { default as TextBlockComponent } from './ui/TextBlockComponent'
export { default as TextPropertyComponent } from './ui/TextPropertyComponent'
export { default as TextPropertyEditor } from './ui/TextPropertyEditor'
export { default as TOC } from './ui/TOC'
export { default as TOCProvider } from './ui/TOCProvider'
export { default as Tool } from './ui/Tool'
export { default as Toolbar } from './ui/Toolbar'

// util
export { default as ArrayIterator } from './util/ArrayIterator'
export { default as Configurator } from './util/AbstractConfigurator'
export { default as EventEmitter } from './util/EventEmitter'
export { default as Factory } from './util/Factory'
export { default as inBrowser } from './util/inBrowser'
export { default as makeMap } from './util/makeMap'
export { default as keys } from './util/keys'
export { default as oo } from './util/oo'
export { default as platform } from './util/platform'
export { default as Registry } from './util/Registry'
export { default as request } from './util/request'
export { default as substanceGlobals } from './util/substanceGlobals'
export { default as uuid } from './util/uuid'<|endoftext|>


<commit_before>/** ---------------------------------------------------------------------------
 *  SonosJS
 *  Copyright 2014 Dennis Alund
 *  http://github.com/oddbit/sonosjs
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * ------------------------------------------------------------------------- */

define(function () {
        "use strict";

        /**
         * Defines a structured HTTP header object that allows you to query for header values.
         *
         * @param {object}      opts                    Object initialization configuration
         * @param {object[]}    [opts.headers]          Array of key value pair objects: {key: "", value: ""}
         * @param {string}      [opts.responseLine]     First line of the HTTP response (only if it is a HTTP response header)
         * @param {string}      [opts.requestLine]      First line of the HTTP request (only if it is a HTTP request header)
         * @returns {object} HTTP header object
         */
        function httpHeader(opts) {
            opts = opts || {};
            var that = {};

            var headers = opts.headers || [];

            /**
             * Get the header value for a specific header key.
             *
             * @param {string}  key     Case insensitive header name
             * @returns {string|null} The value of the specified header key (null if key is not present)
             */
            that.getHeaderValue = function (key) {
                var value = null;
                headers.forEach(function (headerEntry) {
                    if (value === null && key.toUpperCase() === headerEntry.key.toUpperCase()) {
                        value = headerEntry.value;
                    }
                });

                return value;
            };

            (function init() {
                if (opts.responseLine) {
                    var responseMatch = opts.responseLine.match(/HTTP\/1\.1\s+(\d+)\s+(.*)/i);
                    if (responseMatch && responseMatch.length === 3) {
                        that.code = Number(responseMatch[1]);
                        that.statusMessage = responseMatch[2].trim();
                    }
                }
                else if (opts.requestLine) {
                    var requestMatch = opts.requestLine.match(/(\w+)\s+(.*)\s+HTTP\/1\.1/i);
                    if (requestMatch && requestMatch.length === 3) {
                        that.action = requestMatch[1];
                        that.requestPath = requestMatch[2];
                    }
                }
            }());

            return that;
        }

        /**
         * Factory method that creates a HTTP header object from a portion of a raw HTTP request. It can either be only
         * the HTTP header part or a whole request with body (that will be ignored).
         *
         * @param {string}  data    HTTP request data
         * @returns {object} HTTP header object
         */
        httpHeader.fromData = function (data) {
            var dataParts = (data || "")
                .trim()
                .replace(/\r\n/g, "\n") // Normalize line endings
                .split("\n\n"); // Separate header from body
            if (!dataParts || dataParts.length === 0) {
                return null;
            }

            var opts = {headers: []};
            dataParts[0].split("\n").forEach(function (headerLine, lineNumber) {
                headerLine = headerLine.trim();
                if (lineNumber === 0) {
                    if (headerLine.indexOf("HTTP/1.1") === 0) {
                        opts.responseLine = headerLine;
                    }
                    else {
                        opts.requestLine = headerLine;
                    }
                }

                else if (lineNumber > 0 && headerLine.length > 0) {
                    var keyEnd = headerLine.indexOf(":");
                    opts.headers.push({
                        key: headerLine.substr(0, keyEnd).toUpperCase(),
                        value: headerLine.substr(keyEnd + 1).trim()
                    });
                }
            });

            return httpHeader(opts);
        };

        return httpHeader;
    }
);
<commit_msg>Implement methods for outgoing actions for HTTP header<commit_after>/** ---------------------------------------------------------------------------
 *  SonosJS
 *  Copyright 2014 Dennis Alund
 *  http://github.com/oddbit/sonosjs
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * ------------------------------------------------------------------------- */

define(function () {
        "use strict";

        /**
         * Defines a structured HTTP header object that allows you to query for header values.
         *
         * @param {object}      opts                    Object initialization configuration
         * @param {object[]}    [opts.headers]          Array of key value pair objects: {key: "", value: ""}
         * @param {string}      [opts.responseLine]     First line of the HTTP response (only if it is a HTTP response header)
         * @param {string}      [opts.requestLine]      First line of the HTTP request (only if it is a HTTP request header)
         * @returns {object} HTTP header object
         */
        function httpHeader(opts) {
            opts = opts || {};
            var that = {};

            var headers = opts.headers || [];

            /**
             * Get the header value for a specific header key.
             *
             * @param {string}  key     Case insensitive header name
             * @returns {string|null} The value of the specified header key (null if key is not present)
             */
            that.getHeaderValue = function (key) {
                var value = null;
                headers.forEach(function (headerEntry) {
                    if (value === null && key.toUpperCase() === headerEntry.key.toUpperCase()) {
                        value = headerEntry.value;
                    }
                });

                return value;
            };

            that.setHeaderValue = function (key, value) {
                var keyExists = false;
                headers.forEach(function (keyValuePair) {
                    if (keyValuePair.key === key) {
                        keyValuePair.value = value;
                        keyExists = true;
                    }
                });

                if (!keyExists) {
                    headers.push({key: key, value: value});
                }
            };

            that.toData = function () {
                var data = [];
                if (that.code && that.statusMessage) {
                    data.push("HTTP/1.1 " + that.code + " " + that.statusMessage);
                }
                else if (that.action && that.requestPath) {
                    data.push(that.action + " " + that.requestPath + " HTTP/1.1");
                }
                else {
                    return "";
                }

                headers.forEach(function (headerEntry) {
                    data.push(headerEntry.key.toUpperCase() + ": " + headerEntry.value);
                });

                return data.join("\n");
            };

            (function init() {
                if (opts.responseLine) {
                    var responseMatch = opts.responseLine.match(/HTTP\/1\.1\s+(\d+)\s+(.*)/i);
                    if (responseMatch && responseMatch.length === 3) {
                        that.code = Number(responseMatch[1]);
                        that.statusMessage = responseMatch[2].trim();
                    }
                }
                else if (opts.requestLine) {
                    var requestMatch = opts.requestLine.match(/(\w+)\s+(.*)\s+HTTP\/1\.1/i);
                    if (requestMatch && requestMatch.length === 3) {
                        that.action = requestMatch[1];
                        that.requestPath = requestMatch[2];
                    }
                }
            }());

            return that;
        }

        /**
         * Factory method that creates a HTTP header object from a portion of a raw HTTP request. It can either be only
         * the HTTP header part or a whole request with body (that will be ignored).
         *
         * @param {string}  data    HTTP request data
         * @returns {object} HTTP header object
         */
        httpHeader.fromData = function (data) {
            var dataParts = (data || "")
                .trim()
                .replace(/\r\n/g, "\n") // Normalize line endings
                .split("\n\n"); // Separate header from body
            if (!dataParts || dataParts.length === 0) {
                return null;
            }

            var opts = {headers: []};
            dataParts[0].split("\n").forEach(function (headerLine, lineNumber) {
                headerLine = headerLine.trim();
                if (lineNumber === 0) {
                    if (headerLine.indexOf("HTTP/1.1") === 0) {
                        opts.responseLine = headerLine;
                    }
                    else {
                        opts.requestLine = headerLine;
                    }
                }

                else if (lineNumber > 0 && headerLine.length > 0) {
                    var keyEnd = headerLine.indexOf(":");
                    opts.headers.push({
                        key: headerLine.substr(0, keyEnd).toUpperCase(),
                        value: headerLine.substr(keyEnd + 1).trim()
                    });
                }
            });

            return httpHeader(opts);
        };

        return httpHeader;
    }
);
<|endoftext|>


<commit_before>var Infinite=require("react-infinite");
var React=require("react");
var E=React.createElement;
var itemClassName="infinite-list-item";
var ListItem = React.createClass({
    getDefaultProps: function() {
        return {
            height: 50,
            lineHeight: "50px"
        }
    },
    render: function() {
        return E("div",{className:itemClassName, style:{height: this.props.height,lineHeight: this.props.lineHeight}},
            "List Item"+this.props.index);
    }
});

var VariableInfiniteList = React.createClass({
    getInitialState: function() {
        return {
        	elements:[],
        	elementData:[],
            elementHeights: [],//this.generateVariableElementHeights(100),
            isInfiniteLoading: false
        };
    }
    ,componentWillReceiveProps:function(nextProps) {
    	if (nextProps.onLoad && nextProps.onLoad!=this.props.onLoad) {
    		setTimeout(function(){
    			this.handleInfiniteLoad();
    		}.bind(this),1);

    	}
    }
    ,componentDidMount:function() {
    	this.handleInfiniteLoad();
    }
    ,generateEmptyElementHeights: function(number) {
        var heights = [];
        for (var i = 0; i < number; i++) heights.push(50);
        return heights;
    },
    calculateHeight:function(newdata) {
      	//var root=
      	var div=document.createElement("div");
      	div.className=itemClassName;
      	div.style.visibility="hidden";
      	document.body.appendChild(div);

      	var now=this.state.elements.length;
      	var newHeights=[];
      	var elements=this.state.elements;
      	for (var i=0;i<newdata.length;i++) {
      		var ele=E(this.props.itemClass,{key:now+i,index:now+i,text:newdata[i]});
      		elements.push(ele);
      		React.render(ele , div,function(comp){
      			var h=this.getDOMNode().offsetHeight;
      			newHeights.push(h);
      		});
      	}
        this.setState({
            	elements:elements,
            	elementData:this.state.elementData.concat(newdata),
                isInfiniteLoading: false,
                elementHeights: this.state.elementHeights.concat(newHeights)
        });
        document.body.removeChild(div);

    }
    ,handleInfiniteLoad: function() {
        var that = this;
        if (!this.props.onLoad) return;

        this.setState({ isInfiniteLoading: true});
        this.props.onLoad(this.state.elementHeights.length,function(newdata){
  			that.calculateHeight(newdata);
        });
    },
    elementInfiniteLoad: function() {
        return E("div",{className:itemClassName},"Loading...");
    },
    render: function() {
    	var itemClass=this.props.itemClass;
        var containerHeight=this.props.height;
        infiniteLoadBeginBottomOffset=containerHeight-50;
        return E(Infinite,{elementHeight:this.state.elementHeights,
                         containerHeight:containerHeight,
                         infiniteLoadBeginBottomOffset:infiniteLoadBeginBottomOffset,
                         onInfiniteLoad:this.handleInfiniteLoad,
                         loadingSpinnerDelegate:this.elementInfiniteLoad(),
                         isInfiniteLoading:this.state.isInfiniteLoading,
                         timeScrollStateLastsForAfterUserScrolls:1000}
                         ,this.state.elements);
    }
});

module.exports=VariableInfiniteList;<commit_msg>minor reformat<commit_after>var Infinite=require("react-infinite");
var React=require("react");
var E=React.createElement;
var itemClassName="infinite-list-item";
var ListItem = React.createClass({
    getDefaultProps: function() {
        return { height: 50,  lineHeight: "50px" }
    },
    render: function() {
        return E("div",{className:itemClassName, style:{height: this.props.height,lineHeight: this.props.lineHeight}},
            "List Item"+this.props.index);
    }
});

var VariableInfiniteList = React.createClass({
    displayName:"VariableInfiniteList"
    ,getInitialState: function() {
        return {
        	elements:[],
        	elementData:[],
            elementHeights: [],//this.generateVariableElementHeights(100),
            isInfiniteLoading: false
        };
    }
    ,componentWillReceiveProps:function(nextProps) {
    	if (nextProps.onLoad && nextProps.onLoad!=this.props.onLoad) {
    		setTimeout(function(){
    			this.handleInfiniteLoad();
    		}.bind(this),1);
    	}
    }
    ,componentDidMount:function() {
    	this.handleInfiniteLoad();
    }
    ,generateEmptyElementHeights: function(number) {
        var heights = [];
        for (var i = 0; i < number; i++) heights.push(50);
        return heights;
    },
    calculateHeight:function(newdata) {
      	var div=document.createElement("div");
      	div.className=itemClassName;
      	div.style.visibility="hidden";
      	document.body.appendChild(div);

      	var now=this.state.elements.length;
      	var newHeights=[];
      	var elements=this.state.elements;
      	for (var i=0;i<newdata.length;i++) {
      		var ele=E(this.props.itemClass,{key:now+i,index:now+i,text:newdata[i]});
      		elements.push(ele);
      		React.render(ele , div,function(comp){
      			var h=this.getDOMNode().offsetHeight;
      			newHeights.push(h);
      		});
      	}
        this.setState({
            	elements:elements,
            	elementData:this.state.elementData.concat(newdata),
                isInfiniteLoading: false,
                elementHeights: this.state.elementHeights.concat(newHeights)
        });
        document.body.removeChild(div);

    }
    ,handleInfiniteLoad: function() {
        var that = this;
        if (!this.props.onLoad) return;

        this.setState({ isInfiniteLoading: true});
        this.props.onLoad(this.state.elementHeights.length,function(newdata){
          that.calculateHeight(newdata);
        });
    },
    elementInfiniteLoad: function() {
        return E("div",{className:itemClassName},"Loading...");
    },
    render: function() {
    	var itemClass=this.props.itemClass;
        var containerHeight=this.props.height;
        infiniteLoadBeginBottomOffset=containerHeight-50;
        return E(Infinite
               ,{elementHeight:this.state.elementHeights,
                 containerHeight:containerHeight,
                 infiniteLoadBeginBottomOffset:infiniteLoadBeginBottomOffset,
                 onInfiniteLoad:this.handleInfiniteLoad,
                 loadingSpinnerDelegate:this.elementInfiniteLoad(),
                 isInfiniteLoading:this.state.isInfiniteLoading,
                 timeScrollStateLastsForAfterUserScrolls:1000}
               ,this.state.elements
        );
    }
});

module.exports=VariableInfiniteList;<|endoftext|>


<commit_before>/*
 * Copyright © 2012-2015, Paul Fischer, Intel Corporation. All rights reserved.
 * Please see the included README.md file for license terms and conditions.
 */

// This file is optional.
// It is only required if you choose to use the app.Ready event it generates.
// Note the reference that includes it in the index.html file.

/*
 * NOTE: In most cases, you can leave the code in this file alone and use it as is.
 *
 * The functions in this file are designed to reliably detect various "ready" events
 * within a variety of containers (Intel XDK "legacy" container, Cordova 3+ container,
 * standard browser, App Preview, Crosswalk, etc.). It "unifies" the commonly used
 * ready events and is very helpful for moving a "web app" to a "hybrid app" scenario.
 *
 * This file has no dependencies. It will generate a custom "app.Ready" event
 * that you should use once to start your application, rather than waiting on a
 * "device ready" or "document ready" or "window load" or similar events.
 *
 * You should not have to modify anything in this file to use it. See the example
 * index.html file that accompanies this file (in its sample repo location) for
 * recommendations on the best placement of this file relative to other files and
 * for recommendations regarding the loading of other JavaScript files.
 *
 * There are many console.log messages contained within this file. They can be used
 * to debug initialization problems and understand how the code in this file works.
 * It is highly recommended that you leave them in your app, they will not unduly
 * slow down or burden your application. The console.log messages in this file
 * will only display if you set the dev.Log variable to "true" (see below).
 *
 * There are many comments in this file and the accompanying index.html file.
 * Please read the comments within for details and for further documentation.
 *
 * BTW: "dev" means "device" in this context, not "develop," because it grew out
 * of a desire to build a more reliable and flexible "device ready" detector.
 */

/*jslint browser:true, devel:true, white:true, vars:true */
/*global $:false, intel:false, dev:false, performance:false */

window.dev = window.dev || {} ;         // might be predefined in index.html file...

// Use performance counter if it is available, otherwise, use milliseconds since 1970

if( window.performance && performance.now ) {
    dev.timeStamp = function() { return performance.now().toFixed(3) ; } ;
}
else {
    dev.timeStart = Date.now() ;        // feeble zero ref for relative time in ms
    dev.timeStamp = function() { return (Date.now() - dev.timeStart) ; } ;
}

// Set to "true" if you want the console.log messages to appear.
// Helpful for debugging and understanding how this file works.

dev.LOG = dev.LOG || false ;

dev.consoleLog = function() {       // only emits console.log messages if dev.LOG != false
    if( dev.LOG ) {
        var args = Array.prototype.slice.call(arguments, 0) ;
        console.log.apply(console, args) ;
    }
} ;

// Defines some delay constants used throughout for ready detections.
// Each should be smaller than the next; most cases should work as is.
// Lowering dev.BROWSER speeds up detection of browser scenario...
// ...at expense of possible false detects of browser environment...
// ...probably okay to go as low as 3000ms, depends on external libraries, etc.
// dev.NAME = dev.NAME || ## ; allows for override of values in index.html

if( typeof window.cordova !== "undefined" ) // if real cordova.js is present, we should detect a "deviceready"...
    dev.BROWSER = dev.BROWSER || 7000 ;     // ...best if >5 seconds when Cordova is expected to be present

dev.INSURANCE = dev.INSURANCE || 250 ;      // msecs, insurance on registering ready events detected
dev.WINDOW_LOAD = dev.WINDOW_LOAD || 500 ;  // msecs, for combating premature window load events
dev.BROWSER = dev.BROWSER || 500 ;          // msecs, non-Cordova apps don't care about "deviceready" events
dev.FAIL_SAFE = dev.FAIL_SAFE || 10000 ;    // msecs, if all else fails, this saves our bacon :-)

// Used to keep track of the moment when each of these items was triggered.
// Sorry for the weird names in the isDeviceReady structure, it's done for
// easier debugging and comparison of numbers when displayed in the CDT console.
// Only those that occurred will have a numberic value when inspected in CDT console.

dev.isDeviceReady = {                   // listed in approximate expected order
    a_startTime______:dev.timeStamp(),  // when we started execution of this module
    b_fnDocumentReady:false,            // detected document.readyState == "complete"
    c_cordova_ready__:false,            // detected cordova device ready event
    d_xdk_ready______:false,            // detected Intel XDK device ready event
    e_fnDeviceReady__:false,            // entered onDeviceReady()
    f_browser_ready__:false             // detected browser container
} ;

// Where the device ready event ultimately ends up, regardless of runtime environment.
// This function runs after the underlying device native code and browser is initialized.
// Usually not much needed here, just generates the unified app.Ready event.
// initDeviceReady() sets up the onDeviceReady*() functions which all try to trigger this.
// Technique works with Cordova, Crosswalk, App Preview, Intel XDK legacy and browser.

// NOTE: Customize this function, if necessary, for early low-level init of your app.

dev.onDeviceReady = function() {
    var fName = "dev.onDeviceReady():" ;
    dev.consoleLog(fName, "entry") ;

    // Useful for debug and understanding initialization flow.
    if( dev.isDeviceReady.e_fnDeviceReady__ ) {
        dev.consoleLog(fName, "function terminated") ;
        return ;
    }
    else {
        dev.isDeviceReady.e_fnDeviceReady__ = dev.timeStamp() ;
    }

// TODO: change this to use new custom events if I can confirm it works in all webviews.
// All device initialization is done; create and issue custom event named "app.Ready".
// Using deprecated custom events until I can confirm new method works in all webviews...

    var evt = document.createEvent("Event") ;
    evt.initEvent("app.Ready", false, false) ;
    document.dispatchEvent(evt) ;

    dev.consoleLog(fName, dev.isDeviceReady) ;
    dev.consoleLog(fName, "exit") ;
} ;

/*
 * The following is an excerpt from the 3.3.0 cordova.js file and is useful for understanding
 * Cordova events. The order of events during page load and Cordova startup is as follows:
 *
 * onDOMContentLoaded*         Internal event that is received when the web page is loaded and parsed.
 * onNativeReady*              Internal event that indicates the Cordova native side is ready.
 * onCordovaReady*             Internal event fired when all Cordova JavaScript objects have been created.
 * onDeviceReady*              User event fired to indicate that Cordova is ready
 * onResume                    User event fired to indicate a start/resume lifecycle event
 * onPause                     User event fired to indicate a pause lifecycle event
 * onDestroy*                  Internal event fired when app is being destroyed (User should use window.onunload event, not this one).
 *
 * The events marked with an * are sticky. Once they have fired, they will stay in the fired state.
 * All listeners that subscribe after the event is fired will be executed right away.
 *
 * The only Cordova events that user code should register for are:
 *      deviceready           Cordova native code is initialized and Cordova APIs can be called from JavaScript
 *      pause                 App has moved to background
 *      resume                App has returned to foreground
 *
 * Listeners can be registered as:
 *      document.addEventListener("deviceready", myDeviceReadyListener, false);
 *      document.addEventListener("resume", myResumeListener, false);
 *      document.addEventListener("pause", myPauseListener, false);
 *
 * The DOM lifecycle events should be used for saving and restoring state
 *      window.onload
 *      window.onunload
 *
 */

// The following is not fool-proof, we're mostly interested in detecting one
// or both events to insure device init is finished, detecting either will do.
// Even though the timing should indicate which container, it does not always work.

// If this event is called first, we should be in the Cordova container.

dev.onDeviceReadyCordova = function() {
    dev.isDeviceReady.c_cordova_ready__ = dev.timeStamp() ;
    var fName = "dev.onDeviceReadyCordova():" ;
    dev.consoleLog(fName, dev.isDeviceReady.c_cordova_ready__) ;
    window.setTimeout(dev.onDeviceReady, dev.INSURANCE) ;
} ;

// If this event is called first, we should be in the legacy Intel XDK container.

dev.onDeviceReadyXDK = function() {
    dev.isDeviceReady.d_xdk_ready______ = dev.timeStamp() ;
    var fName = "dev.onDeviceReadyXDK():" ;
    dev.consoleLog(fName, dev.isDeviceReady.d_xdk_ready______) ;
    window.setTimeout(dev.onDeviceReady, dev.INSURANCE) ;
} ;

// This is a faux onDeviceReady for browser scenario, for code symmetry and fail-safe.

dev.onDeviceReadyBrowser = function() {
    dev.isDeviceReady.f_browser_ready__ = dev.timeStamp() ;
    var fName = "dev.onDeviceReadyBrowser():" ;
    dev.consoleLog(fName, dev.isDeviceReady.f_browser_ready__) ;
    window.setTimeout(dev.onDeviceReady, dev.INSURANCE) ;
} ;

// Runs after document is loaded, and sets up wait for native (device) init to finish.
// If we are running in a browser we are ready to go when document is loaded, but...
// if we are running on a device we need to wait for the native code to finish its init.

dev.initDeviceReady = function() {
    var fName = "dev.initDeviceReady():" ;
    dev.consoleLog(fName, "entry") ;

    // Useful for debug and understanding initialization flow.
    if( dev.isDeviceReady.b_fnDocumentReady ) {
        dev.consoleLog(fName, "function terminated") ;
        return ;
    } else {
        dev.isDeviceReady.b_fnDocumentReady = dev.timeStamp() ;
    }

    document.addEventListener("intel.xdk.device.ready", dev.onDeviceReadyXDK, false) ;
    document.addEventListener("deviceready", dev.onDeviceReadyCordova, false) ;
    window.setTimeout(dev.onDeviceReadyBrowser, dev.BROWSER) ;

// Last one, above, is a fail-safe, in case we get no device ready event from Cordova.
// Cordova will timeout after five seconds, so we use a longer timeout to be conservative.
// Very end of this file includes a "fail-safe, fail-safe" in case all else fails!

// TODO: might want to double-check for Cordova deviceready, shouldn't be required...
// "if" logic (below) needs further investigation in Cordova, legacy and debug containers
// 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired.
// if( window.channel && channel.onCordovaReady && (channel.onCordovaReady.state === 2) )
//     dev.onDeviceReadyCordova() ;

    dev.consoleLog(fName, "navigator.vendor:", navigator.vendor) ;
    dev.consoleLog(fName, "navigator.platform:", navigator.platform) ;
    dev.consoleLog(fName, "navigator.userAgent:", navigator.userAgent) ;

    dev.consoleLog(fName, "exit") ;
} ;

// Wait for document ready before looking for device ready.
// This insures the app does not start running until DOM is ready and...
// ...makes it easier to deal with both in-browser and on-device scenarios and...
// ...makes it easier to init device-dependent and device-independent code in one place.

// NOTE: document.readyState seems to be more reliable, but seems not to be omnipresent.
// NOTE: Delay after "load" event is added because some webviews appear to trigger prematurely.
// NOTE: Looks like overkill, we are trying to capture any and all doc ready events.
// Parts derived from http://dean.edwards.name/weblog/2006/06/again/

if( document.readyState ) {
    dev.consoleLog("document.readyState:", document.readyState) ;
    document.onreadystatechange = function () {
        dev.consoleLog("document.readyState:", document.readyState) ;
        if( (document.readyState === "complete") || (document.readyState === "loaded") ) {
            dev.initDeviceReady() ;
        }
    } ;
}

if( document.addEventListener ) {
    dev.consoleLog("document.addEventListener:", dev.timeStamp()) ;
    document.addEventListener("DOMContentLoaded", dev.initDeviceReady, false) ;
}

if( window.addEventListener ) {
    dev.consoleLog("window.addEventListener:", dev.timeStamp()) ;
    window.addEventListener("load", dev.initDeviceReady, false) ;
}
else if( window.attachEvent ) {
    dev.consoleLog("window.attachEvent:", dev.timeStamp()) ;
    window.attachEvent("onload", dev.initDeviceReady) ;
}

// window.addEventListener("load", function(){window.setTimeout(dev.initDeviceReady,dev.WINDOW_LOAD);}.bind(dev), false) ;
// window.onload = function(){window.setTimeout(dev.initDeviceReady,dev.WINDOW_LOAD);}.bind(dev) ;
// window.onload = dev.initDeviceReady ;

window.setTimeout(dev.initDeviceReady, dev.FAIL_SAFE) ;     // fail-safe fail-safe, just in case we miss all events!
dev.consoleLog("end init-dev.js:", dev.timeStamp()) ;       // debug marker to indicate finished reading init-dev.js
<commit_msg>Update name of the license file reference and copyright.<commit_after>/*
 * Copyright © 2012-2016, Paul Fischer, Intel Corporation. All rights reserved.
 * Please see the included LICENSE.md file for license terms and conditions.
 */

// This file is optional.
// It is only required if you choose to use the app.Ready event it generates.
// Note the reference that includes it in the index.html file.

/*
 * NOTE: In most cases, you can leave the code in this file alone and use it as is.
 *
 * The functions in this file are designed to reliably detect various "ready" events
 * within a variety of containers (Intel XDK "legacy" container, Cordova 3+ container,
 * standard browser, App Preview, Crosswalk, etc.). It "unifies" the commonly used
 * ready events and is very helpful for moving a "web app" to a "hybrid app" scenario.
 *
 * This file has no dependencies. It will generate a custom "app.Ready" event
 * that you should use once to start your application, rather than waiting on a
 * "device ready" or "document ready" or "window load" or similar events.
 *
 * You should not have to modify anything in this file to use it. See the example
 * index.html file that accompanies this file (in its sample repo location) for
 * recommendations on the best placement of this file relative to other files and
 * for recommendations regarding the loading of other JavaScript files.
 *
 * There are many console.log messages contained within this file. They can be used
 * to debug initialization problems and understand how the code in this file works.
 * It is highly recommended that you leave them in your app, they will not unduly
 * slow down or burden your application. The console.log messages in this file
 * will only display if you set the dev.Log variable to "true" (see below).
 *
 * There are many comments in this file and the accompanying index.html file.
 * Please read the comments within for details and for further documentation.
 *
 * BTW: "dev" means "device" in this context, not "develop," because it grew out
 * of a desire to build a more reliable and flexible "device ready" detector.
 */

/*jslint browser:true, devel:true, white:true, vars:true */
/*global $:false, intel:false, dev:false, performance:false */

window.dev = window.dev || {} ;         // might be predefined in index.html file...

// Use performance counter if it is available, otherwise, use milliseconds since 1970

if( window.performance && performance.now ) {
    dev.timeStamp = function() { return performance.now().toFixed(3) ; } ;
}
else {
    dev.timeStart = Date.now() ;        // feeble zero ref for relative time in ms
    dev.timeStamp = function() { return (Date.now() - dev.timeStart) ; } ;
}

// Set to "true" if you want the console.log messages to appear.
// Helpful for debugging and understanding how this file works.

dev.LOG = dev.LOG || false ;

dev.consoleLog = function() {       // only emits console.log messages if dev.LOG != false
    if( dev.LOG ) {
        var args = Array.prototype.slice.call(arguments, 0) ;
        console.log.apply(console, args) ;
    }
} ;

// Defines some delay constants used throughout for ready detections.
// Each should be smaller than the next; most cases should work as is.
// Lowering dev.BROWSER speeds up detection of browser scenario...
// ...at expense of possible false detects of browser environment...
// ...probably okay to go as low as 3000ms, depends on external libraries, etc.
// dev.NAME = dev.NAME || ## ; allows for override of values in index.html

if( typeof window.cordova !== "undefined" ) // if real cordova.js is present, we should detect a "deviceready"...
    dev.BROWSER = dev.BROWSER || 7000 ;     // ...best if >5 seconds when Cordova is expected to be present

dev.INSURANCE = dev.INSURANCE || 250 ;      // msecs, insurance on registering ready events detected
dev.WINDOW_LOAD = dev.WINDOW_LOAD || 500 ;  // msecs, for combating premature window load events
dev.BROWSER = dev.BROWSER || 500 ;          // msecs, non-Cordova apps don't care about "deviceready" events
dev.FAIL_SAFE = dev.FAIL_SAFE || 10000 ;    // msecs, if all else fails, this saves our bacon :-)

// Used to keep track of the moment when each of these items was triggered.
// Sorry for the weird names in the isDeviceReady structure, it's done for
// easier debugging and comparison of numbers when displayed in the CDT console.
// Only those that occurred will have a numberic value when inspected in CDT console.

dev.isDeviceReady = {                   // listed in approximate expected order
    a_startTime______:dev.timeStamp(),  // when we started execution of this module
    b_fnDocumentReady:false,            // detected document.readyState == "complete"
    c_cordova_ready__:false,            // detected cordova device ready event
    d_xdk_ready______:false,            // detected Intel XDK device ready event
    e_fnDeviceReady__:false,            // entered onDeviceReady()
    f_browser_ready__:false             // detected browser container
} ;

// Where the device ready event ultimately ends up, regardless of runtime environment.
// This function runs after the underlying device native code and browser is initialized.
// Usually not much needed here, just generates the unified app.Ready event.
// initDeviceReady() sets up the onDeviceReady*() functions which all try to trigger this.
// Technique works with Cordova, Crosswalk, App Preview, Intel XDK legacy and browser.

// NOTE: Customize this function, if necessary, for early low-level init of your app.

dev.onDeviceReady = function() {
    var fName = "dev.onDeviceReady():" ;
    dev.consoleLog(fName, "entry") ;

    // Useful for debug and understanding initialization flow.
    if( dev.isDeviceReady.e_fnDeviceReady__ ) {
        dev.consoleLog(fName, "function terminated") ;
        return ;
    }
    else {
        dev.isDeviceReady.e_fnDeviceReady__ = dev.timeStamp() ;
    }

// TODO: change this to use new custom events if I can confirm it works in all webviews.
// All device initialization is done; create and issue custom event named "app.Ready".
// Using deprecated custom events until I can confirm new method works in all webviews...

    var evt = document.createEvent("Event") ;
    evt.initEvent("app.Ready", false, false) ;
    document.dispatchEvent(evt) ;

    dev.consoleLog(fName, dev.isDeviceReady) ;
    dev.consoleLog(fName, "exit") ;
} ;

/*
 * The following is an excerpt from the 3.3.0 cordova.js file and is useful for understanding
 * Cordova events. The order of events during page load and Cordova startup is as follows:
 *
 * onDOMContentLoaded*         Internal event that is received when the web page is loaded and parsed.
 * onNativeReady*              Internal event that indicates the Cordova native side is ready.
 * onCordovaReady*             Internal event fired when all Cordova JavaScript objects have been created.
 * onDeviceReady*              User event fired to indicate that Cordova is ready
 * onResume                    User event fired to indicate a start/resume lifecycle event
 * onPause                     User event fired to indicate a pause lifecycle event
 * onDestroy*                  Internal event fired when app is being destroyed (User should use window.onunload event, not this one).
 *
 * The events marked with an * are sticky. Once they have fired, they will stay in the fired state.
 * All listeners that subscribe after the event is fired will be executed right away.
 *
 * The only Cordova events that user code should register for are:
 *      deviceready           Cordova native code is initialized and Cordova APIs can be called from JavaScript
 *      pause                 App has moved to background
 *      resume                App has returned to foreground
 *
 * Listeners can be registered as:
 *      document.addEventListener("deviceready", myDeviceReadyListener, false);
 *      document.addEventListener("resume", myResumeListener, false);
 *      document.addEventListener("pause", myPauseListener, false);
 *
 * The DOM lifecycle events should be used for saving and restoring state
 *      window.onload
 *      window.onunload
 *
 */

// The following is not fool-proof, we're mostly interested in detecting one
// or both events to insure device init is finished, detecting either will do.
// Even though the timing should indicate which container, it does not always work.

// If this event is called first, we should be in the Cordova container.

dev.onDeviceReadyCordova = function() {
    dev.isDeviceReady.c_cordova_ready__ = dev.timeStamp() ;
    var fName = "dev.onDeviceReadyCordova():" ;
    dev.consoleLog(fName, dev.isDeviceReady.c_cordova_ready__) ;
    window.setTimeout(dev.onDeviceReady, dev.INSURANCE) ;
} ;

// If this event is called first, we should be in the legacy Intel XDK container.

dev.onDeviceReadyXDK = function() {
    dev.isDeviceReady.d_xdk_ready______ = dev.timeStamp() ;
    var fName = "dev.onDeviceReadyXDK():" ;
    dev.consoleLog(fName, dev.isDeviceReady.d_xdk_ready______) ;
    window.setTimeout(dev.onDeviceReady, dev.INSURANCE) ;
} ;

// This is a faux onDeviceReady for browser scenario, for code symmetry and fail-safe.

dev.onDeviceReadyBrowser = function() {
    dev.isDeviceReady.f_browser_ready__ = dev.timeStamp() ;
    var fName = "dev.onDeviceReadyBrowser():" ;
    dev.consoleLog(fName, dev.isDeviceReady.f_browser_ready__) ;
    window.setTimeout(dev.onDeviceReady, dev.INSURANCE) ;
} ;

// Runs after document is loaded, and sets up wait for native (device) init to finish.
// If we are running in a browser we are ready to go when document is loaded, but...
// if we are running on a device we need to wait for the native code to finish its init.

dev.initDeviceReady = function() {
    var fName = "dev.initDeviceReady():" ;
    dev.consoleLog(fName, "entry") ;

    // Useful for debug and understanding initialization flow.
    if( dev.isDeviceReady.b_fnDocumentReady ) {
        dev.consoleLog(fName, "function terminated") ;
        return ;
    } else {
        dev.isDeviceReady.b_fnDocumentReady = dev.timeStamp() ;
    }

    document.addEventListener("intel.xdk.device.ready", dev.onDeviceReadyXDK, false) ;
    document.addEventListener("deviceready", dev.onDeviceReadyCordova, false) ;
    window.setTimeout(dev.onDeviceReadyBrowser, dev.BROWSER) ;

// Last one, above, is a fail-safe, in case we get no device ready event from Cordova.
// Cordova will timeout after five seconds, so we use a longer timeout to be conservative.
// Very end of this file includes a "fail-safe, fail-safe" in case all else fails!

// TODO: might want to double-check for Cordova deviceready, shouldn't be required...
// "if" logic (below) needs further investigation in Cordova, legacy and debug containers
// 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired.
// if( window.channel && channel.onCordovaReady && (channel.onCordovaReady.state === 2) )
//     dev.onDeviceReadyCordova() ;

    dev.consoleLog(fName, "navigator.vendor:", navigator.vendor) ;
    dev.consoleLog(fName, "navigator.platform:", navigator.platform) ;
    dev.consoleLog(fName, "navigator.userAgent:", navigator.userAgent) ;

    dev.consoleLog(fName, "exit") ;
} ;

// Wait for document ready before looking for device ready.
// This insures the app does not start running until DOM is ready and...
// ...makes it easier to deal with both in-browser and on-device scenarios and...
// ...makes it easier to init device-dependent and device-independent code in one place.

// NOTE: document.readyState seems to be more reliable, but seems not to be omnipresent.
// NOTE: Delay after "load" event is added because some webviews appear to trigger prematurely.
// NOTE: Looks like overkill, we are trying to capture any and all doc ready events.
// Parts derived from http://dean.edwards.name/weblog/2006/06/again/

if( document.readyState ) {
    dev.consoleLog("document.readyState:", document.readyState) ;
    document.onreadystatechange = function () {
        dev.consoleLog("document.readyState:", document.readyState) ;
        if( (document.readyState === "complete") || (document.readyState === "loaded") ) {
            dev.initDeviceReady() ;
        }
    } ;
}

if( document.addEventListener ) {
    dev.consoleLog("document.addEventListener:", dev.timeStamp()) ;
    document.addEventListener("DOMContentLoaded", dev.initDeviceReady, false) ;
}

if( window.addEventListener ) {
    dev.consoleLog("window.addEventListener:", dev.timeStamp()) ;
    window.addEventListener("load", dev.initDeviceReady, false) ;
}
else if( window.attachEvent ) {
    dev.consoleLog("window.attachEvent:", dev.timeStamp()) ;
    window.attachEvent("onload", dev.initDeviceReady) ;
}

// window.addEventListener("load", function(){window.setTimeout(dev.initDeviceReady,dev.WINDOW_LOAD);}.bind(dev), false) ;
// window.onload = function(){window.setTimeout(dev.initDeviceReady,dev.WINDOW_LOAD);}.bind(dev) ;
// window.onload = dev.initDeviceReady ;

window.setTimeout(dev.initDeviceReady, dev.FAIL_SAFE) ;     // fail-safe fail-safe, just in case we miss all events!
dev.consoleLog("end init-dev.js:", dev.timeStamp()) ;       // debug marker to indicate finished reading init-dev.js
<|endoftext|>