<commit_before>const async = require('async');

const Events = require('./events.js');
const Logger = require('./logger.js');
const Config = require('./config.js');
const Blockchain = require('../contracts/blockchain.js');
const Compiler = require('../contracts/compiler.js');
const ContractsManager = require('../contracts/contracts.js');
const DeployManager = require('../contracts/deploy_manager.js');
const CodeGenerator = require('../contracts/code_generator.js');
const ServicesMonitor = require('./services_monitor.js');
const Pipeline = require('../pipeline/pipeline.js');
const Watch = require('../pipeline/watch.js');
const LibraryManager = require('../versions/library_manager.js');
const CodeRunner = require('../coderunner/codeRunner.js');
const utils = require('../utils/utils');

class Engine {
  constructor(options) {
    this.env = options.env;
    this.isDev = options.isDev;
    this.client = options.client;
    this.locale = options.locale;
    this.embarkConfig = options.embarkConfig;
    this.interceptLogs = options.interceptLogs;
    this.version = options.version;
    this.logFile = options.logFile;
    this.logLevel = options.logLevel;
    this.events = options.events;
    this.context = options.context;
  }

  init(_options) {
    let self = this;
    let options = _options || {};
    this.events = options.events || this.events || new Events();
    this.logger = options.logger || new Logger({logLevel: options.logLevel || this.logLevel || 'debug', events: this.events, logFile: this.logFile});
    this.config = new Config({env: this.env, logger: this.logger, events: this.events, context: this.context});
    this.config.loadConfigFiles({embarkConfig: this.embarkConfig, interceptLogs: this.interceptLogs});
    this.plugins = this.config.plugins;

    this.servicesMonitor = new ServicesMonitor({events: this.events, logger: this.logger});
    this.servicesMonitor.addCheck('embarkVersion', function (cb) {
      return cb({name: 'Embark ' + self.version, status: 'on'});
    }, 0);

    if (this.interceptLogs || this.interceptLogs === undefined) {
      // this.doInterceptLogs();
    }
  }

  doInterceptLogs() {
    var self = this;
    let context = {};
    context.console = console;

    context.console.log  = function() {
      self.logger.info(utils.normalizeInput(arguments));
    };
    context.console.warn  = function() {
      self.logger.warn(utils.normalizeInput(arguments));
    };
    context.console.info  = function() {
      self.logger.info(utils.normalizeInput(arguments));
    };
    context.console.debug  = function() {
      // TODO: ue JSON.stringify
      self.logger.debug(utils.normalizeInput(arguments));
    };
    context.console.trace  = function() {
      self.logger.trace(utils.normalizeInput(arguments));
    };
    context.console.dir  = function() {
      self.logger.dir(utils.normalizeInput(arguments));
    };
  }

  startMonitor() {
    let self = this;
    if (this.plugins) {
      // --------
      // TODO: this only works for services done on startup
      // --------
      let servicePlugins = this.plugins.getPluginsFor('serviceChecks');
      servicePlugins.forEach(function (plugin) {
        plugin.serviceChecks.forEach(function (pluginCheck) {
          self.servicesMonitor.addCheck(pluginCheck.checkName, pluginCheck.checkFn, pluginCheck.time);
        });
      });
    }
    this.servicesMonitor.startMonitor();
  }

  registerModule(moduleName, options) {
    this.plugins.loadInternalPlugin(moduleName, options);
  }

  startService(serviceName, _options) {
    let options = _options || {};

    let services = {
      "pipeline": this.pipelineService,
      "codeRunner": this.codeRunnerService,
      "codeGenerator": this.codeGeneratorService,
      "deployment": this.deploymentService,
      "fileWatcher": this.fileWatchService,
      "webServer": this.webServerService,
      "namingSystem": this.namingSystem,
      "ipfs": this.ipfsService,
      "web3": this.web3Service,
      "libraryManager": this.libraryManagerService,
      "swarm": this.swarmService
    };

    let service = services[serviceName];

    if (!service) {
      throw new Error("unknown service: " + serviceName);
    }

    // need to be careful with circular references due to passing the web3 object
    //this.logger.trace("calling: " + serviceName + "(" + JSON.stringify(options) + ")");
    return service.apply(this, [options]);
  }

  pipelineService(_options) {
    const self = this;
    this.events.emit("status", "Building Assets");
    const pipeline = new Pipeline({
      buildDir: this.config.buildDir,
      contractsFiles: this.config.contractsFiles,
      assetFiles: this.config.assetFiles,
      events: this.events,
      logger: this.logger,
      plugins: this.plugins
    });

    this.events.on('code-generator-ready', function () {
      self.events.request('code', function (abi, contractsJSON) {
        pipeline.build(abi, contractsJSON, null, () => {
          if (self.watch) {
            self.watch.restart(); // Necessary because changing a file while it is writing can stop it from being watched
          }
          self.events.emit('outputDone');
        });
      });
    });
  }

  codeRunnerService(_options) {
    this.codeRunner = new CodeRunner({
      plugins: this.plugins,
      events: this.events,
      logger: this.logger
    });
  }

  codeGeneratorService(_options) {
    let self = this;

    this.codeGenerator = new CodeGenerator({
      blockchainConfig: self.config.blockchainConfig,
      contractsConfig: self.config.contractsConfig,
      contractsManager: this.contractsManager,
      plugins: self.plugins,
      storageConfig: self.config.storageConfig,
      communicationConfig: self.config.communicationConfig,
      events: self.events
    });
    this.codeGenerator.listenToCommands();

    const generateCode = function () {
      self.codeGenerator.buildEmbarkJS(function() {
        self.events.emit('code-generator-ready');
      });
    };
    const cargo = async.cargo((tasks, callback) => {
      generateCode(tasks[tasks.length - 1].contractsManager);
      self.events.once('outputDone', callback);
    });
    const addToCargo = function (contractsManager) {
      cargo.push({contractsManager});
    };

    this.events.on('contractsDeployed', addToCargo);
    this.events.on('blockchainDisabled', addToCargo);
    this.events.on('asset-changed', addToCargo);
  }

  deploymentService(options) {
    let self = this;

    let compiler = new Compiler({plugins: self.plugins, logger: self.logger});
    this.events.setCommandHandler("compiler:contracts", function(contractFiles, cb) {
      compiler.compile_contracts(contractFiles, cb);
    });

    this.registerModule('solidity', {
      contractDirectories: self.config.contractDirectories
    });
    this.registerModule('vyper', {
      contractDirectories: self.config.contractDirectories
    });
    this.registerModule('profiler', {
      events: this.events,
      logger: this.logger
    });

    this.registerModule('deploytracker', {
    });

    this.registerModule('specialconfigs', {
    });

    this.contractsManager = new ContractsManager({
      contractFiles: this.config.contractsFiles,
      contractsConfig: this.config.contractsConfig,
      logger: this.logger,
      plugins: this.plugins,
      gasLimit: false,
      events: this.events
    });

    this.deployManager = new DeployManager({
      blockchain: this.blockchain,
      trackContracts: options.trackContracts,
      config: this.config,
      logger: this.logger,
      plugins: this.plugins,
      events: this.events,
      contractsManager: this.contractsManager,
      onlyCompile: options.onlyCompile
    });

    this.events.on('file-event', function (fileType) {
      clearTimeout(self.fileTimeout);
      self.fileTimeout = setTimeout(() => {
        // TODO: still need to redeploy contracts because the original contracts
        // config is being corrupted
        if (fileType === 'asset') {
          // Throttle file changes so we re-write only once for all files
          self.events.emit('asset-changed', self.contractsManager);
        }
        // TODO: for now need to deploy on asset changes as well
        // because the contractsManager config is corrupted after a deploy
        if (fileType === 'contract' || fileType === 'config') {
          self.config.reloadConfig();
          self.deployManager.deployContracts(function () {
          });
        }
      }, 50);
    });
  }

  fileWatchService(_options) {
    this.events.emit("status", "Watching for changes");
    this.watch = new Watch({logger: this.logger, events: this.events});
    this.watch.start();
  }

  webServerService() {
    this.registerModule('webserver', {
      addCheck: this.servicesMonitor.addCheck.bind(this.servicesMonitor)
    });
  }

  ipfsService(_options) {
    this.registerModule('ipfs', {
      addCheck: this.servicesMonitor.addCheck.bind(this.servicesMonitor),
      storageConfig: this.config.storageConfig,
      host: _options.host,
      port: _options.port
    });
  }

  swarmService(_options) {
    this.registerModule('swarm', {
      addCheck: this.servicesMonitor.addCheck.bind(this.servicesMonitor),
      storageConfig: this.config.storageConfig,
      // TODO: this should not be needed and should be deducted from the config instead
      // the eth provider is not necessary the same as the swarm one
      bzz: this.blockchain.web3.bzz
    });
  }

  web3Service(options) {
    this.blockchain = new Blockchain({
      contractsConfig: this.config.contractsConfig,
      blockchainConfig: this.config.blockchainConfig,
      addCheck: this.servicesMonitor.addCheck.bind(this.servicesMonitor),
      events: this.events,
      logger: this.logger,
      isDev: this.isDev,
      locale: this.locale,
      web3: options.web3
    });

    this.registerModule('whisper', {
      addCheck: this.servicesMonitor.addCheck.bind(this.servicesMonitor),
      communicationConfig: this.config.communicationConfig,
      // TODO: this should not be needed and should be deducted from the config instead
      // the eth provider is not necessary the same as the whisper one
      web3: this.blockchain.web3
    });
  }

  libraryManagerService(_options) {
    this.libraryManager = new LibraryManager({
      plugins: this.plugins,
      config: this.config
    });
  }

}

module.exports = Engine;
<commit_msg>add missing module init<commit_after>const async = require('async');

const Events = require('./events.js');
const Logger = require('./logger.js');
const Config = require('./config.js');
const Blockchain = require('../contracts/blockchain.js');
const Compiler = require('../contracts/compiler.js');
const ContractsManager = require('../contracts/contracts.js');
const DeployManager = require('../contracts/deploy_manager.js');
const CodeGenerator = require('../contracts/code_generator.js');
const ServicesMonitor = require('./services_monitor.js');
const Pipeline = require('../pipeline/pipeline.js');
const Watch = require('../pipeline/watch.js');
const LibraryManager = require('../versions/library_manager.js');
const CodeRunner = require('../coderunner/codeRunner.js');
const utils = require('../utils/utils');

class Engine {
  constructor(options) {
    this.env = options.env;
    this.isDev = options.isDev;
    this.client = options.client;
    this.locale = options.locale;
    this.embarkConfig = options.embarkConfig;
    this.interceptLogs = options.interceptLogs;
    this.version = options.version;
    this.logFile = options.logFile;
    this.logLevel = options.logLevel;
    this.events = options.events;
    this.context = options.context;
  }

