<commit_before>'use strict';

var extend = require('extend'),
    async = require('async'),
    mongoose = require('mongoose'),
    Schema = mongoose.Schema,
    ObjectId = mongoose.Schema.ObjectId,
    mongo = require('./mongo'),
    util = require('./util');

var dbRefSchema = {
    kind: {
        type: String
    },
    id: {
        type: ObjectId
    },
    _id: false
};

var attachmentSchema = {
    _id: ObjectId,
    fileId: ObjectId,
    name: 'string',
    mime: 'string',
    md5: 'string'
};

var baseDefinition = {
    _an: [dbRefSchema],         // Ancestors array
    _ch: [dbRefSchema],         // Children array
    _at: [attachmentSchema],    // Attachments array
    _dc: Date,                  // Date of creation
    _dm: Date,                  // Date of modification
    _ow: String                 // Owner (email)
};

var baseOptions = {
    strict: 'throw'
};

var kinds = {};

var kindProvider = function defaultProvider(kind, callback) {
    callback(new Error('Kind ' + kind + ' not found'));
};

var hooks = [
    'Save',
    'Remove',
    'Init',
    'Validate'
];

exports.create = function createKind(name, definition, options) {
    if (kinds[name]) {
        throw new Error('Cannot instantiate two kinds with the same name');
    }

    if (!definition || typeof definition !== 'object') {
        throw new Error('Kind definition has to be an object');
    }

    for (var i in definition) {
        if (i[0] === '_') {
            throw new Error('Kind definition cannot contain fields that begin with a "_". Found: ' + i);
        }
    }

    var thisDef = extend({}, baseDefinition, definition);
    var thisOptions = extend({}, baseOptions);

    var thisSchema = new Schema(thisDef, thisOptions);

    options = options || {};

    var hookName, preHookName, postHookName;
    for (i = 0; i < hooks.length; i++) {
        hookName = hooks[i];
        preHookName = 'pre' + hookName;
        if (options[preHookName] && typeof options[preHookName] === 'function') {
            thisSchema.pre(hookName.toLowerCase(), options[preHookName]);
        }
        postHookName = 'post' + hookName;
        if (options[postHookName] && typeof options[postHookName] === 'function') {
            thisSchema.post(hookName.toLowerCase(), options[postHookName]);
        }
    }

    thisSchema.add({
        _dc: Date,
        _dm: Date
    });

    thisSchema.pre('save', function (next) {
        if (!this._dc){
            this._dc = this._id.getTimestamp();
        }

        this._dm = this.isNew ? this._dc : new Date();

        next();
    });

    thisSchema.index({
        'ancestors.kind': 1,
        'ancestors.id': 1
    });

    thisSchema.methods.getKind = thisSchema.statics.getKind = function () {
        return name;
    };

    thisSchema.virtual('owner').set(function (v) {
        this._ow = v; // TODO check
    }).get(function () {
        return this._ow;
    });

    thisSchema.methods.createChild = createChild;
    thisSchema.methods.getChildren = getChildren;
    //thisSchema.methods.setParent = setParent;

    thisSchema.methods.createAttachment = createAttachment;
    thisSchema.methods.removeAttachment = removeAttachment;
    thisSchema.methods.getAttachment = getAttachment;

    thisSchema.pre('save', preSaveChild);
    thisSchema.pre('remove', preRemove);

    kinds[name] = mongoose.model('kind_' + name, thisSchema, 'kind_' + name);

};

function createChild(kind, value) {

    if (!this._dc) {
        throw new Error('Cannot call method createChild of an unsaved entry');
    }

    var kindModel = exports.getSync(kind);
    var child = new kindModel(value);
    child._ow = this._ow;                           // By default, owner is propagated
    for (var i = 0; i < this._an.length; i++) {
        child._an.push(this._an[i]);
    }
    child._an.push({
        id: this._id,
        kind: this.getKind()
    });
    child._newChild = true;
    child._parent = this;

    return child;

}

function preSaveChild(next) {
    var self = this;
    if (this._newChild) {
        var parentModel = exports.getSync(this._parent.getKind());
        parentModel.findByIdAndUpdate(this._parent._id, {
            $push: {
                _ch: {
                    kind: this.getKind(),
                    id: this._id
                }
            }
        }, function (err) {
            if (err) {
                return next(err);
            }
            self._newChild = false;
            next();
        });
    } else {
        next();
    }
}

function preRemove(next) {
    var ref = {
        id: this._id,
        kind: this.getKind()
    };

    exports.getSync(ref.kind).findById(ref.id, function (err, res) {
        if (err) {
            return next(err);
        }
        // First we have to remove the reference from the parent
        if (res._an.length) {
            var parent = res._an[res._an.length - 1];
            exports.get(parent.kind, function (err, parentModel) {
                if (err) {
                    return next(err);
                }
                parentModel.findByIdAndUpdate(parent.id, {
                    $pull: {
                        _ch: ref
                    }
                }, function (err) {
                    if (err) {
                        return next(err);
                    }
                    async.map(res._ch, removeEntryChildrenAndAttachments, next);
                });
            });
        } else {
            async.map(res._ch, removeEntryChildrenAndAttachments, next);
        }
    });

}

function removeEntryChildrenAndAttachments(entry, cb) {

    exports.get(entry.kind, function (err, entryModel) {
        if (err) {
            return cb(err);
        }
        entryModel.findByIdAndRemove(entry.id, function (err, result) {
            if (err) {
                return cb(err);
            }
            if(result) {
                async.map(result._ch, removeEntryChildrenAndAttachments, cb);
                // TODO remove attachments
            } else {
                cb();
            }
        });
    })
}

function getChildren(kind, callback) {

    if (typeof kind === 'function') {
        callback = kind;
        kind = null;
    }

    var ref = {
        kind: this.getKind(),
        id: this._id
    };

    if (kind) { // Search all children of a specific kind
        exports.get(kind, function (err, kindModel) {
            if (err) {
                return callback(err);
            }
            kindModel.find({
                _an: {
                    $elemMatch: ref
                }
            }, callback);
        });
    } else { // Retrieve all first level children of this entry
        var kindModel = exports.getSync(ref.kind);
        kindModel.findOne(this._id, function (err, res) {
            if (err) {
                return callback(err);
            }
            var children = res._ch;
            async.map(children, getChild, callback);
        });
    }

}

function getChild(child, callback) {
    exports.get(child.kind, function (err, kindModel) {
        if (err) {
            return callback(err);
        }
        kindModel.findOne(child.id, callback);
    });
}

/** TODO enable setParent
 function setParent(other, callback) {
    var kind = this.getKind(),
        id = this._id;
    exports.getSync(kind).findById(id, function (err, that) {
        if(err) {
            return callback(err);
        }
        if(that._an.length) {

        }
    });
}
 */

function createAttachment(attachment, callback) {
    callback = util.ensureCallback(callback);

    var self = this;
    mongo.writeFile(attachment.data, attachment.name, {
        root: 'attachments',
        content_type: attachment.contentType
    }, function (err, fileData) {
        if (err) {
            return callback(err);
        }
        var attachment = {
            _id: fileData._id,
            fileId: fileData._id,
            name: fileData.filename,
            mime: fileData.contentType,
            md5: fileData.md5
        };
        exports.getSync(self.getKind()).findByIdAndUpdate(self._id, {
            $push: {
                _at: attachment
            }
        }, function (err, res) {
            if (err) {
                return callback(err);
            }
            callback(null, attachment);
        });
    });
}

function removeAttachment(attachmentId, callback) {
    callback = util.ensureCallback(callback);

    exports.getSync(this.getKind()).findOneAndUpdate({
        _id: this._id,
        '_at._id': attachmentId
    }, {
        $pull: {
            _at: {
                _id: attachmentId
            }
        }
    }, {
        'new': false // Important because we need to retrieve the fileId
    }, function (err, res) {
        if (err) {
            return callback(err);
        }
        if (!res) { // Attachment not found
            return callback(new Error('attachment with id ' + attachmentId.toString() + ' not found'));
        }
        callback(null); // File can be removed from GridFS later
        for (var i = 0, ii = res._at.length; i < ii; i++) {
            if (res._at[i]._id.toString() === attachmentId.toString()) {
                mongo.removeFile(res._at[i].fileId, 'attachments', util.noop);
            }
        }
    });
}

function getAttachment(attachmentId, callback) {
    exports.getSync(this.getKind()).findOne({
        _id: this._id,
        '_at._id': attachmentId
    }, '_at.$.fileId', function (err, res) {
        if (err) {
            return callback(err);
        }
        mongo.readFile(res._at[0].fileId, {
            root: 'attachments'
        }, callback);
    });
}

exports.setProvider = function setKindProvider(provider) {
    if (typeof provider === 'function') {
        kindProvider = provider;
    } else {
        throw new Error('Kind provider must be a function');
    }
};

exports.get = function getKindModel(name, callback) {
    var prom = new Promise(function (resolve, reject) {
        if (kinds[name]) {
            resolve(kinds[name]);
        } else {
            kindProvider(name, function gotKindHandler(err, res) {
                if (err) {
                    return reject(err);
                }
                exports.create(name, res.definition, res.options);
                resolve(kinds[name]);
            });
        }
    });
    return util.bindPromise(prom, callback);
};

exports.getSync = function getKindModelSync(name) {
    if (!kinds[name]) {
        throw new Error('Kind ' + name + ' is not loaded');
    }
    return kinds[name];
};<commit_msg>use mongoose isNew check<commit_after>'use strict';

var extend = require('extend'),
    async = require('async'),
    mongoose = require('mongoose'),
    Schema = mongoose.Schema,
    ObjectId = mongoose.Schema.ObjectId,
    mongo = require('./mongo'),
    util = require('./util');

var dbRefSchema = {
    kind: {
        type: String
    },
    id: {
        type: ObjectId
    },
    _id: false
};

var attachmentSchema = {
    _id: ObjectId,
    fileId: ObjectId,
    name: 'string',
    mime: 'string',
    md5: 'string'
};

var baseDefinition = {
    _an: [dbRefSchema],         // Ancestors array
    _ch: [dbRefSchema],         // Children array
    _at: [attachmentSchema],    // Attachments array
    _dc: Date,                  // Date of creation
    _dm: Date,                  // Date of modification
    _ow: String                 // Owner (email)
};

var baseOptions = {
    strict: 'throw'
};

var kinds = {};

var kindProvider = function defaultProvider(kind, callback) {
    callback(new Error('Kind ' + kind + ' not found'));
};

var hooks = [
    'Save',
    'Remove',
    'Init',
    'Validate'
];

exports.create = function createKind(name, definition, options) {
    if (kinds[name]) {
        throw new Error('Cannot instantiate two kinds with the same name');
    }

    if (!definition || typeof definition !== 'object') {
        throw new Error('Kind definition has to be an object');
    }

    for (var i in definition) {
        if (i[0] === '_') {
            throw new Error('Kind definition cannot contain fields that begin with a "_". Found: ' + i);
        }
    }

    var thisDef = extend({}, baseDefinition, definition);
    var thisOptions = extend({}, baseOptions);

    var thisSchema = new Schema(thisDef, thisOptions);

    options = options || {};

    var hookName, preHookName, postHookName;
    for (i = 0; i < hooks.length; i++) {
        hookName = hooks[i];
        preHookName = 'pre' + hookName;
        if (options[preHookName] && typeof options[preHookName] === 'function') {
            thisSchema.pre(hookName.toLowerCase(), options[preHookName]);
        }
        postHookName = 'post' + hookName;
        if (options[postHookName] && typeof options[postHookName] === 'function') {
            thisSchema.post(hookName.toLowerCase(), options[postHookName]);
        }
    }

    thisSchema.add({
        _dc: Date,
        _dm: Date
    });

    thisSchema.pre('save', function (next) {
        if (!this._dc){
            this._dc = this._id.getTimestamp();
        }

        this._dm = this.isNew ? this._dc : new Date();

        next();
    });

    thisSchema.index({
        'ancestors.kind': 1,
        'ancestors.id': 1
    });

    thisSchema.methods.getKind = thisSchema.statics.getKind = function () {
        return name;
    };

    thisSchema.virtual('owner').set(function (v) {
        this._ow = v; // TODO check
    }).get(function () {
        return this._ow;
    });

    thisSchema.methods.createChild = createChild;
    thisSchema.methods.getChildren = getChildren;
    //thisSchema.methods.setParent = setParent;

    thisSchema.methods.createAttachment = createAttachment;
    thisSchema.methods.removeAttachment = removeAttachment;
    thisSchema.methods.getAttachment = getAttachment;

    thisSchema.pre('save', preSaveChild);
    thisSchema.pre('remove', preRemove);

    kinds[name] = mongoose.model('kind_' + name, thisSchema, 'kind_' + name);

};

