4 * Nokia Web Runtime Service API emulation
7 * Copyright 2009 Nokia Corporation. All rights reserved.
12 * device object. entry point to device service API (SAPI)
16 * device API public method
19 * @param {string} provider Name of service provider, eg, "Service.Calendar"
20 * @param {string} Interface Name of interface, eg, "IDataSource"
21 * @return {Object} service object
23 getServiceObject: function(provider, Interface){
25 if (!device.implementation.context)
26 throw 'device implementation object not instantiated!'
28 if (device.implementation.options.enabled)
29 return device.implementation.getInterface(provider, Interface);
31 device.implementation.context.notify('device SAPI is disabled.');
32 throw 'device not defined!';
40 * implementation of device emulation mode
42 * @param {String} version - version number (default: current version)
43 * @return {Object} returns new implementation context object
46 device.implementation = function(version){
48 this.version = version || '';
50 // set context to current object
51 device.implementation.context = this;
53 var libpath = 'preview/script/lib/',
54 datapath = 'preview/data/';
56 // load implementation files
57 // this is done async by the browser engine, so be aware of sync conditions!!
59 loadSAPI(libpath + 'sapi1/');
63 throw 'unsuppported SAPI version!';
65 function loadSAPI(path){
66 var path = path || (libpath + "sapi/");
69 loadScript(path + "AppManager.js");
70 loadScript(path + "Calendar.js");
71 loadScript(path + "Contact.js");
72 loadScript(path + "Landmarks.js");
73 loadScript(path + "Location.js");
74 loadScript(path + "Logging.js");
75 loadScript(path + "MediaManagement.js");
76 loadScript(path + "Messaging.js");
77 loadScript(path + "Sensor.js");
78 loadScript(path + "SysInfo.js");
81 loadScript(datapath + "appManager_data.js");
82 loadScript(datapath + "calendar_data.js");
83 loadScript(datapath + "contact_data.js");
84 loadScript(datapath + "landmarks_data.js");
85 loadScript(datapath + "location_data.js");
86 loadScript(datapath + "logging_data.js");
87 loadScript(datapath + "mediaManagement_data.js");
88 loadScript(datapath + "messaging_data.js");
89 loadScript(datapath + "sensor_data.js");
90 loadScript(datapath + "sysInfo_data.js");
93 function loadScript(src){
94 var head = document.getElementsByTagName("head")[0] || document.documentElement,
95 script = document.createElement("script");
97 script.type = "text/javascript";
99 head.appendChild(script);
104 device.implementation.prototype = {
109 * object returned by API calls
111 * @param {Object} value
112 * @param {Integer} code
113 * @param {String} msg
115 Result : function(value, code, msg){
118 ErrorCode : code || 0,
119 ErrorMessage: msg || undefined
126 * object returned by API calls with callbacks
128 * @param {Integer} transaction id
129 * @param {Integer} code
130 * @param {String} msg
132 AsyncResult : function(id, code, msg){
135 ErrorCode : code || 0,
136 ErrorMessage : msg || undefined
142 * object returned by API calls when error
144 * @param {Integer} code
145 * @param {String} msg
147 ErrorResult : function(code, msg){
148 device.implementation.context.debug(code, msg);
150 ErrorCode : code || 0,
151 ErrorMessage: msg || undefined
158 * object returned as ReturnValue by some API
160 * @param {Array} data
162 Iterator : function(data){
176 getNext : function(){
177 return index < data.length ? data[index++] : undefined;
184 * internal __methods__
187 $break: {}, // 'not implemented',
190 if (device.implementation.options.debug && window.console && console.log)
191 console.log(arguments);
194 // notify developer of api action
195 notify: function(msg){
196 if (window.console && console.warn)
197 console.warn('API Notice -- ' + msg);
200 getData : function(provider){
201 if (!device.implementation.data[provider])
202 throw "no data defined for provider '"+provider+"'";
204 if (device.implementation.data[provider]['default'])
205 return device.implementation.data[provider]['default'];
207 return device.implementation.data[provider];
210 getUniqueID : function(){
211 return Number(''+Number(new Date())+ Math.floor(1000*Math.random()));
214 callAsync : function(object, method, criteria, callback, flag){
215 flag = flag || false;
216 var tid = setTimeout(function(){
218 eventCode = {completed:2, error:4, progress:9},
219 code = eventCode.completed;
221 // call method in object's context
222 // flag is passed to trigger the method in case of mandatory callback arg
224 result = method.call(object, criteria, null, flag);
226 result = method.call(object, criteria);
229 code = eventCode.error;
231 callback(tid, code, result);
233 }, device.implementation.options.callbackDelay);
235 return this.AsyncResult(tid);
238 addListener : function(provider, eventType, criteria, callback, handler){
239 if (!device.implementation.listeners[provider])
240 device.implementation.listeners[provider] = {};
242 var tid = this.getUniqueID();
243 device.implementation.listeners[provider][eventType] = {
244 'criteria': criteria,
245 'callback': callback,
247 'transactionID' : tid
249 return this.AsyncResult(tid);
253 * specify either eventType or transactionID
254 * return true if found and removed
256 removeListener: function(provider, eventType, transactionID){
257 transactionID = transactionID || null;
259 var allEvents = device.implementation.listeners[provider];
260 for (var i in allEvents) {
261 var event = allEvents[i];
262 if (event.transactionID == transactionID) {
263 device.implementation.listeners[provider][i] = null;
264 delete device.implementation.listeners[provider][i];
271 this.hasListener(provider, eventType)) {
272 device.implementation.listeners[provider][eventType] = null;
273 delete device.implementation.listeners[provider][eventType];
279 hasListener: function(provider, eventType) {
280 if (!device.implementation.listeners[provider]
281 || !device.implementation.listeners[provider][eventType])
287 // pluck object properties as array
288 keys: function(obj) {
295 // extend object properties
296 extend: function(root, ext) {
302 // extended text string functionality
305 str = typeof str != 'undefined' ? String(str) : '';
306 return new StringEx(str);
311 * extended String object (available only within device.implementation.context through _t() method)
313 var StringEx = function(str){
314 // define base String non-transferrable methods!
315 this.toString = function(){return str;};
316 this.valueOf = function(){return str.valueOf();};
318 StringEx.prototype = new String();
322 * simple sprintf-type functionality
324 * "string {title} %s and %s and {here} ".arg({title:'T', here:'H'}, 1, 'there')"
325 * ==> string T 1 and there and H
326 * hash (if present) must be first argument
328 * @param {Object} [hash] optional hash to replace {tags}
329 * @param {String,Number} data for %s tags
330 * @return {String} original string with tags replaced
332 StringEx.prototype.arg = function(){
333 var pattern = /\%s|\{\w+\}/g;
334 var args = arguments,
335 len = arguments.length,
337 i = typeof hash == 'object' && !(hash instanceof String) ? 1 : 0;
339 return this.replace(pattern, function(capture){
340 var key = capture != '%s' && capture.match(/\w+/);
342 return hash && hash[key] ? hash[key] : capture;
344 return i < len ? args[i++] : capture;
349 * trim whitespace from beginning and end of string
350 * @return {String} trimmed string
352 StringEx.prototype.trim = function(){
353 return this.replace(/^\s+/, '').replace(/\s+$/, '');
358 * @return {String} capitalized string
360 StringEx.prototype.capitalize = function(){
361 return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
368 * device.implementation static (class) properties
373 * pointer to current instantiated device.implementation object.
374 * use to access device.implemenation namespace.
376 * @see device.implementation
378 device.implementation.context = null;
382 * emulation settings options
384 device.implementation.options = {
387 * callback delay (msec)
390 callbackDelay : 1200,
394 * @property {Boolean}
400 * @property {Boolean}
407 * store of interfaces (objects) in the current device implementation.
408 * format: [provider][interface]
412 device.implementation.interfaces = {};
416 * store of data objects defined for current implementation.
417 * data is added useing the loadData method.
419 * @property {Object} format depends on data
421 device.implementation.data = {};
425 * store of event listeners
426 * format: [provider][eventType]
428 device.implementation.listeners = {};
432 * device.implementation static (class) methods
437 * Add a service provider to device implementation
439 * @param {string} provider Name of service provider, eg, "Service.Calendar"
440 * @param {string} Interface Name of interface, eg, "IDataService"
441 * @param {Object} serviceProvider Service object
444 device.implementation.extend = function(provider, Interface, serviceProvider){
446 if (!device.implementation.interfaces[provider])
447 device.implementation.interfaces[provider] = {};
449 device.implementation.interfaces[provider][Interface] = serviceProvider;
454 * Internal implementation to return a service provider interface object
456 * @param {String} provider Service provider name
457 * @param {String} Interface Provider interface name
458 * @exception {String} exception thrown if provider or interface is not implemented
459 * @return {Object} the service provider interface object or 'undefined'
461 device.implementation.getInterface = function(provider, Interface){
463 if (device.implementation.interfaces[provider]
464 && typeof device.implementation.interfaces[provider][Interface] == 'object')
466 var service = new Object();
467 service[Interface] = device.implementation.interfaces[provider][Interface];
471 throw 'Error: unknown error';
476 * Loads data to the data store
478 * @param {String} provider Service provider name
479 * @param {String} type Data name/label
480 * @param {Function,Object,Array} dataFactory Function to generate the data object, or array/object
483 device.implementation.loadData = function(provider, type, dataFactory){
485 type = type || 'default';
486 if (!device.implementation.data[provider])
487 device.implementation.data[provider] = {};
489 device.implementation.data[provider][type] =
490 typeof dataFactory == 'function'
497 * trigger an event listener
499 * @param {String} provider Service provider name
500 * @param {String} eventType event type
501 * @param {Variant} data ReturnValue for callback function
503 device.implementation.triggerListener = function(provider, eventType, data){
505 if (!device.implementation.context.hasListener(provider, eventType)) {
506 device.implementation.context.notify('no listener defined for provider=' + provider + ', eventType=' + eventType);
509 var listener = device.implementation.listeners[provider][eventType];
511 // call the provider's handler
512 listener.handler(listener.transactionID, listener.criteria, listener.callback, data);
520 device.implementation.ERR_SUCCESS = 0;
521 device.implementation.ERR_INVALID_SERVICE_ARGUMENT = 1000;
522 device.implementation.ERR_UNKNOWN_ARGUMENT_NAME = 1001;
523 device.implementation.ERR_BAD_ARGUMENT_TYPE = 1002;
524 device.implementation.ERR_MISSING_ARGUMENT = 1003;
525 device.implementation.ERR_SERVICE_NOT_SUPPORTED = 1004;
526 device.implementation.ERR_SERVICE_IN_USE = 1005;
527 device.implementation.ERR_SERVICE_NOT_READY = 1006;
528 device.implementation.ERR_NO_MEMORY = 1007;
529 device.implementation.ERR_HARDWARE_NOT_AVAILABLE = 1008;
530 device.implementation.ERR_SEVER_BUSY = 1009;
531 device.implementation.ERR_ENTRY_EXISTS = 1010;
532 device.implementation.ERR_ACCESS_DENIED = 1011;
533 device.implementation.ERR_NOT_FOUND = 1012;
534 device.implementation.ERR_UNKNOWN_FORMAT = 1013;
535 device.implementation.ERR_GENERAL_ERROR = 1014;
536 device.implementation.ERR_CANCEL_SUCCESS = 1015;
537 device.implementation.ERR_SERVICE_TIMEDOUT = 1016;
538 device.implementation.ERR_PATH_NOT_FOUND = 1017;
542 // instantiate device imlementation
543 new device.implementation();