<commit_before>/*
 * Responsible for making the ds object:
 *
 * ds is { c : {min, max}, d: {min,max}}
 */
var _ = require('underscore');
var utils = require('./utils.cs.js');

/* If no marginsO are defined, here are the rules:
 *  - ticks and ticks labels are 20 px in the y dir (height of text),
 *			40 px in the x dir (length of text).
 *  - we take a 10px margin on title and labels
 *  - bottom and right margin:
 *			- 20px + ({x,y}LabelFSize + 10 px) if a {x,y}Label is defined,
 *  - top and left margin:
 *			- 20px + ({x,y}LabelFSize	+ 10 px) if a {x,y}Label is defined,
 *  - top margin takes a titleFSize + 10px more if a title is defined
 */
var defaults = {
	axis: {
		label: {
			x: 20,
			y: 20,
			mar: 10
		},
		ticks: {
			y: 20,
			X: 40
		}
	},
	title: 10,
	min: 0,
	max: 4
};

var roundDWorld = function(dWorld,isDate){

	var min = dWorld.min;
	var max = dWorld.max;
	var om = utils.orderMag(max - min);

	return {
		min: (isDate)? utils.date.closestRound(min,om,'down'):utils.nbr.closestRound(min,om,'down'),
		max: (isDate)? utils.date.closestRound(max,om,'up'):utils.nbr.closestRound(max,om,'up'),
	};

};

var m = {};

/* universe is {width , height}, this
 * is the total size of the svg picture.
 * The goal here is to compute the
 * world, i.e. the printed area
 *
 *				width
 * <------------------------>
 *  ________________________
 * |                        | ^
 * |   title/top axis       | |
 * |    ________________    | |
 * |   |                |   | |
 * |   |                |   | |
 * | 1 |                | 2 | |
 * |   |     WORLD      |   | | height
 * |   |                |   | |
 * |   |                |   | |
 * |   |________________|   | |
 * |                        | |
 * |   bottom axis          | |
 * |________________________| |
 *										^
 * 1 - left axis
 * 2 - right axis
 *
 *
 */

/*
 * We need to know some stuff to compute the margins:
 *
 *
 * title = {
 *  title: '',
 *  titleFSize: 30
 * } if given
 *
 * universe = in coordinate space, length
 *
 * borders = {
 *  axis: [{label: '', labelFSize: 15, placement: left}],
 *  marginsO: {l: 0,  r: 0},
 *  marginsI: {l: 10, r: 10}
 * } or
 * borders = {
 *  axis: [{label: '', labelFSize: 15, placement: bottom}],
 *  marginsO: {t: 0,  b: 0},
 *  marginsI: {t: 10, b: 10}
 * }
 *
 * marginsO is for the outer margin, it overrides any
 * computations of them du to title and axis definitions.
 * marginsI are the inner margins we add to the world to
 * have a more aesthetic view.
 *
 * If no marginsO are defined, here are the rules:
 *  - ticks and ticks labels are 20 px in the y dir (height of text),
 *			40 px in the x dir (length of text).
 *  - we take a 10px margin on title and labels
 *  - bottom and right margin:
 *			- 20px + ({x,y}LabelFSize + 10 px) if a {x,y}Label is defined,
 *  - top and left margin:
 *			- 20px + ({x,y}LabelFSize	+ 10 px) if a {x,y}Label is defined,
 *  - top margin takes a titleFSize + 10px more if a title is defined
 *
 * Then the data space is extended to the inner margin values,
 * then the data space can be even more extended to reach round values.
 *
 *	datas: {series:[{x:0, y:0}], stacked:'y', type:{ abs: 'number', ord: 'number'}], //
 *
 *
 * the cs/ds correspondance is found with:
 *    universe - marginsO - marginsI = datas
 */
var space = function(datas,universe,borders,title){
	// 1 - the coordinate space

		// get the (right,left) or (top,bottom)
		var places = [];
		for(var p in borders.marginsO){
			places.push(p);
		}

		// compute the world
		// universe-world margins
		// min and max of coord space
		// margins between borders and axis
		var margins = {};
		for(p  = 0; p < places.length; p++){
			margins[places[p]] = 0;
		}

		// fetch the margin (label + default) for an axis
		var margin = function(axis){
			var marg = defaults.axis[axis.placement];
			if(axis.label.length !== 0){
			marg += ( axis.labelFSize + defaults.axis.mar );
			}
			return marg;
		};

		// labels
		for(var l = 0; l < borders.axis.length; l++){
			var key = borders.axis[l].placement;
			margins[key] = Math.max(margins[key],margin(borders.axis[l]));
		}

		// title is at the top
		if(!!margins.top && !!title){
			margins.top += (title.length !== 0)?title.titleFSize + defaults.title:0;
		}

		// more suppleness, but less
		// efficiencies: automatic
		// margins computed whatever
		// happens, overwrite here
		// if defined
		for(p = 0; p < places.length; p++){
			var k = places[p];
			if(!utils.isNil(borders.marginsO[k])){
				margins[k] = borders.marginsO[k];
			}
		}

		// we have the world's corners
		// the transformation between data space and the world space is
		// given by data space scaled to (world size - inner margins) and
		// placed at (origin.x.x + inner x margin, origin.y.y - inner y margin)
		var min, max;
		var rmin, rmax;
		if(!!margins.left){
			min = margins.left;
			max = universe - margins.right;
			rmin = min + borders.marginsI.left;
			rmax = max - borders.marginsI.right;
		}else{
			min = universe - margins.bottom;
			max = margins.top;
			rmin = min - borders.marginsI.bottom;
			rmax = max + borders.marginsI.top;
		}

		var cWorld = {
			min: min,
			max: max
		};
		var rawCWorld = {
			min: rmin,
			max: rmax
		};

	// 2 - the data space
	// either data defined or explicitely defined
		var minVals = (vals) => {
			return utils.isDate(vals[0])? utils.date.min(vals) : utils.nbr.min(vals);
		};
		var maxVals = (vals) => {
			return utils.isDate(vals[0])? utils.date.max(vals) : utils.nbr.max(vals);
		};

		var bounds = {
			min: minVals(datas),
			max: maxVals(datas)
		};
		// empty graph
		if(!isFinite(bounds.min)){
			bounds.min = 0;
		}
		if(!isFinite(bounds.max)){
			bounds.max = 4;
		}

		var multiply = (val,fac) => {
			return ( utils.isDate(val) ) ?  new Date(val.getTime() * fac):val * fac;
		};

		var subtract = (val1,val2) => {
			return ( utils.isDate(val1) ) ?  val1.getTime() - val2.getTime() : val1 - val2;
		};

		var divide = (val,fac) => {
			return ( utils.isDate(val) ) ?  val.getTime() / fac : val / fac;
		};

		// règle de trois
		var rawDWorld = {
			min: multiply(bounds.min, cWorld.min / rawCWorld.min),
			max: multiply(bounds.max, cWorld.max / rawCWorld.max)
		};

		var isDate = (!!_.find(datas, (value) => {return utils.isDate(value);}))?true:false;
		var dWorld = roundDWorld(rawDWorld,isDate);

/**
 * ds is {
    c : {
      min,
      max
    },
    d: {
      min,
      max
    },
    c2d ,
    d2c
  }
*/
		return {
			c: {
				min: cWorld.min,
				max: cWorld.max,
			},
			d: {
				min: dWorld.min,
				max: dWorld.max,
			},
			d2c: divide(cWorld.max - cWorld.min, subtract( dWorld.max , dWorld.min ) ),
			c2d: divide ( subtract(dWorld.max, dWorld.min) , cWorld.max - cWorld.min )
		};

};

m.spaces = function(datas,universe,borders,title){

	var filter = (datas,dir) => {
		return _.map(datas, (serie) => {
			return _.map(serie.series, (point,idx) => {
				return (utils.isString(point[dir]))?idx:point[dir];
				});
			});
	};

	// worlds = (l,b), (l,t), (r,b), (r,t)
	var rights = filter(_.filter(datas,(series) => {return !!series.ord            && series.ord.axis === 'right';}),  'y');
	var lefts  = filter(_.filter(datas,(series) => {return utils.isNil(series.ord) || series.ord.axis === 'left';}),   'y');
	var top    = filter(_.filter(datas,(series) => {return !!series.abs            && series.abs.axis === 'top';}),    'x');
	var bottom = filter(_.filter(datas,(series) => {return utils.isNil(series.abs) || series.abs.axis === 'bottom';}), 'x');

	var bordersy = {
		marginsO: {top: borders.marginsO.top, b: borders.marginsO.bottom},
		marginsI: {top: borders.marginsI.top, b: borders.marginsI.bottom},
		axis: borders.abs
	};

	var bordersx = {
		marginsO: {left: borders.marginsO.left, right: borders.marginsO.right},
		marginsI: {left: borders.marginsI.left, right: borders.marginsI.right},
		axis: borders.ord
	};

	return {
		y: {
			left:  space(lefts, universe.height,bordersy,title),
			right: space(rights,universe.height,bordersy,title)
		},
		x: {
			bottom: space(bottom,universe.width,bordersx),
			top:    space(top,   universe.width,bordersx)
		}
	};
};

module.exports = m;
<commit_msg>calculations of the spaces is done, corrections are at a good level<commit_after>/*
 * Responsible for making the ds object:
 *
 * ds is { c : {min, max}, d: {min,max}}
 */
var _ = require('underscore');
var utils = require('./utils.cs.js');

/* If no marginsO are defined, here are the rules:
 *  - ticks and ticks labels are 20 px in the y dir (height of text),
 *			40 px in the x dir (length of text).
 *  - we take a 10px margin on title and labels
 *  - bottom and right margin:
 *			- 20px + ({x,y}LabelFSize + 10 px) if a {x,y}Label is defined,
 *  - top and left margin:
 *			- 20px + ({x,y}LabelFSize	+ 10 px) if a {x,y}Label is defined,
 *  - top margin takes a titleFSize + 10px more if a title is defined
 */
var defaults = {
	axis: {
		label: {
			bottom: 20,
			top: 20,
			left: 20,
			right: 20,
			mar: 10
		},
		ticks: {
			left: 20,
			right: 20,
			bottom: 40,
			top: 40
		}
	},
	title: 10,
	min: 0,
	max: 4
};

var m = {};

/* universe is {width , height}, this
 * is the total size of the svg picture.
 * The goal here is to compute the
 * world, i.e. the printed area
 *
 *				width
 * <------------------------>
 *  ________________________
 * |                        | ^
 * |   title/top axis       | |
 * |    ________________    | |
 * |   |                |   | |
 * |   |                |   | |
 * | 1 |                | 2 | |
 * |   |     WORLD      |   | | height
 * |   |                |   | |
 * |   |                |   | |
 * |   |________________|   | |
 * |                        | |
 * |   bottom axis          | |
 * |________________________| |
 *										^
 * 1 - left axis
 * 2 - right axis
 *
 *
 */

/*
 * We need to know some stuff to compute the margins:
 *
 *
 * title = {
 *  title: '',
 *  titleFSize: 30
 * } if given
 *
 * universe = in coordinate space, length
 *
 * borders = {
 *  axis: [{label: '', labelFSize: 15, placement: left}],
 *  marginsO: {l: 0,  r: 0},
 *  marginsI: {l: 10, r: 10}
 * } or
 * borders = {
 *  axis: [{label: '', labelFSize: 15, placement: bottom}],
 *  marginsO: {t: 0,  b: 0},
 *  marginsI: {t: 10, b: 10}
 * }
 *
 * marginsO is for the outer margin, it overrides any
 * computations of them du to title and axis definitions.
 * marginsI are the inner margins we add to the world to
 * have a more aesthetic view.
 *
 * If no marginsO are defined, here are the rules:
 *  - ticks and ticks labels are 20 px in the y dir (height of text),
 *			40 px in the x dir (length of text).
 *  - we take a 10px margin on title and labels
 *  - bottom and right margin:
 *			- 20px + ({x,y}LabelFSize + 10 px) if a {x,y}Label is defined,
 *  - top and left margin:
 *			- 20px + ({x,y}LabelFSize	+ 10 px) if a {x,y}Label is defined,
 *  - top margin takes a titleFSize + 10px more if a title is defined
 *
 * Then the data space is extended to the inner margin values,
 * then the data space can be even more extended to reach round values.
 *
 *	datas: {series:[{x:0, y:0}], stacked:'y', type:{ abs: 'number', ord: 'number'}], //
 *
 *
 * the cs/ds correspondance is found with:
 *    universe - marginsO - marginsI = datas
 */
