Final polish of Ajax support.

This commit is contained in:
Jeremy Grelle
2008-04-25 16:06:14 +00:00
parent b8151d133f
commit ff33b67afc
22 changed files with 579 additions and 360 deletions

View File

@@ -0,0 +1,31 @@
package org.springframework.js.ajax;
import java.io.IOException;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.support.RequestContextUtils;
import org.springframework.web.servlet.view.RedirectView;
public class AjaxRedirectView extends RedirectView implements View {
private AjaxHandler ajaxHandler = new SpringJavascriptAjaxHandler();
public AjaxRedirectView(String redirectUrl, boolean redirectContextRelative, boolean redirectHttp10Compatible) {
super(redirectUrl, redirectContextRelative, redirectHttp10Compatible);
}
protected void sendRedirect(HttpServletRequest request, HttpServletResponse response, String targetUrl,
boolean http10Compatible) throws IOException {
ServletContext context = RequestContextUtils.getWebApplicationContext(request).getServletContext();
if (ajaxHandler.isAjaxRequest(context, request, response)) {
ajaxHandler.sendAjaxRedirect(context, request, response, targetUrl, false);
} else {
super.sendRedirect(request, response, targetUrl, http10Compatible);
}
}
}

View File

@@ -0,0 +1,28 @@
package org.springframework.js.ajax;
import java.util.Locale;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.view.UrlBasedViewResolver;
public class AjaxUrlBasedViewResolver extends UrlBasedViewResolver {
/**
* Overridden to implement check for "redirect:" prefix.
* <p>
* Redirect requires special behavior on an Ajax request.
*/
protected View createView(String viewName, Locale locale) throws Exception {
// If this resolver is not supposed to handle the given view,
// return null to pass on to the next resolver in the chain.
if (!canHandle(viewName, locale)) {
return null;
}
// Check for special "redirect:" prefix.
if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());
return new AjaxRedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible());
}
return super.createView(viewName, locale);
}
}

View File

