<commit_before>///<reference path="jquery-1.6.2-vsdoc.js"/>
///<reference path="Order.js"/>

//Self-Executing Anonymous Function
//Adding New Functionality to Purchasing for Edit
(function (purchasing, $, undefined) {
    //Private Property
    var routingAdjusted = false;
    var startingLineItemCount = 3;
    var startingOrderSplitCount = 3; //TODO: move these into a public var?  or options or something?  Statics maybe?
    var startingLineItemSplitCount = 2;
    var lineItemAndSplitSections = "#line-items-section, #order-split-section, #order-account-section";

    //Public Method
    purchasing.initEdit = function () {
        loadLineItemsAndSplits({ disableModification: false }); //TODO: better name?
        attachModificationEvents();
    };

    //Public Method
    purchasing.initCopy = function () {
        loadLineItemsAndSplits({ disableModification: false }); //TODO: decide if we want to load splits
    };

    function attachModificationEvents() {
        $("#item-modification-template").tmpl({}).insertBefore("#line-items-section");

        purchasing.updateNav(); //Update navigation now that we inserted a new section

        $("#item-modification-button").click(function (e, data) {
            e.preventDefault();

            var automate = data === undefined ? false : data.automate;

            if (!automate && !confirm("Enabling line item and account modification will necessitate recalculating approvals once this order edit is submitted. [Details]")) {
                return;
            }

            enableLineItemAndSplitModification();
        });

    }

    function loadLineItemsAndSplits(options) {
        //Place a 'loading line items' ui block
        $.getJSON(purchasing._getOption("GetLineItemsAndSplitsUrl"), null, function (result) {
            console.log(result);
            purchasing.splitType = result.splitType;
            var newLineItemsNeeded = result.lineItems.length - startingLineItemCount;

            if (newLineItemsNeeded > 0) { //Add the number of new line items needed so we have enough
                for (var j = 0; j < newLineItemsNeeded; j++) {
                    $("#add-line-item").trigger('createline');
                }
            }

            var isLineItemSplit = purchasing.splitType === "Line";

            if (isLineItemSplit) {
                $("#split-by-line").trigger('click', { automate: true });
            } else {
                createSplits(result);
            }

            //TODO: do this with the unserialize plugin??
            //Go through each line item and bind it to the ui
            for (var i = 0; i < result.lineItems.length; i++) {
                var prefix = "items[" + i + "].";

                for (var prop in result.lineItems[i]) {
                    var inputName = prefix + purchasing.lowerCaseFirstLetter(prop);

                    $(document.getElementsByName(inputName)).val(result.lineItems[i][prop]);
                }

                if (isLineItemSplit) bindLineItemSplits(result, i);
            }

            //Show the line details if any sub inputs have a value
            $(".line-item-details").has(".sub-line-item :input[value]").show();

            lineItemsAndSplitLoadingComplete(options);
        });
    }

    function lineItemsAndSplitLoadingComplete(options) {
        purchasing.calculateSubTotal(); //TODO: maybe move these somewhere better? or refactor the get method? or use defer/await?
        purchasing.calculateGrandTotal();

        //TODO: do we want to bother with this, making percentages appear?
        //TODO: is it worth rewriting the percent generation logic to avoid recalculation?
        $(".order-split-account-amount, .line-item-split-account-amount").filter(function (el) {
            return this.value !== ''; //return the ones with actual values
        }).trigger("change");

        if (options.disableModification) {
            disableLineItemAndSplitModification();
        }
    }

    function disableLineItemAndSplitModification() {
        routingAdjusted = false;
        $(":input", lineItemAndSplitSections).attr("disabled", "disabled");
        $("a.button", lineItemAndSplitSections).hide(); //TODO: better way to disable the buttons?
    }

    function enableLineItemAndSplitModification() {
        routingAdjusted = true;
        $(":input", lineItemAndSplitSections).removeAttr("disabled");
        $("a.button", lineItemAndSplitSections).show();
        $("#adjustRouting").val("true");
        $("#item-modification-section").hide();
        purchasing.setSplitType(purchasing.splitType, true);
    }

    //Create splits for order splits and no split cases
    function createSplits(data) {
        if (data.splitType === "Order") {
            $("#split-order").trigger('click', { automate: true });

            var newSplitsNeeded = data.splits.length - startingOrderSplitCount;

            if (newSplitsNeeded > 0) {
                for (var j = 0; j < newSplitsNeeded; j++) {
                    $("#add-order-split").trigger('createsplit');
                }
            }

            bindOrderSplits(data);
        }
        else if (data.splitType === "None") {
            bindSplitlessOrder(data);
        }
    }

    function bindLineItemSplits(data, index) {
        var splitsForThisLine = $.map(data.splits, function (val) {
            return val.LineItemId === data.lineItems[index]["Id"] ? val : null;
        });

        var numNewSplitsNeeded = splitsForThisLine.length - startingLineItemSplitCount;

        if (numNewSplitsNeeded > 0) { //Add the number of splits to this line item so we have enough
            var splitButton = $(".sub-line-item-split-body[data-line-item-index='" + index + "']").next().find(".add-line-item-split");

            for (var k = 0; k < numNewSplitsNeeded; k++) {
                splitButton.trigger('createsplit');
            }
        }

        //Now bind all of the splits for this line
        bindLineItemSplitData(index, data.lineItems[index], splitsForThisLine);
    }

    function bindLineItemSplitData(rowIndex, line, splits) {
        console.log(rowIndex);

        var splitsToBind = $(".sub-line-item-split-body[data-line-item-index='" + rowIndex + "'] > tr");

        console.log("splitsToBind", splitsToBind);

        splitsToBind.each(function (index, row) {
            var $splitRow = $(row);

            if (splits[index] === undefined) return; //here we'll have an empty account

            console.log("splits for " + splits[index].LineItemId, splits[index]);

            var $splitAccountSelect = $splitRow.find("select.account-number");
            var lineItemId = splits[index].LineItemId;
            var account = splits[index].Account;
            var subAccount = splits[index].SubAccount;
            var amount = splits[index].Amount;

            if (!purchasing.selectListContainsValue($splitAccountSelect, account)) {
                //Add the account to the list if it is not already in the select
                $("#select-option-template").tmpl({ id: account, name: account }).appendTo($splitAccountSelect);
            }

            $splitAccountSelect.val(account);

            $splitRow.find("input.account-projectcode").val(splits[index].Project);
            $splitRow.find("input.line-item-split-account-amount").val(amount);
            $splitRow.find("input.line-item-split-item-id").val(lineItemId);

            if (subAccount != null) {
                var $splitSubAccountSelect = $splitRow.find("select.account-subaccount");
                loadSubAccountsAndBind(account, subAccount, $splitSubAccountSelect);
            }
        });
    }

    function bindSplitlessOrder(data) {
        var singleSplit = data.splits[0];

        if (singleSplit.Account !== null) {//we have account info, bind
            var $accountSelect = $("select.account-number");

            if (!purchasing.selectListContainsValue($accountSelect, singleSplit.Account)) {
                //Add the account to the list if it is not already in the select
                $("#select-option-template").tmpl({ id: singleSplit.Account, name: singleSplit.Account }).appendTo($accountSelect);
            }

            $accountSelect.val(singleSplit.Account);
            $("input.account-projectcode").val(singleSplit.Project);

            if (singleSplit.SubAccount != null) {
                var $subAccountSelect = $("select.account-subaccount");
                loadSubAccountsAndBind(singleSplit.Account, singleSplit.SubAccount, $subAccountSelect);
            }
        }
    }

    function bindOrderSplits(data) {
        for (var i = 0; i < data.splits.length; i++) {
            var splitPrefix = "splits[" + i + "].";
            var $splitAccountSelect = $("select.account-number").filter("[name='" + splitPrefix + "Account']");
            var account = data.splits[i].Account;
            var subAccount = data.splits[i].SubAccount;
            var amount = data.splits[i].Amount;

            if (!purchasing.selectListContainsValue($splitAccountSelect, account)) {
                //Add the account to the list if it is not already in the select
                $("#select-option-template").tmpl({ id: account, name: account }).appendTo($splitAccountSelect);
            }

            $splitAccountSelect.val(account);

            $("input.account-projectcode").filter("[name='" + splitPrefix + "Project']").val(data.splits[i].Project);
            $("input.order-split-account-amount").filter("[name='" + splitPrefix + "amount']").val(amount);
            //TODO: figure out how to create percentages, hopefully without looping through each split again.

            if (subAccount != null) {
                var $splitSubAccountSelect = $("select.account-subaccount").filter("[name='" + splitPrefix + "SubAccount']");
                loadSubAccountsAndBind(account, subAccount, $splitSubAccountSelect);
            }
        }

        purchasing.calculateOrderAccountSplits();
    }

    //TODO: only call if subaccount != null, maybe refactor to move redundant code to OrderMockup.js
    function loadSubAccountsAndBind(account, subAccount, $subAccountSelect) {
        $.getJSON(purchasing._getOption("KfsSearchSubAccountsUrl"), { accountNumber: account }, function (result) {
            $subAccountSelect.find("option:not(:first)").remove();

            if (result.length > 0) {
                var data = $.map(result, function (n, i) { return { name: n.Name, id: n.Id }; });

                $("#select-option-template").tmpl(data).appendTo($subAccountSelect);
            }

            if (!purchasing.selectListContainsValue($subAccountSelect, subAccount)) {
                //If we still don't have the necessary value in sub account, add it in (shouldn't happen?)
                $("#select-option-template").tmpl({ id: subAccount, name: subAccount }).appendTo($subAccountSelect);
            }

            $subAccountSelect.val(subAccount);

            if (routingAdjusted) {
                $subAccountSelect.removeAttr("disabled");
            }
        });
    }

    purchasing.lowerCaseFirstLetter = function (w) {
        return w.charAt(0).toLowerCase() + w.slice(1);
    };

    purchasing.selectListContainsValue = function ($select, val) {
        var exists = false;
        $select.find("option").each(function () {
            if (this.value === val) {
                exists = true;
            }
        });

        return exists;
    };

} (window.purchasing = window.purchasing || {}, jQuery));
<commit_msg>fixed order edit modification bug<commit_after>///<reference path="jquery-1.6.2-vsdoc.js"/>
///<reference path="Order.js"/>

