<commit_before>// TODO: Add arity checking.
// TODO: Add type checking.
// TODO: Add reduce.
// TODO: Add fold.
// TODO: Add join.

var global = (1, eval)("this");
var print = function(x) { return LANG$$log(x); };
var not = function(x) { return !!x; };
var $lt = function(a, b) {
    var ta = typeof a;
    var tb = typeof b;
    if (ta === tb && (ta === 'string' || ta === 'number')) {
        return a < b;
    }
    throw new LANG$$js_Error('incorrect argument types for <')
};
var $gt = function(a, b) {
    var ta = typeof a;
    var tb = typeof b;
    if (ta === tb && (ta === 'string' || ta === 'number')) {
        return a > b;
    }
    throw new LANG$$js_Error('incorrect argument types for >')
};
var $lt$eq = function(a, b) {
    return $lt(a, b) || a === b;
};
var $gt$eq = function(a, b) {
    return $gt(a, b) || a === b;
};
var $bang$eq = function(a, b) {
    return not($eq(a, b));
};
var not = function(x) {
    return !LANG$$assert_boolean(x);
};
var $pipe$gt = function(x, f) {
    if (typeof f !== 'function') {
        throw new LANG$$js_Error('right-side not a function in |>');
    }
    return f(x);
};
var $at = function(f, x) {
    if (typeof f !== 'function') {
        throw new LANG$$js_Error('left-side not a function in @');
    }
    return f.bind(null, x);
};
var $ampersand = function(a, b) {
    if (arguments.length !== 2) {
        throw new LANG$$js_Error('wrong number of arguments for &');
    }
    return (
        LANG$$assert_boolean(a) &&
        LANG$$assert_boolean(b)
    );
};
var $semicolon = function(a, b) {
    return b;
};
var $pipe = function(a, b) {
    if (arguments.length !== 2) {
        throw new LANG$$js_Error('wrong number of arguments for |');
    }
    return (
        LANG$$assert_boolean(a) ||
        LANG$$assert_boolean(b)
    );
};
var $eq = function recur(a, b) {
    if (typeof a !== typeof b) {
        return false;
    }
    if (a === b) {
        return true;
    }
    // Check if both values are NaN.
    if (a !== a && b !== b) {
        return true;
    }
    if (LANG$$is_object(a) && LANG$$is_object(b)) {
        // TODO: Remove duplicates.
        var ks = LANG$$keys(a).concat(LANG$$keys(b)).sort();
        return ks.every(function(k) {
            return (
                k in a &&
                k in b &&
                recur(a[k], b[k])
            );
        });
    }
    return false;
};
var isNan = function(x) {
    return x !== x;
};
var $plus = function(a, b) {
    if (typeof a === 'number' && typeof b === 'number') {
        return a + b;
    }
    throw new LANG$$js_Error('incorrect argument types for +');
};
var $plus$plus = function(a, b) {
    var A = Array.isArray;
    var S = function(x) { return typeof x === 'string'; };
    var aOk = A(a) && A(b);
    var sOk = S(a) && S(b)
    if (aOk || sOk) {
        return a.concat(b);
    }
    throw new LANG$$js_Error('incorrect argument types for ++');
};
var $minus = function(a, b) { return a - b; };
var $star = function(a, b) { return a * b; };
var $slash = function(a, b) { return a / b; };
var map = function(f, xs) {
    return xs.map(function(x) {
        return f(x);
    });
};
var fold_left = function(f, z, xs) {
    xs.forEach(function(x) {
        z = f(z, x);
    });
    return z;
};
var is_empty = function(xs) {
    return xs.length === 0;
};
var head = function(xs) {
    if (!is_empty(xs)) {
        return xs[0];
    }
    throw new LANG$$js_Error('cannot get head of empty list');
};
var tail = function(xs) {
    return [].slice.call(xs, 1);
};
var reduce = function(f, xs) {
    return fold_left(f, head(xs), tail(xs));
};
var fold_right = function(f, z, xs) {
    return fold_left(flip(f), z, reverse(xs));
};
var reverse = function(xs) {
    return to_array(xs).reverse();
};
var to_array = function(xs) {
    return [].slice.call(xs);
};
var flip = function(f) {
    return function(x, y) {
        return f(y, x);
    };
};
var js_get = function(k, obj) {
    if (k in obj) {
        return obj[k];
    }
    throw new LANG$$js_Error('key ' + k + ' not in ' + obj);
};
var js_set = function(k, v, obj) {
    if (obj === null || typeof obj !== 'object') {
        throw new LANG$$js_Error('cannot set ' + k + ' on ' + obj);
    }
    obj[k] = v;
    return obj;
};
var js_method_get = function(method, obj) {
    return obj[method].bind(obj);
};
var js_method_call = function(method, obj, args) {
    return obj[method].apply(obj, args);
};
var LANG$$object = function(data) {
    if (!LANG$$is_array(data)) {
        throw new LANG$$js_Error(
            'objects can only be constructed from an array'
        );
    }
    var obj = {};
    var i = 0;
    var n = data.length;
    while (i < n) {
        if (typeof data[i][0] !== "string") {
            throw new LANG$$js_Error(
                "object keys must be strings: " + data[i]
            );
        }
        obj[data[i][0]] = data[i][1];
        i++;
    }
    return LANG$$freeze(obj);
};
var LANG$$is_object = function(x) {
    if (arguments.length !== 1) {
        throw new LANG$$js_Error(
            'wrong number of arguments to LANG$$is_object'
        );
    }
    return x !== null && typeof x === 'object';
};
var LANG$$assert_boolean = function(x) {
    if (typeof x !== 'boolean') {
        throw new LANG$$js_Error('not a boolean: ' + x);
    }
    return x;
};
var LANG$$freeze = Object.freeze;
var LANG$$create = Object.create;
var LANG$$is_array = Array.isArray;
var LANG$$keys = Object.keys;
var LANG$$js_get = js_get;
var LANG$$js_method_get = js_method_get;
var LANG$$js_method_call = js_method_call;
var LANG$$js_Error = Error;
var LANG$$custom_logger = null;
var LANG$$global = global;
var LANG$$log = function(x) {
    if (LANG$$custom_logger) {
        LANG$$custom_logger(x);
    } else if (LANG$$global.console && LANG$$global.console.log) {
        LANG$$global.console.log(x);
    }
    return x;
};
<commit_msg>Predef maintenance<commit_after>// TODO: Add arity checking.
// TODO: Add type checking.

var global = (1, eval)("this");
var print = function(x) { return LANG$$log(x); };
var not = function(x) { return !!x; };
var $lt = function(a, b) {
    var ta = typeof a;
    var tb = typeof b;
    if (ta === tb && (ta === 'string' || ta === 'number')) {
        return a < b;
    }
    throw new LANG$$js_Error('incorrect argument types for <')
};
var $gt = function(a, b) {
    var ta = typeof a;
    var tb = typeof b;
    if (ta === tb && (ta === 'string' || ta === 'number')) {
        return a > b;
    }
    throw new LANG$$js_Error('incorrect argument types for >')
};
var $lt$eq = function(a, b) {
    return $lt(a, b) || a === b;
};
var $gt$eq = function(a, b) {
    return $gt(a, b) || a === b;
};
var $bang$eq = function(a, b) {
    return not($eq(a, b));
};
var not = function(x) {
    return !LANG$$assert_boolean(x);
};
var $pipe$gt = function(x, f) {
    if (typeof f !== 'function') {
        throw new LANG$$js_Error('right-side not a function in |>');
    }
    return f(x);
};
var $at = function(f, x) {
    if (typeof f !== 'function') {
        throw new LANG$$js_Error('left-side not a function in @');
    }
    return f.bind(null, x);
};
var $ampersand = function(a, b) {
    if (arguments.length !== 2) {
        throw new LANG$$js_Error('wrong number of arguments for &');
    }
    return (
        LANG$$assert_boolean(a) &&
        LANG$$assert_boolean(b)
    );
};
var $semicolon = function(a, b) {
    return b;
};
var $pipe = function(a, b) {
    if (arguments.length !== 2) {
        throw new LANG$$js_Error('wrong number of arguments for |');
    }
    return (
        LANG$$assert_boolean(a) ||
        LANG$$assert_boolean(b)
    );
};
var $eq = function recur(a, b) {
    if (typeof a !== typeof b) {
        return false;
    }
    if (a === b) {
        return true;
    }
    // Check if both values are NaN.
    if (a !== a && b !== b) {
        return true;
    }
    if (LANG$$is_object(a) && LANG$$is_object(b)) {
        // TODO: Remove duplicates.
        var ks = LANG$$keys(a).concat(LANG$$keys(b)).sort();
        return ks.every(function(k) {
            return (
                k in a &&
                k in b &&
                recur(a[k], b[k])
            );
        });
    }
    return false;
};
var isNan = function(x) {
    return x !== x;
};
var $plus = function(a, b) {
    if (typeof a === 'number' && typeof b === 'number') {
        return a + b;
    }
    throw new LANG$$js_Error('incorrect argument types for +');
};
var $plus$plus = function(a, b) {
    var A = Array.isArray;
    var S = function(x) { return typeof x === 'string'; };
    var aOk = A(a) && A(b);
    var sOk = S(a) && S(b)
    if (aOk || sOk) {
        return a.concat(b);
    }
    throw new LANG$$js_Error('incorrect argument types for ++');
};
var $minus = function(a, b) { return a - b; };
var $star = function(a, b) { return a * b; };
var $slash = function(a, b) { return a / b; };
var map = function(f, xs) {
    return xs.map(function(x) {
        return f(x);
    });
};
var join = function(separator, items) {
    return [].join.call(items, separator);
};
var fold_left = function(f, z, xs) {
    xs.forEach(function(x) {
        z = f(z, x);
    });
    return z;
};
var is_empty = function(xs) {
    return xs.length === 0;
};
var head = function(xs) {
    if (!is_empty(xs)) {
        return xs[0];
    }
    throw new LANG$$js_Error('cannot get head of empty list');
};
var tail = function(xs) {
    return [].slice.call(xs, 1);
};
var reduce = function(f, xs) {
    return fold_left(f, head(xs), tail(xs));
};
var fold_right = function(f, z, xs) {
    return fold_left(flip(f), z, reverse(xs));
};
var reverse = function(xs) {
    return to_array(xs).reverse();
};
var to_array = function(xs) {
    return [].slice.call(xs);
};
var flip = function(f) {
    return function(x, y) {
        return f(y, x);
    };
};
var js_get = function(k, obj) {
    if (k in obj) {
        return obj[k];
    }
    throw new LANG$$js_Error('key ' + k + ' not in ' + obj);
};
var js_set = function(k, v, obj) {
    if (obj === null || typeof obj !== 'object') {
        throw new LANG$$js_Error('cannot set ' + k + ' on ' + obj);
    }
    obj[k] = v;
    return obj;
};
var js_method_get = function(method, obj) {
    return obj[method].bind(obj);
};
var js_method_call = function(method, obj, args) {
    return obj[method].apply(obj, args);
};
var LANG$$object = function(data) {
    if (!LANG$$is_array(data)) {
        throw new LANG$$js_Error(
            'objects can only be constructed from an array'
        );
    }
    var obj = {};
    var i = 0;
    var n = data.length;
    while (i < n) {
        if (typeof data[i][0] !== "string") {
            throw new LANG$$js_Error(
                "object keys must be strings: " + data[i]
            );
        }
        obj[data[i][0]] = data[i][1];
        i++;
    }
    return LANG$$freeze(obj);
};
var LANG$$is_object = function(x) {
    if (arguments.length !== 1) {
        throw new LANG$$js_Error(
            'wrong number of arguments to LANG$$is_object'
        );
    }
    return x !== null && typeof x === 'object';
};
var LANG$$assert_boolean = function(x) {
    if (typeof x !== 'boolean') {
        throw new LANG$$js_Error('not a boolean: ' + x);
    }
    return x;
};
var LANG$$freeze = Object.freeze;
var LANG$$create = Object.create;
var LANG$$is_array = Array.isArray;
var LANG$$keys = Object.keys;
var LANG$$js_get = js_get;
var LANG$$js_method_get = js_method_get;
var LANG$$js_method_call = js_method_call;
var LANG$$js_Error = Error;
var LANG$$custom_logger = null;
var LANG$$global = global;
var LANG$$log = function(x) {
    if (LANG$$custom_logger) {
        LANG$$custom_logger(x);
    } else if (LANG$$global.console && LANG$$global.console.log) {
        LANG$$global.console.log(x);
    }
    return x;
};
<|endoftext|>


