<commit_before>/* eslint-env node */

"use strict";

var XPathEvaluator = require("xpath-evaluator");

var ReactAttribute = require("./react_attribute");

var ReactText = require("./react_text");

function ReactElement (nativeNode, parent, nChild) {
  this.nativeNode = nativeNode;
  this.parent = parent;
  this.nChild = nChild;
}

ReactElement.prototype.getId = function () {
  return this.getParent().getId() + "." + this.nChild;
};

ReactElement.prototype.isEqual = function (node) {
  return this.getId() === node.getId();
};

ReactElement.prototype.getNativeNode = function () {
  return this.nativeNode;
};

ReactElement.prototype.asString = function () {
  var textContent = "";

  this.getChildNodes().forEach(function (child) {
    if (child.getNodeType() === XPathEvaluator.Node.ELEMENT_NODE ||
        child.getNodeType() === XPathEvaluator.Node.TEXT_NODE) {
      textContent = textContent + child.asString();
    }
  });

  return textContent;
};

ReactElement.prototype.asNumber = function () {
  return +this.asString();
};

ReactElement.prototype.getNodeType = function () {
  return XPathEvaluator.Node.ELEMENT_NODE;
};

ReactElement.prototype.getParent = function () {
  return this.parent;
};

ReactElement.prototype.getChildNodes = function () {
  if (!this.nativeNode.props || !this.nativeNode.props.children) {
    return [];
  }

  if (!Array.isArray(this.nativeNode.props.children)) {
    this.nativeNode.props.children = [this.nativeNode.props.children];
  }

  var children = [];

  for (var i = 0; i < this.nativeNode.props.children.length; i++) {
    if (this.nativeNode.props.children[i]) {
      if (typeof this.nativeNode.props.children[i] === "string") {
        children.push(new ReactText(this.nativeNode.props.children[i], this, i));
      } else {
        children.push(new ReactElement(this.nativeNode.props.children[i], this, i));
      }
    }
  }

  return children;
};

ReactElement.prototype.getFollowingSiblings = function () {
  var followingSiblings = [];

  var siblings = this.getParent().getChildNodes();

  var thisSiblingIndex = siblings.findIndex(function (sibling) {
    return sibling.isEqual(this);
  }.bind(this));

  for (var i = thisSiblingIndex + 1; i < siblings.length; i++) {
    followingSiblings.push(siblings[i]);
  }

  return followingSiblings;
};

ReactElement.prototype.getPrecedingSiblings = function () {
  var precedingSiblings = [];

  var siblings = this.getParent().getChildNodes();

  var thisSiblingIndex = siblings.findIndex(function (sibling) {
    return sibling.isEqual(this);
  }.bind(this));

  for (var i = 0; i < thisSiblingIndex; i++) {
    precedingSiblings.push(siblings[i]);
  }

  return precedingSiblings;
};

ReactElement.prototype.getName = function () {
  return this.nativeNode.type;
};

ReactElement.prototype.getAttributes = function () {
  if (!this.nativeNode.props) {
    return [];
  }

  var attributes = [];

  var i = 0;

  for (var attribute in this.nativeNode.props) {
    if (this.nativeNode.props.hasOwnProperty(attribute) && attribute !== "children") {
      attributes.push(new ReactAttribute(attribute, this.nativeNode.props[attribute], this, i++));
    }
  }

  return attributes;
};

ReactElement.prototype.getOwnerDocument = function () {
  if (this.getParent().getNodeType() === XPathEvaluator.Node.DOCUMENT_NODE) {
    return this.getParent();
  } else {
    return this.getParent().getOwnerDocument();
  }
};

/* eslint-disable no-underscore-dangle */
ReactElement.prototype._getElementById = function (id) {
  if (this.nativeNode.props && this.nativeNode.props.id === id) {
    return this;
  } else {
    var children = this.getChildNodes();

    for (var i = 0; i < children.length; i++) {
      if (children[i].getNodeType() === XPathEvaluator.Node.ELEMENT_NODE) {
        var elementWithId = children[i]._getElementById(id);

        if (elementWithId) {
          return elementWithId;
        }
      }
    }
  }
};
/* eslint-enable no-underscore-dangle */

ReactElement.prototype.toString = function () {
  var name = this.getName();

  if (this.nativeNode.props) {
    if (this.nativeNode.props.className) {
      name = name + "." + this.nativeNode.props.className.split(/\s+/g).join(".");
    }

    if (this.nativeNode.props.id) {
      name = name + "#" + this.nativeNode.props.id;
    }
  }

  return "Node<" + name + ">";
};

module.exports = ReactElement;
<commit_msg>Avoid modifying react elements<commit_after>/* eslint-env node */

"use strict";

var XPathEvaluator = require("xpath-evaluator");

var ReactAttribute = require("./react_attribute");

var ReactText = require("./react_text");

function ReactElement (nativeNode, parent, nChild) {
  this.nativeNode = nativeNode;
  this.parent = parent;
  this.nChild = nChild;
}

ReactElement.prototype.getId = function () {
  return this.getParent().getId() + "." + this.nChild;
};

ReactElement.prototype.isEqual = function (node) {
  return this.getId() === node.getId();
};

ReactElement.prototype.getNativeNode = function () {
  return this.nativeNode;
};

ReactElement.prototype.asString = function () {
  var textContent = "";

  this.getChildNodes().forEach(function (child) {
    if (child.getNodeType() === XPathEvaluator.Node.ELEMENT_NODE ||
        child.getNodeType() === XPathEvaluator.Node.TEXT_NODE) {
      textContent = textContent + child.asString();
    }
  });

  return textContent;
};

ReactElement.prototype.asNumber = function () {
  return +this.asString();
};

ReactElement.prototype.getNodeType = function () {
  return XPathEvaluator.Node.ELEMENT_NODE;
};

ReactElement.prototype.getParent = function () {
  return this.parent;
};

ReactElement.prototype.getChildNodes = function () {
  if (!this.nativeNode.props || !this.nativeNode.props.children) {
    return [];
  }

  var children = [];

  var addChild = function (child, i) {
    if (child) {
      if (typeof child === "string") {
        children.push(new ReactText(child, this, i));
      } else {
        children.push(new ReactElement(child, this, i));
      }
    }
  }.bind(this);

  if (Array.isArray(this.nativeNode.props.children)) {
    for (var i = 0; i < this.nativeNode.props.children.length; i++) {
      addChild(this.nativeNode.props.children[i], i);
    }
  } else {
    addChild(this.nativeNode.props.children, 0);
  }

  return children;
};

ReactElement.prototype.getFollowingSiblings = function () {
  var followingSiblings = [];

  var siblings = this.getParent().getChildNodes();

  var thisSiblingIndex = siblings.findIndex(function (sibling) {
    return sibling.isEqual(this);
  }.bind(this));

  for (var i = thisSiblingIndex + 1; i < siblings.length; i++) {
    followingSiblings.push(siblings[i]);
  }

  return followingSiblings;
};

ReactElement.prototype.getPrecedingSiblings = function () {
  var precedingSiblings = [];

  var siblings = this.getParent().getChildNodes();

  var thisSiblingIndex = siblings.findIndex(function (sibling) {
    return sibling.isEqual(this);
  }.bind(this));

  for (var i = 0; i < thisSiblingIndex; i++) {
    precedingSiblings.push(siblings[i]);
  }

  return precedingSiblings;
};

ReactElement.prototype.getName = function () {
  return this.nativeNode.type;
};

ReactElement.prototype.getAttributes = function () {
  if (!this.nativeNode.props) {
    return [];
  }

  var attributes = [];

  var i = 0;

  for (var attribute in this.nativeNode.props) {
    if (this.nativeNode.props.hasOwnProperty(attribute) && attribute !== "children") {
      attributes.push(new ReactAttribute(attribute, this.nativeNode.props[attribute], this, i++));
    }
  }

  return attributes;
};

ReactElement.prototype.getOwnerDocument = function () {
  if (this.getParent().getNodeType() === XPathEvaluator.Node.DOCUMENT_NODE) {
    return this.getParent();
  } else {
    return this.getParent().getOwnerDocument();
  }
};

/* eslint-disable no-underscore-dangle */
ReactElement.prototype._getElementById = function (id) {
  if (this.nativeNode.props && this.nativeNode.props.id === id) {
    return this;
  } else {
    var children = this.getChildNodes();

    for (var i = 0; i < children.length; i++) {
      if (children[i].getNodeType() === XPathEvaluator.Node.ELEMENT_NODE) {
        var elementWithId = children[i]._getElementById(id);

        if (elementWithId) {
          return elementWithId;
        }
      }
    }
  }
};
/* eslint-enable no-underscore-dangle */

ReactElement.prototype.toString = function () {
  var name = this.getName();

  if (this.nativeNode.props) {
    if (this.nativeNode.props.className) {
      name = name + "." + this.nativeNode.props.className.split(/\s+/g).join(".");
    }

    if (this.nativeNode.props.id) {
      name = name + "#" + this.nativeNode.props.id;
    }
  }

  return "Node<" + name + ">";
};

module.exports = ReactElement;
<|endoftext|>


<commit_before>//get the iwc.Client class def.
/*
iwc = iwc || {};
iwc.Client = iwc.Client || {};

/**
 * Add a function to set the compnent name of the iwc.Client class.

 * This component name is for filtering incoming intent at the iwc.Client. The intent can be further processed
 * only when the intent.component attribute matches the component name of the iwc.Client or the intent.component is an empty string(pseudo broadcast).
 * @param componentName The component name
 */
/*
iwc.Client.prototype.setComponentName = function(componentName){
	this._componentName = componentName;
};
*/

