<commit_before>import clone from 'lodash/clone'
import defaults from 'lodash/defaults'

export default {
  schema: {
    autoStart: {
      type: 'boolean',
      default: true
    },
    loop: {
      type: 'boolean',
      default: true
    },
    wait: {
      type: 'number',
      default: 2000
    },
    move: {
      type: 'number',
      default: 3000
    }
  },

  init: function () {
    this._currentWayPoint = -1
    this.el.setAttribute('animation__move', { startEvents: 'doNotFire', pauseEvents: 'pauseTour', resumeEvents:'resumeTour', property: 'position', easing: 'easeInOutSine', dur: 100 })
    this.el.setAttribute('animation__turn', { startEvents: 'doNotFire', pauseEvents: 'pauseTour', resumeEvents:'resumeTour', property: 'rotation', easing: 'easeInOutSine', dur: 100 })
    this._nextWaypointHandler = this._nextWaypoint.bind(this)
  },

  update: function () {
    this._waypoints = Array.from(this.el.querySelectorAll('[tour-waypoint]'))

    if(this.data.autoStart) {
      this.playTour()
    }
  },

  playTour: function () {
    if (!this._waypoints || !this._waypoints.length) {
      console.warn('camera tour has no waypoints')
      return
    }
    if (this._isPlaying) {
      if(this._isChangingAnimation) {
        clearTimeout(this._nextAnimationTimeout)
        this.goTo(this._waypoints[this._currentWayPoint].getAttribute('tour-waypoint'), this._isPlaying)
      } else {
        this.el.dispatchEvent(new CustomEvent('resumeTour'))
      }
      this._isPaused = false
    } else {
      this._isPlaying = true
      this._isPaused = false
      this.el.addEventListener('animation__move-complete', this._nextWaypointHandler)
      var next = this._waypoints[++this._currentWayPoint]
      if (next) this.goTo(next.getAttribute('tour-waypoint'), true)
      else if (this.data.loop) {
        this._currentWayPoint = 0
        this.goTo(this._waypoints[0].getAttribute('tour-waypoint'), true)
      }
    }
  },

  pauseTour: function () {
    this._isPaused = true
    this.el.dispatchEvent(new CustomEvent('pauseTour'))
  },

  stopTour: function () {
    this.pauseTour()
    this.el.removeEventListener('animation__move-complete', this._nextWaypointHandler)
    this._isPlaying = false
    this._isPaused = false
  },

  goTo: function (label, keepPlaying) {
    this._isPlaying = !!keepPlaying
    var target = this._waypoints.find(function (item) { return item.getAttribute('tour-waypoint') === label })
    if (!target) {
      console.error('The given waypoint '+ label + ' does not exist. Available waypoints:', this._waypoints.map(function (elem) { elem.getAttribute('tour-waypoint') }))
      return
    }

    this.animate(target)
  },

  // set camera position and rotation by providing changes for certain axes
  // to reset camera to walking mode do:
  // setViewPoint({position: {y:1.6}, rotation: {x:0})
  updateViewPoint: function (args) {
    args = args || {}
    if (typeof args !== 'object') {
      console.error('not supported camera view point: ' + args)
      return
    }
    var posChange = args.position || {}
    var rotChange = args.rotation || {}

    this._isPlaying = false
    // apply changes to current camera position
    var pos = defaults({}, posChange, clone(this.el.getAttribute('position')))
    var rot = defaults({}, rotChange, clone(this.el.getAttribute('rotation')))

    var target = {
      position: AFRAME.utils.coordinates.stringify(pos),
      rotation: AFRAME.utils.coordinates.stringify(rot)
    }
    this.animate(target)
  },

  animate: function (bookmark) {
    var isDomElement = isElement(bookmark)
    var entity = this.el
    var newPosition = isDomElement ? bookmark.getAttribute('position') : bookmark.position
    var newRotation = isDomElement ? bookmark.getAttribute('rotation') : bookmark.rotation
    var currentPosition = entity.getAttribute('position')
    var currentRotation = entity.getAttribute('rotation')
    var startPosition = AFRAME.utils.coordinates.stringify(currentPosition)
    var startRotation = AFRAME.utils.coordinates.stringify(currentRotation)

    // compute distance to adapt speed
    var d = dist(currentPosition, AFRAME.utils.coordinates.parse(newPosition))
    // compute angle difference to adapt speed
    var angle = Math.abs(currentRotation.y - AFRAME.utils.coordinates.parse(newRotation).y)
    // compute animation time
    // add 1 to the this.data.move parameter to allow users to specify 0 without the animation cancelling out
    var t = Math.round((this.data.move === undefined ? 3000 : this.data.move + 1) / 6 * (d + angle / 30))
    if (t > Math.max(10000, this.data.move)) t = Math.max(10000, this.data.move)

    // prevent zero length animation
    if (!t) return this._nextWaypoint()

    entity.components.animation__move.pauseAnimation()
    entity.components.animation__turn.pauseAnimation()
    entity.components.animation__move.data.dur = t
    entity.components.animation__move.data.from = startPosition
    entity.components.animation__move.data.to = newPosition
    entity.components.animation__move.update()
    entity.components.animation__turn.data.dur = t
    entity.components.animation__turn.data.from = startRotation
    entity.components.animation__turn.data.to = newRotation
    entity.components.animation__turn.update()
    entity.components.animation__move.resumeAnimation()
    entity.components.animation__turn.resumeAnimation()
    this._isChangingAnimation = false
  },

  _nextWaypoint: function () {
    if (!this._isPlaying) return this.stopTour()
    if (this._currentWayPoint === this._waypoints.length - 1) {
      if (!this.data.loop) return
      this._currentWayPoint = -1
    }
    this._isChangingAnimation = true
    var next = this._waypoints[++this._currentWayPoint]
    this._nextAnimationTimeout = setTimeout(function () { this.goTo(next.getAttribute('tour-waypoint'), this._isPlaying) }.bind(this), this.data.wait === undefined ? 0 : this.data.wait)
  }
}

function dist(p, q) {
  var a = parseFloat(q.x) - parseFloat(p.x)
  var b = parseFloat(q.y) - parseFloat(p.y)
  var c = parseFloat(q.z) - parseFloat(p.z)
  return Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2) + Math.pow(c, 2))
}

// Returns true if it is a DOM element
// https://stackoverflow.com/a/384380/2835973
function isElement(o){
  var DOM_ELEMENT = 1
  return (
    typeof HTMLElement === "object" ? o instanceof HTMLElement : //DOM2
      o && typeof o === "object" && o !== null && o.nodeType === DOM_ELEMENT && typeof o.nodeName==="string"
  );
}<commit_msg>Fixed spinning animations<commit_after>import clone from 'lodash/clone'
import defaults from 'lodash/defaults'

export default {
  schema: {
    autoStart: {
      type: 'boolean',
      default: true
    },
    loop: {
      type: 'boolean',
      default: true
    },
    wait: {
      type: 'number',
      default: 2000
    },
    move: {
      type: 'number',
      default: 3000
    }
  },

  init: function () {
    this._currentWayPoint = -1
    this.el.setAttribute('animation__move', { startEvents: 'doNotFire', pauseEvents: 'pauseTour', resumeEvents:'resumeTour', property: 'position', easing: 'easeInOutSine', dur: 100 })
    this.el.setAttribute('animation__turn', { startEvents: 'doNotFire', pauseEvents: 'pauseTour', resumeEvents:'resumeTour', property: 'rotation', easing: 'easeInOutSine', dur: 100 })
    this._nextWaypointHandler = this._nextWaypoint.bind(this)
  },

  update: function () {
    this._waypoints = Array.from(this.el.querySelectorAll('[tour-waypoint]'))

    if(this.data.autoStart) {
      this.playTour()
    }
  },

  playTour: function () {
    if (!this._waypoints || !this._waypoints.length) {
      console.warn('camera tour has no waypoints')
      return
    }
    if (this._isPlaying) {
      if(this._isChangingAnimation) {
        clearTimeout(this._nextAnimationTimeout)
        this.goTo(this._waypoints[this._currentWayPoint].getAttribute('tour-waypoint'), this._isPlaying)
      } else {
        this.el.dispatchEvent(new CustomEvent('resumeTour'))
      }
      this._isPaused = false
    } else {
      this._isPlaying = true
      this._isPaused = false
      this.el.addEventListener('animation__move-complete', this._nextWaypointHandler)
      var next = this._waypoints[++this._currentWayPoint]
      if (next) this.goTo(next.getAttribute('tour-waypoint'), true)
      else if (this.data.loop) {
        this._currentWayPoint = 0
        this.goTo(this._waypoints[0].getAttribute('tour-waypoint'), true)
      }
    }
  },

  pauseTour: function () {
    this._isPaused = true
    this.el.dispatchEvent(new CustomEvent('pauseTour'))
  },

  stopTour: function () {
    this.pauseTour()
    this.el.removeEventListener('animation__move-complete', this._nextWaypointHandler)
    this._isPlaying = false
    this._isPaused = false
  },

  goTo: function (label, keepPlaying) {
    this._isPlaying = !!keepPlaying
    var target = this._waypoints.find(function (item) { return item.getAttribute('tour-waypoint') === label })
    if (!target) {
      console.error('The given waypoint '+ label + ' does not exist. Available waypoints:', this._waypoints.map(function (elem) { elem.getAttribute('tour-waypoint') }))
      return
    }

    this.animate(target)
  },

  // set camera position and rotation by providing changes for certain axes
  // to reset camera to walking mode do:
  // setViewPoint({position: {y:1.6}, rotation: {x:0})
  updateViewPoint: function (args) {
    args = args || {}
    if (typeof args !== 'object') {
      console.error('not supported camera view point: ' + args)
      return
    }
    var posChange = args.position || {}
    var rotChange = args.rotation || {}

    this._isPlaying = false
    // apply changes to current camera position
    var pos = defaults({}, posChange, clone(this.el.getAttribute('position')))
    var rot = defaults({}, rotChange, clone(this.el.getAttribute('rotation')))

    var target = {
      position: AFRAME.utils.coordinates.stringify(pos),
      rotation: AFRAME.utils.coordinates.stringify(rot)
    }
    this.animate(target)
  },

  animate: function (bookmark) {
    var isDomElement = isElement(bookmark)
    var entity = this.el
    var newPosition = isDomElement ? bookmark.getAttribute('position') : bookmark.position
    var newRotation = isDomElement ? bookmark.getAttribute('rotation') : bookmark.rotation
    var startPosition = entity.getAttribute('position')
    var startRotation = entity.getAttribute('rotation')

    // compute shortest rotation
    newRotation = normalizeRotation(startRotation, newRotation)

    // compute distance to adapt speed
    var d = dist(startPosition, newPosition)
    // compute angle difference to adapt speed
    var angle = Math.abs(startRotation.y - newRotation.y)
    // compute animation time
    // add 1 to the this.data.move parameter to allow users to specify 0 without the animation cancelling out
    var t = Math.round((this.data.move === undefined ? 3000 : this.data.move + 1) / 6 * (d + angle / 30))
    if (t > Math.max(10000, this.data.move)) t = Math.max(10000, this.data.move)

    // prevent zero length animation
    if (!t) return this._nextWaypoint()

    entity.components.animation__move.pauseAnimation()
    entity.components.animation__turn.pauseAnimation()
    entity.components.animation__move.data.dur = t
    entity.components.animation__move.data.from = startPosition
    entity.components.animation__move.data.to = newPosition
    entity.components.animation__move.update()
    entity.components.animation__turn.data.dur = t
    entity.components.animation__turn.data.from = startRotation
    entity.components.animation__turn.data.to = newRotation
    entity.components.animation__turn.update()
    entity.components.animation__move.resumeAnimation()
    entity.components.animation__turn.resumeAnimation()
    this._isChangingAnimation = false
  },

  _nextWaypoint: function () {
    if (!this._isPlaying) return this.stopTour()
    if (this._currentWayPoint === this._waypoints.length - 1) {
      if (!this.data.loop) return
      this._currentWayPoint = -1
    }
    this._isChangingAnimation = true
    var next = this._waypoints[++this._currentWayPoint]
    this._nextAnimationTimeout = setTimeout(function () { this.goTo(next.getAttribute('tour-waypoint'), this._isPlaying) }.bind(this), this.data.wait === undefined ? 0 : this.data.wait)
  }
}