<commit_before>var DOM = require('../../util/dom'),
    Handler = require('../Handler'),
    marks = require('./marks');

function CanvasHandler() {
  Handler.call(this);
  this._down = null;
  this._touch = null;
  this._first = true;
}

var base = Handler.prototype;
var prototype = (CanvasHandler.prototype = Object.create(base));
prototype.constructor = CanvasHandler;

prototype.initialize = function(el, pad, obj) {
  // add event listeners
  var canvas = this._canvas = DOM.find(el, 'canvas'),
      that = this;
  this.events.forEach(function(type) {
    canvas.addEventListener(type, function(evt) {
      if (prototype[type]) {
        prototype[type].call(that, evt);
      } else {
        that.fire(type, evt);
      }
    });
  });

  return base.initialize.call(this, el, pad, obj);
};

prototype.canvas = function() {
  return this._canvas;
};

// retrieve the current canvas context
prototype.context = function() {
  return this._canvas.getContext('2d');
};

// supported events
prototype.events = [
  'keydown',
  'keypress',
  'keyup',
  'mousedown',
  'mouseup',
  'mousemove',
  'mouseout',
  'mouseover',
  'click',
  'dblclick',
  'wheel',
  'mousewheel',
  'touchstart',
  'touchmove',
  'touchend'
];

// to keep firefox happy
prototype.DOMMouseScroll = function(evt) {
  this.fire('mousewheel', evt);
};

prototype.mousemove = function(evt) {
  var a = this._active,
      p = this.pickEvent(evt);

  if (p === a) {
    // active item and picked item are the same
    this.fire('mousemove', evt); // fire move
  } else {
    // active item and picked item are different
    this.fire('mouseout', evt);  // fire out for prior active item
    this._active = p;            // set new active item
    this.fire('mouseover', evt); // fire over for new active item
    this.fire('mousemove', evt); // fire move for new active item
  }
};

prototype.mouseout = function(evt) {
  this.fire('mouseout', evt);
  this._active = null;
};

prototype.mousedown = function(evt) {
  this._down = this._active;
  this.fire('mousedown', evt);
};

prototype.click = function(evt) {
  if (this._down === this._active) {
    this.fire('click', evt);
    this._down = null;
  }
};

prototype.touchstart = function(evt) {
  this._touch = this.pickEvent(evt.changedTouches[0]);

  if (this._first) {
    this._active = this._touch;
    this._first = false;
  }

  this.fire('touchstart', evt, true);
};

prototype.touchmove = function(evt) {
  this.fire('touchmove', evt, true);
};

prototype.touchend = function(evt) {
  this.fire('touchend', evt, true);
  this._touch = null;
};

// fire an event
prototype.fire = function(type, evt, touch) {
  var a = touch ? this._touch : this._active,
      h = this._handlers[type], i, len;
  if (h) {
    evt.vegaType = type;
    for (i=0, len=h.length; i<len; ++i) {
      h[i].handler.call(this._obj, evt, a);
    }
  }
};

// add an event handler
prototype.on = function(type, handler) {
  var name = this.eventName(type),
      h = this._handlers;
  (h[name] || (h[name] = [])).push({
    type: type,
    handler: handler
  });
  return this;
};

// remove an event handler
prototype.off = function(type, handler) {
  var name = this.eventName(type),
      h = this._handlers[name], i;
  if (!h) return;
  for (i=h.length; --i>=0;) {
    if (h[i].type !== type) continue;
    if (!handler || h[i].handler === handler) h.splice(i, 1);
  }
  return this;
};

prototype.pickEvent = function(evt) {
  var rect = this._canvas.getBoundingClientRect(),
      pad = this._padding, x, y;
  return this.pick(this._scene,
    x = (evt.clientX - rect.left),
    y = (evt.clientY - rect.top),
    x - pad.left, y - pad.top);
};

// find the scenegraph item at the current mouse position
// x, y -- the absolute x, y mouse coordinates on the canvas element
// gx, gy -- the relative coordinates within the current group
prototype.pick = function(scene, x, y, gx, gy) {
  var g = this.context(),
      mark = marks[scene.marktype];
  return mark.pick.call(this, g, scene, x, y, gx, gy);
};

module.exports = CanvasHandler;
<commit_msg>Fix canvas handler to allow missing canvas element.<commit_after>var DOM = require('../../util/dom'),
    Handler = require('../Handler'),
    marks = require('./marks');

function CanvasHandler() {
  Handler.call(this);
  this._down = null;
  this._touch = null;
  this._first = true;
}

var base = Handler.prototype;
var prototype = (CanvasHandler.prototype = Object.create(base));
prototype.constructor = CanvasHandler;

prototype.initialize = function(el, pad, obj) {
  // add event listeners
  var canvas = this._canvas = DOM.find(el, 'canvas');
  if (canvas) {
    var that = this;
    this.events.forEach(function(type) {
      canvas.addEventListener(type, function(evt) {
        if (prototype[type]) {
          prototype[type].call(that, evt);
        } else {
          that.fire(type, evt);
        }
      });
    });
  }

  return base.initialize.call(this, el, pad, obj);
};

prototype.canvas = function() {
  return this._canvas;
};

// retrieve the current canvas context
prototype.context = function() {
  return this._canvas.getContext('2d');
};

// supported events
prototype.events = [
  'keydown',
  'keypress',
  'keyup',
  'mousedown',
  'mouseup',
  'mousemove',
  'mouseout',
  'mouseover',
  'click',
  'dblclick',
  'wheel',
  'mousewheel',
  'touchstart',
  'touchmove',
  'touchend'
];

// to keep firefox happy
prototype.DOMMouseScroll = function(evt) {
  this.fire('mousewheel', evt);
};

prototype.mousemove = function(evt) {
  var a = this._active,
      p = this.pickEvent(evt);

  if (p === a) {
    // active item and picked item are the same
    this.fire('mousemove', evt); // fire move
  } else {
    // active item and picked item are different
    this.fire('mouseout', evt);  // fire out for prior active item
    this._active = p;            // set new active item
    this.fire('mouseover', evt); // fire over for new active item
    this.fire('mousemove', evt); // fire move for new active item
  }
};

prototype.mouseout = function(evt) {
  this.fire('mouseout', evt);
  this._active = null;
};

prototype.mousedown = function(evt) {
  this._down = this._active;
  this.fire('mousedown', evt);
};

prototype.click = function(evt) {
  if (this._down === this._active) {
    this.fire('click', evt);
    this._down = null;
  }
};

prototype.touchstart = function(evt) {
  this._touch = this.pickEvent(evt.changedTouches[0]);

  if (this._first) {
    this._active = this._touch;
    this._first = false;
  }

  this.fire('touchstart', evt, true);
};

prototype.touchmove = function(evt) {
  this.fire('touchmove', evt, true);
};

prototype.touchend = function(evt) {
  this.fire('touchend', evt, true);
  this._touch = null;
};

// fire an event
prototype.fire = function(type, evt, touch) {
  var a = touch ? this._touch : this._active,
      h = this._handlers[type], i, len;
  if (h) {
    evt.vegaType = type;
    for (i=0, len=h.length; i<len; ++i) {
      h[i].handler.call(this._obj, evt, a);
    }
  }
};

// add an event handler
prototype.on = function(type, handler) {
  var name = this.eventName(type),
      h = this._handlers;
  (h[name] || (h[name] = [])).push({
    type: type,
    handler: handler
  });
  return this;
};

// remove an event handler
prototype.off = function(type, handler) {
  var name = this.eventName(type),
      h = this._handlers[name], i;
  if (!h) return;
  for (i=h.length; --i>=0;) {
    if (h[i].type !== type) continue;
    if (!handler || h[i].handler === handler) h.splice(i, 1);
  }
  return this;
};

prototype.pickEvent = function(evt) {
  var rect = this._canvas.getBoundingClientRect(),
      pad = this._padding, x, y;
  return this.pick(this._scene,
    x = (evt.clientX - rect.left),
    y = (evt.clientY - rect.top),
    x - pad.left, y - pad.top);
};

// find the scenegraph item at the current mouse position
// x, y -- the absolute x, y mouse coordinates on the canvas element
// gx, gy -- the relative coordinates within the current group
prototype.pick = function(scene, x, y, gx, gy) {
  var g = this.context(),
      mark = marks[scene.marktype];
  return mark.pick.call(this, g, scene, x, y, gx, gy);
};

module.exports = CanvasHandler;
<|endoftext|>


<commit_before>/*
 * BSD 3-Clause License
 *
 * Copyright (c) 2018, MapCreator
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 *  Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 *  Neither the name of the copyright holder nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

import { camel as camelCase, snake as snakeCase } from 'case';
import { AbstractClassError, AbstractError } from '../../errors/AbstractError';
import Maps4News from '../../Maps4News';
import SimpleResourceProxy from '../../proxy/SimpleResourceProxy';
import Injectable from '../../traits/Injectable';
import { fnv32b } from '../../utils/hash';
import { isParentOf, mix } from '../../utils/reflection';

function unique (input) {
  return input.filter((v, i) => input.findIndex(vv => vv === v) === i);
}

/**
 * Resource base
 * @abstract
 */
