<commit_before>/*
 * Copyright (c) 2014, B3log
 *
 * 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.
 */

var menu = {
    init: function () {
        this.subMenu();
        this._initPreference();
        this._initAbout();
        this._initShare();

        // 点击子菜单后消失
        $(".frame li").click(function () {
            $(this).closest(".frame").hide();
            $(".menu > ul > li > a, .menu > ul> li > span").removeClass("selected");
        });

    },
    _initShare: function () {
        $(".menu .ico-share").hover(function () {
            $(".menu .share-panel").show();
        });

        $(".share-panel .font-ico").click(function () {
            var key = $(this).attr('class').split('-')[2];
            var title = encodeURIComponent($('title').text() + '. \n' + $('meta[name=description]').attr('content')),
                    url = "https://wide.b3log.org",
                    pic = 'https://wide.b3log.org/static/images/wide-logo.png';
            var urls = {};
            urls.email = "mailto:?subject=" + $('title').text()
                    + "&body=" + $('meta[name=description]').attr('content') + ' ' + url;
            urls.twitter = "https://twitter.com/intent/tweet?status="
                    + $('meta[name=description]').attr('content') + " " + url;
            urls.facebook = "https://www.facebook.com/sharer/sharer.php?u=" + url;
            urls.googleplus = "https://plus.google.com/share?url=" + url;
            urls.weibo = "http://v.t.sina.com.cn/share/share.php?title=" +
                    title + "&url=" + url + "&pic=" + pic;
            urls.tencent = "http://share.v.t.qq.com/index.php?c=share&a=index&title=" + title +
                    "&url=" + url + "&pic=" + pic;
            window.open(urls[key], "_blank", "top=100,left=200,width=648,height=618");
        });
    },
    _initAbout: function () {
        $("#dialogAbout").load(config.context + '/about', function () {
            $("#dialogAbout").dialog({
                "modal": true,
                "height": 460,
                "width": 800,
                "title": config.label.about,
                "hideFooter": true,
                "afterOpen": function () {
                    $.ajax({
                        url: "https://rhythm.b3log.org/version/wide/latest",
                        type: "GET",
                        dataType: "jsonp",
                        jsonp: "callback",
                        success: function (data, textStatus) {
                            if ($("#dialogAbout .version").text() === data.wideVersion) {
                                $(".upgrade").text(config.label.uptodate);
                            } else {
                                $(".upgrade").html(config.label.new_version_available + config.label.colon
                                        + "" + data.wideVersion + "");
                            }
                        }
                    });
                }
            });
        });
    },
    disabled: function (list) {
        for (var i = 0, max = list.length; i < max; i++) {
            $(".menu li." + list[i]).addClass("disabled");
        }
    },
    undisabled: function (list) {
        for (var i = 0, max = list.length; i < max; i++) {
            $(".menu li." + list[i]).removeClass("disabled");
        }
    },
    // 焦点不在菜单上时需点击展开子菜单，否则为鼠标移动展开
    subMenu: function () {
        $(".menu > ul > li > a, .menu > ul> li > span").click(function () {
            var $it = $(this);
            $it.next().show();
            $(".menu > ul > li > a, .menu > ul> li > span").removeClass("selected");
            $(this).addClass("selected");

            $(".menu > ul > li > a, .menu > ul> li > span").unbind();

            $(".menu > ul > li > a, .menu > ul> li > span").mouseover(function () {
                $(".frame").hide();
                $(this).next().show();
                $(".menu > ul > li > a, .menu > ul> li > span").removeClass("selected");
                $(this).addClass("selected");
            });
        });
    },
    openPreference: function () {
        $("#dialogPreference").dialog("open");
    },
    saveAllFiles: function () {
        if ($(".menu li.save-all").hasClass("disabled")) {
            return false;
        }
        for (var i = 0, ii = editors.data.length; i < ii; i++) {
            var path = tree.fileTree.getNodeByTId(editors.data[i].id).path;
            var editor = editors.data[i].editor;

            if ("text/x-go" === editor.getOption("mode")) {
                wide.fmt(path, editor);
            } else {
                wide._save(path, editor);
            }
        }
    },
    closeAllFiles: function () {
        if ($(".menu li.close-all").hasClass("disabled")) {
            return false;
        }

        // 设置全部关闭标识
        var removeData = [];
        $(".edit-panel .tabs > div").each(function (i) {
            if (i !== 0) {
                removeData.push($(this).data("index"));
            }
        });
        $("#dialogCloseEditor").data("removeData", removeData);
        // 开始关闭
        $(".edit-panel .tabs .ico-close:eq(0)").click();
    },
    exit: function () {
        var request = newWideRequest();

        $.ajax({
            type: 'POST',
            url: config.context + '/logout',
            data: JSON.stringify(request),
            dataType: "json",
            success: function (data) {
                if (data.succ) {
                    window.location.href = "/login";
                }
            }
        });
    },
    openAbout: function () {
        $("#dialogAbout").dialog("open");
    },
    goget: function () {
        menu.saveAllFiles();

        var currentPath = editors.getCurrentPath();
        if (!currentPath) {
            return false;
        }

        if ($(".menu li.go-get").hasClass("disabled")) {
            return false;
        }

        var request = newWideRequest();
        request.file = currentPath;

        $.ajax({
            type: 'POST',
            url: config.context + '/go/get',
            data: JSON.stringify(request),
            dataType: "json",
            beforeSend: function (data) {
                bottomGroup.resetOutput();
            },
            success: function (data) {
            }
        });
    },
    goinstall: function () {
        menu.saveAllFiles();

        var currentPath = editors.getCurrentPath();
        if (!currentPath) {
            return false;
        }

        if ($(".menu li.go-install").hasClass("disabled")) {
            return false;
        }

        var request = newWideRequest();
        request.file = currentPath;

        $.ajax({
            type: 'POST',
            url: config.context + '/go/install',
            data: JSON.stringify(request),
            dataType: "json",
            beforeSend: function (data) {
                bottomGroup.resetOutput();
            },
            success: function (data) {
            }
        });
    },
    // 测试.
    test: function () {
        menu.saveAllFiles();

        var currentPath = editors.getCurrentPath();
        if (!currentPath) {
            return false;
        }

        if ($(".menu li.test").hasClass("disabled")) {
            return false;
        }

        var request = newWideRequest();
        request.file = currentPath;

        $.ajax({
            type: 'POST',
            url: config.context + '/go/test',
            data: JSON.stringify(request),
            dataType: "json",
            beforeSend: function (data) {
                bottomGroup.resetOutput();
            },
            success: function (data) {
            }
        });
    },
    // Build & Run.
    run: function () {
        menu.saveAllFiles();

        var currentPath = editors.getCurrentPath();
        if (!currentPath) {
            return false;
        }

        if ($(".menu li.run").hasClass("disabled")) {
            return false;
        }

        if ($("#buildRun").hasClass("ico-stop")) {
            wide.stop();
            return false;
        }

        var request = newWideRequest();
        request.file = currentPath;
        request.code = wide.curEditor.getValue();
        request.nextCmd = "run";

        $.ajax({
            type: 'POST',
            url: config.context + '/build',
            data: JSON.stringify(request),
            dataType: "json",
            beforeSend: function (data) {
                bottomGroup.resetOutput();
            },
            success: function (data) {
                $("#buildRun").addClass("ico-stop")
                        .removeClass("ico-buildrun").attr("title", config.label.stop);
            }
        });
    },
    // Build.
    build: function () {
        menu.saveAllFiles();

        var currentPath = editors.getCurrentPath();
        if (!currentPath) {
            return false;
        }

        if ($(".menu li.build").hasClass("disabled")) {
            return false;
        }

        var request = newWideRequest();
        request.file = currentPath;
        request.code = wide.curEditor.getValue();
        request.nextCmd = ""; // 只构建，无下一步操作

        $.ajax({
            type: 'POST',
            url: config.context + '/build',
            data: JSON.stringify(request),
            dataType: "json",
            beforeSend: function (data) {
                bottomGroup.resetOutput();
            },
            success: function (data) {
            }
        });
    },
    _initPreference: function () {
        $("#dialogPreference").load(config.context + '/preference', function () {
            $("#dialogPreference input").keyup(function () {
                var isChange = false,
                        emptys = [],
                        emptysTip = '';
                $("#dialogPreference input").each(function () {
                    var $it = $(this);
                    // data-value 如为数字，则不会和 value 一样转换为 String，再次不使用全等
                    if ($it.val() != $it.data("value")) {
                        isChange = true;
                    }

                    if ($.trim($it.val()) === '') {
                        emptys.push($it);
                    }
                });

                var $okBtn = $("#dialogPreference").closest(".dialog-main").find(".dialog-footer > button:eq(0)");
                if (isChange) {
                    $okBtn.prop("disabled", false);
                } else {
                    $okBtn.prop("disabled", true);
                }

                if (emptys.length === 0) {
                    $("#dialogPreference").find(".tip").html("");
                    $okBtn.prop("disabled", false);
                } else {
                    for (var i = 0, max = emptys.length; i < max; i++) {
                        var tabIndex = emptys[i].closest('div').data("index"),
                                text = $.trim(emptys[i].parent().text());
                        emptysTip += '[' + $("#dialogPreference .tabs > div[data-index=" + tabIndex + "]").text()
                                + '] -> [' + text.substr(0, text.length - 1)
                                + ']: ' + config.label.no_empty + "
";
                    }
                    $("#dialogPreference").find(".tip").html(emptysTip);
                    $okBtn.prop("disabled", true);
                }
            });

            $("#dialogPreference select").on("change", function () {
                var isChange = false;
                $("#dialogPreference select").each(function () {
                    if ($(this).val() !== $(this).data("value")) {
                        isChange = true;
                    }
                });

                var $okBtn = $("#dialogPreference").closest(".dialog-main").find(".dialog-footer > button:eq(0)");
                if (isChange) {
                    $okBtn.prop("disabled", false);
                } else {
                    $okBtn.prop("disabled", true);
                }
            });

            $("#dialogPreference").dialog({
                "modal": true,
                "height": 280,
                "width": 800,
                "title": config.label.perference,
                "okText": config.label.apply,
                "cancelText": config.label.cancel,
                "afterOpen": function () {
                    var $okBtn = $("#dialogPreference").closest(".dialog-main").find(".dialog-footer > button:eq(0)");
                    $okBtn.prop("disabled", true);
                },
                "ok": function () {
                    var request = newWideRequest(),
                            $dialogPreference = $("#dialogPreference"),
                            $fontFamily = $dialogPreference.find("input[name=fontFamily]"),
                            $fontSize = $dialogPreference.find("input[name=fontSize]"),
                            $goFmt = $dialogPreference.find("select[name=goFmt]"),
                            $workspace = $dialogPreference.find("input[name=workspace]"),
                            $password = $dialogPreference.find("input[name=password]"),
                            $email = $dialogPreference.find("input[name=email]"),
                            $locale = $dialogPreference.find("select[name=locale]"),
                            $theme = $dialogPreference.find("select[name=theme]"),
                            $editorFontFamily = $dialogPreference.find("input[name=editorFontFamily]"),
                            $editorFontSize = $dialogPreference.find("input[name=editorFontSize]"),
                            $editorLineHeight = $dialogPreference.find("input[name=editorLineHeight]"),
                            $editorTheme = $dialogPreference.find("select[name=editorTheme]"),
                            $editorTabSize = $dialogPreference.find("input[name=editorTabSize]");

                    $.extend(request, {
                        "fontFamily": $fontFamily.val(),
                        "fontSize": $fontSize.val(),
                        "goFmt": $goFmt.val(),
                        "workspace": $workspace.val(),
                        "password": $password.val(),
                        "email": $email.val(),
                        "locale": $locale.val(),
                        "theme": $theme.val(),
                        "editorFontFamily": $editorFontFamily.val(),
                        "editorFontSize": $editorFontSize.val(),
                        "editorLineHeight": $editorLineHeight.val(),
                        "editorTheme": $editorTheme.val(),
                        "editorTabSize": $editorTabSize.val()
                    });

                    $.ajax({
                        type: 'POST',
                        url: config.context + '/preference',
                        data: JSON.stringify(request),
                        success: function (data, textStatus, jqXHR) {
                            if (!data.succ) {
                                return false;
                            }

                            $fontFamily.data("value", $fontFamily.val());
                            $fontSize.data("value", $fontSize.val());
                            $goFmt.data("value", $goFmt.val());
                            $workspace.data("value", $workspace.val());
                            $password.data("value", $password.val());
                            $email.data("value", $email.val());
                            $locale.data("value", $locale.val());
                            $theme.data("value", $theme.val());
                            $editorFontFamily.data("value", $editorFontFamily.val());
                            $editorFontSize.data("value", $editorFontSize.val());
                            $editorLineHeight.data("value", $editorLineHeight.val());
                            $editorTheme.data("value", $editorTheme.val());
                            $editorTabSize.data("value", $editorTabSize.val());

                            var $okBtn = $("#dialogPreference").closest(".dialog-main").find(".dialog-footer > button:eq(0)");
                            $okBtn.prop("disabled", true);

                            $("#themesLink").attr("href", config.staticServer + '/static/css/themes/' + $theme.val() + '.css');

                            config.editorTheme = $editorTheme.val();
                            for (var i = 0, ii = editors.data.length; i < ii; i++) {
                                editors.data[i].editor.setOption("theme", $editorTheme.val());
                            }
                        }
                    });
                }
            });

            new Tabs({
                id: ".preference"
            });
        });
    }
};<commit_msg>share<commit_after>/*
 * Copyright (c) 2014, B3log
 *
 * 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.
 */

