<commit_before>/**
 * 简单选色控件
 *
 * Created by GUY on 2015/11/16.
 * @class BI.ColorPickerEditor
 * @extends BI.Widget
 */
BI.HexColorPickerEditor = BI.inherit(BI.Widget, {

    constants: {
        RGB_WIDTH: 32,
        HEX_WIDTH: 70,
        HEX_PREFIX_POSITION: 1
    },

    props: {
        baseCls: "bi-color-picker-editor",
        height: 30
    },

    render: function () {
        var self = this, o = this.options, c = this.constants;
        this.storeValue = {};
        var RGB = BI.createItems([{text: "R"}, {text: "G"}, {text: "B"}], {
            type: "bi.label",
            cls: "color-picker-editor-label",
            height: 20
        });

        var checker = function (v) {
            return BI.isNumeric(v) && (v | 0) >= 0 && (v | 0) <= 255;
        };
        var Ws = BI.map(BI.range(0, 3), function () {
            return {
                type: "bi.small_text_editor",
                cls: "color-picker-editor-input",
                validationChecker: checker,
                errorText: BI.i18nText("BI-Color_Picker_Error_Text"),
                allowBlank: true,
                value: 255,
                width: c.RGB_WIDTH,
                height: 24,
                listeners: [{
                    eventName: BI.TextEditor.EVENT_CHANGE,
                    action: function () {
                        self._checkEditors();
                        if (checker(self.storeValue.r) && checker(self.storeValue.g) && checker(self.storeValue.b)) {
                            self.colorShow.element.css("background-color", self.getValue());
                            self.fireEvent(BI.ColorPickerEditor.EVENT_CHANGE);
                        }
                    }
                }]
            };
        });

        return {
            type: "bi.absolute",
            items: [{
                el: {
                    type: "bi.vertical",
                    tgap: 10,
                    items: [{
                        type: 'bi.vertical_adapt',
                        columnSize: [0.5, 'fill'],
                        height: 24,
                        items: [{
                            type: "bi.color_picker_show_button",
                            cls: "trans-color-icon",
                            height: 22,
                            title: BI.i18nText("BI-Transparent_Color"),
                            text: BI.i18nText("BI-Transparent_Color"),
                            listeners: [{
                                eventName: BI.ColorChooserShowButton.EVENT_CHANGE,
                                action: function () {
                                    var value = self.getValue();
                                    self.setValue("transparent");
                                    (value !== "transparent") && self.fireEvent(BI.ColorPickerEditor.EVENT_CHANGE);
                                }
                            }],
                            ref: function (_ref) {
                                self.transparent = _ref;
                            }
                        }, {
                            el: {
                                type: "bi.color_picker_show_button",
                                cls: "auto-color-icon",
                                height: 22,
                                title: BI.i18nText("BI-Basic_Auto"),
                                text: BI.i18nText("BI-Basic_Auto"),
                                listeners: [{
                                    eventName: BI.ColorChooserShowButton.EVENT_CHANGE,
                                    action: function () {
                                        var value = self.getValue();
                                        self.setValue("");
                                        (value !== "") && self.fireEvent(BI.ColorPickerEditor.EVENT_CHANGE);
                                    }
                                }],
                                ref: function (_ref) {
                                    self.none = _ref;
                                }
                            },
                            lgap: 10,
                        }]
                    }, {
                        el: {
                            type: "bi.vertical_adapt",
                            columnSize: [22, 10, 'fill', 12, c.RGB_WIDTH, 12, c.RGB_WIDTH, 12, c.RGB_WIDTH],

                            rgap: 5,
                            items: [{
                                el: {
                                    type: "bi.layout",
                                    cls: "color-picker-editor-display bi-card bi-border",
                                    height: 22,
                                    width: 22,
                                    ref: function (_ref) {
                                        self.colorShow = _ref;
                                    }
                                },
                                width: 18
                            }, {
                                type: "bi.label",
                                text: "#",
                                width: 10
                            }, {
                                type: "bi.small_text_editor",
                                ref: function (_ref) {
                                    self.hexEditor = _ref;
                                },
                                cls: "color-picker-editor-input",
                                validationChecker: this._hexChecker,
                                allowBlank: true,
                                errorText: BI.i18nText("BI-Color_Picker_Error_Text_Hex"),
                                width: c.HEX_WIDTH,
                                height: 24,
                                listeners: [{
                                    eventName: "EVENT_CHANGE",
                                    action: function () {
                                        self._checkHexEditor();
                                        if (checker(self.storeValue.r) && checker(self.storeValue.g) && checker(self.storeValue.b)) {
                                            self.colorShow.element.css("background-color", self.getValue());
                                            self.fireEvent(BI.ColorPickerEditor.EVENT_CHANGE);
                                        }

                                    }
                                }]
                            }, RGB[0], {
                                el: BI.extend(Ws[0], {
                                    ref: function (_ref) {
                                        self.R = _ref
                                    }
                                }),
                                width: c.RGB_WIDTH
                            }, RGB[1], {
                                el: BI.extend(Ws[1], {
                                    ref: function (_ref) {
                                        self.G = _ref
                                    }
                                }),
                                width: c.RGB_WIDTH
                            }, RGB[2], {
                                el: BI.extend(Ws[2], {
                                    ref: function (_ref) {
                                        self.B = _ref
                                    }
                                }),
                                rgap: -5,
                                width: c.RGB_WIDTH
                            }]
                        }
                    }]
                },
                left: 0,
                right: 0,
                top: 0,
                bottom: 0
            }]
        };
    },

    _hexChecker: function (v) {
        return /^[0-9a-fA-F]{6}$/.test(v);
    },

    _checkEditors: function () {
        if(BI.isEmptyString(this.R.getValue())) {
            this.R.setValue(0);
        }
        if(BI.isEmptyString(this.G.getValue())) {
            this.G.setValue(0);
        }
        if(BI.isEmptyString(this.B.getValue())) {
            this.B.setValue(0);
        }
        this.storeValue = {
            r: this.R.getValue() || 0,
            g: this.G.getValue() || 0,
            b: this.B.getValue() || 0
        };
        this.hexEditor.setValue(this.getValue().slice(this.constants.HEX_PREFIX_POSITION));
    },

    _isEmptyRGB: function () {
        return BI.isEmptyString(this.storeValue.r) && BI.isEmptyString(this.storeValue.g) && BI.isEmptyString(this.storeValue.b);
    },

    _checkHexEditor: function () {
        if (BI.isEmptyString(this.hexEditor.getValue())) {
            this.hexEditor.setValue("000000");
        }
        var json = BI.DOM.rgb2json(BI.DOM.hex2rgb("#" + this.hexEditor.getValue()));
        this.storeValue = {
            r: json.r || 0,
            g: json.g || 0,
            b: json.b || 0,
        };
        this.R.setValue(this.storeValue.r);
        this.G.setValue(this.storeValue.g);
        this.B.setValue(this.storeValue.b);
    },

    _showPreColor: function (color) {
        if (color === "") {
            this.colorShow.element.css("background-color", "").removeClass("trans-color-background").addClass("auto-color-square-normal-background");
        } else if (color === "transparent") {
            this.colorShow.element.css("background-color", "").removeClass("auto-color-square-normal-background").addClass("trans-color-background");
        } else {
            this.colorShow.element.css({"background-color": color}).removeClass("auto-color-square-normal-background").removeClass("trans-color-background");
        }
    },

    _setEnable: function (enable) {
        BI.ColorPickerEditor.superclass._setEnable.apply(this, arguments);
        if (enable === true) {
            this.element.removeClass("base-disabled disabled");
        } else if (enable === false) {
            this.element.addClass("base-disabled disabled");
        }
    },

    setValue: function (color) {
        if (color === "transparent") {
            this.transparent.setSelected(true);
            this.none.setSelected(false);
            this._showPreColor("transparent");
            this.R.setValue("");
            this.G.setValue("");
            this.B.setValue("");
            this.hexEditor.setValue("");
            this.storeValue = {
                r: "",
                g: "",
                b: ""
            };
            return;
        }
        if (!color) {
            color = "";
            this.none.setSelected(true);
        } else {
            this.none.setSelected(false);
        }
        this.transparent.setSelected(false);
        this._showPreColor(color);
        var json = BI.DOM.rgb2json(BI.DOM.hex2rgb(color));
        this.storeValue = {
            r: BI.isNull(json.r) ? "" : json.r,
            g: BI.isNull(json.g) ? "" : json.g,
            b: BI.isNull(json.b) ? "" : json.b
        };
        this.R.setValue(this.storeValue.r);
        this.G.setValue(this.storeValue.g);
        this.B.setValue(this.storeValue.b);
        this.hexEditor.setValue(color.slice(this.constants.HEX_PREFIX_POSITION));
    },

    getValue: function () {
        if (this._isEmptyRGB() && this.transparent.isSelected()) {
            return "transparent";
        }
        return BI.DOM.rgb2hex(BI.DOM.json2rgb({
            r: this.storeValue.r,
            g: this.storeValue.g,
            b: this.storeValue.b
        }));
    }
});
BI.HexColorPickerEditor.EVENT_CHANGE = "EVENT_CHANGE";
BI.shortcut("bi.hex_color_picker_editor", BI.HexColorPickerEditor);<commit_msg>Pull request #2308: CHART-22056 fix:点击就传值，无需判断是否改变<commit_after>/**
 * 简单选色控件
 *
 * Created by GUY on 2015/11/16.
 * @class BI.ColorPickerEditor
 * @extends BI.Widget
 */