export default class ResourceBase extends mix(null, Injectable) {
  /**
   * @param {Maps4News} api - Api instance
   * @param {Object<String, *>} data - Item data
   */
  constructor (api, data = {}) {
    super();

    if (this.constructor === ResourceBase) {
      throw new AbstractClassError();
    }

    this.api = api;

    // De-reference
    data = { ...data };

    // Normalize keys to snake_case
    // Fix data types
    for (const key of Object.keys(data)) {
      const newKey = snakeCase(key);

      data[newKey] = this.constructor._guessType(newKey, data[key]);

      if (newKey !== key) {
        delete data[key];
      }
    }

    this._baseProperties = data || {};
    this._properties = {};
    this._api = api;

    const fields = Object.keys(this._baseProperties)
      .filter(field => !Object.prototype.hasOwnProperty.call(this, field));

    // Apply properties
    for (const key of fields) {
      this._applyProperty(key);
    }

    // Add deleted field if possible
    if (fields.includes('deleted_at')) {
      Object.defineProperty(this, 'deleted', {
        enumerable: true,
        configurable: true,

        get: () => Boolean(this.deletedAt),
      });
    }

    /* We keep track of any new fields by recording the
     * keys the object currently has. We don't need no
     * fancy-pants observers, Proxies etc.
     * snake_case only
     */
    this._knownFields = Object.keys(this).filter(x => x[0] !== '_');
  }

  /**
   * Get api instance
   * @returns {Maps4News} - Api instance
   */
  get api () {
    return this._api;
  }

  /**
   * Set the api instance
   * @param {Maps4News} value - Api instance
   */
  set api (value) {
    if (!isParentOf(Maps4News, value)) {
      throw new TypeError('Expected api to be of type Maps4News or null');
    }

    this._api = value;
  }

  /**
   * Resource path template
   * @returns {String} - Path template
   */
  static get resourcePath () {
    return `/${this.resourceName}/{id}`;
  }

  /**
   * Resource name
   * @returns {String} - Resource name
   * @abstract
   */
  static get resourceName () {
    throw new AbstractError();
  }

  /**
   * Returns the url key of the resource
   * @returns {String} - Resource key
   */
  static get resourceUrlKey () {
    return 'id';
  }

  /**
   * Protected read-only fields
   * @returns {Array<string>} - Array containing protected read-only fields
   * @protected
   */
  static get protectedFields () {
    return ['id', 'created_at', 'updated_at', 'deleted_at'];
  }

  /**
   * Returns if the resource is readonly
   * @returns {boolean} - readonly
   */
  static get readonly () {
    return false;
  }

  /**
   * Moves new fields to this._properties and turns them into a getter/setter
   * @protected
   */
  _updateProperties () {
    // Build a list of new fields
    let fields = Object.keys(this)
      .filter(x => x[0] !== '_')
      .filter(x => !this._knownFields.includes(x));

    // Move the pointer from this to the properties object
    for (const key of fields) {
      const newKey = snakeCase(key);

      this._properties[newKey] = this[key];
      delete this[key];

      this._applyProperty(newKey);
      this._knownFields.push(newKey);
    }

    // Build a list of new BaseProperty fields
    fields = Object.keys(this._baseProperties)
      .filter(x => !this._knownFields.includes(camelCase(x)));

    for (const key of fields) {
      this._applyProperty(key);
      this._knownFields.push(key);
    }

    this._knownFields = unique(this._knownFields);
  }

  /**
   * Clean up instance and commit all changes locally.
   * This means that any changed fields will be marked
   * as unchanged whilst  keeping their new values. The
   * changes will not be saved.
   */
  sanitize () {
    this._updateProperties();
    Object.assign(this._baseProperties, this._properties);
    this._properties = {};
  }

  /**
   * Resets model instance to it's original state
   * @param {Array<string>|string|null} [fields=null] - Fields to reset, defaults to all fields
   */
  reset (fields = null) {
    this._updateProperties();

    if (typeof fields === 'string') {
      this.reset([fields]);
    } else if (fields === null) {
      this._properties = {}; // Delete all
    } else if (Array.isArray(fields)) {
      fields
        .map(String)
        .map(snakeCase)
        .forEach(field => delete this._properties[field]);
    }
  }

  /**
   * Clone the object
   * @returns {ResourceBase} - Exact clone of the object
   */
  clone () {
    this._updateProperties();

    const out = new this.constructor(this.api, this._baseProperties);

    for (const key of Object.keys(this._properties)) {
      out[key] = this._properties[key];
    }

    return out;
  }

  /**
   * Refresh the resource by requesting it from the server again
   * @param {Boolean} updateSelf - Update the current instance
   * @returns {Promise<ResourceBase>} - Refreshed instance
   * @throws {ApiError}
   */
  async refresh (updateSelf = true) {
    const { data: { data } } = await this.api.axios.get(this.url);

    if (updateSelf) {
      this._properties = {};
      this._baseProperties = data;

      this._updateProperties();
    }

    return new this.constructor(this._api, data);
  }

  /**
   * Create proxy for property
   * @param {string} key - property key
   * @private
   */
  _applyProperty (key) {
    const desc = {
      enumerable: true,
      configurable: true,

      get: () => {
        if (this._properties.hasOwnProperty(key)) {
          return this._properties[key];
        }

        return this._baseProperties[key];
      },
    };

    if (!this.constructor.protectedFields.includes(key) && !this.constructor.readonly) {
      desc.set = val => {
        this._properties[key] = ResourceBase._guessType(key, val);
        delete this._url; // Clears url cache
      };
    }

    const newKey = camelCase(key);

    Object.defineProperty(this, newKey, desc);
  }

  /**
   * Guess type based on property name
   * @param {string} name - Field name
   * @param {*} value - Field Value
   * @private
   * @returns {*} - Original or converted value
   */
  static _guessType (name, value) {
    const regexp = /(?:^|_)([^_$]+)$/g;
    const match = regexp.exec(name);
    const idMacros = ['last', 'me', 'mine'];

    if (match === null || typeof value !== 'string') {
      return value;
    }

    switch (match[1]) {
      case 'end':
      case 'start':
      case 'at':
        return new Date(value.replace(' ', 'T'));
      case 'id':
        // Test if the value is in fact a macro
        if (idMacros.includes(String(value).toLowerCase())) {
          return value;
        }

        return Number(value);
      default:
        return value;
    }
  }

  /**
   * If the resource can be owned by an organisation
   * @returns {boolean} - Can be owned by an organisation
   */
  get ownable () {
    return false;
  }

  /**
   * Auto generated resource url
   * @returns {string} - Resource url
   */
  get url () {
    if (!this._url) {
      let url = `${this._api.host}/${this._api.version}${this.constructor.resourcePath}`;

      // Find and replace any keys
      url = url.replace(/{(\w+)}/g, (match, key) => this[camelCase(key)]);

      this._url = url;
    }

    return this._url;
  }

  /**
   * Auto generated Resource base url
   * @returns {string} - Resource base url
   */
  get baseUrl () {
    const basePath = this.constructor.resourcePath.match(/^(\/[^{]+\b)/)[1];

    return `${this._api.host}/${this._api.version}${basePath}`;
  }

  /**
   * List fields that contain object data
   * @returns {Array<String>} - A list of fields
   */
  get fieldNames () {
    const keys = unique([
      ...Object.keys(this._baseProperties),
      ...Object.keys(this._properties),
    ]);

    return keys.map(camelCase);
  }

  /**
   * String representation of the resource, similar to Python's __repr__
   * @returns {string} - Resource name and id
   */
  toString () {
    return `${this.constructor.name}(${this[this.resourceUrlKey]})`;
  }

  /**
   * Transform instance to object
   * @param {boolean} [camelCaseKeys=false] - camelCase object keys
   * @returns {{}} - object
   */
  toObject (camelCaseKeys = false) {
    this._updateProperties();

    const out = { ...this._baseProperties, ...this._properties };

    if (camelCaseKeys) {
      for (const key of Object.keys(out)) {
        const ccKey = camelCase(key);

        if (key !== ccKey) {
          out[ccKey] = out[key];

          delete out[key];
        }
      }
    }

    return out;
  }

  /**
   * Macro for resource listing
   * @param {string|function} Target - Target object
   * @param {?String} url - Target url, if null it will guess
   * @param {object} seedData - Internal use, used for seeding SimpleResourceProxy::new
   * @returns {SimpleResourceProxy} - A proxy for accessing the resource
   * @protected
   */
  _proxyResourceList (Target, url = null, seedData = {}) {
    if (!url) {
      url = `${Target.resourceName.replace(/s+$/, '')}s`;
    }

    if (typeof url === 'string' && !url.startsWith('/') && !url.match(/https?:/)) {
      url = `${this.url}/${url}`;
    }

    return new SimpleResourceProxy(this.api, Target, url, seedData);
  }

  /**
   * Static proxy generation
   * @param {string|function} Target - Constructor or url
   * @param {function?} Constructor - Constructor for a resource that the results should be cast to
   * @param {Object<string, *>} seedData - Optional data to seed the resolved resources
   * @returns {SimpleResourceProxy} - A proxy for accessing the resource
   * @example
   * user.static('jobs').lister();
   *
   * @example
   * class FooBar extends ResourceBase {
   *    static get resourceName() {
   *      return 'custom';
   *    }
   * }
   *
   * api.static(FooBar)
   *   .get(1)
   *   .then(console.log);
   */
  static (Target, Constructor = ResourceBase, seedData = {}) {
    let url;

    if (typeof Target === 'string') {
      url = `${this.url}/${Target}`;

      const name = Constructor.name || 'AnonymousResource';

      Target = class AnonymousResource extends Constructor {
        static get resourceName () {
          return Object.getPrototypeOf(this).resourceName || 'anonymous';
        }

        static get resourcePath () {
          return url;
        }
      };

      Object.defineProperty(Target, 'name', {
        value: `${name}_${fnv32b(url)}`,
      });
    }

    if (!isParentOf(ResourceBase, Target)) {
      throw new TypeError('Expected Target to be of type String or ResourceBase constructor');
    }

    return this._proxyResourceList(Target, url, seedData);
  }
}
<commit_msg>Fix not overwriting existing properties<commit_after>/*
 * BSD 3-Clause License
 *
 * Copyright (c) 2018, MapCreator
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 *  Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 *  Neither the name of the copyright holder nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

import { camel as camelCase, snake as snakeCase } from 'case';
import { AbstractClassError, AbstractError } from '../../errors/AbstractError';
import Maps4News from '../../Maps4News';
import SimpleResourceProxy from '../../proxy/SimpleResourceProxy';
import Injectable from '../../traits/Injectable';
import { fnv32b } from '../../utils/hash';
import { isParentOf, mix } from '../../utils/reflection';

function unique (input) {
  return input.filter((v, i) => input.findIndex(vv => vv === v) === i);
}

/**
 * Resource base
 * @abstract
 */
export default class ResourceBase extends mix(null, Injectable) {
  /**
   * @param {Maps4News} api - Api instance
   * @param {Object<String, *>} data - Item data
   */
  constructor (api, data = {}) {
    super();

    if (this.constructor === ResourceBase) {
      throw new AbstractClassError();
    }

    this.api = api;

    // De-reference
    data = { ...data };

    // Normalize keys to snake_case
    // Fix data types
    for (const key of Object.keys(data)) {
      const newKey = snakeCase(key);

      data[newKey] = this.constructor._guessType(newKey, data[key]);

      if (newKey !== key) {
        delete data[key];
      }
    }

    this._baseProperties = data || {};
    this._properties = {};
    this._api = api;

    const fields = Object.keys(this._baseProperties)
      .filter(field => !Object.prototype.hasOwnProperty.call(this, camelCase(field)));

    // Apply properties
    for (const key of fields) {
      this._applyProperty(key);
    }

    // Add deleted field if possible
    if (fields.includes('deleted_at')) {
      Object.defineProperty(this, 'deleted', {
        enumerable: true,
        configurable: true,

        get: () => Boolean(this.deletedAt),
      });
    }

    /* We keep track of any new fields by recording the
     * keys the object currently has. We don't need no
     * fancy-pants observers, Proxies etc.
     * snake_case only
     */
    this._knownFields = Object.keys(this).filter(x => x[0] !== '_');
  }

