vanilla-lib

Vanilla JS library

目前為 2019-11-03 提交的版本,檢視 最新版本

此腳本不應該直接安裝,它是一個供其他腳本使用的函式庫。欲使用本函式庫,請在腳本 metadata 寫上: // @require https://update.cn-greasyfork.org/scripts/369430/746399/vanilla-lib.js

  1. function VanillaLib( ) {
  2. 'use strict';
  3. let self = { version:'1.2.181103.1315' },
  4. undefined; // ensure an 'undefined' reference
  5.  
  6. // Logging related
  7. self.logging = true;
  8. self.log = function( ) { return ! self.logging ? false : console.debug.apply(console, arguments); };
  9. self.logGroup = function( ) { return ! self.logging ? false : console.groupCollapsed.apply(console, arguments); };
  10. self.logEnd = function( ) { return ! self.logging ? false : console.groupEnd.apply(console, arguments); };
  11. self.time = function( ) { return ! self.logging ? false : console.time.apply(console, arguments); };
  12. self.timeEnd = function( ) { return ! self.logging ? false : console.timeEnd.apply(console, arguments); };
  13. self.warn = function( ) { return ! self.logging ? false : console.warn.apply(console, arguments); };
  14. // Informative functionality
  15. self.isobj = ( expr,type ) => ( 'object' === typeof expr && ( ! type || null !== expr && ( true === type ||
  16. !! expr.constructor && type === ( self.isstr(type) ? expr.constructor.name : expr.constructor ) ) ) );
  17. self.ownsIt = ( obj,prop ) => ( !! prop && self.isobj(obj, true) && obj.hasOwnProperty(prop) );
  18. self.hasval = expr => ( null !== expr && ! self.ndef(expr) );
  19. self.isbool = expr => ( 'boolean' === typeof expr );
  20. self.ifnan = ( expr,value ) => ( isNaN(expr) ? value : expr );
  21. self.ifndef = ( expr,value ) => ( self.ndef(expr) ? value : expr );
  22. self.ispojo = expr => self.isobj(expr, Object);
  23. self.isarr = expr => self.isobj(expr, Array);
  24. self.isnum = expr => ( 'number' === typeof expr );
  25. self.isstr = expr => ( 'string' === typeof expr );
  26. self.isfn = expr => ( 'function' === typeof expr );
  27. self.defn = expr => ( 'undefined' !== typeof expr );
  28. self.ndef = expr => ( 'undefined' === typeof expr );
  29. // Miscelaneous
  30. self.mapFlat = ( array,func ) => array.map( x => func(x) ).reduce( (a,b) => a.concat(b) );
  31. self.test = ( expr,func,other ) => ( !! expr ? func(expr) : self.isfn(other) ? other(expr) : other );
  32. // DOM related
  33. self.parenth = ( elem,nth ) => self.traverse(elem, self.ifndef(nth, 1), 0);
  34. self.html = ( elem,val ) => self.test(elem, el => self.ndef(val) ? el.innerHTML : (el.innerHTML = val) );
  35. self.text = ( elem,val ) => self.test(elem, el => self.ndef(val) ? el.innerText : (el.innerText = val) );
  36. self.$$ = ( sel,elem ) => Array.slice((elem || document).querySelectorAll(sel));
  37. self.$ = ( sel,elem ) => (elem || document).querySelector(sel);
  38. // Number related
  39. self.aggRate = ( amnt,rate,times ) => ( times < 1 ? amnt : self.aggRate(amnt * rate, rate, times - 1) );
  40. self.between = ( value,from,to,open ) => ( from > to ? self.between(value, to, from, open)
  41. : open ? from < value && value < to : from <= value && value <= to );
  42. self.toDec = expr => ( Math.round(parseFloat((expr +'').replace(/\$|,/g, '')) * 100) / 100 );
  43. // Date/Time related
  44. self.secondsIn = ( from,to,other ) => self.ifnan((to - from) / 1000, self.ifndef(other, NaN));
  45. self.minutesIn = ( from,to,other ) => self.ifnan((to - from) / 60000, self.ifndef(other, NaN));
  46. self.hoursIn = ( from,to,other ) => self.ifnan((to - from) / 3600000, self.ifndef(other, NaN));
  47. self.daysIn = ( from,to,other ) => self.ifnan((to - from) / 86400000, self.ifndef(other, NaN));
  48. self.secondsSince = ( from,other ) => self.secondsIn(from, Date.now(), other);
  49. self.minutesSince = ( from,other ) => self.minutesIn(from, Date.now(), other);
  50. self.hoursSince = ( from,other ) => self.hoursIn(from, Date.now(), other);
  51. self.daysSince = ( from,other ) => self.daysIn(from, Date.now(), other);
  52.  
  53.  
  54. self.addClass = function( element, name ) {
  55. if ( !! element && !! name ) {
  56. if ( self.isarr(element) ) {
  57. return element.map( elem => self.addClass(elem, name) );
  58. }
  59.  
  60. // ToDo: Use .classList if available
  61. name = ( self.isarr(name) ? name : name.split(',') );
  62. name = name.map( nm => nm.trim() )
  63. .filter( nm => ! element.classList.contains(nm) );
  64. element.className = (element.className +' '+ name.join(' ')).trim();
  65. return true;
  66. }
  67. return false;
  68. };
  69.  
  70. self.appendTo = function( element, parent, reference ) {
  71. if ( self.isarr(element) ) {
  72. return element.map( elem => self.appendTo(elem, parent, reference) );
  73. }
  74.  
  75. if ( !! reference ) {
  76. parent = reference.parentNode;
  77. reference = reference.nextSibling;
  78. }
  79.  
  80. if ( !! reference ) {
  81. return self.prependTo(element, parent, reference);
  82. } else if ( !! parent ) {
  83. parent.append(element);
  84. } else {
  85. self.warn('*** appendTo() could not add element: No parent or reference element provided');
  86. }
  87.  
  88. return element;
  89. };
  90.  
  91. self.attr = function( element, name, value ) {
  92. if ( !! element ) {
  93. if ( self.isarr(element) ) {
  94. return element.map( elem => self.attr(elem, name, value) );
  95. }
  96.  
  97. return self.keysAndValues(name, value, ( n,v ) => {
  98. return ( self.hasval(v) ? element.setAttribute(n, v)
  99. : null === v ? element.removeAttribute(n) : element.getAttribute(n) );
  100. } );
  101. }
  102. return element;
  103. };
  104.  
  105. self.choose = function( index, values ) {
  106. return Array.slice(arguments)[ index ];
  107. }
  108.  
  109. self.create = function( html, containerType ) {
  110. let container = null,
  111. result = null,
  112. attrs, style;
  113.  
  114. if ( self.isobj(containerType) ) {
  115. attrs = containerType.attrs;
  116. style = containerType.style;
  117. containerType = containerType.container;
  118. }
  119.  
  120. containerType = containerType || 'div';
  121. create[ containerType ] =
  122. container = self.create[ containerType ] || document.createElement(containerType);
  123. container.innerHTML = html;
  124. result = Array.slice(container.childNodes)
  125. .map( elem => (elem.remove(), elem) );
  126.  
  127. if ( !! attrs ) {
  128. self.attr(result, attrs);
  129. }
  130. if ( !! style ) {
  131. self.css(result, style);
  132. }
  133.  
  134. if ( 1 == result.length ) {
  135. result = result[ 0 ];
  136. }
  137. return result;
  138. };
  139.  
  140. // Create sandbox, optionally adding it to `cache` as (read-only) `property` (or `_sandbox`, if missing)
  141. self.createSandbox = function( cache, property ) {
  142. const frame = document.createElement('iframe');
  143. frame.src = 'about:blank', frame.style.display = 'none';
  144. document.body.appendChild(frame);
  145.  
  146. const context = frame.contentWindow;
  147. !! cache && Object.defineProperty(cache, (property || '_sandbox'), { value:context, enumerable:false, writable:false, configurable:false });
  148.  
  149. document.body.removeChild(frame);
  150. return context;
  151. };
  152.  
  153. self.createXHR = function( ) {
  154. let xhr = new XMLHttpRequest( );
  155. xhr.onabort = function( ev, xhr ) { self.log('XHR Abort:', ev, xhr, this); };
  156. xhr.onerror = function( ev, xhr ) { self.log('XHR Error:', ev, xhr, this); };
  157. xhr.onload = function( ev, xhr ) { self.log('XHR Load:', ev, xhr, this); };
  158. self.on(xhr, {
  159. 'abort': function( ev ) { self.isfn(this.onabort) && this.onabort(ev, this); },
  160. 'error': function( ev ) { self.isfn(this.onerror) && this.onerror(ev, this); },
  161. 'load': function( ev ) { self.isfn(this.onload) && this.onload(ev, this); },
  162. });
  163. return xhr;
  164. };
  165.  
  166. self.css = function( element, key, value ) {
  167. if ( isarr(element) ) {
  168. return element.map( elem => self.css(elem, key, value) );
  169. }
  170.  
  171. keysAndValues(key, value, ( k,v ) => element.style[ k ] = v );
  172. return element;
  173. };
  174.  
  175. self.extend = function( target, sources ) {
  176. for ( let i = 1, n = arguments.length; i < n; i ++ ) {
  177. self.isobj(arguments[ i ], true) && self.copyMembers(arguments[ i ], target);
  178. }
  179. return target;
  180. };
  181.  
  182. self.extendProperties = function( target, source, overwrite, writable, enumerable, configurable ) {
  183. if ( !! target && !! source ) {
  184. overwrite = !! overwrite;
  185. writable = !! writable;
  186. enumerable = !! enumerable;
  187. configurable = !! configurable;
  188.  
  189. if ( self.isarr(source) ) {
  190. for ( let i = 0, n = source.length; i < n; i ++ ) {
  191. self.extendProperties(target, source[ i ], overwrite, writable, enumerable, configurable);
  192. }
  193. } else if ( self.isobj(source, true) ) {
  194. for ( let prop in source ) {
  195. if ( overwrite || self.ndef(target[ prop ]) ) {
  196. Object.defineProperty(target, prop,
  197. self.propDef(source[ prop ], writable, enumerable, configurable));
  198. }
  199. }
  200. }
  201. }
  202. return target;
  203. };
  204.  
  205. self.fire = function( element, event, args ) {
  206. if ( isarr(element) ) {
  207. return element.map( elem => self.fire(elem, event, args) );
  208. }
  209.  
  210. if ( self.isstr(event) ) {
  211. args = self.ifndef(args, { 'bubbles':true, 'cancelable':true });
  212. event = new Event( event, args );
  213. }
  214. return element.dispatchEvent(event);
  215. };
  216.  
  217. self.keysAndValues = function( key, value, action ) {
  218. if ( self.ndef(action) && self.isfn(value) ) {
  219. action = value;
  220. value = undefined;
  221. }
  222.  
  223. // Case 1: key is an object (and there is no value)
  224. if ( self.isobj(key) && ! value ) {
  225. return Object.keys(key)
  226. .map( k => action(k, key[ k ]) );
  227. // Case 2: key is an array
  228. } else if ( self.isarr(key) ) {
  229. // Case 1.a: value is an array of the same length
  230. if ( self.isarr(value) && key.length === value.length ) {
  231. return key.map( ( k,i ) => action(k, value[ i ]) );
  232. // Case 1.b: value is considered a simple, plain value
  233. } else {
  234. return key.map( k => action(k, value) );
  235. }
  236. // Default Case: key and value considered as simple, plain values
  237. } else {
  238. return action(key, value);
  239. }
  240. };
  241.  
  242. self.lazy = function( func, storage ) {
  243. // If the argument is a function (expected), set it as lazy getter
  244. if ( self.isfn(func) ) {
  245. let name = 'initializer::'+ Math.random(),
  246. me = self.lazy;
  247. storage = storage || me.storage || (me.storage = { });
  248. return ( ) => ( self.defn(storage[ name ]) ? storage[ name ] : (storage[ name ] = func()) );
  249. // If the argument was "something" else (not undefined), set it as the result
  250. } else if ( self.defn(func) ) {
  251. return ( ) => func;
  252. }
  253. // Otherwise: No idea
  254. throw 'lazy(): The first argument (lazy getter / value) must be provided';
  255. //return null;
  256. };
  257.  
  258. self.localJson = function( key, value ) {
  259. if ( !! key && self.isstr(key) ) {
  260. try {
  261. if ( self.ndef(value) ) {
  262. return JSON.parse(localStorage.getItem(key));
  263. } else if ( null === value ) {
  264. return localStorage.removeItem(key);
  265. } else {
  266. return localStorage.setItem(key, JSON.stringify(value));
  267. }
  268. } catch ( error ) {
  269. self.warn('* localJson() error:', error, '\n\tfor:', key, value);
  270. }
  271. }
  272. return null;
  273. };
  274.  
  275. self.off = function( element, event, callback ) {
  276. if ( self.ndef(callback) && self.isobj(event) ) {
  277. return self.keysAndValues(event, ( k,v ) => self.off(element, k, v) );
  278. } else if ( self.isarr(element) ) {
  279. return element.map( elem => self.off(elem, event, callback) );
  280. }
  281. return element.removeEventListener(event, callback);
  282. };
  283.  
  284. self.on = function( element, event, callback ) {
  285. if ( self.ndef(callback) && self.isobj(event) ) {
  286. return self.keysAndValues(event, ( k,v ) => self.on(element, k, v) );
  287. } else if ( self.isarr(element) ) {
  288. return element.map( elem => self.on(elem, event, callback) );
  289. }
  290. return element.addEventListener(event, callback);
  291. };
  292.  
  293. self.onmutate = function( element, callback, config ) {
  294. if ( !! element && self.isfn(callback) ) {
  295. config = config || { 'attributes':false, 'childList':true, 'subtree':false };
  296.  
  297. if ( self.isarr(element) ) {
  298. return element.map( elem => self.onmutate(elem, callback, config) );
  299. }
  300.  
  301. let observer = new MutationObserver( callback );
  302. observer.initialConfig = ( ) => config;
  303. observer.reconnect = function( newConfig ) {
  304. this.observe(element, newConfig || this.initialConfig());
  305. return this;
  306. };
  307. return observer.reconnect();
  308. }
  309. return null;
  310. };
  311.  
  312. self.pojo2query = function( pojo ) {
  313. if ( self.isobj(pojo) && !! pojo ) {
  314. let query = Object.keys(pojo)
  315. .map( key => escape(key) +'='+ escape(pojo[ key ]) )
  316. .join('&');
  317. return '?'+ query;
  318. }
  319. return null;
  320. };
  321.  
  322. self.prependTo = function( element, parent, reference ) {
  323. if ( ! reference && !! parent ) {
  324. reference = parent.childNodes[ 0 ];
  325. }
  326.  
  327. if ( isarr(element) ) {
  328. return element.map( elem => self.prependTo(elem, parent, reference) );
  329. }
  330.  
  331. if ( !! reference ) {
  332. reference.parentNode.insertBefore(element, reference);
  333. } else if ( !! parent ) {
  334. parent.append(element);
  335. } else {
  336. self.warn('*** prependTo() could not add element: No parent or reference element provided');
  337. }
  338.  
  339. return element;
  340. };
  341.  
  342. self.propDef = function( value, writable, enumerable, configurable ) {
  343. enumerable = !! enumerable;
  344. var def = {
  345. 'enumerable': enumerable,
  346. 'configurable': !! configurable,
  347. };
  348.  
  349. if ( self.isfn(value) && ( enumerable || self.isfn(writable) ) ) {
  350. def.get = value;
  351. if ( self.isfn(writable) ) {
  352. def.set = writable;
  353. }
  354. } else {
  355. def.value = value;
  356. def.writable = !! writable;
  357. }
  358.  
  359. return def;
  360. }
  361.  
  362. self.query2pojo = function( query ) {
  363. query = (self.ifndef(query, location.search) +'')
  364. .replace(/^[?&]+|$&+/g, '');
  365. if ( !! query ) {
  366. let segs, key, val, pojo = { };
  367. query.split('&')
  368. .forEach( item => {
  369. [ key, val ] =
  370. segs = item.split('=');
  371. val = ( self.ndef(val) ? null : segs.slice(1).join('=') );
  372. pojo[ unescape(key) ] = unescape(val);
  373. } );
  374. return pojo;
  375. }
  376. return null;
  377. };
  378.  
  379. self.range = function( from, to, inc ) {
  380. inc = ( ! inc || isNaN(inc) ? 1 : inc );
  381. if ( from == to - inc ) {
  382. return [ from, to ];
  383. } else if ( from == to ) {
  384. return [ to ];
  385. } else if ( (to - from) % inc || ! self.between(from + inc, from, to) ) {
  386. throw 'Cannot create range '+ from +'..'+ to +' with increments of '+ inc;
  387. //return null ;//[ ];
  388. }
  389. return self.range(from, to - inc, inc).concat(to);
  390. };
  391.  
  392. self.request = function( url, verb, data, callback ) {
  393. self.log('* request of:', verb, url, data, callback);
  394.  
  395. // "Validate" HTTP Verb, to an extent
  396. verb = (verb || 'GET').toUpperCase();
  397. switch ( verb ) {
  398. case 'P': verb = 'POST'; break;
  399. case 'G': verb = 'GET'; break;
  400. case 'H': verb = 'HEAD'; break;
  401. }
  402.  
  403. // Switch callback and data when ther is no data
  404. if ( self.ndef(callback) && self.isfn(data) ) {
  405. callback = data;
  406. data = null;
  407. }
  408.  
  409. // Set the data to a string or null
  410. data = self.ifndef(data, null);
  411. data = ( !! data && self.isobj(data) ? self.pojo2query(data).replace('?', '') : data.toString() );
  412. self.log('- request data:', data);
  413.  
  414. // Add data to the URL for GET requests
  415. if ( 'GET' === verb && !! data ) {
  416. url += ( url.includes('?') ? '&' : '?' ) + data;
  417. data = null;
  418. }
  419.  
  420. // Create & open XHR object...
  421. let xhr = self.createXHR();
  422. self.log('-> opening request:', verb, url);
  423. xhr.open(verb, url);
  424. xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  425.  
  426. // Set the internal event handler, which removes itself on execution
  427. xhr.onabort =
  428. xhr.onerror =
  429. xhr.onload = callback;
  430.  
  431. // Send the actual request
  432. self.log('-> sending request:', data, xhr.readyState, xhr);
  433. return xhr.send(data);
  434. };
  435.  
  436. // Sandboxed `Function([exportedValues,] arg1, ..., argN, funcBody)`
  437. self.sandbox = function( exports, funcArgsAndCode ) {
  438. const C = self.sandbox._sandbox || self.createSandbox(self.sandbox),
  439. F = C.Function.bind(C);
  440. const args = self.toArray(arguments);
  441. if ( 'string' !== typeof exports ) {
  442. args.shift();
  443. }
  444.  
  445. // Do we need to pass-in any "exports" values (as arguments?)
  446. if ( !! exports && self.ispojo(exports) ) {
  447. let inrArgs = Object.keys(exports);
  448.  
  449. if ( inrArgs.length > 0 ) {
  450. inrArgs = inrArgs.concat(args);
  451. const vals = Object.values(exports),
  452. fn = F.apply(null, inrArgs);
  453. (arguments[ arguments.length - 1 ] || '').includes('arguments') && console.warn('sandbox() - sandboxed code with `exports` should not rely on `arguments`');
  454.  
  455. return function _sandboxed_withExports( ){ return fn.apply(null, vals.concat(toArray(arguments))); };
  456. }
  457. }
  458. return F.apply(null, args);
  459. };
  460.  
  461. self.table2json = function( table, headers, filter ) {
  462. if ( !! table && !! table.rows ) {
  463. let obj = { head:[ ], data:[ ] };
  464.  
  465. obj.head = ( self.isfn(headers) ? headers(table) : table.rows[ 0 ] );
  466. if ( self.isobj(obj.head) && !! obj.head.cells ) {
  467. obj.head = Array.map(obj.head.cells, th => th.innerText.trim() );
  468. }
  469.  
  470. if ( obj.head.length ) {
  471. filter = filter || (( row,i ) => ( i && 'TBODY' === row.parentNode.nodeName ));
  472.  
  473. for ( let r = 0, nr = table.rows.length; r < nr; r ++ ) {
  474. let row = table.rows[ r ];
  475.  
  476. if ( filter(row, r) ) {
  477. let item = { };
  478. obj.head.forEach( ( col,i ) => {
  479. col[ 0 ] && (item[ col ] = row.cells[ i ].innerText.trim());
  480. } );
  481. obj.data.push(item);
  482. }
  483. }
  484. }
  485. return obj.data;
  486. }
  487. return null;
  488. };
  489.  
  490. self.toArray = function( expr ) {
  491. if ( self.hasval(expr) && ! self.isarr(expr) ) {
  492. return ( self.ndef(expr.length) ? [ expr ] : Array.prototype.slice.call(expr) );
  493. }
  494. return expr || [ ];
  495. };
  496.  
  497. self.toDec2 = function( amount ) {
  498. amount = self.toDec(amount);
  499. if ( isNaN(amount) ) {
  500. return null;
  501. }
  502. let segs = (amount +'').split('.');
  503. return segs[ 0 ] +'.'+ ((segs[ 1 ] || 0) +'0').slice(0, 2);
  504. };
  505.  
  506. self.toMoney = function( amount ) {
  507. let dec2 = self.toDec2(amount);
  508. return ( isNaN(dec2) ? null : dec2 < 0 ? '-$ '+ (-dec2) : '$ '+ dec2 );
  509. };
  510.  
  511. self.traverse = function( elem, up, sideways, elementsOnly, lastIfNull ) {
  512. let last = elem;
  513. while ( !! elem && up -- > 0 ) elem = (last = elem, elem.parentNode);
  514.  
  515. let prop = ( elementsOnly ? 'Element' : '' ) +'Sibling';
  516. if ( sideways < 0 ) {
  517. while ( !! elem && sideways ++ < 0 ) elem = (last = elem, elem[ 'previous'+ prop ]);
  518. } else if ( sideways > 0 ) {
  519. while ( !! elem && sideways -- > 0 ) elem = (last = elem, elem[ 'next'+ prop ]);
  520. }
  521.  
  522. return ( ! lastIfNull ? elem : elem || last );
  523. };
  524.  
  525. self.wrapWith = function( content, wrapper ) {
  526. let wrap = content;
  527. if ( !! content && !! wrapper ) {
  528. wrap = self.toArray( self.isstr(wrapper) ? self.create(wrapper) : wrapper )[ 0 ];
  529. if ( !! wrap ) {
  530. let cont = self.toArray(content);
  531.  
  532. self.prependTo(wrap, null, cont[ 0 ]);
  533. cont.forEach( c => self.appendTo(c, wrap) );
  534. }
  535. }
  536. return wrap;
  537. };
  538.  
  539.  
  540. // Object for feature-detection (modern browsers only --e.g., uses lambdas)
  541. self.detected = Object.create(null, {
  542. // Detect support for passive event listeners
  543. // Reference: https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md#feature-detection
  544. 'passiveEvents': self.propDef(self.lazy( ( ) => {
  545. var supported = false;
  546. try {
  547. var opts = Object.defineProperty({ }, 'passive', self.propDef( ( ) => supported = true ));
  548. window.addEventListener('testPassive', null, opts);
  549. window.removeEventListener('testPassive', null, opts);
  550. } catch ( e ) {
  551. }
  552. return supported;
  553. } )),
  554. });
  555.  
  556.  
  557. // ----------------------------------------------------
  558. // Intended for Internal Use
  559.  
  560. self.copyMembers = function( source, target, members, preserve ) {
  561. //self.log('* Copying from', source, '\n\tto', target, '\n\t'+ members, preserve);
  562. if ( ! self.isobj(source) || ! self.isobj(target) ) {
  563. self.warn('=> Cannot copy from/to non-objects');
  564. return false;
  565. }
  566.  
  567. let names = Object.keys(source);
  568. preserve = ( self.isobj(preserve) ? preserve : false );
  569. //self.log('- Full list of members:', names, '\n\t', source);
  570.  
  571. if ( self.isstr(members) ) {
  572. members = members.split(',').map( nm => nm.trim() );
  573. }
  574. if ( self.isarr(members) ) {
  575. //self.log('* Member filter:', members);
  576. names = names.filter( nm => members.includes(nm) );
  577. } else if ( self.isfn(members) ) {
  578. names = names.filter(members);
  579. }
  580. //self.log('- Filtered list of members:', names);
  581.  
  582. names.forEach( nm => {
  583. if ( !! target[ nm ] && !! preserve ) {
  584. preserve[ nm ] = target[ nm ];
  585. }
  586. target[ nm ] = source[ nm ];
  587. //self.log('- Target members', nm, target[ nm ]);
  588. } );
  589. //self.log('=>', target);
  590. return (preserve || target);
  591. };
  592.  
  593. self.export = function( scope, members, overwriten ) {
  594. if ( ! scope ) {
  595. return false;
  596. }
  597. if ( '*' === (members +'').trim() ) {
  598. members = null;
  599. }
  600. return self.copyMembers(self, scope, members, overwriten);
  601. };
  602.  
  603. // Avoid needing a 'new' operator; this is just a wrapper
  604. return self;
  605. }