<commit_before>function file_list_sort(name, elem)
{
  var td = $(elem), reverse = ui.env.sort_reverse;

  if (ui.env.sort_col == name)
    reverse = !reverse;
  else
    reverse = 0;

  $('td', td.parent()).removeClass('sorted reverse');
  td.addClass('sorted').removeClass('reverse');

  if (reverse)
    td.addClass('reverse');

  ui.file_list_sort(name, reverse);
};

function hack_file_input(id)
{
  var link = $('#'+id),
    file = $('<input>'),
    offset = link.offset();

  file.attr({name: 'file[]', type: 'file', multiple: 'multiple', size: 5})
    .change(function() { ui.file_upload(); })
    // opacity:0 does the trick, display/visibility doesn't work
    .css({opacity: 0, cursor: 'pointer', position: 'relative', outline: 'none', top: '10000px', left: '10000px'});

  // In FF and IE we need to move the browser file-input's button under the cursor
  // Thanks to the size attribute above we know the length of the input field
  if (navigator.userAgent.match(/Firefox|MSIE/))
    file.css({marginLeft: '-80px'});

  // Note: now, I observe problem with cursor style on FF < 4 only
  link.css({overflow: 'hidden', cursor: 'pointer'})
    // place button under the cursor
    .mousemove(function(e) {
      if (ui.commands['file.upload'])
        file.css({top: (e.pageY - offset.top - 10) + 'px', left: (e.pageX - offset.left - 10) + 'px'});
      // move the input away if button is disabled
      else
        $(this).mouseleave();
    })
    .mouseleave(function() { file.css({top: '10000px', left: '10000px'}); })
    .append(file);
};

