<commit_before>/*
 ---

 name: Tree

 script: tree.js

 description: MUI.Tree - Creates a generic tree control.

 copyright: (c) 2011 Contributors in (/AUTHORS.txt).

 license: MIT-style license in (/MIT-LICENSE.txt).

 note:
 This documentation is taken directly from the javascript source files. It is built using Natural Docs.

 requires:
 - Core/Element
 - Core/Class
 - Core/Options
 - Core/Events
 - MUI
 - MUI.Core

 provides: [MUI.Tree]
 ...
 */

MUI.Tree = new NamedClass('MUI.Tree', {

	Implements: [Events, Options],

	options: {
		id:					'',				// id of the primary element, and id os control that is registered with mocha
		container:			null,			// the parent control in the document to add the control to
		clearContainer:		true,			// should the control clear its parent container before it appends itself
		drawOnInit:			true,			// true to add tree to container when control is initialized

		content:			false,			// used to load content
		nodes:				[],				// the hierarchical list of nodes

		textField:			'text',			// the name of the field that has the node's text
		valueField:			'value',		// the name of the field that has the node's value
		idField:			'id',			// the name of the field that has anchors id value
		titleField:			'title',		// the name of the field that has the node's tip text
		isCheckedField:		'checked',		// the name of the field that has the node's isChecked state
		hasChildrenField:	'hasChildren',	// the name of the field that has the node's hasChildren flag
		imageField:			'image',		// the name of the field that has the node's image if imageOpenField and imageClosedField are not defined
		imageOpenField:		'imageOpen',	// the name of the field that has the node's open image
		imageClosedField:	'imageClosed',	// the name of the field that has the node's closed image

		partner:			 false,			// default partner element to send content to
		partnerMethod:		 'xhr',			// default loadMethod when sending content to partner
		cssClass:			'tree',			// the primary css tag
		showIcon:			true,
		showCheckBox:		false,			// true to show checkBoxes
		canSelect:			true,			// can the user select a node by clicking it
		value:				'',				// the currently selected node's value
		selectedNode:		null,			// the currently selected node
		depth:				2				// how deep to expand the nodes to

		//onNodeExpanded:	null			// event: called when node is expanded
		//onNodeChecked: 	null			// event: called when node's checkbox is checked
		//onNodeClicked:	null			// event: when a node is checked
		//onLoaded:		    null			// event: called when tree is done building itself
	},

	initialize: function(options){
		this.setOptions(options);
		options = this.options;
		this.el = {};

		// If tree has no ID, give it one.
		this.id = options.id = options.id || 'tree' + (++MUI.idCount);
		MUI.set(this.id, this);

		if (options.content){
			options.content.loadMethod = MUI.getDefaultJsonProvider(options.content.loadMethod);
			options.content.onLoaded = (function(element, options){
				this.options.nodes = MUI.Content.getRecords(options);
				this.draw();
			}).bind(this);
			MUI.Content.update(options.content);
		} else {
			// create sub items if available
			if (options.drawOnInit && options.nodes.length > 0) this.draw();
		}
	},

	draw: function(container){
		var o = this.options;
		if (!container) container = o.container;

		var isNew = false;
		var div = o.element ? o.element : $(o.id);
		var ul;
		if (!div){
			div = new Element('div', {'id': o.id, 'class': o.cssClass});
			isNew = true;
		} else ul = div.getElement('ul');
		if (!ul) ul = new Element('ul', {'class': o.cssClass}).inject(div.empty());
		else ul.empty();
		this.el.element = div;

		var nodes = o.nodes;
		if (o.nodes.length > 1){
			var li = new Element('li').inject(ul);
			ul = new Element('ul').inject(li);
		}
		nodes.each(function(node){
			this.buildNode(node, ul, 1);
		}, this);
		var first = ul.getFirst();
		if (first) first.addClass('first');
		var last = ul.getChildren().getLast();
		if (last) last.addClass('last');

		o.depth = 0;

		if (!isNew){
			this.fireEvent('loaded', [this]);
			return this;
		}

		var addToContainer = function(){
			if (o.clearContainer) container.empty();
			div.inject(container);
			this.fireEvent('loaded', [this]);
		}.bind(this);

		if (typeof(container) == 'element'){
			addToContainer();
			return this;
		} else window.addEvent('domready', function(){
			// determine parent container object
			if (typeof(container) == 'string'){
				container = $(container);
				var instance = MUI.get(container);
				if (instance){
					div.setStyle('overflow', 'auto');
					if (instance.el.content) container = instance.el.content;
				}
			}
			addToContainer();
		}.bind(this));

		return this;
	},

	selectValue: function(val, e, suppressEvent){
		var self = this;
		var o = self.options;
		var node = self.nodeFind(val);
		if (!node) return;

		if (!o.canSelect){
			if (o.showCheckBox){
				node._checkbox.checked = !node._checkbox.checked;
				self.onNodeCheck(node, e);
			} else if (!suppressEvent) this.fireEvent('nodeSelected', [node, self, e]);
			return;
		}

		if (node._element){
			if (o.selectedNode && o.selectedNode._element) o.selectedNode._element.getElement('a').removeClass('sel');
			o.selectedNode = node;
			node._element.getElement('a').addClass('sel');
		}
		o.value = val;
		if (!suppressEvent) this.fireEvent('nodeSelected', [node, self, e]);
	},

	updateNode: function(node){
		if (!node) return;

		var self = this;
		var o = self.options;
		var n = node;
		if (!node._element) n = self.nodeFind(MUI.getData(node, o.valueField));
		if (n){
			var el = n._element;
			if (el){
				self.buildNode(node, el.getParent());
				self.setLast(el.getParent());
			}
		}
	},

	buildNode: function(node, parent, depth){
		var o = this.options;
		if (!depth) depth = 1;

		var a, span, ul, li;
		var id = MUI.getData(node, o.idField);
		if (!id) id = 'tn' + (++MUI.idCount);

		if (node._element != null) li = node._element;
		if (!li) li = new Element('li', {'id': id + '_li'});
		else li.empty();

		if (parent){
			if (parent._ul) li.inject(parent._ul);
			else li.inject(parent);
		}

		var value = MUI.getData(node, o.valueField);
		var text = MUI.getData(node, o.textField);
		if (o.showCheckBox) node._checkbox = new Element('INPUT', {'type': 'checkbox', 'value': value, 'id': id + '_cb'}).inject(li);
		a = node._a = new Element('a', {'id': id}).inject(li);
		if (node.target) a.setAttribute('target', node.target); 									// add anchor target
		span = node._span = new Element('span', {'text': text, 'id': id + '_tle'}).inject(a);		// add node text
		if (o.showIcon) node._icon = new Element('span', {'class': 'treeIcon'}).inject(a, 'top');	// add node image

		node._element = li;
		var title = MUI.getData(node, o.titleField);
		if (title) a.title = title;

		var url = node.url;
		if (!url || node.registered){		// is node using registered function mapping
			url = '#';

			// determine partner settings
			var partner = node.partnerContent;
			if (url && partner){
				if (!partner.element) partner.element = o.partner;
				if (!partner.loadMethod) partner.loadMethod = o.partnerMethod;
				if (!partner.title) partner.title = node.title;
				if (!partner.title) partner.title = node.text;
				if (partner.element) a.addEvent('click', MUI.getPartnerLoader(this, partner));
			} else

			// if not using a partner then check for registered method calls
			if (node.registered && node.registered != '')
				a.addEvent('click', MUI.getRegistered(this, node.registered, [node]));
		}
		a.setAttribute('href', MUI.replacePaths(url));

		if (o.value == value){
			this.el.element.getElements('.sel').removeClass('sel');
			a.className = 'sel';
			o.selectedNode = this;
		}

		if (node.nodes && node.nodes.length > 0){
			if (!ul) ul = new Element('ul').inject(li);
			if (!node.isExpanded && o.depth <= depth){
				ul.style.display = 'none';
				node.isExpanded = false;
			} else node.isExpanded = true;
			node._ul = ul;

			for (var i = 0; i < node.nodes.length; i++){
				this.buildNode(node.nodes[i], node, ul, depth + 1);
			}
			ul.childNodes[ul.childNodes.length - 1].addClass('last');
		} else li.addClass('nochild');
		if (node.isExpanded) li.set('class', 'O');

		// add image to node if necessary
		this._nodeSetImage(node);

		var hasChildren = MUI.getData(node, o.hasChildrenField);
		if (hasChildren && li.hasClass('nochild')) li.removeClass('nochild').addClass('C');

		// set events
		if (node._checkbox){
			var isChecked = MUI.getData(node, o.isCheckedField);
			if (isChecked != null) node._checkbox.checked = isChecked;
			node._checkbox.removeEvents('click')._checkbox.addEvent('click', MUI.getWrappedEvent(this, this.onNodeCheck, [node]));
		}
		li.addEvent('click', MUI.getWrappedEvent(this, this.onNodeExpand, [node]));
		a.addEvent('click', MUI.getWrappedEvent(this, this.onNodeClick, [node]));

		return this;
	},

	nodeFind: function(val, node){
		var self = this;
		var o = self.options;
		if (node != null){
			var value = MUI.getData(node, o.valueField);
			if (value && value + '' == val + '') return node;
		} else node = self;
		var nodes;
		if (node.options) nodes = node.options.nodes;
		if (nodes == null) nodes = node.nodes;
		if (nodes){
			var l = nodes.length;
			for (var i = 0; i < l; i++){
				var snode = this.nodeFind(val, nodes[i]);
				if (snode) return snode;
			}
		}
		return null;
	},

	nodeRefresh: function(node){
		if (!node._element) return;
		this.buildNode(node, node._element.getParent())
				.setLast(node._element.getParent());
	},

	nodeGetPath: function(node){
		var self = this;
		var o = self.options;
		var value = MUI.getData(node, o.valueField);

		if (!node._parent) return value;
		return this.getPath(node._parent) + '/' + value;
	},

	setLast: function(node){
		if (!node) return this;
		if (node.childNodes){
			var u = node;
			if (node.nodeName != 'UL') u = node.getElement('ul');
			if (u){
				var children = u.getChildren();
				if (children){
					children.removeClass('last');
					children.getLast().addClass('last');
				}
			}
		}
		return this;
	},

	_nodeSetImage: function(node){
		var o = this.options;
		var span = node._span;
		var def = MUI.getData(node, o.imageField);
		var open = MUI.getData(node, o.imageOpenField) || def;
		var closed = MUI.getData(node, o.imageClosedField) || def;

		span.removeClass(closed).removeClass(open);

		if (closed && !node.isExpanded){
			if (closed.indexOf('.') < 0) span.addClass(closed);
			else span.setStyles({'background': 'transparent url(' + closed + ') no-repeat scroll left top', 'paddingLeft': '20px'});
		}
		if (open && node.isExpanded){
			if (open.indexOf('.') < 0) span.addClass(open);
			else span.setStyles({'background': 'transparent url(' + open + ') no-repeat scroll left top', 'paddingLeft': '20px'});
		}
	},

	onNodeExpand: function(e, node){
		var itm = node._element;
		var mY = 0;
		var mX = 0;
		if (e){
			e = new Event(e).stop();
			var c = itm.getCoordinates();
			mY = e.client.y - c.top;
			mX = e.client.x - c.left;
		}

		if (mX < 20 && mY < 20){
			var ul = itm.getElement('ul');
			if (ul && node.isExpanded){
				ul.style.display = 'none';
				itm.removeClass('O').addClass('C');
				node.isExpanded = false;
				//return;
			} else if (ul && !node.isExpanded){
				ul.style.display = '';
				itm.removeClass('C').addClass('O');
				node.isExpanded = true;
				//if (node.nodes.length > 0) return;
			}
			this._nodeSetImage(node);
		}

		this.fireEvent('nodeExpanded', [e, node, this]);
	},

	onNodeClick: function(e, node){
		var o = this.options;
		e = new Event(e).stop();
		this.selectValue(MUI.getData(node, o.valueField), e);
		this.fireEvent('nodeClicked', [e, node, this]);
	},

	onNodeCheck: function(e, node){
		e = new Event(e).stopPropagation();
		this.fireEvent('nodeChecked', [e, node, this]);
	}

});
<commit_msg>Removed extra param in function call<commit_after>/*
 ---

 name: Tree

 script: tree.js

 description: MUI.Tree - Creates a generic tree control.

 copyright: (c) 2011 Contributors in (/AUTHORS.txt).

 license: MIT-style license in (/MIT-LICENSE.txt).

 note:
 This documentation is taken directly from the javascript source files. It is built using Natural Docs.

 requires:
 - Core/Element
 - Core/Class
 - Core/Options
 - Core/Events
 - MUI
 - MUI.Core

 provides: [MUI.Tree]
 ...
 */