function createChild(kind, value) {

    if (this.isNew) {
        throw new Error('Cannot call method createChild of an unsaved entry');
    }

    var kindModel = exports.getSync(kind);
    var child = new kindModel(value);
    child._ow = this._ow;                           // By default, owner is propagated
    for (var i = 0; i < this._an.length; i++) {
        child._an.push(this._an[i]);
    }
    child._an.push({
        id: this._id,
        kind: this.getKind()
    });
    child._newChild = true;
    child._parent = this;

    return child;

}

function preSaveChild(next) {
    var self = this;
    if (this._newChild) {
        var parentModel = exports.getSync(this._parent.getKind());
        parentModel.findByIdAndUpdate(this._parent._id, {
            $push: {
                _ch: {
                    kind: this.getKind(),
                    id: this._id
                }
            }
        }, function (err) {
            if (err) {
                return next(err);
            }
            self._newChild = false;
            next();
        });
    } else {
        next();
    }
}

function preRemove(next) {
    var ref = {
        id: this._id,
        kind: this.getKind()
    };

    exports.getSync(ref.kind).findById(ref.id, function (err, res) {
        if (err) {
            return next(err);
        }
        // First we have to remove the reference from the parent
        if (res._an.length) {
            var parent = res._an[res._an.length - 1];
            exports.get(parent.kind, function (err, parentModel) {
                if (err) {
                    return next(err);
                }
                parentModel.findByIdAndUpdate(parent.id, {
                    $pull: {
                        _ch: ref
                    }
                }, function (err) {
                    if (err) {
                        return next(err);
                    }
                    async.map(res._ch, removeEntryChildrenAndAttachments, next);
                });
            });
        } else {
            async.map(res._ch, removeEntryChildrenAndAttachments, next);
        }
    });

}

function removeEntryChildrenAndAttachments(entry, cb) {

    exports.get(entry.kind, function (err, entryModel) {
        if (err) {
            return cb(err);
        }
        entryModel.findByIdAndRemove(entry.id, function (err, result) {
            if (err) {
                return cb(err);
            }
            if(result) {
                async.map(result._ch, removeEntryChildrenAndAttachments, cb);
                // TODO remove attachments
            } else {
                cb();
            }
        });
    })
}

function getChildren(kind, callback) {

    if (typeof kind === 'function') {
        callback = kind;
        kind = null;
    }

    var ref = {
        kind: this.getKind(),
        id: this._id
    };

    if (kind) { // Search all children of a specific kind
        exports.get(kind, function (err, kindModel) {
            if (err) {
                return callback(err);
            }
            kindModel.find({
                _an: {
                    $elemMatch: ref
                }
            }, callback);
        });
    } else { // Retrieve all first level children of this entry
        var kindModel = exports.getSync(ref.kind);
        kindModel.findOne(this._id, function (err, res) {
            if (err) {
                return callback(err);
            }
            var children = res._ch;
            async.map(children, getChild, callback);
        });
    }

}

function getChild(child, callback) {
    exports.get(child.kind, function (err, kindModel) {
        if (err) {
            return callback(err);
        }
        kindModel.findOne(child.id, callback);
    });
}

/** TODO enable setParent
 function setParent(other, callback) {
    var kind = this.getKind(),
        id = this._id;
    exports.getSync(kind).findById(id, function (err, that) {
        if(err) {
            return callback(err);
        }
        if(that._an.length) {

        }
    });
}
 */

function createAttachment(attachment, callback) {
    callback = util.ensureCallback(callback);

    var self = this;
    mongo.writeFile(attachment.data, attachment.name, {
        root: 'attachments',
        content_type: attachment.contentType
    }, function (err, fileData) {
        if (err) {
            return callback(err);
        }
        var attachment = {
            _id: fileData._id,
            fileId: fileData._id,
            name: fileData.filename,
            mime: fileData.contentType,
            md5: fileData.md5
        };
        exports.getSync(self.getKind()).findByIdAndUpdate(self._id, {
            $push: {
                _at: attachment
            }
        }, function (err, res) {
            if (err) {
                return callback(err);
            }
            callback(null, attachment);
        });
    });
}

function removeAttachment(attachmentId, callback) {
    callback = util.ensureCallback(callback);

    exports.getSync(this.getKind()).findOneAndUpdate({
        _id: this._id,
        '_at._id': attachmentId
    }, {
        $pull: {
            _at: {
                _id: attachmentId
            }
        }
    }, {
        'new': false // Important because we need to retrieve the fileId
    }, function (err, res) {
        if (err) {
            return callback(err);
        }
        if (!res) { // Attachment not found
            return callback(new Error('attachment with id ' + attachmentId.toString() + ' not found'));
        }
        callback(null); // File can be removed from GridFS later
        for (var i = 0, ii = res._at.length; i < ii; i++) {
            if (res._at[i]._id.toString() === attachmentId.toString()) {
                mongo.removeFile(res._at[i].fileId, 'attachments', util.noop);
            }
        }
    });
}

function getAttachment(attachmentId, callback) {
    exports.getSync(this.getKind()).findOne({
        _id: this._id,
        '_at._id': attachmentId
    }, '_at.$.fileId', function (err, res) {
        if (err) {
            return callback(err);
        }
        mongo.readFile(res._at[0].fileId, {
            root: 'attachments'
        }, callback);
    });
}

exports.setProvider = function setKindProvider(provider) {
    if (typeof provider === 'function') {
        kindProvider = provider;
    } else {
        throw new Error('Kind provider must be a function');
    }
};

exports.get = function getKindModel(name, callback) {
    var prom = new Promise(function (resolve, reject) {
        if (kinds[name]) {
            resolve(kinds[name]);
        } else {
            kindProvider(name, function gotKindHandler(err, res) {
                if (err) {
                    return reject(err);
                }
                exports.create(name, res.definition, res.options);
                resolve(kinds[name]);
            });
        }
    });
    return util.bindPromise(prom, callback);
};

exports.getSync = function getKindModelSync(name) {
    if (!kinds[name]) {
        throw new Error('Kind ' + name + ' is not loaded');
    }
    return kinds[name];
};<|endoftext|>


<commit_before>import {
  inBrowser,
  CustomEvent,
  remove,
  some,
  find,
  _,
  throttle,
  supportWebp,
  getDPR,
  scrollParent,
  getBestSelectionFromSrcset,
  assign,
  isObject,
  hasIntersectionObserver,
  modeType
} from './util'

import ReactiveListener from './listener'

const DEFAULT_URL = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
const DEFAULT_EVENTS = ['scroll', 'wheel', 'mousewheel', 'resize', 'animationend', 'transitionend', 'touchmove']
const DEFAULT_OBSERVER_OPTIONS = {
  rootMargin: '0px',
  threshold: 0
}

