<commit_before>import Ember from 'ember';
import Row from 'ember-light-table/classes/Row';
import Column from 'ember-light-table/classes/Column';
import SyncArrayProxy from 'ember-light-table/-private/sync-array-proxy';
import { mergeOptionsWithGlobals } from 'ember-light-table/-private/global-options';
import fixProto from 'ember-light-table/utils/fix-proto';

const {
  get,
  computed,
  isNone,
  A: emberArray,
  Object: EmberObject
} = Ember;

const RowSyncArrayProxy = SyncArrayProxy.extend({
  serializeContentObjects(objects) {
    return Table.createRows(objects);
  },

  serializeSyncArrayObjects(objects) {
    return objects.map((o) => get(o, 'content'));
  }
});

/**
 * @module Table
 * @private
 */

/**
 * @module Table
 * @class Table
 */
export default class Table extends EmberObject.extend({
  /**
   * @property columns
   * @type {Ember.Array}
   * @default []
   */
  columns: null,

  /**
   * @property rows
   * @type {Ember.Array}
   * @default []
   */
  rows: null,

  /**
   * @property isEmpty
   * @type {Boolean}
   */
  isEmpty: computed.empty('rows').readOnly(),

  /**
   * @property expandedRows
   * @type {Ember.Array}
   */
  expandedRows: computed.filterBy('rows', 'expanded', true).readOnly(),

  /**
   * @property selectedRows
   * @type {Ember.Array}
   */
  selectedRows: computed.filterBy('rows', 'selected', true).readOnly(),

  /**
   * @property visibleRows
   * @type {Ember.Array}
   */
  visibleRows: computed.filterBy('rows', 'hidden', false).readOnly(),

  /**
   * @property sortableColumns
   * @type {Ember.Array}
   */
  sortableColumns: computed.filterBy('visibleColumns', 'sortable', true).readOnly(),

  /**
   * @property sortedColumns
   * @type {Ember.Array}
   */
  sortedColumns: computed.filterBy('visibleColumns', 'sorted', true).readOnly(),

  /**
   * @property hideableColumns
   * @type {Ember.Array}
   */
  hideableColumns: computed.filterBy('allColumns', 'hideable', true).readOnly(),

  /**
   * @property hiddenColumns
   * @type {Ember.Array}
   */
  hiddenColumns: computed.filterBy('allColumns', 'hidden', true).readOnly(),

  /**
   * @property responsiveHiddenColumns
   * @type {Ember.Array}
   */
  responsiveHiddenColumns: computed.filterBy('allColumns', 'responsiveHidden', true).readOnly(),

  /**
   * @property visibleColumns
   * @type {Ember.Array}
   */
  visibleColumns: computed.filterBy('allColumns', 'isHidden', false).readOnly(),

  /**
   * @property visibleColumnGroups
   * @type {Ember.Array}
   */
  visibleColumnGroups: computed('columns.[]', 'columns.@each.{isHidden,isVisibleGroupColumn}', function() {
    return this.get('columns').reduce((arr, c) => {
      if (c.get('isVisibleGroupColumn') || (!c.get('isGroupColumn') && !c.get('isHidden'))) {
        arr.pushObject(c);
      }
      return arr;
    }, emberArray([]));
  }).readOnly(),

  /**
   * @property visibleSubColumns
   * @type {Ember.Array}
   */
  visibleSubColumns: computed('columns.[]', 'columns.@each.visibleSubColumns', function() {
    return emberArray([].concat(...this.get('columns').getEach('visibleSubColumns')));
  }).readOnly(),

  /**
   * @property allColumns
   * @type {Ember.Array}
   */
  allColumns: computed('columns.[]', 'columns.@each.subColumns', function() {
    return this.get('columns').reduce((arr, c) => {
      arr.pushObjects(c.get('isGroupColumn') ? c.get('subColumns') : [c]);
      return arr;
    }, emberArray([]));
  }).readOnly()
}) {
  /**
   * @class Table
   * @constructor
   * @param  {Array} columns
   * @param  {Array} rows
   * @param  {Object} options
   *    - enableSync ( _Boolean_ ): If true, creates a two way sync between the table's rows
   *                                and the passed rows collection
   */
  constructor(columns = [], rows = [], options = {}) {
    super();

    let _columns = emberArray(Table.createColumns(columns));
    let _rows = emberArray(Table.createRows(rows));
    let _options = mergeOptionsWithGlobals(options);

    if (_options.enableSync) {
      _rows = RowSyncArrayProxy.create({
        syncArray: rows,
        content: _rows
      });
    }

    this.setProperties({
      columns: _columns,
      rows: _rows
    });
  }

  destroy() {
    this._super(...arguments);

    let rows = this.get('rows');

    if (rows instanceof RowSyncArrayProxy) {
      rows.destroy();
    }
  }

  // Rows

  /**
   * Replace all the row's content with content of the argument. If argument is an empty array rows will be cleared.
   * @method setRows
   * @param  {Array} rows
   * @param  {Object} options
   * @return {Array} rows
   */
  setRows(rows = [], options = {}) {
    return this.get('rows').setObjects(Table.createRows(rows, options));
  }

  /**
   * The same as `setRows`, however the given array is synced, meaning that
   * mutating the array also updates the table and vice-versa.
   *
   * Also see `enableSync` in the constructor options.
   *
   * @method setRowsSynced
   * @param  {Array} rows
   * @param  {Object} options
   * @return {Array} rows
   */
  setRowsSynced(rows = [], options = {}) {
    let _rows = RowSyncArrayProxy.create({
      syncArray: rows,
      content: emberArray(Table.createRows(rows, options))
    });

    return this.set('rows', _rows);
  }

  /**
   * Push the object onto the end of the row array if it is not already present.
   * @method addRow
   * @param  {Object} row
   * @param  {Object} options
   */
  addRow(row, options = {}) {
    if (row instanceof Row) {
      this.get('rows').addObject(row);
    } else if (isNone(this.get('rows').findBy('content', row))) {
      this.pushRow(row, options);
    }
  }

  /**
   * Push the objects onto the end of the row array if it is not already present.
   * @method addRows
   * @param  {Array} rows
   * @param  {Object} options
   */
  addRows(rows = [], options = {}) {
    rows.forEach((r) => this.addRow(r, options));
  }

  /**
   * Push the object onto the end of the row array.
   * @method pushRow
   * @param  {Object} row
   * @param  {Object} options
   * @return {Row} pushed row
   */
  pushRow(row, options = {}) {
    let _row = Table.createRow(row, options);
    this.get('rows').pushObject(_row);
    return _row;
  }

  /**
   * Push the object onto the end of the row array.
   * @method pushRows
   * @param  {Array}  rows
   * @param  {Object} options
   * @return {Array} pushed rows
   */
  pushRows(rows = [], options = {}) {
    let _rows = Table.createRows(rows, options);
    this.get('rows').pushObjects(_rows);
    return _rows;
  }

  /**
   * Insert a row at the specified index.
   * @method insertRowAt
   * @param  {Number}  index
   * @param  {Object}  row
   * @param  {Object} options
   * @return {Row} inserted row
   */
  insertRowAt(index, row, options = {}) {
    let _row = Table.createRow(row, options);
    this.get('rows').insertAt(index, _row);
    return _row;
  }

  /**
   * Remove all occurrences of an object in the rows
   * @method removeRow
   * @param  {Object}  row
   */
  removeRow(row) {
    if (row instanceof Row) {
      this.get('rows').removeObject(row);
    } else {
      this.get('rows').removeObjects(this.get('rows').filterBy('content', row));
    }
  }

  /**
   * Removes each object in the passed enumerable from the rows.
   * @method removeRows
   * @param  {Array}    rows
   */
  removeRows(rows = []) {
    rows.forEach((r) => this.removeRow(r));
  }

  /**
   * Remove a row at the specified index
   * @method removeRowAt
   * @param  {Number}  index
   */
  removeRowAt(index) {
    this.get('rows').removeAt(index);
  }

  // Columns

  /**
   * Replace all the column's content with content of the argument. If argument is an empty array columns will be cleared.
   * @method setColumns
   * @param  {Array} columns
   * @return {Array} columns
   */
  setColumns(columns = []) {
    return this.get('columns').setObjects(Table.createColumns(columns));
  }

  /**
   * Push the object onto the end of the column array if it is not already present.
   * @method addColumn
   * @param  {Object} column
   */
  addColumn(column) {
    this.get('columns').addObject(Table.createColumn(column));
  }

  /**
   * Push the objects onto the end of the column array if it is not already present.
   * @method addColumns
   * @param  {Array} columns
   */
  addColumns(columns = []) {
    this.get('columns').addObjects(Table.createColumns(columns));
  }

  /**
   * Push the object onto the end of the column array.
   * @method pushColumn
   * @param  {Object} column
   * @return {Column} pushed column
   */
  pushColumn(column) {
    let _column = Table.createColumn(column);
    this.get('columns').pushObject(_column);
    return _column;
  }

  /**
   * Push the object onto the end of the column array.
   * @method pushColumns
   * @param  {Array}  columns
   * @return {Array} pushed columns
   */
  pushColumns(columns = []) {
    let _columns = Table.createColumns(columns);
    this.get('columns').pushObjects(_columns);
    return _columns;
  }

  /**
   * Insert a column at the specified index.
   * @method insertColumnAt
   * @param  {Number}  index
   * @param  {Object}  column
   * @return {Column} inserted column
   */
  insertColumnAt(index, column) {
    let _column = Table.createColumn(column);
    this.get('columns').insertAt(index, _column);
    return _column;
  }

  /**
   * Remove all occurrences of an object in the columns
   * @method removeColumn
   * @param  {Object}  column
   */
  removeColumn(column) {
    return this.get('columns').removeObject(column);
  }

  /**
   * Removes each object in the passed enumerable from the columns.
   * @method removeColumns
   * @param  {Array}    columns
   */
  removeColumns(columns = []) {
    return this.get('columns').removeObjects(columns);
  }

  /**
   * Remove a column at the specified index
   * @method removeColumnAt
   * @param  {Number}  index
   */
  removeColumnAt(index) {
    this.get('columns').removeAt(index);
  }

  /**
   * Create a Row object with the given content
   * @method createRow
   * @static
   * @param  {Object}  content
   * @param  {Object}  options
   * @return {Row}
   */
  static createRow(content, options = {}) {
    return new Row(content, options);
  }

  /**
   * Create a collection of Row objects with the given collection
   * @method createRows
   * @static
   * @param  {Array}  rows
   * @param  {Object} options
   * @return {Array}
   */
  static createRows(rows = [], options = {}) {
    return rows.map((r) => Table.createRow(r, options));
  }

  /**
   * Create a Column object with the given options
   * @method createColumn
   * @static
   * @param  {Object}  column
   * @return {Column}
   */
  static createColumn(column) {
    return new Column(column);
  }

  /**
   * Create a collection of Column objects with the given collection
   * @method createColumns
   * @static
   * @param  {Array}  columns
   * @return {Array}
   */
  static createColumns(columns = []) {
    return columns.map((c) => Table.createColumn(c));
  }
}

// https://github.com/offirgolan/ember-light-table/issues/436#issuecomment-310138868
fixProto(Table);
<commit_msg>Table: add `rowOptions` to constructor<commit_after>import Ember from 'ember';
import Row from 'ember-light-table/classes/Row';
import Column from 'ember-light-table/classes/Column';
import SyncArrayProxy from 'ember-light-table/-private/sync-array-proxy';
import { mergeOptionsWithGlobals } from 'ember-light-table/-private/global-options';
import fixProto from 'ember-light-table/utils/fix-proto';

