<commit_before>import _ from 'lodash'
import {boolMerge} from './utils'

/**
 * QueryBuilder class to build query clauses.
 *
 * @private
 */
export default class QueryBuilder {

  constructor() {
    this._queries = {}
    this._filters = {}
    this._aggs = {}
  }

  get queries() {
    return _.cloneDeep(this._queries)
  }

  /**
   * Apply a query of a given type providing all the necessary arguments,
   * passing these arguments directly to the specified query builder. Merges
   * existing query(s) with the new query.
   *
   * @param  {String}  boolType Name of the query type.
   * @param  {...args} args     Arguments passed to query builder.
   * @returns {QueryBuilder}    Builder class.
   */
  _makeQuery(boolType, ...args) {
    let nested = _.last(args)

    let newQuery = this._buildQuery(...args)

    if (_.isFunction(nested)) {
      let clause = newQuery[_.findKey(newQuery)]
      let builder = new QueryBuilder()
      let recursiveResult = nested(builder)
      if (!_.isEmpty(recursiveResult._aggs)) {clause.aggs = recursiveResult._aggs}
      if (!_.isEmpty(recursiveResult._queries)) {clause.query = recursiveResult._queries}
      if (!_.isEmpty(recursiveResult._filters)) {clause.filter = recursiveResult._filters}
    }

    return boolMerge(newQuery, this._queries, boolType)
  }

  _buildQuery(type, field, value, opts) {
    let clause = {}

    if (field && value && opts) {
      clause = Object.assign({}, opts, {[field]: value})
    } else if (field && value) {
      clause = {[field]: value}
    } else if (field) {
      clause = {field}
    }

    return {[type]: clause}
  }

  _makeFilter(boolType, ...args) {
    let nested = _.last(args)

    let newFilter = this._buildFilter(...args)

    if (_.isFunction(nested)) {
      let clause = newFilter[_.findKey(newFilter)]
      let builder = new QueryBuilder()
      let recursiveResult = nested(builder)

      if (!_.isEmpty(recursiveResult._aggs)) {clause.aggs = recursiveResult._aggs}
      if (!_.isEmpty(recursiveResult._queries)) {clause.query = recursiveResult._queries}
      if (!_.isEmpty(recursiveResult._filters)) {clause.filter = recursiveResult._filters}
    }

    return boolMerge(newFilter, this._filters, boolType)
  }

  _buildFilter(type, field, value, opts) {
    let clause = {}

    if (field && value && opts) {
      clause = Object.assign({}, opts, {[field]: value})
    } else if (field && value) {
      clause = {[field]: value}
    } else if (field) {
      clause = {field}
    }

    return {[type]: clause}
  }

  _makeAggregation(...args) {
    let nested = _.last(args)

    let newAggregation = this._buildAggregation(...args)

    if (_.isFunction(nested)) {
      let clause = newAggregation[_.findKey(newAggregation)]
      let builder = new QueryBuilder()
      let recursiveResult = nested(builder)
      if (!_.isEmpty(recursiveResult._aggs)) {clause.aggs = recursiveResult._aggs}
      if (!_.isEmpty(recursiveResult._queries)) {clause.query = recursiveResult._queries}
      if (!_.isEmpty(recursiveResult._filters)) {clause.filter = recursiveResult._filters}
    }

    return newAggregation
  }

  _buildAggregation(type, field, name, opts) {
    if (_.isObject(name)) {
      let tmp = opts
      opts = name
      name = tmp
    }

    name = name || `agg_${type}_${field}`

    return {
      [name]: {
        [type]: (() => Object.assign({}, {field}, opts))()
      }
    }
  }

  query(...args) {
    this._queries = this._makeQuery('and', ...args)
    return this
  }

  andQuery(...args) {
    this._queries = this._makeQuery('and', ...args)
    return this
  }

  addQuery(...args) {
    this._queries = this._makeQuery('and', ...args)
    return this
  }

  orQuery(...args) {
    this._queries = this._makeQuery('or', ...args)
    return this
  }

  notQuery(...args) {
    this._queries = this._makeQuery('not', ...args)
    return this
  }

  filter(...args) {
    this._filters = this._makeFilter('and', ...args)
    return this
  }

  andFilter(...args) {
    this._filters = this._makeFilter('and', ...args)
    return this
  }

  orFilter(...args) {
    this._filters = this._makeFilter('or', ...args)
    return this
  }

  notFilter(...args) {
    this._filters = this._makeFilter('not', ...args)
    return this
  }

  aggregation(...args) {
    this._aggs = this._makeAggregation(...args)
    return this
  }

  agg(...args) {
    this._aggs = this.aggregation(...args)
    return this
  }

}
<commit_msg>Use _.find to get clause<commit_after>import _ from 'lodash'
import {boolMerge} from './utils'

/**
 * QueryBuilder class to build query clauses.
 *
 * @private
 */
export default class QueryBuilder {

  constructor() {
    this._queries = {}
    this._filters = {}
    this._aggs = {}
  }

  get queries() {
    return _.cloneDeep(this._queries)
  }

  /**
   * Apply a query of a given type providing all the necessary arguments,
   * passing these arguments directly to the specified query builder. Merges
   * existing query(s) with the new query.
   *
   * @param  {String}  boolType Name of the query type.
   * @param  {...args} args     Arguments passed to query builder.
   * @returns {QueryBuilder}    Builder class.
   */
  _makeQuery(boolType, ...args) {
    let nested = _.last(args)

    let newQuery = this._buildQuery(...args)

    if (_.isFunction(nested)) {
      let clause = _.find(newQuery)
      let builder = new QueryBuilder()
      let recursiveResult = nested(builder)
      if (!_.isEmpty(recursiveResult._aggs)) {clause.aggs = recursiveResult._aggs}
      if (!_.isEmpty(recursiveResult._queries)) {clause.query = recursiveResult._queries}
      if (!_.isEmpty(recursiveResult._filters)) {clause.filter = recursiveResult._filters}
    }

    return boolMerge(newQuery, this._queries, boolType)
  }

  _buildQuery(type, field, value, opts) {
    let clause = {}

    if (field && value && opts) {
      clause = Object.assign({}, opts, {[field]: value})
    } else if (field && value) {
      clause = {[field]: value}
    } else if (field) {
      clause = {field}
    }

    return {[type]: clause}
  }

  _makeFilter(boolType, ...args) {
    let nested = _.last(args)

    let newFilter = this._buildFilter(...args)

    if (_.isFunction(nested)) {
      let clause = _.find(newFilter)
      let builder = new QueryBuilder()
      let recursiveResult = nested(builder)

      if (!_.isEmpty(recursiveResult._aggs)) {clause.aggs = recursiveResult._aggs}
      if (!_.isEmpty(recursiveResult._queries)) {clause.query = recursiveResult._queries}
      if (!_.isEmpty(recursiveResult._filters)) {clause.filter = recursiveResult._filters}
    }

    return boolMerge(newFilter, this._filters, boolType)
  }

  _buildFilter(type, field, value, opts) {
    let clause = {}

    if (field && value && opts) {
      clause = Object.assign({}, opts, {[field]: value})
    } else if (field && value) {
      clause = {[field]: value}
    } else if (field) {
      clause = {field}
    }

    return {[type]: clause}
  }

  _makeAggregation(...args) {
    let nested = _.last(args)

    let newAggregation = this._buildAggregation(...args)

    if (_.isFunction(nested)) {
      let clause = _.find(newAggregation)
      let builder = new QueryBuilder()
      let recursiveResult = nested(builder)
      if (!_.isEmpty(recursiveResult._aggs)) {clause.aggs = recursiveResult._aggs}
      if (!_.isEmpty(recursiveResult._queries)) {clause.query = recursiveResult._queries}
      if (!_.isEmpty(recursiveResult._filters)) {clause.filter = recursiveResult._filters}
    }

    return newAggregation
  }

  _buildAggregation(type, field, name, opts) {
    if (_.isObject(name)) {
      let tmp = opts
      opts = name
      name = tmp
    }

    name = name || `agg_${type}_${field}`

    return {
      [name]: {
        [type]: (() => Object.assign({}, {field}, opts))()
      }
    }
  }

  query(...args) {
    this._queries = this._makeQuery('and', ...args)
    return this
  }

  andQuery(...args) {
    this._queries = this._makeQuery('and', ...args)
    return this
  }

  addQuery(...args) {
    this._queries = this._makeQuery('and', ...args)
    return this
  }

  orQuery(...args) {
    this._queries = this._makeQuery('or', ...args)
    return this
  }

  notQuery(...args) {
    this._queries = this._makeQuery('not', ...args)
    return this
  }

  filter(...args) {
    this._filters = this._makeFilter('and', ...args)
    return this
  }

  andFilter(...args) {
    this._filters = this._makeFilter('and', ...args)
    return this
  }

  orFilter(...args) {
    this._filters = this._makeFilter('or', ...args)
    return this
  }

  notFilter(...args) {
    this._filters = this._makeFilter('not', ...args)
    return this
  }

  aggregation(...args) {
    this._aggs = this._makeAggregation(...args)
    return this
  }

  agg(...args) {
    this._aggs = this.aggregation(...args)
    return this
  }

}
<|endoftext|>


