<commit_before>var _ = require('lodash');
var fs = require('fs');
var util = require('../../core/util');
var config = util.getConfig();
var dirs = util.dirs();
var log = require(dirs.core + 'log');

var ENV = util.gekkoEnv();
var mode = util.gekkoMode();
var startTime = util.getStartTime();

if(config.tradingAdvisor.talib.enabled) {
  // verify talib is installed properly
  var pluginHelper = require(dirs.core + 'pluginUtil');
  var pluginMock = {
    slug: 'tradingAdvisor',
    dependencies: [{
      module: 'talib',
      version: config.tradingAdvisor.talib.version
    }]
  };

  var cannotLoad = pluginHelper.cannotLoad(pluginMock);
  if(cannotLoad)
    util.die(cannotLoad);

  var talib = require(dirs.core + 'talib');
}

if(config.tradingAdvisor.tulind.enabled) {
  // verify talib is installed properly
  var pluginHelper = require(dirs.core + 'pluginUtil');
  var pluginMock = {
    slug: 'tradingAdvisor',
    dependencies: [{
      module: 'tulind',
      version: config.tradingAdvisor.tulind.version
    }]
  };

  var cannotLoad = pluginHelper.cannotLoad(pluginMock);
  if(cannotLoad)
    util.die(cannotLoad);

  var tulind = require(dirs.core + 'tulind');
}

var indicatorsPath = dirs.methods + 'indicators/';

var indicatorFiles = fs.readdirSync(indicatorsPath);
var Indicators = {};

_.each(indicatorFiles, function(indicator){

    var indicatorName = indicator.split('.')[0];
    if (indicatorName[0] != '_')
        Indicators[indicatorName] = require(indicatorsPath + indicator);
});

var allowedIndicators = _.keys(Indicators);
var allowedTalibIndicators = _.keys(talib);
var allowedTulipIndicators = _.keys(tulind);

var Base = function(settings) {
  _.bindAll(this);

  // properties
  this.age = 0;
  this.processedTicks = 0;
  this.setup = false;
  this.settings = settings;
  this.tradingAdvisor = config.tradingAdvisor;
  // defaults
  this.requiredHistory = 0;
  this.priceValue = 'close';
  this.indicators = {};
  this.talibIndicators = {};
  this.tulipIndicators = {};
  this.asyncTick = false;
  this.candlePropsCacheSize = 1000;
  this.deferredTicks = [];

  this._prevAdvice;

  this.candleProps = {
    open: [],
    high: [],
    low: [],
    close: [],
    volume: [],
    vwp: [],
    trades: []
  };

  // make sure we have all methods
  _.each(['init', 'check'], function(fn) {
    if(!this[fn])
      util.die('No ' + fn + ' function in this trading method found.')
  }, this);

  if(!this.update)
    this.update = function() {};

  if(!this.end)
    this.end = function() {};

  // let's run the implemented starting point
  this.init();

  if(!config.debug || !this.log)
    this.log = function() {};

  this.setup = true;

  if(_.size(this.talibIndicators) || _.size(this.tulipIndicators))
    this.asyncTick = true;

  if(_.size(this.indicators))
    this.hasSyncIndicators = true;
}

// teach our base trading method events
util.makeEventEmitter(Base);

Base.prototype.tick = function(candle) {

  if(
    this.asyncTick &&
    this.hasSyncIndicators &&
    this.age !== this.processedTicks
  ) {
    // Gekko will call talib and run strat
    // functions when talib is done, but by
    // this time the sync indicators might be
    // updated with future candles.
    //
    // See @link: https://github.com/askmike/gekko/issues/837#issuecomment-316549691
    return this.deferredTicks.push(candle);
  }

  this.age++;

  if(this.asyncTick) {
    this.candleProps.open.push(candle.open);
    this.candleProps.high.push(candle.high);
    this.candleProps.low.push(candle.low);
    this.candleProps.close.push(candle.close);
    this.candleProps.volume.push(candle.volume);
    this.candleProps.vwp.push(candle.vwp);
    this.candleProps.trades.push(candle.trades);

    if(this.age > this.candlePropsCacheSize) {
      this.candleProps.open.shift();
      this.candleProps.high.shift();
      this.candleProps.low.shift();
      this.candleProps.close.shift();
      this.candleProps.volume.shift();
      this.candleProps.vwp.shift();
      this.candleProps.trades.shift();
    }
  }

  // update all indicators
  var price = candle[this.priceValue];
  _.each(this.indicators, function(i) {
    if(i.input === 'price')
      i.update(price);
    if(i.input === 'candle')
      i.update(candle);
  },this);

  // update the trading method
  if(!this.asyncTick) {
    this.propogateTick(candle);
  } else {

    var next = _.after(
      _.size(this.talibIndicators) + _.size(this.tulipIndicators),
      () => this.propogateTick(candle)
    );

    var basectx = this;

    // handle result from talib
    var talibResultHander = function(err, result) {
      if(err)
        util.die('TALIB ERROR:', err);

      // fn is bound to indicator
      this.result = _.mapValues(result, v => _.last(v));
      next(candle);
    }

    // handle result from talib
    _.each(
      this.talibIndicators,
      indicator => indicator.run(
        basectx.candleProps,
        talibResultHander.bind(indicator)
      )
    );

    // handle result from tulip
    var tulindResultHander = function(err, result) {
      if(err)
        util.die('TULIP ERROR:', err);

      // fn is bound to indicator
      this.result = _.mapValues(result, v => _.last(v));
      next(candle);
    }

    // handle result from tulip indicators
    _.each(
      this.tulipIndicators,
      indicator => indicator.run(
        basectx.candleProps,
        tulindResultHander.bind(indicator)
      )
    );
  }

  this.propogateCustomCandle(candle);
}

// if this is a child process the parent might
// be interested in the custom candle.
if(ENV !== 'child-process') {
  Base.prototype.propogateCustomCandle = _.noop;
} else {
  Base.prototype.propogateCustomCandle = function(candle) {
    process.send({
      type: 'candle',
      candle: candle
    });
  }
}

Base.prototype.propogateTick = function(candle) {
  this.candle = candle;

  this.update(candle);

  var isAllowedToCheck = this.requiredHistory <= this.age;

  // in live mode we might receive more candles
  // than minimally needed. In that case check
  // whether candle start time is > startTime
  var isPremature;
  if(mode === 'realtime')
    isPremature = candle.start < startTime;
  else
    isPremature = false;

  if(isAllowedToCheck && !isPremature) {
    this.log(candle);
    this.check(candle);
  }
  this.processedTicks++;

  if(
    this.asyncTick &&
    this.hasSyncIndicators &&
    this.deferredTicks.length
  ) {
    return this.tick(this.deferredTicks.shift())
  }

  // are we totally finished?
  var done = this.age === this.processedTicks;
  if(done && this.finishCb)
    this.finishCb();
}

Base.prototype.addTalibIndicator = function(name, type, parameters) {
  if(!talib)
    util.die('Talib is not enabled');

  if(!_.contains(allowedTalibIndicators, type))
    util.die('I do not know the talib indicator ' + type);

  if(this.setup)
    util.die('Can only add talib indicators in the init method!');

  var basectx = this;

  this.talibIndicators[name] = {
    run: talib[type].create(parameters),
    result: NaN
  }
}

Base.prototype.addTulipIndicator = function(name, type, parameters) {
  if(!tulind)
  util.die('Tulip indicators is not enabled');

  if(!_.contains(allowedTulipIndicators, type))
    util.die('I do not know the tulip indicator ' + type);

  if(this.setup)
    util.die('Can only add tulip indicators in the init method!');

  var basectx = this;

  this.tulipIndicators[name] = {
    run: tulind[type].create(parameters),
    result: NaN
  }
}

Base.prototype.addIndicator = function(name, type, parameters) {
  if(!_.contains(allowedIndicators, type))
    util.die('I do not know the indicator ' + type);

  if(this.setup)
    util.die('Can only add indicators in the init method!');

  this.indicators[name] = new Indicators[type](parameters);

  // some indicators need a price stream, others need full candles
}

Base.prototype.advice = function(newPosition, _candle) {
  // ignore soft advice coming from legacy
  // strategies.
  if(!newPosition)
    return;

  // ignore if advice equals previous advice
  if(newPosition === this._prevAdvice)
    return;

  // cache the candle this advice is based on
  if(_candle)
    var candle = _candle;
  else
    var candle = this.candle;

  this._prevAdvice = newPosition;

  _.defer(function() {
    this.emit('advice', {
      recommendation: newPosition,
      portfolio: 1,
      candle
    });
  }.bind(this));
}

// Because the trading method might be async we need
// to be sure we only stop after all candles are
// processed.
Base.prototype.finish = function(done) {
  if(!this.asyncTick) {
    this.end();
    return done();
  }

  if(this.age === this.processedTicks) {
    this.end();
    return done();
  }

  // we are not done, register cb
  // and call after we are..
  this.finishCb = done;
}

