All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jbpm.designer.public.js.datamanager.js Maven / Gradle / Ivy

/**
 * @author martin.czuchra
 */

/*
 * Save and triple generation behaviour. Use this area to configure
 * data management to your needs.
 */
var USE_ASYNCHRONOUS_REQUESTS =		true;
var DISCARD_UNUSED_TRIPLES =			true;
var PREFER_SPANS_OVER_DIVS =			true;
var PREFER_TITLE_OVER_TEXTNODE =		false;
var RESOURCE_ID_PREFIX =				'resource';

var SHOW_DEBUG_ALERTS_WHEN_SAVING =	false;
var SHOW_EXTENDED_DEBUG_INFORMATION =	false;

/*
 * Back end specific workarounds.
 */

var USE_ARESS_WORKAROUNDS =		true;

/*
 * Data management constants. Do not change these, as they are used
 * both internally and externally to communicate on events and to identify
 * command object actions in triple production and embedding rules.
 */

// Resource constants
var RESOURCE_CREATED =			0x01;
var RESOURCE_REMOVED =			0x02;
var RESOURCE_SAVED =				0x04;
var RESOURCE_RELOADED =			0x08;
var RESOURCE_SYNCHRONIZED = 		0x10;

// Triple constants
var TRIPLE_REMOVE =	0x01;
var TRIPLE_ADD =		0x02;
var TRIPLE_RELOAD =	0x04;
var TRIPLE_SAVE =		0x08;

var PROCESSDATA_REF = 'processdata';

// HTTP status code constants
//
//// 2xx
//const 200_OK =			'Ok';
//const 201_CREATED =		'Created';
//const 202_ACCEPTED =		'Accepted';
//const 204_NO_CONTENT =	'No Content';
//
//// 3xx
//const 301_MOVED_PERMANENTLY =	'Moved Permanently';
//const 302_MOVED_TEMPORARILY =	'Moved Temporarily';
//const 304_NOT_MODIFIED =		'Not Modified';
//
//// 4xx
//const 400_BAD_REQUEST =	'Bad Request';
//const 401_UNAUTHORIZED =	'Unauthorized';
//const 403_FORBIDDEN =		'Forbidden';
//const 404_NOT_FOUND =		'Not Found';
//const 409_CONFLICT =		'Conflict';
//
//// 5xx
//const 500_INTERNAL_SERVER_ERROR =		'Internal Server Error';
//const 501_NOT_IMPLEMENTED =			'Not Implemented';
//const 502_BAD_GATEWAY =				'Bad Gateway';
//const 503_SERVICE_UNAVAILABLE =		'Service Unavailable';
//
/**
 * The Data Management object. Use this one when interacting with page internal
 * data. Initialize data management by DataManager.init();
 * @class DataManager
 */
