<commit_before>/**
 * You can customize the initial state of the module from the editor initialization, by passing the following [Configuration Object](https://github.com/artf/grapesjs/blob/master/src/asset_manager/config/config.js)
 * ```js
 * const editor = grapesjs.init({
 *  assetManager: {
 *    // options
 *  }
 * })
 * ```
 *
 * Once the editor is instantiated you can use its API. Before using these methods you should get the module from the instance
 *
 * ```js
 * const assetManager = editor.AssetManager;
 * ```
 * ## Available Events
 * * `asset:add` - Added new asset. The [Asset] is passed as an argument to the callback.
 * * `asset:remove` - Asset removed. The [Asset] is passed as an argument to the callback.
 * * `asset:update` - Asset updated. The updated [Asset] and the object containing changes are passed as arguments to the callback.
 * * `asset:upload:start` - Before the upload is started.
 * * `asset:upload:end` - After the upload is ended.
 * * `asset:upload:error` - On any error in upload, passes the error as an argument.
 * * `asset:upload:response` - On upload response, passes the result as an argument.
 * * `asset` - Catch-all event for all the events mentioned above. An object containing all the available data about the triggered event is passed as an argument to the callback.
 *
 * ## Methods
 * * [add](#add)
 * * [get](#get)
 * * [getAll](#getall)
 * * [getAllVisible](#getallvisible)
 * * [remove](#remove)
 * * [store](#store)
 * * [load](#load)
 * * [getContainer](#getcontainer)
 * * [getAssetsEl](#getassetsel)
 * * [addType](#addtype)
 * * [getType](#gettype)
 * * [getTypes](#gettypes)
 *
 * [Asset]: asset.html
 *
 * @module AssetManager
 */

import Module from 'common/module';
import defaults from './config/config';
import Asset from './model/Assets';
import Assets from './model/Assets';
import AssetsView from './view/AssetsView';
import FileUpload from './view/FileUploader';

export const evAll = 'asset';
export const evPfx = `${evAll}:`;
export const evSelect = `${evPfx}select`;
export const evUpdate = `${evPfx}update`;
export const evAdd = `${evPfx}add`;
export const evRemove = `${evPfx}remove`;
export const evRemoveBefore = `${evRemove}:before`;

export default () => {
  let c = {};
  let assets, assetsVis, am, fu;

  return {
    ...Module,

    name: 'AssetManager',

    storageKey: 'assets',

    Asset,

    Assets,

    events: {
      all: evAll,
      select: evSelect,
      update: evUpdate,
      add: evAdd,
      remove: evRemove,
      removeBefore: evRemoveBefore
    },

    /**
     * Initialize module
     * @param {Object} config Configurations
     * @private
     */
    init(config = {}) {
      c = { ...defaults, ...config };
      const ppfx = c.pStylePrefix;
      const { em } = c;
      this.config = c;
      this.em = em;

      if (ppfx) {
        c.stylePrefix = ppfx + c.stylePrefix;
      }

      // Global assets collection
      assets = new Assets([]);
      assetsVis = new Assets([]);
      this.all = assets;
      this.__initListen();

      // Setup the sync between the global and public collections
      assets.on('add', model => this.getAllVisible().add(model));
      assets.on('remove', model => this.getAllVisible().remove(model));

      return this;
    },

    __propEv(ev, ...data) {
      this.em.trigger(ev, ...data);
      this.getAll().trigger(ev, ...data);
    },

    /**
     * Add new asset/s to the collection. URLs are supposed to be unique
     * @param {String|Object|Array<String>|Array<Object>} asset URL strings or an objects representing the resource.
     * @param {Object} [opts] Options
     * @returns {[Asset]}
     * @example
     * // As strings
     * assetManager.add('http://img.jpg');
     * assetManager.add(['http://img.jpg', './path/to/img.png']);
     *
     * // Using objects you can indicate the type and other meta informations
     * assetManager.add({
     *  // type: 'image',	// image is default
     * 	src: 'http://img.jpg',
     * 	height: 300,
     *	width: 200,
     * });
     * assetManager.add([{ src: 'img2.jpg' }, { src: 'img2.png' }]);
     */
    add(asset, opts = {}) {
      // Put the model at the beginning
      if (typeof opts.at == 'undefined') {
        opts.at = 0;
      }

      return assets.add(asset, opts);
    },

    /**
     * Return asset by URL
     * @param  {String} src URL of the asset
     * @returns {[Asset]|null} Object representing the asset
     * @example
     * const asset = assetManager.get('http://img.jpg');
     */
    get(src) {
      return assets.where({ src })[0] || null;
    },

    /**
     * Return the global collection, containing all the assets
     * @returns {Collection<[Asset]>}
     */
    getAll() {
      return assets;
    },

    /**
     * Return the visible collection, which contains assets actually rendered
     * @returns {Collection<[Asset]>}
     */
    getAllVisible() {
      return assetsVis;
    },

    /**
     * Remove asset
     * @param {String|[Asset]} asset Asset or asset URL
     * @returns {[Asset]} Removed asset
     * @example
     * const removed = assetManager.remove('http://img.jpg');
     * // or by passing the Asset
     * const asset = assetManager.get('http://img.jpg');
     * assetManager.remove(asset);
     */
    remove(asset) {
      return this.__remove(asset, opts);
    },

    /**
     * Store assets data to the selected storage
     * @param {Boolean} noStore If true, won't store
     * @returns {Object} Data to store
     * @example
     * var assets = assetManager.store();
     */
    store(noStore) {
      const obj = {};
      const assets = JSON.stringify(this.getAll().toJSON());
      obj[this.storageKey] = assets;
      if (!noStore && c.stm) c.stm.store(obj);
      return obj;
    },

    /**
     * Load data from the passed object.
     * The fetched data will be added to the collection.
     * @param {Object} data Object of data to load
     * @returns {Object} Loaded assets
     * @example
     * var assets = assetManager.load({
     * 	assets: [...]
     * })
     *
     */
    load(data = {}) {
      const name = this.storageKey;
      let assets = data[name] || [];

      if (typeof assets == 'string') {
        try {
          assets = JSON.parse(data[name]);
        } catch (err) {}
      }

      if (assets && assets.length) {
        this.getAll().reset(assets);
      }

      return assets;
    },

    /**
     * Return the Asset Manager Container
     * @returns {HTMLElement}
     */
    getContainer() {
      return am.el;
    },

    /**
     *  Get assets element container
     * @returns {HTMLElement}
     */
    getAssetsEl() {
      return am.el.querySelector('[data-el=assets]');
    },

    /**
     * Render assets
     * @param  {array} assets Assets to render, without the argument will render all global assets
     * @returns {HTMLElement}
     * @example
     * // Render all assets
     * assetManager.render();
     *
     * // Render some of the assets
     * const assets = assetManager.getAll();
     * assetManager.render(assets.filter(
     *  asset => asset.get('category') == 'cats'
     * ));
     */
    render(assts) {
      const toRender = assts || this.getAll().models;

      if (!am) {
        const obj = {
          collection: assetsVis, // Collection visible in asset manager
          globalCollection: assets,
          config: c,
          module: this
        };
        fu = new FileUpload(obj);
        obj.fu = fu;
        const el = am && am.el;
        am = new AssetsView({
          el,
          ...obj
        });
        am.render();
      }

      assetsVis.reset(toRender);
      return this.getContainer();
    },

    /**
     * Add new type. If you want to get more about type definition we suggest to read the [module's page](/modules/Assets.html)
     * @param {string} id Type ID
     * @param {Object} definition Definition of the type. Each definition contains
     *                            `model` (business logic), `view` (presentation logic)
     *                            and `isType` function which recognize the type of the
     *                            passed entity
     * @example
     * assetManager.addType('my-type', {
     *  model: {},
     *  view: {},
     *  isType: (value) => {},
     * })
     */
    addType(id, definition) {
      this.getAll().addType(id, definition);
    },

    /**
     * Get type
     * @param {string} id Type ID
     * @returns {Object} Type definition
     */
    getType(id) {
      return this.getAll().getType(id);
    },

    /**
     * Get types
     * @returns {Array}
     */
    getTypes() {
      return this.getAll().getTypes();
    },

    //-------

    AssetsView() {
      return am;
    },

    FileUploader() {
      return fu;
    },

    onLoad() {
      this.getAll().reset(c.assets);
    },

    postRender(editorView) {
      c.dropzone && fu && fu.initDropzone(editorView);
    },

    /**
     * Set new target
     * @param	{Object}	m Model
     * @private
     * */
    setTarget(m) {
      assetsVis.target = m;
    },

    /**
     * Set callback after asset was selected
     * @param	{Object}	f Callback function
     * @private
     * */
    onSelect(f) {
      assetsVis.onSelect = f;
    },

    /**
     * Set callback to fire when the asset is clicked
     * @param {function} func
     * @private
     */
    onClick(func) {
      c.onClick = func;
    },

    /**
     * Set callback to fire when the asset is double clicked
     * @param {function} func
     * @private
     */
    onDblClick(func) {
      c.onDblClick = func;
    },

    destroy() {
      assets.stopListening();
      assetsVis.stopListening();
      assets.reset();
      assetsVis.reset();
      fu && fu.remove();
      am && am.remove();
      [assets, am, fu].forEach(i => (i = null));
      c = {};
    }
  };
};
<commit_msg>Fix asset remove<commit_after>/**
 * You can customize the initial state of the module from the editor initialization, by passing the following [Configuration Object](https://github.com/artf/grapesjs/blob/master/src/asset_manager/config/config.js)
 * ```js
 * const editor = grapesjs.init({
 *  assetManager: {
 *    // options
 *  }
 * })
 * ```
 *
 * Once the editor is instantiated you can use its API. Before using these methods you should get the module from the instance
 *
 * ```js
 * const assetManager = editor.AssetManager;
 * ```
 * ## Available Events
 * * `asset:add` - Added new asset. The [Asset] is passed as an argument to the callback.
 * * `asset:remove` - Asset removed. The [Asset] is passed as an argument to the callback.
 * * `asset:update` - Asset updated. The updated [Asset] and the object containing changes are passed as arguments to the callback.
 * * `asset:upload:start` - Before the upload is started.
 * * `asset:upload:end` - After the upload is ended.
 * * `asset:upload:error` - On any error in upload, passes the error as an argument.
 * * `asset:upload:response` - On upload response, passes the result as an argument.
 * * `asset` - Catch-all event for all the events mentioned above. An object containing all the available data about the triggered event is passed as an argument to the callback.
 *
 * ## Methods
 * * [add](#add)
 * * [get](#get)
 * * [getAll](#getall)
 * * [getAllVisible](#getallvisible)
 * * [remove](#remove)
 * * [store](#store)
 * * [load](#load)
 * * [getContainer](#getcontainer)
 * * [getAssetsEl](#getassetsel)
 * * [addType](#addtype)
 * * [getType](#gettype)
 * * [getTypes](#gettypes)
 *
 * [Asset]: asset.html
 *
 * @module AssetManager
 */

