<commit_before>var Site = function(Site) {

    var that = this;

    this.init = function() {

        // Global cached jQuery objects
        this.$html = $('html');
        this.$body = $('html');

        // Base JS (any page that extends base.html)
        if (this.$html.hasClass('base')) {
            this.Views['base']();
        }

        // Page specific JS
        if (this.$html.attr('id')) {
            this.Views[this.$html.attr('id')]();
        }

    };
    this.Utils = {
        chosenify: function() {
            $('select', '.v1 .content').filter(function() {
                return !$(this).parents('div').hasClass('ajaxChosen');
            }).chosen().change(function() {
                $select = $(this);

                // New message
                if ($('body').hasClass('new-message')) {
                    $option = $('option:selected', $select);

                    if ($select.attr('id') === 'id_team') {
                        if ($option.val() !== '') {
                            $('div.recipient, div.or').addClass('disabled');
                            $('select#id_user').attr('disabled', 'disabled').trigger('liszt:updated');
                        } else {
                            $('div.recipient, div.or').removeClass('disabled');
                            $('select#id_user').removeAttr('disabled').trigger('liszt:updated');
                        }
                    }
                }
            });
        },
        resetLangFilter: function($select) {
            if (typeof $select == 'undefined') {
                $select = $('select#lang-filter');
            }
            if (window.REQUEST_GET_LANG) {
                $opt = $('option[id="lang-opt-' + window.REQUEST_GET_LANG + '"]');
            } else {
                $opt = $('option[id="lang-opt-any"]');
            }
            $select.children().removeAttr('selected');
            $opt.attr('selected', 'selected');
            $select.trigger('liszt:updated');
        }
    };
    this.Views = {
        base: function() {

            /*
             * TODO: The modules in this section need to be
             * pulled out into site.Utils and only
             * initialized on pages that use them.
             */
            if ($('.abbr').length) {
                $('.abbr').each(function(){
                    var container = $(this);
                    var content = $(this).children('div');
                    var oheight = content.css('height', 'auto').height();
                    content.css('height','6em');
                    $(this).find('.expand').live('click', function(e){
                        e.preventDefault();
                        if(container.hasClass('collapsed')){
                            content.animate({
                                height: oheight
                            }, 'fast');
                            $(this).text('Collapse ↑');
                        } else {
                            content.animate({
                                height: '6em'
                            }, 'fast');
                            $(this).text('Show all ↓');
                        }
                        container.toggleClass('collapsed expanded');
                    });
                });
            }
            if ($('#sort-filter').length) {
                $('#sort-filter').click(function(e) {
                    e.preventDefault();
                    $('.filters').toggle();
                    $(this).children('span').toggleClass('open');
                });
                $('select', '.filters').change(function(e) {
                    window.location = $(this).children('option:selected').attr('value');
                });
            }
            if ($('a.open-modal').length) {
                $('a.open-modal').live('click',function(e){
                    e.preventDefault();
                    $target = $($(this).attr('href'));
                    $target.show();

                    $('body').append('

');

                    $target.click(function(event){
                        event.stopPropagation();
                    });
                    $('html').bind('click.modal', function() {
                        closeModal($target);
                    });
                });
                $('.action-close, .close', '.bootstrap').click(function(){
                    closeModal($(this).parents('.modal'));
                    return false;
                });
                function closeModal(e) {
                    e.hide();
                    $('body div.well').remove();
                    $('html').unbind('click.modal');
                }
            }
            $.fn.tabs = function(options){
                this.each(function(){
                    var $this = $(this);

                    var $last_active_tab = $($('li.current a', $this).attr('href'));
                    $('a', $this).add($('a.link_to_tab')).click(function(){
                        var href = $(this).attr('href');
                        $last_active_tab.hide();
                        $last_active_tab = $(href).show();
                        $('li', $this).removeClass('current');
                        $('a[href='+href+']', $this).parent('li').addClass('current');
                        document.location.hash = href.split('-')[0];
                        return false;
                    });
                });
                if (document.location.hash){
                    var tab_name = document.location.hash.split('-', 1);
                    if (tab_name) {
                        $('a[href='+tab_name+'-tab]').click();
                        document.location.href = document.location.href;
                    }
                }
                return this;
            };
            function addCSRFHeader($){
                /* Django will guard against csrf even on XHR requests, so we need to read
                   the value from the cookie and add the header for it */
                $.ajaxSetup({
                    beforeSend: function(xhr, settings) {
                        function getCookie(name) {
                            var cookieValue = null;
                            if (document.cookie && document.cookie !== '') {
                                var cookies = document.cookie.split(';');
                                for (var i = 0; i < cookies.length; i++) {
                                    var cookie = jQuery.trim(cookies[i]);
                                    // Does this cookie string begin with the name we want?
                                    if (cookie.substring(0, name.length + 1) == (name + '=')) {
                                        cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                                        break;
                                    }
                                }
                            }
                            return cookieValue;
                        }
                        if (!((/^http:.*/).test(settings.url) || (/^https:.*/).test(settings.url))) {
                            // Only send the token to relative URLs i.e. locally.
                            xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
                        }
                    }
                });
            }
            $('#closeBut').click(function(){
                $('#messages').remove();
                return false;
            });
            $('li.search input').keypress(function(e) {
                if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
                    $('li.search form').submit();
                    return false;
                }
                else
                    return true;
            });
            jQuery.Rpc.on('exception', function(e){
                jQuery.jGrowl.error(e.message);
            });
            if (window.OLD_MODAL) {
                $.mod();
                $.metadata.setType("attr", "data");
            }

            window.usStartTime = (new Date()).getTime();
            window.addCSRFHeader = addCSRFHeader;
            addCSRFHeader($);
        },

        // Public
        video_view: function() {
            $('.add_subtitles').click(function() {
                widget_widget_div.selectMenuItem(
                unisubs.widget.DropDown.Selection.IMPROVE_SUBTITLES);
                return false;
            });
            $('.add-translation-behavior').click(function() {
                widget_widget_div.selectMenuItem(
                unisubs.widget.DropDown.Selection.ADD_LANGUAGE);
                return false;
            });
            $('.edit-title').click( function() {
                $('#edit-title-dialog .title-input').val($('.title-container').html());
            });
            $('#edit-title-dialog .save-title').click(function() {
                var title = $('#edit-title-dialog .title-input').val();
                if (title) {
                    $('.title-container').html(title).hide().fadeIn();
                    VideosApi.change_title_video(window.VIDEO_ID, title, function(response) {
                        if (response.error) {
                            $.jGrowl.error(response.error);
                        } else {
                            $('.title-container').html(title);
                            document.title = title + ' | Universal Subtitles';
                        }
                    });
                    $('#edit-title-dialog').modClose();
                } else {
                    $.jGrowl.error(window.TITLE_ERROR);
                }
            });
            if (window.TASK) {
                var videoSource = unisubs.player.MediaSource.videoSourceForURL('{{ task.team_video.video.get_video_url }}');
                var opener = new unisubs.widget.SubtitleDialogOpener(
                                     window.TASK_TEAM_VIDEO_ID,
                                     window.TASK_TEAM_VIDEO_URL,
                                     videoSource,
                                     null,
                                     null);
                opener.showStartDialog();
            }

            $('.tabs').tabs();
            unisubs.messaging.simplemessage.displayPendingMessages();
        },

        // Teams
        team_applications: function() {
            that.Utils.chosenify();
        },
        team_members_list: function() {
            that.Utils.resetLangFilter();
            that.Utils.chosenify();
        },
        team_tasks: function() {
            $('a.action-assign').click(function(e) {

                $('div.assignee-choice').hide();

                $form = $(e.target).parents('.admin-controls').siblings('form.assign-form');

                $assignee_choice = $form.children('div.assignee-choice');
                $assignee_choice.fadeIn('fast');

                if (!window.begin_typing_trans) {
                    window.begin_typing_trans = $('option.begin-typing-trans').eq(0).text();
                }
                $select = $form.find('select');
                $select.children('option').remove();
                $select.append('<option value="">-----</option>');
                $select.append('<option value="">' + window.begin_typing_trans + '</option>');
                $select.trigger('liszt:updated');

                $chzn_container = $assignee_choice.find('.chzn-container');
                $chzn_container.css('width', '100%');

                $chzn_drop = $chzn_container.find('.chzn-drop');
                $chzn_drop.css('width', '99%');

                $chzn_input = $chzn_drop.find('input');
                $chzn_input.css('width', '82%');

                return false;
            });
            $('.assignee-choice a.cancel').click(function(e) {
                $(e.target).parents('.assignee-choice').fadeOut('fast');
                return false;
            });
            $('a.action-assign-submit').click(function(e) {
                $(e.target).closest('form').submit();
                return false;
            });
            $('a.assign-and-perform').click(function(e) {
                var $target = $(e.target);
                $target.text('Loading...');

                $.ajax({
                    url: window.ASSIGN_TASK_AJAX_URL,
                    type: 'POST',
                    data: {
                        task: $target.attr('data-id'),
                        assignee: window.ASSIGNEE
                    },
                    success: function(data, textStatus, jqXHR) {
                        $target.hide();

                        $li = $target.parent().siblings('li.hidden-perform-link');
                        $li.show();

                        $link = $li.children('a.perform');
                        $link.text('Loading...');
                        if ($link.attr('href') !== '') {
                            window.location = $link.attr('href');
                        } else {
                            $link.click();
                        }
                    }
                });

                return false;
            });
            $('div.member-ajax-chosen select', '.v1 .content').ajaxChosen({
                method: 'GET',
                url: '/en/teams/' + window.TEAM_SLUG + '/members/search/',
                dataType: 'json'
            }, function (data) {
                var terms = {};
                $.each(data.results, function (i, val) {
                    var can_perform_task = data.results[i][2];

                    if (can_perform_task) {
                        terms[data.results[i][0]] = data.results[i][1];
                    }
                });
                return terms;
            });

            unisubs.widget.WidgetController.makeGeneralSettings(window.WIDGET_SETTINGS);
            that.Utils.resetLangFilter($('select#id_task_language'));
            that.Utils.chosenify();
        },
        team_videos_list: function() {
            $form = $('form', 'div#remove-modal');

            $('a.remove-video').click(function() {
                $form.attr('action', $(this).siblings('form').attr('action'));
            });
            $form.submit(function() {
                var $checked = $('input[name="del-opt"]:checked', 'div#remove-modal');
                if ($checked.val() == 'total-destruction') {
                    $form.attr('action', $form.attr('action').replace('remove', 'delete'));
                    if (confirm('Are you sure you want to permanently delete this video? This action is irreversible.')) {
                        return true;
                    }
                    else {
                        return false;
                    }
                } else {
                    if (confirm('All open tasks for this video will be aborted, and in-progress subtitles will be published. Do you want to proceed?')) {
                        return true;
                    }
                    else {
                        return false;
                    }
                }
            });

            that.Utils.resetLangFilter();
            that.Utils.chosenify();
        }
    };
};

