├── .gitattributes ├── LICENSE ├── .gitignore ├── README.md └── qatrix.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Disable LF normalization for all files 2 | * -text -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | [MIT LICENSE] 2 | 3 | Copyright (c) 2013 Angel Lai, http://qatrix.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | Software), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, andor sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | [Dd]ebug/ 46 | [Rr]elease/ 47 | *_i.c 48 | *_p.c 49 | *.ilk 50 | *.meta 51 | *.obj 52 | *.pch 53 | *.pdb 54 | *.pgc 55 | *.pgd 56 | *.rsp 57 | *.sbr 58 | *.tlb 59 | *.tli 60 | *.tlh 61 | *.tmp 62 | *.vspscc 63 | .builds 64 | *.dotCover 65 | 66 | ## TODO: If you have NuGet Package Restore enabled, uncomment this 67 | #packages/ 68 | 69 | # Visual C++ cache files 70 | ipch/ 71 | *.aps 72 | *.ncb 73 | *.opensdf 74 | *.sdf 75 | 76 | # Visual Studio profiler 77 | *.psess 78 | *.vsp 79 | 80 | # ReSharper is a .NET coding add-in 81 | _ReSharper* 82 | 83 | # Installshield output folder 84 | [Ee]xpress 85 | 86 | # DocProject is a documentation generator add-in 87 | DocProject/buildhelp/ 88 | DocProject/Help/*.HxT 89 | DocProject/Help/*.HxC 90 | DocProject/Help/*.hhc 91 | DocProject/Help/*.hhk 92 | DocProject/Help/*.hhp 93 | DocProject/Help/Html2 94 | DocProject/Help/html 95 | 96 | # Click-Once directory 97 | publish 98 | 99 | # Others 100 | [Bb]in 101 | [Oo]bj 102 | sql 103 | TestResults 104 | *.Cache 105 | ClientBin 106 | stylecop.* 107 | ~$* 108 | *.dbmdl 109 | Generated_Code #added for RIA/Silverlight projects 110 | 111 | # Backup & report files from converting an old project file to a newer 112 | # Visual Studio version. Backup files are not needed, because we have git ;-) 113 | _UpgradeReport_Files/ 114 | Backup*/ 115 | UpgradeLog*.XML 116 | 117 | 118 | 119 | ############ 120 | ## Windows 121 | ############ 122 | 123 | # Windows image file caches 124 | Thumbs.db 125 | 126 | # Folder config file 127 | Desktop.ini 128 | 129 | 130 | ############# 131 | ## Python 132 | ############# 133 | 134 | *.py[co] 135 | 136 | # Packages 137 | *.egg 138 | *.egg-info 139 | dist 140 | build 141 | eggs 142 | parts 143 | bin 144 | var 145 | sdist 146 | develop-eggs 147 | .installed.cfg 148 | 149 | # Installer logs 150 | pip-log.txt 151 | 152 | # Unit test / coverage reports 153 | .coverage 154 | .tox 155 | 156 | #Translations 157 | *.mo 158 | 159 | #Mr Developer 160 | .mr.developer.cfg 161 | 162 | # Mac crap 163 | .DS_Store 164 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Qatrix - Easily build up high-performance applications with less code. 2 | 3 | > This project is no longer maintained. 4 | 5 | Qatrix is a new kind of JavaScript framework targeting building up high-performance and flexible web applications with less code and friendly construction. It`s free and open source. 6 | 7 | Designed to simplify the script with friendly and easy-to-learn code construction and noticeably increase the performance and efficiency of the development of web applications. 8 | 9 | ### Main Features 10 | 11 | * **Hardware accelerated animation** - The first framework supports hardware-accelerated native CSS3 transition for animation. The animation of Qatrix will be impressively faster and smoother than other frameworks. Significantly improved the visual effects on the web application. 12 | 13 | * **High performance code** - Supports CSS3 and HTML5. Qatrix is using more native code and special design to increase performance. The web application will run much faster and more efficiently than other frameworks about 50% on average. 14 | 15 | * **Easy-to-learn** - The names of functions on Qatrix are simple, user-friendly, and familiar with jQuery. It will be much easier to use without re-learn other new concepts and knowledge. 16 | 17 | * **Incredible size** - Only 6KB compressed and gzipped file size with 60+ functions, including hardware accelerated animation, DOM, AJAX, template, require loader, various selectors, cookie, event handle, local storage, and so on, enough for most common web development needs. Load powerful script instantly without expectation. 18 | 19 | ### Quick start 20 | 21 | #### DOM & Animation 22 | ```JavaScript 23 | $tag($('wrap'), 'div', function (item) { 24 | $html(item, 'some value'); 25 | }); 26 | 27 | $hide($('element_id')); 28 | 29 | $hide($('element_id_1 element_id_2 element_id_3'), 500); 30 | 31 | $animate($("element"), { 32 | "width": { 33 | from: 200, 34 | to: 30 35 | } 36 | }, 500, function () { 37 | // Do something 38 | }); 39 | ``` 40 | 41 | #### AJAX 42 | ```JavaScript 43 | $ajax("example.php", { 44 | data: { 45 | "foo": "bar" 46 | }, 47 | success: function (data) { 48 | // Do something 49 | } 50 | }); 51 | ``` 52 | 53 | #### Template 54 | ```JavaScript 55 | var template = "

{{header}}

{{header2}}