module.exports = Base;
<commit_msg>catch error<commit_after>var _ = require('lodash');
var fs = require('fs');
var util = require('../../core/util');
var config = util.getConfig();
var dirs = util.dirs();
var log = require(dirs.core + 'log');

var ENV = util.gekkoEnv();
var mode = util.gekkoMode();
var startTime = util.getStartTime();

if(config.tradingAdvisor.talib.enabled) {
  // verify talib is installed properly
  var pluginHelper = require(dirs.core + 'pluginUtil');
  var pluginMock = {
    slug: 'tradingAdvisor',
    dependencies: [{
      module: 'talib',
      version: config.tradingAdvisor.talib.version
    }]
  };

  var cannotLoad = pluginHelper.cannotLoad(pluginMock);
  if(cannotLoad)
    util.die(cannotLoad);

  var talib = require(dirs.core + 'talib');
}

if(config.tradingAdvisor.tulind.enabled) {
  // verify talib is installed properly
  var pluginHelper = require(dirs.core + 'pluginUtil');
  var pluginMock = {
    slug: 'tradingAdvisor',
    dependencies: [{
      module: 'tulind',
      version: config.tradingAdvisor.tulind.version
    }]
  };

  var cannotLoad = pluginHelper.cannotLoad(pluginMock);
  if(cannotLoad)
    util.die(cannotLoad);

  var tulind = require(dirs.core + 'tulind');
}

var indicatorsPath = dirs.methods + 'indicators/';

var indicatorFiles = fs.readdirSync(indicatorsPath);
var Indicators = {};

_.each(indicatorFiles, function(indicator){

    var indicatorName = indicator.split('.')[0];
    if (indicatorName[0] != '_')
	try {
	    Indicators[indicatorName] = require(indicatorsPath + indicator);
        }
        catch(e) {
        log.error('Failed to load indicator', indicatorName);
        }
});

var allowedIndicators = _.keys(Indicators);
var allowedTalibIndicators = _.keys(talib);
var allowedTulipIndicators = _.keys(tulind);

var Base = function(settings) {
  _.bindAll(this);

  // properties
  this.age = 0;
  this.processedTicks = 0;
  this.setup = false;
  this.settings = settings;
  this.tradingAdvisor = config.tradingAdvisor;
  // defaults
  this.requiredHistory = 0;
  this.priceValue = 'close';
  this.indicators = {};
  this.talibIndicators = {};
  this.tulipIndicators = {};
  this.asyncTick = false;
  this.candlePropsCacheSize = 1000;
  this.deferredTicks = [];

  this._prevAdvice;

  this.candleProps = {
    open: [],
    high: [],
    low: [],
    close: [],
    volume: [],
    vwp: [],
    trades: []
  };

  // make sure we have all methods
  _.each(['init', 'check'], function(fn) {
    if(!this[fn])
      util.die('No ' + fn + ' function in this trading method found.')
  }, this);

  if(!this.update)
    this.update = function() {};

  if(!this.end)
    this.end = function() {};

  // let's run the implemented starting point
  this.init();

  if(!config.debug || !this.log)
    this.log = function() {};

  this.setup = true;

  if(_.size(this.talibIndicators) || _.size(this.tulipIndicators))
    this.asyncTick = true;

  if(_.size(this.indicators))
    this.hasSyncIndicators = true;
}

// teach our base trading method events
util.makeEventEmitter(Base);

Base.prototype.tick = function(candle) {

  if(
    this.asyncTick &&
    this.hasSyncIndicators &&
    this.age !== this.processedTicks
  ) {
    // Gekko will call talib and run strat
    // functions when talib is done, but by
    // this time the sync indicators might be
    // updated with future candles.
    //
    // See @link: https://github.com/askmike/gekko/issues/837#issuecomment-316549691
    return this.deferredTicks.push(candle);
  }

  this.age++;

  if(this.asyncTick) {
    this.candleProps.open.push(candle.open);
    this.candleProps.high.push(candle.high);
    this.candleProps.low.push(candle.low);
    this.candleProps.close.push(candle.close);
    this.candleProps.volume.push(candle.volume);
    this.candleProps.vwp.push(candle.vwp);
    this.candleProps.trades.push(candle.trades);

    if(this.age > this.candlePropsCacheSize) {
      this.candleProps.open.shift();
      this.candleProps.high.shift();
      this.candleProps.low.shift();
      this.candleProps.close.shift();
      this.candleProps.volume.shift();
      this.candleProps.vwp.shift();
      this.candleProps.trades.shift();
    }
  }

  // update all indicators
  var price = candle[this.priceValue];
  _.each(this.indicators, function(i) {
    if(i.input === 'price')
      i.update(price);
    if(i.input === 'candle')
      i.update(candle);
  },this);

  // update the trading method
  if(!this.asyncTick) {
    this.propogateTick(candle);
  } else {

    var next = _.after(
      _.size(this.talibIndicators) + _.size(this.tulipIndicators),
      () => this.propogateTick(candle)
    );

    var basectx = this;

    // handle result from talib
    var talibResultHander = function(err, result) {
      if(err)
        util.die('TALIB ERROR:', err);

      // fn is bound to indicator
      this.result = _.mapValues(result, v => _.last(v));
      next(candle);
    }

    // handle result from talib
    _.each(
      this.talibIndicators,
      indicator => indicator.run(
        basectx.candleProps,
        talibResultHander.bind(indicator)
      )
    );

    // handle result from tulip
    var tulindResultHander = function(err, result) {
      if(err)
        util.die('TULIP ERROR:', err);

      // fn is bound to indicator
      this.result = _.mapValues(result, v => _.last(v));
      next(candle);
    }

    // handle result from tulip indicators
    _.each(
      this.tulipIndicators,
      indicator => indicator.run(
        basectx.candleProps,
        tulindResultHander.bind(indicator)
      )
    );
  }

  this.propogateCustomCandle(candle);
}

// if this is a child process the parent might
// be interested in the custom candle.
if(ENV !== 'child-process') {
  Base.prototype.propogateCustomCandle = _.noop;
} else {
  Base.prototype.propogateCustomCandle = function(candle) {
    process.send({
      type: 'candle',
      candle: candle
    });
  }
}

Base.prototype.propogateTick = function(candle) {
  this.candle = candle;

  this.update(candle);

  var isAllowedToCheck = this.requiredHistory <= this.age;

  // in live mode we might receive more candles
  // than minimally needed. In that case check
  // whether candle start time is > startTime
  var isPremature;
  if(mode === 'realtime')
    isPremature = candle.start < startTime;
  else
    isPremature = false;

  if(isAllowedToCheck && !isPremature) {
    this.log(candle);
    this.check(candle);
  }
  this.processedTicks++;

  if(
    this.asyncTick &&
    this.hasSyncIndicators &&
    this.deferredTicks.length
  ) {
    return this.tick(this.deferredTicks.shift())
  }

  // are we totally finished?
  var done = this.age === this.processedTicks;
  if(done && this.finishCb)
    this.finishCb();
}

Base.prototype.addTalibIndicator = function(name, type, parameters) {
  if(!talib)
    util.die('Talib is not enabled');

  if(!_.contains(allowedTalibIndicators, type))
    util.die('I do not know the talib indicator ' + type);

  if(this.setup)
    util.die('Can only add talib indicators in the init method!');

  var basectx = this;

  this.talibIndicators[name] = {
    run: talib[type].create(parameters),
    result: NaN
  }
}

Base.prototype.addTulipIndicator = function(name, type, parameters) {
  if(!tulind)
  util.die('Tulip indicators is not enabled');

  if(!_.contains(allowedTulipIndicators, type))
    util.die('I do not know the tulip indicator ' + type);

  if(this.setup)
    util.die('Can only add tulip indicators in the init method!');

  var basectx = this;

  this.tulipIndicators[name] = {
    run: tulind[type].create(parameters),
    result: NaN
  }
}

Base.prototype.addIndicator = function(name, type, parameters) {
  if(!_.contains(allowedIndicators, type))
    util.die('I do not know the indicator ' + type);

  if(this.setup)
    util.die('Can only add indicators in the init method!');

  this.indicators[name] = new Indicators[type](parameters);

  // some indicators need a price stream, others need full candles
}

Base.prototype.advice = function(newPosition, _candle) {
  // ignore soft advice coming from legacy
  // strategies.
  if(!newPosition)
    return;

  // ignore if advice equals previous advice
  if(newPosition === this._prevAdvice)
    return;

  // cache the candle this advice is based on
  if(_candle)
    var candle = _candle;
  else
    var candle = this.candle;

  this._prevAdvice = newPosition;

  _.defer(function() {
    this.emit('advice', {
      recommendation: newPosition,
      portfolio: 1,
      candle
    });
  }.bind(this));
}

// Because the trading method might be async we need
// to be sure we only stop after all candles are
// processed.
Base.prototype.finish = function(done) {
  if(!this.asyncTick) {
    this.end();
    return done();
  }

  if(this.age === this.processedTicks) {
    this.end();
    return done();
  }

  // we are not done, register cb
  // and call after we are..
  this.finishCb = done;
}

