polyfill.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. /* Native JavaScript for Bootstrap 3 IE8+ Polyfill
  2. --------------------------------------------*/
  3. (function(){
  4. // all repeated strings get a single reference
  5. // document | window | element + corrections
  6. var Doc = 'Document', doc = document, DOCUMENT = this[Doc] || this.HTMLDocument, // IE8
  7. WIN = 'Window', win = window, WINDOW = this.constructor || this[WIN] || Window, // old Safari
  8. HTMLELEMENT = 'HTMLElement', documentElement = 'documentElement', ELEMENT = Element,
  9. // classList related
  10. className = 'className', add = 'add', classList = 'classList', remove = 'remove', contains = 'contains',
  11. CLASS = 'class', setATTRIBUTE = 'setAttribute', getATTRIBUTE = 'getAttribute',
  12. // object | array related
  13. prototype = 'prototype', indexOf = 'indexOf', length = 'length', split = 'split', trim = 'trim',
  14. // event related
  15. EVENT = 'Event', CustomEvent = 'CustomEvent', IE8EVENTS = '_events',
  16. etype = 'type', target = 'target', currentTarget = 'currentTarget', relatedTarget = 'relatedTarget',
  17. cancelable = 'cancelable', bubbles = 'bubbles', cancelBubble = 'cancelBubble', cancelImmediate = 'cancelImmediate', detail = 'detail',
  18. addEventListener = 'addEventListener', removeEventListener = 'removeEventListener', dispatchEvent = 'dispatchEvent';
  19. // Element
  20. if (!win[HTMLELEMENT]) { win[HTMLELEMENT] = win[ELEMENT]; }
  21. // Array[prototype][indexOf]
  22. if (!Array[prototype][indexOf]) {
  23. Array[prototype][indexOf] = function(searchElement) {
  24. if (this === undefined || this === null) {
  25. throw new TypeError(this + ' is not an object');
  26. }
  27. var arraylike = this instanceof String ? this[split]('') : this,
  28. lengthValue = Math.max(Math.min(arraylike[length], 9007199254740991), 0) || 0,
  29. index = Number(arguments[1]) || 0;
  30. index = (index < 0 ? Math.max(lengthValue + index, 0) : index) - 1;
  31. while (++index < lengthValue) {
  32. if (index in arraylike && arraylike[index] === searchElement) {
  33. return index;
  34. }
  35. }
  36. return -1;
  37. };
  38. }
  39. if (!String[prototype][trim]) {
  40. String[prototype][trim] = function () {
  41. return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
  42. };
  43. }
  44. // Element.prototype.classList by thednp
  45. if( !(classList in ELEMENT[prototype]) ) {
  46. var ClassLIST = function(elem){
  47. var classArr = (elem[getATTRIBUTE](CLASS)||'').replace(/^\s+|\s+$/g,'')[split](/\s+/) || [];
  48. // methods
  49. hasClass = this[contains] = function(classNAME){
  50. return classArr[indexOf](classNAME) > -1;
  51. },
  52. addClass = this[add] = function(classNAME){
  53. if (!hasClass(classNAME)) {
  54. classArr.push(classNAME);
  55. elem[setATTRIBUTE](CLASS, classArr.join(' '));
  56. }
  57. },
  58. removeClass = this[remove] = function(classNAME){
  59. if (hasClass(classNAME)) {
  60. classArr.splice(classArr[indexOf](classNAME),1);
  61. elem[setATTRIBUTE](CLASS, classArr.join(' '));
  62. }
  63. },
  64. toggleClass = this.toggle = function(classNAME){
  65. if ( hasClass(classNAME) ) { removeClass(classNAME); }
  66. else { addClass(classNAME); }
  67. };
  68. }
  69. Object.defineProperty(ELEMENT[prototype], classList, { get: function () { return new ClassLIST(this); } });
  70. }
  71. // Event
  72. if (!win[EVENT]||!WINDOW[prototype][EVENT]) {
  73. win[EVENT] = WINDOW[prototype][EVENT] = DOCUMENT[prototype][EVENT] = ELEMENT[prototype][EVENT] = function(type, eventInitDict) {
  74. if (!type) { throw new Error('Not enough arguments'); }
  75. var event,
  76. bubblesValue = eventInitDict && eventInitDict[bubbles] !== undefined ? eventInitDict[bubbles] : false,
  77. cancelableValue = eventInitDict && eventInitDict[cancelable] !== undefined ? eventInitDict[cancelable] : false;
  78. if ( 'createEvent' in doc ) {
  79. event = doc.createEvent(EVENT);
  80. event.initEvent(type, bubblesValue, cancelableValue);
  81. } else {
  82. event = doc.createEventObject();
  83. event[etype] = type;
  84. event[bubbles] = bubblesValue;
  85. event[cancelable] = cancelableValue;
  86. }
  87. return event;
  88. };
  89. }
  90. // CustomEvent
  91. if (!(CustomEvent in win) || !(CustomEvent in WINDOW[prototype])) {
  92. win[CustomEvent] = WINDOW[prototype][CustomEvent] = DOCUMENT[prototype][CustomEvent] = Element[prototype][CustomEvent] = function(type, eventInitDict) {
  93. if (!type) {
  94. throw Error('CustomEvent TypeError: An event name must be provided.');
  95. }
  96. var event = new Event(type, eventInitDict);
  97. event[detail] = eventInitDict && eventInitDict[detail] || null;
  98. return event;
  99. };
  100. }
  101. // addEventListener | removeEventListener
  102. if (!win[addEventListener]||!WINDOW[prototype][addEventListener]) {
  103. win[addEventListener] = WINDOW[prototype][addEventListener] = DOCUMENT[prototype][addEventListener] = ELEMENT[prototype][addEventListener] = function() {
  104. var element = this,
  105. type = arguments[0],
  106. listener = arguments[1];
  107. if (!element[IE8EVENTS]) { element[IE8EVENTS] = {}; }
  108. if (!element[IE8EVENTS][type]) {
  109. element[IE8EVENTS][type] = function (event) {
  110. var list = element[IE8EVENTS][event[etype]].list,
  111. events = list.slice(),
  112. index = -1,
  113. lengthValue = events[length],
  114. eventElement;
  115. event.preventDefault = function() {
  116. if (event[cancelable] !== false) {
  117. event.returnValue = false;
  118. }
  119. };
  120. event.stopPropagation = function() {
  121. event[cancelBubble] = true;
  122. };
  123. event.stopImmediatePropagation = function() {
  124. event[cancelBubble] = true;
  125. event[cancelImmediate] = true;
  126. };
  127. event[currentTarget] = element;
  128. event[relatedTarget] = event[relatedTarget] || event.fromElement || null;
  129. event[target] = event[target] || event.srcElement || element;
  130. event.timeStamp = new Date().getTime();
  131. if (event.clientX) {
  132. event.pageX = event.clientX + doc[documentElement].scrollLeft;
  133. event.pageY = event.clientY + doc[documentElement].scrollTop;
  134. }
  135. while (++index < lengthValue && !event[cancelImmediate]) {
  136. if (index in events) {
  137. eventElement = events[index];
  138. if (list[indexOf](eventElement) !== -1 && typeof eventElement === 'function') {
  139. eventElement.call(element, event);
  140. }
  141. }
  142. }
  143. };
  144. element[IE8EVENTS][type].list = [];
  145. if (element.attachEvent) {
  146. element.attachEvent('on' + type, element[IE8EVENTS][type]);
  147. }
  148. }
  149. element[IE8EVENTS][type].list.push(listener);
  150. };
  151. win[removeEventListener] = WINDOW[prototype][removeEventListener] = DOCUMENT[prototype][removeEventListener] = ELEMENT[prototype][removeEventListener] = function() {
  152. var element = this,
  153. type = arguments[0],
  154. listener = arguments[1],
  155. index;
  156. if (element[IE8EVENTS] && element[IE8EVENTS][type] && element[IE8EVENTS][type].list) {
  157. index = element[IE8EVENTS][type].list[indexOf](listener);
  158. if (index !== -1) {
  159. element[IE8EVENTS][type].list.splice(index, 1);
  160. if (!element[IE8EVENTS][type].list[length]) {
  161. if (element.detachEvent) {
  162. element.detachEvent('on' + type, element[IE8EVENTS][type]);
  163. }
  164. delete element[IE8EVENTS][type];
  165. }
  166. }
  167. }
  168. };
  169. }
  170. // Event dispatcher
  171. if (!win[dispatchEvent]||!WINDOW[prototype][dispatchEvent]||!DOCUMENT[prototype][dispatchEvent]||!ELEMENT[prototype][dispatchEvent]) {
  172. win[dispatchEvent] = WINDOW[prototype][dispatchEvent] = DOCUMENT[prototype][dispatchEvent] = ELEMENT[prototype][dispatchEvent] = function (event) {
  173. if (!arguments[length]) {
  174. throw new Error('Not enough arguments');
  175. }
  176. if (!event || typeof event[etype] !== 'string') {
  177. throw new Error('DOM Events Exception 0');
  178. }
  179. var element = this, type = event[etype];
  180. try {
  181. if (!event[bubbles]) {
  182. event[cancelBubble] = true;
  183. var cancelBubbleEvent = function (event) {
  184. event[cancelBubble] = true;
  185. (element || win).detachEvent('on' + type, cancelBubbleEvent);
  186. };
  187. this.attachEvent('on' + type, cancelBubbleEvent);
  188. }
  189. this.fireEvent('on' + type, event);
  190. } catch (error) {
  191. event[target] = element;
  192. do {
  193. event[currentTarget] = element;
  194. if (IE8EVENTS in element && typeof element[IE8EVENTS][type] === 'function') {
  195. element[IE8EVENTS][type].call(element, event);
  196. }
  197. if (typeof element['on' + type] === 'function') {
  198. element['on' + type].call(element, event);
  199. }
  200. element = element.nodeType === 9 ? element.parentWindow : element.parentNode;
  201. } while (element && !event[cancelBubble]);
  202. }
  203. return true;
  204. };
  205. }
  206. }());