MUI.Tree = new NamedClass('MUI.Tree', {

	Implements: [Events, Options],

	options: {
		id:					'',				// id of the primary element, and id os control that is registered with mocha
		container:			null,			// the parent control in the document to add the control to
		clearContainer:		true,			// should the control clear its parent container before it appends itself
		drawOnInit:			true,			// true to add tree to container when control is initialized

		content:			false,			// used to load content
		nodes:				[],				// the hierarchical list of nodes

		textField:			'text',			// the name of the field that has the node's text
		valueField:			'value',		// the name of the field that has the node's value
		idField:			'id',			// the name of the field that has anchors id value
		titleField:			'title',		// the name of the field that has the node's tip text
		isCheckedField:		'checked',		// the name of the field that has the node's isChecked state
		hasChildrenField:	'hasChildren',	// the name of the field that has the node's hasChildren flag
		imageField:			'image',		// the name of the field that has the node's image if imageOpenField and imageClosedField are not defined
		imageOpenField:		'imageOpen',	// the name of the field that has the node's open image
		imageClosedField:	'imageClosed',	// the name of the field that has the node's closed image

		partner:			 false,			// default partner element to send content to
		partnerMethod:		 'xhr',			// default loadMethod when sending content to partner
		cssClass:			'tree',			// the primary css tag
		showIcon:			true,
		showCheckBox:		false,			// true to show checkBoxes
		canSelect:			true,			// can the user select a node by clicking it
		value:				'',				// the currently selected node's value
		selectedNode:		null,			// the currently selected node
		depth:				2				// how deep to expand the nodes to

		//onNodeExpanded:	null			// event: called when node is expanded
		//onNodeChecked: 	null			// event: called when node's checkbox is checked
		//onNodeClicked:	null			// event: when a node is checked
		//onLoaded:		    null			// event: called when tree is done building itself
	},

	initialize: function(options){
		this.setOptions(options);
		options = this.options;
		this.el = {};

		// If tree has no ID, give it one.
		this.id = options.id = options.id || 'tree' + (++MUI.idCount);
		MUI.set(this.id, this);

		if (options.content){
			options.content.loadMethod = MUI.getDefaultJsonProvider(options.content.loadMethod);
			options.content.onLoaded = (function(element, options){
				this.options.nodes = MUI.Content.getRecords(options);
				this.draw();
			}).bind(this);
			MUI.Content.update(options.content);
		} else {
			// create sub items if available
			if (options.drawOnInit && options.nodes.length > 0) this.draw();
		}
	},

	draw: function(container){
		var o = this.options;
		if (!container) container = o.container;

		var isNew = false;
		var div = o.element ? o.element : $(o.id);
		var ul;
		if (!div){
			div = new Element('div', {'id': o.id, 'class': o.cssClass});
			isNew = true;
		} else ul = div.getElement('ul');
		if (!ul) ul = new Element('ul', {'class': o.cssClass}).inject(div.empty());
		else ul.empty();
		this.el.element = div;

		var nodes = o.nodes;
		if (o.nodes.length > 1){
			var li = new Element('li').inject(ul);
			ul = new Element('ul').inject(li);
		}
		nodes.each(function(node){
			this.buildNode(node, ul, 1);
		}, this);
		var first = ul.getFirst();
		if (first) first.addClass('first');
		var last = ul.getChildren().getLast();
		if (last) last.addClass('last');

		o.depth = 0;

		if (!isNew){
			this.fireEvent('loaded', [this]);
			return this;
		}

		var addToContainer = function(){
			if (o.clearContainer) container.empty();
			div.inject(container);
			this.fireEvent('loaded', [this]);
		}.bind(this);

		if (typeof(container) == 'element'){
			addToContainer();
			return this;
		} else window.addEvent('domready', function(){
			// determine parent container object
			if (typeof(container) == 'string'){
				container = $(container);
				var instance = MUI.get(container);
				if (instance){
					div.setStyle('overflow', 'auto');
					if (instance.el.content) container = instance.el.content;
				}
			}
			addToContainer();
		}.bind(this));

		return this;
	},

	selectValue: function(val, e, suppressEvent){
		var self = this;
		var o = self.options;
		var node = self.nodeFind(val);
		if (!node) return;

		if (!o.canSelect){
			if (o.showCheckBox){
				node._checkbox.checked = !node._checkbox.checked;
				self.onNodeCheck(node, e);
			} else if (!suppressEvent) this.fireEvent('nodeSelected', [node, self, e]);
			return;
		}

		if (node._element){
			if (o.selectedNode && o.selectedNode._element) o.selectedNode._element.getElement('a').removeClass('sel');
			o.selectedNode = node;
			node._element.getElement('a').addClass('sel');
		}
		o.value = val;
		if (!suppressEvent) this.fireEvent('nodeSelected', [node, self, e]);
	},

	updateNode: function(node){
		if (!node) return;

		var self = this;
		var o = self.options;
		var n = node;
		if (!node._element) n = self.nodeFind(MUI.getData(node, o.valueField));
		if (n){
			var el = n._element;
			if (el){
				self.buildNode(node, el.getParent());
				self.setLast(el.getParent());
			}
		}
	},

	buildNode: function(node, parent, depth){
		var o = this.options;
		if (!depth) depth = 1;

		var a, span, ul, li;
		var id = MUI.getData(node, o.idField);
		if (!id) id = 'tn' + (++MUI.idCount);

		if (node._element != null) li = node._element;
		if (!li) li = new Element('li', {'id': id + '_li'});
		else li.empty();

		if (parent){
			if (parent._ul) li.inject(parent._ul);
			else li.inject(parent);
		}

		var value = MUI.getData(node, o.valueField);
		var text = MUI.getData(node, o.textField);
		if (o.showCheckBox) node._checkbox = new Element('INPUT', {'type': 'checkbox', 'value': value, 'id': id + '_cb'}).inject(li);
		a = node._a = new Element('a', {'id': id}).inject(li);
		if (node.target) a.setAttribute('target', node.target); 									// add anchor target
		span = node._span = new Element('span', {'text': text, 'id': id + '_tle'}).inject(a);		// add node text
		if (o.showIcon) node._icon = new Element('span', {'class': 'treeIcon'}).inject(a, 'top');	// add node image

		node._element = li;
		var title = MUI.getData(node, o.titleField);
		if (title) a.title = title;

		var url = node.url;
		if (!url || node.registered){		// is node using registered function mapping
			url = '#';

			// determine partner settings
			var partner = node.partnerContent;
			if (url && partner){
				if (!partner.element) partner.element = o.partner;
				if (!partner.loadMethod) partner.loadMethod = o.partnerMethod;
				if (!partner.title) partner.title = node.title;
				if (!partner.title) partner.title = node.text;
				if (partner.element) a.addEvent('click', MUI.getPartnerLoader(this, partner));
			} else

			// if not using a partner then check for registered method calls
			if (node.registered && node.registered != '')
				a.addEvent('click', MUI.getRegistered(this, node.registered, [node]));
		}
		a.setAttribute('href', MUI.replacePaths(url));

		if (o.value == value){
			this.el.element.getElements('.sel').removeClass('sel');
			a.className = 'sel';
			o.selectedNode = this;
		}

		if (node.nodes && node.nodes.length > 0){
			if (!ul) ul = new Element('ul').inject(li);
			if (!node.isExpanded && o.depth <= depth){
				ul.style.display = 'none';
				node.isExpanded = false;
			} else node.isExpanded = true;
			node._ul = ul;

			for (var i = 0; i < node.nodes.length; i++){
				this.buildNode(node.nodes[i], node, depth + 1);
			}
			ul.childNodes[ul.childNodes.length - 1].addClass('last');
		} else li.addClass('nochild');
		if (node.isExpanded) li.set('class', 'O');

		// add image to node if necessary
		this._nodeSetImage(node);

		var hasChildren = MUI.getData(node, o.hasChildrenField);
		if (hasChildren && li.hasClass('nochild')) li.removeClass('nochild').addClass('C');

		// set events
		if (node._checkbox){
			var isChecked = MUI.getData(node, o.isCheckedField);
			if (isChecked != null) node._checkbox.checked = isChecked;
			node._checkbox.removeEvents('click')._checkbox.addEvent('click', MUI.getWrappedEvent(this, this.onNodeCheck, [node]));
		}
		li.addEvent('click', MUI.getWrappedEvent(this, this.onNodeExpand, [node]));
		a.addEvent('click', MUI.getWrappedEvent(this, this.onNodeClick, [node]));

		return this;
	},

	nodeFind: function(val, node){
		var self = this;
		var o = self.options;
		if (node != null){
			var value = MUI.getData(node, o.valueField);
			if (value && value + '' == val + '') return node;
		} else node = self;
		var nodes;
		if (node.options) nodes = node.options.nodes;
		if (nodes == null) nodes = node.nodes;
		if (nodes){
			var l = nodes.length;
			for (var i = 0; i < l; i++){
				var snode = this.nodeFind(val, nodes[i]);
				if (snode) return snode;
			}
		}
		return null;
	},

	nodeRefresh: function(node){
		if (!node._element) return;
		this.buildNode(node, node._element.getParent())
				.setLast(node._element.getParent());
	},

	nodeGetPath: function(node){
		var self = this;
		var o = self.options;
		var value = MUI.getData(node, o.valueField);

		if (!node._parent) return value;
		return this.getPath(node._parent) + '/' + value;
	},

	setLast: function(node){
		if (!node) return this;
		if (node.childNodes){
			var u = node;
			if (node.nodeName != 'UL') u = node.getElement('ul');
			if (u){
				var children = u.getChildren();
				if (children){
					children.removeClass('last');
					children.getLast().addClass('last');
				}
			}
		}
		return this;
	},

	_nodeSetImage: function(node){
		var o = this.options;
		var span = node._span;
		var def = MUI.getData(node, o.imageField);
		var open = MUI.getData(node, o.imageOpenField) || def;
		var closed = MUI.getData(node, o.imageClosedField) || def;

		span.removeClass(closed).removeClass(open);

		if (closed && !node.isExpanded){
			if (closed.indexOf('.') < 0) span.addClass(closed);
			else span.setStyles({'background': 'transparent url(' + closed + ') no-repeat scroll left top', 'paddingLeft': '20px'});
		}
		if (open && node.isExpanded){
			if (open.indexOf('.') < 0) span.addClass(open);
			else span.setStyles({'background': 'transparent url(' + open + ') no-repeat scroll left top', 'paddingLeft': '20px'});
		}
	},

	onNodeExpand: function(e, node){
		var itm = node._element;
		var mY = 0;
		var mX = 0;
		if (e){
			e = new Event(e).stop();
			var c = itm.getCoordinates();
			mY = e.client.y - c.top;
			mX = e.client.x - c.left;
		}

		if (mX < 20 && mY < 20){
			var ul = itm.getElement('ul');
			if (ul && node.isExpanded){
				ul.style.display = 'none';
				itm.removeClass('O').addClass('C');
				node.isExpanded = false;
				//return;
			} else if (ul && !node.isExpanded){
				ul.style.display = '';
				itm.removeClass('C').addClass('O');
				node.isExpanded = true;
				//if (node.nodes.length > 0) return;
			}
			this._nodeSetImage(node);
		}

		this.fireEvent('nodeExpanded', [e, node, this]);
	},

	onNodeClick: function(e, node){
		var o = this.options;
		e = new Event(e).stop();
		this.selectValue(MUI.getData(node, o.valueField), e);
		this.fireEvent('nodeClicked', [e, node, this]);
	},

	onNodeCheck: function(e, node){
		e = new Event(e).stopPropagation();
		this.fireEvent('nodeChecked', [e, node, this]);
	}

});
<|endoftext|>