<commit_before>var pk = pk || {};
(function(pk) {
    pk.rating = function(opt) {
        var el = opt.element,
            listeners = opt.listeners === undefined ? {} : opt.listeners,
            inputValue = opt.value || el.getAttribute('value') || 0,
            inputDisabled = (opt.disabled || el.getAttribute('disabled')) ? 'disabled' : '',
            inputName = opt.name || el.getAttribute('name') || 'pk-rating-' + pk.getRand(1, 999),
            inputTabIndex = opt.tabindex || el.getAttribute('tabindex') || 0,
            lastVal = inputValue;

        /*jshint multistr:true */
        var str = "
\
            <fieldset>\
                <input type='radio' id='" + inputName + "_5' name='" + inputName + "' value='5' tabindex='" + inputTabIndex + "'/>\
                \
                <input type='radio' id='" + inputName + "_4' name='" + inputName + "' value='4' />\
                \
                <input type='radio' id='" + inputName + "_3' name='" + inputName + "' value='3' />\
                \
                <input type='radio' id='" + inputName + "_2' name='" + inputName + "' value='2' />\
                \
                <input type='radio' id='" + inputName + "_1' name='" + inputName + "' value='1' />\
                \
            </fieldset>\

";
        el = pk.replaceEl(el, str);

        var rEl = [];
        rEl.push(el.children[0].children[8]);
        rEl.push(el.children[0].children[6]);
        rEl.push(el.children[0].children[4]);
        rEl.push(el.children[0].children[2]);
        rEl.push(el.children[0].children[0]);
        pk.bindListeners(listeners, rEl[0]);
        pk.bindListeners(listeners, rEl[1]);
        pk.bindListeners(listeners, rEl[2]);
        pk.bindListeners(listeners, rEl[3]);
        pk.bindListeners(listeners, rEl[4]);

        pk.bindEvent("mousewheel", el, function(e) {
            pk.preventBubble(e);
            var offset = 1;
            if (e.wheelDelta > 0 || e.detail < 0) {
                offset = -1;
            }
            obj.val(obj.val() + offset);
        });

        function clickHandler() {
            if (lastVal === obj.val()) {
                obj.val(obj.val() - 1);
            }
            lastVal = obj.val();
        }
        for (var i = 0; i < rEl.length; i++) {
            pk.bindEvent('click', rEl[i], clickHandler);
        }
        var obj = {
            0: el,
            val: function(val) {
                if (val === undefined) {
                    for (var r in rEl) {
                        if (rEl[r].checked) {
                            val = rEl[r].value;
                            break;
                        }
                    }
                    return parseInt(val === undefined ? 0 : val, 0);
                }
                val = val < 0 ? 0 : val;
                val = val > 5 ? 5 : val;
                if (val === 0) {
                    rEl[0].checked = true;
                    rEl[0].checked = false;
                } else {
                    rEl[val - 1].checked = true;
                }
                lastVal = val;
            },
            disabled: function(val) {
                if (val !== undefined) {
                    pk.toggleClass(el, 'pk-disabled', val);
                    for (var r in rEl) {
                        pk.attribute(rEl[r], 'disabled', val);
                    }
                }
                return pk.attribute(rEl[0], 'disabled');
            }
        };
        obj.val(inputValue);
        if (inputDisabled) {
            obj.disabled(true);
        }
        return obj;
    };
    return pk;
})(pk);
<commit_msg>Update rating.js<commit_after>var pk = pk || {};
(function(pk) {
    pk.rating = function(opt) {
        var el = opt.element,
            listeners = opt.listeners === undefined ? {} : opt.listeners,
            inputValue = opt.value || el.getAttribute('value') || 0,
            inputDisabled = (opt.disabled || el.getAttribute('disabled')) ? 'disabled' : '',
            inputName = opt.name || el.getAttribute('name') || 'pk-rating-' + pk.getRand(1, 999),
            inputTabIndex = opt.tabindex || el.getAttribute('tabindex') || 0,
            lastVal = inputValue;

        /*jshint multistr:true */
        var str = "
\
            <fieldset>\
                <input type='radio' id='" + inputName + "_5' name='" + inputName + "' value='5' tabindex='" + inputTabIndex + "'/>\
                \
                <input type='radio' id='" + inputName + "_4' name='" + inputName + "' value='4' />\
                \
                <input type='radio' id='" + inputName + "_3' name='" + inputName + "' value='3' />\
                \
                <input type='radio' id='" + inputName + "_2' name='" + inputName + "' value='2' />\
                \
                <input type='radio' id='" + inputName + "_1' name='" + inputName + "' value='1' />\
                \
            </fieldset>\

";
        el = pk.replaceEl(el, str);

        var rEl = [];
        rEl.push(el.children[0].children[8]);
        rEl.push(el.children[0].children[6]);
        rEl.push(el.children[0].children[4]);
        rEl.push(el.children[0].children[2]);
        rEl.push(el.children[0].children[0]);
        pk.bindListeners(listeners, rEl[0]);
        pk.bindListeners(listeners, rEl[1]);
        pk.bindListeners(listeners, rEl[2]);
        pk.bindListeners(listeners, rEl[3]);
        pk.bindListeners(listeners, rEl[4]);

        pk.bindEvent("mousewheel", el, function(e) {
            pk.preventBubble(e);
            var offset = 1;
            if (e.wheelDelta > 0 || e.detail < 0) {
                offset = -1;
            }
            obj.val(obj.val() + offset);
        });

        function clickHandler() {
            if (lastVal === obj.val()) {
                obj.val(obj.val() - 1);
            }
            lastVal = obj.val();
        }
        for (var i = 0; i < rEl.length; i++) {
            pk.bindEvent('click', rEl[i], clickHandler);
        }
        var obj = {
            0: el,
            val: function(val) {
                if (val === undefined) {
                    for (var r in rEl) {
                        if (rEl[r].checked) {
                            val = rEl[r].value;
                            break;
                        }
                    }
                    return parseInt(val === undefined ? 0 : val, 0);
                }
                val = val < 0 ? 0 : val;
                val = val > 5 ? 5 : val;
                if (val === 0) {
                    rEl[0].checked = true;
                    rEl[0].checked = false;
                } else {
                    rEl[val - 1].checked = true;
                }
                lastVal = val;
            },
            disabled: function(val) {
                if (val !== undefined) {
                    pk.toggleClass(el, 'pk-disabled', val);
                    for (var r = 0; r< rEl.length;r++) {
                        pk.attribute(rEl[r], 'disabled', val);
                    }
                }
                return pk.attribute(rEl[0], 'disabled');
            }
        };
        obj.val(inputValue);
        if (inputDisabled) {
            obj.disabled(true);
        }
        return obj;
    };
    return pk;
})(pk);
<|endoftext|>


<commit_before>/**
 * This Source Code is licensed under the MIT license. If a copy of the
 * MIT-license was not distributed with this file, You can obtain one at:
 * http://opensource.org/licenses/mit-license.html.
 *
 * @author: Hein Rutjes (IjzerenHein)
 * @license MIT
 * @copyright Gloey Apps, 2014
 */

/*global define*/
/*eslint no-use-before-define:0 */

/**
 * LayoutNodeManager is a private class used internally by the LayoutControllers and
 * ScrollViews. It manages the layout-nodes that are rendered exposes the layout-context
 * which is passed along to the layout-function.
 *
 * LayoutNodeManager keept track of every rendered node through an ordered single-linked
 * list. The first time the layout-function is called, the linked list is created.
 * After that, the linked list is updated to reflect the output of the layout-function.
 * When the layout is unchanged, then the linked-list exactly matches the order of the
 * accessed nodes in the layout-function, and no layout-nodes need to be created or
 * re-ordered.
 *
 * @module
 */