import Module from 'common/module';
import defaults from './config/config';
import Asset from './model/Assets';
import Assets from './model/Assets';
import AssetsView from './view/AssetsView';
import FileUpload from './view/FileUploader';

export const evAll = 'asset';
export const evPfx = `${evAll}:`;
export const evSelect = `${evPfx}select`;
export const evUpdate = `${evPfx}update`;
export const evAdd = `${evPfx}add`;
export const evRemove = `${evPfx}remove`;
export const evRemoveBefore = `${evRemove}:before`;

export default () => {
  let c = {};
  let assets, assetsVis, am, fu;

  return {
    ...Module,

    name: 'AssetManager',

    storageKey: 'assets',

    Asset,

    Assets,

    events: {
      all: evAll,
      select: evSelect,
      update: evUpdate,
      add: evAdd,
      remove: evRemove,
      removeBefore: evRemoveBefore
    },

    /**
     * Initialize module
     * @param {Object} config Configurations
     * @private
     */
    init(config = {}) {
      c = { ...defaults, ...config };
      const ppfx = c.pStylePrefix;
      const { em } = c;
      this.config = c;
      this.em = em;

      if (ppfx) {
        c.stylePrefix = ppfx + c.stylePrefix;
      }

      // Global assets collection
      assets = new Assets([]);
      assetsVis = new Assets([]);
      this.all = assets;
      this.__initListen();

      // Setup the sync between the global and public collections
      assets.on('add', model => this.getAllVisible().add(model));
      assets.on('remove', model => this.getAllVisible().remove(model));

      return this;
    },

    __propEv(ev, ...data) {
      this.em.trigger(ev, ...data);
      this.getAll().trigger(ev, ...data);
    },

    /**
     * Add new asset/s to the collection. URLs are supposed to be unique
     * @param {String|Object|Array<String>|Array<Object>} asset URL strings or an objects representing the resource.
     * @param {Object} [opts] Options
     * @returns {[Asset]}
     * @example
     * // As strings
     * assetManager.add('http://img.jpg');
     * assetManager.add(['http://img.jpg', './path/to/img.png']);
     *
     * // Using objects you can indicate the type and other meta informations
     * assetManager.add({
     *  // type: 'image',	// image is default
     * 	src: 'http://img.jpg',
     * 	height: 300,
     *	width: 200,
     * });
     * assetManager.add([{ src: 'img2.jpg' }, { src: 'img2.png' }]);
     */
    add(asset, opts = {}) {
      // Put the model at the beginning
      if (typeof opts.at == 'undefined') {
        opts.at = 0;
      }

      return assets.add(asset, opts);
    },

    /**
     * Return asset by URL
     * @param  {String} src URL of the asset
     * @returns {[Asset]|null} Object representing the asset
     * @example
     * const asset = assetManager.get('http://img.jpg');
     */
    get(src) {
      return assets.where({ src })[0] || null;
    },

    /**
     * Return the global collection, containing all the assets
     * @returns {Collection<[Asset]>}
     */
    getAll() {
      return assets;
    },

    /**
     * Return the visible collection, which contains assets actually rendered
     * @returns {Collection<[Asset]>}
     */
    getAllVisible() {
      return assetsVis;
    },

    /**
     * Remove asset
     * @param {String|[Asset]} asset Asset or asset URL
     * @returns {[Asset]} Removed asset
     * @example
     * const removed = assetManager.remove('http://img.jpg');
     * // or by passing the Asset
     * const asset = assetManager.get('http://img.jpg');
     * assetManager.remove(asset);
     */
    remove(asset, opts) {
      return this.__remove(asset, opts);
    },

    /**
     * Store assets data to the selected storage
     * @param {Boolean} noStore If true, won't store
     * @returns {Object} Data to store
     * @example
     * var assets = assetManager.store();
     */
    store(noStore) {
      const obj = {};
      const assets = JSON.stringify(this.getAll().toJSON());
      obj[this.storageKey] = assets;
      if (!noStore && c.stm) c.stm.store(obj);
      return obj;
    },

    /**
     * Load data from the passed object.
     * The fetched data will be added to the collection.
     * @param {Object} data Object of data to load
     * @returns {Object} Loaded assets
     * @example
     * var assets = assetManager.load({
     * 	assets: [...]
     * })
     *
     */
    load(data = {}) {
      const name = this.storageKey;
      let assets = data[name] || [];

      if (typeof assets == 'string') {
        try {
          assets = JSON.parse(data[name]);
        } catch (err) {}
      }

      if (assets && assets.length) {
        this.getAll().reset(assets);
      }

      return assets;
    },

    /**
     * Return the Asset Manager Container
     * @returns {HTMLElement}
     */
    getContainer() {
      return am.el;
    },

    /**
     *  Get assets element container
     * @returns {HTMLElement}
     */
    getAssetsEl() {
      return am.el.querySelector('[data-el=assets]');
    },

    /**
     * Render assets
     * @param  {array} assets Assets to render, without the argument will render all global assets
     * @returns {HTMLElement}
     * @example
     * // Render all assets
     * assetManager.render();
     *
     * // Render some of the assets
     * const assets = assetManager.getAll();
     * assetManager.render(assets.filter(
     *  asset => asset.get('category') == 'cats'
     * ));
     */
    render(assts) {
      const toRender = assts || this.getAll().models;

      if (!am) {
        const obj = {
          collection: assetsVis, // Collection visible in asset manager
          globalCollection: assets,
          config: c,
          module: this
        };
        fu = new FileUpload(obj);
        obj.fu = fu;
        const el = am && am.el;
        am = new AssetsView({
          el,
          ...obj
        });
        am.render();
      }

      assetsVis.reset(toRender);
      return this.getContainer();
    },

    /**
     * Add new type. If you want to get more about type definition we suggest to read the [module's page](/modules/Assets.html)
     * @param {string} id Type ID
     * @param {Object} definition Definition of the type. Each definition contains
     *                            `model` (business logic), `view` (presentation logic)
     *                            and `isType` function which recognize the type of the
     *                            passed entity
     * @example
     * assetManager.addType('my-type', {
     *  model: {},
     *  view: {},
     *  isType: (value) => {},
     * })
     */
    addType(id, definition) {
      this.getAll().addType(id, definition);
    },

    /**
     * Get type
     * @param {string} id Type ID
     * @returns {Object} Type definition
     */
    getType(id) {
      return this.getAll().getType(id);
    },

    /**
     * Get types
     * @returns {Array}
     */
    getTypes() {
      return this.getAll().getTypes();
    },

    //-------

    AssetsView() {
      return am;
    },

    FileUploader() {
      return fu;
    },

    onLoad() {
      this.getAll().reset(c.assets);
    },

    postRender(editorView) {
      c.dropzone && fu && fu.initDropzone(editorView);
    },

    /**
     * Set new target
     * @param	{Object}	m Model
     * @private
     * */
    setTarget(m) {
      assetsVis.target = m;
    },

    /**
     * Set callback after asset was selected
     * @param	{Object}	f Callback function
     * @private
     * */
    onSelect(f) {
      assetsVis.onSelect = f;
    },

    /**
     * Set callback to fire when the asset is clicked
     * @param {function} func
     * @private
     */
    onClick(func) {
      c.onClick = func;
    },

    /**
     * Set callback to fire when the asset is double clicked
     * @param {function} func
     * @private
     */
    onDblClick(func) {
      c.onDblClick = func;
    },

    destroy() {
      assets.stopListening();
      assetsVis.stopListening();
      assets.reset();
      assetsVis.reset();
      fu && fu.remove();
      am && am.remove();
      [assets, am, fu].forEach(i => (i = null));
      c = {};
    }
  };
};
<|endoftext|>