var space = function(datas,universe,borders,title){
		// if no data, we don't waste time
		if(datas.length === 0){
			return null;
		}

	// 1 - the coordinate space

		// get the (right,left) or (top,bottom)
		var places = [];
		for(var p in borders.marginsO){
			places.push(p);
		}

		// compute the world
		// universe-world margins
		// min and max of coord space
		// margins between borders and axis
		var margins = {};
		for(p  = 0; p < places.length; p++){
			margins[places[p]] = 0;
		}

		// fetch the margin (label + ticks + default) for an axis
		var margin = function(axis){
			var marg = defaults.axis.label[axis.placement];
			if(!axis.empty){
				marg += defaults.axis.ticks[axis.placement];
			}
			if(axis.label.length !== 0){
			marg += ( axis.labelFSize + defaults.axis.label.mar );
			}
			return marg;
		};

		// labels
		for(var l = 0; l < borders.axis.length; l++){
			var key = borders.axis[l].placement;
			margins[key] = Math.max(margins[key],margin(borders.axis[l]));
		}

		// title is at the top
		if(!!margins.top && !!title){
			margins.top += (title.length !== 0)?title.titleFSize + defaults.title:0;
		}

		// more suppleness, but less
		// efficiencies: automatic
		// margins computed whatever
		// happens, overwrite here
		// if defined
		for(p = 0; p < places.length; p++){
			var k = places[p];
			if(!utils.isNil(borders.marginsO[k])){
				margins[k] = borders.marginsO[k];
			}
		}

		// we have the world's corners
		// the transformation between data space and the world space is
		// given by data space scaled to (world size - inner margins) and
		// placed at (origin.x.x + inner x margin, origin.y.y - inner y margin)
		var min, max;
		var rmin, rmax;
		if(utils.isNil(margins.left)){
			min = universe - margins.bottom;
			max = margins.top;
			rmin = min - borders.marginsI.bottom;
			rmax = max + borders.marginsI.top;
		}else{
			min = margins.left;
			max = universe - margins.right;
			rmin = min + borders.marginsI.left;
			rmax = max - borders.marginsI.right;
		}

		var cWorld = {
			min: min,
			max: max
		};
		var rawCWorld = {
			min: rmin,
			max: rmax
		};

	// 2 - the data space

		var allValues = _.flatten(datas);

		var mgr = (allValues.length === 0)?null:utils.mgr(allValues[0]);

	// either data defined or explicitely defined
		var minVals = (vals) => {
      if(vals.length === 0){
        return null;
      }

			return mgr.min(vals);
		};

		var maxVals = (vals) => {
      if(vals.length === 0){
        return null;
      }

			return mgr.max(vals);
		};

		var bounds = {
			min: minVals(allValues),
			max: maxVals(allValues)
		};
		// empty graph
		if(!isFinite(bounds.min)){
			bounds.min = 0;
		}
		if(!isFinite(bounds.max)){
			bounds.max = 4;
		}

		var multiply = (val,fac) => {
			return ( utils.isDate(val) ) ?  new Date(val.getTime() * fac):val * fac;
		};

		var subtract = (val1,val2) => {
			return ( utils.isDate(val1) ) ?  val1.getTime() - val2.getTime() : val1 - val2;
		};

		var divide = (val,fac) => {
			return ( utils.isDate(val) ) ?  val.getTime() / fac : val / fac;
		};

		// règle de trois
		var dWorld = {
			min: multiply(bounds.min, 1 - Math.abs( (cWorld.min - rawCWorld.min) / (rawCWorld.max - rawCWorld.min) ) ),
			max: multiply(bounds.max, 1 + Math.abs( (cWorld.max - rawCWorld.max) / (rawCWorld.max - rawCWorld.min) ) )
		};

/**
 * ds is {
    c : {
      min,
      max
    },
    d: {
      min,
      max
    },
    c2d ,
    d2c
  }
*/
		return {
			c: {
				min: cWorld.min,
				max: cWorld.max,
			},
			d: {
				min: dWorld.min,
				max: dWorld.max,
			},
			d2c: divide(cWorld.max - cWorld.min, subtract( dWorld.max , dWorld.min ) ),
			c2d: divide ( subtract(dWorld.max, dWorld.min) , cWorld.max - cWorld.min )
		};

};

m.spaces = function(datas,universe,borders,title){

	var filter = (datas,dir) => {
		return _.map(datas, (serie) => {
			return _.map(serie.series, (point,idx) => {
				return (utils.isString(point[dir]))?idx:point[dir];
				});
			});
	};

	// worlds = (l,b), (l,t), (r,b), (r,t)
	var rights = filter(_.filter(datas,(series) => {return !!series.ord            && series.ord.axis === 'right';}),  'y');
	var lefts  = filter(_.filter(datas,(series) => {return utils.isNil(series.ord) || series.ord.axis === 'left';}),   'y');
	var top    = filter(_.filter(datas,(series) => {return !!series.abs            && series.abs.axis === 'top';}),    'x');
	var bottom = filter(_.filter(datas,(series) => {return utils.isNil(series.abs) || series.abs.axis === 'bottom';}), 'x');

	var bordersy = {
		marginsO: {top: borders.marginsO.top, bottom: borders.marginsO.bottom},
		marginsI: {top: borders.marginsI.top, bottom: borders.marginsI.bottom},
		axis: borders.abs
	};

	var bordersx = {
		marginsO: {left: borders.marginsO.left, right: borders.marginsO.right},
		marginsI: {left: borders.marginsI.left, right: borders.marginsI.right},
		axis: borders.ord
	};

	return {
		y: {
			left:  space(lefts, universe.height,bordersy,title),
			right: space(rights,universe.height,bordersy,title)
		},
		x: {
			bottom: space(bottom,universe.width,bordersx),
			top:    space(top,   universe.width,bordersx)
		}
	};
};

module.exports = m;
<|endoftext|>


<commit_before>// namespace
var MPLAY = MPLAY || {};

(function() {
	"use_strict";

	/**
	 *
	 * @class Page1_1
	 * @augments MPLAY.MPlayPage
	 */
	var Page1_1 = function() {
		MPLAY.MPlayPage.call(this);
	};

	Page1_1.prototype = Object.create(MPLAY.MPlayPage.prototype);
	Page1_1.prototype.constructor = Page1_1;

	/**
	 * @override
	 */
	Page1_1.prototype._onLoad = function() {
		MPLAY.MPlayPage.prototype._onLoad.call(this);

		this.setBackground("/static/gnovel/res/textures/backgrounds/uc final layers png.png");

		//create images
		this._priyaImg = this.createImage("/static/gnovel/res/textures/char/thoughtful-julia.png", new THREE.Vector3(-300, -140, 120), 600, 825);
		this._ryanImg = this.createImage("/static/gnovel/res/textures/char/ryan-happy.png", new THREE.Vector3(0, -110, 140), 600, 923);
		this._catImg = this.createImage("/static/gnovel/res/textures/char/cat-neutral.png", new THREE.Vector3(450, -130, 100), 600, 799);

		this._talked = 0;

		var pageObj = this;
		var io1 = this.createInteractableObject(
			"/static/gnovel/res/textures/Perspective-Button-Stop-icon.png",
			{x: -100, y: 200, width : 64, height : 64, onClick: function() {
				pageObj._talked = 1;
				pageObj._runFlow();
			}});

		var io2 = this.createInteractableObject(
			"/static/gnovel/res/textures/Perspective-Button-Stop-icon.png",
			{x: 100, y: 200, width : 64, height : 64, onClick: function() {
				pageObj._talked = 2;
				pageObj._runFlow();
			}});

		this._priyaImg.material.opacity = 0;
		this._ryanImg.material.opacity = 0;
		this._catImg.material.opacity = 0;

		this._priya = "priya";
		this._ryan = "ryan";
		this._cat = "cat";

		// add object tags
		this._setObjectTag(this._priya, this._priyaImg);
		this._setObjectTag(this._ryan, this._ryanImg);
		this._setObjectTag(this._cat, this._catImg);

	};

	Page1_1.prototype._createFlowElements = function() {
		var priya = "%priya";
		var ryan = "%ryan";
		var cat = "%cat";
		var o = null;
		// variables from scene 1
		var isPhonePickedUp = 1;
		var isPhoneWithYou = 0;
		// player name which the player entered at the beginning of the game
		var player = "Lindsey";
		// this._talked = 1;

		if(this._talked == 0) {
			o = [
				// transition of this flow doesn't work
				{type: "show", img: ryan, position: "center", waitUntilShown: false},
				{type: "dialog", speaker: "Ryan", text: "Awesome! Both you and Priya are in my group. This is Priya. She’s super smart, speaks like a bajillion languages. Too cool for me."},
				// transition of this flow doesn't work
				{type: "hide", img: ryan, waitUntilHidden: false},
				// transition of this flow doesn't work
				{type: "show", img: priya, position: "left", waitUntilShown: false},
				{type: "dialog", speaker: "Priya", text: "RYAN here helped me with some of my writing last semester. Always willing to be my study partner. I think I annoyed him most of the time. Anyway, nice to meet you"},
				// transition of this flow doesn't work
				{type: "hide", img: priya, waitUntilHidden: false},
				// transition of this flow doesn't work
				{type: "show", img: cat, position: "right", waitUntilShown: false, flip: true},
				{type: "dialog", speaker: "Cat", text: "Hey I’m Cat. I’m in Tepper. I think I’m going to be in over my head a little here in a CS class It’s been an adjustment coming back to school."},
				{type: "hide", img: cat, waitUntilHidden: false, flip: true},
				{type: "show", img: ryan, position: "center", waitUntilShown: false},
				{type: "dialog", speaker: "Ryan", text: "Oh, don’t sweat it, Cat. We’ll help you out if you get stuck."},
				{type: "hide", img: ryan, waitUntilHidden: false},
				{type: "show", img: cat, waitUntilShown: false, flip: true},
				{type: "dialog", speaker: "Cat", text: "Sorry - I’m a little all over the place. I lost my phone yesterday."},
				{type: "hide", img: cat, waitUntilHidden: false, flip: true},
				{type: "compare", leftop: isPhonePickedUp, operator: "equal", rightop: 1, goTrue: "#phone_picked", goFalse: "#phone_notpicked"},
				{type: "show", img: ryan, label: "phone_picked", waitUntilShown: false},
				{type: "dialog", speaker: "Ryan", text: "Were you at Scottie’s Bar yesterday? " + player +" found a phone there."},
				{type: "hide", img: ryan, waitUntilHidden: false},
				{type: "show", img: cat, waitUntilShown: false, flip: true},
				{type: "dialog", speaker: "Cat", text: "Oh my God, do you guys have it with you?"},
				{type: "hide", img: cat, waitUntilHidden: false, flip: true},
				{type: "show", img: ryan, waitUntilShown: false},
				{type: "compare", leftop: isPhoneWithYou, operator: "equal", rightop: 1, goTrue: "#phone_withyou", goFalse: "#phone_notwithyou"},
				{type: "dialog", speaker: "Ryan", text: "Yeah, " + player + " has it, right?", label: "phone_withyou"},
				{type: "hide", img: ryan, waitUntilHidden: false},
				{type: "show", img: cat, waitUntilShown: false, flip: true},
				{type: "dialog", speaker: "Cat", text: "Oh my God - you charged it too? You’ve totally restored my faith in humanity."},
				{type: "jump", condition: true, goTrue: "#choices", goFalse: 1000},
				{type: "dialog", speaker: "Ryan", text: "We left it with the bartender.", label: "phone_notwithyou"},
				{type: "hide", img: ryan, waitUntilHidden: false},
				{type: "show", img: cat, waitUntilShown: false, flip: true},
				{type: "dialog", speaker: "Cat", text: "Thank you! I’ll run over there after this. Lifesaver!"},
				{type: "choices", choices : [{text: "No Problem.", go: "#hidecat", relationship: {name:"cat", score:0}}, {text : "Happy to help.", go : "#hidecat", integrityScore: 0, relationship: {name:"cat", score:0}}], label: "choices"},
				{type: "hide", img: cat, label: "hidecat", waitUntilHidden: false, flip: true},
				{type: "jump", condition: true, goTrue: 1000, goFalse: 1000},
				{type: "dialog", speaker: "Ryan", text: "I think we saw a phone on the bar at Scotties, right? Maybe it’s yours.", label: "phone_notpicked"},
				{type: "dialog", speaker: "Cat", text: "Oh, uh thanks. I’ll call them."},
				{type: "hide", img: cat, waitUntilHidden: false, flip: true},
			];
		}
		else if(this._talked == 1) {
			o = [
				{type: "show", img: ryan, waitUntilShown: false},
				{type: "dialog", speaker: "Ryan", text: "What did I tell you, that karma!"},
			];
		}
		else if(this._talked == 2) {
			o = [
				{type: "show", img: priya, waitUntilShown: false},
				{type: "dialog", speaker: "Priya", text: "What are the chances!"},
			];
		}
		return o;
	}

	MPLAY.Page1_1 = Page1_1;
}());
<commit_msg>Comment interactable objects in page1_1.js<commit_after>// namespace
var MPLAY = MPLAY || {};