<commit_before>goog.provide('fontface.Observer');

goog.require('fontface.Ruler');
goog.require('dom');

goog.scope(function () {
  var Ruler = fontface.Ruler;

  /**
   * @constructor
   *
   * @param {string} family
   * @param {fontface.Descriptors=} opt_descriptors
   */
  fontface.Observer = function (family, opt_descriptors) {
    var descriptors = opt_descriptors || {};

    /**
     * @type {string}
     */
    this['family'] = family;

    /**
     * @type {string}
     */
    this['style'] = descriptors.style || 'normal';

    /**
     * @type {string}
     */
    this['variant'] = descriptors.variant || 'normal';

    /**
     * @type {string}
     */
    this['weight'] = descriptors.weight || 'normal';

    /**
     * @type {string}
     */
    this['stretch'] = descriptors.stretch || 'normal';

    /**
     * @type {string}
     */
    this['featureSettings'] = descriptors.featureSettings || 'normal';
  };

  var Observer = fontface.Observer;

  /**
   * @type {null|boolean}
   */
  Observer.HAS_WEBKIT_FALLBACK_BUG = null;

  /**
   * @type {number}
   */
  Observer.DEFAULT_TIMEOUT = 3000;

  /**
   * @return {string}
   */
  Observer.getUserAgent = function () {
    return window.navigator.userAgent;
  };

  /**
   * Returns true if this browser is WebKit and it has the fallback bug
   * which is present in WebKit 536.11 and earlier.
   *
   * @return {boolean}
   */
  Observer.hasWebKitFallbackBug = function () {
    if (Observer.HAS_WEBKIT_FALLBACK_BUG === null) {
      var match = /AppleWebKit\/([0-9]+)(?:\.([0-9]+))/.exec(Observer.getUserAgent());

      Observer.HAS_WEBKIT_FALLBACK_BUG = !!match &&
                                          (parseInt(match[1], 10) < 536 ||
                                           (parseInt(match[1], 10) === 536 &&
                                            parseInt(match[2], 10) <= 11));
    }
    return Observer.HAS_WEBKIT_FALLBACK_BUG;
  };

  /**
   * @private
   * @return {string}
   */
  Observer.prototype.getStyle = function () {
    return 'font-style:' + this['style'] + ';' +
           'font-variant:' + this['variant'] + ';' +
           'font-weight:' + this['weight'] + ';' +
           'font-stretch:' + this['stretch'] + ';' +
           'font-feature-settings:' + this['featureSettings'] + ';' +
           '-moz-font-feature-settings:' + this['featureSettings'] + ';' +
           '-webkit-font-feature-settings:' + this['featureSettings'] + ';';
  };

  /**
   * @param {string=} text Optional test string to use for detecting if a font is available.
   * @param {number=} timeout Optional timeout for giving up on font load detection and rejecting the promise (defaults to 3 seconds).
   * @return {Promise.<fontface.Observer>}
   */
  Observer.prototype.check = function (text, timeout) {
    var testString = text || 'BESbswy',
        timeoutValue = timeout || Observer.DEFAULT_TIMEOUT,
        style = this.getStyle(),
        container = dom.createElement('div'),

        rulerA = new Ruler(testString),
        rulerB = new Ruler(testString),
        rulerC = new Ruler(testString),

        widthA = -1,
        widthB = -1,
        widthC = -1,

        fallbackWidthA = -1,
        fallbackWidthB = -1,
        fallbackWidthC = -1,

        that = this;

    return new Promise(function (resolve, reject) {
      /**
       * @private
       */
      function removeContainer() {
        if (container.parentNode !== null) {
          dom.remove(container.parentNode, container);
        }
      }

      /**
       * @private
       *
       * If metric compatible fonts are detected, one of the widths will be -1. This is
       * because a metric compatible font won't trigger a scroll event. We work around
       * this by considering a font loaded if at least two of the widths are the same.
       * Because we have three widths, this still prevents false positives.
       *
       * Cases:
       * 1) Font loads: both a, b and c are called and have the same value.
       * 2) Font fails to load: resize callback is never called and timeout happens.
       * 3) WebKit bug: both a, b and c are called and have the same value, but the
       *    values are equal to one of the last resort fonts, we ignore this and
       *    continue waiting until we get new values (or a timeout).
       */
      function check() {
        if ((widthA !== -1 && widthB !== -1) || (widthA !== -1 && widthC !== -1) || (widthB !== -1 && widthC !== -1)) {
          if (widthA === widthB || widthA === widthC || widthB === widthC) {
            // All values are the same, so the browser has most likely loaded the web font

            if (Observer.hasWebKitFallbackBug()) {
              // Except if the browser has the WebKit fallback bug, in which case we check to see if all
              // values are set to one of the last resort fonts.

              if (!((widthA === fallbackWidthA && widthB === fallbackWidthA && widthC === fallbackWidthA) ||
                    (widthA === fallbackWidthB && widthB === fallbackWidthB && widthC === fallbackWidthB) ||
                    (widthA === fallbackWidthC && widthB === fallbackWidthC && widthC === fallbackWidthC))) {
                // The width we got doesn't match any of the known last resort fonts, so let's assume fonts are loaded.
                removeContainer();
                resolve(that);
              }
            } else {
              removeContainer();
              resolve(that);
            }
          }
        }
      }

      dom.waitForBody(function () {
        var start = Date.now();

        rulerA.setFont('sans-serif', style);
        rulerB.setFont('serif', style);
        rulerC.setFont('monospace', style);

        dom.append(container, rulerA.getElement());
        dom.append(container, rulerB.getElement());
        dom.append(container, rulerC.getElement());

        dom.append(document.body, container);

        fallbackWidthA = rulerA.getWidth();
        fallbackWidthB = rulerB.getWidth();
        fallbackWidthC = rulerC.getWidth();

        function checkForTimeout() {
          var now = Date.now();

          if (now - start >= timeoutValue) {
            removeContainer();
            reject(that);
          } else {
            var hidden = document['hidden'];
            if (hidden === true || hidden === undefined) {
              widthA = rulerA.getWidth();
              widthB = rulerB.getWidth();
              widthC = rulerC.getWidth();
              check();
            }
            setTimeout(checkForTimeout, 50);
          }
        }

        checkForTimeout();

        rulerA.onResize(function (width) {
          widthA = width;
          check();
        });

        rulerA.setFont('"' + that['family'] + '",sans-serif', style);

        rulerB.onResize(function (width) {
          widthB = width;
          check();
        });

        rulerB.setFont('"' + that['family'] + '",serif', style);

        rulerC.onResize(function (width) {
          widthC = width;
          check();
        });

        rulerC.setFont('"' + that['family'] + '",monospace', style);
      });
    });
  };
});
<commit_msg>Clear the `#checkForInterval()` timeout when resolving promise.<commit_after>goog.provide('fontface.Observer');

goog.require('fontface.Ruler');
goog.require('dom');