//Self-Executing Anonymous Function
//Adding New Functionality to Purchasing for Edit
(function (purchasing, $, undefined) {
    //Private Property
    var routingAdjusted = false;
    var startingLineItemCount = 3;
    var startingOrderSplitCount = 3; //TODO: move these into a public var?  or options or something?  Statics maybe?
    var startingLineItemSplitCount = 2;
    var lineItemAndSplitSections = "#line-items-section, #order-split-section, #order-account-section";

    //Public Method
    purchasing.initEdit = function () {
        loadLineItemsAndSplits({ disableModification: true }); //TODO: better name?
        attachModificationEvents();
    };

    //Public Method
    purchasing.initCopy = function () {
        loadLineItemsAndSplits({ disableModification: false }); //TODO: decide if we want to load splits
    };

    function attachModificationEvents() {
        $("#item-modification-template").tmpl({}).insertBefore("#line-items-section");

        purchasing.updateNav(); //Update navigation now that we inserted a new section

        $("#item-modification-button").click(function (e, data) {
            e.preventDefault();

            var automate = data === undefined ? false : data.automate;

            if (!automate && !confirm("Enabling line item and account modification will necessitate recalculating approvals once this order edit is submitted. [Details]")) {
                return;
            }

            enableLineItemAndSplitModification();
        });

    }

    function loadLineItemsAndSplits(options) {
        //Place a 'loading line items' ui block
        $.getJSON(purchasing._getOption("GetLineItemsAndSplitsUrl"), null, function (result) {
            console.log(result);
            purchasing.splitType = result.splitType;
            var newLineItemsNeeded = result.lineItems.length - startingLineItemCount;

            if (newLineItemsNeeded > 0) { //Add the number of new line items needed so we have enough
                for (var j = 0; j < newLineItemsNeeded; j++) {
                    $("#add-line-item").trigger('createline');
                }
            }

            var isLineItemSplit = purchasing.splitType === "Line";

            if (isLineItemSplit) {
                $("#split-by-line").trigger('click', { automate: true });
            } else {
                createSplits(result);
            }

            //TODO: do this with the unserialize plugin??
            //Go through each line item and bind it to the ui
            for (var i = 0; i < result.lineItems.length; i++) {
                var prefix = "items[" + i + "].";

                for (var prop in result.lineItems[i]) {
                    var inputName = prefix + purchasing.lowerCaseFirstLetter(prop);

                    $(document.getElementsByName(inputName)).val(result.lineItems[i][prop]);
                }

                if (isLineItemSplit) bindLineItemSplits(result, i);
            }

            //Show the line details if any sub inputs have a value
            $(".line-item-details").has(".sub-line-item :input[value]").show();

            lineItemsAndSplitLoadingComplete(options);
        });
    }

    function lineItemsAndSplitLoadingComplete(options) {
        purchasing.calculateSubTotal(); //TODO: maybe move these somewhere better? or refactor the get method? or use defer/await?
        purchasing.calculateGrandTotal();

        //TODO: do we want to bother with this, making percentages appear?
        //TODO: is it worth rewriting the percent generation logic to avoid recalculation?
        $(".order-split-account-amount, .line-item-split-account-amount").filter(function (el) {
            return this.value !== ''; //return the ones with actual values
        }).trigger("change");

        if (options.disableModification) {
            disableLineItemAndSplitModification();
        }
    }

    function disableLineItemAndSplitModification() {
        routingAdjusted = false;
        $(":input", lineItemAndSplitSections).attr("disabled", "disabled");
        $("a.button", lineItemAndSplitSections).hide(); //TODO: better way to disable the buttons?
    }

    function enableLineItemAndSplitModification() {
        routingAdjusted = true;
        $(":input", lineItemAndSplitSections).removeAttr("disabled");
        $("a.button", lineItemAndSplitSections).show();
        $("#adjustRouting").val("true");
        $("#item-modification-section").hide();
        purchasing.setSplitType(purchasing.splitType, true);
    }

    //Create splits for order splits and no split cases
    function createSplits(data) {
        if (data.splitType === "Order") {
            $("#split-order").trigger('click', { automate: true });

            var newSplitsNeeded = data.splits.length - startingOrderSplitCount;

            if (newSplitsNeeded > 0) {
                for (var j = 0; j < newSplitsNeeded; j++) {
                    $("#add-order-split").trigger('createsplit');
                }
            }

            bindOrderSplits(data);
        }
        else if (data.splitType === "None") {
            bindSplitlessOrder(data);
        }
    }

    function bindLineItemSplits(data, index) {
        var splitsForThisLine = $.map(data.splits, function (val) {
            return val.LineItemId === data.lineItems[index]["Id"] ? val : null;
        });

        var numNewSplitsNeeded = splitsForThisLine.length - startingLineItemSplitCount;

        if (numNewSplitsNeeded > 0) { //Add the number of splits to this line item so we have enough
            var splitButton = $(".sub-line-item-split-body[data-line-item-index='" + index + "']").next().find(".add-line-item-split");

            for (var k = 0; k < numNewSplitsNeeded; k++) {
                splitButton.trigger('createsplit');
            }
        }

        //Now bind all of the splits for this line
        bindLineItemSplitData(index, data.lineItems[index], splitsForThisLine);
    }

    function bindLineItemSplitData(rowIndex, line, splits) {
        console.log(rowIndex);

        var splitsToBind = $(".sub-line-item-split-body[data-line-item-index='" + rowIndex + "'] > tr");

        console.log("splitsToBind", splitsToBind);

        splitsToBind.each(function (index, row) {
            var $splitRow = $(row);

            if (splits[index] === undefined) return; //here we'll have an empty account

            console.log("splits for " + splits[index].LineItemId, splits[index]);

            var $splitAccountSelect = $splitRow.find("select.account-number");
            var lineItemId = splits[index].LineItemId;
            var account = splits[index].Account;
            var subAccount = splits[index].SubAccount;
            var amount = splits[index].Amount;

            if (!purchasing.selectListContainsValue($splitAccountSelect, account)) {
                //Add the account to the list if it is not already in the select
                $("#select-option-template").tmpl({ id: account, name: account }).appendTo($splitAccountSelect);
            }

            $splitAccountSelect.val(account);

            $splitRow.find("input.account-projectcode").val(splits[index].Project);
            $splitRow.find("input.line-item-split-account-amount").val(amount);
            $splitRow.find("input.line-item-split-item-id").val(lineItemId);

            if (subAccount != null) {
                var $splitSubAccountSelect = $splitRow.find("select.account-subaccount");
                loadSubAccountsAndBind(account, subAccount, $splitSubAccountSelect);
            }
        });
    }

    function bindSplitlessOrder(data) {
        var singleSplit = data.splits[0];

        if (singleSplit.Account !== null) {//we have account info, bind
            var $accountSelect = $("select.account-number");

            if (!purchasing.selectListContainsValue($accountSelect, singleSplit.Account)) {
                //Add the account to the list if it is not already in the select
                $("#select-option-template").tmpl({ id: singleSplit.Account, name: singleSplit.Account }).appendTo($accountSelect);
            }

            $accountSelect.val(singleSplit.Account);
            $("input.account-projectcode").val(singleSplit.Project);

            if (singleSplit.SubAccount != null) {
                var $subAccountSelect = $("select.account-subaccount");
                loadSubAccountsAndBind(singleSplit.Account, singleSplit.SubAccount, $subAccountSelect);
            }
        }
    }

    function bindOrderSplits(data) {
        for (var i = 0; i < data.splits.length; i++) {
            var splitPrefix = "splits[" + i + "].";
            var $splitAccountSelect = $("select.account-number").filter("[name='" + splitPrefix + "Account']");
            var account = data.splits[i].Account;
            var subAccount = data.splits[i].SubAccount;
            var amount = data.splits[i].Amount;

            if (!purchasing.selectListContainsValue($splitAccountSelect, account)) {
                //Add the account to the list if it is not already in the select
                $("#select-option-template").tmpl({ id: account, name: account }).appendTo($splitAccountSelect);
            }

            $splitAccountSelect.val(account);

            $("input.account-projectcode").filter("[name='" + splitPrefix + "Project']").val(data.splits[i].Project);
            $("input.order-split-account-amount").filter("[name='" + splitPrefix + "amount']").val(amount);
            //TODO: figure out how to create percentages, hopefully without looping through each split again.

            if (subAccount != null) {
                var $splitSubAccountSelect = $("select.account-subaccount").filter("[name='" + splitPrefix + "SubAccount']");
                loadSubAccountsAndBind(account, subAccount, $splitSubAccountSelect);
            }
        }

        purchasing.calculateOrderAccountSplits();
    }

    //TODO: only call if subaccount != null, maybe refactor to move redundant code to OrderMockup.js
    function loadSubAccountsAndBind(account, subAccount, $subAccountSelect) {
        $.getJSON(purchasing._getOption("KfsSearchSubAccountsUrl"), { accountNumber: account }, function (result) {
            $subAccountSelect.find("option:not(:first)").remove();

            if (result.length > 0) {
                var data = $.map(result, function (n, i) { return { name: n.Name, id: n.Id }; });

                $("#select-option-template").tmpl(data).appendTo($subAccountSelect);
            }

            if (!purchasing.selectListContainsValue($subAccountSelect, subAccount)) {
                //If we still don't have the necessary value in sub account, add it in (shouldn't happen?)
                $("#select-option-template").tmpl({ id: subAccount, name: subAccount }).appendTo($subAccountSelect);
            }

            $subAccountSelect.val(subAccount);

            if (routingAdjusted) {
                $subAccountSelect.removeAttr("disabled");
            }
        });
    }

    purchasing.lowerCaseFirstLetter = function (w) {
        return w.charAt(0).toLowerCase() + w.slice(1);
    };

    purchasing.selectListContainsValue = function ($select, val) {
        var exists = false;
        $select.find("option").each(function () {
            if (this.value === val) {
                exists = true;
            }
        });

        return exists;
    };

} (window.purchasing = window.purchasing || {}, jQuery));
<|endoftext|>


