<commit_before>var $ = require("jquery");

$.fn.popup = function(button) {

    var $body = $('body');
    var $popup = this;
    var $overlay = $('.overlay');
    var cancel = '.cancel__button';

    /**
     * Overlay
     */

    $body.keyup(function(e){
        if(e.which == 27){
            $popup.addClass('hidden');
            $overlay.addClass('hidden');
        }
    });

    $overlay.click(function(e) {
        e.stopPropagation();
        $popup.addClass('hidden');
        $overlay.addClass('hidden');
    });

    /**
     * Popup
     */

    $body.on('click', button, function(e) {
        e.preventDefault();
        $popup.removeClass('hidden');
        $overlay.removeClass('hidden');
        if(e.currentTarget.id == "signin__button") {
            $("#signin_mail").focus();
        } else {
            $("#login_mail").focus();
        }
        return false;
    });

    $popup.on('click', cancel, function(e) {
        e.preventDefault();
        $popup.addClass('hidden');
        $overlay.addClass('hidden');
        return false;
    });

    return this;

};<commit_msg>more generic autofocus<commit_after>var $ = require("jquery");

$.fn.popup = function(button) {

    var $body = $('body');
    var $popup = this;
    var $overlay = $('.overlay');
    var cancel = '.cancel__button';

    /**
     * Overlay
     */

    $body.keyup(function(e){
        if(e.which == 27){
            $popup.addClass('hidden');
            $overlay.addClass('hidden');
        }
    });

    $overlay.click(function(e) {
        e.stopPropagation();
        $popup.addClass('hidden');
        $overlay.addClass('hidden');
    });

    /**
     * Popup
     */

    $body.on('click', button, function(e) {
        e.preventDefault();
        $popup.removeClass('hidden');
        $overlay.removeClass('hidden');
        $(":focusable:first-child").focus();
        return false;
    });

    $popup.on('click', cancel, function(e) {
        e.preventDefault();
        $popup.addClass('hidden');
        $overlay.addClass('hidden');
        return false;
    });

    return this;

};<|endoftext|>


<commit_before>"use strict";
/**
 * @module opcua.client
 */
require("requirish")._(module);
var util = require("util");
var EventEmitter = require("events").EventEmitter;
var subscription_service = require("lib/services/subscription_service");
var read_service = require("lib/services/read_service");

var StatusCodes = require("lib/datamodel/opcua_status_code").StatusCodes;
var assert = require("better-assert");
var TimestampsToReturn = read_service.TimestampsToReturn;

var AttributeIds = read_service.AttributeIds;

var _ = require("underscore");

/**
 * ClientMonitoredItem
 * @class ClientMonitoredItem
 * @extends EventEmitter
 *
 * @param subscription  {ClientSubscription}
 * @param itemToMonitor {ItemToMonitor}
 * @param monitoringParameters
 * @param timestampsToReturn
 * @constructor
 *
 * event:
 *    "initialized"
 *    "err"
 *    "changed"
 */
function ClientMonitoredItem(subscription, itemToMonitor, monitoringParameters, timestampsToReturn) {

    timestampsToReturn = timestampsToReturn || TimestampsToReturn.Neither;

    //xx var ClientSubscription = require("./client_subscription").ClientSubscription;
    assert(subscription.constructor.name === "ClientSubscription");

    this.itemToMonitor = itemToMonitor;
    this.monitoringParameters = new subscription_service.MonitoringParameters(monitoringParameters);
    this.subscription = subscription;
    this.timestampsToReturn = timestampsToReturn;
}

util.inherits(ClientMonitoredItem, EventEmitter);

/**
 * remove the MonitoredItem from its subscription
 * @method terminate
 * @param  done {Function} the done callback
 * @async
 */
ClientMonitoredItem.prototype.terminate = function (done) {

    assert(!done || _.isFunction(done));
    var self = this;
    /**
     * Notify the observer that this monitored item has been terminated.
     * @event terminated
     */
    self.emit("terminated");

    self.subscription._delete_monitored_item(self, function (err) {
        if (done) { done(err); }
    });
};

ClientMonitoredItem.prototype._notify_value_change = function (value) {
    var self = this;
    /**
     * Notify the observers that the MonitoredItem value has changed on the server side.
     * @event changed
     * @param value
     */
    self.emit("changed", value);
};

ClientMonitoredItem.prototype._monitor = function (done) {

    assert(done === undefined || _.isFunction(done));

    var self = this;

    assert(self.subscription.subscriptionId !== "pending");

    self.monitoringParameters.clientHandle = self.subscription.nextClientHandle();
    assert(self.monitoringParameters.clientHandle > 0);

    // If attributeId is EventNotifier then monitoring parameters need a filter.
    // The filter must then either be DataChangeFilter, EventFilter or AggregateFilter.
    // todo can be done in another way?
    // todo implement AggregateFilter
    if (!((self.itemToMonitor.attributeId === AttributeIds.EventNotifier
            && self.monitoringParameters.filter
            && (self.monitoringParameters.filter instanceof subscription_service.EventFilter
                || self.monitoringParameters.filter instanceof subscription_service.DataChangeFilter))
        || self.itemToMonitor.attributeId !== AttributeIds.EventNotifier
            && !self.monitoringParameters.filter)) {
        throw new Error({ message: 'Mismatch between attributeId and filter in monitoring parameters'});
    }

    var createMonitorItemsRequest = new subscription_service.CreateMonitoredItemsRequest({
        subscriptionId: self.subscription.subscriptionId,
        // timestampsToReturn:
        timestampsToReturn: self.timestampsToReturn,
        itemsToCreate: [
            {
                itemToMonitor: self.itemToMonitor,
                monitoringMode: subscription_service.MonitoringMode.Reporting,
                requestedParameters: self.monitoringParameters
            }
        ]
    });

    self.subscription.session.createMonitoredItems(createMonitorItemsRequest, function (err, response) {

        /* istanbul ignore next */
        if (err) {
            console.log("  ERROR in createMonitoredItems ".red, err.message);
            self.emit("err", err.message);
            self.emit("terminated");
        } else {
            assert(response instanceof subscription_service.CreateMonitoredItemsResponse);
            assert(response.results.length === 1);
            var monitoredItemResult = response.results[0];

            /* istanbul ignore else */
            if (monitoredItemResult.statusCode === StatusCodes.Good) {

                self.result = monitoredItemResult;
                self.monitoredItemId = monitoredItemResult.monitoredItemId;
                self.monitoringParameters.samplingInterval = monitoredItemResult.revisedSamplingInterval;
                self.monitoringParameters.queueSize = monitoredItemResult.revisedQueueSize;
                self.filterResult = monitoredItemResult.filterResult;

                /**
                 * Notify the observers that the monitored item is now fully initialized.
                 * @event initialized
                 */
                self.subscription._add_monitored_item(self.monitoringParameters.clientHandle, self);

                self.emit("initialized");

            } else {

                //xx console.log(" monitoredItemResult statusCode = ".red, monitoredItemResult.statusCode.toString());
                //xx require("lib/misc/utils").dump(response);
                //xx require("lib/misc/utils").dump(createMonitorItemsRequest);

                /**
                 * Notify the observers that the monitored item is now fully initialized.
                 * @event err
                 * @param statusCode {StatusCode}
                 */
                self.emit("err", monitoredItemResult.statusCode);
            }
        }
        if (done) {
            done(err);
        }
    });
};

var ModifyMonitoredItemsRequest = subscription_service.ModifyMonitoredItemsRequest;
var MonitoredItemModifyRequest = subscription_service.MonitoredItemModifyRequest;

/**
 *
 * @param parameters
 * @param [timestampsToReturn=null]
 *  MonitoredItemModifyRequest
 * @param callback
 */
ClientMonitoredItem.prototype.modify = function(parameters,timestampsToReturn,callback) {

    var self = this;

    if (_.isFunction(timestampsToReturn)) {
        callback = timestampsToReturn;
        timestampsToReturn = null;
    }

    parameters.clientHandle =   parameters.clientHandle ||  self.monitoringParameters.clientHandle;

    assert(callback === undefined || _.isFunction(callback));

    //xx console.log(" parameters = ",parameters);

    var modifyMonitoredItemsRequest = new ModifyMonitoredItemsRequest({
        subscriptionId:     self.subscription.subscriptionId,
        timestampsToReturn: timestampsToReturn || self.timestampsToReturn,
        itemsToModify: [
            new MonitoredItemModifyRequest({
                monitoredItemId: self.monitoredItemId,

                requestedParameters: parameters
            })
        ]
    });

    self.subscription.session.modifyMonitoredItems(modifyMonitoredItemsRequest, function (err, response) {

        /* istanbul ignore next */
        if(err) {
            return callback(err);
        }
        assert(response.results.length === 1);

        var res = response.results[0];

        /* istanbul ignore next */
        if ( res.statusCode !== StatusCodes.Good) {
            return callback(new Error("Error" +  res.statusCode.toString() ));
        }
        callback(null,response.results[0]);
    });

};

exports.ClientMonitoredItem = ClientMonitoredItem;
<commit_msg>Monitor will instantiate EventFilter correctly<commit_after>"use strict";
/**
 * @module opcua.client
 */
require("requirish")._(module);
var util = require("util");
var EventEmitter = require("events").EventEmitter;
var subscription_service = require("lib/services/subscription_service");
var read_service = require("lib/services/read_service");

var StatusCodes = require("lib/datamodel/opcua_status_code").StatusCodes;
var assert = require("better-assert");
var TimestampsToReturn = read_service.TimestampsToReturn;

var AttributeIds = read_service.AttributeIds;

var resolveNodeId = require("lib/datamodel/nodeid").resolveNodeId;
var ObjectTypeIds = require("lib/opcua_node_ids").ObjectTypeIds;

var _ = require("underscore");

/**
 * ClientMonitoredItem
 * @class ClientMonitoredItem
 * @extends EventEmitter
 *
 * @param subscription  {ClientSubscription}
 * @param itemToMonitor {ItemToMonitor}
 * @param monitoringParameters
 * @param timestampsToReturn
 * @constructor
 *
 * event:
 *    "initialized"
 *    "err"
 *    "changed"
 */
function ClientMonitoredItem(subscription, itemToMonitor, monitoringParameters, timestampsToReturn) {

    timestampsToReturn = timestampsToReturn || TimestampsToReturn.Neither;

    //xx var ClientSubscription = require("./client_subscription").ClientSubscription;
    assert(subscription.constructor.name === "ClientSubscription");

    this.itemToMonitor = itemToMonitor;
    this.monitoringParameters = new subscription_service.MonitoringParameters(monitoringParameters);
    this.subscription = subscription;
    this.timestampsToReturn = timestampsToReturn;
}

util.inherits(ClientMonitoredItem, EventEmitter);

