<commit_before>BI.DynamicDatePopup = BI.inherit(BI.Widget, {
    constants: {
        tabHeight: 30,
        buttonHeight: 24
    },

    props: {
        baseCls: "bi-dynamic-date-popup",
        width: 248,
        supportDynamic: true,
    },

    _init: function () {
        BI.DynamicDatePopup.superclass._init.apply(this, arguments);
        var self = this, opts = this.options, c = this.constants;
        this.storeValue = {type: BI.DynamicDateCombo.Static};
        BI.createWidget({
            element: this,
            type: "bi.vertical",
            items: [{
                el: this._getTabJson()
            }, {
                el: {
                    type: "bi.grid",
                    items: [[{
                        type: "bi.text_button",
                        cls: "bi-high-light bi-split-top",
                        shadow: true,
                        text: BI.i18nText("BI-Basic_Clear"),
                        textHeight: c.buttonHeight - 1,
                        listeners: [{
                            eventName: BI.TextButton.EVENT_CHANGE,
                            action: function () {
                                self.fireEvent(BI.DynamicDatePopup.BUTTON_CLEAR_EVENT_CHANGE);
                            }
                        }]
                    }, {
                        type: "bi.text_button",
                        cls: "bi-split-left bi-split-right bi-high-light bi-split-top",
                        shadow: true,
                        textHeight: c.buttonHeight - 1,
                        text: BI.i18nText("BI-Multi_Date_Today"),
                        disabled: this._checkTodayValid(),
                        ref: function () {
                            self.todayButton = this;
                        },
                        listeners: [{
                            eventName: BI.TextButton.EVENT_CHANGE,
                            action: function () {
                                self.fireEvent(BI.DynamicDatePopup.BUTTON_lABEL_EVENT_CHANGE);
                            }
                        }]
                    }, {
                        type: "bi.text_button",
                        cls: "bi-high-light bi-split-top",
                        textHeight: c.buttonHeight - 1,
                        shadow: true,
                        text: BI.i18nText("BI-Basic_OK"),
                        listeners: [{
                            eventName: BI.TextButton.EVENT_CHANGE,
                            action: function () {
                                self.fireEvent(BI.DynamicDatePopup.BUTTON_OK_EVENT_CHANGE);
                            }
                        }]
                    }]],
                    height: 24
                },
            }]
        });
        this.setValue(opts.value);
    },

    _getTabJson: function () {
        var self = this, o = this.options;
        return {
            type: "bi.tab",
            logic: {
                dynamic: true
            },
            ref: function () {
                self.dateTab = this;
            },
            tab: {
                type: "bi.linear_segment",
                invisible: !o.supportDynamic,
                cls: "bi-split-bottom",
                height: this.constants.tabHeight,
                items: BI.createItems([{
                    text: BI.i18nText("BI-Multi_Date_YMD"),
                    value: BI.DynamicDateCombo.Static
                }, {
                    text: BI.i18nText("BI-Basic_Dynamic_Title"),
                    value: BI.DynamicDateCombo.Dynamic
                }], {
                    textAlign: "center"
                })
            },
            cardCreator: function (v) {
                switch (v) {
                    case BI.DynamicDateCombo.Dynamic:
                        return {
                            type: "bi.dynamic_date_card",
                            cls: "dynamic-date-pane",
                            listeners: [{
                                eventName: "EVENT_CHANGE",
                                action: function () {
                                    self._setInnerValue(self.year, v);
                                }
                            }],
                            min: self.options.min,
                            max: self.options.max,
                            ref: function () {
                                self.dynamicPane = this;
                            }
                        };
                    case BI.DynamicDateCombo.Static:
                    default:
                        return {
                            type: "bi.date_calendar_popup",
                            behaviors: o.behaviors,
                            min: self.options.min,
                            max: self.options.max,
                            listeners: [{
                                eventName: BI.DateCalendarPopup.EVENT_CHANGE,
                                action: function () {
                                    self.fireEvent(BI.DynamicDatePopup.EVENT_CHANGE);
                                }
                            }, {
                                eventName: BI.DateCalendarPopup.EVENT_BEFORE_YEAR_MONTH_POPUPVIEW,
                                action: function () {
                                    self.fireEvent(BI.DynamicDatePopup.EVENT_BEFORE_YEAR_MONTH_POPUPVIEW);
                                }
                            }],
                            ref: function () {
                                self.ymd = this;
                            }
                        };
                }
            },
            listeners: [{
                eventName: BI.Tab.EVENT_CHANGE,
                action: function () {
                    var v = self.dateTab.getSelect();
                    switch (v) {
                        case BI.DynamicDateCombo.Static:
                            var date = BI.DynamicDateHelper.getCalculation(self.dynamicPane.getValue());
                            self.ymd.setValue({
                                year: date.getFullYear(),
                                month: date.getMonth() + 1,
                                day: date.getDate()
                            });
                            self._setInnerValue();
                            break;
                        case BI.DynamicDateCombo.Dynamic:
                        default:
                            if(self.storeValue && self.storeValue.type === BI.DynamicDateCombo.Dynamic) {
                                self.dynamicPane.setValue(self.storeValue.value);
                            }else{
                                self.dynamicPane.setValue({
                                    year: 0
                                });
                            }
                            self._setInnerValue();
                            break;
                    }
                }
            }]
        };
    },

    _setInnerValue: function () {
        if (this.dateTab.getSelect() === BI.DynamicDateCombo.Static) {
            this.todayButton.setValue(BI.i18nText("BI-Multi_Date_Today"));
            this.textButton.setEnable(!this._checkTodayValid());
        } else {
            var date = BI.DynamicDateHelper.getCalculation(this.dynamicPane.getValue());
            date = BI.print(date, "%Y-%X-%d");
            this.todayButton.setValue(date);
            this.todayButton.setEnable(false);
        }
    },

    _checkValueValid: function (value) {
        return BI.isNull(value) || BI.isEmptyObject(value) || BI.isEmptyString(value);
    },

    _checkTodayValid: function () {
        var o = this.options;
        var today = BI.getDate();
        return !!BI.checkDateVoid(today.getFullYear(), today.getMonth() + 1, today.getDate(), o.min, o.max)[0];
    },

    setMinDate: function (minDate) {
        if (this.options.min !== minDate) {
            this.options.min = minDate;
            this.ymd && this.ymd.setMinDate(minDate);
            this.dynamicPane && this.ymd.setMinDate(minDate);
        }
    },

    setMaxDate: function (maxDate) {
        if (this.options.max !== maxDate) {
            this.options.max = maxDate;
            this.ymd && this.ymd.setMaxDate(maxDate);
            this.dynamicPane && this.ymd.setMaxDate(maxDate);
        }
    },

    setValue: function (v) {
        this.storeValue = v;
        var self = this;
        var type, value;
        v = v || {};
        type = v.type || BI.DynamicDateCombo.Static;
        value = v.value || v;
        this.dateTab.setSelect(type);
        switch (type) {
            case BI.DynamicDateCombo.Dynamic:
                this.dynamicPane.setValue(value);
                self._setInnerValue();
                break;
            case BI.DynamicDateCombo.Static:
            default:
                if (this._checkValueValid(value)) {
                    var date = BI.getDate();
                    this.ymd.setValue({
                        year: date.getFullYear(),
                        month: date.getMonth() + 1,
                        day: date.getDate()
                    });
                    this.todayButton.setValue(BI.i18nText("BI-Multi_Date_Today"));
                } else {
                    this.ymd.setValue(value);
                    this.todayButton.setValue(BI.i18nText("BI-Multi_Date_Today"));
                }
                this.todayButton.setEnable(!this._checkTodayValid());
                break;
        }
    },

    getValue: function () {
        return {
            type: this.dateTab.getSelect(),
            value: this.dateTab.getValue()
        };
    }
});
BI.DynamicDatePopup.EVENT_CHANGE = "EVENT_CHANGE";
BI.DynamicDatePopup.BUTTON_OK_EVENT_CHANGE = "BUTTON_OK_EVENT_CHANGE";
BI.DynamicDatePopup.BUTTON_lABEL_EVENT_CHANGE = "BUTTON_lABEL_EVENT_CHANGE";
BI.DynamicDatePopup.BUTTON_CLEAR_EVENT_CHANGE = "BUTTON_CLEAR_EVENT_CHANGE";
BI.DynamicDatePopup.EVENT_BEFORE_YEAR_MONTH_POPUPVIEW = "EVENT_BEFORE_YEAR_MONTH_POPUPVIEW";
BI.shortcut("bi.dynamic_date_popup", BI.DynamicDatePopup);<commit_msg>无JIRA任务 变量修改<commit_after>BI.DynamicDatePopup = BI.inherit(BI.Widget, {
    constants: {
        tabHeight: 30,
        buttonHeight: 24
    },

    props: {
        baseCls: "bi-dynamic-date-popup",
        width: 248,
        supportDynamic: true,
    },

    _init: function () {
        BI.DynamicDatePopup.superclass._init.apply(this, arguments);
        var self = this, opts = this.options, c = this.constants;
        this.storeValue = {type: BI.DynamicDateCombo.Static};
        BI.createWidget({
            element: this,
            type: "bi.vertical",
            items: [{
                el: this._getTabJson()
            }, {
                el: {
                    type: "bi.grid",
                    items: [[{
                        type: "bi.text_button",
                        cls: "bi-high-light bi-split-top",
                        shadow: true,
                        text: BI.i18nText("BI-Basic_Clear"),
                        textHeight: c.buttonHeight - 1,
                        listeners: [{
                            eventName: BI.TextButton.EVENT_CHANGE,
                            action: function () {
                                self.fireEvent(BI.DynamicDatePopup.BUTTON_CLEAR_EVENT_CHANGE);
                            }
                        }]
                    }, {
                        type: "bi.text_button",
                        cls: "bi-split-left bi-split-right bi-high-light bi-split-top",
                        shadow: true,
                        textHeight: c.buttonHeight - 1,
                        text: BI.i18nText("BI-Multi_Date_Today"),
                        disabled: this._checkTodayValid(),
                        ref: function () {
                            self.todayButton = this;
                        },
                        listeners: [{
                            eventName: BI.TextButton.EVENT_CHANGE,
                            action: function () {
                                self.fireEvent(BI.DynamicDatePopup.BUTTON_lABEL_EVENT_CHANGE);
                            }
                        }]
                    }, {
                        type: "bi.text_button",
                        cls: "bi-high-light bi-split-top",
                        textHeight: c.buttonHeight - 1,
                        shadow: true,
                        text: BI.i18nText("BI-Basic_OK"),
                        listeners: [{
                            eventName: BI.TextButton.EVENT_CHANGE,
                            action: function () {
                                self.fireEvent(BI.DynamicDatePopup.BUTTON_OK_EVENT_CHANGE);
                            }
                        }]
                    }]],
                    height: 24
                },
            }]
        });
        this.setValue(opts.value);
    },

    _getTabJson: function () {
        var self = this, o = this.options;
        return {
            type: "bi.tab",
            logic: {
                dynamic: true
            },
            ref: function () {
                self.dateTab = this;
            },
            tab: {
                type: "bi.linear_segment",
                invisible: !o.supportDynamic,
                cls: "bi-split-bottom",
                height: this.constants.tabHeight,
                items: BI.createItems([{
                    text: BI.i18nText("BI-Multi_Date_YMD"),
                    value: BI.DynamicDateCombo.Static
                }, {
                    text: BI.i18nText("BI-Basic_Dynamic_Title"),
                    value: BI.DynamicDateCombo.Dynamic
                }], {
                    textAlign: "center"
                })
            },
            cardCreator: function (v) {
                switch (v) {
                    case BI.DynamicDateCombo.Dynamic:
                        return {
                            type: "bi.dynamic_date_card",
                            cls: "dynamic-date-pane",
                            listeners: [{
                                eventName: "EVENT_CHANGE",
                                action: function () {
                                    self._setInnerValue(self.year, v);
                                }
                            }],
                            min: self.options.min,
                            max: self.options.max,
                            ref: function () {
                                self.dynamicPane = this;
                            }
                        };
                    case BI.DynamicDateCombo.Static:
                    default:
                        return {
                            type: "bi.date_calendar_popup",
                            behaviors: o.behaviors,
                            min: self.options.min,
                            max: self.options.max,
                            listeners: [{
                                eventName: BI.DateCalendarPopup.EVENT_CHANGE,
                                action: function () {
                                    self.fireEvent(BI.DynamicDatePopup.EVENT_CHANGE);
                                }
                            }, {
                                eventName: BI.DateCalendarPopup.EVENT_BEFORE_YEAR_MONTH_POPUPVIEW,
                                action: function () {
                                    self.fireEvent(BI.DynamicDatePopup.EVENT_BEFORE_YEAR_MONTH_POPUPVIEW);
                                }
                            }],
                            ref: function () {
                                self.ymd = this;
                            }
                        };
                }
            },
            listeners: [{
                eventName: BI.Tab.EVENT_CHANGE,
                action: function () {
                    var v = self.dateTab.getSelect();
                    switch (v) {
                        case BI.DynamicDateCombo.Static:
                            var date = BI.DynamicDateHelper.getCalculation(self.dynamicPane.getValue());
                            self.ymd.setValue({
                                year: date.getFullYear(),
                                month: date.getMonth() + 1,
                                day: date.getDate()
                            });
                            self._setInnerValue();
                            break;
                        case BI.DynamicDateCombo.Dynamic:
                        default:
                            if(self.storeValue && self.storeValue.type === BI.DynamicDateCombo.Dynamic) {
                                self.dynamicPane.setValue(self.storeValue.value);
                            }else{
                                self.dynamicPane.setValue({
                                    year: 0
                                });
                            }
                            self._setInnerValue();
                            break;
                    }
                }
            }]
        };
    },

    _setInnerValue: function () {
        if (this.dateTab.getSelect() === BI.DynamicDateCombo.Static) {
            this.todayButton.setValue(BI.i18nText("BI-Multi_Date_Today"));
            this.todayButton.setEnable(!this._checkTodayValid());
        } else {
            var date = BI.DynamicDateHelper.getCalculation(this.dynamicPane.getValue());
            date = BI.print(date, "%Y-%X-%d");
            this.todayButton.setValue(date);
            this.todayButton.setEnable(false);
        }
    },

    _checkValueValid: function (value) {
        return BI.isNull(value) || BI.isEmptyObject(value) || BI.isEmptyString(value);
    },

    _checkTodayValid: function () {
        var o = this.options;
        var today = BI.getDate();
        return !!BI.checkDateVoid(today.getFullYear(), today.getMonth() + 1, today.getDate(), o.min, o.max)[0];
    },

    setMinDate: function (minDate) {
        if (this.options.min !== minDate) {
            this.options.min = minDate;
            this.ymd && this.ymd.setMinDate(minDate);
            this.dynamicPane && this.ymd.setMinDate(minDate);
        }
    },

    setMaxDate: function (maxDate) {
        if (this.options.max !== maxDate) {
            this.options.max = maxDate;
            this.ymd && this.ymd.setMaxDate(maxDate);
            this.dynamicPane && this.ymd.setMaxDate(maxDate);
        }
    },

    setValue: function (v) {
        this.storeValue = v;
        var self = this;
        var type, value;
        v = v || {};
        type = v.type || BI.DynamicDateCombo.Static;
        value = v.value || v;
        this.dateTab.setSelect(type);
        switch (type) {
            case BI.DynamicDateCombo.Dynamic:
                this.dynamicPane.setValue(value);
                self._setInnerValue();
                break;
            case BI.DynamicDateCombo.Static:
            default:
                if (this._checkValueValid(value)) {
                    var date = BI.getDate();
                    this.ymd.setValue({
                        year: date.getFullYear(),
                        month: date.getMonth() + 1,
                        day: date.getDate()
                    });
                    this.todayButton.setValue(BI.i18nText("BI-Multi_Date_Today"));
                } else {
                    this.ymd.setValue(value);
                    this.todayButton.setValue(BI.i18nText("BI-Multi_Date_Today"));
                }
                this.todayButton.setEnable(!this._checkTodayValid());
                break;
        }
    },

    getValue: function () {
        return {
            type: this.dateTab.getSelect(),
            value: this.dateTab.getValue()
        };
    }
});
BI.DynamicDatePopup.EVENT_CHANGE = "EVENT_CHANGE";
BI.DynamicDatePopup.BUTTON_OK_EVENT_CHANGE = "BUTTON_OK_EVENT_CHANGE";
BI.DynamicDatePopup.BUTTON_lABEL_EVENT_CHANGE = "BUTTON_lABEL_EVENT_CHANGE";
BI.DynamicDatePopup.BUTTON_CLEAR_EVENT_CHANGE = "BUTTON_CLEAR_EVENT_CHANGE";
BI.DynamicDatePopup.EVENT_BEFORE_YEAR_MONTH_POPUPVIEW = "EVENT_BEFORE_YEAR_MONTH_POPUPVIEW";
BI.shortcut("bi.dynamic_date_popup", BI.DynamicDatePopup);<|endoftext|>