  init(_options) {
    let self = this;
    let options = _options || {};
    this.events = options.events || this.events || new Events();
    this.logger = options.logger || new Logger({logLevel: options.logLevel || this.logLevel || 'debug', events: this.events, logFile: this.logFile});
    this.config = new Config({env: this.env, logger: this.logger, events: this.events, context: this.context});
    this.config.loadConfigFiles({embarkConfig: this.embarkConfig, interceptLogs: this.interceptLogs});
    this.plugins = this.config.plugins;

    this.servicesMonitor = new ServicesMonitor({events: this.events, logger: this.logger});
    this.servicesMonitor.addCheck('embarkVersion', function (cb) {
      return cb({name: 'Embark ' + self.version, status: 'on'});
    }, 0);

    if (this.interceptLogs || this.interceptLogs === undefined) {
      // this.doInterceptLogs();
    }
  }

  doInterceptLogs() {
    var self = this;
    let context = {};
    context.console = console;

    context.console.log  = function() {
      self.logger.info(utils.normalizeInput(arguments));
    };
    context.console.warn  = function() {
      self.logger.warn(utils.normalizeInput(arguments));
    };
    context.console.info  = function() {
      self.logger.info(utils.normalizeInput(arguments));
    };
    context.console.debug  = function() {
      // TODO: ue JSON.stringify
      self.logger.debug(utils.normalizeInput(arguments));
    };
    context.console.trace  = function() {
      self.logger.trace(utils.normalizeInput(arguments));
    };
    context.console.dir  = function() {
      self.logger.dir(utils.normalizeInput(arguments));
    };
  }

  startMonitor() {
    let self = this;
    if (this.plugins) {
      // --------
      // TODO: this only works for services done on startup
      // --------
      let servicePlugins = this.plugins.getPluginsFor('serviceChecks');
      servicePlugins.forEach(function (plugin) {
        plugin.serviceChecks.forEach(function (pluginCheck) {
          self.servicesMonitor.addCheck(pluginCheck.checkName, pluginCheck.checkFn, pluginCheck.time);
        });
      });
    }
    this.servicesMonitor.startMonitor();
  }

  registerModule(moduleName, options) {
    this.plugins.loadInternalPlugin(moduleName, options);
  }

  startService(serviceName, _options) {
    let options = _options || {};

    let services = {
      "pipeline": this.pipelineService,
      "codeRunner": this.codeRunnerService,
      "codeGenerator": this.codeGeneratorService,
      "deployment": this.deploymentService,
      "fileWatcher": this.fileWatchService,
      "webServer": this.webServerService,
      "namingSystem": this.namingSystem,
      "ipfs": this.ipfsService,
      "web3": this.web3Service,
      "libraryManager": this.libraryManagerService,
      "swarm": this.swarmService
    };

    let service = services[serviceName];

    if (!service) {
      throw new Error("unknown service: " + serviceName);
    }

    // need to be careful with circular references due to passing the web3 object
    //this.logger.trace("calling: " + serviceName + "(" + JSON.stringify(options) + ")");
    return service.apply(this, [options]);
  }

  pipelineService(_options) {
    const self = this;
    this.events.emit("status", "Building Assets");
    const pipeline = new Pipeline({
      buildDir: this.config.buildDir,
      contractsFiles: this.config.contractsFiles,
      assetFiles: this.config.assetFiles,
      events: this.events,
      logger: this.logger,
      plugins: this.plugins
    });

    this.events.on('code-generator-ready', function () {
      self.events.request('code', function (abi, contractsJSON) {
        pipeline.build(abi, contractsJSON, null, () => {
          if (self.watch) {
            self.watch.restart(); // Necessary because changing a file while it is writing can stop it from being watched
          }
          self.events.emit('outputDone');
        });
      });
    });
  }

  namingSystem(_options) {
    this.registerModule('ens', {
      logger: this.logger,
      events: this.events,
      web3: this.blockchain.web3,
      namesConfig: this.config.namesystemConfig
    });
  }

  codeRunnerService(_options) {
    this.codeRunner = new CodeRunner({
      plugins: this.plugins,
      events: this.events,
      logger: this.logger
    });
  }

  codeGeneratorService(_options) {
    let self = this;

    this.codeGenerator = new CodeGenerator({
      blockchainConfig: self.config.blockchainConfig,
      contractsConfig: self.config.contractsConfig,
      contractsManager: this.contractsManager,
      plugins: self.plugins,
      storageConfig: self.config.storageConfig,
      communicationConfig: self.config.communicationConfig,
      events: self.events
    });
    this.codeGenerator.listenToCommands();

    const generateCode = function () {
      self.codeGenerator.buildEmbarkJS(function() {
        self.events.emit('code-generator-ready');
      });
    };
    const cargo = async.cargo((tasks, callback) => {
      generateCode(tasks[tasks.length - 1].contractsManager);
      self.events.once('outputDone', callback);
    });
    const addToCargo = function (contractsManager) {
      cargo.push({contractsManager});
    };

    this.events.on('contractsDeployed', addToCargo);
    this.events.on('blockchainDisabled', addToCargo);
    this.events.on('asset-changed', addToCargo);
  }

  deploymentService(options) {
    let self = this;

    let compiler = new Compiler({plugins: self.plugins, logger: self.logger});
    this.events.setCommandHandler("compiler:contracts", function(contractFiles, cb) {
      compiler.compile_contracts(contractFiles, cb);
    });

    this.registerModule('solidity', {
      contractDirectories: self.config.contractDirectories
    });
    this.registerModule('vyper', {
      contractDirectories: self.config.contractDirectories
    });
    this.registerModule('profiler', {
      events: this.events,
      logger: this.logger
    });

    this.registerModule('deploytracker', {
    });

    this.registerModule('specialconfigs', {
    });

    this.contractsManager = new ContractsManager({
      contractFiles: this.config.contractsFiles,
      contractsConfig: this.config.contractsConfig,
      logger: this.logger,
      plugins: this.plugins,
      gasLimit: false,
      events: this.events
    });

    this.deployManager = new DeployManager({
      blockchain: this.blockchain,
      trackContracts: options.trackContracts,
      config: this.config,
      logger: this.logger,
      plugins: this.plugins,
      events: this.events,
      contractsManager: this.contractsManager,
      onlyCompile: options.onlyCompile
    });

    this.events.on('file-event', function (fileType) {
      clearTimeout(self.fileTimeout);
      self.fileTimeout = setTimeout(() => {
        // TODO: still need to redeploy contracts because the original contracts
        // config is being corrupted
        if (fileType === 'asset') {
          // Throttle file changes so we re-write only once for all files
          self.events.emit('asset-changed', self.contractsManager);
        }
        // TODO: for now need to deploy on asset changes as well
        // because the contractsManager config is corrupted after a deploy
        if (fileType === 'contract' || fileType === 'config') {
          self.config.reloadConfig();
          self.deployManager.deployContracts(function () {
          });
        }
      }, 50);
    });
  }

  fileWatchService(_options) {
    this.events.emit("status", "Watching for changes");
    this.watch = new Watch({logger: this.logger, events: this.events});
    this.watch.start();
  }

  webServerService() {
    this.registerModule('webserver', {
      addCheck: this.servicesMonitor.addCheck.bind(this.servicesMonitor)
    });
  }

  ipfsService(_options) {
    this.registerModule('ipfs', {
      addCheck: this.servicesMonitor.addCheck.bind(this.servicesMonitor),
      storageConfig: this.config.storageConfig,
      host: _options.host,
      port: _options.port
    });
  }

  swarmService(_options) {
    this.registerModule('swarm', {
      addCheck: this.servicesMonitor.addCheck.bind(this.servicesMonitor),
      storageConfig: this.config.storageConfig,
      // TODO: this should not be needed and should be deducted from the config instead
      // the eth provider is not necessary the same as the swarm one
      bzz: this.blockchain.web3.bzz
    });
  }

  web3Service(options) {
    this.blockchain = new Blockchain({
      contractsConfig: this.config.contractsConfig,
      blockchainConfig: this.config.blockchainConfig,
      addCheck: this.servicesMonitor.addCheck.bind(this.servicesMonitor),
      events: this.events,
      logger: this.logger,
      isDev: this.isDev,
      locale: this.locale,
      web3: options.web3
    });

    this.registerModule('whisper', {
      addCheck: this.servicesMonitor.addCheck.bind(this.servicesMonitor),
      communicationConfig: this.config.communicationConfig,
      // TODO: this should not be needed and should be deducted from the config instead
      // the eth provider is not necessary the same as the whisper one
      web3: this.blockchain.web3
    });
  }

  libraryManagerService(_options) {
    this.libraryManager = new LibraryManager({
      plugins: this.plugins,
      config: this.config
    });
  }

}

module.exports = Engine;
<|endoftext|>


<commit_before>/**
 * UX Rocket
 * jQuery based accordion
 * @author Bilal Cinarli
 */

