CodeFelony JS Library

A JavaScript library used by CodeFelony

Script này sẽ không được không được cài đặt trực tiếp. Nó là một thư viện cho các script khác để bao gồm các chỉ thị meta // @require https://update.greatest.deepsurf.us/scripts/9003/44596/CodeFelony%20JS%20Library.js

  1. // ==UserScript==
  2. // @name CodeFelony JS Library
  3. // @namespace https://greatest.deepsurf.us/en/users/10166-moriarty
  4. // @description A JavaScript library used by CodeFelony
  5. // @include *
  6. // @copyright (c) 2015 CodeFelony. All Rights Reserved
  7. // @author Moriarty
  8. // @version 1.3.1
  9. // @license LGPL version 3 or any later version; http://www.gnu.org/copyleft/lgpl.html
  10. // @grant GM_addStyle
  11. // ==/UserScript==
  12.  
  13. /**
  14. WIKI ==> https://github.com/codefelony/cfl/wiki/
  15. **/
  16.  
  17. (function (window, undefined) {
  18.  
  19. 'use strict'; // use strict mode in ECMAScript-5
  20.  
  21. var version = '1.3.1'; // this will be used for CFL.prototype.version
  22. var intervals = []; // for the setInterval/clearInterval methods
  23.  
  24. // regular expressions
  25. var rSelector = /^\*|^\.[a-z][\w\d-]*|^#[^ ]+|^[a-z]+|^\[a-z]+/i; // matches a CSS selector
  26. var rXpath = /^(\.*\/{1,2})+[a-zA-Z\*]+/; // matches an XPath query
  27. var rHTML = /<[^>]+>/; // matches a string of HTML
  28. var rHyphenated = /-([a-zA-Z])/g; // matches alphabetic, hyphenated strings
  29. var rElementObject = /^\[object HTML([a-zA-Z]+)?Element\]$/; // matches the toString value of an element
  30. var rWindowObject = /^\[object Window\]$/; // matches the toString value of a window object
  31. var rValidVarname = /^[a-zA-Z$_][a-zA-Z0-9$_]*$/; // matches a valid variable name
  32.  
  33. // compatibility methods for browsers that don't support ECMAScript-5 completely
  34. var compat = {
  35. 'arr_indexOf' : function (searchElement, fromIndex) {
  36. var index = parseInt(fromIndex || 0, 10), len = this.length;
  37. index = index < 0 ? len + index : index; // handle negative fromIndex
  38. index = !(index > 0) ? 0 : index; // handle out of range and/or NaN fromIndex
  39.  
  40. while (index < len && index >= 0) {
  41. if (this[index] === searchElement) {
  42. return index;
  43. }
  44. index += 1;
  45. }
  46.  
  47. return -1;
  48. },
  49. /*
  50. 'filter' : function (fn, oThis) {
  51. var index, value, len = this.length, ret = [];
  52.  
  53. for (index = 0; index < len; index += 1) {
  54. value = this[index];
  55. if ( fn.call(oThis, value, index, this) ) {
  56. ret.push(value);
  57. }
  58. }
  59.  
  60. return ret;
  61. },
  62. */
  63. 'forEach' : function (fn, oThis) {
  64. var index, len;
  65.  
  66. for (index = 0, len = this.length; index < len; index += 1) {
  67. fn.call(oThis, this[index], index, this);
  68. }
  69. },
  70. 'map' : function (fn, oThis) {
  71. var index, newArr = [], len;
  72.  
  73. for (index = 0, len = this.length; index < len; index += 1) {
  74. newArr[index] = fn.call(oThis, this[index], index, this);
  75. }
  76.  
  77. return newArr;
  78. },
  79. 'reduce' : function (fn, initialValue) {
  80. var index, len, value, isValueSet = false;
  81.  
  82. if (arguments.length > 1) {
  83. value = initialValue;
  84. isValueSet = true;
  85. }
  86.  
  87. for (index = 0, len = this.length; index < len; index += 1) {
  88. if (isValueSet) {
  89. value = fn(value, this[index], index, this);
  90. } else {
  91. value = this[index];
  92. isValueSet = true;
  93. }
  94. }
  95.  
  96. return value;
  97. }
  98. };
  99.  
  100. // gets a method from an object's prototype. returns undefined if not found
  101. var getMethod = function (obj, method) {
  102. if (typeof XPCNativeWrapper === 'function' && typeof XPCNativeWrapper.unwrap === 'function') {
  103. obj = XPCNativeWrapper.unwrap(obj);
  104. } else if (obj.wrappedJSObject) {
  105. obj = obj.wrappedJSObject;
  106. }
  107.  
  108. if (obj.prototype && typeof obj.prototype[method] === 'function') {
  109. return obj.prototype[method];
  110. }
  111. };
  112.  
  113. // original methods for some common uses
  114. var core = {
  115. // array
  116. 'arr_indexOf' : getMethod(Array, 'indexOf') || compat.arr_indexOf,
  117. 'concat' : getMethod(Array, 'concat'),
  118. 'filter' : getMethod(Array, 'filter') || compat.filter,
  119. 'forEach' : getMethod(Array, 'forEach') || compat.forEach,
  120. 'map' : getMethod(Array, 'map') || compat.map,
  121. 'reduce' : getMethod(Array, 'reduce') || compat.reduce,
  122. 'slice' : getMethod(Array, 'slice'),
  123.  
  124. // object
  125. 'hasOwnProperty' : getMethod(Object, 'hasOwnProperty'),
  126. 'toString' : getMethod(Object, 'toString'),
  127. };
  128.  
  129. var CFL = function CFL(selector, context) {
  130. return new CFL.fn.init(selector, context);
  131. };
  132.  
  133. // a simple class for dealing with event listener handlers
  134. var handlers = {
  135. stack : [],
  136.  
  137. add : function (thisElement, type, fn) {
  138. this.stack.push({
  139. element : thisElement,
  140. type : type,
  141. fn : fn
  142. });
  143. },
  144.  
  145. get : function (thisElement, type) {
  146. var events = [];
  147. type = typeof type === 'string' ? type : '*';
  148.  
  149. CFL.each(this.stack, function (thisEventObj) {
  150. if (thisElement === thisEventObj.element) {
  151. if (type === '*' || thisEventObj.type === type) {
  152. events.push(thisEventObj);
  153. }
  154. }
  155. });
  156.  
  157. return events;
  158. },
  159.  
  160. remove : function (thisElement, type) {
  161. var handlerIndices = [], that = this;
  162.  
  163. // find all the indices of what we need to remove
  164. CFL.each(handlers.get(thisElement, type), function (thisEventObj, index, array) {
  165. handlerIndices.push(
  166. core.arr_indexOf.call(that.stack, thisEventObj)
  167. );
  168. });
  169.  
  170. // remove all the indices here, using a separate array of indices
  171. // we can't do this as we loop over the (stack) array itself, because
  172. // we would be removing values as they are being iterated through
  173. CFL.each(handlerIndices, function (thisIndex) {
  174. that.stack.splice(thisIndex, 1);
  175. });
  176. }
  177. };
  178.  
  179. // Node.prototype.matchesSelector compat for vendor prefixes
  180. function matchesSelector(element, selector) {
  181. if (element && typeof selector === 'string') {
  182. if (typeof element.mozMatchesSelector === 'function') {
  183. // Mozilla
  184. return element.mozMatchesSelector(selector);
  185. } else if (typeof element.webkitMatchesSelector === 'function') {
  186. // Webkit
  187. return element.webkitMatchesSelector(selector);
  188. } else if (typeof element.oMatchesSelector === 'function') {
  189. // Opera
  190. return element.oMatchesSelector(selector);
  191. } else if (typeof element.msMatchesSelector === 'function') {
  192. // IE
  193. return element.msMatchesSelector(selector);
  194. }
  195. }
  196.  
  197. return false;
  198. }
  199.  
  200. // calls 'this' with the first parameter as the first argument
  201. function call(a) {
  202. return this(a);
  203. }
  204.  
  205. function toCamelCase(string) {
  206. return string.replace(rHyphenated, function (fullMatch, firstGroup) {
  207. return firstGroup.toUpperCase();
  208. });
  209. }
  210.  
  211. // walkTheDom by Douglas Crockford
  212. function walkTheDom(node, func) {
  213. func(node);
  214. node = node.firstChild;
  215.  
  216. while (node) {
  217. walkTheDom(node, func);
  218. node = node.nextSibling;
  219. }
  220. }
  221.  
  222. // can pluck a key out of an object
  223. function pluck(obj) {
  224. var subs = this.split('.'),
  225. ret = obj, i;
  226.  
  227. for (i = 0; i < subs.length; i += 1) {
  228. ret = ret[ subs[i] ];
  229. if (ret == null) {
  230. return '';
  231. }
  232. }
  233.  
  234. return ret;
  235. }
  236.  
  237. function sum(curValue, nextValue) {
  238. return curValue + nextValue;
  239. }
  240.  
  241. function sumInt(curValue, nextValue) {
  242. return parseInt(curValue, 10) + parseInt(nextValue, 10);
  243. }
  244.  
  245. // internal function for throwing errors, so the user gets
  246. // some sort of hint as to why their operation failed
  247. function error(errorString) {
  248. if (typeof console !== 'undefined' && typeof console.error === 'function') {
  249. console.error(errorString);
  250. }
  251.  
  252. return null; // always return null
  253. }
  254.  
  255. // will copy an element and return a new copy with the same event listeners
  256. function cloneElement(thisElement) {
  257. var newElement = thisElement.cloneNode(true);
  258.  
  259. // clone event listeners of element
  260. CFL.each(handlers.get(thisElement), function (thisEventObj) {
  261. CFL.addEvent(newElement, thisEventObj.type, thisEventObj.fn);
  262. });
  263.  
  264. return newElement;
  265. }
  266.  
  267. function getEachElements(array, selector, key, type) {
  268. var newElementsArray = [],
  269. isValidSelector = typeof selector === 'string' && selector.trim() !== '';
  270.  
  271. CFL.each(array, function (currentElement) {
  272. while ( currentElement = currentElement[key] ) { // note: intentional assignment
  273. if (type > 0 ? currentElement.nodeType === type : true) {
  274. if ( isValidSelector === false || CFL(currentElement).filter(selector).exists ) {
  275. newElementsArray.push(currentElement);
  276. return;
  277. }
  278. }
  279. }
  280. });
  281.  
  282. return newElementsArray;
  283. }
  284.  
  285. // this will take
  286. function doElementOperationOnEach(args, op) {
  287. var newElementsArray = [], newElement,
  288. passedElements = CFL.create.apply(CFL, args);
  289.  
  290. if (this.exists) {
  291. if (CFL.typeOf(passedElements) === 'array') {
  292. this.each(function (thisElement) {
  293. CFL.each(passedElements, function (passedElement) {
  294. // clone the element
  295. var newElement = cloneElement(passedElement);
  296.  
  297. // add the new elements to an array
  298. newElementsArray.push(newElement);
  299.  
  300. // perform the passed operation on the element
  301. op(thisElement, newElement);
  302. });
  303. });
  304. } else {
  305. this.each(function (thisElement) {
  306. // clone the element
  307. var newElement = cloneElement(passedElements);
  308.  
  309. // add the new elements to an array
  310. newElementsArray.push(newElement);
  311.  
  312. // perform the passed operation on the element
  313. op(thisElement, newElement);
  314. });
  315. }
  316. }
  317.  
  318. return newElementsArray;
  319. }
  320.  
  321. // define CFL's prototype, aka CFL.fn
  322. CFL.fn = CFL.prototype = {
  323. isCFL : true,
  324. constructor : CFL,
  325. length : 0,
  326. version : version,
  327.  
  328. // similar to jQuery. CFL is just the init constructor
  329. init : function (selector, context) {
  330. var selectorStringValue = core.toString.call(selector),
  331. that = this,
  332. elems = [];
  333.  
  334. switch (typeof selector) {
  335. case 'string': { // -- STRING --
  336. if ( selector.match(rXpath) ) {
  337. // handle an XPath expression
  338. elems = CFL.xpath({expression : selector, type : 7, context : context});
  339. } else if ( selector.match(rHTML) ) {
  340. // reserved for html code creation
  341. // not sure if I want to implement it
  342. } else if ( selector.match(rSelector) ) {
  343. if (CFL.typeOf(context) === 'array') {
  344. // handle an array being passed as the context
  345. return that.find.call(context, selector);
  346. } else if (typeof context === 'string') {
  347. // handle a selector being passsed as the context
  348. context = CFL(context);
  349. if (context.exists) {
  350. return CFL(selector, context[0]);
  351. }
  352. } else if (context != null && context.isCFL === true && context.exists) {
  353. // handle a CFL object being passsed as the context
  354. return CFL( selector, context[0] );
  355. } else {
  356. // handle a regular element being passed as the context
  357. context = context != null && context.querySelectorAll ? context : document;
  358. elems = context.querySelectorAll(selector);
  359. }
  360. }
  361. break;
  362. }
  363. // ---------------------------------------------------
  364. case 'object': { // -- OBJECT --
  365. if (selector != null) {
  366. if (selector.isCFL === true) {
  367. // handle a CFL object
  368. return selector;
  369. } else if ( core.hasOwnProperty.call(selector, 'length') ) {
  370. // handle an array-like object
  371. elems = selector;
  372. } else if ( selectorStringValue.match(rElementObject) || selectorStringValue.match(rWindowObject) ) {
  373. // handle a single element
  374. elems = [selector];
  375. }
  376. }
  377. break;
  378. }
  379. // ---------------------------------------------------
  380. default: { // -- UNKNOWN --
  381. if ( selectorStringValue.match(rElementObject) || selectorStringValue.match(rWindowObject) ) {
  382. // handle elements that are typeof === 'function'
  383. // e.g., object, applet, embed
  384. elems = [selector];
  385. }
  386. }
  387. }
  388.  
  389. // define the length property of our object wrapper
  390. that.length = elems.length;
  391.  
  392. // bind the elements to array-like key:value pairs in our wrapper
  393. // e.g., this[0] ==> element
  394. CFL.each(elems, function (value, index) {
  395. that[index] = value;
  396. });
  397.  
  398. return that;
  399. },
  400.  
  401. // --- STARTING LINE FOR THE CFL WRAPPER METHODS
  402. add : function (selector, context) {
  403. var newElements = CFL(selector, context).raw(),
  404. allElements = core.concat.call(this.raw(), newElements);
  405. return CFL(allElements);
  406. },
  407.  
  408. addEvent : function (type, fn) {
  409. return this.each(function (thisElement) {
  410. CFL.addEvent(thisElement, type, fn);
  411. });
  412. },
  413.  
  414. after : function () {
  415. var newElementsArray = doElementOperationOnEach.call(this, CFL.toArray(arguments), function (baseElement, newElement) {
  416. var parent = baseElement.parentNode,
  417. next = baseElement.nextSibling;
  418.  
  419. if (parent) {
  420. if (next) {
  421. // add the newElement after the current element
  422. parent.insertBefore(newElement, next);
  423. } else {
  424. // nextSibling didn't exist. just append to its parent
  425. parent.appendChild(newElement);
  426. }
  427. }
  428. });
  429.  
  430. return CFL(newElementsArray);
  431. },
  432.  
  433. append : function () {
  434. var newElementsArray = doElementOperationOnEach.call(this, CFL.toArray(arguments), function (baseElement, newElement) {
  435. baseElement.appendChild(newElement);
  436. });
  437.  
  438. return CFL(newElementsArray);
  439. },
  440.  
  441. attribute : function (name, value) {
  442. var ret = '', valueIsValid = value != null;
  443.  
  444. if ( typeof name === 'string' && this.exists ) {
  445. this.each(function (elem) {
  446. if (valueIsValid) {
  447. elem.setAttribute(name, value);
  448. } else {
  449. ret += elem.getAttribute(name) || '';
  450. }
  451. });
  452. }
  453.  
  454. return valueIsValid ? this : ret;
  455. },
  456.  
  457. before : function () {
  458. var newElementsArray = doElementOperationOnEach.call(this, CFL.toArray(arguments), function (baseElement, newElement) {
  459. var parent = baseElement.parentNode;
  460.  
  461. // add the newElement before the current element
  462. if (parent) {
  463. parent.insertBefore(newElement, baseElement);
  464. }
  465. });
  466.  
  467. return CFL(newElementsArray);
  468. },
  469.  
  470. center : function () {
  471. return this.each(function (thisElement) {
  472. thisElement = CFL(thisElement);
  473. thisElement.css('position', 'fixed');
  474. thisElement.css('top', Math.floor( (window.innerHeight - thisElement.height) / 2 ) + 'px');
  475. thisElement.css('left', Math.floor( (window.innerWidth - thisElement.width) / 2 ) + 'px');
  476. });
  477. },
  478.  
  479. clone : function () {
  480. var clonedElements = core.map.call(this, cloneElement); // variable for clarity
  481. return CFL(clonedElements);
  482. },
  483.  
  484. css : function (name, value) {
  485. if (typeof name === 'string') {
  486. // convert the hyphenated string to camel-case
  487. name = toCamelCase(name);
  488.  
  489. if (typeof value === 'string') {
  490. return this.each(function (thisElement) {
  491. if (name in thisElement.style) {
  492. thisElement.style[name] = value;
  493. }
  494. });
  495. }
  496.  
  497. return core.map.call(this, pluck, 'style.' + name).join('');
  498. } else {
  499. return error('.css() was not passed a string for the first argument.');
  500. }
  501. },
  502.  
  503. each : function (fn, oThis) {
  504. if (this.exists) {
  505. CFL.each(this, fn, oThis);
  506. }
  507.  
  508. return this;
  509. },
  510.  
  511. get exists() {
  512. return this.length > 0 && this[0] != null;
  513. },
  514.  
  515. filter : function (selector) {
  516. var newElementsArray = [];
  517.  
  518. if (typeof selector === 'string') {
  519. this.each(function (thisElement) {
  520. if ( matchesSelector(thisElement, selector) ) {
  521. newElementsArray.push(thisElement);
  522. }
  523. });
  524. }
  525.  
  526. // returns an empty CFL object if no elements are matched
  527. return CFL(newElementsArray);
  528. },
  529.  
  530. find : function (selector) {
  531. var arrayOfMatchesArrays = core.map.call(this, function (thisElement) {
  532. var matches = thisElement.querySelectorAll(selector);
  533. return CFL.toArray(matches);
  534. });
  535. var singleArrayOfMatches = arrayOfMatchesArrays.length > 0 ?
  536. core.reduce.call(arrayOfMatchesArrays, function (a, b) {
  537. return core.concat.call(a, b);
  538. }) : [];
  539.  
  540. return CFL(singleArrayOfMatches);
  541. },
  542.  
  543. first : function () {
  544. return this.get(0);
  545. },
  546.  
  547. focus : function () {
  548. var firstElement;
  549.  
  550. if (this.exists) {
  551. firstElement = this[0];
  552. if (typeof firstElement.focus === 'function') {
  553. firstElement.focus();
  554. }
  555. }
  556. },
  557.  
  558. get : function (index) {
  559. index = index === 'first' ? 0 : index === 'last' ? -1 : parseInt(index, 10);
  560.  
  561. if ( !isNaN(index) ) {
  562. return CFL( index < 0 ? this[this.length + index] : this[index] );
  563. }
  564.  
  565. return CFL.toArray(this);
  566. },
  567.  
  568. get height() {
  569. var arrayOfElemHeights = core.map.call(this, pluck, 'offsetHeight');
  570. return core.reduce.call(arrayOfElemHeights, sum);
  571. },
  572.  
  573. has : function (selector) {
  574. var newElementsArray = [];
  575.  
  576. if ( typeof selector === 'string' && selector.match(rSelector) ) {
  577. this.each(function (thisElement) {
  578. if ( CFL(selector, thisElement).exists ) {
  579. newElementsArray.push(thisElement);
  580. }
  581. });
  582. }
  583.  
  584. return CFL(newElementsArray);
  585. },
  586.  
  587. hide : function () {
  588. return this.css('display', 'none');
  589. },
  590.  
  591. /*
  592. get inView(passedContainer) {
  593. var isInView = false;
  594.  
  595. this.each(function (thisElement) {
  596. var container = passedContainer || thisElement.parentNode;
  597. var visible = !!( (container.scrollTop + container.offsetHeight) >= thisElement.offsetTop &&
  598. (container.scrollTop - thisElement.offsetHeight) <= thisElement.offsetTop );
  599.  
  600. if (visible) {
  601. isInView = true;
  602. return 'stop';
  603. }
  604. });
  605.  
  606. return isInView;
  607. },
  608. */
  609.  
  610. is : function (selector) {
  611. for (var i = 0; i < this.length; i += 1) {
  612. if ( matchesSelector(this[i], selector) ) {
  613. return true;
  614. }
  615. }
  616.  
  617. return false;
  618. },
  619.  
  620. isnt : function (selector) {
  621. return !this.is(selector);
  622. },
  623.  
  624. last : function (selector) {
  625. return this.get(-1);
  626. },
  627.  
  628. next : function (selector) {
  629. return CFL( getEachElements(this, selector, 'nextSibling', 1) );
  630. },
  631.  
  632. not : function (selector) {
  633. var newElementsArray = [];
  634.  
  635. if ( typeof selector === 'string' && selector.match(rSelector) ) {
  636. this.each(function (thisElement) {
  637. if ( CFL(thisElement).isnt(selector) ) {
  638. newElementsArray.push(thisElement);
  639. }
  640. });
  641. }
  642.  
  643. return CFL(newElementsArray);
  644. },
  645.  
  646. parent : function (selector) {
  647. return CFL( getEachElements(this, selector, 'parentNode', 1) );
  648. },
  649.  
  650. prepend : function () {
  651. var newElementsArray = doElementOperationOnEach.call(this, CFL.toArray(arguments), function (baseElement, newElement) {
  652. var firstChild = baseElement.firstChild;
  653.  
  654. if (firstChild) {
  655. baseElement.insertBefore(newElement, firstChild);
  656. }
  657. });
  658.  
  659. return CFL(newElementsArray);
  660. },
  661.  
  662. prev : function (selector) {
  663. return CFL( getEachElements(this, selector, 'previousSibling', 1) );
  664. },
  665.  
  666. prop : function (name, value) {
  667. var valueIsValid = value != null, ret;
  668.  
  669. if (typeof name === 'string' && this.exists) {
  670. this.each(function (thisElement) {
  671. if (valueIsValid) {
  672. thisElement[name] = value;
  673. } else {
  674. if (typeof ret === 'undefined') {
  675. ret = thisElement[name];
  676. } else {
  677. ret += thisElement[name];
  678. }
  679. }
  680. });
  681. }
  682.  
  683. return valueIsValid ? this : ret;
  684. },
  685.  
  686. raw : function () {
  687. return core.slice.call(this, 0);
  688. },
  689.  
  690. remove : function () {
  691. return this.each(function (element) {
  692. var parent = element.parentNode;
  693.  
  694. if (element && parent) {
  695. parent.removeChild(element);
  696. }
  697. });
  698. },
  699.  
  700. removeAttribute : function (attributeName) {
  701. if (typeof attributeName === 'string') {
  702. return this.each(function (thisElement) {
  703. thisElement.removeAttribute(attributeName);
  704. });
  705. } else {
  706. return error('.removeAttribute() was not passed a string.');
  707. }
  708. },
  709.  
  710. removeEvent : function (type) {
  711. if (typeof type === 'string') {
  712. return this.each(function (thisElement) {
  713. CFL.removeEvent(thisElement, type);
  714. });
  715. } else {
  716. return error('.removeEvent() was not passed a string.');
  717. }
  718. },
  719.  
  720. replace : function () {
  721. var newElementsArray = doElementOperationOnEach.call(this, CFL.toArray(arguments), function (baseElement, newElement) {
  722. var parent = baseElement.parentNode;
  723.  
  724. if (parent) {
  725. parent.replaceChild(newElement, baseElement);
  726. }
  727. });
  728.  
  729. return CFL(newElementsArray);
  730. },
  731.  
  732. show : function (value) {
  733. value = typeof value === 'string' ? value : 'inline';
  734. return this.css('display', value);
  735. },
  736.  
  737. text : function (passedText, append) {
  738. // convert a number to a string
  739. if ( typeof passedText === 'number' && !isNaN(passedText) && isFinite(passedText) ) {
  740. passedText += '';
  741. }
  742.  
  743. // handle setting text
  744. if (typeof passedText === 'string') {
  745. if (append !== true) {
  746. this.each(function (thisElement) {
  747. CFL('.//text()', thisElement).each(function (textNode) {
  748. textNode.data = '';
  749. });
  750. });
  751. }
  752.  
  753. this.append('text', passedText);
  754. return this;
  755. }
  756.  
  757. // handle getting text
  758. return core.reduce.call(this, function (curValue, nextElement) {
  759. return curValue + nextElement.textContent;
  760. }, '');
  761. },
  762.  
  763. toggle : function () {
  764. return this.each(function (thisElement) {
  765. thisElement = CFL(thisElement);
  766.  
  767. if (thisElement.visible) {
  768. thisElement.hide();
  769. } else {
  770. thisElement.show();
  771. }
  772. });
  773. },
  774.  
  775. value : function (passedValue) {
  776. var elem = this[0],
  777. tagName = elem && elem.tagName || '',
  778. selectedOptions = [],
  779. rInputTypeBlacklist = /button|checkbox|file|image|radio|reset|submit/,
  780. passedValueType = CFL.typeOf(passedValue);
  781.  
  782. if (passedValue == null) {
  783. // no arguments were passed, return a value
  784. if (tagName === 'SELECT') {
  785. if ( elem.hasAttribute('multiple') ) {
  786. CFL.each(elem.options, function (thisOption) {
  787. if (thisOption.selected) {
  788. selectedOptions.push(thisOption.value);
  789. }
  790. });
  791.  
  792. return selectedOptions;
  793. } else {
  794. return elem.options[elem.selectedIndex].value;
  795. }
  796. } else if ( tagName === 'INPUT' && !elem.type.match(rInputTypeBlacklist) ) {
  797. return elem.value;
  798. }
  799. if (tagName === 'TEXTAREA') {
  800. return elem.value;
  801. }
  802. } else {
  803. // an argument was passed, set the value on each element
  804. return this.each(function (thisElement) {
  805. var tagName = thisElement.tagName;
  806.  
  807. if (tagName === 'SELECT') {
  808. if (thisElement.hasAttribute('multiple') && passedValueType === 'array') {
  809. CFL.each(thisElement.options, function (thisOption) {
  810. CFL.each(passedValue, function (thisPassedValue) {
  811. if (thisOption.value == thisPassedValue) {
  812. thisOption.selected = true;
  813. return 'stop';
  814. } else {
  815. thisOption.selected = false;
  816. }
  817. });
  818. });
  819. } else {
  820. CFL.each(thisElement.options, function (thisOption) {
  821. thisOption.selected = thisOption.value == passedValue;
  822. });
  823. }
  824. } else if (tagName === 'INPUT') {
  825. if ( !thisElement.type.match(rInputTypeBlacklist) ) {
  826. thisElement.value = passedValue;
  827. } else if (thisElement.type === 'checkbox' || thisElement.type === 'radio') {
  828. if (passedValueType === 'array') {
  829. CFL.each(passedValue, function (thisPassedValue) {
  830. if (thisElement.value == thisPassedValue) {
  831. thisElement.checked = true;
  832. return 'stop';
  833. } else {
  834. thisElement.checked = false;
  835. }
  836. });
  837. } else if (thisElement.value == passedValue) {
  838. thisElement.checked = true;
  839. }
  840. }
  841. } else if (tagName === 'TEXTAREA') {
  842. thisElement.value = passedValue;
  843. }
  844. });
  845. }
  846.  
  847. return null;
  848. },
  849.  
  850. get visible() {
  851. return Math.max(this.width, this.height) > 0;
  852. },
  853.  
  854. get width() {
  855. var arrayOfElemHeights = core.map.call(this, pluck, 'offsetWidth');
  856. return core.reduce.call(arrayOfElemHeights, sum);
  857. },
  858. };
  859.  
  860. // give the init function the CFL prototype for later instantiation
  861. CFL.fn.init.prototype = CFL.fn;
  862.  
  863. // extend method. can extend any object it's run upon
  864. CFL.fn.extend = CFL.extend = function (obj) {
  865. var name, copy;
  866.  
  867. for (name in obj) {
  868. copy = obj[name];
  869.  
  870. if ( !core.hasOwnProperty.call(this, name) && typeof copy !== 'undefined' ) {
  871. this[name] = copy;
  872. }
  873. }
  874. };
  875.  
  876. // --- STARTLING LINE FOR THE DIRECT CFL METHODS
  877. CFL.extend({
  878. addEvent : function addEvent(thisElement, type, fn) {
  879. if (thisElement != null && typeof type === 'string' && typeof fn === 'function') {
  880. if (typeof thisElement.addEventListener === 'function') {
  881. thisElement.addEventListener(type, fn, false);
  882. } else if (typeof thisElement.attachEvent === 'function') {
  883. type = 'on' + type;
  884. thisElement.attachEvent(type, fn);
  885. } else {
  886. return;
  887. }
  888.  
  889. handlers.add(thisElement, type, fn);
  890. }
  891. },
  892.  
  893. addScript : function addScript(contents, id, node) {
  894. var newElement = document.createElement('script');
  895. newElement.id = id || ( 'cfl-script-' + CFL.random(999) );
  896. newElement.innerHTML = contents;
  897.  
  898. node = node || document.head || document.querySelector('html > head');
  899. node.appendChild(newElement);
  900.  
  901. return {
  902. remove : function () {
  903. node.removeChild(newElement);
  904. }
  905. };
  906. },
  907.  
  908. addStyle : function addStyle(css, id, node) {
  909. id = id || ( 'cfl-style-' + CFL.random(999) );
  910. node = node || document.head || document.querySelector('html > head');
  911. if (node) {
  912. node.appendChild(
  913. CFL.create('style', {id : id, type : 'text/css'}, [ CFL.create('text', css) ] )
  914. );
  915. }
  916. },
  917.  
  918. alias : function alias(newAlias) {
  919. if (typeof newAlias === 'string' && newAlias.match(rValidVarname) && typeof window[newAlias] === 'undefined') {
  920. window[newAlias] = CFL;
  921. }
  922. },
  923.  
  924. clearInterval : function clearInterval(index) {
  925. if (typeof index === 'number' && index < intervals.length) {
  926. window.clearTimeout( intervals[index] );
  927. intervals[index] = null;
  928. }
  929. },
  930.  
  931. create : function create(elementName, descObj, kidsArray) {
  932. var argsLength = arguments.length,
  933. typeValue, prop, val, HTMLholder, ret, i;
  934.  
  935. if (argsLength === 2 && elementName === 'text' && typeof descObj === 'string') {
  936. // handle text node creation
  937. return document.createTextNode(descObj);
  938. } else if ( argsLength === 1 && typeof elementName === 'string' && elementName.match(rHTML) ) {
  939. // handle HTML strings
  940.  
  941. // take the HTML string and put it inside a div
  942. HTMLholder = document.createElement('div');
  943. HTMLholder.innerHTML = elementName;
  944.  
  945. // add each childNode to an array to return
  946. ret = [];
  947. ret.push.apply(ret, HTMLholder.childNodes);
  948. return ret.length > 0 ? (ret.length === 1 ? ret[0] : ret) : null;
  949. } else if (argsLength > 1 && typeof elementName === 'string' && typeof descObj === 'object') {
  950. // handle the normal element name and descriptor object
  951. ret = document.createElement(elementName + '');
  952.  
  953. for (prop in descObj) {
  954. if ( core.hasOwnProperty.call(descObj, prop) ) {
  955. val = descObj[prop];
  956. if (prop.indexOf('on') === 0 && typeof val === 'function') {
  957. CFL.addEvent(ret, prop.substring(2), val);
  958. } else if ( prop !== 'style' && prop !== 'class' && prop in ret && typeof ret[prop] !== 'undefined' ) {
  959. ret[prop] = val;
  960. } else {
  961. ret.setAttribute(prop, val);
  962. }
  963. }
  964. }
  965.  
  966. if (CFL.typeOf(kidsArray) === 'array') {
  967. CFL.each(kidsArray, function (kid) {
  968. var val, item, i;
  969.  
  970. if (typeof kid === 'string') {
  971. val = CFL.create(kid)
  972.  
  973. if (CFL.typeOf(val) === 'array') {
  974. for (i = 0; i < val.length; i += 1) {
  975. ret.appendChild( val[i] );
  976. }
  977. } else if (CFL.typeOf(kid) === 'element') {
  978. ret.appendChild(kid);
  979. }
  980. } else if (CFL.typeOf(kid) === 'element') {
  981. ret.appendChild(kid);
  982. }
  983. });
  984. }
  985.  
  986. return ret;
  987. } else if (argsLength === 1 && CFL.typeOf(elementName) === 'element') {
  988. // handle an element
  989. return elementName;
  990. }
  991. },
  992.  
  993. each : function each(passedArray, fn, oThis) {
  994. var isOthisUndefined = typeof oThis !== 'undefined',
  995. index, len, otherThis, value;
  996.  
  997. for (index = 0; index < passedArray.length; index += 1) {
  998. value = passedArray[index];
  999. otherThis = isOthisUndefined ? oThis : value;
  1000. if (fn.call(otherThis, value, index, passedArray) === 'stop') {
  1001. break;
  1002. }
  1003. }
  1004. },
  1005.  
  1006. loop : function loop(maxIterations, fn) {
  1007. var args = CFL.toArray(arguments), i;
  1008.  
  1009. if (typeof maxIterations === 'number' && maxIterations > 0 && typeof fn === 'function') {
  1010. args = args.slice(2);
  1011. for (i = 0; i < maxIterations; i += 1) {
  1012. fn.apply(null, args);
  1013. }
  1014. }
  1015. },
  1016.  
  1017. random : function random(maxInteger, minInteger) {
  1018. var rand = -1;
  1019.  
  1020. while (rand < 0 || rand > maxInteger || rand < minInteger) {
  1021. rand = Math.floor( Math.random() * maxInteger ) + Math.round( Math.random() );
  1022. }
  1023.  
  1024. return rand;
  1025. },
  1026.  
  1027. removeEvent : function removeEvent(thisElement, type) {
  1028. CFL.each(handlers.get(thisElement, type), function (thisEventObj) {
  1029. if (typeof thisElement.removeEventListener === 'function') {
  1030. thisEventObj.element.removeEventListener(thisEventObj.type, thisEventObj.fn, false);
  1031. } else if (typeof thisElement.detachEvent === 'function') {
  1032. type = 'on' + type;
  1033. thisEventObj.element.detachEvent(thisEventObj.type, thisEventObj.fn);
  1034. }
  1035.  
  1036. handlers.remove(thisElement, type);
  1037. });
  1038. },
  1039.  
  1040. runAt : function runAt(state, func, oThis) {
  1041. var args = CFL.toArray(arguments), intv,
  1042.  
  1043. // compose a list of the 4 states, to use .indexOf() upon later
  1044. states = ['uninitialized', 'loading', 'interactive', 'complete'],
  1045.  
  1046. // in-case they pass [start/end] instead of [loading/complete]
  1047. state = state.replace('start', 'loading').replace('end', 'complete');
  1048.  
  1049. // this will run their function with the specified arguments, if any,
  1050. // and a custom 'this' value, if specified
  1051. function runFunc() {
  1052. func.apply( oThis, args.slice(3) );
  1053. }
  1054.  
  1055. // this will run on each state change if the specified state is
  1056. // not achieved yet. it will run their function when it is achieved
  1057. function checkState() {
  1058. if (document.readyState === state) {
  1059. runFunc();
  1060. CFL.clearInterval(intv);
  1061. }
  1062. }
  1063.  
  1064. if ( core.arr_indexOf.call(states, state) <= core.arr_indexOf.call(states, document.readyState) ) {
  1065. // we are at, or have missed, our desired state
  1066. // run the specified function
  1067. runFunc();
  1068. } else {
  1069. intv = CFL.setInterval(checkState, 200);
  1070. }
  1071. },
  1072.  
  1073. setInterval : function setInterval(func, delay) {
  1074. var index = intervals.length,
  1075. delay_orig = delay,
  1076. count = 1, startTime;
  1077.  
  1078. function doRe(func, delay) {
  1079. return window.setTimeout(function () {
  1080. // drift accomodation
  1081. var difference = ( new Date().getTime() ) - startTime,
  1082. correctTime = delay_orig * count,
  1083. drift = difference - correctTime;
  1084.  
  1085. // execute the function before setting a new timeout
  1086. func.call(null);
  1087.  
  1088. // fix for when a timeout takes longer than double the original delay time to execute
  1089. if (drift > delay_orig) {
  1090. drift = delay_orig;
  1091. }
  1092.  
  1093. // save the reference of the new timeout in our 'intervals' stack
  1094. if (intervals[index] !== null) {
  1095. intervals[index] = doRe(func, delay_orig - drift);
  1096. }
  1097.  
  1098. count += 1;
  1099. }, delay);
  1100. }
  1101.  
  1102. startTime = new Date().getTime();
  1103. intervals[index] = doRe(func, delay_orig);
  1104.  
  1105. return index;
  1106. },
  1107.  
  1108. toArray : function toArray(arr) {
  1109. var newArr = [], // new array to store the values into
  1110. len = arr.length || arr.snapshotLength,
  1111. item, i;
  1112.  
  1113. if (typeof len === 'number' && len > 0) {
  1114. if (typeof arr.snapshotItem === 'function') {
  1115. for (i = 0; ( item = arr.snapshotItem(i) ); i += 1) {
  1116. newArr.push(item);
  1117. }
  1118. } else {
  1119. // if the specified 'list' is array-like, use slice on it
  1120. // to convert it to an array
  1121. newArr = core.slice.call(arr, 0);
  1122. }
  1123. }
  1124.  
  1125. return newArr;
  1126. },
  1127.  
  1128. toString : function toString(item) {
  1129. var key, value, values = [];
  1130.  
  1131. function stringifyValue(val) {
  1132. var typeOfVal = CFL.typeOf(val),
  1133. toStringValue = core.toString.call(val);
  1134.  
  1135. if (typeOfVal === 'null' || typeOfVal === 'undefined') {
  1136. val = typeOfVal;
  1137. } else if (typeof val === 'string') {
  1138. if (val.length > 15) { // truncate strings longer than 15 characters
  1139. val = '"' + val.substring(0, 12) + '"...';
  1140. } else {
  1141. val = '"' + val + '"';
  1142. }
  1143. } else if (typeOfVal === 'function') {
  1144. val = val.toString().substring(0, 20);
  1145. } else if (typeOfVal !== 'number' && typeOfVal !== 'boolean') {
  1146. val = toStringValue;
  1147. }
  1148.  
  1149. return val;
  1150. }
  1151.  
  1152. switch( CFL.typeOf(item) ) {
  1153. case 'object': {
  1154. for (key in item) {
  1155. if ( item.hasOwnProperty(key) ) {
  1156. value = stringifyValue( item[key] );
  1157. values.push( '"' + key + '" : ' + value );
  1158. }
  1159. }
  1160. return '{\n ' + values.join(',\n ') + '\n}';
  1161. }
  1162. // --------------------------------------
  1163. case 'array': {
  1164. item = core.map.call(item, function (thisValue) {
  1165. return stringifyValue(thisValue);
  1166. });
  1167. return '[\n ' + item.join(',\n ') + '\n]';
  1168. }
  1169. // --------------------------------------
  1170. case 'string': {
  1171. return '"' + item + '"';
  1172. }
  1173. // --------------------------------------
  1174. case 'number': {
  1175. item = parseInt(item, 10);
  1176. if ( isNaN(item) ) { // no ternary operator, for clarity
  1177. return 'NaN';
  1178. } else {
  1179. return item.toString();
  1180. }
  1181. }
  1182. // --------------------------------------
  1183. case 'regexp': {
  1184. if (item.toString().length <= 20) {
  1185. item.toString();
  1186. } else {
  1187. return '[object RegExp]';
  1188. }
  1189. }
  1190. // --------------------------------------
  1191. case 'function': case 'boolean': {
  1192. return item.toString();
  1193. }
  1194. // --------------------------------------
  1195. case 'null': {
  1196. return 'null';
  1197. }
  1198. // --------------------------------------
  1199. case 'undefined': {
  1200. return 'undefined';
  1201. }
  1202. // --------------------------------------
  1203. default: {
  1204. return core.toString.call(item);
  1205. }
  1206. }
  1207. },
  1208.  
  1209. // typeOf by Douglas Crockford. modified by CodeFelony
  1210. typeOf : function typeOf(value) {
  1211. var s = typeof value,
  1212. ostr = core.toString.call(value);
  1213.  
  1214. if (s === 'object' || s === 'function') {
  1215. if (value) {
  1216. if (ostr === '[object Array]') {
  1217. s = 'array';
  1218. } else if ( ostr === '[object Text]' || ostr.match(rElementObject) ) {
  1219. s = 'element';
  1220. } else if (ostr === '[object HTMLCollection]') {
  1221. s = 'collection';
  1222. } else if (ostr === '[object NodeList]') {
  1223. s = 'nodelist';
  1224. } else if (ostr === '[object Arguments]') {
  1225. s = 'arguments';
  1226. } else if (ostr === '[object RegExp]') {
  1227. s = 'regexp';
  1228. }
  1229. } else {
  1230. s = 'null';
  1231. }
  1232. }
  1233. return s;
  1234. },
  1235.  
  1236. waitFor : function waitFor(info) {
  1237. var verifier = function () { return true; },
  1238. done = info ? info.done : null,
  1239. i, selector, context, waitForInterval;
  1240.  
  1241. if (info == null || typeof done !== 'function') { return; }
  1242.  
  1243. switch ( CFL.typeOf(info.selector) ) {
  1244. case 'string': case 'element': case 'array': {
  1245. selector = info.selector;
  1246. break;
  1247. }
  1248. default: {
  1249. return error('Invalid selector passed to CFL.waitFor()');
  1250. }
  1251. }
  1252.  
  1253. switch ( CFL.typeOf(info.context) ) {
  1254. case 'string': case 'element': case 'array': {
  1255. context = info.context;
  1256. }
  1257. }
  1258.  
  1259. if (typeof info.verifier === 'function' && info.verifier.toString().indexOf('return ') !== -1) {
  1260. verifier = info.verifier;
  1261. }
  1262.  
  1263. function clear() {
  1264. CFL.clearInterval(waitForInterval);
  1265. }
  1266.  
  1267. function check() {
  1268. var elem = CFL(selector, context);
  1269.  
  1270. if (elem.exists && verifier(elem) === true) {
  1271. done(elem);
  1272. return clear();
  1273. }
  1274.  
  1275. if (i >= 150) { // check for 30 seconds max
  1276. return clear();
  1277. }
  1278.  
  1279. i += 1;
  1280. }
  1281.  
  1282. waitForInterval = CFL.setInterval(check, 200);
  1283. },
  1284.  
  1285. xpath : function xpath(obj) {
  1286. var type = obj.type || 7,
  1287. types = {
  1288. '1' : 'numberValue',
  1289. '2' : 'stringValue',
  1290. '3' : 'booleanValue',
  1291. '8' : 'singleNodeValue',
  1292. '9' : 'singleNodeValue'
  1293. },
  1294. expression = obj.expression,
  1295. context = obj.context || document,
  1296. doc = document, xp;
  1297.  
  1298. if (typeof context.evaluate === 'function') {
  1299. doc = context;
  1300. } else if (typeof context.ownerDocument.evaluate === 'function') {
  1301. doc = context.ownerDocument;
  1302. }
  1303.  
  1304. xp = doc.evaluate(expression, context, null, type, null);
  1305.  
  1306. if (!expression) {
  1307. error('An expression must be supplied for CFL.xpath()');
  1308. return null;
  1309. }
  1310.  
  1311. if ( types[type] ) {
  1312. return xp[ types[ type ] ];
  1313. } else {
  1314. return CFL.toArray(xp);
  1315. }
  1316. }
  1317. });
  1318.  
  1319. // assign CFL to the window object
  1320. if (typeof window.CFL !== 'function') {
  1321. // if it doesn't exist, just add it
  1322. window.CFL = CFL;
  1323. window._J = CFL;
  1324. } else if (window.CFL.fn && window.CFL.fn.version) {
  1325. // if it already exists, only replace it with a newer, yet
  1326. // backwards compatible version (check for same major version)
  1327. if ( window.CFL.fn.version.substring( 0, window.CFL.fn.version.indexOf('.') )
  1328. === version.substring( 0, version.indexOf('.') ) ) {
  1329. window.CFL = CFL;
  1330. window._J = CFL;
  1331. }
  1332. }
  1333.  
  1334. // just for testing purposes
  1335. // unsafeWindow.CFL = unsafeWindow._J = CFL;
  1336.  
  1337. }(window));
  1338.  
  1339.  
  1340.  
  1341. // CFL test button
  1342. // use it to test code on user click (non-automatic)
  1343. /*
  1344. (function () {
  1345. var mo = new MutationObserver(function (mutations) {
  1346. mutations.forEach(function (mutation) {
  1347. var target = mutation.target;
  1348.  
  1349. if (mutation.attributeName === 'value' && target.value !== 'Run CFL test') {
  1350. target.value = 'Run CFL test';
  1351. }
  1352. });
  1353. });
  1354.  
  1355. CFL(document.body).append(
  1356. 'input',
  1357. {
  1358. id : 'cfl_user_test',
  1359. type : 'button',
  1360. value : 'Run CFL test',
  1361. style : 'display: block; position: fixed; top: 4px; right: 4px; z-index: 999999; padding: 2px 14px; font-size: 11pt; font-family: Arial, Verdana;',
  1362. onclick : function () {
  1363.  
  1364. // ---- ENTER ONCLICK CODE HERE ----
  1365. window.setTimeout(function () {
  1366. CFL(document.body).append('<div id="waitForTest">I\'m a CFL.waitFor() test DIV!</div>');
  1367. }, 1500);
  1368.  
  1369. CFL.waitFor({
  1370. selector : '#waitForTest',
  1371. done : function (elem) {
  1372. alert('#waitForTest is loaded!');
  1373. }
  1374. });
  1375. // ---------------------------------
  1376. }
  1377. }
  1378. );
  1379.  
  1380. mo.observe( CFL('#cfl_user_test')[0], { attributes : true } );
  1381. }());
  1382. */
  1383.