<commit_before>// ==UserScript==
// @name        ArcSoft Project Management
// @version     0.0.9
// @author      maxint <NOT_SPAM_lnychina@gmail.com>
// @namespace   http://maxint.github.io
// @description An enhancement for Arcsoft project management system in http://doc-server
// @include     http://doc-server/*
// @include     https://doc-server/*
// @updateURL   https://raw.githubusercontent.com/maxint/userjs/master/docserver/doc-server-project-ms.user.js
// @downloadURL https://raw.githubusercontent.com/maxint/userjs/master/docserver/doc-server-project-ms.user.js
// @grant       none
// @Note
// v0.0.9
//  - Add https support.
//  - Add "Release" column to "/index2014/Engineering/index.asp" page.
//
// v0.0.8
//  - Add partial auto fill support for "Edit" window.
//  - Add message alert when flushing project IDs.
//  - Fix bug of "Invert Rows" caused by web page update.
//
// v0.0.7
//  - Update @updateURL and @downloadURL.
//  - Add support for "Edit" in "Add Release Page".
//
// v0.0.6
//  - Fix bug of date format.
//
// v0.0.5
//  - Login page: login when press <Enter> in password input.
//
// v0.0.4
//  - Add management of "Related Projects".
//
// v0.0.3
//  - Add "Invert Rows" button to "Release List" page.
//
// v0.0.2
//  - Auto save data in "Add Rlease" form.
//
// v0.0.1
//  - 首页 | “项目” 导航到 “项目跟踪”
//  - “项目跟踪”页面添加 "Release"
//  - "Add Release Package" 窗口：
//      * 自动填写日期
//      * 根据Release Package填写Version
//      * 自动查询Related Project名称
//
// ==/UserScript==