module.exports = Base;
<|endoftext|>


<commit_before>/* ************************************************************************

   qooxdoo - the new era of web development

   http://qooxdoo.org

   Copyright:
     2020 Henner Kollmann

   License:
     MIT: https://opensource.org/licenses/MIT
     See the LICENSE file in the project"s top-level directory for details.

************************************************************************ */
require("./Serve");

const fs = require("fs");
const path = require("path");
const process = require("process");

/**
 * Compiles the project, serves it up as a web page (default, can be turned off),
 * and dispatches the "runTests" event. All tests that should be run need to
 * register an event handler. The handlers are called with a {@link qx.even.type.Data}
 * containing the command instance.
 *
 * A test can write to the (native) `errorCode` property of this instance,
 * which is used to determine the exit code of the `qx test` command.
 * This means, however, that the last run test overwrites the
 * `errorCode` of any previous test, and has to take care of this.
 *
 * A more scalable solution is to  call {@link
  * qx.tool.cli.commands.Test#registerTest} with an
 * instance of {@link qx.tool.cli.api.Test} and then
 * set the `exitCode` qx property of that instance.
 */
qx.Class.define("qx.tool.cli.commands.Test", {
  extend: qx.tool.cli.commands.Serve,

  statics: {

    /**
     * The name of the file containing the compile config for the testrunner
     * defaults to "compile-test.json"
     */
    CONFIG_FILENAME : "compile-test.json",

    YARGS_BUILDER: {
      verbose: {
        describe: "Verbose logging",
        alias: "v",
        type: "boolean"
      },
      diag: {
        describe: "show diagnostic output",
        type: "boolean"
      },
      terse: {
        describe: "show only summary and errors",
        type: "boolean"
      },
      class: {
        describe: "only run tests of this class",
        type: "string"
      },
      method: {
        describe: "only run tests of this method",
        type: "string"
      },
      "fail-fast": {
        describe: "Exit on first failing test",
        defaut: true,
        type: "boolean"
      },
      serve: {
        describe: "Run built-in server",
        default: true,
        type: "boolean"
      }
    },

    getYargsCommand: function() {
      return {
        command   : "test",
        describe  : "run test for current project",
        builder   : (() => {
          let res = Object.assign({},
            qx.tool.cli.commands.Compile.YARGS_BUILDER,
            qx.tool.cli.commands.Serve.YARGS_BUILDER,
            qx.tool.cli.commands.Test.YARGS_BUILDER
          );
          delete res.watch;
          delete res["machine-readable"];
          delete res["feedback"];

          return res;
        })()
      };
    }
  },

  events: {
    /**
     * Fired to start tests. Event data is this command instance
     */
    "runTests": "qx.event.type.Data"
  },

  members: {

    /**
     * The error code of the last run test
     * @var {Number}
     */
    errorCode: 0,

    /**
     * @var {qx.data.Array}
     */
    __tests: null,

    /**
     * Registers a test object and listens for the change of errorCode property
     * @param {qx.tool.cli.api.Test} test
     */
    registerTest: function(test) {
      qx.core.Assert.assertInstance(test, qx.tool.cli.api.Test);
      test.addListenerOnce("changeExitCode", evt => {
        let exitCode = evt.getData();
        // overwrite error code only in case of errors
        if (exitCode) {
          this.errorCode = exitCode;
        }
        // handle result and inform user
        if (exitCode === 0) {
          if (test.getName() && !this.argv.quiet) {
            qx.tool.compiler.Console.info(`Test '${test.getName()}' passed.`);
          }
        } else {
          if (test.getName()) {
            qx.tool.compiler.Console.error(`Test '${test.getName()}' failed with exit code ${exitCode}.`);
          }
          if (this.argv.failFast) {
            process.exit(exitCode);
          }
        }
      });
      this.__tests.push(test);
    },

    /**
     * @Override
     */
    process: async function() {
      this.argv.watch = false;
      this.argv["machine-readable"] = false;
      this.argv["feedback"] = false;
      // check for special test compiler config
      if (!this.argv.configFile && fs.existsSync(path.join(process.cwd(), qx.tool.cli.commands.Test.CONFIG_FILENAME))) {
        this.argv.configFile = qx.tool.cli.commands.Test.CONFIG_FILENAME;
      }
      this.addListener("making", () => {
        if (!this.hasListener("runTests")) {
          qx.tool.compiler.Console.error(
            `No test runner registered!
               Please register a testrunner, e.g. testtapper with:
               qx contrib install @qooxdoo/qxl.testtapper
              `
          );
          process.exit(-1);
        }
      });
      this.__tests = new qx.data.Array();
      this.addListener("afterStart", () => {
        let res = this.fireDataEvent("runTests", this);
        res.then(() => {
          process.exit(this.errorCode);
        });
      });
      if (this.argv.serve) {
        // start server
        await this.base(arguments);
      } else {
        // compile only
        await qx.tool.cli.commands.Compile.prototype.process.call(this);
        // since the server is not started, manually fire the event test necessary for firing the "runTests" event
        this.fireEvent("afterStart");
      }
    }
  },

  defer: function(statics) {
    qx.tool.compiler.Console.addMessageIds({
      "qx.tool.cli.test.noAppName": "Cannot run anything because the config.json does not specify a unique application name",
      "qx.tool.cli.test.tooManyMakers": "Cannot run anything because multiple targets are detected",
      "qx.tool.cli.test.tooManyApplications": "Cannot run anything because multiple applications are detected"
    });
  }
});

<commit_msg>Fix typo<commit_after>/* ************************************************************************

   qooxdoo - the new era of web development

   http://qooxdoo.org

   Copyright:
     2020 Henner Kollmann

   License:
     MIT: https://opensource.org/licenses/MIT
     See the LICENSE file in the project"s top-level directory for details.

************************************************************************ */
require("./Serve");

const fs = require("fs");
const path = require("path");
const process = require("process");

/**
 * Compiles the project, serves it up as a web page (default, can be turned off),
 * and dispatches the "runTests" event. All tests that should be run need to
 * register an event handler. The handlers are called with a {@link qx.even.type.Data}
 * containing the command instance.
 *
 * A test can write to the (native) `errorCode` property of this instance,
 * which is used to determine the exit code of the `qx test` command.
 * This means, however, that the last run test overwrites the
 * `errorCode` of any previous test, and has to take care of this.
 *
 * A more scalable solution is to  call {@link
  * qx.tool.cli.commands.Test#registerTest} with an
 * instance of {@link qx.tool.cli.api.Test} and then
 * set the `exitCode` qx property of that instance.
 */
qx.Class.define("qx.tool.cli.commands.Test", {
  extend: qx.tool.cli.commands.Serve,

  statics: {

    /**
     * The name of the file containing the compile config for the testrunner
     * defaults to "compile-test.json"
     */
    CONFIG_FILENAME : "compile-test.json",

    YARGS_BUILDER: {
      verbose: {
        describe: "Verbose logging",
        alias: "v",
        type: "boolean"
      },
      diag: {
        describe: "show diagnostic output",
        type: "boolean"
      },
      terse: {
        describe: "show only summary and errors",
        type: "boolean"
      },
      class: {
        describe: "only run tests of this class",
        type: "string"
      },
      method: {
        describe: "only run tests of this method",
        type: "string"
      },
      "fail-fast": {
        describe: "Exit on first failing test",
        defaut: true,
        type: "boolean"
      },
      serve: {
        describe: "Run built-in server",
        default: true,
        type: "boolean"
      }
    },

    getYargsCommand: function() {
      return {
        command   : "test",
        describe  : "run test for current project",
        builder   : (() => {
          let res = Object.assign({},
            qx.tool.cli.commands.Compile.YARGS_BUILDER,
            qx.tool.cli.commands.Serve.YARGS_BUILDER,
            qx.tool.cli.commands.Test.YARGS_BUILDER
          );
          delete res.watch;
          delete res["machine-readable"];
          delete res["feedback"];

          return res;
        })()
      };
    }
  },

  events: {
    /**
     * Fired to start tests. Event data is this command instance
     */
    "runTests": "qx.event.type.Data"
  },

  members: {

    /**
     * The error code of the last run test
     * @var {Number}
     */
    errorCode: 0,

    /**
     * @var {qx.data.Array}
     */
    __tests: null,

    /**
     * Registers a test object and listens for the change of errorCode property
     * @param {qx.tool.cli.api.Test} test
     */
    registerTest: function(test) {
      qx.core.Assert.assertInstance(test, qx.tool.cli.api.Test);
      test.addListenerOnce("changeExitCode", evt => {
        let exitCode = evt.getData();
        // overwrite error code only in case of errors
        if (exitCode) {
          this.errorCode = exitCode;
        }
        // handle result and inform user
        if (exitCode === 0) {
          if (test.getName() && !this.argv.quiet) {
            qx.tool.compiler.Console.info(`Test '${test.getName()}' passed.`);
          }
        } else {
          if (test.getName()) {
            qx.tool.compiler.Console.error(`Test '${test.getName()}' failed with exit code ${exitCode}.`);
          }
          if (this.argv.failFast) {
            process.exit(exitCode);
          }
        }
      });
      this.__tests.push(test);
    },

    /**
     * @Override
     */
    process: async function() {
      this.argv.watch = false;
      this.argv["machine-readable"] = false;
      this.argv["feedback"] = false;
      // check for special test compiler config
      if (!this.argv.configFile && fs.existsSync(path.join(process.cwd(), qx.tool.cli.commands.Test.CONFIG_FILENAME))) {
        this.argv.configFile = qx.tool.cli.commands.Test.CONFIG_FILENAME;
      }
      this.addListener("making", () => {
        if (!this.hasListener("runTests")) {
          qx.tool.compiler.Console.error(
            `No test runner registered!
               Please register a testrunner, e.g. testtapper with:
               qx contrib install @qooxdoo/qxl.testtapper
              `
          );
          process.exit(-1);
        }
      });
      this.__tests = new qx.data.Array();
      this.addListener("afterStart", () => {
        let res = this.fireDataEvent("runTests", this);
        res.then(() => {
          process.exit(this.errorCode);
        });
      });
      if (this.argv.serve) {
        // start server
        await this.base(arguments);
      } else {
        // compile only
        await qx.tool.cli.commands.Compile.prototype.process.call(this);
        // since the server is not started, manually fire the event necessary for firing the "runTests" event
        this.fireEvent("afterStart");
      }
    }
  },

  defer: function(statics) {
    qx.tool.compiler.Console.addMessageIds({
      "qx.tool.cli.test.noAppName": "Cannot run anything because the config.json does not specify a unique application name",
      "qx.tool.cli.test.tooManyMakers": "Cannot run anything because multiple targets are detected",
      "qx.tool.cli.test.tooManyApplications": "Cannot run anything because multiple applications are detected"
    });
  }
});