"; 56 | 57 | var data = { 58 | header: "Header", 59 | header2: "Header2", 60 | header3: "Header3", 61 | list: ["1", "2", "3"], 62 | people: [ 63 | {"name": "Tom", "city": "California"}, 64 | {"name": "Jack", "city": "Newton"}, 65 | {"name": "Jone", "city": "Tokyo"} 66 | ] 67 | }; 68 | 69 | $append($("container"), $template(template, data)); 70 | ``` 71 | 72 | #### Require 73 | ```JavaScript 74 | $require([ 75 | "http://abc.com/foo.js", 76 | "http://abc.com/foo.css" 77 | ], function () { 78 | // Do something 79 | }); 80 | ``` 81 | 82 | #### Cookie & storage 83 | ```JavaScript 84 | $cookie.set("foo", "bar"); 85 | $storage.set("foo", "bar"); 86 | ``` 87 | 88 | ### License 89 | 90 | Qatrix is under the MIT license. You can freely use or distribute your project as long as declaring the original copyright information. 91 | 92 | ### Compatibility 93 | 94 | IE6+, Chrome, Firefox 2+, Safari 3+, Opera 9+. 95 | 96 | ### Benchmark 97 | 98 | Template (500% faster) - [http://jsperf.com/dom-vs-innerhtml-based-templating/735](http://jsperf.com/dom-vs-innerhtml-based-templating/735) 99 | -------------------------------------------------------------------------------- /qatrix.js: -------------------------------------------------------------------------------- 1 | /* 2 | Qatrix JavaScript v1.1.2 3 | 4 | Copyright (c) 2013, Angel Lai 5 | The Qatrix project is under MIT license. 6 | For details, see the Qatrix website: http://qatrix.com 7 | */ 8 | 9 | (function (window, document, undefined) { 10 | 11 | var 12 | version = '1.1.2', 13 | 14 | docElem = document.documentElement, 15 | 16 | rbline = /(^\n+)|(\n+$)/g, 17 | rbrace = /^(?:\{.*\}|\[.*\])$/, 18 | rcamelCase = /-([a-z])/ig, 19 | rdigit = /\d/, 20 | rline = /\r\n/g, 21 | rnum = /[\-\+0-9\.]/ig, 22 | rspace = /\s+/, 23 | rquery = /\?/, 24 | ropacity = /opacity=([^)]*)/, 25 | rvalidchars = /^[\],:{}\s]*$/, 26 | rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g, 27 | rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g, 28 | rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, 29 | 30 | animDisplay = 'height margin-top margin-bottom padding-top padding-bottom'.split(' '), 31 | 32 | // For $require loaded resource 33 | require_loaded = {}, 34 | 35 | // For complied template 36 | template_cache = {}, 37 | 38 | // For DOM ready 39 | readyList = [], 40 | ready = function () 41 | { 42 | $each(readyList, function (i, callback) 43 | { 44 | callback(); 45 | }); 46 | document.removeEventListener('DOMContentLoaded', ready, false); 47 | }, 48 | 49 | // For $append, $prepend, $before, $after 50 | nodeManip = function (elem, node) 51 | { 52 | var type = typeof node; 53 | 54 | if (type === 'string') 55 | { 56 | var doc = elem && elem.ownerDocument || document, 57 | fragment = doc.createDocumentFragment(), 58 | div = $new('div'), 59 | ret = []; 60 | 61 | div.innerHTML = node; 62 | while (div.childNodes[0] != null) 63 | { 64 | fragment.appendChild(div.childNodes[0]); 65 | } 66 | node = fragment; 67 | 68 | // Release memory 69 | div = null; 70 | } 71 | 72 | if (type === 'number') 73 | { 74 | node += ''; 75 | } 76 | 77 | return node; 78 | }, 79 | 80 | // For map function callback 81 | mapcall = function (match, callback) 82 | { 83 | if (match === null) 84 | { 85 | return; 86 | } 87 | 88 | if (callback === undefined) 89 | { 90 | return match; 91 | } 92 | 93 | var i = 0, 94 | length = match.length; 95 | 96 | if (length !== undefined && length > 0) 97 | { 98 | for (; i < length;) 99 | { 100 | if (callback.call(match[i], match[i], match[i++]) === false) 101 | { 102 | break; 103 | } 104 | } 105 | 106 | return match; 107 | } 108 | else 109 | { 110 | return callback.call(match, match); 111 | } 112 | }, 113 | 114 | // For $show and $hide 115 | displayElem = function (elem, type, duration, callback) 116 | { 117 | return mapcall(elem, function (elem) 118 | { 119 | var prop = {}, 120 | show = type === 'show', 121 | style = elem.style, 122 | display = elem['_display'], 123 | temp, overflow; 124 | 125 | if (!display) 126 | { 127 | display = $style.get(elem, 'display'); 128 | if (display === 'none' || display === 'inherit') 129 | { 130 | temp = $append(document.body, $new(elem.nodeName)); 131 | display = $style.get(temp, 'display'); 132 | $remove(temp); 133 | } 134 | elem['_display'] = display; 135 | } 136 | 137 | if (show) 138 | { 139 | style.display = display; 140 | } 141 | else 142 | { 143 | display = 'none'; 144 | } 145 | 146 | if (duration) 147 | { 148 | overflow = $style.get(elem, 'overflow'); 149 | style.overflow = 'hidden'; 150 | 151 | prop.opacity = show ? { 152 | from: 0, 153 | to: 1 154 | } : { 155 | from: 1, 156 | to: 0 157 | }; 158 | 159 | $each(animDisplay, function (i, css) 160 | { 161 | prop[css] = show ? { 162 | from: 0, 163 | to: $style.get(elem, css) 164 | } : 0; 165 | }); 166 | $animate(elem, prop, duration, function () 167 | { 168 | $each(animDisplay, function (i, css) 169 | { 170 | $css.set(elem, css, ''); 171 | }); 172 | style.filter = style.opacity = style.overflow = ''; 173 | style.display = display; 174 | 175 | if (callback) 176 | { 177 | callback.call(elem); 178 | } 179 | }); 180 | } 181 | else 182 | { 183 | style.display = display; 184 | } 185 | }); 186 | }, 187 | 188 | // For $ajax parameter 189 | addParam = function (prefix, data) 190 | { 191 | if (typeof data === 'object') 192 | { 193 | var rdata = []; 194 | 195 | $each(data, function (key, value) 196 | { 197 | if (typeof value === 'object') 198 | { 199 | rdata.push(addParam(prefix + '[' + key + ']', value)); 200 | } 201 | else 202 | { 203 | rdata.push(prefix + '[' + $url(key) + ']=' + $url(value)); 204 | } 205 | }); 206 | 207 | return rdata.join('&'); 208 | } 209 | else 210 | { 211 | return $url(prefix) + '=' + $url(data); 212 | } 213 | }, 214 | 215 | removeEvent = document.removeEventListener ? 216 | function(elem, type, fn) 217 | { 218 | elem.removeEventListener(type, fn, false); 219 | } : 220 | function(elem, type, fn) 221 | { 222 | elem.detachEvent('on' + type, fn); 223 | }, 224 | 225 | Qatrix = { 226 | $: function (id) 227 | { 228 | return document.getElementById(id); 229 | }, 230 | 231 | $each: function (haystack, callback) 232 | { 233 | var i = 0, 234 | length = haystack.length, 235 | type = typeof haystack, 236 | is_object = type === 'object', 237 | name; 238 | 239 | if (is_object && (length - 1) in haystack) 240 | { 241 | for (; i < length;) 242 | { 243 | if (callback.call(haystack[i], i, haystack[i++]) === false) 244 | { 245 | break; 246 | } 247 | } 248 | } 249 | else if (is_object) 250 | { 251 | for (name in haystack) 252 | { 253 | callback.call(haystack[name], name, haystack[name]); 254 | } 255 | } 256 | else 257 | { 258 | callback.call(haystack, 0, haystack); 259 | } 260 | 261 | return haystack; 262 | }, 263 | 264 | $id: function (id, callback) 265 | { 266 | var match = [], 267 | elem; 268 | 269 | $each(id instanceof Array ? id : id.split(' '), function (i, item) 270 | { 271 | elem = $(item); 272 | if (elem !== null) 273 | { 274 | match.push(elem); 275 | } 276 | }); 277 | 278 | return callback ? mapcall(match, callback) : match; 279 | }, 280 | 281 | $dom: function (dom, callback) 282 | { 283 | if (callback) 284 | { 285 | dom.length ? mapcall(dom, callback) : callback(dom); 286 | } 287 | 288 | return dom; 289 | }, 290 | 291 | $tag: function (elem, name, callback) 292 | { 293 | var stack = [], 294 | nodeList = elem.getElementsByTagName(name), 295 | l = nodeList.length, 296 | i = 0; 297 | 298 | if (l > 0) 299 | { 300 | for ( ;i < l; i++) 301 | { 302 | stack.push( nodeList[ i ] ); 303 | } 304 | 305 | return mapcall(stack, callback); 306 | } 307 | else 308 | { 309 | return stack; 310 | } 311 | }, 312 | 313 | $class: document.getElementsByClassName ? 314 | function (elem, className, callback) 315 | { 316 | var stack = [], 317 | nodeList = elem.getElementsByClassName(className), 318 | l = nodeList.length, 319 | i = 0; 320 | 321 | if (l > 0) 322 | { 323 | for ( ;i < l; i++) 324 | { 325 | stack.push( nodeList[ i ] ); 326 | } 327 | 328 | return mapcall(stack, callback); 329 | } 330 | else 331 | { 332 | return stack; 333 | } 334 | } : 335 | function (elem, className, callback) 336 | { 337 | var match = [], 338 | rclass = new RegExp("(^|\\s)" + className + "(\\s|$)"); 339 | 340 | $tag(elem, '*', function (item) 341 | { 342 | if (rclass.test(item.className)) 343 | { 344 | match.push(item); 345 | } 346 | }); 347 | 348 | return mapcall(match, callback); 349 | }, 350 | 351 | $select: document.querySelectorAll ? 352 | function (selector, callback) 353 | { 354 | return mapcall(document.querySelectorAll(selector), callback); 355 | } : 356 | // Hack native CSS selector quering matched element for IE6/7 357 | function (selector, callback) 358 | { 359 | var style = Qatrix.Qselector.styleSheet, 360 | match = []; 361 | 362 | style.addRule(selector, 'q:a'); 363 | $tag(document, '*', function (item) 364 | { 365 | if (item.currentStyle.q === 'a') 366 | { 367 | match.push(item); 368 | } 369 | }); 370 | style.cssText = ''; 371 | 372 | return mapcall(match, callback); 373 | }, 374 | 375 | $new: function (tag, properties) 376 | { 377 | var elem = document.createElement(tag); 378 | 379 | if (properties) 380 | { 381 | try 382 | { 383 | $each(properties, function (name, property) 384 | { 385 | switch (name) 386 | { 387 | case 'css': 388 | case 'style': 389 | $css.set(elem, property); 390 | break; 391 | 392 | case 'innerHTML': 393 | case 'html': 394 | $html(elem, property); 395 | break; 396 | 397 | case 'className': 398 | case 'class': 399 | $className.set(elem, property); 400 | break; 401 | 402 | case 'text': 403 | $text(elem, property); 404 | break; 405 | 406 | default: 407 | $attr.set(elem, name, property); 408 | break; 409 | } 410 | }); 411 | 412 | return elem; 413 | } 414 | catch (e) 415 | {} 416 | finally 417 | { 418 | // Prevent memory leak 419 | elem = null; 420 | } 421 | } 422 | 423 | return elem; 424 | }, 425 | 426 | $string: { 427 | camelCase: function (string) 428 | { 429 | return string.replace('-ms-', 'ms-').replace(rcamelCase, function (match, letter) 430 | { 431 | return (letter + '').toUpperCase(); 432 | }); 433 | }, 434 | 435 | replace: function (string, replacements) 436 | { 437 | for (var key in replacements) 438 | { 439 | string = string.replace(new RegExp(key, 'ig'), replacements[key]); 440 | } 441 | 442 | return string; 443 | }, 444 | 445 | slashes: function (string) 446 | { 447 | return $string.replace(string, { 448 | "\\\\": '\\\\', 449 | "\b": '\\b', 450 | "\t": '\\t', 451 | "\n": '\\n', 452 | "\r": '\\r', 453 | '"': '\\"' 454 | }); 455 | }, 456 | 457 | trim: "".trim ? 458 | function (string) 459 | { 460 | return string.trim(); 461 | } : 462 | function (string) 463 | { 464 | return (string + '').replace(/^\s\s*/, '').replace(/\s\s*$/, ''); 465 | } 466 | }, 467 | 468 | $attr: { 469 | get: function (elem, name) 470 | { 471 | return elem.getAttribute(name); 472 | }, 473 | 474 | set: function (elem, name, value) 475 | { 476 | return mapcall(elem, function (elem) 477 | { 478 | elem.setAttribute(name, value); 479 | }); 480 | }, 481 | 482 | remove: function (elem, name) 483 | { 484 | return mapcall(elem, function (elem) 485 | { 486 | elem.removeAttribute(name); 487 | }); 488 | } 489 | }, 490 | 491 | $data: { 492 | get: function (elem, name) 493 | { 494 | var value = $attr.get(elem, 'data-' + name); 495 | 496 | return value === "true" ? true : 497 | value === "false" ? false : 498 | value === "null" ? '' : 499 | value === null ? '' : 500 | value === '' ? '' : 501 | !isNaN(parseFloat(value)) && isFinite(value) ? +value : 502 | rbrace.test(value) ? $json.decode(value) : 503 | value; 504 | }, 505 | 506 | set: function (elem, name, value) 507 | { 508 | return mapcall(elem, function (elem) 509 | { 510 | value = typeof value === 'object' ? $json.encode(value) : value; 511 | typeof name === 'object' ? $each(name, function (key, value) 512 | { 513 | $attr.set(elem, 'data-' + key, value); 514 | }) : $attr.set(elem, 'data-' + name, value); 515 | 516 | return elem; 517 | }); 518 | }, 519 | 520 | remove: function (elem, name) 521 | { 522 | return mapcall(elem, function (elem) 523 | { 524 | $attr.remove(elem, 'data-' + name); 525 | }); 526 | } 527 | }, 528 | 529 | $storage: window.localStorage ? 530 | { 531 | set: function (name, value) 532 | { 533 | localStorage[name] = typeof value === 'object' ? $json.encode(value) : value; 534 | }, 535 | 536 | get: function (name) 537 | { 538 | var data = localStorage[name]; 539 | 540 | if ($json.isJSON(data)) 541 | { 542 | return $json.decode(data); 543 | } 544 | 545 | return data || ''; 546 | }, 547 | 548 | remove: function (name) 549 | { 550 | localStorage.removeItem(name); 551 | 552 | return true; 553 | } 554 | } : 555 | { 556 | set: function (name, value) 557 | { 558 | value = typeof value === 'object' ? $json.encode(value) : value; 559 | $data.set(Qatrix.storage, name, value); 560 | Qatrix.storage.save('Qstorage'); 561 | }, 562 | 563 | get: function (name) 564 | { 565 | Qatrix.storage.load('Qstorage'); 566 | 567 | return $data.get(Qatrix.storage, name) || ''; 568 | }, 569 | 570 | remove: function (name) 571 | { 572 | Qatrix.storage.load('Qstorage'); 573 | $data.remove(Qatrix.storage, name); 574 | 575 | return true; 576 | } 577 | }, 578 | 579 | $event: { 580 | guid: 0, 581 | 582 | global: {}, 583 | 584 | handler: { 585 | call: function (event, target, delegate_event, fn) 586 | { 587 | var handler = $event.handler; 588 | 589 | delegate_event.currentTarget = target; 590 | 591 | if (fn === false || fn.call(target, delegate_event) === false) 592 | { 593 | handler.stopPropagation.call(delegate_event); 594 | handler.preventDefault.call(delegate_event); 595 | } 596 | }, 597 | 598 | preventDefault: function () 599 | { 600 | var original = this.originalEvent; 601 | 602 | if (original.preventDefault) 603 | { 604 | original.preventDefault(); 605 | } 606 | }, 607 | 608 | stopPropagation: function () 609 | { 610 | var original = this.originalEvent; 611 | 612 | if (original.stopPropagation) 613 | { 614 | original.stopPropagation(); 615 | } 616 | }, 617 | 618 | stopImmediatePropagation: function() 619 | { 620 | this.stopPropagation(); 621 | }, 622 | 623 | mouseenter: function (handler) 624 | { 625 | return function (event) 626 | { 627 | var target = event.relatedTarget; 628 | 629 | if (this === target) 630 | { 631 | return; 632 | } 633 | 634 | while (target && target !== this) 635 | { 636 | target = target.parentNode; 637 | } 638 | 639 | if (target === this) 640 | { 641 | return; 642 | } 643 | 644 | handler.call(this, event); 645 | } 646 | } 647 | }, 648 | 649 | on: function (context, types, selector, data, fn) 650 | { 651 | return mapcall(context, function (elem) 652 | { 653 | if (elem.nodeType === 3 || elem.nodeType === 8) 654 | { 655 | return false; 656 | } 657 | 658 | if (typeof types === 'object') 659 | { 660 | if (typeof selector !== 'string') 661 | { 662 | data = data || selector; 663 | selector = undefined; 664 | } 665 | 666 | for (type in types) 667 | { 668 | $event.on(elem, type, selector, data, types[type]); 669 | } 670 | 671 | return this; 672 | } 673 | 674 | if (data == null && fn == null) 675 | { 676 | fn = selector; 677 | data = selector = undefined; 678 | } 679 | else if (fn == null) 680 | { 681 | if (typeof selector === 'string') 682 | { 683 | fn = data; 684 | data = undefined; 685 | } 686 | else 687 | { 688 | fn = data; 689 | data = selector; 690 | selector = undefined; 691 | } 692 | } 693 | 694 | if (elem.guid === undefined) 695 | { 696 | $event.guid++; 697 | elem.guid = $event.guid; 698 | $event.global[ $event.guid ] = {}; 699 | } 700 | 701 | var guid = elem.guid, 702 | event_key = (selector || '') + types, 703 | events = $event.global[ guid ][ event_key ]; 704 | 705 | if (!events) 706 | { 707 | $event.global[ guid ][ event_key ] = {}; 708 | } 709 | 710 | delegate_fn = function (event) 711 | { 712 | var delegate_event = {}, 713 | match = null, 714 | classSelector, 715 | event_prop = 'altKey bubbles button buttons cancelable relatedTarget clientX clientY ctrlKey fromElement offsetX offsetY pageX pageY screenX screenY shiftKey toElement timeStamp'.split(' '), 716 | target; 717 | 718 | $each(event_prop, function (i, key) 719 | { 720 | if (event[key] !== undefined) 721 | { 722 | delegate_event[key] = event[key]; 723 | } 724 | }); 725 | delegate_event.originalEvent = event; 726 | delegate_event.preventDefault = $event.handler.preventDefault; 727 | delegate_event.stopPropagation = $event.handler.stopPropagation; 728 | delegate_event.stopImmediatePropagation = $event.handler.stopImmediatePropagation; 729 | delegate_event.delegateTarget = elem; 730 | 731 | delegate_event.data = data; 732 | 733 | target = delegate_event.target = !selector ? elem : event.target || event.srcElement || document; 734 | 735 | delegate_event.which = event.which || event.charCode || event.keyCode; 736 | 737 | delegate_event.metaKey = event.metaKey || event.ctrlKey; 738 | 739 | if (!selector) 740 | { 741 | $event.handler.call(event, target, delegate_event, fn); 742 | } 743 | else 744 | { 745 | classSelector = selector ? selector.replace('.', '') : ''; 746 | 747 | for (; target !== elem; target = target.parentNode) 748 | { 749 | if (target === null || target === document.body) 750 | { 751 | return false; 752 | } 753 | 754 | if (target.tagName.toLowerCase() === selector || $className.has(target, classSelector)) 755 | { 756 | $event.handler.call(event, target, delegate_event, fn); 757 | } 758 | } 759 | } 760 | }; 761 | 762 | if (elem.addEventListener) 763 | { 764 | if (types === 'mouseenter' || types === 'mouseleave') 765 | { 766 | types = types === 'mouseenter' ? 'mouseover' : 'mouseout'; 767 | delegate_fn = $event.handler.mouseenter(delegate_fn); 768 | } 769 | 770 | elem.addEventListener(types, delegate_fn, (types === 'blur' || types === 'focus')); 771 | } 772 | else 773 | { 774 | elem.attachEvent('on' + types, delegate_fn); 775 | } 776 | 777 | $event.global[ guid ][ event_key ][ fn + '' ] = delegate_fn; 778 | 779 | return elem; 780 | }); 781 | }, 782 | 783 | off: function (context, types, selector, fn) 784 | { 785 | if (typeof types === 'object') 786 | { 787 | for (type in types) 788 | { 789 | $event.off(context, type, types[type]); 790 | } 791 | return this; 792 | } 793 | 794 | if (fn == null) 795 | { 796 | fn = selector; 797 | selector = null; 798 | } 799 | 800 | var guid = context.guid, 801 | event_key = (selector || '') + types; 802 | fn_key = fn + ''; 803 | 804 | if (!fn) 805 | { 806 | $each($event.global[ guid ][ event_key ], function (i, item) 807 | { 808 | removeEvent(context, types, item); 809 | }); 810 | delete $event.global[ guid ][ event_key ]; 811 | } 812 | else 813 | { 814 | removeEvent(context, types, $event.global[ guid ][ event_key ][ fn_key ]); 815 | delete $event.global[ guid ][ event_key ][ fn_key ]; 816 | } 817 | } 818 | }, 819 | 820 | $clear: function (timer) 821 | { 822 | if (timer) 823 | { 824 | clearTimeout(timer); 825 | clearInterval(timer); 826 | } 827 | 828 | return null; 829 | }, 830 | 831 | $ready: function (callback) 832 | { 833 | if (document.readyState === 'complete') 834 | { 835 | return setTimeout(callback, 1); 836 | } 837 | if (document.addEventListener) 838 | { 839 | readyList.push(callback); 840 | document.addEventListener('DOMContentLoaded', ready, false); 841 | 842 | return; 843 | } 844 | // Hack IE DOM for ready event 845 | var domready = function () 846 | { 847 | try 848 | { 849 | docElem.doScroll('left'); 850 | } 851 | catch (e) 852 | { 853 | setTimeout(domready, 1); 854 | return; 855 | } 856 | callback(); 857 | }; 858 | domready(); 859 | }, 860 | 861 | $css: { 862 | get: function (elem, name) 863 | { 864 | if (typeof name === 'object') 865 | { 866 | var haystack = {}; 867 | 868 | $each(name, function (i, property) 869 | { 870 | haystack[property] = $style.get(elem, property); 871 | }); 872 | 873 | return haystack; 874 | } 875 | 876 | return $style.get(elem, name); 877 | }, 878 | 879 | set: function (elem, name, value) 880 | { 881 | return mapcall(elem, function (elem) 882 | { 883 | typeof name === 'object' ? $each(name, function (propertyName, value) 884 | { 885 | $style.set(elem, $string.camelCase(propertyName), $css.fix(propertyName, value)); 886 | }) : $style.set(elem, $string.camelCase(name), $css.fix(name, value)); 887 | 888 | return elem; 889 | }); 890 | }, 891 | 892 | number: { 893 | 'fontWeight': true, 894 | 'lineHeight': true, 895 | 'opacity': true, 896 | 'zIndex': true 897 | }, 898 | 899 | unit: function (name, value) 900 | { 901 | if ($css.number[name]) 902 | { 903 | return ''; 904 | } 905 | var unit = (value + '').replace(rnum, ''); 906 | 907 | return unit === '' ? 'px' : unit; 908 | }, 909 | 910 | fix: function (name, value) 911 | { 912 | if (typeof value === 'number' && !$css.number[name]) 913 | { 914 | value += 'px'; 915 | } 916 | 917 | return value === null && isNaN(value) ? false : value; 918 | } 919 | }, 920 | 921 | $style: { 922 | get: window.getComputedStyle ? 923 | function (elem, property) 924 | { 925 | if (elem !== null) 926 | { 927 | var value = document.defaultView.getComputedStyle(elem, null).getPropertyValue(property); 928 | 929 | return value === 'auto' || value === '' ? 0 : value; 930 | } 931 | 932 | return false; 933 | } : 934 | function (elem, property) 935 | { 936 | if (elem !== null) 937 | { 938 | var value = property === 'opacity' ? ropacity.test(elem.currentStyle['filter']) ? 939 | (0.01 * parseFloat(RegExp.$1)) + '' : 940 | 1 : elem.currentStyle[$string.camelCase(property)]; 941 | 942 | return value === 'auto' ? 0 : value; 943 | } 944 | 945 | return false; 946 | }, 947 | 948 | set: docElem.style.opacity !== undefined ? 949 | function (elem, name, value) 950 | { 951 | return mapcall(elem, function (elem) 952 | { 953 | elem.style[name] = value; 954 | 955 | return true; 956 | }); 957 | } : 958 | function (elem, name, value) 959 | { 960 | return mapcall(elem, function (elem) 961 | { 962 | if (!elem.currentStyle || !elem.currentStyle.hasLayout) 963 | { 964 | elem.style.zoom = 1; 965 | } 966 | 967 | if (name === 'opacity') 968 | { 969 | elem.style.filter = 'alpha(opacity=' + value * 100 + ')'; 970 | elem.style.zoom = 1; 971 | } 972 | else 973 | { 974 | elem.style[name] = value; 975 | } 976 | 977 | return true; 978 | }); 979 | } 980 | }, 981 | 982 | $pos: function (elem, x, y) 983 | { 984 | return mapcall(elem, function (elem) 985 | { 986 | $style.set(elem, 'left', x + 'px'); 987 | $style.set(elem, 'top', y + 'px'); 988 | 989 | return elem; 990 | }); 991 | }, 992 | 993 | $offset: function (elem) 994 | { 995 | var body = document.body, 996 | box = elem.getBoundingClientRect(); 997 | 998 | return { 999 | top: box.top + (window.scrollY || body.parentNode.scrollTop || elem.scrollTop) - (docElem.clientTop || body.clientTop || 0), 1000 | left: box.left + (window.scrollX || body.parentNode.scrollLeft || elem.scrollLeft) - (docElem.clientLeft || body.clientLeft || 0), 1001 | width: elem.offsetWidth, 1002 | height: elem.offsetHeight 1003 | }; 1004 | }, 1005 | 1006 | $append: function (elem, node) 1007 | { 1008 | return mapcall(elem, function (elem) 1009 | { 1010 | return elem.appendChild(nodeManip(elem, node)); 1011 | }); 1012 | }, 1013 | 1014 | $prepend: function (elem, node) 1015 | { 1016 | return mapcall(elem, function (elem) 1017 | { 1018 | return elem.firstChild ? 1019 | elem.insertBefore(nodeManip(elem, node), elem.firstChild) : 1020 | elem.appendChild(nodeManip(elem, node)); 1021 | }); 1022 | }, 1023 | 1024 | $before: function (elem, node) 1025 | { 1026 | return mapcall(elem, function (elem) 1027 | { 1028 | return elem.parentNode.insertBefore(nodeManip(elem, node), elem); 1029 | }); 1030 | }, 1031 | 1032 | $after: function (elem, node) 1033 | { 1034 | return mapcall(elem, function (elem) 1035 | { 1036 | return elem.nextSibling ? 1037 | elem.parentNode.insertBefore(nodeManip(elem, node), elem.nextSibling) : 1038 | elem.parentNode.appendChild(nodeManip(elem, node)); 1039 | }); 1040 | }, 1041 | 1042 | $remove: function (elem) 1043 | { 1044 | return mapcall(elem, function (elem) 1045 | { 1046 | $empty(elem); 1047 | if (elem.guid !== undefined) 1048 | { 1049 | delete $event.global[elem.guid]; 1050 | } 1051 | 1052 | return elem !== null && elem.parentNode ? elem.parentNode.removeChild(elem) : elem; 1053 | }); 1054 | }, 1055 | 1056 | $empty: function (elem) 1057 | { 1058 | return mapcall(elem, function (elem) 1059 | { 1060 | while (elem.firstChild) 1061 | { 1062 | if (elem.nodeType === 1 && elem.guid !== undefined) 1063 | { 1064 | delete $event.global[elem.guid]; 1065 | } 1066 | elem.removeChild(elem.firstChild); 1067 | } 1068 | 1069 | return elem; 1070 | }); 1071 | }, 1072 | 1073 | $html: function (elem, html) 1074 | { 1075 | return mapcall(elem, function (elem) 1076 | { 1077 | if (html) 1078 | { 1079 | try 1080 | { 1081 | elem.innerHTML = html; 1082 | } 1083 | catch (e) 1084 | { 1085 | $append($empty(elem), html); 1086 | } 1087 | return elem; 1088 | } 1089 | 1090 | return elem.nodeType === 1 ? elem.innerHTML : null; 1091 | }); 1092 | }, 1093 | 1094 | $text: function (elem, text) 1095 | { 1096 | // Retrieve the text value 1097 | // textContent and innerText returns different results from different browser 1098 | // So it have to rewrite the process method 1099 | return mapcall(elem, function (elem) 1100 | { 1101 | if (text) 1102 | { 1103 | // Set text node. 1104 | $empty(elem); 1105 | elem.appendChild(document.createTextNode(text)); 1106 | 1107 | return elem; 1108 | } 1109 | else 1110 | { 1111 | var rtext = '', 1112 | textContent = elem.textContent, 1113 | nodeType; 1114 | 1115 | // If the content of elem is text only 1116 | if ((textContent || elem.innerText) === elem.innerHTML) 1117 | { 1118 | rtext = textContent ? $string.trim(elem.textContent.replace(rbline, '')) : elem.innerText.replace(rline, ''); 1119 | } 1120 | else 1121 | { 1122 | for (elem = elem.firstChild; elem; elem = elem.nextSibling) 1123 | { 1124 | nodeType = elem.nodeType; 1125 | 1126 | if (nodeType === 3 && $string.trim(elem.nodeValue) !== '') 1127 | { 1128 | rtext += elem.nodeValue.replace(rbline, '') + (elem.nextSibling && elem.nextSibling.tagName && elem.nextSibling.tagName.toLowerCase() !== 'br' ? "\n" : ''); 1129 | } 1130 | 1131 | if (nodeType === 1 || nodeType === 2) 1132 | { 1133 | rtext += $text(elem) + ($style.get(elem, 'display') === 'block' || elem.tagName.toLowerCase() === 'br' ? "\n" : ''); 1134 | } 1135 | } 1136 | } 1137 | 1138 | return rtext; 1139 | } 1140 | }); 1141 | }, 1142 | 1143 | $className: { 1144 | add: function (elem, name) 1145 | { 1146 | return mapcall(elem, function (elem) 1147 | { 1148 | if (elem.className === '') 1149 | { 1150 | elem.className = name; 1151 | } 1152 | else 1153 | { 1154 | var ori = elem.className, 1155 | nclass = []; 1156 | 1157 | $each(name.split(rspace), function (i, item) 1158 | { 1159 | if (!new RegExp('\\b(' + item + ')\\b').test(ori)) 1160 | { 1161 | nclass.push(' ' + item); 1162 | } 1163 | }); 1164 | elem.className += nclass.join(''); 1165 | } 1166 | 1167 | return elem; 1168 | }); 1169 | }, 1170 | 1171 | set: function (elem, name) 1172 | { 1173 | return mapcall(elem, function (elem) 1174 | { 1175 | elem.className = name; 1176 | 1177 | return elem; 1178 | }); 1179 | }, 1180 | 1181 | has: function (elem, name) 1182 | { 1183 | return new RegExp('\\b(' + name.split(rspace).join('|') + ')\\b').test(elem.className); 1184 | }, 1185 | 1186 | remove: function (elem, name) 1187 | { 1188 | return mapcall(elem, function (elem) 1189 | { 1190 | elem.className = name ? $string.trim( 1191 | elem.className.replace( 1192 | new RegExp('\\b(' + name.split(rspace).join('|') + ')\\b'), '') 1193 | .split(rspace) 1194 | .join(' ') 1195 | ) : ''; 1196 | 1197 | return elem; 1198 | }); 1199 | } 1200 | }, 1201 | 1202 | $hide: function (elem, duration, callback) 1203 | { 1204 | displayElem(elem, 'hide', duration, callback); 1205 | }, 1206 | 1207 | $show: function (elem, duration, callback) 1208 | { 1209 | displayElem(elem, 'show', duration, callback); 1210 | }, 1211 | 1212 | $toggle: function (elem, duration, callback) 1213 | { 1214 | return mapcall(elem, function (elem) 1215 | { 1216 | $style.get(elem, 'display') === 'none' ? 1217 | $show(elem, duration, callback) : 1218 | $hide(elem, duration, callback); 1219 | }); 1220 | }, 1221 | 1222 | $animate: (function () 1223 | { 1224 | // Use CSS3 native transition for animation as possible 1225 | var style = docElem.style; 1226 | 1227 | return ( 1228 | style.webkitTransition !== undefined || 1229 | style.MozTransition !== undefined || 1230 | style.OTransition !== undefined || 1231 | style.msTransition !== undefined || 1232 | style.transition !== undefined 1233 | ); 1234 | }()) ? 1235 | (function () 1236 | { 1237 | var style = docElem.style, 1238 | prefix_name = style.webkitTransition !== undefined ? 'Webkit' : 1239 | style.MozTransition !== undefined ? 'Moz' : 1240 | style.OTransition !== undefined ? 'O' : 1241 | style.msTransition !== undefined ? 'ms' : '', 1242 | transition_name = prefix_name + 'Transition'; 1243 | 1244 | return function (elem, properties, duration, callback) 1245 | { 1246 | return mapcall(elem, function (elem) 1247 | { 1248 | var css_value = [], 1249 | css_name = [], 1250 | unit = [], 1251 | css_style = [], 1252 | style = elem.style, 1253 | css, offset; 1254 | 1255 | duration = duration || 300; 1256 | 1257 | for (css in properties) 1258 | { 1259 | css_name[css] = $string.camelCase(css); 1260 | if (properties[css].from !== undefined) 1261 | { 1262 | properties[css].to = properties[css].to || 0; 1263 | css_value[css] = !$css.number[css] ? parseInt(properties[css].to, 10) : properties[css].to; 1264 | unit[css] = $css.unit(css, properties[css].to); 1265 | $style.set(elem, css_name[css], parseInt(properties[css].from, 10) + unit[css]); 1266 | } 1267 | else 1268 | { 1269 | css_value[css] = !$css.number[css] ? parseInt(properties[css], 10) : properties[css]; 1270 | unit[css] = $css.unit(css, properties[css]); 1271 | $style.set(elem, css_name[css], $style.get(elem, css_name[css])); 1272 | } 1273 | css_style.push(css); 1274 | } 1275 | 1276 | setTimeout(function () 1277 | { 1278 | style[transition_name] = 'all ' + duration + 'ms'; 1279 | 1280 | $each(css_style, function (i, css) 1281 | { 1282 | style[css_name[css]] = css_value[css] + unit[css]; 1283 | }); 1284 | }, 15); 1285 | 1286 | // Animation completed 1287 | setTimeout(function () 1288 | { 1289 | // Clear up CSS transition property 1290 | style[transition_name] = ''; 1291 | 1292 | if (callback) 1293 | { 1294 | callback.call(elem); 1295 | } 1296 | }, duration); 1297 | 1298 | return elem; 1299 | }); 1300 | } 1301 | })() : 1302 | function (elem, properties, duration, callback) 1303 | { 1304 | return mapcall(elem, function (elem) 1305 | { 1306 | var step = 0, 1307 | i = 0, 1308 | j = 0, 1309 | length = 0, 1310 | p = 30, 1311 | css_to_value = [], 1312 | css_from_value = [], 1313 | css_name = [], 1314 | css_unit = [], 1315 | css_style = [], 1316 | property_value, css, offset, timer; 1317 | 1318 | duration = duration || 300; 1319 | 1320 | for (css in properties) 1321 | { 1322 | css_name.push($string.camelCase(css)); 1323 | if (properties[css].from !== undefined) 1324 | { 1325 | property_value = properties[css].to; 1326 | css_from_value.push(!$css.number[css] ? parseInt(properties[css].from, 10) : properties[css].from); 1327 | $style.set(elem, css_name[i], css_from_value[i] + $css.unit(css, property_value)); 1328 | } 1329 | else 1330 | { 1331 | property_value = properties[css]; 1332 | css_from_value.push(parseInt($style.get(elem, $string.camelCase(css)), 10)); 1333 | } 1334 | css_to_value.push(!$css.number[css] ? parseInt(property_value, 10) : property_value); 1335 | css_unit.push($css.unit(css, property_value)); 1336 | i++; 1337 | length++; 1338 | } 1339 | // Pre-calculation for CSS value 1340 | for (j = 0; j < p; j++) 1341 | { 1342 | css_style[j] = []; 1343 | for (i = 0; i < length; i++) 1344 | { 1345 | css_style[j][css_name[i]] = 1346 | (css_from_value[i] + (css_to_value[i] - css_from_value[i]) / p * j) + 1347 | (css_name[i] === 'opacity' ? '' : css_unit[i]); 1348 | } 1349 | } 1350 | 1351 | for (; i < p; i++) 1352 | { 1353 | timer = setTimeout(function () 1354 | { 1355 | for (i = 0; i < length; i++) 1356 | { 1357 | $style.set(elem, css_name[i], css_style[step][css_name[i]]); 1358 | } 1359 | step++; 1360 | }, (duration / p) * i); 1361 | } 1362 | 1363 | setTimeout(function () 1364 | { 1365 | for (i = 0; i < length; i++) 1366 | { 1367 | $style.set(elem, css_name[i], css_to_value[i] + css_unit[i]); 1368 | } 1369 | if (callback) 1370 | { 1371 | callback.call(elem); 1372 | } 1373 | }, duration); 1374 | 1375 | return elem; 1376 | }); 1377 | }, 1378 | 1379 | $fadeout: function (elem, duration, callback) 1380 | { 1381 | return mapcall(elem, function (elem) 1382 | { 1383 | $animate(elem, { 1384 | 'opacity': { 1385 | from: 1, 1386 | to: 0 1387 | } 1388 | }, duration || 500, callback); 1389 | }); 1390 | }, 1391 | 1392 | $fadein: function (elem, duration, callback) 1393 | { 1394 | return mapcall(elem, function (elem) 1395 | { 1396 | $animate(elem, { 1397 | 'opacity': { 1398 | from: 0, 1399 | to: 1 1400 | } 1401 | }, duration || 500, callback); 1402 | }); 1403 | }, 1404 | 1405 | $cookie: { 1406 | get: function (key) 1407 | { 1408 | var cookies = document.cookie.split('; '), 1409 | i = 0, 1410 | l = cookies.length, 1411 | temp, value; 1412 | 1413 | for (; i < l; i++) 1414 | { 1415 | temp = cookies[i].split('='); 1416 | if (temp[0] === key) 1417 | { 1418 | value = decodeURIComponent(temp[1]); 1419 | 1420 | return $json.isJSON(value) ? $json.decode(value) : value + ''; 1421 | } 1422 | } 1423 | 1424 | return null; 1425 | }, 1426 | 1427 | set: function (key, value, expires) 1428 | { 1429 | if (typeof key === 'object') 1430 | { 1431 | expires = value; 1432 | 1433 | return $each(key, function (name, value) 1434 | { 1435 | $cookie.set(name, value, expires); 1436 | }); 1437 | } 1438 | 1439 | var today = new Date(); 1440 | 1441 | today.setTime(today.getTime()); 1442 | expires = expires ? ';expires=' + new Date(today.getTime() + expires * 86400000).toGMTString() : ''; 1443 | value = typeof value === 'object' ? $json.encode(value) : value; 1444 | 1445 | return document.cookie = key + '=' + $url(value) + expires + ';path=/'; 1446 | }, 1447 | 1448 | remove: function () 1449 | { 1450 | $each(arguments, function (i, key) 1451 | { 1452 | $cookie.set(key, '', -1); 1453 | }); 1454 | 1455 | return true; 1456 | } 1457 | }, 1458 | 1459 | $json: { 1460 | decode: window.JSON ? 1461 | function (data) 1462 | { 1463 | return $json.isJSON(data) ? JSON.parse($string.trim(data)) : false; 1464 | } : 1465 | function (data) 1466 | { 1467 | return $json.isJSON(data) ? (new Function('return ' + $string.trim(data)))() : false; 1468 | }, 1469 | 1470 | encode: window.JSON ? 1471 | function (data) 1472 | { 1473 | return JSON.stringify(data); 1474 | } : 1475 | function (data) 1476 | { 1477 | function stringify(data) 1478 | { 1479 | var temp = [], 1480 | i, type, value, rvalue; 1481 | 1482 | for (i in data) 1483 | { 1484 | value = data[i]; 1485 | type = typeof value; 1486 | 1487 | if (type === 'undefined') 1488 | { 1489 | return; 1490 | } 1491 | 1492 | if (type !== 'function') 1493 | { 1494 | switch (type) 1495 | { 1496 | case 'object': 1497 | rvalue = value === null ? value : 1498 | // For ISO date format 1499 | value.getDay ? 1500 | '"' + (1e3 - ~value.getUTCMonth() * 10 + value.toUTCString() + 1e3 + value / 1) 1501 | .replace(/1(..).*?(\d\d)\D+(\d+).(\S+).*(...)/, '$3-$1-$2T$4.$5Z') + '"' : 1502 | // For Array 1503 | value.length ? '[' + (function () 1504 | { 1505 | var rdata = []; 1506 | $each(value, function (i, item) 1507 | { 1508 | rdata.push((typeof item === 'string' ? '"' + $string.slashes(item) + '"' : item)); 1509 | }); 1510 | 1511 | return rdata.join(','); 1512 | })() + ']' : 1513 | // For Object 1514 | $json.encode(value); 1515 | break; 1516 | 1517 | case 'number': 1518 | rvalue = !isFinite(value) ? null : value; 1519 | break; 1520 | 1521 | case 'boolean': 1522 | case 'null': 1523 | rvalue = value; 1524 | break; 1525 | 1526 | case 'string': 1527 | rvalue = '"' + $string.slashes(value) + '"'; 1528 | break; 1529 | } 1530 | temp.push('"' + i + '"' + ':' + rvalue); 1531 | } 1532 | } 1533 | 1534 | return temp.join(','); 1535 | } 1536 | 1537 | return '{' + stringify(data) + '}'; 1538 | }, 1539 | 1540 | isJSON: function (string) 1541 | { 1542 | return typeof string === 'string' && $string.trim(string) !== '' ? 1543 | rvalidchars.test(string 1544 | .replace(rvalidescape, '@') 1545 | .replace(rvalidtokens, ']') 1546 | .replace(rvalidbraces, '')) : 1547 | false; 1548 | } 1549 | }, 1550 | 1551 | $ajax: function (url, options) 1552 | { 1553 | if (typeof url === 'object') 1554 | { 1555 | options = url; 1556 | url = undefined; 1557 | } 1558 | 1559 | options = options || {}; 1560 | 1561 | var request = window.ActiveXObject ? new ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest(), 1562 | url = url || options.url, 1563 | param = [], 1564 | response, 1565 | data; 1566 | 1567 | if (options.data) 1568 | { 1569 | $each(options.data, function (key, value) 1570 | { 1571 | param.push(addParam(key, value)); 1572 | }); 1573 | } 1574 | data = param.join('&').replace(/%20/g, '+'); 1575 | 1576 | if (options.type === 'GET') 1577 | { 1578 | request.open('GET', url + (rquery.test(url) ? '&' : '?') + data, true); 1579 | data = null; 1580 | } 1581 | else 1582 | { 1583 | request.open(options.type || 'POST', url, true); 1584 | } 1585 | 1586 | request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); 1587 | 1588 | if (options.header) 1589 | { 1590 | $each(options.header, function (key, value) 1591 | { 1592 | request.setRequestHeader(key, value); 1593 | }); 1594 | } 1595 | 1596 | request.send(data); 1597 | request.onreadystatechange = function () 1598 | { 1599 | if (request.readyState === 4) 1600 | { 1601 | if (request.status === 200 && options.success) 1602 | { 1603 | data = request.responseText; 1604 | options.success(data !== '' && $json.isJSON(data) ? $json.decode(data) : data); 1605 | } 1606 | else 1607 | { 1608 | if (options.error) 1609 | { 1610 | options.error(request.status); 1611 | } 1612 | } 1613 | } 1614 | }; 1615 | }, 1616 | 1617 | $require: function (context, callback) 1618 | { 1619 | var queue = [], 1620 | item; 1621 | 1622 | $each(context, function (i, src) 1623 | { 1624 | if (!require_loaded[src]) 1625 | { 1626 | require_loaded[src] = true; 1627 | queue.push(src); 1628 | item = /\.css[^\.]*$/ig.test(src) ? 1629 | 1630 | $new('link', { 1631 | 'type': 'text/css', 1632 | 'rel': 'stylesheet', 1633 | 'href': src 1634 | }) : 1635 | 1636 | $new('script', { 1637 | 'type': 'text/javascript', 1638 | 'async': true, 1639 | 'src': src 1640 | }); 1641 | 1642 | item.onload = item.onreadystatechange = function (event) 1643 | { 1644 | if (event.type === 'load' || (/loaded|complete/.test(item.readyState))) 1645 | { 1646 | item.onload = item.onreadystatechange = null; 1647 | queue.splice(queue.indexOf(src), 1); 1648 | if (queue.length === 0 && callback) 1649 | { 1650 | callback(); 1651 | } 1652 | } 1653 | }; 1654 | $append(document.head || $tag(document, 'head')[0] || docElem, item); 1655 | } 1656 | }); 1657 | }, 1658 | 1659 | $template: function (template, data) 1660 | { 1661 | var content = template_cache[template]; 1662 | 1663 | if (!content) 1664 | { 1665 | content = "var s='';s+=\'" + 1666 | template.replace(/[\r\t\n]/g, " ") 1667 | .split("'").join("\\'") 1668 | .replace(/\{\{#([\w]*)\}\}(.*)\{\{\/(\1)\}\}/ig, function (match, $1, $2) 1669 | { 1670 | return "\';var i=0,l=data." + $1 + ".length,d=data." + $1 + ";for(;i -1; 1701 | } 1702 | 1703 | for (; i < 12; i++) 1704 | { 1705 | browser['msie' + i] = ua.indexOf('msie ' + i) > -1; 1706 | } 1707 | 1708 | browser.is = function (keyword) 1709 | { 1710 | return new RegExp(keyword, 'ig').test(ua); 1711 | }; 1712 | 1713 | return browser; 1714 | }()) 1715 | }; 1716 | 1717 | // Expose Qatrix functions to global 1718 | for (var fn in Qatrix) 1719 | { 1720 | window[fn] = Qatrix[fn]; 1721 | } 1722 | 1723 | Qatrix.version = version; 1724 | window.Qatrix = Qatrix; 1725 | 1726 | $ready(function () 1727 | { 1728 | // For hack CSS selector 1729 | if (!document.querySelectorAll) 1730 | { 1731 | Qatrix.Qselector = $append(document.body, $new('style')); 1732 | } 1733 | // For hack storage 1734 | if (!window.localStorage) 1735 | { 1736 | Qatrix.storage = $append(document.body, $new('link', { 1737 | 'style': { 1738 | 'behavior': 'url(#default#userData)' 1739 | } 1740 | })); 1741 | } 1742 | }); 1743 | 1744 | // Define Qatrix as an AMD module 1745 | if (typeof define === 'function' && define.amd) 1746 | { 1747 | define('qatrix', [], Qatrix); 1748 | } 1749 | 1750 | // Create a shortcut for compression 1751 | })(window, document); --------------------------------------------------------------------------------