// a function that loads jQuery and calls a callback function when jQuery has finished loading
; (function (callback, safe) {
    if (typeof(jQuery) == "undefined") {
        var script = document.createElement("script");
        script.type = "text/javascript";
        script.src = "https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.11.1.min.js";
        if (safe) {
            var cb = document.createElement("script");
            cb.type = "text/javascript";
            cb.textContent = "jQuery.noConflict();(" + callback.toString() + ")(jQuery, window);";
            script.addEventListener('load', function () {
                document.head.appendChild(cb);
            });
        } else {
            var dollar = undefined;
            if (typeof($) != "undefined") dollar = $;
            script.addEventListener('load', function () {
                jQuery.noConflict();
                $ = dollar;
                callback(jQuery, window);
            });
        }
        document.head.appendChild(script);
    } else {
        console.log('Using jquery ' + jQuery().jquery);
        setTimeout(function () {
            //Firefox supports
            console.log('Runing custom script');
            callback(jQuery, typeof(unsafeWindow) == "undefined" ? window : unsafeWindow);
        }, 30);
    }
})(function ($, window) {
    // helper functions
    // local storage
    var IStorage = function (prefix) {
        var pref = prefix + '.';
        var addpref = function (key) { return pref + key; };
        this.get = function (key, def) {
            var val = window.localStorage.getItem(addpref(key));
            return val || def || null;
        };
        this.set = function (key, val) {
            window.localStorage.setItem(addpref(key), val);
        };
        this.flush = function () {
            window.localStorage.clear();
        };
        this.getObject = function (key, def) {
            var val = this.get(key);
            return val ? JSON.parse(val) : (def || null);
        };
        this.setObject = function (key, val) {
            this.set(key, JSON.stringify(val));
        };
    };

    // replace main menu [Project]
    function redirectToProjectListPage(obj) {
        obj.attr('href', '/projectManage/ProjectList.asp');
    }
    redirectToProjectListPage($('li#mainMenuItem_150000 a'));

    // add "Release" column in second row of table
    function addReleaseToTable(table) {
        var trs = table.find('tbody tr');
        trs.first().find('th:nth-child(2)').after('Operations	');
        trs.nextAll().each(function () {
            var id = $(this).find('td:first a:first').text();
            var rlsUrl = 'http://doc-server/projectManage/ProjectOther/ReleaseList.asp?proj_id=' + id
            var link = 'Release'
            $(this).find('td:nth-child(2)').after('' + link + '	');
        });
    };

    // fill input values
    var fillValues = function (dict, istore) {
        for (var key in dict) {
            var elem = dict[key];
            if (!elem.val())
                elem.val(istore.get(key, ''));
        }
    }
    // save input values
    var storeValues = function (dict, istore) {
        for (var key in dict) {
            istore.set(key, dict[key].val());
        }
    }

    // operate w.r.t. sub path
    var subpath = window.location.pathname;
    if (subpath == '/login.asp') {
        $('input#password').keyup(function (e) {
            if (e.which == 13) {
                $('input[value="Login"]').click();
            }
        });
    } else if (subpath == '/index2014/index.asp') {
        console.log('Index2014');
        redirectToProjectListPage($('div#headerTopDiv div a:nth-child(2)'));
    } else if (subpath == '/projectManage/ProjectList.asp') {
        console.log('ProjectList');
        addReleaseToTable($('table.ListTable'));
    } else if (subpath == '/index2014/Engineering/index.asp') {
        console.log('Engineering');
        addReleaseToTable($('#workspace table:first'));
    } else if (subpath == '/projectManage/ProjectOther/ReleaseList.asp') {
        console.log('ReleaseList');
        if (window.location.protocol == 'https:') {
            console.log('Redirecting to http ...');
            window.location.replace(window.location.href.replace('https://', 'http://'));
            return;
        }
        // invert table row
        $('<input type="button" value="Invert Rows"/>').insertBefore($("input[type='button']")).click(function () {
            $('table.ListTable tbody').each(function (elem, index) {
                var arr = $.makeArray($("tr", this).detach());
                var th = arr.shift();
                arr.reverse();
                arr.unshift(th);
                $(this).append(arr);
            });
        }).click();
    } else if (subpath == '/projectManage/ProjectDelivery/delivery_codingreport_update.asp') {
        console.log('delivery');
        var id = $('#projectid').val();
        var istore = new IStorage('project/' + id);
        var dict = {
            'svn_path': $('input#SourceCodePath'),
            'last_tag': $('input#SOSLabel'),
            'hzpm_notes': $('textarea#hzpm_notes'),
        };
        fillValues(dict, istore);
        $(window).unload(function () {
            console.log('window unload');
            storeValues(dict, istore);
        });
    } else if (subpath == '/projectManage/ProjectOther/addRelease.asp') {
        console.log('addRelease');
        var istore = new IStorage('addRelease');
        // related project IDs
        var IDManager = function (db) {
            var storeid = 'IDs';
            var idb = db;
            var cb = function () {};
            this.data = {};
            this.load = function () {
                this.data = idb.getObject(storeid, {});
                cb(this.data);
                return this;
            };
            this.save = function () {
                idb.setObject(storeid, this.data);
                return this;
            };
            this.add = function (id, name) {
                if (!(id in this.data)) {
                    this.data[id] = {name: name};
                    cb(this.data);
                }
                return this;
            };
            this.set = function (id, name) {
                if (id in this.data) {
                    this.data[id] = {name: name};
                }
                return this;
            };
            this.remove = function (id) {
                if (id in this.data) {
                    delete this.data[id];
                    cb(this.data);
                }
                return this;
            };
            this.clear = function (id) {
                if (this.data) {
                    this.data = {};
                    cb(this.data);
                }
                return this;
            };
            this.change = function (callback) {
                var oldcb = cb;
                cb = function (data) { oldcb(data); callback(data); }
                return this;
            };
            this.check = function (id, callback) {
                if (/^[0-9]{4}$/.test(id)) {
                    var url = '../ProjectDelivery/delivery_releated_project_list.asp';
                    $.get(url, {projid: id}, function (data, status) {
                        name = $(data).find('td:nth-child(2)').text();
                        proj_status = $(data).find('td:nth-child(3)').text();
                        if (status == 'success' && callback)
                            callback(name, id, proj_status);
                        else
                            callback();
                    });
                } else {
                    callback();
                }
                return this;
            };
        };
        var idmgr = new IDManager(istore);
        if (window.location.search.indexOf('IdentityID=') == -1) {
            // date
            var d = new Date();
            $('input#txtDate').val(d.getFullYear() + '/' + (d.getMonth()+1) + '/' + d.getDate());
            // create packages textarea
            var packagesTextArea = $('<textarea id="txtDeliveryPackages"></textarea>').css({
                'width': '100%',
                'height': '80px',
            });
            $('input#txtDeliveryPackage').siblings('input').last().after(packagesTextArea);
            // fill previous data
            var dict = {
                'version': $("input[name='txtVersion']"),
                'releasepath': $('input#txtReleasePath'),
                'package': $('input#txtDeliveryPackage'),
                'packages': $('textarea#txtDeliveryPackages'),
                'relatedProjectID': $("input[name='txtReleaseReleatedProject']"),
                'note': $('textarea#txtNotes'),
            };
            fillValues(dict, istore);
            // save result before close window
            $(window).unload(function () {
                console.log('window closing');
                storeValues(dict, istore);
                idmgr.save();
            });
            // submit
            $('#btnSubmit').removeAttr('onclick').click(function () {
                // check form
                console.log('checking form ...');
                if (!checkReleateProject())
                    return;
                var pkgs = packagesTextArea.val().split('\n');
                for (var i in pkgs) {
                    var pkg = pkgs[i];
                    $('input#txtReleasePath,input#txtDeliveryPackage').val(pkg);
                    if (!$('#form1').valid()) {
                        alert('提交包列表格式不对');
                        return;
                    }
                }
                // submit
                $(this).attr('disabled', true);
                for (var i in pkgs) {
                    var pkg = pkgs[i];
                    console.log('submitting ' + pkg + ' ...');
                    $('input#txtReleasePath,input#txtDeliveryPackage').val(pkg);
                    var qstr = $('#form1').formSerialize();
                    $.post('../Ajax/AjaxSubmitProjectRelease.asp', qstr, function (data) {
                        if (data != "success")
                            alert(data);
                    }).error(function () {
                        alert("系统网络错误,请联系相关人员处理.");
                        return;
                    });
                }
                alert("提交成功");
                parent.document.location.reload();
            });
        }
        // update version
        $('#txtDeliveryPackage,#txtDeliveryPackages').change(function () {
            var val = $(this).val();
            var vers = /(\d+)\.(\d+)\.\d+\.(\d+)/g.exec(val);
            if (vers == null)
                vers = /(\d+)\.(\d+)\.(\d+)/g.exec(val);
            if (vers) {
                vstr = 'v' + [vers[1], vers[2], vers[3]].join('.')
                $("input[name='txtVersion']").val(vstr);
            }
        }).css({
            'width': '100%',
        });
        // release package
        $('input#txtReleasePath').css({
            'width': '100%',
        });
        // related project table
        $(function () {
            var table = $('
' +
                          '

ID	Name	Operation

' +
                          '

' +
                          '
' +
                              '
<input id="inputID" type="text" size="4"/>	' +
                              'Clicking "Add" to add item	' +
                              '<input id="addID" type="button" value="Add"/>
' +
                              '
Clear all saved data	' +
                              '<input id="flushIDs" type="button" value="Flush"/>
' +
                          '
' +
                          '
').css({ width: '100%' });
            $('input#btnCheckReleatedProject').after('

').next().after(table);
            idmgr.change(function (data) {
                table.find('tbody').each(function () {
                    $(this).empty();
                    // insert exist items
                    for (var id in data) {
                        var val = data[id];
                        $('
' + id + '	' +
                          '' + val['name'] + '	' +
                          '<input id="delID" type="button" value="Del"/>
').appendTo($(this));
                    }
                });
            }).load();
            table.find('tbody').delegate('input#delID', 'click', function () {
                var id = $(this).parent().prev().prev().text();
                idmgr.remove(id);
            }).delegate('td.projIdName', 'click', function () {
                if ($(this).find('input').length) return;
                var oldval = $(this).text();
                $(this).addClass('cellEditing');
                $(this).empty();
                var input = $('<input type="text", value="' + oldval + '"/>');
                input.appendTo($(this)).focus().keypress(function (e) {
                    if (e.which == 13) {
                        // enter
                        var id = $(this).parent().prev().text();
                        var newval = $(this).val();
                        $(this).parent().text(newval);
                        idmgr.set(id, newval);
                    }
                }).blur(function () {
                    $(this).parent().text(oldval);
                }).css({
                    width: '100%',
                });
            }).delegate('td.projId', 'click', function () {
                var id = $(this).text();
                $("input[name='txtReleaseReleatedProject']").val(id).keyup();
            });
            table.find('input#inputID').keyup(function (e) {
                if (e.which == 13) {
                    $(this).parent().nextAll().find('input#addID').click();
                    return;
                }
                idmgr.check($(this).val(), function (name) {
                    table.find('td#inputIDtxt').text(name || '');
                });
            });
            table.find('input#addID').click(function () {
                var id = table.find('input#inputID').val();
                var name = table.find('td#inputIDtxt').text();
                if (id && name) {
                    idmgr.add(id, name);
                }
            });
            table.find('input#flushIDs').click(function () {
                if (confirm('Delete all project IDs?')) {
                    idmgr.clear();
                }
            });
        });
        $("input[name='txtReleaseReleatedProject']").keyup(function () {
            var id = $(this).val();
            var msgdiv = $('input#btnCheckReleatedProject').next();
            idmgr.check(id, function (name) {
                if (name)
                    msgdiv.html(name);
                else
                    msgdiv.html('No project found');
            });
        }).keyup();
        // notes
        $('textarea#txtNotes').css({
            width: '100%',
            height: '80px',
        });
    }
}, true);
<commit_msg>Add tip for multiple packages<commit_after>// ==UserScript==
// @name        ArcSoft Project Management
// @version     1
// @author      maxint <NOT_SPAM_lnychina@gmail.com>
// @namespace   http://maxint.github.io
// @description An enhancement for Arcsoft project management system in http://doc-server
// @include     http://doc-server/*
// @include     https://doc-server/*
// @updateURL   https://raw.githubusercontent.com/maxint/userjs/master/docserver/doc-server-project-ms.user.js
// @downloadURL https://raw.githubusercontent.com/maxint/userjs/master/docserver/doc-server-project-ms.user.js
// @grant       none
// @Note
// v1
//  - Add support for submitting multiple packages at one time.
//
// v0.0.9
//  - Add https support.
//  - Add "Release" column to "/index2014/Engineering/index.asp" page.
//
// v0.0.8
//  - Add partial auto fill support for "Edit" window.
//  - Add message alert when flushing project IDs.
//  - Fix bug of "Invert Rows" caused by web page update.
//
// v0.0.7
//  - Update @updateURL and @downloadURL.
//  - Add support for "Edit" in "Add Release Page".
//
// v0.0.6
//  - Fix bug of date format.
//
// v0.0.5
//  - Login page: login when press <Enter> in password input.
//
// v0.0.4
//  - Add management of "Related Projects".
//
// v0.0.3
//  - Add "Invert Rows" button to "Release List" page.
//
// v0.0.2
//  - Auto save data in "Add Rlease" form.
//
// v0.0.1
//  - 首页 | “项目” 导航到 “项目跟踪”
//  - “项目跟踪”页面添加 "Release"
//  - "Add Release Package" 窗口：
//      * 自动填写日期
//      * 根据Release Package填写Version
//      * 自动查询Related Project名称
//
// ==/UserScript==

// a function that loads jQuery and calls a callback function when jQuery has finished loading
; (function (callback, safe) {
    if (typeof(jQuery) == "undefined") {
        var script = document.createElement("script");
        script.type = "text/javascript";
        script.src = "https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.11.1.min.js";
        if (safe) {
            var cb = document.createElement("script");
            cb.type = "text/javascript";
            cb.textContent = "jQuery.noConflict();(" + callback.toString() + ")(jQuery, window);";
            script.addEventListener('load', function () {
                document.head.appendChild(cb);
            });
        } else {
            var dollar = undefined;
            if (typeof($) != "undefined") dollar = $;
            script.addEventListener('load', function () {
                jQuery.noConflict();
                $ = dollar;
                callback(jQuery, window);
            });
        }
        document.head.appendChild(script);
    } else {
        console.log('Using jquery ' + jQuery().jquery);
        setTimeout(function () {
            //Firefox supports
            console.log('Runing custom script');
            callback(jQuery, typeof(unsafeWindow) == "undefined" ? window : unsafeWindow);
        }, 30);
    }
})(function ($, window) {
    // helper functions
    // local storage
    var IStorage = function (prefix) {
        var pref = prefix + '.';
        var addpref = function (key) { return pref + key; };
        this.get = function (key, def) {
            var val = window.localStorage.getItem(addpref(key));
            return val || def || null;
        };
        this.set = function (key, val) {
            window.localStorage.setItem(addpref(key), val);
        };
        this.flush = function () {
            window.localStorage.clear();
        };
        this.getObject = function (key, def) {
            var val = this.get(key);
            return val ? JSON.parse(val) : (def || null);
        };
        this.setObject = function (key, val) {
            this.set(key, JSON.stringify(val));
        };
    };

    // replace main menu [Project]
    function redirectToProjectListPage(obj) {
        obj.attr('href', '/projectManage/ProjectList.asp');
    }
    redirectToProjectListPage($('li#mainMenuItem_150000 a'));

    // add "Release" column in second row of table
    function addReleaseToTable(table) {
        var trs = table.find('tbody tr');
        trs.first().find('th:nth-child(2)').after('Operations	');
        trs.nextAll().each(function () {
            var id = $(this).find('td:first a:first').text();
            var rlsUrl = 'http://doc-server/projectManage/ProjectOther/ReleaseList.asp?proj_id=' + id
            var link = 'Release'
            $(this).find('td:nth-child(2)').after('' + link + '	');
        });
    };

    // fill input values
    var fillValues = function (dict, istore) {
        for (var key in dict) {
            var elem = dict[key];
            if (!elem.val())
                elem.val(istore.get(key, ''));
        }
    }
    // save input values
    var storeValues = function (dict, istore) {
        for (var key in dict) {
            istore.set(key, dict[key].val());
        }
    }

    // operate w.r.t. sub path
    var subpath = window.location.pathname;
    if (subpath == '/login.asp') {
        $('input#password').keyup(function (e) {
            if (e.which == 13) {
                $('input[value="Login"]').click();
            }
        });
    } else if (subpath == '/index2014/index.asp') {
        console.log('Index2014');
        redirectToProjectListPage($('div#headerTopDiv div a:nth-child(2)'));
    } else if (subpath == '/projectManage/ProjectList.asp') {
        console.log('ProjectList');
        addReleaseToTable($('table.ListTable'));
    } else if (subpath == '/index2014/Engineering/index.asp') {
        console.log('Engineering');
        addReleaseToTable($('#workspace table:first'));
    } else if (subpath == '/projectManage/ProjectOther/ReleaseList.asp') {
        console.log('ReleaseList');
        if (window.location.protocol == 'https:') {
            console.log('Redirecting to http ...');
            window.location.replace(window.location.href.replace('https://', 'http://'));
            return;
        }
        // invert table row
        $('<input type="button" value="Invert Rows"/>').insertBefore($("input[type='button']")).click(function () {
            $('table.ListTable tbody').each(function (elem, index) {
                var arr = $.makeArray($("tr", this).detach());
                var th = arr.shift();
                arr.reverse();
                arr.unshift(th);
                $(this).append(arr);
            });
        }).click();
    } else if (subpath == '/projectManage/ProjectDelivery/delivery_codingreport_update.asp') {
        console.log('delivery');
        var id = $('#projectid').val();
        var istore = new IStorage('project/' + id);
        var dict = {
            'svn_path': $('input#SourceCodePath'),
            'last_tag': $('input#SOSLabel'),
            'hzpm_notes': $('textarea#hzpm_notes'),
        };
        fillValues(dict, istore);
        $(window).unload(function () {
            console.log('window unload');
            storeValues(dict, istore);
        });
    } else if (subpath == '/projectManage/ProjectOther/addRelease.asp') {
        console.log('addRelease');
        var istore = new IStorage('addRelease');
        // related project IDs
        var IDManager = function (db) {
            var storeid = 'IDs';
            var idb = db;
            var cb = function () {};
            this.data = {};
            this.load = function () {
                this.data = idb.getObject(storeid, {});
                cb(this.data);
                return this;
            };
            this.save = function () {
                idb.setObject(storeid, this.data);
                return this;
            };
            this.add = function (id, name) {
                if (!(id in this.data)) {
                    this.data[id] = {name: name};
                    cb(this.data);
                }
                return this;
            };
            this.set = function (id, name) {
                if (id in this.data) {
                    this.data[id] = {name: name};
                }
                return this;
            };
            this.remove = function (id) {
                if (id in this.data) {
                    delete this.data[id];
                    cb(this.data);
                }
                return this;
            };
            this.clear = function (id) {
                if (this.data) {
                    this.data = {};
                    cb(this.data);
                }
                return this;
            };
            this.change = function (callback) {
                var oldcb = cb;
                cb = function (data) { oldcb(data); callback(data); }
                return this;
            };
            this.check = function (id, callback) {
                if (/^[0-9]{4}$/.test(id)) {
                    var url = '../ProjectDelivery/delivery_releated_project_list.asp';
                    $.get(url, {projid: id}, function (data, status) {
                        name = $(data).find('td:nth-child(2)').text();
                        proj_status = $(data).find('td:nth-child(3)').text();
                        if (status == 'success' && callback)
                            callback(name, id, proj_status);
                        else
                            callback();
                    });
                } else {
                    callback();
                }
                return this;
            };
        };
        var idmgr = new IDManager(istore);
        if (window.location.search.indexOf('IdentityID=') == -1) {
            // date
            var d = new Date();
            $('input#txtDate').val(d.getFullYear() + '/' + (d.getMonth()+1) + '/' + d.getDate());
            // create packages textarea
            var packagesTextArea = $('<textarea id="txtDeliveryPackages"></textarea>').css({
                'width': '100%',
                'height': '80px',
            });
            $('input#txtDeliveryPackage').hide().siblings('input').hide().last().after(packagesTextArea);
            packagesTextArea.next().each(function () {
                $(this).html('请输入递交包文件名，支持多个文件一起提交，每行一个文件名。');
            });
            // fill previous data
            var dict = {
                'version': $("input[name='txtVersion']"),
                'releasepath': $('input#txtReleasePath'),
                'package': $('input#txtDeliveryPackage'),
                'packages': $('textarea#txtDeliveryPackages'),
                'relatedProjectID': $("input[name='txtReleaseReleatedProject']"),
                'note': $('textarea#txtNotes'),
            };
            fillValues(dict, istore);
            // save result before close window
            $(window).unload(function () {
                console.log('window closing');
                storeValues(dict, istore);
                idmgr.save();
            });
            // submit
            $('#btnSubmit').removeAttr('onclick').click(function () {
                // check form
                console.log('checking form ...');
                if (!checkReleateProject())
                    return;
                var pkgs = packagesTextArea.val().split('\n');
                for (var i in pkgs) {
                    var pkg = pkgs[i];
                    $('input#txtReleasePath,input#txtDeliveryPackage').val(pkg);
                    if (!$('#form1').valid()) {
                        alert('提交包列表格式不对');
                        return;
                    }
                }
                // submit
                $(this).attr('disabled', true);
                for (var i in pkgs) {
                    var pkg = pkgs[i];
                    console.log('submitting ' + pkg + ' ...');
                    $('input#txtReleasePath,input#txtDeliveryPackage').val(pkg);
                    var qstr = $('#form1').formSerialize();
                    $.post('../Ajax/AjaxSubmitProjectRelease.asp', qstr, function (data) {
                        if (data != "success")
                            alert(data);
                    }).error(function () {
                        alert("系统网络错误,请联系相关人员处理.");
                        return;
                    });
                }
                alert("提交成功");
                parent.document.location.reload();
            });
        }
        // update version
        $('#txtDeliveryPackage,#txtDeliveryPackages').change(function () {
            var val = $(this).val();
            var vers = /(\d+)\.(\d+)\.\d+\.(\d+)/g.exec(val);
            if (vers == null)
                vers = /(\d+)\.(\d+)\.(\d+)/g.exec(val);
            if (vers) {
                vstr = 'v' + [vers[1], vers[2], vers[3]].join('.')
                $("input[name='txtVersion']").val(vstr);
            }
        }).css({
            'width': '100%',
        });
        // release package
        $('input#txtReleasePath').css({
            'width': '100%',
        });
        // related project table
        $(function () {
            var table = $('
' +
                          '

ID	Name	Operation

' +
                          '

' +
                          '
' +
                              '
<input id="inputID" type="text" size="4"/>	' +
                              'Clicking "Add" to add item	' +
                              '<input id="addID" type="button" value="Add"/>
' +
                              '
Clear all saved data	' +
                              '<input id="flushIDs" type="button" value="Flush"/>
' +
                          '
' +
                          '
').css({ width: '100%' });
            $('input#btnCheckReleatedProject').after('

').next().after(table);
            idmgr.change(function (data) {
                table.find('tbody').each(function () {
                    $(this).empty();
                    // insert exist items
                    for (var id in data) {
                        var val = data[id];
                        $('
' + id + '	' +
                          '' + val['name'] + '	' +
                          '<input id="delID" type="button" value="Del"/>
').appendTo($(this));
                    }
                });
            }).load();
            table.find('tbody').delegate('input#delID', 'click', function () {
                var id = $(this).parent().prev().prev().text();
                idmgr.remove(id);
            }).delegate('td.projIdName', 'click', function () {
                if ($(this).find('input').length) return;
                var oldval = $(this).text();
                $(this).addClass('cellEditing');
                $(this).empty();
                var input = $('<input type="text", value="' + oldval + '"/>');
                input.appendTo($(this)).focus().keypress(function (e) {
                    if (e.which == 13) {
                        // enter
                        var id = $(this).parent().prev().text();
                        var newval = $(this).val();
                        $(this).parent().text(newval);
                        idmgr.set(id, newval);
                    }
                }).blur(function () {
                    $(this).parent().text(oldval);
                }).css({
                    width: '100%',
                });
            }).delegate('td.projId', 'click', function () {
                var id = $(this).text();
                $("input[name='txtReleaseReleatedProject']").val(id).keyup();
            });
            table.find('input#inputID').keyup(function (e) {
                if (e.which == 13) {
                    $(this).parent().nextAll().find('input#addID').click();
                    return;
                }
                idmgr.check($(this).val(), function (name) {
                    table.find('td#inputIDtxt').text(name || '');
                });
            });
            table.find('input#addID').click(function () {
                var id = table.find('input#inputID').val();
                var name = table.find('td#inputIDtxt').text();
                if (id && name) {
                    idmgr.add(id, name);
                }
            });
            table.find('input#flushIDs').click(function () {
                if (confirm('Delete all project IDs?')) {
                    idmgr.clear();
                }
            });
        });
        $("input[name='txtReleaseReleatedProject']").keyup(function () {
            var id = $(this).val();
            var msgdiv = $('input#btnCheckReleatedProject').next();
            idmgr.check(id, function (name) {
                if (name)
                    msgdiv.html(name);
                else
                    msgdiv.html('No project found');
            });
        }).keyup();
        // notes
        $('textarea#txtNotes').css({
            width: '100%',
            height: '80px',
        });
    }
}, true);
<|endoftext|>


<commit_before>import {storage, message} from 'src/helpers/chrome-api'
import defaultConfig from 'src/app-config'

// background script as transfer station
const msgChecker = /_SELF$/
message.listen((data, sender, sendResponse) => {
  if (msgChecker.test(data.msg)) {
    data.msg = data.msg.slice(0, -5)
    message.send(sender.tab.id, data, response => {
      sendResponse(response)
    })
    return true
  }

  switch (data.msg) {
    case 'CREATE_TAB':
      chrome.tabs.create({url: data.url})
      break
    case 'AUDIO_PLAY':
      let audio = new Audio(data.src)
      let timer = setTimeout(() => {
        timer = null
        sendResponse()
      }, 4000)
      audio.addEventListener('ended', () => {
        if (timer) {
          clearTimeout(timer)
          sendResponse()
        }
      })
      audio.play()
      return true
  }
})

const _dicts = {}
// dynamic load components
const _compReq = require.context('./dicts', true, /\.js$/i)
const _idChecker = /\/(\S+)\.js$/i
_compReq.keys().forEach(path => {
  let id = _idChecker.exec(path)
  if (!id) { return }
  id = id[1].toLowerCase()
  if (!defaultConfig.dicts.all[id]) { return }

  let search = _compReq(path)
  if (typeof search !== 'function') {
    search = search.default
  }
  _dicts[id] = {
    search,
    config: JSON.parse(JSON.stringify(defaultConfig))
  }
})

function setConfigs (config) {
  Object.keys(_dicts).forEach(id => {
    _dicts[id].config = JSON.parse(JSON.stringify(config))
  })
}

function setContextMenu (config) {
  chrome.contextMenus.removeAll()

  config.contextMenu.selected.forEach(id => {
    chrome.contextMenus.create({
      id,
      title: chrome.i18n.getMessage('context_' + id),
      contexts: ['selection']
    })
  })

  chrome.contextMenus.create({
    id: 'google_page_translate',
    title: chrome.i18n.getMessage('context_google_page_translate'),
    contexts: ['all']
  })
}

storage.sync.get('config', data => {
  let config = data.config

  if (config) {
    setConfigs(config)
    setContextMenu(config)

    // listen context menu
    chrome.contextMenus.onClicked.addListener(({menuItemId, selectionText, pageUrl}) => {
      if (menuItemId === 'google_page_translate') {
        chrome.tabs.create({url: `https://translate.google.com/translate?sl=auto&tl=zh-CN&js=y&prev=_t&ie=UTF-8&u=${pageUrl}&edit-text=&act=url`})
        return
      }

      let url = config.contextMenu.all[menuItemId]
      if (url) {
        chrome.tabs.create({url: url.replace('%s', selectionText)})
      }
    })
  }
})

storage.listen('config', changes => {
  let config = changes.config.newValue
  if (config) {
    setConfigs(config)
    setContextMenu(config)
  }
})

message.on('FETCH_DICT_RESULT', (data, sender, sendResponse) => {
  let dict = _dicts[data.dict]
  if (!dict) {
    sendResponse({error: 'Missing Dictionary!'})
    return
  }

  function handleSuccess (result) {
    sendResponse({result, dict: data.dict})
  }

  function handleError (error) {
    sendResponse({error, dict: data.dict})
  }

  dict.search(data.text, dict.config)
    .then(handleSuccess, handleError)
    .catch(handleError)

  // keep the channel alive
  return true
})

// merge config on installed
chrome.runtime.onInstalled.addListener(({previousVersion}) => {
  let config = defaultConfig
  let [major, minor, patch] = previousVersion ? previousVersion.split('.').map(n => Number(n)) : [0, 0, 0]
  if (major <= 4) {
    storage.local.clear()
    storage.sync.clear()
      .then(() => {
        storage.sync.set({config})
        setConfigs(config)
      })
  } else if (major === 5) {
    storage.sync.get('config', data => {
      let config = data.config

      if (config) {
        if (minor < 3) {
          // 5.3 added
          config.dicts.all.howjsay = defaultConfig.dicts.all.howjsay
        }
      } else {
        config = defaultConfig
      }

      storage.sync.set({config})
      setConfigs(config)
    })
  }
})
<commit_msg>Added extension installation hook<commit_after>import {storage, message} from 'src/helpers/chrome-api'
import defaultConfig from 'src/app-config'

// background script as transfer station
const msgChecker = /_SELF$/
message.listen((data, sender, sendResponse) => {
  if (msgChecker.test(data.msg)) {
    data.msg = data.msg.slice(0, -5)
    message.send(sender.tab.id, data, response => {
      sendResponse(response)
    })
    return true
  }

  switch (data.msg) {
    case 'CREATE_TAB':
      chrome.tabs.create({url: data.url})
      break
    case 'AUDIO_PLAY':
      let audio = new Audio(data.src)
      let timer = setTimeout(() => {
        timer = null
        sendResponse()
      }, 4000)
      audio.addEventListener('ended', () => {
        if (timer) {
          clearTimeout(timer)
          sendResponse()
        }
      })
      audio.play()
      return true
  }
})

const _dicts = {}
// dynamic load components
const _compReq = require.context('./dicts', true, /\.js$/i)
const _idChecker = /\/(\S+)\.js$/i
_compReq.keys().forEach(path => {
  let id = _idChecker.exec(path)
  if (!id) { return }
  id = id[1].toLowerCase()
  if (!defaultConfig.dicts.all[id]) { return }

  let search = _compReq(path)
  if (typeof search !== 'function') {
    search = search.default
  }
  _dicts[id] = {
    search,
    config: JSON.parse(JSON.stringify(defaultConfig))
  }
})

function setConfigs (config) {
  Object.keys(_dicts).forEach(id => {
    _dicts[id].config = JSON.parse(JSON.stringify(config))
  })
}

function setContextMenu (config) {
  chrome.contextMenus.removeAll()

  config.contextMenu.selected.forEach(id => {
    chrome.contextMenus.create({
      id,
      title: chrome.i18n.getMessage('context_' + id),
      contexts: ['selection']
    })
  })

  chrome.contextMenus.create({
    id: 'google_page_translate',
    title: chrome.i18n.getMessage('context_google_page_translate'),
    contexts: ['all']
  })
}

storage.sync.get('config', data => {
  let config = data.config

  if (config) {
    setConfigs(config)
    setContextMenu(config)

    // listen context menu
    chrome.contextMenus.onClicked.addListener(({menuItemId, selectionText, pageUrl}) => {
      if (menuItemId === 'google_page_translate') {
        chrome.tabs.create({url: `https://translate.google.com/translate?sl=auto&tl=zh-CN&js=y&prev=_t&ie=UTF-8&u=${pageUrl}&edit-text=&act=url`})
        return
      }

      let url = config.contextMenu.all[menuItemId]
      if (url) {
        chrome.tabs.create({url: url.replace('%s', selectionText)})
      }
    })
  }
})

storage.listen('config', changes => {
  let config = changes.config.newValue
  if (config) {
    setConfigs(config)
    setContextMenu(config)
  }
})

message.on('FETCH_DICT_RESULT', (data, sender, sendResponse) => {
  let dict = _dicts[data.dict]
  if (!dict) {
    sendResponse({error: 'Missing Dictionary!'})
    return
  }

  function handleSuccess (result) {
    sendResponse({result, dict: data.dict})
  }

  function handleError (error) {
    sendResponse({error, dict: data.dict})
  }

  dict.search(data.text, dict.config)
    .then(handleSuccess, handleError)
    .catch(handleError)

  // keep the channel alive
  return true
})

// merge config on installed
chrome.runtime.onInstalled.addListener(({previousVersion}) => {
  let config = defaultConfig
  let [major, minor, patch] = previousVersion ? previousVersion.split('.').map(n => Number(n)) : [0, 0, 0]
  if (major <= 4) {
    storage.local.clear()
    storage.sync.clear()
      .then(() => {
        storage.sync.set({config})
        setConfigs(config)
      })
  } else if (major === 5) {
    storage.sync.get('config', data => {
      let config = data.config

      if (config) {
        if (minor < 3) {
          // 5.3 added
          config.dicts.all.howjsay = defaultConfig.dicts.all.howjsay
        }
        if (minor < 5) {
          config.dicts.all.eudic = defaultConfig.dicts.all.eudic
        }
      } else {
        config = defaultConfig
      }

      storage.sync.set({config})
      setConfigs(config)
    })
  }
})
<|endoftext|>


<commit_before>
// http://stackoverflow.com/a/4234006
$.ajaxSetup({beforeSend: function(xhr) {
    if (xhr.overrideMimeType)
    {
      xhr.overrideMimeType("application/json");
    }
}
});

var dataDir = "./data/"

var map = new ol.Map({target: 'map'});
var view = new ol.View( {center: [0, 0], zoom: 3, projection: 'EPSG:3857'} );
map.setView(view);

var osmSource = new ol.source.OSM("OpenCycleMap");
//osmSource.setUrl("http://a.tile.opencyclemap.org/transport/{z}/{x}/{y}.png");
//osmSource.setUrl("http://a.tile.openstreetmap.org/{z}/{x}/{y}.png");
osmSource.setUrl("https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png");
//osmSource.setUrl("http://a.tile.stamen.com/toner/{z}/{x}/{y}.png");

var osmLayer = new ol.layer.Tile({source: osmSource});

map.addLayer(osmLayer);

var lon = 360.0;
var lat = 0.0;
view.setCenter(ol.proj.fromLonLat([lon, lat]));

var plotTypesMonthsLayers = {};

addContours('cloud', 1);  // initial contourd of January

function addContours(dateType, monthNr)
{
    $.getJSON(dataDir + "contour_" + dateType + "_" + monthNr + ".json", function(json) {
        var contours = json.contours;
        var contourLayers = createContoursLayer(contours, dateType);
        if ( !(dateType in plotTypesMonthsLayers)) {
            plotTypesMonthsLayers[dateType] = {};
        }
        plotTypesMonthsLayers[dateType][monthNr] = contourLayers;
    });
}

function createContoursLayer(contours, name) {
    console.log('create new contour layers');
    console.log(contours.length + ' contours');
    var contourLayers = [];

    // each contour can have multiple (including zero) paths.
    for (var k = 0; k < contours.length; ++k)
    {
        var paths = contours[k].paths;
        for (var j = 0; j < paths.length; ++j)
        {
            var markers = [];
            for (var i = 0; i < paths[j].x.length; ++i)
            {
                var lon = paths[j].x[i];
                var lat = -paths[j].y[i];
                var lonLat = [lon, lat];
                markers.push(ol.proj.fromLonLat(lonLat));
            }

            var color = [paths[j].linecolor[0]*255, paths[j].linecolor[1]*255, paths[j].linecolor[2]*255, 0.8];
            var lineWidth = 4;

            var lineStyle = new ol.style.Style({
                stroke: new ol.style.Stroke({
                    color: color,
                    width: lineWidth
                })
            });

            var layerLines = new ol.layer.Vector({
                source: new ol.source.Vector({
                    features: [new ol.Feature({
                        geometry: new ol.geom.LineString(markers, 'XY'),
                        name: paths[j].label
                    })]
                }),
                style: lineStyle
            });

            contourLayers.push(layerLines);
            map.addLayer(layerLines);
        }
    }

    return contourLayers;
}

map.addControl(new ol.control.FullScreen());

// Tooltip

var info = $('#info');

var displayFeatureInfo = function(pixel) {
  info.css({
    left: (pixel[0] + 10) + 'px',
    top: (pixel[1] - 50) + 'px'
  });

  var feature = map.forEachFeatureAtPixel(pixel, function(feature, layer) {
    return feature;
  });

  if (feature) {
    info.text(feature.get('name'));
    info.show();
  } else {
    info.hide();
  }
};

map.on('pointermove', function(evt) {
  if (evt.dragging) {
    info.hide();
    return;
  }
  displayFeatureInfo(map.getEventPixel(evt.originalEvent));
});

// Select features

//var select = new ol.interaction.Select({
//    condition: ol.events.condition.click
//});
//
//select.on('select', function(evt) {
//    for (var i = 0; i < contourLayers.length; ++i)
//    {
//        var removedLayer = map.removeLayer(contourLayers[i]);
//    }
//    contourLayers.length = 0;
//    addContours(1);
//});

//map.addInteraction(select);

var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Jan"];

$(function() {
    $("#month-slider").slider({
      orientation: "horizontal",
      range: "min",
      min: 0,
      max: 12,
      value: 0,
      slide: sliderChanged,
      change: sliderChanged
    })
    .slider("pips", {
        rest: "label",
        labels: months
    })
//    .slider("float");
});

var hideAllContours = function() {
    console.log('hide all contours');
    for (type in plotTypesMonthsLayers) {
        for (month in plotTypesMonthsLayers[type]) {
            for (var i = 0; i < plotTypesMonthsLayers[type][month].length; ++i) {
                plotTypesMonthsLayers[type][month][i].setVisible(false);
            }
        }
    }
};

var showOrCreateContour = function(monthNr) {
    console.log("showOrCreateContour");
    hideAllContours();
    var selectedType = getSelectedType();
    if ( !plotExists(selectedType, monthNr) ) {
        addContours(selectedType, monthNr);
    }
    else {
        var monthLayers = plotTypesMonthsLayers[selectedType][monthNr];
        for (var i = 0; i < monthLayers.length; ++i) {
            monthLayers[i].setVisible(true);
        }
    }
};

var sliderChanged = function() {
    var monthNr = $("#month-slider").slider("value") + 1;
    if (monthNr == 13) {
        $("#month-slider").slider("value", 0);
        return;
    }
    console.log("slider changed to: " + monthNr);
    showOrCreateContour(monthNr);
};

var intervalID = 0;

var toggleAnimation = function() {
    var playButton = document.getElementById('animate-button');
    var selectedType = getSelectedType();
    if (playButton.innerHTML == "Animate") {
        for (var i = 1; i < 13; ++i) {
            if ( !plotExists(selectedType, i) ) {
                addContours(selectedType, i);
            };
        };
        playButton.innerHTML = "Stop";
        intervalID = window.setInterval(playAnimation, 800);
    }
    else {
        window.clearInterval(intervalID);
        playButton.innerHTML = "Animate";
    }
};

var stopAnimation = function() {
    window.clearInterval(intervalID);
};

var playAnimation = function() {
    var monthNr = $("#month-slider").slider("value");
    $("#month-slider").slider("value", monthNr+1);
};

document.getElementById("animate-button").onclick = toggleAnimation;

var updateMap = function() {
    hideAllContours();
};

var getSelectedType = function() {
    return document.getElementById("select-type").value;
};

var typeChanged = function() {
//    alert('type changed');
    var selection = getSelectedType()
    console.log(selection);
    sliderChanged();
};

document.getElementById("select-type").onchange = typeChanged;

var plotExists = function(typeName, monthNr) {
    var exists = (typeName in plotTypesMonthsLayers) && (plotTypesMonthsLayers[typeName].hasOwnProperty(monthNr));
    return exists;
};<commit_msg>Scale line width to zoom level<commit_after>
// http://stackoverflow.com/a/4234006
$.ajaxSetup({beforeSend: function(xhr) {
    if (xhr.overrideMimeType)
    {
      xhr.overrideMimeType("application/json");
    }
}
});

var dataDir = "./data/";
var lineScaleFactor = 1.2;

var map = new ol.Map({target: 'map'});
var view = new ol.View( {center: [0, 0], zoom: 3, projection: 'EPSG:3857'} );
map.setView(view);

var osmSource = new ol.source.OSM("OpenCycleMap");
//osmSource.setUrl("http://a.tile.opencyclemap.org/transport/{z}/{x}/{y}.png");
//osmSource.setUrl("http://a.tile.openstreetmap.org/{z}/{x}/{y}.png");
osmSource.setUrl("https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png");
//osmSource.setUrl("http://a.tile.stamen.com/toner/{z}/{x}/{y}.png");

var osmLayer = new ol.layer.Tile({source: osmSource});

map.addLayer(osmLayer);

var lon = 360.0;
var lat = 0.0;
view.setCenter(ol.proj.fromLonLat([lon, lat]));

var plotTypesMonthsLayers = {};

addContours('cloud', 1);  // initial contourd of January

function addContours(dateType, monthNr)
{
    $.getJSON(dataDir + "contour_" + dateType + "_" + monthNr + ".json", function(json) {
        var contours = json.contours;
        var contourLayers = createContoursLayer(contours, dateType);
        if ( !(dateType in plotTypesMonthsLayers)) {
            plotTypesMonthsLayers[dateType] = {};
        }
        plotTypesMonthsLayers[dateType][monthNr] = contourLayers;
    });
}

var getWidth = function() {
    //I am setting attribute widthInMeters to each feature, and I am using that
    //for a calculation of line width, where 1m = 100px
    var r = map.getResolution() * 10000000;
    return 6;
};

function createContoursLayer(contours, name) {
    console.log('create new contour layers');
    console.log(contours.length + ' contours');
    var contourLayers = [];

    // each contour can have multiple (including zero) paths.
    for (var k = 0; k < contours.length; ++k)
    {
        var paths = contours[k].paths;
        for (var j = 0; j < paths.length; ++j)
        {
            var markers = [];
            for (var i = 0; i < paths[j].x.length; ++i)
            {
                var lon = paths[j].x[i];
                var lat = -paths[j].y[i];
                var lonLat = [lon, lat];
                markers.push(ol.proj.fromLonLat(lonLat));
            }

            var color = [paths[j].linecolor[0]*255, paths[j].linecolor[1]*255, paths[j].linecolor[2]*255, 1];

            var lineStyle = new ol.style.Style({
                stroke: new ol.style.Stroke({
                    color: color,
                    width: view.getZoom() * lineScaleFactor
                })
            });

            var layerLines = new ol.layer.Vector({
                source: new ol.source.Vector({
                    features: [new ol.Feature({
                        geometry: new ol.geom.LineString(markers, 'XY'),
                        name: paths[j].label
                    })]
                }),
                style: lineStyle
            });

            contourLayers.push(layerLines);
            map.addLayer(layerLines);
        }
    }

    return contourLayers;
}

map.addControl(new ol.control.FullScreen());

// Tooltip

var info = $('#info');

var displayFeatureInfo = function(pixel) {
  info.css({
    left: (pixel[0] + 10) + 'px',
    top: (pixel[1] - 50) + 'px'
  });

  var feature = map.forEachFeatureAtPixel(pixel, function(feature, layer) {
    return feature;
  });

  if (feature) {
    info.text(feature.get('name'));
    info.show();
  } else {
    info.hide();
  }
};

map.on('pointermove', function(evt) {
  if (evt.dragging) {
    info.hide();
    return;
  }
  displayFeatureInfo(map.getEventPixel(evt.originalEvent));
});

// Select features

//var select = new ol.interaction.Select({
//    condition: ol.events.condition.click
//});
//
//select.on('select', function(evt) {
//    for (var i = 0; i < contourLayers.length; ++i)
//    {
//        var removedLayer = map.removeLayer(contourLayers[i]);
//    }
//    contourLayers.length = 0;
//    addContours(1);
//});

//map.addInteraction(select);

var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Jan"];

$(function() {
    $("#month-slider").slider({
      orientation: "horizontal",
      range: "min",
      min: 0,
      max: 12,
      value: 0,
      slide: sliderChanged,
      change: sliderChanged
    })
    .slider("pips", {
        rest: "label",
        labels: months
    })
//    .slider("float");
});

var hideAllContours = function() {
    console.log('hide all contours');
    for (type in plotTypesMonthsLayers) {
        for (month in plotTypesMonthsLayers[type]) {
            for (var i = 0; i < plotTypesMonthsLayers[type][month].length; ++i) {
                plotTypesMonthsLayers[type][month][i].setVisible(false);
            }
        }
    }
};

var showOrCreateContour = function(monthNr) {
    console.log("showOrCreateContour");
    hideAllContours();
    var selectedType = getSelectedType();
    if ( !plotExists(selectedType, monthNr) ) {
        addContours(selectedType, monthNr);
    }
    else {
        var monthLayers = plotTypesMonthsLayers[selectedType][monthNr];
        for (var i = 0; i < monthLayers.length; ++i) {
            monthLayers[i].setVisible(true);
        }
    }
};

var sliderChanged = function() {
    var monthNr = $("#month-slider").slider("value") + 1;
    if (monthNr == 13) {
        $("#month-slider").slider("value", 0);
        return;
    }
    console.log("slider changed to: " + monthNr);
    showOrCreateContour(monthNr);
};

var intervalID = 0;

var toggleAnimation = function() {
    var playButton = document.getElementById('animate-button');
    var selectedType = getSelectedType();
    if (playButton.innerHTML == "Animate") {
        for (var i = 1; i < 13; ++i) {
            if ( !plotExists(selectedType, i) ) {
                addContours(selectedType, i);
            };
        };
        playButton.innerHTML = "Stop";
        intervalID = window.setInterval(playAnimation, 800);
    }
    else {
        window.clearInterval(intervalID);
        playButton.innerHTML = "Animate";
    }
};

var stopAnimation = function() {
    window.clearInterval(intervalID);
};

var playAnimation = function() {
    var monthNr = $("#month-slider").slider("value");
    $("#month-slider").slider("value", monthNr+1);
};

document.getElementById("animate-button").onclick = toggleAnimation;

var updateMap = function() {
    hideAllContours();
};

var getSelectedType = function() {
    return document.getElementById("select-type").value;
};

var typeChanged = function() {
//    alert('type changed');
    var selection = getSelectedType()
    console.log(selection);
    sliderChanged();
};

document.getElementById("select-type").onchange = typeChanged;

var plotExists = function(typeName, monthNr) {
    var exists = (typeName in plotTypesMonthsLayers) && (plotTypesMonthsLayers[typeName].hasOwnProperty(monthNr));
    return exists;
};

map.on("moveend", function() {
    for (type in plotTypesMonthsLayers) {
        for (month in plotTypesMonthsLayers[type]) {
            for (var i = 0; i < plotTypesMonthsLayers[type][month].length; ++i) {
                var oldStyle = plotTypesMonthsLayers[type][month][i].getStyle();
                oldStyle.getStroke().setWidth(view.getZoom() * lineScaleFactor);
                plotTypesMonthsLayers[type][month][i].setStyle(oldStyle);
            }
        }
    }
});<|endoftext|>


<commit_before>(function(){
	/**
	 * Object Pie()
	 * Defines Pie
	 * @param {Object} config
	 * @param {Object} [config.name] pie name
	 * @param {Object} [config.radius] pie radius in pixel
	 * @param {Object} [config.nature] pie projection nature, User or Device
	 * @param {Object} [config.x] pie center x, depends on projection nature
	 * @param {Object} [config.y] pie center y, depends on projection nature
	 * @param {Object} [config.startAngleDegree] pie center y, depends on projection nature
	 *
	 */
	JenScript.Pie = function(config){
		config = config||{};
		this.name = (config.name !== undefined)?config.name:'Pie name undefined';
		this.Id = 'pie'+JenScript.sequenceId++;
		this.x =  (config.x !== undefined)?config.x:0;
		this.y =  (config.y !== undefined)?config.y:0;
		this.radius =  (config.radius !== undefined)?config.radius:80;
		this.startAngleDegree =  (config.startAngleDegree !== undefined)?config.startAngleDegree:0;
		this.nature =  (config.nature !== undefined)?config.nature:'User';
		this.effects= [];
		this.slices = [];
		this.svg={};
	};
	JenScript.Model.addMethods(JenScript.Pie,{

		/**
		 * set pie center x
		 * @param {Number} pie center x
		 */
		setX : function(x) {
			this.x = x;
			this.plugin.repaintPlugin();
		},

		/**
		 * get pie center x
		 * @returns {Number} get pie center x
		 */
		getX : function() {
			return this.x;
		},

		/**
		 * set pie center y
		 * @param {Number} pie center y
		 */
		setY : function(y) {
			this.y = y;
			this.plugin.repaintPlugin();
		},

		/**
		 * get pie center y
		 * @returns {Number} get pie center y
		 */
		getY : function() {
			return this.y;
		},

		/**
		 * set pie radius in pixel
		 * @param {Number} pie radius
		 */
		setRadius : function(radius) {
			this.radius = radius;
			this.plugin.repaintPlugin();
		},

		/**
		 * get pie radius in pixel
		 * @returns {Number} get pie radius
		 */
		getRadius : function() {
			return this.radius;
		},

		/**
		 * set pie projection nature, user or Device
		 * @param {String} projection nature to set
		 */
		setNature : function(nature) {
			this.nature = nature;
			this.plugin.repaintPlugin();
		},

		/**
		 * get pie projection nature, user or Device
		 * @returns {String} get projection nature
		 */
		getNature : function() {
			return this.nature;
		},

		/**
		 * set pie start angle degreee
		 * @param {Number} start angle degree to set
		 */
		setStartAngleDegree : function(startAngleDegree) {
			this.startAngleDegree = startAngleDegree;
			this.plugin.repaintPlugin();
		},

		/**
		 * set pie start angle degreee
		 * @returns {Number} ge start angle degree
		 */
		getStartAngleDegree : function() {
			return this.startAngleDegree;
		},

		/**
		 * add pie effect
		 * @param {Object} effect to add
		 */
		addEffect : function(effect) {
			this.effects[this.effects.length] = effect;
			this.plugin.repaintPlugin();
		},

		/**
		 * set pie stroke
		 * @param {Object} stroke to set
		 */
		setStroke : function(stroke) {
			this.stroke = stroke;
			this.plugin.repaintPlugin();
		},

		/**
		 * set pie fill
		 * @param {Object} fill to set
		 */
		setFill : function(fill) {
			this.fill = fill;
			this.plugin.repaintPlugin();
		},

		/**
		 * add slice in this pie
		 * @param {Object} slice
		 */
		addSlice : function(slice) {
			slice.pie = this;
			this.slices[this.slices.length] = slice;
			this.plugin.repaintPlugin();
		},

		/**
		 * generate a slice with given config, add in pie and return pie.
		 */
		slice : function(config){
			var s = new JenScript.PieSlice(config);
			this.addSlice(s);
			return this;
		},

		/**
		 * build slice
		 * @param {Object} slice The slice to build
		 *
		 */
		buildSlice : function(slice) {

			var deltaDegree = slice.getRatio() * 360;
			slice.extendsDegree = deltaDegree;

			if (this.startAngleDegree > 360)
				this.startAngleDegree = this.startAngleDegree - 360;

			slice.startAngleDegree = this.startAngleDegree;
			slice.endAngleDegree = this.startAngleDegree+deltaDegree;
			var medianDegree = this.startAngleDegree + deltaDegree/2;
			if (medianDegree > 360)
				medianDegree = medianDegree - 360;

			slice.medianDegree = medianDegree;

			var polar = function(origin,radius,angle){
				return {
					x : origin.x + radius* Math.cos(JenScript.Math.toRadians(angle)),
					y : origin.y - radius* Math.sin(JenScript.Math.toRadians(angle))
				};
			};
			var sc = polar(this.buildCenter,slice.divergence,medianDegree);
			var ss = polar(sc,this.radius,slice.startAngleDegree);
			var se = polar(sc,this.radius,slice.endAngleDegree);
			slice.sc = sc;
			slice.ss = ss;
			slice.se = se;

			var largeArcFlag = "0";
			if (deltaDegree > 180) {
				largeArcFlag = "1";
			}

			slice.svgPath = "M" + ss.x + "," + ss.y + " A" + this.radius + ","
					+ this.radius + " 0 " + largeArcFlag + ",0 " + se.x + ","
					+ se.y + " L" + sc.x + "," + sc.y + " Z";

			this.startAngleDegree = this.startAngleDegree + deltaDegree;
		},

		 /**
	     * compute buildCenterX and buildCenterY with given projection nature
	     */
	    projection : function() {
	        if (this.nature == 'User') {
	            var projectedCenter = this.plugin.getProjection().userToPixel(new JenScript.Point2D(this.x,this.y));
	            this.buildCenterX = projectedCenter.x;
	            this.buildCenterY = projectedCenter.y;
	            this.buildCenter = new JenScript.Point2D(this.buildCenterX,this.buildCenterY);
	        }
	        else  if (this.nature == 'Device') {
	            this.buildCenterX = this.centerX;
	            this.buildCenterY = this.centerY;
	            this.buildCenter = new JenScript.Point2D(this.buildCenterX,this.buildCenterY);
	        }
	    },

		/**
		 * build pie by slice normlization, center projection and build slices geometry
		 */
		solvePie : function() {
			var that = this;
			var normalization = (function(){
				var sum = 0;
		        for (var i = 0; i < that.slices.length; i++) {
		            var s = that.slices[i];
		            sum = sum + s.value;
		        }
		        for (var i = 0; i < that.slices.length; i++) {
		        	var s = that.slices[i];
		            var ratio = s.value / sum;
		            s.ratio=ratio;
		        }
			})();
			this.projection();
			for (var i = 0; i < this.slices.length; i++) {
				var s = this.slices[i];
				this.buildSlice(s);
			}
		},

		/**
		 * true if pie has more one slice, false otherwise
		 * @returns true if pie has more one slice, false otherwise
		 */
		isSolvable : function(){
		    	return this.slices.length > 0;
		},

		/**
		 * shift pie
		 */
		shift : function(){
			var that = this;
			for (var i = 0; i < 10; i++) {
				shiftAngle(i);
			}
			function shiftAngle(i){
				setTimeout(function(){
					that.startAngleDegree=that.startAngleDegree+36;
					that.plugin.repaintPlugin();
				},i*100);
			}
		},

	});
})();<commit_msg>add pie slice array prototype <commit_after>(function(){
	/**
	 * Object Pie()
	 * Defines Pie
	 * @param {Object} config
	 * @param {Object} [config.name] pie name
	 * @param {Object} [config.radius] pie radius in pixel
	 * @param {Object} [config.nature] pie projection nature, User or Device
	 * @param {Object} [config.x] pie center x, depends on projection nature
	 * @param {Object} [config.y] pie center y, depends on projection nature
	 * @param {Object} [config.startAngleDegree] pie center y, depends on projection nature
	 *
	 */
	JenScript.Pie = function(config){
		config = config||{};
		this.name = (config.name !== undefined)?config.name:'Pie name undefined';
		this.Id = 'pie'+JenScript.sequenceId++;
		this.x =  (config.x !== undefined)?config.x:0;
		this.y =  (config.y !== undefined)?config.y:0;
		this.radius =  (config.radius !== undefined)?config.radius:80;
		this.startAngleDegree =  (config.startAngleDegree !== undefined)?config.startAngleDegree:0;
		this.nature =  (config.nature !== undefined)?config.nature:'User';
		this.effects= [];
		this.slices = [];
		this.svg={};
	};
	JenScript.Model.addMethods(JenScript.Pie,{

		/**
		 * set pie center x
		 * @param {Number} pie center x
		 */
		setX : function(x) {
			this.x = x;
			this.plugin.repaintPlugin();
		},

		/**
		 * get pie center x
		 * @returns {Number} get pie center x
		 */
		getX : function() {
			return this.x;
		},

		/**
		 * set pie center y
		 * @param {Number} pie center y
		 */
		setY : function(y) {
			this.y = y;
			this.plugin.repaintPlugin();
		},

		/**
		 * get pie center y
		 * @returns {Number} get pie center y
		 */
		getY : function() {
			return this.y;
		},

		/**
		 * set pie radius in pixel
		 * @param {Number} pie radius
		 */
		setRadius : function(radius) {
			this.radius = radius;
			this.plugin.repaintPlugin();
		},

		/**
		 * get pie radius in pixel
		 * @returns {Number} get pie radius
		 */
		getRadius : function() {
			return this.radius;
		},

		/**
		 * set pie projection nature, user or Device
		 * @param {String} projection nature to set
		 */
		setNature : function(nature) {
			this.nature = nature;
			this.plugin.repaintPlugin();
		},

		/**
		 * get pie projection nature, user or Device
		 * @returns {String} get projection nature
		 */
		getNature : function() {
			return this.nature;
		},

		/**
		 * set pie start angle degreee
		 * @param {Number} start angle degree to set
		 */
		setStartAngleDegree : function(startAngleDegree) {
			this.startAngleDegree = startAngleDegree;
			this.plugin.repaintPlugin();
		},

		/**
		 * set pie start angle degreee
		 * @returns {Number} ge start angle degree
		 */
		getStartAngleDegree : function() {
			return this.startAngleDegree;
		},

		/**
		 * add pie effect
		 * @param {Object} effect to add
		 */
		addEffect : function(effect) {
			this.effects[this.effects.length] = effect;
			this.plugin.repaintPlugin();
		},

		/**
		 * set pie stroke
		 * @param {Object} stroke to set
		 */
		setStroke : function(stroke) {
			this.stroke = stroke;
			this.plugin.repaintPlugin();
		},

		/**
		 * set pie fill
		 * @param {Object} fill to set
		 */
		setFill : function(fill) {
			this.fill = fill;
			this.plugin.repaintPlugin();
		},

		/**
		 * add slice in this pie
		 * @param {Object} slice
		 */
		addSlice : function(slice) {
			slice.pie = this;
			this.slices[this.slices.length] = slice;
			this.plugin.repaintPlugin();
			return this;
		},

		/**
		 * generate a slice with given config, add in pie and return pie.
		 */
		slice : function(config){
			var s = new JenScript.PieSlice(config);
			this.addSlice(s);
			return this;
		},

		 /**
		  * add slices array in this pie
		  * @param {Object} slice
		  */
		 addSlices : function (slices) {
	       for (var s = 0; s < slices.length; s++) {
	    	   this.addSlice(slices[s]);
	       }
	       return this;
		 },

		/**
		 * build slice
		 * @param {Object} slice The slice to build
		 *
		 */
		buildSlice : function(slice) {

			var deltaDegree = slice.getRatio() * 360;
			slice.extendsDegree = deltaDegree;

			if (this.startAngleDegree > 360)
				this.startAngleDegree = this.startAngleDegree - 360;

			slice.startAngleDegree = this.startAngleDegree;
			slice.endAngleDegree = this.startAngleDegree+deltaDegree;
			var medianDegree = this.startAngleDegree + deltaDegree/2;
			if (medianDegree > 360)
				medianDegree = medianDegree - 360;

			slice.medianDegree = medianDegree;

			var polar = function(origin,radius,angle){
				return {
					x : origin.x + radius* Math.cos(JenScript.Math.toRadians(angle)),
					y : origin.y - radius* Math.sin(JenScript.Math.toRadians(angle))
				};
			};
			var sc = polar(this.buildCenter,slice.divergence,medianDegree);
			var ss = polar(sc,this.radius,slice.startAngleDegree);
			var se = polar(sc,this.radius,slice.endAngleDegree);
			slice.sc = sc;
			slice.ss = ss;
			slice.se = se;

			var largeArcFlag = "0";
			if (deltaDegree > 180) {
				largeArcFlag = "1";
			}

			slice.svgPath = "M" + ss.x + "," + ss.y + " A" + this.radius + ","
					+ this.radius + " 0 " + largeArcFlag + ",0 " + se.x + ","
					+ se.y + " L" + sc.x + "," + sc.y + " Z";

			this.startAngleDegree = this.startAngleDegree + deltaDegree;
		},

		 /**
	     * compute buildCenterX and buildCenterY with given projection nature
	     */
	    projection : function() {
	        if (this.nature == 'User') {
	            var projectedCenter = this.plugin.getProjection().userToPixel(new JenScript.Point2D(this.x,this.y));
	            this.buildCenterX = projectedCenter.x;
	            this.buildCenterY = projectedCenter.y;
	            this.buildCenter = new JenScript.Point2D(this.buildCenterX,this.buildCenterY);
	        }
	        else  if (this.nature == 'Device') {
	            this.buildCenterX = this.centerX;
	            this.buildCenterY = this.centerY;
	            this.buildCenter = new JenScript.Point2D(this.buildCenterX,this.buildCenterY);
	        }
	    },

		/**
		 * build pie by slice normlization, center projection and build slices geometry
		 */
		solvePie : function() {
			var that = this;
			var normalization = (function(){
				var sum = 0;
		        for (var i = 0; i < that.slices.length; i++) {
		            var s = that.slices[i];
		            sum = sum + s.value;
		        }
		        for (var i = 0; i < that.slices.length; i++) {
		        	var s = that.slices[i];
		            var ratio = s.value / sum;
		            s.ratio=ratio;
		        }
			})();
			this.projection();
			for (var i = 0; i < this.slices.length; i++) {
				var s = this.slices[i];
				this.buildSlice(s);
			}
		},

		/**
		 * true if pie has more one slice, false otherwise
		 * @returns true if pie has more one slice, false otherwise
		 */
		isSolvable : function(){
		    	return this.slices.length > 0;
		},

		/**
		 * shift pie
		 */
		shift : function(){
			var that = this;
			for (var i = 0; i < 10; i++) {
				shiftAngle(i);
			}
			function shiftAngle(i){
				setTimeout(function(){
					that.startAngleDegree=that.startAngleDegree+36;
					that.plugin.repaintPlugin();
				},i*100);
			}
		},

	});
})();<|endoftext|>


<commit_before>// A "this works for now" way to process/format new background
// images.
// To use: node optimize-images.js ~/folder-with-photos/

/* eslint import/no-extraneous-dependencies: 0 */
const fs = require('fs')
const path = require('path')
const sharp = require('sharp')
const uuid = require('uuid').v4

// Expect one argument, the input directory.
const args = process.argv.slice(2)
const dirRaw = args[0]
if (!dirRaw) {
  throw new Error('The first argument should be the images directory.')
}
const dir = path.resolve(dirRaw)
const outDir = path.join(dir, '../', `${path.basename(dir)}-edited`)
const processTime = new Date().toISOString()

// https://github.com/lovell/sharp
const formatImg = async (imgFilePath, newFileName) => {
  console.log(`Formatting image: ${imgFilePath}`)
  const newImgWidth = 2000

  // Resizing:
  // https://sharp.pixelplumbing.com/api-resize#resize
  // JPEG options:
  // https://sharp.pixelplumbing.com/api-output#jpeg
  const newFilePath = path.join(outDir, newFileName)

  console.log(`Saving as: ${newFilePath}`)

  await sharp(imgFilePath)
    .resize({
      width: newImgWidth,
    })
    .jpeg()
    .toFile(newFilePath)
}

// Takes a file, saves a new image, returns a fixture.
const processImage = async fileName => {
  const id = uuid()
  const newFileName = `${id}.jpg`
  await formatImg(path.join(dir, fileName), newFileName)
  return {
    id,
    image: newFileName,
    created: processTime,
    updated: processTime,
  }
}

const processImages = async () => {
  if (!fs.existsSync(outDir)) {
    fs.mkdirSync(outDir)
  }

  const files = await fs.promises.readdir(dir)
  const fixtures = await Promise.all(
    files.map(fileName => processImage(fileName))
  )

  // Save the fixtures to file.
  fs.writeFileSync(
    path.join(outDir, 'fixtures.json'),
    JSON.stringify(fixtures, null, 4),
    'utf8'
  )
}

const main = () => {
  console.log(`Starting image optimization for images in directory: ${dir}`)
  console.log(`Will save to: ${outDir}`)
  processImages()
}

main()
<commit_msg>Add category<commit_after>// A "this works for now" way to process/format new background
// images. The category is hardcoded.
// To use: node optimize-images.js ~/folder-with-photos/

/* eslint import/no-extraneous-dependencies: 0 */
const fs = require('fs')
const path = require('path')
const sharp = require('sharp')
const uuid = require('uuid').v4

// Expect one argument, the input directory.
const args = process.argv.slice(2)
const dirRaw = args[0]
if (!dirRaw) {
  throw new Error('The first argument should be the images directory.')
}
const dir = path.resolve(dirRaw)
const outDir = path.join(dir, '../', `${path.basename(dir)}-edited`)
const processTime = new Date().toISOString()

// https://github.com/lovell/sharp
const formatImg = async (imgFilePath, newFileName) => {
  console.log(`Formatting image: ${imgFilePath}`)
  const newImgWidth = 2000

  // Resizing:
  // https://sharp.pixelplumbing.com/api-resize#resize
  // JPEG options:
  // https://sharp.pixelplumbing.com/api-output#jpeg
  const newFilePath = path.join(outDir, newFileName)

  console.log(`Saving as: ${newFilePath}`)

  await sharp(imgFilePath)
    .resize({
      width: newImgWidth,
    })
    .jpeg()
    .toFile(newFilePath)
}

// Takes a file, saves a new image, returns a fixture.
const processImage = async fileName => {
  const id = uuid()
  const newFileName = `${id}.jpg`
  await formatImg(path.join(dir, fileName), newFileName)
  return {
    id,
    image: newFileName,
    category: 'cats', // change or add input var as needed
    created: processTime,
    updated: processTime,
  }
}

const processImages = async () => {
  if (!fs.existsSync(outDir)) {
    fs.mkdirSync(outDir)
  }

  const files = await fs.promises.readdir(dir)
  const fixtures = await Promise.all(
    files.map(fileName => processImage(fileName))
  )

  // Save the fixtures to file.
  fs.writeFileSync(
    path.join(outDir, 'fixtures.json'),
    JSON.stringify(fixtures, null, 4),
    'utf8'
  )
}

const main = () => {
  console.log(`Starting image optimization for images in directory: ${dir}`)
  console.log(`Will save to: ${outDir}`)
  processImages()
}

main()
<|endoftext|>


<commit_before>import _ from 'lodash'
import postcss from 'postcss'

import substituteTailwindAtRules from './lib/substituteTailwindAtRules'
import evaluateTailwindFunctions from './lib/evaluateTailwindFunctions'
import substituteVariantsAtRules from './lib/substituteVariantsAtRules'
import substituteResponsiveAtRules from './lib/substituteResponsiveAtRules'
import convertLayerAtRulesToControlComments from './lib/convertLayerAtRulesToControlComments'
import substituteScreenAtRules from './lib/substituteScreenAtRules'
import substituteClassApplyAtRules from './lib/substituteClassApplyAtRules'
import applyImportantConfiguration from './lib/applyImportantConfiguration'
import purgeUnusedStyles from './lib/purgeUnusedStyles'

import corePlugins from './corePlugins'
import processPlugins from './util/processPlugins'
import cloneNodes from './util/cloneNodes'
import { issueFlagNotices, flagEnabled } from './featureFlags.js'

import darkModeVariantPlugin from './flagged/darkModeVariantPlugin'

import hash from 'object-hash'

let previousConfig = null
let processedPlugins = null
let getProcessedPlugins = null

export default function(getConfig) {
  return function(css) {
    const config = getConfig()
    const configChanged = hash(previousConfig) !== hash(config)
    previousConfig = config

    if (configChanged) {
      issueFlagNotices(config)

      processedPlugins = processPlugins(
        [
          ...corePlugins(config),
          ...[flagEnabled(config, 'darkModeVariant') ? darkModeVariantPlugin : () => {}],
          ..._.get(config, 'plugins', []),
        ],
        config
      )

      getProcessedPlugins = function() {
        return {
          ...processedPlugins,
          base: cloneNodes(processedPlugins.base),
          components: cloneNodes(processedPlugins.components),
          utilities: cloneNodes(processedPlugins.utilities),
        }
      }
    }

    return postcss([
      substituteTailwindAtRules(config, getProcessedPlugins()),
      evaluateTailwindFunctions(config),
      substituteVariantsAtRules(config, getProcessedPlugins()),
      substituteResponsiveAtRules(config),
      convertLayerAtRulesToControlComments(config),
      substituteScreenAtRules(config),
      substituteClassApplyAtRules(config, getProcessedPlugins, configChanged),
      applyImportantConfiguration(config),
      purgeUnusedStyles(config, configChanged),
    ]).process(css, { from: _.get(css, 'source.input.file') })
  }
}
<commit_msg>Warn users who still have `target` in their config file<commit_after>import _ from 'lodash'
import postcss from 'postcss'

import substituteTailwindAtRules from './lib/substituteTailwindAtRules'
import evaluateTailwindFunctions from './lib/evaluateTailwindFunctions'
import substituteVariantsAtRules from './lib/substituteVariantsAtRules'
import substituteResponsiveAtRules from './lib/substituteResponsiveAtRules'
import convertLayerAtRulesToControlComments from './lib/convertLayerAtRulesToControlComments'
import substituteScreenAtRules from './lib/substituteScreenAtRules'
import substituteClassApplyAtRules from './lib/substituteClassApplyAtRules'
import applyImportantConfiguration from './lib/applyImportantConfiguration'
import purgeUnusedStyles from './lib/purgeUnusedStyles'

import corePlugins from './corePlugins'
import processPlugins from './util/processPlugins'
import cloneNodes from './util/cloneNodes'
import { issueFlagNotices, flagEnabled } from './featureFlags.js'

import darkModeVariantPlugin from './flagged/darkModeVariantPlugin'

import hash from 'object-hash'
import log from './util/log'

let previousConfig = null
let processedPlugins = null
let getProcessedPlugins = null

export default function(getConfig) {
  return function(css) {
    const config = getConfig()
    const configChanged = hash(previousConfig) !== hash(config)
    previousConfig = config

    if (configChanged) {
      if (config.target) {
        log.warn([
          'The `target` feature has been removed in Tailwind CSS v2.0.',
          'Please remove this option from your config file to silence this warning.',
        ])
      }

      issueFlagNotices(config)

      processedPlugins = processPlugins(
        [
          ...corePlugins(config),
          ...[flagEnabled(config, 'darkModeVariant') ? darkModeVariantPlugin : () => {}],
          ..._.get(config, 'plugins', []),
        ],
        config
      )

      getProcessedPlugins = function() {
        return {
          ...processedPlugins,
          base: cloneNodes(processedPlugins.base),
          components: cloneNodes(processedPlugins.components),
          utilities: cloneNodes(processedPlugins.utilities),
        }
      }
    }

    return postcss([
      substituteTailwindAtRules(config, getProcessedPlugins()),
      evaluateTailwindFunctions(config),
      substituteVariantsAtRules(config, getProcessedPlugins()),
      substituteResponsiveAtRules(config),
      convertLayerAtRulesToControlComments(config),
      substituteScreenAtRules(config),
      substituteClassApplyAtRules(config, getProcessedPlugins, configChanged),
      applyImportantConfiguration(config),
      purgeUnusedStyles(config, configChanged),
    ]).process(css, { from: _.get(css, 'source.input.file') })
  }
}
<|endoftext|>