Compare commits

37 Commits
Author SHA1 Message Date
codepoet80 71e143ecb1 build with new dependencies 2022-09-17 15:01:51 -04:00
codepoet80 4d56a992a0 update dependencies and attributions 2022-09-17 14:59:05 -04:00
codepoet80 78568bce56 sync from new PC 2022-01-01 14:41:54 -05:00
CodePoet80 4a1b85936e updater 2021-12-11 15:00:56 -05:00
CodePoet80 3dac57e20d update updater 2021-12-11 13:05:20 -05:00
CodePoet80 cdfa4013ee update updater 2021-12-11 12:50:47 -05:00
CodePoet80 9979b509df upgrade updater 2021-11-23 19:22:55 -05:00
CodePoet80 54f905a458 bug fix background sync 2021-10-17 20:34:40 -04:00
CodePoet80 295d774488 remove debug 2021-06-18 18:58:03 -04:00
CodePoet80 ab11c4ea57 bump version 2021-06-05 19:19:13 -04:00
CodePoet80 ef7cb5a2fb update readme 2021-06-01 14:09:11 -04:00
CodePoet80 5ca6c24ea0 tweak styles 2021-05-29 22:56:15 -04:00
CodePoet80 eca2e7537a put back download option 2021-05-29 22:49:32 -04:00
CodePoet80 be4f547873 more bug fixes 2021-05-29 21:24:48 -04:00
CodePoet80 ebe00543aa parts and service group for the forest moon 2021-05-29 20:40:02 -04:00
CodePoet80 4816b817dc fix bugs 2021-05-29 19:49:04 -04:00
CodePoet80 7b772c1d99 update links...again, and mini icon 2021-05-29 19:08:42 -04:00
CodePoet80 cf913f7900 change links again... i hate facebook 2021-05-29 16:45:08 -04:00
CodePoet80 323b8a81a0 change links again 2021-05-29 16:05:12 -04:00
CodePoet80 5bd35db2e0 change links 2021-05-29 15:55:28 -04:00
CodePoet80 dc49a6dbd9 tweak some strings 2021-05-29 15:42:32 -04:00
CodePoet80 af90efd60d 1.0 release candidate 2021-05-29 15:29:05 -04:00
CodePoet80 e32fcbbea2 download timer and camera added 2021-05-29 13:05:58 -04:00
CodePoet80 561b54bf97 configurable alarm time 2021-05-29 10:06:07 -04:00
CodePoet80 cbb507b4cb background sycn and dashboard 2021-05-28 18:18:43 -04:00
CodePoet80 ea2c54fcf4 improve error handling everywhere 2021-05-28 09:12:06 -04:00
CodePoet80 00657e6fb0 add default error handler 2021-05-27 17:17:07 -04:00
CodePoet80 946d21b431 improved error handling 2021-05-27 17:10:49 -04:00
CodePoet80 1f99489737 switch to using credential 2021-05-27 13:58:13 -04:00
CodePoet80 4dc4e96b85 fix up notifications 2021-05-27 12:33:03 -04:00
CodePoet80 b22e1ec4a2 finish detail menu, prep for query launch 2021-05-26 21:02:28 -04:00
CodePoet80 3f951e75d9 prep for sub menu 2021-05-26 20:05:29 -04:00
CodePoet80 c5a0997c11 tweak create key 2021-05-26 19:59:09 -04:00
CodePoet80 76149a40ac add example 2021-05-26 19:10:25 -04:00
CodePoet80 d61bee6ab3 add support for create key 2021-05-26 19:09:35 -04:00
CodePoet80 a990fca7bc bug fixes and tweaks 2021-05-26 18:03:04 -04:00
CodePoet80 4c9b302df1 first commit 2021-05-26 17:51:26 -04:00
76 changed files with 2635 additions and 7608 deletions

No files matched your search