$(function() {
    window.site = new Site();
    window.site.init();
});
<commit_msg>Docs for unisubs.site.js<commit_after>// Universal Subtitles, universalsubtitles.org
//
// Copyright (C) 2012 Participatory Culture Foundation
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see
// http://www.gnu.org/licenses/agpl-3.0.html.

var Site = function(Site) {
    /*
     * This is the master javascript file for
     * the Universal Subtitles website.
     */

    var that = this;

    this.init = function() {

        // Global cached jQuery objects
        this.$html = $('html');
        this.$body = $('html');

        // Base JS (any page that extends base.html)
        if (this.$html.hasClass('base')) {
            this.Views['base']();
        }

        // Page specific JS
        if (this.$html.attr('id')) {
            this.Views[this.$html.attr('id')]();
        }

    };
    this.Utils = {
        /*
         * These are reusable utilities that are
         * usually run on multiple pages. If you
         * find duplicate code that runs on multiple
         * pages, it should be converted to a
         * utility function in this object and
         * called from each of the specific views,
         * like this:
         *
         *     that.Utils.chosenify();
         *
         */

        chosenify: function() {
            $('select', '.v1 .content').filter(function() {
                return !$(this).parents('div').hasClass('ajaxChosen');
            }).chosen().change(function() {
                $select = $(this);

                // New message
                if ($('body').hasClass('new-message')) {
                    $option = $('option:selected', $select);

                    if ($select.attr('id') === 'id_team') {
                        if ($option.val() !== '') {
                            $('div.recipient, div.or').addClass('disabled');
                            $('select#id_user').attr('disabled', 'disabled').trigger('liszt:updated');
                        } else {
                            $('div.recipient, div.or').removeClass('disabled');
                            $('select#id_user').removeAttr('disabled').trigger('liszt:updated');
                        }
                    }
                }
            });
        },
        resetLangFilter: function($select) {
            if (typeof $select == 'undefined') {
                $select = $('select#lang-filter');
            }
            if (window.REQUEST_GET_LANG) {
                $opt = $('option[id="lang-opt-' + window.REQUEST_GET_LANG + '"]');
            } else {
                $opt = $('option[id="lang-opt-any"]');
            }
            $select.children().removeAttr('selected');
            $opt.attr('selected', 'selected');
            $select.trigger('liszt:updated');
        }
    };
    this.Views = {
        /*
         * Each of these views runs on a specific
         * page on the Universal Subtitles site
         * (except for base, which runs on every
         * page that extends base.html)
         *
         * Adding a view is as simple as adding an
         * ID attribute to the specific page's
         * element, and adding the corresponding view
         * below.
         */

        // Global
        base: function() {

            /*
             * TODO: The modules in this section need to
             * be pulled out into that.Utils and only
             * initialized on pages that use them.
             */
            if ($('.abbr').length) {
                $('.abbr').each(function(){
                    var container = $(this);
                    var content = $(this).children('div');
                    var oheight = content.css('height', 'auto').height();
                    content.css('height','6em');
                    $(this).find('.expand').live('click', function(e){
                        e.preventDefault();
                        if(container.hasClass('collapsed')){
                            content.animate({
                                height: oheight
                            }, 'fast');
                            $(this).text('Collapse ↑');
                        } else {
                            content.animate({
                                height: '6em'
                            }, 'fast');
                            $(this).text('Show all ↓');
                        }
                        container.toggleClass('collapsed expanded');
                    });
                });
            }
            if ($('#sort-filter').length) {
                $('#sort-filter').click(function(e) {
                    e.preventDefault();
                    $('.filters').toggle();
                    $(this).children('span').toggleClass('open');
                });
                $('select', '.filters').change(function(e) {
                    window.location = $(this).children('option:selected').attr('value');
                });
            }
            if ($('a.open-modal').length) {
                $('a.open-modal').live('click',function(e){
                    e.preventDefault();
                    $target = $($(this).attr('href'));
                    $target.show();

                    $('body').append('

');

                    $target.click(function(event){
                        event.stopPropagation();
                    });
                    $('html').bind('click.modal', function() {
                        closeModal($target);
                    });
                });
                $('.action-close, .close', '.bootstrap').click(function(){
                    closeModal($(this).parents('.modal'));
                    return false;
                });
                function closeModal(e) {
                    e.hide();
                    $('body div.well').remove();
                    $('html').unbind('click.modal');
                }
            }
            $.fn.tabs = function(options){
                this.each(function(){
                    var $this = $(this);

                    var $last_active_tab = $($('li.current a', $this).attr('href'));
                    $('a', $this).add($('a.link_to_tab')).click(function(){
                        var href = $(this).attr('href');
                        $last_active_tab.hide();
                        $last_active_tab = $(href).show();
                        $('li', $this).removeClass('current');
                        $('a[href='+href+']', $this).parent('li').addClass('current');
                        document.location.hash = href.split('-')[0];
                        return false;
                    });
                });
                if (document.location.hash){
                    var tab_name = document.location.hash.split('-', 1);
                    if (tab_name) {
                        $('a[href='+tab_name+'-tab]').click();
                        document.location.href = document.location.href;
                    }
                }
                return this;
            };
            function addCSRFHeader($){
                /* Django will guard against csrf even on XHR requests, so we need to read
                   the value from the cookie and add the header for it */
                $.ajaxSetup({
                    beforeSend: function(xhr, settings) {
                        function getCookie(name) {
                            var cookieValue = null;
                            if (document.cookie && document.cookie !== '') {
                                var cookies = document.cookie.split(';');
                                for (var i = 0; i < cookies.length; i++) {
                                    var cookie = jQuery.trim(cookies[i]);
                                    // Does this cookie string begin with the name we want?
                                    if (cookie.substring(0, name.length + 1) == (name + '=')) {
                                        cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                                        break;
                                    }
                                }
                            }
                            return cookieValue;
                        }
                        if (!((/^http:.*/).test(settings.url) || (/^https:.*/).test(settings.url))) {
                            // Only send the token to relative URLs i.e. locally.
                            xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
                        }
                    }
                });
            }
            $('#closeBut').click(function(){
                $('#messages').remove();
                return false;
            });
            $('li.search input').keypress(function(e) {
                if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
                    $('li.search form').submit();
                    return false;
                }
                else
                    return true;
            });
            jQuery.Rpc.on('exception', function(e){
                jQuery.jGrowl.error(e.message);
            });
            if (window.OLD_MODAL) {
                $.mod();
                $.metadata.setType("attr", "data");
            }

            window.usStartTime = (new Date()).getTime();
            window.addCSRFHeader = addCSRFHeader;
            addCSRFHeader($);
        },

        // Public
        video_view: function() {
            $('.add_subtitles').click(function() {
                widget_widget_div.selectMenuItem(
                unisubs.widget.DropDown.Selection.IMPROVE_SUBTITLES);
                return false;
            });
            $('.add-translation-behavior').click(function() {
                widget_widget_div.selectMenuItem(
                unisubs.widget.DropDown.Selection.ADD_LANGUAGE);
                return false;
            });
            $('.edit-title').click( function() {
                $('#edit-title-dialog .title-input').val($('.title-container').html());
            });
            $('#edit-title-dialog .save-title').click(function() {
                var title = $('#edit-title-dialog .title-input').val();
                if (title) {
                    $('.title-container').html(title).hide().fadeIn();
                    VideosApi.change_title_video(window.VIDEO_ID, title, function(response) {
                        if (response.error) {
                            $.jGrowl.error(response.error);
                        } else {
                            $('.title-container').html(title);
                            document.title = title + ' | Universal Subtitles';
                        }
                    });
                    $('#edit-title-dialog').modClose();
                } else {
                    $.jGrowl.error(window.TITLE_ERROR);
                }
            });
            if (window.TASK) {
                var videoSource = unisubs.player.MediaSource.videoSourceForURL('{{ task.team_video.video.get_video_url }}');
                var opener = new unisubs.widget.SubtitleDialogOpener(
                                     window.TASK_TEAM_VIDEO_ID,
                                     window.TASK_TEAM_VIDEO_URL,
                                     videoSource,
                                     null,
                                     null);
                opener.showStartDialog();
            }

            $('.tabs').tabs();
            unisubs.messaging.simplemessage.displayPendingMessages();
        },

        // Teams
        team_applications: function() {
            that.Utils.chosenify();
        },
        team_members_list: function() {
            that.Utils.resetLangFilter();
            that.Utils.chosenify();
        },
        team_tasks: function() {
            $('a.action-assign').click(function(e) {

                $('div.assignee-choice').hide();

                $form = $(e.target).parents('.admin-controls').siblings('form.assign-form');

                $assignee_choice = $form.children('div.assignee-choice');
                $assignee_choice.fadeIn('fast');

                if (!window.begin_typing_trans) {
                    window.begin_typing_trans = $('option.begin-typing-trans').eq(0).text();
                }
                $select = $form.find('select');
                $select.children('option').remove();
                $select.append('<option value="">-----</option>');
                $select.append('<option value="">' + window.begin_typing_trans + '</option>');
                $select.trigger('liszt:updated');

                $chzn_container = $assignee_choice.find('.chzn-container');
                $chzn_container.css('width', '100%');

                $chzn_drop = $chzn_container.find('.chzn-drop');
                $chzn_drop.css('width', '99%');

                $chzn_input = $chzn_drop.find('input');
                $chzn_input.css('width', '82%');

                return false;
            });
            $('.assignee-choice a.cancel').click(function(e) {
                $(e.target).parents('.assignee-choice').fadeOut('fast');
                return false;
            });
            $('a.action-assign-submit').click(function(e) {
                $(e.target).closest('form').submit();
                return false;
            });
            $('a.assign-and-perform').click(function(e) {
                var $target = $(e.target);
                $target.text('Loading...');

                $.ajax({
                    url: window.ASSIGN_TASK_AJAX_URL,
                    type: 'POST',
                    data: {
                        task: $target.attr('data-id'),
                        assignee: window.ASSIGNEE
                    },
                    success: function(data, textStatus, jqXHR) {
                        $target.hide();

                        $li = $target.parent().siblings('li.hidden-perform-link');
                        $li.show();

                        $link = $li.children('a.perform');
                        $link.text('Loading...');
                        if ($link.attr('href') !== '') {
                            window.location = $link.attr('href');
                        } else {
                            $link.click();
                        }
                    }
                });

                return false;
            });
            $('div.member-ajax-chosen select', '.v1 .content').ajaxChosen({
                method: 'GET',
                url: '/en/teams/' + window.TEAM_SLUG + '/members/search/',
                dataType: 'json'
            }, function (data) {
                var terms = {};
                $.each(data.results, function (i, val) {
                    var can_perform_task = data.results[i][2];

                    if (can_perform_task) {
                        terms[data.results[i][0]] = data.results[i][1];
                    }
                });
                return terms;
            });

            unisubs.widget.WidgetController.makeGeneralSettings(window.WIDGET_SETTINGS);
            that.Utils.resetLangFilter($('select#id_task_language'));
            that.Utils.chosenify();
        },
        team_videos_list: function() {
            $form = $('form', 'div#remove-modal');

            $('a.remove-video').click(function() {
                $form.attr('action', $(this).siblings('form').attr('action'));
            });
            $form.submit(function() {
                var $checked = $('input[name="del-opt"]:checked', 'div#remove-modal');
                if ($checked.val() == 'total-destruction') {
                    $form.attr('action', $form.attr('action').replace('remove', 'delete'));
                    if (confirm('Are you sure you want to permanently delete this video? This action is irreversible.')) {
                        return true;
                    }
                    else {
                        return false;
                    }
                } else {
                    if (confirm('All open tasks for this video will be aborted, and in-progress subtitles will be published. Do you want to proceed?')) {
                        return true;
                    }
                    else {
                        return false;
                    }
                }
            });

            that.Utils.resetLangFilter();
            that.Utils.chosenify();
        }
    };
};