DUIClient = function(){
	//in role framework the parent div of the widget ifr is IDed as "widget-{widgetId}-body" sth. like this
	var _widgetId = parent.document.getElementById(self.frameElement.id).parentNode.id.split("-")[1];
	var that = this;
	var _iwcClient = new iwc.Client(["*"]);
	_iwcClient._componentName = "duiclient-"+_widgetId;

	this.externalCallback = function(intent){};

/**
 * The target function when the intent is for updating widget state request
 */
	this._onUpdateState = function(intent){
		var isForMigration = intent.extras.isForMigration;
		if (isForMigration)
			this.finishMigration(intent);
		else
			this.updateState(intent);
	};

	/**
	 * The target function when the intent is for getting the current widget state.

	 * The intent.extras object here is always a Json object.
	 */
	this._onGetWidgetState = function(intent){
		var target = null;
		var forMigration = false;
		if (intent.extras.target != null){
			target = intent.extras.target;
			forMigration = true;
		}
		var states = this.getWidgetState(forMigration);

		var resIntent = {};
		if (forMigration)
			resIntent = {
					"action": "DUI_WS_MIG",
					"categories": ["DUI"],
					"component": "duimanager",
					"data":"",
					"dataType":"",
					"extras":{"target": target, "widgetId": _widgetId, "widgetStates": states}
			};
		else
			resIntent = {
				"action": "DUI_WS",
				"categories": ["DUI"],
				"component": intent.sender,
				"data":"",
				"dataType":"",
				"extras":{"widgetId": _widgetId, "widgetStates": states}
			};

		_iwcClient.publish(resIntent);
	};

	/**
	 * The target function when the intent is to inform a change in the scope of the application
	 */
	this._onAppStateChange = function(intent){
		this.changeWithApp(intent);
	};

	/**
	 * The target function when the intent is to inform a migration of this widget is waiting to be taken place
	 */
	this._prepareMigration = function(intent){
		console.log("do sth before the widget is removed");
		this.prepareMigration();
	};

	this._logOff = function(intent){
		var states = this.getWidgetState(false);
		resIntent = {
			"action": "DUI_WS_LOGOFF",
			"categories": ["DUI"],
			"component": "duimanager",
			"data":"",
			"dataType":"",
			"extras":{"widgetId": _widgetId, "widgetStates": states}
		};

		_iwcClient.publish(resIntent);
	};

	/**
	 * The intent dispatcher and the callback function connected to the private field of iwc.Client.onIntent.

	 * This function is called once an intent is received by the iwc.Client and passed the first level filter of the iwc.Client.

	 * @param intent The incoming intent. Technically all intents will come, the filter of the iwc.Client class is weak...
	 */
	var _iwcCallback = function(intent){
		that.externalCallback(intent);
		//does not accept global intents(global intents are processed by normal iwc.Client, normal iwc.Proxy and DUI manager)
		//does not accept intents that are not categorized as "DUI"
		if ((typeof intent.flags != "undefined" && intent.flags.indexOf("PUBLISH_GLOBAL")!=-1)
				|| typeof intent.categories == "undefined" || intent.categories.indexOf("DUI") == -1)
			return;
		//then does not accept intents for other widgets
		//if the widget id is undefined here, this is an DUI intent from the DUI manager for all involved widget, e.g. application state changed
		var action = intent.action;
		if (typeof intent.extras.widgetId != "undefined" && intent.extras.widgetId == _widgetId){
			if (action == "DUI_UPDATE_STATE"){
				that._onUpdateState(intent);
				return;
			}
			if (action == "DUI_GET_WS"){
				that._onGetWidgetState(intent);
				return;
			}
			if (action == "DUI_PRE_MIG"){
				that._prepareMigration(intent);
				return;
			}
		}else if (typeof intent.extras.widgetId == "undefined"){
			if (action == "DUI_LOG_OFF"){
				that._logOff(intent);
				return;
			}
			if (action == "DUI_APP_CHANGE"){
				that._onAppStateChange(intent);
				return;
			}
			if (action == "DUI_REG_CLIENT"){
				that.initOK();
				return;
			}
			if (action == "DUI_AS"){
				that.onAppState(intent.extras.appStates);
			}
		}
	};

	_iwcClient.connect(_iwcCallback);

	//remember to bind(this) the function when override

	/**
	 * The function is called when the dui manager wants the widget states.

	 * Notice: avoid putting complex data and data structure to the state value, the browser and Java JSON encoder and parser might cause inconsistent input and output.
	 * @param isForMigration A boolean. True if special state for migration is needed otherwise not.
	 * @returns an object containing the widget states, e.g. {"selectIndex":1, "phaseNum":2, "textinput":"iamatextvalueinatextinput"}
	 */
	this.getWidgetState = function(isForMigration){
		console.log("the widget collects it is state and return, overwrite it");
		var states = {};
		return states;
	};

	/**
	 * The function is called when there detected a application state change at the dui manager and the manager informs the widget about the change.

	 * Override this function to apply changes to the widget according to the valuable application state changes.

	 * @param intent intent The infos are in intent.extras object e.g. intent.extras = {"oldStates":{}, "newStates":{"statename":value, "state2":value2}}. the property 'oldStates' can be null if the space has not set app state ever before.
	 */
	this.changeWithApp = function(intent){
		//sample
		var oldStates = intent.extras.oldStates;
		var newStates = intent.extras.newStates;
		console.log(oldStates);
		console.log(newStates);
		console.log("the widget may need to change something following the whole app");
	};

	/**
	 * The function is called right before a migration for this widget and the widget state is already saved to the server in previous migration phases.

	 * And it is the last chance to perform any moves before the widget is removed from current web page.

	 * Override this method to perform state update for each different widget.

	 * AND DO REMEMBER TO CALL {@link DUIClient#prepareMigDone} AT THE END OF THIS FUNCTION!
	 */
	this.prepareMigration = function(){
		//e.g. ..... just a joke....
		/*
		if (confirm("you sure to sign out?..."))
			parent.location = parent.location.protocol + "//" + parent.location.host + "/:authentication?return=&action=signout";
		console.log("the migration is at hand, the widget may need to do sth special before it is removed from the role widget container e.g. disconnect from the lasServer etc.");
		*/
		this.prepareMigDone();
	};

	/**
	 * The function is called when the dui manager asks the widget to update its states.

	 * Compared to the function DUIClient.finishMigration(), this is a typical normal state update for active widget on presence.

	 * This method will be called as a callback for DUIClient#requireWidgetState(); or DUIClient#initOK() when it is not a migration.
	 * Override this method to perform state update for each different widget.
	 * @param intent The Intent object that contains infos of required widget states, the infos are in intent.extras.widgetStates e.g. {"state1":value1,"state2":value2}.
	 * The object might contain appStates as well if there is any application state, get it in intent.extras.appStates e.g. {"appstate1":value1,"appstate2":value2}.
	 */
	this.updateState = function(intent){
		var states = {};
		states = intent.extras.widgetStates;
		var appStates = intent.extras.appStates;
		console.log(states);
		if (typeof appStates != "undefined")
			console.log(appStates);
		console.log("update the widget state, widget need to overwrite it");
	};

	/**
	 * The function is called to finish the Migration and update the widget state.

	 * Compared to the method DUIClient.updateState(), this method is a special widget state update for the widget that has just migrated.

	 * Override this method to perform finishing moves for each different widget.
	 * @param intent The Intent object that contains infos to complete the migration, the infos are in intent.extras.states e.g. {"state1":value1, "state2":value2}.
	 *  The object might contain appStates as well if there is any application state, get it in intent.extras.appStates e.g. {"appstate1":value1,"appstate2":value2}.
	 */
	this.finishMigration = function(intent){
		var states = {};
		states = intent.extras.widgetStates;
		var appStates = intent.extras.appStates;
		console.log(states);
		if (typeof appStates != "undefined")
			console.log(appStates);
		console.log("the migration is done, the widget may need to perform special inits before update the widget state e.g. login to the lasServer again.");
	};

	/**
	 * The function to signal the dui manager that the preparation for the migration is ready on this widget.

	 * This function should be called at the end of the overwritten function {@link DUIClient#prepareMigration}

	 * Do not override this method unless there is really an unstoppable reason.
	 */
	this.prepareMigDone = function(){
		//prepared and send OK response to DUIMgr
		var intent = {
				"component": "duimanager",
				"categories": ["DUI"],
				"action": "DUI_PRE_MIG_OK",
				"data": "",
				"dataType": "",
				"extras": {"widgetId": _widgetId}
			};
		_iwcClient.publish(intent);
	};

	/**
	 * The function to call the DUI manager to save the widget state on the server.

	 * Do not override this method unless there is really an unstoppable reason.
	 * @param states An array of widget state object {"stateName": stateValue}
	 */
	this.saveWidgetState = function(){
		var states = this.getWidgetState(false);
		var intent = {
			"action": "DUI_SAVE_WS",
			"categories": ["DUI"],
			"component": "duimanager",// the overwritten dui manager from the iwc.Proxy should have the _componentName set to "duimanager"
			"data":"",
			"dataType":"",
			"extras":{"widgetStates":states, "widgetId": _widgetId}
		};
		_iwcClient.publish(intent);
	};

	/**
	 * An open interface to send any intent
	 */
	this.sendIntent = function(intent){
		//or to send the intent to "duimanager"
		_iwcClient.publish(intent);
	};

	/**
	 * This function asks the framework for the states stored on the server.
	 * Do not override it.
	 */
	this.requireWidgetState = function(){
		var intent = {
				"action": "DUI_REQ_WS",
				"categories": ["DUI"],
				"component": "duimanager",// the overwritten dui manager from the iwc.Proxy should have the _componentName set to "duimanager"
				"data":"",
				"dataType":"",
				"extras":{"widgetId": _widgetId}
		};
		_iwcClient.publish(intent);
	};

	/**
	 * Store the global app state
	 * @param states the app state to be stored e.g. {"state1":value1, "state2":value2}
	 */
	this.setAppState = function(states){
		var intent = {
				"action": "DUI_SET_AS",
				"categories": ["DUI"],
				"component": "duimanager",// the overwritten dui manager from the iwc.Proxy should have the _componentName set to "duimanager"
				"data":"",
				"dataType":"",
				"extras":{"states": states}
		};
		_iwcClient.publish(intent);
	};

	/**
	 * Ask the dui manager for the app state.
	 */
	this.getAppState = function(){
		var intent = {
				"action": "DUI_GET_AS",
				"categories": ["DUI"],
				"component": "duimanager",// the overwritten dui manager from the iwc.Proxy should have the _componentName set to "duimanager"
				"data":"",
				"dataType":"",
		};
		_iwcClient.publish(intent);
	};

	/**
	 * Override this function to do something when the requested app state comes.
	 * @param appStates the json format of the app state:{"name1": value1, "name2": value2};
	 */
	this.onAppState = function(appStates){};

	/**
	 * call this function to register the duiclient to duimanager after all things are OK
	 */
	this.initOK = function(){
		var okIntent = {
			"action": "DUI_CLIENT_OK",
			"categories": ["DUI"],
			"component": "duimanager",// the overwritten dui manager from the iwc.Proxy should have the _componentName set to "duimanager"
			"data":"",
			"dataType":"",
			"extras":{"widgetId": _widgetId}
		};

		_iwcClient.publish(okIntent);
	};

	/**
	 * publish the intent in the domain of the user only
	 */
	this.publishToUser = function(intent){
		var wrap = {
				"action": "DUI_PUB_USER",
				"categories": ["DUI"],
				"component": "duimanager",
				"data": JSON.stringify(intent),
				"dataType": "application/json",
				"extras": {}
		};
		_iwcClient.publish(intent);
		_iwcClient.publish(wrap);
	};

	/**
	 * register the call back function of the widget to the DUI client.
	 */
	this.connect = function(callback){
		this.externalCallback = callback;
	};
};

// reminder to myself:.... the callback funcs injected into this DUIClient need to bind()
<commit_msg>changed duiClient<commit_after>//get the iwc.Client class def.
/*
iwc = iwc || {};
iwc.Client = iwc.Client || {};

/**
 * Add a function to set the compnent name of the iwc.Client class.

 * This component name is for filtering incoming intent at the iwc.Client. The intent can be further processed
 * only when the intent.component attribute matches the component name of the iwc.Client or the intent.component is an empty string(pseudo broadcast).
 * @param componentName The component name
 */
/*
iwc.Client.prototype.setComponentName = function(componentName){
	this._componentName = componentName;
};
*/

