blob: c7ea23fb5f71601231897ab2b1ecbb74bcdd8088 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012, 2013 EclipseSource and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* EclipseSource - initial API and implementation
******************************************************************************/
(function(){
/**
* @public
* @since 2.0
* @namespace Holds all public API of the RAP WebClient.
*/
rap = {
/**
* @description Registers a RAP protocol type handler for a specific type of client objects.
* The handler is used by the protocol message processor to process operations that target
* any client object of this type. Example:
*
* @example
* rap.registerTypeHandler( "project.MyWidget", {
* factory : function( properties ) {
* return new MyWidget();
* },
* properties : [ "propA", "propB" ]
* } );
*
* @param {string} type
*
* @param {Object} handler The handler object.
*
* @param {Function} handler.factory Called for create operations.
* Is given a properties object as the first argument, which may contain any number for
* properties/fields set by the server. Has to return a "client object" representing an instance
* of the type of this handler. <em>Required for all type handler</em>.
*
* @param {string} handler.destructor Name of the method that is called for destroy operations.
* If the string is given, the client object <em>has</em> to implement a method with the given
* name. <em>Optional</em>
*
* @param {string[]} handler.properties List of properties supported by this type.
* The order in the list controls the order in which the properties are applied by the message
* processor. The client object <em>has</em> to implement a setter for each supported property.
* For example, if the property is "bounds", <code>setBounds</code> will be called on the client
* object. Properties given by the server that are not in this list will be ignored. (One
* exception is the factory, which gets an object with <i>all</i> properties set by the server
* at that time.) If the property changes on the client, {@link RemoteObject#set} can be
* used to synchronize the value with the server.
* <em>Optional.</em>
*
* @param {string[]} handler.methods List of methods supported by this type.
* The order in the list is meaningless, "call" operations are processed in the order in which
* they are given by the server. The client object has to implement a method of the same name.
* One argument will be given, which is a properties object with any number of properties/fields.
* A "call" operation given by the server for a method that is not in this list will be ignored.
* <em>Optional.</em>
*
* @param {string[]} handler.events List of event types supported by this type.
* The server may instruct the client object with "listen" operations to start or stop sending
* notifications when events of he given event type occur. Notifications may and can only be
* sent for types that are given in this list and are listend to by the server. See also
* {@link RemoteObject#notify}.
* <em>Optional.</em>
*/
registerTypeHandler : function( type, handler ) {
handler.isPublic = true;
rwt.remote.HandlerRegistry.add( type, handler );
},
/**
* @description Returns the client object associated with the given id.
* If there is no object registered for the given id, null is returned.
* For RAP internal objects (e.g. RWT widgets) a wrapper is returned instead of the real object.
* @see Composite
* @param {string} id The protocol id for a client object.
* @returns {Object} The client object associated with the id.
*/
getObject : function( id ) {
var entry = rwt.remote.ObjectRegistry.getEntry( id );
var result;
if( entry && entry.handler.isPublic ) {
result = entry.object;
} else {
result = this._.getWrapperFor( entry.object );
}
return result;
},
/**
* @description Returns an instance of {@link RemoteObject} for the given client object.
* A client object is any object that was created by an type handler factory method.
* Multiple calls for the same object will return the same RemoteObject
* instance.
* @see rap.registerTypeHandler
* @param {Object} object The client object.
* @returns {RemoteObject}
*/
getRemoteObject : function( object ) {
return rwt.remote.Connection.getInstance().getRemoteObject( object );
},
/**
* @description Register the function as a listener of the given type. Registering unkown
* types throws an Error.
* @param {string} type The type of the event (e.g. "send").
* @param {Function} listener The callback function. It is executed in global context.
*/
on : function( type, handler ) {
if( this._.events[ type ] ) {
if( this._.events[ type ].indexOf( handler ) === -1 ) {
this._.events[ type ].push( handler );
}
} else {
throw new Error( "Unkown type " + type );
}
},
/**
* @description De-register the function as a listener of the given type.
* @param {string} type The type of the event
* @param {Function} listener The callback function
*/
off : function( type, handler ) {
if( this._.events[ type ] ) {
var index = this._.events[ type ].indexOf( handler );
rwt.util.Arrays.removeAt( this._.events[ type ], index );
}
},
_ : {
wrapperMap : {},
events : {
/**
* @event
* @description Sent right before a message is send to the server.
* @name rap#send
*/
"render" : [],
/**
* @event
* @description Sent after a message has been processed.
* @name rap#render
*/
"send" : []
},
notify : function( type ) {
var listener = this.events[ type ];
for( var i = 0; i < listener.length; i++ ) {
listener[ i ]();
}
},
getWrapperFor : function( obj ) {
var result = null;
if( obj instanceof Object ) {
var hash = rwt.qx.Object.toHashCode( obj );
if( this.wrapperMap[ hash ] == null ) {
if( obj instanceof rwt.widgets.Composite ) {
result = new CompositeWrapper( obj );
} else {
result = {};
}
this.wrapperMap[ hash ] = result;
}
result = this.wrapperMap[ hash ];
}
return result;
},
removeWrapper : function( obj ) {
if( obj instanceof Object ) {
var hash = rwt.qx.Object.toHashCode( obj );
delete this.wrapperMap[ hash ];
}
}
}
};
// TODO [tb] : propper class/namespace for this event? (Control? SWT? RWT? rap? rwt.widget?)
/**
* @event
* @description Sent when widget changes size.
* @name Composite#Resize
*/
function convertEventType( type ) {
var result;
if( type === "Resize" ) {
result = "clientAreaChanged"; // works only for Composite
} else {
throw new Error( "Unkown event type " + type );
}
return result;
}
/**
* @private
* @class Represents RWT Composite widgets
* @description This constructor is not available in the global namespace. Instances can only
* be obtained from {@link rap.getObject}.
* @name Composite
* @since 2.0
*/
// TODO [tb] : where to put this? rap.CompositeWrapper? rwt.widget.Composite? in CompositeHandler?
function CompositeWrapper( widget ) {
var children = null;
if( !widget.isCreated() ) {
children = [];
widget.addEventListener( "create", function() {
for( var i = 0; i < children.length; i++ ) {
widget._getTargetNode().appendChild( children[ i ] );
}
widget.removeEventListener( "create", arguments.callee );
children = null;
} );
}
/**
* @name append
* @function
* @memberOf Composite#
* @description Adds a given HTMLElement to the Composite.
* @param {HTMLElement} childElement The element to append.
*/
this.append = function( childElement ) {
if( children ) {
children.push( childElement );
} else {
widget._getTargetNode().appendChild( childElement );
}
};
/**
* @name getClientArea
* @function
* @memberOf Composite#
* @description Returns the client Area of the Composite
* @returns {int[]} the client area as array [ x, y, width, height ]
*/
this.getClientArea = function() {
return widget.getClientArea();
};
/**
* @name addListener
* @function
* @memberOf Composite#
* @description Register the function as a listener of the given type
* @param {string} type The type of the event (e.g. "Resize").
* @param {Function} listener The callback function. It is executed in global context.
*/
this.addListener = function( type, listener ) {
widget.addEventListener( convertEventType( type ), listener, window );
};
/**
* @name removeListener
* @function
* @memberOf Composite#
* @description De-register the function as a listener of the given type
* @param {string} type The type of the event (e.g. "Resize").
* @param {Function} listener The callback function
*/
this.removeListener = function( type, listener ) {
widget.removeEventListener( convertEventType( type ), listener, window );
};
}
}());