Rationale
With the release of MAX 6 I'm restarting the process of rethinking what Im doing with Javascript, and aim to refactor things a bit more sensibly a la Crockford, maybe by hijacking bits of Google's Closure.
However, in the interim, I still need a cheap-n-cheerful include mechanism, so Im back with the one I started with, a very simple dump of all the lines of code from a file into a buffer, with an eval at the end. Ive renamed it crudeinclude since it is indeed pretty crude. Its probably not that well-written either, to be honest.
Implementation
Part of the post-MAX6-tidy means that I've split it into two parts so that I can use multiple versions of it with multiple versions of MAX without editing the javascript that actually does the work, and renamed the files with a 'sxa.jsextension' class-hierarchy prefix a la goog.closure. Hence there's a now a sxa.jsextensions.crudeinclude.js file file and a sxa.jsextensions._setenv_includes_.js, with the latter declaring 'environment variables' used by the include routine. Both of these .js files need to be located the Cycling '74\jsextensions folder so that they're loaded automatically when MAX starts up.
file path : This include mechanism is based on the cpp #define
style, so there are two formats for the filename argument.
The first, the 'direct' form "localIncludeLibrary2"
, uses the same directory as the including code as the included file's expected root folder. The second format, the 'angle-bracket' format "<siteIncludeLibrary1>"
uses a global 'library folder' as the included file's expected root folder. This library folder is defined by the path set in SXA_JS_INCLUDEPATH
mock 'environment variable, which should normally be initialised when MAX starts via the code in sxa.jsextensions._setenv_includes_.js
file suffix : The code has been written to try and open a file suffixed with .c.js first, or, if that does not exist, then it defaults to a version with the .js suffix. This was implemented to allow a speed up in file reading and eval-ing; the .c.js is expected to be a 'minified' or 'compressed' version of the original javascript. Originally a simple comment-and-whitespace stripper was developed to do this, but something like JSMIN or the Google closure compiler could be used instead.
examples
If SXA_JS_INCLUDEPATH
is set to U:\MAX6\global then the following filename arguments to crudeinclude when called from a javascript file U:\MAX\project\example\example.js will result in crudeinclude trying to read the following files in the order described:
"localLibrary"
:
U:\MAX\project\example\localLibrary.c.js
then
U:\MAX\project\example\localLibrary.js
"<siteLibrary>"
:
U:\MAX6\global\siteLibrary.c.js
then
U:\MAX6\global\siteLibrary.js
code
This javascript, sxa.jsextensions._setenv_includes_.js, does the setup:
1: //sxa.jsextensions._setenv_includes_ v0.2
2: //------------------------------------------------------------------------
3: // 'environment variables' for sxa.jsextensions.crudeinclude
4: //------------------------------------------------------------------------
5: // v0.2 : 21.11.2011 : add SXA_JS_INCLUDEBUFFER variable
6: //------------------------------------------------------------------------
7: // useage : this file to be located in Cycling '74/jsxtensions
8: //
9: //----------------------------------------------------------------------------------------
10: var SXA_JS_INCLUDEPATH="U:_MAX6_\\site\\jsincludes\\";
11: var SXA_JS_INCLUDEBUFFER = 800;
And this javascript, sxa.jsextensions.crudinclude.js, does all the work:
1: //sxa.jsextensions.crudeinclude v0.5
2: //------------------------------------------------------------------------
3: // simple brute-force javascript include mechanism for jsextensions folder
4: //------------------------------------------------------------------------
5: // v0.5 : 23.11.2011 : tidying, better comments, add SXA_JS_INCLUDEBUFFER
6: // variable and changed '.h.js' form to '.c.js'
7: //------------------------------------------------------------------------
8: // useage : this file to be located in Cycling '74/jsxtensions
9: //
10: // crudeinclude takes the suffix-less name of a javascript file, and loads that
11: // file into a buffer for eval() to interpret.
12: // crudeinclude is modelled after the cpp #include directive so takes two forms,
13: // the angle-bracket form, which expects the source file to be in a folder defined
14: // by the SXA_JS_INCLUDEPATH 'pseudo-environment variable' and the direct form, which
15: // expects the source file to be in the same folder as the 'parent' javascript file
16: // doing the include.
17: // crudeinclude has been written to search for a file suffixed with .c.js first, -before-
18: // checking for a version with the .js suffix. This was done to speed up file reading;
19: // the .c.js is expected to be a 'compressed' or 'compiled' version of the file
20: // (as per the Google closure compiler) which contains a stripped and cleaned version of the
21: // original javascript.
22: //
23: // buffer = crudeinclude("<siteInclude>"); // includes siteInclude.c.js located in path SXA_JS_INCLUDEBUFFER
24: // buffer = crudeinclude("<localInclude"); // includes localInclude.js located in same path as calling code
25: //
26: //------------------------------------------------------------------------
27: crudeinclude.local = 1;
28: function crudeinclude(filename){
29: var includes ="";
30: var compressedType = ".c.js";
31: var rawType = ".js";
32: length = filename.length;
33: // determine possible full path names for filename
34: if ((filename.substring(0,1) == "<")){ // '<' indicates possible global library name
35: if ((filename.substring(length-1,length) == ">")){ // '>' confirms well-formed global library name
36: base_filename = SXA_JS_INCLUDEPATH + filename.substring(1,length-1);
37: compiled_filename = base_filename + compressedType;
38: raw_filename = base_filename + rawType;
39: }else{ //badly formed global
40: post("ERROR in include; malformed filename '",filename, "'\n");
41: return;
42: }
43: }else{ // ! == "<"
44: if ((filename.substring(length-1,length) == ">")){ //<..> not matched, so badly formed include
45: post("ERROR in include; malformed filename '",filename, "'\n");
46: return;
47: }else{ // ! == ">" so not <...> form, thus a local filename
48: compiled_filename = filename + compressedType;
49: raw_filename = filename + rawType;
50: }// done checking angle brackets
51: }// done determining path and name options
52: // open file to copy into a string
53: // prioritise the compiled version first
54: file = new File(compiled_filename, "read");
55: file.open();
56: if (!(file.isopen)){
57: file = new File(raw_filename, "read");
58: file.open();
59: }
60: if (file.isopen){
61: // read in lines of up to 120 chars at a time
62: //(compensates for strange filesize/buffer issue)
63: // this is probably slower,
64: //but strings get weirdly truncated otherwise.
65: fileposition = 0;
66: while (fileposition < file.eof){
67: includes += file.readline(SXA_JS_INCLUDEBUFFER);
68: includes += "\n";
69: fileposition = file.position;
70: }// end while
71: file.close();
72: }else{// file not open
73: post("ERROR in include; cannot open ", filename, "\n");
74: }
75: return(includes);
76: }// end function include
Basically this returns a buffer containing the code from an external javascript file. The
file can then be interpreted via eval
from within the code of a js or jsui object.
useage : A simple way of using this include code in javascript would be
eval(crudeinclude("<siteIncludeLibrary1>"));
eval(crudeinclude("localIncludeLibrary2"));
or
includeBuf = (crudeinclude("<siteIncludeLibrary1>"));
includeBuf += (crudeinclude("localIncludeLibrary2"));
eval(includeBuf);