diff --git a/config/alfresco/messages/webclient.properties b/config/alfresco/messages/webclient.properties
index 2b3540b434..c766f44221 100644
--- a/config/alfresco/messages/webclient.properties
+++ b/config/alfresco/messages/webclient.properties
@@ -1532,5 +1532,6 @@ validation_provide_values_for_required_fields=Please provide values for all requ
idle=Idle
loading=Loading
eg=e.g.
+click_to_edit=click to edit
# File Picker
go_up=Go up
diff --git a/source/java/org/alfresco/web/bean/wcm/CreateWebContentWizard.java b/source/java/org/alfresco/web/bean/wcm/CreateWebContentWizard.java
index 7ae2a2ab8e..39f9afe029 100644
--- a/source/java/org/alfresco/web/bean/wcm/CreateWebContentWizard.java
+++ b/source/java/org/alfresco/web/bean/wcm/CreateWebContentWizard.java
@@ -26,6 +26,7 @@ package org.alfresco.web.bean.wcm;
import java.io.ByteArrayInputStream;
import java.io.Serializable;
+import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -48,6 +49,7 @@ import org.alfresco.repo.avm.AVMNodeConverter;
import org.alfresco.repo.avm.wf.AVMSubmittedAspect;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.workflow.WorkflowModel;
+import org.alfresco.service.cmr.avm.AVMExistsException;
import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
import org.alfresco.service.cmr.avm.AVMService;
import org.alfresco.service.cmr.avmsync.AVMDifference;
@@ -469,7 +471,7 @@ public class CreateWebContentWizard extends BaseContentWizard
final Form form = (MimetypeMap.MIMETYPE_XML.equals(this.mimeType)
? this.getForm()
: null);
- String path = null;
+ String path = cwd;
if (form != null)
{
path = form.getOutputPathForFormInstanceData(this.instanceDataDocument,
@@ -491,9 +493,18 @@ public class CreateWebContentWizard extends BaseContentWizard
LOGGER.debug("creating file " + fileName + " in " + path);
// put the content of the file into the AVM store
- avmService.createFile(path,
- fileName,
- new ByteArrayInputStream((this.content == null ? "" : this.content).getBytes("UTF-8")));
+ try
+ {
+ avmService.createFile(path,
+ fileName,
+ new ByteArrayInputStream((this.content == null ? "" : this.content).getBytes("UTF-8")));
+ }
+ catch (AVMExistsException avmee)
+ {
+ String msg = Application.getMessage(FacesContext.getCurrentInstance(), "error_exists");
+ msg = MessageFormat.format(msg, fileName);
+ throw new AlfrescoRuntimeException(msg, avmee);
+ }
// remember the created path
this.createdPath = AVMNodeConverter.ExtendAVMPath(path, fileName);
diff --git a/source/java/org/alfresco/web/forms/xforms/Schema2XForms.java b/source/java/org/alfresco/web/forms/xforms/Schema2XForms.java
index 6dc8e707b3..b05ae6955e 100644
--- a/source/java/org/alfresco/web/forms/xforms/Schema2XForms.java
+++ b/source/java/org/alfresco/web/forms/xforms/Schema2XForms.java
@@ -1868,12 +1868,6 @@ public class Schema2XForms
//NamespaceConstants.XFORMS_PREFIX + ":ref",
//".");
- Element hint = this.createHint(xformsDocument, owner, resourceBundle);
- if (hint != null)
- {
- formControl.appendChild(hint);
- }
-
//add selector if repeat
//if (repeatSection != formSection)
//this.addSelector(xformsDocument, (Element) formControl.getParentNode());
@@ -1992,10 +1986,23 @@ public class Schema2XForms
alert = ("Please provide a valid value for '" + caption + "'." +
" '" + caption +
"' is " + (o.minimum == 0 ? "an optional" : "a required") + " '" +
- createCaption(this.getXFormsTypeName(xformsDocument, schema, controlType)) +
+ this.createCaption(this.getXFormsTypeName(xformsDocument, schema, controlType)) +
"' value.");
}
alertElement.appendChild(xformsDocument.createTextNode(alert));
+
+ final String hint = Schema2XForms.extractPropertyFromAnnotation(NamespaceService.ALFRESCO_URI,
+ "hint",
+ this.getAnnotation(owner),
+ resourceBundle);
+ if (hint != null)
+ {
+ final Element hintElement = xformsDocument.createElementNS(NamespaceConstants.XFORMS_NS,
+ NamespaceConstants.XFORMS_PREFIX + ":hint");
+ formControl.appendChild(hintElement);
+ this.setXFormsId(hintElement);
+ hintElement.appendChild(xformsDocument.createTextNode(hint));
+ }
return formControl;
}
@@ -2706,45 +2713,6 @@ public class Schema2XForms
return control;
}
- /**
- * Creates a hint XML Schema annotated node (AttributeDecl or ElementDecl).
- * The implementation is responsible for providing an xforms:hint element for the
- * specified schemaNode suitable to be dsipalayed to users of the XForm. The caller
- * is responsible for adding the returned element to the form.
- * This typically includes extracting documentation from the element/attribute's
- * annotation/documentation elements and/or extracting the same information from the
- * element/attribute's type annotation/documentation.
- *
- * @param xformsDocument
- * @param node
- * @param resourceBundle
- * @return The xforms:hint element. If a null value is returned a hint is not added.
- */
- public Element createHint(final Document xformsDocument,
- final XSObject node,
- final ResourceBundle resourceBundle)
- {
- final XSAnnotation annotation = this.getAnnotation(node);
- if (annotation == null)
- {
- return null;
- }
- final String s = this.extractPropertyFromAnnotation(NamespaceService.ALFRESCO_URI,
- "hint",
- annotation,
- resourceBundle);
- if (s == null)
- {
- return null;
- }
- final Element hintElement =
- xformsDocument.createElementNS(NamespaceConstants.XFORMS_NS,
- NamespaceConstants.XFORMS_PREFIX + ":hint");
- this.setXFormsId(hintElement);
- hintElement.appendChild(xformsDocument.createTextNode(s));
- return hintElement;
- }
-
private XSAnnotation getAnnotation(final XSObject o)
{
return (o instanceof XSElementDeclaration
diff --git a/source/java/org/alfresco/web/forms/xforms/XFormsProcessor.java b/source/java/org/alfresco/web/forms/xforms/XFormsProcessor.java
index b2f1ae7394..c367334073 100644
--- a/source/java/org/alfresco/web/forms/xforms/XFormsProcessor.java
+++ b/source/java/org/alfresco/web/forms/xforms/XFormsProcessor.java
@@ -46,6 +46,10 @@ public class XFormsProcessor
private static final Log LOGGER = LogFactory.getLog(XFormsProcessor.class);
+ /**
+ * A triple of js variable name, namespace uri, and namespace prefix which
+ * will form javascript variables within alfresco.constants.
+ */
private final static String[][] JS_NAMESPACES =
{
{ "xforms", NamespaceConstants.XFORMS_NS, NamespaceConstants.XFORMS_PREFIX },
@@ -54,6 +58,7 @@ public class XFormsProcessor
{ "alfresco", NamespaceService.ALFRESCO_URI, NamespaceService.ALFRESCO_PREFIX }
};
+ /** Scripts needed to initialize the xforms client. */
private final static String[] JS_SCRIPTS =
{
"/scripts/tiny_mce/" + (LOGGER.isDebugEnabled()
@@ -68,18 +73,19 @@ public class XFormsProcessor
"/scripts/upload_helper.js",
};
-
+ /** Localized strings needed by the xforms client. */
private final static String[] BUNDLE_KEYS =
{
- "validation_provide_values_for_required_fields",
+ "add_content",
+ "cancel",
+ "click_to_edit",
+ "eg",
+ "go_up",
"idle",
"loading",
- "add_content",
- "go_up",
- "cancel",
- "upload",
"path",
- "eg"
+ "upload",
+ "validation_provide_values_for_required_fields"
};
public XFormsProcessor()
diff --git a/source/test-resources/xforms/unit-tests/interesting-schema-test/recursive-test.xsd b/source/test-resources/xforms/unit-tests/interesting-schema-test/recursive-test.xsd
new file mode 100644
index 0000000000..ac61994e54
--- /dev/null
+++ b/source/test-resources/xforms/unit-tests/interesting-schema-test/recursive-test.xsd
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/source/test-resources/xforms/unit-tests/simple-test/components-test.xsd b/source/test-resources/xforms/unit-tests/simple-test/components-test.xsd
index 3d2af4dd27..b0e598e8ea 100644
--- a/source/test-resources/xforms/unit-tests/simple-test/components-test.xsd
+++ b/source/test-resources/xforms/unit-tests/simple-test/components-test.xsd
@@ -154,13 +154,19 @@
- full
+
+ full
+ this control should appear as radio buttons.
+
- full
+
+ full
+ Please select some of these numbers. This control should appear as a list.
+
@@ -169,6 +175,7 @@
${components-test.list_of_ten_select_three.label}
${components-test.list_of_ten_select_three.alert}
+ Please select exactly three elements from this list.
diff --git a/source/web/css/xforms.css b/source/web/css/xforms.css
index 5d20237995..65287c417b 100644
--- a/source/web/css/xforms.css
+++ b/source/web/css/xforms.css
@@ -97,6 +97,22 @@
height: 200px;
}
+.xformsRichTextEditorHoverLayer
+{
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ width: 100%;
+ height: 100%;
+ background-color: lightgray;
+ color: black;
+ z-index: 100;
+ font-weight: bolder;
+ font-size: 16px;
+ text-align: center;
+ opacity: .5;
+}
+
.xformsRepeat
{
}
diff --git a/source/web/scripts/ajax/xforms.js b/source/web/scripts/ajax/xforms.js
index fe1872c62f..23691a6c87 100644
--- a/source/web/scripts/ajax/xforms.js
+++ b/source/web/scripts/ajax/xforms.js
@@ -386,18 +386,6 @@ dojo.declare("alfresco.xforms.Widget",
return xpath;
},
- /** Returns the label node for this widget from the xforms document. */
- _getLabelNode: function()
- {
- return this._getChildXFormsNode("label");
- },
-
- /** Returns the alert node for this widget from the xforms document. */
- _getAlertNode: function()
- {
- return this._getChildXFormsNode("alert");
- },
-
/** Returns a child node by name within the xform. */
_getChildXFormsNode: function(nodeName)
{
@@ -418,7 +406,7 @@ dojo.declare("alfresco.xforms.Widget",
/** Returns the widget's label. */
getLabel: function()
{
- var node = this._getLabelNode();
+ var node = this._getChildXFormsNode("label");
var result = node ? dojo.dom.textContent(node) : "";
if (djConfig.isDebug)
{
@@ -430,9 +418,16 @@ dojo.declare("alfresco.xforms.Widget",
/** Returns the widget's alert text. */
getAlert: function()
{
- var node = this._getAlertNode();
+ 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()
@@ -816,24 +811,44 @@ dojo.declare("alfresco.xforms.PlainTextEditor",
/** 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)
+ function(xform, xformsNode, params)
{
- this.focused = false;
+ this._focused = false;
+ this._tinyMCE_buttons = params;
+ if (!this.statics.tinyMCEInitialized)
+ {
+ this.statics.tinyMCEInitialized = true;
+ }
},
{
/////////////////////////////////////////////////////////////////
- // methods
+ // 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();
@@ -856,6 +871,8 @@ dojo.declare("alfresco.xforms.RichTextEditor",
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++)
@@ -868,17 +885,18 @@ dojo.declare("alfresco.xforms.RichTextEditor",
}
if (!this.isReadonly())
{
- this._createTinyMCE();
+// this._createTinyMCE();
+ var me = this;
+ dojo.event.browser.addListener(this.widget,
+ "onmouseover",
+ function(event) { me._div_mouseoverHandler(event) },
+ true);
}
},
setValue: function(value)
{
- if (this.isReadonly())
- {
- this.widget.innerHTML = value;
- }
- else
+ if (this.statics.currentInstance == this)
{
tinyMCE.selectedInstance = tinyMCE.getInstanceById(this.id);
try
@@ -891,11 +909,15 @@ dojo.declare("alfresco.xforms.RichTextEditor",
dojo.debug(e);
}
}
+ else
+ {
+ this.widget.innerHTML = value;
+ }
},
getValue: function()
{
- var result = this.isReadonly() ? this.widget.innerHTML : tinyMCE.getContent(this.id);
+ 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;
},
@@ -903,15 +925,10 @@ dojo.declare("alfresco.xforms.RichTextEditor",
setReadonly: function(readonly)
{
alfresco.xforms.RichTextEditor.superclass.setReadonly.call(this, readonly);
- var mce = tinyMCE.getInstanceById(this.id);
- if (readonly && mce)
+ if (readonly && this.statics.currentInstance == this)
{
this._removeTinyMCE();
}
- else if (!readonly && !mce && this.widget)
- {
- this._createTinyMCE();
- }
},
_destroy: function()
@@ -936,14 +953,14 @@ dojo.declare("alfresco.xforms.RichTextEditor",
}
var widget = event.target.widget;
widget._commitValueChange();
- this.focused = false;
+ this._focused = false;
},
_tinyMCE_focusHandler: function(event)
{
var widget = event.target.widget;
var repeatIndices = widget.getRepeatIndices();
- if (repeatIndices.length != 0 && !this.focused)
+ if (repeatIndices.length != 0 && !this._focused)
{
var r = repeatIndices[repeatIndices.length - 1].repeat;
var p = widget;
@@ -962,7 +979,49 @@ dojo.declare("alfresco.xforms.RichTextEditor",
}
repeatIndices[repeatIndices.length - 1].repeat.setFocusedChild(p);
}
- this.focused = true;
+ 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();
+ }
}
});
@@ -2325,7 +2384,15 @@ dojo.declare("alfresco.xforms.AbstractGroup",
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;
},
@@ -3943,7 +4010,7 @@ dojo.declare("alfresco.xforms.XForm",
{
return null;
}
- var result = new x(this, xformsNode);
+ var result = new x.className(this, xformsNode, x.params);
if (result instanceof alfresco.xforms.Widget)
{
return result;
@@ -4568,7 +4635,6 @@ dojo.html.toCamelCase = function(str)
////////////////////////////////////////////////////////////////////////////////
// tiny mce integration
////////////////////////////////////////////////////////////////////////////////
-
tinyMCE.init({
theme: "advanced",
mode: "exact",
@@ -4582,8 +4648,8 @@ tinyMCE.init({
execcommand_callback: "alfresco_TinyMCE_execcommand_callback",
theme_advanced_toolbar_location: "top",
theme_advanced_toolbar_align: "left",
- theme_advanced_buttons1: "bold,italic,underline,strikethrough,separator,fontselect,fontsizeselect",
- theme_advanced_buttons2: "link,unlink,image,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,bullist,numlist,separator,undo,redo,separator,forecolor,backcolor",
+ theme_advanced_buttons1: "",
+ theme_advanced_buttons2: "",
theme_advanced_buttons3: "",
urlconverter_callback: "alfresco_TinyMCE_urlconverter_callback"
});
@@ -4791,62 +4857,64 @@ alfresco.xforms.widgetConfig =
{
"xf:group":
{
- "*": { "minimal": alfresco.xforms.HGroup, "*": alfresco.xforms.VGroup }
+ "*": { "minimal": { "className": alfresco.xforms.HGroup }, "*": { "className": alfresco.xforms.VGroup }}
},
"xf:repeat":
{
- "*": { "*": alfresco.xforms.Repeat }
+ "*": { "*": { "className": alfresco.xforms.Repeat } }
},
"xf:textarea":
{
- "*": { "minimal": alfresco.xforms.PlainTextEditor, "*": alfresco.xforms.RichTextEditor },
+ "*": { "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":
{
- "*": { "*": alfresco.xforms.FilePicker }
+ "*": { "*": { "className": alfresco.xforms.FilePicker } }
},
"xf:range":
{
- "*": { "*": alfresco.xforms.NumericalRange }
+ "*": { "*": { "className": alfresco.xforms.NumericalRange } }
},
"xf:input":
{
- "date": { "*": alfresco.xforms.DatePicker },
- "time": { "*": alfresco.xforms.TimePicker },
- "gDay": { "*": alfresco.xforms.DayPicker },
- "gMonth": { "*": alfresco.xforms.MonthPicker },
- "gYear": { "*": alfresco.xforms.YearPicker },
- "gMonthDay": { "*": alfresco.xforms.MonthDayPicker },
- "gYearMonth": { "*": alfresco.xforms.YearMonthPicker },
- "dateTime": { "*": alfresco.xforms.DateTimePicker },
- "*": { "*": alfresco.xforms.TextField }
+ "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": { "*": alfresco.xforms.Checkbox },
- "*": { "full": alfresco.xforms.RadioSelect1,
- "*": alfresco.xforms.ComboboxSelect1 }
+ "boolean": { "*": { "className": alfresco.xforms.Checkbox }},
+ "*": { "full": { "className": alfresco.xforms.RadioSelect1},
+ "*": { "className": alfresco.xforms.ComboboxSelect1 }}
},
"xf:select":
{
- "*": { "full": alfresco.xforms.CheckboxSelect,
- "*": alfresco.xforms.ListSelect }
+ "*": { "full": { "className": alfresco.xforms.CheckboxSelect},
+ "*": { "className": alfresco.xforms.ListSelect }}
},
"xf:submit":
{
- "*": { "*": alfresco.xforms.Submit }
+ "*": { "*": { "className": alfresco.xforms.Submit } }
},
"xf:trigger":
{
- "*": { "*": alfresco.xforms.Trigger }
+ "*": { "*": { "className": alfresco.xforms.Trigger }}
},
"xf:switch":
{
- "*": { "*": alfresco.xforms.SwitchGroup }
+ "*": { "*": { "className": alfresco.xforms.SwitchGroup } }
},
"xf:case":
{
- "*": { "*": alfresco.xforms.CaseGroup }
+ "*": { "*": { "className": alfresco.xforms.CaseGroup }}
},
"chiba:data": { "*": { "*": null } },
"xf:label": { "*": { "*": null } },