/**
 * remove the MonitoredItem from its subscription
 * @method terminate
 * @param  done {Function} the done callback
 * @async
 */
ClientMonitoredItem.prototype.terminate = function (done) {

    assert(!done || _.isFunction(done));
    var self = this;
    /**
     * Notify the observer that this monitored item has been terminated.
     * @event terminated
     */
    self.emit("terminated");

    self.subscription._delete_monitored_item(self, function (err) {
        if (done) { done(err); }
    });
};

ClientMonitoredItem.prototype._notify_value_change = function (value) {
    var self = this;
    /**
     * Notify the observers that the MonitoredItem value has changed on the server side.
     * @event changed
     * @param value
     */
    self.emit("changed", value);
};

/**
 *
 * Creates the monitor.
 *
 * If the monitor attributeId is EventNotifer then the filter must be
 * spcified in this data format:
 *
 * filter: {
 *   extensionType: 'EventFilter',
 *   data: {
 *       selectClauses: [
 *           {browsePath: [{name: 'ActiveState'}, {name: 'id'} ]},
 *           {browsePath: {name: 'ConditionName'} }
 *       ],
 *       whereClause: []
 *   }
 *
 *
 * @param done
 * @private
 */
ClientMonitoredItem.prototype._monitor = function (done) {

    assert(done === undefined || _.isFunction(done));

    var self = this;

    assert(self.subscription.subscriptionId !== "pending");

    self.monitoringParameters.clientHandle = self.subscription.nextClientHandle();
    assert(self.monitoringParameters.clientHandle > 0);

    // If attributeId is EventNotifier then monitoring parameters need a filter.
    // The filter must then either be DataChangeFilter, EventFilter or AggregateFilter.
    // todo can be done in another way?
    // todo implement AggregateFilter
    // todo support DataChangeFilter
    // todo support where clause
    if(self.itemToMonitor.attributeId === AttributeIds.EventNotifier) {
        var filter = self.monitoringParameters.filter;
        assert(filter);

        if(filter.extensionType === 'EventFilter' ) {
            assert(filter.data);
            // todo Where clause not supported yet
            assert(filter.data.whereClause.length === 0);

            filter.data.selectClauses = filter.data.selectClauses.map(function(selectClause){

                assert(selectClause.browsePath);

                var browsePath = _.isArray(selectClause.browsePath)
                    ? selectClause.browsePath : [selectClause.browsePath];

                // Create SimpleAttributeOperand based on the browsePath array
                browsePath = browsePath.map(function(bp){
                    assert(bp.name);
                    return {
                        namespaceIndex: bp.namespaceIndex || 0,
                        name: bp.name
                    }
                });

                return {
                    typeId: selectClause.typeId || resolveNodeId(ObjectTypeIds.BaseEventType),
                    browsePath: browsePath,
                    attributeId: selectClause.attributeId || AttributeIds.Value,
                    indexRange: selectClause.indexRange || null
                }
            });

            // Instantiate the EventFilter
            self.monitoringParameters.filter = new subscription_service.EventFilter(filter.data);

        } else if (filter.extensionType === 'DataChangeFilter') {
            throw new Error({ message: 'DataChangeFilter not implemented'});
        } else {
            throw new Error({ message: 'Mismatch between attributeId and filter in monitoring parameters'});
        }

    } else {
        assert(!self.monitoringParameters.filter);
    }

    var createMonitorItemsRequest = new subscription_service.CreateMonitoredItemsRequest({
        subscriptionId: self.subscription.subscriptionId,
        // timestampsToReturn:
        timestampsToReturn: self.timestampsToReturn,
        itemsToCreate: [
            {
                itemToMonitor: self.itemToMonitor,
                monitoringMode: subscription_service.MonitoringMode.Reporting,
                requestedParameters: self.monitoringParameters
            }
        ]
    });

    self.subscription.session.createMonitoredItems(createMonitorItemsRequest, function (err, response) {

        /* istanbul ignore next */
        if (err) {
            console.log("  ERROR in createMonitoredItems ".red, err.message);
            self.emit("err", err.message);
            self.emit("terminated");
        } else {
            assert(response instanceof subscription_service.CreateMonitoredItemsResponse);
            assert(response.results.length === 1);
            var monitoredItemResult = response.results[0];

            /* istanbul ignore else */
            if (monitoredItemResult.statusCode === StatusCodes.Good) {

                self.result = monitoredItemResult;
                self.monitoredItemId = monitoredItemResult.monitoredItemId;
                self.monitoringParameters.samplingInterval = monitoredItemResult.revisedSamplingInterval;
                self.monitoringParameters.queueSize = monitoredItemResult.revisedQueueSize;
                self.filterResult = monitoredItemResult.filterResult;

                /**
                 * Notify the observers that the monitored item is now fully initialized.
                 * @event initialized
                 */
                self.subscription._add_monitored_item(self.monitoringParameters.clientHandle, self);

                self.emit("initialized");

            } else {

                //xx console.log(" monitoredItemResult statusCode = ".red, monitoredItemResult.statusCode.toString());
                //xx require("lib/misc/utils").dump(response);
                //xx require("lib/misc/utils").dump(createMonitorItemsRequest);

                /**
                 * Notify the observers that the monitored item is now fully initialized.
                 * @event err
                 * @param statusCode {StatusCode}
                 */
                self.emit("err", monitoredItemResult.statusCode);
            }
        }
        if (done) {
            done(err);
        }
    });
};

var ModifyMonitoredItemsRequest = subscription_service.ModifyMonitoredItemsRequest;
var MonitoredItemModifyRequest = subscription_service.MonitoredItemModifyRequest;

/**
 *
 * @param parameters
 * @param [timestampsToReturn=null]
 *  MonitoredItemModifyRequest
 * @param callback
 */
ClientMonitoredItem.prototype.modify = function(parameters,timestampsToReturn,callback) {

    var self = this;

    if (_.isFunction(timestampsToReturn)) {
        callback = timestampsToReturn;
        timestampsToReturn = null;
    }

    parameters.clientHandle =   parameters.clientHandle ||  self.monitoringParameters.clientHandle;

    assert(callback === undefined || _.isFunction(callback));

    //xx console.log(" parameters = ",parameters);

    var modifyMonitoredItemsRequest = new ModifyMonitoredItemsRequest({
        subscriptionId:     self.subscription.subscriptionId,
        timestampsToReturn: timestampsToReturn || self.timestampsToReturn,
        itemsToModify: [
            new MonitoredItemModifyRequest({
                monitoredItemId: self.monitoredItemId,

                requestedParameters: parameters
            })
        ]
    });

    self.subscription.session.modifyMonitoredItems(modifyMonitoredItemsRequest, function (err, response) {

        /* istanbul ignore next */
        if(err) {
            return callback(err);
        }
        assert(response.results.length === 1);

        var res = response.results[0];

        /* istanbul ignore next */
        if ( res.statusCode !== StatusCodes.Good) {
            return callback(new Error("Error" +  res.statusCode.toString() ));
        }
        callback(null,response.results[0]);
    });

};

exports.ClientMonitoredItem = ClientMonitoredItem;
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////////
/**
 * Create a new instance of class widget
 *
 * @class
 * @extends {geo.sceneObject}
 * @returns {geo.gui.widget}
 */
