Posts mit dem Label Javascript werden angezeigt. Alle Posts anzeigen
Posts mit dem Label Javascript werden angezeigt. Alle Posts anzeigen

Mittwoch, 1. Februar 2012

webOS: Detecting Enyo on phones

With the trojan horse maps update for all webOS devices, every device has the option of running Enyo applications. Which is great, but how can you determine whether the user has updated his phone or not?

Arthur Thornton posted a very nice solution in the webOS developer forums.

In the likely situation that no update to older devices is pushed out including enyo, here is a solution...it isn't pretty, but it will get the job done.

The very first thing you need to do is mention in your app description that your app requires "updated system software" included in the Maps app. This way, the users should know to expect this as a requirement, and even though many users don't read the description (grr...) you're still covered by mentioning this.

Then use the following code in your app:

index.html
Code:
<!doctype html>
<html>
  <head>
    <title></title>
    <meta name="viewport" content="height=device-height" />
    <script src="C:\Program Files (x86)\HP webOS\SDK\share\framework\enyo\1.0\framework\enyo.js" type="text/javascript"></script>
  </head>
  <body>
    <script type="text/javascript">
      if (typeof enyo == "undefined")
        window.location = "./requiresEnyo.html";
      else
        new MyApp().renderInto(document.body);
    </script>
  </body>
</html>

requiresEnyo.html
Code:
<!doctype html>
<html>
  <head>
    <title>Install Maps and Enyo</title>
    <meta name="viewport" content="height=device-height" />
    <script src="/usr/palm/frameworks/mojo/mojo.js" type="text/javascript" x-mojo-version="1" />
  </head>
  <body>
    <div style="padding: 5px">
      Attention: This application requires an updated version of the system software which is not available on your phone. To install this updated software, you must install the updated Maps app by tapping the below button (will open the App Catalog):
    </div>
    <div class="palm-button" onclick="installEnyo()">Install</div>
    <script>
      window.onload = function() {
        PalmSystem.stageReady(); // required for page to load
      };
      function installEnyo() {
        window.location = "http://developer.palm.com/appredirect/?packageid=com.palm.app.maps";
      }
    </script>
  </body>
</html>

Note that this loads Mojo (which will obviously be on the device) in a separate HTML file *if* enyo isn't already on the device (i.e. a Pre2). This was tested to work on my Pre2.

