jabs 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,137 @@
1
+ /*!
2
+ jquery.event.drag.js ~ v1.5 ~ Copyright (c) 2008, Three Dub Media (http://threedubmedia.com)
3
+ Liscensed under the MIT License ~ http://threedubmedia.googlecode.com/files/MIT-LICENSE.txt
4
+ */
5
+ ;(function($){ // secure $ jQuery alias
6
+ /*******************************************************************************************/
7
+ // Created: 2008-06-04 | Updated: 2009-03-24
8
+ /*******************************************************************************************/
9
+ // Events: drag, dragstart, dragend
10
+ /*******************************************************************************************/
11
+
12
+ // jquery method
13
+ $.fn.drag = function( fn1, fn2, fn3 ){
14
+ if ( fn2 ) this.bind('dragstart', fn1 ); // 2+ args
15
+ if ( fn3 ) this.bind('dragend', fn3 ); // 3 args
16
+ return !fn1 ? this.trigger('drag') // 0 args
17
+ : this.bind('drag', fn2 ? fn2 : fn1 ); // 1+ args
18
+ };
19
+
20
+ // local refs
21
+ var $event = $.event, $special = $event.special,
22
+
23
+ // special event configuration
24
+ drag = $special.drag = {
25
+ not: ':input', // don't begin to drag on event.targets that match this selector
26
+ distance: 0, // distance dragged before dragstart
27
+ which: 1, // mouse button pressed to start drag sequence
28
+ dragging: false, // hold the active target element
29
+ setup: function( data ){
30
+ data = $.extend({
31
+ distance: drag.distance,
32
+ which: drag.which,
33
+ not: drag.not
34
+ }, data || {});
35
+ data.distance = squared( data.distance ); // x� + y� = distance�
36
+ $event.add( this, "mousedown", handler, data );
37
+ if ( this.attachEvent ) this.attachEvent("ondragstart", dontStart ); // prevent image dragging in IE...
38
+ },
39
+ teardown: function(){
40
+ $event.remove( this, "mousedown", handler );
41
+ if ( this === drag.dragging ) drag.dragging = drag.proxy = false; // deactivate element
42
+ selectable( this, true ); // enable text selection
43
+ if ( this.detachEvent ) this.detachEvent("ondragstart", dontStart ); // prevent image dragging in IE...
44
+ }
45
+ };
46
+
47
+ // prevent normal event binding...
48
+ $special.dragstart = $special.dragend = { setup:function(){}, teardown:function(){} };
49
+
50
+ // handle drag-releatd DOM events
51
+ function handler ( event ){
52
+ var elem = this, returned, data = event.data || {};
53
+ // mousemove or mouseup
54
+ if ( data.elem ){
55
+ // update event properties...
56
+ elem = event.dragTarget = data.elem; // drag source element
57
+ event.dragProxy = drag.proxy || elem; // proxy element or source
58
+ event.cursorOffsetX = data.pageX - data.left; // mousedown offset
59
+ event.cursorOffsetY = data.pageY - data.top; // mousedown offset
60
+ event.offsetX = event.pageX - event.cursorOffsetX; // element offset
61
+ event.offsetY = event.pageY - event.cursorOffsetY; // element offset
62
+ }
63
+ // mousedown, check some initial props to avoid the switch statement
64
+ else if ( drag.dragging || ( data.which>0 && event.which!=data.which ) ||
65
+ $( event.target ).is( data.not ) ) return;
66
+ // handle various events
67
+ switch ( event.type ){
68
+ // mousedown, left click, event.target is not restricted, init dragging
69
+ case 'mousedown':
70
+ $.extend( data, $( elem ).offset(), {
71
+ elem: elem, target: event.target,
72
+ pageX: event.pageX, pageY: event.pageY
73
+ }); // store some initial attributes
74
+ $event.add( document, "mousemove mouseup", handler, data );
75
+ selectable( elem, false ); // disable text selection
76
+ drag.dragging = null; // pending state
77
+ return false; // prevents text selection in safari
78
+ // mousemove, check distance, start dragging
79
+ case !drag.dragging && 'mousemove':
80
+ if ( squared( event.pageX-data.pageX )
81
+ + squared( event.pageY-data.pageY ) // x� + y� = distance�
82
+ < data.distance ) break; // distance tolerance not reached
83
+ event.target = data.target; // force target from "mousedown" event (fix distance issue)
84
+ returned = hijack( event, "dragstart", elem ); // trigger "dragstart", return proxy element
85
+ if ( returned !== false ){ // "dragstart" not rejected
86
+ drag.dragging = elem; // activate element
87
+ drag.proxy = event.dragProxy = $( returned || elem )[0]; // set proxy
88
+ }
89
+ // mousemove, dragging
90
+ case 'mousemove':
91
+ if ( drag.dragging ){
92
+ returned = hijack( event, "drag", elem ); // trigger "drag"
93
+ if ( $special.drop ){ // manage drop events
94
+ $special.drop.allowed = ( returned !== false ); // prevent drop
95
+ $special.drop.handler( event ); // "dropstart", "dropend"
96
+ }
97
+ if ( returned !== false ) break; // "drag" not rejected, stop
98
+ event.type = "mouseup"; // helps "drop" handler behave
99
+ }
100
+ // mouseup, stop dragging
101
+ case 'mouseup':
102
+ $event.remove( document, "mousemove mouseup", handler ); // remove page events
103
+ if ( drag.dragging ){
104
+ if ( $special.drop ) $special.drop.handler( event ); // "drop"
105
+ hijack( event, "dragend", elem ); // trigger "dragend"
106
+ }
107
+ selectable( elem, true ); // enable text selection
108
+ drag.dragging = drag.proxy = data.elem = false; // deactivate element
109
+ break;
110
+ }
111
+ return true;
112
+ };
113
+
114
+ // set event type to custom value, and handle it
115
+ function hijack ( event, type, elem ){
116
+ event.type = type; // force the event type
117
+ var result = $.event.handle.call( elem, event );
118
+ return result===false ? false : result || event.result;
119
+ };
120
+
121
+ // return the value squared
122
+ function squared ( value ){ return Math.pow( value, 2 ); };
123
+
124
+ // suppress default dragstart IE events...
125
+ function dontStart(){ return ( drag.dragging === false ); };
126
+
127
+ // toggles text selection attributes
128
+ function selectable ( elem, bool ){
129
+ if ( !elem ) return; // maybe element was removed ?
130
+ elem.unselectable = bool ? "off" : "on"; // IE
131
+ elem.onselectstart = function(){ return bool; }; // IE
132
+ //if ( document.selection && document.selection.empty ) document.selection.empty(); // IE
133
+ if ( elem.style ) elem.style.MozUserSelect = bool ? "" : "none"; // FF
134
+ };
135
+
136
+ /*******************************************************************************************/
137
+ })( jQuery ); // confine scope
@@ -0,0 +1,157 @@
1
+ /*! jquery.event.drop.js * v1.2
2
+ Copyright (c) 2008-2009, Three Dub Media (http://threedubmedia.com)
3
+ Liscensed under the MIT License (http://threedubmedia.googlecode.com/files/MIT-LICENSE.txt)
4
+ */;(function($){ // secure $ jQuery alias
5
+ // Created: 2008-06-04 | Updated: 2009-03-16
6
+ /*******************************************************************************************/
7
+ // Events: drop, dropstart, dropend
8
+ /*******************************************************************************************/
9
+
10
+ // JQUERY METHOD
11
+ $.fn.drop = function( fn1, fn2, fn3 ){
12
+ if ( fn2 ) this.bind('dropstart', fn1 ); // 2+ args
13
+ if ( fn3 ) this.bind('dropend', fn3 ); // 3 args
14
+ return !fn1 ? this.trigger('drop') // 0 args
15
+ : this.bind('drop', fn2 ? fn2 : fn1 ); // 1+ args
16
+ };
17
+
18
+ // DROP MANAGEMENT UTILITY
19
+ $.dropManage = function( opts ){ // return filtered drop target elements, cache their positions
20
+ opts = opts || {};
21
+ // safely set new options...
22
+ drop.data = [];
23
+ drop.filter = opts.filter || '*';
24
+ drop.delay = opts.delay || drop.delay;
25
+ drop.tolerance = opts.tolerance || null;
26
+ drop.mode = opts.mode || drop.mode || 'intersect';
27
+ // return the filtered set of drop targets
28
+ return drop.$targets.filter( drop.filter ).each(function(){
29
+ // locate and store the filtered drop targets
30
+ drop.data[ drop.data.length ] = drop.locate( this );
31
+ });
32
+ };
33
+
34
+ // local refs
35
+ var $event = $.event, $special = $event.special,
36
+
37
+ // SPECIAL EVENT CONFIGURATION
38
+ drop = $special.drop = {
39
+ delay: 100, // default frequency to track drop targets
40
+ mode: 'intersect', // default mode to determine valid drop targets
41
+ $targets: $([]), data: [], // storage of drop targets and locations
42
+ setup: function(){
43
+ drop.$targets = drop.$targets.add( this );
44
+ drop.data[ drop.data.length ] = drop.locate( this );
45
+ },
46
+ teardown: function(){ var elem = this;
47
+ drop.$targets = drop.$targets.not( this );
48
+ drop.data = $.grep( drop.data, function( obj ){
49
+ return ( obj.elem !== elem );
50
+ });
51
+ },
52
+ // shared handler
53
+ handler: function( event ){
54
+ var dropstart = null, dropped;
55
+ event.dropTarget = drop.dropping || undefined; // dropped element
56
+ if ( drop.data.length && event.dragTarget ){
57
+ // handle various events
58
+ switch ( event.type ){
59
+ // drag/mousemove, from $.event.special.drag
60
+ case 'drag': // TOLERATE >>
61
+ drop.event = event; // store the mousemove event
62
+ if ( !drop.timer ) // monitor drop targets
63
+ drop.timer = setTimeout( tolerate, 20 );
64
+ break;
65
+ // dragstop/mouseup, from $.event.special.drag
66
+ case 'mouseup': // DROP >> DROPEND >>
67
+ drop.timer = clearTimeout( drop.timer ); // delete timer
68
+ if ( !drop.dropping ) break; // stop, no drop
69
+ if ( drop.allowed )
70
+ dropped = hijack( event, "drop", drop.dropping ); // trigger "drop"
71
+ dropstart = false;
72
+ // activate new target, from tolerate (async)
73
+ case drop.dropping && 'dropstart': // DROPSTART >> ( new target )
74
+ dropstart = dropstart===null && drop.allowed ? true : false;
75
+ // deactivate active target, from tolerate (async)
76
+ case drop.dropping && 'dropend': // DROPEND >>
77
+ hijack( event, "dropend", drop.dropping ); // trigger "dropend"
78
+ drop.dropping = null; // empty dropper
79
+ if ( dropped === false ) event.dropTarget = undefined;
80
+ if ( !dropstart ) break; // stop
81
+ // activate target, from tolerate (async)
82
+ case drop.allowed && 'dropstart': // DROPSTART >>
83
+ event.dropTarget = this;
84
+ drop.dropping = hijack( event, "dropstart", this )!==false ? this : null; // trigger "dropstart"
85
+ break;
86
+ }
87
+ }
88
+ },
89
+ // returns the location positions of an element
90
+ locate: function( elem ){ // return { L:left, R:right, T:top, B:bottom, H:height, W:width }
91
+ var $el = $(elem), pos = $el.offset(), h = $el.outerHeight(), w = $el.outerWidth();
92
+ return { elem: elem, L: pos.left, R: pos.left+w, T: pos.top, B: pos.top+h, W: w, H: h };
93
+ },
94
+ // test the location positions of an element against another OR an X,Y coord
95
+ contains: function( target, test ){ // target { L,R,T,B,H,W } contains test [x,y] or { L,R,T,B,H,W }
96
+ return ( ( test[0] || test.L ) >= target.L && ( test[0] || test.R ) <= target.R
97
+ && ( test[1] || test.T ) >= target.T && ( test[1] || test.B ) <= target.B );
98
+ },
99
+ // stored tolerance modes
100
+ modes: { // fn scope: "$.event.special.drop" object
101
+ // target with mouse wins, else target with most overlap wins
102
+ 'intersect': function( event, proxy, target ){
103
+ return this.contains( target, [ event.pageX, event.pageY ] ) ? // check cursor
104
+ target : this.modes['overlap'].apply( this, arguments ); // check overlap
105
+ },
106
+ // target with most overlap wins
107
+ 'overlap': function( event, proxy, target ){
108
+ // calculate the area of overlap...
109
+ target.overlap = Math.max( 0, Math.min( target.B, proxy.B ) - Math.max( target.T, proxy.T ) )
110
+ * Math.max( 0, Math.min( target.R, proxy.R ) - Math.max( target.L, proxy.L ) );
111
+ if ( target.overlap > ( ( this.best || {} ).overlap || 0 ) ) // compare overlap
112
+ this.best = target; // set as the best match so far
113
+ return null; // no winner
114
+ },
115
+ // proxy is completely contained within target bounds
116
+ 'fit': function( event, proxy, target ){
117
+ return this.contains( target, proxy ) ? target : null;
118
+ },
119
+ // center of the proxy is contained within target bounds
120
+ 'middle': function( event, proxy, target ){
121
+ return this.contains( target, [ proxy.L+proxy.W/2, proxy.T+proxy.H/2 ] ) ? target : null;
122
+ }
123
+ }
124
+ };
125
+
126
+ // set event type to custom value, and handle it
127
+ function hijack ( event, type, elem ){
128
+ event.type = type; // force the event type
129
+ try { var result = $event.handle.call( elem, event );
130
+ } catch ( ex ){ /* catch IE error with async event handling */ }
131
+ return result===false ? false : result || event.result;
132
+ };
133
+
134
+ // async, recursive tolerance execution
135
+ function tolerate (){
136
+ var i = 0, drp, winner, // local variables
137
+ xy = [ drop.event.pageX, drop.event.pageY ], // mouse location
138
+ drg = drop.locate( drop.event.dragProxy ); // drag proxy location
139
+ drop.tolerance = drop.tolerance || drop.modes[ drop.mode ]; // custom or stored tolerance fn
140
+ do if ( drp = drop.data[i] ){ // each drop target location
141
+ // tolerance function is defined, or mouse contained
142
+ winner = drop.tolerance ? drop.tolerance.call( drop, drop.event, drg, drp )
143
+ : drop.contains( drp, xy ) ? drp : null; // mouse is always fallback
144
+ }
145
+ while ( ++i<drop.data.length && !winner ); // loop
146
+ drop.event.type = ( winner = winner || drop.best ) ? 'dropstart' : 'dropend'; // start ? stop
147
+ if ( drop.event.type=='dropend' || winner.elem!=drop.dropping ) // don't dropstart on active drop target
148
+ drop.handler.call( winner ? winner.elem : drop.dropping, drop.event ); // handle events
149
+ if ( drop.last && xy[0] == drop.last.pageX && xy[1] == drop.last.pageY ) // no movement
150
+ delete drop.timer; // idle, don't recurse
151
+ else drop.timer = setTimeout( tolerate, drop.delay ); // recurse
152
+ drop.last = drop.event; // to compare idleness
153
+ drop.best = null; // reset comparitors
154
+ };
155
+
156
+ /*******************************************************************************************/
157
+ })(jQuery); // confine scope
@@ -0,0 +1,81 @@
1
+ (function(){
2
+
3
+ var special = jQuery.event.special,
4
+ uid1 = 'D' + (+new Date()),
5
+ uid2 = 'D' + (+new Date() + 1);
6
+
7
+ jQuery.event.special.focus = {
8
+ setup: function() {
9
+ var _self = this,
10
+ handler = function(e) {
11
+ e = jQuery.event.fix(e);
12
+ e.type = 'focus';
13
+ if (_self === document) {
14
+ jQuery.event.handle.call(_self, e);
15
+ }
16
+ };
17
+
18
+ jQuery(this).data(uid1, handler);
19
+
20
+ if (_self === document) {
21
+ /* Must be live() */
22
+ if (_self.addEventListener) {
23
+ _self.addEventListener('focus', handler, true);
24
+ } else {
25
+ _self.attachEvent('onfocusin', handler);
26
+ }
27
+ } else {
28
+ return false;
29
+ }
30
+
31
+ },
32
+ teardown: function() {
33
+ var handler = jQuery(this).data(uid1);
34
+ if (this === document) {
35
+ if (this.removeEventListener) {
36
+ this.removeEventListener('focus', handler, true);
37
+ } else {
38
+ this.detachEvent('onfocusin', handler);
39
+ }
40
+ }
41
+ }
42
+ };
43
+
44
+ jQuery.event.special.blur = {
45
+ setup: function() {
46
+ var _self = this,
47
+ handler = function(e) {
48
+ e = jQuery.event.fix(e);
49
+ e.type = 'blur';
50
+ if (_self === document) {
51
+ jQuery.event.handle.call(_self, e);
52
+ }
53
+ };
54
+
55
+ jQuery(this).data(uid2, handler);
56
+
57
+ if (_self === document) {
58
+ /* Must be live() */
59
+ if (_self.addEventListener) {
60
+ _self.addEventListener('blur', handler, true);
61
+ } else {
62
+ _self.attachEvent('onfocusout', handler);
63
+ }
64
+ } else {
65
+ return false;
66
+ }
67
+
68
+ },
69
+ teardown: function() {
70
+ var handler = jQuery(this).data(uid2);
71
+ if (this === document) {
72
+ if (this.removeEventListener) {
73
+ this.removeEventListener('blur', handler, true);
74
+ } else {
75
+ this.detachEvent('onfocusout', handler);
76
+ }
77
+ }
78
+ }
79
+ };
80
+
81
+ })();
@@ -4,6 +4,7 @@ require 'colored'
4
4
 
