├── .gitignore
├── .jshintrc
├── .npmignore
├── README.md
├── bower.json
├── chibi-min.js
├── chibi.js
├── gulpfile.js
├── package.json
└── tests
└── runner.html
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | package-lock.json
3 | npm-debug.log
4 | tests/server.js
5 | tests/sandpit.html
6 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "maxerr" : 50, // {int} Maximum error before stopping
3 |
4 | // Enforcing
5 | "bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.)
6 | "camelcase" : false, // true: Identifiers must be in camelCase
7 | "curly" : false, // true: Require {} for every new block or scope
8 | "eqeqeq" : true, // true: Require triple equals (===) for comparison
9 | "forin" : false, // true: Require filtering for..in loops with obj.hasOwnProperty()
10 | "immed" : true, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());`
11 | "indent" : 2, // {int} Number of spaces to use for indentation
12 | "latedef" : true, // true: Require variables/functions to be defined before being used
13 | "newcap" : true, // true: Require capitalization of all constructor functions e.g. `new F()`
14 | "noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee`
15 | "noempty" : true, // true: Prohibit use of empty blocks
16 | "nonew" : true, // true: Prohibit use of constructors for side-effects (without assignment)
17 | "plusplus" : true, // true: Prohibit use of `++` & `--`
18 | "quotmark" : "single", // Quotation mark consistency:
19 | // false : do nothing (default)
20 | // true : ensure whatever is used is consistent
21 | // "single" : require single quotes
22 | // "double" : require double quotes
23 | "undef" : true, // true: Require all non-global variables to be declared (prevents global leaks)
24 | "unused" : true, // true: Require all defined variables be used
25 | "strict" : true, // true: Requires all functions run in ES5 Strict Mode
26 | "maxparams" : false, // {int} Max number of formal params allowed per function
27 | "maxdepth" : false, // {int} Max depth of nested blocks (within functions)
28 | "maxstatements" : false, // {int} Max number statements per function
29 | "maxcomplexity" : false, // {int} Max cyclomatic complexity per function
30 | "maxlen" : false, // {int} Max number of characters per line
31 |
32 | // Relaxing
33 | "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons)
34 | "boss" : false, // true: Tolerate assignments where comparisons would be expected
35 | "debug" : false, // true: Allow debugger statements e.g. browser breakpoints.
36 | "eqnull" : false, // true: Tolerate use of `== null`
37 | "es5" : false, // true: Allow ES5 syntax (ex: getters and setters)
38 | "esnext" : false, // true: Allow ES.next (ES6) syntax (ex: `const`)
39 | "moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features)
40 | // (ex: `for each`, multiple try/catch, function expression…)
41 | "evil" : false, // true: Tolerate use of `eval` and `new Function()`
42 | "expr" : false, // true: Tolerate `ExpressionStatement` as Programs
43 | "funcscope" : false, // true: Tolerate defining variables inside control statements
44 | "globalstrict" : false, // true: Allow global "use strict" (also enables 'strict')
45 | "iterator" : false, // true: Tolerate using the `__iterator__` property
46 | "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block
47 | "laxbreak" : false, // true: Tolerate possibly unsafe line breakings
48 | "laxcomma" : false, // true: Tolerate comma-first style coding
49 | "loopfunc" : false, // true: Tolerate functions being defined in loops
50 | "multistr" : false, // true: Tolerate multi-line strings
51 | "proto" : false, // true: Tolerate using the `__proto__` property
52 | "scripturl" : false, // true: Tolerate script-targeted URLs
53 | "shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;`
54 | "sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation
55 | "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;`
56 | "validthis" : false, // true: Tolerate using this in a non-constructor function
57 |
58 | // Environments
59 | "browser" : true, // Web Browser (window, document, etc)
60 | "couch" : false, // CouchDB
61 | "devel" : true, // Development/debugging (alert, confirm, etc)
62 | "dojo" : false, // Dojo Toolkit
63 | "jquery" : false, // jQuery
64 | "mootools" : false, // MooTools
65 | "node" : false, // Node.js
66 | "nonstandard" : false, // Widely adopted globals (escape, unescape, etc)
67 | "prototypejs" : false, // Prototype and Scriptaculous
68 | "rhino" : false, // Rhino
69 | "worker" : false, // Web Workers
70 | "wsh" : true, // Windows Scripting Host
71 | "yui" : false, // Yahoo User Interface
72 |
73 | // Custom Globals
74 | "globals": {
75 | "angular" : false,
76 | "define" : false,
77 | "require" : false,
78 | "exports" : false,
79 | "module" : false,
80 | "describe" : false,
81 | "before" : false,
82 | "beforeEach" : false,
83 | "after" : false,
84 | "afterEach" : false,
85 | "it" : false,
86 | "inject" : false,
87 | "expect" : false,
88 | "spyOn" : false
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | tests/sandpit.html
2 | tests/server.js
3 | bower.json
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Chibi v3.0.9
2 |
3 | #### A tiny JavaScript micro-library
4 |
5 | Think it's OK to serve up 30KB over 3G just to manipulate a couple of DOM elements? Of course you don't because that's an asshat move and you're no asshat. You'll probably instead use a couple of lines of vanilla JavaScript, perhaps a little CSS `:active` with transitions, all while riding a unicorn bareback through a double rainbow, no hands.
6 |
7 | Working on something a wee bit more complex? Unlike fat, grown-up frameworks and libraries, Chibi focuses on just the essentials, melted down and mixed with optimisation rainbows to create a really light micro-library that allows you to do awesome things, asshatory free.
8 |
9 | ### The sweet, juicy bits
10 |
11 | * Chibi is really tiny: 7KB minified, 3KB gzipped, small enough to stick inline on single page web apps, saving an extra HTTP request.
12 | * Supports modern desktop and mobile browsers including Chrome, Firefox, Internet Explorer, Opera and Safari (see Browser Support below).
13 | * Even supports creaky old browsers like IE6, I don't know why you would do this.
14 | * No animation cruft, instead use CSS transitions like a nice person.
15 | * In modern browsers, Chibi typically executes DOM manipulation 20% to 50% faster than grown-up libraries.
16 |
17 | ### The lumpy, chewy bits
18 |
19 | * Chibi's polyfill for `document.querySelectorAll()` is limited to browser CSS support and is not as fast as some dedicated selector engines. This means no `input[type=text]` or `p:nth-child(even)` selectors with IE6. Fortunately modern browser don't need this polyfill.
20 | * Ancient browsers that support neither `document.querySelectorAll()` nor `window.getComputedStyle` can bugger off.
21 |
22 | **Version 3 is a major update with many breaking changes. If it's difficult to embrace change, version 1 is still available [here](https://github.com/kylebarrow/chibi/tree/1.1.5).**
23 |
24 | ### Browser Support
25 |
26 | Chibi has been tested with and supports the following browsers:
27 |
28 | * Android Browser 2.1 or higher
29 | * Blackberry Browser 6 or higher
30 | * Chrome
31 | * Chrome Android
32 | * Firefox 3.5 or higher
33 | * Firefox Mobile
34 | * Internet Explorer 6 or higher
35 | * Internet Explorer Mobile 9 or higher
36 | * Opera 10 or higher
37 | * Opera Mini
38 | * Opera Mobile 10 or higher
39 | * Safari 3.2 or higher
40 | * Safari Mobile 3.2 or higher
41 | * Symbian^3 Browser or higher
42 |
43 | Chibi should also work with any other browser that supports `document.querySelectorAll()`.
44 |
45 | ### Installation
46 |
47 | Grab it from [here](https://github.com/kylebarrow/chibi/) or
48 |
49 | ```shell
50 | npm install chibijs
51 | ```
52 |
53 | ### Using Chibi
54 |
55 | Chibi syntax is similar to that pioneered by jQuery: `$(selector).method()`. It intentionally uses the same `$` namespace as jQuery because micro-libraries and grown-up libraries should never mix.
56 |
57 | Chibi's supports standard CSS selectors but you can also pass in DOM elements directly:
58 |
59 | ##### CSS selector
60 |
61 | ```js
62 | $("p") // Returns an array of all paragraph elements
63 | $("p").hide() // Hides all paragraphs
64 | $("#foo").show() // Shows element with id equal to "foo"
65 | $(".foo").hide() // Hides elements with "foo" CSS class
66 | ```
67 |
68 | ##### A DOM element selector, pointless
69 |
70 | ```js
71 | $(document.getElementsByTagName('p')).hide() // Hides all paragraphs
72 | ```
73 |
74 | ##### A more interesting DOM element selector
75 |
76 | ```js
77 | $($('p')[0]).hide() // Hides first paragraph
78 | ```
79 |
80 | ### Methods
81 |
82 | Chibi supports method chaining `$(selector).method().anothermethod().evenmoremethods()` of any method not returning a value (string, boolean, etc.).
83 |
84 | #### $().ready(handler)
85 | *Fires handler when the DOM is ready.*
86 |
87 | Use to fire a function when the DOM is ready. Including a selector makes no sense for this method, don't do it.
88 |
89 | ```js
90 | $().ready(function(){
91 | // Do awesome
92 | });
93 | ```
94 | or perhaps
95 |
96 | ```js
97 | function foo() {
98 | // Do awesome
99 | }
100 |
101 | $().ready(foo);
102 | ```
103 |
104 | #### $().loaded(handler)
105 | *Fires handler when the page is loaded.*
106 |
107 | Use to fire a function when the page is loaded. Including a selector makes no sense for this method, don't do it.
108 |
109 | ```js
110 | function foo() {
111 | // Do awesome
112 | }
113 |
114 | $().loaded(foo);
115 | ```
116 |
117 | #### $(selector).each(function)
118 | *Executes a function on each matching element*
119 |
120 | **each** passes each matching element to the specified function.
121 |
122 | ```html
123 |
124 |
125 |
126 |
127 |
128 |
129 |
Foo
130 |
Bar
131 |
145 |
146 |
147 | ```
148 |
149 | #### $(selector).first()
150 | *Finds the first matching element.*
151 |
152 | **first** will return an array containing the first matching element, useful when working with crappy browsers like IE6 with weak CSS pseudo support, especially when combined with method chaining.
153 |
154 | #### $(selector).last()
155 | *Finds the last matching element.*
156 |
157 | **last** will return an array containing the last matching element.
158 |
159 | #### $(selector).odd()
160 | *Finds matching odd elements.*
161 |
162 | **odd** will return an array containing matching odd elements.
163 |
164 | #### $(selector).even()
165 | *Finds matching even elements.*
166 |
167 | **even** will return an array containing matching even elements.
168 |
169 |
170 | ```html
171 |
172 |
173 |
174 |
175 |
176 |
177 |
263 |
266 |
267 |
268 | ```
269 |
270 | #### $(selector).css(property, value)
271 | *Gets or optionally sets the CSS property for matching elements.*
272 |
273 | **css** with no *value* will return the CSS property string of the first matching element found. **css** will return the computed property value if the property isn't explicitly set which can vary between browsers. For example, an element with no explicit font weight will return 'normal' in Opera and Webkit browsers but '400' in Firefox and Internet Explorer browsers.
274 |
275 | *value* will set the value of the CSS property for all matching elements.
276 |
277 | ```html
278 |
279 |
280 |
281 |
284 |
285 |
286 |
287 |
413 |
416 |
417 |
418 | ```
419 |
420 | #### $(selector).hasClass(class)
421 | *Returns true if first matching element found includes the class.*
422 |
423 | ```html
424 |
425 |
426 |
427 |
432 |
433 |
434 |
435 |
Foo
436 |
Bar
437 |
Foo
438 |
Bar
439 |
443 |
444 |
445 | ```
446 |
447 | #### $(selector).html(html)
448 | *Gets or optionally sets the inner HTML of matching elements.*
449 |
450 | **html** with no arguments will return the HTML string of the first matching element found.
451 |
452 | If the *html* argument is specified, this will replace the inner HTML of all matching elements.
453 |
454 | ```html
455 |
456 |
457 |
458 |
459 |
460 |
461 |
540 |
543 |
544 |
545 | ```
546 |
547 | #### $(selector).attr(property, value)
548 | *Gets or optionally sets the property for all matching elements.*
549 |
550 | **attr** with no value argument will return the property string of the first matching element found.
551 |
552 | *value* will set the value of the property for all matching elements.
553 |
554 | ```html
555 |
556 |
557 |
558 |
559 |
560 |
561 |
562 |
566 |
567 |
568 | ```
569 |
570 | #### $(selector).data(key, value)
571 | *Gets or optionally sets the data key value for all matching elements.*
572 |
573 | **data** with no *value* argument will return the data key value of the first matching element found.
574 |
575 | *value* will set the value of the data key for all matching elements.
576 |
577 | ```html
578 |
579 |
580 |
581 |
582 |
583 |
584 |
585 |
586 |
590 |
591 |
592 | ```
593 |
594 | #### $(selector).val(value)
595 | *Gets or optionally sets the value of matching form elements.*
596 |
597 | **val** with no arguments will return the value string of the first matching form element found. For select lists, Chibi will return the selected option value string, if any. For select lists with multiple selects, Chibi will return an array of selected option value strings, if any.
598 |
599 | *value* will set the value of matching form field elements. For select lists, this will select the option matching this value. For select lists with multiple selects, passing an array of values will select all options in the select list matching these values.
600 |
601 |
602 | ```html
603 |
604 |
605 |
606 |
607 |
608 |
609 |
616 |
623 |
624 |
625 | ```
626 |
627 | #### $(selector).checked(boolean)
628 | *Gets or optionally sets checked status of checkbox or radio elements.*
629 |
630 | **checked** with no arguments will return the checked boolean of the first matching element found.
631 |
632 | *boolean* will set the checked status of matching checkbox or radio elements.
633 |
634 | ```html
635 |
636 |
637 |
638 |
639 |
640 |
641 |
644 |
650 |
651 |
652 | ```
653 |
654 | #### $(selector).on(event, listener)
655 | *Adds an event listener to all matching elements.*
656 |
657 | **on** adds an event listener to all matching elements. There is no need to use the HTML event format ('on' + event) as Chibi will automatically prefix the event as required. **on** also supports passing `window` and `document` as the selector.
658 |
659 | ```html
660 |
661 |
662 |
663 |
664 |
665 |
666 |
Foo
667 |
Bar
668 |
675 |
676 |
677 | ```
678 |
679 | #### $(selector).off(event, listener)
680 | *Removed an event listener from all matching elements.*
681 |
682 | **off** removed an event listener from all matching elements. There is no need to use the HTML event format ('off' + event) as Chibi will automatically prefix the event as required. **off** also supports passing `window` and `document` as the selector.
683 |
684 | ```html
685 |
686 |
687 |
688 |
689 |
690 |
691 |
Foo
692 |
Bar
693 |
701 |
702 |
703 | ```
704 |
705 | #### $(selector).get(url, callback, nocache, nojsonp)
706 | *Sends a GET AJAX request, optionally firing a callback with the XHR `responseText` and `status`. Alias of $(selector).ajax with GET method*
707 |
708 | When *nocache* is true, a `_ts` time stamp is added to the URL to prevent caching, yes, I'm looking at you Android Browser and iOS 6.
709 |
710 | **get** supports JSON as a selector ({name:value}), useful for when you want to send data without using form elements.
711 |
712 | For cross-domain requests, **get** uses JSONP by default but this is overridden when *nojsonp* is true. JSONP requests will apply any *callback* to `callback=?` or similar in the **get** url.
713 |
714 | ```html
715 |
716 |
717 |
718 |
719 |
720 |
721 |
724 |
732 |
733 |
734 | ```
735 | ```html
736 |
737 |
738 |
739 |
740 |
741 |
742 |
753 |
754 |
755 | ```
756 |
757 | #### $(selector).post(url, callback, nocache)
758 | *Sends a POST AJAX request, optionally firing a callback with the XHR `responseText` and `status`. Alias of $(selector).ajax with POST method*
759 |
760 | When *nocache* is true, a `_ts` time stamp is added to the URL to prevent caching.
761 |
762 | **post** supports JSON as a selector ({name:value}), useful for when you want to send data without using form elements.
763 |
764 | ```html
765 |
766 |
767 |
768 |
769 |
770 |
771 |
774 |
783 |
784 |
785 | ```
786 |
787 | #### $(selector).ajax(url, method, callback, nocache, nojsonp)
788 | *Sends an AJAX request, optionally firing a callback with the XHR `responseText` and `status`*
789 |
790 | **ajax** uses the GET method if none is specified. When *nocache* is true, a `_ts` time stamp is added to the URL to prevent caching.
791 |
792 | **ajax** supports JSON as a selector ({name:value}), useful for when you want to send data without using form elements.
793 |
794 | For cross-domain requests, **ajax** uses JSONP by default but this is overridden when *nojsonp* is true. JSONP requests will apply any *callback* to `callback=?` or similar in the **ajax** url. The *method* is obviously always `GET` for JSONP requests.
795 |
796 | ```html
797 |
798 |
799 |
800 |
801 |
802 |
803 |
806 |
818 |
819 |
820 | ```
821 | ```html
822 |
823 |
824 |
825 |
826 |
827 |
828 |
839 |
840 |
841 | ```
842 |
843 | ### Modify, build, contribute
844 |
845 | ```shell
846 | npm install
847 | gulp
848 | ```
849 |
850 | ##### FIN
851 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "chibi",
3 | "description": "A tiny JavaScript micro-library",
4 | "main": "chibi-min.js",
5 | "license": "MIT",
6 | "ignore": [
7 | "node_modules",
8 | "tests",
9 | ".*",
10 | "gulpfile.js",
11 | "package.json"
12 | ],
13 | "keywords": [
14 | "browser",
15 | "chibi",
16 | "dom",
17 | "library",
18 | "microlibrary"
19 | ],
20 | "authors": [
21 | "Kyle Barrow (https://barrow.io)"
22 | ],
23 | "homepage": "https://github.com/kylebarrow/chibi",
24 | "repository": {
25 | "type": "git",
26 | "url": "https://github.com/kylebarrow/chibi.git"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/chibi-min.js:
--------------------------------------------------------------------------------
1 | /*!chibi 3.0.9, Copyright 2012-2017 Kyle Barrow, released under MIT license */
2 | !function(){"use strict";function e(){var e;for(h=!0,e=0;e=0;n-=1)e(t[n])}function r(e){return e.replace(/-\w/g,function(e){return e.charAt(1).toUpperCase()})}function a(e,t){return e.currentStyle?e.currentStyle[r(t)]:v.getComputedStyle?v.getComputedStyle(e,null).getPropertyValue(t):null}function o(e,t){return encodeURIComponent(e).replace(/%20/g,"+")+"="+encodeURIComponent(t).replace(/%20/g,"+")}function c(e,t,n){try{e.style[r(t)]=n}catch(e){console.error('Could not set css style property "'+t+'".')}}function s(e){e.style.display="","none"===a(e,"display")&&(e.style.display="block")}function i(e){var t,r,a,c="";if(e.constructor===Object){for(t in e)if(e.hasOwnProperty(t))if(e[t].constructor===Array)for(r=0;r0&&(c+="&"+o(t.name,t.value));break;case"select-multiple":for(a=0;a0?c.substring(1):""}function u(e,t,r){var a,o,c,s,i=!1;return e&&(a=e.split(/\s+/),n(function(e){for(s=0;s0)return T[0].className.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"").replace(/\s+/," ")},t.setClass=function(e){return(e||""===e)&&n(function(t){t.className=e},T),t},t.addClass=function(e){return e&&n(function(t){t.className+=" "+e},T),t},t.removeClass=function(e){return u(e,"remove",T),t},t.toggleClass=function(e){return u(e,"toggle",T),t},t.hasClass=function(e){return u(e,"has",T)},t.html=function(e){return e||""===e?(n(function(t){t.innerHTML=e},T),t):T[0]?T[0].innerHTML:void 0},t.htmlBefore=function(e){return l(e,"before",T),t},t.htmlAfter=function(e){return l(e,"after",T),t},t.htmlAppend=function(e){return l(e,"append",T),t},t.htmlPrepend=function(e){return l(e,"prepend",T),t},t.attr=function(e,r){if(e){if(e=e.toLowerCase(),r||""===r)return n(function(t){"style"===e?t.style.cssText=r:"class"===e?t.className=r:t.setAttribute(e,r)},T),t;if(T[0])if("style"===e){if(T[0].style.cssText)return T[0].style.cssText}else if("class"===e){if(T[0].className)return T[0].className}else if(T[0].getAttribute(e))return T[0].getAttribute(e)}},t.data=function(e,n){if(e)return t.attr("data-"+e,n)},t.val=function(e){var r,a,o;if(e||""===e)return n(function(t){switch(t.nodeName){case"SELECT":for("string"!=typeof e&&"number"!=typeof e||(e=[e]),a=0;a1?r:r[0];case"INPUT":case"TEXTAREA":case"BUTTON":return T[0].value}},t.checked=function(e){return"boolean"==typeof e?(n(function(t){"INPUT"!==t.nodeName||"checkbox"!==t.type&&"radio"!==t.type||(t.checked=e)},T),t):!T[0]||"INPUT"!==T[0].nodeName||"checkbox"!==T[0].type&&"radio"!==T[0].type?void 0:!!T[0].checked},t.on=function(r,a){return e!==v&&e!==g||(T=[e]),n(function(e){g.addEventListener?e.addEventListener(r,a,!1):g.attachEvent&&(e[r+a]=function(){return a.apply(e,arguments)},e.attachEvent("on"+r,e[r+a]))},T),t},t.off=function(r,a){return e!==v&&e!==g||(T=[e]),n(function(e){g.addEventListener?e.removeEventListener(r,a,!1):g.attachEvent&&(e.detachEvent("on"+r,e[r+a]),e[r+a]=null)},T),t},t.ajax=function(e,n,r,a,o){var c,s,u=i(T),l=n?n.toUpperCase():"GET",f=new RegExp("http[s]?://(.*?)/","gi").exec(e),d="_ts="+ +new Date,p=g.getElementsByTagName("head")[0],h="chibi"+ +new Date+(m+=1);return!u||"GET"!==l&&"DELETE"!==l||(e+=-1===e.indexOf("?")?"?"+u:"&"+u,u=null),"GET"===l&&!o&&f&&v.location.host!==f[1]?(a&&(e+=-1===e.indexOf("?")?"?"+d:"&"+d),e=e.replace("=%3F","=?"),r&&-1!==e.indexOf("=?")&&(e=e.replace("=?","="+h),v[h]=function(e){try{r(e,200)}catch(e){}v[h]=void 0}),(s=document.createElement("script")).async=!0,s.src=e,s.onload=function(){p.removeChild(s)},p.appendChild(s)):(v.XMLHttpRequest?c=new XMLHttpRequest:v.ActiveXObject&&(c=new ActiveXObject("Microsoft.XMLHTTP")),c&&(a&&(e+=-1===e.indexOf("?")?"?"+d:"&"+d),c.open(l,e,!0),c.onreadystatechange=function(){4===c.readyState&&r&&r(c.responseText,c.status)},c.setRequestHeader("X-Requested-With","XMLHttpRequest"),"POST"!==l&&"PUT"!==l||c.setRequestHeader("Content-Type","application/x-www-form-urlencoded"),c.send(u))),t},t.get=function(e,n,r,a){return t.ajax(e,"get",n,r,a)},t.post=function(e,n,r){return t.ajax(e,"post",n,r)},t}var d=[],p=[],h=!1,y=!1,m=0,g=document,v=window;g.addEventListener?(g.addEventListener("DOMContentLoaded",e,!1),v.addEventListener("load",t,!1)):g.attachEvent?(g.attachEvent("onreadystatechange",e),v.attachEvent("onload",t)):v.onload=t,v.$=f}();
--------------------------------------------------------------------------------
/chibi.js:
--------------------------------------------------------------------------------
1 | /*!chibi 3.0.9, Copyright 2012-2017 Kyle Barrow, released under MIT license */
2 | (function () {
3 | 'use strict';
4 |
5 | var readyfn = [],
6 | loadedfn = [],
7 | domready = false,
8 | pageloaded = false,
9 | jsonpcount = 0,
10 | d = document,
11 | w = window;
12 |
13 | // Fire any function calls on ready event
14 | function fireReady() {
15 | var i;
16 | domready = true;
17 | for (i = 0; i < readyfn.length; i += 1) {
18 | readyfn[i]();
19 | }
20 | readyfn = [];
21 | }
22 |
23 | // Fire any function calls on loaded event
24 | function fireLoaded() {
25 | var i;
26 | pageloaded = true;
27 | // For browsers with no DOM loaded support
28 | if (!domready) {
29 | fireReady();
30 | }
31 | for (i = 0; i < loadedfn.length; i += 1) {
32 | loadedfn[i]();
33 | }
34 | loadedfn = [];
35 | }
36 |
37 | // Check DOM ready, page loaded
38 | if (d.addEventListener) {
39 | // Standards
40 | d.addEventListener('DOMContentLoaded', fireReady, false);
41 | w.addEventListener('load', fireLoaded, false);
42 | } else if (d.attachEvent) {
43 | // IE
44 | d.attachEvent('onreadystatechange', fireReady);
45 | // IE < 9
46 | w.attachEvent('onload', fireLoaded);
47 | } else {
48 | // Anything else
49 | w.onload = fireLoaded;
50 | }
51 |
52 | // Utility functions
53 |
54 | // Loop through node array
55 | function nodeLoop(fn, nodes) {
56 | var i;
57 | // Good idea to walk up the DOM
58 | for (i = nodes.length - 1; i >= 0; i -= 1) {
59 | fn(nodes[i]);
60 | }
61 | }
62 |
63 | // Convert to camel case
64 | function cssCamel(property) {
65 | return property.replace(/-\w/g, function (result) {return result.charAt(1).toUpperCase(); });
66 | }
67 |
68 | // Get computed style
69 | function computeStyle(elm, property) {
70 | // IE, everything else or null
71 | return (elm.currentStyle) ? elm.currentStyle[cssCamel(property)] : (w.getComputedStyle) ? w.getComputedStyle(elm, null).getPropertyValue(property) : null;
72 |
73 | }
74 |
75 | // Returns URI encoded query string pair
76 | function queryPair(name, value) {
77 | return encodeURIComponent(name).replace(/%20/g, '+') + '=' + encodeURIComponent(value).replace(/%20/g, '+');
78 | }
79 |
80 | // Set CSS, important to wrap in try to prevent error thrown on unsupported property
81 | function setCss(elm, property, value) {
82 | try {
83 | elm.style[cssCamel(property)] = value;
84 | } catch (e) {
85 | console.error('Could not set css style property "' + property + '".');
86 | }
87 | }
88 |
89 | // Show CSS
90 | function showCss(elm) {
91 | elm.style.display = '';
92 | // For elements still hidden by style block
93 | if (computeStyle(elm, 'display') === 'none') {
94 | elm.style.display = 'block';
95 | }
96 | }
97 |
98 | // Serialize form & JSON values
99 | function serializeData(nodes) {
100 | var querystring = '', subelm, i, j;
101 | if (nodes.constructor === Object) { // Serialize JSON data
102 | for (subelm in nodes) {
103 | if (nodes.hasOwnProperty(subelm)) {
104 | if (nodes[subelm].constructor === Array) {
105 | for (i = 0; i < nodes[subelm].length; i += 1) {
106 | querystring += '&' + queryPair(subelm, nodes[subelm][i]);
107 | }
108 | } else {
109 | querystring += '&' + queryPair(subelm, nodes[subelm]);
110 | }
111 | }
112 | }
113 | } else { // Serialize node data
114 | nodeLoop(function (elm) {
115 | if (elm.nodeName === 'FORM') {
116 | for (i = 0; i < elm.elements.length; i += 1) {
117 | subelm = elm.elements[i];
118 |
119 | if (!subelm.disabled) {
120 | switch (subelm.type) {
121 | // Ignore buttons, unsupported XHR 1 form fields
122 | case 'button':
123 | case 'image':
124 | case 'file':
125 | case 'submit':
126 | case 'reset':
127 | break;
128 |
129 | case 'select-one':
130 | if (subelm.length > 0) {
131 | querystring += '&' + queryPair(subelm.name, subelm.value);
132 | }
133 | break;
134 |
135 | case 'select-multiple':
136 | for (j = 0; j < subelm.length; j += 1) {
137 | if (subelm[j].selected) {
138 | querystring += '&' + queryPair(subelm.name, subelm[j].value);
139 | }
140 | }
141 | break;
142 |
143 | case 'checkbox':
144 | case 'radio':
145 | if (subelm.checked) {
146 | querystring += '&' + queryPair(subelm.name, subelm.value);
147 | }
148 | break;
149 |
150 | // Everything else including shinny new HTML5 input types
151 | default:
152 | querystring += '&' + queryPair(subelm.name, subelm.value);
153 | }
154 | }
155 | }
156 | }
157 | }, nodes);
158 | }
159 | // Tidy up first &
160 | return (querystring.length > 0) ? querystring.substring(1) : '';
161 | }
162 |
163 | // Class helper
164 | function classHelper(classes, action, nodes) {
165 | var classarray, search, replace, i, has = false;
166 | if (classes) {
167 | // Trim any whitespace
168 | classarray = classes.split(/\s+/);
169 | nodeLoop(function (elm) {
170 | for (i = 0; i < classarray.length; i += 1) {
171 | search = new RegExp('\\b' + classarray[i] + '\\b', 'g');
172 | replace = new RegExp(' *' + classarray[i] + '\\b', 'g');
173 | if (action === 'remove') {
174 | elm.className = elm.className.replace(replace, '');
175 | } else if (action === 'toggle') {
176 | elm.className = (elm.className.match(search)) ? elm.className.replace(replace, '') : elm.className + ' ' + classarray[i];
177 | } else if (action === 'has') {
178 | if (elm.className.match(search)) {
179 | has = true;
180 | break;
181 | }
182 | }
183 | }
184 | }, nodes);
185 | }
186 | return has;
187 | }
188 |
189 | // HTML insertion helper
190 | function insertHtml(value, position, nodes) {
191 | var tmpnodes, tmpnode;
192 | if (value) {
193 | nodeLoop(function (elm) {
194 | // No insertAdjacentHTML support for FF < 8 and IE doesn't allow insertAdjacentHTML table manipulation, so use this instead
195 | // Convert string to node. We can't innerHTML on a document fragment
196 | tmpnodes = d.createElement('div');
197 | tmpnodes.innerHTML = value;
198 | while ((tmpnode = tmpnodes.lastChild) !== null) {
199 | // Catch error in unlikely case elm has been removed
200 | try {
201 | if (position === 'before') {
202 | elm.parentNode.insertBefore(tmpnode, elm);
203 | } else if (position === 'after') {
204 | elm.parentNode.insertBefore(tmpnode, elm.nextSibling);
205 | } else if (position === 'append') {
206 | elm.appendChild(tmpnode);
207 | } else if (position === 'prepend') {
208 | elm.insertBefore(tmpnode, elm.firstChild);
209 | }
210 | } catch (e) {break; }
211 | }
212 | }, nodes);
213 | }
214 | }
215 |
216 | // Get nodes and return chibi
217 | function chibi(selector) {
218 | var cb, nodes = [], json = false, nodelist, i;
219 |
220 | if (selector) {
221 |
222 | // Element node, would prefer to use (selector instanceof HTMLElement) but no IE support
223 | if (selector.nodeType && selector.nodeType === 1) {
224 | nodes = [selector]; // return element as node list
225 | } else if (typeof selector === 'object') {
226 | // JSON, document object or node list, would prefer to use (selector instanceof NodeList) but no IE support
227 | json = (typeof selector.length !== 'number');
228 | nodes = selector;
229 | } else if (typeof selector === 'string') {
230 |
231 | // A very light querySelectorAll polyfill for IE < 8. It suits my needs but is restricted to IE CSS support, is no speed demon, and does leave older mobile browsers in the cold (that support neither querySelectorAll nor currentStyle/getComputedStyle). If you want to use a fuller featured selector engine like Qwery, Sizzle et al, just return results to the nodes array: nodes = altselectorengine(selector)
232 |
233 | // IE < 8
234 | if (!d.querySelectorAll) {
235 | // Polyfill querySelectorAll
236 | d.querySelectorAll = function (selector) {
237 |
238 | var style, head = d.getElementsByTagName('head')[0], allnodes, selectednodes = [], i;
239 |
240 | style = d.createElement('STYLE');
241 | style.type = 'text/css';
242 |
243 | if (style.styleSheet) {
244 | style.styleSheet.cssText = selector + ' {a:b}';
245 |
246 | head.appendChild(style);
247 |
248 | allnodes = d.getElementsByTagName('*');
249 |
250 | for (i = 0; i < allnodes.length; i += 1) {
251 | if (computeStyle(allnodes[i], 'a') === 'b') {
252 | selectednodes.push(allnodes[i]);
253 | }
254 | }
255 |
256 | head.removeChild(style);
257 | }
258 |
259 | return selectednodes;
260 | };
261 | }
262 |
263 | nodelist = d.querySelectorAll(selector);
264 |
265 | // Convert node list to array so results have full access to array methods
266 | // Array.prototype.slice.call not supported in IE < 9 and often slower than loop anyway
267 | for (i = 0; i < nodelist.length; i += 1) {
268 | nodes[i] = nodelist[i];
269 | }
270 |
271 | }
272 | }
273 |
274 | // Only attach nodes if not JSON
275 | cb = json ? {} : nodes;
276 |
277 | // Public functions
278 |
279 | // Fire on DOM ready
280 | cb.ready = function (fn) {
281 | if (fn) {
282 | if (domready) {
283 | fn();
284 | return cb;
285 | } else {
286 | readyfn.push(fn);
287 | }
288 | }
289 | };
290 | // Fire on page loaded
291 | cb.loaded = function (fn) {
292 | if (fn) {
293 | if (pageloaded) {
294 | fn();
295 | return cb;
296 | } else {
297 | loadedfn.push(fn);
298 | }
299 | }
300 | };
301 | // Executes a function on nodes
302 | cb.each = function (fn) {
303 | if (typeof fn === 'function') {
304 | nodeLoop(function (elm) {
305 | // <= IE 8 loses scope so need to apply
306 | return fn.apply(elm, arguments);
307 | }, nodes);
308 | }
309 | return cb;
310 | };
311 | // Find first
312 | cb.first = function () {
313 | return chibi(nodes.shift());
314 | };
315 | // Find last
316 | cb.last = function () {
317 | return chibi(nodes.pop());
318 | };
319 | // Find odd
320 | cb.odd = function () {
321 | var odds = [], i;
322 | for (i = 0; i < nodes.length; i += 2) {
323 | odds.push(nodes[i]);
324 | }
325 | return chibi(odds);
326 | };
327 | // Find even
328 | cb.even = function () {
329 | var evens = [], i;
330 | for (i = 1; i < nodes.length; i += 2) {
331 | evens.push(nodes[i]);
332 | }
333 | return chibi(evens);
334 | };
335 | // Hide node
336 | cb.hide = function () {
337 | nodeLoop(function (elm) {
338 | elm.style.display = 'none';
339 | }, nodes);
340 | return cb;
341 | };
342 | // Show node
343 | cb.show = function () {
344 | nodeLoop(function (elm) {
345 | showCss(elm);
346 | }, nodes);
347 | return cb;
348 | };
349 | // Toggle node display
350 | cb.toggle = function () {
351 | nodeLoop(function (elm) {
352 | // computeStyle instead of style.display == 'none' catches elements that are hidden via style block
353 | if (computeStyle(elm, 'display') === 'none') {
354 | showCss(elm);
355 | } else {
356 | elm.style.display = 'none';
357 | }
358 |
359 | }, nodes);
360 | return cb;
361 | };
362 | // Remove node
363 | cb.remove = function () {
364 | nodeLoop(function (elm) {
365 | // Catch error in unlikely case elm has been removed
366 | try {
367 | elm.parentNode.removeChild(elm);
368 | } catch (e) {}
369 | }, nodes);
370 | return chibi();
371 | };
372 | // Get/Set CSS
373 | cb.css = function (property, value) {
374 | if (property) {
375 | if (value || value === '') {
376 | nodeLoop(function (elm) {
377 | setCss(elm, property, value);
378 | }, nodes);
379 | return cb;
380 | }
381 | if (nodes[0]) {
382 | if (nodes[0].style[cssCamel(property)]) {
383 | return nodes[0].style[cssCamel(property)];
384 | }
385 | if (computeStyle(nodes[0], property)) {
386 | return computeStyle(nodes[0], property);
387 | }
388 | }
389 | }
390 | };
391 | // Get class(es)
392 | cb.getClass = function () {
393 | if (nodes[0] && nodes[0].className.length > 0) {
394 | // Weak IE trim support
395 | return nodes[0].className.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '').replace(/\s+/,' ');
396 | }
397 | };
398 | // Set (replaces) classes
399 | cb.setClass = function (classes) {
400 | if (classes || classes === '') {
401 | nodeLoop(function (elm) {
402 | elm.className = classes;
403 | }, nodes);
404 | }
405 | return cb;
406 | };
407 | // Add class
408 | cb.addClass = function (classes) {
409 | if (classes) {
410 | nodeLoop(function (elm) {
411 | elm.className += ' ' + classes;
412 | }, nodes);
413 | }
414 | return cb;
415 | };
416 | // Remove class
417 | cb.removeClass = function (classes) {
418 | classHelper(classes, 'remove', nodes);
419 | return cb;
420 | };
421 | // Toggle class
422 | cb.toggleClass = function (classes) {
423 | classHelper(classes, 'toggle', nodes);
424 | return cb;
425 | };
426 | // Has class
427 | cb.hasClass = function (classes) {
428 | return classHelper(classes, 'has', nodes);
429 | };
430 | // Get/set HTML
431 | cb.html = function (value) {
432 | if (value || value === '') {
433 | nodeLoop(function (elm) {
434 | elm.innerHTML = value;
435 | }, nodes);
436 | return cb;
437 | }
438 | if (nodes[0]) {
439 | return nodes[0].innerHTML;
440 | }
441 | };
442 | // Insert HTML before selector
443 | cb.htmlBefore = function (value) {
444 | insertHtml(value, 'before', nodes);
445 | return cb;
446 | };
447 | // Insert HTML after selector
448 | cb.htmlAfter = function (value) {
449 | insertHtml(value, 'after', nodes);
450 | return cb;
451 | };
452 | // Insert HTML after selector innerHTML
453 | cb.htmlAppend = function (value) {
454 | insertHtml(value, 'append', nodes);
455 | return cb;
456 | };
457 | // Insert HTML before selector innerHTML
458 | cb.htmlPrepend = function (value) {
459 | insertHtml(value, 'prepend', nodes);
460 | return cb;
461 | };
462 | // Get/Set HTML attributes
463 | cb.attr = function (property, value) {
464 | if (property) {
465 | property = property.toLowerCase();
466 | // IE < 9 doesn't allow style or class via get/setAttribute so switch. cssText returns prettier CSS anyway
467 | if (value || value === '') {
468 | nodeLoop(function (elm) {
469 | if (property === 'style') {
470 | elm.style.cssText = value;
471 | } else if (property === 'class') {
472 | elm.className = value;
473 | } else {
474 | elm.setAttribute(property, value);
475 | }
476 | }, nodes);
477 | return cb;
478 | }
479 | if (nodes[0]) {
480 | if (property === 'style') {
481 | if (nodes[0].style.cssText) {
482 | return nodes[0].style.cssText;
483 | }
484 | } else if (property === 'class') {
485 | if (nodes[0].className) {
486 | return nodes[0].className;
487 | }
488 | } else {
489 | if (nodes[0].getAttribute(property)) {
490 | return nodes[0].getAttribute(property);
491 | }
492 | }
493 | }
494 | }
495 | };
496 | // Get/Set HTML data property
497 | cb.data = function (key, value) {
498 | if (key) {
499 | return cb.attr('data-'+key, value);
500 | }
501 | };
502 | // Get/Set form element values
503 | cb.val = function (value) {
504 | var values, i, j;
505 | if (value || value === '') {
506 | nodeLoop(function (elm) {
507 | switch (elm.nodeName) {
508 | case 'SELECT':
509 | if (typeof value === 'string' || typeof value === 'number') {
510 | value = [value];
511 | }
512 | for (i = 0; i < elm.length; i += 1) {
513 | // Multiple select
514 | for (j = 0; j < value.length; j += 1) {
515 | elm[i].selected = '';
516 | if (elm[i].value === value[j]) {
517 | elm[i].selected = 'selected';
518 | break;
519 | }
520 | }
521 | }
522 | break;
523 | case 'INPUT':
524 | case 'TEXTAREA':
525 | case 'BUTTON':
526 | elm.value = value;
527 | break;
528 | }
529 | }, nodes);
530 |
531 | return cb;
532 | }
533 | if (nodes[0]) {
534 | switch (nodes[0].nodeName) {
535 | case 'SELECT':
536 | values = [];
537 | for (i = 0; i < nodes[0].length; i += 1) {
538 | if (nodes[0][i].selected) {
539 | values.push(nodes[0][i].value);
540 | }
541 | }
542 | return (values.length > 1) ? values : values[0];
543 | case 'INPUT':
544 | case 'TEXTAREA':
545 | case 'BUTTON':
546 | return nodes[0].value;
547 | }
548 | }
549 | };
550 | // Return matching checked checkbox or radios
551 | cb.checked = function (check) {
552 | if (typeof check === 'boolean') {
553 | nodeLoop(function (elm) {
554 | if (elm.nodeName === 'INPUT' && (elm.type === 'checkbox' || elm.type === 'radio')) {
555 | elm.checked = check;
556 | }
557 | }, nodes);
558 | return cb;
559 | }
560 | if (nodes[0] && nodes[0].nodeName === 'INPUT' && (nodes[0].type === 'checkbox' || nodes[0].type === 'radio')) {
561 | return (!!nodes[0].checked);
562 | }
563 | };
564 | // Add event handler
565 | cb.on = function (event, fn) {
566 | if (selector === w || selector === d) {
567 | nodes = [selector];
568 | }
569 | nodeLoop(function (elm) {
570 | if (d.addEventListener) {
571 | elm.addEventListener(event, fn, false);
572 | } else if (d.attachEvent) {
573 | // <= IE 8 loses scope so need to apply, we add this to object so we can detach later (can't detach anonymous functions)
574 | elm[event + fn] = function () { return fn.apply(elm, arguments); };
575 | elm.attachEvent('on' + event, elm[event + fn]);
576 | }
577 | }, nodes);
578 | return cb;
579 | };
580 | // Remove event handler
581 | cb.off = function (event, fn) {
582 | if (selector === w || selector === d) {
583 | nodes = [selector];
584 | }
585 | nodeLoop(function (elm) {
586 | if (d.addEventListener) {
587 | elm.removeEventListener(event, fn, false);
588 | } else if (d.attachEvent) {
589 | elm.detachEvent('on' + event, elm[event + fn]);
590 | // Tidy up
591 | elm[event + fn] = null;
592 | }
593 | }, nodes);
594 | return cb;
595 | };
596 | // Basic XHR 1, no file support. Shakes fist at IE
597 | cb.ajax = function (url, method, callback, nocache, nojsonp) {
598 | var xhr,
599 | query = serializeData(nodes),
600 | type = (method) ? method.toUpperCase() : 'GET',
601 | hostsearch = new RegExp('http[s]?://(.*?)/', 'gi'),
602 | domain = hostsearch.exec(url),
603 | timestamp = '_ts=' + (+new Date()),
604 | head = d.getElementsByTagName('head')[0],
605 | jsonpcallback = 'chibi' + (+new Date()) + (jsonpcount += 1),
606 | script;
607 |
608 | if (query && (type === 'GET' || type === 'DELETE')) {
609 | url += (url.indexOf('?') === -1) ? '?' + query : '&' + query;
610 | query = null;
611 | }
612 |
613 | // JSONP if cross domain url
614 | if (type === 'GET' && !nojsonp && domain && w.location.host !== domain[1]) {
615 |
616 | if (nocache) {
617 | url += (url.indexOf('?') === -1) ? '?' + timestamp : '&' + timestamp;
618 | }
619 |
620 | // Replace possible encoded ?
621 | url = url.replace('=%3F', '=?');
622 |
623 | // Replace jsonp ? with callback
624 | if (callback && url.indexOf('=?') !== -1) {
625 |
626 | url = url.replace('=?', '=' + jsonpcallback);
627 |
628 | w[jsonpcallback] = function (data) {
629 | try {
630 | callback(data, 200);
631 | } catch (e) {}
632 |
633 | // Tidy up
634 | w[jsonpcallback] = undefined;
635 | };
636 | }
637 |
638 | // JSONP
639 | script = document.createElement('script');
640 | script.async = true;
641 | script.src = url;
642 |
643 | // Tidy up
644 | script.onload = function () {
645 | head.removeChild(script);
646 | };
647 |
648 | head.appendChild(script);
649 |
650 | } else {
651 |
652 | if (w.XMLHttpRequest) {
653 | xhr = new XMLHttpRequest();
654 | } else if (w.ActiveXObject) {
655 | xhr = new ActiveXObject('Microsoft.XMLHTTP'); // IE < 9
656 | }
657 |
658 | if (xhr) {
659 |
660 | if (nocache) {
661 | url += (url.indexOf('?') === -1) ? '?' + timestamp : '&' + timestamp;
662 | }
663 |
664 | // Douglas Crockford: "Synchronous programming is disrespectful and should not be employed in applications which are used by people"
665 | xhr.open(type, url, true);
666 |
667 | xhr.onreadystatechange = function () {
668 | if (xhr.readyState === 4) {
669 | if (callback) {
670 | callback(xhr.responseText, xhr.status);
671 | }
672 | }
673 | };
674 |
675 | xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
676 |
677 | if (type === 'POST' || type === 'PUT') {
678 | xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
679 | }
680 |
681 | xhr.send(query);
682 |
683 | }
684 | }
685 | return cb;
686 | };
687 | // Alias to cb.ajax(url, 'get', callback, nocache, nojsonp)
688 | cb.get = function (url, callback, nocache, nojsonp) {
689 | return cb.ajax(url, 'get', callback, nocache, nojsonp);
690 | };
691 | // Alias to cb.ajax(url, 'post', callback, nocache)
692 | cb.post = function (url, callback, nocache) {
693 | return cb.ajax(url, 'post', callback, nocache);
694 | };
695 |
696 | return cb;
697 | }
698 |
699 | // Set Chibi's global namespace here ($)
700 | w.$ = chibi;
701 |
702 | }());
703 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp'),
2 | replace = require('gulp-replace'),
3 | jshint = require('gulp-jshint'),
4 | rename = require('gulp-rename'),
5 | uglify = require('gulp-uglify'),
6 | qunit = require('gulp-qunit'),
7 | package = require('./package.json');
8 |
9 | var paths = {
10 | source: ['chibi.js'],
11 | readme: ['README.md'],
12 | test: ['tests/runner.html']
13 | };
14 |
15 | var handleError = function(err) {
16 | process.exit(1);
17 | }
18 |
19 | gulp.task('update', function(callback) {
20 | gulp.src(paths.source)
21 | .pipe(replace(/(\/\*!)(.*)(\*\/)/g, '$1chibi '+package.version+', Copyright 2012-'+(new Date()).getUTCFullYear()+' '+package.author.name+', released under '+package.license+' license $3'))
22 | .pipe(gulp.dest(''))
23 | gulp.src(paths.readme)
24 | .pipe(replace(/(\# Chibi v)([\d\.]*)/g, '$1'+package.version))
25 | .pipe(gulp.dest(''))
26 | .on('end', callback);
27 | });
28 |
29 | gulp.task('lint', function() {
30 | gulp.src(paths.source)
31 | .pipe(jshint())
32 | .pipe(jshint.reporter('default'))
33 | .pipe(jshint.reporter('fail'))
34 | .on('error', handleError);
35 | });
36 |
37 | gulp.task('compress', function() {
38 | gulp.src(paths.source)
39 | .pipe(rename('chibi-min.js'))
40 | .pipe(uglify({output: {comments: /^!/i}}))
41 | .pipe(gulp.dest(''));
42 | });
43 |
44 | gulp.task('test', function() {
45 | gulp.src(paths.test)
46 | .pipe(qunit())
47 | .on('error', handleError);
48 | });
49 |
50 | gulp.task('watch', function() {
51 | gulp.watch(paths.source, ['lint', 'compress']);
52 | });
53 |
54 | gulp.task('default', ['lint', 'compress', 'test']);
55 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "chibijs",
3 | "version": "3.0.9",
4 | "description": "A tiny JavaScript micro-library",
5 | "keywords": [
6 | "browser",
7 | "chibi",
8 | "dom",
9 | "library",
10 | "microlibrary"
11 | ],
12 | "homepage": "https://github.com/kylebarrow/chibi",
13 | "bugs": {
14 | "url": "https://github.com/kylebarrow/chibi/issues"
15 | },
16 | "license": "MIT",
17 | "author": {
18 | "name": "Kyle Barrow",
19 | "email": "kyle@barrow.io",
20 | "url": "https://barrow.io"
21 | },
22 | "main": "chibi-min.js",
23 | "repository": {
24 | "type": "git",
25 | "url": "https://github.com/kylebarrow/chibi.git"
26 | },
27 | "devDependencies": {
28 | "gulp": "^3.9.1",
29 | "gulp-jshint": "^2.0.4",
30 | "gulp-qunit": "^1.5.0",
31 | "gulp-rename": "^1.2.2",
32 | "gulp-replace": "^0.5.4",
33 | "gulp-uglify": "^3.0.0",
34 | "jshint": "^2.9.4",
35 | "qunitjs": "^2.3.3"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/tests/runner.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Chibi Unit Tests
5 |
6 |
7 |
25 |
26 |
27 |
461 |
462 |
463 |
464 |
465 | Element 1
466 | Element 2
467 | Element 3
468 | Element 4
469 | Element 5
470 |
471 |
485 |
496 |