<commit_before>define('app/controllers/machines', ['app/models/machine'],
    /**
     *  Machines Controller
     *
     *  @returns Class
     */
    function(Machine) {
        return Ember.ArrayController.extend(Ember.Evented, {

            /**
             *  Properties
             */

            content: [],
            loading: null,
            backend: null,
            failCounter: null,
            addingMachine: null,
            startingMachine: null,
            rebootingMachine: null,
            destroyingMachine: null,
            shutingdownMachine: null,

            /* Let's disable sorting for now
            sortAscending: true,
            sortProperties: ['hasMonitoring', 'probed'],
            */

            /**
             *
             *  Initialization
             *
             */

            init: function () {
                this._super();
                this.set('content', []);
                this.set('loadint', true);
            },

            load: function (machines) {
                this._updateContent(machines);
                this.set('loading', false);
            },

            /**
             *
             *  Methods
             *
             */

            newMachine: function(name, image, size, location, key, script, monitoring,
                dockerEnv, dockerCommand, scriptParams, dockerPorts) {

                // Create a fake machine model for the user
                // to see until we get the real machine from
                // the server
                var dummyMachine = Machine.create({
                    'state': 'pending',
                    'backend': this.backend,
                    'name': name,
                    'image': image,
                    'id': -1,
                    'pendingCreation': true
                });

                this.addObject(dummyMachine);

                // Don't send dummy key text
                key = Mist.keysController.keyExists(key.id) ? key : null;
                var that = this;

                // Construct array of network ids for openstack
                var networks = [];
                this.backend.networks.content.forEach(function (network) {
                    if (network.selected)
                        networks.push(network.id);
                });

                // Construct docerEnv dict
                var environment = null;
                if (dockerEnv.length) {
                    environment = {};
                    dockerEnv.split('\n').forEach(function (definition) {
                        definition = definition.split('=');
                        environment[definition[0]] = definition[1];
                    });
                }

                // Construct docker port bindings
                if (dockerPorts.length) {
                    var portBindings = {};
                    var exposedPorts = {};
                    dockerPorts.split('\n').forEach(function (line) {
                        var vars = line.split(':');
                        var key = vars[1] + '/tcp';
                        portBindings[key] = [{'HostPort': vars[0]}];
                        exposedPorts[key] = {};
                    });
                }

                this.set('addingMachine', true);
                Mist.ajax.POST('backends/' + this.backend.id + '/machines', {
                        'name': name,
                        'key': key ? key.id : null,
                        'size': size.id,
                        'script': script.id ? undefined : script,
                        'script_id': script.id || undefined,
                        'script_params': scriptParams,
                        'image': image.id,
                        'location': location.id,
                        // Linode specific
                        'disk': size.disk,
                        'image_extra': image.extra,
                        // Gce specific
                        'size_name': size.name,
                        'image_name': image.name,
                        'location_name': location.name,
                        'monitoring' : monitoring,
                        // Openstack
                        'networks': networks,
                        // Docker
                        'docker_env': environment,
                        'docker_command': dockerCommand,
                        'docker_exposed_ports': exposedPorts,
                        'docker_port_bindings': portBindings
                }).success(function (machine) {
                    machine.backend = that.backend;
                    // Nephoscale returns machine id on request success,
                    // but the machine is not listed on the next list_machines.
                    // This makes the machine dissappear from the UI.
                    if (that.backend.provider != 'nephoscale')
                        that._createMachine(machine, key, dummyMachine);
                    else
                        dummyMachine.set('pendingCreation', false);
                }).error(function (message) {
                    that.content.removeObject(that.content.findBy('name', name));
                    Mist.notificationController.timeNotify('Failed to create machine: ' + message, 5000);
                }).complete(function (success, machine) {
                    that.set('addingMachine', false);
                    that.set('onMachineAdd');
                });
            },

            shutdownMachine: function(machineId, callback) {
                var that = this;
                var machine = this.getMachine(machineId);
                machine.waitFor('stopped');
                machine.lockOn('pending');
                this.set('shutingdownMachine', true);
                Mist.ajax.POST('/backends/' + this.backend.id + '/machines/' + machineId, {
                    'action' : 'stop'
                }).success(function() {
                    //that._shutdownMachine(machineId);
                }).error(function() {
                    machine.restoreState();
                    Mist.notificationController.notify('Failed to shutdown machine');
                }).complete(function(success) {
                    that.set('shutingdownMachine', false);
                    that.trigger('onMachineShutdown');
                    if (callback) callback(success);
                });
            },

            destroyMachine: function(machineId, callback) {
                var that = this;
                var machine = this.getMachine(machineId);
                machine.waitFor('terminated');
                machine.lockOn('pending');
                this.set('destroyingMachine', true);
                machine.set('beingDestroyed', true);
                Mist.ajax.POST('/backends/' + this.backend.id + '/machines/' + machineId, {
                    'action' : 'destroy'
                }).success(function() {
                    //that._destroyMachine(machineId);
                }).error(function() {
                    machine.restoreState();
                    Mist.notificationController.notify('Failed to destroy machine');
                }).complete(function(success) {
                    that.set('destroyingMachine', false);
                    machine.set("beingDestroyed",false);
                    that.trigger('onMachineDestroy');
                    if (callback) callback(success);
                });
            },

            rebootMachine: function(machineId, callback) {
                var that = this;
                var machine = this.getMachine(machineId);
                machine.waitFor('running');
                machine.lockOn('rebooting');
                this.set('rebootingMachine', true);
                Mist.ajax.POST('/backends/' + this.backend.id + '/machines/' + machineId, {
                    'action' : 'reboot'
                }).success(function() {
                    //that.rebootMachine(machineId);
                }).error(function() {
                    machine.restoreState();
                    Mist.notificationController.notify('Failed to reboot machine');
                }).complete(function(success) {
                    that.set('rebootingMachine', false);
                    that.trigger('onMachineReboot');
                    if (callback) callback(success);
                });
            },

            startMachine: function(machineId, callback) {
                var that = this;
                var machine = this.getMachine(machineId);
                machine.waitFor('running');
                machine.lockOn('pending');
                this.set('startingMachine', true);
                Mist.ajax.POST('/backends/' + this.backend.id + '/machines/' + machineId, {
                    'action' : 'start'
                }).success(function() {
                    //that.startMachine(machineId);
                }).error(function() {
                    machine.restoreState();
                    Mist.notificationController.notify('Failed to start machine');
                }).complete(function(success) {
                    that.set('startingMachine', false);
                    that.trigger('onMachineStart');
                    if (callback) callback(success);
                });
            },

            getMachine: function(machineId) {
                return this.content.findBy('id', machineId);
            },

            machineExists: function(machineId) {
                return !!this.getMachine(machineId);
            },

            /**
             *
             *  Pseudo-Private Methods
             *
             */

            _updateContent: function(machines) {
                var that = this;
                Ember.run(function() {

                    // Replace dummy machines (newly created)

                    var dummyMachines = that.content.filterBy('id', -1);

                    dummyMachines.forEach(function(machine) {
                        var realMachine = machines.findBy('name', machine.name);
                        if (realMachine)
                            for (var attr in realMachine)
                                machine.set(attr, realMachine[attr]);
                    });

                    // Remove deleted machines

                    that.content.forEach(function(machine) {
                        if (!machines.findBy('id', machine.id))
                            if (machine.id != -1)
                                that.content.removeObject(machine);
                    });

                    // Update content

                    machines.forEach(function(machine) {
                        if (that.machineExists(machine.id)) {

                            // Update existing machines
                            var old_machine = that.getMachine(machine.id);
                            // We save previous state here because it will
                            // be overwritten by the following for loop
                            var prevState = old_machine.state;

                            for (var attr in machine) {

                                // Do not overwrite ips
                                if (attr == 'private_ips') continue;
                                if (attr == 'pubic_ips') continue;
                                old_machine.set(attr, machine[attr]);
                            }

                        } else {

                            // Add new machine
                            machine.backend = that.backend;
                            that.content.pushObject(Machine.create(machine));
                        }
                    });

                    that._updateMonitoredMachines();

                    that.trigger('onMachineListChange');
                });
            },

            _createMachine: function(machine, key, dummyMachine) {
                Ember.run(this, function() {
                    machine = Machine.create(machine);
                    if (machine.state == 'stopped')
                        machine.set('state', 'pending');
                    this.content.addObject(machine);
                    this.content.removeObject(dummyMachine);
                    Mist.keysController._associateKey(key.id, machine);
                    this.trigger('onMachineListChange');
                });
            },

            _updateSelectedMachines: function() {
                Ember.run(this, function() {
                    var newSelectedMachines = [];
                    this.content.forEach(function(machine) {
                        if (machine.selected) newSelectedMachines.push(machine);
                    });
                    this.set('selectedMachines', newSelectedMachines);
                    this.trigger('onSelectedMachinesChange');
                });
            },

            _updateMonitoredMachines: function() {

                forIn(this, Mist.monitored_machines_, function (machineDict, uuid) {

                    var machine = this.getMachine(machineDict.machine_id);
                    if (!machine) return;

                    machine.set('hasMonitoring', true);

                    // Inject installation status on machine
                    forIn(machineDict.installation_status, function (value, property) {
                        machine.installationStatus.set(property, value);
                    });

                    // Pass machine reference to rules
                    Mist.rulesController.content.forEach(function (rule) {
                        if (rule.machine.id) return;
                        if (machine.equals([rule.backend, rule.machine]))
                            rule.set('machine', machine);
                    });

                    // Pass machine reference to metrics
                    Mist.metricsController.customMetrics.forEach(function (metric) {
                        metric.machines.forEach(function (metricMachine, index) {
                            if (machine.equals(metricMachine)) {
                                metric.machines[index] = machine;
                                Mist.metricsController.trigger('onMetricListChange');
                            }
                        });
                    });
                });
            },

            /**
             *
             *  Observers
             *
             */

            selectedMachinesObserver: function() {
                Ember.run.once(this, '_updateSelectedMachines');
            }.observes('content.@each.selected')
        });
    }
);
<commit_msg>Associate key on machine creation only if key exists<commit_after>define('app/controllers/machines', ['app/models/machine'],
    /**
     *  Machines Controller
     *
     *  @returns Class
     */
    function(Machine) {
        return Ember.ArrayController.extend(Ember.Evented, {

            /**
             *  Properties
             */

            content: [],
            loading: null,
            backend: null,
            failCounter: null,
            addingMachine: null,
            startingMachine: null,
            rebootingMachine: null,
            destroyingMachine: null,
            shutingdownMachine: null,

            /* Let's disable sorting for now
            sortAscending: true,
            sortProperties: ['hasMonitoring', 'probed'],
            */

            /**
             *
             *  Initialization
             *
             */

            init: function () {
                this._super();
                this.set('content', []);
                this.set('loadint', true);
            },

            load: function (machines) {
                this._updateContent(machines);
                this.set('loading', false);
            },

            /**
             *
             *  Methods
             *
             */

            newMachine: function(name, image, size, location, key, script, monitoring,
                dockerEnv, dockerCommand, scriptParams, dockerPorts) {

                // Create a fake machine model for the user
                // to see until we get the real machine from
                // the server
                var dummyMachine = Machine.create({
                    'state': 'pending',
                    'backend': this.backend,
                    'name': name,
                    'image': image,
                    'id': -1,
                    'pendingCreation': true
                });

                this.addObject(dummyMachine);

                // Don't send dummy key text
                key = Mist.keysController.keyExists(key.id) ? key : null;
                var that = this;

                // Construct array of network ids for openstack
                var networks = [];
                this.backend.networks.content.forEach(function (network) {
                    if (network.selected)
                        networks.push(network.id);
                });

                // Construct docerEnv dict
                var environment = null;
                if (dockerEnv.length) {
                    environment = {};
                    dockerEnv.split('\n').forEach(function (definition) {
                        definition = definition.split('=');
                        environment[definition[0]] = definition[1];
                    });
                }

                // Construct docker port bindings
                if (dockerPorts.length) {
                    var portBindings = {};
                    var exposedPorts = {};
                    dockerPorts.split('\n').forEach(function (line) {
                        var vars = line.split(':');
                        var key = vars[1] + '/tcp';
                        portBindings[key] = [{'HostPort': vars[0]}];
                        exposedPorts[key] = {};
                    });
                }

                this.set('addingMachine', true);
                Mist.ajax.POST('backends/' + this.backend.id + '/machines', {
                        'name': name,
                        'key': key ? key.id : null,
                        'size': size.id,
                        'script': script.id ? undefined : script,
                        'script_id': script.id || undefined,
                        'script_params': scriptParams,
                        'image': image.id,
                        'location': location.id,
                        // Linode specific
                        'disk': size.disk,
                        'image_extra': image.extra,
                        // Gce specific
                        'size_name': size.name,
                        'image_name': image.name,
                        'location_name': location.name,
                        'monitoring' : monitoring,
                        // Openstack
                        'networks': networks,
                        // Docker
                        'docker_env': environment,
                        'docker_command': dockerCommand,
                        'docker_exposed_ports': exposedPorts,
                        'docker_port_bindings': portBindings
                }).success(function (machine) {
                    machine.backend = that.backend;
                    // Nephoscale returns machine id on request success,
                    // but the machine is not listed on the next list_machines.
                    // This makes the machine dissappear from the UI.
                    if (that.backend.provider != 'nephoscale')
                        that._createMachine(machine, key, dummyMachine);
                    else
                        dummyMachine.set('pendingCreation', false);
                }).error(function (message) {
                    that.content.removeObject(that.content.findBy('name', name));
                    Mist.notificationController.timeNotify('Failed to create machine: ' + message, 5000);
                }).complete(function (success, machine) {
                    that.set('addingMachine', false);
                    that.set('onMachineAdd');
                });
            },

            shutdownMachine: function(machineId, callback) {
                var that = this;
                var machine = this.getMachine(machineId);
                machine.waitFor('stopped');
                machine.lockOn('pending');
                this.set('shutingdownMachine', true);
                Mist.ajax.POST('/backends/' + this.backend.id + '/machines/' + machineId, {
                    'action' : 'stop'
                }).success(function() {
                    //that._shutdownMachine(machineId);
                }).error(function() {
                    machine.restoreState();
                    Mist.notificationController.notify('Failed to shutdown machine');
                }).complete(function(success) {
                    that.set('shutingdownMachine', false);
                    that.trigger('onMachineShutdown');
                    if (callback) callback(success);
                });
            },

            destroyMachine: function(machineId, callback) {
                var that = this;
                var machine = this.getMachine(machineId);
                machine.waitFor('terminated');
                machine.lockOn('pending');
                this.set('destroyingMachine', true);
                machine.set('beingDestroyed', true);
                Mist.ajax.POST('/backends/' + this.backend.id + '/machines/' + machineId, {
                    'action' : 'destroy'
                }).success(function() {
                    //that._destroyMachine(machineId);
                }).error(function() {
                    machine.restoreState();
                    Mist.notificationController.notify('Failed to destroy machine');
                }).complete(function(success) {
                    that.set('destroyingMachine', false);
                    machine.set("beingDestroyed",false);
                    that.trigger('onMachineDestroy');
                    if (callback) callback(success);
                });
            },

            rebootMachine: function(machineId, callback) {
                var that = this;
                var machine = this.getMachine(machineId);
                machine.waitFor('running');
                machine.lockOn('rebooting');
                this.set('rebootingMachine', true);
                Mist.ajax.POST('/backends/' + this.backend.id + '/machines/' + machineId, {
                    'action' : 'reboot'
                }).success(function() {
                    //that.rebootMachine(machineId);
                }).error(function() {
                    machine.restoreState();
                    Mist.notificationController.notify('Failed to reboot machine');
                }).complete(function(success) {
                    that.set('rebootingMachine', false);
                    that.trigger('onMachineReboot');
                    if (callback) callback(success);
                });
            },

            startMachine: function(machineId, callback) {
                var that = this;
                var machine = this.getMachine(machineId);
                machine.waitFor('running');
                machine.lockOn('pending');
                this.set('startingMachine', true);
                Mist.ajax.POST('/backends/' + this.backend.id + '/machines/' + machineId, {
                    'action' : 'start'
                }).success(function() {
                    //that.startMachine(machineId);
                }).error(function() {
                    machine.restoreState();
                    Mist.notificationController.notify('Failed to start machine');
                }).complete(function(success) {
                    that.set('startingMachine', false);
                    that.trigger('onMachineStart');
                    if (callback) callback(success);
                });
            },

            getMachine: function(machineId) {
                return this.content.findBy('id', machineId);
            },

            machineExists: function(machineId) {
                return !!this.getMachine(machineId);
            },

            /**
             *
             *  Pseudo-Private Methods
             *
             */

            _updateContent: function(machines) {
                var that = this;
                Ember.run(function() {

                    // Replace dummy machines (newly created)

                    var dummyMachines = that.content.filterBy('id', -1);

                    dummyMachines.forEach(function(machine) {
                        var realMachine = machines.findBy('name', machine.name);
                        if (realMachine)
                            for (var attr in realMachine)
                                machine.set(attr, realMachine[attr]);
                    });

                    // Remove deleted machines

                    that.content.forEach(function(machine) {
                        if (!machines.findBy('id', machine.id))
                            if (machine.id != -1)
                                that.content.removeObject(machine);
                    });

                    // Update content

                    machines.forEach(function(machine) {
                        if (that.machineExists(machine.id)) {

                            // Update existing machines
                            var old_machine = that.getMachine(machine.id);
                            // We save previous state here because it will
                            // be overwritten by the following for loop
                            var prevState = old_machine.state;

                            for (var attr in machine) {

                                // Do not overwrite ips
                                if (attr == 'private_ips') continue;
                                if (attr == 'pubic_ips') continue;
                                old_machine.set(attr, machine[attr]);
                            }

                        } else {

                            // Add new machine
                            machine.backend = that.backend;
                            that.content.pushObject(Machine.create(machine));
                        }
                    });

                    that._updateMonitoredMachines();

                    that.trigger('onMachineListChange');
                });
            },

            _createMachine: function(machine, key, dummyMachine) {
                Ember.run(this, function() {
                    machine = Machine.create(machine);
                    if (machine.state == 'stopped')
                        machine.set('state', 'pending');
                    this.content.addObject(machine);
                    this.content.removeObject(dummyMachine);
                    if (key && key.id)
                        Mist.keysController._associateKey(key.id, machine);
                    this.trigger('onMachineListChange');
                });
            },

            _updateSelectedMachines: function() {
                Ember.run(this, function() {
                    var newSelectedMachines = [];
                    this.content.forEach(function(machine) {
                        if (machine.selected) newSelectedMachines.push(machine);
                    });
                    this.set('selectedMachines', newSelectedMachines);
                    this.trigger('onSelectedMachinesChange');
                });
            },

            _updateMonitoredMachines: function() {

                forIn(this, Mist.monitored_machines_, function (machineDict, uuid) {

                    var machine = this.getMachine(machineDict.machine_id);
                    if (!machine) return;

                    machine.set('hasMonitoring', true);

                    // Inject installation status on machine
                    forIn(machineDict.installation_status, function (value, property) {
                        machine.installationStatus.set(property, value);
                    });

                    // Pass machine reference to rules
                    Mist.rulesController.content.forEach(function (rule) {
                        if (rule.machine.id) return;
                        if (machine.equals([rule.backend, rule.machine]))
                            rule.set('machine', machine);
                    });

                    // Pass machine reference to metrics
                    Mist.metricsController.customMetrics.forEach(function (metric) {
                        metric.machines.forEach(function (metricMachine, index) {
                            if (machine.equals(metricMachine)) {
                                metric.machines[index] = machine;
                                Mist.metricsController.trigger('onMetricListChange');
                            }
                        });
                    });
                });
            },

            /**
             *
             *  Observers
             *
             */

            selectedMachinesObserver: function() {
                Ember.run.once(this, '_updateSelectedMachines');
            }.observes('content.@each.selected')
        });
    }
);
<|endoftext|>