define(function(require, exports, module) {

    // import dependencies
    var LayoutNode = require('./LayoutNode');
    var LayoutContext = require('./LayoutContext');

    var MAX_POOL_SIZE = 10;

    /**
     * @class
     * @param {LayoutNode} LayoutNode Layout-nodes to create
     * @param {Function} initLayoutNodeFunction function to use when initializing new nodes
     * @alias module:LayoutNodeManager
     */
    function LayoutNodeManager(LayoutNode, initLayoutNodeFn) {
        this.LayoutNode = LayoutNode;
        this._initLayoutNodeFn = initLayoutNodeFn;
        this._context = new LayoutContext({
            next: _contextNextNode.bind(this),
            prev: _contextPrevNode.bind(this),
            get: _contextGetNode.bind(this),
            set: _contextSetNode.bind(this),
            resolveSize: _contextResolveSize.bind(this)
        });
        this._contextState = {
            // enumation state for the context
            //nextSequence: undefined,
            //prevSequence: undefined,
            //next: undefined,
            //prev: undefined
        };
        this._pool = {
            size: 0
            //first: undefined
        };
        //this._first = undefined; // first item in the linked list
        //this._currentRenderNode = undefined; // first node in the view-sequence
        //this._nodesById = undefined;
        //this._trueSizeRequested = false;
    }

    /**
     * Prepares the manager for a new layout iteration, after which it returns the
     * context which can be used by the layout-function.
     *
     * @param {ViewSequence} viewSequence first node to layout
     * @param {Object} [nodesById] dictionary to use when looking up nodes by id
     * @return {LayoutContext} context which can be passed to the layout-function
     */
    LayoutNodeManager.prototype.prepareForLayout = function(viewSequence, nodesById, contextData) {

        // Reset all nodes
        var node = this._first;
        while (node) {
            node.reset();
            node = node._next;
        }

        // Prepare data
        this._nodesById = nodesById;
        this._trueSizeRequested = false;
        this._currentRenderNode = viewSequence ? viewSequence.get() : undefined;

        // Prepare context for enumation
        this._contextState.nextSequence = viewSequence;
        this._contextState.prevSequence = viewSequence;
        this._contextState.next = undefined;
        this._contextState.prev = undefined;

        // Prepare content
        this._context.size = contextData.size;
        this._context.direction = contextData.direction;
        this._context.scrollOffset = contextData.scrollOffset || 0;
        return this._context;
    };

    /**
     * When the layout-function no longer lays-out the node, then it is not longer
     * being invalidated. In this case the destination is set to the removeSpec
     * after which the node is animated towards the remove-spec.
     *
     * @param {Spec} [removeSpec] spec towards which the no longer layed-out nodes are animated
     */
    LayoutNodeManager.prototype.removeNonInvalidatedNodes = function(removeSpec) {
        var node = this._first;
        while (node) {
            if (!node._invalidated && !node._removing) {
                node.remove(removeSpec);
            }
            node = node._next;
        }
    };

    /**
     * Builds the render-spec and destroy any layout-nodes that no longer
     * return a render-spec.
     *
     * @return {Array.Spec} array of Specs
     */
    LayoutNodeManager.prototype.buildSpecAndDestroyUnrenderedNodes = function() {
        var result = [];
        var node = this._first;
        while (node) {
            var spec = node.getSpec();
            if (!spec) {

                // Remove node from linked-list
                if (node._next) {
                    node._next._prev = node._prev;
                }
                if (node._prev) {
                    node._prev._next = node._next;
                }
                else {
                    this._first = node._next;
                }

                // Destroy the node
                var destroyNode = node;
                node = node._next;
                destroyNode.destroy();
                if (this._current === destroyNode) {
                    this._current = undefined;
                }

                // Add node to pool
                if (this._pool.size < MAX_POOL_SIZE) {
                    this._pool.size++;
                    destroyNode._next = this._pool.first;
                    this._pool.first = destroyNode;
                }

                _checkIntegrity.call(this);
            }
            else {

                // Add node to result output
                result.push(spec);
                node = node._next;
            }
        }
        return result;
    };

    /**
     * Get the layout-node by its renderable.
     *
     * @param {Object} renderable renderable
     * @return {LayoutNode} layout-node or undefined
     */
    LayoutNodeManager.prototype.getNodeByRenderNode = function(renderable) {
        var node = this._first;
        while (node) {
            if (node._spec.renderNode === renderable) {
                return node;
            }
            node = node._next;
        }
        return undefined;
    };

    /**
     * Inserts a layout-node into the linked-list.
     *
     * @param {LayoutNode} node layout-node to insert
     */
    LayoutNodeManager.prototype.insertNode = function(node) {
        node._next = this._first;
        if (this._first) {
            this._first._prev = node;
        }
        this._first = node;
        _checkIntegrity.call(this);
    };

    /**
     * Creates a layout-node
     *
     * @param {Object} renderNode render-node for whom to create a layout-node for
     * @return {LayoutNode} layout-node
     */
    LayoutNodeManager.prototype.createNode = function(renderNode, spec) {
        var layoutNode;
        if (this._pool.first) {
            layoutNode = this._pool.first;
            this._pool.first = layoutNode._next;
            this._pool.size--;
            layoutNode._prev = undefined;
            layoutNode._next = undefined;
            layoutNode.constructor.apply(layoutNode, arguments);
        }
        else {
            layoutNode = new this.LayoutNode(renderNode, spec);
        }
        if (this._initLayoutNodeFn) {
            this._initLayoutNodeFn.call(this, layoutNode, spec);
        }
        return layoutNode;
    };

    /**
     * Checks whether the end of was reached when using next/prev
     * to enumerate the nodes.
     *
     * @param {Boolean} prev prev or next direction
     */
    LayoutNodeManager.prototype.endReached = function(prev) {
        if (prev) {
            if (!this._contextState.prevSequence) {
                return true;
            }
            var prevSequence = this._contextState.prevSequence.getPrevious();
            return !(prevSequence && prevSequence.get());
        }
        else {
            return !(this._contextState.nextSequence && this._contextState.nextSequence.get());
        }
    };

    function _checkIntegrity() {
        /*var node = this._first;
        var count = 0;
        var prevNode;
        while (node) {
            if (!node._prev && (node !== this._first)) {
                throw 'No prev but not first';
            }
            if (node._prev !== prevNode) {
                throw 'Bork';
            }
            prevNode = node;
            node = node._next;
            count++;
        }*/
    }

    function _contextGetCreateAndOrderNodes(renderNode, prev) {

        // The first time this function is called, the current
        // prev/next position is obtained.
        var node;
        if (!this._contextState.next) {
            var currentRenderNode = this._currentRenderNode || renderNode;
            if (this._current && (this._current._spec.renderNode === currentRenderNode)) {
                node = this._current;
            }
            else {
                node = this._first;
                while (node) {
                    if (node._spec.renderNode === currentRenderNode) {
                        break;
                    }
                    node = node._next;
                }
                if (!node) {
                    node = this.createNode(currentRenderNode);
                    node._next = this._first;
                    if (this._first) {
                        this._first._prev = node;
                    }
                    this._first = node;
                }
                this._current = node;
            }
            this._contextState.next = node;
            this._contextState.prev = node;

            _checkIntegrity.call(this);
        }

        // Check whether node already exist at the correct position
        // in the linked-list. If so, return that node immediately
        // and advanced the prev/next pointer for the next/prev
        // lookup operation.
        if (prev) {
            if (this._contextState.prev) {
                var prevNode = this._contextState.prev._prev;
                if (prevNode && (prevNode._spec.renderNode === renderNode)) {
                    this._contextState.prev = prevNode;
                    _checkIntegrity.call(this);
                    return prevNode;
                }
            }
        }
        else {
            var nextNode = this._contextState.next;
            if (nextNode && (nextNode._spec.renderNode === renderNode)) {
                if (nextNode._next) {
                    this._contextState.next = nextNode._next;
                }
                _checkIntegrity.call(this);
                return nextNode;
            }
        }

        // Lookup the node anywhere in the list..
        node = this._first;
        while (node) {
            if (node._spec.renderNode === renderNode) {
                break;
            }
            node = node._next;
        }

        // Create new node if neccessary
        if (!node) {
            node = this.createNode(renderNode);
            node._next = undefined;
            node._prev = undefined;
        }

        // Node existed, remove from linked-list
        else {
            if (node._next) {
                node._next._prev = node._prev;
            }
            if (node._prev) {
                node._prev._next = node._next;
            }
            else {
                this._first = node._next;
            }
            node._next = undefined;
            node._prev = undefined;
            _checkIntegrity.call(this);
        }

        // Insert node into the linked list
        if (prev) {
            if (this._contextState.prev._prev) {
                node._prev = this._contextState.prev._prev;
                this._contextState.prev._prev._next = node;
            }
            else {
                this._first = node;
            }
            this._contextState.prev._prev = node;
            node._next = this._contextState.prev;
            this._contextState.prev = node;
        }
        else {
            if (this._contextState.next._next) {
                node._next = this._contextState.next._next;
                this._contextState.next._next._prev = node;
            }
            this._contextState.next._next = node;
            node._prev = this._contextState.next;
            this._contextState.next = node;
        }
        _checkIntegrity.call(this);

        return node;
    }

    /**
     * Get the next layout-node
     */
    function _contextNextNode() {

        // Get the next node from the sequence
        if (!this._contextState.nextSequence) {
            return undefined;
        }
        var renderNode = this._contextState.nextSequence.get();
        if (!renderNode) {
            this._contextState.nextSequence = undefined;
            return undefined;
        }
        this._contextState.nextSequence = this._contextState.nextSequence.getNext();

        // Get the layout-node by its render-node
        return _contextGetCreateAndOrderNodes.call(this, renderNode, false);
    }

    /**
     * Get the next layout-node
     */
    function _contextPrevNode() {

        // Get the previous node from the sequence
        if (!this._contextState.prevSequence) {
            return undefined;
        }
        this._contextState.prevSequence = this._contextState.prevSequence.getPrevious();
        if (!this._contextState.prevSequence) {
            return undefined;
        }
        var renderNode = this._contextState.prevSequence.get();
        if (!renderNode) {
            this._contextState.prevSequence = undefined;
            return undefined;
        }

        // Get the layout-node by its render-node
        return _contextGetCreateAndOrderNodes.call(this, renderNode, true);
    }

    /**
     * Get the layout-node by id.
     */
     function _contextGetNode(nodeId) {
        if (!nodeId) {
            return undefined;
        }
        if (nodeId instanceof LayoutNode) {
            return nodeId;
        }
        var renderNode;
        if ((nodeId instanceof String) || (typeof nodeId === 'string')) {
            if (!this._nodesById) {
               return undefined;
            }
            renderNode = this._nodesById[nodeId];
            if (!renderNode) {
                return undefined;
            }

            // If the result was an array, return that instead
            if (renderNode instanceof Array) {
                return renderNode;
            }
        }
        else {
            renderNode = nodeId;
        }

        // Get the layout-node by its render-node
        return _contextGetCreateAndOrderNodes.call(this, renderNode);
    }

    /**
     * Set the node content
     */
    function _contextSetNode(node, set) {
        node = _contextGetNode.call(this, node);
        if (!node) {
            return this;
        }
        else {
            node.set(set);
        }
    }

    /**
     * Resolve the size of the layout-node from the renderable itsself
     */
    function _contextResolveSize(node, parentSize) {
        node = _contextGetNode.call(this, node);
        if (!node) {
            return this;
        }
        var size = node._spec.renderNode.getSize(true);
        if (!size) {
            size = node._spec.renderNode.getSize(false);
            if (!size) {
                size = parentSize;
            }
            else {
                var newSize = [size[0], size[1]];
                if (size[0] === true) {
                   newSize[0] = 0; // true cannot be resolved at this stage, try again next render-cycle
                   this._trueSizeRequested = true;
                   node._spec.trueSizeRequested = true;
                }
                else if (size[0] === undefined) {
                    newSize[0] = parentSize[0];
                }
                if (size[1] === true) {
                   newSize[1] = 0; // true cannot be resolved at this stage, try again next render-cycle
                   this._trueSizeRequested = true;
                   node._spec.trueSizeRequested = true;
                }
                else if (size[1] === undefined) {
                    newSize[1] = parentSize[1];
                }
                size = newSize;
            }
        }
        return size;
    }

    module.exports = LayoutNodeManager;
});
<commit_msg>Added LayoutNodeManager.forEach function to enumerating the layout-nodes<commit_after>/**
 * This Source Code is licensed under the MIT license. If a copy of the
 * MIT-license was not distributed with this file, You can obtain one at:
 * http://opensource.org/licenses/mit-license.html.
 *
 * @author: Hein Rutjes (IjzerenHein)
 * @license MIT
 * @copyright Gloey Apps, 2014
 */

/*global define*/
/*eslint no-use-before-define:0 */

/**
 * LayoutNodeManager is a private class used internally by the LayoutControllers and
 * ScrollViews. It manages the layout-nodes that are rendered exposes the layout-context
 * which is passed along to the layout-function.
 *
 * LayoutNodeManager keept track of every rendered node through an ordered single-linked
 * list. The first time the layout-function is called, the linked list is created.
 * After that, the linked list is updated to reflect the output of the layout-function.
 * When the layout is unchanged, then the linked-list exactly matches the order of the
 * accessed nodes in the layout-function, and no layout-nodes need to be created or
 * re-ordered.
 *
 * @module
 */