(function() {
	"use_strict";

	/**
	 *
	 * @class Page1_1
	 * @augments MPLAY.MPlayPage
	 */
	var Page1_1 = function() {
		MPLAY.MPlayPage.call(this);
	};

	Page1_1.prototype = Object.create(MPLAY.MPlayPage.prototype);
	Page1_1.prototype.constructor = Page1_1;

	/**
	 * @override
	 */
	Page1_1.prototype._onLoad = function() {
		MPLAY.MPlayPage.prototype._onLoad.call(this);

		this.setBackground("/static/gnovel/res/textures/backgrounds/uc final layers png.png");

		//create images
		this._priyaImg = this.createImage("/static/gnovel/res/textures/char/thoughtful-julia.png", new THREE.Vector3(-300, -140, 120), 600, 825);
		this._ryanImg = this.createImage("/static/gnovel/res/textures/char/ryan-happy.png", new THREE.Vector3(0, -110, 140), 600, 923);
		this._catImg = this.createImage("/static/gnovel/res/textures/char/cat-neutral.png", new THREE.Vector3(450, -130, 100), 600, 799);

		this._talked = 0;

		var pageObj = this;
		// var io1 = this.createInteractableObject(
		// 	"/static/gnovel/res/textures/Perspective-Button-Stop-icon.png",
		// 	{x: -100, y: 200, width : 64, height : 64, onClick: function() {
		// 		pageObj._talked = 1;
		// 		pageObj._runFlow();
		// 	}});

		// var io2 = this.createInteractableObject(
		// 	"/static/gnovel/res/textures/Perspective-Button-Stop-icon.png",
		// 	{x: 100, y: 200, width : 64, height : 64, onClick: function() {
		// 		pageObj._talked = 2;
		// 		pageObj._runFlow();
		// 	}});

		this._priyaImg.material.opacity = 0;
		this._ryanImg.material.opacity = 0;
		this._catImg.material.opacity = 0;

		this._priya = "priya";
		this._ryan = "ryan";
		this._cat = "cat";

		// add object tags
		this._setObjectTag(this._priya, this._priyaImg);
		this._setObjectTag(this._ryan, this._ryanImg);
		this._setObjectTag(this._cat, this._catImg);

	};

	Page1_1.prototype._createFlowElements = function() {
		var priya = "%priya";
		var ryan = "%ryan";
		var cat = "%cat";
		var o = null;
		// variables from scene 1
		var isPhonePickedUp = 1;
		var isPhoneWithYou = 0;
		// player name which the player entered at the beginning of the game
		var player = "Lindsey";
		// this._talked = 1;

		if(this._talked == 0) {
			o = [
				// transition of this flow doesn't work
				{type: "show", img: ryan, position: "center", waitUntilShown: false},
				{type: "dialog", speaker: "Ryan", text: "Awesome! Both you and Priya are in my group. This is Priya. She’s super smart, speaks like a bajillion languages. Too cool for me."},
				// transition of this flow doesn't work
				{type: "hide", img: ryan, waitUntilHidden: false},
				// transition of this flow doesn't work
				{type: "show", img: priya, position: "left", waitUntilShown: false},
				{type: "dialog", speaker: "Priya", text: "RYAN here helped me with some of my writing last semester. Always willing to be my study partner. I think I annoyed him most of the time. Anyway, nice to meet you"},
				// transition of this flow doesn't work
				{type: "hide", img: priya, waitUntilHidden: false},
				// transition of this flow doesn't work
				{type: "show", img: cat, position: "right", waitUntilShown: false, flip: true},
				{type: "dialog", speaker: "Cat", text: "Hey I’m Cat. I’m in Tepper. I think I’m going to be in over my head a little here in a CS class It’s been an adjustment coming back to school."},
				{type: "hide", img: cat, waitUntilHidden: false, flip: true},
				{type: "show", img: ryan, position: "center", waitUntilShown: false},
				{type: "dialog", speaker: "Ryan", text: "Oh, don’t sweat it, Cat. We’ll help you out if you get stuck."},
				{type: "hide", img: ryan, waitUntilHidden: false},
				{type: "show", img: cat, waitUntilShown: false, flip: true},
				{type: "dialog", speaker: "Cat", text: "Sorry - I’m a little all over the place. I lost my phone yesterday."},
				{type: "hide", img: cat, waitUntilHidden: false, flip: true},
				{type: "compare", leftop: isPhonePickedUp, operator: "equal", rightop: 1, goTrue: "#phone_picked", goFalse: "#phone_notpicked"},
				{type: "show", img: ryan, label: "phone_picked", waitUntilShown: false},
				{type: "dialog", speaker: "Ryan", text: "Were you at Scottie’s Bar yesterday? " + player +" found a phone there."},
				{type: "hide", img: ryan, waitUntilHidden: false},
				{type: "show", img: cat, waitUntilShown: false, flip: true},
				{type: "dialog", speaker: "Cat", text: "Oh my God, do you guys have it with you?"},
				{type: "hide", img: cat, waitUntilHidden: false, flip: true},
				{type: "show", img: ryan, waitUntilShown: false},
				{type: "compare", leftop: isPhoneWithYou, operator: "equal", rightop: 1, goTrue: "#phone_withyou", goFalse: "#phone_notwithyou"},
				{type: "dialog", speaker: "Ryan", text: "Yeah, " + player + " has it, right?", label: "phone_withyou"},
				{type: "hide", img: ryan, waitUntilHidden: false},
				{type: "show", img: cat, waitUntilShown: false, flip: true},
				{type: "dialog", speaker: "Cat", text: "Oh my God - you charged it too? You’ve totally restored my faith in humanity."},
				{type: "jump", condition: true, goTrue: "#choices", goFalse: 1000},
				{type: "dialog", speaker: "Ryan", text: "We left it with the bartender.", label: "phone_notwithyou"},
				{type: "hide", img: ryan, waitUntilHidden: false},
				{type: "show", img: cat, waitUntilShown: false, flip: true},
				{type: "dialog", speaker: "Cat", text: "Thank you! I’ll run over there after this. Lifesaver!"},
				{type: "choices", choices : [{text: "No Problem.", go: "#hidecat", relationship: {name:"cat", score:0}}, {text : "Happy to help.", go : "#hidecat", integrityScore: 0, relationship: {name:"cat", score:0}}], label: "choices"},
				{type: "hide", img: cat, label: "hidecat", waitUntilHidden: false, flip: true},
				{type: "jump", condition: true, goTrue: 1000, goFalse: 1000},
				{type: "dialog", speaker: "Ryan", text: "I think we saw a phone on the bar at Scotties, right? Maybe it’s yours.", label: "phone_notpicked"},
				{type: "dialog", speaker: "Cat", text: "Oh, uh thanks. I’ll call them."},
				{type: "hide", img: cat, waitUntilHidden: false, flip: true},
			];
		}
		else if(this._talked == 1) {
			o = [
				{type: "show", img: ryan, waitUntilShown: false},
				{type: "dialog", speaker: "Ryan", text: "What did I tell you, that karma!"},
			];
		}
		else if(this._talked == 2) {
			o = [
				{type: "show", img: priya, waitUntilShown: false},
				{type: "dialog", speaker: "Priya", text: "What are the chances!"},
			];
		}
		return o;
	}

	MPLAY.Page1_1 = Page1_1;
}());
<|endoftext|>