<commit_before>Editor.registerWidget( 'color-picker', {
    is: 'color-picker',

    properties: {
        value: {
            type: Object,
            value: function () {
                return {
                    r: 255,
                    g: 255,
                    b: 255,
                    a: 1
                }
            },
            notity: true,
            observer: '_valueChanged'
        }
    },

    created: function () {
        this._Rgba = function (r, g, b, a) {
            return {
                r: r,
                g: g,
                b: b,
                a: a
            };
        };
        this.dragMove = false;
    },

    ready: function () {
        this.setColor(this.value);
        this._h = 0;
    },

    _valueChanged: function () {
        if (!this.value) {
            return;
        }
        this.hsv = this._Rgba2FireColor(this.value).toHSV();
        this._repaint();
    },

    setColor: function ( value ) {
        this.value = new this._Rgba(value.r,value.g,value.b,value.a);
        this.hsv = this._Rgba2FireColor(this.value).toHSV();
        this._h = this.hsv.h;
        this._repaint();
    },

    _repaint: function () {
        var cssRGB = Fire.hsv2rgb( this._h, 1, 1 );
        cssRGB = "rgb("+ (cssRGB.r * 255|0) + "," + (cssRGB.g * 255 | 0) + "," + (cssRGB.b * 255 | 0) + ")";
        this.$.colorCtrl.style.backgroundColor = cssRGB;
        this.$.opacityCtrl.style.backgroundColor = cssRGB;
        this.$.opacityHandle.style.top = (1.0-this.value.a)*100 + "%";
        this.$.hueHandle.style.top = (1.0-this._h)*100 + "%";
        this.$.colorHandle.style.left = this.hsv.s*100 + "%";
        this.$.colorHandle.style.top = (1.0-this.hsv.v)*100 + "%";
    },

    _updateColor: function () {
        this._repaint();
    },

    _hueCtrlMouseDownAction: function ( event ) {
        EditorUI.addDragGhost("crosshair");

        var rect = this.$.hueCtrl.getBoundingClientRect();
        var mouseDownY = rect.top;
        this.dragMove = true;

        var updateMouseMove = function (event) {
            var offsetY = (event.clientY - mouseDownY)/this.$.hueCtrl.clientHeight;
            offsetY = Math.max( Math.min( offsetY, 1.0 ), 0.001 );

            this.hsv.h = 1.0 - offsetY;
            this._updateColor();
            var h = Math.round( this.hsv.h * 100.0 )/100.0;
            var _value = this._Rgba2FireColor(this.value).fromHSV( h, this.hsv.s, this.hsv.v );
            this._h = this.hsv.h;
            this.value = this._fireColor2Rgba(_value);
            event.stopPropagation();
        };
        updateMouseMove.call(this,event);
        this._updateColor();

        var mouseMoveHandle = updateMouseMove.bind(this);
        var mouseUpHandle = (function(event) {
            document.removeEventListener('mousemove', mouseMoveHandle);
            document.removeEventListener('mouseup', mouseUpHandle);

            EditorUI.removeDragGhost();
            this.dragMove = false;
            event.stopPropagation();
        }).bind(this);
        document.addEventListener ( 'mousemove', mouseMoveHandle );
        document.addEventListener ( 'mouseup', mouseUpHandle );

        event.stopPropagation();
    },

    _colorCtrlMouseDownAction: function ( event ) {
        EditorUI.addDragGhost("crosshair");

        var rect = this.$.colorCtrl.getBoundingClientRect();
        var mouseDownX = rect.left;
        var mouseDownY = rect.top;
        this.dragMove = true;

        var updateMouseMove = function (event) {
            var offsetX = (event.clientX - mouseDownX)/this.$.colorCtrl.clientWidth;
            var offsetY = (event.clientY - mouseDownY)/this.$.colorCtrl.clientHeight;

            offsetX = Math.max( Math.min( offsetX, 1.0 ), 0.0 );
            offsetY = Math.max( Math.min( offsetY, 1.0 ), 0.0 );

            this.hsv.s = offsetX;
            this.hsv.v = 1.0 - offsetY;
            var h = Math.round( this._h * 100.0 ) / 100.0;
            var _value = this._Rgba2FireColor(this.value).fromHSV( h, this.hsv.s, this.hsv.v );
            this.value = this._fireColor2Rgba(_value);
            this._updateColor();
            event.stopPropagation();
        };
        updateMouseMove.call(this,event);

        var mouseMoveHandle = updateMouseMove.bind(this);
        var mouseUpHandle = (function(event) {
            document.removeEventListener('mousemove', mouseMoveHandle);
            document.removeEventListener('mouseup', mouseUpHandle);

            EditorUI.removeDragGhost();
            this.dragMove = false;
            event.stopPropagation();
        }).bind(this);
        document.addEventListener ( 'mousemove', mouseMoveHandle );
        document.addEventListener ( 'mouseup', mouseUpHandle );

        event.stopPropagation();
    },

    _opacityCtrlMouseDownAction: function (event) {
        EditorUI.addDragGhost("crosshair");

        var rect = this.$.opacityCtrl.getBoundingClientRect();
        var mouseDownY = rect.top;
        this.dragMove = true;

        var updateMouseMove = function (event) {
            var offsetY = (event.clientY - mouseDownY)/this.$.opacityCtrl.clientHeight;
            offsetY = Math.max( Math.min( offsetY, 1.0 ), 0.0 );
            this.value.a = this.floatFixed(1.0 - offsetY);
            this.value = new this._Rgba(this.value.r, this.value.g, this.value.b,this.value.a);
            this._updateColor();

            event.stopPropagation();
        };
        updateMouseMove.call(this,event);

        var mouseMoveHandle = updateMouseMove.bind(this);
        var mouseUpHandle = (function(event) {
            document.removeEventListener('mousemove', mouseMoveHandle);
            document.removeEventListener('mouseup', mouseUpHandle);

            EditorUI.removeDragGhost();
            this.dragMove = false;
            event.stopPropagation();
        }).bind(this);
        document.addEventListener ( 'mousemove', mouseMoveHandle );
        document.addEventListener ( 'mouseup', mouseUpHandle );

        event.stopPropagation();
    },

    _Rgba2FireColor: function (value) {
        return new Fire.color(value.r/255,value.g/255,value.b/255,value.a);
    },

    _fireColor2Rgba: function (value) {
        return new this._Rgba(Math.round(value.r*255),Math.round(value.g*255),Math.round(value.b*255),value.a);
    },

    floatFixed: function (value) {
        return parseFloat(value.toFixed(2));
    },

    _inputChanged: function () {
        if (!this.value || this.dragMove === true) {
            return;
        }
        this.hsv = this._Rgba2FireColor(this.value).toHSV();
        this._h = this.hsv.h;
        this._updateColor();
    },
});
<commit_msg>update this._Rgba to Object<commit_after>Editor.registerWidget( 'color-picker', {
    is: 'color-picker',

    properties: {
        value: {
            type: Object,
            value: function () {
                return {
                    r: 255,
                    g: 255,
                    b: 255,
                    a: 1
                }
            },
            notity: true,
            observer: '_valueChanged'
        }
    },

    created: function () {
        this.dragMove = false;
    },

    ready: function () {
        this.setColor(this.value);
        this._h = 0;
    },

    _valueChanged: function () {
        if (!this.value) {
            return;
        }
        this.hsv = this._Rgba2FireColor(this.value).toHSV();
        this._repaint();
    },

    setColor: function ( value ) {
        this.value = new Object({r: value.r, g: value.g, b: value.b, a: value.a});
        this.hsv = this._Rgba2FireColor(this.value).toHSV();
        this._h = this.hsv.h;
        this._repaint();
    },

    _repaint: function () {
        var cssRGB = Fire.hsv2rgb( this._h, 1, 1 );
        cssRGB = "rgb("+ (cssRGB.r * 255|0) + "," + (cssRGB.g * 255 | 0) + "," + (cssRGB.b * 255 | 0) + ")";
        this.$.colorCtrl.style.backgroundColor = cssRGB;
        this.$.opacityCtrl.style.backgroundColor = cssRGB;
        this.$.opacityHandle.style.top = (1.0-this.value.a)*100 + "%";
        this.$.hueHandle.style.top = (1.0-this._h)*100 + "%";
        this.$.colorHandle.style.left = this.hsv.s*100 + "%";
        this.$.colorHandle.style.top = (1.0-this.hsv.v)*100 + "%";
        this.fire('color-changed');
    },

    _hueCtrlMouseDownAction: function ( event ) {
        EditorUI.addDragGhost("crosshair");

        var rect = this.$.hueCtrl.getBoundingClientRect();
        var mouseDownY = rect.top;
        this.dragMove = true;

        var updateMouseMove = function (event) {
            var offsetY = (event.clientY - mouseDownY)/this.$.hueCtrl.clientHeight;
            offsetY = Math.max( Math.min( offsetY, 1.0 ), 0.001 );

            this.hsv.h = 1.0 - offsetY;
            this._repaint();
            var h = Math.round( this.hsv.h * 100.0 )/100.0;
            var _value = this._Rgba2FireColor(this.value).fromHSV( h, this.hsv.s, this.hsv.v );
            this._h = this.hsv.h;
            this.value = this._fireColor2Rgba(_value);
            event.stopPropagation();
        };
        updateMouseMove.call(this,event);
        this._repaint();

        var mouseMoveHandle = updateMouseMove.bind(this);
        var mouseUpHandle = (function(event) {
            document.removeEventListener('mousemove', mouseMoveHandle);
            document.removeEventListener('mouseup', mouseUpHandle);

            EditorUI.removeDragGhost();
            this.dragMove = false;
            event.stopPropagation();
        }).bind(this);
        document.addEventListener ( 'mousemove', mouseMoveHandle );
        document.addEventListener ( 'mouseup', mouseUpHandle );

        event.stopPropagation();
    },

    _colorCtrlMouseDownAction: function ( event ) {
        EditorUI.addDragGhost("crosshair");

        var rect = this.$.colorCtrl.getBoundingClientRect();
        var mouseDownX = rect.left;
        var mouseDownY = rect.top;
        this.dragMove = true;

        var updateMouseMove = function (event) {
            var offsetX = (event.clientX - mouseDownX)/this.$.colorCtrl.clientWidth;
            var offsetY = (event.clientY - mouseDownY)/this.$.colorCtrl.clientHeight;

            offsetX = Math.max( Math.min( offsetX, 1.0 ), 0.0 );
            offsetY = Math.max( Math.min( offsetY, 1.0 ), 0.0 );

            this.hsv.s = offsetX;
            this.hsv.v = 1.0 - offsetY;
            var h = Math.round( this._h * 100.0 ) / 100.0;
            var _value = this._Rgba2FireColor(this.value).fromHSV( h, this.hsv.s, this.hsv.v );
            this.value = this._fireColor2Rgba(_value);
            this._repaint();
            event.stopPropagation();
        };
        updateMouseMove.call(this,event);

        var mouseMoveHandle = updateMouseMove.bind(this);
        var mouseUpHandle = (function(event) {
            document.removeEventListener('mousemove', mouseMoveHandle);
            document.removeEventListener('mouseup', mouseUpHandle);

            EditorUI.removeDragGhost();
            this.dragMove = false;
            event.stopPropagation();
        }).bind(this);
        document.addEventListener ( 'mousemove', mouseMoveHandle );
        document.addEventListener ( 'mouseup', mouseUpHandle );

        event.stopPropagation();
    },

    _opacityCtrlMouseDownAction: function (event) {
        EditorUI.addDragGhost("crosshair");

        var rect = this.$.opacityCtrl.getBoundingClientRect();
        var mouseDownY = rect.top;
        this.dragMove = true;

        var updateMouseMove = function (event) {
            var offsetY = (event.clientY - mouseDownY)/this.$.opacityCtrl.clientHeight;
            offsetY = Math.max( Math.min( offsetY, 1.0 ), 0.0 );
            this.value.a = this._floatFixed(1.0 - offsetY);
            this.value = new Object({r: this.value.r, g: this.value.g, b: this.value.b, a: this.value.a});
            this._repaint();

            event.stopPropagation();
        };
        updateMouseMove.call(this,event);

        var mouseMoveHandle = updateMouseMove.bind(this);
        var mouseUpHandle = (function(event) {
            document.removeEventListener('mousemove', mouseMoveHandle);
            document.removeEventListener('mouseup', mouseUpHandle);

            EditorUI.removeDragGhost();
            this.dragMove = false;
            event.stopPropagation();
        }).bind(this);
        document.addEventListener ( 'mousemove', mouseMoveHandle );
        document.addEventListener ( 'mouseup', mouseUpHandle );

        event.stopPropagation();
    },

    _Rgba2FireColor: function (value) {
        return new Fire.color(value.r/255,value.g/255,value.b/255,value.a);
    },

    _fireColor2Rgba: function (value) {
        return new Object({r: Math.round(value.r*255), g: Math.round(value.g*255), b: Math.round(value.b*255), a: value.a});
    },

    _floatFixed: function (value) {
        return parseFloat(value.toFixed(2));
    },

    _inputChanged: function () {
        if (!this.value || this.dragMove === true) {
            return;
        }
        this.hsv = this._Rgba2FireColor(this.value).toHSV();
        this._h = this.hsv.h;
        this._repaint();
    },
});
<|endoftext|>


<commit_before>// CREATE AND APPEND GEAR TO THE BODY

// Import css (Github icons pack)
var link = document.createElement("link");
link.setAttribute("rel", "stylesheet");
link.setAttribute("type", "text/css");
link.setAttribute("href", "//maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css");
document.getElementsByTagName("head")[0].appendChild(link);

// Import css (css of the widget)
link = document.createElement("link");
link.setAttribute("rel", "stylesheet");
link.setAttribute("type", "text/css");
link.setAttribute("href", API.url(widgetID,'css.css'));
document.getElementsByTagName("head")[0].appendChild(link);

// Make the div container for the gear button
var gearDiv = document.createElement('div');
gearDiv.className = 'config_buttongear';
gearDiv.innerHTML = '';

// Append the gear to the body
document.body.appendChild(gearDiv);

// CREATE AND APPEND CONTENT CONFIGURATION DIV

// Make the div container for the config window
var contentDiv = document.createElement('div');
contentDiv.className = 'config_contentdiv';

// Append the config window to the body
document.body.appendChild(contentDiv);

// Make the div container for the widgets in the config window and append the container for the widgets in the config window
var contentwidgetsDiv = document.createElement('div');
contentwidgetsDiv.className = 'contentwidgets';
contentDiv.appendChild(contentwidgetsDiv);

// Make the div container for the result of the configuration function of each widget (share the div) and append the container for the widgets in the config window
var configwidgetDiv = document.createElement('div');
configwidgetDiv.className = 'configwidget';
contentDiv.appendChild(configwidgetDiv);