goog.scope(function () {
  var Ruler = fontface.Ruler;

  /**
   * @constructor
   *
   * @param {string} family
   * @param {fontface.Descriptors=} opt_descriptors
   */
  fontface.Observer = function (family, opt_descriptors) {
    var descriptors = opt_descriptors || {};

    /**
     * @type {string}
     */
    this['family'] = family;

    /**
     * @type {string}
     */
    this['style'] = descriptors.style || 'normal';

    /**
     * @type {string}
     */
    this['variant'] = descriptors.variant || 'normal';

    /**
     * @type {string}
     */
    this['weight'] = descriptors.weight || 'normal';

    /**
     * @type {string}
     */
    this['stretch'] = descriptors.stretch || 'normal';

    /**
     * @type {string}
     */
    this['featureSettings'] = descriptors.featureSettings || 'normal';

    /**
     * @type {integer}
     */
    this['timeoutId'] = null;
  };

  var Observer = fontface.Observer;

  /**
   * @type {null|boolean}
   */
  Observer.HAS_WEBKIT_FALLBACK_BUG = null;

  /**
   * @type {number}
   */
  Observer.DEFAULT_TIMEOUT = 3000;

  /**
   * @return {string}
   */
  Observer.getUserAgent = function () {
    return window.navigator.userAgent;
  };

  /**
   * Returns true if this browser is WebKit and it has the fallback bug
   * which is present in WebKit 536.11 and earlier.
   *
   * @return {boolean}
   */
  Observer.hasWebKitFallbackBug = function () {
    if (Observer.HAS_WEBKIT_FALLBACK_BUG === null) {
      var match = /AppleWebKit\/([0-9]+)(?:\.([0-9]+))/.exec(Observer.getUserAgent());

      Observer.HAS_WEBKIT_FALLBACK_BUG = !!match &&
                                          (parseInt(match[1], 10) < 536 ||
                                           (parseInt(match[1], 10) === 536 &&
                                            parseInt(match[2], 10) <= 11));
    }
    return Observer.HAS_WEBKIT_FALLBACK_BUG;
  };

  /**
   * @private
   * @return {string}
   */
  Observer.prototype.getStyle = function () {
    return 'font-style:' + this['style'] + ';' +
           'font-variant:' + this['variant'] + ';' +
           'font-weight:' + this['weight'] + ';' +
           'font-stretch:' + this['stretch'] + ';' +
           'font-feature-settings:' + this['featureSettings'] + ';' +
           '-moz-font-feature-settings:' + this['featureSettings'] + ';' +
           '-webkit-font-feature-settings:' + this['featureSettings'] + ';';
  };

  /**
   * @param {string=} text Optional test string to use for detecting if a font is available.
   * @param {number=} timeout Optional timeout for giving up on font load detection and rejecting the promise (defaults to 3 seconds).
   * @return {Promise.<fontface.Observer>}
   */
  Observer.prototype.check = function (text, timeout) {
    var testString = text || 'BESbswy',
        timeoutValue = timeout || Observer.DEFAULT_TIMEOUT,
        style = this.getStyle(),
        container = dom.createElement('div'),

        rulerA = new Ruler(testString),
        rulerB = new Ruler(testString),
        rulerC = new Ruler(testString),

        widthA = -1,
        widthB = -1,
        widthC = -1,

        fallbackWidthA = -1,
        fallbackWidthB = -1,
        fallbackWidthC = -1,

        that = this;

    return new Promise(function (resolve, reject) {
      /**
       * @private
       */
      function removeContainer() {
        if (container.parentNode !== null) {
          dom.remove(container.parentNode, container);
        }
      }

      /**
       * @private
       *
       * If metric compatible fonts are detected, one of the widths will be -1. This is
       * because a metric compatible font won't trigger a scroll event. We work around
       * this by considering a font loaded if at least two of the widths are the same.
       * Because we have three widths, this still prevents false positives.
       *
       * Cases:
       * 1) Font loads: both a, b and c are called and have the same value.
       * 2) Font fails to load: resize callback is never called and timeout happens.
       * 3) WebKit bug: both a, b and c are called and have the same value, but the
       *    values are equal to one of the last resort fonts, we ignore this and
       *    continue waiting until we get new values (or a timeout).
       */
      function check() {
        if ((widthA !== -1 && widthB !== -1) || (widthA !== -1 && widthC !== -1) || (widthB !== -1 && widthC !== -1)) {
          if (widthA === widthB || widthA === widthC || widthB === widthC) {
            // All values are the same, so the browser has most likely loaded the web font

            if (Observer.hasWebKitFallbackBug()) {
              // Except if the browser has the WebKit fallback bug, in which case we check to see if all
              // values are set to one of the last resort fonts.

              if (!((widthA === fallbackWidthA && widthB === fallbackWidthA && widthC === fallbackWidthA) ||
                    (widthA === fallbackWidthB && widthB === fallbackWidthB && widthC === fallbackWidthB) ||
                    (widthA === fallbackWidthC && widthB === fallbackWidthC && widthC === fallbackWidthC))) {
                // The width we got doesn't match any of the known last resort fonts, so let's assume fonts are loaded.
                removeContainer();
                clearTimeout(that.timeoutId);
                resolve(that);
              }
            } else {
              removeContainer();
              clearTimeout(that.timeoutId);
              resolve(that);
            }
          }
        }
      }

      dom.waitForBody(function () {
        var start = Date.now();

        rulerA.setFont('sans-serif', style);
        rulerB.setFont('serif', style);
        rulerC.setFont('monospace', style);

        dom.append(container, rulerA.getElement());
        dom.append(container, rulerB.getElement());
        dom.append(container, rulerC.getElement());

        dom.append(document.body, container);

        fallbackWidthA = rulerA.getWidth();
        fallbackWidthB = rulerB.getWidth();
        fallbackWidthC = rulerC.getWidth();

        function checkForTimeout() {
          var now = Date.now();

          if (now - start >= timeoutValue) {
            removeContainer();
            reject(that);
          } else {
            var hidden = document['hidden'];
            if (hidden === true || hidden === undefined) {
              widthA = rulerA.getWidth();
              widthB = rulerB.getWidth();
              widthC = rulerC.getWidth();
              check();
            }
            that.timeoutId = setTimeout(checkForTimeout, 50);
          }
        }

        checkForTimeout();

        rulerA.onResize(function (width) {
          widthA = width;
          check();
        });

        rulerA.setFont('"' + that['family'] + '",sans-serif', style);

        rulerB.onResize(function (width) {
          widthB = width;
          check();
        });

        rulerB.setFont('"' + that['family'] + '",serif', style);

        rulerC.onResize(function (width) {
          widthC = width;
          check();
        });

        rulerC.setFont('"' + that['family'] + '",monospace', style);
      });
    });
  };
});
<|endoftext|>


<commit_before>/*
 * XMonad status plugin, receiving workspace status over DBus.
 * To send status, use dbusLog or dbusLogWithMarkup from
 * System.Tianbar.XMonadLog as your XMonad logHook.
 *
 * The status appears in elements matching class 'widget-xmonad'.
 *
 * The plugin requires 'jquery' to be available through RequireJS.
 */
define(['jquery', './dbus'], function ($, dbus) {
  dbus.listen(
    {
      path: '/org/xmonad/Log',
      iface: 'org.xmonad.Log',
      member: 'Update'
    },
    function (signal, body) {
      var st = body[0];
      $('.widget-xmonad').html(st);
    }
  );
});
<commit_msg>Status change callback for XMonad plugin<commit_after>/*
 * XMonad status plugin, receiving workspace status over DBus.
 * To send status, use dbusLog or dbusLogWithMarkup from
 * System.Tianbar.XMonadLog as your XMonad logHook.
 *
 * The status appears in elements matching class 'widget-xmonad'.
 *
 * The 'change' callback ($.Callbacks) object is fired whenever the
 * status changes.
 *
 * The plugin requires 'jquery' to be available through RequireJS.
 */
define(['jquery', './dbus'], function ($, dbus) {
  var change = $.Callbacks();

  dbus.listen(
    {
      path: '/org/xmonad/Log',
      iface: 'org.xmonad.Log',
      member: 'Update'
    },
    function (signal, body) {
      var st = body[0];
      $('.widget-xmonad').html(st);
      change.fire(st);
    }
  );

  return {
    change: change
  };
});
<|endoftext|>


