<commit_before>"use strict";

function Reuq(controller) {
  var rq = this;
  this.templates = {};
  this.controller = controller;
  this.utils = this.getUtils();

  this._storeTemplates();
  // submit
  $('body').on('submit', '[lib-form]:not([lib-tmpl] [lib-form]):not([lib-tmpl][lib-form])', function(e) {
    e.preventDefault();
    rq.utils.submit($(this))
  });

  (function(rq) {
    var resources = rq.controller.resources;
    var locals = rq.controller.locals || {};

    Object.keys(locals).forEach(function(name) {
      rq.setLocal(name, rq.getLocal(name));
    });
    //load all resources set to autoload
    Object.keys(resources).forEach(function(resourceName) {
      // if autoload is not set, autoload it by default
      if (resources[resourceName]['autoload'] === undefined || resources[resourceName]['autoload']) {
        rq.getResource(resourceName, true);
        rq.render(resourceName, null);
      }
    });

    rq.addEvents();
    // should this be run 1st inetead?
    if (typeof rq.controller.onInit === 'function') {
      rq.controller.onInit.apply(rq);
    }
  })(this);
}

//render
Reuq.prototype.render = function(templateName, data) {
  var processedTemplate = this._processTemplate(templateName, data);
  this._render(templateName, processedTemplate);
}

Reuq.prototype._processTemplate = function(templateName, data) {
  var rq = this;

  function compile(template, data) {
    template = template.replace(/\[\[(\w+)\]\]/g, function(){
      var expression = arguments[1];
      return data[expression] || rq.controller.fn[expression].apply(data);
    });
    return template;
  }

  var templateObj = this.templates[templateName];
  var resourceName = templateObj.resourceName;
  var template = templateObj.html;
  var $template = $(template);

  // process lib-rsrc-loading
  if (resourceName && this.controller.resources[resourceName].loading) {
    $template.not('[lib-rsrc-loading], [lib-rsrc-loading] *').remove();
  } else {
    $template.find('[lib-rsrc-loading], [lib-rsrc-loading] *').remove();
  }

  //process iteration
  $template.find('[lib-iter], [lib-iter-self]').each(function(id, el) {
    var $el = $(el);

    if ($el.is("[lib-iter]")) {
      var listKey = $el.attr('lib-iter');
      var list = data[listKey] || [];
    } else {
      // then it's lib-iter-self
      var list = data || [];
    }
    list.forEach(function(listItem) {
      var $compiled = $(compile($el.prop('outerHTML'), listItem));
      $compiled.removeAttr('lib-iter');
      $el.after($compiled);
    });
    $el.remove();
  });

  //process ifs
  $template.find('[lib-if]').each(function(id, el) {
    var $el = $(el);
    var condition = $el.attr('lib-if');
    if (!data[condition]) {
      $el.remove();
    }
  })

  //process if-nots
  $template.find('[lib-if-not]').each(function(id, el) {
    var $el = $(el);
    var condition = $el.attr('lib-if-not');
    if (data[condition]) {
      $el.remove();
    }
  });

  template = $template.prop('outerHTML');
  $template = $(compile(template, data))

  //process src
  $template.find('[lib-src]').each(function(id, el) {
    var $el = $(el);
    $el.attr('src', $el.attr('lib-src'));
    $el.removeAttr('lib-src');
  })

  return $template.prop('outerHTML');
}

Reuq.prototype._render = function(templateName, processedTemplate) {
  //remove previously rendered template
  $('[from-tmpl=' + templateName + ']').remove();

  var $template = $('[lib-tmpl][lib-tmpl=' + templateName + ']');
  var $newTemplate = $(processedTemplate).removeAttr('hidden').removeAttr('lib-tmpl');
  $newTemplate.attr('from-tmpl', templateName);
  $template.after($newTemplate);
  this.addEvents($newTemplate);
}

//renderEach
Reuq.prototype.renderEach = function(templateName, dataList) {
  var rq = this;

  var subTemplates = dataList.map(function(data) {
    return rq._processTemplate(templateName, data);
  });
  this._render(templateName, subTemplates.join(''));
}

//renderData
//TODO automatically subscribe templates to resource changes
Reuq.prototype.renderData = function(templateName, data) {
  this.render(templateName, data);
}

Reuq.prototype.cacheIsValid = function(resourceName) {
  var resource = this.controller.resources[resourceName]

  if (resource.shouldReload) {
    return false;
  } else {
    var cacheTimeout = resource.cacheTimeout || 10; //minutes
    var timeoutDate = new Date(resource.updatedAt.getTime() + cacheTimeout * 60000);
    return timeoutDate > new Date();
  }
}

Reuq.prototype.invalidateResourceCache = function(resourceName) {
  this.controller.resources[resourceName].shouldReload = true;
}

Reuq.prototype.getResource = function(resourceName, force, cb) {
  // coerce optional arguments to appropriate values
  if (arguments.length < 3 && typeof force === 'function') {
    cb = force;
    force = false;
  }
  var rq = this;
  var resource = this.controller.resources[resourceName];
  if (resource.data && !force && this.cacheIsValid(resourceName)) {
    cb(resource.data);
  } else {
    resource.loading = true;

    var url = typeof resource.url === 'function' ? resource.url(this) : resource.url;
    $.ajax({
      url: url,
      beforeSend: function(xhr) {
        Object.keys(resource.headers || {}).forEach(function(header){
          xhr.setRequestHeader(header, resource.headers[header]);
        })
      },
      success: function(resp) {
        resource.loading = false;
        resource.loaded = true;

        rq.setResource(resourceName, resource.dataKey ? resp[resource.dataKey] : resp);

        if (typeof cb === 'function') {
          cb(resource.data);
        }
      }
    })
  }
}

Reuq.prototype.setResource = function(resourceName, data) {
  var rq = this;
  var resource = this.controller.resources[resourceName];
  resource.data = data;
  resource.shouldReload = false;
  resource.updatedAt = new Date();
  this.runResourceSubscribers(resourceName, data);

  $('[lib-tmpl][lib-rsrc=' + resourceName + ']:not([manual-render])').each(function(id, el) {
    rq.renderData($(el).attr('lib-tmpl'), data);
  });
}

Reuq.prototype.runResourceSubscribers = function(resourceName, data) {
  var resource = this.controller.resources[resourceName];
  data = data || resource.data;
  this.runSubscribers(resource.subscribers, data)
}

Reuq.prototype.updateResource = function(resourceName, cb) {
  var rq = this;
  this.getResource(resourceName, function(data) {
    rq.setResource(resourceName, cb(data));
  });
}

Reuq.prototype.setLocal = function(name, data) {
  var rq = this;
  var local = this.controller.locals[name];
  local.data = data;
  this.runLocalSubscribers(name, data);

  $('[lib-tmpl][lib-local=' + name + ']:not([manual-render])').each(function(id, el) {
    rq.renderData($(el).attr('lib-tmpl'), data);
  });
}

Reuq.prototype.getLocal = function(name) {
  return this.controller.locals[name].data;
}

Reuq.prototype.updateLocal = function(name, cb) {
  var data = this.getLocal(name);
  this.setLocal(name, cb(data));
}

Reuq.prototype.runLocalSubscribers = function(name, data) {
  var local = this.controller.locals[name];
  data = data || local.data;
  this.runSubscribers(local.subscribers, data);
}

Reuq.prototype.runSubscribers = function(subscribers, data) {
  var rq = this;
  if (subscribers) {
    subscribers.forEach(function(subscriber) {
      var path = subscriber.split('.');
      var fn = rq.controller[path[0]][path[1]];
      fn.apply(rq, [data]);
    })
  }
}

//storeTemplates
Reuq.prototype._storeTemplates = function() {
  var rq = this;
  $('[lib-tmpl]').each(function(id, el) {
    var $el = $(el);
    rq.templates[$el.attr('lib-tmpl')] = {
      html: $el.prop('outerHTML'),
      dom: $el,
      dataKey: $el.attr('lib-data'),
      resourceName: $el.attr('lib-rsrc')
    };
  });
}

Reuq.prototype.addEvents = function($dom) {
  $dom = $dom || $('body');
  var rq = this;
  var evtSelector = '[lib-evt]:not([lib-tmpl] [lib-evt]):not([lib-tmpl][lib-evt])';
  $dom.find(evtSelector).addBack(evtSelector).each(function(id, el) {
    var $el = $(el);
    var evtConfig = $el.attr('lib-evt').split(' ')
    var evtType = evtConfig[0];
    var evtHandler = rq.controller.eventHandlers[evtConfig[1]];
    $el.on(evtType, function(e) {
      var handlerArgs = [$el].concat(evtConfig.slice(2))
      evtHandler.apply(rq, handlerArgs);
    })
  });
}

Reuq.prototype.getUtils = function() {
  var rq = this;
  console.log(rq);

  return {
    submit: function(form) {
      var data = form.serialize();
      var url = form.attr('action');
      var type = form.attr('method');

      $.ajax({ type: type, url: url, data: data })
        .done(function(data, status, jqXHR) {
          var cb = form.attr('lib-cb-done');
          if (cb) {
            rq.controller.callbacks[cb](data, status, form);
          }
        })
        .fail(function(jqXHR, status, error) {
          var cb = form.attr('lib-cb-fail');
          if (cb) {
            rq.controller.callbacks[cb](error, status, form, jqXHR);
          }
        });
    }
  }
}

$('head').append('<style type="text/css">[lib-tmpl] {display: none !important;}</style>');
window.Rq = window.Reuq = Reuq;
<commit_msg>refactor: change lib- flags to rq-<commit_after>"use strict";

function Reuq(controller) {
  var rq = this;
  this.templates = {};
  this.controller = controller;
  this.utils = this.getUtils();

  this._storeTemplates();
  // submit
  $('body').on('submit', '[rq-form]:not([rq-tmpl] [rq-form]):not([rq-tmpl][rq-form])', function(e) {
    e.preventDefault();
    rq.utils.submit($(this))
  });

  (function(rq) {
    var resources = rq.controller.resources;
    var locals = rq.controller.locals || {};

    Object.keys(locals).forEach(function(name) {
      rq.setLocal(name, rq.getLocal(name));
    });
    //load all resources set to autoload
    Object.keys(resources).forEach(function(resourceName) {
      // if autoload is not set, autoload it by default
      if (resources[resourceName]['autoload'] === undefined || resources[resourceName]['autoload']) {
        rq.getResource(resourceName, true);
        rq.render(resourceName, null);
      }
    });

    rq.addEvents();
    // should this be run 1st inetead?
    if (typeof rq.controller.onInit === 'function') {
      rq.controller.onInit.apply(rq);
    }
  })(this);
}

//render
Reuq.prototype.render = function(templateName, data) {
  var processedTemplate = this._processTemplate(templateName, data);
  this._render(templateName, processedTemplate);
}

