<commit_before>/*
 * Copyright (c) 2015 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

define(function (require, exports) {
    "use strict";

    var Promise = require("bluebird"),
        Immutable = require("immutable");

    var descriptor = require("adapter").ps.descriptor,
        boundsLib = require("adapter").lib.bounds,
        vectorMaskLib = require("adapter").lib.vectorMask,
        documentLib = require("adapter").lib.document;

    var locks = require("../locks"),
        events = require("../events"),
        nls = require("js/util/nls");

    var _CLEAR_PATH = 106;

    /**
     * Select the vector mask for the currently selected layer.
     *
     * @return {Promise}
     */
    var selectVectorMask = function () {
        return descriptor.playObject(vectorMaskLib.selectVectorMask());
    };

    selectVectorMask.action = {
        reads: [],
        writes: [locks.PS_DOC],
        modal: true
    };

    /**
     * Reveal and select the vector mask of the selected layer.
     * Also switch to the vector based superselect tool.
     *
     * @return {Promise}
     */
    var editVectorMask = function () {
        var toolStore = this.flux.store("tool"),
            superselectVector = toolStore.getToolByID("superselectVector");

        return this.transfer("tools.select", superselectVector)
            .then(function () {
                // select and activate knots on Current Vector Mask
                return descriptor.playObject(vectorMaskLib.activateVectorMaskEditing());
            });
    };
    editVectorMask.action = {
        reads: [locks.JS_TOOL],
        writes: [locks.PS_DOC],
        transfers: ["tools.select"],
        modal: true
    };

    /**
     * Removes a vector mask on the selected layer.
     *
     * @return {Promise}
     */
    var deleteVectorMask = function () {
        var applicationStore = this.flux.store("application"),
            currentDocument = applicationStore.getCurrentDocument();

        if (currentDocument === null) {
            return Promise.resolve();
        }

        var layers = currentDocument.layers.selected;

        if (layers === null || layers.isEmpty()) {
            return Promise.resolve();
        }

        var currentLayer = layers.first();

        if (currentLayer.vectorMaskEnabled) {
            var deleteMaskOptions = {
                historyStateInfo: {
                    name: nls.localize("strings.ACTIONS.DELETE_VECTOR_MASK"),
                    target: documentLib.referenceBy.id(currentDocument.id)
                }
            };
            return descriptor.playObject(vectorMaskLib.deleteVectorMask(), deleteMaskOptions)
                .bind(this)
                .then(function () {
                    var payload = {
                            documentID: currentDocument.id,
                            layerIDs: Immutable.List.of(currentLayer.id),
                            vectorMaskEnabled: false,
                            history: {
                                newState: true,
                                name: nls.localize("strings.ACTIONS.DELETE_VECTOR_MASK")
                            }
                        },
                        event = events.document.history.REMOVE_VECTOR_MASK_FROM_LAYER;

                    return this.dispatchAsync(event, payload);
                });
        } else {
            return Promise.resolve();
        }
    };
    deleteVectorMask.action = {
        reads: [locks.JS_TOOL],
        writes: [locks.PS_DOC, locks.JS_DOC]
    };

    /**
     * Handle escaping from vector mask for the selection-based vector mask tools.
     * Most tools can just call tools.changeVectorMaskMode directly.
     *
     * @return {Promise}
     */
    var handleEscapeVectorMask = function () {
        var appStore = this.flux.store("application"),
            toolStore = this.flux.store("tool"),
            currentDocument = appStore.getCurrentDocument();

        if (!currentDocument) {
            return Promise.resolve();
        }

        if (toolStore.getVectorMode() && toolStore.getModalToolState()) {
            return this.transfer("tools.changeVectorMaskMode", false);
        }

        var currentLayers = currentDocument.layers.selected;

        if (currentLayers.isEmpty()) {
            return Promise.resolve();
        }

        var currentLayer = currentLayers.first();

        return this.transfer("layers.resetLayers", currentDocument, currentLayer)
            .bind(this)
            .then(function () {
                currentDocument = appStore.getCurrentDocument();
                currentLayer = currentDocument.layers.selected.first();
                if (currentLayer && currentLayer.vectorMaskEmpty) {
                    return this.transfer("tools.changeVectorMaskMode", false);
                } else {
                    return this.transfer("tools.select", toolStore.getToolByID("newSelect"));
                }
            });
    };
    handleEscapeVectorMask.action = {
        reads: [locks.JS_APP, locks.JS_DOC],
        writes: [],
        transfers: ["layers.resetLayers", "tools.changeVectorMaskMode", "tools.select"],
        modal: true
    };

    /**
     * Handle deleting the vector mask for all of the vector mask mode tools.
     *
     * @return {Promise}
     */
    var handleDeleteVectorMask = function () {
        var appStore = this.flux.store("application"),
            toolStore = this.flux.store("tool"),
            currentDocument = appStore.getCurrentDocument();

        if (!currentDocument) {
            return Promise.resolve();
        }

        if (toolStore.getModalToolState()) {
            return this.transfer("mask.deleteVectorMask")
                .bind(this)
                .then(function () {
                    return this.transfer("tools.changeVectorMaskMode", false);
                });
        }

        var currentLayer = currentDocument.layers.selected.first();

        return this.transfer("layers.resetLayers", currentDocument, currentLayer)
            .bind(this)
            .then(function () {
                currentDocument = appStore.getCurrentDocument();
                currentLayer = currentDocument.layers.selected.first();

                if (currentLayer && !currentLayer.vectorMaskEmpty) {
                    var payload = { commandID: _CLEAR_PATH, waitForCompletion: true };
                    return this.transfer("menu.native", payload)
                        .bind(this)
                        .then(function () {
                            return this.transfer("layers.resetLayers", currentDocument, currentLayer);
                        })
                        .then(function () {
                            currentDocument = appStore.getCurrentDocument();
                            currentLayer = currentDocument.layers.selected.first();
                            if (currentLayer && !currentLayer.vectorMaskEnabled) {
                                return this.transfer("mask.deleteVectorMask")
                                    .bind(this)
                                    .then(function () {
                                        return this.transfer("tools.changeVectorMaskMode", false);
                                    });
                            }
                        });
                } else {
                    return this.transfer("mask.deleteVectorMask")
                        .bind(this)
                        .then(function () {
                            this.transfer("tools.changeVectorMaskMode", false);
                        });
                }
            });
    };
    handleDeleteVectorMask.action = {
        reads: [locks.JS_APP, locks.JS_DOC],
        writes: [],
        transfers: ["layers.resetLayers", "mask.deleteVectorMask", "tools.changeVectorMaskMode",
            "menu.native"]
    };

    /**
     * Create a mask that matches the bounds of the currently selected layer
     *
     * @return {Promise}
     */
    var applyRectangle = function () {
        var appStore = this.flux.store("application"),
            toolStore = this.flux.store("tool"),
            currentDocument = appStore.getCurrentDocument();

        if (!currentDocument) {
            return Promise.resolve();
        }

        var currentLayers = currentDocument.layers.selected;

        if (currentLayers.isEmpty()) {
            return Promise.resolve();
        }

        var currentLayer = currentLayers.first(),
            bounds = boundsLib.bounds(currentDocument.layers.childBounds(currentLayer)),
            options = {
                historyStateInfo: {
                    name: nls.localize("strings.ACTIONS.ADD_VECTOR_MASK"),
                    target: documentLib.referenceBy.id(currentDocument.id),
                    coalesce: true,
                    suppressHistoryStateNotification: true
                }
            };

        return descriptor.batchPlayObjects([vectorMaskLib.makeBoundsWorkPath(bounds),
                vectorMaskLib.makeVectorMaskFromWorkPath(),
                vectorMaskLib.deleteWorkPath()], options)
            .bind(this)
            .then(function () {
                return this.transfer("tools.select", toolStore.getToolByID("newSelect"));
            });
    };
    applyRectangle.action = {
        reads: [locks.JS_APP, locks.JS_DOC],
        writes: [locks.PS_DOC],
        transfers: ["tools.select"]
    };

    /**
     * Create a circular mask the size of the currently selected layer
     *
     * @return {Promise}
     */
    var applyEllipse = function () {
        var appStore = this.flux.store("application"),
            toolStore = this.flux.store("tool"),
            currentDocument = appStore.getCurrentDocument();

        if (!currentDocument) {
            return Promise.resolve();
        }

        var currentLayers = currentDocument.layers.selected;

        if (currentLayers.isEmpty()) {
            return Promise.resolve();
        }

        var currentLayer = currentLayers.first(),
            bounds = currentLayer.bounds,
            options = {
                historyStateInfo: {
                    name: nls.localize("strings.ACTIONS.ADD_VECTOR_MASK"),
                    target: documentLib.referenceBy.id(currentDocument.id),
                    coalesce: true,
                    suppressHistoryStateNotification: true
                }
            };

        return descriptor.batchPlayObjects([vectorMaskLib.makeCircularBoundsWorkPath(bounds),
                vectorMaskLib.makeVectorMaskFromWorkPath(),
                vectorMaskLib.deleteWorkPath()], options)
            .bind(this)
            .then(function () {
                return this.transfer("tools.select", toolStore.getToolByID("newSelect"));
            });
    };
    applyEllipse.action = {
        reads: [locks.JS_APP, locks.JS_DOC],
        writes: [locks.PS_DOC],
        transfers: ["tools.select"]
    };

    exports.editVectorMask = editVectorMask;
    exports.selectVectorMask = selectVectorMask;
    exports.deleteVectorMask = deleteVectorMask;
    exports.handleDeleteVectorMask = handleDeleteVectorMask;
    exports.handleEscapeVectorMask = handleEscapeVectorMask;
    exports.applyEllipse = applyEllipse;
    exports.applyRectangle = applyRectangle;
});
<commit_msg>switch vector mask HUD actions to use Layer Actions Util to avoid issues when multiple layers are selected<commit_after>/*
 * Copyright (c) 2015 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

define(function (require, exports) {
    "use strict";

    var Promise = require("bluebird"),
        Immutable = require("immutable");

    var descriptor = require("adapter").ps.descriptor,
        boundsLib = require("adapter").lib.bounds,
        vectorMaskLib = require("adapter").lib.vectorMask,
        documentLib = require("adapter").lib.document;

    var locks = require("../locks"),
        events = require("../events"),
        nls = require("js/util/nls"),
        layerActionsUtil = require("js/util/layeractions");

    var _CLEAR_PATH = 106;

    /**
     * Select the vector mask for the currently selected layer.
     *
     * @return {Promise}
     */
    var selectVectorMask = function () {
        return descriptor.playObject(vectorMaskLib.selectVectorMask());
    };

    selectVectorMask.action = {
        reads: [],
        writes: [locks.PS_DOC],
        modal: true
    };

    /**
     * Reveal and select the vector mask of the selected layer.
     * Also switch to the vector based superselect tool.
     *
     * @return {Promise}
     */
    var editVectorMask = function () {
        var toolStore = this.flux.store("tool"),
            superselectVector = toolStore.getToolByID("superselectVector");

        return this.transfer("tools.select", superselectVector)
            .then(function () {
                // select and activate knots on Current Vector Mask
                return descriptor.playObject(vectorMaskLib.activateVectorMaskEditing());
            });
    };
    editVectorMask.action = {
        reads: [locks.JS_TOOL],
        writes: [locks.PS_DOC],
        transfers: ["tools.select"],
        modal: true
    };

    /**
     * Removes a vector mask on the selected layer.
     *
     * @return {Promise}
     */
    var deleteVectorMask = function () {
        var applicationStore = this.flux.store("application"),
            currentDocument = applicationStore.getCurrentDocument();

        if (currentDocument === null) {
            return Promise.resolve();
        }

        var layers = currentDocument.layers.selected;

        if (layers === null || layers.isEmpty()) {
            return Promise.resolve();
        }

        var currentLayer = layers.first();

        if (currentLayer.vectorMaskEnabled) {
            var deleteMaskOptions = {
                historyStateInfo: {
                    name: nls.localize("strings.ACTIONS.DELETE_VECTOR_MASK"),
                    target: documentLib.referenceBy.id(currentDocument.id)
                }
            };
            return descriptor.playObject(vectorMaskLib.deleteVectorMask(), deleteMaskOptions)
                .bind(this)
                .then(function () {
                    var payload = {
                            documentID: currentDocument.id,
                            layerIDs: Immutable.List.of(currentLayer.id),
                            vectorMaskEnabled: false,
                            history: {
                                newState: true,
                                name: nls.localize("strings.ACTIONS.DELETE_VECTOR_MASK")
                            }
                        },
                        event = events.document.history.REMOVE_VECTOR_MASK_FROM_LAYER;

                    return this.dispatchAsync(event, payload);
                });
        } else {
            return Promise.resolve();
        }
    };
    deleteVectorMask.action = {
        reads: [locks.JS_TOOL],
        writes: [locks.PS_DOC, locks.JS_DOC]
    };

    /**
     * Handle escaping from vector mask for the selection-based vector mask tools.
     * Most tools can just call tools.changeVectorMaskMode directly.
     *
     * @return {Promise}
     */
    var handleEscapeVectorMask = function () {
        var appStore = this.flux.store("application"),
            toolStore = this.flux.store("tool"),
            currentDocument = appStore.getCurrentDocument();

        if (!currentDocument) {
            return Promise.resolve();
        }

        if (toolStore.getVectorMode() && toolStore.getModalToolState()) {
            return this.transfer("tools.changeVectorMaskMode", false);
        }

        var currentLayers = currentDocument.layers.selected;

        if (currentLayers.isEmpty()) {
            return Promise.resolve();
        }

        var currentLayer = currentLayers.first();

        return this.transfer("layers.resetLayers", currentDocument, currentLayer)
            .bind(this)
            .then(function () {
                currentDocument = appStore.getCurrentDocument();
                currentLayer = currentDocument.layers.selected.first();
                if (currentLayer && currentLayer.vectorMaskEmpty) {
                    return this.transfer("tools.changeVectorMaskMode", false);
                } else {
                    return this.transfer("tools.select", toolStore.getToolByID("newSelect"));
                }
            });
    };
    handleEscapeVectorMask.action = {
        reads: [locks.JS_APP, locks.JS_DOC],
        writes: [],
        transfers: ["layers.resetLayers", "tools.changeVectorMaskMode", "tools.select"],
        modal: true
    };

    /**
     * Handle deleting the vector mask for all of the vector mask mode tools.
     *
     * @return {Promise}
     */
    var handleDeleteVectorMask = function () {
        var appStore = this.flux.store("application"),
            toolStore = this.flux.store("tool"),
            currentDocument = appStore.getCurrentDocument();

        if (!currentDocument) {
            return Promise.resolve();
        }

        if (toolStore.getModalToolState()) {
            return this.transfer("mask.deleteVectorMask")
                .bind(this)
                .then(function () {
                    return this.transfer("tools.changeVectorMaskMode", false);
                });
        }

        var currentLayer = currentDocument.layers.selected.first();

        return this.transfer("layers.resetLayers", currentDocument, currentLayer)
            .bind(this)
            .then(function () {
                currentDocument = appStore.getCurrentDocument();
                currentLayer = currentDocument.layers.selected.first();

                if (currentLayer && !currentLayer.vectorMaskEmpty) {
                    var payload = { commandID: _CLEAR_PATH, waitForCompletion: true };
                    return this.transfer("menu.native", payload)
                        .bind(this)
                        .then(function () {
                            return this.transfer("layers.resetLayers", currentDocument, currentLayer);
                        })
                        .then(function () {
                            currentDocument = appStore.getCurrentDocument();
                            currentLayer = currentDocument.layers.selected.first();
                            if (currentLayer && !currentLayer.vectorMaskEnabled) {
                                return this.transfer("mask.deleteVectorMask")
                                    .bind(this)
                                    .then(function () {
                                        return this.transfer("tools.changeVectorMaskMode", false);
                                    });
                            }
                        });
                } else {
                    return this.transfer("mask.deleteVectorMask")
                        .bind(this)
                        .then(function () {
                            this.transfer("tools.changeVectorMaskMode", false);
                        });
                }
            });
    };
    handleDeleteVectorMask.action = {
        reads: [locks.JS_APP, locks.JS_DOC],
        writes: [],
        transfers: ["layers.resetLayers", "mask.deleteVectorMask", "tools.changeVectorMaskMode",
            "menu.native"]
    };

    /**
     * Create a mask that matches the bounds of the currently selected layer
     *
     * @return {Promise}
     */
    var applyRectangle = function () {
        var appStore = this.flux.store("application"),
            toolStore = this.flux.store("tool"),
            currentDocument = appStore.getCurrentDocument();

        if (!currentDocument) {
            return Promise.resolve();
        }

        var currentLayers = currentDocument.layers.selected;

        if (currentLayers.isEmpty()) {
            return Promise.resolve();
        }

        var currentLayer = currentLayers.first(),
            bounds = boundsLib.bounds(currentDocument.layers.childBounds(currentLayer)),
            options = {
                historyStateInfo: {
                    name: nls.localize("strings.ACTIONS.ADD_VECTOR_MASK"),
                    target: documentLib.referenceBy.id(currentDocument.id),
                    coalesce: true,
                    suppressHistoryStateNotification: true
                }
            },
            layerList = Immutable.List.of(currentLayer),
            createActions = [
                vectorMaskLib.makeBoundsWorkPath(bounds),
                vectorMaskLib.makeVectorMaskFromWorkPath(),
                vectorMaskLib.deleteWorkPath()];

        return layerActionsUtil.playSimpleLayerActions(currentDocument, layerList, createActions, true, options)
            .bind(this)
            .then(function () {
                return this.transfer("tools.select", toolStore.getToolByID("newSelect"));
            });
    };
    applyRectangle.action = {
        reads: [locks.JS_APP, locks.JS_DOC],
        writes: [locks.PS_DOC],
        transfers: ["tools.select"]
    };

    /**
     * Create a circular mask the size of the currently selected layer
     *
     * @return {Promise}
     */
    var applyEllipse = function () {
        var appStore = this.flux.store("application"),
            toolStore = this.flux.store("tool"),
            currentDocument = appStore.getCurrentDocument();

        if (!currentDocument) {
            return Promise.resolve();
        }

        var currentLayers = currentDocument.layers.selected;

        if (currentLayers.isEmpty()) {
            return Promise.resolve();
        }

        var currentLayer = currentLayers.first(),
            bounds = currentLayer.bounds,
            options = {
                historyStateInfo: {
                    name: nls.localize("strings.ACTIONS.ADD_VECTOR_MASK"),
                    target: documentLib.referenceBy.id(currentDocument.id),
                    coalesce: true,
                    suppressHistoryStateNotification: true
                }
            },
            layerList = Immutable.List.of(currentLayer),
            createActions = [
                vectorMaskLib.makeCircularBoundsWorkPath(bounds),
                vectorMaskLib.makeVectorMaskFromWorkPath(),
                vectorMaskLib.deleteWorkPath()];

        return layerActionsUtil.playSimpleLayerActions(currentDocument, layerList, createActions, true, options)
            .bind(this)
            .then(function () {
                return this.transfer("tools.select", toolStore.getToolByID("newSelect"));
            });
    };
    applyEllipse.action = {
        reads: [locks.JS_APP, locks.JS_DOC],
        writes: [locks.PS_DOC],
        transfers: ["tools.select"]
    };

    exports.editVectorMask = editVectorMask;
    exports.selectVectorMask = selectVectorMask;
    exports.deleteVectorMask = deleteVectorMask;
    exports.handleDeleteVectorMask = handleDeleteVectorMask;
    exports.handleEscapeVectorMask = handleEscapeVectorMask;
    exports.applyEllipse = applyEllipse;
    exports.applyRectangle = applyRectangle;
});
<|endoftext|>