const {
  get,
  computed,
  isNone,
  A: emberArray,
  Object: EmberObject
} = Ember;

const RowSyncArrayProxy = SyncArrayProxy.extend({
  serializeContentObjects(objects) {
    return Table.createRows(objects);
  },

  serializeSyncArrayObjects(objects) {
    return objects.map((o) => get(o, 'content'));
  }
});

/**
 * @module Table
 * @private
 */

/**
 * @module Table
 * @class Table
 */
export default class Table extends EmberObject.extend({
  /**
   * @property columns
   * @type {Ember.Array}
   * @default []
   */
  columns: null,

  /**
   * @property rows
   * @type {Ember.Array}
   * @default []
   */
  rows: null,

  /**
   * @property isEmpty
   * @type {Boolean}
   */
  isEmpty: computed.empty('rows').readOnly(),

  /**
   * @property expandedRows
   * @type {Ember.Array}
   */
  expandedRows: computed.filterBy('rows', 'expanded', true).readOnly(),

  /**
   * @property selectedRows
   * @type {Ember.Array}
   */
  selectedRows: computed.filterBy('rows', 'selected', true).readOnly(),

  /**
   * @property visibleRows
   * @type {Ember.Array}
   */
  visibleRows: computed.filterBy('rows', 'hidden', false).readOnly(),

  /**
   * @property sortableColumns
   * @type {Ember.Array}
   */
  sortableColumns: computed.filterBy('visibleColumns', 'sortable', true).readOnly(),

  /**
   * @property sortedColumns
   * @type {Ember.Array}
   */
  sortedColumns: computed.filterBy('visibleColumns', 'sorted', true).readOnly(),

  /**
   * @property hideableColumns
   * @type {Ember.Array}
   */
  hideableColumns: computed.filterBy('allColumns', 'hideable', true).readOnly(),

  /**
   * @property hiddenColumns
   * @type {Ember.Array}
   */
  hiddenColumns: computed.filterBy('allColumns', 'hidden', true).readOnly(),

  /**
   * @property responsiveHiddenColumns
   * @type {Ember.Array}
   */
  responsiveHiddenColumns: computed.filterBy('allColumns', 'responsiveHidden', true).readOnly(),

  /**
   * @property visibleColumns
   * @type {Ember.Array}
   */
  visibleColumns: computed.filterBy('allColumns', 'isHidden', false).readOnly(),

  /**
   * @property visibleColumnGroups
   * @type {Ember.Array}
   */
  visibleColumnGroups: computed('columns.[]', 'columns.@each.{isHidden,isVisibleGroupColumn}', function() {
    return this.get('columns').reduce((arr, c) => {
      if (c.get('isVisibleGroupColumn') || (!c.get('isGroupColumn') && !c.get('isHidden'))) {
        arr.pushObject(c);
      }
      return arr;
    }, emberArray([]));
  }).readOnly(),

  /**
   * @property visibleSubColumns
   * @type {Ember.Array}
   */
  visibleSubColumns: computed('columns.[]', 'columns.@each.visibleSubColumns', function() {
    return emberArray([].concat(...this.get('columns').getEach('visibleSubColumns')));
  }).readOnly(),

  /**
   * @property allColumns
   * @type {Ember.Array}
   */
  allColumns: computed('columns.[]', 'columns.@each.subColumns', function() {
    return this.get('columns').reduce((arr, c) => {
      arr.pushObjects(c.get('isGroupColumn') ? c.get('subColumns') : [c]);
      return arr;
    }, emberArray([]));
  }).readOnly()
}) {
  /**
   * @class Table
   * @constructor
   * @param  {Array} columns
   * @param  {Array} rows
   * @param  {Object} options
   * @param  {Boolean} options.enableSync If `true`, creates a two way sync
   *           between the table's rows and the passed rows collection. Also see
   *           `setRowsSynced(rows)`.
   * @param  {Object}  options.rowOptions Options hash passed through to
   *           `createRow(content, options)`.
   */
  constructor(columns = [], rows = [], options = {}) {
    super();

    let _options = mergeOptionsWithGlobals(options);
    let _columns = emberArray(Table.createColumns(columns));
    let _rows = emberArray(Table.createRows(rows, _options.rowOptions));

    if (_options.enableSync) {
      _rows = RowSyncArrayProxy.create({
        syncArray: rows,
        content: _rows
      });
    }

    this.setProperties({
      columns: _columns,
      rows: _rows
    });
  }

  destroy() {
    this._super(...arguments);

    let rows = this.get('rows');

    if (rows instanceof RowSyncArrayProxy) {
      rows.destroy();
    }
  }

  // Rows

  /**
   * Replace all the row's content with content of the argument. If argument is an empty array rows will be cleared.
   * @method setRows
   * @param  {Array} rows
   * @param  {Object} options
   * @return {Array} rows
   */
  setRows(rows = [], options = {}) {
    return this.get('rows').setObjects(Table.createRows(rows, options));
  }

  /**
   * The same as `setRows`, however the given array is synced, meaning that
   * mutating the array also updates the table and vice-versa.
   *
   * Also see `enableSync` in the constructor options.
   *
   * @method setRowsSynced
   * @param  {Array} rows
   * @param  {Object} options
   * @return {Array} rows
   */
  setRowsSynced(rows = [], options = {}) {
    let _rows = RowSyncArrayProxy.create({
      syncArray: rows,
      content: emberArray(Table.createRows(rows, options))
    });

    return this.set('rows', _rows);
  }

  /**
   * Push the object onto the end of the row array if it is not already present.
   * @method addRow
   * @param  {Object} row
   * @param  {Object} options
   */
  addRow(row, options = {}) {
    if (row instanceof Row) {
      this.get('rows').addObject(row);
    } else if (isNone(this.get('rows').findBy('content', row))) {
      this.pushRow(row, options);
    }
  }

  /**
   * Push the objects onto the end of the row array if it is not already present.
   * @method addRows
   * @param  {Array} rows
   * @param  {Object} options
   */
  addRows(rows = [], options = {}) {
    rows.forEach((r) => this.addRow(r, options));
  }

  /**
   * Push the object onto the end of the row array.
   * @method pushRow
   * @param  {Object} row
   * @param  {Object} options
   * @return {Row} pushed row
   */
  pushRow(row, options = {}) {
    let _row = Table.createRow(row, options);
    this.get('rows').pushObject(_row);
    return _row;
  }

  /**
   * Push the object onto the end of the row array.
   * @method pushRows
   * @param  {Array}  rows
   * @param  {Object} options
   * @return {Array} pushed rows
   */
  pushRows(rows = [], options = {}) {
    let _rows = Table.createRows(rows, options);
    this.get('rows').pushObjects(_rows);
    return _rows;
  }

  /**
   * Insert a row at the specified index.
   * @method insertRowAt
   * @param  {Number}  index
   * @param  {Object}  row
   * @param  {Object} options
   * @return {Row} inserted row
   */
  insertRowAt(index, row, options = {}) {
    let _row = Table.createRow(row, options);
    this.get('rows').insertAt(index, _row);
    return _row;
  }

  /**
   * Remove all occurrences of an object in the rows
   * @method removeRow
   * @param  {Object}  row
   */
  removeRow(row) {
    if (row instanceof Row) {
      this.get('rows').removeObject(row);
    } else {
      this.get('rows').removeObjects(this.get('rows').filterBy('content', row));
    }
  }

  /**
   * Removes each object in the passed enumerable from the rows.
   * @method removeRows
   * @param  {Array}    rows
   */
  removeRows(rows = []) {
    rows.forEach((r) => this.removeRow(r));
  }

  /**
   * Remove a row at the specified index
   * @method removeRowAt
   * @param  {Number}  index
   */
  removeRowAt(index) {
    this.get('rows').removeAt(index);
  }

  // Columns

  /**
   * Replace all the column's content with content of the argument. If argument is an empty array columns will be cleared.
   * @method setColumns
   * @param  {Array} columns
   * @return {Array} columns
   */
  setColumns(columns = []) {
    return this.get('columns').setObjects(Table.createColumns(columns));
  }

  /**
   * Push the object onto the end of the column array if it is not already present.
   * @method addColumn
   * @param  {Object} column
   */
  addColumn(column) {
    this.get('columns').addObject(Table.createColumn(column));
  }

  /**
   * Push the objects onto the end of the column array if it is not already present.
   * @method addColumns
   * @param  {Array} columns
   */
  addColumns(columns = []) {
    this.get('columns').addObjects(Table.createColumns(columns));
  }

  /**
   * Push the object onto the end of the column array.
   * @method pushColumn
   * @param  {Object} column
   * @return {Column} pushed column
   */
  pushColumn(column) {
    let _column = Table.createColumn(column);
    this.get('columns').pushObject(_column);
    return _column;
  }

  /**
   * Push the object onto the end of the column array.
   * @method pushColumns
   * @param  {Array}  columns
   * @return {Array} pushed columns
   */
  pushColumns(columns = []) {
    let _columns = Table.createColumns(columns);
    this.get('columns').pushObjects(_columns);
    return _columns;
  }

  /**
   * Insert a column at the specified index.
   * @method insertColumnAt
   * @param  {Number}  index
   * @param  {Object}  column
   * @return {Column} inserted column
   */
  insertColumnAt(index, column) {
    let _column = Table.createColumn(column);
    this.get('columns').insertAt(index, _column);
    return _column;
  }

  /**
   * Remove all occurrences of an object in the columns
   * @method removeColumn
   * @param  {Object}  column
   */
  removeColumn(column) {
    return this.get('columns').removeObject(column);
  }

  /**
   * Removes each object in the passed enumerable from the columns.
   * @method removeColumns
   * @param  {Array}    columns
   */
  removeColumns(columns = []) {
    return this.get('columns').removeObjects(columns);
  }

  /**
   * Remove a column at the specified index
   * @method removeColumnAt
   * @param  {Number}  index
   */
  removeColumnAt(index) {
    this.get('columns').removeAt(index);
  }

  /**
   * Create a Row object with the given content
   * @method createRow
   * @static
   * @param  {Object}  content
   * @param  {Object}  options
   * @return {Row}
   */
  static createRow(content, options = {}) {
    return new Row(content, options);
  }

  /**
   * Create a collection of Row objects with the given collection
   * @method createRows
   * @static
   * @param  {Array}  rows
   * @param  {Object} options
   * @return {Array}
   */
  static createRows(rows = [], options = {}) {
    return rows.map((r) => Table.createRow(r, options));
  }

  /**
   * Create a Column object with the given options
   * @method createColumn
   * @static
   * @param  {Object}  column
   * @return {Column}
   */
  static createColumn(column) {
    return new Column(column);
  }

  /**
   * Create a collection of Column objects with the given collection
   * @method createColumns
   * @static
   * @param  {Array}  columns
   * @return {Array}
   */
  static createColumns(columns = []) {
    return columns.map((c) => Table.createColumn(c));
  }
}

// https://github.com/offirgolan/ember-light-table/issues/436#issuecomment-310138868
fixProto(Table);
<|endoftext|>


<commit_before>'use strict';

import { documentReady, getDirection } from './shims';
import {
  setAttributes, getAttributes, translateFragment, translateMutations,
  getResourceLinks
} from './dom';

const observerConfig = {
  attributes: true,
  characterData: false,
  childList: true,
  subtree: true,
  attributeFilter: ['data-l10n-id', 'data-l10n-args']
};

const readiness = new WeakMap();