  /**
   * Get api instance
   * @returns {Maps4News} - Api instance
   */
  get api () {
    return this._api;
  }

  /**
   * Set the api instance
   * @param {Maps4News} value - Api instance
   */
  set api (value) {
    if (!isParentOf(Maps4News, value)) {
      throw new TypeError('Expected api to be of type Maps4News or null');
    }

    this._api = value;
  }

  /**
   * Resource path template
   * @returns {String} - Path template
   */
  static get resourcePath () {
    return `/${this.resourceName}/{id}`;
  }

  /**
   * Resource name
   * @returns {String} - Resource name
   * @abstract
   */
  static get resourceName () {
    throw new AbstractError();
  }

  /**
   * Returns the url key of the resource
   * @returns {String} - Resource key
   */
  static get resourceUrlKey () {
    return 'id';
  }

  /**
   * Protected read-only fields
   * @returns {Array<string>} - Array containing protected read-only fields
   * @protected
   */
  static get protectedFields () {
    return ['id', 'created_at', 'updated_at', 'deleted_at'];
  }

  /**
   * Returns if the resource is readonly
   * @returns {boolean} - readonly
   */
  static get readonly () {
    return false;
  }

  /**
   * Moves new fields to this._properties and turns them into a getter/setter
   * @protected
   */
  _updateProperties () {
    // Build a list of new fields
    let fields = Object.keys(this)
      .filter(x => x[0] !== '_')
      .filter(x => !this._knownFields.includes(x));

    // Move the pointer from this to the properties object
    for (const key of fields) {
      const newKey = snakeCase(key);

      this._properties[newKey] = this[key];
      delete this[key];

      this._applyProperty(newKey);
      this._knownFields.push(newKey);
    }

    // Build a list of new BaseProperty fields
    fields = Object.keys(this._baseProperties)
      .filter(x => !this._knownFields.includes(camelCase(x)));

    for (const key of fields) {
      this._applyProperty(key);
      this._knownFields.push(key);
    }

    this._knownFields = unique(this._knownFields);
  }

  /**
   * Clean up instance and commit all changes locally.
   * This means that any changed fields will be marked
   * as unchanged whilst  keeping their new values. The
   * changes will not be saved.
   */
  sanitize () {
    this._updateProperties();
    Object.assign(this._baseProperties, this._properties);
    this._properties = {};
  }

  /**
   * Resets model instance to it's original state
   * @param {Array<string>|string|null} [fields=null] - Fields to reset, defaults to all fields
   */
  reset (fields = null) {
    this._updateProperties();

    if (typeof fields === 'string') {
      this.reset([fields]);
    } else if (fields === null) {
      this._properties = {}; // Delete all
    } else if (Array.isArray(fields)) {
      fields
        .map(String)
        .map(snakeCase)
        .forEach(field => delete this._properties[field]);
    }
  }

  /**
   * Clone the object
   * @returns {ResourceBase} - Exact clone of the object
   */
  clone () {
    this._updateProperties();

    const out = new this.constructor(this.api, this._baseProperties);

    for (const key of Object.keys(this._properties)) {
      out[key] = this._properties[key];
    }

    return out;
  }

  /**
   * Refresh the resource by requesting it from the server again
   * @param {Boolean} updateSelf - Update the current instance
   * @returns {Promise<ResourceBase>} - Refreshed instance
   * @throws {ApiError}
   */
  async refresh (updateSelf = true) {
    const { data: { data } } = await this.api.axios.get(this.url);

    if (updateSelf) {
      this._properties = {};
      this._baseProperties = data;

      this._updateProperties();
    }

    return new this.constructor(this._api, data);
  }

  /**
   * Create proxy for property
   * @param {string} key - property key
   * @private
   */
  _applyProperty (key) {
    const desc = {
      enumerable: true,
      configurable: true,

      get: () => {
        if (this._properties.hasOwnProperty(key)) {
          return this._properties[key];
        }

        return this._baseProperties[key];
      },
    };

    if (!this.constructor.protectedFields.includes(key) && !this.constructor.readonly) {
      desc.set = val => {
        this._properties[key] = ResourceBase._guessType(key, val);
        delete this._url; // Clears url cache
      };
    }

    const newKey = camelCase(key);

    Object.defineProperty(this, newKey, desc);
  }

  /**
   * Guess type based on property name
   * @param {string} name - Field name
   * @param {*} value - Field Value
   * @private
   * @returns {*} - Original or converted value
   */
  static _guessType (name, value) {
    const regexp = /(?:^|_)([^_$]+)$/g;
    const match = regexp.exec(name);
    const idMacros = ['last', 'me', 'mine'];

    if (match === null || typeof value !== 'string') {
      return value;
    }

    switch (match[1]) {
      case 'end':
      case 'start':
      case 'at':
        return new Date(value.replace(' ', 'T'));
      case 'id':
        // Test if the value is in fact a macro
        if (idMacros.includes(String(value).toLowerCase())) {
          return value;
        }

        return Number(value);
      default:
        return value;
    }
  }

  /**
   * If the resource can be owned by an organisation
   * @returns {boolean} - Can be owned by an organisation
   */
  get ownable () {
    return false;
  }

  /**
   * Auto generated resource url
   * @returns {string} - Resource url
   */
  get url () {
    if (!this._url) {
      let url = `${this._api.host}/${this._api.version}${this.constructor.resourcePath}`;

      // Find and replace any keys
      url = url.replace(/{(\w+)}/g, (match, key) => this[camelCase(key)]);

      this._url = url;
    }

    return this._url;
  }