Reuq.prototype._processTemplate = function(templateName, data) {
  var rq = this;

  function compile(template, data) {
    template = template.replace(/\[\[(\w+)\]\]/g, function(){
      var expression = arguments[1];
      return data[expression] || rq.controller.fn[expression].apply(data);
    });
    return template;
  }

  var templateObj = this.templates[templateName];
  var resourceName = templateObj.resourceName;
  var template = templateObj.html;
  var $template = $(template);

  // process rq-rsrc-loading
  if (resourceName && this.controller.resources[resourceName].loading) {
    $template.not('[rq-rsrc-loading], [rq-rsrc-loading] *').remove();
  } else {
    $template.find('[rq-rsrc-loading], [rq-rsrc-loading] *').remove();
  }

  //process iteration
  $template.find('[rq-iter], [rq-iter-self]').each(function(id, el) {
    var $el = $(el);

    if ($el.is("[rq-iter]")) {
      var listKey = $el.attr('rq-iter');
      var list = data[listKey] || [];
    } else {
      // then it's rq-iter-self
      var list = data || [];
    }
    list.forEach(function(listItem) {
      var $compiled = $(compile($el.prop('outerHTML'), listItem));
      $compiled.removeAttr('rq-iter');
      $el.after($compiled);
    });
    $el.remove();
  });

  //process ifs
  $template.find('[rq-if]').each(function(id, el) {
    var $el = $(el);
    var condition = $el.attr('rq-if');
    if (!data[condition]) {
      $el.remove();
    }
  })

  //process if-nots
  $template.find('[rq-if-not]').each(function(id, el) {
    var $el = $(el);
    var condition = $el.attr('rq-if-not');
    if (data[condition]) {
      $el.remove();
    }
  });

  template = $template.prop('outerHTML');
  $template = $(compile(template, data))

  //process src
  $template.find('[rq-src]').each(function(id, el) {
    var $el = $(el);
    $el.attr('src', $el.attr('rq-src'));
    $el.removeAttr('rq-src');
  })

  return $template.prop('outerHTML');
}

Reuq.prototype._render = function(templateName, processedTemplate) {
  //remove previously rendered template
  $('[from-tmpl=' + templateName + ']').remove();

  var $template = $('[rq-tmpl][rq-tmpl=' + templateName + ']');
  var $newTemplate = $(processedTemplate).removeAttr('hidden').removeAttr('rq-tmpl');
  $newTemplate.attr('from-tmpl', templateName);
  $template.after($newTemplate);
  this.addEvents($newTemplate);
}

//renderEach
Reuq.prototype.renderEach = function(templateName, dataList) {
  var rq = this;

  var subTemplates = dataList.map(function(data) {
    return rq._processTemplate(templateName, data);
  });
  this._render(templateName, subTemplates.join(''));
}

//renderData
//TODO automatically subscribe templates to resource changes
Reuq.prototype.renderData = function(templateName, data) {
  this.render(templateName, data);
}

Reuq.prototype.cacheIsValid = function(resourceName) {
  var resource = this.controller.resources[resourceName]

  if (resource.shouldReload) {
    return false;
  } else {
    var cacheTimeout = resource.cacheTimeout || 10; //minutes
    var timeoutDate = new Date(resource.updatedAt.getTime() + cacheTimeout * 60000);
    return timeoutDate > new Date();
  }
}

Reuq.prototype.invalidateResourceCache = function(resourceName) {
  this.controller.resources[resourceName].shouldReload = true;
}

Reuq.prototype.getResource = function(resourceName, force, cb) {
  // coerce optional arguments to appropriate values
  if (arguments.length < 3 && typeof force === 'function') {
    cb = force;
    force = false;
  }
  var rq = this;
  var resource = this.controller.resources[resourceName];
  if (resource.data && !force && this.cacheIsValid(resourceName)) {
    cb(resource.data);
  } else {
    resource.loading = true;

    var url = typeof resource.url === 'function' ? resource.url(this) : resource.url;
    $.ajax({
      url: url,
      beforeSend: function(xhr) {
        Object.keys(resource.headers || {}).forEach(function(header){
          xhr.setRequestHeader(header, resource.headers[header]);
        })
      },
      success: function(resp) {
        resource.loading = false;
        resource.loaded = true;

        rq.setResource(resourceName, resource.dataKey ? resp[resource.dataKey] : resp);

        if (typeof cb === 'function') {
          cb(resource.data);
        }
      }
    })
  }
}

Reuq.prototype.setResource = function(resourceName, data) {
  var rq = this;
  var resource = this.controller.resources[resourceName];
  resource.data = data;
  resource.shouldReload = false;
  resource.updatedAt = new Date();
  this.runResourceSubscribers(resourceName, data);

  $('[rq-tmpl][rq-rsrc=' + resourceName + ']:not([manual-render])').each(function(id, el) {
    rq.renderData($(el).attr('rq-tmpl'), data);
  });
}

Reuq.prototype.runResourceSubscribers = function(resourceName, data) {
  var resource = this.controller.resources[resourceName];
  data = data || resource.data;
  this.runSubscribers(resource.subscribers, data)
}

Reuq.prototype.updateResource = function(resourceName, cb) {
  var rq = this;
  this.getResource(resourceName, function(data) {
    rq.setResource(resourceName, cb(data));
  });
}

Reuq.prototype.setLocal = function(name, data) {
  var rq = this;
  var local = this.controller.locals[name];
  local.data = data;
  this.runLocalSubscribers(name, data);

  $('[rq-tmpl][rq-local=' + name + ']:not([manual-render])').each(function(id, el) {
    rq.renderData($(el).attr('rq-tmpl'), data);
  });
}

Reuq.prototype.getLocal = function(name) {
  return this.controller.locals[name].data;
}

Reuq.prototype.updateLocal = function(name, cb) {
  var data = this.getLocal(name);
  this.setLocal(name, cb(data));
}

Reuq.prototype.runLocalSubscribers = function(name, data) {
  var local = this.controller.locals[name];
  data = data || local.data;
  this.runSubscribers(local.subscribers, data);
}

Reuq.prototype.runSubscribers = function(subscribers, data) {
  var rq = this;
  if (subscribers) {
    subscribers.forEach(function(subscriber) {
      var path = subscriber.split('.');
      var fn = rq.controller[path[0]][path[1]];
      fn.apply(rq, [data]);
    })
  }
}

//storeTemplates
Reuq.prototype._storeTemplates = function() {
  var rq = this;
  $('[rq-tmpl]').each(function(id, el) {
    var $el = $(el);
    rq.templates[$el.attr('rq-tmpl')] = {
      html: $el.prop('outerHTML'),
      dom: $el,
      dataKey: $el.attr('rq-data'),
      resourceName: $el.attr('rq-rsrc')
    };
  });
}

Reuq.prototype.addEvents = function($dom) {
  $dom = $dom || $('body');
  var rq = this;
  var evtSelector = '[rq-evt]:not([rq-tmpl] [rq-evt]):not([rq-tmpl][rq-evt])';
  $dom.find(evtSelector).addBack(evtSelector).each(function(id, el) {
    var $el = $(el);
    var evtConfig = $el.attr('rq-evt').split(' ')
    var evtType = evtConfig[0];
    var evtHandler = rq.controller.eventHandlers[evtConfig[1]];
    $el.on(evtType, function(e) {
      var handlerArgs = [$el].concat(evtConfig.slice(2))
      evtHandler.apply(rq, handlerArgs);
    })
  });
}

Reuq.prototype.getUtils = function() {
  var rq = this;
  console.log(rq);

  return {
    submit: function(form) {
      var data = form.serialize();
      var url = form.attr('action');
      var type = form.attr('method');

      $.ajax({ type: type, url: url, data: data })
        .done(function(data, status, jqXHR) {
          var cb = form.attr('rq-cb-done');
          if (cb) {
            rq.controller.callbacks[cb](data, status, form);
          }
        })
        .fail(function(jqXHR, status, error) {
          var cb = form.attr('rq-cb-fail');
          if (cb) {
            rq.controller.callbacks[cb](error, status, form, jqXHR);
          }
        });
    }
  }
}

$('head').append('<style type="text/css">[rq-tmpl] {display: none !important;}</style>');
window.Rq = window.Reuq = Reuq;
<|endoftext|>


<commit_before>"use strict";

var Rule = function() {
  if (this instanceof Rule) {
    this.association = null;
    this.errors = [];
    this.ifInvalidThenFunction = null;
    this.ifValidThenFunction = null;
    this.successors = [];
    this.valid = true;
  } else {
    return new Rule();
  }
};

Rule.prototype = {

  constructor: Rule,

  __invalidate: function(errors) {
    var self = this;
    this.valid = false;
    if (!Array.isArray(errors)) {
      errors = [errors];
    }
    errors.forEach(function(err) {
      if (typeof err === "string") {
        self.errors.push({ association: self.association, error: err });
      } else {
        self.errors.push(err);
      }
    });
  },

  __onValidate: function(done) {
  },

  validate: function(done) {
    var self = this;

    this.__onValidate(function() {
      if (self.valid) {
        if (self.ifValidThenFunction) {
          self.ifValidThenFunction();
        }
        if (self.successors.length > 0) {
          var counter = self.successors.length;

          self.successors.forEach(function(rule) {
            rule.validate(onRuleValidated);

            function onRuleValidated() {
              if (!rule.valid) {
                self.__invalidate(rule.errors);
              }
              counter--;
              if (counter === 0) {
                onValidationsComplete();
              }
            }
          });

          function onValidationsComplete() {
            done();
          }
          return;
        }
      } else {
        if (self.ifInvalidThenFunction) {
          self.ifInvalidThenFunction();
        }
      }
      done();
    });
  },

  ifValidThenValidate: function(rules) {
    if (!Array.isArray(rules)) {
      rules = [rules]
    }
    this.successors = rules;
    return this;
  },

  ifValidThenExecute: function(funcToExecute) {
    this.ifValidThenFunction = funcToExecute;
    return this;
  },

  ifInvalidThenExecute: function(funcToExecute) {
    this.ifInvalidThenFunction = funcToExecute;
    return this;
  }

};

module.exports = Rule;
<commit_msg>refactor rule.js to consume RuleValidator<commit_after>"use strict";

var RulesValidator = require('./rulesValidator');

var Rule = function() {
  if (this instanceof Rule) {
    this.association = null;
    this.errors = [];
    this.ifInvalidThenFunction = null;
    this.ifValidThenFunction = null;
    this.successors = [];
    this.valid = true;
  } else {
    return new Rule();
  }
};

Rule.prototype = {

  constructor: Rule,

  __invalidate: function(errors) {
    var self = this;
    this.valid = false;
    if (!Array.isArray(errors)) {
      errors = [errors];
    }
    errors.forEach(function(err) {
      if (typeof err === "string") {
        self.errors.push({ association: self.association, error: err });
      } else {
        self.errors.push(err);
      }
    });
  },

  __onValidate: function(done) {
  },

  validate: function(done) {
    var self = this;

    this.__onValidate(function() {
      if (self.valid) {
        if (self.ifValidThenFunction) {
          self.ifValidThenFunction();
        }
        if (self.successors.length > 0) {
          new RulesValidator(self.successors).validate(function() {
            self.successors.filter(function(rule) { return !rule.valid; })
                           .forEach(function(rule) {
                             self.__invalidate(rule.errors);
                           });

            done();
          });
          return;
        }
      } else {
        if (self.ifInvalidThenFunction) {
          self.ifInvalidThenFunction();
        }
      }
      done();
    });
  },

  ifValidThenValidate: function(rules) {
    if (!Array.isArray(rules)) {
      rules = [rules]
    }
    this.successors = rules;
    return this;
  },

  ifValidThenExecute: function(funcToExecute) {
    this.ifValidThenFunction = funcToExecute;
    return this;
  },

  ifInvalidThenExecute: function(funcToExecute) {
    this.ifInvalidThenFunction = funcToExecute;
    return this;
  }

};