<commit_before>(function()
{

  var View = function(id, name, container_class)
  {
    var self = this;

    this.createView = function(container)
    {
      container.innerHTML = '';
      //container.render(templates.runtimes(runtimes.getRuntimes()));
      container.render(templates.windows(runtimes.getWindows(), 'script'));
    }
    this.init(id, name, container_class);
  }
  View.prototype = ViewBase;
  new View('runtimes', 'Runtimes Script', 'scroll runtimes');

  View = function(id, name, container_class)
  {
    var self = this;

    this.createView = function(container)
    {
      container.innerHTML = '';
      container.render(templates.windows(runtimes.getWindows(), 'dom'));
    }

    this.updateSelectedRuntime = function(rt_id)
    {
      var containers = this.getAllContainers(), c = null , i = 0;
      var lis = null, li = null , k = 0;
      for( ; c = containers[i]; i++)
      {
        lis = c.getElementsByTagName('li');
        for( k = 0; li = lis[k]; k++ )
        {
          if( li.hasAttribute('runtime_id') )
          {
            if( li.getAttribute('runtime_id') == rt_id)
            {
              li.firstChild.addClass('selected-runtime');
              helpers.setSelected({target: li.parentNode.parentNode});
            }
            else
            {
              li.firstChild.removeClass('selected-runtime');
            }
          }
        }
      }
    }

    var onRuntimeSelected = function(msg)
    {
      if(self.isvisible())
      {
        self.updateSelectedRuntime(msg.id);
      }

    }

    this.init(id, name, container_class);

    messages.addListener('runtime-selected', onRuntimeSelected);
  }
  View.prototype = ViewBase;
  new View('runtimes_dom', 'Runtimes DOM', 'scroll runtimes');

  View = function(id, name, container_class)
  {
    var self = this;

    this.createView = function(container)
    {
      container.innerHTML = '';
      container.render(templates.windows(runtimes.getWindows(), 'css'));
    }

    this.updateSelectedRuntime = function(rt_id)
    {
      /*
      var containers = this.getAllContainers(), c = null , i = 0;
      var lis = null, li = null , k = 0;
      for( ; c = containers[i]; i++)
      {
        lis = c.getElementsByTagName('li');
        for( k = 0; li = lis[k]; k++ )
        {
          if( li.hasAttribute('runtime_id') )
          {
            if( li.getAttribute('runtime_id') == rt_id)
            {
              li.firstChild.addClass('selected-runtime');
              helpers.setSelected({target: li.parentNode.parentNode});
            }
            else
            {
              li.firstChild.removeClass('selected-runtime');
            }
          }
        }
      }
      */
    }

    var onRuntimeSelected = function(msg)
    {
      if(self.isvisible())
      {
        //self.updateSelectedRuntime(msg.id);
      }

    }

    this.init(id, name, container_class);

    messages.addListener('runtime-selected', onRuntimeSelected);
  }
  View.prototype = ViewBase;
  new View('runtimes_css', 'Runtimes CSS', 'scroll runtimes');

  View = function(id, name, container_class)
  {
    var self = this;
    this.createView = function(container)
    {
      container.innerHTML = '';
      container.render( templates.hello( services['ecmascript-debugger'].getEnvironment()) );
    }
    this.init(id, name, container_class);
  }
  View.prototype = ViewBase;
  new View('environment', 'Environment', 'scroll');

  View = function(id, name, container_class)
  {
    var container_id = 'backtrace';
    var __clear_timeout = 0;

    var __clearView = function()
    {
      var container = document.getElementById(container_id);
      if( container )
      {
        container.innerHTML = '';
        __clear_timeout = 0;
      }
    }

    this.createView = function(container)
    {
      var list = container.getElementsByTagName('ul')[0];
      if(!list)
      {
        container.innerHTML = "

"; // TODO clean up
        list = container.getElementsByTagName('ul')[0];
      }

      if( __clear_timeout )
      {
        __clear_timeout = clearTimeout( __clear_timeout );
      }
      var _frames = stop_at.getFrames(), frame = null, i = 0;
      list.innerHTML = '';
      for( ; frame = _frames[i]; i++)
      {
        list.render(templates.frame(frame, i == 0));
      }

    }

    this.clearView = function()
    {
      __clear_timeout = setTimeout( __clearView, 150 );
    }

    this.init(id, name, container_class);
  }

  View.prototype = ViewBase;
  new View('callstack', 'Callstack', 'scroll');

  View = function(id, name, container_class)
  {

    var self = this;
    var container_id = 'examine-objects';

    var getContainer = function(path_arr)
    {
      var container = document.getElementById(container_id);
      var prov = null, length = 0, i = 0;
      if( container )
      {
        if( path_arr )
        {
          length = path_arr.length
          for( ; i < length; i++ )
          {
            container = container.getElementsByTagName('ul')[0].childNodes[ path_arr[ i ] ];
            if( !container )
            {
              opera.postError('Error in views.frame_inspection.update');
              break;
            }
          }
        }
      }
      return container;
    }

    this.createView = function(container)
    {
      container.clearAndRender(['div', ['div', 'id', container_id], 'id', 'examine-objects-container']); // TODO clean up
      this.updatePath(null);
    }

    this.showGlobalScopeUpdateLink = function()
    {
      var containers = this.getAllContainers(), c = null , i = 0;
      var lis = null, li = null , k = 0;
      for( ; c = containers[i]; i++)
      {
       c.innerHTML =
        "

show global scope

";
      }
    }

    this.updatePath = function( path_arr )
    {
      var container = getContainer( path_arr );
      if( container )
      {
        var items = frame_inspection.getObject( path_arr ).items;
        if(items.length)
        {
          container.renderInner( templates.examineObject( items ) );
        }
        else
        {
          var input = container.getElementsByTagName('input')[0];
          if(input)
          {
            input.removeAttribute('handler');
            input.removeAttribute('style');
            input.disabled = true;
          }
        }
      }
    }

    this.clearView = function(path_arr)
    {
      var container = getContainer( path_arr );
      if( container )
      {
        var ul = container.getElementsByTagName('ul')[0];
        if( ul )
        {
          container.removeChild( ul );
        }
      }
      else
      {
        var containers = this.getAllContainers(), c = null , i = 0;
        for( ; c = containers[i]; i++)
        {
         c.clearAndRender(['div', ['div', 'id', container_id], 'id', 'examine-objects-container']);
        }
      }
    }

    this.init(id, name, container_class);

  }

  View.prototype = ViewBase;
  new View('frame_inspection', 'Frame Inspection', 'scroll');

  new Settings
  (
    // id
    'frame_inspection',
    // key-value map
    {
      'automatic-update-global-scope': false
    },
    // key-label map
    {
      'automatic-update-global-scope': ' update global scope automatically'
    },
    // settings map
    {
      checkboxes:
      [
        'automatic-update-global-scope'
      ]
    }
  );

  View = function(id, name, container_class)
  {
    /* a quick hack */

    var self = this;

    var handleEval = function(xml, runtime_id)
    {
      var value_type = xml.getNodeData('data-type');
      var status = xml.getNodeData('status');
      if( status == 'completed' )
      {
        var return_value = xml.getElementsByTagName('string')[0];
        if(return_value)
        {
          var out = document.getElementById('console-output');
          out.render(['pre', return_value.firstChild.nodeValue]);
        }
        else if (return_value = xml.getElementsByTagName('object-id')[0])
        {
          var object_id = return_value.textContent;
          var object_ref_name = "$" + object_id;
          var tag = tagManager.setCB(null, handleEval, [runtime_id] );
          var script_string  = "return " + object_ref_name + ".toString()";
          services['ecmascript-debugger'].eval(
            tag, runtime_id, '', '', "<![CDATA["+script_string+"]]>", [object_ref_name, object_id]);
        }
      }
      else
      {
        var error_id = xml.getNodeData('object-id');
        if( error_id )
        {
          var tag = tagManager.setCB(null, handleError);
          services['ecmascript-debugger'].examineObjects(tag, runtime_id, error_id);
        }
      }

    }

    var handleError = function(xml)
    {
      var return_value = xml.getElementsByTagName('string')[0];
      if(return_value)
      {
        var out = document.getElementById('console-output');
        out.render(['pre', return_value.firstChild.nodeValue]);
      }
    }

    var markup = "\

\

\

\
          >>> \

<textarea handler='commandline' rows='1' title='hold shift to add a new line'></textarea>
\

\

";

    var templates = {};

    templates.consoleInput = function(entry)
    {
      var lines_count = entry.msg.split(/\r?\n/).length;
      var line_head = '>>>';
      while( --lines_count > 1 )
      {
        line_head += '\n...';
      }
      return [['div', line_head], ['pre', entry.msg]];
    }

    eventHandlers.click['console-focus-input'] = function(event, ele)
    {
      ele.getElementsByTagName('textarea')[0].focus();
    }

    var submit = function(input)
    {
      var rt_id = runtimes.getSelectedRuntimeId();
      if(rt_id)
      {
        var tag = tagManager.setCB(null, handleEval, [rt_id] );
        var script_string  = submit_buffer.join('');
        services['ecmascript-debugger'].eval(tag, rt_id, '', '', "<![CDATA["+script_string+"]]>");
        submit_buffer = [];
      }
      else
      {
        alert('select runtime');
      }
    }

    var submit_buffer = [];
    var line_buffer = [];
    var line_buffer_cursor = 0;

    var line_buffer_push = function(line)
    {
      line_buffer[line_buffer.length] = line.replace(/\r\n/g, "");
      if( line_buffer.length > 100 )
      {
        line_buffer = line_buffer.slice(line_buffer.length - 100);
      }
      line_buffer_cursor = line_buffer.length;
    }

    eventHandlers.keyup['commandline'] = function(event)
    {
      if(event.keyCode == 38 || event.keyCode == 40)
      {

        line_buffer_cursor += event.keyCode == 38 ? -1 : 1;
        line_buffer_cursor =
          line_buffer_cursor < 0 ? line_buffer.length-1 : line_buffer_cursor > line_buffer.length-1 ? 0 : line_buffer_cursor;
        event.target.value = (line_buffer.length ? line_buffer[line_buffer_cursor] : '').replace(/\r\n/g, '');
        event.preventDefault();
        return;
      }
      const CRLF = "\r\n";
      var value = event.target.value;
      var lastCRLFIndex = value.lastIndexOf(CRLF);
      if(lastCRLFIndex != -1)
      {
        if ( value.length -2 != lastCRLFIndex )
        {
          value = value.slice(0, lastCRLFIndex) + value.slice(lastCRLFIndex + 2) + CRLF;
        }
        document.getElementById("console-output").render(
          ['div', ( submit_buffer.length ? "... " : ">>> " ) + value, 'class', 'log-entry']);
        line_buffer_push( submit_buffer[submit_buffer.length] = value );
        if(!event.shiftKey)
        {
          submit();
        }
        document.getElementById("commandline-prefix").textContent = submit_buffer.length ? "... " : ">>> ";
        event.target.value = '';
        event.target.scrollTop = 0;
      }

    }

    this.createView = function(container)
    {
      container.innerHTML = markup;
    }

    this.init(id, name, container_class);

  }

  View.prototype = ViewBase;
  new View('command_line', 'Command Line', 'scroll');

  View = function(id, name, container_class)
  {
    var __url = '';
    this.setURL = function(url)
    {
      __url = url;
    }
    this.createView = function(container)
    {
      if( __url )
      {
        container.render(['iframe',
                          'width', '100%', 'height', '100%',
                          'style', 'dispaly:block;border:none',
                          'src', __url])
      }

    }
    this.init(id, name, container_class);
  }

  View.prototype = ViewBase;

  new View('documentation', 'Documentation', '');

  View = function(id, name, container_class)
  {
    this.ishidden_in_menu = true;
    this.createView = function(container)
    {
      ;
    }
    this.init(id, name, container_class);
  }

  View.prototype = ViewBase;

  new View('debug_remote_setting', 'Debug remote', '');

  new Settings
  (
    // id
    'debug_remote_setting',
    // key-value map
    {
      "debug-remote": false,
      "port": 7001
    },
    // key-label map
    {
      "debug-remote": "debug remote"
    },
    // settings map
    {
      checkboxes:
      [
        "debug-remote"
      ]
    },
    // template
    function(setting)
    {
      return [
        ['setting-composite',
          ['label',
            ['input',
              'type', 'checkbox',
              'checked', this.get('debug-remote'),
              'handler', 'toggle-remote-debug'
            ],
            this.label_map['debug-remote']
          ],
          ['label',
            'port: ',
            ['input',
              'type', 'number',
              'value', this.get('port'),
              'disabled', !this.get('debug-remote')
            ]
          ],
          ['input',
            'type', 'button',
            'value', 'apply',
            'handler', 'apply-remote-debugging'
          ]
        ]
      ];
    }
  );

  eventHandlers.change['toggle-remote-debug'] = function(event, target)
  {
    target.parentNode.nextSibling.childNodes[1].disabled = !event.target.checked;
  }

  eventHandlers.click['apply-remote-debugging'] = function(event, target)
  {
    var is_debug_remote = target.parentNode.getElementsByTagName('input')[0].checked;
    var port = parseInt(target.parentNode.getElementsByTagName('input')[1].value);
    if( port )
    {
      settings.debug_remote_setting.set('debug-remote', is_debug_remote);
      settings.debug_remote_setting.set('port', port);
      client.scopeSetupClient();
    }
  }

})()