define(function(require, exports, module) {

    // import dependencies
    var LayoutNode = require('./LayoutNode');
    var LayoutContext = require('./LayoutContext');

    var MAX_POOL_SIZE = 10;

    /**
     * @class
     * @param {LayoutNode} LayoutNode Layout-nodes to create
     * @param {Function} initLayoutNodeFunction function to use when initializing new nodes
     * @alias module:LayoutNodeManager
     */
    function LayoutNodeManager(LayoutNode, initLayoutNodeFn) {
        this.LayoutNode = LayoutNode;
        this._initLayoutNodeFn = initLayoutNodeFn;
        this._context = new LayoutContext({
            next: _contextNextNode.bind(this),
            prev: _contextPrevNode.bind(this),
            get: _contextGetNode.bind(this),
            set: _contextSetNode.bind(this),
            resolveSize: _contextResolveSize.bind(this)
        });
        this._contextState = {
            // enumation state for the context
            //nextSequence: undefined,
            //prevSequence: undefined,
            //next: undefined,
            //prev: undefined
        };
        this._pool = {
            size: 0
            //first: undefined
        };
        //this._first = undefined; // first item in the linked list
        //this._currentRenderNode = undefined; // first node in the view-sequence
        //this._nodesById = undefined;
        //this._trueSizeRequested = false;
    }

    /**
     * Prepares the manager for a new layout iteration, after which it returns the
     * context which can be used by the layout-function.
     *
     * @param {ViewSequence} viewSequence first node to layout
     * @param {Object} [nodesById] dictionary to use when looking up nodes by id
     * @return {LayoutContext} context which can be passed to the layout-function
     */
    LayoutNodeManager.prototype.prepareForLayout = function(viewSequence, nodesById, contextData) {

        // Reset all nodes
        var node = this._first;
        while (node) {
            node.reset();
            node = node._next;
        }

        // Prepare data
        this._nodesById = nodesById;
        this._trueSizeRequested = false;
        this._currentRenderNode = viewSequence ? viewSequence.get() : undefined;

        // Prepare context for enumation
        this._contextState.nextSequence = viewSequence;
        this._contextState.prevSequence = viewSequence;
        this._contextState.next = undefined;
        this._contextState.prev = undefined;

        // Prepare content
        this._context.size = contextData.size;
        this._context.direction = contextData.direction;
        this._context.scrollOffset = contextData.scrollOffset || 0;
        return this._context;
    };

    /**
     * When the layout-function no longer lays-out the node, then it is not longer
     * being invalidated. In this case the destination is set to the removeSpec
     * after which the node is animated towards the remove-spec.
     *
     * @param {Spec} [removeSpec] spec towards which the no longer layed-out nodes are animated
     */
    LayoutNodeManager.prototype.removeNonInvalidatedNodes = function(removeSpec) {
        var node = this._first;
        while (node) {
            if (!node._invalidated && !node._removing) {
                node.remove(removeSpec);
            }
            node = node._next;
        }
    };

    /**
     * Builds the render-spec and destroy any layout-nodes that no longer
     * return a render-spec.
     *
     * @return {Array.Spec} array of Specs
     */
    LayoutNodeManager.prototype.buildSpecAndDestroyUnrenderedNodes = function() {
        var result = [];
        var node = this._first;
        while (node) {
            var spec = node.getSpec();
            if (!spec) {

                // Remove node from linked-list
                if (node._next) {
                    node._next._prev = node._prev;
                }
                if (node._prev) {
                    node._prev._next = node._next;
                }
                else {
                    this._first = node._next;
                }

                // Destroy the node
                var destroyNode = node;
                node = node._next;
                destroyNode.destroy();
                if (this._current === destroyNode) {
                    this._current = undefined;
                }

                // Add node to pool
                if (this._pool.size < MAX_POOL_SIZE) {
                    this._pool.size++;
                    destroyNode._next = this._pool.first;
                    this._pool.first = destroyNode;
                }

                _checkIntegrity.call(this);
            }
            else {

                // Add node to result output
                result.push(spec);
                node = node._next;
            }
        }
        return result;
    };

    /**
     * Get the layout-node by its renderable.
     *
     * @param {Object} renderable renderable
     * @return {LayoutNode} layout-node or undefined
     */
    LayoutNodeManager.prototype.getNodeByRenderNode = function(renderable) {
        var node = this._first;
        while (node) {
            if (node._spec.renderNode === renderable) {
                return node;
            }
            node = node._next;
        }
        return undefined;
    };

    /**
     * Inserts a layout-node into the linked-list.
     *
     * @param {LayoutNode} node layout-node to insert
     */
    LayoutNodeManager.prototype.insertNode = function(node) {
        node._next = this._first;
        if (this._first) {
            this._first._prev = node;
        }
        this._first = node;
        _checkIntegrity.call(this);
    };

    /**
     * Creates a layout-node
     *
     * @param {Object} renderNode render-node for whom to create a layout-node for
     * @return {LayoutNode} layout-node
     */
    LayoutNodeManager.prototype.createNode = function(renderNode, spec) {
        var layoutNode;
        if (this._pool.first) {
            layoutNode = this._pool.first;
            this._pool.first = layoutNode._next;
            this._pool.size--;
            layoutNode._prev = undefined;
            layoutNode._next = undefined;
            layoutNode.constructor.apply(layoutNode, arguments);
        }
        else {
            layoutNode = new this.LayoutNode(renderNode, spec);
        }
        if (this._initLayoutNodeFn) {
            this._initLayoutNodeFn.call(this, layoutNode, spec);
        }
        return layoutNode;
    };

    /**
     * Enumates all layout-nodes.
     *
     * @param {Function} callback Function that is called every node
     */
    LayoutNodeManager.prototype.forEach = function(callback) {
        var node = this._first;
        while (node) {
            callback(node);
            node = node._next;
        }
    };

    /**
     * Checks whether the end of was reached when using next/prev
     * to enumerate the nodes.
     *
     * @param {Boolean} prev prev or next direction
     */
    LayoutNodeManager.prototype.endReached = function(prev) {
        if (prev) {
            if (!this._contextState.prevSequence) {
                return true;
            }
            var prevSequence = this._contextState.prevSequence.getPrevious();
            return !(prevSequence && prevSequence.get());
        }
        else {
            return !(this._contextState.nextSequence && this._contextState.nextSequence.get());
        }
    };

    function _checkIntegrity() {
        /*var node = this._first;
        var count = 0;
        var prevNode;
        while (node) {
            if (!node._prev && (node !== this._first)) {
                throw 'No prev but not first';
            }
            if (node._prev !== prevNode) {
                throw 'Bork';
            }
            prevNode = node;
            node = node._next;
            count++;
        }*/
    }

    function _contextGetCreateAndOrderNodes(renderNode, prev) {

        // The first time this function is called, the current
        // prev/next position is obtained.
        var node;
        if (!this._contextState.next) {
            var currentRenderNode = this._currentRenderNode || renderNode;
            if (this._current && (this._current._spec.renderNode === currentRenderNode)) {
                node = this._current;
            }
            else {
                node = this._first;
                while (node) {
                    if (node._spec.renderNode === currentRenderNode) {
                        break;
                    }
                    node = node._next;
                }
                if (!node) {
                    node = this.createNode(currentRenderNode);
                    node._next = this._first;
                    if (this._first) {
                        this._first._prev = node;
                    }
                    this._first = node;
                }
                this._current = node;
            }
            this._contextState.next = node;
            this._contextState.prev = node;

            _checkIntegrity.call(this);
        }

        // Check whether node already exist at the correct position
        // in the linked-list. If so, return that node immediately
        // and advanced the prev/next pointer for the next/prev
        // lookup operation.
        if (prev) {
            if (this._contextState.prev) {
                var prevNode = this._contextState.prev._prev;
                if (prevNode && (prevNode._spec.renderNode === renderNode)) {
                    this._contextState.prev = prevNode;
                    _checkIntegrity.call(this);
                    return prevNode;
                }
            }
        }
        else {
            var nextNode = this._contextState.next;
            if (nextNode && (nextNode._spec.renderNode === renderNode)) {
                if (nextNode._next) {
                    this._contextState.next = nextNode._next;
                }
                _checkIntegrity.call(this);
                return nextNode;
            }
        }

        // Lookup the node anywhere in the list..
        node = this._first;
        while (node) {
            if (node._spec.renderNode === renderNode) {
                break;
            }
            node = node._next;
        }

        // Create new node if neccessary
        if (!node) {
            node = this.createNode(renderNode);
            node._next = undefined;
            node._prev = undefined;
        }

        // Node existed, remove from linked-list
        else {
            if (node._next) {
                node._next._prev = node._prev;
            }
            if (node._prev) {
                node._prev._next = node._next;
            }
            else {
                this._first = node._next;
            }
            node._next = undefined;
            node._prev = undefined;
            _checkIntegrity.call(this);
        }

        // Insert node into the linked list
        if (prev) {
            if (this._contextState.prev._prev) {
                node._prev = this._contextState.prev._prev;
                this._contextState.prev._prev._next = node;
            }
            else {
                this._first = node;
            }
            this._contextState.prev._prev = node;
            node._next = this._contextState.prev;
            this._contextState.prev = node;
        }
        else {
            if (this._contextState.next._next) {
                node._next = this._contextState.next._next;
                this._contextState.next._next._prev = node;
            }
            this._contextState.next._next = node;
            node._prev = this._contextState.next;
            this._contextState.next = node;
        }
        _checkIntegrity.call(this);

        return node;
    }

    /**
     * Get the next layout-node
     */
    function _contextNextNode() {

        // Get the next node from the sequence
        if (!this._contextState.nextSequence) {
            return undefined;
        }
        var renderNode = this._contextState.nextSequence.get();
        if (!renderNode) {
            this._contextState.nextSequence = undefined;
            return undefined;
        }
        this._contextState.nextSequence = this._contextState.nextSequence.getNext();

        // Get the layout-node by its render-node
        return _contextGetCreateAndOrderNodes.call(this, renderNode, false);
    }

    /**
     * Get the next layout-node
     */
    function _contextPrevNode() {

        // Get the previous node from the sequence
        if (!this._contextState.prevSequence) {
            return undefined;
        }
        this._contextState.prevSequence = this._contextState.prevSequence.getPrevious();
        if (!this._contextState.prevSequence) {
            return undefined;
        }
        var renderNode = this._contextState.prevSequence.get();
        if (!renderNode) {
            this._contextState.prevSequence = undefined;
            return undefined;
        }

        // Get the layout-node by its render-node
        return _contextGetCreateAndOrderNodes.call(this, renderNode, true);
    }

    /**
     * Get the layout-node by id.
     */
     function _contextGetNode(nodeId) {
        if (!nodeId) {
            return undefined;
        }
        if (nodeId instanceof LayoutNode) {
            return nodeId;
        }
        var renderNode;
        if ((nodeId instanceof String) || (typeof nodeId === 'string')) {
            if (!this._nodesById) {
               return undefined;
            }
            renderNode = this._nodesById[nodeId];
            if (!renderNode) {
                return undefined;
            }

            // If the result was an array, return that instead
            if (renderNode instanceof Array) {
                return renderNode;
            }
        }
        else {
            renderNode = nodeId;
        }

        // Get the layout-node by its render-node
        return _contextGetCreateAndOrderNodes.call(this, renderNode);
    }

    /**
     * Set the node content
     */
    function _contextSetNode(node, set) {
        node = _contextGetNode.call(this, node);
        if (!node) {
            return this;
        }
        else {
            node.set(set);
        }
    }

    /**
     * Resolve the size of the layout-node from the renderable itsself
     */
    function _contextResolveSize(node, parentSize) {
        node = _contextGetNode.call(this, node);
        if (!node) {
            return this;
        }
        var size = node._spec.renderNode.getSize(true);
        if (!size) {
            size = node._spec.renderNode.getSize(false);
            if (!size) {
                size = parentSize;
            }
            else {
                var newSize = [size[0], size[1]];
                if (size[0] === true) {
                   newSize[0] = 0; // true cannot be resolved at this stage, try again next render-cycle
                   this._trueSizeRequested = true;
                   node._spec.trueSizeRequested = true;
                }
                else if (size[0] === undefined) {
                    newSize[0] = parentSize[0];
                }
                if (size[1] === true) {
                   newSize[1] = 0; // true cannot be resolved at this stage, try again next render-cycle
                   this._trueSizeRequested = true;
                   node._spec.trueSizeRequested = true;
                }
                else if (size[1] === undefined) {
                    newSize[1] = parentSize[1];
                }
                size = newSize;
            }
        }
        return size;
    }

    module.exports = LayoutNodeManager;
});
<|endoftext|>


