jabs 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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