<commit_before>/*global define*/
define([
        '../Core/Cartesian3',
        '../Core/createGuid',
        '../Core/defaultValue',
        '../Core/defined',
        '../Core/defineProperties',
        '../Core/deprecationWarning',
        '../Core/DeveloperError',
        '../Core/Event',
        '../Core/Matrix3',
        '../Core/Matrix4',
        '../Core/Quaternion',
        '../Core/Transforms',
        './BillboardGraphics',
        './BoxGraphics',
        './ConstantPositionProperty',
        './CorridorGraphics',
        './createPropertyDescriptor',
        './createRawPropertyDescriptor',
        './CylinderGraphics',
        './EllipseGraphics',
        './EllipsoidGraphics',
        './LabelGraphics',
        './ModelGraphics',
        './PathGraphics',
        './PointGraphics',
        './PolygonGraphics',
        './PolylineGraphics',
        './PolylineVolumeGraphics',
        './Property',
        './RectangleGraphics',
        './WallGraphics'
    ], function(
        Cartesian3,
        createGuid,
        defaultValue,
        defined,
        defineProperties,
        deprecationWarning,
        DeveloperError,
        Event,
        Matrix3,
        Matrix4,
        Quaternion,
        Transforms,
        BillboardGraphics,
        BoxGraphics,
        ConstantPositionProperty,
        CorridorGraphics,
        createPropertyDescriptor,
        createRawPropertyDescriptor,
        CylinderGraphics,
        EllipseGraphics,
        EllipsoidGraphics,
        LabelGraphics,
        ModelGraphics,
        PathGraphics,
        PointGraphics,
        PolygonGraphics,
        PolylineGraphics,
        PolylineVolumeGraphics,
        Property,
        RectangleGraphics,
        WallGraphics) {
    "use strict";

    function createConstantPositionProperty(value) {
        return new ConstantPositionProperty(value);
    }

    function createPositionPropertyDescriptor(name) {
        return createPropertyDescriptor(name, undefined, createConstantPositionProperty);
    }

    function createPropertyTypeDescriptor(name, Type) {
        return createPropertyDescriptor(name, undefined, function(value) {
            if (value instanceof Type) {
                return value;
            }
            return new Type(value);
        });
    }

    /**
     * Entity instances aggregate multiple forms of visualization into a single high-level object.
     * They can be created manually and added to {@link Viewer#entities} or be produced by
     * data sources, such as {@link CzmlDataSource} and {@link GeoJsonDataSource}.
     * @alias Entity
     * @constructor
     *
     * @param {Object} [options] Object with the following properties:
     * @param {String} [options.id] A unique identifier for this object. If none is provided, a GUID is generated.
     * @param {String} [options.name] A human readable name to display to users. It does not have to be unique.
     * @param {Property} [options.description] A string Property specifying an HTML description for this entity.
     * @param {PositionProperty} [options.position] A Property specifying the entity position.
     * @param {Property} [options.orientation] A Property specifying the entity orientation.
     * @param {Property} [options.viewFrom] A suggested initial offset for viewing this object.
     * @param {Entity} [options.parent] A parent entity to associate with this entity.
     * @param {BillboardGraphics} [options.billboard] A billboard to associate with this entity.
     * @param {BoxGraphics} [options.box] A box to associate with this entity.
     * @param {CorridorGraphics} [options.corridor] A corridor to associate with this entity.
     * @param {CylinderGraphics} [options.cylinder] A cylinder to associate with this entity.
     * @param {EllipseGraphics} [options.ellipse] A ellipse to associate with this entity.
     * @param {EllipsoidGraphics} [options.ellipsoid] A ellipsoid to associate with this entity.
     * @param {LabelGraphics} [options.label] A options.label to associate with this entity.
     * @param {ModelGraphics} [options.model] A model to associate with this entity.
     * @param {PathGraphics} [options.path] A path to associate with this entity.
     * @param {PointGraphics} [options.point] A point to associate with this entity.
     * @param {PolygonGraphics} [options.polygon] A polygon to associate with this entity.
     * @param {PolylineGraphics} [options.polyline] A polyline to associate with this entity.
     * @param {PolylineVolumeGraphics} [options.polylineVolume] A polylineVolume to associate with this entity.
     * @param {RectangleGraphics} [options.rectangle] A rectangle to associate with this entity.
     * @param {WallGraphics} [options.wall] A wall to associate with this entity.
     *
     * @see {@link http://cesiumjs.org/2015/02/02/Working-with-Entities/|Working with Entities}
     */
    var Entity = function(options) {
        options = defaultValue(options, defaultValue.EMPTY_OBJECT);

        var id = options.id;
        if (typeof options === 'string') {
            deprecationWarning('Entity', 'The Entity constructor taking a string was deprecated in Cesium 1.5.  It will be removed in 1.7.  Use "new Entity({ id : \'id\'})" instead.');
            id = options;
            options = defaultValue.EMPTY_OBJECT;
        }

        if (!defined(id)) {
            id = createGuid();
        }

        this._availability = undefined;
        this._id = id;
        this._definitionChanged = new Event();
        this._name = undefined;
        this._parent = options.parent;
        this._propertyNames = ['billboard', 'box', 'corridor', 'cylinder', 'description', 'ellipse', //
                               'ellipsoid', 'label', 'model', 'orientation', 'path', 'point', 'polygon', //
                               'polyline', 'polylineVolume', 'position', 'rectangle', 'viewFrom', 'wall'];

        this._billboard = undefined;
        this._billboardSubscription = undefined;
        this._box = undefined;
        this._boxSubscription = undefined;
        this._corridor = undefined;
        this._corridorSubscription = undefined;
        this._cylinder = undefined;
        this._cylinderSubscription = undefined;
        this._description = undefined;
        this._descriptionSubscription = undefined;
        this._ellipse = undefined;
        this._ellipseSubscription = undefined;
        this._ellipsoid = undefined;
        this._ellipsoidSubscription = undefined;
        this._label = undefined;
        this._labelSubscription = undefined;
        this._model = undefined;
        this._modelSubscription = undefined;
        this._orientation = undefined;
        this._orientationSubscription = undefined;
        this._path = undefined;
        this._pathSubscription = undefined;
        this._point = undefined;
        this._pointSubscription = undefined;
        this._polygon = undefined;
        this._polygonSubscription = undefined;
        this._polyline = undefined;
        this._polylineSubscription = undefined;
        this._polylineVolume = undefined;
        this._polylineVolumeSubscription = undefined;
        this._position = undefined;
        this._positionSubscription = undefined;
        this._rectangle = undefined;
        this._rectangleSubscription = undefined;
        this._viewFrom = undefined;
        this._viewFromSubscription = undefined;
        this._wall = undefined;
        this._wallSubscription = undefined;

        this.merge(defaultValue(options, defaultValue.EMPTY_OBJECT));
    };

    defineProperties(Entity.prototype, {
        /**
         * The availability, if any, associated with this object.
         * If availability is undefined, it is assumed that this object's
         * other properties will return valid data for any provided time.
         * If availability exists, the objects other properties will only
         * provide valid data if queried within the given interval.
         * @memberof Entity.prototype
         * @type {TimeIntervalCollection}
         */
        availability : createRawPropertyDescriptor('availability'),
        /**
         * Gets the unique ID associated with this object.
         * @memberof Entity.prototype
         * @type {String}
         */
        id : {
            get : function() {
                return this._id;
            }
        },
        /**
         * Gets the event that is raised whenever a property or sub-property is changed or modified.
         * @memberof Entity.prototype
         *
         * @type {Event}
         * @readonly
         */
        definitionChanged : {
            get : function() {
                return this._definitionChanged;
            }
        },
        /**
         * Gets or sets the name of the object.  The name is intended for end-user
         * consumption and does not need to be unique.
         * @memberof Entity.prototype
         * @type {String}
         */
        name : {
            configurable : false,
            get : function() {
                return this._name;
            },
            set : function(value) {
                var oldValue = this._name;
                if (oldValue !== value) {
                    this._name = value;
                    this._definitionChanged.raiseEvent(this, 'name', value, oldValue);
                }
            }
        },
        /**
         * Gets or sets the parent object.
         * @memberof Entity.prototype
         * @type {Entity}
         */
        parent : createRawPropertyDescriptor('parent'),
        /**
         * Gets the names of all properties registered on this instance.
         * @memberof Entity.prototype
         * @type {Event}
         */
        propertyNames : {
            get : function() {
                return this._propertyNames;
            }
        },
        /**
         * Gets or sets the billboard.
         * @memberof Entity.prototype
         * @type {BillboardGraphics}
         */
        billboard : createPropertyTypeDescriptor('billboard', BillboardGraphics),
        /**
         * Gets or sets the box.
         * @memberof Entity.prototype
         * @type {BoxGraphics}
         */
        box : createPropertyTypeDescriptor('box', BoxGraphics),
        /**
         * Gets or sets the corridor.
         * @memberof Entity.prototype
         * @type {CorridorGraphics}
         */
        corridor : createPropertyTypeDescriptor('corridor', CorridorGraphics),
        /**
         * Gets or sets the cylinder.
         * @memberof Entity.prototype
         * @type {CylinderGraphics}
         */
        cylinder : createPropertyTypeDescriptor('cylinder', CylinderGraphics),
        /**
         * Gets or sets the description.
         * @memberof Entity.prototype
         * @type {Property}
         */
        description : createPropertyDescriptor('description'),
        /**
         * Gets or sets the ellipse.
         * @memberof Entity.prototype
         * @type {EllipseGraphics}
         */
        ellipse : createPropertyTypeDescriptor('ellipse', EllipseGraphics),
        /**
         * Gets or sets the ellipsoid.
         * @memberof Entity.prototype
         * @type {EllipsoidGraphics}
         */
        ellipsoid : createPropertyTypeDescriptor('ellipsoid', EllipsoidGraphics),
        /**
         * Gets or sets the label.
         * @memberof Entity.prototype
         * @type {LabelGraphics}
         */
        label : createPropertyTypeDescriptor('label', LabelGraphics),
        /**
         * Gets or sets the model.
         * @memberof Entity.prototype
         * @type {ModelGraphics}
         */
        model : createPropertyTypeDescriptor('model', ModelGraphics),
        /**
         * Gets or sets the orientation.
         * @memberof Entity.prototype
         * @type {Property}
         */
        orientation : createPropertyDescriptor('orientation'),
        /**
         * Gets or sets the path.
         * @memberof Entity.prototype
         * @type {PathGraphics}
         */
        path : createPropertyTypeDescriptor('path', PathGraphics),
        /**
         * Gets or sets the point graphic.
         * @memberof Entity.prototype
         * @type {PointGraphics}
         */
        point : createPropertyTypeDescriptor('point', PointGraphics),
        /**
         * Gets or sets the polygon.
         * @memberof Entity.prototype
         * @type {PolygonGraphics}
         */
        polygon : createPropertyTypeDescriptor('polygon', PolygonGraphics),
        /**
         * Gets or sets the polyline.
         * @memberof Entity.prototype
         * @type {PolylineGraphics}
         */
        polyline : createPropertyTypeDescriptor('polyline', PolylineGraphics),
        /**
         * Gets or sets the polyline volume.
         * @memberof Entity.prototype
         * @type {PolylineVolumeGraphics}
         */
        polylineVolume : createPropertyTypeDescriptor('polylineVolume', PolylineVolumeGraphics),
        /**
         * Gets or sets the position.
         * @memberof Entity.prototype
         * @type {PositionProperty}
         */
        position : createPositionPropertyDescriptor('position'),
        /**
         * Gets or sets the rectangle.
         * @memberof Entity.prototype
         * @type {RectangleGraphics}
         */
        rectangle : createPropertyTypeDescriptor('rectangle', RectangleGraphics),
        /**
         * Gets or sets the suggested initial offset for viewing this object
         * with the camera.  The offset is defined in the east-north-up reference frame.
         * @memberof Entity.prototype
         * @type {Property}
         */
        viewFrom : createPropertyDescriptor('viewFrom'),
        /**
         * Gets or sets the wall.
         * @memberof Entity.prototype
         * @type {WallGraphics}
         */
        wall : createPropertyTypeDescriptor('wall', WallGraphics)
    });

    /**
     * Given a time, returns true if this object should have data during that time.
     *
     * @param {JulianDate} time The time to check availability for.
     * @returns true if the object should have data during the provided time, false otherwise.
     */
    Entity.prototype.isAvailable = function(time) {
        //>>includeStart('debug', pragmas.debug);
        if (!defined(time)) {
            throw new DeveloperError('time is required.');
        }
        //>>includeEnd('debug');

        var availability = this._availability;
        return !defined(availability) || availability.contains(time);
    };

    /**
     * Adds a property to this object.  Once a property is added, it can be
     * observed with {@link Entity#definitionChanged} and composited
     * with {@link CompositeEntityCollection}
     *
     * @param {String} propertyName The name of the property to add.
     *
     * @exception {DeveloperError} "propertyName" is a reserved property name.
     * @exception {DeveloperError} "propertyName" is already a registered property.
     */
    Entity.prototype.addProperty = function(propertyName) {
        var propertyNames = this._propertyNames;

        //>>includeStart('debug', pragmas.debug);
        if (!defined(propertyName)) {
            throw new DeveloperError('propertyName is required.');
        }
        if (propertyNames.indexOf(propertyName) !== -1) {
            throw new DeveloperError(propertyName + ' is already a registered property.');
        }
        if (propertyName in this) {
            throw new DeveloperError(propertyName + ' is a reserved property name.');
        }
        //>>includeEnd('debug');

        propertyNames.push(propertyName);
        Object.defineProperty(this, propertyName, createRawPropertyDescriptor(propertyName, true));
    };

    /**
     * Removed a property previously added with addProperty.
     *
     * @param {String} propertyName The name of the property to remove.
     *
     * @exception {DeveloperError} "propertyName" is a reserved property name.
     * @exception {DeveloperError} "propertyName" is not a registered property.
     */
    Entity.prototype.removeProperty = function(propertyName) {
        var propertyNames = this._propertyNames;

        //>>includeStart('debug', pragmas.debug);
        if (!defined(propertyName)) {
            throw new DeveloperError('propertyName is required.');
        }
        if (propertyNames.indexOf(propertyName) === -1) {
            throw new DeveloperError(propertyName + ' is not a registered property.');
        }
        //>>includeEnd('debug');

        this._propertyNames.push(propertyName);
        delete this[propertyName];
    };

    /**
     * Assigns each unassigned property on this object to the value
     * of the same property on the provided source object.
     *
     * @param {Entity} source The object to be merged into this object.
     */
    Entity.prototype.merge = function(source) {
        //>>includeStart('debug', pragmas.debug);
        if (!defined(source)) {
            throw new DeveloperError('source is required.');
        }
        //>>includeEnd('debug');

        //Name and availability are not Property objects and are currently handled differently.
        this.name = defaultValue(this.name, source.name);
        this.availability = defaultValue(source.availability, this.availability);

        var propertyNames = this._propertyNames;
        var sourcePropertyNames = defined(source._propertyNames) ? source._propertyNames : Object.keys(source);
        var propertyNamesLength = sourcePropertyNames.length;
        for (var i = 0; i < propertyNamesLength; i++) {
            var name = sourcePropertyNames[i];

            //Ignore parent when merging, this only happens at construction time.
            if (name === 'parent') {
                continue;
            }

            var targetProperty = this[name];
            var sourceProperty = source[name];

            //Custom properties that are registered on the source entity must also
            //get registered on this entity.
            if (!defined(targetProperty) && propertyNames.indexOf(name) === -1) {
                this.addProperty(name);
            }

            if (defined(sourceProperty)) {
                if (defined(targetProperty)) {
                    if (defined(targetProperty.merge)) {
                        targetProperty.merge(sourceProperty);
                    }
                } else if (defined(sourceProperty.merge) && defined(sourceProperty.clone)) {
                    this[name] = sourceProperty.clone();
                } else {
                    this[name] = sourceProperty;
                }
            }
        }
    };

    var matrix3Scratch = new Matrix3();
    var positionScratch = new Cartesian3();
    var orientationScratch = new Quaternion();

    /**
     * @private
     */
    Entity.prototype._getModelMatrix = function(time, result) {
        var position = Property.getValueOrUndefined(this._position, time, positionScratch);
        if (!defined(position)) {
            return undefined;
        }
        var orientation = Property.getValueOrUndefined(this._orientation, time, orientationScratch);
        if (!defined(orientation)) {
            result = Transforms.eastNorthUpToFixedFrame(position, undefined, result);
        } else {
            result = Matrix4.fromRotationTranslation(Matrix3.fromQuaternion(orientation, matrix3Scratch), position, result);
        }
        return result;
    };

    return Entity;
});
<commit_msg>Fix link to new tutorial.<commit_after>/*global define*/
define([
        '../Core/Cartesian3',
        '../Core/createGuid',
        '../Core/defaultValue',
        '../Core/defined',
        '../Core/defineProperties',
        '../Core/deprecationWarning',
        '../Core/DeveloperError',
        '../Core/Event',
        '../Core/Matrix3',
        '../Core/Matrix4',
        '../Core/Quaternion',
        '../Core/Transforms',
        './BillboardGraphics',
        './BoxGraphics',
        './ConstantPositionProperty',
        './CorridorGraphics',
        './createPropertyDescriptor',
        './createRawPropertyDescriptor',
        './CylinderGraphics',
        './EllipseGraphics',
        './EllipsoidGraphics',
        './LabelGraphics',
        './ModelGraphics',
        './PathGraphics',
        './PointGraphics',
        './PolygonGraphics',
        './PolylineGraphics',
        './PolylineVolumeGraphics',
        './Property',
        './RectangleGraphics',
        './WallGraphics'
    ], function(
        Cartesian3,
        createGuid,
        defaultValue,
        defined,
        defineProperties,
        deprecationWarning,
        DeveloperError,
        Event,
        Matrix3,
        Matrix4,
        Quaternion,
        Transforms,
        BillboardGraphics,
        BoxGraphics,
        ConstantPositionProperty,
        CorridorGraphics,
        createPropertyDescriptor,
        createRawPropertyDescriptor,
        CylinderGraphics,
        EllipseGraphics,
        EllipsoidGraphics,
        LabelGraphics,
        ModelGraphics,
        PathGraphics,
        PointGraphics,
        PolygonGraphics,
        PolylineGraphics,
        PolylineVolumeGraphics,
        Property,
        RectangleGraphics,
        WallGraphics) {
    "use strict";

    function createConstantPositionProperty(value) {
        return new ConstantPositionProperty(value);
    }

    function createPositionPropertyDescriptor(name) {
        return createPropertyDescriptor(name, undefined, createConstantPositionProperty);
    }

    function createPropertyTypeDescriptor(name, Type) {
        return createPropertyDescriptor(name, undefined, function(value) {
            if (value instanceof Type) {
                return value;
            }
            return new Type(value);
        });
    }

    /**
     * Entity instances aggregate multiple forms of visualization into a single high-level object.
     * They can be created manually and added to {@link Viewer#entities} or be produced by
     * data sources, such as {@link CzmlDataSource} and {@link GeoJsonDataSource}.
     * @alias Entity
     * @constructor
     *
     * @param {Object} [options] Object with the following properties:
     * @param {String} [options.id] A unique identifier for this object. If none is provided, a GUID is generated.
     * @param {String} [options.name] A human readable name to display to users. It does not have to be unique.
     * @param {Property} [options.description] A string Property specifying an HTML description for this entity.
     * @param {PositionProperty} [options.position] A Property specifying the entity position.
     * @param {Property} [options.orientation] A Property specifying the entity orientation.
     * @param {Property} [options.viewFrom] A suggested initial offset for viewing this object.
     * @param {Entity} [options.parent] A parent entity to associate with this entity.
     * @param {BillboardGraphics} [options.billboard] A billboard to associate with this entity.
     * @param {BoxGraphics} [options.box] A box to associate with this entity.
     * @param {CorridorGraphics} [options.corridor] A corridor to associate with this entity.
     * @param {CylinderGraphics} [options.cylinder] A cylinder to associate with this entity.
     * @param {EllipseGraphics} [options.ellipse] A ellipse to associate with this entity.
     * @param {EllipsoidGraphics} [options.ellipsoid] A ellipsoid to associate with this entity.
     * @param {LabelGraphics} [options.label] A options.label to associate with this entity.
     * @param {ModelGraphics} [options.model] A model to associate with this entity.
     * @param {PathGraphics} [options.path] A path to associate with this entity.
     * @param {PointGraphics} [options.point] A point to associate with this entity.
     * @param {PolygonGraphics} [options.polygon] A polygon to associate with this entity.
     * @param {PolylineGraphics} [options.polyline] A polyline to associate with this entity.
     * @param {PolylineVolumeGraphics} [options.polylineVolume] A polylineVolume to associate with this entity.
     * @param {RectangleGraphics} [options.rectangle] A rectangle to associate with this entity.
     * @param {WallGraphics} [options.wall] A wall to associate with this entity.
     *
     * @see {@link http://cesiumjs.org/2015/02/02/Working-with-Spatial-Data/|Working with Special Data}
     */
    var Entity = function(options) {
        options = defaultValue(options, defaultValue.EMPTY_OBJECT);

        var id = options.id;
        if (typeof options === 'string') {
            deprecationWarning('Entity', 'The Entity constructor taking a string was deprecated in Cesium 1.5.  It will be removed in 1.7.  Use "new Entity({ id : \'id\'})" instead.');
            id = options;
            options = defaultValue.EMPTY_OBJECT;
        }

        if (!defined(id)) {
            id = createGuid();
        }

        this._availability = undefined;
        this._id = id;
        this._definitionChanged = new Event();
        this._name = undefined;
        this._parent = options.parent;
        this._propertyNames = ['billboard', 'box', 'corridor', 'cylinder', 'description', 'ellipse', //
                               'ellipsoid', 'label', 'model', 'orientation', 'path', 'point', 'polygon', //
                               'polyline', 'polylineVolume', 'position', 'rectangle', 'viewFrom', 'wall'];

        this._billboard = undefined;
        this._billboardSubscription = undefined;
        this._box = undefined;
        this._boxSubscription = undefined;
        this._corridor = undefined;
        this._corridorSubscription = undefined;
        this._cylinder = undefined;
        this._cylinderSubscription = undefined;
        this._description = undefined;
        this._descriptionSubscription = undefined;
        this._ellipse = undefined;
        this._ellipseSubscription = undefined;
        this._ellipsoid = undefined;
        this._ellipsoidSubscription = undefined;
        this._label = undefined;
        this._labelSubscription = undefined;
        this._model = undefined;
        this._modelSubscription = undefined;
        this._orientation = undefined;
        this._orientationSubscription = undefined;
        this._path = undefined;
        this._pathSubscription = undefined;
        this._point = undefined;
        this._pointSubscription = undefined;
        this._polygon = undefined;
        this._polygonSubscription = undefined;
        this._polyline = undefined;
        this._polylineSubscription = undefined;
        this._polylineVolume = undefined;
        this._polylineVolumeSubscription = undefined;
        this._position = undefined;
        this._positionSubscription = undefined;
        this._rectangle = undefined;
        this._rectangleSubscription = undefined;
        this._viewFrom = undefined;
        this._viewFromSubscription = undefined;
        this._wall = undefined;
        this._wallSubscription = undefined;

        this.merge(defaultValue(options, defaultValue.EMPTY_OBJECT));
    };

    defineProperties(Entity.prototype, {
        /**
         * The availability, if any, associated with this object.
         * If availability is undefined, it is assumed that this object's
         * other properties will return valid data for any provided time.
         * If availability exists, the objects other properties will only
         * provide valid data if queried within the given interval.
         * @memberof Entity.prototype
         * @type {TimeIntervalCollection}
         */
        availability : createRawPropertyDescriptor('availability'),
        /**
         * Gets the unique ID associated with this object.
         * @memberof Entity.prototype
         * @type {String}
         */
        id : {
            get : function() {
                return this._id;
            }
        },
        /**
         * Gets the event that is raised whenever a property or sub-property is changed or modified.
         * @memberof Entity.prototype
         *
         * @type {Event}
         * @readonly
         */
        definitionChanged : {
            get : function() {
                return this._definitionChanged;
            }
        },
        /**
         * Gets or sets the name of the object.  The name is intended for end-user
         * consumption and does not need to be unique.
         * @memberof Entity.prototype
         * @type {String}
         */
        name : {
            configurable : false,
            get : function() {
                return this._name;
            },
            set : function(value) {
                var oldValue = this._name;
                if (oldValue !== value) {
                    this._name = value;
                    this._definitionChanged.raiseEvent(this, 'name', value, oldValue);
                }
            }
        },
        /**
         * Gets or sets the parent object.
         * @memberof Entity.prototype
         * @type {Entity}
         */
        parent : createRawPropertyDescriptor('parent'),
        /**
         * Gets the names of all properties registered on this instance.
         * @memberof Entity.prototype
         * @type {Event}
         */
        propertyNames : {
            get : function() {
                return this._propertyNames;
            }
        },
        /**
         * Gets or sets the billboard.
         * @memberof Entity.prototype
         * @type {BillboardGraphics}
         */
        billboard : createPropertyTypeDescriptor('billboard', BillboardGraphics),
        /**
         * Gets or sets the box.
         * @memberof Entity.prototype
         * @type {BoxGraphics}
         */
        box : createPropertyTypeDescriptor('box', BoxGraphics),
        /**
         * Gets or sets the corridor.
         * @memberof Entity.prototype
         * @type {CorridorGraphics}
         */
        corridor : createPropertyTypeDescriptor('corridor', CorridorGraphics),
        /**
         * Gets or sets the cylinder.
         * @memberof Entity.prototype
         * @type {CylinderGraphics}
         */
        cylinder : createPropertyTypeDescriptor('cylinder', CylinderGraphics),
        /**
         * Gets or sets the description.
         * @memberof Entity.prototype
         * @type {Property}
         */
        description : createPropertyDescriptor('description'),
        /**
         * Gets or sets the ellipse.
         * @memberof Entity.prototype
         * @type {EllipseGraphics}
         */
        ellipse : createPropertyTypeDescriptor('ellipse', EllipseGraphics),
        /**
         * Gets or sets the ellipsoid.
         * @memberof Entity.prototype
         * @type {EllipsoidGraphics}
         */
        ellipsoid : createPropertyTypeDescriptor('ellipsoid', EllipsoidGraphics),
        /**
         * Gets or sets the label.
         * @memberof Entity.prototype
         * @type {LabelGraphics}
         */
        label : createPropertyTypeDescriptor('label', LabelGraphics),
        /**
         * Gets or sets the model.
         * @memberof Entity.prototype
         * @type {ModelGraphics}
         */
        model : createPropertyTypeDescriptor('model', ModelGraphics),
        /**
         * Gets or sets the orientation.
         * @memberof Entity.prototype
         * @type {Property}
         */
        orientation : createPropertyDescriptor('orientation'),
        /**
         * Gets or sets the path.
         * @memberof Entity.prototype
         * @type {PathGraphics}
         */
        path : createPropertyTypeDescriptor('path', PathGraphics),
        /**
         * Gets or sets the point graphic.
         * @memberof Entity.prototype
         * @type {PointGraphics}
         */
        point : createPropertyTypeDescriptor('point', PointGraphics),
        /**
         * Gets or sets the polygon.
         * @memberof Entity.prototype
         * @type {PolygonGraphics}
         */
        polygon : createPropertyTypeDescriptor('polygon', PolygonGraphics),
        /**
         * Gets or sets the polyline.
         * @memberof Entity.prototype
         * @type {PolylineGraphics}
         */
        polyline : createPropertyTypeDescriptor('polyline', PolylineGraphics),
        /**
         * Gets or sets the polyline volume.
         * @memberof Entity.prototype
         * @type {PolylineVolumeGraphics}
         */
        polylineVolume : createPropertyTypeDescriptor('polylineVolume', PolylineVolumeGraphics),
        /**
         * Gets or sets the position.
         * @memberof Entity.prototype
         * @type {PositionProperty}
         */
        position : createPositionPropertyDescriptor('position'),
        /**
         * Gets or sets the rectangle.
         * @memberof Entity.prototype
         * @type {RectangleGraphics}
         */
        rectangle : createPropertyTypeDescriptor('rectangle', RectangleGraphics),
        /**
         * Gets or sets the suggested initial offset for viewing this object
         * with the camera.  The offset is defined in the east-north-up reference frame.
         * @memberof Entity.prototype
         * @type {Property}
         */
        viewFrom : createPropertyDescriptor('viewFrom'),
        /**
         * Gets or sets the wall.
         * @memberof Entity.prototype
         * @type {WallGraphics}
         */
        wall : createPropertyTypeDescriptor('wall', WallGraphics)
    });

    /**
     * Given a time, returns true if this object should have data during that time.
     *
     * @param {JulianDate} time The time to check availability for.
     * @returns true if the object should have data during the provided time, false otherwise.
     */
    Entity.prototype.isAvailable = function(time) {
        //>>includeStart('debug', pragmas.debug);
        if (!defined(time)) {
            throw new DeveloperError('time is required.');
        }
        //>>includeEnd('debug');

        var availability = this._availability;
        return !defined(availability) || availability.contains(time);
    };

    /**
     * Adds a property to this object.  Once a property is added, it can be
     * observed with {@link Entity#definitionChanged} and composited
     * with {@link CompositeEntityCollection}
     *
     * @param {String} propertyName The name of the property to add.
     *
     * @exception {DeveloperError} "propertyName" is a reserved property name.
     * @exception {DeveloperError} "propertyName" is already a registered property.
     */
    Entity.prototype.addProperty = function(propertyName) {
        var propertyNames = this._propertyNames;

        //>>includeStart('debug', pragmas.debug);
        if (!defined(propertyName)) {
            throw new DeveloperError('propertyName is required.');
        }
        if (propertyNames.indexOf(propertyName) !== -1) {
            throw new DeveloperError(propertyName + ' is already a registered property.');
        }
        if (propertyName in this) {
            throw new DeveloperError(propertyName + ' is a reserved property name.');
        }
        //>>includeEnd('debug');

        propertyNames.push(propertyName);
        Object.defineProperty(this, propertyName, createRawPropertyDescriptor(propertyName, true));
    };

    /**
     * Removed a property previously added with addProperty.
     *
     * @param {String} propertyName The name of the property to remove.
     *
     * @exception {DeveloperError} "propertyName" is a reserved property name.
     * @exception {DeveloperError} "propertyName" is not a registered property.
     */
    Entity.prototype.removeProperty = function(propertyName) {
        var propertyNames = this._propertyNames;

        //>>includeStart('debug', pragmas.debug);
        if (!defined(propertyName)) {
            throw new DeveloperError('propertyName is required.');
        }
        if (propertyNames.indexOf(propertyName) === -1) {
            throw new DeveloperError(propertyName + ' is not a registered property.');
        }
        //>>includeEnd('debug');

        this._propertyNames.push(propertyName);
        delete this[propertyName];
    };

    /**
     * Assigns each unassigned property on this object to the value
     * of the same property on the provided source object.
     *
     * @param {Entity} source The object to be merged into this object.
     */
    Entity.prototype.merge = function(source) {
        //>>includeStart('debug', pragmas.debug);
        if (!defined(source)) {
            throw new DeveloperError('source is required.');
        }
        //>>includeEnd('debug');

        //Name and availability are not Property objects and are currently handled differently.
        this.name = defaultValue(this.name, source.name);
        this.availability = defaultValue(source.availability, this.availability);

        var propertyNames = this._propertyNames;
        var sourcePropertyNames = defined(source._propertyNames) ? source._propertyNames : Object.keys(source);
        var propertyNamesLength = sourcePropertyNames.length;
        for (var i = 0; i < propertyNamesLength; i++) {
            var name = sourcePropertyNames[i];

            //Ignore parent when merging, this only happens at construction time.
            if (name === 'parent') {
                continue;
            }

            var targetProperty = this[name];
            var sourceProperty = source[name];

            //Custom properties that are registered on the source entity must also
            //get registered on this entity.
            if (!defined(targetProperty) && propertyNames.indexOf(name) === -1) {
                this.addProperty(name);
            }

            if (defined(sourceProperty)) {
                if (defined(targetProperty)) {
                    if (defined(targetProperty.merge)) {
                        targetProperty.merge(sourceProperty);
                    }
                } else if (defined(sourceProperty.merge) && defined(sourceProperty.clone)) {
                    this[name] = sourceProperty.clone();
                } else {
                    this[name] = sourceProperty;
                }
            }
        }
    };

    var matrix3Scratch = new Matrix3();
    var positionScratch = new Cartesian3();
    var orientationScratch = new Quaternion();

    /**
     * @private
     */
    Entity.prototype._getModelMatrix = function(time, result) {
        var position = Property.getValueOrUndefined(this._position, time, positionScratch);
        if (!defined(position)) {
            return undefined;
        }
        var orientation = Property.getValueOrUndefined(this._orientation, time, orientationScratch);
        if (!defined(orientation)) {
            result = Transforms.eastNorthUpToFixedFrame(position, undefined, result);
        } else {
            result = Matrix4.fromRotationTranslation(Matrix3.fromQuaternion(orientation, matrix3Scratch), position, result);
        }
        return result;
    };

    return Entity;
});
<|endoftext|>


