11 var Local = Local || {};
13 var fire = 'fireEvent', create = function(){
14 return new Element('div');
17 describe('Events API: Element', function(){
19 beforeEach(function(){
21 Local.fn = function(){
22 return Local.called++;
26 it('should add an Event to the Class', function(){
27 var object = create();
29 object.addEvent('event', Local.fn)[fire]('event');
31 expect(Local.called).toEqual(1);
34 it('should add multiple Events to the Class', function(){
38 })[fire]('event1')[fire]('event2');
40 expect(Local.called).toEqual(2);
43 it('should remove a specific method for an event', function(){
44 var object = create();
45 var x = 0, fn = function(){ x++; };
47 object.addEvent('event', Local.fn).addEvent('event', fn).removeEvent('event', Local.fn)[fire]('event');
50 expect(Local.called).toEqual(0);
53 it('should remove an event and its methods', function(){
54 var object = create();
55 var x = 0, fn = function(){ x++; };
57 object.addEvent('event', Local.fn).addEvent('event', fn).removeEvents('event')[fire]('event');
60 expect(Local.called).toEqual(0);
63 it('should remove all events', function(){
64 var object = create();
65 var x = 0, fn = function(){ x++; };
67 object.addEvent('event1', Local.fn).addEvent('event2', fn).removeEvents();
68 object[fire]('event1')[fire]('event2');
71 object.removeEvents()[fire]('event1')[fire]('event2');
74 expect(Local.called).toEqual(0);
77 it('should remove events with an object', function(){
78 var object = create();
84 object.addEvent('event1', function(){ Local.fn(); }).addEvents(events)[fire]('event1');
85 expect(Local.called).toEqual(2);
87 object.removeEvents(events);
88 object[fire]('event1');
89 expect(Local.called).toEqual(3);
91 object[fire]('event2');
92 expect(Local.called).toEqual(3);
95 it('should remove an event immediately', function(){
96 var object = create();
100 var three = function(){
104 object.addEvent('event', function(){
106 this.removeEvent('event', three);
107 }).addEvent('event', function(){
109 }).addEvent('event', three);
111 object[fire]('event');
112 expect(methods).toEqual([1, 2]);
114 object[fire]('event');
115 expect(methods).toEqual([1, 2, 1, 2]);
118 it('should be able to remove itself', function(){
119 var object = create();
123 var one = function(){
124 object.removeEvent('event', one);
127 var two = function(){
128 object.removeEvent('event', two);
131 var three = function(){
135 object.addEvent('event', one).addEvent('event', two).addEvent('event', three);
137 object[fire]('event');
138 expect(methods).toEqual([1, 2, 3]);
140 object[fire]('event');
141 expect(methods).toEqual([1, 2, 3, 3]);
146 var fragment = document.createDocumentFragment();
148 // Restore native fireEvent in IE for Syn
149 var createElement = function(tag, props){
150 var el = new Element(tag);
151 if (el._fireEvent) el.fireEvent = el._fireEvent;
152 return el.set(props);
155 describe('Element.Event', function(){
157 it('Should trigger the click event', function(){
159 var callback = jasmine.createSpy('Element.Event click');
161 var el = createElement('a', {
171 }).inject(document.body);
173 Syn.trigger('click', null, el);
175 expect(callback).toHaveBeenCalled();
179 it('Should trigger the click event and prevent the default behavior', function(){
181 var callback = jasmine.createSpy('Element.Event click with prevent');
183 var el = createElement('a', {
191 click: function(event){
192 event.preventDefault();
196 }).inject(document.body);
198 Syn.trigger('click', null, el);
200 expect(callback).toHaveBeenCalled();
205 if (window.postMessage && !navigator.userAgent.match(/phantomjs/i)) it('Should trigger message event', function(){
207 var theMessage, spy = jasmine.createSpy('message');
208 window.addEvent('message', function(e){
209 theMessage = e.event.data;
212 window.postMessage('I am a message from outer space...', '*');
215 expect(spy).toHaveBeenCalled();
216 expect(theMessage).toEqual('I am a message from outer space...');
220 it('Should watch for a key-down event', function(){
222 var callback = jasmine.createSpy('keydown');
224 var div = createElement('div').addEvent('keydown', function(event){
226 }).inject(document.body);
230 expect(callback).toHaveBeenCalledWith('a');
234 it('should clone events of an element', function(){
238 var element = new Element('div').addEvent('click', function(){ calls++; });
239 element.fireEvent('click');
241 expect(calls).toBe(1);
243 var clone = new Element('div').cloneEvents(element, 'click');
244 clone.fireEvent('click');
246 expect(calls).toBe(2);
248 element.addEvent('custom', function(){ calls += 2; }).fireEvent('custom');
250 expect(calls).toBe(4);
252 clone.cloneEvents(element);
253 clone.fireEvent('click');
255 expect(calls).toBe(5);
257 clone.fireEvent('custom');
259 expect(calls).toBe(7);
264 describe('Element.Event', function(){
265 // This is private API. Do not use.
267 it('should pass the name of the custom event to the callbacks', function(){
269 var callback = jasmine.createSpy('Element.Event custom');
271 var fn = function(anything, type){
272 expect(type).toEqual('customEvent');
275 Element.Events.customEvent = {
279 condition: function(event, type){
289 var div = createElement('div').addEvent('customEvent', callback).inject(document.body);
291 Syn.trigger('click', null, div);
293 expect(callback).toHaveBeenCalled();
294 div.removeEvent('customEvent', callback).destroy();
295 expect(callbacks).toEqual(3);
300 describe('Element.Event.change', function(){
302 it('should not fire "change" for any property', function(){
303 var callback = jasmine.createSpy('Element.Event.change');
305 var radio = new Element('input', {
307 'class': 'someClass',
309 }).addEvent('change', callback).inject(document.body);
311 radio.removeClass('someClass');
312 expect(callback).not.toHaveBeenCalled();
314 var checkbox = new Element('input', {
316 'class': 'someClass',
318 }).addEvent('change', callback).inject(document.body);
320 checkbox.removeClass('someClass');
321 expect(callback).not.toHaveBeenCalled();
323 var text = new Element('input', {
325 'class': 'otherClass',
326 'value': 'text value'
327 }).addEvent('change', callback).inject(document.body);
329 text.removeClass('otherClass');
330 expect(callback).not.toHaveBeenCalled();
332 [radio, checkbox, text].invoke('destroy');
337 describe('Element.Event keyup with f<key>', function(){
339 it('should pass event.key == f2 when pressing f2 on keyup and keydown', function(){
341 var keydown = jasmine.createSpy('keydown');
342 var keyup = jasmine.createSpy('keyup');
344 var div = createElement('div')
345 .addEvent('keydown', function(event){
348 .addEvent('keyup', function(event){
351 .inject(document.body);
353 Syn.trigger('keydown', 'f2', div);
354 Syn.trigger('keyup', 'f2', div);
356 expect(keydown).toHaveBeenCalledWith('f2');
357 expect(keyup).toHaveBeenCalledWith('f2');
365 describe('Keypress key code', function(){
368 // return early for IE8- because Syn.js does not fire events
369 if (!document.addEventListener) return;
372 var input, key, shift, done;
373 DOMEvent.defineKey(33, 'pageup');
375 function keyHandler(e){
377 shift = !!e.event.shiftKey;
380 function typeWriter(action){
381 setTimeout(function () {
382 Syn.type(action, 'keyTester');
384 if (done) return true;
387 beforeEach(function(){
388 input = new Element('input', {
391 }).addEvent('keypress', keyHandler).inject(document.body);
394 afterEach(function(){
395 input.removeEvent('keypress', keyHandler).destroy();
396 input = key = shift = done = null;
399 it('should return "enter" in event.key', function(){
400 typeWriter('[enter]');
403 expect(key).toBe('enter');
404 expect(shift).not.toBeTruthy();
408 it('should return "1" in event.key', function(){
412 expect(key).toBe('1');
413 expect(shift).not.toBeTruthy();
417 it('should return "!" when pressing SHIFT + 1', function(){
418 typeWriter('[shift]![shift-up]');
421 expect(key).toBe('!');
422 expect(shift).toBeTruthy();
426 it('should map code 33 correctly with keypress event', function(){
427 var mock = {type: 'keypress', which: 33, shiftKey: true};
428 var e = new DOMEvent(mock);
429 expect(e.key).toBe('!');
434 describe('Element.removeEvent', function(){
436 it('should remove the onunload method', function(){
438 var handler = function(){ text = 'nope'; };
439 window.addEvent('unload', handler);
440 window.removeEvent('unload', handler);
441 window.fireEvent('unload');
442 expect(text).toBe(undefined);
448 describe('relatedTarget', function () {
450 var outer = new Element('div');
451 var el = new Element('div').inject(outer);
452 ['mouseenter', 'mouseleave', 'mouseover', 'mouseout'].each(function(event, i){
453 it('should listen to a ' + event + ' event and set the correct relatedTarget', function(){
454 var mockEvent = {type: event};
455 mockEvent[(i % 2 == 0 ? 'from' : 'to') + 'Element'] = outer; // simulate FF that does not set relatedTarget
457 var e = new DOMEvent(mockEvent);
458 expect(e.type).toBe(event);
459 expect(e.relatedTarget).toBe(outer);
465 describe('Mouse wheel', function(){
467 function attachProperties(e, direction){
468 e.detail = 1 * direction;
469 e.wheelDelta = 1 * direction;
470 e.deltaY = -1 * direction;
473 function dispatchFakeWheel(type, wheelDirection){
478 event = document.createEvent("MouseEvents");
479 event.initMouseEvent(type, true, true, window, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, null);
480 attachProperties(event, wheelDirection);
481 window.dispatchEvent(event);
485 // Chrome, PhantomJS, Safari
486 event = document.createEvent("WheelEvent");
487 event.initMouseEvent(type, 0, 100, window, 0, 0, 0, 0, null, null, null, null);
488 attachProperties(event, wheelDirection);
489 window.dispatchEvent(event);
494 event = document.createEvent("HTMLEvents");
495 event.initEvent(type, true, false);
496 attachProperties(event, wheelDirection);
497 window.dispatchEvent(event);
502 var event = document.createEvent("MouseEvents");
503 event.initEvent(type, true, true);
504 attachProperties(event, wheelDirection);
505 window.dispatchEvent(event);
510 var event = document.createEventObject();
511 document.documentElement.fireEvent(type, event);
515 var triggered = false;
517 var testWheel = !!window.addEventListener;
518 var callback = function(e){
519 if (e.wheel) wheel = e.wheel > 0 ? 'wheel moved up' : 'wheel moved down';
520 triggered = 'triggered';
523 beforeEach(function(){
524 wheel = triggered = false;
525 window.addEvent('mousewheel', callback);
526 document.documentElement.addEvent('mousewheel', callback);
529 afterEach(function(){
530 window.removeEvent('mousewheel', callback);
531 document.documentElement.removeEvent('mousewheel', callback);
534 it('should trigger/listen to mousewheel event', function(){
535 // http://jsfiddle.net/W6QrS/3
537 ['mousewheel', 'wheel' ,'DOMMouseScroll' ].each(dispatchFakeWheel);
538 expect(triggered).toBeTruthy();
541 it('should listen to mouse wheel direction', function(){
542 // http://jsfiddle.net/58yCr/
544 if (!testWheel) return;
546 // fire event with wheel going up
547 ['mousewheel', 'wheel' ,'DOMMouseScroll' ].each(function(type){
548 dispatchFakeWheel(type, 120);
550 expect(wheel).toEqual('wheel moved up');
553 // fire event with wheel going down
554 ['mousewheel', 'wheel' ,'DOMMouseScroll' ].each(function(type){
555 dispatchFakeWheel(type, -120);
557 expect(wheel).toEqual('wheel moved down');