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
; },
7 if (typeof require
=== 'function') {
8 _
= require('underscore-plus');
9 $ = jQuery
= require('jquery');
10 Grim
= require('grim');
12 _
= window
._
, jQuery
= window
.jQuery
;
16 Tags
= 'a abbr address article aside audio b bdi bdo blockquote body button canvas\
17 caption cite code colgroup datalist dd del details dfn dialog div dl dt em\
18 fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 head header html i\
19 iframe ins kbd label legend li main map mark menu meter nav noscript object\
20 ol optgroup option output p pre progress q rp rt ruby s samp script section\
21 select small span strong style sub summary sup table tbody td textarea tfoot\
22 th thead time title tr u ul var video area base br col command embed hr img\
23 input keygen link meta param source track wbr'.split(/\s+/);
27 'area base br col command embed hr img input keygen link meta param\
28 source track wbr'.split(/\s+/).forEach(function(tag
) {
29 return SelfClosingTags
[tag
] = true;
32 Events
= 'blur change click dblclick error focus input keydown\
33 keypress keyup load mousedown mousemove mouseout mouseover\
34 mouseup resize scroll select submit unload'.split(/\s+/);
36 docEl
= document
.documentElement
;
38 matches
= docEl
.matchesSelector
|| docEl
.mozMatchesSelector
|| docEl
.webkitMatchesSelector
|| docEl
.oMatchesSelector
|| docEl
.msMatchesSelector
;
40 matchesSelector
= matches
? (function(elem
, selector
) {
41 return matches
.call(elem
[0], selector
);
42 }) : (function(elem
, selector
) {
43 return elem
.is(selector
);
48 CustomElementPrototype
= Object
.create(HTMLElement
.prototype);
50 CustomElementPrototype
.attachedCallback = function() {
51 return typeof this.attached
=== "function" ? this.attached() : void 0;
54 CustomElementPrototype
.detachedCallback = function() {
55 return typeof this.detached
=== "function" ? this.detached() : void 0;
58 if (window
.__spacePenCustomElements
== null) {
59 window
.__spacePenCustomElements
= {};
62 registerElement = function(tagName
) {
63 var customTagName
, _base
;
64 customTagName
= "space-pen-" + tagName
;
65 if ((_base
= window
.__spacePenCustomElements
)[customTagName
] == null) {
66 _base
[customTagName
] = typeof document
.registerElement
=== "function" ? document
.registerElement(customTagName
, {
67 prototype: Object
.create(CustomElementPrototype
),
74 View
= (function(_super
) {
75 __extends(View
, _super
);
77 View
.builderStack
= null;
79 Tags
.forEach(function(tagName
) {
80 return View
[tagName
] = function() {
82 args
= 1 <= arguments
.length
? __slice
.call(arguments
, 0) : [];
83 return (_ref
= this.currentBuilder
).tag
.apply(_ref
, [tagName
].concat(__slice
.call(args
)));
87 View
.subview = function(name
, view
) {
88 return this.currentBuilder
.subview(name
, view
);
91 View
.text = function(string
) {
92 return this.currentBuilder
.text(string
);
95 View
.tag = function() {
96 var args
, tagName
, _ref
;
97 tagName
= arguments
[0], args
= 2 <= arguments
.length
? __slice
.call(arguments
, 1) : [];
98 return (_ref
= this.currentBuilder
).tag
.apply(_ref
, [tagName
].concat(__slice
.call(args
)));
101 View
.raw = function(string
) {
102 return this.currentBuilder
.raw(string
);
105 View
.pushBuilder = function() {
107 builder
= new Builder
;
108 if (this.builderStack
== null) {
109 this.builderStack
= [];
111 this.builderStack
.push(builder
);
112 return this.currentBuilder
= builder
;
115 View
.popBuilder = function() {
116 this.currentBuilder
= this.builderStack
[this.builderStack
.length
- 2];
117 return this.builderStack
.pop();
120 View
.buildHtml = function(fn
) {
121 var html
, postProcessingSteps
, _ref
;
124 return _ref
= this.popBuilder().buildHtml(), html
= _ref
[0], postProcessingSteps
= _ref
[1], _ref
;
127 View
.render = function(fn
) {
128 var div
, fragment
, html
, postProcessingSteps
, step
, _i
, _len
, _ref
;
129 _ref
= this.buildHtml(fn
), html
= _ref
[0], postProcessingSteps
= _ref
[1];
130 div
= document
.createElement('div');
131 div
.innerHTML
= html
;
132 fragment
= $(div
.childNodes
);
133 for (_i
= 0, _len
= postProcessingSteps
.length
; _i
< _len
; _i
++) {
134 step
= postProcessingSteps
[_i
];
140 View
.prototype.element
= null;
143 var args
, element
, html
, postProcessingSteps
, step
, treeWalker
, _i
, _len
, _ref
,
145 args
= 1 <= arguments
.length
? __slice
.call(arguments
, 0) : [];
146 if (typeof this.afterAttach
=== 'function') {
147 throw new Error("The ::afterAttach hook has been replaced by ::attached. See https://github.com/atom/space-pen#attacheddetached-hooks for details.");
149 if (typeof this.beforeRemove
=== 'function') {
150 throw new Error("The ::beforeRemove hook has been replaced by ::detached. See https://github.com/atom/space-pen#attacheddetached-hooks for details.");
152 if (this.element
!= null) {
153 jQuery
.fn
.init
.call(this, this.element
);
155 _ref
= this.constructor.buildHtml(function() {
156 return this.content
.apply(this, args
);
157 }), html
= _ref
[0], postProcessingSteps
= _ref
[1];
158 jQuery
.fn
.init
.call(this, html
);
159 if (this.length
!== 1) {
160 throw new Error("View markup must have a single root element");
162 this.element
= this[0];
163 this.element
.attached = function() {
164 return typeof _this
.attached
=== "function" ? _this
.attached() : void 0;
166 this.element
.detached = function() {
167 return typeof _this
.detached
=== "function" ? _this
.detached() : void 0;
170 this.wireOutlets(this);
171 this.bindEventHandlers(this);
172 this.element
.spacePenView
= this;
173 treeWalker
= document
.createTreeWalker(this.element
, NodeFilter
.SHOW_ELEMENT
);
174 while (element
= treeWalker
.nextNode()) {
175 element
.spacePenView
= this;
177 if (postProcessingSteps
!= null) {
178 for (_i
= 0, _len
= postProcessingSteps
.length
; _i
< _len
; _i
++) {
179 step
= postProcessingSteps
[_i
];
183 if (typeof this.initialize
=== "function") {
184 this.initialize
.apply(this, args
);
188 View
.prototype.buildHtml = function(params
) {
189 var html
, postProcessingSteps
, _ref
;
190 this.constructor.builder
= new Builder
;
191 this.constructor.content(params
);
192 _ref
= this.constructor.builder
.buildHtml(), html
= _ref
[0], postProcessingSteps
= _ref
[1];
193 this.constructor.builder
= null;
194 return postProcessingSteps
;
197 View
.prototype.wireOutlets = function(view
) {
198 var element
, outlet
, _i
, _len
, _ref
;
199 _ref
= view
[0].querySelectorAll('[outlet]');
200 for (_i
= 0, _len
= _ref
.length
; _i
< _len
; _i
++) {
202 outlet
= element
.getAttribute('outlet');
203 view
[outlet
] = $(element
);
204 element
.removeAttribute('outlet');
209 View
.prototype.bindEventHandlers = function(view
) {
210 var element
, eventName
, methodName
, selector
, _fn
, _i
, _j
, _len
, _len1
, _ref
;
211 for (_i
= 0, _len
= Events
.length
; _i
< _len
; _i
++) {
212 eventName
= Events
[_i
];
213 selector
= "[" + eventName
+ "]";
214 _ref
= view
[0].querySelectorAll(selector
);
215 _fn = function(element
) {
217 methodName
= element
.getAttribute(eventName
);
218 element
= $(element
);
219 return element
.on(eventName
, function(event
) {
220 return view
[methodName
](event
, element
);
223 for (_j
= 0, _len1
= _ref
.length
; _j
< _len1
; _j
++) {
227 if (matchesSelector(view
, selector
)) {
228 methodName
= view
[0].getAttribute(eventName
);
229 (function(methodName
) {
230 return view
.on(eventName
, function(event
) {
231 return view
[methodName
](event
, view
);
239 View
.prototype.pushStack = function(elems
) {
241 ret
= jQuery
.merge(jQuery(), elems
);
242 ret
.prevObject
= this;
243 ret
.context
= this.context
;
247 View
.prototype.end = function() {
249 return (_ref
= this.prevObject
) != null ? _ref : jQuery(null);
252 View
.prototype.preempt = function(eventName
, handler
) {
253 return View
.__super__
.preempt
.call(this, eventName
, handler
);
260 Builder
= (function() {
263 this.postProcessingSteps
= [];
266 Builder
.prototype.buildHtml = function() {
267 return [this.document
.join(''), this.postProcessingSteps
];
270 Builder
.prototype.tag = function() {
271 var args
, name
, options
;
272 name
= arguments
[0], args
= 2 <= arguments
.length
? __slice
.call(arguments
, 1) : [];
273 options
= this.extractOptions(args
);
274 this.openTag(name
, options
.attributes
);
275 if (SelfClosingTags
.hasOwnProperty(name
)) {
276 if ((options
.text
!= null) || (options
.content
!= null)) {
277 throw new Error("Self-closing tag " + name
+ " cannot have text or content");
280 if (typeof options
.content
=== "function") {
284 this.text(options
.text
);
286 return this.closeTag(name
);
290 Builder
.prototype.openTag = function(name
, attributes
) {
291 var attributeName
, attributePairs
, attributesString
, value
;
292 if (this.document
.length
=== 0) {
293 if (attributes
== null) {
296 if (attributes
.is
== null) {
297 attributes
.is
= registerElement(name
);
300 attributePairs
= (function() {
303 for (attributeName
in attributes
) {
304 value
= attributes
[attributeName
];
305 _results
.push("" + attributeName
+ "=\"" + value
+ "\"");
309 attributesString
= attributePairs
.length
? " " + attributePairs
.join(" ") : "";
310 return this.document
.push("<" + name
+ attributesString
+ ">");
313 Builder
.prototype.closeTag = function(name
) {
314 return this.document
.push("</" + name
+ ">");
317 Builder
.prototype.text = function(string
) {
319 escapedString
= string
.replace(/&/g
, '&').replace(/"/g, '"').replace(/'/g, ''').replace(/</g, '<').replace(/>/g, '>');
320 return this.document.push(escapedString);
323 Builder.prototype.raw = function(string) {
324 return this.document.push(string);
327 Builder.prototype.subview = function(outletName, subview) {
329 subviewId = "subview
-" + (++idCounter);
333 return this.postProcessingSteps.push(function(view) {
334 view[outletName] = subview;
335 subview.parentView = view;
336 return view.find("div
#" + subviewId).replaceWith(subview);
340 Builder.prototype.extractOptions = function(args) {
341 var arg, options, _i, _len;
343 for (_i = 0, _len = args.length; _i < _len; _i++) {
345 switch (typeof arg) {
347 options.content = arg;
351 options.text = arg.toString();
354 options.attributes = arg;
364 $.fn.view = function() {
365 var element, viewConstructorName;
366 if (element = this[0]) {
367 if ((element.__spacePenView != null) && !element.__allowViewAccess) {
368 viewConstructorName = element.__spacePenView.constructor.name;
370 Grim.deprecate("Accessing
`" + viewConstructorName + "` via
`$::view()` is deprecated
. Use the raw DOM node or underlying model object instead
.");
373 return element.spacePenView;
377 $.fn.views = function() {
378 return this.toArray().map(function(elt) {
381 return (_ref = $elt.view()) != null ? _ref : $elt;
385 $.fn.containingView = function() {
388 while (element != null) {
389 if (view = element.spacePenView) {
392 element = element.parentNode;
396 $.fn.scrollBottom = function(newValue) {
397 if (newValue != null) {
398 return this.scrollTop(newValue - this.height());
400 return this.scrollTop() + this.height();
404 $.fn.scrollDown = function() {
405 return this.scrollTop(this.scrollTop() + $(window).height() / 20);
408 $.fn.scrollUp = function() {
409 return this.scrollTop(this.scrollTop() - $(window).height() / 20);
412 $.fn.scrollToTop = function() {
413 return this.scrollTop(0);
416 $.fn.scrollToBottom = function() {
417 return this.scrollTop(this.prop('scrollHeight'));
420 $.fn.scrollRight = function(newValue) {
421 if (newValue != null) {
422 return this.scrollLeft(newValue - this.width());
424 return this.scrollLeft() + this.width();
428 $.fn.pageUp = function() {
429 return this.scrollTop(this.scrollTop() - this.height());
432 $.fn.pageDown = function() {
433 return this.scrollTop(this.scrollTop() + this.height());
436 $.fn.isOnDom = function() {
437 return this.closest(document.body).length === 1;
440 $.fn.isVisible = function() {
441 return !this.isHidden();
444 $.fn.isHidden = function() {
446 style = this[0].style;
447 if (style.display === 'none' || !this.isOnDom()) {
449 } else if (style.display) {
452 return getComputedStyle(this[0]).display === 'none';
456 $.fn.isDisabled = function() {
457 return !!this.attr('disabled');
460 $.fn.enable = function() {
461 return this.removeAttr('disabled');
464 $.fn.disable = function() {
465 return this.attr('disabled', 'disabled');
468 $.fn.insertAt = function(index, element) {
470 target = this.children(":eq(" + index + ")");
472 return $(element).insertBefore(target);
474 return this.append(element);
478 $.fn.removeAt = function(index) {
479 return this.children(":eq(" + index + ")").remove();
482 $.fn.indexOf = function(child) {
483 return this.children().toArray().indexOf($(child)[0]);
486 $.fn.containsElement = function(element) {
487 return (element[0].compareDocumentPosition(this[0]) & 8) === 8;
490 $.fn.preempt = function(eventName, handler) {
491 var eventNameWithoutNamespace, handlers, wrappedHandler, _ref,
493 wrappedHandler = function() {
495 e = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
496 if (handler.apply(null, [e].concat(__slice.call(args))) === false) {
497 return e.stopImmediatePropagation();
500 this.on(eventName, wrappedHandler);
501 eventNameWithoutNamespace = eventName.split('.')[0];
502 handlers = (_ref = this.handlers()[eventNameWithoutNamespace]) != null ? _ref : [];
503 handlers.unshift(handlers.pop());
506 return _this.off(eventName, wrappedHandler);
511 $.fn.handlers = function(eventName) {
512 var handlers, _ref, _ref1;
513 handlers = this.length ? (_ref = $._data(this[0], 'events')) != null ? _ref : {} : {};
514 if (arguments.length === 1) {
515 handlers = (_ref1 = handlers[eventName]) != null ? _ref1 : [];
520 $.fn.hasParent = function() {
521 return this.parent()[0] != null;
524 $.fn.hasFocus = function() {
525 return this.is(':focus') || this.is(':has(:focus)');
528 $.fn.flashError = function() {
529 var removeErrorClass,
531 this.addClass('error');
532 removeErrorClass = function() {
533 return _this.removeClass('error');
535 return window.setTimeout(removeErrorClass, 300);
538 $.fn.trueHeight = function() {
539 return this[0].getBoundingClientRect().height;
542 $.fn.trueWidth = function() {
543 return this[0].getBoundingClientRect().width;
546 $.fn.iconSize = function(size) {
547 return this.width(size).height(size).css('font-size', size);
550 $.fn.intValue = function() {
551 return parseInt(this.text());
554 $.Event.prototype.abortKeyBinding = function() {};
556 $.Event.prototype.currentTargetView = function() {
557 return $(this.currentTarget).containingView();
560 $.Event.prototype.targetView = function() {
561 return $(this.target).containingView();
564 View.prototype.subscribe = function() {
566 message = "The
`::subscribe` method is no longer available on SpacePen views
.\n\n";
567 if (arguments.length === 1) {
568 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.";
570 if ((_ref
= arguments
[0]) != null ? _ref
.jquery : void 0) {
571 message
+= "To subscribe to events on a jQuery object, use the traditional `::on` and\n`::off methods`.";
573 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.";
576 throw new Error(message
);
579 View
.prototype.subscribeToCommand = function() {
580 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.");
583 $.fn
.command = function(eventName
, handler
) {
584 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.");
587 JQueryEventAdd
= jQuery
.event
.add
;
589 jQuery
.event
.add = function(elem
, types
, handler
, data
, selector
) {
590 if (/\:/.test(types
)) {
592 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.");
595 return JQueryEventAdd
.call(this, elem
, types
, handler
, data
, selector
);
598 if ($.fn
.originalTrigger
== null) {
599 $.fn
.originalTrigger
= $.fn
.trigger
;
600 $.fn
.trigger = function(eventName
, data
) {
601 if (typeof eventName
=== 'string' && /\:/.test(eventName
) && (eventName
!== 'cursor:moved' && eventName
!== 'selection:changed' && eventName
!== 'editor:display-updated')) {
603 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.");
606 return this.originalTrigger(eventName
, data
);
610 $.fn
.setTooltip = function() {
611 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");
614 $.fn
.destroyTooltip
= $.fn
.hideTooltip = function() {
615 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");
618 exports
= exports
!= null ? exports : this;
622 exports
.jQuery
= jQuery
;
626 exports
.$$ = function(fn
) {
627 return View
.render
.call(View
, fn
);
630 exports
.$$$ = function(fn
) {
631 return View
.buildHtml
.call(View
, fn
)[0];