<|endoftext|>


<commit_before>var Utils = require('/includes/utils');
Ti.UI.setBackgroundColor('#000');

var db = Ti.Database.open('skins');
db.execute('CREATE TABLE IF NOT EXISTS skins (id VARCHAR(16) PRIMARY KEY, name VARCHAR(16) NOT NULL, description TEXT NOT NULL, timestamp VARCHAR(16) NOT NULL)');
db.file.setRemoteBackup(true);
db.close();

if(Ti.Platform.getOsname() === 'iphone') {
	var mainWin = Ti.UI.createWindow({
		url: 'views_iphone/main.js',
		tabBarHidden: true,
		title: Ti.App.getName(),
		backgroundImage: Utils.getBGImage(),
		barColor: Utils.getNavColor()
	});

	var navGroup = Ti.UI.iPhone.createNavigationGroup({
		window: mainWin
	});

	var container = Ti.UI.createWindow({
		navBarHidden: true
	});

	container.add(navGroup);
	container.open({
		modal: false
	});
} else if(Ti.Platform.getOsname() === 'ipad') {
	Ti.include('/includes/lib/json.i18n.js');

	var detailWin = Ti.UI.createWindow({
		title: I('main.skinDetails.title'),
		backgroundGradient: {
			colors: ['c6c6c6', 'e4e4e4']
		}
	});

	var initialInfoView = getInitialInfoView();
	var content = initialInfoView;
	detailWin.add(content);

	var iad = Ti.UI.iOS.createAdView({
		adSize: Ti.UI.iOS.AD_SIZE_PORTRAIT,
		height: Ti.UI.SIZE,
		width: Ti.UI.FIT,
		bottom: 0
	});

	detailWin.add(iad);

	var masterWin = Ti.UI.createWindow({
		url: 'views_ipad/main.js',
		backgroundImage: Utils.getBGImage(),
		backgroundRepeat: true,
		title: I('main.skinList'),
		detailWin: detailWin,
		detailContent: content,
		initialInfoView: initialInfoView
	});

	var splitWin = Ti.UI.iPad.createSplitWindow({
		detailView: Ti.UI.iPhone.createNavigationGroup({
			window: detailWin
		}),
		masterView: Ti.UI.iPhone.createNavigationGroup({
			window: masterWin
		}),
		showMasterInPortrait: true
	});

	splitWin.open();

	masterWin.masterGroup = splitWin.masterView;
	masterWin.detailGroup = splitWin.detailView;

	detailWin.masterGroup = splitWin.masterView;
	detailWin.detailGroup = splitWin.detailView;

	function getInitialInfoView() {
		var view = Ti.UI.createView({
			height: Ti.UI.SIZE,
			width: Ti.UI.FILL,
			layout: 'vertical'
		});

		var lbl_noskin = Ti.UI.createLabel({
			text: I('main.noSelectedSkin'),
			width: Ti.UI.FILL,
			textAlign: 'center',
			left: view.size.width / 2 - this.width,
			height: Ti.UI.SIZE,
			font: {
				fontSize: 30
			},
			color: 'gray'
		});

		view.add(lbl_noskin);

		var b_add = Ti.UI.createButton({
			title: 'Ajouter un skin',
			font: {
				fontSize: 23
			},
			backgroundImage: '/img/button.png',
			width: Ti.UI.FILL,
			height: 50,
			left: '8%',
			right: '8%',
			top: 40
		});

		b_add.addEventListener('click', function() {
			var info_win = Ti.UI.createWindow({
				url: 'views_ipad/add_process/info.js',
				title: I('addProcess.skinInfo.title'),
				backgroundImage: Utils.getBGImage(),
				backgroundRepeat: true,
				masterGroup: splitWin.masterView
			});

			splitWin.masterView.open(info_win);
		});

		view.add(b_add);

		var b_settings = Ti.UI.createButton({
			title: 'Modifier les réglages',
			font: {
				fontSize: 23
			},
			backgroundImage: '/img/button.png',
			width: Ti.UI.FILL,
			height: 50,
			left: '8%',
			right: '8%',
			top: 10
		});

		b_settings.addEventListener('click', function() {
			var win_settings = Ti.UI.createWindow({
				title: I('settings.title'),
				backgroundImage: Utils.getBGImage(),
				backgroundRepeat: true,
				url: 'views_ipad/settings.js',
				masterGroup: splitWin.masterView
			});

			splitWin.masterView.open(win_settings);
		});

		view.add(b_settings);

		return view;
	}

}
<commit_msg>Fixed ad size on iPad (?)<commit_after>var Utils = require('/includes/utils');
Ti.UI.setBackgroundColor('#000');

var db = Ti.Database.open('skins');
db.execute('CREATE TABLE IF NOT EXISTS skins (id VARCHAR(16) PRIMARY KEY, name VARCHAR(16) NOT NULL, description TEXT NOT NULL, timestamp VARCHAR(16) NOT NULL)');
db.file.setRemoteBackup(true);
db.close();

if(Ti.Platform.getOsname() === 'iphone') {
	var mainWin = Ti.UI.createWindow({
		url: 'views_iphone/main.js',
		tabBarHidden: true,
		title: Ti.App.getName(),
		backgroundImage: Utils.getBGImage(),
		barColor: Utils.getNavColor()
	});

	var navGroup = Ti.UI.iPhone.createNavigationGroup({
		window: mainWin
	});

	var container = Ti.UI.createWindow({
		navBarHidden: true
	});

	container.add(navGroup);
	container.open({
		modal: false
	});
} else if(Ti.Platform.getOsname() === 'ipad') {
	Ti.include('/includes/lib/json.i18n.js');

	var detailWin = Ti.UI.createWindow({
		title: I('main.skinDetails.title'),
		backgroundGradient: {
			colors: ['c6c6c6', 'e4e4e4']
		}
	});

	var initialInfoView = getInitialInfoView();
	var content = initialInfoView;
	detailWin.add(content);

	var iad = Ti.UI.iOS.createAdView({
		height: Ti.UI.SIZE,
		width: Ti.UI.FIT,
		bottom: 0
	});

	detailWin.add(iad);

	var masterWin = Ti.UI.createWindow({
		url: 'views_ipad/main.js',
		backgroundImage: Utils.getBGImage(),
		backgroundRepeat: true,
		title: I('main.skinList'),
		detailWin: detailWin,
		detailContent: content,
		initialInfoView: initialInfoView
	});

	var splitWin = Ti.UI.iPad.createSplitWindow({
		detailView: Ti.UI.iPhone.createNavigationGroup({
			window: detailWin
		}),
		masterView: Ti.UI.iPhone.createNavigationGroup({
			window: masterWin
		}),
		showMasterInPortrait: true
	});

	splitWin.open();

	masterWin.masterGroup = splitWin.masterView;
	masterWin.detailGroup = splitWin.detailView;

	detailWin.masterGroup = splitWin.masterView;
	detailWin.detailGroup = splitWin.detailView;

	function getInitialInfoView() {
		var view = Ti.UI.createView({
			height: Ti.UI.SIZE,
			width: Ti.UI.FILL,
			layout: 'vertical'
		});

		var lbl_noskin = Ti.UI.createLabel({
			text: I('main.noSelectedSkin'),
			width: Ti.UI.FILL,
			textAlign: 'center',
			left: view.size.width / 2 - this.width,
			height: Ti.UI.SIZE,
			font: {
				fontSize: 30
			},
			color: 'gray'
		});

		view.add(lbl_noskin);

		var b_add = Ti.UI.createButton({
			title: 'Ajouter un skin',
			font: {
				fontSize: 23
			},
			backgroundImage: '/img/button.png',
			width: Ti.UI.FILL,
			height: 50,
			left: '8%',
			right: '8%',
			top: 40
		});

		b_add.addEventListener('click', function() {
			var info_win = Ti.UI.createWindow({
				url: 'views_ipad/add_process/info.js',
				title: I('addProcess.skinInfo.title'),
				backgroundImage: Utils.getBGImage(),
				backgroundRepeat: true,
				masterGroup: splitWin.masterView
			});

			splitWin.masterView.open(info_win);
		});

		view.add(b_add);

		var b_settings = Ti.UI.createButton({
			title: 'Modifier les réglages',
			font: {
				fontSize: 23
			},
			backgroundImage: '/img/button.png',
			width: Ti.UI.FILL,
			height: 50,
			left: '8%',
			right: '8%',
			top: 10
		});

		b_settings.addEventListener('click', function() {
			var win_settings = Ti.UI.createWindow({
				title: I('settings.title'),
				backgroundImage: Utils.getBGImage(),
				backgroundRepeat: true,
				url: 'views_ipad/settings.js',
				masterGroup: splitWin.masterView
			});

			splitWin.masterView.open(win_settings);
		});

		view.add(b_settings);

		return view;
	}

}
<|endoftext|>


