Admittedly I am still a novice at Dojo, and I have always been weak at Javascript, so excuse and sloppy code or language here.
I am using Dojo 1.7.1 with Spring Roo 1.2.1RELEASE. I am loading Dojo through CDM from Google.
I some time ago I created a custom image thumbnail viewer to use on my site, which I include by adding a module to my djConfig in Spring Roo's load-scripts.tagx, which gets ran on each page load. The thumbnail Widget does not follow the AMD pattern, because at the time I couldn't get it to work right.
Here is the djConfig:
<script type="text/javascript">
var djConfig = {
parseOnLoad: false,
isDebug: false,
locale: '${fn:toLowerCase(userLocale)}',
modulePaths: {
"message": "${message_dojo_url}",
"img.ArtThumbnailWidget": "${artThumbnailWidget_dojo_url}",
"img.ArtTableWidget": "${artTableWidget_dojo_url}",
},
};
</script>
Here is the JS for the thumbailer:
// img.ArtThumbnailWidget
dojo.provide("img.ArtThumbnailWidget");
dojo.require("dojo._base.declare");
dojo.require("dojo.parser");
dojo.require("dojo.ready");
dojo.require("dijit._WidgetBase");
dojo.require("dijit._TemplatedMixin");
dojo.require("dojox.image.LightboxNano");
// Create the widget
require([
"dojo/_base/declare",
"dojo/parser",
"dojo/ready",
"dijit/_WidgetBase",
"dijit/_TemplatedMixin",
"dojo/dom",
"dojo/dom-construct",
"dojo/on",
"dojo/text!img/ArtThumbnailWidget/templates/ArtThumbnailWidget.html",
"dojox/image/LightboxNano",
"dojo/domReady!"
], function(declare, parser, ready, _WidgetBase, _TemplatedMixin, dom, domConstruct, on, template) {
dojo.declare("img.ArtThumbnailWidget",[dijit._WidgetBase, dijit._TemplatedMixin], {
/* Our properties will go here */
// Art JSON object, default is null
art: null,
// Viewer ID (the username of the person looking at this image), which will default to null
viewerId: null,
// maxThumbnailSize is how large of an image to return for the thumbnail. The back-end will resize the thumbnail accordingly
maxThumbnailSize: 100,
// maxImageSize is how large of an image to return for the LightboxNano. The back-end will resize the image accordingly
maxImageSize: 500,
// Our template - important!
templateString: template,
// A class to be applied to the root node in our template
baseClass: "artThumbnailWidget",
// Specifies there are widgets in the template itself that need to be rendered as well
widgetsInTemplate: true,
// Competition-related vars
competitionUrlBase: null,
competitionButtonIconUrl: null,
/* This is called once the DOM structure is ready, but before anything is shown */
postCreate: function() {
// Get a DOM node reference for the root of our widget
var domNode = this.domNode;
// Run any parent postCreate processes - can be done at any point
this.inherited(arguments);
if(this.art!=null && this.viewerId!=null && this.art.owner.name == this.viewerId) { // If the view is the owner, add the toolbar
// TODO: We need to clean this up, make it "prettier", and make the URLs more generic
var toolbarNode = domConstruct.create("div", {}, this.containerNode);
if(this.competitionUrlBase!=null) {
var url = this.competitionUrlBase;
if(url.indexOf('?')<0) { // URL does not have a '?'
url = url+"?";
} else { // URL has a '?', so we need to tack on and additional '&'
url = url+"&";
}
url = url+"username="+this.art.owner.name+"&artPieceId="+this.art.id;
var compButtonNode = domConstruct.create("a",
{
href: url,
},toolbarNode);
var compButtonImg = domConstruct.create("img",
{
src: this.competitionButtonIconUrl,
width: this.maxThumbnailSize/4,
height: this.maxThumbnailSize/4,
},compButtonNode);
}
}
},
/* This private method is used to re-set the node values when something changes */
_resetNodeValues: function() {
if(this.art !=null) {
// Using our thumbnailNode attach point, set its src value
this.thumbnailNode.src = this.art.url+"?maxSize="+this.maxThumbnailSize;
this.thumbnailNode.alt = this.art.title;
this.thumbnailNode.width = this.maxThumbnailSize;
this.thumbnailNode.height = this.maxThumbnailSize;
// Now setup the link for the LightboxNano
var lightboxNano = new dojox.image.LightboxNano({
href: this.art.url+"?maxSize="+this.maxImageSize,
},this.thumbnailNode);
}
},
/* This is called anytime the "art" attribute is set. Consider is a "setter" method */
_setArtAttr: function(av) {
if (av != null) {
// Save it on our widget instance - note that
// we're using _set, to support anyone using
// our widget's Watch functionality, to watch values change
this._set("art", av);
this._resetNodeValues();
} else {
// We could have a default here...would be an error, since we
// shouldn't be calling this without an art object
}
},
_setMaxThumbnailSizeAttr: function(ms) {
// Save it on our widget instance - note that
// we're using _set, to support anyone using
// our widget's Watch functionality, to watch values change
this._set("maxThumbnailSize", ms);
this._resetNodeValues();
},
_setMaxImageSizeAttr: function(ms) {
// Save it on our widget instance - note that
// we're using _set, to support anyone using
// our widget's Watch functionality, to watch values change
this._set("maxImageSize",ms);
this._resetNodeValues();
}
}); // End of the widget
});
Now I am trying to add another custom component, a table of the above thumbnails. The new code needs to reference this old Widget, but I can't seem to get it to work.
The new Table widget (so far):
// in "img/ArtTableWidget"
define([
"dojo/_base/declare", "dojo/parser",
"dijit/_WidgetBase", "dijit/_TemplatedMixin",
"dojo/dom", "dojo/dom-construct","img/ArtThumbnailWidget",
"dojo/text!./ArtTableWidget/templates/ArtTableWidget.html"],
function(declare,parser,_WidgetBase,_TemplatedMixin, dom, domConstruct, ArtThumbnailWidget, template) {
return declare("img.ArtTableWidget",[dijit._WidgetBase,dijit._TemplatedMixin], {
// Default values for the ArtTable
// The base URL to use for downloading the photos
artUrlBase: null,
// The base URL used for submitting competitions and the button URL
newCompetitionUrlBase: null,
newCompetitionButtonIconUrl: null,
// Indicates what params on the URL are used to control page
// and size. These will be appended to the URL as needed.
pageNumberParameterName: "page",
pageSizeNumberParameterName: "size",
// Holds the page and size
page: 1,
size: 15,
totalPages: 0,
columns: 3,
// Holds the current list of "art"
artList: [],
// The userid currently viewing
viewerId: null,
// Our HTML template
templateString: template,
baseClass: "artTableWidget",
// Specifies there are widgets in the template itself that need to be rendered as well
widgetsInTemplate: true,
// Functions //
postCreate: function() {
this._load(this.page);
},
// Loads the given page
_load: function(pageToLoad) {
if(pageToLoad==null) {
pageToLoad=1;
}
// Generate the URL
genUrl = this.artUrlBase.indexOf("?")>=0 ? this.artUrlBase+"&page="+pageToLoad+"&size="+this.size : this.artUrlBase+"?page="+pageToLoad+"&size="+this.size;
// Make the call to the backend
dojo.xhrGet({
url: genUrl,
handleAs: "json",
tableWidget: this,
load: function(data,ioArgs) {
this.tableWidget.page = data.page;
this.tableWidget.totalPages = data.totalPages;
this.tableWidget.artList = data.data;
this.tableWidget._updateTable();
}
});
},
_updateTable: function() {
// Fix the buttons at the bottom
// Clear the artTable
domConstruct.empty(this.artTable);
// Loop through the art and build the rows
tableRow = tableRow = domConstruct.create("tr",{},this.artTable);
dojo.forEach(this.artList,function(art,index) {
if(index % columns == 0) {
tableRow = domConstruct.create("tr",{},this.artTable);
}
tableColumn = domConstruct.create("td",{style: { marginLeft: "auto", marginRight: "auto" }},tableRow);
var tnNode = new ArtThumbnailWidget({
art: art,
viewerId: this.viewerId,
competitionUrlBase: this.newCompetitionUrlBase,
competitionButtonIconUrl: this.newCompetitionButtonIconUrl,
});
tnNode.placeAt(tableColumn);
});
}
});
});
However, when I run the new component in Chrome, I get a generic Error in dojo.js.uncompressed.js line 1716. The message of the error is "multipleDefine", and the attached Object looks to be my ArtTableWidget. I noticed in digging though this object that the "deps" member, which appears to be an Array of all the dependencies defined in the define() at the top, includes the img/ArtThumbnailWidget in it, but the "pack" member is undefined. I am guessing that it's just not loading my module or something.
The error (sorry if Copy/Paste doesn't look right) is:
dojo.js.uncompressed.js:1716
Error
arguments: undefined
get stack: function getter() { [native code] }
info: Object
cacheId: 0
cjs: Object
def: function (declare,parser,_WidgetBase,_TemplatedMixin, dom, domConstruct, ArtThumbnailWidget, template) {
deps: Array[8]
0: Object
1: Object
2: Object
3: Object
4: Object
5: Object
6: Object
cacheId: 0
def: 0
executed: 4
injected: 2
isAmd: false
isXd: null
mid: "img/ArtThumbnailWidget"
pack: undefined
pid: ""
result: Object
url: "/ArtSite/resources/img/ArtThumbnailWidget.js"
__proto__: Object
7: Object
length: 8
__proto__: Array[0]
executed: 0
injected: 2
isAmd: false
isXd: null
mid: "img/ArtTableWidget"
node: HTMLScriptElement
pack: undefined
pid: ""
require: function (a1, a2, a3){
result: Object
url: "/ArtSite/resources/img/ArtTableWidget.js"
__proto__: Object
message: "multipleDefine"
set stack: function setter() { [native code] }
src: "dojoLoader"
type: undefined
__proto__: ErrorPrototype
dojo.js.uncompressed.js:1719src: dojoLoader
dojo.js.uncompressed.js:1719info:
Object
dojo.js.uncompressed.js:1721.
I need some help getting back on the right track here.
EDIT 1 I updated all of the modules using the information in BuffaloBuffalo's reply, except instead of a "path" in the dojoConfig I used the following:
<script type="text/javascript">
var djConfig = {
parseOnLoad: false,
isDebug: false,
locale: '${fn:toLowerCase(userLocale)}',
packages: [
{ name: "message", location: "${message_dojo_module_base_url}" },
{ name: "img", location: "${img_dojo_module_base_url}" }
]
};
</script>
It seems to find the .js files, but not the templates loaded there-in using dojo/text. I tried doing "./path/Template.html" and "/module/path/Template.html", but the first seems to try to resolve the URL through the CDN (Google APIs site linked above), the latter seems to want a fully qualified path. I shutter to put a full path in as it seems like a dirty way to do it. I also tried adding a path to the dojoConfig as such:
paths: [
{ "message" : "${message_dojo_module_base_url}" }
]
but that did not seem to help at all, causing some really nasty errors in Chrome's JS console.
Doesn't dojo/text use the modules, if I am reading correctly here?