<commit_msg>link show "DOM "view with "runtimes DOM" and "Stylesheets" with "runtimes CSS"<commit_after>(function()
{

  var View = function(id, name, container_class)
  {
    var self = this;

    this.createView = function(container)
    {
      container.innerHTML = '';
      //container.render(templates.runtimes(runtimes.getRuntimes()));
      container.render(templates.windows(runtimes.getWindows(), 'script'));
    }
    this.init(id, name, container_class);
  }
  View.prototype = ViewBase;
  new View('runtimes', 'Runtimes Script', 'scroll runtimes');

  View = function(id, name, container_class)
  {
    var self = this;

    this.createView = function(container)
    {
      container.innerHTML = '';
      container.render(templates.windows(runtimes.getWindows(), 'dom'));
    }

    this.updateSelectedRuntime = function(rt_id)
    {
      var containers = this.getAllContainers(), c = null , i = 0;
      var lis = null, li = null , k = 0;
      for( ; c = containers[i]; i++)
      {
        lis = c.getElementsByTagName('li');
        for( k = 0; li = lis[k]; k++ )
        {
          if( li.hasAttribute('runtime_id') )
          {
            if( li.getAttribute('runtime_id') == rt_id)
            {
              li.firstChild.addClass('selected-runtime');
              helpers.setSelected({target: li.parentNode.parentNode});
            }
            else
            {
              li.firstChild.removeClass('selected-runtime');
            }
          }
        }
      }
    }

    var onRuntimeSelected = function(msg)
    {
      if(self.isvisible())
      {
        self.updateSelectedRuntime(msg.id);
      }

    }

    this.init(id, name, container_class);

    messages.addListener('runtime-selected', onRuntimeSelected);

    var onViewCreated = function(msg)
    {
      if( msg.id == 'dom' )
      {
        topCell.showView(id);
      }
    }
    messages.addListener('view-created', onViewCreated);

  }
  View.prototype = ViewBase;
  new View('runtimes_dom', 'Runtimes DOM', 'scroll runtimes');

  View = function(id, name, container_class)
  {
    var self = this;

    this.createView = function(container)
    {
      container.innerHTML = '';
      container.render(templates.windows(runtimes.getWindows(), 'css'));
    }

    this.updateSelectedRuntime = function(rt_id)
    {
      /*
      var containers = this.getAllContainers(), c = null , i = 0;
      var lis = null, li = null , k = 0;
      for( ; c = containers[i]; i++)
      {
        lis = c.getElementsByTagName('li');
        for( k = 0; li = lis[k]; k++ )
        {
          if( li.hasAttribute('runtime_id') )
          {
            if( li.getAttribute('runtime_id') == rt_id)
            {
              li.firstChild.addClass('selected-runtime');
              helpers.setSelected({target: li.parentNode.parentNode});
            }
            else
            {
              li.firstChild.removeClass('selected-runtime');
            }
          }
        }
      }
      */
    }

    var onRuntimeSelected = function(msg)
    {
      if(self.isvisible())
      {
        //self.updateSelectedRuntime(msg.id);
      }

    }

    var onViewCreated = function(msg)
    {
      if( msg.id == 'stylesheets' )
      {
        topCell.showView(id);
      }
    }
    messages.addListener('view-created', onViewCreated);

    this.init(id, name, container_class);

    messages.addListener('runtime-selected', onRuntimeSelected);
  }
  View.prototype = ViewBase;
  new View('runtimes_css', 'Runtimes CSS', 'scroll runtimes');

  View = function(id, name, container_class)
  {
    var self = this;
    this.createView = function(container)
    {
      container.innerHTML = '';
      container.render( templates.hello( services['ecmascript-debugger'].getEnvironment()) );
    }
    this.init(id, name, container_class);
  }
  View.prototype = ViewBase;
  new View('environment', 'Environment', 'scroll');

  View = function(id, name, container_class)
  {
    var container_id = 'backtrace';
    var __clear_timeout = 0;

    var __clearView = function()
    {
      var container = document.getElementById(container_id);
      if( container )
      {
        container.innerHTML = '';
        __clear_timeout = 0;
      }
    }

    this.createView = function(container)
    {
      var list = container.getElementsByTagName('ul')[0];
      if(!list)
      {
        container.innerHTML = "

"; // TODO clean up
        list = container.getElementsByTagName('ul')[0];
      }

      if( __clear_timeout )
      {
        __clear_timeout = clearTimeout( __clear_timeout );
      }
      var _frames = stop_at.getFrames(), frame = null, i = 0;
      list.innerHTML = '';
      for( ; frame = _frames[i]; i++)
      {
        list.render(templates.frame(frame, i == 0));
      }

    }

    this.clearView = function()
    {
      __clear_timeout = setTimeout( __clearView, 150 );
    }

    this.init(id, name, container_class);
  }

  View.prototype = ViewBase;
  new View('callstack', 'Callstack', 'scroll');

  View = function(id, name, container_class)
  {

    var self = this;
    var container_id = 'examine-objects';

    var getContainer = function(path_arr)
    {
      var container = document.getElementById(container_id);
      var prov = null, length = 0, i = 0;
      if( container )
      {
        if( path_arr )
        {
          length = path_arr.length
          for( ; i < length; i++ )
          {
            container = container.getElementsByTagName('ul')[0].childNodes[ path_arr[ i ] ];
            if( !container )
            {
              opera.postError('Error in views.frame_inspection.update');
              break;
            }
          }
        }
      }
      return container;
    }

    this.createView = function(container)
    {
      container.clearAndRender(['div', ['div', 'id', container_id], 'id', 'examine-objects-container']); // TODO clean up
      this.updatePath(null);
    }

    this.showGlobalScopeUpdateLink = function()
    {
      var containers = this.getAllContainers(), c = null , i = 0;
      var lis = null, li = null , k = 0;
      for( ; c = containers[i]; i++)
      {
       c.innerHTML =
        "

show global scope

";
      }
    }

    this.updatePath = function( path_arr )
    {
      var container = getContainer( path_arr );
      if( container )
      {
        var items = frame_inspection.getObject( path_arr ).items;
        if(items.length)
        {
          container.renderInner( templates.examineObject( items ) );
        }
        else
        {
          var input = container.getElementsByTagName('input')[0];
          if(input)
          {
            input.removeAttribute('handler');
            input.removeAttribute('style');
            input.disabled = true;
          }
        }
      }
    }

    this.clearView = function(path_arr)
    {
      var container = getContainer( path_arr );
      if( container )
      {
        var ul = container.getElementsByTagName('ul')[0];
        if( ul )
        {
          container.removeChild( ul );
        }
      }
      else
      {
        var containers = this.getAllContainers(), c = null , i = 0;
        for( ; c = containers[i]; i++)
        {
         c.clearAndRender(['div', ['div', 'id', container_id], 'id', 'examine-objects-container']);
        }
      }
    }

    this.init(id, name, container_class);

  }

  View.prototype = ViewBase;
  new View('frame_inspection', 'Frame Inspection', 'scroll');

  new Settings
  (
    // id
    'frame_inspection',
    // key-value map
    {
      'automatic-update-global-scope': false
    },
    // key-label map
    {
      'automatic-update-global-scope': ' update global scope automatically'
    },
    // settings map
    {
      checkboxes:
      [
        'automatic-update-global-scope'
      ]
    }
  );

  View = function(id, name, container_class)
  {
    /* a quick hack */

    var self = this;

    var handleEval = function(xml, runtime_id)
    {
      var value_type = xml.getNodeData('data-type');
      var status = xml.getNodeData('status');
      if( status == 'completed' )
      {
        var return_value = xml.getElementsByTagName('string')[0];
        if(return_value)
        {
          var out = document.getElementById('console-output');
          out.render(['pre', return_value.firstChild.nodeValue]);
        }
        else if (return_value = xml.getElementsByTagName('object-id')[0])
        {
          var object_id = return_value.textContent;
          var object_ref_name = "$" + object_id;
          var tag = tagManager.setCB(null, handleEval, [runtime_id] );
          var script_string  = "return " + object_ref_name + ".toString()";
          services['ecmascript-debugger'].eval(
            tag, runtime_id, '', '', "<![CDATA["+script_string+"]]>", [object_ref_name, object_id]);
        }
      }
      else
      {
        var error_id = xml.getNodeData('object-id');
        if( error_id )
        {
          var tag = tagManager.setCB(null, handleError);
          services['ecmascript-debugger'].examineObjects(tag, runtime_id, error_id);
        }
      }

    }

    var handleError = function(xml)
    {
      var return_value = xml.getElementsByTagName('string')[0];
      if(return_value)
      {
        var out = document.getElementById('console-output');
        out.render(['pre', return_value.firstChild.nodeValue]);
      }
    }

    var markup = "\

\

\

\
          >>> \

<textarea handler='commandline' rows='1' title='hold shift to add a new line'></textarea>
\

\

";

    var templates = {};

    templates.consoleInput = function(entry)
    {
      var lines_count = entry.msg.split(/\r?\n/).length;
      var line_head = '>>>';
      while( --lines_count > 1 )
      {
        line_head += '\n...';
      }
      return [['div', line_head], ['pre', entry.msg]];
    }

    eventHandlers.click['console-focus-input'] = function(event, ele)
    {
      ele.getElementsByTagName('textarea')[0].focus();
    }

    var submit = function(input)
    {
      var rt_id = runtimes.getSelectedRuntimeId();
      if(rt_id)
      {
        var tag = tagManager.setCB(null, handleEval, [rt_id] );
        var script_string  = submit_buffer.join('');
        services['ecmascript-debugger'].eval(tag, rt_id, '', '', "<![CDATA["+script_string+"]]>");
        submit_buffer = [];
      }
      else
      {
        alert('select runtime');
      }
    }

    var submit_buffer = [];
    var line_buffer = [];
    var line_buffer_cursor = 0;

    var line_buffer_push = function(line)
    {
      line_buffer[line_buffer.length] = line.replace(/\r\n/g, "");
      if( line_buffer.length > 100 )
      {
        line_buffer = line_buffer.slice(line_buffer.length - 100);
      }
      line_buffer_cursor = line_buffer.length;
    }

    eventHandlers.keyup['commandline'] = function(event)
    {
      if(event.keyCode == 38 || event.keyCode == 40)
      {

        line_buffer_cursor += event.keyCode == 38 ? -1 : 1;
        line_buffer_cursor =
          line_buffer_cursor < 0 ? line_buffer.length-1 : line_buffer_cursor > line_buffer.length-1 ? 0 : line_buffer_cursor;
        event.target.value = (line_buffer.length ? line_buffer[line_buffer_cursor] : '').replace(/\r\n/g, '');
        event.preventDefault();
        return;
      }
      const CRLF = "\r\n";
      var value = event.target.value;
      var lastCRLFIndex = value.lastIndexOf(CRLF);
      if(lastCRLFIndex != -1)
      {
        if ( value.length -2 != lastCRLFIndex )
        {
          value = value.slice(0, lastCRLFIndex) + value.slice(lastCRLFIndex + 2) + CRLF;
        }
        document.getElementById("console-output").render(
          ['div', ( submit_buffer.length ? "... " : ">>> " ) + value, 'class', 'log-entry']);
        line_buffer_push( submit_buffer[submit_buffer.length] = value );
        if(!event.shiftKey)
        {
          submit();
        }
        document.getElementById("commandline-prefix").textContent = submit_buffer.length ? "... " : ">>> ";
        event.target.value = '';
        event.target.scrollTop = 0;
      }

    }

    this.createView = function(container)
    {
      container.innerHTML = markup;
    }

    this.init(id, name, container_class);

  }

  View.prototype = ViewBase;
  new View('command_line', 'Command Line', 'scroll');

  View = function(id, name, container_class)
  {
    var __url = '';
    this.setURL = function(url)
    {
      __url = url;
    }
    this.createView = function(container)
    {
      if( __url )
      {
        container.render(['iframe',
                          'width', '100%', 'height', '100%',
                          'style', 'dispaly:block;border:none',
                          'src', __url])
      }

    }
    this.init(id, name, container_class);
  }

  View.prototype = ViewBase;

  new View('documentation', 'Documentation', '');

  View = function(id, name, container_class)
  {
    this.ishidden_in_menu = true;
    this.createView = function(container)
    {
      ;
    }
    this.init(id, name, container_class);
  }

  View.prototype = ViewBase;

  new View('debug_remote_setting', 'Debug remote', '');

  new Settings
  (
    // id
    'debug_remote_setting',
    // key-value map
    {
      "debug-remote": false,
      "port": 7001
    },
    // key-label map
    {
      "debug-remote": "debug remote"
    },
    // settings map
    {
      checkboxes:
      [
        "debug-remote"
      ]
    },
    // template
    function(setting)
    {
      return [
        ['setting-composite',
          ['label',
            ['input',
              'type', 'checkbox',
              'checked', this.get('debug-remote'),
              'handler', 'toggle-remote-debug'
            ],
            this.label_map['debug-remote']
          ],
          ['label',
            'port: ',
            ['input',
              'type', 'number',
              'value', this.get('port'),
              'disabled', !this.get('debug-remote')
            ]
          ],
          ['input',
            'type', 'button',
            'value', 'apply',
            'handler', 'apply-remote-debugging'
          ]
        ]
      ];
    }
  );

  eventHandlers.change['toggle-remote-debug'] = function(event, target)
  {
    target.parentNode.nextSibling.childNodes[1].disabled = !event.target.checked;
  }

  eventHandlers.click['apply-remote-debugging'] = function(event, target)
  {
    var is_debug_remote = target.parentNode.getElementsByTagName('input')[0].checked;
    var port = parseInt(target.parentNode.getElementsByTagName('input')[1].value);
    if( port )
    {
      settings.debug_remote_setting.set('debug-remote', is_debug_remote);
      settings.debug_remote_setting.set('port', port);
      client.scopeSetupClient();
    }
  }

})()

<|endoftext|>


<commit_before>var resemble = require('node-resemble-js');
var path = require('path');
var map = require('bluebird').map;

var fs = require('./fs');
var streamToPromise = require('./streamToPromise');
var Reporter = require('./Reporter');
var logger = require('./logger')('compare');

var MAX_COMPARISONS_CONCURRENCY = 20;

function storeFailedDiffImage (testPath, data) {
  var failedDiffFilename = getFailedDiffFilename(testPath);
  console.log('   See:', failedDiffFilename);

  var failedDiffStream = fs.createWriteStream(failedDiffFilename);
  var storageStream = data.getDiffImage()
    .pack()
    .pipe(failedDiffStream);

  return streamToPromise(storageStream, failedDiffFilename);
}