// Placeholder for the back button variable
var backbutton;

// Create the close button for the config window
var closebutton = document.createElement('i');
closebutton.className = 'fa fa-times closebutton';
contentDiv.appendChild(closebutton);
closebutton.onclick = function(){
	// Reset content
	contentwidgetsDiv.innerHTML = '';
	configwidgetDiv.innerHTML = '';
	if(backbutton){
		backbutton.remove();
	}
	// Hide window
	contentDiv.className = contentDiv.className.split('visible').join('').trim();
};

// SET GEAR BUTTON ACTION

gearDiv.onclick = function(){
	contentDiv.className += ' visible';
	contentwidgetsDiv.style.display = '';

	// Fill the config window

	// Go over the array CONFIG
	for(widget in CONFIG){
		var buttonWidget = document.createElement('div');
		buttonWidget.innerHTML += CONFIG[widget]['name'];
		contentwidgetsDiv.appendChild(buttonWidget);

		// set the onclick for the button. executes the widget function and appends the result to the
		buttonWidget.onclick = function(){
			contentwidgetsDiv.style.display = 'none';
			// Execute the function and append the result to the corresponding div container
			configwidgetDiv.appendChild(CONFIG[widget]['function']());

			// Create the back button for the widget config window
			backbutton = document.createElement('i');
			backbutton.className = 'fa fa-reply backbutton';
			contentDiv.appendChild(backbutton);
			backbutton.onclick = function(){
				// Reset content
				configwidgetDiv.innerHTML = '';
				contentwidgetsDiv.style.display = '';
				backbutton.remove();
			};
		}
	}

};

// Function for the config widgetID. It returns the html object to append on the config window.
// In this case we only want to allow the user to change the position of the widget.
var CONFIG_function = function(){
	var div = document.createElement('div');
	return div;
}
<commit_msg>config widget fix (closure problem with a function created inside a for)<commit_after>// CREATE AND APPEND GEAR TO THE BODY

// Import css (Github icons pack)
var link = document.createElement("link");
link.setAttribute("rel", "stylesheet");
link.setAttribute("type", "text/css");
link.setAttribute("href", "//maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css");
document.getElementsByTagName("head")[0].appendChild(link);

// Import css (css of the widget)
link = document.createElement("link");
link.setAttribute("rel", "stylesheet");
link.setAttribute("type", "text/css");
link.setAttribute("href", API.url(widgetID,'css.css'));
document.getElementsByTagName("head")[0].appendChild(link);

// Make the div container for the gear button
var gearDiv = document.createElement('div');
gearDiv.className = 'config_buttongear';
gearDiv.innerHTML = '';

// Append the gear to the body
document.body.appendChild(gearDiv);

// CREATE AND APPEND CONTENT CONFIGURATION DIV

// Make the div container for the config window
var contentDiv = document.createElement('div');
contentDiv.className = 'config_contentdiv';

// Append the config window to the body
document.body.appendChild(contentDiv);

// Make the div container for the widgets in the config window and append the container for the widgets in the config window
var contentwidgetsDiv = document.createElement('div');
contentwidgetsDiv.className = 'contentwidgets';
contentDiv.appendChild(contentwidgetsDiv);

// Make the div container for the result of the configuration function of each widget (share the div) and append the container for the widgets in the config window
var configwidgetDiv = document.createElement('div');
configwidgetDiv.className = 'configwidget';
contentDiv.appendChild(configwidgetDiv);

// Placeholder for the back button variable
var backbutton;

// Create the close button for the config window
var closebutton = document.createElement('i');
closebutton.className = 'fa fa-times closebutton';
contentDiv.appendChild(closebutton);
closebutton.onclick = function(){
	// Reset content
	contentwidgetsDiv.innerHTML = '';
	configwidgetDiv.innerHTML = '';
	if(backbutton){
		backbutton.remove();
	}
	// Hide window
	contentDiv.className = contentDiv.className.split('visible').join('').trim();
};

// SET GEAR BUTTON ACTION

gearDiv.onclick = function(){
	contentDiv.className += ' visible';
	contentwidgetsDiv.style.display = '';

	// Fill the config window

	// Go over the array CONFIG
	for(widget in CONFIG){
		var buttonWidget = document.createElement('div');
		buttonWidget.innerHTML += CONFIG[widget]['name'];
		contentwidgetsDiv.appendChild(buttonWidget);

		// set the onclick for the button. executes the widget function and appends the result to the
		buttonWidget.onclick = (function(widget){
			return function(){
				contentwidgetsDiv.style.display = 'none';
				// Execute the function and append the result to the corresponding div container
				configwidgetDiv.appendChild(CONFIG[widget]['function']());

				// Create the back button for the widget config window
				backbutton = document.createElement('i');
				backbutton.className = 'fa fa-reply backbutton';
				contentDiv.appendChild(backbutton);
				backbutton.onclick = function(){
					// Reset content
					configwidgetDiv.innerHTML = '';
					contentwidgetsDiv.style.display = '';
					backbutton.remove();
				};
			};
		})(widget);
	}

};

// Function for the config widgetID. It returns the html object to append on the config window.
// In this case we only want to allow the user to change the position of the widget.
var CONFIG_function = function(){
	var div = document.createElement('div');
	return div;
}
<|endoftext|>


<commit_before>/* eslint consistent-return: 0 */

const cheerio = require('cheerio')

const scrapeUtil = require('./utility')

// Parse Globals
const HOSTNAME = 'https://hope.huntsmancancer.org'
const BASENAME = 'huntsmanchallenge'

// Parse Utilities
const teamIdFromURI = (url) => {
  const re = new RegExp(`${BASENAME}\\/(\\d+)\\/`)
  const found = url.match(re)
  return found.length > 0 && found[1]
}

// Parse Functions
const raisedValuesForSchool = (html, schoolId) => new Promise((resolve, reject) => {
  const raisedValues = {}
  const dom = cheerio.load(html)
  const teams = dom('.GroupRosterWidget-partdesc')

  // funds donated to school page
  const schoolAmount = dom('.page-raised').first().text()
  const schoolCleanAmount = schoolAmount.trim().replace('$', '').replace(',', '')
  const schoolFloatAmount = parseFloat(schoolCleanAmount)
  if (!schoolCleanAmount.split('').every(c => (parseInt(c) || ['0', '.'].includes(c)))) {
    // If any of the characters are not integers or '.'
    return reject(new Error(`amount raised is not valid: ${schoolCleanAmount}`))
  }
  if (!schoolFloatAmount && schoolFloatAmount !== 0) {
    // If parsing the string to float failed
    return reject(new Error(`amount raised is not a valid float: ${schoolCleanAmount}`))
  }
  raisedValues[schoolId] = schoolFloatAmount

  teams.each((i, elm) => {
    const teamURI = dom(elm).children('.GroupRosterWidget-name').first().attr('href')
    const teamId = teamIdFromURI(teamURI)
    if (!teamId) {
      return reject(new Error(`failed to find teamId in teamURI: ${teamURI}`))
    }
    const amount = dom(elm).children('.GroupRosterWidget-raised').first().text()
    const cleanAmount = amount.trim().replace('$', '').replace(',', '')
    const floatAmount = parseFloat(cleanAmount)

    // validate data
    if (!teamId.split('').every(c => (parseInt(c) || c === '0'))) {
      // If any of the characters are not integers
      return reject(new Error(`teamId is not valid: ${teamId}`))
    }
    if (!cleanAmount.split('').every(c => (parseInt(c) || ['0', '.'].includes(c)))) {
      // If any of the characters are not integers or '.'
      return reject(new Error(`amount raised is not valid: ${cleanAmount}`))
    }
    if (!floatAmount && floatAmount !== 0) {
      // If parsing the string to float failed
      return reject(new Error(`amount raised is not a valid float: ${cleanAmount}`))
    }
    // Data is valid, add it to the object
    raisedValues[teamId] = floatAmount
  })
  if (Object.keys(raisedValues).length === 0) {
    return reject(new Error('PARSE FAILED: raisedValues object was empty'))
  }
  return resolve(raisedValues)
})

const teamURLsForSchool = (html, schoolId) => new Promise((resolve, reject) => {
  const urls = {}
  const dom = cheerio.load(html)
  const teams = dom('.GroupRosterWidget-partdesc')

  teams.each((i, elm) => {
    const teamNode = dom(elm).children('.GroupRosterWidget-name').first()
    const teamName = teamNode.text()
    const teamURI = teamNode.attr('href')
    const teamId = teamIdFromURI(teamURI)
    if (!teamId) {
      return reject(new Error(`failed to find teamId in teamURI: ${teamURI}`))
    }
    const shortTeamURI = teamURI.substring(0, teamURI.lastIndexOf('/'))
    const teamURL = `${HOSTNAME}${shortTeamURI}`

    // validate data
    if (!teamId.split('').every(c => (parseInt(c) || c === '0'))) {
      // If any of the characters are not integers
      return reject(new Error(`teamId is not valid: ${teamId}`))
    }
    urls[teamId] = { schoolId, url: teamURL, name: teamName }
  })
  // validate urls
  const urlValidations = Object.keys(urls).map(key => (
    scrapeUtil.validURL(urls[key])
  ))
  Promise.all(urlValidations).then((results) => {
    if (results.every(result => result)) {
      // all urls must be valid
      if (Object.keys(urls).length === 0) {
        return reject(new Error('PARSE FAILED: urls object was empty'))
      }
      return resolve(urls)
    }
    return reject(new Error('An invalid url was found when parsing teamURLsForSchool'))
  }).catch(err => reject(err))
})

const teamValues = (html, teamId) => new Promise((resolve, reject) => {
  const dom = cheerio.load(html)

  const teamName = dom('#page_name').text()
  const avatarURL = dom('#page-image-camp').attr('src')
  const coverURL = dom('#page-banner').attr('src')

  const memberNode = dom('.group-member-count').first()
  const memberText = memberNode.children().first().text()
  const found = memberText.match(/(\d+).+/)
  const memberNumber = found.length > 0 && found[1]
  if (!memberNumber) {
    return reject(new Error(`failed to find number of members for team: ${teamId}`))
  }

  const finalValues = {
    teamId,
    name: teamName,
    members: parseInt(memberNumber),
    avatar: avatarURL,
    cover: coverURL,
  }

  // validate data
  if (!memberNumber.split('').every(c => (parseInt(c) || c === '0'))) {
    // If any of the characters are not integers
    return reject(new Error(`number of members is not valid: ${memberNumber}`))
  }
  const urlValidations = [
    scrapeUtil.validURL(avatarURL),
    scrapeUtil.validURL(coverURL),
  ]
  Promise.all(urlValidations).then((results) => {
    if (results.every(result => result)) {
      // all urls must be valid
      return resolve(finalValues)
    }
    return reject(new Error(`An invalid url was found when parsing team: ${teamId}`))
  }).catch(err => reject(err))
})

// Exports
module.exports = {
  raisedValuesForSchool,
  teamURLsForSchool,
  teamValues,
}
<commit_msg>Update parsing<commit_after>/* eslint consistent-return: 0 */

const cheerio = require('cheerio')

const scrapeUtil = require('./utility')

// Parse Globals
const HOSTNAME = 'https://hope.huntsmancancer.org'
const BASENAME = 'huntsmanchallenge2021'

// Parse Utilities
const teamIdFromURI = (url) => {
  const re = new RegExp(`${BASENAME}\\/(\\d+)\\/`)
  const found = url.match(re)
  return found.length > 0 && found[1]
}

