<commit_before>/* jshint maxdepth: 5, maxparams: 6 */

(function(W, U) {
	'use strict';

	var reg = {
			tags: /{{\s*(?:([#\/])([^#{\|\n\s]+)\s*(\|[^{\n]+)?|else)\s*}}/g,
			partial: /{{\s*> (.+?)}}/g,
			pair: /{{#(.+?)(?:|\|?([^}]*))}}([\s\S]*?){{\/\1}}/g,
			single: /{{(.+?)}}/g,
			ext: /(.[^\(]+)(?:\((.*)\))?/,
			str: /^\\?("|')/,
			args: /(\\?['"][^'"]+\\?['"]|[^,]+)/g
		},
		helpers = {
			is: function(val) {
				return this.val === val;
			},
			not: function(val) {
				return this.val !== val;
			},
			isEmpty: function() {
				return this.empty;
			},
			notEmpty: function() {
				return ! this.empty;
			}
		},
		partials = {},
		esc,

		/**
		 * Determine if value is matches empty criteria
		 *
		 * @private
		 * @param {*} val
		 * @returns {boolean}
		 */
		_isEmpty = function(val) {
			return val === '' ||
				val === false ||
				val == null ||
				(typeof val == 'object' && ! Object.keys(val).length);
		},

		/**
		 * Render template string
		 *
		 * @private
		 * @param {string} temp
		 * @param {object} data
		 * @returns {string}
		 */
		_render = function(temp, data) {
			var tags = [],
				depth = [];

			// Make partial replacements and match tag pairs
			temp = temp.replace(reg.partial, function(match, tag) {
				var partial = partials[tag.trim()];

				return partial ? (
					W.$isFunction(partial) ?
						partial() :
						partial
				) : '';
			}).replace(reg.tags, function(m, pre, tag, helper) {
				var resp = '{{';

				if (pre) {
					var segs = tag.split('('),
						root = segs[0],
						exists = tags.hasOwnProperty(tag);
					resp += pre + root + '%';

					if (pre == '#') {
						depth.push(root);

						if (exists) {
							tags[root].i++;
							tags[root].o.push(tags[root].i);
						} else {
							tags[root] = {
								i: 1,
								o: [1]
							};
						}

						if (segs.length > 1) {
							helper = '(' + segs.slice(1).join('(');
						}

						resp += tags[root].i + (helper || '');
					} else if (exists) {
						resp += tags[root].o.pop();
					}
				} else {
					tag = depth.pop();
					resp += ':' + tag + '%' + tags[tag].i;
				}

				return resp + '}}';
			});

			// Parse template tags
			temp = _parse(temp, data, {}, data, 0);

			// Reconstitute replacements
			return esc ?
				temp.replace(/{~/g, '{{')
					.replace(/~}/g, '}}')
					.replace(/%\d+/g, '') :
				temp;
		},

		/**
		 * Parse template string
		 *
		 * @private
		 * @param {string} temp
		 * @param {object} data
		 * @param {object} prev
		 * @param {object} init
		 * @param {int} index
		 * @returns {string}
		 */
		_parse = function(temp, data, prev, init, index) {
			return temp.replace(reg.pair, function(m, t, helper, inner) {
				var tag = t.replace(/%\d+/, '');

				// Escape child template tags
				if (tag == '!') {
					esc = true;

					return inner.replace(/{{:[^{\s]+}}/g, '{{ else }}')
						.replace(/{{/g, '{~ ')
						.replace(/}}/g, ' ~}');
				}

				var cond = inner.split('{{:' + t + '}}');
				inner = cond[0];
				esc = false;

				var val = _get(data, prev, tag, U, init, index),
					empty = _isEmpty(val),
					help = [],
					each;

				// Parse helpers
				if (helper || empty) {
					var meth = helper ? helper.split('|') : [],
						sec = cond.length > 1 ? cond[1] : '',
						agg = [];

					// Check for root helpers
					if (empty) {
						var arg = meth[0] && meth[0][0] == '(';
						meth.unshift(tag + (arg ? meth[0] : '()'));

						if (arg) {
							meth.splice(1, 1);
						}
					}

					// Capture available aggregates and helpers
					meth.forEach(function(el) {
						var arr = el.match(reg.ext),
							name = arr[1].trim();

						// Check for each helper
						if (name == 'each') {
							each = true;
						} else if (helpers[name]) {
							el = [helpers[name], arr[2]];
							each ? help.push(el) : agg.push(el);
						}
					});

					// Process aggregates
					if (agg.length) {
						if (! agg.every(function(f) {
								var rv = f[0].apply({
									val: val,
									data: data,
									root: init,
									tag: tag,
									empty: empty,
									index: index
								}, _parseArgs(f[1], val));

								if (rv === false) {
									return rv;
								}

								if (rv !== true) {
									val = rv;
									empty = _isEmpty(val);
								}

								return true;
							})) {
							return sec;
						}
					} else if (empty) {
						return sec;
					}
				}

				var isObject = typeof val == 'object';

				if (! each) {
					if (! isObject) {
						val = W.$extend({}, data, {
							'.': val,
							'#': 0,
							'##': 1
						});
					}

					return _parse(inner, val, data, init, index);
				}

				if (! empty) {
					// Loop through objects and arrays
					if (isObject) {
						var isPlainObject = W.$isObject(val),
							resp = '',
							i = 0;

						for (var key in val) {
							if (val.hasOwnProperty(key)) {
								// Merge default properties
								var el = val[key];
								empty = _isEmpty(el);

								// Process helpers
								if (! help.length ||
									help.every(function(f) {
										var rv = f[0].apply({
											val: el,
											data: data,
											root: init,
											tag: tag,
											empty: empty,
											index: i
										}, _parseArgs(f[1], val));

										if (rv === false) {
											return rv;
										}

										if (rv !== true) {
											el = rv;
										}

										return true;
									})) {
									var item = W.$extend({}, W.$isObject(el) ?
											el :
											(isPlainObject ? val : {}),
										{
											$key: key,
											'.': el,
											'#': i,
											'##': i + 1
										});

									i++;

									resp += _parse(inner, item, data, init, i);
								}
							}
						}

						return resp;
					}

					return inner;
				}
			}).replace(reg.single, function(m, set) {
				var split = set.split('||'),
					fb = split[1],
					segs = split[0].split('|'),
					tag = segs[0].trim(),
					val = _get(data, prev, tag, fb, init, index),
					helps = segs.length > 1 ? segs.slice(1) : segs;

				// Return empty string if output isn't available
				if (val === U || typeof val == 'object') {
					val = '';
				}

				// Process helpers
				helps.forEach(function(el, i) {
					var arr = el.match(reg.ext);
					helps[i] = el.trim();

					if (arr) {
						var helper = helpers[arr[1].trim()];

						if (helper && (segs.length > 1 ||
							! data.hasOwnProperty(tag))) {
							val = helper.apply({
								val: val,
								data: data,
								root: init,
								tag: tag,
								index: index,
								fallback: fb
							}, _parseArgs(arr[2], data));
						}
					}
				});

				// Encode output by default
				if (val === U) {
					val = '';
				} else if (typeof val == 'string') {
					if (helps.indexOf('raw') < 0) {
						val = val.replace(/&/g, '&')
							.replace(/&/g, '&')
							.replace(/</g, '<')
							.replace(/>/g, '>')
							.replace(/"/g, '"');
					}
				}

				return val;
			});
		},

		/**
		 * Get specific object value
		 *
		 * @private
		 * @param {object} data
		 * @param {object} prev
		 * @param {string} key
		 * @param {string} fb
		 * @param {object} init
		 * @param {int} x
		 * @returns {*}
		 */
		_get = function(data, prev, key, fb, init, x) {
			key = key.trim();

			// Alter context
			if (key.substr(0, 6) == '$root.') {
				key = key.substr(6);
				data = init;
			} else if (key.substr(0, 3) == '../') {
				key = key.substr(3);
				data = prev;
			}

			var segs = key == '.' ? ['.'] : key.split('.'),
				orig = data,
				len = segs.length - 1,
				i = 0;

			// Loop through object segments
			for (; i <= len; i++) {
				key = segs[i];

				if (data && data.hasOwnProperty(key)) {
					data = data[key];

					// Return value on last segment
					if (i === len) {
						return data;
					}
				} else {
					break;
				}
			}

			if (key == '.') {
				return data;
			}

			// Process fallback value
			if (fb && fb !== '') {
				fb = fb.trim();
				var match = fb.match(reg.str);

				if (match) {
					return fb.replace(reg.str, '')
						.replace(new RegExp(match[0] + '$'), '');
				}

				return _get(orig, prev, fb, '', init, x);
			}

			return fb;
		},

		/**
		 * Parse helper arguments
		 *
		 * @private
		 * @param {string} str
		 * @returns {*}
		 */
		_parseArgs = function(str, data) {
			var args = str !== U ? str.match(reg.args) || [] : [];

			return args.map(function(arg) {
				arg = arg.trim();

				if (data && data.hasOwnProperty(arg) && isNaN(arg)) {
					return data[arg];
				} else {
					var match = arg.match(reg.str);

					if (match) {
						return arg.replace(reg.str, '')
							.replace(new RegExp(match[0] + '$'), '');
					}
				}

				return arg == 'true' ? true :
					arg == 'false' ? false :
						arg == 'null' ? null :
							parseInt(arg).toString() == arg ? parseInt(arg) :
								'';
			});
		};

	W.app = {
		/**
		 * Create an application
		 *
		 * @param {string} name
		 * @param {object} [options] - application configuration
		 */
		make: function(name, options) {
			var views = W.$(options.view).map(function(el) {
					return [el, el.outerHTML];
				}),
				fn = function(data) {
					views.forEach(function(view) {
						W.view.diff(view[0], W.view.render(view[1], data));
					});
				};

			W.app[name] = W._make(name, {}, false, options.model);
			W[name] = new W.app[name]();

			fn(options.model);

			W[name].$observe('*', fn);
		}
	};

	W.view = {
		/**
		 * Parse data into template string
		 *
		 * @param {string} template
		 * @param {object} data
		 * @returns {string}
		 */
		render: function(template, data) {
			return _render(template, W.$extend(data));
		},

		/**
		 * Add conditional template handler or tag data modifier
		 *
		 * @param {string} name
		 * @param {function} fn
		 */
		addHelper: function(name, fn) {
			W._extend(helpers, name, fn);
		},

		/**
		 * Make partial available for injection into other templates
		 *
		 * @param {string} name
		 * @param {string} value
		 */
		addPartial: function(name, value) {
			W._extend(partials, name, value);
		}
	};
})(Wee, undefined);<commit_msg>Ensure that else tag data is parsed<commit_after>/* jshint maxdepth: 5, maxparams: 6 */

(function(W, U) {
	'use strict';

	var reg = {
			args: /(\\?['"][^'"]+\\?['"]|[^,]+)/g,
			ext: /(.[^\(]+)(?:\((.*)\))?/,
			pair: /{{#(.+?)(?:|\|?([^}]*))}}([\s\S]*?){{\/\1}}/g,
			partial: /{{\s*> (.+?)}}/g,
			single: /{{(.+?)}}/g,
			str: /^\\?("|')/,
			tags: /{{\s*(?:([#\/])([^#{\|\n\s]+)\s*(\|[^{\n]+)?|else)\s*}}/g
		},
		helpers = {
			is: function(val) {
				return this.val === val;
			},
			not: function(val) {
				return this.val !== val;
			},
			isEmpty: function() {
				return this.empty;
			},
			notEmpty: function() {
				return ! this.empty;
			}
		},
		partials = {},
		esc,

		/**
		 * Determine if value is matches empty criteria
		 *
		 * @private
		 * @param {*} val
		 * @returns {boolean}
		 */
		_isEmpty = function(val) {
			return val === '' ||
				val === false ||
				val == null ||
				(typeof val == 'object' && ! Object.keys(val).length);
		},

		/**
		 * Render template string
		 *
		 * @private
		 * @param {string} temp
		 * @param {object} data
		 * @returns {string}
		 */
		_render = function(temp, data) {
			var tags = [],
				depth = [];

			// Make partial replacements and match tag pairs
			temp = temp.replace(reg.partial, function(match, tag) {
				var partial = partials[tag.trim()];

				return partial ? (
					W.$isFunction(partial) ?
						partial() :
						partial
				) : '';
			}).replace(reg.tags, function(m, pre, tag, helper) {
				var resp = '{{';

				if (pre) {
					var segs = tag.split('('),
						root = segs[0],
						exists = tags.hasOwnProperty(tag);
					resp += pre + root + '%';

					if (pre == '#') {
						depth.push(root);

						if (exists) {
							tags[root].i++;
							tags[root].o.push(tags[root].i);
						} else {
							tags[root] = {
								i: 1,
								o: [1]
							};
						}

						if (segs.length > 1) {
							helper = '(' + segs.slice(1).join('(');
						}

						resp += tags[root].i + (helper || '');
					} else if (exists) {
						resp += tags[root].o.pop();
					}
				} else {
					tag = depth.pop();
					resp += ':' + tag + '%' + tags[tag].i;
				}

				return resp + '}}';
			});

			// Parse template tags
			temp = _parse(temp, data, {}, data, 0);

			// Reconstitute replacements
			return esc ?
				temp.replace(/{~/g, '{{')
					.replace(/~}/g, '}}')
					.replace(/%\d+/g, '') :
				temp;
		},

		/**
		 * Parse template string
		 *
		 * @private
		 * @param {string} temp
		 * @param {object} data
		 * @param {object} prev
		 * @param {object} init
		 * @param {int} index
		 * @returns {string}
		 */
		_parse = function(temp, data, prev, init, index) {
			return temp.replace(reg.pair, function(m, t, helper, inner) {
				var tag = t.replace(/%\d+/, '');

				// Escape child template tags
				if (tag == '!') {
					esc = true;

					return inner.replace(/{{:[^{\s]+}}/g, '{{ else }}')
						.replace(/{{/g, '{~ ')
						.replace(/}}/g, ' ~}');
				}

				var cond = inner.split('{{:' + t + '}}');
				inner = cond[0];
				esc = false;

				var val = _get(data, prev, tag, U, init, index),
					empty = _isEmpty(val),
					help = [],
					each;

				// Parse helpers
				if (helper || empty) {
					var meth = helper ? helper.split('|') : [],
						sec = cond.length > 1 ? cond[1] : '',
						agg = [];

					// Check for root helpers
					if (empty) {
						var arg = meth[0] && meth[0][0] == '(';
						meth.unshift(tag + (arg ? meth[0] : '()'));

						if (arg) {
							meth.splice(1, 1);
						}
					}

					// Capture available aggregates and helpers
					meth.forEach(function(el) {
						var arr = el.match(reg.ext),
							name = arr[1].trim();

						// Check for each helper
						if (name == 'each') {
							each = true;
						} else if (helpers[name]) {
							el = [helpers[name], arr[2]];
							each ? help.push(el) : agg.push(el);
						}
					});

					// Process aggregates
					if (agg.length) {
						if (! agg.every(function(f) {
								var rv = f[0].apply({
									val: val,
									data: data,
									root: init,
									tag: tag,
									empty: empty,
									index: index
								}, _parseArgs(f[1], val));

								if (rv === false) {
									return rv;
								}

								if (rv !== true) {
									val = rv;
									empty = _isEmpty(val);
								}

								return true;
							})) {
							return _parse(sec, data, prev, init, index);
						}
					} else if (empty) {
						return _parse(sec, data, prev, init, index);
					}
				}

				var isObject = typeof val == 'object';

				if (! each) {
					if (! isObject) {
						val = W.$extend({}, data, {
							'.': val,
							'#': 0,
							'##': 1
						});
					}

					return _parse(inner, val, data, init, index);
				}

				if (! empty) {
					// Loop through objects and arrays
					if (isObject) {
						var isPlainObject = W.$isObject(val),
							resp = '',
							i = 0;

						for (var key in val) {
							if (val.hasOwnProperty(key)) {
								// Merge default properties
								var el = val[key];
								empty = _isEmpty(el);

								// Process helpers
								if (! help.length ||
									help.every(function(f) {
										var rv = f[0].apply({
											val: el,
											data: data,
											root: init,
											tag: tag,
											empty: empty,
											index: i
										}, _parseArgs(f[1], val));

										if (rv === false) {
											return rv;
										}

										if (rv !== true) {
											el = rv;
										}

										return true;
									})) {
									var item = W.$extend({}, W.$isObject(el) ?
											el :
											(isPlainObject ? val : {}),
										{
											$key: key,
											'.': el,
											'#': i,
											'##': i + 1
										});

									i++;

									resp += _parse(inner, item, data, init, i);
								}
							}
						}

						return resp;
					}

					return inner;
				}
			}).replace(reg.single, function(m, set) {
				var split = set.split('||'),
					fb = split[1],
					segs = split[0].split('|'),
					tag = segs[0].trim(),
					val = _get(data, prev, tag, fb, init, index),
					helps = segs.length > 1 ? segs.slice(1) : segs;

				// Return empty string if output isn't available
				if (val === U || typeof val == 'object') {
					val = '';
				}

				// Process helpers
				helps.forEach(function(el, i) {
					var arr = el.match(reg.ext);
					helps[i] = el.trim();

					if (arr) {
						var helper = helpers[arr[1].trim()];

						if (helper && (segs.length > 1 ||
							! data.hasOwnProperty(tag))) {
							val = helper.apply({
								val: val,
								data: data,
								root: init,
								tag: tag,
								index: index,
								fallback: fb
							}, _parseArgs(arr[2], data));
						}
					}
				});

				// Encode output by default
				if (val === U) {
					val = '';
				} else if (typeof val == 'string') {
					if (helps.indexOf('raw') < 0) {
						val = val.replace(/&/g, '&')
							.replace(/&/g, '&')
							.replace(/</g, '<')
							.replace(/>/g, '>')
							.replace(/"/g, '"');
					}
				}

				return val;
			});
		},

		/**
		 * Get specific object value
		 *
		 * @private
		 * @param {object} data
		 * @param {object} prev
		 * @param {string} key
		 * @param {string} fb
		 * @param {object} init
		 * @param {int} x
		 * @returns {*}
		 */
		_get = function(data, prev, key, fb, init, x) {
			key = key.trim();

			// Alter context
			if (key.substr(0, 6) == '$root.') {
				key = key.substr(6);
				data = init;
			} else if (key.substr(0, 3) == '../') {
				key = key.substr(3);
				data = prev;
			}

			var segs = key == '.' ? ['.'] : key.split('.'),
				orig = data,
				len = segs.length - 1,
				i = 0;

			// Loop through object segments
			for (; i <= len; i++) {
				key = segs[i];

				if (data && data.hasOwnProperty(key)) {
					data = data[key];

					// Return value on last segment
					if (i === len) {
						return data;
					}
				} else {
					break;
				}
			}

			if (key == '.') {
				return data;
			}

			// Process fallback value
			if (fb && fb !== '') {
				fb = fb.trim();
				var match = fb.match(reg.str);

				if (match) {
					return fb.replace(reg.str, '')
						.replace(new RegExp(match[0] + '$'), '');
				}

				return _get(orig, prev, fb, '', init, x);
			}

			return fb;
		},

		/**
		 * Parse helper arguments
		 *
		 * @private
		 * @param {string} str
		 * @returns {*}
		 */
		_parseArgs = function(str, data) {
			var args = str !== U ? str.match(reg.args) || [] : [];

			return args.map(function(arg) {
				arg = arg.trim();

				if (data && data.hasOwnProperty(arg) && isNaN(arg)) {
					return data[arg];
				} else {
					var match = arg.match(reg.str);

					if (match) {
						return arg.replace(reg.str, '')
							.replace(new RegExp(match[0] + '$'), '');
					}
				}

				return arg == 'true' ? true :
					arg == 'false' ? false :
						arg == 'null' ? null :
							parseInt(arg).toString() == arg ? parseInt(arg) :
								'';
			});
		};

	W.app = {
		/**
		 * Create an application
		 *
		 * @param {string} name
		 * @param {object} [options] - application configuration
		 */
		make: function(name, options) {
			var views = W.$(options.view).map(function(el) {
					return [el, el.outerHTML];
				}),
				fn = function(data) {
					views.forEach(function(view) {
						W.view.diff(view[0], W.view.render(view[1], data));
					});
				};

			W.app[name] = W._make(name, {}, false, options.model);
			W[name] = new W.app[name]();

			fn(options.model);

			W[name].$observe('*', fn);
		}
	};

	W.view = {
		/**
		 * Parse data into template string
		 *
		 * @param {string} template
		 * @param {object} data
		 * @returns {string}
		 */
		render: function(template, data) {
			return _render(template, W.$extend(data));
		},

		/**
		 * Add conditional template handler or tag data modifier
		 *
		 * @param {string} name
		 * @param {function} fn
		 */
		addHelper: function(name, fn) {
			W._extend(helpers, name, fn);
		},

		/**
		 * Make partial available for injection into other templates
		 *
		 * @param {string} name
		 * @param {string} value
		 */
		addPartial: function(name, value) {
			W._extend(partials, name, value);
		}
	};
})(Wee, undefined);<|endoftext|>


<commit_before>(function(module){
  // Create a new .js file with the appropriate methods to help modify your source data to help render it to the DOM:
  // Use good Object Oriented code: Create a constructor function for projects or source data.
  // Leave as little in the window (global) namespace as possible: attach functions to objects, etc.
  // Use jQuery to clone the example markup for each project, as you add additional content.
  // Your "Project" prototype should have a .toHtml() function that adds new data to the DOM.

  // new constructor
  function Blog (opts) {
    for (keys in opts) {
      this[keys] = opts[keys];
    }
  }

  /* The old constructor
  // constructor that will take in the blogEntries object array
  function Blog (arr) {
    this.title = arr.title;
    this.date = arr.date;
    this.tag = arr.tag;
    this.link = arr.link;
    this.body = arr.body;
  }*/

  // add a property to the obj constructor with an array value
  Blog.blogsArr = [];

  Blog.prototype.toHtml = function() {
    var source = $('#blog-handlebars').html();
    var template = Handlebars.compile(source);
    var html = template(this);

    return html;
  };

  // sorts blog entries by date but the date value needs yyyy-mm-dd notation
  // blogEntries.sort(function(curElem, nextElem) {
  //   return (new Date(nextElem.publishedOn)) - (new Date(curElem.publishedOn));
  // });

  Blog.pushToBlogsArr = function (inputArr) {
    // for each element of the inputArr, push a new blog object into Blog.blogsArr. The new blog object has the needed toHtml function
    console.log('inputArr ', inputArr);
    inputArr.forEach(function(ele) {
      Blog.blogsArr.push(new Blog(ele));
    });
  };

  module.Blog = Blog;
})(window);
<commit_msg>changed pushToBlogsArr from property to prototype method<commit_after>(function(module){
  // Create a new .js file with the appropriate methods to help modify your source data to help render it to the DOM:
  // Use good Object Oriented code: Create a constructor function for projects or source data.
  // Leave as little in the window (global) namespace as possible: attach functions to objects, etc.
  // Use jQuery to clone the example markup for each project, as you add additional content.
  // Your "Project" prototype should have a .toHtml() function that adds new data to the DOM.

  // new constructor
  function Blog (opts) {
    for (keys in opts) {
      this[keys] = opts[keys];
    }
  }

  /* The old constructor
  // constructor that will take in the blogEntries object array
  function Blog (arr) {
    this.title = arr.title;
    this.date = arr.date;
    this.tag = arr.tag;
    this.link = arr.link;
    this.body = arr.body;
  }*/

  // add a property to the obj constructor with an array value
  Blog.blogsArr = [];

  Blog.prototype.toHtml = function() {
    var source = $('#blog-handlebars').html();
    var template = Handlebars.compile(source);
    var html = template(this);

    return html;
  };

  // sorts blog entries by date but the date value needs yyyy-mm-dd notation
  // blogEntries.sort(function(curElem, nextElem) {
  //   return (new Date(nextElem.publishedOn)) - (new Date(curElem.publishedOn));
  // });

  Blog.prototype.pushToBlogsArr = function (inputArr) {
    // for each element of the inputArr, push a new blog object into Blog.blogsArr. The new blog object has the needed toHtml function
    console.log('inputArr ', inputArr);
    inputArr.forEach(function(ele) {
      Blog.blogsArr.push(new Blog(ele));
    });
  };

  module.Blog = Blog;
})(window);
<|endoftext|>


<commit_before>/*

index.js - "tart-marshal": Send messages between memory domains (tart module)

The MIT License (MIT)

Copyright (c) 2013 Dale Schumacher

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

*/
"use strict";

var marshal = module.exports;

marshal.router = function router(sponsor, defaultRoute) {  // table-based routing transport
    var self = {};

    self.sponsor = sponsor;
    self.defaultRoute = defaultRoute || sponsor(function(message) {
        throw Error('No route for ' + message.address);
    });

    self.routingTable = {};  // mapping from domains to transports

    self.transport = sponsor(function routerBeh(message) {
        // { address:<token>, content:<json> }
        var remote = message.address;
        var parsed = remote.split('#');
        if (parsed.length != 2) { throw Error('Bad address format: ' + remote); }
        var domain = parsed[0];
        var route = self.routingTable[domain];
        if (!route) {
            route = defaultRoute;
        }
        route(message);
    });

    self.domain = function domain(name, sponsor) {
        sponsor = sponsor || self.sponsor;
        var dom = marshal.domain(name, sponsor, self.transport);
        self.routingTable[name] = dom.receptionist;
        return dom;
    };

    return self;
};

marshal.domain = function domain(name, sponsor, transport) {
    var self = {};
    var tokenMap = {};

    self.name = name;
    self.sponsor = sponsor;
    self.transport = transport;

    self.receptionist = sponsor(function receptionistBeh(message) {
        // { address:<token>, content:<json> }
        var local = tokenMap[message.address];
        if (!local) { throw Error('Unknown address: ' + message.address); }
        local(decode(message.content));
    });

    var localToRemote = function localToRemote(local) {
        var remote;
        for (remote in tokenMap) {
            if (tokenMap[remote] === local) {
                return remote;
            }
        }
        /* not found, create a new entry */
        remote = name + '#' + generateCapability();
        tokenMap[remote] = local;
        return remote;
    };
    var generateCapability = function generateCapability() {
        try {
            return require('crypto').randomBytes(42).toString('base64');
        } catch (exception) {
            // FIXME: if the system runs out of entropy, an exception will be
            //        thrown; we need to define system behavior when we are out
            //        of entropy, remembering that the entire OS crypto activity
            //        (including any encrypted network traffic) will grind to
            //        a halt while waiting for entropy to be available
            throw exception;
        }
    };

    var remoteToLocal = function remoteToLocal(remote) {
        var local = tokenMap[remote];
        if (local === undefined) {
            local = sponsor(proxy(remote));  // create new proxy
            tokenMap[remote] = local;
        }
        return local;
    };
    var proxy = function proxy(remote) {
        return function proxyBeh(message) {
            transport({
                address: remote,
                content: encode(message)
            });
        };
    };

    var encode = function encode(message) {
        var json;
        json = JSON.stringify(message, replacer);
        return json;
    };
    var replacer = function replacer(key, value) {
        if (typeof value === 'function') {
            return localToRemote(value);
        }
        if (typeof value === 'string') {
            return encodeString(value);
        }
        return value;
    };
    var encodeString = function encodeString(value) {
        return ":" + value;
    };

    var decode = function decode(json) {
        var message;
        message = JSON.parse(json, reviver);
        return message;
    };
    var reviver = function reviver(key, value) {
        if (typeof value === 'string') {
            if (isString(value)) {
                return decodeString(value);
            } else {
                return remoteToLocal(value);
            }
        }
        return value;
    };
    var isString = function isString(value) {
        return (value.charAt(0) === ":");
    };
    var decodeString = function decodeString(value) {
        return value.slice(1);
    };

    self.localToRemote = localToRemote;
    self.remoteToLocal = remoteToLocal;
    return self;
};

marshal.applyBeh = function (obj, fn) {
    return function applyBeh(message) {
        message.customer(fn.apply(obj, message.arguments));
    };
};
<commit_msg>Prune unused applyBeh()<commit_after>/*

index.js - "tart-marshal": Send messages between memory domains (tart module)

The MIT License (MIT)

Copyright (c) 2013 Dale Schumacher

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

*/
"use strict";

var marshal = module.exports;

marshal.router = function router(sponsor, defaultRoute) {  // table-based routing transport
    var self = {};

    self.sponsor = sponsor;
    self.defaultRoute = defaultRoute || sponsor(function(message) {
        throw Error('No route for ' + message.address);
    });

    self.routingTable = {};  // mapping from domains to transports

    self.transport = sponsor(function routerBeh(message) {
        // { address:<token>, content:<json> }
        var remote = message.address;
        var parsed = remote.split('#');
        if (parsed.length != 2) { throw Error('Bad address format: ' + remote); }
        var domain = parsed[0];
        var route = self.routingTable[domain];
        if (!route) {
            route = defaultRoute;
        }
        route(message);
    });

    self.domain = function domain(name, sponsor) {
        sponsor = sponsor || self.sponsor;
        var dom = marshal.domain(name, sponsor, self.transport);
        self.routingTable[name] = dom.receptionist;
        return dom;
    };

    return self;
};

marshal.domain = function domain(name, sponsor, transport) {
    var self = {};
    var tokenMap = {};

    self.name = name;
    self.sponsor = sponsor;
    self.transport = transport;

    self.receptionist = sponsor(function receptionistBeh(message) {
        // { address:<token>, content:<json> }
        var local = tokenMap[message.address];
        if (!local) { throw Error('Unknown address: ' + message.address); }
        local(decode(message.content));
    });

    var localToRemote = function localToRemote(local) {
        var remote;
        for (remote in tokenMap) {
            if (tokenMap[remote] === local) {
                return remote;
            }
        }
        /* not found, create a new entry */
        remote = name + '#' + generateCapability();
        tokenMap[remote] = local;
        return remote;
    };
    var generateCapability = function generateCapability() {
        try {
            return require('crypto').randomBytes(42).toString('base64');
        } catch (exception) {
            // FIXME: if the system runs out of entropy, an exception will be
            //        thrown; we need to define system behavior when we are out
            //        of entropy, remembering that the entire OS crypto activity
            //        (including any encrypted network traffic) will grind to
            //        a halt while waiting for entropy to be available
            throw exception;
        }
    };

    var remoteToLocal = function remoteToLocal(remote) {
        var local = tokenMap[remote];
        if (local === undefined) {
            local = sponsor(proxy(remote));  // create new proxy
            tokenMap[remote] = local;
        }
        return local;
    };
    var proxy = function proxy(remote) {
        return function proxyBeh(message) {
            transport({
                address: remote,
                content: encode(message)
            });
        };
    };

    var encode = function encode(message) {
        var json;
        json = JSON.stringify(message, replacer);
        return json;
    };
    var replacer = function replacer(key, value) {
        if (typeof value === 'function') {
            return localToRemote(value);
        }
        if (typeof value === 'string') {
            return encodeString(value);
        }
        return value;
    };
    var encodeString = function encodeString(value) {
        return ":" + value;
    };

    var decode = function decode(json) {
        var message;
        message = JSON.parse(json, reviver);
        return message;
    };
    var reviver = function reviver(key, value) {
        if (typeof value === 'string') {
            if (isString(value)) {
                return decodeString(value);
            } else {
                return remoteToLocal(value);
            }
        }
        return value;
    };
    var isString = function isString(value) {
        return (value.charAt(0) === ":");
    };
    var decodeString = function decodeString(value) {
        return value.slice(1);
    };

    self.localToRemote = localToRemote;
    self.remoteToLocal = remoteToLocal;
    return self;
};
<|endoftext|>


<commit_before>"use strict";
var VFindMode = {
  isActive: false,
  query: "",
  parsedQuery: "",
  isRegex: false,
  ignoreCase: false,
  hasResults: false,
  matchCount: 0,
  scrollX: 0,
  scrollY: 0,
  initialRange: null,
  activeRegexIndex: 0,
  regexMatches: null,
  box: null,
  input: null,
  countEl: null,
  styleIn: null,
  options: null,
  cssSel: "::selection{background:#ff9632;}",
  cssIFrame: '*{font:normal normal normal 12px "Helvetica Neue",Helvetica,Arial,sans-serif !important;\
height:14px;line-height:12px;margin:0;overflow-y:hidden;vertical-align:top;white-space:nowrap;cursor:default;}\
body{display:inline-block;padding:0 3px 0 1px;min-width:7px;}body *{display:inline;}body br{display:none;}',
  activate: function(count, options) {
    if (!document.head) { return false; }
    if (this.isActive) {
      this.input.focus();
      this.box.contentWindow.getSelection().selectAllChildren(this.input);
      return;
    }
    this.options = Object.setPrototypeOf(options || {}, null);
    this.scrollX = window.scrollX;
    this.scrollY = window.scrollY;
    this.parsedQuery = this.query = "";
    this.regexMatches = null;
    this.activeRegexIndex = 0;
    this.getCurrentRange();

    var el, wnd, doc;
    DomUtils.UI.addElement(el = this.box = DomUtils.createElement("iframe"));
    el.className = "R HUD";
    el.style.width = "0px";
    el.onmousedown = this.OnMousedown;
    wnd = el.contentWindow;
    wnd.onmousedown = this.OnMousedown;
    wnd.onkeydown = this.onKeydown.bind(this);
    doc = wnd.document;
    el = this.input = doc.body;
    el.contentEditable = "plaintext-only";
    el.oninput = this.onInput.bind(this);
    doc.documentElement.appendChild(this.countEl = doc.createElement("span"));

    el = DomUtils.UI.createStyle(this.cssIFrame, doc);
    doc.head.appendChild(el);
    doc.documentElement.insertBefore(new wnd.Text("/"), doc.body);

    this.init && this.init();
    DomUtils.UI.focus(this.input);
    this.isActive = true;
  },
  init: function() {
    var ref = this.postMode, UI = DomUtils.UI;
    ref.exit = ref.exit.bind(ref);
    this.styleIn = UI.createStyle(this.cssSel);
    UI.init && UI.init();
    UI.box.appendChild(UI.createStyle(".vimiumFindMode " + this.cssSel));
    this.init = null;
  },
  findAndFocus: function(count, backwards) {
    this.init && this.init();
    this.execute(null, {count: count, backwards: backwards});
    if (!this.hasResults) {
      VHUD.showForDuration("No matches for '" + this.query + "'", 1000);
      return;
    }
    this.focusFoundLink(window.getSelection().anchorNode);
    this.postMode.activate();
  },
  refocus: function() {
    this.checkReturnToViewPort();
    window.focus();
    var el = DomUtils.getSelectionFocusElement();
    el && el.focus();
    this.exit();
    return el;
  },
  exit: function() { // need keep @hasResults
    this.box.remove();
    this.box = this.input = this.countEl = this.options = null;
    this.styleIn.remove();
    this.parsedQuery = this.query = "";
    this.initialRange = this.regexMatches = null;
    this.matchCount = 0;
    this.isActive = false;
  },
  OnMousedown: function(event) { if (event.target !== VFindMode.input) { event.preventDefault(); VFindMode.input.focus(); } },
  onKeydown: function(event) {
    var i = event.keyCode, el, el2;
    i = event.altKey ? 0 : i === KeyCodes.enter ? (this.saveQuery(), 2)
      : (i === KeyCodes.backspace || i === KeyCodes.deleteKey) ? +!this.query.length
      : i === KeyCodes.esc && KeyboardUtils.isPlain(event) ? 3 : 0;
    if (!i) { return; }
    DomUtils.suppressEvent(event);
    el = this.refocus();
    if (i < 2 || !this.hasResults) { return; }
    if (i === 3 && this.styleIn.parentNode) {
      this.toggleStyle("remove");
      this.restoreSelection(true);
    }
    if (!el || el !== VInsertMode.lock) {
      el = window.getSelection().anchorNode;
      if (el && !this.focusFoundLink(el) && i === 3 && (el2 = document.activeElement)) {
        DomUtils.getEditableType(el2) === 3 && el.contains(el2) && DomUtils.UI.simulateSelect(el2);
      }
    }
    i === 2 && this.postMode.activate();
  },
  focusFoundLink: function(el) {
    for (; el && el !== document.body; el = el.parentElement) {
      if (el instanceof HTMLAnchorElement) {
        el.focus();
        return true;
      }
    }
  },
  saveQuery: function() {
    Settings.set("findModeRawQuery", this.query);
  },
  postMode: {
    lock: null,
    activate: function() {
      var el = VInsertMode.lock, Exit = this.exit;
      Exit();
      if (!el || DomUtils.getEditableType(el) < 2) { return; }
      // TODO: onblur won't be called on Vomnibar.input
      el.addEventListener("blur", Exit);
      this.lock = el;
      addEventListener("click", Exit, true);
      VInsertMode.setupSuppress(Exit);
      handlerStack.push(this.onKeydown, this);
    },
    onKeydown: function(event) {
      var exit = event.keyCode === KeyCodes.esc && KeyboardUtils.isPlain(event);
      exit ? this.exit() : handlerStack.remove(this);
      return 2 * exit;
    },
    exit: function() {
      if (!this.lock) { return; }
      this.lock.removeEventListener("blur", this.exit, true);
      this.lock = null;
      removeEventListener("click", this.exit, true);
      handlerStack.remove(this);
      VInsertMode.exitSuppress();
    }
  },
  onInput: function() {
    var query = this.input.textContent.replace('\xa0', " "), count;
    this.checkReturnToViewPort();
    this.updateQuery(query);
    this.restoreSelection();
    this.execute(!this.isRegex ? this.parsedQuery : this.regexMatches ? this.regexMatches[0] : "");
    count = this.matchCount;
    this.countEl.textContent = this.parsedQuery ? "(" + (count || (this.hasResults ? "Some" : "No")) + " match" + (count !== 1 ? "es)" : ")") : "";
    count = this.input.getBoundingClientRect().width + this.countEl.getBoundingClientRect().width;
    this.box.style.width = (count | 0) + 4 + "px";
    // TODO: prevent VInsertMode from locking
  },
  checkReturnToViewPort: function() {
    this.options.returnToViewport && window.scrollTo(this.scrollX, this.scrollY);
  },
  _ctrlRe: /(\\\\?)([rRI]?)/g,
  escapeAllRe: /[\$\(\)\*\+\.\?\[\\\]\^\{\|\}]/g,
  updateQuery: function(query) {
    this.query = query;
    this.isRegex = Settings.cache.regexFindMode;
    this.hasNoIgnoreCaseFlag = false;
    query = this.parsedQuery = query.replace(this._ctrlRe, this.FormatQuery);
    this.ignoreCase = !this.hasNoIgnoreCaseFlag && !/[A-Z]/.test(query);
    this.isRegex || (query = query.replace(this.escapeAllRe, "\\$&"));

    var re, matches;
    try {
      re = query && new RegExp(query, this.ignoreCase ? "g" : "gi");
    } catch (e) {}
    matches = re && (document.webkitFullscreenElement || document.documentElement).innerText.match(re);
    this.regexMatches = this.isRegex && matches || null;
    this.activeRegexIndex = 0;
    this.matchCount = matches ? matches.length : 0;
  },
  FormatQuery: function(match, slashes, flag) {
    if (!flag || slashes.length != 1) { return match; }
    if (flag === 'I') { VFindMode.hasNoIgnoreCaseFlag = true; }
    else { VFindMode.isRegex = flag === 'r'; }
    return "";
  },
  restoreSelection: function(isCur) {
    var sel = window.getSelection(), range;
    range = !isCur ? this.initialRange : sel.isCollapsed ? null : sel.getRangeAt(0);
    if (!range) { return; }
    sel.removeAllRanges()
    sel.addRange(range);
  },
  getNextQueryFromRegexMatches: function(step) {
    if (!this.regexMatches) { return ""; }
    var count = this.matchCount;
    this.activeRegexIndex = count = (this.activeRegexIndex + step + count) % count;
    return this.regexMatches[count];
  },
  getQuery: function(backwards) {
    var query = Settings.cache.findModeRawQuery;
    query === this.query || this.updateQuery(query);
    return this.isRegex ? this.getNextQueryFromRegexMatches(backwards ? -1 : 1) : this.parsedQuery;
  },
  execute: function(query, options) {
    options || (options = {});
    var el, found, count = options.count | 0, backwards = !!options.backwards, q;
    options.noColor || this.toggleStyle('add');
    do {
      q = query != null ? query : this.getQuery(backwards);
      found = window.find(q, options.caseSensitive || !this.ignoreCase, backwards, true, false, true, false);
    } while (0 < --count && found);
    options.noColor || setTimeout(this.bindSel.bind(this, "add", 0), 0);
    (el = VInsertMode.lock) && DomUtils.getEditableType(el) > 1 && !DomUtils.isSelected(document.activeElement) && el.blur();
    return this.hasResults = found;
  },
  RestoreHighlight: function() { VFindMode.toggleStyle('remove'); },
  bindSel: function(action) { document[action + "EventListener"]("selectionchange", this.RestoreHighlight, true); },
  toggleStyle: function(action) {
    this.bindSel("remove");
    document.documentElement.classList[action]("vimiumFindMode");
    action === "add" ? DomUtils.UI.addElement(this.styleIn) : this.styleIn.remove();
  },
  getCurrentRange: function() {
    var sel = window.getSelection(), range;
    if (sel.type == "None") {
      range = this.initialRange = document.createRange();
      range.setStart(document.body, 0);
      range.setEnd(document.body, 0);
    } else {
      sel.type == "Range" && sel.collapseToStart();
      this.initialRange = sel.getRangeAt(0);
    }
  }
};
<commit_msg>noop: change VFindMode's styles<commit_after>"use strict";
var VFindMode = {
  isActive: false,
  query: "",
  parsedQuery: "",
  isRegex: false,
  ignoreCase: false,
  hasResults: false,
  matchCount: 0,
  scrollX: 0,
  scrollY: 0,
  initialRange: null,
  activeRegexIndex: 0,
  regexMatches: null,
  box: null,
  input: null,
  countEl: null,
  styleIn: null,
  options: null,
  cssSel: "::selection{background:#ff9632;}",
  cssIFrame: '*{font:normal normal normal 12px "Helvetica Neue",Helvetica,Arial,sans-serif !important;\
height:14px;line-height:12px;margin:0;overflow-y:hidden;vertical-align:top;white-space:nowrap;cursor:default;}\
body{cursor:text;display:inline-block;padding:0 3px 0 1px;min-width:7px;}body *{cursor:text;display:inline;}body br{display:none;}',
  activate: function(count, options) {
    if (!document.head) { return false; }
    if (this.isActive) {
      this.input.focus();
      this.box.contentWindow.getSelection().selectAllChildren(this.input);
      return;
    }
    this.options = Object.setPrototypeOf(options || {}, null);
    this.scrollX = window.scrollX;
    this.scrollY = window.scrollY;
    this.parsedQuery = this.query = "";
    this.regexMatches = null;
    this.activeRegexIndex = 0;
    this.getCurrentRange();

    var el, wnd, doc;
    DomUtils.UI.addElement(el = this.box = DomUtils.createElement("iframe"));
    el.className = "R HUD";
    el.style.width = "0px";
    el.onmousedown = this.OnMousedown;
    wnd = el.contentWindow;
    wnd.onmousedown = this.OnMousedown;
    wnd.onkeydown = this.onKeydown.bind(this);
    doc = wnd.document;
    el = this.input = doc.body;
    el.contentEditable = "plaintext-only";
    el.oninput = this.onInput.bind(this);
    doc.documentElement.appendChild(this.countEl = doc.createElement("span"));

    el = DomUtils.UI.createStyle(this.cssIFrame, doc);
    doc.head.appendChild(el);
    doc.documentElement.insertBefore(new wnd.Text("/"), doc.body);

    this.init && this.init();
    DomUtils.UI.focus(this.input);
    this.isActive = true;
  },
  init: function() {
    var ref = this.postMode, UI = DomUtils.UI;
    ref.exit = ref.exit.bind(ref);
    this.styleIn = UI.createStyle(this.cssSel);
    UI.init && UI.init();
    UI.box.appendChild(UI.createStyle(".vimiumFindMode " + this.cssSel));
    this.init = null;
  },
  findAndFocus: function(count, backwards) {
    this.init && this.init();
    this.execute(null, {count: count, backwards: backwards});
    if (!this.hasResults) {
      VHUD.showForDuration("No matches for '" + this.query + "'", 1000);
      return;
    }
    this.focusFoundLink(window.getSelection().anchorNode);
    this.postMode.activate();
  },
  refocus: function() {
    this.checkReturnToViewPort();
    window.focus();
    var el = DomUtils.getSelectionFocusElement();
    el && el.focus();
    this.exit();
    return el;
  },
  exit: function() { // need keep @hasResults
    this.box.remove();
    this.box = this.input = this.countEl = this.options = null;
    this.styleIn.remove();
    this.parsedQuery = this.query = "";
    this.initialRange = this.regexMatches = null;
    this.matchCount = 0;
    this.isActive = false;
  },
  OnMousedown: function(event) { if (event.target !== VFindMode.input) { event.preventDefault(); VFindMode.input.focus(); } },
  onKeydown: function(event) {
    var i = event.keyCode, el, el2;
    i = event.altKey ? 0 : i === KeyCodes.enter ? (this.saveQuery(), 2)
      : (i === KeyCodes.backspace || i === KeyCodes.deleteKey) ? +!this.query.length
      : i === KeyCodes.esc && KeyboardUtils.isPlain(event) ? 3 : 0;
    if (!i) { return; }
    DomUtils.suppressEvent(event);
    el = this.refocus();
    if (i < 2 || !this.hasResults) { return; }
    if (i === 3 && this.styleIn.parentNode) {
      this.toggleStyle("remove");
      this.restoreSelection(true);
    }
    if (!el || el !== VInsertMode.lock) {
      el = window.getSelection().anchorNode;
      if (el && !this.focusFoundLink(el) && i === 3 && (el2 = document.activeElement)) {
        DomUtils.getEditableType(el2) === 3 && el.contains(el2) && DomUtils.UI.simulateSelect(el2);
      }
    }
    i === 2 && this.postMode.activate();
  },
  focusFoundLink: function(el) {
    for (; el && el !== document.body; el = el.parentElement) {
      if (el instanceof HTMLAnchorElement) {
        el.focus();
        return true;
      }
    }
  },
  saveQuery: function() {
    Settings.set("findModeRawQuery", this.query);
  },
  postMode: {
    lock: null,
    activate: function() {
      var el = VInsertMode.lock, Exit = this.exit;
      Exit();
      if (!el || DomUtils.getEditableType(el) < 2) { return; }
      // TODO: onblur won't be called on Vomnibar.input
      el.addEventListener("blur", Exit);
      this.lock = el;
      addEventListener("click", Exit, true);
      VInsertMode.setupSuppress(Exit);
      handlerStack.push(this.onKeydown, this);
    },
    onKeydown: function(event) {
      var exit = event.keyCode === KeyCodes.esc && KeyboardUtils.isPlain(event);
      exit ? this.exit() : handlerStack.remove(this);
      return 2 * exit;
    },
    exit: function() {
      if (!this.lock) { return; }
      this.lock.removeEventListener("blur", this.exit, true);
      this.lock = null;
      removeEventListener("click", this.exit, true);
      handlerStack.remove(this);
      VInsertMode.exitSuppress();
    }
  },
  onInput: function() {
    var query = this.input.textContent.replace('\xa0', " "), count;
    this.checkReturnToViewPort();
    this.updateQuery(query);
    this.restoreSelection();
    this.execute(!this.isRegex ? this.parsedQuery : this.regexMatches ? this.regexMatches[0] : "");
    count = this.matchCount;
    this.countEl.textContent = this.parsedQuery ? "(" + (count || (this.hasResults ? "Some" : "No")) + " match" + (count !== 1 ? "es)" : ")") : "";
    count = this.input.getBoundingClientRect().width + this.countEl.getBoundingClientRect().width;
    this.box.style.width = (count | 0) + 4 + "px";
    // TODO: prevent VInsertMode from locking
  },
  checkReturnToViewPort: function() {
    this.options.returnToViewport && window.scrollTo(this.scrollX, this.scrollY);
  },
  _ctrlRe: /(\\\\?)([rRI]?)/g,
  escapeAllRe: /[\$\(\)\*\+\.\?\[\\\]\^\{\|\}]/g,
  updateQuery: function(query) {
    this.query = query;
    this.isRegex = Settings.cache.regexFindMode;
    this.hasNoIgnoreCaseFlag = false;
    query = this.parsedQuery = query.replace(this._ctrlRe, this.FormatQuery);
    this.ignoreCase = !this.hasNoIgnoreCaseFlag && !/[A-Z]/.test(query);
    this.isRegex || (query = query.replace(this.escapeAllRe, "\\$&"));

    var re, matches;
    try {
      re = query && new RegExp(query, this.ignoreCase ? "g" : "gi");
    } catch (e) {}
    matches = re && (document.webkitFullscreenElement || document.documentElement).innerText.match(re);
    this.regexMatches = this.isRegex && matches || null;
    this.activeRegexIndex = 0;
    this.matchCount = matches ? matches.length : 0;
  },
  FormatQuery: function(match, slashes, flag) {
    if (!flag || slashes.length != 1) { return match; }
    if (flag === 'I') { VFindMode.hasNoIgnoreCaseFlag = true; }
    else { VFindMode.isRegex = flag === 'r'; }
    return "";
  },
  restoreSelection: function(isCur) {
    var sel = window.getSelection(), range;
    range = !isCur ? this.initialRange : sel.isCollapsed ? null : sel.getRangeAt(0);
    if (!range) { return; }
    sel.removeAllRanges()
    sel.addRange(range);
  },
  getNextQueryFromRegexMatches: function(step) {
    if (!this.regexMatches) { return ""; }
    var count = this.matchCount;
    this.activeRegexIndex = count = (this.activeRegexIndex + step + count) % count;
    return this.regexMatches[count];
  },
  getQuery: function(backwards) {
    var query = Settings.cache.findModeRawQuery;
    query === this.query || this.updateQuery(query);
    return this.isRegex ? this.getNextQueryFromRegexMatches(backwards ? -1 : 1) : this.parsedQuery;
  },
  execute: function(query, options) {
    options || (options = {});
    var el, found, count = options.count | 0, backwards = !!options.backwards, q;
    options.noColor || this.toggleStyle('add');
    do {
      q = query != null ? query : this.getQuery(backwards);
      found = window.find(q, options.caseSensitive || !this.ignoreCase, backwards, true, false, true, false);
    } while (0 < --count && found);
    options.noColor || setTimeout(this.bindSel.bind(this, "add", 0), 0);
    (el = VInsertMode.lock) && DomUtils.getEditableType(el) > 1 && !DomUtils.isSelected(document.activeElement) && el.blur();
    return this.hasResults = found;
  },
  RestoreHighlight: function() { VFindMode.toggleStyle('remove'); },
  bindSel: function(action) { document[action + "EventListener"]("selectionchange", this.RestoreHighlight, true); },
  toggleStyle: function(action) {
    this.bindSel("remove");
    document.documentElement.classList[action]("vimiumFindMode");
    action === "add" ? DomUtils.UI.addElement(this.styleIn) : this.styleIn.remove();
  },
  getCurrentRange: function() {
    var sel = window.getSelection(), range;
    if (sel.type == "None") {
      range = this.initialRange = document.createRange();
      range.setStart(document.body, 0);
      range.setEnd(document.body, 0);
    } else {
      sel.type == "Range" && sel.collapseToStart();
      this.initialRange = sel.getRangeAt(0);
    }
  }
};
<|endoftext|>


<commit_before>var TreeSvg = function () {
    var ts = Object.create(null);

    // the rendering radius of nodes
    var nodeRadius = 4.5;
    ts.setNodeRadius = function (r) {
        nodeRadius = r;
    };

    // parameters used by the layout
    var displayWidth = 600;
    var displayHeight = 400;

    // parameters used to make pretty curves in the edges
    var edgeTension = 0.4;

    // "padding" values on the row lines
    var rowPadding = 0.5;

    // label drawing assistance
    var drawLabels = true;
    var labelLength = 12;
    var TextPlacement = {
        "LEFT": -1,
        "RIGHT": 1
    };
    var labelStyle = {
        "LEFT": ' style="text-anchor:end;" ',
        "RIGHT": ' style="text-anchor:start;" '
    };
    var textPostSpacing = 0.33;

    // utility function to make points from pairs
    var point = function (x, y) { return { "x": x, "y": y }; };

    // layout base classes
    var linearLayout = function (include) {
        var ll = Object.create(include);

        ll.setup = function (treeWidth, treeDepth) {
            this.treeWidth = treeWidth;
            Object.getPrototypeOf(this).setup(treeWidth, treeDepth);
        };

        ll.drawRow = function (i) {
            var a = this.xy(point(-rowPadding, i));
            var b = this.xy(point(this.treeWidth + rowPadding, i));
            return '<line class="tree-svg-row" x1="' + a.x + '" y1="' + a.y + '" x2="' + b.x + '" y2="' + b.y + '" />';
        };

        return ll;
    };

    var radialLayout = function (include) {
        var rl = Object.create(include);

        rl.setup = function (treeWidth, treeDepth) {
            this.treeWidth = treeWidth;
            Object.getPrototypeOf(this).setup(treeWidth, treeDepth);
        };

        rl.drawRow = function (i) {
            var prototype = Object.getPrototypeOf(this);
            if (prototype.hasOwnProperty("drawRow")) {
                return prototype.drawRow(i);
            } else {
                var left = this.xy(point(-rowPadding, i));
                var right = this.xy(point(this.treeWidth + rowPadding, i));
                var r = i * this.yScale;
                return '<path d="M' + left.x + ',' + left.y + ' A' + r + ',' + r + ' 0 0,0 ' + right.x + ',' + right.y + '" class="tree-svg-row" />';
            }
        };

        rl.xy = function (xy) {
            var x = (xy.x * this.xScale) + this.zero;
            var y = xy.y * this.yScale;
            return point(this.c.x + (Math.cos(x) * y), this.c.y + (Math.sin(x) * y));
        };

        rl.textTransform = function (xy, leftOrRight) {
            var p = this.xy(xy);
            var angle = ((xy.x * this.xScale) + this.zero) * (180.0 / Math.PI);
            while (angle > 90) { angle -= 180; leftOrRight *= -1; }
            while (angle < -90) { angle += 180; leftOrRight *= -1; }
            var svg = (leftOrRight < 0) ? labelStyle.LEFT : labelStyle.RIGHT;
            svg += 'transform="rotate(' + angle + ', ' + p.x + ', ' + p.y + ') translate(' + (leftOrRight * nodeRadius * 1.5) + ', 0)"';
            return svg;
        };

        return rl;
    };

    // various layouts supported by the tree renderer
    var layouts = {
        "Linear-Vertical": linearLayout({
            "setup": function (treeWidth, treeDepth) {
                this.xScale = displayWidth / treeWidth;
                this.yScale = displayHeight / (treeDepth + textPostSpacing);
            },
            "xy": function (xy) {
                return point(xy.x * this.xScale, xy.y * this.yScale);
            },
            "textTransform": function (xy, leftOrRight) {
                var p = this.xy(xy);
                var svg = (leftOrRight == TextPlacement.LEFT) ? labelStyle.LEFT : labelStyle.RIGHT;
                svg += 'transform="rotate(90, ' + p.x + ', ' + p.y + ') translate(' + (leftOrRight * nodeRadius * 1.5) + ', 0)"';
                return svg;
            }
        }),
        "Linear-Horizontal": linearLayout({
            "setup": function (treeWidth, treeDepth) {
                this.xScale = displayWidth / (treeDepth + textPostSpacing);
                this.yScale = displayHeight / treeWidth;
            },
            "xy": function (xy) {
                return point(xy.y * this.xScale, displayHeight - (xy.x * this.yScale));
            },
            "textTransform": function (xy, leftOrRight) {
                var svg = (leftOrRight == TextPlacement.LEFT) ? labelStyle.LEFT : labelStyle.RIGHT;
                svg += 'transform="translate(' + (leftOrRight * nodeRadius * 1.5) + ', 0)"';
                return svg;
            }
        }),
        "Radial": radialLayout({
            "setup": function (treeWidth, treeDepth) {
                this.zero = 0.0;
                this.xScale = (Math.PI * -2.0) / (treeWidth + 1);
                this.yScale = (displayHeight * 0.5) / (treeDepth + textPostSpacing);
                this.c = point(displayWidth * 0.5, displayHeight * 0.5);
            },
            "drawRow": function (i) {
                var r = i * this.yScale;
                return '<circle cx="' + this.c.x + '" cy="' + this.c.y + '" r="' + r + '" class="tree-svg-row" />';
            }
        }),
        "Arc-Vertical": radialLayout({
            "setup": function (treeWidth, treeDepth) {
                var angle = Math.asin((displayWidth * 0.5) / displayHeight) * 2.0;
                this.zero = Math.PI - ((Math.PI - angle) / 2.0);
                this.xScale = -angle / treeWidth;
                this.yScale = displayHeight / (treeDepth + textPostSpacing);
                this.c = point(displayWidth * 0.5, 0.0);
            }
        }),
        "Arc-Horizontal": radialLayout({
            "setup": function (treeWidth, treeDepth) {
                var angle = Math.asin((displayHeight * 0.5) / displayWidth) * 2.0;
                this.zero = angle / 2.0;
                this.xScale = -angle / treeWidth;
                this.yScale = displayWidth / (treeDepth + textPostSpacing);
                this.c = point(0.0, displayHeight * 0.5);
            }
        })
    };

    // functions to get a list of available layout names
    ts.getLayouts = function () {
        var layoutNames = [];
        for (var layoutName in layouts) {
            if (layouts.hasOwnProperty(layoutName)) {
                layoutNames.push(layoutName);
            }
        }
        layoutNames.sort();
        return layoutNames;
    };

    // render with an adapter (an object that links externally defined values
    // to the display characteristics of the node)
    ts.renderSvg = function (root, layoutName, adapter) {
        // create the raw SVG picture for display, assumes a width/height aspect ratio of 3/2
        var svg = '
';
        svg += '<svg class="tree-svg-svg" xmlns="http://www.w3.org/2000/svg" version="1.1" ';

        // compute the viewbox from the desired size with a bit of buffer
        var buffer = 0.1;
        var l, t, w, h;
        if (displayWidth > displayHeight) {
            var ratio = displayWidth / displayHeight;
            t = -buffer * displayHeight;
            l = t * ratio;
            h = displayHeight * (1.0 + (buffer * 2.0));
            w = h * ratio;
        } else {
            var ratio = displayHeight / displayWidth;
            l = -buffer * displayWidth;
            t = l * ratio;
            w = displayWidth * (1.0 + (buffer * 2.0));
            h = w * ratio;
        }
        svg += 'viewBox="' + l + ', ' + t + ', ' + w + ', ' + h + '" ';
        svg += 'preserveAspectRatio="xMidYMid meet"';
        svg += '>';

        // recursive depth check
        var recursiveDepthCheck = function (depth, container) {
            container.depth = depth;
            var nextDepth = depth + 1;
            for (var i = 0, childCount = container.children.length; i < childCount; ++i) {
                recursiveDepthCheck(nextDepth, container.children[i]);
            }
        };
        recursiveDepthCheck(0, root);

        // function to see if we should traverse further in the tree
        var getShowChildren = function (container) {
            return (container.children.length == 0) || container.expanded;
        }

        // recursive layout in uniform scale space
        var depth = 1;
        var recursiveLayout = function (x, y, container) {
            var childX = x;
            if (getShowChildren(container)) {
                var childCount = container.children.length;
                if (childCount > 0) {
                    var nextY = y + 1;
                    childX = recursiveLayout(x, nextY, container.children[0]);
                    for (var i = 1; i < childCount; ++i) {
                        childX = recursiveLayout(childX + 1, nextY, container.children[i]);
                    }
                }
            }

            // compute layout
            if (container.node != null) {
                container.x = (x + childX) / 2.0;
                container.y = y;
            }
            depth = Math.max(depth, y);
            return childX;
        };
        var width = recursiveLayout(0, (root.node == null) ? -1 : 0, root);

        // setup the layout object with the computed tree properties
        var layout = (layoutName in layouts) ? layouts[layoutName] : layouts["Linear-Vertical"];
        layout.setup(width, depth);

        // draw the rows
        for (var i = 0; i <= depth; ++i) {
            svg += layout.drawRow(i);
        }

        // draw the edges, cubic bezier style
        var interpolate = function (a, b, i) { return (a * i) + (b * (1.0 - i)); };
        var recursiveDrawEdges = function (container) {
            if (getShowChildren(container)) {
                for (var i = 0, childCount = container.children.length; i < childCount; ++i) {
                    var child = container.children[i];
                    recursiveDrawEdges(child);
                    if (container.node != null) {
                        var c1 = point(container.x, interpolate(child.y, container.y, edgeTension));
                        var c2 = point(child.x, interpolate(container.y, child.y, edgeTension));
                        var f = layout.xy(container), t = layout.xy(child), m1 = layout.xy(c1), m2 = layout.xy(c2);
                        svg += '<path class="tree-svg-edge" ';
                        svg += 'd="M' + f.x + ',' + f.y + ' C' + m1.x + ',' + m1.y + ' ' + m2.x + ',' + m2.y + ' ' + t.x + ',' + t.y + '" ';
                        svg += '/>';
                    }
                }
            }
        };
        recursiveDrawEdges(root);

        // draw the nodes
        var recursiveDrawNodes = function (container) {
            if (getShowChildren(container)) {
                for (var i = 0, childCount = container.children.length; i < childCount; ++i) {
                    recursiveDrawNodes(container.children[i]);
                }
            }
            if (container.node != null) {
                var title = adapter.getTitle(container);

                // create an SVG group, with a click handler, note that the
                // browsers all handle this differently (of course) - so we
                // go with the W3C way, and only handle click events
                svg += '<g onclick="onTreeClick({ id:' + container.id + ', event:evt });">';

                // add a node as a circle
                svg += '<circle title="' + title + '" ';
                var p = layout.xy(container);
                svg += 'cx="' + p.x + '" cy="' + p.y + '" r="' + nodeRadius + '" ';
                svg += 'class="' + (getShowChildren(container) ? 'tree-svg-node' : 'tree-svg-node-expandable') + '" ';

                // this will override the class definition if fill was not
                // *EVER*specified - useful for programmatic control
                svg += 'fill="' + adapter.getColor(container) + '" ';
                svg += '/>';

                // add the text description of the node
                if (drawLabels) {
                    svg += '<text x="' + p.x + '" y="' + p.y + '" ';
                    svg += 'class="tree-svg-node-title" '
                    if ((container.children.length == 0) || (!container.expanded)) {
                        svg += layout.textTransform(container, TextPlacement.RIGHT) + ' ';
                    } else {
                        svg += layout.textTransform(container, TextPlacement.LEFT) + ' ';
                    }

                    // trim the title to a displayable length
                    if (title.length > labelLength) {
                        title = title.substring(0, labelLength - 1) + "…";
                    }
                    svg += '><tspan dy="0.25em">' + title + '</tspan></text>';
                }

                // close the SVG group
                svg += '</g>';
            }
        };
        recursiveDrawNodes(root);

        // close the plot
        svg += "

";
        return svg;
    };

    ts.getDefaultAdapter = function () {
        return {
            getTitle: function (container) { return "" + container.id; },
            getColor: function (container) { return "red"; }
        };
    };

    return ts;
}();
<commit_msg>slight update to text placement<commit_after>var TreeSvg = function () {
    var ts = Object.create(null);

    // the rendering radius of nodes
    var nodeRadius = 4.5;
    ts.setNodeRadius = function (r) {
        nodeRadius = r;
    };

    // parameters used by the layout
    var displayWidth = 600;
    var displayHeight = 400;

    // parameters used to make pretty curves in the edges
    var edgeTension = 0.4;

    // "padding" values on the row lines
    var rowPadding = 0.5;

    // label drawing assistance
    var drawLabels = true;
    var labelLength = 12;
    var TextPlacement = {
        "LEFT": -1,
        "RIGHT": 1
    };
    var labelStyle = {
        "LEFT": ' style="text-anchor:end;" ',
        "RIGHT": ' style="text-anchor:start;" '
    };
    var textPostSpacing = 0.33;

    // utility function to make points from pairs
    var point = function (x, y) { return { "x": x, "y": y }; };

    // layout base classes
    var linearLayout = function (include) {
        var ll = Object.create(include);

        ll.setup = function (treeWidth, treeDepth) {
            this.treeWidth = treeWidth;
            Object.getPrototypeOf(this).setup(treeWidth, treeDepth);
        };

        ll.drawRow = function (i) {
            var a = this.xy(point(-rowPadding, i));
            var b = this.xy(point(this.treeWidth + rowPadding, i));
            return '<line class="tree-svg-row" x1="' + a.x + '" y1="' + a.y + '" x2="' + b.x + '" y2="' + b.y + '" />';
        };

        return ll;
    };

    var radialLayout = function (include) {
        var rl = Object.create(include);

        rl.setup = function (treeWidth, treeDepth) {
            this.treeWidth = treeWidth;
            Object.getPrototypeOf(this).setup(treeWidth, treeDepth);
        };

        rl.drawRow = function (i) {
            var prototype = Object.getPrototypeOf(this);
            if (prototype.hasOwnProperty("drawRow")) {
                return prototype.drawRow(i);
            } else {
                var left = this.xy(point(-rowPadding, i));
                var right = this.xy(point(this.treeWidth + rowPadding, i));
                var r = i * this.yScale;
                return '<path d="M' + left.x + ',' + left.y + ' A' + r + ',' + r + ' 0 0,0 ' + right.x + ',' + right.y + '" class="tree-svg-row" />';
            }
        };

        rl.xy = function (xy) {
            var x = (xy.x * this.xScale) + this.zero;
            var y = xy.y * this.yScale;
            return point(this.c.x + (Math.cos(x) * y), this.c.y + (Math.sin(x) * y));
        };

        rl.textTransform = function (xy, leftOrRight) {
            var p = this.xy(xy);
            var angle = ((xy.x * this.xScale) + this.zero) * (180.0 / Math.PI);
            while (angle > 90) { angle -= 180; leftOrRight *= -1; }
            while (angle < -90) { angle += 180; leftOrRight *= -1; }
            var svg = (leftOrRight < 0) ? labelStyle.LEFT : labelStyle.RIGHT;
            svg += 'transform="rotate(' + angle + ', ' + p.x + ', ' + p.y + ') translate(' + (leftOrRight * nodeRadius * 1.5) + ', 0)"';
            return svg;
        };

        return rl;
    };

    // various layouts supported by the tree renderer
    var layouts = {
        "Linear-Vertical": linearLayout({
            "setup": function (treeWidth, treeDepth) {
                this.xScale = displayWidth / treeWidth;
                this.yScale = displayHeight / (treeDepth + textPostSpacing);
            },
            "xy": function (xy) {
                return point(xy.x * this.xScale, xy.y * this.yScale);
            },
            "textTransform": function (xy, leftOrRight) {
                var p = this.xy(xy);
                var svg = (leftOrRight == TextPlacement.LEFT) ? labelStyle.LEFT : labelStyle.RIGHT;
                svg += 'transform="rotate(90, ' + p.x + ', ' + p.y + ') translate(' + (leftOrRight * nodeRadius * 1.5) + ', 0)"';
                return svg;
            }
        }),
        "Linear-Horizontal": linearLayout({
            "setup": function (treeWidth, treeDepth) {
                this.xScale = displayWidth / (treeDepth + textPostSpacing);
                this.yScale = displayHeight / treeWidth;
            },
            "xy": function (xy) {
                return point(xy.y * this.xScale, displayHeight - (xy.x * this.yScale));
            },
            "textTransform": function (xy, leftOrRight) {
                var svg = (leftOrRight == TextPlacement.LEFT) ? labelStyle.LEFT : labelStyle.RIGHT;
                svg += 'transform="translate(' + (leftOrRight * nodeRadius * 1.5) + ', 0)"';
                return svg;
            }
        }),
        "Radial": radialLayout({
            "setup": function (treeWidth, treeDepth) {
                this.zero = 0.0;
                this.xScale = (Math.PI * -2.0) / (treeWidth + 1);
                this.yScale = (displayHeight * 0.5) / (treeDepth + textPostSpacing);
                this.c = point(displayWidth * 0.5, displayHeight * 0.5);
            },
            "drawRow": function (i) {
                var r = i * this.yScale;
                return '<circle cx="' + this.c.x + '" cy="' + this.c.y + '" r="' + r + '" class="tree-svg-row" />';
            }
        }),
        "Arc-Vertical": radialLayout({
            "setup": function (treeWidth, treeDepth) {
                var angle = Math.asin((displayWidth * 0.5) / displayHeight) * 2.0;
                this.zero = Math.PI - ((Math.PI - angle) / 2.0);
                this.xScale = -angle / treeWidth;
                this.yScale = displayHeight / (treeDepth + textPostSpacing);
                this.c = point(displayWidth * 0.5, 0.0);
            }
        }),
        "Arc-Horizontal": radialLayout({
            "setup": function (treeWidth, treeDepth) {
                var angle = Math.asin((displayHeight * 0.5) / displayWidth) * 2.0;
                this.zero = angle / 2.0;
                this.xScale = -angle / treeWidth;
                this.yScale = displayWidth / (treeDepth + textPostSpacing);
                this.c = point(0.0, displayHeight * 0.5);
            }
        })
    };

    // functions to get a list of available layout names
    ts.getLayouts = function () {
        var layoutNames = [];
        for (var layoutName in layouts) {
            if (layouts.hasOwnProperty(layoutName)) {
                layoutNames.push(layoutName);
            }
        }
        layoutNames.sort();
        return layoutNames;
    };

    // render with an adapter (an object that links externally defined values
    // to the display characteristics of the node)
    ts.renderSvg = function (root, layoutName, adapter) {
        // create the raw SVG picture for display, assumes a width/height aspect ratio of 3/2
        var svg = '
';
        svg += '<svg class="tree-svg-svg" xmlns="http://www.w3.org/2000/svg" version="1.1" ';

        // compute the viewbox from the desired size with a bit of buffer
        var buffer = 0.1;
        var l, t, w, h;
        if (displayWidth > displayHeight) {
            var ratio = displayWidth / displayHeight;
            t = -buffer * displayHeight;
            l = t * ratio;
            h = displayHeight * (1.0 + (buffer * 2.0));
            w = h * ratio;
        } else {
            var ratio = displayHeight / displayWidth;
            l = -buffer * displayWidth;
            t = l * ratio;
            w = displayWidth * (1.0 + (buffer * 2.0));
            h = w * ratio;
        }
        svg += 'viewBox="' + l + ', ' + t + ', ' + w + ', ' + h + '" ';
        svg += 'preserveAspectRatio="xMidYMid meet"';
        svg += '>';

        // recursive depth check
        var recursiveDepthCheck = function (depth, container) {
            container.depth = depth;
            var nextDepth = depth + 1;
            for (var i = 0, childCount = container.children.length; i < childCount; ++i) {
                recursiveDepthCheck(nextDepth, container.children[i]);
            }
        };
        recursiveDepthCheck(0, root);

        // function to see if we should traverse further in the tree
        var getShowChildren = function (container) {
            return (container.children.length == 0) || container.expanded;
        }

        // recursive layout in uniform scale space
        var depth = 1;
        var recursiveLayout = function (x, y, container) {
            var childX = x;
            if (getShowChildren(container)) {
                var childCount = container.children.length;
                if (childCount > 0) {
                    var nextY = y + 1;
                    childX = recursiveLayout(x, nextY, container.children[0]);
                    for (var i = 1; i < childCount; ++i) {
                        childX = recursiveLayout(childX + 1, nextY, container.children[i]);
                    }
                }
            }

            // compute layout
            if (container.node != null) {
                container.x = (x + childX) / 2.0;
                container.y = y;
            }
            depth = Math.max(depth, y);
            return childX;
        };
        var width = recursiveLayout(0, (root.node == null) ? -1 : 0, root);

        // setup the layout object with the computed tree properties
        var layout = (layoutName in layouts) ? layouts[layoutName] : layouts["Linear-Vertical"];
        layout.setup(width, depth);

        // draw the rows
        for (var i = 0; i <= depth; ++i) {
            svg += layout.drawRow(i);
        }

        // draw the edges, cubic bezier style
        var interpolate = function (a, b, i) { return (a * i) + (b * (1.0 - i)); };
        var recursiveDrawEdges = function (container) {
            if (getShowChildren(container)) {
                for (var i = 0, childCount = container.children.length; i < childCount; ++i) {
                    var child = container.children[i];
                    recursiveDrawEdges(child);
                    if (container.node != null) {
                        var c1 = point(container.x, interpolate(child.y, container.y, edgeTension));
                        var c2 = point(child.x, interpolate(container.y, child.y, edgeTension));
                        var f = layout.xy(container), t = layout.xy(child), m1 = layout.xy(c1), m2 = layout.xy(c2);
                        svg += '<path class="tree-svg-edge" ';
                        svg += 'd="M' + f.x + ',' + f.y + ' C' + m1.x + ',' + m1.y + ' ' + m2.x + ',' + m2.y + ' ' + t.x + ',' + t.y + '" ';
                        svg += '/>';
                    }
                }
            }
        };
        recursiveDrawEdges(root);

        // draw the nodes
        var recursiveDrawNodes = function (container) {
            if (getShowChildren(container)) {
                for (var i = 0, childCount = container.children.length; i < childCount; ++i) {
                    recursiveDrawNodes(container.children[i]);
                }
            }
            if (container.node != null) {
                var title = adapter.getTitle(container);

                // create an SVG group, with a click handler, note that the
                // browsers all handle this differently (of course) - so we
                // go with the W3C way, and only handle click events
                svg += '<g onclick="onTreeClick({ id:' + container.id + ', event:evt });">';

                // add a node as a circle
                svg += '<circle title="' + title + '" ';
                var p = layout.xy(container);
                svg += 'cx="' + p.x + '" cy="' + p.y + '" r="' + nodeRadius + '" ';
                svg += 'class="' + (getShowChildren(container) ? 'tree-svg-node' : 'tree-svg-node-expandable') + '" ';

                // this will override the class definition if fill was not
                // *EVER*specified - useful for programmatic control
                svg += 'fill="' + adapter.getColor(container) + '" ';
                svg += '/>';

                // add the text description of the node
                if (drawLabels) {
                    svg += '<text x="' + p.x + '" y="' + p.y + '" ';
                    svg += 'class="tree-svg-node-title" '
                    if ((container.children.length == 0) || (!container.expanded)) {
                        svg += layout.textTransform(container, TextPlacement.RIGHT) + ' ';
                    } else {
                        svg += layout.textTransform(container, TextPlacement.LEFT) + ' ';
                    }

                    // trim the title to a displayable length
                    if (title.length > labelLength) {
                        title = title.substring(0, labelLength - 1) + "…";
                    }
                    svg += '><tspan dy="0.33em">' + title + '</tspan></text>';
                }

                // close the SVG group
                svg += '</g>';
            }
        };
        recursiveDrawNodes(root);

        // close the plot
        svg += "

";
        return svg;
    };

    ts.getDefaultAdapter = function () {
        return {
            getTitle: function (container) { return "" + container.id; },
            getColor: function (container) { return "red"; }
        };
    };

    return ts;
}();
<|endoftext|>


<commit_before>/* eslint-disable arrow-parens */
/* eslint-disable react/jsx-indent */
/* eslint-disable indent */
/* eslint-disable quote-props */
/* eslint-disable no-var */
/* eslint-disable prefer-template */
/* eslint-disable no-mixed-operators */
/* eslint-disable vars-on-top */
/* eslint-disable prefer-arrow-callback */
/* eslint-disable no-return-assign */
/* eslint-disable no-console */
/* eslint-disable no-plusplus */

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';

/**
 * COMPONENT
 */

class DataVisWordCloud extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  componentDidMount() {
    this.createBubbles(this.createBubbleStructure(this.props));
  }

  componentWillReceiveProps(nextProps) {
    this.createBubbles(this.createBubbleStructure(nextProps));
  }

  createBubbleStructure(data) {
    let level1Words = [];
    let level2Words = [];
    let level3Words = [];
    let level4Words = [];
    let level5Words = [];
    let level6Words = [];
    let level7Words = [];
    let level8Words = [];
    let level9Words = [];
    let level10Words = [];

    var rootWords = Object.entries(data.userWords);
    rootWords.forEach(function (word) {
      if (word[1].level === 1) {
        level1Words.push({ "name": word[0], "size": word[1].numUsed });
      } else if (word[1].level === 2) {
        level2Words.push({ "name": word[0], "size": word[1].numUsed });
      } else if (word[1].level === 3) {
        level3Words.push({ "name": word[0], "size": word[1].numUsed });
      } else if (word[1].level === 4) {
        level4Words.push({ "name": word[0], "size": word[1].numUsed });
      } else if (word[1].level === 5) {
        level5Words.push({ "name": word[0], "size": word[1].numUsed });
      } else if (word[1].level === 6) {
        level6Words.push({ "name": word[0], "size": word[1].numUsed });
      } else if (word[1].level === 7) {
        level7Words.push({ "name": word[0], "size": word[1].numUsed });
      } else if (word[1].level === 8) {
        level8Words.push({ "name": word[0], "size": word[1].numUsed });
      } else if (word[1].level === 9) {
        level9Words.push({ "name": word[0], "size": word[1].numUsed });
      } else if (word[1].level === 10) {
        level10Words.push({ "name": word[0], "size": word[1].numUsed });
      }
    });

    const childrenWords = [];
    if (!level1Words.length) level1Words = [{ "name": "You have not used any words from level 1 yet!", "size": 10 }];
    if (!level2Words.length) level2Words = [{ "name": "You have not used any words from level 2 yet!", "size": 10 }];
    if (!level3Words.length) level3Words = [{ "name": "You have not used any words from level 3 yet!", "size": 10 }];
    if (!level4Words.length) level4Words = [{ "name": "You have not used any words from level 4 yet!", "size": 10 }];
    if (!level5Words.length) level5Words = [{ "name": "You have not used any words from level 5 yet!", "size": 10 }];
    if (!level6Words.length) level6Words = [{ "name": "You have not used any words from level 6 yet!", "size": 10 }];
    if (!level7Words.length) level7Words = [{ "name": "You have not used any words from level 7 yet!", "size": 10 }];
    if (!level8Words.length) level8Words = [{ "name": "You have not used any words from level 8 yet!", "size": 10 }];
    if (!level9Words.length) level9Words = [{ "name": "You have not used any words from level 9 yet!", "size": 10 }];
    if (!level10Words.length) level10Words = [{ "name": "You have not used any words from level 10 yet!", "size": 10 }];
    childrenWords.push({ "name": "Level 1", "children": level1Words }, { "name": "Level 2", "children": level2Words }, { "name": "Level 3", "children": level3Words }, { "name": "Level 4", "children": level4Words }, { "name": "Level 5", "children": level5Words }, { "name": "Level 6", "children": level6Words }, { "name": "Level 7", "children": level7Words }, { "name": "Level 8", "children": level8Words }, { "name": "Level 9", "children": level9Words }, { "name": "Level 10", "children": level10Words });

    const root = {
      "name": "wordCloud",
      "children": childrenWords,
    };
    return root;
  }

  createBubbles(rootParam) {
    console.log(this.props.userWords);
    var svg = d3.select(this.svgRoot),
      margin = 20,
      diameter = +svg.attr("width"),
      g = svg.append("g").attr("transform", "translate(" + diameter / 2 + "," + diameter / 2 + ")");

    var color = d3.scaleLinear()
      .domain([-1, 2])
      .range(["hsl(0, 0%, 91%)", "hsl(259, 100%, 20%)"])
      .interpolate(d3.interpolateHcl);

    var pack = d3.pack()
      .size([diameter - margin, diameter - margin])
      .padding(2);

    var root = rootParam || {
      "name": "wordCloud",
      "children": [
        {
          "name": "Level 1",
          "size": 100,
        },
        {
          "name": "Level 2",
          "size": 100,
        },
        {
          "name": "Level 3",
          "size": 100,
        },
        {
          "name": "Level 4",
          "size": 100,
        },
        {
          "name": "Level 5",
          "size": 100,
        },
        {
          "name": "Level 6",
          "size": 100,
        },
        {
          "name": "Level 7",
          "size": 100,
        },
        {
          "name": "Level 8",
          "size": 100,
        },
        {
          "name": "Level 9",
          "size": 100,
        },
        {
          "name": "Level 10",
          "size": 100,
        },
      ],
    };

    root = d3.hierarchy(root)
      .sum(function (d) { return d.size; })
      .sort(function (a, b) { return b.value - a.value; });

    var focus = root,
      nodes = pack(root).descendants(),
      view;

    var circle = g.selectAll("circle")
      .data(nodes)
      .enter().append("circle")
      .attr("class", function (d) { return d.parent ? d.children ? "node" : "node node--leaf" : "node node--root"; })
      .style("fill", function (d) { return d.children ? color(d.depth) : null; })
      .on("click", function (d) { if (focus !== d) zoom(d), d3.event.stopPropagation(); });

    var text = g.selectAll("text")
      .data(nodes)
      .enter().append("text")
      .attr("class", "label")
      .style("fill-opacity", function (d) { return d.parent === root ? 1 : 0; })
      .style("display", function (d) { return d.parent === root ? "inline" : "none"; })
      .text(function (d) { return d.data.name; });

    var node = g.selectAll("circle,text");

    svg
      .style("background", color(-1))
      .on("click", function () { zoom(root); });

    zoomTo([root.x, root.y, root.r * 2 + margin]);

    function zoom(d) {
      var focus0 = focus; focus = d;

      var transition = d3.transition()
        .duration(d3.event.altKey ? 7500 : 750)
        .tween("zoom", function (d) {
          var i = d3.interpolateZoom(view, [focus.x, focus.y, focus.r * 2 + margin]);
          return function (t) { zoomTo(i(t)); };
        });

      transition.selectAll("text")
        .filter(function (d) { return d.parent === focus || this.style.display === "inline"; })
        .style("fill-opacity", function (d) { return d.parent === focus ? 1 : 0; })
        .on("start", function (d) { if (d.parent === focus) this.style.display = "inline"; })
        .on("end", function (d) { if (d.parent !== focus) this.style.display = "none"; });
    }

    function zoomTo(v) {
      var k = diameter / v[2]; view = v;
      node.attr("transform", function (d) { return "translate(" + (d.x - v[0]) * k + "," + (d.y - v[1]) * k + ")"; });
      circle.attr("r", function (d) { return d.r * k; });
    }
  }

  render() {
    console.log(this.props.userWords);
    return (
      <svg
        width="900"
        height="900"
        ref={svg => this.svgRoot = svg}
      />
    );
  }
}

/**
 * CONTAINER
 */
const mapState = (state) => {
  return {
    userWords: state.userWords,
  };
};

const mapDispatch = (dispatch) => {
  return {};
};

export default withRouter(connect(mapState, mapDispatch)(DataVisWordCloud));

/**
 * PROP TYPES
 */
DataVisWordCloud.propTypes = {
  userWords: PropTypes.object.isRequired,
};<commit_msg>Remove console log statements<commit_after>/* eslint-disable arrow-parens */
/* eslint-disable react/jsx-indent */
/* eslint-disable indent */
/* eslint-disable quote-props */
/* eslint-disable no-var */
/* eslint-disable prefer-template */
/* eslint-disable no-mixed-operators */
/* eslint-disable vars-on-top */
/* eslint-disable prefer-arrow-callback */
/* eslint-disable no-return-assign */
/* eslint-disable no-console */
/* eslint-disable no-plusplus */

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';

/**
 * COMPONENT
 */

class DataVisWordCloud extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  componentDidMount() {
    this.createBubbles(this.createBubbleStructure(this.props));
  }

  componentWillReceiveProps(nextProps) {
    this.createBubbles(this.createBubbleStructure(nextProps));
  }

  createBubbleStructure(data) {
    let level1Words = [];
    let level2Words = [];
    let level3Words = [];
    let level4Words = [];
    let level5Words = [];
    let level6Words = [];
    let level7Words = [];
    let level8Words = [];
    let level9Words = [];
    let level10Words = [];

    var rootWords = Object.entries(data.userWords);
    rootWords.forEach(function (word) {
      if (word[1].level === 1) {
        level1Words.push({ "name": word[0], "size": word[1].numUsed });
      } else if (word[1].level === 2) {
        level2Words.push({ "name": word[0], "size": word[1].numUsed });
      } else if (word[1].level === 3) {
        level3Words.push({ "name": word[0], "size": word[1].numUsed });
      } else if (word[1].level === 4) {
        level4Words.push({ "name": word[0], "size": word[1].numUsed });
      } else if (word[1].level === 5) {
        level5Words.push({ "name": word[0], "size": word[1].numUsed });
      } else if (word[1].level === 6) {
        level6Words.push({ "name": word[0], "size": word[1].numUsed });
      } else if (word[1].level === 7) {
        level7Words.push({ "name": word[0], "size": word[1].numUsed });
      } else if (word[1].level === 8) {
        level8Words.push({ "name": word[0], "size": word[1].numUsed });
      } else if (word[1].level === 9) {
        level9Words.push({ "name": word[0], "size": word[1].numUsed });
      } else if (word[1].level === 10) {
        level10Words.push({ "name": word[0], "size": word[1].numUsed });
      }
    });

    const childrenWords = [];
    if (!level1Words.length) level1Words = [{ "name": "You have not used any words from level 1 yet!", "size": 10 }];
    if (!level2Words.length) level2Words = [{ "name": "You have not used any words from level 2 yet!", "size": 10 }];
    if (!level3Words.length) level3Words = [{ "name": "You have not used any words from level 3 yet!", "size": 10 }];
    if (!level4Words.length) level4Words = [{ "name": "You have not used any words from level 4 yet!", "size": 10 }];
    if (!level5Words.length) level5Words = [{ "name": "You have not used any words from level 5 yet!", "size": 10 }];
    if (!level6Words.length) level6Words = [{ "name": "You have not used any words from level 6 yet!", "size": 10 }];
    if (!level7Words.length) level7Words = [{ "name": "You have not used any words from level 7 yet!", "size": 10 }];
    if (!level8Words.length) level8Words = [{ "name": "You have not used any words from level 8 yet!", "size": 10 }];
    if (!level9Words.length) level9Words = [{ "name": "You have not used any words from level 9 yet!", "size": 10 }];
    if (!level10Words.length) level10Words = [{ "name": "You have not used any words from level 10 yet!", "size": 10 }];
    childrenWords.push({ "name": "Level 1", "children": level1Words }, { "name": "Level 2", "children": level2Words }, { "name": "Level 3", "children": level3Words }, { "name": "Level 4", "children": level4Words }, { "name": "Level 5", "children": level5Words }, { "name": "Level 6", "children": level6Words }, { "name": "Level 7", "children": level7Words }, { "name": "Level 8", "children": level8Words }, { "name": "Level 9", "children": level9Words }, { "name": "Level 10", "children": level10Words });

    const root = {
      "name": "wordCloud",
      "children": childrenWords,
    };
    return root;
  }

  createBubbles(rootParam) {
    var svg = d3.select(this.svgRoot),
      margin = 20,
      diameter = +svg.attr("width"),
      g = svg.append("g").attr("transform", "translate(" + diameter / 2 + "," + diameter / 2 + ")");

    var color = d3.scaleLinear()
      .domain([-1, 2])
      .range(["hsl(0, 0%, 91%)", "hsl(259, 100%, 20%)"])
      .interpolate(d3.interpolateHcl);

    var pack = d3.pack()
      .size([diameter - margin, diameter - margin])
      .padding(2);

    var root = rootParam || {
      "name": "wordCloud",
      "children": [
        {
          "name": "Level 1",
          "size": 100,
        },
        {
          "name": "Level 2",
          "size": 100,
        },
        {
          "name": "Level 3",
          "size": 100,
        },
        {
          "name": "Level 4",
          "size": 100,
        },
        {
          "name": "Level 5",
          "size": 100,
        },
        {
          "name": "Level 6",
          "size": 100,
        },
        {
          "name": "Level 7",
          "size": 100,
        },
        {
          "name": "Level 8",
          "size": 100,
        },
        {
          "name": "Level 9",
          "size": 100,
        },
        {
          "name": "Level 10",
          "size": 100,
        },
      ],
    };

    root = d3.hierarchy(root)
      .sum(function (d) { return d.size; })
      .sort(function (a, b) { return b.value - a.value; });

    var focus = root,
      nodes = pack(root).descendants(),
      view;

    var circle = g.selectAll("circle")
      .data(nodes)
      .enter().append("circle")
      .attr("class", function (d) { return d.parent ? d.children ? "node" : "node node--leaf" : "node node--root"; })
      .style("fill", function (d) { return d.children ? color(d.depth) : null; })
      .on("click", function (d) { if (focus !== d) zoom(d), d3.event.stopPropagation(); });

    var text = g.selectAll("text")
      .data(nodes)
      .enter().append("text")
      .attr("class", "label")
      .style("fill-opacity", function (d) { return d.parent === root ? 1 : 0; })
      .style("display", function (d) { return d.parent === root ? "inline" : "none"; })
      .text(function (d) { return d.data.name; });

    var node = g.selectAll("circle,text");

    svg
      .style("background", color(-1))
      .on("click", function () { zoom(root); });

    zoomTo([root.x, root.y, root.r * 2 + margin]);

    function zoom(d) {
      var focus0 = focus; focus = d;

      var transition = d3.transition()
        .duration(d3.event.altKey ? 7500 : 750)
        .tween("zoom", function (d) {
          var i = d3.interpolateZoom(view, [focus.x, focus.y, focus.r * 2 + margin]);
          return function (t) { zoomTo(i(t)); };
        });

      transition.selectAll("text")
        .filter(function (d) { return d.parent === focus || this.style.display === "inline"; })
        .style("fill-opacity", function (d) { return d.parent === focus ? 1 : 0; })
        .on("start", function (d) { if (d.parent === focus) this.style.display = "inline"; })
        .on("end", function (d) { if (d.parent !== focus) this.style.display = "none"; });
    }

    function zoomTo(v) {
      var k = diameter / v[2]; view = v;
      node.attr("transform", function (d) { return "translate(" + (d.x - v[0]) * k + "," + (d.y - v[1]) * k + ")"; });
      circle.attr("r", function (d) { return d.r * k; });
    }
  }

  render() {
    return (
      <svg
        width="900"
        height="900"
        ref={svg => this.svgRoot = svg}
      />
    );
  }
}

/**
 * CONTAINER
 */
const mapState = (state) => {
  return {
    userWords: state.userWords,
  };
};

const mapDispatch = (dispatch) => {
  return {};
};

export default withRouter(connect(mapState, mapDispatch)(DataVisWordCloud));

/**
 * PROP TYPES
 */
DataVisWordCloud.propTypes = {
  userWords: PropTypes.object.isRequired,
};<|endoftext|>