module.exports = Rule;
<|endoftext|>


<commit_before>/*global Module, FS, ALLOC_STACK*/
/*jshint strict:false*/
var Sass = {
  style: {
    nested: 0,
    expanded: 1,
    compact: 2,
    compressed: 3
  },
  comments: {
    'none': 0,
    'default': 1
  },
  _options: {
    style: 0,
    comments: 0
  },
  _files: {},
  _path: '/sass/',

  FS: FS,
  Module: Module,

  options: function(options) {
    if (typeof options !== 'object') {
      return;
    }

    Object.keys(options).forEach(function(key) {
      switch (key) {
        case 'style':
          Sass._options[key] = Number(options[key]);
          break;
        case 'comments':
          Sass._options[key] = Number(!!options[key]);
          break;
      }
    });
  },

  _absolutePath: function(filename) {
    return Sass._path + (filename.slice(0, 1) === '/' ? filename.slice(1) : filename);
  },

  _createPath: function(parts) {
    var base = [];

    while (parts.length) {
      var directory = parts.shift();
      try {
        FS.createFolder(base.join('/'), directory, true, true);
      } catch(e) {
        // IGNORE file exists errors
      }

      base.push(directory);
    }
  },

  _ensurePath: function(filename) {
    var parts = filename.split('/');
    parts.pop();
    if (!parts.length) {
      return;
    }

    try {
      FS.stat(parts.join('/'));
      return;
    } catch(e) {
      Sass._createPath(parts);
    }
  },

  writeFile: function(filename, text) {
    var _absolute = filename.slice(0, 1) === '/';
    var path = Sass._absolutePath(filename);
    try {
      Sass._ensurePath(path);
      FS.writeFile(path, text);
      Sass._files[path] = filename;
      // create symlink for absolute path resolution
      if (_absolute) {
        Sass._ensurePath(filename);
        FS.symlink(path, filename);
      }
      return true;
    } catch(e) {
      return false;
    }
  },

  readFile: function(filename) {
    var path = Sass._absolutePath(filename);
    try {
      return FS.readFile(path, {encoding: 'utf8'});
    } catch(e) {
      return undefined;
    }
  },

  listFiles: function() {
    return Object.keys(Sass._files).map(function(path) {
      return Sass._files[path];
    });
  },

  removeFile: function(filename) {
    var _absolute = filename.slice(0, 1) === '/';
    var path = Sass._absolutePath(filename);
    try {
      FS.unlink(path);
      delete Sass._files[path];

      // undo symlink for absolute path resolution
      if (_absolute && FS.lstat(filename)) {
        FS.unlink(filename);
      }

      return true;
    } catch(e) {
      return false;
    }
  },

  compile: function(text) {
    try {
      // in C we would use char *ptr; foo(&ptr) - in EMScripten this is not possible,
      // so we allocate a pointer to a pointer on the stack by hand
      var errorPointerPointer = Module.allocate([0], 'i8', ALLOC_STACK);
      var result = Module.ccall(
        // C/++ function to call
        'sass_compile_emscripten',
        // return type
        'string',
        // parameter types
        ['string', 'number', 'number', 'string', 'i8'],
        // arguments for invocation
        [text, Sass._options.style, Sass._options.comments, Sass._path, errorPointerPointer]
      );
      // this is equivalent to *ptr
      var errorPointer = Module.getValue(errorPointerPointer, '*');
      // error string set? if not, it would be NULL and therefore 0
      if (errorPointer) {
        // pull string from pointer

        /*jshint camelcase:false*/
        errorPointer = Module.Pointer_stringify(errorPointer);
        /*jshint camelcase:true*/

        // Sass.compile("$foo:123px; .m { width:$foo; }") yields
        // errorPointer === "stdin:1: unbound variable $foobar"
        var error = errorPointer.match(/^stdin:(\d+):/);
        var message = errorPointer.slice(error[0].length).replace(/(^\s+)|(\s+$)/g, '');
        // throw new Error(message, 'string', error[1]);
        return {
          line: Number(error[1]),
          message: message
        };
      }

      return result;
    } catch(e) {
      // in case libsass.js was compiled without exception support (or something failed in parsing the error message)
      return {
        line: null,
        message: e.message,
        error: e
      };
    }
  }
};
<commit_msg>feature(api): add basic path helper functions<commit_after>/*global Module, FS, ALLOC_STACK*/
/*jshint strict:false*/

function stripLeadingSlash(text) {
  return text.slice(0, 1) === '/' ? text.slice(1) : text;
}

function addLeadingSlash(text) {
  return text.slice(0, 1) !== '/' ? ('/' + text) : text;
}

function stripTrailingSlash(text) {
  return text.slice(-1) === '/' ? text.slice(0, -1) : text;
}

function addTrailingSlash(text) {
  return text.slice(-1) !== '/' ? (text + '/') : text;
}

var Sass = {
  style: {
    nested: 0,
    expanded: 1,
    compact: 2,
    compressed: 3
  },
  comments: {
    'none': 0,
    'default': 1
  },
  _options: {
    style: 0,
    comments: 0
  },
  _files: {},
  _path: '/sass/',

  FS: FS,
  Module: Module,

  options: function(options) {
    if (typeof options !== 'object') {
      return;
    }

    Object.keys(options).forEach(function(key) {
      switch (key) {
        case 'style':
          Sass._options[key] = Number(options[key]);
          break;
        case 'comments':
          Sass._options[key] = Number(!!options[key]);
          break;
      }
    });
  },

  _absolutePath: function(filename) {
    return Sass._path + stripLeadingSlash(filename);
  },

  _createPath: function(parts) {
    var base = [];

    while (parts.length) {
      var directory = parts.shift();
      try {
        FS.createFolder(base.join('/'), directory, true, true);
      } catch(e) {
        // IGNORE file exists errors
      }

      base.push(directory);
    }
  },

  _ensurePath: function(filename) {
    var parts = filename.split('/');
    parts.pop();

    if (!parts.length) {
      return;
    }

    try {
      FS.stat(parts.join('/'));
      return;
    } catch(e) {
      Sass._createPath(parts);
    }
  },

  writeFile: function(filename, text) {
    var _absolute = filename.slice(0, 1) === '/';
    var path = Sass._absolutePath(filename);
    try {
      Sass._ensurePath(path);
      FS.writeFile(path, text);
      Sass._files[path] = filename;
      // create symlink for absolute path resolution
      if (_absolute) {
        Sass._ensurePath(filename);
        FS.symlink(path, filename);
      }
      return true;
    } catch(e) {
      return false;
    }
  },

  readFile: function(filename) {
    var path = Sass._absolutePath(filename);
    try {
      return FS.readFile(path, {encoding: 'utf8'});
    } catch(e) {
      return undefined;
    }
  },

  listFiles: function() {
    return Object.keys(Sass._files).map(function(path) {
      return Sass._files[path];
    });
  },

  removeFile: function(filename) {
    var _absolute = filename.slice(0, 1) === '/';
    var path = Sass._absolutePath(filename);
    try {
      FS.unlink(path);
      delete Sass._files[path];

      // undo symlink for absolute path resolution
      if (_absolute && FS.lstat(filename)) {
        FS.unlink(filename);
      }

      return true;
    } catch(e) {
      return false;
    }
  },

  compile: function(text) {
    try {
      // in C we would use char *ptr; foo(&ptr) - in EMScripten this is not possible,
      // so we allocate a pointer to a pointer on the stack by hand
      var errorPointerPointer = Module.allocate([0], 'i8', ALLOC_STACK);
      var result = Module.ccall(
        // C/++ function to call
        'sass_compile_emscripten',
        // return type
        'string',
        // parameter types
        ['string', 'number', 'number', 'string', 'i8'],
        // arguments for invocation
        [text, Sass._options.style, Sass._options.comments, Sass._path, errorPointerPointer]
      );
      // this is equivalent to *ptr
      var errorPointer = Module.getValue(errorPointerPointer, '*');
      // error string set? if not, it would be NULL and therefore 0
      if (errorPointer) {
        // pull string from pointer

        /*jshint camelcase:false*/
        errorPointer = Module.Pointer_stringify(errorPointer);
        /*jshint camelcase:true*/

        // Sass.compile("$foo:123px; .m { width:$foo; }") yields
        // errorPointer === "stdin:1: unbound variable $foobar"
        var error = errorPointer.match(/^stdin:(\d+):/);
        var message = errorPointer.slice(error[0].length).replace(/(^\s+)|(\s+$)/g, '');
        // throw new Error(message, 'string', error[1]);
        return {
          line: Number(error[1]),
          message: message
        };
      }

      return result;
    } catch(e) {
      // in case libsass.js was compiled without exception support (or something failed in parsing the error message)
      return {
        line: null,
        message: e.message,
        error: e
      };
    }
  }
};
<|endoftext|>


<commit_before>'use strict';

const FetchGoal = require('../../../ranvier-quests/lib/FetchGoal');
const EquipGoal = require('../../../ranvier-quests/lib/EquipGoal');

module.exports = (srcPath) => {
  const LevelUtil = require(srcPath + 'LevelUtil');

  return {
    1: {
      config: {
        title: "Find A Weapon",
        desc: "You're defenseless! Pick up the sword from the chest by typing 'get sword chest' then wield it with `wield sword`.",
        autoComplete: true,
        reward: (quest, player) => {
          player.emit('experience', LevelUtil.mobExp(player.level) * 5);
        }
      },
      goals: [
        {
          type: FetchGoal,
          config: {
            title: 'Retrieved a Sword',
            count: 1,
            item: "limbo:1"
          }
        },
        {
          type: EquipGoal,
          config: {
            title: 'Equipped a Sword',
            slot: 'wield'
          }
        }
      ]
    },

    2: {
      config: {
        title: "One Cheese Please",
        desc: "A rat's squeaks seem to indicate it wants some cheese. ",
        repeatable: true,
        reward: (quest, player) => {
          player.emit('experience', LevelUtil.mobExp(player.level) * 3);
        }
      },
      goals: [
        {
          type: FetchGoal,
          config: {
            title: 'Found Cheese',
            count: 0,
            item: "limbo:2",
            removeItem: true,
          }
        }
      ]
    }
  };
};
<commit_msg>Fix cheese quest definition<commit_after>'use strict';

const FetchGoal = require('../../../ranvier-quests/lib/FetchGoal');
const EquipGoal = require('../../../ranvier-quests/lib/EquipGoal');

module.exports = (srcPath) => {
  const LevelUtil = require(srcPath + 'LevelUtil');

  return {
    1: {
      config: {
        title: "Find A Weapon",
        desc: "You're defenseless! Pick up the sword from the chest by typing 'get sword chest' then wield it with `wield sword`.",
        autoComplete: true,
        reward: (quest, player) => {
          player.emit('experience', LevelUtil.mobExp(player.level) * 5);
        }
      },
      goals: [
        {
          type: FetchGoal,
          config: {
            title: 'Retrieved a Sword',
            count: 1,
            item: "limbo:1"
          }
        },
        {
          type: EquipGoal,
          config: {
            title: 'Equipped a Sword',
            slot: 'wield'
          }
        }
      ]
    },

    2: {
      config: {
        title: "One Cheese Please",
        desc: "A rat's squeaks seem to indicate it wants some cheese. ",
        repeatable: true,
        reward: (quest, player) => {
          player.emit('experience', LevelUtil.mobExp(player.level) * 3);
        }
      },
      goals: [
        {
          type: FetchGoal,
          config: {
            title: 'Found Cheese',
            count: 1,
            item: "limbo:2",
            removeItem: true,
          }
        }
      ]
    }
  };
};
<|endoftext|>