// Parse Functions
const raisedValuesForSchool = (html, schoolId) => new Promise((resolve, reject) => {
  const raisedValues = {}
  const dom = cheerio.load(html)
  const teams = dom('.GroupRosterWidget-partdesc')

  // funds donated to school page
  const schoolAmount = dom('.page-raised').first().text()
  const schoolCleanAmount = schoolAmount.trim().replace('$', '').replace(',', '')
  const schoolFloatAmount = parseFloat(schoolCleanAmount)
  if (!schoolCleanAmount.split('').every(c => (parseInt(c) || ['0', '.'].includes(c)))) {
    // If any of the characters are not integers or '.'
    return reject(new Error(`amount raised is not valid: ${schoolCleanAmount}`))
  }
  if (!schoolFloatAmount && schoolFloatAmount !== 0) {
    // If parsing the string to float failed
    return reject(new Error(`amount raised is not a valid float: ${schoolCleanAmount}`))
  }
  raisedValues[schoolId] = schoolFloatAmount

  teams.each((i, elm) => {
    const teamURI = dom(elm).children('.GroupRosterWidget-name').first().attr('href')
    const teamId = teamIdFromURI(teamURI)
    if (!teamId) {
      return reject(new Error(`failed to find teamId in teamURI: ${teamURI}`))
    }
    const amount = dom(elm).children('.GroupRosterWidget-raised').first().text()
    const cleanAmount = amount.trim().replace('$', '').replace(',', '')
    const floatAmount = parseFloat(cleanAmount)

    // validate data
    if (!teamId.split('').every(c => (parseInt(c) || c === '0'))) {
      // If any of the characters are not integers
      return reject(new Error(`teamId is not valid: ${teamId}`))
    }
    if (!cleanAmount.split('').every(c => (parseInt(c) || ['0', '.'].includes(c)))) {
      // If any of the characters are not integers or '.'
      return reject(new Error(`amount raised is not valid: ${cleanAmount}`))
    }
    if (!floatAmount && floatAmount !== 0) {
      // If parsing the string to float failed
      return reject(new Error(`amount raised is not a valid float: ${cleanAmount}`))
    }
    // Data is valid, add it to the object
    raisedValues[teamId] = floatAmount
  })
  if (Object.keys(raisedValues).length === 0) {
    return reject(new Error('PARSE FAILED: raisedValues object was empty'))
  }
  return resolve(raisedValues)
})

const teamURLsForSchool = (html, schoolId) => new Promise((resolve, reject) => {
  const urls = {}
  const dom = cheerio.load(html)
  const teams = dom('.GroupRosterWidget-partdesc')

  teams.each((i, elm) => {
    const teamNode = dom(elm).children('.GroupRosterWidget-name').first()
    const teamName = teamNode.text()
    const teamURI = teamNode.attr('href')
    const teamId = teamIdFromURI(teamURI)
    if (!teamId) {
      return reject(new Error(`failed to find teamId in teamURI: ${teamURI}`))
    }
    const shortTeamURI = teamURI.substring(0, teamURI.lastIndexOf('/'))
    const teamURL = `${HOSTNAME}${shortTeamURI}`

    // validate data
    if (!teamId.split('').every(c => (parseInt(c) || c === '0'))) {
      // If any of the characters are not integers
      return reject(new Error(`teamId is not valid: ${teamId}`))
    }
    urls[teamId] = { schoolId, url: teamURL, name: teamName }
  })
  // validate urls
  const urlValidations = Object.keys(urls).map(key => (
    scrapeUtil.validURL(urls[key])
  ))
  Promise.all(urlValidations).then((results) => {
    if (results.every(result => result)) {
      // all urls must be valid
      if (Object.keys(urls).length === 0) {
        return reject(new Error('PARSE FAILED: urls object was empty'))
      }
      return resolve(urls)
    }
    return reject(new Error('An invalid url was found when parsing teamURLsForSchool'))
  }).catch(err => reject(err))
})

const teamValues = (html, teamId) => new Promise((resolve, reject) => {
  const dom = cheerio.load(html)

  const teamName = dom('#page_name').text()
  const avatarURL = dom('#page-image-camp').attr('src')
  const coverURL = dom('#page-banner').attr('src')

  const memberNode = dom('.group-member-count').first()
  const memberText = memberNode.children().first().text()
  const found = memberText.match(/(\d+).+/)
  const memberNumber = found.length > 0 && found[1]
  if (!memberNumber) {
    return reject(new Error(`failed to find number of members for team: ${teamId}`))
  }

  const finalValues = {
    teamId,
    name: teamName,
    members: parseInt(memberNumber),
    avatar: avatarURL,
    cover: coverURL,
  }

  // validate data
  if (!memberNumber.split('').every(c => (parseInt(c) || c === '0'))) {
    // If any of the characters are not integers
    return reject(new Error(`number of members is not valid: ${memberNumber}`))
  }
  const urlValidations = [
    scrapeUtil.validURL(avatarURL),
    scrapeUtil.validURL(coverURL),
  ]
  Promise.all(urlValidations).then((results) => {
    if (results.every(result => result)) {
      // all urls must be valid
      return resolve(finalValues)
    }
    return reject(new Error(`An invalid url was found when parsing team: ${teamId}`))
  }).catch(err => reject(err))
})

// Exports
module.exports = {
  raisedValuesForSchool,
  teamURLsForSchool,
  teamValues,
}
<|endoftext|>


<commit_before>define(["Tone/core/Tone", "Tone/component/Envelope", "Tone/source/Oscillator",
	"Tone/signal/Signal", "Tone/component/Filter", "Tone/signal/Add", "Tone/instrument/Monophonic"],
function(Tone){

	"use strict";

	/**
	 *  @class  the MonoSynth is a single oscillator, monophonic synthesizer
	 *          with a filter, and two envelopes (on the filter and the amplitude)
	 *
	 *  @constructor
	 *  @extends {Tone.Monophonic}
	 *  @param {Object} options the options available for the synth
	 *                          see defaults below
	 */
	Tone.MonoSynth = function(options){

		//get the defaults
		options = this.defaultArg(options, Tone.MonoSynth.defaults);
		Tone.Monophonic.call(this, options);

		/**
		 *  the first oscillator
		 *  @type {Tone.Oscillator}
		 */
		this.oscillator = new Tone.Oscillator(0, options.oscType);

		/**
		 *  the frequency control signal
		 *  @type {Tone.Signal}
		 */
		this.frequency = this.oscillator.frequency;

		/**
		 *  the detune control signal
		 *  @type {Tone.Signal}
		 */
		this.detune = this.oscillator.detune;

		/**
		 *  the filter
		 *  @type {Tone.Filter}
		 */
		this.filter = new Tone.Filter(options.filter);

		/**
		 *  the filter envelope
		 *  @type {Tone.Envelope}
		 */
		this.filterEnvelope = new Tone.Envelope(options.filterEnvelope);

		/**
		 *  the amplitude envelope
		 *  @type {Tone.Envelope}
		 */
		this.envelope = new Tone.Envelope(options.envelope);

		/**
		 *  the amplitude
		 *  @type {GainNode}
		 *  @private
		 */
		this._amplitude = this.context.createGain();

		//connect the oscillators to the output
		this.oscillator.connect(this.filter);
		this.filter.connect(this._amplitude);
		//start the oscillators
		this.oscillator.start();
		//connect the envelopes
		this.filterEnvelope.connect(this.filter.frequency);
		this.envelope.connect(this._amplitude.gain);
		this._amplitude.connect(this.output);
	};

	Tone.extend(Tone.MonoSynth, Tone.Monophonic);

	/**
	 *  @const
	 *  @static
	 *  @type {Object}
	 */
	Tone.MonoSynth.defaults = {
		"oscType" : "square",
		"filter" : {
			"Q" : 6,
			"type" : "lowpass",
			"rolloff" : -24
		},
		"envelope" : {
			"attack" : 0.005,
			"decay" : 0.1,
			"sustain" : 0.9,
			"release" : 1
		},
		"filterEnvelope" : {
			"attack" : 0.06,
			"decay" : 0.2,
			"sustain" : 0.5,
			"release" : 2,
			"min" : 10,
			"max" : 4000
		}
	};

	/**
	 *  start the attack portion of the envelope
	 *  @param {Tone.Time=} [time=now] the time the attack should start
	 *  @param {number=} velocity the velocity of the note (0-1)
	 */
	Tone.MonoSynth.prototype.triggerEnvelopeAttack = function(time, velocity){
		//the envelopes
		this.envelope.triggerAttack(time, velocity);
		this.filterEnvelope.triggerAttack(time);
	};

	/**
	 *  start the release portion of the envelope
	 *  @param {Tone.Time=} [time=now] the time the release should start
	 */
	Tone.MonoSynth.prototype.triggerEnvelopeRelease = function(time){
		this.envelope.triggerRelease(time);
		this.filterEnvelope.triggerRelease(time);
	};

	/**
	 *  set the oscillator type
	 *  @param {string} oscType the type of oscillator
	 */
	Tone.MonoSynth.prototype.setOscType = function(type){
		this.oscillator.setType(type);
	};

	/**
	 *  set the members at once
	 *  @param {Object} params all of the parameters as an object.
	 *                         params for envelope and filterEnvelope
	 *                         should be nested objects.
	 */
	Tone.MonoSynth.prototype.set = function(params){
		if (!this.isUndef(params.detune)) this.detune.setValue(params.detune);
		if (!this.isUndef(params.oscType)) this.setOscType(params.oscType);
		if (!this.isUndef(params.filterEnvelope)) this.filterEnvelope.set(params.filterEnvelope);
		if (!this.isUndef(params.envelope)) this.envelope.set(params.envelope);
		if (!this.isUndef(params.filter)) this.filter.set(params.filter);
		Tone.Monophonic.prototype.set.call(this, params);
	};

	/**
	 *  clean up
	 */
	Tone.MonoSynth.prototype.dispose = function(){
		Tone.Monophonic.prototype.dispose.call(this);
		this.oscillator.dispose();
		this.envelope.dispose();
		this.filterEnvelope.dispose();
		this.filter.dispose();
		this._amplitude.disconnect();
		this.oscillator = null;
		this.filterEnvelope = null;
		this.envelope = null;
		this.filter = null;
		this.detune = null;
		this._amplitude = null;
		this.frequency = null;
		this.detune = null;
	};

	return Tone.MonoSynth;
});<commit_msg>small default change<commit_after>define(["Tone/core/Tone", "Tone/component/Envelope", "Tone/source/Oscillator",
	"Tone/signal/Signal", "Tone/component/Filter", "Tone/signal/Add", "Tone/instrument/Monophonic"],
function(Tone){

	"use strict";

	/**
	 *  @class  the MonoSynth is a single oscillator, monophonic synthesizer
	 *          with a filter, and two envelopes (on the filter and the amplitude)
	 *
	 *  @constructor
	 *  @extends {Tone.Monophonic}
	 *  @param {Object} options the options available for the synth
	 *                          see defaults below
	 */
	Tone.MonoSynth = function(options){

		//get the defaults
		options = this.defaultArg(options, Tone.MonoSynth.defaults);
		Tone.Monophonic.call(this, options);

		/**
		 *  the first oscillator
		 *  @type {Tone.Oscillator}
		 */
		this.oscillator = new Tone.Oscillator(0, options.oscType);

		/**
		 *  the frequency control signal
		 *  @type {Tone.Signal}
		 */
		this.frequency = this.oscillator.frequency;

		/**
		 *  the detune control signal
		 *  @type {Tone.Signal}
		 */
		this.detune = this.oscillator.detune;

		/**
		 *  the filter
		 *  @type {Tone.Filter}
		 */
		this.filter = new Tone.Filter(options.filter);

		/**
		 *  the filter envelope
		 *  @type {Tone.Envelope}
		 */
		this.filterEnvelope = new Tone.Envelope(options.filterEnvelope);

		/**
		 *  the amplitude envelope
		 *  @type {Tone.Envelope}
		 */
		this.envelope = new Tone.Envelope(options.envelope);

		/**
		 *  the amplitude
		 *  @type {GainNode}
		 *  @private
		 */
		this._amplitude = this.context.createGain();

		//connect the oscillators to the output
		this.oscillator.connect(this.filter);
		this.filter.connect(this._amplitude);
		//start the oscillators
		this.oscillator.start();
		//connect the envelopes
		this.filterEnvelope.connect(this.filter.frequency);
		this.envelope.connect(this._amplitude.gain);
		this._amplitude.connect(this.output);
	};

	Tone.extend(Tone.MonoSynth, Tone.Monophonic);

	/**
	 *  @const
	 *  @static
	 *  @type {Object}
	 */
	Tone.MonoSynth.defaults = {
		"oscType" : "square",
		"filter" : {
			"Q" : 6,
			"type" : "lowpass",
			"rolloff" : -24
		},
		"envelope" : {
			"attack" : 0.005,
			"decay" : 0.1,
			"sustain" : 0.9,
			"release" : 1
		},
		"filterEnvelope" : {
			"attack" : 0.06,
			"decay" : 0.2,
			"sustain" : 0.5,
			"release" : 2,
			"min" : 20,
			"max" : 4000
		}
	};

	/**
	 *  start the attack portion of the envelope
	 *  @param {Tone.Time=} [time=now] the time the attack should start
	 *  @param {number=} velocity the velocity of the note (0-1)
	 */
	Tone.MonoSynth.prototype.triggerEnvelopeAttack = function(time, velocity){
		//the envelopes
		this.envelope.triggerAttack(time, velocity);
		this.filterEnvelope.triggerAttack(time);
	};

	/**
	 *  start the release portion of the envelope
	 *  @param {Tone.Time=} [time=now] the time the release should start
	 */
	Tone.MonoSynth.prototype.triggerEnvelopeRelease = function(time){
		this.envelope.triggerRelease(time);
		this.filterEnvelope.triggerRelease(time);
	};

	/**
	 *  set the oscillator type
	 *  @param {string} oscType the type of oscillator
	 */
	Tone.MonoSynth.prototype.setOscType = function(type){
		this.oscillator.setType(type);
	};

	/**
	 *  set the members at once
	 *  @param {Object} params all of the parameters as an object.
	 *                         params for envelope and filterEnvelope
	 *                         should be nested objects.
	 */
	Tone.MonoSynth.prototype.set = function(params){
		if (!this.isUndef(params.detune)) this.detune.setValue(params.detune);
		if (!this.isUndef(params.oscType)) this.setOscType(params.oscType);
		if (!this.isUndef(params.filterEnvelope)) this.filterEnvelope.set(params.filterEnvelope);
		if (!this.isUndef(params.envelope)) this.envelope.set(params.envelope);
		if (!this.isUndef(params.filter)) this.filter.set(params.filter);
		Tone.Monophonic.prototype.set.call(this, params);
	};

	/**
	 *  clean up
	 */
	Tone.MonoSynth.prototype.dispose = function(){
		Tone.Monophonic.prototype.dispose.call(this);
		this.oscillator.dispose();
		this.envelope.dispose();
		this.filterEnvelope.dispose();
		this.filter.dispose();
		this._amplitude.disconnect();
		this.oscillator = null;
		this.filterEnvelope = null;
		this.envelope = null;
		this.filter = null;
		this.detune = null;
		this._amplitude = null;
		this.frequency = null;
		this.detune = null;
	};

	return Tone.MonoSynth;
});<|endoftext|>