BI.HexColorPickerEditor = BI.inherit(BI.Widget, {

    constants: {
        RGB_WIDTH: 32,
        HEX_WIDTH: 70,
        HEX_PREFIX_POSITION: 1
    },

    props: {
        baseCls: "bi-color-picker-editor",
        height: 30
    },

    render: function () {
        var self = this, o = this.options, c = this.constants;
        this.storeValue = {};
        var RGB = BI.createItems([{text: "R"}, {text: "G"}, {text: "B"}], {
            type: "bi.label",
            cls: "color-picker-editor-label",
            height: 20
        });

        var checker = function (v) {
            return BI.isNumeric(v) && (v | 0) >= 0 && (v | 0) <= 255;
        };
        var Ws = BI.map(BI.range(0, 3), function () {
            return {
                type: "bi.small_text_editor",
                cls: "color-picker-editor-input",
                validationChecker: checker,
                errorText: BI.i18nText("BI-Color_Picker_Error_Text"),
                allowBlank: true,
                value: 255,
                width: c.RGB_WIDTH,
                height: 24,
                listeners: [{
                    eventName: BI.TextEditor.EVENT_CHANGE,
                    action: function () {
                        self._checkEditors();
                        if (checker(self.storeValue.r) && checker(self.storeValue.g) && checker(self.storeValue.b)) {
                            self.colorShow.element.css("background-color", self.getValue());
                            self.fireEvent(BI.ColorPickerEditor.EVENT_CHANGE);
                        }
                    }
                }]
            };
        });

        return {
            type: "bi.absolute",
            items: [{
                el: {
                    type: "bi.vertical",
                    tgap: 10,
                    items: [{
                        type: 'bi.vertical_adapt',
                        columnSize: [0.5, 'fill'],
                        height: 24,
                        items: [{
                            type: "bi.color_picker_show_button",
                            cls: "trans-color-icon",
                            height: 22,
                            title: BI.i18nText("BI-Transparent_Color"),
                            text: BI.i18nText("BI-Transparent_Color"),
                            listeners: [{
                                eventName: BI.ColorChooserShowButton.EVENT_CHANGE,
                                action: function () {
                                    self.setValue("transparent");
                                    self.fireEvent(BI.ColorPickerEditor.EVENT_CHANGE);
                                }
                            }],
                            ref: function (_ref) {
                                self.transparent = _ref;
                            }
                        }, {
                            el: {
                                type: "bi.color_picker_show_button",
                                cls: "auto-color-icon",
                                height: 22,
                                title: BI.i18nText("BI-Basic_Auto"),
                                text: BI.i18nText("BI-Basic_Auto"),
                                listeners: [{
                                    eventName: BI.ColorChooserShowButton.EVENT_CHANGE,
                                    action: function () {
                                        self.setValue("");
                                        self.fireEvent(BI.ColorPickerEditor.EVENT_CHANGE);
                                    }
                                }],
                                ref: function (_ref) {
                                    self.none = _ref;
                                }
                            },
                            lgap: 10,
                        }]
                    }, {
                        el: {
                            type: "bi.vertical_adapt",
                            columnSize: [22, 10, 'fill', 12, c.RGB_WIDTH, 12, c.RGB_WIDTH, 12, c.RGB_WIDTH],

                            rgap: 5,
                            items: [{
                                el: {
                                    type: "bi.layout",
                                    cls: "color-picker-editor-display bi-card bi-border",
                                    height: 22,
                                    width: 22,
                                    ref: function (_ref) {
                                        self.colorShow = _ref;
                                    }
                                },
                                width: 18
                            }, {
                                type: "bi.label",
                                text: "#",
                                width: 10
                            }, {
                                type: "bi.small_text_editor",
                                ref: function (_ref) {
                                    self.hexEditor = _ref;
                                },
                                cls: "color-picker-editor-input",
                                validationChecker: this._hexChecker,
                                allowBlank: true,
                                errorText: BI.i18nText("BI-Color_Picker_Error_Text_Hex"),
                                width: c.HEX_WIDTH,
                                height: 24,
                                listeners: [{
                                    eventName: "EVENT_CHANGE",
                                    action: function () {
                                        self._checkHexEditor();
                                        if (checker(self.storeValue.r) && checker(self.storeValue.g) && checker(self.storeValue.b)) {
                                            self.colorShow.element.css("background-color", self.getValue());
                                            self.fireEvent(BI.ColorPickerEditor.EVENT_CHANGE);
                                        }

                                    }
                                }]
                            }, RGB[0], {
                                el: BI.extend(Ws[0], {
                                    ref: function (_ref) {
                                        self.R = _ref
                                    }
                                }),
                                width: c.RGB_WIDTH
                            }, RGB[1], {
                                el: BI.extend(Ws[1], {
                                    ref: function (_ref) {
                                        self.G = _ref
                                    }
                                }),
                                width: c.RGB_WIDTH
                            }, RGB[2], {
                                el: BI.extend(Ws[2], {
                                    ref: function (_ref) {
                                        self.B = _ref
                                    }
                                }),
                                rgap: -5,
                                width: c.RGB_WIDTH
                            }]
                        }
                    }]
                },
                left: 0,
                right: 0,
                top: 0,
                bottom: 0
            }]
        };
    },

    _hexChecker: function (v) {
        return /^[0-9a-fA-F]{6}$/.test(v);
    },

    _checkEditors: function () {
        if(BI.isEmptyString(this.R.getValue())) {
            this.R.setValue(0);
        }
        if(BI.isEmptyString(this.G.getValue())) {
            this.G.setValue(0);
        }
        if(BI.isEmptyString(this.B.getValue())) {
            this.B.setValue(0);
        }
        this.storeValue = {
            r: this.R.getValue() || 0,
            g: this.G.getValue() || 0,
            b: this.B.getValue() || 0
        };
        this.hexEditor.setValue(this.getValue().slice(this.constants.HEX_PREFIX_POSITION));
    },

    _isEmptyRGB: function () {
        return BI.isEmptyString(this.storeValue.r) && BI.isEmptyString(this.storeValue.g) && BI.isEmptyString(this.storeValue.b);
    },

    _checkHexEditor: function () {
        if (BI.isEmptyString(this.hexEditor.getValue())) {
            this.hexEditor.setValue("000000");
        }
        var json = BI.DOM.rgb2json(BI.DOM.hex2rgb("#" + this.hexEditor.getValue()));
        this.storeValue = {
            r: json.r || 0,
            g: json.g || 0,
            b: json.b || 0,
        };
        this.R.setValue(this.storeValue.r);
        this.G.setValue(this.storeValue.g);
        this.B.setValue(this.storeValue.b);
    },

    _showPreColor: function (color) {
        if (color === "") {
            this.colorShow.element.css("background-color", "").removeClass("trans-color-background").addClass("auto-color-square-normal-background");
        } else if (color === "transparent") {
            this.colorShow.element.css("background-color", "").removeClass("auto-color-square-normal-background").addClass("trans-color-background");
        } else {
            this.colorShow.element.css({"background-color": color}).removeClass("auto-color-square-normal-background").removeClass("trans-color-background");
        }
    },

    _setEnable: function (enable) {
        BI.ColorPickerEditor.superclass._setEnable.apply(this, arguments);
        if (enable === true) {
            this.element.removeClass("base-disabled disabled");
        } else if (enable === false) {
            this.element.addClass("base-disabled disabled");
        }
    },

    setValue: function (color) {
        if (color === "transparent") {
            this.transparent.setSelected(true);
            this.none.setSelected(false);
            this._showPreColor("transparent");
            this.R.setValue("");
            this.G.setValue("");
            this.B.setValue("");
            this.hexEditor.setValue("");
            this.storeValue = {
                r: "",
                g: "",
                b: ""
            };
            return;
        }
        if (!color) {
            color = "";
            this.none.setSelected(true);
        } else {
            this.none.setSelected(false);
        }
        this.transparent.setSelected(false);
        this._showPreColor(color);
        var json = BI.DOM.rgb2json(BI.DOM.hex2rgb(color));
        this.storeValue = {
            r: BI.isNull(json.r) ? "" : json.r,
            g: BI.isNull(json.g) ? "" : json.g,
            b: BI.isNull(json.b) ? "" : json.b
        };
        this.R.setValue(this.storeValue.r);
        this.G.setValue(this.storeValue.g);
        this.B.setValue(this.storeValue.b);
        this.hexEditor.setValue(color.slice(this.constants.HEX_PREFIX_POSITION));
    },

    getValue: function () {
        if (this._isEmptyRGB() && this.transparent.isSelected()) {
            return "transparent";
        }
        return BI.DOM.rgb2hex(BI.DOM.json2rgb({
            r: this.storeValue.r,
            g: this.storeValue.g,
            b: this.storeValue.b
        }));
    }
});
BI.HexColorPickerEditor.EVENT_CHANGE = "EVENT_CHANGE";
BI.shortcut("bi.hex_color_picker_editor", BI.HexColorPickerEditor);<|endoftext|>


<commit_before>/**
 * File Contents Description.
 *
 * Site Kit by Google, Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import invariant from 'invariant';

// Actions
const SET_REGISTRY_KEY = 'SET_REGISTRY_KEY';

const INITIAL_STATE = {
	registryKey: undefined,
};

export const actions = {
	/**
	 * Sets the registryKey in the data store.
	 *
	 * @since n.e.x.t
	 *
	 * @param {string} registryKey The registryKey for a given store.
	 * @return {Object} Redux-style action.
	 */
	setRegistryKey( registryKey ) {
		invariant( registryKey, 'registryKey is required.' );
		return {
			payload: { registryKey },
			type: SET_REGISTRY_KEY,
		};
	},
};

/**
 * Registry reducer.
 *
 * @since n.e.x.t
 *
 * @param {Object}             state          Data store's state.
 * @param {Object}             action         Redux-style action.
 * @return {Object} Data store's state
 */
export const reducer = ( state, { payload, type } ) => {
	switch ( type ) {
		case SET_REGISTRY_KEY: {
			const { registryKey } = payload;
			return {
				...state,
				registryKey,
			};
		}
		default: {
			return { ...state };
		}
	}
};

export const selectors = {
	/**
	 * Returns the registry key being used for a given store.
	 *
	 * @since n.e.x.t
	 * @private
	 *
	 * @param {Object} state Data store's state.
	 * @return {(string|undefined)} The registryKey for a given store. Returns `undefined` if the key has not yet been set.
	 */
	getRegistryKey( state ) {
		const { registryKey } = state;

		return registryKey;
	},
};

export default {
	INITIAL_STATE,
	actions,
	reducer,
	selectors,
};
<commit_msg>Remove docbloc for reducer.<commit_after>/**
 * File Contents Description.
 *
 * Site Kit by Google, Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import invariant from 'invariant';

// Actions
const SET_REGISTRY_KEY = 'SET_REGISTRY_KEY';

const INITIAL_STATE = {
	registryKey: undefined,
};

export const actions = {
	/**
	 * Sets the registryKey in the data store.
	 *
	 * @since n.e.x.t
	 *
	 * @param {string} registryKey The registryKey for a given store.
	 * @return {Object} Redux-style action.
	 */
	setRegistryKey( registryKey ) {
		invariant( registryKey, 'registryKey is required.' );
		return {
			payload: { registryKey },
			type: SET_REGISTRY_KEY,
		};
	},
};

export const reducer = ( state, { payload, type } ) => {
	switch ( type ) {
		case SET_REGISTRY_KEY: {
			const { registryKey } = payload;
			return {
				...state,
				registryKey,
			};
		}
		default: {
			return { ...state };
		}
	}
};

export const selectors = {
	/**
	 * Returns the registry key being used for a given store.
	 *
	 * @since n.e.x.t
	 * @private
	 *
	 * @param {Object} state Data store's state.
	 * @return {(string|undefined)} The registryKey for a given store. Returns `undefined` if the key has not yet been set.
	 */
	getRegistryKey( state ) {
		const { registryKey } = state;

		return registryKey;
	},
};