DUIClient = function(){
	//in role framework the parent div of the widget ifr is IDed as "widget-{widgetId}-body" sth. like this
	var _widgetId = parent.document.getElementById(self.frameElement.id).parentNode.id.split("-")[1];
	var that = this;
	var _iwcClient = new iwc.Client(["*"]);
	_iwcClient._componentName = "duiclient-"+_widgetId;

	this.externalCallback = function(intent){};

/**
 * The target function when the intent is for updating widget state request
 */
	this._onUpdateState = function(intent){
		var isForMigration = intent.extras.isForMigration;
		if (isForMigration)
			this.finishMigration(intent);
		else
			this.updateState(intent);
	};

        this.getIwcClient = function(){
          return _iwcClient;
        }
	/**
	 * The target function when the intent is for getting the current widget state.

	 * The intent.extras object here is always a Json object.
	 */
	this._onGetWidgetState = function(intent){
		var target = null;
		var forMigration = false;
		if (intent.extras.target != null){
			target = intent.extras.target;
			forMigration = true;
		}
		var states = this.getWidgetState(forMigration);

		var resIntent = {};
		if (forMigration)
			resIntent = {
					"action": "DUI_WS_MIG",
					"categories": ["DUI"],
					"component": "duimanager",
					"data":"",
					"dataType":"",
					"extras":{"target": target, "widgetId": _widgetId, "widgetStates": states}
			};
		else
			resIntent = {
				"action": "DUI_WS",
				"categories": ["DUI"],
				"component": intent.sender,
				"data":"",
				"dataType":"",
				"extras":{"widgetId": _widgetId, "widgetStates": states}
			};

		_iwcClient.publish(resIntent);
	};

	/**
	 * The target function when the intent is to inform a change in the scope of the application
	 */
	this._onAppStateChange = function(intent){
		this.changeWithApp(intent);
	};

	/**
	 * The target function when the intent is to inform a migration of this widget is waiting to be taken place
	 */
	this._prepareMigration = function(intent){
		console.log("do sth before the widget is removed");
		this.prepareMigration();
	};

	this._logOff = function(intent){
		var states = this.getWidgetState(false);
		resIntent = {
			"action": "DUI_WS_LOGOFF",
			"categories": ["DUI"],
			"component": "duimanager",
			"data":"",
			"dataType":"",
			"extras":{"widgetId": _widgetId, "widgetStates": states}
		};

		_iwcClient.publish(resIntent);
	};

	/**
	 * The intent dispatcher and the callback function connected to the private field of iwc.Client.onIntent.

	 * This function is called once an intent is received by the iwc.Client and passed the first level filter of the iwc.Client.

	 * @param intent The incoming intent. Technically all intents will come, the filter of the iwc.Client class is weak...
	 */
	var _iwcCallback = function(intent){
		that.externalCallback(intent);
		//does not accept global intents(global intents are processed by normal iwc.Client, normal iwc.Proxy and DUI manager)
		//does not accept intents that are not categorized as "DUI"
		if ((typeof intent.flags != "undefined" && intent.flags.indexOf("PUBLISH_GLOBAL")!=-1)
				|| typeof intent.categories == "undefined" || intent.categories.indexOf("DUI") == -1)
			return;
		//then does not accept intents for other widgets
		//if the widget id is undefined here, this is an DUI intent from the DUI manager for all involved widget, e.g. application state changed
		var action = intent.action;
		if (typeof intent.extras.widgetId != "undefined" && intent.extras.widgetId == _widgetId){
			if (action == "DUI_UPDATE_STATE"){
				that._onUpdateState(intent);
				return;
			}
			if (action == "DUI_GET_WS"){
				that._onGetWidgetState(intent);
				return;
			}
			if (action == "DUI_PRE_MIG"){
				that._prepareMigration(intent);
				return;
			}
		}else if (typeof intent.extras.widgetId == "undefined"){
			if (action == "DUI_LOG_OFF"){
				that._logOff(intent);
				return;
			}
			if (action == "DUI_APP_CHANGE"){
				that._onAppStateChange(intent);
				return;
			}
			if (action == "DUI_REG_CLIENT"){
				that.initOK();
				return;
			}
			if (action == "DUI_AS"){
				that.onAppState(intent.extras.appStates);
			}
		}
	};

	_iwcClient.connect(_iwcCallback);

	//remember to bind(this) the function when override

	/**
	 * The function is called when the dui manager wants the widget states.

	 * Notice: avoid putting complex data and data structure to the state value, the browser and Java JSON encoder and parser might cause inconsistent input and output.
	 * @param isForMigration A boolean. True if special state for migration is needed otherwise not.
	 * @returns an object containing the widget states, e.g. {"selectIndex":1, "phaseNum":2, "textinput":"iamatextvalueinatextinput"}
	 */
	this.getWidgetState = function(isForMigration){
		console.log("the widget collects it is state and return, overwrite it");
		var states = {};
		return states;
	};

	/**
	 * The function is called when there detected a application state change at the dui manager and the manager informs the widget about the change.

	 * Override this function to apply changes to the widget according to the valuable application state changes.

	 * @param intent intent The infos are in intent.extras object e.g. intent.extras = {"oldStates":{}, "newStates":{"statename":value, "state2":value2}}. the property 'oldStates' can be null if the space has not set app state ever before.
	 */
	this.changeWithApp = function(intent){
		//sample
		var oldStates = intent.extras.oldStates;
		var newStates = intent.extras.newStates;
		console.log(oldStates);
		console.log(newStates);
		console.log("the widget may need to change something following the whole app");
	};

	/**
	 * The function is called right before a migration for this widget and the widget state is already saved to the server in previous migration phases.

	 * And it is the last chance to perform any moves before the widget is removed from current web page.

	 * Override this method to perform state update for each different widget.

	 * AND DO REMEMBER TO CALL {@link DUIClient#prepareMigDone} AT THE END OF THIS FUNCTION!
	 */
	this.prepareMigration = function(){
		//e.g. ..... just a joke....
		/*
		if (confirm("you sure to sign out?..."))
			parent.location = parent.location.protocol + "//" + parent.location.host + "/:authentication?return=&action=signout";
		console.log("the migration is at hand, the widget may need to do sth special before it is removed from the role widget container e.g. disconnect from the lasServer etc.");
		*/
		this.prepareMigDone();
	};

	/**
	 * The function is called when the dui manager asks the widget to update its states.

	 * Compared to the function DUIClient.finishMigration(), this is a typical normal state update for active widget on presence.

	 * This method will be called as a callback for DUIClient#requireWidgetState(); or DUIClient#initOK() when it is not a migration.
	 * Override this method to perform state update for each different widget.
	 * @param intent The Intent object that contains infos of required widget states, the infos are in intent.extras.widgetStates e.g. {"state1":value1,"state2":value2}.
	 * The object might contain appStates as well if there is any application state, get it in intent.extras.appStates e.g. {"appstate1":value1,"appstate2":value2}.
	 */
	this.updateState = function(intent){
		var states = {};
		states = intent.extras.widgetStates;
		var appStates = intent.extras.appStates;
		console.log(states);
		if (typeof appStates != "undefined")
			console.log(appStates);
		console.log("update the widget state, widget need to overwrite it");
	};

	/**
	 * The function is called to finish the Migration and update the widget state.

	 * Compared to the method DUIClient.updateState(), this method is a special widget state update for the widget that has just migrated.

	 * Override this method to perform finishing moves for each different widget.
	 * @param intent The Intent object that contains infos to complete the migration, the infos are in intent.extras.states e.g. {"state1":value1, "state2":value2}.
	 *  The object might contain appStates as well if there is any application state, get it in intent.extras.appStates e.g. {"appstate1":value1,"appstate2":value2}.
	 */
	this.finishMigration = function(intent){
		var states = {};
		states = intent.extras.widgetStates;
		var appStates = intent.extras.appStates;
		console.log(states);
		if (typeof appStates != "undefined")
			console.log(appStates);
		console.log("the migration is done, the widget may need to perform special inits before update the widget state e.g. login to the lasServer again.");
	};

	/**
	 * The function to signal the dui manager that the preparation for the migration is ready on this widget.

	 * This function should be called at the end of the overwritten function {@link DUIClient#prepareMigration}

	 * Do not override this method unless there is really an unstoppable reason.
	 */
	this.prepareMigDone = function(){
		//prepared and send OK response to DUIMgr
		var intent = {
				"component": "duimanager",
				"categories": ["DUI"],
				"action": "DUI_PRE_MIG_OK",
				"data": "",
				"dataType": "",
				"extras": {"widgetId": _widgetId}
			};
		_iwcClient.publish(intent);
	};

	/**
	 * The function to call the DUI manager to save the widget state on the server.

	 * Do not override this method unless there is really an unstoppable reason.
	 * @param states An array of widget state object {"stateName": stateValue}
	 */
	this.saveWidgetState = function(){
		var states = this.getWidgetState(false);
		var intent = {
			"action": "DUI_SAVE_WS",
			"categories": ["DUI"],
			"component": "duimanager",// the overwritten dui manager from the iwc.Proxy should have the _componentName set to "duimanager"
			"data":"",
			"dataType":"",
			"extras":{"widgetStates":states, "widgetId": _widgetId}
		};
		_iwcClient.publish(intent);
	};

	/**
	 * An open interface to send any intent
	 */
	this.sendIntent = function(intent){
		//or to send the intent to "duimanager"
		_iwcClient.publish(intent);
	};

	/**
	 * This function asks the framework for the states stored on the server.
	 * Do not override it.
	 */
	this.requireWidgetState = function(){
		var intent = {
				"action": "DUI_REQ_WS",
				"categories": ["DUI"],
				"component": "duimanager",// the overwritten dui manager from the iwc.Proxy should have the _componentName set to "duimanager"
				"data":"",
				"dataType":"",
				"extras":{"widgetId": _widgetId}
		};
		_iwcClient.publish(intent);
	};

	/**
	 * Store the global app state
	 * @param states the app state to be stored e.g. {"state1":value1, "state2":value2}
	 */
	this.setAppState = function(states){
		var intent = {
				"action": "DUI_SET_AS",
				"categories": ["DUI"],
				"component": "duimanager",// the overwritten dui manager from the iwc.Proxy should have the _componentName set to "duimanager"
				"data":"",
				"dataType":"",
				"extras":{"states": states}
		};
		_iwcClient.publish(intent);
	};

	/**
	 * Ask the dui manager for the app state.
	 */
	this.getAppState = function(){
		var intent = {
				"action": "DUI_GET_AS",
				"categories": ["DUI"],
				"component": "duimanager",// the overwritten dui manager from the iwc.Proxy should have the _componentName set to "duimanager"
				"data":"",
				"dataType":"",
		};
		_iwcClient.publish(intent);
	};

	/**
	 * Override this function to do something when the requested app state comes.
	 * @param appStates the json format of the app state:{"name1": value1, "name2": value2};
	 */
	this.onAppState = function(appStates){};

	/**
	 * call this function to register the duiclient to duimanager after all things are OK
	 */
	this.initOK = function(){
		var okIntent = {
			"action": "DUI_CLIENT_OK",
			"categories": ["DUI"],
			"component": "duimanager",// the overwritten dui manager from the iwc.Proxy should have the _componentName set to "duimanager"
			"data":"",
			"dataType":"",
			"extras":{"widgetId": _widgetId}
		};

		_iwcClient.publish(okIntent);
	};

	/**
	 * publish the intent in the domain of the user only
	 */
	this.publishToUser = function(intent){
		var wrap = {
				"action": "DUI_PUB_USER",
				"categories": ["DUI"],
				"component": "duimanager",
				"data": JSON.stringify(intent),
				"dataType": "application/json",
				"extras": {}
		};
		_iwcClient.publish(intent);
		_iwcClient.publish(wrap);
	};

	/**
	 * register the call back function of the widget to the DUI client.
	 */
	this.connect = function(callback){
		this.externalCallback = callback;
	};
};

// reminder to myself:.... the callback funcs injected into this DUIClient need to bind()
<|endoftext|>


<commit_before>
parseFragment = function (input) {
  var scanner = new Scanner(input);

  // XXX
};

// Take a numeric Unicode code point, which may be larger than 16 bits,
// and encode it as a JavaScript UTF-16 string.
//
// Adapted from
// http://stackoverflow.com/questions/7126384/expressing-utf-16-unicode-characters-in-javascript/7126661.
var codePointToString = function(cp) {
  if (cp >= 0 && cp <= 0xD7FF || cp >= 0xE000 && cp <= 0xFFFF) {
    return String.fromCharCode(cp);
  } else if (cp >= 0x10000 && cp <= 0x10FFFF) {

    // we substract 0x10000 from cp to get a 20-bit number
    // in the range 0..0xFFFF
    cp -= 0x10000;

    // we add 0xD800 to the number formed by the first 10 bits
    // to give the first byte
    var first = ((0xffc00 & cp) >> 10) + 0xD800;

    // we add 0xDC00 to the number formed by the low 10 bits
    // to give the second byte
    var second = (0x3ff & cp) + 0xDC00;

    return String.fromCharCode(first) + String.fromCharCode(second);
  } else {
    return '';
  }
};

getContent = function (scanner) {
  var items = [];

  while (! scanner.isEOF()) {
    // Stop at any top-level end tag.  We could use the tokenizer
    // but these two characters are a giveaway.
    if (scanner.rest().slice(0, 2) === '</')
      break;

    var token = getHTMLToken(scanner);

    // XXX cover all token types
    if (token.t === 'Doctype') {
      scanner.fatal("Unexpected Doctype");
    } else if (token.t === 'Chars') {
      if (items.length && typeof items[items.length - 1] === 'string')
        items[items.length - 1] += token.v;
      else
        items.push(token.v);
    } else if (token.t === 'CharRef') {
      var codePoints = token.cp;
      var str = '';
      for (var i = 0; i < codePoints.length; i++)
        str += codePointToString(codePoints[i]);
      items.push(HTML.CharRef({ html: token.v,
                                str: str }));
    } else if (token.t === 'Comment') {
      items.push(HTML.Comment(token.v));
    } else {
      throw new Error(token.t);
    }
  }

  if (items.length === 0)
    return null;
  else if (items.length === 1)
    return items[0];
  else
    return items;
};<commit_msg>baby steps<commit_after>
parseFragment = function (input) {
  var scanner = new Scanner(input);

  // XXX
};