<commit_before>"use strict";

var assert = require('assert');

var canSmush = function(a,b) {
  return (a[a.length-1] === b[0]);
};

var smush = function(a,b) {
  if (!canSmush(a,b)) throw Error('unsmushable');

  return a + b.substr(1);
};

describe('word smushing', function() {
  describe('can smush', function() {
    it('should', function() {
      assert(canSmush('it','to'));
    });

    it('shouldn\'t', function() {
      assert(!canSmush('be','to'));
    });
  });

  describe('smush together', function() {
    it('wont smush unsmushable', function() {
      assert.throws(function() { smush('be','to'); });
    });

    it('joins together when 1 character overlaps', function() {
      var smushed = smush('it', 'to');
      assert.equal('ito', smushed);
    });
  });
});<commit_msg>failing test case determines that is an invalid test<commit_after>"use strict";

var assert = require('assert');

var canSmush = function(a,b) {
  return (a[a.length-1] === b[0]);
};

var smush = function(a,b) {
  if (!canSmush(a,b)) throw Error('unsmushable');

  return a + b.substr(1);
};

describe('word smushing', function() {
  describe('can smush', function() {
    it('should deal with single character smushes', function() {
      assert(canSmush('it','to'));
    });

    it('shouldn\'t', function() {
      assert(!canSmush('be','to'));
    });
  });

  describe('smush together', function() {
    it('wont smush unsmushable', function() {
      assert.throws(function() { smush('be','to'); });
    });

    it('joins together when 1 character overlaps', function() {
      var smushed = smush('it', 'to');
      assert.equal('ito', smushed);
    });

    it('should deal with multiple overlaps', function() {
      var smushed = smush('bea', 'ear');
      assert.equal('bear', smushed);
    });

  });
});<|endoftext|>


<commit_before>import { Application } from 'spectron'
import path from 'path'
import test from 'ava'

let electronPath = path.join(
  __dirname,
  '..',
  'node_modules',
  '.bin',
  'electron',
)
if (process.platform === 'win32') {
  electronPath += '.cmd'
}
const appPath = path.join(__dirname, '..')

const app = new Application({
  path: electronPath,
  args: [appPath],
})

test.before(async () => {
  await app.start()
  await app.client.waitUntilWindowLoaded()
})

test.after(async () => {
  if (app && app.isRunning()) {
    await app.stop()
  }
})

test.serial('should login successfully', async t => {
  // Go to login page
  await app.client.waitUntilTextExists('#home', 'Login', 60000)
  await app.client.click('#react-tabs-2')
  // await app.client.click('div[aria-label="Private Key"]')

  // // Enter Wif
  await app.client.setValue(
    'input[type="password"]',
    'KxB52D1FGe5xBn6YeezNwj7grhkHZxq7bv2tmaCPoT4rxApMwMvU',
  )
  // Click on login btn
  await app.client.click('#loginButton')
  // // Check that the default network is MainNet
  await app.client
    .getValue('#current-network')
    .catch(error =>
      t.is(
        error.message,
        'An element could not be located on the page using the given search parameters ("#current-network").',
      ),
    )
  // click activity tab
  await app.client.click('#history')
  await app.client.waitUntilWindowLoaded(10000)

  // click send tab
  await app.client.click('#send')
  await app.client.waitUntilWindowLoaded(10000)

  // click receive tab
  await app.client.click('#receive')
  await app.client.waitUntilWindowLoaded(10000)

  // click contacts tab
  await app.client.click('#contacts')
  await app.client.waitUntilWindowLoaded(10000)

  // click token sale tab
  await app.client.click('#tokensale')
  await app.client.waitUntilWindowLoaded(10000)

  // click settings tab
  await app.client.click('#settings')
  await app.client.waitUntilWindowLoaded(10000)

  //click logout
  //await app.client.click('#logout')
  //await app.client.waitUntilWindowLoaded(10000)
})

<commit_msg>package changes<commit_after>import { Application } from 'spectron'
import path from 'path'
import test from 'ava'

let electronPath = path.join(
  __dirname,
  '..',
  'node_modules',
  '.bin',
  'electron',
)
if (process.platform === 'win32') {
  electronPath += '.cmd'
}
const appPath = path.join(__dirname, '..')

const app = new Application({
  path: electronPath,
  args: [appPath],
})

test.before(async () => {
  await app.start()
  await app.client.waitUntilWindowLoaded()
})

test.after(async () => {
  if (app && app.isRunning()) {
    await app.stop()
  }
})

test.serial('should login successfully', async t => {
  // Go to login page
  await app.client.waitUntilTextExists('#home', 'Login', 60000)
  await app.client.click('#react-tabs-2')
  // await app.client.click('div[aria-label="Private Key"]')

  // // Enter Wif
  await app.client.setValue(
    'input[type="password"]',
    'KxB52D1FGe5xBn6YeezNwj7grhkHZxq7bv2tmaCPoT4rxApMwMvU',
  )
  // Click on login btn
  await app.client.click('#loginButton')
  await app.client.waitUntilTextExists('//span', 'Manage Wallets')
  t.pass()
})

test.serial('Activity page clicked', async t => {
  // click activity tab
  await app.client.click('#history')
  await app.client.waitUntilTextExists('//h3', 'All Activity')
  t.pass()
})
test.serial('Send tab clicked', async t => {
  // click send tab
  await app.client.click('#send')
  await app.client.waitUntilTextExists('//h3', 'Send Assets')
  t.pass()
})

test.serial('Receive tab clicked', async t => {
  // click receive tab
  await app.client.click('#receive')
  await app.client.waitUntilTextExists('//h3', 'Receive Assets')
  t.pass()
})
test.serial('Contacts tab clicked', async t => {
  // click contacts tab
  await app.client.click('#contacts')
  await app.client.waitUntilTextExists('//h3', 'Manage Contacts')
  t.pass()
})
test.serial('Token sale tab clicked', async t => {
  // click token sale tab
  await app.client.click('#tokensale')
  await app.client.waitUntilTextExists('//h3', 'Token Sale')
  t.pass()
})
test.serial('News tab clicked', async t => {
  // click token sale tab
  await app.client.click('#News')
  await app.client.waitUntilTextExists('//h3', 'News')
  t.pass()
})
test.serial('Settings tab clicked', async t => {
  // click settings tab
  await app.client.click('#settings')
  await app.client.waitUntilTextExists('//h3', 'Settings')
  await app.browserWindow.isVisible('//h3[text()=\'Settings\']')
  t.pass()
})
test.serial('Logout button clicked', async t => {
  //click logout
  await app.client.click('#logout')
  await app.client.waitUntilTextExists('//span', 'Create Wallet')
  t.pass()

})
<|endoftext|>


<commit_before>
App.page.home = function(force) {

	if (!force && !App.loc.loaded) {
		// if we arent forcing and theres no pos, then this was a home request. we need to wait a second
		console.log('QUE HOME PAGE')
		App.loc.bind('location-loaded', function() {
			App.page.home(force);
		});
		App.loc.bind('location-detected', function() {
			App.page.home(force);
		});

		return;
	}
	console.log('HOME PAGE')

	var homeSuccess = function() {
		$('.nav-back').removeClass('nav-back-show');
		$('.config-icon').addClass('config-icon-mobile-hide');
		$('.content').addClass('short-meal-list');

		App.showPage({
			page: 'home',
			title: 'Crunchbutton',
			data: {
				topCommunities: App.topCommunities,
				yourArea: App.loc.city() || 'your area',
				autofocus: $(window).width() >= 768 ? ' autofocus="autofocus"' : ''
			}
		});

		// @todo: put these in the css. @hacks
		if (navigator.userAgent.toLowerCase().indexOf('safari') > -1 && navigator.userAgent.toLowerCase().indexOf('mobile') == -1 && navigator.userAgent.toLowerCase().indexOf('chrome') == -1) {
			// safari desktop
			$('.location-detect').css({
				'margin-top': '2px',
				'height': '50px'
			});
		} else if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {
			// firefox desktop
			$('.location-detect').css({
				'margin-top': '0px',
				'height': '52px'
			});
		}
	};

	if (!force && App.loc.address() && App.restaurants.list === false) {
		// we have an address, but no restaurants
console.log('LOCATION NO REST')
		App.page.foodDelivery();

		return;

	} else {
		homeSuccess();
	}

	if (!force && App.loc.address() && App.restaurants.list && App.restaurants.list.length == 0) {
		App.loc.log();

		$('.home-greeting, .enter-location, .button-letseat-form').hide();
		$('.error-location').show();
console.log('LOCATION ERROR')
		App.track('Location Error', {
			lat: App.loc.pos().lat,
			lon: App.loc.pos().lon,
			address: App.loc.address()
		});

	} else {
console.log('JUST HOME')
		$('.location-address').val('');
		$('.error-location').hide();
		$('.home-greeting, .enter-location, .button-letseat-form').show();

	}
};