// we want to prevent excessive spinning in rotations
function normalizeRotation(start, end) {
  // prevent angles larger than 360
  var normRot = {
    x: end.x % 360,
    y: end.y % 360,
    z: end.z % 360,
  }
  // if delta is bigger than 180 degrees we spin to the other direction
  Object.keys(normRot).forEach(function(axis) {
    if (normRot[axis] - start[axis] > 180) normRot[axis] -= 360
  })
  return normRot
}

function dist(p, q) {
  var a = parseFloat(q.x) - parseFloat(p.x)
  var b = parseFloat(q.y) - parseFloat(p.y)
  var c = parseFloat(q.z) - parseFloat(p.z)
  return Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2) + Math.pow(c, 2))
}

// Returns true if it is a DOM element
// https://stackoverflow.com/a/384380/2835973
function isElement(o){
  var DOM_ELEMENT = 1
  return (
    typeof HTMLElement === "object" ? o instanceof HTMLElement : //DOM2
      o && typeof o === "object" && o !== null && o.nodeType === DOM_ELEMENT && typeof o.nodeName==="string"
  );
}<|endoftext|>


<commit_before>/*
 * Tangram
 * Copyright 2012 Baidu Inc. All rights reserved.
 *
 * version: 1.0
 * date: 2012/12/20
 * author: robin
 */

///import magic.setup;
///import magic.control.Tooltip;
///import magic.Background;
///import magic.Background.$styleBox;
///import baidu.type;
///import baidu.global.getZIndex;
///import baidu.dom.children;
///import baidu.dom.hide;
///import baidu.dom;

/**
 * @description 在页面已有 html 结构的基础上创建提示框组件
 * @name magic.setup.tooltip
 * @function
 * @grammar  magic.setup.tooltip(el,options)
 * @param {String|HTMLElement} el 容器，ID或者HTML元素
 * @param {Object} options 控制选项
 * @grammar {Boolean} options.autoHide 是否自动隐藏, 默认值为true。
 * @grammar {Boolean} options.hasCloseBtn 是否可以通过右上角X来关闭提示。默认值为false。
 * @grammar {Boolean} options.hasArrow 是否显示箭头。默认值为true。
 * @grammar {Boolean} options.autoBuild 自动检测需要提示的节点，通过attr值来判断。默认值为false。
 * @grammar {Number} options.offsetX 定位时的偏移量，X方向。
 * @grammar {Number} options.offsetY 定位时的偏移量，Y方向。
 * @grammar {Array} options.target 需要提示的节点。
 * @grammar {Function|String} options.content 自定义内容定制。若为Function,参数为Tangram对象(目标节点)。
 * @grammar {String} options.showEvent 提示显示的动作，默认值为mouseover,focus。
 * @grammar {String} options.hideEvent 提示隐藏的动作，默认值为mouseout,blur。
 * @grammar {String} options.position 设置tooltip的位置，值为top|bottom|left|right，默认值为bottom。
 * @grammar {Number|Percent} options.arrowPosition 设置arrow的位置，如果是上、下方位的话，都相对于左边的距离。如果是左、右方位的话，都相对于上面的距离。如果该值不存在，则自动计算相对于目标节点中间的位置。
 * @example
 * var tooltip = new magic.setup.tooltip(el, {});
 * @return {magic.control.Tooltip} magic.control.Tooltip 实例
 */
magic.setup.tooltip = function(el, options){
    if(baidu.type(el) === "string"){
        el = '#' + el;
    }
    el = baidu(el)[0];
    var opt = options || {};
    opt.target || (opt.target = document.body);

    /**
     *@description tooltip 组件 setup 模式的实例对象
     *@instace
     *@name magic.setup.tooltip!
     *@superClass magic.control.Tooltip
     *@return {instace} magic.control.Tooltip 实例对象
     */
    var instance = magic.setup(el, magic.control.Tooltip, opt),
        container = instance.getElement();

    container.style.zIndex = baidu.global.getZIndex("popup");

    instance.background = new magic.Background({coverable:true, styleBox:true});
    instance.background.render(container);
    instance.on("dispose", function(){
        instance.background.$dispose();
    });

    instance.$mappingDom("", baidu(".magic-tooltip", container)[0]);
    instance.$mappingDom("close", baidu(".magic-tooltip-close", container)[0]);
    instance.$mappingDom("closeBtn", baidu("a", instance.getElement("close"))[0]);
    instance.$mappingDom("content", baidu(".magic-tooltip-content", container)[0]);
    instance.$mappingDom("arrow", baidu(".magic-tooltip-arrow", instance.getElement("body"))[0]);
    instance._isShow = true;
    instance.hide();

    /**
     * @description 提示框渲染完时触发
     * @name magic.Tooltip#onload
     * @event
     * @grammar magic.Tooltip#onload()
     * @example
     * var instance = new magic.Tooltip();
     * instance.on("load", function(){
     *     //do something...
     * });
     * @example
     * var instance = new magic.Tooltip();
     * instance.onload = function(){
     *     //do something...
     * };
     */
    instance.fire("load");

    return instance;
};<commit_msg>modify tooltip comment<commit_after>/*
 * Tangram
 * Copyright 2012 Baidu Inc. All rights reserved.
 *
 * version: 1.0
 * date: 2012/12/20
 * author: robin
 */

///import magic.setup;
///import magic.control.Tooltip;
///import magic.Background;
///import magic.Background.$styleBox;
///import baidu.type;
///import baidu.global.getZIndex;
///import baidu.dom.children;
///import baidu.dom.hide;
///import baidu.dom;

/**
 * @description 在页面已有 html 结构的基础上创建提示框组件
 * @name magic.setup.tooltip
 * @function
 * @grammar  magic.setup.tooltip(el,options)
 * @param {String|HTMLElement} el 容器，ID或者HTML元素
 * @param {Object} options 控制选项
 * @param {Boolean} options.autoHide 是否自动隐藏, 默认值为true。
 * @param {Boolean} options.hasCloseBtn 是否可以通过右上角X来关闭提示。默认值为false。
 * @param {Boolean} options.hasArrow 是否显示箭头。默认值为true。
 * @param {Boolean} options.autoBuild 自动检测需要提示的节点，通过attr值来判断。默认值为false。
 * @param {Number} options.offsetX 定位时的偏移量，X方向。
 * @param {Number} options.offsetY 定位时的偏移量，Y方向。
 * @param {Array} options.target 需要提示的节点。
 * @param {Function|String} options.content 自定义内容定制。若为Function,参数为Tangram对象(目标节点)。
 * @param {String} options.showEvent 提示显示的动作，默认值为mouseover,focus。
 * @param {String} options.hideEvent 提示隐藏的动作，默认值为mouseout,blur。
 * @param {String} options.position 设置tooltip的位置，值为top|bottom|left|right，默认值为bottom。
 * @param {Number|Percent} options.arrowPosition 设置arrow的位置，如果是上、下方位的话，都相对于左边的距离。如果是左、右方位的话，都相对于上面的距离。如果该值不存在，则自动计算相对于目标节点中间的位置。
 * @example
 * var tooltip = new magic.setup.tooltip(el, {});
 * @return {magic.control.Tooltip} magic.control.Tooltip 实例
 */
magic.setup.tooltip = function(el, options){
    if(baidu.type(el) === "string"){
        el = '#' + el;
    }
    el = baidu(el)[0];
    var opt = options || {};
    opt.target || (opt.target = document.body);

    /**
     *@description tooltip 组件 setup 模式的实例对象
     *@instace
     *@name magic.setup.tooltip!
     *@superClass magic.control.Tooltip
     *@return {instace} magic.control.Tooltip 实例对象
     */
    var instance = magic.setup(el, magic.control.Tooltip, opt),
        container = instance.getElement();

    container.style.zIndex = baidu.global.getZIndex("popup");

    instance.background = new magic.Background({coverable:true, styleBox:true});
    instance.background.render(container);
    instance.on("dispose", function(){
        instance.background.$dispose();
    });

    instance.$mappingDom("", baidu(".magic-tooltip", container)[0]);
    instance.$mappingDom("close", baidu(".magic-tooltip-close", container)[0]);
    instance.$mappingDom("closeBtn", baidu("a", instance.getElement("close"))[0]);
    instance.$mappingDom("content", baidu(".magic-tooltip-content", container)[0]);
    instance.$mappingDom("arrow", baidu(".magic-tooltip-arrow", instance.getElement("body"))[0]);
    instance._isShow = true;
    instance.hide();

    /**
     * @description 提示框渲染完时触发
     * @name magic.Tooltip#onload
     * @event
     * @grammar magic.Tooltip#onload()
     * @example
     * var instance = new magic.Tooltip();
     * instance.on("load", function(){
     *     //do something...
     * });
     * @example
     * var instance = new magic.Tooltip();
     * instance.onload = function(){
     *     //do something...
     * };
     */
    instance.fire("load");

    return instance;
};<|endoftext|>