export default {
	INITIAL_STATE,
	actions,
	reducer,
	selectors,
};
<|endoftext|>


<commit_before>var $ = require('jquery');
var _ = require('underscore');
var log = require('cdb.log');
var View = require('../../core/view');

/**
 *  FullScreen widget:
 *
 *  var widget = new FullScreen({
 *    doc: ".container", // optional; if not specified, we do the fullscreen of the whole window
 *    template: this.getTemplate("table/views/fullscreen")
 *  });
 *
 */
var FullScreen = View.extend({

  tagName: 'div',
  className: 'CDB-Fullscreen',

  events: {
    "click a": "_toggleFullScreen"
  },

  initialize: function() {
    _.bindAll(this, 'render');
    _.defaults(this.options, this.default_options);
    this._addWheelEvent();
  },

  _addWheelEvent: function() {
    var self    = this;
    var mapView = this.options.mapView;

    $(document).on('webkitfullscreenchange mozfullscreenchange fullscreenchange', function() {
      if (!document.fullscreenElement && !document.webkitFullscreenElement && !document.mozFullScreenElement && !document.msFullscreenElement) {
        if (self.model.get("allowWheelOnFullscreen")) {
          mapView.options.map.set("scrollwheel", false);
        }
      }
      mapView.invalidateSize();
    });
  },

  _toggleFullScreen: function(ev) {
    if (ev) {
      this.killEvent(ev);
    }

    var doc   = window.document;
    var docEl = doc.documentElement;

    if (this.options.doc) { // we use a custom element
      docEl = $(this.options.doc)[0];
    }

    var requestFullScreen = docEl.requestFullscreen || docEl.mozRequestFullScreen || docEl.webkitRequestFullScreen || docEl.msRequestFullscreen;
    var cancelFullScreen = doc.exitFullscreen || doc.mozCancelFullScreen || doc.webkitExitFullscreen || doc.msExitFullscreen;
    var mapView = this.options.mapView;

    if (!doc.fullscreenElement && !doc.mozFullScreenElement && !doc.webkitFullscreenElement && !doc.msFullscreenElement) {
      if (docEl.webkitRequestFullScreen) {
        // Cartodb.js #361 :: Full screen button not working on Safari 8.0.3 #361
        // Safari has a bug that fullScreen doestn't work with Element.ALLOW_KEYBOARD_INPUT);
        // Reference: Ehttp://stackoverflow.com/questions/8427413/webkitrequestfullscreen-fails-when-passing-element-allow-keyboard-input-in-safar
        requestFullScreen.call(docEl, undefined);
      } else {
        // CartoDB.js #412 :: Fullscreen button is throwing errors
        // Nowadays (2015/03/25), fullscreen is not supported in iOS Safari. Reference: http://caniuse.com/#feat=fullscreen
        if (requestFullScreen) {
          requestFullScreen.call(docEl);
        }
      }

      if (mapView && this.model.get("allowWheelOnFullscreen")) {
        mapView.map.set("scrollwheel", true);
      }
    } else {
      cancelFullScreen.call(doc);
    }
  },

  render: function() {
    var options = _.extend(
      this.options,
      {
        mapUrl: location.href || ''
      }
    );
    this.$el.html(this.options.template(options));

    if (!this._canFullScreenBeEnabled()) {
      this.undelegateEvents();
      log.info('FullScreen API is deprecated on insecure origins. See https://goo.gl/rStTGz for more details.');
    }

    return this;
  },

  _canFullScreenBeEnabled: function() {
    if (this._isInIframe()) {
      var parentUrl = document.referrer;
      if (parentUrl.search('https:') !== 0) {
        return false;
      }
    }
    return true;
  },

  _isInIframe: function() {
    try {
      return window.self !== window.top;
    } catch (e) {
      return true;
    }
  }

});

module.exports = FullScreen;
<commit_msg>Moved old fullscreen code to a new folder location<commit_after><|endoftext|>


<commit_before>THREE.MeshLine = function() {

	this.positions = [];

	this.previous = [];
	this.next = [];
	this.side = [];
	this.width = [];
	this.indices_array = [];
	this.uvs = [];

	this.geometry = new THREE.BufferGeometry();

	this.widthCallback = null;

}

THREE.MeshLine.prototype.setGeometry = function( g, c ) {

	this.widthCallback = c;

	this.positions = [];

	if( g instanceof THREE.Geometry ) {
		for( var j = 0; j < g.vertices.length; j++ ) {
			var v = g.vertices[ j ];
			this.positions.push( v.x, v.y, v.z );
			this.positions.push( v.x, v.y, v.z );
		}
	}

	if( g instanceof THREE.BufferGeometry ) {
		// read attribute positions ?
	}

	if( g instanceof Float32Array || g instanceof Array ) {
		for( var j = 0; j < g.length; j += 3 ) {
			this.positions.push( g[ j ], g[ j + 1 ], g[ j + 2 ] );
			this.positions.push( g[ j ], g[ j + 1 ], g[ j + 2 ] );
		}
	}

	this.process();

}

THREE.MeshLine.prototype.compareV3 = function( a, b ) {

	var aa = a * 6;
	var ab = b * 6;
	return ( this.positions[ aa ] === this.positions[ ab ] ) && ( this.positions[ aa + 1 ] === this.positions[ ab + 1 ] ) && ( this.positions[ aa + 2 ] === this.positions[ ab + 2 ] );

}

THREE.MeshLine.prototype.copyV3 = function( a ) {

	var aa = a * 6;
	return [ this.positions[ aa ], this.positions[ aa + 1 ], this.positions[ aa + 2 ] ];

}

THREE.MeshLine.prototype.process = function() {

	var l = this.positions.length / 6;

	this.previous = [];
	this.next = [];
	this.side = [];
	this.width = [];
	this.indices_array = [];
	this.uvs = [];

	for( var j = 0; j < l; j++ ) {
		this.side.push( 1 );
		this.side.push( -1 );
	}

	var w;
	for( var j = 0; j < l; j++ ) {
		if( this.widthCallback ) w = this.widthCallback( j / ( l -1 ) );
		else w = 1;
		this.width.push( w );
		this.width.push( w );
	}

	for( var j = 0; j < l; j++ ) {
		this.uvs.push( j / ( l - 1 ), 0 );
		this.uvs.push( j / ( l - 1 ), 1 );
	}

	var v;

	if( this.compareV3( 0, l - 1 ) ){
		v = this.copyV3( l - 2 );
	} else {
		v = this.copyV3( 0 );
	}
	this.previous.push( v[ 0 ], v[ 1 ], v[ 2 ] );
	this.previous.push( v[ 0 ], v[ 1 ], v[ 2 ] );
	for( var j = 0; j < l - 1; j++ ) {
		v = this.copyV3( j );
		this.previous.push( v[ 0 ], v[ 1 ], v[ 2 ] );
		this.previous.push( v[ 0 ], v[ 1 ], v[ 2 ] );
	}

	for( var j = 1; j < l; j++ ) {
		v = this.copyV3( j );
		this.next.push( v[ 0 ], v[ 1 ], v[ 2 ] );
		this.next.push( v[ 0 ], v[ 1 ], v[ 2 ] );
	}

	if( this.compareV3( l - 1, 0 ) ){
		v = this.copyV3( 1 );
	} else {
		v = this.copyV3( l - 1 );
	}
	this.next.push( v[ 0 ], v[ 1 ], v[ 2 ] );
	this.next.push( v[ 0 ], v[ 1 ], v[ 2 ] );

	for( var j = 0; j < l - 1; j++ ) {
		var n = j * 2;
		this.indices_array.push( n, n + 1, n + 2 );
		this.indices_array.push( n + 2, n + 1, n + 3 );
	}

	this.attributes = {
		position: new THREE.BufferAttribute( new Float32Array( this.positions ), 3 ),
		previous: new THREE.BufferAttribute( new Float32Array( this.previous ), 3 ),
		next: new THREE.BufferAttribute( new Float32Array( this.next ), 3 ),
		side: new THREE.BufferAttribute( new Float32Array( this.side ), 1 ),
		width: new THREE.BufferAttribute( new Float32Array( this.width ), 1 ),
		uv: new THREE.BufferAttribute( new Float32Array( this.uvs ), 2 ),
		index: new THREE.BufferAttribute( new Uint16Array( this.indices_array ), 1 )
	}

	this.geometry.addAttribute( 'position', this.attributes.position );
	this.geometry.addAttribute( 'previous', this.attributes.previous );
	this.geometry.addAttribute( 'next', this.attributes.next );
	this.geometry.addAttribute( 'side', this.attributes.side );
	this.geometry.addAttribute( 'width', this.attributes.width );
	this.geometry.addAttribute( 'uv', this.attributes.uv );

	this.geometry.setIndex( this.attributes.index );

}

THREE.MeshLineMaterial = function() {

	this.material = new THREE.RawShaderMaterial( {
		uniforms:{
			lineWidth: { type: 'f', value: 1 },
			map: { type: 't', value: strokeTexture },
			useMap: { type: 'f', value: 0 },
			color: { type: 'c', value: new THREE.Color( colors[ ~~Maf.randomInRange( 0, colors.length ) ] ) },
			resolution: { type: 'v2', value: resolution },
			sizeAttenuation: { type: 'f', value: 1 },
			near: { type: 'f', value: camera.near },
			far: { type: 'f', value: camera.far }
		},
		vertexShader: document.getElementById( 'vs-line' ).textContent,
		fragmentShader: document.getElementById( 'fs-line' ).textContent,
		/*side: THREE.DoubleSide,
		transparent: true,
		depthTest: false,
		blending: THREE.AdditiveAlphaBlending*/
	});

}