<commit_before>define(
  ['require', './lib/platform', './lib/couch', './lib/dav', './lib/webfinger', './lib/hardcoded'],
  function (require, platform, couch, dav, webfinger, hardcoded) {
    var getStorageInfo = function (userAddress, cb) {
        webfinger.getStorageInfo(userAddress, {timeout: 3000}, function(err, storageInfo) {
          if(err) {
            hardcoded.guessStorageInfo(userAddress, {timeout: 3000}, function(err2, data) {
              cb(err2, data);
            });
          } else {
            cb(err, storageInfo);
          }
        });
      },
      createOAuthAddress = function (storageInfo, categories, redirectUri) {
        if(storageInfo.type.split('#')[0]=='pds-remotestorage-00') {
          scopeParts = categories;
        } else {
          scopeParts=[];
          for(category in categories) {
            if(category=='public') {
              scopeParts.push('legacy:full');
            } else {
              scopeParts.push(category+':full');
            }
          }
        }
        var terms = [
          'redirect_uri='+encodeURIComponent(redirectUri),
          'scope='+encodeURIComponent(scopeParts.join(',')),
          'response_type=token',
          'client_id='+encodeURIComponent(redirectUri)
        ];
        return storageInfo.auth.href + (storageInfo.auth.href.indexOf('?') === -1?'?':'&') + terms.join('&');
      },
      getDriver = function (type, cb) {
        cb(type === 'pds-remotestorage-00#couchdb'?couch:dav);
      },
      resolveKey = function(storageInfo, zone, category, item) {
        return storageInfo.href + '/' + zone + '/' + category
          + (storageInfo.legacySuffix ? storageInfo.legacySuffix : '')
          + '/' + (item[0] == '_' ? 'u' : '') + item;
      },
      createClient = function (storageInfo, category, token) {
        if(category == 'public') {
          zone = 'public';
          category = 'legacy';
        } else {
          zone = 'private';
        }
        return {
          get: function (key, cb) {
            if(typeof(key) != 'string') {
              cb('argument "key" should be a string');
            } else {
              getDriver(storageInfo.type, function (d) {
                d.get(resolveKey(storageInfo, zone, category, key), token, cb);
              });
            }
          },
          put: function (key, value, cb) {
            if(typeof(key) != 'string') {
              cb('argument "key" should be a string');
            } else if(typeof(value) != 'string') {
              cb('argument "value" should be a string');
            } else {
              getDriver(storageInfo.type, function (d) {
                d.put(resolveKey(storageInfo, zone, category, key), value, token, cb);
              });
            }
          },
          'delete': function (key, cb) {
            if(typeof(key) != 'string') {
              cb('argument "key" should be a string');
            } else {
              getDriver(storageInfo.type, function (d) {
                d['delete'](resolveKey(storageInfo, zone, category, key), token, cb);
              });
            }
          }
        };
      },
      receiveToken = function () {
        var params, kv;
        if(location.hash.length > 0) {
          params = location.hash.split('&');
          for(var i = 0; i < params.length; i++) {
            if(params[i][0]=='#') {
              params[i] = params[i].substring(1);
            }
            if(params[i].substring(0, 'access_token='.length)=='access_token=') {
              return params[i].substring('access_token='.length);
            }
          }
        }
        return null;
      };

  return {
    getStorageInfo     : getStorageInfo,
    createOAuthAddress : createOAuthAddress,
    createClient       : createClient,
    receiveToken       : receiveToken
  };
});
<commit_msg>get rid of zone in resolveKey() function - DON'T USE, TESTS FAILING<commit_after>define(
  ['require', './lib/platform', './lib/couch', './lib/dav', './lib/webfinger', './lib/hardcoded'],
  function (require, platform, couch, dav, webfinger, hardcoded) {
    var getStorageInfo = function (userAddress, cb) {
        webfinger.getStorageInfo(userAddress, {timeout: 3000}, function(err, storageInfo) {
          if(err) {
            hardcoded.guessStorageInfo(userAddress, {timeout: 3000}, function(err2, data) {
              cb(err2, data);
            });
          } else {
            cb(err, storageInfo);
          }
        });
      },
      createOAuthAddress = function (storageInfo, categories, redirectUri) {
        if(storageInfo.type.split('#')[0]=='pds-remotestorage-00') {
          scopeParts = categories;
        } else {
          scopeParts=[];
          for(category in categories) {
            if(category=='public') {
              scopeParts.push('legacy:full');
            } else {
              scopeParts.push(category+':full');
            }
          }
        }
        var terms = [
          'redirect_uri='+encodeURIComponent(redirectUri),
          'scope='+encodeURIComponent(scopeParts.join(',')),
          'response_type=token',
          'client_id='+encodeURIComponent(redirectUri)
        ];
        return storageInfo.auth.href + (storageInfo.auth.href.indexOf('?') === -1?'?':'&') + terms.join('&');
      },
      getDriver = function (type, cb) {
        cb(type === 'pds-remotestorage-00#couchdb'?couch:dav);
      },
      resolveKey = function(storageInfo, category, item) {
        return storageInfo.href + '/' + category
          + (storageInfo.legacySuffix ? storageInfo.legacySuffix : '')
          + '/' + (item[0] == '_' ? 'u' : '') + item;
      },
      createClient = function (storageInfo, category, token) {
        return {
          get: function (key, cb) {
            if(typeof(key) != 'string') {
              cb('argument "key" should be a string');
            } else {
              getDriver(storageInfo.type, function (d) {
                d.get(resolveKey(storageInfo, category, key), token, cb);
              });
            }
          },
          put: function (key, value, cb) {
            if(typeof(key) != 'string') {
              cb('argument "key" should be a string');
            } else if(typeof(value) != 'string') {
              cb('argument "value" should be a string');
            } else {
              getDriver(storageInfo.type, function (d) {
                d.put(resolveKey(storageInfo, category, key), value, token, cb);
              });
            }
          },
          'delete': function (key, cb) {
            if(typeof(key) != 'string') {
              cb('argument "key" should be a string');
            } else {
              getDriver(storageInfo.type, function (d) {
                d['delete'](resolveKey(storageInfo, category, key), token, cb);
              });
            }
          }
        };
      },
      receiveToken = function () {
        var params, kv;
        if(location.hash.length > 0) {
          params = location.hash.split('&');
          for(var i = 0; i < params.length; i++) {
            if(params[i][0]=='#') {
              params[i] = params[i].substring(1);
            }
            if(params[i].substring(0, 'access_token='.length)=='access_token=') {
              return params[i].substring('access_token='.length);
            }
          }
        }
        return null;
      };

  return {
    getStorageInfo     : getStorageInfo,
    createOAuthAddress : createOAuthAddress,
    createClient       : createClient,
    receiveToken       : receiveToken
  };
});
<|endoftext|>


<commit_before>import Settings from '../util/Settings';
import debounce from './debounce';
import Event from '../util/Event';
import Util from '../util/Util';

const CLS_FIXED_WINDOW = 'fixed-window-open';

export const EVENT_BEFORE_FIXED_ADD = 'flexcss.fixedWindow.beforeAdd';
export const EVENT_AFTER_FIXED_REMOVE = 'flexcss.fixedWindow.afterRemove';

/**
 * @type {string}
 */
export const ALLOW_ELEMENT_OVERFLOW_TOUCH = 'data-overflow';

/**
 * @type {FixedWindow}
 */
let fixedWindowInstance;

export default class FixedWindow {