<commit_before>/*************************************************************************
## require - Node.js-style module loading in ScriptCraft

Node.js is a server-side javascript environment with an excellent
module loading system based on CommonJS. Modules in Node.js are really
simple. Each module is in its own javascript file and all variables
and functions within the file are private to that file/module only.
There is a very concise explanation of CommonJS modules at...

[http://wiki.commonjs.org/wiki/Modules/1.1.1.][cjsmodules]

Node.js also has good documentation on [Modules][njsmod].

If you want to export a variable or function you use the module.export
property.

For example imagine you have 3 files program.js, inc.js  and math.js ...

### math.js

```javascript
exports.add = function(a,b){
    return a + b;
}
```

### inc.js

```javascript
var math = require('./math');
exports.increment = function(n){
    return math.add(n, 1);
}
```

### program.js

```javascript
var inc = require('./inc').increment;
var a = 7;
a = inc(a);
print(a);
```

You can see from the above sample code that programs can use modules
and modules themeselves can use other modules. Modules have full
control over what functions and properties they want to provide to
others.

### Important

Although ScriptCraft now supports Node.js style modules, it does not
support node modules. Node.js and Rhino are two very different
Javascript environments. ScriptCraft uses Rhino Javascript, not
Node.js. Standard Node.js modules such as `'fs'` are not available in ScriptCraft.

Modules can be loaded using relative or absolute paths. Per the CommonJS
module specification, the '.js' suffix is optional.

[cjsmodules]: http://wiki.commonjs.org/wiki/Modules/1.1.1.

***/
(function ( rootDir, modulePaths, hooks, evaluate ) {

  var File = java.io.File,
    FileReader = java.io.FileReader,
    BufferedReader = java.io.BufferedReader;

  function fileExists( file ) {
    if ( file.isDirectory() ) {
      return readModuleFromDirectory( file );
    } else {
      return file;
    }
  }

  function _canonize(file){
    return "" + file.canonicalPath.replaceAll("\\\\","/");
  }

  function readModuleFromDirectory( dir ) {

    // look for a package.json file
    var pkgJsonFile = new File( dir, './package.json' );
    if ( pkgJsonFile.exists() ) {
      var pkg = scload( pkgJsonFile );
      var mainFile = new File( dir, pkg.main );
      if ( mainFile.exists() ) {
        return mainFile;
      } else {
        return null;
      }
    } else {
      // look for an index.js file
      var indexJsFile = new File( dir, './index.js' );
      if ( indexJsFile.exists() ) {
        return indexJsFile;
      } else {
        return null;
      }
    }
  }

/**********************************************************************
### module name resolution

When resolving module names to file paths, ScriptCraft uses the following rules...

 1. if the module does not begin with './' or '/' then ...

    1.1 Look in the 'scriptcraft/lib' directory. If it's not there then...
    1.2 Look in the 'scriptcraft/modules' directory. If it's not there then
        Throw an Error.

 2. If the module begins with './' or '/' then ...

    2.1 if the module begins with './' then it's treated as a file path. File paths are
        always relative to the module from which the require() call is being made.

    2.2 If the module begins with '/' then it's treated as an absolute path.

    If the module does not have a '.js' suffix, and a file with the same name and a .js sufix exists,
    then the file will be loaded.

 3. If the module name resolves to a directory then...

    3.1 look for a package.json file in the directory and load the `main` property e.g.

    // package.json located in './some-library/'
    {
      "main": './some-lib.js',
      "name": 'some-library'
    }

    3.2 if no package.json file exists then look for an index.js file in the directory

***/
  function resolveModuleToFile( moduleName, parentDir ) {
    var file = new File(moduleName),
      i = 0,
      pathWithJSExt,
      resolvedFile;
    if ( file.exists() ) {
      return fileExists(file);
    }
    if ( moduleName.match( /^[^\.\/]/ ) ) {
      // it's a module named like so ... 'events' , 'net/http'
      //
      for ( ; i < modulePaths.length; i++ ) {
        resolvedFile = new File(modulePaths[i] + moduleName);
        if ( resolvedFile.exists() ) {
          return fileExists(resolvedFile);
        } else {
          // try appending a .js to the end
          resolvedFile = new File(modulePaths[i] + moduleName + '.js');
          if ( resolvedFile.exists() ) {
            return resolvedFile;
          }
        }
      }
    } else {
      // it's of the form ./path
      file = new File(parentDir, moduleName);
      if ( file.exists() ) {
        return fileExists(file);
      } else {
        // try appending a .js to the end
        pathWithJSExt = file.canonicalPath + '.js';
        file = new File( parentDir, pathWithJSExt );
        if (file.exists()) {
          return file;
        } else {
          file = new File(pathWithJSExt);
          if ( file.exists() ) {
            return file;
          }
        }

      }
    }
    return null;
  }
  /*
   require() function implementation
   */
  function _require( parentFile, path, options ) {
    var file,
        canonizedFilename,
        moduleInfo,
        buffered,
        head = '(function(exports,module,require,__filename,__dirname){ ',
        code = '',
        line = null;

    if ( typeof options == 'undefined' ) {
      options = { cache: true };
    } else {
      if ( typeof options.cache == 'undefined' ) {
        options.cache = true;
      }
    }

    file = resolveModuleToFile(path, parentFile);
    if ( !file ) {
      var errMsg = '' + _format("require() failed to find matching file for module '%s' " +
                                "in working directory '%s' ", [path, parentFile.canonicalPath]);
      if (! ( (''+path).match( /^\./ ) ) ) {
        errMsg = errMsg + ' and not found in paths ' + JSON.stringify(modulePaths);
      }
      var find = _require(parentFile, 'find').exports;
      var allJS = [];
      for (var i = 0;i < modulePaths.length; i++){
	var js = find( modulePaths[i] );
	for (var j = 0;j < js.length; j++){
	  if (js[j].match(/\.js$/)){
	    allJS.push( js[j].replace(modulePaths[i],'') );
	  }
	}
      }
      var pathL = path.toLowerCase();
      var candidates = [];
      for (i = 0;i < allJS.length;i++){
	var filenameparts = allJS[i];
	var candidate = filenameparts.replace(/\.js/,'') ;
	var lastpart = candidate.toLowerCase();
	if (pathL.indexOf(lastpart) > -1 || lastpart.indexOf(pathL) > -1){
	  candidates.push(candidate);
	}
      }
      if (candidates.length > 0){
	errMsg += '\nBut found module/s named: ' + candidates.join(',') + ' - is this what you meant?';
      }
      throw new Error(errMsg);
    }
    canonizedFilename = _canonize(file);

    moduleInfo = _loadedModules[canonizedFilename];
    if ( moduleInfo ) {
      if ( options.cache ) {
        return moduleInfo;
      }
    }
    if ( hooks ) {
      hooks.loading( canonizedFilename );
    }
    buffered = new BufferedReader(new FileReader(file));
    while ( (line = buffered.readLine()) !== null ) {
      code += line + '\n';
    }
    buffered.close(); // close the stream so there's no file locks

    moduleInfo = {
      loaded: false,
      id: canonizedFilename,
      exports: {},
      require: _requireClosure(file.parentFile)
    };
    var tail = '})';
    code = head + code + tail;

    if ( options.cache ) {
      _loadedModules[canonizedFilename] = moduleInfo;
    }
    var compiledWrapper = null;
    try {
      compiledWrapper = evaluate(code);
    } catch (e) {
      /*
       wph 20140313 JRE8 (nashorn) gives misleading linenumber of evaluating code not evaluated code.
       This can be fixed by instead using __engine.eval
       */
      throw new Error( "Error evaluating module " + path
          + " line #" + e.lineNumber
	  + " : " + e.message, canonizedFilename, e.lineNumber );
    }
    var __dirname = '' + file.parentFile.canonicalPath;
    var parameters = [
      moduleInfo.exports, /* exports */
      moduleInfo,         /* module */
      moduleInfo.require, /* require */
      canonizedFilename,  /* __filename */
      __dirname           /* __dirname */
    ];
    try {
      compiledWrapper
        .apply(moduleInfo.exports,  /* this */
               parameters);
    } catch (e) {
      var snippet = '';
      if ((''+e.lineNumber).match(/[0-9]/)){
	var lines = code.split(/\n/);
	if (e.lineNumber > 1){
	  snippet = ' ' + lines[e.lineNumber-2] + '\n';
	}
	snippet += '> ' + lines[e.lineNumber-1] + '\n';
	if (e.lineNumber < lines.length){
	  snippet += ' ' + lines[e.lineNumber] + '\n';
	}
      }
      throw new Error( "Error executing module " + path
        + " line #" + e.lineNumber
        + " : " + e.message + (snippet?('\n' + snippet):''), canonizedFilename, e.lineNumber );
    }
    if ( hooks ) {
      hooks.loaded( canonizedFilename );
    }
    moduleInfo.loaded = true;
    return moduleInfo;
  }

  function _requireClosure( parent ) {
    return function requireBoundToParent( path, options ) {
      var module = _require( parent, path , options);
      return module.exports;
    };
  }
  var _loadedModules = {};
  var _format = java.lang.String.format;
  return _requireClosure( new java.io.File(rootDir) );
  // last line deliberately has no semicolon!
})
<commit_msg>Fixed: Allow loading json using require()<commit_after>/*************************************************************************
## require - Node.js-style module loading in ScriptCraft

Node.js is a server-side javascript environment with an excellent
module loading system based on CommonJS. Modules in Node.js are really
simple. Each module is in its own javascript file and all variables
and functions within the file are private to that file/module only.
There is a very concise explanation of CommonJS modules at...

[http://wiki.commonjs.org/wiki/Modules/1.1.1.][cjsmodules]

Node.js also has good documentation on [Modules][njsmod].

If you want to export a variable or function you use the module.export
property.

For example imagine you have 3 files program.js, inc.js  and math.js ...

### math.js

```javascript
exports.add = function(a,b){
    return a + b;
}
```

### inc.js

```javascript
var math = require('./math');
exports.increment = function(n){
    return math.add(n, 1);
}
```

### program.js

```javascript
var inc = require('./inc').increment;
var a = 7;
a = inc(a);
print(a);
```

You can see from the above sample code that programs can use modules
and modules themeselves can use other modules. Modules have full
control over what functions and properties they want to provide to
others.

### Important

Although ScriptCraft now supports Node.js style modules, it does not
support node modules. Node.js and Rhino are two very different
Javascript environments. ScriptCraft uses Rhino Javascript, not
Node.js. Standard Node.js modules such as `'fs'` are not available in ScriptCraft.

Modules can be loaded using relative or absolute paths. Per the CommonJS
module specification, the '.js' suffix is optional.

[cjsmodules]: http://wiki.commonjs.org/wiki/Modules/1.1.1.

***/
(function ( rootDir, modulePaths, hooks, evaluate ) {

  var File = java.io.File,
    FileReader = java.io.FileReader,
    BufferedReader = java.io.BufferedReader;

  function fileExists( file ) {
    if ( file.isDirectory() ) {
      return readModuleFromDirectory( file );
    } else {
      return file;
    }
  }

  function _canonize(file){
    return "" + file.canonicalPath.replaceAll("\\\\","/");
  }

  function readModuleFromDirectory( dir ) {

    // look for a package.json file
    var pkgJsonFile = new File( dir, './package.json' );
    if ( pkgJsonFile.exists() ) {
      var pkg = scload( pkgJsonFile );
      var mainFile = new File( dir, pkg.main );
      if ( mainFile.exists() ) {
        return mainFile;
      } else {
        return null;
      }
    } else {
      // look for an index.js file
      var indexJsFile = new File( dir, './index.js' );
      if ( indexJsFile.exists() ) {
        return indexJsFile;
      } else {
        return null;
      }
    }
  }

/**********************************************************************
### module name resolution

When resolving module names to file paths, ScriptCraft uses the following rules...

 1. if the module does not begin with './' or '/' then ...

    1.1 Look in the 'scriptcraft/lib' directory. If it's not there then...
    1.2 Look in the 'scriptcraft/modules' directory. If it's not there then
        Throw an Error.

 2. If the module begins with './' or '/' then ...

    2.1 if the module begins with './' then it's treated as a file path. File paths are
        always relative to the module from which the require() call is being made.

    2.2 If the module begins with '/' then it's treated as an absolute path.

    If the module does not have a '.js' suffix, and a file with the same name and a .js sufix exists,
    then the file will be loaded.

 3. If the module name resolves to a directory then...

    3.1 look for a package.json file in the directory and load the `main` property e.g.

    // package.json located in './some-library/'
    {
      "main": './some-lib.js',
      "name": 'some-library'
    }

    3.2 if no package.json file exists then look for an index.js file in the directory

***/
  function resolveModuleToFile( moduleName, parentDir ) {
    var file = new File(moduleName),
      i = 0,
      pathWithJSExt,
      resolvedFile;
    if ( file.exists() ) {
      return fileExists(file);
    }
    if ( moduleName.match( /^[^\.\/]/ ) ) {
      // it's a module named like so ... 'events' , 'net/http'
      //
      for ( ; i < modulePaths.length; i++ ) {
        resolvedFile = new File(modulePaths[i] + moduleName);
        if ( resolvedFile.exists() ) {
          return fileExists(resolvedFile);
        } else {
          // try appending a .js to the end
          resolvedFile = new File(modulePaths[i] + moduleName + '.js');
          if ( resolvedFile.exists() ) {
            return resolvedFile;
          }
        }
      }
    } else {
      if ((file = new File(parentDir, moduleName)).exists()) {
        return fileExists(file);
      } else if ((file = new File(parentDir, moduleName + ".js")).exists()) { // try .js extension
        return file;
      } else if ((file = new File(parentDir, moduleName + ".json")).exists()) { // try .json extension
        return file;
      }
    }
    return null;
  }
  /*
   require() function implementation
   */
  function _require( parentFile, path, options ) {
    var file,
        canonizedFilename,
        moduleInfo,
        buffered,
        head = '(function(exports,module,require,__filename,__dirname){ ',
        code = '',
        line = null;

    if ( typeof options == 'undefined' ) {
      options = { cache: true };
    } else {
      if ( typeof options.cache == 'undefined' ) {
        options.cache = true;
      }
    }

    file = resolveModuleToFile(path, parentFile);
    if ( !file ) {
      var errMsg = '' + _format("require() failed to find matching file for module '%s' " +
                                "in working directory '%s' ", [path, parentFile.canonicalPath]);
      if (! ( (''+path).match( /^\./ ) ) ) {
        errMsg = errMsg + ' and not found in paths ' + JSON.stringify(modulePaths);
      }
      var find = _require(parentFile, 'find').exports;
      var allJS = [];
      for (var i = 0;i < modulePaths.length; i++){
	var js = find( modulePaths[i] );
	for (var j = 0;j < js.length; j++){
	  if (js[j].match(/\.js$/)){
	    allJS.push( js[j].replace(modulePaths[i],'') );
	  }
	}
      }
      var pathL = path.toLowerCase();
      var candidates = [];
      for (i = 0;i < allJS.length;i++){
	var filenameparts = allJS[i];
	var candidate = filenameparts.replace(/\.js/,'') ;
	var lastpart = candidate.toLowerCase();
	if (pathL.indexOf(lastpart) > -1 || lastpart.indexOf(pathL) > -1){
	  candidates.push(candidate);
	}
      }
      if (candidates.length > 0){
	errMsg += '\nBut found module/s named: ' + candidates.join(',') + ' - is this what you meant?';
      }
      throw new Error(errMsg);
    }
    canonizedFilename = _canonize(file);

    moduleInfo = _loadedModules[canonizedFilename];
    if ( moduleInfo ) {
      if ( options.cache ) {
        return moduleInfo;
      }
    }
    if ( hooks ) {
      hooks.loading( canonizedFilename );
    }
    buffered = new BufferedReader(new FileReader(file));
    while ( (line = buffered.readLine()) !== null ) {
      code += line + '\n';
    }
    buffered.close(); // close the stream so there's no file locks

    if(canonizedFilename.toLowerCase().substring(canonizedFilename.length - 5) === ".json") // patch code when it is json
      code = "module.exports = (" + code + ");";

    moduleInfo = {
      loaded: false,
      id: canonizedFilename,
      exports: {},
      require: _requireClosure(file.parentFile)
    };
    var tail = '})';
    code = head + code + tail;

    if ( options.cache ) {
      _loadedModules[canonizedFilename] = moduleInfo;
    }
    var compiledWrapper = null;
    try {
      compiledWrapper = evaluate(code);
    } catch (e) {
      /*
       wph 20140313 JRE8 (nashorn) gives misleading linenumber of evaluating code not evaluated code.
       This can be fixed by instead using __engine.eval
       */
      throw new Error( "Error evaluating module " + path
          + " line #" + e.lineNumber
	  + " : " + e.message, canonizedFilename, e.lineNumber );
    }
    var __dirname = '' + file.parentFile.canonicalPath;
    var parameters = [
      moduleInfo.exports, /* exports */
      moduleInfo,         /* module */
      moduleInfo.require, /* require */
      canonizedFilename,  /* __filename */
      __dirname           /* __dirname */
    ];
    try {
      compiledWrapper
        .apply(moduleInfo.exports,  /* this */
               parameters);
    } catch (e) {
      var snippet = '';
      if ((''+e.lineNumber).match(/[0-9]/)){
	var lines = code.split(/\n/);
	if (e.lineNumber > 1){
	  snippet = ' ' + lines[e.lineNumber-2] + '\n';
	}
	snippet += '> ' + lines[e.lineNumber-1] + '\n';
	if (e.lineNumber < lines.length){
	  snippet += ' ' + lines[e.lineNumber] + '\n';
	}
      }
      throw new Error( "Error executing module " + path
        + " line #" + e.lineNumber
        + " : " + e.message + (snippet?('\n' + snippet):''), canonizedFilename, e.lineNumber );
    }
    if ( hooks ) {
      hooks.loaded( canonizedFilename );
    }
    moduleInfo.loaded = true;
    return moduleInfo;
  }

  function _requireClosure( parent ) {
    return function requireBoundToParent( path, options ) {
      var module = _require( parent, path , options);
      return module.exports;
    };
  }
  var _loadedModules = {};
  var _format = java.lang.String.format;
  return _requireClosure( new java.io.File(rootDir) );
  // last line deliberately has no semicolon!
})
<|endoftext|>