<commit_before>// Module: task controller app using angular js. You need to keep this to use it in your app as per licence agreement.
// Author Sateesh Peetha
// BLog: http://tech.dingg.org
// Connect with me on LinkedIn at https://www.linkedin.com/in/sateeshpeetha/
// or at angel.co here https://angel.co/sateesh-peetha

var app = angular.module('myApp', []);

//app.controller('TaskCtrl',

function TaskCtrl($scope, $element, $attrs) {
  $scope.taskList = [{
    taskText: 'Eat Breakfast',
    done: false,
    edit: false
  }];
  $scope.Error = false;

  $scope.taskAdd = function() {

    $scope.isDuplicate($scope.taskInput, function(dup) {

      if (dup) {
        $scope.Error = true;
        $scope.taskInput = "";

      } else {
        $scope.taskList.push({
          taskText: $scope.taskInput,
          done: false,
          edit: false
        });
        $scope.taskInput = "";
      }
    });

  }; // end of taskAdd

  $scope.isDuplicate = function(inp, callback) {

      var len = $scope.taskList.length;

      var counter = 0;
      var dup = false;

      if (len === 0)
        callback(false);
      else {
        angular.forEach($scope.taskList, function(l) {

          if (l.taskText.toLowerCase() == inp.toLowerCase()) {
            dup = true;
            callback(true);

          } else {
            if (counter == (len - 1) && dup === false) {

              callback(false);
            }
          }
          counter++;

        });
      }

    }; // end of Is Duplicate

  $scope.isUpdDuplicate = function(inp, callback) {

      var len = $scope.taskList.length;

      var counter = 0;
      var dup = false;

      if (len === 0)
        callback(false);
      else {
        angular.forEach($scope.taskList, function(l) {

          if ((l.taskText.toLowerCase() == inp.taskText.toLowerCase()) && (l.$$hashKey != inp.$$hashKey)) {

            dup = true;
            callback(true);

          } else {
            if (counter == (len - 1) && dup === false) {

              callback(false);
            }
          }
          counter++;

        });
      }

    }; // end of Is update Duplicate

  $scope.remove = function() {
    var oldList = $scope.taskList;
    $scope.taskList = [];
    angular.forEach(oldList, function(x) {

      if (!x.done) $scope.taskList.push(x);
    });
    $scope.masterSelect = false;
  }; // end of remove

  $scope.edit = function() {

    var oldList = $scope.taskList;
    $scope.taskList = [];
    angular.forEach(oldList, function(x) {

      if (x.done) {
        $scope.taskList.push(x);
        x.edit = true;
        x.old = x.taskText;
      }

      if (!x.done) $scope.taskList.push(x);

    });

  }; // end of edit

  $scope.selectAll = function(checkbox) {

    var oldList = $scope.taskList;
    $scope.taskList = [];
    angular.forEach(oldList, function(x) {

      x.done = checkbox.masterSelect;

      $scope.taskList.push(x);

    });

  }; // end of  update checkboxes

  $scope.editUpdate = function(task) {

    console.log(task,event,e);

    if (event.which == 13 && task.x.taskText !== "") {
      $scope.isUpdDuplicate(task.x, function(dup) {

        if (dup) {
          $scope.Error = true;
          $scope.taskInput = "";

        } else {
          task.x.edit = false;
          task.x.done = false;
          $scope.Error = false;
        }
      });
      $scope.masterSelect = false;

    }

    if (task.x.taskText === "") {

      $scope.Error = true;
    }
  }; // end of inline edit.

}

//);

app.component('taskCt', {

  templateUrl: 'task.html',
  controller: TaskCtrl

});
<commit_msg>Create task.js<commit_after>// Module: task controller app using angular js. You need to keep this to use it in your app as per licence agreement.
// Author Sateesh Peetha
// BLog: http://tech.dingg.org
// Connect with me on LinkedIn at https://www.linkedin.com/in/sateeshpeetha/
// or at angel.co here https://angel.co/sateesh-peetha

var app = angular.module('myApp', []);

//app.controller('TaskCtrl',

function TaskCtrl($scope, $element, $attrs) {
  $scope.taskList = [{
    taskText: 'Eat Breakfast',
    done: false,
    edit: false
  }];
  $scope.Error = false;

  $scope.taskAdd = function() {

    $scope.isDuplicate($scope.taskInput, function(dup) {

      if (dup) {
        $scope.Error = true;
        $scope.taskInput = "";

      } else {
        $scope.taskList.push({
          taskText: $scope.taskInput,
          done: false,
          edit: false
        });
        $scope.taskInput = "";
      }
    });

  }; // end of taskAdd

  $scope.isDuplicate = function(inp, callback) {

      var len = $scope.taskList.length;

      var counter = 0;
      var dup = false;

      if (len === 0)
        callback(false);
      else {
        angular.forEach($scope.taskList, function(l) {

          if (l.taskText.toLowerCase() == inp.toLowerCase()) {
            dup = true;
            callback(true);

          } else {
            if (counter == (len - 1) && dup === false) {

              callback(false);
            }
          }
          counter++;

        });
      }

    }; // end of Is Duplicate

  $scope.isUpdDuplicate = function(inp, callback) {

      var len = $scope.taskList.length;

      var counter = 0;
      var dup = false;

      if (len === 0)
        callback(false);
      else {
        angular.forEach($scope.taskList, function(l) {

          if ((l.taskText.toLowerCase() == inp.taskText.toLowerCase()) && (l.$$hashKey != inp.$$hashKey)) {

            dup = true;
            callback(true);

          } else {
            if (counter == (len - 1) && dup === false) {

              callback(false);
            }
          }
          counter++;

        });
      }

    }; // end of Is update Duplicate

  $scope.remove = function() {
    var oldList = $scope.taskList;
    $scope.taskList = [];
    angular.forEach(oldList, function(x) {

      if (!x.done) $scope.taskList.push(x);
    });
    $scope.masterSelect = false;
  }; // end of remove

  $scope.edit = function() {

    var oldList = $scope.taskList;
    $scope.taskList = [];
    angular.forEach(oldList, function(x) {

      if (x.done) {
        $scope.taskList.push(x);
        x.edit = true;
        x.old = x.taskText;
      }

      if (!x.done) $scope.taskList.push(x);

    });

  }; // end of edit

  $scope.selectAll = function(checkbox) {

    var oldList = $scope.taskList;
    $scope.taskList = [];
    angular.forEach(oldList, function(x) {

      x.done = checkbox.masterSelect;

      $scope.taskList.push(x);

    });

  }; // end of  update checkboxes

  $scope.editUpdate = function(task) {

    console.log(task,event);

    if (event.which == 13 && task.x.taskText !== "") {
      $scope.isUpdDuplicate(task.x, function(dup) {

        if (dup) {
          $scope.Error = true;
          $scope.taskInput = "";

        } else {
          task.x.edit = false;
          task.x.done = false;
          $scope.Error = false;
        }
      });
      $scope.masterSelect = false;

    }

    if (task.x.taskText === "") {

      $scope.Error = true;
    }
  }; // end of inline edit.

}

//);

app.component('taskCt', {

  templateUrl: 'task.html',
  controller: TaskCtrl

});
<|endoftext|>