<commit_before>define([
  'jquery',
  'summernote/base/core/func',
  'summernote/base/core/list',
  'summernote/base/core/dom'
], function ($, func, list, dom) {
  /**
   * @param {jQuery} $note
   * @param {Object} options
   * @return {Context}
   */
  var Context = function ($note, options) {
    var self = this;

    var ui = $.summernote.ui;
    this.memos = {};
    this.modules = {};
    this.layoutInfo = {};
    this.options = options;
    this.dom = dom;

    /**
     * create layout and initialize modules and other resources
     */
    this.initialize = function () {
      this.layoutInfo = ui.createLayout($note, options);
      this._initialize();
      $note.hide();
      return this;
    };

    /**
     * destroy modules and other resources and remove layout
     */
    this.destroy = function () {
      this._destroy();
      $note.removeData('summernote');
      ui.removeLayout($note, this.layoutInfo);
    };

    /**
     * destory modules and other resources and initialize it again
     */
    this.reset = function () {
      var disabled = self.isDisabled();
      this.code(dom.emptyPara);
      this._destroy();
      this._initialize();

      if (disabled) {
        self.disable();
      }
    };

    this._initialize = function () {
      // add optional buttons
      var buttons = $.extend({}, this.options.buttons);
      Object.keys(buttons).forEach(function (key) {
        self.memo('button.' + key, buttons[key]);
      });

      var modules = $.extend({}, this.options.modules, $.summernote.plugins || {});

      // add and initialize modules
      Object.keys(modules).forEach(function (key) {
        self.module(key, modules[key], true);
      });

      Object.keys(this.modules).forEach(function (key) {
        self.initializeModule(key);
      });
    };

    this._destroy = function () {
      // destroy modules with reversed order
      Object.keys(this.modules).reverse().forEach(function (key) {
        self.removeModule(key);
      });

      Object.keys(this.memos).forEach(function (key) {
        self.removeMemo(key);
      });
    };

    this.code = function (html) {
      var isActivated = this.invoke('codeview.isActivated');

      if (html === undefined) {
        this.invoke('codeview.sync');
        return isActivated ? this.layoutInfo.codable.val() : this.layoutInfo.editable.html();
      } else {
        if (isActivated) {
          this.layoutInfo.codable.val(html);
        } else {
          this.layoutInfo.editable.html(html);
        }
        $note.val(html);
        this.triggerEvent('change', html);
      }
    };

    this.isDisabled = function () {
      return this.layoutInfo.editable.attr('contenteditable') === 'false';
    };

    this.enable = function () {
      this.layoutInfo.editable.attr('contenteditable', true);
      this.invoke('toolbar.activate', true);
    };

    this.disable = function () {
      // close codeview if codeview is opend
      if (this.invoke('codeview.isActivated')) {
        this.invoke('codeview.deactivate');
      }
      this.layoutInfo.editable.attr('contenteditable', false);
      this.invoke('toolbar.deactivate', true);
    };

    this.triggerEvent = function () {
      var namespace = list.head(arguments);
      var args = list.tail(list.from(arguments));

      var callback = this.options.callbacks[func.namespaceToCamel(namespace, 'on')];
      if (callback) {
        callback.apply($note[0], args);
      }
      $note.trigger('summernote.' + namespace, args);
    };

    this.initializeModule = function (key) {
      var module = this.modules[key];
      module.shouldInitialize = module.shouldInitialize || func.ok;
      if (!module.shouldInitialize()) {
        return;
      }

      // initialize module
      if (module.initialize) {
        module.initialize();
      }

      // attach events
      if (module.events) {
        dom.attachEvents($note, module.events);
      }
    };

    this.module = function (key, ModuleClass, withoutIntialize) {
      if (arguments.length === 1) {
        return this.modules[key];
      }

      this.modules[key] = new ModuleClass(this);

      if (!withoutIntialize) {
        this.initializeModule(key);
      }
    };

    this.removeModule = function (key) {
      var module = this.modules[key];
      if (module.shouldInitialize()) {
        if (module.events) {
          dom.detachEvents($note, module.events);
        }

        if (module.destroy) {
          module.destroy();
        }
      }

      delete this.modules[key];
    };

    this.memo = function (key, obj) {
      if (arguments.length === 1) {
        return this.memos[key];
      }
      this.memos[key] = obj;
    };

    this.removeMemo = function (key) {
      if (this.memos[key] && this.memos[key].destroy) {
        this.memos[key].destroy();
      }

      delete this.memos[key];
    };

    this.createInvokeHandler = function (namespace, value) {
      return function (event) {
        event.preventDefault();
        self.invoke(namespace, value || $(event.target).closest('[data-value]').data('value'));
      };
    };

    this.invoke = function () {
      var namespace = list.head(arguments);
      var args = list.tail(list.from(arguments));

      var splits = namespace.split('.');
      var hasSeparator = splits.length > 1;
      var moduleName = hasSeparator && list.head(splits);
      var methodName = hasSeparator ? list.last(splits) : list.head(splits);

      var module = this.modules[moduleName || 'editor'];
      if (!moduleName && this[methodName]) {
        return this[methodName].apply(this, args);
      } else if (module && module[methodName] && module.shouldInitialize()) {
        return module[methodName].apply(module, args);
      }
    };

    return this.initialize();
  };

  return Context;
});
<commit_msg>Revert "make Dom accessible in Context for plugins"<commit_after>define([
  'jquery',
  'summernote/base/core/func',
  'summernote/base/core/list',
  'summernote/base/core/dom'
], function ($, func, list, dom) {
  /**
   * @param {jQuery} $note
   * @param {Object} options
   * @return {Context}
   */
  var Context = function ($note, options) {
    var self = this;

    var ui = $.summernote.ui;
    this.memos = {};
    this.modules = {};
    this.layoutInfo = {};
    this.options = options;

    /**
     * create layout and initialize modules and other resources
     */
    this.initialize = function () {
      this.layoutInfo = ui.createLayout($note, options);
      this._initialize();
      $note.hide();
      return this;
    };

    /**
     * destroy modules and other resources and remove layout
     */
    this.destroy = function () {
      this._destroy();
      $note.removeData('summernote');
      ui.removeLayout($note, this.layoutInfo);
    };

    /**
     * destory modules and other resources and initialize it again
     */
    this.reset = function () {
      var disabled = self.isDisabled();
      this.code(dom.emptyPara);
      this._destroy();
      this._initialize();

      if (disabled) {
        self.disable();
      }
    };

    this._initialize = function () {
      // add optional buttons
      var buttons = $.extend({}, this.options.buttons);
      Object.keys(buttons).forEach(function (key) {
        self.memo('button.' + key, buttons[key]);
      });

      var modules = $.extend({}, this.options.modules, $.summernote.plugins || {});

      // add and initialize modules
      Object.keys(modules).forEach(function (key) {
        self.module(key, modules[key], true);
      });

      Object.keys(this.modules).forEach(function (key) {
        self.initializeModule(key);
      });
    };

    this._destroy = function () {
      // destroy modules with reversed order
      Object.keys(this.modules).reverse().forEach(function (key) {
        self.removeModule(key);
      });

      Object.keys(this.memos).forEach(function (key) {
        self.removeMemo(key);
      });
    };

    this.code = function (html) {
      var isActivated = this.invoke('codeview.isActivated');

      if (html === undefined) {
        this.invoke('codeview.sync');
        return isActivated ? this.layoutInfo.codable.val() : this.layoutInfo.editable.html();
      } else {
        if (isActivated) {
          this.layoutInfo.codable.val(html);
        } else {
          this.layoutInfo.editable.html(html);
        }
        $note.val(html);
        this.triggerEvent('change', html);
      }
    };

    this.isDisabled = function () {
      return this.layoutInfo.editable.attr('contenteditable') === 'false';
    };

    this.enable = function () {
      this.layoutInfo.editable.attr('contenteditable', true);
      this.invoke('toolbar.activate', true);
    };

    this.disable = function () {
      // close codeview if codeview is opend
      if (this.invoke('codeview.isActivated')) {
        this.invoke('codeview.deactivate');
      }
      this.layoutInfo.editable.attr('contenteditable', false);
      this.invoke('toolbar.deactivate', true);
    };

    this.triggerEvent = function () {
      var namespace = list.head(arguments);
      var args = list.tail(list.from(arguments));

      var callback = this.options.callbacks[func.namespaceToCamel(namespace, 'on')];
      if (callback) {
        callback.apply($note[0], args);
      }
      $note.trigger('summernote.' + namespace, args);
    };

    this.initializeModule = function (key) {
      var module = this.modules[key];
      module.shouldInitialize = module.shouldInitialize || func.ok;
      if (!module.shouldInitialize()) {
        return;
      }

      // initialize module
      if (module.initialize) {
        module.initialize();
      }

      // attach events
      if (module.events) {
        dom.attachEvents($note, module.events);
      }
    };

    this.module = function (key, ModuleClass, withoutIntialize) {
      if (arguments.length === 1) {
        return this.modules[key];
      }

      this.modules[key] = new ModuleClass(this);

      if (!withoutIntialize) {
        this.initializeModule(key);
      }
    };

    this.removeModule = function (key) {
      var module = this.modules[key];
      if (module.shouldInitialize()) {
        if (module.events) {
          dom.detachEvents($note, module.events);
        }

        if (module.destroy) {
          module.destroy();
        }
      }

      delete this.modules[key];
    };

    this.memo = function (key, obj) {
      if (arguments.length === 1) {
        return this.memos[key];
      }
      this.memos[key] = obj;
    };

    this.removeMemo = function (key) {
      if (this.memos[key] && this.memos[key].destroy) {
        this.memos[key].destroy();
      }

      delete this.memos[key];
    };

    this.createInvokeHandler = function (namespace, value) {
      return function (event) {
        event.preventDefault();
        self.invoke(namespace, value || $(event.target).closest('[data-value]').data('value'));
      };
    };

    this.invoke = function () {
      var namespace = list.head(arguments);
      var args = list.tail(list.from(arguments));

      var splits = namespace.split('.');
      var hasSeparator = splits.length > 1;
      var moduleName = hasSeparator && list.head(splits);
      var methodName = hasSeparator ? list.last(splits) : list.head(splits);

      var module = this.modules[moduleName || 'editor'];
      if (!moduleName && this[methodName]) {
        return this[methodName].apply(this, args);
      } else if (module && module[methodName] && module.shouldInitialize()) {
        return module[methodName].apply(module, args);
      }
    };

    return this.initialize();
  };

  return Context;
});
<|endoftext|>


