Files
alfresco-community-repo/source/web/scripts/ajax/xforms.js
Ariel Backenroth 52950cfcfb xforms ui updates and fixes
- WCM-261:  only one active tinymce instance per page.  also extracted tinymce to what will soon be externally configurable parameters which enables different button configurations based on appearance.  having on instance per page does seem to provide a marginal performance boost
- WCM-453: better error message when creating content with a filename that already exists.
- WCM-431: providing tooltips on label based on a hint annotation
- test case for recursive schemas (haven't addressed the bug)
- fix for create web content for non form based content

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5603 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
2007-05-02 21:56:36 +00:00

4923 lines
203 KiB
JavaScript

/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
////////////////////////////////////////////////////////////////////////////////
// XForms user interface
//
// This script communicates with the XFormBean to produce and manage an xform.
//
// This script requires dojo.js, tiny_mce.js, and upload_helper.js to be
// loaded in advance.
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// initialization
//
// Initiliaze dojo requirements, tinymce, and add a hook to load the xform.
////////////////////////////////////////////////////////////////////////////////
djConfig.bindEncoding = "UTF-8";
djConfig.parseWidgets = false;
dojo.require("dojo.date.common");
dojo.require("dojo.debug.console");
dojo.require("dojo.lang.assert");
dojo.require("dojo.lfx.html");
//dojo.hostenv.writeIncludes();
function _xforms_init()
{
document.xform = new alfresco.xforms.XForm();
}
dojo.addOnLoad(_xforms_init);
////////////////////////////////////////////////////////////////////////////////
// constants
//
// These are the client side declared constants. Others relating to namespaces
// and the webapp context path are expected to be provided by the jsp including
// this script.
////////////////////////////////////////////////////////////////////////////////
alfresco.xforms.constants.XFORMS_ERROR_DIV_ID = "alfresco-xforms-error";
alfresco.xforms.constants.EXPANDED_IMAGE = new Image();
alfresco.xforms.constants.EXPANDED_IMAGE.src =
alfresco.constants.WEBAPP_CONTEXT + "/images/icons/expanded.gif";
alfresco.xforms.constants.COLLAPSED_IMAGE = new Image();
alfresco.xforms.constants.COLLAPSED_IMAGE.src =
alfresco.constants.WEBAPP_CONTEXT + "/images/icons/collapsed.gif";
////////////////////////////////////////////////////////////////////////////////
// widgets
////////////////////////////////////////////////////////////////////////////////
/**
* Base class for all xforms widgets. Each widget has a set of common properties,
* particularly a corresponding xforms node, a node within the browser DOM,
* a parent widget, and state variables.
*/
dojo.declare("alfresco.xforms.Widget",
null,
function(xform, xformsNode)
{
this.xform = xform;
this.xformsNode = xformsNode;
this.id = this.xformsNode.getAttribute("id");
this._modified = false;
this._valid = true;
var b = this.xform.getBinding(this.xformsNode);
if (b)
{
dojo.debug("adding " + this.id + " to binding " + b.id);
b.widgets[this.id] = this;
}
else
{
dojo.debug("no binding found for " + this.id);
}
this.domNode = this.domNode || document.createElement("div");
this.domNode.setAttribute("id", this.id + "-domNode");
this.domNode.widget = this;
dojo.html.setClass(this.domNode, "xformsItem");
},
{
/////////////////////////////////////////////////////////////////
// properties
/////////////////////////////////////////////////////////////////
/** A reference to the xform. */
xform: null,
/** The xformsNode managed by this widget. */
xformsNode: null,
/** The dom node containing the label for this widget. */
labelNode: null,
/** The parent widget, or null if this is the root widget. */
parent: null,
/** The dom node for this widget. */
domNode: null,
/** The dom node containing this widget. */
domContainer: null,
/** The parent widget which is using this as a composite. */
_compositeParent: null,
/////////////////////////////////////////////////////////////////
// methods
/////////////////////////////////////////////////////////////////
/** Sets the widget's modified state, as indicated by an XFormsEvent. */
setModified: function(b)
{
if (this._modified != b)
{
this._modified = b;
this._updateDisplay(false);
if (this.isValidForSubmit())
{
this.hideAlert();
}
}
},
/** Sets the widget's valid state, as indicated by an XFormsEvent */
setValid: function(b)
{
if (this._valid != b)
{
this._valid = b;
this._updateDisplay(false);
if (this.isValidForSubmit())
{
this.hideAlert();
}
else
{
this.showAlert();
}
}
},
/**
* Heuristic approach to determine if the widget is valid for submit or
* if it's causing an xforms-error.
*/
isValidForSubmit: function()
{
if (typeof this._valid != "undefined" && !this._valid)
{
dojo.debug(this.id + " is invalid");
return false;
}
if (!this._modified &&
this.isRequired() &&
this.getInitialValue() == null)
{
dojo.debug(this.id + " is unmodified and required and empty");
return false;
}
if (this.isRequired() && this.getValue() == null)
{
dojo.debug(this.id + " is required and empty");
return false;
}
dojo.debug(this.id + " is valid: {" +
"modified: " + this._modified +
", required: " + this.isRequired() +
", initial_value: " + this.getInitialValue() +
", value: " + this.getValue() + "}");
return true;
},
/** Returns the depth of the widget within the widget heirarchy. */
getDepth: function()
{
var result = 1;
var p = this.parent;
while (p)
{
result++;
p = p.parent;
}
return result;
},
/** Returns the root group element */
getViewRoot: function()
{
var p = this;
while (p.parent)
{
p = p.parent;
}
if (! (p instanceof alfresco.xforms.ViewRoot))
{
throw new Error("expected root widget " + p + " to be a view root");
}
return p;
},
/** Returns true if the parent is an ancestor of the given parent */
isAncestorOf: function(parent)
{
var p = this;
while (p.parent)
{
if (p.parent == parent)
{
return true;
}
p = p.parent;
}
return false;
},
/** Sets the widget's enabled state, as indicated by an XFormsEvent */
setEnabled: function(enabled)
{
},
/** Returns the widget's enabled state */
isEnabled: function()
{
return true;
},
/** Sets the widget's required state, as indicated by an XFormsEvent */
setRequired: function(b)
{
if (this._required != b)
{
this._required = b;
this._updateDisplay(false);
}
},
/** Indicates if a value is required for the widget. */
isRequired: function()
{
if (typeof this._required != "undefined")
{
return this._required;
}
var binding = this.xform.getBinding(this.xformsNode);
return binding && binding.isRequired();
},
/** Sets the widget's readonly state, as indicated by an XFormsEvent */
setReadonly: function(readonly)
{
this._readonly = readonly;
},
/** Indicates if the widget's value is readonly. */
isReadonly: function()
{
if (typeof this._readonly != "undefined")
{
return this._readonly;
}
var binding = this.xform.getBinding(this.xformsNode);
return binding && binding.isReadonly();
},
isVisible: function()
{
return true;
},
/** Commits the changed value to the server */
_commitValueChange: function()
{
if (this._compositeParent)
{
this._compositeParent._commitValueChange();
}
else
{
this.xform.setXFormsValue(this.id, this.getValue());
}
},
/** Sets the value contained by the widget */
setValue: function(value, forceCommit)
{
if (forceCommit)
{
this.xform.setXFormsValue(this.id, value);
}
},
/** Returns the value contained by the widget, or null if none is set */
getValue: function()
{
return null;
},
/** Sets the widget's initial value. */
setInitialValue: function(value, forceCommit)
{
this._initialValue =
(typeof value == "string" && value.length == 0 ? null : value);
if (forceCommit)
{
this.xform.setXFormsValue(this.id, value);
}
},
/**
* Returns the widget's local value, either with a local variable, or by
* looking it up within the model section.
*/
getInitialValue: function()
{
if (typeof this._initialValue != "undefined")
{
return this._initialValue;
}
var xpath = this._getXPathInInstanceDocument();
var d = this.xformsNode.ownerDocument;
var contextNode = this.xform.getInstance();
dojo.debug("locating " + xpath + " in " + contextNode.nodeName);
this._initialValue = _evaluateXPath("/" + xpath,
this.xform.getInstance(),
XPathResult.FIRST_ORDERED_NODE_TYPE);
if (!this._initialValue)
{
dojo.debug("unable to resolve xpath /" + xpath + " for " + this.id);
this._initialValue = null;
}
else
{
this._initialValue = (this._initialValue.nodeType == dojo.dom.ELEMENT_NODE
? dojo.dom.textContent(this._initialValue)
: this._initialValue.nodeValue);
if (typeof this._initialValue == "string" && this._initialValue.length == 0)
{
this._initialValue = null;
}
dojo.debug("resolved xpath " + xpath + " to " + this._initialValue);
}
return this._initialValue;
},
/** Produces an xpath to the model node within the instance data document. */
_getXPathInInstanceDocument: function()
{
var binding = this.xform.getBinding(this.xformsNode);
var xpath = '';
var repeatIndices = this.getRepeatIndices();
do
{
var s = binding.nodeset;
if (binding.nodeset == '.')
{
binding = binding.parent;
}
if (binding.nodeset.match(/.+\[.+\]/))
{
s = binding.nodeset.replace(/([^\[]+)\[.*/, "$1");
s += '[' + (repeatIndices.shift().index) + ']';
}
xpath = s + (xpath.length != 0 ? '/' + xpath : "");
binding = binding.parent;
}
while (binding);
return xpath;
},
/** Returns a child node by name within the xform. */
_getChildXFormsNode: function(nodeName)
{
var x = _getElementsByTagNameNS(this.xformsNode,
alfresco.xforms.constants.XFORMS_NS,
alfresco.xforms.constants.XFORMS_PREFIX,
nodeName);
for (var i = 0; i < x.length; i++)
{
if (x[i].parentNode == this.xformsNode)
{
return x[i];
}
}
return null;
},
/** Returns the widget's label. */
getLabel: function()
{
var node = this._getChildXFormsNode("label");
var result = node ? dojo.dom.textContent(node) : "";
if (djConfig.isDebug)
{
result += " [" + this.id + "]";
}
return result;
},
/** Returns the widget's alert text. */
getAlert: function()
{
var node = this._getChildXFormsNode("alert");
return node ? dojo.dom.textContent(node) : "";
},
/** Returns the widget's alert text. */
getHint: function()
{
var node = this._getChildXFormsNode("hint");
return node ? dojo.dom.textContent(node) : null;
},
/** Makes the label red. */
showAlert: function()
{
if (!dojo.html.hasClass(this.labelNode, "xformsItemLabelSubmitError"))
{
dojo.html.addClass(this.labelNode, "xformsItemLabelSubmitError");
}
},
/** Restores the label to its original color. */
hideAlert: function()
{
if (dojo.html.hasClass(this.labelNode, "xformsItemLabelSubmitError"))
{
dojo.html.removeClass(this.labelNode, "xformsItemLabelSubmitError");
}
},
/** Returns the value of the appearance attribute for widget */
getAppearance: function()
{
var result = (this.xformsNode.getAttribute("appearance") ||
this.xformsNode.getAttribute(alfresco.xforms.constants.XFORMS_PREFIX + ":appearance"));
return result == null || result.length == 0 ? null : result;
},
/** Updates the display of the widget. This is intended to be overridden. */
_updateDisplay: function(recursively)
{
},
/** Destroy the widget and any resources no longer needed. */
_destroy: function()
{
dojo.debug("destroying " + this.id);
},
/**
* Returns an array of RepeatIndexDatas corresponding to all enclosing repeats.
* The closest repeat will be at index 0.
*/
getRepeatIndices: function()
{
var result = [];
var w = this;
while (w.parent)
{
if (w.parent instanceof alfresco.xforms.Repeat)
{
result.push(new alfresco.xforms.RepeatIndexData(w.parent,
w.parent.getChildIndex(w) + 1));
}
w = w.parent;
}
return result;
},
/**
*/
getParentGroups: function(appearance)
{
var result = [];
var w = this;
while (w.parent)
{
if (w.parent instanceof alfresco.xforms.AbstractGroup)
{
if (appearance && w.parent.getAppearance() == appearance)
{
result.push(w.parent);
}
}
w = w.parent;
}
return result;
}
});
////////////////////////////////////////////////////////////////////////////////
// widgets for atomic types
////////////////////////////////////////////////////////////////////////////////
/** The file picker widget which handles xforms widget xf:upload. */
dojo.declare("alfresco.xforms.FilePicker",
alfresco.xforms.Widget,
function(xform, xformsNode)
{
},
{
/////////////////////////////////////////////////////////////////
// overridden methods
/////////////////////////////////////////////////////////////////
render: function(attach_point)
{
dojo.html.prependClass(this.domNode, "xformsFilePicker");
attach_point.appendChild(this.domNode);
//XXXarielb support readonly and disabled
this.widget = new alfresco.FilePickerWidget(this.id,
this.domNode,
this.getInitialValue(),
false,
this._filePicker_changeHandler,
this._filePicker_resizeHandler);
this.widget.render();
},
getValue: function()
{
return this.widget.getValue();
},
setValue: function(value, forceCommit)
{
if (!this.widget)
{
this.setInitialValue(value, forceCommit);
}
else
{
alfresco.xforms.FilePicker.superclass.setValue.call(this, value, forceCommit);
this.widget.setValue(value);
}
},
/////////////////////////////////////////////////////////////////
// DOM event handlers
/////////////////////////////////////////////////////////////////
_filePicker_changeHandler: function(fpw)
{
fpw.node.widget._commitValueChange();
},
_filePicker_resizeHandler: function(fpw)
{
var w = fpw.node.widget;
w.domContainer.style.height =
Math.max(fpw.node.offsetHeight +
dojo.html.getMargin(w.domNode.parentNode).height,
20) + "px";
}
});
/** The textfield widget which handle xforms widget xf:input with any string or numerical type */
dojo.declare("alfresco.xforms.TextField",
alfresco.xforms.Widget,
function(xform, xformsNode)
{
this.domNode = document.createElement("span");
this._maxLength = (_hasAttribute(this.xformsNode, alfresco.xforms.constants.ALFRESCO_PREFIX + ":maxLength")
? Number(this.xformsNode.getAttribute(alfresco.xforms.constants.ALFRESCO_PREFIX + ":maxLength"))
: -1);
this._length = (_hasAttribute(this.xformsNode, alfresco.xforms.constants.ALFRESCO_PREFIX + ":length")
? Number(this.xformsNode.getAttribute(alfresco.xforms.constants.ALFRESCO_PREFIX + ":length"))
: -1);
},
{
/////////////////////////////////////////////////////////////////
// overridden methods
/////////////////////////////////////////////////////////////////
render: function(attach_point)
{
var initial_value = this.getInitialValue() || "";
attach_point.appendChild(this.domNode);
this.widget = document.createElement("input");
this.widget.setAttribute("type", "text");
this.widget.setAttribute("id", this.id + "-widget");
this.widget.setAttribute("value", initial_value);
if (this._maxLength >= 0 || this._length >= 0)
{
this.widget.setAttribute("maxlength", this._maxLength >= 0 ? this._maxLength : this._length);
var maxWidth = this.domNode.offsetWidth;
this.widget.style.maxWidth = "100%";
this.widget.setAttribute("size", this._maxLength >= 0 ? this._maxLength : this._length);
}
else if (this.getAppearance() == "full")
{
this.widget.style.width = "100%";
}
this.domNode.appendChild(this.widget);
if (this.isReadonly())
{
this.widget.setAttribute("readonly", this.isReadonly());
this.widget.setAttribute("disabled", this.isReadonly());
}
else
{
dojo.event.connect(this.widget, "onblur", this, this._widget_changeHandler);
}
},
setValue: function(value, forceCommit)
{
if (!this.widget)
{
this.setInitialValue(value, forceCommit);
}
else
{
alfresco.xforms.TextField.superclass.setValue.call(this, value, forceCommit);
this.widget.value = value;
}
},
getValue: function()
{
return (this.widget.value != null && this.widget.value.length == 0
? null
: this.widget.value);
},
/////////////////////////////////////////////////////////////////
// DOM event handlers
/////////////////////////////////////////////////////////////////
_widget_changeHandler: function(event)
{
this._commitValueChange();
}
});
/** The number range widget which handle xforms widget xf:range with any numerical type */
dojo.declare("alfresco.xforms.NumericalRange",
alfresco.xforms.Widget,
function(xform, xformsNode)
{
dojo.require("dojo.widget.Slider");
this._fractionDigits = (_hasAttribute(this.xformsNode, alfresco.xforms.constants.ALFRESCO_PREFIX + ":fractionDigits")
? Number(this.xformsNode.getAttribute(alfresco.xforms.constants.ALFRESCO_PREFIX + ":fractionDigits"))
: -1);
},
{
/////////////////////////////////////////////////////////////////
// overridden methods
/////////////////////////////////////////////////////////////////
render: function(attach_point)
{
var initial_value = this.getInitialValue() || "";
attach_point.appendChild(this.domNode);
var sliderDiv = document.createElement("div");
sliderDiv.style.fontWeight = "bold";
sliderDiv.style.marginBottom = "5px";
this.domNode.appendChild(sliderDiv);
var minimum = Number(this.xformsNode.getAttribute(alfresco.xforms.constants.XFORMS_PREFIX + ":start"));
var maximum = Number(this.xformsNode.getAttribute(alfresco.xforms.constants.XFORMS_PREFIX + ":end"));
var snapValues = 0;
if (this._fractionDigits == 0)
{
snapValues = maximum - minimum + 1;
}
sliderDiv.appendChild(document.createTextNode(minimum));
var sliderWidgetDiv = document.createElement("div");
sliderDiv.appendChild(sliderWidgetDiv);
this.widget = dojo.widget.createWidget("SliderHorizontal",
{
initialValue: initial_value,
minimumX: minimum,
maximumX: maximum,
showButtons: false,
activeDrag: false,
snapValues: snapValues
},
sliderWidgetDiv);
sliderDiv.appendChild(document.createTextNode(maximum));
this.currentValueDiv = document.createElement("div");
this.domNode.appendChild(this.currentValueDiv);
this.currentValueDiv.appendChild(document.createTextNode("Value: " + initial_value));
dojo.event.connect(this.widget,
"onValueChanged",
this,
this._hSlider_valueChangedHandler);
},
setValue: function(value, forceCommit)
{
if (!this.widget)
{
this.setInitialValue(value, forceCommit);
}
else
{
alfresco.xforms.NumericalRange.superclass.setValue.call(this, value, forceCommit);
this.widget.setValue(value);
}
},
getValue: function()
{
return this.widget.getValue();
},
/////////////////////////////////////////////////////////////////
// DOM event handlers
/////////////////////////////////////////////////////////////////
_hSlider_valueChangedHandler: function(value)
{
if (this._fractionDigits >= 0)
{
value = Math.round(value * Math.pow(10, this._fractionDigits)) / Math.pow(10, this._fractionDigits);
}
this.currentValueDiv.replaceChild(document.createTextNode("Value: " + value),
this.currentValueDiv.firstChild);
if (!this.widget._isDragInProgress)
{
this._commitValueChange();
}
}
});
/** The text area widget handles xforms widget xf:textarea with appearance minimal */
dojo.declare("alfresco.xforms.PlainTextEditor",
alfresco.xforms.Widget,
function(xform, xformsNode)
{
},
{
/////////////////////////////////////////////////////////////////
// overridden methods
/////////////////////////////////////////////////////////////////
render: function(attach_point)
{
attach_point.appendChild(this.domNode);
dojo.html.prependClass(this.domNode, "xformsTextArea");
var initialValue = this.getInitialValue() || "";
this.widget = document.createElement("textarea");
this.domNode.appendChild(this.widget);
this.widget.setAttribute("id", this.id + "-widget");
this.widget.appendChild(document.createTextNode(initialValue));
if (this.isReadonly())
{
this.widget.setAttribute("readonly", this.isReadonly());
}
this.widget.style.width = "100%";
this.widget.style.height = "100%";
dojo.event.connect(this.widget, "onchange", this, this._textarea_changeHandler);
},
setValue: function(value, forceCommit)
{
if (!this.widget)
{
this.setInitialValue(value, forceCommit);
}
else
{
alfresco.xform.PlainTextEditor.superclass.setValue.call(this, value, forceCommit);
this.widget.value = value;
}
},
getValue: function()
{
return this.widget.value;
},
/////////////////////////////////////////////////////////////////
// DOM event handlers
/////////////////////////////////////////////////////////////////
_textarea_changeHandler: function(event)
{
this._commitValueChange();
}
});
/** The textfield widget which handle xforms widget xf:textarea. with appearance full or compact */
dojo.declare("alfresco.xforms.RichTextEditor",
alfresco.xforms.Widget,
function(xform, xformsNode, params)
{
this._focused = false;
this._tinyMCE_buttons = params;
if (!this.statics.tinyMCEInitialized)
{
this.statics.tinyMCEInitialized = true;
}
},
{
/////////////////////////////////////////////////////////////////
// methods & properties
/////////////////////////////////////////////////////////////////
statics: { currentInstance: null, tinyMCEInitialized: false },
_removeTinyMCE: function()
{
var value = tinyMCE.getContent(this.id);
this._commitValueChange();
tinyMCE.removeMCEControl(this.id);
this._focused = false;
},
_createTinyMCE:function()
{
if (this.statics.currentInstance &&
this.statics.currentInstance != this)
{
this.statics.currentInstance._removeTinyMCE();
}
this.statics.currentInstance = this;
tinyMCE.settings.theme_advanced_buttons1 = this._tinyMCE_buttons[0];
tinyMCE.settings.theme_advanced_buttons2 = this._tinyMCE_buttons[1];
tinyMCE.settings.theme_advanced_buttons3 = this._tinyMCE_buttons[2];
tinyMCE.addMCEControl(this.widget, this.id);
var editorDocument = tinyMCE.getInstanceById(this.id).getDoc();
editorDocument.widget = this;
tinyMCE.addEvent(editorDocument,
dojo.render.html.ie ? "beforedeactivate" : "blur",
this._tinyMCE_blurHandler);
tinyMCE.addEvent(editorDocument, "focus", this._tinyMCE_focusHandler);
},
/////////////////////////////////////////////////////////////////
// overridden methods
/////////////////////////////////////////////////////////////////
render: function(attach_point)
{
attach_point.appendChild(this.domNode);
dojo.html.prependClass(this.domNode, "xformsTextArea");
this.widget = document.createElement("div");
this.domNode.appendChild(this.widget);
dojo.html.prependClass(this.widget, "xformsTextArea");
this.widget.style.border = "1px solid black";
this.widget.style.overflow = "auto";
this.widget.innerHTML = this.getInitialValue() || "";
var images = this.widget.getElementsByTagName("img");
for (var i = 0; i < images.length; i++)
{
if (images[i].getAttribute("src") &&
images[i].getAttribute("src").match("^/"))
{
images[i].setAttribute("src", alfresco.constants.AVM_WEBAPP_URL + images[i].getAttribute("src"));
}
}
if (!this.isReadonly())
{
// this._createTinyMCE();
var me = this;
dojo.event.browser.addListener(this.widget,
"onmouseover",
function(event) { me._div_mouseoverHandler(event) },
true);
}
},
setValue: function(value)
{
if (this.statics.currentInstance == this)
{
tinyMCE.selectedInstance = tinyMCE.getInstanceById(this.id);
try
{
tinyMCE.setContent(value);
}
catch (e)
{
//XXXarielb figure this out - getting intermittent errors in IE.
dojo.debug(e);
}
}
else
{
this.widget.innerHTML = value;
}
},
getValue: function()
{
var result = this.statics.currentInstance == this ? tinyMCE.getContent(this.id) : this.widget.innerHTML;
result = result.replace(new RegExp(alfresco.constants.AVM_WEBAPP_URL, "g"), "");
return result;
},
setReadonly: function(readonly)
{
alfresco.xforms.RichTextEditor.superclass.setReadonly.call(this, readonly);
if (readonly && this.statics.currentInstance == this)
{
this._removeTinyMCE();
}
},
_destroy: function()
{
alfresco.xforms.RichTextEditor.superclass._destroy.call(this);
if (!this.isReadonly())
{
dojo.debug("removing mce control " + this.id);
tinyMCE.removeMCEControl(this.id);
}
},
/////////////////////////////////////////////////////////////////
// DOM event handlers
/////////////////////////////////////////////////////////////////
_tinyMCE_blurHandler: function(event)
{
if (event.type == "beforedeactivate")
{
event.target = event.srcElement.ownerDocument;
}
var widget = event.target.widget;
widget._commitValueChange();
this._focused = false;
},
_tinyMCE_focusHandler: function(event)
{
var widget = event.target.widget;
var repeatIndices = widget.getRepeatIndices();
if (repeatIndices.length != 0 && !this._focused)
{
var r = repeatIndices[repeatIndices.length - 1].repeat;
var p = widget;
while (p && p.parent != r)
{
if (p.parent instanceof alfresco.xforms.Repeat)
{
throw new Error("unexpected parent repeat " + p.parent.id);
}
p = p.parent;
}
if (!p)
{
throw new Error("unable to find parent repeat " + r.id +
" of " + widget.id);
}
repeatIndices[repeatIndices.length - 1].repeat.setFocusedChild(p);
}
this._focused = true;
},
_div_mouseoverHandler: function(event)
{
if (!this.hoverLayer)
{
this.hoverLayer = document.createElement("div");
dojo.html.setClass(this.hoverLayer, "xformsRichTextEditorHoverLayer");
this.hoverLayer.appendChild(document.createTextNode(alfresco.xforms.constants.resources["click_to_edit"]));
}
if (!this.hoverLayer.parentNode)
{
this.widget.appendChild(this.hoverLayer);
this.hoverLayer.style.lineHeight = this.hoverLayer.offsetHeight + "px";
var me = this;
dojo.event.browser.addListener(this.hoverLayer,
"onmouseout",
function(event) { me._hoverLayer_mouseoutHandler(event) },
true);
dojo.event.browser.addListener(this.hoverLayer,
"onclick",
function(event) { me._hoverLayer_clickHandler(event); },
true);
}
},
_hoverLayer_mouseoutHandler: function(event)
{
if (this.hoverLayer.parentNode)
{
this.widget.removeChild(this.hoverLayer);
}
},
_hoverLayer_clickHandler: function(event)
{
if (this.hoverLayer.parentNode)
{
this.widget.removeChild(this.hoverLayer);
this._createTinyMCE();
}
}
});
/** Base class for all select widgets. */
dojo.declare("alfresco.xforms.AbstractSelectWidget",
alfresco.xforms.Widget,
function(xform, xformsNode)
{
},
{
/////////////////////////////////////////////////////////////////
// methods
/////////////////////////////////////////////////////////////////
/**
* Returns the possible item values for the select control as an array
* of anonymous objects with properties id, label, value, and valid.
*/
_getItemValues: function()
{
var binding = this.xform.getBinding(this.xformsNode);
var values = _getElementsByTagNameNS(this.xformsNode,
alfresco.xforms.constants.XFORMS_NS,
alfresco.xforms.constants.XFORMS_PREFIX,
"item");
var result = [];
for (var i = 0; i < values.length; i++)
{
var label = _getElementsByTagNameNS(values[i],
alfresco.xforms.constants.XFORMS_NS,
alfresco.xforms.constants.XFORMS_PREFIX,
"label")[0];
var value = _getElementsByTagNameNS(values[i],
alfresco.xforms.constants.XFORMS_NS,
alfresco.xforms.constants.XFORMS_PREFIX,
"value")[0];
var valid = true;
if (binding.constraint)
{
if (!dojo.render.html.ie)
{
valid = _evaluateXPath(binding.constraint, value, XPathResult.BOOLEAN_TYPE);
if (djConfig.isDebug)
{
dojo.debug("evaludated constraint " + binding.constraint +
" on " + dojo.dom.textContent(value) +
" to " + valid);
}
}
else
{
valid = !(dojo.dom.textContent(value) == dojo.dom.textContent(label) &&
dojo.dom.textContent(value).match(/^\[.+\]$/));
}
}
result.push({
id: value.getAttribute("id"),
label: valid ? dojo.dom.textContent(label) : "",
value: valid ? dojo.dom.textContent(value) : "_invalid_value_",
valid: valid
});
if (djConfig.isDebug)
{
dojo.debug("values["+ i + "] = {id: " + result[i].id +
",label: " + result[i].label + ",value: " + result[i].value +
",valid: " + result[i].valid + "}");
}
}
return result;
}
});
/**
* Handles xforms widget xf:select. Produces either a multiselect list or a set of
* checkboxes depending on the number of inputs.
*/
dojo.declare("alfresco.xforms.CheckboxSelect",
alfresco.xforms.AbstractSelectWidget,
function(xform, xformsNode)
{
},
{
/////////////////////////////////////////////////////////////////
// overridden methods
/////////////////////////////////////////////////////////////////
render: function(attach_point)
{
var values = this._getItemValues();
var initial_value = this.getInitialValue();
initial_value = initial_value ? initial_value.split(' ') : [];
this._selectedValues = [];
this.widget = document.createElement("div");
this.widget.style.width = "100%";
attach_point.appendChild(this.widget);
for (var i = 0; i < values.length; i++)
{
var checkboxDiv = document.createElement("div");
checkboxDiv.style.lineHeight = "16px";
this.widget.appendChild(checkboxDiv);
var checkbox = document.createElement("input");
checkbox.setAttribute("id", this.id + "_" + i + "-widget");
checkbox.setAttribute("name", this.id + "_" + i + "-widget");
checkbox.setAttribute("type", "checkbox");
checkbox.setAttribute("value", values[i].value);
if (initial_value.indexOf(values[i].value) != -1)
{
this._selectedValues.push(values[i].value);
checkbox.checked = true;
}
checkboxDiv.appendChild(checkbox);
checkboxDiv.appendChild(document.createTextNode(values[i].label));
dojo.event.connect(checkbox, "onclick", this, this._checkbox_clickHandler);
}
},
setValue: function(value, forceCommit)
{
if (!this.widget)
{
this.setInitialValue(value, forceCommit);
}
else
{
alfresco.xforms.ListSelect.superclass.setValue(this, value, forceCommit);
this._selectedValues = value.split(' ');
var checkboxes = this.widgets.getElementsByTagName("input");
for (var i = 0; i < checkboxes.length; i++)
{
checkboxes[i].checked =
this._selectedValues.indexOf(checkboxes[i].getAttribute("value")) != -1;
}
}
},
getValue: function()
{
return this._selectedValues.length == 0 ? null : this._selectedValues.join(" ");
},
/////////////////////////////////////////////////////////////////
// DOM event handlers
/////////////////////////////////////////////////////////////////
_checkbox_clickHandler: function(event)
{
this._selectedValues = [];
var all_checkboxes = this.widget.getElementsByTagName("input");
for (var i = 0; i < all_checkboxes.length; i++)
{
if (all_checkboxes[i] && all_checkboxes[i].checked)
{
this._selectedValues.push(all_checkboxes[i].getAttribute("value"));
}
}
this._commitValueChange();
}
});
/**
* Handles xforms widget xf:select. Produces either a multiselect list or a set of
* checkboxes depending on the number of inputs.
*/
dojo.declare("alfresco.xforms.ListSelect",
alfresco.xforms.AbstractSelectWidget,
function(xform, xformsNode)
{
},
{
/////////////////////////////////////////////////////////////////
// overridden methods
/////////////////////////////////////////////////////////////////
render: function(attach_point)
{
var values = this._getItemValues();
var initial_value = this.getInitialValue();
initial_value = initial_value ? initial_value.split(' ') : [];
this._selectedValues = [];
this.widget = document.createElement("select");
this.widget.setAttribute("id", this.id + "-widget");
this.widget.setAttribute("multiple", true);
attach_point.appendChild(this.widget);
for (var i = 0; i < values.length; i++)
{
var option = document.createElement("option");
option.appendChild(document.createTextNode(values[i].label));
option.setAttribute("value", values[i].value);
if (initial_value.indexOf(values[i].value) != -1)
{
this._selectedValues.push(values[i].value);
option.selected = true;
}
this.widget.appendChild(option);
}
dojo.event.connect(this.widget, "onblur", this, this._list_changeHandler);
},
setValue: function(value, forceCommit)
{
if (!this.widget)
{
this.setInitialValue(value, forceCommit);
}
else
{
alfresco.xforms.CheckboxSelect.superclass.setValue(this, value, forceCommit);
this._selectedValues = value.split(' ');
var options = this.widgets.getElementsByTagName("option");
for (var i = 0; i < options.length; i++)
{
options[i].selected =
this._selectedValues.indexOf(options[i].getAttribute("value")) != -1;
}
}
},
getValue: function()
{
return this._selectedValues.length == 0 ? null : this._selectedValues.join(" ");
},
/////////////////////////////////////////////////////////////////
// DOM event handlers
/////////////////////////////////////////////////////////////////
_list_changeHandler: function(event)
{
this._selectedValues = [];
for (var i = 0; i < event.target.options.length; i++)
{
if (event.target.options[i].selected)
{
this._selectedValues.push(event.target.options[i].getAttribute("value"));
}
}
this._commitValueChange();
},
});
/**
* Handles xforms widget xf:select1. Produces either a combobox or a set of
* radios depending on the number of inputs.
*/
dojo.declare("alfresco.xforms.RadioSelect1",
alfresco.xforms.AbstractSelectWidget,
function(xform, xformsNode)
{
},
{
/////////////////////////////////////////////////////////////////
// overridden methods
/////////////////////////////////////////////////////////////////
render: function(attach_point)
{
var values = this._getItemValues();
var initial_value = this.getInitialValue();
this.widget = document.createElement("div");
this.widget.style.width = "100%";
attach_point.appendChild(this.widget);
for (var i = 0; i < values.length; i++)
{
if (!values[i].valid)
{
// always skip the invalid values for radios
continue;
}
var radio_div = document.createElement("div");
radio_div.style.lineHeight = "16px";
this.widget.appendChild(radio_div);
var radio = document.createElement("input");
radio.setAttribute("id", this.id + "-widget");
radio.setAttribute("name", this.id + "-widget");
radio.setAttribute("type", "radio");
radio_div.appendChild(radio);
radio_div.appendChild(document.createTextNode(values[i].label));
radio.setAttribute("value", values[i].value);
if (values[i].value == initial_value)
{
this._selectedValue = initial_value;
radio.checked = true;
}
if (this.isReadonly())
{
radio.setAttribute("disabled", true);
}
dojo.event.connect(radio, "onclick", this, this._radio_clickHandler);
}
this.widget.style.height = this.widget.offsetHeight + "px";
},
/** */
setValue: function(value, forceCommit)
{
if (!this.widget)
{
this.setInitialValue(value, forceCommit);
}
else
{
alfresco.xforms.RadioSelect1.superclass.setValue.call(this, value, forceCommit);
this._selectedValue = value;
var radios = this.widget.getElementsByTagName("input");
for (var i = 0; i < radios.length; i++)
{
radios[i].checked = radios[i].getAttribute("value") == this._selectedValue;
}
}
},
getValue: function()
{
return this._selectedValue;
},
/////////////////////////////////////////////////////////////////
// DOM event handlers
/////////////////////////////////////////////////////////////////
_radio_clickHandler: function(event)
{
if (!event.target.checked)
{
var all_radios = this.widget.getElementsByTagName("input");
for (var i = 0; i < all_radios.length; i++)
{
if (all_radios[i].name == event.target.name)
{
all_radios[i].checked = event.target == all_radios[i];
}
}
}
this._selectedValue = event.target.value;
this._commitValueChange();
}
});
/**
* Handles xforms widget xf:select1. Produces either a combobox or a set of
* radios depending on the number of inputs.
*/
dojo.declare("alfresco.xforms.ComboboxSelect1",
alfresco.xforms.AbstractSelectWidget,
function(xform, xformsNode)
{
},
{
/////////////////////////////////////////////////////////////////
// overridden methods
/////////////////////////////////////////////////////////////////
render: function(attach_point)
{
var values = this._getItemValues();
var initial_value = this.getInitialValue();
this.widget = document.createElement("select");
this.widget.setAttribute("id", this.id + "-widget");
attach_point.appendChild(this.widget);
for (var i = 0; i < values.length; i++)
{
if (initial_value && !values[i].valid)
{
// skip the invalid value if we have a default value
continue;
}
var option = document.createElement("option");
this.widget.appendChild(option);
option.appendChild(document.createTextNode(values[i].label));
option.setAttribute("value", values[i].value);
if (values[i].value == initial_value)
{
this._selectedValue = initial_value;
option.selected = true;
}
if (this.isReadonly())
{
this.widget.setAttribute("disabled", true);
}
}
dojo.event.connect(this.widget, "onchange", this, this._combobox_changeHandler);
},
/** */
setValue: function(value, forceCommit)
{
if (!this.widget)
{
this.setInitialValue(value, forceCommit);
}
else
{
alfresco.xforms.ComboboxSelect1.superclass.setValue.call(this, value, forceCommit);
this._selectedValue = value;
var options = this.widget.getElementsByTagName("option");
for (var i = 0; i < options.length; i++)
{
options[i].selected = options[i].getAttribute("value") == this._selectedValue;
}
}
},
getValue: function()
{
return this._selectedValue;
},
/////////////////////////////////////////////////////////////////
// DOM event handlers
/////////////////////////////////////////////////////////////////
_combobox_changeHandler: function(event)
{
this._selectedValue = event.target.options[event.target.selectedIndex].value;
this._commitValueChange();
}
});
/**
* Handles xforms widget xf:select1 with a type of boolean.
*/
dojo.declare("alfresco.xforms.Checkbox",
alfresco.xforms.Widget,
function(xform, xformsNode)
{
},
{
/////////////////////////////////////////////////////////////////
// overridden methods
/////////////////////////////////////////////////////////////////
render: function(attach_point)
{
var initial_value = this.getInitialValue() == "true";
this.widget = document.createElement("input");
this.widget.setAttribute("type", "checkbox");
this.widget.setAttribute("id", this.id + "-widget");
attach_point.appendChild(this.widget);
if (initial_value)
{
this.widget.setAttribute("checked", true);
}
if (this.isReadonly())
{
this.widget.setAttribute("disabled", true);
}
dojo.event.connect(this.widget, "onclick", this, this._checkbox_clickHandler);
},
setValue: function(value, forceCommit)
{
if (!this.widget)
{
this.setInitialValue(value, forceCommit);
}
else
{
alfresco.xforms.Checkbox.superclass.setValue.call(this, value, forceCommit);
this.widget.checked = value == "true";
}
},
getValue: function()
{
return this.widget.checked;
},
/////////////////////////////////////////////////////////////////
// DOM event handlers
/////////////////////////////////////////////////////////////////
_checkbox_clickHandler: function(event)
{
this._commitValueChange();
}
});
////////////////////////////////////////////////////////////////////////////////
// widgets for date types
////////////////////////////////////////////////////////////////////////////////
/** The date picker widget which handles xforms widget xf:input with type xf:date */
dojo.declare("alfresco.xforms.DatePicker",
alfresco.xforms.Widget,
function(xform, xformsNode)
{
dojo.require("dojo.widget.DatePicker");
this._minInclusive = (_hasAttribute(this.xformsNode, alfresco.xforms.constants.ALFRESCO_PREFIX + ":minInclusive")
? this.xformsNode.getAttribute(alfresco.xforms.constants.ALFRESCO_PREFIX + ":minInclusive")
: null);
this._maxInclusive = (_hasAttribute(this.xformsNode, alfresco.xforms.constants.ALFRESCO_PREFIX + ":maxInclusive")
? this.xformsNode.getAttribute(alfresco.xforms.constants.ALFRESCO_PREFIX + ":maxInclusive")
: null);
// XXXarielb - change to a static
this._noValueSet = (alfresco.xforms.constants.resources["eg"] + " " +
dojo.date.format(new Date(),
{datePattern: alfresco.xforms.constants.DATE_FORMAT,
selector: 'dateOnly'}));
},
{
_createPicker: function()
{
var datePickerDiv = document.createElement("div");
this.domNode.parentNode.appendChild(datePickerDiv);
var dp_initial_value = this.getValue() || null; //dojo.date.toRfc3339(new Date());
var datePickerProperties = { value: dp_initial_value };
if (this._minInclusive)
{
datePickerProperties.startDate = this._minInclusive;
}
if (this._maxInclusive)
{
datePickerProperties.endDate = this._maxInclusive;
}
this.widget.picker = dojo.widget.createWidget("DatePicker",
datePickerProperties,
datePickerDiv);
this.domContainer.style.height =
Math.max(this.widget.picker.domNode.offsetHeight +
this.widget.offsetHeight +
dojo.html.getMargin(this.domNode.parentNode).height,
20) + "px";
dojo.event.connect(this.widget.picker,
"onValueChanged",
this,
this._datePicker_valueChangedHandler);
},
_destroyPicker: function()
{
if (this.widget.picker)
{
this.domNode.parentNode.removeChild(this.widget.picker.domNode);
this.widget.picker = null;
this.domContainer.style.height =
Math.max(this.widget.offsetHeight +
dojo.html.getMargin(this.domNode.parentNode).height,
20) + "px";
}
},
/////////////////////////////////////////////////////////////////
// overridden methods
/////////////////////////////////////////////////////////////////
render: function(attach_point)
{
var initial_value = this.getInitialValue();
attach_point.appendChild(this.domNode);
this.widget = document.createElement("input");
this.widget.setAttribute("id", this.id + "-widget");
this.widget.setAttribute("type", "text");
if (initial_value)
{
var jsDate = dojo.date.fromRfc3339(initial_value);
this.widget.setAttribute("value",
dojo.date.format(jsDate,
{datePattern: alfresco.xforms.constants.DATE_FORMAT,
selector: 'dateOnly'}));
}
else
{
this.widget.setAttribute("value", this._noValueSet);
dojo.html.addClass(this.widget, "xformsGhostText");
}
if (this.isReadonly())
{
this.widget.setAttribute("disabled", true);
}
this.domNode.appendChild(this.widget);
var expandoImage = document.createElement("img");
expandoImage.setAttribute("src", alfresco.constants.WEBAPP_CONTEXT + "/images/icons/action.gif");
expandoImage.align = "absmiddle";
expandoImage.style.margin = "0px 5px";
this.domNode.appendChild(expandoImage);
if (!this.isReadonly())
{
dojo.event.connect(expandoImage, "onclick", this, this._expando_clickHandler);
dojo.event.connect(this.widget, "onfocus", this, this._dateTextBox_focusHandler);
dojo.event.connect(this.widget, "onchange", this, this._dateTextBox_changeHandler);
}
},
setValue: function(value, forceCommit)
{
if (!this.widget)
{
this.setInitialValue(value, forceCommit);
}
else
{
alfresco.xforms.DatePicker.superclass.setValue.call(this, value, forceCommit);
var jsDate = dojo.date.fromRfc3339(value);
this.widget.value = dojo.date.format(jsDate,
{datePattern: alfresco.xforms.constants.DATE_FORMAT,
selector: 'dateOnly'});
dojo.html.removeClass(this.widget, "xformsGhostText");
}
},
getValue: function()
{
if (this.widget.value == null ||
this.widget.value.length == 0 ||
this.widget.value == this._noValueSet)
{
return null;
}
else
{
var jsDate = dojo.date.parse(this.widget.value,
{datePattern: alfresco.xforms.constants.DATE_FORMAT,
selector: 'dateOnly'});
return dojo.date.toRfc3339(jsDate, "dateOnly");
}
},
/////////////////////////////////////////////////////////////////
// DOM event handlers
/////////////////////////////////////////////////////////////////
_dateTextBox_focusHandler: function(event)
{
this._destroyPicker();
},
_dateTextBox_changeHandler: function(event)
{
this._commitValueChange();
},
_datePicker_valueChangedHandler: function(date)
{
var rfcDate = dojo.date.toRfc3339(date, "dateOnly");
this._destroyPicker();
this.setValue(rfcDate);
this._commitValueChange();
},
_expando_clickHandler: function()
{
if (this.widget.picker)
{
this._destroyPicker();
}
else
{
this._createPicker();
}
}
});
/** The date picker widget which handles xforms widget xf:input with type xf:date */
dojo.declare("alfresco.xforms.TimePicker",
alfresco.xforms.Widget,
function(xform, xformsNode)
{
dojo.require("dojo.widget.TimePicker");
this._noValueSet = (alfresco.xforms.constants.resources["eg"] + " " +
dojo.date.format(new Date(),
{timePattern: alfresco.xforms.constants.TIME_FORMAT,
selector: "timeOnly"}));
this._xformsFormat = "HH:mm:ss.S";
},
{
/** */
_createPicker: function()
{
var timePickerDiv = document.createElement("div");
this.domNode.appendChild(timePickerDiv);
var jsDate = (this.getValue()
? dojo.date.parse(this.getValue(),
{timePattern: this._xformsFormat,
selector: "timeOnly"})
: new Date());
this.widget.picker = dojo.widget.createWidget("TimePicker",
{
value: jsDate
},
timePickerDiv);
this.widget.picker.anyTimeContainerNode.innerHTML = "";
// don't let it float - it screws up layout somehow
this.widget.picker.domNode.style.cssFloat = "none";
this.domContainer.style.height =
Math.max(this.widget.picker.domNode.offsetHeight +
this.widget.offsetHeight +
dojo.html.getMargin(this.domNode.parentNode).height,
20) + "px";
dojo.event.connect(this.widget.picker,
"onValueChanged",
this,
this._timePicker_valueChangedHandler);
},
_destroyPicker: function()
{
if (this.widget.picker)
{
this.domNode.removeChild(this.widget.picker.domNode);
this.widget.picker = null;
this.domContainer.style.height =
Math.max(this.widget.offsetHeight +
dojo.html.getMargin(this.domNode.parentNode).height,
20) + "px";
}
},
/////////////////////////////////////////////////////////////////
// overridden methods
/////////////////////////////////////////////////////////////////
render: function(attach_point)
{
var initial_value = this.getInitialValue();
attach_point.appendChild(this.domNode);
this.widget = document.createElement("input");
this.widget.setAttribute("id", this.id + "-widget");
this.widget.setAttribute("type", "text");
if (initial_value)
{
var jsDate = dojo.date.parse(initial_value, {timePattern: this._xformsFormat, selector: "timeOnly"});
this.widget.setAttribute("value",
dojo.date.format(jsDate,
{timePattern: alfresco.xforms.constants.TIME_FORMAT,
selector: "timeOnly"}));
}
else
{
this.widget.setAttribute("value", this._noValueSet);
dojo.html.addClass(this.widget, "xformsGhostText");
}
if (this.isReadonly())
{
this.widget.setAttribute("disabled", true);
}
this.domNode.appendChild(this.widget);
var expandoImage = document.createElement("img");
expandoImage.setAttribute("src", alfresco.constants.WEBAPP_CONTEXT + "/images/icons/action.gif");
expandoImage.align = "absmiddle";
expandoImage.style.margin = "0px 5px";
this.domNode.appendChild(expandoImage);
if (!this.isReadonly())
{
dojo.event.connect(expandoImage, "onclick", this, this._expando_clickHandler);
dojo.event.connect(this.widget, "onfocus", this, this._timeTextBox_focusHandler);
dojo.event.connect(this.widget, "onchange", this, this._timeTextBox_changeHandler);
}
},
setValue: function(value, forceCommit)
{
if (!this.widget)
{
this.setInitialValue(value, forceCommit);
}
else
{
alfresco.xforms.TimePicker.superclass.setValue.call(this, value, forceCommit);
var jsDate = dojo.date.parse(value, {timePattern: this._xformsFormat, selector: "timeOnly"});
this.widget.value = dojo.date.format(jsDate,
{timePattern: alfresco.xforms.constants.TIME_FORMAT,
selector: "timeOnly"});
dojo.html.removeClass(this.widget, "xformsGhostText");
}
},
getValue: function()
{
if (this.widget.value == null ||
this.widget.value.length == 0 ||
this.widget.value == this._noValueSet)
{
return null;
}
else
{
var jsDate = dojo.date.parse(this.widget.value,
{timePattern: alfresco.xforms.constants.TIME_FORMAT,
selector: "timeOnly"});
return dojo.date.format(jsDate, {timePattern: this._xformsFormat, selector: "timeOnly"});
}
},
/////////////////////////////////////////////////////////////////
// DOM event handlers
/////////////////////////////////////////////////////////////////
_timeTextBox_focusHandler: function(event)
{
this._destroyPicker();
},
_timeTextBox_changeHandler: function(event)
{
this._commitValueChange();
},
_timePicker_valueChangedHandler: function(date)
{
var xfDate = dojo.date.format(date, {timePattern: this._xformsFormat, selector: "timeOnly"});
this.setValue(xfDate);
this._commitValueChange();
},
_expando_clickHandler: function()
{
if (this.widget.picker)
{
this._destroyPicker();
}
else
{
this._createPicker();
}
}
});
/** The date time picker widget which handles xforms widget xf:input with type xf:datetime */
dojo.declare("alfresco.xforms.DateTimePicker",
alfresco.xforms.Widget,
function(xform, xformsNode)
{
dojo.require("dojo.widget.DatePicker");
dojo.require("dojo.widget.TimePicker");
this._noValueSet = (alfresco.xforms.constants.resources["eg"] + " " +
dojo.date.format(new Date(),
{datePattern: alfresco.xforms.constants.DATE_TIME_FORMAT,
selector: "dateOnly"}));
},
{
/** */
_createPicker: function()
{
this._pickerDiv = document.createElement("div");
this._pickerDiv.style.position = "relative";
this._pickerDiv.style.width = this.widget.offsetWidth + "px";
this.domNode.appendChild(this._pickerDiv);
var datePickerDiv = document.createElement("div");
datePickerDiv.style.position = "absolute";
datePickerDiv.style.left = "0px";
datePickerDiv.style.top = "0px";
this._pickerDiv.appendChild(datePickerDiv);
var dp_initial_value = this.getValue() || dojo.date.toRfc3339(new Date());
this.widget.datePicker = dojo.widget.createWidget("DatePicker",
{
value: dp_initial_value
},
datePickerDiv);
var timePickerDiv = document.createElement("div");
timePickerDiv.style.position = "absolute";
timePickerDiv.style.right = "0px";
timePickerDiv.style.top = "0px";
this._pickerDiv.appendChild(timePickerDiv);
var jsDate = this.getValue() ? dojo.date.fromRfc3339(this.getValue()) : new Date();
this.widget.timePicker = dojo.widget.createWidget("TimePicker",
{
value: jsDate
},
timePickerDiv);
this.widget.timePicker.anyTimeContainerNode.innerHTML = "";
// don't let it float - it screws up layout somehow
this.widget.timePicker.domNode.style.cssFloat = "none";
this._pickerDiv.style.height = Math.max(this.widget.timePicker.domNode.offsetHeight,
this.widget.datePicker.domNode.offsetHeight);
this.domContainer.style.height =
Math.max(this._pickerDiv.offsetHeight +
this.widget.offsetHeight +
dojo.html.getMargin(this.domNode.parentNode).height,
20) + "px";
dojo.event.connect(this.widget.datePicker,
"onValueChanged",
this,
this._datePicker_valueChangedHandler);
dojo.event.connect(this.widget.timePicker,
"onValueChanged",
this,
this._timePicker_valueChangedHandler);
},
_destroyPicker: function()
{
if (this._pickerDiv)
{
this.domNode.removeChild(this._pickerDiv);
this.widget.datePicker = null;
this.widget.timePicker = null;
this._pickerDiv = null;
this.domContainer.style.height =
Math.max(this.widget.offsetHeight +
dojo.html.getMargin(this.domNode.parentNode).height,
20) + "px";
}
},
/////////////////////////////////////////////////////////////////
// overridden methods
/////////////////////////////////////////////////////////////////
render: function(attach_point)
{
var initial_value = this.getInitialValue();
attach_point.appendChild(this.domNode);
this.widget = document.createElement("input");
this.widget.setAttribute("id", this.id + "-widget");
this.widget.setAttribute("type", "text");
if (initial_value)
{
var jsDate = dojo.date.fromRfc3339(initial_value);
this.widget.setAttribute("value",
dojo.date.format(jsDate,
{timePattern: alfresco.xforms.constants.DATE_TIME_FORMAT,
selector: "timeOnly"}));
}
else
{
this.widget.setAttribute("value", this._noValueSet);
dojo.html.addClass(this.widget, "xformsGhostText");
}
this.domNode.appendChild(this.widget);
this.widget.style.width = (3 * this.widget.offsetWidth) + "px";
var expandoImage = document.createElement("img");
expandoImage.setAttribute("src", alfresco.constants.WEBAPP_CONTEXT + "/images/icons/action.gif");
expandoImage.align = "absmiddle";
expandoImage.style.margin = "0px 5px";
this.domNode.appendChild(expandoImage);
dojo.event.connect(expandoImage, "onclick", this, this._expando_clickHandler);
dojo.event.connect(this.widget, "onfocus", this, this._dateTimeTextBox_focusHandler);
dojo.event.connect(this.widget, "onchange", this, this._dateTimeTextBox_changeHandler);
},
setValue: function(value, forceCommit)
{
if (!this.widget)
{
this.setInitialValue(value, forceCommit);
}
else
{
alfresco.xforms.DateTimePicker.superclass.setValue.call(this, value, forceCommit);
var jsDate = dojo.date.fromRfc3339(value);
this.widget.value = dojo.date.format(jsDate,
{datePattern: alfresco.xforms.constants.DATE_TIME_FORMAT,
selector: "dateOnly"});
dojo.html.removeClass(this.widget, "xformsGhostText");
}
},
getValue: function()
{
if (this.widget.value == null ||
this.widget.value.length == 0 ||
this.widget.value == this._noValueSet)
{
return null;
}
else
{
var jsDate = dojo.date.parse(this.widget.value,
{datePattern: alfresco.xforms.constants.DATE_TIME_FORMAT,
selector: "dateOnly"});
return dojo.date.toRfc3339(jsDate);
}
},
/////////////////////////////////////////////////////////////////
// DOM event handlers
/////////////////////////////////////////////////////////////////
_dateTimeTextBox_focusHandler: function(event)
{
this._destroyPicker();
},
_dateTimeTextBox_changeHandler: function(event)
{
this._commitValueChange();
},
_timePicker_valueChangedHandler: function(date)
{
var value = this.getValue() ? dojo.date.fromRfc3339(this.getValue()) : new Date();
value.setHours(date.getHours());
value.setMinutes(date.getMinutes());
value = dojo.date.toRfc3339(value);
this.setValue(value);
this._commitValueChange();
},
_datePicker_valueChangedHandler: function(date)
{
var value = this.getValue() ? dojo.date.fromRfc3339(this.getValue()) : new Date();
value.setYear(date.getYear());
value.setMonth(date.getMonth());
value.setDate(date.getDate());
value = dojo.date.toRfc3339(value);
this.setValue(value);
this._commitValueChange();
},
_expando_clickHandler: function()
{
if (this._pickerDiv)
{
this._destroyPicker();
}
else
{
this._createPicker();
}
}
});
/** The year picker handles xforms widget xf:input with a gYear type */
dojo.declare("alfresco.xforms.YearPicker",
alfresco.xforms.TextField,
function(xform, xformsNode)
{
},
{
/////////////////////////////////////////////////////////////////
// overridden methods
/////////////////////////////////////////////////////////////////
render: function(attach_point)
{
alfresco.xforms.YearPicker.superclass.render.call(this, attach_point);
this.widget.size = "4";
this.widget.setAttribute("maxlength", "4");
},
getInitialValue: function()
{
var result = alfresco.xforms.YearPicker.superclass.getInitialValue.call(this);
return result ? result.replace(/^0*([^0]+)$/, "$1") : result;
},
setValue: function(value, forceCommit)
{
alfresco.xforms.YearPicker.superclass.setValue.call(this,
(value
? value.replace(/^0*([^0]+)$/, "$1")
: null),
forceCommit);
},
getValue: function()
{
var result = alfresco.xforms.YearPicker.superclass.getValue.call(this);
return result ? dojo.string.padLeft(result, 4, "0") : null;
}
});
/** The day picker widget which handles xforms widget xf:input with type xf:gDay */
dojo.declare("alfresco.xforms.DayPicker",
alfresco.xforms.ComboboxSelect1,
function(xform, xformsNode)
{
},
{
/////////////////////////////////////////////////////////////////
// overridden methods
/////////////////////////////////////////////////////////////////
_getItemValues: function()
{
var result = [];
result.push({id: "day_empty", label: "", value: "", valid: false});
for (var i = 1; i <= 31; i++)
{
result.push({
id: "day_" + i,
label: i,
value: "---" + (i < 10 ? "0" + i : i),
valid: true});
}
return result;
}
});
/** The month picker widget which handles xforms widget xf:input with type xf:gMonth */
dojo.declare("alfresco.xforms.MonthPicker",
alfresco.xforms.ComboboxSelect1,
function(xform, xformsNode)
{
},
{
/////////////////////////////////////////////////////////////////
// overridden methods
/////////////////////////////////////////////////////////////////
_getItemValues: function()
{
var result = [];
result.push({id: "month_empty", label: "", value: "", valid: false});
for (var i = 0; i <= 12; i++)
{
var d = new Date();
d.setMonth(i);
result.push({
id: "month_" + i,
label: dojo.date.getMonthName(d),
value: "--" + (i + 1 < 10 ? "0" + (i + 1) : i + 1),
valid: true});
}
return result;
}
});
/** The month day picker widget which handles xforms widget xf:input with type xf:gMonthDay */
dojo.declare("alfresco.xforms.MonthDayPicker",
alfresco.xforms.Widget,
function(xform, xformsNode)
{
this.monthPicker = new alfresco.xforms.MonthPicker(xform, xformsNode);
this.monthPicker._compositeParent = this;
this.dayPicker = new alfresco.xforms.DayPicker(xform, xformsNode);
this.dayPicker._compositeParent = this;
},
{
/////////////////////////////////////////////////////////////////
// overridden methods
/////////////////////////////////////////////////////////////////
render: function(attach_point)
{
this.setValue(this.getInitialValue());
attach_point.appendChild(this.domNode);
this.dayPicker.render(this.domNode);
this.dayPicker.widget.style.marginRight = "10px";
this.monthPicker.render(this.domNode);
},
setValue: function(value)
{
this.monthPicker.setValue(value ? value.match(/^--[^-]+/)[0] : null);
this.dayPicker.setValue(value ? "---" + value.replace(/^--[^-]+-/, "") : null);
},
getValue: function()
{
// format is --MM-DD
var day = this.dayPicker.getValue();
var month = this.monthPicker.getValue();
return month && day ? day.replace(/^--/, month) : null;
}
});
/** The year month picker widget which handles xforms widget xf:input with type xf:gYearMonth */
dojo.declare("alfresco.xforms.YearMonthPicker",
alfresco.xforms.Widget,
function(xform, xformsNode)
{
this.yearPicker = new alfresco.xforms.YearPicker(xform, xformsNode);
this.yearPicker._compositeParent = this;
this.monthPicker = new alfresco.xforms.MonthPicker(xform, xformsNode);
this.monthPicker._compositeParent = this;
},
{
/////////////////////////////////////////////////////////////////
// overridden methods
/////////////////////////////////////////////////////////////////
render: function(attach_point)
{
this.setValue(this.getInitialValue());
attach_point.appendChild(this.domNode);
this.monthPicker.render(this.domNode);
this.monthPicker.widget.style.marginRight = "10px";
this.yearPicker.domNode.style.display = "inline";
this.yearPicker.render(this.domNode);
},
setValue: function(value)
{
this.monthPicker.setValue(value ? value.replace(/^[^-]+-/, "--") : null);
this.yearPicker.setValue(value ? value.match(/^[^-]+/)[0] : null);
},
getValue: function()
{
// format is CCYY-MM
var year = this.yearPicker.getValue();
var month = this.monthPicker.getValue();
return year && month ? month.replace(/^-/, year) : null;
}
});
////////////////////////////////////////////////////////////////////////////////
// widgets for group types
////////////////////////////////////////////////////////////////////////////////
/**
* Handles xforms widget xf:group. A group renders and manages a set of children
* and provides a header for expanding and collapsing the group. A group header
* is shown for all group that don't have xf:appearance set to 'repeated' and
* that are not the root group.
*/
dojo.declare("alfresco.xforms.AbstractGroup",
alfresco.xforms.Widget,
function(xform, xformsNode)
{
this._children = [];
dojo.html.removeClass(this.domNode, "xformsItem");
if (!this.statics._requiredImage)
{
this.statics._requiredImage = document.createElement("img");
this.statics._requiredImage.setAttribute("src",
alfresco.constants.WEBAPP_CONTEXT + "/images/icons/required_field.gif");
this.statics._requiredImage.setAttribute("class", "xformsItemRequiredImage");
}
},
{
/////////////////////////////////////////////////////////////////
// methods & properties
/////////////////////////////////////////////////////////////////
statics: { _requiredImage: null },
/** Returns the child at the specified index or null if the index is out of range. */
getChildAt: function(index)
{
return index < this._children.length ? this._children[index] : null;
},
/** Returns the index of a particular child or -1 if the child was not found. */
getChildIndex: function(child)
{
for (var i = 0; i < this._children.length; i++)
{
if (djConfig.isDebug)
{
dojo.debug(this.id + "[" + i + "]: " +
" is " + this._children[i].id +
" the same as " + child.id + "?");
}
if (this._children[i] == child)
{
return i;
}
}
return -1;
},
/** Adds the child to end of the list of children. */
addChild: function(child)
{
return this._insertChildAt(child, this._children.length);
},
/** Inserts a child at the specified position. */
_insertChildAt: function(child, position)
{
dojo.debug(this.id + "._insertChildAt(" + child.id + ", " + position + ")");
child.parent = this;
child.domContainer = child.domContainer || document.createElement("div");
child.domContainer.setAttribute("id", child.id + "-domContainer");
dojo.html.addClass(child.domContainer, "xformsItemDOMContainer");
if (position == this._children.length)
{
this.domNode.childContainerNode.appendChild(child.domContainer);
this._children.push(child);
}
else
{
this.domNode.childContainerNode.insertBefore(child.domContainer,
this.getChildAt(position).domContainer);
this._children.splice(position, 0, child);
}
return child.domContainer;
},
/** Removes the child at the specified position. */
_removeChildAt: function(position)
{
var child = this.getChildAt(position);
if (!child)
{
throw new Error("unable to find child at " + position);
}
this._children.splice(position, 1);
child.domContainer.group = this;
var anim = dojo.lfx.html.fadeOut(child.domContainer, 500);
anim.onEnd = function()
{
child.domContainer.style.display = "none";
child._destroy();
dojo.dom.removeChildren(child.domContainer);
dojo.dom.removeNode(child.domContainer);
child.domContainer.group._updateDisplay(false);
};
anim.play();
this._childRemoved(child);
return child;
},
/** Event handler for when a child has been added. */
_childAdded: function(child) { },
/** Event handler for when a child has been removed. */
_childRemoved: function(child) { },
/** Utility function to create the a label container */
_createLabelContainer: function(child)
{
var labelNode = document.createElement("span");
labelNode.setAttribute("id", child.id + "-label");
labelNode.style.position = "relative";
labelNode.style.left = "0px";
child.domContainer.appendChild(labelNode);
var requiredImage = this.statics._requiredImage.cloneNode(true);
labelNode.appendChild(requiredImage);
if (!child.isRequired())
{
requiredImage.style.visibility = "hidden";
}
var label = child.getLabel();
if (label)
{
child.labelNode = document.createElement("span");
child.labelNode.style.verticalAlign = "middle";
child.labelNode.style.marginRight = "5px";
labelNode.appendChild(child.labelNode);
child.labelNode.appendChild(document.createTextNode(label));
}
var hint = child.getHint();
if (hint)
{
labelNode.setAttribute("title", hint);
requiredImage.setAttribute("alt", hint);
}
return labelNode;
},
/////////////////////////////////////////////////////////////////
// overridden methods & properties
/////////////////////////////////////////////////////////////////
isValidForSubmit: function()
{
return true;
},
/** Iterates all children a produces an array of widgets which are invalid for submit. */
getWidgetsInvalidForSubmit: function()
{
var result = [];
for (var i = 0; i < this._children.length; i++)
{
if (this._children[i] instanceof alfresco.xforms.AbstractGroup)
{
result = result.concat(this._children[i].getWidgetsInvalidForSubmit());
}
else if (!this._children[i].isValidForSubmit())
{
result.push(this._children[i]);
}
}
return result;
},
/** Recusively destroys all children. */
_destroy: function()
{
alfresco.xforms.AbstractGroup.superclass._destroy.call(this);
for (var i = 0; i < this._children.length; i++)
{
this._children[i]._destroy();
}
},
setReadonly: function(readonly)
{
alfresco.xforms.AbstractGroup.superclass.setReadonly.call(this, readonly);
for (var i = 0; i < this._children.length; i++)
{
this._children[i].setReadonly(readonly);
}
},
render: function(attach_point)
{
this.domNode.widget = this;
return this.domNode;
},
_updateDisplay: function(recursively)
{
if (recursively)
{
this._children[i]._updateDisplay(recursively);
}
},
showAlert: function()
{
for (var i = 0; i < this._children.length; i++)
{
this._children[i].showAlert();
}
},
hideAlert: function()
{
for (var i = 0; i < this._children.length; i++)
{
this._children[i].hideAlert();
}
}
});
/**
* Handles xforms widget xf:group. A group renders and manages a set of children
* and provides a header for expanding and collapsing the group. A group header
* is shown for all group that don't have xf:appearance set to 'repeated' and
* that are not the root group.
*/
dojo.declare("alfresco.xforms.VGroup",
alfresco.xforms.AbstractGroup,
function(xform, xformsNode)
{
},
{
/////////////////////////////////////////////////////////////////
// methods & properties
/////////////////////////////////////////////////////////////////
_groupHeaderNode: null,
/** Inserts a child at the specified position. */
_insertChildAt: function(child, position)
{
if (!this.domNode.childContainerNode.parentNode)
{
// only add this to the dom once we're adding a child
this.domNode.appendChild(this.domNode.childContainerNode);
}
child.domContainer =
alfresco.xforms.VGroup.superclass._insertChildAt.call(this, child, position);
if (this.parent && this.parent.domNode)
{
child.domContainer.style.top = this.parent.domNode.style.bottom;
}
function shouldInsertDivider(group, child, position)
{
if (group.getAppearance() != "full")
{
return false;
}
if (group instanceof alfresco.xforms.Repeat)
{
return false;
}
if (!child.isVisible())
{
return false;
}
if (group._children[position - 1] instanceof alfresco.xforms.AbstractGroup)
{
return true;
}
if (child instanceof alfresco.xforms.AbstractGroup)
{
for (var i = position - 1; i > 0; i--)
{
if (group._children[i].isVisible())
{
return true;
}
}
}
return false;
}
if (shouldInsertDivider(this, child, position))
{
var divider = document.createElement("div");
dojo.html.setClass(divider, "xformsGroupDivider");
this.domNode.childContainerNode.insertBefore(divider,
child.domContainer);
}
var labelNode = null;
if (!(child instanceof alfresco.xforms.AbstractGroup))
{
labelNode = this._createLabelContainer(child);
child.domContainer.appendChild(labelNode);
}
var contentDiv = document.createElement("div");
contentDiv.setAttribute("id", child.id + "-content");
dojo.html.setClass(contentDiv, "xformsGroupItem");
child.domContainer.appendChild(contentDiv);
contentDiv.style.left = (child instanceof alfresco.xforms.AbstractGroup
? "0px"
: "30%");
contentDiv.style.width = (child instanceof alfresco.xforms.AbstractGroup
? "100%"
: (1 - (contentDiv.offsetLeft /
child.domContainer.offsetWidth)) * 100 + "%");
child.render(contentDiv);
if (!(child instanceof alfresco.xforms.AbstractGroup))
{
child.domContainer.style.height =
Math.max(contentDiv.offsetHeight +
dojo.html.getMargin(contentDiv).height, 20) + "px";
}
dojo.debug(contentDiv.getAttribute("id") + " offsetTop is " + contentDiv.offsetTop);
contentDiv.style.top = "-" + Math.max(0, contentDiv.offsetTop -
dojo.html.getPixelValue(contentDiv, "margin-top")) + "px";
if (labelNode)
{
labelNode.style.top = (contentDiv.offsetTop + ((.5 * contentDiv.offsetHeight) -
(.5 * labelNode.offsetHeight))) + "px";
}
contentDiv.widget = child;
this._updateDisplay(false);
this._childAdded(child);
return child.domContainer;
},
/////////////////////////////////////////////////////////////////
// overridden methods & properties
/////////////////////////////////////////////////////////////////
render: function(attach_point)
{
this.domNode.widget = this;
if (false && djConfig.isDebug)
{
var idNode = document.createElement("div");
idNode.style.backgroundColor = "red";
idNode.appendChild(document.createTextNode(this.getLabel()));
this.domNode.appendChild(idNode);
}
this.domNode.style.marginLeft = 10 + "px";
if (this.getAppearance() == "full")
{
dojo.html.setClass(this.domNode, "xformsGroup");
this.domNode.style.position = "relative";
this.domNode.style.marginRight = (parseInt(this.domNode.style.marginLeft) / 3) + "px";
if (dojo.render.html.ie)
{
this.domNode.style.width = "100%";
}
else
{
this.domNode.style.width = (1 - ((dojo.html.getBorder(this.domNode).width +
dojo.html.getPadding(this.domNode).width +
dojo.html.getMargin(this.domNode).width) /
attach_point.offsetWidth)) * 100 + "%";
}
this._groupHeaderNode = document.createElement("div");
this._groupHeaderNode.setAttribute("id", this.id + "-groupHeaderNode");
dojo.html.setClass(this._groupHeaderNode, "xformsGroupHeader");
this.domNode.appendChild(this._groupHeaderNode);
this.toggleExpandedImage = document.createElement("img");
this._groupHeaderNode.appendChild(this.toggleExpandedImage);
this.toggleExpandedImage.setAttribute("src", alfresco.xforms.constants.EXPANDED_IMAGE.src);
this.toggleExpandedImage.align = "absmiddle";
this.toggleExpandedImage.style.marginLeft = "5px";
this.toggleExpandedImage.style.marginRight = "5px";
dojo.event.connect(this.toggleExpandedImage,
"onclick",
this,
this._toggleExpanded_clickHandler);
this._groupHeaderNode.appendChild(document.createTextNode(this.getLabel()));
}
attach_point.appendChild(this.domNode);
this.domNode.childContainerNode = document.createElement("div");
this.domNode.childContainerNode.setAttribute("id", this.id + "-childContainerNode");
this.domNode.childContainerNode.style.position = "relative";
this.domNode.childContainerNode.style.width = "100%";
return this.domNode;
},
/** Indicates if the group is expanded. */
isExpanded: function()
{
return (this.toggleExpandedImage.getAttribute("src") ==
alfresco.xforms.constants.EXPANDED_IMAGE.src);
},
/**
* Sets the expanded state of the widget. If collapsed, everything but the header
* will be hidden.
*/
setExpanded: function(expanded)
{
if (expanded != this.isExpanded())
{
this.toggleExpandedImage.src =
(expanded
? alfresco.xforms.constants.EXPANDED_IMAGE.src
: alfresco.xforms.constants.COLLAPSED_IMAGE.src);
this.domNode.childContainerNode.style.display = expanded ? "block" : "none";
}
},
_updateDisplay: function(recursively)
{
if (dojo.render.html.ie)
{
this.domNode.style.width = "100%";
}
else
{
this.domNode.style.width = (1 - ((dojo.html.getBorder(this.domNode).width +
dojo.html.getPadding(this.domNode).width +
dojo.html.getMargin(this.domNode).width) /
this.domNode.parentNode.offsetWidth)) * 100 + "%";
}
for (var i = 0; i < this._children.length; i++)
{
var contentDiv = document.getElementById(this._children[i].id + "-content");
contentDiv.style.position = "static";
contentDiv.style.top = "0px";
contentDiv.style.left = "0px";
contentDiv.style.position = "relative";
contentDiv.style.left = (this._children[i] instanceof alfresco.xforms.AbstractGroup
? "0px"
: "30%");
contentDiv.style.width = (this._children[i] instanceof alfresco.xforms.AbstractGroup
? "100%"
: (1 - (contentDiv.offsetLeft /
this._children[i].domContainer.parentNode.offsetWidth)) * 100 + "%");
if (recursively)
{
this._children[i]._updateDisplay(recursively);
}
if (!(this._children[i] instanceof alfresco.xforms.AbstractGroup))
{
this._children[i].domContainer.style.height =
Math.max(contentDiv.offsetHeight +
dojo.html.getMargin(contentDiv).height, 20) + "px";
}
contentDiv.style.top = "-" + Math.max(0, contentDiv.offsetTop -
dojo.html.getPixelValue(contentDiv, "margin-top")) + "px";
var labelNode = document.getElementById(this._children[i].id + "-label");
if (labelNode)
{
labelNode.style.position = "static";
labelNode.style.top = "0px";
labelNode.style.left = "0px";
labelNode.style.position = "relative";
labelNode.style.top = (contentDiv.offsetTop + ((.5 * contentDiv.offsetHeight) -
(.5 * labelNode.offsetHeight))) + "px";
}
}
},
/////////////////////////////////////////////////////////////////
// DOM event handlers
/////////////////////////////////////////////////////////////////
_toggleExpanded_clickHandler: function(event)
{
this.setExpanded(!this.isExpanded());
}
});
/**
* Handles xforms widget xf:group. A group renders and manages a set of children
* and provides a header for expanding and collapsing the group. A group header
* is shown for all group that don't have xf:appearance set to 'repeated' and
* that are not the root group.
*/
dojo.declare("alfresco.xforms.HGroup",
alfresco.xforms.AbstractGroup,
function(xform, xformsNode)
{
},
{
/////////////////////////////////////////////////////////////////
// methods & properties
/////////////////////////////////////////////////////////////////
/** Inserts a child at the specified position. */
_insertChildAt: function(child, position)
{
child.domContainer = document.createElement("td");
child.domContainer.style.marginRight = "5px";
child.domContainer =
alfresco.xforms.HGroup.superclass._insertChildAt.call(this, child, position);
var labelNode = this._createLabelContainer(child);
child.domContainer.appendChild(labelNode);
var contentDiv = document.createElement("div");
contentDiv.setAttribute("id", child.id + "-content");
dojo.html.setClass(contentDiv, "xformsGroupItem");
child.domContainer.appendChild(contentDiv);
contentDiv.style.left = labelNode.offsetWidth + "px";
child.render(contentDiv);
var childDomNodeWidth = (child.domNode.offsetWidth +
dojo.html.getMargin(child.domNode).width +
dojo.html.getBorder(child.domNode).width);
if (childDomNodeWidth < contentDiv.offsetWidth)
{
// if we don't have a greedy widget (width 100%) try to constrain the cells
// width so we can fit as much as possible on a row
contentDiv.style.width = childDomNodeWidth + "px";
child.domContainer.style.width = (contentDiv.offsetWidth + labelNode.offsetWidth) + "px";
}
if (!(child instanceof alfresco.xforms.AbstractGroup))
{
child.domContainer.style.height =
Math.max(contentDiv.offsetHeight +
dojo.html.getMargin(contentDiv).height, 20) + "px";
}
dojo.debug(contentDiv.getAttribute("id") + " offsetTop is " + contentDiv.offsetTop);
contentDiv.style.top = "-" + Math.max(0, contentDiv.offsetTop -
dojo.html.getPixelValue(contentDiv, "margin-top")) + "px";
if (labelNode)
{
labelNode.style.top = (contentDiv.offsetTop + ((.5 * contentDiv.offsetHeight) -
(.5 * labelNode.offsetHeight))) + "px";
}
contentDiv.widget = child;
this._updateDisplay(false);
this._childAdded(child);
return child.domContainer;
},
/////////////////////////////////////////////////////////////////
// overridden methods & properties
/////////////////////////////////////////////////////////////////
render: function(attach_point)
{
this.domNode.widget = this;
if (false && djConfig.isDebug)
{
var idNode = document.createElement("div");
idNode.style.backgroundColor = "red";
idNode.appendChild(document.createTextNode(this.getLabel()));
this.domNode.appendChild(idNode);
}
this.domNode.style.marginLeft = 10 + "px";
this.domNode.style.position = "relative";
this.domNode.style.marginRight = (parseInt(this.domNode.style.marginLeft) / 3) + "px";
attach_point.appendChild(this.domNode);
var ccnode = document.createElement("table");
ccnode.style.width = "100%";
ccnode.setAttribute("cellpadding", "0px");
ccnode.setAttribute("cellspacing", "0px");
this.domNode.appendChild(ccnode);
this.domNode.childContainerNode = document.createElement("tr");
ccnode.appendChild(this.domNode.childContainerNode);
this.domNode.childContainerNode.setAttribute("id", this.id + "-childContainerNode");
this.domNode.childContainerNode.style.position = "relative";
this.domNode.childContainerNode.style.width = "100%";
var me = this;
dojo.event.browser.addListener(window,
"onresize",
function() { me._updateDisplay(false) },
false);
return this.domNode;
},
_updateDisplay: function(recursively)
{
if (dojo.render.html.ie)
{
this.domNode.style.width = "100%";
}
else
{
this.domNode.style.width = (1 - ((dojo.html.getBorder(this.domNode).width +
dojo.html.getPadding(this.domNode).width +
dojo.html.getMargin(this.domNode).width) /
this.domNode.parentNode.offsetWidth)) * 100 + "%";
}
for (var i = 0; i < this._children.length; i++)
{
var contentDiv = document.getElementById(this._children[i].id + "-content");
var labelNode = document.getElementById(this._children[i].id + "-label");
contentDiv.style.left = labelNode.offsetWidth + "px";
contentDiv.style.width = (((this._children[i].domContainer.offsetWidth - labelNode.offsetWidth) /
this._children[i].domContainer.offsetWidth) * 100) + "%";
if (recursively)
{
this._children[i]._updateDisplay(recursively);
}
}
}
});
dojo.declare("alfresco.xforms.SwitchGroup",
alfresco.xforms.VGroup,
function(xform, xformsNode)
{
if (this.getInitialValue())
{
var initialValueTrigger = this._getCaseToggleTriggerByTypeValue(this.getInitialValue());
this._selectedCaseId = initialValueTrigger.getActions()["toggle"].properties["case"];
}
},
{
/////////////////////////////////////////////////////////////////
// methods & properties
/////////////////////////////////////////////////////////////////
_getCaseToggleTriggers: function()
{
var bw = this.xform.getBinding(this.xformsNode).widgets;
var result = [];
for (var i in bw)
{
if (! (bw[i] instanceof alfresco.xforms.Trigger))
{
continue;
}
var action = bw[i].getActions()["toggle"];
if (action)
{
result.push(bw[i]);
}
}
return result;
},
_getCaseToggleTriggerByCaseId: function(caseId)
{
var bw = this.xform.getBinding(this.xformsNode).widgets;
for (var i in bw)
{
if (! (bw[i] instanceof alfresco.xforms.Trigger))
{
continue;
}
var action = bw[i].getActions()["toggle"];
if (!action)
{
continue;
}
if (action.properties["case"] == caseId)
{
return bw[i];
}
}
throw new Error("unable to find trigger " + type +
", properties " + properties +
" for " + this.id);
},
_getCaseToggleTriggerByTypeValue: function(typeValue)
{
var bw = this.xform.getBinding(this.xformsNode).widgets;
for (var i in bw)
{
if (! (bw[i] instanceof alfresco.xforms.Trigger))
{
continue;
}
var action = bw[i].getActions()["setvalue"];
if (!action)
{
continue;
}
if (action.properties["value"] == typeValue)
{
return bw[i];
}
}
throw new Error("unable to find toggle trigger for type value " + typeValue +
" for " + this.id);
},
/////////////////////////////////////////////////////////////////
// overridden methods & properties
/////////////////////////////////////////////////////////////////
/** */
_insertChildAt: function(child, position)
{
var childDomContainer =
alfresco.xforms.SwitchGroup.superclass._insertChildAt.call(this, child, position);
if (child.id == this._selectedCaseId)
{
this._getCaseToggleTriggerByCaseId(this._selectedCaseId).fire();
}
else
{
childDomContainer.style.display = "none";
}
return childDomContainer;
},
render: function(attach_point)
{
alfresco.xforms.SwitchGroup.superclass.render.call(this, attach_point);
var cases = this._getCaseToggleTriggers();
var caseToggleSelect = document.createElement("select");
caseToggleSelect.setAttribute("id", this.id + "-toggle-select");
caseToggleSelect.style.position = "absolute";
caseToggleSelect.style.right = "0px";
caseToggleSelect.style.top = "0px";
this._groupHeaderNode.appendChild(caseToggleSelect);
for (var i = 0; i < cases.length; i++)
{
var option = document.createElement("option");
caseToggleSelect.appendChild(option);
var caseId = cases[i].getActions()["toggle"].properties["case"];
option.setAttribute("value", caseId);
option.appendChild(document.createTextNode(cases[i].getLabel()));
if (cases[i].getActions()["toggle"].properties["case"] == this._selectedCaseId)
{
option.selected = true;
}
}
dojo.event.connect(caseToggleSelect, "onchange", this, this._caseToggleSelect_changeHandler);
},
/////////////////////////////////////////////////////////////////
// XForms event handlers
/////////////////////////////////////////////////////////////////
/** */
handleSwitchToggled: function(selectedCaseId, deselectedCaseId)
{
dojo.debug(this.id + ".handleSwitchToggled(" + selectedCaseId +
", " + deselectedCaseId + ")");
this.selectedCaseId = selectedCaseId;
for (var i = 0; i < this._children.length; i++)
{
if (this._children[i].id == selectedCaseId)
{
this._children[i].domContainer.style.display = "block";
}
else if (this._children[i].id == deselectedCaseId)
{
this._children[i].domContainer.style.display = "none";
}
}
this._updateDisplay(true);
},
/////////////////////////////////////////////////////////////////
// DOM event handlers
/////////////////////////////////////////////////////////////////
_caseToggleSelect_changeHandler: function(event)
{
dojo.event.browser.stopEvent(event);
var t = this._getCaseToggleTriggerByCaseId(event.target.value);
t.fire();
}
});
/** */
dojo.declare("alfresco.xforms.CaseGroup",
alfresco.xforms.VGroup,
function(xform, xformsNode)
{
},
{
});
/**
* Handles xforms widget xf:group for the root group. Does some special rendering
* to present a title rather than a group header.
*/
dojo.declare("alfresco.xforms.ViewRoot",
alfresco.xforms.VGroup,
function(xform, xformsNode)
{
this.focusedRepeat = null;
},
{
/////////////////////////////////////////////////////////////////
// overridden methods & properties
/////////////////////////////////////////////////////////////////
render: function(attach_point)
{
this.domNode.widget = this;
this.domNode.style.position = "relative";
this.domNode.style.width = "100%";
dojo.html.setClass(this.domNode, "xformsViewRoot");
this._groupHeaderNode = document.createElement("div");
this._groupHeaderNode.id = this.id + "-groupHeaderNode";
dojo.html.setClass(this._groupHeaderNode, "xformsViewRootHeader");
this.domNode.appendChild(this._groupHeaderNode);
var icon = document.createElement("img");
this._groupHeaderNode.appendChild(icon);
icon.setAttribute("src", alfresco.constants.WEBAPP_CONTEXT + "/images/icons/file_large.gif");
icon.align = "absmiddle";
icon.style.marginLeft = "5px";
icon.style.marginRight = "5px";
this._groupHeaderNode.appendChild(document.createTextNode(this.getLabel()));
attach_point.appendChild(this.domNode);
this.domNode.childContainerNode = document.createElement("div");
this.domNode.childContainerNode.setAttribute("id", this.id + "-childContainerNode");
this.domNode.childContainerNode.style.position = "relative";
this.domNode.childContainerNode.style.width = "100%";
return this.domNode;
},
/** */
getLabel: function()
{
var result = alfresco.xforms.ViewRoot.superclass.getLabel.call(this);
result += " " + alfresco.xforms.constants.FORM_INSTANCE_DATA_NAME;
return result;
}
});
/** A struct for providing repeat index data. */
alfresco.xforms.RepeatIndexData = function(repeat, index)
{
this.repeat = repeat;
this.index = index;
this.toString = function()
{
return "{" + this.repeat.id + " = " + this.index + "}";
};
}
/**
* Handles xforms widget xf:repeat.
*/
dojo.declare("alfresco.xforms.Repeat",
alfresco.xforms.VGroup,
function(xform, xformsNode)
{
this.repeatControls = [];
this._selectedIndex = -1;
this._locked = false;
},
{
/////////////////////////////////////////////////////////////////
// methods & properties
/////////////////////////////////////////////////////////////////
/**
* Indicates whether or not this repeat can insert more children based
* on the alf:maximum restriction.
*/
isInsertRepeatItemEnabled: function()
{
var maximum = this.xform.getBinding(this.xformsNode).maximum;
maximum = isNaN(maximum) ? Number.MAX_VALUE : maximum;
return this._children.length < maximum;
},
/**
* Indicates whether or not this repeat can removed children based
* on the alf:minimum restriction.
*/
isRemoveRepeatItemEnabled: function()
{
var minimum = this.xform.getBinding(this.xformsNode).minimum;
minimum = isNaN(minimum) ? this.isRequired() ? 1 : 0 : minimum;
return this._children.length > minimum;
},
/**
* Returns the currently selected index or -1 if this repeat has no repeat items.
*/
getSelectedIndex: function()
{
this._selectedIndex = Math.min(this._children.length, this._selectedIndex);
if (this._children.length == 0)
{
this._selectedIndex = -1;
}
return this._selectedIndex;
},
/**
* Helper function to locate the appropriate repeat item trigger for this repeat.
* This is done by locating all related widgets via binding, and selecting the
* Trigger who's action type is the type provided and where the properties
* provided are the same for that action. This approach is used rather than simply
* looking up the trigger by id since the id isn't known for nested repeats as
* chiba modifies them.
*/
_getRepeatItemTrigger: function(type, properties)
{
var bw = this.xform.getBinding(this.xformsNode).widgets;
for (var i in bw)
{
if (! (bw[i] instanceof alfresco.xforms.Trigger))
{
continue;
}
var action = bw[i].getActions()[type];
if (!action)
{
continue;
}
var propertiesEqual = true;
for (var p in properties)
{
if (!(p in action.properties) ||
action.properties[p] != properties[p])
{
propertiesEqual = false;
break;
}
}
if (propertiesEqual)
{
return bw[i];
}
}
throw new Error("unable to find trigger " + type +
", properties " + properties +
" for " + this.id);
},
/**
* Sets the currently selected child by calliing XFormsBean.setRepeatIndeces.
* If the child provided is null, the index is set to 0.
*/
setFocusedChild: function(child)
{
var oldFocusedRepeat = this.getViewRoot().focusedRepeat;
this.getViewRoot().focusedRepeat = this;
if (oldFocusedRepeat != null && oldFocusedRepeat != this)
{
if (!oldFocusedRepeat.isAncestorOf(this))
{
oldFocusedRepeat._selectedIndex = -1;
}
oldFocusedRepeat._updateDisplay(false);
}
var repeatIndices = this.getRepeatIndices();
if (!child)
{
repeatIndices.push(new alfresco.xforms.RepeatIndexData(this, 0));
this.xform.setRepeatIndeces(repeatIndices);
}
else
{
var index = this.getChildIndex(child);
if (index < 0)
{
throw new Error("unable to find child " + child.id + " in " + this.id);
}
repeatIndices.push(new alfresco.xforms.RepeatIndexData(this, index + 1));
// xforms repeat indexes are 1-based
this.xform.setRepeatIndeces(repeatIndices);
}
},
/**
* Calls swapRepeatItems on the XFormsBean which will produce the event log
* to insert and remove the appropriate repeat items.
*/
_swapChildren: function(fromIndex, toIndex)
{
dojo.debug(this.id + ".swapChildren(" + fromIndex + ", " + toIndex + ")");
var fromChild = this.getChildAt(fromIndex);
var toChild = this.getChildAt(toIndex);
this.xform.swapRepeatItems(fromChild, toChild);
var anim = dojo.lfx.html.fadeOut(fromChild.domContainer, 500);
anim.onEnd = function()
{
fromChild.domContainer.style.display = "none";
};
anim.play();
},
/**
* Updates the repeat controls by changing the opacity on the image based on
* whether or not the action is enabled.
*/
_updateRepeatControls: function()
{
var insertEnabled = this.isInsertRepeatItemEnabled();
var removeEnabled = this.isRemoveRepeatItemEnabled();
for (var i = 0; i < this.repeatControls.length; i++)
{
dojo.html.setOpacity(this.repeatControls[i].moveRepeatItemUpImage,
i == 0 ? .3 : 1);
dojo.html.setOpacity(this.repeatControls[i].moveRepeatItemDownImage,
i == this.repeatControls.length - 1 ? .3 : 1);
dojo.html.setOpacity(this.repeatControls[i].insertRepeatItemImage,
insertEnabled ? 1 : .3);
dojo.html.setOpacity(this.repeatControls[i].removeRepeatItemImage,
removeEnabled ? 1 : .3);
}
},
/////////////////////////////////////////////////////////////////
// overridden methods & properties
/////////////////////////////////////////////////////////////////
/** When debugging, insert the id into the label. */
getLabel: function()
{
var label = this.parent.getLabel();
if (djConfig.isDebug)
{
label += " [" + this.id + "]";
}
return label;
},
/** Overrides _insertChildAt in Group to provide repeater controls. */
_insertChildAt: function(child, position)
{
this.repeatControls.splice(position, 0, document.createElement("div"));
var images =
[
{ name: "insertRepeatItemImage", src: "plus", action: this._insertRepeatItemAfter_handler },
{ name: "moveRepeatItemUpImage", src: "arrow_up", action: this._moveRepeatItemUp_handler },
{ name: "moveRepeatItemDownImage", src: "arrow_down", action: this._moveRepeatItemDown_handler },
{ name: "removeRepeatItemImage", src: "minus", action: this._removeRepeatItem_handler }
];
var repeatControlsWidth = 0;
for (var i = 0; i < images.length; i++)
{
var img = document.createElement("img");
this.repeatControls[position][images[i].name] = img;
img.setAttribute("src", (alfresco.constants.WEBAPP_CONTEXT + "/images/icons/" +
images[i].src + ".gif"));
img.style.width = "16px";
img.style.height = "16px";
img.style.margin = "2px 5px 2px " + (i == 0 ? 5 : 0) + "px";
img.repeat = this;
repeatControlsWidth += (parseInt(img.style.width) +
dojo.html.getMargin(img).width);
this.repeatControls[position].appendChild(img);
dojo.event.connect(img, "onclick", this, images[i].action);
}
var result = alfresco.xforms.Repeat.superclass._insertChildAt.call(this, child, position);
child.repeat = this;
dojo.event.connect(result, "onclick", function(event)
{
child.repeat.setFocusedChild(child);
event.stopPropagation();
});
dojo.html.addClass(result, "xformsRepeatItem");
if (result.nextSibling)
{
result.parentNode.insertBefore(this.repeatControls[position],
result.nextSibling);
}
else
{
result.parentNode.appendChild(this.repeatControls[position]);
}
dojo.html.setClass(this.repeatControls[position], "xformsRepeatControls");
this.repeatControls[position].style.width = repeatControlsWidth + "px";
this.repeatControls[position].style.backgroundColor =
dojo.html.getStyle(result, "background-color");
result.style.paddingBottom = (.5 * this.repeatControls[position].offsetHeight) + "px";
this.repeatControls[position].style.top = -(.5 * (this.repeatControls[position].offsetHeight ) +
dojo.html.getPixelValue(result, "margin-bottom") +
dojo.html.getBorderExtent(result, "bottom")) + "px";
this.repeatControls[position].style.marginRight =
(.5 * result.offsetWidth -
.5 * this.repeatControls[position].offsetWidth) + "px";
this.repeatControls[position].style.marginLeft =
(.5 * result.offsetWidth -
.5 * this.repeatControls[position].offsetWidth) + "px";
return result;
},
/**
* Overrides _removeChildAt in Group to remove the repeat controls associated with
* the repeat item.
*/
_removeChildAt: function(position)
{
this.repeatControls[position].style.display = "none";
dojo.dom.removeChildren(this.repeatControls[position]);
dojo.dom.removeNode(this.repeatControls[position]);
this.repeatControls.splice(position, 1);
return alfresco.xforms.Repeat.superclass._removeChildAt.call(this, position);
},
/** Disables insert before. */
_childAdded: function(child)
{
dojo.html.setOpacity(this.headerInsertRepeatItemImage, .3);
this._updateRepeatControls();
},
/** Reenables insert before if there are no children left. */
_childRemoved: function(child)
{
if (this._children.length == 0)
{
dojo.html.setOpacity(this.headerInsertRepeatItemImage, 1);
}
this._updateRepeatControls();
},
render: function(attach_point)
{
this.domNode = alfresco.xforms.Repeat.superclass.render.call(this, attach_point);
dojo.html.addClass(this.domNode, "xformsRepeat");
// clear the border bottom for the group header since we'll be getting it
// from the repeat item border
this._groupHeaderNode.style.borderBottomWidth = "0px";
this._groupHeaderNode.repeat = this;
dojo.event.connect(this._groupHeaderNode, "onclick", function(event)
{
if (event.target == event.currentTarget)
{
event.currentTarget.repeat.setFocusedChild(null);
}
});
this.headerInsertRepeatItemImage = document.createElement("img");
this.headerInsertRepeatItemImage.repeat = this;
this._groupHeaderNode.appendChild(this.headerInsertRepeatItemImage);
this.headerInsertRepeatItemImage.setAttribute("src",
alfresco.constants.WEBAPP_CONTEXT +
"/images/icons/plus.gif");
this.headerInsertRepeatItemImage.style.width = "16px";
this.headerInsertRepeatItemImage.style.height = "16px";
this.headerInsertRepeatItemImage.align = "absmiddle";
this.headerInsertRepeatItemImage.style.marginLeft = "5px";
dojo.event.connect(this.headerInsertRepeatItemImage,
"onclick",
this,
this._headerInsertRepeatItemBefore_handler);
return this.domNode;
},
_updateDisplay: function(recursively)
{
alfresco.xforms.Repeat.superclass._updateDisplay.call(this, recursively);
if (this.getViewRoot().focusedRepeat != null &&
(this.getViewRoot().focusedRepeat == this ||
this.getViewRoot().focusedRepeat.isAncestorOf(this)))
{
if (!dojo.html.hasClass(this._groupHeaderNode, "xformsRepeatFocusedHeader"))
{
dojo.html.addClass(this._groupHeaderNode, "xformsRepeatFocusedHeader");
}
}
else if (dojo.html.hasClass(this._groupHeaderNode, "xformsRepeatFocusedHeader"))
{
dojo.html.removeClass(this._groupHeaderNode, "xformsRepeatFocusedHeader");
}
for (var i = 0; i < this._children.length; i++)
{
var domContainerClasses = dojo.html.getClasses(this._children[i].domContainer);
if (i + 1 == this.getSelectedIndex() && this.getViewRoot().focusedRepeat == this)
{
if (domContainerClasses.indexOf("xformsRowOdd") >= 0)
{
dojo.html.removeClass(this._children[i].domContainer, "xformsRowOdd");
}
if (domContainerClasses.indexOf("xformsRowEven") >= 0)
{
dojo.html.removeClass(this._children[i].domContainer, "xformsRowEven");
}
if (domContainerClasses.indexOf("xformsRepeatItemSelected") < 0)
{
dojo.html.addClass(this._children[i].domContainer, "xformsRepeatItemSelected");
}
}
else
{
if (domContainerClasses.indexOf("xformsRepeatItemSelected") >= 0)
{
dojo.html.removeClass(this._children[i].domContainer, "xformsRepeatItemSelected");
}
if (domContainerClasses.indexOf("xformsRow" + (i % 2 ? "Odd" : "Even")) >= 0)
{
dojo.html.removeClass(this._children[i].domContainer, "xformsRow" + (i % 2 ? "Odd" : "Even"));
}
dojo.html.addClass(this._children[i].domContainer,
"xformsRow" + (i % 2 ? "Even" : "Odd"));
}
this.repeatControls[i].style.backgroundColor =
dojo.html.getStyle(this._children[i].domContainer, "background-color");
}
},
/////////////////////////////////////////////////////////////////
// DOM event handlers
/////////////////////////////////////////////////////////////////
/**
* Event handler for insert after. If insert is enabled, causes a setRepeatIndeces
* and an insert.
*/
_insertRepeatItemAfter_handler: function(event)
{
dojo.event.browser.stopEvent(event);
var repeat = event.target.repeat;
if (!repeat._locked && repeat.isInsertRepeatItemEnabled())
{
var index = repeat.repeatControls.indexOf(event.target.parentNode);
var repeatItem = repeat.getChildAt(index);
this.setFocusedChild(repeatItem);
var trigger = this._getRepeatItemTrigger("insert", { position: "after" });
trigger.fire();
repeat._locked = true;
}
},
/**
* Event handler for insert before. If insert is enabled, causes a setRepeatIndeces
* and an insert.
*/
_headerInsertRepeatItemBefore_handler: function(event)
{
if (this._children.length == 0)
{
dojo.event.browser.stopEvent(event);
var repeat = event.target.repeat;
if (!repeat._locked && repeat.isInsertRepeatItemEnabled())
{
this.setFocusedChild(null);
var trigger = this._getRepeatItemTrigger("insert", { position: "before" });
trigger.fire();
repeat._locked = true;
}
}
},
/**
* Event handler for remove. If remove is enabled, causes a setRepeatIndeces
* and an delete.
*/
_removeRepeatItem_handler: function(event)
{
dojo.event.browser.stopEvent(event);
var repeat = event.target.repeat;
if (!repeat._locked && repeat.isRemoveRepeatItemEnabled())
{
var index = repeat.repeatControls.indexOf(event.target.parentNode);
var repeatItem = repeat.getChildAt(index);
this.setFocusedChild(repeatItem);
var trigger = this._getRepeatItemTrigger("delete", {});
trigger.fire();
repeat._locked = true;
}
},
/**
* Event handler for move up. Calls swap children with the child before
* if the current select child is not the first child.
*/
_moveRepeatItemUp_handler: function(event)
{
dojo.event.browser.stopEvent(event);
var repeat = event.target.repeat;
var index = repeat.repeatControls.indexOf(event.target.parentNode);
if (!repeat._locked && index != 0 && repeat._children.length != 1)
{
var repeatItem = repeat.getChildAt(index);
this.setFocusedChild(repeatItem);
repeat._swapChildren(index, index - 1);
repeat._locked = true;
}
},
/**
* Event handler for move down. Calls swap children with the child after
* if the current select child is not the last child.
*/
_moveRepeatItemDown_handler: function(event)
{
dojo.event.browser.stopEvent(event);
var repeat = event.target.repeat;
var index = repeat.repeatControls.indexOf(event.target.parentNode);
if (!repeat._locked && index != repeat._children.length - 1 && repeat._children.length != 1)
{
var repeatItem = repeat.getChildAt(index);
this.setFocusedChild(repeatItem);
repeat._swapChildren(index, index + 1);
repeat._locked = true;
}
},
/////////////////////////////////////////////////////////////////
// XForms event handlers
/////////////////////////////////////////////////////////////////
/** Sets the selected index. */
handleIndexChanged: function(index)
{
dojo.debug(this.id + ".handleIndexChanged(" + index + ")");
this._selectedIndex = index;
this._updateDisplay(false);
},
/** Returns a clone of the specified prototype id. */
handlePrototypeCloned: function(prototypeId)
{
dojo.debug(this.id + ".handlePrototypeCloned("+ prototypeId +")");
var chibaData = _getElementsByTagNameNS(this.xformsNode,
alfresco.xforms.constants.CHIBA_NS,
alfresco.xforms.constants.CHIBA_PREFIX,
"data");
chibaData = chibaData[chibaData.length - 1];
if (djConfig.isDebug)
{
dojo.debug(alfresco.xforms.constants.CHIBA_PREFIX +
":data == " + dojo.dom.innerXML(chibaData));
}
var prototypeToClone = dojo.dom.firstElement(chibaData);
if (prototypeToClone.getAttribute("id") != prototypeId)
{
throw new Error("unable to locate " + prototypeId +
" in " + this.id);
}
return prototypeToClone.cloneNode(true);
},
/** Inserts the clonedPrototype at the specified position. */
handleItemInserted: function(clonedPrototype, position)
{
dojo.debug(this.id + ".handleItemInserted(" + clonedPrototype.nodeName +
", " + position + ")");
var w = this.xform.createWidget(clonedPrototype);
this._insertChildAt(w, position);
this.xform.loadWidgets(w.xformsNode, w);
this._locked = false;
},
/** Deletes the item at the specified position. */
handleItemDeleted: function(position)
{
dojo.debug(this.id + ".handleItemDeleted(" + position + ")");
this._removeChildAt(position);
this._locked = false;
}
});
////////////////////////////////////////////////////////////////////////////////
// trigger widgets
////////////////////////////////////////////////////////////////////////////////
/**
* Handles xforms widget xf:trigger.
*/
dojo.declare("alfresco.xforms.Trigger",
alfresco.xforms.Widget,
function(xform, xformsNode)
{
},
{
/////////////////////////////////////////////////////////////////
// methods & properties
/////////////////////////////////////////////////////////////////
/** TODO: DOCUMENT */
getActions: function()
{
if (typeof this._actions == "undefined")
{
var actionNode = _getElementsByTagNameNS(this.xformsNode,
alfresco.xforms.constants.XFORMS_NS,
alfresco.xforms.constants.XFORMS_PREFIX,
"action")[0];
this._actions = {};
for (var i = 0; i < actionNode.childNodes.length; i++)
{
if (actionNode.childNodes[i].nodeType != dojo.dom.ELEMENT_NODE)
{
continue;
}
var a = new alfresco.xforms.XFormsAction(this.xform, actionNode.childNodes[i]);
this._actions[a.getType()] = a;
}
}
return this._actions;
},
/** fires the xforms action associated with the trigger */
fire: function()
{
this.xform.fireAction(this.id);
},
/////////////////////////////////////////////////////////////////
// overridden methods
/////////////////////////////////////////////////////////////////
isValidForSubmit: function()
{
return true;
},
isVisible: function()
{
return false;
},
render: function(attach_point)
{
attach_point.appendChild(this.domNode);
this.widget = document.createElement("input");
this.widget.setAttribute("type", "submit");
this.widget.setAttribute("id", this.id + "-widget");
this.widget.setAttribute("value", this.getLabel() + " " + this.id);
dojo.event.connect(this.widget, "onclick", this, this._clickHandler);
this.domContainer.style.display = "none";
},
/////////////////////////////////////////////////////////////////
// DOM event handlers
/////////////////////////////////////////////////////////////////
_clickHandler: function(event)
{
this.fire();
}
});
/**
* Handles xforms widget xf:submit.
*/
dojo.declare("alfresco.xforms.Submit",
alfresco.xforms.Trigger,
function(xform, xformsNode)
{
var submit_buttons = (this.id == "submit"
? _xforms_getSubmitButtons()
: (this.id == "save-draft"
? _xforms_getSaveDraftButtons()
: null));
if (submit_buttons == null)
{
throw new Error("unknown submit button " + this.id);
}
for (var i = 0; i < submit_buttons.length; i++)
{
dojo.debug("adding submit handler for " + submit_buttons[i].getAttribute('id'));
submit_buttons[i].widget = this;
dojo.event.browser.addListener(submit_buttons[i],
"onclick",
this._submitButton_clickHandler,
false);
}
},
{
/////////////////////////////////////////////////////////////////
// DOM event handlers
/////////////////////////////////////////////////////////////////
_clickHandler: function(event)
{
this.done = false;
_hide_errors();
this.fire();
},
/** */
_submitButton_clickHandler: function(event)
{
if (!event.target.widget)
{
return true;
}
var xform = event.target.widget.xform;
if (xform.submitWidget && xform.submitWidget.done)
{
dojo.debug("done - doing base click on " + xform.submitWidget.currentButton.id);
xform.submitWidget.currentButton = null;
xform.submitWidget = null;
return true;
}
else
{
dojo.debug("triggering submit from handler " + event.target.id);
dojo.event.browser.stopEvent(event);
_hide_errors();
xform.submitWidget = event.target.widget;
xform.submitWidget.currentButton = event.target;
xform.submitWidget.fire();
return false;
}
}
});
/**
* A struct describing an xforms action block.
*/
dojo.declare("alfresco.xforms.XFormsAction",
null,
function(xform, xformsNode)
{
this.xform = xform;
this.xformsNode = xformsNode;
/** All properties of the action as map of key value pairs */
this.properties = [];
for (var i = 0; i < this.xformsNode.attributes.length; i++)
{
var attr = this.xformsNode.attributes[i];
if (attr.nodeName.match(new RegExp("^" + alfresco.xforms.constants.XFORMS_PREFIX + ":")))
{
this.properties[attr.nodeName.substring((alfresco.xforms.constants.XFORMS_PREFIX + ":").length)] =
attr.nodeValue;
}
}
if (this.getType() == "setvalue" && !this.properties["value"])
{
this.properties["value"] = this.xformsNode.firstChild.nodeValue;
}
},
{
/** Returns the action type. */
getType: function()
{
return this.xformsNode.nodeName.substring((alfresco.xforms.constants.XFORMS_PREFIX + ":").length);
}
});
////////////////////////////////////////////////////////////////////////////////
// xforms data model
////////////////////////////////////////////////////////////////////////////////
/**
* An xforms event. A log of events is returned by any xforms action and
* is used to update the UI appropriately.
*/
dojo.declare("alfresco.xforms.XFormsEvent",
null,
function(node)
{
this.type = node.nodeName;
this.targetId = node.getAttribute("targetId");
this.targetName = node.getAttribute("targetName");
this.properties = {};
for (var i = 0; i < node.childNodes.length; i++)
{
if (node.childNodes[i].nodeType == dojo.dom.ELEMENT_NODE)
{
this.properties[node.childNodes[i].getAttribute("name")] =
node.childNodes[i].getAttribute("value");
}
}
},
{
/** Returns the widget managing the specified target id. */
getTarget: function()
{
var targetDomNode = document.getElementById(this.targetId + "-content");
if (!targetDomNode)
{
throw new Error("unable to find node " + this.targetId + "-content");
}
return targetDomNode.widget;
}
});
/**
* A parsed xf:bind.
*/
dojo.declare("alfresco.xforms.Binding",
null,
function(xformsNode, parent)
{
this.xformsNode = xformsNode;
this.id = this.xformsNode.getAttribute("id");
this.nodeset = this.xformsNode.getAttribute(alfresco.xforms.constants.XFORMS_PREFIX + ":nodeset");
this._readonly =
(_hasAttribute(this.xformsNode, alfresco.xforms.constants.XFORMS_PREFIX + ":readonly")
? this.xformsNode.getAttribute(alfresco.xforms.constants.XFORMS_PREFIX + ":readonly") == "true()"
: null);
this._required =
(_hasAttribute(this.xformsNode, alfresco.xforms.constants.XFORMS_PREFIX + ":required")
? this.xformsNode.getAttribute(alfresco.xforms.constants.XFORMS_PREFIX + ":required") == "true()"
: null);
this._type =
(_hasAttribute(this.xformsNode, alfresco.xforms.constants.XFORMS_PREFIX + ":type")
? this.xformsNode.getAttribute(alfresco.xforms.constants.XFORMS_PREFIX + ":type")
: null);
this.constraint =
(_hasAttribute(this.xformsNode, alfresco.xforms.constants.XFORMS_PREFIX + ":constraint")
? this.xformsNode.getAttribute(alfresco.xforms.constants.XFORMS_PREFIX + ":constraint")
: null);
this.maximum = this.xformsNode.getAttribute(alfresco.xforms.constants.XFORMS_PREFIX + ":maxOccurs");
this.maximum = this.maximum == "unbounded" ? Number.MAX_VALUE : parseInt(this.maximum);
this.minimum = parseInt(this.xformsNode.getAttribute(alfresco.xforms.constants.XFORMS_PREFIX + ":minOccurs"));
this.parent = parent;
this.widgets = {};
},
{
/** Returns the expected schema type for this binding. */
getType: function()
{
return (this._type != null
? this._type
: (this.parent != null ? this.parent.getType() : null));
},
/** Returns true if a node bound by this binding has a readonly value */
isReadonly: function()
{
return (this._readonly != null ? this._readonly :
(this.parent != null ? this.parent.isReadonly() : false));
},
/** Returns true if a node bound by this binding has a required value */
isRequired: function()
{
return (this._required != null ? this._required :
(this.parent != null ? this.parent.isRequired() : false));
},
toString: function()
{
return ("{id: " + this.id +
",type: " + this.getType() +
",required: " + this.isRequired() +
",readonly: " + this.isReadonly() +
",nodeset: " + this.nodeset + "}");
}
});
/**
* Manages the xforms document.
*/
dojo.declare("alfresco.xforms.XForm",
null,
/** Makes a request to the XFormsBean to load the xforms document. */
function()
{
var req = alfresco.AjaxHelper.createRequest(this,
"getXForm",
{},
function(type, data, evt, kwArgs)
{
this.target._loadHandler(data);
});
alfresco.AjaxHelper.sendRequest(req);
},
{
/////////////////////////////////////////////////////////////////
// Initialization
/////////////////////////////////////////////////////////////////
/** Parses the xforms document and produces the widget tree. */
_loadHandler: function(xformDocument)
{
this.xformDocument = xformDocument;
this.xformsNode = xformDocument.documentElement;
this._bindings = this._loadBindings(this.getModel());
var bindings = this.getBindings();
var alfUI = document.getElementById(alfresco.xforms.constants.XFORMS_UI_DIV_ID);
alfUI.style.width = "100%";
var rootGroup = _getElementsByTagNameNS(this.getBody(),
alfresco.xforms.constants.XFORMS_NS,
alfresco.xforms.constants.XFORMS_PREFIX,
"group")[0];
this.rootWidget = new alfresco.xforms.ViewRoot(this, rootGroup);
this.rootWidget.render(alfUI);
this.loadWidgets(rootGroup, this.rootWidget);
},
/** Creates the widget for the provided xforms node. */
createWidget: function(xformsNode)
{
var appearance = (xformsNode.getAttribute("appearance") ||
xformsNode.getAttribute(alfresco.xforms.constants.XFORMS_PREFIX + ":appearance"));
appearance = appearance == null || appearance.length == 0 ? null : appearance;
var xformsType = xformsNode.nodeName.toLowerCase();
var binding = this.getBinding(xformsNode);
var schemaType = binding ? binding.getType() : "*";
dojo.debug("creating widget for xforms type " + xformsType +
" schema type " + schemaType +
" with appearance " + appearance);
var x = alfresco.xforms.widgetConfig[xformsType];
if (!x)
{
throw new Error("unknown type " + xformsNode.nodeName);
}
x = schemaType in x ? x[schemaType] : x["*"];
x = appearance in x ? x[appearance] : x["*"];
// dojo.debug(xformsType + ":" + schemaType + ":" + appearance + " =>" + x);
if (x === undefined)
{
throw new Error("unable to find widget for xforms type " + xformsType +
" schemaType " + schemaType +
" appearance " + appearance);
}
if (x == null)
{
return null;
}
var result = new x.className(this, xformsNode, x.params);
if (result instanceof alfresco.xforms.Widget)
{
return result;
}
else
{
throw new Error("constructor for widget " + x +
" for xforms type " + xformsType +
" schemaType " + schemaType +
" appearance " + appearance +
" is not an alfresco.xforms.Widget");
}
},
/** Loads all widgets for the provided xforms node's children. */
loadWidgets: function(xformsNode, parentWidget)
{
for (var i = 0; i < xformsNode.childNodes.length; i++)
{
if (xformsNode.childNodes[i].nodeType != dojo.dom.ELEMENT_NODE)
{
continue;
}
dojo.debug("loading " + xformsNode.childNodes[i].nodeName +
" into " + parentWidget.id);
if (xformsNode.childNodes[i].getAttribute(alfresco.xforms.constants.ALFRESCO_PREFIX +
":prototype") == "true")
{
dojo.debug(xformsNode.childNodes[i].getAttribute("id") +
" is a prototype, ignoring");
continue;
}
var w = this.createWidget(xformsNode.childNodes[i]);
if (w != null)
{
dojo.debug("created " + w.id + " for " + xformsNode.childNodes[i].nodeName);
parentWidget.addChild(w);
if (w instanceof alfresco.xforms.AbstractGroup)
{
this.loadWidgets(xformsNode.childNodes[i], w);
}
}
}
},
/** Loads all bindings from the xforms document. */
_loadBindings: function(bind, parent, result)
{
result = result || [];
for (var i = 0; i < bind.childNodes.length; i++)
{
if (bind.childNodes[i].nodeName.toLowerCase() ==
alfresco.xforms.constants.XFORMS_PREFIX + ":bind")
{
var b = new alfresco.xforms.Binding(bind.childNodes[i], parent);
result[b.id] = b;
dojo.debug("loaded binding " + b);
this._loadBindings(bind.childNodes[i], result[b.id], result);
}
}
return result;
},
/////////////////////////////////////////////////////////////////
// XForms model properties & methods
/////////////////////////////////////////////////////////////////
/** Returns the model section of the xforms document. */
getModel: function()
{
return _getElementsByTagNameNS(this.xformsNode,
alfresco.xforms.constants.XFORMS_NS,
alfresco.xforms.constants.XFORMS_PREFIX,
"model")[0];
},
/** Returns the instance section of the xforms document. */
getInstance: function()
{
var model = this.getModel();
return _getElementsByTagNameNS(model,
alfresco.xforms.constants.XFORMS_NS,
alfresco.xforms.constants.XFORMS_PREFIX,
"instance")[0];
},
/** Returns the body section of the xforms document. */
getBody: function()
{
var b = _getElementsByTagNameNS(this.xformsNode,
alfresco.xforms.constants.XHTML_NS,
alfresco.xforms.constants.XHTML_PREFIX,
"body");
return b[b.length - 1];
},
/** Returns the binding corresponding to the provided xforms node. */
getBinding: function(xformsNode)
{
return this._bindings[xformsNode.getAttribute(alfresco.xforms.constants.XFORMS_PREFIX + ":bind")];
},
/** Returns all parsed bindings. */
getBindings: function()
{
return this._bindings;
},
/////////////////////////////////////////////////////////////////
// XFormsBean interaction
/////////////////////////////////////////////////////////////////
/** swaps the specified repeat items by calling XFormsBean.swapRepeatItems. */
swapRepeatItems: function(fromChild, toChild)
{
var params =
{
fromItemId: fromChild.xformsNode.getAttribute("id"),
toItemId: toChild.xformsNode.getAttribute("id"),
instanceId: this.getInstance().getAttribute("id")
};
var req = alfresco.AjaxHelper.createRequest(this,
"swapRepeatItems",
params,
function(type, data, event)
{
this.target._handleEventLog(data.documentElement);
});
alfresco.AjaxHelper.sendRequest(req);
},
/** sets the repeat indexes by calling XFormsBean.setRepeatIndeces. */
setRepeatIndeces: function(repeatIndeces)
{
dojo.debug("setting repeat indeces [" + repeatIndeces.join(", ") + "]");
var params = { };
params["repeatIds"] = [];
for (var i = 0; i < repeatIndeces.length; i++)
{
params.repeatIds.push(repeatIndeces[i].repeat.id);
params[repeatIndeces[i].repeat.id] = repeatIndeces[i].index;
}
params.repeatIds = params.repeatIds.join(",");
var req = alfresco.AjaxHelper.createRequest(this,
"setRepeatIndeces",
params,
function(type, data, evt)
{
this.target._handleEventLog(data.documentElement);
});
alfresco.AjaxHelper.sendRequest(req);
},
/** Fires an action specified by the id by calling XFormsBean.fireAction. */
fireAction: function(id)
{
var req = alfresco.AjaxHelper.createRequest(this,
"fireAction",
{ id: id },
function(type, data, evt)
{
dojo.debug("fireAction." + type);
this.target._handleEventLog(data.documentElement);
});
alfresco.AjaxHelper.sendRequest(req);
},
/** Sets the value of the specified control id by calling XFormsBean.setXFormsValue. */
setXFormsValue: function(id, value)
{
value = value == null ? "" : value;
dojo.debug("setting value " + id + " = " + value);
var req = alfresco.AjaxHelper.createRequest(this,
"setXFormsValue",
{ id: id, value: value },
function(type, data, evt)
{
this.target._handleEventLog(data.documentElement);
});
alfresco.AjaxHelper.sendRequest(req);
},
/** Handles the xforms event log resulting from a call to the XFormsBean. */
_handleEventLog: function(events)
{
var prototypeClones = [];
var generatedIds = null;
for (var i = 0; i < events.childNodes.length; i++)
{
if (events.childNodes[i].nodeType != dojo.dom.ELEMENT_NODE)
{
continue;
}
var xfe = new alfresco.xforms.XFormsEvent(events.childNodes[i]);
dojo.debug("parsing " + xfe.type +
"(" + xfe.targetId + ", " + xfe.targetName + ")");
switch (xfe.type)
{
case "chiba-index-changed":
{
var index = Number(xfe.properties["index"]);
try
{
xfe.getTarget().handleIndexChanged(index);
}
catch (e)
{
dojo.debug(e);
}
break;
}
case "chiba-state-changed":
{
dojo.debug("handleStateChanged(" + xfe.targetId + ")");
xfe.getTarget().setModified(true);
if ("valid" in xfe.properties)
{
xfe.getTarget().setValid(xfe.properties["valid"] == "true");
}
if ("required" in xfe.properties)
{
xfe.getTarget().setRequired(xfe.properties["required"] == "true");
}
if ("readonly" in xfe.properties)
{
xfe.getTarget().setReadonly(xfe.properties["readonly"] == "true");
}
if ("enabled" in xfe.properties)
{
xfe.getTarget().setEnabled(xfe.properties["enabled"] == "true");
}
if ("value" in xfe.properties)
{
dojo.debug("setting " + xfe.getTarget().id + " = " + xfe.properties["value"]);
xfe.getTarget().setValue(xfe.properties["value"]);
}
break;
}
case "chiba-prototype-cloned":
{
var prototypeId = xfe.properties["prototypeId"];
var originalId = xfe.properties["originalId"];
dojo.debug("handlePrototypeCloned(" + xfe.targetId +
", " + originalId +
", " + prototypeId + ")");
var clone = null;
var prototypeNode = _findElementById(this.xformsNode, prototypeId);
if (prototypeNode)
{
dojo.debug("cloning prototype " + prototypeNode.getAttribute("id"));
clone = prototypeNode.cloneNode(true);
}
else
{
dojo.debug("cloning prototype " + originalId);
var prototypeNode = _findElementById(this.xformsNode, originalId);
//clone = prototypeNode.cloneNode(true);
clone = prototypeNode.ownerDocument.createElement(alfresco.xforms.constants.XFORMS_PREFIX + ":group");
clone.setAttribute(alfresco.xforms.constants.XFORMS_PREFIX + ":appearance", "repeated");
for (var j = 0; j < prototypeNode.childNodes.length; j++)
{
clone.appendChild(prototypeNode.childNodes[j].cloneNode(true));
}
clone.setAttribute("id", prototypeId);
}
if (clone == null)
{
throw new Error("unable to clone prototype " + prototypeId);
}
dojo.debug("created clone " + clone.getAttribute("id") +
" nodeName " + clone.nodeName +
" parentClone " + (prototypeClones.length != 0
? prototypeClones.peek().getAttribute("id")
: null));
prototypeClones.push(clone);
break;
}
case "chiba-id-generated":
{
var originalId = xfe.properties["originalId"];
dojo.debug("handleIdGenerated(" + xfe.targetId + ", " + originalId + ")");
var node = _findElementById(prototypeClones.peek(), originalId);
if (!node)
{
throw new Error("unable to find " + originalId +
" in clone " + dojo.dom.innerXML(clone));
}
dojo.debug("applying id " + xfe.targetId +
" to " + node.nodeName + "(" + originalId + ")");
node.setAttribute("id", xfe.targetId);
generatedIds = generatedIds || new Object();
generatedIds[xfe.targetId] = originalId;
if (prototypeClones.length != 1)
{
var e = _findElementById(prototypeClones[prototypeClones.length - 2], originalId);
if (e)
{
e.setAttribute(alfresco.xforms.constants.ALFRESCO_PREFIX + ":prototype", "true");
}
}
break;
}
case "chiba-item-inserted":
{
var position = Number(xfe.properties["position"]) - 1;
var originalId = xfe.properties["originalId"];
var clone = prototypeClones.pop();
// walk all nodes of the clone and ensure that they have generated ids.
// those that do not are nested repeats that should not be added
dojo.lang.assert(clone.getAttribute("id") in generatedIds,
"expected clone id " + clone.getAttribute("id") +
" to be a generated id");
function _removeNonGeneratedChildNodes(node, ids)
{
var child = node.firstChild;
while (child)
{
var next = child.nextSibling;
if (child.nodeType == dojo.dom.ELEMENT_NODE)
{
if (child.getAttribute("id") in ids)
{
_removeNonGeneratedChildNodes(child, ids);
}
else
{
node.removeChild(child);
}
}
child = next;
}
};
_removeNonGeneratedChildNodes(clone, generatedIds);
if (prototypeClones.length != 0)
{
dojo.debug("using parentClone " + prototypeClones.peek().getAttribute("id") +
" of " + clone.getAttribute("id"));
var parentRepeat = _findElementById(prototypeClones.peek(), xfe.targetId);
parentRepeat.appendChild(clone);
}
else
{
dojo.debug("no parentClone found, directly insert " + clone.getAttribute("id") +
" on " + xfe.targetId);
xfe.getTarget().handleItemInserted(clone, position);
}
break;
}
case "chiba-item-deleted":
{
var position = Number(xfe.properties["position"]) - 1;
xfe.getTarget().handleItemDeleted(position);
break;
}
case "chiba-replace-all":
{
if (this.submitWidget)
{
this.submitWidget.done = true;
this.submitWidget.currentButton.click();
}
break;
}
case "chiba-switch-toggled":
{
var switchElement = xfe.getTarget();
switchElement.handleSwitchToggled(xfe.properties["selected"],
xfe.properties["deselected"]);
}
case "xforms-valid":
{
xfe.getTarget().setValid(true);
xfe.getTarget().setModified(true);
break;
}
case "xforms-invalid":
{
xfe.getTarget().setValid(false);
xfe.getTarget().setModified(true);
break;
}
case "xforms-required":
{
xfe.getTarget().setRequired(true);
break;
}
case "xforms-optional":
{
xfe.getTarget().setRequired(false);
break;
}
case "xforms-submit-error":
{
this.submitWidget = null;
var invalid = this.rootWidget.getWidgetsInvalidForSubmit();
_show_error(document.createTextNode(alfresco.xforms.constants.resources["validation_provide_values_for_required_fields"]));
var error_list = document.createElement("ul");
for (var j = 0; j < invalid.length; j++)
{
var error_item = document.createElement("li");
error_item.appendChild(document.createTextNode(invalid[j].getAlert()));
error_list.appendChild(error_item);
invalid[j].showAlert();
}
_show_error(error_list);
break;
}
default:
{
dojo.debug("unhandled event " + events.childNodes[i].nodeName);
}
}
}
}
});
////////////////////////////////////////////////////////////////////////////////
// error message display management
////////////////////////////////////////////////////////////////////////////////
/** hides the error message display. */
function _hide_errors()
{
var errorDiv = document.getElementById(alfresco.xforms.constants.XFORMS_ERROR_DIV_ID);
if (errorDiv)
{
dojo.dom.removeChildren(errorDiv);
errorDiv.style.display = "none";
}
}
/** shows the error message display. */
function _show_error(msg)
{
var errorDiv = document.getElementById(alfresco.xforms.constants.XFORMS_ERROR_DIV_ID);
if (!errorDiv)
{
errorDiv = document.createElement("div");
errorDiv.setAttribute("id", alfresco.xforms.constants.XFORMS_ERROR_DIV_ID);
dojo.html.setClass(errorDiv, "infoText statusErrorText xformsError");
var alfUI = document.getElementById(alfresco.xforms.constants.XFORMS_UI_DIV_ID);
dojo.dom.prependChild(errorDiv, alfUI);
}
if (errorDiv.style.display == "block")
{
errorDiv.appendChild(document.createElement("br"));
}
else
{
errorDiv.style.display = "block";
}
errorDiv.appendChild(msg);
}
////////////////////////////////////////////////////////////////////////////////
// DOM utilities
////////////////////////////////////////////////////////////////////////////////
function _findElementById(node, id)
{
// dojo.debug("looking for " + id +
// " in " + (node ? node.nodeName : null) +
// "(" + (node ? node.getAttribute("id") : null) + ")");
if (node.getAttribute("id") == id)
{
return node;
}
for (var i = 0; i < node.childNodes.length; i++)
{
if (node.childNodes[i].nodeType == dojo.dom.ELEMENT_NODE)
{
var n = _findElementById(node.childNodes[i], id);
if (n)
{
return n;
}
}
}
return null;
}
function _hasAttribute(node, name)
{
return (node == null
? false
: (node.hasAttribute
? node.hasAttribute(name)
: node.getAttribute(name) != null));
}
function _getElementsByTagNameNS(parentNode, ns, nsPrefix, tagName)
{
return (parentNode.getElementsByTagNameNS
? parentNode.getElementsByTagNameNS(ns, tagName)
: parentNode.getElementsByTagName(nsPrefix + ":" + tagName));
}
////////////////////////////////////////////////////////////////////////////////
// XPath wrapper
////////////////////////////////////////////////////////////////////////////////
function _evaluateXPath(xpath, contextNode, result_type)
{
var xmlDocument = contextNode.ownerDocument;
if (djConfig.isDebug)
{
dojo.debug("evaluating xpath " + xpath +
" on node " + contextNode.nodeName +
" in document " + xmlDocument);
}
var result = null;
if (xmlDocument.evaluate)
{
var nsResolver = (xmlDocument.createNSResolver
? xmlDocument.createNSResolver(xmlDocument.documentElement)
: null);
result = xmlDocument.evaluate(xpath,
contextNode,
nsResolver,
result_type,
null);
if (result)
{
switch (result_type)
{
case XPathResult.FIRST_ORDERED_NODE_TYPE:
result = result.singleNodeValue;
break;
case XPathResult.BOOLEAN_TYPE:
result = result.booleanValue;
break;
case XPathResult.STRING_TYPE:
result = result.stringValue;
break;
}
}
}
else
{
xmlDocument.setProperty("SelectionLanguage", "XPath");
var namespaces = [];
for (var i = 0; i < xmlDocument.documentElement.attributes.length; i++)
{
var attr = xmlDocument.documentElement.attributes[i];
if (attr.nodeName.match(/^xmlns:/))
{
namespaces.push(attr.nodeName + "=\'" + attr.nodeValue + "\'");
}
}
if (djConfig.isDebug)
{
dojo.debug("using namespaces " + namespaces.join(","));
}
xmlDocument.setProperty("SelectionNamespaces", namespaces.join(' '));
if (result_type == XPathResult.FIRST_ORDERED_NODE_TYPE)
{
result = xmlDocument.selectSingleNode(xpath);
}
else if (result_type == XPathResult.BOOLEAN_TYPE)
{
result = true;
}
}
dojo.debug("resolved xpath " + xpath + " to " + result);
return result;
}
if (!XPathResult)
{
var XPathResult =
{
ANY_TYPE: 0,
NUMBER_TYPE: 1,
STRING_TYPE: 2,
BOOEAN_TYPE: 3,
FIRST_ORDERED_NODE_TYPE: 9
};
}
if (!String.prototype.startsWith)
{
String.prototype.startsWith = function(s)
{
return this.indexOf(s) == 0;
}
}
if (!Array.prototype.indexOf)
{
Array.prototype.indexOf = function(o)
{
for (var i = 0; i < this.length; i++)
{
if (this[i] == o)
{
return i;
}
}
return -1;
}
}
if (!Array.prototype.peek)
{
Array.prototype.peek = function(o)
{
return this[this.length - 1];
}
}
dojo.html.toCamelCase = function(str)
{
return str.replace(/-./, function(str) { return str.charAt(1).toUpperCase(); });
}
////////////////////////////////////////////////////////////////////////////////
// tiny mce integration
////////////////////////////////////////////////////////////////////////////////
tinyMCE.init({
theme: "advanced",
mode: "exact",
width: -1,
auto_resize: false,
force_p_newlines: false,
encoding: "UTF-8",
entity_encoding: "raw",
add_unload_trigger: false,
add_form_submit_trigger: false,
execcommand_callback: "alfresco_TinyMCE_execcommand_callback",
theme_advanced_toolbar_location: "top",
theme_advanced_toolbar_align: "left",
theme_advanced_buttons1: "",
theme_advanced_buttons2: "",
theme_advanced_buttons3: "",
urlconverter_callback: "alfresco_TinyMCE_urlconverter_callback"
});
function alfresco_TinyMCE_urlconverter_callback(href, element, onsave)
{
dojo.debug("request to convert " + href + " onsave = " + onsave);
if (onsave)
{
return (href && href.startsWith(alfresco.constants.AVM_WEBAPP_URL)
? href.substring(alfresco.constants.AVM_WEBAPP_URL.length)
: href);
}
else
{
return (href && href.startsWith("/")
? alfresco.constants.AVM_WEBAPP_URL + href
: href);
}
}
function alfresco_TinyMCE_execcommand_callback(editor_id, elm, command, user_interface, value)
{
if (command == "mceLink")
{
// BEGIN COPIED FROM ADVANCED THEME editor_template_src.js
var inst = tinyMCE.getInstanceById(editor_id);
var doc = inst.getDoc();
var selectedText = (tinyMCE.isMSIE
? doc.selection.createRange().text
: inst.getSel().toString());
if (!tinyMCE.linkElement &&
tinyMCE.selectedElement.nodeName.toLowerCase() != "img" &&
selectedText.length <= 0)
{
return true;
}
var href = "", target = "", title = "", onclick = "", action = "insert", style_class = "";
if (tinyMCE.selectedElement.nodeName.toLowerCase() == "a")
{
tinyMCE.linkElement = tinyMCE.selectedElement;
}
// Is anchor not a link
if (tinyMCE.linkElement != null && tinyMCE.getAttrib(tinyMCE.linkElement, 'href') == "")
{
tinyMCE.linkElement = null;
}
if (tinyMCE.linkElement)
{
href = tinyMCE.getAttrib(tinyMCE.linkElement, 'href');
target = tinyMCE.getAttrib(tinyMCE.linkElement, 'target');
title = tinyMCE.getAttrib(tinyMCE.linkElement, 'title');
onclick = tinyMCE.getAttrib(tinyMCE.linkElement, 'onclick');
style_class = tinyMCE.getAttrib(tinyMCE.linkElement, 'class');
// Try old onclick to if copy/pasted content
if (onclick == "")
{
onclick = tinyMCE.getAttrib(tinyMCE.linkElement, 'onclick');
}
onclick = tinyMCE.cleanupEventStr(onclick);
href = eval(tinyMCE.settings['urlconverter_callback'] + "(href, tinyMCE.linkElement, true);");
// Use mce_href if defined
mceRealHref = tinyMCE.getAttrib(tinyMCE.linkElement, 'mce_href');
if (mceRealHref != "")
{
href = mceRealHref;
if (tinyMCE.getParam('convert_urls'))
{
href = eval(tinyMCE.settings['urlconverter_callback'] + "(href, tinyMCE.linkElement, true);");
}
}
action = "update";
}
var window_props = { file: alfresco.constants.WEBAPP_CONTEXT + "/jsp/wcm/tiny_mce_link_dialog.jsp",
width: 510 + tinyMCE.getLang('lang_insert_link_delta_width', 0),
height: 400 + tinyMCE.getLang('lang_insert_link_delta_height', 0) };
var dialog_props = { href: href,
target: target,
title: title,
onclick: onclick,
action: action,
className: style_class,
inline: "yes" };
tinyMCE.openWindow(window_props, dialog_props);
return true;
}
else if (command == "mceImage")
{
var src = "", alt = "", border = "", hspace = "", vspace = "", width = "", height = "", align = "",
title = "", onmouseover = "", onmouseout = "", action = "insert";
var img = tinyMCE.imgElement;
var inst = tinyMCE.getInstanceById(editor_id);
if (tinyMCE.selectedElement != null && tinyMCE.selectedElement.nodeName.toLowerCase() == "img")
{
img = tinyMCE.selectedElement;
tinyMCE.imgElement = img;
}
if (img)
{
// Is it a internal MCE visual aid image, then skip this one.
if (tinyMCE.getAttrib(img, 'name').indexOf('mce_') == 0)
{
return true;
}
src = tinyMCE.getAttrib(img, 'src');
alt = tinyMCE.getAttrib(img, 'alt');
// Try polling out the title
if (alt == "")
{
alt = tinyMCE.getAttrib(img, 'title');
}
// Fix width/height attributes if the styles is specified
if (tinyMCE.isGecko)
{
var w = img.style.width;
if (w != null && w.length != 0)
{
img.setAttribute("width", w);
}
var h = img.style.height;
if (h != null && h.length != 0)
{
img.setAttribute("height", h);
}
}
border = tinyMCE.getAttrib(img, 'border');
hspace = tinyMCE.getAttrib(img, 'hspace');
vspace = tinyMCE.getAttrib(img, 'vspace');
width = tinyMCE.getAttrib(img, 'width');
height = tinyMCE.getAttrib(img, 'height');
align = tinyMCE.getAttrib(img, 'align');
onmouseover = tinyMCE.getAttrib(img, 'onmouseover');
onmouseout = tinyMCE.getAttrib(img, 'onmouseout');
title = tinyMCE.getAttrib(img, 'title');
// Is realy specified?
if (tinyMCE.isMSIE)
{
width = img.attributes['width'].specified ? width : "";
height = img.attributes['height'].specified ? height : "";
}
//onmouseover = tinyMCE.getImageSrc(tinyMCE.cleanupEventStr(onmouseover));
//onmouseout = tinyMCE.getImageSrc(tinyMCE.cleanupEventStr(onmouseout));
src = eval(tinyMCE.settings['urlconverter_callback'] + "(src, img, true);");
// Use mce_src if defined
mceRealSrc = tinyMCE.getAttrib(img, 'mce_src');
if (mceRealSrc != "")
{
src = mceRealSrc;
if (tinyMCE.getParam('convert_urls'))
{
src = eval(tinyMCE.settings['urlconverter_callback'] + "(src, img, true);");
}
}
action = "update";
}
var window_props = { file: alfresco.constants.WEBAPP_CONTEXT + "/jsp/wcm/tiny_mce_image_dialog.jsp",
width: 510 + tinyMCE.getLang('lang_insert_image_delta_width', 0),
height: 400 + (tinyMCE.isMSIE ? 25 : 0) + tinyMCE.getLang('lang_insert_image_delta_height', 0) };
var dialog_props = { src: src,
alt: alt,
border: border,
hspace: hspace,
vspace: vspace,
width: width,
height: height,
align: align,
title: title,
onmouseover: onmouseover,
onmouseout: onmouseout,
action: action,
inline: "yes" };
tinyMCE.openWindow(window_props, dialog_props);
return true;
}
else
{
return false;
}
}
alfresco.xforms.widgetConfig =
{
"xf:group":
{
"*": { "minimal": { "className": alfresco.xforms.HGroup }, "*": { "className": alfresco.xforms.VGroup }}
},
"xf:repeat":
{
"*": { "*": { "className": alfresco.xforms.Repeat } }
},
"xf:textarea":
{
"*": { "minimal": { "className": alfresco.xforms.PlainTextEditor },
"*": { "className": alfresco.xforms.RichTextEditor, params: [ "bold,italic,underline,separator,forecolor,backcolor,separator,link,unlink,image", "", "" ] },
"full": { "className": alfresco.xforms.RichTextEditor, params: ["bold,italic,underline,strikethrough,separator,fontselect,fontsizeselect", "link,unlink,image,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,bullist,numlist,separator,undo,redo,separator,forecolor,backcolor", "" ] }},
},
"xf:upload":
{
"*": { "*": { "className": alfresco.xforms.FilePicker } }
},
"xf:range":
{
"*": { "*": { "className": alfresco.xforms.NumericalRange } }
},
"xf:input":
{
"date": { "*": { "className": alfresco.xforms.DatePicker }},
"time": { "*": { "className": alfresco.xforms.TimePicker }},
"gDay": { "*": { "className": alfresco.xforms.DayPicker }},
"gMonth": { "*": { "className": alfresco.xforms.MonthPicker }},
"gYear": { "*": { "className": alfresco.xforms.YearPicker }},
"gMonthDay": { "*": { "className": alfresco.xforms.MonthDayPicker }},
"gYearMonth": { "*": { "className": alfresco.xforms.YearMonthPicker }},
"dateTime": { "*": { "className": alfresco.xforms.DateTimePicker }},
"*": { "*": { "className": alfresco.xforms.TextField }}
},
"xf:select1":
{
"boolean": { "*": { "className": alfresco.xforms.Checkbox }},
"*": { "full": { "className": alfresco.xforms.RadioSelect1},
"*": { "className": alfresco.xforms.ComboboxSelect1 }}
},
"xf:select":
{
"*": { "full": { "className": alfresco.xforms.CheckboxSelect},
"*": { "className": alfresco.xforms.ListSelect }}
},
"xf:submit":
{
"*": { "*": { "className": alfresco.xforms.Submit } }
},
"xf:trigger":
{
"*": { "*": { "className": alfresco.xforms.Trigger }}
},
"xf:switch":
{
"*": { "*": { "className": alfresco.xforms.SwitchGroup } }
},
"xf:case":
{
"*": { "*": { "className": alfresco.xforms.CaseGroup }}
},
"chiba:data": { "*": { "*": null } },
"xf:label": { "*": { "*": null } },
"xf:alert": { "*": { "*": null } }
}