  /**
   * Auto generated Resource base url
   * @returns {string} - Resource base url
   */
  get baseUrl () {
    const basePath = this.constructor.resourcePath.match(/^(\/[^{]+\b)/)[1];

    return `${this._api.host}/${this._api.version}${basePath}`;
  }

  /**
   * List fields that contain object data
   * @returns {Array<String>} - A list of fields
   */
  get fieldNames () {
    const keys = unique([
      ...Object.keys(this._baseProperties),
      ...Object.keys(this._properties),
    ]);

    return keys.map(camelCase);
  }

  /**
   * String representation of the resource, similar to Python's __repr__
   * @returns {string} - Resource name and id
   */
  toString () {
    return `${this.constructor.name}(${this[this.resourceUrlKey]})`;
  }

  /**
   * Transform instance to object
   * @param {boolean} [camelCaseKeys=false] - camelCase object keys
   * @returns {{}} - object
   */
  toObject (camelCaseKeys = false) {
    this._updateProperties();

    const out = { ...this._baseProperties, ...this._properties };

    if (camelCaseKeys) {
      for (const key of Object.keys(out)) {
        const ccKey = camelCase(key);

        if (key !== ccKey) {
          out[ccKey] = out[key];

          delete out[key];
        }
      }
    }

    return out;
  }

  /**
   * Macro for resource listing
   * @param {string|function} Target - Target object
   * @param {?String} url - Target url, if null it will guess
   * @param {object} seedData - Internal use, used for seeding SimpleResourceProxy::new
   * @returns {SimpleResourceProxy} - A proxy for accessing the resource
   * @protected
   */
  _proxyResourceList (Target, url = null, seedData = {}) {
    if (!url) {
      url = `${Target.resourceName.replace(/s+$/, '')}s`;
    }

    if (typeof url === 'string' && !url.startsWith('/') && !url.match(/https?:/)) {
      url = `${this.url}/${url}`;
    }

    return new SimpleResourceProxy(this.api, Target, url, seedData);
  }

  /**
   * Static proxy generation
   * @param {string|function} Target - Constructor or url
   * @param {function?} Constructor - Constructor for a resource that the results should be cast to
   * @param {Object<string, *>} seedData - Optional data to seed the resolved resources
   * @returns {SimpleResourceProxy} - A proxy for accessing the resource
   * @example
   * user.static('jobs').lister();
   *
   * @example
   * class FooBar extends ResourceBase {
   *    static get resourceName() {
   *      return 'custom';
   *    }
   * }
   *
   * api.static(FooBar)
   *   .get(1)
   *   .then(console.log);
   */
  static (Target, Constructor = ResourceBase, seedData = {}) {
    let url;

    if (typeof Target === 'string') {
      url = `${this.url}/${Target}`;

      const name = Constructor.name || 'AnonymousResource';

      Target = class AnonymousResource extends Constructor {
        static get resourceName () {
          return Object.getPrototypeOf(this).resourceName || 'anonymous';
        }

        static get resourcePath () {
          return url;
        }
      };

      Object.defineProperty(Target, 'name', {
        value: `${name}_${fnv32b(url)}`,
      });
    }

    if (!isParentOf(ResourceBase, Target)) {
      throw new TypeError('Expected Target to be of type String or ResourceBase constructor');
    }

    return this._proxyResourceList(Target, url, seedData);
  }
}
<|endoftext|>


<commit_before>/*
 * A jQuery extension for adding a load mask to any element
 * The image for the load mask is expected by default to be found at
 * /img/working.gif but can be overridden by setting jQuery.working.imgPath
 *
 * @author Philip Graham <philip@zeptech.ca>
 */
(function ( $ ) {

  $.working = {};
  $.working.imgPath = '/img/working.gif';

  $.fn.working = function () {

    return this.each(function () {
      var ctx = $(this), mask = ctx.data('working-mask'), img;

      if (mask === undefined) {
        mask = $('<div/>')
          .addClass('ui-widget-overlay')
          .css('opacity', '0.65')
          .append(
            $('<img/>')
              .css('position', 'absolute')
              .css('opacity', '1')
              .attr('src', $.working.imgPath)
          );

        ctx.data('working-mask', mask);
      }

      mask.appendTo(ctx);
      img = mask.find('img');
      img.offset({
        top: (mask.height() / 2) - (img.height() / 2),
        left: (mask.width() / 2) - (img.width() / 2)
      });
    });
  };

  $.fn.done = function () {

    return this.each(function () {
      var ctx = $(this), mask = ctx.data('working-mask');

      if (mask !== undefined) {
        mask.detach();
      }
    });
  };

})( jQuery );

<commit_msg>Fixed positioning of loading image for jQuery working plugin.  Was being positioned relative to the document rather than relative to the load mask<commit_after>/*
 * A jQuery extension for adding a load mask to any element
 * The image for the load mask is expected by default to be found at
 * /img/working.gif but can be overridden by setting jQuery.working.imgPath
 *
 * @author Philip Graham <philip@zeptech.ca>
 */
(function ( $ ) {

  $.working = {};
  $.working.imgPath = '/img/working.gif';

  $.fn.working = function () {

    return this.each(function () {
      var ctx = $(this), mask = ctx.data('working-mask'), img;

      if (mask === undefined) {
        mask = $('<div/>')
          .addClass('ui-widget-overlay')
          .css('opacity', '0.65')
          .append(
            $('<img/>')
              .css('position', 'absolute')
              .css('opacity', '1')
              .attr('src', $.working.imgPath)
          );

        ctx.data('working-mask', mask);
      }

      mask.appendTo(ctx);
      img = mask.find('img');
      img.position({
        my: 'center',
        at: 'center',
        of: mask
      });
    });
  };

  $.fn.done = function () {

    return this.each(function () {
      var ctx = $(this), mask = ctx.data('working-mask');

      if (mask !== undefined) {
        mask.detach();
      }
    });
  };

})( jQuery );

<|endoftext|>


<commit_before>import React, { Component,PureComponent } from 'react';
import {  Text, View } from 'react-native';
import { StackNavigator } from 'react-navigation';

import { Button,Divider } from 'react-native-elements';

import styles from './index.style';
import { theme } from '../../theme';

import RefreshFlatList from '../../components/RefreshFlatList';

let selected = 0,tht;

/**
 *
 * swap-vert MaterialIcons
 *
 * @class CatalogScreen
 * @extends {PureComponent}
 */
class CatalogScreen extends PureComponent {
    static navigationOptions = ({ navigation, screenProps }) => {
      const callback = () => {
        alert('sort');
      };
      return {
        title: `${navigation.state.params.bookName}`,

        headerRight: (
          <View style={styles.navRightContainer}>
            <Button
              containerViewStyle={styles.wrapper}
              buttonStyle={styles.button}
              color={'#fff'}
              title='正序'
              fontSize={16}
              leftIcon={{ name: 'swap-vert', type:'MaterialIcons', color: '#fff', style: styles.chevron }}
              onPress={() => {
                screenProps.a();
              }}
            />
          </View>
        ),
        tabBarVisible: false,
      };
    }
    constructor(props) {
      super(props);
      tht = this;
      this._FlatList;
      this.state = {
        bookList:[
          {
            num:0,
            title:'入坑必看~',
            url:'http://www.qu.la/book/book/33301/1825139.html',
            isDownload:true,
          },{
            num:1,
            title: '楔子',
            url: 'http://www.qu.la/book/book/33301/1825140.html',
            isDownload:false,
          },{
            num:2,
            title: '楔子',
            url: 'http://www.qu.la/book/book/33301/1825140.html',
            isDownload:false,
          },{
            num:3,
            title: '楔子',
            url: 'http://www.qu.la/book/book/33301/1825140.html',
            isDownload:false,
          },{
            num:4,
            title: '楔子',
            url: 'http://www.qu.la/book/book/33301/1825140.html',
            isDownload:false,
          },{
            num:5,
            title: '楔子',
            url: 'http://www.qu.la/book/book/33301/1825140.html',
            isDownload:false,
          },{
            num:6,
            title: '楔子',
            url: 'http://www.qu.la/book/book/33301/1825140.html',
            isDownload:false,
          },{
            num:7,
            title: '楔子',
            url: 'http://www.qu.la/book/book/33301/1825140.html',
            isDownload:false,
          },{
            num:8,
            title: '楔子',
            url: 'http://www.qu.la/book/book/33301/1825140.html',
            isDownload:false,
          },{
            num:9,
            title: '楔子',
            url: 'http://www.qu.la/book/book/33301/1825140.html',
            isDownload:false,
          },{
            num:10,
            title: '楔子',
            url: 'http://www.qu.la/book/book/33301/1825140.html',
            isDownload:false,
          },{
            num:11,
            title: '楔子',
            url: 'http://www.qu.la/book/book/33301/1825140.html',
            isDownload:false,
          },{
            num:12,
            title: '楔子',
            url: 'http://www.qu.la/book/book/33301/1825140.html',
            isDownload:false,
          },{
            num:13,
            title: '楔子',
            url: 'http://www.qu.la/book/book/33301/1825140.html',
            isDownload:false,
          },{
            num:14,
            title: '楔子',
            url: 'http://www.qu.la/book/book/33301/1825140.html',
            isDownload:false,
          }
        ],
        fetchFlag:0,
      };

      this.renderSeparator = this.renderSeparator.bind(this);
      this.onHeaderRefresh = this.onHeaderRefresh.bind(this);
      this.renderRow = this.renderRow.bind(this);
    }

    renderSeparator() {
      return (
        <View style={styles.dividerContainer}>
          <Divider style={styles.divider} />
        </View>
      );
    }

    onHeaderRefresh() {
      return;
    }

    renderRow(item) {
      const itemColor = item.item.isDownload?styles.Catalogcolors.loadedChapterColor:styles.Catalogcolors.noLoadChapterColor;
      return(
        <View style={styles.itemContainerStyle}>
          <Text style={[styles.itemFontStyle,itemColor]}>{item.item.title}</Text>
        </View>
      );
    }

    render() {//this.refs._flat.refs.listRef.
      return (
        <View style={styles.SunnyModeContainer}>
          <RefreshFlatList
            style={{backgroundColor:'#eeeeee'}}
            ref={'_flat'}
            listRef={'_flatListx'}
            data = {this.state.bookList}
            renderItem={this.renderRow}
            ItemSeparatorComponent={this.renderSeparator}
            keyExtractor={(item, index) => item.num}
            refreshState={this.state.fetchFlag}
            onHeaderRefresh={this.onHeaderRefresh} />

        </View>
      );
    }
}

const Wrapper = StackNavigator({
  cat: {
    screen: (props) => {
      return <CatalogScreen {...this.props} screenProps={{
        ...this.props.screenProps,
        sort: () => {
          alert('sort');
        }
      }} />;
    },
  },
});

export default Wrapper;<commit_msg>remove some code<commit_after>import React, { Component,PureComponent } from 'react';
import {  Text, View } from 'react-native';
import { StackNavigator } from 'react-navigation';

import { Button,Divider } from 'react-native-elements';

import styles from './index.style';
import { theme } from '../../theme';

import RefreshFlatList from '../../components/RefreshFlatList';

let selected = 0,tht;

class CatalogScreen extends PureComponent {
    static navigationOptions = ({ navigation, screenProps }) => {
      const callback = () => {
        alert('sort');
      };
      return {
        title: `${navigation.state.params.bookName}`,

        headerRight: (
          <View style={styles.navRightContainer}>
            <Button
              containerViewStyle={styles.wrapper}
              buttonStyle={styles.button}
              color={'#fff'}
              title='正序'
              fontSize={16}
              leftIcon={{ name: 'swap-vert', type:'MaterialIcons', color: '#fff', style: styles.chevron }}
              onPress={() => {
                screenProps.a();
              }}
            />
          </View>
        ),
        tabBarVisible: false,
      };
    }
    constructor(props) {
      super(props);
      tht = this;
      this._FlatList;
      this.state = {
        bookList:[
          {
            num:0,
            title:'入坑必看~',
            url:'http://www.qu.la/book/book/33301/1825139.html',
            isDownload:true,
          },{
            num:1,
            title: '楔子',
            url: 'http://www.qu.la/book/book/33301/1825140.html',
            isDownload:false,
          },{
            num:2,
            title: '楔子',
            url: 'http://www.qu.la/book/book/33301/1825140.html',
            isDownload:false,
          },{
            num:3,
            title: '楔子',
            url: 'http://www.qu.la/book/book/33301/1825140.html',
            isDownload:false,
          },{
            num:4,
            title: '楔子',
            url: 'http://www.qu.la/book/book/33301/1825140.html',
            isDownload:false,
          },{
            num:5,
            title: '楔子',
            url: 'http://www.qu.la/book/book/33301/1825140.html',
            isDownload:false,
          },{
            num:6,
            title: '楔子',
            url: 'http://www.qu.la/book/book/33301/1825140.html',
            isDownload:false,
          },{
            num:7,
            title: '楔子',
            url: 'http://www.qu.la/book/book/33301/1825140.html',
            isDownload:false,
          },{
            num:8,
            title: '楔子',
            url: 'http://www.qu.la/book/book/33301/1825140.html',
            isDownload:false,
          },{
            num:9,
            title: '楔子',
            url: 'http://www.qu.la/book/book/33301/1825140.html',
            isDownload:false,
          },{
            num:10,
            title: '楔子',
            url: 'http://www.qu.la/book/book/33301/1825140.html',
            isDownload:false,
          },{
            num:11,
            title: '楔子',
            url: 'http://www.qu.la/book/book/33301/1825140.html',
            isDownload:false,
          },{
            num:12,
            title: '楔子',
            url: 'http://www.qu.la/book/book/33301/1825140.html',
            isDownload:false,
          },{
            num:13,
            title: '楔子',
            url: 'http://www.qu.la/book/book/33301/1825140.html',
            isDownload:false,
          },{
            num:14,
            title: '楔子',
            url: 'http://www.qu.la/book/book/33301/1825140.html',
            isDownload:false,
          }
        ],
        fetchFlag:0,
      };

      this.renderSeparator = this.renderSeparator.bind(this);
      this.onHeaderRefresh = this.onHeaderRefresh.bind(this);
      this.renderRow = this.renderRow.bind(this);
    }

    renderSeparator() {
      return (
        <View style={styles.dividerContainer}>
          <Divider style={styles.divider} />
        </View>
      );
    }

    onHeaderRefresh() {
      return;
    }

    renderRow(item) {
      const itemColor = item.item.isDownload?styles.Catalogcolors.loadedChapterColor:styles.Catalogcolors.noLoadChapterColor;
      return(
        <View style={styles.itemContainerStyle}>
          <Text style={[styles.itemFontStyle,itemColor]}>{item.item.title}</Text>
        </View>
      );
    }