THREE.MeshLineMaterial = function ( parameters ) {

	var vertexShaderSource = [
'precision highp float;',
'',
'attribute vec3 position;',
'attribute vec3 previous;',
'attribute vec3 next;',
'attribute float side;',
'attribute float width;',
'attribute vec2 uv;',
'',
'uniform mat4 projectionMatrix;',
'uniform mat4 modelViewMatrix;',
'uniform vec2 resolution;',
'uniform float lineWidth;',
'uniform vec3 color;',
'uniform float opacity;',
'uniform float near;',
'uniform float far;',
'uniform float sizeAttenuation;',
'',
'varying vec2 vUV;',
'varying vec4 vColor;',
'varying vec3 vPosition;',
'',
'vec2 fix( vec4 i, float aspect ) {',
'',
'    vec2 res = i.xy / i.w;',
'    res.x *= aspect;',
'    return res;',
'',
'}',
'',
'void main() {',
'',
'    float aspect = resolution.x / resolution.y;',
'	 float pixelWidthRatio = 1. / (resolution.x * projectionMatrix[0][0]);',
'',
'    vColor = vec4( color, opacity );',
'    vUV = uv;',
'',
'    mat4 m = projectionMatrix * modelViewMatrix;',
'    vec4 finalPosition = m * vec4( position, 1.0 );',
'    vec4 prevPos = m * vec4( previous, 1.0 );',
'    vec4 nextPos = m * vec4( next, 1.0 );',
'',
'    vec2 currentP = fix( finalPosition, aspect );',
'    vec2 prevP = fix( prevPos, aspect );',
'    vec2 nextP = fix( nextPos, aspect );',
'',
'	 float pixelWidth = finalPosition.w * pixelWidthRatio;',
'    float w = 1.8 * pixelWidth * lineWidth * width;',
'',
'    if( sizeAttenuation == 1. ) {',
'        w = 1.8 * lineWidth * width;',
'    }',
'',
'    vec2 dir;',
'    if( nextP == currentP ) dir = normalize( currentP - prevP );',
'    else if( prevP == currentP ) dir = normalize( nextP - currentP );',
'    else {',
'        vec2 dir1 = normalize( currentP - prevP );',
'        vec2 dir2 = normalize( nextP - currentP );',
'        dir = normalize( dir1 + dir2 );',
'',
'        vec2 perp = vec2( -dir1.y, dir1.x );',
'        vec2 miter = vec2( -dir.y, dir.x );',
'        //w = clamp( w / dot( miter, perp ), 0., 4. * lineWidth * width );',
'',
'    }',
'',
'    //vec2 normal = ( cross( vec3( dir, 0. ), vec3( 0., 0., 1. ) ) ).xy;',
'    vec2 normal = vec2( -dir.y, dir.x );',
'    normal.x /= aspect;',
'    normal *= .5 * w;',
'',
'    vec4 offset = vec4( normal * side, 0.0, 1.0 );',
'    finalPosition.xy += offset.xy;',
'',
'	 vPosition = ( modelViewMatrix * vec4( position, 1. ) ).xyz;',
'    gl_Position = finalPosition;',
'',
'}' ];

	var fragmentShaderSource = [
		'#extension GL_OES_standard_derivatives : enable',
'precision mediump float;',
'',
'uniform sampler2D map;',
'uniform float useMap;',
'uniform float useDash;',
'uniform vec2 dashArray;',
'',
'varying vec2 vUV;',
'varying vec4 vColor;',
'varying vec3 vPosition;',
'',
'void main() {',
'',
'    vec4 c = vColor;',
'    if( useMap == 1. ) c *= texture2D( map, vUV );',
'	 if( useDash == 1. ){',
'	 	 ',
'	 }',
'    gl_FragColor = c;',
'',
'}' ];

	function check( v, d ) {
		if( v === undefined ) return d;
		return v;
	}

	THREE.Material.call( this );

	parameters = parameters || {};

	this.lineWidth = check( parameters.lineWidth, 1 );
	this.map = check( parameters.map, null );
	this.useMap = check( parameters.useMap, 0 );
	this.color = check( parameters.color, new THREE.Color( 0xffffff ) );
	this.opacity = check( parameters.opacity, 1 );
	this.resolution = check( parameters.resolution, new THREE.Vector2( 1, 1 ) );
	this.sizeAttenuation = check( parameters.sizeAttenuation, 1 );
	this.near = check( parameters.near, 1 );
	this.far = check( parameters.far, 1 );
	this.dashArray = check( parameters.dashArray, [] );
	this.useDash = ( this.dashArray !== [] ) ? 1 : 0;

	var material = new THREE.RawShaderMaterial( {
		uniforms:{
			lineWidth: { type: 'f', value: this.lineWidth },
			map: { type: 't', value: this.map },
			useMap: { type: 'f', value: this.useMap },
			color: { type: 'c', value: this.color },
			opacity: { type: 'f', value: this.opacity },
			resolution: { type: 'v2', value: this.resolution },
			sizeAttenuation: { type: 'f', value: this.sizeAttenuation },
			near: { type: 'f', value: this.near },
			far: { type: 'f', value: this.far },
			dashArray: { type: 'v2', value: new THREE.Vector2( this.dashArray[ 0 ], this.dashArray[ 1 ] ) },
			useDash: { type: 'f', value: this.useDash }
		},
		vertexShader: vertexShaderSource.join( '\r\n' ),
		fragmentShader: fragmentShaderSource.join( '\r\n' )
	});

	delete parameters.lineWidth;
	delete parameters.map;
	delete parameters.useMap;
	delete parameters.color;
	delete parameters.opacity;
	delete parameters.resolution;
	delete parameters.sizeAttenuation;
	delete parameters.near;
	delete parameters.far;
	delete parameters.dashArray;

	material.type = 'MeshLineMaterial';

	material.setValues( parameters );

	return material;

};

THREE.MeshLineMaterial.prototype = Object.create( THREE.Material.prototype );
THREE.MeshLineMaterial.prototype.constructor = THREE.MeshLineMaterial;

THREE.MeshLineMaterial.prototype.copy = function ( source ) {

	THREE.Material.prototype.copy.call( this, source );

	this.lineWidth = source.lineWidth;
	this.map = source.map;
	this.useMap = source.useMap;
	this.color.copy( source.color );
	this.opacity = source.opacity;
	this.resolution.copy( source.resolution );
	this.sizeAttenuation = source.sizeAttenuation;
	this.near = source.near;
	this.far = source.far;

	return this;

};<commit_msg>Update THREE.MeshLine.js<commit_after>THREE.MeshLine = function() {

	this.positions = [];

	this.previous = [];
	this.next = [];
	this.side = [];
	this.width = [];
	this.indices_array = [];
	this.uvs = [];

	this.geometry = new THREE.BufferGeometry();

	this.widthCallback = null;

}

THREE.MeshLine.prototype.setGeometry = function( g, c ) {

	this.widthCallback = c;

	this.positions = [];

	if( g instanceof THREE.Geometry ) {
		for( var j = 0; j < g.vertices.length; j++ ) {
			var v = g.vertices[ j ];
			this.positions.push( v.x, v.y, v.z );
			this.positions.push( v.x, v.y, v.z );
		}
	}

	if( g instanceof THREE.BufferGeometry ) {
		// read attribute positions ?
	}

	if( g instanceof Float32Array || g instanceof Array ) {
		for( var j = 0; j < g.length; j += 3 ) {
			this.positions.push( g[ j ], g[ j + 1 ], g[ j + 2 ] );
			this.positions.push( g[ j ], g[ j + 1 ], g[ j + 2 ] );
		}
	}

	this.process();

}

THREE.MeshLine.prototype.compareV3 = function( a, b ) {

	var aa = a * 6;
	var ab = b * 6;
	return ( this.positions[ aa ] === this.positions[ ab ] ) && ( this.positions[ aa + 1 ] === this.positions[ ab + 1 ] ) && ( this.positions[ aa + 2 ] === this.positions[ ab + 2 ] );

}

THREE.MeshLine.prototype.copyV3 = function( a ) {

	var aa = a * 6;
	return [ this.positions[ aa ], this.positions[ aa + 1 ], this.positions[ aa + 2 ] ];

}

THREE.MeshLine.prototype.process = function() {

	var l = this.positions.length / 6;

	this.previous = [];
	this.next = [];
	this.side = [];
	this.width = [];
	this.indices_array = [];
	this.uvs = [];

	for( var j = 0; j < l; j++ ) {
		this.side.push( 1 );
		this.side.push( -1 );
	}

	var w;
	for( var j = 0; j < l; j++ ) {
		if( this.widthCallback ) w = this.widthCallback( j / ( l -1 ) );
		else w = 1;
		this.width.push( w );
		this.width.push( w );
	}

	for( var j = 0; j < l; j++ ) {
		this.uvs.push( j / ( l - 1 ), 0 );
		this.uvs.push( j / ( l - 1 ), 1 );
	}

	var v;

	if( this.compareV3( 0, l - 1 ) ){
		v = this.copyV3( l - 2 );
	} else {
		v = this.copyV3( 0 );
	}
	this.previous.push( v[ 0 ], v[ 1 ], v[ 2 ] );
	this.previous.push( v[ 0 ], v[ 1 ], v[ 2 ] );
	for( var j = 0; j < l - 1; j++ ) {
		v = this.copyV3( j );
		this.previous.push( v[ 0 ], v[ 1 ], v[ 2 ] );
		this.previous.push( v[ 0 ], v[ 1 ], v[ 2 ] );
	}

	for( var j = 1; j < l; j++ ) {
		v = this.copyV3( j );
		this.next.push( v[ 0 ], v[ 1 ], v[ 2 ] );
		this.next.push( v[ 0 ], v[ 1 ], v[ 2 ] );
	}

	if( this.compareV3( l - 1, 0 ) ){
		v = this.copyV3( 1 );
	} else {
		v = this.copyV3( l - 1 );
	}
	this.next.push( v[ 0 ], v[ 1 ], v[ 2 ] );
	this.next.push( v[ 0 ], v[ 1 ], v[ 2 ] );

	for( var j = 0; j < l - 1; j++ ) {
		var n = j * 2;
		this.indices_array.push( n, n + 1, n + 2 );
		this.indices_array.push( n + 2, n + 1, n + 3 );
	}

	this.attributes = {
		position: new THREE.BufferAttribute( new Float32Array( this.positions ), 3 ),
		previous: new THREE.BufferAttribute( new Float32Array( this.previous ), 3 ),
		next: new THREE.BufferAttribute( new Float32Array( this.next ), 3 ),
		side: new THREE.BufferAttribute( new Float32Array( this.side ), 1 ),
		width: new THREE.BufferAttribute( new Float32Array( this.width ), 1 ),
		uv: new THREE.BufferAttribute( new Float32Array( this.uvs ), 2 ),
		index: new THREE.BufferAttribute( new Uint16Array( this.indices_array ), 1 )
	}

	this.geometry.addAttribute( 'position', this.attributes.position );
	this.geometry.addAttribute( 'previous', this.attributes.previous );
	this.geometry.addAttribute( 'next', this.attributes.next );
	this.geometry.addAttribute( 'side', this.attributes.side );
	this.geometry.addAttribute( 'width', this.attributes.width );
	this.geometry.addAttribute( 'uv', this.attributes.uv );

	this.geometry.setIndex( this.attributes.index );

}