<commit_before>/*global require:true */
var Countree = require('../Countree.js');

/*
 ======== A Handy Little Nodeunit Reference ========
 https://github.com/caolan/nodeunit

 Test methods:
 test.expect(numAssertions)
 test.done()
 Test assertions:
 test.ok(value, [message])
 test.equal(actual, expected, [message])
 test.notEqual(actual, expected, [message])
 test.deepEqual(actual, expected, [message])
 test.notDeepEqual(actual, expected, [message])
 test.strictEqual(actual, expected, [message])
 test.notStrictEqual(actual, expected, [message])
 test.throws(block, [error], [message])
 test.doesNotThrow(block, [error], [message])
 test.ifError(value)
 */

exports['TimeHelper'] = {
    'setUp':function (done) {
        this.msToDigit = Countree.TIME_HELPER.getDigitFromMsForTimeUnit; // aliasing for better readability
        this.unitMillis = Countree.TIME_UNIT.MILLISECONDS;
        this.unitSecs = Countree.TIME_UNIT.SECONDS;
        this.unitMins = Countree.TIME_UNIT.MINUTES;
        this.unitHours = Countree.TIME_UNIT.HOURS;
        this.unitDays = Countree.TIME_UNIT.DAYS;
        done();
    },
    'TimeUtil(0) creates zeros for each digit':function (test) {
        var ms = 0;

        test.expect(5);
        test.equal(this.msToDigit(ms, this.unitMillis), 0, 'Retained digit is incorrect.');
        test.equal(this.msToDigit(ms, this.unitSecs), 0, 'Retained digit is incorrect.');
        test.equal(this.msToDigit(ms, this.unitMins), 0, 'Retained digit is incorrect.');
        test.equal(this.msToDigit(ms, this.unitHours), 0, 'Retained digit is incorrect.');
        test.equal(this.msToDigit(ms, this.unitDays), 0, 'Retained digit is incorrect.');
        test.done();
    },
    'TimeUtil(446582010) creates correct digits for each digit':function (test) {
        var ms = 446582010;

        test.expect(5);
        test.equal(this.msToDigit(ms, this.unitMillis), 10, 'Retained digit is incorrect.');
        test.equal(this.msToDigit(ms, this.unitSecs), 2, 'Retained digit is incorrect.');
        test.equal(this.msToDigit(ms, this.unitMins), 3, 'Retained digit is incorrect.');
        test.equal(this.msToDigit(ms, this.unitHours), 4, 'Retained digit is incorrect.');
        test.equal(this.msToDigit(ms, this.unitDays), 5, 'Retained digit is incorrect.');
        test.done();
    },
    'Fill digits of 0':function (test) {
        var ms = 0;

        test.expect(1);
        test.equal(this.msToDigit(ms, this.unitMillis, 3), '000', 'Retained digit is incorrect.');
        test.done();
    },
    'Fill digits for 446582010':function (test) {
        var ms = 446582010;

        test.expect(4);
        test.equal(this.msToDigit(ms, this.unitMillis, 3), '010', 'Retained digit is incorrect.');
        test.equal(this.msToDigit(ms, this.unitSecs, 2), '02', 'Retained digit is incorrect.');
        test.equal(this.msToDigit(ms, this.unitMins, 2), '03', 'Retained digit is incorrect.');
        test.equal(this.msToDigit(ms, this.unitHours, 2), '04', 'Retained digit is incorrect.');
        test.done();
    }
};

<commit_msg>Fix tests (nodeunit bug?)<commit_after>/*global require:true */
var Countree = require('../Countree.js');

/*
 ======== A Handy Little Nodeunit Reference ========
 https://github.com/caolan/nodeunit

 Test methods:
 test.expect(numAssertions)
 test.done()
 Test assertions:
 test.ok(value, [message])
 test.equal(actual, expected, [message])
 test.notEqual(actual, expected, [message])
 test.deepEqual(actual, expected, [message])
 test.notDeepEqual(actual, expected, [message])
 test.strictEqual(actual, expected, [message])
 test.notStrictEqual(actual, expected, [message])
 test.throws(block, [error], [message])
 test.doesNotThrow(block, [error], [message])
 test.ifError(value)
 */