<commit_before>/*
 * angular-lazy-load
 *
 * Copyright(c) 2014 Paweł Wszoła <wszola.p@gmail.com>
 * MIT Licensed
 *
 */

/**
 * @author Paweł Wszoła (wszola.p@gmail.com)
 *
 */

angular.module('angularLazyImg', []);

angular.module('angularLazyImg').factory('LazyImgMagic', [
  '$window', '$rootScope', 'lazyImgConfig', 'lazyImgHelpers',
  function($window, $rootScope, lazyImgConfig, lazyImgHelpers){
    'use strict';

    var winDimensions, $win, images, isListening, options;
    var checkImagesT, saveWinOffsetT, containers;

    images = [];
    isListening = false;
    options = lazyImgConfig.getOptions();
    $win = angular.element($window);
    winDimensions = lazyImgHelpers.getWinDimensions();
    saveWinOffsetT = lazyImgHelpers.throttle(function(){
      winDimensions = lazyImgHelpers.getWinDimensions();
    }, 60);
    containers = [options.container || $win];

    function checkImages(){
      for(var i = images.length - 1; i >= 0; i--){
        var image = images[i];
        if(image && lazyImgHelpers.isElementInView(image.$elem[0], options.offset, winDimensions)){
          loadImage(image);
          images.splice(i, 1);
        }
      }
      if(images.length === 0){ stopListening(); }
    }

    checkImagesT = lazyImgHelpers.throttle(checkImages, 30);

    function listen(param){
      containers.forEach(function (container) {
        container[param]('scroll', checkImagesT);
        container[param]('touchmove', checkImagesT);
      });
      $win[param]('resize', checkImagesT);
      $win[param]('resize', saveWinOffsetT);
    }

    function startListening(){
      isListening = true;
      setTimeout(function(){
        checkImages();
        listen('on');
      }, 1);
    }

    function stopListening(){
      isListening = false;
      listen('off');
    }

    function removeImage(image){
      var index = images.indexOf(image);
      if(index !== -1) {
        images.splice(index, 1);
      }
    }

    function loadImage(photo){
      var img = new Image();
      img.onerror = function(){
        if(options.errorClass){
          photo.$elem.addClass(options.errorClass);
        }
        $rootScope.$emit('lazyImg:error', photo);
        options.onError(photo);
      };
      img.onload = function(){
        setPhotoSrc(photo.$elem, photo.src);
        if(options.successClass){
          photo.$elem.addClass(options.successClass);
        }
        $rootScope.$emit('lazyImg:success', photo);
        options.onSuccess(photo);
      };
      img.src = photo.src;
    }

    function setPhotoSrc($elem, src){
      if ($elem[0].nodeName.toLowerCase() === 'img') {
        $elem[0].src = src;
      } else {
        $elem.css('background-image', 'url("' + src + '")');
      }
    }

    // PHOTO
    function Photo($elem){
      this.$elem = $elem;
    }

    Photo.prototype.setSource = function(source){
      this.src = source;
      images.unshift(this);
      if (!isListening){ startListening(); }
    };

    Photo.prototype.removeImage = function(){
      removeImage(this);
      if(images.length === 0){ stopListening(); }
    };

    Photo.prototype.checkImages = function(){
      checkImages();
    };

    Photo.addContainer = function (container) {
      stopListening();
      containers.push(container);
      startListening();
    };

    Photo.removeContainer = function (container) {
      stopListening();
      containers.splice(containers.indexOf(container), 1);
      startListening();
    };

    return Photo;

  }
]);
<commit_msg>Always listen when we set a new image source<commit_after>/*
 * angular-lazy-load
 *
 * Copyright(c) 2014 Paweł Wszoła <wszola.p@gmail.com>
 * MIT Licensed
 *
 */

/**
 * @author Paweł Wszoła (wszola.p@gmail.com)
 *
 */

angular.module('angularLazyImg', []);

angular.module('angularLazyImg').factory('LazyImgMagic', [
  '$window', '$rootScope', 'lazyImgConfig', 'lazyImgHelpers',
  function($window, $rootScope, lazyImgConfig, lazyImgHelpers){
    'use strict';

    var winDimensions, $win, images, isListening, options;
    var checkImagesT, saveWinOffsetT, containers;

    images = [];
    isListening = false;
    options = lazyImgConfig.getOptions();
    $win = angular.element($window);
    winDimensions = lazyImgHelpers.getWinDimensions();
    saveWinOffsetT = lazyImgHelpers.throttle(function(){
      winDimensions = lazyImgHelpers.getWinDimensions();
    }, 60);
    containers = [options.container || $win];

    function checkImages(){
      for(var i = images.length - 1; i >= 0; i--){
        var image = images[i];
        if(image && lazyImgHelpers.isElementInView(image.$elem[0], options.offset, winDimensions)){
          loadImage(image);
          images.splice(i, 1);
        }
      }
      if(images.length === 0){ stopListening(); }
    }

    checkImagesT = lazyImgHelpers.throttle(checkImages, 30);

    function listen(param){
      containers.forEach(function (container) {
        container[param]('scroll', checkImagesT);
        container[param]('touchmove', checkImagesT);
      });
      $win[param]('resize', checkImagesT);
      $win[param]('resize', saveWinOffsetT);
    }

    function startListening(){
      isListening = true;
      setTimeout(function(){
        checkImages();
        listen('on');
      }, 1);
    }

    function stopListening(){
      isListening = false;
      listen('off');
    }

    function removeImage(image){
      var index = images.indexOf(image);
      if(index !== -1) {
        images.splice(index, 1);
      }
    }

    function loadImage(photo){
      var img = new Image();
      img.onerror = function(){
        if(options.errorClass){
          photo.$elem.addClass(options.errorClass);
        }
        $rootScope.$emit('lazyImg:error', photo);
        options.onError(photo);
      };
      img.onload = function(){
        setPhotoSrc(photo.$elem, photo.src);
        if(options.successClass){
          photo.$elem.addClass(options.successClass);
        }
        $rootScope.$emit('lazyImg:success', photo);
        options.onSuccess(photo);
      };
      img.src = photo.src;
    }

    function setPhotoSrc($elem, src){
      if ($elem[0].nodeName.toLowerCase() === 'img') {
        $elem[0].src = src;
      } else {
        $elem.css('background-image', 'url("' + src + '")');
      }
    }

    // PHOTO
    function Photo($elem){
      this.$elem = $elem;
    }

    Photo.prototype.setSource = function(source){
      this.src = source;
      images.unshift(this);
      startListening();
    };

    Photo.prototype.removeImage = function(){
      removeImage(this);
      if(images.length === 0){ stopListening(); }
    };

    Photo.prototype.checkImages = function(){
      checkImages();
    };

    Photo.addContainer = function (container) {
      stopListening();
      containers.push(container);
      startListening();
    };

    Photo.removeContainer = function (container) {
      stopListening();
      containers.splice(containers.indexOf(container), 1);
      startListening();
    };

    return Photo;

  }
]);
<|endoftext|>


<commit_before>define([
    'dojo/topic',
    'dojo/_base/Color',
    'dojo/_base/lang',

    'esri/graphic',
    'esri/symbols/SimpleFillSymbol',
    'esri/symbols/SimpleLineSymbol',
    'esri/symbols/SimpleMarkerSymbol'
], function (
    topic,
    Color,
    lang,

    Graphic,
    SimpleFillSymbol,
    SimpleLineSymbol,
    SimpleMarkerSymbol
) {
    return {
        // description:
        //      Handles interaction between app widgets and the  Mostly Layerthrough pub/sub

        // handles: Object[]
        //      container to track handles for this object
        handles: null,

        graphic: null,

        symbols: null,

        // Properties to be sent into constructor

        // esri/GraphicsLayer - the graphics layer for the map
        graphicsLayer: null,

        initialize: function (config, symbols) {
            // summary:
            //      set up default highlights and topics
            // topics: {
            //     graphics: {
            //         highlight:,
            //         clear:
            //     }
            // },
            // symbols: {
            //     point: {},
            //     line: {},
            //     poly: {}
            // }
            console.info('app.GraphicsController::initialize', arguments);

            if (symbols) {
                this.symbols = symbols;
            } else {
                this.symbols = {
                    point: null,
                    line: null,
                    poly: null
                };

                this.symbols.point = new SimpleMarkerSymbol({
                    color: [240, 28, 190, 200],
                    size: 7.5,
                    angle: 0,
                    xoffset: 0,
                    yoffset: 0,
                    type: 'esriSMS',
                    style: 'esriSMSCircle',
                    outline: {
                        color: [0, 31, 63, 255],
                        width: 0.5,
                        type: 'esriSLS',
                        style: 'esriSLSSolid'
                    }
                });
                this.symbols.line = new SimpleLineSymbol({
                    color: [255, 0, 197, 255],
                    width: 1.5,
                    type: 'esriSLS',
                    style: 'esriSLSDashDot'
                });
                this.symbols.poly = new SimpleFillSymbol({
                    color: [240, 28, 190, 200],
                    outline: {
                        color: [0, 31, 63, 255],
                        width: 0.5,
                        type: 'esriSLS',
                        style: 'esriSLSSolid'
                    },
                    type: 'esriSFS',
                    style: 'esriSFSSolid'
                });
            }

            this.handles = [];
            this.handles.push(
                topic.subscribe(config.topics.graphics.highlight,
                    lang.hitch(this, 'highlight')),
                topic.subscribe(config.topics.graphics.clear,
                    lang.hitch(this, 'removeGraphic'))
            );
        },
        highlight: function (graphic) {
            // summary:
            //      adds the clicked shape geometry to the graphics layer
            //      highlighting it
            // graphic - esri/Graphic
            console.info('app.GraphicsController::highlight', arguments);

            if (!graphic) {
                return;
            }

            this.removeGraphic(this.graphic);

            var symbol;
            switch (lang.getObject('geometry.type', false, graphic) || graphic[0].geometry.type) {
                case 'polygon':
                    symbol = this.symbols.poly;
                    break;
                case 'polyline':
                    symbol = this.symbols.line;
                    break;
                default:
                    symbol = this.symbols.point;
            }

            if (Array.isArray(graphic)) {
                this.graphic = [];

                graphic.forEach(function (item) {
                    var g = new Graphic(item.geometry, symbol);

                    this.graphic.push(g);
                    this.graphicsLayer.add(g);
                }, this);
            } else {
                this.graphic = new Graphic(graphic.geometry, symbol);
                this.graphicsLayer.add(this.graphic);
            }
        },
        removeGraphic: function (graphic) {
            // summary:
            //      removes the graphic from the map
            // graphic - esri/Graphic
            console.info('app.GraphicsController::removeGraphic', arguments);

            graphic = lang.getObject('graphic', false, graphic) || graphic || this.graphic;
            if (!graphic) {
                return;
            }

            if (Array.isArray(graphic)) {
                graphic.forEach(function (item) {
                    this.graphicsLayer.remove(item);
                }, this);
            } else {
                this.graphicsLayer.remove(graphic);
            }

            this.graphic = null;
        },
        destroy: function () {
            // summary:
            //      destroys all handles
            console.info('app.GraphicsController::destroy', arguments);

            this.handles.forEach(function (hand) {
                hand.remove();
            });

            this.removeGraphic();
        }
    };
});
<commit_msg>ignore magic numbers for colors<commit_after>define([
    'dojo/topic',
    'dojo/_base/Color',
    'dojo/_base/lang',

    'esri/graphic',
    'esri/symbols/SimpleFillSymbol',
    'esri/symbols/SimpleLineSymbol',
    'esri/symbols/SimpleMarkerSymbol'
], function (
    topic,
    Color,
    lang,

    Graphic,
    SimpleFillSymbol,
    SimpleLineSymbol,
    SimpleMarkerSymbol
) {
    return {
        // description:
        //      Handles interaction between app widgets and the  Mostly Layerthrough pub/sub

        // handles: Object[]
        //      container to track handles for this object
        handles: null,

        graphic: null,

        symbols: null,

        // Properties to be sent into constructor

        // esri/GraphicsLayer - the graphics layer for the map
        graphicsLayer: null,

        initialize: function (config, symbols) {
            // summary:
            //      set up default highlights and topics
            // topics: {
            //     graphics: {
            //         highlight:,
            //         clear:
            //     }
            // },
            // symbols: {
            //     point: {},
            //     line: {},
            //     poly: {}
            // }
            console.info('app.GraphicsController::initialize', arguments);

            if (symbols) {
                this.symbols = symbols;
            } else {
                this.symbols = {
                    point: null,
                    line: null,
                    poly: null
                };

                this.symbols.point = new SimpleMarkerSymbol({
                    color: [240, 28, 190, 200], // eslint-disable-line no-magic-numbers
                    size: 7.5,
                    angle: 0,
                    xoffset: 0,
                    yoffset: 0,
                    type: 'esriSMS',
                    style: 'esriSMSCircle',
                    outline: {
                        color: [0, 31, 63, 255], // eslint-disable-line no-magic-numbers
                        width: 0.5,
                        type: 'esriSLS',
                        style: 'esriSLSSolid'
                    }
                });
                this.symbols.line = new SimpleLineSymbol({
                    color: [255, 0, 197, 255], // eslint-disable-line no-magic-numbers
                    width: 1.5,
                    type: 'esriSLS',
                    style: 'esriSLSDashDot'
                });
                this.symbols.poly = new SimpleFillSymbol({
                    color: [240, 28, 190, 200], // eslint-disable-line no-magic-numbers
                    outline: {
                        color: [0, 31, 63, 255], // eslint-disable-line no-magic-numbers
                        width: 0.5,
                        type: 'esriSLS',
                        style: 'esriSLSSolid'
                    },
                    type: 'esriSFS',
                    style: 'esriSFSSolid'
                });
            }

            this.handles = [];
            this.handles.push(
                topic.subscribe(config.topics.graphics.highlight,
                    lang.hitch(this, 'highlight')),
                topic.subscribe(config.topics.graphics.clear,
                    lang.hitch(this, 'removeGraphic'))
            );
        },
        highlight: function (graphic) {
            // summary:
            //      adds the clicked shape geometry to the graphics layer
            //      highlighting it
            // graphic - esri/Graphic
            console.info('app.GraphicsController::highlight', arguments);

            if (!graphic) {
                return;
            }

            this.removeGraphic(this.graphic);

            var symbol;
            switch (lang.getObject('geometry.type', false, graphic) || graphic[0].geometry.type) {
                case 'polygon':
                    symbol = this.symbols.poly;
                    break;
                case 'polyline':
                    symbol = this.symbols.line;
                    break;
                default:
                    symbol = this.symbols.point;
            }

            if (Array.isArray(graphic)) {
                this.graphic = [];

                graphic.forEach(function (item) {
                    var g = new Graphic(item.geometry, symbol);

                    this.graphic.push(g);
                    this.graphicsLayer.add(g);
                }, this);
            } else {
                this.graphic = new Graphic(graphic.geometry, symbol);
                this.graphicsLayer.add(this.graphic);
            }
        },
        removeGraphic: function (graphic) {
            // summary:
            //      removes the graphic from the map
            // graphic - esri/Graphic
            console.info('app.GraphicsController::removeGraphic', arguments);

            graphic = lang.getObject('graphic', false, graphic) || graphic || this.graphic;
            if (!graphic) {
                return;
            }

            if (Array.isArray(graphic)) {
                graphic.forEach(function (item) {
                    this.graphicsLayer.remove(item);
                }, this);
            } else {
                this.graphicsLayer.remove(graphic);
            }

            this.graphic = null;
        },
        destroy: function () {
            // summary:
            //      destroys all handles
            console.info('app.GraphicsController::destroy', arguments);

            this.handles.forEach(function (hand) {
                hand.remove();
            });

            this.removeGraphic();
        }
    };
});
<|endoftext|>