// Take a numeric Unicode code point, which may be larger than 16 bits,
// and encode it as a JavaScript UTF-16 string.
//
// Adapted from
// http://stackoverflow.com/questions/7126384/expressing-utf-16-unicode-characters-in-javascript/7126661.
var codePointToString = function(cp) {
  if (cp >= 0 && cp <= 0xD7FF || cp >= 0xE000 && cp <= 0xFFFF) {
    return String.fromCharCode(cp);
  } else if (cp >= 0x10000 && cp <= 0x10FFFF) {

    // we substract 0x10000 from cp to get a 20-bit number
    // in the range 0..0xFFFF
    cp -= 0x10000;

    // we add 0xD800 to the number formed by the first 10 bits
    // to give the first byte
    var first = ((0xffc00 & cp) >> 10) + 0xD800;

    // we add 0xDC00 to the number formed by the low 10 bits
    // to give the second byte
    var second = (0x3ff & cp) + 0xDC00;

    return String.fromCharCode(first) + String.fromCharCode(second);
  } else {
    return '';
  }
};

getContent = function (scanner) {
  var items = [];

  while (! scanner.isEOF()) {
    // Stop at any top-level end tag.  We could use the tokenizer
    // but these two characters are a giveaway.
    if (scanner.rest().slice(0, 2) === '</')
      break;

    var token = getHTMLToken(scanner);

    if (token.t === 'Doctype') {
      scanner.fatal("Unexpected Doctype");
    } else if (token.t === 'Chars') {
      if (items.length && typeof items[items.length - 1] === 'string')
        items[items.length - 1] += token.v;
      else
        items.push(token.v);
    } else if (token.t === 'CharRef') {
      var codePoints = token.cp;
      var str = '';
      for (var i = 0; i < codePoints.length; i++)
        str += codePointToString(codePoints[i]);
      items.push(HTML.CharRef({ html: token.v,
                                str: str }));
    } else if (token.t === 'Comment') {
      items.push(HTML.Comment(token.v));
    } else if (token.t === 'Tag') {
      if (token.isEnd)
        // we've already screened for `</` so this shouldn't be
        // possible.
        throw new Error("Assertion failed: didn't expect end tag");

      // XXX parse start tag and, possibly, content (recursively)
      // and end tag
      throw new Error("XXX implement");
    } else {
      throw new Error("Unknown token type: " + token.t);
    }
  }

  if (items.length === 0)
    return null;
  else if (items.length === 1)
    return items[0];
  else
    return items;
};<|endoftext|>


<commit_before>import React from 'react';
import styled from 'styled-components';
import { getWindowSize } from 'ui/utils/measurements';
import UIState, { UIStateListener } from 'ui/UIState';
import MimicControls from 'ui/components/MimicControls';
import MainControls from 'ui/components/common/MainControls';
import ResizeHandle from 'ui/components/common/ResizeHandle';

const Container = styled.div`
  width: 100%;
  height: calc(100% - 51px);
  font-size: 13px;
  line-height: 20px;
  font-family: -apple-system, BlinkMacSystemFont, Arial, sans-serif;
  background-color: white;
  border-top: 1px solid #e7e7e7;
  bottom: 51px;
  z-index: 999999999999;
`;

const Actions = styled.div`
  display: flex;
  align-items: center;
  padding-left: 8px;
  position: relative;
  justify-content: flex-end;
`;

class Frame extends React.Component {

  componentDidMount() {
    window.addEventListener('keyup', this.closeOnEscape);
  }

  componentWillUnmount() {
    window.removeEventListener('keyup', this.closeOnEscape);
  }

  closeOnEscape = (event) => {
    if (event.keyCode === 27) {
      UIState.update({ viewMode: 'closed' });
    }
  };

  render() {
    const style = {
      width: '100%',
      height: getWindowSize(UIState.editorHeight)
    };

    const disabledStyle = {
      filter: 'grayscale(100%)',
      opacity: 0.25
    };

    return (

        <ResizeHandle horizontal/>

        <Container style={ !UIState.mimicEnabled && disabledStyle }>
          { this.props.children }
        </Container>

        <MimicControls fullWidth>
          <Actions>
            { this.props.controls }
          </Actions>

          <MainControls/>
        </MimicControls>

    );
  }
}

export default UIStateListener(Frame);<commit_msg>add disabled state to mimic frame when master checkbox is off<commit_after>import React from 'react';
import styled from 'styled-components';
import { getWindowSize } from 'ui/utils/measurements';
import UIState, { UIStateListener } from 'ui/UIState';
import MimicControls from 'ui/components/MimicControls';
import MainControls from 'ui/components/common/MainControls';
import ResizeHandle from 'ui/components/common/ResizeHandle';

const Container = styled.div`
  position: relative;
  width: 100%;
  height: calc(100% - 51px);
  font-size: 13px;
  line-height: 20px;
  font-family: -apple-system, BlinkMacSystemFont, Arial, sans-serif;
  background-color: white;
  border-top: 1px solid #e7e7e7;
  bottom: 51px;
  z-index: 90000000000;
`;

const Actions = styled.div`
  display: flex;
  align-items: center;
  padding-left: 8px;
  position: relative;
  justify-content: flex-end;
`;

const Overlay = styled.div`
  position: absolute;
  top: 0;
  bottom: 0;
  width: 100%;
  background: transparent;
  z-index: 90000000001;
`;

class Frame extends React.Component {

  componentDidMount() {
    window.addEventListener('keyup', this.closeOnEscape);
  }

  componentWillUnmount() {
    window.removeEventListener('keyup', this.closeOnEscape);
  }

  closeOnEscape = (event) => {
    if (event.keyCode === 27) {
      UIState.update({ viewMode: 'closed' });
    }
  };

  render() {
    const style = {
      width: '100%',
      height: getWindowSize(UIState.editorHeight)
    };

    const disabledStyle = {
      filter: 'grayscale(100%)',
      opacity: 0.25
    };

    return (

        <ResizeHandle horizontal/>

        <Container style={ !UIState.mimicEnabled && disabledStyle }>
          { !UIState.mimicEnabled && <Overlay/> }

          { this.props.children }
        </Container>

        <MimicControls fullWidth>
          {
            UIState.mimicEnabled &&
            <Actions>
              { this.props.controls }
            </Actions>
          }

          <MainControls/>
        </MimicControls>

    );
  }
}

export default UIStateListener(Frame);<|endoftext|>


<commit_before>const mockHttp = jest.genMockFromModule('../common/http');
jest.mock('../common/http', () => mockHttp);

const { api } = require('.'); // need to use require because of jest mocks being weird

describe('api', () => {
  beforeEach(() => {
    mockHttp.get = jest.fn();
    mockHttp.post = jest.fn();
    mockHttp.postForm = jest.fn();
    mockHttp.put = jest.fn();
  });

  it('can authenticate with a phone number', () => {
    const phoneNumber = '1234567';
    const controlCode = '123123123';
    mockHttp.post.mockImplementationOnce(() => Promise.resolve({
      mobileIdChallengeCode: controlCode,
    }));
    expect(mockHttp.post).not.toHaveBeenCalled();
    return api
      .authenticateWithPhoneNumber(phoneNumber)
      .then((givenControlCode) => {
        expect(givenControlCode).toBe(controlCode);
        expect(mockHttp.post).toHaveBeenCalledTimes(1);
        expect(mockHttp.post).toHaveBeenCalledWith('/authenticate', { phoneNumber });
      });
  });

  it('can authenticate with id card', () => {
    mockHttp.get = jest.fn(() => Promise.resolve());
    mockHttp.post = jest.fn(() => Promise.resolve({
      success: true,
    }));
    expect(mockHttp.get).not.toHaveBeenCalled();
    expect(mockHttp.post).not.toHaveBeenCalled();
    return api
      .authenticateWithIdCard()
      .then((success) => {
        expect(success).toBe(true);
        expect(mockHttp.get).toHaveBeenCalledTimes(1);
        expect(mockHttp.get).toHaveBeenCalledWith('https://id.tuleva.ee/');
        expect(mockHttp.post).toHaveBeenCalledTimes(1);
        expect(mockHttp.post).toHaveBeenCalledWith('https://id.tuleva.ee/idLogin', undefined, { 'Content-Type': 'text/plain' });
      });
  });

  it('can get a mobile id token', () => {
    mockHttp.postForm = jest.fn(() => Promise.resolve({ access_token: 'mobile_id_token' }));
    expect(mockHttp.postForm).not.toHaveBeenCalled();
    return api
      .getMobileIdToken()
      .then((token) => {
        expect(token).toBe('mobile_id_token');
        expect(mockHttp.postForm).toHaveBeenCalledTimes(1);
        expect(mockHttp.postForm).toHaveBeenCalledWith('/oauth/token', {
          client_id: 'onboarding-client',
          grant_type: 'mobile_id',
        }, { Authorization: 'Basic b25ib2FyZGluZy1jbGllbnQ6b25ib2FyZGluZy1jbGllbnQ=' });
      });
  });

  it('can get an id card token', () => {
    mockHttp.postForm = jest.fn(() => Promise.resolve({ access_token: 'token' }));
    expect(mockHttp.postForm).not.toHaveBeenCalled();
    return api
      .getIdCardToken()
      .then((token) => {
        expect(token).toBe('token');
        expect(mockHttp.postForm).toHaveBeenCalledTimes(1);
        expect(mockHttp.postForm).toHaveBeenCalledWith('/oauth/token', {
          client_id: 'onboarding-client',
          grant_type: 'id_card',
        }, { Authorization: 'Basic b25ib2FyZGluZy1jbGllbnQ6b25ib2FyZGluZy1jbGllbnQ=' });
      });
  });

  it('throws in getting token if authentication is finished but errored', () => {
    const error = { error: 'oh no!' };
    mockHttp.postForm = jest.fn(() => Promise.reject(error));
    return api
      .getMobileIdToken()
      .then(() => expect(0).toBe(1)) // fail, should not go to then.
      .catch(givenError => expect(givenError).toEqual(error));
  });

  it('gives no token in authentication check if error is auth not completed', () => {
    mockHttp.postForm = jest.fn(() => Promise.reject({ error: 'AUTHENTICATION_NOT_COMPLETE' }));
    return api
      .getMobileIdToken()
      .then(token => expect(token).toBeFalsy());
  });

  it('can get a user with a token', () => {
    const user = { iAmAUser: true };
    const token = 'token';
    mockHttp.get = jest.fn(() => Promise.resolve(user));
    return api
      .getUserWithToken(token)
      .then((givenUser) => {
        expect(givenUser).toEqual(user);
        expect(mockHttp.get).toHaveBeenCalledWith('/v1/me', undefined, {
          Authorization: `Bearer ${token}`,
        });
      });
  });

  it('can get existing funds and converts them with a token', () => {
    const pensionFunds = [
      {
        fund: {
          name: 'name',
          isin: 'AA123123123123',
          managementFeeRate: 0.005,
        },
        activeContributions: false,
        value: 100,
      },
      {
        fund: {
          name: 'name 2',
          isin: 'AA123123123124',
          managementFeeRate: 0.0039,
        },
        activeContributions: true,
        value: 200,
        currency: 'GBP',
      },
    ];
    const token = 'token';
    mockHttp.get = jest.fn(() => Promise.resolve(pensionFunds));
    return api
      .getSourceFundsWithToken(token)
      .then((givenPensionFunds) => {
        expect(givenPensionFunds).toEqual([
          {
            name: 'name',
            isin: 'AA123123123123',
            managementFeePercent: '0.5',
            activeFund: false,
            price: 100,
            currency: 'EUR',
          },
          {
            name: 'name 2',
            isin: 'AA123123123124',
            managementFeePercent: '0.39',
            activeFund: true,
            price: 200,
            currency: 'GBP',
          },
        ]);
        expect(mockHttp.get).toHaveBeenCalledWith('/v1/pension-account-statement', undefined, {
          Authorization: `Bearer ${token}`,
        });
      });
  });

  it('can get target funds with a token', () => {
    const targetFunds = [{ iAmAFund: true }];
    const token = 'token';
    mockHttp.get = jest.fn(() => Promise.resolve(targetFunds));
    return api
      .getTargetFundsWithToken(token)
      .then((givenTarget) => {
        expect(givenTarget).toEqual(targetFunds);
        expect(mockHttp.get).toHaveBeenCalledWith('/v1/funds', { 'fundManager.name': 'Tuleva' }, {
          Authorization: `Bearer ${token}`,
        });
      });
  });

  it('can download mandate preview', () => {
      mockHttp.downloadFile = jest.fn(() => Promise.resolve());
      const mandateId = '123';
      const token = 'a token';
      return api.downloadMandatePreviewWithIdAndToken(mandateId, token)
          .then(() => expect(mockHttp.downloadFile).toHaveBeenCalledWith('/v1/mandates/123/file/preview', {
              Authorization: `Bearer ${token}`,
          }));
  });

  it('can download a mandate', () => {
    mockHttp.downloadFile = jest.fn(() => Promise.resolve());
    const mandateId = '123';
    const token = 'a token';
    return api.downloadMandateWithIdAndToken(mandateId, token)
      .then(() => expect(mockHttp.downloadFile).toHaveBeenCalledWith('/v1/mandates/123/file', {
        Authorization: `Bearer ${token}`,
      }));
  });

  it('can get a mobile id signature challenge code', () => {
    mockHttp.put = jest.fn(() => Promise.resolve({ mobileIdChallengeCode: 7777 }));
    expect(mockHttp.put).not.toHaveBeenCalled();
    const mandateId = '123';
    const token = 'a token';
    return api.getMobileIdSignatureChallengeCodeForMandateIdWithToken(mandateId, token)
      .then((mobileIdChallengeCode) => {
        expect(mobileIdChallengeCode).toBe(7777);
        expect(mockHttp.put).toHaveBeenCalledTimes(1);
        expect(mockHttp.put).toHaveBeenCalledWith('/v1/mandates/123/signature/mobileId', undefined, {
          Authorization: `Bearer ${token}`,
        });
      });
  });

  it('can get a mobile id signature status', () => {
    mockHttp.get = jest.fn(() => Promise.resolve({ statusCode: 'SIGNATURE' }));
    expect(mockHttp.get).not.toHaveBeenCalled();
    const mandateId = '123';
    const token = 'a token';
    return api.getMobileIdSignatureStatusForMandateIdWithToken(mandateId, token)
      .then((statusCode) => {
        expect(statusCode).toBe('SIGNATURE');
        expect(mockHttp.get).toHaveBeenCalledTimes(1);
        expect(mockHttp.get).toHaveBeenCalledWith('/v1/mandates/123/signature/mobileId/status', undefined, {
          Authorization: `Bearer ${token}`,
        });
      });
  });

  it('can get an id card hash to be signed', () => {
    mockHttp.put = jest.fn(() => Promise.resolve({ hash: 'asdfg' }));
    expect(mockHttp.put).not.toHaveBeenCalled();
    const clientCertificate = 'a certificate';
    const mandateId = '123';
    const token = 'a token';
    return api.getIdCardSignatureHashForMandateIdWithCertificateHexAndToken(
      mandateId, clientCertificate, token)
      .then((hash) => {
        expect(hash).toBe('asdfg');
        expect(mockHttp.put).toHaveBeenCalledTimes(1);
        expect(mockHttp.put).toHaveBeenCalledWith('/v1/mandates/123/signature/idCard', { clientCertificate }, {
          Authorization: `Bearer ${token}`,
        });
      });
  });

  it('can get an id card signature status', () => {
    mockHttp.put = jest.fn(() => Promise.resolve({ statusCode: 'SIGNATURE' }));
    expect(mockHttp.put).not.toHaveBeenCalled();
    const signedHash = 'a signed hash';
    const mandateId = '123';
    const token = 'a token';
    return api.getIdCardSignatureStatusForMandateIdWithSignedHashAndToken(
      mandateId, signedHash, token)
      .then((statusCode) => {
        expect(statusCode).toBe('SIGNATURE');
        expect(mockHttp.put).toHaveBeenCalledTimes(1);
        expect(mockHttp.put).toHaveBeenCalledWith('/v1/mandates/123/signature/idCard/status', { signedHash }, {
          Authorization: `Bearer ${token}`,
        });
      });
  });
});
<commit_msg>Fixed test<commit_after>const mockHttp = jest.genMockFromModule('../common/http');
jest.mock('../common/http', () => mockHttp);

