These updates reflect the ajax spec/impl work for sending the Ajax response.
All tests/demos run successsfully.
M jsf-api/resources/ajax.js
-- added jsdocs for jsf.ajax.response
-- implemented update
M jsf-ri/src/com/sun/faces/application/PartialTraversalImpl.java
-- write new response format
Index: jsf-api/resources/ajax.js
===================================================================
--- jsf-api/resources/ajax.js (revision 5982)
+++ jsf-api/resources/ajax.js (working copy)
@@ -318,24 +318,136 @@
* <code>responseXML</code> object and update the <code>DOM</code>
* as follows:
* <ul>
- * <li>Determine if the entire <code>DOM</code> should be replaced, or
- * if only specified sections (known as partial rendering) should be
- * updated. The entire <code>DOM</code> must be replaced if a
- * <code>render</code> element identifier is
- * <code>javax.faces.viewRoot</code>.</li>
- * <li>If partial <code>DOM</code> update is required, replace the
- * <code>DOM</code> markup whose identifier matches the corresponding
- * <code>render</code> identifier.</li>
- * <li>Capture the view state sent in the response and insert it into
- * the <code>DOM</code> as a <code>hidden input</code> field with the
- * identifier <code>javax.faces.viewState</code>. Look for all the
- * <code>form</code> elements in the <code>DOM</code>, and for each
- * <code>form</code> element, determine if a
<code>javax.faces.viewState</code>
- * field exists. If it does, replace it with the view state from the
- * response. If it does not exist, create a <code>hidden input</code>
- * field with the identifier <code>javax.faces.viewState</code> and
- * insert it as a child element of the <code>form</code> elements.</li>
+ * <p><b>Update Element Processing</b></p>
+ * <li>If an <code>update</code> element is found in the response
+ * with the identifier <code>javax.faces.ViewRoot</code>:
+ * <pre><code><update id="javax.faces.ViewRoot">
+ * <![CDATA[...]]>
+ * </update></code></pre>
+ * Update the entire DOM as follows:
+ * <ul>
+ * <li>Extract the <code>CDATA</code> content and trim the <html>
+ * and </html> from the <code>CDATA</code> content if it is
present.</li>
+ * <li>If the <code>CDATA</code> content contains a <head> element,
+ * and the document has a <code><head></code> section, extract the
+ * contents of the <head> element from the
<code><update></code>
+ * element's <code>CDATA</code> content and replace the document's
<head>
+ * section with this contents.</li>
+ * <li>If the <code>CDATA</code> content contains a <body> element,
+ * and the document has a <code><body></code> section, extract
the contents
+ * of the <body> element from the <code><update></code>
+ * element's <code>CDATA</code> content and replace the document's
<body>
+ * section with this contents.</li>
+ * <li>If the <code>CDATA</code> content does not contain a
<body> element,
+ * replace the document's <body> section with the <code>CDATA</code>
+ * contents.</li>
* </ul>
+ * <li>If an <code>update</code> element is found in the response with
the identifier
+ * <code>javax.faces.ViewState</code>:
+ * <pre><code><update id="javax.faces.ViewState">
+ * <![CDATA[...]]>
+ * </update></code></pre>
+ * Include this <code>state</code> in the document as follows:
+ * <ul>
+ * <li>Extract this <code><update></code> element's
<code>CDATA</code> contents
+ * from the response.</li>
+ * <li>If the document contains an element with the identifier
+ * <code>javax.faces.ViewState</code> replace its contents with the
+ * <code>CDATA</code> contents.</li>
+ * <li>For each <code><form></code> element in the document:
+ * <ul>
+ * <li>If the <code><form></code> element contains an
<code><input></code>
+ * element with the identifier <code>javax.faces.ViewState</code>,
replace the
+ * <code><input></code> element contents with the
<code><update></code>
+ * element's <code>CDATA</code> contents.</li>
+ * <li>If the <code><form></code> element does not contain an
element with
+ * the identifier <code>javax.faces.ViewState</code>, create an
+ * <code><input></code> element of the type <code>hidden</code>,
+ * with the identifier <code>javax.faces.ViewState</code>, set its contents
+ * to the <code><update></code> element's <code>CDATA</code>
contents, and
+ * add the <code><input></code> element as a child to the
+ * <code><form></code> element.</li>
+ * </ul>
+ * </li>
+ * </ul>
+ * </li>
+ * <li>For any other <code><update></code> element:
+ * <pre><code><update id="update id">
+ * <![CDATA[...]]>
+ * </update></code></pre>
+ * Find the DOM element with the identifier that matches the
+ * <code><update></code> element identifier, and replace its
contents with
+ * the <code><update></code> element's <code>CDATA</code>
contents.</li>
+ * </ul>
+ * </li>
+ * <p><b>Insert Element Processing</b></p>
+ * <li>If an <code><input></code> element is found in the
response with the
+ * attribute <code>before</code>:
+ * <pre><code><insert id="insert id" before="before id">
+ * <![CDATA[...]]>
+ * </insert></code></pre>
+ * <ul>
+ * <li>Extract this <code><input></code> element's
<code>CDATA</code> contents
+ * from the response.</li>
+ * <li>Find the DOM element whose identifier matches <code>before
id</code> and insert
+ * the <code><input></code> element's <code>CDATA</code> content
before
+ * the DOM element in the document.</li>
+ * </ul>
+ * </li>
+ * <li>If an <code><input></code> element is found in the
response with the
+ * attribute <code>after</code>:
+ * <pre><code><insert id="insert id" after="after id">
+ * <![CDATA[...]]>
+ * </insert></code></pre>
+ * <ul>
+ * <li>Extract this <code><input></code> element's
<code>CDATA</code> contents
+ * from the response.</li>
+ * <li>Find the DOM element whose identifier matches <code>after
id</code> and insert
+ * the <code><input></code> element's <code>CDATA</code> content
after
+ * the DOM element in the document.</li>
+ * </ul>
+ * </li>
+ * <p><b>Delete Element Processing</b></p>
+ * <li>If a <code><delete></code> element is found in the response:
+ * <pre><code><delete id="delete id"/></code></pre>
+ * Find the DOM element whose identifier matches <code>delete id</code>
and remove it
+ * from the DOM.</li>
+ * <p><b>Element Attribute Update Processing</b></p>
+ * <li>If an <code><attributes></code> element is found in the
response:
+ * <pre><code><attributes id="id of element with attribute">
+ * <attribute name="attribute name" value="attribute value">
+ * ...
+ * </attributes></code></pre>
+ * <ul>
+ * <li>Find the DOM element that matches the
<code><attributes></code> identifier.</li>
+ * <li>For each nested <code><attribute></code> element in
<code><attribute></code>,
+ * update the DOM element attribute value (whose name matches
<code>attribute name</code>),
+ * with <code>attribute value</code>.</li>
+ * </ul>
+ * </li>
+ * <p><b>JavaScript Processing</b></p>
+ * <li>If an <code><eval></code> element is found in the response:
+ * <pre><code><eval>
+ * <![CDATA[...JavaScript...]]>
+ * </eval></code></pre>
+ * <ul>
+ * <li>Extract this <code><eval></code> element's
<code>CDATA</code> contents
+ * from the response and execute it as if it were JavaScript code.</li>
+ * </ul>
+ * </li>
+ * <p><b>Redirect Processing</b></p>
+ * <li>If a <code><redirect></code> element is found in the response:
+ * <pre><code><redirect url="redirect url"/></code></pre>
+ * Cause a redirect to the url <code>redirect url</code>.</li>
+ * <p><b>Error Processing</b></p>
+ * <li>If an <code><error></code> element is found in the response:
+ * <pre><code><error>
+ * <![CDATA[...]]>
+ * </error></code></pre>
+ * Extract this <code><error></code> element's <code>CDATA</code>
contents.
+ * This is an error from the server, and implementations can use this
information
+ * as needed.</li>
+ *
* </p>
*
* @param request The <code>XMLHttpRequest</code> instance that
@@ -361,17 +473,24 @@
throw new Error("jsf.ajax.response: Reponse contains no data");
}
- var id, content, markup, str;
+ var id, content, markup, str, state;
- var components = xml.getElementsByTagName('components')[0];
- var render = components.getElementsByTagName('render');
+ //////////////////////
+ // Check for updates..
+ //////////////////////
- for (var i = 0; i < render.length; i++) {
- id = render[i].getAttribute('id');
+ var update = xml.getElementsByTagName('update');
+
+ for (var i = 0; i < update.length; i++) {
+ id = update[i].getAttribute('id');
+ if (id === "javax.faces.ViewState") {
+ state = state || update[i].firstChild;
+ continue;
+ }
// join the CDATA sections in the markup
markup = '';
- for (var j = 0; j < render[i].firstChild.childNodes.length; j++) {
- content = render[i].firstChild.childNodes[j];
+ for (var j = 0; j < update[i].childNodes.length; j++) {
+ content = update[i].childNodes[j];
markup += content.text || content.data;
}
str = utils.stripScripts(markup);
@@ -452,11 +571,34 @@
}
}
+ //////////////////////
+ // Check For Inserts.
+ //////////////////////
+
+ //////////////////////
+ // Check For Deletes.
+ //////////////////////
+
+ //////////////////////
+ // Update Attributes.
+ //////////////////////
+
+ //////////////////////
+ // JavaScript Eval.
+ //////////////////////
+
+ //////////////////////
+ // Redirect.
+ //////////////////////
+
+ //////////////////////
+ // Error.
+ //////////////////////
+
// Now set the view state from the server into the DOM
// If there are multiple forms, make sure they all have a
// viewState hidden field.
- var state = state || xml.getElementsByTagName('state')[0].firstChild;
if (state) {
var stateElem = utils.$("javax.faces.ViewState");
if (stateElem) {
Index: jsf-ri/src/com/sun/faces/application/PartialTraversalImpl.java
===================================================================
--- jsf-ri/src/com/sun/faces/application/PartialTraversalImpl.java
(revision 5982)
+++ jsf-ri/src/com/sun/faces/application/PartialTraversalImpl.java
(working copy)
@@ -84,6 +84,7 @@
private static final String RENDER_ALL_MARKER = "javax.faces.ViewRoot";
private static final String ORIGINAL_WRITER =
"javax.faces.originalWriter";
+ private static final String VIEW_STATE_MARKER =
"javax.faces.ViewState";
public void traverse(FacesContext context, PhaseId phaseId,
UIViewRoot viewRoot) {
@@ -136,12 +137,10 @@
exContext.setResponseContentType("text/xml");
exContext.setResponseHeader("Cache-Control",
"no-cache");
writer.startElement("partial-response", viewRoot);
- writer.startElement("components", viewRoot);
}
if (partialViewContext.isRenderAll()) {
renderAll(context, viewRoot);
- writer.endElement("components");
renderState(context, viewRoot);
writer.endElement("partial-response");
return;
@@ -155,8 +154,6 @@
processComponents(viewRoot, phaseId,
renderPhaseClientIds, context);
}
- writer.endElement("components");
-
renderState(context, viewRoot);
writer.endElement("partial-response");
@@ -190,21 +187,18 @@
component.processUpdates(context);
}
} else if (phaseId == PhaseId.RENDER_RESPONSE) {
- if (phaseClientIds.contains(component.getClientId()) ||
- partialViewContext.isRenderAll()) {
+ if (phaseClientIds.contains(component.getClientId())) {
if (component.isRendered()) {
ResponseWriter writer = context.getResponseWriter();
- writer.startElement("render", component);
+ writer.startElement("update", component);
writer.writeAttribute("id",
component.getClientId(context), "id");
try {
- writer.startElement("markup", component);
writer.write("<![CDATA[");
// do the default behavior...
component.encodeAll(context);
writer.write("]]>");
- writer.endElement("markup");
} catch (Exception ce) {
if (LOGGER.isLoggable(Level.SEVERE)) {
LOGGER.severe(ce.toString());
@@ -215,7 +209,7 @@
ce);
}
}
- writer.endElement("render");
+ writer.endElement("update");
}
}
}
@@ -233,10 +227,9 @@
// JavaScript knows how to replace the entire document with
// this response.
ResponseWriter writer = context.getResponseWriter();
- writer.startElement("render", viewRoot);
+ writer.startElement("update", viewRoot);
writer.writeAttribute("id", RENDER_ALL_MARKER, "id");
- writer.startElement("markup", viewRoot);
writer.write("<![CDATA[");
Iterator<UIComponent> itr = viewRoot.getFacetsAndChildren();
@@ -246,17 +239,17 @@
}
writer.write("]]>");
- writer.endElement("markup");
- writer.endElement("render");
+ writer.endElement("update");
}
private void renderState(FacesContext context, UIViewRoot viewRoot)
throws IOException {
// Get the view state and write it to the response..
ResponseWriter writer = context.getResponseWriter();
- writer.startElement("state", viewRoot);
+ writer.startElement("update", viewRoot);
+ writer.writeAttribute("id", VIEW_STATE_MARKER, "id");
String state =
context.getApplication().getStateManager().getViewState(context);
writer.write("<![CDATA[" + state + "]]>");
- writer.endElement("state");
+ writer.endElement("update");
}