exports['TimeHelper'] = {
    'setUp':function (done) {
        this.msToDigit = Countree.TIME_HELPER.getDigitFromMsForTimeUnitLeftFilled; // aliasing for better readability
        this.unitMillis = Countree.TIME_UNIT.MILLISECONDS;
        this.unitSecs = Countree.TIME_UNIT.SECONDS;
        this.unitMins = Countree.TIME_UNIT.MINUTES;
        this.unitHours = Countree.TIME_UNIT.HOURS;
        this.unitDays = Countree.TIME_UNIT.DAYS;
        done();
    },
    'TimeHelper(0) creates zeros for each digit':function (test) {
        var ms = 0;

        test.expect(5);
        test.equal(this.msToDigit(ms, this.unitMillis), 0, 'Retained digit is incorrect.');
        test.equal(this.msToDigit(ms, this.unitSecs), 0, 'Retained digit is incorrect.');
        test.equal(this.msToDigit(ms, this.unitMins), 0, 'Retained digit is incorrect.');
        test.equal(this.msToDigit(ms, this.unitHours), 0, 'Retained digit is incorrect.');
        test.equal(this.msToDigit(ms, this.unitDays), 0, 'Retained digit is incorrect.');
        test.done();
    },
    'TimeHelper(446582010) creates correct digits for each digit':function (test) {
        var ms = 446582010;

        test.expect(5);
        test.equal(this.msToDigit(ms, this.unitMillis), 10, 'Retained digit is incorrect.');
        test.equal(this.msToDigit(ms, this.unitSecs), 2, 'Retained digit is incorrect.');
        test.equal(this.msToDigit(ms, this.unitMins), 3, 'Retained digit is incorrect.');
        test.equal(this.msToDigit(ms, this.unitHours), 4, 'Retained digit is incorrect.');
        test.equal(this.msToDigit(ms, this.unitDays), 5, 'Retained digit is incorrect.');
        test.done();
    },
    'Fill digits of 0':function (test) {
        var ms = 0;

        test.expect(1);
        test.ok(this.msToDigit(ms, this.unitMillis, 3) === '000', 'Retained digit is incorrect.');
        test.done();
    },
    'Fill digits for 446582010':function (test) {
        var ms = 446582010;

        test.expect(4);
        test.ok(this.msToDigit(ms, this.unitMillis, 3) === '010', 'Retained digit is incorrect.');
        test.ok(this.msToDigit(ms, this.unitSecs, 2) === '02', 'Retained digit is incorrect.');
        test.ok(this.msToDigit(ms, this.unitMins, 2) === '03', 'Retained digit is incorrect.');
        test.ok(this.msToDigit(ms, this.unitHours, 2) === '04', 'Retained digit is incorrect.');
        test.done();
    }
};

<|endoftext|>


<commit_before>/**
 * assemble <https://github.com/assemble/assemble>
 *
 * Copyright (c) 2014-2015, Jon Schlinkert, Brian Woodward.
 * Licensed under the MIT License (MIT).
 */

'use strict';

var path = require('path');
var should = require('should');
var rimraf = require('rimraf');

var assemble = require('..');
var actual = __dirname + '/render-actual';

describe('assemble render', function () {
  var site = null;

  describe('assemble.render()', function () {
    beforeEach(function (done) {
      site = assemble.init();
      rimraf(actual, done);
    });

    afterEach(function(done) {
      rimraf(actual, done);
    });

    it('should render a file', function (done) {
      site.option('layout', 'default');
      site.option('renameKey', function (key) {
        return path.basename(key, path.extname(key));
      });

      site.partials(['test/fixtures/includes/*.hbs']);
      site.layouts(['test/fixtures/layouts/*.hbs']);
      site.data({
        posts: [
          { author: 'Brian Woodward', timestamp: '2014-11-01', summary: 'This is just a summary. First', content: 'Here\'s the real content. One' },
          { author: 'Brian Woodward', timestamp: '2014-11-02', summary: 'This is just a summary. Second', content: 'Here\'s the real content. Two' },
          { author: 'Jon Schlinkert', timestamp: '2014-11-03', summary: 'This is just a summary. Third', content: 'Here\'s the real content. Three' },
          { author: 'Jon Schlinkert', timestamp: '2014-11-04', summary: 'This is just a summary. Fourth', content: 'Here\'s the real content. Four' },
          { author: 'Brian Woodward', timestamp: '2014-11-05', summary: 'This is just a summary. Fifth', content: 'Here\'s the real content. Five' },
        ]
      });

      site.src('test/fixtures/pages/*.hbs')
        .pipe(site.dest(actual))
        .on('data', function (file) {
          file.options.layoutApplied.should.be.true;
          (file.path.indexOf('.html') > -1).should.be.true;
          (file.contents.toString().indexOf('doctype html') > -1).should.be.true;
        })
        .on('error', done)
        .on('end', done);

    });
  });
});
<commit_msg>ensure that render plugin tests are running<commit_after>/**
 * assemble <https://github.com/assemble/assemble>
 *
 * Copyright (c) 2014-2015, Jon Schlinkert, Brian Woodward.
 * Licensed under the MIT License (MIT).
 */

'use strict';

var path = require('path');
var should = require('should');
var rimraf = require('rimraf');
var app;

var assemble = require('..');
var actual = __dirname + '/render-actual';

describe('assemble render', function () {

  describe('assemble.render()', function () {
    beforeEach(function (done) {
      app = assemble.init();
      rimraf(actual, done);
    });

    afterEach(function(done) {
      rimraf(actual, done);
    });

    it('should render a file', function (done) {
      app.option('layout', 'default');
      app.option('renameKey', function (key) {
        return path.basename(key, path.extname(key));
      });

      app.partials(['test/fixtures/includes/*.hbs']);
      app.layouts(['test/fixtures/layouts/*.hbs']);
      app.data({
        posts: [
          { author: 'Brian Woodward', timestamp: '2014-11-01', summary: 'This is just a summary. First', content: 'Here\'s the real content. One' },
          { author: 'Brian Woodward', timestamp: '2014-11-02', summary: 'This is just a summary. Second', content: 'Here\'s the real content. Two' },
          { author: 'Jon Schlinkert', timestamp: '2014-11-03', summary: 'This is just a summary. Third', content: 'Here\'s the real content. Three' },
          { author: 'Jon Schlinkert', timestamp: '2014-11-04', summary: 'This is just a summary. Fourth', content: 'Here\'s the real content. Four' },
          { author: 'Brian Woodward', timestamp: '2014-11-05', summary: 'This is just a summary. Fifth', content: 'Here\'s the real content. Five' },
        ]
      });

      var i = 0;
      app.src('test/fixtures/pages/*.hbs')
        .pipe(app.dest(actual))
        .on('data', function (file) {
          i++;
          file.options.layoutApplied.should.be.true;
          (file.path.indexOf('.html') > -1).should.be.true;
          (file.contents.toString().indexOf('doctype html') > -1).should.be.true;
        })
        .on('error', done)
        .on('end', function () {
          i.should.equal(1);
          done();
        });
    });
  });
});
<|endoftext|>


<commit_before>import { isObject } from 'lodash';
const errors = {
  'transaction underpriced':
    'Current network is busy. Please try again with a higher priority.'
};
/**
 * @param {Object | String} err
 * @returns {String} Error Message
 */
const handleError = err => {
  const errorValues = Object.keys(errors);
  const message =
    err && err.message
      ? isObject(err.message)
        ? err.message.message
        : err.message
      : err;
  if (!message) return '';
  const foundError = errorValues.find(item => message.includes(item));
  return foundError ? errors[foundError] : message;
};

export default handleError;
<commit_msg>devop: 🔧 added nonce message<commit_after>import { isObject } from 'lodash';
const errors = {
  'transaction underpriced':
    'Current network is busy. Please try again with a higher priority.',
  'nonce too low': 'Nonce too low.'
};
/**
 * @param {Object | String} err
 * @returns {String} Error Message
 */
const handleError = err => {
  const errorValues = Object.keys(errors);
  const message =
    err && err.message
      ? isObject(err.message)
        ? err.message.message
        : err.message
      : err;
  if (!message) return '';
  const foundError = errorValues.find(item => message.includes(item));
  return foundError ? errors[foundError] : message;
};

export default handleError;
<|endoftext|>


<commit_before>/*
 * Copyright 2015, Yahoo Inc
 * Copyrights licensed under the MIT License.
 * See the accompanying LICENSE file for terms.
 */

'use strict';

var sepatarorUtility = require('./sepataror-utility');

function isAutoFormatEnabled(e) {
  var keyCode = e.keyCode;
  if(!keyCode) {
    return true;
  }

  if(keyCode >= 48 && keyCode <= 90 || keyCode >= 96 && keyCode <= 105) {
    return true;
  }

  return false;
}

function isModifierKey(e) {
  var keyCode = e.keyCode;

  if(keyCode >= 8 && keyCode <= 46) {
    return true;
  }
  return false;
}

function unFormat(value, separatorPattern) {
  return value.replace(separatorPattern, '');
}

function formatter(targetNode, separator, separatorIndex, separatorPattern, maxLength, e) {
  var caretIndex = targetNode.selectionStart;
  var lastCharTyped = targetNode.value.charAt(caretIndex - 1);
  var lastCharTypedIsSeparator = separator.indexOf(lastCharTyped) !== -1 ? 1 : 0;
  var expectedValueArray = unFormat(targetNode.value, separatorPattern).split('');

  /*
   * no format
   * ---------
   * if the keycode is between 8 & 46, backspace, left/right arrow keys etc.
   * avoid the pain of maintaining the caretIndex when ever formattig is done.
   * format
   * ------
   * if the last character typed is one of the separator
   * so that the seperator is not typed over and over
   */
  if( (lastCharTypedIsSeparator && !isModifierKey(e) ) || isAutoFormatEnabled(e) ) {
    for( var i = 0, l = separatorIndex.length; i < l; i += 1 ) {
      if(expectedValueArray.length >= separatorIndex[i]) {
        expectedValueArray.splice(separatorIndex[i], 0, separator[i]);
        if (lastCharTypedIsSeparator) {
          continue;
        }
        /*
         * update the caret index
         * ----------------------
         * formatting happens only on keyup
         * if the key has not been released for a long
         * same character will be entered multiple time in the input
         * the caret index needs to be updated accordingly, after the formatting
         * which must take, the separator added, in to consideration
         */
        if(caretIndex >= targetNode.value.length) {
          caretIndex += 1;
        }

        if(caretIndex === separatorIndex[i] + 1) {
          caretIndex += 1;
        }
      }
    }

    if (this.hasMaxLength) {
      targetNode.value = expectedValueArray.slice(0, maxLength).join('');
    } else {
      targetNode.value = expectedValueArray.join('');
    }
    if (e.type) {
        targetNode.selectionStart = caretIndex;
        targetNode.selectionEnd = caretIndex;
    }
  }
}

var AutoFormatter = function(targetNode, hasMaxLength) {
  this.targetNode = targetNode;
  this.hasMaxLength = hasMaxLength;
};