    constructor() {
        this.widgets = [];
        this.currentScrollTop = 0;
        this.fixedScreenConstraints = [];
        this.windowWidth = 0;
        this.isFixedWindowActive = false;
        this.touchListener = null;
    }

    /**
     * Adds a constraint to detect if the window needs to be changed when the screensize changes
     *
     * @param {Function} widget
     * @param {Function} fixedBreakpointFn gets a width argument, return true to open a window
     */
    addScreenConstraint(widget, fixedBreakpointFn) {
        this.fixedScreenConstraints[widget] = fixedBreakpointFn;
    }

    /**
     * @returns {null|DestroyableWidget}
     */
    getCurrentWidget() {
        return this.widgets.length > 0 ? this.widgets[this.widgets.length - 1] : null;
    }

    /**
     * @private
     */
    _checkFixedNeeded() {
        if (this.widgets.length === 0) {
            return;
        }
        const widgets = new Set(this.widgets);
        const widgetsThatRequireFixedWindow = Array.from(widgets).some(({ widget }) => {
            return this.fixedScreenConstraints[widget] && this.fixedScreenConstraints[widget](this.windowWidth);
        });
        if (!widgetsThatRequireFixedWindow) {
            this._removeFixedContainer();
        } else {
            this._addFixedContainer();
        }
    }

    /**
     * @private
     */
    _addFixedContainer() {
        if (this.isFixedWindowActive) {
            return;
        }
        Event.dispatchAndFire(global.document, EVENT_BEFORE_FIXED_ADD, {
            detail: this.getCurrentWidget()
        });
        // this causes layout and should be optimized
        // At lest we write in a batch later
        Settings.get().scrollbarUpdateNodes.map((n) => {
            let foundProperty = 'paddingRight';
            let direction = 1;
            let node = n;
            if (n instanceof Array) {
                const [whatNode, property, d] = n;
                foundProperty = property;
                node = whatNode;
                direction = d || 1;
            }
            return {
                node,
                property: foundProperty,
                value: `${parseInt(global.getComputedStyle(node)[foundProperty], 10) +
                (!node.__fixedWindowMod__ ? (Settings.getScrollbarWidth() * direction) : 0)}px`
            };
        }).forEach((d) => {
            d.node.__fixedWindowMod__ = true;
            d.node.style[d.property] = d.value;
        });

        this.touchListener = (e) => {
            e.preventDefault();
        };

        let shouldNotMoveUp = false;
        let shouldNotMoveDown = false;
        let neverScroll = false;
        let lastClientY = 0;
        this.touchStartListener = (e) => {
            let { element } = this.getCurrentWidget();
            const closestOverflow = Util.closestCallback(e.target,
                (el) => el instanceof HTMLTextAreaElement ||
                (el.hasAttribute && el.hasAttribute(ALLOW_ELEMENT_OVERFLOW_TOUCH)));
            if (closestOverflow && closestOverflow.scrollHeight !== closestOverflow.offsetHeight) {
                element = closestOverflow;
            }
            if (Util.isPartOfNode(e.target, element)) {
                neverScroll = element.scrollHeight === element.offsetHeight;
                lastClientY = e.touches[0].clientY;
                // never allow scrolling when there is nothing to scroll
                if (neverScroll) {
                    return false;
                }
                if (element.scrollTop === 0) {
                    element.scrollTop = 1;
                    shouldNotMoveUp = true;
                } else if (element.scrollHeight === element.scrollTop + element.offsetHeight) {
                    shouldNotMoveDown = true;
                    element.scrollTop -= 1;
                }
            }
        };

        global.addEventListener('touchmove', this.touchListener);
        global.document.body.addEventListener('touchstart', this.touchStartListener);

        this.touchMoveListener = (e) => {
            const { element } = this.getCurrentWidget();
            if (Util.isPartOfNode(e.target, element)) {
                const { clientY } = e.touches[0];
                const isScrollingDown = (lastClientY - clientY) > 0;
                lastClientY = clientY;

                if (neverScroll) {
                    neverScroll = false;
                    return false;
                }

                if ((!shouldNotMoveDown && isScrollingDown) ||
                    (shouldNotMoveDown && !isScrollingDown) ||
                    (!shouldNotMoveDown && !shouldNotMoveUp && !isScrollingDown) ||
                    (shouldNotMoveDown && shouldNotMoveUp && isScrollingDown)
                ) {
                    e.stopImmediatePropagation();
                }

                shouldNotMoveUp = false;
                shouldNotMoveDown = false;
            }
        };
        global.document.body.addEventListener('touchmove', this.touchMoveListener);

        global.document.documentElement.classList.add(CLS_FIXED_WINDOW);
        this.isFixedWindowActive = true;
    }

    /**
     * @private
     */
    _removeFixedContainer() {
        if (this.isFixedWindowActive) {
            // cleanup event listeners
            global.removeEventListener('touchmove', this.touchListener);
            global.document.body.removeEventListener('touchstart', this.touchStartListener);
            global.document.body.removeEventListener('touchmove', this.touchMoveListener);

            // reset scrollbar nodes
            Settings.get().scrollbarUpdateNodes.forEach((node) => {
                if (node instanceof Array) {
                    const [whatNode, property] = node;
                    delete whatNode.__fixedWindowMod__;
                    whatNode.style[property] = '';
                } else {
                    delete node.__fixedWindowMod__;
                    node.style.paddingRight = '';
                }
            });
            global.document.documentElement.classList.remove(CLS_FIXED_WINDOW);
            Event.dispatchAndFire(global.document, EVENT_AFTER_FIXED_REMOVE);
            this.isFixedWindowActive = false;
        }
    }

    /**
     * Will close a window when no widgets are opened that need one
     */
    resizeListener() {
        this.windowWidth = global.innerWidth;
        this._checkFixedNeeded();
    }

    /**
     * @returns {FixedWindow}
     */
    static getInstance() {
        if (!fixedWindowInstance) {
            fixedWindowInstance = new FixedWindow();
            fixedWindowInstance.windowWidth = global.innerWidth;
            const eventHandler = fixedWindowInstance.resizeListener.bind(fixedWindowInstance);
            global.addEventListener(
                'resize',
                debounce(eventHandler, 500)
            );
            global.addEventListener('orientationchange', eventHandler);
        }
        return fixedWindowInstance;
    }

    /**
     * Request a close of the fixed window
     */
    close() {
        this.widgets.pop();
        if (this.widgets.length === 0) {
            this._removeFixedContainer();
        }
    }

    /**
     * Request to open a fixed windows
     * @param {Object|DestroyableWidget} instance
     * @param {HTMLElement} element
     */
    open(instance, element) {
        let fixed = false;
        if (typeof instance === 'object') {
            const widget = instance.constructor;
            const fixedWidget = this.fixedScreenConstraints[instance.constructor];
            if (widget && fixedWidget) {
                fixed = fixedWidget(this.windowWidth);
            }
            const length = this.widgets.length;
            this.widgets.push(
                {
                    widget,
                    element
                }
            );
            // open a new window if there is no window active
            if (length === 0) {
                if (fixed) {
                    this._addFixedContainer();
                }
            }
        }
    }
}
<commit_msg>fix(FixedWindow): fixed stacking<commit_after>import Settings from '../util/Settings';
import debounce from './debounce';
import Event from '../util/Event';
import Util from '../util/Util';

const CLS_FIXED_WINDOW = 'fixed-window-open';

export const EVENT_BEFORE_FIXED_ADD = 'flexcss.fixedWindow.beforeAdd';
export const EVENT_AFTER_FIXED_REMOVE = 'flexcss.fixedWindow.afterRemove';

/**
 * @type {string}
 */
export const ALLOW_ELEMENT_OVERFLOW_TOUCH = 'data-overflow';

/**
 * @type {FixedWindow}
 */
let fixedWindowInstance;

export default class FixedWindow {

    constructor() {
        this.widgets = [];
        this.currentScrollTop = 0;
        this.fixedScreenConstraints = [];
        this.windowWidth = 0;
        this.isFixedWindowActive = false;
        this.touchListener = null;
    }

    /**
     * Adds a constraint to detect if the window needs to be changed when the screensize changes
     *
     * @param {Function} widget
     * @param {Function} fixedBreakpointFn gets a width argument, return true to open a window
     */
    addScreenConstraint(widget, fixedBreakpointFn) {
        this.fixedScreenConstraints[widget] = fixedBreakpointFn;
    }

    /**
     * @returns {null|DestroyableWidget}
     */
    getCurrentWidget() {
        return this.widgets.length > 0 ? this.widgets[this.widgets.length - 1] : null;
    }

    /**
     * @private
     */
    _checkFixedNeeded() {
        if (this.widgets.length === 0) {
            return;
        }
        const widgets = new Set(this.widgets);
        const widgetsThatRequireFixedWindow = Array.from(widgets).some(({ widget }) => {
            return this.fixedScreenConstraints[widget] && this.fixedScreenConstraints[widget](this.windowWidth);
        });
        if (!widgetsThatRequireFixedWindow) {
            this._removeFixedContainer();
        } else {
            this._addFixedContainer();
        }
    }

