diff --git a/Ping.fm/LICENSE.txt b/Ping.fm/LICENSE.txt new file mode 100644 index 0000000..3d5788a --- /dev/null +++ b/Ping.fm/LICENSE.txt @@ -0,0 +1,31 @@ +Software License Agreement (BSD License) + +Copyright (c) 2010, Erik C. Thauvin (http://erik.thauvin.net/) +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + Neither the name of the authors nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +$Id$ \ No newline at end of file diff --git a/Ping.fm/app/assistants/main-assistant.js b/Ping.fm/app/assistants/main-assistant.js new file mode 100644 index 0000000..4be02ee --- /dev/null +++ b/Ping.fm/app/assistants/main-assistant.js @@ -0,0 +1,732 @@ +// --------------------------------------------------------------------------- +// KeyDialogAssistant +// --------------------------------------------------------------------------- +function KeyDialogAssistant(sceneAssistant, focusField) +{ + this.sceneAssistant = sceneAssistant; + this.focusField = focusField; +} + +KeyDialogAssistant.prototype.setup = function(widget) +{ + this.widget = widget; + + this.sceneAssistant.controller.setupWidget('mobileKey', + { + hintText: 'Enter your Ping.fm mobile key...', + autoFocus: true, + limitResize: true, + autoReplace: false, + textCase: Mojo.Widget.steModeLowerCase, + focusMode: Mojo.Widget.focusAppendMode, + maxLength: 4 + }, this.mobileKeyModel = + { + value: '', + disabled: false + }); + + this.okButtonModel = + { + label: 'OK', + disabled: false + }; + + this.sceneAssistant.controller.setupWidget('okButton', + { + type: Mojo.Widget.activityButton + }, this.okButtonModel); + + this.okButton = this.sceneAssistant.controller.get('okButton'); + + this.checkKeyHandler = this.checkKey.bindAsEventListener(this); + this.sceneAssistant.controller.listen('okButton', Mojo.Event.tap, this.checkKeyHandler); + + this.handleKeyHandler = this.handleKeyEvent.bindAsEventListener(this); + this.sceneAssistant.controller.document.addEventListener('keyup', this.handleKeyHandler, true); + + this.cancelButtonModel = + { + label: 'Cancel', + disabled: false + }; + + this.sceneAssistant.controller.setupWidget('cancelButton', + { + type: Mojo.Widget.defaultButton + }, this.cancelButtonModel); + + this.sceneAssistant.controller.listen('cancelButton', Mojo.Event.tap, this.widget.mojo.close); +}; + +KeyDialogAssistant.prototype.checkKey = function() +{ + this.okButton.mojo.activate(); + this.okButtonModel.label = 'Validating Key'; + this.okButtonModel.disabled = true; + this.sceneAssistant.controller.modelChanged(this.okButtonModel); + + var params = new Hash( + { + 'api_key': this.sceneAssistant.api_key, + 'mobile_key': this.mobileKeyModel.value + }); + + Mojo.Log.info('checkKey: ' + params.toQueryString()); + + var request = new Ajax.Request('http://api.ping.fm/v1/user.key', + { + method: 'post', + parameters: params, + evalJSON: 'false', + onSuccess: this.checkKeySuccess.bind(this), + onFailure: this.checkKeyFailure.bind(this) + }); +}; + +KeyDialogAssistant.prototype.checkKeySuccess = function(transport) +{ + if (transport.responseXML === null) + { + Mojo.Controller.errorDialog("Invalid response from the Ping.fm API.", this.controller.window); + } + else + { + var rsp = transport.responseXML.getElementsByTagName('rsp'); + var status = rsp[0].getAttribute('status'); + + if (status == 'FAIL') + { + this.sceneAssistant.controller.get('keyDialogTitle').update('Invalid or Expired Key. Please Retry.'); + this.mobileKeyModel.value = ''; + this.sceneAssistant.controller.modelChanged(this.mobileKeyModel); + this.sceneAssistant.controller.get('mobileKey').mojo.focus(); + + Mojo.Log.info(transport.responseText); + + this.okButton.mojo.deactivate(); + this.okButtonModel.label = 'OK'; + this.okButtonModel.disabled = false; + this.sceneAssistant.controller.modelChanged(this.okButtonModel); + } + else + { + this.sceneAssistant.prefs.user_app_key = rsp[0].getElementsByTagName('key').item(0).textContent; + this.sceneAssistant.updateMethods(); + + this.okButton.mojo.deactivate(); + this.widget.mojo.close(); + } + } +}; + +KeyDialogAssistant.prototype.checkKeyFailure = function(transport) +{ + this.sceneAssistant.transportFailure('checkKeyFailure', transport); +}; + +KeyDialogAssistant.prototype.handleKeyEvent = function(event) +{ + if (Mojo.Char.isEnterKey(event.keyCode)) + { + if (event.srcElement.parentElement.id == 'mobileKey') + { + this.checkKey(); + } + } +}; + +KeyDialogAssistant.prototype.cleanup = function() +{ + this.sceneAssistant.controller.stopListening('okButton', Mojo.Event.tap, this.checkKeyHandler); + this.sceneAssistant.controller.stopListening('cancelButton', Mojo.Event.tap, this.widget.mojo.close); + this.sceneAssistant.controller.document.removeEventListener('keyup', this.handleKeyHandler, false); + + this.focusField.mojo.focus(); +}; + +KeyDialogAssistant.prototype.activate = function(event) +{ + this.sceneAssistant.controller.get('mobileKey').mojo.focus(); +}; + +// --------------------------------------------------------------------------- +// MainAssistant +// --------------------------------------------------------------------------- +function MainAssistant() +{ +} + +MainAssistant.prototype.setup = function() +{ + //$$('body')[0].addClassName('palm-dark'); + + this.hasConnectivity = false; + this.checkConnectivity(); + + this.debug = 0; + + this.cookieData = new Mojo.Model.Cookie('netThauvinErikWebOsPingFm'); + this.prefs = this.cookieData.get(); + + this.api_key = 'edb93979c2abd58781f72d96f042e3a4'; + this.messageMaxLen = 140; + + this.defaultMethods = [ + { + label: 'Default', + value: 'default' + }, + { + label: 'Micro-blogs', + value: 'microblog' + }, + { + label: 'Statuses', + value: 'status' + }, + { + label: 'Blogs', + value: 'blog' + }]; + + if (!this.prefs) + { + this.prefs = + { + version: 1, + user_app_key: null, + showTitle: false, + defaultMethod: this.defaultMethods[0].value, + methods: this.defaultMethods.clone() + }; + + this.cookieData.put(this.prefs); + } + + var hasNoMethods = (this.defaultMethods.length == this.prefs.methods.length); + + this.updatedMethods = + { + hasNoServices: hasNoMethods, + hasNoTargets: hasNoMethods + }; + + this.showTitleMenuItem = + { + label: '', + command: 'do-title' + }; + this.toggleTitleMenu(); + + this.appMenuModel = + { + visible: true, + items: [ + { + label: 'About #{title}...'.interpolate( + { + title: Mojo.Controller.appInfo.title + }), + command: 'do-about' + }, Mojo.Menu.editItem, this.showTitleMenuItem, + { + label: 'Refresh Methods', + command: 'do-methods-refresh' + }, + { + label: 'Reset Key...', + command: 'do-key-reset' + }] + }; + + this.controller.setupWidget(Mojo.Menu.appMenu, + { + omitDefaultItems: true + }, this.appMenuModel); + + this.controller.setupWidget('methodList', + { + label: 'Method' + }, this.methodModel = + { + choices: this.prefs.methods, + value: this.prefs.defaultMethod + + }); + + this.controller.setupWidget('titleField', + { + hintText: 'Type a title...', + focusMode: Mojo.Widget.focusAppendMode, + hide: true + }, this.titleModel = + { + value: '' + }); + + this.controller.setupWidget('messageField', + { + hintText: 'Type your message...', + multiline: true, + changeOnKeyPress: true, + focusMode: Mojo.Widget.focusAppendMode + }, this.messageModel = + { + value: '' + }); + + this.pingButton = this.controller.get('pingBtn'); + this.pingBtnModel = + { + label: 'Ping It!', + original: 'Ping It!', + disabled: true + }; + this.controller.setupWidget('pingBtn', + { + type: Mojo.Widget.activityButton + }, this.pingBtnModel); + + this.handleKeyHandler = this.handleKeyEvent.bindAsEventListener(this); + this.controller.listen('messageField', Mojo.Event.propertyChange, this.handleKeyHandler); + + this.pingItHandler = this.pingIt.bindAsEventListener(this); + this.controller.listen('pingBtn', Mojo.Event.tap, this.pingItHandler); + + this.activateWindowHandler = this.activateWindow.bindAsEventListener(this); + this.controller.listen(this.controller.stageController.document, Mojo.Event.activate, this.activateWindowHandler); +}; + +MainAssistant.prototype.activateWindow = function() +{ + this.askForKey(); +}; + +MainAssistant.prototype.toggleTitleMenu = function() +{ + if (!this.prefs.showTitle) + { + this.controller.get('titleRow').hide(); + this.focusField = this.controller.get('messageField'); + this.showTitleMenuItem.label = 'Show Title'; + } + else + { + this.controller.get('titleRow').show(); + this.focusField = this.controller.get('titleField'); + this.showTitleMenuItem.label = 'Hide Title'; + } +}; + +MainAssistant.prototype.togglePingButton = function() +{ + Mojo.Log.info("togglePingButton"); + + if (this.hasConnectivity) + { + this.pingBtnModel.disabled = (this.messageModel.value.length == 0); + } + else + { + this.pingBtnModel.disabled = true; + } + + this.controller.modelChanged(this.pingBtnModel); +}; + +MainAssistant.prototype.activate = function(event) +{ + //this.askForKey(); +}; + +MainAssistant.prototype.deactivate = function(event) +{ + this.cookieData.put(this.prefs); + //this.cookieData.remove(); +}; + +MainAssistant.prototype.cleanup = function() +{ + this.controller.stopListening('pingBtn', Mojo.Event.tap, this.pingItHandler); + this.controller.stopListening('messageField', Mojo.Event.propertyChange, this.handleKeyHandler); + this.controller.stopListening(this.controller.stageController.document, Mojo.Event.activate, this.activateWindowHandler); +}; + + +MainAssistant.prototype.handleCommand = function(event) +{ + if (event.type == Mojo.Event.command) + { + switch (event.command) + { + case 'do-about': + var currentScene = this.controller.stageController.activeScene(); + currentScene.showAlertDialog( + { + allowHTMLMessage: true, + onChoose: function(value) + { + }, + message: '#{title} v#{version}
© 2010, Erik C. Thauvin

This application uses the Ping.fm API but is not endorsed or certified by Ping.fm'.interpolate( + { + title: Mojo.Controller.appInfo.title, + version: Mojo.Controller.appInfo.version + }), + choices: [ + { + label: 'OK', + value: '' + }] + }); + break; + + case 'do-title': + this.prefs.showTitle = !this.prefs.showTitle; + this.toggleTitleMenu(); + + this.focusField.mojo.focus(); + + break; + + case 'do-methods-refresh': + this.resetMethods(); + this.updateMethods(); + + this.focusField.mojo.focus(); + break; + + case 'do-key-reset': + this.resetMethods(); + this.prefs.user_app_key = null; + + this.askForKey(); + break; + + default: + break; + + } + } +}; + +MainAssistant.prototype.handleKeyEvent = function(event) +{ + var len = this.messageMaxLen - this.messageModel.value.length; + + if (len < 0) + { + this.controller.get('cntLabel').update('' + len + ''); + } + else + { + this.controller.get('cntLabel').update(len); + } + + this.togglePingButton(); +}; + +MainAssistant.prototype.askForKey = function(event) +{ + if (this.prefs.user_app_key === null) + { + this.controller.showDialog( + { + template: 'main/key-dialog', + assistant: new KeyDialogAssistant(this, this.focusField) + }); + } +}; + +MainAssistant.prototype.pingIt = function() +{ + var message = this.messageModel.value; + + if (this.prefs.user_app_key === null) + { + this.pingButton.mojo.deactivate(); + this.askForKey(); + } + else if (message.length > 0) + { + this.pingBtnModel.label = 'Posting...'; + this.pingBtnModel.disabled = true; + this.controller.modelChanged(this.pingBtnModel); + + var method = this.methodModel.value; + var url = 'http://api.ping.fm/v1/user.post'; + + this.prefs.defaultMethod = method; + + var params = new Hash( + { + 'api_key': this.api_key, + 'user_app_key': this.prefs.user_app_key, + 'body': Base64.encode(message), + 'encoding': 'base64', + 'debug': this.debug + }); + + if (method.charAt(0) == '#') + { + url = 'http://api.ping.fm/v1/user.tpost'; + params.set('trigger', method.substring(1)); + } + else if (method.charAt(0) == '@') + { + params.set('service', method.substring(1)); + params.set('post_method', 'default'); + } + else + { + params.set('post_method', method); + } + + var title = this.titleModel.value; + if (title != '') + { + params.set('title', Base64.encode(title)); + } + + Mojo.Log.info('pingIt: ' + params.toQueryString()); + + var request = new Ajax.Request(url, + { + method: 'post', + parameters: params, + evalJSON: 'false', + onSuccess: this.pingItSuccess.bind(this), + onFailure: this.pingItFailure.bind(this) + }); + } + else + { + this.focusField.mojo.focus(); + this.pingButton.mojo.deactivate(); + } +}; + +MainAssistant.prototype.pingItSuccess = function(transport) +{ + this.pingButton.mojo.deactivate(); + this.pingBtnModel.label = this.pingBtnModel.original; + + if (transport.responseXML === null) + { + Mojo.Log.warn("pingItSuccess failure."); + Mojo.Controller.errorDialog("Invalid response from the Ping.fm API.", this.controller.window); + + this.pingBtnModel.disabled = false; + } + else + { + var rsp = transport.responseXML.getElementsByTagName('rsp'); + var status = rsp[0].getAttribute('status'); + + if (status == 'FAIL') + { + Mojo.Log.warn(transport.responseText); + Mojo.Controller.errorDialog(rsp[0].getElementsByTagName('message').item(0).textContent, this.controller.window); + this.pingBtnModel.disabled = false; + } + else + { + this.messageModel.value = ''; + this.titleModel.value = ''; + this.controller.modelChanged(this.messageModel); + this.controller.modelChanged(this.titleModel); + this.controller.get('cntLabel').update(this.messageMaxLen); + this.pingBtnModel.disabled = true; + + Mojo.Controller.getAppController().showBanner('Your message has been posted.', {}); + } + } + + this.controller.modelChanged(this.pingBtnModel); + this.focusField.mojo.focus(); + +}; + +MainAssistant.prototype.pingItFailure = function(transport) +{ + this.pingButton.mojo.deactivate(); + this.pingBtnModel.label = this.pingBtnModel.original; + this.pingBtnModel.disabled = false; + this.controller.modelChanged(this.pingBtnModel); + + this.transportFailure('pingItFailure', transport); +}; + +MainAssistant.prototype.resetMethods = function() +{ + this.updatedMethods.hasNoServices = true; + this.updatedMethods.hasNoTargets = true; + + this.prefs.methods.clear(); + for (var i = 0; i < this.defaultMethods.length; i++) + { + this.prefs.methods.push(this.defaultMethods[i]); + } + this.prefs.defaultMethod = this.defaultMethods[0].value; + + this.methodModel.value = this.prefs.defaultMethod; + this.controller.modelChanged(this.methodModel); +}; + +MainAssistant.prototype.updateMethods = function() +{ + if (this.prefs.user_app_key && this.hasConnectivity) + { + var request; + + if (this.updatedMethods.hasNoServices) + { + request = new Ajax.Request('http://api.ping.fm/v1/user.services', + { + method: 'post', + parameters: + { + 'api_key': this.api_key, + 'user_app_key': this.prefs.user_app_key + }, + evalJSON: 'false', + onSuccess: this.updateMethodsSuccess.bind(this), + onFailure: this.updateMethodsFailure.bind(this) + }); + } + + if (this.updatedMethods.hasNoTargets) + { + request = new Ajax.Request('http://api.ping.fm/v1/user.triggers', + { + method: 'post', + parameters: + { + 'api_key': this.api_key, + 'user_app_key': this.prefs.user_app_key + }, + evalJSON: 'false', + onSuccess: this.updateTriggersSuccess.bind(this), + onFailure: this.updateTriggersFailure.bind(this) + }); + } + } +}; + +MainAssistant.prototype.updateMethodsSuccess = function(transport) +{ + if (transport.responseXML === null) + { + Mojo.Log.warn("updateMethodsSuccess failure."); + this.updateMethods(); + } + else + { + this.updateMethods.hasNoServices = false; + + var services = transport.responseXML.getElementsByTagName('service'); + for (var i = 0; i < services.length; i++) + { + var id = '@' + services[i].getAttribute('id'); + var name = services[i].getAttribute('name'); + var trigger = services[i].getElementsByTagName('trigger').item(0).textContent; + + this.prefs.methods.push( + { + label: name + ' (' + trigger + ')', + value: id + }); + + if (this.prefs.defaultMethod == id) + { + this.methodModel.value = id; + this.controller.modelChanged(this.methodModel); + } + } + + Mojo.Controller.getAppController().showBanner('Methods successfully updated.', {}); + } +}; + + +MainAssistant.prototype.updateMethodsFailure = function(transport) +{ + this.transportFailure('updateMethodFailure', transport); +}; + +MainAssistant.prototype.updateTriggersSuccess = function(transport) +{ + if (transport.responseXML === null) + { + Mojo.Log.warn("updateTriggersSuccess failure."); + this.updateMethods(); + } + else + { + this.updateMethods.hasNoTargets = false; + + var triggers = transport.responseXML.getElementsByTagName('trigger'); + + for (var i = 0; i < triggers.length; i++) + { + var id = '#' + triggers[i].getAttribute('id'); + //var method = triggers[i].getAttribute('method'); + + this.prefs.methods.unshift( + { + label: id, + value: id + }); + + if (this.prefs.defaultMethod == id) + { + this.methodModel.value = id; + this.controller.modelChanged(this.methodModel); + } + } + } +}; + +MainAssistant.prototype.updateTriggersFailure = function(transport) +{ + this.transportFailure('updateTriggersFailure', transport); +}; + + +MainAssistant.prototype.handleConnectivity = function(status) +{ + if (status.isInternetConnectionAvailable === true) + { + this.hasConnectivity = true; + } + else + { + this.hasConnectivity = false; + Mojo.Controller.getAppController().showBanner('No connectivity to the Internet.', {}); + } + + this.togglePingButton(); +}; + +MainAssistant.prototype.checkConnectivity = function() +{ + this.controller.serviceRequest('palm://com.palm.connectionmanager', + { + method: 'getstatus', + parameters: + { + subscribe: true + }, + onSuccess: this.handleConnectivity.bind(this) + }); +}; + +MainAssistant.prototype.transportFailure = function(caller, transport) +{ + Mojo.Log.error(caller + ': ' + transport.responseText); + Mojo.Controller.errorDialog('Error status #{status} returned from Ping.fm API request.'.interpolate( + { + status: transport.status + }), this.controller.window); +}; + diff --git a/Ping.fm/app/assistants/stage-assistant.js b/Ping.fm/app/assistants/stage-assistant.js new file mode 100644 index 0000000..6eed90b --- /dev/null +++ b/Ping.fm/app/assistants/stage-assistant.js @@ -0,0 +1,8 @@ +function StageAssistant() +{ +} + +StageAssistant.prototype.setup = function() +{ + this.controller.pushScene('main'); +}; diff --git a/Ping.fm/app/helpers/base64.js b/Ping.fm/app/helpers/base64.js new file mode 100644 index 0000000..0221530 --- /dev/null +++ b/Ping.fm/app/helpers/base64.js @@ -0,0 +1,86 @@ +// --------------------------------------------------------------------------- +// Base64 +// +// Encodes binary files into base64 strings. +// Taken from the Palm's Data sample application. +// --------------------------------------------------------------------------- +var Base64 = + { + // private property + _keyStr: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=', + + // public method for encoding + encode: function(input) + { + var output = ''; + var chr1, chr2, chr3, enc1, enc2, enc3, enc4; + var i = 0; + + while (i < input.length) + { + + chr1 = input.charCodeAt(i++); + chr2 = input.charCodeAt(i++); + chr3 = input.charCodeAt(i++); + + enc1 = chr1 >> 2; + enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); + enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); + enc4 = chr3 & 63; + + if (isNaN(chr2)) + { + enc3 = enc4 = 64; + } + else if (isNaN(chr3)) + { + enc4 = 64; + } + + output = output + + this._keyStr.charAt(enc1) + + this._keyStr.charAt(enc2) + + this._keyStr.charAt(enc3) + + this._keyStr.charAt(enc4); + + } + + return output; + }, + + // public method for decoding + decode: function(input) + { + var output = ''; + var chr1, chr2, chr3; + var enc1, enc2, enc3, enc4; + var i = 0; + + input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ''); + + while (i < input.length) + { + + enc1 = this._keyStr.indexOf(input.charAt(i++)); + enc2 = this._keyStr.indexOf(input.charAt(i++)); + enc3 = this._keyStr.indexOf(input.charAt(i++)); + enc4 = this._keyStr.indexOf(input.charAt(i++)); + + chr1 = (enc1 << 2) | (enc2 >> 4); + chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); + chr3 = ((enc3 & 3) << 6) | enc4; + + output = output + String.fromCharCode(chr1); + + if (enc3 != 64) + { + output = output + String.fromCharCode(chr2); + } + if (enc4 != 64) + { + output = output + String.fromCharCode(chr3); + } + } + return output; + } + }; diff --git a/Ping.fm/app/views/main/key-dialog.html b/Ping.fm/app/views/main/key-dialog.html new file mode 100644 index 0000000..1ea5907 --- /dev/null +++ b/Ping.fm/app/views/main/key-dialog.html @@ -0,0 +1,18 @@ +
+
+ Enter Ping.fm Mobile Key +
+
+ Get your Mobile Key +
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Ping.fm/app/views/main/main-scene.html b/Ping.fm/app/views/main/main-scene.html new file mode 100644 index 0000000..77ee30c --- /dev/null +++ b/Ping.fm/app/views/main/main-scene.html @@ -0,0 +1,52 @@ +
+
+
+
+ Ping.fm +
+
+
+
+ Ping My +
+
+
+
+
+
+
+
+
+
+
+
+ Your Message +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 140 +
+
+
+
+
+
+
+
+
diff --git a/Ping.fm/appinfo.json b/Ping.fm/appinfo.json new file mode 100644 index 0000000..361a8f4 --- /dev/null +++ b/Ping.fm/appinfo.json @@ -0,0 +1,10 @@ +{ + "id": "net.thauvin.erik.webos.pingfm", + "version": "1.0.0", + "vendor": "Erik C. Thauvin", + "type": "web", + "theme": "light", + "main": "index.html", + "title": "Ping.fm", + "icon": "icon.png" +} diff --git a/Ping.fm/ect-logo.png b/Ping.fm/ect-logo.png new file mode 100644 index 0000000..64abdfc Binary files /dev/null and b/Ping.fm/ect-logo.png differ diff --git a/Ping.fm/framework_config.json b/Ping.fm/framework_config.json new file mode 100644 index 0000000..078e742 --- /dev/null +++ b/Ping.fm/framework_config.json @@ -0,0 +1,3 @@ +{ + "logLevel":0 +} \ No newline at end of file diff --git a/Ping.fm/icon.png b/Ping.fm/icon.png new file mode 100644 index 0000000..860e428 Binary files /dev/null and b/Ping.fm/icon.png differ diff --git a/Ping.fm/images/mini-icon.png b/Ping.fm/images/mini-icon.png new file mode 100644 index 0000000..0822a7a Binary files /dev/null and b/Ping.fm/images/mini-icon.png differ diff --git a/Ping.fm/index.html b/Ping.fm/index.html new file mode 100644 index 0000000..1da9438 --- /dev/null +++ b/Ping.fm/index.html @@ -0,0 +1,14 @@ + + + + + Ping.fm +