5
5
  describe Jabs::Engine do
6
6
  def assert_jabs src, target
7
+ target = "(function(){#{target}})()"
7
8
  jabsed = Jabs::Engine.new(src).render
8
9
  src = Johnson::Parser.parse(jabsed).to_ecma
9
10
  target = Johnson::Parser.parse(target).to_ecma
@@ -119,7 +120,7 @@ def sets_default_value
119
120
  }, %{
120
121
  jQuery.fn.sets_default_value = function() {
121
122
  var $this = this;
122
- (function($this) {})($this.find('[default_value]'))
123
+ return (function($this) {return $this})($this.find('[default_value]'))
123
124
  }
124
125
  }
125
126
  end
@@ -131,11 +132,11 @@ jQuery.fn.sets_default_value = function() {
131
132
  end
132
133
 
133
134
  it "makes a query" do
134
- assert_jabs "$#{@css}", "(function($this) {})(jQuery('#{@css}'));"
135
+ assert_jabs "$#{@css}", "return (function($this) { return $this})(jQuery('#{@css}'));"
135
136
  end
136
137
 
137
138
  it "renders iterator" do
138
- assert_jabs "$#{@css}\n this.rules();", "(function($this) {this.rules();})(jQuery('#{@css}'));"
139
+ assert_jabs "$#{@css}\n this.rules();", "return (function($this) {this.rules(); return $this})(jQuery('#{@css}'));"
139
140
  end
140
141
 
141
142
  # it "wraps with document.ready if not already wrapped" do
@@ -145,22 +146,35 @@ jQuery.fn.sets_default_value = function() {
145
146
 
146
147
  describe "events" do
147
148
  it "has a special :ready event" do
148
- assert_jabs(":ready", "jQuery(function() {\n (function($this) { })(jQuery(window));\n});")
149
+ assert_jabs(":ready", "jQuery(function() {\n return (function($this) { return $this})(jQuery(window));\n});")
149
150
  end
150
151
 
151
152
  it "has it's own $this" do
152
- assert_jabs ":click", "var $this = jQuery(this);"
153
+ assert_jabs %{
154
+ $element
155
+ :click
156
+ .hide
157
+ },
158
+ %{
159
+ return (function($this) {
160
+ $this.live("click", function(event) {
161
+ var $this = jQuery(this);
162
+ $this.hide();
163
+ });
164
+ return $this
165
+ })(jQuery("element"))
166
+ }
153
167
  end
154
168
 
155
169
  it "binds events to 'this' and preserves namespace" do
156
- assert_jabs ":click.awesomely", "$this.live(\"click.awesomely\", function(e){var $this = jQuery(this);});"
170
+ assert_jabs ":click.awesomely", "$this.live(\"click.awesomely\", function(event){var $this = jQuery(this);});"
157
171
  end
158
172
 
159
173
  it "renders callback" do
160
- assert_jabs ":click.awesomely\n a()\n b()", "$this.live(\"click.awesomely\", function(e){var $this = jQuery(this);a();b();});"
174
+ assert_jabs ":click.awesomely\n a()\n b()", "$this.live(\"click.awesomely\", function(event){var $this = jQuery(this);a();b();});"
161
175
  end
162
176
 
163
- it "compiles nested with anything with arbitraty javascript inbetween" do
177
+ it "compiles nested with anything with arbitrary javascript in between" do
164
178
  assert_jabs %{
165
179
  fun test
166
180
  var cat = yum
@@ -168,7 +182,7 @@ fun test
168
182
  },%{
169
183
  function test() {
170
184
  var cat = yum;
171
- $this.live( 'click', function(e) {var $this = jQuery(this);});
185
+ $this.live( 'click', function(event) {var $this = jQuery(this);});
172
186
  }
173
187
  }
174
188
  end
@@ -180,12 +194,13 @@ $document
180
194
  :click
181
195
  var cool = "beans"
182
196
  },%{
183
- (function($this) {
197
+ return (function($this) {
184
198
  cars++;
185
- $this.live('click', function(e) {
199
+ $this.live('click', function(event) {
186
200
  var $this = jQuery(this);
187
201
  var cool = "beans"
188
202
  });
203
+ return $this
189
204
  })(jQuery("document"));
190
205
  }
191
206
  end
@@ -197,7 +212,7 @@ var cat = poo
197
212
  slot++
198
213
  }, %{
199
214
  var cat = poo;
200
- $this.live('click', function(e) {
215
+ $this.live('click', function(event) {
201
216
  var $this = jQuery(this);
202
217
  slot++;
203
218
  });
@@ -208,11 +223,11 @@ $this.live('click', function(e) {
208
223
  describe "sub selections" do
209
224
  before(:each) {@css= "#some.convoluted:selector"}
210
225
  it "queries against this" do
211
- assert_jabs "&#{@css}", "(function($this) {})($this.find(\"#{@css}\"));"
226
+ assert_jabs "&#{@css}", "return (function($this) {return $this})($this.find(\"#{@css}\"));"
212
227
  end
213
228
 
214
229
  it "renders iterator" do
215
- assert_jabs "&#{@css}\n a()\n b()", "(function($this) {a();b();})($this.find(\"#{@css}\"));"
230
+ assert_jabs "&#{@css}\n a()\n b()", "return (function($this) {a();b(); return $this})($this.find(\"#{@css}\"));"
216
231
  end
217
232
  end
218
233
 
@@ -342,15 +357,62 @@ else unless 3 == 4
342
357
  end
343
358
  end
344
359
 
360
+ describe "hash literals" do
361
+ it "works for method calls" do
362
+ assert_jabs %{
363
+ def sortable parent_selector
364
+ $#selector
365
+ .clone
366
+ .css
367
+ position: 'absolute'
368
+ top: 5
369
+ },
370
+ %{
371
+ jQuery.fn.sortable = function(parent_selector) {
372
+ var $this = this;
373
+ return (function($this){
374
+ return (function($this){
375
+ $this.css({
376
+ 'position': 'absolute',
377
+ 'top': 5
378
+ })
379
+ return $this
380
+ })($this.clone())
381
+ return $this
382
+ })(jQuery('#selector'))
383
+ }
384
+ }
385
+ end
386
+ end
387
+
345
388
  describe "nested function calls" do
346
- it "assumes previous line returns jquery object" do
389
+ it "assumes previous line returns jquery object without implied self" do
390
+ assert_jabs %{
391
+ :ready
392
+ object.targetElement
393
+ .call 'awesomely'
394
+ },
395
+ %{
396
+ jQuery(function() {
397
+ return (function($this) {
398
+ return (function($this) {
399
+ $this.call("awesomely");
400
+ return $this
401
+ })(jQuery(object.targetElement));
402
+ return $this
403
+ })(jQuery(window));
404
+ });
405
+ }
406
+ end
407
+ it "assumes previous line returns jquery object for implied self" do
347
408
  assert_jabs %{
348
409
  .methodA :val
349
410
  .methodB :name
350
411
  },
351
412
  %{
352
- (function($this){
413
+ return (function($this){
353
414
  $this.methodB('name')
415
+ return $this
354
416
  })($this.methodA('val'))
355
417
  }
356
418
  end