(function(window)
{
var Gitana = window.Gitana;
Gitana.AbstractObject = Gitana.AbstractPersistable.extend(
/** @lends Gitana.AbstractObject.prototype */
{
/**
* @constructs
* @augments Gitana.AbstractPersistable
*
* @class Abstract base class for Gitana document objects.
*
* @param {Gitana} driver
* @param {Object} [object]
*/
constructor: function(driver, object)
{
this.__system = (function() {
var _system = new Gitana.SystemMetadata();
return function(system) {
if (!Gitana.isUndefined(system)) { _system.updateFrom(system); }
return _system;
};
})();
///////////////////////////////////////////////////////////////////////////////////////////////
//
// INSTANCE CHAINABLE METHODS
//
///////////////////////////////////////////////////////////////////////////////////////////////
/**
* Executes an HTTP delete for this object and continues the chain with the chainable.
*
* @param chainable
* @param uri
* @param params
*/
this.chainDelete = function(chainable, uri, params)
{
var self = this;
return this.subchain(chainable).then(function() {
var chain = this;
// allow for closures on uri for late resolution
if (Gitana.isFunction(uri)) {
uri = uri.call(self);
}
// delete
chain.getDriver().gitanaDelete(uri, params, function() {
chain.next();
}, function(http) {
self.httpError(http);
});
// NOTE: we return false to tell the chain that we'll manually call next()
return false;
});
};
/**
* Reloads this object from the server and then passes control to the chainable.
*
* @param uri
* @param params
*/
this.chainReload = function(chainable, uri, params)
{
var self = this;
return this.subchain(chainable).then(function() {
var chain = this;
// allow for closures on uri for late resolution
if (Gitana.isFunction(uri)) {
uri = uri.call(self);
}
// reload
chain.getDriver().gitanaGet(uri, params, {}, function(obj) {
chain.handleResponse(obj);
chain.next();
}, function(http) {
self.httpError(http);
});
// NOTE: we return false to tell the chain that we'll manually call next()
return false;
});
};
/**
* Executes an update (write + read) of this object and then passes control to the chainable.
*
* @param chainable
* @param uri
* @param params
*/
this.chainUpdate = function(chainable, uri, params)
{
var self = this;
return this.subchain(chainable).then(function() {
var chain = this;
// allow for closures on uri for late resolution
if (Gitana.isFunction(uri)) {
uri = uri.call(self);
}
// delete
chain.getDriver().gitanaPut(uri, params, chain, function() {
chain.getDriver().gitanaGet(uri, params, {}, function(obj) {
chain.handleResponse(obj);
chain.next();
}, function(http) {
self.httpError(http);
});
}, function(http) {
self.httpError(http);
});
// NOTE: we return false to tell the chain that we'll manually call next()
return false;
});
};
// finally chain to parent prototype
this.base(driver, object);
},
/**
* Override to include:
*
* __system
*
* @param otherObject
*/
chainCopyState: function(otherObject)
{
this.base(otherObject);
// include __system properties?
if (otherObject.__system) {
this.__system(otherObject.__system());
}
},
/**
* @EXTENSION_POINT
*/
getUri: function()
{
return null;
},
/**
* @abstract
*/
getType: function()
{
return null;
},
/**
* @abstract
*
* @returns {String} a string denoting a reference to this object.
*/
ref: function()
{
return null;
},
/**
* Hands back the URI of this object as referenced by the browser.
*/
getProxiedUri: function()
{
return this.getDriver().baseURL + this.getUri();
},
/**
* Get a json property
*
* @param key
*/
get: function(key)
{
return this[key];
},
/**
* Set a json property
*
* @param key
* @param value
*/
set: function(key ,value)
{
this[key] = value;
},
/**
* Hands back the ID ("_doc") of this object.
*
* @public
*
* @returns {String} id
*/
getId: function()
{
return this.get("_doc");
},
/**
* Hands back the system metadata for this object.
*
* @public
*
* @returns {Gitana.SystemMetadata} system metadata
*/
getSystemMetadata: function()
{
return this.__system();
},
/**
* The title for the object.
*
* @public
*
* @returns {String} the title
*/
getTitle: function()
{
return this.get("title");
},
/**
* The description for the object.
*
* @public
*
* @returns {String} the description
*/
getDescription: function()
{
return this.get("description");
},
// TODO: this is a temporary workaround at the moment
// it has to do all kinds of special treatment for _ variables because these variables are
// actually system managed but they're on the top level object.
//
// TODO:
// 1) gitana repo system managed properties should all be under _system
// 2) the system block should be pulled off the object on read and not required on write
/**
* Replaces all of the properties of this object with those of the given object.
* This method should be used to update the state of this object.
*
* Any functions from the incoming object will not be copied.
*
* @public
*
* @param object {Object} object containing the properties
*/
replacePropertiesWith: function(object)
{
// create a copy of the incoming object
var candidate = {};
Gitana.copyInto(candidate, object);
// we don't allow the following values to be replaced
var backups = {};
backups["_doc"] = this["_doc"];
delete candidate["_doc"];
backups["_type"] = this["_type"];
delete candidate["_type"];
backups["_qname"] = this["_qname"];
delete candidate["_qname"];
// remove our properties (not functions)
Gitana.deleteProperties(this, false);
// restore
this["_doc"] = backups["_doc"];
this["_type"] = backups["_type"];
this["_qname"] = backups["_qname"];
// copy in candidate properties
Gitana.copyInto(this, candidate);
},
/**
* @override
*/
handleSystemProperties: function(response)
{
this.base(response);
if (this["_system"])
{
// strip out system metadata
var json = this["_system"];
delete this["_system"];
// update system properties
this.__system().updateFrom(json);
}
},
/**
* Helper function to convert the object portion to JSON
*
* @param pretty
*/
stringify: function(pretty)
{
return Gitana.stringify(this, pretty);
},
/**
* Helper method that loads this object from another object of the same type.
*
* For example, loading a node from another loaded node.
*
* @param anotherObject
*/
loadFrom: function(anotherObject)
{
this.handleResponse(anotherObject);
}
});
})(window);