    /**
     * @private
     */
    _addFixedContainer() {
        if (this.isFixedWindowActive) {
            return;
        }
        Event.dispatchAndFire(global.document, EVENT_BEFORE_FIXED_ADD, {
            detail: this.getCurrentWidget()
        });
        // this causes layout and should be optimized
        // At lest we write in a batch later
        Settings.get().scrollbarUpdateNodes.map((n) => {
            let foundProperty = 'paddingRight';
            let direction = 1;
            let node = n;
            if (n instanceof Array) {
                const [whatNode, property, d] = n;
                foundProperty = property;
                node = whatNode;
                direction = d || 1;
            }
            return {
                node,
                property: foundProperty,
                value: `${parseInt(global.getComputedStyle(node)[foundProperty], 10) +
                (!node.__fixedWindowMod__ ? (Settings.getScrollbarWidth() * direction) : 0)}px`
            };
        }).forEach((d) => {
            d.node.__fixedWindowMod__ = true;
            d.node.style[d.property] = d.value;
        });

        this.touchListener = (e) => {
            e.preventDefault();
        };

        let shouldNotMoveUp = false;
        let shouldNotMoveDown = false;
        let neverScroll = false;
        let lastClientY = 0;
        this.touchStartListener = (e) => {
            let { element } = this.getCurrentWidget();
            const closestOverflow = Util.closestCallback(e.target,
                (el) => el instanceof HTMLTextAreaElement ||
                (el.hasAttribute && el.hasAttribute(ALLOW_ELEMENT_OVERFLOW_TOUCH)));
            if (closestOverflow && closestOverflow.scrollHeight !== closestOverflow.offsetHeight) {
                element = closestOverflow;
            }
            if (Util.isPartOfNode(e.target, element)) {
                neverScroll = element.scrollHeight === element.offsetHeight;
                lastClientY = e.touches[0].clientY;
                // never allow scrolling when there is nothing to scroll
                if (neverScroll) {
                    return false;
                }
                if (element.scrollTop === 0) {
                    element.scrollTop = 1;
                    shouldNotMoveUp = true;
                } else if (element.scrollHeight === element.scrollTop + element.offsetHeight) {
                    shouldNotMoveDown = true;
                    element.scrollTop -= 1;
                }
            }
        };

        global.addEventListener('touchmove', this.touchListener);
        global.document.body.addEventListener('touchstart', this.touchStartListener);

        this.touchMoveListener = (e) => {
            const { element } = this.getCurrentWidget();
            if (Util.isPartOfNode(e.target, element)) {
                const { clientY } = e.touches[0];
                const isScrollingDown = (lastClientY - clientY) > 0;
                lastClientY = clientY;

                if (neverScroll) {
                    neverScroll = false;
                    return false;
                }

                if ((!shouldNotMoveDown && isScrollingDown) ||
                    (shouldNotMoveDown && !isScrollingDown) ||
                    (!shouldNotMoveDown && !shouldNotMoveUp && !isScrollingDown) ||
                    (shouldNotMoveDown && shouldNotMoveUp && isScrollingDown)
                ) {
                    e.stopImmediatePropagation();
                }

                shouldNotMoveUp = false;
                shouldNotMoveDown = false;
            }
        };
        global.document.body.addEventListener('touchmove', this.touchMoveListener);

        global.document.documentElement.classList.add(CLS_FIXED_WINDOW);
        this.isFixedWindowActive = true;
    }

    /**
     * @private
     */
    _removeFixedContainer() {
        if (this.isFixedWindowActive) {
            // cleanup event listeners
            global.removeEventListener('touchmove', this.touchListener);
            global.document.body.removeEventListener('touchstart', this.touchStartListener);
            global.document.body.removeEventListener('touchmove', this.touchMoveListener);

            // reset scrollbar nodes
            Settings.get().scrollbarUpdateNodes.forEach((node) => {
                if (node instanceof Array) {
                    const [whatNode, property] = node;
                    delete whatNode.__fixedWindowMod__;
                    whatNode.style[property] = '';
                } else {
                    delete node.__fixedWindowMod__;
                    node.style.paddingRight = '';
                }
            });
            global.document.documentElement.classList.remove(CLS_FIXED_WINDOW);
            Event.dispatchAndFire(global.document, EVENT_AFTER_FIXED_REMOVE);
            this.isFixedWindowActive = false;
        }
    }

    /**
     * Will close a window when no widgets are opened that need one
     */
    resizeListener() {
        this.windowWidth = global.innerWidth;
        this._checkFixedNeeded();
    }

    /**
     * @returns {FixedWindow}
     */
    static getInstance() {
        if (!fixedWindowInstance) {
            fixedWindowInstance = new FixedWindow();
            fixedWindowInstance.windowWidth = global.innerWidth;
            const eventHandler = fixedWindowInstance.resizeListener.bind(fixedWindowInstance);
            global.addEventListener(
                'resize',
                debounce(eventHandler, 500)
            );
            global.addEventListener('orientationchange', eventHandler);
        }
        return fixedWindowInstance;
    }

    /**
     * Request a close of the fixed window
     */
    close() {
        this.widgets.pop();
        if (this.widgets.length === 0) {
            this._removeFixedContainer();
        }
    }

    /**
     * Request to open a fixed windows
     * @param {Object|DestroyableWidget} instance
     * @param {HTMLElement} element
     */
    open(instance, element) {
        let fixed = false;
        if (typeof instance === 'object') {
            const widget = instance.constructor;
            const fixedWidget = this.fixedScreenConstraints[instance.constructor];
            if (widget && fixedWidget) {
                fixed = fixedWidget(this.windowWidth);
            }
            this.widgets.push(
                {
                    widget,
                    element
                }
            );
            // open a new window if there is no window active
            if (!this.isFixedWindowActive && fixed) {
                this._addFixedContainer();
            }
        }
    }
}
<|endoftext|>


<commit_before>/**
 * Copyright 2013-2015, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @typechecks
 * @providesModule ReactCSSTransitionGroup
 */

'use strict';

var React = require('React');

var assign = require('Object.assign');

var ReactTransitionGroup = React.createFactory(
  require('ReactTransitionGroup')
);
var ReactCSSTransitionGroupChild = React.createFactory(
  require('ReactCSSTransitionGroupChild')
);

var ReactCSSTransitionGroup = React.createClass({
  displayName: 'ReactCSSTransitionGroup',

  propTypes: {
    transitionName: React.PropTypes.oneOfType([
      React.PropTypes.string,
      React.PropTypes.shape({
        enter: React.PropTypes.string,
        leave: React.PropTypes.string,
        active: React.PropTypes.string
      }),
      React.PropTypes.shape({
        enter: React.PropTypes.string,
        enterActive: React.PropTypes.string,
        leave: React.PropTypes.string,
        leaveActive: React.PropTypes.string,
        appear: React.PropTypes.string,
        appearActive: React.PropTypes.string
      })
    ]).isRequired,
    transitionAppear: React.PropTypes.bool,
    transitionEnter: React.PropTypes.bool,
    transitionLeave: React.PropTypes.bool,
  },

  getDefaultProps: function() {
    return {
      transitionAppear: false,
      transitionEnter: true,
      transitionLeave: true,
    };
  },

  _wrapChild: function(child) {
    // We need to provide this childFactory so that
    // ReactCSSTransitionGroupChild can receive updates to name, enter, and
    // leave while it is leaving.
    return ReactCSSTransitionGroupChild(
      {
        name: this.props.transitionName,
        appear: this.props.transitionAppear,
        enter: this.props.transitionEnter,
        leave: this.props.transitionLeave,
      },
      child
    );
  },

  render: function() {
    return (
      ReactTransitionGroup(
        assign({}, this.props, {childFactory: this._wrapChild})
      )
    );
  },
});

module.exports = ReactCSSTransitionGroup;
<commit_msg>Fix a couple lint issues as a followup for #3761<commit_after>/**
 * Copyright 2013-2015, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @typechecks
 * @providesModule ReactCSSTransitionGroup
 */

'use strict';

var React = require('React');

var assign = require('Object.assign');

var ReactTransitionGroup = React.createFactory(
  require('ReactTransitionGroup')
);
var ReactCSSTransitionGroupChild = React.createFactory(
  require('ReactCSSTransitionGroupChild')
);

var ReactCSSTransitionGroup = React.createClass({
  displayName: 'ReactCSSTransitionGroup',

  propTypes: {
    transitionName: React.PropTypes.oneOfType([
      React.PropTypes.string,
      React.PropTypes.shape({
        enter: React.PropTypes.string,
        leave: React.PropTypes.string,
        active: React.PropTypes.string,
      }),
      React.PropTypes.shape({
        enter: React.PropTypes.string,
        enterActive: React.PropTypes.string,
        leave: React.PropTypes.string,
        leaveActive: React.PropTypes.string,
        appear: React.PropTypes.string,
        appearActive: React.PropTypes.string,
      }),
    ]).isRequired,
    transitionAppear: React.PropTypes.bool,
    transitionEnter: React.PropTypes.bool,
    transitionLeave: React.PropTypes.bool,
  },

  getDefaultProps: function() {
    return {
      transitionAppear: false,
      transitionEnter: true,
      transitionLeave: true,
    };
  },

  _wrapChild: function(child) {
    // We need to provide this childFactory so that
    // ReactCSSTransitionGroupChild can receive updates to name, enter, and
    // leave while it is leaving.
    return ReactCSSTransitionGroupChild(
      {
        name: this.props.transitionName,
        appear: this.props.transitionAppear,
        enter: this.props.transitionEnter,
        leave: this.props.transitionLeave,
      },
      child
    );
  },

  render: function() {
    return (
      ReactTransitionGroup(
        assign({}, this.props, {childFactory: this._wrapChild})
      )
    );
  },
});

module.exports = ReactCSSTransitionGroup;
<|endoftext|>


<commit_before>import React from 'react';
import TabView from '@economist/component-tabview';
import AnimatedPanel from '@economist/component-animatedpanel';
import ArticleStore from '@economist/component-articlestore';
import Gobbet from '@economist/component-wifgobbet';
import ImageCaption from '@economist/component-imagecaption';
import Video from '@economist/component-video';
import Omniture from '@economist/component-omniture';
import NotFound from '@economist/component-404';
import Gallery from '@economist/component-gallery';
import Authenticated from '@economist/component-authenticated';

const authenticated = new Authenticated();
const articleStore = new ArticleStore('/content');
const articleComponent = {
  Image: 'img',
  Pullquote: 'blockquote',
  ArticleSubHead: 'h3',
  Gobbet,
  ImageCaption,
  Video,
  AnimatedPanel,
  Gallery,
};
export default class ArticleTemplate extends React.Component {

  static get propTypes() {
    return {
      id: React.PropTypes.string.isRequired,
    };
  }

  static get store() {
    return articleStore;
  }

  static addComponentType(component, name) {
    articleComponent[name || component.name] = component;
  }

  renderJSONContents(contents) {
    return (contents || []).map((contentPiece, key) => {
      if (typeof contentPiece === 'string') {
        return (

        );
      }
      const Component = articleComponent[contentPiece.component];
      if (!Component) {
        throw new Error('Unknown component ' + contentPiece.component);
      }
      const children = this.renderJSONContents(contentPiece.content);
      return (
        <Component key={key} {...contentPiece.props}>
          {children}
        </Component>
      );
    });
  }