const { api } = require('.'); // need to use require because of jest mocks being weird

describe('api', () => {
  beforeEach(() => {
    mockHttp.get = jest.fn();
    mockHttp.post = jest.fn();
    mockHttp.postForm = jest.fn();
    mockHttp.put = jest.fn();
    mockHttp.simpleFetch = jest.fn();
  });

  it('can authenticate with a phone number', () => {
    const phoneNumber = '1234567';
    const controlCode = '123123123';
    mockHttp.post.mockImplementationOnce(() => Promise.resolve({
      mobileIdChallengeCode: controlCode,
    }));
    expect(mockHttp.post).not.toHaveBeenCalled();
    return api
      .authenticateWithPhoneNumber(phoneNumber)
      .then((givenControlCode) => {
        expect(givenControlCode).toBe(controlCode);
        expect(mockHttp.post).toHaveBeenCalledTimes(1);
        expect(mockHttp.post).toHaveBeenCalledWith('/authenticate', { phoneNumber });
      });
  });

  it('can authenticate with id card', () => {
    mockHttp.simpleFetch = jest.fn(() => Promise.resolve({
      success: true,
    }));
    expect(mockHttp.simpleFetch).not.toHaveBeenCalled();
    return api
      .authenticateWithIdCard()
      .then((success) => {
        expect(success).toBe(true);
        expect(mockHttp.simpleFetch).toHaveBeenCalledTimes(2);
        expect(mockHttp.simpleFetch).toHaveBeenCalledWith('GET', 'https://id.tuleva.ee/');
        expect(mockHttp.simpleFetch).toHaveBeenCalledWith('POST', 'https://id.tuleva.ee/idLogin');
      });
  });

  it('can get a mobile id token', () => {
    mockHttp.postForm = jest.fn(() => Promise.resolve({ access_token: 'mobile_id_token' }));
    expect(mockHttp.postForm).not.toHaveBeenCalled();
    return api
      .getMobileIdToken()
      .then((token) => {
        expect(token).toBe('mobile_id_token');
        expect(mockHttp.postForm).toHaveBeenCalledTimes(1);
        expect(mockHttp.postForm).toHaveBeenCalledWith('/oauth/token', {
          client_id: 'onboarding-client',
          grant_type: 'mobile_id',
        }, { Authorization: 'Basic b25ib2FyZGluZy1jbGllbnQ6b25ib2FyZGluZy1jbGllbnQ=' });
      });
  });

  it('can get an id card token', () => {
    mockHttp.postForm = jest.fn(() => Promise.resolve({ access_token: 'token' }));
    expect(mockHttp.postForm).not.toHaveBeenCalled();
    return api
      .getIdCardToken()
      .then((token) => {
        expect(token).toBe('token');
        expect(mockHttp.postForm).toHaveBeenCalledTimes(1);
        expect(mockHttp.postForm).toHaveBeenCalledWith('/oauth/token', {
          client_id: 'onboarding-client',
          grant_type: 'id_card',
        }, { Authorization: 'Basic b25ib2FyZGluZy1jbGllbnQ6b25ib2FyZGluZy1jbGllbnQ=' });
      });
  });

  it('throws in getting token if authentication is finished but errored', () => {
    const error = { error: 'oh no!' };
    mockHttp.postForm = jest.fn(() => Promise.reject(error));
    return api
      .getMobileIdToken()
      .then(() => expect(0).toBe(1)) // fail, should not go to then.
      .catch(givenError => expect(givenError).toEqual(error));
  });

  it('gives no token in authentication check if error is auth not completed', () => {
    mockHttp.postForm = jest.fn(() => Promise.reject({ error: 'AUTHENTICATION_NOT_COMPLETE' }));
    return api
      .getMobileIdToken()
      .then(token => expect(token).toBeFalsy());
  });

  it('can get a user with a token', () => {
    const user = { iAmAUser: true };
    const token = 'token';
    mockHttp.get = jest.fn(() => Promise.resolve(user));
    return api
      .getUserWithToken(token)
      .then((givenUser) => {
        expect(givenUser).toEqual(user);
        expect(mockHttp.get).toHaveBeenCalledWith('/v1/me', undefined, {
          Authorization: `Bearer ${token}`,
        });
      });
  });

  it('can get existing funds and converts them with a token', () => {
    const pensionFunds = [
      {
        fund: {
          name: 'name',
          isin: 'AA123123123123',
          managementFeeRate: 0.005,
        },
        activeContributions: false,
        value: 100,
      },
      {
        fund: {
          name: 'name 2',
          isin: 'AA123123123124',
          managementFeeRate: 0.0039,
        },
        activeContributions: true,
        value: 200,
        currency: 'GBP',
      },
    ];
    const token = 'token';
    mockHttp.get = jest.fn(() => Promise.resolve(pensionFunds));
    return api
      .getSourceFundsWithToken(token)
      .then((givenPensionFunds) => {
        expect(givenPensionFunds).toEqual([
          {
            name: 'name',
            isin: 'AA123123123123',
            managementFeePercent: '0.5',
            activeFund: false,
            price: 100,
            currency: 'EUR',
          },
          {
            name: 'name 2',
            isin: 'AA123123123124',
            managementFeePercent: '0.39',
            activeFund: true,
            price: 200,
            currency: 'GBP',
          },
        ]);
        expect(mockHttp.get).toHaveBeenCalledWith('/v1/pension-account-statement', undefined, {
          Authorization: `Bearer ${token}`,
        });
      });
  });

  it('can get target funds with a token', () => {
    const targetFunds = [{ iAmAFund: true }];
    const token = 'token';
    mockHttp.get = jest.fn(() => Promise.resolve(targetFunds));
    return api
      .getTargetFundsWithToken(token)
      .then((givenTarget) => {
        expect(givenTarget).toEqual(targetFunds);
        expect(mockHttp.get).toHaveBeenCalledWith('/v1/funds', { 'fundManager.name': 'Tuleva' }, {
          Authorization: `Bearer ${token}`,
        });
      });
  });

  it('can download mandate preview', () => {
      mockHttp.downloadFile = jest.fn(() => Promise.resolve());
      const mandateId = '123';
      const token = 'a token';
      return api.downloadMandatePreviewWithIdAndToken(mandateId, token)
          .then(() => expect(mockHttp.downloadFile).toHaveBeenCalledWith('/v1/mandates/123/file/preview', {
              Authorization: `Bearer ${token}`,
          }));
  });

  it('can download a mandate', () => {
    mockHttp.downloadFile = jest.fn(() => Promise.resolve());
    const mandateId = '123';
    const token = 'a token';
    return api.downloadMandateWithIdAndToken(mandateId, token)
      .then(() => expect(mockHttp.downloadFile).toHaveBeenCalledWith('/v1/mandates/123/file', {
        Authorization: `Bearer ${token}`,
      }));
  });

  it('can get a mobile id signature challenge code', () => {
    mockHttp.put = jest.fn(() => Promise.resolve({ mobileIdChallengeCode: 7777 }));
    expect(mockHttp.put).not.toHaveBeenCalled();
    const mandateId = '123';
    const token = 'a token';
    return api.getMobileIdSignatureChallengeCodeForMandateIdWithToken(mandateId, token)
      .then((mobileIdChallengeCode) => {
        expect(mobileIdChallengeCode).toBe(7777);
        expect(mockHttp.put).toHaveBeenCalledTimes(1);
        expect(mockHttp.put).toHaveBeenCalledWith('/v1/mandates/123/signature/mobileId', undefined, {
          Authorization: `Bearer ${token}`,
        });
      });
  });

  it('can get a mobile id signature status', () => {
    mockHttp.get = jest.fn(() => Promise.resolve({ statusCode: 'SIGNATURE' }));
    expect(mockHttp.get).not.toHaveBeenCalled();
    const mandateId = '123';
    const token = 'a token';
    return api.getMobileIdSignatureStatusForMandateIdWithToken(mandateId, token)
      .then((statusCode) => {
        expect(statusCode).toBe('SIGNATURE');
        expect(mockHttp.get).toHaveBeenCalledTimes(1);
        expect(mockHttp.get).toHaveBeenCalledWith('/v1/mandates/123/signature/mobileId/status', undefined, {
          Authorization: `Bearer ${token}`,
        });
      });
  });

  it('can get an id card hash to be signed', () => {
    mockHttp.put = jest.fn(() => Promise.resolve({ hash: 'asdfg' }));
    expect(mockHttp.put).not.toHaveBeenCalled();
    const clientCertificate = 'a certificate';
    const mandateId = '123';
    const token = 'a token';
    return api.getIdCardSignatureHashForMandateIdWithCertificateHexAndToken(
      mandateId, clientCertificate, token)
      .then((hash) => {
        expect(hash).toBe('asdfg');
        expect(mockHttp.put).toHaveBeenCalledTimes(1);
        expect(mockHttp.put).toHaveBeenCalledWith('/v1/mandates/123/signature/idCard', { clientCertificate }, {
          Authorization: `Bearer ${token}`,
        });
      });
  });

  it('can get an id card signature status', () => {
    mockHttp.put = jest.fn(() => Promise.resolve({ statusCode: 'SIGNATURE' }));
    expect(mockHttp.put).not.toHaveBeenCalled();
    const signedHash = 'a signed hash';
    const mandateId = '123';
    const token = 'a token';
    return api.getIdCardSignatureStatusForMandateIdWithSignedHashAndToken(
      mandateId, signedHash, token)
      .then((statusCode) => {
        expect(statusCode).toBe('SIGNATURE');
        expect(mockHttp.put).toHaveBeenCalledTimes(1);
        expect(mockHttp.put).toHaveBeenCalledWith('/v1/mandates/123/signature/idCard/status', { signedHash }, {
          Authorization: `Bearer ${token}`,
        });
      });
  });
});
<|endoftext|>