<commit_before>'use strict';

module.exports = (srcPath) => {
  const Broadcast = require(srcPath + 'Broadcast');
  const Parser = require(srcPath + 'CommandParser').CommandParser;

  return {
    aliases: [ 'unwield', 'unequip' ],
    usage: 'remove <item>',
    command : state => (arg, player) => {
      if (!arg.length) {
        return Broadcast.sayAt(player, 'Remove what?');
      }

      const [slot, item] = Parser.parseDot(arg, player.equipment, true);

      if (!item) {
        return Broadcast.sayAt(player, "You aren't wearing anything like that.");
      }

      player.unequip(slot);

      Broadcast.sayAt(player, `<green>You un-equip: </green>${item.display}<green>.</green>`);

      item.emit('unequip', player);
      player.emit('unequip', slot, item);
    }
  };
};
<commit_msg>Fix node error when trying to remove invalid equipment<commit_after>'use strict';

module.exports = (srcPath) => {
  const Broadcast = require(srcPath + 'Broadcast');
  const Parser = require(srcPath + 'CommandParser').CommandParser;

  return {
    aliases: [ 'unwield', 'unequip' ],
    usage: 'remove <item>',
    command : state => (arg, player) => {
      if (!arg.length) {
        return Broadcast.sayAt(player, 'Remove what?');
      }

      const result =  Parser.parseDot(arg, player.equipment, true);
      if (!result) {
        return Broadcast.sayAt(player, "You aren't wearing anything like that.");
      }

      const [slot, item] = result;
      player.unequip(slot);

      Broadcast.sayAt(player, `<green>You un-equip: </green>${item.display}<green>.</green>`);
      item.emit('unequip', player);
      player.emit('unequip', slot, item);
    }
  };
};
<|endoftext|>


<commit_before>var mainColor = new Value({
	value:'blue',
});
function StagRoot(args){
	var self = this;
	args = args || {};
	Windows.call(this, args);

	this.addClass('root');
	this.windowManager = new StagWindowManager();
	this.menu = this.windowManager.menuButton.panel;

	this.splash = new Element(document.getElementById('stag-splash'));

	this.append(this.sessionManager);
	this.append(this.windowManager);
	this.apps = {};
	document.body.appendChild(this.e);

}

StagRoot.prototype = Object.create(Windows.prototype);

StagRoot.prototype.registerApp = function(args){
	args = args || {};
	if (args.key === undefined || args.key in this.apps){
		return;
	}
	var app = {
		onRun: args.onRun || function(){},
		name: args.name || "Unnamed App",
		color: args.color || mainColor,
		key:args.key,
	};
	try{
		app.menuItem = new Element({
			className:'stag-menu-item clickable',
		});

		app.menuItem.append(app.name || "Unnamed App");
		app.menuItem.addClass(app.color || mainColor);
		this.menu.append(app.menuItem);
		app.menuItem.setAction(function(){
			app.onRun();
		});
	}
	catch(e){

	}
	this.apps[app.key] = app;
};

StagRoot.prototype.runApp = function(key){
	try{
		this.apps[key].onRun();
	}
	catch(e){

	}
}

StagRoot.prototype.onStartUp = function(){

}

StagRoot.prototype.start = function(){
	this.dispatchEvent('start');
}

StagRoot.prototype.init = function(){
	this.splash.hide();
	this.switchTo(this.windowManager);
	this.show();

}

StagRoot.prototype.addWindow = function(wind, handleArgs){
	var self = this;
	handleArgs = handleArgs || {};
	wind = wind || new StandardWindow();
	this.windowManager.windows.append(wind);
	var handle = wind.getHandle(handleArgs);
	this.windowManager.toolbar.append(handle);
	this.windowManager.windows.switchTo(wind);

	return wind;
}

function StagWindowManager(args){
	var self = this;
	args = args || {};
	Windows.call(this, args);
	this.e.style.justifyContent = 'center';
	this.bodyContainer = new Container({
		share:1,
	});
	this.toolbar = new Toolbar({
		className:'white mh-r',
	});
	this.menuButton = new Dropdown({
		className:'quiet',
		icon:'bars',
	},{
		className:'stag-menu',
		contentType:'lines',
	});
	this.filterElement = new TextInputCore({
		className:'stag-menu-filter',
	});
	this.filterElement.addClass(mainColor);
	this.menuButton.button.addClass(mainColor);
	this.menuButton.panel.append(this.filterElement);
	this.menuButton.panel.addClass(mainColor);
	this.toolbar.append(this.menuButton);
	this.windows = new Windows({
		share:1,
	});

	this.addClass('window-manager black');

	this.append(this.bodyContainer);
	this.bodyContainer.append(this.toolbar);
	this.bodyContainer.append(this.windows);

}

StagWindowManager.prototype = Object.create(Windows.prototype);

// To be removed
StagWindowManager.prototype.create = function(args, handleArgs){
	var self = this;
	args = args || {};
	args.color = args.color || 'white';
	var container = new Containers({
		share:1,
	});
	container.addClass(args.color);
	//self.windows.append(container);

	if(args.open == true){
		self.windows.appendAndShow(container);
	}
	else{
		self.windows.append(container);
	}
	handleArgs = handleArgs || {};
	handleArgs.text = args.title;
	var handle = container.getHandle(handleArgs);
	handle.addClass(args.color);
	this.toolbar.append(handle);

	return container;
}

var stag = new StagRoot();<commit_msg>Some fixes<commit_after>var mainColor = new Value({
	value:'blue',
});
function StagRoot(args){
	var self = this;
	args = args || {};
	Windows.call(this, args);

	this.addClass('root');
	this.windowManager = new StagWindowManager();
	this.menu = this.windowManager.menuButton.panel;

	this.splash = new Element(document.getElementById('stag-splash'));

	this.append(this.windowManager);
	this.apps = {};
	document.body.appendChild(this.e);

}

StagRoot.prototype = Object.create(Windows.prototype);

StagRoot.prototype.registerApp = function(args){
	args = args || {};
	var self = this;
	if (args.key === undefined || args.key in this.apps){
		return;
	}
	var app = {
		onRun: args.onRun || function(){},
		name: args.name || "Unnamed App",
		color: args.color || mainColor,
		key:args.key,
	};
	try{
		app.menuItem = new Element({
			className:'stag-menu-item clickable',
		});

		app.menuItem.append(app.name || "Unnamed App");
		app.menuItem.addClass(app.color || mainColor);
		this.menu.append(app.menuItem);
		app.menuItem.setAction(function(){
			self.runApp(app.key);
		});
	}
	catch(e){

	}
	this.apps[app.key] = app;
};

StagRoot.prototype.runApp = function(key){
	try{
		this.apps[key].onRun(this.apps[key]);
	}
	catch(e){

	}
}

StagRoot.prototype.onStartUp = function(){

}

StagRoot.prototype.start = function(){
	this.dispatchEvent('start');
}

StagRoot.prototype.init = function(){
	this.splash.hide();
	this.switchTo(this.windowManager);
	this.show();

}

StagRoot.prototype.addWindow = function(wind, handleArgs){
	var self = this;
	handleArgs = handleArgs || {};
	wind = wind || new StandardWindow();
	this.windowManager.windows.append(wind);
	var handle = wind.getHandle(handleArgs);
	this.windowManager.toolbar.append(handle);
	this.windowManager.windows.switchTo(wind);

	return wind;
}

function StagWindowManager(args){
	var self = this;
	args = args || {};
	Windows.call(this, args);
	this.e.style.justifyContent = 'center';
	this.bodyContainer = new Container({
		share:1,
	});
	this.toolbar = new Toolbar({
		className:'white mh-r',
	});
	this.menuButton = new Dropdown({
		className:'quiet',
		icon:'bars',
	},{
		className:'stag-menu',
		contentType:'lines',
	});
	this.filterElement = new TextInputCore({
		className:'stag-menu-filter',
	});
	this.filterElement.addClass('white');
	this.menuButton.button.addClass(mainColor);
	this.menuButton.panel.append(this.filterElement);
	this.menuButton.panel.addClass('white');
	this.toolbar.append(this.menuButton);
	this.windows = new Windows({
		share:1,
	});

	this.addClass('window-manager black');

	this.append(this.bodyContainer);
	this.bodyContainer.append(this.toolbar);
	this.bodyContainer.append(this.windows);

}

StagWindowManager.prototype = Object.create(Windows.prototype);

// To be removed
StagWindowManager.prototype.create = function(args, handleArgs){
	var self = this;
	args = args || {};
	args.color = args.color || 'white';
	var container = new Containers({
		share:1,
	});
	container.addClass(args.color);
	//self.windows.append(container);

	if(args.open == true){
		self.windows.appendAndShow(container);
	}
	else{
		self.windows.append(container);
	}
	handleArgs = handleArgs || {};
	handleArgs.text = args.title;
	var handle = container.getHandle(handleArgs);
	handle.addClass(args.color);
	this.toolbar.append(handle);

	return container;
}

var stag = new StagRoot();<|endoftext|>