export class View {
  constructor(client, doc) {
    this._doc = doc;
    this.pseudo = {
      'qps-ploc': createPseudo(this, 'qps-ploc'),
      'qps-plocm': createPseudo(this, 'qps-plocm')
    };

    this._interactive = documentReady().then(
      () => init(this, client));

    const observer = new MutationObserver(onMutations.bind(this));
    this._observe = () => observer.observe(doc, observerConfig);
    this._disconnect = () => observer.disconnect();

    const translateView = langs => translateDocument(this, langs);
    client.on('translateDocument', translateView);
    this.ready = this._interactive.then(
      client => client.method('resolvedLanguages')).then(
      translateView);
  }

  requestLanguages(langs, global) {
    return this._interactive.then(
      client => client.method('requestLanguages', langs, global));
  }

  _resolveEntities(langs, keys) {
    return this._interactive.then(
      client => client.method('resolveEntities', client.id, langs, keys));
  }

  formatValue(id, args) {
    return this._interactive.then(
      client => client.method('formatValues', client.id, [[id, args]])).then(
      values => values[0]);
  }

  formatValues(...keys) {
    return this._interactive.then(
      client => client.method('formatValues', client.id, keys));
  }

  translateFragment(frag) {
    return this._interactive.then(
      client => client.method('resolvedLanguages')).then(
      langs => translateFragment(this, langs, frag));
  }
}

View.prototype.setAttributes = setAttributes;
View.prototype.getAttributes = getAttributes;

function createPseudo(view, code) {
  return {
    getName: () => view._interactive.then(
      client => client.method('getName', code)),
    processString: str => view._interactive.then(
      client => client.method('processString', code, str)),
  };
}

function init(view, client) {
  view._observe();
  return client.method(
    'registerView', client.id, getResourceLinks(view._doc.head)).then(
      () => client);
}

function onMutations(mutations) {
  return this.resolvedLanguages().then(
    langs => translateMutations(this, langs, mutations));
}

export function translateDocument(view, langs) {
  const html = view._doc.documentElement;

  if (readiness.has(html)) {
    return translateFragment(view, langs, html).then(
      () => setDOMAttrsAndEmit(html, langs));
  }

  const translated =
    // has the document been already pre-translated?
    langs[0].code === html.getAttribute('lang') ?
      Promise.resolve() :
      translateFragment(view, langs, html).then(
        () => setDOMAttrs(html, langs));

  return translated.then(
    () => readiness.set(html, true));
}

function setDOMAttrsAndEmit(html, langs) {
  setDOMAttrs(html, langs);
  html.parentNode.dispatchEvent(new CustomEvent('DOMRetranslated', {
    bubbles: false,
    cancelable: false,
  }));
}

function setDOMAttrs(html, langs) {
  const codes = langs.map(lang => lang.code);
  html.setAttribute('langs', codes.join(' '));
  html.setAttribute('lang', codes[0]);
  html.setAttribute('dir', getDirection(codes[0]));
}
<commit_msg>Bug 1215123 (hotfix) - Remove resolvedLanguages from onMutations<commit_after>'use strict';

import { documentReady, getDirection } from './shims';
import {
  setAttributes, getAttributes, translateFragment, translateMutations,
  getResourceLinks
} from './dom';

const observerConfig = {
  attributes: true,
  characterData: false,
  childList: true,
  subtree: true,
  attributeFilter: ['data-l10n-id', 'data-l10n-args']
};

const readiness = new WeakMap();

export class View {
  constructor(client, doc) {
    this._doc = doc;
    this.pseudo = {
      'qps-ploc': createPseudo(this, 'qps-ploc'),
      'qps-plocm': createPseudo(this, 'qps-plocm')
    };

    this._interactive = documentReady().then(
      () => init(this, client));

    const observer = new MutationObserver(onMutations.bind(this));
    this._observe = () => observer.observe(doc, observerConfig);
    this._disconnect = () => observer.disconnect();

    const translateView = langs => translateDocument(this, langs);
    client.on('translateDocument', translateView);
    this.ready = this._interactive.then(
      client => client.method('resolvedLanguages')).then(
      translateView);
  }

  requestLanguages(langs, global) {
    return this._interactive.then(
      client => client.method('requestLanguages', langs, global));
  }

  _resolveEntities(langs, keys) {
    return this._interactive.then(
      client => client.method('resolveEntities', client.id, langs, keys));
  }

  formatValue(id, args) {
    return this._interactive.then(
      client => client.method('formatValues', client.id, [[id, args]])).then(
      values => values[0]);
  }

  formatValues(...keys) {
    return this._interactive.then(
      client => client.method('formatValues', client.id, keys));
  }

  translateFragment(frag) {
    return this._interactive.then(
      client => client.method('resolvedLanguages')).then(
      langs => translateFragment(this, langs, frag));
  }
}

View.prototype.setAttributes = setAttributes;
View.prototype.getAttributes = getAttributes;

function createPseudo(view, code) {
  return {
    getName: () => view._interactive.then(
      client => client.method('getName', code)),
    processString: str => view._interactive.then(
      client => client.method('processString', code, str)),
  };
}

function init(view, client) {
  view._observe();
  return client.method(
    'registerView', client.id, getResourceLinks(view._doc.head)).then(
      () => client);
}

function onMutations(mutations) {
  return this._interactive.then(
    client => client.method('resolvedLanguages')).then(
    langs => translateMutations(this, langs, mutations));
}

export function translateDocument(view, langs) {
  const html = view._doc.documentElement;

  if (readiness.has(html)) {
    return translateFragment(view, langs, html).then(
      () => setDOMAttrsAndEmit(html, langs));
  }

  const translated =
    // has the document been already pre-translated?
    langs[0].code === html.getAttribute('lang') ?
      Promise.resolve() :
      translateFragment(view, langs, html).then(
        () => setDOMAttrs(html, langs));

  return translated.then(
    () => readiness.set(html, true));
}

function setDOMAttrsAndEmit(html, langs) {
  setDOMAttrs(html, langs);
  html.parentNode.dispatchEvent(new CustomEvent('DOMRetranslated', {
    bubbles: false,
    cancelable: false,
  }));
}

function setDOMAttrs(html, langs) {
  const codes = langs.map(lang => lang.code);
  html.setAttribute('langs', codes.join(' '));
  html.setAttribute('lang', codes[0]);
  html.setAttribute('dir', getDirection(codes[0]));
}
<|endoftext|>


<commit_before>/**
 * RightJS UI Internationalization: Dutch module
 *
 * Copyright (C) Douwe Maan, Jeffrey Gelens <jeffrey@noppo.pro>
 */
RightJS.Object.each({

  Calendar: {
    Done:           'Klaar',
    Now:            'Nu',
    NextMonth:      'Volgende maand',
    PrevMonth:      'Vorige maand',
    NextYear:       'Volgend jaar',
    PrevYear:       'Vorig jaar',

    dayNames:        'Zondag Maandag Dinsdag Woensdag Donderdag Vrijdag Zaterdag'.split(' '),
    dayNamesShort:   'Zo Ma Di Wo Do Vr Za'.split(' '),
    dayNamesMin:     'Zo Ma Di Wo Do Vr Za'.split(' '),
    monthNames:      'Januari Februari Maart April Mei Juni Juli Augustus September Oktober November December'.split(' '),
    monthNamesShort: 'Jan Feb Maa Apr Mei Juni Juli Aug Sept Okt Nov Dec'.split(' ')
  },

  Lightbox: {
    Close: 'Sluiten',
    Prev:  'Vorige afbeelding',
    Next:  'Volgende afbeelding'
  },

  InEdit: {
    Save:   "Opslaan",
    Cancel: "Annuleren"
  },

  Colorpicker: {
    Done: 'Klaar'
  },

  Dialog: {
    Ok:       'Ok',
    Close:    'Sluiten',
    Cancel:   'Annuleren',
    Help:     'Help',
    Expand:   'Uitklappen',
    Collapse: 'Inklappen',

    Alert:    'Let op!',
    Confirm:  'Bevestigen',
    Prompt:   'Enter'
  },

  Rte: {
    Clear:       'Clear',
    Save:        'Bewaar',
    Source:      'Bron',
    Bold:        'Vetgedrukt',
    Italic:      'Schuingedrukt',
    Underline:   'Onderstreept',
    Strike:      'Doorhalen',
    Ttext:       'Typetekst',
    Header:      'Kop',
    Cut:         'Knippen',
    Copy:        'Kopieren',
    Paste:       'Plakken',
    Left:        'Links uitlijnen',
    Center:      'Centreren',
    Right:       'Rechts uitlijnen',
    Justify:     'Uitlijnen',
    Undo:        'Ongedaan maken',
    Redo:        'Opnieuw',
    Code:        'Code block',
    Quote:       'Blokcitaat',
    Link:        'Link toevoegen',
    Image:       'Plaatje toevoegen',
    Video:       'Video toevoegen',
    Dotlist:     'Lijst met punten',
    Numlist:     'Genummerde lijst',
    Indent:      'Inspringen',
    Outdent:     'Uitspringen',
    Forecolor:   'Tekstkleur',
    Backcolor:   'Achtergrond kleur',
    Select:      'Selecteren',
    Remove:      'Verwijderen',
    Format:      'Formaat',
    Fontname:    'Lettertype',
    Fontsize:    'Lettergrootte',
    Subscript:   'Subscript',
    Superscript: 'Superscript',
    UrlAddress:  'URL'
  }

}, function(module, i18n) {
  if (self[module]) {
    RightJS.$ext(self[module].i18n, i18n);
  }
});
<commit_msg>i18n lowcasing the daynames for the NL translation<commit_after>/**
 * RightJS UI Internationalization: Dutch module
 *
 * Copyright (C) Douwe Maan, Jeffrey Gelens <jeffrey@noppo.pro>
 */
RightJS.Object.each({

  Calendar: {
    Done:           'Klaar',
    Now:            'Nu',
    NextMonth:      'Volgende maand',
    PrevMonth:      'Vorige maand',
    NextYear:       'Volgend jaar',
    PrevYear:       'Vorig jaar',

    dayNames:        'zondag maandag dinsdag woensdag donderdag vrijdag zaterdag'.split(' '),
    dayNamesShort:   'zo ma di wo do vr za'.split(' '),
    dayNamesMin:     'zo ma di wo do vr za'.split(' '),
    monthNames:      'januari februari maart april mei juni juli augustus september oktober november december'.split(' '),
    monthNamesShort: 'jan feb maa apr mei juni juli aug sept okt nov dec'.split(' ')
  },

  Lightbox: {
    Close: 'Sluiten',
    Prev:  'Vorige afbeelding',
    Next:  'Volgende afbeelding'
  },

  InEdit: {
    Save:   "Opslaan",
    Cancel: "Annuleren"
  },

  Colorpicker: {
    Done: 'Klaar'
  },

  Dialog: {
    Ok:       'Ok',
    Close:    'Sluiten',
    Cancel:   'Annuleren',
    Help:     'Help',
    Expand:   'Uitklappen',
    Collapse: 'Inklappen',

    Alert:    'Let op!',
    Confirm:  'Bevestigen',
    Prompt:   'Enter'
  },

  Rte: {
    Clear:       'Clear',
    Save:        'Bewaar',
    Source:      'Bron',
    Bold:        'Vetgedrukt',
    Italic:      'Schuingedrukt',
    Underline:   'Onderstreept',
    Strike:      'Doorhalen',
    Ttext:       'Typetekst',
    Header:      'Kop',
    Cut:         'Knippen',
    Copy:        'Kopieren',
    Paste:       'Plakken',
    Left:        'Links uitlijnen',
    Center:      'Centreren',
    Right:       'Rechts uitlijnen',
    Justify:     'Uitlijnen',
    Undo:        'Ongedaan maken',
    Redo:        'Opnieuw',
    Code:        'Code block',
    Quote:       'Blokcitaat',
    Link:        'Link toevoegen',
    Image:       'Plaatje toevoegen',
    Video:       'Video toevoegen',
    Dotlist:     'Lijst met punten',
    Numlist:     'Genummerde lijst',
    Indent:      'Inspringen',
    Outdent:     'Uitspringen',
    Forecolor:   'Tekstkleur',
    Backcolor:   'Achtergrond kleur',
    Select:      'Selecteren',
    Remove:      'Verwijderen',
    Format:      'Formaat',
    Fontname:    'Lettertype',
    Fontsize:    'Lettergrootte',
    Subscript:   'Subscript',
    Superscript: 'Superscript',
    UrlAddress:  'URL'
  }

}, function(module, i18n) {
  if (self[module]) {
    RightJS.$ext(self[module].i18n, i18n);
  }
});
<|endoftext|>