export default function (Vue) {
  return class Lazy {
    constructor ({ preLoad, error, throttleWait, preLoadTop, dispatchEvent, loading, attempt, silent = true, scale, listenEvents, hasbind, filter, adapter, observer, observerOptions }) {
      this.version = '__VUE_LAZYLOAD_VERSION__'
      this.mode = modeType.event
      this.ListenerQueue = []
      this.TargetIndex = 0
      this.TargetQueue = []
      this.options = {
        silent: silent,
        dispatchEvent: !!dispatchEvent,
        throttleWait: throttleWait || 200,
        preLoad: preLoad || 1.3,
        preLoadTop: preLoadTop || 0,
        error: error || DEFAULT_URL,
        loading: loading || DEFAULT_URL,
        attempt: attempt || 3,
        scale: scale || getDPR(scale),
        ListenEvents: listenEvents || DEFAULT_EVENTS,
        hasbind: false,
        supportWebp: supportWebp(),
        filter: filter || {},
        adapter: adapter || {},
        observer: !!observer,
        observerOptions: observerOptions || DEFAULT_OBSERVER_OPTIONS
      }
      this._initEvent()

      this.lazyLoadHandler = throttle(this._lazyLoadHandler.bind(this), this.options.throttleWait)

      this.setMode(this.options.observer ? modeType.observer : modeType.event)
    }

    /**
     * update config
     * @param  {Object} config params
     * @return
     */
    config (options = {}) {
      assign(this.options, options)
    }

    /**
     * output listener's load performance
     * @return {Array}
     */
    performance () {
      let list = []

      this.ListenerQueue.map(item => {
        list.push(item.performance())
      })

      return list
    }

    /*
     * add lazy component to queue
     * @param  {Vue} vm lazy component instance
     * @return
     */
    addLazyBox (vm) {
      this.ListenerQueue.push(vm)
      if (inBrowser) {
        this._addListenerTarget(window)
        this._observer && this._observer.observe(vm.el)
        if (vm.$el && vm.$el.parentNode) {
          this._addListenerTarget(vm.$el.parentNode)
        }
      }
    }

    /*
     * add image listener to queue
     * @param  {DOM} el
     * @param  {object} binding vue directive binding
     * @param  {vnode} vnode vue directive vnode
     * @return
     */
    add (el, binding, vnode) {
      if (some(this.ListenerQueue, item => item.el === el)) {
        this.update(el, binding)
        return Vue.nextTick(this.lazyLoadHandler)
      }

      let { src, loading, error } = this._valueFormatter(binding.value)

      Vue.nextTick(() => {
        src = getBestSelectionFromSrcset(el, this.options.scale) || src
        this._observer && this._observer.observe(el)

        const container = Object.keys(binding.modifiers)[0]
        let $parent

        if (container) {
          $parent = vnode.context.$refs[container]
          // if there is container passed in, try ref first, then fallback to getElementById to support the original usage
          $parent = $parent ? $parent.$el || $parent : document.getElementById(container)
        }

        if (!$parent) {
          $parent = scrollParent(el)
        }

        const newListener = new ReactiveListener({
          bindType: binding.arg,
          $parent,
          el,
          loading,
          error,
          src,
          elRenderer: this._elRenderer.bind(this),
          options: this.options
        })

        this.ListenerQueue.push(newListener)

        if (inBrowser) {
          this._addListenerTarget(window)
          this._addListenerTarget($parent)
        }

        this.lazyLoadHandler()
        Vue.nextTick(() => this.lazyLoadHandler())
      })
    }

    /**
    * update image src
    * @param  {DOM} el
    * @param  {object} vue directive binding
    * @return
    */
    update (el, binding) {
      let { src, loading, error } = this._valueFormatter(binding.value)
      src = getBestSelectionFromSrcset(el, this.options.scale) || src

      const exist = find(this.ListenerQueue, item => item.el === el)

      exist && exist.update({
        src,
        loading,
        error
      })
      if (this._observer) {
        this._observer.unobserve(el)
        this._observer.observe(el)
      }
      this.lazyLoadHandler()
      Vue.nextTick(() => this.lazyLoadHandler())
    }

    /**
    * remove listener form list
    * @param  {DOM} el
    * @return
    */
    remove (el) {
      if (!el) return
      this._observer && this._observer.unobserve(el)
      const existItem = find(this.ListenerQueue, item => item.el === el)
      if (existItem) {
        this._removeListenerTarget(existItem.$parent)
        this._removeListenerTarget(window)
        remove(this.ListenerQueue, existItem) && existItem.destroy()
      }
    }

    /*
     * remove lazy components form list
     * @param  {Vue} vm Vue instance
     * @return
     */
    removeComponent (vm) {
      if (!vm) return
      remove(this.ListenerQueue, vm)
      this._observer && this._observer.unobserve(vm.el)
      if (vm.$parent && vm.$el.parentNode) {
        this._removeListenerTarget(vm.$el.parentNode)
      }
      this._removeListenerTarget(window)
    }

    setMode (mode) {
      if (!hasIntersectionObserver && mode === modeType.observer) {
        mode = modeType.event
      }

      this.mode = mode // event or observer

      if (mode === modeType.event) {
        if (this._observer) {
          this.ListenerQueue.forEach(listener => {
            this._observer.unobserve(listener.el)
          })
          this._observer = null
        }

        this.TargetQueue.forEach(target => {
          this._initListen(target.el, true)
        })
      } else {
        this.TargetQueue.forEach(target => {
          this._initListen(target.el, false)
        })
        this._initIntersectionObserver()
      }
    }

    /*
    *** Private functions ***
    */

    /*
     * add listener target
     * @param  {DOM} el listener target
     * @return
     */
    _addListenerTarget (el) {
      if (!el) return
      let target = find(this.TargetQueue, target => target.el === el)
      if (!target) {
        target = {
          el: el,
          id: ++this.TargetIndex,
          childrenCount: 1,
          listened: true
        }
        this.mode === modeType.event && this._initListen(target.el, true)
        this.TargetQueue.push(target)
      } else {
        target.childrenCount++
      }
      return this.TargetIndex
    }

    /*
     * remove listener target or reduce target childrenCount
     * @param  {DOM} el or window
     * @return
     */
    _removeListenerTarget (el) {
      this.TargetQueue.forEach((target, index) => {
        if (target.el === el) {
          target.childrenCount--
          if (!target.childrenCount) {
            this._initListen(target.el, false)
            this.TargetQueue.splice(index, 1)
            target = null
          }
        }
      })
    }

    /*
     * add or remove eventlistener
     * @param  {DOM} el DOM or Window
     * @param  {boolean} start flag
     * @return
     */
    _initListen (el, start) {
      this.options.ListenEvents.forEach((evt) => _[start ? 'on' : 'off'](el, evt, this.lazyLoadHandler))
    }

    _initEvent () {
      this.Event = {
        listeners: {
          loading: [],
          loaded: [],
          error: []
        }
      }

      this.$on = (event, func) => {
        this.Event.listeners[event].push(func)
      }

      this.$once = (event, func) => {
        const vm = this
        function on () {
          vm.$off(event, on)
          func.apply(vm, arguments)
        }
        this.$on(event, on)
      }

      this.$off = (event, func) => {
        if (!func) {
          this.Event.listeners[event] = []
          return
        }
        remove(this.Event.listeners[event], func)
      }

      this.$emit = (event, context, inCache) => {
        this.Event.listeners[event].forEach(func => func(context, inCache))
      }
    }

    /**
     * find nodes which in viewport and trigger load
     * @return
     */
    _lazyLoadHandler () {
      let catIn = false
      this.ListenerQueue.forEach((listener, index) => {
        if (listener.state.loaded) return
        catIn = listener.checkInView()
        if (!catIn) return
        listener.load(() => {
          if (!listener.state.error && listener.state.loaded) {
            this.ListenerQueue.splice(index, 1)
          }
        })
      })
    }
    /**
    * init IntersectionObserver
    * set mode to observer
    * @return
    */
    _initIntersectionObserver () {
      if (!hasIntersectionObserver) return
      this._observer = new IntersectionObserver(this._observerHandler.bind(this), this.options.observerOptions)
      if (this.ListenerQueue.length) {
        this.ListenerQueue.forEach(listener => {
          this._observer.observe(listener.el)
        })
      }
    }

    /**
    * init IntersectionObserver
    * @return
    */
    _observerHandler (entries, observer) {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          this.ListenerQueue.forEach(listener => {
            if (listener.el === entry.target) {
              if (listener.state.loaded) return this._observer.unobserve(listener.el)
              listener.load()
            }
          })
        }
      })
    }

    /**
    * set element attribute with image'url and state
    * @param  {object} lazyload listener object
    * @param  {string} state will be rendered
    * @param  {bool} inCache  is rendered from cache
    * @return
    */
    _elRenderer (listener, state, cache) {
      if (!listener.el) return
      const { el, bindType } = listener

      let src
      switch (state) {
        case 'loading':
          src = listener.loading
          break
        case 'error':
          src = listener.error
          break
        default:
          src = listener.src
          break
      }

      if (bindType) {
        el.style[bindType] = 'url("' + src + '")'
      } else if (el.getAttribute('src') !== src) {
        el.setAttribute('src', src)
      }

      el.setAttribute('lazy', state)

      this.$emit(state, listener, cache)
      this.options.adapter[state] && this.options.adapter[state](listener, this.options)

      if (this.options.dispatchEvent) {
        const event = new CustomEvent(state, {
          detail: listener
        })
        el.dispatchEvent(event)
      }
    }

    /**
    * generate loading loaded error image url
    * @param {string} image's src
    * @return {object} image's loading, loaded, error url
    */
    _valueFormatter (value) {
      let src = value
      let loading = this.options.loading
      let error = this.options.error

      // value is object
      if (isObject(value)) {
        if (!value.src && !this.options.silent) console.error('Vue Lazyload warning: miss src with ' + value)
        src = value.src
        loading = value.loading || this.options.loading
        error = value.error || this.options.error
      }
      return {
        src,
        loading,
        error
      }
    }
  }
}
<commit_msg>debug: ISSUE=#263<commit_after>import {
  inBrowser,
  CustomEvent,
  remove,
  some,
  find,
  _,
  throttle,
  supportWebp,
  getDPR,
  scrollParent,
  getBestSelectionFromSrcset,
  assign,
  isObject,
  hasIntersectionObserver,
  modeType
} from './util'

import ReactiveListener from './listener'

const DEFAULT_URL = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
const DEFAULT_EVENTS = ['scroll', 'wheel', 'mousewheel', 'resize', 'animationend', 'transitionend', 'touchmove']
const DEFAULT_OBSERVER_OPTIONS = {
  rootMargin: '0px',
  threshold: 0
}

export default function (Vue) {
  return class Lazy {
    constructor ({ preLoad, error, throttleWait, preLoadTop, dispatchEvent, loading, attempt, silent = true, scale, listenEvents, hasbind, filter, adapter, observer, observerOptions }) {
      this.version = '__VUE_LAZYLOAD_VERSION__'
      this.mode = modeType.event
      this.ListenerQueue = []
      this.TargetIndex = 0
      this.TargetQueue = []
      this.options = {
        silent: silent,
        dispatchEvent: !!dispatchEvent,
        throttleWait: throttleWait || 200,
        preLoad: preLoad || 1.3,
        preLoadTop: preLoadTop || 0,
        error: error || DEFAULT_URL,
        loading: loading || DEFAULT_URL,
        attempt: attempt || 3,
        scale: scale || getDPR(scale),
        ListenEvents: listenEvents || DEFAULT_EVENTS,
        hasbind: false,
        supportWebp: supportWebp(),
        filter: filter || {},
        adapter: adapter || {},
        observer: !!observer,
        observerOptions: observerOptions || DEFAULT_OBSERVER_OPTIONS
      }
      this._initEvent()

      this.lazyLoadHandler = throttle(this._lazyLoadHandler.bind(this), this.options.throttleWait)

      this.setMode(this.options.observer ? modeType.observer : modeType.event)
    }

    /**
     * update config
     * @param  {Object} config params
     * @return
     */
    config (options = {}) {
      assign(this.options, options)
    }

    /**
     * output listener's load performance
     * @return {Array}
     */
    performance () {
      let list = []

      this.ListenerQueue.map(item => {
        list.push(item.performance())
      })

      return list
    }

    /*
     * add lazy component to queue
     * @param  {Vue} vm lazy component instance
     * @return
     */
    addLazyBox (vm) {
      this.ListenerQueue.push(vm)
      if (inBrowser) {
        this._addListenerTarget(window)
        this._observer && this._observer.observe(vm.el)
        if (vm.$el && vm.$el.parentNode) {
          this._addListenerTarget(vm.$el.parentNode)
        }
      }
    }

    /*
     * add image listener to queue
     * @param  {DOM} el
     * @param  {object} binding vue directive binding
     * @param  {vnode} vnode vue directive vnode
     * @return
     */
    add (el, binding, vnode) {
      if (some(this.ListenerQueue, item => item.el === el)) {
        this.update(el, binding)
        return Vue.nextTick(this.lazyLoadHandler)
      }

      let { src, loading, error } = this._valueFormatter(binding.value)

      Vue.nextTick(() => {
        src = getBestSelectionFromSrcset(el, this.options.scale) || src
        this._observer && this._observer.observe(el)

        const container = Object.keys(binding.modifiers)[0]
        let $parent

        if (container) {
          $parent = vnode.context.$refs[container]
          // if there is container passed in, try ref first, then fallback to getElementById to support the original usage
          $parent = $parent ? $parent.$el || $parent : document.getElementById(container)
        }

        if (!$parent) {
          $parent = scrollParent(el)
        }

        const newListener = new ReactiveListener({
          bindType: binding.arg,
          $parent,
          el,
          loading,
          error,
          src,
          elRenderer: this._elRenderer.bind(this),
          options: this.options
        })

        this.ListenerQueue.push(newListener)

        if (inBrowser) {
          this._addListenerTarget(window)
          this._addListenerTarget($parent)
        }

        this.lazyLoadHandler()
        Vue.nextTick(() => this.lazyLoadHandler())
      })
    }

    /**
    * update image src
    * @param  {DOM} el
    * @param  {object} vue directive binding
    * @return
    */
    update (el, binding) {
      let { src, loading, error } = this._valueFormatter(binding.value)
      src = getBestSelectionFromSrcset(el, this.options.scale) || src

      const exist = find(this.ListenerQueue, item => item.el === el)

      exist && exist.update({
        src,
        loading,
        error
      })
      if (this._observer) {
        this._observer.unobserve(el)
        this._observer.observe(el)
      }
      this.lazyLoadHandler()
      Vue.nextTick(() => this.lazyLoadHandler())
    }

    /**
    * remove listener form list
    * @param  {DOM} el
    * @return
    */
    remove (el) {
      if (!el) return
      this._observer && this._observer.unobserve(el)
      const existItem = find(this.ListenerQueue, item => item.el === el)
      if (existItem) {
        this._removeListenerTarget(existItem.$parent)
        this._removeListenerTarget(window)
        remove(this.ListenerQueue, existItem) && existItem.destroy()
      }
    }

    /*
     * remove lazy components form list
     * @param  {Vue} vm Vue instance
     * @return
     */
    removeComponent (vm) {
      if (!vm) return
      remove(this.ListenerQueue, vm)
      this._observer && this._observer.unobserve(vm.el)
      if (vm.$parent && vm.$el.parentNode) {
        this._removeListenerTarget(vm.$el.parentNode)
      }
      this._removeListenerTarget(window)
    }

    setMode (mode) {
      if (!hasIntersectionObserver && mode === modeType.observer) {
        mode = modeType.event
      }

      this.mode = mode // event or observer

      if (mode === modeType.event) {
        if (this._observer) {
          this.ListenerQueue.forEach(listener => {
            this._observer.unobserve(listener.el)
          })
          this._observer = null
        }

        this.TargetQueue.forEach(target => {
          this._initListen(target.el, true)
        })
      } else {
        this.TargetQueue.forEach(target => {
          this._initListen(target.el, false)
        })
        this._initIntersectionObserver()
      }
    }

    /*
    *** Private functions ***
    */

    /*
     * add listener target
     * @param  {DOM} el listener target
     * @return
     */
    _addListenerTarget (el) {
      if (!el) return
      let target = find(this.TargetQueue, target => target.el === el)
      if (!target) {
        target = {
          el: el,
          id: ++this.TargetIndex,
          childrenCount: 1,
          listened: true
        }
        this.mode === modeType.event && this._initListen(target.el, true)
        this.TargetQueue.push(target)
      } else {
        target.childrenCount++
      }
      return this.TargetIndex
    }

    /*
     * remove listener target or reduce target childrenCount
     * @param  {DOM} el or window
     * @return
     */
    _removeListenerTarget (el) {
      this.TargetQueue.forEach((target, index) => {
        if (target.el === el) {
          target.childrenCount--
          if (!target.childrenCount) {
            this._initListen(target.el, false)
            this.TargetQueue.splice(index, 1)
            target = null
          }
        }
      })
    }

    /*
     * add or remove eventlistener
     * @param  {DOM} el DOM or Window
     * @param  {boolean} start flag
     * @return
     */
    _initListen (el, start) {
      this.options.ListenEvents.forEach((evt) => _[start ? 'on' : 'off'](el, evt, this.lazyLoadHandler))
    }

    _initEvent () {
      this.Event = {
        listeners: {
          loading: [],
          loaded: [],
          error: []
        }
      }

      this.$on = (event, func) => {
        this.Event.listeners[event].push(func)
      }

      this.$once = (event, func) => {
        const vm = this
        function on () {
          vm.$off(event, on)
          func.apply(vm, arguments)
        }
        this.$on(event, on)
      }

      this.$off = (event, func) => {
        if (!func) {
          this.Event.listeners[event] = []
          return
        }
        remove(this.Event.listeners[event], func)
      }

      this.$emit = (event, context, inCache) => {
        this.Event.listeners[event].forEach(func => func(context, inCache))
      }
    }

    /**
     * find nodes which in viewport and trigger load
     * @return
     */
    _lazyLoadHandler () {
      let catIn = false
      this.ListenerQueue.forEach((listener, index) => {
        if (!listener.state.error && listener.state.loaded) {
          this.ListenerQueue.splice(index, 1)
          return
        }
        catIn = listener.checkInView()
        if (!catIn) return
        listener.load()
      })
    }
    /**
    * init IntersectionObserver
    * set mode to observer
    * @return
    */
    _initIntersectionObserver () {
      if (!hasIntersectionObserver) return
      this._observer = new IntersectionObserver(this._observerHandler.bind(this), this.options.observerOptions)
      if (this.ListenerQueue.length) {
        this.ListenerQueue.forEach(listener => {
          this._observer.observe(listener.el)
        })
      }
    }

    /**
    * init IntersectionObserver
    * @return
    */
    _observerHandler (entries, observer) {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          this.ListenerQueue.forEach(listener => {
            if (listener.el === entry.target) {
              if (listener.state.loaded) return this._observer.unobserve(listener.el)
              listener.load()
            }
          })
        }
      })
    }

    /**
    * set element attribute with image'url and state
    * @param  {object} lazyload listener object
    * @param  {string} state will be rendered
    * @param  {bool} inCache  is rendered from cache
    * @return
    */
    _elRenderer (listener, state, cache) {
      if (!listener.el) return
      const { el, bindType } = listener

      let src
      switch (state) {
        case 'loading':
          src = listener.loading
          break
        case 'error':
          src = listener.error
          break
        default:
          src = listener.src
          break
      }

      if (bindType) {
        el.style[bindType] = 'url("' + src + '")'
      } else if (el.getAttribute('src') !== src) {
        el.setAttribute('src', src)
      }

      el.setAttribute('lazy', state)

      this.$emit(state, listener, cache)
      this.options.adapter[state] && this.options.adapter[state](listener, this.options)

      if (this.options.dispatchEvent) {
        const event = new CustomEvent(state, {
          detail: listener
        })
        el.dispatchEvent(event)
      }
    }

    /**
    * generate loading loaded error image url
    * @param {string} image's src
    * @return {object} image's loading, loaded, error url
    */
    _valueFormatter (value) {
      let src = value
      let loading = this.options.loading
      let error = this.options.error

      // value is object
      if (isObject(value)) {
        if (!value.src && !this.options.silent) console.error('Vue Lazyload warning: miss src with ' + value)
        src = value.src
        loading = value.loading || this.options.loading
        error = value.error || this.options.error
      }
      return {
        src,
        loading,
        error
      }
    }
  }
}
<|endoftext|>