//////////////////////////////////////////////////////////////////////////////
geo.gui.widget = function (arg) {
  'use strict';
  if (!(this instanceof geo.gui.widget)) {
    return new geo.gui.widget(arg);
  }
  geo.sceneObject.call(this, arg);

  var m_this = this,
      s_exit = this._exit,
      m_layer = arg.layer,
      m_canvas = null;

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Parses the arguments a widget can take, merges them with the defaults and
   * then validates the resulting arguments.
   * @param {object} args
   * @returns {object} The arguments as a result of adding defaults and validating
   */
  ////////////////////////////////////////////////////////////////////////////
  this.parseArgs = function (args) {
    var defaults = {
      sticky: false,
      positionType: 'viewport'
    };

    args = $.extend({}, defaults, args || {});

    if ('parent' in args && !(args.parent instanceof geo.gui.widget)) {
      throw 'Parent must be of type geo.gui.widget';
    }

    return args;
  };

  this._init = function () {
    m_this.modified();
  };

  this._exit = function () {
    m_this.children().forEach(function (child) {
      m_this._deleteFeature(child);
    });

    m_this.layer().geoOff(geo.event.pan, m_this.repositionEvent);
    m_this.parentCanvas().removeChild(m_this.canvas());
    s_exit();
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Create feature give a name
   *
   * @returns {geo.Feature} Will return a new feature
   */
  ////////////////////////////////////////////////////////////////////////////
  this._createFeature = function (featureName, arg) {

    var newFeature = geo.createFeature(
      featureName, m_this, m_this.renderer(), arg);

    m_this.addChild(newFeature);
    m_this.modified();
    return newFeature;
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Delete feature
   */
  ////////////////////////////////////////////////////////////////////////////
  this._deleteFeature = function (feature) {
    m_this.removeChild(feature);
    feature._exit();
    return m_this;
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Return the layer associated with this widget.
   */
  ////////////////////////////////////////////////////////////////////////////
  this.layer = function () {
    return m_layer;
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Create the canvas this widget will operate on.
   */
  ////////////////////////////////////////////////////////////////////////////
  this._createCanvas = function () {
    throw 'Must be defined in derived classes';
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Get/Set the canvas for the widget
   */
  ////////////////////////////////////////////////////////////////////////////
  this.canvas = function (val) {
    if (val === undefined) {
      return m_canvas;
    } else {
      m_canvas = val;
    }
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Appends a child to the widget
   * The widget determines how to append itself to a parent, the parent can either
   * be another widget, or the UI Layer.
   */
  ////////////////////////////////////////////////////////////////////////////
  this._appendChild = function () {
    m_this.parentCanvas().appendChild(m_this.canvas());
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Get the parent canvas (top level widgets define their layer as their parent canvas)
   */
  ////////////////////////////////////////////////////////////////////////////
  this.parentCanvas = function () {
    if (this.parent === undefined) {
      return this.layer().canvas();
    } else {
      return this.parent().canvas();
    }
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Gets the CSS positioning that a widget should be placed at. This is based on
   * the positionType of the widget, but returns
   * { top: 0, left: 0 } by default.
   */
  ////////////////////////////////////////////////////////////////////////////
  this.position = function () {
    var position;

    if (m_this.args &&
        m_this.args.hasOwnProperty('position')) {
      position = m_this.args.position;

      if (m_this.args.hasOwnProperty('positionType') &&
          m_this.args.positionType === 'gcs') {
        position = m_this.layer().map().gcsToDisplay(m_this.args.position);
      }

      return {
        left: position.x,
        top: position.y
      };
    }

    return {
      left: 0,
      top: 0
    };
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Repositions a widget based on the argument passed, or calling position on
   * the widget itself.
   * @param {object} position A position with the form:
   * { top: m, left: n }
   */
  ////////////////////////////////////////////////////////////////////////////
  this.reposition = function (position) {
    position = position || m_this.position();
    m_this.canvas().style.position = 'absolute';

    for (var cssAttr in position) {
      if (position.hasOwnProperty(cssAttr)) {
        m_this.canvas().style[cssAttr] = position[cssAttr];
      }
    }
  };

  this.repositionEvent = function () {
    return m_this.reposition();
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Determines whether or not the widget is completely within the viewport.
   */
  ////////////////////////////////////////////////////////////////////////////
  this.isInViewport = function () {
    var position = m_this.position();
    var map = m_this.layer().map().node();

    return ((position.left >= 0 && position.top >= 0) &&
            (position.left <= map.width() && position.top <= map.height()));
  };

  if (arg &&
      arg.hasOwnProperty('sticky') &&
      arg.sticky &&
      arg.hasOwnProperty('positionType') &&
      arg.positionType === 'gcs') {
    this.layer().geoOn(geo.event.pan, m_this.repositionEvent);
  }
};
inherit(geo.gui.widget, geo.sceneObject);
<commit_msg>Fix position style set to include 'px'<commit_after>//////////////////////////////////////////////////////////////////////////////
/**
 * Create a new instance of class widget
 *
 * @class
 * @extends {geo.sceneObject}
 * @returns {geo.gui.widget}
 */
//////////////////////////////////////////////////////////////////////////////
geo.gui.widget = function (arg) {
  'use strict';
  if (!(this instanceof geo.gui.widget)) {
    return new geo.gui.widget(arg);
  }
  geo.sceneObject.call(this, arg);

  var m_this = this,
      s_exit = this._exit,
      m_layer = arg.layer,
      m_canvas = null;

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Parses the arguments a widget can take, merges them with the defaults and
   * then validates the resulting arguments.
   * @param {object} args
   * @returns {object} The arguments as a result of adding defaults and validating
   */
  ////////////////////////////////////////////////////////////////////////////
  this.parseArgs = function (args) {
    var defaults = {
      sticky: false,
      positionType: 'viewport'
    };

    args = $.extend({}, defaults, args || {});

    if ('parent' in args && !(args.parent instanceof geo.gui.widget)) {
      throw 'Parent must be of type geo.gui.widget';
    }

    return args;
  };

  this._init = function () {
    m_this.modified();
  };

  this._exit = function () {
    m_this.children().forEach(function (child) {
      m_this._deleteFeature(child);
    });

    m_this.layer().geoOff(geo.event.pan, m_this.repositionEvent);
    m_this.parentCanvas().removeChild(m_this.canvas());
    s_exit();
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Create feature give a name
   *
   * @returns {geo.Feature} Will return a new feature
   */
  ////////////////////////////////////////////////////////////////////////////
  this._createFeature = function (featureName, arg) {

    var newFeature = geo.createFeature(
      featureName, m_this, m_this.renderer(), arg);

    m_this.addChild(newFeature);
    m_this.modified();
    return newFeature;
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Delete feature
   */
  ////////////////////////////////////////////////////////////////////////////
  this._deleteFeature = function (feature) {
    m_this.removeChild(feature);
    feature._exit();
    return m_this;
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Return the layer associated with this widget.
   */
  ////////////////////////////////////////////////////////////////////////////
  this.layer = function () {
    return m_layer;
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Create the canvas this widget will operate on.
   */
  ////////////////////////////////////////////////////////////////////////////
  this._createCanvas = function () {
    throw 'Must be defined in derived classes';
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Get/Set the canvas for the widget
   */
  ////////////////////////////////////////////////////////////////////////////
  this.canvas = function (val) {
    if (val === undefined) {
      return m_canvas;
    } else {
      m_canvas = val;
    }
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Appends a child to the widget
   * The widget determines how to append itself to a parent, the parent can either
   * be another widget, or the UI Layer.
   */
  ////////////////////////////////////////////////////////////////////////////
  this._appendChild = function () {
    m_this.parentCanvas().appendChild(m_this.canvas());
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Get the parent canvas (top level widgets define their layer as their parent canvas)
   */
  ////////////////////////////////////////////////////////////////////////////
  this.parentCanvas = function () {
    if (this.parent === undefined) {
      return this.layer().canvas();
    } else {
      return this.parent().canvas();
    }
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Gets the CSS positioning that a widget should be placed at. This is based on
   * the positionType of the widget, but returns
   * { top: 0, left: 0 } by default.
   */
  ////////////////////////////////////////////////////////////////////////////
  this.position = function () {
    var position;

    if (m_this.args &&
        m_this.args.hasOwnProperty('position')) {
      position = m_this.args.position;

      if (m_this.args.hasOwnProperty('positionType') &&
          m_this.args.positionType === 'gcs') {
        position = m_this.layer().map().gcsToDisplay(m_this.args.position);
      }

      return {
        left: position.x,
        top: position.y
      };
    }

    return {
      left: 0,
      top: 0
    };
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Repositions a widget based on the argument passed, or calling position on
   * the widget itself.
   * @param {object} position A position with the form:
   * { top: m, left: n }
   */
  ////////////////////////////////////////////////////////////////////////////
  this.reposition = function (position) {
    position = position || m_this.position();
    m_this.canvas().style.position = 'absolute';

    for (var cssAttr in position) {
      if (position.hasOwnProperty(cssAttr)) {
        m_this.canvas().style[cssAttr] = position[cssAttr] + 'px';
      }
    }
  };

  this.repositionEvent = function () {
    return m_this.reposition();
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Determines whether or not the widget is completely within the viewport.
   */
  ////////////////////////////////////////////////////////////////////////////
  this.isInViewport = function () {
    var position = m_this.position();
    var map = m_this.layer().map().node();

    return ((position.left >= 0 && position.top >= 0) &&
            (position.left <= map.width() && position.top <= map.height()));
  };

  if (arg &&
      arg.hasOwnProperty('sticky') &&
      arg.sticky &&
      arg.hasOwnProperty('positionType') &&
      arg.positionType === 'gcs') {
    this.layer().geoOn(geo.event.pan, m_this.repositionEvent);
  }
};
inherit(geo.gui.widget, geo.sceneObject);
<|endoftext|>


<commit_before>'use strict'

const assert = require('assert')
const pathresolve = require('path').resolve
const Koa = require('koa')
const mixins = require('./mixin')
const LocalUtil = require('./util.js')

const Tiz = module.exports = class Tiz extends Koa {
  constructor(projectHome) {
    super()

    this.projectHome = projectHome || process.cwd()
    this.appHome = this.projectHome + '/app'
    this.configHome = this.projectHome + '/config'

    // others
    this._util = LocalUtil
  }

  /**
   * path.resolve bind for projectHome
   */

  resolve(path) {
    return pathresolve(this.projectHome, path)
  }

  /**
   * init for Tiz
   */

  async start(startConfig) {
    // global var
    global.tiz = this
    const app = this
    this.startConfig = startConfig

    // read configs
    this.config = this.readConfig(startConfig)

    // service
    this.setupServices()

    // middlewares
    this.setupMiddlewares()

    // plugins
    this.setupPlugins()

    // await bootstrap
    await require(this.appHome + '/bootstrap.js')

    // listen
    if (this.config.listen !== false) {
      await new Promise((resolve, reject) => {
        app.listen(this.config.port, function() {
          console.log('tiz listening at http://localhost:%s', this.address().port)
          app.server = this
          app.emit('ready')
          resolve()
        })
      })
    }
  }
}

/**
 * add mixin
 */

Object.assign(Tiz.prototype, mixins)<commit_msg>core: fix bootstrap<commit_after>'use strict'

const assert = require('assert')
const pathresolve = require('path').resolve
const fs = require('fs')
const Koa = require('koa')
const mixins = require('./mixin')
const LocalUtil = require('./util.js')

const Tiz = module.exports = class Tiz extends Koa {
  constructor(projectHome) {
    super()

    this.projectHome = projectHome || process.cwd()
    this.appHome = this.projectHome + '/app'
    this.configHome = this.projectHome + '/config'

    // others
    this._util = LocalUtil
  }

  /**
   * path.resolve bind for projectHome
   */

  resolve(path) {
    return pathresolve(this.projectHome, path)
  }

  /**
   * init for Tiz
   */

  async start(startConfig) {
    // global var
    global.tiz = this
    const app = this
    this.startConfig = startConfig

    // read configs
    this.config = this.readConfig(startConfig)

    // service
    this.setupServices()

    // middlewares
    this.setupMiddlewares()

    // plugins
    this.setupPlugins()

    // await bootstrap
    const bsp = this.appHome + '/bootstrap.js'
    if (fs.existsAync(bsp)) {
      await require(bsp).call(this, this)
    }

    // listen
    if (this.config.listen !== false) {
      await new Promise((resolve, reject) => {
        app.listen(this.config.port, function() {
          console.log('tiz listening at http://localhost:%s', this.address().port)
          app.server = this
          app.emit('ready')
          resolve()
        })
      })
    }
  }
}

/**
 * add mixin
 */

Object.assign(Tiz.prototype, mixins)<|endoftext|>


<commit_before>;(function(){

/**
	Locale Library - Convert Date and Number types to locale appropriate English strings.

	NOTE: If using timestamps, convert them with 'new Date(MyTimestamp)' first.
*/

var DateSuffixTable = [
	"th","st","nd","rd","th","th","th","th","th","th",
	"th","th","th","th","th","th","th","th","th","th"
];
var DayOfTheWeekTable = [
	"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"
];
var MonthOfTheYearTable = [
	"January","February","March","April","May","June","July",
	"August","September","October","November","December"
];

var time_locale = navigator.language;

// Since official time standards don't necessarily match common use, remap time locales //
var LocaleTimeRemapTable = {
	'en-GB':'en-US',			// 12 hour, from 24 hour
};
if ( LocaleTimeRemapTable.hasOwnProperty(navigator.language) ) {
	time_locale = LocaleTimeRemapTable[navigator.language];
}

// Timezone remapping table
var LocaleZoneRemaps = {
	"Argentina Standard Time":"ART",
	"GMT Standard Time":"BST"/*"GMT+1"*/,					// British Summer Time*
	//"??":"CET"/*"GMT+1"*/,
	"Western European Daylight Time":"CEST"/*"GMT+2"*/,		// was WEDT, but VERY uncommon
	//"??":"CET"/*"GMT+1"*/,
	"Western European Summer Time":"CEST"/*"GMT+2"*/,		// was WEST, but uncommon
	"Romance Standard Time":"CET"/*"GMT+1"*/,				// was RST, but uncommon
	"Romance Daylight Time":"CEST"/*"GMT+2"*/,				// was RDT, but uncommon
	"Mitteleuropäische Zeit":"MEZ"/*"GMT+1"*/,
	"Mitteleuropäische Sommerzeit":"MESZ"/*"GMT+2"*/,

	// Microsoft
	"W. Europe Standard Time":"CET"/*"GMT+1"*/,
}
// References:
// * https://gist.github.com/stemar/5556910e99e8df2fd21d - I'm not sure I trust this
// * https://msdn.microsoft.com/en-us/library/ms912391(v=winembedded.11).aspx

// Locale dependent changes
var LocaleCustomZoneRemaps = {
	'en-IE': {
		"GMT Standard Time":"IST"/*"GMT+1"*/,				// Irish Standard Time
	},
};

// Overwrite master list with custom mappings
if ( LocaleCustomZoneRemaps[navigator.language] ) {
	LocaleZoneRemaps = Object.assign(LocaleZoneRemaps, LocaleCustomZoneRemaps[navigator.language]);
}
if ( navigator.languages ) {
	navigator.languages.forEach(function(lang) {
		if ( LocaleCustomZoneRemaps[lang] ) {
			LocaleZoneRemaps = Object.assign(LocaleZoneRemaps, LocaleCustomZoneRemaps[lang]);
		}
	});
}

// I don't see this being used much, but a way to get the internal locale //
window.getLocale = function() {
	return time_locale;
}

// Get the suffix you'd append on a numer (i.e. 10th, 31st, just the TH, RD, ST, ND part) //
window.getLocaleNumberSuffix = function( num ) {
	var Digit = Math.abs(num) % 100;
	if ( (Digit > 10) && (Digit < 20) )
		return "th";
	else
		return DateSuffixTable[Digit % 10];
}

// Time, as either 12 hour (i.e. 2:35 AM) or 24 hour (i.e. 02:30) form, depending on browser locale //
window.getLocaleTime = function( date ) {
	// Check toLocaleTimeString for 12 hour clock, or if language is English, assume 12 hour clock //
	if ( ('toLocaleTimeString' in Date.prototype )
		&& (date.toLocaleTimeString(time_locale).indexOf('M') > -1)	// AM PM both have M's
		|| (time_locale.indexOf("en-") >= 0) )
	{
		var HalfDay = (date.getHours() - 12) >= 0;
		var Hours = (date.getHours() % 12);
		if ( Hours == 0 )
			Hours = 12;
		return Hours + ":" +
			new String("00"+date.getMinutes()).slice(-2) +
			(HalfDay?" PM":" AM");
	}
	else {
		return new String("00"+date.getHours()).slice(-2) + ":" + new String("00"+date.getMinutes()).slice(-2);
	}
}

// Day of the Week (i.e. Sunday to Saturday) //
window.getLocaleDay = function( date ) {
	return DayOfTheWeekTable[date.getDay()];
}

// Date (i.e. January 21st, 2015) //
window.getLocaleDate = function( date ) {
	return MonthOfTheYearTable[date.getMonth()] + " " +
		date.getDate() + DateSuffixTable[date.getDate() % 20] + ", " +
		date.getFullYear();
}

// Date (i.e. January 21st) //
window.getLocaleMonthDay = function( date ) {
	return MonthOfTheYearTable[date.getMonth()] + " " +
		date.getDate() + DateSuffixTable[date.getDate() % 20];
}

// Time Zone, short abbreviated form (i.e. EST, CET) //
window.getLocaleTimeZone = function( date ) {
	// http://stackoverflow.com/a/12496442
	date = date.toString();
	for (var key in LocaleZoneRemaps) {
		date = date.replace(key, LocaleZoneRemaps[key]);
	}
	var TZ = date.indexOf('(') > -1 ?
	date.match(/\([^\)]+\)/)[0].match(/[A-Z]/g).join('') :
	date.match(/[A-Z]{3,4}/)[0];
	if (TZ == "GMT" && /(GMT\W*\d{4})/.test(date)) TZ = RegExp.$1;
	return TZ;
}

})();
<commit_msg>fix for mac<commit_after>;(function(){

/**
	Locale Library - Convert Date and Number types to locale appropriate English strings.

	NOTE: If using timestamps, convert them with 'new Date(MyTimestamp)' first.
*/

var DateSuffixTable = [
	"th","st","nd","rd","th","th","th","th","th","th",
	"th","th","th","th","th","th","th","th","th","th"
];
var DayOfTheWeekTable = [
	"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"
];
var MonthOfTheYearTable = [
	"January","February","March","April","May","June","July",
	"August","September","October","November","December"
];

var time_locale = navigator.language;

// Since official time standards don't necessarily match common use, remap time locales //
var LocaleTimeRemapTable = {
	'en-GB':'en-US',			// 12 hour, from 24 hour
};
if ( LocaleTimeRemapTable.hasOwnProperty(navigator.language) ) {
	time_locale = LocaleTimeRemapTable[navigator.language];
}

// Timezone remapping table
var LocaleZoneRemaps = {
	"Argentina Standard Time":"ART",
	"GMT Standard Time":"BST"/*"GMT+1"*/,					// British Summer Time*
	//"??":"CET"/*"GMT+1"*/,
	"Western European Daylight Time":"CEST"/*"GMT+2"*/,		// was WEDT, but VERY uncommon
	//"??":"CET"/*"GMT+1"*/,
	"Western European Summer Time":"CEST"/*"GMT+2"*/,		// was WEST, but uncommon
	"Romance Standard Time":"CET"/*"GMT+1"*/,				// was RST, but uncommon
	"Romance Daylight Time":"CEST"/*"GMT+2"*/,				// was RDT, but uncommon
	"Mitteleuropäische Zeit":"MEZ"/*"GMT+1"*/,
	"Mitteleuropäische Sommerzeit":"MESZ"/*"GMT+2"*/,

	// Microsoft
	"W. Europe Standard Time":"CET"/*"GMT+1"*/,
}
// References:
// * https://gist.github.com/stemar/5556910e99e8df2fd21d - I'm not sure I trust this
// * https://msdn.microsoft.com/en-us/library/ms912391(v=winembedded.11).aspx

// Locale dependent changes
var LocaleCustomZoneRemaps = {
	'en-IE': {
		"GMT Standard Time":"IST"/*"GMT+1"*/,				// Irish Standard Time
	},
};

// Overwrite master list with custom mappings
if ( LocaleCustomZoneRemaps[navigator.language] ) {
	LocaleZoneRemaps = Object.assign(LocaleZoneRemaps, LocaleCustomZoneRemaps[navigator.language]);
}
if ( navigator.languages ) {
	navigator.languages.forEach(function(lang) {
		if ( LocaleCustomZoneRemaps[lang] ) {
			LocaleZoneRemaps = Object.assign(LocaleZoneRemaps, LocaleCustomZoneRemaps[lang]);
		}
	});
}

// I don't see this being used much, but a way to get the internal locale //
window.getLocale = function() {
	return time_locale;
}

// Get the suffix you'd append on a numer (i.e. 10th, 31st, just the TH, RD, ST, ND part) //
window.getLocaleNumberSuffix = function( num ) {
	var Digit = Math.abs(num) % 100;
	if ( (Digit > 10) && (Digit < 20) )
		return "th";
	else
		return DateSuffixTable[Digit % 10];
}

// Time, as either 12 hour (i.e. 2:35 AM) or 24 hour (i.e. 02:30) form, depending on browser locale //
window.getLocaleTime = function( date ) {
	// Check toLocaleTimeString for 12 hour clock, or if language is English, assume 12 hour clock //
	if ( ('toLocaleTimeString' in Date.prototype )
		&& (date.toLocaleTimeString(time_locale).indexOf('M') > -1)	// AM PM both have M's
		|| (time_locale.indexOf("en-") >= 0) )
	{
		var HalfDay = (date.getHours() - 12) >= 0;
		var Hours = (date.getHours() % 12);
		if ( Hours == 0 )
			Hours = 12;
		return Hours + ":" +
			new String("00"+date.getMinutes()).slice(-2) +
			(HalfDay?" PM":" AM");
	}
	else {
		return new String("00"+date.getHours()).slice(-2) + ":" + new String("00"+date.getMinutes()).slice(-2);
	}
}

// Day of the Week (i.e. Sunday to Saturday) //
window.getLocaleDay = function( date ) {
	return DayOfTheWeekTable[date.getDay()];
}

// Date (i.e. January 21st, 2015) //
window.getLocaleDate = function( date ) {
	return MonthOfTheYearTable[date.getMonth()] + " " +
		date.getDate() + DateSuffixTable[date.getDate() % 20] + ", " +
		date.getFullYear();
}

// Date (i.e. January 21st) //
window.getLocaleMonthDay = function( date ) {
	return MonthOfTheYearTable[date.getMonth()] + " " +
		date.getDate() + DateSuffixTable[date.getDate() % 20];
}

// Time Zone, short abbreviated form (i.e. EST, CET) //
window.getLocaleTimeZone = function( date ) {
	// http://stackoverflow.com/a/12496442
	date = date.toString();
	for (var key in LocaleZoneRemaps) {
		date = date.replace(key, LocaleZoneRemaps[key]);
	}
	var TZ, TZAll;
	if ( date.indexOf('(') > -1 ) {
		TZAll = date.match(/\([^\)]+\)/)[0];
		if ( TZAll ) {
			TZ = TZAll.match(/[A-Z]/g);
			if ( TZ ) {
				TZ = TZ.join('');
			}
		}
		if ( !TZ ) {
			TZ = TZAll;
		}
	}
	else {
		TZ = date.match(/[A-Z]{3,4}/)[0];
	}

//	var TZ = date.indexOf('(') > -1 ?
//		date.match(/\([^\)]+\)/)[0].match(/[A-Z]/g).join('') :
//		date.match(/[A-Z]{3,4}/)[0];
	if (TZ == "GMT" && /(GMT\W*\d{4})/.test(date))
		TZ = RegExp.$1;
	return TZ;
}

})();
<|endoftext|>


<commit_before>import Model from '../model/model';
import Ember from 'ember';
import Reference from './reference';

import isEnabled from '../../features';
import { deprecate } from '@ember/debug';
import { assertPolymorphicType } from 'ember-data/-debug';

/**
   A BelongsToReference is a low level API that allows users and
   addon author to perform meta-operations on a belongs-to
   relationship.

   @class BelongsToReference
   @namespace DS
   @extends DS.Reference
*/
const BelongsToReference = function(store, parentInternalModel, belongsToRelationship) {
  this._super$constructor(store, parentInternalModel);
  this.belongsToRelationship = belongsToRelationship;
  this.type = belongsToRelationship.relationshipMeta.type;
  this.parent = parentInternalModel.recordReference;

  // TODO inverse
};

BelongsToReference.prototype = Object.create(Reference.prototype);
BelongsToReference.prototype.constructor = BelongsToReference;
BelongsToReference.prototype._super$constructor = Reference;

/**
   This returns a string that represents how the reference will be
   looked up when it is loaded. If the relationship has a link it will
   use the "link" otherwise it defaults to "id".

   Example

   ```javascript
    // models/blog.js
    export default DS.Model.extend({
      user: DS.belongsTo({ async: true })
    });

    let blog = store.push({
      type: 'blog',
      id: 1,
      relationships: {
        user: {
          data: { type: 'user', id: 1 }
        }
      }
    });
    let userRef = blog.belongsTo('user');

    // get the identifier of the reference
    if (userRef.remoteType() === "id") {
      let id = userRef.id();
    } else if (userRef.remoteType() === "link") {
      let link = userRef.link();
    }
    ```

   @method remoteType
   @return {String} The name of the remote type. This should either be "link" or "id"
*/
BelongsToReference.prototype.remoteType = function() {
  if (this.belongsToRelationship.link) {
    return "link";
  }

  return "id";
};

/**
   The `id` of the record that this reference refers to. Together, the
   `type()` and `id()` methods form a composite key for the identity
   map. This can be used to access the id of an async relationship
   without triggering a fetch that would normally happen if you
   attempted to use `record.get('relationship.id')`.

   Example

   ```javascript
    // models/blog.js
    export default DS.Model.extend({
      user: DS.belongsTo({ async: true })
    });

    let blog = store.push({
      data: {
        type: 'blog',
        id: 1,
        relationships: {
          user: {
            data: { type: 'user', id: 1 }
          }
        }
      }
    });
    let userRef = blog.belongsTo('user');

    // get the identifier of the reference
    if (userRef.remoteType() === "id") {
      let id = userRef.id();
    }
    ```

   @method id
   @return {String} The id of the record in this belongsTo relationship.
*/
BelongsToReference.prototype.id = function() {
  let inverseInternalModel = this.belongsToRelationship.inverseInternalModel;
  return inverseInternalModel && inverseInternalModel.id;
};

/**
   The link Ember Data will use to fetch or reload this belongs-to
   relationship.

   Example

   ```javascript
    // models/blog.js
    export default DS.Model.extend({
      user: DS.belongsTo({ async: true })
    });

    let blog = store.push({
      data: {
        type: 'blog',
        id: 1,
        relationships: {
          user: {
            links: {
              related: '/articles/1/author'
            }
          }
        }
      }
    });
    let userRef = blog.belongsTo('user');

    // get the identifier of the reference
    if (userRef.remoteType() === "link") {
      let link = userRef.link();
    }
    ```

   @method link
   @return {String} The link Ember Data will use to fetch or reload this belongs-to relationship.
*/
BelongsToReference.prototype.link = function() {
  return this.belongsToRelationship.link;
};

/**
   The meta data for the belongs-to relationship.

   Example

   ```javascript
    // models/blog.js
    export default DS.Model.extend({
      user: DS.belongsTo({ async: true })
    });

    let blog = store.push({
      data: {
        type: 'blog',
        id: 1,
        relationships: {
          user: {
            links: {
              related: {
                href: '/articles/1/author',
                meta: {
                  lastUpdated: 1458014400000
                }
              }
            }
          }
        }
      }
    });

    let userRef = blog.belongsTo('user');

    userRef.meta() // { lastUpdated: 1458014400000 }
    ```

   @method meta
   @return {Object} The meta information for the belongs-to relationship.
*/
BelongsToReference.prototype.meta = function() {
  return this.belongsToRelationship.meta;
};

/**
   `push` can be used to update the data in the relationship and Ember
   Data will treat the new data as the conanical value of this
   relationship on the backend.

   Example

    ```javascript
    // models/blog.js
    export default DS.Model.extend({
      user: DS.belongsTo({ async: true })
    });

    let blog = store.push({
      data: {
        type: 'blog',
        id: 1,
        relationships: {
          user: {
            data: { type: 'user', id: 1 }
          }
        }
      }
    });
    let userRef = blog.belongsTo('user');

    // provide data for reference
    userRef.push({
      data: {
        type: 'user',
        id: 1,
        attributes: {
          username: "@user"
        }
      }
    }).then(function(user) {
      userRef.value() === user;
    });
    ```

   @method push
   @param {Object|Promise} objectOrPromise a promise that resolves to a JSONAPI document object describing the new value of this relationship.
   @return {Promise<record>} A promise that resolves with the new value in this belongs-to relationship.
*/
BelongsToReference.prototype.push = function(objectOrPromise) {
  return Ember.RSVP.resolve(objectOrPromise).then((data) => {
    let record;

    if (data instanceof Model) {
      if (isEnabled('ds-overhaul-references')) {
        deprecate("BelongsToReference#push(DS.Model) is deprecated. Update relationship via `model.set('relationshipName', value)` instead.", false, {
          id: 'ds.references.belongs-to.push-record',
          until: '3.0'
        });
      }
      record = data;
    } else {
      record = this.store.push(data);
    }

    assertPolymorphicType(this.internalModel, this.belongsToRelationship.relationshipMeta, record._internalModel);

    this.belongsToRelationship.setCanonicalInternalModel(record._internalModel);

    return record;
  });
};

/**
   `value()` synchronously returns the current value of the belongs-to
   relationship. Unlike `record.get('relationshipName')`, calling
   `value()` on a reference does not trigger a fetch if the async
   relationship is not yet loaded. If the relationship is not loaded
   it will always return `null`.

   Example

    ```javascript
    // models/blog.js
    export default DS.Model.extend({
      user: DS.belongsTo({ async: true })
    });

    let blog = store.push({
      data: {
        type: 'blog',
        id: 1,
        relationships: {
          user: {
            data: { type: 'user', id: 1 }
          }
        }
      }
    });
    let userRef = blog.belongsTo('user');

    userRef.value(); // null

    // provide data for reference
    userRef.push({
      data: {
        type: 'user',
        id: 1,
        attributes: {
          username: "@user"
        }
      }
    }).then(function(user) {
      userRef.value(); // user
    });
    ```

   @method value
   @param {Object|Promise} objectOrPromise a promise that resolves to a JSONAPI document object describing the new value of this relationship.
   @return {DS.Model} the record in this relationship
*/
BelongsToReference.prototype.value = function() {
  let inverseInternalModel = this.belongsToRelationship.inverseInternalModel;

  if (inverseInternalModel && inverseInternalModel.isLoaded()) {
    return inverseInternalModel.getRecord();
  }

  return null;
};

/**
   Loads a record in a belongs to relationship if it is not already
   loaded. If the relationship is already loaded this method does not
   trigger a new load.

   Example

    ```javascript
    // models/blog.js
    export default DS.Model.extend({
      user: DS.belongsTo({ async: true })
    });

    let blog = store.push({
      data: {
        type: 'blog',
        id: 1,
        relationships: {
          user: {
            data: { type: 'user', id: 1 }
          }
        }
      }
    });
    let userRef = blog.belongsTo('user');

    userRef.value(); // null

    userRef.load().then(function(user) {
      userRef.value() === user
    });
    ```

   @method load
   @return {Promise} a promise that resolves with the record in this belongs-to relationship.
*/
BelongsToReference.prototype.load = function() {
  if (this.remoteType() === "id") {
    return this.belongsToRelationship.getRecord();
  }

  if (this.remoteType() === "link") {
    return this.belongsToRelationship.findLink().then((internalModel) => {
      return this.value();
    });
  }
};

/**
   Triggers a reload of the value in this relationship. If the
   remoteType is `"link"` Ember Data will use the relationship link to
   reload the relationship. Otherwise it will reload the record by its
   id.

   Example

    ```javascript
    // models/blog.js
    export default DS.Model.extend({
      user: DS.belongsTo({ async: true })
    });

    let blog = store.push({
      data: {
        type: 'blog',
        id: 1,
        relationships: {
          user: {
            data: { type: 'user', id: 1 }
          }
        }
      }
    });
    let userRef = blog.belongsTo('user');

    userRef.reload().then(function(user) {
      userRef.value() === user
    });
    ```

   @method reload
   @return {Promise} a promise that resolves with the record in this belongs-to relationship after the reload has completed.
*/
BelongsToReference.prototype.reload = function() {
  return this.belongsToRelationship.reload().then((internalModel) => {
    return this.value();
  });
};

export default BelongsToReference;
<commit_msg>[DOC] Remove parameter from BelongsToReference.value<commit_after>import Model from '../model/model';
import Ember from 'ember';
import Reference from './reference';

import isEnabled from '../../features';
import { deprecate } from '@ember/debug';
import { assertPolymorphicType } from 'ember-data/-debug';

/**
   A BelongsToReference is a low level API that allows users and
   addon author to perform meta-operations on a belongs-to
   relationship.

   @class BelongsToReference
   @namespace DS
   @extends DS.Reference
*/
const BelongsToReference = function(store, parentInternalModel, belongsToRelationship) {
  this._super$constructor(store, parentInternalModel);
  this.belongsToRelationship = belongsToRelationship;
  this.type = belongsToRelationship.relationshipMeta.type;
  this.parent = parentInternalModel.recordReference;

  // TODO inverse
};

BelongsToReference.prototype = Object.create(Reference.prototype);
BelongsToReference.prototype.constructor = BelongsToReference;
BelongsToReference.prototype._super$constructor = Reference;

/**
   This returns a string that represents how the reference will be
   looked up when it is loaded. If the relationship has a link it will
   use the "link" otherwise it defaults to "id".

   Example

   ```javascript
    // models/blog.js
    export default DS.Model.extend({
      user: DS.belongsTo({ async: true })
    });

    let blog = store.push({
      type: 'blog',
      id: 1,
      relationships: {
        user: {
          data: { type: 'user', id: 1 }
        }
      }
    });
    let userRef = blog.belongsTo('user');

    // get the identifier of the reference
    if (userRef.remoteType() === "id") {
      let id = userRef.id();
    } else if (userRef.remoteType() === "link") {
      let link = userRef.link();
    }
    ```

   @method remoteType
   @return {String} The name of the remote type. This should either be "link" or "id"
*/
BelongsToReference.prototype.remoteType = function() {
  if (this.belongsToRelationship.link) {
    return "link";
  }

  return "id";
};

/**
   The `id` of the record that this reference refers to. Together, the
   `type()` and `id()` methods form a composite key for the identity
   map. This can be used to access the id of an async relationship
   without triggering a fetch that would normally happen if you
   attempted to use `record.get('relationship.id')`.

   Example

   ```javascript
    // models/blog.js
    export default DS.Model.extend({
      user: DS.belongsTo({ async: true })
    });

    let blog = store.push({
      data: {
        type: 'blog',
        id: 1,
        relationships: {
          user: {
            data: { type: 'user', id: 1 }
          }
        }
      }
    });
    let userRef = blog.belongsTo('user');

    // get the identifier of the reference
    if (userRef.remoteType() === "id") {
      let id = userRef.id();
    }
    ```

   @method id
   @return {String} The id of the record in this belongsTo relationship.
*/
BelongsToReference.prototype.id = function() {
  let inverseInternalModel = this.belongsToRelationship.inverseInternalModel;
  return inverseInternalModel && inverseInternalModel.id;
};

/**
   The link Ember Data will use to fetch or reload this belongs-to
   relationship.

   Example

   ```javascript
    // models/blog.js
    export default DS.Model.extend({
      user: DS.belongsTo({ async: true })
    });

    let blog = store.push({
      data: {
        type: 'blog',
        id: 1,
        relationships: {
          user: {
            links: {
              related: '/articles/1/author'
            }
          }
        }
      }
    });
    let userRef = blog.belongsTo('user');

    // get the identifier of the reference
    if (userRef.remoteType() === "link") {
      let link = userRef.link();
    }
    ```

   @method link
   @return {String} The link Ember Data will use to fetch or reload this belongs-to relationship.
*/
BelongsToReference.prototype.link = function() {
  return this.belongsToRelationship.link;
};

/**
   The meta data for the belongs-to relationship.

   Example

   ```javascript
    // models/blog.js
    export default DS.Model.extend({
      user: DS.belongsTo({ async: true })
    });

    let blog = store.push({
      data: {
        type: 'blog',
        id: 1,
        relationships: {
          user: {
            links: {
              related: {
                href: '/articles/1/author',
                meta: {
                  lastUpdated: 1458014400000
                }
              }
            }
          }
        }
      }
    });

    let userRef = blog.belongsTo('user');

    userRef.meta() // { lastUpdated: 1458014400000 }
    ```

   @method meta
   @return {Object} The meta information for the belongs-to relationship.
*/
BelongsToReference.prototype.meta = function() {
  return this.belongsToRelationship.meta;
};

/**
   `push` can be used to update the data in the relationship and Ember
   Data will treat the new data as the conanical value of this
   relationship on the backend.

   Example

    ```javascript
    // models/blog.js
    export default DS.Model.extend({
      user: DS.belongsTo({ async: true })
    });

    let blog = store.push({
      data: {
        type: 'blog',
        id: 1,
        relationships: {
          user: {
            data: { type: 'user', id: 1 }
          }
        }
      }
    });
    let userRef = blog.belongsTo('user');

    // provide data for reference
    userRef.push({
      data: {
        type: 'user',
        id: 1,
        attributes: {
          username: "@user"
        }
      }
    }).then(function(user) {
      userRef.value() === user;
    });
    ```

   @method push
   @param {Object|Promise} objectOrPromise a promise that resolves to a JSONAPI document object describing the new value of this relationship.
   @return {Promise<record>} A promise that resolves with the new value in this belongs-to relationship.
*/
BelongsToReference.prototype.push = function(objectOrPromise) {
  return Ember.RSVP.resolve(objectOrPromise).then((data) => {
    let record;

    if (data instanceof Model) {
      if (isEnabled('ds-overhaul-references')) {
        deprecate("BelongsToReference#push(DS.Model) is deprecated. Update relationship via `model.set('relationshipName', value)` instead.", false, {
          id: 'ds.references.belongs-to.push-record',
          until: '3.0'
        });
      }
      record = data;
    } else {
      record = this.store.push(data);
    }

    assertPolymorphicType(this.internalModel, this.belongsToRelationship.relationshipMeta, record._internalModel);

    this.belongsToRelationship.setCanonicalInternalModel(record._internalModel);

    return record;
  });
};

/**
   `value()` synchronously returns the current value of the belongs-to
   relationship. Unlike `record.get('relationshipName')`, calling
   `value()` on a reference does not trigger a fetch if the async
   relationship is not yet loaded. If the relationship is not loaded
   it will always return `null`.

   Example

    ```javascript
    // models/blog.js
    export default DS.Model.extend({
      user: DS.belongsTo({ async: true })
    });

    let blog = store.push({
      data: {
        type: 'blog',
        id: 1,
        relationships: {
          user: {
            data: { type: 'user', id: 1 }
          }
        }
      }
    });
    let userRef = blog.belongsTo('user');

    userRef.value(); // null

    // provide data for reference
    userRef.push({
      data: {
        type: 'user',
        id: 1,
        attributes: {
          username: "@user"
        }
      }
    }).then(function(user) {
      userRef.value(); // user
    });
    ```

   @method value
   @return {DS.Model} the record in this relationship
*/
BelongsToReference.prototype.value = function() {
  let inverseInternalModel = this.belongsToRelationship.inverseInternalModel;

  if (inverseInternalModel && inverseInternalModel.isLoaded()) {
    return inverseInternalModel.getRecord();
  }

  return null;
};

/**
   Loads a record in a belongs to relationship if it is not already
   loaded. If the relationship is already loaded this method does not
   trigger a new load.

   Example

    ```javascript
    // models/blog.js
    export default DS.Model.extend({
      user: DS.belongsTo({ async: true })
    });

    let blog = store.push({
      data: {
        type: 'blog',
        id: 1,
        relationships: {
          user: {
            data: { type: 'user', id: 1 }
          }
        }
      }
    });
    let userRef = blog.belongsTo('user');

    userRef.value(); // null

    userRef.load().then(function(user) {
      userRef.value() === user
    });
    ```

   @method load
   @return {Promise} a promise that resolves with the record in this belongs-to relationship.
*/
BelongsToReference.prototype.load = function() {
  if (this.remoteType() === "id") {
    return this.belongsToRelationship.getRecord();
  }

  if (this.remoteType() === "link") {
    return this.belongsToRelationship.findLink().then((internalModel) => {
      return this.value();
    });
  }
};

/**
   Triggers a reload of the value in this relationship. If the
   remoteType is `"link"` Ember Data will use the relationship link to
   reload the relationship. Otherwise it will reload the record by its
   id.

   Example

    ```javascript
    // models/blog.js
    export default DS.Model.extend({
      user: DS.belongsTo({ async: true })
    });

    let blog = store.push({
      data: {
        type: 'blog',
        id: 1,
        relationships: {
          user: {
            data: { type: 'user', id: 1 }
          }
        }
      }
    });
    let userRef = blog.belongsTo('user');

    userRef.reload().then(function(user) {
      userRef.value() === user
    });
    ```

   @method reload
   @return {Promise} a promise that resolves with the record in this belongs-to relationship after the reload has completed.
*/
BelongsToReference.prototype.reload = function() {
  return this.belongsToRelationship.reload().then((internalModel) => {
    return this.value();
  });
};

export default BelongsToReference;
<|endoftext|>


<commit_before>/** This worker is attached to all documents served directly by PageShot
    It effectively gives those pages some superpowers

    The real work is generally done in `lib/helperworker.js`
    */

document.addEventListener("request-clipboard", function (event) {
  self.port.emit("requestClipboard", event.detail);
}, false);

document.addEventListener("add-tags", function (event) {
  self.port.emit("addTags", event.detail);
}, false);

document.addEventListener("error", function (event) {
  console.error("Error via helper from", location.href);
  self.port.emit("alertError", event.detail);
}, false);

document.addEventListener("request-sign-up", function (event) {
  self.port.emit("requestSignUp");
});
document.addEventListener("request-sign-in", function (event) {
  self.port.emit("requestSignIn");
});
document.addEventListener("request-profile", function (event) {
  self.port.emit("requestProfile");
});
document.addEventListener("set-profile-state", function (event) {
  self.port.emit("setProfileState", event.detail);
});
document.addEventListener("delete-everything", function (event) {
  self.port.emit("deleteEverything");
});
document.addEventListener("content-tour-complete", function (event) {
  self.port.emit("contentTourComplete");
});
document.addEventListener("has-saved-shot", function (event) {
  self.port.emit("hasSavedShot", event.detail);
});
document.addEventListener("request-saved-shot", function (event) {
  self.port.emit("requestSavedShot", event.detail);
});
document.addEventListener("remove-saved-shot", function (event) {
  self.port.emit("removeSavedShot", event.detail);
});
self.port.on("profile", function (profile) {
  var event = document.createEvent("CustomEvent");
  event.initCustomEvent("refresh-profile", true, true, JSON.stringify(profile));
  document.dispatchEvent(event);
});

self.port.on("screenshot", function (image, info) {
  var event = document.createEvent("CustomEvent");
  event.initCustomEvent("got-screenshot", true, true, JSON.stringify({
    image: image,
    info: info
  }));
  document.dispatchEvent(event);
});

self.port.on("checkCapturedResult", function (result) {
  var event = document.createEvent("CustomEvent");
  event.initCustomEvent("check-captured-result", true, true, JSON.stringify(result));
  document.dispatchEvent(event);
});

self.port.on("hasSavedShotResult", function (hasShot) {
  var event = document.createEvent("CustomEvent");
  event.initCustomEvent("has-saved-shot-result", true, true, JSON.stringify(hasShot));
  document.dispatchEvent(event);
});

self.port.on("savedShotData", function (data) {
  var event = document.createEvent("CustomEvent");
  event.initCustomEvent("saved-shot-data", true, true, JSON.stringify(data));
  document.dispatchEvent(event);
});

let readyTimeout = setInterval(function () {
  var readyEvent = document.createEvent("CustomEvent");
  readyEvent.initCustomEvent("helper-ready", true, true, null);
  document.dispatchEvent(readyEvent);
}, 200);

document.addEventListener("page-ready", function () {
  clearTimeout(readyTimeout);
}, false);

// FIXME: not sure if this might mess up an in-content onerror handler, though I suppose
// we just shouldn't create one?
window.onerror = function (message, url, line, col, error) {
  console.error("Error from onerror", url);
  self.port.emit("alertError", {
    name: error.name || "ERROR",
    message: message,
    help: "Uncaught error: " + error + " at " + url + "@" + line + ":" + col
  });
};
<commit_msg>Fixing a FIXME (#1229): remove window.onerror entirely from worker script that is added to pageshot pages.  Sentry should be doing what we need for those errors.<commit_after>/** This worker is attached to all documents served directly by PageShot
    It effectively gives those pages some superpowers

    The real work is generally done in `lib/helperworker.js`
    */

document.addEventListener("request-clipboard", function (event) {
  self.port.emit("requestClipboard", event.detail);
}, false);

document.addEventListener("add-tags", function (event) {
  self.port.emit("addTags", event.detail);
}, false);

document.addEventListener("error", function (event) {
  console.error("Error via helper from", location.href);
  self.port.emit("alertError", event.detail);
}, false);

document.addEventListener("request-sign-up", function (event) {
  self.port.emit("requestSignUp");
});
document.addEventListener("request-sign-in", function (event) {
  self.port.emit("requestSignIn");
});
document.addEventListener("request-profile", function (event) {
  self.port.emit("requestProfile");
});
document.addEventListener("set-profile-state", function (event) {
  self.port.emit("setProfileState", event.detail);
});
document.addEventListener("delete-everything", function (event) {
  self.port.emit("deleteEverything");
});
document.addEventListener("content-tour-complete", function (event) {
  self.port.emit("contentTourComplete");
});
document.addEventListener("has-saved-shot", function (event) {
  self.port.emit("hasSavedShot", event.detail);
});
document.addEventListener("request-saved-shot", function (event) {
  self.port.emit("requestSavedShot", event.detail);
});
document.addEventListener("remove-saved-shot", function (event) {
  self.port.emit("removeSavedShot", event.detail);
});
self.port.on("profile", function (profile) {
  var event = document.createEvent("CustomEvent");
  event.initCustomEvent("refresh-profile", true, true, JSON.stringify(profile));
  document.dispatchEvent(event);
});

self.port.on("screenshot", function (image, info) {
  var event = document.createEvent("CustomEvent");
  event.initCustomEvent("got-screenshot", true, true, JSON.stringify({
    image: image,
    info: info
  }));
  document.dispatchEvent(event);
});

self.port.on("checkCapturedResult", function (result) {
  var event = document.createEvent("CustomEvent");
  event.initCustomEvent("check-captured-result", true, true, JSON.stringify(result));
  document.dispatchEvent(event);
});

self.port.on("hasSavedShotResult", function (hasShot) {
  var event = document.createEvent("CustomEvent");
  event.initCustomEvent("has-saved-shot-result", true, true, JSON.stringify(hasShot));
  document.dispatchEvent(event);
});

self.port.on("savedShotData", function (data) {
  var event = document.createEvent("CustomEvent");
  event.initCustomEvent("saved-shot-data", true, true, JSON.stringify(data));
  document.dispatchEvent(event);
});

let readyTimeout = setInterval(function () {
  var readyEvent = document.createEvent("CustomEvent");
  readyEvent.initCustomEvent("helper-ready", true, true, null);
  document.dispatchEvent(readyEvent);
}, 200);

document.addEventListener("page-ready", function () {
  clearTimeout(readyTimeout);
}, false);
<|endoftext|>


<commit_before>var mag = (function(mag, configs, document, undefined) {

  var ELEMENT_NODE = 1
  var cached = []

  // helper method to detect arrays -- silly javascript
    function _isArray(obj) {
      return Object.prototype.toString.call(obj) === '[object Array]'
    }

  var templates = {}

  // this is the entry point for this module, to fill the dom with data
    function fill(nodeList, data, key, index) {
      var node
      var parent
      var dataIsArray

      // there is nothing to do if there is nothing to fill
      if (!nodeList) return

      // remove all child nodes if there is no data
      if (data == null) data = {
        _text: ''
      }

      // CACHE
      // DIFF
      // CHANGE? then modify only the changes
      // KEYS for indentification

      // nodeList updates as the dom changes, so freeze it in an array
      var elements = nodeListToArray(nodeList)

      dataIsArray = _isArray(data)

      // match the number of nodes to the number of data elements
      if (dataIsArray) {

        if (templates[key + index] && elements.length === 0) {

          templates[key + index].parent.insertAdjacentHTML("beforeend", templates[key + index].node);
          elements = nodeListToArray(templates[key + index].parent.children)

        }

        if (elements.length === 0) {

          //=====================================================================
          // Warning: the following is a case where we could end up here: A page
          // that returns search results as the user is typing. If the results
          // are empty, then the child nodes that display the results will all
          // be removed. Then a subsequent attempt to fill in the search results
          // with data won't have any dom elements to clone.
          //=====================================================================

          // cannot fill empty nodeList with an array of data
          return
        }

        // clone the first node if more nodes are needed
        parent = elements[0].parentNode

        if (!templates[key + index]) {
          templates[key + index] = {
            node: elements[0].cloneNode(true).outerHTML,
            parent: parent
          }
          //remove from dom
          parent.removeChild(elements[0])
        }

        while (elements.length < data.length) {
          if (templates[key + index]) {
            parent.insertAdjacentHTML("beforeend", templates[key + index].node)
            node = parent.lastChild
          } else {
            node = elements[0].cloneNode(true)
          }

          elements.push(node)
          if (parent) parent.appendChild(node)
        }

        // remove the last node until the number of nodes matches the data
        while (elements.length > data.length) {
          node = elements.pop()
          parent = node.parentNode
          if (parent) parent.removeChild(node)
        }
      }

      // now fill each node with the data
      for (var i = 0; i < elements.length; i++) {
        if (dataIsArray) {
          if (elements[i]) {
            fill(elements[i], data[i])
          }
        } else {
          fillNode(elements[i], data)
        }
      }
      return nodeList
    }

    function fillNode(node, data) {
      var attributes,
        attrValue,
        element,
        elements

        // ignore functions
      if (typeof data === 'function') {

        return
      }

      // if the value is a simple property wrap it in the attributes hash
      if (typeof data !== 'object') return fillNode(node, {
        _text: data
      })

      // find all the attributes
      for (var key in data) {
        var value = data[key]

        // null values are treated like empty strings
        if (value === undefined) value = ''

        // anything that starts with an underscore is an attribute
        if (key[0] === '_') {
          // store the properties to set them all at once
          // if (typeof value === 'string' || typeof value === 'number') {
          attributes = attributes || {}
          attributes[key.substr(1)] = value;
          // } else {
          //   throw new Error('Expected a string or number for "' + key +
          //                   '", got: "' + JSON.stringify(value) + '"');
          // }
        }
      }

      // fill in all the attributes
      if (attributes) {
        fillAttributes(node, attributes)
      }

      var index = 0
      // look for non-attribute keys and recurse into those elements
      for (var key in data) {
        var value = data[key]

        // only attributes start with an underscore
        if (key[0] !== '_') {
          elements = matchingElements(node, key);

          // function
          if (typeof value === 'function' && value.type == 'fun') {
            try {
              value = value()
            } catch (e) {}
          }

          // check for key replacement within the element
          //domElement.replaceWithin(node, key, value)

          fill(elements, value, key, index);

          index++
        }
      }
    }

    // freeze the NodeList into a real Array so it can't update as DOM changes
    function nodeListToArray(nodeList) {
      var temp;

      // wrap single item into an array for iteration
      // NOTE: can't use _isArray here, because it could be a NodeList (array-ish)
      if (nodeList.length == null) {
        nodeList = [nodeList];
      }

      // convert array-like object into a real array
      if (!_isArray(nodeList)) {
        temp = [];
        for (var i = 0; i < nodeList.length; i += 1) {
          // Note: occassionaly jsdom returns undefined elements in the NodeList
          if (nodeList[i]) {
            temp.push(nodeList[i]);
          }
        }
        nodeList = temp;
      }

      return nodeList;
    }

    // fill in the attributes on an element (setting text and html first)
    function fillAttributes(node, attributes) {

      // set html after setting text because html overrides text
      setText(node, attributes.text)
      setHtml(node, attributes.html)
      node._events = node._events || []

      // set the rest of the attributes
      for (var attrName in attributes) {

        // skip text and html, they've already been set
        if (attrName === 'text' || attrName === 'html') continue

        // events
        if (attrName.indexOf('on') == 0) {
          if (node._events.indexOf(attrName) !== -1) continue

          node.addEventListener(attrName.substr(2), attributes[attrName])
          node._events.push(attrName)

        } else {

          if (attrName == 'config') {

            // have we been here before?
            // does the element already exist in cache
            // useful to know if this is newly added
            var isNew = true

            // bind
            var callback = function(data, args) {
              return function() {
                return data.apply(data, args)
              }
            };

            configs.push(callback(attributes[attrName], [node, isNew]))
            continue;
          }

          if (attributes[attrName] === null) {
            node.removeAttribute(attrName)
          } else {
            node.setAttribute(attrName, attributes[attrName].toString())
          }
        }
      }
    }

    function setText(node, text) {
      var child
      var children

      // make sure that we have a node and text to insert
      if (!node || text == null) return

      // cache all of the child nodes
      if (!children) {
        children = [];
        for (var i = 0; i < node.childNodes.length; i += 1) {
          child = node.childNodes[i];
          if (child.nodeType === ELEMENT_NODE) {
            children.push(child)
          }
        }
      }

      // remove all of the children
      //WHY?
      while (node.firstChild) {
        node.removeChild(node.firstChild)
      }

      // SELECT|INPUT|TEXTAREA
      // now add the text
      if (node.nodeName.toLowerCase() === 'input') {
        // special case for input elements
        node.setAttribute('value', text.toString());
      } else {
        // create a new text node and stuff in the value
        node.appendChild(node.ownerDocument.createTextNode(text.toString()));
      }

      // reattach all the child nodes
      for (var i = 0; i < children.length; i += 1) {
        node.appendChild(children[i]);
      }
    }

    function setHtml(node, html) {
      if (!node || html == null) return;
      node.innerHTML = html;
      // CAN'T do below since it will append on every new call
      // node.insertAdjacentHTML("afterbegin", html)
    };

  //===========================================================================
  // TODO: Decide if the caching of element matching should be reintroduced.
  // The original implementation cached the lookup of elements, but it seems
  // like this will only be useful in cases where the same DOM elements are
  // getting filled mutliple times -- that seems like it would only happen
  // when someone is running performance benchmarks.
  //===========================================================================

  // find all of the matching elements (breadth-first)

  function matchingElements(node, key, nested) {
    var elements = childElements(node)
    var matches = []
    var keyName = key

    if (!(node.queryCache || {})[key]) {

      node.queryCache = (node.queryCache || {})[key] = [];

      var globalSearch = key[0] === '$'

      if (keyName[0] === '$') keyName = keyName.substr(1)

      // search all child elements for a match
      for (var i = 0; i < elements.length; i += 1) {
        if (elementMatcher(elements[i], keyName)) {
          matches.push(elements[i]);
        }
      }

      // if there is no match, recursively search the childNodes
      if (!matches.length || globalSearch) {
        for (var i = 0; i < elements.length; i++) {
          // NOTE: pass in a flag to prevent recursive calls from logging
          matches = matches.concat(matchingElements(elements[i], key, true))
          if (matches.length && !globalSearch) break
        }
      }

      if (!nested && !matches.length) log('FILL - Warning: no matches found for "' + key + '"');

      // return matches
      node.queryCache[key] = matches
    }
    return node.queryCache[key];
  }

  // return just the child nodes that are elements
  function childElements(node) {
    var children = node.childNodes
    var elements = []

    for (var i = 0; i < children.length; i += 1) {
      if (children[i].nodeType === ELEMENT_NODE) {
        elements.push(children[i])
      }
    }

    return elements
  }

  // match elements on tag, id, name, class name, data-bind, etc.
  function elementMatcher(element, key) {
    var paddedClass = ' ' + element.className + ' ';

    return (
      element.id === key ||
      paddedClass.indexOf(' ' + key + ' ') > -1 ||
      element.name === key ||
      element.nodeName.toLowerCase() === key.toLowerCase() ||
      element.getAttribute('data-bind') === key
    );
  }

  // attach fill to current context (in the browser this will be window.fill)
  // this.fill = fill;
  // this.configs = configs

  // the user can inject a logger function to get some feedback from fill
  function log(methodName) {
    return function() {
      if (typeof mag.logger === 'object') {
        mag.logger[methodName || 'log'].apply(mag.logger, arguments)
      }
    }
  }

  mag.fill = {
    fill: fill,
    log: log,
    configs: configs
  }
  return mag
}(window.mag || {}, [], document))
<commit_msg>Remove first element in array issue<commit_after>var mag = (function(mag, configs, document, undefined) {

  var ELEMENT_NODE = 1
  var cached = []

  // helper method to detect arrays -- silly javascript
    function _isArray(obj) {
      return Object.prototype.toString.call(obj) === '[object Array]'
    }

  var templates = {}

  // this is the entry point for this module, to fill the dom with data
    function fill(nodeList, data, key, index) {
      var node
      var parent
      var dataIsArray

      // there is nothing to do if there is nothing to fill
      if (!nodeList) return

      // remove all child nodes if there is no data
      if (data == null) data = {
        _text: ''
      }

      // CACHE
      // DIFF
      // CHANGE? then modify only the changes
      // KEYS for indentification

      // nodeList updates as the dom changes, so freeze it in an array
      var elements = nodeListToArray(nodeList)

      dataIsArray = _isArray(data)

      // match the number of nodes to the number of data elements
      if (dataIsArray) {

        if (templates[key + index] && elements.length === 0) {

          templates[key + index].parent.insertAdjacentHTML("beforeend", templates[key + index].node);
          elements = nodeListToArray(templates[key + index].parent.children)

        }

        if (elements.length === 0) {

          //=====================================================================
          // Warning: the following is a case where we could end up here: A page
          // that returns search results as the user is typing. If the results
          // are empty, then the child nodes that display the results will all
          // be removed. Then a subsequent attempt to fill in the search results
          // with data won't have any dom elements to clone.
          //=====================================================================

          // cannot fill empty nodeList with an array of data
          return
        }

        // clone the first node if more nodes are needed
        parent = elements[0].parentNode

        if (!templates[key + index]) {
          templates[key + index] = {
            node: elements[0].cloneNode(true).outerHTML,
            parent: parent
          }
          //remove from dom
          //parent.removeChild(elements[0])
        }

        while (elements.length < data.length) {
          if (templates[key + index]) {
            parent.insertAdjacentHTML("beforeend", templates[key + index].node)
            node = parent.lastChild
          } else {
            node = elements[0].cloneNode(true)
          }

          elements.push(node)
          if (parent) parent.appendChild(node)
        }

        // remove the last node until the number of nodes matches the data
        while (elements.length > data.length) {
          node = elements.pop()
          parent = node.parentNode
          if (parent) parent.removeChild(node)
        }
      }

      // now fill each node with the data
      for (var i = 0; i < elements.length; i++) {
        if (dataIsArray) {
          if (elements[i]) {
            fill(elements[i], data[i])
          }
        } else {
          fillNode(elements[i], data)
        }
      }
      return nodeList
    }

    function fillNode(node, data) {
      var attributes,
        attrValue,
        element,
        elements

        // ignore functions
      if (typeof data === 'function') {

        return
      }

      // if the value is a simple property wrap it in the attributes hash
      if (typeof data !== 'object') return fillNode(node, {
        _text: data
      })

      // find all the attributes
      for (var key in data) {
        var value = data[key]

        // null values are treated like empty strings
        if (value === undefined) value = ''

        // anything that starts with an underscore is an attribute
        if (key[0] === '_') {
          // store the properties to set them all at once
          // if (typeof value === 'string' || typeof value === 'number') {
          attributes = attributes || {}
          attributes[key.substr(1)] = value;
          // } else {
          //   throw new Error('Expected a string or number for "' + key +
          //                   '", got: "' + JSON.stringify(value) + '"');
          // }
        }
      }

      // fill in all the attributes
      if (attributes) {
        fillAttributes(node, attributes)
      }

      var index = 0
      // look for non-attribute keys and recurse into those elements
      for (var key in data) {
        var value = data[key]

        // only attributes start with an underscore
        if (key[0] !== '_') {
          elements = matchingElements(node, key);

          // function
          if (typeof value === 'function' && value.type == 'fun') {
            try {
              value = value()
            } catch (e) {}
          }

          // check for key replacement within the element
          //domElement.replaceWithin(node, key, value)

          fill(elements, value, key, index);

          index++
        }
      }
    }

    // freeze the NodeList into a real Array so it can't update as DOM changes
    function nodeListToArray(nodeList) {
      var temp;

      // wrap single item into an array for iteration
      // NOTE: can't use _isArray here, because it could be a NodeList (array-ish)
      if (nodeList.length == null) {
        nodeList = [nodeList];
      }

      // convert array-like object into a real array
      if (!_isArray(nodeList)) {
        temp = [];
        for (var i = 0; i < nodeList.length; i += 1) {
          // Note: occassionaly jsdom returns undefined elements in the NodeList
          if (nodeList[i]) {
            temp.push(nodeList[i]);
          }
        }
        nodeList = temp;
      }

      return nodeList;
    }

    // fill in the attributes on an element (setting text and html first)
    function fillAttributes(node, attributes) {

      // set html after setting text because html overrides text
      setText(node, attributes.text)
      setHtml(node, attributes.html)
      node._events = node._events || []

      // set the rest of the attributes
      for (var attrName in attributes) {

        // skip text and html, they've already been set
        if (attrName === 'text' || attrName === 'html') continue

        // events
        if (attrName.indexOf('on') == 0) {
          if (node._events.indexOf(attrName) !== -1) continue

          node.addEventListener(attrName.substr(2), attributes[attrName])
          node._events.push(attrName)

        } else {

          if (attrName == 'config') {

            // have we been here before?
            // does the element already exist in cache
            // useful to know if this is newly added
            var isNew = true

            // bind
            var callback = function(data, args) {
              return function() {
                return data.apply(data, args)
              }
            };

            configs.push(callback(attributes[attrName], [node, isNew]))
            continue;
          }

          if (attributes[attrName] === null) {
            node.removeAttribute(attrName)
          } else {
            node.setAttribute(attrName, attributes[attrName].toString())
          }
        }
      }
    }

    function setText(node, text) {
      var child
      var children

      // make sure that we have a node and text to insert
      if (!node || text == null) return

      // cache all of the child nodes
      if (!children) {
        children = [];
        for (var i = 0; i < node.childNodes.length; i += 1) {
          child = node.childNodes[i];
          if (child.nodeType === ELEMENT_NODE) {
            children.push(child)
          }
        }
      }

      // remove all of the children
      //WHY?
      while (node.firstChild) {
        node.removeChild(node.firstChild)
      }

      // SELECT|INPUT|TEXTAREA
      // now add the text
      if (node.nodeName.toLowerCase() === 'input') {
        // special case for input elements
        node.setAttribute('value', text.toString());
      } else {
        // create a new text node and stuff in the value
        node.appendChild(node.ownerDocument.createTextNode(text.toString()));
      }

      // reattach all the child nodes
      for (var i = 0; i < children.length; i += 1) {
        node.appendChild(children[i]);
      }
    }

    function setHtml(node, html) {
      if (!node || html == null) return;
      node.innerHTML = html;
      // CAN'T do below since it will append on every new call
      // node.insertAdjacentHTML("afterbegin", html)
    };

  //===========================================================================
  // TODO: Decide if the caching of element matching should be reintroduced.
  // The original implementation cached the lookup of elements, but it seems
  // like this will only be useful in cases where the same DOM elements are
  // getting filled mutliple times -- that seems like it would only happen
  // when someone is running performance benchmarks.
  //===========================================================================

  // find all of the matching elements (breadth-first)

  function matchingElements(node, key, nested) {
    var elements = childElements(node)
    var matches = []
    var keyName = key

    if (!(node.queryCache || {})[key]) {

      node.queryCache = (node.queryCache || {})[key] = [];

      var globalSearch = key[0] === '$'

      if (keyName[0] === '$') keyName = keyName.substr(1)

      // search all child elements for a match
      for (var i = 0; i < elements.length; i += 1) {
        if (elementMatcher(elements[i], keyName)) {
          matches.push(elements[i]);
        }
      }

      // if there is no match, recursively search the childNodes
      if (!matches.length || globalSearch) {
        for (var i = 0; i < elements.length; i++) {
          // NOTE: pass in a flag to prevent recursive calls from logging
          matches = matches.concat(matchingElements(elements[i], key, true))
          if (matches.length && !globalSearch) break
        }
      }

      if (!nested && !matches.length) log('FILL - Warning: no matches found for "' + key + '"');

      // return matches
      node.queryCache[key] = matches
    }
    return node.queryCache[key];
  }

  // return just the child nodes that are elements
  function childElements(node) {
    var children = node.childNodes
    var elements = []

    for (var i = 0; i < children.length; i += 1) {
      if (children[i].nodeType === ELEMENT_NODE) {
        elements.push(children[i])
      }
    }

    return elements
  }

  // match elements on tag, id, name, class name, data-bind, etc.
  function elementMatcher(element, key) {
    var paddedClass = ' ' + element.className + ' ';

    return (
      element.id === key ||
      paddedClass.indexOf(' ' + key + ' ') > -1 ||
      element.name === key ||
      element.nodeName.toLowerCase() === key.toLowerCase() ||
      element.getAttribute('data-bind') === key
    );
  }

  // attach fill to current context (in the browser this will be window.fill)
  // this.fill = fill;
  // this.configs = configs

  // the user can inject a logger function to get some feedback from fill
  function log(methodName) {
    return function() {
      if (typeof mag.logger === 'object') {
        mag.logger[methodName || 'log'].apply(mag.logger, arguments)
      }
    }
  }

  mag.fill = {
    fill: fill,
    log: log,
    configs: configs
  }
  return mag
}(window.mag || {}, [], document))
<|endoftext|>