<commit_before>(function() {
    var bfjs = {};

    bfjs.LateActor = (function() {
        var TheClass = function() {
            this.loaded = false;
            this.deferredTransactions = [];
        };

        TheClass.construct = function() {
            return new TheClass();
        };

        var p = TheClass.prototype;

        p.loadedCallback = function() {
            this.loaded = true;

            for (var i in this.deferredTransactions) {
                var transaction = this.deferredTransactions[i];
                transaction.do();
            }
            this.deferredTransactions = [];
        };

        p.doWhenReady = function(transaction) {
            this.deferredTransactions.push(transaction);
            if (this.loaded) {
                this.loadedCallback();
            }
        };

        return TheClass;
    }());

    bfjs.CoreActor = (function() {
        var TheClass = function() {
            this.hasBfCredentials = false;
            this.gatewayChosen = false;
        };

        TheClass.construct = function() {
            return new TheClass();
        };

        var p = bfjs.LateActor.prototype;
        p.constructor = TheClass;

        return TheClass;
    }());

    bfjs.GatewayActor = (function() {
        var TheClass = function() {
            this.loaded = false;
            this.loadMe = false;
        };

        TheClass.construct = function() {
            return new TheClass();
        };

        var p = bfjs.LateActor.prototype;
        p.constructor = TheClass;

        return TheClass;
    }());

    bfjs.StripeGateway = (function() {
        var TheClass = function() {
            this.key = 'stripe';
        };

        TheClass.construct = function() {
            return new TheClass();
        };

        var p = bfjs.GatewayActor.prototype;
        p.constructor = TheClass;

        return TheClass;
    }());

    bfjs.BraintreeGateway = (function() {
        var TheClass = function() {
            this.key = 'stripe';
        };

        TheClass.construct = function() {
            return new TheClass();
        };

        var p = bfjs.GatewayActor.prototype;
        p.constructor = TheClass;

        return TheClass;
    }());

    // core is mainly to check if jquery is loaded
    bfjs.core = bfjs.CoreActor.construct();

    bfjs.stripe = bfjs.StripeGateway.construct();

    bfjs.braintree = bfjs.BraintreeGateway.construct();

    bfjs.state = {
        api: {
            url: null,
            token: null,
            organizationID: null
        }
    };

    bfjs.grabScripts = function() {
        var queue = [];
        if (typeof jQuery !== 'undefined') {
            bfjs.core.loadedCallback();
        } else {
            // everyone has this in their cache anyway, so..
            queue.push({
                src: "//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js",
                callback: bfjs.core.loadedCallback
            });
        }
        if (bfjs.stripe.loadMe) {
            if (typeof window.Stripe !== 'undefined') {
                queue.push({
                    src: "https://js.stripe.com/v2/",
                    callback: bfjs.stripe.loadedCallback
                });
            } else {
                bfjs.stripe.loadedCallback();
            }
        }
        if (bfjs.braintree.loadMe) {
            if (typeof window.braintree !== 'undefined') {
                queue.push({
                    src: "https://assets.braintreegateway.com/v2/braintree.js",
                    callback: bfjs.braintree.loadedCallback
                });
            } else {
                bfjs.braintree.loadedCallback();
            }
        }

        for (var i = 0; i<queue.length; i++) {
            bfjs.loadScript(queue[i].src, queue[i].callback);
        }
    };

    bfjs.Transaction = (function() {
        var TheClass = function(bfjs, formElementCandidate, accountID, callback, targetGateway) {
            this.formElementCandidate = formElementCandidate;
            this.callback = callback;
            this.accountID = accountID;
            this.targetGateway = targetGateway;
            this.bfjs = bfjs;
            this.state = {
                formElement:  null;
                $formElement: null;
            };
        };

        TheClass.construct = function(bfjs, formElementCandidate, accountID, callback, targetGateway) {
            return new TheClass(bfjs, formElementCandidate, accountID, callback, targetGateway);
        };

        var p = TheClass.prototype;

        p.do = function() {
            $( document ).ready(function() {
                var $formElement = $(this.formElementCandidate);
                var formElement = $formElement.get(0);

                if (!(formElement instanceof HTMLElement)) {
                    throw "Expected jQuery object or HTML element. Perhaps the Form hasn't finished loading?";
                }

                this.state.formElement = formElement;
                this.state.$formElement = $formElement;

                $formElement.submit(function(e) {
                    // Disable the submit button to prevent repeated clicks
                    $(this).find('button').prop('disabled', true);

                    e.preventDefault();
                    e.stopPropagation();
                    this.bfjs[this.chosenGateway].deferRequest();
                });

                // ready to go
                $formElement.find('button').prop('disabled', false);
            });
        };

        return TheClass;
    }());

    bfjs.loadScript = function(url, callback){

        var script = document.createElement("script")
        script.type = "text/javascript";

        var doCallback = function() {
            callback();
        };

        if (script.readyState){  //IE
            script.onreadystatechange = function(){
                if (script.readyState == "loaded" ||
                        script.readyState == "complete"){
                    script.onreadystatechange = null;
                    doCallback();
                }
            };
        } else {  //Others
            script.onload = function(){
                doCallback();
            };
        }

        script.src = url;
        document.getElementsByTagName("head")[0].appendChild(script);
    };

    bfjs.stripe.do = function(state) {
    	var payload = {
    		"gateway": "Stripe"
    	}

    	if(bfjs.state.api.organizationID != null) {
        	payload.organizationID = bfjs.state.api.organizationID;
        }

        bfjs.doPreAuth(payload, bfjs.stripe.key);
    };

    bfjs.braintree.do = function(state) {
        var payload = {
            "gateway": "Braintree"
        }

        if(bfjs.state.api.organizationID != null) {
            payload.organizationID = bfjs.state.api.organizationID;
        }

        bfjs.doPreAuth(payload, bfjs.braintree.key);
    };

    bfjs.stripe.responseHandler = function(status, response) {
        if (response.error) {
            // Show the errors on the form
            bfjs.ultimateFailure(response.error.message);
        } else {
            // token contains id, last4, and card type
            var token = response.id;
            var card = response.card;

            var payload = {
                stripeToken: token,
                cardID: card.id,
                accountID: bfjs.state.accountID
            };

            if(bfjs.state.api.organizationID != null) {
            	payload.organizationID = bfjs.state.api.organizationID;
            }

            // and re-submit
            bfjs.doAuthCapture(payload, bfjs.stripe.key);
        }
    };

    bfjs.doPreAuth = function(payload, gateway) {
        var controller = "tokenization/"
        var endpoint = "pre-auth";
        var fullURL = bfjs.state.api.url + controller + endpoint;
        var auth = bfjs.state.api.token;

        $.support.cors = true;

        $.ajax({
                type: "POST",
                url: fullURL,
                data: JSON.stringify(payload),
                contentType: 'application/json',
                //dataType: 'jsonp',
                //jsonp: function(data){console.log(data);},
                crossDomain: true,
                xhrFields: {
                    //withCredentials: true
                },
                headers: {
                    'Authorization': 'Bearer '+auth,
                    //'Access-Control-Allow-Origin': "*",
                    //'Access-Control-Request-Headers': 'Authorization Access-Control-Allow-Origin'
                },
                /*beforeSend: function (xhr) {
                    xhr.setRequestHeader ("Authorization", 'Bearer '+auth);
                    xhr.setRequestHeader("Access-Control-Allow-Origin", "*");
                    xhr.withCredentials = true;
                },*/
            })
        .success(function(data) {
            bfjs.preAuthSuccessHandler(data, bfjs.stripe.key);
        })
        .fail(bfjs.preAuthFailHandler);
    };

    bfjs.doAuthCapture = function(payload, gateway) {
        var controller = "tokenization/"
        var endpoint = "auth-capture";
        var fullURL = bfjs.state.api.url + controller + endpoint;
        var auth = bfjs.state.api.token;

        $.ajax({
                type: "POST",
                url: fullURL,
                data: JSON.stringify(payload),
                contentType: 'application/json',
                //dataType: 'jsonp',
                //jsonp: function(data){console.log(data);},
                crossDomain: true,
                xhrFields: {
                    //withCredentials: true
                },
                headers: {
                    'Authorization': 'Bearer '+auth,
                    //'Access-Control-Allow-Origin': "*",
                    //'Access-Control-Request-Headers': 'Authorization Access-Control-Allow-Origin'
                },
                /*beforeSend: function (xhr) {
                    xhr.setRequestHeader ("Authorization", 'Bearer '+auth);
                    xhr.setRequestHeader("Access-Control-Allow-Origin", "*");
                    xhr.withCredentials = true;
                },*/
            })
        .success(function(data) {
            bfjs.authCaptureSuccessHandler(data, bfjs.stripe.key);
        })
        .fail(bfjs.authCaptureFailHandler);
    };

    bfjs.ultimateSuccess = function(paymentMethod) {
        //console.log(paymentMethod);
        bfjs.state.callback(paymentMethod, false);
    };

    bfjs.ultimateFailure = function(reason) {
        console.error(reason);
        bfjs.state.callback(null, reason);
    };

    bfjs.core.getFormValue = function(key) {
        var $formElement = bfjs.state.$formElement;

        return $formElement.find("input[bf-data='"+key+"'], select[bf-data='"+key+"']").val();
    };

    bfjs.stripe.oncePreauthed = function(data) {
        if (!data.results) {
            bfjs.ultimateFailure("Preauthorization failed. Response received, but with no prauth information in it.");
        }
        // This identifies your website in the createToken call below
        var stripePublishableKey = data.results[0].publicKey;
        Stripe.setPublishableKey(stripePublishableKey);

        var mappings = {
            'cardholder-name': 'name',
            'cvc': 'cvc',
            'number': 'number',
            'exp-month': 'exp_month',
            'exp-year': 'exp_year',
            'address-line1': 'address_line1',
            'address-line2': 'address_line2',
            'address-city': 'address_city',
            'address-state': 'address_state',
            'address-zip': 'address_zip',
            'address-country': 'address_country',
        };

        var tokenInfo = {};

        for (var i in mappings) {
            var mapping = mappings[i];
            var valueFromForm = bfjs.core.getFormValue(i);
            if (valueFromForm) {
                tokenInfo[mappings[i]] = valueFromForm;
            }
        }

        Stripe.card.createToken(tokenInfo, bfjs.stripe.responseHandler);
    };

    bfjs.preAuthSuccessHandler = function(data, gateway) {
        //console.log(data);
        try {
            bfjs[gateway].oncePreauthed(data);
        } catch(e) {
            bfjs.ultimateFailure("Preauthorization failed. "+e.message);
        }
    };

    bfjs.preAuthFailHandler = function(reason) {
        // maybe should only go to ultimate failure if ALL gateways fail to tokenize
        bfjs.ultimateFailure(reason);
    };

    bfjs.authCaptureSuccessHandler = function(data, gateway) {
        //console.log(data);
        try {
            var paymentMethod = data.results[0];
            bfjs.ultimateSuccess(paymentMethod);
        } catch(e) {
            bfjs.ultimateFailure("Authorized capture failed. "+e.message);
        }
    };

    bfjs.authCaptureFailHandler = function(reason) {
        // maybe should only go to ultimate failure if ALL gateways fail to tokenize
        bfjs.ultimateFailure(reason);
    };

    bfjs.captureCardOnSubmit = function(formElementSelector, accountID, callback, targetGateway) {
        if (bfjs.core.hasBfCredentials) {
            if (bfjs.core.gatewayChosen){
                var newTransaction = bfjs.Transaction.construct(bfjs, formElementSelector, accountID, callback, targetGateway);
                bfjs.core.doWhenReady(newTransaction);
            } else {
                throw "You need to first call bfjs.loadGateways() with a list of gateways you are likely to use (ie ['stripe', 'braintree'])";
            }
        } else {
            throw "You need to first call bfjs.useAPI() will BillForward credentials";
        }
    };

    bfjs.useAPI = function(url, token, organizationID) {
        bfjs.state.api.url = url;
        bfjs.state.api.token = token;
        bfjs.state.api.organizationID = organizationID;
        bfjs.core.hasBfCredentials = true;
    };

    bfjs.loadGateways = function(gateways) {
        for(var g in gateways) {
            var gateway = gateways[g];
            switch(gateway.toLowerCase()) {
                case 'stripe':
                case 'braintree':
                    bfjs[gateway.toLowerCase()].loadMe = true;
                    bfjs.core.gatewayChosen = true;
                    break;
                default:
                    throw "'"+gateway+"' is not the name of any supported gateway."
            }
        }

        if (bfjs.core.gatewayChosen){
            bfjs.grabScripts();
        }
    };

    window.BillForward = window.BillForward || bfjs;
}());<commit_msg>Bit less broken inheritance<commit_after>(function() {
    var bfjs = {};

    bfjs.LateActor = (function() {
        var TheClass = function() {
            this.loaded = false;
            this.deferredTransactions = [];
        };

        TheClass.construct = function() {
            return new this();
        };

        var p = TheClass.prototype;

        p.loadedCallback = function() {
            this.loaded = true;

            for (var i in this.deferredTransactions) {
                var transaction = this.deferredTransactions[i];
                transaction.do();
            }
            this.deferredTransactions = [];
        };

        p.doWhenReady = function(transaction) {
            this.deferredTransactions.push(transaction);
            if (this.loaded) {
                this.loadedCallback();
            }
        };

        return TheClass;
    }());

    bfjs.CoreActor = (function() {
        var TheClass = function() {
            this.hasBfCredentials = false;
            this.gatewayChosen = false;
            this.loadMe = true;

            // statics
            this.depUrl = "//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js";
            this.depName = "jQuery";
        };

        TheClass.construct = function() {
            return new this();
        };

        var p = TheClass.prototype = new bfjs.LateActor();
        p.constructor = TheClass;

        return TheClass;
    }());

    bfjs.GatewayActor = (function() {
        var TheClass = function() {
            this.loaded = false;
            this.loadMe = false;
        };

        TheClass.construct = function() {
            return new this();
        };

        var p = TheClass.prototype = new bfjs.LateActor();
        p.constructor = TheClass;

        return TheClass;
    }());

    bfjs.StripeGateway = (function() {
        var TheClass = function() {
            // statics
            this.key = 'stripe';
            this.depUrl = "https://js.stripe.com/v2/";
            this.depName = "Stripe";
        };

        TheClass.construct = function() {
            return new this();
        };

        var p = TheClass.prototype = new bfjs.GatewayActor();

        p.constructor = TheClass;

        return TheClass;
    }());

    bfjs.BraintreeGateway = (function() {
        var TheClass = function() {
            // statics
            this.key = 'braintree';
            this.depUrl = "https://assets.braintreegateway.com/v2/braintree.js";
            this.depName = "braintree";
        };

        TheClass.construct = function() {
            return new this();
        };

        var p = TheClass.prototype = new bfjs.GatewayActor();
        p.constructor = TheClass;

        return TheClass;
    }());

    // core is mainly to check if jquery is loaded
    bfjs.core = bfjs.CoreActor.construct();

    bfjs.stripe = bfjs.StripeGateway.construct();

    bfjs.braintree = bfjs.BraintreeGateway.construct();

    bfjs.lateActors = [
        bfjs.core,
        bfjs.stripe,
        bfjs.braintree
    ];

    bfjs.state = {
        api: {
            url: null,
            token: null,
            organizationID: null
        }
    };

    bfjs.grabScripts = function() {
        var queue = [];
        for (var i in bfjs.lateActors) {
            var actor = bfjs.lateActors[i];
            console.log(actor);

            if (typeof window[actor.depName] !== 'undefined') {
                actor.loadedCallback();
            } else {
                queue.push({
                    src: actor.depUrl,
                    callback: actor.loadedCallback
                });
            }
        }

        for (var i = 0; i<queue.length; i++) {
            bfjs.loadScript(queue[i].src, queue[i].callback);
        }
    };

    bfjs.Transaction = (function() {
        var TheClass = function(bfjs, formElementCandidate, accountID, callback, targetGateway) {
            this.formElementCandidate = formElementCandidate;
            this.callback = callback;
            this.accountID = accountID;
            this.targetGateway = targetGateway;
            this.bfjs = bfjs;
            this.state = {
                formElement:  null,
                $formElement: null
            };
        };

        TheClass.construct = function(bfjs, formElementCandidate, accountID, callback, targetGateway) {
            return new TheClass(bfjs, formElementCandidate, accountID, callback, targetGateway);
        };

        var p = TheClass.prototype;

        p.do = function() {
            $( document ).ready(function() {
                var $formElement = $(this.formElementCandidate);
                var formElement = $formElement.get(0);

                if (!(formElement instanceof HTMLElement)) {
                    throw "Expected jQuery object or HTML element. Perhaps the Form hasn't finished loading?";
                }

                this.state.formElement = formElement;
                this.state.$formElement = $formElement;

                $formElement.submit(function(e) {
                    // Disable the submit button to prevent repeated clicks
                    $(this).find('button').prop('disabled', true);

                    e.preventDefault();
                    e.stopPropagation();
                    this.bfjs[this.chosenGateway].deferRequest();
                });

                // ready to go
                $formElement.find('button').prop('disabled', false);
            });
        };

        return TheClass;
    }());

    bfjs.loadScript = function(url, callback){

        var script = document.createElement("script")
        script.type = "text/javascript";

        var doCallback = function() {
            callback();
        };

        if (script.readyState){  //IE
            script.onreadystatechange = function(){
                if (script.readyState == "loaded" ||
                        script.readyState == "complete"){
                    script.onreadystatechange = null;
                    doCallback();
                }
            };
        } else {  //Others
            script.onload = function(){
                doCallback();
            };
        }

        script.src = url;
        document.getElementsByTagName("head")[0].appendChild(script);
    };

    bfjs.stripe.do = function(state) {
    	var payload = {
    		"gateway": "Stripe"
    	}

    	if(bfjs.state.api.organizationID != null) {
        	payload.organizationID = bfjs.state.api.organizationID;
        }

        bfjs.doPreAuth(payload, bfjs.stripe.key);
    };

    bfjs.braintree.do = function(state) {
        var payload = {
            "gateway": "Braintree"
        }

        if(bfjs.state.api.organizationID != null) {
            payload.organizationID = bfjs.state.api.organizationID;
        }

        bfjs.doPreAuth(payload, bfjs.braintree.key);
    };

    bfjs.stripe.responseHandler = function(status, response) {
        if (response.error) {
            // Show the errors on the form
            bfjs.ultimateFailure(response.error.message);
        } else {
            // token contains id, last4, and card type
            var token = response.id;
            var card = response.card;

            var payload = {
                stripeToken: token,
                cardID: card.id,
                accountID: bfjs.state.accountID
            };

            if(bfjs.state.api.organizationID != null) {
            	payload.organizationID = bfjs.state.api.organizationID;
            }

            // and re-submit
            bfjs.doAuthCapture(payload, bfjs.stripe.key);
        }
    };

    bfjs.doPreAuth = function(payload, gateway) {
        var controller = "tokenization/"
        var endpoint = "pre-auth";
        var fullURL = bfjs.state.api.url + controller + endpoint;
        var auth = bfjs.state.api.token;

        $.support.cors = true;

        $.ajax({
                type: "POST",
                url: fullURL,
                data: JSON.stringify(payload),
                contentType: 'application/json',
                //dataType: 'jsonp',
                //jsonp: function(data){console.log(data);},
                crossDomain: true,
                xhrFields: {
                    //withCredentials: true
                },
                headers: {
                    'Authorization': 'Bearer '+auth,
                    //'Access-Control-Allow-Origin': "*",
                    //'Access-Control-Request-Headers': 'Authorization Access-Control-Allow-Origin'
                },
                /*beforeSend: function (xhr) {
                    xhr.setRequestHeader ("Authorization", 'Bearer '+auth);
                    xhr.setRequestHeader("Access-Control-Allow-Origin", "*");
                    xhr.withCredentials = true;
                },*/
            })
        .success(function(data) {
            bfjs.preAuthSuccessHandler(data, bfjs.stripe.key);
        })
        .fail(bfjs.preAuthFailHandler);
    };

    bfjs.doAuthCapture = function(payload, gateway) {
        var controller = "tokenization/"
        var endpoint = "auth-capture";
        var fullURL = bfjs.state.api.url + controller + endpoint;
        var auth = bfjs.state.api.token;

        $.ajax({
                type: "POST",
                url: fullURL,
                data: JSON.stringify(payload),
                contentType: 'application/json',
                //dataType: 'jsonp',
                //jsonp: function(data){console.log(data);},
                crossDomain: true,
                xhrFields: {
                    //withCredentials: true
                },
                headers: {
                    'Authorization': 'Bearer '+auth,
                    //'Access-Control-Allow-Origin': "*",
                    //'Access-Control-Request-Headers': 'Authorization Access-Control-Allow-Origin'
                },
                /*beforeSend: function (xhr) {
                    xhr.setRequestHeader ("Authorization", 'Bearer '+auth);
                    xhr.setRequestHeader("Access-Control-Allow-Origin", "*");
                    xhr.withCredentials = true;
                },*/
            })
        .success(function(data) {
            bfjs.authCaptureSuccessHandler(data, bfjs.stripe.key);
        })
        .fail(bfjs.authCaptureFailHandler);
    };

    bfjs.ultimateSuccess = function(paymentMethod) {
        //console.log(paymentMethod);
        bfjs.state.callback(paymentMethod, false);
    };

    bfjs.ultimateFailure = function(reason) {
        console.error(reason);
        bfjs.state.callback(null, reason);
    };

    bfjs.core.getFormValue = function(key) {
        var $formElement = bfjs.state.$formElement;

        return $formElement.find("input[bf-data='"+key+"'], select[bf-data='"+key+"']").val();
    };

    bfjs.stripe.oncePreauthed = function(data) {
        if (!data.results) {
            bfjs.ultimateFailure("Preauthorization failed. Response received, but with no prauth information in it.");
        }
        // This identifies your website in the createToken call below
        var stripePublishableKey = data.results[0].publicKey;
        Stripe.setPublishableKey(stripePublishableKey);

        var mappings = {
            'cardholder-name': 'name',
            'cvc': 'cvc',
            'number': 'number',
            'exp-month': 'exp_month',
            'exp-year': 'exp_year',
            'address-line1': 'address_line1',
            'address-line2': 'address_line2',
            'address-city': 'address_city',
            'address-state': 'address_state',
            'address-zip': 'address_zip',
            'address-country': 'address_country',
        };

        var tokenInfo = {};

        for (var i in mappings) {
            var mapping = mappings[i];
            var valueFromForm = bfjs.core.getFormValue(i);
            if (valueFromForm) {
                tokenInfo[mappings[i]] = valueFromForm;
            }
        }

        Stripe.card.createToken(tokenInfo, bfjs.stripe.responseHandler);
    };

    bfjs.preAuthSuccessHandler = function(data, gateway) {
        //console.log(data);
        try {
            bfjs[gateway].oncePreauthed(data);
        } catch(e) {
            bfjs.ultimateFailure("Preauthorization failed. "+e.message);
        }
    };

    bfjs.preAuthFailHandler = function(reason) {
        // maybe should only go to ultimate failure if ALL gateways fail to tokenize
        bfjs.ultimateFailure(reason);
    };

    bfjs.authCaptureSuccessHandler = function(data, gateway) {
        //console.log(data);
        try {
            var paymentMethod = data.results[0];
            bfjs.ultimateSuccess(paymentMethod);
        } catch(e) {
            bfjs.ultimateFailure("Authorized capture failed. "+e.message);
        }
    };

    bfjs.authCaptureFailHandler = function(reason) {
        // maybe should only go to ultimate failure if ALL gateways fail to tokenize
        bfjs.ultimateFailure(reason);
    };

    bfjs.captureCardOnSubmit = function(formElementSelector, accountID, callback, targetGateway) {
        if (bfjs.core.hasBfCredentials) {
            if (bfjs.core.gatewayChosen){
                var newTransaction = bfjs.Transaction.construct(bfjs, formElementSelector, accountID, callback, targetGateway);
                bfjs.core.doWhenReady(newTransaction);
            } else {
                throw "You need to first call bfjs.loadGateways() with a list of gateways you are likely to use (ie ['stripe', 'braintree'])";
            }
        } else {
            throw "You need to first call bfjs.useAPI() will BillForward credentials";
        }
    };

    bfjs.useAPI = function(url, token, organizationID) {
        bfjs.state.api.url = url;
        bfjs.state.api.token = token;
        bfjs.state.api.organizationID = organizationID;
        bfjs.core.hasBfCredentials = true;
    };

    bfjs.loadGateways = function(gateways) {
        for(var g in gateways) {
            var gateway = gateways[g];
            switch(gateway.toLowerCase()) {
                case 'stripe':
                case 'braintree':
                    bfjs[gateway.toLowerCase()].loadMe = true;
                    bfjs.core.gatewayChosen = true;
                    break;
                default:
                    throw "'"+gateway+"' is not the name of any supported gateway."
            }
        }

        if (bfjs.core.gatewayChosen){
            bfjs.grabScripts();
        }
    };

    window.BillForward = window.BillForward || bfjs;
}());<|endoftext|>


