1
|
/*
|
2
|
License: LGPL as per: http://www.gnu.org/copyleft/lesser.html
|
3
|
$Id$
|
4
|
*/
|
5
|
|
6
|
/**
|
7
|
* Base Class for widgets. Associates a node on the page with a stylesheet and
|
8
|
* model. All widgets must extend this base class.
|
9
|
* Defines the default paint() method for all widgets which is where the
|
10
|
* stylesheet is applied to the model XML document.
|
11
|
* To override widget.paint(), define it before calling this constructor.
|
12
|
* The stylesheet URL defaults to "widget/<widgetName>.xsl" if it is not defined
|
13
|
* in config file. Set a stylesheet property containing an XSL URL in config
|
14
|
* to customize the stylesheet used.
|
15
|
* All stylesheets will have "modelId" and "widgetId" parameters set when called.
|
16
|
*
|
17
|
* @constructor
|
18
|
* @author Mike Adair
|
19
|
* @param widget Pointer to the widget instance being created
|
20
|
* @param widgetNode The widget's XML object node from the configuration document.
|
21
|
* @param model The model object that this widget belongs to.
|
22
|
*/
|
23
|
function WidgetBase(widget,widgetNode,model) {
|
24
|
widget.model = model;
|
25
|
widget.widgetNode = widgetNode;
|
26
|
|
27
|
/** Method used for painting.
|
28
|
* xsl2html (default) => output of XSL will be HTML.
|
29
|
* xsl2js => output of XSL will be javascript to execute.
|
30
|
* image2html => where the model doc has content type image/*
|
31
|
*/
|
32
|
widget.paintMethod="xsl2html";
|
33
|
|
34
|
/** Widget's Id defined in the Config (required) */
|
35
|
if (widgetNode.attributes.getNamedItem("id")) {
|
36
|
widget.id = widgetNode.attributes.getNamedItem("id").nodeValue;
|
37
|
} else {
|
38
|
alert("id required for object:" + widgetNode.nodeName );
|
39
|
}
|
40
|
|
41
|
//allow the widget output to be replaced on each paint call
|
42
|
var outputNode = widgetNode.selectSingleNode("mb:outputNodeId");
|
43
|
if ( outputNode ) {
|
44
|
widget.outputNodeId = outputNode.firstChild.nodeValue;
|
45
|
} else {
|
46
|
widget.outputNodeId = "MbWidget_" + mbIds.getId();
|
47
|
}
|
48
|
|
49
|
//until htmlTagNode becomes required allow setting of it by widget id
|
50
|
if (!widget.htmlTagId) {
|
51
|
var htmlTagNode = widgetNode.selectSingleNode("mb:htmlTagId");
|
52
|
if (htmlTagNode) {
|
53
|
widget.htmlTagId = htmlTagNode.firstChild.nodeValue;
|
54
|
} else {
|
55
|
widget.htmlTagId = widget.id;
|
56
|
}
|
57
|
}
|
58
|
|
59
|
// Node in main HTML to attach widget to.
|
60
|
widget.node = document.getElementById(widget.htmlTagId);
|
61
|
if(!widget.node) {
|
62
|
//alert("htmlTagId: "+widget.htmlTagId+" for widget "+widgetNode.nodeName+" not found in config");
|
63
|
}
|
64
|
|
65
|
//set an empty debug property in config to see inputs and outputs of stylehseet
|
66
|
if ( widgetNode.selectSingleNode("mb:debug") ) widget.debug=true;
|
67
|
|
68
|
/** Transient var used to store model XML before and then after XSL transform.
|
69
|
* It can be modified by prePaint() .
|
70
|
*/
|
71
|
widget.resultDoc = null;
|
72
|
|
73
|
// Set this.stylesheet
|
74
|
// Defaults to "widget/<widgetName>.xsl" if not defined in config file.
|
75
|
if ( !widget.stylesheet ) {
|
76
|
var styleNode = widgetNode.selectSingleNode("mb:stylesheet");
|
77
|
if (styleNode ) {
|
78
|
widget.stylesheet = new XslProcessor(styleNode.firstChild.nodeValue,model.namespace);
|
79
|
} else {
|
80
|
widget.stylesheet = new XslProcessor(baseDir+"/widget/"+widgetNode.nodeName+".xsl",model.namespace);
|
81
|
}
|
82
|
}
|
83
|
|
84
|
/**
|
85
|
* Initialize dynamic properties.set the target model
|
86
|
* @param toolRef Pointer to this object.
|
87
|
*/
|
88
|
this.initTargetModel = function(objRef) {
|
89
|
//set the target model
|
90
|
var targetModel = objRef.widgetNode.selectSingleNode("mb:targetModel");
|
91
|
if (targetModel) {
|
92
|
objRef.targetModel = eval("config.objects."+targetModel.firstChild.nodeValue);
|
93
|
if ( !objRef.targetModel ) {
|
94
|
alert("error finding targetModel:" + targetModel.firstChild.nodeValue + " for:" + objRef.id);
|
95
|
}
|
96
|
} else {
|
97
|
objRef.targetModel = objRef.model;
|
98
|
}
|
99
|
objRef.stylesheet.setParameter("targetModelId", objRef.targetModel.id );
|
100
|
}
|
101
|
|
102
|
|
103
|
// Set stylesheet parameters for all the child nodes from the config file
|
104
|
for (var j=0;j<widgetNode.childNodes.length;j++) {
|
105
|
if (widgetNode.childNodes[j].firstChild
|
106
|
&& widgetNode.childNodes[j].firstChild.nodeValue)
|
107
|
{
|
108
|
widget.stylesheet.setParameter(
|
109
|
widgetNode.childNodes[j].nodeName,
|
110
|
widgetNode.childNodes[j].firstChild.nodeValue);
|
111
|
}
|
112
|
}
|
113
|
|
114
|
// Set widget text values as parameters
|
115
|
if (config.widgetText) {
|
116
|
var textNodeXpath = "/mb:WidgetText/mb:widgets/mb:" + widgetNode.nodeName;
|
117
|
var textParams = config.widgetText.selectNodes(textNodeXpath+"/*");
|
118
|
for (var j=0;j<textParams.length;j++) {
|
119
|
widget.stylesheet.setParameter(textParams[j].nodeName,textParams[j].firstChild.nodeValue);
|
120
|
}
|
121
|
}
|
122
|
|
123
|
//all stylesheets will have these properties available
|
124
|
widget.stylesheet.setParameter("modelId", widget.model.id );
|
125
|
widget.stylesheet.setParameter("modelTitle", widget.model.title );
|
126
|
widget.stylesheet.setParameter("widgetId", widget.id );
|
127
|
widget.stylesheet.setParameter("skinDir", config.skinDir );
|
128
|
widget.stylesheet.setParameter("lang", config.lang );
|
129
|
|
130
|
/**
|
131
|
* Move this widget to the absolute (left,top) position in the browser.
|
132
|
* @param left Absolute left coordinate.
|
133
|
* @param top Absolute top coordinate.
|
134
|
*/
|
135
|
this.move = function(left,top) {
|
136
|
this.node.style.left = left;
|
137
|
this.node.style.top = top;
|
138
|
}
|
139
|
|
140
|
/**
|
141
|
* Resize this widget.
|
142
|
* @param width New width.
|
143
|
* @param height New height.
|
144
|
*/
|
145
|
this.resize = function(width,height) {
|
146
|
this.node.style.width = width;
|
147
|
this.node.style.height = height;
|
148
|
}
|
149
|
|
150
|
/**
|
151
|
* Called change the visibility of this widget's output node
|
152
|
* @param vis boolean true or false
|
153
|
*/
|
154
|
this.setVisibility = function(vis) {
|
155
|
var vis="visible";
|
156
|
if (vis) vis="hidden";
|
157
|
document.getElementById(this.outputNodeId).style.visibility = vis;
|
158
|
}
|
159
|
|
160
|
/**
|
161
|
* Called before paint(), can be used to set up a widget's paint parameters,
|
162
|
* or modify model using this.resultDoc().
|
163
|
* @param objRef Pointer to this object.
|
164
|
*/
|
165
|
this.prePaint = function(objRef) {
|
166
|
//no-op by default
|
167
|
}
|
168
|
|
169
|
/**
|
170
|
* Called after paint(), can be used to initialize things that depend on the
|
171
|
* the widget output being presetn, eg. form and form elements
|
172
|
* @param objRef Pointer to this object.
|
173
|
*/
|
174
|
this.postPaint = function(objRef) {
|
175
|
//no-op by default
|
176
|
}
|
177
|
|
178
|
|
179
|
|
180
|
|
181
|
|
182
|
|
183
|
//to override the paint method, define it in the exetnsion class before calling
|
184
|
//the WidgetBase constructor. This is so that when paint is registered as a
|
185
|
//listener, the method from the instance is used.
|
186
|
if (!widget.paint) {
|
187
|
|
188
|
/**
|
189
|
* Render the widget.
|
190
|
* @param objRef Pointer to widget object.
|
191
|
*/
|
192
|
|
193
|
|
194
|
this.paint = function(objRef) {
|
195
|
|
196
|
if (objRef.model.template) return;
|
197
|
|
198
|
// Remove widget from display if the model is empty
|
199
|
if (!objRef.model.doc){
|
200
|
objRef.clearWidget(objRef);
|
201
|
}
|
202
|
|
203
|
if (objRef.model.doc && objRef.node) {
|
204
|
objRef.stylesheet.setParameter("modelUrl", objRef.model.url);
|
205
|
|
206
|
//if (objRef.debug) alert("source:"+Sarissa.serialize(objRef.model.doc));
|
207
|
objRef.resultDoc = objRef.model.doc; // resultDoc sometimes modified by prePaint()
|
208
|
objRef.prePaint(objRef);
|
209
|
|
210
|
//confirm inputs
|
211
|
if (objRef.debug) alert("prepaint:"+Sarissa.serialize(objRef.resultDoc));
|
212
|
if (objRef.debug) alert("stylesheet:"+Sarissa.serialize(objRef.stylesheet.xslDom));
|
213
|
|
214
|
//set to output to a temporary node
|
215
|
//hack to get by doc parsing problem in IE
|
216
|
//the firstChild of tempNode will be the root element output by the stylesheet
|
217
|
var outputNode = document.getElementById( objRef.outputNodeId );
|
218
|
var tempNode = document.createElement("DIV");
|
219
|
switch (objRef.paintMethod) {
|
220
|
case "xsl2html":
|
221
|
//process the doc with the stylesheet
|
222
|
var s = objRef.stylesheet.transformNodeToString(objRef.resultDoc);
|
223
|
if (config.serializeUrl && objRef.debug) postLoad(config.serializeUrl, s);
|
224
|
if (objRef.debug) alert("painting:"+objRef.id+":"+s);
|
225
|
tempNode.innerHTML = s;
|
226
|
tempNode.firstChild.setAttribute("id", objRef.outputNodeId);
|
227
|
|
228
|
//look for this widgets output and replace if found,
|
229
|
//otherwise append it
|
230
|
if (outputNode) {
|
231
|
objRef.node.replaceChild(tempNode.firstChild,outputNode);
|
232
|
} else {
|
233
|
objRef.node.appendChild(tempNode.firstChild);
|
234
|
}
|
235
|
break;
|
236
|
case "image2html":
|
237
|
//here the model document is an image
|
238
|
tempNode.style.position="absolute";
|
239
|
tempNode.style.top=0;
|
240
|
tempNode.style.left=0;
|
241
|
tempNode.appendChild(objRef.model.doc);
|
242
|
tempNode.setAttribute("id", objRef.outputNodeId);
|
243
|
|
244
|
//look for this widgets output and replace if found,
|
245
|
//otherwise append it
|
246
|
if (outputNode) {
|
247
|
objRef.node.replaceChild(tempNode,outputNode);
|
248
|
} else {
|
249
|
objRef.node.appendChild(tempNode);
|
250
|
}
|
251
|
break;
|
252
|
case "xsl2js":
|
253
|
jsNode = objRef.stylesheet.transformNodeToObject(objRef.resultDoc);
|
254
|
js=jsNode.selectSingleNode("js").firstChild.nodeValue;
|
255
|
tempNode.style.position="absolute";
|
256
|
tempNode.style.top=0;
|
257
|
tempNode.style.left=0;
|
258
|
tempNode.setAttribute("id", objRef.outputNodeId);
|
259
|
//look for this widgets output and replace if found,
|
260
|
//otherwise append it
|
261
|
if (outputNode) {
|
262
|
objRef.node.replaceChild(tempNode,outputNode);
|
263
|
} else {
|
264
|
objRef.node.appendChild(tempNode);
|
265
|
}
|
266
|
if (objRef.debug) alert("javascript eval:"+js);
|
267
|
objRef.model.setParam("modelStatus","rendering");
|
268
|
eval(js);
|
269
|
|
270
|
break;
|
271
|
//Michael Jenik added this case for the MapContainer Paint
|
272
|
case "preloading":
|
273
|
break;
|
274
|
|
275
|
default:
|
276
|
alert("WidgetBase: Invalid paintMethod="+objRef.paintMethod);
|
277
|
}
|
278
|
|
279
|
objRef.postPaint(objRef);
|
280
|
}
|
281
|
}
|
282
|
}
|
283
|
|
284
|
/**
|
285
|
* Remove widget from display.
|
286
|
* @param objRef Pointer to this object.
|
287
|
*/
|
288
|
this.clearWidget = function(objRef) {
|
289
|
//with objRef.node remove child
|
290
|
var outputNode = document.getElementById( objRef.outputNodeId );
|
291
|
if (outputNode) objRef.node.removeChild(outputNode);
|
292
|
}
|
293
|
|
294
|
// If this object is being created because a child is extending this object,
|
295
|
// then child.properties = this.properties
|
296
|
for (sProperty in this) {
|
297
|
widget[sProperty] = this[sProperty];
|
298
|
}
|
299
|
|
300
|
// Call paint when model changes
|
301
|
widget.model.addListener("init", widget.initTargetModel, widget);
|
302
|
widget.model.addListener("refresh",widget.paint, widget);
|
303
|
widget.model.addListener("newModel",widget.clearWidget, widget);
|
304
|
}
|