THREE.MeshLineMaterial = function ( parameters ) {

	var vertexShaderSource = [
'precision highp float;',
'',
'attribute vec3 position;',
'attribute vec3 previous;',
'attribute vec3 next;',
'attribute float side;',
'attribute float width;',
'attribute vec2 uv;',
'',
'uniform mat4 projectionMatrix;',
'uniform mat4 modelViewMatrix;',
'uniform vec2 resolution;',
'uniform float lineWidth;',
'uniform vec3 color;',
'uniform float opacity;',
'uniform float near;',
'uniform float far;',
'uniform float sizeAttenuation;',
'',
'varying vec2 vUV;',
'varying vec4 vColor;',
'varying vec3 vPosition;',
'',
'vec2 fix( vec4 i, float aspect ) {',
'',
'    vec2 res = i.xy / i.w;',
'    res.x *= aspect;',
'    return res;',
'',
'}',
'',
'void main() {',
'',
'    float aspect = resolution.x / resolution.y;',
'	 float pixelWidthRatio = 1. / (resolution.x * projectionMatrix[0][0]);',
'',
'    vColor = vec4( color, opacity );',
'    vUV = uv;',
'',
'    mat4 m = projectionMatrix * modelViewMatrix;',
'    vec4 finalPosition = m * vec4( position, 1.0 );',
'    vec4 prevPos = m * vec4( previous, 1.0 );',
'    vec4 nextPos = m * vec4( next, 1.0 );',
'',
'    vec2 currentP = fix( finalPosition, aspect );',
'    vec2 prevP = fix( prevPos, aspect );',
'    vec2 nextP = fix( nextPos, aspect );',
'',
'	 float pixelWidth = finalPosition.w * pixelWidthRatio;',
'    float w = 1.8 * pixelWidth * lineWidth * width;',
'',
'    if( sizeAttenuation == 1. ) {',
'        w = 1.8 * lineWidth * width;',
'    }',
'',
'    vec2 dir;',
'    if( nextP == currentP ) dir = normalize( currentP - prevP );',
'    else if( prevP == currentP ) dir = normalize( nextP - currentP );',
'    else {',
'        vec2 dir1 = normalize( currentP - prevP );',
'        vec2 dir2 = normalize( nextP - currentP );',
'        dir = normalize( dir1 + dir2 );',
'',
'        vec2 perp = vec2( -dir1.y, dir1.x );',
'        vec2 miter = vec2( -dir.y, dir.x );',
'        //w = clamp( w / dot( miter, perp ), 0., 4. * lineWidth * width );',
'',
'    }',
'',
'    //vec2 normal = ( cross( vec3( dir, 0. ), vec3( 0., 0., 1. ) ) ).xy;',
'    vec2 normal = vec2( -dir.y, dir.x );',
'    normal.x /= aspect;',
'    normal *= .5 * w;',
'',
'    vec4 offset = vec4( normal * side, 0.0, 1.0 );',
'    finalPosition.xy += offset.xy;',
'',
'	 vPosition = ( modelViewMatrix * vec4( position, 1. ) ).xyz;',
'    gl_Position = finalPosition;',
'',
'}' ];

	var fragmentShaderSource = [
		'#extension GL_OES_standard_derivatives : enable',
'precision mediump float;',
'',
'uniform sampler2D map;',
'uniform float useMap;',
'uniform float useDash;',
'uniform vec2 dashArray;',
'',
'varying vec2 vUV;',
'varying vec4 vColor;',
'varying vec3 vPosition;',
'',
'void main() {',
'',
'    vec4 c = vColor;',
'    if( useMap == 1. ) c *= texture2D( map, vUV );',
'	 if( useDash == 1. ){',
'	 	 ',
'	 }',
'    gl_FragColor = c;',
'',
'}' ];

	function check( v, d ) {
		if( v === undefined ) return d;
		return v;
	}

	THREE.Material.call( this );

	parameters = parameters || {};

	this.lineWidth = check( parameters.lineWidth, 1 );
	this.map = check( parameters.map, null );
	this.useMap = check( parameters.useMap, 0 );
	this.color = check( parameters.color, new THREE.Color( 0xffffff ) );
	this.opacity = check( parameters.opacity, 1 );
	this.resolution = check( parameters.resolution, new THREE.Vector2( 1, 1 ) );
	this.sizeAttenuation = check( parameters.sizeAttenuation, 1 );
	this.near = check( parameters.near, 1 );
	this.far = check( parameters.far, 1 );
	this.dashArray = check( parameters.dashArray, [] );
	this.useDash = ( this.dashArray !== [] ) ? 1 : 0;

	var material = new THREE.RawShaderMaterial( {
		uniforms:{
			lineWidth: { type: 'f', value: this.lineWidth },
			map: { type: 't', value: this.map },
			useMap: { type: 'f', value: this.useMap },
			color: { type: 'c', value: this.color },
			opacity: { type: 'f', value: this.opacity },
			resolution: { type: 'v2', value: this.resolution },
			sizeAttenuation: { type: 'f', value: this.sizeAttenuation },
			near: { type: 'f', value: this.near },
			far: { type: 'f', value: this.far },
			dashArray: { type: 'v2', value: new THREE.Vector2( this.dashArray[ 0 ], this.dashArray[ 1 ] ) },
			useDash: { type: 'f', value: this.useDash }
		},
		vertexShader: vertexShaderSource.join( '\r\n' ),
		fragmentShader: fragmentShaderSource.join( '\r\n' )
	});

	delete parameters.lineWidth;
	delete parameters.map;
	delete parameters.useMap;
	delete parameters.color;
	delete parameters.opacity;
	delete parameters.resolution;
	delete parameters.sizeAttenuation;
	delete parameters.near;
	delete parameters.far;
	delete parameters.dashArray;

	material.type = 'MeshLineMaterial';

	material.setValues( parameters );

	return material;

};

THREE.MeshLineMaterial.prototype = Object.create( THREE.Material.prototype );
THREE.MeshLineMaterial.prototype.constructor = THREE.MeshLineMaterial;

THREE.MeshLineMaterial.prototype.copy = function ( source ) {

	THREE.Material.prototype.copy.call( this, source );

	this.lineWidth = source.lineWidth;
	this.map = source.map;
	this.useMap = source.useMap;
	this.color.copy( source.color );
	this.opacity = source.opacity;
	this.resolution.copy( source.resolution );
	this.sizeAttenuation = source.sizeAttenuation;
	this.near = source.near;
	this.far = source.far;

	return this;

};
<|endoftext|>


<commit_before>Sidebar.Script = function ( editor ) {

	var signals = editor.signals;

	var container = new UI.CollapsiblePanel();
	container.setCollapsed( true );

	container.addStatic( new UI.Text( 'Script' ).setTextTransform( 'uppercase' ) );
	container.add( new UI.Break() );

	var scriptsRow = new UI.Panel();
	container.add( scriptsRow );

	return container;

}
<commit_msg>Editor: Fixed Script panel behaviour.<commit_after>Sidebar.Script = function ( editor ) {

	var signals = editor.signals;

	var container = new UI.CollapsiblePanel();
	container.setCollapsed( true );
	container.setDisplay( 'none' );

	container.addStatic( new UI.Text( 'Script' ).setTextTransform( 'uppercase' ) );
	container.add( new UI.Break() );

	var scriptsRow = new UI.Panel();
	container.add( scriptsRow );

	signals.objectSelected.add( function ( object ) {

		if ( object !== null ) {

			container.setDisplay( 'block' );

		} else {

			container.setDisplay( 'none' );

		}

	} );

	return container;

}
<|endoftext|>