<commit_before>var CalcForm = {

	getFieldLabel: function($field) {
		$formGroup = $field.closest('.form-group');
		$labelEl = $formGroup.find('.control-label');
		return $labelEl == null ? "": $labelEl.text();
	},
	removeErrors: function (form) {
		form.find('.form-group').removeClass('has-error');
	},
	updateErrors: function(form, errors) {
		CalcForm.removeErrors(form);

		$.each(errors, function(i, error) {
			var fieldName = error.field;
			var $field = form.find('[name=' + fieldName + ']');
			if ( $field != null ) {
				$formGroup = $field.closest('.form-group');
				$formGroup.addClass('has-error');

				var fieldLabel = CalcForm.getFieldLabel($field);
				var message = fieldLabel + " " + error.defaultMessage;

				$field.tooltip({
					title: message,
					container: 'body'
				});
			}
		});
	}

};<commit_msg>Form validation: show error tooltip<commit_after>var CalcForm = {

	getFieldLabel: function($field) {
		$formGroup = $field.closest('.form-group');
		$labelEl = $formGroup.find('.control-label');
		return $labelEl == null ? "": $labelEl.text();
	},
	removeErrors: function (form) {
		form.find('.form-group').removeClass('has-error');
		form.find('.form-control').tooltip('destroy');
	},
	updateErrors: function(form, errors) {
		CalcForm.removeErrors(form);

		$.each(errors, function(i, error) {
			var fieldName = error.field;
			var $field = form.find('[name=' + fieldName + ']');
			if ( $field != null ) {
				CalcForm._createErrorTooltip($field, error);
			}
		});
	},
	_createErrorTooltip: function($field, error) {
		$formGroup = $field.closest('.form-group');
		$formGroup.addClass('has-error');

		var fieldLabel = CalcForm.getFieldLabel($field);
		var message = fieldLabel + " " + error.defaultMessage;

		$field.tooltip({
			title: message,
			container: 'body'
		});
	}

};<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2017 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.u2.view',
  name: 'ImageBlobView',
  extends: 'foam.u2.View',
  requires: [
    'foam.blob.BlobBlob'
  ],
  imports: [
    'blobService'
  ],
  properties: [
    'data',
  ],
  methods: [
    function initE() {
      var view = this;
      this.
        start('img').
        attrs({
          src: this.data$.map(function(data) {
            return view.blobService.urlFor(data) || '';
          })
        }).
        end().
        add(this.slot(function(mode) {
          if ( mode == foam.u2.DisplayMode.RW ) {
            return this.
              E('input').
              attrs({ type: 'file' }).
              on('change', this.onChange);
          }
          return this.E('span');
        }, this.mode$));
    }
  ],
  listeners: [
    function onChange(e) {
      var file = e.target.files[0];

      this.data = this.BlobBlob.create({
        blob: file
      });
    }
  ]
});
<commit_msg>ImageBlobView: Don't use view.blobService.urlFor when dealing with BlobBlobs.<commit_after>/**
 * @license
 * Copyright 2017 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.u2.view',
  name: 'ImageBlobView',
  extends: 'foam.u2.View',
  requires: [
    'foam.blob.BlobBlob'
  ],
  imports: [
    'blobService'
  ],
  properties: [
    'data',
  ],
  methods: [
    function initE() {
      var view = this;
      this.
        start('img').
        attrs({
          src: this.data$.map(function(data) {
            return view.BlobBlob.isInstance(data) ?
              URL.createObjectURL(data.blob) :
              ( view.blobService.urlFor(data) || '' );
          })
        }).
        end().
        add(this.slot(function(mode) {
          if ( mode == foam.u2.DisplayMode.RW ) {
            return this.
              E('input').
              attrs({ type: 'file' }).
              on('change', this.onChange);
          }
          return this.E('span');
        }, this.mode$));
    }
  ],
  listeners: [
    function onChange(e) {
      var file = e.target.files[0];

      this.data = this.BlobBlob.create({
        blob: file
      });
    }
  ]
});
<|endoftext|>


<commit_before>/**
 * angular-ui-carousel
 * for example:
 * length = 8, show = 4, scroll = 3, current = 0
 *          ---------
 *          |       |
 *  |4|5|6|7|0|1|2|3|4|5|6|7|1|2|3|4
 *          |       |
 *          ---------
 * rectangle is visible for users
 */
angular.module('ui.carousel.controllers')
.controller('CarouselController', [
  '$scope', '$element', '$timeout', '$q', 'Carousel',
  function ($scope, $element, $timeout, $q, Carousel) {

    /**
     * Initial carousel
     *
     * Mirgate to angularjs 1.6
     * @see https://docs.angularjs.org/guide/migration#commit-bcd0d4
     */
    this.$onInit = () => {
      this.initOptions();
      this.initRanges();
      this.setProps();
      this.setupInfinite();
    };

    /**
     * Init option based on directive config
     */
    this.initOptions = () => {
      this.options = angular.extend({}, Carousel.getOptions());

      // TODO customize attribute from directive
      if (this.initialSlide !== undefined) {
        this.options.initialSlide = this.initialSlide;
      }
      if (this.fade !== undefined) {
        this.options.fade = this.fade;
      }
      if (this.autoplay !== undefined) {
        this.options.autoplay = this.autoplay;
      }
      if (this.autoplaySpeed !== undefined) {
        this.options.autoplaySpeed = this.autoplaySpeed;
      }
      if (this.cssEase !== undefined) {
        this.options.cssEase = this.cssEase;
      }
      if (this.speed !== undefined) {
        this.options.speed = this.speed;
      }
      if (this.infinite !== undefined) {
        this.options.infinite = this.infinite;
      }
      if (this.arrows !== undefined) {
        this.options.arrows = this.arrows;
      }
      if (this.dots !== undefined) {
        this.options.dots = this.dots;
      }

      // TODO write more options for fade mode
      // In fade mode we have to setting slides-to-show and slides-to-scroll
      // to 1 slide
      if (this.options.fade) {
        this.options.slidesToShow = 1;
        this.options.slidesToScroll = 1;
      } else {
        if (this.show) {
          this.options.slidesToShow = this.show;
        }
        if (this.scroll) {
          this.options.slidesToScroll = this.scroll;
        }
      }
    };

    /**
     * init variables, slides, ..
     */
    this.initRanges = () => {
      if (!this.slides) {
        this.slides = [];
      }

      this.isCarouselReady = false;
      this.isTrackMoving = false;
      this.track = $element.find('.track');
      this.width = 1; // Fake width
      this.currentSlide = this.options.initialSlide;
      this.trackStyle = {};
      this.slideStyle = {};

      this.isVisibleDots = false;
      this.isVisiblePrev = false;
      this.isVisibleNext = false;

      this.isClickablePrev = false;
      this.isClickableNext = false;

      this.animType = null;
      this.transformType = null;
      this.transitionType = null;

      this.slidesInTrack = angular.copy(this.slides);
    };

    /**
     * Init UI and carousel track
     */
    this.initUI = () => {
      $timeout(() => {
        this.width = $element[0].clientWidth;
        this.updateItemStyle();
        this.initTrack();
      });
    };

    /**
     * update common style for each carousel item
     */
    this.updateItemStyle = () => {
      this.itemWidth = this.width / this.options.slidesToShow;
      this.slideStyle = {
        'width': this.itemWidth + 'px'
      };
    };

    /**
     * init carousel track
     * also make Carousel is Ready
     */
    this.initTrack = () => {
      const itemWidth = this.width / this.options.slidesToShow;
      const trackWidth = itemWidth * this.slidesInTrack.length;

      this.trackStyle.width = trackWidth + 'px';

      this
        .slideHandler(this.currentSlide)
        .finally(() => {
          this.isCarouselReady = true;

          if (!this.options.fade) {
            this.refreshTrackStyle();
          }

          // onInit callback
          if (this.onInit) {
            this.onInit();
          }
        })
        .catch(() => {
          // Catch err
        });
    };

    /**
     * @see https://github.com/kenwheeler/slick/blob/master/slick/slick.js#L680
     *
     * Sync slide to place it should be
     * for example:
     * - 9 total, 3 show, 3 scroll, current 1
     *   => next index = 3 (previous index counted = 0)
     *
     * and scroll to next page:
     * - 6 total, 1 show, 1 scroll, current 0 => next index = 1
     * - 9 total, 3 show, 3 scroll, current 1 => next index = 3
     * - 9 total, 3 show, 3 scroll, current 3 => next index = 6
     * - 9 total, 3 show, 3 scroll, current 8 => next index = 3
     * - 8 total, 4 show, 3 scroll, current 1 => next index = 4
     */
    this.next = () => {
      if (!this.isClickableNext) {
        return false;
      }

      const indexOffset = this.getIndexOffset();
      const slideOffset = indexOffset === 0
        ? this.options.slidesToScroll
        : indexOffset;

      this
        .slideHandler(this.currentSlide + slideOffset)
        .catch(() => {
          // Catch err
        });
    };

    /**
     * move to previous slide
     * same calculate with next
     * @see next function
     */
    this.prev = () => {
      if (!this.isClickablePrev) {
        return false;
      }

      const indexOffset = this.getIndexOffset();
      const slideOffset = indexOffset === 0
        ? this.options.slidesToScroll
        : this.options.slidesToShow - indexOffset;

      this
        .slideHandler(this.currentSlide - slideOffset)
        .catch(() => {
          // Catch err
        });
    };

    /**
     * Get index offset
     */
    this.getIndexOffset = () => {
      const scrollOffset = this.slides.length % this.options.slidesToScroll !== 0;
      const indexOffset = scrollOffset
        ? 0
        : (this.slides.length - this.currentSlide) % this.options.slidesToScroll;

      return indexOffset;
    };

    /**
     * move to page
     * @params int page
     * Page counter from 0 (start = 0)
     */
    this.movePage = (page) => {
      const target = this.options.slidesToScroll * page;
      this
        .slideHandler(target)
        .catch(() => {
          // Catch err
        });
    };

    /**
     * hanlder carousel
     * @description move carousel to correct page
     *
     * @params int index
     */
    this.slideHandler = (index) => {
      // TODO prevent when slides not exists
      if (!this.slides) {
        return $q.reject('Carousel not fully setup');
      }

      // TODO Prevent when track is moving
      if (this.isTrackMoving) {
        return $q.reject('Track is moving');
      }

      const len = this.slides.length;
      const show = this.options.slidesToShow;

      if (len <= show) {
        return $q.reject('Length of slides smaller than slides to show');
      }

      // We need target to destination
      // and a anim slide to translate track
      //
      // anim = animSlide (which we use to move)
      // target = targetSlide
      const anim = index;
      let target = null;

      if (anim < 0) {
       if (len % this.options.slidesToScroll !== 0) {
          target = len - (len % this.options.slidesToScroll);
        } else {
          target = len + anim;
        }
      } else if (anim >= len) {
        if (len % this.options.slidesToScroll !== 0) {
          target = 0;
        } else {
          target = anim - len;
        }
      } else {
        target = anim;
      }

      if (this.onBeforeChange) {
        this.onBeforeChange(this.currentSlide, target);
      }

      // Fade handler
      if (this.options.fade) {
        this.currentSlide = target;

        // XXX
        // afterChange method
        // fire after faded
        // Should be revised
        $timeout(() => {
          if (this.onAfterChange) {
            this.onAfterChange(this.currentSlide);
          }
        }, this.options.speed);
        return $q.resolve('Handler fade');
      }

      // No-fade handler
      let left = -1 * target * this.itemWidth;
      if (this.options.infinite) {
        left = -1 * (anim + show) * this.itemWidth;
      }

      this.isTrackMoving = true;
      return this
        .moveTrack(left)
        .then(() => {
          this.isTrackMoving = false;
          this.currentSlide = target;
          this.autoplayTrack();

          if (target !== anim) {
            this.correctTrack();
          }

          if (!this.options.infinite) {
            if (this.currentSlide === 0) {
              this.isClickablePrev = false;
            } else if (this.currentSlide === this.slidesInTrack.length - 1) {
              this.isClickableNext = false;
            } else {
              this.isClickablePrev = true;
              this.isClickableNext = true;
            }
          }

          // XXX
          // afterChange method
          // fire after 200ms wakeup and correct track
          // Should be revised
          $timeout(() => {
            if (this.onAfterChange) {
              this.onAfterChange(this.currentSlide);
            }
          }, 200);
        });
    };

    /**
     * moveTrack
     * move track to left position using css3 translate
     * for example left: -1000px
     */
    this.moveTrack = (left) => {
      const deferred = $q.defer();
      if (this.options.vertical === false) {
        this.trackStyle[this.animType] = 'translate3d(' + left + 'px, 0px, 0px)';
      } else {
        this.trackStyle[this.animType] = 'translate3d(0px, ' + left + 'px, 0px)';
      }

      $timeout(() => {
        deferred.resolve('Track moved');
      }, this.options.speed);

      return deferred.promise;
    };

    /**
     * correctTrack
     * @description correct track after move to animSlide we have to move track
     * to exactly its position
     */
    this.correctTrack = () => {
      if (this.options.infinite) {
        let left = -1 * (this.currentSlide + this.options.slidesToShow) * this.itemWidth;

        // Move without anim
        this.trackStyle[this.transitionType] =
          this.transformType + ' ' + 0 + 'ms ' + this.options.cssEase;

        this.isTrackMoving = true;
        $timeout(() => {
          this.trackStyle[this.animType] = 'translate3d(' + left + 'px, 0, 0px)';

          // Revert animation
          $timeout(() => {
            this.refreshTrackStyle();
            this.isTrackMoving = false;
          }, 200);
        });
      }
    };

    /**
     * Refresh track style
     */
    this.refreshTrackStyle = () => {
      this.trackStyle[this.transitionType] =
        this.transformType + ' ' + this.options.speed + 'ms ' + this.options.cssEase;
    };

    /**
     * autoplay track
     * @description autoplay = true
     */
    this.autoplayTrack = () => {
      if (this.options.autoplay) {
        if (this.timeout) {
          $timeout.cancel(this.timeout);
        }

        this.timeout = $timeout(() => {
          this.next();

          $timeout.cancel(this.timeout);
          this.timeout = null;
        }, this.options.autoplaySpeed);
      }
    };

    this.getSlideStyle = index => {
      let style = this.slideStyle;
      if (this.options.fade) {
        const left = -1 * index * this.itemWidth;
        const uniqueStyle = {
          position: 'relative',
          top: '0px',
          left: left + 'px',
          'z-index': index === this.currentSlide? 10 : 9,
          opacity: index === this.currentSlide? 1 : 0
        };

        if (index >= this.currentSlide - 1 && index <= this.currentSlide + 1) {
          uniqueStyle.transition = 'opacity 250ms linear';
        }

        style = angular.extend(style, uniqueStyle);
      }

      return style;
    };

    /**
     * setupInfinite
     * To make carouse infinite we need close number of slidesToShow elements to
     * previous elements and to after elements
     *
     * length = 8, show = 4, scroll = 3, current = 0
     *          ---------
     *          |       |
     *  |4|5|6|7|0|1|2|3|4|5|6|7|1|2|3|4
     *          |       |
     *          ---------
     */
    this.setupInfinite = () => {
      // Clone
      const len = this.slides.length;
      const show = this.options.slidesToShow;

      if (this.options.infinite && this.options.fade === false) {
        if (len > show) {
          const number = show;
          for (let i = 0; i < number; i++) {
            this.slidesInTrack.push(angular.copy(this.slides[i]));
          }
          for (let i = len -1; i >= len - show; i--) {
            this.slidesInTrack.unshift(angular.copy(this.slides[i]));
          }
        }
      }
    };

    /**
     * get number of dosts
     *
     * @return Array
     */
    this.getDots = () => {
      if (!this.slides) {
        return [];
      }

      const dots = Math.ceil(this.slides.length / this.options.slidesToScroll);

      let res = [];
      for (let i = 0; i < dots; i++) {
        res.push(i);
      }
      return res;
    };

    /**
     * set carousel property
     *
     * - animType
     * - transformType
     * - transitionType
     */
    this.setProps = () => {
      const bodyStyle = document.body.style;

      /* eslint-disable */
      if (bodyStyle.OTransform !== undefined) {
        this.animType = 'OTransform';
        this.transformType = '-o-transform';
        this.transitionType = 'OTransition';
      }
      if (bodyStyle.MozTransform !== undefined) {
        this.animType = 'MozTransform';
        this.transformType = '-moz-transform';
        this.transitionType = 'MozTransition';
      }
      if (bodyStyle.webkitTransform !== undefined) {
        this.animType = 'webkitTransform';
        this.transformType = '-webkit-transform';
        this.transitionType = 'webkitTransition';
      }
      if (bodyStyle.msTransform !== undefined) {
        this.animType = 'msTransform';
        this.transformType = '-ms-transform';
        this.transitionType = 'msTransition';
      }
      if (bodyStyle.transform !== undefined && this.animType !== false) {
        this.animType = 'transform';
        this.transformType = 'transform';
        this.transitionType = 'transition';
      }
      /* eslint-enable */

      this.transformsEnabled = true;
    };

    this.refreshCarousel = () => {
      if (this.slides && this.slides.length && this.slides.length > this.options.slidesToShow) {
        this.isVisibleDots = true;
        this.isVisiblePrev = true;
        this.isVisibleNext = true;
        this.isClickablePrev = true;
        this.isClickableNext = true;
      }

      // Re-init UI
      this.initUI();
    };

    /**
     * refresh model
     */
    $scope.$watch('ctrl.slides', () => {
      this.refreshCarousel();
    });

    // Prior to v1.5, we need to call `$onInit()` manually.
    // (Bindings will always be pre-assigned in these versions.)
    if (angular.version.major === 1 && angular.version.minor < 5) {
      this.$onInit();
    }
  }]);