<commit_before>/**
 * Created by fdimonte on 23/02/2015.
 */

var UIBasePanel = (function($){

    /**
     * UIBasePanel Class
     *
     * @constructor
     * @param id
     * @param label
     */
    function UIBasePanel(id,label) {
        this.$el = null;
        this._ID = id;
        this._label = label;
        this._gui = null;

        /*
        the initialize process will call
            this.createContent() - should be overridden
        which will returns a group of jQuery object to be appended to this.$el by
            this.createElement() - should NOT be overridden
        this method returns a Boolean success, if TRUE will call
            this.setEvents() - should be overridden
         */
        this.init();
    }

    /**
     * UIBasePanel prototype
     *
     * @type {{setEvents: Function, getStyles: Function, createContent: Function, init: Function, createElement: Function, addTo: Function, open: Function, close: Function, toggle: Function, addListener: Function, on: Function, off: Function, trigger: Function, fiboSelect: Function, panelCheckbox: Function}}
     */
    UIBasePanel.prototype = {

        /********************
         * OVERRIDABLE METHODS
         ********************/

        setEvents: function() {},
        getStyles: function() {},
        createContent: function() {},

        /********************
         * PUBLIC METHODS
         ********************/

        /*---INITIALIZE METHODS---*/

        init: function() {
            if(this.createElement(this.createContent()))
                this.setEvents();
            else
                throw new Error('cannot initialize panel: '+this._ID+' ('+this._label+')');
        },

        createElement: function(content) {
            if(!content) return false;
            var label_id = this._ID+'_checkbox';

            var $module  = $('<div/>').addClass('vui-panel').attr('id',this._ID),
                $label   = $('<div/>').addClass('vui-label'),
                $content = $('<div/>').addClass('vui-content');

            $label.append($('<input/>').attr('id',label_id).addClass('fibo_checkbox').attr('type','checkbox'));
            $label.append($('<label/>').attr('for',label_id).html(this._label));

            $content.append(content);

            this.$el = $module.append($label).append($content);
            this.$el.find('.fibo_checkbox').on('change',this.toggle_handler.bind(this));
            return true;
        },

        /*---SERVICE METHODS---*/

        // add panel to FibOS GUI
        addTo: function(gui) {
            this._gui = gui;
        },

        // open/close panel management
        open: function() {
            this.$el.addClass('fibo_panel_open');
            this.$el.find('.vui-label').find('.fibo_checkbox').attr('checked',true);
            this.$el.find('.vui-content').slideDown();
        },
        close: function() {
            this.$el.removeClass('fibo_panel_open');
            this.$el.find('.vui-label').find('.fibo_checkbox').attr('checked',false);
            this.$el.find('.vui-content').slideUp();
        },
        toggle: function() {
            if(isPanelOpen(this))
                this.close();
            else
                this.open();
        },
        toggle_handler: function(e) {
            var $t = $(e.currentTarget);
            if($t.is(':checked'))
                this.open();
            else
                this.close();
        },

        /*---FACTORY METHODS---*/

        fiboSelect : function(list,id,skipFirst) {
            if(!list && !id) return null;

            var $select = $('<select/>').attr('id',id);

            if(!skipFirst)
                $select.append($('<option/>').attr('disabled',true).attr('selected',true).val('none').text('chose a spacer'));

            for(var f=0;f<list.length;f++)
                $select.append($('<option/>').val(('00'+list[f]).substr(-3)).text(list[f]));

            return $select;
        },

        panelCheckbox : function(cont_id,title,checked) {
            var labid = cont_id+'_checkbox';
            var $container = $('<div/>').attr('id',cont_id).addClass('fibo_toggle');
            var $checkbox = $('<input/>').attr('id',labid).addClass('fibo_checkbox').attr('type','checkbox').attr('checked',checked);
            var $label = $('<label/>').attr('for',labid).attr('title',title).html(' ');
            return $container.append($checkbox).append($label);
        }

    };

    /********************
     * PRIVATE METHODS
     ********************/

    function isPanelOpen(panel){
        return panel.$el.find('.vui-content').css('display')!=='none';
    }

    return UIBasePanel;

}(jQuery));
<commit_msg>added event methods on uiBasePanel<commit_after>/**
 * Created by fdimonte on 23/02/2015.
 */

var UIBasePanel = (function($){

    /**
     * UIBasePanel Class
     *
     * @constructor
     * @param id
     * @param label
     */
    function UIBasePanel(id,label) {
        this.$el = null;
        this._ID = id;
        this._label = label;
        this._gui = null;

        this._listeners = {};

        /*
        the initialize process will call
            this.createContent() - should be overridden
        which will returns a group of jQuery object to be appended to this.$el by
            this.createElement() - should NOT be overridden
        this method returns a Boolean success, if TRUE will call
            this.setEvents() - should be overridden
         */
        this.init();
    }

    /**
     * UIBasePanel prototype
     *
     * @type {{setEvents: Function, getStyles: Function, createContent: Function, init: Function, createElement: Function, addTo: Function, open: Function, close: Function, toggle: Function, addListener: Function, on: Function, off: Function, trigger: Function, fiboSelect: Function, panelCheckbox: Function}}
     */
    UIBasePanel.prototype = {

        /********************
         * OVERRIDABLE METHODS
         ********************/

        setEvents: function() {},
        getStyles: function() {},
        createContent: function() {},

        /********************
         * PUBLIC METHODS
         ********************/

        /*---INITIALIZE METHODS---*/

        init: function() {
            if(this.createElement(this.createContent()))
                this.setEvents();
            else
                throw new Error('cannot initialize panel: '+this._ID+' ('+this._label+')');
        },

        createElement: function(content) {
            if(!content) return false;
            var label_id = this._ID+'_checkbox';

            var $module  = $('<div/>').addClass('vui-panel').attr('id',this._ID),
                $label   = $('<div/>').addClass('vui-label'),
                $content = $('<div/>').addClass('vui-content');

            $label.append($('<input/>').attr('id',label_id).addClass('fibo_checkbox').attr('type','checkbox'));
            $label.append($('<label/>').attr('for',label_id).html(this._label));

            $content.append(content);

            this.$el = $module.append($label).append($content);
            this.$el.find('.fibo_checkbox').on('change',this.toggle_handler.bind(this));
            return true;
        },

        /*---SERVICE METHODS---*/

        // add panel to FibOS GUI
        addTo: function(gui) {
            this._gui = gui;
        },

        // open/close panel management
        open: function() {
            this.$el.addClass('fibo_panel_open');
            this.$el.find('.vui-label').find('.fibo_checkbox').attr('checked',true);
            this.$el.find('.vui-content').slideDown();
        },
        close: function() {
            this.$el.removeClass('fibo_panel_open');
            this.$el.find('.vui-label').find('.fibo_checkbox').attr('checked',false);
            this.$el.find('.vui-content').slideUp();
        },
        toggle: function() {
            if(isPanelOpen(this))
                this.close();
            else
                this.open();
        },
        toggle_handler: function(e) {
            var $t = $(e.currentTarget);
            if($t.is(':checked'))
                this.open();
            else
                this.close();
        },

        // events management
        addListener: function(event,child,callback){
            if(typeof(child)=='function')
                this.$el.on(event,child.bind(this));
            else if(typeof(child)=='string')
                this.$el.on(event,child,callback.bind(this));
        },
        on: function(event,handler){
            this._listeners[event] || (this._listeners[event]=[]);
            this._listeners[event].push(handler);
        },
        off: function(event){
            this._listeners[event] = null;
        },
        trigger: function(event,data){
            this._gui && this._gui._logEvents && console.log('trigger [%s] -> %s(%s)',this._ID,event,data);

            var events = this._listeners[event];
            if(!events) return;
            for(var e in events) if(events.hasOwnProperty(e)) events[e](data,event);
        },

        /*---FACTORY METHODS---*/

        fiboSelect : function(list,id,skipFirst) {
            if(!list && !id) return null;

            var $select = $('<select/>').attr('id',id);

            if(!skipFirst)
                $select.append($('<option/>').attr('disabled',true).attr('selected',true).val('none').text('chose a spacer'));

            for(var f=0;f<list.length;f++)
                $select.append($('<option/>').val(('00'+list[f]).substr(-3)).text(list[f]));

            return $select;
        },

        panelCheckbox : function(cont_id,title,checked) {
            var labid = cont_id+'_checkbox';
            var $container = $('<div/>').attr('id',cont_id).addClass('fibo_toggle');
            var $checkbox = $('<input/>').attr('id',labid).addClass('fibo_checkbox').attr('type','checkbox').attr('checked',checked);
            var $label = $('<label/>').attr('for',labid).attr('title',title).html(' ');
            return $container.append($checkbox).append($label);
        }

    };

    /********************
     * PRIVATE METHODS
     ********************/

    function isPanelOpen(panel){
        return panel.$el.find('.vui-content').css('display')!=='none';
    }

    return UIBasePanel;

}(jQuery));
<|endoftext|>


