Update I want to avoid compiling the templates client-side, and have them compile during my local ant build process. Perhaps something like loading jQuery and jQuery templates into rhino, passing the $.template() function the contents of each .jst file in turn, and building a "templates.js" which should contain:
$.template['model-view'] = resultingFunction.toString();
// 1 for each .jst file
This way, I can maintain each template in a seperate file, and avoid having all clients redundantly compile the same template.
I'm using jQuery templates, and was hoping to separate them out into their own files (eg. model-view.jst) that are compiled into functions when the project is built and made available in the jQuery .tmpl() scope for later use.
For example, given the file model-view.jst
<li>${name}</li>
This file and all other .jst files should be picked up on build, compiled into a function that can later be used anywhere in the program like so:
$.tmpl('model-view', {
name: 'Matt'
});
I solved this problem using Node.js and coffeescript by making directory of partial templated into executable, pre-compiled functions. Hope this helps.
https://github.com/wookiehangover/jquery-tmpl-jst
I let you decide if you like it or not :)
in you common js library define this function:
function loadTemplate(templateName) {
$.ajax({
url: templateName + '.jst',
success: function(data) {
$.template(templateName, data);
}});
}
Then in you master hml file <head></head> section you can add:
<script type="text/javascript">loadTemplate('model-view');</script>
<script type="text/javascript">loadTemplate('another-model-view');</script>
so you can use anywhere in your code
$.tmpl('model-view', your-data)
$.tmpl('another-model-view', your-data)
Hope it helps
Related
While trying to split up my meteor application in separate packages I encountered a problem when trying to encapsulate templates. The package name would be gs-users:
packages/gs-users/package.js
Package.onUse(function(api) {
api.versionsFrom('1.1.0.2');
api.use('mquandalle:jade');
api.addFiles('views/list.jade');
api.addFiles('gs-users.js');
});
My template file packages/gs-users/views/list.jade:
template(name="GsUsersList")
p Ola seƱior!!
Inside my main applications route definition (lib/routes.js):
Router.route('/', function() {
this.render('GsUsersList');
});
Meteor now complains: Couldn't find a template named "GsUsersList" or "gsUsersList". Are you sure you defined it?
When using the templating package instead of mquandalle:jade and .html files instead of .jade files inside the gs-users package everything works fine. But I really hate plain HTML ;)
The solution is more simple than I thought. Just use waitingkuo:jade instead of mquandalle:jade and add templating as a dependency:
Package.onUse(function(api) {
api.versionsFrom('1.1.0.3');
api.use('waitingkuo:jade');
api.use('templating');
api.addFiles([
'le-template.jade',
], ['client']);
});
Works like a charm!
Using a version of what grunt-contrib-watch recommends for compiling only changed files in here: https://github.com/gruntjs/grunt-contrib-watch#compiling-files-as-needed
var changedFiles = Object.create(null);
var onChange = grunt.util._.debounce(function() {
grunt.config('jshint.all.src', Object.keys(changedFiles));
changedFiles = Object.create(null);
}, 200);
grunt.event.on('watch', function(action, filepath) {
changedFiles[filepath] = action;
onChange();
});
This works fine (again with a variation I wrote for it here: https://gist.github.com/pgilad/6897875)
The problem is when using include inside Jade templates, meaning you are including other Jade templates in order to build the complete html file.
Using the singular solution for compile doesn't work because if a .jade file you are working on is embeded using include current_working_jade.jade - the including file won't get recompiled.
Are there any workarounds for this besides compiling all of your jade files from scratch? This causes a problem when you have around ~60 large jade files to compile every time.
The only possible solution I can think of is either mapping jade templates dependencies either externally or with directories, but I don't know any tools/plugins which do that...
After already starting to work on a scaffold that will generate a sortof jade sourcemap I found this great project, that already solves this issue:
Jade Inheritance
Usage is as follows:
Install package using: npm install jade-inheritance --save-dev
Where you want to get a list of dependent files from a jade:
var JadeInheritance = require('jade-inheritance');
var inheritance = new JadeInheritance(file, basedirname, {basedir:basedirname});
Then when you want to get the file:
depenedentFiles = inheritance.files;
The project also demonstrates how to apply the concept with grunt.watch in order to compile only changed jade files with their dependents, exactly what I needed:
Using jade-inheritance with grunt watch
I imagine something like checking all jade files and if they include your changed file then recompile that as well. Shouldn't be too hard. Pseudo code:
var allFiles = getAllJadeFileWithIncludesAndProjectPathMap();
//allFiles now contains something like this
{
'jade/index.jade': ['jade/menu.jade', 'jade/home.jade'],
'jade/about.jade': ['jade/menu.jade']
}
var rootFiles = [];
_.each(allFiles, function (includes, parent) {
_.each(includes, function (includePath) {
var parent;
while (parent = getParentPath(includePath)) {
//nothing needed if getParentPath returns null for files that aren't included
}
if (rootFiles.indexOf(parent) !== -1) {
rootFiles.push(parent);
}
});
});
Now add these files to the compile task.
How can I get the current file name I'm in, using dojo.
I have a javascript file and my break point is within that file. I want to know the file name.
and using dojo or javascipt I want to get the name of this file
Any Help will be highly appreciated
Thank you
If you are using AMD (Dojo 1.7+) you can get the module ID of the current module from the special module module:
define([ 'module' ], function (module) {
console.log(module.id);
});
If using legacy Dojo modules, the filename of the script currently being executed is never provided and cannot be retrieved in a cross-browser way because they are loaded using XHR and eval.
There is an example of that in dojo/tests/_base/loader/moduleIds.js :
function get(mid, refmod){
return require.getModuleInfo(mid, refmod, require.packs, require.modules, "../../dojo/", require.mapProgs, require.pathsMapProg, 1);
}
I tried the following in one of my modules :
require.getModuleInfo("my/Module", null, require.packs, require.modules, "../../dojo/", require.mapProgs, require.pathsMapProg, 1).url
This resolved the path to the javascript file that contains my module code...
This works too :
require.modules["my/module"].url
I'm using requireJS to load scripts. It has this detail in the docs:
The path that is used for a module name should not include the .js
extension, since the path mapping could be for a directory.
In my app, I map all of my script files in a config path, because they're dynamically generated at runtime (my scripts start life as things like order.js but become things like order.min.b25a571965d02d9c54871b7636ca1c5e.js (this is a hash of the file contents, for cachebusting purposes).
In some cases, require will add a second .js extension to the end of these paths. Although I generate the dynamic paths on the server side and then populate the config path, I have to then write some extra javascript code to remove the .js extension from the problematic files.
Reading the requireJS docs, I really don't understand why you'd ever want the path mapping to be used for a directory. Does this mean it's possible to somehow load an entire directory's worth of files in one call? I don't get it.
Does anybody know if it's possible to just force require to stop adding .js to file paths so I don't have to hack around it?
thanks.
UPDATE: added some code samples as requested.
This is inside my HTML file (it's a Scala project so we can't write these variables directly into a .js file):
foo.js.modules = {
order : '#Static("javascripts/order.min.js")',
reqwest : 'http://5.foo.appspot.com/js/libs/reqwest',
bean : 'http://4.foo.appspot.com/js/libs/bean.min',
detect : 'order!http://4.foo.appspot.com/js/detect/detect.js',
images : 'order!http://4.foo.appspot.com/js/detect/images.js',
basicTemplate : '#Static("javascripts/libs/basicTemplate.min.js")',
trailExpander : '#Static("javascripts/libs/trailExpander.min.js")',
fetchDiscussion : '#Static("javascripts/libs/fetchDiscussion.min.js")'
mostPopular : '#Static("javascripts/libs/mostPopular.min.js")'
};
Then inside my main.js:
requirejs.config({
paths: foo.js.modules
});
require([foo.js.modules.detect, foo.js.modules.images, "bean"],
function(detect, images, bean) {
// do stuff
});
In the example above, I have to use the string "bean" (which refers to the require path) rather than my direct object (like the others use foo.js.modules.bar) otherwise I get the extra .js appended.
Hope this makes sense.
If you don't feel like adding a dependency on noext, you can also just append a dummy query string to the path to prevent the .js extension from being appended, as in:
require.config({
paths: {
'signalr-hubs': '/signalr/hubs?noext'
}
});
This is what the noext plugin does.
requirejs' noext plugin:
Load scripts without appending ".js" extension, useful for dynamic scripts...
Documentation
check the examples folder. All the info you probably need will be inside comments or on the example code itself.
Basic usage
Put the plugins inside the baseUrl folder (usually same folder as the main.js file) or create an alias to the plugin location:
require.config({
paths : {
//create alias to plugins (not needed if plugins are on the baseUrl)
async: 'lib/require/async',
font: 'lib/require/font',
goog: 'lib/require/goog',
image: 'lib/require/image',
json: 'lib/require/json',
noext: 'lib/require/noext',
mdown: 'lib/require/mdown',
propertyParser : 'lib/require/propertyParser',
markdownConverter : 'lib/Markdown.Converter'
}
});
//use plugins as if they were at baseUrl
define([
'image!awsum.jpg',
'json!data/foo.json',
'noext!js/bar.php',
'mdown!data/lorem_ipsum.md',
'async!http://maps.google.com/maps/api/js?sensor=false',
'goog!visualization,1,packages:[corechart,geochart]',
'goog!search,1',
'font!google,families:[Tangerine,Cantarell]'
], function(awsum, foo, bar, loremIpsum){
//all dependencies are loaded (including gmaps and other google apis)
}
);
I am using requirejs server side with node.js. The noext plugin does not work for me. I suspect this is because it tries to add ?noext to a url and we have filenames instead of urls serverside.
I need to name my files .njs or .model to separate them from static .js files. Hopefully the author will update requirejs to not force automatic .js file extension conventions on the users.
Meanwhile here is a quick patch to disable this behavior.
To apply this patch (against version 2.1.15 of node_modules/requirejs/bin/r.js) :
Save in a file called disableAutoExt.diff or whatever and open a terminal
cd path/to/node_modules/
patch -p1 < path/to/disableAutoExt.diff
add disableAutoExt: true, to your requirejs.config: requirejs.config({disableAutoExt: true,});
Now we can do require(["test/index.njs", ...] ... and get back to work.
Save this patch in disableAutoExt.diff :
--- mod/node_modules/requirejs/bin/r.js 2014-09-07 20:54:07.000000000 -0400
+++ node_modules/requirejs/bin/r.js 2014-12-11 09:33:21.000000000 -0500
## -1884,6 +1884,10 ##
//Delegates to req.load. Broken out as a separate function to
//allow overriding in the optimizer.
load: function (id, url) {
+ if (config.disableAutoExt && url.match(/\..*\.js$/)) {
+ url = url.replace(/\.js$/, '');
+ }
+
req.load(context, id, url);
},
The patch simply adds the following around line 1887 to node_modules/requirejs/bin/r.js:
if (config.disableAutoExt && url.match(/\..*\.js$/)) {
url = url.replace(/\.js$/, '');
}
UPDATE: Improved patch by moving url change deeper in the code so it no longer causes a hang after calling undef on a module. Needed undef because:
To disable caching of modules when developing with node.js add this to your main app file:
requirejs.onResourceLoad = function(context, map)
{
requirejs.undef(map.name);
};
We have extended/customized dojo for our projects inside the company. our toolkit is called xwt.
I am considering making a copy of the sample file that is part of the toolkit into a local directory and start using it. So, I copied the SampleExtendedIFWS.js file into the local directory and changed the namespace it uses from dojo.provide("xwt.widget.tests.table.store.SampleExtendedIFWS") to dojo.provide("SampleExtendedIFWS").
From my application page(jsp), I started using dojo.require("SampleExtendedIFWS") -- however, now it is expecting the file from /app/resources/dojoroot/SampleExtendedIFWS.js and not the local directory.
How can I make dojo/xwt take the local directory version of SampleExtendedIFWS.js instead of expecting from /app/resources/dojoroot/SampleExtendedIFWS.js ?
Anjan
you need to specify your own namespace else it will look into dojoroot.
so at the same level as where you have dojo and xwt, you can create your own directory, lets say anjanb and put your SampleExtendedIFWS.js and change the dojo.provide to call it anjans.SampleExtendedIFWS
Now, in your sample HTML, you need to specify the module path in djConfig. For example:
djConfig = {
isDebug: false,
debugAtAllCosts: false,
parseOnLoad: true,
baseUrl: "<path to where your dojo.js resides>",
modulePaths: {
'xwt': '../xwt',
'anjans' : '../anjans'
}
};
Note that the module path is always relative to where dojo.js resides
do a dojo.require of your object:
dojo.require ("anjans.SampleExtendedIFWS");
this should get you going
btw, If you wish to extend the functionality, dojo provides more elegant mechanisms to extend the object instead of copying and changing by using dojo.extend, for example.