function getFailedDiffFilename (testPath) {
  var lastSlash = testPath.lastIndexOf(path.sep);
  return testPath.slice(0, lastSlash + 1) + 'failed_diff_' + testPath.slice(lastSlash + 1, testPath.length);
}

function compareImage (referencePath, testPath, resembleOutputSettings) {
  return new Promise(function (resolve, reject) {
    if (!fs.existsSync(referencePath)) {
      reject('Reference image not found: ' + referencePath);
    }

    if (!fs.existsSync(testPath)) {
      reject('Test image not found: ' + testPath);
    }

    resemble.outputSettings(resembleOutputSettings || {});
    resemble(referencePath).compareTo(testPath)
      .onComplete(function (data) {
        resolve(data);
      });
  });
}

module.exports = function (config) {
  var compareConfig = require(config.tempCompareConfigFileName).compareConfig;

  var report = new Reporter(config.ciReport.testSuiteName);

  return tests = map(compareConfig.testPairs, function (pair) {
    var Test = report.addTest(pair);

    var referencePath = path.join(config.projectPath, pair.reference);
    var testPath = path.join(config.projectPath, pair.test);

    return compareImage(referencePath, testPath, config.resembleOutputOptions)
      .then(function logCompareResult (data) {
        pair.diff = data;

        if (data.isSameDimensions && data.misMatchPercentage <= pair.misMatchThreshold) {
          Test.status = 'pass';
          logger.success('OK: ' + pair.label + ' ' + pair.fileName);

          return pair;
        }

        Test.status = 'fail';
        logger.error('ERROR { size: ' + (data.isSameDimensions ? 'ok' : 'isDifferent') + ', content: ' + data.misMatchPercentage + '%, threshold: ' + pair.misMatchThreshold + '% }: ' + pair.label + ' ' + pair.fileName);

        return storeFailedDiffImage(testPath, data).then(function (compare) {
          pair.diffImage = compare;

          return pair;
        });
      });
  }, {concurrency: MAX_COMPARISONS_CONCURRENCY}).then(function () {
    return report;
  });
};
<commit_msg>fix #329 (#354)<commit_after>var resemble = require('node-resemble-js');
var path = require('path');
var map = require('bluebird').map;

var fs = require('./fs');
var streamToPromise = require('./streamToPromise');
var Reporter = require('./Reporter');
var logger = require('./logger')('compare');

var MAX_COMPARISONS_CONCURRENCY = 1;

function storeFailedDiffImage (testPath, data) {
  var failedDiffFilename = getFailedDiffFilename(testPath);
  console.log('   See:', failedDiffFilename);

  var failedDiffStream = fs.createWriteStream(failedDiffFilename);
  var storageStream = data.getDiffImage()
    .pack()
    .pipe(failedDiffStream);

  return streamToPromise(storageStream, failedDiffFilename);
}

function getFailedDiffFilename (testPath) {
  var lastSlash = testPath.lastIndexOf(path.sep);
  return testPath.slice(0, lastSlash + 1) + 'failed_diff_' + testPath.slice(lastSlash + 1, testPath.length);
}

function compareImage (referencePath, testPath, resembleOutputSettings) {
  return new Promise(function (resolve, reject) {
    if (!fs.existsSync(referencePath)) {
      reject('Reference image not found: ' + referencePath);
    }

    if (!fs.existsSync(testPath)) {
      reject('Test image not found: ' + testPath);
    }

    resemble.outputSettings(resembleOutputSettings || {});
    resemble(referencePath).compareTo(testPath)
      .onComplete(function (data) {
        resolve(data);
      });
  });
}

module.exports = function (config) {
  var compareConfig = require(config.tempCompareConfigFileName).compareConfig;

  var report = new Reporter(config.ciReport.testSuiteName);

  return tests = map(compareConfig.testPairs, function (pair) {
    var Test = report.addTest(pair);

    var referencePath = path.join(config.projectPath, pair.reference);
    var testPath = path.join(config.projectPath, pair.test);

    return compareImage(referencePath, testPath, config.resembleOutputOptions)
      .then(function logCompareResult (data) {
        pair.diff = data;

        if (data.isSameDimensions && data.misMatchPercentage <= pair.misMatchThreshold) {
          Test.status = 'pass';
          logger.success('OK: ' + pair.label + ' ' + pair.fileName);
          data=null;
          pair.diff.getDiffImage=null;

          return pair;
        }

        Test.status = 'fail';
        logger.error('ERROR { size: ' + (data.isSameDimensions ? 'ok' : 'isDifferent') + ', content: ' + data.misMatchPercentage + '%, threshold: ' + pair.misMatchThreshold + '% }: ' + pair.label + ' ' + pair.fileName);

        return storeFailedDiffImage(testPath, data).then(function (compare) {
          pair.diffImage = compare;
          data=null;
          pair.diff.getDiffImage=null;

          return pair;
        });
      });
  }, {concurrency: MAX_COMPARISONS_CONCURRENCY}).then(function () {
    return report;
  });
};
<|endoftext|>


<commit_before>import {subscriberCollection} from './subscriber-collection';
import {DOM} from 'aurelia-pal';

export class XLinkAttributeObserver {
  // xlink namespaced attributes require getAttributeNS/setAttributeNS
  // (even though the NS version doesn't work for other namespaces
  // in html5 documents)
  constructor(element, propertyName, attributeName) {
    this.element = element;
    this.propertyName = propertyName;
    this.attributeName = attributeName;
  }

  getValue() {
    return this.element.getAttributeNS('http://www.w3.org/1999/xlink', this.attributeName);
  }

  setValue(newValue) {
    return this.element.setAttributeNS('http://www.w3.org/1999/xlink', this.attributeName, newValue);
  }

  subscribe() {
    throw new Error(`Observation of a "${this.element.nodeName}" element\'s "${this.propertyName}" property is not supported.`);
  }
}

export class DataAttributeObserver {
  constructor(element, propertyName) {
    this.element = element;
    this.propertyName = propertyName;
  }

  getValue() {
    return this.element.getAttribute(this.propertyName);
  }

  setValue(newValue) {
    return this.element.setAttribute(this.propertyName, newValue);
  }

  subscribe() {
    throw new Error(`Observation of a "${this.element.nodeName}" element\'s "${this.propertyName}" property is not supported.`);
  }
}

export class StyleObserver {
  constructor(element, propertyName) {
    this.element = element;
    this.propertyName = propertyName;
  }

  getValue() {
    return this.element.style.cssText;
  }

  setValue(newValue) {
    if (newValue instanceof Object) {
      newValue = this.flattenCss(newValue);
    }
    this.element.style.cssText = newValue;
  }

  subscribe() {
    throw new Error(`Observation of a "${this.element.nodeName}" element\'s "${this.propertyName}" property is not supported.`);
  }

  flattenCss(object) {
    var s = '';
    for(var propertyName in object) {
      if (object.hasOwnProperty(propertyName)){
        s += propertyName + ': ' + object[propertyName] + '; ';
      }
    }
    return s;
  }
}

@subscriberCollection()
export class ValueAttributeObserver {
  constructor(element, propertyName, handler){
    this.element = element;
    this.propertyName = propertyName;
    this.handler = handler;
  }

  getValue() {
    return this.element[this.propertyName];
  }

  setValue(newValue) {
    this.element[this.propertyName] =
      (newValue === undefined || newValue === null) ? '' : newValue;

    this.notify();
  }

  notify() {
    let oldValue = this.oldValue;
    let newValue = this.getValue();

    this.callSubscribers(newValue, oldValue);

    this.oldValue = newValue;
  }

  subscribe(context, callable) {
    if (!this.hasSubscribers()) {
      this.oldValue = this.getValue();
      this.disposeHandler = this.handler.subscribe(this.element, this.notify.bind(this));
    }

    this.addSubscriber(context, callable);
  }

  unsubscribe(context, callable) {
    if (this.removeSubscriber(context, callable) && !this.hasSubscribers()) {
      this.disposeHandler();
      this.disposeHandler = null;
    }
  }
}

const selectArrayContext = 'SelectValueObserver:array'

@subscriberCollection()
export class SelectValueObserver {
  constructor(element, handler, observerLocator){
    this.element = element;
    this.handler = handler;
    this.observerLocator = observerLocator;
  }

  getValue() {
    return this.value;
  }

  setValue(newValue) {
    if (newValue !== null && newValue !== undefined && this.element.multiple && !Array.isArray(newValue)) {
      throw new Error('Only null or Array instances can be bound to a multi-select.')
    }
    if (this.value === newValue) {
      return;
    }
    // unsubscribe from old array.
    if (this.arrayObserver) {
      this.arrayObserver.unsubscribe(selectArrayContext, this);
      this.arrayObserver = null;
    }
    // subscribe to new array.
    if (Array.isArray(newValue)) {
      this.arrayObserver = this.observerLocator.getArrayObserver(newValue);
      this.arrayObserver.subscribe(selectArrayContext, this);
    }
    // assign and sync element.
    this.value = newValue;
    this.synchronizeOptions();
    // queue up an initial sync after the bindings have been evaluated.
    if (this.element.options.length > 0 && !this.initialSync) {
      this.initialSync = true;
      this.observerLocator.taskQueue.queueMicroTask(this);
    }
  }

  call(context, splices) {
    // called by task queue and array observer.
    this.synchronizeOptions();
  }

  synchronizeOptions() {
    var value = this.value, i, options, option, optionValue, clear, isArray;

    if (value === null || value === undefined) {
      clear = true;
    } else if (Array.isArray(value)) {
      isArray = true;
    }

    options = this.element.options;
    i = options.length;
    while(i--) {
      option = options.item(i);
      if (clear) {
        option.selected = false;
        continue;
      }
      optionValue = option.hasOwnProperty('model') ? option.model : option.value;
      if (isArray) {
        option.selected = value.indexOf(optionValue) !== -1;
        continue;
      }
      option.selected = value === optionValue;
    }
  }

  synchronizeValue() {
    var options = this.element.options, option, i, ii, count = 0, value = [];

    for(i = 0, ii = options.length; i < ii; i++) {
      option = options.item(i);
      if (!option.selected) {
        continue;
      }
      value[count] = option.hasOwnProperty('model') ? option.model : option.value;
      count++;
    }

    if (!this.element.multiple) {
      if (count === 0) {
        value = null;
      } else {
        value = value[0];
      }
    }

    this.oldValue = this.value;
    this.value = value;
    this.notify();
  }

  notify() {
    let oldValue = this.oldValue;
    let newValue = this.value;

    this.callSubscribers(newValue, oldValue);
  }

  subscribe(context, callable) {
    if (!this.hasSubscribers()) {
      this.disposeHandler = this.handler.subscribe(this.element, this.synchronizeValue.bind(this, false));
    }
    this.addSubscriber(context, callable);
  }

  unsubscribe(context, callable) {
    if (this.removeSubscriber(context, callable) && !this.hasSubscribers()) {
      this.disposeHandler();
      this.disposeHandler = null;
    }
  }

  bind() {
    this.domObserver = DOM.createMutationObserver(() => {
      this.synchronizeOptions();
      this.synchronizeValue();
    });
    this.domObserver.observe(this.element, { childList: true, subtree: true });
  }

  unbind() {
    this.domObserver.disconnect();
    this.domObserver = null;

    if (this.arrayObserver) {
      this.arrayObserver.unsubscribe(selectArrayContext, this);
      this.arrayObserver = null;
    }
  }
}

const checkedArrayContext = 'CheckedObserver:array';

@subscriberCollection()
export class CheckedObserver {
  constructor(element, handler, observerLocator){
    this.element = element;
    this.handler = handler;
    this.observerLocator = observerLocator;
  }

  getValue() {
    return this.value;
  }