var menu = {
    init: function () {
        this.subMenu();
        this._initPreference();
        this._initAbout();
        this._initShare();

        // 点击子菜单后消失
        $(".frame li").click(function () {
            $(this).closest(".frame").hide();
            $(".menu > ul > li > a, .menu > ul> li > span").removeClass("selected");
        });

    },
    _initShare: function () {
        $(".menu .ico-share").hover(function () {
            $(".menu .share-panel").show();
        });

        $(".share-panel .font-ico").click(function () {
            var key = $(this).attr('class').split('-')[2];
            var title = encodeURIComponent($('title').text() + '. \n' + $('meta[name=description]').attr('content')),
                    url = "https://wide.b3log.org",
                    pic = 'https://wide.b3log.org/static/images/wide-logo.png';
            var urls = {};
            urls.email = "mailto:?subject=" + $('title').text()
                    + "&body=" + $('meta[name=description]').attr('content') + ' ' + url;
            urls.twitter = "https://twitter.com/intent/tweet?status="
                    + $('meta[name=description]').attr('content') + " " + url + " #golang";
            urls.facebook = "https://www.facebook.com/sharer/sharer.php?u=" + url;
            urls.googleplus = "https://plus.google.com/share?url=" + url + " +golang";
            urls.weibo = "http://v.t.sina.com.cn/share/share.php?title=" +
                    title + "&url=" + url + "&pic=" + pic;
            urls.tencent = "http://share.v.t.qq.com/index.php?c=share&a=index&title=" + title +
                    "&url=" + url + "&pic=" + pic;
            window.open(urls[key], "_blank", "top=100,left=200,width=648,height=618");
        });
    },
    _initAbout: function () {
        $("#dialogAbout").load(config.context + '/about', function () {
            $("#dialogAbout").dialog({
                "modal": true,
                "height": 460,
                "width": 800,
                "title": config.label.about,
                "hideFooter": true,
                "afterOpen": function () {
                    $.ajax({
                        url: "https://rhythm.b3log.org/version/wide/latest",
                        type: "GET",
                        dataType: "jsonp",
                        jsonp: "callback",
                        success: function (data, textStatus) {
                            if ($("#dialogAbout .version").text() === data.wideVersion) {
                                $(".upgrade").text(config.label.uptodate);
                            } else {
                                $(".upgrade").html(config.label.new_version_available + config.label.colon
                                        + "" + data.wideVersion + "");
                            }
                        }
                    });
                }
            });
        });
    },
    disabled: function (list) {
        for (var i = 0, max = list.length; i < max; i++) {
            $(".menu li." + list[i]).addClass("disabled");
        }
    },
    undisabled: function (list) {
        for (var i = 0, max = list.length; i < max; i++) {
            $(".menu li." + list[i]).removeClass("disabled");
        }
    },
    // 焦点不在菜单上时需点击展开子菜单，否则为鼠标移动展开
    subMenu: function () {
        $(".menu > ul > li > a, .menu > ul> li > span").click(function () {
            var $it = $(this);
            $it.next().show();
            $(".menu > ul > li > a, .menu > ul> li > span").removeClass("selected");
            $(this).addClass("selected");

            $(".menu > ul > li > a, .menu > ul> li > span").unbind();

            $(".menu > ul > li > a, .menu > ul> li > span").mouseover(function () {
                $(".frame").hide();
                $(this).next().show();
                $(".menu > ul > li > a, .menu > ul> li > span").removeClass("selected");
                $(this).addClass("selected");
            });
        });
    },
    openPreference: function () {
        $("#dialogPreference").dialog("open");
    },
    saveAllFiles: function () {
        if ($(".menu li.save-all").hasClass("disabled")) {
            return false;
        }
        for (var i = 0, ii = editors.data.length; i < ii; i++) {
            var path = tree.fileTree.getNodeByTId(editors.data[i].id).path;
            var editor = editors.data[i].editor;

            if ("text/x-go" === editor.getOption("mode")) {
                wide.fmt(path, editor);
            } else {
                wide._save(path, editor);
            }
        }
    },
    closeAllFiles: function () {
        if ($(".menu li.close-all").hasClass("disabled")) {
            return false;
        }

        // 设置全部关闭标识
        var removeData = [];
        $(".edit-panel .tabs > div").each(function (i) {
            if (i !== 0) {
                removeData.push($(this).data("index"));
            }
        });
        $("#dialogCloseEditor").data("removeData", removeData);
        // 开始关闭
        $(".edit-panel .tabs .ico-close:eq(0)").click();
    },
    exit: function () {
        var request = newWideRequest();

        $.ajax({
            type: 'POST',
            url: config.context + '/logout',
            data: JSON.stringify(request),
            dataType: "json",
            success: function (data) {
                if (data.succ) {
                    window.location.href = "/login";
                }
            }
        });
    },
    openAbout: function () {
        $("#dialogAbout").dialog("open");
    },
    goget: function () {
        menu.saveAllFiles();

        var currentPath = editors.getCurrentPath();
        if (!currentPath) {
            return false;
        }

        if ($(".menu li.go-get").hasClass("disabled")) {
            return false;
        }

        var request = newWideRequest();
        request.file = currentPath;

        $.ajax({
            type: 'POST',
            url: config.context + '/go/get',
            data: JSON.stringify(request),
            dataType: "json",
            beforeSend: function (data) {
                bottomGroup.resetOutput();
            },
            success: function (data) {
            }
        });
    },
    goinstall: function () {
        menu.saveAllFiles();

        var currentPath = editors.getCurrentPath();
        if (!currentPath) {
            return false;
        }

        if ($(".menu li.go-install").hasClass("disabled")) {
            return false;
        }

        var request = newWideRequest();
        request.file = currentPath;

        $.ajax({
            type: 'POST',
            url: config.context + '/go/install',
            data: JSON.stringify(request),
            dataType: "json",
            beforeSend: function (data) {
                bottomGroup.resetOutput();
            },
            success: function (data) {
            }
        });
    },
    // 测试.
    test: function () {
        menu.saveAllFiles();

        var currentPath = editors.getCurrentPath();
        if (!currentPath) {
            return false;
        }

        if ($(".menu li.test").hasClass("disabled")) {
            return false;
        }

        var request = newWideRequest();
        request.file = currentPath;

        $.ajax({
            type: 'POST',
            url: config.context + '/go/test',
            data: JSON.stringify(request),
            dataType: "json",
            beforeSend: function (data) {
                bottomGroup.resetOutput();
            },
            success: function (data) {
            }
        });
    },
    // Build & Run.
    run: function () {
        menu.saveAllFiles();

        var currentPath = editors.getCurrentPath();
        if (!currentPath) {
            return false;
        }

        if ($(".menu li.run").hasClass("disabled")) {
            return false;
        }

        if ($("#buildRun").hasClass("ico-stop")) {
            wide.stop();
            return false;
        }

        var request = newWideRequest();
        request.file = currentPath;
        request.code = wide.curEditor.getValue();
        request.nextCmd = "run";

        $.ajax({
            type: 'POST',
            url: config.context + '/build',
            data: JSON.stringify(request),
            dataType: "json",
            beforeSend: function (data) {
                bottomGroup.resetOutput();
            },
            success: function (data) {
                $("#buildRun").addClass("ico-stop")
                        .removeClass("ico-buildrun").attr("title", config.label.stop);
            }
        });
    },
    // Build.
    build: function () {
        menu.saveAllFiles();

        var currentPath = editors.getCurrentPath();
        if (!currentPath) {
            return false;
        }

        if ($(".menu li.build").hasClass("disabled")) {
            return false;
        }

        var request = newWideRequest();
        request.file = currentPath;
        request.code = wide.curEditor.getValue();
        request.nextCmd = ""; // 只构建，无下一步操作

        $.ajax({
            type: 'POST',
            url: config.context + '/build',
            data: JSON.stringify(request),
            dataType: "json",
            beforeSend: function (data) {
                bottomGroup.resetOutput();
            },
            success: function (data) {
            }
        });
    },
    _initPreference: function () {
        $("#dialogPreference").load(config.context + '/preference', function () {
            $("#dialogPreference input").keyup(function () {
                var isChange = false,
                        emptys = [],
                        emptysTip = '';
                $("#dialogPreference input").each(function () {
                    var $it = $(this);
                    // data-value 如为数字，则不会和 value 一样转换为 String，再次不使用全等
                    if ($it.val() != $it.data("value")) {
                        isChange = true;
                    }

                    if ($.trim($it.val()) === '') {
                        emptys.push($it);
                    }
                });

                var $okBtn = $("#dialogPreference").closest(".dialog-main").find(".dialog-footer > button:eq(0)");
                if (isChange) {
                    $okBtn.prop("disabled", false);
                } else {
                    $okBtn.prop("disabled", true);
                }

                if (emptys.length === 0) {
                    $("#dialogPreference").find(".tip").html("");
                    $okBtn.prop("disabled", false);
                } else {
                    for (var i = 0, max = emptys.length; i < max; i++) {
                        var tabIndex = emptys[i].closest('div').data("index"),
                                text = $.trim(emptys[i].parent().text());
                        emptysTip += '[' + $("#dialogPreference .tabs > div[data-index=" + tabIndex + "]").text()
                                + '] -> [' + text.substr(0, text.length - 1)
                                + ']: ' + config.label.no_empty + "
";
                    }
                    $("#dialogPreference").find(".tip").html(emptysTip);
                    $okBtn.prop("disabled", true);
                }
            });

            $("#dialogPreference select").on("change", function () {
                var isChange = false;
                $("#dialogPreference select").each(function () {
                    if ($(this).val() !== $(this).data("value")) {
                        isChange = true;
                    }
                });

                var $okBtn = $("#dialogPreference").closest(".dialog-main").find(".dialog-footer > button:eq(0)");
                if (isChange) {
                    $okBtn.prop("disabled", false);
                } else {
                    $okBtn.prop("disabled", true);
                }
            });

            $("#dialogPreference").dialog({
                "modal": true,
                "height": 280,
                "width": 800,
                "title": config.label.perference,
                "okText": config.label.apply,
                "cancelText": config.label.cancel,
                "afterOpen": function () {
                    var $okBtn = $("#dialogPreference").closest(".dialog-main").find(".dialog-footer > button:eq(0)");
                    $okBtn.prop("disabled", true);
                },
                "ok": function () {
                    var request = newWideRequest(),
                            $dialogPreference = $("#dialogPreference"),
                            $fontFamily = $dialogPreference.find("input[name=fontFamily]"),
                            $fontSize = $dialogPreference.find("input[name=fontSize]"),
                            $goFmt = $dialogPreference.find("select[name=goFmt]"),
                            $workspace = $dialogPreference.find("input[name=workspace]"),
                            $password = $dialogPreference.find("input[name=password]"),
                            $email = $dialogPreference.find("input[name=email]"),
                            $locale = $dialogPreference.find("select[name=locale]"),
                            $theme = $dialogPreference.find("select[name=theme]"),
                            $editorFontFamily = $dialogPreference.find("input[name=editorFontFamily]"),
                            $editorFontSize = $dialogPreference.find("input[name=editorFontSize]"),
                            $editorLineHeight = $dialogPreference.find("input[name=editorLineHeight]"),
                            $editorTheme = $dialogPreference.find("select[name=editorTheme]"),
                            $editorTabSize = $dialogPreference.find("input[name=editorTabSize]");

                    $.extend(request, {
                        "fontFamily": $fontFamily.val(),
                        "fontSize": $fontSize.val(),
                        "goFmt": $goFmt.val(),
                        "workspace": $workspace.val(),
                        "password": $password.val(),
                        "email": $email.val(),
                        "locale": $locale.val(),
                        "theme": $theme.val(),
                        "editorFontFamily": $editorFontFamily.val(),
                        "editorFontSize": $editorFontSize.val(),
                        "editorLineHeight": $editorLineHeight.val(),
                        "editorTheme": $editorTheme.val(),
                        "editorTabSize": $editorTabSize.val()
                    });

                    $.ajax({
                        type: 'POST',
                        url: config.context + '/preference',
                        data: JSON.stringify(request),
                        success: function (data, textStatus, jqXHR) {
                            if (!data.succ) {
                                return false;
                            }

                            $fontFamily.data("value", $fontFamily.val());
                            $fontSize.data("value", $fontSize.val());
                            $goFmt.data("value", $goFmt.val());
                            $workspace.data("value", $workspace.val());
                            $password.data("value", $password.val());
                            $email.data("value", $email.val());
                            $locale.data("value", $locale.val());
                            $theme.data("value", $theme.val());
                            $editorFontFamily.data("value", $editorFontFamily.val());
                            $editorFontSize.data("value", $editorFontSize.val());
                            $editorLineHeight.data("value", $editorLineHeight.val());
                            $editorTheme.data("value", $editorTheme.val());
                            $editorTabSize.data("value", $editorTabSize.val());

                            var $okBtn = $("#dialogPreference").closest(".dialog-main").find(".dialog-footer > button:eq(0)");
                            $okBtn.prop("disabled", true);

                            $("#themesLink").attr("href", config.staticServer + '/static/css/themes/' + $theme.val() + '.css');

                            config.editorTheme = $editorTheme.val();
                            for (var i = 0, ii = editors.data.length; i < ii; i++) {
                                editors.data[i].editor.setOption("theme", $editorTheme.val());
                            }
                        }
                    });
                }
            });

            new Tabs({
                id: ".preference"
            });
        });
    }
};<|endoftext|>