<commit_before>/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2014 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
(function () {
  'use strict';

  angular.module('pnc.build-records').controller('RecordDetailController', [
    '$scope',
    '$state',
    '$log',
    '$uibModal',
    'eventTypes',
    'BuildRecord',
    'recordDetail',
    'buildRecordPushResult',
    'messageBus',
    function($scope, $state, $log, $uibModal, eventTypes, BuildRecord, recordDetail, buildRecordPushResult, messageBus) {
      this.record = recordDetail;
      this.buildRecordPushResult = buildRecordPushResult;

      this.hasPushResults = function () {
        return angular.isDefined(buildRecordPushResult);
      };

      $scope.$on(eventTypes.BUILD_FINISHED, function (event, payload) {
        if (recordDetail.id === payload.id) {
          recordDetail.$get();
        }
      });

      var unsubscribe = messageBus.subscribe({
        topic: 'component-build',
        id: recordDetail.id
      });

      $scope.$on('$destroy', unsubscribe);
    }
  ]);

})();
<commit_msg>NCL-3485 Fixes issue where brew push tab was visible when no push results were available<commit_after>/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2014 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
(function () {
  'use strict';

  angular.module('pnc.build-records').controller('RecordDetailController', [
    '$scope',
    '$state',
    '$log',
    '$uibModal',
    'eventTypes',
    'BuildRecord',
    'recordDetail',
    'buildRecordPushResult',
    'messageBus',
    'utils',
    function($scope, $state, $log, $uibModal, eventTypes, BuildRecord, recordDetail, buildRecordPushResult, messageBus, utils) {
      this.record = recordDetail;
      this.buildRecordPushResult = buildRecordPushResult;

      this.hasPushResults = function () {
        return !utils.isEmpty(buildRecordPushResult);
      };

      $scope.$on(eventTypes.BUILD_FINISHED, function (event, payload) {
        if (recordDetail.id === payload.id) {
          recordDetail.$get();
        }
      });

      var unsubscribe = messageBus.subscribe({
        topic: 'component-build',
        id: recordDetail.id
      });

      $scope.$on('$destroy', unsubscribe);
    }
  ]);

})();
<|endoftext|>


<commit_before>function createElement(type, props, ...children) {
  return {
    type,
    props: {
      ...props,
      children: children.map(child =>
        typeof child === "object"
          ? child
          : createTextElement(child)
      ),
    },
  }
}

function createTextElement(text) {
  return {
    type: "TEXT_ELEMENT",
    props: {
      nodeValue: text,
      children: [],
    },
  }
}

const element = React.createElement(
  "div",
  { id: "foo" },
  React.createElement("a", null, "bar"),
  React.createElement("b")
)
const container = document.getElementById("root")
ReactDOM.render(element, container)
<commit_msg>Add didact object<commit_after>function createElement(type, props, ...children) {
  return {
    type,
    props: {
      ...props,
      children: children.map(child =>
        typeof child === "object"
          ? child
          : createTextElement(child)
      ),
    },
  }
}

function createTextElement(text) {
  return {
    type: "TEXT_ELEMENT",
    props: {
      nodeValue: text,
      children: [],
    },
  }
}

const Didact = {
  createElement,
}

const element = Didact.createElement(
  "div",
  { id: "foo" },
  Didact.createElement("a", null, "bar"),
  Didact.createElement("b")
)
const container = document.getElementById("root")
ReactDOM.render(element, container)
<|endoftext|>


<commit_before>/*---------------------------------------------------------
 * OpenERP diagram library
 *---------------------------------------------------------*/