<commit_before>(function (angular, _, toastr) {
    "use strict";

    angular.module("mfl.rating.controllers", [])

    .controller("mfl.rating.controllers.rating", ["$scope", "$stateParams",
        "facilitiesApi", "$window", "mfl.rating.services.rating","gisAdminUnitsApi",
        function ($scope, $stateParams,facilitiesApi, $window, ratingService,gisAdminUnitsApi) {
            $scope.spinneractive = true;
            $scope.tooltip = {
                "title": "",
                "checked": false
            };
            $scope.fac_id = $stateParams.fac_id;
            $scope.oneFacility = {};
            $scope.getFacility = function () {
                facilitiesApi.chus.filter({
                    "facility" : $scope.fac_id,
                    "fields": "id,code,name,status,households_monitored"
                })
                .success(function (data) {
                    $scope.chus = data.results;
                })
                .error(function (e) {
                    $scope.alert = e.error;
                });
                facilitiesApi.facilities.get($scope.fac_id)
                .success(function (data) {
                    $scope.spinneractive = false;
                    $scope.rating = [
                        {
                            current: 3,
                            max: 5
                        }
                    ];
                    $scope.oneFacility = data;
                    /*get link for gis to go to county*/
                    gisAdminUnitsApi.counties.get(data.boundaries.county_boundary)
                        .success(function (data) {
                            $scope.const_boundaries =data.properties
                                                            .constituency_boundary_ids.join(",");
                        })
                        .error(function (error) {
                            $scope.error = error;
                        });
                    /*get link for gis to go to constituency*/
                    gisAdminUnitsApi.constituencies.get(data.boundaries.constituency_boundary)
                        .success(function (data) {
                            $scope.ward_boundaries =data.properties.ward_boundary_ids.join(",");
                        })
                        .error(function (error) {
                            $scope.error = error;
                        });
                    _.each($scope.oneFacility.facility_services,
                        function (service) {
                            var current_rate = "";
                            current_rate = ratingService.getRating(service.id);
                            if(!_.isNull(current_rate)) {
                                service.ratings = [
                                    {
                                        current : current_rate,
                                        max: 5
                                    }
                                ];
                            }
                            else {
                                service.ratings = [
                                    {
                                        current : 0,
                                        max: 5
                                    }
                                ];
                            }
                        }
                    );
                })
                .error(function (e) {
                    $scope.alert_main = e.detail;
                    $scope.spinneractive = false;
                });
            };
            $scope.getFacility();

            $scope.getSelectedRating = function (rating, id) {
                $scope.fac_rating = {
                    facility_service : id,
                    rating : rating
                };
            };
            $scope.rateService = function (service_obj) {
                $scope.service_rating = {
                    facility_service : service_obj.id,
                    rating : service_obj.ratings
                };
                service_obj.spinner = true;
                facilitiesApi.ratings.create($scope.service_rating)
                    .success(function (data) {
                        //save rating in localStorage
                        service_obj.spinner = false;
                        ratingService.storeRating(
                            data.facility_service, data.rating);
                        $scope.getFacility();
                        toastr.success("Successfully rated");
                    })
                    .error(function (e) {
                        console.log($scope.service_rating);
                        service_obj.spinner = false;
                        $scope.alert = e.detail || "Service can only be rated once a day";
                        toastr.error($scope.alert);
                    });
            };
            //printing function
            $scope.printing = function () {
                $window.print();
            };
        }
    ])
    .controller("mfl.rating.controllers.rating.map",["$scope","$log","gisAdminUnitsApi",
        "leafletData",
        function($scope,$log,gisAdminUnitsApi,leafletData){
        $scope.spinner = true;
        /*Setup for map data*/
        angular.extend($scope, {
            defaults: {
                scrollWheelZoom: false
            },
            layers:{},
            tiles:{
                openstreetmap: {
                    url: "http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
                    options: {
                        opacity: 0.7,
                        attribution: "© OpenStreetMap contributors"
                    }
                }
            }
        });

        /*Wait for facility to be defined*/
        $scope.$watch("oneFacility", function (f) {
            if (_.isUndefined(f)){
                return;
            }
            /*ward coordinates*/
            gisAdminUnitsApi.wards.get(f.boundaries.ward_boundary)
            .success(function(data){
                $scope.spinner = false;
                $scope.ward_gis = data;
                leafletData.getMap("wardmap")
                    .then(function (map) {
                        var coords = data.properties.bound.coordinates[0];
                        var bounds = _.map(coords, function(c) {
                            return [c[1], c[0]];
                        });
                        map.fitBounds(bounds);
                    });
                var gis = data;
                angular.extend($scope, {
                    geojson: {
                        data: gis,
                        style: {
                            fillColor: "rgb(255, 135, 32)",
                            weight: 2,
                            opacity: 1,
                            color: "rgba(0, 0, 0, 0.52)",
                            dashArray: "3",
                            fillOpacity: 0.8
                        }
                    },
                    layers:{
                        baselayers:{
                            ward: {
                                name: "Ward",
                                url: "/assets/img/transparent.png",
                                type:"group"
                            }
                        },
                        overlays:{
                            facility:{
                                name:"Facility Location",
                                type:"group",
                                visible: true
                            }
                        }
                    }
                });

                /*facility's coordinates*/
                gisAdminUnitsApi.facilities.get(f.coordinates)
                .success(function(data){
                    angular.extend($scope,{
                        markers: {
                            mainMarker: {
                                layer:"facility",
                                lat: data.properties.coordinates.coordinates[1],
                                lng: data.properties.coordinates.coordinates[0],
                                message: "Facility location"
                            }
                        }
                    });
                })
                .error(function(error){
                    $log.error(error);
                });
            })
            .error(function(error){
                $log.error(error);
            });

        });
    }]);
})(window.angular, window._, window.toastr);
<commit_msg>Fixing service rating<commit_after>(function (angular, _, toastr) {
    "use strict";

    angular.module("mfl.rating.controllers", [])

    .controller("mfl.rating.controllers.rating", ["$scope", "$stateParams",
        "facilitiesApi", "$window", "mfl.rating.services.rating","gisAdminUnitsApi",
        function ($scope, $stateParams,facilitiesApi, $window, ratingService,gisAdminUnitsApi) {
            $scope.spinneractive = true;
            $scope.tooltip = {
                "title": "",
                "checked": false
            };
            $scope.fac_id = $stateParams.fac_id;
            $scope.oneFacility = {};
            $scope.getFacility = function () {
                facilitiesApi.chus.filter({
                    "facility" : $scope.fac_id,
                    "fields": "id,code,name,status,households_monitored"
                })
                .success(function (data) {
                    $scope.chus = data.results;
                })
                .error(function (e) {
                    $scope.alert = e.error;
                });
                facilitiesApi.facilities.get($scope.fac_id)
                .success(function (data) {
                    $scope.spinneractive = false;
                    $scope.rating = [
                        {
                            current: 3,
                            max: 5
                        }
                    ];
                    $scope.oneFacility = data;
                    /*get link for gis to go to county*/
                    gisAdminUnitsApi.counties.get(data.boundaries.county_boundary)
                        .success(function (data) {
                            $scope.const_boundaries =data.properties
                                                            .constituency_boundary_ids.join(",");
                        })
                        .error(function (error) {
                            $scope.error = error;
                        });
                    /*get link for gis to go to constituency*/
                    gisAdminUnitsApi.constituencies.get(data.boundaries.constituency_boundary)
                        .success(function (data) {
                            $scope.ward_boundaries =data.properties.ward_boundary_ids.join(",");
                        })
                        .error(function (error) {
                            $scope.error = error;
                        });
                    _.each($scope.oneFacility.facility_services,
                        function (service) {
                            var current_rate = "";
                            current_rate = ratingService.getRating(service.id);
                            if(!_.isNull(current_rate)) {
                                service.comment = current_rate[1];
                                service.ratings = [
                                    {
                                        current : current_rate[0],
                                        max: 5
                                    }
                                ];
                            }
                            else {
                                service.ratings = [
                                    {
                                        current : 0,
                                        max: 5
                                    }
                                ];
                            }
                        }
                    );
                })
                .error(function (e) {
                    $scope.alert_main = e.detail;
                    $scope.spinneractive = false;
                });
            };
            $scope.getFacility();

            $scope.getSelectedRating = function (rating, id) {
                $scope.fac_rating = {
                    facility_service : id,
                    rating : rating
                };
            };
            $scope.rateService = function (service_obj) {
                $scope.service_rating = {
                    facility_service : service_obj.id,
                    rating : service_obj.ratings[0].current,
                    comment : service_obj.ratings[0].comment
                };
                service_obj.spinner = true;
                facilitiesApi.ratings.create($scope.service_rating)
                    .success(function (data) {
                        //save rating in localStorage
                        var rating_val = [];
                        rating_val[0] = data.rating;
                        rating_val[1] = data.comment;
                        service_obj.spinner = false;
                        ratingService.storeRating(
                            data.facility_service, rating_val);
                        $scope.getFacility();
                        toastr.success("Successfully rated");
                    })
                    .error(function (e) {
                        service_obj.spinner = false;
                        $scope.alert = e.detail || "Service can only be rated once a day";
                        toastr.error($scope.alert);
                    });
            };
            //printing function
            $scope.printing = function () {
                $window.print();
            };
        }
    ])
    .controller("mfl.rating.controllers.rating.map",["$scope","$log","gisAdminUnitsApi",
        "leafletData",
        function($scope,$log,gisAdminUnitsApi,leafletData){
        $scope.spinner = true;
        /*Setup for map data*/
        angular.extend($scope, {
            defaults: {
                scrollWheelZoom: false
            },
            layers:{},
            tiles:{
                openstreetmap: {
                    url: "http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
                    options: {
                        opacity: 0.7,
                        attribution: "© OpenStreetMap contributors"
                    }
                }
            }
        });

        /*Wait for facility to be defined*/
        $scope.$watch("oneFacility", function (f) {
            if (_.isUndefined(f)){
                return;
            }
            /*ward coordinates*/
            gisAdminUnitsApi.wards.get(f.boundaries.ward_boundary)
            .success(function(data){
                $scope.spinner = false;
                $scope.ward_gis = data;
                leafletData.getMap("wardmap")
                    .then(function (map) {
                        var coords = data.properties.bound.coordinates[0];
                        var bounds = _.map(coords, function(c) {
                            return [c[1], c[0]];
                        });
                        map.fitBounds(bounds);
                    });
                var gis = data;
                angular.extend($scope, {
                    geojson: {
                        data: gis,
                        style: {
                            fillColor: "rgb(255, 135, 32)",
                            weight: 2,
                            opacity: 1,
                            color: "rgba(0, 0, 0, 0.52)",
                            dashArray: "3",
                            fillOpacity: 0.8
                        }
                    },
                    layers:{
                        baselayers:{
                            ward: {
                                name: "Ward",
                                url: "/assets/img/transparent.png",
                                type:"group"
                            }
                        },
                        overlays:{
                            facility:{
                                name:"Facility Location",
                                type:"group",
                                visible: true
                            }
                        }
                    }
                });

                /*facility's coordinates*/
                gisAdminUnitsApi.facilities.get(f.coordinates)
                .success(function(data){
                    angular.extend($scope,{
                        markers: {
                            mainMarker: {
                                layer:"facility",
                                lat: data.properties.coordinates.coordinates[1],
                                lng: data.properties.coordinates.coordinates[0],
                                message: "Facility location"
                            }
                        }
                    });
                })
                .error(function(error){
                    $log.error(error);
                });
            })
            .error(function(error){
                $log.error(error);
            });

        });
    }]);
})(window.angular, window._, window.toastr);
<|endoftext|>