(function(factory) {
    'use strict';
    if(typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['jquery'], factory);
    } else if(typeof exports === 'object' && typeof require === 'function') {
        // Browserify
        factory(jQuery);
    } else {
        // Browser globals
        factory(jQuery);
    }
}(function($) {
    var ux,
        rocketName = 'uxrCollapsible',

        defaults = {
            header       : '.collapsible-header',
            content      : '.collapsible-content',
            closeSiblings: false,
            animateWith  : 'css', // css or js
            duration     : 200,

            onReady: false,
            onOpen : false,
            onClose: false
        },
        events = {
            click    : 'click.' + rocketName,
            collapsed: 'uxrcollapsed.' + rocketName,
            expanded : 'uxrexpanded.' + rocketName
        },
        ns = {
            prefix : 'uxr-',
            rocket : 'uxRocket',
            data   : rocketName,
            name   : 'collapsible',
            classes: {
                node   : 'node',
                header : 'header',
                content: 'content',
                ready  : 'ready',
                current: 'current',
                animate: 'animate'
            }
        };

    // Constructor
    var Collapsible = function(el, options, selector) {
        this._name = rocketName;
        this._defaults = defaults;

        this.el = el;
        this.$el = $(el);
        this.options = $.extend(true, {}, defaults, options, this.$el.data());
        this.selector = selector;
        this.siblings = this.$el.siblings(this.selector);

        this.init();
    };

    Collapsible.prototype.init = function() {
        var uxrocket = this.$el.data(ns.rocket) || {};

        this.getChildren();

        // add ready class
        this.handleClasses();
        this.handleChildClasses();

        // register plugin data to rocket
        uxrocket[ns.data] = {hasWrapper: false, ready: utils.getClassname('ready'), selector: this.selector, options: this.options};
        this.$el.data(ns.rocket, uxrocket);

        utils.callback(this.options.onReady);

        this.bindUIActions();
    };

    Collapsible.prototype.handleClasses = function() {
        this.$el.addClass(utils.getClassname('node') + ' ' + utils.getClassname('ready') + ' ' + utils.getClassname('animate') + this.options.animateWith.toUpperCase());
    };

    Collapsible.prototype.handleChildClasses = function() {
        this.$header.addClass(utils.getClassname('header'));
        this.$content.addClass(utils.getClassname('content'));
    };

    Collapsible.prototype.getChildren = function() {
        this.$header = this.$el.find('> ' + this.options.header);
        this.$content = this.$el.find('> ' + this.options.content);
    };

    Collapsible.prototype.bindUIActions = function() {
        var _this = this;

        this.$header.on(events.click, function() {
            _this.toggle();
        });

        this.$el
            .on(events.collapsed, function() {
                utils.callback(_this.options.onClose);
            })
            .on(events.expanded, function() {
                utils.callback(_this.options.onOpen);
            });
    };

    Collapsible.prototype.unbindUIActions = function() {
        this.$el.off('.' + rocketName);
        this.$header.off('.' + rocketName);
    };

    Collapsible.prototype.toggle = function() {
        if(this.options.animateWith === 'js') {
            this.animate();
        }

        if(this.options.closeSiblings) {
            this.closeSiblings();
        }

        this.emitEvent();

        this.$el.toggleClass(utils.getClassname('current'));
    };

    Collapsible.prototype.animate = function() {
        this.$content.slideToggle(this.options.duration);
    };

    Collapsible.prototype.closeSiblings = function() {
        this.siblings.each(function() {
            var $this = $(this),
                collapsible = $this.data(rocketName);

            if(!$this.hasClass(utils.getClassname('current'))){
                return;
            }

            if($this.hasClass(utils.getClassname('animate') + 'JS')) {
                collapsible.$content.slideUp();
            }

            collapsible.emitEvent();
            $this.removeClass(utils.getClassname('current'));
        });
    };

    Collapsible.prototype.emitEvent = function() {
        if(this.$el.hasClass(utils.getClassname('current'))) {
            this.$el.trigger('uxrcollapsed');
        }
        else {
            this.$el.trigger('uxrexpanded');
        }
    };

    var utils = {
        callback: function(fn) {
            // if callback string is function call it directly
            if(typeof fn === 'function') {
                fn.apply(this);
            }

            // if callback defined via data-attribute, call it via new Function
            else {
                if(fn !== false) {
                    var _fn = /([a-zA-Z._$0-9]+)(\(?(.*)?\))?/.exec(fn),
                        _fn_ns = _fn[1].split('.'),
                        _args = _fn[3] ? _fn[3] : '',
                        func = _fn_ns.pop(),
                        context = _fn_ns[0] ? window[_fn_ns[0]] : window;

                    for(var i = 1; i < _fn_ns.length; i++) {
                        context = context[_fn_ns[i]];
                    }

                    return context[func](_args);
                }
            }
        },

        getStringVariable: function(str) {
            var val;
            // check if it is chained
            if(str.indexOf('.') > -1) {
                var chain = str.split('.'),
                    chainVal = window[chain[0]];

                for(var i = 1; i < chain.length; i++) {
                    chainVal = chainVal[chain[i]];
                }

                val = chainVal;
            }

            else {
                val = window[str];
            }

            return val;
        },

        getClassname: function(which) {
            return ns.prefix + ns.name + '-' + ns.classes[which];
        }
    };

    ux = $.fn.collapsible = $.fn.uxrcollapsible = $.uxrcollapsible = function(options) {
        var selector = this.selector;

        return this.each(function() {
            if($.data(this, ns.data)) {
                return;
            }

            // Bind the plugin and attach the instance to data
            $.data(this, ns.data, new Collapsible(this, options, selector));
        });
    };

    // Version
    ux.version = '1.0.0';

    // settings
    ux.settings = defaults;
}));<commit_msg>custom current class option<commit_after>/**
 * UX Rocket
 * jQuery based accordion
 * @author Bilal Cinarli
 */

(function(factory) {
    'use strict';
    if(typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['jquery'], factory);
    } else if(typeof exports === 'object' && typeof require === 'function') {
        // Browserify
        factory(jQuery);
    } else {
        // Browser globals
        factory(jQuery);
    }
}(function($) {
    var ux,
        rocketName = 'uxrCollapsible',

        defaults = {
            header       : '.collapsible-header',
            content      : '.collapsible-content',
            current      : '',
            closeSiblings: false,
            animateWith  : 'css', // css or js
            duration     : 200,

            onReady: false,
            onOpen : false,
            onClose: false
        },
        events = {
            click    : 'click.' + rocketName,
            collapsed: 'uxrcollapsed.' + rocketName,
            expanded : 'uxrexpanded.' + rocketName
        },
        ns = {
            prefix : 'uxr-',
            rocket : 'uxRocket',
            data   : rocketName,
            name   : 'collapsible',
            classes: {
                node   : 'node',
                header : 'header',
                content: 'content',
                ready  : 'ready',
                current: 'current',
                animate: 'animate'
            }
        };

    // Constructor
    var Collapsible = function(el, options, selector) {
        this._name = rocketName;
        this._defaults = defaults;

        this.el = el;
        this.$el = $(el);
        this.options = $.extend(true, {}, defaults, options, this.$el.data());
        this.selector = selector;
        this.siblings = this.$el.siblings(this.selector);

        this.init();
    };

    Collapsible.prototype.init = function() {
        var uxrocket = this.$el.data(ns.rocket) || {};

        this.getChildren();

        // add ready class
        this.handleClasses();
        this.handleChildClasses();

        // register plugin data to rocket
        uxrocket[ns.data] = {hasWrapper: false, ready: utils.getClassname('ready'), selector: this.selector, options: this.options};
        this.$el.data(ns.rocket, uxrocket);

        utils.callback(this.options.onReady);

        this.bindUIActions();
    };

    Collapsible.prototype.handleClasses = function() {
        this.$el.addClass(utils.getClassname('node') + ' ' + utils.getClassname('ready') + ' ' + utils.getClassname('animate') + this.options.animateWith.toUpperCase());
    };

    Collapsible.prototype.handleChildClasses = function() {
        this.$header.addClass(utils.getClassname('header'));
        this.$content.addClass(utils.getClassname('content'));
    };

    Collapsible.prototype.getChildren = function() {
        this.$header = this.$el.find('> ' + this.options.header);
        this.$content = this.$el.find('> ' + this.options.content);
    };

    Collapsible.prototype.bindUIActions = function() {
        var _this = this;

        this.$header.on(events.click, function() {
            _this.toggle();
        });

        this.$el
            .on(events.collapsed, function() {
                utils.callback(_this.options.onClose);
            })
            .on(events.expanded, function() {
                utils.callback(_this.options.onOpen);
            });
    };

    Collapsible.prototype.unbindUIActions = function() {
        this.$el.off('.' + rocketName);
        this.$header.off('.' + rocketName);
    };

    Collapsible.prototype.toggle = function() {
        if(this.options.animateWith === 'js') {
            this.animate();
        }

        if(this.options.closeSiblings) {
            this.closeSiblings();
        }

        this.emitEvent();

        this.$el.toggleClass(utils.getClassname('current') + ' ' + this.options.current);
    };

    Collapsible.prototype.animate = function() {
        this.$content.slideToggle(this.options.duration);
    };

    Collapsible.prototype.closeSiblings = function() {
        var _this = this;

        this.siblings.each(function() {
            var $this = $(this),
                collapsible = $this.data(rocketName);

            if(!$this.hasClass(utils.getClassname('current'))) {
                return;
            }

            if($this.hasClass(utils.getClassname('animate') + 'JS')) {
                collapsible.$content.slideUp();
            }

            collapsible.emitEvent();
            $this.removeClass(utils.getClassname('current') + ' ' + _this.options.current);
        });
    };

    Collapsible.prototype.emitEvent = function() {
        if(this.$el.hasClass(utils.getClassname('current'))) {
            this.$el.trigger('uxrcollapsed');
        }
        else {
            this.$el.trigger('uxrexpanded');
        }
    };

    var utils = {
        callback: function(fn) {
            // if callback string is function call it directly
            if(typeof fn === 'function') {
                fn.apply(this);
            }

            // if callback defined via data-attribute, call it via new Function
            else {
                if(fn !== false) {
                    var _fn = /([a-zA-Z._$0-9]+)(\(?(.*)?\))?/.exec(fn),
                        _fn_ns = _fn[1].split('.'),
                        _args = _fn[3] ? _fn[3] : '',
                        func = _fn_ns.pop(),
                        context = _fn_ns[0] ? window[_fn_ns[0]] : window;

                    for(var i = 1; i < _fn_ns.length; i++) {
                        context = context[_fn_ns[i]];
                    }

                    return context[func](_args);
                }
            }
        },

        getStringVariable: function(str) {
            var val;
            // check if it is chained
            if(str.indexOf('.') > -1) {
                var chain = str.split('.'),
                    chainVal = window[chain[0]];

                for(var i = 1; i < chain.length; i++) {
                    chainVal = chainVal[chain[i]];
                }

                val = chainVal;
            }

            else {
                val = window[str];
            }

            return val;
        },

        getClassname: function(which) {
            return ns.prefix + ns.name + '-' + ns.classes[which];
        }
    };

    ux = $.fn.collapsible = $.fn.uxrcollapsible = $.uxrcollapsible = function(options) {
        var selector = this.selector;

        return this.each(function() {
            if($.data(this, ns.data)) {
                return;
            }

            // Bind the plugin and attach the instance to data
            $.data(this, ns.data, new Collapsible(this, options, selector));
        });
    };

    // Version
    ux.version = '1.0.1';

    // settings
    ux.settings = defaults;
}));<|endoftext|>