var DataManager = {
	
	/**
	 * The init method should be called once in the DataManagers lifetime.
	 * It causes the DataManager to initialize itself, the erdf parser, do all
	 * neccessary registrations and configurations, to run the parser and
	 * from then on deliver all resulting triples.
	 * No parameters needed are needed in a call to this method.
	 */
	init: function() {
		ERDF.init(DataManager._registerTriple);
		DataManager.__synclocal();
	},
	
	/**
	 * This triple array is meant to be the whole knowledge of the DataManager.
	 */
	_triples: [],
	
	/**
	 * This method is meant for callback from erdf parsing. It is not to be
	 * used in another way than to add triples to the triple store.
	 * @param {Object} triple the triple to add to the triple store.
	 */
	_registerTriple: function(triple) {
		DataManager._triples.push(triple)
	},
	
	/**
	 * The __synclocal method is for internal usage only.
	 * It performs synchronization with the local document, that is, the triple
	 * store is adjustet to the content of the document, which could have been
	 * changed by any other applications running on the same page.
	 */
	__synclocal: function() {
		DataManager._triples = [];
		ERDF.run();
	},
	
	/**
	 * Makes the shape passed into this method synchronize itself with the DOM.
	 * This method returns the shapes resource object for further manipulation.
	 * @param {Object} shape
	 */
	__synchronizeShape: function(shape) {

		var r = ResourceManager.getResource(shape.resourceId);
		var serialize = shape.serialize();

		// store all serialize values
		serialize.each( function(ser) {
			
			var resource = (ser.type == 'resource');
			var _triple = new ERDF.Triple(
				new ERDF.Resource(shape.resourceId),
				{prefix: ser.prefix, name: ser.name},
				resource ?
					new ERDF.Resource(ser.value) :
					new ERDF.Literal(ser.value)
			);
			DataManager.setObject(_triple);
		});
		
		return r;
	},

	__storeShape: function(shape) {
		
		// first synchronize the shape,
		var resource = DataManager.__synchronizeShape(shape);
		
		// then save the synchronized dom.
		resource.save();
	},
		
	__forceExistance: function(shape) {
		
		if(!$(shape.resourceId)) {
			
			if(!$$('.' + PROCESSDATA_REF)[0])
				DataManager.graft(XMLNS.XHTML,
					document.getElementsByTagNameNS(XMLNS.XHTML, 'body').item(0), ['div', {'class': PROCESSDATA_REF, 'style':'display:none;'}]);
				
			// object is literal
			DataManager.graft(XMLNS.XHTML,
				$$('.' + PROCESSDATA_REF)[0], [
				
				'div', {
                    'id': shape.resourceId,
                    //This should be done in a more dynamic way!!!!!
                    'class': (shape instanceof ORYX.Core.Canvas) ? "-oryx-canvas" : undefined
                }
			]);
			
		} else {
			var resource = $(shape.resourceId)
			var children = $A(resource.childNodes)
			children.each( function(child) {
				resource.removeChild(child);
			});
		};
	},
	
	__persistShape: function(shape) {

		// a shape serialization.
		var shapeData = shape.serialize();
		
		// initialize a triple array and construct a shape resource
		// to be used in triple generation.
		var triplesArray = [];
		var shapeResource = new ERDF.Resource(shape.resourceId);

		// remove all triples for this particular shape's resource
		DataManager.removeTriples( DataManager.query(
			shapeResource, undefined, undefined));

		// for each data set in the shape's serialization
		shapeData.each( function(data) {

			// construct a triple's value
			var value = (data.type == 'resource') ?
				new ERDF.Resource(data.value) :
				new ERDF.Literal(data.value);

			// construct triple and add it to the DOM.
			DataManager.addTriple( new ERDF.Triple(
				shapeResource,
				{prefix: data.prefix, name: data.name},
				value
			));
		});
	},
	
	__persistDOM: function(facade) {

		// getChildShapes gets all shapes (nodes AND edges), deep flag
		// makes it return a flattened child hierarchy.
		
		var canvas = facade.getCanvas();
		var shapes = canvas.getChildShapes(true);
		var result = '';
		
		// persist all shapes.
		shapes.each( function(shape) {
			DataManager.__forceExistance(shape);
		});
		//DataManager.__synclocal();
		
		DataManager.__renderCanvas(facade);
		result += DataManager.serialize(
				$(ERDF.__stripHashes(facade.getCanvas().resourceId)), true);
				
		shapes.each( function(shape) {
			
			DataManager.__persistShape(shape);
			result += DataManager.serialize(
				$(ERDF.__stripHashes(shape.resourceId)), true);
		});
		
		//result += DataManager.__renderCanvas(facade);
		
		return result;
	},

	__renderCanvas: function(facade) {

		var canvas = facade.getCanvas();
		var stencilSets = facade.getStencilSets();
		var shapes = canvas.getChildShapes(true);
		
		DataManager.__forceExistance(canvas);
		
		DataManager.__persistShape(canvas);
		
		var shapeResource = new ERDF.Resource(canvas.resourceId);

		// remove all triples for this particular shape's resource
		DataManager.removeTriples( DataManager.query(
			shapeResource, undefined, undefined));

		DataManager.addTriple( new ERDF.Triple(
			shapeResource,
			{prefix: "oryx", name: "mode"},
			new ERDF.Literal("writable")
		));

		DataManager.addTriple( new ERDF.Triple(
			shapeResource,
			{prefix: "oryx", name: "mode"},
			new ERDF.Literal("fullscreen")
		));

		stencilSets.values().each(function(stencilset) {
			DataManager.addTriple( new ERDF.Triple(
				shapeResource,
				{prefix: "oryx", name: "stencilset"},
				new ERDF.Resource(stencilset.source().replace(/&/g, "%26"))
			));
			
			DataManager.addTriple( new ERDF.Triple(
				shapeResource,
				{prefix: "oryx", name: "ssnamespace"},
				new ERDF.Resource(stencilset.namespace())
			));
			
			stencilset.extensions().keys().each(function(extension) {
				DataManager.addTriple( new ERDF.Triple(
					shapeResource,
					{prefix: "oryx", name: "ssextension"},
					new ERDF.Literal(extension)
				));
			});
		});
						
		shapes.each(function(shape) {
			DataManager.addTriple( new ERDF.Triple(
				shapeResource,
				{prefix: "oryx", name: "render"},
				new ERDF.Resource("#" + shape.resourceId)
			));
		});
	},

	__counter: 0,
	__provideId: function() {
		
		while($(RESOURCE_ID_PREFIX+DataManager.__counter))
			DataManager.__counter++;
			
		return RESOURCE_ID_PREFIX+DataManager.__counter;
	},
		
	serializeDOM: function(facade) {
		
		return DataManager.__persistDOM(facade);
	},
	
	syncGlobal: function(facade) {
		
		return DataManager.__syncglobal(facade);
	},
	
	/**
	 * This method is used to synchronize local DOM with remote resources.
	 * Local changes are commited to the server, and remote changes are
	 * performed to the local document.
	 * @param {Object} facade The facade of the editor that holds certain
	 * resource representations as shapes.
	 */
	__syncglobal: function(facade) {

		// getChildShapes gets all shapes (nodes AND edges), deep flag
		// makes it return a flattened child hierarchy.
		
		var canvas = facade.getCanvas();
		var shapes = canvas.getChildShapes(true);

		// create dummy resource representations in the dom
		// for all shapes that were newly created.

		shapes.select( function(shape) {

			// select shapes without resource id.

			return !($(shape.resourceId));

		}).each( function(shape) {

			// create new resources for them.
			if(USE_ARESS_WORKAROUNDS) {
				
				/*
				 * This is a workaround due to a bug in aress. Resources are
				 * ignoring changes to raziel:type property once they are
				 * created. As long as this is not fixed, the resource is now
				 * being created using a randomly guessed id, this temporary id
				 * is then used in references and the appropriate div is being
				 * populated with properties.
				 * 
				 * AFTER THIS PHASE THE DATA IS INCONSISTENT AS REFERENCES POINT
				 * TO IDS THAT ARE UNKNOWN TO THE BACK END.
				 * 
				 * After the resource is actually created in aress, it gets an id
				 * that is persistent. All shapes are then being populated with the
				 * correct id references and stored on the server.
				 * 
				 * AFTER THE SAVE PROCESS HAS RETURNED, THE DATA IS CONSISTENT
				 * REGARDING THE ID REFERENCES AGAIN.
				 */
				
				var razielType = shape.properties['raziel-type'];
				
				var div = '
' + ''+razielType+'
'; var r = ResourceManager.__createResource(div); shape.resourceId = r.id(); } else { var r = ResourceManager.__createResource(); shape.resourceId = r.id(); } }); shapes.each( function(shape) { // store all shapes. DataManager.__storeShape(shape); }); }, /** * This method serializes a single div into a string that satisfies the * client/server communication protocol. It ingnores all elements that have * an attribute named class that includes 'transient'. * @param {Object} node the element to serialize. * @param {Object} preserveNamespace whether to preserve the parent's * namespace. If you are not sure about namespaces, provide * just the element to be serialized. */ serialize: function(node, preserveNamespace) { if (node.nodeType == node.ELEMENT_NODE) { // serialize an element node. var children = $A(node.childNodes); var attributes = $A(node.attributes); var clazz = new String(node.getAttribute('class')); var ignore = clazz.split(' ').member('transient'); // ignore transients. if(ignore) return ''; // start serialization. var result = '<' + node.nodeName; // preserve namespace? if(!preserveNamespace) result += ' xmlns="' + (node.namespaceURI ? node.namespaceURI : XMLNS.XHTML) + '" xmlns:oryx="http://oryx-editor.org"'; // add all attributes. attributes.each(function(attribute) { var attrValue = attribute.nodeValue; if (attrValue.indexOf('&') !== -1 || attrValue.indexOf('>') !== -1 || attrValue.indexOf('<') !== -1 || attrValue.indexOf('"') !== -1) { attrValue = Ext.util.Format.htmlEncode(attrValue); } result += ' ' + attribute.nodeName + '="' + attrValue + '"'; }); // close if no children. if(children.length == 0) result += '/>'; else { // serialize all children. result += '>'; children.each(function(_node) { result += DataManager.serialize(_node, true)}); result += '' } return result; } else if (node.nodeType == node.TEXT_NODE) { // serialize a text node. return node.nodeValue; } //TODO serialize cdata areas also. //TODO work on namespace awareness. }, addTriple: function(triple) { // assert the subject is a resource if(!triple.subject.type == ERDF.LITERAL) throw 'Cannot add the triple ' + triple.toString() + ' because the subject is not a resource.' // get the element which represents this triple's subject. var elementId = ERDF.__stripHashes(triple.subject.value); var element = $(elementId); // assert the subject is inside this document. if(!element) throw 'Cannot add the triple ' + triple.toString() + ' because the subject "'+elementId+'" is not in the document.'; if(triple.object.type == ERDF.LITERAL) // object is literal DataManager.graft(XMLNS.XHTML, element, [ 'span', {'class': (triple.predicate.prefix + "-" + triple.predicate.name)}, triple.object.value.escapeHTML() ]); else { // object is resource DataManager.graft(XMLNS.XHTML, element, [ 'a', {'rel': (triple.predicate.prefix + "-" + triple.predicate.name), 'href': triple.object.value} ]); } return true; }, removeTriples: function(triples) { // alert('Removing ' +triples.length+' triples.'); // from all the triples select those ... var removed = triples.select( function(triple) { // TODO remove also from triple store. // ... that were actually removed. return DataManager.__removeTriple(triple); }); // sync and return removed triples. // DataManager.__synclocal(); return removed; }, removeTriple: function(triple) { // remember whether the triple was actually removed. var result = DataManager.__removeTriple(triple); // sync and return removed triples. // DataManager.__synclocal(); return result; }, __removeTriple: function(triple) { // assert the subject is a resource if(!triple.subject.type == ERDF.LITERAL) throw 'Cannot remove the triple ' + triple.toString() + ' because the subject is not a resource.'; // get the element which represents this triple's subject. var elementId = ERDF.__stripHashes(triple.subject.value); var element = $(elementId); // assert the subject is inside this document. if(!element) throw 'Cannot remove the triple ' + triple.toString() + ' because the subject is not in the document.'; if(triple.object.type == ERDF.LITERAL) { // continue searching actively for the triple. var result = DataManager.__removeTripleRecursively(triple, element); return result; } }, __removeTripleRecursively: function(triple, continueFrom) { // return when this node is not an element node. if(continueFrom.nodeType != continueFrom.ELEMENT_NODE) return false; var classes = new String(continueFrom.getAttribute('class')); var children = $A(continueFrom.childNodes); if(classes.include(triple.predicate.prefix + '-' + triple.predicate.name)) { var content = continueFrom.textContent; if( (triple.object.type == ERDF.LITERAL) && (triple.object.value == content)) continueFrom.parentNode.removeChild(continueFrom); return true; } else { children.each(function(_node) { DataManager.__removeTripleRecursively(triple, _node)}); return false; } }, /** * graft() function * Originally by Sean M. Burke from interglacial.com, altered for usage with * SVG and namespace (xmlns) support. Be sure you understand xmlns before * using this funtion, as it creates all grafted elements in the xmlns * provided by you and all element's attribures in default xmlns. If you * need to graft elements in a certain xmlns and wish to assign attributes * in both that and another xmlns, you will need to do stepwise grafting, * adding non-default attributes yourself or you'll have to enhance this * function. Latter, I would appreciate: martin�apfelfabrik.de * @param {Object} namespace The namespace in which * elements should be grafted. * @param {Object} parent The element that should contain the grafted * structure after the function returned. * @param {Object} t the crafting structure. * @param {Object} doc the document in which grafting is performed. */ graft: function(namespace, parent, t, doc) { doc = (doc || (parent && parent.ownerDocument) || document); var e; if(t === undefined) { echo( "Can't graft an undefined value"); } else if(t.constructor == String) { e = doc.createTextNode( t ); } else { for(var i = 0; i < t.length; i++) { if( i === 0 && t[i].constructor == String ) { var snared = t[i].match( /^([a-z][a-z0-9]*)\.([^\s\.]+)$/i ); if( snared ) { e = doc.createElementNS(namespace, snared[1]); e.setAttributeNS(null, 'class', snared[2] ); continue; } snared = t[i].match( /^([a-z][a-z0-9]*)$/i ); if( snared ) { e = doc.createElementNS(namespace, snared[1]); // but no class continue; } // Otherwise: e = doc.createElementNS(namespace, "span"); e.setAttribute(null, "class", "namelessFromLOL" ); } if( t[i] === undefined ) { echo("Can't graft an undefined value in a list!"); } else if( t[i].constructor == String || t[i].constructor == Array) { this.graft(namespace, e, t[i], doc ); } else if( t[i].constructor == Number ) { this.graft(namespace, e, t[i].toString(), doc ); } else if( t[i].constructor == Object ) { // hash's properties => element's attributes for(var k in t[i]) { e.setAttributeNS(null, k, t[i][k] ); } } else if( t[i].constructor == Boolean ) { this.graft(namespace, e, t[i] ? 'true' : 'false', doc ); } else throw "Object " + t[i] + " is inscrutable as an graft arglet."; } } if(parent) parent.appendChild(e); return Element.extend(e); // return the topmost created node }, setObject: function(triple) { /** * Erwartungen von Arvid an diese Funktion: * - Es existiert genau ein triple mit dem Subjekt und Praedikat, * das uebergeben wurde, und dieses haelt uebergebenes Objekt. */ var triples = DataManager.query( triple.subject, triple.predicate, undefined ); DataManager.removeTriples(triples); DataManager.addTriple(triple); return true; }, query: function(subject, predicate, object) { /* * Typical triple. * {value: subject, type: subjectType}, * {prefix: schema.prefix, name: property}, * {value: object, type: objectType}); */ return DataManager._triples.select(function(triple) { var select = ((subject) ? (triple.subject.type == subject.type) && (triple.subject.value == subject.value) : true); if(predicate) { select = select && ((predicate.prefix) ? (triple.predicate.prefix == predicate.prefix) : true); select = select && ((predicate.name) ? (triple.predicate.name == predicate.name) : true); } select = select && ((object) ? (triple.object.type == object.type) && (triple.object.value == object.value) : true); return select; }); } } Kickstart.register(DataManager.init); function assert(expr, m) { if(!expr) throw m; }; function DMCommand(action, triple) { // store action and triple. this.action = action; this.triple = triple; this.toString = function() { return 'Command('+action+', '+triple+')'; }; } function DMCommandHandler(nextHandler) { /** * Private method to set the next handler in the Chain of Responsibility * (see http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern for * details). * @param {DMCommandHandler} handler The handler that is next in the chain. */ this.__setNext = function(handler) { var _next = this.__next; this.__next = nextHandler; return _next ? _next : true; }; this.__setNext(nextHandler); /** * Invokes the next handler. If there is no next handler, this method * returns false, otherwise it forwards the result of the handling. * @param {Object} command The command object to be processed. */ this.__invokeNext = function(command) { return this.__next ? this.__next.handle(command) : false; }; /** * Handles a command. The abstract method process() is called with the * command object that has been passed. If the process method catches the * command (returns true on completion), the handle() method returns true. * If the process() method doesn't catch the command, the next handler will * be invoked. * @param {Object} command The command object to be processed. */ this.handle = function(command) { return this.process(command) ? true : this.__invokeNext(command); } /** * Empty process() method returning false. If javascript knew abstract * class members, this would be one. * @param {Object} command The command object to process. */ this.process = function(command) { return false; }; }; /** * This Handler manages the addition and the removal of meta elements in the * head of the document. * @param {DMCommandHandler} next The handler that is next in the chain. */ function MetaTagHandler(next) { DMCommandHandler.apply(this, [next]); this.process = function(command) { with(command.triple) { /* assert prerequisites */ if( !( (subject instanceof ERDF.Resource) && (subject.isCurrentDocument()) && (object instanceof ERDF.Literal) )) return false; } }; }; var chain = new MetaTagHandler(); var command = new DMCommand(TRIPLE_ADD, new ERDF.Triple( new ERDF.Resource(''), 'rdf:tool', new ERDF.Literal('') )); /* if(chain.handle(command)) alert('Handled!'); */ ResourceManager = { __corrupt: false, __latelyCreatedResource: undefined, __listeners: $H(), __token: 1, addListener: function(listener, mask) { if(!(listener instanceof Function)) throw 'Resource event listener is not a function!'; if(!(mask)) throw 'Invalid mask for resource event listener registration.'; // construct controller and token. var controller = {listener: listener, mask: mask}; var token = ResourceManager.__token++; // add new listener. ResourceManager.__listeners[token] = controller; // return the token generated. return token; }, removeListener: function(token) { // remove the listener with the token and return it. return ResourceManager.__listners.remove(token); }, __Event: function(action, resourceId) { this.action = action; this.resourceId = resourceId; }, __dispatchEvent: function(event) { // get all listeners. for each listener, ... ResourceManager.__listeners.values().each(function(controller) { // .. if listener subscribed to this type of event ... if(event.action & controller.mask) return controller.listener(event); }); }, getResource: function(id) { // get all possible resources for this. id = ERDF.__stripHashes(id); var resources = DataManager.query( new ERDF.Resource('#'+id), {prefix: 'raziel', name: 'entry'}, undefined ); // check for consistency. if((resources.length == 1) && (resources[0].object.isResource())) { var entryUrl = resources[0].object.value; return new ResourceManager.__Resource(id, entryUrl); } // else throw an error message. throw ('Resource with id ' +id+ ' not recognized as such. ' + ((resources.length > 1) ? ' There is more than one raziel:entry URL.' : ' There is no raziel:entry URL.')); return false; }, __createResource: function(alternativeDiv) { var collectionUrls = DataManager.query( new ERDF.Resource(''), // TODO This will become raziel:collection in near future. {prefix: 'raziel', name: 'collection'}, undefined ); // check for consistency. if( (collectionUrls.length == 1) && (collectionUrls[0].object.isResource())) { // get the collection url. var collectionUrl = collectionUrls[0].object.value; var resource = undefined; // if there is an old id, serialize the dummy div from there, // otherwise create a dummy div on the fly. var serialization = alternativeDiv? alternativeDiv : '
'; ResourceManager.__request( 'POST', collectionUrl, serialization, // on success function() { // get div and id that have been generated by the server. var response = (this.responseXML); var div = response.childNodes[0]; var id = div.getAttribute('id'); // store div in DOM if(!$$('.' + PROCESSDATA_REF)[0]) DataManager.graft(XMLNS.XHTML, document.getElementsByTagNameNS(XMLNS.XHTML, 'body').item(0), ['div', {'class': PROCESSDATA_REF, 'style':'display:none;'}]); $$('.' + PROCESSDATA_REF)[0].appendChild(div.cloneNode(true)); // parse local erdf data once more. DataManager.__synclocal(); // get new resource object. resource = new ResourceManager.getResource(id); // set up an action informing of the creation. ResourceManager.__resourceActionSucceeded( this, RESOURCE_CREATED, undefined); }, function() { ResourceManager.__resourceActionFailed( this, RESOURCE_CREATED, undefined);}, false ); return resource; } // else throw 'Could not create resource! raziel:collection URL is missing!'; return false; }, __Resource: function(id, url) { this.__id = id; this.__url = url; /* * Process URL is no longer needed to refer to the shape element on the * canvas. AReSS uses the id's to gather information on fireing * behaviour now. */ // // find the process url. // var processUrl = undefined; // // var urls = DataManager.query( // new ERDF.Resource('#'+this.__id), // {prefix: 'raziel', name: 'process'}, // undefined // ); // // if(urls.length == 0) { throw 'The resource with the id ' +id+ ' has no process url.'}; // // urls.each( function(triple) { // // // if there are more urls, use the last one. // processUrl = triple.object.value; // }); // // this.__processUrl = processUrl; // // // convenience function for getting the process url. // this.processUrl = function() { // return this.__processUrl; // } // convenience finction for getting the id. this.id = function() { return this.__id; } // convenience finction for getting the entry url. this.url = function() { return this.__url; } this.reload = function() { var _url = this.__url; var _id = this.__id; ResourceManager.__request( 'GET', _url, null, function() { ResourceManager.__resourceActionSucceeded( this, RESOURCE_RELOADED, _id); }, function() { ResourceManager.__resourceActionFailed( this, RESURCE_RELOADED, _id); }, USE_ASYNCHRONOUS_REQUESTS ); }; this.save = function(synchronize) { var _url = this.__url; var _id = this.__id; data = DataManager.serialize($(_id)); ResourceManager.__request( 'PUT', _url, data, function() { ResourceManager.__resourceActionSucceeded( this, synchronize ? RESOURCE_SAVED | RESOURCE_SYNCHRONIZED : RESOURCE_SAVED, _id); }, function() { ResourceManager.__resourceActionFailed( this, synchronize ? RESOURCE_SAVED | RESOURCE_SYNCHRONIZED : RESOURCE.SAVED, _id); }, USE_ASYNCHRONOUS_REQUESTS ); }; this.remove = function() { var _url = this.__url; var _id = this.__id; ResourceManager.__request( 'DELETE', _url, null, function() { ResourceManager.__resourceActionSucceeded( this, RESOURCE_REMOVED, _id); }, function() { ResourceManager.__resourceActionFailed( this, RESOURCE_REMOVED, _id);}, USE_ASYNCHRONOUS_REQUESTS ); }; }, request: function(url, requestOptions) { var options = { method: 'get', asynchronous: true, parameters: {} }; Object.extend(options, requestOptions || {}); var params = Hash.toQueryString(options.parameters); if (params) url += (url.include('?') ? '&' : '?') + params; return ResourceManager.__request( options.method, url, options.data, (options.onSuccess instanceof Function ? function() { options.onSuccess(this); } : undefined ), (options.onFailure instanceof Function ? function() { options.onFailure(this); } : undefined ), options.asynchronous && USE_ASYNCHRONOUS_REQUESTS, options.headers); }, __request: function(method, url, data, success, error, async, headers) { // get a request object var httpRequest = Try.these( /* do the Mozilla/Safari/Opera stuff */ function() { return new XMLHttpRequest(); }, /* do the IE stuff */ function() { return new ActiveXObject("Msxml2.XMLHTTP"); }, function() { return new ActiveXObject("Microsoft.XMLHTTP") } ); // if there is no request object ... if (!httpRequest) { if(!this.__corrupt) throw 'This browser does not provide any AJAX functionality. You will not be able to use the software provided with the page you are viewing. Please consider installing appropriate extensions.'; this.__corrupt = true; return false; } if(success instanceof Function) httpRequest.onload = success; if(error instanceof Function) { httpRequest.onerror = error; } var h = $H(headers) h.keys().each(function(key) { httpRequest.setRequestHeader(key, h[key]); }); try { if(SHOW_DEBUG_ALERTS_WHEN_SAVING) alert(method + ' ' + url + '\n' + SHOW_EXTENDED_DEBUG_INFORMATION ? data : ''); // TODO Remove synchronous calls to the server as soon as xenodot // handles asynchronous requests without failure. httpRequest.open(method, url, !async?false:true); httpRequest.send(data); } catch(e) { return false; } return true; }, __resourceActionSucceeded: function(transport, action, id) { var status = transport.status; var response = transport.responseText; if(SHOW_DEBUG_ALERTS_WHEN_SAVING) alert(status + ' ' + url + '\n' + SHOW_EXTENDED_DEBUG_INFORMATION ? data : ''); // if the status code is not in 2xx, throw an error. if(status >= 300) throw 'The server responded with an error: ' + status + '\n' + (SHOW_EXTENDED_DEBUG_INFORMATION ? + data : 'If you need additional information here, including the data sent by the server, consider setting SHOW_EXTENDED_DEBUG_INFORMATION to true.'); switch(action) { case RESOURCE_REMOVED: // get div and id var response = (transport.responseXML); var div = response.childNodes[0]; var id = div.getAttribute('id'); // remove the resource from DOM var localDiv = document.getElementById(id); localDiv.parentNode.removeChild(localDiv); break; case RESOURCE_CREATED: // nothing remains to be done. break; case RESOURCE_SAVED | RESOURCE_SYNCHRONIZED: DataManager.__synclocal(); case RESOURCE_SAVED: // nothing remains to be done. break; case RESOURCE_RELOADED: // get div and id var response = (transport.responseXML); var div = response.childNodes[0]; var id = div.getAttribute('id'); // remove the local resource representation from DOM var localDiv = document.getElementById(id) localDiv.parentNode.removeChild(localDiv); // store div in DOM if(!$$(PROCESSDATA_REF)[0]) DataManager.graft(XMLNS.XHTML, document.getElementsByTagNameNS(XMLNS.XHTML, 'body').item(0), ['div', {'class': PROCESSDATA_REF, 'style':'display:none;'}]); $$(PROCESSDATA_REF)[0].appendChild(div.cloneNode(true)); DataManager.__synclocal(); break; default: DataManager.__synclocal(); } // dispatch to all listeners ... ResourceManager.__dispatchEvent( // ... an event describing the change that happened here. new ResourceManager.__Event(action, id) ); }, __resourceActionFailed: function(transport, action, id) { throw "Fatal: Resource action failed. There is something horribly " + "wrong with either the server, the transport protocol or your " + "online status. Sure you're online?"; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy