1 |
|
2 | define(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 |