<commit_before>import Ember from 'ember';

export default Ember.Mixin.create({
  importActions(path){
    let actionPath = '';

    if(path){
      actionPath = path;
    }else{
      const config = this.container.lookupFactory('config:environment');
      actionPath = config.podModulePrefix?
        `${config.podModulePrefix}/${this.routeName}/actions` :
        `${applicationConfig.modulePrefix}/actions/${this.routeName}`;
    }

    const actions = System.import(actionPath);
    actions.then(res=>{
        let binded = {};
        for(let i in res){
            if(res.hasOwnProperty(i) && typeof res[i] === 'function'){
                res[i].bind(this)
                binded[i] = res[i].bind(this);
            }
        }
        // Set the actions hash as an object inside the route
        // Need to pass the actions hash in the model.
        this.set('actions',binded);
    });
  }
});
<commit_msg>fix(manual): Fixes default actions path for non-pod structure<commit_after>import Ember from 'ember';

export default Ember.Mixin.create({
  importActions(path){
    let actionPath = '';

    if(path){
      actionPath = path;
    }else{
      const config = this.container.lookupFactory('config:environment');
      actionPath = config.podModulePrefix?
        `${config.podModulePrefix}/${this.routeName}/actions` :
        `${config.modulePrefix}/actions/${this.routeName}`;
    }

    const actions = System.import(actionPath);
    actions.then(res=>{
        let binded = {};
        for(let i in res){
            if(res.hasOwnProperty(i) && typeof res[i] === 'function'){
                res[i].bind(this)
                binded[i] = res[i].bind(this);
            }
        }
        // Set the actions hash as an object inside the route
        // Need to pass the actions hash in the model.
        this.set('actions',binded);
    });
  }
});
<|endoftext|>