<commit_before>import program from 'commander';
import path from 'path';
import chalk from 'chalk';
import envinfo from 'envinfo';
import leven from 'leven';
import pkg from '../package.json';
import initiate from './initiate';
import { codeLog } from './helpers';
import { add } from './add';
import { migrate } from './migrate';
import { extract } from './extract';

const logger = console;

if (process.argv[1].includes('getstorybook')) {
  logger.log(chalk.yellow('WARNING: getstorybook is deprecated.'));
  logger.log(chalk.yellow('The official command to install Storybook from now on is:\n'));
  codeLog(['sb init']);
  logger.log();
  initiate({}, pkg).then(() => process.exit(0));
} else {
  program
    .command('init')
    .description('Initialize Storybook into your project.')
    .option('-f --force', 'Force add storybook')
    .option('-s --skip-install', 'Skip installing deps')
    .option('-N --use-npm', 'Use npm to install deps')
    .option('-p --parser <babel | babylon | flow | ts | tsx>', 'jscodeshift parser')
    .option('-t --type <type>', 'Add Storybook for a specific project type')
    .option('--story-format <csf | csf-ts | mdx >', 'Generate stories in a specified format')
    .option('-y --yes', 'Answer yes to all prompts')
    .action(options => initiate(options, pkg));

  program
    .command('add <addon>')
    .description('Add an addon to your Storybook')
    .option('-N --use-npm', 'Use NPM to build the Storybook server')
    .option('-s --skip-postinstall', 'Skip package specific postinstall config modifications')
    .action((addonName, options) => add(addonName, options));

  program
    .command('info')
    .description('Prints debugging information about the local environment')
    .action(() => {
      logger.log(chalk.bold('\nEnvironment Info:'));
      envinfo
        .run({
          System: ['OS', 'CPU'],
          Binaries: ['Node', 'Yarn', 'npm'],
          Browsers: ['Chrome', 'Edge', 'Firefox', 'Safari'],
          npmPackages: '@storybook/*',
          npmGlobalPackages: '@storybook/*',
        })
        .then(logger.log);
    });

  program
    .command('migrate [migration]')
    .description('Run a storybook codemod migration on your source files')
    .option('-l --list', 'List available migrations')
    .option('-g --glob <glob>', 'Glob for files upon which to apply the migration', '**/*.js')
    .option('-p --parser <babel | babylon | flow | ts | tsx>', 'jscodeshift parser')
    .option(
      '-n --dry-run',
      'Dry run: verify the migration exists and show the files to which it will be applied'
    )
    .option(
      '-r --rename <from-to>',
      'Rename suffix of matching files after codemod has been applied, e.g. ".js:.ts"'
    )
    .action((migration, { configDir, glob, dryRun, list, rename, parser }) => {
      migrate(migration, { configDir, glob, dryRun, list, rename, parser, logger }).catch(err => {
        logger.error(err);
        process.exit(1);
      });
    });

  program
    .command('extract [location] [output]')
    .description('extract stories.json from a built version')
    .action((location = 'storybook-static', output = path.join(location, 'stories.json')) =>
      extract(location, output).catch(e => {
        logger.error(e);
        process.exit(1);
      })
    );

  program.command('*', { noHelp: true }).action(() => {
    const [, , invalidCmd] = process.argv;
    logger.error(
      ' Invalid command: %s.\n See --help for a list of available commands.',
      invalidCmd
    );
    // eslint-disable-next-line
    const availableCommands = program.commands.map(cmd => cmd._name);
    const suggestion = availableCommands.find(cmd => leven(cmd, invalidCmd) < 3);
    if (suggestion) {
      logger.log(`\n Did you mean ${suggestion}?`);
    }
    process.exit(1);
  });

  program
    .usage('<command> [options]')
    .version(pkg.version)
    .parse(process.argv);

  if (program.rawArgs.length < 3) {
    program.help();
  }
}
<commit_msg>REMOVE deprecated APIs in lib/cli<commit_after>import program from 'commander';
import path from 'path';
import chalk from 'chalk';
import envinfo from 'envinfo';
import leven from 'leven';
import pkg from '../package.json';
import initiate from './initiate';
import { codeLog } from './helpers';
import { add } from './add';
import { migrate } from './migrate';
import { extract } from './extract';