<commit_before>(function (exports){
    /**
     * Returns the color for a resistor band value
     * @param  {string} value resistor band value between -2 to 9
     * @return {string}       color corresponding to that value
     */
    function getcolor(value){
        var color = {'-2': "silver",
                '-1': "gold",
                '0': "black",
                '1': "brown",
                '2': "red",
                '3': "orange",
                '4': "yellow",
                '5': "green",
                '6': "blue",
                '7': "violet",
                '8': "grey",
                '9': "white"};
        return color[value];
    }

    /**
     * Returns the color corresponding to the tolerance value
     * @param  {string} tol tolerance
     * @return {string}     color corresponding to the tolerance value
     */
    function getToleranceColor(tol){
        var tolerance_color={
            '5':'gray',
            '10':'violet',
            '25':'blue',
            '50':'green',
            '100':'brown',
            '200':'red',
            '500':'gold',
            '1000':'silver',
            '2000':''
        };
        var val = (+tol) * 100;
        if(val in tolerance_color){
            return tolerance_color[val];
        }
        return '-1';
    }

    /**
     * Return the color bands
     * @param  {String}     resistor_value resistor value
     * @param  {double}     tol      tolerance value
     * @param  {interger}   mul      multiplier([0,3,6])
     * @return {Dict object}         band color
     */
    exports.resistorToColor = function (resistor_value, tol, mul){
        var digit = [0, 0, 0],
            digits = [],
            dec = -1,
            mul = {
                value:'',
                pos:''
            },
            multiplier;
        if (!resistor_value){
            throw ("resistor: invalid parameter");
        }
        resistor_value = String(resistor_value).replace(/^0*/,'');
        tol = tol || 5;
        mul = mul || null;
        var significant_digit = tol > 2 ? 2 : 3;
        if(/[kK]/.test(resistor_value)){
            mul['value'] = 100000;
        }else if(/[mM]/.test(resistor_value)){
            mul['value'] = 100000000;
        }else{
            mul['value'] = 100;
        }
        if(/[.]/.test(resistor_value)){
            resistor_value = resistor_value.replace(/[rRkKmM]/,'');
        }else{
            resistor_value = resistor_value.replace(/[rRkKmM]/,'.');
        }
        resistor_value = (""+ +(+resistor_value * mul['value']).toFixed(4));
        for (var i = 0 ; i< significant_digit ; i++){
            digits.push(resistor_value[i]?resistor_value[i]:0);
        }
        multiplier = resistor_value.length - significant_digit - 2;
        if(significant_digit == 2){
            return {
                'band1':getcolor(digits[0]),
                'band2':getcolor(digits[1]),
                'band3':getcolor(multiplier),
                'band4':'',
                'band5':getToleranceColor(tol)
            };
        }
        return {
            'band1':getcolor(digits[0]),
            'band2':getcolor(digits[1]),
            'band3':getcolor(digits[2]),
            'band4':getcolor(multiplier),
            'band5':getToleranceColor(tol)
        };
    };

})(typeof exports === "undefined" ?this['resistor'] = {}:exports);
<commit_msg>add commits and created a preprocessing function<commit_after>(function (exports){
    /**
     * Returns the color for a resistor band value
     * @param  {string} value resistor band value between -2 to 9
     * @return {string}       color corresponding to that value
     */
    function getcolor(value){
        var color = {'-2': "silver",
                '-1': "gold",
                '0': "black",
                '1': "brown",
                '2': "red",
                '3': "orange",
                '4': "yellow",
                '5': "green",
                '6': "blue",
                '7': "violet",
                '8': "grey",
                '9': "white"};
        return color[value];
    }

    /**
     * Returns the color corresponding to the tolerance value
     * @param  {string} tol tolerance
     * @return {string}     color corresponding to the tolerance value
     */
    function getToleranceColor(tol){
        var tolerance_color={
            '5':'gray',
            '10':'violet',
            '25':'blue',
            '50':'green',
            '100':'brown',
            '200':'red',
            '500':'gold',
            '1000':'silver',
            '2000':''
        };
        var val = (+tol) * 100;
        if(val in tolerance_color){
            return tolerance_color[val];
        }
        return '-1';
    }

    function toStandardForm(value){
        var replace_char;
        //remove any zeros present in the start of string
        value = String(value).replace(/^0*/,'');

        //find the replace character if it exist else default to 'R'
        //and add R to the last of the value so as to make is consistent
        //if char is not present
        replace_char = value.match(/[mMkKrR]/);
        if(!replace_char){
            replace_char = ['R'];
            value = value + 'R';
        }

        //replace '.' is exist with replace_char
        if(value.indexOf(".")!== -1){
            value = value.replace(replace_char[0], '');
            value = value.replace(".",replace_char[0]);
        }

        return value;
    }

    /**
     * Return the color bands
     * @param  {String}     resistor_value resistor value
     * @param  {double}     tol      tolerance value
     * @param  {interger}   mul      multiplier([0,3,6])
     * @return {Dict object}         band color
     */
    exports.resistorToColor = function (resistor_value, tol){
        var digit = [0, 0, 0],
            digits = [],
            dec = -1,
            mul = {
                value:'',
                pos:''
            },
            multiplier,
            significant_digit;

        //defaulting parameters if not present
        tol = tol || 5;
        mul = mul || null;

        //calculating number of digit to consider before taking the digit for multiplier
        significant_digit = tol > 2 ? 2 : 3;

        //check if resistor value exist or not...
        if (!resistor_value){
            throw ("resistor: invalid parameter");
        }

        //preprocess the value
        resistor_value = toStandardForm(resistor_value);

        //setting the multiplier value k=1000*100, m=100000*100, and default=100
        //extra 100 is used to get accuracy when doing float division and multiplication
        if(/[kK]/.test(resistor_value)){
            mul['value'] = 100000;
        }else if(/[mM]/.test(resistor_value)){
            mul['value'] = 100000000;
        }else{
            mul['value'] = 100;
        }

        //remove multiplier character and replace by . if not present.
        resistor_value = resistor_value.replace(/[rRkKmM]/,'.');

        //convert resistor_value to float by unioperator +
        //round of to precision 4 to remove float point bug eg try (1.16 * 100)
        //remove trailing zeros
        //finally convert to string by ""+
        resistor_value = (""+ +(+resistor_value * mul['value']).toFixed(4));

        for (var i = 0 ; i< significant_digit ; i++){
            digits.push(resistor_value[i]?resistor_value[i]:0);
        }
        multiplier = resistor_value.length - significant_digit - 2;
        if(significant_digit == 2){
            return {
                'band1':getcolor(digits[0]),
                'band2':getcolor(digits[1]),
                'band3':getcolor(multiplier),
                'band4':'',
                'band5':getToleranceColor(tol)
            };
        }
        return {
            'band1':getcolor(digits[0]),
            'band2':getcolor(digits[1]),
            'band3':getcolor(digits[2]),
            'band4':getcolor(multiplier),
            'band5':getToleranceColor(tol)
        };
    };

})(typeof exports === "undefined" ?this['resistor'] = {}:exports);
<|endoftext|>