<commit_before>import React from 'react'
import { api } from '../../data'
import {
  Aside,
  FormWrapper,
  Fieldset,
  FormAndTableRow,
  Field,
  Submit,
  Form,
  TableOfContents
} from '../components/Forms'
import LeaderInviteForm from '../components/LeaderInviteForm'
import Button from '../components/Button'
import { Container, Flex, Box } from '@hackclub/design-system'
import { withFormik } from 'formik'

const InnerForm = props => {
  const {
    values,
    errors,
    touched,
    handleChange,
    handleBlur,
    handleSubmit,
    isSubmitting,
    id,
    authToken,
    params
  } = props
  const markSubmitted = e => {
    e.preventDefault()
    if (values.submitted_at) {
      alert(
        'Application already submitted. If you want to make further edits, just "Save Draft"'
      )
    } else {
      fetch(`${api}/v1/new_club_applications/${id}/submit`, {
        method: 'POST',
        headers: {
          Authorization: `Bearer ${authToken}`
        }
      })
        .then(res => {
          if (res.ok) {
            alert(
              "Application submitted! You'll get a confirmation email shortly."
            )
          } else {
            throw res
          }
        })
        .catch(e => {
          console.error(e)
          if (e.status === 422) {
            alert(
              'Can’t submit. Finish filling out the application and make sure all co-leads have filled out their profiles.'
            )
          } else {
            alert('Something went terribly wrong')
          }
        })
    }
  }
  return (
    <FormWrapper>
      <Form onSubmit={handleSubmit}>
        <Fieldset section="school">
          <Field
            name="high_school_name"
            label="Name of high school"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.high_school_name}
            error={touched.high_school_name && errors.high_school_name}
            isRequired
          />
          <Field
            name="high_school_url"
            label="Link to your high school's website, if any"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.high_school_url}
            error={touched.high_school_url && errors.high_school_url}
          />
          <Field
            name="high_school_type"
            label="Type of school"
            type="select"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.high_school_type || 'select'}
            error={touched.high_school_type && errors.high_school_type}
            isRequired
          >
            <option disabled value="select">
              Select One
            </option>
            <option value="public_school">Public school</option>
            <option value="private_school">Private school</option>
            <option value="charter_school">Charter school</option>
          </Field>
          <Field
            name="high_school_address"
            label="High school's full address (include city, state/province, country)"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.high_school_address}
            error={touched.high_school_address && errors.high_school_address}
            type="textarea"
            isRequired
          />
        </Fieldset>
        <Fieldset section="leaders">
          <LeaderInviteForm params={values} id={id} authToken={authToken} />
          <Field
            name="point_of_contact_id"
            label="Point of contact"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.point_of_contact_id || 'select'}
            error={touched.point_of_contact_id && errors.point_of_contact_id}
            type="select"
            isRequired
          >
            <option disabled value="select">
              Select One
            </option>
            {values.applicant_profiles.map((profile, index) => (
              <option value={profile.applicant.id} key={index}>
                {profile.applicant.email}
              </option>
            ))}
          </Field>
          <Field
            name="leaders_video_url"
            label="Please enter the URL of a 1 minute unlisted (not private) YouTube video introducing the leaders"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.leaders_video_url}
            error={touched.leaders_video_url && errors.leaders_video_url}
            isRequired
          />
          <Field
            name="leaders_interesting_project"
            label="Please tell us about an interesting project, preferably outside of class, that two or more of you created together. Include URLs if possible."
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.leaders_interesting_project}
            error={
              touched.leaders_interesting_project &&
              errors.leaders_interesting_project
            }
            type="textarea"
            isRequired
          />
          <Field
            name="leaders_team_origin_story"
            label="How long have you known your other club leaders and how did you meet?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.leaders_team_origin_story}
            error={
              touched.leaders_team_origin_story &&
              errors.leaders_team_origin_story
            }
            type="textarea"
            isRequired
          />
        </Fieldset>
        <Fieldset section="progress">
          <Field
            name="progress_general"
            label="How far along are you in starting your club?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.progress_general}
            error={touched.progress_general && errors.progress_general}
            type="textarea"
            isRequired
          />
          <Field
            name="progress_student_interest"
            label="Have you already polled for interest at your school? Are students interested? If you've already had meetings, how many people came?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.progress_student_interest}
            error={
              touched.progress_student_interest &&
              errors.progress_student_interest
            }
            type="textarea"
            isRequired
          />
          <Field
            name="progress_meeting_yet"
            label="Have you begun meeting yet? We encourage you to not begin meeting until we accept you."
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.progress_meeting_yet}
            error={touched.progress_meeting_yet && errors.progress_meeting_yet}
            type="textarea"
            isRequired
          />
        </Fieldset>
        <Fieldset section="idea">
          <Field
            name="idea_why"
            label="Why did you decide to start a Hack Club? Have you ran anything like a Hack Club before? Why do you think the club is going to work?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.idea_why}
            error={touched.idea_why && errors.idea_why}
            type="textarea"
            isRequired
          />
          <Field
            name="idea_other_coding_clubs"
            label="Has your school had coding clubs before? What's going to be new about your Hack Club?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.idea_other_coding_clubs}
            error={
              touched.idea_other_coding_clubs && errors.idea_other_coding_clubs
            }
            type="textarea"
            isRequired
          />
          <Field
            name="idea_other_general_clubs"
            label="What other clubs exist at your school? Why will you be just as successful, if not more, than them?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.idea_other_general_clubs}
            error={
              touched.idea_other_general_clubs &&
              errors.idea_other_general_clubs
            }
            type="textarea"
            isRequired
          />
        </Fieldset>
        <Fieldset section="formation">
          <Field
            name="formation_registered"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.formation_registered}
            error={touched.formation_registered && errors.formation_registered}
            label="Have you already registered your club with your school?"
            isRequired
          />
          <Field
            name="formation_misc"
            label="Please provide any other relevant information about the structure or formation of the club."
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.formation_misc}
            error={touched.formation_misc && errors.formation_misc}
            type="textarea"
          />
        </Fieldset>
        <Fieldset section="other">
          <Field
            name="other_surprising_or_amusing_discovery"
            label="What is something surprising or amusing you discovered?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.other_surprising_or_amusing_discovery}
            error={
              touched.other_surprising_or_amusing_discovery &&
              errors.other_surprising_or_amusing_discovery
            }
            type="textarea"
            isRequired
          />
        </Fieldset>
        <Fieldset section="curious">
          <Field
            name="curious_what_convinced"
            label="What convinced you to start a Hack Club?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.curious_what_convinced}
            error={
              touched.curious_what_convinced && errors.curious_what_convinced
            }
            type="textarea"
          />
          <Field
            name="curious_how_did_hear"
            label="How did you hear about Hack Club?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.curious_how_did_hear}
            error={touched.curious_how_did_hear && errors.curious_how_did_hear}
            type="textarea"
          />
        </Fieldset>
        <Container maxWidth={24}>
          <Submit
            value="Save Draft"
            disabled={isSubmitting}
            w={1}
            my={2}
            bg="white"
            color="primary"
          />
          <Submit
            value="Submit Application"
            disabled={isSubmitting}
            onClick={markSubmitted}
            w={1}
            my={2}
          />
        </Container>
      </Form>
    </FormWrapper>
  )
}