@@ -17,13 +17,14 @@ import org.apache.tiles.context.TilesRequestContext;
import org.apache.tiles.impl.BasicTilesContainer;
import org.springframework.js.ajax.AjaxHandler;
import org.springframework.js.ajax.SpringJavascriptAjaxHandler;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.support.JstlUtils;
import org.springframework.web.servlet.support.RequestContext;
import org.springframework.web.servlet.view.tiles2.TilesView;
public class AjaxTilesView extends TilesView {
public static final String FRAGMENTS_PARAM = "fragments";
private static final String FRAGMENTS_PARAM = "fragments";
private AjaxHandler ajaxHandler = new SpringJavascriptAjaxHandler();
@@ -48,16 +49,22 @@ public class AjaxTilesView extends TilesView {
Map flattenedAttributeMap = new HashMap();
flattenAttributeMap(container, tilesRequestContext, flattenedAttributeMap, compositeDefinition);
String attrName = request.getParameter(FRAGMENTS_PARAM);
Attribute attributeToRender = (Attribute) flattenedAttributeMap.get(attrName);
container.render(attributeToRender, response.getWriter(), new Object[] { request, response });
String[] attrNames = getRenderFragments(model, request, response);
response.flushBuffer();
for (int i = 0; i < attrNames.length; i++) {
Attribute attributeToRender = (Attribute) flattenedAttributeMap.get(attrNames[i]);
container.render(attributeToRender, response.getWriter(), new Object[] { request, response });
}
} else {
super.renderMergedOutputModel(model, request, response);
}
}
protected String[] getRenderFragments(Map model, HttpServletRequest request, HttpServletResponse response) {
String attrName = request.getParameter(FRAGMENTS_PARAM);
return StringUtils.commaDelimitedListToStringArray(attrName);
}
private void flattenAttributeMap(BasicTilesContainer container, TilesRequestContext requestContext, Map resultMap,
Definition compositeDefinition) throws Exception {
Iterator i = compositeDefinition.getAttributes().keySet().iterator();

File diff suppressed because one or more lines are too long

View File

@@ -13,8 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
dojo.declare("Spring.DefaultEquals", null, {
equals : function(/*Object*/other){
if (other.declaredClass && other.declaredClass == this.declaredClass) {
return true;
}else{
return false;
}
}
});
dojo.declare("Spring.ElementDecoration", Spring.AbstractElementDecoration, {
dojo.declare("Spring.ElementDecoration", [Spring.AbstractElementDecoration, Spring.DefaultEquals], {
constructor : function(config) {
this.copyFields = new Array('name', 'value', 'type', 'checked', 'selected', 'readOnly', 'disabled', 'alt', 'maxLength');
dojo.mixin(this, config);
@@ -28,17 +37,23 @@ dojo.declare("Spring.ElementDecoration", Spring.AbstractElementDecoration, {
dijit.byId(this.elementId).destroyRecursive(false);
}
var element = dojo.byId(this.elementId);
for (var copyField in this.copyFields) {
copyField = this.copyFields[copyField];
if (!this.widgetAttrs[copyField] && element[copyField] && (typeof element[copyField] != 'number' ||
(typeof element[copyField] == 'number' && element[copyField] >= 0))) {
this.widgetAttrs[copyField] = element[copyField];
}
if (!element) {
console.error("Could not apply " + this.widgetType + " decoration. Element with id '" + this.elementId + "' not found in the DOM.");
}
else {
for (var copyField in this.copyFields) {
copyField = this.copyFields[copyField];
if (!this.widgetAttrs[copyField] && element[copyField] &&
(typeof element[copyField] != 'number' ||
(typeof element[copyField] == 'number' && element[copyField] >= 0))) {
this.widgetAttrs[copyField] = element[copyField];
}
}
dojo.require(this.widgetModule);
var widgetConstructor = dojo.eval(this.widgetType);
this.widget = new widgetConstructor(this.widgetAttrs, element);
this.widget.startup();
}
dojo.require(this.widgetModule);
var widgetConstructor = dojo.eval(this.widgetType);
this.widget = new widgetConstructor(this.widgetAttrs, element);
this.widget.startup();
//return this to support method chaining
return this;
},
@@ -54,10 +69,10 @@ dojo.declare("Spring.ElementDecoration", Spring.AbstractElementDecoration, {
this.widget._setStateClass();
}
return isValid;
}
}
});
dojo.declare("Spring.ValidateAllDecoration", Spring.AbstractValidateAllDecoration, {
dojo.declare("Spring.ValidateAllDecoration", [Spring.AbstractValidateAllDecoration, Spring.DefaultEquals], {
constructor : function(config) {
this.originalHandler = null;
this.connection = null;
@@ -90,7 +105,7 @@ dojo.declare("Spring.ValidateAllDecoration", Spring.AbstractValidateAllDecoratio
}
});
dojo.declare("Spring.AjaxEventDecoration", Spring.AbstractAjaxEventDecoration, {
dojo.declare("Spring.AjaxEventDecoration", [Spring.AbstractAjaxEventDecoration, Spring.DefaultEquals], {
constructor : function(config){
this.connection = null;
dojo.mixin(this, config);
@@ -110,7 +125,7 @@ dojo.declare("Spring.AjaxEventDecoration", Spring.AbstractAjaxEventDecoration, {
this.sourceId = this.elementId;
}
if(this.formId == ""){
Spring.remoting.getLinkedResource(this.sourceId, this.params, false);
Spring.remoting.getLinkedResource(this.sourceId, this.params, this.popup);
} else {
Spring.remoting.submitForm(this.sourceId, this.formId, this.params);
}
@@ -130,8 +145,11 @@ dojo.declare("Spring.RemotingHandler", Spring.AbstractRemotingHandler, {
var sourceComponent = dojo.byId(sourceId);
if (sourceComponent != null){
if(sourceComponent.value != undefined) {
content[sourceId] = sourceComponent.value;
if(sourceComponent.value != undefined && sourceComponent.type && ("button,submit,reset").indexOf(sourceComponent.type) < 0) {
content[sourceId] = sourceComponent.value;
}
else if(sourceComponent.name != undefined) {
content[sourceComponent.name] = sourceComponent.name;
} else {
content[sourceId] = sourceId;
}
@@ -198,7 +216,19 @@ dojo.declare("Spring.RemotingHandler", Spring.AbstractRemotingHandler, {
return response;
}
else {
window.location = window.location.protocol + "//" + window.location.host + redirectURL;
if (redirectURL.indexOf("/") >= 0) {
window.location = window.location.protocol + "//" + window.location.host + redirectURL;
} else {
var location = window.location.protocol + "//" + window.location.host + window.location.pathname;
var appendIndex = location.lastIndexOf("/");
location = location.substr(0,appendIndex+1) + redirectURL;
if (location == window.location) {
Spring.remoting.getResource(location, ioArgs.args.content, false);
}
else {
window.location = location;
}
}
return response;
}
}
@@ -240,7 +270,11 @@ dojo.declare("Spring.RemotingHandler", Spring.AbstractRemotingHandler, {
newNodes.forEach(function(item){
if (item.id != null && item.id != "") {
var target = dojo.byId(item.id);
target.parentNode.replaceChild(item, target);
if (!target) {
console.error("An existing DOM elment with id '" + item.id + "' could not be found for replacement.");
} else {
target.parentNode.replaceChild(item, target);
}
}
});
}
@@ -276,7 +310,7 @@ dojo.declare("Spring.RemotingHandler", Spring.AbstractRemotingHandler, {
}
});
dojo.declare("Spring.CommandLinkDecoration", Spring.AbstractCommandLinkDecoration, {
dojo.declare("Spring.CommandLinkDecoration", [Spring.AbstractCommandLinkDecoration, Spring.DefaultEquals], {
constructor : function(config){
dojo.mixin(this, config);
},

View File

@@ -13,4 +13,4 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
Spring={};Spring.decorations=[];Spring.decorations.applied=false;Spring.initialize=function(){Spring.applyDecorations();Spring.remoting=new Spring.RemotingHandler();};Spring.addDecoration=function(_1){Spring.decorations.push(_1);if(Spring.decorations.applied){_1.apply();}};Spring.applyDecorations=function(){if(!Spring.decorations.applied){for(var x=0;x<Spring.decorations.length;x++){Spring.decorations[x].apply();}Spring.decorations.applied=true;}};Spring.validateAll=function(){var _3=true;for(x in Spring.decorations){if(Spring.decorations[x].widget&&!Spring.decorations[x].validate()){_3=false;}}return _3;};Spring.validateRequired=function(){var _4=true;for(x in Spring.decorations){if(Spring.decorations[x].decorator&&Spring.decorations[x].isRequired()&&!Spring.decorations[x].validate()){_4=false;}}return _4;};Spring.AbstractElementDecoration=function(){};Spring.AbstractElementDecoration.prototype={elementId:"",widgetType:"",widgetModule:"",widget:null,widgetAttrs:{},apply:function(){},validate:function(){},isRequired:function(){}};Spring.AbstractValidateAllDecoration=function(){};Spring.AbstractValidateAllDecoration.prototype={event:"",elementId:"",apply:function(){},cleanup:function(){},handleEvent:function(_5){}};Spring.AbstractCommandLinkDecoration=function(){};Spring.AbstractCommandLinkDecoration.prototype={elementId:"",linkHtml:"",apply:function(){},submitFormFromLink:function(_6,_7,_8){}};Spring.AbstractAjaxEventDecoration=function(){};Spring.AbstractAjaxEventDecoration.prototype={event:"",elementId:"",sourceId:"",formId:"",params:{},apply:function(){},cleanup:function(){},submit:function(_9){}};Spring.AbstractRemotingHandler=function(){};Spring.AbstractRemotingHandler.prototype={submitForm:function(_a,_b,_c){},getLinkedResource:function(_d,_e,_f){},getResource:function(_10,_11,_12){},handleResponse:function(){},handleError:function(){}};
Spring={};Spring.decorations={};Spring.decorations.applied=false;Spring.initialize=function(){Spring.applyDecorations();Spring.remoting=new Spring.RemotingHandler();};Spring.addDecoration=function(_1){if(!Spring.decorations[_1.elementId]){Spring.decorations[_1.elementId]=[];Spring.decorations[_1.elementId].push(_1);}else{var _2=false;for(var i=0;i<Spring.decorations[_1.elementId].length;i++){var _4=Spring.decorations[_1.elementId][i];if(_4.equals(_1)){if(_4.cleanup!=undefined){_4.cleanup();}Spring.decorations[_1.elementId][i]=_1;_2=true;break;}}if(!_2){Spring.decorations[_1.elementId].push(_1);}}if(Spring.decorations.applied){_1.apply();}};Spring.applyDecorations=function(){if(!Spring.decorations.applied){for(var _5 in Spring.decorations){for(var x=0;x<Spring.decorations[_5].length;x++){Spring.decorations[_5][x].apply();}}Spring.decorations.applied=true;}};Spring.validateAll=function(){var _7=true;for(var _8 in Spring.decorations){for(var x=0;x<Spring.decorations[_8].length;x++){if(Spring.decorations[_8][x].widget&&!Spring.decorations[_8][x].validate()){_7=false;}}}return _7;};Spring.validateRequired=function(){var _a=true;for(var _b in Spring.decorations){for(var x=0;x<Spring.decorations[_b].length;x++){if(Spring.decorations[_b][x].widget&&Spring.decorations[_b][x].isRequired()&&!Spring.decorations[_b][x].validate()){_a=false;}}}return _a;};Spring.AbstractElementDecoration=function(){};Spring.AbstractElementDecoration.prototype={elementId:"",widgetType:"",widgetModule:"",widget:null,widgetAttrs:{},apply:function(){},validate:function(){},isRequired:function(){},equals:function(_d){}};Spring.AbstractValidateAllDecoration=function(){};Spring.AbstractValidateAllDecoration.prototype={event:"",elementId:"",apply:function(){},cleanup:function(){},handleEvent:function(_e){},equals:function(_f){}};Spring.AbstractCommandLinkDecoration=function(){};Spring.AbstractCommandLinkDecoration.prototype={elementId:"",linkHtml:"",apply:function(){},submitFormFromLink:function(_10,_11,_12){},equals:function(_13){}};Spring.AbstractAjaxEventDecoration=function(){};Spring.AbstractAjaxEventDecoration.prototype={event:"",elementId:"",sourceId:"",formId:"",popup:false,params:{},apply:function(){},cleanup:function(){},submit:function(_14){},equals:function(_15){}};Spring.AbstractRemotingHandler=function(){};Spring.AbstractRemotingHandler.prototype={submitForm:function(_16,_17,_18){},getLinkedResource:function(_19,_1a,_1b){},getResource:function(_1c,_1d,_1e){},handleResponse:function(){},handleError:function(){}};

View File

@@ -15,7 +15,7 @@
*/
Spring = {};
Spring.decorations = [];
Spring.decorations = {};
Spring.decorations.applied = false;
@@ -25,16 +25,40 @@ Spring.initialize = function(){
};
Spring.addDecoration = function(/*Object*/decoration){
Spring.decorations.push(decoration);
//Spring.decorations.push(decoration);
if (!Spring.decorations[decoration.elementId]) {
Spring.decorations[decoration.elementId] = [];
Spring.decorations[decoration.elementId].push(decoration);
} else {
var replaced = false;
for(var i = 0; i<Spring.decorations[decoration.elementId].length; i++) {
var existingDecoration = Spring.decorations[decoration.elementId][i];
if(existingDecoration.equals(decoration)) {
if (existingDecoration.cleanup != undefined) {
existingDecoration.cleanup();
}
Spring.decorations[decoration.elementId][i] = decoration;
replaced=true;
break;
}
}
if (!replaced) {
Spring.decorations[decoration.elementId].push(decoration);
}
}
if(Spring.decorations.applied) {
decoration.apply();
}
};
Spring.applyDecorations = function(){
if (!Spring.decorations.applied) {
for (var x=0; x<Spring.decorations.length; x++) {
Spring.decorations[x].apply();
if (!Spring.decorations.applied) {
for (var elementId in Spring.decorations) {
for (var x = 0; x < Spring.decorations[elementId].length; x++) {
Spring.decorations[elementId][x].apply();
}
}
Spring.decorations.applied = true;
}
@@ -42,10 +66,11 @@ Spring.applyDecorations = function(){
Spring.validateAll = function(){
var valid = true;
for(x in Spring.decorations) {
if (Spring.decorations[x].widget &&
!Spring.decorations[x].validate()) {
valid = false;
for (var elementId in Spring.decorations) {
for (var x = 0; x < Spring.decorations[elementId].length; x++) {
if (Spring.decorations[elementId][x].widget && !Spring.decorations[elementId][x].validate()) {
valid = false;
}
}
}
return valid;
@@ -53,11 +78,13 @@ Spring.validateAll = function(){
Spring.validateRequired = function(){
var valid = true;
for(x in Spring.decorations) {
if(Spring.decorations[x].decorator &&
Spring.decorations[x].isRequired() &&
!Spring.decorations[x].validate())
valid = false;
for (var elementId in Spring.decorations) {
for (var x = 0; x < Spring.decorations[elementId].length; x++) {
if (Spring.decorations[elementId][x].widget && Spring.decorations[elementId][x].isRequired() &&
!Spring.decorations[elementId][x].validate()) {
valid = false;
}
}
}
return valid;
};
@@ -76,7 +103,9 @@ Spring.AbstractElementDecoration.prototype = {
validate : function(){},
isRequired : function(){}
isRequired : function(){},
equals : function(/*Object*/other){}
};
Spring.AbstractValidateAllDecoration = function(){};
@@ -90,7 +119,9 @@ Spring.AbstractValidateAllDecoration.prototype = {
cleanup : function(){},
handleEvent : function(event){}
handleEvent : function(event){},
equals : function(/*Object*/other){}
};
Spring.AbstractCommandLinkDecoration = function(){};
@@ -102,7 +133,9 @@ Spring.AbstractCommandLinkDecoration.prototype = {
apply : function(){},
submitFormFromLink : function(/*String*/ formId, /*String*/ sourceId, /*Array of name,value params*/ params){}
submitFormFromLink : function(/*String*/ formId, /*String*/ sourceId, /*Array of name,value params*/ params){},
equals : function(/*Object*/other){}
};
Spring.AbstractAjaxEventDecoration = function(){};
@@ -113,13 +146,16 @@ Spring.AbstractAjaxEventDecoration.prototype = {
elementId : "",
sourceId : "",
formId : "",
popup : false,
params : {},
apply : function(){},
cleanup : function(){},
submit : function(event){}
submit : function(event){},
equals : function(/*Object*/other){}
};
Spring.AbstractRemotingHandler = function(){};