AutoFormatter.prototype.disableFormatting = function() {
  var value = this.targetNode.value;

  /* istanbul ignore next */
  if (value !== '') {
    this.targetNode.value = unFormat(value, this.separatorPattern);
  }

  /* istanbul ignore next */
  if (this.formatter) {
    this.targetNode.removeEventListener('keyup', this.formatter);
  }

  /*
   * Is the commented code required?
   * IE does not support CustomEvent constructor
   */
  // document.dispatchEvent(new CustomEvent('cleared-formatting', {
  //   'detail': {
  //     targetNode: this.targetNode
  //   }
  // }));
};

AutoFormatter.prototype.enableFormatting = function(e) {
  var targetNode = this.targetNode;
  var value;
  var format = targetNode.getAttribute('data-format');
  var separator;
  var separatorIndex;
  var separatorPattern;

  if (this.formatter || this.separatorPattern) {
    this.disableFormatting();
  }

  value = targetNode.value;

  this.format = format = format === null ? '' : format;

  if (format && format.length) {
    this.separator = separator = format.match(/[^X]/g);
    this.separatorIndex = separatorIndex = sepatarorUtility.getSepatarorIndex(separator, format);
    this.separatorPattern = separatorPattern = sepatarorUtility.getSepatarorPattern(separator);

    if (this.hasMaxLength) {
      targetNode.setAttribute('maxlength', format.length);
    }

    this.formatter = formatter.bind(this, targetNode, separator, separatorIndex, separatorPattern, format.length);
    targetNode.addEventListener('keyup', this.formatter);
    if(value !== '') {
      formatter.bind(this)(targetNode, separator, separatorIndex, separatorPattern, format.length, e || {});
    }
  }
};

AutoFormatter.format = function(value, format, hasMaxLength) {
  var separator;
  var separatorIndex;
  var separatorPattern;
  var expectedValueArray;

  if (!value) {
    return value;
  }

  if (!format) {
    return value;
  }

  separator = format.match(/[^X]/g);
  separatorIndex = sepatarorUtility.getSepatarorIndex(separator, format);
  separatorPattern = sepatarorUtility.getSepatarorPattern(separator);

  expectedValueArray = unFormat(value, separatorPattern).split('');

  for( var i = 0, l = separatorIndex.length; i < l; i += 1 ) {
    if(expectedValueArray.length >= separatorIndex[i]) {
      expectedValueArray.splice(separatorIndex[i], 0, separator[i]);
    }
  }
  if (hasMaxLength) {
    return expectedValueArray.slice(0, format.length).join('');
  } else {
    return expectedValueArray.join('');
  }
};

module.exports = AutoFormatter;
<commit_msg>removed commented code<commit_after>/*
 * Copyright 2015, Yahoo Inc
 * Copyrights licensed under the MIT License.
 * See the accompanying LICENSE file for terms.
 */

'use strict';

var sepatarorUtility = require('./sepataror-utility');

function isAutoFormatEnabled(e) {
  var keyCode = e.keyCode;
  if(!keyCode) {
    return true;
  }

  if(keyCode >= 48 && keyCode <= 90 || keyCode >= 96 && keyCode <= 105) {
    return true;
  }

  return false;
}

function isModifierKey(e) {
  var keyCode = e.keyCode;

  if(keyCode >= 8 && keyCode <= 46) {
    return true;
  }
  return false;
}

function unFormat(value, separatorPattern) {
  return value.replace(separatorPattern, '');
}

function formatter(targetNode, separator, separatorIndex, separatorPattern, maxLength, e) {
  var caretIndex = targetNode.selectionStart;
  var lastCharTyped = targetNode.value.charAt(caretIndex - 1);
  var lastCharTypedIsSeparator = separator.indexOf(lastCharTyped) !== -1 ? 1 : 0;
  var expectedValueArray = unFormat(targetNode.value, separatorPattern).split('');

  /*
   * no format
   * ---------
   * if the keycode is between 8 & 46, backspace, left/right arrow keys etc.
   * avoid the pain of maintaining the caretIndex when ever formattig is done.
   * format
   * ------
   * if the last character typed is one of the separator
   * so that the seperator is not typed over and over
   */
  if( (lastCharTypedIsSeparator && !isModifierKey(e) ) || isAutoFormatEnabled(e) ) {
    for( var i = 0, l = separatorIndex.length; i < l; i += 1 ) {
      if(expectedValueArray.length >= separatorIndex[i]) {
        expectedValueArray.splice(separatorIndex[i], 0, separator[i]);
        if (lastCharTypedIsSeparator) {
          continue;
        }
        /*
         * update the caret index
         * ----------------------
         * formatting happens only on keyup
         * if the key has not been released for a long
         * same character will be entered multiple time in the input
         * the caret index needs to be updated accordingly, after the formatting
         * which must take, the separator added, in to consideration
         */
        if(caretIndex >= targetNode.value.length) {
          caretIndex += 1;
        }

        if(caretIndex === separatorIndex[i] + 1) {
          caretIndex += 1;
        }
      }
    }

    if (this.hasMaxLength) {
      targetNode.value = expectedValueArray.slice(0, maxLength).join('');
    } else {
      targetNode.value = expectedValueArray.join('');
    }
    if (e.type) {
        targetNode.selectionStart = caretIndex;
        targetNode.selectionEnd = caretIndex;
    }
  }
}

var AutoFormatter = function(targetNode, hasMaxLength) {
  this.targetNode = targetNode;
  this.hasMaxLength = hasMaxLength;
};

AutoFormatter.prototype.disableFormatting = function() {
  var value = this.targetNode.value;

  /* istanbul ignore next */
  if (value !== '') {
    this.targetNode.value = unFormat(value, this.separatorPattern);
  }

  /* istanbul ignore next */
  if (this.formatter) {
    this.targetNode.removeEventListener('keyup', this.formatter);
  }

};

AutoFormatter.prototype.enableFormatting = function(e) {
  var targetNode = this.targetNode;
  var value;
  var format = targetNode.getAttribute('data-format');
  var separator;
  var separatorIndex;
  var separatorPattern;

  if (this.formatter || this.separatorPattern) {
    this.disableFormatting();
  }

  value = targetNode.value;

  this.format = format = format === null ? '' : format;

  if (format && format.length) {
    this.separator = separator = format.match(/[^X]/g);
    this.separatorIndex = separatorIndex = sepatarorUtility.getSepatarorIndex(separator, format);
    this.separatorPattern = separatorPattern = sepatarorUtility.getSepatarorPattern(separator);

    if (this.hasMaxLength) {
      targetNode.setAttribute('maxlength', format.length);
    }

    this.formatter = formatter.bind(this, targetNode, separator, separatorIndex, separatorPattern, format.length);
    targetNode.addEventListener('keyup', this.formatter);
    if(value !== '') {
      formatter.bind(this)(targetNode, separator, separatorIndex, separatorPattern, format.length, e || {});
    }
  }
};

AutoFormatter.format = function(value, format, hasMaxLength) {
  var separator;
  var separatorIndex;
  var separatorPattern;
  var expectedValueArray;

  if (!value) {
    return value;
  }

  if (!format) {
    return value;
  }

  separator = format.match(/[^X]/g);
  separatorIndex = sepatarorUtility.getSepatarorIndex(separator, format);
  separatorPattern = sepatarorUtility.getSepatarorPattern(separator);

  expectedValueArray = unFormat(value, separatorPattern).split('');

  for( var i = 0, l = separatorIndex.length; i < l; i += 1 ) {
    if(expectedValueArray.length >= separatorIndex[i]) {
      expectedValueArray.splice(separatorIndex[i], 0, separator[i]);
    }
  }
  if (hasMaxLength) {
    return expectedValueArray.slice(0, format.length).join('');
  } else {
    return expectedValueArray.join('');
  }
};

module.exports = AutoFormatter;
<|endoftext|>


