--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mpviewplugins/mpdetailsviewplugin/tsrc/unittest_resources/test-src/publishplayer.js Thu May 27 12:49:57 2010 +0300
@@ -0,0 +1,1312 @@
+window["ovi"] = window["ovi"] ||
+{};
+ovi.player = ovi.player ||
+{};
+ovi.player.contextobject = ovi.player.contextobject ||
+{};
+
+ovi.player.contextobject.getInstance = function(config) {
+ var player = {};
+ player._create = function(options, handler, context) {
+ var callable = (typeof handler === "function");
+ if (callable) {
+ handler.call(context, "CREATE_PENDING");
+ }
+ // TODO: add context object to player store
+ // TODO: store options.miniview to be returned with view as HTML
+ // TODO: store other properties of options to be returned with view as JSON
+ // TODO: return uri (unique id in this player's store) in callback
+ };
+ player._cancel = function(options, handler, context) {
+ var callable = (typeof handler === "function");
+ if (callable) {
+ handler.call(context, "CANCEL_PENDING");
+ }
+ // TODO: cancel pending tasks
+ // TODO: cancel Player
+ };
+ player._delete = function(options, handler, context) {
+ var callable = (typeof handler === "function");
+ if (callable) {
+ handler.call(context, "DELETE_PENDING");
+ }
+ // TODO: delete object defined in options.uri from store
+ };
+ player._edit = function(options, handler, context) {
+ var callable = (typeof handler === "function");
+ if (callable) {
+ handler.call(context, "EDIT_PENDING");
+ }
+ // TODO: update object defined in options.uri
+ };
+ player._pick = function(options, handler, context) {
+ var callable = (typeof handler === "function");
+ if (callable) {
+ handler.call(context, "PICK_PENDING");
+ }
+ // TODO: return list of all objects, or object defined in options.uri, fork with options.view
+ };
+ player._view = function(options, handler, context) {
+ var callable = (typeof handler === "function");
+ if (callable) {
+ handler.call(context, "VIEW_PENDING");
+ }
+ // TODO: return object defined in options.uri, JSON if options.view == "none", HTML if "mini"
+ };
+ ovi.player._getInstance.call(player, config);
+};
+
+ovi.player.contextobject.Player = ovi.player.contextobject.getInstance;
+/*
+ * Basic namespaces & common Player functions
+ */
+
+
+
+window["ovi"] = window["ovi"] ||
+{};
+ovi.player = ovi.player ||
+{};
+
+
+
+/**
+ * A function for creating a callback chain
+ * @param {Object} options
+ * @param {Object} handler
+ * @param {Object} context
+ * @return {Function}
+ */
+ovi.player._notImplemented = function(functionId) {
+ return function() {
+ var status = ovi.player._status;
+ handler.call(context, status["NOT_IMPLEMENTED"], null);
+ handler.call(context, status[functionId + "_FAILURE"], null); // TODO: return description, too?
+ };
+};
+
+
+
+/**
+ * A method for returning an instance of a singleton
+ * @param {Object} options A configuration object for the player
+ */
+ovi.player._getInstance = function(options) {
+ // TODO: store the configuration options
+ return (function() {
+ return (this.instance ||
+ (function() {
+ this.instance = {
+ // Public interface
+ cancel: (this._cancel || ovi.player._notImplemented("CANCEL")),
+ create: (this._create || ovi.player._notImplemented("CREATE")),
+ "delete": (this._delete || ovi.player._notImplemented("DELETE")), // delete is a keyword
+ edit: (this._edit || ovi.player._notImplemented("EDIT")),
+ pick: (this._pick || ovi.player._notImplemented("PICK")),
+ show: (this._view || ovi.player._notImplemented("VIEW")), // show is the same function as view, included in API for compatibility
+ sync: (this._sync || ovi.player._notImplemented("SYNC")),
+ view: (this._view || ovi.player._notImplemented("VIEW"))
+ };
+ return this.instance;
+ }()));
+ }());
+};
+
+
+
+ovi.player._status = {
+ USER_CANCEL: "USER_CANCEL",
+
+ CANCEL_PENDING: "CANCEL_PENDING",
+ CANCEL_FAILURE: "CANCEL_FAILURE",
+ CANCEL_SUCCESS: "CANCEL_SUCCESS",
+
+ CREATE_PENDING: "CREATE_PENDING",
+ CREATE_FAILURE: "CREATE_FAILURE",
+ CREATE_SUCCESS: "CREATE_SUCCESS",
+
+ DELETE_PENDING: "DELETE_PENDING",
+ DELETE_FAILURE: "DELETE_FAILURE",
+ DELETE_SUCCESS: "DELETE_SUCCESS",
+
+ EDIT_PENDING: "EDIT_PENDING",
+ EDIT_FAILURE: "EDIT_FAILURE",
+ EDIT_SUCCESS: "EDIT_SUCCESS",
+
+ PICK_PENDING: "PICK_PENDING",
+ PICK_FAILURE: "PICK_FAILURE",
+ PICK_SUCCESS: "PICK_SUCCESS",
+
+ SYNC_PENDING: "SYNC_PENDING",
+ SYNC_FAILURE: "SYNC_FAILURE",
+ SYNC_SUCCESS: "SYNC_SUCCESS",
+ SYNC_CONNECT_PENDING: "SYNC_CONNECT_PENDING",
+ SYNC_CONNECT_FAILED: "SYNC_CONNECT_FAILED",
+ SYNC_CONNECT_SUCCEEDED: "SYNC_CONNECT_SUCCEEDED",
+ SYNC_LOGIN_PENDING: "SYNC_LOGIN_PENDING",
+ SYNC_LOGIN_FAILED: "SYNC_LOGIN_FAILED",
+ SYNC_LOGIN_SUCCEEDED: "SYNC_LOGIN_SUCCEEDED",
+ SYNC_UPDATE_PENDING: "SYNC_UPDATE_PENDING",
+ SYNC_UPDATE_FAILED: "SYNC_UPDATE_FAILED",
+ SYNC_UPDATE_SUCCEEDED: "SYNC_UPDATE_SUCCEEDED",
+
+ VIEW_PENDING: "VIEW_PENDING",
+ VIEW_FAILURE: "VIEW_FAILURE",
+ VIEW_SUCCESS: "VIEW_SUCCESS",
+
+ NOT_IMPLEMENTED: "NOT_IMPLEMENTED"
+};
+window["ovi"] = window["ovi"] ||
+{};
+ovi.player = ovi.player ||
+{};
+ovi.player.publish = ovi.player.publish ||
+{};
+
+ovi.player.publish.getInstance = function(config) {
+ var player = {};
+ player._create = function(options, handler, context) {
+ var callable = (typeof handler === "function");
+ if (callable) {
+ handler.call(context, "CREATE_PENDING");
+ }
+ // TODO: create UI
+ // TODO: get the sub-players, sync them
+ };
+ player._cancel = function(options, handler, context) {
+ var callable = (typeof handler === "function");
+ if (callable) {
+ handler.call(context, "CANCEL_PENDING");
+ }
+ // TODO: cancel sub-players
+ // TODO: cancel pending tasks
+ // TODO: cancel Player
+ };
+ ovi.player._getInstance.call(player, config);
+};
+
+ovi.player.publish.Player = ovi.player.publish.getInstance;
+window["ovi"] = (window["ovi"] || {});
+ovi.player = (ovi.player || {});
+ovi.player.snc = (ovi.player.snc || {});
+ovi.player.snc.engine = (ovi.player.snc.engine || {});
+
+
+(function(){
+
+ var engine = ovi.player.snc.engine;
+
+
+ engine.status = {
+ SUCCESS : "SUCCESS",
+ FAILED : "FAILED",
+ }
+
+
+ var _callback = function(status, data, callback, context) {
+ if (typeof callback == "function") {
+ callback.call(context, status, data);
+ }
+ }
+
+ // External functions
+
+ /**
+ * Publish the given object to the social networks.
+ * @param {Object} object Published data
+ * @param {String} object.text Free text
+ * @param {String} object.context.artist Artist name
+ * @param {String} object.context.title Song title
+ * @param {Array} object.networks Array of social networks ids where to publish
+ * @param {Object} [callback] Called when publish is ready.
+ * @param {Object} [context]
+ */
+ engine.publish = function(data, callback, context){
+
+ // Just concatenate some status text from received data
+ var status = data.text;
+
+ // Add attached objects (temporarily just append to end of text)
+ // TODO : object.type == "URI" ... etc., add as attachment when supported by SNC
+ if (typeof data.object != "undefined") {
+ // Get URL to song before publishing and to status text
+ var link = data.object.content;
+ if (link.length > 0) {
+ status += " - " + link;
+ }
+ }
+
+ // Update to services
+ ovi.activities.updateStatus(status, {networkId: data.networks }, function(response){
+
+ if (response.status == "success") {
+ _callback(engine.status.SUCCESS, null, callback, context);
+ }
+ else {
+ // TODO : Implement finer error handling
+ _callback(engine.status.FAILED, { message : "Status update failed" }, callback, context);
+ }
+ });
+ }
+
+ /**
+ *
+ * @param {Object} data
+ * @param {Object} callback
+ * @param {Object} context
+ */
+ engine.cancelPublish = function(data, callback, context){
+ _callback(engine.status.SUCCESS, null, callback, context);
+ }
+
+
+ /**
+ * Reload social networks from SNC backend to the local store. Use getServices() to retrieve the
+ * list of loaded services.
+ * @param {Object} options Object containing Noa account information. Can be user, password or already
+ * autheticated session token to be used. { username : "", password : "" } or { token : "" }
+ * @param {Object} callback
+ * @param {Object} context
+ */
+ engine.sync = function(options, callback, context) {
+
+ // TODO : Seperate init and login from sync (we need both for publish also...)
+
+ // Do service didscovery
+
+ // 1. Init APIs
+ requests.initOviApi(function(response){
+
+ if(response.status != engine.status.SUCCESS) {
+ _callback(engine.status.FAILED, response.data, callback, context);
+ return;
+ }
+
+ // 2. Login noa
+ requests.noaLogin(options, function(response){
+
+ if(response.status != engine.status.SUCCESS) {
+ _callback(engine.status.FAILED, { message: response.message }, callback, context);
+ return;
+ }
+
+ // 3. Service discover
+ requests.discover(function(response){
+
+ // Store to player store
+ store.clear();
+ store.append(response.networks);
+ store.commit();
+
+ // Callback function
+ if (response.status == engine.status.SUCCESS) {
+ _callback(engine.status.OK, { networks: response.networks }, callback, context);
+ }
+ else {
+ _callback(engine.status.FAILED, { message: response.message }, callback, context);
+ }
+ });
+ });
+ });
+ }
+
+ /**
+ * Get list of services (social networks). Data is loaded from local
+ * player store. To synchronize data social networks from SNC call sync().
+ */
+ engine.getServices = function() {
+ // Get list of services from store
+ return store.getList();
+ }
+
+ /**
+ * Mark service as selected / unselected. Saves the selection to the persistent
+ * local storage to save data over sessions.
+ * @param {Object} id
+ * @param {Object} enable
+ */
+ engine.selectService = function(id, enable) {
+ // Select / unselect service in player store
+ store.select(id, enable);
+ }
+
+ // Player store
+ var STORE_KEY_SERVICES = "ovi.player.snc.services";
+ var STORE_KEY_SELECTED = "ovi.player.snc.services.selected";
+
+ /**
+ * Player store implementation. Persists the social networks (services) and selections
+ * to the HTML5 local storage, which provides over sessions caching.
+ */
+ var store = {
+
+ _services : {},
+ _selected : {},
+
+ /**
+ * Add new server or services to the store.
+ * @param {Object} service
+ */
+ append : function(service) {
+ if (service.length) {
+ for(var i=0; i < service.length; i++) {
+ var s = service[i];
+ this._services[s.id] = s;
+ }
+ } else {
+ this._services[service.id] = service;
+ }
+ },
+
+ /**
+ * Mark service selected or unselected in the store. Also commits changes in
+ * selections to the store.
+ * @param {Object} id
+ * @param {Object} enable
+ */
+ select : function(id, enable) {
+ this._selected[id] = enable;
+ localStorage.setItem(STORE_KEY_SELECTED, JSON.stringify(this._selected));
+ },
+
+ /**
+ * Clear services.
+ */
+ clear : function() {
+ this._services = {};
+ },
+
+ /**
+ * Get list (array) of services in the store.
+ */
+ getList : function() {
+ // Convert to array
+ var res = [];
+ for(var o in this._services) {
+ var serv = this._services[o];
+ serv.selected = typeof this._selected[o] != "undefined" ? this._selected[o] : false;
+ res.push(serv);
+ }
+ return res;
+ },
+
+ /**
+ * Commit services to the store.
+ */
+ commit : function() {
+ localStorage.setItem(STORE_KEY_SERVICES, JSON.stringify(this._services));
+ },
+
+ /**
+ * Retrieve services and selections in the store.
+ */
+ load : function() {
+ this._services = JSON.parse(localStorage.getItem(STORE_KEY_SERVICES));
+ this._selected = JSON.parse(localStorage.getItem(STORE_KEY_SELECTED));
+
+ if (this._services == null) this._services = {};
+ if (this._selected == null) this._selected = {};
+ }
+ }
+
+
+ // SNC Request implementation
+ var requests = {
+
+ /**
+ *
+ * @param {Object} callback
+ */
+ initOviApi: function(callback){
+ var myincludes = "ovi.auth.noa_login, ovi.api.snc, ovi.api.activities, ovi.net.xss";
+ ovi.onReady = function(libs){
+ if (ovi.testIfLoaded(myincludes, libs)) {
+
+ // Successful, set environment for NCIM
+ ovi.config.setenv("st-account", "delegate");
+
+ // Allow cross-domain scripting
+ function xssInitCallback(data){
+ if (data.event === "InitializeOk") {
+ callback( { status : engine.status.SUCCESS });
+ }
+ }
+
+ ovi.net.XssInit({
+ back_url: "http://spb.ci.wipsl.com/ovi-api/js/ovi/net/",
+ callback: xssInitCallback
+ });
+
+ }
+ }
+
+ ovi.include(myincludes);
+ },
+
+ /**
+ *
+ * @param {Object} callback
+ */
+ noaLogin: function(options, callback){
+
+ var noa = {};
+ if (typeof options.token != "undefined") { // This propably is not supported yet..
+ noa = { token : options.token };
+ }
+ else {
+ noa = { username : options.username, password : options.password };
+ }
+
+ // Login
+ ovi.noa.login(noa, function(state){
+
+ // Callback
+ if (state.status == "success") {
+ callback( {
+ status: engine.status.SUCCESS
+ } );
+ }
+ else {
+ callback( {
+ status: engine.status.FAILED,
+ message: "NOA login failed - " + state.statusCode + " - " + state.status
+ } );
+ }
+ });
+ },
+
+ /**
+ *
+ * @param {Object} callback
+ */
+ discover: function(callback){
+
+ // Discover service available
+ ovi.snc.discoverSocialNetworks(function(response){
+
+ if (response.status != "success") {
+ callback( {
+ status: engine.status.FAILED,
+ message : "Service discovery failed - " + response.statusCode + " - " + response.responseText
+ } );
+ return;
+ }
+
+ var netw = response.data.network;
+
+ // And get activated
+ ovi.snc.getActivatedSocialNetworks(function(response){
+
+ if (response.status != "success") {
+ callback( {
+ status: engine.status.FAILED,
+ message : "Service discovery failed - " + response.statusCode + " - " + response.responseText
+ } );
+
+ return;
+ }
+ else if (response.statusCode == 204) { // Not an error, no active networks
+ callback( {
+ status: engine.status.SUCCESS,
+ networks : []
+ } );
+
+ return;
+ }
+
+ var active = response.data.network;
+
+ // Now we have finally the service discovery ready, create final response
+ // Remove all not-active networks from supported networks
+ var results = [];
+ for(var i=0; i < netw.length; i++) {
+ var id = netw[i].id;
+
+ for(var j=0; j < active.length; j++) {
+ if (active[j].id == id) {
+ // We have a winner
+ results.push({ name : netw[i].name, id : netw[i].id, maxTextInput : netw[i].maxTextInput });
+ break;
+ }
+ }
+ }
+
+ callback( {
+ status: engine.status.SUCCESS,
+ networks : results
+ } );
+ });
+ });
+ }
+ }
+
+ // Restore data from store
+ store.load();
+
+})();
+// Create needed namespace ovi.player.share.ui
+window["ovi"] = window["ovi"] ||
+{};
+ovi.player = ovi.player ||
+{};
+ovi.player.share = ovi.player.share ||
+{};
+ovi.player.share.ui = ovi.player.share.ui ||
+{};
+
+/**
+ * TODO
+ *
+ * This API tries to imitate medos framework UI controls for future compability.
+ * @param {Object} params
+ * @param {Object} target
+ */
+ovi.player.share.ui.Button = function(params, target) {
+
+ var CLICK_EVENT = "selected";
+ var that = this;
+
+ function createHtml() {
+ var template = '<button class="ovi_Button ovi_unselectable ovi_clip">' +
+ params.text + '</button>';
+
+ var node = document.createElement("div"); // Do we need this ??
+ node.innerHTML = template;
+ return node;
+ }
+
+ var _root = createHtml();
+ var _button = _root.firstChild;
+
+ target.appendChild(_root);
+
+ // Interface functions
+ this.addEventHandler = function(event, callback) {
+ // selected = click (comes from medos...)
+ if (event == CLICK_EVENT) {
+ _root.addEventListener("click", function(e) { callback.call(that, e); }, that);
+ }
+ }
+
+ this.setProperty = function(name, value) {
+ _button[name] = value;
+ }
+
+ this.getProperty = function(name) {
+ return _button[name];
+ }
+}
+// Create needed namespace ovi.player.share.ui
+window["ovi"] = window["ovi"] ||
+{};
+ovi.player = ovi.player ||
+{};
+ovi.player.share = ovi.player.share ||
+{};
+ovi.player.share.ui = ovi.player.share.ui ||
+{};
+
+/**
+ * Checkbox UI control implementation. TODO
+ *
+ * This API tries to imitate medos framework UI controls for future compability.
+ * @param {Object} params
+ * @param {Object} target
+ */
+ovi.player.share.ui.CheckBox = function(params, target) {
+
+ var that = this;
+
+ function createHtml() {
+
+ var template = '<div class="ovi_CheckBox ovi_unselectable ovi_clip">' +
+ '<input type="checkbox"></input>' +
+ '<span data-bind-text="label">' + params.label + '</span>' +
+ '</div>';
+
+ var node = document.createElement("div"); // Do we need this ??
+ node.innerHTML = template;
+ return node;
+ }
+
+ var _root = createHtml();
+ var _checkBox = _root.firstChild.firstChild;
+
+ target.appendChild(_root);
+
+ this.setProperty = function(name, value) {
+
+ if (name == "selected") { // Use medos property name mappings
+ _checkBox["checked"] = value;
+ }
+ else {
+ _checkBox = value;
+ }
+ }
+
+ this.getProperty = function(name) {
+ if (name == "selected") {
+ return _checkBox["checked"];
+ }
+ return _checkBox[name];
+ }
+
+ for(var v in params) {
+ this.setProperty(v, params[v]);
+ }
+}
+// Create needed namespace ovi.player.share.ui
+window["ovi"] = window["ovi"] ||
+{};
+ovi.player = ovi.player ||
+{};
+
+
+/**
+ * Context object player poc implementation
+ */
+ovi.player.contextobject = ovi.player.contextobject ||
+{};
+
+
+ovi.player.contextobject.Player = function() {
+
+ var targetNS = this;
+ targetNS.create = function(params) {
+ targetNS.object = params;
+ }
+}
+
+
+
+/**
+ * Publish player poc implementation
+ */
+ovi.player.publish = ovi.player.publish ||
+{};
+
+// Extend the namespace
+ovi.player.publish.Player = function(params) {
+
+ // TODO : MAKE THIS SINGLETON SOMEHOW ??
+ var targetNS = this;
+
+ // Utils
+ var _id = function(id) {
+ return document.getElementById(id);
+ };
+
+ var _addClass = function(target, className) {
+ var classes = target.className;
+ if (!classes.match(new RegExp("\\b" + className + "\\b"))) {
+ if (classes != "" && classes.substr(-1) != " ") {
+ target.className += " ";
+ }
+ target.className += className;
+ }
+ };
+ var _removeClass = function(target, className) {
+ target.className = target.className.replace(new RegExp("\\b" + className + "\\b", "g"), "");
+ //TODO: clean extra spaces?
+
+ };
+ var _toggleClass = function(target, className) {
+ if (target.className.indexOf(className) == -1) {
+ _addClass(target, className);
+ return true;
+ } else {
+ _removeClass(target, className);
+ return false;
+ }
+
+ };
+
+
+
+ /**
+ * "State engine"
+ */
+ var _state = {
+ visible: false,
+ services: {}
+ };
+
+
+
+ /**
+ * HTML templates for ui
+ */
+ var _templates = {
+ // TODO: localization
+ "share.ui": '<div class="player">\
+ <div class="panel header">Publish</div>\
+ <div class="panel panel-message">\
+ <div class="info hidden" id="comment-limit"><span id="comment-length">0</span>/<span id="comment-maxlength">0</span></div>\
+ <div class="comment" id="comment-area">\
+ <div class="hint">Write message here</div>\
+ <textarea id="message"></textarea>\
+ </div>\
+ <hr/><div class="info" id="shared-object"></div><hr/>\
+ </div>\
+ <div class="panel networks-panel"><ul class="list checked" id="available-services"></ul></div>\
+ <div class="panel panel-buttons">\
+ <ul class="list button-bar">\
+ <li id="action-ok" class="disabled"><span>OK</span></li>\
+ <li id="action-cancel"><span>Cancel</span></li>\
+ </ul>\
+ </div>\
+ </div>'
+ };
+
+
+
+ /**
+ * Generic callback invoker
+ *
+ * @param {Object} notification
+ * @param {Object} data
+ * @param {Object} callback
+ * @param {Object} context
+ */
+ var _callback = function(notification, data, callback, context) {
+ if (typeof callback == "function") {
+ callback.call(context, notification, data);
+ }
+ };
+
+
+
+ /**
+ * status messages
+ */
+ var _status = {
+
+ show: "SHOW",
+ show_ok: "SHOW_SUCCEEDED",
+ show_fail: "SHOW_FAILED",
+
+ updateobject: "UPDATEOBJECT",
+ updateobject_ok: "UPDATEOBJECT_SUCCEEDED",
+ updateobject_fail: "UPDATEOBJECT_FAILED",
+
+ updateservices: "UPDATESERVICES",
+ updateservices_ok: "UPDATESERVICES_SUCCEEDED",
+ updateservices_fail: "UPDATESERVICES_FAILED",
+ updateservices_nonetworks : "UPDATESERVICES_NONETWORKS"
+
+ };
+
+
+
+ /**
+ * Invokes the ui for the player
+ *
+ * @param {Object} [options]
+ * @param {Object} [options.target] the dom node or id where the ui should be inserted
+ * @param {Object} [options.template] the html for the ui
+ * @param {Object} [callback]
+ * @param {Object} [context]
+ */
+ var _show = function(options, callback, context) {
+
+ var target = (options && options.target) || _id("ovi.player.share.ui"), template = (options && options.template) || _templates["share.ui"];
+
+ // Find target node if id was given
+ if (typeof target == "string") {
+ target = _id(_target);
+ }
+ if (target) {
+ if (template) {
+ if (_state.visible && target.innerHTML.indexOf('"player"') >= 0) {
+ // _show was already called earlier, and player is shown
+ _callback(_status.show, {
+ message: "Player is already visible"
+ }, callback, context);
+ } else {
+ target.innerHTML = template;
+
+ // add handler for textarea
+ var message = _id("message");
+ _id("message").onkeyup = _handleMessageChange;
+ message.style.backgroundColor = "transparent";
+
+ // add handlers for buttons
+ _id("action-ok").onclick = _handleSubmit;
+ _id("action-cancel").onclick = _handleSubmit;
+
+ // Update state
+ _state.visible = true;
+ _callback(_status.show_ok, null, callback, context);
+ }
+ } else {
+ _callback(_status.show_fail, {
+ message: "Template not found",
+ data: {
+ template: template
+ }
+ }, callback, context);
+ }
+ } else {
+ _callback(_status.show_fail, {
+ message: "Target container not found",
+ data: {
+ target: target
+ }
+ }, callback, context);
+ }
+
+ onResize(); // Initial resize
+
+ // If we would like to show the services stored in local storage, uncommenting the following would do
+ // the job..
+ /*
+ var services = ovi.player.share.engine.getServices();
+ targetNS.updateServices(services);*/
+ };
+
+ /**
+ * Removes all the handlers from the ui and the ui
+ *
+ * @param {Object} options
+ * @param {Object} callback
+ * @param {Object} context
+ */
+ var _teardown = function(options, callback, context) {
+ //TODO: clear handlers
+ //TODO: destroy html
+ //TODO: update status
+ };
+
+
+ var _updateServices = function(data, callback, context) {
+
+ var target = _id("available-services");
+
+ if (target) {
+ if (data.length) {
+ var listToCheck = [], i;
+ // TODO: add loading animation?
+ for (i = 0; i < data.length; i++) {
+ var id = data[i].id, label = data[i].name;
+ if (id && label) {
+ id = "service-" + id;
+ listToCheck.push(id);
+ if (!_id(id)) {
+ // We don't have the network in our list yet, create one
+ var item = document.createElement("LI"), checkbox = document.createElement("SPAN");
+ checkbox.setAttribute("class", "checkbox");
+ checkbox.appendChild(document.createTextNode(label));
+ item.appendChild(checkbox);
+ item.setAttribute("id", id);
+ item.onclick = _handleServiceListClick;
+ target.appendChild(item);
+ // store object to the state
+ if (data[i].selected) {
+ data[i].checked = _toggleClass(item, "checked");
+ }
+ _state.services[id] = data[i];
+ }
+ } else {
+ _callback(_status.updateservices, {
+ message: "Service object formatted badly",
+ data: data[i]
+ }, callback, context);
+ }
+ }
+ //make a searchable string
+ listToCheck = listToCheck.join();
+ //remove obsolete networks
+ for (i = 0; i < target.childNodes.length; i++) {
+ var node = target.childNodes[i], id = node.getAttribute("id");
+ if (listToCheck.indexOf(id) == -1) {
+ node.onclick = null;
+ target.removeChild(node);
+ }
+ // TODO: update _state?
+ }
+ _updateServiceLimits();
+ _callback(_status.updateservices_ok, null, callback, context);
+ } else {
+ _callback(_status.updateservices_fail, {
+ message: "Received data was not an array",
+ data: data
+ }, callback, context);
+ }
+ } else {
+ _callback(_status.updateservices_fail, {
+ message: "Target container not found"
+ }, callback, context);
+ }
+ };
+
+ /**
+ * Handler for message changes
+ * @param {Object} e
+ */
+ var _handleMessageChange = function(e) {
+ _id("comment-length").innerHTML = this.value.length;
+ _checkMessageLength();
+ }
+
+
+
+ /**
+ * Handler for service selection
+ * @param {Object} e
+ */
+ var _handleServiceListClick = function(e) {
+ _state.services[this.id].checked = _toggleClass(this, "checked");
+ ovi.player.snc.engine.selectService(_state.services[this.id].id, _state.services[this.id].checked);
+ _updateServiceLimits();
+ };
+
+
+
+ /**
+ * Check limits and if the OK button can be clicked
+ */
+ var _updateServiceLimits = function() {
+ var bigNumber = 9999999, maxTextInput = bigNumber, min = Math.min, services = _state.services, service;
+ for (sid in services) {
+ service = services[sid];
+ if (service.checked && service.maxTextInput && service.maxTextInput > 0) {
+ maxTextInput = min(maxTextInput, service.maxTextInput);
+ }
+ }
+
+ if (maxTextInput < bigNumber) {
+ // Reduce the link and context reserved size from input (data that will be allocated
+ // from maxTextInput for context)
+ var contextData = _state.contextPlayer.object.data;
+ maxTextInput -= contextData.object.reservedLength;
+
+ _id("comment-maxlength").innerHTML = maxTextInput;
+ _removeClass(_id("comment-limit"), "hidden");
+ //TODO: alter size of elements to make space for the limit?
+ } else {
+ _id("comment-maxlength").innerHTML = maxTextInput;
+ _addClass(_id("comment-limit"), "hidden");
+ }
+ _checkMessageLength();
+ };
+
+
+
+ var _checkMessageLength = function() {
+ var length = parseInt(_id("comment-length").innerHTML), maxLength = parseInt(_id("comment-maxlength").innerHTML), message = _id("message");
+ if (length == 0) {
+ message.style.backgroundColor = "transparent";
+ } else {
+ message.style.backgroundColor = "";
+ }
+ if ((maxLength > 0) && (length > maxLength)) {
+ _addClass(_id("comment-limit"), "error");
+ _addClass(message, "error");
+ } else {
+ _removeClass(_id("comment-limit"), "error");
+ _removeClass(message, "error");
+ }
+ _updateActions();
+ };
+
+
+
+ var _updateActions = function() {
+ if (_canSubmit()) {
+ _removeClass(_id("action-ok"), "disabled");
+ } else {
+ _addClass(_id("action-ok"), "disabled");
+ }
+ };
+ var _canSubmit = function() {
+ var length = parseInt(_id("comment-length").innerHTML), maxLength = parseInt(_id("comment-maxlength").innerHTML), services = _state.services, service;
+ if ((maxLength > 0) && (length > maxLength)) {
+ return false;
+ }
+ for (sid in services) {
+ service = services[sid];
+ if (service.checked && service.maxTextInput && service.maxTextInput > 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ var _handleSubmit = function(e) {
+ // don't accept clicks from elements with class "disabled"
+ if (/\bdisabled\b/.test(this.className)) {
+ return;
+ }
+ if (this.id == "action-ok") {
+ _addClass(this, "disabled");
+ _addClass(_id("action-cancel"), "disabled");
+ //TODO: disable testarea and service list?
+
+ var services = _state.services, service, networks = [];
+ for (sid in services) {
+ service = services[sid];
+ if (service.checked) {
+ networks.push(service.id);
+ }
+ }
+
+ var contextData = _state.contextPlayer.object.data;
+
+ var data = {
+ text: _id("message").value,
+ object : contextData.object,
+ networks: networks
+ };
+
+ ovi.player.snc.engine.publish(data, function(status, data) {
+ if (status == ovi.player.snc.engine.status.FAILED) {
+ alert(data.message);
+ }
+ _reset();
+ });
+ // TODO: call window.close here? teardown first? window.close in teardown?
+ } else {
+ ovi.player.snc.engine.cancelPublish(null, function(status, data) {
+ _reset();
+ });
+ }
+ };
+
+ var _reset = function() {
+ _id("shared-object").innerHTML = "";
+ _id("message").value = "";
+ _handleMessageChange.call(_id("message"));
+ _removeClass(_id("action-cancel"), "disabled");
+
+ // Request window to be closed
+ window.close();
+ };
+
+ var _sync = function(contextPlayer, handler, context) {
+ // Sync context to UI
+ _state.contextPlayer = contextPlayer; // Store context object for publishing
+ _id("shared-object").innerHTML = _state.contextPlayer.object.data.miniview;
+ }
+
+
+ var _sncInit = function(credentials, handler, context) {
+ // Sync SNC stuff
+ ovi.player.snc.engine.sync(credentials.token, function(status, data) {
+ if (status == ovi.player.snc.engine.status.FAILED) {
+ _callback(_status.updateservices_fail,
+ { message: data.message },
+ handler, context);
+ }
+ else if (data.networks.length == 0) {
+ _callback(_status.updateservices_nonetworks,
+ { message: "No networks" },
+ handler, context);
+ }
+ else {
+ var services = ovi.player.snc.engine.getServices();
+ _updateServices(services, handler, context);
+ }
+ } );
+ }
+
+
+
+ // Register onResize for landscape / portrait mode changes
+ window.addEventListener("resize", onResize, true);
+
+ function onResize(e) {
+
+ function isLandscape(){
+ return window.innerWidth > window.innerHeight;
+ }
+
+ function _setMode(mode) {
+ _changeMode(_id("comment-area"), mode);
+
+ var services = _id("available-services").children;
+ for(var i=0; i < services.length; i++) {
+ _changeMode(services[i], mode);
+ }
+ }
+
+ // Determine - landscape or portrait mode
+ if (isLandscape()) {
+ _setMode("landscape");
+ }
+ else {
+ _setMode("portrait");
+ }
+ }
+
+ function _changeMode(id, mode) {
+ if (mode == "portrait") {
+ _removeClass(id, "landscape");
+ _addClass(id, "portrait");
+ } else {
+ _removeClass(id, "portrait");
+ _addClass(id, "landscape");
+ }
+ }
+
+ /**
+ * Assign needed functions to the target namespace => defined public API.
+ */
+ targetNS.view = _show;
+ targetNS.teardown = _teardown;
+ targetNS.reset = _reset;
+
+ /**
+ * Synchronize context data from context object
+ */
+ targetNS.sync = _sync;
+
+ /**
+ * Launch UI and initialize SNC
+ */
+ targetNS.create = function(options, handler, context) {
+
+ // Show UI
+ _show(options, handler, context);
+
+ // Start loading SNC networks
+ _sncInit(params.credentials, handler, context);
+ }
+
+ targetNS.status = _status;
+};
+// Create needed namespace ovi.player.share.ui
+window["ovi"] = window["ovi"] ||
+{};
+ovi.player = ovi.player ||
+{};
+ovi.player.share = ovi.player.share ||
+{};
+ovi.player.share.ui = ovi.player.share.ui ||
+{};
+
+/**
+ * Label UI control implementation. TODO
+ *
+ * This API tries to imitate medos framework UI controls for future compability.
+ * @param {Object} params
+ * @param {Object} target
+ */
+ovi.player.share.ui.Label = function(params, target) {
+
+ var CLICK_EVENT = "selected";
+ var that = this;
+
+ function createHtml() {
+ var template = '<span class="ovi_Label">' + params.text + '</span>';
+
+ var node = document.createElement("div"); // Do we need this ??
+ node.innerHTML = template;
+ return node;
+ }
+
+ var _root = createHtml();
+ var _label = _root.firstChild;
+
+ target.appendChild(_root);
+
+ this.setProperty = function(name, value) {
+ _label[name] = value;
+ }
+
+ this.getProperty = function(name) {
+ return _label[name];
+ }
+
+ for(var v in params) {
+ this.setProperty(v, params[v]);
+ }
+}
+// Create needed namespace ovi.player.share.ui
+window["ovi"] = window["ovi"] ||
+{};
+ovi.player = ovi.player ||
+{};
+ovi.player.share = ovi.player.share ||
+{};
+ovi.player.share.ui = ovi.player.share.ui ||
+{};
+
+/**
+ * Textarea UI control implementation. TODO
+ *
+ * This API tries to imitate medos framework UI controls for future compability.
+ * @param {Object} params
+ * @param {Object} target
+ */
+ovi.player.share.ui.TextArea = function(params, target) {
+
+ var CLICK_EVENT = "selected";
+ var that = this;
+
+ function createHtml() {
+ var template = '<textarea class="ovi_TextInput ovi_Textarea" rows="2"></textarea>';
+
+ var node = document.createElement("div"); // Do we need this ??
+ node.innerHTML = template;
+ return node;
+ }
+
+ var _root = createHtml();
+ var _textarea = _root.firstChild;
+
+ target.appendChild(_root);
+
+ this.setProperty = function(name, value) {
+ _textarea[name] = value;
+ }
+
+ this.getProperty = function(name) {
+ return _textarea[name];
+ }
+
+ for(var v in params) {
+ this.setProperty(v, params[v]);
+ }
+}
+window["ovi"] = window["ovi"] ||
+{};
+ovi.player = ovi.player ||
+{};
+ovi.player.snc = ovi.player.snc ||
+{};
+
+ovi.player.snc.getInstance = function(config) {
+ var player = {};
+ player._cancel = function(options, handler, context) {
+ var callable = (typeof handler === "function");
+ if (callable) {
+ handler.call(context, "CANCEL_PENDING");
+ }
+ // TODO: cancel Player
+ };
+ player._pick = function(options, handler, context) {
+ var callable = (typeof handler === "function");
+ if (callable) {
+ handler.call(context, "PICK_PENDING");
+ }
+ // TODO: offer list of configured networks
+ };
+ player._view = function(options, handler, context) {
+ var callable = (typeof handler === "function");
+ if (callable) {
+ handler.call(context, "VIEW_PENDING");
+ }
+ // TODO: offer miniviews for networks list
+ };
+ player._sync = function(options, handler, context) {
+ var callable = (typeof handler === "function");
+ if (callable) {
+ handler.call(context, "SYNC_PENDING");
+ }
+ // TODO: connect to the Ovi API and SNC
+ };
+ ovi.player._getInstance.call(player, config);
+};
+
+ovi.player.snc.Player = ovi.player.snc.getInstance;