0/*!
1 * kimbo v1.0.4 - 2013-12-11
2 * http://kimbojs.com
3 * Copyright (c) 2013 Denis Ciccale (@tdecs)
4 * Released under the MIT license
5 * https://github.com/dciccale/kimbo.js/blob/master/LICENSE.txt
6 */
7(function (window, document) {
8
9  'use strict';
10
11  /*\
12   * $
13   [ object ]
14   * Global namespace for using Kimbo functions
15  \*/
16
17  // Kimbo modules
18  var modules = {};
19
20  // Common helpers
21  var _ = {
22
23    // Array methods
24    push: Array.prototype.push,
25    slice: Array.prototype.slice,
26
27    // Reference to the current document
28    document: document,
29    rootContext: document,
30
31    // Creates and returns a new Kimbo object
32    kimbo: function (element) {
33      return new Kimbo(element);
34    }
35  };
36
37  /*\
38   * $(…)
39   * Kimbo object collection.
40   * All methods called from a Kimbo collection affects all elements in it.
41  \*/
42  var Kimbo = function (selector, context) {
43    var match;
44
45    // Auto create a new instance of Kimbo if needed
46    if (!(this instanceof Kimbo)) {
47      return new Kimbo(selector, context);
48    }
49
50    // No selector, return empty Kimbo object
51    if (!selector) {
52      return this;
53    }
54
55    // Asume a css selector, query the dom
56    if (typeof selector === 'string') {
57
58      // Handle faster $('#id');
59      match = /^#([\w\-]+)$/.exec(selector);
60      if (match && match[1]) {
61        match = document.getElementById(match[1]);
62
63        if (match) {
64          this[0] = match;
65          this.length = 1;
66        }
67
68        return this;
69      }
70
71      // All other selectors
72      context = context ? _.kimbo(context) : _.rootContext;
73
74      return context.find(selector);
75    }
76
77    // Already a dom element
78    if (selector.nodeType) {
79      this[0] = selector;
80      this.length = 1;
81      return this;
82    }
83
84    // Is a function, call it when DOM is ready
85    if (Kimbo.isFunction(selector)) {
86      return _.rootContext.ready(selector);
87    }
88
89    // Handle kimbo object, plain objects or other objects
90    return Kimbo.makeArray(selector, this);
91  };
92
93  Kimbo.require = function (module) {
94    return modules[module];
95  };
96
97  Kimbo.define = function (module, fn) {
98    modules[module] = fn(_);
99  };
100
101  /*
102   * Kimbo prototype aliased as fn
103   */
104  Kimbo.prototype = Kimbo.fn = {
105
106    /*\
107     * $(…).length
108     [ property ]
109     * The length of the current Kimbo collection.
110     = (number) Integer representing the lenght of the current collection.
111     > Usage
112     * Having these paragraphs:
113     | <p>one</p>
114     | <p>two</p>
115     | <p>three</p>
116     * Grab them and check for the length property:
117     | $('p').length; // 3
118    \*/
119    length: 0,
120
121    /*\
122     * $(…).ready
123     [ method ]
124     * Execute a callback after de DOM is completely loaded
125     > Parameters
126     - callback (function) A function to call after de DOM is ready
127     = (object) The original element
128     > Usage
129     | $(document).ready(function () {
130     |   console.log('the DOM is loaded!');
131     | });
132     * Or using the shortcut (recommended)
133     | $(function () {
134     |   console.log('the DOM is loaded!);
135     | });
136    \*/
137    ready: function (callback) {
138      var completed;
139
140      // First check if already loaded, interactive or complete state so the t is enough
141      if (/t/.test(document.readyState)) {
142
143        // Execute the callback
144        callback.call(document);
145
146      // If not listen for when it loads
147      } else {
148        completed = function () {
149
150          // When completed remove the listener
151          document.removeEventListener('DOMContentLoaded', completed, false);
152
153          // Execute the callback
154          callback.call(document);
155        };
156
157        // Register the event
158        document.addEventListener('DOMContentLoaded', completed, false);
159      }
160
161      // Return the Kimbo wrapped document
162      return _.rootContext;
163    },
164
165    /*\
166     * $(…).get
167     [ method ]
168     * Retrieve native DOM elements from the current collection
169     > Parameters
170     - index (number) #optional A zero-based integer indicating which element to retrieve, supports going backwards with negative index.
171     = (array|object) An array of the native DOM elements or the specified element by index matched by Kimbo.
172     > Usage
173     | <ul>
174     |   <li id="foo"></li>
175     |   <li id="bar"></li>
176     | </ul>
177     * Get standard array of elements
178     | $('li').get(); // [<li id="foo">, <li id="bar">]
179     * Get the first element
180     | $('li').get(0); // <li id="foo">
181     * Get the last element
182     | $('li').get(-1); // <li id="bar">
183    \*/
184    get: function (index) {
185      if (!this.length) {
186        return;
187      }
188
189      // If no index specified return a new set
190      // Else return the element in the specified positive index or backwards if negative
191      return (!arguments.length) ? _.slice.call(this) :
192        (index < 0 ? this[this.length + index] : this[index]);
193    },
194
195    // Needed to have an array-like object
196    splice: Array.prototype.splice
197  };
198
199  /*\
200   * $.forEach
201   [ method ]
202   * Iterator function that can be used to seamlessly iterate over both objects and arrays.
203   > Parameters
204   - obj (object) Object or array to iterate
205   - callback (function) Function that will be executed on each iteration
206   = (object) The original array or object
207   > Usage
208   | // Iterating array
209   | $.forEach(['a', 'b', 'c'], function (index, value) {
210   |   alert(index + ': ' + value);
211   | });
212   |
213   | // Iterating object
214   | $.forEach({name: 'Denis', surname: 'Ciccale'}, function (key, value) {
215   |   alert(key + ': ' + value);
216   | });
217  \*/
218  Kimbo.forEach = function (obj, callback) {
219    var l = obj.length;
220    var isObj = l === undefined || typeof obj === 'function';
221    var i;
222
223    if (isObj) {
224      for (i in obj) {
225        if (obj.hasOwnProperty(i) && callback.call(obj[i], i, obj[i], obj) === false) {
226          break;
227        }
228      }
229    } else {
230      for (i = 0; i < l; i++) {
231        if (callback.call(obj[i], obj[i], i, obj) === false) {
232          break;
233        }
234      }
235    }
236
237    // Return original obj
238    return obj;
239  };
240
241
242  /*\
243   * $.extend
244   [ method ]
245   * Merge the contents of two or more objects together into the first object.
246   > Parameters
247   - target (object|boolean) Object that will receive the merged properties if objects are passed, or target will extend Kimbo object. If target is `true` the passed objects will be recursively merged.
248   - objectN (object) #optional One or more objects with additional properties.
249   = (object) The extended target or a new copy if target is an empty object.
250   > Usage
251   * When passing two or more objects, all properties will be merged into the target object.
252   | var obj1 = { msg: 'hi', info: { from: 'Denis' }};
253   | var obj2 = { msg: 'Hi!', info: { time: '22:00PM' }};
254   |
255   | // Merge obj1 into obj2
256   | $.extend(obj1, obj2);
257   |
258   | // Now obj1 is equal to:
259   | { msg: 'Hi!', info: { time: '22:00PM' }}
260   * If an empty target object is passed, none of the other objects will be directly modified
261   | // Pass an empty target
262   | var obj3 = $.extend({}, obj1, obj);
263   * To do a recursive merge, pass true as first argument, then the objects to merge
264   | $.extend(true, obj1, obj2);
265   | // Obj1 will be:
266   | { msg: 'Hi!', info: { from: 'Denis', time: '22:00PM' }}
267  \*/
268  Kimbo.extend = Kimbo.fn.extend = function () {
269    var objs = arguments;
270    var target = objs[0] || {};
271    var deep = (target === true);
272    var cut = 1;
273
274    // Check for deep copy
275    if (deep) {
276      target = objs[1] || {};
277      cut = 2;
278
279    // Extend Kimbo itself if only one argument is passed
280    } else if (objs.length === 1) {
281      target = this;
282      cut = 0;
283    }
284
285    // Make an array from the arguments removing the target and/or the deep boolean
286    objs = _.slice.call(objs, cut);
287
288    // Loop through the objects
289    Kimbo.forEach(objs, function (source) {
290
291      // Populate target from source
292      Kimbo.forEach(source, function (key, value) {
293        var src;
294
295        if (deep && (Kimbo.isObject(value) || Kimbo.isArray(value))) {
296          src = target[key];
297          target[key] = Kimbo.extend(deep, src, value);
298
299        } else if (value !== undefined) {
300          target[key] = value;
301        }
302      });
303    });
304
305    return target;
306  };
307
308  // Unique reference for the current instance of Kimbo
309  Kimbo.ref = 'kimbo' + ('1' + Math.random()).replace(/\D/g, '');
310
311  // Expose Kimbo as an AMD module
312  if (typeof window.define === 'function' && window.define.amd) {
313    window.define('kimbo', [], function () {
314      return Kimbo;
315    });
316  }
317
318  // Expose Kimbo to global object
319  window.Kimbo = window.$ = Kimbo;
320
321}(window, window.document));
322
323
324Kimbo.define('query', function (_) {
325
326  'use strict';
327
328  // Selector regexes
329  var ID_RE = /^#([\w\-]+)$/;
330  var CLASS_RE = /^\.([\w\-]+)$/;
331  var TAG_RE = /^[\w\-]+$/;
332  var NAME_RE = /^\[name=["']?([\w\-]+)["']?\]$/;
333
334  // Use querySelectoAll but optimize for id, class, tagName and name
335  var _find = function (element, selector) {
336    var els = [], sel;
337
338    // #id
339    if (element === _.document && (sel = ID_RE.exec(selector))) {
340      els = element.getElementById(sel[1]);
341
342    // .class
343    } else if ((sel = CLASS_RE.exec(selector))) {
344      els = element.getElementsByClassName(sel[1]);
345
346    // tag
347    } else if (TAG_RE.test(selector)) {
348      els = element.getElementsByTagName(selector);
349
350    // [name=val]
351    } else if ((sel = NAME_RE.exec(selector))) {
352      els = element.getElementsByName(sel[1]);
353
354    // Other CSS selectors
355    } else {
356      els = element.querySelectorAll(selector);
357    }
358
359    // Return NodeList/Node as an array
360    return _.slice.call(els);
361  };
362
363  // DOM Level 4 contains improved
364  var _contains = function (el1, el2) {
365    return (el1 === window && (el2 && (el2 === window || el2.nodeType))) ||
366      ((el1 && el1.nodeType) &&
367     (el2 && el2.nodeType)) ? (el1.contains ? el1.contains(el2) : true) : false;
368  };
369
370  return {
371    find: _find,
372    contains: _contains
373  };
374});
375
376
377Kimbo.define('data', function () {
378
379  'use strict';
380
381  var cache = {};
382  var dataId = 1;
383
384  var data = {
385    get: function (el, key) {
386      var dataCache = cache[el._dataId];
387      var value;
388
389      // Look first in cached data
390      if (dataCache) {
391        value = dataCache[key];
392
393      // If none, try dataset
394      } else {
395        value = el.dataset[key];
396
397        // Cache the value
398        if (value) {
399          this.set(el, key, value);
400        }
401      }
402
403      return value;
404    },
405
406    set: function (el, key, value) {
407      var elementId = el._dataId || (el._dataId = dataId++);
408      var dataCache = cache[elementId];
409
410      // Create data cache for the current element if necessary
411      if (!dataCache) {
412        dataCache = cache[elementId] = {};
413      }
414
415      dataCache[key] = value;
416    },
417
418    remove: function (el, key) {
419      if (key === undefined) {
420        cache[el._dataId] = {};
421      } else {
422        delete cache[el._dataId][key];
423      }
424    }
425  };
426
427  Kimbo.fn.extend({
428    /*\
429     * $(…).data
430     [ method ]
431     * Store or retrieve elements dataset.
432     > Parameters
433     - key (string) Key of the data attribute to to set.
434     - value (string) #optional Value to store in dataset.
435     = (object) Original matched collection.
436     > Usage
437     | <div id="panel"></div>
438     * Set some data to the panel:
439     | $('#panel').data('isOpen', true);
440     * No a data-* attribute was added
441     | <div id="panel" data-isOpen="true"></div>
442     * We can retrieve the data
443     | $('#panel').data('isOpen'); // 'true'
444    \*/
445    data: function (key, value) {
446      if (!this.length || !Kimbo.isString(key)) {
447        return this;
448      }
449
450      key = Kimbo.camelCase(key);
451
452      // Get
453      if (value === undefined) {
454        return data.get(this[0], key);
455
456      // Set
457      } else {
458        return this.each(function (el) {
459          data.set(el, key, value);
460        });
461      }
462    },
463
464    /*\
465     * $(…).removeData
466     [ method ]
467     * Remove data from the element dataset.
468     > Parameters
469     - key (string) Key of the data attribute to to remove.
470     = (object) Original matched collection.
471     > Usage
472     | <div id="panel" data-isOpen="true"></div>
473     * Remove data associated to the panel div:
474     | $('#panel').removeData('isOpen');
475     * Data attribute and value was removed:
476     | <div id="panel"></div>
477     * data-isOpen is undefined
478     | $('#panel').data('isOpen'); // Undefined
479    \*/
480    removeData: function (key) {
481      if (!this.length || !Kimbo.isString(key)) {
482        return this;
483      }
484
485      key = Kimbo.camelCase(key);
486
487      return this.each(function (el) {
488        data.remove(el, key);
489      });
490    }
491  });
492
493  return data;
494});
495
496
497Kimbo.define('css', function (_) {
498
499  'use strict';
500
501  // Properties without 'px' at the end
502  var CSS_NO_PX = {
503    fontWeight: true,
504    lineHeight: true,
505    opacity: true,
506    zIndex: true
507  };
508
509  // Wrap native to extend behavoiur
510  var _getComputedStyle = function (element, property) {
511
512    // Support both camelCase and dashed property names
513    property = property.replace(/([A-Z])/g, '-$1').toLowerCase();
514
515    return window.getComputedStyle(element, null).getPropertyValue(property);
516  };
517
518  var iframe = null;
519
520  var createIframe = function () {
521    iframe = _.document.createElement('iframe');
522    _.document.documentElement.appendChild(iframe);
523    return iframe;
524  };
525
526  var getActualDisplay = function (nodeName, doc) {
527    doc = doc || _.document;
528
529    var elem, display;
530
531    // Create and append the node
532    elem = doc.createElement(nodeName);
533    doc.body.appendChild(elem);
534
535    // Get display
536    display = _getComputedStyle(elem, 'display');
537
538    // Remove it from the dom
539    elem.parentNode.removeChild(elem);
540
541    return display;
542  };
543
544  var elementsDisplay = {};
545
546  Kimbo.fn.extend({
547    /*\
548     * $(…).show
549     [ method ]
550     * Display all matched elements.
551     = (object) Original matched collection.
552     > Usage
553     | <p style="display: none;">Lorem</p>
554     * Show it
555     | $('p').show();
556     * Now it's visible
557     | <p style="display: block;">Lorem</p>
558    \*/
559    show: function () {
560      return this.each(function (el) {
561        var nodeName = el.nodeName;
562        var display = elementsDisplay[nodeName];
563        var doc;
564
565        if (!display) {
566          display = getActualDisplay(nodeName);
567
568          // If still fails for some css rule try creating the element in an isolated iframe
569          if (display === 'none' || !display) {
570
571            // Use the already-created iframe if possible
572            iframe = (iframe || createIframe());
573
574            doc = (iframe.contentWindow || iframe.contentDocument).document;
575            doc.write('<!doctype html><html><body>');
576            doc.close();
577            display = getActualDisplay(nodeName, doc);
578            iframe.parentNode.removeChild(iframe);
579          }
580
581          // Save the default display for this element
582          elementsDisplay[nodeName] = display;
583        }
584
585        el.style.display = display || 'block';
586      });
587    },
588
589    /*\
590     * $(…).hide
591     [ method ]
592     * Hide all matched elements.
593     = (object) Original matched collection.
594     > Usage
595     | <p>Lorem</p>
596     * Hide it
597     | $('p').hide();
598     * Now it's hidden
599     | <p style="display: none;">Lorem</p>
600    \*/
601    hide: function () {
602      return this.each(function (el) {
603        var nodeName = el.nodeName;
604        var display = elementsDisplay[nodeName];
605
606        if (!display) {
607          display = _getComputedStyle(el, 'display');
608          elementsDisplay[nodeName] = display;
609        } else {
610          display = el.style.display;
611        }
612
613        // Only hide if not already hidden
614        if (display !== 'none') {
615          el.style.display = 'none';
616        }
617      });
618    },
619
620    /*\
621     * $(…).css
622     [ method ]
623     * Get the css value of a property from one element or set a css property to all matched elements.
624     > Parameters
625     - property (string|object) Name of the css property.
626     - value (string|number) #optional Value for the property.
627     = (object) Original matched collection.
628     > Usage
629     | <p>Hello dude!</p>
630     * Modify some styles
631     | $('p').css('color', 'red'); // Now the text is red
632     * The HTML will look like this:
633     | <p style="color: red;">Hello dude!</p>
634     * You can also pass an object for setting multiple properties at the same time
635     | $('p').css({
636     |   color: 'red',
637     |   'font-size': '30px',
638     |   backgroundColor: 'blue'
639     | });
640     * Properties can be dash-separated (add quotes) or camelCase.
641     | <p style="color: red; font-size: 30px; background-color: blue">Hello dude!</p>
642    \*/
643    css: function (property, value) {
644      var that = this;
645      var setCss;
646
647      if (!this.length || (!Kimbo.isString(property) && !Kimbo.isObject(property))) {
648        return this;
649      }
650
651      setCss = function (name, value) {
652
653        // If it's a number add 'px' except for some properties
654        if (Kimbo.isNumeric(value) && !CSS_NO_PX[Kimbo.camelCase(name)]) {
655          value += 'px';
656        }
657
658        // Apply styles to all elements in the set
659        that.each(function (el) {
660          el.style[name] = value;
661        });
662      };
663
664      // Setting one property
665      if (Kimbo.isString(property)) {
666
667        // Get
668        if (value === undefined) {
669          return _getComputedStyle(this[0], property);
670
671        // Set
672        } else {
673          setCss(property, value);
674        }
675
676      // Multiple properties with an object
677      } else if (Kimbo.isObject(property)) {
678        Kimbo.forEach(property, setCss);
679      }
680
681      return this;
682    }
683  });
684});
685
686
687Kimbo.define('manipulation', function (_) {
688
689  'use strict';
690
691  var SPACE_RE = /\s+/;
692
693  // Browser native classList
694  var _hasClass = function (el, name) {
695    return (el.nodeType === 1 && el.classList.contains(name));
696  };
697
698  /*\
699   * $(…).text
700   [ method ]
701   * Get the text of the first element in the set or set the text of all the matched elements.
702   > Parameters
703   - value (string) #optional A string of text to set as the text content of all matched elements.
704   = (string) string value of the text content of the element if no parameter passed.
705   = (object) current Kimbo object.
706   > Usage
707   * Get the text content of an element
708   | <p>Demo text</p>
709   * without passing any parameter to the function:
710   | $('p').text(); // 'Demo text'
711   * To replace the text of the paragraph pass a string parameter to the function:
712   | $('p').text('Another text');
713   * Now the text content was replaced:
714   | <p>Another text</p>
715  \*/
716
717  /*\
718   * $(…).html
719   [ method ]
720   * Get the HTML content of the first element in the set or set the HTML content of all the matched elements.
721   > Parameters
722   - value (string) #optional A string of HTML to set as the HTML content of all matched elements.
723   = (string) a string value of the HTML content of the element if no parameter passed.
724   = (object) current Kimbo object.
725   > Usage
726   * Get the HTML content of an element
727   | <p><span>Demo text<span></p>
728   * without passing any parameter to the function:
729   | $('p').html(); // '<span>Demo tetxt</span>'
730   * To replace the HTML content of the paragraph pass a string parameter to the function:
731   | $('p').html('<strong>Another content</strong>');
732   * Now the text content was replaced:
733   | <p><strong>Another content</strong></p>
734  \*/
735
736  /*\
737   * $(…).val
738   [ method ]
739   * Get the current value of the first element in the set or set the value of all the matched elements.
740   > Parameters
741   - value (string) #optional A string of text to set as the value of all matched elements.
742   = (string) the current value of the first element if no parameter passed
743   = (object) current Kimbo object
744   > Usage
745   * Get the value of a form element:
746   | <input type="text" name="color" value="red" />
747   * without passing any parameter to the function:
748   | $('input').val(); // 'red'
749   * To change the value of the input pass a string parameter to the function:
750   | $('input').val('blue');
751   * Now the value was changed:
752   | $('input').val(); // 'blue'
753  \*/
754  Kimbo.forEach({
755    text: 'textContent',
756    html: 'innerHTML',
757    val: 'value'
758  }, function (method, prop) {
759    Kimbo.fn[method] = function (value) {
760
761      // No element
762      if (!this.length) {
763        return undefined;
764      }
765
766      // Get
767      if (value === undefined) {
768        return this[0][prop];
769
770        // Set
771      } else {
772        return this.each(function (el) {
773          el[prop] = value;
774        });
775      }
776    };
777  });
778
779  /*\
780   * $(…).addClass
781   [ method ]
782   * Adds a class to all matched elements.
783   > Parameters
784   - name (string) Name of the class to add.
785   = (object) Original matched collection.
786   > Usage
787   | <p>I want to be green</p>
788   | <script>
789   | $('p').addClass('green');
790   | </script>
791   * Now it's green
792   | <p class="green">I want to be green</p>
793   * You can add multiple classes separated by a space
794   | <p>Add classes to me</p>
795   | <script>
796   | $('p').addClass('green big width100');
797   | </script>
798   * All classes added and they won't be repetead if you try to add an existing one
799   | <p class="green big width100">Add classes to me</p>
800  \*/
801
802  /*\
803   * $(…).removeClass
804   [ method ]
805   * Removes a class to all matched elements.
806   > Parameters
807   - name (string) Name of the class to remove.
808   = (object) Original matched collection.
809   > Usage
810   | <p class="big green title float-rigth">Lorem ipsum</p>
811   * Remove a specific class from the paragraph:
812   | $('p').removeClass('green');
813   * The specified class was removed:
814   | <p class="big title float-right">Lorem ipsum</p>
815   * You can remove multiple classes separating them by a space when calling the function:
816   | $('p').removeClass('big title');
817   * Now only one class left:
818   | <p class="float-right">Lorem ipsum</p>
819   * You can remove all classes just calling .removeClass() without parameters
820   | $('p').removeClass();
821   * All classes were removed including the class attribute:
822   | <p>Lorem ipsum</p>
823  \*/
824
825  // Generate addClass and removeClass methods
826  // Use native classList
827  // Mdn: https://developer.mozilla.org/en-US/docs/DOM/element.classList
828  // Spec: http://www.whatwg.org/specs/web-apps/current-work/multipage/elements.html#dom-classlist
829  Kimbo.forEach(['add', 'remove'], function (method, i) {
830    var isRemove = i > 0;
831
832    Kimbo.fn[method + 'Class'] = function (name) {
833      var classNames;
834
835      if (name && Kimbo.isString(name)) {
836        classNames = name.split(SPACE_RE);
837        this.each(function (el) {
838
839          // Skip comments, text, etc
840          if (el.nodeType === 1) {
841
842            // Iterate through all class names passed
843            Kimbo.forEach(classNames, function (className) {
844              el.classList[method](className);
845            });
846          }
847        });
848
849        // Remove all element classes if no classname specified
850      } else if (!name && isRemove) {
851        this.removeAttr('class');
852      }
853
854      return this;
855    };
856  });
857
858  /*\
859   * $(…).append
860   [ method ]
861   * Insert content to the end of all elements matched by Kimbo.
862   > Parameters
863   - value (string|object) HTML string, DOM element, or Kimbo object to insert.
864   = (object) Original matched collection.
865   > Usage
866   | <div class="container">
867   |   <p class="lorem">Lorem </p>
868   |   <p class="lorem">Lorem </p>
869   | </div>
870   * Insert content
871   | $('.lorem').append('<em>ipsum</em>')
872   * Each element gets the content
873   | <div class="container">
874   |   <p class="lorem">Lorem <em>ipsum</em></p>
875   |   <p class="lorem">Lorem <em>ipsum</em></p>
876   | </div>
877   * You can also get an element and insert it elsewhere
878   | $('.container').append($('.ipsum'))
879   * The selected element will be moved, not cloned.
880   | <div class="container">
881   |   <p class="lorem">Lorem</p>
882   |   <p class="lorem">Lorem</p>
883   |   <p class="ipsum">Ipsum</p>
884   | </div>
885  \*/
886
887  /*\
888   * $(…).prepend
889   [ method ]
890   * Insert content to the beginning of all elements matched by Kimbo.
891   > Parameters
892   - value (string|object) HTML string, DOM element, or Kimbo object to insert.
893   = (object) Original matched collection.
894   > Usage
895   | <div class="container">
896   |   <p class="lorem"> Lorem</p>
897   |   <p class="lorem"> Lorem</p>
898   | </div>
899   * Insert content
900   | $('.lorem').prepend('<em>ipsum</em>')
901   * Each element gets the content
902   | <div class="container">
903   |   <p class="lorem"><em>ipsum</em> Lorem</p>
904   |   <p class="lorem"><em>ipsum</em> Lorem</p>
905   | </div>
906   * You can also get an element and insert it elsewhere
907   | $('.container').prepend($('.ipsum'))
908   * The selected element will be moved, not cloned.
909   | <div class="container">
910   |   <p class="ipsum">Ipsum</p>
911   |   <p class="lorem">Lorem</p>
912   |   <p class="lorem">Lorem</p>
913   | </div>
914  \*/
915
916  // Generate append and prepend methods
917  Kimbo.forEach(['append', 'prepend'], function (method, i) {
918    var isPrepend = i > 0;
919
920    Kimbo.fn[method] = function (value) {
921      var div;
922
923      // Exit if no value passed
924      if (!this.length || !value) {
925        return this;
926      }
927
928      // Handle html string
929      if (Kimbo.isString(value)) {
930
931        // Placeholder element
932        div = document.createElement('div');
933        div.innerHTML = value;
934        value = div.firstChild;
935      }
936
937      // Already a dom node or kimbo collection, just insert it
938      if (value.nodeType || (value instanceof Kimbo)) {
939        return this.each(function (el) {
940
941          // Be sure we can append/prepend to the element
942          if (el.nodeType === 1 || el.nodeType === 11) {
943            _.kimbo(value).each(function (_el) {
944              el.insertBefore(_el, isPrepend ? el.firstChild : null);
945            });
946          }
947        });
948      }
949    };
950  });
951
952  Kimbo.fn.extend({
953    /*\
954     * $(…).empty
955     [ method ]
956     * Remove all child nodes from the DOM of the elements in the collection.
957     = (object) Original matched collection.
958     > Usage
959     | <div class="container">
960     |   <p class="lorem">Lorem</p>
961     |   <p class="lorem">Lorem</p>
962     | </div>
963     * Empty .container
964     | $('.container').empty();
965     * All elements inside ".container" are removed from the DOM
966     | <div class="container"></div>
967    \*/
968    empty: function () {
969      return this.each(function (el) {
970        while (el.hasChildNodes()) {
971          el.removeChild(el.childNodes[0]);
972        }
973      });
974    },
975
976    /*\
977     * $(…).remove
978     [ method ]
979     * Remove all matched elements from the DOM.
980     * Similar to @$(…).empty but .remove() removes the element itself
981     = (object) Original matched collection.
982     > Usage
983     | <div class="container">
984     |   <p class="lorem">Lorem</p>
985     |   <p>Lorem</p>
986     | </div>
987     * Remove one element
988     | $('.lorem').remove();
989     * The result element is:
990     | <div class="container">
991     |   <p>Lorem</p>
992     | </div>
993    \*/
994    remove: function () {
995      return this.each(function (el) {
996        if (el.parentNode) {
997          el.parentNode.removeChild(el);
998        }
999      });
1000    },
1001
1002    // Todo: extend to accept objects and functions to set values
1003    /*\
1004     * $(…).attr
1005     [ method ]
1006     * Get an attribute value from one element or set attributes to all matched elements.
1007     > Parameters
1008     - name (string) Name of the attribute.
1009     - value (string) #optional Value for the attribute.
1010     = (string) Attribute value, only if name was passed.
1011     = (object) Original matched collection when setting a value.
1012     > Usage
1013     | <a href="http://kimbojs.com">Go to Kimbojs.com</a>
1014     * Get href attribute
1015     | $('a').attr('href'); // Http://kimbojs.com
1016     * Set a new attribute
1017     | $('a').attr('title', 'Go to Kimbojs.com');
1018     * Now element has a title attribute
1019     | <a href="http://kimbojs.com" title="Go to Kimbojs.com">Go to Kimbojs.com</a>
1020    \*/
1021    attr: function (name, value) {
1022      if (!this.length) {
1023        return this;
1024      }
1025
1026      if (Kimbo.isString(name) && value === undefined) {
1027        return this[0].getAttribute(name);
1028      } else {
1029        return this.each(function (el) {
1030          el.setAttribute(name, value);
1031        });
1032      }
1033    },
1034
1035    /*\
1036     * $(…).removeAttr
1037     [ method ]
1038     * Removes an attribute from all matched elements.
1039     > Parameters
1040     - name (string) Name of the attribute to remove.
1041     = (object) Original matched collection.
1042     > Usage
1043     | <a href="http://kimbojs.com" title="Go to Kimbojs.com">Go to Kimbojs.com</a>
1044     * Remove the title attribute
1045     | $('a').removeAttr('title');
1046     * Now the element has no title
1047     | <a href="http://kimbojs.com">Go to Kimbojs.com</a>
1048    \*/
1049    removeAttr: function (name) {
1050      return this.each(function (el) {
1051        el.removeAttribute(name);
1052      });
1053    },
1054
1055    /*\
1056     * $(…).toggleClass
1057     [ method ]
1058     * Removes a class to all matched elements.
1059     > Parameters
1060     - name (string) Name of the class to toggle.
1061     - state (boolean) #optional If state is true the class will be added, if false, removed.
1062     = (object) Original matched collection.
1063     > Usage
1064     | <p class="foo">Lorem ipsum.</p>
1065     | <script>
1066     | $('p').toggleClass('foo');
1067     | </script>
1068     * The `p` element has the class foo soo it will be removed
1069     | <p>Lorem ipsum.</p>
1070    \*/
1071    toggleClass: function (name, state) {
1072      var classNames;
1073
1074      if (this.length && name && Kimbo.isString(name)) {
1075
1076        classNames = name.split(SPACE_RE);
1077
1078        this.each(function (el) {
1079          Kimbo.forEach(classNames, function (name) {
1080
1081            // Use custom toggle (anyway it uses classList.add/remove)
1082            state = Kimbo.isBoolean(state) ? state : !_hasClass(el, name);
1083            _.kimbo(el)[state ? 'addClass' : 'removeClass'](name);
1084          });
1085        });
1086      }
1087
1088      return this;
1089    },
1090
1091    /*\
1092     * $(…).hasClass
1093     [ method ]
1094     * Determine whether any matched elements has the given class.
1095     > Parameters
1096     - name (string) Name of the class to search for.
1097     = (object) Original matched collection.
1098     > Usage
1099     | <p class="asd foo qwe">Lorem ipsum.</p>
1100     * Check if the element has the class 'foo'
1101     | $('p').hasClass('foo'); // True
1102     * You could also check if it has multiple classes
1103     | $('p').hasClass('qwe asd'); // True
1104    \*/
1105    hasClass: function (name) {
1106      var has = false;
1107      var classNames;
1108
1109      if (this.length && name && Kimbo.isString(name)) {
1110
1111        classNames = name.trim().split(SPACE_RE);
1112
1113        this.each(function (el) {
1114
1115          // Classlist.contains only accepts one class parameter
1116          Kimbo.forEach(classNames, function (name) {
1117            has = _hasClass(el, name);
1118
1119            // When only one is missing break the loop
1120            if (!has) {
1121              return false;
1122            }
1123          });
1124        });
1125      }
1126
1127      return has;
1128    },
1129
1130    /*\
1131     * $(…).clone
1132     [ method ]
1133     * Clones a DOM node.
1134     > Parameters
1135     = (object) Original matched collection.
1136     > Usage
1137     | <p class="asd foo qwe">Lorem ipsum.</p>
1138     | var p1 = $('p'); // Grab the p element
1139     | var p2 = p1.clone(); // Clone p1 into p2
1140     | console.log(p2 === p1); // False
1141    \*/
1142    clone: function () {
1143      return this.each(function (el) {
1144        return el.cloneNode(true);
1145      });
1146    }
1147  });
1148
1149  // Generate get/set .width() and .height() methods
1150  /*\
1151   * $(…).width
1152   [ method ]
1153   * Get the current width of the first element or set the width of all matched elements.
1154   > Parameters
1155   - value (number|string) #optional An integer indicating the width of the element or a string width a unit of measure.
1156   = (number) the actual width of the element if no parameter passed.
1157   = (object) Kimbo object.
1158   > Usage
1159   | <style>
1160   |   div { width: 100px; }
1161   | </style>
1162   | <div>Actual width is 100px</div>
1163   * Get the width:
1164   | $('div').width(); // 100
1165   * Change the width:
1166   | $('div').width(200); // Now its width is 200
1167   * Or passing a specific unit:
1168   | $('div').width('50%'); // Now its width is 50%
1169  \*/
1170
1171  /*\
1172   * $(…).height
1173   [ method ]
1174   * Get the current height of the first element or set the height of all matched elements.
1175   > Parameters
1176   - value (number|string) #optional An integer indicating the height of the element or a string height a unit of measure.
1177   = (number) the actual height of the element if no parameter passed.
1178   = (object) Kimbo object.
1179   > Usage
1180   | <style>
1181   |   div { height: 100px; }
1182   | </style>
1183   | <div>Actual height is 100px</div>
1184   * Get the height:
1185   | $('div').height(); // 100
1186   * Change the height:
1187   | $('div').height(200); // Now its height is 200
1188   * Or passing a specific unit:
1189   | $('div').height('50%'); // Now its height is 50%
1190  \*/
1191  Kimbo.forEach(['width', 'height'], function (dimension) {
1192    Kimbo.fn[dimension] = function (value) {
1193      if (!value) {
1194        return parseInt(this.css(dimension), 10);
1195      }
1196
1197      return this.css(dimension, value);
1198    };
1199  });
1200});
1201
1202
1203Kimbo.define('traversing', function (_) {
1204
1205  'use strict';
1206
1207  var query = Kimbo.require('query');
1208
1209  var _filter = Array.prototype.filter;
1210
1211  var IS_UNIQUE = {
1212    children: true,
1213    contents: true,
1214    next: true,
1215    prev: true
1216  };
1217
1218  // Use native matchesSelector
1219  var _matchesSelector = _.document.documentElement.webkitMatchesSelector ||
1220    _.document.documentElement.mozMatchesSelector ||
1221    _.document.documentElement.oMatchesSelector ||
1222    _.document.documentElement.matchesSelector;
1223
1224  var _matches = function (elem, selector) {
1225    return (!elem || elem.nodeType !== 1) ? false : _matchesSelector.call(elem, selector);
1226  };
1227
1228  // Remove duplicates from an array
1229  var _unique = function (array) {
1230    return array.filter(function (item, index) {
1231      return array.indexOf(item) === index;
1232    });
1233  };
1234
1235  var _sibling = function (node, elem) {
1236    var result = [];
1237    for (; node; node = node.nextSibling) {
1238      if (node.nodeType === 1 && node !== elem ) {
1239        result.push(node);
1240      }
1241    }
1242    return result;
1243  };
1244
1245  var _singleSibling = function (node, prop) {
1246    do {
1247      node = node[prop];
1248    } while (node && node.nodeType !== 1);
1249
1250    return node;
1251  };
1252
1253  Kimbo.fn.extend({
1254    /*\
1255     * $(…).filter
1256     [ method ]
1257     * Filter element collection by the passed argument.
1258     > Parameters
1259     - selector (string|object|function) The argument by which the collection will be filtered.
1260     = (object) Filtered elements collection.
1261     > Usage
1262     | <ul>
1263     |   <li>One</li>
1264     |   <li>Two</li>
1265     |   <li>Three</li>
1266     |   <li>Four</li>
1267     | </ul>
1268     * Get even items.
1269     | $('li').filter(':nth-child(even)').addClass('even');
1270     * Only even items were affected.
1271     | <ul>
1272     |   <li>One</li>
1273     |   <li class="even">Two</li>
1274     |   <li>Three</li>
1275     |   <li class="even">Four</li>
1276     | </ul>
1277     > Using a function(index, element)
1278     * You can also filter the collection using a function, receiving the current index and element in the collection.
1279     | $('li').filter(function (index, element) {
1280     |   return index % 3 == 2;
1281     | }).addClass('red');
1282     * This will add a 'red' class to the third, sixth, ninth elements and so on...
1283     > Filter by DOM or Kimbo object
1284     * You can also filter by a DOM or Kimbo object.
1285     | $('li').filter(document.getElementById('id'));
1286     | // Or a Kimbo object
1287     | $('li').filter($('#id'));
1288    \*/
1289    filter: function (selector) {
1290      var result;
1291
1292      // Filter collection
1293      result = _filter.call(this, function (elem, i) {
1294        var ret;
1295
1296        if (Kimbo.isFunction(selector)) {
1297          ret = !!selector.call(elem, i, elem);
1298        } else if (Kimbo.isString(selector)) {
1299          ret = _matches(elem, selector);
1300        } else if (selector.nodeType) {
1301          ret = elem === selector;
1302        } else if (selector instanceof Kimbo) {
1303          ret = elem === selector[0];
1304        }
1305
1306        return ret;
1307      });
1308
1309      return _.kimbo(result);
1310    },
1311
1312    /*\
1313     * $(…).eq
1314     [ method ]
1315     * Reduce the matched elements collection to the one at the specified index.
1316     > Parameters
1317     - index (number) An integer indicating the position of the element. Use a negative number to go backwards in the collection.
1318     = (object) Kimbo object at specified index.
1319     > Usage
1320     | <ul>
1321     |   <li>Item 1</li>
1322     |   <li>Item 2</li>
1323     |   <li>Item 3</li>
1324     |   <li>Item 4</li>
1325     | </ul>
1326     * Get 3rd element, index always start at 0, so to get the 3rd we need to pass the number 2.
1327     | $('li').eq(2); // Item 3
1328    \*/
1329    eq: function (i) {
1330      return this.length && i === -1 ? this.slice(i) : this.slice(i, i + 1);
1331    },
1332
1333    /*\
1334     * $(…).first
1335     [ method ]
1336     * Reduce the matched elements collection to the first in the set.
1337     = (object) First Kimbo object of the collection
1338     > Usage
1339     | <ul>
1340     |   <li>Item 1</li>
1341     |   <li>Item 2</li>
1342     |   <li>Item 3</li>
1343     | </ul>
1344     * Get only the first element
1345     | $('li').first(); // Item 1
1346    \*/
1347    first: function () {
1348      return this.eq(0);
1349    },
1350
1351    /*\
1352     * $(…).last
1353     [ method ]
1354     * Reduce the matched elements collection to the last in the set.
1355     = (object) Last Kimbo object of the collection
1356     > Usage
1357     | <ul>
1358     |   <li>Item 1</li>
1359     |   <li>Item 2</li>
1360     |   <li>Item 3</li>
1361     | </ul>
1362     * Get only the last element
1363     | $('li').last(); // Item 3
1364    \*/
1365    last: function () {
1366      return this.eq(-1);
1367    },
1368
1369    /*\
1370     * $(…).slice
1371     [ method ]
1372     * Reduce the matched elements collection to a subset specified by a range of indices
1373     > Parameters
1374     - start (number) An integer indicating the position at which the elements begin to be selected. Use a negative number to go backwards in the collection.
1375     - end (number) #optional An integer indicating the position at which the elements stop being selected. Use a negative number to start at the end of the collection. If ommited, the range continues to the end.
1376     = (object) Reduced Kimbo object collection in the range specified
1377     > Usage
1378     | <ul>
1379     |   <li>Item 1</li>
1380     |   <li>Item 2</li>
1381     |   <li>Item 3</li>
1382     |   <li>Item 4</li>
1383     |   <li>Item 5</li>
1384     | </ul>
1385     * This will add the class selected to Item 3, 4 and 5, as the index starts at 0
1386     | $('li').slice(2).addClass('selected');
1387     * This will select only Items 3 and 4
1388     | $('li').slice(2, 4).addClass('selected');
1389     > Negative index
1390     * Here only Item 4 will be selected since is the only between -2 (Item 3) and -1 (Item 5)
1391     | $('li').slice(-2, -1).addClass('selected');
1392    \*/
1393    slice: function () {
1394      return this.length && _.kimbo(_.slice.apply(this, arguments));
1395    },
1396
1397    /*\
1398     * $(…).each
1399     [ method ]
1400     * Iterate over a Kimbo objct, executing a function for each element.
1401     > Parameters
1402     - callback (function) A function to call for each element in the collection.
1403     = (object) Kimbo object
1404     > Usage
1405     * Here we have an unordered list:
1406     | <ul>
1407     |   <li>Item 1</li>
1408     |   <li>Item 2</li>
1409     |   <li>Item 3</li>
1410     | </ul>
1411     * You can iterate over all the list items and execute a function
1412     | $('li').each(function (el, index, collection) {
1413     |   console.log('index of ' + $(this).text() + ' is: ' + index);
1414     | });
1415     * This will log the following message
1416     *
1417     * index of Item 1 is: 0
1418     *
1419     * index of Item 2 is: 1
1420     *
1421     * index of Item 3 is: 2
1422    \*/
1423    each: function (callback) {
1424      return Kimbo.forEach(this, callback);
1425    },
1426
1427    /*\
1428     * $(…).map
1429     [ method ]
1430     * Execute a function for each element in the collection, producing a new Kimbo set with the returned values
1431     > Parameters
1432     - callback (function) A function to call for each element in the collection.
1433     = (object) Kimbo object
1434     > Usage
1435     * Here we have an unordered list:
1436     | <ul>
1437     |   <li id="item1">Item 1</li>
1438     |   <li id="item2">Item 2</li>
1439     |   <li id="item3">Item 3</li>
1440     | </ul>
1441     * You can call a function for each element to create a new Kimbo object
1442     | $('li').map(function (el, index) {
1443     |   return this.id;
1444     | }).get().join();
1445     * This will produce a list of the item ids.
1446     | "item1,item2,item3"
1447    \*/
1448    map: function (callback) {
1449      return _.kimbo(Kimbo.map(this, function (elem, i) {
1450        return callback.call(elem, elem, i);
1451      }));
1452    },
1453
1454    /*\
1455     * $(…).find
1456     [ method ]
1457     * Find descendant elements for each element in the current collection.
1458     > Parameters
1459     - selector (string) A string selector to match elements.
1460     = (object) Kimbo object
1461     > Usage
1462     * Here we have some HTML
1463     | <div id="container">
1464     |   <p>Demo</p>
1465     |   <div class="article">
1466     |     <p>This is an article</p>
1467     |     <p>with some paragraphs</p>
1468     |   </div>
1469     | </div>
1470     * You can find all paragraph elements inside the article:
1471     | $('.article').find('p');
1472    \*/
1473    find: function (selector) {
1474      var i, l, length, n, r, result, elems;
1475
1476      // Make new empty kimbo collection
1477      result = _.kimbo();
1478
1479      // Could use Kimbo.forEach, but this is a bit faster..
1480      for (i = 0, l = this.length; i < l; i++) {
1481        length = result.length;
1482
1483        // Get elements
1484        elems = query.find(this[i], selector);
1485
1486        // Push them to current kimbo collection
1487        _.push.apply(result, elems);
1488
1489        if (i) {
1490
1491          // Make results unique
1492          for (n = length; n < result.length; n++) {
1493            for (r = 0; r < length; r++) {
1494              if (result[r] === result[n]) {
1495                result.splice(n--, 1);
1496                break;
1497              }
1498            }
1499          }
1500        }
1501      }
1502
1503      return result;
1504    },
1505
1506    /*\
1507     * $(…).closest
1508     [ method ]
1509     * Get a Kimbo collection that matches the closest selector
1510     > Parameters
1511     - selector (string) A string selector to match elements.
1512     - context (string) #optional A DOM element within which matching elements may be found.
1513     = (object) Kimbo object
1514     > Usage
1515     * Here we have a nested unordered lists:
1516     | <ul>
1517     |   <li>
1518     |     Item 1
1519     |     <ul class="ul-level-2">
1520     |       <li class="item-1-1">Item 1.1</li>
1521     |       <li class="item-1-2">Item 1.2</li>
1522     |     </ul>
1523     |   </li>
1524     |   <li>Item 2</li>
1525     | </ul>
1526     * You can find the containing ul of the items in the nested ul:
1527     | $('.item-1-1').closest('ul');
1528     * This will return `ul.level-2` element
1529    \*/
1530    closest: function (selector, context) {
1531      var l = this.length;
1532      var result = [];
1533      var closest = function (node) {
1534
1535        // Check selector match and grab the element
1536        while (node && !_matches(node, selector)) {
1537          node = node !== context && node !== _.document && node.parentNode;
1538        }
1539        return node;
1540      };
1541
1542      if (!l) {
1543        return this;
1544
1545      // Get closest only for one element
1546      } else if (l === 1) {
1547        result = closest(this[0]);
1548
1549      // Get closest from all elements in the set
1550      } else {
1551        Kimbo.forEach(this, function (node) {
1552          node = closest(node);
1553          if (node) {
1554            result.push(node);
1555          }
1556        });
1557
1558        // Only unique results
1559        result = result.length > 1 ? _unique(result) : result;
1560      }
1561
1562      return _.kimbo(result);
1563    },
1564
1565    /*\
1566     * $(…).contains
1567     [ method ]
1568     * Determine whether an element is contained by the current matched element.
1569     > Parameters
1570     - element (string|object) Selector of the element or the actual DOM or Kimbo object.
1571     = (boolean) true if it is contained, false if not.
1572     > Usage
1573     | <div id="container">
1574     |   <p id="inside">Inside paragraph</p>
1575     | </div>
1576     | <p id="outside">Outside paragraph</p>
1577     * The paragraph with id "inside" is actually contained by "#container"
1578     | $('#container').contains('#inside'); // True
1579     * The paragraph ourside is not contained
1580     | var outside_p = $('#outside');
1581     | $('#container').contains(outside_p); // False
1582    \*/
1583    contains: function (element) {
1584      element = (element instanceof Kimbo) ? element[0] :
1585        (Kimbo.isString(element) ? this.find(element)[0] : element);
1586
1587      return query.contains(this[0], element);
1588    },
1589
1590    /*\
1591     * $(…).add
1592     [ method ]
1593     * Add elements to the current Kimbo collection.
1594     > Parameters
1595     - selector (string|object) Selector of the element or the actual DOM or Kimbo object.
1596     - context (string|object) #optional Selector of the context element or the actual DOM or Kimbo object.
1597     = (object) The merged Kimbo collection.
1598     > Usage
1599     | <ul id="menu1">
1600     |   <li>Apple</li>
1601     |   <li>Orange</li>
1602     | </ul>
1603     |
1604     | <ul id="menu2">
1605     |   <li>Lemon</li>
1606     |   <li>Banana</li>
1607     | </ul>
1608     * Get the items from the #menu1 and add the ones from #menu2, all the following ways will produce the same collection
1609     | $('#menu1 li').add('#menu2 li');
1610     * or
1611     | $('#menu1 li').add('li', '#menu2');
1612     * or
1613     | $('#menu1 li').add($('#menu2 li'));
1614    \*/
1615    add: function (selector, context) {
1616      var set = Kimbo.isString(selector) ? _.kimbo(selector, context) :
1617        Kimbo.makeArray(selector && selector.nodeType ? [selector] : selector);
1618
1619      var all = Kimbo.merge(this, set);
1620
1621      return _.kimbo(all);
1622    },
1623
1624    /*\
1625     * $(…).is
1626     [ method ]
1627     * Check the current elements collection against a selector, object or function.
1628     - selector (string|object|function) The argument by which the collection will be matched against.
1629     = (boolean)
1630     > Usage
1631     | <ul>
1632     |   <li>Click the <em>Apple</em></li>
1633     |   <li><span>Click the Orange</span></li>
1634     |   <li>Or the Banana</li>
1635     | </ul>
1636     * Test if the current clicked element is an `<li>` element.
1637     | $('ul').click(function (event) {
1638     |   var $target = $(event.target);
1639     |   if ($target.is('li')) {
1640     |     $target.css('background-color', 'red');
1641     |   }
1642     | });
1643    \*/
1644    is: function (selector) {
1645      return !!(this.length && this.filter(selector).length);
1646    }
1647  });
1648
1649  Kimbo.forEach({
1650    /*\
1651     * $(…).parent
1652     [ method ]
1653     * Get the parent of each element matched in the current collection.
1654     * If a selector is specified, it will return the parent element only if it matches that selector.
1655     - selector (string) #optional A string containing a selector expression to match elements against
1656     = (object) Kimbo object
1657     > Usage
1658     * Suppose a page with this HTML:
1659     | <ul>
1660     |   <li class="item-a">Item 1</li>
1661     |   <li class="item-b">Item 2</li>
1662     | </ul>
1663     * Get the parent element of `.item-a`
1664     | $('.item-a').parent(); // Ul
1665    \*/
1666    parent: function (elem) {
1667      var parent = elem.parentNode;
1668
1669      return parent && parent.nodeType !== 11 ? parent : null;
1670    },
1671
1672    /*\
1673     * $(…).next
1674     [ method ]
1675     * Get the immedeately following sibling of each element in the current collection.
1676     * If a selector is specified, it will return the element only if it matches that selector.
1677     - selector (string) #optional A string containing a selector expression to match elements against
1678     = (object) Kimbo object
1679     > Usage
1680     * Suppose a page with this HTML:
1681     | <ul>
1682     |   <li class="item-a">Item 1</li>
1683     |   <li class="item-b">Item 2</li>
1684     | </ul>
1685     * Get the parent element of `.item-a`
1686     | $('.item-a').next(); // .item-b
1687    \*/
1688    next: function (elem) {
1689      return _singleSibling(elem, 'nextSibling');
1690    },
1691
1692    /*\
1693     * $(…).prev
1694     [ method ]
1695     * Get the immedeately previous sibling of each element in the current collection.
1696     * If a selector is specified, it will return the element only if it matches that selector.
1697     - selector (string) #optional A string containing a selector expression to match elements against
1698     = (object) Kimbo object
1699     > Usage
1700     * Suppose a page with this HTML:
1701     | <ul>
1702     |   <li class="item-a">Item 1</li>
1703     |   <li class="item-b">Item 2</li>
1704     | </ul>
1705     * Get the parent element of `.item-a`
1706     | $('.item-b').prev(); // .item-a
1707    \*/
1708    prev: function (elem) {
1709      return _singleSibling(elem, 'previousSibling');
1710    },
1711
1712    /*\
1713     * $(…).sibling
1714     [ method ]
1715     * Get the immedeately previous sibling of each element in the current collection.
1716     * If a selector is specified, it will return the element only if it matches that selector.
1717     - selector (string) #optional A string containing a selector expression to match elements against
1718     = (object) Kimbo object
1719     > Usage
1720     * Suppose a page with this HTML:
1721     | <ul>
1722     |   <li class="item-a">Item 1</li>
1723     |   <li class="item-b">Item 2</li>
1724     | </ul>
1725     * Get the parent element of `.item-a`
1726     | $('.item-b').prev(); // .item-a
1727    \*/
1728    siblings: function (elem) {
1729      return _sibling((elem.parentNode || {}).firstChild, elem);
1730    },
1731
1732    /*\
1733     * $(…).children
1734     [ method ]
1735     * Get the children of all matched elements, optionally filtered by a selector.
1736     - selector (string) #optional A string selector to match elements against.
1737     = (object) Kimbo object
1738     > Usage
1739     * Suppose a page with the following HTML:
1740     | <div class="demo">
1741     |   <p>This</p>
1742     |   <p>is</p>
1743     |   <p>a</p>
1744     |   <p>demo.</p>
1745     | </div>
1746     * Get all children of `.demo`:
1747     | $('.demo').children(); // Al <p> tags inside .demo div
1748     * Another example passing an specific selector:
1749     | <form>
1750     |   <input type="text" name="name" />
1751     |   <input type="text" name="last" />
1752     |   <input type="submit" value="Send" />
1753     | </form>
1754     * Get only the children that are text type elements:
1755     | $('form').children('input[type="text"]'); // Only name and last inputs
1756    \*/
1757    children: function (elem) {
1758      return _sibling(elem.firstChild);
1759    },
1760
1761    /*\
1762     * $(…).contents
1763     [ method ]
1764     * Get the HTML content of an iframe
1765     = (object) Kimbo object
1766     > Usage
1767     * Suppose an iframe loading an external page:
1768     | <iframe src="http://api.kimbojs.com"></iframe>
1769     * Find the body element of the contents of that iframe:
1770     | $('iframe').contents().find('body');
1771    \*/
1772    contents: function (elem) {
1773      return elem.nodeName.toLowerCase() === 'iframe' ? elem.contentDocument || elem.contentWindow[_.document] : Kimbo.makeArray(elem.childNodes);
1774    }
1775  }, function (name, fn) {
1776    Kimbo.fn[name] = function (selector) {
1777      var ret;
1778
1779      if (!this.length) {
1780        return this;
1781      }
1782
1783      ret = Kimbo.map(this, fn);
1784
1785      // Clean collection
1786      ret = this.length > 1 && !IS_UNIQUE[name] ? _unique(ret) : ret;
1787
1788      if (Kimbo.isString(selector)) {
1789        ret = _.kimbo(ret).filter(selector);
1790      }
1791
1792      return _.kimbo(ret);
1793    };
1794  });
1795});
1796
1797
1798Kimbo.define('utilities', function (_) {
1799
1800  'use strict';
1801
1802  // Mobile userAgent escaped regexes
1803  var ANDROID_RE = '(Android)\\s+([\\d.]+)';
1804  var BLACKBERRY_RE = '(BlackBerry|BB10|Playbook).*Version\/([\\d.]+)';
1805  var FIREFOXOS_RE = '(Mozilla).*Mobile[^\/]*\/([\\d.]*)';
1806  var IPAD_RE = '(iPad).*OS\\s([\\d_]+)';
1807  var IPHONE_RE = '(iPhone\\sOS)\\s([\\d_]+)';
1808  var WEBOS = '(web|hpw)OS[\\s\/]([\\d.]+)';
1809
1810  // Full regexp to test the userAgent
1811  var MOBILE_OS_RE = new RegExp(
1812    ANDROID_RE + '|' +
1813    BLACKBERRY_RE + '|' +
1814    FIREFOXOS_RE + '|' +
1815    IPHONE_RE + '|' +
1816    IPAD_RE + '|' +
1817    WEBOS
1818  );
1819
1820  var isMobile = null;
1821
1822  var objectTypes = {};
1823
1824  // Map object types
1825  Kimbo.forEach([ 'Array', 'Boolean', 'Date', 'Error', 'Function',
1826    'Number', 'Object', 'RegExp', 'String'
1827  ], function (type) {
1828      objectTypes['[object ' + type + ']'] = type.toLowerCase();
1829    }
1830  );
1831
1832  Kimbo.extend({
1833    /*\
1834     * $.typeOf
1835     [ method ]
1836     * Determine the internal JavaScript [[Class]] of an object.
1837     > Parameters
1838     - obj (object) Object to get its [[Class]] type.
1839     = (string) Type of the object.
1840     > Usage
1841     | $.typeOf('i am a string'); // 'string'
1842     | $.typeOf(/(\.regexp?)/); // 'regexp'
1843     | $.typeOf(null); // 'null'
1844     | $.typeOf(undefined); // 'undefined'
1845     | $.typeOf(window.notDefined); // 'undefined'
1846     | $.typeOf(function () {}); // 'function'
1847     | $.typeOf({key: 'value'}); // 'object'
1848     | $.typeOf(true); // 'boolean'
1849     | $.typeOf([]); // 'array'
1850     | $.typeOf(new Date()); // 'date'
1851     | $.typeOf(3); // 'number'
1852    \*/
1853    typeOf: function (obj) {
1854      var type;
1855
1856      if (obj === null || obj === undefined) {
1857        type = String(obj);
1858
1859      } else {
1860        type = (objectTypes[Object.prototype.toString.call(obj)] || 'object');
1861      }
1862
1863      return type;
1864    },
1865
1866    /*\
1867     * $.isArray
1868     [ method ]
1869     * Determine if the parameter passed is an array object.
1870     > Parameters
1871     - obj (object) Object to test if its an array.
1872     = (boolean) According wether or not it is an array object.
1873     > Usage
1874     | $.isArray([]); // True
1875     | $.isArray({}); // False
1876     | $.isArray('test'); // False
1877    \*/
1878    isArray: Array.isArray,
1879
1880    /*\
1881     * $.isNumeric
1882     [ method ]
1883     * Determine if the parameter passed is an number.
1884     > Parameters
1885     - obj (object) Object to test if its a number.
1886     = (boolean) According wether or not it is a number.
1887     > Usage
1888     | $.isNumeric(3); // True
1889     | $.isNumeric('3'); // False
1890    \*/
1891    isNumeric: function (obj) {
1892      return !isNaN(parseFloat(obj)) && isFinite(obj);
1893    },
1894
1895    /*\
1896     * $.isWindow
1897     [ method ]
1898     * Determine if the parameter passed is the window object.
1899     > Parameters
1900     - obj (object) Object to test if its the window object.
1901     = (boolean) According wether or not it is the window object.
1902     > Usage
1903     | $.isWindow(window); // True
1904     | $.isWindow({ window: window }); // False
1905    \*/
1906    isWindow: function (obj) {
1907      return obj && obj === obj.window;
1908    },
1909
1910    /*\
1911     * $.isEmptyObject
1912     [ method ]
1913     * Determine if the parameter passed is an empty object.
1914     > Parameters
1915     - obj (object) Object to test if its an empty object.
1916     = (boolean) According wether or not it is an empty object.
1917     > Usage
1918     | $.isEmptyObject({}); // True
1919     | $.isEmptyObject([]); // True
1920     | $.isEmptyObject([1, 2]); // False
1921    \*/
1922    isEmptyObject: function (obj) {
1923      var key;
1924
1925      for (key in obj) {
1926        if (obj.hasOwnProperty(key)) {
1927          return false;
1928        }
1929      }
1930
1931      return true;
1932    },
1933
1934    /*\
1935     * $.isMobile
1936     [ method ]
1937     * Determine if the current platform is a mobile device, (otherwise is a desktop browser).
1938     > Parameters
1939     = (boolean) According wether or not is a mobile device.
1940     > Usage
1941     | $.isMobile(); // False
1942    \*/
1943    isMobile: function () {
1944
1945      // Check only once for the current browser
1946      if (isMobile === null) {
1947        isMobile = MOBILE_OS_RE.test(navigator.userAgent);
1948      }
1949
1950      return isMobile;
1951    },
1952
1953    /*\
1954     * $.parseJSON
1955     [ method ]
1956     * Parses a well-formed JSON string and returns the resulting JavaScript object.
1957     > Parameters
1958     - data (string) The JSON string to parse.
1959     = (object) A JavaScript object.
1960     > Usage
1961     | var obj = $.parseJSON('{"name":"Denis"}');
1962     | console.log(obj.name === 'Denis'); // True
1963    \*/
1964    parseJSON: function (data) {
1965
1966      // Use native JSON parser
1967      if (data && Kimbo.isString(data)) {
1968        return window.JSON.parse(data);
1969      }
1970    },
1971
1972    /*\
1973     * $.parseXML
1974     [ method ]
1975     * Parses a string into an XML document.
1976     > Parameters
1977     - data (string) The JSON string to parse.
1978     = (object) A JavaScript object.
1979     > Usage
1980     | var xml = "<rss version='2.0'><channel><title>RSS Title</title></channel></rss>"
1981     | var xmlDoc = $.parseXML(xml);
1982     | $(xmlDoc).find('title'); // 'RSS Title'
1983    \*/
1984    parseXML: function (data) {
1985
1986      // Use native XML (DOM) parser
1987      var domparser;
1988      var xml;
1989
1990      if (data && Kimbo.isString(data)) {
1991        domparser = new window.DOMParser();
1992        xml = domparser.parseFromString(data, 'text/xml');
1993
1994        if (xml.getElementsByTagName('parsererror').length) {
1995          throw new Error('Invalid XML: ' + data);
1996        }
1997
1998        return xml;
1999      }
2000    },
2001
2002    /*\
2003     * $.map
2004     [ method ]
2005     * Translate all items in an array or object to new array of items.
2006     > Parameters
2007     - obj (array|object) The Array or Object to translate.
2008     = (array) A new array.
2009     > Usage
2010     | var arr = ['a', 'b', 'c'];
2011     | arr = $.map(arr, function (element, index) {
2012     |   return element.toUpperCase() + index;
2013     | });
2014     | console.log(arr); // ['A0', 'B1', 'C2']
2015     * Or wit an object
2016     | var obj = {a: 'a', b: 'b', c: 'c'};
2017     | obj = $.map(arr, function (key, value) {
2018     |   return key + ': ' + value.toUpperCase();
2019     | });
2020     | console.log(obj); // ['a: A', 'b: B', 'c: C']
2021    \*/
2022    map: function (obj, callback) {
2023      var values = [];
2024
2025      if (obj) {
2026        Kimbo.forEach(obj, function (key, val) {
2027          var value = callback(key, val);
2028
2029          if (value !== null && value !== undefined) {
2030            values.push(value);
2031          }
2032        });
2033      }
2034
2035      // Flatten any nested arrays
2036      return values.concat.apply([], values);
2037    },
2038
2039    /*\
2040     * $.makeArray
2041     [ method ]
2042     * Create an Array from the given object
2043     > Parameters
2044     - obj (array|object) The Array or Object to make an array from.
2045     = (array) A new array.
2046     > Usage
2047     | var lis = $('li'); // Kimbo object
2048     | var arr = $.makeArray(lis);
2049     |
2050     | console.log($.isArray(lis)); // False
2051     | console.log($.isArray(arr)); // True
2052    \*/
2053    makeArray: function (obj, results) {
2054      results = results || [];
2055
2056      if (obj) {
2057        if (Kimbo.isArray(obj) || (obj instanceof Kimbo) || obj instanceof window.NodeList) {
2058          results = Kimbo.merge(results, obj);
2059        } else {
2060          _.push.call(results, obj);
2061        }
2062      }
2063
2064      return results;
2065    },
2066
2067    /*\
2068     * $.merge
2069     [ method ]
2070     * Merge the contents of two arrays into the first array passed.
2071     > Parameters
2072     - first (array) The first array to merge the contents of the second.
2073     - second (array|string) The second array to merge into the first.
2074     = (array) The first array merged with the second.
2075     > Usage
2076     | $.merge(['a', 'b'], ['c', 'd']);
2077     * Result:
2078     | ['a', 'b', 'c', 'd']
2079    \*/
2080    merge: function (first, second) {
2081
2082      // Concat is very fast, use it if we can
2083      if (Kimbo.isArray(first)) {
2084        first = first.concat(second);
2085
2086      // Kimbo object, do a consecutive push
2087      } else {
2088        _.push.apply(first, _.slice.call(second));
2089      }
2090
2091      return first;
2092    },
2093
2094    /*\
2095     * $.camelCase
2096     [ method ]
2097     * Camelize any dashed separated string
2098     > Parameters
2099     - str (string) A dashed separated string value to transform into camelCase.
2100     = (string) camelCase string
2101     > Usage
2102     | $.camelCase('background-color');
2103     * Result:
2104     | 'backgroundColor'
2105    \*/
2106    camelCase: function (str) {
2107      return str.replace(/-+(.)?/g, function (wholeMatch, character) {
2108        return character.toUpperCase();
2109      });
2110    },
2111
2112    /*\
2113     * $.isFunction
2114     [ method ]
2115     * Determine if the parameter passed is a Javascript function object.
2116     > Parameters
2117     - obj (object) Object to test if its a function.
2118     = (boolean) According wether or not it is a function.
2119     > Usage
2120     | var myFunction = function () {};
2121     | $.isFunction(myFunction); // True
2122     | var something = ['lala', 'jojo'];
2123     | $.isFunction(something); // False
2124    \*/
2125    isFunction: function (obj) {
2126      return Kimbo.typeOf(obj) === 'function';
2127    },
2128
2129    /*\
2130     * $.isObject
2131     [ method ]
2132     * Determine if the parameter passed is a Javascript plain object.
2133     > Parameters
2134     - obj (object) Object to test if its a plain object.
2135     = (boolean) According wether or not it is a plain object.
2136     > Usage
2137     | $.isObject({}); // True
2138     | $.isObject([]); // False
2139     | $.isObject('test'); // False
2140    \*/
2141    isObject: function (obj) {
2142      return Kimbo.typeOf(obj) === 'object';
2143    },
2144
2145    /*\
2146     * $.isString
2147     [ method ]
2148     * Determine if the parameter passed is a string.
2149     > Parameters
2150     - obj (object) Object to test if its a string.
2151     = (boolean) According wether or not it is a string.
2152     > Usage
2153     | $.isString('test'); // True
2154     | $.isString({ name: 'asd' }); // False
2155    \*/
2156    isString: function (obj) {
2157      return Kimbo.typeOf(obj) === 'string';
2158    },
2159
2160    /*\
2161     * $.isBoolean
2162     [ method ]
2163     * Determine if the parameter passed is boolean.
2164     > Parameters
2165     - obj (object) Object to test if its boolean..
2166     = (boolean) According wether or not it is boolean.
2167     > Usage
2168     | $.isBoolean(false); // True
2169     | $.isBoolean(3); // False
2170    \*/
2171    isBoolean: function (obj) {
2172      return Kimbo.typeOf(obj) === 'boolean';
2173    }
2174  });
2175
2176  // Save reference to Kimbo wrapped document as the default context
2177  _.rootContext = _.kimbo(_.rootContext);
2178});
2179
2180
2181Kimbo.define('events', function (_) {
2182
2183  'use strict';
2184
2185  var query = Kimbo.require('query');
2186
2187  var _guid = 1;
2188
2189  var MOUSE_EVENT_RE = /^(?:mouse|menu)|click/;
2190
2191  var KEY_EVENT_RE = /^key/;
2192
2193  var DEFAULT_EVENT_PROPS = [
2194    'altKey', 'bubbles', 'cancelable', 'ctrlKey', 'currentTarget', 'defaultPrevented', 'eventPhase',
2195    'metaKey', 'relatedTarget', 'shiftKey', 'target', 'timeStamp', 'type', 'view', 'which'
2196  ];
2197
2198  var MOUSE_EVENT_PROPS = [
2199    'button', 'buttons', 'clientX', 'clientY', 'fromElement',
2200    'offsetX', 'offsetY', 'screenX', 'screenY', 'toElement'
2201  ];
2202
2203  var KEY_EVENT_PROPS = ['char', 'charCode', 'key', 'keyCode'];
2204
2205  // Gestures fallback for not mobile environment
2206  var GESTURES_FALLBACK = Kimbo.isMobile() ? {} : {
2207    touchstart: 'mousedown',
2208    touchmove: 'mousemove',
2209    touchend: 'mouseup',
2210    touch: 'click',
2211    doubletap: 'dblclick',
2212    orientationchange: 'resize'
2213  };
2214
2215  var handlersHash = {};
2216  var fixEventProps = {};
2217  var specialEvents = {};
2218
2219  var _fixEvent = function (event) {
2220    var originalEvent, eventProps, props;
2221
2222    // Already fixed
2223    if (event[Kimbo.ref]) {
2224      return event;
2225    }
2226
2227    // Get event properties
2228    originalEvent = event;
2229    eventProps = fixEventProps[event.type] || [];
2230    props = DEFAULT_EVENT_PROPS.concat(eventProps);
2231
2232    // Create a new event writable custom event object
2233    event = new Kimbo.Event(originalEvent);
2234
2235    // Set event props to Kimbo.Event object
2236    Kimbo.forEach(props, function (prop) {
2237      event[prop] = originalEvent[prop];
2238    });
2239
2240    return event;
2241  };
2242
2243  // Return element id
2244  var _getElementId = function (element) {
2245    return element._guid || (element._guid = _guid++);
2246  };
2247
2248  // Get element handlers for the specified type
2249  var _getHandlers = function (elementId, type) {
2250    var events = ((handlersHash[elementId] || {}).events || {});
2251
2252    return (type ? events[type] : events) || [];
2253  };
2254
2255  // Quick is() to check if event target matches when events are delegated
2256  var _is = function (target, selector, element) {
2257    return (target.nodeName.toLowerCase() === selector && _.kimbo(target).closest(selector, element)[0]);
2258  };
2259
2260  var _returnFalse = function () {
2261    return false;
2262  };
2263
2264  var _returnTrue = function () {
2265    return true;
2266  };
2267
2268  // Register events to dom elements
2269  var _addEvent = function (element, type, callback, data, selector) {
2270
2271    // TODO: element should use Kimbo.ref and the handler the _guid
2272    var elementId = _getElementId(element);
2273    var elementHandlers = handlersHash[elementId];
2274    var origType = type;
2275    var events, handlers, handleObj, handler;
2276
2277    // Could be a special type like mouseenter/mouseleave
2278    type = specialEvents[type] ? specialEvents[type].origType : type;
2279
2280    // Create hash for this element if first init
2281    if (!elementHandlers) {
2282      handlersHash[elementId] = elementHandlers = {};
2283    }
2284
2285    // Create events object if first init
2286    events = elementHandlers.events;
2287    if (!events) {
2288      elementHandlers.events = events = {};
2289    }
2290
2291    // Create the handler for this element if first init
2292    handler = elementHandlers.handler;
2293    if (!handler) {
2294      elementHandlers.handler = handler = function () {
2295        return _dispatchEvent.apply(element, arguments);
2296      };
2297    }
2298
2299    // Create handler object
2300    handleObj = {
2301      type: type,
2302      origType: origType,
2303      data: data,
2304      callback: callback,
2305      selector: selector
2306    };
2307
2308    // Only add an event listener one time for each type of event
2309    handlers = events[type];
2310    if (!handlers) {
2311
2312      // Array of events for the current type
2313      handlers = events[type] = [];
2314      handlers.delegateCount = 0;
2315
2316      // Add event
2317      if (element.addEventListener) {
2318        element.addEventListener(type, handler, false);
2319      }
2320    }
2321
2322    // Add to handlers hash, delegates first
2323    if (selector) {
2324      handlers.splice(handlers.delegateCount++, 0, handleObj);
2325
2326    } else {
2327      handlers.push(handleObj);
2328    }
2329  };
2330
2331  // Unregister events from dom elements
2332  var _removeEvent = function (element, type, callback, selector) {
2333    var elementId = _getElementId(element);
2334    var handleObj, handlers, name, i;
2335
2336    if (!elementId) {
2337      return;
2338    }
2339
2340    handlers = _getHandlers(elementId, type);
2341
2342    // Return if no handlers for the current event type
2343    if (type && !handlers.length) {
2344      return;
2345    }
2346
2347    // Remove all handlers if no type provided
2348    if (!type) {
2349      for (name in handlers) {
2350        if (handlers.hasOwnProperty(name)) {
2351          _removeEvent(element, name, callback, selector);
2352        }
2353      }
2354    }
2355
2356    // Remove handlers that match
2357    for (i = 0; i < handlers.length; i++) {
2358      handleObj = handlers[i];
2359      if ((!callback || callback === handleObj.callback) && (!selector || selector === handleObj.selector)) {
2360
2361        // Remove current handler from stack
2362        handlers.splice(i--, 1);
2363
2364        // Decrement delegate count
2365        if (handleObj.selector) {
2366          handlers.delegateCount--;
2367        }
2368      }
2369    }
2370
2371    // If no more events for the current type delete its hash
2372    if (!handlers.length) {
2373
2374      // Remove event handler
2375      element.removeEventListener(type, handlersHash[elementId].handler, false);
2376      delete handlersHash[elementId].events[type];
2377    }
2378
2379    // Remove kimbo reference if element have no more events
2380    // If (Kimbo.isEmptyObject(handlersHash[elementId].events)) {
2381    //   delete handlersHash[elementId];
2382    //   delete element._guid;
2383    // }
2384  };
2385
2386  // Triggers a provided event type
2387  var _triggerEvent = function (element, type, data) {
2388
2389    /* jshint validthis: true */
2390    var currentElement, lastElement, eventTree, elementId, event;
2391
2392    // Don't do events if element is text or comment node
2393    // Or if there is no event type at all or type is not a string
2394    if ((element && (element.nodeType === 3 || element.nodeType === 8)) || !type || !Kimbo.isString(type)) {
2395      return this;
2396    }
2397
2398    // Try triggering native focus and blur events
2399    if (type === 'focus' || type === 'blur') {
2400      try {
2401        return element[type]();
2402      } catch (e) {}
2403    }
2404
2405    // Create a new writable custom event object
2406    event = new Kimbo.Event(type);
2407
2408    // Triggered programatically
2409    event.isTrigger = true;
2410
2411    // Set the target
2412    if (!event.target) {
2413      event.target = element;
2414    }
2415
2416    // Include data if any
2417    data = data ? Kimbo.makeArray(data) : [];
2418    // Event goes first
2419    data.unshift(event);
2420
2421    // Generate a stack of [element, event] to be triggered
2422    eventTree = [[element, type]];
2423    if (!Kimbo.isWindow(element)) {
2424
2425      // Get all parent elements to bubble event later
2426      for (currentElement = element.parentNode; currentElement; currentElement = currentElement.parentNode) {
2427        eventTree.push([currentElement, type]);
2428        lastElement = currentElement;
2429      }
2430
2431      // Only add window object if we got to document (e.g., not plain obj or detached DOM)
2432      if (lastElement && lastElement === element.ownerDocument) {
2433        eventTree.push([window, type]);
2434      }
2435    }
2436
2437    // Fire handlers up to the document (or the last element)
2438    Kimbo.forEach(eventTree, function (branch) {
2439
2440      // Element
2441      currentElement = branch[0];
2442
2443      // Type
2444      event.type = branch[1];
2445
2446      // Get element id
2447      elementId = currentElement._guid;
2448
2449      // If the current element has events of the specified type, dispatch them
2450      if (elementId && _getHandlers(elementId, type)) {
2451        handlersHash[elementId].handler.apply(currentElement, data);
2452      }
2453    });
2454  };
2455
2456  // Own defined dispatchEvent()
2457  var _dispatchEvent = function (event) {
2458    /* jshint -W040 */
2459
2460    // Use own event object
2461    event = _fixEvent(event);
2462
2463    var elementId = _getElementId(this);
2464    var handlers = _getHandlers(elementId, event.type);
2465    var delegateCount = handlers.delegateCount;
2466    var args = _.slice.call(arguments);
2467    var handlerQueue = [];
2468    var currentElement, ret, selMatch, matches, handleObj, selector, i;
2469
2470    // Set the native event to be the fixed event
2471    args[0] = event;
2472
2473    // Save the delegate target element
2474    event.delegateTarget = this;
2475
2476    // Get delegated handlers if any
2477    if (delegateCount) {
2478
2479      // Go up to the dom finding the elements that matches the current selector from delegated event
2480      for (currentElement = event.target; currentElement !== this; currentElement = currentElement.parentNode || this) {
2481
2482        // Don't do events on disabled elements
2483        if (currentElement.disabled !== true || event.type !== 'click') {
2484          selMatch = {};
2485          matches = [];
2486
2487          // Loop throgh delegated events
2488          for (i = 0; i < delegateCount; i++) {
2489
2490            // Get its handler
2491            handleObj = handlers[i];
2492
2493            // Get its selector
2494            selector = handleObj.selector;
2495
2496            if (!selMatch[selector]) {
2497              selMatch[selector] = _is(currentElement, selector, this);
2498            }
2499
2500            if (selMatch[selector]) {
2501              matches.push(handleObj);
2502            }
2503          }
2504
2505          if (matches.length) {
2506            handlerQueue.push({elem: currentElement, matches: matches});
2507          }
2508        }
2509      }
2510    }
2511
2512    // Add the remaining not delegated handlers
2513    if (handlers.length > delegateCount) {
2514      handlerQueue.push({elem: this, matches: handlers.slice(delegateCount)});
2515    }
2516
2517    // Fire callbacks queue
2518    Kimbo.forEach(handlerQueue, function (handler) {
2519
2520      // Only fire handler if event wasnt stopped
2521      if (!event.isPropagationStopped()) {
2522        event.currentTarget = handler.elem;
2523
2524        Kimbo.forEach(handler.matches, function (handleObj) {
2525
2526          // Only fire bubble if not stopped
2527          if (!event.isImmediatePropagationStopped()) {
2528            event.data = handleObj.data;
2529            event.handleObj = handleObj;
2530
2531            // Call original callback, check if its an special event first
2532            ret = ((specialEvents[handleObj.origType] || {}).handle || handleObj.callback).apply(handler.elem, args);
2533
2534            // If callback returns false, stop the event
2535            if (ret === false) {
2536              event.preventDefault();
2537              event.stopPropagation();
2538            }
2539          }
2540        });
2541      }
2542    });
2543
2544    /* jshint +W040 */
2545  };
2546
2547  Kimbo.Event = function (event) {
2548
2549    // Is event object
2550    if (event && event.type) {
2551      this.originalEvent = event;
2552      this.type = event.type;
2553
2554      // The event may have been prevented
2555      // Check dom level 3 new attribute and set proper value
2556      if (event.defaultPrevented) {
2557        this.isDefaultPrevented = _returnTrue;
2558      } else {
2559        this.isDefaultPrevented = _returnFalse;
2560      }
2561
2562    // Is event type
2563    } else {
2564      this.type = event;
2565    }
2566
2567    // Create a timestamp if doesn't have one
2568    this.timeStamp = (event && event.timeStamp) || Date.now();
2569
2570    // Made by kimbo, yeah
2571    this[Kimbo.ref] = true;
2572  };
2573
2574  // Dom-Level-3-Events compliant
2575  Kimbo.Event.prototype = {
2576    isDefaultPrevented: _returnFalse,
2577    isPropagationStopped: _returnFalse,
2578    isImmediatePropagationStopped: _returnFalse,
2579
2580    preventDefault: function () {
2581      this.isDefaultPrevented = _returnTrue;
2582
2583      // Originalevent is not present when trigger is called
2584      if (!this.isTrigger) {
2585        this.originalEvent.preventDefault();
2586      }
2587    },
2588
2589    stopPropagation: function () {
2590      this.isPropagationStopped = _returnTrue;
2591
2592      if (!this.isTrigger) {
2593        this.originalEvent.stopPropagation();
2594      }
2595    },
2596
2597    stopImmediatePropagation: function () {
2598      this.isImmediatePropagationStopped = _returnTrue;
2599
2600      if (!this.isTrigger) {
2601        this.originalEvent.stopImmediatePropagation();
2602      }
2603    }
2604  };
2605
2606  Kimbo.fn.extend({
2607    /*\
2608     * $(…).on
2609     [ method ]
2610     * Add an event handler to the selected elements.
2611     > Parameters
2612     - type (string) A string name for the event to register.
2613     - selector (string) #optional Delegate an event providing a string selector.
2614     - data (any) #optional Data to be passed to the handler in `event.data` when an event is triggered.
2615     - callback (function) A callback function to execute when the event is triggered.
2616     > Usage
2617     * Suppose a button element:
2618     | <button id='btn'>click me</button>
2619     * Register a click event handler
2620     | $('#btn').on('click', function (event) {
2621     |   console.log('clicked!', event);
2622     | });
2623     * There are shorthands for all events for example:
2624     | $('#btn').click(function (event) {
2625     |   console.log('clicked!', event);
2626     | });
2627     * Passing some data when registering the handler:
2628     | $('#btn').on('click', { name: 'denis' }, function (event) {
2629     |   // Data passed is inside event.data
2630     |   console.log('name:', event.data.name);
2631     | });
2632     * Here is a list for all the shorthand methods available:
2633     | 'blur', 'change', 'click', 'contextmenu', 'dblclick', 'error',
2634     | 'focus', 'keydown', 'keypress', 'keyup', 'load', 'mousedown', 'mouseenter', 'mouseleave',
2635     | 'mousemove', 'mouseout', 'mouseup', 'mouseover', 'resize', 'scroll', 'select', 'submit', 'unload'
2636    \*/
2637    on: function (type, selector, data, callback) {
2638      // Prepare the arguments
2639
2640      // (type, callback)
2641      if (!data && !callback) {
2642        callback = selector;
2643        data = selector = undefined;
2644
2645      // (type, selector, callback)
2646      } else if (!callback) {
2647        if (Kimbo.isString(selector)) {
2648          callback = data;
2649          data = undefined;
2650
2651        // (type, data, callback)
2652        } else {
2653          callback = data;
2654          data = selector;
2655          selector = undefined;
2656        }
2657      }
2658
2659      // Don't add events if no callback
2660      if (!callback) {
2661        return this;
2662      }
2663
2664      type = GESTURES_FALLBACK[type] || type;
2665
2666      // Add the event
2667      return this.each(function (el) {
2668        _addEvent(el, type, callback, data, selector);
2669      });
2670    },
2671
2672    /*\
2673     * $(…).off
2674     [ method ]
2675     * Remove an event handler to the selected elements for the specified type, or all of them if no type defined.
2676     > Parameters
2677     - type (string) #optional A string name for the event to remove, or All if none specified.
2678     - selector (string) #optional A string selector to undelegate an event from that element.
2679     - callback (function) #optional A specific callback function if there are multiple registered under the same event type
2680     > Usage
2681     * Suppose a button element:
2682     | <button id='btn'>click me</button>
2683     * Register a click event handler
2684     | $('#btn').on('click', function (event) {
2685     |   console.log('clicked!', event);
2686     | });
2687     * Remove the handler
2688     | $('#btn').off('click');
2689     * Also you could specify the handler for example:
2690     | var firstFunction = function () { console.log('first fn'); };
2691     | var secondFunction = function () { console.log('second fn'); };
2692     | var btn = $('#btn');
2693     | btn.click(firstFunction);
2694     | btn.click(secondFunction);
2695     * If you want to remove the click event only for the second function, do this:
2696     | btn.off('click', secondFunction);
2697     * Or if you want to remove All handlers (click and any other attached):
2698     | btn.off();
2699    \*/
2700    off: function (type, selector, callback) {
2701
2702      // Prepare the arguments
2703
2704      // (type, callback)
2705      if (Kimbo.isFunction(selector)) {
2706        callback = selector;
2707        selector = undefined;
2708      }
2709
2710      // Remove the event
2711      return this.each(function (el) {
2712        _removeEvent(el, type, callback, selector);
2713      });
2714    },
2715
2716    /*\
2717     * $(…).trigger
2718     [ method ]
2719     * Execute all handlers attached to the matched elements for the fiven event type.
2720     > Parameters
2721     - type (string) #optional A string name for the event to remove, or All if none specified.
2722     - data (any) #optional Additional parameters to be passed to the handler in `event.data` when an event is triggered.
2723     > Usage
2724     * Suppose a button element:
2725     | <button id='btn'>click me</button>
2726     * Register a click event handler
2727     | $('#btn').on('click', function (event, data) {
2728     |   console.log('name', data.name);
2729     | });
2730     * Trigger the event programatically passing some data:
2731     | $('#btn').trigger('click', { name: 'denis' });
2732     | // 'name denis'
2733     * Allow the handler to recieve multiple data:
2734     | $('#btn').on('click', function (event, name, last) {
2735     |   console.log('name', name);
2736     |   console.log('last', last);
2737     | });
2738     | $('#btn').trigger('click', ['denis', 'ciccale']);
2739     | // Name denis
2740     | // Last ciccale
2741    \*/
2742    trigger: function (type, data) {
2743      return this.each(function (el) {
2744        _triggerEvent(el, type, data);
2745      });
2746    },
2747
2748    /*\
2749     * $(…).hover
2750     [ method ]
2751     * A shortcut method to register moseenter and/or mouseleave event handlers to the matched elements.
2752     > Parameters
2753     - fnOver (function) A function to execute when the cursor enters the element.
2754     - fnOut (function) #optional A function to execute when the cursor leaves the element.
2755     > Usage
2756     * Suppose a div element:
2757     | <div id='box'></div>
2758     * Register hover event
2759     | var fnOver = function () { console.log('enter'); };
2760     | var fnOut = function () { console.log('leave'); };
2761     |
2762     | $('.box').hover(fnOver, fnOut);
2763     * When the cursor enters the `.box` element the console will log:
2764     | 'enter'
2765     * When the cursor leaves the `.box` element the console will log:
2766     | 'leave'
2767    \*/
2768    hover: function (fnOver, fnOut) {
2769      return this.mouseenter(fnOver).mouseleave(fnOut || fnOver);
2770    }
2771  });
2772
2773  // Shortcut methods for each event type
2774  Kimbo.forEach(['blur', 'change', 'click', 'contextmenu', 'dblclick', 'error',
2775    'focus', 'keydown', 'keypress', 'keyup', 'load', 'mousedown', 'mouseenter', 'mouseleave', 'mousemove',
2776    'mouseout', 'mouseup', 'mouseover', 'resize', 'scroll', 'select', 'submit', 'unload'], function (type) {
2777
2778    Kimbo.fn[type] = function (data, callback) {
2779      return arguments.length > 0 ? this.on(type, null, data, callback) : this.trigger(type);
2780    };
2781
2782    // Set event props for the specific type
2783    fixEventProps[type] = KEY_EVENT_RE.test(type) ? KEY_EVENT_PROPS : MOUSE_EVENT_RE.test(type) ? MOUSE_EVENT_PROPS : null;
2784  });
2785
2786  // Fix mouseover and mouseout events to use mouseenter mouseleave
2787  Kimbo.forEach({
2788    mouseenter: 'mouseover',
2789    mouseleave: 'mouseout'
2790  }, function (orig, fix) {
2791    specialEvents[orig] = {
2792      origType: fix,
2793
2794      handle: function (event) {
2795        var target = this;
2796        var related = event.relatedTarget;
2797        var handleObj = event.handleObj;
2798        var ret;
2799
2800        if (!related || (related !== target && !query.contains(target, related))) {
2801          event.type = handleObj.origType;
2802          ret = handleObj.callback.apply(this, arguments);
2803          event.type = fix;
2804        }
2805
2806        return ret;
2807      }
2808    };
2809  });
2810
2811});
2812
2813
2814Kimbo.define('ajax', function (_) {
2815
2816  'use strict';
2817
2818  var JSONP_RE = /(\=)\?(&|$)|\?\?/i;
2819
2820  var MIME_TYPES = {
2821    html: 'text/html',
2822    json: 'application/json',
2823    script: 'text/javascript, application/javascript',
2824    text: 'text/plain',
2825    xml: 'application/xml, text/xml'
2826  };
2827
2828  var dataParse = {
2829    json: Kimbo.parseJSON,
2830    xml: Kimbo.parseXML
2831  };
2832
2833  var xhrCallbacks = {};
2834
2835  // Success and error callbacks
2836  Kimbo.forEach(['success', 'error'], function (type) {
2837    xhrCallbacks[type] = function (res, msg, xhr, settings) {
2838      settings = settings || xhr;
2839      if (Kimbo.isFunction(settings[type])) {
2840        settings[type].apply(settings.context, arguments);
2841      }
2842    };
2843  });
2844
2845  var _getResponse = function (response, type) {
2846    return (dataParse[type] ? dataParse[type](response) : response);
2847  };
2848
2849  var _handleResponse = function (xhr, settings) {
2850    var response, contentType;
2851
2852    // Set dataType if missing
2853    if (!settings.dataType) {
2854      contentType = xhr.getResponseHeader('Content-Type');
2855
2856      Kimbo.forEach(MIME_TYPES, function (name, type) {
2857        if (type.match(contentType)) {
2858          settings.dataType = name;
2859          return false;
2860        }
2861      });
2862
2863      // Fix settings headers
2864      _setHeaders(settings);
2865    }
2866
2867    try {
2868      response = _getResponse(xhr.responseText, settings.dataType);
2869    } catch (e) {
2870      response = false;
2871      xhrCallbacks.error('parseerror', e, xhr, settings);
2872    }
2873
2874    return response;
2875  };
2876
2877  var _setHeaders = function (settings) {
2878    if (!settings.crossDomain && !settings.headers['X-Requested-With']) {
2879      settings.headers['X-Requested-With'] = 'XMLHttpRequest';
2880    }
2881
2882    if (settings.contentType) {
2883      settings.headers['Content-Type'] = settings.contentType;
2884    }
2885
2886    settings.headers.Accept = MIME_TYPES[settings.dataType] || '*/*';
2887  };
2888
2889  var _timeout = function (xhr, settings) {
2890    xhr.onreadystatechange = null;
2891    xhr.abort();
2892    xhrCallbacks.error('error', 'timeout', xhr, settings);
2893  };
2894
2895  var _createAbortTimeout = function (xhr, settings) {
2896    return window.setTimeout(function () {
2897      _timeout(xhr, settings);
2898    }, settings.timeout);
2899  };
2900
2901  /*\
2902   * $.ajaxSettings
2903   [ property ]
2904   * Default ajax settings object.
2905   > Usage
2906   * If you want to change the global and default ajax settings, change this object properties:
2907   | $.ajaxSettings.error = function () {
2908   |   // Handle any failed ajax request in your app
2909   | };
2910   | $.ajaxSettings.timeout = 1000; // 1 second
2911  \*/
2912  Kimbo.ajaxSettings = {
2913    type: 'GET',
2914    async: true,
2915    success: {},
2916    error: {},
2917    context: null,
2918    headers: {},
2919    data: null,
2920    crossDomain: false,
2921    timeout: 0,
2922    contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
2923    xhr: function () {
2924      return new window.XMLHttpRequest();
2925    }
2926  };
2927
2928  /*\
2929   * $.ajax
2930   [ method ]
2931   * Perform an asynchronous HTTP (Ajax) request.
2932   > Parameters
2933   - options (object) #optional An object with options
2934   o {
2935   o   url (string) Url to make the request.
2936   o   type (string) #optional Type of request. Could be `'GET'` or `'POST'`. Default value is `'GET'`.
2937   o   async (boolean) #optional Default value is `true` if you want synchronous requests set option to `false`.
2938   o   success (function) #optional A function that will be called if the request succeeds. Recieving (response, responseMessage, xhr, settings).
2939   o   error (function) #optional A function that will be called if the request fails. Recieving (response, responseMessage, xhr, settings).
2940   o   context (object) #optional The context in which all ajax request are made. By default the context are the settings object. Could be any DOM element.
2941   o   headers (object) #optional An object with additional header key/value pairs to send along with the request.
2942   o   data (string|object) #optional Additional data to send with the request, if it is an object is converted to a query string.
2943   o   xhr (function) #optional A function that returns a `new XMLHttpRequest()` object by default.
2944   o   crossDomain (boolean) #optional Indicate wether you want to force crossDomain requests. `false` by defualt.
2945   o   timeout (number) #optional Set a default timeout in milliseconds for the request.
2946   o   contentType (string) #optional The default and finest contentType for most cases is `'application/x-www-form-urlencoded; charset=UTF-8'`.
2947   o }
2948   = (object) The native xhr object.
2949   > Usage
2950   * Get a username passing an id to the /users url
2951   | $.ajax({
2952   |   url '/users',
2953   |   data: {
2954   |     id: 3
2955   |   },
2956   |   success: function (response, responseMessage, xhr, settings) {
2957   |     // Success...
2958   |   },
2959   |   error: function (response, responseMessage, xhr, settings) {
2960   |     // Error...
2961   |   }
2962   | });
2963  \*/
2964  Kimbo.ajax = function (options) {
2965    var settings = Kimbo.extend({}, Kimbo.ajaxSettings, options);
2966    var xhr, abortTimeout, callback;
2967
2968    // Add data to url
2969    if (settings.data) {
2970      settings.url += (/\?/.test(settings.url) ? '&' : '?') +
2971        Kimbo.param(settings.data);
2972      delete settings.data;
2973    }
2974
2975    // Set default context
2976    if (!settings.context) {
2977      settings.context = settings;
2978    }
2979
2980    // Check if its jsonp
2981    if (JSONP_RE.test(settings.url)) {
2982      return _getJSONP(settings);
2983    }
2984
2985    // Create new instance
2986    xhr = settings.xhr();
2987
2988    // User specified timeout
2989    if (settings.timeout > 0) {
2990      abortTimeout = _createAbortTimeout(xhr, settings);
2991    }
2992
2993    // On complete callback
2994    callback = function () {
2995      var response, status;
2996
2997      // Request complete
2998      if (xhr.readyState === 4) {
2999        status = xhr.status;
3000
3001        // Clear timeout
3002        window.clearTimeout(abortTimeout);
3003
3004        // Scuccess
3005        if ((status >= 200 && status < 300) || status === 304) {
3006          if (settings.async) {
3007            response = _handleResponse(xhr, settings);
3008            if (response !== false) {
3009              xhrCallbacks.success(response, xhr, settings);
3010            }
3011          }
3012
3013        // Fail
3014        } else {
3015          xhrCallbacks.error('error', xhr.statusText, xhr, settings);
3016        }
3017      }
3018    };
3019
3020    // Listen for response
3021    xhr.onreadystatechange = callback;
3022
3023    // Init request
3024    xhr.open(settings.type, settings.url, settings.async);
3025
3026    // Set settings headers
3027    _setHeaders(settings);
3028
3029    // Set xhr headers
3030    Kimbo.forEach(settings.headers, function (header, value) {
3031      xhr.setRequestHeader(header, value);
3032    });
3033
3034    // Try to send request
3035    xhr.send(settings.data);
3036
3037    return (settings.async) ? xhr : callback();
3038  };
3039
3040  /*\
3041   * $.get
3042   [ method ]
3043   * Load data from the server using HTTP GET request.
3044   > Parameters
3045   - url (string) A string containing the URL to which the request is sent.
3046   - data (string|object) #optional An option string or object with data params to send to the server.
3047   - callback (function) A callback function to execute if the request succeeds.
3048   - type (string) #optional String with the type of the data to send (intelligent guess by default).
3049   > Usage
3050   | $.get('url/users.php', { id: '123' }, function (data) {
3051   |   // Success
3052   |   console.log('response:', data);
3053   | });
3054   * This method is a shorthand for the $.ajax
3055   | $.ajax({
3056   |   url: url,
3057   |   data: data,
3058   |   success: success,
3059   |   dataType: dataType
3060   | });
3061  \*/
3062
3063  /*\
3064   * $.post
3065   [ method ]
3066   * Load data from the server using HTTP POST request.
3067   > Parameters
3068   - url (string) A string containing the URL to which the request is sent.
3069   - data (string|object) #optional An option string or object with data params to send to the server.
3070   - callback (function) A callback function to execute if the request succeeds.
3071   - type (string) #optional String with the type of the data to send (intelligent guess by default).
3072   > Usage
3073   | $.post('url/users.php', { user: 'denis', pass: '123' }, function (data) {
3074   |   // Success
3075   |   console.log('response:', data);
3076   | });
3077   * This method is a shorthand for the $.ajax
3078   | $.ajax({
3079   |   type: 'POST',
3080   |   url: url,
3081   |   data: data,
3082   |   success: success,
3083   |   dataType: dataType
3084   | });
3085  \*/
3086  Kimbo.forEach(['get', 'post'], function (method) {
3087    Kimbo[method] = function (url, data, callback, type) {
3088
3089      // Prepare arguments
3090      if (Kimbo.isFunction(data)) {
3091        type = type || callback;
3092        callback = data;
3093        data = null;
3094      }
3095
3096      // Call ajax
3097      return Kimbo.ajax({
3098        type: method.toUpperCase(),
3099        url: url,
3100        data: data,
3101        success: callback,
3102        dataType: type
3103      });
3104    };
3105  });
3106
3107  Kimbo.extend({
3108   /*\
3109    * $.getScript
3110    [ method ]
3111    * Load a JavaScript file from the server using a GET HTTP request, then execute it.
3112    > Parameters
3113    - url (string) A string containing the URL to which the request is sent.
3114    - callback (function) A callback function to execute if the request succeeds.
3115    > Usage
3116    | $.getScript('url/script.js', function (data) {
3117    |   // Success
3118    |   console.log('response:', data);
3119    | });
3120    * This method is a shorthand for the $.ajax
3121    | $.ajax({
3122    |   url: url,
3123    |   dataType: 'script',
3124    |   success: success
3125    | });
3126   \*/
3127    getScript: function (url, callback) {
3128      return Kimbo.get(url, callback, 'script');
3129    },
3130
3131   /*\
3132    * $.getJSON
3133    [ method ]
3134    * Load data from the server using HTTP POST request.
3135    > Parameters
3136    - url (string) A string containing the URL to which the request is sent.
3137    - data (string|object) #optional An option string or object with data params to send to the server.
3138    - callback (function) A callback function to execute if the request succeeds.
3139    - type (string) #optional String with the type of the data to send (intelligent guess by default).
3140    > Usage
3141    | $.getJSON('url/test.json', { id: '2' }, function (data) {
3142    |   // Success
3143    |   console.log('response:', data);
3144    | });
3145    * This method is a shorthand for the $.ajax
3146    | $.ajax({
3147    |   url: url,
3148    |   dataType: 'json',
3149    |   success: success
3150    | });
3151    * To get json data with jsonp:
3152    | $.getJSON('http://search.twitter.com/search.json?callback=?', 'q=#javascript', function (data) {
3153    |   console.log(data);
3154    | });
3155   \*/
3156    getJSON: function (url, data, callback) {
3157      return Kimbo.get(url, data, callback, 'json');
3158    }
3159  });
3160
3161  // getJSONP internal use
3162  var _getJSONP = function (settings) {
3163    var jsonpCallback = Kimbo.ref + '_' + Date.now();
3164    var script = _.document.createElement('script');
3165    var head = _.document.head;
3166    var xhr = {
3167      abort: function () {
3168        window.clearTimeout(abortTimeout);
3169        head.removeChild(script);
3170        delete window[jsonpCallback];
3171      }
3172    };
3173    var abortTimeout;
3174
3175    // User specified timeout
3176    if (settings.timeout > 0) {
3177      abortTimeout = _createAbortTimeout(xhr, settings);
3178    }
3179
3180    // Set url
3181    script.src = settings.url.replace(JSONP_RE, '$1' + jsonpCallback + '$2');
3182
3183    // Jsonp callback
3184    window[jsonpCallback] = function (response) {
3185
3186      // Remove script
3187      xhr.abort();
3188
3189      // Fake xhr
3190      Kimbo.extend(xhr, {
3191        statusText: 'OK',
3192        status: 200,
3193        response: response,
3194        headers: settings.headers
3195      });
3196
3197      // Success
3198      xhrCallbacks.success(response, xhr, settings);
3199    };
3200
3201    // Set settings headers
3202    _setHeaders(settings);
3203
3204    // Apend script to head to make the request
3205    head.appendChild(script);
3206
3207    // Return fake xhr object to abort manually
3208    return xhr;
3209  };
3210
3211  /*\
3212   * $.param
3213   [ method ]
3214   * Create a serialized representation of an array or object, suitable for use in a URL query string or Ajax request.
3215   > Parameters
3216   - data (string|object) A string or object to serialize.
3217   > Usage
3218   | var obj = { name: 'Denis', last: 'Ciccale' };
3219   | var serialized = $.param(obj); // 'name=Denis&last=Ciccale'
3220  \*/
3221  Kimbo.param = function (data) {
3222    var params = '';
3223
3224    if (Kimbo.isObject(data)) {
3225      Kimbo.forEach(data, function (name, value) {
3226        params += name + '=' + value + '&';
3227      });
3228    } else {
3229      params = data;
3230    }
3231
3232    return window.encodeURIComponent(params)
3233      .replace(/%20/g, '+')
3234      .replace(/%\d[D6F]/g, window.unescape)
3235      .replace(/^\?|&$/g, '');
3236  };
3237});
3238