const ClubApplicationForm = withFormik({
  mapPropsToValues: props => props.params,
  enableReinitialize: true,
  handleSubmit: (data, { setSubmitting, props }) => {
    fetch(`${api}/v1/new_club_applications/${props.id}`, {
      method: 'PATCH',
      headers: {
        Authorization: `Bearer ${props.authToken}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(data)
    })
      .then(res => {
        if (res.ok) {
          return res.json()
        } else {
          throw res
        }
      })
      .then(json => {
        alert('Saved!')
        setSubmitting(false)
      })
      .catch(e => {
        console.error(e)
        alert(e)
        setSubmitting(false)
      })
  },
  displayName: 'ClubApplicationForm'
})(InnerForm)
export default ClubApplicationForm
<commit_msg>Use rich apostrophe character<commit_after>import React from 'react'
import { api } from '../../data'
import {
  Aside,
  FormWrapper,
  Fieldset,
  FormAndTableRow,
  Field,
  Submit,
  Form,
  TableOfContents
} from '../components/Forms'
import LeaderInviteForm from '../components/LeaderInviteForm'
import Button from '../components/Button'
import { Container, Flex, Box } from '@hackclub/design-system'
import { withFormik } from 'formik'

const InnerForm = props => {
  const {
    values,
    errors,
    touched,
    handleChange,
    handleBlur,
    handleSubmit,
    isSubmitting,
    id,
    authToken,
    params
  } = props
  const markSubmitted = e => {
    e.preventDefault()
    if (values.submitted_at) {
      alert(
        'Application already submitted. If you want to make further edits, just "Save Draft"'
      )
    } else {
      fetch(`${api}/v1/new_club_applications/${id}/submit`, {
        method: 'POST',
        headers: {
          Authorization: `Bearer ${authToken}`
        }
      })
        .then(res => {
          if (res.ok) {
            alert(
              'Application submitted! You’ll get a confirmation email shortly.'
            )
          } else {
            throw res
          }
        })
        .catch(e => {
          console.error(e)
          if (e.status === 422) {
            alert(
              'Can’t submit. Finish filling out the application and make sure all co-leads have filled out their profiles.'
            )
          } else {
            alert('Something went terribly wrong')
          }
        })
    }
  }
  return (
    <FormWrapper>
      <Form onSubmit={handleSubmit}>
        <Fieldset section="school">
          <Field
            name="high_school_name"
            label="Name of high school"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.high_school_name}
            error={touched.high_school_name && errors.high_school_name}
            isRequired
          />
          <Field
            name="high_school_url"
            label="Link to your high school's website, if any"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.high_school_url}
            error={touched.high_school_url && errors.high_school_url}
          />
          <Field
            name="high_school_type"
            label="Type of school"
            type="select"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.high_school_type || 'select'}
            error={touched.high_school_type && errors.high_school_type}
            isRequired
          >
            <option disabled value="select">
              Select One
            </option>
            <option value="public_school">Public school</option>
            <option value="private_school">Private school</option>
            <option value="charter_school">Charter school</option>
          </Field>
          <Field
            name="high_school_address"
            label="High school's full address (include city, state/province, country)"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.high_school_address}
            error={touched.high_school_address && errors.high_school_address}
            type="textarea"
            isRequired
          />
        </Fieldset>
        <Fieldset section="leaders">
          <LeaderInviteForm params={values} id={id} authToken={authToken} />
          <Field
            name="point_of_contact_id"
            label="Point of contact"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.point_of_contact_id || 'select'}
            error={touched.point_of_contact_id && errors.point_of_contact_id}
            type="select"
            isRequired
          >
            <option disabled value="select">
              Select One
            </option>
            {values.applicant_profiles.map((profile, index) => (
              <option value={profile.applicant.id} key={index}>
                {profile.applicant.email}
              </option>
            ))}
          </Field>
          <Field
            name="leaders_video_url"
            label="Please enter the URL of a 1 minute unlisted (not private) YouTube video introducing the leaders"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.leaders_video_url}
            error={touched.leaders_video_url && errors.leaders_video_url}
            isRequired
          />
          <Field
            name="leaders_interesting_project"
            label="Please tell us about an interesting project, preferably outside of class, that two or more of you created together. Include URLs if possible."
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.leaders_interesting_project}
            error={
              touched.leaders_interesting_project &&
              errors.leaders_interesting_project
            }
            type="textarea"
            isRequired
          />
          <Field
            name="leaders_team_origin_story"
            label="How long have you known your other club leaders and how did you meet?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.leaders_team_origin_story}
            error={
              touched.leaders_team_origin_story &&
              errors.leaders_team_origin_story
            }
            type="textarea"
            isRequired
          />
        </Fieldset>
        <Fieldset section="progress">
          <Field
            name="progress_general"
            label="How far along are you in starting your club?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.progress_general}
            error={touched.progress_general && errors.progress_general}
            type="textarea"
            isRequired
          />
          <Field
            name="progress_student_interest"
            label="Have you already polled for interest at your school? Are students interested? If you've already had meetings, how many people came?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.progress_student_interest}
            error={
              touched.progress_student_interest &&
              errors.progress_student_interest
            }
            type="textarea"
            isRequired
          />
          <Field
            name="progress_meeting_yet"
            label="Have you begun meeting yet? We encourage you to not begin meeting until we accept you."
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.progress_meeting_yet}
            error={touched.progress_meeting_yet && errors.progress_meeting_yet}
            type="textarea"
            isRequired
          />
        </Fieldset>
        <Fieldset section="idea">
          <Field
            name="idea_why"
            label="Why did you decide to start a Hack Club? Have you ran anything like a Hack Club before? Why do you think the club is going to work?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.idea_why}
            error={touched.idea_why && errors.idea_why}
            type="textarea"
            isRequired
          />
          <Field
            name="idea_other_coding_clubs"
            label="Has your school had coding clubs before? What's going to be new about your Hack Club?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.idea_other_coding_clubs}
            error={
              touched.idea_other_coding_clubs && errors.idea_other_coding_clubs
            }
            type="textarea"
            isRequired
          />
          <Field
            name="idea_other_general_clubs"
            label="What other clubs exist at your school? Why will you be just as successful, if not more, than them?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.idea_other_general_clubs}
            error={
              touched.idea_other_general_clubs &&
              errors.idea_other_general_clubs
            }
            type="textarea"
            isRequired
          />
        </Fieldset>
        <Fieldset section="formation">
          <Field
            name="formation_registered"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.formation_registered}
            error={touched.formation_registered && errors.formation_registered}
            label="Have you already registered your club with your school?"
            isRequired
          />
          <Field
            name="formation_misc"
            label="Please provide any other relevant information about the structure or formation of the club."
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.formation_misc}
            error={touched.formation_misc && errors.formation_misc}
            type="textarea"
          />
        </Fieldset>
        <Fieldset section="other">
          <Field
            name="other_surprising_or_amusing_discovery"
            label="What is something surprising or amusing you discovered?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.other_surprising_or_amusing_discovery}
            error={
              touched.other_surprising_or_amusing_discovery &&
              errors.other_surprising_or_amusing_discovery
            }
            type="textarea"
            isRequired
          />
        </Fieldset>
        <Fieldset section="curious">
          <Field
            name="curious_what_convinced"
            label="What convinced you to start a Hack Club?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.curious_what_convinced}
            error={
              touched.curious_what_convinced && errors.curious_what_convinced
            }
            type="textarea"
          />
          <Field
            name="curious_how_did_hear"
            label="How did you hear about Hack Club?"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.curious_how_did_hear}
            error={touched.curious_how_did_hear && errors.curious_how_did_hear}
            type="textarea"
          />
        </Fieldset>
        <Container maxWidth={24}>
          <Submit
            value="Save Draft"
            disabled={isSubmitting}
            w={1}
            my={2}
            bg="white"
            color="primary"
          />
          <Submit
            value="Submit Application"
            disabled={isSubmitting}
            onClick={markSubmitted}
            w={1}
            my={2}
          />
        </Container>
      </Form>
    </FormWrapper>
  )
}

const ClubApplicationForm = withFormik({
  mapPropsToValues: props => props.params,
  enableReinitialize: true,
  handleSubmit: (data, { setSubmitting, props }) => {
    fetch(`${api}/v1/new_club_applications/${props.id}`, {
      method: 'PATCH',
      headers: {
        Authorization: `Bearer ${props.authToken}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(data)
    })
      .then(res => {
        if (res.ok) {
          return res.json()
        } else {
          throw res
        }
      })
      .then(json => {
        alert('Saved!')
        setSubmitting(false)
      })
      .catch(e => {
        console.error(e)
        alert(e)
        setSubmitting(false)
      })
  },
  displayName: 'ClubApplicationForm'
})(InnerForm)
export default ClubApplicationForm
<|endoftext|>


<commit_before>if (typeof (require) != 'undefined') {
	var loader = require('../../node_modules/Butterfly-js/dist/butterfly.min.js').loader;
}

/**
 * Engine module, deal with the whole game linking, the screens, display
 * of a loading bar...
 */
loader.addModule('Engine',
'B', 'Canvas', 'Controls', 'Level', 'data', 'GUI', 'Camera',
function (B, canvas, Controls, Level, data, GUI, Camera) {
	"use strict";

	var _callbacks = {},
		engine = {},
		fps = 30,
		currentLevelIndex = 0,
		// some states
		gameFinished = false,
		levelFinished = false,
		_drawables = [],
		level,
		// If set to true, the camera will scroll, otherwise, the
		// level will have to fit in the camera
		_fixedSizeWorld,
		_camera;

	engine.NO_DEBUG = 0;

	engine.OPTION_USE_KEYBOARD = 0x1;
	engine.OPTION_USE_MOUSE = 0x2;
	engine.OPTION_FIXED_SIZE_WORLD = 0x4;

	/**
	 * PRIVATE METHOD
	 *
	 * Method to load the resources provided in data to be used in the
	 * game. Once all the resources are loaded, loadedCallback is
	 * executed.
	 */
	function _loadResources (loadedCallback) {
		var r, loaded = 0,
			loadingPadding = canvas.width() / 5,
			loadingWidth = 3 * loadingPadding,
			resources = data.resources,
			_resourceLoaded;

		if (!resources) {
			loadedCallback();
			return;
		}

		canvas.clearScreen();
		GUI.progressBar(
			loadingPadding, canvas.height() / 2,
			loadingWidth, 30,
			0,
			'black', 'white', 'black'
		);

		_resourceLoaded = function () {
			loaded++;
			GUI.progressBar(
				loadingPadding, canvas.height() / 2,
				loadingWidth, 30,
				loaded / resources.length,
				'black', 'white', 'black'
			);

			if (loaded == resources.length) {
				loadedCallback();
			}
		};

		for (r = 0; r < resources.length; r++) {
			if (resources[r] && resources[r].url) {
				resources[r].resource = new Image();
				resources[r].resource.onload = _resourceLoaded;
				resources[r].resource.src = resources[r].url;
			}
			else {
				if (resources[r]) {
					resources[r].resource = resources[r].color;
				}
				++loaded;
			}
		}

		if (loaded == resources.length) {
			loadedCallback();
		}
	}

	/**
	 * PRIVATE METHOD
	 *
	 * Method to execute on each frame to update the game state with the
	 * moveAll event.
	 *
	 * During the move allEvent, if the win event is fired, gameFinished
	 * or levelFinished will be switched to true. If one of those is
	 * true, the corresponding event (gameFinishedScreen or
	 * levelFinishedScreen) will be fired to display the correct screen.
	 */
	function _updateAll () {
		if (!gameFinished && !levelFinished) {
			_runCallback('moveAll');
		}

		canvas.clearScreen('black');
		if (gameFinished) {
			_runCallback('gameFinishedScreen');
		}
		else if (levelFinished) {
			_runCallback('levelFinishedScreen');
		}
		else {
			_drawAll([level.cells, _drawables]);
		}
	}

	/**
	 * Draw a list of elements
	 * Every element's coordinate is relative to the world, so
	 * the startPosition argument is supposed to be an object with
	 * the coordinates of where to start to draw the elements in the
	 * world to convert the world coordinates into camera
	 * coordinates
	 */
	function _drawAll (all) {
		function _subDrawAll (all) {
			var a, visible,
				shiftCameraX = _camera.xWorld - _camera.x,
				shiftCameraY = _camera.yWorld - _camera.y;
			for (a = 0; a < all.length; a++) {
				if (all[a].length) {
					_subDrawAll(all[a]);
				}
				else {
					// [all[a].x, all[a].y] are the position of the
					// element in the world
					var x = all[a].x - shiftCameraX,
						y = all[a].y - shiftCameraY;
					// [x, y] are the position of the element in the
					// canvas

					visible = true;
					if (x + all[a].w < _camera.x || x > _camera.x + _camera.w) {
						visible = false;
					}
					else if (y + all[a].h < _camera.y || y > _camera.y + _camera.h) {
						visible = false;
					}

					if (visible) {
						all[a].draw(x, y);
					}
				}
			}
		}

		_subDrawAll(all);
		_camera.draw();
	}

	/**
	 * PRIVATE METHOD
	 *
	 * Callbacks can be hooked in the engine from the application to be
	 * executed at specific times (eg. display a end of level/game
	 * screen).
	 * This method runs a callback from its name with given arguments.
	 */
	function _runCallback (name, args) {
		if (typeof _callbacks[name] == 'function') {
			_callbacks[name].apply(this, args);
		}
	}

	/**
	 * PRIVATE METHOD
	 *
	 * This method resets the current level. If the argument newLevel is
	 * set to true, the level is reconstructed.
	 */
	function _resetLevel (newLevel) {
		if (newLevel) {
			level = Level.createLevel(
				data,
				currentLevelIndex,
				_getGridCellDimensions()
			);
		}
		else {
			level.reset();
		}

		_runCallback('resetLevel');
	}

	/**
	 * PRIVATE METHOD
	 *
	 * Return the dimensions of a gridcell depending on if the level has
	 * a fix size or not
	 */
	function _getGridCellDimensions () {
		var cellDimensions;
		if (!_fixedSizeWorld) {
			cellDimensions = [
				canvas.width() / data.maps[currentLevelIndex].width,
				canvas.height() / data.maps[currentLevelIndex].height
			];
		}
		else if (data.maps[currentLevelIndex].cellWidth && data.maps[currentLevelIndex].cellHeight) {
			cellDimensions = [
				data.maps[currentLevelIndex].cellWidth,
				data.maps[currentLevelIndex].cellHeight
			];
		}
		else {
			throw "The dimensions of the grid's cells are needed in the map definition";
		}

		return cellDimensions;
	}

	/**
	 * PRIVATE METHOD
	 *
	 * Inits different events in the engine, from Butterfly.Events
	 */
	function _initEvents () {
		// Event to execute when the player wins
		B.Events.on('win', null, function () {
			if (currentLevelIndex == data.maps.length - 1) {
				_resetLevel(true);
				gameFinished = true;
			}
			else {
				_resetLevel(false);
				levelFinished = true;
			}

			_runCallback('win', arguments);
		});

		// Event to execute when the player loses
		B.Events.on('lost', null, function () {
			_resetLevel(false);

			_runCallback('lose');
		});

		// Event to execute when the mouse is clicked
		B.Events.on('mouse-clicked', null, function () {
			if (levelFinished) {
				currentLevelIndex++;
				_resetLevel(true);
				levelFinished = false;
			}
			else if (gameFinished) {
				currentLevelIndex = 0;
				_resetLevel(true);
				gameFinished = false;
			}

			_runCallback('mouseClicked');
		});

		// Event to execute when the mouse move
		B.Events.on('mouse-moved', null, function (mX, mY) {
			_runCallback('mouseMoved', [mX, mY]);
		});
	}

	/**
	 * Method to add a callback to the engine, to be executed in the
	 * appropriate time.
	 */
	engine.addCallback = function (name, callback) {
		_callbacks[name] = callback;
	};

	/**
	 * Initialise the camera in a given position in the world and with
	 * given dimensions and positions in the screen.
	 */
	engine.initCamera = function (xWorld, yWorld, x, y, w, h) {
		_camera = new Camera(xWorld, yWorld, x, y, w, h);
	};

	/**
	 * Moves the camera to the given position in the world
	 * The camera will be bounded by the world's limits. If the camera is too
	 * close to the wall, it will be blocked to not display the
	 * "outside" of the level. However, if the level is smaller than the
	 * camera, the level will be centered (vertically and/or
	 * horizontally) in the camera.
	 */
	engine.updateCameraPosition = function (xWorld, yWorld) {
		var x, y,
			worldWidth = level.gridCellWidth * level.width,
			worldHeight = level.gridCellHeight * level.height;

		// If the world width fits in the camera
		if (_camera.w >= worldWidth) {
			x = (worldWidth - _camera.w) / 2;
		}
		// else if the world is wider than the camera
		// place the camera where it is supposed to be, bounded by the
		// world's limits
		else {
			x = Math.max(
				0,
				Math.min(
					xWorld - _camera.w / 2,
					worldWidth - _camera.w
				)
			);
		}

		// If the world height fits in the camera
		if (_camera.h >= worldHeight) {
			y = (worldHeight - _camera.h) / 2;
		}
		// else if the world is taller than the camera
		// place the camera where it is supposed to be, bounded by the
		// world's limits
		else {
			y = Math.max(
				0,
				Math.min(
					yWorld - _camera.h / 2,
					worldHeight - _camera.h
				)
			);
		}

		_camera.xWorld = x;
		_camera.yWorld = y;
	};

	/**
	 * This method is the engine's entry point. It takes in arguments a
	 * canvas element, some options (in an integer value) and a
	 * callback.
	 * The options can be:
	 * 	Engine.OPTION_USE_KEYBOARD: To monitor the key strokes
	 * 	Engine.OPTION_USE_MOUSE: To monitor the mouse movements and
	 * 		clicks
	 * 	Engine.OPTION_FIXED_SIZE_WORLD: If provided, The world has a
	 * 		fixed size and does not have to fit in the camera. If the
	 * 		option is not provided, the level will be stretched to fit
	 * 		in the camera dimensions.
	 *
	 * The method initialises the canvas, the controls and loads the
	 * resources provided in the data module. Once the resources are
	 * loaded, the callback is then executed.
	 */
	engine.init = function (canvasElement, options, callback) {
		_fixedSizeWorld = (options & engine.OPTION_FIXED_SIZE_WORLD) == engine.OPTION_FIXED_SIZE_WORLD;
		B.on(window, 'load', function () {
			// Init the view
			canvas.init(canvasElement);
			Controls.init(
				(options & engine.OPTION_USE_KEYBOARD) == engine.OPTION_USE_KEYBOARD,
				(options & engine.OPTION_USE_MOUSE) == engine.OPTION_USE_MOUSE ? canvasElement : null
			);

			_loadResources(function () {
				_resetLevel(true);

				if (typeof callback == 'function') {
					callback();

					if (!_camera) {
						engine.initCamera(
							0, 0,
							0, 0,
							canvas.width(), canvas.height()
						);
					}
				}
				setInterval(_updateAll, 1000 / fps);
			});
		});

		_initEvents();
	};

	/**
	 * This method is called to add a drawable element in the engine.
	 * All the added drawable elements are displayed on each frame.
	 */
	engine.addDrawable = function (drawable) {
		_drawables.push(drawable);
	};

	/**
	 * Returns the game's current level.
	 */
	engine.getLevel = function () {
		return level;
	};

	return engine;
});

<commit_msg>CORE - if the element has no coordinates, the draw method is directly called with the camera in arguments<commit_after>if (typeof (require) != 'undefined') {
	var loader = require('../../node_modules/Butterfly-js/dist/butterfly.min.js').loader;
}

/**
 * Engine module, deal with the whole game linking, the screens, display
 * of a loading bar...
 */
loader.addModule('Engine',
'B', 'Canvas', 'Controls', 'Level', 'data', 'GUI', 'Camera',
function (B, canvas, Controls, Level, data, GUI, Camera) {
	"use strict";

	var _callbacks = {},
		engine = {},
		fps = 30,
		currentLevelIndex = 0,
		// some states
		gameFinished = false,
		levelFinished = false,
		_drawables = [],
		level,
		// If set to true, the camera will scroll, otherwise, the
		// level will have to fit in the camera
		_fixedSizeWorld,
		_camera;

	engine.NO_DEBUG = 0;

	engine.OPTION_USE_KEYBOARD = 0x1;
	engine.OPTION_USE_MOUSE = 0x2;
	engine.OPTION_FIXED_SIZE_WORLD = 0x4;

	/**
	 * PRIVATE METHOD
	 *
	 * Method to load the resources provided in data to be used in the
	 * game. Once all the resources are loaded, loadedCallback is
	 * executed.
	 */
	function _loadResources (loadedCallback) {
		var r, loaded = 0,
			loadingPadding = canvas.width() / 5,
			loadingWidth = 3 * loadingPadding,
			resources = data.resources,
			_resourceLoaded;

		if (!resources) {
			loadedCallback();
			return;
		}

		canvas.clearScreen();
		GUI.progressBar(
			loadingPadding, canvas.height() / 2,
			loadingWidth, 30,
			0,
			'black', 'white', 'black'
		);

		_resourceLoaded = function () {
			loaded++;
			GUI.progressBar(
				loadingPadding, canvas.height() / 2,
				loadingWidth, 30,
				loaded / resources.length,
				'black', 'white', 'black'
			);

			if (loaded == resources.length) {
				loadedCallback();
			}
		};

		for (r = 0; r < resources.length; r++) {
			if (resources[r] && resources[r].url) {
				resources[r].resource = new Image();
				resources[r].resource.onload = _resourceLoaded;
				resources[r].resource.src = resources[r].url;
			}
			else {
				if (resources[r]) {
					resources[r].resource = resources[r].color;
				}
				++loaded;
			}
		}

		if (loaded == resources.length) {
			loadedCallback();
		}
	}

	/**
	 * PRIVATE METHOD
	 *
	 * Method to execute on each frame to update the game state with the
	 * moveAll event.
	 *
	 * During the move allEvent, if the win event is fired, gameFinished
	 * or levelFinished will be switched to true. If one of those is
	 * true, the corresponding event (gameFinishedScreen or
	 * levelFinishedScreen) will be fired to display the correct screen.
	 */
	function _updateAll () {
		if (!gameFinished && !levelFinished) {
			_runCallback('moveAll');
		}

		canvas.clearScreen('black');
		if (gameFinished) {
			_runCallback('gameFinishedScreen');
		}
		else if (levelFinished) {
			_runCallback('levelFinishedScreen');
		}
		else {
			_drawAll([level.cells, _drawables]);
		}
	}

	/**
	 * Draw a list of elements
	 * Every element's coordinate is relative to the world, so
	 * the startPosition argument is supposed to be an object with
	 * the coordinates of where to start to draw the elements in the
	 * world to convert the world coordinates into camera
	 * coordinates
	 */
	function _drawAll (all) {
		function _subDrawAll (all) {
			var a, visible,
				shiftCameraX = _camera.xWorld - _camera.x,
				shiftCameraY = _camera.yWorld - _camera.y;
			for (a = 0; a < all.length; a++) {
				if (all[a].length) {
					_subDrawAll(all[a]);
				}
				// delegate the draw to the element itself
				else if (all[a].x === undefined || all[a].y === undefined) {
					// call the draw method of the element with the top
					// left corner of the camera and the camera itself
					all[a].draw(shiftCameraX, shiftCameraY, _camera);
				}
				else {
					// [all[a].x, all[a].y] are the position of the
					// element in the world
					var x = all[a].x - shiftCameraX,
						y = all[a].y - shiftCameraY;
					// [x, y] are the position of the element in the
					// canvas

					visible = true;
					if (x + all[a].w < _camera.x || x > _camera.x + _camera.w) {
						visible = false;
					}
					else if (y + all[a].h < _camera.y || y > _camera.y + _camera.h) {
						visible = false;
					}

					if (visible) {
						all[a].draw(x, y);
					}
				}
			}
		}

		_subDrawAll(all);
		_camera.draw();
	}

	/**
	 * PRIVATE METHOD
	 *
	 * Callbacks can be hooked in the engine from the application to be
	 * executed at specific times (eg. display a end of level/game
	 * screen).
	 * This method runs a callback from its name with given arguments.
	 */
	function _runCallback (name, args) {
		if (typeof _callbacks[name] == 'function') {
			_callbacks[name].apply(this, args);
		}
	}

	/**
	 * PRIVATE METHOD
	 *
	 * This method resets the current level. If the argument newLevel is
	 * set to true, the level is reconstructed.
	 */
	function _resetLevel (newLevel) {
		if (newLevel) {
			level = Level.createLevel(
				data,
				currentLevelIndex,
				_getGridCellDimensions()
			);
		}
		else {
			level.reset();
		}

		_runCallback('resetLevel');
	}

	/**
	 * PRIVATE METHOD
	 *
	 * Return the dimensions of a gridcell depending on if the level has
	 * a fix size or not
	 */
	function _getGridCellDimensions () {
		var cellDimensions;
		if (!_fixedSizeWorld) {
			cellDimensions = [
				canvas.width() / data.maps[currentLevelIndex].width,
				canvas.height() / data.maps[currentLevelIndex].height
			];
		}
		else if (data.maps[currentLevelIndex].cellWidth && data.maps[currentLevelIndex].cellHeight) {
			cellDimensions = [
				data.maps[currentLevelIndex].cellWidth,
				data.maps[currentLevelIndex].cellHeight
			];
		}
		else {
			throw "The dimensions of the grid's cells are needed in the map definition";
		}

		return cellDimensions;
	}

	/**
	 * PRIVATE METHOD
	 *
	 * Inits different events in the engine, from Butterfly.Events
	 */
	function _initEvents () {
		// Event to execute when the player wins
		B.Events.on('win', null, function () {
			if (currentLevelIndex == data.maps.length - 1) {
				_resetLevel(true);
				gameFinished = true;
			}
			else {
				_resetLevel(false);
				levelFinished = true;
			}

			_runCallback('win', arguments);
		});

		// Event to execute when the player loses
		B.Events.on('lost', null, function () {
			_resetLevel(false);

			_runCallback('lose');
		});

		// Event to execute when the mouse is clicked
		B.Events.on('mouse-clicked', null, function () {
			if (levelFinished) {
				currentLevelIndex++;
				_resetLevel(true);
				levelFinished = false;
			}
			else if (gameFinished) {
				currentLevelIndex = 0;
				_resetLevel(true);
				gameFinished = false;
			}

			_runCallback('mouseClicked');
		});

		// Event to execute when the mouse move
		B.Events.on('mouse-moved', null, function (mX, mY) {
			_runCallback('mouseMoved', [mX, mY]);
		});
	}

	/**
	 * Method to add a callback to the engine, to be executed in the
	 * appropriate time.
	 */
	engine.addCallback = function (name, callback) {
		_callbacks[name] = callback;
	};

	/**
	 * Initialise the camera in a given position in the world and with
	 * given dimensions and positions in the screen.
	 */
	engine.initCamera = function (xWorld, yWorld, x, y, w, h) {
		_camera = new Camera(xWorld, yWorld, x, y, w, h);
	};

	/**
	 * Moves the camera to the given position in the world
	 * The camera will be bounded by the world's limits. If the camera is too
	 * close to the wall, it will be blocked to not display the
	 * "outside" of the level. However, if the level is smaller than the
	 * camera, the level will be centered (vertically and/or
	 * horizontally) in the camera.
	 */
	engine.updateCameraPosition = function (xWorld, yWorld) {
		var x, y,
			worldWidth = level.gridCellWidth * level.width,
			worldHeight = level.gridCellHeight * level.height;

		// If the world width fits in the camera
		if (_camera.w >= worldWidth) {
			x = (worldWidth - _camera.w) / 2;
		}
		// else if the world is wider than the camera
		// place the camera where it is supposed to be, bounded by the
		// world's limits
		else {
			x = Math.max(
				0,
				Math.min(
					xWorld - _camera.w / 2,
					worldWidth - _camera.w
				)
			);
		}

		// If the world height fits in the camera
		if (_camera.h >= worldHeight) {
			y = (worldHeight - _camera.h) / 2;
		}
		// else if the world is taller than the camera
		// place the camera where it is supposed to be, bounded by the
		// world's limits
		else {
			y = Math.max(
				0,
				Math.min(
					yWorld - _camera.h / 2,
					worldHeight - _camera.h
				)
			);
		}

		_camera.xWorld = x;
		_camera.yWorld = y;
	};

	/**
	 * This method is the engine's entry point. It takes in arguments a
	 * canvas element, some options (in an integer value) and a
	 * callback.
	 * The options can be:
	 * 	Engine.OPTION_USE_KEYBOARD: To monitor the key strokes
	 * 	Engine.OPTION_USE_MOUSE: To monitor the mouse movements and
	 * 		clicks
	 * 	Engine.OPTION_FIXED_SIZE_WORLD: If provided, The world has a
	 * 		fixed size and does not have to fit in the camera. If the
	 * 		option is not provided, the level will be stretched to fit
	 * 		in the camera dimensions.
	 *
	 * The method initialises the canvas, the controls and loads the
	 * resources provided in the data module. Once the resources are
	 * loaded, the callback is then executed.
	 */
	engine.init = function (canvasElement, options, callback) {
		_fixedSizeWorld = (options & engine.OPTION_FIXED_SIZE_WORLD) == engine.OPTION_FIXED_SIZE_WORLD;
		B.on(window, 'load', function () {
			// Init the view
			canvas.init(canvasElement);
			Controls.init(
				(options & engine.OPTION_USE_KEYBOARD) == engine.OPTION_USE_KEYBOARD,
				(options & engine.OPTION_USE_MOUSE) == engine.OPTION_USE_MOUSE ? canvasElement : null
			);

			_loadResources(function () {
				_resetLevel(true);

				if (typeof callback == 'function') {
					callback();

					if (!_camera) {
						engine.initCamera(
							0, 0,
							0, 0,
							canvas.width(), canvas.height()
						);
					}
				}
				setInterval(_updateAll, 1000 / fps);
			});
		});

		_initEvents();
	};

	/**
	 * This method is called to add a drawable element in the engine.
	 * All the added drawable elements are displayed on each frame.
	 */
	engine.addDrawable = function (drawable) {
		_drawables.push(drawable);
	};

	/**
	 * Returns the game's current level.
	 */
	engine.getLevel = function () {
		return level;
	};

	return engine;
});

<|endoftext|>


<commit_before>function Slider(node, config){
	var defaultPara = {
		mode: 'horizontal', //滚动方向
		speed: 500, //滚动速度
		perGroup: 1, //显示数量
		slidePerView: 1, //每次滚动的数量
		autoPlay: 0, //自动滚动的时间间隔，不大于0时关闭
		loop: true, //是否循环播放
		pagination: null, //分页器
		pageClickable: true //分页器是否可点击
	};
	$.extend(defaultPara, config);
	this.block = $(node),
	this.mode = defaultPara.mode,
	this.speed = defaultPara.speed,
	this.perGroup = defaultPara.perGroup,
	this.slidePerView = defaultPara.slidePerView,
	this.autoPlay = defaultPara.autoPlay,
	this.pagination = $(defaultPara.pagination),
	this.pageClickable = defaultPara.pageClickable;
	this.list = this.block.find('ul'),
	this.li = this.list.find('li'),
	this.length = this.li.length,
	this.slideLength = Math.ceil((this.length - this.perGroup) / this.slidePerView) + 1;
	this.liWidth = this.li.width(),
	this.liHeight = this.li.height(),
	this.slideIndex = 0,
	this.timer = null;
	var _that = this;
	this.canShowPagination = _that.pagination && _that.perGroup === 1 && _that.slidePerView === 1;

	var _init = function(){
		//设定轮播样式
		if(_that.mode === 'horizontal'){
			_that.block.width(_that.liWidth * _that.perGroup);
			_that.list.width(_that.liWidth * _that.length);
			_that.list.addClass('slide-horizontal');
		}
		else if(_that.mode === 'vertical'){
			_that.block.height(_that.liHeight * _that.perGroup);
			_that.list.height(_that.liHeight * _that.length);
			_that.list.addClass('slide-vertical');
		}
		//添加翻页圆点
		if(_that.canShowPagination){
			for(var i = 0; i< _that.length; i++){
				_that.pagination.append('');
			}
			_that.pagination.find('span').eq(0).addClass('on');
		}
		//自动播放
		if(_that.autoPlay){
			_that.timer = setInterval(function(){
				_that.slideNext(true);
			}, _that.autoPlay);
		}
		if(_that.pageClickable){
			_pageBind();
		}
	}

	this.slidePrev = function(){
		clearInterval(this.timer);
		if(this.slideIndex > 0){
			this.slideIndex --;
			_slideAnimation(this.slidePerView);
		}
		else{
			this.slideTo(this.slideLength - 1);
		}
	};

	this.slideNext = function(notClear){
		if(!notClear){
			clearInterval(this.timer);
		}
		if(_that.slideIndex < _that.slideLength - 1){
			_that.slideIndex ++;
			_slideAnimation(-_that.slidePerView);
		}
		else{
			_that.slideTo(0, notClear);
		}
	};

	this.slideTo = function(num, notClear){
		if(!notClear){
			clearInterval(this.timer);
		}
		var _delta = num - this.slideIndex;
		_slideAnimation(-_delta * _that.slidePerView);
		this.slideIndex = num;
	}

	var _slideAnimation = function(num){
		if(_that.mode === 'horizontal'){
			_that.list.animate({left: '+=' + num * _that.liWidth + 'px'}, _that.speed);
		}
		else if(_that.mode === 'vertical'){
			_that.list.animate({top: '+=' + num * _that.liHeight + 'px'}, _that.speed);
		}
		if(_that.canShowPagination){
			_paginationChange();
		}
	}

	var _paginationChange = function(){
		_that.pagination.find('span').eq(_that.slideIndex).addClass('on').siblings().removeClass('on');
	}

	var _pageBind = function(){
		_that.pagination.find('span').on('click', function(){
			var dotIndex = $(this).index();
			_that.slideTo(dotIndex);
		});
	}

	_init();
}<commit_msg>删除无用注释<commit_after>function Slider(node, config){
	var defaultPara = {
		mode: 'horizontal',
		speed: 500,
		perGroup: 1,
		slidePerView: 1,
		autoPlay: 0,
		pagination: null,
		pageClickable: true
	};
	$.extend(defaultPara, config);
	this.block = $(node),
	this.mode = defaultPara.mode,
	this.speed = defaultPara.speed,
	this.perGroup = defaultPara.perGroup,
	this.slidePerView = defaultPara.slidePerView,
	this.autoPlay = defaultPara.autoPlay,
	this.pagination = $(defaultPara.pagination),
	this.pageClickable = defaultPara.pageClickable;
	this.list = this.block.find('ul'),
	this.li = this.list.find('li'),
	this.length = this.li.length,
	this.slideLength = Math.ceil((this.length - this.perGroup) / this.slidePerView) + 1;
	this.liWidth = this.li.width(),
	this.liHeight = this.li.height(),
	this.slideIndex = 0,
	this.timer = null;
	var _that = this;
	this.canShowPagination = _that.pagination && _that.perGroup === 1 && _that.slidePerView === 1;

//初始化
var _init = function(){
		//设定轮播样式
		if(_that.mode === 'horizontal'){
			_that.block.width(_that.liWidth * _that.perGroup);
			_that.list.width(_that.liWidth * _that.length);
			_that.list.addClass('slide-horizontal');
		}
		else if(_that.mode === 'vertical'){
			_that.block.height(_that.liHeight * _that.perGroup);
			_that.list.height(_that.liHeight * _that.length);
			_that.list.addClass('slide-vertical');
		}
		//添加分页器
		if(_that.canShowPagination){
			for(var i = 0; i< _that.length; i++){
				_that.pagination.append('');
			}
			_that.pagination.find('span').eq(0).addClass('on');
		}
		//自动播放
		if(_that.autoPlay){
			_that.timer = setInterval(function(){
				_that.slideNext(true);
			}, _that.autoPlay);
		}
		if(_that.pageClickable){
			_pageBind();
		}
	}

	this.slidePrev = function(){
		clearInterval(this.timer);
		if(this.slideIndex > 0){
			this.slideIndex --;
			_slideAnimation(this.slidePerView);
		}
		else{
			this.slideTo(this.slideLength - 1);
		}
	};

	this.slideNext = function(notClear){
		if(!notClear){
			clearInterval(this.timer);
		}
		if(_that.slideIndex < _that.slideLength - 1){
			_that.slideIndex ++;
			_slideAnimation(-_that.slidePerView);
		}
		else{
			_that.slideTo(0, notClear);
		}
	};

	this.slideTo = function(num, notClear){
		if(!notClear){
			clearInterval(this.timer);
		}
		var _delta = num - this.slideIndex;
		this.slideIndex = num;
		_slideAnimation(-_delta * _that.slidePerView);
	}

//执行滚动
var _slideAnimation = function(num){
	if(_that.mode === 'horizontal'){
		_that.list.animate({left: '+=' + num * _that.liWidth + 'px'}, _that.speed);
	}
	else if(_that.mode === 'vertical'){
		_that.list.animate({top: '+=' + num * _that.liHeight + 'px'}, _that.speed);
	}
	if(_that.canShowPagination){
		_paginationChange();
	}
}

//分页器变换
var _paginationChange = function(){
	_that.pagination.find('span').eq(_that.slideIndex).addClass('on').siblings().removeClass('on');
}

//绑定分页器事件
var _pageBind = function(){
	_that.pagination.find('span').on('click', function(){
		var dotIndex = $(this).index();
		_that.slideTo(dotIndex);
	});
}

_init();
}<|endoftext|>


<commit_before>window.addEventListener("load", function () {

	// Grabbing elements from the page =====================================================================
	const music = document.querySelector('#music');
	const player = document.querySelector('#player');
	const playButton = document.querySelector('#pButton');
	const playHead = document.querySelector('#playhead');
	const timeLine = document.querySelector('#timeline');

	// Section for functions =============================================================
	function togglePlay () {	// function to toggle play/pause
		music[music.paused ? 'play' : 'pause']();
	}

	function updateButton () {	// Function to handle play/pause icon
		if (!music.paused) {
			playButton.classList.remove('play');
			playButton.classList.add('pause');
		}
		else {
			playButton.classList.remove('pause');
			playButton.classList.add('play');
		}
	}

	function handleProgress () {	// A  function to handle song duration bar
		var percent = (music.currentTime / music.duration ) * 100;
		if (percent == 100) {
			percent = 0;
			order.push(order.shift());	// Take the completed one and place it at the end of playlist
			play();
		}
		playHead.style.marginLeft = (percent / 100) * 364  + "px";	// Geez -_-
	}

	function scrub (e) {	// function to enable track seek
		const scrubTime = (e.offsetX / 362) * music.duration;
		music.currentTime = scrubTime;
	}

	// The de-facto unbiased shuffle algorithm is the Fisher-Yates (aka Knuth) Shuffle (based on SE answer).
	function shuffle (array) {
		var currentIndex = array.length, temporaryValue, randomIndex;
		// While there remain elements to shuffle
		while (0 !== currentIndex) {
			// Pick a remaining element
			randomIndex = Math.floor(Math.random() * currentIndex);
			currentIndex -= 1;
			// And swap it with the current element.
			temporaryValue = array[currentIndex];
			array[currentIndex] = array[randomIndex];
			array[randomIndex] = temporaryValue;
		}
		return array;
	}

	// Entry Point ! ===========================================================
	let order = shuffle(data);
	function play () {
		music.src = order[0].link;
		music.play();
		updateButton();
		document.body.style.backgroundImage = "url('" + order[0].img + "')";
	}

	play();

	// Section for handling events ===========================================================
	playButton.addEventListener('click', togglePlay);
	playButton.addEventListener('click', updateButton);

	music.addEventListener('timeupdate', handleProgress);

	let mousedown = false;	// variable to keep track of mousedown event
	timeline.addEventListener('mousedown', ()  => mousedown = true);
	timeline.addEventListener('mouseup', () => mousedown =  false);
	timeline.addEventListener('mousemove', (e) => mousedown && scrub(e));
	timeline.addEventListener('click', (e) => scrub(e));
});

//===============================================================================================================================================

data = [
			/* Skeleton
			{
				link :
				name :
				img :
			}
			*/

			// Store Opening here for now
			{
				link : "http://www.youtubeinmp3.com/download/get/?i=wIcqkYMcAAcbblTZ2WeKktyTu5nlffWi&e=49&progressType=button",
				name : "Boku no Hero Academia S2 OP-1",
				img : "http://greywolf-graphics.com/images/boku-no-hero-academia-wallpaper/boku-no-hero-academia-wallpaper-6.jpg"
			},

			{
				link : "http://w20.youtubeinmp3.com/download/get/?id=Q0v3ajXh5S0&r=N31suCidRZYtTdO0vmb4ZMMTVc2pFJYc&t=Tokyo+Ghoul+Unravel+-+Lyrics",
				name : "Tokyo Ghoul - Unravel",
				img : "https://wallpaperscraft.com/image/tokyo_ghoul_kaneki_ken_man_reflection_100594_1920x1080.jpg"
			},

			{
				link : "http://lyricmp3skull.org/s363640c/file/boku-dake-ga-inai-machi-erased-op-rip/256820788.mp3",
				name : "Boku dake ha Inai Machi OP",
				img : "https://s-media-cache-ak0.pinimg.com/originals/94/2d/cd/942dcd797700a370636b5a90115a4026.jpg"
			},

			{
				link : "http://lyricmp3skull.org/s363640c/file/boku-no-hero-academia-op-1/261606779.mp3",
				name : "Boku no Hero Academia S1 OP-1",
				img : "http://www.ricedigital.co.uk/wp-content/uploads/2017/03/003-1.jpg"
			},

			{
				link : "http://lyricmp3skull.org/s363640c/file/op-3/294904496.mp3",
				name : "Bongou Stray Dogs 2 OP-1",
				img : "https://pbs.twimg.com/media/C-FAE86UQAAdckd.jpg"
			},

			{
				link : "http://lyricmp3skull.org/s363640c/file/danganronpa-anime-op-tv-size/249496430.mp3",
				name : "Danganronpa The Animation OP",
				img : "http://data.freehdw.com/danganronpa-2-goodbye-despair-ps-vita-characters.jpg"
			},

			{
				link : "http://lyricmp3skull.org/s363640c/file/masayume-chasing-fairytail-season-2-op-1/148886932.mp3",
				name : "Fairy Tail OP-15",
				img : "https://s-media-cache-ak0.pinimg.com/originals/a5/25/67/a52567b58c01b41ef84f6ce6715a80a1.jpg"
			},

			// Store endings here for now
			{
				link : "http://lyricmp3skull.org/s363640c/file/boku-no-hero-academia-season-2-ed-1/317870688.mp3",
				name : "Boku no Hero Academia S2 ED-1",
				img : "https://i.ytimg.com/vi/ldTgrPe6Y4E/maxresdefault.jpg"
			},

			{
				link : "https://www.youtubeinmp3.com/fetch/?video=https://www.youtube.com/watch?v=n-or12ftZB8",
				name : "Magi S2 ED-1",
				img : "https://vignette4.wikia.nocookie.net/magi/images/d/d0/AlaAliMor_S2_ending.png/revision/latest?cb=20140330134404"
			},

			{
				link : "http://lyricmp3skull.org/s363640c/file/rin-sore-wa-chiisana-hikari-no-youna-boku-dake-ga-inai-machi-erased-ending-tv-sized/285358460.mp3",
				name : "Boku dake ga Inai Machi ED",
				img : "https://s-media-cache-ak0.pinimg.com/originals/8b/9a/b0/8b9ab099322ef6e31bf291ceaa17a0a9--manga-art-kenya.jpg"
			},

			{
				link : "http://lyricmp3skull.org/s363640c/file/boku-no-hero-academia-ed-ending-heroes/257300066.mp3",
				name : "Boku no Hero Academia S1 ED",
				img : "http://lostinanime.com/wp-content/uploads/2017/04/Boku-no-Hero-Academia-2-01-34-1280x720.jpg"
			},

			//  Store OSTs here for now
			{
				link : "http://66.90.93.122/ost/death-note-original-soundtrack/fghgpcdtbm/04-l-s-theme.mp3",
				name : "L's Theme A",
				img : "http://www.imgbase.info/images/safe-wallpapers/anime/death_note/3579-anime_death_note_wallpaper.jpg"
			},

			{
				link : "http://66.90.93.122/ost/death-note-original-soundtrack/ftrosjnhdv/03-light-s-theme.mp3",
				name : "Light's Theme",
				img : "https://www.walldevil.com/wallpapers/a91/death-note-yagami.jpg"
			},

			{
				link : "http://66.90.93.122/ost/death-note-original-soundtrack/drakbyuujm/19-death-note-theme.mp3",
				name : "Death Note Main Theme",
				img : "http://wallpoper.com/images/00/31/67/12/death-note_00316712.jpg"
			},

			{
				link : "http://66.90.93.122/ost/death-note-original-soundtrack/cnpikmfqsu/11-l-s-theme-b.mp3",
				name : "L's theme B",
				img : "http://cdn.wallpapersafari.com/87/52/DSgHjT.jpg"
			}

]<commit_msg>some updated audio links (#18)<commit_after>window.addEventListener("load", function () {

	// Grabbing elements from the page =====================================================================
	const music = document.querySelector('#music');
	const player = document.querySelector('#player');
	const playButton = document.querySelector('#pButton');
	const playHead = document.querySelector('#playhead');
	const timeLine = document.querySelector('#timeline');

	// Section for functions =============================================================
	function togglePlay () {	// function to toggle play/pause
		music[music.paused ? 'play' : 'pause']();
	}

	function updateButton () {	// Function to handle play/pause icon
		if (!music.paused) {
			playButton.classList.remove('play');
			playButton.classList.add('pause');
		}
		else {
			playButton.classList.remove('pause');
			playButton.classList.add('play');
		}
	}

	function handleProgress () {	// A  function to handle song duration bar
		var percent = (music.currentTime / music.duration ) * 100;
		if (percent == 100) {
			percent = 0;
			order.push(order.shift());	// Take the completed one and place it at the end of playlist
			play();
		}
		playHead.style.marginLeft = (percent / 100) * 364  + "px";	// Geez -_-
	}

	function scrub (e) {	// function to enable track seek
		const scrubTime = (e.offsetX / 362) * music.duration;
		music.currentTime = scrubTime;
	}

	// The de-facto unbiased shuffle algorithm is the Fisher-Yates (aka Knuth) Shuffle (based on SE answer).
	function shuffle (array) {
		var currentIndex = array.length, temporaryValue, randomIndex;
		// While there remain elements to shuffle
		while (0 !== currentIndex) {
			// Pick a remaining element
			randomIndex = Math.floor(Math.random() * currentIndex);
			currentIndex -= 1;
			// And swap it with the current element.
			temporaryValue = array[currentIndex];
			array[currentIndex] = array[randomIndex];
			array[randomIndex] = temporaryValue;
		}
		return array;
	}

	// Entry Point ! ===========================================================
	let order = shuffle(data);
	function play () {
		music.src = order[0].link;
		music.play();
		updateButton();
		document.body.style.backgroundImage = "url('" + order[0].img + "')";
	}

	play();

	// Section for handling events ===========================================================
	playButton.addEventListener('click', togglePlay);
	playButton.addEventListener('click', updateButton);

	music.addEventListener('timeupdate', handleProgress);

	let mousedown = false;	// variable to keep track of mousedown event
	timeline.addEventListener('mousedown', ()  => mousedown = true);
	timeline.addEventListener('mouseup', () => mousedown =  false);
	timeline.addEventListener('mousemove', (e) => mousedown && scrub(e));
	timeline.addEventListener('click', (e) => scrub(e));
});

