UNPKG

nk

Version:

nodakwaeri (nk): A simple, yet powerful, and fully-featured cross-platform application framework for Node.js.

939 lines (851 loc) 36.7 kB
/** * package: nodakwaeri * sub-package: renderer * author: Richard B. Winters <a href='mailto:rik@mmogp.com'>Rik At MMOGP</a> * copyright: 2011-2015 Massively Modified, Inc. * license: Apache, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0> */ // Deps; var fs = require( 'fs' ); /** * Entry point for the application renderer * * @param rtools Rendering tools * @param dpath Derived path to application views * * @since 0.2.4 */ function renderer( rtools, dpath ) { this.nk = rtools; this.rtools = new this.nk.html( this.nk ); this.dpath = dpath; this.date = new Date(); }; /** * Fetches the layout content so it can be parsed * * @param request * @param response * @param klay * * @since 0.2.5 */ renderer.prototype.turn = function( request, response, klay ) { // We would normally invoke the nodaklay module, and use the Pottr to construct our layout. For now we will use a JS // version in order to help spur on development. var vpath = this.dpath; var processor = this; // Construct will check if there is a layout specified, and invoke parse accordingly. if( klay.layout ) { fs.readFile ( vpath + '/' + klay.layout + '.kml', 'utf8', function( error, ldata ) { var buffer; // If there is an error if( error ) { // Log it console.log( 'Error reading layout: ' + vpath + '/' + klay.layout + '.kml' ); // And set content to contain an error message buffer = "<html><head><title>Failure</title></head><body><h1>Too Bad...</h1><p>There was an issue loading the requested layout!</p></body></html>"; response.statusCode = 200; response.setHeader( 'Content-Type', 'text/html' ); //response.writeHead( 200, { 'Content-Type': 'text/html' } ); response.write( buffer ); response.end(); } else { // Success // There should always be a body fs.readFile ( vpath + '/' + klay.controller + '/' + klay.view + '.kml', 'utf8', function( error, vdata ) { var buffer; if( error ) { // Log it console.log( 'Error reading view, ' + vpath + '/' + klay.controller + '/' + klay.view + '.kml' ); // And set content to contain an error message buffer = "<html><head><title>Failure</title></head><body><h1>Too Bad???...</h1><p>There was an issue loading the requested view!</p></body></html>"; response.statusCode = 200; response.setHeader( 'Content-Type', 'text/html' ); //response.writeHead(); response.write ( buffer ); response.end(); } else { //var pottr = nodakwaeri.klay(); //pottr.turn( request, response, klay ); klay.layout = ldata; klay.view = vdata; processor.shape( request, response, klay ); } } ); } } ); }else { // There should always be a body fs.readFile ( view_path + '/' + klay.controller + '/' + klay.view + '.kml', 'utf8', function( error, vdata ) { var buffer; if( error ) { // Log it console.log( 'Error reading view, ' + vpath + '/' + klay.controller + '/' + klay.view + '.kml' ); // And set content to contain an error message buffer = "<html><head><title>Failure</title></head><body><h1>Too Bad???...</h1><p>There was an issue loading the requested view!</p></body></html>"; response.statusCode = 200; response.setHeader( 'Content-Type', 'text/html' ); //response.writeHead(); response.write ( buffer ); response.end(); } else { //var pottr = nodakwaeri.klay(); //pottr.turn( request, response, klay ); klay.layout = false; klay.view = vdata; processor.shape( request, response, klay ); } } ); } }; /** * Fetches a partial view so it can be parsed * * @param piece * * @since 2.5 */ renderer.prototype.partial = function( piece ) { var processor = this; if( piece ) { fs.readFile ( this.dpath + '/' + piece + '.kml', 'utf8', function( error, pdata ) { var buffer; // If there is an error if( error ) { // Log it console.log( 'Error reading partial: ' + klay.partial[p] + '.kml' ); // And set content to contain an error message buffer = "<html><head><title>Failure</title></head><body><h1>Too Bad...</h1><p>There was an issue loading the requested layout!</p></body></html>"; response.statusCode = 200; response.setHeader( 'Content-Type', 'text/html' ); //response.writeHead( 200, { 'Content-Type': 'text/html' } ); response.write( buffer ); response.end(); } else { // Success return pdata; } } ); } return false; }; /** * Pieces together - and sends - the response * * @param request * @param response * @param klay * * @since 0.0.1 */ renderer.prototype.shape = function( request, response, klay ) { var processor = this; if( klay ) { klay.authenticated = request.isAuthenticated; } // Now let's prepare the body content; there may not be a layout, but if there is we need the body first. var body = klay.view; body = this.parse( body, klay ); // If a layout was requested, let's prep it if( klay.layout ) { klay.view = body; var view = klay.layout; view = this.parse( view, klay ); response.statusCode = 200; response.setSession(); response.setHeader( 'Content-Type', 'text/html' ); response.write( view ); response.end(); } else { response.statusCode = 200; response.setSession(); response.setHeader( 'Content-Type', 'text/html' ); response.write( body ); response.end(); } }; /** * Parses kwaeri script * * @param content * @param klay * @param iteration * @param identification * * @since 0.0.5 */ renderer.prototype.parse = function( content, klay, iteration, identification ) { // Shedding some light on syntax: // If you have a predeclared variable in question, you can use the ol' fashioned if( !var ) // this will check against undefined, null, and false. // If you're not sure the variable exists, use if( var == null ), the two equal-sign characters // check var against both null and undefined, since undefined evaluates to null. if( !iteration ) { //console.log( 'parse not iterated: ' + iteration ); iteration = false; } if( !identification ) { //console.log( 'parse not identified: ' + identification ); identification = false; } var processor = this, o = content .replace // First strip all comments ( /[^:"](\/\/[^\r\n]*)[\r\n]|(\/\*(.*)\*\/)*/mg, function( match, singline, multiline, extra ) { return ""; } ) .replace // Now we parse through the subscript blocks and invoke any members and replace any variables ( /(\[\[[\s]*?(([\w_]*)((\.([\w_]*))*(\((.*)\))*([\s]*\{([^]*)\}[\s]*)?([\s]*(else\{(.*)\})[\s]*)?)*)[\s]*?\]\])/mg, function( match, subscript, codeflow, fof, memflow, memstring, member, argflow, args, ssflow, superscript, esflow, extrascript ) { if( fof === 'partial' ) { if( args ) { var pdata = args; pdata = pdata.replace( /^[\s\r\n]*|[\s\r\n]*$/g, '' ); return processor.parse( processor.partial( pdata ), klay ); } return ""; } if( fof === 'if' ) { //console.log( codeflow ); //console.log( 'ARGS: \n\n'); var argument = args.replace( /[\s\r\n]*/g, '' ); //console.log( args ); //console.log( '\n\n ENDSSFLOW'); var pieces = ssflow.split( "else" ); if( pieces.length > 1 ) { if( klay.viewbag.hasOwnProperty( argument ) || klay.hasOwnProperty( argument ) ) { var status; if( argument === 'authenticated' ) { if( klay[argument] ) { status = true; } } else { if( klay.viewbag[argument] ) { status = true; } } if( status ) { if( !pieces[0] ) { return ''; } //console.log( 'PIECE1: \n\n' ); pieces[0] = pieces[0].replace( /^[\s\r\n]*\{|\}?[\s\r\n]*$/g, '' ); //console.log( pieces[0] ); return processor.parse( pieces[0], klay ); } else { if( !pieces[1] ) { return ''; } //console.log( '\n\n PIECE2: \n\n'); pieces[1] = pieces[1].replace( /^[\s\r\n]*\{|\}?[\s\r\n]*$/g, '' ); //console.log( pieces[1] ); return processor.parse( pieces[1], klay ); } } else { if( !pieces[1] ) { return ''; } //console.log( '\n\n PIECE2: \n\n'); pieces[1] = pieces[1].replace( /^[\s\r\n]*\{|\}?[\s\r\n]*$/g, '' ); //console.log( pieces[1] ); return processor.parse( pieces[1], klay ); } } else { if( klay.viewbag.hasOwnProperty( argument ) || klay.hasOwnProperty( argument ) ) { if( !pieces[0] ) { return ''; } var status; if( argument === 'authenticated' ) { if( klay[argument] ) { status = true; } } else { if( klay.viewbag[argument] ) { status = true; } } if( !status ) { return ''; } //console.log( 'PIECE1: \n\n' ); pieces[0] = pieces[0].replace( /^[\s\r\n]*\{|\}?[\s\r\n]*$/g,'' ); //console.log( pieces[0] ); return processor.parse( pieces[0], klay ); } else { return ''; } } return 'NoGottedIt'; } if( fof === 'foreach' ) { var found = false, pieces = false, iterator = false, identifier = false, subscript = superscript, ncf = codeflow; // For some reason we cannot single out the arguments when there are curly brackets following // so let's parse it out from a smaller piece of data found = ncf.replace ( /\([\s]*([_\w\s]*)[\s]*\)/g, function( match, match1 ) { pieces = match1; return; } ); if( found ) { found = true; } if( pieces ) { pieces = pieces.split( " as " ); if( pieces.length > 1 ) { // User has specified '..as <identifier>' iterator = pieces[0]; identifier = pieces[1]; } else { iterator = pieces[0]; } } // Strip all white space identifier = identifier.replace( /^[\s\r\n]*|[\s\r\n]*$/g, '' ); //console.log( 'iterator:' + iterator ); //console.log( 'identifier:' + identifier ); //console.log( ssflow ); //console.log( superscript ); // Now, for each member of our array or object, we want to recursively run some scripts. There could // also be plain html, which should be copied and values parsed for each iteration. Everything within // superscript should be run/copied for each iteration, and should be passed only the member/record that // the iteration pertains to. var so = ""; if( klay.viewbag.hasOwnProperty( iterator ) ) { for( var record in klay.viewbag[iterator] ) { // We pass the individual record as well as the entire contents of the foreach call, to be parsed // by the processor. By passing the individual record, our processor will know to use the passed // record for values within //console.log( record ); //console.log( superscript ); if( identifier ) { so += processor.parse( superscript, klay, klay.viewbag[iterator][record], identifier ); } else { so += processor.parse( superscript, klay, klay.viewbag[iterator][record], false ); } } return so; } return so; } if( fof === 'html' ) { // Here we need to apply logic for filtering iterated parses if( iteration ) { if( identification ) { return processor.decorate( fof, args, klay, memstring, iteration, identification ); } else { return processor.decorate( fof, args, klay, memstring, iteration, false ); } } else { return processor.decorate( fof, args, klay, memstring, false, false ); } } if( iteration ) { if( identification ) { //console.log( 'this one id: ' + iteration + ' id: ' + identification ); return processor.decorate( codeflow, codeflow, klay, "", iteration, identification ); } else { //console.log( 'this one noid: ' + iteration + ' id: ' + identification ); return processor.decorate( codeflow, codeflow, klay, "", iteration, false ); } } else { //console.log( 'this one noiterator: ' + iteration + ' id: ' + identification ); return processor.decorate( codeflow, codeflow, klay, "", false, false ); } } ); return o; }; /** * Returns the result of a subscript * * @param fof * @param args * @param klay * @param memstring * @param iteration * @param identification * * @since 0.2.4 */ renderer.prototype.decorate = function( fof, args, klay, memstring, iteration, identification ) { var processor = this; if( !iteration ) { iteration = false; //console.log( 'decor not iterated - ' + iteration ); } if( !identification ) { identification = false; //console.log( 'decor not identified - ' + identification ); } // Returns the output of the subscript switch( fof ) { case 'test': { return 'Test replacement worked!'; }break; case 'title': { return klay.viewbag.title; }break; case 'pagetitle': { return klay.viewbag.pagetitle; }break; case 'body': { return klay.view; }break; case 'date.year': { return this.date.getFullYear(); }break; case 'model': { return 'model'; }break; case 'html': { var rtools = processor.rtools, subscript = args, rargs = [], control = 0; // Strip our arguments subscript = subscript .replace //(((([a-zA-Z0-9_]*)(\.([a-zA-Z0-9_]*))*(\((.*)\))?[\}]?)|([\{](.*)\}))[\,]?)*/mg, ( /(((([a-zA-Z0-9_]*)(\.([a-zA-Z0-9_]*))*(\((.*)\))?[\}]?)|([\{](.*)\}))[\,]?)*/mg, function( match, match2, match3, noobjarg, method, memflow, member, argflow, argstring, objarg, objcontents ) { if( match3 ) { rargs[control] = match3; control++; } return ""; } ); // The memstring contained .<whatever members were present after html>, let's split it var members = memstring.split( '.' ); //console.log( members[0] + ' - ' + members[1] ); // Make sure the rendering tools support the requested method if( rtools._classmap.hasOwnProperty( members[1] ) ) { var memberparts = rargs[0].split( '.' ); if( memberparts[0] === 'model' ) { // We'll grab the display text value from the model's schema if( memberparts[1] ) { if( klay.model.schema.hasOwnProperty( memberparts[1] ) ) { rargs[0] = [ memberparts[1], klay.model ]; } else { console.log( 'Error: Unknown member: `[Model].' + memberparts[1] + '`.' ); rargs[0] = [ false, 'Unknown member: `[Model].' + memberparts[1] + '`.' ]; } } else { rargs[0] = [ false, 'Unknown member: `[Model].' + memberparts[1] + '`.' ]; } } else { // We'll literally pass what is requested from the viewbag if( klay.viewbag ) { var pcnt = 0, cnt; if( this.nk.type( memberparts ) === 'array' ) { pcnt = memberparts.length; } // We only support 3 deep here switch( pcnt ) { case 0: case 1: { if( pcnt == 0 ) { if( klay.viewbag.hasOwnProperty( memberparts ) ) { rargs[0] = [ memberparts, klay.viewbag[memberparts] ]; } else { if( memberparts ) { console.log( 'Error: Unknown member: `[' + memberparts + ']`.' ); rargs[0] = [ memberparts, memberparts ]; } else { console.log( 'Error: Invalid member: `[' + memberparts + ']`.' ); rargs[0] = [ false, 'Error: Invalid member: `[' + memberparts + ']`.' ]; } } } else { // pcnt MUST be 1 if( klay.viewbag.hasOwnProperty( memberparts[0] ) ) { rargs[0] = [ memberparts[0], klay.viewbag[memberparts[0]] ]; } else { if( memberparts[0] ) { console.log( 'Error: Unknown member: `[' + memberparts[0] + ']`.' ); rargs[0] = [ memberparts[0], memberparts[0] ]; } else { console.log( 'Error: Invalid member: `[' + memberparts[0] + ']`.' ); rargs[0] = [ false, 'Error: Invalid member: `[' + memberparts[0] + ']`.' ]; } } } }break; case 2: { if( klay.viewbag.hasOwnProperty( memberparts[0] ) ) { if( klay.viewbag[memberparts[0]].hasOwnProperty( memberparts[1] ) ) { rargs[0] = [ memberparts.join( '' ), klay.viewbag[memberparts[0]][memberparts[1]] ]; } else { if( memberparts[1] ) { console.log( 'Error: Unknown member: `[' + memberparts[0] + ']`.`[' + memberparts[1] + ']`.' ); rargs[0] = [ memberparts[1], memberparts.join( '' ) ]; } else { console.log( 'Error: Invalid member: `[' + memberparts[0] + ']`.`[' + memberparts[1] + ']`.' ); rargs[0] = [ false, 'Error: Invalid member: `[' + memberparts[0] + ']`.`[' + memberparts[1] + ']`.' ]; } } } else { if( memberparts[0] ) { console.log( 'Error: Unknown member: `[' + memberparts[0] + ']`.' ); if( memberparts[1] ) { console.log( 'Error: Unknown member: `[' + memberparts[0] + ']`.`[' + memberparts[1] + ']`.' ); rargs[0] = [ memberparts[1], memberparts.join( '' ) ]; } else { console.log( 'Error: Invalid member: `[' + memberparts[0] + ']`.`[' + memberparts[1] + ']`.' ); rargs[0] = [ false, 'Error: Invalid member: `[' + memberparts[0] + ']`.`[' + memberparts[1] + ']`.' ]; } } else { console.log( 'Error: Invalid member: `[' + memberparts[0] + ']`.`[' + memberparts[1] + ']`.' ); rargs[0] = [ false, 'Error: Invalid member: `[' + memberparts[0] + ']`.`[' + memberparts[1] + ']`.' ]; } } }break; case 3: { if( klay.viewbag.hasOwnProperty( memberparts[0] ) ) { if( klay.viewbag[memberparts[0]].hasOwnProperty( memberparts[1] ) ) { if( klay.viewbag[memberparts[0]][memberparts[1]].hasOwnProperty( memberparts[2] ) ) { rargs[0] = [ memberparts.join( '' ), klay.viewbag[memberparts[0]][memberparts[1]][memberparts[2]] ]; } else { console.log( 'Error: Unknown member: `[' + memberparts[0] + ']`.`[' + memberparts[1] + ']`.`[' + memberparts[2] + ']`.' ); rargs[0] = [ false, 'Error: Unknown member: `[' + memberparts[0] + ']`.`[' + memberparts[1] + ']`.`[' + memberparts[2] + ']`.' ]; } } else { console.log( 'Error: Unknown member: `[' + memberparts[0] + ']`.`[' + memberparts[1] + ']`.' ); rargs[0] = [ false, 'Error: Unknown member: `[' + memberparts[0] + ']`.`[' + memberparts[1] + ']`.' ]; } } else { if( memberparts[0] ) { console.log( 'Error: Unknown member: `[' + memberparts[0] + ']`.' ); if( memberparts[1] ) { console.log( 'Error: Unknown member: `[' + memberparts[0] + ']`.`[' + memberparts[1] + ']`.' ); if( memberparts[2] ) { console.log( 'Error: Unknown member: `[' + memberparts[0] + ']`.`[' + memberparts[1] + ']`.`[' + memberparts[2] + ']`.' ); rargs[0] = [ memberparts.join( '' ), memberparts.join( '' ) ] } else { console.log( 'Error: Invalid member: `[' + memberparts[0] + ']`.`[' + memberparts[1] + ']`.`[' + memberparts[2] + ']`.'); rargs[0] = [ false, 'Error: Invalid member: `[' + memberparts[0] + ']`.`[' + memberparts[1] + ']`.`[' + memberparts[2] + ']`.' ]; } } else { console.log( 'Error: Invalid member: `[' + memberparts[0] + ']`.`[' + memberparts[1] + ']`.`[' + memberparts[2] + ']`.' ); rargs[0] = [ false, 'Error: Invalid member: `[' + memberparts[0] + ']`.`[' + memberparts[1] + ']`.' ]; } } else { console.log( 'Error: Invalid member: `[' + memberparts[0] + ']`.`[' + memberparts[1] + ']`.`[' + memberparts[2] + ']`.' ); rargs[0] = [ false, 'Error: Invalid member: `[' + memberparts[0] + ']`.' ]; } } }break; default: { // pcnt is >= 4 console.log( 'Error: Only 3 chain links are allowed: `' + memberparts.join( '.' ) + '`.' ); rargs[0] = [ false, 'Only 3 chain links are allowed: `' + memberparts.join( '.' ) + '`.' ]; }break; } // Get length of memberparts and iterate over and send proper value if( klay.viewbag.hasOwnProperty( memberparts[0] ) ) { if( memberparts[1] ) { if( klay.viewbag[memberparts[0]].hasOwnProperty( memberparts[1] ) ) { rargs[0] = [ memberparts[1], klay.viewbag[memberparts[0]][memberparts[1]] ]; } else { console.log( 'Error: Unknown member: `[' + memberparts[0] + '].' + memberparts[1] + '`.' ); rargs[0] = [ false, 'Unknown member: `[' + memberparts[0] + '].' + memberparts[1] + '`.' ]; } } else { if( memberparts) rargs[0] = [ memberparts[0], klay.viewbag[memberparts[0]] ]; } } else { if( memberparts[0] ) { rargs[0] = [ memberparts[0], memberparts[0] ]; } else { rargs[0] = [ false, 'whoops' ]; } } } else { // Text value if( memberparts[0] ) { rargs[0] = [ memberparts[0], memberparts[0] ]; } else { rargs[0] = [ false, 'whoops' ]; } } } // And finally we invoke the requested method and pass it any arguments that it needs to return a string if( rargs[0] && rargs[1] ) { // Two args provided, parse second argument as a JSON string representation of an object rargs[1] = JSON.parse( rargs[1] ); subscript = rtools.generate( members[1], rargs[0], rargs[1] ); } else if( rargs[0] ) { // One arg provided subscript = rtools.generate( members[1], rargs[0] ); } else { // No args provided //console.log( '1: ' + rargs[0] + ', 2: ' + rargs[1] ); subscript = rtools.generate( members[1] ); } } else { // There just weren't any members which matched console.log( 'Error: Invalid script `html.' + members[1] + '`.' ); subscript = ""; } return String( subscript ); }break; default: { if( iteration ) { if( identification ) { if( fof ) { // We're already iterating over a viewbag item, the identification let's us know what word was used to signify the current iteration. var vbag = fof.split( "." ); //console.log( 'First is: ' + vbag[0] + ', and second is: ' + vbag[1] + ', and Identification is: ' + identification ); if( vbag[0].toString == identification.toString ) { //console.log( 'Were in here' ); if( iteration.hasOwnProperty( vbag[1] ) ) { return iteration[vbag[1]]; } else { return 'Does not exist: ' + iteration + '[' + vbag[1] + ']'; } } } return ''; } else { return 'Bad'; } } else { if( fof ) { return klay.viewbag[fof]; } return ''; } }break; } return 'Too bad...'; }; //Export module.exports = exports = renderer;