<commit_msg>Set next and prev button will be visible in the option<commit_after>/**
 * angular-ui-carousel
 * for example:
 * length = 8, show = 4, scroll = 3, current = 0
 *          ---------
 *          |       |
 *  |4|5|6|7|0|1|2|3|4|5|6|7|1|2|3|4
 *          |       |
 *          ---------
 * rectangle is visible for users
 */
angular.module('ui.carousel.controllers')
.controller('CarouselController', [
  '$scope', '$element', '$timeout', '$q', 'Carousel',
  function ($scope, $element, $timeout, $q, Carousel) {

    /**
     * Initial carousel
     *
     * Mirgate to angularjs 1.6
     * @see https://docs.angularjs.org/guide/migration#commit-bcd0d4
     */
    this.$onInit = () => {
      this.initOptions();
      this.initRanges();
      this.setProps();
      this.setupInfinite();
    };

    /**
     * Init option based on directive config
     */
    this.initOptions = () => {
      this.options = angular.extend({}, Carousel.getOptions());

      // TODO customize attribute from directive
      if (this.initialSlide !== undefined) {
        this.options.initialSlide = this.initialSlide;
      }
      if (this.fade !== undefined) {
        this.options.fade = this.fade;
      }
      if (this.autoplay !== undefined) {
        this.options.autoplay = this.autoplay;
      }
      if (this.autoplaySpeed !== undefined) {
        this.options.autoplaySpeed = this.autoplaySpeed;
      }
      if (this.cssEase !== undefined) {
        this.options.cssEase = this.cssEase;
      }
      if (this.speed !== undefined) {
        this.options.speed = this.speed;
      }
      if (this.infinite !== undefined) {
        this.options.infinite = this.infinite;
      }
      if (this.arrows !== undefined) {
        this.options.arrows = this.arrows;
      }
      if (this.dots !== undefined) {
        this.options.dots = this.dots;
      }
      if (this.isVisiblePrev !== undefined) {
        this.options.isVisiblePrev = this.isVisiblePrev;
      }
      if (this.isVisibleNext !== undefined) {
        this.options.isVisibleNext = this.isVisibleNext;
      }

      // TODO write more options for fade mode
      // In fade mode we have to setting slides-to-show and slides-to-scroll
      // to 1 slide
      if (this.options.fade) {
        this.options.slidesToShow = 1;
        this.options.slidesToScroll = 1;
      } else {
        if (this.show) {
          this.options.slidesToShow = this.show;
        }
        if (this.scroll) {
          this.options.slidesToScroll = this.scroll;
        }
      }
    };

    /**
     * init variables, slides, ..
     */
    this.initRanges = () => {
      if (!this.slides) {
        this.slides = [];
      }

      this.isCarouselReady = false;
      this.isTrackMoving = false;
      this.track = $element.find('.track');
      this.width = 1; // Fake width
      this.currentSlide = this.options.initialSlide;
      this.trackStyle = {};
      this.slideStyle = {};

      this.isVisibleDots = false;
      this.isVisiblePrev = this.options.isVisiblePrev || false;
      this.isVisibleNext = this.options.isVisibleNext || false;

      this.isClickablePrev = false;
      this.isClickableNext = false;

      this.animType = null;
      this.transformType = null;
      this.transitionType = null;

      this.slidesInTrack = angular.copy(this.slides);
    };

    /**
     * Init UI and carousel track
     */
    this.initUI = () => {
      $timeout(() => {
        this.width = $element[0].clientWidth;
        this.updateItemStyle();
        this.initTrack();
      });
    };

    /**
     * update common style for each carousel item
     */
    this.updateItemStyle = () => {
      this.itemWidth = this.width / this.options.slidesToShow;
      this.slideStyle = {
        'width': this.itemWidth + 'px'
      };
    };

    /**
     * init carousel track
     * also make Carousel is Ready
     */
    this.initTrack = () => {
      const itemWidth = this.width / this.options.slidesToShow;
      const trackWidth = itemWidth * this.slidesInTrack.length;

      this.trackStyle.width = trackWidth + 'px';

      this
        .slideHandler(this.currentSlide)
        .finally(() => {
          this.isCarouselReady = true;

          if (!this.options.fade) {
            this.refreshTrackStyle();
          }

          // onInit callback
          if (this.onInit) {
            this.onInit();
          }
        })
        .catch(() => {
          // Catch err
        });
    };

    /**
     * @see https://github.com/kenwheeler/slick/blob/master/slick/slick.js#L680
     *
     * Sync slide to place it should be
     * for example:
     * - 9 total, 3 show, 3 scroll, current 1
     *   => next index = 3 (previous index counted = 0)
     *
     * and scroll to next page:
     * - 6 total, 1 show, 1 scroll, current 0 => next index = 1
     * - 9 total, 3 show, 3 scroll, current 1 => next index = 3
     * - 9 total, 3 show, 3 scroll, current 3 => next index = 6
     * - 9 total, 3 show, 3 scroll, current 8 => next index = 3
     * - 8 total, 4 show, 3 scroll, current 1 => next index = 4
     */
    this.next = () => {
      if (!this.isClickableNext) {
        return false;
      }

      const indexOffset = this.getIndexOffset();
      const slideOffset = indexOffset === 0
        ? this.options.slidesToScroll
        : indexOffset;

      this
        .slideHandler(this.currentSlide + slideOffset)
        .catch(() => {
          // Catch err
        });
    };

    /**
     * move to previous slide
     * same calculate with next
     * @see next function
     */
    this.prev = () => {
      if (!this.isClickablePrev) {
        return false;
      }

      const indexOffset = this.getIndexOffset();
      const slideOffset = indexOffset === 0
        ? this.options.slidesToScroll
        : this.options.slidesToShow - indexOffset;

      this
        .slideHandler(this.currentSlide - slideOffset)
        .catch(() => {
          // Catch err
        });
    };

    /**
     * Get index offset
     */
    this.getIndexOffset = () => {
      const scrollOffset = this.slides.length % this.options.slidesToScroll !== 0;
      const indexOffset = scrollOffset
        ? 0
        : (this.slides.length - this.currentSlide) % this.options.slidesToScroll;

      return indexOffset;
    };

    /**
     * move to page
     * @params int page
     * Page counter from 0 (start = 0)
     */
    this.movePage = (page) => {
      const target = this.options.slidesToScroll * page;
      this
        .slideHandler(target)
        .catch(() => {
          // Catch err
        });
    };

    /**
     * hanlder carousel
     * @description move carousel to correct page
     *
     * @params int index
     */
    this.slideHandler = (index) => {
      // TODO prevent when slides not exists
      if (!this.slides) {
        return $q.reject('Carousel not fully setup');
      }

      // TODO Prevent when track is moving
      if (this.isTrackMoving) {
        return $q.reject('Track is moving');
      }

      const len = this.slides.length;
      const show = this.options.slidesToShow;

      if (len <= show) {
        return $q.reject('Length of slides smaller than slides to show');
      }

      // We need target to destination
      // and a anim slide to translate track
      //
      // anim = animSlide (which we use to move)
      // target = targetSlide
      const anim = index;
      let target = null;

      if (anim < 0) {
       if (len % this.options.slidesToScroll !== 0) {
          target = len - (len % this.options.slidesToScroll);
        } else {
          target = len + anim;
        }
      } else if (anim >= len) {
        if (len % this.options.slidesToScroll !== 0) {
          target = 0;
        } else {
          target = anim - len;
        }
      } else {
        target = anim;
      }

      if (this.onBeforeChange) {
        this.onBeforeChange(this.currentSlide, target);
      }

      // Fade handler
      if (this.options.fade) {
        this.currentSlide = target;

        // XXX
        // afterChange method
        // fire after faded
        // Should be revised
        $timeout(() => {
          if (this.onAfterChange) {
            this.onAfterChange(this.currentSlide);
          }
        }, this.options.speed);
        return $q.resolve('Handler fade');
      }

      // No-fade handler
      let left = -1 * target * this.itemWidth;
      if (this.options.infinite) {
        left = -1 * (anim + show) * this.itemWidth;
      }

      this.isTrackMoving = true;
      return this
        .moveTrack(left)
        .then(() => {
          this.isTrackMoving = false;
          this.currentSlide = target;
          this.autoplayTrack();

          if (target !== anim) {
            this.correctTrack();
          }

          if (!this.options.infinite) {
            if (this.currentSlide === 0) {
              this.isClickablePrev = false;
            } else if (this.currentSlide === this.slidesInTrack.length - 1) {
              this.isClickableNext = false;
            } else {
              this.isClickablePrev = true;
              this.isClickableNext = true;
            }
          }

          // XXX
          // afterChange method
          // fire after 200ms wakeup and correct track
          // Should be revised
          $timeout(() => {
            if (this.onAfterChange) {
              this.onAfterChange(this.currentSlide);
            }
          }, 200);
        });
    };

    /**
     * moveTrack
     * move track to left position using css3 translate
     * for example left: -1000px
     */
    this.moveTrack = (left) => {
      const deferred = $q.defer();
      if (this.options.vertical === false) {
        this.trackStyle[this.animType] = 'translate3d(' + left + 'px, 0px, 0px)';
      } else {
        this.trackStyle[this.animType] = 'translate3d(0px, ' + left + 'px, 0px)';
      }

      $timeout(() => {
        deferred.resolve('Track moved');
      }, this.options.speed);

      return deferred.promise;
    };

    /**
     * correctTrack
     * @description correct track after move to animSlide we have to move track
     * to exactly its position
     */
    this.correctTrack = () => {
      if (this.options.infinite) {
        let left = -1 * (this.currentSlide + this.options.slidesToShow) * this.itemWidth;

        // Move without anim
        this.trackStyle[this.transitionType] =
          this.transformType + ' ' + 0 + 'ms ' + this.options.cssEase;

        this.isTrackMoving = true;
        $timeout(() => {
          this.trackStyle[this.animType] = 'translate3d(' + left + 'px, 0, 0px)';

          // Revert animation
          $timeout(() => {
            this.refreshTrackStyle();
            this.isTrackMoving = false;
          }, 200);
        });
      }
    };

    /**
     * Refresh track style
     */
    this.refreshTrackStyle = () => {
      this.trackStyle[this.transitionType] =
        this.transformType + ' ' + this.options.speed + 'ms ' + this.options.cssEase;
    };

    /**
     * autoplay track
     * @description autoplay = true
     */
    this.autoplayTrack = () => {
      if (this.options.autoplay) {
        if (this.timeout) {
          $timeout.cancel(this.timeout);
        }

        this.timeout = $timeout(() => {
          this.next();

          $timeout.cancel(this.timeout);
          this.timeout = null;
        }, this.options.autoplaySpeed);
      }
    };

    this.getSlideStyle = index => {
      let style = this.slideStyle;
      if (this.options.fade) {
        const left = -1 * index * this.itemWidth;
        const uniqueStyle = {
          position: 'relative',
          top: '0px',
          left: left + 'px',
          'z-index': index === this.currentSlide? 10 : 9,
          opacity: index === this.currentSlide? 1 : 0
        };

        if (index >= this.currentSlide - 1 && index <= this.currentSlide + 1) {
          uniqueStyle.transition = 'opacity 250ms linear';
        }

        style = angular.extend(style, uniqueStyle);
      }

      return style;
    };

    /**
     * setupInfinite
     * To make carouse infinite we need close number of slidesToShow elements to
     * previous elements and to after elements
     *
     * length = 8, show = 4, scroll = 3, current = 0
     *          ---------
     *          |       |
     *  |4|5|6|7|0|1|2|3|4|5|6|7|1|2|3|4
     *          |       |
     *          ---------
     */
    this.setupInfinite = () => {
      // Clone
      const len = this.slides.length;
      const show = this.options.slidesToShow;

      if (this.options.infinite && this.options.fade === false) {
        if (len > show) {
          const number = show;
          for (let i = 0; i < number; i++) {
            this.slidesInTrack.push(angular.copy(this.slides[i]));
          }
          for (let i = len -1; i >= len - show; i--) {
            this.slidesInTrack.unshift(angular.copy(this.slides[i]));
          }
        }
      }
    };

    /**
     * get number of dosts
     *
     * @return Array
     */
    this.getDots = () => {
      if (!this.slides) {
        return [];
      }

      const dots = Math.ceil(this.slides.length / this.options.slidesToScroll);

      let res = [];
      for (let i = 0; i < dots; i++) {
        res.push(i);
      }
      return res;
    };

    /**
     * set carousel property
     *
     * - animType
     * - transformType
     * - transitionType
     */
    this.setProps = () => {
      const bodyStyle = document.body.style;

      /* eslint-disable */
      if (bodyStyle.OTransform !== undefined) {
        this.animType = 'OTransform';
        this.transformType = '-o-transform';
        this.transitionType = 'OTransition';
      }
      if (bodyStyle.MozTransform !== undefined) {
        this.animType = 'MozTransform';
        this.transformType = '-moz-transform';
        this.transitionType = 'MozTransition';
      }
      if (bodyStyle.webkitTransform !== undefined) {
        this.animType = 'webkitTransform';
        this.transformType = '-webkit-transform';
        this.transitionType = 'webkitTransition';
      }
      if (bodyStyle.msTransform !== undefined) {
        this.animType = 'msTransform';
        this.transformType = '-ms-transform';
        this.transitionType = 'msTransition';
      }
      if (bodyStyle.transform !== undefined && this.animType !== false) {
        this.animType = 'transform';
        this.transformType = 'transform';
        this.transitionType = 'transition';
      }
      /* eslint-enable */

      this.transformsEnabled = true;
    };

    this.refreshCarousel = () => {
      if (this.slides && this.slides.length && this.slides.length > this.options.slidesToShow) {
        this.isVisibleDots = true;
        this.isVisiblePrev = true;
        this.isVisibleNext = true;
        this.isClickablePrev = true;
        this.isClickableNext = true;
      }

      // Re-init UI
      this.initUI();
    };

    /**
     * refresh model
     */
    $scope.$watch('ctrl.slides', () => {
      this.refreshCarousel();
    });

    // Prior to v1.5, we need to call `$onInit()` manually.
    // (Bindings will always be pre-assigned in these versions.)
    if (angular.version.major === 1 && angular.version.minor < 5) {
      this.$onInit();
    }
  }]);