<commit_before>import Ember from "ember";

const keys = Object.keys;
const copy = Ember.copy;
const get = Ember.get;
const set = Ember.set;

const computed = Ember.computed;

const generateGuid = Ember.generateGuid;

const w = Ember.String.w;

const bind = Ember.run.bind;
const next = Ember.run.next;

const isSimpleClick = Ember.ViewUtils.isSimpleClick;
const $ = Ember.$;

function guard (fn) {
  return function (evt) {
    if (get(this, 'component.disabled')) { return; }
    fn.call(this, evt);
  };
}

function getElementForTarget(target) {
  if (typeof target === 'string') {
    return document.getElementById(target);
  } else if (get(target, 'element')) {
    return get(target, 'element');
  } else {
    return target;
  }
}

function getLabelSelector($element) {
  var id = $element.attr('id');
  if (id) {
    return `label[for="${id}"]`;
  }
}

function getNearestComponentForElement(registry, element) {
  var $target = $(element);
  if (!$target.hasClass('ember-view')) {
    $target = $target.parents('ember-view');
  }
  return registry[$target.attr('id')];
}

function labelForEvent(evt) {
  var $target = $(evt.target);
  if ($target[0].tagName.toLowerCase() === 'label') {
    return $target;
  } else {
    return $target.parents('label');
  }
}

function isLabelClicked(target, label) {
  if (label == null) {
    return false;
  }
  return $(label).attr('for') === $(target).attr('id');
}

const VALID_ACTIVATORS = ["focus", "hover", "click", "hold"];
function parseActivators(value) {
  if (value) {
    var activators = value;
    if (typeof value === "string") {
      activators = Ember.A(w(value));
    }
    Ember.assert(
      `${value} are not valid activators.
        Valid events are ${VALID_ACTIVATORS.join(', ')}`,
      Ember.A(copy(activators)).removeObjects(VALID_ACTIVATORS).length === 0
    );
    return activators;
  }

  Ember.assert(
    `You must provide an event name to the {{pop-over}}.
      Valid events are ${VALID_ACTIVATORS.join(', ')}`,
    false
  );
}

function poll(target, scope, fn) {
  if (getElementForTarget(target)) {
    scope[fn]();
  } else {
    next(null, poll, target, scope, fn);
  }
}

var Target = Ember.Object.extend(Ember.Evented, {

  init: function () {
    var target = get(this, 'target');
    Ember.assert("You cannot make the {{pop-over}} a target of itself.", get(this, 'component') !== target);

    this.eventManager = {
      focusin:    bind(this, 'focus'),
      focusout:   bind(this, 'blur'),
      mouseenter: bind(this, 'mouseEnter'),
      mouseleave: bind(this, 'mouseLeave'),
      mousedown:  bind(this, 'mouseDown')
    };

    if (get(target, 'element')) {
      this.attach();
    } else if (target.one) {
      target.one('didInsertElement', this, 'attach');
    } else if (typeof target === 'string') {
      poll(target, this, 'attach');
    }
  },

  attach: function () {
    var element = getElementForTarget(this.target);
    var $element = $(element);
    var $document = $(document);

    // Already attached or awaiting an element to exist
    if (get(this, 'attached') || element == null) { return; }

    set(this, 'attached', true);
    set(this, 'element', element);

    var id = $element.attr('id');
    if (id == null) {
      id = generateGuid();
      $element.attr('id', id);
    }

    var eventManager = this.eventManager;

    keys(eventManager).forEach(function (event) {
      $document.on(event, `#${id}`, eventManager[event]);
    });

    var selector = getLabelSelector($element);
    if (selector) {
      keys(eventManager).forEach(function (event) {
        $document.on(event, selector, eventManager[event]);
      });
    }
  },

  detach: function () {
    var element = this.element;
    var $element = $(element);
    var $document = $(document);

    var eventManager = this.eventManager;

    var id = $element.attr('id');
    keys(eventManager).forEach(function (event) {
      $document.off(event, '#' + id, eventManager[event]);
    });

    var selector = getLabelSelector($element);
    if (selector) {
      keys(eventManager).forEach(function (event) {
        $document.off(event, selector, eventManager[event]);
      });
    }

    // Remove references for GC
    this.eventManager = null;
    set(this, 'element', null);
    set(this, 'target', null);
    set(this, 'component', null);
  },

  on: computed({
    set(key, value) {
      return parseActivators(value);
    }
  }),

  isClicked: function (evt) {
    if (isSimpleClick(evt)) {
      var label = labelForEvent(evt);
      var element = this.element;
      return evt.target === element || $.contains(element, evt.target) ||
        isLabelClicked(element, label);
    }
    return false;
  },

  active: computed('focused', 'hovered', 'pressed', 'component.hovered', 'component.pressed', {
    set(key, value) {
      var activators = get(this, 'on');
      if (value) {
        if (activators.contains('focus')) {
          set(this, 'focused', true);
        } else if (activators.contains('hover')) {
          set(this, 'hovered', true);
        } else if (activators.contains('click')) {
          set(this, 'pressed', true);
        }
      } else {
        set(this, 'focused', false);
        set(this, 'hovered', false);
        set(this, 'pressed', false);
      }
      return value;
    },

    get() {
      var activators = get(this, 'on');
      var active = false;

      if (activators.contains('focus')) {
        active = active || get(this, 'focused');
        if (activators.contains('hold')) {
          active = active || get(this, 'component.pressed');
        }
      }

      if (activators.contains('hover')) {
        active = active || get(this, 'hovered');
        if (activators.contains('hold')) {
          active = active || get(this, 'component.hovered');
        }
      }

      if (activators.contains('click') || activators.contains('hold')) {
        active = active || get(this, 'pressed');
      }

      return !!active;
    }
  }),

  focus: guard(function () {
    set(this, 'focused', true);
  }),

  blur: guard(function () {
    set(this, 'focused', false);
  }),

  mouseEnter: guard(function () {
    set(this, 'hovered', true);
  }),

  mouseLeave: guard(function () {
    set(this, 'hovered', false);
  }),

  mouseDown: guard(function (evt) {
    if (!this.isClicked(evt)) {
      return false;
    }

    var element = this.element;
    var active = !get(this, 'active');
    set(this, 'pressed', active);

    if (active) {
      this.holdStart = new Date().getTime();

      var eventManager = this.eventManager;
      eventManager.mouseup = bind(this, 'mouseUp');
      $(document).on('mouseup', eventManager.mouseup);

      evt.preventDefault();
    }

    $(element).focus();
    return true;
  }),

  mouseUp: function (evt) {
    // Remove mouseup event
    var eventManager = this.eventManager;
    $(document).off('mouseup', eventManager.mouseup);
    eventManager.mouseup = null;

    var label = labelForEvent(evt);

    // Treat clicks on <label> elements as triggers to
    // open the menu
    if (isLabelClicked(this.element, label)) {
      return true;
    }

    var view = getNearestComponentForElement(this._viewRegistry, evt.target);
    var activators = get(this, 'on');

    // Manually trigger a click on internal elements
    if (view && view.nearestOfType(get(this, 'component').constructor)) {
      view.trigger('click');

    } else if (activators.contains('click') && activators.contains('hold')) {
      // If the user waits more than 400ms between mouseDown and mouseUp,
      // we can assume that they are clicking and dragging to the menu item,
      // and we should close the menu if they mouseup anywhere not inside
      // the menu.
      if (new Date().getTime() - this.holdStart > 400) {
        set(this, 'pressed', false);
      }
    }
    return true;
  }

});