<commit_before>const shell = require('shell');
const _ = require('underscore');
const loophole = require('loophole');

function RemoteRevision(hash, remote) {
  this.hash = hash;
  this.remote = remote;
}

// ================
// Class Methods
// ================

RemoteRevision.create = function(hash, remoteUrl) {
  return new RemoteRevision(hash, remoteUrl);
}

// ================
// Instance Methods
// ================

_.extend(RemoteRevision.prototype, {

  githubTemplate: 'https://github.com/<%- project %>/<%- repo %>/commit/<%- revision %>',

  bitbucketTemplate: 'https://bitbucket.org/<%- project %>/<%- repo %>/commits/<%- revision %>',

  open: function() {
    var url = this.url();
    if (url) {
      console.log('url', url);
      // shell.openExternal(url);
    }
  },

  url: function() {
    var template = this.getTemplate();
    var data = this.parseProjectAndRepo();
    data.revision = this.hash;

    return template(data);
  },

  parseProjectAndRepo: function() {
    var pattern = /\:(.*)\/(.*)\.git/;
    var matches = this.remote.match(pattern);
    return {
      project: matches[1],
      repo: matches[2]
    };
  },

  getTemplate: function() {
    // Use loophole to allow 'new Function' usage without unsafe eval error
    return loophole.allowUnsafeNewFunction(_.bind(function() {

      if (this.isGithub()) {
        return _.template(this.githubTemplate);
      }

      if (this.isBitbucket()) {
        return _.template(this.bitbucketTemplate);
      }

      // read custom template from config and return

      // else show error repo not supported please add custom config here: link

    }, this));
  },

  isGithub: function() {
    return /github.com/.test(this.remote);
  },

  isBitbucket: function() {
    return /bitbucket.org/.test(this.remote);
  }

});

// Exports
module.exports = RemoteRevision;
<commit_msg>fixed hard error when not github or bitbucket. need to show user though...<commit_after>const shell = require('shell');
const _ = require('underscore');
const loophole = require('loophole');

function RemoteRevision(hash, remote) {
  this.hash = hash;
  this.remote = remote;
}

// ================
// Class Methods
// ================

RemoteRevision.create = function(hash, remoteUrl) {
  return new RemoteRevision(hash, remoteUrl);
}

// ================
// Instance Methods
// ================

_.extend(RemoteRevision.prototype, {

  githubTemplate: 'https://github.com/<%- project %>/<%- repo %>/commit/<%- revision %>',

  bitbucketTemplate: 'https://bitbucket.org/<%- project %>/<%- repo %>/commits/<%- revision %>',

  open: function() {
    var url = this.url();
    if (url) {
      console.log('url', url);
      // shell.openExternal(url);
    }
  },

  url: function() {
    var template = this.getTemplate();

    if (!template) {
      // TODO tell user of error here. please create custom template this is not a github repo.
      return;
    }

    var data = this.parseProjectAndRepo();
    data.revision = this.hash;

    return template(data);
  },

  parseProjectAndRepo: function() {
    var pattern = /\:(.*)\/(.*)\.git/;
    var matches = this.remote.match(pattern);
    return {
      project: matches[1],
      repo: matches[2]
    };
  },

  safeTemplate: function(templateString) {
    return loophole.allowUnsafeNewFunction(function() {
      return _.template(templateString);
    });
  },

  getTemplate: function() {
    // read custom template from config and return
    if (this.isGithub()) {
      return this.safeTemplate(this.githubTemplate);
    }

    if (this.isBitbucket()) {
      return this.safeTemplate(this.bitbucketTemplate);
    }
  },

  isGithub: function() {
    return /github.com/.test(this.remote);
  },

  isBitbucket: function() {
    return /bitbucket.org/.test(this.remote);
  }

});

// Exports
module.exports = RemoteRevision;
<|endoftext|>


<commit_before>/**
 * Shopware 5
 * Copyright (c) shopware AG
 *
 * According to our dual licensing model, this program can be used either
 * under the terms of the GNU Affero General Public License, version 3,
 * or under a proprietary license.
 *
 * The texts of the GNU Affero General Public License with an additional
 * permission and of our proprietary license can be found at and
 * in the LICENSE file you have received along with this program.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * "Shopware" is a registered trademark of shopware AG.
 * The licensing of the program under the AGPLv3 does not imply a
 * trademark license. Therefore any rights, title and interest in
 * our trademarks remain entirely with us.
 */

//{namespace name=backend/emotion/presets/presets}

/**
 * Shopware Application
 *
 * @category  Shopware
 * @package   Shopware
 * @copyright Copyright (c) shopware AG (http://www.shopware.de)
 */

