UNPKG

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