Доступ к базам данных – очень востребованный функционал приложений. И в этот раз мы рассмотрим способ для WebOS приложений получить данные из базы данных MySQL, находящейся на удаленном сервере.

Для начала создадим новое приложение и в нем новую сцену с названием Main. Как создать проект и сцену можно узнать из этой статьи.

Затем добавим в созданную сцену список:

views/main/main-scene.html

<div class="palm-group">
  <div class="palm-group-title" id="sample-toggle">
  	<span x-mojo-loc="">Database Content</span></div>
    <div class="palm-list">
       <div id="dbList" x-mojo-element='List'></div>
    </div>
  </div>
</div>

Для нашего списка нам необходимо определить HTML-шаблон элементов списка:
views/main/dbItemTemplate.html

<div class="palm-row" x-mojo-tap-highlight="momentary">
  <div id="nameField">#{Name} (#{Year})</div>
</div>

В шаблоне указано, что если в элементе списка есть свойства Name и Year, то они должны быть отображены.

Теперь в assistants/main-assistant.js внесем необходимые изменения для того, чтобы виджет-список создался при запуске:

function MainAssistant() {
}

MainAssistant.prototype.setup = function() {
this.count = 0;
this.dbListModel = {};
this.controller.setupWidget("dbList",
        {
            itemTemplate: "main/dbItemTemplate"
        },
        this.dbListModel);
}

Как видно из кода, в атрибутах виджета мы указываем шаблон элементов main/dbItemTemplate. Название должно совпадать с названием ранее созданного HTML-файла с описанием шаблона элементов.

После всех манипуляций, описанных выше, у нас должно получиться что-то подобное:

WebOS Empty List

Отлично, с GUI мы закончили, теперь займемся получением данных с сервера.

Для начала создадим базу данных и в ней таблицу, из которой мы будем получать записи и отображать их на форме:

CREATE TABLE remote_data(
 ID INTEGER NOT NULL AUTO_INCREMENT ,
 Name VARCHAR( 32 ) NOT NULL ,
 Year SMALLINT NOT NULL ,
 PRIMARY KEY ( ID )
);

Затем создадим PHP-скрипт, который будет получать данные из таблицы и выдавать их в формате JSON:

<?php
header('Content-type: application/json');
$dbhost = "localhost";
$dbuser = "root";
$dbpass = "";
$dbname = "webos_test";
$link = mysql_connect($dbhost, $dbuser, $dbpass)
    or die('Could not connect: ' . mysql_error());
mysql_select_db($dbname) or die('Could not select database');

switch($_POST['operation'])
{
 case 'getResults':
 {
  $table = $_POST['table'];
  $query = sprintf("SELECT * FROM %s", mysql_real_escape_string($table));
  $result = mysql_query($query) or die('Query failed: ' . mysql_error());
  $all_recs = array();
  while ($line = mysql_fetch_array($result, MYSQL_ASSOC))
  {
   $all_recs[] = $line;
  }
  break;
 }
}
echo json_encode($all_recs);
mysql_free_result($result);
mysql_close($link);
?>

Что делает этот скрипт:

  • Получает из POST-параметров название операции, непример getResults.
  • Если операция поддерживается, то получает из POST-параметров имя таблицы
  • Получает записи из таблицы в массив
  • Конвертирует в JSON и отдает клиенту

В результате у нас в выдаче должно получиться что-то подобное:

[
 {"ID":"1","Name":"Test 1","Year":"2008"},
 {"ID":"2","Name":"Test 2","Year":"2009"},
 {"ID":"3","Name":"Test 3","Year":"2010"}
]

Теперь нам надо научить наше WebOS приложение получать эти данные с сервера.

Для получения данных в приложении нам необходимо выполнить AJAX-запрос на сервер. Для этого используется метода Ajax.Request():

MainAssistant.prototype.getRemoteData = function(table) {
    var url = 'http://192.168.0.1/remote-data.php';
    try
    {
        if(!table)
        {
            throw('getRemoteData(): You should specify database table name');
        }
        var request = new Ajax.Request(url,
        	{
            	method: 'post',
            	parameters: {'operation': 'getResults', 'table': table},
            	evalJSON: 'true',
            	onSuccess: this.getRemoteDataSuccess.bind(this),
            	onFailure: function()
            	{
                	Mojo.Log.error('Failed to get Ajax response');
            	}
        	});
    }
    catch(e)
    {
        Mojo.log.error(e);
    }
}

В исходном коде указан IP адрес машины в локальной сети. Если вы тестируете приложение на эмуляторе, а сервер со скриптом и базой данных находится в Internet, то, скорее всего, доступа к серверу у вас по умолчанию не будет. Для того, чтобы разрешить эмулятору ходить в сеть, надо в настройках LAN-соединения разрешить доступ из подсети VirtualBox:
Share Internet with WebOS Emulator

Итак, в приведенном выше коде указано, что при успешном завершении запроса необходимо вызвать метод getRemoteDataSuccess(). В этом методе мы должны преобразовать полученный ответ от сервера в массив и обновить список. Делается это следующим образом:

MainAssistant.prototype.getRemoteDataSuccess = function(response) {

 	try
 	{
 		this.dbListModel.items = response.responseText.evalJSON();
 		this.controller.modelChanged(this.dbListModel);
 	}
 	catch(e)
 	{
 		Mojo.log.error(e);
 	}
}