    render() {//this.refs._flat.refs.listRef.
      return (
        <View style={styles.SunnyModeContainer}>
          <RefreshFlatList
            style={{backgroundColor:'#eeeeee'}}
            ref={'_flat'}
            listRef={'_flatListx'}
            data = {this.state.bookList}
            renderItem={this.renderRow}
            ItemSeparatorComponent={this.renderSeparator}
            keyExtractor={(item, index) => item.num}
            refreshState={this.state.fetchFlag}
            onHeaderRefresh={this.onHeaderRefresh} />

        </View>
      );
    }
}

export default CatalogScreen;<|endoftext|>


<commit_before>(function () {

    var defaults = {
        line: {
            smooth: false,
            marker: {
                enable: true,
                size: 3
            }
        }
    };

    function render(rawData, layer, options, id) {
        if (!this.xScale) throw new Error('Line Chart requires .cartesian() to be included in the instance.');

        var x = _.bind(function (d) { return this.xScale(d.x) + this.rangeBand / 2; }, this);
        var y = _.bind(function (d) { return this.yScale(d.y); }, this);
        var h = options.chart.plotHeight;
        var duration = 400;
        // jshint eqnull:true
        var data = _.map(rawData, function (s) {
            return _.extend(s, {
                data: _.filter(s.data, function (d, i) {
                    if (i === 0 && d.y != null) return true;
                    var differentX = x(s.data[i-1]) !== x(d); // && y(s.data[i-1]) !== y(d);
                    return d.y != null && differentX;
                })
            });
        });

        renderPaths();
        if (options.line.marker.enable)
            renderMarkers();
        renderTooltipTrackers();

        function seriesClassName(extras) { return function (d, i) { return (extras||'') + ' s-' +(i+1) + ' ' + d.name; }; };

        function renderPaths() {
            var startLine = d3.svg.line()
                .x(function (d) { return x(d); })
                .y(function () { return y({x: 0, y: 0}); });

            var line = d3.svg.line()
                .x(function (d) { return x(d); })
                .y(function (d) { return y(d); });

            if(options.line.smooth) line.interpolate('cardinal');

            var series = layer.selectAll('g.series')
                    .data(data);

            // enter
            var el = series.enter().append('svg:g')
                .attr('class',seriesClassName('series'))
                .append('path')
                    .attr('class', 'line');

            if (options.chart.animations) {
                el.attr('d', function(d) { return startLine(d.data); })
                    .transition().duration(duration)
                    .attr('d', function (d) { return line(d.data); });
            } else {
                el.attr('d', function (d) { return line(d.data); });
            }

            // update
            el = series
                .attr('class', seriesClassName('series'))
                .select('.line')
                ;

            if (options.chart.animations) {
                el.transition().duration(duration)
                    .attr('d', function (d) { return line(d.data); });
            } else  {
                el.attr('d', function (d) { return line(d.data); });
            }

            // remove
            if (options.chart.animations) {
                series.exit()
                    .remove();
            } else  {
                series.exit().remove();
            }
        }

        function renderMarkers() {
            var markers = layer.selectAll('.line-chart-markers')
                .data(data);

            markers.enter().append('g')
                .attr('class', seriesClassName('line-chart-markers markers'));

            markers.exit().remove();

            var dots = markers.selectAll('.dot')
                .data(function (d) { return d.data; }, function (d) { return d.x; });

            dots.enter().append('circle')
                .attr('class', 'dot')
                .attr('r', options.line.marker.size)
                .attr('cx', x)
                .attr('cy', h);

            dots.exit().remove();

            if (options.chart.animations) {
                dots.transition().delay(100).duration(duration)
                    .attr('cx', x)
                    .attr('cy', y);
            } else {
                dots.attr('cx', x)
                    .attr('cy', y);
            }
        }

        function renderTooltipTrackers() {
            var trackerSize = 10;
            var markers = layer.selectAll('.tooltip-trackers')
                .data(data);

            markers.enter().append('g')
                .attr('class', function (d, i) { return 'tooltip-trackers s-' + (i+1); });

            markers.exit().remove();

            var dots = markers.selectAll('.tooltip-tracker')
                .data(function (d) { return d.data; }, function (d) { return d.x; });

            dots.enter().append('circle')
                .attr('class', 'tooltip-tracker')
                .attr('r', trackerSize)
                .attr('opacity', 0)
                .attr('cx', x)
                .attr('cy', h);

            dots.exit().remove();

            dots.attr('cx', x)
                .attr('cy', y);
        }

        return this;
    }

    render.defaults = defaults;

    /**
    * Adds a line chart to the Contour instance.
    *
    * This visualization requires `.cartesian()`.
    *
    * ### Example:
    *
    *     new Contour({el: '.myChart'})
    *           .cartesian()
    *           .line([1,2,3,4])
    *           .render();
    *
    * @name line(data, options)
    * @param {object|array} data The _data series_ to be rendered with this visualization. This can be in any of the supported formats.
    * @param {object} [options] Configuration options particular to this visualization that override the defaults.
    * @api public
    *
    */
    Contour.export('line', render);

})();
<commit_msg>added key to the series groups for line charts so lines animate correctly when chaining data dynamically<commit_after>(function () {

    var defaults = {
        line: {
            smooth: false,
            marker: {
                enable: true,
                size: 3
            }
        }
    };

    function render(rawData, layer, options, id) {
        if (!this.xScale) throw new Error('Line Chart requires .cartesian() to be included in the instance.');

        var x = _.bind(function (d) { return this.xScale(d.x) + this.rangeBand / 2; }, this);
        var y = _.bind(function (d) { return this.yScale(d.y); }, this);
        var h = options.chart.plotHeight;
        var duration = 400;
        // jshint eqnull:true
        var data = _.map(rawData, function (s) {
            return _.extend(s, {
                data: _.filter(s.data, function (d, i) {
                    if (i === 0 && d.y != null) return true;
                    var differentX = x(s.data[i-1]) !== x(d); // && y(s.data[i-1]) !== y(d);
                    return d.y != null && differentX;
                })
            });
        });

        renderPaths();
        if (options.line.marker.enable)
            renderMarkers();
        renderTooltipTrackers();

        function seriesClassName(extras) { return function (d, i) { return (extras||'') + ' s-' +(i+1) + ' ' + d.name; }; };

        function renderPaths() {
            var startLine = d3.svg.line()
                .x(function (d) { return x(d); })
                .y(function () { return y({x: 0, y: 0}); });

            var line = d3.svg.line()
                .x(function (d) { return x(d); })
                .y(function (d) { return y(d); });

            if(options.line.smooth) line.interpolate('cardinal');

            var series = layer.selectAll('g.series')
                    .data(data, function (d) { return d.name; });

            // enter
            var el = series.enter().append('svg:g')
                .attr('class',seriesClassName('series'))
                .append('path')
                    .attr('class', 'line');

            if (options.chart.animations) {
                el.attr('d', function(d) { return startLine(d.data); })
                    .transition().duration(duration)
                    .attr('d', function (d) { return line(d.data); });
            } else {
                el.attr('d', function (d) { return line(d.data); });
            }

            // update
            el = series
                .attr('class', seriesClassName('series'))
                .select('.line')
                ;

            if (options.chart.animations) {
                el.transition().duration(duration)
                    .attr('d', function (d) { return line(d.data); });
            } else  {
                el.attr('d', function (d) { return line(d.data); });
            }

            // remove
            if (options.chart.animations) {
                series.exit()
                    .remove();
            } else  {
                series.exit().remove();
            }
        }

        function renderMarkers() {
            var markers = layer.selectAll('.line-chart-markers')
                .data(data, function (d) { return d.name; });

            markers.enter().append('g')
                .attr('class', seriesClassName('line-chart-markers markers'));

            markers.exit().remove();

            var dots = markers.selectAll('.dot')
                .data(function (d) { return d.data; }, function (d) { return d.x; });

            dots.enter().append('circle')
                .attr('class', 'dot')
                .attr('r', options.line.marker.size)
                .attr('cx', x)
                .attr('cy', h);

            dots.exit().remove();

            if (options.chart.animations) {
                dots.transition().delay(100).duration(duration)
                    .attr('cx', x)
                    .attr('cy', y);
            } else {
                dots.attr('cx', x)
                    .attr('cy', y);
            }
        }

        function renderTooltipTrackers() {
            var trackerSize = 10;
            var markers = layer.selectAll('.tooltip-trackers')
                .data(data, function (d) { return d.name; });

            markers.enter().append('g')
                .attr('class', function (d, i) { return 'tooltip-trackers s-' + (i+1); });

            markers.exit().remove();

            var dots = markers.selectAll('.tooltip-tracker')
                .data(function (d) { return d.data; }, function (d) { return d.x; });

            dots.enter().append('circle')
                .attr('class', 'tooltip-tracker')
                .attr('r', trackerSize)
                .attr('opacity', 0)
                .attr('cx', x)
                .attr('cy', h);

            dots.exit().remove();

            dots.attr('cx', x)
                .attr('cy', y);
        }

        return this;
    }

    render.defaults = defaults;

    /**
    * Adds a line chart to the Contour instance.
    *
    * This visualization requires `.cartesian()`.
    *
    * ### Example:
    *
    *     new Contour({el: '.myChart'})
    *           .cartesian()
    *           .line([1,2,3,4])
    *           .render();
    *
    * @name line(data, options)
    * @param {object|array} data The _data series_ to be rendered with this visualization. This can be in any of the supported formats.
    * @param {object} [options] Configuration options particular to this visualization that override the defaults.
    * @api public
    *
    */
    Contour.export('line', render);

})();
<|endoftext|>


<commit_before>import React, { Component } from "react";
import { View } from "react-native";
import {
	CheckBox,
	Text
} from "native-base";
import TouchableItem from "./TouchableItem";

export default class CheckboxItem extends Component {
	constructor(props) {
		super(props);

		this.state = {
			selected: props.checked
		};
	}

	handlePress = () => {
		this.setState({
			selected: !this.state.selected
		});

		this.props.onPress(this.props.label);
	};

	render() {
		return (
			<TouchableItem
				pressOpacity={0.5}
				delayPressIn={0}
				onPress={this.handlePress}
			>
				<View style={{
					flex: 1,
					flexDirection: "row",
					padding: 15,
					borderBottomColor: "#c9c9c9",
					borderBottomWidth: 0.5
				}}>
					<CheckBox
						onPress={this.handlePress}
						checked={this.state.selected}
					/>
					<Text style={{ marginLeft: 20 }}>{this.props.label}</Text>
				</View>
			</TouchableItem>
		);
	}
}
<commit_msg>Add prop types check for CheckBoxItem #14<commit_after>import React, { Component } from "react";
import { View } from "react-native";
import {
	CheckBox,
	Text
} from "native-base";
import TouchableItem from "./TouchableItem";
import types from "../../utils/propTypesHelper";

class CheckboxItem extends Component {
	constructor(props) {
		super(props);

		this.state = {
			selected: props.checked
		};
	}