<commit_before>/****************************************************
 *
 * All the code in this file will be bundled into a
 * 'common.js' file. By separating code that won't
 * change much as you push updates into production,
 * users' browsers can keep the common.js bundle
 * cached (as long as no changes were made to it),
 * allowing for faster repeat page load speeds.
 *
 ****************************************************/

window.libs = {}
// Import the following libraries in other files like this:
//
//      const { $, throttle } = libs
//
libs.$ = libs.jQuery = require('jquery')
libs.sanitizeHTML = require('sanitize-html')

// Dump static code here
require('./helpers.js')
require('./errors.js')
require('./scroll-animations.js')
<commit_msg>improve docs<commit_after>/****************************************************
 *
 * All the code in this file will be bundled into a
 * 'common.js' file. By separating code that won't
 * change much as you push updates into production,
 * users' browsers can keep the common.js bundle
 * cached (as long as no changes were made to it),
 * allowing for faster repeat page load speeds.
 *
 ****************************************************/

window.libs = {}
// Import the following libraries in other files like this:
//
//      const { sanitizeHTML } = libs
//
libs.sanitizeHTML = require('sanitize-html')

// Dump static code here
require('./helpers.js')
require('./errors.js')
require('./scroll-animations.js')
<|endoftext|>


<commit_before>/**
 * Represents an individual tab within a Stack's header
 *
 * @param {lm.controls.Header} header
 * @param {lm.items.AbstractContentItem} contentItem
 *
 * @constructor
 */