//{block name="backend/emotion/presets/info"}
Ext.define('Shopware.apps.Emotion.view.presets.Info', {
    extend: 'Ext.panel.Panel',
    alias: 'widget.preset-info-panel',

    cls: 'emotion-info-panel',
    layout: 'fit',

    initComponent: function() {
        var me = this;

        me.items = me.buildItems();

        me.callParent(arguments);
    },

    buildItems: function() {
        var me = this;

        me.infoView = Ext.create('Ext.view.View', {
            tpl: me.createTemplate(),
            autoScroll: true,
            padding: 5,
            style: 'color: #6c818f;font-size:11px',
            emptyText: '
{s name="info_panel/empty_text"}{/s}
',
            deferEmptyText: false
        });

        return me.infoView;
    },

    createTemplate: function() {
        return new Ext.XTemplate(
            '<tpl for=".">',
                '
',
                    '{literal}

{/literal}',
                    '

{s name=name}{/s}:

{literal}{label}{/literal}

',
                    '

{s name=description}{/s}:

{literal}{description}{/literal}

',
                    '<tpl if="this.hasRequiredPlugins(values.requiredPlugins)">',
                        '
',
                            '
{s name=required_plugins}{/s}:
',
                            '
',
                                '<tpl for="requiredPlugins">',
                                    '
' +
                                        '<tpl if="valid">' +
                                            ' ' +
                                        '<tpl else>' +
                                            ' ' +
                                        '</tpl>',
                                        '{literal}{plugin_label} ({version}){/literal}' +
                                    '
',
                                '</tpl>',
                            '
',
                        '
',
                    '</tpl>',
                '
',
            '</tpl>',
            {
                hasRequiredPlugins: function(requiredPlugins) {
                    return requiredPlugins.length > 0;
                }
            }
        );
    },

    updateInfoView: function(record) {
        var me = this;

        if (record && record.getData()) {
            me.infoView.update(record.getData());
            var $el = me.infoView.getEl();
            var plugins = $el.query('.required-plugin');

            Ext.each(plugins, function(item) {
                item = Ext.get(item);
                item.on('click', function() {
                    var inStore = item.getAttribute('data-in-store') === "true";
                    if (!inStore) {
                        return;
                    }
                    Shopware.app.Application.addSubApplication({
                        name: 'Shopware.apps.PluginManager',
                        params: {
                            hidden: true,
                            displayPlugin: item.id
                        }
                    });
                });
            });

        } else {
            me.infoView.update('
{s name="info_panel/empty_text"}{/s}
');
        }
    }
});
//{/block}<commit_msg>SW-14802 - Fix required plugins info view<commit_after>/**
 * Shopware 5
 * Copyright (c) shopware AG
 *
 * According to our dual licensing model, this program can be used either
 * under the terms of the GNU Affero General Public License, version 3,
 * or under a proprietary license.
 *
 * The texts of the GNU Affero General Public License with an additional
 * permission and of our proprietary license can be found at and
 * in the LICENSE file you have received along with this program.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * "Shopware" is a registered trademark of shopware AG.
 * The licensing of the program under the AGPLv3 does not imply a
 * trademark license. Therefore any rights, title and interest in
 * our trademarks remain entirely with us.
 */

//{namespace name=backend/emotion/presets/presets}

/**
 * Shopware Application
 *
 * @category  Shopware
 * @package   Shopware
 * @copyright Copyright (c) shopware AG (http://www.shopware.de)
 */

//{block name="backend/emotion/presets/info"}
Ext.define('Shopware.apps.Emotion.view.presets.Info', {
    extend: 'Ext.panel.Panel',
    alias: 'widget.preset-info-panel',

    cls: 'emotion-info-panel',
    layout: 'fit',

    initComponent: function() {
        var me = this;

        me.items = me.buildItems();

        me.callParent(arguments);
    },

    buildItems: function() {
        var me = this;

        me.infoView = Ext.create('Ext.view.View', {
            tpl: me.createTemplate(),
            autoScroll: true,
            padding: 5,
            style: 'color: #6c818f;font-size:11px',
            emptyText: '
{s name="info_panel/empty_text"}{/s}
',
            deferEmptyText: false
        });

        return me.infoView;
    },

    createTemplate: function() {
        return new Ext.XTemplate(
            '<tpl for=".">',
                '
',
                    '{literal}

{/literal}',
                    '

{s name=name}{/s}:

{literal}{label}{/literal}

',
                    '

{s name=description}{/s}:

{literal}{description}{/literal}

',
                    '<tpl if="this.hasRequiredPlugins(values.requiredPlugins)">',
                        '
',
                            '
{s name=required_plugins}{/s}:
',
                            '
',
                                '<tpl for="requiredPlugins">',
                                    '
' +
                                        '<tpl if="valid">' +
                                            ' ' +
                                        '<tpl else>' +
                                            ' ' +
                                        '</tpl>',
                                        '{literal}{[this.getPluginName(values)]} ({version}){/literal}' +
                                    '
',
                                '</tpl>',
                            '
',
                        '
',
                    '</tpl>',
                '
',
            '</tpl>',
            {
                hasRequiredPlugins: function(requiredPlugins) {
                    return requiredPlugins.length > 0;
                }
            },
            {
                getPluginName: function(values) {
                    return values.plugin_label || values.name;
                }
            }
        );
    },

    updateInfoView: function(record) {
        var me = this;

        if (record && record.getData()) {
            me.infoView.update(record.getData());
            var $el = me.infoView.getEl();
            var plugins = $el.query('.required-plugin');

            Ext.each(plugins, function(item) {
                item = Ext.get(item);
                item.on('click', function() {
                    var inStore = item.getAttribute('data-in-store') === "true";
                    if (!inStore) {
                        return;
                    }
                    Shopware.app.Application.addSubApplication({
                        name: 'Shopware.apps.PluginManager',
                        params: {
                            hidden: true,
                            displayPlugin: item.id
                        }
                    });
                });
            });

        } else {
            me.infoView.update('
{s name="info_panel/empty_text"}{/s}
');
        }
    }
});
//{/block}<|endoftext|>


<commit_before>var util = require('util');

var DEFAULTS = {
  '*': {
    colors: {
      opacity: true // rgba / hsla
    },
    properties: {
      backgroundClipMerging: false, // background-clip to shorthand
      backgroundOriginMerging: false, // background-origin to shorthand
      backgroundSizeMerging: false, // background-size to shorthand
      colors: true, // any kind of color transformations, like `#ff00ff` to `#f0f` or `#fff` into `red`
      fontWeight: true, // normal -> '400'
      ieBangHack: false, // !ie suffix hacks on IE<8
      iePrefixHack: false, // underscore / asterisk prefix hacks on IE
      ieSuffixHack: false, // \9 suffix hacks on IE6-9
      merging: true, // merging properties into one
      shorterLengthUnits: false, // optimize pixel units into `pt`, `pc` or `in` units
      spaceAfterClosingBrace: true, // 'url() no-repeat' to 'url()no-repeat'
      urlQuotes: false, // whether to wrap content of `url()` into quotes or not
      zeroUnits: true // 0[unit] -> 0
    },
    selectors: {
      adjacentSpace: false, // div+ nav Android stock browser hack
      ie7Hack: false, // *+html hack
      special: /(\-moz\-|\-ms\-|\-o\-|\-webkit\-|:dir\([a-z-]*\)|:first(?![a-z-])|:fullscreen|:left|:read-only|:read-write|:right|:placeholder|:host|:content|\/deep\/|:shadow|:selection|^,)/ // special selectors which prevent merging
    },
    units: {
      ch: true,
      in: true,
      pc: true,
      pt: true,
      rem: true,
      vh: true,
      vm: true, // vm is vmin on IE9+ see https://developer.mozilla.org/en-US/docs/Web/CSS/length
      vmax: true,
      vmin: true,
      vw: true
    }
  }
};

DEFAULTS.ie9 = merge(DEFAULTS['*'], {
  properties: {
    ieSuffixHack: true
  }
});

DEFAULTS.ie8 = merge(DEFAULTS.ie9, {
  colors: {
    opacity: false
  },
  properties: {
    iePrefixHack: true,
    merging: false
  },
  selectors: {
    special: /(\-moz\-|\-ms\-|\-o\-|\-webkit\-|:root|:nth|:first\-of|:last|:only|:empty|:target|:checked|::selection|:enabled|:disabled|:not|:placeholder|:host|::content|\/deep\/|::shadow|^,)/
  },
  units: {
    ch: false,
    rem: false,
    vh: false,
    vm: false,
    vmax: false,
    vmin: false,
    vw: false
  }
});

DEFAULTS.ie7 = merge(DEFAULTS.ie8, {
  properties: {
    ieBangHack: true
  },
  selectors: {
    ie7Hack: true,
    special: /(\-moz\-|\-ms\-|\-o\-|\-webkit\-|:focus|:before|:after|:root|:nth|:first\-of|:last|:only|:empty|:target|:checked|::selection|:enabled|:disabled|:not|:placeholder|:host|::content|\/deep\/|::shadow|^,)/
  },
});

function compatibility(source) {
  return merge(DEFAULTS['*'], calculateSource(source));
}

function merge(source, target) {
  for (var key in source) {
    var value = source[key];

    if (typeof value === 'object' && !util.isRegExp(value))
      target[key] = merge(value, target[key] || {});
    else
      target[key] = key in target ? target[key] : value;
  }

  return target;
}

function calculateSource(source) {
  if (typeof source == 'object')
    return source;

  if (!/[,\+\-]/.test(source))
    return DEFAULTS[source] || DEFAULTS['*'];

  var parts = source.split(',');
  var template = parts[0] in DEFAULTS ?
    DEFAULTS[parts.shift()] :
    DEFAULTS['*'];

  source = {};

  parts.forEach(function (part) {
    var isAdd = part[0] == '+';
    var key = part.substring(1).split('.');
    var group = key[0];
    var option = key[1];

    source[group] = source[group] || {};
    source[group][option] = isAdd;
  });

  return merge(template, source);
}

module.exports = compatibility;
<commit_msg>See #703 - adds `ie10` alias to default compatibility.<commit_after>var util = require('util');

var DEFAULTS = {
  '*': {
    colors: {
      opacity: true // rgba / hsla
    },
    properties: {
      backgroundClipMerging: false, // background-clip to shorthand
      backgroundOriginMerging: false, // background-origin to shorthand
      backgroundSizeMerging: false, // background-size to shorthand
      colors: true, // any kind of color transformations, like `#ff00ff` to `#f0f` or `#fff` into `red`
      fontWeight: true, // normal -> '400'
      ieBangHack: false, // !ie suffix hacks on IE<8
      iePrefixHack: false, // underscore / asterisk prefix hacks on IE
      ieSuffixHack: false, // \9 suffix hacks on IE6-9
      merging: true, // merging properties into one
      shorterLengthUnits: false, // optimize pixel units into `pt`, `pc` or `in` units
      spaceAfterClosingBrace: true, // 'url() no-repeat' to 'url()no-repeat'
      urlQuotes: false, // whether to wrap content of `url()` into quotes or not
      zeroUnits: true // 0[unit] -> 0
    },
    selectors: {
      adjacentSpace: false, // div+ nav Android stock browser hack
      ie7Hack: false, // *+html hack
      special: /(\-moz\-|\-ms\-|\-o\-|\-webkit\-|:dir\([a-z-]*\)|:first(?![a-z-])|:fullscreen|:left|:read-only|:read-write|:right|:placeholder|:host|:content|\/deep\/|:shadow|:selection|^,)/ // special selectors which prevent merging
    },
    units: {
      ch: true,
      in: true,
      pc: true,
      pt: true,
      rem: true,
      vh: true,
      vm: true, // vm is vmin on IE9+ see https://developer.mozilla.org/en-US/docs/Web/CSS/length
      vmax: true,
      vmin: true,
      vw: true
    }
  }
};

DEFAULTS.ie10 = DEFAULTS['*'];

DEFAULTS.ie9 = merge(DEFAULTS['*'], {
  properties: {
    ieSuffixHack: true
  }
});

DEFAULTS.ie8 = merge(DEFAULTS.ie9, {
  colors: {
    opacity: false
  },
  properties: {
    iePrefixHack: true,
    merging: false
  },
  selectors: {
    special: /(\-moz\-|\-ms\-|\-o\-|\-webkit\-|:root|:nth|:first\-of|:last|:only|:empty|:target|:checked|::selection|:enabled|:disabled|:not|:placeholder|:host|::content|\/deep\/|::shadow|^,)/
  },
  units: {
    ch: false,
    rem: false,
    vh: false,
    vm: false,
    vmax: false,
    vmin: false,
    vw: false
  }
});

DEFAULTS.ie7 = merge(DEFAULTS.ie8, {
  properties: {
    ieBangHack: true
  },
  selectors: {
    ie7Hack: true,
    special: /(\-moz\-|\-ms\-|\-o\-|\-webkit\-|:focus|:before|:after|:root|:nth|:first\-of|:last|:only|:empty|:target|:checked|::selection|:enabled|:disabled|:not|:placeholder|:host|::content|\/deep\/|::shadow|^,)/
  },
});

function compatibility(source) {
  return merge(DEFAULTS['*'], calculateSource(source));
}

function merge(source, target) {
  for (var key in source) {
    var value = source[key];

    if (typeof value === 'object' && !util.isRegExp(value))
      target[key] = merge(value, target[key] || {});
    else
      target[key] = key in target ? target[key] : value;
  }

  return target;
}

function calculateSource(source) {
  if (typeof source == 'object')
    return source;

  if (!/[,\+\-]/.test(source))
    return DEFAULTS[source] || DEFAULTS['*'];

  var parts = source.split(',');
  var template = parts[0] in DEFAULTS ?
    DEFAULTS[parts.shift()] :
    DEFAULTS['*'];

  source = {};

  parts.forEach(function (part) {
    var isAdd = part[0] == '+';
    var key = part.substring(1).split('.');
    var group = key[0];
    var option = key[1];

    source[group] = source[group] || {};
    source[group][option] = isAdd;
  });

  return merge(template, source);
}

module.exports = compatibility;
<|endoftext|>


<commit_before>const path = require('path');
const config = require('config');
const winston = require('winston');
const compose = require('koa-compose');
const webpackDevServer = require('koa-webpack-dev');

var middlewares = [];
var webpackConfig = path.join(config.structure.root, 'config', 'webpack');

winston.info('Initializing middlewares ...');

middlewares.push(webpackDevServer({ config: webpackConfig }));

module.exports = compose(middlewares);
<commit_msg>Update middleware config usage<commit_after>const path = require('path');
const config = require('config');
const winston = require('winston');
const compose = require('koa-compose');
const webpackDevServer = require('koa-webpack-dev');

var middlewares = [];
var webpackConfig = path.join(config.structure.config.build);

winston.info('Initializing middlewares ...');

middlewares.push(webpackDevServer({ config: webpackConfig }));

module.exports = compose(middlewares);
<|endoftext|>


<commit_before>import { useRouter } from "next/router";
import Head from "next/head";
import Link from "next/link";
import Meta from "../../components/Meta";
import classnames from "classnames";
import ErrorPage from "../404";
import {
  Container,
  Markdown,
  SingleColumn,
  Section,
  IntraNav,
  getPostBySlug,
  getPage,
  formatDate,
} from "@urbit/foundation-design-system";
import Header from "../../components/Header";
import Footer from "../../components/Footer";
import MetadataBlock from "../../components/ecosystem/MetadataBlock";
import ResourceCard from "../../components/gateway/ResourceCard";
import JoinGroup from "../../components/JoinGroup";
import ob from "urbit-ob";
import { DateTime } from "luxon";
import fs from 'fs';
import path, { join } from 'path';

export default function Grant({ post, markdown, match, search }) {
  const router = useRouter();
  if (!router.isFallback && !post?.slug) {
    return <ErrorPage />;
  }
  const isOpen = !post?.extra?.completed && post?.extra?.assignee?.[0] === "";
  const canApply = isOpen && post?.extra?.work_request_link;
  const assignee = post?.extra?.assignee;
  const mentor = post.extra.mentor || post.extra.champion;
  const assigneeLink =
    assignee &&
    assignee.map((each, index) => {
      return ob.isValidPatp(each) ? (
        <>
          {index ? ", " : ""}
          <Link href={`/ids/${each}`} passHref>
            {each}
          </Link>
        </>
      ) : (
        <>
          {index ? ", " : ""}
          {each}
        </>
      );
    });
  const mentorLink =
    mentor &&
    mentor.map((each, index) => {
      return ob.isValidPatp(each) ? (
        <>
          {index ? ", " : ""}
          <Link href={`/ids/${each}`} passHref>
            {each}
          </Link>
        </>
      ) : (
        <>
          {index ? ", " : ""}
          {each}
        </>
      );
    });

  let status = "";
  if (isOpen) {
    status = "Open"
  } else if (post?.extra?.completed) {
    status = "Completed"
  } else if (post?.extra?.canceled) {
    status = "Canceled"
  } else {
    status = "In Progress"
  }
  const statusBadge =

    {status}

;

  let deliverable = null;
  if (post.extra.deliverable) {
    if (match) {
      deliverable = <ResourceCard
        title={match.data.title}
        image={match.data.image}
        color={match.data.bgColor || "#000000"}
        description={match.data?.description || ""}
        type="application"
        shortcode={post.extra.deliverable}
        full
      />
    }
    else if (post.extra.deliverable.startsWith("~")) {
      deliverable = <JoinGroup emphasize groupName={post.extra.deliverable} />
    } else {
      deliverable = {post.extra.deliverable}
    }
  }

  const metaPost = Object.assign({}, post);
  metaPost.title = `${post.title} - Grant`;

  return (
    <Container>

        <title>{post.title} - Grant</title>
        {Meta(metaPost)}

      <IntraNav ourSite="https://urbit.org" search={search} />
      <SingleColumn>

{post.title}

            {statusBadge}
            {post.taxonomies.grant_type.map((category) => {
              const className = classnames({
                "bg-blue-400 text-white": category === "Proposal",
                "bg-green-400 text-white": category === "Apprenticeship",
                "bg-yellow-300": category === "Bounty",
              });
              return (
                <div className={`${className} badge-sm mr-1 my-1`}>
                  {category}

              );
            })}
            {post.taxonomies.grant_category.map((category) => (

                {category}

            ))}

            {post?.extra?.grant_id ? (
              <>
                <MetadataBlock
                  title="ID"
                  content={post.extra.grant_id}
                />
              </>
            ) : null}
            <MetadataBlock
              title="Date"
              content={formatDate(DateTime.fromISO(post.date))}
            />
            {post.extra.mentor ? (
              <MetadataBlock
                title="Mentor"
                content={mentorLink}
              />
            ) : null}
            {post.extra.champion ? (
              <MetadataBlock
                title="Champion"
                content={mentorLink}
              />
            ) : null}
            {post.extra.assignee ? (
              <MetadataBlock
                title="Grantee(s)"
                content={assigneeLink}
              />
            ) : null}

          {post?.extra?.link?.startsWith("~") &&

Group

            <JoinGroup emphasize groupName={post.extra.link} />

}
          {deliverable &&

Deliverable

            {deliverable}

}

          <Markdown.render content={JSON.parse(markdown)} />

        {canApply && (

            Apply for this grant

        )}
      </SingleColumn>

    </Container>
  );
}

export async function getStaticProps({ params }) {
  // Gets post in any year folder sharing the slug name in the param
  const basePath = join(process.cwd(), 'content/grants')
  const years = fs.readdirSync(basePath, { 'withFileTypes': true }).filter((f) => f.isDirectory());
  const dir = years.find((year) => {
    const yearDir = fs.readdirSync(join(basePath, year.name), { 'withFileTypes': true });
    return yearDir.some((file) => file.name === `${params.slug}.md`)
  });
  const post = getPostBySlug(
    params.slug,
    ["title", "slug", "date", "description", "content", "extra", "taxonomies"],
    `grants/${dir.name}`
  )

  const markdown = JSON.stringify(Markdown.parse({ post }));

  // Matches deliverable to page
  let match = null;
  if (post?.extra?.deliverable?.startsWith("~")) {
    const ship = post.extra.deliverable.split("/")[0];
    const application = post.extra.deliverable.split("/")[1];
    const fileExists = fs.existsSync(path.join(process.cwd(), "content/applications", ship, `${application}.md`));
    match = fileExists ? getPage(
      join(
        process.cwd(),
        "content/applications",
        post.extra.deliverable
      )
    ) : null
  }
  return {
    props: { post, markdown, match },
  };
}

export async function getStaticPaths() {
  const basePath = join(process.cwd(), 'content/grants')
  const years = fs.readdirSync(basePath, { 'withFileTypes': true });
  const posts = years.filter((year) => year.isDirectory()).map((year) => {
    const yearDir = fs.readdirSync(join(basePath, year.name), { 'withFileTypes': true });
    return yearDir.filter((entry) => entry.isFile()).map((entry) => entry.name.replace(/\.md$/, ""))
  }).flat()

  return {
    paths: posts.map((post) => {
      return {
        params: {
          slug: post,
        },
      };
    }),
    fallback: false,
  };
}
<commit_msg>grants: pull grantYear search into lib<commit_after>import { useRouter } from "next/router";
import Head from "next/head";
import Link from "next/link";
import Meta from "../../components/Meta";
import classnames from "classnames";
import ErrorPage from "../404";
import {
  Container,
  Markdown,
  SingleColumn,
  Section,
  IntraNav,
  getPostBySlug,
  getPage,
  formatDate,
} from "@urbit/foundation-design-system";
import Header from "../../components/Header";
import Footer from "../../components/Footer";
import MetadataBlock from "../../components/ecosystem/MetadataBlock";
import ResourceCard from "../../components/gateway/ResourceCard";
import JoinGroup from "../../components/JoinGroup";
import ob from "urbit-ob";
import { DateTime } from "luxon";
import fs from 'fs';
import path, { join } from 'path';
import { getGrantYear } from "../../lib/lib";

export default function Grant({ post, markdown, match, search }) {
  const router = useRouter();
  if (!router.isFallback && !post?.slug) {
    return <ErrorPage />;
  }
  const isOpen = !post?.extra?.completed && post?.extra?.assignee?.[0] === "";
  const canApply = isOpen && post?.extra?.work_request_link;
  const assignee = post?.extra?.assignee;
  const mentor = post.extra.mentor || post.extra.champion;
  const assigneeLink =
    assignee &&
    assignee.map((each, index) => {
      return ob.isValidPatp(each) ? (
        <>
          {index ? ", " : ""}
          <Link href={`/ids/${each}`} passHref>
            {each}
          </Link>
        </>
      ) : (
        <>
          {index ? ", " : ""}
          {each}
        </>
      );
    });
  const mentorLink =
    mentor &&
    mentor.map((each, index) => {
      return ob.isValidPatp(each) ? (
        <>
          {index ? ", " : ""}
          <Link href={`/ids/${each}`} passHref>
            {each}
          </Link>
        </>
      ) : (
        <>
          {index ? ", " : ""}
          {each}
        </>
      );
    });

  let status = "";
  if (isOpen) {
    status = "Open"
  } else if (post?.extra?.completed) {
    status = "Completed"
  } else if (post?.extra?.canceled) {
    status = "Canceled"
  } else {
    status = "In Progress"
  }
  const statusBadge =

    {status}

;

  let deliverable = null;
  if (post.extra.deliverable) {
    if (match) {
      deliverable = <ResourceCard
        title={match.data.title}
        image={match.data.image}
        color={match.data.bgColor || "#000000"}
        description={match.data?.description || ""}
        type="application"
        shortcode={post.extra.deliverable}
        full
      />
    }
    else if (post.extra.deliverable.startsWith("~")) {
      deliverable = <JoinGroup emphasize groupName={post.extra.deliverable} />
    } else {
      deliverable = {post.extra.deliverable}
    }
  }

  const metaPost = Object.assign({}, post);
  metaPost.title = `${post.title} - Grant`;

  return (
    <Container>

        <title>{post.title} - Grant</title>
        {Meta(metaPost)}

      <IntraNav ourSite="https://urbit.org" search={search} />
      <SingleColumn>

{post.title}

            {statusBadge}
            {post.taxonomies.grant_type.map((category) => {
              const className = classnames({
                "bg-blue-400 text-white": category === "Proposal",
                "bg-green-400 text-white": category === "Apprenticeship",
                "bg-yellow-300": category === "Bounty",
              });
              return (
                <div className={`${className} badge-sm mr-1 my-1`}>
                  {category}

              );
            })}
            {post.taxonomies.grant_category.map((category) => (

                {category}

            ))}

            {post?.extra?.grant_id ? (
              <>
                <MetadataBlock
                  title="ID"
                  content={post.extra.grant_id}
                />
              </>
            ) : null}
            <MetadataBlock
              title="Date"
              content={formatDate(DateTime.fromISO(post.date))}
            />
            {post.extra.mentor ? (
              <MetadataBlock
                title="Mentor"
                content={mentorLink}
              />
            ) : null}
            {post.extra.champion ? (
              <MetadataBlock
                title="Champion"
                content={mentorLink}
              />
            ) : null}
            {post.extra.assignee ? (
              <MetadataBlock
                title="Grantee(s)"
                content={assigneeLink}
              />
            ) : null}

          {post?.extra?.link?.startsWith("~") &&

Group

            <JoinGroup emphasize groupName={post.extra.link} />

}
          {deliverable &&

Deliverable

            {deliverable}

}

          <Markdown.render content={JSON.parse(markdown)} />

        {canApply && (

            Apply for this grant

        )}
      </SingleColumn>

    </Container>
  );
}

export async function getStaticProps({ params }) {
  // Gets post in any year folder sharing the slug name in the param
  const dir = getGrantYear(params.slug);
  const post = getPostBySlug(
    params.slug,
    ["title", "slug", "date", "description", "content", "extra", "taxonomies"],
    `grants/${dir.name}`
  )

  const markdown = JSON.stringify(Markdown.parse({ post }));

  // Matches deliverable to page
  let match = null;
  if (post?.extra?.deliverable?.startsWith("~")) {
    const ship = post.extra.deliverable.split("/")[0];
    const application = post.extra.deliverable.split("/")[1];
    const fileExists = fs.existsSync(path.join(process.cwd(), "content/applications", ship, `${application}.md`));
    match = fileExists ? getPage(
      join(
        process.cwd(),
        "content/applications",
        post.extra.deliverable
      )
    ) : null
  }
  return {
    props: { post, markdown, match },
  };
}

export async function getStaticPaths() {
  // Flatten all year subfolders into a flat array of slugs
  const basePath = join(process.cwd(), 'content/grants')
  const years = fs.readdirSync(basePath, { 'withFileTypes': true });
  const posts = years.filter((year) => year.isDirectory()).map((year) => {
    const yearDir = fs.readdirSync(join(basePath, year.name), { 'withFileTypes': true });
    return yearDir.filter((entry) => entry.isFile()).map((entry) => entry.name.replace(/\.md$/, ""))
  }).flat()

  return {
    paths: posts.map((post) => {
      return {
        params: {
          slug: post,
        },
      };
    }),
    fallback: false,
  };
}
<|endoftext|>


<commit_before>const weatherIcons = {
  chanceflurries: 'snow',
  chancerain: 'rain-chance',
  chancesleet: 'sleet-chance',
  chancesnow: 'snow',
  chancetstroms: 'tstorm-chance',
  clear: 'clear',
  cloudy: 'cloudy',
  flurries: 'snow',
  hazy: 'haze-fog',
  fog: 'haze-fog',
  mostlycloudy: 'cloudy-mostly',
  mostlysunny: 'cloudy-partly',
  partlycloudy: 'cloudy-partly',
  partlysunny: 'cloudy-partly',
  rain: 'rain',
  sleet: 'sleet',
  snow: 'snow',
  sunny: 'clear',
  tstorms: 'tstorm',
  nt_chanceflurries: 'snow',
  nt_chancerain: 'rain-chance',
  nt_chancesleet: 'sleet-chance',
  nt_chancesnow: 'snow',
  nt_chancetstroms: 'tstorm-chance',
  nt_clear: 'clear',
  nt_cloudy: 'cloudy',
  nt_flurries: 'snow',
  nt_hazy: 'haze-fog',
  nt_fog: 'haze-fog',
  nt_mostlycloudy: 'cloudy-mostly-night',
  nt_mostlysunny: 'cloudy-partly-night',
  nt_partlycloudy: 'cloudy-partly-night',
  nt_partlysunny: 'cloudy-partly-night',
  nt_rain: 'rain',
  nt_sleet: 'sleet',
  nt_snow: 'snow',
  nt_sunny: 'clear',
  nt_tstorms: 'tstorm',
};

export default weatherIcons;
<commit_msg>fix name of nighttime clear icon<commit_after>const weatherIcons = {
  chanceflurries: 'snow',
  chancerain: 'rain-chance',
  chancesleet: 'sleet-chance',
  chancesnow: 'snow',
  chancetstorms: 'tstorm-chance',
  clear: 'clear',
  cloudy: 'cloudy',
  flurries: 'snow',
  hazy: 'haze-fog',
  fog: 'haze-fog',
  mostlycloudy: 'cloudy-mostly',
  mostlysunny: 'cloudy-partly',
  partlycloudy: 'cloudy-partly',
  partlysunny: 'cloudy-partly',
  rain: 'rain',
  sleet: 'sleet',
  snow: 'snow',
  sunny: 'clear',
  tstorms: 'tstorm',
  nt_chanceflurries: 'snow',
  nt_chancerain: 'rain-chance',
  nt_chancesleet: 'sleet-chance',
  nt_chancesnow: 'snow',
  nt_chancetstroms: 'tstorm-chance',
  nt_clear: 'clear-night',
  nt_cloudy: 'cloudy',
  nt_flurries: 'snow',
  nt_hazy: 'haze-fog',
  nt_fog: 'haze-fog',
  nt_mostlycloudy: 'cloudy-mostly-night',
  nt_mostlysunny: 'cloudy-partly-night',
  nt_partlycloudy: 'cloudy-partly-night',
  nt_partlysunny: 'cloudy-partly-night',
  nt_rain: 'rain',
  nt_sleet: 'sleet',
  nt_snow: 'snow',
  nt_sunny: 'clear',
  nt_tstorms: 'tstorm',
  '': 'unknown'
};

export default weatherIcons;
<|endoftext|>