skip.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751
  1. // Skip.js
  2. //
  3. // Make JavaScript a little warmer, a little fuzzier.
  4. //
  5. // Author: Stewart Smith.
  6. // Website: http://stewd.io
  7. // GitHub: http://github.com/stewdio
  8. // Twitter: http://twitter.com/stewd_io
  9. // Copyright (C) 2013, Stewart Smith.
  10. //
  11. // Permission is hereby granted, free of charge, to any person obtaining a
  12. // copy of this software and associated documentation files (the "Software"),
  13. // to deal in the Software without restriction, including without limitation
  14. // the rights to use, copy, modify, merge, publish, distribute, sublicense,
  15. // and/or sell copies of the Software, and to permit persons to whom
  16. // the Software is furnished to do so, subject to the following conditions:
  17. //
  18. // The above copyright notice and this permission notice shall be included
  19. // in all copies or substantial portions of the Software.
  20. //
  21. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  22. // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  24. // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
  25. // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  26. // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  27. // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  28. export function skipjs(){
  29. globalThis.SKIP_JS = 20130821.1536
  30. globalThis.forceAugment = function( type, name, data ){
  31. var key
  32. if( typeof name === 'string' && data ){
  33. type.prototype[ name ] = data
  34. }
  35. else if( typeof name === 'object' && !data ){
  36. for( key in name ) forceAugment( type, key, name[ key ] )
  37. }
  38. }
  39. globalThis.augment = function( type, name, data ){
  40. var key
  41. if( typeof name === 'string' &&
  42. type.prototype[ name ] === undefined &&
  43. data ){
  44. forceAugment( type, name, data )
  45. }
  46. else if( typeof name === 'object' && !data ){
  47. for( key in name ) augment( type, key, name[ key ] )
  48. }
  49. }
  50. globalThis.forceLearn = function( student, teacher ){
  51. for( var p in teacher ){
  52. if( teacher.hasOwnProperty( p )){
  53. if( teacher[ p ].constructor === Object )
  54. student[ p ] = forceLearn( student[ p ], teacher[ p ])
  55. else student[ p ] = teacher[ p ]
  56. }
  57. }
  58. return student
  59. }
  60. globalThis.learn = function( student, teacher ){
  61. for( var p in teacher ){
  62. if( teacher.hasOwnProperty( p ) && student[ p ] === undefined ){
  63. if( teacher[ p ].constructor === Object )
  64. student[ p ] = learn( student[ p ], teacher[ p ])
  65. else student[ p ] = teacher[ p ]
  66. }
  67. }
  68. return student
  69. }
  70. globalThis.cascade = function(){
  71. var i, args = Array.prototype.slice.call( arguments )
  72. for( i = 0; i < args.length; i ++ )
  73. if( args[ i ] !== undefined ) return args[ i ]
  74. return false
  75. }
  76. globalThis.coinFlip = function(){
  77. return Math.round( Math.random() )
  78. }
  79. globalThis.isNumeric = function( n ){
  80. return !isNaN( parseFloat( n )) && isFinite( n )
  81. }
  82. globalThis.E = Math.E
  83. globalThis.HALF_PI = Math.PI / 2
  84. globalThis.PI = Math.PI
  85. globalThis.π = Math.PI
  86. globalThis.TAU = Math.PI * 2
  87. globalThis.SQRT2 = Math.SQRT2
  88. globalThis.SQRT1_2 = Math.SQRT1_2
  89. globalThis.LN2 = Math.LN2
  90. globalThis.LN10 = Math.LN10
  91. globalThis.LOG2E = Math.LOG2E
  92. globalThis.LOG10E = Math.LOG10E
  93. globalThis.SECOND = 1000
  94. globalThis.MINUTE = SECOND * 60
  95. globalThis.HOUR = MINUTE * 60
  96. globalThis.DAY = HOUR * 24
  97. globalThis.WEEK = DAY * 7
  98. globalThis.MONTH = DAY * 30.4368499
  99. globalThis.YEAR = DAY * 365.242199
  100. globalThis.DECADE = YEAR * 10
  101. globalThis.CENTURY = YEAR * 100
  102. globalThis.now = function(){ return +Date.now() }
  103. globalThis.MIN = Number.MIN_VALUE
  104. globalThis.MAX = Number.MAX_VALUE
  105. // augment( Array, {
  106. // distanceTo : function( target ){
  107. // var i, sum = 0
  108. // if( arguments.length > 0 )
  109. // target = Array.prototype.slice.call( arguments )
  110. // if( this.length === target.length ){
  111. // for( i = 0; i < this.length; i ++ )
  112. // sum += Math.pow( target[i] - this[i], 2 )
  113. // return Math.pow( sum, 0.5 )
  114. // }
  115. // else return null
  116. // },
  117. // first : function(){
  118. // return this[ 0 ]
  119. // },
  120. // last : function(){
  121. // return this[ this.length - 1 ]
  122. // },
  123. // maximum : function(){
  124. // return Math.max.apply( null, this )
  125. // },
  126. // middle : function(){
  127. // return this[ Math.round(( this.length - 1 ) / 2 ) ]
  128. // },
  129. // minimum : function(){
  130. // return Math.min.apply( null, this )
  131. // },
  132. // indexOf : function( obj, fromIndex ){
  133. // var i, j
  134. // if( fromIndex === null )
  135. // fromIndex = 0
  136. // else if( fromIndex < 0 )
  137. // fromIndex = Math.max( 0, this.length + fromIndex )
  138. // for( i = fromIndex, j = this.length; i < j; i++ )
  139. // if( this[i] === obj ) return i
  140. // return -1// I'd rather return NaN, but this is more standard.
  141. // },
  142. // rand : function(){
  143. // return this[ Math.floor( Math.random() * this.length )]
  144. // },
  145. // random : function(){// Convenience here. Exactly the same as .rand().
  146. // return this[ Math.floor( Math.random() * this.length )]
  147. // },
  148. // // Ran into trouble here with Three.js. Will investigate....
  149. // /*remove: function( from, to ){
  150. // var rest = this.slice(( to || from ) + 1 || this.length )
  151. // this.length = from < 0 ? this.length + from : from
  152. // return this.push.apply( this, rest )
  153. // },*/
  154. // shuffle : function(){
  155. // var
  156. // copy = this,
  157. // i = this.length,
  158. // j,
  159. // tempi,
  160. // tempj
  161. // if( i == 0 ) return false
  162. // while( -- i ){
  163. // j = Math.floor( Math.random() * ( i + 1 ))
  164. // tempi = copy[ i ]
  165. // tempj = copy[ j ]
  166. // copy[ i ] = tempj
  167. // copy[ j ] = tempi
  168. // }
  169. // return copy
  170. // },
  171. // toArray : function(){
  172. // return this
  173. // },
  174. // toHtml : function(){
  175. // var i, html = '<ul>'
  176. // for( i = 0; i < this.length; i ++ ){
  177. // if( this[ i ] instanceof Array )
  178. // html += this[ i ].toHtml()
  179. // else
  180. // html += '<li>' + this[ i ] + '</li>'
  181. // }
  182. // html += '</ul>'
  183. // return html
  184. // },
  185. // toText : function( depth ){
  186. // var i, indent, text
  187. // depth = cascade( depth, 0 )
  188. // indent = '\n' + '\t'.multiply( depth )
  189. // text = ''
  190. // for( i = 0; i < this.length; i ++ ){
  191. // if( this[ i ] instanceof Array )
  192. // text += indent + this[ i ].toText( depth + 1 )
  193. // else
  194. // text += indent + this[ i ]
  195. // }
  196. // return text
  197. // }
  198. // })
  199. augment( Number, {
  200. absolute : function(){
  201. return Math.abs( this )
  202. },
  203. add : function(){
  204. var sum = this
  205. Array.prototype.slice.call( arguments ).forEach( function( n ){
  206. sum += n
  207. })
  208. return sum
  209. },
  210. arcCosine : function(){
  211. return Math.acos( this )
  212. },
  213. arcSine : function(){
  214. return Math.asin( this )
  215. },
  216. arcTangent : function(){
  217. return Math.atan( this )
  218. },
  219. constrain : function( a, b ){
  220. var higher, lower, c = this
  221. b = b || 0
  222. higher = Math.max( a, b )
  223. lower = Math.min( a, b )
  224. c = Math.min( c, higher )
  225. c = Math.max( c, lower )
  226. return c
  227. },
  228. cosine : function(){
  229. return Math.cos( this )
  230. },
  231. degreesToDirection : function(){
  232. var d = this % 360,
  233. directions = [ 'N', 'NNE', 'NE', 'NEE', 'E', 'SEE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'SWW', 'W', 'NWW', 'NW', 'NNW', 'N' ]
  234. return directions[ this.scale( 0, 360, 0, directions.length - 1 ).round() ]
  235. },
  236. degreesToRadians : function(){
  237. return this * Math.PI / 180
  238. },
  239. divide : function(){
  240. var sum = this
  241. Array.prototype.slice.call( arguments ).forEach( function( n ){
  242. sum /= n
  243. })
  244. return sum
  245. },
  246. isBetween : function( a, b ){
  247. var
  248. min = Math.min( a, b ),
  249. max = Math.max( a, b )
  250. return ( min <= this && this <= max )
  251. },
  252. lerp : function( a, b ){
  253. return a + (b - a ) * this
  254. },
  255. log : function( base ){
  256. return Math.log( this ) / ( base === undefined ? 1 : Math.log( base ))
  257. },
  258. log10 : function(){
  259. // is this more pragmatic? ---> return ( '' + this.round() ).length;
  260. return Math.log( this ) / Math.LN10
  261. },
  262. maximum : function( n ){
  263. return Math.max( this, n )
  264. },
  265. minimum : function( n ){
  266. return Math.min( this, n )
  267. },
  268. modulo : function( n ){
  269. return (( this % n ) + n ) % n
  270. },
  271. multiply : function(){
  272. var sum = this
  273. Array.prototype.slice.call( arguments ).forEach( function( n ){
  274. sum *= n
  275. })
  276. return sum
  277. },
  278. normalize : function( a, b ){
  279. if( a == b ) return 1.0
  280. return ( this - a ) / ( b - a )
  281. },
  282. raiseTo : function( exponent ){
  283. return Math.pow( this, exponent )
  284. },
  285. radiansToDegrees : function(){
  286. return this * 180 / Math.PI
  287. },
  288. rand : function( n ){
  289. var min, max
  290. if( n !== undefined ){
  291. min = Math.min( this, n )
  292. max = Math.max( this, n )
  293. return min + Math.floor( Math.random() * ( max - min ))
  294. }
  295. return Math.floor( Math.random() * this )
  296. },
  297. random : function( n ){
  298. var min, max
  299. if( n !== undefined ){
  300. min = Math.min( this, n )
  301. max = Math.max( this, n )
  302. return min + Math.random() * ( max - min )
  303. }
  304. return Math.random() * this
  305. },
  306. remainder : function( n ){
  307. return this % n
  308. },
  309. round : function( decimals ){
  310. var n = this
  311. decimals = decimals || 0
  312. n *= Math.pow( 10, decimals )
  313. n = Math.round( n )
  314. n /= Math.pow( 10, decimals )
  315. return n
  316. },
  317. roundDown : function(){
  318. return Math.floor( this )
  319. },
  320. roundUp : function(){
  321. return Math.ceil( this )
  322. },
  323. scale : function( a0, a1, b0, b1 ){
  324. var phase = this.normalize( a0, a1 )
  325. if( b0 == b1 ) return b1
  326. return b0 + phase * ( b1 - b0 )
  327. },
  328. sine : function(){
  329. return Math.sin( this )
  330. },
  331. subtract : function(){
  332. var sum = this
  333. Array.prototype.slice.call( arguments ).forEach( function( n ){
  334. sum -= n
  335. })
  336. return sum
  337. },
  338. tangent : function(){
  339. return Math.tan( this )
  340. },
  341. toArray : function(){
  342. return [ this.valueOf() ]
  343. },
  344. toNumber : function(){
  345. return this.valueOf()
  346. },
  347. toPaddedString : function( digits, decimals ){
  348. // @@
  349. // Need to review this later.
  350. // Mos def not bullet proof and also doesn't handle decimals.
  351. var
  352. i,
  353. stringed = '' + this,
  354. padding = ''
  355. digits = digits || 2
  356. decimals = decimals || 0
  357. for( i = stringed.length; i < digits; i ++ )
  358. padding += '0'
  359. // so what about decimals? padding to right of decimal?
  360. return padding + stringed
  361. },
  362. toSignedString : function(){
  363. var stringed = '' + this
  364. if( this >= 0 ) stringed = '+' + stringed
  365. return stringed
  366. },
  367. toString : function(){
  368. return ''+ this
  369. },
  370. // Fun with dates:
  371. // ((2).months() + (3).weeks() + (5).days() + (9).hours() + MINUTE ).ago().toDate()
  372. // Sat Jun 16 2012 13:03:07 GMT-0400 (EDT)
  373. // ((2).months() + (3).weeks() + (5).days() + (9).hours() + MINUTE ).fromNow().toDate()
  374. // Sat Dec 08 2012 00:01:23 GMT-0500 (EST)
  375. // (2).days().ago().isBetween( (3).weeks().ago(), (2).hours().ago() )
  376. // true
  377. seconds : function(){
  378. return this * SECOND
  379. },
  380. minutes : function(){
  381. return this * MINUTE
  382. },
  383. hours : function(){
  384. return this * HOUR
  385. },
  386. days : function(){
  387. return this * DAY
  388. },
  389. weeks : function(){
  390. return this * WEEK
  391. },
  392. months : function(){
  393. return this * MONTH
  394. },
  395. years : function(){
  396. return this * YEAR
  397. },
  398. decades : function(){
  399. return this * DECADE
  400. },
  401. centuries : function(){
  402. return this * CENTURY
  403. },
  404. ago : function(){
  405. return +Date.now() - this
  406. },
  407. fromNow : function(){
  408. return +Date.now() + this
  409. },
  410. toDate : function(){
  411. return new Date( +this )
  412. },
  413. // Both the Unix epoch and the JavaScript epoch
  414. // began on 01 January 1970 at 00:00:00 UTC.
  415. // Unix counts time in SECONDS since then.
  416. // JavaScript counts time in MILLISECONDS since then.
  417. // Also don't forget that these below are in LOCAL timezones!
  418. unixToYear : function(){
  419. return ( new Date( this * 1000 )).getFullYear()
  420. },
  421. yearToUnix : function(){
  422. // Pay attention: Every arg is zero-indexed
  423. // except for the day of the month, which is one-indexed!!
  424. return ( new Date( this, 0, 1, 0, 0, 0, 0 )).valueOf() / 1000
  425. }
  426. })
  427. augment( String, {
  428. capitalize : function(){
  429. return this.charAt( 0 ).toUpperCase() + this.slice( 1 )//.toLowerCase()
  430. },
  431. invert: function(){
  432. var
  433. s = '',
  434. i
  435. for( i = 0; i < this.length; i ++ ){
  436. if( this.charAt( i ) === this.charAt( i ).toUpperCase()) s += this.charAt( i ).toLowerCase()
  437. else s += this.charAt( i ).toUpperCase()
  438. }
  439. return s
  440. },
  441. isEmpty : function(){
  442. return this.length === 0 ? true : false
  443. },
  444. justifyCenter : function( n ){
  445. var
  446. thisLeftLength = Math.round( this.length / 2 ),
  447. thisRightLength = this.length - thisLeftLength,
  448. containerLeftLength = Math.round( n / 2 ),
  449. containerRightLength = n - containerLeftLength,
  450. padLeftLength = containerLeftLength - thisLeftLength,
  451. padRightLength = containerRightLength - thisRightLength,
  452. centered = this
  453. if( padLeftLength > 0 ){
  454. while( padLeftLength -- ) centered = ' ' + centered
  455. }
  456. else if( padLeftLength < 0 ){
  457. centered = centered.substr( padLeftLength * -1 )
  458. }
  459. if( padRightLength > 0 ){
  460. while( padRightLength -- ) centered += ' '
  461. }
  462. else if( padRightLength < 0 ){
  463. centered = centered.substr( 0, centered.length + padRightLength )
  464. }
  465. return centered
  466. },
  467. justifyLeft: function( n ){
  468. var justified = this
  469. while( justified.length < n ) justified = justified + ' '
  470. return justified
  471. },
  472. justifyRight: function( n ){
  473. var justified = this
  474. while( justified.length < n ) justified = ' ' + justified
  475. return justified
  476. },
  477. multiply : function( n ){
  478. var i, s = ''
  479. n = cascade( n, 2 )
  480. for( i = 0; i < n; i ++ ){
  481. s += this
  482. }
  483. return s
  484. },
  485. reverse : function(){
  486. var i, s = ''
  487. for( i = 0; i < this.length; i ++ ){
  488. s = this[ i ] + s
  489. }
  490. return s
  491. },
  492. size : function(){
  493. return this.length
  494. },
  495. toEntities : function(){
  496. var i, entities = ''
  497. for( i = 0; i < this.length; i ++ ){
  498. entities += '&#' + this.charCodeAt( i ) + ';'
  499. }
  500. return entities
  501. },
  502. toCamelCase : function(){
  503. var
  504. split = this.split( /\W+|_+/ ),
  505. joined = split[ 0 ],
  506. i
  507. for( i = 1; i < split.length; i ++ )
  508. joined += split[ i ].capitalize()
  509. return joined
  510. },
  511. directionToDegrees : function(){
  512. var
  513. directions = [ 'N', 'NNE', 'NE', 'NEE', 'E', 'SEE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'SWW', 'W', 'NWW', 'NW', 'NNW', 'N' ],
  514. i = directions.indexOf( this.toUpperCase() )
  515. return i >= 0 ? i.scale( 0, directions.length - 1, 0, 360 ) : Number.NaN
  516. },
  517. toArray : function(){
  518. return [ this ]
  519. },
  520. toNumber : function(){
  521. return parseFloat( this )
  522. },
  523. toString : function(){
  524. return this
  525. },
  526. toUnderscoreCase : function(){
  527. var underscored = this.replace( /[A-Z]+/g, function( $0 ){
  528. return '_' + $0
  529. })
  530. if( underscored.charAt( 0 ) === '_' ) underscored = underscored.substr( 1 )
  531. return underscored.toLowerCase()
  532. },
  533. toUnicode : function(){
  534. var i, u, unicode = ''
  535. for( i = 0; i < this.length; i ++ ){
  536. u = this.charCodeAt( i ).toString( 16 ).toUpperCase()
  537. while( u.length < 4 ){
  538. u = '0' + u
  539. }
  540. unicode += '\\u' + u
  541. }
  542. return unicode
  543. }
  544. })
  545. }