lm.controls.Tab = function( header, contentItem ) {
	this.header = header;
	this.contentItem = contentItem;
	this.element = $( lm.controls.Tab._template );
	this.titleElement = this.element.find( '.lm_title' );
	this.closeElement = this.element.find( '.lm_close_tab' );
	this.closeElement[ contentItem.config.isClosable ? 'show' : 'hide' ]();
	this.isActive = false;

	this.setTitle( contentItem.config.title );
	this.contentItem.on( 'titleChanged', this.setTitle, this );

	this._layoutManager = this.contentItem.layoutManager;

	if(
		this._layoutManager.config.settings.reorderEnabled === true &&
		contentItem.config.reorderEnabled === true
	) {
		this._dragListener = new lm.utils.DragListener( this.element );
		this._dragListener.on( 'dragStart', this._onDragStart, this );
	}

	this._onTabClickFn = lm.utils.fnBind( this._onTabClick, this );
	this._onCloseClickFn = lm.utils.fnBind( this._onCloseClick, this );

	this.element.click( this._onTabClickFn );

	if( this._layoutManager.config.settings.showCloseIcon === true ) {
		this.closeElement.click( this._onCloseClickFn );
	} else {
		this.closeElement.remove();
	}

	this.contentItem.tab = this;
	this.contentItem.emit( 'tab', this );
	this.contentItem.layoutManager.emit( 'tabCreated', this );

	if( this.contentItem.isComponent ) {
		this.contentItem.container.tab = this;
		this.contentItem.container.emit( 'tab', this );
	}
};

/**
 * The tab's html template
 *
 * @type {String}
 */
lm.controls.Tab._template = '
' +
							'

' +
							'
';

lm.utils.copy( lm.controls.Tab.prototype,{

	/**
	 * Sets the tab's title to the provided string and sets
	 * its title attribute to a pure text representation (without
	 * html tags) of the same string.
	 *
	 * @public
	 * @param {String} title can contain html
	 */
	setTitle: function( title ) {
		this.element.attr( 'title', lm.utils.stripTags( title ) );
		this.titleElement.html( title );
	},

	/**
	 * Sets this tab's active state. To programmatically
	 * switch tabs, use header.setActiveContentItem( item ) instead.
	 *
	 * @public
	 * @param {Boolean} isActive
	 */
	setActive: function( isActive ) {
		if( isActive === this.isActive ) {
			return;
		}
		this.isActive = isActive;

		if( isActive ) {
			this.element.addClass( 'lm_active' );
		} else {
			this.element.removeClass( 'lm_active');
		}
	},

	/**
	 * Destroys the tab
	 *
	 * @private
	 * @returns {void}
	 */
	_$destroy: function() {
		this.element.off( 'click', this._onTabClickFn );
		this.closeElement.off( 'click', this._onCloseClickFn );
		this.element.remove();
	},

	/**
	 * Callback for the DragListener
	 *
	 * @param   {Number} x The tabs absolute x position
	 * @param   {Number} y The tabs absolute y position
	 *
	 * @private
	 * @returns {void}
	 */
	_onDragStart: function( x, y ) {
		if( this.contentItem.parent.isMaximised === true ) {
			this.contentItem.parent.toggleMaximise();
		}
		new lm.controls.DragProxy(
			x,
			y,
			this._dragListener,
			this._layoutManager,
			this.contentItem,
			this.header.parent
		);
	},

	/**
	 * Callback when the tab is clicked
	 *
	 * @param {jQuery DOM event} event
	 *
	 * @private
	 * @returns {void}
	 */
	_onTabClick: function( event ) {
		// left mouse button
		if( event.button === 0 ) {
			this.header.parent.setActiveContentItem( this.contentItem );

		// middle mouse button
		} else if( event.button === 1 && this.contentItem.config.isClosable ) {
			this._onCloseClick( event );
		}
	},

	/**
	 * Callback when the tab's close button is
	 * clicked
	 *
	 * @param   {jQuery DOM event} event
	 *
	 * @private
	 * @returns {void}
	 */
	_onCloseClick: function( event ) {
		event.stopPropagation();
		this.header.parent.removeChild( this.contentItem );
	}
});
<commit_msg>On destroy, Tab should unsubscribe from its _dragListener's 'dragstart' event.<commit_after>/**
 * Represents an individual tab within a Stack's header
 *
 * @param {lm.controls.Header} header
 * @param {lm.items.AbstractContentItem} contentItem
 *
 * @constructor
 */
lm.controls.Tab = function( header, contentItem ) {
	this.header = header;
	this.contentItem = contentItem;
	this.element = $( lm.controls.Tab._template );
	this.titleElement = this.element.find( '.lm_title' );
	this.closeElement = this.element.find( '.lm_close_tab' );
	this.closeElement[ contentItem.config.isClosable ? 'show' : 'hide' ]();
	this.isActive = false;

	this.setTitle( contentItem.config.title );
	this.contentItem.on( 'titleChanged', this.setTitle, this );

	this._layoutManager = this.contentItem.layoutManager;

	if(
		this._layoutManager.config.settings.reorderEnabled === true &&
		contentItem.config.reorderEnabled === true
	) {
		this._dragListener = new lm.utils.DragListener( this.element );
		this._dragListener.on( 'dragStart', this._onDragStart, this );
	}

	this._onTabClickFn = lm.utils.fnBind( this._onTabClick, this );
	this._onCloseClickFn = lm.utils.fnBind( this._onCloseClick, this );

	this.element.click( this._onTabClickFn );

	if( this._layoutManager.config.settings.showCloseIcon === true ) {
		this.closeElement.click( this._onCloseClickFn );
	} else {
		this.closeElement.remove();
	}

	this.contentItem.tab = this;
	this.contentItem.emit( 'tab', this );
	this.contentItem.layoutManager.emit( 'tabCreated', this );

	if( this.contentItem.isComponent ) {
		this.contentItem.container.tab = this;
		this.contentItem.container.emit( 'tab', this );
	}
};

/**
 * The tab's html template
 *
 * @type {String}
 */
lm.controls.Tab._template = '
' +
							'

' +
							'
';

lm.utils.copy( lm.controls.Tab.prototype,{

	/**
	 * Sets the tab's title to the provided string and sets
	 * its title attribute to a pure text representation (without
	 * html tags) of the same string.
	 *
	 * @public
	 * @param {String} title can contain html
	 */
	setTitle: function( title ) {
		this.element.attr( 'title', lm.utils.stripTags( title ) );
		this.titleElement.html( title );
	},

	/**
	 * Sets this tab's active state. To programmatically
	 * switch tabs, use header.setActiveContentItem( item ) instead.
	 *
	 * @public
	 * @param {Boolean} isActive
	 */
	setActive: function( isActive ) {
		if( isActive === this.isActive ) {
			return;
		}
		this.isActive = isActive;

		if( isActive ) {
			this.element.addClass( 'lm_active' );
		} else {
			this.element.removeClass( 'lm_active');
		}
	},

	/**
	 * Destroys the tab
	 *
	 * @private
	 * @returns {void}
	 */
	_$destroy: function() {
		this.element.off( 'click', this._onTabClickFn );
		this.closeElement.off( 'click', this._onCloseClickFn );
		if( this._dragListener ) {
			this._dragListener.off( 'dragStart', this._onDragStart );
			this._dragListener = null;
		}
		this.element.remove();
	},

	/**
	 * Callback for the DragListener
	 *
	 * @param   {Number} x The tabs absolute x position
	 * @param   {Number} y The tabs absolute y position
	 *
	 * @private
	 * @returns {void}
	 */
	_onDragStart: function( x, y ) {
		if( this.contentItem.parent.isMaximised === true ) {
			this.contentItem.parent.toggleMaximise();
		}
		new lm.controls.DragProxy(
			x,
			y,
			this._dragListener,
			this._layoutManager,
			this.contentItem,
			this.header.parent
		);
	},

	/**
	 * Callback when the tab is clicked
	 *
	 * @param {jQuery DOM event} event
	 *
	 * @private
	 * @returns {void}
	 */
	_onTabClick: function( event ) {
		// left mouse button
		if( event.button === 0 ) {
			this.header.parent.setActiveContentItem( this.contentItem );

		// middle mouse button
		} else if( event.button === 1 && this.contentItem.config.isClosable ) {
			this._onCloseClick( event );
		}
	},

	/**
	 * Callback when the tab's close button is
	 * clicked
	 *
	 * @param   {jQuery DOM event} event
	 *
	 * @private
	 * @returns {void}
	 */
	_onCloseClick: function( event ) {
		event.stopPropagation();
		this.header.parent.removeChild( this.contentItem );
	}
});
<|endoftext|>


<commit_before>/**
 * The `proact-dsl` module provides DSL for creating and managing different ProAct objects.
 *
 *
 * @module proact-dsl
 * @main proact-dsl
 */

/**
 *

 *  Constructs a `ProAct.Registry`.
 *  It is used to store/create objects that can be referenced or configured using the {{#crossLink "ProAct.DSL"}}{{/crossLink}}.
 *

 *

 *  `ProAct.Registry` is part of the `proact-dsl` module of ProAct.js.
 *

 *
 * @class ProAct.Registry
 * @constructor
 */
function Registry () {
  this.providers = {};
}
ProAct.Registry = P.R = Registry;

ProAct.Registry.prototype = rProto = {

  /**
   * Reference to the constructor of this object.
   *
   * @property constructor
   * @type ProAct.Registry
   * @final
   * @for ProAct.Registry
   */
  constructor: ProAct.Registry,

  /**
   * Registers a {{#crossLink "ProAct.Registry.Provider"}}{{/crossLink}} for the passed namespace in the registry.
   *
   * @for ProAct.Registry
   * @instance
   * @method register
   * @param {String} namespace
   *      The namespace to register the provider in.
   * @param {ProAct.Registry.Provider} provider
   *      The {{#crossLink "ProAct.Registry.Provider"}}{{/crossLink}} to register.
   * @return {ProAct.Registers}
   *      this
   * @throws {Error}
   *      If a {{#crossLink "ProAct.Registry.Provider"}}{{/crossLink}} is already registered for the passed namespace.
   */
  register: function (namespace, provider) {
    if (this.providers[namespace]) {
      throw new Error(namespace + 'is already registered in this registry.');
    }
    this.providers[namespace] = provider;
    if (provider.registered) {
      provider.registered(this);
    }
    return this;
  },

  /**
   * Retrieves the right {{#crossLink "ProAct.Registry.Provider"}}{{/crossLink}} using the name of stored
   * in this ProAct.Registry object, or the name of an object to be stored
   *
   * @for ProAct.Registry
   * @instance
   * @method getProviderByName
   * @param {String} name
   *      The name of storable object.
   *

   *        It must be in the format '{namespace}:{key}'.
   *

   *

   *        Here the namespace is the namespace the {{#crossLink "ProAct.Registry.Provider"}}{{/crossLink}} manages.
   *

   * @return {Array}
   *      The first element in the result is the {{#crossLink "ProAct.Registry.Provider"}}{{/crossLink}} or undefined if not found.
   *

   *        The second one is the key at which an object is stored or will be stored in the provider.
   *

   *

   *        The third element is an array with options for storing/creating an object passed to the provider using
   *        the name string.
   *

   */
  getProviderByName: function (name) {
    var parts = name.split(':');

    return [this.providers[parts[0]], parts[1], parts.slice(2)];
  },

  /**
   * Configures an object to be stored using {{#crossLink "ProAct.DSL"}}{{/crossLink}} passed through options and DSL arguments.
   *

   *  Example usage:
   *

   *

   *  A {{#crossLink "ProAct.Stream"}}{{/crossLink}} is passed to the registry for setup with DSL data.
   *

   *

   *  The data passed through the options parameter is
   *

   *    '<<(s:foo)|map(-)|filter($1)'
   *

   *

   *

   *  And the arguments for the DSL machine passed through the args parameter are
   *

   *    [function (v) {
   *      return v % 2 === 0;
   *    }]
   *

   *

   *

   *  This means that a {{#crossLink "ProAct.Stream"}}{{/crossLink}} stored in this registry by the key 'foo' should be set
   *  as a source to the passed as the object parameter simple {{#crossLink "ProAct.Stream"}}{{/crossLink}}.
   *

   *

   *  It also means that for every value comming in the object parameter's stream there should be mapping of negativity and
   *  only even values should be passed to it.
   *

   *

   *  So if we trigger in the 'foo' stream the value of 4 in our stream we will get -4, and if we trigger 5, we won't get anything.
   *

   *
   * @for ProAct.Registry
   * @instance
   * @method setup
   * @param {Object} object
   *      The object to setup.
   * @param {String|Object} options
   *      A {{#crossLink "ProAct.DSL"}}{{/crossLink}} data object or string used to setup the object.
   * @param {Array} args
   *      Arguments to be used by the {{#crossLink "ProAct.DSL/run:method"}}{{/crossLink}} method while configuring the passed object.
   * @return {Object}
   *      Ready to strore object.
   */
  setup: function (object, options, args) {
    return dsl.run.apply(null, [object, options, this].concat(args));
  },

  /**
   * Creates a new object and stores it in this registry, using the right provider for the creation
   * and configuring it using the DSL passed through the options parameter.
   *

   *  {{#crossLink "ProAct.Registry/getProviderByName:method"}}{{/crossLink}} is used to locate the right provider to create the object with.
   *

   *

   *  {{#crossLink "ProAct.Registry/setup:method"}}{{/crossLink}} is used to setup the newly created object using the {{#crossLink "ProAct.DSL"}}{{/crossLink}}
   *

   *

   *  The idea of this method is to create and configure {{#crossLink "ProAct.Actor"}}{{/crossLink}} objects.
   *

   *
   * @for ProAct.Registry
   * @instance
   * @method make
   * @param {String} name
   *      Name of the object to create and store.
   *

   *        It must be in the format '{namespace}:{key}'
   *

   * @param {String|Object} options
   *      A {{#crossLink "ProAct.DSL"}}{{/crossLink}} data object or string used to setup the object to be created.
   * @param [...]
   *      Arguments to be used by the {{#crossLink "ProAct.DSL/run:method"}}{{/crossLink}} method while configuring the newly created object.
   * @return {Object}
   *      The newly created, stored and configured object, or null if there was no {{#crossLink "ProAct.Registry.Provider"}}{{/crossLink}} register for its type.
   */
  make: function (name, options) {
    var args = slice.call(arguments, 2),
        p = this.getProviderByName(name),
        actor;

    if (p[0]) {
      actor = p[0].make.apply(p[0], [p[1], p[2]].concat(args));
      return this.setup(actor, options, args);
    }
    return null;
  },

  /**
   * Stores an object  in this registry, using the right provider to configure it using the DSL passed through the options parameter.
   *

   *  {{#crossLink "ProAct.Registry/getProviderByName:method"}}{{/crossLink}} is used to locate the right provider to store the object to.
   *

   *
   * @for ProAct.Registry
   * @instance
   * @method store
   * @param {String} name
   *      Name of the object to store.
   *

   *        It must be in the format '{namespace}:{key}'
   *

   * @param {Object} object
   *      The object to store.
   * @param {String|Object} options
   *      A {{#crossLink "ProAct.DSL"}}{{/crossLink}} data object or string used to setup the object to be stored (optional).
   * @param [...]
   *      Arguments to be used by the {{#crossLink "ProAct.DSL/run:method"}}{{/crossLink}} method while configuring the object.
   * @return {Object}
   *      The stored and configured object, or null if there was no {{#crossLink "ProAct.Registry.Provider"}}{{/crossLink}} register for its type.
   */
  store: function (name, object, options) {
    var args = slice.call(arguments, 2),
        p = this.getProviderByName(name);

    if (p[0]) {
      return p[0].store.apply(p[0], [p[1], object, p[2]].concat(args));
    }
    return null;
  },

  /**
   * Retrieves an object, stored this registry.
   *

   *  {{#crossLink "ProAct.Registry/getProviderByName:method"}}{{/crossLink}} is used to locate the right provider to retrieve the object from.
   *

   *
   * @for ProAct.Registry
   * @instance
   * @method get
   * @param {String} name
   *      Name of the object to find.
   *

   *        It must be in the format '{namespace}:{key}'
   *

   * @return {Object}
   *      The stored object, or null if there was no {{#crossLink "ProAct.Registry.Provider"}}{{/crossLink}} register for its type or no object registered for the passed name.
   */
  get: function (name) {
    var p = this.getProviderByName(name);

    if (p[0]) {
      return p[0].get(p[1]);
    }
    return null;
  },

  /**
   * Helper method for transforming an array of keys of stored items in this `ProAct.Registry` to an array of the actual items.
   *

   *  Mainly used by the {{#crossLink "ProAct.DSL"}}{{/crossLink}} logic.
   *

   *
   * @for ProAct.Registry
   * @protected
   * @instance
   * @method toObjectArray
   * @param {Array} array
   *      Array of string keys to objects stored in this registry to be retrieved using {{#crossLink "ProAct.Registry/toObject:method"}}{{/crossLink}}.
   *

   *        If object is not stored on some key, the key itself is returned in the same possition in the result array.
   *

   * @return {Array}
   *      Of the retrieved objects, in the same order as the keys.
   */
  toObjectArray: function (array) {
    var self = this;
    if (!P.U.isArray(array)) {
      return this.toObject(array);
    }
    return map.call(array, function (el) {
      return self.toObject(el);
    });
  },

  /**
   * Helper method for transforming a key of stored item in this `ProAct.Registry` to the actual item or returning the key, if
   * the item is not found in the `ProAct.Registry`.
   *

   *  Mainly used by the {{#crossLink "ProAct.DSL"}}{{/crossLink}} logic.
   *

   *
   * @for ProAct.Registry
   * @protected
   * @instance
   * @method toObject
   * @param {String|Object} data
   *      Key of strored object or something else. If the key is valid and there is something stored on it, the stored object is retrieved.
   *

   *        If there is nothing stored for this data, the data itself is returned.
   *

   * @return {Object}
   *      Stored object, if found using the passed data or the data itself.
   */
  toObject: function (data) {
    if (P.U.isString(data)) {
      var result = this.get(data);
      return result ? result : data;
    }

    return data;
  }
};

P.U.ex(P.Actor.prototype, {

  /**
   * Adds a new transformation to the list of transformations
   * of this actor.
   *
   *

   *  A transformation is a function or an object that has a call method defined.
   *  This function or call method should have one argument and to return a transformed version of it.
   *  If the returned value is {{#crossLink "ProAct.Actor/BadValue:property"}}{{/crossLink}}, the next transformations are skipped and the updating
   *  value/event becomes - bad value.
   *

   *
   *

   *  Every value/event that updates this actor will be transformed using the new transformation.
   *

   *
   * This method uses {{#crossLink "ProAct.Actor/transform:method"}}{{/crossLink}}, but can read transformation
   * funtion/object stored in the registry (if the proact-dsl module is present) by it's string name.
   *
   * @for ProAct.Actor
   * @instance
   * @method transformStored
   * @protected
   * @param {Object|String} transformation The transformation to add. Can be string - to be retrieved by name.
   * @param {String} type The type of the transformation, for example `mapping`.
   * @return {ProAct.Actor}
   *      this
   */
  transformStored: function (transformation, type) {
    if (P.U.isString(transformation)) {
      P.DSL.run(this, type + '(' + transformation + ')', P.registry);
      return this;
    }

    return this.transform(transformation);
  }

});

P.U.ex(P.ObjectCore.prototype, {

  // The meta is in format of the {{#crossLink "ProAct.DSL"}}{{/crossLink}}.
  applyMeta: function (meta, property) {
    if (meta && P.registry) {
      if (!P.U.isArray(meta)) {
        meta = [meta];
      }

      if (!(meta[0] instanceof ProAct.Property)) {
        P.registry.setup.apply(P.registry, [property].concat(meta));
      }
    }
  }

});
<commit_msg>Docs for the applyMeta method of the ProAct.ObjectCore.<commit_after>/**
 * The `proact-dsl` module provides DSL for creating and managing different ProAct objects.
 *
 *
 * @module proact-dsl
 * @main proact-dsl
 */

/**
 *

 *  Constructs a `ProAct.Registry`.
 *  It is used to store/create objects that can be referenced or configured using the {{#crossLink "ProAct.DSL"}}{{/crossLink}}.
 *

 *

 *  `ProAct.Registry` is part of the `proact-dsl` module of ProAct.js.
 *

 *
 * @class ProAct.Registry
 * @constructor
 */
function Registry () {
  this.providers = {};
}
ProAct.Registry = P.R = Registry;

ProAct.Registry.prototype = rProto = {

  /**
   * Reference to the constructor of this object.
   *
   * @property constructor
   * @type ProAct.Registry
   * @final
   * @for ProAct.Registry
   */
  constructor: ProAct.Registry,

  /**
   * Registers a {{#crossLink "ProAct.Registry.Provider"}}{{/crossLink}} for the passed namespace in the registry.
   *
   * @for ProAct.Registry
   * @instance
   * @method register
   * @param {String} namespace
   *      The namespace to register the provider in.
   * @param {ProAct.Registry.Provider} provider
   *      The {{#crossLink "ProAct.Registry.Provider"}}{{/crossLink}} to register.
   * @return {ProAct.Registers}
   *      this
   * @throws {Error}
   *      If a {{#crossLink "ProAct.Registry.Provider"}}{{/crossLink}} is already registered for the passed namespace.
   */
  register: function (namespace, provider) {
    if (this.providers[namespace]) {
      throw new Error(namespace + 'is already registered in this registry.');
    }
    this.providers[namespace] = provider;
    if (provider.registered) {
      provider.registered(this);
    }
    return this;
  },

  /**
   * Retrieves the right {{#crossLink "ProAct.Registry.Provider"}}{{/crossLink}} using the name of stored
   * in this ProAct.Registry object, or the name of an object to be stored
   *
   * @for ProAct.Registry
   * @instance
   * @method getProviderByName
   * @param {String} name
   *      The name of storable object.
   *

   *        It must be in the format '{namespace}:{key}'.
   *

   *

   *        Here the namespace is the namespace the {{#crossLink "ProAct.Registry.Provider"}}{{/crossLink}} manages.
   *

   * @return {Array}
   *      The first element in the result is the {{#crossLink "ProAct.Registry.Provider"}}{{/crossLink}} or undefined if not found.
   *

   *        The second one is the key at which an object is stored or will be stored in the provider.
   *

   *

   *        The third element is an array with options for storing/creating an object passed to the provider using
   *        the name string.
   *

   */
  getProviderByName: function (name) {
    var parts = name.split(':');

    return [this.providers[parts[0]], parts[1], parts.slice(2)];
  },

  /**
   * Configures an object to be stored using {{#crossLink "ProAct.DSL"}}{{/crossLink}} passed through options and DSL arguments.
   *

   *  Example usage:
   *

   *

   *  A {{#crossLink "ProAct.Stream"}}{{/crossLink}} is passed to the registry for setup with DSL data.
   *

   *

   *  The data passed through the options parameter is
   *

   *    '<<(s:foo)|map(-)|filter($1)'
   *

   *

   *

   *  And the arguments for the DSL machine passed through the args parameter are
   *

   *    [function (v) {
   *      return v % 2 === 0;
   *    }]
   *

   *

   *

   *  This means that a {{#crossLink "ProAct.Stream"}}{{/crossLink}} stored in this registry by the key 'foo' should be set
   *  as a source to the passed as the object parameter simple {{#crossLink "ProAct.Stream"}}{{/crossLink}}.
   *

   *

   *  It also means that for every value comming in the object parameter's stream there should be mapping of negativity and
   *  only even values should be passed to it.
   *

   *

   *  So if we trigger in the 'foo' stream the value of 4 in our stream we will get -4, and if we trigger 5, we won't get anything.
   *

   *
   * @for ProAct.Registry
   * @instance
   * @method setup
   * @param {Object} object
   *      The object to setup.
   * @param {String|Object} options
   *      A {{#crossLink "ProAct.DSL"}}{{/crossLink}} data object or string used to setup the object.
   * @param {Array} args
   *      Arguments to be used by the {{#crossLink "ProAct.DSL/run:method"}}{{/crossLink}} method while configuring the passed object.
   * @return {Object}
   *      Ready to strore object.
   */
  setup: function (object, options, args) {
    return dsl.run.apply(null, [object, options, this].concat(args));
  },

  /**
   * Creates a new object and stores it in this registry, using the right provider for the creation
   * and configuring it using the DSL passed through the options parameter.
   *

   *  {{#crossLink "ProAct.Registry/getProviderByName:method"}}{{/crossLink}} is used to locate the right provider to create the object with.
   *

   *

   *  {{#crossLink "ProAct.Registry/setup:method"}}{{/crossLink}} is used to setup the newly created object using the {{#crossLink "ProAct.DSL"}}{{/crossLink}}
   *

   *

   *  The idea of this method is to create and configure {{#crossLink "ProAct.Actor"}}{{/crossLink}} objects.
   *

   *
   * @for ProAct.Registry
   * @instance
   * @method make
   * @param {String} name
   *      Name of the object to create and store.
   *

   *        It must be in the format '{namespace}:{key}'
   *

   * @param {String|Object} options
   *      A {{#crossLink "ProAct.DSL"}}{{/crossLink}} data object or string used to setup the object to be created.
   * @param [...]
   *      Arguments to be used by the {{#crossLink "ProAct.DSL/run:method"}}{{/crossLink}} method while configuring the newly created object.
   * @return {Object}
   *      The newly created, stored and configured object, or null if there was no {{#crossLink "ProAct.Registry.Provider"}}{{/crossLink}} register for its type.
   */
  make: function (name, options) {
    var args = slice.call(arguments, 2),
        p = this.getProviderByName(name),
        actor;

    if (p[0]) {
      actor = p[0].make.apply(p[0], [p[1], p[2]].concat(args));
      return this.setup(actor, options, args);
    }
    return null;
  },

  /**
   * Stores an object  in this registry, using the right provider to configure it using the DSL passed through the options parameter.
   *

   *  {{#crossLink "ProAct.Registry/getProviderByName:method"}}{{/crossLink}} is used to locate the right provider to store the object to.
   *

   *
   * @for ProAct.Registry
   * @instance
   * @method store
   * @param {String} name
   *      Name of the object to store.
   *

   *        It must be in the format '{namespace}:{key}'
   *

   * @param {Object} object
   *      The object to store.
   * @param {String|Object} options
   *      A {{#crossLink "ProAct.DSL"}}{{/crossLink}} data object or string used to setup the object to be stored (optional).
   * @param [...]
   *      Arguments to be used by the {{#crossLink "ProAct.DSL/run:method"}}{{/crossLink}} method while configuring the object.
   * @return {Object}
   *      The stored and configured object, or null if there was no {{#crossLink "ProAct.Registry.Provider"}}{{/crossLink}} register for its type.
   */
  store: function (name, object, options) {
    var args = slice.call(arguments, 2),
        p = this.getProviderByName(name);

    if (p[0]) {
      return p[0].store.apply(p[0], [p[1], object, p[2]].concat(args));
    }
    return null;
  },

  /**
   * Retrieves an object, stored this registry.
   *

   *  {{#crossLink "ProAct.Registry/getProviderByName:method"}}{{/crossLink}} is used to locate the right provider to retrieve the object from.
   *

   *
   * @for ProAct.Registry
   * @instance
   * @method get
   * @param {String} name
   *      Name of the object to find.
   *

   *        It must be in the format '{namespace}:{key}'
   *

   * @return {Object}
   *      The stored object, or null if there was no {{#crossLink "ProAct.Registry.Provider"}}{{/crossLink}} register for its type or no object registered for the passed name.
   */
  get: function (name) {
    var p = this.getProviderByName(name);

    if (p[0]) {
      return p[0].get(p[1]);
    }
    return null;
  },

  /**
   * Helper method for transforming an array of keys of stored items in this `ProAct.Registry` to an array of the actual items.
   *

   *  Mainly used by the {{#crossLink "ProAct.DSL"}}{{/crossLink}} logic.
   *

   *
   * @for ProAct.Registry
   * @protected
   * @instance
   * @method toObjectArray
   * @param {Array} array
   *      Array of string keys to objects stored in this registry to be retrieved using {{#crossLink "ProAct.Registry/toObject:method"}}{{/crossLink}}.
   *

   *        If object is not stored on some key, the key itself is returned in the same possition in the result array.
   *

   * @return {Array}
   *      Of the retrieved objects, in the same order as the keys.
   */
  toObjectArray: function (array) {
    var self = this;
    if (!P.U.isArray(array)) {
      return this.toObject(array);
    }
    return map.call(array, function (el) {
      return self.toObject(el);
    });
  },

  /**
   * Helper method for transforming a key of stored item in this `ProAct.Registry` to the actual item or returning the key, if
   * the item is not found in the `ProAct.Registry`.
   *

   *  Mainly used by the {{#crossLink "ProAct.DSL"}}{{/crossLink}} logic.
   *

   *
   * @for ProAct.Registry
   * @protected
   * @instance
   * @method toObject
   * @param {String|Object} data
   *      Key of strored object or something else. If the key is valid and there is something stored on it, the stored object is retrieved.
   *

   *        If there is nothing stored for this data, the data itself is returned.
   *

   * @return {Object}
   *      Stored object, if found using the passed data or the data itself.
   */
  toObject: function (data) {
    if (P.U.isString(data)) {
      var result = this.get(data);
      return result ? result : data;
    }

    return data;
  }
};

P.U.ex(P.Actor.prototype, {

  /**
   * Adds a new transformation to the list of transformations
   * of this actor.
   *
   *

   *  A transformation is a function or an object that has a call method defined.
   *  This function or call method should have one argument and to return a transformed version of it.
   *  If the returned value is {{#crossLink "ProAct.Actor/BadValue:property"}}{{/crossLink}}, the next transformations are skipped and the updating
   *  value/event becomes - bad value.
   *

   *
   *

   *  Every value/event that updates this actor will be transformed using the new transformation.
   *

   *
   * This method uses {{#crossLink "ProAct.Actor/transform:method"}}{{/crossLink}}, but can read transformation
   * funtion/object stored in the registry (if the proact-dsl module is present) by it's string name.
   *
   * @for ProAct.Actor
   * @instance
   * @method transformStored
   * @protected
   * @param {Object|String} transformation The transformation to add. Can be string - to be retrieved by name.
   * @param {String} type The type of the transformation, for example `mapping`.
   * @return {ProAct.Actor}
   *      this
   */
  transformStored: function (transformation, type) {
    if (P.U.isString(transformation)) {
      P.DSL.run(this, type + '(' + transformation + ')', P.registry);
      return this;
    }

    return this.transform(transformation);
  }

});

P.U.ex(P.ObjectCore.prototype, {

  /**
   * Applies meta information and actions on already created property.
   *
   * This method is called by the {{#crossLink "ProAct.ObjectCore/makeProp:method"}}{{/crossLink}} one,
   * other modules can inject logic by overriding it.
   *
   * The meta is in format of the {{#crossLink "ProAct.DSL"}}{{/crossLink}}.
   *
   * @for ProAct.ObjectCore
   * @protected
   * @instance
   * @method applyMeta
   * @param {String|Array} meta
   *      Meta information for the property to modify with.
   * @param {ProAct.Property} property
   *      The property to update.
   */
  applyMeta: function (meta, property) {
    if (meta && P.registry) {
      if (!P.U.isArray(meta)) {
        meta = [meta];
      }

      if (!(meta[0] instanceof ProAct.Property)) {
        P.registry.setup.apply(P.registry, [property].concat(meta));
      }
    }
  }

});
<|endoftext|>