export default Target;
<commit_msg>pause before deactivating the "hover" activator to allow for spaces between the target and pop over<commit_after>import Ember from "ember";

const keys = Object.keys;
const copy = Ember.copy;
const get = Ember.get;
const set = Ember.set;

const computed = Ember.computed;

const generateGuid = Ember.generateGuid;

const w = Ember.String.w;

const bind = Ember.run.bind;
const next = Ember.run.next;

const isSimpleClick = Ember.ViewUtils.isSimpleClick;
const $ = Ember.$;

function guard (fn) {
  return function (evt) {
    if (get(this, 'component.disabled')) { return; }
    fn.call(this, evt);
  };
}

function getElementForTarget(target) {
  if (typeof target === 'string') {
    return document.getElementById(target);
  } else if (get(target, 'element')) {
    return get(target, 'element');
  } else {
    return target;
  }
}

function getLabelSelector($element) {
  var id = $element.attr('id');
  if (id) {
    return `label[for="${id}"]`;
  }
}

function labelForEvent(evt) {
  var $target = $(evt.target);
  if ($target[0].tagName.toLowerCase() === 'label') {
    return $target;
  } else {
    return $target.parents('label');
  }
}

function isLabelClicked(target, label) {
  if (label == null) {
    return false;
  }
  return $(label).attr('for') === $(target).attr('id');
}

const VALID_ACTIVATORS = ["focus", "hover", "click", "hold"];
function parseActivators(value) {
  if (value) {
    var activators = value;
    if (typeof value === "string") {
      activators = Ember.A(w(value));
    }
    Ember.assert(
      `${value} are not valid activators.
        Valid events are ${VALID_ACTIVATORS.join(', ')}`,
      Ember.A(copy(activators)).removeObjects(VALID_ACTIVATORS).length === 0
    );
    return activators;
  }

  Ember.assert(
    `You must provide an event name to the {{pop-over}}.
      Valid events are ${VALID_ACTIVATORS.join(', ')}`,
    false
  );
}

function poll(target, scope, fn) {
  if (getElementForTarget(target)) {
    scope[fn]();
  } else {
    next(null, poll, target, scope, fn);
  }
}

var Target = Ember.Object.extend(Ember.Evented, {

  init: function () {
    var target = get(this, 'target');
    Ember.assert("You cannot make the {{pop-over}} a target of itself.", get(this, 'component') !== target);

    this.eventManager = {
      focusin:    bind(this, 'focus'),
      focusout:   bind(this, 'blur'),
      mouseenter: bind(this, 'mouseEnter'),
      mouseleave: bind(this, 'mouseLeave'),
      mousedown:  bind(this, 'mouseDown')
    };

    if (get(target, 'element')) {
      this.attach();
    } else if (target.one) {
      target.one('didInsertElement', this, 'attach');
    } else if (typeof target === 'string') {
      poll(target, this, 'attach');
    }
  },

  attach: function () {
    var element = getElementForTarget(this.target);
    var $element = $(element);
    var $document = $(document);

    // Already attached or awaiting an element to exist
    if (get(this, 'attached') || element == null) { return; }

    set(this, 'attached', true);
    set(this, 'element', element);

    var id = $element.attr('id');
    if (id == null) {
      id = generateGuid();
      $element.attr('id', id);
    }

    var eventManager = this.eventManager;

    keys(eventManager).forEach(function (event) {
      $document.on(event, `#${id}`, eventManager[event]);
    });

    var selector = getLabelSelector($element);
    if (selector) {
      keys(eventManager).forEach(function (event) {
        $document.on(event, selector, eventManager[event]);
      });
    }
  },

  detach: function () {
    var element = this.element;
    var $element = $(element);
    var $document = $(document);

    var eventManager = this.eventManager;

    var id = $element.attr('id');
    keys(eventManager).forEach(function (event) {
      $document.off(event, '#' + id, eventManager[event]);
    });

    var selector = getLabelSelector($element);
    if (selector) {
      keys(eventManager).forEach(function (event) {
        $document.off(event, selector, eventManager[event]);
      });
    }

    // Remove references for GC
    this.eventManager = null;
    set(this, 'element', null);
    set(this, 'target', null);
    set(this, 'component', null);
  },

  on: computed({
    set(key, value) {
      return parseActivators(value);
    }
  }),

  isClicked: function (evt) {
    if (isSimpleClick(evt)) {
      var label = labelForEvent(evt);
      var element = this.element;
      return evt.target === element || $.contains(element, evt.target) ||
        isLabelClicked(element, label);
    }
    return false;
  },

  active: computed('focused', 'hovered', 'pressed', 'component.hovered', 'component.pressed', {
    set(key, value) {
      var activators = get(this, 'on');
      if (value) {
        if (activators.contains('focus')) {
          set(this, 'focused', true);
        } else if (activators.contains('hover')) {
          set(this, 'hovered', true);
        } else if (activators.contains('click')) {
          set(this, 'pressed', true);
        }
      } else {
        set(this, 'focused', false);
        set(this, 'hovered', false);
        set(this, 'pressed', false);
      }
      return value;
    },

    get() {
      var activators = get(this, 'on');
      var active = false;

      if (activators.contains('focus')) {
        active = active || get(this, 'focused');
        if (activators.contains('hold')) {
          active = active || get(this, 'component.pressed');
        }
      }

      if (activators.contains('hover')) {
        active = active || get(this, 'hovered');
        if (activators.contains('hold')) {
          active = active || get(this, 'component.hovered');
        }
      }

      if (activators.contains('click') || activators.contains('hold')) {
        active = active || get(this, 'pressed');
      }

      return !!active;
    }
  }),

  focus: guard(function () {
    set(this, 'focused', true);
  }),

  blur: guard(function () {
    set(this, 'focused', false);
  }),

  mouseEnter: guard(function () {
    this._willLeave = false;
    set(this, 'hovered', true);
  }),

  mouseLeave: guard(function () {
    this._willLeave = true;
    Ember.run.later(() => {
      if (get(this, 'component.disabled')) { return; }
      this._willLeave = false;
      set(this, 'hovered', false);
    }, 100);
  }),

  mouseDown: guard(function (evt) {
    if (!this.isClicked(evt)) {
      return false;
    }

    var element = this.element;
    var active = !get(this, 'active');
    set(this, 'pressed', active);

    if (active) {
      this.holdStart = new Date().getTime();

      var eventManager = this.eventManager;
      eventManager.mouseup = bind(this, 'mouseUp');
      $(document).on('mouseup', eventManager.mouseup);

      evt.preventDefault();
    }

    $(element).focus();
    return true;
  }),

  mouseUp: function (evt) {
    // Remove mouseup event
    var eventManager = this.eventManager;
    $(document).off('mouseup', eventManager.mouseup);
    eventManager.mouseup = null;

    var label = labelForEvent(evt);

    // Treat clicks on <label> elements as triggers to
    // open the menu
    if (isLabelClicked(this.element, label)) {
      return true;
    }

    var activators = get(this, 'on');

    if (activators.contains('click') && activators.contains('hold')) {
      // If the user waits more than 400ms between mouseDown and mouseUp,
      // we can assume that they are clicking and dragging to the menu item,
      // and we should close the menu if they mouseup anywhere not inside
      // the menu.
      if (new Date().getTime() - this.holdStart > 400) {
        set(this, 'pressed', false);
      }
    }
    return true;
  }

});

export default Target;
<|endoftext|>


<commit_before>import Ember from 'ember';

Ember.$.support.cors = true;