<commit_before>const { DefinePlugin, NoEmitOnErrorsPlugin, ProgressPlugin } = require('webpack');
const path = require('path');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

const PROD = process.env.NODE_ENV === 'production';

const config = {
    mode: PROD ? 'production' : 'development',
    name: 'main-process',
    devtool: PROD ? false : 'cheap-module-source-map',
    entry: {
        main: path.resolve(__dirname, 'src/main-process/main.ts')
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js'
    },
    resolve: {
        extensions: ['.ts', '.js', '.json']
    },
    module: {
        rules: [
            {
                test: /\.ts$/,
                loader: 'awesome-typescript-loader',
                exclude: [/node_modules/, /dist/, /assets/, /test/],
                options: {
                    configFileName: path.resolve(__dirname, 'tsconfig.electron.json')
                }
            }
        ]
    },
    plugins: [
        new NoEmitOnErrorsPlugin(),
        new ProgressPlugin(),
        new DefinePlugin({
            'process.env': {
                NODE_ENV: JSON.stringify(process.env.NODE_ENV)
            }
        })
    ],
    node: {
        __dirname: false,
        __filename: false
    },
    target: 'electron-main',
    externals: {
        nodegit: 'require("nodegit")'
    }
};

if (PROD) {
    config.plugins.push(new UglifyJsPlugin({
        uglifyOptions: { ecma: 6 }
    }));
}

module.exports = config;
<commit_msg>Add external '@sentry/electron' for main process<commit_after>const { DefinePlugin, NoEmitOnErrorsPlugin, ProgressPlugin } = require('webpack');
const path = require('path');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

const PROD = process.env.NODE_ENV === 'production';

const config = {
    mode: PROD ? 'production' : 'development',
    name: 'main-process',
    devtool: PROD ? false : 'cheap-module-source-map',
    entry: {
        main: path.resolve(__dirname, 'src/main-process/main.ts')
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js'
    },
    resolve: {
        extensions: ['.ts', '.js', '.json']
    },
    module: {
        rules: [
            {
                test: /\.ts$/,
                loader: 'awesome-typescript-loader',
                exclude: [/node_modules/, /dist/, /assets/, /test/],
                options: {
                    configFileName: path.resolve(__dirname, 'tsconfig.electron.json')
                }
            }
        ]
    },
    plugins: [
        new NoEmitOnErrorsPlugin(),
        new ProgressPlugin(),
        new DefinePlugin({
            'process.env': {
                NODE_ENV: JSON.stringify(process.env.NODE_ENV)
            }
        })
    ],
    node: {
        __dirname: false,
        __filename: false
    },
    target: 'electron-main',
    externals: {
        nodegit: 'require("nodegit")',
        '@sentry/electron': 'require("@sentry/electron")',
    }
};

if (PROD) {
    config.plugins.push(new UglifyJsPlugin({
        uglifyOptions: { ecma: 6 }
    }));
}

module.exports = config;
<|endoftext|>


<commit_before>
LIB$json$parseJson = function(globals, rawText) {
    try {
        return LIB$json$convertJsonThing(globals, window.JSON.parse(rawText));
    } catch (e) {
        return null;
    }
};

LIB$json$convertJsonThing = function(globals, thing) {
    var type = LIB$Json$typeClassifyHelper(thing);
    switch (type) {
        case 'null': return buildNull(globals);
        case 'bool': return buildBoolean(globals, thing);
        case 'string': return buildString(globals, thing);
        case 'list':
            var list = [];
            for (i = 0; i < thing.length; ++i) {
                list.push(LIB$json$convertJsonThing(globals, thing[i]));
            }
            return buildList(list);
        case 'dict':
            var keys = [];
            var values = [];
            for (var rawKey in thing) {
                keys.push(rawKey);
                values.push(LIB$json$convertJsonThing(globals, thing[rawKey]));
            }
            return buildStringDictionary(globals, keys, values);
        case 'int':
            return buildInteger(globals, thing);
        case 'float':
            return buildFloat(globals, thing);
        default:
            return buildNull(globals);
    }
};

LIB$Json$typeClassifyHelper = function(t) {
    if (t === null) return 'null';
    if (t === true || t === false) return 'bool';
    if (typeof t == "string") return 'string';
    if (typeof t == "number") {
        if (t % 1 == 0) return 'int';
        return 'float';
    }
    ts = Object.prototype.toString.call(t);
    if (ts == '[object Array]') {
        return 'list';
    }
    if (ts == '[object Object]') {
        return 'dict';
    }
    return 'null';
};
<commit_msg>Add missing var declaration in JSON parser for JavaScript for variable 'i'. window.i was being used and the function was recursive. Hilarity ensued.<commit_after>
LIB$json$parseJson = function(globals, rawText) {
    try {
        return LIB$json$convertJsonThing(globals, window.JSON.parse(rawText));
    } catch (e) {
        return null;
    }
};

LIB$json$convertJsonThing = function(globals, thing) {
    var type = LIB$Json$typeClassifyHelper(thing);
    switch (type) {
        case 'null': return buildNull(globals);
        case 'bool': return buildBoolean(globals, thing);
        case 'string': return buildString(globals, thing);
        case 'list':
            var list = [];
            for (var i = 0; i < thing.length; ++i) {
                list.push(LIB$json$convertJsonThing(globals, thing[i]));
            }
            return buildList(list);
        case 'dict':
            var keys = [];
            var values = [];
            for (var rawKey in thing) {
                keys.push(rawKey);
                values.push(LIB$json$convertJsonThing(globals, thing[rawKey]));
            }
            return buildStringDictionary(globals, keys, values);
        case 'int':
            return buildInteger(globals, thing);
        case 'float':
            return buildFloat(globals, thing);
        default:
            return buildNull(globals);
    }
};

LIB$Json$typeClassifyHelper = function(t) {
    if (t === null) return 'null';
    if (t === true || t === false) return 'bool';
    if (typeof t == "string") return 'string';
    if (typeof t == "number") {
        if (t % 1 == 0) return 'int';
        return 'float';
    }
    ts = Object.prototype.toString.call(t);
    if (ts == '[object Array]') {
        return 'list';
    }
    if (ts == '[object Object]') {
        return 'dict';
    }
    return 'null';
};
<|endoftext|>


<commit_before>/**
 * "collection" page behavior
 *
 * @author Viacheslav Lotsmanov
 */

