commit 0ae868ac2d08675bc20c05a99e25f331b10724b8 Author: 斟酌 鵬兄 Date: Tue May 31 17:56:05 2016 +0800 Initial commit diff --git a/array.js b/array.js new file mode 100644 index 0000000..b859fdb --- /dev/null +++ b/array.js @@ -0,0 +1,83 @@ +module.exports = { + array_col: function( arr, name ) + { + var colArr = []; + if( name === undefined ) + { + for( var i in arr ) + { + var o = arr[i]; + colArr.push( o[ Object.keys( o )[0] ] ); + } + } + else + { + for( var i in arr ) + { + colArr.push( arr[i][ name ] ); + } + } + return colArr; + } + + // join exclude + , joinx: function( glue, arr, exclude ) + { + var namedArr = false; + if( arr.length == 2 + && typeof( arr[0] ) == "string" + && typeof( arr[1] ) == "object" ) + { + namedArr = arr[0]; + arr = arr[1]; + } + + var exMatch = []; + if( typeof( exclude ) == "string" ) + { + exMatch.push( exclude ); + } + else if( typeof( exclude ) == "object" ) + { + exMatch.push( exclude[ namedArr ] ); + } + else if( typeof( exclude ) == "array" ) + { + if( namedArr ) + { + for( var i in exclude ) + { + exMatch.push( exclude[i][ namedArr ] ); + } + } + else + { + exMatch = exclude + } + } + + var gluedStr = ""; + if( namedArr ) + { + for( var i = 0, l = arr.length; i < l; i ++ ) + { + if( exMatch.indexOf( arr[i][ namedArr ] ) < 0 ) + { + gluedStr += arr[i][ namedArr ] + "+"; + } + } + } + else + { + for( var i = 0, l = arr.length; i < l; i ++ ) + { + if( exMatch.indexOf( arr[i] ) < 0 ) + { + gluedStr += arr[i] + "+"; + } + } + } + + return gluedStr.substr( 0, gluedStr.length - 1 ); + } +}; diff --git a/date.js b/date.js new file mode 100644 index 0000000..ff9a95b --- /dev/null +++ b/date.js @@ -0,0 +1,66 @@ +// Capital month +var CAP_MONTHS = [ false, false, false, true, false, true, false, false, true, false, true, false ]; +var MONTH_ABBR = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]; +var MONTH = [ + "January", "February", "March", "April" + , "May", "June", "July", "August" + , "September", "October", "November", "December" +]; +var DAY_ABBR = [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ]; +var DAY = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ]; + +var getOrdinalSuffix = function(day) +{ + if (day < 4 || ( 20 < day && day < 24 )) { + if (day == 1 || day == 21) return "st"; + else if (day == 2 || day == 22) return "nd"; + else if (day == 3 || day == 23) return "rd"; + } + else if (day == 31) return "st"; + return "th"; +}; + +module.exports = { + date_pretty: function( dateObj, plain ) + { + return dateObj.getDate() + + ( plain ? "" : "" ) + + getOrdinalSuffix( dateObj.getDate() ) + + ( plain ? " " : " " ) + + MONTH[ dateObj.getMonth() ] + + ", " + + dateObj.getFullYear() + ; + } + , date_bMon: function( date ) { return MONTH[ date.getMonth() ]; } + , date_sDay: function( date ) { return DAY_ABBR[ date.getDay() ]; } + , date_short: function( date ) + { + // Rearrange the date format + var d = date.toDateString().split( " " ); + // ddd dd mmm yyyy + return d[2] + " " + d[1] + " " + d[3] + " " + d[0]; + } + , date_comment: function( date ) + { + var d = date.toDateString().split( " " ); + var t = date.toTimeString().split( ":" ); + var ampm = "AM"; + var h = Number( t[0] ); + if( 12 <= h ) + { + ampm = "PM"; + if( h != 12 ) h -= 12; + } + + // h:mm AM/PM dd mmm, yyyy + return h + ":" + t[1] + " " + ampm + + " " + d[1] + " " + d[3] + ", " + d[2] + " " + d[0]; + } + , date_tzISODate: function( date ) + { + var tzo = new Date().getTimezoneOffset() * 6e4; + var ndate = new Date( date.getTime() - tzo ); + return ndate.toISOString().split( "T" )[0]; + } +}; diff --git a/form.js b/form.js new file mode 100644 index 0000000..904e284 --- /dev/null +++ b/form.js @@ -0,0 +1,120 @@ +var cl = global.botanLoader; +var WebParam = cl.load( "botanss.utils.WebParam" ); +var ReadStream = require( "stream" ).Readable; + +var qstr = require( "./querystr.js" ); + +module.exports = { + form_multipart: function( boundary, request, handler ) + { + boundary = new Buffer( "--" + boundary ); + var delim = new Buffer( "0D0A0D0A", "hex" ); + var endBuff = new Buffer( "2D2D0D0A", "hex" ); + + var st = request.resultStream(); + var firstRead = true; + + var tarBuff = null; + var content = [[]]; + + var i = 0; + var ring = 0; + + st.addListener( "readable", function() + { + if( firstRead ) + { + firstRead = false; + var r = st.read( boundary.length, "hex" ); + if( !r.equals( boundary ) ) + throw new Error( "Invalid form input" ); + } + + // Read them byte by byte + while( ( r = st.read( 1, "hex" ) ) !== null ) + { + switch( ring ) + { + case 0: + tarRBuff = delim; + nextRing = 1; + break; + + case 1: + tarRBuff = boundary; + nextRing = 0; + break; + } + + if( tarBuff ) + { + content[ i ].push( tarBuff[0] ); + tarBuff = Buffer.concat([ tarBuff.slice( 1 ), r ]); + } + else + { + tarBuff = Buffer.concat([ r, st.read( tarRBuff.length - 1, "hex" ) ]); + } + + if( tarBuff.equals( tarRBuff ) ) + { + i ++; content[ i ] = []; + ring = nextRing; + tarBuff = null; + } + } + + } ); + + st.addListener( "end", function() + { + if( !tarBuff.equals( endBuff ) ) + { + throw new Error( "Invalid form data" ); + } + + content = content.map( ( v ) => new Buffer( v ) ); + + var item; + var formData = []; + + var l = content.length; + + for( var i = 0; i < l; i ++ ) + { + if( i % 2 == 0 ) + { + item = {}; + content[i].toString().split( "\r\n" ).forEach( + function( v ) + { + if( !v ) return; + v = v.split( ":" ); + item[ v[0] ] = new WebParam( v[1] ); + } ); + } + else + { + // the -2 is the last 0D0A + item.file = { + content: new ReadStream() + , size: content[i].length - 2 + }; + item.file.content._read = function(){}; + + setTimeout( + function() + { + this.f.push( this.c.slice( 0, -2 ) ); + this.f.push( null ); + }.bind({ f: item.file.content, c: content[i] }) + , 0 ); + + formData.push( item ); + } + } + + handler( formData ); + } ); + } +}; diff --git a/hash.js b/hash.js new file mode 100644 index 0000000..15eb3d3 --- /dev/null +++ b/hash.js @@ -0,0 +1,16 @@ +var crypto = require( "crypto" ); + +module.exports = { + md5: function( str ) + { + var md5 = crypto.createHash( "md5" ); + md5.update( str ); + return md5.digest( "hex" ); + } + , sha1: function( str ) + { + var sha1 = crypto.createHash( "sha1" ); + sha1.update( str ); + return sha1.digest( "hex" ); + } +}; diff --git a/loader.js b/loader.js new file mode 100644 index 0000000..7703d69 --- /dev/null +++ b/loader.js @@ -0,0 +1,23 @@ +var cl = global.botanLoader; + +var Loader = function() +{ + for( var i in arguments ) + { + this.use( arguments[i] ); + } +}; + +Loader.prototype.use = function() +{ + for( var i in arguments ) + { + var module = arguments[i]; + var m = require( "./" + module ); + + // Link all methods to this + for( var j in m ) this[ j ] = m[ j ]; + } +}; + +module.exports = Loader; diff --git a/object.js b/object.js new file mode 100644 index 0000000..ea202f8 --- /dev/null +++ b/object.js @@ -0,0 +1,61 @@ +var cloneObj = function( o ) +{ + if ( o == null || typeof o != "object" ) return o; + + var clone = {}; + + if ( o instanceof Date ) + { + clone = new Date(); + clone.setTime( o.getTime() ); + return clone; + } + + if ( o instanceof Array ) + { + clone = []; + + for ( var i = 0, l = o.length; i < l; i ++ ) + { + clone[i] = cloneObj( o[i] ); + } + + return clone; + } + + if ( o instanceof Object ) + { + for ( var p in o ) + { + o.hasOwnProperty( p ) + && ( clone[ p ] = cloneObj( o[ p ] ) ); + } + + return clone; + } + + throw new Error( "Can't clone object: " + o ); +}; + +var referenceObj = function() +{ + var l = arguments.length; + if( l == 0 ) return null; + + var ref = arguments[0]; + if( l == 1 ) return ref; + + var refd = {}; + for( var i = 1; i < l; i ++ ) + { + var prop = arguments[i]; + refd[ prop ] = ref[ prop ]; + } + + return refd; +}; + +module.exports = { + clone: cloneObj + , refObj: referenceObj +}; diff --git a/querystr.js b/querystr.js new file mode 100644 index 0000000..24d1699 --- /dev/null +++ b/querystr.js @@ -0,0 +1,19 @@ +var cl = global.botanLoader; +var CondStream = cl.load( "botanss.utils.CondStream" ); + +module.exports = { + queryStr: function( qstr ) + { + var qObj = {}; + + if( qstr instanceof CondStream ) qstr = qstr.toString(); + + qstr.split( "&" ).forEach( function( val ) + { + val = val.split( "=" ); + qObj[ val[0] ] = val[1] ? decodeURIComponent( val[1].replace( /\+/g, " " ) ) : ""; + } ); + + return qObj; + } +}; diff --git a/random.js b/random.js new file mode 100644 index 0000000..8fdcfc5 --- /dev/null +++ b/random.js @@ -0,0 +1,15 @@ +var lut = []; for ( var i=0; i<256; i++ ) { lut[i] = (i<16?'0':'')+(i).toString(16); } + +module.exports = { + uuid: function() + { + var d0 = Math.random()*0xffffffff|0; + var d1 = Math.random()*0xffffffff|0; + var d2 = Math.random()*0xffffffff|0; + var d3 = Math.random()*0xffffffff|0; + return lut[d0&0xff]+lut[d0>>8&0xff]+lut[d0>>16&0xff]+lut[d0>>24&0xff]+'-'+ + lut[d1&0xff]+lut[d1>>8&0xff]+'-'+lut[d1>>16&0x0f|0x40]+lut[d1>>24&0xff]+'-'+ + lut[d2&0x3f|0x80]+lut[d2>>8&0xff]+'-'+lut[d2>>16&0xff]+lut[d2>>24&0xff]+ + lut[d3&0xff]+lut[d3>>8&0xff]+lut[d3>>16&0xff]+lut[d3>>24&0xff]; + } +}; diff --git a/string.js b/string.js new file mode 100644 index 0000000..07b0e73 --- /dev/null +++ b/string.js @@ -0,0 +1,22 @@ +module.exports = { + encodeHtml: function ( str, br ) + { + str = ( str + "" ).replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'") + ; + if( br ) str = str.replace( /\n/g, "
" ); + return str; + } + , http_str: function( str ) + { + if( str.match( "^https?://" ) ) + { + return str; + } + + return "http://" + str; + } +}