  setValue(newValue) {
    if (this.value === newValue) {
      return;
    }
    // unsubscribe from old array.
    if (this.arrayObserver) {
      this.arrayObserver.unsubscribe(checkedArrayContext, this);
      this.arrayObserver = null;
    }
    // subscribe to new array.
    if (this.element.type === 'checkbox' && Array.isArray(newValue)) {
      this.arrayObserver = this.observerLocator.getArrayObserver(newValue);
      this.arrayObserver.subscribe(checkedArrayContext, this);
    }
    // assign and sync element.
    this.value = newValue;
    this.synchronizeElement();
    // queue up an initial sync after the bindings have been evaluated.
    if (!this.element.hasOwnProperty('model') && !this.initialSync) {
      this.initialSync = true;
      this.observerLocator.taskQueue.queueMicroTask(this);
    }
  }

  call(context, splices) {
    // called by task queue and array observer.
    this.synchronizeElement();
  }

  synchronizeElement() {
    var value = this.value,
        element = this.element,
        elementValue = element.hasOwnProperty('model') ? element.model : element.value,
        isRadio = element.type === 'radio';

    element.checked =
      isRadio && value === elementValue
      || !isRadio && value === true
      || !isRadio && Array.isArray(value) && value.indexOf(elementValue) !== -1;
  }

  synchronizeValue(){
    var value = this.value,
        element = this.element,
        elementValue = element.hasOwnProperty('model') ? element.model : element.value,
        index;

    if (element.type === 'checkbox') {
      if (Array.isArray(value)) {
        index = value.indexOf(elementValue);
        if (element.checked && index === -1) {
          value.push(elementValue);
        } else if (!element.checked && index !== -1) {
          value.splice(index, 1);
        }
        // don't invoke callbacks.
        return;
      } else {
        value = element.checked;
      }
    } else if (element.checked) {
      value = elementValue;
    } else {
      // don't invoke callbacks.
      return;
    }

    this.oldValue = this.value;
    this.value = value;
    this.notify();
  }

  notify() {
    let oldValue = this.oldValue;
    let newValue = this.value;

    this.callSubscribers(newValue, oldValue);
  }

  subscribe(context, callable) {
    if(!this.hasSubscribers()) {
      this.disposeHandler = this.handler.subscribe(this.element, this.synchronizeValue.bind(this, false));
    }
    this.addSubscriber(context, callable);
  }

  unsubscribe(context, callable) {
    if(this.removeSubscriber(context, callable) && !this.hasSubscribers()){
      this.disposeHandler();
      this.disposeHandler = null;
    }
  }

  unbind() {
    if (this.arrayObserver) {
      this.arrayObserver.unsubscribe(checkedArrayContext, this);
      this.arrayObserver = null;
    }
  }
}
<commit_msg>feat(select): enable matcher functions<commit_after>import {subscriberCollection} from './subscriber-collection';
import {DOM} from 'aurelia-pal';

export class XLinkAttributeObserver {
  // xlink namespaced attributes require getAttributeNS/setAttributeNS
  // (even though the NS version doesn't work for other namespaces
  // in html5 documents)
  constructor(element, propertyName, attributeName) {
    this.element = element;
    this.propertyName = propertyName;
    this.attributeName = attributeName;
  }

  getValue() {
    return this.element.getAttributeNS('http://www.w3.org/1999/xlink', this.attributeName);
  }

  setValue(newValue) {
    return this.element.setAttributeNS('http://www.w3.org/1999/xlink', this.attributeName, newValue);
  }

  subscribe() {
    throw new Error(`Observation of a "${this.element.nodeName}" element\'s "${this.propertyName}" property is not supported.`);
  }
}

export class DataAttributeObserver {
  constructor(element, propertyName) {
    this.element = element;
    this.propertyName = propertyName;
  }

  getValue() {
    return this.element.getAttribute(this.propertyName);
  }

  setValue(newValue) {
    return this.element.setAttribute(this.propertyName, newValue);
  }

  subscribe() {
    throw new Error(`Observation of a "${this.element.nodeName}" element\'s "${this.propertyName}" property is not supported.`);
  }
}

export class StyleObserver {
  constructor(element, propertyName) {
    this.element = element;
    this.propertyName = propertyName;
  }

  getValue() {
    return this.element.style.cssText;
  }

  setValue(newValue) {
    if (newValue instanceof Object) {
      newValue = this.flattenCss(newValue);
    }
    this.element.style.cssText = newValue;
  }

  subscribe() {
    throw new Error(`Observation of a "${this.element.nodeName}" element\'s "${this.propertyName}" property is not supported.`);
  }

  flattenCss(object) {
    var s = '';
    for(var propertyName in object) {
      if (object.hasOwnProperty(propertyName)){
        s += propertyName + ': ' + object[propertyName] + '; ';
      }
    }
    return s;
  }
}

@subscriberCollection()
export class ValueAttributeObserver {
  constructor(element, propertyName, handler){
    this.element = element;
    this.propertyName = propertyName;
    this.handler = handler;
  }

  getValue() {
    return this.element[this.propertyName];
  }

  setValue(newValue) {
    this.element[this.propertyName] =
      (newValue === undefined || newValue === null) ? '' : newValue;

    this.notify();
  }

  notify() {
    let oldValue = this.oldValue;
    let newValue = this.getValue();

    this.callSubscribers(newValue, oldValue);

    this.oldValue = newValue;
  }

  subscribe(context, callable) {
    if (!this.hasSubscribers()) {
      this.oldValue = this.getValue();
      this.disposeHandler = this.handler.subscribe(this.element, this.notify.bind(this));
    }

    this.addSubscriber(context, callable);
  }

  unsubscribe(context, callable) {
    if (this.removeSubscriber(context, callable) && !this.hasSubscribers()) {
      this.disposeHandler();
      this.disposeHandler = null;
    }
  }
}

const selectArrayContext = 'SelectValueObserver:array'

@subscriberCollection()
export class SelectValueObserver {
  constructor(element, handler, observerLocator){
    this.element = element;
    this.handler = handler;
    this.observerLocator = observerLocator;
  }

  getValue() {
    return this.value;
  }

  setValue(newValue) {
    if (newValue !== null && newValue !== undefined && this.element.multiple && !Array.isArray(newValue)) {
      throw new Error('Only null or Array instances can be bound to a multi-select.')
    }
    if (this.value === newValue) {
      return;
    }
    // unsubscribe from old array.
    if (this.arrayObserver) {
      this.arrayObserver.unsubscribe(selectArrayContext, this);
      this.arrayObserver = null;
    }
    // subscribe to new array.
    if (Array.isArray(newValue)) {
      this.arrayObserver = this.observerLocator.getArrayObserver(newValue);
      this.arrayObserver.subscribe(selectArrayContext, this);
    }
    // assign and sync element.
    this.value = newValue;
    this.synchronizeOptions();
    // queue up an initial sync after the bindings have been evaluated.
    if (!this.initialSync) {
      this.initialSync = true;
      this.observerLocator.taskQueue.queueMicroTask(this);
    }
  }

  call(context, splices) {
    // called by task queue and array observer.
    this.synchronizeOptions();
  }

  synchronizeOptions() {
    let value = this.value, clear, isArray;

    if (value === null || value === undefined) {
      clear = true;
    } else if (Array.isArray(value)) {
      isArray = true;
    }

    let options = this.element.options;
    let i = options.length;
    let matcher = this.element.matcher || ((a, b) => a === b);
    while(i--) {
      let option = options.item(i);
      if (clear) {
        option.selected = false;
        continue;
      }
      let optionValue = option.hasOwnProperty('model') ? option.model : option.value;
      if (isArray) {
        option.selected = !!value.find(item => !!matcher(optionValue, item));
        continue;
      }
      option.selected = !!matcher(optionValue, value);
    }
  }

  synchronizeValue() {
    let options = this.element.options,
        count = 0,
        value = [];

    for (let i = 0, ii = options.length; i < ii; i++) {
      let option = options.item(i);
      if (!option.selected) {
        continue;
      }
      value.push(option.hasOwnProperty('model') ? option.model : option.value);
      count++;
    }

    if (this.element.multiple) {
      // multi-select
      if (Array.isArray(this.value)) {
        let matcher = this.element.matcher || ((a, b) => a === b);
        // remove items that are no longer selected.
        let i = 0;
        while (i < this.value.length) {
          let a = this.value[i];
          if (value.findIndex(b => matcher(a, b)) === -1) {
            this.value.splice(i, 1);
          } else {
            i++;
          }
        }
        // add items that have been selected.
        i = 0;
        while (i < value.length) {
          let a = value[i];
          if (this.value.findIndex(b => matcher(a, b)) === -1) {
            this.value.push(a);
          }
          i++;
        }
        return; // don't notify.
      }
    } else {
      // single-select
      if (count === 0) {
        value = null;
      } else {
        value = value[0];
      }
    }

    if (value !== this.value) {
      this.oldValue = this.value;
      this.value = value;
      this.notify();
    }
  }

  notify() {
    let oldValue = this.oldValue;
    let newValue = this.value;

    this.callSubscribers(newValue, oldValue);
  }

  subscribe(context, callable) {
    if (!this.hasSubscribers()) {
      this.disposeHandler = this.handler.subscribe(this.element, this.synchronizeValue.bind(this, false));
    }
    this.addSubscriber(context, callable);
  }

  unsubscribe(context, callable) {
    if (this.removeSubscriber(context, callable) && !this.hasSubscribers()) {
      this.disposeHandler();
      this.disposeHandler = null;
    }
  }

  bind() {
    this.domObserver = DOM.createMutationObserver(() => {
      this.synchronizeOptions();
      this.synchronizeValue();
    });
    this.domObserver.observe(this.element, { childList: true, subtree: true });
  }

  unbind() {
    this.domObserver.disconnect();
    this.domObserver = null;

    if (this.arrayObserver) {
      this.arrayObserver.unsubscribe(selectArrayContext, this);
      this.arrayObserver = null;
    }
  }
}

const checkedArrayContext = 'CheckedObserver:array';

@subscriberCollection()
export class CheckedObserver {
  constructor(element, handler, observerLocator){
    this.element = element;
    this.handler = handler;
    this.observerLocator = observerLocator;
  }

  getValue() {
    return this.value;
  }

  setValue(newValue) {
    if (this.value === newValue) {
      return;
    }
    // unsubscribe from old array.
    if (this.arrayObserver) {
      this.arrayObserver.unsubscribe(checkedArrayContext, this);
      this.arrayObserver = null;
    }
    // subscribe to new array.
    if (this.element.type === 'checkbox' && Array.isArray(newValue)) {
      this.arrayObserver = this.observerLocator.getArrayObserver(newValue);
      this.arrayObserver.subscribe(checkedArrayContext, this);
    }
    // assign and sync element.
    this.value = newValue;
    this.synchronizeElement();
    // queue up an initial sync after the bindings have been evaluated.
    if (!this.initialSync) {
      this.initialSync = true;
      this.observerLocator.taskQueue.queueMicroTask(this);
    }
  }

  call(context, splices) {
    // called by task queue and array observer.
    this.synchronizeElement();
  }

  synchronizeElement() {
    let value = this.value,
        element = this.element,
        elementValue = element.hasOwnProperty('model') ? element.model : element.value,
        isRadio = element.type === 'radio',
        matcher = element.matcher || ((a, b) => a === b);

    element.checked =
      isRadio && !!matcher(value, elementValue)
      || !isRadio && value === true
      || !isRadio && Array.isArray(value) && !!value.find(item => !!matcher(item, elementValue));
  }

  synchronizeValue(){
    let value = this.value,
        element = this.element,
        elementValue = element.hasOwnProperty('model') ? element.model : element.value,
        index,
        matcher = element.matcher || ((a, b) => a === b);

    if (element.type === 'checkbox') {
      if (Array.isArray(value)) {
        index = value.findIndex(item => !!matcher(item, elementValue));
        if (element.checked && index === -1) {
          value.push(elementValue);
        } else if (!element.checked && index !== -1) {
          value.splice(index, 1);
        }
        // don't invoke callbacks.
        return;
      } else {
        value = element.checked;
      }
    } else if (element.checked) {
      value = elementValue;
    } else {
      // don't invoke callbacks.
      return;
    }

    this.oldValue = this.value;
    this.value = value;
    this.notify();
  }

  notify() {
    let oldValue = this.oldValue;
    let newValue = this.value;

    this.callSubscribers(newValue, oldValue);
  }

