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).to.equal(1);
34 it('should add multiple Events to the Class', function(){
38 })[fire]('event1')[fire]('event2');
40 expect(Local.called).to.equal(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');
49 expect(x).to.equal(1);
50 expect(Local.called).to.equal(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');
59 expect(x).to.equal(0);
60 expect(Local.called).to.equal(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');
73 expect(x).to.equal(0);
74 expect(Local.called).to.equal(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).to.equal(2);
87 object.removeEvents(events);
88 object[fire]('event1');
89 expect(Local.called).to.equal(3);
91 object[fire]('event2');
92 expect(Local.called).to.equal(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).to.eql([1, 2]);
114 object[fire]('event');
115 expect(methods).to.eql([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).to.eql([1, 2, 3]);
140 object[fire]('event');
141 expect(methods).to.eql([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 = sinon.spy();
161 var el = createElement('a', {
171 }).inject(document.body);
173 syn.trigger(el, 'click');
175 expect(callback.called).to.equal(true);
179 it('Should trigger the click event and prevent the default behavior', function(){
181 var callback = sinon.spy();
183 var el = createElement('a', {
191 click: function(event){
192 event.preventDefault();
196 }).inject(document.body);
198 syn.trigger(el, 'click');
200 expect(callback.called).to.equal(true);
205 var ddescribe = (window.postMessage && !navigator.userAgent.match(/phantomjs/i)) ? describe : xdescribe;
206 ddescribe('(async)', function(){
208 beforeEach(function(done){
210 this.spy = sinon.spy();
212 window.addEvent('message', function(e){
213 self.message = e.event.data;
216 window.postMessage('I am a message from outer space...', '*');
217 setTimeout(done, 150);
220 it('Should trigger a message event', function(){
221 expect(this.spy.called).to.equal(true);
222 expect(this.message).to.equal('I am a message from outer space...');
226 it('Should watch for a key-down event', function(){
228 var callback = sinon.spy();
230 var div = createElement('div').addEvent('keydown', function(event){
232 }).inject(document.body);
236 expect(callback.calledWith('a')).to.equal(true);
240 it('should clone events of an element', function(){
244 var element = new Element('div').addEvent('click', function(){ calls++; });
245 element.fireEvent('click');
247 expect(calls).to.equal(1);
249 var clone = new Element('div').cloneEvents(element, 'click');
250 clone.fireEvent('click');
252 expect(calls).to.equal(2);
254 element.addEvent('custom', function(){ calls += 2; }).fireEvent('custom');
256 expect(calls).to.equal(4);
258 clone.cloneEvents(element);
259 clone.fireEvent('click');
261 expect(calls).to.equal(5);
263 clone.fireEvent('custom');
265 expect(calls).to.equal(7);
270 describe('Element.Event', function(){
271 // This is private API. Do not use.
273 it('should pass the name of the custom event to the callbacks', function(){
275 var callback = sinon.spy();
277 var fn = function(anything, type){
278 expect(type).to.equal('customEvent');
281 Element.Events.customEvent = {
285 condition: function(event, type){
295 var div = createElement('div').addEvent('customEvent', callback).inject(document.body);
297 syn.trigger(div, 'click');
299 expect(callback.called).to.equal(true);
300 div.removeEvent('customEvent', callback).destroy();
301 expect(callbacks).to.equal(3);
306 describe('Element.Event.change', function(){
308 it('should not fire "change" for any property', function(){
309 var callback = sinon.spy();
311 var radio = new Element('input', {
313 'class': 'someClass',
315 }).addEvent('change', callback).inject(document.body);
317 radio.removeClass('someClass');
318 expect(callback.called).to.equal(false);
320 var checkbox = new Element('input', {
322 'class': 'someClass',
324 }).addEvent('change', callback).inject(document.body);
326 checkbox.removeClass('someClass');
327 expect(callback.called).to.equal(false);
329 var text = new Element('input', {
331 'class': 'otherClass',
332 'value': 'text value'
333 }).addEvent('change', callback).inject(document.body);
335 text.removeClass('otherClass');
336 expect(callback.called).to.equal(false);
338 [radio, checkbox, text].invoke('destroy');
343 describe('Element.Event keyup with f<key>', function(){
345 it('should pass event.key == f2 when pressing f2 on keyup and keydown', function(){
347 var keydown = sinon.spy();
348 var keyup = sinon.spy();
350 var div = createElement('div')
351 .addEvent('keydown', function(event){
354 .addEvent('keyup', function(event){
357 .inject(document.body);
359 syn.trigger(div, 'keydown', 'f2');
360 syn.trigger(div, 'keyup', 'f2');
362 expect(keydown.calledWith('f2')).to.equal(true);
363 expect(keyup.calledWith('f2')).to.equal(true);
371 describe('Keypress key code', function(){
374 // return early for IE8- because Syn.js does not fire events
375 if (!document.addEventListener) return;
378 var input, key, shift, done;
379 DOMEvent.defineKey(33, 'pageup');
381 var tests = ['[enter]', '1', '[shift]![shift-up]'];
383 function keyHandler(e){
385 shift = !!e.event.shiftKey;
388 function typeWriter(action){
389 setTimeout(function () {
390 syn.type('keyTester', action);
392 if (done) return true;
395 beforeEach(function(done){
396 input = new Element('input', {
399 }).addEvent('keypress', keyHandler).inject(document.body);
401 var test = tests.shift();
404 setTimeout(done, 50);
410 afterEach(function(){
411 input.removeEvent('keypress', keyHandler).destroy();
412 input = key = shift = done = null;
415 it('should return "enter" in event.key', function(){
416 expect(key).to.equal('enter');
417 expect(shift).to.equal(false);
420 it('should return "1" in event.key', function(){
421 expect(key).to.equal('1');
422 expect(shift).to.equal(false);
425 it('should return "!" when pressing SHIFT + 1', function(){
426 expect(key).to.equal('!');
427 expect(shift).to.equal(true);
430 it('should map code 33 correctly with keypress event', function(){
431 var mock = {type: 'keypress', which: 33, shiftKey: true};
432 var e = new DOMEvent(mock);
433 expect(e.key).to.equal('!');
438 describe('Element.removeEvent', function(){
440 it('should remove the onunload method', function(){
442 var handler = function(){ text = 'nope'; };
443 window.addEvent('unload', handler);
444 window.removeEvent('unload', handler);
445 window.fireEvent('unload');
446 expect(text).to.equal(undefined);
452 describe('relatedTarget', function () {
454 var outer = new Element('div');
455 var el = new Element('div').inject(outer);
456 ['mouseenter', 'mouseleave', 'mouseover', 'mouseout'].each(function(event, i){
457 it('should listen to a ' + event + ' event and set the correct relatedTarget', function(){
458 var mockEvent = {type: event};
459 mockEvent[(i % 2 == 0 ? 'from' : 'to') + 'Element'] = outer; // simulate FF that does not set relatedTarget
461 var e = new DOMEvent(mockEvent);
462 expect(e.type).to.equal(event);
463 expect(e.relatedTarget).to.equal(outer);
469 describe('Mouse wheel', function(){
471 function attachProperties(e, direction){
472 e.detail = 1 * direction;
473 e.wheelDelta = 1 * direction;
474 e.deltaY = -1 * direction;
477 function dispatchFakeWheel(type, wheelDirection){
482 event = document.createEvent("MouseEvents");
483 event.initMouseEvent(type, true, true, window, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, null);
484 attachProperties(event, wheelDirection);
485 window.dispatchEvent(event);
489 // Chrome, PhantomJS, Safari
490 event = document.createEvent("WheelEvent");
491 event.initMouseEvent(type, 0, 100, window, 0, 0, 0, 0, null, null, null, null);
492 attachProperties(event, wheelDirection);
493 window.dispatchEvent(event);
498 event = document.createEvent("HTMLEvents");
499 event.initEvent(type, true, false);
500 attachProperties(event, wheelDirection);
501 window.dispatchEvent(event);
506 var event = document.createEvent("MouseEvents");
507 event.initEvent(type, true, true);
508 attachProperties(event, wheelDirection);
509 window.dispatchEvent(event);
514 var event = document.createEventObject();
515 document.documentElement.fireEvent(type, event);
519 var triggered = false;
521 var testWheel = !!window.addEventListener;
522 var callback = function(e){
523 if (e.wheel) wheel = e.wheel > 0 ? 'wheel moved up' : 'wheel moved down';
527 beforeEach(function(){
528 wheel = triggered = false;
529 window.addEvent('mousewheel', callback);
530 document.documentElement.addEvent('mousewheel', callback);
533 afterEach(function(){
534 window.removeEvent('mousewheel', callback);
535 document.documentElement.removeEvent('mousewheel', callback);
538 it('should trigger/listen to mousewheel event', function(){
539 // http://jsfiddle.net/W6QrS/3
541 ['mousewheel', 'wheel' ,'DOMMouseScroll' ].each(dispatchFakeWheel);
542 expect(triggered).to.equal(true);
545 it('should listen to mouse wheel direction', function(){
546 // http://jsfiddle.net/58yCr/
548 if (!testWheel) return;
550 // fire event with wheel going up
551 ['mousewheel', 'wheel' ,'DOMMouseScroll' ].each(function(type){
552 dispatchFakeWheel(type, 120);
554 expect(wheel).to.equal('wheel moved up');
557 // fire event with wheel going down
558 ['mousewheel', 'wheel' ,'DOMMouseScroll' ].each(function(type){
559 dispatchFakeWheel(type, -120);
561 expect(wheel).to.equal('wheel moved down');