openerp.web_diagram = function (instance) {
var QWeb = instance.web.qweb,
      _t = instance.web._t,
     _lt = instance.web._lt;
instance.web.views.add('diagram', 'instance.web.DiagramView');
instance.web.DiagramView = instance.web.View.extend({
    display_name: _lt('Diagram'),
    searchable: false,
    init: function(parent, dataset, view_id, options) {
        this._super(parent);
        this.set_default_options(options);
        this.view_manager = parent;
        this.dataset = dataset;
        this.model = this.dataset.model;
        this.view_id = view_id;
        this.domain = this.dataset._domain || [];
        this.context = {};
        this.ids = this.dataset.ids;
    },
    start: function() {
        return this.rpc("/web_diagram/diagram/load", {"model": this.model, "view_id": this.view_id}, this.on_loaded);
    },

    toTitleCase: function(str) {
        return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
    },

    on_loaded: function(result) {

        var self = this;
        if(this.ids && this.ids.length) {
            this.id = this.ids[self.dataset.index || 0];
        }

        this.fields_view = result.fields_view,
        this.view_id = this.fields_view.view_id,
        this.fields = this.fields_view.fields,
        this.nodes = this.fields_view.arch.children[0],
        this.connectors = this.fields_view.arch.children[1],
        this.node = this.nodes.attrs.object,
        this.connector = this.connectors.attrs.object;

        this.$element.html(QWeb.render("DiagramView", this));
        this.$element.addClass(this.fields_view.arch.attrs['class']);

        this.$element.find('div.oe_diagram_pager button[data-pager-action]').click(function() {
            var action = $(this).data('pager-action');
            self.on_pager_action(action);
        });

        this.do_update_pager();

        // New Node,Edge
        this.$element.find('#new_node.oe_diagram_button_new').click(function(){self.add_node();});

        if(this.id) {
            self.get_diagram_info();
        }

    },

    get_diagram_info: function() {
        var self = this;
        var params = {
            'id': this.id,
            'model': this.model,
            'node': this.node,
            'connector': this.connector,
            'bgcolor': this.nodes.attrs.bgcolor,
            'shape': this.nodes.attrs.shape,
            'src_node': this.connectors.attrs.source,
            'des_node': this.connectors.attrs.destination,
            'label': this.connectors.attrs.label || false,
            'visible_nodes': [],
            'invisible_nodes': [],
            'node_fields': [],
            'connectors': [],
            'connectors_fields': []
        };

        _.each(this.nodes.children, function(child) {
            if(child.attrs.invisible == '1')
                params['invisible_nodes'].push(child.attrs.name);
            else {
                params['visible_nodes'].push(child.attrs.name);
                params['node_fields'].push(self.fields[child.attrs.name]['string']|| this.toTitleCase(child.attrs.name));
            }
        });

        _.each(this.connectors.children, function(conn) {
            params['connectors_fields'].push(self.fields[conn.attrs.name]['string']|| this.toTitleCase(conn.attrs.name));
            params['connectors'].push(conn.attrs.name);
        });

        this.rpc(
            '/web_diagram/diagram/get_diagram_info',params,
            function(result) {
                self.draw_diagram(result);
            }
        );
    },

    on_diagram_loaded: function(record) {
        var id_record = record['id'];
        if(id_record) {
            this.id = id_record;
            this.get_diagram_info();
        }
    },

    // Set-up the drawing elements of the diagram
    draw_diagram: function(result) {
        var self = this;
        var res_nodes  = result['nodes'];
        var res_edges  = result['conn'];
        this.parent_field = result.parent_field;
        this.$element.find('h3.oe_diagram_title').text(result.name);

        var id_to_node = {};

        var style = {
            edge_color: "#A0A0A0",
            edge_label_color: "#555",
            edge_label_font_size: 10,
            edge_width: 2,
            edge_spacing: 100,
            edge_loop_radius: 100,

            node_label_color: "#333",
            node_label_font_size: 12,
            node_outline_color: "#333",
            node_outline_width: 1,
            node_selected_color: "#0097BE",
            node_selected_width: 2,
            node_size_x: 110,
            node_size_y: 80,
            connector_active_color: "#FFF",
            connector_radius: 4,

            close_button_radius: 8,
            close_button_color: "#333",
            close_button_x_color: "#FFF",

            gray: "#DCDCDC",
            white: "#FFF",

            viewport_margin: 50
        };

        // remove previous diagram
        var canvas = self.$element.find('div.oe_diagram_diagram')
                             .empty().get(0);

        var r  = new Raphael(canvas, '100%','100%');

        var graph  = new CuteGraph(r,style,canvas.parentNode);

        var confirm_dialog = $('#dialog').dialog({
            autoOpen: false,
            title: _t("Are you sure?") });

        _.each(res_nodes, function(node) {
            var n = new CuteNode(
                graph,
                node.x + 50,  //FIXME the +50 should be in the layout algorithm
                node.y + 50,
                CuteGraph.wordwrap(node.name, 14),
                node.shape === 'rectangle' ? 'rect' : 'circle',
                node.color === 'white' ? style.white : style.gray);

            n.id = node.id;
            id_to_node[node.id] = n;
        });

        _.each(res_edges, function(edge) {
            var e =  new CuteEdge(
                graph,
                CuteGraph.wordwrap(edge.signal, 32),
                id_to_node[edge.s_id],
                id_to_node[edge.d_id] || id_to_node[edge.s_id]  );  //WORKAROUND
            e.id = edge.id;
        });

        CuteNode.double_click_callback = function(cutenode){
            self.edit_node(cutenode.id);
        };
        var i = 0;
        CuteNode.destruction_callback = function(cutenode){
            if(!confirm(_t("Deleting this node cannot be undone.\nIt will also delete all connected transitions.\n\nAre you sure ?"))){
                return $.Deferred().reject().promise();
            }
            return new instance.web.DataSet(self,self.node).unlink([cutenode.id]);
        };
        CuteEdge.double_click_callback = function(cuteedge){
            self.edit_connector(cuteedge.id);
        };

        CuteEdge.creation_callback = function(node_start, node_end){
            return {label:_t("")};
        };
        CuteEdge.new_edge_callback = function(cuteedge){
            self.add_connector(cuteedge.get_start().id,
                               cuteedge.get_end().id,
                               cuteedge);
        };
        CuteEdge.destruction_callback = function(cuteedge){
            if(!confirm(_t("Deleting this transition cannot be undone.\n\nAre you sure ?"))){
                return $.Deferred().reject().promise();
            }
            return new instance.web.DataSet(self,self.connector).unlink([cuteedge.id]);
        };

    },

    // Creates a popup to edit the content of the node with id node_id
    edit_node: function(node_id){
        var self = this;
        var title = _t('Activity');
        var pop = new instance.web.form.FormOpenPopup(self);

        pop.show_element(
                self.node,
                node_id,
                self.context || self.dataset.context,
                {
                    title: _t("Open: ") + title
                }
            );

        pop.on_write.add(function() {
            self.dataset.read_index(_.keys(self.fields_view.fields)).pipe(self.on_diagram_loaded);
            });

        var form_fields = [self.parent_field];
        var form_controller = pop.view_form;

        form_controller.on_record_loaded.add_first(function() {
            _.each(form_fields, function(fld) {
                if (!(fld in form_controller.fields)) { return; }
                var field = form_controller.fields[fld];
                field.$input.prop('disabled', true);
                field.$drop_down.unbind();
                field.$menu_btn.unbind();
            });
        });
    },

    // Creates a popup to add a node to the diagram
    add_node: function(){
        var self = this;
        var title = _t('Activity');
        var pop = new instance.web.form.SelectCreatePopup(self);
        pop.select_element(
            self.node,
            {
                title: _t("Create:") + title,
                initial_view: 'form',
                disable_multiple_selection: true
            },
            self.dataset.domain,
            self.context || self.dataset.context
        );
        pop.on_select_elements.add_last(function(element_ids) {
            self.dataset.read_index(_.keys(self.fields_view.fields)).pipe(self.on_diagram_loaded);
        });

        var form_controller = pop.view_form;
        var form_fields = [this.parent_field];

        form_controller.on_record_loaded.add_last(function() {
            _.each(form_fields, function(fld) {
                if (!(fld in form_controller.fields)) { return; }
                var field = form_controller.fields[fld];
                field.set_value(self.id);
                field.dirty = true;
            });
        });
    },

    // Creates a popup to edit the connector of id connector_id
    edit_connector: function(connector_id){
        var self = this;
        var title = _t('Transition');
        var pop = new instance.web.form.FormOpenPopup(self);
        pop.show_element(
            self.connector,
            parseInt(connector_id,10),      //FIXME Isn't connector_id supposed to be an int ?
            self.context || self.dataset.context,
            {
                title: _t("Open: ") + title
            }
        );
        pop.on_write.add(function() {
            self.dataset.read_index(_.keys(self.fields_view.fields)).pipe(self.on_diagram_loaded);
        });
    },

    // Creates a popup to add a connector from node_source_id to node_dest_id.
    // dummy_cuteedge if not null, will be removed form the graph after the popup is closed.
    add_connector: function(node_source_id, node_dest_id, dummy_cuteedge){
        var self = this;
        var title = _t('Transition');
        var pop = new instance.web.form.SelectCreatePopup(self);

        pop.select_element(
            self.connector,
            {
                title: _t("Create:") + title,
                initial_view: 'form',
                disable_multiple_selection: true
            },
            this.dataset.domain,
            this.context || this.dataset.context
        );

        pop.on_select_elements.add_last(function(element_ids) {
            self.dataset.read_index(_.keys(self.fields_view.fields)).pipe(self.on_diagram_loaded);
        });
        // We want to destroy the dummy edge after a creation cancel. This destroys it even if we save the changes.
        // This is not a problem since the diagram is completely redrawn on saved changes.
        pop.$element.bind("dialogbeforeclose",function(){
            if(dummy_cuteedge){
                dummy_cuteedge.remove();
            }
        });

        var form_controller = pop.view_form;

        form_controller.on_record_loaded.add_last(function () {
            form_controller.fields[self.connectors.attrs.source].set_value(node_source_id);
            form_controller.fields[self.connectors.attrs.source].dirty = true;
            form_controller.fields[self.connectors.attrs.destination].set_value(node_dest_id);
            form_controller.fields[self.connectors.attrs.destination].dirty = true;
        });
    },

    on_pager_action: function(action) {
        switch (action) {
            case 'first':
                this.dataset.index = 0;
                break;
            case 'previous':
                this.dataset.previous();
                break;
            case 'next':
                this.dataset.next();
                break;
            case 'last':
                this.dataset.index = this.dataset.ids.length - 1;
                break;
        }
        var loaded = this.dataset.read_index(_.keys(this.fields_view.fields))
                .pipe(this.on_diagram_loaded);
        this.do_update_pager();
        return loaded;
    },

    do_update_pager: function(hide_index) {
        var $pager = this.$element.find('div.oe_diagram_pager');
        var index = hide_index ? '-' : this.dataset.index + 1;
        if(!this.dataset.count) {
            this.dataset.count = this.dataset.ids.length;
        }
        $pager.find('span.oe_pager_index').html(index);
        $pager.find('span.oe_pager_count').html(this.dataset.count);
    },

    do_show: function() {
        this.do_push_state({});
        return $.when(this._super(), this.on_pager_action('reload'));
    }
});
};

// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
<commit_msg>[MERGE] diagram view label<commit_after>/*---------------------------------------------------------
 * OpenERP diagram library
 *---------------------------------------------------------*/