$(function() {
    window.site = new Site();
    window.site.init();
});
<|endoftext|>


<commit_before>var cookiesMap = {};
var domainReg = /^https?\:\/\/(.*?)\/(.*?)?([\?#].*)?$/i;
var base = domainReg.test(location.href) ? "/" : "http://efront.cc/";
var HeadersKeys = ["Content-Type"];
var cookieItemsInSessionStorageKey = "--zimoli-coms-cross";
var cookiesData = sessionStorage.getItem(cookieItemsInSessionStorageKey);
if (cookiesData) {
    try {
        extend(cookiesMap, JSON.parse(cookiesData));
    } catch (e) {
        console.warn("加载cookie出错！");
    }
}
function getDomainPath(url) {
    return url.replace(domainReg, "$1/$2");
}
function getRequestProtocol(url) {
    if (/^https:/i.test(url)) {
        return "https";
    }
    return "http";
}
function getCookies(domainPath) {
    var cookieObject = {};
    var splited = domainPath.split("/");
    var domain = splited[0];
    do {
        var copy = splited.slice(0);
        do {
            domainPath = copy.join("/");
            var cookie = cookiesMap[domainPath];
            if (cookie) {
                for (var k in cookie) {
                    if (!cookieObject[k]) {
                        cookieObject[k] = cookie[k];
                    }
                }
            }
            copy.pop();
        } while (copy.length);
        domain = domain.replace(/^.*?(\.|$)/, "");
        splited[0] = domain;
    } while (domain.length);
    return serialize(cookieObject, ";");
}
function addCookie(cookie, originDomain = "") {
    if (cookie) {
        clearTimeout(addCookie.save_timer);
        addCookie.save_timer = setTimeout(function () {
            sessionStorage.setItem(cookieItemsInSessionStorageKey, JSON.stringify(cookiesMap));
        }, 20);
        cookie.replace(/(^|;|,)\s*(expires)=(\w*),([^=]*)(;|$)/ig, "$1$2=$3.$4$5")
            .split(/,\s*/).map(function (cookie) {
                var cookieObject = {};
                var result = cookie.split(/;\s*/);
                result.slice(1).map(function (kev) {
                    var kvs = /^(.+?)\=(.+?)$/.exec(kev);
                    if (kvs) {
                        var [, k, v] = kvs;
                        cookieObject[k.toLowerCase()] = v;
                    }
                });
                var { path, domain } = cookieObject;
                if (!domain) {
                    domain = originDomain.replace(/[^\/]+$/, "");
                }
                if (/^\./.test(domain)) {
                    domain = domain.replace(/^\.+/, "");
                }
                var destPath;
                if (/^\//.test(path)) {
                    destPath = domain.replace(/\/.*$/, "") + path;
                } else {
                    destPath = domain;
                }
                destPath = destPath.replace(/\/+$/, "");
                if (originDomain.indexOf(destPath) >= 0) {
                    var cookieMap = parseKV(result[0], ";");
                    if (!cookiesMap[destPath]) {
                        cookiesMap[destPath] = cookieMap;
                    } else {
                        extend(cookiesMap[destPath], cookieMap);
                    }
                }
            });
    }
}
function isChildPath(relative, path) {
    return relative.replace(/^(.*\/)[^\/]*$/, path);
}
var digest = function () {
    if (cross.digest instanceof Function) cross.digest();
};

var getCrossUrl = function (domain, headers) {
    var originDomain = getDomainPath(domain);
    var _cookies = getCookies(originDomain);
    var _headers = {};
    if (_cookies) {
        _headers.Cookie = _cookies;
    }
    extend(_headers, headers);
    var spliter = encodeURIComponent("/");
    return domain.replace(/^s?\/\//i, "http$&").replace(domainReg, `{${spliter + spliter}$1${spliter}${serialize(_headers)}}@$2$3`);
};
function cross(method, url, headers) {
    var originDomain = getDomainPath(url);
    if (!originDomain) throw new Error("Unsupposed url format!");
    var _cookies = getCookies(originDomain);
    var _headers = {};
    if (_cookies) {
        _headers.Cookie = _cookies;
    }
    extend(_headers, headers);
    var xhr = new XHR;
    xhr.open(method, base + encodeURIComponent(JSON.stringify({
        url,
        token: "0",
        headers: _headers
    })));
    HeadersKeys.map(function (k) {
        if (_headers[k]) xhr.setRequestHeader(k, _headers[k]);
        delete _headers[k];
    });

    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
            if (xhr.getResponseHeader) {
                var cookie = xhr.getResponseHeader("cross-cookie");
                addCookie(cookie, originDomain);
            }
            switch (xhr.status) {
                case 0:
                case 200:
                case 304:
                    onload(xhr);
                    break;
                case 302:
                case 301:
                    if (xhr.isRedirected > 2) break;
                    var location = xhr.getResponseHeader("cross-location");
                    if (!domainReg.test(location)) {
                        if (/^\//.test(location)) {
                            location = originDomain.replace(/\/.*$/, location);
                        } else {
                            location = originDomain.replace(/[^\/+]$/, location);
                        }
                        location = getRequestProtocol(url) + "://" + location;
                    }
                    var crs = cross("get", location, headers);
                    crs.isRedirected = (xhr.isRedirected || 0) + 1;
                    onload && crs.done(onload, false);
                    onerror && crs.error(onerror, false);
                    break;
                default:
                    onerror(xhr);
            }
        }
    };
    setTimeout(function () {
        if (jsondata && !datas) {
            datas = JSON.stringify(jsondata);
            xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
        }
        send.call(xhr, datas);
    }, 0);
    var onload = function (xhr) {
        if (xhr.decoder) {
            xhr = xhr.decoder(xhr);
        }
        onloads.map(e => e instanceof Function && e(xhr));
        digest();
    };
    var onerror = function (xhr) {
        onerrors.map(e => e instanceof Function && e(xhr));
        digest();
    };
    var onloads = [], onerrors = [];
    xhr.done = function (on, asqueue = true) {
        if (asqueue) {
            onloads.push(on);
        } else {
            onload = on;
        }
        return xhr;
    };
    var send = xhr.send;
    var datas = "";
    var jsondata = null;
    xhr.json = xhr.data = xhr.send = function (data, value) {
        if (!jsondata) jsondata = {};
        if (data instanceof Object) {
            extend(jsondata, data);
        } else if (value) {
            extend(jsondata, { [data]: value })
        } else if (isString(data) && value !== false) {
            var data = /^\{/.test(data) ? JSON.parse(data) : parseKV(data, "&", "=");
            extend(jsondata, data);
        } else {
            datas = data;
        }
        return xhr;
    };
    xhr.form = function (data) {
        xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        xhr.data(data);
        datas = serialize(jsondata, "&", "=");
    };
    xhr.fail = xhr.error = function (on, asqueue = true) {
        if (asqueue) {
            onerrors.push(on);
        } else {
            onerror = on;
        }
        onerror = on;
        return xhr;
    };
    return xhr;
}
extend(cross, {
    getCookies,
    addCookie,
    getCrossUrl
});<commit_msg>getCrossURL请求路径前加上base<commit_after>var cookiesMap = {};
var domainReg = /^https?\:\/\/(.*?)\/(.*?)?([\?#].*)?$/i;
var base = domainReg.test(location.href) ? "/" : "http://efront.cc/";
var HeadersKeys = ["Content-Type"];
var cookieItemsInSessionStorageKey = "--zimoli-coms-cross";
var cookiesData = sessionStorage.getItem(cookieItemsInSessionStorageKey);
if (cookiesData) {
    try {
        extend(cookiesMap, JSON.parse(cookiesData));
    } catch (e) {
        console.warn("加载cookie出错！");
    }
}
function getDomainPath(url) {
    return url.replace(domainReg, "$1/$2");
}
function getRequestProtocol(url) {
    if (/^https:/i.test(url)) {
        return "https";
    }
    return "http";
}
function getCookies(domainPath) {
    var cookieObject = {};
    var splited = domainPath.split("/");
    var domain = splited[0];
    do {
        var copy = splited.slice(0);
        do {
            domainPath = copy.join("/");
            var cookie = cookiesMap[domainPath];
            if (cookie) {
                for (var k in cookie) {
                    if (!cookieObject[k]) {
                        cookieObject[k] = cookie[k];
                    }
                }
            }
            copy.pop();
        } while (copy.length);
        domain = domain.replace(/^.*?(\.|$)/, "");
        splited[0] = domain;
    } while (domain.length);
    return serialize(cookieObject, ";");
}
function addCookie(cookie, originDomain = "") {
    if (cookie) {
        clearTimeout(addCookie.save_timer);
        addCookie.save_timer = setTimeout(function () {
            sessionStorage.setItem(cookieItemsInSessionStorageKey, JSON.stringify(cookiesMap));
        }, 20);
        cookie.replace(/(^|;|,)\s*(expires)=(\w*),([^=]*)(;|$)/ig, "$1$2=$3.$4$5")
            .split(/,\s*/).map(function (cookie) {
                var cookieObject = {};
                var result = cookie.split(/;\s*/);
                result.slice(1).map(function (kev) {
                    var kvs = /^(.+?)\=(.+?)$/.exec(kev);
                    if (kvs) {
                        var [, k, v] = kvs;
                        cookieObject[k.toLowerCase()] = v;
                    }
                });
                var { path, domain } = cookieObject;
                if (!domain) {
                    domain = originDomain.replace(/[^\/]+$/, "");
                }
                if (/^\./.test(domain)) {
                    domain = domain.replace(/^\.+/, "");
                }
                var destPath;
                if (/^\//.test(path)) {
                    destPath = domain.replace(/\/.*$/, "") + path;
                } else {
                    destPath = domain;
                }
                destPath = destPath.replace(/\/+$/, "");
                if (originDomain.indexOf(destPath) >= 0) {
                    var cookieMap = parseKV(result[0], ";");
                    if (!cookiesMap[destPath]) {
                        cookiesMap[destPath] = cookieMap;
                    } else {
                        extend(cookiesMap[destPath], cookieMap);
                    }
                }
            });
    }
}
function isChildPath(relative, path) {
    return relative.replace(/^(.*\/)[^\/]*$/, path);
}
var digest = function () {
    if (cross.digest instanceof Function) cross.digest();
};

var getCrossUrl = function (domain, headers) {
    var originDomain = getDomainPath(domain);
    var _cookies = getCookies(originDomain);
    var _headers = {};
    if (_cookies) {
        _headers.Cookie = _cookies;
    }
    extend(_headers, headers);
    var spliter = encodeURIComponent("/");
    return domain.replace(/^s?\/\//i, "http$&").replace(domainReg, base + `{${spliter + spliter}$1${spliter}${serialize(_headers)}}@$2$3`);
};
function cross(method, url, headers) {
    var originDomain = getDomainPath(url);
    if (!originDomain) throw new Error("Unsupposed url format!");
    var _cookies = getCookies(originDomain);
    var _headers = {};
    if (_cookies) {
        _headers.Cookie = _cookies;
    }
    extend(_headers, headers);
    var xhr = new XHR;
    xhr.open(method, base + encodeURIComponent(JSON.stringify({
        url,
        token: "0",
        headers: _headers
    })));
    HeadersKeys.map(function (k) {
        if (_headers[k]) xhr.setRequestHeader(k, _headers[k]);
        delete _headers[k];
    });

    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
            if (xhr.getResponseHeader) {
                var cookie = xhr.getResponseHeader("cross-cookie");
                addCookie(cookie, originDomain);
            }
            switch (xhr.status) {
                case 0:
                case 200:
                case 304:
                    onload(xhr);
                    break;
                case 302:
                case 301:
                    if (xhr.isRedirected > 2) break;
                    var location = xhr.getResponseHeader("cross-location");
                    if (!domainReg.test(location)) {
                        if (/^\//.test(location)) {
                            location = originDomain.replace(/\/.*$/, location);
                        } else {
                            location = originDomain.replace(/[^\/+]$/, location);
                        }
                        location = getRequestProtocol(url) + "://" + location;
                    }
                    var crs = cross("get", location, headers);
                    crs.isRedirected = (xhr.isRedirected || 0) + 1;
                    onload && crs.done(onload, false);
                    onerror && crs.error(onerror, false);
                    break;
                default:
                    onerror(xhr);
            }
        }
    };
    setTimeout(function () {
        if (jsondata && !datas) {
            datas = JSON.stringify(jsondata);
            xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
        }
        send.call(xhr, datas);
    }, 0);
    var onload = function (xhr) {
        if (xhr.decoder) {
            xhr = xhr.decoder(xhr);
        }
        onloads.map(e => e instanceof Function && e(xhr));
        digest();
    };
    var onerror = function (xhr) {
        onerrors.map(e => e instanceof Function && e(xhr));
        digest();
    };
    var onloads = [], onerrors = [];
    xhr.done = function (on, asqueue = true) {
        if (asqueue) {
            onloads.push(on);
        } else {
            onload = on;
        }
        return xhr;
    };
    var send = xhr.send;
    var datas = "";
    var jsondata = null;
    xhr.json = xhr.data = xhr.send = function (data, value) {
        if (!jsondata) jsondata = {};
        if (data instanceof Object) {
            extend(jsondata, data);
        } else if (value) {
            extend(jsondata, { [data]: value })
        } else if (isString(data) && value !== false) {
            var data = /^\{/.test(data) ? JSON.parse(data) : parseKV(data, "&", "=");
            extend(jsondata, data);
        } else {
            datas = data;
        }
        return xhr;
    };
    xhr.form = function (data) {
        xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        xhr.data(data);
        datas = serialize(jsondata, "&", "=");
    };
    xhr.fail = xhr.error = function (on, asqueue = true) {
        if (asqueue) {
            onerrors.push(on);
        } else {
            onerror = on;
        }
        onerror = on;
        return xhr;
    };
    return xhr;
}
extend(cross, {
    getCookies,
    addCookie,
    getCrossUrl
});<|endoftext|>


<commit_before>/* global define */
define(['./deps', './functions', './Library', './mergeInto', './objects', './__'], function(__deps, __functions, __Library, __mergeInto, __objects, __tmlib){
	var __Array = __deps.Array;
	var __globals = __deps.globals;
	var __jQuery = __deps.jQuery;
	var __Object = __deps.Object;

	/*
	Library: classes
	Libary for creating and working with classes.
	*/
	var __classes = new __Library({
		/*=====
		==configuration
		=====*/
		'config': {
			//--using autoapply makes for a nicer interface, but also has a performance penalty
			'autoApplyForFunctionInheritance': true
			,'overriddenParentKey': '__base'
		}
		,'creationPlugins': {
			/*
			Function: addParentAccessToMethods

			Adds ability to call 'this.base(arguments)' from child class methods to access parent class methods of same name
			*/
			'addParentAccessToMethods': function(_options){
				var _parent = _options.parent;
				var _prototype = _options.prototype;
				_options = _options.options;
				var _properties =
					(typeof _options.properties == 'object')
					? __objects.merge(_options.properties)
					: {}
				;
				//--add init method to properties if it exists
				if(typeof _options.init != 'undefined'){
					_properties.init = _options.init;
				}
				//--duck punch overridden methods to have access to parent class.  This has a noticable performance penalty, so if you need increased performance, call/apply with the prototype of the parent class directly
				for(var _name in _properties){
					if(
						//--only override if function is in both parent and child classes
						typeof _prototype[_name] == 'function'
						&& typeof _parent.prototype[_name] == 'function'
						//--only override if function actually calls the parent
						&& __functions.contains(_prototype[_name], '\\b' + this.config.overriddenParentKey + '(\\(|\\.apply|\\.call)\\b')
					){
						_prototype[_name] = __functions.duckPunch(
							_parent.prototype[_name]
							,_prototype[_name]
							,{
								autoApply: this.config.autoApplyForFunctionInheritance
								,key: this.config.overriddenParentKey
								,name: _name
								,type: 'this'
							}
						);
					}
				}
			}
		}

		/*=====
		==Library functions
		=====*/
		/*
		Function: create
		Create a class.  Provides an abstraction to creating classes directly by creating functions and manipulating their prototypes.  Will become much more capable, though ideally this'll be designed to be minimal but extensible to support other functionality.  Eventually all non-library classes will be migrated to be created by this function.  Meant to replace __.class.define, though it may take some bits from it before it gets removed.

		Parameters:
			_options(map):
				init(Function|null): Function to run as constructor.  null prevents parent constructor from being run
				mixins(Array): Collection of class definitions to mix in properties of to class.  Mixed in before class properties, so that class properties will override mixin properties.
				name(String): A string name for the class.  Currently used only to assign to the window namespace, though will support any namespace and will use this for class meta data later.
				parent(Object|String): Object to extend.  If none is passed, will extend a base object or the built in object.
				preMixins(Array): Collection of class definitions to mix in properties of to class.  Mixed in before classes properties and before regular mixins.  Here primarily to match postMixins naming convention.
				postMixins(Array): Collection of class definitions to mix in properties of to class.  Mixed in after all other property definitions, and thus will override them.
				properties(map): Properties to add to object's prototype.  Currently added directly, but will eventually support per property configuration by passing a map.
				statics(map): Properties to add directly to class, to be called statically.

		Return:
			Function object, the constructor of the class, but representing the class itself.
		*/
		,'create': function(_options){
			if(typeof _options == 'undefined'){
				_options = {};
			}

			//--create base prototype inheriting from parent
			var _parent;
			switch(typeof _options.parent){
				case 'string':
					//-! should accomodate namespaces
					_parent = __globals[_options.parent];
				break;
				case 'function':
				case 'object':
					_parent = _options.parent;
				break;
				default:
					if(typeof __tmlib.core.BaseClass != 'undefined'){
						_parent = __tmlib.core.BaseClass;
					}else{
						_parent = __Object;
					}
				break;
			}

			//--create class/constructor
			var _class = this.createConstructor(_parent);

			//--create prototype from parent
			var _prototype = this.createPrototype(_parent);

			//--merge statics into class
			//---must explicitely merge in parent statics, since this is a new 'class'
			__mergeInto(_class, _parent);
			//---now merge with overwrite the passed in statics
			if(typeof _options.statics == 'object'){
				_class = __mergeInto(_class, _options.statics);
			}

			//--add properties to object
			this.mixIn(_options, _prototype, _class);
			if(typeof _options.init == 'function'){
				__objects.addProperty(_prototype, 'init', _options.init);
			}

			//--perform plugin functionality
			for(var _key in this.creationPlugins){
				if(this.creationPlugins.hasOwnProperty(_key)){
					this.creationPlugins[_key].call(this, {
						'class': _class
						,'parent': _parent
						,'prototype': _prototype
						,'options': _options
					});
				}
			}

			//--set class prototype
			_class.prototype = _prototype;

			//--replace constructor so it is as it should be
			_class.prototype.constructor = _class;

			//--set appropriate object name if provided
			if(_options.name){
				//-! should support namespaces
				__globals[_options.name] = _class;
			}
			return _class;
		}

		/*
		Function: createConstructor
		Creates default constructor function for class.  Done as separate function so that it can be overridable.
		Parameters:
			_parent(Class): 'class' (constructor) of parent class
		Return:
			Function to act as constructor of class
		*/
		,'createConstructor': function(_parent){
			return function _class(){
				//--don't run if creating prototype via this.createPrototype
				if(!__classes.__isCreatingPrototype){
					//--call defined constructor or parent constructor
					switch(typeof this.init){
						//--call class's init method, if it exists
						case 'function':
							this.init.apply(this, arguments);
						break;
						//--call parent's constructor (useful for non-tmlib classes)
						case 'undefined':
							_parent.apply(this, arguments);
						break;
						//--all other possibilities cause nothing to happen
					}
				}
			};
		}

		/*
		Function: createPrototype
		Create prototype of class by creating an instance.  Set __isCreatingPrototype to ensure the constructors of all functions created through Classes.create will not run

		Parameters:
			Class(Function): class to create prototype for

		Return:
			Object to serve as a prototype for another object that will properly inherit from the given class object.
		*/
		,'createPrototype': function(_Class){
			//--ensure parent constructor not run
			this.__isCreatingPrototype = true;
			//--create prototype with 'new' keyword so that classes using this prototype will be seen as instances of the class
			var _prototype = new _Class();
			//--ensure constructor will be run on future creations
			this.__isCreatingPrototype = false;

			return _prototype;
		}

		/*
		Function: mixIn
		Parameters:
			mixin(Array|Map): If an array of class definitions, run mixIn on each definition.  If a definition, mix this definition in to object/parent.
			object(Object): object to mix properties into
			parent(Function): function to mix statics into
		*/
		,'mixIn': function(_mixin, _object, _parent){
			var _i;
			var _key;
			var _mixinsLength;
			if(typeof _mixin == 'object'){
				//--if _mixin is an array, mix in all objects in array
				if(_mixin instanceof __Array){
					for(
						_i = 0, _mixinsLength = _mixin.length
						; _i < _mixinsLength
						; ++_i
					){
						this.mixIn(_mixin[_i], _object, _parent);
					}
				}else{
					//--mix in pre mixins
					if(typeof _mixin.preMixins == 'object'){
						this.mixIn(_mixin.preMixins, _object, _parent);
					}
					//--mix in mixins
					if(typeof _mixin.mixins == 'object'){
						this.mixIn(_mixin.mixins, _object, _parent);
					}
					//--mix in statics
					if(typeof _mixin.statics == 'object' && typeof _parent == 'function'){
						for(_key in _mixin.statics){
							if(_mixin.statics.hasOwnProperty(_key)){
								_parent[_key] = _mixin.statics[_key];
							}
						}
					}
					//--mix in properties
					if(typeof _mixin.properties == 'object'){
						for(_key in _mixin.properties){
							if(_mixin.properties.hasOwnProperty(_key)){
								_object[_key] = _mixin.properties[_key];
							}
						}
					}
					//--mix in postmixins
					if(typeof _mixin.postMixins == 'object'){
						this.mixIn(_mixin.postMixins, _object, _parent);
					}
				}
			}
		}

		/*
		Function: pluginize
		Converts any class/object into a function to be used by another class/object to give it an instance of the 'pluginized' class/object.  With the jQuery type, this function is added to the jQuery object, effectively making it a plugin.
		Parameters:
			options(map):
				class(Function): Class to instantiate for use as plugin.  Used if each containing object will have its own instance of the class, in place of the 'object' option
				mapToThis(String): string will be key used for passing containing object's 'this' to pluginized object's constructor
				object(Object): Object to use for plugin.  Used if one object instance is shared among all containing object instances, in place of the 'class' option
				type(String): name of the type of plugin to create.  default: method
					method: returns the pluganized method that can be added to any object/class
					jQuery: attaches the pluganized method to the jQuery object
		*/
		,'pluginize': function(_options){
			var _type = _options.type || 'method';
			_options = __mergeInto({
				'mapToThis': 'elements'
			}, _options);
			var _handler = function(){
				var _args = arguments; //-# enhancement for obfuscation to allow arguments to become a shorter variable, saving 128 bytes at time of commit
				if(typeof _handler.instance == 'undefined' || typeof _args[0] == 'undefined'){
					switch(typeof _options.mapToThis){
						case 'string':
							if(typeof _args[0] != 'object'){
								_args[0] = {};
							}
							_args[0][_options.mapToThis] = this;
						break;
						case 'number':
							_args[_options.mapToThis] = this;
						break;
						default:
							throw new Error('Pluginize does not support a "mapToThis" type of ' + typeof _options.mapToThis);
					}
					if(typeof _options.object == 'object'){
						_handler.instance = _options.object;
					}else{
						_handler.instance = new _options['class'](
							_args[0]
							,_args[1]
							,_args[2]
							,_args[3]
							,_args[4]
							,_args[5]
							,_args[6]
							,_args[7]
							,_args[8]
							,_args[9]
						);
					}
				}else if(typeof _args[0] == 'string'){
					//--shift off first argument as name of function
					var _propertyName = __Array.prototype.shift.call(_args);
					if(typeof _handler.instance[_propertyName] == 'function'){
						return _handler.instance[_propertyName].apply(_handler.instance, _args);
					}else{
						return _handler.instance[_propertyName];
					}
				}else{
					throw new Error('Must pass name of function to call for plugin.');
				}
			};
			switch(_type){
				case 'method':
					return _handler;
				//-# break;
				case 'jQuery':
					__jQuery.fn[_options.name] = _handler;
				break;
				default:
					throw new Error('Pluginize doesn\'t support type ' + _type);
				//-# break;
			}
		}
	});

	//--add to tmlib and export
	__tmlib.__('.core', {'classes': __classes});
	return __classes;
});
<commit_msg>src/core/classes: simplified createPrototype() to not need to set 'global' variable and check it in constructors<commit_after>/* global define */
define(['./deps', './functions', './Library', './mergeInto', './objects', './__'], function(__deps, __functions, __Library, __mergeInto, __objects, __tmlib){
	var __Array = __deps.Array;
	var __globals = __deps.globals;
	var __jQuery = __deps.jQuery;
	var __Object = __deps.Object;

	/*
	Library: classes
	Libary for creating and working with classes.
	*/
	var __classes = new __Library({
		/*=====
		==configuration
		=====*/
		'config': {
			//--using autoapply makes for a nicer interface, but also has a performance penalty
			'autoApplyForFunctionInheritance': true
			,'overriddenParentKey': '__base'
		}
		,'creationPlugins': {
			/*
			Function: addParentAccessToMethods

			Adds ability to call 'this.base(arguments)' from child class methods to access parent class methods of same name
			*/
			'addParentAccessToMethods': function(_options){
				var _parent = _options.parent;
				var _prototype = _options.prototype;
				_options = _options.options;
				var _properties =
					(typeof _options.properties == 'object')
					? __objects.merge(_options.properties)
					: {}
				;
				//--add init method to properties if it exists
				if(typeof _options.init != 'undefined'){
					_properties.init = _options.init;
				}
				//--duck punch overridden methods to have access to parent class.  This has a noticable performance penalty, so if you need increased performance, call/apply with the prototype of the parent class directly
				for(var _name in _properties){
					if(
						//--only override if function is in both parent and child classes
						typeof _prototype[_name] == 'function'
						&& typeof _parent.prototype[_name] == 'function'
						//--only override if function actually calls the parent
						&& __functions.contains(_prototype[_name], '\\b' + this.config.overriddenParentKey + '(\\(|\\.apply|\\.call)\\b')
					){
						_prototype[_name] = __functions.duckPunch(
							_parent.prototype[_name]
							,_prototype[_name]
							,{
								autoApply: this.config.autoApplyForFunctionInheritance
								,key: this.config.overriddenParentKey
								,name: _name
								,type: 'this'
							}
						);
					}
				}
			}
		}

		/*=====
		==Library functions
		=====*/
		/*
		Function: create
		Create a class.  Provides an abstraction to creating classes directly by creating functions and manipulating their prototypes.  Will become much more capable, though ideally this'll be designed to be minimal but extensible to support other functionality.  Eventually all non-library classes will be migrated to be created by this function.  Meant to replace __.class.define, though it may take some bits from it before it gets removed.

		Parameters:
			_options(map):
				init(Function|null): Function to run as constructor.  null prevents parent constructor from being run
				mixins(Array): Collection of class definitions to mix in properties of to class.  Mixed in before class properties, so that class properties will override mixin properties.
				name(String): A string name for the class.  Currently used only to assign to the window namespace, though will support any namespace and will use this for class meta data later.
				parent(Object|String): Object to extend.  If none is passed, will extend a base object or the built in object.
				preMixins(Array): Collection of class definitions to mix in properties of to class.  Mixed in before classes properties and before regular mixins.  Here primarily to match postMixins naming convention.
				postMixins(Array): Collection of class definitions to mix in properties of to class.  Mixed in after all other property definitions, and thus will override them.
				properties(map): Properties to add to object's prototype.  Currently added directly, but will eventually support per property configuration by passing a map.
				statics(map): Properties to add directly to class, to be called statically.

		Return:
			Function object, the constructor of the class, but representing the class itself.
		*/
		,'create': function(_options){
			if(typeof _options == 'undefined'){
				_options = {};
			}

			//--create base prototype inheriting from parent
			var _parent;
			switch(typeof _options.parent){
				case 'string':
					//-! should accomodate namespaces
					_parent = __globals[_options.parent];
				break;
				case 'function':
				case 'object':
					_parent = _options.parent;
				break;
				default:
					if(typeof __tmlib.core.BaseClass != 'undefined'){
						_parent = __tmlib.core.BaseClass;
					}else{
						_parent = __Object;
					}
				break;
			}

			//--create class/constructor
			var _class = this.createConstructor(_parent);

			//--create prototype from parent
			var _prototype = this.createPrototype(_parent);

			//--merge statics into class
			//---must explicitely merge in parent statics, since this is a new 'class'
			__mergeInto(_class, _parent);
			//---now merge with overwrite the passed in statics
			if(typeof _options.statics == 'object'){
				_class = __mergeInto(_class, _options.statics);
			}

			//--add properties to object
			this.mixIn(_options, _prototype, _class);
			if(typeof _options.init == 'function'){
				__objects.addProperty(_prototype, 'init', _options.init);
			}

			//--perform plugin functionality
			for(var _key in this.creationPlugins){
				if(this.creationPlugins.hasOwnProperty(_key)){
					this.creationPlugins[_key].call(this, {
						'class': _class
						,'parent': _parent
						,'prototype': _prototype
						,'options': _options
					});
				}
			}

			//--set class prototype
			_class.prototype = _prototype;

			//--replace constructor so it is as it should be
			_class.prototype.constructor = _class;

			//--set appropriate object name if provided
			if(_options.name){
				//-! should support namespaces
				__globals[_options.name] = _class;
			}
			return _class;
		}

		/*
		Function: createConstructor
		Creates default constructor function for class.  Done as separate function so that it can be overridable.
		Parameters:
			_parent(Class): 'class' (constructor) of parent class
		Return:
			Function to act as constructor of class
		*/
		,'createConstructor': function(_parent){
			var _this = this;
			var _constructor = function _tmConstructor(){
				//--using new keyword, handle normally
				if(this instanceof _constructor){
					//--call defined constructor or parent constructor
					switch(typeof this.init){
						//--call class's init method, if it exists
						case 'function':
							this.init.apply(this, arguments);
						break;
						//--call parent's constructor (useful for non-tmlib classes)
						case 'undefined':
							_parent.apply(this, arguments);
						break;
						//--all other possibilities cause nothing to happen
					}
				}
			};
			return _constructor;
		}

		/*
		Function: createPrototype
		Create prototype of class.
		Parameters:
			Class(Function): class to create prototype for

		Return:
			Object to serve as a prototype for another object that will properly inherit from the given class object.
		*/
		,'createPrototype': function(_Class){
			//--create noop function and attach prototype so that we won't run constructor of class
			var _TempClass = function(){};
			_TempClass.prototype = _Class.prototype;
			//--return instance of noop class
			var _prototype = new _TempClass();
			return _prototype;
		}

		/*
		Function: mixIn
		Parameters:
			mixin(Array|Map): If an array of class definitions, run mixIn on each definition.  If a definition, mix this definition in to object/parent.
			object(Object): object to mix properties into
			parent(Function): function to mix statics into
		*/
		,'mixIn': function(_mixin, _object, _parent){
			var _i;
			var _key;
			var _mixinsLength;
			if(typeof _mixin == 'object'){
				//--if _mixin is an array, mix in all objects in array
				if(_mixin instanceof __Array){
					for(
						_i = 0, _mixinsLength = _mixin.length
						; _i < _mixinsLength
						; ++_i
					){
						this.mixIn(_mixin[_i], _object, _parent);
					}
				}else{
					//--mix in pre mixins
					if(typeof _mixin.preMixins == 'object'){
						this.mixIn(_mixin.preMixins, _object, _parent);
					}
					//--mix in mixins
					if(typeof _mixin.mixins == 'object'){
						this.mixIn(_mixin.mixins, _object, _parent);
					}
					//--mix in statics
					if(typeof _mixin.statics == 'object' && typeof _parent == 'function'){
						for(_key in _mixin.statics){
							if(_mixin.statics.hasOwnProperty(_key)){
								_parent[_key] = _mixin.statics[_key];
							}
						}
					}
					//--mix in properties
					if(typeof _mixin.properties == 'object'){
						for(_key in _mixin.properties){
							if(_mixin.properties.hasOwnProperty(_key)){
								_object[_key] = _mixin.properties[_key];
							}
						}
					}
					//--mix in postmixins
					if(typeof _mixin.postMixins == 'object'){
						this.mixIn(_mixin.postMixins, _object, _parent);
					}
				}
			}
		}

		/*
		Function: pluginize
		Converts any class/object into a function to be used by another class/object to give it an instance of the 'pluginized' class/object.  With the jQuery type, this function is added to the jQuery object, effectively making it a plugin.
		Parameters:
			options(map):
				class(Function): Class to instantiate for use as plugin.  Used if each containing object will have its own instance of the class, in place of the 'object' option
				mapToThis(String): string will be key used for passing containing object's 'this' to pluginized object's constructor
				object(Object): Object to use for plugin.  Used if one object instance is shared among all containing object instances, in place of the 'class' option
				type(String): name of the type of plugin to create.  default: method
					method: returns the pluganized method that can be added to any object/class
					jQuery: attaches the pluganized method to the jQuery object
		*/
		,'pluginize': function(_options){
			var _type = _options.type || 'method';
			_options = __mergeInto({
				'mapToThis': 'elements'
			}, _options);
			var _handler = function(){
				var _args = arguments; //-# enhancement for obfuscation to allow arguments to become a shorter variable, saving 128 bytes at time of commit
				if(typeof _handler.instance == 'undefined' || typeof _args[0] == 'undefined'){
					switch(typeof _options.mapToThis){
						case 'string':
							if(typeof _args[0] != 'object'){
								_args[0] = {};
							}
							_args[0][_options.mapToThis] = this;
						break;
						case 'number':
							_args[_options.mapToThis] = this;
						break;
						default:
							throw new Error('Pluginize does not support a "mapToThis" type of ' + typeof _options.mapToThis);
					}
					if(typeof _options.object == 'object'){
						_handler.instance = _options.object;
					}else{
						_handler.instance = new _options['class'](
							_args[0]
							,_args[1]
							,_args[2]
							,_args[3]
							,_args[4]
							,_args[5]
							,_args[6]
							,_args[7]
							,_args[8]
							,_args[9]
						);
					}
				}else if(typeof _args[0] == 'string'){
					//--shift off first argument as name of function
					var _propertyName = __Array.prototype.shift.call(_args);
					if(typeof _handler.instance[_propertyName] == 'function'){
						return _handler.instance[_propertyName].apply(_handler.instance, _args);
					}else{
						return _handler.instance[_propertyName];
					}
				}else{
					throw new Error('Must pass name of function to call for plugin.');
				}
			};
			switch(_type){
				case 'method':
					return _handler;
				//-# break;
				case 'jQuery':
					__jQuery.fn[_options.name] = _handler;
				break;
				default:
					throw new Error('Pluginize doesn\'t support type ' + _type);
				//-# break;
			}
		}
	});

	//--add to tmlib and export
	__tmlib.__('.core', {'classes': __classes});
	return __classes;
});
<|endoftext|>


<commit_before>
var request = require('../../')
  , express = require('express')
  , assert = require('assert')
  , app = express.createServer()
  , fs = require('fs');

function read(file) {
  return fs.readFileSync(file, 'utf8');
}

app.post('/echo', function(req, res){
  res.writeHead(200, req.headers);
  req.pipe(res);
});

app.listen(3005);

function boundary(ct) {
  return ct.match(/boundary="(.*)"/)[1];
}

describe('Request', function(){
  describe('#part()', function(){
    it('should return a new Part', function(){
      var req = request.post('http://localhost:3005');
      req.part().constructor.name.should.equal('Part');
      req.part().constructor.name.should.equal('Part');
      req.part().should.not.equal(req.part());
    })
  })

  it('should default res.files to {}', function(done){
    var req = request.post('http://localhost:3005/echo');

    req.end(function(res){
      res.files.should.eql({});
      res.body.should.eql({});
      done();
    });
  })

  describe('#field(name, value)', function(){
    it('should set a multipart field value', function(done){
      var req = request.post('http://localhost:3005/echo');

      req.field('user[name]', 'tobi');
      req.field('user[age]', '2');
      req.field('user[species]', 'ferret');

      req.end(function(res){
        res.body['user[name]'].should.equal('tobi');
        res.body['user[age]'].should.equal('2');
        res.body['user[species]'].should.equal('ferret');
        done();
      });
    })

    it('should work with file attachments', function(done){
      var req = request.post('http://localhost:3005/echo');

      req.field('name', 'Tobi');
      req.attach('test/node/fixtures/user.html', 'document');
      req.field('species', 'ferret');

      req.end(function(res){
        res.body.name.should.equal('Tobi');
        res.body.species.should.equal('ferret');

        var html = res.files.document;
        html.name.should.equal('document');
        html.type.should.equal('text/html');
        read(html.path).should.equal('
name
');
        done();
      })
    })
  })

  describe('#attach(file)', function(){
    it('should attach a file', function(done){
      var req = request.post('http://localhost:3005/echo');

      req.attach('test/node/fixtures/user.html');
      req.attach('test/node/fixtures/user.json');
      req.attach('test/node/fixtures/user.txt');

      req.end(function(res){
        var html = res.files['user.html'];
        var json = res.files['user.json'];
        var text = res.files['user.txt'];

        html.name.should.equal('user.html');
        html.type.should.equal('text/html');
        read(html.path).should.equal('
name
');

        json.name.should.equal('user.json');
        json.type.should.equal('application/json');
        read(json.path).should.equal('{"name":"tobi"}');

        text.name.should.equal('user.txt');
        text.type.should.equal('text/plain');
        read(text.path).should.equal('Tobi');

        done();
      })
    })

    describe('when a file does not exist', function(){
      it('should emit an error', function(done){
        var req = request.post('http://localhost:3005/echo');

        req.attach('foo');
        req.attach('bar');
        req.attach('baz');

        req.on('error', function(err){
          err.message.should.include('ENOENT, no such file');
          err.path.should.equal('foo');
          done();
        });

        req.end(function(res){
          assert(0, 'end() was called');
        });
      })
    })
  })

  describe('#attach(file, filename)', function(){
    it('should use the custom filename', function(done){
      request
      .post(':3005/echo')
      .attach('test/node/fixtures/user.html', 'document')
      .end(function(res){
        var html = res.files.document;
        html.name.should.equal('document');
        html.type.should.equal('text/html');
        read(html.path).should.equal('
name
');
        done();
      })
    })
  })
})

describe('Part', function(){
  describe('with a single part', function(){
    it('should construct a multipart request', function(done){
      var req = request.post('http://localhost:3005/echo');

      req
        .part()
        .set('Content-Disposition', 'attachment; name="image"; filename="image.png"')
        .set('Content-Type', 'image/png')
        .write('some image data');

      req.end(function(res){
        var ct = res.header['content-type'];
        ct.should.include('multipart/form-data; boundary=');
        res.body.should.eql({});
        res.files.image.name.should.equal('image.png');
        res.files.image.type.should.equal('image/png');
        done();
      });
    })
  })

  describe('with several parts', function(){
    it('should construct a multipart request', function(done){

      var req = request.post('http://localhost:3005/echo');

      req.part()
        .set('Content-Type', 'image/png')
        .set('Content-Disposition', 'attachment; filename="myimage.png"')
        .write('some image data');

      var part = req.part()
        .set('Content-Type', 'image/png')
        .set('Content-Disposition', 'attachment; filename="another.png"')

      part.write('random');
      part.write('thing');
      part.write('here');

      req.part()
        .set('Content-Disposition', 'form-data; name="name"')
        .set('Content-Type', 'text/plain')
        .write('tobi');

      req.end(function(res){
        res.body.name.should.equal('tobi');
        Object.keys(res.files).should.eql(['myimage.png', 'another.png']);
        done();
      });
    })
  })

  describe('with a Content-Type specified', function(){
    it('should append the boundary', function(done){
      var req = request
        .post('http://localhost:3005/echo')
        .type('multipart/form-data');

      req
        .part()
        .set('Content-Type', 'text/plain')
        .set('Content-Disposition', 'form-data; name="name"')
        .write('Tobi');

      req.end(function(res){
        res.header['content-type'].should.include('boundary=');
        res.body.name.should.equal('Tobi');
        done();
      });
    })
  })

  describe('#name(str)', function(){
    it('should set Content-Disposition to form-data and name param', function(done){
      var req = request
        .post('http://localhost:3005/echo');

      req
        .part()
        .name('user[name]')
        .write('Tobi');

      req.end(function(res){
        res.body['user[name]'].should.equal('Tobi');
        done();
      });
    })
  })

  describe('#filename(str)', function(){
    it('should set Content-Disposition and Content-Type', function(done){
      var req = request
        .post('http://localhost:3005/echo')
        .type('multipart/form-data');

      req
        .part()
        .filename('path/to/my.txt')
        .write('Tobi');

      req.end(function(res){
        var file = res.files['my.txt'];
        file.name.should.equal('my.txt');
        file.type.should.equal('text/plain');
        done();
      });
    })
  })
})
<commit_msg>Fixed a test that breaks because of a change in nodes ENOENT error message.<commit_after>
var request = require('../../')
  , express = require('express')
  , assert = require('assert')
  , app = express.createServer()
  , fs = require('fs');

function read(file) {
  return fs.readFileSync(file, 'utf8');
}

app.post('/echo', function(req, res){
  res.writeHead(200, req.headers);
  req.pipe(res);
});

app.listen(3005);

function boundary(ct) {
  return ct.match(/boundary="(.*)"/)[1];
}

describe('Request', function(){
  describe('#part()', function(){
    it('should return a new Part', function(){
      var req = request.post('http://localhost:3005');
      req.part().constructor.name.should.equal('Part');
      req.part().constructor.name.should.equal('Part');
      req.part().should.not.equal(req.part());
    })
  })

  it('should default res.files to {}', function(done){
    var req = request.post('http://localhost:3005/echo');

    req.end(function(res){
      res.files.should.eql({});
      res.body.should.eql({});
      done();
    });
  })

  describe('#field(name, value)', function(){
    it('should set a multipart field value', function(done){
      var req = request.post('http://localhost:3005/echo');

      req.field('user[name]', 'tobi');
      req.field('user[age]', '2');
      req.field('user[species]', 'ferret');

      req.end(function(res){
        res.body['user[name]'].should.equal('tobi');
        res.body['user[age]'].should.equal('2');
        res.body['user[species]'].should.equal('ferret');
        done();
      });
    })

    it('should work with file attachments', function(done){
      var req = request.post('http://localhost:3005/echo');

      req.field('name', 'Tobi');
      req.attach('test/node/fixtures/user.html', 'document');
      req.field('species', 'ferret');

      req.end(function(res){
        res.body.name.should.equal('Tobi');
        res.body.species.should.equal('ferret');

        var html = res.files.document;
        html.name.should.equal('document');
        html.type.should.equal('text/html');
        read(html.path).should.equal('
name
');
        done();
      })
    })
  })

  describe('#attach(file)', function(){
    it('should attach a file', function(done){
      var req = request.post('http://localhost:3005/echo');

      req.attach('test/node/fixtures/user.html');
      req.attach('test/node/fixtures/user.json');
      req.attach('test/node/fixtures/user.txt');

      req.end(function(res){
        var html = res.files['user.html'];
        var json = res.files['user.json'];
        var text = res.files['user.txt'];

        html.name.should.equal('user.html');
        html.type.should.equal('text/html');
        read(html.path).should.equal('
name
');

        json.name.should.equal('user.json');
        json.type.should.equal('application/json');
        read(json.path).should.equal('{"name":"tobi"}');

        text.name.should.equal('user.txt');
        text.type.should.equal('text/plain');
        read(text.path).should.equal('Tobi');

        done();
      })
    })

    describe('when a file does not exist', function(){
      it('should emit an error', function(done){
        var req = request.post('http://localhost:3005/echo');

        req.attach('foo');
        req.attach('bar');
        req.attach('baz');

        req.on('error', function(err){
          err.message.should.include('ENOENT');
          err.path.should.equal('foo');
          done();
        });

        req.end(function(res){
          assert(0, 'end() was called');
        });
      })
    })
  })

  describe('#attach(file, filename)', function(){
    it('should use the custom filename', function(done){
      request
      .post(':3005/echo')
      .attach('test/node/fixtures/user.html', 'document')
      .end(function(res){
        var html = res.files.document;
        html.name.should.equal('document');
        html.type.should.equal('text/html');
        read(html.path).should.equal('
name
');
        done();
      })
    })
  })
})

describe('Part', function(){
  describe('with a single part', function(){
    it('should construct a multipart request', function(done){
      var req = request.post('http://localhost:3005/echo');

      req
        .part()
        .set('Content-Disposition', 'attachment; name="image"; filename="image.png"')
        .set('Content-Type', 'image/png')
        .write('some image data');

      req.end(function(res){
        var ct = res.header['content-type'];
        ct.should.include('multipart/form-data; boundary=');
        res.body.should.eql({});
        res.files.image.name.should.equal('image.png');
        res.files.image.type.should.equal('image/png');
        done();
      });
    })
  })

  describe('with several parts', function(){
    it('should construct a multipart request', function(done){

      var req = request.post('http://localhost:3005/echo');

      req.part()
        .set('Content-Type', 'image/png')
        .set('Content-Disposition', 'attachment; filename="myimage.png"')
        .write('some image data');

      var part = req.part()
        .set('Content-Type', 'image/png')
        .set('Content-Disposition', 'attachment; filename="another.png"')

      part.write('random');
      part.write('thing');
      part.write('here');

      req.part()
        .set('Content-Disposition', 'form-data; name="name"')
        .set('Content-Type', 'text/plain')
        .write('tobi');

      req.end(function(res){
        res.body.name.should.equal('tobi');
        Object.keys(res.files).should.eql(['myimage.png', 'another.png']);
        done();
      });
    })
  })

  describe('with a Content-Type specified', function(){
    it('should append the boundary', function(done){
      var req = request
        .post('http://localhost:3005/echo')
        .type('multipart/form-data');

      req
        .part()
        .set('Content-Type', 'text/plain')
        .set('Content-Disposition', 'form-data; name="name"')
        .write('Tobi');

      req.end(function(res){
        res.header['content-type'].should.include('boundary=');
        res.body.name.should.equal('Tobi');
        done();
      });
    })
  })

  describe('#name(str)', function(){
    it('should set Content-Disposition to form-data and name param', function(done){
      var req = request
        .post('http://localhost:3005/echo');

      req
        .part()
        .name('user[name]')
        .write('Tobi');

      req.end(function(res){
        res.body['user[name]'].should.equal('Tobi');
        done();
      });
    })
  })

  describe('#filename(str)', function(){
    it('should set Content-Disposition and Content-Type', function(done){
      var req = request
        .post('http://localhost:3005/echo')
        .type('multipart/form-data');

      req
        .part()
        .filename('path/to/my.txt')
        .write('Tobi');

      req.end(function(res){
        var file = res.files['my.txt'];
        file.name.should.equal('my.txt');
        file.type.should.equal('text/plain');
        done();
      });
    })
  })
})
<|endoftext|>


<commit_before>const mm = require('plover-test-mate');
const co = require('co');

describe('plover-route/lib/plugin', () => {
  it('config routes', () => {
    const app = mm({
      applicationRoot: __dirname,
      routes: (r) => {
        r.get('/profile', 'users#show');
        r.use('/hello', ctx => {
          ctx.body = 'hello';
        });
      }
    });

    app.install('plover-web');
    app.install(require('../lib/plugin'));

    app.use(ctx => {
      if (ctx.route) {
        ctx.body = ctx.route;
      }
    });

    return co(function* () {
      yield app.get('/profile').expect({
        module: 'users',
        action: 'show',
        query: {}
      });

      yield app.get('/hello').expect('hello');
    });
  });

  it('routes not config', () => {
    const app = mm({
      applicationRoot: __dirname
    });

    app.install('plover-web');
    app.install(require('../lib/plugin'));

    (true).should.be.ok();
  });

  it('put with _method', () => {
    const app = mm({
      applicationRoot: __dirname,
      web: {
        csrf: {
          ignore: ['/*']
        }
      }
    });

    app.install('plover-web');
    app.install(require('../lib/plugin'));

    app.use(ctx => {
      ctx.body = ctx.method;
    });

    return co(function* () {
      yield app.agent.post('/update')
        .send({ _method: 'put' })
        .expect('PUT');
    });
  });
});
<commit_msg>refactor: refactor unit test<commit_after>const mm = require('plover-test-mate');
const co = require('co');

describe('plover-route/lib/plugin', () => {
  it('config routes', () => {
    const app = mm({
      applicationRoot: __dirname,
      routes: (r) => {
        r.get('/profile', 'users#show');
        r.use('/hello', ctx => {
          ctx.body = 'hello';
        });
      }
    });

    app.install('plover-web');
    app.install(require('../lib/plugin'));

    app.use(ctx => {
      if (ctx.route) {
        ctx.body = ctx.route;
      }
    });

    return co(function* () {
      yield app.get('/profile').expect({
        module: 'users',
        action: 'show',
        query: {}
      });

      yield app.get('/hello').expect('hello');
    });
  });

  it('routes not config', () => {
    const app = mm({
      applicationRoot: __dirname
    });

    app.install('plover-web');
    app.install(require('../lib/plugin'));

    (true).should.be.ok();
  });

  describe('http method', () => {
    const app = mm({
      applicationRoot: __dirname,
      web: {
        csrf: {
          ignore: ['/*']
        }
      }
    });

    app.install('plover-web');
    app.install(require('../lib/plugin'));

    app.use(ctx => {
      ctx.body = ctx.method;
    });

    it('put with _method', () => {
      return co(function* () {
        yield app.agent.post('/update')
          .send({ _method: 'put' })
          .expect('PUT');
      });
    });
  });
});
<|endoftext|>


<commit_before>define(function (require) {
  "use strict";

  var React = require('react'),
      modals = require('modals'),
      stores = require('stores');

  return React.createClass({
    renderBadgeDetail: function(e){
      e.preventDefault();
      modals.BadgeModals.showBadge(this.props.badge);
    },

    getInitialState: function(){
      var badgeText = this.props.badge.get('criteria')[0].description;
      return({
        text: badgeText,
        badgeSlug: this.props.badge.get('slug')
      });
    },

    render: function () {
      var badge = this.props.badge;

      return(

{badge.get('name')}

          {this.state.text}

      );
    }

  });

});<commit_msg>load badge image based on host in settings, not host badge image was generated on<commit_after>define(function (require) {
  "use strict";

  var React = require('react'),
      modals = require('modals'),
      globals = require('globals'),
      stores = require('stores');

  return React.createClass({
    renderBadgeDetail: function(e){
      e.preventDefault();
      modals.BadgeModals.showBadge(this.props.badge);
    },

    getInitialState: function(){
      var badgeText = this.props.badge.get('criteria')[0].description;
      return({
        text: badgeText,
        badgeSlug: this.props.badge.get('slug')
      });
    },

    render: function () {
      var badge = this.props.badge,
          // We get the badge image ID from the image URL, since the badge ID is not guaranteed to be the badge image ID
          imageIdIndex = badge.get('imageUrl').lastIndexOf('/');
      return(

{badge.get('name')}

          {this.state.text}

      );
    }

  });

});
<|endoftext|>