UNPKG

18.1 kBJavaScriptView Raw
1/*syn@0.14.0#synthetic*/
2var opts = window.syn ? window.syn : {};
3var extend = function (d, s) {
4 var p;
5 for (p in s) {
6 d[p] = s[p];
7 }
8 return d;
9 }, browser = {
10 msie: !!(window.attachEvent && !window.opera) || navigator.userAgent.indexOf('Trident/') > -1,
11 opera: !!window.opera,
12 webkit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
13 safari: navigator.userAgent.indexOf('AppleWebKit/') > -1 && navigator.userAgent.indexOf('Chrome/') === -1,
14 gecko: navigator.userAgent.indexOf('Gecko') > -1,
15 mobilesafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/),
16 rhino: navigator.userAgent.match(/Rhino/) && true,
17 chrome: !!window.chrome && !!window.chrome.webstore
18 }, createEventObject = function (type, options, element) {
19 var event = element.ownerDocument.createEventObject();
20 return extend(event, options);
21 }, data = {}, id = 1, expando = '_synthetic' + new Date().getTime(), bind, unbind, schedule, key = /keypress|keyup|keydown/, page = /load|unload|abort|error|select|change|submit|reset|focus|blur|resize|scroll/, activeElement, syn = function (type, element, options, callback) {
22 return new syn.init(type, element, options, callback);
23 };
24syn.config = opts;
25syn.__tryFocus = function tryFocus(element) {
26 try {
27 element.focus();
28 } catch (e) {
29 }
30};
31bind = function (el, ev, f) {
32 return el.addEventListener ? el.addEventListener(ev, f, false) : el.attachEvent('on' + ev, f);
33};
34unbind = function (el, ev, f) {
35 return el.addEventListener ? el.removeEventListener(ev, f, false) : el.detachEvent('on' + ev, f);
36};
37schedule = syn.config.schedule || function (fn, ms) {
38 setTimeout(fn, ms);
39};
40extend(syn, {
41 init: function (type, element, options, callback) {
42 var args = syn.args(options, element, callback), self = this;
43 this.queue = [];
44 this.element = args.element;
45 if (typeof this[type] === 'function') {
46 this[type](args.element, args.options, function (defaults, el) {
47 if (args.callback) {
48 args.callback.apply(self, arguments);
49 }
50 self.done.apply(self, arguments);
51 });
52 } else {
53 this.result = syn.trigger(args.element, type, args.options);
54 if (args.callback) {
55 args.callback.call(this, args.element, this.result);
56 }
57 }
58 },
59 jquery: function (el, fast) {
60 if (window.FuncUnit && window.FuncUnit.jQuery) {
61 return window.FuncUnit.jQuery;
62 }
63 if (el) {
64 return syn.helpers.getWindow(el).jQuery || window.jQuery;
65 } else {
66 return window.jQuery;
67 }
68 },
69 args: function () {
70 var res = {}, i = 0;
71 for (; i < arguments.length; i++) {
72 if (typeof arguments[i] === 'function') {
73 res.callback = arguments[i];
74 } else if (arguments[i] && arguments[i].jquery) {
75 res.element = arguments[i][0];
76 } else if (arguments[i] && arguments[i].nodeName) {
77 res.element = arguments[i];
78 } else if (res.options && typeof arguments[i] === 'string') {
79 res.element = document.getElementById(arguments[i]);
80 } else if (arguments[i]) {
81 res.options = arguments[i];
82 }
83 }
84 return res;
85 },
86 click: function (element, options, callback) {
87 syn('click!', element, options, callback);
88 },
89 defaults: {
90 focus: function focus() {
91 if (!syn.support.focusChanges) {
92 var element = this, nodeName = element.nodeName.toLowerCase();
93 syn.data(element, 'syntheticvalue', element.value);
94 if (nodeName === 'input' || nodeName === 'textarea') {
95 bind(element, 'blur', function blur() {
96 if (syn.data(element, 'syntheticvalue') !== element.value) {
97 syn.trigger(element, 'change', {});
98 }
99 unbind(element, 'blur', blur);
100 });
101 }
102 }
103 },
104 submit: function () {
105 syn.onParents(this, function (el) {
106 if (el.nodeName.toLowerCase() === 'form') {
107 el.submit();
108 return false;
109 }
110 });
111 }
112 },
113 changeOnBlur: function (element, prop, value) {
114 bind(element, 'blur', function onblur() {
115 if (value !== element[prop]) {
116 syn.trigger(element, 'change', {});
117 }
118 unbind(element, 'blur', onblur);
119 });
120 },
121 closest: function (el, type) {
122 while (el && el.nodeName.toLowerCase() !== type.toLowerCase()) {
123 el = el.parentNode;
124 }
125 return el;
126 },
127 data: function (el, key, value) {
128 var d;
129 if (!el[expando]) {
130 el[expando] = id++;
131 }
132 if (!data[el[expando]]) {
133 data[el[expando]] = {};
134 }
135 d = data[el[expando]];
136 if (value) {
137 data[el[expando]][key] = value;
138 } else {
139 return data[el[expando]][key];
140 }
141 },
142 onParents: function (el, func) {
143 var res;
144 while (el && res !== false) {
145 res = func(el);
146 el = el.parentNode;
147 }
148 return el;
149 },
150 focusable: /^(a|area|frame|iframe|label|input|select|textarea|button|html|object)$/i,
151 isFocusable: function (elem) {
152 var attributeNode;
153 if (elem.getAttributeNode) {
154 attributeNode = elem.getAttributeNode('tabIndex');
155 }
156 return this.focusable.test(elem.nodeName) || attributeNode && attributeNode.specified && syn.isVisible(elem);
157 },
158 isVisible: function (elem) {
159 return elem.offsetWidth && elem.offsetHeight || elem.clientWidth && elem.clientHeight;
160 },
161 tabIndex: function (elem) {
162 var attributeNode = elem.getAttributeNode('tabIndex');
163 return attributeNode && attributeNode.specified && (parseInt(elem.getAttribute('tabIndex')) || 0);
164 },
165 bind: bind,
166 unbind: unbind,
167 schedule: schedule,
168 browser: browser,
169 helpers: {
170 createEventObject: createEventObject,
171 createBasicStandardEvent: function (type, defaults, doc) {
172 var event;
173 try {
174 event = doc.createEvent('Events');
175 } catch (e2) {
176 event = doc.createEvent('UIEvents');
177 } finally {
178 event.initEvent(type, true, true);
179 extend(event, defaults);
180 }
181 return event;
182 },
183 inArray: function (item, array) {
184 var i = 0;
185 for (; i < array.length; i++) {
186 if (array[i] === item) {
187 return i;
188 }
189 }
190 return -1;
191 },
192 getWindow: function (element) {
193 if (element.ownerDocument) {
194 return element.ownerDocument.defaultView || element.ownerDocument.parentWindow;
195 }
196 },
197 extend: extend,
198 scrollOffset: function (win, set) {
199 var doc = win.document.documentElement, body = win.document.body;
200 if (set) {
201 window.scrollTo(set.left, set.top);
202 } else {
203 return {
204 left: (doc && doc.scrollLeft || body && body.scrollLeft || 0) + (doc.clientLeft || 0),
205 top: (doc && doc.scrollTop || body && body.scrollTop || 0) + (doc.clientTop || 0)
206 };
207 }
208 },
209 scrollDimensions: function (win) {
210 var doc = win.document.documentElement, body = win.document.body, docWidth = doc.clientWidth, docHeight = doc.clientHeight, compat = win.document.compatMode === 'CSS1Compat';
211 return {
212 height: compat && docHeight || body.clientHeight || docHeight,
213 width: compat && docWidth || body.clientWidth || docWidth
214 };
215 },
216 addOffset: function (options, el) {
217 var jq = syn.jquery(el), off;
218 if (typeof options === 'object' && options.clientX === undefined && options.clientY === undefined && options.pageX === undefined && options.pageY === undefined && jq) {
219 el = jq(el);
220 off = el.offset();
221 options.pageX = off.left + el.width() / 2;
222 options.pageY = off.top + el.height() / 2;
223 }
224 }
225 },
226 key: {
227 ctrlKey: null,
228 altKey: null,
229 shiftKey: null,
230 metaKey: null
231 },
232 dispatch: function (event, element, type, autoPrevent) {
233 if (element.dispatchEvent && event) {
234 var preventDefault = event.preventDefault, prevents = autoPrevent ? -1 : 0;
235 if (autoPrevent) {
236 bind(element, type, function ontype(ev) {
237 ev.preventDefault();
238 unbind(this, type, ontype);
239 });
240 }
241 event.preventDefault = function () {
242 prevents++;
243 if (++prevents > 0) {
244 preventDefault.apply(this, []);
245 }
246 };
247 element.dispatchEvent(event);
248 return prevents <= 0;
249 } else {
250 try {
251 window.event = event;
252 } catch (e) {
253 }
254 return element.sourceIndex <= 0 || element.fireEvent && element.fireEvent('on' + type, event);
255 }
256 },
257 create: {
258 page: {
259 event: function (type, options, element) {
260 var doc = syn.helpers.getWindow(element).document || document, event;
261 if (doc.createEvent) {
262 event = doc.createEvent('Events');
263 event.initEvent(type, true, true);
264 return event;
265 } else {
266 try {
267 event = createEventObject(type, options, element);
268 } catch (e) {
269 }
270 return event;
271 }
272 }
273 },
274 focus: {
275 event: function (type, options, element) {
276 syn.onParents(element, function (el) {
277 if (syn.isFocusable(el)) {
278 if (el.nodeName.toLowerCase() !== 'html') {
279 syn.__tryFocus(el);
280 activeElement = el;
281 } else if (activeElement) {
282 var doc = syn.helpers.getWindow(element).document;
283 if (doc !== window.document) {
284 return false;
285 } else if (doc.activeElement) {
286 doc.activeElement.blur();
287 activeElement = null;
288 } else {
289 activeElement.blur();
290 activeElement = null;
291 }
292 }
293 return false;
294 }
295 });
296 return true;
297 }
298 }
299 },
300 support: {
301 clickChanges: false,
302 clickSubmits: false,
303 keypressSubmits: false,
304 mouseupSubmits: false,
305 radioClickChanges: false,
306 focusChanges: false,
307 linkHrefJS: false,
308 keyCharacters: false,
309 backspaceWorks: false,
310 mouseDownUpClicks: false,
311 tabKeyTabs: false,
312 keypressOnAnchorClicks: false,
313 optionClickBubbles: false,
314 pointerEvents: false,
315 touchEvents: false,
316 ready: 0
317 },
318 trigger: function (element, type, options) {
319 if (!options) {
320 options = {};
321 }
322 var create = syn.create, setup = create[type] && create[type].setup, kind = key.test(type) ? 'key' : page.test(type) ? 'page' : 'mouse', createType = create[type] || {}, createKind = create[kind], event, ret, autoPrevent, dispatchEl = element;
323 if (syn.support.ready === 2 && setup) {
324 setup(type, options, element);
325 }
326 autoPrevent = options._autoPrevent;
327 delete options._autoPrevent;
328 if (createType.event) {
329 ret = createType.event(type, options, element);
330 } else {
331 options = createKind.options ? createKind.options(type, options, element) : options;
332 if (!syn.support.changeBubbles && /option/i.test(element.nodeName)) {
333 dispatchEl = element.parentNode;
334 }
335 event = createKind.event(type, options, dispatchEl);
336 ret = syn.dispatch(event, dispatchEl, type, autoPrevent);
337 }
338 if (ret && syn.support.ready === 2 && syn.defaults[type]) {
339 syn.defaults[type].call(element, options, autoPrevent);
340 }
341 return ret;
342 },
343 eventSupported: function (eventName) {
344 var el = document.createElement('div');
345 eventName = 'on' + eventName;
346 var isSupported = eventName in el;
347 if (!isSupported) {
348 el.setAttribute(eventName, 'return;');
349 isSupported = typeof el[eventName] === 'function';
350 }
351 el = null;
352 return isSupported;
353 }
354});
355extend(syn.init.prototype, {
356 then: function (type, element, options, callback) {
357 if (syn.autoDelay) {
358 this.delay();
359 }
360 var args = syn.args(options, element, callback), self = this;
361 this.queue.unshift(function (el, prevented) {
362 if (typeof this[type] === 'function') {
363 this.element = args.element || el;
364 this[type](this.element, args.options, function (defaults, el) {
365 if (args.callback) {
366 args.callback.apply(self, arguments);
367 }
368 self.done.apply(self, arguments);
369 });
370 } else {
371 this.result = syn.trigger(args.element, type, args.options);
372 if (args.callback) {
373 args.callback.call(this, args.element, this.result);
374 }
375 return this;
376 }
377 });
378 return this;
379 },
380 delay: function (timeout, callback) {
381 if (typeof timeout === 'function') {
382 callback = timeout;
383 timeout = null;
384 }
385 timeout = timeout || 600;
386 var self = this;
387 this.queue.unshift(function () {
388 schedule(function () {
389 if (callback) {
390 callback.apply(self, []);
391 }
392 self.done.apply(self, arguments);
393 }, timeout);
394 });
395 return this;
396 },
397 done: function (defaults, el) {
398 if (el) {
399 this.element = el;
400 }
401 if (this.queue.length) {
402 this.queue.pop().call(this, this.element, defaults);
403 }
404 },
405 '_click': function (element, options, callback, force) {
406 syn.helpers.addOffset(options, element);
407 if (syn.support.pointerEvents) {
408 syn.trigger(element, 'pointerdown', options);
409 }
410 if (syn.support.touchEvents) {
411 syn.trigger(element, 'touchstart', options);
412 }
413 syn.trigger(element, 'mousedown', options);
414 schedule(function () {
415 if (syn.support.pointerEvents) {
416 syn.trigger(element, 'pointerup', options);
417 }
418 if (syn.support.touchEvents) {
419 syn.trigger(element, 'touchend', options);
420 }
421 syn.trigger(element, 'mouseup', options);
422 if (!syn.support.mouseDownUpClicks || force) {
423 syn.trigger(element, 'click', options);
424 callback(true);
425 } else {
426 syn.create.click.setup('click', options, element);
427 syn.defaults.click.call(element);
428 schedule(function () {
429 callback(true);
430 }, 1);
431 }
432 }, 1);
433 },
434 '_rightClick': function (element, options, callback) {
435 syn.helpers.addOffset(options, element);
436 var mouseopts = extend(extend({}, syn.mouse.browser.right.mouseup), options);
437 if (syn.support.pointerEvents) {
438 syn.trigger(element, 'pointerdown', mouseopts);
439 }
440 syn.trigger(element, 'mousedown', mouseopts);
441 schedule(function () {
442 if (syn.support.pointerEvents) {
443 syn.trigger(element, 'pointerup', mouseopts);
444 }
445 syn.trigger(element, 'mouseup', mouseopts);
446 if (syn.mouse.browser.right.contextmenu) {
447 syn.trigger(element, 'contextmenu', extend(extend({}, syn.mouse.browser.right.contextmenu), options));
448 }
449 callback(true);
450 }, 1);
451 },
452 '_dblclick': function (element, options, callback) {
453 syn.helpers.addOffset(options, element);
454 var self = this;
455 this._click(element, options, function () {
456 schedule(function () {
457 self._click(element, options, function () {
458 syn.trigger(element, 'dblclick', options);
459 callback(true);
460 }, true);
461 }, 2);
462 });
463 }
464});
465var actions = [
466 'click',
467 'dblclick',
468 'move',
469 'drag',
470 'key',
471 'type',
472 'rightClick'
473 ], makeAction = function (name) {
474 syn[name] = function (element, options, callback) {
475 return syn('_' + name, element, options, callback);
476 };
477 syn.init.prototype[name] = function (element, options, callback) {
478 return this.then('_' + name, element, options, callback);
479 };
480 }, i = 0;
481for (; i < actions.length; i++) {
482 makeAction(actions[i]);
483}
484module.exports = syn;
\No newline at end of file