<commit_before>
vis.binds.buzzhome.wateringventil = {

    init: function (wid, view, data, style, wType) {

        var $div = $('#' + wid).addClass('buzzhome-wateringventil-Root');
        if (!$div.length) {
            setTimeout(function () {
                vis.binds.buzzhome.wateringventil.init(wid, view, data, style, wType);
            }, 100);
            return;
        }

        //DataHandling
        var _data = { wid: wid, view: view, wType: wType };

        for (var a in data) {
            if (!data.hasOwnProperty(a) || typeof data[a] == 'function') continue;
            if (a[0] != '_') {
                _data[a] = data[a];
            }
        }
        data = _data;

        // if (data.oid) {
        //     data.value = vis.states.attr(data.oid + '.val');
        //     data.ack = vis.states.attr(data.oid + '.ack');
        //     data.lc = vis.states.attr(data.oid + '.lc');
        //     console.log(data.value + ',' + data.ack + ',' + data.lc);

        //     vis.states.bind(data.oid + '.val', function (e, newVal, oldVal) {
        //         //console.log("value SetTemperature changed - old: " + oldVal + " newValue: "+ newVal);
        //         data.value = newVal
        //         $('#buzzhome-SetTemperature').html(data.value + 'ºC');
        //         $("#buzzhome-slider").slider('value', data.value)

        //     });
        // }

        if (data['oid-state']) {
            vis.states.bind(data['oid-state'] + '.val', function (e, newVal, oldVal) {
                data.runcountdown = newVal;

                //$('#humidity-value').html(data.humidity);
                //console.log("value oid-humidity changed - old: " + oldVal + " newValue: "+ newVal);
            });
        }

        if (data['oid-runcountdown']) {
            vis.states.bind(data['oid-runcountdown'] + '.val', function (e, newVal, oldVal) {
                data.runcountdown = newVal;

                var ToggleSwitch = $('.toggle').data('toggles');

                  if (data.runcountdown === true){
                        ToggleSwitch.toggle(true);
                    }
                  else{
                   ToggleSwitch.toggle(false);
                    }
                    console.log("value oid-runcountdown changed - old: " + oldVal + " newValue: "+ newVal);
            });
        }

        if (data['oid-countdown']) {
            vis.states.bind(data['oid-countdown'] + '.val', function (e, newVal, oldVal) {
                data.countdown = newVal;

                var ToggleSwitch = $('.toggle');

                ToggleSwitch.toggleClass('text.on', data.countdown);

                console.log("value oid-countdown changed - old: " + oldVal + " newValue: "+ newVal);
            });
        }

        if (data['oid-state']) data.state = vis.states.attr(data['oid-state'] + '.val');
        if (data['oid-runcountdown']) data.runcountdown = vis.states.attr(data['oid-runcountdown'] + '.val');
        if (data['oid-countdown']) data.countdown = vis.states.attr(data['oid-countdown'] + '.val');

        //console.log("Title: " + data.Title + ", Humidity: " + data.humidity + ", Actual:" + data.actual + ", Battery:" + data.battery + ", Window:" + data.windowstate + ", Mode:" + data.mode);

        var $Title = (data.Title).toString();
        var $PrimaryColor = data.maincolor;
        var $invertColors = data.invertColors;

        //HTML Zeichnen
        vis.binds.buzzhome.wateringventil.draw($div, $Title);

        //Farben zuweisen
        // vis.binds.buzzhome.wandthermostat.setHighlightColor($PrimaryColor, $invertColors);
        //console.log($invertColors);

        // create slider
        //vis.binds.buzzhome.wandthermostat.createSlider($Value, data.oid);

        vis.binds.buzzhome.wateringventil.createToggle(data);

    },

    createToggle: function(data){

        $('.toggle').toggles({
            drag: true,
            click: true,
            on: data.runcountdown,
            text: {
                on: data.countdown,
                off: 'OFF'
                },
            width: 200,
            height: 70,
            type: 'compact'
        });

$('.toggle').on('toggle', function(e, active) {
  if (active) {
        console.log(data.runcountdown, data.countdown, "AKTIV");
        vis.setValue(data['oid-countdown'], 20);
        vis.setValue(data['oid-runcountdown'], true);
  } else {
        console.log(data.runcountdown, data.countdown, "NICHT AKTIV");
        vis.setValue(data['oid-countdown'], 5);
        vis.setValue(data['oid-runcountdown'], false);
  }
});

    },

    setHighlightColor: function (PrimaryColor, invertColors) {

        var Color1 = PrimaryColor;
        var Color2 = vis.binds.buzzhome.colorFunctions.ColorLuminance(PrimaryColor, -0.3);
        var BoxshadowColor = vis.binds.buzzhome.colorFunctions.getDropshadowColor(PrimaryColor, 0.2)

        var Root = $(".buzzhome-wandthermostat-Root");
        var Title = $("#buzzhome-Title");

        if (invertColors == true) {

            Root.css("backgroundColor", PrimaryColor);

            // Root.style.boxShadow = "0px 0px 15px transparent";

            // Root.css("box-shadow", "0px 0px 20px transparent");

            Title.css("color", "#FFFFFF");

        }

        else {

            Title.css("color", PrimaryColor);

            Root.css("backgroundColor", "#FFFFFF");

        }

    },

    secToStr: function (sec) {
        sec = parseInt(sec);
        minuten = parseInt(sec / 60);
        sec = sec % 60;
        stunden = parseInt(minuten / 60);
        minuten = minuten % 60;
        return stunden + ':' + minuten + ':' + sec;
    },

    draw: function (container, title) {
        //Hier wird das HTML zusammengebaut und an den Container übergeben

        var $TitleHtml = '' + title + '';

        var $TableHtml = '
' +
            '
' +
            '' +
            '

'
        '	' +
            '' +
            'Humidity:  test  %
' +
            '	' +
            '
' +
            '
'

        container.append($TitleHtml + $TableHtml);

    }

}<commit_msg>added ToggleText<commit_after>
vis.binds.buzzhome.wateringventil = {

    init: function (wid, view, data, style, wType) {

        var $div = $('#' + wid).addClass('buzzhome-wateringventil-Root');
        if (!$div.length) {
            setTimeout(function () {
                vis.binds.buzzhome.wateringventil.init(wid, view, data, style, wType);
            }, 100);
            return;
        }

        //DataHandling
        var _data = { wid: wid, view: view, wType: wType };

        for (var a in data) {
            if (!data.hasOwnProperty(a) || typeof data[a] == 'function') continue;
            if (a[0] != '_') {
                _data[a] = data[a];
            }
        }
        data = _data;

        // if (data.oid) {
        //     data.value = vis.states.attr(data.oid + '.val');
        //     data.ack = vis.states.attr(data.oid + '.ack');
        //     data.lc = vis.states.attr(data.oid + '.lc');
        //     console.log(data.value + ',' + data.ack + ',' + data.lc);

        //     vis.states.bind(data.oid + '.val', function (e, newVal, oldVal) {
        //         //console.log("value SetTemperature changed - old: " + oldVal + " newValue: "+ newVal);
        //         data.value = newVal
        //         $('#buzzhome-SetTemperature').html(data.value + 'ºC');
        //         $("#buzzhome-slider").slider('value', data.value)

        //     });
        // }

        if (data['oid-state']) {
            vis.states.bind(data['oid-state'] + '.val', function (e, newVal, oldVal) {
                data.runcountdown = newVal;

                //$('#humidity-value').html(data.humidity);
                //console.log("value oid-humidity changed - old: " + oldVal + " newValue: "+ newVal);
            });
        }

        if (data['oid-runcountdown']) {
            vis.states.bind(data['oid-runcountdown'] + '.val', function (e, newVal, oldVal) {
                data.runcountdown = newVal;

                var ToggleSwitch = $('.toggle').data('toggles');

                  if (data.runcountdown === true){
                        ToggleSwitch.toggle(true);
                    }
                  else{
                   ToggleSwitch.toggle(false);
                    }
                    console.log("value oid-runcountdown changed - old: " + oldVal + " newValue: "+ newVal);
            });
        }

        if (data['oid-countdown']) {
            vis.states.bind(data['oid-countdown'] + '.val', function (e, newVal, oldVal) {
                data.countdown = newVal;

                var ToggleSwitch = $('.toggle-on');

                ToggleSwitch.html(data.countdown);

                console.log("value oid-countdown changed - old: " + oldVal + " newValue: "+ newVal);
            });
        }

        if (data['oid-state']) data.state = vis.states.attr(data['oid-state'] + '.val');
        if (data['oid-runcountdown']) data.runcountdown = vis.states.attr(data['oid-runcountdown'] + '.val');
        if (data['oid-countdown']) data.countdown = vis.states.attr(data['oid-countdown'] + '.val');

        //console.log("Title: " + data.Title + ", Humidity: " + data.humidity + ", Actual:" + data.actual + ", Battery:" + data.battery + ", Window:" + data.windowstate + ", Mode:" + data.mode);

        var $Title = (data.Title).toString();
        var $PrimaryColor = data.maincolor;
        var $invertColors = data.invertColors;

        //HTML Zeichnen
        vis.binds.buzzhome.wateringventil.draw($div, $Title);

        //Farben zuweisen
        // vis.binds.buzzhome.wandthermostat.setHighlightColor($PrimaryColor, $invertColors);
        //console.log($invertColors);

        // create slider
        //vis.binds.buzzhome.wandthermostat.createSlider($Value, data.oid);

        vis.binds.buzzhome.wateringventil.createToggle(data);

    },

    createToggle: function(data){

        $('.toggle').toggles({
            drag: true,
            click: true,
            on: data.runcountdown,
            text: {
                on:   data['oid-countdown'] + '.val',
                off: 'OFF'
                },
            width: 200,
            height: 70,
            type: 'compact'
        });

$('.toggle').on('toggle', function(e, active) {
  if (active) {
        console.log(data.runcountdown, data.countdown, "AKTIV");
        vis.setValue(data['oid-countdown'], 20);
        vis.setValue(data['oid-runcountdown'], true);
  } else {
        console.log(data.runcountdown, data.countdown, "NICHT AKTIV");
        vis.setValue(data['oid-countdown'], 5);
        vis.setValue(data['oid-runcountdown'], false);
  }
});

    },

    setHighlightColor: function (PrimaryColor, invertColors) {

        var Color1 = PrimaryColor;
        var Color2 = vis.binds.buzzhome.colorFunctions.ColorLuminance(PrimaryColor, -0.3);
        var BoxshadowColor = vis.binds.buzzhome.colorFunctions.getDropshadowColor(PrimaryColor, 0.2)

        var Root = $(".buzzhome-wandthermostat-Root");
        var Title = $("#buzzhome-Title");

        if (invertColors == true) {

            Root.css("backgroundColor", PrimaryColor);

            // Root.style.boxShadow = "0px 0px 15px transparent";

            // Root.css("box-shadow", "0px 0px 20px transparent");

            Title.css("color", "#FFFFFF");

        }

        else {

            Title.css("color", PrimaryColor);

            Root.css("backgroundColor", "#FFFFFF");

        }

    },

    secToStr: function (sec) {
        sec = parseInt(sec);
        minuten = parseInt(sec / 60);
        sec = sec % 60;
        stunden = parseInt(minuten / 60);
        minuten = minuten % 60;
        return stunden + ':' + minuten + ':' + sec;
    },

    draw: function (container, title) {
        //Hier wird das HTML zusammengebaut und an den Container übergeben

        var $TitleHtml = '' + title + '';

        var $TableHtml = '
' +
            '
' +
            '' +
            '

'
        '	' +
            '' +
            'Humidity:  test  %
' +
            '	' +
            '
' +
            '
'

        container.append($TitleHtml + $TableHtml);

    }

}<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */
'use strict';