<commit_before>(function ( Backbone, _ ) {

  'use strict';

  var bbExtend = Backbone.Model.extend;

  function triggerPropChange( ctx, prop ) {
    return function () {
      ctx.trigger( 'change:' + prop, ctx, prop );
    };
  }

  function setupDepsListeners( ctx, prop, deps ) {
    deps = deps || [];
    var l = deps.length;
    while ( l-- ) {
      ctx.on( 'change:' + deps[ l ], triggerPropChange( ctx, prop ) );
    }
  }

  function normalizeComputedProps( computedProps ) {
    var propSpec, action, prop, deps;
    var normalizedProps = {};

    if ( ! computedProps ) {
      return {};
    }

    for ( prop in computedProps ) {
      if ( computedProps.hasOwnProperty( prop ) ) {
        propSpec = computedProps[ prop ];

        if ( propSpec instanceof Function ) {
          action = propSpec;
          deps = [];
        } else {
          action = propSpec.action;
          deps = propSpec.depends || [];
        }

        normalizedProps[ prop ] = {
          action: action,
          deps: deps
        };
      }
    }

    return normalizedProps;
  }

  // Creates a getter for the class, taking as input
  // the original getter to wrap
  var wrapGet = function ( get ) {
    return function ( attr ) {
      var computedProps = this._computedProps;
      var newValue;

      if ( computedProps[ attr ] ) {
        newValue = computedProps[ attr ].action.call( this );
        this._cachedProps[ attr ] = newValue;
        return newValue;
      }

      return get.apply( this, arguments );
    };
  };

  // Creates a setter for the class, taking as input
  // the original setter to wrap
  var wrapSet = function ( set ) {
    return function ( attr, value ) {
      var computedProps = this._computedProps;
      var newValue;

      if ( computedProps[ attr ] ) {
        newValue = computedProps[ attr ].action.call( this, value );
        if ( this._cachedProps[ attr ] !== newValue ) {
          this._cachedProps[ attr ] = newValue;
          this.trigger( 'change:' + attr, this, attr );
        }
        return this;
      }

      return set.apply( this, arguments );
    };
  };

  // Override Bootstrap.Model's extend
  Backbone.Model.extend = function ( properties, classProperties ) {
    var prop, action, propSpec, deps;
    var parent = this;

    properties = properties || {};

    // Setup computed properties
    var computedProps = normalizeComputedProps( properties.properties );
    delete properties.properties;

    // Override Boostrap's default constructor, setting up listeners for dependencies.
    properties.constructor = function () {
      var computedProps = this._computedProps;
      var prop, deps, l;
      this._cachedProps = {};

      for ( prop in computedProps ) {
        if ( computedProps.hasOwnProperty( prop ) ) {
          setupDepsListeners( this, prop, computedProps[ prop ].deps );
        }
      }

      return parent.apply( this, arguments );
    };

    // Extend our class from Boostrap.Model
    var Class = bbExtend.call( this, properties, classProperties );

    Class.prototype._computedProps = computedProps;

    // Override Bootstrap's default getter
    Class.prototype.get = wrapGet( Class.prototype.get );

    // Override Bootstrap's default setter
    Class.prototype.set = wrapSet( Class.prototype.set );

    return Class;
  };

}( this.Backbone, this._ ));
<commit_msg>Use a more idiomatic subclassing structure<commit_after>this.Backbone.Model = (function ( Model, _ ) {

  'use strict';

  function triggerPropChange( ctx, prop ) {
    return function () {
      ctx.trigger( 'change:' + prop, ctx, prop );
    };
  }

  function setupDepsListeners( ctx, prop, deps ) {
    deps = deps || [];
    var l = deps.length;
    while ( l-- ) {
      ctx.on( 'change:' + deps[ l ], triggerPropChange( ctx, prop ) );
    }
  }

  function normalizeComputedProps( computedProps ) {
    var propSpec, action, prop, deps;
    var normalizedProps = {};

    if ( ! computedProps ) {
      return {};
    }

    for ( prop in computedProps ) {
      if ( computedProps.hasOwnProperty( prop ) ) {
        propSpec = computedProps[ prop ];

        if ( propSpec instanceof Function ) {
          action = propSpec;
          deps = [];
        } else {
          action = propSpec.action;
          deps = propSpec.depends || [];
        }

        normalizedProps[ prop ] = {
          action: action,
          deps: deps
        };
      }
    }

    return normalizedProps;
  }

  return Model.extend({

    _computedProps: {},

    // Override Boostrap's default constructor, setting up listeners for dependencies.
    constructor: function () {
      var computedProps = this._computedProps;
      var prop, deps, l;

      this._cachedProps = {};

      for ( prop in computedProps ) {
        if ( computedProps.hasOwnProperty( prop ) ) {
          setupDepsListeners( this, prop, computedProps[ prop ].deps );
        }
      }

      return Model.apply( this, arguments );
    },

    get: _.wrap( Model.prototype.get, function ( get, attr ) {
      var computedProps = this._computedProps;
      var newValue;

      if ( computedProps[ attr ] ) {
        newValue = computedProps[ attr ].action.call( this );
        this._cachedProps[ attr ] = newValue;
        return newValue;
      }

      return get.call( this, attr );
    }),

    set: _.wrap( Model.prototype.set, function ( set, attr, values ) {
      var computedProps = this._computedProps;
      var newValue;

      if ( computedProps[ attr ] ) {
        newValue = computedProps[ attr ].action.call( this, values );
        if ( this._cachedProps[ attr ] !== newValue ) {
          this._cachedProps[ attr ] = newValue;
          this.trigger( 'change:' + attr, this, attr );
        }
        return this;
      }

      return set.call( this, attr, values );
    })

  }, {

    // Override Bootstrap.Model's extend
    extend: _.wrap( Model.extend, function ( extend, properties, classProperties ) {
      var prop, action, propSpec, deps;

      properties = properties || {};

      // Setup computed properties
      var computedProps = normalizeComputedProps( properties.properties );
      delete properties.properties;

      // Extend our class from Boostrap.Model
      var Class = extend.call( this, properties, classProperties );

      _.extend( Class.prototype, {
        _computedProps: computedProps
      });

      return Class;
    })

  });

}( this.Backbone.Model, this._ ));
<|endoftext|>


<commit_before>// Load in our dependencies
var expect = require('chai').expect;
var D = require('../../browser/js/domo');
var Overlay = require('../../browser/js/overlay');
var domUtils = require('./utils/dom');

// Start our tests
describe.only('An overlay over an element', function () {
  // Set up our elements
  before(function createElement () {
    // Create our container element
    this.containerEl = D.DIV();
    document.body.appendChild(this.containerEl);
  });
  after(function cleanup () {
    document.body.removeChild(this.containerEl);
    delete this.containerEl;
  });
  before(function bindOverlay () {
    var el = D.DIV({
      id: 'overlay-container',
      style: 'width: 300px; height: 200px; color: navy'
    });
    this.containerEl.appendChild(el);
    this.overlay = new Overlay(el, {containerEl: this.containerEl});
  });
  after(function cleanup () {
    // TODO: Set up unbinding of overlay
    delete this.overlay;
  });

  // Perform our assertions
  it('is not initially visible', function () {
    var overlayEl = this.containerEl.querySelector('.overlay');
    expect(overlayEl).to.equal(null);
  });

  describe('after dragging over our element', function () {
    // Perform overlay drag
    domUtils.dragOverElement({
      selector: '#overlay-container',
      startCoords: {x: 0, y: 0},
      endCoords: {x: 100, y: 100}
    });

    // Perform our assertions
    it('is visible', function () {
      var overlayEl = this.containerEl.querySelector('.overlay');
      expect(overlayEl).to.not.equal(null);
    });
  });
});

describe.skip('An overlay that attempts to extend past top boundary', function () {
  it('is stopped at top boundary', function () {
    // Test bounds
  });
});

describe.skip('An overlay that attempts to extend past left boundary', function () {
  it('is stopped at left boundary', function () {
    // Test bounds
  });
});
describe.skip('An overlay that attempts to extend past right boundary', function () {
  it('is stopped at right boundary', function () {
    // Test bounds
  });
});

describe.skip('An overlay that attempts to extend past bottom boundary', function () {
  it('is stopped at bottom boundary', function () {
    // Test bounds
  });
});

describe.skip('An overlay on a scrolled page', function () {
  it('keeps boundaries relative to element', function () {
    // Test bounds (e.g. we can go to edge in scrolled direction)
  });
});
<commit_msg>Cleaned up test code for reuse<commit_after>// Load in our dependencies
var expect = require('chai').expect;
var D = require('../../browser/js/domo');
var Overlay = require('../../browser/js/overlay');
var domUtils = require('./utils/dom');

// Define our test helpers
var overlayUtils = {
  init: function () {
    // Set up our elements
    before(function createElement () {
      // Create our container element
      this.containerEl = D.DIV();
      document.body.appendChild(this.containerEl);
    });
    after(function cleanup () {
      document.body.removeChild(this.containerEl);
      delete this.containerEl;
    });
    before(function bindOverlay () {
      var el = D.DIV({
        id: 'overlay-container',
        style: 'width: 300px; height: 200px; color: navy'
      });
      this.containerEl.appendChild(el);
      this.overlay = new Overlay(el, {containerEl: this.containerEl});
    });
    after(function cleanup () {
      // TODO: Set up unbinding of overlay
      delete this.overlay;
    });
  }
};

// Start our tests
describe('An overlay over an element', function () {
  // Set up our elements
  overlayUtils.init();

  // Perform our assertions
  it('is not initially visible', function () {
    var overlayEl = this.containerEl.querySelector('.overlay');
    expect(overlayEl).to.equal(null);
  });

  describe('after dragging over our element', function () {
    // Perform overlay drag
    domUtils.dragOverElement({
      selector: '#overlay-container',
      startCoords: {x: 0, y: 0},
      endCoords: {x: 100, y: 100}
    });

    // Perform our assertions
    it('is visible', function () {
      var overlayEl = this.containerEl.querySelector('.overlay');
      expect(overlayEl).to.not.equal(null);
    });
  });
});

describe.skip('An overlay that attempts to extend past top boundary', function () {
  it('is stopped at top boundary', function () {
    // Test bounds
  });
});

describe.skip('An overlay that attempts to extend past left boundary', function () {
  it('is stopped at left boundary', function () {
    // Test bounds
  });
});
describe.skip('An overlay that attempts to extend past right boundary', function () {
  it('is stopped at right boundary', function () {
    // Test bounds
  });
});

describe.skip('An overlay that attempts to extend past bottom boundary', function () {
  it('is stopped at bottom boundary', function () {
    // Test bounds
  });
});

describe.skip('An overlay on a scrolled page', function () {
  it('keeps boundaries relative to element', function () {
    // Test bounds (e.g. we can go to edge in scrolled direction)
  });
});
<|endoftext|>


<commit_before>'use strict'

import test from 'tape'
import { Application } from 'spectron'
import robot from 'robotjs'

function createApp () {
  return new Application({
    path: './node_modules/.bin/electron',
    args: ['./main.js']
  })
}

test('able to open new window', async t => {
  t.plan(1)
  try {
    const app = createApp()
    await app.start()
    robot.keyTap('w', 'control')
    await app.browserWindow.blur()
    await app.webContents.sendInputEvent({
      type: 'char',
      keyCode: 'w'
    })
    const windowCount = await app.client.getWindowCount()
    t.equals(windowCount, 2, 'New window was opened')
  } catch (e) {
    t.fail(e)
  }
})

test.skip('able to move window to all parts of main display', async t => {
  // TBD
})

test.skip('window cannot move up over another window', async t => {
  // TBD
})

test.skip('window cannot move down over another window', async t => {
  // TBD
})

test.skip('window cannot move left over another window', async t => {
  // TBD
})

test.skip('window cannot move right over another window', async t => {
  // TBD
})
<commit_msg>cleanup<commit_after>'use strict'

import test from 'tape'
import { Application } from 'spectron'
import robot from 'robotjs'

function createApp () {
  return new Application({
    path: './node_modules/.bin/electron',
    args: ['./main.js']
  })
}

test('able to open new window', async t => {
  t.plan(1)
  try {
    const app = createApp()
    await app.start()
    robot.keyTap('w', 'control')
    const windowCount = await app.client.getWindowCount()
    t.equals(windowCount, 2, 'New window was opened')
  } catch (e) {
    t.fail(e)
  }
})

test.skip('able to move window to all parts of main display', async t => {
  // TBD
})

test.skip('window cannot move up over another window', async t => {
  // TBD
})

test.skip('window cannot move down over another window', async t => {
  // TBD
})

test.skip('window cannot move left over another window', async t => {
  // TBD
})

test.skip('window cannot move right over another window', async t => {
  // TBD
})
<|endoftext|>


<commit_before>import { stringify } from '../util'
import { getInstanceName } from './index'