//===============================================================================================================================================

data = [
			/* Skeleton
			{
				link :
				name :
				img :
			}
			*/

			// Store Opening here for now
			{
				link : "http://ostanimemp3.wapka.mobi/music/down/54599472/4162987/MzhkZU9EWGh0Z3YwSlcwSlBoYXRzV3BuUDIzMUQrblN1ZWJlYWtxVjBtQlp4N2pFM2c=/Kenshi+Yonezu-Peace+Sign.mp3",
				name : "Boku no Hero Academia S2 OP-1",
				img : "http://greywolf-graphics.com/images/boku-no-hero-academia-wallpaper/boku-no-hero-academia-wallpaper-6.jpg"
			},

			{
				link : "http://w20.youtubeinmp3.com/download/get/?id=Q0v3ajXh5S0&r=N31suCidRZYtTdO0vmb4ZMMTVc2pFJYc&t=Tokyo+Ghoul+Unravel+-+Lyrics",
				name : "Tokyo Ghoul - Unravel",
				img : "https://wallpaperscraft.com/image/tokyo_ghoul_kaneki_ken_man_reflection_100594_1920x1080.jpg"
			},

			{
				link : "http://lyricmp3skull.org/s363640c/file/boku-dake-ga-inai-machi-erased-op-rip/256820788.mp3",
				name : "Boku dake ha Inai Machi OP",
				img : "https://s-media-cache-ak0.pinimg.com/originals/94/2d/cd/942dcd797700a370636b5a90115a4026.jpg"
			},

			{
				link : "http://lyricmp3skull.org/s363640c/file/boku-no-hero-academia-op-1/261606779.mp3",
				name : "Boku no Hero Academia S1 OP-1",
				img : "http://www.ricedigital.co.uk/wp-content/uploads/2017/03/003-1.jpg"
			},

			{
				link : "http://lyricmp3skull.org/s363640c/file/op-3/294904496.mp3",
				name : "Bongou Stray Dogs 2 OP-1",
				img : "https://pbs.twimg.com/media/C-FAE86UQAAdckd.jpg"
			},

			{
				link : "http://lyricmp3skull.org/s363640c/file/danganronpa-anime-op-tv-size/249496430.mp3",
				name : "Danganronpa The Animation OP",
				img : "http://data.freehdw.com/danganronpa-2-goodbye-despair-ps-vita-characters.jpg"
			},

			{
				link : "http://lyricmp3skull.org/s363640c/file/masayume-chasing-fairytail-season-2-op-1/148886932.mp3",
				name : "Fairy Tail OP-15",
				img : "https://s-media-cache-ak0.pinimg.com/originals/a5/25/67/a52567b58c01b41ef84f6ce6715a80a1.jpg"
			},

			// Store endings here for now
			{
				link : "http://lyricmp3skull.org/s363640c/file/boku-no-hero-academia-season-2-ed-1/317870688.mp3",
				name : "Boku no Hero Academia S2 ED-1",
				img : "https://i.ytimg.com/vi/ldTgrPe6Y4E/maxresdefault.jpg"
			},

			{
				link : "https://www.youtubeinmp3.com/fetch/?video=https://www.youtube.com/watch?v=n-or12ftZB8",
				name : "Magi S2 ED-1",
				img : "https://vignette4.wikia.nocookie.net/magi/images/d/d0/AlaAliMor_S2_ending.png/revision/latest?cb=20140330134404"
			},

			{
				link : "http://lyricmp3skull.org/s363640c/file/rin-sore-wa-chiisana-hikari-no-youna-boku-dake-ga-inai-machi-erased-ending-tv-sized/285358460.mp3",
				name : "Boku dake ga Inai Machi ED",
				img : "https://s-media-cache-ak0.pinimg.com/originals/8b/9a/b0/8b9ab099322ef6e31bf291ceaa17a0a9--manga-art-kenya.jpg"
			},

			{
				link : "http://lyricmp3skull.org/s363640c/file/boku-no-hero-academia-ed-ending-heroes/257300066.mp3",
				name : "Boku no Hero Academia S1 ED",
				img : "http://lostinanime.com/wp-content/uploads/2017/04/Boku-no-Hero-Academia-2-01-34-1280x720.jpg"
			},

			//  Store OSTs here for now
			{
				link : "http://66.90.93.122/ost/death-note-original-soundtrack/fghgpcdtbm/04-l-s-theme.mp3",
				name : "L's Theme A",
				img : "http://www.imgbase.info/images/safe-wallpapers/anime/death_note/3579-anime_death_note_wallpaper.jpg"
			},

			{
				link : "http://66.90.93.122/ost/death-note-original-soundtrack/ftrosjnhdv/03-light-s-theme.mp3",
				name : "Light's Theme",
				img : "https://www.walldevil.com/wallpapers/a91/death-note-yagami.jpg"
			},

			{
				link : "http://66.90.93.122/ost/death-note-original-soundtrack/drakbyuujm/19-death-note-theme.mp3",
				name : "Death Note Main Theme",
				img : "http://wallpoper.com/images/00/31/67/12/death-note_00316712.jpg"
			},

			{
				link : "http://66.90.93.122/ost/death-note-original-soundtrack/cnpikmfqsu/11-l-s-theme-b.mp3",
				name : "L's theme B",
				img : "http://cdn.wallpapersafari.com/87/52/DSgHjT.jpg"
			}

]<|endoftext|>