<commit_before>if("undefined"==typeof OGX)var OGX=function(){};OGX.prototype.MobileChatBox=function(e){"use strict";function o(){y.empty();for(var e=0;e<E.messages.length;e++)t(E.messages[e])}function t(e){var o=r(e),t=l(e,o);y.append(t),setTimeout(function(){y.children('.ogx_mobile_chat_box_message[data-user="'+e.user+'"]').addClass("ogx_mobile_chat_box_message_anim")},100)}function n(e){S[e]=!0;var o='
.

';y.append(o),i(!0)}function a(e){S[e]=!1,y.find('.ogx_mobile_chat_box_typing[data-user="'+e+'"]').remove(),0===y.find(".ogx_mobile_chat_box_typing").length&&i(!1)}function i(e){e?w||(w=setInterval(s,E.dot_speed)):(clearInterval(w),w=null)}function s(){X+=".",X.length>3?X=".":null,y.find(".ogx_mobile_chat_box_typing_body").html(X)}function r(e){return e.user.toString()===E.users.current?E.template_right:E.template_left}function l(e,o){var t=o;for(var n in e)reg=new RegExp("\\$"+n,"g"),t=t.replace(reg,e[n]);return reg=new RegExp("\\$letter","g"),t=t.replace(reg,E.users[e.user].name.substr(0,1).toUpperCase())}function _(){var e=M.find("textarea:first").val(),o=new Date;if(e.length>0){var n={from:"appraiser",msg:e,date:o.toISOString().split("T").shift()};t(n),M.find("textarea:first").val(""),C.el.trigger(OGX.MobileChatBox.SEND_MSG,n)}}function c(e){var o=-M.height()-e.keyboardHeight;M.css({transform:"translate3D(0px, "+o+"px, 0px)"})}function d(){M.css({transform:"translate3D(0px, "+-M.height()+"px, 0px)"}),_()}function g(e){e?(window.addEventListener("native.keyboardshow",c),window.addEventListener("native.keyboardhide",d)):(window.removeEventListener("native.keyboardshow",c),window.removeEventListener("native.keyboardhide",d))}function p(e){e?M.on("keyup","textarea",function(e){13===e.which&&(cordova.plugins.Keyboard.close(),_())}):M.off("keyup","textarea")}function h(e){e?M.on("click",".ogx_mobile_chat_box_composer_send",function(){d()}):M.off("click",".ogx_mobile_chat_box_composer_send")}function x(){var e=$(window).height(),o='
<textarea placeholder="'+E.placeholder+'">';o+='</textarea>
',v.prepend(o),M=v.find(".ogx_mobile_chat_box_composer:first"),e=M.height(),M.css("transform","translate3D(0px, "+-e+"px, 0px)"),C.el.height(C.el.height()-e)}function b(){O=new OGX.MobileScrollContainer({container:C.el[0],initDelay:100,autoScroll:!0}),C.el.on(OGX.MobileScrollContainer.READY,function(){C.el.off(OGX.MobileScrollContainer.READY),y=O.getInner(),y=$(y),y.addClass("ogx_mobile_chat_box"),o()})}function f(){for(var e in E.users)S[e]=!1}function u(){for(var e in G)E.hasOwnProperty(e)||(E[e]=G[e]);C.el=v=$(E.container)}function m(){return"undefined"==typeof OGX.MobileScrollContainer?void console.log("%c CRITICAL ERROR - OGX.MobileScrollContainer not found! ","background:#222; color: #FF0000"):(u(),x(),f(),b(),g(!0),void h(!0))}var v,y,O,M,w,C=this,E=e,G={placeholder:"Type a message",dot_speed:600,messages:[],mode:OGX.MobileChatBox.MODE_DESKTOP,template_left:'
$letter$msg
',template_right:'
$msg
'},S={},X=".";this.el=null,this.setUsers=function(e){E.users=e},this.addMessage=function(e){t(e)},this.userTyping=function(e,o){e&&!S[o]?n(o):!e&&S[o]&&a(o)},this.setMessage=function(e){M.find("textarea:first").val(e)},this.clear=function(){y.empty()},this.destroy=function(){g(!1),p(!1),h(!1)},m()},OGX.MobileChatBox=function(e){"use strict";return new OGX.prototype.MobileChatBox(e)},OGX.MobileChatBox.MODE_DESKTOP="desktop",OGX.MobileChatBox.MODE_MOBILE="mobile",OGX.MobileChatBox.SEND_MSG="MobileChatBoxSend";<commit_msg>Added auto send message on press enter<commit_after>if("undefined"==typeof OGX)var OGX=function(){};OGX.prototype.MobileChatBox=function(e){"use strict";function o(){y.empty();for(var e=0;e<E.messages.length;e++)t(E.messages[e])}function t(e){var o=r(e),t=l(e,o);y.append(t),setTimeout(function(){y.children('.ogx_mobile_chat_box_message[data-user="'+e.user+'"]').addClass("ogx_mobile_chat_box_message_anim")},100)}function n(e){S[e]=!0;var o='
.

';y.append(o),i(!0)}function a(e){S[e]=!1,y.find('.ogx_mobile_chat_box_typing[data-user="'+e+'"]').remove(),0===y.find(".ogx_mobile_chat_box_typing").length&&i(!1)}function i(e){e?w||(w=setInterval(s,E.dot_speed)):(clearInterval(w),w=null)}function s(){X+=".",X.length>3?X=".":null,y.find(".ogx_mobile_chat_box_typing_body").html(X)}function r(e){return e.user.toString()===E.users.current?E.template_right:E.template_left}function l(e,o){var t=o;for(var n in e)reg=new RegExp("\\$"+n,"g"),t=t.replace(reg,e[n]);return reg=new RegExp("\\$letter","g"),t=t.replace(reg,E.users[e.user].name.substr(0,1).toUpperCase())}function _(){var e=M.find("textarea:first").val(),o=new Date;if(e.length>0){var n={user:E.users.current,msg:e,date:o.toISOString().split("T").shift()};t(n),M.find("textarea:first").val(""),C.el.trigger(OGX.MobileChatBox.SEND_MSG,n)}}function c(e){var o=-M.height()-e.keyboardHeight;M.css({transform:"translate3D(0px, "+o+"px, 0px)"})}function d(){M.css({transform:"translate3D(0px, "+-M.height()+"px, 0px)"}),_()}function g(e){e?(window.addEventListener("native.keyboardshow",c),window.addEventListener("native.keyboardhide",d)):(window.removeEventListener("native.keyboardshow",c),window.removeEventListener("native.keyboardhide",d))}function p(e){e?M.on("keyup","textarea",function(e){13===e.which&&("undefined"!=typeof cordova&&cordova.plugins.Keyboard.close(),_())}):M.off("keyup","textarea")}function u(e){e?M.on("click",".ogx_mobile_chat_box_composer_send",function(){d()}):M.off("click",".ogx_mobile_chat_box_composer_send")}function h(){var e=$(window).height(),o='
<textarea placeholder="'+E.placeholder+'">';o+='</textarea>
',v.prepend(o),M=v.find(".ogx_mobile_chat_box_composer:first"),e=M.height(),M.css("transform","translate3D(0px, "+-e+"px, 0px)"),C.el.height(C.el.height()-e)}function x(){O=new OGX.MobileScrollContainer({container:C.el[0],initDelay:100,autoScroll:!0}),C.el.on(OGX.MobileScrollContainer.READY,function(){C.el.off(OGX.MobileScrollContainer.READY),y=O.getInner(),y=$(y),y.addClass("ogx_mobile_chat_box"),o()})}function b(){for(var e in E.users)S[e]=!1}function f(){for(var e in G)E.hasOwnProperty(e)||(E[e]=G[e]);C.el=v=$(E.container)}function m(){return"undefined"==typeof OGX.MobileScrollContainer?void console.log("%c CRITICAL ERROR - OGX.MobileScrollContainer not found! ","background:#222; color: #FF0000"):(f(),h(),b(),x(),g(!0),u(!0),void p(!0))}var v,y,O,M,w,C=this,E=e,G={placeholder:"Type a message",dot_speed:600,messages:[],mode:OGX.MobileChatBox.MODE_DESKTOP,template_left:'
$letter$msg
',template_right:'
$msg
'},S={},X=".";this.el=null,this.setUsers=function(e){E.users=e},this.addMessage=function(e){t(e)},this.userTyping=function(e,o){e&&!S[o]?n(o):!e&&S[o]&&a(o)},this.setMessage=function(e){M.find("textarea:first").val(e)},this.clear=function(){y.empty()},this.destroy=function(){g(!1),p(!1),u(!1)},m()},OGX.MobileChatBox=function(e){"use strict";return new OGX.prototype.MobileChatBox(e)},OGX.MobileChatBox.MODE_DESKTOP="desktop",OGX.MobileChatBox.MODE_MOBILE="mobile",OGX.MobileChatBox.SEND_MSG="MobileChatBoxSend";<|endoftext|>


<commit_before>/*
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import { useCallback, useEffect, useMemo, useState } from 'react';

/**
 * WordPress dependencies
 */
import { __, sprintf } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import useApi from '../../api/useApi';
import { Layout, Dialog, Button } from '../../../components';
import {
  BUTTON_TYPES,
  MIN_IMG_WIDTH,
  MIN_IMG_HEIGHT,
} from '../../../constants';
import { useConfig } from '../../config';
import { PageHeading } from '../shared';
import GoogleAnalyticsSettings from './googleAnalytics';
import { Main, Wrapper } from './components';
import PublisherLogoSettings from './publisherLogo';
import TelemetrySettings from './telemetry';

const ACTIVE_DIALOG_REMOVE_LOGO = 'REMOVE_LOGO';

function EditorSettings() {
  const {
    currentUser,
    fetchCurrentUser,
    fetchSettings,
    updateSettings,
    toggleWebStoriesTrackingOptIn,
    googleAnalyticsId,
    fetchMediaById,
    uploadMedia,
    activePublisherLogoId,
    isMediaLoading,
    mediaById,
    newlyCreatedMediaIds,
    publisherLogoIds,
  } = useApi(
    ({
      actions: {
        settingsApi: { fetchSettings, updateSettings },
        mediaApi: { fetchMediaById, uploadMedia },
        usersApi: { fetchCurrentUser, toggleWebStoriesTrackingOptIn },
      },
      state: {
        settings: {
          activePublisherLogoId,
          googleAnalyticsId,
          publisherLogoIds,
        },
        media: { isLoading: isMediaLoading, mediaById, newlyCreatedMediaIds },
        currentUser,
      },
    }) => ({
      fetchSettings,
      updateSettings,
      googleAnalyticsId,
      fetchMediaById,
      uploadMedia,
      activePublisherLogoId,
      isMediaLoading,
      mediaById,
      newlyCreatedMediaIds,
      publisherLogoIds,
      fetchCurrentUser,
      toggleWebStoriesTrackingOptIn,
      currentUser,
    })
  );

  const {
    capabilities: { canUploadFiles } = {},
    maxUpload,
    maxUploadFormatted,
  } = useConfig();

  const [activeDialog, setActiveDialog] = useState(null);
  const [activeLogo, setActiveLogo] = useState('');
  const [mediaError, setMediaError] = useState('');

  const mediaIds = useMemo(() => Object.keys(mediaById), [mediaById]);
  /**
   * WP settings references publisher logos by ID.
   * We must retrieve the media for those IDs from /media when present
   * Summarized below:
   * FETCH - fetch settings to know what IDs to load media for
   * then fetch media when publisherLogoIds are in state with useEffect
   * ADD - first upload new logo to media. use the new ID(s) to update settings.
   * REMOVE - send ID to remove to settings. Not deleting media, just removing from logos.
   */

  useEffect(() => {
    fetchSettings();
    fetchCurrentUser();
  }, [fetchCurrentUser, fetchSettings]);

  useEffect(() => {
    if (newlyCreatedMediaIds.length > 0) {
      // TODO check to see if there are no logos already, if there isn't make one of the newly createdMediaIds the default logo
      updateSettings({ publisherLogoIds: newlyCreatedMediaIds });
    }
  }, [updateSettings, newlyCreatedMediaIds]);

  useEffect(() => {
    if (publisherLogoIds.length > 0) {
      fetchMediaById(publisherLogoIds);
    }
  }, [fetchMediaById, publisherLogoIds]);

  const handleUpdateGoogleAnalyticsId = useCallback(
    (newGoogleAnalyticsId) =>
      updateSettings({ googleAnalyticsId: newGoogleAnalyticsId }),
    [updateSettings]
  );

  const handleAddLogos = useCallback(
    async (files) => {
      let allFileSizesWithinMaxUpload = true;
      let errorProcessingImages = false;
      let imagePromises = [];

      files.forEach((file) => {
        allFileSizesWithinMaxUpload =
          allFileSizesWithinMaxUpload && file.size <= maxUpload;

        imagePromises.push(
          new Promise((resolve, reject) => {
            const img = new Image();

            img.onload = () => resolve(img);
            img.onerror = () => reject(new Error(file.name));

            img.src = URL.createObjectURL(file);
          })
        );
      });

      if (!allFileSizesWithinMaxUpload) {
        const errorText =
          files.length === 1
            ? sprintf(
                /* translators: %s: max upload size for media */
                __(
                  'Sorry, this file is too big. Make sure your logo is under %s.',
                  'web-stories'
                ),
                maxUploadFormatted
              )
            : sprintf(
                /* translators: %s: max upload size for media */
                __(
                  'Sorry, one or more of these files are too big. Make sure your logos are all under %s.',
                  'web-stories'
                ),
                maxUploadFormatted
              );
        return setMediaError(errorText);
      }

      const images = await Promise.all(imagePromises).catch(() => {
        errorProcessingImages = true;
      });

      if (errorProcessingImages) {
        const errorText =
          files.length === 1
            ? __(
                'Sorry, there was an error processing your upload. Please try again.',
                'web-stories'
              )
            : __(
                'Sorry, there was an error processing one or more of your uploads. Please try again.',
                'web-stories'
              );
        return setMediaError(errorText);
      }

      const allFileDimensionsValid = images.every(
        ({ height, width }) =>
          height >= MIN_IMG_HEIGHT && width >= MIN_IMG_WIDTH
      );

      if (!allFileDimensionsValid) {
        const errorText =
          files.length === 1
            ? sprintf(
                /* translators: 1 = minimum width, 2 = minimum height */
                __(
                  'Sorry, this file is too small. Make sure your logo is larger than %s.',
                  'web-stories'
                ),
                sprintf('%1$dx%2$dpx', MIN_IMG_WIDTH, MIN_IMG_HEIGHT)
              )
            : sprintf(
                /* translators: %s: image dimensions in pixels. */
                __(
                  'Sorry, one or more files are too small. Make sure your logos are all larger than %s.',
                  'web-stories'
                ),
                sprintf('%1$dx%2$dpx', MIN_IMG_WIDTH, MIN_IMG_HEIGHT)
              );
        return setMediaError(errorText);
      }

      setMediaError('');
      return uploadMedia(files);
    },
    [maxUpload, maxUploadFormatted, uploadMedia]
  );

  const handleRemoveLogo = useCallback((media) => {
    setActiveDialog(ACTIVE_DIALOG_REMOVE_LOGO);
    setActiveLogo(media.id);
  }, []);

  const handleDialogConfirmRemoveLogo = useCallback(() => {
    if (activeLogo === activePublisherLogoId) {
      // find the next publisher logo to make default, there's cases where publisher logo ids have their media removed in the editor but the instance of them as a publisher logo is still present
      // so we need to find the next available logo by making sure media exists for it as well.
      const newDefaultLogoId = publisherLogoIds.reduce((acc, logoId) => {
        if (logoId === activeLogo) {
          return undefined;
        }
        const availableMedia = mediaIds.find(
          (mediaId) => mediaId.toString() === logoId.toString()
        );

        if (availableMedia) {
          return availableMedia;
        }
        return acc;
      }, false);

      updateSettings({
        publisherLogoIdToRemove: activeLogo,
        publisherLogoToMakeDefault: newDefaultLogoId,
      });
    } else {
      updateSettings({ publisherLogoIdToRemove: activeLogo });
    }
    setActiveDialog(null);
  }, [
    activeLogo,
    activePublisherLogoId,
    mediaIds,
    publisherLogoIds,
    updateSettings,
  ]);

  const handleUpdateDefaultLogo = useCallback(
    (media) => {
      updateSettings({ publisherLogoToMakeDefault: media.id });
    },
    [updateSettings]
  );

  const isActiveRemoveLogoDialog = Boolean(
    activeDialog === ACTIVE_DIALOG_REMOVE_LOGO && activeLogo
  );

  const orderedPublisherLogos = useMemo(() => {
    if (Object.keys(mediaById).length <= 0) {
      return [];
    }

    return publisherLogoIds
      .map((publisherLogoId) => {
        if (mediaById[publisherLogoId]) {
          return publisherLogoId === activePublisherLogoId
            ? { ...mediaById[publisherLogoId], isDefault: true }
            : mediaById[publisherLogoId];
        }
        return {}; // this is a safeguard against edge cases where a user has > 100 publisher logos, which is more than we're loading
      })
      .filter((logo) => logo?.id);
  }, [activePublisherLogoId, publisherLogoIds, mediaById]);

  return (
    <Layout.Provider>
      <Wrapper data-testid="editor-settings">
        <Layout.Squishable>
          <PageHeading
            defaultTitle={__('Settings', 'web-stories')}
            showTypeahead={false}
          />
        </Layout.Squishable>
        <Layout.Scrollable>
          <Main>
            <GoogleAnalyticsSettings
              handleUpdate={handleUpdateGoogleAnalyticsId}
              googleAnalyticsId={googleAnalyticsId}
            />
            <PublisherLogoSettings
              handleAddLogos={handleAddLogos}
              handleRemoveLogo={handleRemoveLogo}
              handleUpdateDefaultLogo={handleUpdateDefaultLogo}
              publisherLogos={orderedPublisherLogos}
              canUploadFiles={canUploadFiles}
              isLoading={isMediaLoading}
              uploadError={mediaError}
            />
            <TelemetrySettings
              disabled={currentUser.isUpdating}
              onCheckboxSelected={toggleWebStoriesTrackingOptIn}
              selected={Boolean(
                currentUser.data.meta?.web_stories_tracking_optin
              )}
            />
          </Main>
        </Layout.Scrollable>
      </Wrapper>

      <Dialog
        isOpen={isActiveRemoveLogoDialog}
        contentLabel={__(
          'Dialog to confirm removing a publisher logo',
          'web-stories'
        )}
        title={__('Are you sure you want to remove this logo?', 'web-stories')}
        onClose={() => setActiveDialog(null)}
        actions={
          <>
            <Button
              type={BUTTON_TYPES.DEFAULT}
              onClick={() => setActiveDialog(null)}
            >
              {__('Cancel', 'web-stories')}
            </Button>
            <Button
              type={BUTTON_TYPES.DEFAULT}
              onClick={handleDialogConfirmRemoveLogo}
            >
              {__('Delete Logo', 'web-stories')}
            </Button>
          </>
        }
      >
        {__(
          'The logo will be removed from any stories that currently use it as their publisher logo.',
          'web-stories'
        )}
      </Dialog>
    </Layout.Provider>
  );
}

export default EditorSettings;
<commit_msg>Make the uploaded default if it’s the only logo uploaded.<commit_after>/*
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import { useCallback, useEffect, useMemo, useState } from 'react';

/**
 * WordPress dependencies
 */
import { __, sprintf } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import useApi from '../../api/useApi';
import { Layout, Dialog, Button } from '../../../components';
import {
  BUTTON_TYPES,
  MIN_IMG_WIDTH,
  MIN_IMG_HEIGHT,
} from '../../../constants';
import { useConfig } from '../../config';
import { PageHeading } from '../shared';
import GoogleAnalyticsSettings from './googleAnalytics';
import { Main, Wrapper } from './components';
import PublisherLogoSettings from './publisherLogo';
import TelemetrySettings from './telemetry';

const ACTIVE_DIALOG_REMOVE_LOGO = 'REMOVE_LOGO';

function EditorSettings() {
  const {
    currentUser,
    fetchCurrentUser,
    fetchSettings,
    updateSettings,
    toggleWebStoriesTrackingOptIn,
    googleAnalyticsId,
    fetchMediaById,
    uploadMedia,
    activePublisherLogoId,
    isMediaLoading,
    mediaById,
    newlyCreatedMediaIds,
    publisherLogoIds,
  } = useApi(
    ({
      actions: {
        settingsApi: { fetchSettings, updateSettings },
        mediaApi: { fetchMediaById, uploadMedia },
        usersApi: { fetchCurrentUser, toggleWebStoriesTrackingOptIn },
      },
      state: {
        settings: {
          activePublisherLogoId,
          googleAnalyticsId,
          publisherLogoIds,
        },
        media: { isLoading: isMediaLoading, mediaById, newlyCreatedMediaIds },
        currentUser,
      },
    }) => ({
      fetchSettings,
      updateSettings,
      googleAnalyticsId,
      fetchMediaById,
      uploadMedia,
      activePublisherLogoId,
      isMediaLoading,
      mediaById,
      newlyCreatedMediaIds,
      publisherLogoIds,
      fetchCurrentUser,
      toggleWebStoriesTrackingOptIn,
      currentUser,
    })
  );

  const {
    capabilities: { canUploadFiles } = {},
    maxUpload,
    maxUploadFormatted,
  } = useConfig();

  const [activeDialog, setActiveDialog] = useState(null);
  const [activeLogo, setActiveLogo] = useState('');
  const [mediaError, setMediaError] = useState('');

  const mediaIds = useMemo(() => Object.keys(mediaById), [mediaById]);
  /**
   * WP settings references publisher logos by ID.
   * We must retrieve the media for those IDs from /media when present
   * Summarized below:
   * FETCH - fetch settings to know what IDs to load media for
   * then fetch media when publisherLogoIds are in state with useEffect
   * ADD - first upload new logo to media. use the new ID(s) to update settings.
   * REMOVE - send ID to remove to settings. Not deleting media, just removing from logos.
   */

  useEffect(() => {
    fetchSettings();
    fetchCurrentUser();
  }, [fetchCurrentUser, fetchSettings]);

  useEffect(() => {
    if (newlyCreatedMediaIds.length > 0) {
      const updateObject = { publisherLogoIds: newlyCreatedMediaIds };

      if (publisherLogoIds.filter((id) => id !== 0).length === 0) {
        updateObject.publisherLogoToMakeDefault = newlyCreatedMediaIds[0];
      }

      updateSettings(updateObject);
    }
  }, [updateSettings, newlyCreatedMediaIds, publisherLogoIds]);

  useEffect(() => {
    if (publisherLogoIds.length > 0) {
      fetchMediaById(publisherLogoIds);
    }
  }, [fetchMediaById, publisherLogoIds]);

  const handleUpdateGoogleAnalyticsId = useCallback(
    (newGoogleAnalyticsId) =>
      updateSettings({ googleAnalyticsId: newGoogleAnalyticsId }),
    [updateSettings]
  );

  const handleAddLogos = useCallback(
    async (files) => {
      let allFileSizesWithinMaxUpload = true;
      let errorProcessingImages = false;
      let imagePromises = [];

      files.forEach((file) => {
        allFileSizesWithinMaxUpload =
          allFileSizesWithinMaxUpload && file.size <= maxUpload;

        imagePromises.push(
          new Promise((resolve, reject) => {
            const img = new Image();

            img.onload = () => resolve(img);
            img.onerror = () => reject(new Error(file.name));

            img.src = URL.createObjectURL(file);
          })
        );
      });

      if (!allFileSizesWithinMaxUpload) {
        const errorText =
          files.length === 1
            ? sprintf(
                /* translators: %s: max upload size for media */
                __(
                  'Sorry, this file is too big. Make sure your logo is under %s.',
                  'web-stories'
                ),
                maxUploadFormatted
              )
            : sprintf(
                /* translators: %s: max upload size for media */
                __(
                  'Sorry, one or more of these files are too big. Make sure your logos are all under %s.',
                  'web-stories'
                ),
                maxUploadFormatted
              );
        return setMediaError(errorText);
      }

      const images = await Promise.all(imagePromises).catch(() => {
        errorProcessingImages = true;
      });

      if (errorProcessingImages) {
        const errorText =
          files.length === 1
            ? __(
                'Sorry, there was an error processing your upload. Please try again.',
                'web-stories'
              )
            : __(
                'Sorry, there was an error processing one or more of your uploads. Please try again.',
                'web-stories'
              );
        return setMediaError(errorText);
      }

      const allFileDimensionsValid = images.every(
        ({ height, width }) =>
          height >= MIN_IMG_HEIGHT && width >= MIN_IMG_WIDTH
      );

      if (!allFileDimensionsValid) {
        const errorText =
          files.length === 1
            ? sprintf(
                /* translators: 1 = minimum width, 2 = minimum height */
                __(
                  'Sorry, this file is too small. Make sure your logo is larger than %s.',
                  'web-stories'
                ),
                sprintf('%1$dx%2$dpx', MIN_IMG_WIDTH, MIN_IMG_HEIGHT)
              )
            : sprintf(
                /* translators: %s: image dimensions in pixels. */
                __(
                  'Sorry, one or more files are too small. Make sure your logos are all larger than %s.',
                  'web-stories'
                ),
                sprintf('%1$dx%2$dpx', MIN_IMG_WIDTH, MIN_IMG_HEIGHT)
              );
        return setMediaError(errorText);
      }

      setMediaError('');
      return uploadMedia(files);
    },
    [maxUpload, maxUploadFormatted, uploadMedia]
  );

  const handleRemoveLogo = useCallback((media) => {
    setActiveDialog(ACTIVE_DIALOG_REMOVE_LOGO);
    setActiveLogo(media.id);
  }, []);

  const handleDialogConfirmRemoveLogo = useCallback(() => {
    if (activeLogo === activePublisherLogoId) {
      // find the next publisher logo to make default, there's cases where publisher logo ids have their media removed in the editor but the instance of them as a publisher logo is still present
      // so we need to find the next available logo by making sure media exists for it as well.
      const newDefaultLogoId = publisherLogoIds.reduce((acc, logoId) => {
        if (logoId === activeLogo) {
          return undefined;
        }
        const availableMedia = mediaIds.find(
          (mediaId) => mediaId.toString() === logoId.toString()
        );

        if (availableMedia) {
          return availableMedia;
        }
        return acc;
      }, false);

      updateSettings({
        publisherLogoIdToRemove: activeLogo,
        publisherLogoToMakeDefault: newDefaultLogoId,
      });
    } else {
      updateSettings({ publisherLogoIdToRemove: activeLogo });
    }
    setActiveDialog(null);
  }, [
    activeLogo,
    activePublisherLogoId,
    mediaIds,
    publisherLogoIds,
    updateSettings,
  ]);

  const handleUpdateDefaultLogo = useCallback(
    (media) => {
      updateSettings({ publisherLogoToMakeDefault: media.id });
    },
    [updateSettings]
  );

  const isActiveRemoveLogoDialog = Boolean(
    activeDialog === ACTIVE_DIALOG_REMOVE_LOGO && activeLogo
  );

  const orderedPublisherLogos = useMemo(() => {
    if (Object.keys(mediaById).length <= 0) {
      return [];
    }

    return publisherLogoIds
      .map((publisherLogoId) => {
        if (mediaById[publisherLogoId]) {
          return publisherLogoId === activePublisherLogoId
            ? { ...mediaById[publisherLogoId], isDefault: true }
            : mediaById[publisherLogoId];
        }
        return {}; // this is a safeguard against edge cases where a user has > 100 publisher logos, which is more than we're loading
      })
      .filter((logo) => logo?.id);
  }, [activePublisherLogoId, publisherLogoIds, mediaById]);

  return (
    <Layout.Provider>
      <Wrapper data-testid="editor-settings">
        <Layout.Squishable>
          <PageHeading
            defaultTitle={__('Settings', 'web-stories')}
            showTypeahead={false}
          />
        </Layout.Squishable>
        <Layout.Scrollable>
          <Main>
            <GoogleAnalyticsSettings
              handleUpdate={handleUpdateGoogleAnalyticsId}
              googleAnalyticsId={googleAnalyticsId}
            />
            <PublisherLogoSettings
              handleAddLogos={handleAddLogos}
              handleRemoveLogo={handleRemoveLogo}
              handleUpdateDefaultLogo={handleUpdateDefaultLogo}
              publisherLogos={orderedPublisherLogos}
              canUploadFiles={canUploadFiles}
              isLoading={isMediaLoading}
              uploadError={mediaError}
            />
            <TelemetrySettings
              disabled={currentUser.isUpdating}
              onCheckboxSelected={toggleWebStoriesTrackingOptIn}
              selected={Boolean(
                currentUser.data.meta?.web_stories_tracking_optin
              )}
            />
          </Main>
        </Layout.Scrollable>
      </Wrapper>

      <Dialog
        isOpen={isActiveRemoveLogoDialog}
        contentLabel={__(
          'Dialog to confirm removing a publisher logo',
          'web-stories'
        )}
        title={__('Are you sure you want to remove this logo?', 'web-stories')}
        onClose={() => setActiveDialog(null)}
        actions={
          <>
            <Button
              type={BUTTON_TYPES.DEFAULT}
              onClick={() => setActiveDialog(null)}
            >
              {__('Cancel', 'web-stories')}
            </Button>
            <Button
              type={BUTTON_TYPES.DEFAULT}
              onClick={handleDialogConfirmRemoveLogo}
            >
              {__('Delete Logo', 'web-stories')}
            </Button>
          </>
        }
      >
        {__(
          'The logo will be removed from any stories that currently use it as their publisher logo.',
          'web-stories'
        )}
      </Dialog>
    </Layout.Provider>
  );
}

export default EditorSettings;
<|endoftext|>


<commit_before>(function($) {
/*
Muli State Button jQuery Plugin
*/

var methods = {
		init : function(options) {
			var states = $.extend( /* {}, */ $.fn.msb.defaults, options );
			return this.each( function(){
				$(this).addClass('msb');
				// get state
				var state = $(this).data('state');
				// change icon name, and keep it for rebuid
				var icon = $(this)
										.find('i.material-icons')
										.html(states[state].icon.name);
				// remove any icon anim css class (msb-anim-*)
				$(this)
					.find("i.material-icons")
					.removeClass( function(index, className) {
						return (className.match(/(^|\s)msb-anim-\S+/g) || []).join(" ");
					});
				// now, if state icon anim, adding it
				if(states[state].icon.animClass != false){
					$(this)
						.find('i.material-icons')
						.addClass('msb-anim-' + states[state].icon.animClass);
				}
				// rebuild button
				$(this)
					.addClass(states[state].cssClass)
					.html(icon)
					.append(states[state].label)
					.prop("disabled", states[state].disabled);
			});
		},
		update : function( state ) {
			//var states = $.extend( {}, $.fn.msb.defaults, options );
			return this.each( function(){
				if($.fn.msb.defaults[state] != undefined){
					var prevState = $.fn.msb.defaults[$(this).data('state')];
					$(this)
						.removeClass(prevState.cssClass)
						.data("state", state);
					methods.init.apply( $(this) );
				}else{
					console.log("State: '" + state + "' hasn't been defined.");
				}
			});
		}
};

$.fn.msb = function(methodOrOptions) {
		if ( methods[methodOrOptions] ) {
				return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 ));
		} else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) {
				// Default to "init"
				return methods.init.apply( this, arguments );
		} else {
				$.error( 'Method ' +  methodOrOptions + ' does not exist on jQuery.msb' );
		}
};
$.fn.msb.defaults = {
	"default": {
		"cssClass": "blue",
		"label": "submit",
		"icon": {
			"name": "send",
			"animClass": false
		},
		"disabled": false,
		"stateBar": ""
	},
	"success": {
		"cssClass": "green",
		"label": "sent",
		"icon": {
			"name": "check",
			"animClass": false
		},
		"disabled": true,
		"stateBar": ""
	},
	"warning": {
		"cssClass": "orange",
		"label": "try again",
		"icon": {
			"name": "warning",
			"animClass": false
		},
		"disabled": false,
		"stateBar": ""
	},
	"error": {
		"cssClass": "red",
		"label": "try again",
		"icon": {
			"name": "cancel",
			"animClass": false
		},
		"disabled": false,
		"stateBar": ""
	},
	"process": {
		"cssClass": "yellow black-text",
		"label": "procesing",
		"icon": {
			"name": "refresh",
			"animClass": "rotate"
		},
		"disabled": true,
		"stateBar": ""
	}
};

})(jQuery);