var fs = require('fs');
var spawn = require('child_process').spawn;

var firstLaunch = true;

function guessEditor() {
  if (firstLaunch) {
    console.log('When you see Red Box with stack trace, you can click any ' +
      'stack frame to jump to the source file. The packager will launch your ' +
      'editor of choice. It will first look at REACT_EDITOR environment ' +
      'variable, then at EDITOR. To set it up, you can add something like ' +
      'REACT_EDITOR=atom to your .bashrc.');
    firstLaunch = false;
  }

  var editor = process.env.REACT_EDITOR || process.env.EDITOR || 'subl';
  return editor;
}

function launchEditor(fileName, lineNumber) {
  if (!fs.existsSync(fileName)) {
    return;
  }

  var argument = fileName;
  if (lineNumber) {
    argument += ':' + lineNumber;
  }

  var editor = guessEditor();
  console.log('Opening ' + fileName + ' with ' + editor);
  spawn(editor, [argument], { stdio: ['pipe', 'pipe', process.stderr] });
}

module.exports = launchEditor;
<commit_msg>[ReactNative] Fix launchEditor script<commit_after>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */
'use strict';

var chalk = require('chalk');
var fs = require('fs');
var exec = require('child_process').exec;

function printInstructions(title) {
  console.log([
    '',
    chalk.bgBlue.white.bold(' ' + title + ' '),
    '  When you see Red Box with stack trace, you can click any ',
    '  stack frame to jump to the source file. The packager will launch your ',
    '  editor of choice. It will first look at REACT_EDITOR environment ',
    '  variable, then at EDITOR. To set it up, you can add something like ',
    '  REACT_EDITOR=atom to your .bashrc.',
    ''
  ].join('\n'));
}

function launchEditor(fileName, lineNumber) {
  if (!fs.existsSync(fileName)) {
    return;
  }

  var argument = fileName;
  if (lineNumber) {
    argument += ':' + lineNumber;
  }

  var editor = process.env.REACT_EDITOR || process.env.EDITOR;
  if (editor) {
    console.log('Opening ' + chalk.underline(fileName) + ' with ' + chalk.bold(editor));
    exec(editor + ' ' + argument, function(error) {
      if (error) {
        console.log(chalk.red(error.message));
        printInstructions('How to fix');
      }
    });
  } else {
    printInstructions('PRO TIP');
  }
}

module.exports = launchEditor;
<|endoftext|>


<commit_before>// TODO: nothing to build, check parent sources

var fs = require('fs')
	, path = require('path')
	, EventEmitter = require('events').EventEmitter
	, inherit = require('util').inherits
	, async = require('async')
	, extend = require('lodash').extend
	, fileFactory = require('./file')
	, term = require('buddy-term')
	, error = term.error
	, debug = term.debug
	, strong = term.strong
	, colour = term.colour
	, print = term.print
	, warn = term.warn
	, fsutils = require('recur-fs')
	, indir = fsutils.indir
	, readdir = fsutils.readdir
	, mkdir = fsutils.mkdir;

/**
 * Target instance factory
 * @param {Cache} fileCache
 * @param {Object} data
 * @returns {Target}
 */
module.exports = function(fileCache, data) {
	var instance = new Target(fileCache, data);
	return instance;
};

/**
 * Constructor
 * @param {Cache} fileCache
 * @param {Object} options
 */
function Target(fileCache, options) {
/* Decorated properties
	this.type = '';
	this.sources = null;
	this.runtimeOptions = null;
	this.fileCache = null;
	this.fileExtensions = null;
	this.input = '';
	this.output = '';
	this.inputPath = '';
	this.outputPath = '';
	this.workflow = null;
	this.isDir = false;
	this.modular = false;
	this.targets = null;
	this.parent = null;
	this.hasChildren = false;
*/
	extend(this, options);
	this.fileFactoryOptions = {
		type: this.type,
		fileExtensions: this.fileExtensions,
		sources: this.sources,
		runtimeOptions: this.runtimeOptions
	};
	this.fileOptions = {
		filepath: this.outputPath,
		fileCache: fileCache
	};
	this.fileCache = fileCache;
	this.sourceFiles = {}; // All source files
	this.outputFiles = []; // Main output files
	this.outputPaths = []; // Main output paths

	EventEmitter.call(this);

	debug("created "
		+ this.type
		+ " Target instance with input: "
		+ (strong(this.input))
		+ " and output: "
		+ (strong(this.output)), 2);
}

// Inherit
inherit(Target, EventEmitter);

Target.prototype.build = function(fn) {
	var self = this
		, completeHandler = function(err) {
				// Execute 'after' hook
				if (self.after) {
					print('executing AFTER hook...', 3);
					self.executeHook('after', self, function(err) {
						return fn(err, self.outputPaths);
					});
				} else {
					return fn(err, self.outputPaths);
				}
			};
	// reset
	this.sourceFiles = {};
	this.outputFiles = [];
	this.outputPaths = [];
	print("building "
		+ (strong(path.basename(this.inputPath)))
		+ " to "
		+ (strong(path.basename(this.outputPath))), 2);
	// Execute 'before' hook
	if (this.before) {
		print('executing BEFORE hook...', 3);
		this.executeHook('before', this, function(err) {
			if (err) return fn(err);
			self.parse(completeHandler);
		});
	} else {
		this.parse(completeHandler);
	}
};

/**
 * Determine input sourceFiles and start processing
 * @param {Function} fn(err)
 */
Target.prototype.parse = function(fn) {
	var self = this
		, file;
	// Input is directory
	if (this.isDir) {
		// Grab all files
		readdir(this.inputPath, this.fileFilter, null, function(err, files) {
			// Create File instances
			files = files.map(function(file) {
				return self.getFile(file);
			}).filter(function(file) {
				return file != null;
			});
			// Store
			self.outputFiles = files;
			// Process files
			files.length
				? self.process(files, self.workflow, fn)
				: process.nextTick(fn);
		});
	// Input is file
	} else {
		// Create File instance
		file = this.getFile(this.inputPath);
		// Store
		this.outputFiles.push(file);
		// Process
		this.process(this.outputFiles, this.workflow, fn);
	}
};

/**
 * Get unprocessed 'file' instance
 * @param {String} filepath
 * @param {Function} fn(err, file)
 */
Target.prototype.getFile = function(filepath) {
	var file;
	// Only return unprocessed files
	if (!this.hasSource(filepath)) {
		// Create
		if (!this.fileCache.hasFile(filepath)) {
			file = fileFactory(filepath, this.fileFactoryOptions);
			if (file) {
				// Store
				this.sourceFiles[filepath] = file;
				this.fileCache.addFile(file.filepath, file);
				return file;
			} else {
				warn(strong(filepath) + ' not found in project sources', 4);
				return null;
			}
		// Pull from cache and reset
		} else {
			file = this.fileCache.getFile(filepath);
			// Reset in case used by another non-relative target
			file.reset();
			// Store
			this.sourceFiles[filepath] = file;
			return file;
		}
	} else {
		return null;
	}
};

/**
 * Process workflow 'commands'
 * @param {Array} files
 * @param {Array} commands
 * @param {Function} fn(err)
 */
Target.prototype.process = function(files, commands, fn) {
	var self = this;

	// Loop through commands
	async.eachSeries(commands, function(command, cb1) {
		command = command.split(':');
		var context = command[0]
			, cmd = command[1];
		// Handle target level commands
		if (context === 'target') {
			self[cmd](files, cb1);
		} else {
			// Loop through files and apply command
			async.each(files, function(file, cb2) {
				file[cmd](self.fileOptions, cb2);
			}, cb1);
		}
	}, fn);
};

/**
 * Filter 'files' to remove dependencies
 * @param {Array} files
 * @param {Function} fn
 */
Target.prototype.filter = function(files, fn) {
	var i = files.length;
	while(i--) {
		if (files[i].isDependency) files.splice(i, 1);
	}
	fn();
};

/**
 * Resolve dependencies in 'files', generating new instances as needed
 * @param {Array} files
 * @param {Function} fn
 */
Target.prototype.resolve = function(files, fn) {
	var self = this
		, commands = this.workflow.slice(0, this.workflow.indexOf('target:resolve') + 1)
		, outstanding = 0
		, dependencies;
	// Callback
	var cb = function(err) {
		outstanding--;
		if(err) return fn(err);
		if(!outstanding) fn();
	};
	// Loop through files
	files.forEach(function(file) {
		outstanding++;
		// Get all unstored dependency File instances
		dependencies = file.dependencies.map(function(dependency) {
			return self.getFile(dependency.filepath);
		}).filter(function(dependency) {
			return dependency != null;
		});
		// Process
		dependencies.length
			? self.process(dependencies, commands, cb)
			: process.nextTick(cb);
	});
};

/**
 * Write generated content
 * @param {Array} files
 * @param {Function} fn
 */
Target.prototype.write = function(files, fn) {
	var self = this
		, writeHandler = function(cb, filepath) {
				return function(err) {
					if (err) return cb(err);
					// Store
					self.outputPaths.push(filepath);
					cb();
				};
			}
		, filepath;
	async.each(files, function(file, cb) {
		filepath = self.outputPath;
		// Resolve output path if directory
		if (!path.extname(filepath).length) filepath = path.join(filepath, file.id) + '.' + file.type;
		file.outputPath = filepath;
		// Execute 'afterEach' hook
		if (self.afterEach) {
			print('executing AFTER-EACH hook...', 3);
			self.executeHook('afterEach', file, function(err) {
				if (err) return cb(err);
				file.write(writeHandler(cb, file.outputPath));
			});
		} else {
			file.write(writeHandler(cb, file.outputPath));
		}
	}, fn);
};

/**
 * Determine if a File exists in sources, or a parent's if not 'unique'
 * @param {String} filepath
 * @param {Boolean} unique
 * @returns {Boolean}
 */
Target.prototype.hasSource = function(filepath, unique) {
	return this.sourceFiles[filepath] != null
		|| unique ? true : this.hasParent && this.parent.hasSource(filepath);
};

/**
 * Reset modified files
 */
Target.prototype.reset = function() {
	for (var filepath in this.sourceFiles) {
		this.sourceFiles[filepath].reset();
	}
	this.sourceFiles = {};
	if (this.hasParent) this.parent.reset();
};