function progress_update(data)
{
  var txt = ui.t('file.progress'), id = 'progress' + data.id,
    table = $('#' + id), content = $('#info' + id),
    i, row, offset, rows = [];

  if (!data || data.done) {
    if (table.length) {
      table.remove();
      content.remove();
    }
    return;
  }

  if (!table.length) {
    table = $('

');
    content = $('

');

    table.appendTo($('#actionbar'))
      .on('mouseleave', function() { content.hide(); })
      .on('mouseenter', function() { if (content.children().length) content.show(); });

    offset = table.offset();
    content.css({display: 'none', position: 'absolute', top: offset.top + 8, left: offset.left})
      .appendTo(document.body);
  }

  $('td.bar', table).width((data.percent || 1) + '%');

  if (data.total) {
    rows[ui.t('upload.size')] = ui.file_size(data.total);
    rows[ui.t('upload.progress')] = (data.percent || 0) + '%';
    if (data.rate)
      rows[ui.t('upload.rate')] = ui.file_size(data.rate) + '/s';
    if (data.eta)
      rows[ui.t('upload.eta')] = ui.time_format(data.eta);

    content.empty();

    for (i in rows)
      $('
').append($('').text(i))
        .append($('').text(rows[i]))
        .appendTo(content);
  }
};

function enable_command_handler(p)
{
  if (p.command == 'file.save') {
    $('#'+ui.buttons['file.edit']).css('display', p.status ? 'none' : 'block');
    $('#'+ui.buttons['file.save']).css('display', p.status ? 'block' : 'none');
  }
};

$(window).load(function() {
  hack_file_input('file-upload-button');
  $('#forms > form').hide();
  ui.add_event_listener('enable-command', enable_command_handler);
});

// register buttons
ui.buttons({
'folder.create': 'folder-create-button',
'folder.edit': 'folder-edit-button',
'folder.delete': 'folder-delete-button',
'file.upload': 'file-upload-button',
'file.search': 'file-search-button',
'file.delete': 'file-delete-button',
'file.download': 'file-download-button',
'file.edit': 'file-edit-button',
'file.copy': 'file-copy-button',
'file.move': 'file-move-button',
'file.save': 'file-save-button'
});
<commit_msg>Improvements for smart upload button<commit_after>function file_list_sort(name, elem)
{
  var td = $(elem), reverse = ui.env.sort_reverse;

  if (ui.env.sort_col == name)
    reverse = !reverse;
  else
    reverse = 0;

  $('td', td.parent()).removeClass('sorted reverse');
  td.addClass('sorted').removeClass('reverse');

  if (reverse)
    td.addClass('reverse');

  ui.file_list_sort(name, reverse);
};

function hack_file_input(id)
{
  var link = $('#'+id),
    file = $('<input>'),
    offset = link.offset();

  function move_file_input(e) {
    file.css({top: (e.pageY - offset.top - 10) + 'px', left: (e.pageX - offset.left - 10) + 'px'});
  }

  file.attr({name: 'file[]', type: 'file', multiple: 'multiple', size: 5, title: ''})
    .change(function() { ui.file_upload(); })
    .click(function() { setTimeout(function() { link.mouseleave(); }, 20); })
    // opacity:0 does the trick, display/visibility doesn't work
    .css({opacity: 0, cursor: 'pointer', position: 'relative', outline: 'none'});

  // In FF and IE we need to move the browser file-input's button under the cursor
  // Thanks to the size attribute above we know the length of the input field
  if (navigator.userAgent.match(/Firefox|MSIE/))
    file.css({marginLeft: '-80px'});

  // Note: now, I observe problem with cursor style on FF < 4 only
  link.css({overflow: 'hidden', cursor: 'pointer'})
    .mouseenter(function() { this.__active = ui.commands['file.upload'] ? true : false; })
    // place button under the cursor
    .mousemove(function(e) {
      if (ui.commands['file.upload'] && this.__active)
        move_file_input(e);
      // move the input away if button is disabled
      else
        $(this).mouseleave();
    })
    .mouseleave(function() {
      file.css({top: '-10000px', left: '-10000px'});
      this.__active = false;
    })
    .click(function(e) {
      // forward click if mouse-enter event was missed
      if (ui.commands['file.upload'] && !this.__active) {
        this.__active = true;
        move_file_input(e);
        file.trigger(e);
      }
    })
    .mouseleave()
    .append(file);
};

function progress_update(data)
{
  var txt = ui.t('file.progress'), id = 'progress' + data.id,
    table = $('#' + id), content = $('#info' + id),
    i, row, offset, rows = [];

  if (!data || data.done) {
    if (table.length) {
      table.remove();
      content.remove();
    }
    return;
  }

  if (!table.length) {
    table = $('

');
    content = $('

');

    table.appendTo($('#actionbar'))
      .on('mouseleave', function() { content.hide(); })
      .on('mouseenter', function() { if (content.children().length) content.show(); });

    offset = table.offset();
    content.css({display: 'none', position: 'absolute', top: offset.top + 8, left: offset.left})
      .appendTo(document.body);
  }

  $('td.bar', table).width((data.percent || 1) + '%');

  if (data.total) {
    rows[ui.t('upload.size')] = ui.file_size(data.total);
    rows[ui.t('upload.progress')] = (data.percent || 0) + '%';
    if (data.rate)
      rows[ui.t('upload.rate')] = ui.file_size(data.rate) + '/s';
    if (data.eta)
      rows[ui.t('upload.eta')] = ui.time_format(data.eta);

    content.empty();

    for (i in rows)
      $('
').append($('').text(i))
        .append($('').text(rows[i]))
        .appendTo(content);
  }
};

function enable_command_handler(p)
{
  if (p.command == 'file.save') {
    $('#'+ui.buttons['file.edit']).css('display', p.status ? 'none' : 'block');
    $('#'+ui.buttons['file.save']).css('display', p.status ? 'block' : 'none');
  }
};

$(window).load(function() {
  hack_file_input('file-upload-button');
  $('#forms > form').hide();
  ui.add_event_listener('enable-command', enable_command_handler);
});

// register buttons
ui.buttons({
'folder.create': 'folder-create-button',
'folder.edit': 'folder-edit-button',
'folder.delete': 'folder-delete-button',
'file.upload': 'file-upload-button',
'file.search': 'file-search-button',
'file.delete': 'file-delete-button',
'file.download': 'file-download-button',
'file.edit': 'file-edit-button',
'file.copy': 'file-copy-button',
'file.move': 'file-move-button',
'file.save': 'file-save-button'
});
<|endoftext|>


<commit_before>import { Namespace as NS } from 'xmpp-constants';

let internals = {};

internals.definePresence = function (JXT, name, namespace) {

    let Utils = JXT.utils;

    JXT.define({
        name: name,
        namespace: namespace,
        element: 'presence',
        topLevel: true,
        fields: {
            lang: Utils.langAttribute(),
            id: Utils.attribute('id'),
            to: Utils.jidAttribute('to', true),
            from: Utils.jidAttribute('from', true),
            priority: Utils.numberSub(namespace, 'priority', false, 0),
            show: Utils.textSub(namespace, 'show'),
            type: {
                get: function () {

                    return Utils.getAttribute(this.xml, 'type', 'available');
                },
                set: function (value) {

                    if (value === 'available') {
                        value = false;
                    }
                    Utils.setAttribute(this.xml, 'type', value);
                }
            },
            $status: {
                get: function () {

                    return Utils.getSubLangText(this.xml, namespace, 'status', this.lang);
                }
            },
            status: {
                get: function () {

                    let statuses = this.$status;
                    return statuses[this.lang] || '';
                },
                set: function (value) {

                    Utils.setSubLangText(this.xml, namespace, 'status', value, this.lang);
                }
            },
            idleSince: Utils.dateSubAttribute(NS.IDLE_1, 'idle', 'since'),
            decloak: Utils.subAttribute(NS.DECLOAK_0, 'decloak', 'reason'),
            avatarId: {
                get: function () {

                    let update = Utils.find(this.xml, NS.VCARD_TEMP_UPDATE, 'x');
                    if (!update.length) {
                        return '';
                    }
                    return Utils.getSubText(update[0], NS.VCARD_TEMP_UPDATE, 'photo');
                },
                set: function (value) {

                    let update = Utils.findOrCreate(this.xml, NS.VCARD_TEMP_UPDATE, 'x');

                    if (value === '') {
                        Utils.setBoolSub(update, NS.VCARD_TEMP_UPDATE, 'photo', true);
                    } else if (value === true) {
                        return;
                    } else if (value) {
                        Utils.setSubText(update, NS.VCARD_TEMP_UPDATE, 'photo', value);
                    } else {
                        this.xml.removeChild(update);
                    }
                }
            }
        }
    });
};

export default function (JXT) {

    internals.definePresence(JXT, 'presence', NS.CLIENT);
    internals.definePresence(JXT, 'serverPresence', NS.SERVER);
    internals.definePresence(JXT, 'componentPresence', NS.COMPONENT);
}
<commit_msg>Fix XEP-0276 decloak element namespace reference.<commit_after>import { Namespace as NS } from 'xmpp-constants';

let internals = {};

internals.definePresence = function (JXT, name, namespace) {

    let Utils = JXT.utils;

    JXT.define({
        name: name,
        namespace: namespace,
        element: 'presence',
        topLevel: true,
        fields: {
            lang: Utils.langAttribute(),
            id: Utils.attribute('id'),
            to: Utils.jidAttribute('to', true),
            from: Utils.jidAttribute('from', true),
            priority: Utils.numberSub(namespace, 'priority', false, 0),
            show: Utils.textSub(namespace, 'show'),
            type: {
                get: function () {

                    return Utils.getAttribute(this.xml, 'type', 'available');
                },
                set: function (value) {

                    if (value === 'available') {
                        value = false;
                    }
                    Utils.setAttribute(this.xml, 'type', value);
                }
            },
            $status: {
                get: function () {

                    return Utils.getSubLangText(this.xml, namespace, 'status', this.lang);
                }
            },
            status: {
                get: function () {

                    let statuses = this.$status;
                    return statuses[this.lang] || '';
                },
                set: function (value) {

                    Utils.setSubLangText(this.xml, namespace, 'status', value, this.lang);
                }
            },
            idleSince: Utils.dateSubAttribute(NS.IDLE_1, 'idle', 'since'),
            decloak: Utils.subAttribute(NS.DECLOAKING_0, 'decloak', 'reason'),
            avatarId: {
                get: function () {

                    let update = Utils.find(this.xml, NS.VCARD_TEMP_UPDATE, 'x');
                    if (!update.length) {
                        return '';
                    }
                    return Utils.getSubText(update[0], NS.VCARD_TEMP_UPDATE, 'photo');
                },
                set: function (value) {

                    let update = Utils.findOrCreate(this.xml, NS.VCARD_TEMP_UPDATE, 'x');

                    if (value === '') {
                        Utils.setBoolSub(update, NS.VCARD_TEMP_UPDATE, 'photo', true);
                    } else if (value === true) {
                        return;
                    } else if (value) {
                        Utils.setSubText(update, NS.VCARD_TEMP_UPDATE, 'photo', value);
                    } else {
                        this.xml.removeChild(update);
                    }
                }
            }
        }
    });
};

export default function (JXT) {

    internals.definePresence(JXT, 'presence', NS.CLIENT);
    internals.definePresence(JXT, 'serverPresence', NS.SERVER);
    internals.definePresence(JXT, 'componentPresence', NS.COMPONENT);
}
<|endoftext|>


<commit_before>/*!
 * array-keys
 *   version 1.1.1
 *   http://github.com/silverbucket/array-keys
 *
 * Developed and Maintained by:
 *   Nick Jennings <nick@silverbucket.net> copyright 2014
 *
 * array-keys is released under the LGPL (see LICENSE).
 *
 * You don't have to do anything special to choose one license or the other
 * and you don't have to notify anyone which license you are using.
 * Please see the corresponding license file for details of these licenses.
 * You are free to use, modify and distribute this software, but all copyright
 * information must remain.
 *
 */

function ArrayKeys(p) {
  if (typeof p !== 'object') { p = {}; }
  this.identifier = p.identifier || 'id';
  this.idx = [];
}

ArrayKeys.prototype.getIdentifiers = function () {
  var ids = [];
  for (var i = this.idx.length - 1; i >= 0; i--) {
    ids.push(this.idx[i][this.identifier]);
  }
  return ids;
};

ArrayKeys.prototype.getRecord = function (id) {
  for (var i = this.idx.length - 1; i >= 0; i--) {
    if ('' + this.idx[i][this.identifier] === '' + id) {
      return this.idx[i];
    }
  }
  return undefined;
};

ArrayKeys.prototype.addRecord = function (record) {
  if (typeof record !== 'object') {
    throw new Error('cannot add non-object records.');
  } else if (!record[this.identifier]) {
    throw new Error('cannot add a record with no `' + this.identifier +
                    '` property specified.');
  }
  this.removeRecord(record[this.identifier]);
  this.idx.push(record);
  return true;
};

ArrayKeys.prototype.removeRecord = function (id) {
  for (var i = this.idx.length - 1; i >= 0; i--) {
    if ('' + this.idx[i][this.identifier] === '' + id) {
      this.idx.splice(i, 1);
      return true;
    }
  }
  return false;
};

ArrayKeys.prototype.forEachRecord = function (cb) {
  for (var i = this.idx.length - 1; i >= 0; i--) {
    cb(this.idx[i]);
  }
};

ArrayKeys.prototype.getCount = function () {
  return this.idx.length;
};

module.exports = ArrayKeys;
<commit_msg>tons of performance improvements, more than 30% faster<commit_after>/*!
 * array-keys
 *   version 1.2.0
 *   http://github.com/silverbucket/array-keys
 *
 * Developed and Maintained by:
 *   Nick Jennings <nick@silverbucket.net> copyright 2014
 *
 * array-keys is released under the LGPL (see LICENSE).
 *
 * You don't have to do anything special to choose one license or the other
 * and you don't have to notify anyone which license you are using.
 * Please see the corresponding license file for details of these licenses.
 * You are free to use, modify and distribute this software, but all copyright
 * information must remain.
 *
 */

function ArrayKeys(p) {
  if (typeof p !== 'object') { p = {}; }
  this.identifier = p.identifier || 'id';
  this.store = [];
  this.idx = []; // array of identifier strings for quick lookup
}

ArrayKeys.prototype.getIdentifiers = function () {
  var ids = [];
  for (var i = this.store.length - 1; i >= 0; i = i - 1) {
    ids.push(this.store[i][this.identifier]);
  }
  return ids;
};

ArrayKeys.prototype.getRecord = function (id) {
  for (var i = this.store.length - 1; i >= 0; i = i - 1) {
    if ('' + this.store[i][this.identifier] === '' + id) {
      return this.store[i];
    }
  }
  return undefined;
};

ArrayKeys.prototype.exists = function (id) {
  if (this.idx.getIndex(id) >= 0) {
    return true;
  } else {
    return false;
  }
};

// faster than using indexOf
ArrayKeys.prototype.getIndex = function (id) {
  for (i = this.idx.length - 1; i >= 0; i = i - 1) {
    if (this.idx[i] === id) {
      return i;
    }
  }
  return -1;
};

ArrayKeys.prototype.addRecord = function (record) {
  if (typeof record !== 'object') {
    throw new Error('cannot add non-object records.');
  } else if (!record[this.identifier]) {
    throw new Error('cannot add a record with no `' + this.identifier +
                    '` property specified.');
  }

  this.removeRecord(record[this.identifier]);
  this.idx.push(record[this.identifier]);
  this.store.push(record);
  return true;
};

ArrayKeys.prototype.removeRecord = function (id) {
  var i;
  var idx = this.getIndex(id);
  if (idx < 0) {
    return false;
  }

  // start looking for the record at the same point as the idx entry
  for (i = idx; i >= 0; i = i - 1) {
    if (this.store[i][this.identifier] === id) {
      this.store.splice(i, 1);
      this.idx.splice(idx, 1);
      return true;
    }
  }

  // if it was not found, start at the end and break at the idx number
  for (i = this.store.length - 1; i >= idx; i = i - 1) {
    if (this.store[i][this.identifier] === id) {
      this.store.splice(i, 1);
      this.idx.splice(idx, 1);
      return true;
    }
  }
  return false;
};

ArrayKeys.prototype.forEachRecord = function (cb) {
  var count = 0;
  var self = this;
  var finished = function () {};

  setTimeout(function () {
    for (var i = self.store.length - 1; i >= 0; i = i - 1) {
      count += 1;
      cb(self.store[i]);
    }
    finished(count);
  }, 0);

  return {
    finally: function (func) {
      finished = func;
    }
  };
};

ArrayKeys.prototype.getCount = function () {
  return this.store.length;
};

module.exports = ArrayKeys;
<|endoftext|>


<commit_before>/**
 * Hilo
 * Copyright 2015 alibaba.com
 * Licensed under the MIT License
 */

//TODO: 超时timeout，失败重连次数maxTries，更多的下载器Loader，队列暂停恢复等。

/**
 * @language=en
 * @class LoadQueue is a queue-like loader.
 * @mixes EventMixin
 * @borrows EventMixin#on as #on
 * @borrows EventMixin#off as #off
 * @borrows EventMixin#fire as #fire
 * @param {Object} source resource that need to be loaded,could be a single object or array resource.
 * @module hilo/loader/LoadQueue
 * @requires hilo/core/Class
 * @requires hilo/event/EventMixin
 * @requires hilo/loader/ImageLoader
 * @requires hilo/loader/ScriptLoader
 * @property {Int} maxConnections the limited concurrent connections. default value  2.
 */
/**
 * @language=zh
 * @class LoadQueue是一个队列下载工具。
 * @mixes EventMixin
 * @borrows EventMixin#on as #on
 * @borrows EventMixin#off as #off
 * @borrows EventMixin#fire as #fire
 * @param {Object} source 要下载的资源。可以是单个资源对象或多个资源的数组。
 * @module hilo/loader/LoadQueue
 * @requires hilo/core/Class
 * @requires hilo/event/EventMixin
 * @requires hilo/loader/ImageLoader
 * @requires hilo/loader/ScriptLoader
 * @property {Int} maxConnections 同时下载的最大连接数。默认为2。
 */
var LoadQueue = Class.create(/** @lends LoadQueue.prototype */{
    Mixes: EventMixin,
    constructor: function(source){
        this._source = [];
        this.add(source);
    },

    maxConnections: 2, //TODO: 应该是每个host的最大连接数。

    _source: null,
    _loaded: 0,
    _connections: 0,
    _currentIndex: -1,

    /**
     * @language=en
     * Add desired resource,could be a single object or array resource.
     * @param {Object|Array} source ,a single object or array resource. Each resource contains properties like below:
     *

     *
id - resource identifier

     *
src - resource url

     *
type - resource type. By default, we automatically identify resource by file suffix and choose the relevant loader for you

     *
loader - specified resource loader. If you specify this,we abandon choosing loader inside

     *
noCache - a tag that set on or off to prevent cache,implemented by adding timestamp inside

     *
size - predicted resource size, help calculating loading progress

     *

     * @returns {LoadQueue} 下载队列实例本身。
     */
    /**
     * @language=zh
     * 增加要下载的资源。可以是单个资源对象或多个资源的数组。
     * @param {Object|Array} source 资源对象或资源对象数组。每个资源对象包含以下属性：
     *

     *
id - 资源的唯一标识符。可用于从下载队列获取目标资源。

     *
src - 资源的地址url。

     *
type - 指定资源的类型。默认会根据资源文件的后缀来自动判断类型，不同的资源类型会使用不同的加载器来加载资源。

     *
loader - 指定资源的加载器。默认会根据资源类型来自动选择加载器，若指定loader，则会使用指定的loader来加载资源。

     *
noCache - 指示加载资源时是否增加时间标签以防止缓存。

     *
size - 资源对象的预计大小。可用于预估下载进度。

     *

     * @returns {LoadQueue} 下载队列实例本身。
     */
    add: function(source){
        var me = this;
        if(source){
            source = source instanceof Array ? source : [source];
            me._source = me._source.concat(source);
        }
        return me;
    },

    /**
     * @language=en
     * get resource object by id or src
     * @param {String}  specified id or src
     * @returns {Object} resource object
     */
    /**
     * @language=zh
     * 根据id或src地址获取资源对象。
     * @param {String} id 指定资源的id或src。
     * @returns {Object} 资源对象。
     */
    get: function(id){
        if(id){
            var source = this._source;
            for(var i = 0; i < source.length; i++){
                var item = source[i];
                if(item.id === id || item.src === id){
                    return item;
                }
            }
        }
        return null;
    },

    /**
     * @language=en
     * get resource object content  by id or src
     * @param {String} specified id or src
     * @returns {Object} resource object content
     */
    /**
     * @language=zh
     * 根据id或src地址获取资源内容。
     * @param {String} id 指定资源的id或src。
     * @returns {Object} 资源内容。
     */
    getContent: function(id){
        var item = this.get(id);
        return item && item.content;
    },

    /**
     * @language=en
     * start loading
     * @returns {LoadQueue} the loading instance
     */
    /**
     * @language=zh
     * 开始下载队列。
     * @returns {LoadQueue} 下载队列实例本身。
     */
    start: function(){
        var me = this;
        me._loadNext();
        return me;
    },

    /**
     * @language=en
     * @private
     */
    /**
     * @language=zh
     * @private
     */
    _loadNext: function(){
        var me = this, source = me._source, len = source.length;

        //all items loaded
        if(me._loaded >= len){
            me.fire('complete');
            return;
        }

        if(me._currentIndex < len - 1 && me._connections < me.maxConnections){
            var index = ++me._currentIndex;
            var item = source[index];
            var loader = me._getLoader(item);

            if(loader){
                var onLoad = loader.onLoad, onError = loader.onError;

                loader.onLoad = function(e){
                    loader.onLoad = onLoad;
                    loader.onError = onError;
                    var content = onLoad && onLoad.call(loader, e) || e.target;
                    me._onItemLoad(index, content);
                };
                loader.onError = function(e){
                    loader.onLoad = onLoad;
                    loader.onError = onError;
                    onError && onError.call(loader, e);
                    me._onItemError(index, e);
                };
                me._connections++;
            }

            me._loadNext();
            loader && loader.load(item);
        }
    },

    /**
     * @language=en
     * @private
     */
    /**
     * @language=zh
     * @private
     */
    _getLoader: function(item){
        var loader = item.loader;
        if(loader) return loader;

        var type = item.type || getExtension(item.src);

        switch(type){
            case 'png':
            case 'jpg':
            case 'jpeg':
            case 'gif':
                loader = new ImageLoader();
                break;
            case 'js':
            case 'jsonp':
                loader = new ScriptLoader();
                break;
        }

        return loader;
    },

    /**
     * @language=en
     * @private
     */
    /**
     * @language=zh
     * @private
     */
    _onItemLoad: function(index, content){
        var me = this, item = me._source[index];
        item.loaded = true;
        item.content = content;
        me._connections--;
        me._loaded++;
        me.fire('load', item);
        me._loadNext();
    },

    /**
     * @language=en
     * @private
     */
    /**
     * @language=zh
     * @private
     */
    _onItemError: function(index, e){
        var me = this, item = me._source[index];
        item.error = e;
        me._connections--;
        me._loaded++;
        me.fire('error', item);
        me._loadNext();
    },

    /**
     * @language=en
     *  get resource size, loaded or all.
     * @param {Boolean} identify loaded or all resource. default is false, return all resource size. when set true, return loaded resource size.
     * @returns {Number} resource size.
     */
    /**
     * @language=zh
     * 获取全部或已下载的资源的字节大小。
     * @param {Boolean} loaded 指示是已下载的资源还是全部资源。默认为全部。
     * @returns {Number} 指定资源的字节大小。
     */
    getSize: function(loaded){
        var size = 0, source = this._source;
        for(var i = 0; i < source.length; i++){
            var item = source[i];
            size += (loaded ? item.loaded && item.size : item.size) || 0;
        }
        return size;
    },

    /**
     * @language=en
     * get loaded resource count
     * @returns {Uint} loaded resource count
     */
    /**
     * @language=zh
     * 获取已下载的资源数量。
     * @returns {Uint} 已下载的资源数量。
     */
    getLoaded: function(){
        return this._loaded;
    },

    /**
     * @language=en
     * get all resource count
     * @returns {Uint} all resource count
     */
    /**
     * @language=zh
     * 获取所有资源的数量。
     * @returns {Uint} 所有资源的数量。
     */
    getTotal: function(){
        return this._source.length;
    }

});

/**
 * @language=en
 * @private
 */
/**
 * @language=zh
 * @private
 */
function getExtension(src){
    var extRegExp = /\/?[^/]+\.(\w+)(\?\S+)?$/i, match, extension;
    if(match = src.match(extRegExp)){
        extension = match[1].toLowerCase();
    }
    return extension || null;
}<commit_msg>feat:loadQueue add support for webp (#76)<commit_after>/**
 * Hilo
 * Copyright 2015 alibaba.com
 * Licensed under the MIT License
 */

//TODO: 超时timeout，失败重连次数maxTries，更多的下载器Loader，队列暂停恢复等。

/**
 * @language=en
 * @class LoadQueue is a queue-like loader.
 * @mixes EventMixin
 * @borrows EventMixin#on as #on
 * @borrows EventMixin#off as #off
 * @borrows EventMixin#fire as #fire
 * @param {Object} source resource that need to be loaded,could be a single object or array resource.
 * @module hilo/loader/LoadQueue
 * @requires hilo/core/Class
 * @requires hilo/event/EventMixin
 * @requires hilo/loader/ImageLoader
 * @requires hilo/loader/ScriptLoader
 * @property {Int} maxConnections the limited concurrent connections. default value  2.
 */
/**
 * @language=zh
 * @class LoadQueue是一个队列下载工具。
 * @mixes EventMixin
 * @borrows EventMixin#on as #on
 * @borrows EventMixin#off as #off
 * @borrows EventMixin#fire as #fire
 * @param {Object} source 要下载的资源。可以是单个资源对象或多个资源的数组。
 * @module hilo/loader/LoadQueue
 * @requires hilo/core/Class
 * @requires hilo/event/EventMixin
 * @requires hilo/loader/ImageLoader
 * @requires hilo/loader/ScriptLoader
 * @property {Int} maxConnections 同时下载的最大连接数。默认为2。
 */
var LoadQueue = Class.create(/** @lends LoadQueue.prototype */{
    Mixes: EventMixin,
    constructor: function(source){
        this._source = [];
        this.add(source);
    },

    maxConnections: 2, //TODO: 应该是每个host的最大连接数。

    _source: null,
    _loaded: 0,
    _connections: 0,
    _currentIndex: -1,

    /**
     * @language=en
     * Add desired resource,could be a single object or array resource.
     * @param {Object|Array} source ,a single object or array resource. Each resource contains properties like below:
     *

     *
id - resource identifier

     *
src - resource url

     *
type - resource type. By default, we automatically identify resource by file suffix and choose the relevant loader for you

     *
loader - specified resource loader. If you specify this,we abandon choosing loader inside

     *
noCache - a tag that set on or off to prevent cache,implemented by adding timestamp inside

     *
size - predicted resource size, help calculating loading progress

     *

     * @returns {LoadQueue} 下载队列实例本身。
     */
    /**
     * @language=zh
     * 增加要下载的资源。可以是单个资源对象或多个资源的数组。
     * @param {Object|Array} source 资源对象或资源对象数组。每个资源对象包含以下属性：
     *

     *
id - 资源的唯一标识符。可用于从下载队列获取目标资源。

     *
src - 资源的地址url。

     *
type - 指定资源的类型。默认会根据资源文件的后缀来自动判断类型，不同的资源类型会使用不同的加载器来加载资源。

     *
loader - 指定资源的加载器。默认会根据资源类型来自动选择加载器，若指定loader，则会使用指定的loader来加载资源。

     *
noCache - 指示加载资源时是否增加时间标签以防止缓存。

     *
size - 资源对象的预计大小。可用于预估下载进度。

     *

     * @returns {LoadQueue} 下载队列实例本身。
     */
    add: function(source){
        var me = this;
        if(source){
            source = source instanceof Array ? source : [source];
            me._source = me._source.concat(source);
        }
        return me;
    },

    /**
     * @language=en
     * get resource object by id or src
     * @param {String}  specified id or src
     * @returns {Object} resource object
     */
    /**
     * @language=zh
     * 根据id或src地址获取资源对象。
     * @param {String} id 指定资源的id或src。
     * @returns {Object} 资源对象。
     */
    get: function(id){
        if(id){
            var source = this._source;
            for(var i = 0; i < source.length; i++){
                var item = source[i];
                if(item.id === id || item.src === id){
                    return item;
                }
            }
        }
        return null;
    },

    /**
     * @language=en
     * get resource object content  by id or src
     * @param {String} specified id or src
     * @returns {Object} resource object content
     */
    /**
     * @language=zh
     * 根据id或src地址获取资源内容。
     * @param {String} id 指定资源的id或src。
     * @returns {Object} 资源内容。
     */
    getContent: function(id){
        var item = this.get(id);
        return item && item.content;
    },

    /**
     * @language=en
     * start loading
     * @returns {LoadQueue} the loading instance
     */
    /**
     * @language=zh
     * 开始下载队列。
     * @returns {LoadQueue} 下载队列实例本身。
     */
    start: function(){
        var me = this;
        me._loadNext();
        return me;
    },

    /**
     * @language=en
     * @private
     */
    /**
     * @language=zh
     * @private
     */
    _loadNext: function(){
        var me = this, source = me._source, len = source.length;

        //all items loaded
        if(me._loaded >= len){
            me.fire('complete');
            return;
        }

        if(me._currentIndex < len - 1 && me._connections < me.maxConnections){
            var index = ++me._currentIndex;
            var item = source[index];
            var loader = me._getLoader(item);

            if(loader){
                var onLoad = loader.onLoad, onError = loader.onError;

                loader.onLoad = function(e){
                    loader.onLoad = onLoad;
                    loader.onError = onError;
                    var content = onLoad && onLoad.call(loader, e) || e.target;
                    me._onItemLoad(index, content);
                };
                loader.onError = function(e){
                    loader.onLoad = onLoad;
                    loader.onError = onError;
                    onError && onError.call(loader, e);
                    me._onItemError(index, e);
                };
                me._connections++;
            }

            me._loadNext();
            loader && loader.load(item);
        }
    },

    /**
     * @language=en
     * @private
     */
    /**
     * @language=zh
     * @private
     */
    _getLoader: function(item){
        var loader = item.loader;
        if(loader) return loader;

        var type = item.type || getExtension(item.src);

        switch(type){
            case 'png':
            case 'jpg':
            case 'jpeg':
            case 'gif':
            case 'webp':
                loader = new ImageLoader();
                break;
            case 'js':
            case 'jsonp':
                loader = new ScriptLoader();
                break;
        }

        return loader;
    },

    /**
     * @language=en
     * @private
     */
    /**
     * @language=zh
     * @private
     */
    _onItemLoad: function(index, content){
        var me = this, item = me._source[index];
        item.loaded = true;
        item.content = content;
        me._connections--;
        me._loaded++;
        me.fire('load', item);
        me._loadNext();
    },

    /**
     * @language=en
     * @private
     */
    /**
     * @language=zh
     * @private
     */
    _onItemError: function(index, e){
        var me = this, item = me._source[index];
        item.error = e;
        me._connections--;
        me._loaded++;
        me.fire('error', item);
        me._loadNext();
    },

    /**
     * @language=en
     *  get resource size, loaded or all.
     * @param {Boolean} identify loaded or all resource. default is false, return all resource size. when set true, return loaded resource size.
     * @returns {Number} resource size.
     */
    /**
     * @language=zh
     * 获取全部或已下载的资源的字节大小。
     * @param {Boolean} loaded 指示是已下载的资源还是全部资源。默认为全部。
     * @returns {Number} 指定资源的字节大小。
     */
    getSize: function(loaded){
        var size = 0, source = this._source;
        for(var i = 0; i < source.length; i++){
            var item = source[i];
            size += (loaded ? item.loaded && item.size : item.size) || 0;
        }
        return size;
    },

    /**
     * @language=en
     * get loaded resource count
     * @returns {Uint} loaded resource count
     */
    /**
     * @language=zh
     * 获取已下载的资源数量。
     * @returns {Uint} 已下载的资源数量。
     */
    getLoaded: function(){
        return this._loaded;
    },

    /**
     * @language=en
     * get all resource count
     * @returns {Uint} all resource count
     */
    /**
     * @language=zh
     * 获取所有资源的数量。
     * @returns {Uint} 所有资源的数量。
     */
    getTotal: function(){
        return this._source.length;
    }

});

/**
 * @language=en
 * @private
 */
/**
 * @language=zh
 * @private
 */
function getExtension(src){
    var extRegExp = /\/?[^/]+\.(\w+)(\?\S+)?$/i, match, extension;
    if(match = src.match(extRegExp)){
        extension = match[1].toLowerCase();
    }
    return extension || null;
}<|endoftext|>


<commit_before>// art.window.js

// Window Widget. Work in progress.

ART.Window = new Class({

	Extends: ART.Widget,

	name: 'window',

	style: {

		base: {

			'height': 300,
			'width': 400,

			'button-margin': 20,
			'button-top': 5,

			'corner-radius': 3,
			'header-height': 23,
			'footer-height': 16,
			'header-background-color': {0: hsb(0, 0, 80), 1: hsb(0, 0, 50)},
			'footer-background-color': {0: hsb(0, 0, 80), 1: hsb(0, 0, 70)},
			'header-reflection-color': {0: hsb(0, 0, 100, 1), 1: hsb(0, 0, 0, 0)},
			'footer-reflection-color': {0: hsb(0, 0, 100, 1), 1: hsb(0, 0, 0, 0)},
			'border-color': hsb(0, 0, 0, 0.7)
		}

	},

	options: {
		close: true,
		minimize: true,
		maximize: true,
		resize: true,

		closeStyle: {base: {
			'pill': true,

			'background-color': {0: hsb(200, 15, 75), 1: hsb(200, 35, 55)},
			'reflection-color': {0: hsb(200, 10, 95), 1: hsb(200, 0, 0, 0)},
			'border-color': hsb(200, 35, 45),
			'glyph-color': hsb(0, 0, 100, 0.8),

			'glyph': 'close-icon',

			'height': 14,
			'width': 14,

			'glyph-height': 4,
			'glyph-width': 4,
			'glyph-top': 5,
			'glyph-left': 5
		}, active: {
			'glyph-color': hsb(0, 0, 100)
		}},

		minimizeStyle: {base: {
			'pill': true,

			'background-color': {0: hsb(200, 15, 75), 1: hsb(200, 35, 55)},
			'reflection-color': {0: hsb(200, 10, 95), 1: hsb(200, 0, 0, 0)},
			'border-color': hsb(200, 35, 45),
			'glyph-color': hsb(0, 0, 100, 0.8),

			'glyph': 'minus-icon',

			'height': 14,
			'width': 14,

			'glyph-height': 6,
			'glyph-width': 6,
			'glyph-top': 4,
			'glyph-left': 4
		}, active: {
			'glyph-color': hsb(0, 0, 100)
		}},

		maximizeStyle: {base: {
			'pill': true,

			'background-color': {0: hsb(200, 15, 75), 1: hsb(200, 35, 55)},
			'reflection-color': {0: hsb(200, 10, 95), 1: hsb(200, 0, 0, 0)},
			'border-color': hsb(200, 35, 45),
			'glyph-color': hsb(0, 0, 100, 0.8),

			'glyph': 'plus-icon',

			'height': 14,
			'width': 14,

			'glyph-height': 6,
			'glyph-width': 6,
			'glyph-top': 4,
			'glyph-left': 4
		}, active: {
			'glyph-color': hsb(0, 0, 100)
		}}
	},

	initialize: function(options){
		this.parent(options);

		var relative = {'position': 'relative', 'top': 0, 'left': 0};
		var absolute = {'position': 'absolute', 'top': 0, 'left': 0};

		this.paint = new ART.Paint();
		$(this.paint).setStyles(absolute).inject(this.element);

		this.element.setStyles({'position': 'relative'});

		this.header = new Element('div', {'class': 'art-window-header'});
		this.content = new Element('div', {'class': 'art-window-content'});
		this.footer = new Element('div', {'class': 'art-window-footer'});

		this.header.setStyles(relative);
		this.content.setStyles(relative);
		this.footer.setStyles(relative);

		this.element.adopt(this.header, this.content, this.footer);

		if (this.options.close){
			this.close = new ART.Button({style: this.options.closeStyle});
			$(this.close).setStyles(absolute).inject(this.header);
		}

		if (this.options.maximize){
			this.maximize = new ART.Button({style: this.options.maximizeStyle});
			$(this.maximize).setStyles(absolute).inject(this.header);
		}

		if (this.options.minimize){
			this.minimize = new ART.Button({style: this.options.minimizeStyle});
			$(this.minimize).setStyles(absolute).inject(this.header);
		}

		this.render();
	},

	setContent: function(){
		this.content.adopt(arguments);
		return this;
	},

	render: function(style){
		if (!this.paint) return this;
		if (style) $extend(this.style.now, style);

		var now = {};
		for (var p in this.style.now) now[p.camelCase()] = this.style.now[p];

		this.paint.resize({x: now.width, y: now.height});
		this.element.setStyles({height: now.height, width: now.width});
		this.content.setStyles({top: 0, left: 1, height: now.height - now.footerHeight - now.headerHeight - 2, width: now.width -2});

		this.paint.start();
		this.paint.shape('rounded-rectangle', {x: now.width, y: now.height}, now.cornerRadius + 1);
		this.paint.render({'fill': now.borderColor});

		this.header.setStyles({'width': now.width, height: now.headerHeight});

		this.paint.start({x: 1, y: 1});
		this.paint.shape('rounded-rectangle', {x: now.width - 2, y: now.headerHeight - 2}, [now.cornerRadius, now.cornerRadius, 0, 0]);
		this.paint.render({fill: now.headerReflectionColor});

		this.paint.start({x: 1, y: 2});
		this.paint.shape('rounded-rectangle', {x: now.width - 2, y: now.headerHeight - 3}, [now.cornerRadius, now.cornerRadius, 0, 0]);
		this.paint.render({fill: now.headerBackgroundColor});

		this.footer.setStyles({'width': now.width, height: now.footerHeight});

		this.paint.start({x: 1, y: now.height - now.footerHeight - 1});
		this.paint.shape('rounded-rectangle', {x: now.width - 2, y: now.footerHeight}, [0, 0, now.cornerRadius, now.cornerRadius]);
		this.paint.render({fill: now.footerReflectionColor});

		this.paint.start({x: 1, y: now.height - now.footerHeight});
		this.paint.shape('rounded-rectangle', {x: now.width - 2, y: now.footerHeight - 1}, [0, 0, now.cornerRadius, now.cornerRadius]);
		this.paint.render({fill: now.footerBackgroundColor});

		if (this.options.resize){

			this.paint.start({x: now.width - 13, y: now.height - 12});
			this.paint.shape('resize-icon', {x: 10, y: 10});
			this.paint.shape('lift', {x: -6, y: -6});
			this.paint.shape('resize-icon', {x: 6, y: 6});
			this.paint.shape('lift', {x: -2, y: -2});
			this.paint.shape('resize-icon', {x: 2, y: 2});
			this.paint.render({'stroke': hsb(0, 0, 100, 0.6)});

			this.paint.start({x: now.width - 13, y: now.height - 13});
			this.paint.shape('resize-icon', {x: 10, y: 10});
			this.paint.shape('lift', {x: -6, y: -6});
			this.paint.shape('resize-icon', {x: 6, y: 6});
			this.paint.shape('lift', {x: -2, y: -2});
			this.paint.shape('resize-icon', {x: 2, y: 2});
			this.paint.render({'stroke': hsb(0, 0, 0, 0.6)});
		}

		// painting buttons

		var baseLeft = 8;
		var oneLeft = baseLeft + now.buttonMargin;
		var twoLeft = oneLeft + oneLeft - baseLeft;

		if (this.close) $(this.close).setStyles({top: now.buttonTop, left: baseLeft});

		if (this.maximize) $(this.maximize).setStyles({
			top: now.buttonTop,
			left: (this.close && this.maximize) ? twoLeft : (this.close || this.maximize) ? oneLeft : baseLeft
		});

		if (this.minimize) $(this.minimize).setStyles({
			top: now.buttonTop,
			left: (this.close) ? oneLeft : baseLeft
		});

		return this;
	}

});
<commit_msg> - better active style for window buttons.<commit_after>// art.window.js

// Window Widget. Work in progress.

ART.Window = new Class({

	Extends: ART.Widget,

	name: 'window',

	style: {

		base: {

			'height': 300,
			'width': 400,

			'button-margin': 20,
			'button-top': 5,

			'corner-radius': 3,
			'header-height': 23,
			'footer-height': 16,
			'header-background-color': {0: hsb(0, 0, 80), 1: hsb(0, 0, 50)},
			'footer-background-color': {0: hsb(0, 0, 80), 1: hsb(0, 0, 70)},
			'header-reflection-color': {0: hsb(0, 0, 100, 1), 1: hsb(0, 0, 0, 0)},
			'footer-reflection-color': {0: hsb(0, 0, 100, 1), 1: hsb(0, 0, 0, 0)},
			'border-color': hsb(0, 0, 0, 0.7)
		}

	},

	options: {
		close: true,
		minimize: true,
		maximize: true,
		resize: true,

		closeStyle: {base: {
			'pill': true,

			'background-color': {0: hsb(200, 15, 75), 1: hsb(200, 35, 55)},
			'reflection-color': {0: hsb(200, 10, 95), 1: hsb(200, 0, 0, 0)},
			'border-color': hsb(200, 35, 45),
			'glyph-color': hsb(0, 0, 100, 0.8),

			'glyph': 'close-icon',

			'height': 14,
			'width': 14,

			'glyph-height': 4,
			'glyph-width': 4,
			'glyph-top': 5,
			'glyph-left': 5
		}, active: {
			'glyph-color': hsb(0, 0, 100),
			'background-color': hsb(200, 15, 65),
			'reflection-color': hsb(200, 35, 65),
			'border-color': {0: hsb(200, 35, 25), 1: hsb(200, 35, 90)}
		}},

		minimizeStyle: {base: {
			'pill': true,

			'background-color': {0: hsb(200, 15, 75), 1: hsb(200, 35, 55)},
			'reflection-color': {0: hsb(200, 10, 95), 1: hsb(200, 0, 0, 0)},
			'border-color': hsb(200, 35, 45),
			'glyph-color': hsb(0, 0, 100, 0.8),

			'glyph': 'minus-icon',

			'height': 14,
			'width': 14,

			'glyph-height': 6,
			'glyph-width': 6,
			'glyph-top': 4,
			'glyph-left': 4
		}, active: {
			'glyph-color': hsb(0, 0, 100),
			'background-color': hsb(200, 15, 65),
			'reflection-color': hsb(200, 35, 65),
			'border-color': {0: hsb(200, 35, 25), 1: hsb(200, 35, 90)}
		}},

		maximizeStyle: {base: {
			'pill': true,

			'background-color': {0: hsb(200, 15, 75), 1: hsb(200, 35, 55)},
			'reflection-color': {0: hsb(200, 10, 95), 1: hsb(200, 0, 0, 0)},
			'border-color': hsb(200, 35, 45),
			'glyph-color': hsb(0, 0, 100, 0.8),

			'glyph': 'plus-icon',

			'height': 14,
			'width': 14,

			'glyph-height': 6,
			'glyph-width': 6,
			'glyph-top': 4,
			'glyph-left': 4
		}, active: {
			'glyph-color': hsb(0, 0, 100),
			'background-color': hsb(200, 15, 65),
			'reflection-color': hsb(200, 35, 65),
			'border-color': {0: hsb(200, 35, 25), 1: hsb(200, 35, 90)}
		}}
	},

	initialize: function(options){
		this.parent(options);

		var relative = {'position': 'relative', 'top': 0, 'left': 0};
		var absolute = {'position': 'absolute', 'top': 0, 'left': 0};

		this.paint = new ART.Paint();
		$(this.paint).setStyles(absolute).inject(this.element);

		this.element.setStyles({'position': 'relative'});

		this.header = new Element('div', {'class': 'art-window-header'});
		this.content = new Element('div', {'class': 'art-window-content'});
		this.footer = new Element('div', {'class': 'art-window-footer'});

		this.header.setStyles(relative);
		this.content.setStyles(relative);
		this.footer.setStyles(relative);

		this.element.adopt(this.header, this.content, this.footer);

		if (this.options.close){
			this.close = new ART.Button({style: this.options.closeStyle});
			$(this.close).setStyles(absolute).inject(this.header);
		}

		if (this.options.maximize){
			this.maximize = new ART.Button({style: this.options.maximizeStyle});
			$(this.maximize).setStyles(absolute).inject(this.header);
		}

		if (this.options.minimize){
			this.minimize = new ART.Button({style: this.options.minimizeStyle});
			$(this.minimize).setStyles(absolute).inject(this.header);
		}

		this.render();
	},

	setContent: function(){
		this.content.adopt(arguments);
		return this;
	},

	render: function(style){
		if (!this.paint) return this;
		if (style) $extend(this.style.now, style);

		var now = {};
		for (var p in this.style.now) now[p.camelCase()] = this.style.now[p];

		this.paint.resize({x: now.width, y: now.height});
		this.element.setStyles({height: now.height, width: now.width});
		this.content.setStyles({top: 0, left: 1, height: now.height - now.footerHeight - now.headerHeight - 2, width: now.width -2});

		this.paint.start();
		this.paint.shape('rounded-rectangle', {x: now.width, y: now.height}, now.cornerRadius + 1);
		this.paint.render({'fill': now.borderColor});

		this.header.setStyles({'width': now.width, height: now.headerHeight});

		this.paint.start({x: 1, y: 1});
		this.paint.shape('rounded-rectangle', {x: now.width - 2, y: now.headerHeight - 2}, [now.cornerRadius, now.cornerRadius, 0, 0]);
		this.paint.render({fill: now.headerReflectionColor});

		this.paint.start({x: 1, y: 2});
		this.paint.shape('rounded-rectangle', {x: now.width - 2, y: now.headerHeight - 3}, [now.cornerRadius, now.cornerRadius, 0, 0]);
		this.paint.render({fill: now.headerBackgroundColor});

		this.footer.setStyles({'width': now.width, height: now.footerHeight});

		this.paint.start({x: 1, y: now.height - now.footerHeight - 1});
		this.paint.shape('rounded-rectangle', {x: now.width - 2, y: now.footerHeight}, [0, 0, now.cornerRadius, now.cornerRadius]);
		this.paint.render({fill: now.footerReflectionColor});

		this.paint.start({x: 1, y: now.height - now.footerHeight});
		this.paint.shape('rounded-rectangle', {x: now.width - 2, y: now.footerHeight - 1}, [0, 0, now.cornerRadius, now.cornerRadius]);
		this.paint.render({fill: now.footerBackgroundColor});

		if (this.options.resize){

			this.paint.start({x: now.width - 13, y: now.height - 12});
			this.paint.shape('resize-icon', {x: 10, y: 10});
			this.paint.shape('lift', {x: -6, y: -6});
			this.paint.shape('resize-icon', {x: 6, y: 6});
			this.paint.shape('lift', {x: -2, y: -2});
			this.paint.shape('resize-icon', {x: 2, y: 2});
			this.paint.render({'stroke': hsb(0, 0, 100, 0.6)});

			this.paint.start({x: now.width - 13, y: now.height - 13});
			this.paint.shape('resize-icon', {x: 10, y: 10});
			this.paint.shape('lift', {x: -6, y: -6});
			this.paint.shape('resize-icon', {x: 6, y: 6});
			this.paint.shape('lift', {x: -2, y: -2});
			this.paint.shape('resize-icon', {x: 2, y: 2});
			this.paint.render({'stroke': hsb(0, 0, 0, 0.6)});
		}

		// painting buttons

		var baseLeft = 8;
		var oneLeft = baseLeft + now.buttonMargin;
		var twoLeft = oneLeft + oneLeft - baseLeft;

		if (this.close) $(this.close).setStyles({top: now.buttonTop, left: baseLeft});

		if (this.maximize) $(this.maximize).setStyles({
			top: now.buttonTop,
			left: (this.close && this.maximize) ? twoLeft : (this.close || this.maximize) ? oneLeft : baseLeft
		});

		if (this.minimize) $(this.minimize).setStyles({
			top: now.buttonTop,
			left: (this.close) ? oneLeft : baseLeft
		});

		return this;
	}

});
<|endoftext|>


<commit_before>'use strict'

const { stringify } = JSON

exports.user = async function get(context) {
  return {
    body: stringify({
      status: 'authorized',
      requestContext: {
        claims: context.requestContext.authorizer.claims,
        scopes: context.requestContext.authorizer.scopes,
      },
    }),
    statusCode: 200,
  }
}
<commit_msg>code review fix<commit_after>'use strict'

exports.user = async function get(context) {
  return {
    body: JSON.stringify({
      status: 'authorized',
      requestContext: {
        claims: context.requestContext.authorizer.claims,
        scopes: context.requestContext.authorizer.scopes,
      },
    }),
    statusCode: 200,
  }
}
<|endoftext|>


<commit_before>ko.applyBindings(new ProductList());
<commit_msg>Delete ko-binding.js<commit_after><|endoftext|>


<commit_before>'use strict';

/**
 * Naive token generator
 * @param str {string} to be decomposed into stream of tokens
 */
function* tokenizer(str) {

    function newKeyword(kw) {
        return { type: "keyword", value: kw };
    }

    function newIdentifier(value) {
        return { type: "identifier", value: value.trim() };
    }

    let identifier=false;
    let accumulator=[];

    for (let i = 0, len = str.length ; i < len; i++) {

        switch (str[i]) {

            case '(': case ')': case '=': case '&': case '|': case '!': case '~': case '>': case '<':

                if (identifier) {
                    identifier = false;
                    let ni = accumulator.join('');
                    accumulator = [];
                    yield newIdentifier(ni);
                }

                switch (str[i]) {

                    // Compound keywords
                    case '~': case '>': case '<':

                        let nextI = i + 1;
                        if (nextI < len && str[nextI] === "=" ) {
                            yield newKeyword(str[i] + str[nextI]);
                            i++;
                        } else {
                            throw new Error("Unexpected token " + str[i] + " at position " + i + ".");
                        }
                        break;

                    // Single char keywords
                    default:
                        yield newKeyword(str[i]);
                        break;
                }
                break;
            default:

                identifier = true;
                accumulator.push(str[i]);
                break;
        }
    }
}

/**
 * Stream wrapper for {Array} object
 * @param data
 * @param data.array array to be wrapped
 * @param data.pos current position to be used
 * @constructor
 */
function StreamWrapper(data) {
    this.array = data.array;
    this.pos = data.pos;
}

/**
 * Produces immutable stream from array object
 * @param array
 * @returns {StreamWrapper}
 */
StreamWrapper.fromArray = function(array) {
    return new StreamWrapper({ pos: 0, array: array.slice() });
};

StreamWrapper.prototype = {

    isEmpty: function() { return this.pos >= this.array.length; },

    head: function() {
        if(this.isEmpty()) {
            throw new Error("StreamWrapper is empty")
        }
        return this.array[this.pos];
    },

    tail: function() {

        if(this.isEmpty()) {
            throw new Error("StreamWrapper is empty")
        }
        return new StreamWrapper({
            array: this.array,
            pos: this.pos + 1
        });
    }
};

/**
 * Tree
 */
function Tree(val1_, val2_) {
    this._1 = val1_;
    this._2 = val2_;
}

Tree.prototype = {

    /**
     * Tree structure equality check
     * @param that {object} to be compared with
     */
    equals: function(that) {

        function eq(left, right) {
            return (left instanceof Tree ? left.equals(right) : left === right);
        }

        if (that instanceof Tree) {
            return eq(this._1, that._1) && eq(this._2, that._2)
        } else {
            return false;
        }
    }
};

Tree.toLdapFilterList = function(tree) {
    return new LdapFilterList(tree._1, tree._2);
};

Tree.toLdapItem = function(tree) {

    return new LdapItem({
        attr: tree._1._1,
        filtertype: tree._1._2,
        value: tree._2
    });
};

Tree.toLdapFilter = function(tree) {

    /*
     Expected structure of ${tree}:

            value
          /       \
      ___/_       ')'
     /     \
     '('  ${filter}

     */

    return tree._1._2;
};

/**
 *
 * @param impl {function()} which accepts input stream of tokens and returns some
 * parse result.
 * @constructor
 */
function AbstractParser(impl) {
    this.f = impl;
}

/**
 * Produces parser which always succeeds
 * @param value result of successful parser
 * @returns {AbstractParser} which always succeeds
 */
AbstractParser.Success = function(value) {

    return new AbstractParser(function(input) {

        return {
            success: true,
            value: value,
            input: input
        }
    });
};

AbstractParser.prototype = {

    /**
     * Tries to parse given string value to any implementation of {LdapSyntaxEntryTrait}
     * @param str {string} string query
     * @return parse result.
     *
     *   It could be successful:
     *   {
     *       success: true,
     *       value: {LdapFilterList},
     *       input: {StreamWrapper}
     *   }
     *
     *   ... or it could be failure:
     *   {
     *       success: false,
     *       error: "Error message goes here",
     *       input: {StreamWrapper}
     *   }
     */
    parse: function(str) {

        var stream = StreamWrapper.fromArray(Array.from(tokenizer(str)));
        return this.$parse(stream);
    },

    $parse: function(input) {
        return this.f.call(this, input);
    },

    /**
     * Combines `this` as AbstractParser[A] and result of `other` function which is AbstractParser[B] into AbstractParser[A | B] which
     * can produce value of type A, value of type B or failure.
     * @param other {function} which produces some AbstractParser[B] i.e. () -> AbstractParser[B]
     * @returns {AbstractParser}
     */
    $or: function(other) {

        const self = this;
        return new AbstractParser(function(input) {

            let leftResult = self.$parse(input);
            if (leftResult.success) return leftResult;
            else return other().$parse(input)
        });
    },

    /**
     * Combines `this` as AbstractParser[A] and result of `other` function which is AbstractParser[B] into AbstractParser[A ~ B] which
     * produces composite type `A ~ B`. it will succeed if both parsers succeeded on given input. Composite type is pepresented by {Tree}
     * object.
     * @param other {function} which produces some AbstractParser[B] i.e. () -> AbstractParser[B]
     * @returns {AbstractParser}
     */
    $then: function(other) {

        const self = this;
        return new AbstractParser(function(input) {

            let leftResult = self.$parse(input);
            if (leftResult.success) {

                let rightResult = other().$parse(leftResult.input);
                if (rightResult.success) {
                    return {
                        success: true,
                        value: new Tree(leftResult.value, rightResult.value),
                        input: rightResult.input
                    };
                } else {
                    return rightResult;
                }
            } else {
                return leftResult;
            }
        });
    },

    /**
     * Transforms `this` as AbstractParser[A] to AbstractParser[B]
     * @param f a function A -> B
     * @returns {AbstractParser}
     */
    map: function(f) {

        const self = this;
        return new AbstractParser(function (input) {

            let result = self.$parse(input);
            if (result.success) {

                result = {
                    success: true,
                    value: f.call(self, result.value),
                    input: result.input
                };
            }

            return result;
        });
    },

    /**
     * Transforms `this` as AbstractParser[A] to AbstractParser[Array[A]]
     * @return {AbstractParser}
     */
    times: function() {

        const self = this;
        return self.$then(function() { return self.times(); })
            .map(function(p) {

                if (p instanceof Tree) {
                    return [p._1].concat(p._2)
                }
                else { throw new Error("Come up with some idea") }
            })
            .$or(function() { return AbstractParser.Success([]); });
    }
};

const LdapParser = function() {

    function token(value, p) {

        return function() {

            return new AbstractParser(function(input) {

                let result = { success: false, error: "expected " + value, input: input };

                if (!input.isEmpty() && p(input.head())) {
                    result = { success: true, value: input.head().value, input: input.tail(), error: null };
                }
                return result;
            });
        }
    }

    /* Grammar primitives */
    const nothing = new AbstractParser(function() {
        return { success: false, error: "Nothing case" };
    });

    function keyword(value) {

        return token(value, function(head) {
           return head.type === "keyword" && head.value === value;
        });
    }

    function identifier() {

        return token("identifier", function(head) {
            return head.type == "identifier";
        });
    }

    /* Products */
    var P = {

        filter: function() {

            return nothing.$or(keyword("(")).$then(P.filtercomp).$then(keyword(")"))
                .map(Tree.toLdapFilter);
        },

        filtercomp: function() {
            return nothing.$or(P.and).$or(P.or).$or(P.item);
        },

        and: function() {
            return nothing.$or(keyword("&")).$then(P.filterlist)
                .map(Tree.toLdapFilterList);
        },

        or: function() {
            return nothing.$or(keyword("|")).$then(P.filterlist)
                .map(Tree.toLdapFilterList);
        },

        filterlist: function() {

            return nothing.$or(P.filterlistSeq).$or(P.filter);
        },

        filterlistSeq: function() {
            return P.filter().times();
        },

        item: function() {
            return P.simple().map(Tree.toLdapItem);
        },

        simple: function() {
            return nothing.$or(identifier()).$then(P.filtertype).$then(identifier());
        },

        filtertype: function() {
            return nothing.$or(P.equal).$or(P.approx).$or(P.ge).$or(P.le);
        },

        equal: function() {
            return keyword("=")();
        },

        approx: function() {
            return keyword("~=")();
        },

        ge: function() {
            return keyword(">=")();
        },

        le: function() {
            return keyword("<=")();
        }
    };

    return P.filter();
}();
<commit_msg>Removed ugly comment block<commit_after>'use strict';

/**
 * Naive token generator
 * @param str {string} to be decomposed into stream of tokens
 */
function* tokenizer(str) {

    function newKeyword(kw) {
        return { type: "keyword", value: kw };
    }

    function newIdentifier(value) {
        return { type: "identifier", value: value.trim() };
    }

    let identifier=false;
    let accumulator=[];

    for (let i = 0, len = str.length ; i < len; i++) {

        switch (str[i]) {

            case '(': case ')': case '=': case '&': case '|': case '!': case '~': case '>': case '<':

                if (identifier) {
                    identifier = false;
                    let ni = accumulator.join('');
                    accumulator = [];
                    yield newIdentifier(ni);
                }

                switch (str[i]) {

                    // Compound keywords
                    case '~': case '>': case '<':

                        let nextI = i + 1;
                        if (nextI < len && str[nextI] === "=" ) {
                            yield newKeyword(str[i] + str[nextI]);
                            i++;
                        } else {
                            throw new Error("Unexpected token " + str[i] + " at position " + i + ".");
                        }
                        break;

                    // Single char keywords
                    default:
                        yield newKeyword(str[i]);
                        break;
                }
                break;
            default:

                identifier = true;
                accumulator.push(str[i]);
                break;
        }
    }
}

/**
 * Stream wrapper for {Array} object
 * @param data
 * @param data.array array to be wrapped
 * @param data.pos current position to be used
 * @constructor
 */
function StreamWrapper(data) {
    this.array = data.array;
    this.pos = data.pos;
}

/**
 * Produces immutable stream from array object
 * @param array
 * @returns {StreamWrapper}
 */
StreamWrapper.fromArray = function(array) {
    return new StreamWrapper({ pos: 0, array: array.slice() });
};

StreamWrapper.prototype = {

    isEmpty: function() { return this.pos >= this.array.length; },

    head: function() {
        if(this.isEmpty()) {
            throw new Error("StreamWrapper is empty")
        }
        return this.array[this.pos];
    },

    tail: function() {

        if(this.isEmpty()) {
            throw new Error("StreamWrapper is empty")
        }
        return new StreamWrapper({
            array: this.array,
            pos: this.pos + 1
        });
    }
};

/**
 * Tree
 */
function Tree(val1_, val2_) {
    this._1 = val1_;
    this._2 = val2_;
}

Tree.prototype = {

    /**
     * Tree structure equality check
     * @param that {object} to be compared with
     */
    equals: function(that) {

        function eq(left, right) {
            return (left instanceof Tree ? left.equals(right) : left === right);
        }

        if (that instanceof Tree) {
            return eq(this._1, that._1) && eq(this._2, that._2)
        } else {
            return false;
        }
    }
};

Tree.toLdapFilterList = function(tree) {
    return new LdapFilterList(tree._1, tree._2);
};

Tree.toLdapItem = function(tree) {

    return new LdapItem({
        attr: tree._1._1,
        filtertype: tree._1._2,
        value: tree._2
    });
};

Tree.toLdapFilter = function(tree) {
    return tree._1._2;
};

/**
 *
 * @param impl {function()} which accepts input stream of tokens and returns some
 * parse result.
 * @constructor
 */
function AbstractParser(impl) {
    this.f = impl;
}

/**
 * Produces parser which always succeeds
 * @param value result of successful parser
 * @returns {AbstractParser} which always succeeds
 */
AbstractParser.Success = function(value) {

    return new AbstractParser(function(input) {

        return {
            success: true,
            value: value,
            input: input
        }
    });
};

AbstractParser.prototype = {

    /**
     * Tries to parse given string value to any implementation of {LdapSyntaxEntryTrait}
     * @param str {string} string query
     * @return parse result.
     *
     *   It could be successful:
     *   {
     *       success: true,
     *       value: {LdapFilterList},
     *       input: {StreamWrapper}
     *   }
     *
     *   ... or it could be failure:
     *   {
     *       success: false,
     *       error: "Error message goes here",
     *       input: {StreamWrapper}
     *   }
     */
    parse: function(str) {

        var stream = StreamWrapper.fromArray(Array.from(tokenizer(str)));
        return this.$parse(stream);
    },

    $parse: function(input) {
        return this.f.call(this, input);
    },

    /**
     * Combines `this` as AbstractParser[A] and result of `other` function which is AbstractParser[B] into AbstractParser[A | B] which
     * can produce value of type A, value of type B or failure.
     * @param other {function} which produces some AbstractParser[B] i.e. () -> AbstractParser[B]
     * @returns {AbstractParser}
     */
    $or: function(other) {

        const self = this;
        return new AbstractParser(function(input) {

            let leftResult = self.$parse(input);
            if (leftResult.success) return leftResult;
            else return other().$parse(input)
        });
    },

    /**
     * Combines `this` as AbstractParser[A] and result of `other` function which is AbstractParser[B] into AbstractParser[A ~ B] which
     * produces composite type `A ~ B`. it will succeed if both parsers succeeded on given input. Composite type is pepresented by {Tree}
     * object.
     * @param other {function} which produces some AbstractParser[B] i.e. () -> AbstractParser[B]
     * @returns {AbstractParser}
     */
    $then: function(other) {

        const self = this;
        return new AbstractParser(function(input) {

            let leftResult = self.$parse(input);
            if (leftResult.success) {

                let rightResult = other().$parse(leftResult.input);
                if (rightResult.success) {
                    return {
                        success: true,
                        value: new Tree(leftResult.value, rightResult.value),
                        input: rightResult.input
                    };
                } else {
                    return rightResult;
                }
            } else {
                return leftResult;
            }
        });
    },

    /**
     * Transforms `this` as AbstractParser[A] to AbstractParser[B]
     * @param f a function A -> B
     * @returns {AbstractParser}
     */
    map: function(f) {

        const self = this;
        return new AbstractParser(function (input) {

            let result = self.$parse(input);
            if (result.success) {

                result = {
                    success: true,
                    value: f.call(self, result.value),
                    input: result.input
                };
            }

            return result;
        });
    },

    /**
     * Transforms `this` as AbstractParser[A] to AbstractParser[Array[A]]
     * @return {AbstractParser}
     */
    times: function() {

        const self = this;
        return self.$then(function() { return self.times(); })
            .map(function(p) {

                if (p instanceof Tree) {
                    return [p._1].concat(p._2)
                }
                else { throw new Error("Come up with some idea") }
            })
            .$or(function() { return AbstractParser.Success([]); });
    }
};

const LdapParser = function() {

    function token(value, p) {

        return function() {

            return new AbstractParser(function(input) {

                let result = { success: false, error: "expected " + value, input: input };

                if (!input.isEmpty() && p(input.head())) {
                    result = { success: true, value: input.head().value, input: input.tail(), error: null };
                }
                return result;
            });
        }
    }

    /* Grammar primitives */
    const nothing = new AbstractParser(function() {
        return { success: false, error: "Nothing case" };
    });

    function keyword(value) {

        return token(value, function(head) {
           return head.type === "keyword" && head.value === value;
        });
    }

    function identifier() {

        return token("identifier", function(head) {
            return head.type == "identifier";
        });
    }

    /* Products */
    var P = {

        filter: function() {

            return nothing.$or(keyword("(")).$then(P.filtercomp).$then(keyword(")"))
                .map(Tree.toLdapFilter);
        },

        filtercomp: function() {
            return nothing.$or(P.and).$or(P.or).$or(P.item);
        },

        and: function() {
            return nothing.$or(keyword("&")).$then(P.filterlist)
                .map(Tree.toLdapFilterList);
        },

        or: function() {
            return nothing.$or(keyword("|")).$then(P.filterlist)
                .map(Tree.toLdapFilterList);
        },

        filterlist: function() {

            return nothing.$or(P.filterlistSeq).$or(P.filter);
        },

        filterlistSeq: function() {
            return P.filter().times();
        },

        item: function() {
            return P.simple().map(Tree.toLdapItem);
        },

        simple: function() {
            return nothing.$or(identifier()).$then(P.filtertype).$then(identifier());
        },

        filtertype: function() {
            return nothing.$or(P.equal).$or(P.approx).$or(P.ge).$or(P.le);
        },

        equal: function() {
            return keyword("=")();
        },

        approx: function() {
            return keyword("~=")();
        },

        ge: function() {
            return keyword(">=")();
        },

        le: function() {
            return keyword("<=")();
        }
    };

    return P.filter();
}();

<|endoftext|>


<commit_before>// Copyright JS Foundation and other contributors, http://js.foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import { getName, getNamePromise } from "./module-resource-name-export.mjs"

assert(getName().endsWith("/module-resource-name-export.mjs") === true);

var collector = {};
getNamePromise(collector).then(() => { collector["end"] = resourceName(); });

function __checkAsync() {
  assert(collector["start"].endsWith("/module-resource-name-export.mjs") === true);
  assert(collector["middle"].endsWith("/module-resource-name-export.mjs") === true);
  assert(collector["end"].endsWith("/module-resource-name.js") === true);
  assert(Object.keys(collector).length === 3);
}
<commit_msg>Fixes module-resource-name.js on win32. (#4481)<commit_after>// Copyright JS Foundation and other contributors, http://js.foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import { getName, getNamePromise } from "./module-resource-name-export.mjs"

assert(getName().endsWith("module-resource-name-export.mjs"));

var collector = {};
getNamePromise(collector).then(() => { collector["end"] = resourceName(); });

function __checkAsync() {
  assert(collector["start"].endsWith("module-resource-name-export.mjs"));
  assert(collector["middle"].endsWith("module-resource-name-export.mjs"));
  assert(collector["end"].endsWith("module-resource-name.js"));
  assert(Object.keys(collector).length === 3);
}
<|endoftext|>


<commit_before>import React, { PropTypes as Types } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { Message } from 'retranslate';

import { InfoTooltip } from '../';

import { getComparison } from '../../comparison/actions';

import './Comparison.scss';

export const Comparison = ({ overlayed, comparison, onCancel }) => {
  const content = (

<Message>comparison.header</Message>

<Message>comparison.intro</Message>

<Message>comparison.call.to.action</Message>

              <Message>comparison.your.gross.salary.today</Message>

              <Message>comparison.expected.index.return</Message>
                <InfoTooltip
                  name={<Message>comparison.expected.index.return.tooltip.header</Message>}
                >
                  <Message>comparison.expected.index.return.tooltip.content</Message>
                </InfoTooltip>

              <input
                type="number" required="true" className="form-control"
                placeholder="2500" id="salary" name="salary"
              />

              <input
                type="text" required="true" className="form-control"
                placeholder="8" id="return" name="return"
              />

                <Message>comparison.output.calculation</Message>
                <Message>comparison.output.old.funds</Message>
                <Message>comparison.output.new.funds</Message>

                  <Message>comparison.output.calculation.first.row</Message>
                  <InfoTooltip
                    name={<Message>comparison.output.calculation.first.row.tooltip.header</Message>}
                  >
                    <Message>comparison.output.calculation.first.row.tooltip.content</Message>
                  </InfoTooltip>

                44500€
                12873€

                <Message>comparison.output.calculation.second.row</Message>
                127857€
                {
                  comparison ? (
                    {comparison.amount}
                  ) : ''
                }

  );

  if (overlayed) {
    return (

            {content}

              <button className="btn btn-secondary mt-4" onClick={onCancel}>
                <Message>comparison.close</Message>
              </button>

    );
  }
  return (

      {content}

  );
};

const noop = () => null;

Comparison.defaultProps = {
  overlayed: false,
  comparison: null,
  onCancel: noop,
};

Comparison.propTypes = {
  overlayed: Types.bool,
  comparison: Types.shape({}),
  onCancel: Types.func,
};

const mapStateToProps = state => ({
  comparison: state.comparison ? state.comparison.comparison : null,
  error: state.comparison ? state.comparison.error : null,
});

const mapDispatchToProps = dispatch => bindActionCreators({
  onSelect: getComparison,
}, dispatch);

const connectToRedux = connect(mapStateToProps, mapDispatchToProps);

export default connectToRedux(Comparison);
<commit_msg>Propagate rate and salary change from UI to state<commit_after>import React, { PropTypes as Types } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { Message } from 'retranslate';

import { InfoTooltip } from '../';

import {
  getComparison,
  changeSalary,
  changeRate,
} from '../../comparison/actions';

import './Comparison.scss';

export const Comparison = ({ overlayed, comparison, onSalaryChange, onRateChange, onCancel }) => {
  const content = (

<Message>comparison.header</Message>

<Message>comparison.intro</Message>

<Message>comparison.call.to.action</Message>

              <Message>comparison.your.gross.salary.today</Message>

              <Message>comparison.expected.index.return</Message>
                <InfoTooltip
                  name="TODO:comparison.expected.index.return.tooltip.header"
                >
                  <Message>comparison.expected.index.return.tooltip.content</Message>
                </InfoTooltip>

              <input
                onChange={event => onSalaryChange(event.target.value)}
                type="number" required="true" className="form-control"
                placeholder="2500" id="salary" name="salary"
              />

              <input
                onChange={event => onRateChange(event.target.value)}
                type="text" required="true" className="form-control"
                placeholder="5" id="return" name="return"
              />

                <Message>comparison.output.calculation</Message>
                <Message>comparison.output.old.funds</Message>
                <Message>comparison.output.new.funds</Message>

                  <Message>comparison.output.calculation.first.row</Message>
                  <InfoTooltip
                    name="TODO: comparison.output.calculation.first.row.tooltip.header"
                  >
                    <Message>comparison.output.calculation.first.row.tooltip.content</Message>
                  </InfoTooltip>

                44500€
                12873€

                <Message>comparison.output.calculation.second.row</Message>
                127857€
                {
                  comparison ? (
                    {comparison.amount}
                  ) : ''
                }

  );

  if (overlayed) {
    return (

            {content}

              <button className="btn btn-secondary mt-4" onClick={onCancel}>
                <Message>comparison.close</Message>
              </button>

    );
  }
  return (

      {content}

  );
};

const noop = () => null;

Comparison.defaultProps = {
  overlayed: false,
  comparison: null,
  onSalaryChange: noop,
  onRateChange: noop,
  onCancel: noop,
};

Comparison.propTypes = {
  overlayed: Types.bool,
  comparison: Types.shape({}),
  onSalaryChange: Types.func,
  onRateChange: Types.func,
  onCancel: Types.func,
};

const mapStateToProps = state => ({
  comparison: state.comparison ? state.comparison.comparison : null,
  error: state.comparison ? state.comparison.error : null,
});

const mapDispatchToProps = dispatch => bindActionCreators({
  onSelect: getComparison,
  onSalaryChange: changeSalary,
  onRateChange: changeRate,
}, dispatch);

const connectToRedux = connect(mapStateToProps, mapDispatchToProps);

export default connectToRedux(Comparison);
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import styled from 'styled-components'
import TextField from 'material-ui/TextField'
import MenuItem from 'material-ui/MenuItem'
import Avatar from 'material-ui/Avatar'
import RaisedButton from 'material-ui/RaisedButton'
import FlatButton from 'material-ui/FlatButton'
import SelectField from 'material-ui/SelectField'
import Snackbar from 'material-ui/Snackbar'
import { connect } from 'react-redux'
import { firebase, helpers } from 'react-redux-firebase'
import Paper from 'material-ui/Paper'
const { dataToJS } = helpers
import Dropzone from 'react-dropzone'

// Path within Database for metadata (also used for file Storage path)
const filesPath = 'uploadedFiles'

const Main = styled.div`
  display: flex;
  flexWrap: wrap;
  justify-content: space-around;
`

const FormContainer = styled.div`
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  align-items: center;
  padding: 10px 10px 10px 10px;
`

const categories = [
  'None',
  'Video & Film',
  'Podcasts',
  'Comics',
  'Comedy',
  'Crafts & DIY',
  'Music',
  'Drawing & Painting',
  'Games',
  'Science',
  'Dance & Theater',
  'Writing',
  'Animation',
  'Photography',
  'Education',
  'Other'
]

class Uploader extends Component {
  render() {
    let dropzoneRef
    return (

        <Dropzone
          ref={node => {
            dropzoneRef = node
          }}
          onDrop={this.props.onDrop}
          style={{ display: 'hidden' }}
        />
        <FlatButton
          label="Change Profile Picture"
          onTouchTap={() => {
            dropzoneRef.open()
          }}
        />

    )
  }
}

const fbWrappedUploader = firebase([filesPath])(Uploader)
const FbUploader = connect(({ firebase }) => ({
  uploadedFiles: dataToJS(firebase, filesPath)
}))(fbWrappedUploader)

class CategoryDropDown extends Component {
  render() {
    return (

        <SelectField
          floatingLabelText="Category"
          value={this.props.value}
          onChange={this.props.onChange}
          maxHeight={200}
        >
          {categories.map((category, index) => <MenuItem key={index} value={category} primaryText={category} />)}
        </SelectField>

    )
  }
}

class EditProfile extends Component {
  constructor(props) {
    super(props)
    this.state = {
      firstName: '',
      lastName: '',
      emailAddress: '',
      category: 'None',
      content: '',
      biography: '',
      ethereumAddress: '',
      openSnackbar: false,
      snackbarMessage: ''
    }
  }

  handleSave = event => {
    const myAddress = this.props.addresses[0]
    const userProfile = {
      firstName: this.state.firstName,
      lastName: this.state.lastName,
      emailAddress: this.state.emailAddress,
      category: this.state.category,
      content: this.state.content,
      biography: this.state.biography,
      photoURL: this.state.photoURL,
      ethereumAddress: myAddress // get address from app state so there is no danger of being manipulated from front-end
    }
    if (this.state.firstName && this.state.lastName && this.state.emailAddress && myAddress) {
      this.props.firebase.set(`/users/${myAddress}`, userProfile).then((success, error) => {
        if (error) {
          console.error(error)
          this.setState({ openSnackbar: true, snackbarMessage: 'Error: Profile not saved' })
        } else {
          this.setState({ openSnackbar: true, snackbarMessage: 'Profile saved' })
        }
      })
    }
  }

  handleCategoryChange = (event, index, value) => {
    this.setState({ category: value })
  }

  handleFieldChange = (stateKey, event, newValue) => {
    const obj = {}
    obj[stateKey] = newValue // so key can be programatically assigned
    this.setState(obj)
  }
  handleFullNameChange = (event, newValue) => {
    if (!newValue) {
      this.setState({ fullNameError: 'Full name is required' })
    } else {
      this.setState({ fullNameError: false })
      this.setState({ fullName: newValue })
    }
  }

  handleBiographyChange = (event, newValue) => {
    this.setState({ biography: newValue })
  }

  onFilesDrop = files => {
    // Uploads files and push's objects containing metadata to database at dbPath
    // uploadFiles(storagePath, files, dbPath)
    this.props.firebase.uploadFiles(filesPath, files, filesPath).then((resolve, reject) => {
      console.log(resolve)
      const photoURL = resolve[0].File.downloadURL
      this.setState({ photoURL: photoURL })
    })
  }

  componentWillReceiveProps() {
    const myAddress = this.props.addresses[0]
    console.log(this.props.users ? this.props.users[myAddress] : this.props.users)
    if (this.props.users && this.props.users[myAddress]) {
      const myProfile = this.props.users[myAddress]
      this.setState({
        firstName: myProfile.firstName,
        lastName: myProfile.lastName,
        emailAddress: myProfile.emailAddress,
        category: myProfile.category,
        content: myProfile.content,
        biography: myProfile.biography,
        photoURL: myProfile.photoURL
      })
    }
  }

  render() {
    return (

        <Paper>
          <FormContainer>
            <Avatar src={this.state.photoURL} size={150} />
            <Uploader onDrop={this.onFilesDrop} />
            <TextField
              floatingLabelText="First Name"
              onChange={(event, newValue) => this.handleFieldChange('firstName', event, newValue)}
              errorText={!this.state.firstName ? 'First Name is Required' : null}
              value={this.state.firstName}
            />
            <TextField
              floatingLabelText="Last Name"
              onChange={(event, newValue) => this.handleFieldChange('lastName', event, newValue)}
              errorText={!this.state.lastName ? 'Last Name is Required' : null}
              value={this.state.lastName}
            />
            <TextField
              floatingLabelText="Email Address"
              onChange={(event, newValue) => this.handleFieldChange('emailAddress', event, newValue)}
              errorText={!this.state.emailAddress ? 'Email Address is Required' : null}
              value={this.state.emailAddress}
            />
            <CategoryDropDown onChange={this.handleCategoryChange} value={this.state.category} />
            <TextField
              floatingLabelText="Biography"
              onChange={(event, newValue) => this.handleFieldChange('biography', event, newValue)}
              value={this.state.biography}
            />
            <TextField
              floatingLabelText="Content I'm Creating"
              onChange={(event, newValue) => this.handleFieldChange('content', event, newValue)}
              value={this.state.content}
            />
            Ethereum Address
            {this.props.addresses[0]}
            <RaisedButton label="Save Profile" primary={true} onTouchTap={this.handleSave} />
            <Snackbar
              open={this.state.openSnackbar}
              message={this.state.snackbarMessage}
              autoHideDuration={4000}
              onRequestClose={this.handleRequestClose}
            />
          </FormContainer>
        </Paper>

    )
  }
}

EditProfile.defaultProps = {
  userProfile: {}
}

const fbWrappedComponent = firebase([{ type: 'once', path: '/users' }, 'uploadedFiles'])(EditProfile)
export default connect(({ firebase }) => ({
  users: dataToJS(firebase, 'users'),
  uploadedFiles: dataToJS(firebase, 'uploadedFiles')
}))(fbWrappedComponent)
<commit_msg>Make uploader a pure component.<commit_after>import React, { Component } from 'react'
import styled from 'styled-components'
import TextField from 'material-ui/TextField'
import MenuItem from 'material-ui/MenuItem'
import Avatar from 'material-ui/Avatar'
import RaisedButton from 'material-ui/RaisedButton'
import FlatButton from 'material-ui/FlatButton'
import SelectField from 'material-ui/SelectField'
import Snackbar from 'material-ui/Snackbar'
import { connect } from 'react-redux'
import { firebase, helpers } from 'react-redux-firebase'
import Paper from 'material-ui/Paper'
const { dataToJS } = helpers
import Dropzone from 'react-dropzone'

// Path within Database for metadata (also used for file Storage path)
const filesPath = 'uploadedFiles'

const Main = styled.div`
  display: flex;
  flexWrap: wrap;
  justify-content: space-around;
`

const FormContainer = styled.div`
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  align-items: center;
  padding: 10px 10px 10px 10px;
`

const categories = [
  'None',
  'Video & Film',
  'Podcasts',
  'Comics',
  'Comedy',
  'Crafts & DIY',
  'Music',
  'Drawing & Painting',
  'Games',
  'Science',
  'Dance & Theater',
  'Writing',
  'Animation',
  'Photography',
  'Education',
  'Other'
]

class Uploader extends Component {
  render() {
    let dropzoneRef
    return (

        <Dropzone
          ref={node => {
            dropzoneRef = node
          }}
          onDrop={this.props.onDrop}
          style={{ display: 'hidden' }}
        />
        <FlatButton
          label="Change Profile Picture"
          onTouchTap={() => {
            dropzoneRef.open()
          }}
        />

    )
  }
}

class CategoryDropDown extends Component {
  render() {
    return (

        <SelectField
          floatingLabelText="Category"
          value={this.props.value}
          onChange={this.props.onChange}
          maxHeight={200}
        >
          {categories.map((category, index) => <MenuItem key={index} value={category} primaryText={category} />)}
        </SelectField>

    )
  }
}

class EditProfile extends Component {
  constructor(props) {
    super(props)
    this.state = {
      firstName: '',
      lastName: '',
      emailAddress: '',
      category: 'None',
      content: '',
      biography: '',
      ethereumAddress: '',
      openSnackbar: false,
      snackbarMessage: ''
    }
  }

  handleSave = event => {
    const myAddress = this.props.addresses[0]
    const userProfile = {
      firstName: this.state.firstName,
      lastName: this.state.lastName,
      emailAddress: this.state.emailAddress,
      category: this.state.category,
      content: this.state.content,
      biography: this.state.biography,
      photoURL: this.state.photoURL,
      ethereumAddress: myAddress // get address from app state so there is no danger of being manipulated from front-end
    }
    if (this.state.firstName && this.state.lastName && this.state.emailAddress && myAddress) {
      this.props.firebase.set(`/users/${myAddress}`, userProfile).then((success, error) => {
        if (error) {
          console.error(error)
          this.setState({ openSnackbar: true, snackbarMessage: 'Error: Profile not saved' })
        } else {
          this.setState({ openSnackbar: true, snackbarMessage: 'Profile saved' })
        }
      })
    }
  }

  handleCategoryChange = (event, index, value) => {
    this.setState({ category: value })
  }

  handleFieldChange = (stateKey, event, newValue) => {
    const obj = {}
    obj[stateKey] = newValue // so key can be programatically assigned
    this.setState(obj)
  }
  handleFullNameChange = (event, newValue) => {
    if (!newValue) {
      this.setState({ fullNameError: 'Full name is required' })
    } else {
      this.setState({ fullNameError: false })
      this.setState({ fullName: newValue })
    }
  }

  handleBiographyChange = (event, newValue) => {
    this.setState({ biography: newValue })
  }

  onFilesDrop = files => {
    // Uploads files and push's objects containing metadata to database at dbPath
    // uploadFiles(storagePath, files, dbPath)
    this.props.firebase.uploadFiles(filesPath, files, filesPath).then((resolve, reject) => {
      console.log(resolve)
      const photoURL = resolve[0].File.downloadURL
      this.setState({ photoURL: photoURL })
    })
  }

  componentWillReceiveProps() {
    const myAddress = this.props.addresses[0]
    console.log(this.props.users ? this.props.users[myAddress] : this.props.users)
    if (this.props.users && this.props.users[myAddress]) {
      const myProfile = this.props.users[myAddress]
      this.setState({
        firstName: myProfile.firstName,
        lastName: myProfile.lastName,
        emailAddress: myProfile.emailAddress,
        category: myProfile.category,
        content: myProfile.content,
        biography: myProfile.biography,
        photoURL: myProfile.photoURL
      })
    }
  }

  render() {
    return (

        <Paper>
          <FormContainer>
            <Avatar src={this.state.photoURL} size={150} />
            <Uploader onDrop={this.onFilesDrop} />
            <TextField
              floatingLabelText="First Name"
              onChange={(event, newValue) => this.handleFieldChange('firstName', event, newValue)}
              errorText={!this.state.firstName ? 'First Name is Required' : null}
              value={this.state.firstName}
            />
            <TextField
              floatingLabelText="Last Name"
              onChange={(event, newValue) => this.handleFieldChange('lastName', event, newValue)}
              errorText={!this.state.lastName ? 'Last Name is Required' : null}
              value={this.state.lastName}
            />
            <TextField
              floatingLabelText="Email Address"
              onChange={(event, newValue) => this.handleFieldChange('emailAddress', event, newValue)}
              errorText={!this.state.emailAddress ? 'Email Address is Required' : null}
              value={this.state.emailAddress}
            />
            <CategoryDropDown onChange={this.handleCategoryChange} value={this.state.category} />
            <TextField
              floatingLabelText="Biography"
              onChange={(event, newValue) => this.handleFieldChange('biography', event, newValue)}
              value={this.state.biography}
            />
            <TextField
              floatingLabelText="Content I'm Creating"
              onChange={(event, newValue) => this.handleFieldChange('content', event, newValue)}
              value={this.state.content}
            />
            Ethereum Address
            {this.props.addresses[0]}
            <RaisedButton label="Save Profile" primary={true} onTouchTap={this.handleSave} />
            <Snackbar
              open={this.state.openSnackbar}
              message={this.state.snackbarMessage}
              autoHideDuration={4000}
              onRequestClose={this.handleRequestClose}
            />
          </FormContainer>
        </Paper>

    )
  }
}

EditProfile.defaultProps = {
  userProfile: {}
}

const fbWrappedComponent = firebase([{ type: 'once', path: '/users' }, 'uploadedFiles'])(EditProfile)
export default connect(({ firebase }) => ({
  users: dataToJS(firebase, 'users'),
  uploadedFiles: dataToJS(firebase, 'uploadedFiles')
}))(fbWrappedComponent)
<|endoftext|>


<commit_before>function init() {

    // Based on https://github.com/bbrizzi/compass
    function rotate(angle) {
	    //compass.setAttribute("transform", "translate(125,125) rotate("+angle+")");
	    compass.style.transform = "rotate("+angle+"deg)";
    }
    if (window.DeviceOrientationEvent) {
        window.addEventListener("deviceorientation", function( event ) {
            //alpha: rotation around z-axis
            var rotateDegrees = 360 - event.alpha;
	        //document.querySelector("#orientation").innerHTML = rotateDegrees;
	        rotate( rotateDegrees );
        }, false);
    }

    // Initialize Swiss map
    if (typeof GeoAdmin == 'undefined') return;
    document.querySelector('#map').style.background = "none";
	document.querySelector('#map').style.width  = window.innerWidth + 'px';
	document.querySelector('#map').style.height = window.innerHeight + 'px';
	var api14 = new GeoAdmin.API();
    var map = api14.createMap({
        div: "map",
        easting: 501670,
        northing: 118760,
        zoom: 5
    });

    var gml = new OpenLayers.Layer.Vector("Point Layer", {
             strategies: [new OpenLayers.Strategy.Fixed()],
             protocol: new OpenLayers.Protocol.HTTP({
                 url: "data/antennes.xml",
                 format: new OpenLayers.Format.OSM()
             }),
             styleMap: new OpenLayers.StyleMap({
                 strokeColor: "#0066cc",
                 fillColor: "#3399ff",
                 pointRadius: 4
             }),
			// http://spatialreference.org/ref/epsg/2056/
			projection: new OpenLayers.Projection("EPSG:2056")
     });

    map.addLayer(gml);

	//console.log(gml);

	navigator.geolocation.getCurrentPosition(function(position) {
		var lonLat =
			new OpenLayers.LonLat(position.coords.longitude, position.coords.latitude)
			  .transform(
				  new OpenLayers.Projection("EPSG:4326"), //transform from WGS 1984
				  map.getProjectionObject() //to Spherical Mercator Projection
				);

		document.querySelector('#closer').onclick = function() {

			map.setCenter(lonLat, 14);

			api14.showMarker({
				iconPath: 'http://make.opendata.ch/forum/uploads/DN2MBMFGGPQX.png',
				graphicHeight: 30, graphicWidth: 30,
				html: '
Swiss Open Data Camp

make.opendata.ch'
			});

			/*console.log(" Latitude: " +
						position.coords.latitude +
					  " Longitude: " +
						position.coords.longitude);*/

		}; // -- end go-closer click

		document.querySelector('#farther').onclick = function() {

			map.setCenter(new OpenLayers.LonLat(684832.5,249677),9);

			api14.showMarker({
				iconPath: 'http://make.opendata.ch/forum/uploads/DN2MBMFGGPQX.png',
				graphicHeight: 30, graphicWidth: 30,
				html: '
Swiss Open Data Camp

make.opendata.ch'
			});

		}; // -- end go-farther click

	}); // -- end geolocation

}
<commit_msg>Cleaned up geo.js<commit_after>function init() {

    // Based on https://github.com/bbrizzi/compass
    function rotate(angle) {
	    //compass.setAttribute("transform", "translate(125,125) rotate("+angle+")");
	    compass.style.transform = "rotate("+angle+"deg)";
    }
    if (window.DeviceOrientationEvent) {
        window.addEventListener("deviceorientation", function( event ) {
            //alpha: rotation around z-axis
            var rotateDegrees = 360 - event.alpha;
	        //document.querySelector("#orientation").innerHTML = rotateDegrees;
	        rotate( rotateDegrees );
        }, false);
    }

    // Initialize Swiss map
    if (typeof GeoAdmin == 'undefined') return;
    //document.querySelector('#map').style.background = "none";
	document.querySelector('#map').style.width  = window.innerWidth + 'px';
	document.querySelector('#map').style.height = window.innerHeight + 'px';
	var api14 = new GeoAdmin.API();
    var map = api14.createMap({
        div: "map",
        easting: 501670,
        northing: 118760,
        zoom: 5
    });

    var gml = new OpenLayers.Layer.Vector("Point Layer", {
             strategies: [new OpenLayers.Strategy.Fixed()],
             protocol: new OpenLayers.Protocol.HTTP({
                 url: "data/antennes.xml",
                 format: new OpenLayers.Format.OSM()
             }),
             styleMap: new OpenLayers.StyleMap({
                 strokeColor: "#0066cc",
                 fillColor: "#3399ff",
                 pointRadius: 4
             }),
			// http://spatialreference.org/ref/epsg/2056/
			projection: new OpenLayers.Projection("EPSG:2056")
     });

    map.addLayer(gml);

	//console.log(gml);

    navigator.geolocation.getCurrentPosition(function(position) {
	    var lonLat =
		    new OpenLayers.LonLat(position.coords.longitude, position.coords.latitude)
		      .transform(
			      new OpenLayers.Projection("EPSG:4326"), //transform from WGS 1984
			      map.getProjectionObject() //to Spherical Mercator Projection
			    );

	    document.querySelector('#closer').onclick = function() {
            alert('come closer..');
		    map.setCenter(lonLat, 14);

		    api14.showMarker({
			    iconPath: 'http://make.opendata.ch/forum/uploads/DN2MBMFGGPQX.png',
			    graphicHeight: 30, graphicWidth: 30,
			    html: '
Swiss Open Data Camp

make.opendata.ch'
		    });

		    /*console.log(" Latitude: " +
					    position.coords.latitude +
				      " Longitude: " +
					    position.coords.longitude);*/

	    }; // -- end go-closer click

	    document.querySelector('#farther').onclick = function() {
            alert('go farther..');
		    map.setCenter(new OpenLayers.LonLat(684832.5,249677),9);

		    api14.showMarker({
			    iconPath: 'http://make.opendata.ch/forum/uploads/DN2MBMFGGPQX.png',
			    graphicHeight: 30, graphicWidth: 30,
			    html: '
Swiss Open Data Camp

make.opendata.ch'
		    });

	    }; // -- end go-farther click

    }); // -- end geolocation

}
<|endoftext|>