	handlePress = () => {
		this.setState({
			selected: !this.state.selected
		});

		this.props.onPress(this.props.label);
	};

	render() {
		return (
			<TouchableItem
				pressOpacity={0.5}
				delayPressIn={0}
				onPress={this.handlePress}
			>
				<View style={{
					flex: 1,
					flexDirection: "row",
					padding: 15,
					borderBottomColor: "#c9c9c9",
					borderBottomWidth: 0.5
				}}>
					<CheckBox
						onPress={this.handlePress}
						checked={this.state.selected}
					/>
					<Text style={{ marginLeft: 20 }}>{this.props.label}</Text>
				</View>
			</TouchableItem>
		);
	}
}

CheckboxItem.propTypes = {
	checked: types.checked,
	onPress: types.onPress,
	label: types.label
}

export default CheckboxItem;
<|endoftext|>


<commit_before>var Class = require('../../utils/Class');
var BaseSound = require('../BaseSound');
var HTML5AudioSound = new Class({
    Extends: BaseSound,
    initialize: function HTML5AudioSound(manager, key, config) {
        if (config === void 0) { config = {}; }
        /**
         * An array containing all HTML5 Audio tags that could be used for individual
         * sound's playback. Number of instances depends on the config value passed
         * to the Loader#audio method call, default is 1.
         *
         * @private
         * @property {HTMLAudioElement[]} tags
         */
        this.tags = manager.game.cache.audio.get(key);
        if (!this.tags) {
            console.error('No audio loaded in cache with key: \'' + key + '\'!');
            return;
        }
        /**
         * Reference to an HTML5 Audio tag used for playing sound.
         *
         * @private
         * @property {HTMLAudioElement} audio
         * @default null
         */
        this.audio = null;
        /**
         * Timestamp as generated by the Request Animation Frame or SetTimeout
         * representing the time at which the delayed sound playback should start.
         * Set to 0 if sound playback is not delayed.
         *
         * @private
         * @property {number} startTime
         * @default 0
         */
        this.startTime = 0;
        /**
         * Audio tag's playback position recorded on previous
         * update method call. Set to 0 if sound is not playing.
         *
         * @private
         * @property {number} previousTime
         * @default 0
         */
        this.previousTime = 0;
        /**
         * A queue of all actions performed on a sound object while audio was locked.
         * Once the audio gets unlocked, after an explicit user interaction,
         * all actions will be performed in chronological order.
         *
         * @private
         * @property {{
         *   sound: Phaser.Sound.HTML5AudioSound,
         *   type: string,
         *   name: string,
         *   value?: any,
         *   time: number,
         * }[]} touchLockedActionQueue
         */
        this.touchLockedActionQueue = manager.touchLocked ? [] : null;
        this.duration = this.tags[0].duration;
        this.totalDuration = this.tags[0].duration;
        BaseSound.call(this, manager, key, config);
    },
    play: function (markerName, config) {
        if (this.checkTouchLocked('method', 'play', [markerName, config])) {
            return false;
        }
        if (!BaseSound.prototype.play.call(this, markerName, config)) {
            return false;
        }
        //  \/\/\/ isPlaying = true, isPaused = false \/\/\/
        if (!this.pickAndPlayAudioTag()) {
            return false;
        }
        this.emit('play', this);
        return true;
    },
    pause: function () {
        if (this.checkTouchLocked('method', 'pause')) {
            return false;
        }
        if (this.startTime > 0) {
            return false;
        }
        if (!BaseSound.prototype.pause.call(this)) {
            return false;
        }
        //  \/\/\/ isPlaying = false, isPaused = true \/\/\/
        this.currentConfig.seek = this.audio.currentTime
            - (this.currentMarker ? this.currentMarker.start : 0);
        this.stopAndReleaseAudioTag();
        this.emit('pause', this);
        return true;
    },
    resume: function () {
        if (this.startTime > 0) {
            return false;
        }
        if (!BaseSound.prototype.resume.call(this)) {
            return false;
        }
        //  \/\/\/ isPlaying = true, isPaused = false \/\/\/
        if (!this.pickAndPlayAudioTag()) {
            return false;
        }
        this.emit('resume', this);
        return true;
    },
    stop: function () {
        if (!BaseSound.prototype.stop.call(this)) {
            return false;
        }
        //  \/\/\/ isPlaying = false, isPaused = false \/\/\/
        this.stopAndReleaseAudioTag();
        this.emit('stop', this);
        return true;
    },
    pickAndPlayAudioTag: function () {
        if (!this.pickAudioTag()) {
            this.reset();
            return false;
        }
        var seek = this.currentConfig.seek;
        var delay = this.currentConfig.delay;
        var offset = (this.currentMarker ? this.currentMarker.start : 0) + seek;
        this.previousTime = offset;
        this.audio.currentTime = offset;
        this.applyConfig();
        if (delay === 0) {
            this.startTime = 0;
            if (this.audio.paused) {
                this.audio.play();
            }
        }
        else {
            this.startTime = window.performance.now() + delay * 1000;
            if (!this.audio.paused) {
                this.audio.pause();
            }
        }
        this.resetConfig();
        return true;
    },
    pickAudioTag: function () {
        if (!this.audio) {
            for (var i = 0; i < this.tags.length; i++) {
                var audio = this.tags[i];
                if (audio.dataset.used === 'false') {
                    audio.dataset.used = 'true';
                    this.audio = audio;
                    return true;
                }
            }
            if (!this.manager.override) {
                return false;
            }
            var otherSounds_1 = [];
            this.manager.forEachActiveSound(function (sound) {
                if (sound.key === this.key && sound.audio) {
                    otherSounds_1.push(sound);
                }
            }, this);
            otherSounds_1.sort(function (a1, a2) {
                if (a1.loop === a2.loop) {
                    // sort by progress
                    return (a2.seek / a2.duration) - (a1.seek / a1.duration);
                }
                return a1.loop ? 1 : -1;
            });
            var selectedSound = otherSounds_1[0];
            this.audio = selectedSound.audio;
            selectedSound.reset();
            selectedSound.audio = null;
            selectedSound.startTime = 0;
            selectedSound.previousTime = 0;
        }
        return true;
    },
    stopAndReleaseAudioTag: function () {
        this.audio.pause();
        this.audio.dataset.used = 'false';
        this.audio = null;
        this.startTime = 0;
        this.previousTime = 0;
    },
    reset: function () {
        BaseSound.prototype.stop.call(this);
    },
    onBlur: function () {
        this.isPlaying = false;
        this.isPaused = true;
        this.currentConfig.seek = this.audio.currentTime -
            (this.currentMarker ? this.currentMarker.start : 0);
        this.currentConfig.delay = Math.max(0, (this.startTime - window.performance.now()) / 1000);
        this.stopAndReleaseAudioTag();
    },
    onFocus: function () {
        this.isPlaying = true;
        this.isPaused = false;
        this.pickAndPlayAudioTag();
    },
    update: function (time, delta) {
        if (this.isPlaying) {
            // handling delayed playback
            if (this.startTime > 0) {
                if (this.startTime < time - this.manager.audioPlayDelay) {
                    this.audio.currentTime += Math.max(0, time - this.startTime) / 1000;
                    this.startTime = 0;
                    this.previousTime = this.audio.currentTime;
                    this.audio.play();
                }
                return;
            }
            // handle looping and ending
            var startTime = this.currentMarker ? this.currentMarker.start : 0;
            var endTime = startTime + this.duration;
            var currentTime = this.audio.currentTime;
            if (this.currentConfig.loop) {
                if (currentTime >= endTime - this.manager.loopEndOffset) {
                    this.audio.currentTime = startTime + Math.max(0, currentTime - endTime);
                    currentTime = this.audio.currentTime;
                }
                else if (currentTime < startTime) {
                    this.audio.currentTime += startTime;
                    currentTime = this.audio.currentTime;
                }
                if (currentTime < this.previousTime) {
                    this.emit('looped', this);
                }
            }
            else if (currentTime >= endTime) {
                this.reset();
                this.stopAndReleaseAudioTag();
                this.emit('ended', this);
                return;
            }
            this.previousTime = currentTime;
        }
    },
    destroy: function () {
        BaseSound.prototype.destroy.call(this);
        this.tags = null;
        if (this.audio) {
            this.stopAndReleaseAudioTag();
        }
    },
    setMute: function () {
        if (this.audio) {
            this.audio.muted = this.currentConfig.mute || this.manager.mute;
        }
    },
    setVolume: function () {
        if (this.audio) {
            this.audio.volume = this.currentConfig.volume * this.manager.volume;
        }
    },
    setRate: function () {
        BaseSound.prototype.setRate.call(this);
        if (this.audio) {
            this.audio.playbackRate = this.totalRate;
        }
    },
    checkTouchLocked: function (type, name, value) {
        if (this.manager.touchLocked) {
            this.touchLockedActionQueue.push({
                sound: this,
                type: type,
                name: name,
                value: value,
                time: window.performance.now()
            });
            return true;
        }
        return false;
    }
});
/**
 * Mute setting.
 *
 * @name Phaser.Sound.HTML5AudioSound#mute
 * @property {boolean} mute
 */
Object.defineProperty(HTML5AudioSound.prototype, 'mute', {
    get: function () {
        return this.currentConfig.mute;
    },
    set: function (value) {
        this.currentConfig.mute = value;
        this.setMute();
        this.emit('mute', this, value);
    }
});
/**
 * Volume setting.
 *
 * @name Phaser.Sound.HTML5AudioSound#volume
 * @property {number} volume
 */
Object.defineProperty(HTML5AudioSound.prototype, 'volume', {
    get: function () {
        return this.currentConfig.volume;
    },
    set: function (value) {
        this.currentConfig.volume = value;
        this.setVolume();
        this.emit('volume', this, value);
    }
});
/**
 * Current position of playing sound.
 *
 * @name Phaser.Sound.HTML5AudioSound#seek
 * @property {number} seek
 */
Object.defineProperty(HTML5AudioSound.prototype, 'seek', {
    get: function () {
        if (this.isPlaying) {
            return this.audio.currentTime -
                (this.currentMarker ? this.currentMarker.start : 0);
        }
        else if (this.isPaused) {
            return this.currentConfig.seek;
        }
        else {
            return 0;
        }
    },
    set: function (value) {
        if (this.startTime > 0) {
            return;
        }
        if (this.isPlaying || this.isPaused) {
            value = Math.min(Math.max(0, value), this.duration);
            if (this.isPlaying) {
                this.previousTime = value;
                this.audio.currentTime = value;
            }
            else if (this.isPaused) {
                this.currentConfig.seek = value;
            }
            this.emit('seek', this, value);
        }
    }
});
/**
 * Property indicating whether or not
 * the sound or current sound marker will loop.
 *
 * @name Phaser.Sound.HTML5AudioSound#loop
 * @property {boolean} loop
 */
Object.defineProperty(HTML5AudioSound.prototype, 'loop', {
    get: function () {
        return this.currentConfig.loop;
    },
    set: function (value) {
        this.currentConfig.loop = value;
        if (this.audio) {
            this.audio.loop = value;
        }
        this.emit('loop', this, value);
    }
});
module.exports = HTML5AudioSound;
<commit_msg>Using checkTouchLocked with resume method<commit_after>var Class = require('../../utils/Class');
var BaseSound = require('../BaseSound');
var HTML5AudioSound = new Class({
    Extends: BaseSound,
    initialize: function HTML5AudioSound(manager, key, config) {
        if (config === void 0) { config = {}; }
        /**
         * An array containing all HTML5 Audio tags that could be used for individual
         * sound's playback. Number of instances depends on the config value passed
         * to the Loader#audio method call, default is 1.
         *
         * @private
         * @property {HTMLAudioElement[]} tags
         */
        this.tags = manager.game.cache.audio.get(key);
        if (!this.tags) {
            console.error('No audio loaded in cache with key: \'' + key + '\'!');
            return;
        }
        /**
         * Reference to an HTML5 Audio tag used for playing sound.
         *
         * @private
         * @property {HTMLAudioElement} audio
         * @default null
         */
        this.audio = null;
        /**
         * Timestamp as generated by the Request Animation Frame or SetTimeout
         * representing the time at which the delayed sound playback should start.
         * Set to 0 if sound playback is not delayed.
         *
         * @private
         * @property {number} startTime
         * @default 0
         */
        this.startTime = 0;
        /**
         * Audio tag's playback position recorded on previous
         * update method call. Set to 0 if sound is not playing.
         *
         * @private
         * @property {number} previousTime
         * @default 0
         */
        this.previousTime = 0;
        /**
         * A queue of all actions performed on a sound object while audio was locked.
         * Once the audio gets unlocked, after an explicit user interaction,
         * all actions will be performed in chronological order.
         *
         * @private
         * @property {{
         *   sound: Phaser.Sound.HTML5AudioSound,
         *   type: string,
         *   name: string,
         *   value?: any,
         *   time: number,
         * }[]} touchLockedActionQueue
         */
        this.touchLockedActionQueue = manager.touchLocked ? [] : null;
        this.duration = this.tags[0].duration;
        this.totalDuration = this.tags[0].duration;
        BaseSound.call(this, manager, key, config);
    },
    play: function (markerName, config) {
        if (this.checkTouchLocked('method', 'play', [markerName, config])) {
            return false;
        }
        if (!BaseSound.prototype.play.call(this, markerName, config)) {
            return false;
        }
        //  \/\/\/ isPlaying = true, isPaused = false \/\/\/
        if (!this.pickAndPlayAudioTag()) {
            return false;
        }
        this.emit('play', this);
        return true;
    },
    pause: function () {
        if (this.checkTouchLocked('method', 'pause')) {
            return false;
        }
        if (this.startTime > 0) {
            return false;
        }
        if (!BaseSound.prototype.pause.call(this)) {
            return false;
        }
        //  \/\/\/ isPlaying = false, isPaused = true \/\/\/
        this.currentConfig.seek = this.audio.currentTime
            - (this.currentMarker ? this.currentMarker.start : 0);
        this.stopAndReleaseAudioTag();
        this.emit('pause', this);
        return true;
    },
    resume: function () {
        if (this.checkTouchLocked('method', 'resume')) {
            return false;
        }
        if (this.startTime > 0) {
            return false;
        }
        if (!BaseSound.prototype.resume.call(this)) {
            return false;
        }
        //  \/\/\/ isPlaying = true, isPaused = false \/\/\/
        if (!this.pickAndPlayAudioTag()) {
            return false;
        }
        this.emit('resume', this);
        return true;
    },
    stop: function () {
        if (!BaseSound.prototype.stop.call(this)) {
            return false;
        }
        //  \/\/\/ isPlaying = false, isPaused = false \/\/\/
        this.stopAndReleaseAudioTag();
        this.emit('stop', this);
        return true;
    },
    pickAndPlayAudioTag: function () {
        if (!this.pickAudioTag()) {
            this.reset();
            return false;
        }
        var seek = this.currentConfig.seek;
        var delay = this.currentConfig.delay;
        var offset = (this.currentMarker ? this.currentMarker.start : 0) + seek;
        this.previousTime = offset;
        this.audio.currentTime = offset;
        this.applyConfig();
        if (delay === 0) {
            this.startTime = 0;
            if (this.audio.paused) {
                this.audio.play();
            }
        }
        else {
            this.startTime = window.performance.now() + delay * 1000;
            if (!this.audio.paused) {
                this.audio.pause();
            }
        }
        this.resetConfig();
        return true;
    },
    pickAudioTag: function () {
        if (!this.audio) {
            for (var i = 0; i < this.tags.length; i++) {
                var audio = this.tags[i];
                if (audio.dataset.used === 'false') {
                    audio.dataset.used = 'true';
                    this.audio = audio;
                    return true;
                }
            }
            if (!this.manager.override) {
                return false;
            }
            var otherSounds_1 = [];
            this.manager.forEachActiveSound(function (sound) {
                if (sound.key === this.key && sound.audio) {
                    otherSounds_1.push(sound);
                }
            }, this);
            otherSounds_1.sort(function (a1, a2) {
                if (a1.loop === a2.loop) {
                    // sort by progress
                    return (a2.seek / a2.duration) - (a1.seek / a1.duration);
                }
                return a1.loop ? 1 : -1;
            });
            var selectedSound = otherSounds_1[0];
            this.audio = selectedSound.audio;
            selectedSound.reset();
            selectedSound.audio = null;
            selectedSound.startTime = 0;
            selectedSound.previousTime = 0;
        }
        return true;
    },
    stopAndReleaseAudioTag: function () {
        this.audio.pause();
        this.audio.dataset.used = 'false';
        this.audio = null;
        this.startTime = 0;
        this.previousTime = 0;
    },
    reset: function () {
        BaseSound.prototype.stop.call(this);
    },
    onBlur: function () {
        this.isPlaying = false;
        this.isPaused = true;
        this.currentConfig.seek = this.audio.currentTime -
            (this.currentMarker ? this.currentMarker.start : 0);
        this.currentConfig.delay = Math.max(0, (this.startTime - window.performance.now()) / 1000);
        this.stopAndReleaseAudioTag();
    },
    onFocus: function () {
        this.isPlaying = true;
        this.isPaused = false;
        this.pickAndPlayAudioTag();
    },
    update: function (time, delta) {
        if (this.isPlaying) {
            // handling delayed playback
            if (this.startTime > 0) {
                if (this.startTime < time - this.manager.audioPlayDelay) {
                    this.audio.currentTime += Math.max(0, time - this.startTime) / 1000;
                    this.startTime = 0;
                    this.previousTime = this.audio.currentTime;
                    this.audio.play();
                }
                return;
            }
            // handle looping and ending
            var startTime = this.currentMarker ? this.currentMarker.start : 0;
            var endTime = startTime + this.duration;
            var currentTime = this.audio.currentTime;
            if (this.currentConfig.loop) {
                if (currentTime >= endTime - this.manager.loopEndOffset) {
                    this.audio.currentTime = startTime + Math.max(0, currentTime - endTime);
                    currentTime = this.audio.currentTime;
                }
                else if (currentTime < startTime) {
                    this.audio.currentTime += startTime;
                    currentTime = this.audio.currentTime;
                }
                if (currentTime < this.previousTime) {
                    this.emit('looped', this);
                }
            }
            else if (currentTime >= endTime) {
                this.reset();
                this.stopAndReleaseAudioTag();
                this.emit('ended', this);
                return;
            }
            this.previousTime = currentTime;
        }
    },
    destroy: function () {
        BaseSound.prototype.destroy.call(this);
        this.tags = null;
        if (this.audio) {
            this.stopAndReleaseAudioTag();
        }
    },
    setMute: function () {
        if (this.audio) {
            this.audio.muted = this.currentConfig.mute || this.manager.mute;
        }
    },
    setVolume: function () {
        if (this.audio) {
            this.audio.volume = this.currentConfig.volume * this.manager.volume;
        }
    },
    setRate: function () {
        BaseSound.prototype.setRate.call(this);
        if (this.audio) {
            this.audio.playbackRate = this.totalRate;
        }
    },
    checkTouchLocked: function (type, name, value) {
        if (this.manager.touchLocked) {
            this.touchLockedActionQueue.push({
                sound: this,
                type: type,
                name: name,
                value: value,
                time: window.performance.now()
            });
            return true;
        }
        return false;
    }
});
/**
 * Mute setting.
 *
 * @name Phaser.Sound.HTML5AudioSound#mute
 * @property {boolean} mute
 */
Object.defineProperty(HTML5AudioSound.prototype, 'mute', {
    get: function () {
        return this.currentConfig.mute;
    },
    set: function (value) {
        this.currentConfig.mute = value;
        this.setMute();
        this.emit('mute', this, value);
    }
});
/**
 * Volume setting.
 *
 * @name Phaser.Sound.HTML5AudioSound#volume
 * @property {number} volume
 */
Object.defineProperty(HTML5AudioSound.prototype, 'volume', {
    get: function () {
        return this.currentConfig.volume;
    },
    set: function (value) {
        this.currentConfig.volume = value;
        this.setVolume();
        this.emit('volume', this, value);
    }
});
/**
 * Current position of playing sound.
 *
 * @name Phaser.Sound.HTML5AudioSound#seek
 * @property {number} seek
 */
Object.defineProperty(HTML5AudioSound.prototype, 'seek', {
    get: function () {
        if (this.isPlaying) {
            return this.audio.currentTime -
                (this.currentMarker ? this.currentMarker.start : 0);
        }
        else if (this.isPaused) {
            return this.currentConfig.seek;
        }
        else {
            return 0;
        }
    },
    set: function (value) {
        if (this.startTime > 0) {
            return;
        }
        if (this.isPlaying || this.isPaused) {
            value = Math.min(Math.max(0, value), this.duration);
            if (this.isPlaying) {
                this.previousTime = value;
                this.audio.currentTime = value;
            }
            else if (this.isPaused) {
                this.currentConfig.seek = value;
            }
            this.emit('seek', this, value);
        }
    }
});
/**
 * Property indicating whether or not
 * the sound or current sound marker will loop.
 *
 * @name Phaser.Sound.HTML5AudioSound#loop
 * @property {boolean} loop
 */
Object.defineProperty(HTML5AudioSound.prototype, 'loop', {
    get: function () {
        return this.currentConfig.loop;
    },
    set: function (value) {
        this.currentConfig.loop = value;
        if (this.audio) {
            this.audio.loop = value;
        }
        this.emit('loop', this, value);
    }
});
module.exports = HTML5AudioSound;
<|endoftext|>