/**
 * Execute the 'hook' function with a particular 'context'
 * @param {String} hook
 * @param {Object} context
 * @param {Function} callback
 */
Target.prototype.executeHook = function(hook, context, callback) {
	// Make global objects available to the function
	this[hook].call(context, global, process, console, require, context, this.runtimeOptions, callback);
};
<commit_msg>clear identity cache on reset<commit_after>// TODO: nothing to build, check parent sources

var fs = require('fs')
	, path = require('path')
	, EventEmitter = require('events').EventEmitter
	, inherit = require('util').inherits
	, async = require('async')
	, extend = require('lodash').extend
	, fileFactory = require('./file')
	, clearCache = require('identify-resource').clearCache
	, term = require('buddy-term')
	, error = term.error
	, debug = term.debug
	, strong = term.strong
	, colour = term.colour
	, print = term.print
	, warn = term.warn
	, fsutils = require('recur-fs')
	, indir = fsutils.indir
	, readdir = fsutils.readdir
	, mkdir = fsutils.mkdir;

/**
 * Target instance factory
 * @param {Cache} fileCache
 * @param {Object} data
 * @returns {Target}
 */
module.exports = function(fileCache, data) {
	var instance = new Target(fileCache, data);
	return instance;
};

/**
 * Constructor
 * @param {Cache} fileCache
 * @param {Object} options
 */
function Target(fileCache, options) {
/* Decorated properties
	this.type = '';
	this.sources = null;
	this.runtimeOptions = null;
	this.fileCache = null;
	this.fileExtensions = null;
	this.input = '';
	this.output = '';
	this.inputPath = '';
	this.outputPath = '';
	this.workflow = null;
	this.isDir = false;
	this.modular = false;
	this.targets = null;
	this.parent = null;
	this.hasChildren = false;
*/
	extend(this, options);
	this.fileFactoryOptions = {
		type: this.type,
		fileExtensions: this.fileExtensions,
		sources: this.sources,
		runtimeOptions: this.runtimeOptions
	};
	this.fileOptions = {
		filepath: this.outputPath,
		fileCache: fileCache
	};
	this.fileCache = fileCache;
	this.sourceFiles = {}; // All source files
	this.outputFiles = []; // Main output files
	this.outputPaths = []; // Main output paths

	EventEmitter.call(this);

	debug("created "
		+ this.type
		+ " Target instance with input: "
		+ (strong(this.input))
		+ " and output: "
		+ (strong(this.output)), 2);
}

// Inherit
inherit(Target, EventEmitter);

Target.prototype.build = function(fn) {
	var self = this
		, completeHandler = function(err) {
				// Execute 'after' hook
				if (self.after) {
					print('executing AFTER hook...', 3);
					self.executeHook('after', self, function(err) {
						return fn(err, self.outputPaths);
					});
				} else {
					return fn(err, self.outputPaths);
				}
			};
	// reset
	this.sourceFiles = {};
	this.outputFiles = [];
	this.outputPaths = [];
	print("building "
		+ (strong(path.basename(this.inputPath)))
		+ " to "
		+ (strong(path.basename(this.outputPath))), 2);
	// Execute 'before' hook
	if (this.before) {
		print('executing BEFORE hook...', 3);
		this.executeHook('before', this, function(err) {
			if (err) return fn(err);
			self.parse(completeHandler);
		});
	} else {
		this.parse(completeHandler);
	}
};

/**
 * Determine input sourceFiles and start processing
 * @param {Function} fn(err)
 */
Target.prototype.parse = function(fn) {
	var self = this
		, file;
	// Input is directory
	if (this.isDir) {
		// Grab all files
		readdir(this.inputPath, this.fileFilter, null, function(err, files) {
			// Create File instances
			files = files.map(function(file) {
				return self.getFile(file);
			}).filter(function(file) {
				return file != null;
			});
			// Store
			self.outputFiles = files;
			// Process files
			files.length
				? self.process(files, self.workflow, fn)
				: process.nextTick(fn);
		});
	// Input is file
	} else {
		// Create File instance
		file = this.getFile(this.inputPath);
		// Store
		this.outputFiles.push(file);
		// Process
		this.process(this.outputFiles, this.workflow, fn);
	}
};

/**
 * Get unprocessed 'file' instance
 * @param {String} filepath
 * @param {Function} fn(err, file)
 */
Target.prototype.getFile = function(filepath) {
	var file;
	// Only return unprocessed files
	if (!this.hasSource(filepath)) {
		// Create
		if (!this.fileCache.hasFile(filepath)) {
			file = fileFactory(filepath, this.fileFactoryOptions);
			if (file) {
				// Store
				this.sourceFiles[filepath] = file;
				this.fileCache.addFile(file.filepath, file);
				return file;
			} else {
				warn(strong(filepath) + ' not found in project sources', 4);
				return null;
			}
		// Pull from cache and reset
		} else {
			file = this.fileCache.getFile(filepath);
			// Reset in case used by another non-relative target
			file.reset();
			// Store
			this.sourceFiles[filepath] = file;
			return file;
		}
	} else {
		return null;
	}
};

/**
 * Process workflow 'commands'
 * @param {Array} files
 * @param {Array} commands
 * @param {Function} fn(err)
 */
Target.prototype.process = function(files, commands, fn) {
	var self = this;

	// Loop through commands
	async.eachSeries(commands, function(command, cb1) {
		command = command.split(':');
		var context = command[0]
			, cmd = command[1];
		// Handle target level commands
		if (context === 'target') {
			self[cmd](files, cb1);
		} else {
			// Loop through files and apply command
			async.each(files, function(file, cb2) {
				file[cmd](self.fileOptions, cb2);
			}, cb1);
		}
	}, fn);
};

/**
 * Filter 'files' to remove dependencies
 * @param {Array} files
 * @param {Function} fn
 */
Target.prototype.filter = function(files, fn) {
	var i = files.length;
	while(i--) {
		if (files[i].isDependency) files.splice(i, 1);
	}
	fn();
};

/**
 * Resolve dependencies in 'files', generating new instances as needed
 * @param {Array} files
 * @param {Function} fn
 */
Target.prototype.resolve = function(files, fn) {
	var self = this
		, commands = this.workflow.slice(0, this.workflow.indexOf('target:resolve') + 1)
		, outstanding = 0
		, dependencies;
	// Callback
	var cb = function(err) {
		outstanding--;
		if(err) return fn(err);
		if(!outstanding) fn();
	};
	// Loop through files
	files.forEach(function(file) {
		outstanding++;
		// Get all unstored dependency File instances
		dependencies = file.dependencies.map(function(dependency) {
			return self.getFile(dependency.filepath);
		}).filter(function(dependency) {
			return dependency != null;
		});
		// Process
		dependencies.length
			? self.process(dependencies, commands, cb)
			: process.nextTick(cb);
	});
};

/**
 * Write generated content
 * @param {Array} files
 * @param {Function} fn
 */
Target.prototype.write = function(files, fn) {
	var self = this
		, writeHandler = function(cb, filepath) {
				return function(err) {
					if (err) return cb(err);
					// Store
					self.outputPaths.push(filepath);
					cb();
				};
			}
		, filepath;
	async.each(files, function(file, cb) {
		filepath = self.outputPath;
		// Resolve output path if directory
		if (!path.extname(filepath).length) filepath = path.join(filepath, file.id) + '.' + file.type;
		file.outputPath = filepath;
		// Execute 'afterEach' hook
		if (self.afterEach) {
			print('executing AFTER-EACH hook...', 3);
			self.executeHook('afterEach', file, function(err) {
				if (err) return cb(err);
				file.write(writeHandler(cb, file.outputPath));
			});
		} else {
			file.write(writeHandler(cb, file.outputPath));
		}
	}, fn);
};

/**
 * Determine if a File exists in sources, or a parent's if not 'unique'
 * @param {String} filepath
 * @param {Boolean} unique
 * @returns {Boolean}
 */
Target.prototype.hasSource = function(filepath, unique) {
	return this.sourceFiles[filepath] != null
		|| unique ? true : this.hasParent && this.parent.hasSource(filepath);
};

/**
 * Reset modified files
 */
Target.prototype.reset = function() {
	for (var filepath in this.sourceFiles) {
		this.sourceFiles[filepath].reset();
	}
	this.sourceFiles = {};
	if (this.hasParent) this.parent.reset();
	clearCache();
};

/**
 * Execute the 'hook' function with a particular 'context'
 * @param {String} hook
 * @param {Object} context
 * @param {Function} callback
 */
Target.prototype.executeHook = function(hook, context, callback) {
	// Make global objects available to the function
	this[hook].call(context, global, process, console, require, context, this.runtimeOptions, callback);
};
<|endoftext|>