export function initEventsBackend (Vue, bridge) {
  let recording = true

  bridge.on('events:toggle-recording', enabled => {
    recording = enabled
  })

  const vueEmit = Vue.prototype.$emit
  Vue.prototype.$emit = function () {
    const res = vueEmit.apply(this, arguments)

    if (recording) {
      const eventName = arguments[0]
      if (!eventName.startsWith('hook:')) {
        bridge.send('event:emit', stringify({
          instanceId: this._uid,
          instanceName: getInstanceName(this._self || this),
          eventName: eventName,
          eventData: arguments[1],
          timestamp: Date.now()
        }))
      }
    }

    return res
  }
}
<commit_msg>Fix broadcasting events with Vue 1.x (#223)<commit_after>import { stringify } from '../util'
import { getInstanceName } from './index'

export function initEventsBackend (Vue, bridge) {
  let recording = true

  bridge.on('events:toggle-recording', enabled => {
    recording = enabled
  })

  const vueEmit = Vue.prototype.$emit
  Vue.prototype.$emit = function () {
    const res = vueEmit.apply(this, arguments)

    if (recording) {
      let eventName = String(arguments[0])
      if (Object.prototype.toString.call(arguments[0]) === '[object Object]' && arguments[0].name) {
        eventName = String(arguments[0].name)
      }
      if (!eventName.startsWith('hook:')) {
        bridge.send('event:emit', stringify({
          instanceId: this._uid,
          instanceName: getInstanceName(this._self || this),
          eventName: eventName,
          eventData: arguments[1],
          timestamp: Date.now()
        }))
      }
    }

    return res
  }
}
<|endoftext|>


<commit_before>'use strict';

describe('Restmod model class:', function() {

  var $httpBackend, restmod, $rootScope, Bike, query;

  beforeEach(module('restmod'));

  beforeEach(inject(function($injector) {
    $httpBackend = $injector.get('$httpBackend');
    restmod = $injector.get('restmod');
    $rootScope = $injector.get('$rootScope');
    Bike = restmod.model('/api/bikes');
    query = Bike.$collection();
  }));

  describe('$send', function() {

    beforeEach(function() {
      $httpBackend.when('GET','/api/bikes/1').respond(200, { last: false });
      $httpBackend.when('GET','/api/bikes/2').respond(200, { last: true });
      $httpBackend.when('GET','/api/bikes/3').respond(404);
    });

    it('should execute request in FIFO order', function() {
      var bike = Bike.$new();
      bike.$send({ method: 'GET', url: '/api/bikes/1' });
      bike.$send({ method: 'GET', url: '/api/bikes/2' });
      $httpBackend.flush();

      expect(bike.$response.data.last).toEqual(true);
    });

    it('should properly update the $status property', function() {
      var bike = Bike.$new();
      expect(bike.$status).toBeUndefined();
      bike.$send({ method: 'GET', url: '/api/bikes/1' });
      expect(bike.$status).toEqual('pending');
      $httpBackend.flush();
      expect(bike.$status).toEqual('ok');

      bike.$send({ method: 'GET', url: '/api/bikes/3' });
      $rootScope.$digest(); // force digest, since this is a second request.
      expect(bike.$status).toEqual('pending');
      $httpBackend.flush();
      expect(bike.$status).toEqual('error');
    });

    it('should properly update the $pending property', function() {
      var bike = Bike.$new();
      expect(bike.$pending).toBeUndefined();
      bike.$send({ method: 'GET', url: '/api/bikes/1' });
      bike.$send({ method: 'GET', url: '/api/bikes/2' });
      expect(bike.$pending.length).toEqual(2);
      $httpBackend.flush();
      expect(bike.$pending.length).toEqual(0);
    });

  });

  describe('$hasPendingRequests', function() {
    it('should return true if there are pending requests', function() {
      var bike = Bike.$new();
      expect(bike.$hasPendingRequests()).toEqual(false);
      bike.$send({ method: 'GET', url: '/api/bikes/1' });
      expect(bike.$hasPendingRequests()).toEqual(true);
      $httpBackend.when('GET','/api/bikes/1').respond(200, {});
      $httpBackend.flush();
      expect(bike.$hasPendingRequests()).toEqual(false);
    });
  });

  describe('$cancel', function() {
    it('should cancel every pending request', function() {
      var bike = Bike.$new();
      bike.$send({ method: 'GET', url: '/api/bikes/1' });
      bike.$send({ method: 'GET', url: '/api/bikes/6' });

      expect(bike.$hasPendingRequests()).toEqual(true);
      bike.$cancel();
      expect(bike.$hasPendingRequests()).toEqual(false);
    });
  });

  describe('$then', function() {
    // TODO!
  });

  describe('$finally', function() {

    it('should be called on success', function() {
      var spy = jasmine.createSpy('callback');

      Bike.$find(1).$finally(spy);

      $httpBackend.when('GET','/api/bikes/1').respond(200, {});
      $httpBackend.flush();
      expect(spy).toHaveBeenCalledWith();
    });

    it('should be called on error', function() {
      var spy = jasmine.createSpy('callback');

      Bike.$find(1).$finally(spy);

      $httpBackend.when('GET','/api/bikes/1').respond(404);
      $httpBackend.flush();
      expect(spy).toHaveBeenCalledWith();
    });
  });

  describe('$on', function() {

    it('should register a callback at instance level', function() {
      var bike1 = Bike.$build(),
          bike2 = Bike.$build(),
          spy = jasmine.createSpy('callback');

      bike1.$on('poke', spy);
      bike2.$dispatch('poke');
      expect(spy).not.toHaveBeenCalled();

      bike1.$dispatch('poke');
      expect(spy).toHaveBeenCalled();
    });
  });

  describe('$dispatch', function() {
    // TODO!
  });

  describe('$decorate', function() {

    it('should register a callback at decorated context level', function() {
      var bike = Bike.$build(), arg;

      bike.$decorate({
        poke: function(_arg) { arg = _arg; }
      }, function() {
        bike.$dispatch('poke', [1]);
      });

      expect(arg).toEqual(1);
      bike.$dispatch('poke', [2]);
      expect(arg).toEqual(1);
    });

    it('should return the decorated function return value', function() {
      var bike = Bike.$build();
      var ret = bike.$decorate({ }, function() {
        return 'hello';
      });

      expect(ret).toEqual('hello');
    });
  });

});

<commit_msg>test(common): adds $send state propagation tests<commit_after>'use strict';

describe('Restmod model class:', function() {

  var $httpBackend, restmod, $rootScope, Bike, query;

  beforeEach(module('restmod'));

  beforeEach(inject(function($injector) {
    $httpBackend = $injector.get('$httpBackend');
    restmod = $injector.get('restmod');
    $rootScope = $injector.get('$rootScope');
    Bike = restmod.model('/api/bikes');
    query = Bike.$collection();
  }));

  describe('$send', function() {

    beforeEach(function() {
      $httpBackend.when('GET','/api/bikes/1').respond(200, { last: false });
      $httpBackend.when('GET','/api/bikes/2').respond(200, { last: true });
      $httpBackend.when('GET','/api/bikes/3').respond(404);
      $httpBackend.when('POST','/api/bikes').respond(422);
    });

    it('should execute request in FIFO order', function() {
      var bike = Bike.$new();
      bike.$send({ method: 'GET', url: '/api/bikes/1' });
      bike.$send({ method: 'GET', url: '/api/bikes/2' });
      $httpBackend.flush();

      expect(bike.$response.data.last).toEqual(true);
    });

    it('should properly update the $status property', function() {
      var bike = Bike.$new();
      expect(bike.$status).toBeUndefined();
      bike.$send({ method: 'GET', url: '/api/bikes/1' });
      expect(bike.$status).toEqual('pending');
      $httpBackend.flush();
      expect(bike.$status).toEqual('ok');

      bike.$send({ method: 'GET', url: '/api/bikes/3' });
      $rootScope.$digest(); // force digest, since this is a second request.
      expect(bike.$status).toEqual('pending');
      $httpBackend.flush();
      expect(bike.$status).toEqual('error');
    });

    it('should properly update the $pending property', function() {
      var bike = Bike.$new();
      expect(bike.$pending).toBeUndefined();
      bike.$send({ method: 'GET', url: '/api/bikes/1' });
      bike.$send({ method: 'GET', url: '/api/bikes/2' });
      expect(bike.$pending.length).toEqual(2);
      $httpBackend.flush();
      expect(bike.$pending.length).toEqual(0);
    });

    it('should properly propagate success states to $then', function() {
      var bike = Bike.$new();
      var spy = jasmine.createSpy('callback');
      bike.$send({ method: 'GET', url: '/api/bikes/2' }).$then(spy, null);
      $httpBackend.flush();
      expect(spy).toHaveBeenCalled();
    });

    it('should properly propagate error states to $then', function() {
      var bike = Bike.$new();
      var spy = jasmine.createSpy('callback');
      bike.$send({ method: 'POST', url: '/api/bikes' }).$then(null, spy);
      $httpBackend.flush();
      expect(spy).toHaveBeenCalled();
    });

  });

  describe('$hasPendingRequests', function() {
    it('should return true if there are pending requests', function() {
      var bike = Bike.$new();
      expect(bike.$hasPendingRequests()).toEqual(false);
      bike.$send({ method: 'GET', url: '/api/bikes/1' });
      expect(bike.$hasPendingRequests()).toEqual(true);
      $httpBackend.when('GET','/api/bikes/1').respond(200, {});
      $httpBackend.flush();
      expect(bike.$hasPendingRequests()).toEqual(false);
    });
  });

  describe('$cancel', function() {
    it('should cancel every pending request', function() {
      var bike = Bike.$new();
      bike.$send({ method: 'GET', url: '/api/bikes/1' });
      bike.$send({ method: 'GET', url: '/api/bikes/6' });

      expect(bike.$hasPendingRequests()).toEqual(true);
      bike.$cancel();
      expect(bike.$hasPendingRequests()).toEqual(false);
    });
  });

  describe('$then', function() {
    // TODO!
  });

  describe('$finally', function() {

    it('should be called on success', function() {
      var spy = jasmine.createSpy('callback');

      Bike.$find(1).$finally(spy);

      $httpBackend.when('GET','/api/bikes/1').respond(200, {});
      $httpBackend.flush();
      expect(spy).toHaveBeenCalledWith();
    });

    it('should be called on error', function() {
      var spy = jasmine.createSpy('callback');

      Bike.$find(1).$finally(spy);

      $httpBackend.when('GET','/api/bikes/1').respond(404);
      $httpBackend.flush();
      expect(spy).toHaveBeenCalledWith();
    });
  });

  describe('$on', function() {

    it('should register a callback at instance level', function() {
      var bike1 = Bike.$build(),
          bike2 = Bike.$build(),
          spy = jasmine.createSpy('callback');

      bike1.$on('poke', spy);
      bike2.$dispatch('poke');
      expect(spy).not.toHaveBeenCalled();

      bike1.$dispatch('poke');
      expect(spy).toHaveBeenCalled();
    });
  });

  describe('$dispatch', function() {
    // TODO!
  });

  describe('$decorate', function() {

    it('should register a callback at decorated context level', function() {
      var bike = Bike.$build(), arg;

      bike.$decorate({
        poke: function(_arg) { arg = _arg; }
      }, function() {
        bike.$dispatch('poke', [1]);
      });

      expect(arg).toEqual(1);
      bike.$dispatch('poke', [2]);
      expect(arg).toEqual(1);
    });

    it('should return the decorated function return value', function() {
      var bike = Bike.$build();
      var ret = bike.$decorate({ }, function() {
        return 'hello';
      });

      expect(ret).toEqual('hello');
    });
  });

});

<|endoftext|>