<commit_before>/*
 *  Lister.js - v0.5.0
 *  A jQuery plugin to make lists from selects.
 *  http://jsumnersmith.github.io/lister
 *
 *  Made by Joel Smith
 *  Under MIT License
 */
// the semi-colon before function invocation is a safety net against concatenated
// scripts and/or other plugins which may not be closed properly.
;(function ( $, window, document, undefined ) {

    // Create the defaults once
    var pluginName = "lister";
    defaults = {
        listClass: "lister",
        openListClass: "lister-open",
        selectedClass: "lister-selected",
        selectedTop: true,
        selectedTopText: true,
        selectedTopWrapperClass: "lister-selected-top",
        populateSelectedTop: true,
        listClickCallback: function() {},
        selectedTopOpenCallback: function(self) {},
        selectedTopCloseCallback: function(self) {}
    };

    // The actual plugin constructor
    function Lister ( element, options ) {
        // Let's always use self
        var self = this;
        self.element = element;
        self.$element = $(self.element);
        self.settings = $.extend( {}, defaults, options );
        self._defaults = defaults;
        self._name = pluginName;
        self.init();
    }

    Lister.prototype = {

        init: function () {
            // Cache the constructor object
            var self = this;
            // First let's create the markup
            self.cloneSelect();

            // We'll need a special check on the select
            // item itself to pass info around appropriately.
            self.selectItemClick();
            //Add the click event that will close lister
            //when we click elsewhere on page
            self.elsewhereClick();

            if (self.settings.selectedTop) {
                self.createSelectedTop();
                self.selectedTopClick();
            }
        },

        cloneSelect: function() {
            // Cache the constructor object
            var self = this;

            // Loop through and build out the
            // jQuery object; duplicate as necessary;
            self.$element.each(function(){
                var $thisSelect = $(this);

                //Create the new list
                var thisList = $thisSelect.clone().wrap("

").parent().html().replace(/select/g,"ul").replace(/option/g,"li");

                // Make the jQuery object
                var $thisList = $(thisList);

                //Give the list an appropriate class.
                $thisList.addClass(self.settings.listClass);

                //Insert the new list into the DOM.
                $thisSelect.after($thisList);

                // If the option has been passed in, let's also create a new

                // above the
 to house the selected item.
                if (self.settings.selectedTop) {
                }
                //Now that this is a thing, let's bind the clicks
                // Then, let's bind the UI back to the
                // original selects.

            });
            self.listItemClick();
        },

        listItemClick: function() {

            // Cache the constructor object
            var self = this;

            // Create the jQuery object of all appropriates
            // lists given a list class.

            //N.B. We may want to contain this in another div, to avoid confusion.
            // In apostrophe, our ass has been saved, though.
            var $list = self.$element.siblings("ul."+self.settings.listClass);

            // Create the jQuery object of all appropriate
            // list items, given a list class.
            var $listItem = $list.find("li");

            // Create a click event for the list items.
            $listItem.click(function(event){
                // Cache the clicked item
                var $thisItem = $(this);
                // For a given list item, find the preceding <select>
                var $thisItemSelect = $thisItem.parent().prev(self.$element);
                // Stop this click event from bubbling up the DOM
                event.stopPropagation();
                // Add the selected class to the clicked item after
                // removing the class from all the list items.
                $listItem.removeClass(self.settings.selectedClass);
                $thisItem.addClass(self.settings.selectedClass);

                // On click remove the parent class of openListClass
                if ($thisItem.parent().hasClass(self.settings.openListClass)){
                    $thisItem.parent().removeClass(self.settings.openListClass);
                }

                // For a given list item, find the equivalent
                // <option> in the original select item.
                var $thisItemEquivalent = $thisItemSelect.find("option").eq($thisItem.index());

                // For each click event, set the equivalent <option> to selected.
                $thisItemEquivalent.prop("selected", true);

                // Trigger a change event on the equivalent <select> element
                self.$element.trigger('change');

                // If we've passed in the option for the selected top section,
                // let's bind the appropriate clicks to it.
                if (self.settings.selectedTop) {
                    // Let's make a jQuery object out of the container
                    //
 for selectedTop
                    var $thisSelectedTop = $($thisItemSelect.prev("."+self.settings.selectedTopWrapperClass));

                    // Let's add the text to the element.
                    $thisSelectedTop.text($thisItemEquivalent.text());
                }
                // Let's allow for a callback on the click event.
                if (self.settings.listClickCallback) {
                    self.settings.listClickCallback();
                }
            });
        },

        selectItemClick: function() {
            var self = this;

            var $selects = self.$element;
            var $selectOption = $selects.find("option");

            // $selectOption.on("click", function(event){
            //   console.log("I'm finally working");
            //   var $thisOption = $(this);
            //   var $thisSelect = $thisOption.parent("select");
            //   var $thisList = $thisSelect.next("ul."+self.settings.listClass);
            //   var $thisListItems = $thisList.find("li");
            //   var $thisListItemEquivalent = $thisList.find("li").eq($thisOption.index());

            //   $thisListItems.removeClass(self.setting.selectedClass);
            //   $thisListItemEquivalent.addClass(self.setting.selectedClass);
            // });

            self.$element.on("change", function(event){
                var $select = $(this);
                var selectValue = $select.val();
                var $selectOptions = $select.find("option");
                var $thisList = $select.next("ul."+self.settings.listClass);
                var $thisListItems = $thisList.find("li");

                var $selectedTop = $select.prev("."+self.settings.selectedTopWrapperClass);
                $selectOptions.each(function(){
                    var $self = $(this);
                    if($self.val() === selectValue) {
                        var $thisListItemEquivalent = $thisList.find("li").eq($self.index());
                        $thisListItems.removeClass(self.settings.selectedClass);
                        $thisListItemEquivalent.addClass(self.settings.selectedClass);
                        $selectedTop.text($self.text());
                    }
                })
                    });
        },

        createSelectedTop: function() {
            var self = this;

            self.$element.before("

");
            // console.log($selectedTop);
            //First, let's make an object of all the selected tops
            var $selectedTop = $(self.$element.prev("."+self.settings.selectedTopWrapperClass));

            // Then, we'll need to find the closest

            // TO-DO: make sure this only selects the next

            var $nextSelect = $selectedTop.next("select");
            var $nextList = $nextSelect.next("ul");

            if (self.settings.populateSelectedTop) {

                var selectVal = self.$element.val();
                var $selectedOption = self.$element.find('option[value="'+selectVal+'"]');

                if (selectVal === undefined) {
                   $selectedOption = self.$element.children("option").first();
                }
                $selectedTop.text($selectedOption.text());

            }
        },

        selectedTopClick: function() {
            var self = this;
            var $selectedTop = $(self.$element.prev("."+self.settings.selectedTopWrapperClass));
            var $nextSelect = $selectedTop.next("select");
            var $nextList = $nextSelect.next("ul");
            $selectedTop.click(function(event){
                // Stop this click event from bubbling up the DOM
                event.stopPropagation();
                // TO-DO: add callbacks on this click event.
                if ($nextList.hasClass(self.settings.openListClass)){
                    $nextList.removeClass(self.settings.openListClass);
                    self.settings.selectedTopCloseCallback(self);
                } else {
                    $nextList.addClass(self.settings.openListClass);
                    self.settings.selectedTopOpenCallback(self);
                }
            });
        },
        // close the list if the list is open and you click elsewhere
        elsewhereClick: function() {
            var self = this;
            var $elsewhere = $('html');
            var $list = self.$element.siblings("ul."+self.settings.listClass);

            $elsewhere.click(function() {
                if ($list.hasClass(self.settings.openListClass)){
                    $list.removeClass(self.settings.openListClass);
                    self.settings.selectedTopCloseCallback(self);
                } else {
                    return null;
                }
            });
        }
    };

    // A really lightweight plugin wrapper around the constructor,
    // preventing against multiple instantiations
    $.fn.lister = function ( options ) {
        return this.each(function() {
            if ( !$.data( this, "plugin_" + pluginName ) ) {
                $.data( this, "plugin_" + pluginName, new Lister( this, options ) );
            }
        });
    };

})( jQuery, window, document );
<commit_msg>added select and item arguments to listClickCallback<commit_after>/*
 *  Lister.js - v0.5.0
 *  A jQuery plugin to make lists from selects.
 *  http://jsumnersmith.github.io/lister
 *
 *  Made by Joel Smith
 *  Under MIT License
 */
// the semi-colon before function invocation is a safety net against concatenated
// scripts and/or other plugins which may not be closed properly.
;(function ( $, window, document, undefined ) {

    // Create the defaults once
    var pluginName = "lister";
    defaults = {
        listClass: "lister",
        openListClass: "lister-open",
        selectedClass: "lister-selected",
        selectedTop: true,
        selectedTopText: true,
        selectedTopWrapperClass: "lister-selected-top",
        populateSelectedTop: true,
        listClickCallback: function() {},
        selectedTopOpenCallback: function(self) {},
        selectedTopCloseCallback: function(self) {}
    };

    // The actual plugin constructor
    function Lister ( element, options ) {
        // Let's always use self
        var self = this;
        self.element = element;
        self.$element = $(self.element);
        self.settings = $.extend( {}, defaults, options );
        self._defaults = defaults;
        self._name = pluginName;
        self.init();
    }

    Lister.prototype = {

        init: function () {
            // Cache the constructor object
            var self = this;
            // First let's create the markup
            self.cloneSelect();

            // We'll need a special check on the select
            // item itself to pass info around appropriately.
            self.selectItemClick();
            //Add the click event that will close lister
            //when we click elsewhere on page
            self.elsewhereClick();

            if (self.settings.selectedTop) {
                self.createSelectedTop();
                self.selectedTopClick();
            }
        },

        cloneSelect: function() {
            // Cache the constructor object
            var self = this;

            // Loop through and build out the
            // jQuery object; duplicate as necessary;
            self.$element.each(function(){
                var $thisSelect = $(this);

                //Create the new list
                var thisList = $thisSelect.clone().wrap("

").parent().html().replace(/select/g,"ul").replace(/option/g,"li");

                // Make the jQuery object
                var $thisList = $(thisList);

                //Give the list an appropriate class.
                $thisList.addClass(self.settings.listClass);

                //Insert the new list into the DOM.
                $thisSelect.after($thisList);

                // If the option has been passed in, let's also create a new

                // above the
 to house the selected item.
                if (self.settings.selectedTop) {
                }
                //Now that this is a thing, let's bind the clicks
                // Then, let's bind the UI back to the
                // original selects.

            });
            self.listItemClick();
        },

        listItemClick: function() {

            // Cache the constructor object
            var self = this;

            // Create the jQuery object of all appropriates
            // lists given a list class.

            //N.B. We may want to contain this in another div, to avoid confusion.
            // In apostrophe, our ass has been saved, though.
            var $list = self.$element.siblings("ul."+self.settings.listClass);

            // Create the jQuery object of all appropriate
            // list items, given a list class.
            var $listItem = $list.find("li");

            // Create a click event for the list items.
            $listItem.click(function(event){
                // Cache the clicked item
                var $thisItem = $(this);
                // For a given list item, find the preceding <select>
                var $thisItemSelect = $thisItem.parent().prev(self.$element);
                // Stop this click event from bubbling up the DOM
                event.stopPropagation();
                // Add the selected class to the clicked item after
                // removing the class from all the list items.
                $listItem.removeClass(self.settings.selectedClass);
                $thisItem.addClass(self.settings.selectedClass);

                // On click remove the parent class of openListClass
                if ($thisItem.parent().hasClass(self.settings.openListClass)){
                    $thisItem.parent().removeClass(self.settings.openListClass);
                }

                // For a given list item, find the equivalent
                // <option> in the original select item.
                var $thisItemEquivalent = $thisItemSelect.find("option").eq($thisItem.index());

                // For each click event, set the equivalent <option> to selected.
                $thisItemEquivalent.prop("selected", true);

                // Trigger a change event on the equivalent <select> element
                self.$element.trigger('change');

                // If we've passed in the option for the selected top section,
                // let's bind the appropriate clicks to it.
                if (self.settings.selectedTop) {
                    // Let's make a jQuery object out of the container
                    //
 for selectedTop
                    var $thisSelectedTop = $($thisItemSelect.prev("."+self.settings.selectedTopWrapperClass));

                    // Let's add the text to the element.
                    $thisSelectedTop.text($thisItemEquivalent.text());
                }
                // Let's allow for a callback on the click event.
                if (self.settings.listClickCallback) {
                    self.settings.listClickCallback(self.$element, $thisItemEquivalent);
                }
            });
        },

        selectItemClick: function() {
            var self = this;

            var $selects = self.$element;
            var $selectOption = $selects.find("option");

            // $selectOption.on("click", function(event){
            //   console.log("I'm finally working");
            //   var $thisOption = $(this);
            //   var $thisSelect = $thisOption.parent("select");
            //   var $thisList = $thisSelect.next("ul."+self.settings.listClass);
            //   var $thisListItems = $thisList.find("li");
            //   var $thisListItemEquivalent = $thisList.find("li").eq($thisOption.index());

            //   $thisListItems.removeClass(self.setting.selectedClass);
            //   $thisListItemEquivalent.addClass(self.setting.selectedClass);
            // });

            self.$element.on("change", function(event){
                var $select = $(this);
                var selectValue = $select.val();
                var $selectOptions = $select.find("option");
                var $thisList = $select.next("ul."+self.settings.listClass);
                var $thisListItems = $thisList.find("li");

                var $selectedTop = $select.prev("."+self.settings.selectedTopWrapperClass);
                $selectOptions.each(function(){
                    var $self = $(this);
                    if($self.val() === selectValue) {
                        var $thisListItemEquivalent = $thisList.find("li").eq($self.index());
                        $thisListItems.removeClass(self.settings.selectedClass);
                        $thisListItemEquivalent.addClass(self.settings.selectedClass);
                        $selectedTop.text($self.text());
                    }
                })
                    });
        },

        createSelectedTop: function() {
            var self = this;

            self.$element.before("

");
            // console.log($selectedTop);
            //First, let's make an object of all the selected tops
            var $selectedTop = $(self.$element.prev("."+self.settings.selectedTopWrapperClass));

            // Then, we'll need to find the closest

            // TO-DO: make sure this only selects the next

            var $nextSelect = $selectedTop.next("select");
            var $nextList = $nextSelect.next("ul");

            if (self.settings.populateSelectedTop) {

                var selectVal = self.$element.val();
                var $selectedOption = self.$element.find('option[value="'+selectVal+'"]');

                if (selectVal === undefined) {
                   $selectedOption = self.$element.children("option").first();
                }
                $selectedTop.text($selectedOption.text());

            }
        },

        selectedTopClick: function() {
            var self = this;
            var $selectedTop = $(self.$element.prev("."+self.settings.selectedTopWrapperClass));
            var $nextSelect = $selectedTop.next("select");
            var $nextList = $nextSelect.next("ul");
            $selectedTop.click(function(event){
                // Stop this click event from bubbling up the DOM
                event.stopPropagation();
                // TO-DO: add callbacks on this click event.
                if ($nextList.hasClass(self.settings.openListClass)){
                    $nextList.removeClass(self.settings.openListClass);
                    self.settings.selectedTopCloseCallback(self);
                } else {
                    $nextList.addClass(self.settings.openListClass);
                    self.settings.selectedTopOpenCallback(self);
                }
            });
        },
        // close the list if the list is open and you click elsewhere
        elsewhereClick: function() {
            var self = this;
            var $elsewhere = $('html');
            var $list = self.$element.siblings("ul."+self.settings.listClass);

            $elsewhere.click(function() {
                if ($list.hasClass(self.settings.openListClass)){
                    $list.removeClass(self.settings.openListClass);
                    self.settings.selectedTopCloseCallback(self);
                } else {
                    return null;
                }
            });
        }
    };

    // A really lightweight plugin wrapper around the constructor,
    // preventing against multiple instantiations
    $.fn.lister = function ( options ) {
        return this.each(function() {
            if ( !$.data( this, "plugin_" + pluginName ) ) {
                $.data( this, "plugin_" + pluginName, new Lister( this, options ) );
            }
        });
    };

})( jQuery, window, document );
<|endoftext|>


<commit_before>/*
    RateIt
    version 1.0
    06/11/2011
    http://rateit.codeplex.com
    Twitter: @gjunge

*/
(function ($) {
    $.fn.rateit = function (p1, p2) {
        //quick way out.
        var options = {}; var mode = 'init';
        if (this.length == 0) return this;

        var tp1 = $.type(p1);
        if (tp1 == 'object' || p1 === undefined || p1 == null) {
            options = $.extend({}, $.fn.rateit.defaults, p1); //wants to init new rateit plugin(s).
        }
        else if (tp1 == 'string' && p2 === undefined) {
            return this.data('rateit-' + p1); //wants to get a value.
        }
        else if (tp1 == 'string') {
            mode = 'setvalue'
        }

        return this.each(function () {
            var item = $(this);

            //shorten all the item.data('rateit-XXX'), will save space in closure compiler, will be like item.data('XXX') will become x('XXX')
            var itemdata = function (key, value) { return item.data('rateit-' + key, value); };

            //add the rate it class.
            if (!item.hasClass('rateit')) item.addClass('rateit');

            var ltr = item.css('direction') != 'rtl';

            // set value mode
            if (mode == 'setvalue') {
                if (!itemdata('init')) throw 'Can\'t set value before init';

                //if readonly now and it wasn't readonly, remove the eventhandlers.
                if (p1 == 'readonly' && !itemdata('readonly')) {
                    item.find('.rateit-range').unbind();
                    itemdata('wired', false);
                }

                if (itemdata('backingfld')) {
                    //if we have a backing field, check which fields we should update.
                    //In case of input[type=range], although we did read its attributes even in browsers that don't support it (using fld.attr())
                    //we only update it in browser that support it (&& fld[0].min only works in supporting browsers), not only does it save us from checking if it is range input type, it also is unnecessary.
                    var fld = $(itemdata('backingfld'));
                    if (p1 == 'value') fld.val(p2);
                    if (p1 == 'min' && fld[0].min) fld[0].min = p2;
                    if (p1 == 'max' && fld[0].max) fld[0].max = p2;
                    if (p1 == 'step' && fld[0].step) fld[0].step = p2;
                }

                itemdata(p1, p2);
            }

            //init rateit plugin
            if (!itemdata('init')) {

                //get our values, either from the data-* html5 attribute or from the options.
                itemdata('min', itemdata('min') || options.min);
                itemdata('max', itemdata('max') || options.max);
                itemdata('step', itemdata('step') || options.step);
                itemdata('readonly', itemdata('readonly') !== undefined ? itemdata('readonly') : options.readonly);
                itemdata('resetable', itemdata('resetable') !== undefined ? itemdata('resetable') : options.resetable);
                itemdata('backingfld', itemdata('backingfld') || options.backingfld);
                itemdata('starwidth', itemdata('starwidth') || options.starwidth);
                itemdata('starheight', itemdata('starheight') || options.starheight);
                itemdata('value', itemdata('value') || options.min);
                itemdata('ispreset', itemdata('ispreset') !== undefined ? itemdata('ispreset') : options.ispreset);
                //are we LTR or RTL?

                if (itemdata('backingfld')) {
                    //if we have a backing field, hide it, and get its value, and override defaults if range.
                    var fld = $(itemdata('backingfld'));
                    itemdata('value', fld.hide().val());

                    if (fld[0].nodeName == 'INPUT') {
                        if (fld[0].type == 'range' || fld[0].type == 'text') { //in browsers not support the range type, it defaults to text

                            itemdata('min', parseInt(fld.attr('min')) || itemdata('min')); //if we would have done fld[0].min it wouldn't have worked in browsers not supporting the range type.
                            itemdata('max', parseInt(fld.attr('max')) || itemdata('max'));
                            itemdata('step', parseInt(fld.attr('step')) || itemdata('step'));
                        }
                    }
                    if (fld[0].nodeName == 'SELECT' && fld[0].options.length > 1) {
                        itemdata('min', Number(fld[0].options[0].value));
                        itemdata('max', Number(fld[0].options[fld[0].length - 1].value));
                        itemdata('step', Number(fld[0].options[1].value) - Number(fld[0].options[0].value));
                    }
                }

                //Create the necessary tags.
                item.append('

');

                //if we are in RTL mode, we have to change the float of the "reset button"
                if (!ltr) {
                    item.find('.rateit-reset').css('float', 'right');
                    item.find('.rateit-selected').addClass('rateit-selected-rtl');
                    item.find('.rateit-hover').addClass('rateit-hover-rtl');
                }
                itemdata('init', true);
            }

            //set the range element to fit all the stars.
            var range = item.find('.rateit-range');
            range.width(itemdata('starwidth') * (itemdata('max') - itemdata('min'))).height(itemdata('starheight'));

            //add/remove the preset class
            var presetclass = 'rateit-preset' + ((ltr) ? '' : '-rtl');
            if (itemdata('ispreset'))
                item.find('.rateit-selected').addClass(presetclass);
            else
                item.find('.rateit-selected').removeClass(presetclass);

            //set the value if we have it.
            if (itemdata('value')) {
                var score = (itemdata('value') - itemdata('min')) * itemdata('starwidth');
                item.find('.rateit-selected').width(score);
            }

            var resetbtn = item.find('.rateit-reset');

            var calcRawScore = function (element, event) {
                var pageX = (event.changedTouches) ? event.changedTouches[0].pageX : event.pageX;

                var offsetx = pageX - $(element).offset().left;
                if (!ltr) offsetx = range.width() - offsetx;
                if (offsetx > range.width()) offsetx = range.width();
                if (offsetx < 0) offsetx = 0;

                return score = Math.ceil(offsetx / itemdata('starwidth') * (1 / itemdata('step')));
            };

            //

            if (!itemdata('readonly')) {
                //if we are not read only, add all the events

                //if we have a reset button, set the event handler.
                if (itemdata('resetable')) {
                    resetbtn.click(function () {
                        itemdata('value', itemdata('min'));
                        range.find('.rateit-hover').hide().width(0);
                        range.find('.rateit-selected').width(0).show();
                        if (itemdata('backingfld')) $(itemdata('backingfld')).val(itemdata('min'));
                        item.trigger('reset');
                    });

                }
                else {
                    resetbtn.hide();
                }

                //when the mouse goes over the range div, we set the "hover" stars.
                if (!itemdata('wired')) {
                    range.bind('touchmove touchend', touchHandler); //bind touch events
                    range.mousemove(function (e) {
                        var score = calcRawScore(this, e);
                        var w = score * itemdata('starwidth') * itemdata('step');
                        var h = range.find('.rateit-hover');
                        if (h.data('width') != w) {
                            range.find('.rateit-selected').hide();
                            h.width(w).show().data('width', w);
                            item.trigger('hover', [(score * itemdata('step')) + itemdata('min')]);
                        }
                    });
                    //when the mouse leaves the range, we have to hide the hover stars, and show the current value.
                    range.mouseleave(function (e) {
                        range.find('.rateit-hover').hide().width(0).data('width', '');
                        item.trigger('hover', [null]);
                        range.find('.rateit-selected').show();
                    });
                    //when we click on the range, we have to set the value, hide the hover.
                    range.mouseup(function (e) {
                        var score = calcRawScore(this, e);

                        var newvalue = (score * itemdata('step')) + itemdata('min');
                        itemdata('value', newvalue);
                        if (itemdata('backingfld')) {
                            $(itemdata('backingfld')).val(newvalue);
                        }
                        if (itemdata('ispreset')) { //if it was a preset value, unset that.
                            range.find('.rateit-selected').removeClass(presetclass);
                            itemdata('ispreset', false);
                        }
                        range.find('.rateit-hover').hide();
                        range.find('.rateit-selected').width(score * itemdata('starwidth') * itemdata('step')).show();
                        item.trigger('hover', [null]).trigger('rated', [newvalue]);
                    });

                    itemdata('wired', true);
                }
                if (itemdata('resetable')) {
                    resetbtn.show();
                }
            }
            else {
                resetbtn.hide();
            }
        });
    };

    //touch converter http://ross.posterous.com/2008/08/19/iphone-touch-events-in-javascript/
    function touchHandler(event) {

        var touches = event.originalEvent.changedTouches,
                first = touches[0],
                type = "";
        switch (event.type) {
            case "touchmove": type = "mousemove"; break;
            case "touchend": type = "mouseup"; break;
            default: return;
        }

        var simulatedEvent = document.createEvent("MouseEvent");
        simulatedEvent.initMouseEvent(type, true, true, window, 1,
                              first.screenX, first.screenY,
                              first.clientX, first.clientY, false,
                              false, false, false, 0/*left*/, null);

        first.target.dispatchEvent(simulatedEvent);
        event.preventDefault();
    };

    //some default values.
    $.fn.rateit.defaults = { min: 0, max: 5, step: 0.5, starwidth: 16, starheight: 16, readonly: false, resetable: true, ispreset: false };

    //invoke it on all div.rateit elements. This could be removed if not wanted.
    $('div.rateit').rateit();

})(jQuery);<commit_msg>Change version + last change date (because of CSS change)<commit_after>/*
    RateIt
    version 1.0.1
    07/02/2011
    http://rateit.codeplex.com
    Twitter: @gjunge

*/
(function ($) {
    $.fn.rateit = function (p1, p2) {
        //quick way out.
        var options = {}; var mode = 'init';
        if (this.length == 0) return this;

        var tp1 = $.type(p1);
        if (tp1 == 'object' || p1 === undefined || p1 == null) {
            options = $.extend({}, $.fn.rateit.defaults, p1); //wants to init new rateit plugin(s).
        }
        else if (tp1 == 'string' && p2 === undefined) {
            return this.data('rateit-' + p1); //wants to get a value.
        }
        else if (tp1 == 'string') {
            mode = 'setvalue'
        }

        return this.each(function () {
            var item = $(this);

            //shorten all the item.data('rateit-XXX'), will save space in closure compiler, will be like item.data('XXX') will become x('XXX')
            var itemdata = function (key, value) { return item.data('rateit-' + key, value); };

            //add the rate it class.
            if (!item.hasClass('rateit')) item.addClass('rateit');

            var ltr = item.css('direction') != 'rtl';

            // set value mode
            if (mode == 'setvalue') {
                if (!itemdata('init')) throw 'Can\'t set value before init';

                //if readonly now and it wasn't readonly, remove the eventhandlers.
                if (p1 == 'readonly' && !itemdata('readonly')) {
                    item.find('.rateit-range').unbind();
                    itemdata('wired', false);
                }

                if (itemdata('backingfld')) {
                    //if we have a backing field, check which fields we should update.
                    //In case of input[type=range], although we did read its attributes even in browsers that don't support it (using fld.attr())
                    //we only update it in browser that support it (&& fld[0].min only works in supporting browsers), not only does it save us from checking if it is range input type, it also is unnecessary.
                    var fld = $(itemdata('backingfld'));
                    if (p1 == 'value') fld.val(p2);
                    if (p1 == 'min' && fld[0].min) fld[0].min = p2;
                    if (p1 == 'max' && fld[0].max) fld[0].max = p2;
                    if (p1 == 'step' && fld[0].step) fld[0].step = p2;
                }

                itemdata(p1, p2);
            }

            //init rateit plugin
            if (!itemdata('init')) {

                //get our values, either from the data-* html5 attribute or from the options.
                itemdata('min', itemdata('min') || options.min);
                itemdata('max', itemdata('max') || options.max);
                itemdata('step', itemdata('step') || options.step);
                itemdata('readonly', itemdata('readonly') !== undefined ? itemdata('readonly') : options.readonly);
                itemdata('resetable', itemdata('resetable') !== undefined ? itemdata('resetable') : options.resetable);
                itemdata('backingfld', itemdata('backingfld') || options.backingfld);
                itemdata('starwidth', itemdata('starwidth') || options.starwidth);
                itemdata('starheight', itemdata('starheight') || options.starheight);
                itemdata('value', itemdata('value') || options.min);
                itemdata('ispreset', itemdata('ispreset') !== undefined ? itemdata('ispreset') : options.ispreset);
                //are we LTR or RTL?

                if (itemdata('backingfld')) {
                    //if we have a backing field, hide it, and get its value, and override defaults if range.
                    var fld = $(itemdata('backingfld'));
                    itemdata('value', fld.hide().val());

                    if (fld[0].nodeName == 'INPUT') {
                        if (fld[0].type == 'range' || fld[0].type == 'text') { //in browsers not support the range type, it defaults to text

                            itemdata('min', parseInt(fld.attr('min')) || itemdata('min')); //if we would have done fld[0].min it wouldn't have worked in browsers not supporting the range type.
                            itemdata('max', parseInt(fld.attr('max')) || itemdata('max'));
                            itemdata('step', parseInt(fld.attr('step')) || itemdata('step'));
                        }
                    }
                    if (fld[0].nodeName == 'SELECT' && fld[0].options.length > 1) {
                        itemdata('min', Number(fld[0].options[0].value));
                        itemdata('max', Number(fld[0].options[fld[0].length - 1].value));
                        itemdata('step', Number(fld[0].options[1].value) - Number(fld[0].options[0].value));
                    }
                }

                //Create the necessary tags.
                item.append('

');

                //if we are in RTL mode, we have to change the float of the "reset button"
                if (!ltr) {
                    item.find('.rateit-reset').css('float', 'right');
                    item.find('.rateit-selected').addClass('rateit-selected-rtl');
                    item.find('.rateit-hover').addClass('rateit-hover-rtl');
                }
                itemdata('init', true);
            }

            //set the range element to fit all the stars.
            var range = item.find('.rateit-range');
            range.width(itemdata('starwidth') * (itemdata('max') - itemdata('min'))).height(itemdata('starheight'));

            //add/remove the preset class
            var presetclass = 'rateit-preset' + ((ltr) ? '' : '-rtl');
            if (itemdata('ispreset'))
                item.find('.rateit-selected').addClass(presetclass);
            else
                item.find('.rateit-selected').removeClass(presetclass);

            //set the value if we have it.
            if (itemdata('value')) {
                var score = (itemdata('value') - itemdata('min')) * itemdata('starwidth');
                item.find('.rateit-selected').width(score);
            }

            var resetbtn = item.find('.rateit-reset');

            var calcRawScore = function (element, event) {
                var pageX = (event.changedTouches) ? event.changedTouches[0].pageX : event.pageX;

                var offsetx = pageX - $(element).offset().left;
                if (!ltr) offsetx = range.width() - offsetx;
                if (offsetx > range.width()) offsetx = range.width();
                if (offsetx < 0) offsetx = 0;

                return score = Math.ceil(offsetx / itemdata('starwidth') * (1 / itemdata('step')));
            };

            //

            if (!itemdata('readonly')) {
                //if we are not read only, add all the events

                //if we have a reset button, set the event handler.
                if (itemdata('resetable')) {
                    resetbtn.click(function () {
                        itemdata('value', itemdata('min'));
                        range.find('.rateit-hover').hide().width(0);
                        range.find('.rateit-selected').width(0).show();
                        if (itemdata('backingfld')) $(itemdata('backingfld')).val(itemdata('min'));
                        item.trigger('reset');
                    });

                }
                else {
                    resetbtn.hide();
                }

                //when the mouse goes over the range div, we set the "hover" stars.
                if (!itemdata('wired')) {
                    range.bind('touchmove touchend', touchHandler); //bind touch events
                    range.mousemove(function (e) {
                        var score = calcRawScore(this, e);
                        var w = score * itemdata('starwidth') * itemdata('step');
                        var h = range.find('.rateit-hover');
                        if (h.data('width') != w) {
                            range.find('.rateit-selected').hide();
                            h.width(w).show().data('width', w);
                            item.trigger('hover', [(score * itemdata('step')) + itemdata('min')]);
                        }
                    });
                    //when the mouse leaves the range, we have to hide the hover stars, and show the current value.
                    range.mouseleave(function (e) {
                        range.find('.rateit-hover').hide().width(0).data('width', '');
                        item.trigger('hover', [null]);
                        range.find('.rateit-selected').show();
                    });
                    //when we click on the range, we have to set the value, hide the hover.
                    range.mouseup(function (e) {
                        var score = calcRawScore(this, e);

                        var newvalue = (score * itemdata('step')) + itemdata('min');
                        itemdata('value', newvalue);
                        if (itemdata('backingfld')) {
                            $(itemdata('backingfld')).val(newvalue);
                        }
                        if (itemdata('ispreset')) { //if it was a preset value, unset that.
                            range.find('.rateit-selected').removeClass(presetclass);
                            itemdata('ispreset', false);
                        }
                        range.find('.rateit-hover').hide();
                        range.find('.rateit-selected').width(score * itemdata('starwidth') * itemdata('step')).show();
                        item.trigger('hover', [null]).trigger('rated', [newvalue]);
                    });

                    itemdata('wired', true);
                }
                if (itemdata('resetable')) {
                    resetbtn.show();
                }
            }
            else {
                resetbtn.hide();
            }
        });
    };

    //touch converter http://ross.posterous.com/2008/08/19/iphone-touch-events-in-javascript/
    function touchHandler(event) {

        var touches = event.originalEvent.changedTouches,
                first = touches[0],
                type = "";
        switch (event.type) {
            case "touchmove": type = "mousemove"; break;
            case "touchend": type = "mouseup"; break;
            default: return;
        }

        var simulatedEvent = document.createEvent("MouseEvent");
        simulatedEvent.initMouseEvent(type, true, true, window, 1,
                              first.screenX, first.screenY,
                              first.clientX, first.clientY, false,
                              false, false, false, 0/*left*/, null);

        first.target.dispatchEvent(simulatedEvent);
        event.preventDefault();
    };

    //some default values.
    $.fn.rateit.defaults = { min: 0, max: 5, step: 0.5, starwidth: 16, starheight: 16, readonly: false, resetable: true, ispreset: false };

    //invoke it on all div.rateit elements. This could be removed if not wanted.
    $('div.rateit').rateit();

})(jQuery);<|endoftext|>


<commit_before>'use strict';

const assert      = require('assert');
const co          = require('co');
const Heroku      = require('./heroku');
const LetsEncrypt = require('letsencrypt');
const log         = require('log')('example-server');

const baseOptions = {
  agreeTos: true,
  server:   LetsEncrypt.stagingServerUrl,
};

let getCertificate = options => co(function * () {
  try {
    const heroku = new Heroku({
      apiKey: options.apiKey,
      app:    options.appName,
    });

    // Unset the server, because it breaks lets encrypt
    delete options.server;

    // Get domains
    let domains = yield (heroku.request({
      method: 'GET',
      qs:     {kind: 'custom'},
      url:    '/domains',
    }))
    .filter(d => d.kind === 'custom')
    .map(d => d.hostname)
    ;
    log.info('Heroku domains', domains);
    options.domains = domains;
    options.approveDomains = domains;
    assert(options.domains.length, 'You need to setup a custom domain in Heroku');

    // Get certs from letsencrypt
    let certs = yield (options.letsencrypt.register(options));
    // Find out if there is a Heroku cert already
    let endpoint = (yield heroku.request({
      method: 'GET',
      url:    'sni-endpoints',
    }))[0];
    let endpointSpec = '';
    if (endpoint) {
      endpointSpec = `/${endpoint.id}`;
      log.info('Adding Heroku certificate');
    }
    else log.info('Updating Heroku certificate');
    (yield heroku.request({
      body: {
        certificate_chain: certs.cert + '\n' + certs.chain,
        private_key:       certs.privkey,
      },
      method: endpoint ? 'PATCH' : 'POST',
      url:    'sni-endpoints' + endpointSpec,
    }));
    log.info('Heroku certificate updated');
  }
  catch (error) {
    log.error(error.stack || error);
  }
})
;

/**
 * This function will start the server on the specified port. It returns a
 * promise that will be resolved when the server is running.
 *
 * @param {object} options         Map of options for the letsencrypt certificate system
 * @param {string} options.apiKey  The Heroku API key, which can be found in your account preferences
 * @param {string} options.appName The name of the Heroku application this is running in
 * @param {string} options.email   An email address for the let's encrypt account
 * @param {string} options.server  The letsencrypt server that should be used (staging|production) (default: staging)
 *
 * @return {middleware} The letsencrypt middleware
 */
module.exports = options => {
  // Check for an email for the let's encrypt account
  assert(options.email,   'email is required');
  assert(options.appName, 'appName is required');
  assert(options.apiKey,  'apiKey is required');

  let server = options.server === 'production' ?
    LetsEncrypt.productionServerUrl :
    LetsEncrypt.stagingServerUrl
  ;
  if (server === LetsEncrypt.productionServerUrl)
    log.info('Using production server');
  else log.warn('Using staging server');
  let letsencrypt = LetsEncrypt.create({server});
  getCertificate(Object.assign({}, baseOptions, options, {letsencrypt}));
  return letsencrypt.middleware();
};
<commit_msg>Fixed typo<commit_after>'use strict';

const assert      = require('assert');
const co          = require('co');
const Heroku      = require('./heroku');
const LetsEncrypt = require('letsencrypt');
const log         = require('log')('example-server');

const baseOptions = {
  agreeTos: true,
  server:   LetsEncrypt.stagingServerUrl,
};

let getCertificate = options => co(function * () {
  try {
    const heroku = new Heroku({
      apiKey: options.apiKey,
      app:    options.appName,
    });

    // Unset the server, because it breaks lets encrypt
    delete options.server;

    // Get domains
    let domains = (yield heroku.request({
      method: 'GET',
      qs:     {kind: 'custom'},
      url:    '/domains',
    }))
    .filter(d => d.kind === 'custom')
    .map(d => d.hostname)
    ;
    log.info('Heroku domains', domains);
    options.domains = domains;
    options.approveDomains = domains;
    assert(options.domains.length, 'You need to setup a custom domain in Heroku');

    // Get certs from letsencrypt
    let certs = yield options.letsencrypt.register(options);
    // Find out if there is a Heroku cert already
    let endpoint = (yield heroku.request({
      method: 'GET',
      url:    'sni-endpoints',
    }))[0];
    let endpointSpec = '';
    if (endpoint) {
      endpointSpec = `/${endpoint.id}`;
      log.info('Adding Heroku certificate');
    }
    else log.info('Updating Heroku certificate');
    (yield heroku.request({
      body: {
        certificate_chain: certs.cert + '\n' + certs.chain,
        private_key:       certs.privkey,
      },
      method: endpoint ? 'PATCH' : 'POST',
      url:    'sni-endpoints' + endpointSpec,
    }));
    log.info('Heroku certificate updated');
  }
  catch (error) {
    log.error(error.stack || error);
  }
})
;

/**
 * This function will start the server on the specified port. It returns a
 * promise that will be resolved when the server is running.
 *
 * @param {object} options         Map of options for the letsencrypt certificate system
 * @param {string} options.apiKey  The Heroku API key, which can be found in your account preferences
 * @param {string} options.appName The name of the Heroku application this is running in
 * @param {string} options.email   An email address for the let's encrypt account
 * @param {string} options.server  The letsencrypt server that should be used (staging|production) (default: staging)
 *
 * @return {middleware} The letsencrypt middleware
 */
module.exports = options => {
  // Check for an email for the let's encrypt account
  assert(options.email,   'email is required');
  assert(options.appName, 'appName is required');
  assert(options.apiKey,  'apiKey is required');

  let server = options.server === 'production' ?
    LetsEncrypt.productionServerUrl :
    LetsEncrypt.stagingServerUrl
  ;
  if (server === LetsEncrypt.productionServerUrl)
    log.info('Using production server');
  else log.warn('Using staging server');
  let letsencrypt = LetsEncrypt.create({server});
  getCertificate(Object.assign({}, baseOptions, options, {letsencrypt}));
  return letsencrypt.middleware();
};
<|endoftext|>


<commit_before>const Koa = require('koa')
const path = require('path')
const views = require('koa-views')
const Router = require('koa-router')
const koa_static = require('koa-static')

const session = require('koa-session');
const convert = require('koa-convert');

const envir = require('./envir')
const Model = require('./model')

const back = require('./back')
const front = require('./front')

const app = new Koa

app.keys = [envir.session_secret];
const SESSION_CONFIG = {
  key: 'pache:sess', /** (string) cookie key (default is koa:sess) */
  maxAge: 86400000, /** (number) maxAge in ms (default is 1 days) */
  overwrite: true, /** (boolean) can overwrite or not (default true) */
  httpOnly: true, /** (boolean) httpOnly or not (default true) */
  signed: true, /** (boolean) signed or not (default true) */
};
app.use(convert(session(SESSION_CONFIG, app)));

const backRouter = new Router

app
  .use(back.routes())
  .use(back.allowedMethods())

app
  .use(front.routes())
  .use(front.allowedMethods())

app.use(koa_static(path.join(__dirname, 'static/')))
app.use(koa_static(path.join(__dirname, 'public/')))

if (envir.ESD_ENABLE) {
  envir.ESD_LIST.forEach(esd_path => {
    app.use(koa_static(path.join(esd_path)))
  })
}

module.exports = app
<commit_msg>Session 存儲改用 Redis，支持多線程的負載均衡<commit_after>const Koa = require('koa')
const path = require('path')
const views = require('koa-views')
const Router = require('koa-router')
const koa_static = require('koa-static')

const session = require('koa-session-redis')
const convert = require('koa-convert')

const envir = require('./envir')
const Model = require('./model')

const back = require('./back')
const front = require('./front')

const app = new Koa

app.keys = [envir.session_secret];

const session_handle = convert(session({
  key: 'pache:sess', /** (string) cookie key (default is koa:sess) */
  cookie: {
    maxage: 86400000, // cookie 有效期
    maxAge: 86400000, // cookie 有效期
    overwrite: true, /** (boolean) can overwrite or not (default true) */
    httpOnly: true, /** (boolean) httpOnly or not (default true) */
    signed: true, /** (boolean) signed or not (default true) */
  },
  store: {
    host: process.env.SESSION_PORT_6379_TCP_ADDR || '127.0.0.1',
    port: process.env.SESSION_PORT_6379_TCP_PORT || 6379,
    ttl: 3600,
  },
}))

app.use(session_handle);

const backRouter = new Router

app
  .use(back.routes())
  .use(back.allowedMethods())

app
  .use(front.routes())
  .use(front.allowedMethods())

app.use(koa_static(path.join(__dirname, 'static/')))
app.use(koa_static(path.join(__dirname, 'public/')))

if (envir.ESD_ENABLE) {
  envir.ESD_LIST.forEach(esd_path => {
    app.use(koa_static(path.join(esd_path)))
  })
}

module.exports = app
<|endoftext|>


<commit_before>namespace('Sy.Lib');

/**
 * Allow to set a series of function that will be called when a channel is "published" via this object
 *
 * @package Sy
 * @subpackage Lib
 * @class
 */

Sy.Lib.Mediator = function () {

    this.channels = {};
    this.generator = null;
    this.logger = null;

};

Sy.Lib.Mediator.prototype = Object.create(Object.prototype, {

    /**
     * Add a subscriber to a channel
     *
     * @param {object} options Available properties: {channel: string, fn: function, context: object, priority: integer, async: boolean}
     *
     * @return {string} A unique identifier for this subscriber
     */

    subscribe: {
        value: function (options) {

            var options = options || {},
                channel = null;

            if (options.priority === undefined){
                options.priority = 1;
            }

            if (this.channels[options.channel] === undefined) {

                channel = new Sy.Lib.MediatorChannel(options.channel);
                channel.setGenerator(this.generator);

                if (this.logger) {
                    channel.setLogger(this.logger);
                }

                this.channels[options.channel] = channel;

            }

            return this.channels[options.channel].add(options.fn, options.context, options.priority, options.async);

        }

    },

    /**
     * Remove an element of a channel subscribers list
     *
     * @param {string} channel
     * @param {string} id Identifier returned by the method subscribe
     *
     * @return {Sy.Lib.Mediator}
     */

    remove: {
        value: function (channel, id) {

            if (this.channels[channel] !== undefined) {

                this.channels[channel].remove(id);

            }

            return this;

        }

    },

    /**
     * Publish a channel, all arguments after the channel name will
     * be passed to the subscribers as arguments
     *
     * @param {string} channel Channel name
     *
     * @return {Sy.Lib.Mediator}
     */

    publish: {
        value: function () {

            if (arguments.length === 0) {
                return this;
            }

            var channel = Array.prototype.slice.call(arguments, 0, 1)[0],
                args = Array.prototype.slice.call(arguments, 1);

            if (this.channels[channel] !== undefined) {

                this.channels[channel].publish(args);

            }

            return this;

        }

    },

    /**
     * Pause a channel from being fired
     *
     * @param {string} channel
     * @param {string} subscriber Subscriber id, if you want to pause only one subscriber (optional)
     *
     * @return {Sy.Lib.Mediator}
     */

    pause: {
        value: function (channel, subscriber) {

            if (this.channels[channel] !== undefined) {

                this.channels[channel].stopped = true;

                if (subscriber) {
                    this.channels[channel].pause(subscriber);
                }

            }

            return this;

        }

    },

    /**
     * Unpause a channel from being fired
     *
     * @param {string} channel
     * @param {string} subscriber Subscriber id, if you want to unpause only one subscriber (optional)
     *
     * @return {Sy.Lib.Mediator}
     */

    unpause: {
        value: function (channel, subscriber) {

            if (this.channels[channel] !== undefined) {

                this.channels[channel].stopped = false;

                if (subscriber) {
                    this.channels[channel].unpause(subscriber);
                }

            }

            return this;

        }

    },

    /**
     * Say if a channel is paused or not
     *
     * @param {string} channel
     *
     * @return {boolean}
     */

    paused: {
        value: function (channel) {

            if (this.channels[channel] === undefined) {

                return;

            }

            return this.channels[channel].stopped;

        }

    },

    /**
     * Generator dependency setter
     *
     * @param {Sy.Lib.Generator.Interface} object
     *
     * @return {Sy.Lib.Mediator}
     */

    setGenerator: {
        value: function (object) {

            if (!(object instanceof Sy.Lib.Generator.Interface)) {
                throw new TypeError('Invalid generator');
            }

            this.generator = object;

            return this;

        }
    },

    /**
     * Logger dependency setter
     *
     * @param {Sy.Lib.Logger.Interface} object
     *
     * @return {Sy.Lib.Mediator}
     */

    setLogger: {
        value: function (object) {

            if (!(object instanceof Sy.Lib.Logger.Interface)) {
                throw new TypeError('Invalid logger');
            }

            this.logger = object;

            return this;

        }
    }

});

/**
 * Channel object to be instanciated every time a new channel is created
 *
 * @package Sy
 * @subpackage Lib
 * @class
 *
 * @param {string} name
 */

Sy.Lib.MediatorChannel = function (name) {

    this.name = name || '';
    this.stopped = false;
    this.subscribers = {};
    this.generator = null;
    this.logger = null;

};

Sy.Lib.MediatorChannel.prototype = Object.create(Object.prototype, {

    /**
     * Add a subscriber to the channel
     *
     * @param {function} fn
     * @param {object} context Callback context
     * @param {integer} priority
     * @param {boolean} async
     */

    add: {
        value: function (fn, context, priority, async) {

            var guid = this.generator.generate();

            this.subscribers[guid] = {
                fn: fn,
                context: context || window,
                priority: priority || 1,
                async: !!async,
                stopped: false
            };

            return guid;

        }

    },

    /**
     * Remove an element of the subscribers list
     *
     * @param {string} id
     *
     * @return {Sy.Lib.MediatorChannel}
     */

    remove: {
        value: function (id) {

            delete this.subscribers[id];

            return this;

        }

    },

    /**
     * Call every subscribers function when a channel is published
     *
     * @param {Array} args Arguments to be passed to the subscribers
     *
     * @return {Sy.Lib.MediatorChannel}
     */

    publish: {
        value: function (args) {

            var args = args || [];

            if (this.stopped === false) {

                var fns = [];

                for (var s in this.subscribers) {

                    if (this.subscribers.hasOwnProperty(s) && this.subscribers[s].stopped === false) {

                        fns.push(this.subscribers[s]);

                    }

                }

                fns.sort(function (a, b) {
                    return a.priority - b.priority;
                });

                for (var i = 0, l = fns.length; i < l; i++) {

                    try {

                        var subscriber = fns[i];

                        if (subscriber.async === true) {
                            setTimeout(
                                this.subscriberCall,
                                0,
                                this,
                                subscriber.fn,
                                subscriber.context,
                                args
                            );
                        } else {
                            this.subscriberCall(
                                this,
                                subscriber.fn,
                                subscriber.context,
                                args
                            );
                        }

                    } catch (error) {

                        if (this.logger) {
                            this.logger.error(error.message, error);
                        }

                    }

                }

            }

            return this;

        }

    },

    /**
     * Generator dependency setter
     *
     * @param {Sy.Lib.Generator.interface} object
     *
     * @return {Sy.Lib.MediatorChannel}
     */

    setGenerator: {
        value: function (object) {

            if (!(object instanceof Sy.Lib.Generator.Interface)) {
                throw new TypeError('Invalid generator');
            }

            this.generator = object;

            return this;

        }
    },

    /**
     * Logger dependency setter
     *
     * @param {Sy.Lib.Logger.Interface} object
     *
     * @return {Sy.Lib.MediatorChannel}
     */

    setLogger: {
        value: function (object) {

            if (!(object instanceof Sy.Lib.Logger.Interface)) {
                throw new TypeError('Invalid logger');
            }

            this.logger = object;

            return this;

        }
    },

    /**
     * Handle calling subscribers and catching exceptions it may throw
     *
     * @param {Sy.Lib.MediatorChannel} self Channel instance
     * @param {function} fn
     * @param {object} context Subscriber context
     * @param {Array} args Subscriber arguments
     *
     * @return {void}
     */

    subscriberCall: {
        value: function (self, fn, context, args) {

            fn.apply(context, args);

        }
    },

    /**
     * Prevent a subscriber from being fired when the channel is published
     *
     * @param {string} id Subscriber id
     *
     * @return {Sy.Lib.MediatorChannel}
     */

    pause: {
        value: function (id) {

            if (this.subscribers[id]) {
                this.subscribers[id].stopped = true;
            }

            return this;

        }
    },

    /**
     * Re-enable a subscriber from being fired if it has been paused before
     *
     * @param {string} id
     *
     * @return {Sy.Lib.MediatorChannel}
     */

    unpause: {
        value: function (id) {

            if (this.subscribers[id]) {
                this.subscribers[id].stopped = false;
            }

            return this;

        }
    }

});<commit_msg>added an attribute to the subscribers to bubble up errors outside of the mediator<commit_after>namespace('Sy.Lib');

/**
 * Allow to set a series of function that will be called when a channel is "published" via this object
 *
 * @package Sy
 * @subpackage Lib
 * @class
 */

Sy.Lib.Mediator = function () {

    this.channels = {};
    this.generator = null;
    this.logger = null;

};

Sy.Lib.Mediator.prototype = Object.create(Object.prototype, {

    /**
     * Add a subscriber to a channel
     *
     * @param {object} options Available properties: {channel: string, fn: function, context: object, priority: integer, async: boolean}
     *
     * @return {string} A unique identifier for this subscriber
     */

    subscribe: {
        value: function (options) {

            var options = options || {},
                channel = null;

            if (options.priority === undefined){
                options.priority = 1;
            }

            if (this.channels[options.channel] === undefined) {

                channel = new Sy.Lib.MediatorChannel(options.channel);
                channel.setGenerator(this.generator);

                if (this.logger) {
                    channel.setLogger(this.logger);
                }

                this.channels[options.channel] = channel;

            }

            return this.channels[options.channel].add(
                options.fn,
                options.context,
                options.priority,
                options.async,
                options.bubbles
            );

        }

    },

    /**
     * Remove an element of a channel subscribers list
     *
     * @param {string} channel
     * @param {string} id Identifier returned by the method subscribe
     *
     * @return {Sy.Lib.Mediator}
     */

    remove: {
        value: function (channel, id) {

            if (this.channels[channel] !== undefined) {

                this.channels[channel].remove(id);

            }

            return this;

        }

    },

    /**
     * Publish a channel, all arguments after the channel name will
     * be passed to the subscribers as arguments
     *
     * @param {string} channel Channel name
     *
     * @return {Sy.Lib.Mediator}
     */

    publish: {
        value: function () {

            if (arguments.length === 0) {
                return this;
            }

            var channel = Array.prototype.slice.call(arguments, 0, 1)[0],
                args = Array.prototype.slice.call(arguments, 1);

            if (this.channels[channel] !== undefined) {

                this.channels[channel].publish(args);

            }

            return this;

        }

    },

    /**
     * Pause a channel from being fired
     *
     * @param {string} channel
     * @param {string} subscriber Subscriber id, if you want to pause only one subscriber (optional)
     *
     * @return {Sy.Lib.Mediator}
     */

    pause: {
        value: function (channel, subscriber) {

            if (this.channels[channel] !== undefined) {

                this.channels[channel].stopped = true;

                if (subscriber) {
                    this.channels[channel].pause(subscriber);
                }

            }

            return this;

        }

    },

    /**
     * Unpause a channel from being fired
     *
     * @param {string} channel
     * @param {string} subscriber Subscriber id, if you want to unpause only one subscriber (optional)
     *
     * @return {Sy.Lib.Mediator}
     */

    unpause: {
        value: function (channel, subscriber) {

            if (this.channels[channel] !== undefined) {

                this.channels[channel].stopped = false;

                if (subscriber) {
                    this.channels[channel].unpause(subscriber);
                }

            }

            return this;

        }

    },

    /**
     * Say if a channel is paused or not
     *
     * @param {string} channel
     *
     * @return {boolean}
     */

    paused: {
        value: function (channel) {

            if (this.channels[channel] === undefined) {

                return;

            }

            return this.channels[channel].stopped;

        }

    },

    /**
     * Generator dependency setter
     *
     * @param {Sy.Lib.Generator.Interface} object
     *
     * @return {Sy.Lib.Mediator}
     */

    setGenerator: {
        value: function (object) {

            if (!(object instanceof Sy.Lib.Generator.Interface)) {
                throw new TypeError('Invalid generator');
            }

            this.generator = object;

            return this;

        }
    },

    /**
     * Logger dependency setter
     *
     * @param {Sy.Lib.Logger.Interface} object
     *
     * @return {Sy.Lib.Mediator}
     */

    setLogger: {
        value: function (object) {

            if (!(object instanceof Sy.Lib.Logger.Interface)) {
                throw new TypeError('Invalid logger');
            }

            this.logger = object;

            return this;

        }
    }

});

/**
 * Channel object to be instanciated every time a new channel is created
 *
 * @package Sy
 * @subpackage Lib
 * @class
 *
 * @param {string} name
 */

Sy.Lib.MediatorChannel = function (name) {

    this.name = name || '';
    this.stopped = false;
    this.subscribers = {};
    this.generator = null;
    this.logger = null;

};

Sy.Lib.MediatorChannel.prototype = Object.create(Object.prototype, {

    /**
     * Add a subscriber to the channel
     *
     * @param {function} fn
     * @param {object} context Callback context
     * @param {integer} priority
     * @param {boolean} async
     * @param {boolean} bubbles Set to true if you want errors to bubbles up (otherwise it's catched by the library)
     */

    add: {
        value: function (fn, context, priority, async, bubbles) {

            var guid = this.generator.generate();

            this.subscribers[guid] = {
                fn: fn,
                context: context || window,
                priority: priority || 1,
                async: !!async,
                bubbles: !!bubbles,
                stopped: false
            };

            return guid;

        }

    },

    /**
     * Remove an element of the subscribers list
     *
     * @param {string} id
     *
     * @return {Sy.Lib.MediatorChannel}
     */

    remove: {
        value: function (id) {

            delete this.subscribers[id];

            return this;

        }

    },

    /**
     * Call every subscribers function when a channel is published
     *
     * @param {Array} args Arguments to be passed to the subscribers
     *
     * @return {Sy.Lib.MediatorChannel}
     */

    publish: {
        value: function (args) {

            var args = args || [];

            if (this.stopped === false) {

                var fns = [];

                for (var s in this.subscribers) {

                    if (this.subscribers.hasOwnProperty(s) && this.subscribers[s].stopped === false) {

                        fns.push(this.subscribers[s]);

                    }

                }

                fns.sort(function (a, b) {
                    return a.priority - b.priority;
                });

                for (var i = 0, l = fns.length; i < l; i++) {

                    try {

                        var subscriber = fns[i];

                        if (subscriber.async === true) {
                            setTimeout(
                                this.subscriberCall,
                                0,
                                this,
                                subscriber.fn,
                                subscriber.context,
                                args
                            );
                        } else {
                            this.subscriberCall(
                                this,
                                subscriber.fn,
                                subscriber.context,
                                args
                            );
                        }

                    } catch (error) {

                        if (this.logger) {
                            this.logger.error(error.message, error);
                        }

                        if (subscriber.bubbles === true) {
                            throw error;
                        }

                    }

                }

            }

            return this;

        }

    },

    /**
     * Generator dependency setter
     *
     * @param {Sy.Lib.Generator.interface} object
     *
     * @return {Sy.Lib.MediatorChannel}
     */

    setGenerator: {
        value: function (object) {

            if (!(object instanceof Sy.Lib.Generator.Interface)) {
                throw new TypeError('Invalid generator');
            }

            this.generator = object;

            return this;

        }
    },

    /**
     * Logger dependency setter
     *
     * @param {Sy.Lib.Logger.Interface} object
     *
     * @return {Sy.Lib.MediatorChannel}
     */

    setLogger: {
        value: function (object) {

            if (!(object instanceof Sy.Lib.Logger.Interface)) {
                throw new TypeError('Invalid logger');
            }

            this.logger = object;

            return this;

        }
    },

    /**
     * Handle calling subscribers and catching exceptions it may throw
     *
     * @param {Sy.Lib.MediatorChannel} self Channel instance
     * @param {function} fn
     * @param {object} context Subscriber context
     * @param {Array} args Subscriber arguments
     *
     * @return {void}
     */

    subscriberCall: {
        value: function (self, fn, context, args) {

            fn.apply(context, args);

        }
    },

    /**
     * Prevent a subscriber from being fired when the channel is published
     *
     * @param {string} id Subscriber id
     *
     * @return {Sy.Lib.MediatorChannel}
     */

    pause: {
        value: function (id) {

            if (this.subscribers[id]) {
                this.subscribers[id].stopped = true;
            }

            return this;

        }
    },

    /**
     * Re-enable a subscriber from being fired if it has been paused before
     *
     * @param {string} id
     *
     * @return {Sy.Lib.MediatorChannel}
     */

    unpause: {
        value: function (id) {

            if (this.subscribers[id]) {
                this.subscribers[id].stopped = false;
            }

            return this;

        }
    }

});<|endoftext|>


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

goog.require('axs.AuditRule');

goog.provide('axs.AuditRules');

(function(){
    var auditRulesByName = {};
    var auditRulesByCode = {};

    /**
     * Instantiates and registers an audit rule.
     * If a conflicting rule is already registered then the new rule will not be added.
     * @param {axs.AuditRule.Spec} spec The object which defines the AuditRule to add.
     * @throws {Error} If the rule duplicates properties that must be unique.
     */
    axs.AuditRules.addRule = function(spec) {
        // axs.AuditRule.specs[spec.name] = spec;  // This would add backwards compatibility
        // create the auditRule before checking props as we can expect the constructor to perform the
        // first layer of sanity checking.
        var auditRule = new axs.AuditRule(spec);
        if (auditRule.code in auditRulesByCode || auditRule.name in auditRulesByName)
            throw new Error('Can not add audit rule with same name or code: "' + auditRule.code + '"/"' + auditRule.name + '"');
        auditRulesByName[auditRule.name] = auditRulesByCode[auditRule.code] = auditRule;
    };

    /**
     * Gets the audit rule with the given name.
     * @param {string} name The name (or code) of an audit rule.
     * @return {axs.AuditRule}
     */
    axs.AuditRules.getRule = function(name) {
        return auditRulesByName[name] || auditRulesByCode[name] || null;
    };

    /**
     * Gets all registered audit rules.
     * @param {boolean=} namesOnly If true then the result will contain only the rule names.
     * @return {Array.<axs.AuditRule>|Array.<string>}
     */
    axs.AuditRules.getRules = function(namesOnly) {
        var ruleNames = Object.keys(auditRulesByName);
        if(namesOnly)
            return ruleNames;
        return ruleNames.map(function(name) {
            return this.getRule(name);
        }, axs.AuditRules);
    };
})();
<commit_msg>Actioning Alice's feedback.<commit_after>// Copyright 2012 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

goog.require('axs.AuditRule');

goog.provide('axs.AuditRules');

(function(){
    var auditRulesByName = {};
    var auditRulesByCode = {};

    /**
     * Instantiates and registers an audit rule.
     * If a conflicting rule is already registered then the new rule will not be added.
     * @param {axs.AuditRule.Spec} spec The object which defines the AuditRule to add.
     * @throws {Error} If the rule duplicates properties that must be unique.
     */
    axs.AuditRules.addRule = function(spec) {
        // axs.AuditRule.specs[spec.name] = spec;  // This would add backwards compatibility
        // create the auditRule before checking props as we can expect the constructor to perform the
        // first layer of sanity checking.
        var auditRule = new axs.AuditRule(spec);
        if (auditRule.code in auditRulesByCode)
            throw new Error('Can not add audit rule with same code: "' + auditRule.code + '"');
        if (auditRule.name in auditRulesByName)
            throw new Error('Can not add audit rule with same name: "' + auditRule.name + '"');
        auditRulesByName[auditRule.name] = auditRulesByCode[auditRule.code] = auditRule;
    };

    /**
     * Gets the audit rule with the given name.
     * @param {string} name The name (or code) of an audit rule.
     * @return {axs.AuditRule}
     */
    axs.AuditRules.getRule = function(name) {
        return auditRulesByName[name] || auditRulesByCode[name] || null;
    };

    /**
     * Gets all registered audit rules.
     * @param {boolean=} opt_namesOnly If true then the result will contain only the rule names.
     * @return {Array.<axs.AuditRule>|Array.<string>}
     */
    axs.AuditRules.getRules = function(opt_namesOnly) {
        var ruleNames = Object.keys(auditRulesByName);
        if(opt_namesOnly)
            return ruleNames;
        return ruleNames.map(function(name) {
            return this.getRule(name);
        }, axs.AuditRules);
    };
})();
<|endoftext|>


<commit_before>var page = tabris.create("Page", {
  title: "Video",
  topLevel: true
});

tabris.create("Video", {
  layoutData: {left: 0, right: 0, top: 0, bottom: 0},
  url: "http://mirrorblender.top-ix.org/movies/sintel-1280-stereo.mp4"
}).appendTo(page);

page.open();
<commit_msg>Update Sintel video mirror<commit_after>var page = tabris.create("Page", {
  title: "Video",
  topLevel: true
});

tabris.create("Video", {
  layoutData: {left: 0, right: 0, top: 0, bottom: 0},
  url: "http://peach.themazzone.com/durian/movies/sintel-1280-stereo.mp4"
}).appendTo(page);

page.open();
<|endoftext|>