Thanks for this info, Marius.
To get started with Lift I'm reading through the excellent book
"Exploring Lift" you wrote with Eric and Tyler (version 27 July 2009),
plus the source for the PocketChange app and liftweb, downloaded from
GitHub.
As I'm still finding my way through the various packages and file
locations, I hope you can bear with me a bit while I think out loud
here to make sure I understand where to put the .js files and the
references for JavaScript resources which aren't integrated into
lift.
***********************************************************
The only real question I have is way down towards the end of this
message, at the end of point (a):
"Where do I put the 'toserve' directory, and how do I make sure that
Maven uses it?"
Feel free to skip most of this lengthy message and just read point (a)
which is the only real question I have. I'm still just getting used to
Maven and how it pulls files from various locations either locally or
online.
***********************************************************
(1) Searching in directory C:\www\work\PocketChange\ (I'm currently
serving lift web apps just locally, running Jetty under Windows), I
see several .js files for JQuery:
date.js
jquery.datePicker.js
jquery.tablesorter.min.js
jquery-ui.min.js
in directory:
C:\www\work\PocketChange\src\main\webapp\scripts\
So it looks like I could put any needed .js files in that directory.
Searching for the string ".js" *inside* all .html files in directory C:
\www\work\PocketChange, I find the file:
C:\www\work\PocketChange\src\main\webapp\index.html
which contains the tag:
<script type="text/javascript" src="/scripts/jquery-ui.min.js"></
script>
referencing the file:
jquery-ui.min.js
in directory C:\www\work\PocketChange\src\main\webapp\scripts\ above.
So again it looks like I can put any needed .js files in that
directory, and reference them in the app's .html file(s) as shown
above.
(One strange minor thing I noticed: if I search inside all .html files
in directory C:\www\work\PocketChange\ for the string "datePicker.js",
it only shows up in lines that have been commented out. So one minor
curiosity I have is: how is the code for datePicker.js being used?
There appears to be a definition of it in jquery-ui.min.js, as well as
a more readable definition of it in datePicker.js as well. I
understand that JavaScript files are "minified" to remove unnecessary
characters - does jquery-ui.min.js include the "minified" version of
datePicker? Is file datePicker.js never sent to the browser?)
(2) The search for the string ".js" inside all .html files also turned
up two occurences in file:
C:\www\work\PocketChange\src\main\webapp\templates-hidden\default.html
in the tags:
<script id="jquery" src="/classpath/jquery.js" type="text/
javascript"></script>
<script id="json" src="/classpath/json.js" type="text/javascript"></
script>
These seem to be referring not to individual JavaScript widgets - but
maybe to entire JavaScript libraries.
I couldn't find any relevant files called "jquery.js" on my machine -
but reading section 7.8 "Resource Server" in the "Exploring Lift" book
(pp. 119-120) I see it says that Maven puts .css (and presumably .js)
resources to be served *inside* the WAR/JAR file, and lift uses the
var LiftRules.resourceServerPath:
var resourceServerPath = "classpath"
to find these resources.
The book goes on to say that in order to find a .css resource in a
subdirectory such as:
<my-project>\src\main\resources\toserve\css\mystyle.css
I would call the following in Boot:
ResourceServer.allow {
case "css" :: _ => true
}
So, examining the lift source code for object ResourceServer in
package net.liftweb.http (in directory ...\liftweb\lift\src\main\scala
\net\liftweb\http\), I think I see how this is all put together:
object ResourceServer {
private var allowedPaths: PartialFunction[List[String], Boolean] = {
case "jquery.js" :: Nil => true
case "yui" :: _ => true
case "liftYUI.js" :: Nil => true
case "json2.js" :: Nil => true
case "json.js" :: Nil => true
case "jlift.js" :: Nil => true
case bp @ ("blueprint" :: _) if bp.last.endsWith(".css") ||
bp.last.endsWith(".png") => true
case "jquery-autocomplete" :: "jquery.autocomplete.js" :: Nil =>
true
case "jquery-autocomplete" :: "jquery.autocomplete.css" :: Nil =>
true
case "jquery-autocomplete" :: "indicator.gif" :: Nil => true
}
//...
var baseResourceLocation = "toserve"
//...
def allow(path: PartialFunction[List[String], Boolean]) {
allowedPaths = path orElse allowedPaths
}
}
Looking at the lift source from GitHub, I see that there are 6
subdirectories and files:
blueprint\
yui\
jlift.js
jquery-1.3.2.js
json2.js
liftYUI.js
(the JavaScript base libraries?), in directory:
...\liftweb\lift\src\main\resources\toserve\
These correspond to the first 6 clauses in the case statement in
object ResourceServer.
(I can see that the wildcard in "yui" :: _ and "blueprint" :: _
represents possible further Strings in the List, indicating that these
are *subdirectories* - versus *files* which are indicated by a one-
element List such as "jquery.js" :: Nil.)
And looking at the source for PocketChangeApp also from GitHub, I
already saw that there are JavaScript files:
date.js
jquery.datePicker.js
jquery.tablesorter.min.js
jquery-ui.min.js
(for individual widgets?) in directory:
...\PocketChange\src\main\webapp\scripts\
so this is where the JavaScript for any individual widgets would go.
So this is my overall plan:
(a) Following the instructions here:
http://extjs.com/learn/Ext_Getting_Started
or on page 20 of the book "Practical Ext JS Projects with Gears" from
Apress by Frank Zammetti, I would reference the additional libraries
by modifying the suggested tags:
<script type="text/javascript" src="extjs/adapter/ext/ext-base.js"></
script>
<script type="text/javascript" src="extjs/ext-all.js"></script> <!--
or my choice of files -->
to read something like:
<script type="text/javascript" src="classpath/ext-base.js"></script>
<script type="text/javascript" src="classpath/ext-all.js"></script>
<!-- or my choice of files -->
and putting these tags in the file:
<my-project>\src\main\webapp\templates-hidden\default.html
and placing the JavaScript libraries themselves in the toserve
directory described on page 120 of "Exploring Lift".
Now here's where I have a question...
************************* QUESTION *************************
Which of 2 possible toserve directories below should I put the .js
files in?
<my-project>\src\main\resources\toserve\
or
...\liftweb\lift\src\main\resources\toserve\
I'm concerned that lift will search only in its own toserve directory:
...\liftweb\lift\src\main\resources\toserve\
Should I put additional files in there? Can I?
On the one hand, I'm not sure if I *should* put any additional files
in the liftweb project - and from my understanding of how Maven works
online (reading dependencies in the project's pom.xml file), I'm not
sure if I even *can*.
As far as I know, Maven running in online mode gets liftweb from
liftweb.net online - so I don't think I even can add a file to the
directory:
...\liftweb\lift\src\main\resources\toserve\
because I don't want to add anything on GitHub (I'm far from being a
committer!) and I don't understand how I could create a local copy of
lift for Maven to use and add things to that local copy.
If I add a JavaScript file to a directory in my *project*:
<my-project>\src\main\resources\toserve\
then will ResourceServer.allow look in there? Somehow I don't think so
- I think it looks in *liftweb's* directory:
...\liftweb\lift\src\main\resources\toserve\
I guess a third possibility might be downloading the liftweb source
from GitHub, adding any additional JavaScript libraries to the local
copy of the liftweb directory which I'm assuming ResourceServer always
looks in:
...\liftweb\lift\src\main\resources\toserve\
(ie, the directory belonging to the liftweb project, not to my
project), and then running Maven in offline mode (so it won't pull
updates from
liftweb.net), or maybe modifying the pom.xml for my
project only for the liftweb dependency, to instruct Maven to use the
local, augmented copy of liftweb rather than the online one from
liftweb.net.
But maybe I'm making things more complicated than they need to be here
- so this is the question where I could use some additional help:
>>> Where do I put the toserve directory, and how do I make sure that Maven uses it? <<<
************************************************************
Continuing...
(b) I would reference .js files for individual JavaScript widgets in
specific .html files as needed, say:
<my-project>\src\main\webapp\index.html
and place them in the directory:
<my-project>\src\main\webapp\scripts\
(c) As Marius stated above (and as I now see in section 8.2 "JQuery
and other JavaScript frameworks" in "Exploring Lift", page 129), I
would implement the trait net.liftweb.http.js.JsArtifacts in a class
like ExtJsArtifacts and then reference it in Boot.
This trait net.liftweb.http.js.JsArtifacts has method signature:
def toggle(id: String): JsExp
def hide(id: String): JsExp
def show(id: String): JsExp
def showAndFocus(id: String): JsExp
def serialize(id: String): JsExp
def setHtml(id: String, xml: NodeSeq): JsCmd
def onLoad(cmd: JsCmd): JsCmd
def ajax(data: AjaxInfo): String
def comet(data: AjaxInfo): String
def jsonStringify(in: JsExp) : JsExp
def formToJSON(formId: String): JsExp
and it looks straightforward to use
net.liftweb.http.js.jquery.JQueryArtifacts and
net.liftweb.http.js.yui.YUIArtifacts as "models" for implementing
something like net.liftweb.http.js.extjs.ExtJsArtifacts.
(d) In Boot, I would do the following:
import net.liftweb.http.js.extjs.ExtJSArtifacts
class Boot {
def boot = {
//...
LiftRules.jsArtifacts = ExtJSArtifacts
//...
}
//...
ResourceServer.allow {
case "css" :: _ => true
case "extjs" :: _ => true
}
}
as explained on pages 120 and 129 of "Exploring Lift".
The code in ResourceServer.allow above assumes creating a directory
extjs under toserve.
Again, as mentioned in (a) above, I'm not sure if toserve would be
placed in a local copy of liftweb which I can somehow force Maven to
use:
...\liftweb\lift\src\main\resources\toserve\
or if I should create a toserve directory inside my project and tell
lift to look there:
<my-project>\src\main\resources\toserve\
Sorry this has been so long-winded - as I learn more about lift, I'll
feel more comfortable saying less rather than more in these messages.
Right now I'm erring on the side of spelling everything out, to make
sure I'm not getting anything wrong.
Thanks for pointing me in the right direction!