<commit_before>utils = {};
utils.datatables =  {};
utils.datatables.defaults = {
            "processing": true,
            "responsive": true,
            "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]],
            "language": {
                "paginate": {
                    "next": "Volgende",
                    "previous": "Vorige"
                }
            },
            "columnDefs": [ {
                "targets": [0],
                "visible": false,
                "searchable": false
            }],
};

utils.datatables.enable_select = function ($selector) {
    $selector.on( 'click', 'tr', function () {
        $(this).toggleClass('info');
    } );
};

utils.datatables.delete_by_url = function($selector, table, url) {
    $selector.click( function () {
        var selected_ids = [];
        var selected_users = "";
        var selected_rows = table.rows('.info');
        for (i = 0; i < selected_rows.data().length; i++) {
            selected_ids.push(selected_rows.data()[i][0]);
            selected_users += "- " + selected_rows.data()[i][1] + "\n";
        }
        var json_data = { "selected_ids" : selected_ids };
        if (confirm('Do you surely want to delete all these?\n' + selected_users )) {
            $.ajax({
                type: "DELETE",
                url: url,
                contentType: 'application/json',
                success: function (data) {
                    table.ajax.reload();
                },
                data: JSON.stringify(json_data, null, '\t'),
            });

        } else {
            return;
        }
    });
};
<commit_msg>Added a dynamic parameter for type.<commit_after>utils = {};
utils.datatables =  {};
utils.datatables.defaults = {
            "processing": true,
            "responsive": true,
            "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]],
            "language": {
                "paginate": {
                    "next": "Volgende",
                    "previous": "Vorige"
                }
            },
            "columnDefs": [ {
                "targets": [0],
                "visible": false,
                "searchable": false
            }],
};

utils.datatables.enable_select = function ($selector) {
    $selector.on( 'click', 'tr', function () {
        $(this).toggleClass('info');
    } );
};

utils.datatables.get_ids = function($selector, table) {
    var selected_ids = [];
    var selected_users = "";
    var selected_rows = table.rows('.info');
    for (i = 0; i < selected_rows.data().length; i++) {
        selected_ids.push(selected_rows.data()[i][0]);
        selected_users += "- " + selected_rows.data()[i][1] + "\n";
    }
    return { "selected_ids" : selected_ids };
}

utils.datatables.action_by_url = function(
    $selector, table, url, action, refer) {
    $selector.click(function () {
        var json_data = utils.datatables.get_ids($selector, table);
        if (confirm('Are you sure you want to ' + action + '?\n')) {
            $.ajax({
                type: action,
                url: url,
                contentType: 'application/json',
                success: function (data) {
                    if (action === "put") {
                        window.open(refer, "_top");
                    } else {
                        table.ajax.reload();
                    }
                },
                data: JSON.stringify(json_data, null, '\t'),
            });
        } else {
            return;
        }
    });
};
<|endoftext|>


<commit_before>
const livingState = () => {

  const states = {
    living: 0,
    dead: 1
  }

  let value = states.living;

  return {
    is_living: () => {
      return value === states.living;
    },

    is_dead: () => {
      return value === states.dead;
    },

    dead: () => {
      value = states.dead;
    }
  }

}

export default livingState;
<commit_msg>No need of living state<commit_after><|endoftext|>


<commit_before>var Menu = function(table){
	this.table = table; //hold Tabulator object
	this.menuEl = false;
	this.blurEvent = this.hideMenu.bind(this);
	this.escEvent = this.escMenu.bind(this);
	this.nestedMenuBlock = false;
};

Menu.prototype.initializeColumnHeader = function(column){
	var headerMenuEl;

	if(column.definition.headerContextMenu){
		column.getElement().addEventListener("contextmenu", this.LoadMenuEvent.bind(this, column, column.definition.headerContextMenu));
		this.tapHold(column, column.definition.headerContextMenu);
	}

	// if(column.definition.headerClickMenu){
	// 	column.getElement().addEventListener("click", this.LoadMenuEvent.bind(this, column, column.definition.headerClickMenu));
	// }

	if(column.definition.headerMenu){

		headerMenuEl = document.createElement("span");
		headerMenuEl.classList.add("tabulator-header-menu-button");
		headerMenuEl.innerHTML = "⋮";

		headerMenuEl.addEventListener("click", (e) => {
			var menu = typeof column.definition.headerMenu == "function" ? column.definition.headerMenu(column.getComponent()) : column.definition.headerMenu;
			e.stopPropagation();
			e.preventDefault();

			this.loadMenu(e, column, menu);
		});

		column.titleElement.insertBefore(headerMenuEl, column.titleElement.firstChild);
	}
};

Menu.prototype.LoadMenuEvent = function(component, menu, e){
	menu = typeof menu == "function" ? menu(component.getComponent(), e) : menu;

	// if(component instanceof Cell){
	// 	e.stopImmediatePropagation();
	// }

	this.loadMenu(e, component, menu);
};

Menu.prototype.tapHold = function(component, menu){
	var element = component.getElement(),
	tapHold = null,
	loaded = false;

	element.addEventListener("touchstart", (e) => {
		clearTimeout(tapHold);
		loaded = false;

		tapHold = setTimeout(() => {
			clearTimeout(tapHold);
			tapHold = null;
			loaded = true;

			this.LoadMenuEvent(component, menu, e);
		}, 1000);

	}, {passive: true});

	element.addEventListener("touchend", (e) => {
		clearTimeout(tapHold);
		tapHold = null;

		if(loaded){
			e.preventDefault();
		}
	});
};

Menu.prototype.initializeCell = function(cell){
	if(cell.column.definition.contextMenu){
		cell.getElement().addEventListener("contextmenu", this.LoadMenuEvent.bind(this, cell, cell.column.definition.contextMenu));
		this.tapHold(cell, cell.column.definition.contextMenu);
	}

	if(cell.column.definition.clickMenu){
		cell.getElement().addEventListener("click", this.LoadMenuEvent.bind(this, cell, cell.column.definition.clickMenu));
	}
};

Menu.prototype.initializeRow = function(row){
	if(this.table.options.rowContextMenu){
		row.getElement().addEventListener("contextmenu", this.LoadMenuEvent.bind(this, row, this.table.options.rowContextMenu));
		this.tapHold(row, this.table.options.rowContextMenu);
	}

	if(this.table.options.rowClickMenu){
		row.getElement().addEventListener("click", this.LoadMenuEvent.bind(this, row, this.table.options.rowClickMenu));
	}
};

Menu.prototype.initializeGroup = function (group){
	if(this.table.options.groupContextMenu){
		group.getElement().addEventListener("contextmenu", this.LoadMenuEvent.bind(this, group, this.table.options.groupContextMenu));
		this.tapHold(group, this.table.options.groupContextMenu);
	}

	if(this.table.options.groupClickMenu){
		group.getElement().addEventListener("click", this.LoadMenuEvent.bind(this, group, this.table.options.groupClickMenu));
	}
};

Menu.prototype.loadMenu = function(e, component, menu){

	var docHeight = Math.max(document.body.offsetHeight, window.innerHeight),
	touch = !(e instanceof MouseEvent);

	if(!touch){
		e.preventDefault();
	}

	//abort if no menu set
	if(!menu || !menu.length){
		return;
	}

	if(this.nestedMenuBlock){
		//abort if child menu already open
		if(this.isOpen()){
			return;
		}
	}else{
		this.nestedMenuBlock = setTimeout(() => {
			this.nestedMenuBlock = false;
		}, 100)
	}

	this.hideMenu();

	this.menuEl = document.createElement("div");
	this.menuEl.classList.add("tabulator-menu");

	menu.forEach((item) => {
		var itemEl = document.createElement("div");
		var label = item.label
		var disabled = item.disabled;

		if(item.separator){
			itemEl.classList.add("tabulator-menu-separator");
		}else{
			itemEl.classList.add("tabulator-menu-item");

			if(typeof label == "function"){
				label = label(component.getComponent());
			}

			if(label instanceof Node){
				itemEl.appendChild(label);
			}else{
				itemEl.innerHTML = label;
			}

			if(typeof disabled == "function"){
				disabled = disabled(component.getComponent());
			}

			if(disabled){
				itemEl.classList.add("tabulator-menu-item-disabled");
				itemEl.addEventListener("click", (e) => {
					e.stopPropagation();
				});
			}else{
				itemEl.addEventListener("click", (e) => {
					this.hideMenu();
					item.action(e, component.getComponent());
				});
			}
		}

		this.menuEl.appendChild(itemEl);
	});

	this.menuEl.style.top = (touch ? e.touches[0].pageY : e.pageY) + "px";
	this.menuEl.style.left = (touch ? e.touches[0].pageX : e.pageX) + "px";

	setTimeout(() => {
		this.table.rowManager.element.addEventListener("scroll", this.blurEvent);
		document.body.addEventListener("click", this.blurEvent);
		document.body.addEventListener("contextmenu", this.blurEvent);
		document.body.addEventListener("keydown", this.escEvent);
	}, 100);

	document.body.appendChild(this.menuEl);

	//move menu to start on right edge if it is too close to the edge of the screen
	if((e.pageX + this.menuEl.offsetWidth) >= document.body.offsetWidth){
		this.menuEl.style.left = "";
		this.menuEl.style.right = (document.body.offsetWidth - e.pageX) + "px";
	}

	//move menu to start on bottom edge if it is too close to the edge of the screen
	if((e.pageY + this.menuEl.offsetHeight) >= docHeight){
		this.menuEl.style.top = "";
		this.menuEl.style.bottom = (docHeight - e.pageY) + "px";
	}
};

Menu.prototype.isOpen = function(){
	return !!this.menuEl.parentNode;
};

Menu.prototype.escMenu = function(e){
	if(e.keyCode == 27){
		this.hideMenu();
	}
};

Menu.prototype.hideMenu = function(){
	if(this.menuEl.parentNode){
		this.menuEl.parentNode.removeChild(this.menuEl);
	}

	if(this.escEvent){
		document.body.removeEventListener("keydown", this.escEvent);
	}

	if(this.blurEvent){
		document.body.removeEventListener("click", this.blurEvent);
		document.body.removeEventListener("contextmenu", this.blurEvent);
		this.table.rowManager.element.removeEventListener("scroll", this.blurEvent);
	}
};

//default accessors
Menu.prototype.menus = {};

Tabulator.prototype.registerModule("menu", Menu);<commit_msg>pass click event to header menu generator function<commit_after>var Menu = function(table){
	this.table = table; //hold Tabulator object
	this.menuEl = false;
	this.blurEvent = this.hideMenu.bind(this);
	this.escEvent = this.escMenu.bind(this);
	this.nestedMenuBlock = false;
};