App.page.restaurant = function(id) {

	$('.config-icon').addClass('config-icon-mobile-hide');
	$('.nav-back').addClass('nav-back-show');

	App.cartHighlightEnabled = false;

	$('.content').removeClass('smaller-width');
	$('.content').removeClass('short-meal-list');

	App.cache('Restaurant', id, function() {
		if (App.restaurant && App.restaurant.permalink != id) {
			App.cart.resetOrder();
		}

		App.restaurant = this;
		var community = App.getCommunityById(App.restaurant.id_community);

		var lastOrderDelivery = false;
		var lastPayCash = false;

		if( App.config && App.config.user && App.config.user.presets && App.config.user.presets[App.restaurant.id_restaurant] ){
			// Check if the last user's order at this restaurant was a delivery type
			lastOrderDelivery = App.config.user.presets[App.restaurant.id_restaurant].delivery_type;
			// Check if the last user's order at this restaurant was cash type
			lastPayCash = App.config.user.presets[App.restaurant.id_restaurant].pay_type;
			App.order['delivery_type'] = lastOrderDelivery;
			App.order['pay_type'] = lastPayCash;
		}

		App.showPage({
			tracking: {
				title: 'Restaurant page loaded',
				data: {
					restaurant: App.restaurant.name
				}
			},
			page: 'restaurant',
			title: App.restaurant.name + ' | Food Delivery | Order from ' + ( community.name  ? community.name  : 'Local') + ' Restaurants | Crunchbutton',
			data: {
				restaurant: App.restaurant,
				presets: App.config.user.presets,
				lastOrderDelivery: lastOrderDelivery,
				user: App.config.user,
				community: community,
				form: {
					tip: App.order.tip,
					name: App.config.user.name,
					phone: App.phone.format(App.config.user.phone),
					address: App.config.user.address || App.loc.address(),
					notes: (App.config.user && App.config.user.presets && App.config.user.presets[App.restaurant.id_restaurant]) ? App.config.user.presets[App.restaurant.id_restaurant].notes : '',
					card: {
						number: App.config.user.card,
						month: App.config.user.card_exp_month,
						year: App.config.user.card_exp_year
					}
				}
			}
		});

		if (App.config.user.presets) {
			$('.payment-form').hide();
		}

		if (App.cart.hasItems()) {
			App.cart.reloadOrder();
		} else if (App.config.user && App.config.user.presets && App.config.user.presets[App.restaurant.id_restaurant]) {
			try {
				App.cart.loadOrder(App.config.user.presets[App.restaurant.id_restaurant]);
			} catch (e) {
				App.cart.loadOrder(App.restaurant.preset());
			}
		} else {
			App.cart.loadOrder(App.restaurant.preset());
		}

		// As the div restaurant-items has position:absolute this line will make sure the footer will not go up.
		$('.body').css({
			'min-height': $('.restaurant-items').height()
		});

		setTimeout(function() {
			var total = App.cart.updateTotal();
		},200);

		App.cartHighlightEnabled = false;

		if ( App.order['pay_type'] == 'cash' || lastPayCash == 'cash' ) {
			App.trigger.cash();
		} else {
			App.trigger.credit();
		}

		if( lastPayCash == 'cash' ){
			App.trigger.cash();
		} else if ( lastPayCash == 'card' ){
			App.trigger.credit();
		}

		// Rules at #669
		if( ( lastOrderDelivery == 'delivery' && App.restaurant.delivery == '1' ) ||
				( App.order['delivery_type'] == 'delivery' && App.restaurant.delivery == '1' ) ||
				( App.restaurant.takeout == '0' ) ||
				( lastOrderDelivery != 'takeout' && App.restaurant.delivery == '1' ) ){
				App.trigger.delivery();
		}

		// If the restaurant doesn't delivery
		if( App.order['delivery_type'] == 'takeout' || App.restaurant.delivery != '1') {
			App.trigger.takeout();
		}

		// If the user has presets at other's restaurants but he did not typed his address yet
		// and the actual restaurant is a delivery only #875
<<<<<<< HEAD
		if( ( App.restaurant.takeout == '0' || App.order['delivery_type'] == 'delivery' ) && !App.config.user.address ){
=======
		if( App.restaurant.takeout == '0' || App.order['delivery_type'] == 'delivery' && !App.config.user.address ){
>>>>>>> dd3d3dbad9973f2aaed676b0c006b3a6d528fa4e
			$('.payment-form').show();
			$('.delivery-payment-info, .content-padder-before').hide();
		}

		$( '.restaurant-gift' ).hide();

		App.credit.getCredit( function(){
			App.credit.show();
			App.cart.updateTotal();
		} );

		if (!App.config.user.id_user) {
			App.config.user.address = App.loc.enteredLoc;
			App.loc.enteredLoc = '';
		}

	});

};

/**
 * Order page. displayed after order, or at order history
 */
App.page.order = function(id) {

	$( '.config-icon' ).addClass( 'config-icon-mobile-hide' );
	$( '.nav-back' ).addClass( 'nav-back-show' );

	if (App.justCompleted) {
		App.justCompleted = false;
	}

	$('.content').addClass('smaller-width');
	$('.main-content').css('width','auto');

	// Just to make sure the user button will be shown
	App.signin.checkUser();

	App.cache('Order', id, function() {
		var order = this;

		if (!order.uuid) {
			History.replaceState({},'Crunchbutton','/orders');
			return;
		}

		App._order_uuid = id;

		App.facebook.preLoadOrderStatus();

		App.cache('Restaurant',order.id_restaurant, function() {
			var restaurant = this;

			App.showPage({
				title: 'Crunchbutton - Your Order',
				page: 'order',
				data: {
					order: order,
					restaurant: restaurant,
					user: App.config.user.has_auth
				}
			});

		});
	});
};

/**
 * Legal page. loaded from xhr.
 */
App.page.legal = function() {
	App.currentPage = 'legal';
	$.getJSON('/api/legal',function(json) {
		$('.main-content').html(json.data);
		App.refreshLayout();
	});
};

/**
 * Help page. loaded from xhr.
 */
App.page.help = function() {
	App.currentPage = 'help';
	$.getJSON('/api/help',function(json) {
		$('.main-content').html(json.data);
		App.refreshLayout();
	});
};

/**
 * Order page. only avaiable after a user has placed an order or signed up.
 * @todo: change to account page
 */
App.page.orders = function() {
	if (!App.config.user.id_user) {
		History.pushState({}, 'Crunchbutton', '/');
		return;
	}

	$( '.config-icon' ).addClass( 'config-icon-mobile-hide' );
	$( '.nav-back' ).addClass( 'nav-back-show' );

	$.getJSON('/api/user/orders',function(json) {
		App.showPage({
			title: 'Your Account',
			page: 'orders',
			data: {
				orders: json,
				user: App.user
			}
		});
	});

	App.refreshLayout();
};

/**
 * FoodDelivery's methods
 */
App.foodDelivery = {};

// before we change the url we need to make sure that there are restaurants at the typed place.
App.foodDelivery.getRestaurants = function(success, error) {
	if (!App.loc.pos()) {
		error();
		return;
	}

	var url = App.service + 'restaurants?lat=' + App.loc.pos().lat + '&lon=' + App.loc.pos().lon + '&range=' + ( App.loc.range || App.defaultRange );
	App.restaurants.list = false;

	$.getJSON(url, function(json) {
		App.restaurants.list = [];

		// There is no restaurant near to the user. Go home and show the error.
		if (typeof json['restaurants'] == 'undefined' || json['restaurants'].length == 0) {
			error();

		} else {

			for (var x in json.restaurants) {
				var res = new Restaurant(json.restaurants[x]);
				res.open();
				App.restaurants.list[App.restaurants.list.length] = res;
			};
			success();
		}
	});
}

App.foodDelivery.localizedContent = function(){
	// set the slogan and tagline
	try {
		var slogan = App.slogan.slogan;
		var sloganReplace = App.loc.prep() + ' ' + App.loc.city();

		sloganReplace = $.trim(sloganReplace);
		var tagline = App.tagline.tagline.replace('%s', sloganReplace);
		slogan = slogan.replace('%s', sloganReplace);

	} catch (e) {
		console.log('Failed to load dynamic text', App.slogan, App.tagline);
		var slogan = '';
		var tagline = '';
	}

	// set title
	var title = App.loc.city() + ' Food Delivery | Order Food from ' + (App.loc.city() || 'Local') + ' Restaurants | Crunchbutton';
	document.title = title;

	return {
		slogan: slogan,
		tagline: tagline,
		title: title
	};
}
/**
 * food delivery page
 */
App.page.foodDelivery = function(refresh) {
	if (refresh) {
		App.restaurants.list = false;
	}

	//App.loc.reverseGeocode(App.loc.pos().lat, App.loc.pos().lon, success, error);

	console.log('FOOD DELIVERY')
	var success = function() {
		// if we have a success and
		var loc = '/' + App.restaurants.permalink;
		if (loc != location.pathname) {
			History.pushState({}, 'Crunchbutton', '/' + App.restaurants.permalink);
			return;
		}

		$( '.config-icon' ).removeClass( 'config-icon-mobile-hide' );
		$( '.nav-back' ).removeClass( 'nav-back-show' );

		if (App.restaurants.list.length == 4) {
			$('.content').addClass('short-meal-list');
		} else {
			$('.content').removeClass('short-meal-list');
		}
		$('.content').removeClass('smaller-width');

		App.currentPage = 'food-delivery';

		var titles = App.foodDelivery.localizedContent();

		// sort the list by open or not
		App.restaurants.list.sort(sort_by(
			{
				name: '_open',
				reverse: true
			},
			{
				name: '_weight',
				primer: parseInt,
				reverse: true
			}
		));

		App.showPage({
			page: 'restaurants',
			data: {
				slogan: titles.slogan,
				tagline: titles.tagline,
				restaurants: App.restaurants.list
			}
		});
	};

	// we dont have any restaurants
	var error = function() {
		App.loadHome();
	};

	if (App.restaurants.list === false) {
		// we have not checked for restaurants. do that now.
		App.foodDelivery.getRestaurants(success, error);

	} else if (App.restaurants.list === []) {
		// there are no restaurants for this area. go back home
		error();

	} else {
		// we already have a restaurant list. display the restaurant page
		success();
	}
}
/**
 * Gift card page
 */
App.page.giftCard = function(){
	App.giftcard.show();
}<commit_msg>issue 912 - merge<commit_after>
App.page.home = function(force) {

	if (!force && !App.loc.loaded) {
		// if we arent forcing and theres no pos, then this was a home request. we need to wait a second
		console.log('QUE HOME PAGE')
		App.loc.bind('location-loaded', function() {
			App.page.home(force);
		});
		App.loc.bind('location-detected', function() {
			App.page.home(force);
		});

		return;
	}
	console.log('HOME PAGE')

	var homeSuccess = function() {
		$('.nav-back').removeClass('nav-back-show');
		$('.config-icon').addClass('config-icon-mobile-hide');
		$('.content').addClass('short-meal-list');

		App.showPage({
			page: 'home',
			title: 'Crunchbutton',
			data: {
				topCommunities: App.topCommunities,
				yourArea: App.loc.city() || 'your area',
				autofocus: $(window).width() >= 768 ? ' autofocus="autofocus"' : ''
			}
		});

		// @todo: put these in the css. @hacks
		if (navigator.userAgent.toLowerCase().indexOf('safari') > -1 && navigator.userAgent.toLowerCase().indexOf('mobile') == -1 && navigator.userAgent.toLowerCase().indexOf('chrome') == -1) {
			// safari desktop
			$('.location-detect').css({
				'margin-top': '2px',
				'height': '50px'
			});
		} else if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {
			// firefox desktop
			$('.location-detect').css({
				'margin-top': '0px',
				'height': '52px'
			});
		}
	};

	if (!force && App.loc.address() && App.restaurants.list === false) {
		// we have an address, but no restaurants
console.log('LOCATION NO REST')
		App.page.foodDelivery();

		return;

	} else {
		homeSuccess();
	}

	if (!force && App.loc.address() && App.restaurants.list && App.restaurants.list.length == 0) {
		App.loc.log();

		$('.home-greeting, .enter-location, .button-letseat-form').hide();
		$('.error-location').show();
console.log('LOCATION ERROR')
		App.track('Location Error', {
			lat: App.loc.pos().lat,
			lon: App.loc.pos().lon,
			address: App.loc.address()
		});

	} else {
console.log('JUST HOME')
		$('.location-address').val('');
		$('.error-location').hide();
		$('.home-greeting, .enter-location, .button-letseat-form').show();

	}
};

App.page.restaurant = function(id) {

	$('.config-icon').addClass('config-icon-mobile-hide');
	$('.nav-back').addClass('nav-back-show');

	App.cartHighlightEnabled = false;

	$('.content').removeClass('smaller-width');
	$('.content').removeClass('short-meal-list');

	App.cache('Restaurant', id, function() {
		if (App.restaurant && App.restaurant.permalink != id) {
			App.cart.resetOrder();
		}

		App.restaurant = this;
		var community = App.getCommunityById(App.restaurant.id_community);

		var lastOrderDelivery = false;
		var lastPayCash = false;

		if( App.config && App.config.user && App.config.user.presets && App.config.user.presets[App.restaurant.id_restaurant] ){
			// Check if the last user's order at this restaurant was a delivery type
			lastOrderDelivery = App.config.user.presets[App.restaurant.id_restaurant].delivery_type;
			// Check if the last user's order at this restaurant was cash type
			lastPayCash = App.config.user.presets[App.restaurant.id_restaurant].pay_type;
			App.order['delivery_type'] = lastOrderDelivery;
			App.order['pay_type'] = lastPayCash;
		}

		App.showPage({
			tracking: {
				title: 'Restaurant page loaded',
				data: {
					restaurant: App.restaurant.name
				}
			},
			page: 'restaurant',
			title: App.restaurant.name + ' | Food Delivery | Order from ' + ( community.name  ? community.name  : 'Local') + ' Restaurants | Crunchbutton',
			data: {
				restaurant: App.restaurant,
				presets: App.config.user.presets,
				lastOrderDelivery: lastOrderDelivery,
				user: App.config.user,
				community: community,
				form: {
					tip: App.order.tip,
					name: App.config.user.name,
					phone: App.phone.format(App.config.user.phone),
					address: App.config.user.address || App.loc.address(),
					notes: (App.config.user && App.config.user.presets && App.config.user.presets[App.restaurant.id_restaurant]) ? App.config.user.presets[App.restaurant.id_restaurant].notes : '',
					card: {
						number: App.config.user.card,
						month: App.config.user.card_exp_month,
						year: App.config.user.card_exp_year
					}
				}
			}
		});

		if (App.config.user.presets) {
			$('.payment-form').hide();
		}

		if (App.cart.hasItems()) {
			App.cart.reloadOrder();
		} else if (App.config.user && App.config.user.presets && App.config.user.presets[App.restaurant.id_restaurant]) {
			try {
				App.cart.loadOrder(App.config.user.presets[App.restaurant.id_restaurant]);
			} catch (e) {
				App.cart.loadOrder(App.restaurant.preset());
			}
		} else {
			App.cart.loadOrder(App.restaurant.preset());
		}

		// As the div restaurant-items has position:absolute this line will make sure the footer will not go up.
		$('.body').css({
			'min-height': $('.restaurant-items').height()
		});

		setTimeout(function() {
			var total = App.cart.updateTotal();
		},200);

		App.cartHighlightEnabled = false;

		if ( App.order['pay_type'] == 'cash' || lastPayCash == 'cash' ) {
			App.trigger.cash();
		} else {
			App.trigger.credit();
		}

		if( lastPayCash == 'cash' ){
			App.trigger.cash();
		} else if ( lastPayCash == 'card' ){
			App.trigger.credit();
		}

		// Rules at #669
		if( ( lastOrderDelivery == 'delivery' && App.restaurant.delivery == '1' ) ||
				( App.order['delivery_type'] == 'delivery' && App.restaurant.delivery == '1' ) ||
				( App.restaurant.takeout == '0' ) ||
				( lastOrderDelivery != 'takeout' && App.restaurant.delivery == '1' ) ){
				App.trigger.delivery();
		}

		// If the restaurant doesn't delivery
		if( App.order['delivery_type'] == 'takeout' || App.restaurant.delivery != '1') {
			App.trigger.takeout();
		}

		// If the user has presets at other's restaurants but he did not typed his address yet
		// and the actual restaurant is a delivery only #875
		if( ( App.restaurant.takeout == '0' || App.order['delivery_type'] == 'delivery' ) && !App.config.user.address ){
			$('.payment-form').show();
			$('.delivery-payment-info, .content-padder-before').hide();
		}

		$( '.restaurant-gift' ).hide();

		App.credit.getCredit( function(){
			App.credit.show();
			App.cart.updateTotal();
		} );

		if (!App.config.user.id_user) {
			App.config.user.address = App.loc.enteredLoc;
			App.loc.enteredLoc = '';
		}

	});

};

/**
 * Order page. displayed after order, or at order history
 */
App.page.order = function(id) {

	$( '.config-icon' ).addClass( 'config-icon-mobile-hide' );
	$( '.nav-back' ).addClass( 'nav-back-show' );

	if (App.justCompleted) {
		App.justCompleted = false;
	}

	$('.content').addClass('smaller-width');
	$('.main-content').css('width','auto');

	// Just to make sure the user button will be shown
	App.signin.checkUser();

	App.cache('Order', id, function() {
		var order = this;

		if (!order.uuid) {
			History.replaceState({},'Crunchbutton','/orders');
			return;
		}

		App._order_uuid = id;

		App.facebook.preLoadOrderStatus();

		App.cache('Restaurant',order.id_restaurant, function() {
			var restaurant = this;

			App.showPage({
				title: 'Crunchbutton - Your Order',
				page: 'order',
				data: {
					order: order,
					restaurant: restaurant,
					user: App.config.user.has_auth
				}
			});

		});
	});
};

/**
 * Legal page. loaded from xhr.
 */
App.page.legal = function() {
	App.currentPage = 'legal';
	$.getJSON('/api/legal',function(json) {
		$('.main-content').html(json.data);
		App.refreshLayout();
	});
};

/**
 * Help page. loaded from xhr.
 */
App.page.help = function() {
	App.currentPage = 'help';
	$.getJSON('/api/help',function(json) {
		$('.main-content').html(json.data);
		App.refreshLayout();
	});
};

/**
 * Order page. only avaiable after a user has placed an order or signed up.
 * @todo: change to account page
 */
App.page.orders = function() {
	if (!App.config.user.id_user) {
		History.pushState({}, 'Crunchbutton', '/');
		return;
	}

	$( '.config-icon' ).addClass( 'config-icon-mobile-hide' );
	$( '.nav-back' ).addClass( 'nav-back-show' );

	$.getJSON('/api/user/orders',function(json) {
		App.showPage({
			title: 'Your Account',
			page: 'orders',
			data: {
				orders: json,
				user: App.user
			}
		});
	});

	App.refreshLayout();
};

/**
 * FoodDelivery's methods
 */
App.foodDelivery = {};

// before we change the url we need to make sure that there are restaurants at the typed place.
App.foodDelivery.getRestaurants = function(success, error) {
	if (!App.loc.pos()) {
		error();
		return;
	}

	var url = App.service + 'restaurants?lat=' + App.loc.pos().lat + '&lon=' + App.loc.pos().lon + '&range=' + ( App.loc.range || App.defaultRange );
	App.restaurants.list = false;

	$.getJSON(url, function(json) {
		App.restaurants.list = [];

		// There is no restaurant near to the user. Go home and show the error.
		if (typeof json['restaurants'] == 'undefined' || json['restaurants'].length == 0) {
			error();

		} else {

			for (var x in json.restaurants) {
				var res = new Restaurant(json.restaurants[x]);
				res.open();
				App.restaurants.list[App.restaurants.list.length] = res;
			};
			success();
		}
	});
}

App.foodDelivery.localizedContent = function(){
	// set the slogan and tagline
	try {
		var slogan = App.slogan.slogan;
		var sloganReplace = App.loc.prep() + ' ' + App.loc.city();

		sloganReplace = $.trim(sloganReplace);
		var tagline = App.tagline.tagline.replace('%s', sloganReplace);
		slogan = slogan.replace('%s', sloganReplace);

	} catch (e) {
		console.log('Failed to load dynamic text', App.slogan, App.tagline);
		var slogan = '';
		var tagline = '';
	}

	// set title
	var title = App.loc.city() + ' Food Delivery | Order Food from ' + (App.loc.city() || 'Local') + ' Restaurants | Crunchbutton';
	document.title = title;

	return {
		slogan: slogan,
		tagline: tagline,
		title: title
	};
}
/**
 * food delivery page
 */
App.page.foodDelivery = function(refresh) {
	if (refresh) {
		App.restaurants.list = false;
	}

	//App.loc.reverseGeocode(App.loc.pos().lat, App.loc.pos().lon, success, error);

	console.log('FOOD DELIVERY')
	var success = function() {
		// if we have a success and
		var loc = '/' + App.restaurants.permalink;
		if (loc != location.pathname) {
			History.pushState({}, 'Crunchbutton', '/' + App.restaurants.permalink);
			return;
		}

		$( '.config-icon' ).removeClass( 'config-icon-mobile-hide' );
		$( '.nav-back' ).removeClass( 'nav-back-show' );

		if (App.restaurants.list.length == 4) {
			$('.content').addClass('short-meal-list');
		} else {
			$('.content').removeClass('short-meal-list');
		}
		$('.content').removeClass('smaller-width');

		App.currentPage = 'food-delivery';

		var titles = App.foodDelivery.localizedContent();

		// sort the list by open or not
		App.restaurants.list.sort(sort_by(
			{
				name: '_open',
				reverse: true
			},
			{
				name: '_weight',
				primer: parseInt,
				reverse: true
			}
		));

		App.showPage({
			page: 'restaurants',
			data: {
				slogan: titles.slogan,
				tagline: titles.tagline,
				restaurants: App.restaurants.list
			}
		});
	};

	// we dont have any restaurants
	var error = function() {
		App.loadHome();
	};

	if (App.restaurants.list === false) {
		// we have not checked for restaurants. do that now.
		App.foodDelivery.getRestaurants(success, error);

	} else if (App.restaurants.list === []) {
		// there are no restaurants for this area. go back home
		error();

	} else {
		// we already have a restaurant list. display the restaurant page
		success();
	}
}
/**
 * Gift card page
 */
App.page.giftCard = function(){
	App.giftcard.show();
}<|endoftext|>