openerp.web_diagram = function (instance) {
var QWeb = instance.web.qweb,
      _t = instance.web._t,
     _lt = instance.web._lt;
instance.web.views.add('diagram', 'instance.web.DiagramView');
instance.web.DiagramView = instance.web.View.extend({
    display_name: _lt('Diagram'),
    searchable: false,
    init: function(parent, dataset, view_id, options) {
        this._super(parent);
        this.set_default_options(options);
        this.view_manager = parent;
        this.dataset = dataset;
        this.model = this.dataset.model;
        this.view_id = view_id;
        this.domain = this.dataset._domain || [];
        this.context = {};
        this.ids = this.dataset.ids;
    },
    start: function() {
        return this.rpc("/web_diagram/diagram/load", {"model": this.model, "view_id": this.view_id}, this.on_loaded);
    },

    toTitleCase: function(str) {
        return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
    },

    on_loaded: function(result) {

        var self = this;
        if(this.ids && this.ids.length) {
            this.id = this.ids[self.dataset.index || 0];
        }

        this.fields_view = result.fields_view,
        this.view_id = this.fields_view.view_id,
        this.fields = this.fields_view.fields,
        this.nodes = this.fields_view.arch.children[0],
        this.connectors = this.fields_view.arch.children[1],
        this.node = this.nodes.attrs.object,
        this.connector = this.connectors.attrs.object;
        this.labels = _.filter(this.fields_view.arch.children, function(label) {
            return label.tag == "label";
        });

        this.$element.html(QWeb.render("DiagramView", this));
        this.$element.addClass(this.fields_view.arch.attrs['class']);

        _.each(self.labels,function(label){
            html_label = '
' + label.attrs.string + "
";
            self.$element.find('.oe_diagram_header').append(html_label);
        })

        this.$element.find('div.oe_diagram_pager button[data-pager-action]').click(function() {
            var action = $(this).data('pager-action');
            self.on_pager_action(action);
        });

        this.do_update_pager();

        // New Node,Edge
        this.$element.find('#new_node.oe_diagram_button_new').click(function(){self.add_node();});

        if(this.id) {
            self.get_diagram_info();
        }

    },

    get_diagram_info: function() {
        var self = this;
        var params = {
            'id': this.id,
            'model': this.model,
            'node': this.node,
            'connector': this.connector,
            'bgcolor': this.nodes.attrs.bgcolor,
            'shape': this.nodes.attrs.shape,
            'src_node': this.connectors.attrs.source,
            'des_node': this.connectors.attrs.destination,
            'label': this.connectors.attrs.label || false,
            'visible_nodes': [],
            'invisible_nodes': [],
            'node_fields': [],
            'connectors': [],
            'connectors_fields': []
        };

        _.each(this.nodes.children, function(child) {
            if(child.attrs.invisible == '1')
                params['invisible_nodes'].push(child.attrs.name);
            else {
                params['visible_nodes'].push(child.attrs.name);
                params['node_fields'].push(self.fields[child.attrs.name]['string']|| this.toTitleCase(child.attrs.name));
            }
        });

        _.each(this.connectors.children, function(conn) {
            params['connectors_fields'].push(self.fields[conn.attrs.name]['string']|| this.toTitleCase(conn.attrs.name));
            params['connectors'].push(conn.attrs.name);
        });

        this.rpc(
            '/web_diagram/diagram/get_diagram_info',params,
            function(result) {
                self.draw_diagram(result);
            }
        );
    },

    on_diagram_loaded: function(record) {
        var id_record = record['id'];
        if(id_record) {
            this.id = id_record;
            this.get_diagram_info();
        }
    },

    // Set-up the drawing elements of the diagram
    draw_diagram: function(result) {
        var self = this;
        var res_nodes  = result['nodes'];
        var res_edges  = result['conn'];
        this.parent_field = result.parent_field;
        this.$element.find('h3.oe_diagram_title').text(result.name);

        var id_to_node = {};

        var style = {
            edge_color: "#A0A0A0",
            edge_label_color: "#555",
            edge_label_font_size: 10,
            edge_width: 2,
            edge_spacing: 100,
            edge_loop_radius: 100,

            node_label_color: "#333",
            node_label_font_size: 12,
            node_outline_color: "#333",
            node_outline_width: 1,
            node_selected_color: "#0097BE",
            node_selected_width: 2,
            node_size_x: 110,
            node_size_y: 80,
            connector_active_color: "#FFF",
            connector_radius: 4,

            close_button_radius: 8,
            close_button_color: "#333",
            close_button_x_color: "#FFF",

            gray: "#DCDCDC",
            white: "#FFF",

            viewport_margin: 50
        };

        // remove previous diagram
        var canvas = self.$element.find('div.oe_diagram_diagram')
                             .empty().get(0);

        var r  = new Raphael(canvas, '100%','100%');

        var graph  = new CuteGraph(r,style,canvas.parentNode);

        var confirm_dialog = $('#dialog').dialog({
            autoOpen: false,
            title: _t("Are you sure?") });

        _.each(res_nodes, function(node) {
            var n = new CuteNode(
                graph,
                node.x + 50,  //FIXME the +50 should be in the layout algorithm
                node.y + 50,
                CuteGraph.wordwrap(node.name, 14),
                node.shape === 'rectangle' ? 'rect' : 'circle',
                node.color === 'white' ? style.white : style.gray);

            n.id = node.id;
            id_to_node[node.id] = n;
        });

        _.each(res_edges, function(edge) {
            var e =  new CuteEdge(
                graph,
                CuteGraph.wordwrap(edge.signal, 32),
                id_to_node[edge.s_id],
                id_to_node[edge.d_id] || id_to_node[edge.s_id]  );  //WORKAROUND
            e.id = edge.id;
        });

        CuteNode.double_click_callback = function(cutenode){
            self.edit_node(cutenode.id);
        };
        var i = 0;
        CuteNode.destruction_callback = function(cutenode){
            if(!confirm(_t("Deleting this node cannot be undone.\nIt will also delete all connected transitions.\n\nAre you sure ?"))){
                return $.Deferred().reject().promise();
            }
            return new instance.web.DataSet(self,self.node).unlink([cutenode.id]);
        };
        CuteEdge.double_click_callback = function(cuteedge){
            self.edit_connector(cuteedge.id);
        };

        CuteEdge.creation_callback = function(node_start, node_end){
            return {label:_t("")};
        };
        CuteEdge.new_edge_callback = function(cuteedge){
            self.add_connector(cuteedge.get_start().id,
                               cuteedge.get_end().id,
                               cuteedge);
        };
        CuteEdge.destruction_callback = function(cuteedge){
            if(!confirm(_t("Deleting this transition cannot be undone.\n\nAre you sure ?"))){
                return $.Deferred().reject().promise();
            }
            return new instance.web.DataSet(self,self.connector).unlink([cuteedge.id]);
        };

    },

    // Creates a popup to edit the content of the node with id node_id
    edit_node: function(node_id){
        var self = this;
        var title = _t('Activity');
        var pop = new instance.web.form.FormOpenPopup(self);

        pop.show_element(
                self.node,
                node_id,
                self.context || self.dataset.context,
                {
                    title: _t("Open: ") + title
                }
            );

        pop.on_write.add(function() {
            self.dataset.read_index(_.keys(self.fields_view.fields)).pipe(self.on_diagram_loaded);
            });

        var form_fields = [self.parent_field];
        var form_controller = pop.view_form;

        form_controller.on_record_loaded.add_first(function() {
            _.each(form_fields, function(fld) {
                if (!(fld in form_controller.fields)) { return; }
                var field = form_controller.fields[fld];
                field.$input.prop('disabled', true);
                field.$drop_down.unbind();
                field.$menu_btn.unbind();
            });
        });
    },

    // Creates a popup to add a node to the diagram
    add_node: function(){
        var self = this;
        var title = _t('Activity');
        var pop = new instance.web.form.SelectCreatePopup(self);
        pop.select_element(
            self.node,
            {
                title: _t("Create:") + title,
                initial_view: 'form',
                disable_multiple_selection: true
            },
            self.dataset.domain,
            self.context || self.dataset.context
        );
        pop.on_select_elements.add_last(function(element_ids) {
            self.dataset.read_index(_.keys(self.fields_view.fields)).pipe(self.on_diagram_loaded);
        });

        var form_controller = pop.view_form;
        var form_fields = [this.parent_field];

        form_controller.on_record_loaded.add_last(function() {
            _.each(form_fields, function(fld) {
                if (!(fld in form_controller.fields)) { return; }
                var field = form_controller.fields[fld];
                field.set_value(self.id);
                field.dirty = true;
            });
        });
    },

    // Creates a popup to edit the connector of id connector_id
    edit_connector: function(connector_id){
        var self = this;
        var title = _t('Transition');
        var pop = new instance.web.form.FormOpenPopup(self);
        pop.show_element(
            self.connector,
            parseInt(connector_id,10),      //FIXME Isn't connector_id supposed to be an int ?
            self.context || self.dataset.context,
            {
                title: _t("Open: ") + title
            }
        );
        pop.on_write.add(function() {
            self.dataset.read_index(_.keys(self.fields_view.fields)).pipe(self.on_diagram_loaded);
        });
    },

    // Creates a popup to add a connector from node_source_id to node_dest_id.
    // dummy_cuteedge if not null, will be removed form the graph after the popup is closed.
    add_connector: function(node_source_id, node_dest_id, dummy_cuteedge){
        var self = this;
        var title = _t('Transition');
        var pop = new instance.web.form.SelectCreatePopup(self);

        pop.select_element(
            self.connector,
            {
                title: _t("Create:") + title,
                initial_view: 'form',
                disable_multiple_selection: true
            },
            this.dataset.domain,
            this.context || this.dataset.context
        );

        pop.on_select_elements.add_last(function(element_ids) {
            self.dataset.read_index(_.keys(self.fields_view.fields)).pipe(self.on_diagram_loaded);
        });
        // We want to destroy the dummy edge after a creation cancel. This destroys it even if we save the changes.
        // This is not a problem since the diagram is completely redrawn on saved changes.
        pop.$element.bind("dialogbeforeclose",function(){
            if(dummy_cuteedge){
                dummy_cuteedge.remove();
            }
        });

        var form_controller = pop.view_form;

        form_controller.on_record_loaded.add_last(function () {
            form_controller.fields[self.connectors.attrs.source].set_value(node_source_id);
            form_controller.fields[self.connectors.attrs.source].dirty = true;
            form_controller.fields[self.connectors.attrs.destination].set_value(node_dest_id);
            form_controller.fields[self.connectors.attrs.destination].dirty = true;
        });
    },

    on_pager_action: function(action) {
        switch (action) {
            case 'first':
                this.dataset.index = 0;
                break;
            case 'previous':
                this.dataset.previous();
                break;
            case 'next':
                this.dataset.next();
                break;
            case 'last':
                this.dataset.index = this.dataset.ids.length - 1;
                break;
        }
        var loaded = this.dataset.read_index(_.keys(this.fields_view.fields))
                .pipe(this.on_diagram_loaded);
        this.do_update_pager();
        return loaded;
    },

    do_update_pager: function(hide_index) {
        var $pager = this.$element.find('div.oe_diagram_pager');
        var index = hide_index ? '-' : this.dataset.index + 1;
        if(!this.dataset.count) {
            this.dataset.count = this.dataset.ids.length;
        }
        $pager.find('span.oe_pager_index').html(index);
        $pager.find('span.oe_pager_count').html(this.dataset.count);
    },

    do_show: function() {
        this.do_push_state({});
        return $.when(this._super(), this.on_pager_action('reload'));
    }
});
};

// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
<|endoftext|>


<commit_before><commit_msg>Update project EventEmitter to v1.1.3<commit_after><|endoftext|>