Для преобразования JSON-строки в массив мы использовали метод evalJSON(), а для того чтобы виджет обновил список элементов мы вызвали метод modelChanged() объекта-контроллера.

Все это чудесно, научили приложение делать запрос к серверу и обрабатывать результаты, но если мы запустим приложение, то ничего не произойдет. А все потому что мы не указали, когда должен вызываться метод getRemoteData().

Вызвать этот метод можно при запуске приложения. У класса сцены есть метод, который отрабатывает, когда сцена загружена. Это метод ready(). Вот в нем мы и запустим выполнение AJAX-запроса:

MainAssistant.prototype.ready = function() {
this.getRemoteData('remote_data');
}

И вот, после запуска увидим такое:

WebOS List Loaded from MySQL Database

На этом все.

Скачать исходный код демонстрационного приложения.

Previous ArticleNext Article
Технический директор IT-Dimension, компании-разработчика кросс-платформенного программного обеспечения

Leave a Reply

Your email address will not be published. Required fields are marked *

Л.

Локализация приложений для Palm WebOS

Чем больше поддерживаемых языков в вашем приложении, тем больше целевая аудитория. Не каждый у нас знает английский, точно так же обстоят дела и во многих других странах, поэтому наличие локализированной версии будет выгодно отличать ваше приложение от приложений конкурентов.

В Palm WebOS локализация происходит достаточно прозрачно. Никаких сверхъестественных знаний не требуется.

Локализируем имя приложения, отображаемое в Launcher

Для того, чтобы в Launcher’е ваше приложение меняло название при смене системных настроек локализации, необходимо скопировать файл appinfo.json в папку с локализированными ресурсами.

Путь для размещения локализированных ресурсов формируется таким образом:

  • В каталоге с проектом создается папка resources
  • В папке resources для каждого языка создается отдельная папка и в ней необходимо размещать файлы локализации, соблюдая структуру каталогов.

Например мы создали приложение следующим образом:

palm-generate -p "id=com.mobiledeveloper.localizableapp" -p "title=Localizable Application" LocalizableApplication
palm-generate -t new_scene -p "name=Main" LocalizaleApplication

Получаем appinfo.json такого вида:

{
 "id": "com.mobiledeveloper.localizableapplication",
 "version": "1.0.0",
 "vendor": "Mobile-Developer.ru",
 "type": "web",
 "main": "index.html",
 "title": "LocalizableApplication",
 "icon": "icon.png"
}

Теперь нам необходимо сделать локализацию. Для этого файл appinfo.json мы копируем в /resources/es_us/appinfo.json и текст файла заменяем на следующий:

{
 "id": "com.mobiledeveloper.localizableapplication",
 "version": "1.0.0",
 "vendor": "Mobile-Developer.ru",
 "type": "web",
 "main": "../../index.html",
 "title": "Translated Application",
 "icon": "../../icon.png"
}

В результате, при смене языка на испанский, получим такое в Launcher’е:
WebOS Localized Application in Launcher

Локализируем HTML-текст сцен

Для того чтобы создать локализированную версию HTML-файла сцены, его также необходимо скопировать в папку с локализированными ресурсами, соблюдая структуру каталогов.

Допустим, у нас был файл /views/main/main-scene.html

<div class="row" style="padding-left: 5px;">
    My<br />text <b>here</b>!
</div>

Для создания испанской локализации нам надо скопировать его в /resources/es_us/views/main/main-scene.html и заменить текст:

<div class="row" style="padding-left: 5px;">
    Your<br />image <b>there</b>!
</div>

После смены языковых настроек в системе, мы увидим измененный текст.

Локализация строк в JavaScript

Все строки, для которых необходима локализация, должны быть помещены в функцию $L():

$L("My text here");

Если по каким-то причинам вы не можете использовать исходную строку в качестве ключа, то значение ключа в словаре с переводом можно указать вручную.

$L("value":"Done", "key": "done_key");

Файл со словарем должен находиться непосредственно в каталоге с локализированніми ресурсами и называться strings.json

{
"My text here": "Mi texto aquí",
"done_key": "Listo",
}

Файл со словарем должен иметь кодировку UTF-8 (без BOM). Если работаете в Eclipse, то, если не указать кодировку для файла и попытаться ввести неанглийские символы и сохранить файл, должно появиться сообщение об ошибке.

Если в строку необходимо подставлять значения переменных, то не надо делать конкатенацию строк, лучше переменные указать в тексте. Это делается потому что для каждого языка положение этих переменных в тексте и последовательность следования переменных может отличаться.

Например английская версия строки может выглядеть так:

"Not enough memory to #{action} the file #{fname}."

…а финская так:

"Liian vähän muistia tiedoston #{fname} #{action}."

Чтобы правильно сделать локализацию подобных строк, нужно использовать метод interpolate():

var data={num:10};
var localizedText = $L("You have #{num} messages").interpolate(data);

или класс Template

var template = new Template($L("You have #{num} messages"));
var localizedText = template.evaluate({num: 10});

Скачать исходный код к статье.

В.

ВИДЕО: Вебкаст о разработке для Palm webOS

Palm webOS WebCast

Вот.. выложили видео вебкаста о программированиии для Palm webOS. Как я уже говорил, там были проблемы с видео, поэтому первые 1:35 идут без звука. Там, в принципе, только обзор был, поэтому ничего страшного.