<commit_before>var Montage = require("montage/core/core").Montage;

/**
 * @class SnapshotService
 * @extends Montage
 */
exports.SnapshotService = Montage.specialize(/** @lends SnapshotService# */ {
    _cache: {
        value: null
    },

    constructor: {
        value: function() {
            this._cache = new Map();
        }
    },

    saveSnapshotForTypeNameAndId: {
        value: function(snapshot, typeName, id) {
            if (!this._cache.has(typeName)) {
                this._cache.set(typeName, new Map());
            }

            this._cache.get(typeName).set(id, this._getClone(snapshot));
        }
    },

    getSnapshotForTypeNameAndId: {
        value: function(typeName, id) {
            var result;
            if (this._cache.has(typeName)) {
                result = this._cache.get(typeName).get(id);
            }
            return result;
        }
    },

    removeSnapshotForTypeNameAndId: {
        value: function(typeName, id) {
            if (this._cache.has(typeName)) {
                this._cache.get(typeName).delete(id);
            }
        }
    },

    getDifferenceWithSnapshotForTypeNameAndId: {
        value: function(rawData, typeName, id) {
            var difference = this._getClone(rawData),
                cachedVersion, cachedKeys,
                key;
            if (this._cache.has(typeName)) {
                cachedVersion = this._cache.get(typeName).get(id);
            }
            if (cachedVersion) {
                cachedKeys = Object.keys(cachedVersion);
                for (var i = 0, length = cachedKeys.length; i < length; i++) {
                    key = cachedKeys[i];
                    if (this._areSameValues(rawData[key], cachedVersion[key])) {
                        delete difference[key];
                    }
                }
            }
            return difference;
        }
    },

    _getClone: {
        value: function(object) {
            if (object) {
                var result = Object.create(null),
                    keys = Object.keys(object),
                    key, temp, j, arrayLength, arrayKeys;
                for (var i = 0, length = keys.length; i < length; i++) {
                    key = keys[i];
                    if (Array.isArray(object[key])) {
                        result[key] = this._getArrayClone(object[key]);
                    } else if (typeof object[key] === "object") {
                        result[key] = this._getClone(object[key]);
                    } else {
                        result[key] = object[key];
                    }
                }
            } else {
                result = object;
            }
            return result;
        }
    },

    _getArrayClone: {
        value: function(array) {
            var result = [],
                value;
            for (var i = 0, length = array.length; i < length; i++) {
                value = array[i];
                if (Array.isArray(value)) {
                    result.push(this._getArrayClone(value));
                } else if (typeof value === "object") {
                    result.push(this._getClone(value));
                } else {
                    result.push(value);
                }
            }
            return result;
        }
    },

    _areSameValues: {
        value: function(a, b) {
            var result = a === b;
            if (!result) {
                if (typeof a === "object" && typeof b === "object") {
                    result = !!a === !!b;
                    if (result) {
                        var aKeys = Object.keys(a).sort(), aKey, aValue,
                            bKeys = Object.keys(b).sort(), bKey, bValue;
                        result = aKeys.filter(function(x) { return a[x] !== null }).length === bKeys.filter(function(x) { return b[x] !== null }).length;
                        if (result) {
                            for (var i = 0, length = aKeys.length; i < length; i++) {
                                aKey = aKeys[i];
                                bKey = bKeys[i];
                                if (aKey === bKey) {
                                    aValue = a[aKey];
                                    bValue = b[bKey];
                                    if (!this._areSameValues(aValue, bValue)) {
                                        result = false;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return result;
        }
    }
});
<commit_msg>Fix object comparison in snapshot service<commit_after>var Montage = require("montage/core/core").Montage;

/**
 * @class SnapshotService
 * @extends Montage
 */
exports.SnapshotService = Montage.specialize(/** @lends SnapshotService# */ {
    _cache: {
        value: null
    },

    constructor: {
        value: function() {
            this._cache = new Map();
        }
    },

    saveSnapshotForTypeNameAndId: {
        value: function(snapshot, typeName, id) {
            if (!this._cache.has(typeName)) {
                this._cache.set(typeName, new Map());
            }

            this._cache.get(typeName).set(id, this._getClone(snapshot));
        }
    },

    getSnapshotForTypeNameAndId: {
        value: function(typeName, id) {
            var result;
            if (this._cache.has(typeName)) {
                result = this._cache.get(typeName).get(id);
            }
            return result;
        }
    },

    removeSnapshotForTypeNameAndId: {
        value: function(typeName, id) {
            if (this._cache.has(typeName)) {
                this._cache.get(typeName).delete(id);
            }
        }
    },

    getDifferenceWithSnapshotForTypeNameAndId: {
        value: function(rawData, typeName, id) {
            var difference = this._getClone(rawData),
                cachedVersion, cachedKeys,
                key;
            if (this._cache.has(typeName)) {
                cachedVersion = this._cache.get(typeName).get(id);
            }
            if (cachedVersion) {
                cachedKeys = Object.keys(cachedVersion);
                for (var i = 0, length = cachedKeys.length; i < length; i++) {
                    key = cachedKeys[i];
                    if (this._areSameValues(rawData[key], cachedVersion[key])) {
                        delete difference[key];
                    }
                }
            }
            return difference;
        }
    },

    _getClone: {
        value: function(object) {
            if (object) {
                var result = Object.create(null),
                    keys = Object.keys(object),
                    key, temp, j, arrayLength, arrayKeys;
                for (var i = 0, length = keys.length; i < length; i++) {
                    key = keys[i];
                    if (Array.isArray(object[key])) {
                        result[key] = this._getArrayClone(object[key]);
                    } else if (typeof object[key] === "object") {
                        result[key] = this._getClone(object[key]);
                    } else {
                        result[key] = object[key];
                    }
                }
            } else {
                result = object;
            }
            return result;
        }
    },

    _getArrayClone: {
        value: function(array) {
            var result = [],
                value;
            for (var i = 0, length = array.length; i < length; i++) {
                value = array[i];
                if (Array.isArray(value)) {
                    result.push(this._getArrayClone(value));
                } else if (typeof value === "object") {
                    result.push(this._getClone(value));
                } else {
                    result.push(value);
                }
            }
            return result;
        }
    },

    _areSameValues: {
        value: function(a, b) {
            var result = a === b;
            if (!result) {
                if (typeof a === "object" && typeof b === "object") {
                    result = !!a === !!b;
                    if (result) {
                        var aKeys = Object.keys(a).sort(), aValue,
                            bKeys = Object.keys(b).sort(), bValue,
                            key;
                        result = aKeys.filter(function(x) { return a[x] !== null }).length === bKeys.filter(function(x) { return b[x] !== null }).length;
                        if (result) {
                            for (var i = 0, length = bKeys.length; i < length; i++) {
                                key = bKeys[i];
                                aValue = a[key];
                                bValue = b[key];
                                if (!this._areSameValues(aValue, bValue)) {
                                    result = false;
                                    break;
                                }
                            }
                        }
                    }
                }
            }
            return result;
        }
    }
});
<|endoftext|>


<commit_before>/**
 * Cross-Site Request Forgery Protection Settings
 * (sails.config.csrf)
 *
 * CSRF tokens are like a tracking chip.  While a session tells the server that a user
 * "is who they say they are", a csrf token tells the server "you are where you say you are".
 *
 * When enabled, all non-GET requests to the Sails server must be accompanied by
 * a special token, identified as the '_csrf' parameter.
 *
 * This option protects your Sails app against cross-site request forgery (or CSRF) attacks.
 * A would-be attacker needs not only a user's session cookie, but also this timestamped,
 * secret CSRF token, which is refreshed/granted when the user visits a URL on your app's domain.
 *
 * This allows us to have certainty that our users' requests haven't been hijacked,
 * and that the requests they're making are intentional and legitimate.
 *
 * This token has a short-lived expiration timeline, and must be acquired by either:
 *
 * (a)		For traditional view-driven web apps:
 *			Fetching it from one of your views, where it may be accessed as
 *			a local variable, e.g.:
 *			<form>
 *				<input type="hidden" name="_csrf" value="<%= _csrf %>" />
 *			</form>
 *
 * or (b)	For AJAX/Socket-heavy and/or single-page apps:
 *			Sending a GET request to the `/csrfToken` route, where it will be returned
 *			as JSON, e.g.:
 *			{ _csrf: 'ajg4JD(JGdajhLJALHDa' }
 *
 *
 * Enabling this option requires managing the token in your front-end app.
 * For traditional web apps, it's as easy as passing the data from a view into a form action.
 * In AJAX/Socket-heavy apps, just send a GET request to the /csrfToken route to get a valid token.
 *
 * For more information on CSRF, check out:
 * http://en.wikipedia.org/wiki/Cross-site_request_forgery
 *
 * For more information on this configuration file, including info on CSRF + CORS, see:
 * http://sailsjs.org/#!/documentation/reference/sails.config/sails.config.csrf.html
 *
 */

/****************************************************************************
*                                                                           *
* Enabled CSRF protection for your site?                                    *
*                                                                           *
****************************************************************************/

// module.exports.csrf = false;

/****************************************************************************
*                                                                           *
* You may also specify more fine-grained settings for CSRF, including the   *
* domains which are allowed to request the CSRF token via AJAX. These       *
* settings override the general CORS settings in your config/cors.js file.  *
*                                                                           *
****************************************************************************/

// module.exports.csrf = {
//    grantTokenViaAjax: true,
//    origin: ''
// }
<commit_msg>add boilerplate example of using sails.config.csrf.routesDisabled (e.g. for a webhook)<commit_after>/**
 * Cross-Site Request Forgery Protection Settings
 * (sails.config.csrf)
 *
 * CSRF tokens are like a tracking chip.  While a session tells the server that a user
 * "is who they say they are", a csrf token tells the server "you are where you say you are".
 *
 * When enabled, all non-GET requests to the Sails server must be accompanied by
 * a special token, identified as the '_csrf' parameter.
 *
 * This option protects your Sails app against cross-site request forgery (or CSRF) attacks.
 * A would-be attacker needs not only a user's session cookie, but also this timestamped,
 * secret CSRF token, which is refreshed/granted when the user visits a URL on your app's domain.
 *
 * This allows us to have certainty that our users' requests haven't been hijacked,
 * and that the requests they're making are intentional and legitimate.
 *
 * This token has a short-lived expiration timeline, and must be acquired by either:
 *
 * (a)		For traditional view-driven web apps:
 *			Fetching it from one of your views, where it may be accessed as
 *			a local variable, e.g.:
 *			<form>
 *				<input type="hidden" name="_csrf" value="<%= _csrf %>" />
 *			</form>
 *
 * or (b)	For AJAX/Socket-heavy and/or single-page apps:
 *			Sending a GET request to the `/csrfToken` route, where it will be returned
 *			as JSON, e.g.:
 *			{ _csrf: 'ajg4JD(JGdajhLJALHDa' }
 *
 *
 * Enabling this option requires managing the token in your front-end app.
 * For traditional web apps, it's as easy as passing the data from a view into a form action.
 * In AJAX/Socket-heavy apps, just send a GET request to the /csrfToken route to get a valid token.
 *
 * For more information on CSRF, check out:
 * http://en.wikipedia.org/wiki/Cross-site_request_forgery
 *
 * For more information on this configuration file, including info on CSRF + CORS, see:
 * http://sailsjs.org/documentation/reference/configuration/sails-config-csrf
 *
 */

/****************************************************************************
*                                                                           *
* Enabled CSRF protection for your site?                                    *
*                                                                           *
****************************************************************************/

// module.exports.csrf = false;

/****************************************************************************
*                                                                           *
* You may also specify more fine-grained settings for CSRF, including the   *
* domains which are allowed to request the CSRF token via AJAX. These       *
* settings override the general CORS settings in your config/cors.js file.  *
*                                                                           *
****************************************************************************/

// module.exports.csrf = {
//   grantTokenViaAjax: true,
//   origin: '',
//   routesDisabled: [ 'POST /webhooks/stripe/cancel-subscription' ]
// }
<|endoftext|>


<commit_before>/**
 * HTTP Server Settings
 * (sails.config.http)
 *
 * Configuration for the underlying HTTP server in Sails.
 * Only applies to HTTP requests (not WebSockets)
 *
 * For more information on configuration, check out:
 * http://sailsjs.org/#!/documentation/reference/sails.config/sails.config.http.html
 */

module.exports.http = {

  /****************************************************************************
  *                                                                           *
  * Express middleware to use for every Sails request. To add custom          *
  * middleware to the mix, add a function to the middleware config object and *
  * add its key to the "order" array. The $custom key is reserved for         *
  * backwards-compatibility with Sails v0.9.x apps that use the               *
  * `customMiddleware` config option.                                         *
  *                                                                           *
  ****************************************************************************/

  middleware: {

  /***************************************************************************
  *                                                                          *
  * The order in which middleware should be run for HTTP request. (the Sails *
  * router is invoked by the "router" middleware below.)                     *
  *                                                                          *
  ***************************************************************************/

    // order: [
    //   'startRequestTimer',
    //   'cookieParser',
    //   'session',
    //   'myRequestLogger',
    //   'bodyParser',
    //   'handleBodyParserError',
    //   'compress',
    //   'methodOverride',
    //   'poweredBy',
    //   '$custom',
    //   'router',
    //   'www',
    //   'favicon',
    //   '404',
    //   '500'
    // ],

  /****************************************************************************
  *                                                                           *
  * Example custom middleware; logs each request to the console.              *
  *                                                                           *
  ****************************************************************************/

    // myRequestLogger: function (req, res, next) {
    //     console.log("Requested :: ", req.method, req.url);
    //     return next();
    // }

  /***************************************************************************
  *                                                                          *
  * The body parser that will handle incoming multipart HTTP requests. By    *
  * default as of v0.10, Sails uses                                          *
  * [skipper](http://github.com/balderdashy/skipper). See                    *
  * http://www.senchalabs.org/connect/multipart.html for other options.      *
  *                                                                          *
  * Note that Sails uses an internal instance of Skipper by default; to      *
  * override it and specify more options, make sure to "npm install skipper" *
  * in your project first.  You can also specify a different body parser or  *
  * a custom function with req, res and next parameters (just like any other *
  * middleware function).                                                    *
  *                                                                          *
  ***************************************************************************/

    // bodyParser: require('skipper')({strict: true})

  },

  /***************************************************************************
  *                                                                          *
  * The number of seconds to cache flat files on disk being served by        *
  * Express static middleware (by default, these files are in `.tmp/public`) *
  *                                                                          *
  * The HTTP static cache is only active in a 'production' environment,      *
  * since that's the only time Express will cache flat-files.                *
  *                                                                          *
  ***************************************************************************/

  // cache: 31557600000
};
<commit_msg>Update to boilerplate config re: https://github.com/balderdashy/sails/issues/3692<commit_after>/**
 * HTTP Server Settings
 * (sails.config.http)
 *
 * Configuration for the underlying HTTP server in Sails.
 * Only applies to HTTP requests (not WebSockets)
 *
 * For more information on configuration, check out:
 * http://sailsjs.org/#!/documentation/reference/sails.config/sails.config.http.html
 */

module.exports.http = {

  /****************************************************************************
  *                                                                           *
  * Express middleware to use for every Sails request. To add custom          *
  * middleware to the mix, add a function to the middleware config object and *
  * add its key to the "order" array. The $custom key is reserved for         *
  * backwards-compatibility with Sails v0.9.x apps that use the               *
  * `customMiddleware` config option.                                         *
  *                                                                           *
  ****************************************************************************/

  middleware: {

  /***************************************************************************
  *                                                                          *
  * The order in which middleware should be run for HTTP request. (the Sails *
  * router is invoked by the "router" middleware below.)                     *
  *                                                                          *
  ***************************************************************************/

    // order: [
    //   'startRequestTimer',
    //   'cookieParser',
    //   'session',
    //   'myRequestLogger',
    //   'bodyParser',
    //   'handleBodyParserError',
    //   'compress',
    //   'methodOverride',
    //   'poweredBy',
    //   '$custom',
    //   'router',
    //   'www',
    //   'favicon',
    //   '404',
    //   '500'
    // ],

  /****************************************************************************
  *                                                                           *
  * Example custom middleware; logs each request to the console.              *
  *                                                                           *
  ****************************************************************************/

    // myRequestLogger: function (req, res, next) {
    //     console.log("Requested :: ", req.method, req.url);
    //     return next();
    // }

  /***************************************************************************
  *                                                                          *
  * The body parser that will handle incoming multipart HTTP requests. By    *
  * default as of v0.10, Sails uses                                          *
  * [skipper](http://github.com/balderdashy/skipper). See                    *
  * http://www.senchalabs.org/connect/multipart.html for other options.      *
  *                                                                          *
  * Note that Sails uses an internal instance of Skipper by default; to      *
  * override it and specify more options, make sure to "npm install skipper" *
  * in your project first.  You can also specify a different body parser or  *
  * a custom function with req, res and next parameters (just like any other *
  * middleware function).                                                    *
  *                                                                          *
  ***************************************************************************/

    // bodyParser: require('skipper')({strict: true})

  },

  /***************************************************************************
   *
  * The number of milliseconds to cache static assets in production.
  * These are any flat files like images, scripts, styleshseets, etc.
  * that are served by the static middleware.  By default, these files
  * are served from `.tmp/public`, a hidden folder compiled by Grunt.
  *
  ***************************************************************************/

  // cache: 31557600000
};
<|endoftext|>


<commit_before>/**
 *
 */
function initESigDialog(){
	// Make the esig with a jQuery UI dialog.
    var electronicSignatureDialog = $('.eSigDialog').dialog({
    	beforeClose: function(event, ui) {
    		$('#eSigInput').val('');
    	},
        autoOpen: false,
        width: 350,   // body width is 768px
        modal: true
    });

    var openESigButton = $('#signCalculationButton');
    openESigButton.on('click', function(event) {
        event.preventDefault();

        var windowHeight = 170;
        electronicSignatureDialog.dialog('option', 'height', windowHeight);
        electronicSignatureDialog.dialog('open');
    });

    $('#eSigForm').on('submit', function(event) {
    	event.preventDefault();
    	var eSigCode = $('#eSigInput').val();
    	$.ajax({
			url: "signCalculation",
			type: 'POST',
			dataType: 'json',
			data: {
				eSig: eSigCode
			},
			/*
			 * disable button and add loading text
			 * */
			beforeSend: function() {
				$('#eSigButton').prop('disabled', true);
				$('#eSigButton').text("Signing");
			},
			success: function(result) {
				if(result.status == "Success") {
					// Redirect to the success page.
					window.location.replace("successfulSign");
				}
				else {
					// Change the span text to the given error text
					$('#eSigErrorSpan').text(result.status);
					$('#eSigButton').prop('disabled', false);
					$('#eSigButton').text("Sign");
				}
			}
		});
    });

    var cancelESigButton = $('#cancelESigButton');
    cancelESigButton.on('click', function(event) {
    	event.preventDefault();
    	electronicSignatureDialog.dialog('close');
    });
}<commit_msg>The error message is now properly cleared after using an invalid electronic signature code.<commit_after>/**
 *
 */
function initESigDialog(){
	// Make the esig with a jQuery UI dialog.
    var electronicSignatureDialog = $('.eSigDialog').dialog({
    	beforeClose: function(event, ui) {
    		$('#eSigInput').val('');
    		$('#eSigErrorSpan').text('');
    	},
        autoOpen: false,
        width: 350,   // body width is 768px
        modal: true
    });

    var openESigButton = $('#signCalculationButton');
    openESigButton.on('click', function(event) {
        event.preventDefault();

        var windowHeight = 170;
        electronicSignatureDialog.dialog('option', 'height', windowHeight);
        electronicSignatureDialog.dialog('open');
    });

    $('#eSigForm').on('submit', function(event) {
    	event.preventDefault();
    	var eSigCode = $('#eSigInput').val();
    	$.ajax({
			url: "signCalculation",
			type: 'POST',
			dataType: 'json',
			data: {
				eSig: eSigCode
			},
			/*
			 * disable button and add loading text
			 * */
			beforeSend: function() {
				$('#eSigButton').prop('disabled', true);
				$('#eSigButton').text("Signing");
			},
			success: function(result) {
				if(result.status == "Success") {
					// Redirect to the success page.
					window.location.replace("successfulSign");
				}
				else {
					// Change the span text to the given error text
					$('#eSigErrorSpan').text(result.status);
					$('#eSigButton').prop('disabled', false);
					$('#eSigButton').text("Sign");
				}
			}
		});
    });

    var cancelESigButton = $('#cancelESigButton');
    cancelESigButton.on('click', function(event) {
    	event.preventDefault();
    	electronicSignatureDialog.dialog('close');
    });
}<|endoftext|>


<commit_before>define(['sugar-web/activity/activity', "webL10n", 'activity/Board', 'activity/vanilla-state', 'activity/patterns', 'activity/shadeColor','sugar-web/env', 'genSpeedPalette','gridSizePalette'], function (activity, l10n, Board, State, patterns, shadeColor, env, genSpeedPalette, gridSizePalette) {
  requirejs(['domReady!'], function (doc) {
    activity.setup();
	env.getEnvironment(function(err, environment) {
		var defaultLanguage = (typeof chrome != 'undefined' && chrome.app && chrome.app.runtime) ? chrome.i18n.getUILanguage() : navigator.language;
		var language = environment.user ? environment.user.language : defaultLanguage;
		l10n.language.code = language;
		window.addEventListener('localized', function () {
          document.querySelector('.generation-status').innerText = l10n.get('Generation');
          document.querySelector('#speedlabel').innerText = l10n.get('speed');
          document.querySelector('#sizelabel').innerText = l10n.get('size');
	    });
        activity.getXOColor(function (err, color) {
          var dataStore = activity.getDatastoreObject();
          main(Board, State, patterns, color, shadeColor, l10n, dataStore, genSpeedPalette, gridSizePalette);
        });
	});
  });
});

function main(Board, State, patterns, color, shadeColor, l10n, dataStore, genSpeedPalette, gridSizePalette) {
  var state = new State({
    boardState: [],
    generation: 0,
    playPauseIcon: 'play',
    shouldPlay: false,
    generationTimeInterval: 235,
    gridCols: 40,
    gridRows: 20
  });
  var randomPattern = patterns[0],
      gliderPattern = patterns[1],
      noPattern = patterns[2],
      blankPattern = patterns[3];

  var target = document.querySelector('.main canvas');
  var board = new Board(state.state.boardState, color.fill, '#FBF6F5', shadeColor(color.stroke, 10), color.stroke, 12, 12, 2, 2, target);

  var genSpeedButton = document.getElementById("speed-button");
  var genSpeedButtonPallete = new genSpeedPalette.ActivityPalette(
        genSpeedButton, state);

  var gridSizeButton = document.getElementById("size-button");
  var gridSizePallete = new gridSizePalette.ActivityPalette(
              gridSizeButton, state, board);

  document.querySelector('.generation-count').style.color = color.fill;
  document.querySelector('.generation-status').style.color = color.fill;

  board.draw(state);

  var storeLocally = function storeLocally(state) {
    dataStore.setDataAsText({
      boardState: state.boardState,
      generation: state.generation,
      gridCols : state.gridCols,
      gridRows : state.gridRows
    });
    console.log(state);
    console.log('writing');
    dataStore.save(function (err) {
      if (err) {
        console.log('writing failed.');
        console.error(err);
      } else {
        console.log('writing saved.');
      }
    });
  };

  var generateGeneration = function generateGeneration() {
    if (state.state.shouldPlay) {
      var nextGenerationBoard = state.state.boardState.map(function (row, y) {
        return row.map(function (cell, x) {
          return transformCellByRule(cell, findNeighbours(x, y));
        });
      });
      state.set(function (prev) {
        return {
          boardState: nextGenerationBoard,
          generation: prev.generation + 1
        };
      });
      setTimeout(generateGeneration, state.state.generationTimeInterval);
    } else {
      return 0;
    }
  };

  var transformCellByRule = function transformCellByRule(cell, neighbours) {
    var cellIsAlive = cell === 1 || cell === 2;
    var aliveInNeighbour = neighbours.filter(function (cell) {
      return cell === 1 || cell === 2;
    });
    var numOfAliveNeighbours = aliveInNeighbour.length;
    if (cellIsAlive) {
      if (numOfAliveNeighbours < 2) {
        return 0;
      } else if (numOfAliveNeighbours === 2 || numOfAliveNeighbours === 3) {
        return 1;
      } else {
        return 0;
      }
    } else {
      if (numOfAliveNeighbours === 3) {
        return 2;
      } else {
        return 0;
      }
    }
  };

  var findNeighbours = function findNeighbours(x, y) {
    var leftX = x - 1 === -1 ? state.state.gridCols -1 : x - 1;
    var rightX = x + 1 === state.state.gridCols ? 0 : x + 1;
    var topY = y - 1 === -1 ? state.state.gridRows -1: y - 1;
    var bottomY = y + 1 === state.state.gridRows ? 0 : y + 1;
    var boardState = state.state.boardState;

    var left = boardState[y][leftX];
    var right = boardState[y][rightX];
    var top = boardState[topY][x];
    var bottom = boardState[bottomY][x];
    var leftTop = boardState[topY][leftX];
    var leftBottom = boardState[bottomY][leftX];
    var rightTop = boardState[topY][rightX];
    var rightBottom = boardState[bottomY][rightX];

    return [left, right, top, bottom, leftTop, leftBottom, rightTop, rightBottom];
  };

  state.subscribe({
    boardState: ['.fake-selector', function (fakeElem, value, prevValue) {
      board.update(value);
    }],

    generation: ['.generation-count', 'innerText'],

    playPauseIcon: ['#play-pause', function (elem, value, prevValue) {
      elem.className = value + ' toolbutton';
    }],

    shouldPlay: ['.fake-selector', function (fakeElem, value, prevValue) {
      if (value) {
        generateGeneration();
      }
    }],

    gridCols: ['.fake-selector', function (fakeElem, value, prevValue) {
      let sizeScale = document.getElementById('sizevalue');
      sizeScale.value = value / 20;
      board.handleResize(window.innerWidth, state.state.boardState, state);
    }],

    gridRows: ['.fake-selector', function (fakeElem, value, prevValue) {
      let sizeScale = document.getElementById('sizevalue');
      sizeScale.value = value / 10;
      board.handleResize(window.innerWidth, state.state.boardState, state);
    }]
  });

  dataStore.loadAsText(function (err, metadata, data) {
    var boardState = data ? data.boardState : randomPattern(state);
    var generation =  data ? data.generation : 0;
    let gridCols =  data ? data.gridCols : 40;
    let gridRows =  data ? data.gridRows : 20;
    console.log(data);
    console.log(gridCols);
    state.set({
      boardState: boardState,
      generation: parseInt(generation),
      gridCols : parseInt(gridCols),
      gridRows : parseInt(gridRows)
    });
  });

  board.onClick(function (cellX, cellY) {
    state.set(function (prev) {
      var newState = [].concat(prev.boardState);
      var clickedCell = newState[cellY][cellX]
      if (clickedCell === 1 || clickedCell === 2) {
        newState[cellY][cellX] = 0;
      } else {
        newState[cellY][cellX] = 2;
      }
      return {
        boardState: newState
      };
    });
  });

  document.querySelector('#play-pause').addEventListener('click', function () {
    state.set(function (prev) {
      var iconToSet = prev.playPauseIcon === 'play' ? 'pause' : 'play';
      var togglePlay = prev.shouldPlay === true ? false : true;
      if (prev.shouldPlay) {
        storeLocally({
          boardState: state.state.boardState,
          generation: state.state.generation,
          gridCols : state.state.gridCols,
          gridRows : state.state.gridRows
        });
      }
      return {
        playPauseIcon: iconToSet,
        shouldPlay: togglePlay
      };
    });
  });

  document.querySelector('#stop-button').addEventListener('click', function() {
    storeLocally({
      boardState: state.state.boardState,
      generation: state.state.generation,
      gridCols : state.state.gridCols,
      gridRows : state.state.gridRows
    });
  })

  // Full screen
  document.getElementById("fullscreen-button").addEventListener('click', function() {
    document.getElementById("main-toolbar").style.opacity = 0;
    document.getElementById("canvas").style.top = "0px";
    document.getElementById("unfullscreen-button").style.visibility = "visible";
    //board.handleResize(window.innerWidth, state.state.boardState,state);
  });
  document.getElementById("unfullscreen-button").addEventListener('click', function() {
    document.getElementById("main-toolbar").style.opacity = 1;
    document.getElementById("canvas").style.top = "55px";
    document.getElementById("unfullscreen-button").style.visibility = "hidden";
    //board.handleResize(window.innerWidth, state.state.boardState,state);
  });

  document.querySelector('#random').addEventListener('click', function () {
    state.set({
      boardState: randomPattern(state),
      generation: 0
    });
  });
  document.querySelector('#glider').addEventListener('click', function () {
    state.set({
      boardState: gliderPattern(state),
      generation: 0
    });
  });
  document.querySelector('#no').addEventListener('click', function () {
    state.set({
      boardState: noPattern(state),
      generation: 0
    });
  });
  document.querySelector('#clear').addEventListener('click', function () {
    state.set({
      boardState: blankPattern(state),
      generation: 0,
      playPauseIcon: 'play',
      shouldPlay: false
    });
  });

  window.addEventListener('resize', function (e) {
    board.handleResize(window.innerWidth, state.state.boardState,state);
  });
  board.handleResize(window.innerWidth, state.state.boardState,state);
}
<commit_msg>Removed a comment.<commit_after>define(['sugar-web/activity/activity', "webL10n", 'activity/Board', 'activity/vanilla-state', 'activity/patterns', 'activity/shadeColor','sugar-web/env', 'genSpeedPalette','gridSizePalette'], function (activity, l10n, Board, State, patterns, shadeColor, env, genSpeedPalette, gridSizePalette) {
  requirejs(['domReady!'], function (doc) {
    activity.setup();
	env.getEnvironment(function(err, environment) {
		var defaultLanguage = (typeof chrome != 'undefined' && chrome.app && chrome.app.runtime) ? chrome.i18n.getUILanguage() : navigator.language;
		var language = environment.user ? environment.user.language : defaultLanguage;
		l10n.language.code = language;
		window.addEventListener('localized', function () {
          document.querySelector('.generation-status').innerText = l10n.get('Generation');
          document.querySelector('#speedlabel').innerText = l10n.get('speed');
          document.querySelector('#sizelabel').innerText = l10n.get('size');
	    });
        activity.getXOColor(function (err, color) {
          var dataStore = activity.getDatastoreObject();
          main(Board, State, patterns, color, shadeColor, l10n, dataStore, genSpeedPalette, gridSizePalette);
        });
	});
  });
});

function main(Board, State, patterns, color, shadeColor, l10n, dataStore, genSpeedPalette, gridSizePalette) {
  var state = new State({
    boardState: [],
    generation: 0,
    playPauseIcon: 'play',
    shouldPlay: false,
    generationTimeInterval: 235,
    gridCols: 40,
    gridRows: 20
  });
  var randomPattern = patterns[0],
      gliderPattern = patterns[1],
      noPattern = patterns[2],
      blankPattern = patterns[3];

  var target = document.querySelector('.main canvas');
  var board = new Board(state.state.boardState, color.fill, '#FBF6F5', shadeColor(color.stroke, 10), color.stroke, 12, 12, 2, 2, target);

  var genSpeedButton = document.getElementById("speed-button");
  var genSpeedButtonPallete = new genSpeedPalette.ActivityPalette(
        genSpeedButton, state);

  var gridSizeButton = document.getElementById("size-button");
  var gridSizePallete = new gridSizePalette.ActivityPalette(
              gridSizeButton, state, board);

  document.querySelector('.generation-count').style.color = color.fill;
  document.querySelector('.generation-status').style.color = color.fill;

  board.draw(state);

  var storeLocally = function storeLocally(state) {
    dataStore.setDataAsText({
      boardState: state.boardState,
      generation: state.generation,
      gridCols : state.gridCols,
      gridRows : state.gridRows
    });
    console.log(state);
    console.log('writing');
    dataStore.save(function (err) {
      if (err) {
        console.log('writing failed.');
        console.error(err);
      } else {
        console.log('writing saved.');
      }
    });
  };

  var generateGeneration = function generateGeneration() {
    if (state.state.shouldPlay) {
      var nextGenerationBoard = state.state.boardState.map(function (row, y) {
        return row.map(function (cell, x) {
          return transformCellByRule(cell, findNeighbours(x, y));
        });
      });
      state.set(function (prev) {
        return {
          boardState: nextGenerationBoard,
          generation: prev.generation + 1
        };
      });
      setTimeout(generateGeneration, state.state.generationTimeInterval);
    } else {
      return 0;
    }
  };

  var transformCellByRule = function transformCellByRule(cell, neighbours) {
    var cellIsAlive = cell === 1 || cell === 2;
    var aliveInNeighbour = neighbours.filter(function (cell) {
      return cell === 1 || cell === 2;
    });
    var numOfAliveNeighbours = aliveInNeighbour.length;
    if (cellIsAlive) {
      if (numOfAliveNeighbours < 2) {
        return 0;
      } else if (numOfAliveNeighbours === 2 || numOfAliveNeighbours === 3) {
        return 1;
      } else {
        return 0;
      }
    } else {
      if (numOfAliveNeighbours === 3) {
        return 2;
      } else {
        return 0;
      }
    }
  };

  var findNeighbours = function findNeighbours(x, y) {
    var leftX = x - 1 === -1 ? state.state.gridCols -1 : x - 1;
    var rightX = x + 1 === state.state.gridCols ? 0 : x + 1;
    var topY = y - 1 === -1 ? state.state.gridRows -1: y - 1;
    var bottomY = y + 1 === state.state.gridRows ? 0 : y + 1;
    var boardState = state.state.boardState;

    var left = boardState[y][leftX];
    var right = boardState[y][rightX];
    var top = boardState[topY][x];
    var bottom = boardState[bottomY][x];
    var leftTop = boardState[topY][leftX];
    var leftBottom = boardState[bottomY][leftX];
    var rightTop = boardState[topY][rightX];
    var rightBottom = boardState[bottomY][rightX];

    return [left, right, top, bottom, leftTop, leftBottom, rightTop, rightBottom];
  };

  state.subscribe({
    boardState: ['.fake-selector', function (fakeElem, value, prevValue) {
      board.update(value);
    }],

    generation: ['.generation-count', 'innerText'],

    playPauseIcon: ['#play-pause', function (elem, value, prevValue) {
      elem.className = value + ' toolbutton';
    }],

    shouldPlay: ['.fake-selector', function (fakeElem, value, prevValue) {
      if (value) {
        generateGeneration();
      }
    }],

    gridCols: ['.fake-selector', function (fakeElem, value, prevValue) {
      let sizeScale = document.getElementById('sizevalue');
      sizeScale.value = value / 20;
      board.handleResize(window.innerWidth, state.state.boardState, state);
    }],

    gridRows: ['.fake-selector', function (fakeElem, value, prevValue) {
      let sizeScale = document.getElementById('sizevalue');
      sizeScale.value = value / 10;
      board.handleResize(window.innerWidth, state.state.boardState, state);
    }]
  });

  dataStore.loadAsText(function (err, metadata, data) {
    var boardState = data ? data.boardState : randomPattern(state);
    var generation =  data ? data.generation : 0;
    let gridCols =  data ? data.gridCols : 40;
    let gridRows =  data ? data.gridRows : 20;
    console.log(data);
    console.log(gridCols);
    state.set({
      boardState: boardState,
      generation: parseInt(generation),
      gridCols : parseInt(gridCols),
      gridRows : parseInt(gridRows)
    });
  });

  board.onClick(function (cellX, cellY) {
    state.set(function (prev) {
      var newState = [].concat(prev.boardState);
      var clickedCell = newState[cellY][cellX]
      if (clickedCell === 1 || clickedCell === 2) {
        newState[cellY][cellX] = 0;
      } else {
        newState[cellY][cellX] = 2;
      }
      return {
        boardState: newState
      };
    });
  });

  document.querySelector('#play-pause').addEventListener('click', function () {
    state.set(function (prev) {
      var iconToSet = prev.playPauseIcon === 'play' ? 'pause' : 'play';
      var togglePlay = prev.shouldPlay === true ? false : true;
      if (prev.shouldPlay) {
        storeLocally({
          boardState: state.state.boardState,
          generation: state.state.generation,
          gridCols : state.state.gridCols,
          gridRows : state.state.gridRows
        });
      }
      return {
        playPauseIcon: iconToSet,
        shouldPlay: togglePlay
      };
    });
  });

  document.querySelector('#stop-button').addEventListener('click', function() {
    storeLocally({
      boardState: state.state.boardState,
      generation: state.state.generation,
      gridCols : state.state.gridCols,
      gridRows : state.state.gridRows
    });
  })

  // Full screen
  document.getElementById("fullscreen-button").addEventListener('click', function() {
    document.getElementById("main-toolbar").style.opacity = 0;
    document.getElementById("canvas").style.top = "0px";
    document.getElementById("unfullscreen-button").style.visibility = "visible";
    board.handleResize(window.innerWidth, state.state.boardState,state);
  });
  document.getElementById("unfullscreen-button").addEventListener('click', function() {
    document.getElementById("main-toolbar").style.opacity = 1;
    document.getElementById("canvas").style.top = "55px";
    document.getElementById("unfullscreen-button").style.visibility = "hidden";
    board.handleResize(window.innerWidth, state.state.boardState,state);
  });

  document.querySelector('#random').addEventListener('click', function () {
    state.set({
      boardState: randomPattern(state),
      generation: 0
    });
  });
  document.querySelector('#glider').addEventListener('click', function () {
    state.set({
      boardState: gliderPattern(state),
      generation: 0
    });
  });
  document.querySelector('#no').addEventListener('click', function () {
    state.set({
      boardState: noPattern(state),
      generation: 0
    });
  });
  document.querySelector('#clear').addEventListener('click', function () {
    state.set({
      boardState: blankPattern(state),
      generation: 0,
      playPauseIcon: 'play',
      shouldPlay: false
    });
  });

  window.addEventListener('resize', function (e) {
    board.handleResize(window.innerWidth, state.state.boardState,state);
  });
  board.handleResize(window.innerWidth, state.state.boardState,state);
}
<|endoftext|>


<commit_before>import layout from '../../templates/components/nypr-account-forms/signup';
import Component from '@ember/component';
import { get, set } from '@ember/object';
import { next } from '@ember/runloop';
import Changeset from 'ember-changeset';
import SignupValidations from 'nypr-account-settings/validations/nypr-accounts/signup';
import messages from 'nypr-account-settings/validations/nypr-accounts/custom-messages';
import lookupValidator from 'ember-changeset-validations';
import { inject as service } from '@ember/service';
import fetch from 'fetch';
import { rejectUnsuccessfulResponses } from 'nypr-account-settings/utils/fetch-utils';
import { getOwner } from '@ember/application';

export default Component.extend({
  layout,
  store: service(),
  flashMessages: service(),
  showSocialSignup: false,
  authApi: null,
  session: service(),
  allowedKeys: null,

  init() {
    this._super(...arguments);
    set(this, 'newUser', this.get('store').createRecord('user',
      {
        'givenName': get(this, 'givenName'),
        'familyName': get(this, 'familyName')
      }
    ));
    set(this, 'allowedKeys', ['email','emailConfirmation','givenName','familyName','typedPassword']);
    set(this, 'changeset', new Changeset(get(this, 'newUser'), lookupValidator(SignupValidations), SignupValidations));
    get(this, 'changeset').validate();
    set(this, 'changeset.email', get(this, 'email'));
    set(this, 'changeset.emailConfirmation', get(this, 'email'));

    // Ignore the captcha during testing
    let config = getOwner(this).resolveRegistration('config:environment');
    if (config.environment.indexOf("test") > -1) {
      set(this, 'newUser.captchaKey', "test_captcha_key");
    }
  },
  click() {
    get(this, 'flashMessages').clearMessages();
  },
  actions: {
    onSubmit() {
      set(this, 'signupError', null);
      return this.signUp();
    },
    onFailure(e) {
      if (e) {
        if (e.errors && e.errors.code === 'UserNoPassword') {
          set(this, 'signupError', messages.signupNoPassword);
        } else {
          this.applyErrorToChangeset(e.errors, get(this, 'changeset'));
        }
      }
    },
    signupWithFacebook() {
      let authOptions = {};
      if (get(this, 'emailWasDeclined')) {
        //we need to send this option with the fb login request to re-request the email permission
        authOptions = {authType: 'rerequest'};
        //reset emailWasDeclined on a new attempt
        set(this, 'emailWasDeclined', false);
      }
      get(this, 'session').authenticate('authenticator:torii', 'facebook-connect', authOptions)
      .catch((e) => {
        if (e && get(e, 'errors.code') === 'MissingAttributeException') {
          set(this, 'emailWasDeclined', true);
          return this.onFacebookLoginFailure(messages.socialAuthNoEmail);
        } else {
          return this.onFacebookLoginFailure(messages.socialAuthCancelled);
        }
      });
    },
    hasCompletedCaptcha(reCaptchaResponse) {
      set(this, 'newUser.captchaKey', reCaptchaResponse);
    }
  },
  onFacebookLoginFailure(message) {
    // because we clear flash messages when clicking this form,
    // wait a tick when we add one in an action that can
    // be triggered with a click
    next(() => {
      if (message) {
        this.get('flashMessages').add({
          message: message,
          type: 'warning'
        });
      }
    });
  },
  signUp() {
    return get(this, 'newUser').save();
  },
  onEmailInput() {
    if (get(this, 'changeset.emailConfirmation')) {
      get(this, 'changeset').validate('emailConfirmation');
    }
  },
  applyErrorToChangeset(error, changeset) {
    if (error) {
      changeset.rollback(); // so errors don't stack up
      if (error.code === "AccountExists") {
        changeset.validate('email');
        changeset.pushErrors('email', messages.signupAccountExists(changeset.get('email')));
      } else if (error.message === 'User is disabled') {
        changeset.pushErrors('email', messages.userDisabled);
      }
    }
  },
  resendConfirmationEmail(email) {
    let url = `${get(this, 'authAPI')}/v1/confirm/resend?email=${email}`;
    let method = 'GET';
    let mode = 'cors';
    return fetch(url, {method, mode})
    .then(rejectUnsuccessfulResponses);
  }
});
<commit_msg>Use ember-get-config for environment test<commit_after>import layout from '../../templates/components/nypr-account-forms/signup';
import Component from '@ember/component';
import { get, set } from '@ember/object';
import { next } from '@ember/runloop';
import Changeset from 'ember-changeset';
import SignupValidations from 'nypr-account-settings/validations/nypr-accounts/signup';
import messages from 'nypr-account-settings/validations/nypr-accounts/custom-messages';
import lookupValidator from 'ember-changeset-validations';
import { inject as service } from '@ember/service';
import fetch from 'fetch';
import { rejectUnsuccessfulResponses } from 'nypr-account-settings/utils/fetch-utils';
import config from "ember-get-config";

export default Component.extend({
  layout,
  store: service(),
  flashMessages: service(),
  showSocialSignup: false,
  authApi: null,
  session: service(),
  allowedKeys: null,

  init() {
    this._super(...arguments);
    set(this, 'newUser', this.get('store').createRecord('user',
      {
        'givenName': get(this, 'givenName'),
        'familyName': get(this, 'familyName')
      }
    ));
    set(this, 'allowedKeys', ['email','emailConfirmation','givenName','familyName','typedPassword']);
    set(this, 'changeset', new Changeset(get(this, 'newUser'), lookupValidator(SignupValidations), SignupValidations));
    get(this, 'changeset').validate();
    set(this, 'changeset.email', get(this, 'email'));
    set(this, 'changeset.emailConfirmation', get(this, 'email'));

    // Ignore the captcha during testing
    if (config.environment === "test") {
      set(this, 'newUser.captchaKey', "test_captcha_key");
    }
  },
  click() {
    get(this, 'flashMessages').clearMessages();
  },
  actions: {
    onSubmit() {
      set(this, 'signupError', null);
      return this.signUp();
    },
    onFailure(e) {
      if (e) {
        if (e.errors && e.errors.code === 'UserNoPassword') {
          set(this, 'signupError', messages.signupNoPassword);
        } else {
          this.applyErrorToChangeset(e.errors, get(this, 'changeset'));
        }
      }
    },
    signupWithFacebook() {
      let authOptions = {};
      if (get(this, 'emailWasDeclined')) {
        //we need to send this option with the fb login request to re-request the email permission
        authOptions = {authType: 'rerequest'};
        //reset emailWasDeclined on a new attempt
        set(this, 'emailWasDeclined', false);
      }
      get(this, 'session').authenticate('authenticator:torii', 'facebook-connect', authOptions)
      .catch((e) => {
        if (e && get(e, 'errors.code') === 'MissingAttributeException') {
          set(this, 'emailWasDeclined', true);
          return this.onFacebookLoginFailure(messages.socialAuthNoEmail);
        } else {
          return this.onFacebookLoginFailure(messages.socialAuthCancelled);
        }
      });
    },
    hasCompletedCaptcha(reCaptchaResponse) {
      set(this, 'newUser.captchaKey', reCaptchaResponse);
    }
  },
  onFacebookLoginFailure(message) {
    // because we clear flash messages when clicking this form,
    // wait a tick when we add one in an action that can
    // be triggered with a click
    next(() => {
      if (message) {
        this.get('flashMessages').add({
          message: message,
          type: 'warning'
        });
      }
    });
  },
  signUp() {
    return get(this, 'newUser').save();
  },
  onEmailInput() {
    if (get(this, 'changeset.emailConfirmation')) {
      get(this, 'changeset').validate('emailConfirmation');
    }
  },
  applyErrorToChangeset(error, changeset) {
    if (error) {
      changeset.rollback(); // so errors don't stack up
      if (error.code === "AccountExists") {
        changeset.validate('email');
        changeset.pushErrors('email', messages.signupAccountExists(changeset.get('email')));
      } else if (error.message === 'User is disabled') {
        changeset.pushErrors('email', messages.userDisabled);
      }
    }
  },
  resendConfirmationEmail(email) {
    let url = `${get(this, 'authAPI')}/v1/confirm/resend?email=${email}`;
    let method = 'GET';
    let mode = 'cors';
    return fetch(url, {method, mode})
    .then(rejectUnsuccessfulResponses);
  }
});
<|endoftext|>


<commit_before>odoo.define('payment_stripe.stripe', function(require) {
    "use strict";

    var ajax = require('web.ajax');
    var core = require('web.core');
    var _t = core._t;
    var qweb = core.qweb;
    ajax.loadXML('/payment_stripe/static/src/xml/stripe_templates.xml', qweb);

    // The following currencies are integer only, see
    // https://stripe.com/docs/currencies#zero-decimal
    var int_currencies = [
        'BIF', 'XAF', 'XPF', 'CLP', 'KMF', 'DJF', 'GNF', 'JPY', 'MGA', 'PYGí',
        'RWF', 'KRW', 'VUV', 'VND', 'XOF'
    ];

    var handler = StripeCheckout.configure({
        key: $("input[name='stripe_key']").val(),
        image: $("input[name='stripe_image']").val(),
        locale: 'auto',
        closed: function() {
          if (!handler.isTokenGenerate) {
                $('#pay_stripe')
                    .removeAttr('disabled')
                    .find('i').remove();
          }
        },
        token: function(token, args) {
            handler.isTokenGenerate = true;
            ajax.jsonRpc("/payment/stripe/create_charge", 'call', {
                tokenid: token.id,
                email: token.email,
                amount: $("input[name='amount']").val(),
                acquirer_id: $("#acquirer_stripe").val(),
                currency: $("input[name='currency']").val(),
                invoice_num: $("input[name='invoice_num']").val(),
                return_url: $("input[name='return_url']").val()
            }).done(function(data){
                handler.isTokenGenerate = false;
                window.location.href = data;
            }).fail(function(){
                var msg = arguments && arguments[1] && arguments[1].data && arguments[1].data.message;
                var wizard = $(qweb.render('stripe.error', {'msg': msg || _t('Payment error')}));
                wizard.appendTo($('body')).modal({'keyboard': true});
            });
        },
    });

    $('#pay_stripe').on('click', function(e) {
        // Open Checkout with further options
        if(!$(this).find('i').length)
            $(this).append('<i class="fa fa-spinner fa-spin"/>');
            $(this).attr('disabled','disabled');

        var $form = $(e.currentTarget).parents('form');
        var acquirer_id = $(e.currentTarget).closest('div.oe_sale_acquirer_button,div.oe_quote_acquirer_button,div.o_website_payment_new_payment');
        acquirer_id = acquirer_id.data('id') || acquirer_id.data('acquirer_id');
        if (! acquirer_id) {
            return false;
        }

        var so_token = $("input[name='token']").val();
        var so_id = $("input[name='return_url']").val().match(/quote\/([0-9]+)/) || undefined;
        if (so_id) {
            so_id = parseInt(so_id[1]);
        }

        e.preventDefault();
        if ($('.o_website_payment').length !== 0) {
            var currency = $("input[name='currency']").val();
            var currency_id = $("input[name='currency_id']").val();
            var amount = parseFloat($("input[name='amount']").val() || '0.0');
            if (!_.contains(int_currencies, currency)) {
                amount = amount*100;
            }

            ajax.jsonRpc('/website_payment/transaction', 'call', {
                    reference: $("input[name='invoice_num']").val(),
                    amount: amount,
                    currency_id: currency_id,
                    acquirer_id: acquirer_id
                })
                handler.open({
                    name: $("input[name='merchant']").val(),
                    description: $("input[name='invoice_num']").val(),
                    currency: currency,
                    amount: amount,
                });
        } else {
            var currency = $("input[name='currency']").val();
            var amount = parseFloat($("input[name='amount']").val() || '0.0');
            if (!_.contains(int_currencies, currency)) {
                amount = amount*100;
            }

            ajax.jsonRpc('/shop/payment/transaction/' + acquirer_id, 'call', {
                    so_id: so_id,
                    so_token: so_token
                }, {'async': false}).then(function (data) {
                $form.html(data);
                handler.open({
                    name: $("input[name='merchant']").val(),
                    description: $("input[name='invoice_num']").val(),
                    currency: currency,
                    amount: amount,
                });
            });
        }
    });
});
<commit_msg>[FIX] payment_stripe: integer currencies (portal payment)<commit_after>odoo.define('payment_stripe.stripe', function(require) {
    "use strict";

    var ajax = require('web.ajax');
    var core = require('web.core');
    var _t = core._t;
    var qweb = core.qweb;
    ajax.loadXML('/payment_stripe/static/src/xml/stripe_templates.xml', qweb);

    // The following currencies are integer only, see
    // https://stripe.com/docs/currencies#zero-decimal
    var int_currencies = [
        'BIF', 'XAF', 'XPF', 'CLP', 'KMF', 'DJF', 'GNF', 'JPY', 'MGA', 'PYGí',
        'RWF', 'KRW', 'VUV', 'VND', 'XOF'
    ];

    var handler = StripeCheckout.configure({
        key: $("input[name='stripe_key']").val(),
        image: $("input[name='stripe_image']").val(),
        locale: 'auto',
        closed: function() {
          if (!handler.isTokenGenerate) {
                $('#pay_stripe')
                    .removeAttr('disabled')
                    .find('i').remove();
          }
        },
        token: function(token, args) {
            handler.isTokenGenerate = true;
            ajax.jsonRpc("/payment/stripe/create_charge", 'call', {
                tokenid: token.id,
                email: token.email,
                amount: $("input[name='amount']").val(),
                acquirer_id: $("#acquirer_stripe").val(),
                currency: $("input[name='currency']").val(),
                invoice_num: $("input[name='invoice_num']").val(),
                return_url: $("input[name='return_url']").val()
            }).done(function(data){
                handler.isTokenGenerate = false;
                window.location.href = data;
            }).fail(function(){
                var msg = arguments && arguments[1] && arguments[1].data && arguments[1].data.message;
                var wizard = $(qweb.render('stripe.error', {'msg': msg || _t('Payment error')}));
                wizard.appendTo($('body')).modal({'keyboard': true});
            });
        },
    });

    $('#pay_stripe').on('click', function(e) {
        // Open Checkout with further options
        if(!$(this).find('i').length)
            $(this).append('<i class="fa fa-spinner fa-spin"/>');
            $(this).attr('disabled','disabled');

        var $form = $(e.currentTarget).parents('form');
        var acquirer_id = $(e.currentTarget).closest('div.oe_sale_acquirer_button,div.oe_quote_acquirer_button,div.o_website_payment_new_payment');
        acquirer_id = acquirer_id.data('id') || acquirer_id.data('acquirer_id');
        if (! acquirer_id) {
            return false;
        }

        var so_token = $("input[name='token']").val();
        var so_id = $("input[name='return_url']").val().match(/quote\/([0-9]+)/) || undefined;
        if (so_id) {
            so_id = parseInt(so_id[1]);
        }

        e.preventDefault();
        if ($('.o_website_payment').length !== 0) {
            var currency = $("input[name='currency']").val();
            var currency_id = $("input[name='currency_id']").val();
            var amount = parseFloat($("input[name='amount']").val() || '0.0');

            ajax.jsonRpc('/website_payment/transaction', 'call', {
                    reference: $("input[name='invoice_num']").val(),
                    amount: amount,
                    currency_id: currency_id,
                    acquirer_id: acquirer_id
                })
                handler.open({
                    name: $("input[name='merchant']").val(),
                    description: $("input[name='invoice_num']").val(),
                    currency: currency,
                    amount: _.contains(int_currencies, currency) ? amount : amount * 100,
                });
        } else {
            var currency = $("input[name='currency']").val();
            var amount = parseFloat($("input[name='amount']").val() || '0.0');

            ajax.jsonRpc('/shop/payment/transaction/' + acquirer_id, 'call', {
                    so_id: so_id,
                    so_token: so_token
                }, {'async': false}).then(function (data) {
                $form.html(data);
                handler.open({
                    name: $("input[name='merchant']").val(),
                    description: $("input[name='invoice_num']").val(),
                    currency: currency,
                    amount: _.contains(int_currencies, currency) ? amount : amount * 100,
                });
            });
        }
    });
});
<|endoftext|>


<commit_before>odoo.define('portal.chatter', function(require) {
'use strict';

var base = require('web_editor.base');
var ajax = require('web.ajax');
var core = require('web.core');
var Widget = require('web.Widget');
var rpc = require('web.rpc');

var qweb = core.qweb;
var _t = core._t;

/**
 * Widget PortalChatter
 *
 * - Fetch message fron controller
 * - Display chatter: pager, total message, composer (according to access right)
 * - Provider API to filter displayed messages
 */
var PortalChatter = Widget.extend({
    template: 'portal.chatter',
    events: {
        "click .o_portal_chatter_pager_btn": '_onClickPager'
    },

    init: function(parent, options){
        this._super.apply(this, arguments);
        this.options = _.defaults(options || {}, {
            'allow_composer': true,
            'display_composer': false,
            'csrf_token': odoo.csrf_token,
            'message_count': 0,
            'pager_step': 10,
            'pager_scope': 5,
            'pager_start': 1,
            'is_user_public': true,
            'is_user_publisher': false,
            'domain': [],
        });
        this.set('messages', []);
        this.set('message_count', this.options['message_count']);
        this.set('pager', {});
        this.set('domain', this.options['domain']);
        this._current_page = this.options['pager_start'];
    },
    willStart: function(){
        var self = this;
        // load qweb template and init data
        return $.when(
            rpc.query({
                route: '/mail/chatter_init',
                params: this._messageFetchPrepareParams()
            }), this._loadTemplates()
        ).then(function(result){
            self.result = result
            return result;
        });
    },
    /**
     * @override
     */
    start: function () {
        // bind events
        this.on("change:messages", this, this._renderMessages);
        this.on("change:message_count", this, function(){
            this._renderMessageCount();
            this.set('pager', this._pager(this._current_page));
        });
        this.on("change:pager", this, this._renderPager);
        this.on("change:domain", this, this._onChangeDomain);
        // set options and parameters
        this.options = _.extend(this.options, this.result['options'] || {});
        this.set('message_count', this.options['message_count']);
        this.set('messages', this.preprocessMessages(this.result['messages']));
        return this._super.apply(this, arguments);
    },

    //--------------------------------------------------------------------------
    // Public
    //--------------------------------------------------------------------------

    /**
     * Fetch the messages and the message count from the server for the
     * current page and current domain.
     *
     * @param {Array} domain
     * @returns {Deferred}
     */
    messageFetch: function(domain){
        var self = this;
        return rpc.query({
            route: '/mail/chatter_fetch',
            params: self._messageFetchPrepareParams()
        }).then(function(result){
            self.set('messages', self.preprocessMessages(result['messages']));
            self.set('message_count', result['message_count']);
        });
    },
    /**
     * Update the messages format
     *
     * @param {Array<Object>}
     * @returns {Array}
     */
    preprocessMessages: function(messages){
        _.each(messages, function(m){
            m['author_avatar_url'] = _.str.sprintf('/web/image/%s/%s/author_avatar/50x50', 'mail.message', m.id);
            m['published_date_str'] = _.str.sprintf(_t('Published on %s'), moment(m.date).format('MMMM Do YYYY, h:mm:ss a'));
        });
        return messages;
    },

    //--------------------------------------------------------------------------
    // Private
    //--------------------------------------------------------------------------

    /**
     * Change the current page by refreshing current domain
     *
     * @private
     * @param {Number} page
     * @param {Array} domain
     */
    _changeCurrentPage: function(page, domain){
        this._current_page = page;
        var d = domain ? domain : _.clone(this.get('domain'));
        this.set('domain', d); // trigger fetch message
    },
    /**
     * @private
     * @returns {Deferred}
     */
    _loadTemplates: function(){
        return ajax.loadXML('/portal/static/src/xml/portal_chatter.xml', qweb);
    },
    _messageFetchPrepareParams: function(){
        var self = this;
        var data = {
            'res_model': this.options['res_model'],
            'res_id': this.options['res_id'],
            'limit': this.options['pager_step'],
            'offset': (this._current_page-1) * this.options['pager_step'],
            'allow_composer': this.options['allow_composer'],
        };
        // add token field to allow to post comment without being logged
        if(self.options['token']){
            data['token'] = self.options['token'];
        }
        // add domain
        if(this.get('domain')){
            data['domain'] = this.get('domain');
        }
        return data;
    },
    /**
     * Generate the pager data for the given page number
     *
     * @private
     * @param {Number} page
     * @returns {Object}
     */
    _pager: function(page){
        var page = page || 1;
        var total = this.get('message_count');
        var scope = this.options['pager_scope'];
        var step = this.options['pager_step'];

        // Compute Pager
        var page_count = Math.ceil(parseFloat(total) / step);

        var page = Math.max(1, Math.min(parseInt(page), page_count));
        scope -= 1;

        var pmin = Math.max(page - parseInt(Math.floor(scope/2)), 1);
        var pmax = Math.min(pmin + scope, page_count);

        if(pmax - scope > 0){
            pmin = pmax - scope;
        }else{
            pmin = 1;
        }

        var pages = [];
        _.each(_.range(pmin, pmax+1), function(index){
            pages.push(index);
        });

        return {
            "page_count": page_count,
            "offset": (page - 1) * step,
            "page": page,
            "page_start": pmin,
            "page_previous": Math.max(pmin, page - 1),
            "page_next": Math.min(pmax, page + 1),
            "page_end": pmax,
            "pages": pages
        };
    },
    _renderMessages: function(){
        this.$('.o_portal_chatter_messages').html(qweb.render("portal.chatter_messages", {widget: this}));
    },
    _renderMessageCount: function(){
        this.$('.o_message_counter').replaceWith(qweb.render("portal.chatter_message_count", {widget: this}));
    },
    _renderPager: function(){
        this.$('.o_portal_chatter_pager').replaceWith(qweb.render("portal.pager", {widget: this}));
    },

    //--------------------------------------------------------------------------
    // Handlers
    //--------------------------------------------------------------------------

    _onChangeDomain: function(){
        var self = this;
        this.messageFetch().then(function(){
            var p = self._current_page;
            self.set('pager', self._pager(p));
        });
    },
    /**
     * @private
     * @param {MouseEvent} event
     */
    _onClickPager: function(ev){
        ev.preventDefault();
        var page = $(ev.currentTarget).data('page');
        this._changeCurrentPage(page);
    },
});

base.ready().then(function () {
    $('.o_portal_chatter').each(function (index) {
        var $elem = $(this);
        var mail_thread = new PortalChatter(null, $elem.data());
        mail_thread.appendTo($elem);
    });
});

return {
    PortalChatter: PortalChatter,
};

});
<commit_msg>[FIX] portal: It ask to login even if user already logged in<commit_after>odoo.define('portal.chatter', function(require) {
'use strict';

var base = require('web_editor.base');
var ajax = require('web.ajax');
var core = require('web.core');
var Widget = require('web.Widget');
var rpc = require('web.rpc');

var qweb = core.qweb;
var _t = core._t;

/**
 * Widget PortalChatter
 *
 * - Fetch message fron controller
 * - Display chatter: pager, total message, composer (according to access right)
 * - Provider API to filter displayed messages
 */
var PortalChatter = Widget.extend({
    template: 'portal.chatter',
    events: {
        "click .o_portal_chatter_pager_btn": '_onClickPager'
    },

    init: function(parent, options){
        this._super.apply(this, arguments);
        this.options = _.defaults(options || {}, {
            'allow_composer': true,
            'display_composer': false,
            'csrf_token': odoo.csrf_token,
            'message_count': 0,
            'pager_step': 10,
            'pager_scope': 5,
            'pager_start': 1,
            'is_user_public': true,
            'is_user_publisher': false,
            'domain': [],
        });
        this.set('messages', []);
        this.set('message_count', this.options['message_count']);
        this.set('pager', {});
        this.set('domain', this.options['domain']);
        this._current_page = this.options['pager_start'];
    },
    willStart: function(){
        var self = this;
        // load qweb template and init data
        return $.when(
            rpc.query({
                route: '/mail/chatter_init',
                params: this._messageFetchPrepareParams()
            }), this._loadTemplates()
        ).then(function(result){
            self.result = result;
            self.options = _.extend(self.options, self.result['options'] || {});
            return result;
        });
    },
    /**
     * @override
     */
    start: function () {
        // bind events
        this.on("change:messages", this, this._renderMessages);
        this.on("change:message_count", this, function(){
            this._renderMessageCount();
            this.set('pager', this._pager(this._current_page));
        });
        this.on("change:pager", this, this._renderPager);
        this.on("change:domain", this, this._onChangeDomain);
        // set options and parameters
        this.set('message_count', this.options['message_count']);
        this.set('messages', this.preprocessMessages(this.result['messages']));
        return this._super.apply(this, arguments);
    },

    //--------------------------------------------------------------------------
    // Public
    //--------------------------------------------------------------------------

    /**
     * Fetch the messages and the message count from the server for the
     * current page and current domain.
     *
     * @param {Array} domain
     * @returns {Deferred}
     */
    messageFetch: function(domain){
        var self = this;
        return rpc.query({
            route: '/mail/chatter_fetch',
            params: self._messageFetchPrepareParams()
        }).then(function(result){
            self.set('messages', self.preprocessMessages(result['messages']));
            self.set('message_count', result['message_count']);
        });
    },
    /**
     * Update the messages format
     *
     * @param {Array<Object>}
     * @returns {Array}
     */
    preprocessMessages: function(messages){
        _.each(messages, function(m){
            m['author_avatar_url'] = _.str.sprintf('/web/image/%s/%s/author_avatar/50x50', 'mail.message', m.id);
            m['published_date_str'] = _.str.sprintf(_t('Published on %s'), moment(m.date).format('MMMM Do YYYY, h:mm:ss a'));
        });
        return messages;
    },

    //--------------------------------------------------------------------------
    // Private
    //--------------------------------------------------------------------------

    /**
     * Change the current page by refreshing current domain
     *
     * @private
     * @param {Number} page
     * @param {Array} domain
     */
    _changeCurrentPage: function(page, domain){
        this._current_page = page;
        var d = domain ? domain : _.clone(this.get('domain'));
        this.set('domain', d); // trigger fetch message
    },
    /**
     * @private
     * @returns {Deferred}
     */
    _loadTemplates: function(){
        return ajax.loadXML('/portal/static/src/xml/portal_chatter.xml', qweb);
    },
    _messageFetchPrepareParams: function(){
        var self = this;
        var data = {
            'res_model': this.options['res_model'],
            'res_id': this.options['res_id'],
            'limit': this.options['pager_step'],
            'offset': (this._current_page-1) * this.options['pager_step'],
            'allow_composer': this.options['allow_composer'],
        };
        // add token field to allow to post comment without being logged
        if(self.options['token']){
            data['token'] = self.options['token'];
        }
        // add domain
        if(this.get('domain')){
            data['domain'] = this.get('domain');
        }
        return data;
    },
    /**
     * Generate the pager data for the given page number
     *
     * @private
     * @param {Number} page
     * @returns {Object}
     */
    _pager: function(page){
        var page = page || 1;
        var total = this.get('message_count');
        var scope = this.options['pager_scope'];
        var step = this.options['pager_step'];

        // Compute Pager
        var page_count = Math.ceil(parseFloat(total) / step);

        var page = Math.max(1, Math.min(parseInt(page), page_count));
        scope -= 1;

        var pmin = Math.max(page - parseInt(Math.floor(scope/2)), 1);
        var pmax = Math.min(pmin + scope, page_count);

        if(pmax - scope > 0){
            pmin = pmax - scope;
        }else{
            pmin = 1;
        }

        var pages = [];
        _.each(_.range(pmin, pmax+1), function(index){
            pages.push(index);
        });

        return {
            "page_count": page_count,
            "offset": (page - 1) * step,
            "page": page,
            "page_start": pmin,
            "page_previous": Math.max(pmin, page - 1),
            "page_next": Math.min(pmax, page + 1),
            "page_end": pmax,
            "pages": pages
        };
    },
    _renderMessages: function(){
        this.$('.o_portal_chatter_messages').html(qweb.render("portal.chatter_messages", {widget: this}));
    },
    _renderMessageCount: function(){
        this.$('.o_message_counter').replaceWith(qweb.render("portal.chatter_message_count", {widget: this}));
    },
    _renderPager: function(){
        this.$('.o_portal_chatter_pager').replaceWith(qweb.render("portal.pager", {widget: this}));
    },

    //--------------------------------------------------------------------------
    // Handlers
    //--------------------------------------------------------------------------

    _onChangeDomain: function(){
        var self = this;
        this.messageFetch().then(function(){
            var p = self._current_page;
            self.set('pager', self._pager(p));
        });
    },
    /**
     * @private
     * @param {MouseEvent} event
     */
    _onClickPager: function(ev){
        ev.preventDefault();
        var page = $(ev.currentTarget).data('page');
        this._changeCurrentPage(page);
    },
});

base.ready().then(function () {
    $('.o_portal_chatter').each(function (index) {
        var $elem = $(this);
        var mail_thread = new PortalChatter(null, $elem.data());
        mail_thread.appendTo($elem);
    });
});

return {
    PortalChatter: PortalChatter,
};

});
<|endoftext|>