Also note that to put enyo in your app, your users must be using webOS 1.4.5 or newer because the maps app has a minimum webOS version of 1.4.5 (and thus, users prior to 1.4.5 won't see it in the Catalog and won't be able to update) due to (I'm assuming) using the version 2.0 packaging format.

If you have your app currently deployed to users running webOS versions prior to 1.4.5, you will have to retain a Mojo version in it (because the app can still be updated even if you change minimum OS version to 1.4.5 unless changes have recently gone into effect to fix that; this doesn't cause issues for the Maps app because technically, that app is not update-capable on devices prior to the Pre3 without the workaround they came up with).

Arthur Thornton
webOS Application Engineer
Appstuh

Dienstag, 31. Januar 2012

webOS: Kind inheritance tree for Enyo 1.0

With Enyo 2.0 available this information might not be as useful as it was before. Here you can find a PDF document with a tree inheritance model of all Enyo kinds. I always like a visual representation and you can find a new kind you haven't used before.

Montag, 30. Januar 2012

webOS: Implementing promises with Enyo components

I recently needed to make a few web service calls from within my Enyo application. I wanted to use the cujojs.com when.js library for synchronization with promises. Promises in itself are a very intriguing concept and I will write another blog post about them in the future.

In essence a promise works this way:

webservice.login(username, password).then(
  function loginSuccess(response) {
    enyo.log("Login successful");
  }, function loginFailed(response) {
    enyo.log("Login failed.");
  }); 

The login function of the web service sends out an request asynchronously and returns immediately. The usual way to handle this kind of behavior is to pass a set of callback functions to the login method, that are called when the service is successful or had failed. Promises allow for more compact code. See this article for a good explanation.

To make a web service call in Enyo you normally use an enyo.WebService component like this:

enyo.kind({
  name : "LoginComponent",
  kind : enyo.Component,
  components : [ {
    kind : "WebService",
    name : "loginWebService",
    url : "https://<your service URL here>",
    method : "post",
    onSuccess : "loginSuccess",
    onFailure : "loginFailure"
  } ],

  loginSuccess : function(inSender, inResponse, inRequest) {
    enyo.log("Login successful.");
  },

  loginFailure : function(inSender, inResponse, inRequest) {
    enyo.log("Login failed.");
  }
});

The WebService kind has to event methods onSuccess and onFailure. But in the definition of the kind, those two events take only strings. When the doSuccess or doFailure methods are called the intelligence of the enyo.Object handle the translation from the string to the actual method call.

To implement the promise concept with the WebService kind, we have to create our own kind.

enyo.kind({
  name : "LoginWebservice",
  kind : enyo.Component,
  
  deferred : undefined,
  
  components : [ {
    kind : "WebService",
    name : "loginWebService",
    url : "https://<your service URL here>",
    method : "post",
    onSuccess : "loginSuccess",
    onFailure : "loginFailure"
  } ],

  login : function(inUsername, inPassword) {
    this.deferred = when.defer();
    var params = {
      Username : inUsername,
      Password : inPassword
    };
    this.$.loginWebService.call(params);
    return this.deferred.promise;
  },

  loginSuccess : function(inSender, inResponse, inRequest) {
    this.deferred.resolve(inResponse);
  },

  loginFailure : function(inSender, inResponse, inRequest) {
    this.deferred.reject(inResponse);
  }
});

The component creates a deferred object and resolves/rejects it based upon the result of the web service call. Use the following code to integrate the kind in your own software:

enyo.kind({
  name : "LoginWebServiceTest",
  kind : "Component",
  components : [ {
    kind : "LoginWebservice",
    name: "wsLogin"
  }, {
    kind : "Button", 
    onclick: "loginTest"
  } ],

  loginTest : function(inSender) {
    this.$.wsLogin.login("Username", "MySecretPassword").then(
      function loginSuccess(response) {
        enyo.log("Login successful");
      }, function loginFailed(response) {
        enyo.log("Login failed.");
      }
    ); 
  }
});

x

Montag, 23. Januar 2012

webOS: Login dialog with Enyo

The Enyo framework is very modular and thus allows components to be reused very easy. Here we have a simple modal dialog that can be used to let the user enter a login name and a password.

The dialog will look like this:


Just create a file LoginDialog.js and add it to your enyo.depends() call.

enyo.kind({
  kind : "ModalDialog",
  name : "FFComputing.LoginDialog",
  caption : "Login",
  events: {
    onOK: "",
    onCancel: ""
  },
  components : [ {
    kind : "Group",
    name : "LoginCaption",
    caption : "Login",
    components : [ {
      kind : "Input",
      name : "loginInput",
      hint : "Login...",
      autoWordComplete : false,
      spellCheck : false,
      autocorrect : false
    } ]
  }, {
    kind : "Group",
    name : "PasswordCaption",
    caption : "Password",
    components : [ {
      kind : "PasswordInput",
      name : "passwordInput",
      hint : "Password...",
      spellCheck : false,
      autocorrect : false
    } ]
  }, {
    layoutKind : "HFlexLayout",
    components : [ {
      kind : "Button",
      flex : 1,
      caption : "OK",
      onclick : "okClicked",
      className : "enyo-button-blue"
    }, {
      kind : "Button",
      flex : 1,
      caption : "Cancel",
      onclick : "cancelClicked"
    }]
  }, ],
 
  okClicked: function(sender) {
    this.close();
    this.doOK(this.$.loginInput.getValue(), this.$.passwordInput.getValue());
  },
 
  cancelClicked: function(sender) {
    this.close();
    this.doCancel();
  }
});