<commit_msg>spelling mistake<commit_after>(function($) {
/*
Muli State Button jQuery Plugin
*/

var methods = {
		init : function(options) {
			var states = $.extend( /* {}, */ $.fn.msb.defaults, options );
			return this.each( function(){
				$(this).addClass('msb');
				// get state
				var state = $(this).data('state');
				// change icon name, and keep it for rebuid
				var icon = $(this)
										.find('i.material-icons')
										.html(states[state].icon.name);
				// remove any icon anim css class (msb-anim-*)
				$(this)
					.find("i.material-icons")
					.removeClass( function(index, className) {
						return (className.match(/(^|\s)msb-anim-\S+/g) || []).join(" ");
					});
				// now, if state icon anim, adding it
				if(states[state].icon.animClass != false){
					$(this)
						.find('i.material-icons')
						.addClass('msb-anim-' + states[state].icon.animClass);
				}
				// rebuild button
				$(this)
					.addClass(states[state].cssClass)
					.html(icon)
					.append(states[state].label)
					.prop("disabled", states[state].disabled);
			});
		},
		update : function( state ) {
			//var states = $.extend( {}, $.fn.msb.defaults, options );
			return this.each( function(){
				if($.fn.msb.defaults[state] != undefined){
					var prevState = $.fn.msb.defaults[$(this).data('state')];
					$(this)
						.removeClass(prevState.cssClass)
						.data("state", state);
					methods.init.apply( $(this) );
				}else{
					console.log("State: '" + state + "' hasn't been defined.");
				}
			});
		}
};

$.fn.msb = function(methodOrOptions) {
		if ( methods[methodOrOptions] ) {
				return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 ));
		} else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) {
				// Default to "init"
				return methods.init.apply( this, arguments );
		} else {
				$.error( 'Method ' +  methodOrOptions + ' does not exist on jQuery.msb' );
		}
};
$.fn.msb.defaults = {
	"default": {
		"cssClass": "blue",
		"label": "submit",
		"icon": {
			"name": "send",
			"animClass": false
		},
		"disabled": false,
		"stateBar": ""
	},
	"success": {
		"cssClass": "green",
		"label": "sent",
		"icon": {
			"name": "check",
			"animClass": false
		},
		"disabled": true,
		"stateBar": ""
	},
	"warning": {
		"cssClass": "orange",
		"label": "try again",
		"icon": {
			"name": "warning",
			"animClass": false
		},
		"disabled": false,
		"stateBar": ""
	},
	"error": {
		"cssClass": "red",
		"label": "try again",
		"icon": {
			"name": "cancel",
			"animClass": false
		},
		"disabled": false,
		"stateBar": ""
	},
	"process": {
		"cssClass": "yellow black-text",
		"label": "processing",
		"icon": {
			"name": "refresh",
			"animClass": "rotate"
		},
		"disabled": true,
		"stateBar": ""
	}
};

})(jQuery);

<|endoftext|>