<commit_before>Modularity = Modularity || {};
Modularity.Editor = Modularity.Editor || {};

Modularity.Editor.Module = (function ($) {

    var initCompleted = false;

    /**
     * Object to create Thickbox querystring from
     * @type {Object}
     */
    var thickboxOptions = {
        is_thickbox: true,
        //TB_iframe: true,
        //width: 980,
        //height: 600
    };

    var editingModule = false;

    function Module() {
        $(function(){
            if (pagenow == 'admin_page_modularity-editor') {
                this.handleEvents();
                this.loadModules(modularity_post_id);
            }
        }.bind(this));
    }

    /**
     * Loads saved modules and adds them to the page
     * @param  {integer} postId The post id to load modules from
     * @return {void}
     */
    Module.prototype.loadModules = function (postId) {
        var request = {
            action: 'get_post_modules',
            id: postId
        };

        $.post(ajaxurl, request, function (response) {
            $.each(response, function (sidebar, modules) {
                var sidebarElement = $('.modularity-sidebar-area[data-area-id="' + sidebar + '"]');

                $.each(modules.modules, function (key, data) {
                    this.addModule(sidebarElement, data.post_type, data.post_type_name, data.post_title, data.ID, data.hidden);
                }.bind(this));

            }.bind(this));

            this.initCompleted = true;

        }.bind(this), 'json');
    };

    /**
     * Check editing module
     * @return {boolean/string}
     */
    Module.prototype.isEditingModule = function () {
        return editingModule;
    };

    /**
     * Generates a thickbox url to open a thickbox in correct mode
     * @param  {string} action Should be "add" or "edit"
     * @param  {object} data   Should contain additional data (for now supports "postId" and "postType")
     * @return {string}        Thickbox url
     */
    Module.prototype.getThickBoxUrl = function (action, data) {
        var base = '';
        var querystring = {};

        switch (action) {
            case 'add':
                base = 'post-new.php';
                break;

            case 'edit':
                base = 'post.php';
                break;
        }

        if (typeof data.postId == 'number') {
            querystring.post = data.postId;
            querystring.action = 'edit';
        }

        if (typeof data.postType == 'string') {
            querystring.post_type = data.postType;
        }

        return admin_url + base + '?' + $.param(querystring) + '&' + $.param(thickboxOptions);
    };

    /**
     * Adds a module "row" to the target placeholder
     * @param {selector} target   The target selector
     * @param {string} moduleId   The module id slug
     * @param {string} moduleName The module name
     */
    Module.prototype.addModule = function (target, moduleId, moduleName, moduleTitle, postId, hidden) {
        moduleTitle = (typeof moduleTitle != 'undefined') ? ': ' + moduleTitle : '';
        postId = (typeof postId != 'undefined') ? postId : '';

        var thickboxUrl = this.getThickBoxUrl('add', {
            postType: moduleId
        });

        Modularity.Editor.Thickbox.postAction = 'add';

        if (postId) {
            thickboxUrl = this.getThickBoxUrl('edit', {
                postId: postId
            });

            Modularity.Editor.Thickbox.postAction = 'edit';
        }

        var isHidden = '';
        if (hidden) {
            isHidden = 'checked';
        }

        var sidebarId = $(target).data('area-id');

        var itemRowId = Modularity.Helpers.uuid();

        $(target).append('\

\
            	\
                	\
	                \
                        ' + moduleName + '\
                        ' + moduleTitle + '\
                        \
                            <input type="hidden" name="modularity_modules[' + sidebarId + '][' + itemRowId + '][hidden]" value="false" />\
                            <input type="checkbox" name="modularity_modules[' + sidebarId + '][' + itemRowId + '][hidden]" value="true" ' + isHidden + ' />\
                            ' + modularityAdminLanguage.langhide + '\
                        \
	                \
	                \
	                    ' + modularityAdminLanguage.langedit + '\
	                    ' + modularityAdminLanguage.langimport + '\
	                    ' + modularityAdminLanguage.langremove + '\
	                \
	                <input type="hidden" name="modularity_modules[' + sidebarId + '][' + itemRowId + '][postid]" class="modularity-js-module-id" value="' + postId + '" required>\
                \

\
        ');

        $('.modularity-js-sortable').sortable('refresh');
    };

    /**
     * Updates a module "row" after editing the module post
     * @param  {DOM} module    Module dom element
     * @param  {object} data   The data
     * @return {void}
     */
    Module.prototype.updateModule = function (module, data) {
        // Href
        module.find('a.modularity-js-thickbox-open').attr('href', this.getThickBoxUrl('edit', {
            postId: data.post_id
        }));

        // Post id input
        module.find('input.modularity-js-module-id').val(data.post_id).change();

        // Post title
        module.find('.modularity-module-title').text(': ' + data.title);
    };

    /**
     * Removes a module "row" from the placeholder
     * @param  {DOM Element} module The (to be removed) module's dom element
     * @return {void}
     */
    Module.prototype.removeModule = function (module) {
        if (confirm(modularityAdminLanguage.actionRemove)) {
            module.remove();
        }
    };

    /**
     * Removes a module "row" from the placeholder
     * @param  {DOM Element} module The (to be removed) module's dom element
     * @return {void}
     */
    Module.prototype.hideModule = function (module) {

    };

    /**
     * Handle events
     * @return {void}
     */
    Module.prototype.handleEvents = function () {

        // Trash icon
        $(document).on('click', '.modularity-module-remove', function (e) {
            e.preventDefault();
            var target = $(e.target).closest('li');
            this.removeModule(target);
        }.bind(this));

        //Import
        $(document).on('click', '.modularity-js-thickbox-import', function (e) {
            e.preventDefault();
            alert("Import not done, still in beta.");
        });

        // Edit
        $(document).on('click', '.modularity-js-thickbox-open', function (e) {
            e.preventDefault();

            var el = $(e.target).closest('a');
            if (el.attr('href').indexOf('post.php') > -1) {
                Modularity.Editor.Thickbox.postAction = 'edit';
            }

            editingModule = $(e.target).closest('li');

            Modularity.Prompt.Modal.open($(e.target).closest('a').attr('href'));
        }.bind(this));
    };

    return new Module();

})(jQuery);
<commit_msg>Fixes #7 - Show "hide" state correcly<commit_after>Modularity = Modularity || {};
Modularity.Editor = Modularity.Editor || {};

Modularity.Editor.Module = (function ($) {

    var initCompleted = false;

    /**
     * Object to create Thickbox querystring from
     * @type {Object}
     */
    var thickboxOptions = {
        is_thickbox: true,
        //TB_iframe: true,
        //width: 980,
        //height: 600
    };

    var editingModule = false;

    function Module() {
        $(function(){
            if (pagenow == 'admin_page_modularity-editor') {
                this.handleEvents();
                this.loadModules(modularity_post_id);
            }
        }.bind(this));
    }

    /**
     * Loads saved modules and adds them to the page
     * @param  {integer} postId The post id to load modules from
     * @return {void}
     */
    Module.prototype.loadModules = function (postId) {
        var request = {
            action: 'get_post_modules',
            id: postId
        };

        $.post(ajaxurl, request, function (response) {
            $.each(response, function (sidebar, modules) {
                var sidebarElement = $('.modularity-sidebar-area[data-area-id="' + sidebar + '"]');

                $.each(modules.modules, function (key, data) {
                    this.addModule(sidebarElement, data.post_type, data.post_type_name, data.post_title, data.ID, data.hidden);
                }.bind(this));

            }.bind(this));

            this.initCompleted = true;

        }.bind(this), 'json');
    };

    /**
     * Check editing module
     * @return {boolean/string}
     */
    Module.prototype.isEditingModule = function () {
        return editingModule;
    };

    /**
     * Generates a thickbox url to open a thickbox in correct mode
     * @param  {string} action Should be "add" or "edit"
     * @param  {object} data   Should contain additional data (for now supports "postId" and "postType")
     * @return {string}        Thickbox url
     */
    Module.prototype.getThickBoxUrl = function (action, data) {
        var base = '';
        var querystring = {};

        switch (action) {
            case 'add':
                base = 'post-new.php';
                break;

            case 'edit':
                base = 'post.php';
                break;
        }

        if (typeof data.postId == 'number') {
            querystring.post = data.postId;
            querystring.action = 'edit';
        }

        if (typeof data.postType == 'string') {
            querystring.post_type = data.postType;
        }

        return admin_url + base + '?' + $.param(querystring) + '&' + $.param(thickboxOptions);
    };

    /**
     * Adds a module "row" to the target placeholder
     * @param {selector} target   The target selector
     * @param {string} moduleId   The module id slug
     * @param {string} moduleName The module name
     */
    Module.prototype.addModule = function (target, moduleId, moduleName, moduleTitle, postId, hidden) {
        moduleTitle = (typeof moduleTitle != 'undefined') ? ': ' + moduleTitle : '';
        postId = (typeof postId != 'undefined') ? postId : '';

        var thickboxUrl = this.getThickBoxUrl('add', {
            postType: moduleId
        });

        Modularity.Editor.Thickbox.postAction = 'add';

        if (postId) {
            thickboxUrl = this.getThickBoxUrl('edit', {
                postId: postId
            });

            Modularity.Editor.Thickbox.postAction = 'edit';
        }

        var isHidden = '';
        if (hidden == true) {
            isHidden = 'checked';
        }

        var sidebarId = $(target).data('area-id');
        var itemRowId = Modularity.Helpers.uuid();

        $(target).append('\

\
            	\
                	\
	                \
                        ' + moduleName + '\
                        ' + moduleTitle + '\
                        \
                            <input type="hidden" name="modularity_modules[' + sidebarId + '][' + itemRowId + '][hidden]" value="false" />\
                            <input type="checkbox" name="modularity_modules[' + sidebarId + '][' + itemRowId + '][hidden]" value="true" ' + isHidden + ' />\
                            ' + modularityAdminLanguage.langhide + '\
                        \
	                \
	                \
	                    ' + modularityAdminLanguage.langedit + '\
	                    ' + modularityAdminLanguage.langimport + '\
	                    ' + modularityAdminLanguage.langremove + '\
	                \
	                <input type="hidden" name="modularity_modules[' + sidebarId + '][' + itemRowId + '][postid]" class="modularity-js-module-id" value="' + postId + '" required>\
                \

\
        ');

        $('.modularity-js-sortable').sortable('refresh');
    };

    /**
     * Updates a module "row" after editing the module post
     * @param  {DOM} module    Module dom element
     * @param  {object} data   The data
     * @return {void}
     */
    Module.prototype.updateModule = function (module, data) {
        // Href
        module.find('a.modularity-js-thickbox-open').attr('href', this.getThickBoxUrl('edit', {
            postId: data.post_id
        }));

        // Post id input
        module.find('input.modularity-js-module-id').val(data.post_id).change();

        // Post title
        module.find('.modularity-module-title').text(': ' + data.title);
    };

    /**
     * Removes a module "row" from the placeholder
     * @param  {DOM Element} module The (to be removed) module's dom element
     * @return {void}
     */
    Module.prototype.removeModule = function (module) {
        if (confirm(modularityAdminLanguage.actionRemove)) {
            module.remove();
        }
    };

    /**
     * Removes a module "row" from the placeholder
     * @param  {DOM Element} module The (to be removed) module's dom element
     * @return {void}
     */
    Module.prototype.hideModule = function (module) {

    };

    /**
     * Handle events
     * @return {void}
     */
    Module.prototype.handleEvents = function () {

        // Trash icon
        $(document).on('click', '.modularity-module-remove', function (e) {
            e.preventDefault();
            var target = $(e.target).closest('li');
            this.removeModule(target);
        }.bind(this));

        //Import
        $(document).on('click', '.modularity-js-thickbox-import', function (e) {
            e.preventDefault();
            alert("Import not done, still in beta.");
        });

        // Edit
        $(document).on('click', '.modularity-js-thickbox-open', function (e) {
            e.preventDefault();

            var el = $(e.target).closest('a');
            if (el.attr('href').indexOf('post.php') > -1) {
                Modularity.Editor.Thickbox.postAction = 'edit';
            }

            editingModule = $(e.target).closest('li');

            Modularity.Prompt.Modal.open($(e.target).closest('a').attr('href'));
        }.bind(this));
    };

    return new Module();

})(jQuery);
<|endoftext|>


<commit_before>//*@public
/**
	_enyo.DataList_ is an [enyo.DataRepeater](#enyo.DataRepeater) that employs a
	paginated scrolling scheme to enhance performance with larger datasets. The
	data is provided to the DataList by an [enyo.Collection](#enyo.Collection) set
	as the value of its _collection_ property.

	Note that care should be taken when deciding how to lay out the list's
	children. When there are a large number of child elements, the layout process
	can be taxing and non-performant for the browser. Avoid	dynamically-updated
	layouts that require lots of calculations each time the data in a view is
	updated. Try to use CSS whenever possible.

	While paging through data, _enyo.DataList_ emits the _paging_ event, which
	allows you to make updates on a per-page basis, as necessary. You may register
	for this event by calling _addListener()_ and specifying the event, along with
	a callback method.

	The callback method is passed a reference to the _enyo.DataList_, the name of
	the event (_"paging"_), and a hash with the properties _start_, _end_, and
	_action_, referring to the lowest active index in the dataset, the highest
	active index, and the action that triggered the paging, respectively. The
	value of _action_ value may be either _"scroll"_ or _"reset"_.
*/
enyo.kind({
	name: "enyo.DataList",
	kind: enyo.DataRepeater,
	/**
		_enyo.DataList_ places its rows inside of a scroller. Any configurable
		options of _enyo.Scroller_ may be placed in this hash; their values will be
		set accordingly on this list's scroller. If no options are specified, the
		default _enyo.Scroller_ settings are used.
	*/
	scrollerOptions: null,
	/**
		The paging orientation. Valid values are _"vertical"_ and _"horizontal"_.
		This property will be mapped to a particular strategy governing how the list
		will flow.
	*/
	orientation: "vertical",
	/**
		This is typically handled automatically, but some platforms may benefit from
		having a larger or smaller value here. If there is a number here, it will be
		multiplied by the available viewport size (depending on orientation) to
		determine the minimum page size. The page size is directly related to the
		number of controls that are generated at any given time (and that
		subsequently need updating) whenever paging occurs. This number may be any
		rational number greater than _1.2_.
	*/
	pageSizeMultiplier: null,
	/**
		It is helpful for performance if the list doesn't need to guess at the size of
		the children. In cases where all children are a fixed height/width (depending on
		the orientation of the list) you may explicitly define that value for the list
		to use and bypass much of its guesswork. This value is a number that will be interpreted
		in pixels and applied to the primary size depending on orientation: _height_ when
		_vertical_ and _width_ when _horizontal_. Note this value is not applied to the
		children via CSS by the list.
	*/
	fixedChildSize: null,
	/**
		To disable the default smoothing-transitions (for supported platforms), set
		this flag to false.
	*/
	allowTransitions: true,
	/**
		Because some systems perform poorly on initialization, there is a delay when
		we attempt to actually draw the contents of a DataList. Usually, you will
		not need to adjust this value (expressed in milliseconds). If _renderDelay_
		is null, there will be no delay and rendering will take place synchronously.
		If _renderDelay_ is set to 0, rendering will be done asynchronously.
	*/
	renderDelay: 250,
	/**
		Completely resets the current list such that it scrolls to the top of the
		scrollable region and regenerates all of its children. This is typically
		necessary only on initialization or if the entire dataset has been swapped
		out.
	*/
	reset: function () {
		if (this.get("absoluteShowing")) {
			// we can only reset if we've already rendered
			if (this.generated && this.$.scroller.generated) {
				this.delegate.reset(this);
			}
		} else {
			this._addToShowingQueue("reset", this.reset);
		}
	},
	/**
		Unlike _reset()_, which tears down and regenerates the entire list, this
		method attempts to refresh the pages as they are against the current
		dataset. This is much cheaper to call than _reset()_, but is primarily used
		internally.
	*/
	refresh: function (c, e) {
		if (this.get("absoluteShowing")) {
			if (this.hasRendered) {
				this.delegate.refresh(this);
			}
		} else {
			this._addToShowingQueue("refresh", this.refresh);
		}
	},
	/**
		Pass in an integer within the bounds of the lists's collection to scroll to
		the position of that index in the list.
	*/
	scrollToIndex: function (idx) {
		var len = this.collection? this.collection.length: 0;
		if (idx >= 0 && idx < len) {
			if (this.get("absoluteShowing")) {
				this.delegate.scrollToIndex(this, idx);
			} else {
				this._addToShowingQueue("scrollToIndex", function () {
					this.delegate.scrollToIndex(this, idx);
				});
			}
		}
	},
	//*@protected
	constructor: enyo.inherit(function (sup) {
		return function () {
			sup.apply(this, arguments);
			this.metrics       = {};
			this.metrics.pages = {};
			if (this.pageSizeMultiplier !== null && !isNaN(this.pageSizeMultiplier)) {
				this.pageSizeMultiplier = Math.max(1.2, this.pageSizeMultiplier);
			}
		};
	}),
	create: enyo.inherit(function (sup) {
		return function () {
			// if we can, we use transitions
			this.allowTransitionsChanged();
			// map the selected strategy to the correct delegate for operations
			// on the list, default to _vertical_ if none is provided or if it
			// could not be found
			this.delegate = this.ctor.delegates[this.orientation] || this.base.delegates.vertical;
			// if the delegate has an initialization routine execute it now before the
			// container and children are rendered
			if (this.delegate.initList) {
				this.delegate.initList(this);
			}
			sup.apply(this, arguments);
			// initialize the _pages_ array and add the pages to it
			this.pages = [this.$.page1, this.$.page2];
		};
	}),
	render: enyo.inherit(function (sup) {
		return function () {
			this.$.scroller.canGenerate = false;
			this.$.scroller.teardownRender();
			sup.apply(this, arguments);
		};
	}),
	/**
		Attempts to perform initialization. There are only a few basic startup
		paths, but we need to be aware of what they are:

		* The view is rendered, it has a collection, and the collection has data.
		* The view is rendered, it has a collection with no data, and data is added
			later.
		* The view is rendered, but has no collection.

		Once the list itself is rendered, we check to see if we have a collection;
		if so, do we have any data to start rendering the rest of the list?
		Ultimately, the implementation decisions are decided by the delegate
		strategy.
	*/
	rendered: function () {
		if (this.get("absoluteShowing")) {
			// actually rendering a datalist can be taxing for some systems so
			// we arbitrarily delay showing for a fixed amount of time unless delay is
			// null in which case it will be executed immediately
			var startup = function () {
				// now that the base list is rendered, we can safely generate our scroller
				this.$.scroller.canGenerate = true;
				this.$.scroller.render();
				// and now we hand over the action to our strategy to let it initialize the
				// way it needs to
				this.delegate.rendered(this);
				this.hasRendered = true;
				// now add our class to adjust visibility (if no overridden)
				this.addClass("rendered");
				if (this.didRender) {
					this.didRender();
				}
			};
			if (this.renderDelay === null) {
				startup.call(this);
			} else {
				this.startJob("rendering", startup, this.renderDelay);
				// this delay will allow slower systems to keep going and get everything else
				// on screen before worrying about setting up the list
			}
		} else {
			this._addToShowingQueue("rendered", this.rendered);
		}
	},
	//*@protected
	_absoluteShowingChanged: function () {
		if (this.get("absoluteShowing")) {
			if (this._showingQueue && this._showingQueue.length) {
				var queue = this._showingQueue;
				var methods = this._showingQueueMethods;
				var fn;
				var name;
				this._showingQueue = null;
				this._showingQueueMethods = null;
				do {
					name = queue.shift();
					fn = methods[name];
					fn.call(this);
				} while (queue.length);
			}
		}
	},
	_addToShowingQueue: function (name, fn) {
		var queue = this._showingQueue || (this._showingQueue = []);
		var methods = this._showingQueueMethods || (this._showingQueueMethods = {});
		var idx = enyo.indexOf(name, queue);
		if (idx >= 0) {
			queue.splice(idx, 1);
		}
		queue.push(name);
		methods[name] = fn;
	},
	/**
		This function intentionally left blank. In DataRepeater, it removes the
		control at the specified index but that is handled by the delegate here.
	*/
	remove: function(index) {},
	//*@public
	/**
		Overloaded to call a method of the delegate strategy.
	*/
	modelsAdded: function (c, e, props) {
		if (c === this.collection && this.$.scroller.canGenerate) {
			if (this.get("absoluteShowing")) {
				this.delegate.modelsAdded(this, props);
			} else {
				this._addToShowingQueue("refresh", function () {
					this.refresh();
				});
			}
		}
	},
	/**
		Overloaded to call a method of the delegate strategy.
	*/
	modelsRemoved: enyo.inherit(function(sup) {
		return function modelsRemoved(c, e, props) {
			if (c === this.collection && this.$.scroller.canGenerate) {
				if (this.get("absoluteShowing")) {
					this.delegate.modelsRemoved(this, props);
				} else {
					this._addToShowingQueue("refresh", function () {
						this.refresh();
					});
				}
			}

			sup.apply(this, arguments);
		};
	}),
	destroy: enyo.inherit(function (sup) {
		return function () {
			if (this.delegate && this.delegate.destroyList) {
				this.delegate.destroyList(this);
			}
			this._showingQueue = null;
			this._showingQueueMethods = null;
			sup.apply(this, arguments);
		};
	}),
	/**
		Overloaded from base kind to ensure that the container options correctly apply
		the scroller options before instantiating it.
	*/
	initContainer: enyo.inherit(function (sup) {
		return function () {
			var o = enyo.clone(this.get("containerOptions")),
				s = this.get("scrollerOptions");
			if (s) { enyo.mixin(o, s, {exists: true}); }
			this.set("containerOptions", o);
			sup.apply(this, arguments);
		};
	}),
	/**
		We let the delegate strategy manage the event, but we arbitrarily return
		true because we don't want the event to propagate beyond this kind.
	*/
	didScroll: function (sender, event) {
		if (this.hasRendered && this.collection) {
			if (this.heightNeedsUpdate || this.widthNeedsUpdate) {
				// assign this here so that if for any reason it needs to
				// it can reset it
				this.heightNeedsUpdate = this.widthNeedsUpdate = false;
				this.refresh();
			}
			this.delegate.didScroll(this, event);
		}
		return true;
	},
	/**
		Special override to handle resizing in an attempt to minimize the amount of
		work we're doing. We don't want to waterfall the event to all children, so
		we hijack the normal handler.
	*/
	didResize: function (sender, event) {
		if (this.get("absoluteShowing")) {
			if (this.hasRendered && this.collection) {
				if (this.heightNeedsUpdate || this.widthNeedsUpdate) {
					// assign this here so that if for any reason it needs to
					// it can reset it
					this.heightNeedsUpdate = this.widthNeedsUpdate = false;
					this.refresh();
				}
				this.delegate.didResize(this, event);
			}
		} else {
			this._addToShowingQueue("didResize", this.didResize);
		}
	},
	showingChangedHandler: enyo.inherit(function (sup) {
		return function (inSender, inEvent) {
			this.set("absoluteShowing", this.getAbsoluteShowing(true));

			return sup.apply(this, arguments);
		};
	}),
	/**
		Overload to adjust the root method to be able to find the nested child
		based on the requested index if its page is currently active. Returns
		undefined if the index is out of bounds or if the control is not currently
		available.

		Also see _getChildForIndex()_, which calls this method.
	*/
	childForIndex: function (i) {
		return this.delegate.childForIndex(this, i);
	},
	//*@protected
	allowTransitionsChanged: function () {
		this.addRemoveClass("transitions", this.allowTransitions);
	},
	/**
		_enyo.DataList_ uses an overloaded container from its base kind. We set the
		container to a scroller and provide a way to modify the scroller options
		(via the _scrollerOptions_ hash). All children will reside in one of the two
		pages owned by the scroller.
	*/
	containerOptions: {name: "scroller", kind: "enyo.Scroller", components: [
		{name: "active", classes: "active", components: [
			{name: "page1", classes: "page page1"},
			{name: "page2", classes: "page page2"},
			{name: "buffer", classes: "buffer"}
		]}
	], canGenerate: false, classes: "enyo-fit enyo-data-list-scroller"},
	//* We access this kind's constructor and need it to be undeferred at that time.
	noDefer: true,
	absoluteShowing: true,
	//* All of the CSS is relative to this class.
	classes: "enyo-data-list",
	//* Our initial _controlParent_ is us for the _flyweighter_ child.
	controlParentName: "",
	//* Of course we set our container to _scroller_ as needed by the base kind.
	containerName: "scroller",
	/**
		We have to trap the Enyo-generated _onScroll_ event and let the delegate
		handle it. We also need to catch the _onresize_ events so we know when to
		update our cached sizing. We overload the default handler so that we don't
		waterfall the resizing; we arbitrarily handle it to minimize the amount of
		work we do.
	*/
	handlers: {onScroll: "didScroll", onresize: "didResize"},
	observers: [
		{method: "_absoluteShowingChanged", path: "absoluteShowing"}
	],
	//* Add the RegisteredEventSupport mixin for the paging event
	mixins: [enyo.RegisteredEventSupport],
	//* All delegates are named elsewhere but are stored in these statics.
	statics: {delegates: {}},
	//* An array of the actual _page_ references for easier access.
	pages: null
});
//*@protected
/**
	All subclasses of _enyo.DataList_ will have their own _delegates_ static hash.
	This is per _kind_, not per _instance_.
*/
enyo.DataList.subclass = function (ctor) {
	ctor.delegates = enyo.clone(ctor.prototype.base.delegates || this.delegates);
};
<commit_msg>originally from b09ee23b32eb1e3b58389071b4ba5d5e52436f07<commit_after>//*@public
/**
	_enyo.DataList_ is an [enyo.DataRepeater](#enyo.DataRepeater) that employs a
	paginated scrolling scheme to enhance performance with larger datasets. The
	data is provided to the DataList by an [enyo.Collection](#enyo.Collection) set
	as the value of its _collection_ property.

	Note that care should be taken when deciding how to lay out the list's
	children. When there are a large number of child elements, the layout process
	can be taxing and non-performant for the browser. Avoid	dynamically-updated
	layouts that require lots of calculations each time the data in a view is
	updated. Try to use CSS whenever possible.

	While paging through data, _enyo.DataList_ emits the _paging_ event, which
	allows you to make updates on a per-page basis, as necessary. You may register
	for this event by calling _addListener()_ and specifying the event, along with
	a callback method.

	The callback method is passed a reference to the _enyo.DataList_, the name of
	the event (_"paging"_), and a hash with the properties _start_, _end_, and
	_action_, referring to the lowest active index in the dataset, the highest
	active index, and the action that triggered the paging, respectively. The
	value of _action_ value may be either _"scroll"_ or _"reset"_.
*/
enyo.kind({
	name: "enyo.DataList",
	kind: enyo.DataRepeater,
	/**
		_enyo.DataList_ places its rows inside of a scroller. Any configurable
		options of _enyo.Scroller_ may be placed in this hash; their values will be
		set accordingly on this list's scroller. If no options are specified, the
		default _enyo.Scroller_ settings are used.
	*/
	scrollerOptions: null,
	/**
		The paging orientation. Valid values are _"vertical"_ and _"horizontal"_.
		This property will be mapped to a particular strategy governing how the list
		will flow.
	*/
	orientation: "vertical",
	/**
		This is typically handled automatically, but some platforms may benefit from
		having a larger or smaller value here. If there is a number here, it will be
		multiplied by the available viewport size (depending on orientation) to
		determine the minimum page size. The page size is directly related to the
		number of controls that are generated at any given time (and that
		subsequently need updating) whenever paging occurs. This number may be any
		rational number greater than _1.2_.
	*/
	pageSizeMultiplier: null,
	/**
		It is helpful for performance if the list doesn't need to guess at the size of
		the children. In cases where all children are a fixed height/width (depending on
		the orientation of the list) you may explicitly define that value for the list
		to use and bypass much of its guesswork. This value is a number that will be interpreted
		in pixels and applied to the primary size depending on orientation: _height_ when
		_vertical_ and _width_ when _horizontal_. Note this value is not applied to the
		children via CSS by the list.
	*/
	fixedChildSize: null,
	/**
		To disable the default smoothing-transitions (for supported platforms), set
		this flag to false.
	*/
	allowTransitions: true,
	/**
		Because some systems perform poorly on initialization, there is a delay when
		we attempt to actually draw the contents of a DataList. Usually, you will
		not need to adjust this value (expressed in milliseconds). If _renderDelay_
		is null, there will be no delay and rendering will take place synchronously.
		If _renderDelay_ is set to 0, rendering will be done asynchronously.
	*/
	renderDelay: 250,
	/**
		Completely resets the current list such that it scrolls to the top of the
		scrollable region and regenerates all of its children. This is typically
		necessary only on initialization or if the entire dataset has been swapped
		out.
	*/
	reset: function () {
		if (this.get("absoluteShowing")) {
			// we can only reset if we've already rendered
			if (this.generated && this.$.scroller.generated) {
				this.delegate.reset(this);
			}
		} else {
			this._addToShowingQueue("reset", this.reset);
		}
	},
	/**
		Unlike _reset()_, which tears down and regenerates the entire list, this
		method attempts to refresh the pages as they are against the current
		dataset. This is much cheaper to call than _reset()_, but is primarily used
		internally.
	*/
	refresh: function (c, e) {
		if (this.get("absoluteShowing")) {
			if (this.hasRendered) {
				this.delegate.refresh(this);
			}
		} else {
			this._addToShowingQueue("refresh", this.refresh);
		}
	},
	/**
		Pass in an integer within the bounds of the lists's collection to scroll to
		the position of that index in the list.
	*/
	scrollToIndex: function (idx) {
		var len = this.collection? this.collection.length: 0;
		if (idx >= 0 && idx < len) {
			if (this.get("absoluteShowing")) {
				this.delegate.scrollToIndex(this, idx);
			} else {
				this._addToShowingQueue("scrollToIndex", function () {
					this.delegate.scrollToIndex(this, idx);
				});
			}
		}
	},
	//*@protected
	constructor: enyo.inherit(function (sup) {
		return function () {
			sup.apply(this, arguments);
			this.metrics       = {};
			this.metrics.pages = {};
			if (this.pageSizeMultiplier !== null && !isNaN(this.pageSizeMultiplier)) {
				this.pageSizeMultiplier = Math.max(1.2, this.pageSizeMultiplier);
			}
		};
	}),
	create: enyo.inherit(function (sup) {
		return function () {
			// if we can, we use transitions
			this.allowTransitionsChanged();
			// map the selected strategy to the correct delegate for operations
			// on the list, default to _vertical_ if none is provided or if it
			// could not be found
			this.delegate = this.ctor.delegates[this.orientation] || this.base.delegates.vertical;
			// if the delegate has an initialization routine execute it now before the
			// container and children are rendered
			if (this.delegate.initList) {
				this.delegate.initList(this);
			}
			sup.apply(this, arguments);
			// initialize the _pages_ array and add the pages to it
			this.pages = [this.$.page1, this.$.page2];
		};
	}),
	render: enyo.inherit(function (sup) {
		return function () {
			this.$.scroller.canGenerate = false;
			this.$.scroller.teardownRender();
			sup.apply(this, arguments);
		};
	}),
	/**
		Attempts to perform initialization. There are only a few basic startup
		paths, but we need to be aware of what they are:

		* The view is rendered, it has a collection, and the collection has data.
		* The view is rendered, it has a collection with no data, and data is added
			later.
		* The view is rendered, but has no collection.

		Once the list itself is rendered, we check to see if we have a collection;
		if so, do we have any data to start rendering the rest of the list?
		Ultimately, the implementation decisions are decided by the delegate
		strategy.
	*/
	rendered: function () {
		if (this.get("absoluteShowing")) {
			// actually rendering a datalist can be taxing for some systems so
			// we arbitrarily delay showing for a fixed amount of time unless delay is
			// null in which case it will be executed immediately
			var startup = function () {
				// now that the base list is rendered, we can safely generate our scroller
				this.$.scroller.canGenerate = true;
				this.$.scroller.render();
				// and now we hand over the action to our strategy to let it initialize the
				// way it needs to
				this.delegate.rendered(this);
				this.hasRendered = true;
				// now add our class to adjust visibility (if no overridden)
				this.addClass("rendered");
				if (this.didRender) {
					this.didRender();
				}
			};
			if (this.renderDelay === null) {
				startup.call(this);
			} else {
				this.startJob("rendering", startup, this.renderDelay);
				// this delay will allow slower systems to keep going and get everything else
				// on screen before worrying about setting up the list
			}
		} else {
			this._addToShowingQueue("rendered", this.rendered);
		}
	},
	//*@protected
	_absoluteShowingChanged: function () {
		if (this.get("absoluteShowing")) {
			if (this._showingQueue && this._showingQueue.length) {
				var queue = this._showingQueue;
				var methods = this._showingQueueMethods;
				var fn;
				var name;
				this._showingQueue = null;
				this._showingQueueMethods = null;
				do {
					name = queue.shift();
					fn = methods[name];
					fn.call(this);
				} while (queue.length);
			}
		}
	},
	_addToShowingQueue: function (name, fn) {
		var queue = this._showingQueue || (this._showingQueue = []);
		var methods = this._showingQueueMethods || (this._showingQueueMethods = {});
		var idx = enyo.indexOf(name, queue);
		if (idx >= 0) {
			queue.splice(idx, 1);
		}
		queue.push(name);
		methods[name] = fn;
	},
	/**
		This function intentionally left blank. In DataRepeater, it removes the
		control at the specified index but that is handled by the delegate here.
	*/
	remove: function(index) {},
	//*@public
	/**
		Overloaded to call a method of the delegate strategy.
	*/
	modelsAdded: function (c, e, props) {
		if (c === this.collection && this.$.scroller.canGenerate) {
			if (this.get("absoluteShowing")) {
				this.delegate.modelsAdded(this, props);
			} else {
				this._addToShowingQueue("refresh", function () {
					this.refresh();
				});
			}
		}
	},
	/**
		Overloaded to call a method of the delegate strategy.
	*/
	modelsRemoved: enyo.inherit(function(sup) {
		return function modelsRemoved(c, e, props) {
			if (c === this.collection && this.$.scroller.canGenerate) {
				if (this.get("absoluteShowing")) {
					this.delegate.modelsRemoved(this, props);
					sup.apply(this, arguments);
				} else {
					this._addToShowingQueue("refresh", function () {
						sup.apply(this, arguments);
						this.refresh();
					});
				}
			}
		};
	}),
	destroy: enyo.inherit(function (sup) {
		return function () {
			if (this.delegate && this.delegate.destroyList) {
				this.delegate.destroyList(this);
			}
			this._showingQueue = null;
			this._showingQueueMethods = null;
			sup.apply(this, arguments);
		};
	}),
	/**
		Overloaded from base kind to ensure that the container options correctly apply
		the scroller options before instantiating it.
	*/
	initContainer: enyo.inherit(function (sup) {
		return function () {
			var o = enyo.clone(this.get("containerOptions")),
				s = this.get("scrollerOptions");
			if (s) { enyo.mixin(o, s, {exists: true}); }
			this.set("containerOptions", o);
			sup.apply(this, arguments);
		};
	}),
	/**
		We let the delegate strategy manage the event, but we arbitrarily return
		true because we don't want the event to propagate beyond this kind.
	*/
	didScroll: function (sender, event) {
		if (this.hasRendered && this.collection) {
			if (this.heightNeedsUpdate || this.widthNeedsUpdate) {
				// assign this here so that if for any reason it needs to
				// it can reset it
				this.heightNeedsUpdate = this.widthNeedsUpdate = false;
				this.refresh();
			}
			this.delegate.didScroll(this, event);
		}
		return true;
	},
	/**
		Special override to handle resizing in an attempt to minimize the amount of
		work we're doing. We don't want to waterfall the event to all children, so
		we hijack the normal handler.
	*/
	didResize: function (sender, event) {
		if (this.get("absoluteShowing")) {
			if (this.hasRendered && this.collection) {
				if (this.heightNeedsUpdate || this.widthNeedsUpdate) {
					// assign this here so that if for any reason it needs to
					// it can reset it
					this.heightNeedsUpdate = this.widthNeedsUpdate = false;
					this.refresh();
				}
				this.delegate.didResize(this, event);
			}
		} else {
			this._addToShowingQueue("didResize", this.didResize);
		}
	},
	showingChangedHandler: enyo.inherit(function (sup) {
		return function (inSender, inEvent) {
			this.set("absoluteShowing", this.getAbsoluteShowing(true));

			return sup.apply(this, arguments);
		};
	}),
	/**
		Overload to adjust the root method to be able to find the nested child
		based on the requested index if its page is currently active. Returns
		undefined if the index is out of bounds or if the control is not currently
		available.

		Also see _getChildForIndex()_, which calls this method.
	*/
	childForIndex: function (i) {
		return this.delegate.childForIndex(this, i);
	},
	//*@protected
	allowTransitionsChanged: function () {
		this.addRemoveClass("transitions", this.allowTransitions);
	},
	/**
		_enyo.DataList_ uses an overloaded container from its base kind. We set the
		container to a scroller and provide a way to modify the scroller options
		(via the _scrollerOptions_ hash). All children will reside in one of the two
		pages owned by the scroller.
	*/
	containerOptions: {name: "scroller", kind: "enyo.Scroller", components: [
		{name: "active", classes: "active", components: [
			{name: "page1", classes: "page page1"},
			{name: "page2", classes: "page page2"},
			{name: "buffer", classes: "buffer"}
		]}
	], canGenerate: false, classes: "enyo-fit enyo-data-list-scroller"},
	//* We access this kind's constructor and need it to be undeferred at that time.
	noDefer: true,
	absoluteShowing: true,
	//* All of the CSS is relative to this class.
	classes: "enyo-data-list",
	//* Our initial _controlParent_ is us for the _flyweighter_ child.
	controlParentName: "",
	//* Of course we set our container to _scroller_ as needed by the base kind.
	containerName: "scroller",
	/**
		We have to trap the Enyo-generated _onScroll_ event and let the delegate
		handle it. We also need to catch the _onresize_ events so we know when to
		update our cached sizing. We overload the default handler so that we don't
		waterfall the resizing; we arbitrarily handle it to minimize the amount of
		work we do.
	*/
	handlers: {onScroll: "didScroll", onresize: "didResize"},
	observers: [
		{method: "_absoluteShowingChanged", path: "absoluteShowing"}
	],
	//* Add the RegisteredEventSupport mixin for the paging event
	mixins: [enyo.RegisteredEventSupport],
	//* All delegates are named elsewhere but are stored in these statics.
	statics: {delegates: {}},
	//* An array of the actual _page_ references for easier access.
	pages: null
});
//*@protected
/**
	All subclasses of _enyo.DataList_ will have their own _delegates_ static hash.
	This is per _kind_, not per _instance_.
*/
enyo.DataList.subclass = function (ctor) {
	ctor.delegates = enyo.clone(ctor.prototype.base.delegates || this.delegates);
};
<|endoftext|>


<commit_before>import program from 'commander';

process.title = "whiten";
program
    .version(require('../package.json').version)
    .usage('[options] <module ...>')
    .option('-r --registry [source]', 'Source to whiten from (npm), if none given npm will be assumed', /^(npm)$/i, 'npm')
    .parse(process.argv);

let modules = program.args;

if (modules.constructor !== Array || modules.length < 1) {
    program.help();
}
<commit_msg>so beautiful<commit_after>import path from 'path';
import program from 'commander';
import whiten from './index';

process.title = "whiten";
program
    .version(require('../package.json').version)
    .usage('[options] <module ...>')
    .option('-r --registry [source]', 'Source to whiten from (npm), if none given npm will be assumed', /^(npm)$/i, 'npm')
    .parse(process.argv);

let modules = program.args;

if (modules.constructor !== Array || modules.length < 1) {
    program.help();
}
whiten(modules, program.registry, (zip) => {
    zip.writeToFile(path.join(process.cwd(), modules.join(' ') + '.zip'));
});
<|endoftext|>


<commit_before>import * as v from 'engine';

// v.settings.SCALE_MODE = v.SCALE_MODES.NEAREST;

export default {
    application: {
        name: 'Voltar',
        main_scene: 'boot/scene',
    },
    display: {
        view: 'game',
        container: 'container',

        width: 256,
        height: 256,
        resolution: 1,

        background_color: 0x00AAC9,

        force_canvas: false,
        antialias: false,
        pixel_snap: true,

        FPS: 60,

        stretch_mode: v.STRETCH_MODE_VIEWPORT,
        stretch_aspect: v.STRETCH_ASPECT_KEEP_HEIGHT,
    },
};
<commit_msg>Use viewport stretch and aspect keep settings<commit_after>import * as v from 'engine';

// v.settings.SCALE_MODE = v.SCALE_MODES.NEAREST;

export default {
    application: {
        name: 'Voltar',
        main_scene: 'boot/scene',
    },
    display: {
        view: 'game',
        container: 'container',

        width: 256,
        height: 256,
        resolution: 1,

        background_color: 0x00AAC9,

        force_canvas: false,
        antialias: false,
        pixel_snap: true,

        FPS: 60,

        stretch_mode: v.STRETCH_MODE_VIEWPORT,
        stretch_aspect: v.STRETCH_ASPECT_KEEP,
    },
};
<|endoftext|>


<commit_before>// Shebang will be added by webpack
//#!/usr/bin/env node --harmony

const
    VERSION = require('../package.json').version,
    fs = require('fs'),
    program = require('commander'),
    validate = require('./index').default;

program
    .version(VERSION)
    .arguments('<filePath>')
    .description('Validate embedded examples in Swagger-JSONs')
    .action(filePath => {
        const
            jsonSchema = JSON.parse(fs.readFileSync(filePath, 'utf-8')),
            result = validate(jsonSchema);
        if (result.valid) { return; }
        process.stderr.write(JSON.stringify(result.errors, null, '    '));
    });
program.parse(process.argv);
<commit_msg>chore(cli): exit with error, when validation fails<commit_after>// Shebang will be added by webpack
//#!/usr/bin/env node --harmony

const
    VERSION = require('../package.json').version,
    fs = require('fs'),
    program = require('commander'),
    validate = require('./index').default;

program
    .version(VERSION)
    .arguments('<filePath>')
    .description('Validate embedded examples in Swagger-JSONs')
    .action(filePath => {
        const
            jsonSchema = JSON.parse(fs.readFileSync(filePath, 'utf-8')),
            result = validate(jsonSchema);
        if (result.valid) { return; }
        process.stderr.write(JSON.stringify(result.errors, null, '    '));
        process.exit(1);
    });
program.parse(process.argv);
<|endoftext|>


<commit_before>/**
 * Description
 * Let hubot execute shell command.
 *
 * Dependencies:
 * send_message: include this module
 *
 * Configuration:
 * CMD_CONFIG: path to configuration file
 * CMD_MSG_COLOR: color
 *
 * hipchat "color" is allowed in "yellow", "red", "green", "purple", "gray", or "random".
 *
 * You need write CMD_CONFIG file in yaml format like this.
 *
 * "TARGET1":
 *   "ACTION1":
 *     "command": "/path/to/cmd1 ACTION1"
 *     "user": ["foo", "bar"]
 *     "message": "/path/to/cmd1 ACTION1 is executed."
 *   "ACTION2":
 *     "command": "/path/to/cmd1 ACTION2"
 *     "user": ["foo"]
 *     "message": "/path/to/cmd1 ACTION2 is executed."
 * "TARGET2":
 *   "ACTION1":
 *     "command": "/path/to/cmd2 ACTION1"
 *     "user": ["foo", "bar"]
 *     "message": "/path/to/cmd2 ACTION1 is executed."
 *
 * You need to execute hubot as adapter for each group chat system.
 * If you use slack, you need to hubot-slack adapter.
 *
 * You need to let hubot user allow to execute command on your system (ex. sudo).
 * Each ACTION has these properties:
 * command: the expression to execute command.
 * user:    the list of user allowed to execute the command.
 * message: the message to let hubot tell when the command executed.
 *
 * Commands:
 * Tell bot to order.
 * @bot cmd TARGET ACTION
 *
 * Author:
 * Taiyu Fujii
 */

/* @flow */
import fs            from 'fs';
import yaml          from 'js-yaml';
import child_process from 'child_process';

import SendMessage   from './SendMessage';
import Auth          from './Auth';

const prefix      = '[cmd]';
const debug       = process.env.CMD_DEBUG;
const configFile  = process.env.CMD_CONFIG;
const color       = process.env.CMD_MSG_COLOR || '#aaaaaa';
const type        = process.env.HUBOT_IRC_TYPE;
const name        = 'cmd';

module.exports = (robot) => {
  const sm      = new SendMessage(robot, type);
  const log     = sm.robot;
  const options = {
    color: color
  };

  if (!configFile) {
    log.error(`${name}> no config file.`);
    return;
  }

  const conf = yaml.safeLoad(fs.readFileSync(configFile));

  const execCommand = (msg, cmd) => {
    const room    = `#${msg.message.user.room}`;
    const target  = [ room ];
    const exec    = child_process.exec;
    const message = {};
    const result  = [];

    exec(cmd, (err, stdout, stderr) => {
      if (err || stderr) {
        msg.send(`[Unknown error]\n\n${err}\n${stderr}`);
        return;
      }

      if (!stdout) {
        msg.send(`[Result]\n\nexecuted in success.`);
        return;
      }

      msg.send(`[Result]\n\n${stdout}`);
    });
  };

  const checkPrivilege = (list, user) => {
    let flag = false;

    list.map((l) => {
      if (l == user) {
        flag = true;
      }
    });

    if (flag == false) {
      return false;
    }

    return true;
  };

  const help = (msg, title, message) => {
    const room     = `#${msg.message.user.room}`;
    const target   = [ room ];
    const messages = [message];

    if (!title) {
      title = 'Usage: cmd TARGET ACTION.';
    }

    messages.push("Your order is not match my task list. Please check again.\n");
    Object.keys(conf).map((key) => {
      Object.keys(conf[key]).map((key2) => {
        messages.push(`- ${key} ${key2}: ${conf[key][key2]['command']}\n${conf[key][key2]['message']}.\n  by ${conf[key][key2]['user'].join(', ')}`);
      });
    });

    msg.send(`[${title}]\n\n${messages.join("\n")}`);
  };

  robot.hear(/cmd help/i, (msg) => {
    help(msg);
  });

  robot.hear(/cmd (\w+) (\w+)/i, (msg) => {
    const title = `${prefix} ${msg.match[1]} ${msg.match[2]}`;

    Object.keys(conf).map((key) => {
      const value = conf[key];
      switch (msg.match[1]) {
      case key:
        Object.keys(value).map((key2) => {
          const value2 = value[key2];

          if (!checkPrivilege(value2['user']), msg.message.user.name) {
            console.log(`action not found: ${msg.match[2]}`);
            msg.send(`Action not found: ${msg.match[2]}.\n\nSee HUBOT_NAME cmd help.`);
            return;
          }

          msg.send(`[${title}\n\n${value2['message']}]`);
          execCommand(msg, value2['command']);
          return;
        });
        break;

      default:
        console.log(`target not found: ${msg.match[1]}`);
        msg.send(`Target not found: ${msg.match[1]}.\n\nSee HUBOT_NAME cmd help.`);
        return;
      }
    });
  });
};
<commit_msg>fix cmd.<commit_after>/**
 * Description
 * Let hubot execute shell command.
 *
 * Dependencies:
 * send_message: include this module
 *
 * Configuration:
 * CMD_CONFIG: path to configuration file
 * CMD_MSG_COLOR: color
 *
 * hipchat "color" is allowed in "yellow", "red", "green", "purple", "gray", or "random".
 *
 * You need write CMD_CONFIG file in yaml format like this.
 *
 * "TARGET1":
 *   "ACTION1":
 *     "command": "/path/to/cmd1 ACTION1"
 *     "user": ["foo", "bar"]
 *     "message": "/path/to/cmd1 ACTION1 is executed."
 *   "ACTION2":
 *     "command": "/path/to/cmd1 ACTION2"
 *     "user": ["foo"]
 *     "message": "/path/to/cmd1 ACTION2 is executed."
 * "TARGET2":
 *   "ACTION1":
 *     "command": "/path/to/cmd2 ACTION1"
 *     "user": ["foo", "bar"]
 *     "message": "/path/to/cmd2 ACTION1 is executed."
 *
 * You need to execute hubot as adapter for each group chat system.
 * If you use slack, you need to hubot-slack adapter.
 *
 * You need to let hubot user allow to execute command on your system (ex. sudo).
 * Each ACTION has these properties:
 * command: the expression to execute command.
 * user:    the list of user allowed to execute the command.
 * message: the message to let hubot tell when the command executed.
 *
 * Commands:
 * Tell bot to order.
 * @bot cmd TARGET ACTION
 *
 * Author:
 * Taiyu Fujii
 */

/* @flow */
import fs            from 'fs';
import yaml          from 'js-yaml';
import child_process from 'child_process';

import SendMessage   from './SendMessage';
import Auth          from './Auth';

const prefix      = '[cmd]';
const debug       = process.env.CMD_DEBUG;
const configFile  = process.env.CMD_CONFIG;
const color       = process.env.CMD_MSG_COLOR || '#aaaaaa';
const type        = process.env.HUBOT_IRC_TYPE;
const name        = 'cmd';

module.exports = (robot) => {
  const sm      = new SendMessage(robot, type);
  const log     = sm.robot;
  const options = {
    color: color
  };

  if (!configFile) {
    log.error(`${name}> no config file.`);
    return;
  }

  const conf = yaml.safeLoad(fs.readFileSync(configFile));

  const execCommand = (msg, cmd) => {
    const room    = `#${msg.message.user.room}`;
    const target  = [ room ];
    const exec    = child_process.exec;
    const message = {};
    const result  = [];

    exec(cmd, (err, stdout, stderr) => {
      if (err || stderr) {
        msg.send(`[Unknown error]\n\n${err}\n${stderr}`);
        return;
      }

      if (!stdout) {
        msg.send(`[Result]\n\nexecuted in success.`);
        return;
      }

      msg.send(`[Result]\n\n${stdout}`);
    });
  };

  const checkPrivilege = (list, user) => {
    let flag = false;

    list.map((l) => {
      if (l == user) {
        flag = true;
      }
    });

    if (flag == false) {
      return false;
    }

    return true;
  };

  const help = (msg, title, message) => {
    const room     = `#${msg.message.user.room}`;
    const target   = [ room ];
    const messages = [message];

    if (!title) {
      title = 'Usage: cmd TARGET ACTION.';
    }

    messages.push("Your order is not match my task list. Please check again.\n");
    Object.keys(conf).map((key) => {
      Object.keys(conf[key]).map((key2) => {
        messages.push(`- ${key} ${key2}: ${conf[key][key2]['command']}\n${conf[key][key2]['message']}.\n  by ${conf[key][key2]['user'].join(', ')}`);
      });
    });

    msg.send(`[${title}]\n\n${messages.join("\n")}`);
  };

  robot.hear(/cmd help/i, (msg) => {
    help(msg);
  });

  robot.hear(/cmd (\w+) (\w+)/i, (msg) => {
    const target  = msg.match[1];
    const action  = msg.match[2];
    const title   = `${prefix} ${target} ${action}`;

    Object.keys(conf).map((t) => {
      const actions = conf[target];
      switch (target) {
      case t:
        Object.keys(actions).map((a) => {
          const act = actions[a];

          if (!checkPrivilege(act['user']), msg.message.user.name) {
            console.log(`action not found: ${action}`);
            msg.send(`Action not found: ${action}.\n\nSee HUBOT_NAME cmd help.`);
            return;
          }

          msg.send(`[${title}\n\n${act['message']}]`);
          execCommand(msg, act['command']);
          return;
        });
        break;

      default:
        console.log(`target not found: ${target}`);
        msg.send(`Target not found: ${target}.\n\nSee HUBOT_NAME cmd help.`);
        return;
      }
    });
  });
};
<|endoftext|>


<commit_before>/* @flow */

/**
 * Description
 * Let hubot execute shell command.
 *
 * Dependencies:
 * send_message: include this module
 *
 * Configuration:
 * CMD_CONFIG: path to configuration file
 *
 * You need write CMD_CONFIG file in yaml format like this.
 *
 * TARGET1:
 *   ACTION1:
 *     command: "/path/to/cmd1 ACTION1"
 *     user:
 *       - "foo"
 *       - "bar"
 *     message: "/path/to/cmd1 ACTION1 is executed."
 *   ACTION2:
 *     command: "/path/to/cmd1 ACTION2"
 *     user:
 *       - "foo"
 *       - "bar"
 *     message: "/path/to/cmd1 ACTION2 is executed."
 * TARGET2:
 *   ACTION1:
 *     command: "/path/to/cmd2 ACTION1"
 *     user:
 *       - "foo"
 *       - "bar"
 *     message: "/path/to/cmd2 ACTION1 is executed."
 *
 * You need to execute hubot as adapter for each group chat system.
 * If you use slack, you need to hubot-slack adapter.
 *
 * You need to let hubot user allow to execute command on your system (ex. sudo).
 * Each ACTION has these properties:
 * command: the expression to execute command.
 * user:    the list of user allowed to execute the command.
 * message: the message to let hubot tell when the command executed.
 *
 * Commands:
 * Tell bot to order.
 * @hubot cmd TARGET ACTION ARG
 *
 * Author:
 * Taiyu Fujii
 */

import fs            from 'fs';
import yaml          from 'js-yaml';
import child_process from 'child_process';

import SendMessage   from './SendMessage';
import Auth          from './Auth';

const prefix: string      = '[cmd]';
const debug: string       = process.env.CMD_DEBUG || 'false';
const configFile: string  = process.env.CMD_CONFIG || '';
const type: string        = process.env.HUBOT_IRC_TYPE || 'slack';
const name: string        = 'cmd';
const USER: string        = 'user';
const MESSAGE: string     = 'message';
const COMMAND: string     = 'command';

module.exports = (robot: any) => {
  const sm: any  = new SendMessage(robot, type);
  const log: any = sm.robot;

  if (!configFile) {
    log.error(`${name}> no config file.`);
    return;
  }

  const conf: any = yaml.safeLoad(fs.readFileSync(configFile));

  const execCommand = (msg, cmd, arg): void => {
    const room: string           = `#${msg.message.user.room}`;
    const target: Array<string>  = [ room ];
    const exec: any              = child_process.exec;
    const command: string        = arg ? `${cmd} ${arg}` : cmd;

    exec(command, (err: string, stdout: string, stderr: string) => {
      if (err) {
        msg.send(`[Unknown error]\n\n${err}\n${stderr}`);
        return;
      }

      if (!stdout) {
        msg.send(`[Result]\n  executed in success.`);
        return;
      }
      msg.send(`[Result]\n  \`${stdout}\``);
    });
  };

  const checkPrivilege = (list: Array<string>, user: string): boolean => {
    let flag = false;

    list.map((l) => {
      if (l == user) {
        flag = true;
      }
    });

    return flag === true ? true : false;
  };

  const help = (msg: any, title: string, message: string = ''): void => {
    const room     = msg.message.user.room;
    const target   = [ room ];
    const messages = [message];

    Object.keys(conf).map((target) => {
      Object.keys(conf[target]).map((action) => {
        messages.push(`\*${target} ${action}\*: \n  ${conf[target][action][MESSAGE]}\n\n  [command]\n    \`${conf[target][action][COMMAND]}\`\n\n  [user]\n    ${conf[target][action][USER].join(', ')}`);
      });
    });

    msg.send(`[${title}]\n\n${messages.join("\n\n")}`);
  };

  robot.respond(/cmd help/i, (msg: any) => {
    help(msg, 'Usage: cmd TARGET ACTION (ARGUMENT).', "Here is my task list.\n\n");
  });

  robot.respond(/cmd (\w+) (\w+) ?([A-Za-z0-9_\.]+)?/i, (msg: any) => {
    const target  = msg.match[1];
    const action  = msg.match[2];
    const arg     = msg.match[3];
    const title   = `*${target} ${action}*`;
    let flag      = false;

    Object.keys(conf).map((t) => {
      const actions: any = conf[target];
      if (target == t) {
        Object.keys(actions).map((a) => {
          const act: any = actions[a];

          if (action != a) {
            return;
          }

          flag = true;

          if (!checkPrivilege(act[USER], msg.message.user.name)) {
            console.log(`Not allowed user: ${msg.message.user.name}`);
            msg.send(`Not allowed user: ${msg.message.user.name}.\n\nPlease contact the administrator.`);
            return;
          }
console.log(`arg: ${arg}`);
          const cmd: string = arg ? `${act[COMMAND]} ${arg}` : `${act[COMMAND]}`;
          msg.send(`${title}\n  ${act[MESSAGE]}\n\n[command]\n  \`${cmd}\`\n\n`);
          execCommand(msg, act[COMMAND], arg);
        });
      }
    });

    if (flag === false) {
      console.log(`target not found: ${target}`);
      msg.send(`Target not found: ${target}.\n\nTry @HUBOT_NAME cmd help.`);
    }
  });
};
<commit_msg>modify message format.<commit_after>/* @flow */

/**
 * Description
 * Let hubot execute shell command.
 *
 * Dependencies:
 * send_message: include this module
 *
 * Configuration:
 * CMD_CONFIG: path to configuration file
 *
 * You need write CMD_CONFIG file in yaml format like this.
 *
 * TARGET1:
 *   ACTION1:
 *     command: "/path/to/cmd1 ACTION1"
 *     user:
 *       - "foo"
 *       - "bar"
 *     message: "/path/to/cmd1 ACTION1 is executed."
 *   ACTION2:
 *     command: "/path/to/cmd1 ACTION2"
 *     user:
 *       - "foo"
 *       - "bar"
 *     message: "/path/to/cmd1 ACTION2 is executed."
 * TARGET2:
 *   ACTION1:
 *     command: "/path/to/cmd2 ACTION1"
 *     user:
 *       - "foo"
 *       - "bar"
 *     message: "/path/to/cmd2 ACTION1 is executed."
 *
 * You need to execute hubot as adapter for each group chat system.
 * If you use slack, you need to hubot-slack adapter.
 *
 * You need to let hubot user allow to execute command on your system (ex. sudo).
 * Each ACTION has these properties:
 * command: the expression to execute command.
 * user:    the list of user allowed to execute the command.
 * message: the message to let hubot tell when the command executed.
 *
 * Commands:
 * Tell bot to order.
 * @hubot cmd TARGET ACTION ARG
 *
 * Author:
 * Taiyu Fujii
 */

import fs            from 'fs';
import yaml          from 'js-yaml';
import child_process from 'child_process';

import SendMessage   from './SendMessage';
import Auth          from './Auth';

const prefix: string      = '[cmd]';
const debug: string       = process.env.CMD_DEBUG || 'false';
const configFile: string  = process.env.CMD_CONFIG || '';
const type: string        = process.env.HUBOT_IRC_TYPE || 'slack';
const name: string        = 'cmd';
const USER: string        = 'user';
const MESSAGE: string     = 'message';
const COMMAND: string     = 'command';

module.exports = (robot: any) => {
  const sm: any  = new SendMessage(robot, type);
  const log: any = sm.robot;

  if (!configFile) {
    log.error(`${name}> no config file.`);
    return;
  }

  const conf: any = yaml.safeLoad(fs.readFileSync(configFile));

  const execCommand = (msg, cmd, arg): void => {
    const room: string           = `#${msg.message.user.room}`;
    const target: Array<string>  = [ room ];
    const exec: any              = child_process.exec;
    const command: string        = arg ? `${cmd} ${arg}` : cmd;

    exec(command, (err: string, stdout: string, stderr: string) => {
      if (err) {
        msg.send(`[Unknown error]\n\n${err}\n${stderr}`);
        return;
      }

      if (!stdout) {
        msg.send(`[Result]\n  executed in success.`);
        return;
      }
      msg.send(`[Result]\n  \`${stdout}\``);
    });
  };

  const checkPrivilege = (list: Array<string>, user: string): boolean => {
    let flag = false;

    list.map((l) => {
      if (l == user) {
        flag = true;
      }
    });

    return flag === true ? true : false;
  };

  const help = (msg: any): void => {
    const room     = msg.message.user.room;
    const target   = [ room ];
    const messages = ['`[Usage: cmd TARGET ACTION (ARGUMENT)]`\nHere is my task list.'];

    Object.keys(conf).map(target => {
      Object.keys(conf[target]).map(action => {
        const cmds = `\*${target} ${action}\*:
  ${conf[target][action][MESSAGE]}

  [command]
    \`${conf[target][action][COMMAND]}\`

  [user]
    ${conf[target][action][USER].join(', ')}`;

        messages.push(cmds);
      });
    });

    msg.send(messages.join("\n\n"));
  };

  robot.respond(/cmd help/i, (msg: any) => {
    help(msg);
  });

  robot.respond(/cmd (\w+) (\w+) ?([A-Za-z0-9_\.]+)?/i, (msg: any) => {
    const target  = msg.match[1];
    const action  = msg.match[2];
    const arg     = msg.match[3];
    const title   = `*${target} ${action}*`;
    let flag      = false;

    Object.keys(conf).map((t) => {
      const actions: any = conf[target];
      if (target == t) {
        Object.keys(actions).map((a) => {
          const act: any = actions[a];

          if (action != a) {
            return;
          }

          flag = true;

          if (!checkPrivilege(act[USER], msg.message.user.name)) {
            console.log(`Not allowed user: ${msg.message.user.name}`);
            msg.send(`Not allowed user: ${msg.message.user.name}.\n\nPlease contact the administrator.`);
            return;
          }
console.log(`arg: ${arg}`);
          const cmd: string = arg ? `${act[COMMAND]} ${arg}` : `${act[COMMAND]}`;
          msg.send(`${title}\n  ${act[MESSAGE]}\n\n[command]\n  \`${cmd}\`\n\n`);
          execCommand(msg, act[COMMAND], arg);
        });
      }
    });

    if (flag === false) {
      console.log(`target not found: ${target}`);
      msg.send(`Target not found: ${target}.\n\nTry @HUBOT_NAME cmd help.`);
    }
  });
};
<|endoftext|>


<commit_before>// @flow

import * as React from 'react'
import {ScrollView, StyleSheet, View, Text} from 'react-native'
import * as wifi from './wifi'
import * as helpdesk from './helpdesk'
import * as facilities from './facilities'

export type ReportProblemToolNamesEnum =
  | wifi.ToolName
  | facilities.ToolName
  | helpdesk.ToolName

export type ReportProblemToolOptions = {
  wifi?: wifi.ToolOptions,
  'it-helpdesk'?: helpdesk.ToolOptions,
  'facilities-work-order'?: facilities.ToolOptions,
}

type Props = {
  enabledTools: Array<ReportProblemToolNamesEnum>,
  toolOptions: ReportProblemToolOptions,
}

export default class HelpView extends React.Component<Props> {
  static navigationOptions = {
    title: 'Help',
  }

  render() {
    const allTools = [wifi, helpdesk, facilities]
    const enabled = allTools
      .filter(tool => this.props.enabledTools.includes(tool.toolName))
      .map(tool => (
        <tool.ToolView
          key={tool.toolName}
          options={this.props.toolOptions[tool.toolName]}
        />
      ))

    return (
      <ScrollView style={styles.contentContainer}>
        {enabled.length ? enabled : <EmptyListView />}
      </ScrollView>
    )
  }
}

const EmptyListView = () => (
  <View>
    <Text>No tools are enabled.</Text>
  </View>
)

const styles = StyleSheet.create({
  contentContainer: {
    paddingTop: 10,
  },
})
<commit_msg>connect Help to redux<commit_after>// @flow

import * as React from 'react'
import {connect} from 'react-redux'
import {ScrollView, StyleSheet, View, Text} from 'react-native'
import {type TopLevelViewPropsType} from '../types'
import {type ReduxState} from '../../flux'
import {getEnabledTools} from '../../flux/parts/help'
import * as wifi from './wifi'
import * as helpdesk from './helpdesk'
import * as facilities from './facilities'

const ALL_TOOLS = [wifi, helpdesk, facilities]

export type ReportProblemToolNamesEnum =
  | wifi.ToolName
  | facilities.ToolName
  | helpdesk.ToolName

export type ReportProblemTools =
  | wifi.ToolOptions
  | helpdesk.ToolOptions
  | facilities.ToolOptions

type ReduxStateProps = {
  fetching: boolean,
  tools: Array<ReportProblemTools>,
}

type ReduxDispatchProps = {
  getEnabledTools: () => mixed,
}

type Props = TopLevelViewPropsType & ReduxStateProps & ReduxDispatchProps

export class HelpView extends React.Component<Props> {
  static navigationOptions = {
    title: 'Help',
  }

  componentWillMount() {
    this.props.getEnabledTools()
  }

  render() {
    if (this.props.fetching) {
      return <LoadingScreen />
    }

    const tools = ALL_TOOLS.map(tool => [
      tool,
      this.props.tools.find(conf => conf.key === tool.toolName),
    ])

    const views = tools.map(
      ([tool, config]) =>
        config ? <tool.ToolView key={config.key} options={config} /> : null,
    )

    return (
      <ScrollView style={styles.contentContainer}>
        {views.length ? views : <EmptyListView />}
      </ScrollView>
    )
  }
}

function mapState(state: ReduxState): ReduxStateProps {
  if (!state.help) {
    return {
      fetching: false,
      tools: [],
    }
  }

  return {
    fetching: state.help.fetching,
    tools: state.help.tools,
    lastFetchError: state.help.lastFetchError,
  }
}

function mapDispatch(dispatch): ReduxDispatchProps {
  return {
    getEnabledTools: () => dispatch(getEnabledTools()),
  }
}

export default connect(mapState, mapDispatch)(HelpView)

const EmptyListView = () => (
  <View>
    <Text>No tools are enabled.</Text>
  </View>
)

const LoadingScreen = () => (
  <View>
    <Text>Loading…</Text>
  </View>
)

const styles = StyleSheet.create({
  contentContainer: {
    paddingTop: 10,
  },
})
<|endoftext|>


<commit_before>(function(window, factory) {
	var life = factory(window, window.document);
	window.rbLife = life;
	if(typeof module == 'object' && module.exports){
		module.exports = life;
	}
}(typeof window != 'undefined' ? window : this , function(window, document) {
	'use strict';

	var elements, useMutationEvents, timer;
	var docElem = document.documentElement;

	var life = {};
	var removeElements = [];
	var initClass = 'js-rb-life';
	var attachedClass = 'js-rb-attached';
	var rb = window.rb;
	var $ = rb.$;

	window.rb.life = life;

	life.init = function(options){
		if (elements) {throw('only once');}
		clearTimeout(timer);

		if (options) {
			initClass = options.initClass || initClass;
			attachedClass = options.attachedClass || attachedClass;
			useMutationEvents = options.useMutationEvents || false;
		}

		elements = document.getElementsByClassName(initClass);

		life.batch = life.createBatch();

		life.initObserver();
		life.throttledFindElements();
	};

	life.camelCase = (function() {
		var reg = /-([\da-z])/gi;
		var camelCase = function(all, found) {
			return found.toUpperCase();
		};

		return function(str) {
			return str.replace(reg, camelCase);
		};
	})();

	life.parseValue = (function() {
		var regNumber = /^\-*\+*\d+\.*\d*$/;
		var regObj = /^\[.*\]|\{.*\}$/;
		return function( attrVal ) {

			if(attrVal == 'true'){
				attrVal = true;
			}
			else if(attrVal == 'false'){
				attrVal = false;
			}
			else if(regNumber.test(attrVal)){
				attrVal = parseFloat(attrVal);
			}
			else if(regObj.test(attrVal)){
				try {
					attrVal = JSON.parse( attrVal );
				} catch(e){}
			}
			return attrVal;
		};
	})();

	life.createBatch = function(){
		var runs;
		var batch = [];
		var run = function() {
			while ( batch.length ) {
				batch.shift()();
			}
			runs = false;
		};
		return {
			run: run,
			add: function( fn ) {
				batch.push( fn );
			},
			timedRun: function() {
				if ( !runs ) {
					runs = true;
					setTimeout( run );
				}
			}
		};
	};

	life._failed = {};
	life._behaviors = {};
	life._attached = [];

	life.register = function(name, LifeClass, noCheck) {

		life._behaviors[ name ] = LifeClass;

		if ( !noCheck ) {
			if(!elements && !timer){
				timer = setTimeout(life.init);
			}
			life.throttledFindElements();
		}
	};

	life.create = function(element, LifeClass) {
		var instance, trigger;
		if ( !element._rbWidget ) {
			instance = new LifeClass( element );
			trigger = true;
		}

		rb.rAFQueue.add(function(){
			element.classList.add( attachedClass );
		});

		if (!element._rbCreated && instance && (instance.attached || instance.detached || instance.attachedOnce)) {
			life._attached.push(element);

			if(instance.attached){
				life.batch.add(function() {
					instance.attached();
				});
			}
			if(instance.onceAttached){
				life.batch.add(function() {
					instance.onceAttached();
				});
			}
			life.batch.timedRun();
		}
		element._rbCreated = true;

		if(trigger){
			life.batch.add(function() {
				$(element).trigger(LifeClass.prototype.name +'created');
			});
		}
		return instance;
	};

	life.findElements = function() {
		var module, modulePath, moduleId, i;

		var len = elements.length;

		for ( i = 0; i < len; i++ ) {
			module = elements[ i ];

			if(module._rbCreated){continue;}

			modulePath = module.getAttribute( 'data-module' ) || '';
			moduleId = modulePath.split( '/' );
			moduleId = moduleId[ moduleId.length - 1 ];

			if ( life._behaviors[ moduleId ] ) {
				life.create( module, life._behaviors[ moduleId ] );
				removeElements.push( module );
			}
			else if ( life._failed[ moduleId ] ) {
				removeElements.push( module );
			}
			else if ( modulePath && window.loadPackage ) {
				/* jshint loopfunc: true */
				(function (module, modulePath, moduleId) {
					setTimeout(function(){
						loadPackage(modulePath).then(function () {
							if (!life._behaviors[ moduleId ]) {
								module.classList.remove(initClass);
								life._failed[ moduleId ] = true;
							}
						});
					});
				})(module, modulePath, moduleId);
			}
			else {
				life._failed[ moduleId ] = true;
				removeElements.push(module);
			}
		}

		life.removeInitClass();

		life.batch.run();
	};

	life.removeInitClass = rb.rAF(function(){
		while (removeElements.length) {
			removeElements.shift().classList.remove(initClass);
		}
	});

	life.throttledFindElements = (function() {
		var setImmediate = window.setImmediate || window.setTimeout;
		var requestAnimationFrame = window.requestAnimationFrame;
		var runs = false;
		var runImmediate = function() {
			runs = false;
			life.findElements();
		};
		var rAFRun = function() {
			setImmediate(runImmediate);
		};
		return function () {
			if ( !runs ) {
				runs = true;
				requestAnimationFrame( rAFRun );
			}
		};
	})();

	life.destroyWidget = function(instance, index){
		var element = instance.element;

		if(index == null){
			index = life._attached.indexOf(element);
		}
		element.classList.remove( attachedClass );

		if(element._rbCreated){
			delete element._rbCreated;
		}
		if ( instance.detached ) {
			instance.detached( element, instance );
		}

		life._attached.splice(index, 1);
	};

	life.initObserver = function() {
		var removeWidgets = function() {
			var i, len, instance, element;

			for(i = 0, len = life._attached.length; i < len; i++){
				element = life._attached[i];
				if( !docElem.contains(element) ){
					instance = element._rbWidget;

					element.classList.add( initClass );
					life.destroyWidget(instance, i);

					i--;
					len--;
				}
			}
		};

		var onMutation = function( mutations ) {
			var i, mutation;
			var len = mutations.length;

			for ( i = 0; i < len; i++ ) {
				mutation = mutations[ i ];
				if ( mutation.addedNodes.length ) {
					life.throttledFindElements();
				}
				if ( mutation.removedNodes.length ) {
					removeWidgets( mutation.removedNodes );
				}
			}
		};

		if ( !useMutationEvents && window.MutationObserver ) {
			new MutationObserver( onMutation )
				.observe( docElem, { subtree: true, childList: true } )
			;
		} else {
			docElem.addEventListener('DOMNodeInserted', life.throttledFindElements);
			document.addEventListener('DOMContentLoaded', life.throttledFindElements);
			docElem.addEventListener('DOMNodeRemoved', (function(){
				var mutation = {
					addedNodes: []
				};
				var mutations = [
					mutation
				];
				var run = function(){
					onMutation(mutations);
					mutation.removedNodes = false;
				};
				return function(e){
					if (!mutation.removedNodes) {
						mutation.removedNodes = [];
						setTimeout(run, 9);
					}
					if (e.target.nodeType == 1) {
						mutation.removedNodes.push(e.target);
					}
				};
			})());
		}
	};

	return life;
}));

/* Simple JavaScript Inheritance
 * By John Resig http://ejohn.org/
 * MIT Licensed.
 */
// Inspired by base2 and Prototype
(function(){
	var initializing = false;
	var fnTest = (/xyz/.test(function(){var a = xyz;})) ?
		/\b_super\b/ :
		/.*/
	;

	// The base Class implementation (does nothing)
	window.rb.life.Class = function(){};

	// Create a new Class that inherits from this class
	window.rb.life.Class.extend = function(prop) {
		var name, prototype, origDescriptor, copyDescriptor, descProp, superDescriptor;
		var _super = this.prototype;

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

		// Copy the properties over onto the new prototype
		for (name in prop) {
			origDescriptor = Object.getOwnPropertyDescriptor(prop, name);
			if(!origDescriptor){continue;}

			superDescriptor = (name in _super && Object.getOwnPropertyDescriptor(_super, name));

			for(descProp in origDescriptor){
				// Check if we're overwriting an existing function and using super keyword
				origDescriptor[descProp] = superDescriptor && typeof origDescriptor[descProp] == "function" &&
					typeof superDescriptor[descProp] == "function" && fnTest.test(origDescriptor[descProp]) ?
					/* jshint loopfunc: true */
					(function(_superFn, fn){
						return function() {
							var tmp = this._super;

							// Add a new ._super() method that is the same method
							// but on the super-class
							this._super = _superFn;

							// The method only need to be bound temporarily, so we
							// remove it when we're done executing
							var ret = fn.apply(this, arguments);
							this._super = tmp;

							return ret;
						};
					})(superDescriptor[descProp], origDescriptor[descProp]) :
					origDescriptor[descProp]
				;
			}

			Object.defineProperty(prototype, name, origDescriptor);
		}

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

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

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

		// And make this class extendable
		Class.extend = this.extend || window.rb.life.Class.extend;

		return Class;
	};
})();

(function(window, document, life, undefined){
	'use strict';

	var idIndex = 0;
	var regData = /^data-/;
	var $ = window.rb.$;

	life.getWidget = function(element, key, args){
		var ret, moduleId;
		var widget = element && element._rbWidget;

		if(!widget){
			moduleId = (element.getAttribute( 'data-module' ) || '').split( '/' );
			moduleId = moduleId[ moduleId.length - 1 ];

			if(life._behaviors[ moduleId ]){
				widget = life.create(element, life._behaviors[ moduleId ]);
			}
		}

		ret = widget;
		if(widget && key){
			ret = widget[key];

			if(typeof ret == 'function'){
				ret = ret.apply(widget, args || []);
			} else if(args !== undefined){
				widget[key] = args;
				ret = undefined;
			}
		}
		return ret;
	};

	life.Widget = life.Class.extend({
		defaults: {},
		init: function(element){
			this.element = element;
			this.$element = $(element);
			this.options = {};

			this.parseOptions(this.options, this.constructor.defaults);

			this.setupLifeOptions();

			element._rbWidget = this;
		},
		widget: life.getWidget,
		setupLifeOptions: function(){
			var runs, runner, onResize;
			var old = {};
			var that = this;
			if (this.options.watchCSS) {
				old.attached = this.attached;
				old.detached = this.detached;
				runner = function() {
					runs = false;
					if(that._styleOptsStr != (getComputedStyle(that.element, '::after').getPropertyValue('content') || '')){
						that.parseOptions();
					}
				};
				onResize = function() {
					if(!runs){
						runs = true;
						setTimeout(runner, 33);
					}
				};

				this.attached = function(){
					window.addEventListener('resize', onResize);
					if(old.attached){
						return old.attached.apply(this, arguments);
					}
				};
				this.detached = function(){
					window.removeEventListener('resize', onResize);
					if(old.detached){
						return old.detached.apply(this, arguments);
					}
				};
			}

		},

		getId: function(element){
			var id = (element || this.element).id;
			if (!id) {
				idIndex++;
				id = 'rbjsid-' + idIndex;
				(element || this.element).id = id;
			}
			return id;
		},

		setFocus: function(elem){
			try {
				setTimeout(function(){
					$(elem).trigger('rbscriptfocus');
					elem.focus();
				}, 0);
			} catch(e){}
		},

		parseOptions: function(opts, defaults){
			var options = Object.assign(opts || {}, defaults || {}, this.parseCSSOptions() || {}, this.parseHTMLOptions());
			this.setOptions(options);
		},

		setOptions: function(opts){
			for(var prop in opts){
				if(opts[prop] != this.options[prop]){
					this.setOption(prop, opts[prop]);
				}
			}
		},

		setOption: function(name, value){
			this.options[name] = value;
		},

		parseHTMLOptions: function(){
			var i, name;
			var options = {};
			var attributes = this.element.attributes;
			var len = attributes.length;

			for ( i = 0; i < len; i++ ) {
				name = attributes[ i ].nodeName;
				if ( !name.indexOf( 'data-' ) ) {
					options[ life.camelCase( name.replace( regData , '' ) ) ] = life.parseValue( attributes[ i ].nodeValue );
				}
			}

			return options;
		},

		parseCSSOptions: function(){
			var style = getComputedStyle(this.element, '::after').getPropertyValue('content') || '';
			if(style && (!this._styleOptsStr || style != this._styleOptsStr )){
				this._styleOptsStr = style;
				try {
					style = JSON.parse(style.replace(/^"*'*"*/, '').replace(/"*'*"*$/, '').replace(/\\"/g, '"'));
				} catch(e){
					style = false;
				}
			} else {
				style = false;
			}

			return style;
		},

		destroy: function(){
			life.destroyWidget(this);
		}
	});

	life.Widget.extend = function(name, prop){
		var Class;

		if(!prop.name){
			prop.name = name;
		}
		Class = life.Class.extend.call(this, prop);
		Class.defaults = prop.defaults || {};
		life.register(name, Class);
		return Class;
	};
})(window, document, rb.life);
<commit_msg>improvements<commit_after>(function(window, factory) {
	var life = factory(window, window.document);
	window.rbLife = life;
	if(typeof module == 'object' && module.exports){
		module.exports = life;
	}
}(typeof window != 'undefined' ? window : this , function(window, document) {
	'use strict';

	var elements, useMutationEvents, timer;
	var docElem = document.documentElement;

	var life = {};
	var removeElements = [];
	var initClass = 'js-rb-life';
	var attachedClass = 'js-rb-attached';
	var rb = window.rb;
	var $ = rb.$;

	window.rb.life = life;

	life.init = function(options){
		if (elements) {throw('only once');}
		clearTimeout(timer);

		if (options) {
			initClass = options.initClass || initClass;
			attachedClass = options.attachedClass || attachedClass;
			useMutationEvents = options.useMutationEvents || false;
		}

		elements = document.getElementsByClassName(initClass);

		life.batch = life.createBatch();

		life.initObserver();
		life.throttledFindElements();
	};

	life.camelCase = (function() {
		var reg = /-([\da-z])/gi;
		var camelCase = function(all, found) {
			return found.toUpperCase();
		};

		return function(str) {
			return str.replace(reg, camelCase);
		};
	})();

	life.parseValue = (function() {
		var regNumber = /^\-*\+*\d+\.*\d*$/;
		var regObj = /^\[.*\]|\{.*\}$/;
		return function( attrVal ) {

			if(attrVal == 'true'){
				attrVal = true;
			}
			else if(attrVal == 'false'){
				attrVal = false;
			}
			else if(regNumber.test(attrVal)){
				attrVal = parseFloat(attrVal);
			}
			else if(regObj.test(attrVal)){
				try {
					attrVal = JSON.parse( attrVal );
				} catch(e){}
			}
			return attrVal;
		};
	})();

	life.createBatch = function(){
		var runs;
		var batch = [];
		var run = function() {
			while ( batch.length ) {
				batch.shift()();
			}
			runs = false;
		};
		return {
			run: run,
			add: function( fn ) {
				batch.push( fn );
			},
			timedRun: function() {
				if ( !runs ) {
					runs = true;
					setTimeout( run );
				}
			}
		};
	};

	life._failed = {};
	life._behaviors = {};
	life._attached = [];

	life.register = function(name, LifeClass, noCheck) {

		life._behaviors[ name ] = LifeClass;

		if ( !noCheck ) {
			if(!elements && !timer){
				timer = setTimeout(life.init);
			}
			life.throttledFindElements();
		}
	};

	life.create = function(element, LifeClass) {
		var instance, trigger;
		if ( !element._rbWidget ) {
			instance = new LifeClass( element );
			trigger = true;
		}

		rb.rAFQueue.add(function(){
			element.classList.add( attachedClass );
		});

		if (!element._rbCreated && instance && (instance.attached || instance.detached || instance.attachedOnce)) {
			life._attached.push(element);

			if(instance.attached){
				life.batch.add(function() {
					instance.attached();
				});
			}
			if(instance.onceAttached){
				life.batch.add(function() {
					instance.onceAttached();
				});
			}
			life.batch.timedRun();
		}
		element._rbCreated = true;

		if(trigger){
			life.batch.add(function() {
				$(element).trigger(LifeClass.prototype.name +'created');
			});
		}
		return instance;
	};

	life.findElements = function() {
		var module, modulePath, moduleId, i;

		var len = elements.length;

		for ( i = 0; i < len; i++ ) {
			module = elements[ i ];

			if(module._rbCreated){continue;}

			modulePath = module.getAttribute( 'data-module' ) || '';
			moduleId = modulePath.split( '/' );
			moduleId = moduleId[ moduleId.length - 1 ];

			if ( life._behaviors[ moduleId ] ) {
				life.create( module, life._behaviors[ moduleId ] );
				removeElements.push( module );
			}
			else if ( life._failed[ moduleId ] ) {
				removeElements.push( module );
			}
			else if ( modulePath && window.loadPackage ) {
				/* jshint loopfunc: true */
				(function (module, modulePath, moduleId) {
					setTimeout(function(){
						loadPackage(modulePath).then(function () {
							if (!life._behaviors[ moduleId ]) {
								module.classList.remove(initClass);
								life._failed[ moduleId ] = true;
							}
						});
					});
				})(module, modulePath, moduleId);
			}
			else {
				life._failed[ moduleId ] = true;
				removeElements.push(module);
			}
		}

		life.removeInitClass();

		life.batch.run();
	};

	life.removeInitClass = rb.rAF(function(){
		while (removeElements.length) {
			removeElements.shift().classList.remove(initClass);
		}
	});

	life.throttledFindElements = (function() {
		var setImmediate = window.setImmediate || window.setTimeout;
		var requestAnimationFrame = window.requestAnimationFrame;
		var runs = false;
		var runImmediate = function() {
			runs = false;
			life.findElements();
		};
		var rAFRun = function() {
			setImmediate(runImmediate);
		};
		return function () {
			if ( !runs ) {
				runs = true;
				requestAnimationFrame( rAFRun );
			}
		};
	})();

	life.destroyWidget = function(instance, index){
		var element = instance.element;

		if(index == null){
			index = life._attached.indexOf(element);
		}
		element.classList.remove( attachedClass );

		if(element._rbCreated){
			delete element._rbCreated;
		}
		if ( instance.detached ) {
			instance.detached( element, instance );
		}

		life._attached.splice(index, 1);
	};

	life.initObserver = function() {
		var removeWidgets = function() {
			var i, len, instance, element;

			for(i = 0, len = life._attached.length; i < len; i++){
				element = life._attached[i];
				if( !docElem.contains(element) ){
					instance = element._rbWidget;

					element.classList.add( initClass );
					life.destroyWidget(instance, i);

					i--;
					len--;
				}
			}
		};

		var onMutation = function( mutations ) {
			var i, mutation;
			var len = mutations.length;

			for ( i = 0; i < len; i++ ) {
				mutation = mutations[ i ];
				if ( mutation.addedNodes.length ) {
					life.throttledFindElements();
				}
				if ( mutation.removedNodes.length ) {
					removeWidgets( mutation.removedNodes );
				}
			}
		};

		if ( !useMutationEvents && window.MutationObserver ) {
			new MutationObserver( onMutation )
				.observe( docElem, { subtree: true, childList: true } )
			;
		} else {
			docElem.addEventListener('DOMNodeInserted', life.throttledFindElements);
			document.addEventListener('DOMContentLoaded', life.throttledFindElements);
			docElem.addEventListener('DOMNodeRemoved', (function(){
				var mutation = {
					addedNodes: []
				};
				var mutations = [
					mutation
				];
				var run = function(){
					onMutation(mutations);
					mutation.removedNodes = false;
				};
				return function(e){
					if (!mutation.removedNodes) {
						mutation.removedNodes = [];
						setTimeout(run, 9);
					}
					if (e.target.nodeType == 1) {
						mutation.removedNodes.push(e.target);
					}
				};
			})());
		}
	};

	return life;
}));

/* Simple JavaScript Inheritance
 * By John Resig http://ejohn.org/
 * MIT Licensed.
 */
// Inspired by base2 and Prototype
(function(){
	var initializing = false;
	var fnTest = (/xyz/.test(function(){var a = xyz;})) ?
		/\b_super\b/ :
		/.*/
	;

	// The base Class implementation (does nothing)
	window.rb.life.Class = function(){};

	// Create a new Class that inherits from this class
	window.rb.life.Class.extend = function(prop) {
		var name, prototype, origDescriptor, copyDescriptor, descProp, superDescriptor;
		var _super = this.prototype;

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

		// Copy the properties over onto the new prototype
		for (name in prop) {
			origDescriptor = Object.getOwnPropertyDescriptor(prop, name);
			if(!origDescriptor){continue;}

			superDescriptor = (name in _super && Object.getOwnPropertyDescriptor(_super, name));

			for(descProp in origDescriptor){
				// Check if we're overwriting an existing function and using super keyword
				origDescriptor[descProp] = superDescriptor && typeof origDescriptor[descProp] == "function" &&
					typeof superDescriptor[descProp] == "function" && fnTest.test(origDescriptor[descProp]) ?
					/* jshint loopfunc: true */
					(function(_superFn, fn){
						return function() {
							var tmp = this._super;

							// Add a new ._super() method that is the same method
							// but on the super-class
							this._super = _superFn;

							// The method only need to be bound temporarily, so we
							// remove it when we're done executing
							var ret = fn.apply(this, arguments);
							this._super = tmp;

							return ret;
						};
					})(superDescriptor[descProp], origDescriptor[descProp]) :
					origDescriptor[descProp]
				;
			}

			Object.defineProperty(prototype, name, origDescriptor);
		}

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

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

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

		// And make this class extendable
		Class.extend = this.extend || window.rb.life.Class.extend;

		return Class;
	};
})();

(function(window, document, life, undefined){
	'use strict';

	var idIndex = 0;
	var regData = /^data-/;
	var $ = window.rb.$;

	life.getWidget = function(element, key, args){
		var ret, moduleId;
		var widget = element && element._rbWidget;

		if(!widget){
			moduleId = (element.getAttribute( 'data-module' ) || '').split( '/' );
			moduleId = moduleId[ moduleId.length - 1 ];

			if(life._behaviors[ moduleId ]){
				widget = life.create(element, life._behaviors[ moduleId ]);
			}
		}

		ret = widget;
		if(widget && key){
			ret = widget[key];

			if(typeof ret == 'function'){
				ret = ret.apply(widget, args || []);
			} else if(args !== undefined){
				widget[key] = args;
				ret = undefined;
			}
		}
		return ret;
	};

	life.Widget = life.Class.extend({
		defaults: {},
		init: function(element){
			this.element = element;
			this.$element = $(element);
			this.options = {};

			this.parseOptions(this.options, this.constructor.defaults);

			this.setupLifeOptions();

			element._rbWidget = this;
		},
		widget: life.getWidget,
		setupLifeOptions: function(){
			var runs, runner, onResize;
			var old = {};
			var that = this;
			if (this.options.watchCSS) {
				old.attached = this.attached;
				old.detached = this.detached;
				runner = function() {
					runs = false;
					if(that._styleOptsStr != (getComputedStyle(that.element, '::after').getPropertyValue('content') || '')){
						that.parseOptions();
					}
				};
				onResize = function() {
					if(!runs){
						runs = true;
						setTimeout(runner, 33);
					}
				};

				this.attached = function(){
					window.addEventListener('resize', onResize);
					if(old.attached){
						return old.attached.apply(this, arguments);
					}
				};
				this.detached = function(){
					window.removeEventListener('resize', onResize);
					if(old.detached){
						return old.detached.apply(this, arguments);
					}
				};
			}

		},

		getId: function(element){
			var id = (element || this.element).id;
			if (!id) {
				idIndex++;
				id = 'rbjsid-' + idIndex;
				(element || this.element).id = id;
			}
			return id;
		},

		setFocus: function(elem){
			try {
				setTimeout(function(){
					$(elem).trigger('rbscriptfocus');
					elem.focus();
				}, 0);
			} catch(e){}
		},

		parseOptions: function(opts, defaults){
			var options = Object.assign(opts || {}, defaults || {}, this.parseCSSOptions() || {}, this.parseHTMLOptions());
			this.setOptions(options);
		},

		setOptions: function(opts){
			for(var prop in opts){
				if(opts[prop] != this.options[prop]){
					this.setOption(prop, opts[prop]);
				}
			}
		},

		setOption: function(name, value){
			this.options[name] = value;
		},

		parseHTMLOptions: function(element){
			var i, name;
			var options = {};
			var attributes = (element || this.element).attributes;
			var len = attributes.length;

			for ( i = 0; i < len; i++ ) {
				name = attributes[ i ].nodeName;
				if ( !name.indexOf( 'data-' ) ) {
					options[ life.camelCase( name.replace( regData , '' ) ) ] = life.parseValue( attributes[ i ].nodeValue );
				}
			}

			return options;
		},

		parseCSSOptions: function(element){
			var style = getComputedStyle(element || this.element, '::after').getPropertyValue('content') || '';
			if(style && (!this._styleOptsStr || style != this._styleOptsStr )){
				this._styleOptsStr = style;
				try {
					style = JSON.parse(style.replace(/^"*'*"*/, '').replace(/"*'*"*$/, '').replace(/\\"/g, '"'));
				} catch(e){
					style = false;
				}
			} else {
				style = false;
			}

			return style;
		},

		destroy: function(){
			life.destroyWidget(this);
		}
	});

	life.Widget.extend = function(name, prop){
		var Class;

		if(!prop.name){
			prop.name = name;
		}
		Class = life.Class.extend.call(this, prop);
		Class.defaults = prop.defaults || {};
		life.register(name, Class);
		return Class;
	};
})(window, document, rb.life);
<|endoftext|>