<commit_before>import GDPRUserList from '../utils/GDPRUserList';

const accountsToRemove = GDPRUserList;

const filterAccounts = stateAccounts =>
    Object.keys(stateAccounts)
        .filter(name => !accountsToRemove.includes(name))
        .reduce(
            (acc, cur) => ({
                ...acc,
                [cur]: stateAccounts[cur],
            }),
            {}
        );

const filterContent = stateContent => {
    const contentToRemove = Object.keys(stateContent).filter(key =>
        accountsToRemove.includes(stateContent[key].author)
    );

    const contentToKeep = Object.keys(stateContent).filter(
        key => !accountsToRemove.includes(stateContent[key].author)
    );

    // First, remove content authored by GDPR users.
    const removedByAuthor = contentToKeep.reduce(
        (acc, cur) => ({
            ...acc,
            [cur]: stateContent[cur],
        }),
        {}
    );

    // Finally, remove GDPR-authored replies referenced in other content.
    return Object.keys(removedByAuthor).reduce(
        (acc, cur) => ({
            ...acc,
            [cur]: {
                ...removedByAuthor[cur],
                replies: removedByAuthor[cur].replies.filter(
                    url => !contentToRemove.includes(url)
                ),
            },
        }),
        {}
    );
};

export default function stateCleaner(state) {
    return {
        ...state,
        accounts: filterAccounts(state.accounts),
        content: filterContent(state.content),
    };
}
<commit_msg>name fns specific to gdpr<commit_after>import GDPRUserList from '../utils/GDPRUserList';

const accountsToRemove = GDPRUserList;

const gdprFilterAccounts = stateAccounts =>
    Object.keys(stateAccounts)
        .filter(name => !accountsToRemove.includes(name))
        .reduce(
            (acc, cur) => ({
                ...acc,
                [cur]: stateAccounts[cur],
            }),
            {}
        );

const gdprFilterContent = stateContent => {
    const contentToRemove = Object.keys(stateContent).filter(key =>
        accountsToRemove.includes(stateContent[key].author)
    );

    const contentToKeep = Object.keys(stateContent).filter(
        key => !accountsToRemove.includes(stateContent[key].author)
    );

    // First, remove content authored by GDPR users.
    const removedByAuthor = contentToKeep.reduce(
        (acc, cur) => ({
            ...acc,
            [cur]: stateContent[cur],
        }),
        {}
    );

    // Finally, remove GDPR-authored replies referenced in other content.
    return Object.keys(removedByAuthor).reduce(
        (acc, cur) => ({
            ...acc,
            [cur]: {
                ...removedByAuthor[cur],
                replies: removedByAuthor[cur].replies.filter(
                    url => !contentToRemove.includes(url)
                ),
            },
        }),
        {}
    );
};

export default function stateCleaner(state) {
    return {
        ...state,
        accounts: gdprFilterAccounts(state.accounts),
        content: gdprFilterContent(state.content),
    };
}
<|endoftext|>


<commit_before>"use strict";

const { createLogic } = require('redux-logic');

const MangaAction = require('../action/MangaAction');
const RouterAction = require('../action/RouterAction');
const { WorkerTasks, execByWorker } = require('../service/WorkerService');
const FileService = require('../service/FileService');
const MangaSelector = require('../selector/MangaSelector');

const downloadChapter = createLogic({
    type: MangaAction.ACTIONS.ENQUEUE_CHAPTER_DOWNLOAD,
    latest: true,
    process({ getState, action }, dispatch, done) {
        downloadNextChapter(dispatch, getState)
            .then(() => done());
    }
});

function downloadNextChapter(dispatch, getState) {
    const state = getState();

    if (MangaSelector.isDownloading(state)) {
        return Promise.resolve();
    }

    const chapterIds = MangaSelector.getDownloadChapterIds(state);

    if (chapterIds.length === 0) {
        return Promise.resolve();
    }

    const chapter = MangaSelector.getChapter(state, chapterIds[0]);

    dispatch(MangaAction.createStartChapterDownloadAction());

    function downloadChapterProgress({chapterId, status}) {
        dispatch(MangaAction.createChapterDownloadStatusAction(chapterId, status));
    }

    const mangaTitle = MangaSelector.getManga(state).title;
    const managaDirPath = FileService.getMangaDirectory(mangaTitle);
    const arg = {
        chapter,
        dirPath: managaDirPath,
        fileName: FileService.getMangaChapterFileName(mangaTitle, chapter.title)
    };
    return execByWorker(WorkerTasks.DOWNLOAD_MANGA_CHAPTER, arg, downloadChapterProgress)
        .then(() => {
            dispatch(MangaAction.createEndChapterDownloadAction());
            return downloadNextChapter(dispatch, getState);
        })
        .catch((err) => {
            dispatch(MangaAction.createEndChapterDownloadAction());
            console.log('Download failed:', err);
            return downloadNextChapter(dispatch, getState);
        });
}

module.exports = [
    downloadChapter
];
<commit_msg>Fix download queue and download trigger<commit_after>"use strict";

const { createLogic } = require('redux-logic');

const MangaAction = require('../action/MangaAction');
const RouterAction = require('../action/RouterAction');
const { WorkerTasks, execByWorker } = require('../service/WorkerService');
const FileService = require('../service/FileService');
const MangaSelector = require('../selector/MangaSelector');

const validateEnqueuedChapter = createLogic({
    type: MangaAction.ACTIONS.ENQUEUE_CHAPTER_DOWNLOAD,
    validate({ getState, action }, allow, reject) {
        const chapterId = action.payload;
        const enqueuedIds = MangaSelector.getDownloadChapterIds(getState());

        if (enqueuedIds.indexOf(chapterId) === -1) {
            allow(action);
        } else {
            reject();
        }
    }
});

const startDownload = createLogic({
    type: MangaAction.ACTIONS.ENQUEUE_CHAPTER_DOWNLOAD,
    process({ getState, action }, dispatch, done) {
        downloadNextChapter(dispatch, getState)
            .then(() => done());
    }
});

function downloadNextChapter(dispatch, getState) {
    const state = getState();

    if (MangaSelector.isDownloading(state)) {
        return Promise.resolve();
    }

    const chapterIds = MangaSelector.getDownloadChapterIds(state);

    if (chapterIds.length === 0) {
        return Promise.resolve();
    }

    const chapter = MangaSelector.getChapter(state, chapterIds[0]);

    dispatch(MangaAction.createStartChapterDownloadAction());

    function downloadChapterProgress({chapterId, status}) {
        dispatch(MangaAction.createChapterDownloadStatusAction(chapterId, status));
    }

    const mangaTitle = MangaSelector.getManga(state).title;
    const managaDirPath = FileService.getMangaDirectory(mangaTitle);
    const arg = {
        chapter,
        dirPath: managaDirPath,
        fileName: FileService.getMangaChapterFileName(mangaTitle, chapter.title)
    };
    return execByWorker(WorkerTasks.DOWNLOAD_MANGA_CHAPTER, arg, downloadChapterProgress)
        .then(() => {
            dispatch(MangaAction.createEndChapterDownloadAction());
            return downloadNextChapter(dispatch, getState);
        })
        .catch((err) => {
            dispatch(MangaAction.createEndChapterDownloadAction());
            console.log('Download failed:', err);
            return downloadNextChapter(dispatch, getState);
        });
}

module.exports = [
    validateEnqueuedChapter,
    startDownload
];
<|endoftext|>