+1 -3
View File
@@ -1,4 +1,2 @@
secrets.js
.DS_Store
framework_config.json
_bin/
secrets.js
+2 -2
View File
@@ -1,6 +1,6 @@
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
echo copying latest common components
cp $DIR/../../webos-common/Mojo/updater-model.js $DIR/../app/models/updater-model.js
cp $DIR/../../webos-common/Mojo/system-model.js $DIR/../app/models/system-model.js
cp $DIR/../../webos-common/Mojo/com.wosa.mojo.additions.js $DIR/../app/com.wosa.mojo.additions.js
mkdir -p $DIR/../_bin
palm-package $DIR/../ -o $DIR/../_bin
palm-package $DIR/../ -o $DIR/../_bin
+2 -2
View File
@@ -1,5 +1,5 @@
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
echo copying latest common components
cp $DIR/../../webos-common/Mojo/updater-model.js $DIR/../app/models/updater-model.js
cp $DIR/../../webos-common/Mojo/system-model.js $DIR/../app/models/system-model.js
cp $DIR/../../webos-common/Mojo/com.wosa.mojo.additions.js $DIR/../app/com.wosa.mojo.additions.js
palm-run $DIR/../
palm-run $DIR/../
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2022 Jon W
Copyright (c) 2022 webOS Archive
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+7 -35
View File
@@ -1,40 +1,12 @@
# Simple Chat client app for webOS
# Share Space app for webOS
![App Icon](icon.png)
![Share Space Icon](icon.png)
SimpleChat client for legacy Palm/HP webOS devices, depends on back-end services:
Share Space is a sharing service app for legacy Palm/HP webOS devices, which depends on the back-end service listed below.
You can download it for your webOS Device from the [webOS Archive App Museum II](appcatalog.webosarchive.org).
+ [simplechat-service](https://github.com/codepoet80/simplechat-service)
Tested on Pre, Pre2, Pre3, Veer and Touchpad.
+ [simplechat-discordbot](https://github.com/codepoet80/simplechat-discordbot) (Optional)
Uses [Sharing Service](https://github.com/webosarchive/sharing-service) which is hosted by [webOSArchive](http://www.webosarchive.org) for the webOS community without guarantee of privacy or performance. Illegal or illicit use strictly prohibited.
You can also self-host the services.
## What is This?
This is an app for the defunct mobile webOS platform, made by Palm and later acquired by HP. It runs on devices like the Palm Pre or Pixi, or the HP
Pre3 or TouchPad.
webOS technology was acquired by LG and repurposed for TVs and IoT devices, but they made significant changes and this app will not run on those platforms.
Releases of this app, and many other new and restored apps, can be found in the [webOS Archive App Museum](http://appcatalog.webosarchive.org).
## Why?
Aside from being a fan of the platform, the author thinks consumers have lost out now that the smart phone ecosystem has devolved into a duopoly.
Apple and Google take turns copying each other, and consumers line up to buy basically the same new phone every year. The era when webOS, Blackberry and
Windows Phone were serious competitors was marked by creativity in form factor and software development, which has been lost. This app represents a (futile)
attempt to keep webOS mobile devices useful for as long as possible.
The website [http://www.webosarchive.org](http://www.webosarchive.org) recovers, archives and maintains material related to development, and hosts services
that restore functionality to webOS devices. A small but active [community](http://www.webosarchive.org/discord) of users take advantage of these services to keep their retro devices alive.
## How?
Mobile webOS was truly a web-derived platform. Based on Linux, and able to run properly compiled Linux binaries, developers could get raw resources access (including GPU) through a PDK (Plug-in Development Kit) but most apps were written in some flavor of Javascript, interacting with a WebKit-based browser. The toolkits were heavily optimized for the devices, and web-based apps usually felt pretty close to native. Services could be written using NodeJS and talk to each other through API calls structured to look like web service calls. App front-ends were usually written in either the Mojo (pre-tablet) or Enyo (tablet and newer phones) Javascript frameworks. Enyo apps can often be run with only minor modification in any WebKit based browser (eg: Safari or Chrome).
You can learn more about these frameworks at the restored [SDK](http://sdk.webosarchive.org).
webOS devices can be found cheaply on eBay, and while the phones will cease to be useful as phones when the 3G shutdown is through, both the phones and the Touchpad can be used around the home for a variety of [fun and useful things](http://www.webosarchive.org/docs/thingstotry/).
If you have a device, instructions for activating, getting online and getting apps installed can be found in the [webOS Archive Docs section](http://www.webosarchive.org/docs/activate/).
You can also self-host the service, see the [instructions here](https://github.com/webosarchive/sharing-service/blob/main/README.md).
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

+68 -52
View File
@@ -3,85 +3,101 @@ In the app assistant, we setup some app-wide global objects and handle different
*/
var appModel = null;
var updaterModel = null;
var systemModel = null;
var serviceModel = null;
var MainStageName = "main";
var welcomed = false;
Mojo.Additions = Additions;
var InDockMode = false;
function AppAssistant() {
appModel = new AppModel();
updaterModel = new UpdaterModel();
serviceModel = new ShareServiceModel();
systemModel = new SystemModel();
serviceModel = new ServiceModel();
Mojo.Additions = Additions;
}
//This function will handle relaunching the app when an alarm goes off(see the device/alarm scene)
AppAssistant.prototype.handleLaunch = function(params) {
Mojo.Log.info("SimpleChat is Launching! Launch params: " + JSON.stringify(params));
Mojo.Log.info("Share Space is Launching! Launch params: " + JSON.stringify(params));
//Load preferences
appModel.LoadSettings();
Mojo.Log.info("settings now: " + JSON.stringify(appModel.AppSettingsCurrent));
if (!appModel.AppSettingsCurrent["BackgroundUpdate"]) {
appModel.AppSettingsCurrent["BackgroundUpdate"] = "00:30:00";
if (!appModel.AppSettingsCurrent["AutoDownloadTime"]) {
appModel.AppSettingsCurrent["AutoDownloadTime"] = appModel.AppSettingsDefaults["AutoDownloadTime"];
appModel.SaveSettings();
}
//Reset alarms
systemModel.ClearSystemAlarm("SimpleChat");
if (appModel.AppSettingsCurrent["BackgroundUpdate"] && appModel.AppSettingsCurrent["BackgroundUpdate"] != "" && appModel.AppSettingsCurrent["BackgroundUpdate"] != -1)
systemModel.SetSystemAlarmRelative("SimpleChat", appModel.AppSettingsCurrent["BackgroundUpdate"]);
appModel.EstablishAlarms();
var mainStage = this.controller.getStageProxy("main"); //get the proxy for the stage if it already exists (eg: app is currently open)
if (mainStage) //If the stage exists, use it
{
Mojo.Log.info("Found existing main stage, app was already running");
var stageController = this.controller.getStageController("main");
if (!params || params["action"] == undefined) //If no action parameters was passed, this is a normal launch
if (!params || !params["action"]) {
var mainStage = this.controller.getStageProxy("main"); //get the proxy for the stage if it already exists (eg: app is currently open)
if (mainStage) //If the stage exists, use it
{
//if there was a share action, load with that
if (params && params["newshare"] != undefined) {
appModel.LaunchQuery = decodeURI(params["newshare"]);
Mojo.Log.info("This is re-launch with share action: " + appModel.LaunchQuery);
} else {
Mojo.Log.info("This is a normal re-launch");
}
Mojo.Log.info("Found existing main stage, app was already running");
Mojo.Log.info("This is a non-alarm re-launch");
var stageController = this.controller.getStageController("main");
stageController.activate(); //bring existing stage into focus
return;
} else //If parameters were passed, this is a launch from a system alarm
{
Mojo.Log.warn("This is a re-launch with parameters: " + JSON.stringify(params) + ". Safe to ignore, since app is already running.");
appModel.ShowNotificationStage();
return;
}
} else //If no stage exists, determine if we should make one
{
Mojo.Log.info("Did not find existing main stage, app is not running");
if (params)
this.handleParameterLaunch(params, stageController);
if (!params || params["action"] == undefined) //If no action parameters was passed, this is a normal launch
} else //If not, determine if we should make one
{
var currVersion = Mojo.Controller.appInfo.version;
//if there was a share action, load with that
if (params && params["newshare"] != undefined) {
appModel.LaunchQuery = decodeURI(params["newshare"]);
Mojo.Log.info("This is launch with share action: " + appModel.LaunchQuery);
} else {
Mojo.Log.info("This is a normal launch of version " + currVersion);
}
Mojo.Log.info("Did not find existing main stage, app is not running");
Mojo.Log.info("This is a non-alarm launch of version " + Mojo.Controller.appInfo.version);
var stageArguments = { name: MainStageName, lightweight: true };
this.controller.createStageWithCallback(stageArguments, function(stageController) {
stageController.pushScene(MainStageName);
if (params)
this.handleParameterLaunch(params, stageController);
}.bind(this));
return;
} else //If parameters were passed, this is a launch from a system alarm
{
Mojo.Log.info("This is an alarm launch: " + JSON.stringify(params));
appModel.ShowNotificationStage();
return;
}
} else {
this.handleParameterLaunch(params);
}
};
AppAssistant.prototype.handleParameterLaunch = function(params) {
Mojo.Log.info("Launch params: " + JSON.stringify(params));
//Touch2Share Launch (goes to main)
if (params["sendDataToShare"]) {
Mojo.Log.info("Launch with Touch2Share request!");
systemModel.SendDataForTouch2Share(appModel.CurrentShareURL);
}
};
//Alarm Launch (goes to dashboard)
else if (params.action && params.action == "BackgroundDownload"){
Mojo.Log.info("Alarm launch for background sync...");
//TODO: Check if in Dock Mode (and remember)
systemModel.GetDisplayState(function(response) {
Mojo.Log.info("Called back from GetDisplayState with response: " + JSON.stringify(response));
InDockMode = false;
if (response && response.state == "on" && response.active == false) {
InDockMode = true;
systemModel.SetDisplayState("unlock");
systemModel.SetDisplayState("on");
}
appModel.ShowDownloaderStage();
}.bind(this));
}
//JustType or other (goes to main)
else {
Mojo.Log.info("Launch with item request to be handled by Main scene...");
appModel.LaunchQuery = params;
var mainStage = this.controller.getStageProxy(MainStageName);
if (mainStage) {
var stageController = this.controller.getStageController(MainStageName);
stageController.swapScene({ transition: Mojo.Transition.crossFade, name: MainStageName });
}
else {
var stageArguments = { name: MainStageName, lightweight: true };
this.controller.createStageWithCallback(stageArguments, function(stageController) {
stageController.pushScene(MainStageName);
}.bind(this));
}
}
}
-140
View File
@@ -1,140 +0,0 @@
/*
This alarm scene is used for Touchpads, which will only pretend to change settings if running in the background
Launching this scene forces the Touchpad to wake up to deal with presenting it, and when it does we have a good
chance of successfully changing the settings. We can then close this window. All the smarts for this are in stage assistant.
*/
function DashboardAssistant(argFromPusher) {
this.passedArguments = argFromPusher;
this.lastMessageCount = 0;
}
DashboardAssistant.prototype.setup = function() {
Mojo.Log.info("Dashboard notification stage setup at " + new Date());
this.displayDashboard(Mojo.Controller.appInfo.title, "Checking for new messages...");
this.serviceEndpointBase = appModel.ServiceEndpointBase;
if (appModel.AppSettingsCurrent["UseCustomEndpoint"] && appModel.AppSettingsCurrent["EndpointURL"]) {
this.serviceEndpointBase = appModel.AppSettingsCurrent["EndpointURL"];
}
if (!appModel.AppSettingsCurrent["AlertSound"] || appModel.AppSettingsCurrent["AlertSound"] == "") {
appModel.AppSettingsCurrent["AlertSound"] = "Subtle (short)";
}
//Event handlers
Mojo.Event.listen(this.controller.get("dashboardinfo"), Mojo.Event.tap, this.handleTap.bind(this));
}
DashboardAssistant.prototype.activate = function(event) {
Mojo.Log.info("Dashboard activating!");
this.clientId = appModel.ClientId;
if (appModel.AppSettingsCurrent["UseClientAPIKey"] && appModel.AppSettingsCurrent["ClientAPIKey"]) {
this.clientId = appModel.AppSettingsCurrent["ClientAPIKey"];
}
this.checkForMessages();
}
DashboardAssistant.prototype.checkForMessages = function() {
Mojo.Log.info("Checking for new messages in Dashboard...");
serviceModel.getChats(this.serviceEndpointBase, this.clientId, function(response) {
var appController = Mojo.Controller.getAppController();
if (response != null && response != "") {
var responseObj = JSON.parse(response);
if (responseObj.status == "error") {
Mojo.Log.error("Error message from server during Dashboard message check: " + responseObj.msg);
appController.closeStage("dashboard");
} else {
if (responseObj.messages && responseObj.messages.length > 0) {
var newMessageCount = this.findNewMessageCount(appModel.AppSettingsCurrent["LastKnownMessage"], responseObj.messages);
if (newMessageCount > 0) {
Mojo.Log.info("Found new chat on server during Dashboard message check!");
var appController = Mojo.Controller.getAppController();
var mainStage = appController.getStageController("main");
if (!mainStage) { //If the main app window is open,
if (newMessageCount > this.lastMessageCount) {
systemModel.PlayAlertSound(appModel.AppSettingsCurrent["AlertSound"]);
this.lastMessageCount = newMessageCount;
}
this.displayDashboard(Mojo.Controller.appInfo.title, "New messages have arrived!", newMessageCount);
} else {
this.displayDashboard(Mojo.Controller.appInfo.title, "New messages have arrived!");
}
} else {
Mojo.Log.info("No new chats on server during Dashboard message check.");
appController.closeStage("dashboard");
}
} else {
Mojo.Log.warn("Chat results were empty during scheduled Dashboard message check. This is unlikely; server, API or connectivity problem possible");
appController.closeStage("dashboard");
}
}
} else {
Mojo.Log.error("No usable response from server during Dashboard message check: " + response);
appController.closeStage("dashboard");
}
}.bind(this));
}
DashboardAssistant.prototype.findNewMessageCount = function(LastKnownMessage, newMessages) {
var actuallyNewMessages = [];
var startCounting = false;
for (var j = 0; j < newMessages.length; j++) {
if (startCounting) {
actuallyNewMessages.push(newMessages[j].uid);
appModel.AppSettingsCurrent["LastKnownMessage"] = newMessages[j].uid;
Mojo.Log.info("Dashboard counting: " + newMessages[j].uid);
}
if (newMessages[j].uid == LastKnownMessage) {
startCounting = true;
}
}
return actuallyNewMessages.length;
}
DashboardAssistant.prototype.handleTap = function(event) {
Mojo.Log.info("Dashboard tapped!");
var appController = Mojo.Controller.getAppController();
var mainStage = appController.getStageProxy("main");
if (!mainStage) {
systemModel.LaunchApp(Mojo.Controller.appInfo.id);
appController.closeAllStages();
} else {
mainStage.activate();
appController.closeStage("dashboard")
}
}
DashboardAssistant.prototype.handleDrag = function(event) {
var infoElement = this.controller.get("dashboardinfo");
infoElement.style.opacity = "0.5"; //TODO: this only seems to effect the icon
}
DashboardAssistant.prototype.handleDragEnd = function(event) {
Mojo.Log.info("Dashboard drag end!");
var appController = Mojo.Controller.getAppController();
appController.closeAllStages();
}
DashboardAssistant.prototype.displayDashboard = function(title, message, count) {
var infoElement = this.controller.get("dashboardinfo");
var info = { title: title, message: message };
if (count) {
info.count = count;
info.showCount = "inline";
} else {
info.showCount = "none";
}
var renderedInfo = Mojo.View.render({ object: info, template: "dashboard/item-info" });
infoElement.innerHTML = renderedInfo;
this.controller.getSceneScroller().mojo.revealTop(true);
}
DashboardAssistant.prototype.deactivate = function(event) {
Mojo.Event.stopListening(this.controller.get("dashboardinfo"), Mojo.Event.tap, this.handleTap);
}
// Cleanup anything we did in setup function
DashboardAssistant.prototype.cleanup = function() {
Mojo.Log.info("Dashboard notification stage closing at " + new Date());
appModel.SaveSettings();
}
+253
View File
@@ -0,0 +1,253 @@
function DetailAssistant() {
/* this is the creator function for your scene assistant object. It will be passed all the
additional parameters (after the scene name) that were passed to pushScene. The reference
to the scene controller (this.controller) has not be established yet, so any initialization
that needs the scene controller should be done in the setup function below. */
}
DetailAssistant.prototype.setup = function() {
/* setup widgets here */
//Menu
this.appMenuAttributes = { omitDefaultItems: true };
this.appMenuModel = {
label: "Settings",
items: [{
label: $L('Select All'),
command: Mojo.Menu.selectAllCmd,
shortcut: 'a',
disabled: false
}, {
label: $L('Copy'),
command: Mojo.Menu.copyCmd,
shortcut: 'c',
disabled: false
}]
};
this.controller.setupWidget(Mojo.Menu.appMenu, this.appMenuAttributes, this.appMenuModel);
//Text content field
this.controller.setupWidget("divTextContent",
this.attributes = {
multiline: true,
enterSubmits: false,
focus: false
},
this.model = {
value: "",
disabled: false
}
);
//OK Button
this.controller.setupWidget("btnOK",
this.attributes = {
},
this.model = {
label : "OK",
disabled: false
}
);
//Command Menu
this.cmdMenuAttributes = {
spacerHeight: 0,
menuClass: 'no-fade'
},
this.cmdMenuModel = {
visible: true,
items: [{
items: [
{ label: 'Back', icon: 'back', command: 'do-goBack' }
]
},
{
items: [
]
},
{
items: [
{ label: 'Share', command: 'do-share' },
{ label: 'Save', icon: 'save', command: 'do-save' }
]
}
]
};
this.controller.setupWidget(Mojo.Menu.commandMenu, this.cmdMenuAttributes, this.cmdMenuModel);
/* add event handlers to listen to events from widgets */
};
DetailAssistant.prototype.activate = function(event) {
//Bind selected podcast to scene elements
Mojo.Log.info(JSON.stringify(appModel.LastShareSelected));
this.controller.get("divShareTitle").innerHTML = "Shared: " + appModel.ConvertTimeStamp(appModel.LastShareSelected.timestamp, true);
//Calculate links
if (appModel.LastShareSelected && appModel.LastShareSelected.contenttype && appModel.LastShareSelected.contenttype.indexOf("image") != -1) { //image links
var link = serviceModel.MakeShareURL(appModel.AppSettingsCurrent["Username"], appModel.LastShareSelected.guid, "image");
appModel.CurrentShareURL = link;
this.controller.get("divShareLinks").innerHTML += "• <a href='" + link + "'>View in Browser</a>";
this.controller.get("divShareLinks").innerHTML += " &nbsp;(<a href='javascript:this.doCopy(\"" + link + "\")'>Copy Link</a>)<br>";
link = this.makeDownloadURL(appModel.LastShareSelected.thumbnail, "i");
this.downloadLink = link;
} else { //text links
var link = serviceModel.MakeShareURL(appModel.AppSettingsCurrent["Username"], appModel.LastShareSelected.guid, "t");
appModel.CurrentShareURL = link;
this.downloadLink = link;
this.controller.get("divShareLinks").innerHTML = "• <a href='" + link + "'>View in Browser</a>";
this.controller.get("divShareLinks").innerHTML += " &nbsp;(<a href='javascript:this.doCopy(\"" + link + "\")'>Copy Link</a>)<br>";
}
if (appModel.AppSettingsCurrent["DebugMode"]) { //If debugging, show links
this.controller.get("divShareInfo").style.display = "block";
}
//Show actual content
if (appModel.LastShareSelected.contenttype == "application/json") {
this.controller.get("divTextContent").innerHTML = "<pre>" + JSON.stringify(appModel.LastShareSelected.content, null, 1) + "</pre>"
} else if (appModel.LastShareSelected.contenttype == "text/plain") {
this.controller.get("divTextContent").innerHTML = "<pre>" + appModel.LastShareSelected.content + "</pre>"
} else {
var useImg = appModel.LastShareSelected.content;
useImg = useImg.split("?");
useImg = useImg[0] + "?img=" + useImg[1] + "&size=" + this.setPhotoSize();
Mojo.Log.info("Rendering img: " + useImg);
this.controller.get("divImageContent").innerHTML = "<img src='" + useImg + "' style='max-width:90%;'>";
}
Mojo.Controller.getAppController().showBanner({ messageText: 'Touch2Share Ready!', icon: 'assets/notify.png' }, { source: 'notification' });
};
doCopy = function(link) {
Mojo.Log.info("Copy tapped for link " + link);
var stageController = Mojo.Controller.getAppController().getActiveStageController()
stageController.setClipboard(link);
Mojo.Controller.getAppController().showBanner({ messageText: 'Link copied!', icon: 'assets/notify.png' }, { source: 'notification' });
}
DetailAssistant.prototype.makeDownloadURL = function(thumbUrl, type) {
var newURL = thumbUrl;
newURL = newURL.replace("tthumb", type);
newURL = newURL.replace("ithumb", type);
return newURL;
}
DetailAssistant.prototype.setPhotoSize = function() {
switch(systemModel.DetectDevice()) {
case "TouchPad":
return 800;
break;
case "Pre3":
return 400;
break;
case "Pre":
return 300;
break;
case "Tiny":
return 280;
break;
default:
return 400;
}
}
//Handle menu and button bar commands
DetailAssistant.prototype.handleCommand = function(event) {
Mojo.Log.info("handling command button press for command: " + event.command);
if (event.type == Mojo.Event.command) {
var stageController = Mojo.Controller.getAppController().getActiveStageController();
switch (event.command) {
case 'do-goBack':
stageController.popScene();
break;
case 'do-share':
var itemsToShow = [
{ label: 'Open in Browser', command: 'do-browserOpen' },
{ label: 'Email Link', command: 'do-emailLink' },
{ label: 'Message Link', command: 'do-messageLink' },
{ label: 'Copy Link', command: 'do-copyLink' }
]
if (appModel.LastShareSelected.contenttype.indexOf("image") == -1) {
itemsToShow.push({ label: 'Copy Content', command: 'do-copyContent' });
}
this.controller.popupSubmenu({
onChoose: this.handlePopupChoose.bind(this, event.item),
//placeNear: Mojo.Menu.commandMenu,
items: itemsToShow
});
break;
case 'do-save':
var usePath = "sharespace/" + appModel.AppSettingsCurrent["Username"];
if (appModel.AppSettingsCurrent["UseCustomDownloadPath"] && appModel.AppSettingsCurrent["CustomDownloadPath"] != "")
usePath = appModel.AppSettingsCurrent["CustomDownloadPath"];
Mojo.Controller.getAppController().showBanner({ messageText: 'Downloading content...', icon: 'assets/notify.png' }, { source: 'notification' });
systemModel.DownloadFile(this.downloadLink, appModel.LastShareSelected.contenttype, usePath, appModel.LastShareSelected.guid, true);
break;
}
}
};
DetailAssistant.prototype.handlePopupChoose = function(task, command) {
Mojo.Log.info("Perform: ", command);
var stageController = Mojo.Controller.getAppController().getActiveStageController();
switch (command) {
case "do-browserOpen":
this.controller.serviceRequest("palm://com.palm.applicationManager", {
method: "launch",
parameters: {
id: 'com.palm.app.browser',
params: {
"target": appModel.CurrentShareURL
}
}
});
Mojo.Log.warn("target: " + appModel.CurrentShareURL);
break;
case "do-emailLink":
this.controller.serviceRequest("palm://com.palm.applicationManager", {
method: 'open',
parameters: {
id: "com.palm.app.email",
params: {
summary: "Check out this link",
text: appModel.CurrentShareURL
}
}
});
Mojo.Log.warn("target: " + appModel.CurrentShareURL);
break;
case "do-messageLink":
this.controller.serviceRequest('palm://com.palm.applicationManager', {
method: 'open',
parameters: {
id: 'com.palm.app.messaging',
params: {
messageText: "Check out this link: " + appModel.CurrentShareURL
}
}
});
Mojo.Log.warn("target: " + appModel.CurrentShareURL);
break;
case "do-copyLink":
stageController.setClipboard(appModel.CurrentShareURL);
Mojo.Controller.getAppController().showBanner({ messageText: 'Link copied!', icon: 'assets/notify.png' }, { source: 'notification' });
Mojo.Log.warn("target: " + appModel.CurrentShareURL);
break;
case "do-copyContent":
stageController.setClipboard(appModel.LastShareSelected.content);
Mojo.Controller.getAppController().showBanner({ messageText: 'Content copied!', icon: 'assets/notify.png' }, { source: 'notification' });
break;
}
}
DetailAssistant.prototype.deactivate = function(event) {
/* remove any event handlers you added in activate and do any other cleanup that should happen before
this scene is popped or another scene is pushed on top */
};
DetailAssistant.prototype.cleanup = function(event) {
/* this function should do any cleanup needed before the scene is destroyed as
a result of being popped off the scene stack */
};
+210
View File
@@ -0,0 +1,210 @@
/*
This alarm scene is used for Touchpads, which will only pretend to change settings if running in the background
Launching this scene forces the Touchpad to wake up to deal with presenting it, and when it does we have a good
chance of successfully changing the settings. We can then close this window. All the smarts for this are in stage assistant.
*/
var downloadMgrInt = null;
function DownloadAssistant(argFromPusher) {
this.passedArguments = argFromPusher;
this.downloadList = [];
}
DownloadAssistant.prototype.setup = function() {
Mojo.Log.info("Dashboard notification stage setup at " + new Date());
this.displayDashboard(Mojo.Controller.appInfo.title, "Checking for new shares...");
//Event handlers
Mojo.Event.listen(this.controller.get("dashboardinfo"), Mojo.Event.tap, this.handleTap.bind(this));
}
DownloadAssistant.prototype.activate = function(event) {
Mojo.Log.info("Dashboard activating!");
//Set options for service model
serviceModel.ForceHTTP = appModel.AppSettingsCurrent["ForceHTTP"];
serviceModel.UseCustomEndpoint = appModel.AppSettingsCurrent["UseCustomEndpoint"];
serviceModel.CustomEndpointURL = appModel.AppSettingsCurrent["EndpointURL"];
serviceModel.CustomShortURL = appModel.AppSettingsCurrent["ShortURL"];
serviceModel.CustomCreateKey = appModel.AppSettingsCurrent["CustomCreateKey"];
serviceModel.UseCustomClientId = appModel.AppSettingsCurrent["UseCustomClientId"];
serviceModel.CustomClientId = appModel.AppSettingsCurrent["CustomClientId"];
this.fetchShares();
}
DownloadAssistant.prototype.displayDashboard = function(title, message, count) {
var infoElement = this.controller.get("dashboardinfo");
var info = { title: title, message: message };
if (count) {
info.count = count;
info.showCount = "inline";
} else {
info.showCount = "none";
}
var renderedInfo = Mojo.View.render({ object: info, template: "download/item-info" });
infoElement.innerHTML = renderedInfo;
this.controller.getSceneScroller().mojo.revealTop(true);
}
DownloadAssistant.prototype.fetchShares = function() {
serviceModel.DoShareListRequest(appModel.AppSettingsCurrent["Username"], appModel.AppSettingsCurrent["Credential"], function(responseObj){
if (responseObj != null) {
if (responseObj.shares) {
//If we got a good looking response, find out what to download
Mojo.Log.info("Download dashboard ready to process share list: " + JSON.stringify(responseObj));
this.checkIfDownloadNeeded(appModel.AppSettingsCurrent["Username"], responseObj.shares, responseObj.accesslevel);
} else {
Mojo.Log.warn("Share list was empty in Download dashboard. Either there was no matching result, or there were server or connectivity problems.");
appModel.CloseNotificationStage();
}
} else {
Mojo.Log.error("No usable response from server while Download dashboard loading shares: " + response);
appModel.CloseNotificationStage();
}
}.bind(this), this.errorHandler.bind(this));
}
DownloadAssistant.prototype.checkIfDownloadNeeded = function(username, results, accessLevel) {
Mojo.Log.info("Determining which shares need to be downloaded...");
this.downloadList = [];
this.getFileListForUser(username, function(fileList) {
for (var i = 0; i < results.length; i++) {
if (results[i].guid) {
//Figure out what mimetype to use
if (results[i].contenttype == "image/jpeg")
ext = ".jpg";
else if (results[i].contenttype == "text/plain")
ext = ".txt";
else if (results[i].contenttype == "text/json")
ext = ".json";
else {
var ext = results[i].contenttype.split("/");
ext = ext[ext.length - 1];
ext = "." + ext;
}
var fileToCheck = results[i].guid + ext;
var found = false;
if (fileList.items) {
for (var f = 0;f < fileList.items.length;f ++){
if (fileList.items[f].name == fileToCheck) {
Mojo.Log.info("Already downloaded: " + fileToCheck);
found = true;
}
}
}
if (!found) {
var newURL = results[i].thumbnail;
newURL = newURL.replace("tthumb", "t");
newURL = newURL.replace("ithumb", "i");
Mojo.Log.info("Need to download: " + newURL);
this.downloadList.push(newURL);
var usePath = "sharespace/" + username;
if (appModel.AppSettingsCurrent["UseCustomDownloadPath"] && appModel.AppSettingsCurrent["CustomDownloadPath"] != "")
usePath = appModel.AppSettingsCurrent["CustomDownloadPath"];
systemModel.DownloadFile(newURL, results[i].contenttype, usePath, results[i].guid);
}
}
}
Mojo.Log.info("Files in download list: " + this.downloadList.length);
if (this.downloadList.length > 0) {
this.displayDashboard(Mojo.Controller.appInfo.title, "Downloading shares...", this.downloadList.length);
} else {
this.displayDashboard(Mojo.Controller.appInfo.title, "No new shares to download.");
}
downloadMgrInt = this.controller.window.setInterval(function() {
this.checkDownloadManagerStatus();
}.bind(this), 1500);
}.bind(this));
}
DownloadAssistant.prototype.getFileListForUser = function(username, callback) {
if (callback)
callback.bind(this);
Mojo.Log.info("Asking FileMgr service for list of files");
this.controller.serviceRequest('palm://ca.canucksoftware.filemgr', {
method: 'listFiles',
parameters: {
path: "/media/internal/sharespace/" + username + "/",
},
onSuccess: callback,
onFailure: callback
});
}
DownloadAssistant.prototype.checkDownloadManagerStatus = function() {
if (this.downloadList.length > 0) {
Mojo.Log.info("checking if download manager is done...");
this.controller.serviceRequest('palm://com.palm.downloadmanager/', {
method: 'listPending',
parameters: {},
onSuccess : function (response){
//Mojo.Log.info("List Pending success, results="+JSON.stringify(response));
if (response) {
if (response.count && response.count > 0) {
Mojo.Log.info("Remaining downloads: " + response.count);
this.displayDashboard(Mojo.Controller.appInfo.title, "Downloading shares...", response.count);
} else {
Mojo.Log.info("Download Manager completed all downloads!");
this.controller.window.clearInterval(downloadMgrInt);
if (InDockMode)
systemModel.SetDisplayState("dock");
appModel.CloseDashboardStageByName("download");
}
} else {
Mojo.Log.error("List response failure");
this.controller.window.clearInterval(downloadMgrInt);
appModel.CloseDashboardStageByName("download");
}
}.bind(this),
onFailure : function (e){
Mojo.Log.error("List Pending failure, results="+JSON.stringify(e));
this.controller.window.clearInterval(downloadMgrInt);
appModel.CloseDashboardStageByName("download");
}.bind(this)
});
} else {
if (InDockMode)
systemModel.SetDisplayState("dock");
appModel.CloseDashboardStageByName("download");
}
}
DownloadAssistant.prototype.handleTap = function(event) {
Mojo.Log.info("Dashboard tapped!");
var appController = Mojo.Controller.getAppController();
var mainStage = appController.getStageProxy("main");
if (!mainStage) {
systemModel.LaunchApp(Mojo.Controller.appInfo.id);
appController.closeAllStages();
} else {
mainStage.activate();
appController.closeStage("dashboard")
}
}
DownloadAssistant.prototype.handleDrag = function(event) {
var infoElement = this.controller.get("dashboardinfo");
infoElement.style.opacity = "0.5"; //TODO: this only seems to effect the icon
}
DownloadAssistant.prototype.handleDragEnd = function(event) {
Mojo.Log.info("Dashboard drag end!");
this.controller.window.clearInterval(downloadMgrInt);
appModel.CloseDashboardStageByName("download");
}
DownloadAssistant.prototype.errorHandler = function (errorText, callback) {
Mojo.Log.error("Error in Dashboard scene: " + errorText);
}
DownloadAssistant.prototype.deactivate = function(event) {
Mojo.Event.stopListening(this.controller.get("dashboardinfo"), Mojo.Event.tap, this.handleTap);
}
// Cleanup anything we did in setup function
DownloadAssistant.prototype.cleanup = function() {
Mojo.Log.info("Dashboard notification stage closing at " + new Date());
//Event handlers
Mojo.Event.stopListening(this.controller.get("dashboardinfo"), Mojo.Event.tap, this.handleTap);
appModel.SaveSettings();
}
@@ -1,83 +0,0 @@
/* Copyright 2010 Palm, Inc. All rights reserved. */
/*global Mojo, $L, Class, window, document, PalmSystem, AppAssistant, palmGetResource, Foundations, _, */
var EmoticonPickerDialogAssistant = function(sceneAssistant, onselect) {
this.sceneAssistant = sceneAssistant;
this.controller = sceneAssistant.controller;
this.onselect = onselect;
};
EmoticonPickerDialogAssistant.prototype.show = function() {
this.controller.showDialog({
template: 'main/emoticonpicker-dialog',
assistant: this
});
};
EmoticonPickerDialogAssistant.prototype.setup = function(widget) {
this.widget = widget;
var emoTable = this.controller.get('emo-table');
var emoticonList = [
"B-)",
">:(",
":'(",
":[",
":-!",
"X(",
":@",
"o_O",
":O",
">:-)",
"O:)",
"<3",
":-*",
":D",
":/",
":(",
":|",
":P",
";)",
":)"
];
var row = emoTable.insertRow();
var insertCell = this.insertCell;
emoticonList.forEach(function(emoticon) {
if (row.cells.length === 5) {
row = emoTable.insertRow(0);
}
insertCell(row, emoticon);
});
emoTable.addEventListener(Mojo.Event.tap, this.handleEmoticonSelect.bind(this));
this.controller.get('cancel_button').addEventListener(Mojo.Event.tap, this.handleClose.bind(this));
};
EmoticonPickerDialogAssistant.prototype.insertCell = function(row, emoticon) {
var cell = row.insertCell(0);
cell.innerHTML = Mojo.Format.runTextIndexer(emoticon.escapeHTML());
cell.setAttribute("emo", emoticon);
cell.style.height = "40px";
};
EmoticonPickerDialogAssistant.prototype.handleEmoticonSelect = function(event) {
event.stopPropagation(); // stop the tap because it causes the underlying text item to lose focus
event.preventDefault();
var td = event.target;
if (td && td.tagName !== "TD") {
td = event.target.up('td');
}
if (td) {
this.onselect(td.getAttribute("emo"));
}
this.widget.mojo.close();
};
EmoticonPickerDialogAssistant.prototype.handleClose = function(event) {
event.stopPropagation(); // stop the tap because it causes the underlying text item to lose focus
event.preventDefault();
this.widget.mojo.close();
};
+143
View File
@@ -0,0 +1,143 @@
function LoginAssistant(sceneAssistant, doneCallBack) {
this.doneCallBack = doneCallBack;
/* this is the creator function for your scene assistant object. It will be passed all the
additional parameters (after the scene name) that were passed to pushScene. The reference
to the scene controller (this.controller) has not be established yet, so any initialization
that needs the scene controller should be done in the setup function below. */
Mojo.Log.info("new Login assistant exists");
this.sceneAssistant = sceneAssistant; //dialog's do not have their own controller, so need access to the launching scene's controller
}
LoginAssistant.prototype.setup = function(widget) {
/* this function is for setup tasks that have to happen when the scene is first created */
this.widget = widget;
Mojo.Log.info("login assistant setup");
Mojo.Log.info("Current Move is: " + appModel.AppSettingsCurrent["Username"]);
/* setup widgets here */
this.sceneAssistant.controller.setupWidget("txtUsername",
this.attributes = {
textFieldName: "Username",
hintText: "User Name",
property: 'value',
multiline: false,
changeOnKeyPress: true,
autoReplace: false,
textCase: Mojo.Widget.steModeLowerCase,
requiresEnterKey: false,
focus: false
},
this.model = {
value: appModel.AppSettingsCurrent["Username"],
disabled: false
}
);
this.sceneAssistant.controller.setupWidget("txtCredential",
this.attributes = {
textFieldName: "Credential",
hintText: "Admin Password",
property: 'value',
multiline: false,
changeOnKeyPress: true,
autoReplace: false,
textCase: Mojo.Widget.steModeLowerCase,
requiresEnterKey: false,
focus: false
},
this.model = {
value: appModel.AppSettingsCurrent["Credential"],
disabled: false
}
);
this.sceneAssistant.controller.setupWidget("linkSpinner",
this.attributes = {
spinnerSize: "small"
},
this.model = {
spinning: true
}
);
this.sceneAssistant.controller.setupWidget("goButton", { type: Mojo.Widget.activityButton }, { label: "OK", disabled: false });
this.sceneAssistant.controller.setupWidget("cancelButton", { type: Mojo.Widget.button }, { label: "Cancel", disabled: false });
/* add event handlers to listen to events from widgets */
Mojo.Event.listen(this.sceneAssistant.controller.get("txtUsername"), Mojo.Event.propertyChange, this.handleValueChange.bind(this));
Mojo.Event.listen(this.sceneAssistant.controller.get("txtCredential"), Mojo.Event.propertyChange, this.handleValueChange.bind(this));
Mojo.Event.listen(this.sceneAssistant.controller.get("goButton"), Mojo.Event.tap, this.handleGoPress.bind(this));
Mojo.Event.listen(this.sceneAssistant.controller.get("cancelButton"), Mojo.Event.tap, this.handleCancelPress.bind(this));
};
LoginAssistant.prototype.activate = function(event) {
Mojo.Log.info("Login assistant activated");
/* put in event handlers here that should only be in effect when this scene is active. For
example, key handlers that are observing the document */
};
LoginAssistant.prototype.handleValueChange = function(event) {
appModel.AppSettingsCurrent[event.srcElement.title] = event.value;
}
LoginAssistant.prototype.handleCancelPress = function(event) {
this.doneCallBack(false);
this.widget.mojo.close();
}
LoginAssistant.prototype.handleGoPress = function(event) {
if (this.sceneAssistant.controller.get("txtUsername").mojo.getValue() == "") {
this.sceneAssistant.controller.get("txtUsername").mojo.focus();
this.sceneAssistant.controller.get("goButton").mojo.deactivate();
return;
}
if (this.sceneAssistant.controller.get("txtCredential").mojo.getValue() == "") {
this.sceneAssistant.controller.get("txtCredential").mojo.focus();
this.sceneAssistant.controller.get("goButton").mojo.deactivate();
return;
}
//Update UI for this state
this.tryServiceLogin();
}
LoginAssistant.prototype.tryServiceLogin = function() {
serviceModel.DoShareListRequest(appModel.AppSettingsCurrent["Username"], appModel.AppSettingsCurrent["Credential"], function(response) {
if (response.error) {
this.doneCallBack(response);
} else {
if (response && response.shares && response.shares != "") {
Mojo.Log.info("Login success!");
appModel.SaveSettings();
this.doneCallBack(true);
} else {
this.doneCallBack({"error": "Login failure. Check connectivity and your credentials. If you haven't logged in for a long time, create a new account."});
}
}
this.widget.mojo.close(); //Dismiss this dialog
}.bind(this), this.errorHandler.bind(this));
}
LoginAssistant.prototype.deactivate = function(event) {
Mojo.Log.info("Login assistant deactivated");
/* remove any event handlers you added in activate and do any other cleanup that should happen before
this scene is popped or another scene is pushed on top */
Mojo.Event.stopListening(this.sceneAssistant.controller.get("txtUsername"), Mojo.Event.propertyChange, this.handleValueChange);
Mojo.Event.stopListening(this.sceneAssistant.controller.get("txtCredential"), Mojo.Event.propertyChange, this.handleValueChange);
Mojo.Event.stopListening(this.sceneAssistant.controller.get("goButton"), Mojo.Event.tap, this.handleGoPress);
Mojo.Event.stopListening(this.sceneAssistant.controller.get("cancelButton"), Mojo.Event.tap, this.handleCancelPress);
};
LoginAssistant.prototype.cleanup = function(event) {
Mojo.Log.info("Login assistant cleaned up");
/* this function should do any cleanup needed before the scene is destroyed as
a result of being popped off the scene stack */
};
LoginAssistant.prototype.errorHandler = function (errorText, callback) {
Mojo.Log.error(errorText);
if (callback) {
callback.bind(this);
callback({"error": errorText});
} else {
Mojo.Controller.getAppController().showBanner({ messageText: errorText, icon: "assets/notify.png" }, "", "");
}
}
File diff suppressed because it is too large. Load diff
+132
View File
@@ -0,0 +1,132 @@
function NewshareAssistant(sceneAssistant, doneCallBack) {
this.doneCallBack = doneCallBack;
/* this is the creator function for your scene assistant object. It will be passed all the
additional parameters (after the scene name) that were passed to pushScene. The reference
to the scene controller (this.controller) has not be established yet, so any initialization
that needs the scene controller should be done in the setup function below. */
Mojo.Log.info("new NewShare assistant exists");
this.sceneAssistant = sceneAssistant; //dialog's do not have their own controller, so need access to the launching scene's controller
}
NewshareAssistant.prototype.setup = function(widget) {
/* this function is for setup tasks that have to happen when the scene is first created */
this.widget = widget;
Mojo.Log.info("Current Share Target is: " + appModel.AppSettingsCurrent["Username"]);
/* setup widgets here */
//Text box
var textAttrib = {
textFieldName: "ShareContent",
hintText: "Text to share",
property: 'value',
multiline: true,
changeOnKeyPress: true,
autoReplace: true,
textCase: Mojo.Widget.steModeSentenceCase,
requiresEnterKey: false,
focus: true
};
if (appModel.LastShareSelected.contenttype == "application/json") {
textAttrib.hintText = "JSON to share"
textAttrib.autoReplace = false;
textAttrib.textCase = Mojo.Widget.steModeLowerCase;
}
Mojo.Log.info("Using Last Share: " + JSON.stringify(appModel.LastShareSelected));
this.controller.setupWidget("txtShareContent",
this.attributes = textAttrib,
this.model = {
value: appModel.LastShareSelected.content,
disabled: false
}
);
this.controller.setupWidget("goButton", { type: Mojo.Widget.activityButton }, { label: "OK", disabled: false });
this.controller.setupWidget("cancelButton", { type: Mojo.Widget.button }, { label: "Cancel", disabled: false });
};
NewshareAssistant.prototype.activate = function(event) {
Mojo.Log.info("NewShare assistant activated for share: " + appModel.LastShareSelected.guid);
if (appModel.LastShareSelected.guid == "new") {
this.controller.get("divEditTitle").innerHTML = "New Share Content";
} else {
this.controller.get("divEditTitle").innerHTML = "Edit Share Content";
}
/* add event handlers to listen to events from widgets */
Mojo.Event.listen(this.controller.get("goButton"), Mojo.Event.tap, this.handleOKPress.bind(this));
Mojo.Event.listen(this.controller.get("cancelButton"), Mojo.Event.tap, this.handleCancelPress.bind(this));
//Resize event
this.controller.window.onresize = this.calculateControlsPosition.bind(this);
this.calculateControlsPosition();
};
NewshareAssistant.prototype.calculateControlsPosition = function() {
var maxHeight = 380;
if ((this.controller.window.innerHeight - 210) < maxHeight)
maxHeight = this.controller.window.innerHeight - 210;
this.controller.get("txtShareContent").style.height = maxHeight + "px";
}
NewshareAssistant.prototype.handleCancelPress = function(event) {
var stageController = Mojo.Controller.getAppController().getActiveStageController();
stageController.pushScene({ transition: Mojo.Transition.crossFade, name: "main" });
}
NewshareAssistant.prototype.handleOKPress = function(event) {
var shareContent = this.controller.get("txtShareContent").mojo.getValue();
if (shareContent && shareContent != "") {
if (appModel.LastShareSelected.contenttype == "application/json") {
try {
var testObj = JSON.parse(shareContent);
} catch (ex) {
Mojo.Controller.getAppController().showBanner({ messageText: 'JSON content not be parsed', icon: 'assets/notify.png' }, { source: 'notification' });
this.controller.get('goButton').mojo.deactivate();
this.controller.window.setTimeout(this.controller.get('txtShareContent').mojo.focus(), 500);
return false;
}
}
appModel.LastShareSelected.content = shareContent;
this.tryAddShare();
} else {
this.controller.get('goButton').mojo.deactivate();
this.controller.get("txtShareContent").mojo.focus();
}
}
NewshareAssistant.prototype.tryAddShare = function() {
serviceModel.DoShareAddRequestText(appModel.LastShareSelected.content, appModel.AppSettingsCurrent["Username"], appModel.AppSettingsCurrent["Credential"], appModel.LastShareSelected.contenttype, function(responseObj) {
if (responseObj && responseObj.guid && responseObj.guid != "") {
Mojo.Log.info("Add share success!");
if (appModel.AppSettingsCurrent["CopyLinkOnShare"]) {
var stageController = Mojo.Controller.getAppController().getActiveStageController()
stageController.setClipboard(serviceModel.MakeShareURL(appModel.AppSettingsCurrent["Username"], responseObj.guid, "text"));
Mojo.Controller.getAppController().showBanner({ messageText: 'Content shared, link copied!', icon: 'assets/notify.png' }, { source: 'notification' });
} else {
Mojo.Controller.getAppController().showBanner({ messageText: 'Content shared!', icon: 'assets/notify.png' }, { source: 'notification' });
}
} else {
this.errorHandler("Share failure: " + JSON.stringify(responseObj))
}
this.handleCancelPress();
}.bind(this), this.errorHandler.bind(this));
}
NewshareAssistant.prototype.errorHandler = function (errorText, callback) {
Mojo.Log.error(errorText);
Mojo.Controller.getAppController().showBanner({ messageText: errorText, icon: "assets/notify.png" }, "", "");
errorText = errorText.charAt(0).toUpperCase() + errorText.slice(1);
this.controller.get('goButton').mojo.deactivate();
Mojo.Additions.ShowDialogBox("Share Sevice Error", errorText);
}
NewshareAssistant.prototype.deactivate = function(event) {
Mojo.Log.info("NewShare assistant deactivated");
Mojo.Event.stopListening(this.controller.get("goButton"), Mojo.Event.tap, this.handleOKPress);
Mojo.Event.stopListening(this.controller.get("cancelButton"), Mojo.Event.tap, this.handleCancelPress);
};
NewshareAssistant.prototype.cleanup = function(event) {
Mojo.Log.info("NewShare assistant cleaned up");
/* this function should do any cleanup needed before the scene is destroyed as
a result of being popped off the scene stack */
};
+173
View File
@@ -0,0 +1,173 @@
function NewuserAssistant() {
/* this is the creator function for your scene assistant object. It will be passed all the
additional parameters (after the scene name) that were passed to pushScene. The reference
to the scene controller (this.controller) has not be established yet, so any initialization
that needs the scene controller should be done in the setup function below. */
}
NewuserAssistant.prototype.setup = function() {
/* setup widgets here */
this.controller.setupWidget("scrollTnC",
this.attributes = {
mode: 'vertical'
},
this.model = {}
);
//Agree Button
this.controller.setupWidget("btnAgree", { type: Mojo.Widget.defaultButton }, { label: "Agree", buttonClass: "affirmative", disabled: true });
//Cancel Button
this.controller.setupWidget("btnCancel", { type: Mojo.Widget.defaultButton }, { label: "Cancel", buttonClass: "negative", disabled: false });
//OK Button
this.controller.setupWidget("btnOK", { type: Mojo.Widget.activityButton }, { label: "Create Space", buttonClass: "affirmative", disabled: false });
//Username Field
this.controller.setupWidget("txtUsername",
this.attributes = {
hintText: $L("Choose a username"),
multiline: false,
enterSubmits: false,
focus: true,
textCase: Mojo.Widget.steModeLowerCase,
autoReplace: false
},
this.model = {
disabled: false
}
);
//Username Field
this.controller.setupWidget("txtPassword",
this.attributes = {
hintText: $L("Enter a Password"),
multiline: false,
enterSubmits: false,
focus: false,
textCase: Mojo.Widget.steModeLowerCase,
autoReplace: false
},
this.model = {
disabled: false
}
);
//Menu
this.appMenuAttributes = { omitDefaultItems: true };
this.appMenuModel = {};
this.controller.setupWidget(Mojo.Menu.appMenu, this.appMenuAttributes, this.appMenuModel);
};
NewuserAssistant.prototype.activate = function(event) {
/* add event handlers to listen to events from widgets */
Mojo.Event.listen(this.controller.get("btnAgree"), Mojo.Event.tap, this.agreeClick.bind(this));
Mojo.Event.listen(this.controller.get("btnCancel"), Mojo.Event.tap, this.cancelClick.bind(this));
Mojo.Event.listen(this.controller.get("btnOK"), Mojo.Event.tap, this.okClick.bind(this));
//bind tryagain listener
this.controller.get("imgTryagain").addEventListener("click", this.generateSharePhrase.bind(this));
//Get terms and conditions from service and put into UI
serviceModel.GetTnC(function(response) {
this.controller.get("divTnC").innerHTML = response;
Mojo.Additions.DisableWidget("btnAgree", false);
}.bind(this));
this.sharephrase = "";
//Resize event
this.controller.window.onresize = this.calculateControlsPosition.bind(this);
this.calculateControlsPosition();
};
NewuserAssistant.prototype.calculateControlsPosition = function() {
var maxHeight = 380;
if ((this.controller.window.innerHeight - 180) < maxHeight)
maxHeight = this.controller.window.innerHeight - 180;
this.controller.get("scrollTnC").style.height = maxHeight + "px";
}
NewuserAssistant.prototype.agreeClick = function(event) {
Mojo.Additions.DisableWidget("btnAgree", true);
this.controller.get("divCredentials").style.display = "block";
this.controller.get("btnOK").style.display = "block";
this.generateSharePhrase();
this.controller.getSceneScroller().mojo.revealElement(this.controller.get("txtPassword"));
}
NewuserAssistant.prototype.generateSharePhrase = function() {
//Get new credentials from service and put into UI
serviceModel.GetRandomWords(function(response) {
if (response) {
this.controller.get("divSharephrase").innerHTML = response;
this.sharephrase = response;
} else {
Mojo.Additions.ShowDialogBox("Service Error", "Did not receive random words from service.");
}
}.bind(this));
}
NewuserAssistant.prototype.okClick = function(event) {
//validate input
var disallowed = ["con", "prn", "aux", "nul", "com", "do", "done", "elif", "else", "esac", "fi", "for", "function", "if", "in", "select", "then", "until", "while", "time"];
this.username = this.controller.get('txtUsername').mojo.getValue().toLowerCase();
if (this.username == "" || disallowed.indexOf(this.username) != -1 || this.username.match(/[^a-z]/g) || this.username.indexOf(" ") != -1) {
Mojo.Additions.ShowDialogBox("Invalid username", "Your username must be one word, alphabetic characters only, and cannot contain any reserved words for Unix or Windows operating systems.");
this.controller.get('btnOK').mojo.deactivate();
} else {
if (this.sharephrase && this.sharephrase != "") {
this.password = this.controller.get('txtPassword').mojo.getValue().toLowerCase();
if (this.password == "" || disallowed.indexOf(this.password) != -1 || this.password.match(/[^A-Za-z0-9 ]/g) || this.password.indexOf(" ") != -1) {
Mojo.Additions.ShowDialogBox("Invalid password", "Your password must be one word, alpha-numeric characters only, and cannot contain any reserved words for Unix or Windows operating systems.");
this.controller.get('btnOK').mojo.deactivate();
} else {
serviceModel.DoNewUserRequest(this.username, this.sharephrase, this.password, function(responseObj) {
if (responseObj != null) {
appModel.AppSettingsCurrent["Username"] = this.username;
appModel.AppSettingsCurrent["Credential"] = this.password;
appModel.AppSettingsCurrent["SharePhrase"] = this.sharephrase;
appModel.SaveSettings();
Mojo.Log.info("Successfully created account ", appModel.AppSettingsCurrent["Username"], appModel.AppSettingsCurrent["Credential"], appModel.AppSettingsCurrent["SharePhrase"]);
var stageController = Mojo.Controller.getAppController().getActiveStageController();
stageController.swapScene({ transition: Mojo.Transition.zoomFade, name: "welcome" });
} else {
Mojo.Log.error("No usable response from server while uploading share");
Mojo.Controller.getAppController().showBanner({ messageText: "Bad response uploading image", icon: "assets/notify.png" }, "", "");
}
this.controller.get('btnOK').mojo.deactivate();
}.bind(this), this.errorHandler.bind(this));
}
} else {
Mojo.Additions.ShowDialogBox("Missing Share Phrase", "The share phrase is provided by the server, but appears to be missing. This likely means the server is unreachable, down, or improperly configured.");
this.controller.get('btnOK').mojo.deactivate();
}
}
}
NewuserAssistant.prototype.cancelClick = function(event) {
var stageController = Mojo.Controller.getAppController().getActiveStageController();
stageController.swapScene({ transition: Mojo.Transition.zoomFade, name: "main" });
}
NewuserAssistant.prototype.errorHandler = function (errorText, callback) {
Mojo.Log.error(errorText);
Mojo.Controller.getAppController().showBanner({ messageText: errorText, icon: "assets/notify.png" }, "", "");
errorText = errorText.charAt(0).toUpperCase() + errorText.slice(1);
Mojo.Additions.ShowDialogBox("Share Sevice Error", errorText);
this.controller.get('btnOK').mojo.deactivate();
}
NewuserAssistant.prototype.deactivate = function(event) {
/* remove any event handlers you added in activate and do any other cleanup that should happen before
this scene is popped or another scene is pushed on top */
Mojo.Event.stopListening(this.controller.get("btnAgree"), Mojo.Event.tap, this.agreeClick);
Mojo.Event.stopListening(this.controller.get("btnCancel"), Mojo.Event.tap, this.cancelClick);
Mojo.Event.stopListening(this.controller.get("btnOK"), Mojo.Event.tap, this.cancelClick);
this.controller.window.removeEventListener("resize", this.calculateControlsPosition);
this.controller.window.onresize = null;
};
NewuserAssistant.prototype.cleanup = function(event) {
/* this function should do any cleanup needed before the scene is destroyed as
a result of being popped off the scene stack */
};
+151 -203
View File
@@ -8,139 +8,87 @@ function PreferencesAssistant() {
PreferencesAssistant.prototype.setup = function() {
/* setup widgets here */
//Theme picker
this.controller.setupWidget("listThemePreference",
{label: $L({value:"Theme", key:"theme"}),
labelPlacement: Mojo.Widget.labelPlacementLeft,
choices: [
{label: $L({value:"Light", key:"themeLight"}), value: "palm-default"},
{label: $L({value:"Dark", key:"themeDark"}), value: "palm-dark"},
{label: $L({value:"System Pref", key:"themeSystem"}), value: "system-theme"}
]},
{ value: appModel.AppSettingsCurrent["ThemePreference"] });
//Timeout picker
this.controller.setupWidget("listForegroundUpdate",
//Refresh timeout picker
this.controller.setupWidget("listRefresh",
this.attributes = {
label: $L("Foreground Update"),
label: $L("Refresh"),
choices: [
{ label: "5 seconds", value: 5000 },
{ label: "10 seconds", value: 10000 },
{ label: "20 seconds", value: 20000 },
{ label: "30 second", value: 30000 },
{ label: "Manual", value: "" },
{ label: "1 minute", value: 60000 },
{ label: "2 minutes", value: 120000 },
{ label: "5 minutes", value: 180000 },
{ label: "3 minutes", value: 180000 },
{ label: "5 minutes", value: 300000 }
]
},
this.model = {
value: appModel.AppSettingsCurrent["ForegroundUpdate"],
value: appModel.AppSettingsCurrent["RefreshTimeout"],
disabled: false
}
);
var backgroundValue;
if (!appModel.AppSettingsCurrent["BackgroundUpdate"] || appModel.AppSettingsCurrent["BackgroundUpdate"] == 0 || appModel.AppSettingsCurrent["BackgroundUpdate"] == "")
backgroundValue = "-1";
else
backgroundValue = appModel.AppSettingsCurrent["BackgroundUpdate"]
this.controller.setupWidget("listBackgroundUpdate",
//Toggles
var disableDL = true;
if (appModel.FileMgrPresent)
disableDL = false;
this.controller.setupWidget("toggleAutoDownload",
this.attributes = {
label: $L("Background Update"),
trueValue: true,
falseValue: false
},
this.model = {
value: appModel.AppSettingsCurrent["UseAutoDownload"],
disabled: disableDL
}
);
//List boxes
this.controller.setupWidget("listAutoDownloadTime",
this.attributes = {
label: $L("Download Interval"),
choices: [
{ label: "Off", value: -1 },
{ label: "5 minutes", value: "00:05:00" },
{ label: "10 minutes", value: "00:10:00" },
{ label: "15 minutes", value: "00:15:00" },
{ label: "30 minutes", value: "00:30:00" },
{ label: "45 minutes", value: "00:45:00" },
{ label: "1 Hour", value: "01:00:00" },
{ label: "2 Hours", value: "02:00:00" },
{ label: "3 Hours", value: "02:00:00" },
{ label: "5 Hours", value: "05:00:00" },
{ label: "3 Hours", value: "03:00:00" },
{ label: "6 Hours", value: "06:00:00" },
{ label: "12 Hours", value: "12:00:00" },
{ label: "24 Hours", value: "23:59:59" }
]
},
this.model = {
value: backgroundValue,
disabled: false
value: appModel.AppSettingsCurrent["AutoDownloadTime"],
disabled: disableDL
}
);
//Enter Action listEnterSubmits
this.controller.setupWidget("listEnterSubmits",
this.attributes = {
label: $L("Enter Submits"),
choices: [
{ label: "Never", value: "never" },
{ label: "Collapsed", value: "collapsed" },
{ label: "Always", value: "always" }
]
},
this.model = {
value: appModel.AppSettingsCurrent["EnterSubmits"],
disabled: false
}
);
//Emoji toggle
this.controller.setupWidget("toggleEmojis",
if (appModel.FileMgrPresent)
this.controller.get("divDownloadExplain").innerHTML = "Frequent automatic downloads can have significant impact on battery life.";
//More toggles
this.controller.setupWidget("toggleCopyLinkOnShare",
this.attributes = {
trueValue: true,
falseValue: false
},
this.model = {
value: appModel.AppSettingsCurrent["ShowEmojis"],
value: appModel.AppSettingsCurrent["CopyLinkOnShare"],
disabled: false
}
);
//Link toggle
this.controller.setupWidget("toggleParsing",
this.controller.setupWidget("toggleForceHTTP",
this.attributes = {
trueValue: true,
falseValue: false
},
this.model = {
value: appModel.AppSettingsCurrent["SkipParsing"],
value: appModel.AppSettingsCurrent["ForceHTTP"],
disabled: false
}
);
//Thumbnail toggle
this.controller.setupWidget("toggleThumbs",
this.controller.setupWidget("toggleCustomClientId",
this.attributes = {
trueValue: true,
falseValue: false
},
this.model = {
value: appModel.AppSettingsCurrent["ShowWOSAThumbs"],
disabled: false
}
);
//Setup sound picker
this.soundChoices = {
choices: [
{ label: "Choose...", value: "choose" },
{ label: "Off", value: "off" }
]
};
if (appModel.AppSettingsCurrent["AlertSound"] != "off") {
var useVal = appModel.AppSettingsCurrent["AlertSound"];
var labelVal = useVal;
if (Mojo.Environment.DeviceInfo.platformVersionMajor < 3) {
labelVal = useVal.substring(0, 8) + "...";
}
this.soundChoices.choices.unshift({ label: labelVal, value: useVal });
}
this.controller.setupWidget("listAlertSound",
this.attributes = this.soundChoices,
this.model = {
value: appModel.AppSettingsCurrent["AlertSound"],
disabled: false
}
);
//API Toggles
this.controller.setupWidget("toggleClientAPI",
this.attributes = {
trueValue: true,
falseValue: false
},
this.model = {
value: appModel.AppSettingsCurrent["UseClientAPIKey"],
value: appModel.AppSettingsCurrent["UseCustomClientId"],
disabled: false
}
);
@@ -154,25 +102,23 @@ PreferencesAssistant.prototype.setup = function() {
disabled: false
}
);
//API Text fields
this.controller.setupWidget("txtClientAPI",
//Text fields
this.controller.setupWidget("txtCustomClientId",
this.attributes = {
hintText: $L("Your Client Id"),
hintText: $L("Your Service Client Id"),
multiline: false,
enterSubmits: false,
autoReplace: false,
focus: false,
autoFocus: false,
textCase: Mojo.Widget.steModeLowerCase
},
this.model = {
value: appModel.AppSettingsCurrent["ClientAPIKey"],
disabled: !appModel.AppSettingsCurrent["UseClientAPIKey"]
value: appModel.AppSettingsCurrent["CustomClientId"],
disabled: !appModel.AppSettingsCurrent["UseCustomEndpoint"]
}
);
this.controller.setupWidget("txtEndpointURL",
this.attributes = {
hintText: $L("http://your-chat-server.com/"),
hintText: $L("http://your-server.com/"),
multiline: false,
enterSubmits: false,
autoReplace: false,
@@ -183,6 +129,43 @@ PreferencesAssistant.prototype.setup = function() {
disabled: !appModel.AppSettingsCurrent["UseCustomEndpoint"]
}
);
this.controller.setupWidget("txtShortURL",
this.attributes = {
hintText: $L("http://short.link/"),
multiline: false,
enterSubmits: false,
autoReplace: false,
textCase: Mojo.Widget.steModeLowerCase
},
this.model = {
value: appModel.AppSettingsCurrent["ShortURL"],
disabled: !appModel.AppSettingsCurrent["UseCustomEndpoint"]
}
);
this.controller.setupWidget("txtCustomCreateKey",
this.attributes = {
hintText: $L("Your Service Create Key"),
multiline: false,
enterSubmits: false,
autoReplace: false,
textCase: Mojo.Widget.steModeLowerCase
},
this.model = {
value: appModel.AppSettingsCurrent["CustomCreateKey"],
disabled: !appModel.AppSettingsCurrent["UseCustomEndpoint"]
}
);
//Drawer
this.controller.setupWidget("drawerSelfHost",
this.attributes = {
modelProperty: 'open',
unstyled: false
},
this.model = {
open: appModel.AppSettingsCurrent["UseCustomEndpoint"]
}
);
//OK Button
this.controller.setupWidget("btnOK", { type: Mojo.Widget.activityButton }, { label: "Done", disabled: false });
//Menu
@@ -195,27 +178,26 @@ PreferencesAssistant.prototype.setup = function() {
]
};
this.controller.setupWidget(Mojo.Menu.appMenu, this.appMenuAttributes, this.appMenuModel);
/* add event handlers to listen to events from widgets */
Mojo.Event.listen(this.controller.get("listThemePreference"), Mojo.Event.propertyChange, this.handleValueChange.bind(this));
Mojo.Event.listen(this.controller.get("listForegroundUpdate"), Mojo.Event.propertyChange, this.handleValueChange.bind(this));
Mojo.Event.listen(this.controller.get("listBackgroundUpdate"), Mojo.Event.propertyChange, this.handleValueChange.bind(this));
Mojo.Event.listen(this.controller.get("toggleEmojis"), Mojo.Event.propertyChange, this.handleValueChange.bind(this));
Mojo.Event.listen(this.controller.get("toggleParsing"), Mojo.Event.propertyChange, this.handleValueChange.bind(this));
Mojo.Event.listen(this.controller.get("toggleThumbs"), Mojo.Event.propertyChange, this.handleValueChange.bind(this));
Mojo.Event.listen(this.controller.get("listEnterSubmits"), Mojo.Event.propertyChange, this.handleValueChange.bind(this));
Mojo.Event.listen(this.controller.get("listAlertSound"), Mojo.Event.propertyChange, this.handleValueChange.bind(this));
Mojo.Event.listen(this.controller.get("txtClientAPI"), Mojo.Event.propertyChange, this.handleValueChange.bind(this));
Mojo.Event.listen(this.controller.get("txtEndpointURL"), Mojo.Event.propertyChange, this.handleValueChange.bind(this));
Mojo.Event.listen(this.controller.get("toggleClientAPI"), Mojo.Event.propertyChange, this.handleValueChange.bind(this));
Mojo.Event.listen(this.controller.get("toggleCustomEndPoint"), Mojo.Event.propertyChange, this.handleValueChange.bind(this));
Mojo.Event.listen(this.controller.get("btnOK"), Mojo.Event.tap, this.okClick.bind(this));
};
PreferencesAssistant.prototype.activate = function(event) {
/* put in event handlers here that should only be in effect when this scene is active. For
example, key handlers that are observing the document */
//this.showBetaFeatures();
/* add event handlers to listen to events from widgets */
Mojo.Event.listen(this.controller.get("listRefresh"), Mojo.Event.propertyChange, this.handleValueChange.bind(this));
Mojo.Event.listen(this.controller.get("toggleAutoDownload"), Mojo.Event.propertyChange, this.handleValueChange.bind(this));
Mojo.Event.listen(this.controller.get("listAutoDownloadTime"), Mojo.Event.propertyChange, this.handleValueChange.bind(this));
Mojo.Event.listen(this.controller.get("toggleCopyLinkOnShare"), Mojo.Event.propertyChange, this.handleValueChange.bind(this));
Mojo.Event.listen(this.controller.get("toggleForceHTTP"), Mojo.Event.propertyChange, this.handleValueChange.bind(this));
Mojo.Event.listen(this.controller.get("toggleCustomClientId"), Mojo.Event.propertyChange, this.handleValueChange.bind(this));
Mojo.Event.listen(this.controller.get("txtCustomClientId"), Mojo.Event.propertyChange, this.handleValueChange.bind(this));
Mojo.Event.listen(this.controller.get("toggleCustomEndPoint"), Mojo.Event.propertyChange, this.handleValueChange.bind(this));
Mojo.Event.listen(this.controller.get("txtEndpointURL"), Mojo.Event.propertyChange, this.handleValueChange.bind(this));
Mojo.Event.listen(this.controller.get("txtShortURL"), Mojo.Event.propertyChange, this.handleValueChange.bind(this));
Mojo.Event.listen(this.controller.get("txtCustomCreateKey"), Mojo.Event.propertyChange, this.handleValueChange.bind(this));
Mojo.Event.listen(this.controller.get("btnOK"), Mojo.Event.tap, this.okClick.bind(this));
};
PreferencesAssistant.prototype.showBetaFeatures = function() {
@@ -226,46 +208,51 @@ PreferencesAssistant.prototype.handleValueChange = function(event) {
Mojo.Log.info(event.srcElement.id + " value changed to " + event.value);
switch (event.srcElement.id) {
case "listThemePreference":
appModel.AppSettingsCurrent["ThemePreference"] = event.value;
appModel.SetThemePreference(this.controller);
break;
case "toggleParsing":
Mojo.Controller.getAppController().showBanner({ messageText: "Re-launch app to apply this setting" }, "", "");
break;
case "toggleEmojis":
Mojo.Controller.getAppController().showBanner({ messageText: "Re-launch app to apply this setting" }, "", "");
break;
case "toggleThumbs":
Mojo.Controller.getAppController().showBanner({ messageText: "Re-launch app to apply this setting" }, "", "");
break;
case "listAlertSound":
if (event.value == "choose") {
this.setAlarmSound();
} else {
appModel.AppSettingsCurrent["AlertSound"] = event.value;
case "toggleCustomClientId":
{
var thisWidgetSetup = this.controller.getWidgetSetup("txtCustomClientId");
thisWidgetSetup.model.disabled = !event.value;
this.controller.modelChanged(thisWidgetSetup.model);
if (event.value)
this.controller.get('txtCustomClientId').mojo.focus();
break;
}
case "toggleAutoDownload":
{
var thisWidgetSetup = this.controller.getWidgetSetup("listAutoDownloadTime");
thisWidgetSetup.model.disabled = !event.value;
this.controller.modelChanged(thisWidgetSetup.model);
break;
}
break;
case "toggleClientAPI":
var thisWidgetSetup = this.controller.getWidgetSetup("txtClientAPI");
thisWidgetSetup.model.disabled = !event.value;
this.controller.modelChanged(thisWidgetSetup.model);
if (event.value)
this.controller.get('txtClientAPI').mojo.focus();
break;
case "toggleCustomEndPoint":
var thisWidgetSetup = this.controller.getWidgetSetup("txtEndpointURL");
thisWidgetSetup.model.disabled = !event.value;
this.controller.modelChanged(thisWidgetSetup.model);
if (event.value)
this.controller.get('txtEndpointURL').mojo.focus();
break;
{
//Toggle enabled on related text boxes
var thisWidgetSetup = this.controller.getWidgetSetup("drawerSelfHost");
thisWidgetSetup.model.open = event.value;
this.controller.modelChanged(thisWidgetSetup.model);
var thisWidgetSetup = this.controller.getWidgetSetup("txtEndpointURL");
thisWidgetSetup.model.disabled = !event.value;
this.controller.modelChanged(thisWidgetSetup.model);
var thisWidgetSetup = this.controller.getWidgetSetup("txtShortURL");
thisWidgetSetup.model.disabled = !event.value;
this.controller.modelChanged(thisWidgetSetup.model);
var thisWidgetSetup = this.controller.getWidgetSetup("txtCustomCreateKey");
thisWidgetSetup.model.disabled = !event.value;
this.controller.modelChanged(thisWidgetSetup.model);
if (event.value)
this.controller.get('txtEndpointURL').mojo.focus();
break;
}
case "txtEndpointURL":
var lastChar = event.value[event.value.length - 1]
if (lastChar != "/") {
event.value = event.value + "/";
Mojo.Log.warn("Custom end point URL was missing trailing slash, it has been added. Value is now: " + event.value);
}
if(!appModel.AppSettingsCurrent["ShortURL"] || appModel.AppSettingsCurrent["ShortURL"] == "") {
this.controller.get('txtShortURL').mojo.setValue(event.value);
appModel.AppSettingsCurrent["ShortURL"] = event.value;
}
break;
}
@@ -273,56 +260,14 @@ PreferencesAssistant.prototype.handleValueChange = function(event) {
Mojo.Log.info(event.srcElement.title + " now: " + event.value);
appModel.AppSettingsCurrent[event.srcElement.title] = event.value;
appModel.SaveSettings();
//Show/hide beta features
this.showBetaFeatures();
};
// opens ringtone picker.
PreferencesAssistant.prototype.setAlarmSound = function() {
var self = this;
var params = {
defaultKind: 'ringtone',
onSelect: function(file) {
var fileToUse = file.fullPath.replace("/media/internal/ringtones/", "").replace(".mp3", "");
appModel.AppSettingsCurrent["AlertSound"] = fileToUse;
appModel.SaveSettings();
var useVal = fileToUse;
var labelVal = useVal;
try {
if (Mojo.Environment.DeviceInfo.platformVersionMajor < 3) {
labelVal = useVal.substring(0, 8) + "...";
}
} catch (ex) {
Mojo.Log.error("Could not set ringtone value");
}
self.soundChoices.choices[0].label = labelVal;
self.soundChoices.choices[0].value = useVal;
var thisWidgetSetup = self.controller.getWidgetSetup("listAlertSound");
var thisWidgetModel = thisWidgetSetup.model;
thisWidgetModel.value = fileToUse;
self.controller.setWidgetModel("listAlertSound", thisWidgetModel);
self.controller.modelChanged(thisWidgetModel);
Mojo.Log.info("alarm sound changed to: " + fileToUse)
}
}
var appController = Mojo.Controller.getAppController();
var stageController = appController.getStageProxy("main");
Mojo.FilePicker.pickFile(params, stageController);
}
//Handle menu and button bar commands
PreferencesAssistant.prototype.handleCommand = function(event) {
if (event.type == Mojo.Event.command) {
switch (event.command) {
case 'do-goBack':
this.okClick();
Mojo.Controller.stageController.popScene();
break;
case 'do-resetSettings':
appModel.ResetSettings(appModel.AppSettingsDefaults);
@@ -332,27 +277,30 @@ PreferencesAssistant.prototype.handleCommand = function(event) {
};
PreferencesAssistant.prototype.okClick = function(event) {
var appController = Mojo.Controller.getAppController();
var stageController = appController.getStageProxy("main");
var stageController = Mojo.Controller.getAppController().getActiveStageController();
stageController.popScene();
}
PreferencesAssistant.prototype.deactivate = function(event) {
if (this.controller.get('txtEndpointURL').mojo.getValue() == "") {
appModel.AppSettingsCurrent["UseCustomEndpoint"] = false;
}
appModel.SaveSettings();
appModel.EstablishAlarms();
/* remove any event handlers you added in activate and do any other cleanup that should happen before
this scene is popped or another scene is pushed on top */
Mojo.Event.stopListening(this.controller.get("listThemePreference"), Mojo.Event.propertyChange, this.handleValueChange);
Mojo.Event.stopListening(this.controller.get("listBackgroundUpdate"), Mojo.Event.propertyChange, this.handleValueChange);
Mojo.Event.stopListening(this.controller.get("toggleEmojis"), Mojo.Event.propertyChange, this.handleValueChange);
Mojo.Event.stopListening(this.controller.get("toggleParsing"), Mojo.Event.propertyChange, this.handleValueChange);
Mojo.Event.stopListening(this.controller.get("toggleThumbs"), Mojo.Event.propertyChange, this.handleValueChange);
Mojo.Event.stopListening(this.controller.get("listEnterSubmits"), Mojo.Event.propertyChange, this.handleValueChange);
Mojo.Event.stopListening(this.controller.get("listAlertSound"), Mojo.Event.propertyChange, this.handleValueChange);
Mojo.Event.stopListening(this.controller.get("toggleClientAPI"), Mojo.Event.propertyChange, this.handleValueChange);
Mojo.Event.stopListening(this.controller.get("listRefresh"), Mojo.Event.propertyChange, this.handleValueChange);
Mojo.Event.stopListening(this.controller.get("toggleAutoDownload"), Mojo.Event.propertyChange, this.handleValueChange);
Mojo.Event.stopListening(this.controller.get("listAutoDownloadTime"), Mojo.Event.propertyChange, this.handleValueChange);
Mojo.Event.stopListening(this.controller.get("toggleForceHTTP"), Mojo.Event.propertyChange, this.handleValueChange);
Mojo.Event.stopListening(this.controller.get("toggleCustomClientId"), Mojo.Event.propertyChange, this.handleValueChange);
Mojo.Event.stopListening(this.controller.get("txtCustomClientId"), Mojo.Event.propertyChange, this.handleValueChange);
Mojo.Event.stopListening(this.controller.get("toggleCustomEndPoint"), Mojo.Event.propertyChange, this.handleValueChange);
Mojo.Event.stopListening(this.controller.get("txtClientAPI"), Mojo.Event.propertyChange, this.handleValueChange);
Mojo.Event.stopListening(this.controller.get("txtEndpointURL"), Mojo.Event.propertyChange, this.handleValueChange);
Mojo.Event.stopListening(this.controller.get("btnOK"), Mojo.Event.tap, this.okClick.bind(this));
Mojo.Event.stopListening(this.controller.get("txtShortURL"), Mojo.Event.propertyChange, this.handleValueChange);
Mojo.Event.stopListening(this.controller.get("txtCustomCreateKey"), Mojo.Event.propertyChange, this.handleValueChange);
Mojo.Event.stopListening(this.controller.get("btnOK"), Mojo.Event.tap, this.okClick);
};
PreferencesAssistant.prototype.cleanup = function(event) {
+5 -8
View File
@@ -1,14 +1,11 @@
Mojo.Additions = Additions;
function StageAssistant() {
/* this is the creator function for your stage assistant object */
}
StageAssistant.prototype.activate = function() {
Mojo.Log.error("Stage activated");
stageController = Mojo.Controller.stageController;
if (stageController.getScenes().length < 1)
stageController.pushScene('main');
}
StageAssistant.prototype.setup = function() {
Mojo.Log.info("Stage assistant created!");
/* this function is for setup tasks that have to happen when the stage is first created */
this.controller.pushScene({ name: "main" });
this.controller.setWindowOrientation("free");
};
-79
View File
@@ -1,79 +0,0 @@
function UserAssistant(sceneAssistant, doneCallBack) {
this.doneCallBack = doneCallBack;
/* this is the creator function for your scene assistant object. It will be passed all the
additional parameters (after the scene name) that were passed to pushScene. The reference
to the scene controller (this.controller) has not be established yet, so any initialization
that needs the scene controller should be done in the setup function below. */
Mojo.Log.info("new User assistant exists");
this.sceneAssistant = sceneAssistant; //dialog's do not have their own controller, so need access to the launching scene's controller
}
UserAssistant.prototype.setup = function(widget) {
/* this function is for setup tasks that have to happen when the scene is first created */
this.widget = widget;
Mojo.Log.info("User assistant setup");
Mojo.Log.info("Current username is: " + appModel.AppSettingsCurrent["SenderName"]);
/* setup widgets here */
this.sceneAssistant.controller.setupWidget("txtUserName",
this.attributes = {
textFieldName: "userName",
hintText: " Enter nickname",
property: 'value',
multi: false,
enterSubmits: true,
changeOnKeyPress: false,
textReplacement: false,
requiresEnterKey: false,
focus: true
},
this.model = {
value: appModel.AppSettingsCurrent["SenderName"],
disabled: false
}
);
this.sceneAssistant.controller.setupWidget("goButton", { type: Mojo.Widget.defaultButton }, { label: "OK", disabled: false });
//this.sceneAssistant.controller.setupWidget("cancelButton", { type: Mojo.Widget.button }, { label: "Cancel", disabled: false });
/* add event handlers to listen to events from widgets */
Mojo.Event.listen(this.sceneAssistant.controller.get("txtUserName"), Mojo.Event.propertyChange, this.handleValueChange.bind(this));
Mojo.Event.listen(this.sceneAssistant.controller.get("goButton"), Mojo.Event.tap, this.handleGoPress.bind(this));
//Mojo.Event.listen(this.sceneAssistant.controller.get("cancelButton"), Mojo.Event.tap, this.handleCancelPress.bind(this));
};
UserAssistant.prototype.handleValueChange = function(event) {
this.handleGoPress();
};
UserAssistant.prototype.handleGoPress = function(event) {
var newName = this.sceneAssistant.controller.get('txtUserName').mojo.getValue();
if (newName && newName != "" && newName != " " && newName.toLowerCase() != "webos user") {
//Remember the name they entered
appModel.AppSettingsCurrent["SenderName"] = newName;
appModel.SaveSettings();
this.doneCallBack(newName);
this.widget.mojo.close();
} else {
Mojo.Controller.getAppController().showBanner({ messageText: "Provide a unique username!" }, "", "");
}
}
UserAssistant.prototype.activate = function(event) {
this.sceneAssistant.controller.get('txtUserName').mojo.focus();
/* put in event handlers here that should only be in effect when this scene is active. For
example, key handlers that are observing the document */
};
UserAssistant.prototype.deactivate = function(event) {
/* remove any event handlers you added in activate and do any other cleanup that should happen before
this scene is popped or another scene is pushed on top */
Mojo.Event.stopListening(this.sceneAssistant.controller.get("txtUserName"), Mojo.Event.propertyChange, this.handleValueChange.bind(this));
Mojo.Event.stopListening(this.sceneAssistant.controller.get("goButton"), Mojo.Event.tap, this.handleGoPress.bind(this));
//Mojo.Event.stopListening(this.sceneAssistant.controller.get("cancelButton"), Mojo.Event.tap, this.handleCancelPress.bind(this));
};
UserAssistant.prototype.cleanup = function(event) {
Mojo.Log.info("user assistant cleaned up");
/* this function should do any cleanup needed before the scene is destroyed as
a result of being popped off the scene stack */
};
+14 -87
View File
@@ -7,106 +7,33 @@ function VersionAssistant(startup) {
//New Features
this.changelog = [
{
version: "Version 1.9.0",
version: "Version 1.0.2 Changes",
detail: [
"Share images in the chat, right from your webOS device!",
"Fixes a bug that prevents background downloads when Always Use HTTP is on",
]
},
{
version: "Version 1.8.6",
version: "Version 1.0.1 Changes",
detail: [
"Fix a bug parsing certain kinds of links.",
"Add download button to detail scene",
"Fix a layout issue",
]
},
{
version: "Version 1.8.5",
version: "Version 1.0.0 Features",
detail: [
"Add support for sharing from JustType and other apps.",
"Wirelessly add photos to Exhibition from anywhere with automatic downloads -- just turn it on in Preferences (requires FileMgr)",
"Touch2Share content between your devices, either loading it in a web page, or right in the app (turn on 'Handle URLs' in the menu)",
"Share photos you take on your device via email, text message, or other web apps by copying the link the app makes for you -- grab it from the content detail scene, or turn on 'Copy Link on Share' in Preferences",
"Start a new share from JustType -- turn it on in your JustType settings",
"Host your own server for more control and privacy!"
]
},
{
version: "Version 1.8.0",
version: "Coming Soon",
detail: [
"Dark theme now available in Preferences!",
]
},
{
version: "Version 1.7.1",
detail: [
"Fix a bug where hardware mute switch wasn't respected. Show transmit indicator. Add ability to disable link and image parsing to speed things up on tiny devices.",
]
},{
version: "Version 1.7.0",
detail: [
"Images from Discord are now supported! Inline rendering uses a thumbnail for efficiency; tap the image to load the fullsize, or tap elsewhere on the row to pull up the menu that lets you download the image to your device (it will be saved to /internal/downloads)",
]
},{
version: "Version 1.6.0",
detail: [
"Added ability to parse Imgur album links and render via a service proxy.",
]
},{
version: "Version 1.5.0",
detail: [
"Added ability to parse Share Services links and show thumbnails, configurable in Preferences.",
]
},{
version: "Version 1.4.1",
detail: [
"Add support for some basic markdown",
]
},
{
version: "Version 1.4.0",
detail: [
"Enter key behavior as a Preference",
"Even more silent background sync, won't sync if offline",
"Swiping notifications resets missed message count",
"Adjust tap target for collapsing controls"
]
},
{
version: "Version 1.3.2",
detail: [
"More sync timing options.",
"Refactored some code to make forking easier."
]
}, {
version: "Version 1.3.1",
detail: [
"Enter key now sends message when Command menu buttons are hidden."
]
},
{
version: "Version 1.3.0",
detail: [
"Drastically improved background update and notifications."
]
}, {
version: "Version 1.2.0",
detail: [
"Converts image links to an image proxy so they can be viewed and scaled properly on tiny devices",
"Improved background update, using a notification launch, no longer interupts Exhibition, video playback or One Night Stand"
]
},
{
version: "Version 1.1.3",
detail: [
"Bug fixes and general maintenance"
]
}, {
version: "Version 1.1.2",
detail: [
"Show/Hide the Command menu buttons by tapping the Compose area title bar",
"Enable/Disable Discord Emojis in Preferences",
]
}, {
version: "Version 1.1.1",
detail: [
"Improved Discord integration, including showing Emojis!<span class='emoji-outer emoji-sizer'><span class='emoji-inner emoji1f388'></span></span>",
"Now with a smaller emoji file!",
"Improved timeout logic.",
"Trying different background sync logic."
"Shared Clipboard mode will minimize to a Dashboard to make it quick and easy to share text and links between your devices",
"Share with other users, without needing to log out and back in",
]
}
];
+68
View File
@@ -0,0 +1,68 @@
function WelcomeAssistant(startup) {
this.isStartup = startup;
// on first start, this message is displayed, along with the current version message from below
//this.startupMessage = Mojo.Controller.appInfo.startupMessage;
this.startupMessage = "Your account has been created!";
// setup command menu
this.cmdMenuModel = {
visible: false,
items: [
{},
{
label: $L("Got it!"),
command: 'do-continue'
},
{}
]
};
};
WelcomeAssistant.prototype.setup = function() {
//this.titleElement = this.controller.get('title');
this.dataElement = this.controller.get('welcome-data');
//this.titleElement.innerHTML = $L('Version Info');
var useURL = serviceModel.buildURL(null, "");
useURL = useURL.replace(".php", "");
var html = '<p>';
html += '<b>Name:</b> <em>' + appModel.AppSettingsCurrent["Username"] + "</em><br>";
html += '<b>Share Phrase:</b> <em>' + appModel.AppSettingsCurrent["SharePhrase"] + "</em><br>";
html += '<b>Admin Password:</b> <em>' + appModel.AppSettingsCurrent["Credential"] + "</em><br>";
html += '<b>URL:</b> <em>' + useURL + "</em><br></p>";
// set data
this.dataElement.innerHTML = html;
// setup menu
this.controller.setupWidget(Mojo.Menu.appMenu, { omitDefaultItems: true }, { visible: false });
//if (this.isStartup) {
// set command menu
this.controller.setupWidget(Mojo.Menu.commandMenu, { menuClass: 'no-fade' }, this.cmdMenuModel);
//}
};
WelcomeAssistant.prototype.activate = function(event) {
this.timer = this.controller.window.setTimeout(this.showContinue.bind(this), 4 * 1000);
};
WelcomeAssistant.prototype.deactivate = function(event) {};
WelcomeAssistant.prototype.cleanup = function(event) {};
WelcomeAssistant.prototype.showContinue = function() {
// show the command menu
this.controller.setMenuVisible(Mojo.Menu.commandMenu, true);
};
WelcomeAssistant.prototype.handleCommand = function(event) {
if (event.type == Mojo.Event.command) {
switch (event.command) {
case 'do-continue':
var stageController = Mojo.Controller.getAppController().getActiveStageController();
stageController.swapScene({ transition: Mojo.Transition.zoomFade, name: "main" });
break;
}
}
};
+1 -1
View File
@@ -12,7 +12,7 @@ Mojo Additions
this.Additions = function() {}
console.log("** Mojo Additions loaded **");
Mojo.Log.info("#### Mojo Additions added");
Additions.ShowDialogBox = function(title, message) {
var stageController = Mojo.Controller.getAppController().getActiveStageController();
+58 -85
View File
@@ -2,7 +2,6 @@
App Model
Version 0.4
Created: 2018
Author: Jon W
License: MIT
Description: Common functions for webOS apps, particularly for managing persisted options in cookies
*/
@@ -12,58 +11,41 @@ var AppModel = function() {
this.DefaultScene = "main";
//Define your app-wide, non-persisted settings here
this.UpdateCheckDone = false;
this.LaunchQuery = "";
this.ServiceEndpointBase = Mojo.Controller.appInfo.serviceURL;
this.ClientId = secrets.clientid;
this.LastMessageSelected = null;
this.LastShareSelected = null;
this.CurrentShareURL = null;
this.FileMgrPresent = true;
//Define your app preferences (to be saved by OS)
this.AppSettingsCurrent = null;
this.AppSettingsDefaults = {
ThemePreference: "palm-default",
ForegroundUpdate: 10000,
BackgroundUpdate: "00:30:00",
AlertSound: "Subtle (short)",
ShowEmojis: true,
SkipParsing: false,
ShowWOSAThumbs: true,
EnterSubmits: "collapsed",
UseClientAPIKey: false,
Username: "",
Credential: "",
SharePhrase: "",
RefreshTimeout: 60000,
UseAutoDownload: false,
AutoDownloadTime: "01:00:00",
CopyLinkOnShare: true,
ForceHTTP: false,
UseCustomEndpoint: false,
ClientAPIKey: "",
EndpointURL: "",
SenderName: "webOS User",
FirstRun: true,
MyMessages: null,
LastKnownMessage: null,
LastVersionRun: 0
ShortURL: "",
UseCustomClientId: false,
CustomClientId: "",
CustomCreateKey: "",
UseCustomDownloadPath: false,
CustomDownloadPath: null,
LastVersionRun: "0.0.1",
DebugMode: false,
};
}
AppModel.prototype.SetThemePreference = function(theController) {
if (appModel.AppSettingsCurrent["ThemePreference"] != "system-theme") {
theController.document.body.className = appModel.AppSettingsCurrent["ThemePreference"];
Mojo.Log.info("Using local theme pref: " + appModel.AppSettingsCurrent["ThemePreference"]);
} else {
systemModel.LoadWOSAPrefs(function(response) {
if (response) {
Mojo.Log.error("Using system theme pref: " + systemModel.WOSAPrefs.theme);
theController.document.body.className = systemModel.WOSAPrefs.theme;
}
}.bind(this))
}
}
AppModel.prototype.ShowNotificationStage = function() {
Mojo.Log.info("App Model checking if we need to show Dashboard stage...");
AppModel.prototype.ShowDownloaderStage = function() {
Mojo.Log.info("App Model checking if we should to show Dashboard stage...");
this.serviceEndpointBase = appModel.ServiceEndpointBase;
if (appModel.AppSettingsCurrent["UseCustomEndpoint"] && appModel.AppSettingsCurrent["EndpointURL"]) {
this.serviceEndpointBase = appModel.AppSettingsCurrent["EndpointURL"];
}
if (appModel.AppSettingsCurrent["UseClientAPIKey"] && appModel.AppSettingsCurrent["ClientAPIKey"]) {
this.ClientId = appModel.AppSettingsCurrent["ClientAPIKey"];
}
//Check for connectivity, then check for messages
systemModel.GetInternetConnectionState(this.checkForMessages.bind(this));
}
@@ -71,57 +53,28 @@ AppModel.prototype.ShowNotificationStage = function() {
AppModel.prototype.checkForMessages = function(connMgrResponse) {
Mojo.Log.info("App Model got response from connection manager: " + JSON.stringify(connMgrResponse));
if (connMgrResponse && connMgrResponse.isInternetConnectionAvailable) {
Mojo.Log.info("Checking for new messages in App Model...");
serviceModel.getChats(this.serviceEndpointBase, this.ClientId, function(response) {
Mojo.Log.info("App Model got response from getChats: " + response);
if (response != null && response != "") {
var responseObj = JSON.parse(response);
if (responseObj.status != "error") {
if (responseObj.messages && responseObj.messages.length > 0) {
var newMessageCount = this.findNewMessageCount(appModel.AppSettingsCurrent["LastKnownMessage"], responseObj.messages);
if (newMessageCount > 0) {
Mojo.Log.info("Found new chat on server during App Model message check!");
this.actuallyShowNotificationStage();
}
}
}
}
}.bind(this));
this.actuallyShowDownloaderStage();
}
}
AppModel.prototype.findNewMessageCount = function(LastKnownMessage, newMessages) {
var actuallyNewMessages = [];
var startCounting = false;
for (var j = 0; j < newMessages.length; j++) {
if (startCounting) {
actuallyNewMessages.push(newMessages[j].uid);
}
if (newMessages[j].uid == LastKnownMessage) {
startCounting = true;
}
}
return actuallyNewMessages.length;
}
AppModel.prototype.actuallyShowNotificationStage = function() {
AppModel.prototype.actuallyShowDownloaderStage = function() {
this.controller = Mojo.Controller.getAppController();
var dashboardStage = this.controller.getStageProxy("dashboard");
var dashboardStage = this.controller.getStageProxy("download");
var pushDashScene = function(stageController) {
stageController.pushScene('dashboard', "dashboard/dashboard-scene");
stageController.pushScene('download', "download/download-scene");
}.bind(this);
if (!dashboardStage) {
Mojo.Log.info("Dashboard stage not open, creating it...");
Mojo.Log.info("Download dashboard not open, creating it...");
this.controller.createStageWithCallback({
name: 'dashboard',
name: 'download',
lightweight: true,
height: 100,
soundclass: "assets/silent.mp3"
}, pushDashScene, 'dashboard');
} else {
Mojo.Log.info("Dashboard stage already open, activating it...");
var dashboardStageController = this.controller.getStageController("dashboard");
Mojo.Log.info("Download dashboard already open, activating it...");
var dashboardStageController = this.controller.getStageController("download");
if (dashboardStageController) {
dashboardStageController.activate();
dashboardStageController.delegateToSceneAssistant("activate");
@@ -129,19 +82,41 @@ AppModel.prototype.actuallyShowNotificationStage = function() {
}
}
AppModel.prototype.CloseNotificationStage = function() {
AppModel.prototype.CloseDashboardStageByName = function(stageName) {
this.controller = Mojo.Controller.getAppController();
var dashboardStage = this.controller.getStageProxy("dashboard");
var dashboardStage = this.controller.getStageProxy(stageName);
if (!dashboardStage) {
Mojo.Log.info("Dashboard stage not open, nothing to do");
Mojo.Log.info(stageName + " dashboard not open, nothing to do");
} else {
Mojo.Log.info("Dashboard stage open, closing it...");
this.controller.closeStage("dashboard");
Mojo.Log.info(stageName + " dashboard open, closing it...");
this.controller.closeStage(stageName);
}
}
//#region Inherited from common App Model
AppModel.prototype.EstablishAlarms = function() {
//Reset alarms
systemModel.ClearSystemAlarm("BackgroundDownload");
if (appModel.AppSettingsCurrent["UseAutoDownload"] && appModel.AppSettingsCurrent["Username"] != "" && appModel.AppSettingsCurrent["Credential"]) {
Mojo.Log.warn("Re-establishing background download alarm with time: " + appModel.AppSettingsCurrent["AutoDownloadTime"]);
systemModel.SetSystemAlarmRelative("BackgroundDownload", appModel.AppSettingsCurrent["AutoDownloadTime"]);
} else {
Mojo.Log.warn("Not setting background download alarm since conditions weren't met.");
}
}
AppModel.prototype.ConvertTimeStamp = function(timeStamp, isUTC) {
if (isUTC) {
var offset = new Date().getTimezoneOffset();
timeStamp = Date.parse(timeStamp);
timeStamp = timeStamp - ((offset * 60) * 1000);
timeStamp = new Date(timeStamp);
}
timeStamp = timeStamp.toLocaleString();
timeStamp = timeStamp.split("GMT");
timeStamp = timeStamp[0];
return timeStamp;
}
//You probably don't need to change the below functions since they all work against the Cookie defaults you defined above.
// LoadSettings: call when your app starts, or you want to load previously persisted options.
@@ -219,6 +194,4 @@ AppModel.prototype.ResetSettings = function() {
//Restart main scene
stageController.pushScene(this.DefaultScene);
Mojo.Log.info("re-opened default scene");
}
//#endregion
}
-175
View File
@@ -1,175 +0,0 @@
var ServiceModel = function() {
};
ServiceModel.prototype.makeServiceUrl = function(serviceBase, endPoint) {
if (endPoint.indexOf(".php") == -1)
endPoint = endPoint + ".php";
return serviceBase + endPoint;
}
ServiceModel.prototype.getChats = function(serviceBase, clientId, callback) {
var serviceURL = serviceBase + "get-chat.php";
Mojo.Log.info("Trying to get chats from: " + serviceURL);
this.retVal = "";
if (callback)
callback = callback.bind(this);
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", serviceURL);
xmlhttp.setRequestHeader("Client-Id", clientId);
xmlhttp.send();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE) {
if (callback)
callback(xmlhttp.responseText);
}
}.bind(this);
}
ServiceModel.prototype.postChat = function(useSender, useMessage, serviceBase, clientId, callback) {
var serviceURL = serviceBase + "post-chat.php";
var msgToPost = {
sender: useSender,
message: useMessage
}
Mojo.Log.info("Posting chat to: " + serviceURL);
Mojo.Log.info(JSON.stringify(msgToPost));
this.retVal = "";
if (callback)
callback = callback.bind(this);
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", serviceURL);
xmlhttp.setRequestHeader("Client-Id", clientId);
xmlhttp.timeout = 2000;
xmlhttp.send(JSON.stringify(msgToPost));
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE) {
if (callback)
callback(xmlhttp.responseText);
}
}.bind(this);
xmlhttp.ontimeout = function() {
callback();
}.bind(this);
}
ServiceModel.prototype.editChat = function(useSender, useMessage, uid, editKey, serviceBase, clientId, callback) {
var serviceURL = serviceBase + "edit-chat.php";
var msgToPost = {
sender: useSender,
message: useMessage,
uid: uid,
editKey: editKey
}
Mojo.Log.info("Edit chat to: " + serviceURL);
Mojo.Log.info(JSON.stringify(msgToPost));
this.retVal = "";
if (callback)
callback = callback.bind(this);
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", serviceURL);
xmlhttp.setRequestHeader("Client-Id", clientId);
xmlhttp.send(JSON.stringify(msgToPost));
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE) {
if (callback)
callback(xmlhttp.responseText);
}
}.bind(this);
}
ServiceModel.prototype.uploadPhoto = function(fullFilePath, sender, serviceBase, clientId, callback, errorhandler) {
var useURL = serviceBase + 'upload-attachment.php';
Mojo.Log.info("Uploading photo: " + fullFilePath + " to " + useURL);
return new Mojo.Service.Request('palm://com.palm.downloadmanager/', {
method: 'upload',
parameters: {
fileName: fullFilePath,
url: useURL,
fileLabel: 'image',
contentType: (function(p) {
var e = p.split('.').pop().toLowerCase();
return e === 'png' ? 'image/png' : e === 'gif' ? 'image/gif' : 'image/jpeg';
}(fullFilePath)),
postParameters: [
{ key: 'sender', data: sender }
],
customHttpHeaders: ['Client-Id: ' + clientId],
subscribe: true
},
onSuccess: function(e) {
if (!e.completed) return;
if (e.completionCode !== 0 || e.httpCode !== 200) {
if (errorhandler) errorhandler('Upload failed: HTTP ' + e.httpCode + ', code ' + e.completionCode);
return;
}
try {
var result = JSON.parse(e.responseString);
if (callback) callback(result);
} catch (ex) {
if (errorhandler) errorhandler('Bad response from upload server');
}
},
onFailure: function(e) {
if (errorhandler) errorhandler('Upload error: ' + JSON.stringify(e));
}
});
};
ServiceModel.prototype.postChatWithAttachment = function(useSender, attachments, serviceBase, clientId, callback) {
var serviceURL = serviceBase + 'post-chat.php';
var msgToPost = {
sender: useSender,
message: '',
attachments: attachments
};
Mojo.Log.info("Posting chat with attachment to: " + serviceURL);
if (callback)
callback = callback.bind(this);
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", serviceURL);
xmlhttp.setRequestHeader("Client-Id", clientId);
xmlhttp.timeout = 5000;
xmlhttp.send(JSON.stringify(msgToPost));
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE) {
if (callback)
callback(xmlhttp.responseText);
}
}.bind(this);
xmlhttp.ontimeout = function() {
if (callback) callback();
}.bind(this);
};
ServiceModel.prototype.likeChat = function(uid, serviceBase, clientId, callback) {
var serviceURL = serviceBase + "like-chat.php";
var msgToPost = {
uid: uid,
like: "+1"
}
Mojo.Log.info("Like chat to: " + serviceURL);
Mojo.Log.info(JSON.stringify(msgToPost));
this.retVal = "";
if (callback)
callback = callback.bind(this);
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", serviceURL);
xmlhttp.setRequestHeader("Client-Id", clientId);
xmlhttp.send(JSON.stringify(msgToPost));
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE) {
if (callback)
callback(xmlhttp.responseText);
}
}.bind(this);
}
+449
View File
@@ -0,0 +1,449 @@
/*
ShareBoard Model - Mojo
Version 1.0
Created: 2021
License: MIT
Description: A model to interact with a share service
*/
var ShareServiceModel = function() {
this.urlBase = Mojo.Controller.appInfo.serviceURL;
this.shortUrlBase = Mojo.Controller.appInfo.shortURL;
};
//Properties
ShareServiceModel.prototype.ForceHTTP = false;
ShareServiceModel.prototype.UseCustomShare = false;
ShareServiceModel.prototype.UseCustomEndpoint = false;
ShareServiceModel.prototype.CustomEndpointURL = "";
ShareServiceModel.prototype.CustomShortURL = "";
ShareServiceModel.prototype.CustomCreateKey = "";
ShareServiceModel.prototype.UseCustomClientId = false;
ShareServiceModel.prototype.CustomClientId = "";
//ShareServiceModel.prototype.ServiceCompatWarning = 0;
ShareServiceModel.prototype.buildURL = function(username, actionType) {
var urlBase = this.urlBase;
if (this.UseCustomEndpoint == true && this.CustomEndpointURL != "") {
urlBase = this.CustomEndpointURL;
}
//Make sure we don't end up with double slashes in the built URL if there's a custom endpoint
var urlTest = urlBase.split("://");
if (urlTest[urlTest.length - 1].indexOf("/") != -1) {
urlBase = urlBase.substring(0, urlBase.length - 1);
}
var path = urlBase + "/" + actionType + ".php";
if (username)
path += "?username=" + username;
if (this.ForceHTTP)
path = path.replace ("https:", "http:");
return path;
}
ShareServiceModel.prototype.MakeShareURL = function(username, guid, type) {
var urlBase = this.shortUrlBase;
if (this.CustomShortURL == true && this.CustomShortURL != "") {
urlBase = this.CustomShortURL;
}
if (type.indexOf("image") != -1)
urlBase = urlBase + "download.php?";
else
urlBase = urlBase + "t.php?";
var data = username + "|" + guid;
data = btoa(data);
urlBase = urlBase + data;
if (urlBase.indexOf("==") == urlBase.length - 2)
urlBase = urlBase.slice(0, urlBase.length - 2)
return urlBase;
}
//HTTP request for list files
ShareServiceModel.prototype.DoShareListRequest = function(username, credential, callback, errorhandler) {
if (callback)
callback = callback.bind(this);
if (!errorhandler) {
errorhandler = function(errorText) {
Mojo.Log.warn(errorText);
Mojo.Controller.getAppController().showBanner({ messageText: errorText }, "", "");
}
} else {
errorhandler = errorhandler.bind(this);
}
var useURL = this.buildURL(username, "get-shares");
Mojo.Log.info("Calling sharing service at " + useURL + " with key " + this.getCurrentClientKey());
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", useURL);
xmlhttp.setRequestHeader("client-id", this.getCurrentClientKey());
xmlhttp.setRequestHeader("credential", credential);
xmlhttp.send();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE) {
if (xmlhttp.status >= 400) {
errorhandler(xmlhttp.status + " Error getting share list: " + responseObj.error, callback);
return false;
} else {
if (xmlhttp.responseText && xmlhttp.responseText != "") {
try {
var responseObj = JSON.parse(xmlhttp.responseText);
if (responseObj.error) {
errorhandler("Share service error: " + responseObj.error, callback);
return false;
} else {
//Mojo.Log.info("Share List success! " + xmlhttp.responseText);
if (callback) {
callback(responseObj);
} else {
Mojo.Controller.getAppController().showBanner({ messageText: "Shares retreived!" }, "", "");
}
return true;
}
} catch (ex) {
errorhandler("Error parsing share list response: " + ex + ", response: " + xmlhttp.responseText, callback);
return false;
}
} else {
errorhandler("Share list response was empty", callback);
return false;
}
}
}
}.bind(this);
}
//HTTP request for add file
ShareServiceModel.prototype.DoShareAddRequestText = function(content, username, credential, contenttype, callback, errorhandler) {
if (callback)
callback = callback.bind(this);
if (!errorhandler) {
errorhandler = function(errorText) {
Mojo.Log.warn(errorText);
Mojo.Controller.getAppController().showBanner({ messageText: errorText }, "", "");
}
}
var useURL = this.buildURL(username, "share-text");
Mojo.Log.info("Adding text share: " + content + " of type " + contenttype + " from URL " + useURL);
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", useURL);
xmlhttp.setRequestHeader("client-id", this.getCurrentClientKey());
xmlhttp.setRequestHeader("credential", credential);
xmlhttp.setRequestHeader("content-type", contenttype);
xmlhttp.send(content);
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE) {
if (xmlhttp.status >= 400) {
errorhandler(xmlhttp.status + " Error adding share text: " + responseObj.error);
return false;
} else {
Mojo.Log.info("Share service sent response while sharing text: " + xmlhttp.responseText);
if (xmlhttp.responseText && xmlhttp.responseText != "") {
try {
var responseObj = JSON.parse(xmlhttp.responseText);
if (responseObj.error) {
errorhandler("Error sharing text: " + responseObj.error);
return false;
} else {
Mojo.Log.info("Share text success! " + xmlhttp.responseText);
if (callback) {
callback(responseObj);
} else {
Mojo.Controller.getAppController().showBanner({ messageText: "Content shared!" }, "", "");
}
return true;
}
} catch (ex) {
errorhandler("Error parsing add share response: " + ex);
return false;
}
} else {
errorhandler("Add share response was empty");
return false;
}
}
}
}.bind(this);
}
//Upload a file
ShareServiceModel.prototype.DoShareAddRequestImage = function (fullFilePath, username, credential, contenttype, callback, errorhandler) {
if (callback)
callback = callback.bind(this);
if (!errorhandler) {
errorhandler = function(errorText) {
Mojo.Log.warn(errorText);
Mojo.Controller.getAppController().showBanner({ messageText: errorText }, "", "");
}
}
var useURL = this.buildURL(username, "share-image");
Mojo.Log.info("Adding image share: " + fullFilePath + " of type " + contenttype + " from URL " + useURL);
this.uploadRequest = new Mojo.Service.Request('palm://com.palm.downloadmanager/', {
method: 'upload',
parameters: {
fileName: fullFilePath,
url: useURL,
fileLabel: "image",
contentType: contenttype,
postParameters: [
{"key":"username", "data": username},
{"key":"credential" , "data": credential},
],
customHttpHeaders : [
'client-id: ' + this.getCurrentClientKey(),
],
subscribe: true
},
onSuccess: function(response) {
Mojo.Log.info("Upload progress", JSON.stringify(response));
if ((response.completed && response.completed == true) || (response.completionCode && response.completionCode != 0)) {
if (response.error) {
errorhandler(response.error);
return false;
} else if (response.completionCode && response.completionCode != 0) {
var errMsg = "error code " + response.completionCode;
switch(Math.abs(response.completionCode)) {
case 1:
errMsg = "General Error";
break;
case 2:
errMsg = "Connection Timeout";
break;
case 3:
errMsg = "Corrupt File";
break;
case 4:
errMsg = "File System Error";
break;
case 5:
errMsg = "HTTP Error";
break;
case 6:
errMsg = "Connection Offline";
break;
}
errorhandler(errMsg);
return false;
} else {
if (response.responseString) {
Mojo.Log.info("Upload response: " + response.responseString);
var responseObj = JSON.parse(response.responseString);
if (responseObj.error) {
errorhandler(responseObj.error);
return false;
} else {
if (callback) {
callback(responseObj);
} else {
Mojo.Controller.getAppController().showBanner({ messageText: "Image uploaded!" }, "", "");
}
return true;
}
} else {
errorhandler("Error uploading image: server response was empty");
return false;
}
}
}
},
onFailure: function(response) {
errorhandler("Error uploading image share: " + response);
return false;
}
});
}
//HTTP request for list files
ShareServiceModel.prototype.DoShareDeleteRequest = function(itemid, username, credential, callback, errorhandler) {
if (callback)
callback = callback.bind(this);
if (!errorhandler) {
errorhandler = function(errorText) {
Mojo.Log.warn(errorText);
Mojo.Controller.getAppController().showBanner({ messageText: errorText }, "", "");
}
}
var useURL = this.buildURL(username, "delete-share-item");
Mojo.Log.info("Calling sharing service at " + useURL + " for item " + itemid + " with key " + this.getCurrentClientKey());
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", useURL);
xmlhttp.setRequestHeader("client-id", this.getCurrentClientKey());
xmlhttp.setRequestHeader("credential", credential);
xmlhttp.setRequestHeader("itemid", itemid);
xmlhttp.send();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE) {
if (xmlhttp.status >= 400) {
errorhandler(xmlhttp.status + " Error deleting share: " + responseObj.error);
return false;
} else {
Mojo.Log.info("Share service sent response while deleting share: " + xmlhttp.responseText);
if (xmlhttp.responseText && xmlhttp.responseText != "") {
try {
var responseObj = JSON.parse(xmlhttp.responseText);
if (responseObj.error) {
errorhandler("Error deleting share: " + responseObj.error);
return false;
} else {
Mojo.Log.info("Share Delete success! " + xmlhttp.responseText);
if (callback) {
callback(responseObj);
} else {
Mojo.Controller.getAppController().showBanner({ messageText: "Content deleted!" }, "", "");
}
return true;
}
} catch (ex) {
errorhandler("Error parsing delete share response: " + ex);
return false;
}
} else {
errorhandler("Delete share response was empty");
return false;
}
}
}
}.bind(this);
}
//HTTP request for new user
ShareServiceModel.prototype.DoNewUserRequest = function(username, sharephrase, password, callback, errorhandler) {
if (callback)
callback = callback.bind(this);
if (!errorhandler) {
errorhandler = function(errorText) {
Mojo.Log.warn(errorText);
Mojo.Controller.getAppController().showBanner({ messageText: errorText }, "", "");
}
}
var useURL = this.buildURL(null, "new-user");
Mojo.Log.info("Creating user: " + username + " with share-phrase " + sharephrase + " and password " + password + " from URL " + useURL);
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", useURL);
xmlhttp.setRequestHeader("client-id", this.getCurrentClientKey());
var request = {
"username":username,
"sharephrase":sharephrase,
"password":password,
"createkey":this.getCurrentCreateKey()
}
xmlhttp.send(JSON.stringify(request));
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE) {
if (xmlhttp.status >= 400) {
errorhandler(xmlhttp.status + " Error creating user: " + responseObj.error);
return false;
} else {
Mojo.Log.info("Share service sent response while creating user: " + xmlhttp.responseText);
if (xmlhttp.responseText && xmlhttp.responseText != "") {
try {
var responseObj = JSON.parse(xmlhttp.responseText);
if (responseObj.error) {
errorhandler("Error creating user: " + responseObj.error);
return false;
} else {
Mojo.Log.info("New user success! " + xmlhttp.responseText);
if (callback) {
callback(responseObj);
} else {
Mojo.Controller.getAppController().showBanner({ messageText: "User created!" }, "", "");
}
return true;
}
} catch (ex) {
errorhandler("Error parsing create user response: " + ex);
return false;
}
} else {
errorhandler("Create user response was empty");
return false;
}
}
}
}.bind(this);
}
//HTTP request to get Terms and Conditions
ShareServiceModel.prototype.GetTnC = function(callback) {
if (callback)
callback = callback.bind(this);
var useURL = this.buildURL(null, "tandc");
Mojo.Log.info("Getting Terms and Conditions with query: " + useURL);
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", useURL);
xmlhttp.send();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE) {
if (callback)
callback(xmlhttp.responseText);
}
}.bind(this);
}
//HTTP request to get random share phrase
ShareServiceModel.prototype.GetRandomWords = function(callback) {
if (callback)
callback = callback.bind(this);
var theQuery = this.buildURL(null, "random-words");
Mojo.Log.info("Getting Random words query: " + theQuery);
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", theQuery);
xmlhttp.send();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE) {
if (callback)
callback(xmlhttp.responseText);
}
}.bind(this);
}
//HTTP request to get random share phrase
ShareServiceModel.prototype.QueryShareData = function(query, callback) {
if (callback)
callback = callback.bind(this);
var theQuery = query;
theQuery = theQuery.replace("download.php", "q.php");
theQuery = theQuery.replace("image.php", "q.php");
theQuery = theQuery.replace("t.php", "q.php");
Mojo.Log.warn("Querying share item with URL: " + theQuery);
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", theQuery);
xmlhttp.send();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE) {
try {
var itemData = JSON.parse(xmlhttp.responseText);
if (callback)
callback(itemData);
} catch (ex) {
Mojo.Log.error("Got bad item query response payload: " + ex, xmlhttp.responseText);
}
}
}.bind(this);
}
ShareServiceModel.prototype.getCurrentClientKey = function() {
var retVal = atob(appKeys['shareBoardClientKey']);
if (this.UseCustomEndpoint) {
retVal = this.CustomClientId;
Mojo.Log.info("Using custom shareboard client key: " + retVal);
}
//Mojo.Log.info("Using shareboard client key: " + retVal);
return retVal;
}
ShareServiceModel.prototype.getCurrentCreateKey = function() {
var retVal = atob(appKeys['shareBoardCreateKey']);
if (this.UseCustomEndpoint) {
retVal = this.CustomCreateKey;
Mojo.Log.info("Using custom shareboard create key: " + retVal);
}
//Mojo.Log.info("Using shareboard create key: " + retVal);
return retVal;
}
+26
View File
@@ -0,0 +1,26 @@
<div class="palm-hasheader" style="margin-bottom:60px">
<div id="divShareTitle" class="palm-header center" onclick="Mojo.Controller.stageController.swapScene({ transition: Mojo.Transition.crossFade, name: 'main' });">
Share Details
</div>
</div>
<!-- only visible in debug mode -->
<div class="palm-group" id="divShareInfo" style="display:none">
<div class="palm-group-title">
<span x-mojo-loc=''>Debug Links</span>
</div>
<div id="divShareLinks" name="divShareLinks">
</div>
</div>
<div class="palm-group" id="divTextDetail">
<div class="palm-group-title">
<span x-mojo-loc=''>Content</span>
</div>
<div id="divTextContent" name="divTextContent" style="background-color:white; border: 1px solid dimgray; margin: 0px;">
<div id="divImageContent" style="width:100%; margin:auto; align-content: center; text-align: center;margin-top: 6px !important;">
<img src="icon-256.png" style="width:128px;height:128px" /><br/>
</div>
</div>
</div>
@@ -3,7 +3,7 @@
<div class="dashboard-newitem" style="display:#{showCount}">
<span>#{count}</span>
</div>
<div id="dashboard-icon" class="palm-dashboard-icon dashboard-icon-chat">
<div id="dashboard-icon" class="palm-dashboard-icon dashboard-icon-download">
</div>
</div>
<div class="palm-dashboard-text-container">
+31
View File
@@ -0,0 +1,31 @@
<div class="palm-dialog-content">
<div id="login-title" class="palm-dialog-title">
Log In to a Share Space
</div>
<div class="palm-dialog-seperator"></div>
<div class="textfield-group" x-mojo-focus-highlight="true">
<div class="title">
<div id="txtUsername" name="txtUsername" x-mojo-element="TextField" title="Username"></div>
</div>
</div>
<div class="textfield-group" x-mojo-focus-highlight="true">
<div class="title">
<div id="txtCredential" name="txtCredential" x-mojo-element="TextField" title="Credential"></div>
</div>
</div>
<div class="palm-group" id="linkError" style="display:none" name="linkError">
<div class="palm-group-title"><span style="color:white">Error</span></div>
<div class="errorresponse">
There was no usable response from the Service before its timeout.
</div>
</div>
<div class="palm-dialog-buttons">
<div x-mojo-element="Button" id="goButton"></div>
<div x-mojo-element="Button" id="cancelButton"></div>
</div>
</div>
@@ -1,8 +0,0 @@
<div>
<table width="100%" id="emo-table">
</table>
<div id="cancel_button" class="palm-button" x-mojo-tap-highlight="momentary">
<span x-mojo-loc="">Cancel</span>
</div>
</div>
+7 -3
View File
@@ -1,6 +1,10 @@
<div class="palm-row" style="min-height: 68px;">
<div class="palm-row" x-mojo-tap-highlight='momentary'>
<div class="palm-row-wrapper">
<div id="divMsg-#{uid}" class="chat-log" style="color:#{color}"><span class="sender #{postedFrom}">#{sender}:</span> #{formattedMessage}</div>
<div class="chat-time">#{timestamp} <span class="likes">#{likes}</span></div>
<div class="task-row">
<div style="height:48px; float:left;"><img class="thumbnail" src="#{thumbnail}" style="width:48px; height: 48px; margin-right: 8px;"></div>
<div title="#{guid}"><span style="font-size:18px;">#{timestamp}</span>
<p style="margin:0px; padding: 0px;padding-bottom: 3px;">#{contenttype}</p>
</div>
</div>
</div>
</div>
+1 -1
View File
@@ -1,3 +1,3 @@
<div class="palm-list">
<div> #{-listElements}</div>
#{-listElements}
</div>
+9 -17
View File
@@ -1,25 +1,17 @@
<div class="palm-page-header multi-line">
<div class="header-icon preferences"></div>
<div id="imgTransmit" style="float:right;width:32px;height:32px;margin-top:-24px;margin-right:-12px; background: url('assets/transmit.png') no-repeat; background-size: 32px 32px;"></div>
<div class="palm-page-header">
<div class="header-icon sharespace"></div>
<div class="header-text">
<span x-mojo-loc='' style="text-transform:none;" id="spnTitle">webOS SimpleChat</span>
<span x-mojo-loc=''>Share Space</span>
</div>
</div>
<div id="showChatList" name="showChatList" style="display:block;">
<div id="showShareList" name="showShareList" style="display:none">
<div class="palm-group">
<div class="palm-group-title"><span x-mojo-loc=''>Chat Log</span></div>
<div x-mojo-element="Scroller" id="chatScroller" class="scrollerClass" name="chatScroller" style="height: 100px;padding: 0px;margin:-8px;">
<div id="chatList" x-mojo-element="List"></div>
</div>
<div class="palm-group-title"><span x-mojo-loc='' id="spnUsername">Task List</span></div>
<div id="shareList" x-mojo-element="List" style="padding: 1px;margin:-12px;"></div>
</div>
</div>
<div class="palm-group" style="min-height:64px">
<div class="palm-group-title" id="divComposeTitle"><span x-mojo-loc='' id="spanCompose">Compose</span> &nbsp;<img src="assets/twisty-down.png" id="imgTwisty"></div>
<div x-mojo-element="TextField" id="txtMessage" class="textFieldClass" name="txtMessage"></div>
<div id="divSpinnerContainer" style="width: 30px;margin-left: auto;margin-right: auto; align-items: center; margin-top:-25px;">
<div x-mojo-element="Spinner" class="spinnerClass" id="workingSpinner" name="workingSpinner"></div>
</div>
</div>
&nbsp;
<div id="divSpinnerContainer" style="margin-top: 100px; width: 130px;margin-left: auto;margin-right: auto; align-items: center;">
<div x-mojo-element="Spinner" class="spinnerClass" id="workingSpinner" name="workingSpinner"></div>
</div>
+24
View File
@@ -0,0 +1,24 @@
<div class="palm-page-header">
<div class="header-icon sharespace"></div>
<div class="header-text">
<span x-mojo-loc=''>Share Space</span>
</div>
</div>
<div class="palm-group">
<div class="palm-group-title" id="divEditTitle">New Content</div>
<div class="palm-list">
<div class="palm-row single">
<div class="palm-row-wrapper textfield-group" x-mojo-focus-highlight="true">
<div class="title">
<div class="search-bar">
<div class="textfield-search" id="txtShareContent" x-mojo-element="TextField" style="height: 300px;" title="ShareContent"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div x-mojo-element="Button" id="goButton" class="buttonClass" name="goButton"></div>
<div x-mojo-element="Button" id="cancelButton" class="buttonClass" name="cancelButton"></div>
+87
View File
@@ -0,0 +1,87 @@
<div class="palm-page-header">
<div class="header-icon sharespace"></div>
<div class="header-text">
<span x-mojo-loc=''>Share Space - New User</span>
</div>
</div>
<div class="palm-group">
<div class="palm-group-title">
<span x-mojo-loc=''>Terms and Conditions (Scroll)</span>
</div>
<div x-mojo-element="Scroller" class="scrollerClass" id="scrollTnC" name="scrollTnC" style="height:200px;margin:-15px 10px 10px -15px;padding:0px;">
<div id="divTnC">
<ul>
<li>Loading Terms and Conditions...</li>
</ul>
</div>
<div x-mojo-element="Button" id="btnAgree" name="btnAgree" style="margin-left: 20%; margin-right:14%"></div>
</div>
</div>
<div class="palm-group" id="divCredentials" style="display:none">
<div class="palm-group-title">
<span x-mojo-loc=''>Credentials</span>
</div>
<div class="palm-list">
<div class="palm-row first">
<div class="palm-row-wrapper">
<div class="title" style="float:left; margin-left: 8px; margin-top: 14px;padding:0px;"><span class="label ">Username</span></div>
</div>
</div>
<div class="palm-row">
<div class="palm-row-wrapper" style="height: 12px">
<div class="textfield-group" x-mojo-focus-highlight="true">
<div class="title">
<div id="txtUsername" name="txtUsername" x-mojo-element="TextField" title="Username"></div>
</div>
</div>
</div>
</div>
<div class="palm-row">
<div class="palm-row-wrapper" style="height: 12px">
<div class="title" class="truncating-text" style="float:left; margin-left: 8px; margin-top: 14px;padding:0px"><span class="label ">Share phrase</span></div>
<img id="imgTryagain" src="assets/tryagain.png" style="height:24px; width:24px; margin-top: 12px; margin-left: 12px;">
</div>
</div>
<div class="palm-row">
<div class="palm-row-wrapper">
<div id="divSharephrase" style="margin: 12px 14px;font-style: italic;">&nbsp;</div>
<div class="explainer" style="margin-left:10px; padding-bottom: 12px;">Anyone who knows this phrase can share with you.</div>
</div>
</div>
<div class="palm-row">
<div class="palm-row-wrapper" style="height: 12px">
<div class="title" class="truncating-text" style="float:left; margin-left: 8px; margin-top: 14px;padding:0px"><span class="label ">Admin Password</span></div>
</div>
</div>
<div class="palm-row">
<div class="palm-row-wrapper">
<div class="textfield-group" x-mojo-focus-highlight="true">
<div class="title">
<div id="txtPassword" name="txtPassword" x-mojo-element="TextField" title="Password"></div>
</div>
</div>
</div>
</div>
<div class="palm-row last">
<div class="palm-row-wrapper">
<div id="divPasswordInstructions" style="padding:6px 10px 12px 10px;line-height: 16px">
<span class="explainer">Keep this one safe, you'll use it to delete shares or configure your space.</span>
</div>
</div>
</div>
</div>
</div>
<div x-mojo-element="Button" id="btnOK" name="btnOK" style="display: none;"></div>
<div x-mojo-element="Button" id="btnCancel" name="btnCancel"></div>
+40 -38
View File
@@ -8,60 +8,45 @@
<div class="palm-group-title">
<span x-mojo-loc=''>Basic</span>
</div>
<div class="palm-list" id="divTest">
<div class="palm-list" id="listBasic">
<div class="palm-row first">
<div class="palm-row-wrapper">
<div x-mojo-element="ListSelector" title="ThemePreference" id="listThemePreference"></div>
<div id="listRefresh" x-mojo-element="ListSelector" title="RefreshTimeout" class="right"></div>
</div>
</div>
<div class="palm-row">
<div class="palm-row-wrapper">
<div id="listForegroundUpdate" x-mojo-element="ListSelector" title="ForegroundUpdate" class="right"></div>
<div x-mojo-element="ToggleButton" id="toggleAutoDownload" title="UseAutoDownload"></div>
<div class="title" style="margin-left: -4px; float:left;"><span class="label">Auto Download</span></div>
</div>
</div>
<div class="palm-row">
<div class="palm-row-wrapper">
<div id="listBackgroundUpdate" x-mojo-element="ListSelector" title="BackgroundUpdate" class="right"></div>
<div id="listAutoDownloadTime" x-mojo-element="ListSelector" title="AutoDownloadTime" class="right"></div>
</div>
</div>
<div class="palm-row">
<div class="palm-row-wrapper">
<div x-mojo-element="ToggleButton" id="toggleParsing" title="SkipParsing"></div>
<div class="title" style="margin-left: -4px; float:left;"><span class="label">Skip Parsing</span></div>
<div class="explanation-text" id="divDownloadExplain">Download features require FileMgr, which you can install from PreWare.</div>
</div>
</div>
<div class="palm-row">
<div class="palm-row-wrapper">
<div x-mojo-element="ToggleButton" id="toggleEmojis" title="ShowEmojis"></div>
<div class="title" style="margin-left: -4px; float:left;"><span class="label">Discord Emojis</span></div>
</div>
</div>
<div class="palm-row">
<div class="palm-row-wrapper">
<div x-mojo-element="ToggleButton" id="toggleThumbs" title="ShowWOSAThumbs"></div>
<div class="title" style="margin-left: -4px; float:left;"><span class="label">Share Thumbnails</span></div>
</div>
</div>
<div class="palm-row">
<div class="palm-row-wrapper">
<div id="listEnterSubmits" x-mojo-element="ListSelector" title="EnterSubmits" class="right"></div>
<div x-mojo-element="ToggleButton" id="toggleCopyLinkOnShare" title="CopyLinkOnShare"></div>
<div class="title" style="margin-left: -4px; float:left;"><span class="label">Copy Link on Share</span></div>
</div>
</div>
<div class="palm-row last">
<div class="palm-row-wrapper">
<span x-mojo-loc="" id="SoundOptionLabel" width="100%" class="label truncating-text" style="float:left; min-width:120px; margin-left: 14px; margin-top: 14px;">Alert Sound</span>
<div x-mojo-element="ListSelector" id="listAlertSound" class="listselectorClass" style="float:right" name="listAlertSound"></div>
<div x-mojo-element="ToggleButton" id="toggleForceHTTP" title="ForceHTTP"></div>
<div class="title" style="margin-left: -4px; float:left;"><span class="label">Always use HTTP</span></div>
</div>
</div>
</div>
</div>
@@ -74,32 +59,49 @@
<div class="palm-row first">
<div class="palm-row-wrapper">
<div x-mojo-element="ToggleButton" id="toggleClientAPI" title="UseClientAPIKey"></div>
<div class="title" style="margin-left: -4px; float:left;"><span class="label">Custom Client Id</span></div>
<div x-mojo-element="ToggleButton" id="toggleCustomClientId" title="UseCustomClientId"></div>
<div class="title" style="margin-left: -4px; float:left;"><span class="label">Custom Client API Key</span></div>
</div>
</div>
<div class="palm-row">
<div class="palm-row-wrapper" style="margin:14px 22px 4px 12px">
<div id="txtClientAPI" name="txtClientAPI" x-mojo-element="TextField" title="ClientAPIKey"></div>
</div>
</div>
<div class="palm-row first">
<div class="palm-row-wrapper">
<div x-mojo-element="ToggleButton" id="toggleCustomEndPoint" title="UseCustomEndpoint"></div>
<div class="title" style="margin-left: -4px; float:left;"><span class="label">Custom Endpoint URL</span></div>
<div id="txtCustomClientId" name="txtCustomClientId" x-mojo-element="TextField" title="CustomClientId"></div>
</div>
</div>
<div class="palm-row last">
<div class="palm-row-wrapper" style="margin:14px 22px 4px 12px">
<div id="txtEndpointURL" name="txtEndpointURL" x-mojo-element="TextField" title="EndpointURL"></div>
<div class="palm-row-wrapper">
<div x-mojo-element="ToggleButton" id="toggleCustomEndPoint" title="UseCustomEndpoint"></div>
<div class="title" style="margin-left: -4px; float:left;"><span class="label">Custom Endpoint</span></div>
</div>
</div>
<div x-mojo-element="Drawer" id="drawerSelfHost" class="drawerClass" name="drawerSelfHost">
<div class="palm-row">
<div class="palm-row-wrapper" style="margin:14px 22px 4px 12px">
<div id="txtEndpointURL" name="txtEndpointURL" x-mojo-element="TextField" title="EndpointURL"></div>
</div>
</div>
<div class="palm-row">
<div class="palm-row-wrapper" style="margin:14px 22px 4px 12px">
<div id="txtShortURL" name="txtShortURL" x-mojo-element="TextField" title="ShortURL"></div>
</div>
</div>
<div class="palm-row last">
<div class="palm-row-wrapper" style="margin:14px 22px 4px 12px">
<div id="txtCustomCreateKey" name="txtCustomCreateKey" x-mojo-element="TextField" title="CustomCreateKey"></div>
</div>
</div>
</div>
<div class="explanation-text">For more information on self-hosting, please visit <a href="https://github.com/webosarchive/webos-sharespace">https://github.com/webosarchivewebos-sharespace</a></div>
</div>
</div>
<div class="explanation-text">For more information on self-hosting, please visit <a href="https://github.com/codepoet80/simplechat-service">https://github.com/codepoet80/simplechat-service</a></div>
<div x-mojo-element="Button" id="btnOK" name="btnOK"></div>
-21
View File
@@ -1,21 +0,0 @@
<div class="palm-dialog-content">
<div id="hue-title" class="palm-dialog-title multi-line">
Getting Acquainted
</div>
<div class="palm-dialog-seperator" style="height: 8px;"></div>
<div class="palm-body-text">
SimpleChat is a lightweight message board for webOS. It keeps a log of recent messages, and allows you to post public messages.<br> How do you want to identify yourself?
</div>
<div class="textfield-group" x-mojo-focus-highlight="true" id="divUserInfo" style="display:block; margin-left: 15px; margin-right: 15px;">
<div class="title">
<div id="txtUserName" name="txtUserName" x-mojo-element="TextField" title="senderName"></div>
</div>
</div>
<div class="palm-dialog-seperator" style="height: 18px;"></div>
<div class="palm-dialog-buttons">
<div x-mojo-element="Button" id="goButton"></div>
</div>
</div>
+1 -1
View File
@@ -7,7 +7,7 @@
</div>
<div class="palm-header-spacer"></div>
<div id="data"></div>
<div id="data" style="margin-right: 12px"></div>
<div class="my-scene-fade-bottom" x-mojo-scroll-fade="bottom"></div>
</div>
+26
View File
@@ -0,0 +1,26 @@
<div class="palm-page-header">
<div class="header-icon sharespace"></div>
<div class="header-text">
<span x-mojo-loc=''>Share Space - Welcome</span>
</div>
</div>
<div class="welcome">
<div class="my-scene-fade-top" x-mojo-scroll-fade="top"></div>
<h3>Getting Started</h3>
<div class="welcome-text">
<p>Your Share Space has been created! Keep your credentials somewhere safe:</p>
</div>
<div id="welcome-data" class="welcome-text"></div>
<div class="welcome-text">
<p>Anyone who has your <b>Name</b> and <b>Share Phrase</b> can share content with you from their webOS device, or from the web.</p>
<p>Any time content is shared to your Share Space, a public URL will be generated that you can give to others.
This URL will contain your Share Space <b>Name</b>, but <i>not</i> your <b>Share Phrase</b>.</p>
<p>Only users with your <b>Admin Password</b> can delete content, or manage your Share Space.</p>
</div>
<div class="my-scene-fade-bottom" x-mojo-scroll-fade="bottom"></div>
</div>
+15 -14
View File
@@ -1,25 +1,26 @@
{
"id": "com.palm.app.notalexnoyle.almostsimplechat",
"version": "1.9.1",
"vendor": "NotAlexNoyle",
"id": "com.palm.webos.sharespace",
"version": "1.0.3",
"vendor": "webOS Archive",
"type": "web",
"main": "index.html",
"noWindow": true,
"title": "AlmostSimpleChat",
"appMuseumTitle": "Almost webOS SimpleChat",
"title": "Share Space",
"icon": "icon.png",
"pageTitle": "Almost webOS SimpleChat",
"startupMessage": "<img src='icon.png' style='float:left; margin-right:8px'>Welcome to SimpleChat! We're so excited you're here chatting with us more than 10 years after this platform was supposed to have died!<br>You can also join this chat from Discord: <a href='http://www.webosarchive.org/discord'>webosarchive.org/discord</a> or view the log on the web: <a href='http://chat.webosarchive.org'>chat.webosarchive.org</a>",
"serviceURL": "http://chat.webosarchive.org/",
"splashicon": "icon-256x256.png",
"miniicon": "assets/notify.png",
"noWindow": true,
"splashicon": "icon-256.png",
"uiRevision": "2",
"universalSearch" : {
"serviceURL": "https://share.webosarchive.org/",
"shortURL": "https://wosa.link/",
"tapToShareSupported": true,
"universalSearch": {
"action": {
"displayName": "New Share",
"url": "com.palm.app.notalexnoyle.almostsimplechat",
"url": "com.palm.webos.sharespace",
"launchParam": {
"newshare": "#{searchTerms}"
}
}
}
}
},
"startupMessage": "<img src='icon.png' style='float:right; margin-left: 6px'>Welcome to ShareSpace -- a powerful app for getting content on and off your webOS device! You can interact with this app from anywhere at <a href='http://share.webosarchive.org'>share.webosarchive.org</a>!<br>Here are some things you can do..."
}
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

-5225
View File
File diff suppressed because it is too large. Load diff
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

-98
View File
@@ -1,98 +0,0 @@
/* TODO: put your application-specific CSS here */
.palm-page-header .header-icon.preferences {
background: url(../icon.png) no-repeat;
background-size: 32px 32px;
}
.palm-dark .header-text {
color:lightgray !important;
}
.explanation-text {
margin-top: -5px;
padding: 14px;
font-size: 14px;
color: #000;
}
.palm-dark .explanation-text {
color: lightgray;
}
.chat-log {
margin-top: 8px;
}
.palm-dark .chat-log {
color:lightgray !important;
}
.sender {
font-weight: bold;
}
.sender.discord {
color: #6473b9;
}
.sender.discord::before {
content: url('../assets/discord.png');
}
.chat-time {
margin-top: 6px;
font-size: 12px;
font-style: italic;
color: dimgray;
padding-bottom: 14px;
}
.palm-dark .chat-time {
color: white;
}
.textFieldClass {
min-height:56px;
background-color:white;
border: 1px solid dimgray;
}
.palm-dark .textFieldClass {
min-height:56px;
background-color:lightgray;
border: 1px solid dimgray;
}
.textFieldClass input {
padding: 1px;
}
.dashboard-icon-chat {
background: url(../icon-48.png);
}
textarea {
margin-top: 0px !important;
}
.palm-dark .palm-dialog-content .palm-body-text {
color: black !important;
}
.multiline-hint-text.oblique {
color: darkgray;
}
.likes:not(:empty) {
background: url('../assets/heart.png');
background-size: 12px 12px;
background-repeat: no-repeat;
background-position: 8px;
background-position-x: 0;
padding-left: 14px;
}
#emo-table td {
text-align: center;
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

+1 -1
View File
@@ -1,5 +1,5 @@
{
"logLevel": 10,
"logLevel": 0,
"debuggingEnabled": false,
"timingEnabled": false,
"logEvents": false,
Executable
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

+3 -8
View File
@@ -3,23 +3,18 @@
<head>
<meta name='viewport' content='height=device-height'>
<title>Simple Chat</title>
<title>Share Space</title>
<script src="/usr/palm/frameworks/mojo/mojo.js" type="text/javascript" x-mojo-version="1"></script>
<!-- load my additions -->
<script src="app/com.wosa.mojo.additions.js" type="text/javascript"></script>
<!-- application stylesheet should come in after the one loaded by the framework -->
<link href="assets/simplechat.css" media="screen" rel="stylesheet" type="text/css">
<link href="assets/emoji.css" rel="stylesheet" type="text/css" />
<link href="stylesheets/sharespace.css" media="screen" rel="stylesheet" type="text/css">
</head>
<body>
<!--
<audio id="audioPlayer">
<source src="/media/internal/ringtones/Subtle (short).mp3" type="audio/mp3">
</audio>
-->
</body>
</html>
+4
View File
@@ -0,0 +1,4 @@
var appKeys = {
'shareBoardClientKey': 'base64 encode the client key from the server',
'shareBoardCreateKey': 'base64 encode the create key from the server (if needed)'
};
-3
View File
@@ -1,3 +0,0 @@
var secrets = {
'clientid': 'SecretSharedWithServer'
};
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+27 -9
View File
@@ -6,24 +6,42 @@
"source": "app/assistants/main-assistant.js"
},
{
"scenes": "preferences",
"source": "app/assistants/preferences-assistant.js"
"source": "app/assistants/login-assistant.js",
"comment": "since this will be a dialog, not a scene, we do not include the 'scenes' member (or we get errors)"
},
{
"source": "app/assistants/user-assistant.js",
"comment": "since this will be a dialog, not a scene, we do not include the 'scenes' member (or we get errors)"
"scene": "newuser",
"source": "app/assistants/newuser-assistant.js"
},
{
"scene": "welcome",
"source": "app/assistants/welcome-assistant.js"
},
{
"scene": "detail",
"source": "app/assistants/detail-assistant.js"
},
{
"scene": "newshare",
"source": "app/assistants/newshare-assistant.js"
},
{
"scenes": "preferences",
"source": "app/assistants/preferences-assistant.js"
},
{
"scenes": "version",
"source": "app/assistants/version-assistant.js"
},
{
"source": "app/assistants/emoticonpicker-dialog-assistant.js"
{
"scenes": "download",
"source": "app/assistants/download-assistant.js",
"comment": "this is a dashboard"
},
{ "scenes": "dashboard", "source": "app/assistants/dashboard-assistant.js" },
{ "source": "app/models/service-model.js" },
{ "source": "app/models/system-model.js" },
{ "source": "app/models/shareservice-model.js" },
{ "source": "app/models/updater-model.js" },
{ "source": "app/models/app-model.js" },
{ "source": "app/models/system-model.js" },
{ "source": "secrets.js" }
]
+89
View File
@@ -0,0 +1,89 @@
/* TODO: put your application-specific CSS here */
.palm-page-header .header-icon.sharespace {
background: url(../icon.png) no-repeat;
background-size: 32px 32px;
}
.task-title.new {
color: dimgray;
font-style: italic;
}
.task-row {
padding: 8px 0px 8px 8px;
}
.checkmark {
float: right;
visibility: visible;
opacity: 0.1;
margin-top: 3px;
width: 30px;
}
.checkmark.true {
opacity: 1;
visibility: visible;
}
.explanation-text {
margin-top: -5px;
padding: 14px;
font-size: 14px;
color: #000;
}
.palm-group-title.detail {
color: #000;
margin-left: -4px;
}
.palm-row-wrapper.detail {
padding: 3px;
}
.explainer {
font-style: italic;font-size: smaller; color:dimgray;
}
#welcome-data {
margin-left: 8px;
padding-left: 3px;
margin-right: 8px;
padding-right: 3px;
border-top: 1px solid lightgray;
border-right: 1px solid lightgray;
border-bottom: 1px solid lightgray;
border-left: 1px solid lightgray;
background-color: #efefef;
}
.welcome-text {
margin: 8px 12px 12px 12px
}
.welcome-text p {
padding: 0px; margin: 4px 0px;
}
.welcome-text b {
color: #1f75bf; font-variant: small-caps;
}
.welcome-text em {
font-weight: bold;
}
h3 {
margin: 8px 12px 12px 12px
}
.dashboard-icon-download {
background: url(../assets/dash-icon.png);
}
.palm-dashboard-text {
font-size: 14px;
margin-top: -2px;
}
-160
View File
@@ -1,160 +0,0 @@
function VersionAssistant(startup) {
this.isStartup = startup;
// on first start, this message is displayed, along with the current version message from below
this.startupMessage = Mojo.Controller.appInfo.startupMessage;
//New Features
this.changelog = [
{
version: "Version 1.8.0",
detail: [
"Dark theme now available in Preferences!",
]
},
{
version: "Version 1.7.1",
detail: [
"Fix a bug where hardware mute switch wasn't respected. Show transmit indicator. Add ability to disable link and image parsing to speed things up on tiny devices.",
]
},{
version: "Version 1.7.0",
detail: [
"Images from listThemePreference are now supported! Inline rendering uses a thumbnail for efficiency; tap the image to load the fullsize, or tap elsewhere on the row to pull up the menu that lets you download the image to your device (it will be saved to /internal/downloads)",
]
},{
version: "Version 1.6.0",
detail: [
"Added ability to parse Imgur album links and render via a service proxy.",
]
},{
version: "Version 1.5.0",
detail: [
"Added ability to parse Share Services links and show thumbnails, configurable in Preferences.",
]
},{
version: "Version 1.4.1",
detail: [
"Add support for some basic markdown",
]
},
{
version: "Version 1.4.0",
detail: [
"Enter key behavior as a Preference",
"Even more silent background sync, won't sync if offline",
"Swiping notifications resets missed message count",
"Adjust tap target for collapsing controls"
]
},
{
version: "Version 1.3.2",
detail: [
"More sync timing options.",
"Refactored some code to make forking easier."
]
}, {
version: "Version 1.3.1",
detail: [
"Enter key now sends message when Command menu buttons are hidden."
]
},
{
version: "Version 1.3.0",
detail: [
"Drastically improved background update and notifications."
]
}, {
version: "Version 1.2.0",
detail: [
"Converts image links to an image proxy so they can be viewed and scaled properly on tiny devices",
"Improved background update, using a notification launch, no longer interupts Exhibition, video playback or One Night Stand"
]
},
{
version: "Version 1.1.3",
detail: [
"Bug fixes and general maintenance"
]
}, {
version: "Version 1.1.2",
detail: [
"Show/Hide the Command menu buttons by tapping the Compose area title bar",
"Enable/Disable listThemePreference Emojis in Preferences",
]
}, {
version: "Version 1.1.1",
detail: [
"Improved listThemePreference integration, including showing Emojis!<span class='emoji-outer emoji-sizer'><span class='emoji-inner emoji1f388'></span></span>",
"Now with a smaller emoji file!",
"Improved timeout logic.",
"Trying different background sync logic."
]
}
];
// setup command menu
this.cmdMenuModel = {
visible: false,
items: [
{},
{
label: $L("OK! Let's Go..."),
command: 'do-continue'
},
{}
]
};
};
VersionAssistant.prototype.setup = function() {
this.titleElement = this.controller.get('title');
this.dataElement = this.controller.get('data');
this.titleElement.innerHTML = $L('Version Info');
var html = '';
html += '<div style="margin: 2px 12px 12px 12px">' + this.startupMessage + '</div>';
for (var i = 0; i < this.changelog.length; i++) {
html += Mojo.View.render({ object: { title: this.changelog[i].version }, template: 'version/rowDivider' });
html += '<ul>';
for (var j = 0; j < this.changelog[i].detail.length; j++) {
html += '<li>' + this.changelog[i].detail[j] + '</li>';
}
html += '</ul>';
}
// set data
this.dataElement.innerHTML = html;
// setup menu
this.controller.setupWidget(Mojo.Menu.appMenu, { omitDefaultItems: true }, { visible: false });
//if (this.isStartup) {
// set command menu
this.controller.setupWidget(Mojo.Menu.commandMenu, { menuClass: 'no-fade' }, this.cmdMenuModel);
//}
};
VersionAssistant.prototype.activate = function(event) {
this.timer = this.controller.window.setTimeout(this.showContinue.bind(this), 2 * 1000);
};
VersionAssistant.prototype.deactivate = function(event) {};
VersionAssistant.prototype.cleanup = function(event) {};
VersionAssistant.prototype.showContinue = function() {
// show the command menu
this.controller.setMenuVisible(Mojo.Menu.commandMenu, true);
};
VersionAssistant.prototype.handleCommand = function(event) {
if (event.type == Mojo.Event.command) {
switch (event.command) {
case 'do-continue':
this.controller.stageController.popScene();
break;
}
}
};