Menu.prototype.initializeColumnHeader = function(column){
	var headerMenuEl;

	if(column.definition.headerContextMenu){
		column.getElement().addEventListener("contextmenu", this.LoadMenuEvent.bind(this, column, column.definition.headerContextMenu));
		this.tapHold(column, column.definition.headerContextMenu);
	}

	// if(column.definition.headerClickMenu){
	// 	column.getElement().addEventListener("click", this.LoadMenuEvent.bind(this, column, column.definition.headerClickMenu));
	// }

	if(column.definition.headerMenu){

		headerMenuEl = document.createElement("span");
		headerMenuEl.classList.add("tabulator-header-menu-button");
		headerMenuEl.innerHTML = "⋮";

		headerMenuEl.addEventListener("click", (e) => {
			var menu = typeof column.definition.headerMenu == "function" ? column.definition.headerMenu(column.getComponent(), e) : column.definition.headerMenu;
			e.stopPropagation();
			e.preventDefault();

			this.loadMenu(e, column, menu);
		});

		column.titleElement.insertBefore(headerMenuEl, column.titleElement.firstChild);
	}
};

Menu.prototype.LoadMenuEvent = function(component, menu, e){
	menu = typeof menu == "function" ? menu(component.getComponent(), e) : menu;

	// if(component instanceof Cell){
	// 	e.stopImmediatePropagation();
	// }

	this.loadMenu(e, component, menu);
};

Menu.prototype.tapHold = function(component, menu){
	var element = component.getElement(),
	tapHold = null,
	loaded = false;

	element.addEventListener("touchstart", (e) => {
		clearTimeout(tapHold);
		loaded = false;

		tapHold = setTimeout(() => {
			clearTimeout(tapHold);
			tapHold = null;
			loaded = true;

			this.LoadMenuEvent(component, menu, e);
		}, 1000);

	}, {passive: true});

	element.addEventListener("touchend", (e) => {
		clearTimeout(tapHold);
		tapHold = null;

		if(loaded){
			e.preventDefault();
		}
	});
};

Menu.prototype.initializeCell = function(cell){
	if(cell.column.definition.contextMenu){
		cell.getElement().addEventListener("contextmenu", this.LoadMenuEvent.bind(this, cell, cell.column.definition.contextMenu));
		this.tapHold(cell, cell.column.definition.contextMenu);
	}

	if(cell.column.definition.clickMenu){
		cell.getElement().addEventListener("click", this.LoadMenuEvent.bind(this, cell, cell.column.definition.clickMenu));
	}
};

Menu.prototype.initializeRow = function(row){
	if(this.table.options.rowContextMenu){
		row.getElement().addEventListener("contextmenu", this.LoadMenuEvent.bind(this, row, this.table.options.rowContextMenu));
		this.tapHold(row, this.table.options.rowContextMenu);
	}

	if(this.table.options.rowClickMenu){
		row.getElement().addEventListener("click", this.LoadMenuEvent.bind(this, row, this.table.options.rowClickMenu));
	}
};

Menu.prototype.initializeGroup = function (group){
	if(this.table.options.groupContextMenu){
		group.getElement().addEventListener("contextmenu", this.LoadMenuEvent.bind(this, group, this.table.options.groupContextMenu));
		this.tapHold(group, this.table.options.groupContextMenu);
	}

	if(this.table.options.groupClickMenu){
		group.getElement().addEventListener("click", this.LoadMenuEvent.bind(this, group, this.table.options.groupClickMenu));
	}
};

Menu.prototype.loadMenu = function(e, component, menu){

	var docHeight = Math.max(document.body.offsetHeight, window.innerHeight),
	touch = !(e instanceof MouseEvent);

	if(!touch){
		e.preventDefault();
	}

	//abort if no menu set
	if(!menu || !menu.length){
		return;
	}

	if(this.nestedMenuBlock){
		//abort if child menu already open
		if(this.isOpen()){
			return;
		}
	}else{
		this.nestedMenuBlock = setTimeout(() => {
			this.nestedMenuBlock = false;
		}, 100)
	}

	this.hideMenu();

	this.menuEl = document.createElement("div");
	this.menuEl.classList.add("tabulator-menu");

	menu.forEach((item) => {
		var itemEl = document.createElement("div");
		var label = item.label
		var disabled = item.disabled;

		if(item.separator){
			itemEl.classList.add("tabulator-menu-separator");
		}else{
			itemEl.classList.add("tabulator-menu-item");

			if(typeof label == "function"){
				label = label(component.getComponent());
			}

			if(label instanceof Node){
				itemEl.appendChild(label);
			}else{
				itemEl.innerHTML = label;
			}

			if(typeof disabled == "function"){
				disabled = disabled(component.getComponent());
			}

			if(disabled){
				itemEl.classList.add("tabulator-menu-item-disabled");
				itemEl.addEventListener("click", (e) => {
					e.stopPropagation();
				});
			}else{
				itemEl.addEventListener("click", (e) => {
					this.hideMenu();
					item.action(e, component.getComponent());
				});
			}
		}

		this.menuEl.appendChild(itemEl);
	});

	this.menuEl.style.top = (touch ? e.touches[0].pageY : e.pageY) + "px";
	this.menuEl.style.left = (touch ? e.touches[0].pageX : e.pageX) + "px";

	setTimeout(() => {
		this.table.rowManager.element.addEventListener("scroll", this.blurEvent);
		document.body.addEventListener("click", this.blurEvent);
		document.body.addEventListener("contextmenu", this.blurEvent);
		document.body.addEventListener("keydown", this.escEvent);
	}, 100);

	document.body.appendChild(this.menuEl);

	//move menu to start on right edge if it is too close to the edge of the screen
	if((e.pageX + this.menuEl.offsetWidth) >= document.body.offsetWidth){
		this.menuEl.style.left = "";
		this.menuEl.style.right = (document.body.offsetWidth - e.pageX) + "px";
	}

	//move menu to start on bottom edge if it is too close to the edge of the screen
	if((e.pageY + this.menuEl.offsetHeight) >= docHeight){
		this.menuEl.style.top = "";
		this.menuEl.style.bottom = (docHeight - e.pageY) + "px";
	}
};

Menu.prototype.isOpen = function(){
	return !!this.menuEl.parentNode;
};

Menu.prototype.escMenu = function(e){
	if(e.keyCode == 27){
		this.hideMenu();
	}
};

Menu.prototype.hideMenu = function(){
	if(this.menuEl.parentNode){
		this.menuEl.parentNode.removeChild(this.menuEl);
	}

	if(this.escEvent){
		document.body.removeEventListener("keydown", this.escEvent);
	}

	if(this.blurEvent){
		document.body.removeEventListener("click", this.blurEvent);
		document.body.removeEventListener("contextmenu", this.blurEvent);
		this.table.rowManager.element.removeEventListener("scroll", this.blurEvent);
	}
};

//default accessors
Menu.prototype.menus = {};

Tabulator.prototype.registerModule("menu", Menu);<|endoftext|>


<commit_before>
import React, { Component } from 'react';
import { observer, inject } from 'mobx-react';
import { ipcRenderer } from 'electron';

import Loader from 'components/Loader';
import Snackbar from 'components/Snackbar';
import Header from './Header';
import Footer from './Footer';
import Login from './Login';
import UserInfo from './UserInfo';
import AddFriend from './AddFriend';
import NewChat from './NewChat';
import Members from './Members';
import AddMember from './AddMember';
import Forward from './Forward';

@inject(stores => ({
    isLogin: () => !!stores.session.auth,
    loading: stores.session.loading,

    message: stores.snackbar.text,
    show: stores.snackbar.show,
    close: () => stores.snackbar.toggle(false),
}))
@observer
export default class Layout extends Component {
    render() {
        if (!this.props.isLogin()) {
            return <Login />;
        }

        ipcRenderer.send('logined');

        return (

                <Snackbar
                    close={this.props.close}
                    show={this.props.show}
                    text={this.props.message} />

                <Loader show={this.props.loading} />

                <div style={{
                    height: 'calc(100vh - 100px)',
                    overflow: 'hidden',
                    overflowY: 'auto',
                    background: `rgba(255,255,255,.8)`,
                }}>
                    {this.props.children}

                <UserInfo />
                <AddFriend />
                <NewChat />
                <Members />
                <AddMember />
                <Forward />

        );
    }
}
<commit_msg>add contextmenu on input field<commit_after>
import React, { Component } from 'react';
import { observer, inject } from 'mobx-react';
import { ipcRenderer, remote } from 'electron';

import Loader from 'components/Loader';
import Snackbar from 'components/Snackbar';
import Header from './Header';
import Footer from './Footer';
import Login from './Login';
import UserInfo from './UserInfo';
import AddFriend from './AddFriend';
import NewChat from './NewChat';
import Members from './Members';
import AddMember from './AddMember';
import Forward from './Forward';

@inject(stores => ({
    isLogin: () => !!stores.session.auth,
    loading: stores.session.loading,

    message: stores.snackbar.text,
    show: stores.snackbar.show,
    close: () => stores.snackbar.toggle(false),
}))
@observer
export default class Layout extends Component {
    componentDidMount() {
        var templates = [
            {
                label: 'Undo',
                role: 'undo',
            }, {
                label: 'Redo',
                role: 'redo',
            }, {
                type: 'separator',
            }, {
                label: 'Cut',
                role: 'cut',
            }, {
                label: 'Copy',
                role: 'copy',
            }, {
                label: 'Paste',
                role: 'paste',
            }, {
                type: 'separator',
            }, {
                label: 'Select all',
                role: 'selectall',
            },
        ];
        var menu = new remote.Menu.buildFromTemplate(templates);

        document.body.addEventListener('contextmenu', e => {
            e.preventDefault();

            let node = e.target;

            while (node) {
                if (node.nodeName.match(/^(input|textarea)$/i) || node.isContentEditable) {
                    menu.popup(remote.getCurrentWindow());
                    break;
                }
                node = node.parentNode;
            }
        });
    }

    render() {
        if (!this.props.isLogin()) {
            return <Login />;
        }

        ipcRenderer.send('logined');

        return (

                <Snackbar
                    close={this.props.close}
                    show={this.props.show}
                    text={this.props.message} />

                <Loader show={this.props.loading} />

                <div style={{
                    height: 'calc(100vh - 100px)',
                    overflow: 'hidden',
                    overflowY: 'auto',
                    background: `rgba(255,255,255,.8)`,
                }}>
                    {this.props.children}

                <UserInfo />
                <AddFriend />
                <NewChat />
                <Members />
                <AddMember />
                <Forward />

        );
    }
}
<|endoftext|>