1
0

space-pen.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. (function() {
  2. var $, Builder, CustomElementPrototype, Events, Grim, JQueryEventAdd, SelfClosingTags, Tags, View, docEl, exports, idCounter, jQuery, matches, matchesSelector, registerElement, _,
  3. __hasProp = {}.hasOwnProperty,
  4. __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
  5. __slice = [].slice;
  6. if (typeof require === 'function') {
  7. _ = require('underscore-plus');
  8. $ = jQuery = require('jquery');
  9. Grim = require('grim');
  10. } else {
  11. _ = window._, jQuery = window.jQuery;
  12. $ = jQuery;
  13. }
  14. Tags = 'a abbr address article aside audio b bdi bdo blockquote body button canvas\
  15. caption cite code colgroup datalist dd del details dfn dialog div dl dt em\
  16. fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 head header html i\
  17. iframe ins kbd label legend li main map mark menu meter nav noscript object\
  18. ol optgroup option output p pre progress q rp rt ruby s samp script section\
  19. select small span strong style sub summary sup table tbody td textarea tfoot\
  20. th thead time title tr u ul var video area base br col command embed hr img\
  21. input keygen link meta param source track wbr'.split(/\s+/);
  22. SelfClosingTags = {};
  23. 'area base br col command embed hr img input keygen link meta param\
  24. source track wbr'.split(/\s+/).forEach(function(tag) {
  25. return SelfClosingTags[tag] = true;
  26. });
  27. Events = 'blur change click dblclick error focus input keydown\
  28. keypress keyup load mousedown mousemove mouseout mouseover\
  29. mouseup resize scroll select submit unload'.split(/\s+/);
  30. docEl = document.documentElement;
  31. matches = docEl.matchesSelector || docEl.mozMatchesSelector || docEl.webkitMatchesSelector || docEl.oMatchesSelector || docEl.msMatchesSelector;
  32. matchesSelector = matches ? (function(elem, selector) {
  33. return matches.call(elem[0], selector);
  34. }) : (function(elem, selector) {
  35. return elem.is(selector);
  36. });
  37. idCounter = 0;
  38. CustomElementPrototype = Object.create(HTMLElement.prototype);
  39. CustomElementPrototype.attachedCallback = function() {
  40. return typeof this.attached === "function" ? this.attached() : void 0;
  41. };
  42. CustomElementPrototype.detachedCallback = function() {
  43. return typeof this.detached === "function" ? this.detached() : void 0;
  44. };
  45. if (window.__spacePenCustomElements == null) {
  46. window.__spacePenCustomElements = {};
  47. }
  48. registerElement = function(tagName) {
  49. var customTagName, _base;
  50. customTagName = "space-pen-" + tagName;
  51. if ((_base = window.__spacePenCustomElements)[customTagName] == null) {
  52. _base[customTagName] = typeof document.registerElement === "function" ? document.registerElement(customTagName, {
  53. prototype: Object.create(CustomElementPrototype),
  54. "extends": tagName
  55. }) : void 0;
  56. }
  57. return customTagName;
  58. };
  59. View = (function(_super) {
  60. __extends(View, _super);
  61. View.builderStack = null;
  62. Tags.forEach(function(tagName) {
  63. return View[tagName] = function() {
  64. var args, _ref;
  65. args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
  66. return (_ref = this.currentBuilder).tag.apply(_ref, [tagName].concat(__slice.call(args)));
  67. };
  68. });
  69. View.subview = function(name, view) {
  70. return this.currentBuilder.subview(name, view);
  71. };
  72. View.text = function(string) {
  73. return this.currentBuilder.text(string);
  74. };
  75. View.tag = function() {
  76. var args, tagName, _ref;
  77. tagName = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
  78. return (_ref = this.currentBuilder).tag.apply(_ref, [tagName].concat(__slice.call(args)));
  79. };
  80. View.raw = function(string) {
  81. return this.currentBuilder.raw(string);
  82. };
  83. View.pushBuilder = function() {
  84. var builder;
  85. builder = new Builder;
  86. if (this.builderStack == null) {
  87. this.builderStack = [];
  88. }
  89. this.builderStack.push(builder);
  90. return this.currentBuilder = builder;
  91. };
  92. View.popBuilder = function() {
  93. this.currentBuilder = this.builderStack[this.builderStack.length - 2];
  94. return this.builderStack.pop();
  95. };
  96. View.buildHtml = function(fn) {
  97. var html, postProcessingSteps, _ref;
  98. this.pushBuilder();
  99. fn.call(this);
  100. return _ref = this.popBuilder().buildHtml(), html = _ref[0], postProcessingSteps = _ref[1], _ref;
  101. };
  102. View.render = function(fn) {
  103. var div, fragment, html, postProcessingSteps, step, _i, _len, _ref;
  104. _ref = this.buildHtml(fn), html = _ref[0], postProcessingSteps = _ref[1];
  105. div = document.createElement('div');
  106. div.innerHTML = html;
  107. fragment = $(div.childNodes);
  108. for (_i = 0, _len = postProcessingSteps.length; _i < _len; _i++) {
  109. step = postProcessingSteps[_i];
  110. step(fragment);
  111. }
  112. return fragment;
  113. };
  114. View.prototype.element = null;
  115. function View() {
  116. var args, element, html, postProcessingSteps, step, treeWalker, _i, _len, _ref,
  117. _this = this;
  118. args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
  119. if (typeof this.afterAttach === 'function') {
  120. throw new Error("The ::afterAttach hook has been replaced by ::attached. See https://github.com/atom/space-pen#attacheddetached-hooks for details.");
  121. }
  122. if (typeof this.beforeRemove === 'function') {
  123. throw new Error("The ::beforeRemove hook has been replaced by ::detached. See https://github.com/atom/space-pen#attacheddetached-hooks for details.");
  124. }
  125. if (this.element != null) {
  126. jQuery.fn.init.call(this, this.element);
  127. } else {
  128. _ref = this.constructor.buildHtml(function() {
  129. return this.content.apply(this, args);
  130. }), html = _ref[0], postProcessingSteps = _ref[1];
  131. jQuery.fn.init.call(this, html);
  132. if (this.length !== 1) {
  133. throw new Error("View markup must have a single root element");
  134. }
  135. this.element = this[0];
  136. this.element.attached = function() {
  137. return typeof _this.attached === "function" ? _this.attached() : void 0;
  138. };
  139. this.element.detached = function() {
  140. return typeof _this.detached === "function" ? _this.detached() : void 0;
  141. };
  142. }
  143. this.wireOutlets(this);
  144. this.bindEventHandlers(this);
  145. this.element.spacePenView = this;
  146. treeWalker = document.createTreeWalker(this.element, NodeFilter.SHOW_ELEMENT);
  147. while (element = treeWalker.nextNode()) {
  148. element.spacePenView = this;
  149. }
  150. if (postProcessingSteps != null) {
  151. for (_i = 0, _len = postProcessingSteps.length; _i < _len; _i++) {
  152. step = postProcessingSteps[_i];
  153. step(this);
  154. }
  155. }
  156. if (typeof this.initialize === "function") {
  157. this.initialize.apply(this, args);
  158. }
  159. }
  160. View.prototype.buildHtml = function(params) {
  161. var html, postProcessingSteps, _ref;
  162. this.constructor.builder = new Builder;
  163. this.constructor.content(params);
  164. _ref = this.constructor.builder.buildHtml(), html = _ref[0], postProcessingSteps = _ref[1];
  165. this.constructor.builder = null;
  166. return postProcessingSteps;
  167. };
  168. View.prototype.wireOutlets = function(view) {
  169. var element, outlet, _i, _len, _ref;
  170. _ref = view[0].querySelectorAll('[outlet]');
  171. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  172. element = _ref[_i];
  173. outlet = element.getAttribute('outlet');
  174. view[outlet] = $(element);
  175. element.removeAttribute('outlet');
  176. }
  177. return void 0;
  178. };
  179. View.prototype.bindEventHandlers = function(view) {
  180. var element, eventName, methodName, selector, _fn, _i, _j, _len, _len1, _ref;
  181. for (_i = 0, _len = Events.length; _i < _len; _i++) {
  182. eventName = Events[_i];
  183. selector = "[" + eventName + "]";
  184. _ref = view[0].querySelectorAll(selector);
  185. _fn = function(element) {
  186. var methodName;
  187. methodName = element.getAttribute(eventName);
  188. element = $(element);
  189. return element.on(eventName, function(event) {
  190. return view[methodName](event, element);
  191. });
  192. };
  193. for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
  194. element = _ref[_j];
  195. _fn(element);
  196. }
  197. if (matchesSelector(view, selector)) {
  198. methodName = view[0].getAttribute(eventName);
  199. (function(methodName) {
  200. return view.on(eventName, function(event) {
  201. return view[methodName](event, view);
  202. });
  203. })(methodName);
  204. }
  205. }
  206. return void 0;
  207. };
  208. View.prototype.pushStack = function(elems) {
  209. var ret;
  210. ret = jQuery.merge(jQuery(), elems);
  211. ret.prevObject = this;
  212. ret.context = this.context;
  213. return ret;
  214. };
  215. View.prototype.end = function() {
  216. var _ref;
  217. return (_ref = this.prevObject) != null ? _ref : jQuery(null);
  218. };
  219. View.prototype.preempt = function(eventName, handler) {
  220. return View.__super__.preempt.call(this, eventName, handler);
  221. };
  222. return View;
  223. })(jQuery);
  224. Builder = (function() {
  225. function Builder() {
  226. this.document = [];
  227. this.postProcessingSteps = [];
  228. }
  229. Builder.prototype.buildHtml = function() {
  230. return [this.document.join(''), this.postProcessingSteps];
  231. };
  232. Builder.prototype.tag = function() {
  233. var args, name, options;
  234. name = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
  235. options = this.extractOptions(args);
  236. this.openTag(name, options.attributes);
  237. if (SelfClosingTags.hasOwnProperty(name)) {
  238. if ((options.text != null) || (options.content != null)) {
  239. throw new Error("Self-closing tag " + name + " cannot have text or content");
  240. }
  241. } else {
  242. if (typeof options.content === "function") {
  243. options.content();
  244. }
  245. if (options.text) {
  246. this.text(options.text);
  247. }
  248. return this.closeTag(name);
  249. }
  250. };
  251. Builder.prototype.openTag = function(name, attributes) {
  252. var attributeName, attributePairs, attributesString, value;
  253. if (this.document.length === 0) {
  254. if (attributes == null) {
  255. attributes = {};
  256. }
  257. if (attributes.is == null) {
  258. attributes.is = registerElement(name);
  259. }
  260. }
  261. attributePairs = (function() {
  262. var _results;
  263. _results = [];
  264. for (attributeName in attributes) {
  265. value = attributes[attributeName];
  266. _results.push("" + attributeName + "=\"" + value + "\"");
  267. }
  268. return _results;
  269. })();
  270. attributesString = attributePairs.length ? " " + attributePairs.join(" ") : "";
  271. return this.document.push("<" + name + attributesString + ">");
  272. };
  273. Builder.prototype.closeTag = function(name) {
  274. return this.document.push("</" + name + ">");
  275. };
  276. Builder.prototype.text = function(string) {
  277. var escapedString;
  278. escapedString = string.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/'/g, '&#39;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
  279. return this.document.push(escapedString);
  280. };
  281. Builder.prototype.raw = function(string) {
  282. return this.document.push(string);
  283. };
  284. Builder.prototype.subview = function(outletName, subview) {
  285. var subviewId;
  286. subviewId = "subview-" + (++idCounter);
  287. this.tag('div', {
  288. id: subviewId
  289. });
  290. return this.postProcessingSteps.push(function(view) {
  291. view[outletName] = subview;
  292. subview.parentView = view;
  293. return view.find("div#" + subviewId).replaceWith(subview);
  294. });
  295. };
  296. Builder.prototype.extractOptions = function(args) {
  297. var arg, options, _i, _len;
  298. options = {};
  299. for (_i = 0, _len = args.length; _i < _len; _i++) {
  300. arg = args[_i];
  301. switch (typeof arg) {
  302. case 'function':
  303. options.content = arg;
  304. break;
  305. case 'string':
  306. case 'number':
  307. options.text = arg.toString();
  308. break;
  309. default:
  310. options.attributes = arg;
  311. }
  312. }
  313. return options;
  314. };
  315. return Builder;
  316. })();
  317. $.fn.view = function() {
  318. var element, viewConstructorName;
  319. if (element = this[0]) {
  320. if ((element.__spacePenView != null) && !element.__allowViewAccess) {
  321. viewConstructorName = element.__spacePenView.constructor.name;
  322. if (Grim != null) {
  323. Grim.deprecate("Accessing `" + viewConstructorName + "` via `$::view()` is deprecated. Use the raw DOM node or underlying model object instead.");
  324. }
  325. }
  326. return element.spacePenView;
  327. }
  328. };
  329. $.fn.views = function() {
  330. return this.toArray().map(function(elt) {
  331. var $elt, _ref;
  332. $elt = $(elt);
  333. return (_ref = $elt.view()) != null ? _ref : $elt;
  334. });
  335. };
  336. $.fn.containingView = function() {
  337. var element, view;
  338. element = this[0];
  339. while (element != null) {
  340. if (view = element.spacePenView) {
  341. return view;
  342. }
  343. element = element.parentNode;
  344. }
  345. };
  346. $.fn.scrollBottom = function(newValue) {
  347. if (newValue != null) {
  348. return this.scrollTop(newValue - this.height());
  349. } else {
  350. return this.scrollTop() + this.height();
  351. }
  352. };
  353. $.fn.scrollDown = function() {
  354. return this.scrollTop(this.scrollTop() + $(window).height() / 20);
  355. };
  356. $.fn.scrollUp = function() {
  357. return this.scrollTop(this.scrollTop() - $(window).height() / 20);
  358. };
  359. $.fn.scrollToTop = function() {
  360. return this.scrollTop(0);
  361. };
  362. $.fn.scrollToBottom = function() {
  363. return this.scrollTop(this.prop('scrollHeight'));
  364. };
  365. $.fn.scrollRight = function(newValue) {
  366. if (newValue != null) {
  367. return this.scrollLeft(newValue - this.width());
  368. } else {
  369. return this.scrollLeft() + this.width();
  370. }
  371. };
  372. $.fn.pageUp = function() {
  373. return this.scrollTop(this.scrollTop() - this.height());
  374. };
  375. $.fn.pageDown = function() {
  376. return this.scrollTop(this.scrollTop() + this.height());
  377. };
  378. $.fn.isOnDom = function() {
  379. return this.closest(document.body).length === 1;
  380. };
  381. $.fn.isVisible = function() {
  382. return !this.isHidden();
  383. };
  384. $.fn.isHidden = function() {
  385. var style;
  386. style = this[0].style;
  387. if (style.display === 'none' || !this.isOnDom()) {
  388. return true;
  389. } else if (style.display) {
  390. return false;
  391. } else {
  392. return getComputedStyle(this[0]).display === 'none';
  393. }
  394. };
  395. $.fn.isDisabled = function() {
  396. return !!this.attr('disabled');
  397. };
  398. $.fn.enable = function() {
  399. return this.removeAttr('disabled');
  400. };
  401. $.fn.disable = function() {
  402. return this.attr('disabled', 'disabled');
  403. };
  404. $.fn.insertAt = function(index, element) {
  405. var target;
  406. target = this.children(":eq(" + index + ")");
  407. if (target.length) {
  408. return $(element).insertBefore(target);
  409. } else {
  410. return this.append(element);
  411. }
  412. };
  413. $.fn.removeAt = function(index) {
  414. return this.children(":eq(" + index + ")").remove();
  415. };
  416. $.fn.indexOf = function(child) {
  417. return this.children().toArray().indexOf($(child)[0]);
  418. };
  419. $.fn.containsElement = function(element) {
  420. return (element[0].compareDocumentPosition(this[0]) & 8) === 8;
  421. };
  422. $.fn.preempt = function(eventName, handler) {
  423. var eventNameWithoutNamespace, handlers, wrappedHandler, _ref,
  424. _this = this;
  425. wrappedHandler = function() {
  426. var args, e;
  427. e = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
  428. if (handler.apply(null, [e].concat(__slice.call(args))) === false) {
  429. return e.stopImmediatePropagation();
  430. }
  431. };
  432. this.on(eventName, wrappedHandler);
  433. eventNameWithoutNamespace = eventName.split('.')[0];
  434. handlers = (_ref = this.handlers()[eventNameWithoutNamespace]) != null ? _ref : [];
  435. handlers.unshift(handlers.pop());
  436. return {
  437. off: function() {
  438. return _this.off(eventName, wrappedHandler);
  439. }
  440. };
  441. };
  442. $.fn.handlers = function(eventName) {
  443. var handlers, _ref, _ref1;
  444. handlers = this.length ? (_ref = $._data(this[0], 'events')) != null ? _ref : {} : {};
  445. if (arguments.length === 1) {
  446. handlers = (_ref1 = handlers[eventName]) != null ? _ref1 : [];
  447. }
  448. return handlers;
  449. };
  450. $.fn.hasParent = function() {
  451. return this.parent()[0] != null;
  452. };
  453. $.fn.hasFocus = function() {
  454. return this.is(':focus') || this.is(':has(:focus)');
  455. };
  456. $.fn.flashError = function() {
  457. var removeErrorClass,
  458. _this = this;
  459. this.addClass('error');
  460. removeErrorClass = function() {
  461. return _this.removeClass('error');
  462. };
  463. return window.setTimeout(removeErrorClass, 300);
  464. };
  465. $.fn.trueHeight = function() {
  466. return this[0].getBoundingClientRect().height;
  467. };
  468. $.fn.trueWidth = function() {
  469. return this[0].getBoundingClientRect().width;
  470. };
  471. $.fn.iconSize = function(size) {
  472. return this.width(size).height(size).css('font-size', size);
  473. };
  474. $.fn.intValue = function() {
  475. return parseInt(this.text());
  476. };
  477. $.Event.prototype.abortKeyBinding = function() {};
  478. $.Event.prototype.currentTargetView = function() {
  479. return $(this.currentTarget).containingView();
  480. };
  481. $.Event.prototype.targetView = function() {
  482. return $(this.target).containingView();
  483. };
  484. View.prototype.subscribe = function() {
  485. var message, _ref;
  486. message = "The `::subscribe` method is no longer available on SpacePen views.\n\n";
  487. if (arguments.length === 1) {
  488. message += "To store multiple subscription objects for later disposal, add them to a\n`CompositeDisposable` instance (https://atom.io/docs/api/v0.150.0/CompositeDisposable)\nand call `.dispose()` on it explicitly in this view's `::detached` hook.";
  489. } else {
  490. if ((_ref = arguments[0]) != null ? _ref.jquery : void 0) {
  491. message += "To subscribe to events on a jQuery object, use the traditional `::on` and\n`::off methods`.";
  492. } else {
  493. message += "To subscribe to events on an Atom object, use an explicit event-subscription\nmethod (starting with ::onDid* or ::onWill*).\n\nTo collect multiple subscription objects for later disposal, add them to a\n`CompositeDisposable` instance:\nhttps://atom.io/docs/api/v0.150.0/CompositeDisposable\n\nCall `.dispose()` on your `CompositeDisposable` in this view's `::detached` hook.";
  494. }
  495. }
  496. throw new Error(message);
  497. };
  498. View.prototype.subscribeToCommand = function() {
  499. throw new Error("The `::subscribeToCommand` method is no longer available on SpacePen views.\"\n\nPlease subscribe to commands via `atom.commands.add`:\nhttps://atom.io/docs/api/latest/CommandRegistry#instance-add\n\nCollect the returned subscription objects in a CompositeDisposable:\nhttps://atom.io/docs/api/latest/CompositeDisposable\n\nCall `.dispose()` on your `CompositeDisposable` in this view's `::detached` hook.");
  500. };
  501. $.fn.command = function(eventName, handler) {
  502. throw new Error("The `::command` method is no longer available on SpacePen views.\"\n\nPlease subscribe to commands via `atom.commands.add`:\nhttps://atom.io/docs/api/latest/CommandRegistry#instance-add\n\nCollect the returned subscription objects in a CompositeDisposable:\nhttps://atom.io/docs/api/latest/CompositeDisposable\n\nCall `.dispose()` on your `CompositeDisposable` in this view's `::detached` hook.");
  503. };
  504. JQueryEventAdd = jQuery.event.add;
  505. jQuery.event.add = function(elem, types, handler, data, selector) {
  506. if (/\:/.test(types)) {
  507. if (Grim != null) {
  508. Grim.deprecate("Are you trying to listen for the '" + types + "' Atom command with `jQuery::on`?\n`jQuery::trigger` can no longer be used to listen for Atom commands. Please\nuse `atom.commands.add` instead. See the docs at\nhttps://atom.io/docs/api/latest/CommandRegistry#instance-add for details.");
  509. }
  510. }
  511. return JQueryEventAdd.call(this, elem, types, handler, data, selector);
  512. };
  513. if ($.fn.originalTrigger == null) {
  514. $.fn.originalTrigger = $.fn.trigger;
  515. $.fn.trigger = function(eventName, data) {
  516. if (typeof eventName === 'string' && /\:/.test(eventName) && (eventName !== 'cursor:moved' && eventName !== 'selection:changed' && eventName !== 'editor:display-updated')) {
  517. if (Grim != null) {
  518. Grim.deprecate("Are you trying to dispatch the '" + eventName + "' Atom command with `jQuery::trigger`?\n`jQuery::trigger` can no longer emit Atom commands as it will not correctly route\nthe command to its handlers. Please use `atom.commands.dispatch` instead.\nSee the docs at https://atom.io/docs/api/latest/CommandRegistry#instance-dispatch\nfor details.");
  519. }
  520. }
  521. return this.originalTrigger(eventName, data);
  522. };
  523. }
  524. $.fn.setTooltip = function() {
  525. throw new Error("setTooltip is no longer available. Please use `atom.tooltips.add` instead.\nSee the docs at https://atom.io/docs/api/latest/TooltipManager#instance-add");
  526. };
  527. $.fn.destroyTooltip = $.fn.hideTooltip = function() {
  528. throw new Error("destroyTooltip is no longer available. Please dispose the object returned\nfrom `atom.tooltips.add` instead.\nSee the docs at https://atom.io/docs/api/latest/TooltipManager#instance-add");
  529. };
  530. exports = exports != null ? exports : this;
  531. exports.View = View;
  532. exports.jQuery = jQuery;
  533. exports.$ = $;
  534. exports.$$ = function(fn) {
  535. return View.render.call(View, fn);
  536. };
  537. exports.$$$ = function(fn) {
  538. return View.buildHtml.call(View, fn)[0];
  539. };
  540. }).call(this);