PageRenderTime 58ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/source/IO.js

https://github.com/licson0729/SO-ChatBot
JavaScript | 298 lines | 205 code | 59 blank | 34 comment | 21 complexity | 3465df8aa0bab95d00e6c6acc7612b23 MD5 | raw file
  1. var IO = window.IO = {
  2. //event handling
  3. events : {},
  4. preventDefault : false,
  5. //register for an event
  6. register : function ( name, fun, thisArg ) {
  7. if ( !this.events[name] ) {
  8. this.events[ name ] = [];
  9. }
  10. this.events[ name ].push({
  11. fun : fun,
  12. thisArg : thisArg,
  13. args : Array.prototype.slice.call( arguments, 3 )
  14. });
  15. return this;
  16. },
  17. unregister : function ( name, fun ) {
  18. if ( !this.events[name] ) {
  19. return this;
  20. }
  21. this.events[ name ] = this.events[ name ].filter(function ( obj ) {
  22. return obj.fun !== fun;
  23. });
  24. return this;
  25. },
  26. //fire event!
  27. fire : function ( name ) {
  28. this.preventDefault = false;
  29. if ( !this.events[name] ) {
  30. return;
  31. }
  32. var args = Array.prototype.slice.call( arguments, 1 ),
  33. that = this;
  34. this.events[ name ].forEach( fireEvent );
  35. function fireEvent( evt ) {
  36. var call = evt.fun.apply( evt.thisArg, evt.args.concat(args) );
  37. that.preventDefault = call === false;
  38. }
  39. },
  40. urlstringify : (function () {
  41. //simple types, for which toString does the job
  42. //used in singularStringify
  43. var simplies = { number : true, string : true, boolean : true };
  44. var singularStringify = function ( thing ) {
  45. if ( typeof thing in simplies ) {
  46. return encodeURIComponent( thing.toString() );
  47. }
  48. return '';
  49. };
  50. var arrayStringify = function ( key, array ) {
  51. key = singularStringify( key );
  52. return array.map(function ( val ) {
  53. return pair( key, val, true );
  54. }).join( '&' );
  55. };
  56. //returns a key=value pair. pass in dontStringifyKey so that, well, the
  57. // key won't be stringified (used in arrayStringify)
  58. var pair = function ( key, val, dontStringifyKey ) {
  59. if ( !dontStringifyKey ) {
  60. key = singularStringify( key );
  61. }
  62. return key + '=' + singularStringify( val );
  63. };
  64. return function ( obj ) {
  65. return Object.keys( obj ).map(function ( key ) {
  66. var val = obj[ key ];
  67. if ( Array.isArray(val) ) {
  68. return arrayStringify( key, val );
  69. }
  70. else {
  71. return pair( key, val );
  72. }
  73. }).join( '&' );
  74. };
  75. }()),
  76. loadScript : function ( url, cb ) {
  77. var script = document.createElement( 'script' );
  78. script.src = url;
  79. script.onload = cb;
  80. document.head.appendChild( script );
  81. }
  82. };
  83. IO.decodehtmlEntities = (function (){
  84. var entities; //will be filled in the following line
  85. //#build static/htmlEntities.js
  86. /*
  87. & -all entities start with &
  88. (
  89. # -charcode entities also have a #
  90. x? -hex charcodes
  91. )?
  92. [\w;] -now the entity (alphanumeric, separated by ;)
  93. +? -capture em until there aint no more (don't get the trailing ;)
  94. ; -trailing ;
  95. */
  96. var entityRegex = /&(#x?)?[\w;]+?;/g;
  97. var replaceEntities = function ( entities ) {
  98. //remove the & and split into each separate entity
  99. return entities.slice( 1 ).split( ';' ).map( decodeEntity ).join( '' );
  100. };
  101. var decodeEntity = function ( entity ) {
  102. //starts with a #, it's charcode
  103. if ( entity[0] === '#' ) {
  104. return decodeCharcodeEntity( entity );
  105. }
  106. return entities[ entity ] || entity;
  107. };
  108. var decodeCharcodeEntity = function ( entity ) {
  109. //remove the # prefix
  110. entity = entity.slice( 1 );
  111. var cc;
  112. //hex entities
  113. if ( entity[0] === 'x' ) {
  114. cc = parseInt( entity.slice(1), 16 );
  115. }
  116. //decimal entities
  117. else {
  118. cc = parseInt( entity, 10 );
  119. }
  120. return String.fromCharCode( cc );
  121. };
  122. return function ( html ) {
  123. return html.replace( entityRegex, replaceEntities );
  124. };
  125. }());
  126. //build IO.in and IO.out
  127. [ 'in', 'out' ].forEach(function ( dir ) {
  128. var fullName = dir + 'put';
  129. IO[ dir ] = {
  130. buffer : [],
  131. receive : function ( obj ) {
  132. IO.fire( 'receive' + fullName, obj );
  133. if ( IO.preventDefault ) {
  134. return this;
  135. }
  136. this.buffer.push( obj );
  137. return this;
  138. },
  139. //unload the next item in the buffer
  140. tick : function () {
  141. if ( this.buffer.length ) {
  142. IO.fire( fullName, this.buffer.shift() );
  143. }
  144. return this;
  145. },
  146. //unload everything in the buffer
  147. flush : function () {
  148. IO.fire( 'before' + fullName );
  149. if ( !this.buffer.length ) {
  150. return this;
  151. }
  152. var i = this.buffer.length;
  153. while( i --> 0 ) {
  154. this.tick();
  155. }
  156. IO.fire( 'after' + fullName );
  157. this.buffer = [];
  158. return this;
  159. }
  160. };
  161. });
  162. IO.xhr = function ( params ) {
  163. //merge in the defaults
  164. params = Object.merge({
  165. method : 'GET',
  166. headers : {},
  167. complete : function (){}
  168. }, params );
  169. params.headers = Object.merge({
  170. 'Content-Type' : 'application/x-www-form-urlencoded'
  171. }, params.headers );
  172. //if the data is an object, and not a fakey String object, dress it up
  173. if ( typeof params.data === 'object' && !params.data.charAt ) {
  174. params.data = IO.urlstringify( params.data );
  175. }
  176. var xhr = new XMLHttpRequest();
  177. xhr.open( params.method, params.url );
  178. xhr.addEventListener( 'readystatechange', function () {
  179. if ( xhr.readyState === 4 ) {
  180. params.complete.call(
  181. params.thisArg, xhr.responseText, xhr
  182. );
  183. }
  184. });
  185. Object.keys( params.headers ).forEach(function ( header ) {
  186. xhr.setRequestHeader( header, params.headers[header] );
  187. });
  188. xhr.send( params.data );
  189. return xhr;
  190. };
  191. IO.jsonp = function ( opts ) {
  192. opts.data = opts.data || {};
  193. opts.jsonpName = opts.jsonpName || 'jsonp';
  194. var script = document.createElement( 'script' ),
  195. semiRandom;
  196. do {
  197. semiRandom = 'IO' + ( Date.now() * Math.ceil(Math.random()) );
  198. } while ( window[semiRandom] );
  199. //this is the callback function, called from the "jsonp file"
  200. window[ semiRandom ] = function () {
  201. opts.fun.apply( opts.thisArg, arguments );
  202. //cleanup
  203. delete window[ semiRandom ];
  204. script.parentNode.removeChild( script );
  205. };
  206. //add the jsonp parameter to the data we're sending
  207. opts.data[ opts.jsonpName ] = semiRandom;
  208. //start preparing the url to be sent
  209. if ( opts.url.indexOf('?') === -1 ) {
  210. opts.url += '?';
  211. }
  212. //append the data to be sent, in string form, to the url
  213. opts.url += this.urlstringify( opts.data );
  214. script.src = opts.url;
  215. document.head.appendChild( script );
  216. };
  217. //generic, pre-made calls to be used inside commands
  218. IO.jsonp.ddg = function ( query, cb ) {
  219. IO.jsonp({
  220. url : 'http://api.duckduckgo.com/',
  221. jsonpName : 'callback',
  222. data : {
  223. format : 'json',
  224. q : query
  225. },
  226. fun : cb
  227. });
  228. };
  229. IO.jsonp.google = function ( query, cb ) {
  230. IO.jsonp({
  231. url : 'http://ajax.googleapis.com/ajax/services/search/web',
  232. jsonpName : 'callback',
  233. data : {
  234. v : '1.0',
  235. q : query
  236. },
  237. fun : cb
  238. });
  239. };