<|endoftext|>


<commit_before>function test(a) {
  for (let i = 0; i < 10; i++) {
    a+=1;
  }
  if (a == 1) {
    return 1;
  } else {
    return 0;
  }
}

export default test;<commit_msg>test travis ci<commit_after>function test(a) {
  for (let i = 0; i < 10; i++) {
    a+=1;
  }

  if (a == 1) {
    return 1;
  } else {
    return 0;
  }
}

export default test;<|endoftext|>


<commit_before>import path from "path";
import Canvas, { Font } from "canvas";

// Reference: https://github.com/badges/shields
const element = new Canvas(0, 0);
const ctx = element.getContext("2d");
try {
  const fontFile = path.join(__dirname, "..", "Verdana.ttf");
  const font = new Font("Verdana", fontFile);
  ctx.addFont(font);
} catch(err) {
  console.warn(`Failed to add font: ${err}`);
}
ctx.font = "11px Verdana, \"DejaVu Sans\"";

export default function measureTextWidth(text) {
  return ctx.measureText(text).width | 0;
}
<commit_msg>Add text width tester<commit_after>import path from "path";
import Canvas, { Font } from "canvas";

// Reference: https://github.com/badges/shields
const element = new Canvas(0, 0);
const ctx = element.getContext("2d");
try {
  const fontFile = path.join(__dirname, "..", "Verdana.ttf");
  const font = new Font("Verdana", fontFile);
  ctx.addFont(font);
} catch(err) {
  console.warn(`Failed to add font: ${err}`);
}
ctx.font = "11px Verdana, \"DejaVu Sans\"";

export default function measureTextWidth(text) {
  return ctx.measureText(text).width | 0;
}

if (require.main === module) {
  const TEST_STRINGS = [
    "FF",
    "Google Chrome",
    "Microsoft Internet Explorer",
    "Safari"
  ];
  TEST_STRINGS.forEach(str => {
    console.log(`${str} [${measureTextWidth(str)}]`);
  });
}
<|endoftext|>


<commit_before>import React from 'react';
import ReactDOM from 'react-dom';
import d3 from 'd3';
import d3tip from 'd3-tip';
import _ from 'lodash';
import Dimensions from 'react-dimensions';
import { logger } from '../../../../system';
import {  createScales,
          getPositionsDataFromSeries,
          updateNodes,
          drawCircles,
          drawLabels,
          getRadius,
          getPositionValue} from './chartUtil';

const _log:logger.Logger = logger.create('PositionsBubbleChart');

@Dimensions()
export default class PositionsBubbleChart extends React.Component{

  static propTypes = {
    data: React.PropTypes.array,
    containerWidth: React.PropTypes.number,
    containerHeight: React.PropTypes.number
  };

  static defaultProps = {
    data: []
  };

  constructor(props){
    super(props);
    this.state = {
      nodes: [],
      prevPositionsData: {}
    };
  }

  componentDidMount() {
    this._redrawChart();
  };

  componentWillReceiveProps(nextProps){
    this._updateNodesFromPropsData(nextProps);

    if (this._shouldRedrawChart(nextProps)){
      this.setState({updateRequired: true});
      this._redrawChart(nextProps);
    }
  }

  componentDidUpdate(){
    this._update(this.state.nodes);
  }

