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