  renderTabView() {
    const sections = articleStore
      .getWhere((item) => item.id !== this.props.id)
      .reduce((total, article) => {
        const section = article.attributes.section;
        total[section] = total[section] || [];
        total[section].push(article);
        return total;
      }, {});
    return (
      <TabView>
        {Object.keys(sections).map((title, key) => (

            {sections[title].map((article) => (
              <a href={`/article/${article.id}/${article.attributes.slug}`}>

                  <img
                    src={`${article.attributes.tileimage['1.0x']}`}
                    srcSet={this.getSrcSet(article.attributes.tileimage)}
                    alt={article.attributes.imagealt}
                  />

{article.attributes.toc}

            ))}

        ))}
      </TabView>
    );
  }

  getSrcSet(image) {
    return Object.keys(image).map((key) => `${image[key]} ${key}`).join(',');
  }

  renderHeader(attributes) {
    let section = null;
    let flytitle = null;
    let title = null;
    if (attributes.flytitle) {
      flytitle = (

          {attributes.flytitle}

      );
    }
    if (attributes.title) {
      title = (

          {attributes.title}

      );
    }
    if (flytitle || title) {
      if (attributes.section) {
        section = (

            {attributes.section}

        );
      }
      return (

          {section}
          {flytitle}
          {title}

      );
    }
  }

  render() {
    const article = articleStore.get(this.props.id);
    if (!article) {
      return (<NotFound/>);
    }
    const contents = this.renderJSONContents(article.attributes.content);
    const tabs = this.renderTabView();
    const title = article.attributes.title || article.attributes.slug;
    const omnitureProps = {
      pageName: `the_world_if|${article.attributes.section}|${title}`,
      server: 'economist.com',
      channel: article.attributes.section,
      prop1: 'the_world_if',
      prop3: 'web',
      prop4: 'article',
      prop5: title,
      prop11: authenticated.getCookie('mm-logged-in-state') ? 'logged_in' : 'not_logged_in',
      prop13: 'anonymous',
      prop31: new Date(),
    };
    let image = null;
    if (article.attributes.mainimage) {
      image = (<img
        className="ArticleTemplate--image"
        src={`${article.attributes.mainimage['1.0x']}`}
        srcSet={this.getSrcSet(article.attributes.mainimage)}
        alt={article.attributes.imagealt}
        itemProp="image"
      />);
    }
    return (

            {image}
            {this.renderHeader(article.attributes)}

{article.attributes.rubric}

          {contents}

        {tabs}
        <Omniture {...omnitureProps} />

    );
  }
}
<commit_msg>Added microdata to tabview<commit_after>import React from 'react';
import TabView from '@economist/component-tabview';
import AnimatedPanel from '@economist/component-animatedpanel';
import ArticleStore from '@economist/component-articlestore';
import Gobbet from '@economist/component-wifgobbet';
import ImageCaption from '@economist/component-imagecaption';
import Video from '@economist/component-video';
import Omniture from '@economist/component-omniture';
import NotFound from '@economist/component-404';
import Gallery from '@economist/component-gallery';
import Authenticated from '@economist/component-authenticated';

const authenticated = new Authenticated();
const articleStore = new ArticleStore('/content');
const articleComponent = {
  Image: 'img',
  Pullquote: 'blockquote',
  ArticleSubHead: 'h3',
  Gobbet,
  ImageCaption,
  Video,
  AnimatedPanel,
  Gallery,
};
export default class ArticleTemplate extends React.Component {

  static get propTypes() {
    return {
      id: React.PropTypes.string.isRequired,
    };
  }

  static get store() {
    return articleStore;
  }

  static addComponentType(component, name) {
    articleComponent[name || component.name] = component;
  }

  renderJSONContents(contents) {
    return (contents || []).map((contentPiece, key) => {
      if (typeof contentPiece === 'string') {
        return (

        );
      }
      const Component = articleComponent[contentPiece.component];
      if (!Component) {
        throw new Error('Unknown component ' + contentPiece.component);
      }
      const children = this.renderJSONContents(contentPiece.content);
      return (
        <Component key={key} {...contentPiece.props}>
          {children}
        </Component>
      );
    });
  }

  renderTabView() {
    const sections = articleStore
      .getWhere((item) => item.id !== this.props.id)
      .reduce((total, article) => {
        const section = article.attributes.section;
        total[section] = total[section] || [];
        total[section].push(article);
        return total;
      }, {});
    return (
      <TabView>
        {Object.keys(sections).map((title, key) => (

            {sections[title].map((article) => (
              <a href={`/article/${article.id}/${article.attributes.slug}`}>

                  <img
                    src={`${article.attributes.tileimage['1.0x']}`}
                    srcSet={this.getSrcSet(article.attributes.tileimage)}
                    alt={article.attributes.imagealt}
                    itemProp="image"
                  />

{article.attributes.toc}

            ))}

        ))}
      </TabView>
    );
  }

  getSrcSet(image) {
    return Object.keys(image).map((key) => `${image[key]} ${key}`).join(',');
  }

  renderHeader(attributes) {
    let section = null;
    let flytitle = null;
    let title = null;
    if (attributes.flytitle) {
      flytitle = (

          {attributes.flytitle}

      );
    }
    if (attributes.title) {
      title = (

          {attributes.title}

      );
    }
    if (flytitle || title) {
      if (attributes.section) {
        section = (

            {attributes.section}

        );
      }
      return (

          {section}
          {flytitle}
          {title}

      );
    }
  }

  render() {
    const article = articleStore.get(this.props.id);
    if (!article) {
      return (<NotFound/>);
    }
    const contents = this.renderJSONContents(article.attributes.content);
    const tabs = this.renderTabView();
    const title = article.attributes.title || article.attributes.slug;
    const omnitureProps = {
      pageName: `the_world_if|${article.attributes.section}|${title}`,
      server: 'economist.com',
      channel: article.attributes.section,
      prop1: 'the_world_if',
      prop3: 'web',
      prop4: 'article',
      prop5: title,
      prop11: authenticated.getCookie('mm-logged-in-state') ? 'logged_in' : 'not_logged_in',
      prop13: 'anonymous',
      prop31: new Date(),
    };
    let image = null;
    if (article.attributes.mainimage) {
      image = (<img
        className="ArticleTemplate--image"
        src={`${article.attributes.mainimage['1.0x']}`}
        srcSet={this.getSrcSet(article.attributes.mainimage)}
        alt={article.attributes.imagealt}
        itemProp="image"
      />);
    }
    return (

            {image}
            {this.renderHeader(article.attributes)}

{article.attributes.rubric}

          {contents}

        {tabs}
        <Omniture {...omnitureProps} />

    );
  }
}
<|endoftext|>


<commit_before>var _ua = (function(u)
{
	var mobile =
	{
		0: (u.indexOf("windows") != -1 && u.indexOf("phone") != -1)
			|| u.indexOf("iphone") != -1
			|| u.indexOf("ipod") != -1
			|| (u.indexOf("android") != -1 && u.indexOf("mobile") != -1)
			|| (u.indexOf("firefox") != -1 && u.indexOf("mobile") != -1)
			|| u.indexOf("blackberry") != -1,
		iPhone: (u.indexOf("iphone") != -1),
		Android: (u.indexOf("android") != -1 && u.indexOf("mobile") != -1)
	};
	var tablet = (u.indexOf("windows") != -1 && u.indexOf("touch") != -1)
		|| u.indexOf("ipad") != -1
		|| (u.indexOf("android") != -1 && u.indexOf("mobile") == -1)
		|| (u.indexOf("firefox") != -1 && u.indexOf("tablet") != -1)
		|| u.indexOf("kindle") != -1
		|| u.indexOf("silk") != -1
		|| u.indexOf("playbook") != -1;
	var pc = !mobile[0] && !tablet;
	return
	{
		Mobile: mobile,
		Tablet: tablet,
		PC: pc
	};
})(window.navigator.userAgent.toLowerCase());

tm.main(function()
{
    var app = tm.display.CanvasApp("#game-main");
    app.background = "#000";
    app.resize(1280, 720);

    if (_ua.PC === true)
	{

    }
	else
	{
		var label = tm.display.Label("PC端末からプレイしてください。").addChildTo(app.currentScene);
    	label.setPosition(1280/2, 720/2);
    }
    app.run();
});<commit_msg>fix bug<commit_after>var ua = (function(u) {
	var mobile = {
		0: (u.indexOf("windows") != -1 && u.indexOf("phone") != -1)
			|| u.indexOf("iphone") != -1
			|| u.indexOf("ipod") != -1
			|| (u.indexOf("android") != -1 && u.indexOf("mobile") != -1)
			|| (u.indexOf("firefox") != -1 && u.indexOf("mobile") != -1)
			|| u.indexOf("blackberry") != -1,
		iPhone: (u.indexOf("iphone") != -1),
		Android: (u.indexOf("android") != -1 && u.indexOf("mobile") != -1)
	};
	var tablet = (u.indexOf("windows") != -1 && u.indexOf("touch") != -1)
		|| u.indexOf("ipad") != -1
		|| (u.indexOf("android") != -1 && u.indexOf("mobile") == -1)
		|| (u.indexOf("firefox") != -1 && u.indexOf("tablet") != -1)
		|| u.indexOf("kindle") != -1
		|| u.indexOf("silk") != -1
		|| u.indexOf("playbook") != -1;
	var pc = !mobile[0] && !tablet;
	return {
		Mobile: mobile,
		Tablet: tablet,
		PC: pc
	};
})(window.navigator.userAgent.toLowerCase());

tm.main(function() {
    var app = tm.display.CanvasApp("#game-main");
    app.background = "#000";
    app.resize(1280, 720);

    if (ua.PC === true)
	{

    }
	else
	{
		var label = tm.display.Label("PC端末からプレイしてください。").addChildTo(app.currentScene);
    	label.setPosition(1280/2, 720/2);
    }
    app.run();
});<|endoftext|>