Permalink
Browse files

Add js, package.json

  • Loading branch information...
1 parent a74623f commit c6066e4e6630f1740ac439ad5aec17828cb5b5b1 adamstallard committed Jul 20, 2012
Showing with 468 additions and 0 deletions.
  1. +3 −0 .hgignore
  2. +140 −0 ModestCompiler.js
  3. +222 −0 modest-preview.js
  4. +75 −0 modest.js
  5. +28 −0 package.json
View
@@ -0,0 +1,3 @@
+^node_modules$
+^nbproject$
+
View
@@ -0,0 +1,140 @@
+// globals required by preview.js
+
+fs = require('fs');
+$ = null;
+
+// required modules
+
+var jsdom = require('jsdom');
+var async = require('async');
+var _ = require('underscore');
+
+function ModestCompiler(params){
+ this.params = params;
+ this.scripts = [];
+ if(this.params.jqueryPath)
+ this.scripts.push(this.params.jqueryPath);
+ else
+ $ = require('jquery');
+ require('./' + this.params.previewScript);
+ _.bindAll(this);
+}
+
+ModestCompiler.prototype = {
+ setPath : function(path){
+ this.path = path;
+ this.resetModest();
+ },
+ resetModest : function(){
+ modest.reset();
+ },
+ compileFile : function(file,callback){
+ console.log('compiling ' + this.path + file);
+ jsdom.env(file,
+ this.scripts,
+ function(errors, window) {
+ var script, head, includes, previewScriptTags, output;
+
+ if(errors)
+ callback(errors);
+ else {
+ try{
+ modest.setWindow(window);
+ modest.loadModules();
+ modest.compileModules();
+ modest.compileNode($(document.body));
+
+ // remove the modest includes
+
+ head = window.document.getElementsByTagName('head')[0];
+ includes = head.getElementsByTagName('include');
+
+ _.each(includes,function(node){
+ head.removeChild(node);
+ });
+
+ // remove any modest-preview script tags
+
+ previewScriptTags = window.document.evaluate(
+ "//script[@src='" + this.params.previewScript + "']", head, null, 0);
+
+ _.each(previewScriptTags._value.nodes, function(node){
+ head.removeChild(node);
+ });
+
+ // remove any jquery script tags inserted by jsdom
+
+ $('script.jsdom').remove();
+
+ // add a script tag with a reference to 'modest.js', if needed
+
+ if(!_.isEmpty(modest.saveAsJs)){
+ script = window.document.createElement('script');
+ script.src = 'modest.js';
+ insertAfter(window.document.body, script);
+ }
+
+ // write the compiled xhtml out to a file (minus the '-pre')
+
+ output = window.document.innerHTML.replace(/\s+/g,' ');
+ fs.writeFileSync(this.path + file.replace(/-pre(\..+)?$/,'$1'),output);
+ }
+ catch(e){
+ callback(e);
+ }
+ callback();
+ }
+ }.bind(this));
+ },
+ writeModestJs : function(){
+
+ // Save the modules requested for use with JS
+
+ var module, modestJs, moduleDefinition;
+ var savedModules = '';
+
+ for (module in modest.saveAsJs){
+ moduleDefinition = modest.modules[module].replace(/\s+/g,' ') + "';\n";
+ savedModules += 'modest.modules.' + module + " = '" + moduleDefinition;
+ }
+
+ if(savedModules !== ''){
+
+ // Take out everything that isn't needed from the modest object
+
+ modestJs = fs.readFileSync(this.params.previewScript,'utf8');
+ modestJs = modestJs.replace(/\/\/#REMOVE-POST-COMPILE[\s\S]*?\/\/#!REMOVE-POST-COMPILE/g,'');
+
+ // Write the saved modules and the modest object to modest.js
+
+ fs.writeFileSync(this.path + 'modest.js', modestJs + savedModules);
+ }
+ },
+ compileFiles : function(){
+ var f, files;
+ var compile = [];
+
+ files = fs.readdirSync(this.path);
+
+ // compile the files in series so dependency detection works
+
+ for (f in files){
+ if(files[f].indexOf('-pre.') != -1 || files[f].indexOf('-pre') - files[f].length == 4)
+ compile.push(async.apply(this.compileFile, files[f]));
+ }
+
+ async.series(compile,function(err){
+ if(err)
+ throw(err);
+ else
+ this.writeModestJs();
+ }.bind(this));
+ }
+};
+
+function insertAfter(referenceNode, newNode)
+{
+ referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
+}
+
+module.exports = ModestCompiler;
View
@@ -0,0 +1,222 @@
+modest = this.modest || {
+ modules : {}, // compiled modules as strings
+ //#REMOVE-POST-COMPILE
+ $uncompiled : {}, // uncompiled modules as jquery objects
+ compiled : {}, // set {X:X} -- names of modules that have been compiled
+ saveAsJs : {}, // set {X:X} -- names of modules needed for js
+ setWindow : function(w){
+ window = w;
+ document = w.document;
+ if(w.$) $ = w.$;
+ modest.nodejs = true;
+ },
+ reset : function(){
+ modest.modules = {};
+ modest.$uncompiled = {};
+ modest.compiled = {};
+ modest.saveAsJs = {};
+ },
+ loadModules : function(){
+ var includes = document.getElementsByTagName('head')[0].getElementsByTagName('include');
+ var path, pathAttr, moduleName, moduleContent;
+
+ for(var i = 0; i < includes.length; ++i){
+
+ // Assume the include tag has a single text node with the name of the module
+
+ moduleName = includes[i].childNodes[0].nodeValue;
+
+ // Remove leading and trailing whitespace from the module name
+
+ moduleName = moduleName.replace(/^\s+/, '').replace(/\s+$/, '');
+
+ if(!modest.compiled[moduleName]){
+ path = '';
+ pathAttr = includes[i].getAttribute('path');
+ if(pathAttr){
+
+ // Remove trailing slashes and whitespace from the "path" attribute; Add one slash
+
+ path = pathAttr.replace(/[\/\\\s]+$/,'') + '/';
+ }
+
+ path += moduleName;
+
+ // Append ".xml" if the path doesn't already end with it
+
+ path = path.replace(/\.xml$/,'') + '.xml';
+
+ if(modest.nodejs){
+ moduleContent = fs.readFileSync(path,'utf8');
+ }
+ else{
+ moduleContent = $.ajax({
+ url: path,
+ async : false
+ }).responseText;
+ }
+ modest.$uncompiled[moduleName] = $(moduleContent);
+ }
+
+ if(includes[i].hasAttribute('js')){
+ modest.saveAsJs[moduleName] = moduleName;
+ }
+ }
+
+ },
+ compileNode : function($node,modules){
+ if(!modules)
+ modules = modest.compiled;
+ modest.compileTemplate($node,modules);
+
+ // Clean up: remove 'uses' attributes
+
+ $node.find('[uses]').removeAttr('uses');
+ },
+ compileModules : function(){
+ var dependencies = {};
+ var compiledCount = 0;
+ var numModules = 0;
+ var waitToCompile, module, otherModule, lastCompiledCount;
+
+ function loopError(){
+ var badModules = '';
+
+ for (var module in modest.$uncompiled){
+ if(!modest.compiled[module])
+ badModules += module + ' ';
+ }
+
+ throw ('Infinite loop detected in modules: ' + badModules);
+ }
+
+ function compileModule(module){
+ var $module = modest.$uncompiled[module];
+ modest.compileTemplate($module, dependencies[module]);
+ if($module[0].outerHTML)
+ modest.modules[module] = $module[0].outerHTML;
+ else
+ modest.modules[module] = new XMLSerializer().serializeToString($module[0]);
+ modest.$uncompiled[module] = false;
+ modest.compiled[module] = module;
+ }
+
+ for (module in modest.$uncompiled){
+ ++numModules;
+ if(!modest.compiled[module]){
+ dependencies[module] = [];
+
+ for (otherModule in modest.$uncompiled){
+ if(modest.$uncompiled[module].find(otherModule).length)
+ dependencies[module].push(otherModule);
+ }
+
+ }
+ }
+
+ while(compiledCount < numModules){
+ lastCompiledCount = compiledCount;
+
+ for (module in modest.$uncompiled){
+ if(modest.compiled[module]){
+ ++compiledCount;
+ continue;
+ }
+ waitToCompile = false;
+
+ for (var d in dependencies[module]){
+ if(!modest.compiled[dependencies[module][d]]){
+ waitToCompile = true;
+ break;
+ }
+ }
+
+ if(!waitToCompile){
+ compileModule(module);
+ ++compiledCount;
+ }
+ }
+
+ if(lastCompiledCount == compiledCount)
+ loopError();
+ }
+
+ },
+ compileTemplate : function($template, modules){
+
+ $.each(modules, function(i,module){
+
+ // find and compile module instances in the template
+
+ $template.find(module).each(function(){
+ modest.compile($(this),module,true);
+ });
+ });
+
+ },
+ //#!REMOVE-POST-COMPILE
+ compile : function($instance,module){
+ var parameters = {};
+ var usesParameters = {};
+
+ // read the parameters from the instance
+
+ $instance.children().each(function(){
+ var param = this;
+ parameters[param.tagName.toLowerCase()] = param.innerHTML;
+ if(param.hasAttribute('uses'))
+ usesParameters[param.tagName.toLowerCase()] = param.innerHTML;
+ });
+
+ $instance.html(modest.modules[module]);
+ $instance = $instance.children(':first').unwrap();
+ $instance.addClass(module);
+
+ $instance.find('[uses]').each(function(){
+ var $target = $(this);
+ var uses = $target.attr('uses').toLowerCase().split(' ');
+ var eq, param, u, attr;
+
+ for(u = 0; u < uses.length; ++u){
+ eq = uses[u].indexOf('=');
+ if(eq === -1){
+ if(usesParameters[uses[u]])
+ $target.attr('uses',usesParameter[uses[u]]);
+ else if(parameters[uses[u]]){
+ $target.html(parameters[uses[u]]).addClass(uses[u]);
+ }
+ }
+ else {
+ attr = uses[u].slice(0,eq);
+ param = uses[u].slice(eq+1);
+ if(parameters[param])
+ $target.attr(attr,parameters[param]);
+ }
+ }
+
+ });
+
+ },
+ html : function(module,parameters){
+ var $instance = $('<' + module + '>');
+ var paramEl;
+
+ for (var param in parameters){
+ paramEl = document.createElement(param);
+ paramEl.innerHTML = parameters[param];
+ $instance.append(paramEl);
+ }
+
+ modest.compile($instance,module);
+ return $instance[0].outerHTML;
+ }
+};
+//#REMOVE-POST-COMPILE
+if(this.window){
+ $(function(){
+ modest.loadModules(window);
+ modest.compileModules();
+ modest.compileNode($(document.body));
+ });
+}
+//#!REMOVE-POST-COMPILE
Oops, something went wrong.

0 comments on commit c6066e4

Please sign in to comment.