export default Ember.Object.extend(
  Ember.Evented,
{
  baseUrl: Ember.required(),
  namespace: null,
  context: null,
  /**
    To be defined as needed by app.
   */
  authParams: null,

  cachePerContext: true,
  clearCacheOnContextChange: false,

  setNamespace: function (namespace) {
    this.set('namespace', namespace);
  },
  resetNamespace: function () {
    this.setNamespace(null);
  },

  setContext: function (context) {
    this.set('context', context);
  },
  resetContext: function () {
    this.setContext(null);
  },

  GET: function (url, data, sync) {
    var settings = {
      type: 'GET',
      url: this._contextifiedUrl(url),
      data: this.buildParams(data),
      sync: Ember.isNone(sync) ? false : sync
    };
    return this._promisifiedAjax(settings);
  },

  POST: function (url, data, sync) {
    return this._jsonBasedAjax('POST', url, data, sync);
  },
  PUT: function (url, data, sync) {
    return this._jsonBasedAjax('PUT', url, data, sync);
  },
  DELETE: function (url, data, sync) {
    return this._jsonBasedAjax('DELETE', url, data, sync);
  },

  _jsonBasedAjax: function (action, url, data, sync) {
    var settings = {
      type: action,
      url: this._contextifiedUrl(url),
      contentType: 'application/json',
      dataType: 'json',
      data: JSON.stringify(this.buildParams(data)),
      sync: Ember.isNone(sync) ? false : sync
    };
    return this._promisifiedAjax(settings);
  },

  _contextifiedUrl: function (url) {
    var parts = [],
        namespace = this.get('namespace'),
        context = this.get('context');

    parts.pushObject(this.get('baseUrl'));
    if (namespace) {
      parts.pushObject(namespace);
    }
    if (!Ember.isNone(context)) {
      parts.pushObject(context);
    }
    parts.pushObject(url);
    return parts.join('/');
  },

  _promisifiedAjax: function (settings) {
    var self = this;
    return new Ember.RSVP.Promise(function (resolve, reject) {
      self._xhr(
        settings,
        function (data) {
          resolve(data);
        },
        function (xhr, status, error) {
          Ember.run(function () {
            self.xhrError(settings, xhr, status, error);
            reject({
              xhr: xhr,
              status: status,
              error: error
            });
          });
        });
    });
  },

  _xhr: function (settings, success, error) {
    if (!settings.async) {
      settings = Ember.merge(settings, {
        success: success,
        error: error
      });
    }

    var call = this.ajax(settings);

    if (settings.async) {
      call
        .done(success)
        .fail(error);
    }
  },

  find: function (model, query, result) {
    var useContext = Ember.isNone(query.options.useContext) ? true : query.options.useContext,
        url = this.buildUrl(
          model.key,
          query.findMany ? null : model.ids,
          model.parent,
          useContext),
        settings = {
      async: query.async,
      type: 'GET',
      url: url,
      dataType: 'json',
      data: this.buildParams(query.options.params, query.findMany ? {
        ids: model.ids, // Ember.isEmpty(ids) ? null : ids,
      } : null)
    };

    Ember.tryInvoke(result.hooks, 'willXHR', [url]);
    this._xhr(settings,

    function (data) {
      var resourceKey = model.key;
      if (query.findMany) {
        resourceKey = resourceKey.pluralize();
        Ember.Logger.debug("DATA - Found many", resourceKey,
          (model.parent ? "(parent " + model.parent.toString() + ")" : '') + ":", data);
      } else {
        Ember.Logger.debug("DATA - Found one", resourceKey,
          "(" + query.ids + "):", data);
      }

      if (data[resourceKey]) {
        Ember.tryInvoke(query.hooks, 'willLoad', [data]);
        var got;
        if (query.findMany) {
          got = result.store.loadMany(model.key, data[resourceKey]);
        } else {
          got = result.store.load(model.key, data[resourceKey]);
        }
        result.store.sideLoad(data, resourceKey);
        Ember.tryInvoke(query.hooks, 'didLoad', [data]);
        result.ok(got);
      } else {
        var message = "API returned JSON with missing key '" + resourceKey + "'";

        Ember.Logger.error(message, data);
        result.ko({
          xhr: null,
          status: null,
          error: message
        });
      }
    },
    function (xhr, status, error) {
      this.xhrError(settings, xhr, status, error);
      result.ko({
        xhr: xhr,
        status: status,
        error: error
      });
    }.bind(this));
  },

  save: function (record, extraParams, includeProperties) {
    var adapter = this,
        action,
        async = true,
        params = {},
        resourceKey = record.constructor.resourceKey(),
        url = [
      this.get('baseUrl'),
      this.get('namespace'),
      this.get('context'),
      record.get('_url')
    ].compact().join('/');

    return new Ember.RSVP.Promise(function (resolve, reject) {
      Ember.run(adapter, function () {
        if (!(record.get('meta.isDirty') || record.get('meta.isNew'))) {
          Ember.Logger.warn('Do not save clean record: ' + record.toString());
          record.unload();
          resolve(record);
          return;
        }

        if (record.get('meta.isDeleted')) {
          action = 'DELETE';
        } else {
          params[resourceKey] = record.toJSON(includeProperties);

          if (record.get('meta.isNew')) {
            action = 'POST';
          } else {
            action = 'PUT';
          }
        }

        var settings = {
          async: async,
          type: action,
          url: url,
          dataType: 'json',
          contentType: 'application/json',
          data: JSON.stringify(adapter.buildParams(params, extraParams))
        };

        this.ajax(settings).
        done(function (data) {
          Ember.run(function () {
            Ember.Logger.debug("DATA - Saved (" + action + ")",
              record.toString(), ":", data);

            if (data && data[resourceKey]) {
              record.reloadFrom(data, resourceKey);
              resolve(record);
            } else {
              if (action === 'DELETE') {
                record.unload();
                resolve(record);
              } else {
                Ember.Logger.warn("API returned JSON with missing key '%@'".fmt(resourceKey), data);
                resolve(record);
              }
            }
          });
        }).
        fail(function (xhr, status, error) {
          Ember.run(function () {
            adapter.xhrError(settings, xhr, status, error);
            reject({
              xhr: xhr,
              status: status,
              error: error
            });
          });
        });
      });
    });
  },

  buildUrl: function (key, id, parent, useContext) {
    var namespace = this.get('namespace'),
        context = this.get('context'),
        urlParts = [
      this.get('baseUrl')
    ];

    if (namespace) {
      urlParts.pushObject(namespace);
    }
    if (context && useContext) {
      urlParts.pushObject(context);
    }
    if (parent) {
      urlParts.pushObject(parent.get('_url'));
    }
    urlParts.pushObject(key.pluralize());
    if (!Ember.isNone(id)) {
      urlParts.pushObject(id);
    }
    return urlParts.join('/');
  },

  buildParams: function (optionParams, extraParams) {
    var params = {};
    // Ember.merge(params, this.get('authParams'));

    if (optionParams) {
      Ember.merge(params, optionParams);
    }
    if (extraParams) {
      Ember.merge(params, extraParams);
    }
    return params;
  },

  xhrError: function (settings, xhr, status, error) {
    Ember.Logger.error('XHR Failed:', xhr.type, xhr.url, '->', status, error);
    this.trigger('xhr:error', xhr, status, error);
  },

  ajax: function (settings) {
    return Ember.$.ajax(Ember.merge(settings, {
      xhrFields: {
        withCredentials: true
      }
    }));
  },
});
<commit_msg>Simplify notation<commit_after>import Ember from 'ember';

Ember.$.support.cors = true;

export default Ember.Object.extend(
  Ember.Evented,
{
  baseUrl: Ember.required(),
  namespace: null,
  context: null,
  /**
    To be defined as needed by app.
   */
  authParams: null,

  cachePerContext: true,
  clearCacheOnContextChange: false,

  setNamespace: function (namespace) {
    this.set('namespace', namespace);
  },
  resetNamespace: function () {
    this.setNamespace(null);
  },

  setContext: function (context) {
    this.set('context', context);
  },
  resetContext: function () {
    this.setContext(null);
  },

  GET: function (url, data, sync) {
    var settings = {
      type: 'GET',
      url: this._contextifiedUrl(url),
      data: this.buildParams(data),
      sync: Ember.isNone(sync) ? false : sync
    };
    return this._promisifiedAjax(settings);
  },

  POST: function (url, data, sync) {
    return this._jsonBasedAjax('POST', url, data, sync);
  },
  PUT: function (url, data, sync) {
    return this._jsonBasedAjax('PUT', url, data, sync);
  },
  DELETE: function (url, data, sync) {
    return this._jsonBasedAjax('DELETE', url, data, sync);
  },

  _jsonBasedAjax: function (action, url, data, sync) {
    var settings = {
      type: action,
      url: this._contextifiedUrl(url),
      contentType: 'application/json',
      dataType: 'json',
      data: JSON.stringify(this.buildParams(data)),
      sync: Ember.isNone(sync) ? false : sync
    };
    return this._promisifiedAjax(settings);
  },

  _contextifiedUrl: function (url) {
    var parts = [],
        namespace = this.get('namespace'),
        context = this.get('context');

    parts.pushObject(this.get('baseUrl'));
    if (namespace) {
      parts.pushObject(namespace);
    }
    if (!Ember.isNone(context)) {
      parts.pushObject(context);
    }
    parts.pushObject(url);
    return parts.join('/');
  },

  _promisifiedAjax: function (settings) {
    var self = this;
    return new Ember.RSVP.Promise(function (resolve, reject) {
      self._xhr(
        settings,
        function (data) {
          resolve(data);
        },
        function (xhr, status, error) {
          Ember.run(function () {
            self.xhrError(settings, xhr, status, error);
            reject({
              xhr: xhr,
              status: status,
              error: error
            });
          });
        });
    });
  },

  _xhr: function (settings, success, error) {
    if (!settings.async) {
      settings = Ember.merge(settings, {
        success: success,
        error: error
      });
    }

    var call = this.ajax(settings);

    if (settings.async) {
      call
        .done(success)
        .fail(error);
    }
  },

  find: function (model, query, result) {
    var useContext = Ember.isNone(query.options.useContext) ? true : query.options.useContext,
        url = this.buildUrl(
          model.key,
          query.findMany ? null : model.ids,
          model.parent,
          useContext),
        settings = {
      async: query.async,
      type: 'GET',
      url: url,
      dataType: 'json',
      data: this.buildParams(query.options.params, query.findMany ? {
        ids: model.ids, // Ember.isEmpty(ids) ? null : ids,
      } : null)
    };

    Ember.tryInvoke(result.hooks, 'willXHR', [url]);
    this._xhr(settings,

    function (data) {
      var resourceKey = model.key;
      if (query.findMany) {
        resourceKey = resourceKey.pluralize();
        Ember.Logger.debug("DATA - Found many", resourceKey,
          (model.parent ? "(parent " + model.parent.toString() + ")" : '') + ":", data);
      } else {
        Ember.Logger.debug("DATA - Found one", resourceKey,
          "(" + query.ids + "):", data);
      }

      if (Ember.isNone(data[resourceKey])) {
        var message = "API returned JSON with missing key '" + resourceKey + "'";

        Ember.Logger.error(message, data);
        result.ko({
          xhr: null,
          status: null,
          error: message
        });
      } else {
        Ember.tryInvoke(query.hooks, 'willLoad', [data]);
        var got;
        if (query.findMany) {
          got = result.store.loadMany(model.key, data);
        } else {
          got = result.store.load(model.key, data);
        }
        Ember.tryInvoke(query.hooks, 'didLoad', [data]);
        result.ok(got);
      }
    },
    function (xhr, status, error) {
      this.xhrError(settings, xhr, status, error);
      result.ko({
        xhr: xhr,
        status: status,
        error: error
      });
    }.bind(this));
  },

  save: function (record, extraParams, includeProperties) {
    var adapter = this,
        action,
        async = true,
        params = {},
        resourceKey = record.constructor.resourceKey(),
        url = [
      this.get('baseUrl'),
      this.get('namespace'),
      this.get('context'),
      record.get('_url')
    ].compact().join('/');

    return new Ember.RSVP.Promise(function (resolve, reject) {
      Ember.run(adapter, function () {
        if (!(record.get('meta.isDirty') || record.get('meta.isNew'))) {
          Ember.Logger.warn('Do not save clean record: ' + record.toString());
          record.unload();
          resolve(record);
          return;
        }

        if (record.get('meta.isDeleted')) {
          action = 'DELETE';
        } else {
          params[resourceKey] = record.toJSON(includeProperties);

          if (record.get('meta.isNew')) {
            action = 'POST';
          } else {
            action = 'PUT';
          }
        }

        var settings = {
          async: async,
          type: action,
          url: url,
          dataType: 'json',
          contentType: 'application/json',
          data: JSON.stringify(adapter.buildParams(params, extraParams))
        };

        this.ajax(settings).
        done(function (data) {
          Ember.run(function () {
            Ember.Logger.debug("DATA - Saved (" + action + ")",
              record.toString(), ":", data);

            if (data && data[resourceKey]) {
              record.reloadFrom(data, resourceKey);
              resolve(record);
            } else {
              if (action === 'DELETE') {
                record.unload();
                resolve(record);
              } else {
                Ember.Logger.warn("API returned JSON with missing key '%@'".fmt(resourceKey), data);
                resolve(record);
              }
            }
          });
        }).
        fail(function (xhr, status, error) {
          Ember.run(function () {
            adapter.xhrError(settings, xhr, status, error);
            reject({
              xhr: xhr,
              status: status,
              error: error
            });
          });
        });
      });
    });
  },

  buildUrl: function (key, id, parent, useContext) {
    var namespace = this.get('namespace'),
        context = this.get('context'),
        urlParts = [
      this.get('baseUrl')
    ];

    if (namespace) {
      urlParts.pushObject(namespace);
    }
    if (context && useContext) {
      urlParts.pushObject(context);
    }
    if (parent) {
      urlParts.pushObject(parent.get('_url'));
    }
    urlParts.pushObject(key.pluralize());
    if (!Ember.isNone(id)) {
      urlParts.pushObject(id);
    }
    return urlParts.join('/');
  },

  buildParams: function (optionParams, extraParams) {
    var params = {};
    // Ember.merge(params, this.get('authParams'));

    if (optionParams) {
      Ember.merge(params, optionParams);
    }
    if (extraParams) {
      Ember.merge(params, extraParams);
    }
    return params;
  },

  xhrError: function (settings, xhr, status, error) {
    Ember.Logger.error('XHR Failed:', xhr.type, xhr.url, '->', status, error);
    this.trigger('xhr:error', xhr, status, error);
  },

  ajax: function (settings) {
    return Ember.$.ajax(Ember.merge(settings, {
      xhrFields: {
        withCredentials: true
      }
    }));
  },
});
<|endoftext|>