<commit_before>(function(Handsontable){
  var TextEditor = Handsontable.editors.BaseEditor.prototype.extend();

  TextEditor.prototype.init = function(){
    var that = this;
    this.createElements();
    this.eventManager = new Handsontable.eventManager(this);
    this.bindEvents();
    this.autoResize = autoResize();

    this.instance.addHook('afterDestroy', function () {
      that.destroy();
    });
  };

  TextEditor.prototype.getValue = function(){
    return this.TEXTAREA.value
  };

  TextEditor.prototype.setValue = function(newValue){
    this.TEXTAREA.value = newValue;
  };

  var onBeforeKeyDown =  function onBeforeKeyDown(event){

    var instance = this;
    var that = instance.getActiveEditor();

    var keyCodes = Handsontable.helper.keyCode;
    var ctrlDown = (event.ctrlKey || event.metaKey) && !event.altKey; //catch CTRL but not right ALT (which in some systems triggers ALT+CTRL)

    Handsontable.Dom.enableImmediatePropagation(event);

    //Process only events that have been fired in the editor
    if (event.target !== that.TEXTAREA || event.isImmediatePropagationStopped()){
      return;
    }

    if (event.keyCode === 17 || event.keyCode === 224 || event.keyCode === 91 || event.keyCode === 93) {
      //when CTRL or its equivalent is pressed and cell is edited, don't prepare selectable text in textarea
      event.stopImmediatePropagation();
      return;
    }

    switch (event.keyCode) {
      case keyCodes.ARROW_RIGHT:
        if (Handsontable.Dom.getCaretPosition(that.TEXTAREA) !== that.TEXTAREA.value.length) {
          event.stopImmediatePropagation();
        }
        break;

      case keyCodes.ARROW_LEFT: /* arrow left */
        if (Handsontable.Dom.getCaretPosition(that.TEXTAREA) !== 0) {
          event.stopImmediatePropagation();
        }
        break;

      case keyCodes.ENTER:
        var selected = that.instance.getSelected();
        var isMultipleSelection = !(selected[0] === selected[2] && selected[1] === selected[3]);
        if ((ctrlDown && !isMultipleSelection) || event.altKey) { //if ctrl+enter or alt+enter, add new line
          if(that.isOpened()){
            that.setValue(that.getValue() + '\n');
            that.focus();
          } else {
            that.beginEditing(that.originalValue + '\n')
          }
          event.stopImmediatePropagation();
        }
        event.preventDefault(); //don't add newline to field
        break;

      case keyCodes.A:
      case keyCodes.X:
      case keyCodes.C:
      case keyCodes.V:
        if(ctrlDown){
          event.stopImmediatePropagation(); //CTRL+A, CTRL+C, CTRL+V, CTRL+X should only work locally when cell is edited (not in table context)
        }
        break;

      case keyCodes.BACKSPACE:
      case keyCodes.DELETE:
      case keyCodes.HOME:
      case keyCodes.END:
        event.stopImmediatePropagation(); //backspace, delete, home, end should only work locally when cell is edited (not in table context)
        break;
    }

  };

  TextEditor.prototype.open = function(){
    this.refreshDimensions(); //need it instantly, to prevent https://github.com/handsontable/handsontable/issues/348

    this.instance.addHook('beforeKeyDown', onBeforeKeyDown);
  };

  TextEditor.prototype.close = function(){
    this.textareaParentStyle.display = 'none';

    this.autoResize.unObserve();

    if (document.activeElement === this.TEXTAREA) {
      this.instance.listen(); //don't refocus the table if user focused some cell outside of HT on purpose
    }

    this.instance.removeHook('beforeKeyDown', onBeforeKeyDown);
  };

  TextEditor.prototype.focus = function(){
    this.TEXTAREA.focus();
    Handsontable.Dom.setCaretPosition(this.TEXTAREA, this.TEXTAREA.value.length);
  };

  TextEditor.prototype.createElements = function () {
//    this.$body = $(document.body);

    this.TEXTAREA = document.createElement('TEXTAREA');

    Handsontable.Dom.addClass(this.TEXTAREA, 'handsontableInput');

    this.textareaStyle = this.TEXTAREA.style;
    this.textareaStyle.width = 0;
    this.textareaStyle.height = 0;

    this.TEXTAREA_PARENT = document.createElement('DIV');
    Handsontable.Dom.addClass(this.TEXTAREA_PARENT, 'handsontableInputHolder');

    this.textareaParentStyle = this.TEXTAREA_PARENT.style;
    this.textareaParentStyle.top = 0;
    this.textareaParentStyle.left = 0;
    this.textareaParentStyle.display = 'none';

    this.TEXTAREA_PARENT.appendChild(this.TEXTAREA);

    this.instance.rootElement.appendChild(this.TEXTAREA_PARENT);

    var that = this;
    this.instance._registerTimeout(setTimeout(function () {
      that.refreshDimensions();
    }, 0));
  };

  TextEditor.prototype.checkEditorSection = function () {
    if(this.row < this.instance.getSettings().fixedRowsTop) {
      if(this.col < this.instance.getSettings().fixedColumnsLeft) {
        return 'corner';
      } else {
        return 'top';
      }
    } else {
      if(this.col < this.instance.getSettings().fixedColumnsLeft) {
        return 'left';
      }
    }
  };

  TextEditor.prototype.getEditedCell = function () {
    var editorSection = this.checkEditorSection()
      , editedCell;

    switch (editorSection) {
      case 'top':
        editedCell = this.instance.view.wt.wtScrollbars.vertical.clone.wtTable.getCell({row: this.row, col: this.col});
        this.textareaParentStyle.zIndex = 101;
        break;
      case 'corner':
        editedCell = this.instance.view.wt.wtScrollbars.corner.clone.wtTable.getCell({row: this.row, col: this.col});
        this.textareaParentStyle.zIndex = 103;
        break;
      case 'left':
        editedCell = this.instance.view.wt.wtScrollbars.horizontal.clone.wtTable.getCell({row: this.row, col: this.col});
        this.textareaParentStyle.zIndex = 102;
        break;
      default :
        editedCell = this.instance.getCell(this.row, this.col);
        this.textareaParentStyle.zIndex = "";
        break;
    }

    return editedCell != -1 && editedCell != -2 ? editedCell : void 0;
  };

  TextEditor.prototype.refreshDimensions = function () {
    if (this.state !== Handsontable.EditorState.EDITING) {
      return;
    }

    ///start prepare textarea position
//    this.TD = this.instance.getCell(this.row, this.col);
    this.TD = this.getEditedCell();

    if (!this.TD) {
      //TD is outside of the viewport. Otherwise throws exception when scrolling the table while a cell is edited
      return;
    }
    //var $td = $(this.TD); //because old td may have been scrolled out with scrollViewport

    var currentOffset = Handsontable.Dom.offset(this.TD);
    var containerOffset = Handsontable.Dom.offset(this.instance.rootElement);
    var editTop = currentOffset.top - containerOffset.top - 1;
    var editLeft = currentOffset.left - containerOffset.left - 1;

    var settings = this.instance.getSettings();
    var rowHeadersCount = settings.rowHeaders === false ? 0 : 1;
    var colHeadersCount = settings.colHeaders === false ? 0 : 1;
    var editorSection = this.checkEditorSection();
    var cssTransformOffset;

    // TODO: Refactor this to the new instance.getCell method (from #ply-59), after 0.12.1 is released
    switch(editorSection) {
      case 'top':
        cssTransformOffset = Handsontable.Dom.getCssTransform(this.instance.view.wt.wtScrollbars.vertical.clone.wtTable.holder.parentNode);
        break;
      case 'left':
        cssTransformOffset = Handsontable.Dom.getCssTransform(this.instance.view.wt.wtScrollbars.horizontal.clone.wtTable.holder.parentNode);
        break;
      case 'corner':
        cssTransformOffset = Handsontable.Dom.getCssTransform(this.instance.view.wt.wtScrollbars.corner.clone.wtTable.holder.parentNode);
        break;
    }

    if (editTop < 0) {
      editTop = 0;
    }
    if (editLeft < 0) {
      editLeft = 0;
    }
    //if (rowHeadersCount > 0 && parseInt($td.css('border-top-width'), 10) > 0) {
    if (rowHeadersCount > 0 && parseInt(this.TD.style.borderTopWidth, 10) > 0) {
      editTop += 1;
    }
    //if (colHeadersCount > 0 && parseInt($td.css('border-left-width'), 10) > 0) {
    if (colHeadersCount > 0 && parseInt(this.TD.style.borderLeftWidth, 10) > 0) {
      editLeft += 1;
    }

    if(cssTransformOffset && cssTransformOffset != -1) {
      this.textareaParentStyle[cssTransformOffset[0]] = cssTransformOffset[1];
    } else {
      Handsontable.Dom.resetCssTransform(this.textareaParentStyle);
    }

    this.textareaParentStyle.top = editTop + 'px';
    this.textareaParentStyle.left = editLeft + 'px';

    ///end prepare textarea position

    var cellTopOffset = this.TD.offsetTop - this.instance.view.wt.wtScrollbars.vertical.getScrollPosition(),
        cellLeftOffset = this.TD.offsetLeft - this.instance.view.wt.wtScrollbars.horizontal.getScrollPosition();

    var width = Handsontable.Dom.innerWidth(this.TD) - 8  //$td.width()
      , maxWidth = this.instance.view.maximumVisibleElementWidth(cellLeftOffset) - 10 //10 is TEXTAREAs border and padding
      , height = Handsontable.Dom.outerHeight(this.TD) - 4  //$td.outerHeight() - 4
      , maxHeight = this.instance.view.maximumVisibleElementHeight(cellTopOffset) - 2; //10 is TEXTAREAs border and padding

    //if (parseInt($td.css('border-top-width'), 10) > 0) {
    if (parseInt(this.TD.style.borderTopWidth, 10) > 0) {
      height -= 1;
    }
    //if (parseInt($td.css('border-left-width'), 10) > 0) {
    if (parseInt(this.TD.style.borderLeftWidth, 10) > 0) {
      if (rowHeadersCount > 0) {
        width -= 1;
      }
    }

    this.TEXTAREA.style.fontSize = Handsontable.Dom.getComputedStyle(this.TD).fontSize;
    this.TEXTAREA.style.fontFamily = Handsontable.Dom.getComputedStyle(this.TD).fontFamily;

    this.autoResize.init(this.TEXTAREA, {
      minHeight: Math.min(height, maxHeight),
      maxHeight: maxHeight, //TEXTAREA should never be wider than visible part of the viewport (should not cover the scrollbar)
      minWidth: Math.min(width, maxWidth),
      maxWidth: maxWidth //TEXTAREA should never be wider than visible part of the viewport (should not cover the scrollbar)
    });

    this.textareaParentStyle.display = 'block';
  };

  TextEditor.prototype.bindEvents = function () {
    var editor = this;

    this.eventManager.addEventListener(this.TEXTAREA, 'cut',function (event){
      Handsontable.helper.stopPropagation(event);
      //event.stopPropagation();
    });

    this.eventManager.addEventListener(this.TEXTAREA, 'paste', function (event){
      Handsontable.helper.stopPropagation(event);
      //event.stopPropagation();
    });

    this.instance.addHook('afterScrollVertically', function () {
      editor.refreshDimensions();
    });

    this.instance.addHook('afterDestroy', function () {
      eventManager.clear();
    });
  };

  TextEditor.prototype.destroy = function () {
    this.eventManager.clear();
  };

  Handsontable.editors.TextEditor = TextEditor;
  Handsontable.editors.registerEditor('text', Handsontable.editors.TextEditor);

})(Handsontable);
<commit_msg>Quick fix for #1948<commit_after>(function(Handsontable){
  var TextEditor = Handsontable.editors.BaseEditor.prototype.extend();

  TextEditor.prototype.init = function(){
    var that = this;
    this.createElements();
    this.eventManager = new Handsontable.eventManager(this);
    this.bindEvents();
    this.autoResize = autoResize();

    this.instance.addHook('afterDestroy', function () {
      that.destroy();
    });
  };

  TextEditor.prototype.getValue = function(){
    return this.TEXTAREA.value
  };

  TextEditor.prototype.setValue = function(newValue){
    this.TEXTAREA.value = newValue;
  };

  var onBeforeKeyDown =  function onBeforeKeyDown(event){

    var instance = this;
    var that = instance.getActiveEditor();

    var keyCodes = Handsontable.helper.keyCode;
    var ctrlDown = (event.ctrlKey || event.metaKey) && !event.altKey; //catch CTRL but not right ALT (which in some systems triggers ALT+CTRL)

    Handsontable.Dom.enableImmediatePropagation(event);

    //Process only events that have been fired in the editor
    if (event.target !== that.TEXTAREA || event.isImmediatePropagationStopped()){
      return;
    }

    if (event.keyCode === 17 || event.keyCode === 224 || event.keyCode === 91 || event.keyCode === 93) {
      //when CTRL or its equivalent is pressed and cell is edited, don't prepare selectable text in textarea
      event.stopImmediatePropagation();
      return;
    }

    switch (event.keyCode) {
      case keyCodes.ARROW_RIGHT:
        if (Handsontable.Dom.getCaretPosition(that.TEXTAREA) !== that.TEXTAREA.value.length) {
          event.stopImmediatePropagation();
        }
        break;

      case keyCodes.ARROW_LEFT: /* arrow left */
        if (Handsontable.Dom.getCaretPosition(that.TEXTAREA) !== 0) {
          event.stopImmediatePropagation();
        }
        break;

      case keyCodes.ENTER:
        var selected = that.instance.getSelected();
        var isMultipleSelection = !(selected[0] === selected[2] && selected[1] === selected[3]);
        if ((ctrlDown && !isMultipleSelection) || event.altKey) { //if ctrl+enter or alt+enter, add new line
          if(that.isOpened()){
            that.setValue(that.getValue() + '\n');
            that.focus();
          } else {
            that.beginEditing(that.originalValue + '\n')
          }
          event.stopImmediatePropagation();
        }
        event.preventDefault(); //don't add newline to field
        break;

      case keyCodes.A:
      case keyCodes.X:
      case keyCodes.C:
      case keyCodes.V:
        if(ctrlDown){
          event.stopImmediatePropagation(); //CTRL+A, CTRL+C, CTRL+V, CTRL+X should only work locally when cell is edited (not in table context)
        }
        break;

      case keyCodes.BACKSPACE:
      case keyCodes.DELETE:
      case keyCodes.HOME:
      case keyCodes.END:
        event.stopImmediatePropagation(); //backspace, delete, home, end should only work locally when cell is edited (not in table context)
        break;
    }

  };

  TextEditor.prototype.open = function(){
    this.refreshDimensions(); //need it instantly, to prevent https://github.com/handsontable/handsontable/issues/348

    this.instance.addHook('beforeKeyDown', onBeforeKeyDown);
  };

  TextEditor.prototype.close = function(){
    this.textareaParentStyle.display = 'none';

    this.autoResize.unObserve();

    if (document.activeElement === this.TEXTAREA) {
      this.instance.listen(); //don't refocus the table if user focused some cell outside of HT on purpose
    }

    this.instance.removeHook('beforeKeyDown', onBeforeKeyDown);
  };

  TextEditor.prototype.focus = function(){
    this.TEXTAREA.focus();
    Handsontable.Dom.setCaretPosition(this.TEXTAREA, this.TEXTAREA.value.length);
  };

  TextEditor.prototype.createElements = function () {
//    this.$body = $(document.body);

    this.TEXTAREA = document.createElement('TEXTAREA');

    Handsontable.Dom.addClass(this.TEXTAREA, 'handsontableInput');

    this.textareaStyle = this.TEXTAREA.style;
    this.textareaStyle.width = 0;
    this.textareaStyle.height = 0;

    this.TEXTAREA_PARENT = document.createElement('DIV');
    Handsontable.Dom.addClass(this.TEXTAREA_PARENT, 'handsontableInputHolder');

    this.textareaParentStyle = this.TEXTAREA_PARENT.style;
    this.textareaParentStyle.top = 0;
    this.textareaParentStyle.left = 0;
    this.textareaParentStyle.display = 'none';

    this.TEXTAREA_PARENT.appendChild(this.TEXTAREA);

    this.instance.rootElement.appendChild(this.TEXTAREA_PARENT);

    var that = this;
    this.instance._registerTimeout(setTimeout(function () {
      that.refreshDimensions();
    }, 0));
  };

  TextEditor.prototype.checkEditorSection = function () {
    if(this.row < this.instance.getSettings().fixedRowsTop) {
      if(this.col < this.instance.getSettings().fixedColumnsLeft) {
        return 'corner';
      } else {
        return 'top';
      }
    } else {
      if(this.col < this.instance.getSettings().fixedColumnsLeft) {
        return 'left';
      }
    }
  };

  TextEditor.prototype.getEditedCell = function () {
    var editorSection = this.checkEditorSection()
      , editedCell;

    switch (editorSection) {
      case 'top':
        editedCell = this.instance.view.wt.wtScrollbars.vertical.clone.wtTable.getCell({row: this.row, col: this.col});
        this.textareaParentStyle.zIndex = 101;
        break;
      case 'corner':
        editedCell = this.instance.view.wt.wtScrollbars.corner.clone.wtTable.getCell({row: this.row, col: this.col});
        this.textareaParentStyle.zIndex = 103;
        break;
      case 'left':
        editedCell = this.instance.view.wt.wtScrollbars.horizontal.clone.wtTable.getCell({row: this.row, col: this.col});
        this.textareaParentStyle.zIndex = 102;
        break;
      default :
        editedCell = this.instance.getCell(this.row, this.col);
        this.textareaParentStyle.zIndex = "";
        break;
    }

    return editedCell != -1 && editedCell != -2 ? editedCell : void 0;
  };

  TextEditor.prototype.refreshDimensions = function () {
    if (this.state !== Handsontable.EditorState.EDITING) {
      return;
    }

    ///start prepare textarea position
//    this.TD = this.instance.getCell(this.row, this.col);
    this.TD = this.getEditedCell();

    if (!this.TD) {
      //TD is outside of the viewport. Otherwise throws exception when scrolling the table while a cell is edited
      return;
    }
    //var $td = $(this.TD); //because old td may have been scrolled out with scrollViewport

    var currentOffset = Handsontable.Dom.offset(this.TD);
    var containerOffset = Handsontable.Dom.offset(this.instance.rootElement);
    var editTop = currentOffset.top - containerOffset.top - 1;
    var editLeft = currentOffset.left - containerOffset.left - 1;

    var settings = this.instance.getSettings();
    var rowHeadersCount = settings.rowHeaders === false ? 0 : 1;
    var colHeadersCount = settings.colHeaders === false ? 0 : 1;
    var editorSection = this.checkEditorSection();
    var cssTransformOffset;

    // TODO: Refactor this to the new instance.getCell method (from #ply-59), after 0.12.1 is released
    switch(editorSection) {
      case 'top':
        cssTransformOffset = Handsontable.Dom.getCssTransform(this.instance.view.wt.wtScrollbars.vertical.clone.wtTable.holder.parentNode);
        break;
      case 'left':
        cssTransformOffset = Handsontable.Dom.getCssTransform(this.instance.view.wt.wtScrollbars.horizontal.clone.wtTable.holder.parentNode);
        break;
      case 'corner':
        cssTransformOffset = Handsontable.Dom.getCssTransform(this.instance.view.wt.wtScrollbars.corner.clone.wtTable.holder.parentNode);
        break;
    }

    if (editTop < 0) {
      editTop = 0;
    }
    if (editLeft < 0) {
      editLeft = 0;
    }
    //if (rowHeadersCount > 0 && parseInt($td.css('border-top-width'), 10) > 0) {
    if (rowHeadersCount > 0 && parseInt(this.TD.style.borderTopWidth, 10) > 0) {
      editTop += 1;
    }
    //if (colHeadersCount > 0 && parseInt($td.css('border-left-width'), 10) > 0) {
    if (colHeadersCount > 0 && parseInt(this.TD.style.borderLeftWidth, 10) > 0) {
      editLeft += 1;
    }

    if(cssTransformOffset && cssTransformOffset != -1) {
      this.textareaParentStyle[cssTransformOffset[0]] = cssTransformOffset[1];
    } else {
      Handsontable.Dom.resetCssTransform(this.textareaParentStyle);
    }

    this.textareaParentStyle.top = editTop + 'px';
    this.textareaParentStyle.left = editLeft + 'px';

    ///end prepare textarea position

    var cellTopOffset = this.TD.offsetTop - this.instance.view.wt.wtScrollbars.vertical.getScrollPosition(),
        cellLeftOffset = this.TD.offsetLeft - this.instance.view.wt.wtScrollbars.horizontal.getScrollPosition();

    var width = Handsontable.Dom.innerWidth(this.TD) - 8  //$td.width()
      , maxWidth = this.instance.view.maximumVisibleElementWidth(cellLeftOffset) - 10 //10 is TEXTAREAs border and padding
      , height = Handsontable.Dom.outerHeight(this.TD) - 4  //$td.outerHeight() - 4
      , maxHeight = this.instance.view.maximumVisibleElementHeight(cellTopOffset) - 2; //10 is TEXTAREAs border and padding

    //if (parseInt($td.css('border-top-width'), 10) > 0) {
    if (parseInt(this.TD.style.borderTopWidth, 10) > 0) {
      height -= 1;
    }
    //if (parseInt($td.css('border-left-width'), 10) > 0) {
    if (parseInt(this.TD.style.borderLeftWidth, 10) > 0) {
      if (rowHeadersCount > 0) {
        width -= 1;
      }
    }

    this.TEXTAREA.style.fontSize = Handsontable.Dom.getComputedStyle(this.TD).fontSize;
    this.TEXTAREA.style.fontFamily = Handsontable.Dom.getComputedStyle(this.TD).fontFamily;

    this.autoResize.init(this.TEXTAREA, {
      minHeight: Math.min(height, maxHeight),
      maxHeight: maxHeight, //TEXTAREA should never be wider than visible part of the viewport (should not cover the scrollbar)
      minWidth: Math.min(width, maxWidth),
      maxWidth: maxWidth //TEXTAREA should never be wider than visible part of the viewport (should not cover the scrollbar)
    });

    this.textareaParentStyle.display = 'block';
  };

  TextEditor.prototype.bindEvents = function () {
    var editor = this;

    this.eventManager.addEventListener(this.TEXTAREA, 'cut',function (event){
      Handsontable.helper.stopPropagation(event);
      //event.stopPropagation();
    });

    this.eventManager.addEventListener(this.TEXTAREA, 'paste', function (event){
      Handsontable.helper.stopPropagation(event);
      //event.stopPropagation();
    });

    this.instance.addHook('afterScrollVertically', function () {
      editor.refreshDimensions();
    });

    this.instance.addHook('afterDestroy', function () {
      editor.eventManager.clear();
    });
  };

  TextEditor.prototype.destroy = function () {
    this.eventManager.clear();
  };

  Handsontable.editors.TextEditor = TextEditor;
  Handsontable.editors.registerEditor('text', Handsontable.editors.TextEditor);

})(Handsontable);
<|endoftext|>