const logger = console;

program
  .command('init')
  .description('Initialize Storybook into your project.')
  .option('-f --force', 'Force add storybook')
  .option('-s --skip-install', 'Skip installing deps')
  .option('-N --use-npm', 'Use npm to install deps')
  .option('-p --parser <babel | babylon | flow | ts | tsx>', 'jscodeshift parser')
  .option('-t --type <type>', 'Add Storybook for a specific project type')
  .option('--story-format <csf | csf-ts | mdx >', 'Generate stories in a specified format')
  .option('-y --yes', 'Answer yes to all prompts')
  .action(options => initiate(options, pkg));

program
  .command('add <addon>')
  .description('Add an addon to your Storybook')
  .option('-N --use-npm', 'Use NPM to build the Storybook server')
  .option('-s --skip-postinstall', 'Skip package specific postinstall config modifications')
  .action((addonName, options) => add(addonName, options));

program
  .command('info')
  .description('Prints debugging information about the local environment')
  .action(() => {
    logger.log(chalk.bold('\nEnvironment Info:'));
    envinfo
      .run({
        System: ['OS', 'CPU'],
        Binaries: ['Node', 'Yarn', 'npm'],
        Browsers: ['Chrome', 'Edge', 'Firefox', 'Safari'],
        npmPackages: '@storybook/*',
        npmGlobalPackages: '@storybook/*',
      })
      .then(logger.log);
  });