  _shouldRedrawChart(nextProps = this.props){
    let positionsData = getPositionsDataFromSeries(nextProps.data);
    let existingPositionsData = this.state.prevPositionsData;
    let nodesChanged = positionsData.length !== existingPositionsData.length;
    return nodesChanged;
  }

  _updateNodesFromPropsData(nextProps = this.props){
    if (this.state.nodes.length === 0 && nextProps.data.length > 0){
      this._updateNodes(nextProps.data);
    }
    let positionsData = getPositionsDataFromSeries(nextProps.data);
    let existingPositionsData = this.state.prevPositionsData;

    //positions data has changed on the existing nodes
    let modifiedData = _.reduce(positionsData, (result, value, key) => {
      return _.isEqual(value, existingPositionsData[key]) ?
        result : result.concat(key);
    }, []);

    let stalePositions = _.filter(existingPositionsData, (existingPos) => _.findIndex(positionsData, (pos) => pos.symbol === existingPos.symbol) === -1);

    if (modifiedData.length > 0 || stalePositions.length > 0){
      this.setState({prevPositionsData: positionsData, updateRequired: true});
      this.scales = createScales(nextProps);

      if (this.state.nodes.length === 0){
        this._updateNodes(this.props.data);
      }else{
        this._updateNodes(nextProps.data);
      }
    }

    return modifiedData.length > 0 || stalePositions.length > 0;
  }

  _updateNodes(data){
    let nodes = this.state.nodes;
    let colours = ['#6db910', '#d90a0a'];
    let positionsData = getPositionsDataFromSeries(data);

    nodes = _.map(positionsData, (dataObj, index) => {
      let color =  dataObj.baseTradedAmount > 0 ? colours[0] : colours[1];

      //update an existing node:
      let existingNode = _.find(nodes, (node) => node.id === dataObj.symbol);
      if (existingNode){
        existingNode.r = getRadius(dataObj, this.scales);
        existingNode.cx = this.scales.x(index);
        existingNode.color = color;
        return existingNode;
      }else{
        let newNode = {
          id: dataObj.symbol,
          r: getRadius(dataObj, this.scales),
          cx: this.scales.x(index),
          color: color
        };
        nodes.push(newNode);
        return newNode;
      }
    });

    let updatedNodes = _.filter(this.state.nodes, (node) => _.findIndex(positionsData, (pos) => pos.symbol === node.id) !== -1);
    this.setState({nodes: updatedNodes, prevPositionsData: positionsData, updateRequired: true});
  }

  _redrawChart(nextProps = this.props){
    let dom = ReactDOM.findDOMNode(this);
    let svg = d3.select(dom).select('svg');
    svg.remove(); //clear all child nodes
    if (this.tooltipGroup) this.tooltipGroup.hide();
    this.setState({updateRequired: true});
    this._createChartForce(nextProps);
  }

  _createChartForce(nextProps = this.props){
    let dom = ReactDOM.findDOMNode(this);
    this.scales = createScales(nextProps);

    const tick = (e) => {
      let nodeGroup = svg.selectAll('g.node')
        .on('mouseover', this.tooltipGroup.show )
        .on('mousemove', this.tooltipGroup.show )
        .on('mouseout',  this.tooltipGroup.hide );

      updateNodes(nodeGroup, this.state.nodes, this.scales);
    };

    let svg = d3.select(dom).append('svg')
      .attr({
        width: this.props.containerWidth,
        height: this.props.containerHeight
      });

    this.tooltipGroup = d3tip().html((d)=>{
      return `${d.id} ${getPositionValue(d.id, this.state.prevPositionsData)}` ;
    })
      .attr('class', 'analytics__positions-tooltip').direction('s').offset([-5, 0]);

    svg.call(this.tooltipGroup);

    this.force = d3.layout.force()
        .nodes(this.state.nodes)
        .links([])
        .size([this.props.containerWidth, this.props.containerHeight])
        .charge((d) => {
          return -1 ;
        })
        .gravity(0.1)
        .on('tick', tick);

    this._update(this.state.nodes);
  }

  _update(nodes){
    if (!nodes || !this.force) return;
    if (!this.state.updateRequired) return;
    this.setState({updateRequired: false});

    let dom = ReactDOM.findDOMNode(this);
    let svg = d3.select(dom).select('svg');

    let nodeGroup = svg.selectAll('g.node')
      .data(nodes, (d, i) => {
        return d.id;
      });

    nodeGroup.enter().append('g')
      .attr({
        'class': 'node'
      })
      .call(this.force.drag);

    if (nodeGroup.selectAll('circle').empty()) {
      let circleNodeGroup = nodeGroup.append('circle');
      let labelGroup = nodeGroup.append('text');
      drawCircles(circleNodeGroup, 0);
      drawLabels(labelGroup);
      this.force.nodes(nodes).start();

    } else {
      let circle = nodeGroup.selectAll('circle');
      drawCircles(circle);

      setTimeout(() => {
        updateNodes(nodeGroup, this.state.nodes, this.scales);
        this.force.start();
      }, 200);

    }
    nodeGroup.exit().remove();
  };

  render(){
    return (

    );
  }
}

<commit_msg>code review changes<commit_after>import React from 'react';
import ReactDOM from 'react-dom';
import d3 from 'd3';
import d3tip from 'd3-tip';
import _ from 'lodash';
import Dimensions from 'react-dimensions';
import { logger } from '../../../../system';
import {  createScales,
          getPositionsDataFromSeries,
          updateNodes,
          drawCircles,
          drawLabels,
          getRadius,
          getPositionValue} from './chartUtil';

const _log:logger.Logger = logger.create('PositionsBubbleChart');

@Dimensions()
export default class PositionsBubbleChart extends React.Component{

  static propTypes = {
    data: React.PropTypes.array,
    containerWidth: React.PropTypes.number,
    containerHeight: React.PropTypes.number
  };

  static defaultProps = {
    data: []
  };

  constructor(props){
    super(props);
    this.state = {
      nodes: [],
      prevPositionsData: {}
    };
  }

  componentDidMount() {
    this._redrawChart();
  };

  componentWillReceiveProps(nextProps){
    this._updateNodesFromPropsData(nextProps);

    if (this._shouldRedrawChart(nextProps)){
      this.setState({updateRequired: true});
      this._redrawChart(nextProps);
    }
  }

  componentDidUpdate(){
    this._update(this.state.nodes);
  }

  _shouldRedrawChart(nextProps = this.props){
    let positionsData = getPositionsDataFromSeries(nextProps.data);
    let existingPositionsData = this.state.prevPositionsData;
    let nodesChanged = positionsData.length !== existingPositionsData.length;
    return nodesChanged;
  }

  _updateNodesFromPropsData(nextProps = this.props){
    if (this.state.nodes.length === 0 && nextProps.data.length > 0){
      this._updateNodes(nextProps.data);
    }
    let positionsData = getPositionsDataFromSeries(nextProps.data);
    let existingPositionsData = this.state.prevPositionsData;

    //positions data has changed on the existing nodes
    let modifiedData = _.reduce(positionsData, (result, value, key) => {
      return _.isEqual(value, existingPositionsData[key]) ?
        result : result.concat(key);
    }, []);

    let stalePositions = _.filter(existingPositionsData, (existingPos) => _.findIndex(positionsData, (pos) => pos.symbol === existingPos.symbol) === -1);

    if (modifiedData.length > 0 || stalePositions.length > 0){
      this.setState({prevPositionsData: positionsData, updateRequired: true});
      this.scales = createScales(nextProps);

      if (this.state.nodes.length === 0){
        this._updateNodes(this.props.data);
      }else{
        this._updateNodes(nextProps.data);
      }
    }

    return modifiedData.length > 0 || stalePositions.length > 0;
  }

  _updateNodes(data){
    let nodes = this.state.nodes;
    let colours = ['#6db910', '#d90a0a'];
    let positionsData = getPositionsDataFromSeries(data);

    nodes = _.map(positionsData, (dataObj, index) => {
      let color =  dataObj.baseTradedAmount > 0 ? colours[0] : colours[1];

      //update an existing node:
      let existingNode = _.find(nodes, (node) => node.id === dataObj.symbol);
      if (existingNode){
        existingNode.r = getRadius(dataObj, this.scales);
        existingNode.cx = this.scales.x(index);
        existingNode.color = color;
        return existingNode;
      }else{
        let newNode = {
          id: dataObj.symbol,
          r: getRadius(dataObj, this.scales),
          cx: this.scales.x(index),
          color: color
        };
        return newNode;
      }
    });

    let updatedNodes = _.filter(nodes, (node) => _.findIndex(positionsData, (pos) => pos.symbol === node.id) !== -1);
    this.setState({nodes: updatedNodes, prevPositionsData: positionsData, updateRequired: true});
  }

  _redrawChart(nextProps = this.props){
    let dom = ReactDOM.findDOMNode(this);
    let svg = d3.select(dom).select('svg');
    svg.remove(); //clear all child nodes
    if (this.tooltipGroup) this.tooltipGroup.hide();
    this.setState({updateRequired: true});
    this._createChartForce(nextProps);
  }

  _createChartForce(nextProps = this.props){
    let dom = ReactDOM.findDOMNode(this);
    this.scales = createScales(nextProps);

    const tick = (e) => {
      let nodeGroup = svg.selectAll('g.node')
        .on('mouseover', this.tooltipGroup.show )
        .on('mousemove', this.tooltipGroup.show )
        .on('mouseout',  this.tooltipGroup.hide );

      updateNodes(nodeGroup, this.state.nodes, this.scales);
    };

    let svg = d3.select(dom).append('svg')
      .attr({
        width: this.props.containerWidth,
        height: this.props.containerHeight
      });

    this.tooltipGroup = d3tip().html((d)=>{
      return `${d.id} ${getPositionValue(d.id, this.state.prevPositionsData)}` ;
    })
      .attr('class', 'analytics__positions-tooltip').direction('s').offset([-5, 0]);

    svg.call(this.tooltipGroup);

    this.force = d3.layout.force()
        .nodes(this.state.nodes)
        .links([])
        .size([this.props.containerWidth, this.props.containerHeight])
        .charge((d) => {
          return -1 ;
        })
        .gravity(0.1)
        .on('tick', tick);

    this._update(this.state.nodes);
  }

  _update(nodes){
    if (!nodes || !this.force) return;
    if (!this.state.updateRequired) return;
    this.setState({updateRequired: false});

    let dom = ReactDOM.findDOMNode(this);
    let svg = d3.select(dom).select('svg');

    let nodeGroup = svg.selectAll('g.node')
      .data(nodes, (d, i) => {
        return d.id;
      });

    nodeGroup.enter().append('g')
      .attr({
        'class': 'node'
      })
      .call(this.force.drag);

    if (nodeGroup.selectAll('circle').empty()) {
      let circleNodeGroup = nodeGroup.append('circle');
      let labelGroup = nodeGroup.append('text');
      drawCircles(circleNodeGroup, 0);
      drawLabels(labelGroup);
      this.force.nodes(nodes).start();

    } else {
      let circle = nodeGroup.selectAll('circle');
      drawCircles(circle);

      setTimeout(() => {
        updateNodes(nodeGroup, this.state.nodes, this.scales);
        this.force.start();
      }, 200);

    }
    nodeGroup.exit().remove();
  };

  render(){
    return (

    );
  }
}

<|endoftext|>