  subscribe(context, callable) {
    if(!this.hasSubscribers()) {
      this.disposeHandler = this.handler.subscribe(this.element, this.synchronizeValue.bind(this, false));
    }
    this.addSubscriber(context, callable);
  }

  unsubscribe(context, callable) {
    if(this.removeSubscriber(context, callable) && !this.hasSubscribers()){
      this.disposeHandler();
      this.disposeHandler = null;
    }
  }

  unbind() {
    if (this.arrayObserver) {
      this.arrayObserver.unsubscribe(checkedArrayContext, this);
      this.arrayObserver = null;
    }
  }
}
<|endoftext|>


<commit_before>import cx from 'classnames'
import _ from 'lodash'
import React, { Component, PropTypes } from 'react'
import DocumentTitle from 'react-document-title'
import { Link } from 'react-router'

import ComponentExamples from './ComponentExamples'
import ComponentProps from './ComponentProps'
import docgenInfo from '../../docgenInfo.json'

import { META } from 'src/lib'
import * as stardust from 'src'
import { Grid, Header, Icon, List } from 'src'

const docgenPaths = _.keys(docgenInfo)

const pathSepRegEx = new RegExp(_.escapeRegExp(__PATH_SEP__), 'g')

const getDocgenPath = (componentName) => _.find(docgenPaths, path => {
  return new RegExp(`${__PATH_SEP__}${componentName}.js$`).test(path)
})

// no matter the OS path separator, use '/'
const getPosixPath = (componentName) => getDocgenPath(componentName).replace(pathSepRegEx, '/')

const getGithubSourceUrl = (componentName) => {
  const posixPath = getPosixPath(componentName)
  return `https://github.com/TechnologyAdvice/stardust/blob/master/${posixPath}`
}

const getGithubEditUrl = (componentName) => {
  const posixPath = getPosixPath(componentName)
  return `https://github.com/TechnologyAdvice/stardust/edit/master/${posixPath}`
}

const getSemanticUIDocsUrl = (_meta) => {
  return `http://semantic-ui.com/${_meta.type}s/${_meta.parent || _meta.name}`.toLowerCase()
}

const showPropsStyle = {
  display: 'inline-flex',
  marginRight: '0.5em',
  marginTop: 0,
  cursor: 'pointer',
}

const linkListStyle = {
  position: 'absolute',
  padding: '0.5em',
  margin: '0.5em',
  top: '0',
  right: '0',
  boxShadow: '0 0 1em 0.5em #f7f7f7',
  background: '#f7f7f7',
}

export default class ComponentDoc extends Component {
  static propTypes = {
    _meta: PropTypes.object,
  }

  state = {
    showPropsFor: null,
  }

  componentWillReceiveProps(nextProps) {
    this.setState({
      showPropsFor: this.state.showPropsFor ? nextProps._meta.name : null,
    })
  }

  toggleProps = (name) => {
    this.setState({
      showPropsFor: this.state.showPropsFor === name ? null : name,
    })
  }

  renderSee() {
    const { _meta } = this.props
    const docPath = getDocgenPath(_meta.name)
    const docgen = docgenInfo[docPath]
    const seeTags = _.filter(docgen.docBlock.tags, ['title', 'see'])

    const seeLinks = _.map(seeTags, ({ description }) => {
      const seeMeta = _.get(stardust[description], '_meta')
      if (!seeMeta) return

      const { type, name } = seeMeta

      return (
        <Link key={description} to={`/${type}s/${_.kebabCase(name)}`} className='item'>
          {description}
        </Link>
      )
    })

    // still render empty lists to reserve the whitespace
    return (
      <List className='horizontal' style={{ display: 'block' }}>

            {seeLinks.length > 0 ? 'See:' : ' '}

        {seeLinks}
      </List>
    )
  }

  renderSemanticDocsLink = () => {
    const { _meta } = this.props

    if (META.isAddon(_meta)) return null

    return (
      <List.Item icon='book'>

          Semantic UI {_meta.parent || _meta.name} Docs

      </List.Item>
    )
  }

  renderGithubSourceLink() {
    const { _meta } = this.props
    const docPath = getDocgenPath(_meta.name)
    // no matter the OS path separator, use '/' since these link to github
    const posixPath = docPath.replace(pathSepRegEx, '/')
    return (
      <List.Item icon='github'>

          {posixPath}

      </List.Item>
    )
  }

  renderProps = () => {
    const { _meta } = this.props
    const { showPropsFor } = this.state

    const itemCX = name => cx(showPropsFor === name && 'active', 'link item')
    const selectedDocgen = docgenInfo[getDocgenPath(showPropsFor)]
    const toggleIcon = `toggle ${showPropsFor ? 'on' : 'off'}`

    const subComponents = _.flatMap(stardust, SDComponent => _.filter(SDComponent, staticValue => (
      _.get(staticValue, '_meta.parent') === _meta.name
    )))

    const hasSubComponents = !_.isEmpty(subComponents)

    const subComponentItems = _.map(subComponents, ({ _meta: { name } }) => (

 this.toggleProps(name)}>
        {_meta.name}.{name.replace(_meta.name, '')}

    ))

    return (

         this.toggleProps(showPropsFor || _meta.name)}
        >
          <Icon name={toggleIcon} /> Props{hasSubComponents && ':'}

          {hasSubComponents && (

 this.toggleProps(_meta.name)}>
              {_meta.name}

          )}
          {subComponentItems}

        {selectedDocgen && (

            <ComponentProps props={selectedDocgen.props} />

        )}

    )
  }

  renderHeader = () => {
    const { _meta } = this.props
    const docgen = docgenInfo[getDocgenPath(_meta.name)]

    return (

        {_meta.name}

          {/* TODO: Remove once all components have descriptions */}
          {docgen.docBlock.description || (

              Add a description. Instructions are{' '}

                here.

              {' '}Description is in the SUI Docs, right there <Icon name='pointing right' />

          )}

    )
  }

  render() {
    const { _meta } = this.props

    return (
      <DocumentTitle title={`${_meta.name} | UI React`}>

          <Grid padded columns='1'>
            <Grid.Column>
              {this.renderHeader()}
              {this.renderSee()}
              <List className='link' style={linkListStyle}>
                {this.renderGithubSourceLink()}
                {this.renderSemanticDocsLink()}
              </List>
              {this.renderProps()}
            </Grid.Column>
          </Grid>
          <ComponentExamples name={_meta.name} />

      </DocumentTitle>
    )
  }
}
<commit_msg>docs(ComponentDoc): improve props ux<commit_after>import cx from 'classnames'
import _ from 'lodash'
import React, { Component, PropTypes } from 'react'
import DocumentTitle from 'react-document-title'
import { Link } from 'react-router'

import ComponentExamples from './ComponentExamples'
import ComponentProps from './ComponentProps'
import docgenInfo from '../../docgenInfo.json'

import { META } from 'src/lib'
import * as stardust from 'src'
import { Grid, Header, Icon, List } from 'src'

const docgenPaths = _.keys(docgenInfo)

const pathSepRegEx = new RegExp(_.escapeRegExp(__PATH_SEP__), 'g')

const getDocgenPath = (componentName) => _.find(docgenPaths, path => {
  return new RegExp(`${__PATH_SEP__}${componentName}.js$`).test(path)
})

// no matter the OS path separator, use '/'
const getPosixPath = (componentName) => getDocgenPath(componentName).replace(pathSepRegEx, '/')

const getGithubSourceUrl = (componentName) => {
  const posixPath = getPosixPath(componentName)
  return `https://github.com/TechnologyAdvice/stardust/blob/master/${posixPath}`
}

const getGithubEditUrl = (componentName) => {
  const posixPath = getPosixPath(componentName)
  return `https://github.com/TechnologyAdvice/stardust/edit/master/${posixPath}`
}

const getSemanticUIDocsUrl = (_meta) => {
  return `http://semantic-ui.com/${_meta.type}s/${_meta.parent || _meta.name}`.toLowerCase()
}

const showPropsStyle = {
  display: 'inline-flex',
  margin: '1em 0.5em',
  marginLeft: 0,
  cursor: 'pointer',
}

const linkListStyle = {
  position: 'absolute',
  padding: '0.5em',
  margin: '0.5em',
  top: '0',
  right: '0',
  boxShadow: '0 0 1em 0.5em #f7f7f7',
  background: '#f7f7f7',
}

export default class ComponentDoc extends Component {
  static propTypes = {
    _meta: PropTypes.object,
  }

  state = {
    showPropsFor: null,
  }

  componentWillReceiveProps(nextProps) {
    this.setState({
      showPropsFor: this.state.showPropsFor ? nextProps._meta.name : null,
    })
  }

  toggleProps = (name) => {
    this.setState({
      showPropsFor: this.state.showPropsFor === name ? null : name,
    })
  }

  renderSee() {
    const { _meta } = this.props
    const docPath = getDocgenPath(_meta.name)
    const docgen = docgenInfo[docPath]
    const seeTags = _.filter(docgen.docBlock.tags, ['title', 'see'])

    const seeLinks = _.map(seeTags, ({ description }) => {
      const seeMeta = _.get(stardust[description], '_meta')
      if (!seeMeta) return

      const { type, name } = seeMeta

      return (
        <Link key={description} to={`/${type}s/${_.kebabCase(name)}`} className='item'>
          {description}
        </Link>
      )
    })

    // still render empty lists to reserve the whitespace
    return (
      <List className='small horizontal link' style={{ display: 'block' }}>
        <List.Item>

            {seeLinks.length > 0 ? 'See:' : ' '}

        </List.Item>
        {seeLinks}
      </List>
    )
  }

  renderSemanticDocsLink = () => {
    const { _meta } = this.props

    if (META.isAddon(_meta)) return null

    return (
      <List.Item icon='book'>

          Semantic UI {_meta.parent || _meta.name} Docs

      </List.Item>
    )
  }

  renderGithubSourceLink() {
    const { _meta } = this.props
    const docPath = getDocgenPath(_meta.name)
    // no matter the OS path separator, use '/' since these link to github
    const posixPath = docPath.replace(pathSepRegEx, '/')
    return (
      <List.Item icon='github'>

          {posixPath}

      </List.Item>
    )
  }

  renderProps = () => {
    const { _meta } = this.props
    const { showPropsFor } = this.state

    const itemCX = name => cx(showPropsFor === name && 'active', 'link item')
    const selectedDocgen = docgenInfo[getDocgenPath(showPropsFor)]
    const toggleIcon = `toggle ${showPropsFor ? 'on' : 'off'}`

    const subComponents = _.flatMap(stardust, SDComponent => _.filter(SDComponent, staticValue => (
      _.get(staticValue, '_meta.parent') === _meta.name
    )))

    const hasSubComponents = !_.isEmpty(subComponents)

    const subComponentItems = _.map(subComponents, ({ _meta: { name } }) => (

 this.toggleProps(name)}>
        {_meta.name}.{name.replace(_meta.name, '')}

    ))

    return (

         this.toggleProps(showPropsFor || _meta.name)}
        >
          <Icon name={toggleIcon} /> Props{hasSubComponents && ':'}

          {hasSubComponents && (

 this.toggleProps(_meta.name)}>
              {_meta.name}

          )}
          {subComponentItems}

        {selectedDocgen && (

            <ComponentProps props={selectedDocgen.props} />

        )}

    )
  }

  renderHeader = () => {
    const { _meta } = this.props
    const docgen = docgenInfo[getDocgenPath(_meta.name)]

    return (

        {_meta.name}

          {/* TODO: Remove once all components have descriptions */}
          {docgen.docBlock.description || (

              Add a description. Instructions are{' '}

                here.

              {' '}Description is in the SUI Docs, right there <Icon name='pointing right' />

          )}

    )
  }

  render() {
    const { _meta } = this.props

    return (
      <DocumentTitle title={`${_meta.name} | UI React`}>

          <Grid padded columns='1'>
            <Grid.Column>
              {this.renderHeader()}
              {this.renderSee()}
              <List className='link' style={linkListStyle}>
                {this.renderGithubSourceLink()}
                {this.renderSemanticDocsLink()}
              </List>
              {this.renderProps()}
            </Grid.Column>
          </Grid>
          <ComponentExamples name={_meta.name} />

      </DocumentTitle>
    )
  }
}
<|endoftext|>