define(['jquery', 'styles_ready'],
function ($, stylesReady) {
stylesReady(function () {

var $html = $('html');
if (!$html.hasClass('collection_page')) return;
require(['get_val', 'get_local_text', 'relative_number'],
function (getVal, getLocalText, relativeNumber) {

	// values
	var bindSuffix = '.collection_page_bind';

	// dom elements
	var $main = $('main');
	var $footer = $('footer');
	var $list = $main.find('ul.collection_list');
	var $liArr;
	var $previews;
	var $infos;
	var $zooms;
	var $more = $main.find('.load_more');
	var $d = $(document);
	var $w = $(window);

	function initList() {
		$liArr = $list.find('>li');
		$previews = $liArr.find('.preview');
		$infos = $liArr.find('.info');
		$zooms = $liArr.find('.zoom');
	}
	initList();

	function liInitHandler() { // {{{1
		var $ul = $list;
		var $li = $(this);
		var $info = $li.find('.info');
		var $a = $li.find('a.preview');
		var $preview = $li.find('.preview');
		var $img = $preview.find('img');

		var imgSrc = $img.attr('src');

		// loadGray {{{2
		if ($ul.hasClass('products')) {
			function loadGray() {
				require(['grayscale_img', 'load_img'],
				function (grayscaleImg, loadImg) {
					grayscaleImg(imgSrc, function (err, dataURL) {
						if (err) {
							if (err instanceof loadImg.exceptions.Timeout) {
								setTimeout(loadGray, 1); // try again
							} else window.console.error(err);
							return;
						}

						var $newImg = $('', {
							'alt': '',
							'src': dataURL,
							'class': 'grayscale',
						});
						$preview.append( $newImg );
					});
				});
			}
			setTimeout(loadGray, 1);
		}
		// loadGray }}}2

		// loadBlur {{{2
		if ($ul.hasClass('brand')) {
			function loadBlur() {
				require(['blur_img', 'load_img'],
				function (blurImg, loadImg) {
					blurImg({
						src: imgSrc,
						radius: 10,
					}, function (err, dataURL) {
						if (err) {
							if (err instanceof loadImg.exceptions.Timeout) {
								setTimeout(loadBlur, 1); // try again
							} else window.console.error(err);
							return;
						}

						var $newImg = $('', {
							'alt': '',
							'src': dataURL,
							'class': 'blur',
						});
						$preview.append( $newImg );
					});
				});
			}
			setTimeout(loadBlur, 1);
		}
		// loadBlur }}}2

		if ($ul.hasClass('brand')) {
			$info
				.css('opacity', 0)
				.prepend('')
				.prepend('');

			function closeHandler() { // {{{2
				$info.animate({
					'opacity': 0,
				}, getVal('animationSpeed'), getVal('animationCurve'), function () {
					$(this).css('display', 'none');
					$ul.removeClass('popup');
					$li.removeClass('popup');
				});
				return false;
			} // closeHandler() }}}2

			$info.find('.closer').click(closeHandler);
			$info.find('.zoom').click(function () {
				alert('Поведение кнопки не определено.');
				return false;
			});

			$a.click(function () { // {{{2
				if ($ul.hasClass('popup')) {
					$ul.find('>li.popup .info .closer').trigger('click');
					return false;
				}

				$ul.addClass('popup');
				$li.addClass('popup');
				$info.css('display', 'block');
				$info.css('top', (
					$d.scrollTop() +
					($w.height() / 2) -
					($info.innerHeight() / 2)
				) + 'px');
				$info.stop().animate({
					'opacity': 1,
				}, getVal('animationSpeed'), getVal('animationCurve'));
				return false;
			}); // open popup }}}2
		} else if ($ul.hasClass('rings')) {
			$info.append('');
			$info.find('.zoom').click(function () {
				alert('Поведение кнопки не определено.');
				return false;
			});
		}

		initList();
	} // liInitHandler() }}}1

	$liArr.each(liInitHandler);

	if ($list.hasClass('brand')) {
		$d.on('click' + bindSuffix, function (event) { // {{{1
			var $infoOpened = $list.find('>li.popup .info');
			if ($infoOpened.size() <= 0) return true;

			var x = $infoOpened.offset().left;
			var y = $infoOpened.offset().top;
			var w = $infoOpened.innerWidth();
			var h = $infoOpened.innerHeight();

			// hell IE
			if (event.pageX < 0 || event.pageY < 0) return true;

			if (
				!(event.pageX >= x && event.pageX <= x+w) ||
				!(event.pageY >= y && event.pageY <= y+h)
			) {
				$infoOpened.find('.closer').trigger('click');
				return false;
			}

			return true;
		}); // $d.click }}}1
	}

	// relative size {{{1

		var relativeSizeBindSuffix = '.collection_page_relative_size_bind';
		var moreSizeMin = getVal('circleDownArrowButtonSizeMin');
		var moreSizeMax = getVal('circleDownArrowButtonSizeMax');
		var itemSizeMin = 208;
		var itemSizeMax = 342;
		var rMinW = getVal('minWidth');
		var rMaxW = getVal('maxWidth');
		var topMin = 75;
		var topMax = 130;

		if ($list.hasClass('rings')) {
			itemSizeMin = 170;
			itemSizeMax = 272;
			topMin = 50;
			topMax = 80;

			var ringItemSizeMin = 277;
			var ringItemSizeMax = 450;
			var zoomHeightMin = 49;
			var zoomHeightMax = 79;
		}

		var $relMore = $main.find('ul.collection_list + .load_more');

		function setRelSizes() { // {{{2
			var w = $footer.width();

			function rn(min, max) {
				return relativeNumber({
					relVal: w,
					relMin: rMinW,
					relMax: rMaxW,
					min: min,
					max: max,
				});
			} // rn()

			var size;
			var top = rn(topMin, topMax);

			size = rn(moreSizeMin, moreSizeMax);
			$more.css({
				width: size + 'px',
				height: size + 'px',
				'border-radius': (size / 2) + 'px',
			});

			size = rn(itemSizeMin, itemSizeMax);

			$liArr.css('margin-top', top + 'px');

			if ($list.hasClass('rings')) {
				var iSize = rn(ringItemSizeMin, ringItemSizeMax);
				$liArr.css('height', iSize + 'px');
				$infos.css('width', iSize + 'px');
				$infos.css('margin-left', (($liArr.eq(0).width() - iSize) / 2) + 'px');
				$zooms.css('height', rn(zoomHeightMin, zoomHeightMax) + 'px');
			} else if ($list.hasClass('brand')) {
				$liArr.css('height', size + 'px');
			}

			$previews.css({
				'width': size + 'px',
				'height': size + 'px',
			});
			$relMore.css('margin-top', top + 'px');
		} // setRelSizes() }}}2

		$w.on('resize' + relativeSizeBindSuffix, $.proxy(setTimeout, null, function () {
			// reset
			$more.css({
				width: '',
				height: '',
				'border-radius': '',
			});
			$liArr.css({
				'width': '',
				'height': '',
				'margin-top': '',
			});
			$previews.css({
				'width': '',
				'height': '',
			});
			$infos.css({
				'width': '',
				'height': '',
				'margin-left': '',
			});
			$zooms.css({
				'width': '',
				'height': '',
			});
			$relMore.css('margin-top', '');

			setRelSizes();
		}, 1));

		$w.trigger('resize' + relativeSizeBindSuffix);

	// relative size }}}1

	$more.on('click' + bindSuffix, function () { // {{{1
		if ($more.data('process')) return false;
		$more.data('process', true)
		$more.addClass('loading');

		setTimeout(function () {

			function stopping() {
				$more.removeClass('loading');
				setTimeout(function () {
					$more.removeData('process');
					$w.trigger('scroll' + bindSuffix);
				}, getVal('animationSpeed'));
			}

			var getData = {
				page: parseInt($more.attr("data-next-page"), 10),
				iblock: $more.attr('data-iblock'),
			};

			if ($more.attr('data-count'))
				getData.count = parseInt($more.attr('data-count'), 10);

			$.ajax({ // {{{2
				url: getVal('dynamicItemsLoadURL'),
				type: 'GET',
				cache: false,
				dataType: 'text',
				data: getData,
				success: function (data) {
					require(['json_answer'], function (jsonAnswer) {
						jsonAnswer.validate(data, function (err, json) {
							$more.attr("data-next-page", ++(getData.page));

							if (err) {
								if (
									err instanceof jsonAnswer.exceptions.UnknownStatusValue &&
									err.json && err.json.status === 'end_of_list'
								) {
									$list.addClass('end_of_list');
									$more.slideUp(getVal('animationSpeed') * 6, function () {
										$more.remove();
									});
									if (!err.json.items) return;
									else json = err.json;
								} else {
									alert(getLocalText('ERR', 'AJAX') + '\n\n' + err.toString());
									return stopping();
								}
							}

							if (!$.isArray(json.items)) {
								alert(getLocalText('ERR', 'AJAX_PARSE'));
								return stopping();
							}

							var items = json.items;
							var i = 0;

							var loopEnd = stopping;

							function loadItemLoop() { // {{{3
								if (items.length <= i) return loopEnd();

								var item = items[i++];
								var imgTag;

								var $newLi = $('
');
								if (item.id) $newLi.attr('id', item.id);

								// preview {{{4

								if (
									!$.isPlainObject( item.preview ) ||
									$.type(item.preview.src) !== 'string'
								) {
									alert(getLocalText('ERR', 'AJAX_PARSE'));
									return stopping();
								}

								var $preview;
								if (item.info) $preview = $('');
								else $preview = $('');
								$preview.addClass('preview');

								imgTag = '';

								$preview.html( imgTag );
								$newLi.append( $preview );

								// preview }}}4

								// info {{{4
								var $info = '';
								if (item.info) {
									$info = $('
');

									if ($list.hasClass('brand')) {
										if (
											$.type(item.info.text) !== 'string' ||
											!$.isPlainObject(item.info.picture) ||
											$.type(item.info.picture.src) !== 'string'
										) {
											alert(getLocalText('ERR', 'AJAX_PARSE'));
											return stopping();
										}

										var $text = $('
');
										$text.html(item.info.text);
										$info.append( $text );

										imgTag = '';

										$info.append(imgTag);
									} else if ($list.hasClass('rings')) {
										if ($.type(item.info.text) === 'string') {
											var $text = $('
');
											$text.html(item.info.text);
											$info.append( $text );
										}
									}

									$newLi.append( $info );
								}
								// info }}}4

								$newLi.css('opacity', 0);
								$newLi.each(liInitHandler);
								$liArr.last().after( $newLi );
								initList();
								setRelSizes();

								setTimeout(function () {
									var $el = $liArr.last();
									$el.animate(
										{ opacity: 1 },
										getVal('animationSpeed'),
										getVal('animationCurve'),
										loadItemLoop
									);
								}, 1);
							} // loadItemLoop() }}}3

							loadItemLoop();
						}); // jsonAnswer.validate()
					}); // require(['json_answer']...
				}, // "success"
				error: function () {
					alert(getLocalText('ERR', 'AJAX'));
					stopping();
				}
			}); // .ajax() }}}2

		}, getVal('animationSpeed')); // setTimeout()

		return false;
	}); // $more.click }}}1

	$w.on('scroll' + bindSuffix, function () {
		if ($d.scrollTop() + $w.height() >= $more.offset().top) {
			$more.trigger('click' + bindSuffix);
		}
	});

}); // require() for page passed

}); // stylesReady()
}); // define()
<commit_msg>removed unused loadGray function<commit_after>/**
 * "collection" page behavior
 *
 * @author Viacheslav Lotsmanov
 */

define(['jquery', 'styles_ready'],
function ($, stylesReady) {
stylesReady(function () {

var $html = $('html');
if (!$html.hasClass('collection_page')) return;
require(['get_val', 'get_local_text', 'relative_number'],
function (getVal, getLocalText, relativeNumber) {

	// values
	var bindSuffix = '.collection_page_bind';

	// dom elements
	var $main = $('main');
	var $footer = $('footer');
	var $list = $main.find('ul.collection_list');
	var $liArr;
	var $previews;
	var $infos;
	var $zooms;
	var $more = $main.find('.load_more');
	var $d = $(document);
	var $w = $(window);

	function initList() {
		$liArr = $list.find('>li');
		$previews = $liArr.find('.preview');
		$infos = $liArr.find('.info');
		$zooms = $liArr.find('.zoom');
	}
	initList();

	function liInitHandler() { // {{{1
		var $ul = $list;
		var $li = $(this);
		var $info = $li.find('.info');
		var $a = $li.find('a.preview');
		var $preview = $li.find('.preview');
		var $img = $preview.find('img');

		var imgSrc = $img.attr('src');

		// loadBlur {{{2
		if ($ul.hasClass('brand')) {
			function loadBlur() {
				require(['blur_img', 'load_img'],
				function (blurImg, loadImg) {
					blurImg({
						src: imgSrc,
						radius: 10,
					}, function (err, dataURL) {
						if (err) {
							if (err instanceof loadImg.exceptions.Timeout) {
								setTimeout(loadBlur, 1); // try again
							} else window.console.error(err);
							return;
						}

						var $newImg = $('', {
							'alt': '',
							'src': dataURL,
							'class': 'blur',
						});
						$preview.append( $newImg );
					});
				});
			}
			setTimeout(loadBlur, 1);
		}
		// loadBlur }}}2

		if ($ul.hasClass('brand')) {
			$info
				.css('opacity', 0)
				.prepend('')
				.prepend('');

			function closeHandler() { // {{{2
				$info.animate({
					'opacity': 0,
				}, getVal('animationSpeed'), getVal('animationCurve'), function () {
					$(this).css('display', 'none');
					$ul.removeClass('popup');
					$li.removeClass('popup');
				});
				return false;
			} // closeHandler() }}}2

			$info.find('.closer').click(closeHandler);
			$info.find('.zoom').click(function () {
				alert('Поведение кнопки не определено.');
				return false;
			});

			$a.click(function () { // {{{2
				if ($ul.hasClass('popup')) {
					$ul.find('>li.popup .info .closer').trigger('click');
					return false;
				}

				$ul.addClass('popup');
				$li.addClass('popup');
				$info.css('display', 'block');
				$info.css('top', (
					$d.scrollTop() +
					($w.height() / 2) -
					($info.innerHeight() / 2)
				) + 'px');
				$info.stop().animate({
					'opacity': 1,
				}, getVal('animationSpeed'), getVal('animationCurve'));
				return false;
			}); // open popup }}}2
		} else if ($ul.hasClass('rings')) {
			$info.append('');
			$info.find('.zoom').click(function () {
				alert('Поведение кнопки не определено.');
				return false;
			});
		}

		initList();
	} // liInitHandler() }}}1

	$liArr.each(liInitHandler);

	if ($list.hasClass('brand')) {
		$d.on('click' + bindSuffix, function (event) { // {{{1
			var $infoOpened = $list.find('>li.popup .info');
			if ($infoOpened.size() <= 0) return true;

			var x = $infoOpened.offset().left;
			var y = $infoOpened.offset().top;
			var w = $infoOpened.innerWidth();
			var h = $infoOpened.innerHeight();

			// hell IE
			if (event.pageX < 0 || event.pageY < 0) return true;

			if (
				!(event.pageX >= x && event.pageX <= x+w) ||
				!(event.pageY >= y && event.pageY <= y+h)
			) {
				$infoOpened.find('.closer').trigger('click');
				return false;
			}

			return true;
		}); // $d.click }}}1
	}

	// relative size {{{1

		var relativeSizeBindSuffix = '.collection_page_relative_size_bind';
		var moreSizeMin = getVal('circleDownArrowButtonSizeMin');
		var moreSizeMax = getVal('circleDownArrowButtonSizeMax');
		var itemSizeMin = 208;
		var itemSizeMax = 342;
		var rMinW = getVal('minWidth');
		var rMaxW = getVal('maxWidth');
		var topMin = 75;
		var topMax = 130;

		if ($list.hasClass('rings')) {
			itemSizeMin = 170;
			itemSizeMax = 272;
			topMin = 50;
			topMax = 80;

			var ringItemSizeMin = 277;
			var ringItemSizeMax = 450;
			var zoomHeightMin = 49;
			var zoomHeightMax = 79;
		}

		var $relMore = $main.find('ul.collection_list + .load_more');

		function setRelSizes() { // {{{2
			var w = $footer.width();

			function rn(min, max) {
				return relativeNumber({
					relVal: w,
					relMin: rMinW,
					relMax: rMaxW,
					min: min,
					max: max,
				});
			} // rn()

			var size;
			var top = rn(topMin, topMax);

			size = rn(moreSizeMin, moreSizeMax);
			$more.css({
				width: size + 'px',
				height: size + 'px',
				'border-radius': (size / 2) + 'px',
			});

			size = rn(itemSizeMin, itemSizeMax);

			$liArr.css('margin-top', top + 'px');

			if ($list.hasClass('rings')) {
				var iSize = rn(ringItemSizeMin, ringItemSizeMax);
				$liArr.css('height', iSize + 'px');
				$infos.css('width', iSize + 'px');
				$infos.css('margin-left', (($liArr.eq(0).width() - iSize) / 2) + 'px');
				$zooms.css('height', rn(zoomHeightMin, zoomHeightMax) + 'px');
			} else if ($list.hasClass('brand')) {
				$liArr.css('height', size + 'px');
			}

			$previews.css({
				'width': size + 'px',
				'height': size + 'px',
			});
			$relMore.css('margin-top', top + 'px');
		} // setRelSizes() }}}2

		$w.on('resize' + relativeSizeBindSuffix, $.proxy(setTimeout, null, function () {
			// reset
			$more.css({
				width: '',
				height: '',
				'border-radius': '',
			});
			$liArr.css({
				'width': '',
				'height': '',
				'margin-top': '',
			});
			$previews.css({
				'width': '',
				'height': '',
			});
			$infos.css({
				'width': '',
				'height': '',
				'margin-left': '',
			});
			$zooms.css({
				'width': '',
				'height': '',
			});
			$relMore.css('margin-top', '');

			setRelSizes();
		}, 1));

		$w.trigger('resize' + relativeSizeBindSuffix);

	// relative size }}}1

	$more.on('click' + bindSuffix, function () { // {{{1
		if ($more.data('process')) return false;
		$more.data('process', true)
		$more.addClass('loading');

		setTimeout(function () {

			function stopping() {
				$more.removeClass('loading');
				setTimeout(function () {
					$more.removeData('process');
					$w.trigger('scroll' + bindSuffix);
				}, getVal('animationSpeed'));
			}

			var getData = {
				page: parseInt($more.attr("data-next-page"), 10),
				iblock: $more.attr('data-iblock'),
			};

			if ($more.attr('data-count'))
				getData.count = parseInt($more.attr('data-count'), 10);

			$.ajax({ // {{{2
				url: getVal('dynamicItemsLoadURL'),
				type: 'GET',
				cache: false,
				dataType: 'text',
				data: getData,
				success: function (data) {
					require(['json_answer'], function (jsonAnswer) {
						jsonAnswer.validate(data, function (err, json) {
							$more.attr("data-next-page", ++(getData.page));

							if (err) {
								if (
									err instanceof jsonAnswer.exceptions.UnknownStatusValue &&
									err.json && err.json.status === 'end_of_list'
								) {
									$list.addClass('end_of_list');
									$more.slideUp(getVal('animationSpeed') * 6, function () {
										$more.remove();
									});
									if (!err.json.items) return;
									else json = err.json;
								} else {
									alert(getLocalText('ERR', 'AJAX') + '\n\n' + err.toString());
									return stopping();
								}
							}

							if (!$.isArray(json.items)) {
								alert(getLocalText('ERR', 'AJAX_PARSE'));
								return stopping();
							}

							var items = json.items;
							var i = 0;

							var loopEnd = stopping;

							function loadItemLoop() { // {{{3
								if (items.length <= i) return loopEnd();

								var item = items[i++];
								var imgTag;

								var $newLi = $('
');
								if (item.id) $newLi.attr('id', item.id);

								// preview {{{4

								if (
									!$.isPlainObject( item.preview ) ||
									$.type(item.preview.src) !== 'string'
								) {
									alert(getLocalText('ERR', 'AJAX_PARSE'));
									return stopping();
								}

								var $preview;
								if (item.info) $preview = $('');
								else $preview = $('');
								$preview.addClass('preview');

								imgTag = '';

								$preview.html( imgTag );
								$newLi.append( $preview );

								// preview }}}4

								// info {{{4
								var $info = '';
								if (item.info) {
									$info = $('
');

									if ($list.hasClass('brand')) {
										if (
											$.type(item.info.text) !== 'string' ||
											!$.isPlainObject(item.info.picture) ||
											$.type(item.info.picture.src) !== 'string'
										) {
											alert(getLocalText('ERR', 'AJAX_PARSE'));
											return stopping();
										}

										var $text = $('
');
										$text.html(item.info.text);
										$info.append( $text );

										imgTag = '';

										$info.append(imgTag);
									} else if ($list.hasClass('rings')) {
										if ($.type(item.info.text) === 'string') {
											var $text = $('
');
											$text.html(item.info.text);
											$info.append( $text );
										}
									}

									$newLi.append( $info );
								}
								// info }}}4

								$newLi.css('opacity', 0);
								$newLi.each(liInitHandler);
								$liArr.last().after( $newLi );
								initList();
								setRelSizes();

								setTimeout(function () {
									var $el = $liArr.last();
									$el.animate(
										{ opacity: 1 },
										getVal('animationSpeed'),
										getVal('animationCurve'),
										loadItemLoop
									);
								}, 1);
							} // loadItemLoop() }}}3

							loadItemLoop();
						}); // jsonAnswer.validate()
					}); // require(['json_answer']...
				}, // "success"
				error: function () {
					alert(getLocalText('ERR', 'AJAX'));
					stopping();
				}
			}); // .ajax() }}}2

		}, getVal('animationSpeed')); // setTimeout()

		return false;
	}); // $more.click }}}1

	$w.on('scroll' + bindSuffix, function () {
		if ($d.scrollTop() + $w.height() >= $more.offset().top) {
			$more.trigger('click' + bindSuffix);
		}
	});

}); // require() for page passed

}); // stylesReady()
}); // define()
<|endoftext|>


<commit_before>define([
	'dojo/topic',
	'dojo/_base/array',
	'dojo/dom-geometry',
	'dojo/_base/connect',
	'dijit/registry',
	'esri/map',
	'esri/layers/CSVLayer',
	'esri/layers/FeatureLayer',
	'esri/layers/ArcGISTiledMapServiceLayer',
	'esri/Color',
	'esri/symbols/SimpleMarkerSymbol',
	'esri/renderers/UniqueValueRenderer',
	'lib-app/jquery',
	'lib-app/jquery.mousewheel',
	'lib-build/css!./css/styles.css'
	],
	function(
		topic,
		array,
		domGeom,
		connect,
		registry,
		Map,
		CSVLayer,
		FeatureLayer,
		ArcGISTiledMapServiceLayer,
		Color,
		SimpleMarkerSymbol,
		UniqueValueRenderer
		){

	// The application is ready
	topic.subscribe("tpl-ready", function(){

		//Hide splash page on scroll/button click
		var showApp = function () {
			$(".splash").slideUp("800", function() {
				$(".content-wrapper").delay(100).animate({"opacity":"1.0"},800);
			});
		};

		//Trigger slide animation
		$(".splash-arrow").on('click',showApp);
		$('.splash').on('mousewheel',showApp);

		//Toggle index map when overview button is clicked
		$("#bt").click(function() {
			$(".sliding-panel").toggleClass("panel-active");
			console.log("Sliding panel clicked");
		});

		/* BASEMAP TOGGLE */
		basemapSwitcher();

		/*  OVERVIEW MAP IN SIDEBAR  */

		//Map CSV fields to JS variables;
		var LabelField = 'Label';
		var StoryIndexField = 'StoryIndex';
		var ActiveField = 'Active';

		// Set map marker colors
		var defaultMarkerColor = new Color([100,100,100, 1]);
		var activeMarkerColor = new Color([0,94,184, 1]);

		// Path to CSV file
		var csvPath = 'resources/index-map/index-map-layer.csv';

		// Variable to store selected graphic
		var selectedGraphic = false;

		// Remove the help text tooltip after the user first clicks on the map (not currently used)
		$('#index-map').click(function(){
			$('#index-map-helper').removeClass('active');
		});

		// Create default map extent and spatial reference
		var startExtent = new esri.geometry.Extent(400000, -2000000, 8000000, 6000000,
			new esri.SpatialReference(102100) );

		// Create the index map with minimal UI;
		var indexMap = new Map('index-map',{
			slider: false,
			logo: false,
			showAttribution: false,
			extent: startExtent,
			fitExtent: true
		});

		//Disable all map controls
		indexMap.on("load", function(){
			console.log("Map loaded");
			indexMap.disableMapNavigation();
			indexMap.disableKeyboardNavigation();
			indexMap.disablePan();
			indexMap.disableRubberBandZoom();
			indexMap.disableScrollWheelZoom();

			// Variables used for responsive map
			var resizeTimer;
			var height = $("#index-map").height();

			// Redraw map if container width changes; don't redraw when height changes
			indexMap.on("resize", function(){

				if (height == $("#index-map").height()) {
					console.log("Map width has changed; redrawing map");

					clearTimeout(resizeTimer);
					resizeTimer = setTimeout(function() {
						indexMap.setExtent(startExtent,true);
						indexMap.reposition();
					}, 500);
				}
				else {
					console.log("Map width has not changed; not redrawing map");
				}
			});
		});

		//Create country layer from Feature Service
		var countriesLayer = new FeatureLayer("http://services.arcgis.com/nzS0F0zdNLvs7nc8/arcgis/rest/services/CountriesGeneralized/FeatureServer/0");

		// Load CSV File as point later
		var indexMapLayer = new CSVLayer(csvPath);

		// Create simple point symbols
		var activeMarker =  new SimpleMarkerSymbol('solid', 12, null, activeMarkerColor);
		var defaultMarker = new SimpleMarkerSymbol('solid', 9, null, defaultMarkerColor);

		// Change the CSV Layer renderer to use the symbols we just created
		var renderer = new UniqueValueRenderer(defaultMarker,ActiveField);
		renderer.addValue('TRUE', activeMarker);
		indexMapLayer.setRenderer(renderer);

		// Add countries layer to map
		indexMap.addLayer(countriesLayer,0);

		// Add CSV layer to map
		indexMap.addLayer(indexMapLayer,1);

		// Select current section in index map on Loading
		setIconDisplay(app.data.getCurrentSectionIndex());

		// Add map events
		indexMapLayer.on('click',function(event){
			$('#index-map-helper').removeClass('active');
			hideIndexMapInfo();
			topic.publish('story-navigate-section', event.graphic.attributes[StoryIndexField]);
		});

		indexMapLayer.on('mouse-over',function(event){
			indexMap.setCursor('pointer');
			setIndexMapInfo(event.graphic);
		});

		indexMapLayer.on('mouse-out',function(){
			indexMap.setCursor('default');
			hideIndexMapInfo();
		});

		indexMap.on('extent-change',function(){
			indexMap.setCursor('default');
			hideIndexMapInfo();
			moveSelectedToFront();
		});

		topic.subscribe('story-load-section', setIconDisplay);

		// Select current section in index map (Update symbol color)
		function setIconDisplay(index){
			selectedGraphic = false;
			if (index !== null){
				array.forEach(indexMapLayer.graphics,function(g){
					if (g.attributes[StoryIndexField].toString() === index.toString()){
						g.attributes[ActiveField] = 'TRUE';
						if(g.getDojoShape()){
							selectedGraphic = g;
							g.getDojoShape().moveToFront();
						}
					}
					else{
						g.attributes[ActiveField] = 'FALSE';
					}
				});
				indexMapLayer.redraw();
			}
		}

		// Make sure selected point is on top.
		function moveSelectedToFront(){
			if (selectedGraphic && selectedGraphic.getDojoShape()) {
				selectedGraphic.getDojoShape().moveToFront();
				console.log("Moved item to front,")
			}
		}

		// Hide point tooltip
		function hideIndexMapInfo(){
			$('#index-map-info').hide();
		}

		// Show point tooltip
		function setIndexMapInfo(graphic){
			$('#index-map-info').html(graphic.attributes[LabelField]);
			if (graphic.getDojoShape()){
				graphic.getDojoShape().moveToFront();
			}
			positionIndexMapInfo(graphic);
		}

		// Move tooltip next to selected point
		function positionIndexMapInfo(graphic){
			var pos = domGeom.position(graphic.getNode());
			$('#index-map-info').css({
				'top': pos.y - (pos.h/2) - 3,
				'left': pos.x + pos.w
			}).show();
		}
	});

	/* Click handler for map symbols */

    var WEBMAP_ID = "0df1997ac587470f9e3713a15c532cb9",
        LAYER_ID = "UNHCR_PoC_2016_8102";

    var clickHandlerIsSetup = false;

    topic.subscribe("story-loaded-map", function(result){

    	/* Add thousands separator to attributes */
    	function numberWithCommas(x) {
    		return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
		}

        if ( result.id == WEBMAP_ID && ! clickHandlerIsSetup ) {
            var map = app.maps[result.id].response.map,
                layer = map.getLayer(LAYER_ID);

            if ( layer ) {
                layer.on("mouse-over", function(e){
                    map.setMapCursor("pointer");
                    map.infoWindow.setContent(
                    	"
"+e.graphic.attributes["Rank"]+". "+e.graphic.attributes["name"]+" ("+e.graphic.attributes["Country"]+")"+"

"+
						"
People of concern | "+numberWithCommas(e.graphic.attributes["PoCTotal"])+"
"+
						"
Year of establishment | "+e.graphic.attributes["EstabDate"]+"
"
                    	);
                    map.infoWindow.show(e.graphic.geometry);
                });

                layer.on("mouse-out", function(e){
                    map.setMapCursor("default");
                    map.infoWindow.hide();
                });

                layer.on("click", function(e){
                    var index = e.graphic.attributes["story_index_10"];
                    topic.publish("story-navigate-section", index);
                });
            }

            clickHandlerIsSetup = true;
        }
    });

	function basemapSwitcher(){

		/* BASEMAP TOGGLE */
		var activeBasemap = 'streets';
		$("#switcher-button").text("view satellite basemap");

		$("#switcher-button").click(function () {
			var satelliteBasemap = app.map.getLayer(app.map.layerIds[3]);
			var satelliteReference = app.map.getLayer(app.map.layerIds[4]);
			if (activeBasemap == 'streets'){
				satelliteBasemap.setVisibility(true);
				satelliteReference.setVisibility(true);
				activeBasemap = 'satellite';
				$("#switcher-button").text('view streets basemap');
			} else {
				//// Your aerial Layer
				/*var newbase = new VETiledLayer({
					bingMapsKey: "-Your Bing Key-",
					mapStyle: VETiledLayer.MAP_STYLE_AERIAL_WITH_LABELS
				}); //BING AERIAL */
				activeBasemap = 'streets';
				$("#switcher-button").text('view satellite basemap');
				satelliteBasemap.setVisibility(false);
				satelliteReference.setVisibility(false);
			}
		});
	};
});

<commit_msg>Corrected layer IDs<commit_after>define([
	'dojo/topic',
	'dojo/_base/array',
	'dojo/dom-geometry',
	'dojo/_base/connect',
	'dijit/registry',
	'esri/map',
	'esri/layers/CSVLayer',
	'esri/layers/FeatureLayer',
	'esri/layers/ArcGISTiledMapServiceLayer',
	'esri/Color',
	'esri/symbols/SimpleMarkerSymbol',
	'esri/renderers/UniqueValueRenderer',
	'lib-app/jquery',
	'lib-app/jquery.mousewheel',
	'lib-build/css!./css/styles.css'
	],
	function(
		topic,
		array,
		domGeom,
		connect,
		registry,
		Map,
		CSVLayer,
		FeatureLayer,
		ArcGISTiledMapServiceLayer,
		Color,
		SimpleMarkerSymbol,
		UniqueValueRenderer
		){

	// The application is ready
	topic.subscribe("tpl-ready", function(){

		//Hide splash page on scroll/button click
		var showApp = function () {
			$(".splash").slideUp("800", function() {
				$(".content-wrapper").delay(100).animate({"opacity":"1.0"},800);
			});
		};

		//Trigger slide animation
		$(".splash-arrow").on('click',showApp);
		$('.splash').on('mousewheel',showApp);

		//Toggle index map when overview button is clicked
		$("#bt").click(function() {
			$(".sliding-panel").toggleClass("panel-active");
			console.log("Sliding panel clicked");
		});

		/* BASEMAP TOGGLE */
		basemapSwitcher();

		/*  OVERVIEW MAP IN SIDEBAR  */

		//Map CSV fields to JS variables;
		var LabelField = 'Label';
		var StoryIndexField = 'StoryIndex';
		var ActiveField = 'Active';

		// Set map marker colors
		var defaultMarkerColor = new Color([100,100,100, 1]);
		var activeMarkerColor = new Color([0,94,184, 1]);

		// Path to CSV file
		var csvPath = 'resources/index-map/index-map-layer.csv';

		// Variable to store selected graphic
		var selectedGraphic = false;

		// Remove the help text tooltip after the user first clicks on the map (not currently used)
		$('#index-map').click(function(){
			$('#index-map-helper').removeClass('active');
		});

		// Create default map extent and spatial reference
		var startExtent = new esri.geometry.Extent(400000, -2000000, 8000000, 6000000,
			new esri.SpatialReference(102100) );

		// Create the index map with minimal UI;
		var indexMap = new Map('index-map',{
			slider: false,
			logo: false,
			showAttribution: false,
			extent: startExtent,
			fitExtent: true
		});

		//Disable all map controls
		indexMap.on("load", function(){
			console.log("Map loaded");
			indexMap.disableMapNavigation();
			indexMap.disableKeyboardNavigation();
			indexMap.disablePan();
			indexMap.disableRubberBandZoom();
			indexMap.disableScrollWheelZoom();

			// Variables used for responsive map
			var resizeTimer;
			var height = $("#index-map").height();

			// Redraw map if container width changes; don't redraw when height changes
			indexMap.on("resize", function(){

				if (height == $("#index-map").height()) {
					console.log("Map width has changed; redrawing map");

					clearTimeout(resizeTimer);
					resizeTimer = setTimeout(function() {
						indexMap.setExtent(startExtent,true);
						indexMap.reposition();
					}, 500);
				}
				else {
					console.log("Map width has not changed; not redrawing map");
				}
			});
		});

		//Create country layer from Feature Service
		var countriesLayer = new FeatureLayer("http://services.arcgis.com/nzS0F0zdNLvs7nc8/arcgis/rest/services/CountriesGeneralized/FeatureServer/0");

		// Load CSV File as point later
		var indexMapLayer = new CSVLayer(csvPath);

		// Create simple point symbols
		var activeMarker =  new SimpleMarkerSymbol('solid', 12, null, activeMarkerColor);
		var defaultMarker = new SimpleMarkerSymbol('solid', 9, null, defaultMarkerColor);

		// Change the CSV Layer renderer to use the symbols we just created
		var renderer = new UniqueValueRenderer(defaultMarker,ActiveField);
		renderer.addValue('TRUE', activeMarker);
		indexMapLayer.setRenderer(renderer);

		// Add countries layer to map
		indexMap.addLayer(countriesLayer,0);

		// Add CSV layer to map
		indexMap.addLayer(indexMapLayer,1);

		// Select current section in index map on Loading
		setIconDisplay(app.data.getCurrentSectionIndex());

		// Add map events
		indexMapLayer.on('click',function(event){
			$('#index-map-helper').removeClass('active');
			hideIndexMapInfo();
			topic.publish('story-navigate-section', event.graphic.attributes[StoryIndexField]);
		});

		indexMapLayer.on('mouse-over',function(event){
			indexMap.setCursor('pointer');
			setIndexMapInfo(event.graphic);
		});

		indexMapLayer.on('mouse-out',function(){
			indexMap.setCursor('default');
			hideIndexMapInfo();
		});

		indexMap.on('extent-change',function(){
			indexMap.setCursor('default');
			hideIndexMapInfo();
			moveSelectedToFront();
		});

		topic.subscribe('story-load-section', setIconDisplay);

		// Select current section in index map (Update symbol color)
		function setIconDisplay(index){
			selectedGraphic = false;
			if (index !== null){
				array.forEach(indexMapLayer.graphics,function(g){
					if (g.attributes[StoryIndexField].toString() === index.toString()){
						g.attributes[ActiveField] = 'TRUE';
						if(g.getDojoShape()){
							selectedGraphic = g;
							g.getDojoShape().moveToFront();
						}
					}
					else{
						g.attributes[ActiveField] = 'FALSE';
					}
				});
				indexMapLayer.redraw();
			}
		}

		// Make sure selected point is on top.
		function moveSelectedToFront(){
			if (selectedGraphic && selectedGraphic.getDojoShape()) {
				selectedGraphic.getDojoShape().moveToFront();
				console.log("Moved item to front,")
			}
		}

		// Hide point tooltip
		function hideIndexMapInfo(){
			$('#index-map-info').hide();
		}

		// Show point tooltip
		function setIndexMapInfo(graphic){
			$('#index-map-info').html(graphic.attributes[LabelField]);
			if (graphic.getDojoShape()){
				graphic.getDojoShape().moveToFront();
			}
			positionIndexMapInfo(graphic);
		}

		// Move tooltip next to selected point
		function positionIndexMapInfo(graphic){
			var pos = domGeom.position(graphic.getNode());
			$('#index-map-info').css({
				'top': pos.y - (pos.h/2) - 3,
				'left': pos.x + pos.w
			}).show();
		}
	});

	/* Click handler for map symbols */

    var WEBMAP_ID = "0df1997ac587470f9e3713a15c532cb9",
        LAYER_ID = "UNHCR_PoC_2016_8102";

    var clickHandlerIsSetup = false;

    topic.subscribe("story-loaded-map", function(result){

    	/* Add thousands separator to attributes */
    	function numberWithCommas(x) {
    		return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
		}

        if ( result.id == WEBMAP_ID && ! clickHandlerIsSetup ) {
            var map = app.maps[result.id].response.map,
                layer = map.getLayer(LAYER_ID);

            if ( layer ) {
                layer.on("mouse-over", function(e){
                    map.setMapCursor("pointer");
                    map.infoWindow.setContent(
                    	"
"+e.graphic.attributes["Rank"]+". "+e.graphic.attributes["name"]+" ("+e.graphic.attributes["Country"]+")"+"

"+
						"
People of concern | "+numberWithCommas(e.graphic.attributes["PoCTotal"])+"
"+
						"
Year of establishment | "+e.graphic.attributes["EstabDate"]+"
"
                    	);
                    map.infoWindow.show(e.graphic.geometry);
                });

                layer.on("mouse-out", function(e){
                    map.setMapCursor("default");
                    map.infoWindow.hide();
                });

                layer.on("click", function(e){
                    var index = e.graphic.attributes["story_index_10"];
                    topic.publish("story-navigate-section", index);
                });
            }

            clickHandlerIsSetup = true;
        }
    });

	function basemapSwitcher(){

		/* BASEMAP TOGGLE */
		var activeBasemap = 'streets';
		$("#switcher-button").text("view satellite basemap");

		$("#switcher-button").click(function () {
			var satelliteBasemap = app.map.getLayer(app.map.layerIds[2]);
			var satelliteReference = app.map.getLayer(app.map.layerIds[3]);
			if (activeBasemap == 'streets'){
				satelliteBasemap.setVisibility(true);
				satelliteReference.setVisibility(true);
				activeBasemap = 'satellite';
				$("#switcher-button").text('view streets basemap');
			} else {
				//// Your aerial Layer
				/*var newbase = new VETiledLayer({
					bingMapsKey: "-Your Bing Key-",
					mapStyle: VETiledLayer.MAP_STYLE_AERIAL_WITH_LABELS
				}); //BING AERIAL */
				activeBasemap = 'streets';
				$("#switcher-button").text('view satellite basemap');
				satelliteBasemap.setVisibility(false);
				satelliteReference.setVisibility(false);
			}
		});
	};
});

<|endoftext|>