program
  .command('migrate [migration]')
  .description('Run a storybook codemod migration on your source files')
  .option('-l --list', 'List available migrations')
  .option('-g --glob <glob>', 'Glob for files upon which to apply the migration', '**/*.js')
  .option('-p --parser <babel | babylon | flow | ts | tsx>', 'jscodeshift parser')
  .option(
    '-n --dry-run',
    'Dry run: verify the migration exists and show the files to which it will be applied'
  )
  .option(
    '-r --rename <from-to>',
    'Rename suffix of matching files after codemod has been applied, e.g. ".js:.ts"'
  )
  .action((migration, { configDir, glob, dryRun, list, rename, parser }) => {
    migrate(migration, { configDir, glob, dryRun, list, rename, parser, logger }).catch(err => {
      logger.error(err);
      process.exit(1);
    });
  });

program
  .command('extract [location] [output]')
  .description('extract stories.json from a built version')
  .action((location = 'storybook-static', output = path.join(location, 'stories.json')) =>
    extract(location, output).catch(e => {
      logger.error(e);
      process.exit(1);
    })
  );

program.command('*', { noHelp: true }).action(() => {
  const [, , invalidCmd] = process.argv;
  logger.error(' Invalid command: %s.\n See --help for a list of available commands.', invalidCmd);
  // eslint-disable-next-line
    const availableCommands = program.commands.map(cmd => cmd._name);
  const suggestion = availableCommands.find(cmd => leven(cmd, invalidCmd) < 3);
  if (suggestion) {
    logger.log(`\n Did you mean ${suggestion}?`);
  }
  process.exit(1);
});

program
  .usage('<command> [options]')
  .version(pkg.version)
  .parse(process.argv);

if (program.rawArgs.length < 3) {
  program.help();
}
<|endoftext|>


<commit_before>'use strict';

import { Events } from './Events.js';
import { Vec3 } from './math/Vec3.js';
import { getHTML, parseHTML, createLonLat } from './utils/shared.js';

const TEMPLATE =
    `

×

`;

class Popup {
    constructor(options) {

        this._id = Popup._staticCounter++;

        this.events = new Events(["open", "close"]);

        this._template = getHTML(TEMPLATE, { className: options.className });

        this.el = null;

        this._title = options.title || "";

        this._content = options.content || null;

        this._contentEl = null;

        this._titleEl = null;

        this._planet = options.planet;

        this._offset = options.offset || [0, 0];

        this._lonLat = createLonLat(options.lonLat);

        this._cartPos = new Vec3();

        this._visibility = options.visibility || false;

        this.render();
    }

    static get _staticCounter() {
        if (!this.__counter__ && this.__counter__ !== 0) {
            this.__counter__ = 0;
        }
        return this.__counter__;
    }

    static set _staticCounter(n) {
        this.__counter__ = n;
    }

    _renderTemplate() {
        return parseHTML(this._template)[0];
    }

    _updatePosition() {
        this.setCartesian3v(this._cartPos);
    }

    setScreen(p) {
        if (this._planet) {
            this.el.style.transform = "translate(" + (p.x - this.clientWidth * 0.5) + "px, " + (p.y - this._planet.renderer.handler.canvas.height - this.clientHeight * 0.5) + "px)"
        }
    }

    get clientWidth() {
        return this.el.clientWidth;
    }

    get clientHeight() {
        return this.el.clientHeight;
    }

    setOffset(x = 0, y = 0) {
        this._offset[0] = x;
        this._offset[1] = y;
        if (this.el) {
            this.el.style.left = `${x}px`;
            this.el.style.bottom = `${y}px`;
        }
        return this;
    }

    render(params) {
        this.el = this._renderTemplate(params);
        this._contentEl = this.el.querySelector(".og-popup-content");
        this._titleEl = this.el.querySelector(".og-popup-title")
        this.setOffset(this._offset[0], this._offset[1]);
        this.setContent(this._content);
        this.setTitle(this._title);
        this.setLonLat(this._lonLat);
        this.setVisibility(this._visibility);
        this.el.querySelector(".og-popup-close").addEventListener("click", (e) => {
            this.hide();
        });
        return this;
    }

    setVisibility(visibility) {
        if (visibility) {
            this.show();
        } else {
            this.hide();
        }
        return this;
    }

    getContainer() {
        return this._contentEl;
    }

    getToolbarContainer() {
        return this.el.querySelector(".og-popup-toolbar");
    }

    show() {
        this._visibility = true;
        if (this._planet) {
            this._planet.events.on("draw", this._updatePosition, this);
            this._planet.renderer.div.appendChild(this.el);
            this.events.dispatch(this.events.open, this);
        }
        return this;
    }

    hide() {
        this._visibility = false;
        if (this.el.parentNode) {
            this._planet.events.off("draw", this._updatePosition);
            this.el.parentNode.removeChild(this.el);
            this.events.dispatch(this.events.close, this);
        }
        return this;
    }

    setCartesian3v(cart, height = 0) {

        this._cartPos = cart;

        if (this._planet) {
            let cam = this._planet.camera;
            let f = this._planet.ellipsoid._a + height,
                g = cam._lonLat.height;

            let look = cart.sub(cam.eye),
                v = Math.sqrt((f + g) * (f + g) - f * f);

            if (v > look.length() && cam.getForward().dot(look.normalize()) > 0.0) {
                this.el.style.display = "block";
                this.setScreen(cam.project(cart));
            } else {
                this.el.style.display = "none";
            }
        }
        return this;
    }

    setTitle(html) {
        this._title = html;
        this._titleEl.innerHTML = html;
        return this;
    }

    setLonLat(lonLat) {
        this._lonLat = lonLat;
        if (this._planet) {
            this.setCartesian3v(this._planet.ellipsoid.lonLatToCartesian(lonLat), lonLat.height);
        }
        return this;
    }

    setContent(content) {
        if (content) {
            this.clear();
            this._content = content;
            if (typeof content === 'string') {
                this._contentEl.innerHTML = content;
            } else {
                this._contentEl.appendChild(content)
            }
        }
        return this;
    }

    clear() {
        this._content = null;
        this._contentEl.innerHTML = "";
    }
}

export { Popup };<commit_msg>fix popup position<commit_after>'use strict';

import { Events } from './Events.js';
import { Vec3 } from './math/Vec3.js';
import { getHTML, parseHTML, createLonLat } from './utils/shared.js';

const TEMPLATE =
    `

×

`;

class Popup {
    constructor(options) {

        this._id = Popup._staticCounter++;

        this.events = new Events(["open", "close"]);

        this._template = getHTML(TEMPLATE, { className: options.className });

        this.el = null;

        this._title = options.title || "";

        this._content = options.content || null;

        this._contentEl = null;

        this._titleEl = null;

        this._planet = options.planet;

        this._offset = options.offset || [0, 0];

        this._lonLat = createLonLat(options.lonLat);

        this._cartPos = new Vec3();

        this._visibility = options.visibility || false;

        this.render();
    }

    static get _staticCounter() {
        if (!this.__counter__ && this.__counter__ !== 0) {
            this.__counter__ = 0;
        }
        return this.__counter__;
    }

    static set _staticCounter(n) {
        this.__counter__ = n;
    }

    _renderTemplate() {
        return parseHTML(this._template)[0];
    }

    _updatePosition() {
        this.setCartesian3v(this._cartPos);
    }

    setScreen(p) {
        if (this._planet) {
            this.el.style.transform = "translate(" + (p.x - this.clientWidth * 0.5) + "px, " + (p.y - this._planet.renderer.handler.canvas.height - this._tipEl.clientHeight) + "px)"
        }
    }

    get clientWidth() {
        return this.el.clientWidth;
    }

    get clientHeight() {
        return this.el.clientHeight;
    }

    setOffset(x = 0, y = 0) {
        this._offset[0] = x;
        this._offset[1] = y;
        if (this.el) {
            this.el.style.left = `${x}px`;
            this.el.style.bottom = `${y}px`;
        }
        return this;
    }

    render(params) {
        this.el = this._renderTemplate(params);
        this._contentEl = this.el.querySelector(".og-popup-content");
        this._titleEl = this.el.querySelector(".og-popup-title")
        this._tipEl = this.el.querySelector(".og-popup-tip-container")
        this.setOffset(this._offset[0], this._offset[1]);
        this.setContent(this._content);
        this.setTitle(this._title);
        this.setLonLat(this._lonLat);
        this.setVisibility(this._visibility);
        this.el.querySelector(".og-popup-close").addEventListener("click", (e) => {
            this.hide();
        });
        return this;
    }

    setVisibility(visibility) {
        if (visibility) {
            this.show();
        } else {
            this.hide();
        }
        return this;
    }

    getContainer() {
        return this._contentEl;
    }

    getToolbarContainer() {
        return this.el.querySelector(".og-popup-toolbar");
    }

    show() {
        this._visibility = true;
        if (this._planet) {
            this._planet.events.on("draw", this._updatePosition, this);
            this._planet.renderer.div.appendChild(this.el);
            this.events.dispatch(this.events.open, this);
        }
        return this;
    }

    hide() {
        this._visibility = false;
        if (this.el.parentNode) {
            this._planet.events.off("draw", this._updatePosition);
            this.el.parentNode.removeChild(this.el);
            this.events.dispatch(this.events.close, this);
        }
        return this;
    }

    setCartesian3v(cart, height = 0) {

        this._cartPos = cart;

        if (this._planet) {
            let cam = this._planet.camera;
            let f = this._planet.ellipsoid._a + height,
                g = cam._lonLat.height;

            let look = cart.sub(cam.eye),
                v = Math.sqrt((f + g) * (f + g) - f * f);

            if (v > look.length() && cam.getForward().dot(look.normalize()) > 0.0) {
                this.el.style.display = "block";
                this.setScreen(cam.project(cart));
            } else {
                this.el.style.display = "none";
            }
        }
        return this;
    }

    setTitle(html) {
        this._title = html;
        this._titleEl.innerHTML = html;
        return this;
    }

    setLonLat(lonLat) {
        this._lonLat = lonLat;
        if (this._planet) {
            this.setCartesian3v(this._planet.ellipsoid.lonLatToCartesian(lonLat), lonLat.height);
        }
        return this;
    }

    setContent(content) {
        if (content) {
            this.clear();
            this._content = content;
            if (typeof content === 'string') {
                this._contentEl.innerHTML = content;
            } else {
                this._contentEl.appendChild(content)
            }
        }
        return this;
    }

    clear() {
        this._content = null;
        this._contentEl.innerHTML = "";
    }
}

export { Popup };<|endoftext|>