From 6a6bdf293b772dda5581d75b3b934033a05fa237 Mon Sep 17 00:00:00 2001
From: Piotr Kosko
Date: Tue, 27 Oct 2015 11:05:17 +0100
Subject: [PATCH] [Cordova][Globalization] Added C++ layer for missing
functionalities.
[Verification] All globalization tests pass
Change-Id: Iaeade03161404f6e8510dd100b792c136d96bfa4
Signed-off-by: Piotr Kosko
---
src/globalization/cordova_globalization.gyp | 6 +
src/globalization/cordova_globalization_api.js | 312 +++++++++-----
.../cordova_globalization_extension.cc | 18 +-
.../cordova_globalization_extension.h | 10 +-
.../cordova_globalization_instance.cc | 467 +++++++++++++++++++++
src/globalization/cordova_globalization_instance.h | 47 +++
src/globalization/cordova_globalization_tools.cc | 394 +++++++++++++++++
src/globalization/cordova_globalization_tools.h | 87 ++++
8 files changed, 1219 insertions(+), 122 deletions(-)
create mode 100644 src/globalization/cordova_globalization_instance.cc
create mode 100644 src/globalization/cordova_globalization_instance.h
create mode 100644 src/globalization/cordova_globalization_tools.cc
create mode 100644 src/globalization/cordova_globalization_tools.h
diff --git a/src/globalization/cordova_globalization.gyp b/src/globalization/cordova_globalization.gyp
index 9c44927..82599f6 100644
--- a/src/globalization/cordova_globalization.gyp
+++ b/src/globalization/cordova_globalization.gyp
@@ -10,6 +10,10 @@
'cordova_globalization_api.js',
'cordova_globalization_extension.cc',
'cordova_globalization_extension.h',
+ 'cordova_globalization_instance.cc',
+ 'cordova_globalization_instance.h',
+ 'cordova_globalization_tools.cc',
+ 'cordova_globalization_tools.h',
],
'include_dirs': [
'../',
@@ -18,6 +22,8 @@
'variables': {
'packages': [
'webapi-plugins',
+ 'icu-i18n',
+ 'vconf'
],
},
},
diff --git a/src/globalization/cordova_globalization_api.js b/src/globalization/cordova_globalization_api.js
index e857ba9..d15fee5 100755
--- a/src/globalization/cordova_globalization_api.js
+++ b/src/globalization/cordova_globalization_api.js
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+var utils_ = xwalk.utils;
+var native_ = new utils_.NativeManager(extension);
+
var _navigator = navigator || {};
var _global = window || global || {};
@@ -47,6 +50,15 @@ var formatMediumStr = 'medium';
var formatLongStr = 'long';
var formatFullStr = 'full';
+var typeWide = 'wide';
+var typeNarrow = 'narrow';
+var itemMonths = 'months';
+var itemDays = 'days';
+
+var numberTypeDecimal = 'decimal';
+var numberTypePercent = 'percent';
+var numberTypeCurrency = 'currency';
+
var oneHourSeconds = 60*60;
var Globalization = {};
@@ -64,7 +76,7 @@ Globalization.getPreferredLanguage = function(successCb, errorCb) {
function(error) {
console.log('Cordova, getLocaleName, An error occurred ' + error.message);
errorCb(new GlobalizationError(GlobalizationError.UNKNOWN_ERROR ,
- 'cannot retrieve language name'));
+ 'cannot retrieve language name'));
}
);
}
@@ -73,125 +85,143 @@ Globalization.getLocaleName = function(successCb, errorCb) {
Globalization.getPreferredLanguage(successCb, errorCb);
}
-//TODO dateToString would support only full length (one format is supprted),
+//TODO JS implementation of dateToString would support only full length (one format is supprted),
// but selector for getting only needed values is fully supported
Globalization.dateToString = function(date, successCb, errorCb, options) {
// TODO add validation of parameters
var result = null;
var formatLength = formatFullStr;
var selector = selectorDateAndTimeStr;
- console.log("options " + JSON.stringify(options));
if (options) {
formatLength = options.formatLength || formatFullStr;
selector = options.selector || selectorDateAndTimeStr;
}
- console.log("len: " + formatLength + " selector: " + selector);
- var tzdate = new tizen.TZDate(date);
- if (tzdate) {
- // TODO only one format length is supprted
- // "Wednesday, January 7, 2015, 12:33:15 PM"
- if (selectorDateStr === selector) {
- result = tzdate.toLocaleDateString();
- } else if (selectorTimeStr === selector) {
- result = tzdate.toLocaleTimeString();
+ var timestamp = date.getTime();
+ var callback = function(result) {
+ if (native_.isFailure(result)) {
+ var error = new GlobalizationError(
+ GlobalizationError.FORMATTING_ERROR , native_.getErrorObject(result).message);
+ native_.callIfPossible(errorCb, error);
} else {
- result = tzdate.toLocaleString();
+ successCb(native_.getResultObject(result));
}
- }
-
- if (result) {
- setTimeout( function() {
- successCb ({'value': result});
- }, 0);
- } else {
- setTimeout( function() {
- errorCb(new GlobalizationError(
- GlobalizationError.FORMATTING_ERROR , 'cannot format date string'));
- }, 0);
- }
+ };
+ var callArgs = {
+ formatLength: String(formatLength),
+ selector: String(selector),
+ timestamp: String(timestamp)
+ };
+ native_.call('CordovaGlobalization_dateToString', callArgs, callback);
}
//TODO implementation would try to convert string to Date using javascript Date object
// constructor, options are basically ignored
Globalization.stringToDate = function(dateString, successCb, errorCb, options) {
// TODO add validation of parameters
- var d = new Date(dateString);
- if (!d.getTime()) {
- setTimeout( function() {
- errorCb(new GlobalizationError(
- GlobalizationError.PARSING_ERROR , 'cannot parse date from string'));
- }, 0);
- } else {
- var result = {
- year : d.getYear() + 1900,
- month : d.getMonth(),
- day : d.getDate(),
- hour : d.getHours(),
- minute : d.getMinutes(),
- second : d.getSeconds(),
- millisecond : d.getMilliseconds()
- };
- setTimeout( function() {
- successCb (result);
- }, 0);
+ var result = null;
+ var formatLength = formatFullStr;
+ var selector = selectorDateAndTimeStr;
+ if (options) {
+ formatLength = options.formatLength || formatFullStr;
+ selector = options.selector || selectorDateAndTimeStr;
}
+
+ var callback = function(result) {
+ if (native_.isFailure(result)) {
+ var error = new GlobalizationError(
+ GlobalizationError.PARSING_ERROR , native_.getErrorObject(result).message);
+ native_.callIfPossible(errorCb, error);
+ } else {
+ successCb(native_.getResultObject(result));
+ }
+ };
+ var callArgs = {
+ formatLength: String(formatLength),
+ selector: String(selector),
+ dateString : String(dateString)
+ };
+ native_.call('CordovaGlobalization_stringToDate', callArgs, callback);
}
-// TODO getDatePattern would support only short and full length,
-// but selector for getting only needed values is fully supported
Globalization.getDatePattern = function(successCb, errorCb, options) {
// TODO add validation of parameters
+ var formatLength = formatFullStr;
var selector = selectorDateAndTimeStr;
- var isShortFormat = false;
+
if (options) {
+ formatLength = options.formatLength || formatFullStr;
selector = options.selector || selectorDateAndTimeStr;
- isShortFormat = (options.formatLength === formatShortStr);
- }
- var pattern = null;
- if (selectorTimeStr === selector) {
- pattern = tizen.time.getTimeFormat();
- } else if (selectorDateStr === selector) {
- pattern = tizen.time.getDateFormat(isShortFormat);
- } else {
- // TODO in tizen there is no unified date and time format getter
- // (for now implementation separates date and time formats with colon ','
- pattern = tizen.time.getDateFormat(isShortFormat) + ", " + tizen.time.getTimeFormat();
}
- var currentDateTime = tizen.time.getCurrentDateTime();
- if (pattern && currentDateTime) {
- // TODO currently value as "GMT+09:00" will be returned,
- // to get value "Asia/Seoul" use .getTimezone() instead
- var timezoneAbbreviation = currentDateTime.getTimezoneAbbreviation();
-
- // TODO method secondsFromUTC returns inverted offset: if time zone is GMT+8, it will return -32,400.
- // TODO currently utcOffset will include DST additional hour if it is present, value will be
- // timezoneOffset = timezoneOffsetWithoutDST + DSTAdditionalOffset
- // if other behaviour is correct, just need to substract dstOffset from utcOffset
- var utcOffset = currentDateTime.secondsFromUTC() * (-1);
- var dstOffset = currentDateTime.isDST() ? oneHourSeconds : 0;
-
- var result = {
- "pattern": pattern,
- "timezone": timezoneAbbreviation,
- "utc_offset": utcOffset,
- "dst_offset": dstOffset
- };
- setTimeout( function() {
- successCb (result);
- }, 0);
- } else {
- errorCb(new GlobalizationError(GlobalizationError.PATTERN_ERROR , "cannot get pattern"));
- }
+ var callback = function(result) {
+ // Checking succes of gathering pattern
+ var fullResult = {};
+ if (native_.isFailure(result)) {
+ var error = new GlobalizationError(
+ GlobalizationError.PATTERN_ERROR , native_.getErrorObject(result).message)
+ native_.callIfPossible(errorCb, error);
+ return;
+ } else {
+ // not calling success callback yet
+ fullResult = native_.getResultObject(result);
+ }
+
+ // looking for missing pieces of fullResult object
+ var currentDateTime = tizen.time.getCurrentDateTime();
+ if (currentDateTime) {
+ // TODO currently value as "GMT+09:00" will be returned,
+ // to get value "Asia/Seoul" use .getTimezone() instead
+ var timezoneAbbreviation = currentDateTime.getTimezoneAbbreviation();
+
+ // TODO method secondsFromUTC returns inverted offset: if time zone is GMT+8, it will return -32,400.
+ // TODO currently utcOffset will include DST additional hour if it is present, value will be
+ // timezoneOffset = timezoneOffsetWithoutDST + DSTAdditionalOffset
+ // if other behaviour is correct, just need to substract dstOffset from utcOffset
+ var utcOffset = currentDateTime.secondsFromUTC() * (-1);
+ var dstOffset = currentDateTime.isDST() ? oneHourSeconds : 0;
+
+ //adding missing parts of result
+ fullResult["timezone"] = timezoneAbbreviation;
+ fullResult["utc_offset"] = utcOffset;
+ fullResult["dst_offset"] = dstOffset;
+ successCb(fullResult);
+ } else {
+ var error = new GlobalizationError(
+ GlobalizationError.PATTERN_ERROR , "cannot get pattern");
+ native_.callIfPossible(errorCb, error);
+ }
+ };
+ var callArgs = {
+ formatLength: String(formatLength),
+ selector: String(selector)
+ };
+ native_.call('CordovaGlobalization_getDatePattern', callArgs, callback);
}
-// TODO implement this as native method
Globalization.getDateNames = function(successCb, errorCb, options) {
// TODO add validation of parameters
- setTimeout( function() {
- errorCb(new GlobalizationError(GlobalizationError.UNKNOWN_ERROR , "unsupported"))
- }, 0);
+ var type = typeWide;
+ var item = itemDays;
+ if (options) {
+ type = options.type || typeWide;
+ item = options.item || itemDays;
+ }
+
+ var callback = function(result) {
+ if (native_.isFailure(result)) {
+ var error = new GlobalizationError(
+ GlobalizationError.UNKNOWN_ERROR , native_.getErrorObject(result).message)
+ native_.callIfPossible(errorCb, error);
+ } else {
+ successCb(native_.getResultObject(result));
+ }
+ };
+ var callArgs = {
+ type: String(type),
+ item: String(item)
+ };
+ native_.call('CordovaGlobalization_getDateNames', callArgs, callback);
}
Globalization.isDayLightSavingsTime = function(date, successCb, errorCb) {
@@ -209,53 +239,105 @@ Globalization.isDayLightSavingsTime = function(date, successCb, errorCb) {
}
}
-//TODO implement this as native method
Globalization.getFirstDayOfWeek = function(successCb, errorCb) {
// TODO add validation of parameters
- setTimeout( function() {
- errorCb(new GlobalizationError(GlobalizationError.UNKNOWN_ERROR , "unsupported"))
- }, 0);
+ var callback = function(result) {
+ if (native_.isFailure(result)) {
+ var error = new GlobalizationError(
+ GlobalizationError.UNKNOWN_ERROR , native_.getErrorObject(result).message)
+ native_.callIfPossible(errorCb, error);
+ } else {
+ successCb(native_.getResultObject(result));
+ }
+ };
+ native_.call('CordovaGlobalization_getFirstDayOfWeek', {}, callback);
}
-//TODO how to implement this??
Globalization.numberToString = function(number, successCb, errorCb, options) {
// TODO add validation of parameters
- var result = number.toLocaleString();
- setTimeout( function() {
- successCb ( {'value' : result} );
- }, 0);
+ var type = numberTypeDecimal;
+ if (options) {
+ type = options.type || numberTypeDecimal;
+ }
+
+ var callback = function(result) {
+ if (native_.isFailure(result)) {
+ var error = new GlobalizationError(
+ GlobalizationError.FORMATTING_ERROR , native_.getErrorObject(result).message)
+ native_.callIfPossible(errorCb, error);
+ } else {
+ successCb(native_.getResultObject(result));
+ }
+ };
+ var callArgs = {
+ number: String(number),
+ type: String(type)
+ };
+ native_.call('CordovaGlobalization_numberToString', callArgs, callback);
}
-//TODO how should look this implementation about options??
Globalization.stringToNumber = function(numberStr, successCb, errorCb, options) {
// TODO add validation of parameters
- var result = Number(numberStr);
- if ('NaN' != result.toString()) {
- setTimeout( function() {
- successCb ( {'value' : result} );
- }, 0);
- } else {
- setTimeout( function() {
- errorCb(new GlobalizationError(GlobalizationError.PARSING_ERROR ,
- "cannot convert string to number"))
- }, 0);
+ var type = numberTypeDecimal;
+ if (options) {
+ type = options.type || numberTypeDecimal;
}
+
+ var callback = function(result) {
+ if (native_.isFailure(result)) {
+ var error = new GlobalizationError(
+ GlobalizationError.PARSING_ERROR , native_.getErrorObject(result).message)
+ native_.callIfPossible(errorCb, error);
+ } else {
+ var result = native_.getResultObject(result);
+ result.value = Number(result.value);
+ successCb(result);
+ }
+ };
+ var callArgs = {
+ number: String(numberStr),
+ type: String(type)
+ };
+ native_.call('CordovaGlobalization_stringToNumber', callArgs, callback);
}
-//TODO how to implement this??
Globalization.getNumberPattern = function(successCb, errorCb, options) {
// TODO add validation of parameters
- setTimeout( function() {
- errorCb(new GlobalizationError(GlobalizationError.UNKNOWN_ERROR , "unsupported"))
- }, 0);
+ var type = numberTypeDecimal;
+ if (options) {
+ type = options.type || numberTypeDecimal;
+ }
+
+ var callback = function(result) {
+ if (native_.isFailure(result)) {
+ var error = new GlobalizationError(
+ GlobalizationError.UNKNOWN_ERROR , native_.getErrorObject(result).message)
+ native_.callIfPossible(errorCb, error);
+ } else {
+ successCb(native_.getResultObject(result));
+ }
+ };
+ var callArgs = {
+ type: String(type)
+ };
+ native_.call('CordovaGlobalization_getNumberPattern', callArgs, callback);
}
-//TODO how to implement this??
Globalization.getCurrencyPattern = function(currencyCode, successCb, errorCb) {
// TODO add validation of parameters
- setTimeout( function() {
- errorCb(new GlobalizationError(GlobalizationError.UNKNOWN_ERROR , "unsupported"))
- }, 0);
+ var callback = function(result) {
+ if (native_.isFailure(result)) {
+ var error = new GlobalizationError(
+ GlobalizationError.UNKNOWN_ERROR , native_.getErrorObject(result).message)
+ native_.callIfPossible(errorCb, error);
+ } else {
+ successCb(native_.getResultObject(result));
+ }
+ };
+ var callArgs = {
+ currencyCode : String(currencyCode)
+ };
+ native_.call('CordovaGlobalization_getCurrencyPattern', callArgs, callback);
}
_navigator.globalization = Globalization;
diff --git a/src/globalization/cordova_globalization_extension.cc b/src/globalization/cordova_globalization_extension.cc
index 7bb780d..ddf1d3d 100755
--- a/src/globalization/cordova_globalization_extension.cc
+++ b/src/globalization/cordova_globalization_extension.cc
@@ -15,11 +15,13 @@
*/
#include "globalization/cordova_globalization_extension.h"
+#include "globalization/cordova_globalization_instance.h"
// This will be generated from cordova_globalization_api.js
extern const char kSource_cordova_globalization_api[];
common::Extension* CreateExtension() {
+ LoggerD("Entered");
return new extension::cordova::globalization::CordovaGlobalizationExtension();
}
@@ -28,12 +30,20 @@ namespace cordova {
namespace globalization {
CordovaGlobalizationExtension::CordovaGlobalizationExtension() {
+ LoggerD("Entered");
SetExtensionName("tizen.cordova.globalization");
SetJavaScriptAPI(kSource_cordova_globalization_api);
}
-CordovaGlobalizationExtension::~CordovaGlobalizationExtension() {}
+CordovaGlobalizationExtension::~CordovaGlobalizationExtension() {
+ LoggerD("Entered");
+}
+
+common::Instance* CordovaGlobalizationExtension::CreateInstance() {
+ LoggerD("Entered");
+ return new extension::cordova::globalization::CordovaGlobalizationInstance();
+}
-} // globalization
-} // cordova
-} // extension
+} // globalization
+} // cordova
+} // extension
diff --git a/src/globalization/cordova_globalization_extension.h b/src/globalization/cordova_globalization_extension.h
index 91a37ec..cf053aa 100755
--- a/src/globalization/cordova_globalization_extension.h
+++ b/src/globalization/cordova_globalization_extension.h
@@ -27,10 +27,14 @@ class CordovaGlobalizationExtension : public common::Extension {
public:
CordovaGlobalizationExtension();
virtual ~CordovaGlobalizationExtension();
+
+ private:
+ // common::Extension implementation.
+ virtual common::Instance* CreateInstance();
};
-} // globalization
-} // cordova
-} // extension
+} // globalization
+} // cordova
+} // extension
#endif // GLOBALIZATION_CORDOVA_GLOBALIZATION_EXTENSION_H_
diff --git a/src/globalization/cordova_globalization_instance.cc b/src/globalization/cordova_globalization_instance.cc
new file mode 100644
index 0000000..721039a
--- /dev/null
+++ b/src/globalization/cordova_globalization_instance.cc
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "globalization/cordova_globalization_instance.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "globalization/cordova_globalization_tools.h"
+
+namespace extension {
+namespace cordova {
+namespace globalization {
+
+using std::string;
+using common::ErrorCode;
+using common::PlatformResult;
+using common::Instance;
+using common::TaskQueue;
+
+CordovaGlobalizationInstance::CordovaGlobalizationInstance() {
+ using std::placeholders::_1;
+ using std::placeholders::_2;
+
+ LoggerD("Entered");
+
+#define REGISTER_SYNC(c, x) \
+ RegisterSyncHandler(c, std::bind(&CordovaGlobalizationInstance::x, this, _1, _2));
+#define REGISTER_ASYNC(c, x) \
+ RegisterSyncHandler(c, std::bind(&CordovaGlobalizationInstance::x, this, _1, _2));
+
+ REGISTER_SYNC("CordovaGlobalization_dateToString", DateToString);
+ REGISTER_SYNC("CordovaGlobalization_stringToDate", StringToDate);
+ REGISTER_SYNC("CordovaGlobalization_getDatePattern", GetDatePattern);
+ REGISTER_SYNC("CordovaGlobalization_getDateNames", GetDateNames);
+ REGISTER_SYNC("CordovaGlobalization_getFirstDayOfWeek", GetFirstDayOfWeek);
+ REGISTER_SYNC("CordovaGlobalization_numberToString", NumberToString);
+ REGISTER_SYNC("CordovaGlobalization_stringToNumber", StringToNumber);
+ REGISTER_SYNC("CordovaGlobalization_getNumberPattern", GetNumberPattern);
+ REGISTER_SYNC("CordovaGlobalization_getCurrencyPattern", GetCurrencyPattern);
+
+
+#undef REGISTER_SYNC
+#undef REGISTER_ASYNC
+}
+
+CordovaGlobalizationInstance::~CordovaGlobalizationInstance() {
+ LoggerD("Entered");
+}
+
+void CordovaGlobalizationInstance::DateToString(const picojson::value& args,
+ picojson::object& out) {
+ LoggerD("Entered");
+ if (!args.contains("formatLength") || !args.contains("selector") || !args.contains("timestamp") ||
+ !args.contains("callbackId")) {
+ LoggerE("Invalid parameter passed.");
+ ReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."), &out);
+ return;
+ }
+ const double callback_id = args.get("callbackId").get();
+
+ const std::string& format_length = args.get("formatLength").get();
+ const std::string& selector = args.get("selector").get();
+ const std::string& timestamp_str = args.get("timestamp").get();
+ UDate date = std::stod(timestamp_str);
+
+ auto get = [this, format_length, selector, date](const std::shared_ptr& response) -> void {
+ string result_str = CordovaGlobalizationTools::GetDateString(
+ date, CordovaGlobalizationTools::GetDateFormat(format_length), selector);
+
+ picojson::value result = picojson::value(picojson::object());
+ picojson::object& result_obj = result.get();
+ result_obj.insert(std::make_pair("value", picojson::value(result_str)));
+ ReportSuccess(result, response->get());
+ };
+
+ auto get_response = [this, callback_id](const std::shared_ptr& response) -> void {
+ LoggerD("Getting response");
+ picojson::object& obj = response->get();
+ obj.insert(std::make_pair("callbackId", picojson::value{static_cast(callback_id)}));
+ LoggerD("message: %s", response->serialize().c_str());
+ Instance::PostMessage(this, response->serialize().c_str());
+ };
+
+ auto data = std::shared_ptr(new picojson::value(picojson::object()));
+ TaskQueue::GetInstance().Queue(get, get_response, data);
+}
+
+void CordovaGlobalizationInstance::StringToDate(const picojson::value& args,
+ picojson::object& out) {
+ LoggerD("Entered");
+ if (!args.contains("formatLength") || !args.contains("selector") || !args.contains("dateString") ||
+ !args.contains("callbackId")) {
+ LoggerE("Invalid parameter passed.");
+ ReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."), &out);
+ return;
+ }
+ const double callback_id = args.get("callbackId").get();
+
+ const std::string& format_length = args.get("formatLength").get();
+ const std::string& selector = args.get("selector").get();
+ const std::string& date_str = args.get("dateString").get();
+
+ auto get = [this, format_length, selector, date_str](const std::shared_ptr& response) -> void {
+ UDate result_date = 0;
+ PlatformResult ret = CordovaGlobalizationTools::GetUDateFromString(
+ date_str, CordovaGlobalizationTools::GetDateFormat(format_length), selector, &result_date);
+
+ if (ret.IsSuccess()) {
+ // UDate holds milliseconds, conversion to time_t needs seconds
+ time_t seconds_ts = (time_t)(result_date / 1000);
+
+ struct tm * result_time = localtime(&seconds_ts);
+ picojson::value result = picojson::value(picojson::object());
+ picojson::object& result_obj = result.get();
+ result_obj.insert(std::make_pair(
+ "year", picojson::value(static_cast(result_time->tm_year + 1900))));
+ result_obj.insert(std::make_pair(
+ "month", picojson::value(static_cast(result_time->tm_mon))));
+ result_obj.insert(std::make_pair(
+ "day", picojson::value(static_cast(result_time->tm_mday))));
+ result_obj.insert(std::make_pair(
+ "hour", picojson::value(static_cast(result_time->tm_hour))));
+ result_obj.insert(std::make_pair(
+ "minute", picojson::value(static_cast(result_time->tm_min))));
+ result_obj.insert(std::make_pair(
+ "second", picojson::value(static_cast(result_time->tm_sec))));
+ result_obj.insert(std::make_pair(
+ "millisecond", picojson::value(static_cast(0.0))));
+
+ ReportSuccess(result, response->get());
+ } else {
+ ReportError(ret, &(response->get()));
+ }
+ };
+
+ auto get_response = [this, callback_id](const std::shared_ptr& response) -> void {
+ LoggerD("Getting response");
+ picojson::object& obj = response->get();
+ obj.insert(std::make_pair("callbackId", picojson::value{static_cast(callback_id)}));
+ LoggerD("message: %s", response->serialize().c_str());
+ Instance::PostMessage(this, response->serialize().c_str());
+ };
+
+ auto data = std::shared_ptr(new picojson::value(picojson::object()));
+ TaskQueue::GetInstance().Queue(get, get_response, data);
+}
+
+void CordovaGlobalizationInstance::GetDatePattern(const picojson::value& args,
+ picojson::object& out) {
+ LoggerD("Entered");
+ if (!args.contains("formatLength") || !args.contains("selector") || !args.contains("callbackId")) {
+ LoggerE("Invalid parameter passed.");
+ ReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."), &out);
+ return;
+ }
+ const double callback_id = args.get("callbackId").get();
+
+ const std::string& format_length = args.get("formatLength").get();
+ const std::string& selector = args.get("selector").get();
+
+ auto get = [this, format_length, selector](const std::shared_ptr& response) -> void {
+ string result_str;
+ PlatformResult ret = CordovaGlobalizationTools::GetDatePattern(
+ CordovaGlobalizationTools::GetDateFormat(format_length), selector, &result_str);
+
+ if (ret.IsSuccess()) {
+ picojson::value result = picojson::value(picojson::object());
+ picojson::object& result_obj = result.get();
+
+ // returning only pattern of date, rest of result should be added in JS using web device API
+ result_obj.insert(std::make_pair("pattern", picojson::value(result_str)));
+
+ ReportSuccess(result, response->get());
+ } else {
+ ReportError(ret, &(response->get()));
+ }
+ };
+
+ auto get_response = [this, callback_id](const std::shared_ptr& response) -> void {
+ LoggerD("Getting response");
+ picojson::object& obj = response->get();
+ obj.insert(std::make_pair("callbackId", picojson::value{static_cast(callback_id)}));
+ LoggerD("message: %s", response->serialize().c_str());
+ Instance::PostMessage(this, response->serialize().c_str());
+ };
+
+ auto data = std::shared_ptr(new picojson::value(picojson::object()));
+ TaskQueue::GetInstance().Queue(get, get_response, data);
+}
+
+void CordovaGlobalizationInstance::GetDateNames(const picojson::value& args,
+ picojson::object& out) {
+ LoggerD("Entered");
+ if (!args.contains("type") || !args.contains("item") || !args.contains("callbackId")) {
+ LoggerE("Invalid parameter passed.");
+ ReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."), &out);
+ return;
+ }
+ const double callback_id = args.get("callbackId").get();
+
+ const std::string& type = args.get("type").get();
+ const std::string& item = args.get("item").get();
+
+ auto get = [this, type, item](const std::shared_ptr& response) -> void {
+ std::vector items;
+ PlatformResult ret = CordovaGlobalizationTools::GetNames(item, type, &items);
+
+ if (ret.IsError() || items.empty()) {
+ LoggerE("Cannot get names for %s", item.c_str());
+ ReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Cannot get names."),
+ &(response->get()));
+ }
+
+ // creating json array
+ picojson::value result_array = picojson::value(picojson::array());
+ picojson::array& array_obj = result_array.get();
+ for (size_t i = 0 ; i < items.size(); i++) {
+ array_obj.push_back(picojson::value(items[i]));
+ }
+
+ picojson::value result = picojson::value(picojson::object());
+ picojson::object& result_obj = result.get();
+ result_obj.insert(std::make_pair("value", result_array));
+ ReportSuccess(result, response->get());
+ };
+
+ auto get_response = [this, callback_id](const std::shared_ptr& response) -> void {
+ LoggerD("Getting response");
+ picojson::object& obj = response->get();
+ obj.insert(std::make_pair("callbackId", picojson::value{static_cast(callback_id)}));
+ LoggerD("message: %s", response->serialize().c_str());
+ Instance::PostMessage(this, response->serialize().c_str());
+ };
+
+ auto data = std::shared_ptr(new picojson::value(picojson::object()));
+ TaskQueue::GetInstance().Queue(get, get_response, data);
+}
+
+void CordovaGlobalizationInstance::GetFirstDayOfWeek(const picojson::value& args,
+ picojson::object& out) {
+ LoggerD("Entered");
+ if (!args.contains("callbackId")) {
+ LoggerE("Invalid parameter passed.");
+ ReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."), &out);
+ return;
+ }
+ const double callback_id = args.get("callbackId").get();
+
+ auto get = [this](const std::shared_ptr& response) -> void {
+ double first_day_value = 0;
+ PlatformResult ret = CordovaGlobalizationTools::GetFirstDayOfWeek(&first_day_value);
+ if (ret.IsSuccess()) {
+ picojson::value result = picojson::value(picojson::object());
+ picojson::object& result_obj = result.get();
+ result_obj.insert(std::make_pair("value", picojson::value(first_day_value)));
+ ReportSuccess(result, response->get());
+ } else {
+ ReportError(ret, &(response->get()));
+ }
+ };
+
+ auto get_response = [this, callback_id](const std::shared_ptr& response) -> void {
+ LoggerD("Getting response");
+ picojson::object& obj = response->get();
+ obj.insert(std::make_pair("callbackId", picojson::value{static_cast(callback_id)}));
+ LoggerD("message: %s", response->serialize().c_str());
+ Instance::PostMessage(this, response->serialize().c_str());
+ };
+
+ auto data = std::shared_ptr(new picojson::value(picojson::object()));
+ TaskQueue::GetInstance().Queue(get, get_response, data);
+}
+
+void CordovaGlobalizationInstance::NumberToString(const picojson::value& args,
+ picojson::object& out) {
+ LoggerD("Entered");
+ if (!args.contains("type") || !args.contains("number") || !args.contains("callbackId")) {
+ LoggerE("Invalid parameter passed.");
+ ReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."), &out);
+ return;
+ }
+ const double callback_id = args.get("callbackId").get();
+
+ // this type of conversion of double is locale independent, always parse dots (JS send number with dot)
+ double number = 0.0f;
+ std::istringstream istr(args.get("number").get());
+ istr >> number;
+
+ const std::string& type = args.get("type").get();
+
+ auto get = [this, type, number](const std::shared_ptr& response) -> void {
+ std::string result_str;
+ PlatformResult ret = CordovaGlobalizationTools::FormatNumber(number, type, &result_str);
+ if (ret.IsSuccess()) {
+ picojson::value result = picojson::value(picojson::object());
+ picojson::object& result_obj = result.get();
+ result_obj.insert(std::make_pair("value", picojson::value(result_str)));
+ ReportSuccess(result, response->get());
+ } else {
+ ReportError(ret, &(response->get()));
+ }
+ };
+
+ auto get_response = [this, callback_id](const std::shared_ptr& response) -> void {
+ LoggerD("Getting response");
+ picojson::object& obj = response->get();
+ obj.insert(std::make_pair("callbackId", picojson::value{static_cast(callback_id)}));
+ LoggerD("message: %s", response->serialize().c_str());
+ Instance::PostMessage(this, response->serialize().c_str());
+ };
+
+ auto data = std::shared_ptr(new picojson::value(picojson::object()));
+ TaskQueue::GetInstance().Queue(get, get_response, data);
+}
+
+void CordovaGlobalizationInstance::StringToNumber(const picojson::value& args,
+ picojson::object& out) {
+ LoggerD("Entered");
+ if (!args.contains("type") || !args.contains("number") || !args.contains("callbackId")) {
+ LoggerE("Invalid parameter passed.");
+ ReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."), &out);
+ return;
+ }
+ const double callback_id = args.get("callbackId").get();
+ const std::string& number_str = args.get("number").get();
+ const std::string& type = args.get("type").get();
+
+ auto get = [this, type, number_str](const std::shared_ptr& response) -> void {
+ double result_num = 0;
+ PlatformResult ret = CordovaGlobalizationTools::ParseNumber(number_str, type, &result_num);
+
+ if (ret.IsSuccess()) {
+ // replacing ',' for '.' if any exist, locale independence (JS need number with dot)
+ std::string result_str = std::to_string(result_num);
+ std::replace(result_str.begin(), result_str.end(), ',', '.');
+
+ picojson::value result = picojson::value(picojson::object());
+ picojson::object& result_obj = result.get();
+ result_obj.insert(std::make_pair("value", picojson::value(result_str)));
+ ReportSuccess(result, response->get());
+ } else {
+ ReportError(ret, &(response->get()));
+ }
+ };
+
+ auto get_response = [this, callback_id](const std::shared_ptr& response) -> void {
+ LoggerD("Getting response");
+ picojson::object& obj = response->get();
+ obj.insert(std::make_pair("callbackId", picojson::value{static_cast(callback_id)}));
+ LoggerD("message: %s", response->serialize().c_str());
+ Instance::PostMessage(this, response->serialize().c_str());
+ };
+
+ auto data = std::shared_ptr(new picojson::value(picojson::object()));
+ TaskQueue::GetInstance().Queue(get, get_response, data);
+}
+
+void CordovaGlobalizationInstance::GetNumberPattern(const picojson::value& args,
+ picojson::object& out) {
+ LoggerD("Entered");
+ if (!args.contains("type") || !args.contains("callbackId")) {
+ LoggerE("Invalid parameter passed.");
+ ReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."), &out);
+ return;
+ }
+ const double callback_id = args.get("callbackId").get();
+ const std::string& type = args.get("type").get();
+
+ auto get = [this, type](const std::shared_ptr& response) -> void {
+ picojson::value result = picojson::value(picojson::object());
+ picojson::object& result_obj = result.get();
+
+ std::string res_pattern, res_symbol, res_positive, res_negative, res_decimal, res_grouping;
+ double res_fraction = 0;
+ double res_rounding = 0;
+
+ CordovaGlobalizationTools::GetNumberPattern(type, &res_pattern, &res_symbol, &res_fraction,
+ &res_rounding, &res_positive, &res_negative,
+ &res_decimal, &res_grouping);
+ result_obj.insert(std::make_pair("pattern", picojson::value(res_pattern)));
+ result_obj.insert(std::make_pair("symbol", picojson::value(res_symbol)));
+ result_obj.insert(std::make_pair("fraction", picojson::value(res_fraction)));
+ result_obj.insert(std::make_pair("rounding", picojson::value(res_rounding)));
+ result_obj.insert(std::make_pair("positive", picojson::value(res_positive)));
+ result_obj.insert(std::make_pair("negative", picojson::value(res_negative)));
+ result_obj.insert(std::make_pair("decimal", picojson::value(res_decimal)));
+ result_obj.insert(std::make_pair("grouping", picojson::value(res_grouping)));
+
+ ReportSuccess(result, response->get());
+ };
+
+ auto get_response = [this, callback_id](const std::shared_ptr& response) -> void {
+ LoggerD("Getting response");
+ picojson::object& obj = response->get();
+ obj.insert(std::make_pair("callbackId", picojson::value{static_cast(callback_id)}));
+ LoggerD("message: %s", response->serialize().c_str());
+ Instance::PostMessage(this, response->serialize().c_str());
+ };
+
+ auto data = std::shared_ptr(new picojson::value(picojson::object()));
+ TaskQueue::GetInstance().Queue(get, get_response, data);
+}
+
+void CordovaGlobalizationInstance::GetCurrencyPattern(const picojson::value& args,
+ picojson::object& out) {
+ LoggerD("Entered");
+ if (!args.contains("currencyCode") || !args.contains("callbackId")) {
+ LoggerE("Invalid parameter passed.");
+ ReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."), &out);
+ return;
+ }
+ const double callback_id = args.get("callbackId").get();
+ const std::string& code = args.get("currencyCode").get();
+
+ auto get = [this, code](const std::shared_ptr& response) -> void {
+ picojson::value result = picojson::value(picojson::object());
+ picojson::object& result_obj = result.get();
+
+ std::string res_pattern, res_decimal, res_grouping;
+ double res_fraction = 0;
+ double res_rounding = 0;
+
+ CordovaGlobalizationTools::GetCurrencyPattern(code, &res_pattern, &res_fraction,
+ &res_rounding, &res_decimal, &res_grouping);
+ result_obj.insert(std::make_pair("pattern", picojson::value(res_pattern)));
+ result_obj.insert(std::make_pair("code", picojson::value(code)));
+ result_obj.insert(std::make_pair("fraction", picojson::value(res_fraction)));
+ result_obj.insert(std::make_pair("rounding", picojson::value(res_rounding)));
+ result_obj.insert(std::make_pair("decimal", picojson::value(res_decimal)));
+ result_obj.insert(std::make_pair("grouping", picojson::value(res_grouping)));
+
+ ReportSuccess(result, response->get());
+ };
+
+ auto get_response = [this, callback_id](const std::shared_ptr& response) -> void {
+ LoggerD("Getting response");
+ picojson::object& obj = response->get();
+ obj.insert(std::make_pair("callbackId", picojson::value{static_cast(callback_id)}));
+ LoggerD("message: %s", response->serialize().c_str());
+ Instance::PostMessage(this, response->serialize().c_str());
+ };
+
+ auto data = std::shared_ptr(new picojson::value(picojson::object()));
+ TaskQueue::GetInstance().Queue(get, get_response, data);
+}
+
+} // globalization
+} // cordova
+} // extension
diff --git a/src/globalization/cordova_globalization_instance.h b/src/globalization/cordova_globalization_instance.h
new file mode 100644
index 0000000..d4fc780
--- /dev/null
+++ b/src/globalization/cordova_globalization_instance.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GLOBALIZATION_CORDOVA_GLOBALIZATION_INSTANCE_H_
+#define GLOBALIZATION_CORDOVA_GLOBALIZATION_INSTANCE_H_
+
+#include
+#include
+
+namespace extension {
+namespace cordova {
+namespace globalization {
+
+class CordovaGlobalizationInstance : public common::ParsedInstance {
+ public:
+ CordovaGlobalizationInstance();
+ virtual ~CordovaGlobalizationInstance();
+
+ private:
+ void DateToString(const picojson::value& args, picojson::object& out);
+ void StringToDate(const picojson::value& args, picojson::object& out);
+ void GetDatePattern(const picojson::value& args, picojson::object& out);
+ void GetDateNames(const picojson::value& args, picojson::object& out);
+ void GetFirstDayOfWeek(const picojson::value& args, picojson::object& out);
+ void NumberToString(const picojson::value& args, picojson::object& out);
+ void StringToNumber(const picojson::value& args, picojson::object& out);
+ void GetNumberPattern(const picojson::value& args, picojson::object& out);
+ void GetCurrencyPattern(const picojson::value& args, picojson::object& out);
+};
+} // globalization
+} // cordova
+} // extension
+
+#endif // GLOBALIZATION_CORDOVA_GLOBALIZATION_INSTANCE_H_
diff --git a/src/globalization/cordova_globalization_tools.cc b/src/globalization/cordova_globalization_tools.cc
new file mode 100644
index 0000000..a42680c
--- /dev/null
+++ b/src/globalization/cordova_globalization_tools.cc
@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "globalization/cordova_globalization_tools.h"
+#include
+#include
+#include
+#include
+#include
+
+namespace extension {
+namespace cordova {
+namespace globalization {
+
+using std::string;
+using common::ErrorCode;
+using common::PlatformResult;
+
+const std::string kSelectorDateStr = "date";
+const std::string kSelectorTimeStr = "time";
+
+const std::string kFormatShortStr = "short";
+const std::string kFormatMediumStr = "medium";
+const std::string kFormatLongStr = "long";
+const std::string kFormatFullStr = "full";
+
+const std::string kItemMonths = "months";
+const std::string kItemDays = "days";
+
+const std::string kTypeWide = "wide";
+const std::string kTypeNarrow = "narrow";
+
+const std::string kNumberTypeDecimal = "decimal";
+const std::string kNumberTypePercent = "percent";
+const std::string kNumberTypeCurrency = "currency";
+
+Locale CordovaGlobalizationTools::GetDefaultLocale() {
+ //TODO add gathering locale according to settings
+ return Locale::createFromName("en_US");
+ //return Locale::getUK();
+}
+
+std::string CordovaGlobalizationTools::ToUTF8String(const UnicodeString& uni_str) {
+ LoggerD("Entered");
+ int buffer_len = sizeof(UChar) * uni_str.length() + 1;
+ std::unique_ptr result_buffer(static_cast(malloc(buffer_len)),
+ &std::free);
+ if (!result_buffer) {
+ return "";
+ }
+
+ memset(result_buffer.get(), 0, buffer_len);
+ CheckedArrayByteSink sink(result_buffer.get(), buffer_len);
+ uni_str.toUTF8(sink);
+
+ if (sink.Overflowed()) {
+ return "";
+ }
+
+ return result_buffer.get();
+}
+
+DateFormat::EStyle CordovaGlobalizationTools::GetDateFormat(const std::string& length) {
+ LoggerD("Entered");
+ if (kFormatShortStr == length) {
+ return DateFormat::kShort;
+ } else if (kFormatMediumStr == length) {
+ return DateFormat::kMedium;
+ } else if (kFormatLongStr == length) {
+ return DateFormat::kLong;
+ }
+ // default length would be full
+ return DateFormat::kFull;
+}
+
+std::unique_ptr CordovaGlobalizationTools::GetDateFormatPtr(DateFormat::EStyle format,
+ const std::string& selector) {
+ LoggerD("Entered");
+ bool foundDate = (std::string::npos != selector.find(kSelectorDateStr));
+ bool foundTime = (std::string::npos != selector.find(kSelectorTimeStr));
+
+ std::unique_ptr dfmt;
+ Locale l = GetDefaultLocale();
+ if (foundDate && !foundTime) {
+ dfmt.reset(DateFormat::createDateInstance(format, l));
+ } else if (!foundDate && foundTime) {
+ dfmt.reset(DateFormat::createTimeInstance(format, l));
+ } else {
+ dfmt.reset(DateFormat::createDateTimeInstance(format, format, l));
+ }
+ return dfmt;
+}
+
+std::string CordovaGlobalizationTools::GetDateString(UDate date, DateFormat::EStyle format,
+ const std::string& selector) {
+ LoggerD("Entered");
+ UnicodeString str;
+ std::unique_ptr dfmt = GetDateFormatPtr(format, selector);
+
+ dfmt->format(date, str);
+ return ToUTF8String(str);
+}
+
+PlatformResult CordovaGlobalizationTools::GetUDateFromString(const std::string& date,
+ DateFormat::EStyle format,
+ const std::string& selector,
+ UDate* result) {
+ LoggerD("Entered");
+ UErrorCode ec = U_ZERO_ERROR;
+ std::unique_ptr dfmt = GetDateFormatPtr(format, selector);
+
+ UDate tmp_result = dfmt->parse(UnicodeString(date.c_str()), ec);
+ if (U_ZERO_ERROR >= ec) {
+ *result = tmp_result;
+ return PlatformResult(ErrorCode::NO_ERROR);
+ } else {
+ return PlatformResult(ErrorCode::UNKNOWN_ERR, "Could not parse date");
+ }
+}
+
+PlatformResult CordovaGlobalizationTools::GetDatePattern(DateFormat::EStyle format,
+ const std::string& selector, std::string* result) {
+ LoggerD("Entered");
+ UErrorCode ec = U_ZERO_ERROR;
+ UnicodeString res;
+ std::unique_ptr dfmt = GetDateFormatPtr(format, selector);
+
+ if (SimpleDateFormat::getStaticClassID() != dfmt->getDynamicClassID()) {
+ LoggerE("Could not cast to SimpleDateFormat, operation failed");
+ return PlatformResult(ErrorCode::UNKNOWN_ERR, "Could not cast to SimpleDateFormat");
+ } else {
+ LoggerE("Casting to SimpleDateFormat is allowed");
+ }
+
+ SimpleDateFormat* sdf = dynamic_cast(dfmt.get());
+ if (sdf) {
+ std::string tmp_result = ToUTF8String(sdf->toLocalizedPattern(res, ec));
+ if (U_ZERO_ERROR >= ec) {
+ *result = tmp_result;
+ return PlatformResult(ErrorCode::NO_ERROR);
+ }
+ }
+ return PlatformResult(ErrorCode::UNKNOWN_ERR, "Could not get date pattern");
+}
+
+PlatformResult CordovaGlobalizationTools::GetNames(const std::string& item,
+ const std::string& type,
+ std::vector* result) {
+ LoggerD("Entered");
+ std::vector tmp_result;
+ int32_t count = 0;
+ UErrorCode ec = U_ZERO_ERROR;
+ icu::DateFormatSymbols dfs = DateFormatSymbols(GetDefaultLocale(), ec);
+ if (U_ZERO_ERROR >= ec) {
+ UnicodeString* names_vector = nullptr; // DateFormatSymbols retains ownership.
+ if (kItemMonths == item) {
+ if (kTypeWide == type) {
+ names_vector = const_cast(dfs.getMonths(count));
+ } else {
+ names_vector = const_cast(dfs.getShortMonths(count));
+ }
+ } else {
+ if (kTypeWide == type) {
+ names_vector = const_cast(dfs.getWeekdays(count));
+ } else {
+ names_vector = const_cast(dfs.getShortWeekdays(count));
+ }
+ }
+
+ if (names_vector) {
+ for (int i = 0; i < count;++i) {
+ if (names_vector[i].length() > 0) {
+ tmp_result.push_back(ToUTF8String(names_vector[i]));
+ }
+ }
+ }
+ *result = tmp_result;
+ return PlatformResult(ErrorCode::NO_ERROR);
+ } else {
+ return PlatformResult(ErrorCode::UNKNOWN_ERR, "Could not get days names");
+ }
+}
+
+PlatformResult CordovaGlobalizationTools::GetFirstDayOfWeek(double* result) {
+ LoggerD("Entered");
+ UnicodeString str;
+ UErrorCode ec = U_ZERO_ERROR;
+ std::unique_ptr dfmt(DateFormat::createDateInstance(DateFormat::kFull,
+ GetDefaultLocale()));
+
+ UCalendarDaysOfWeek first_day = dfmt->getCalendar()->getFirstDayOfWeek(ec);
+ if (U_ZERO_ERROR >= ec) {
+ *result = static_cast(first_day);
+ return PlatformResult(ErrorCode::NO_ERROR);
+ } else {
+ return PlatformResult(ErrorCode::UNKNOWN_ERR, "Could not get day first of week");
+ }
+}
+
+PlatformResult CordovaGlobalizationTools::FormatNumber(double number, const std::string& type,
+ std::string* result) {
+ LoggerD("Entered");
+ UErrorCode ec = U_ZERO_ERROR;
+ UnicodeString str;
+ Locale l = GetDefaultLocale();
+
+ std::unique_ptr nfmt;
+ if (kNumberTypeCurrency == type) {
+ nfmt.reset(NumberFormat::createCurrencyInstance(l, ec));
+ } else if (kNumberTypePercent == type) {
+ nfmt.reset(NumberFormat::createPercentInstance(l, ec));
+ } else {
+ nfmt.reset(NumberFormat::createInstance(l, ec));
+ }
+ if (U_ZERO_ERROR >= ec) {
+ nfmt->format(number, str);
+ *result = ToUTF8String(str);;
+ return PlatformResult(ErrorCode::NO_ERROR);
+ } else {
+ return PlatformResult(ErrorCode::UNKNOWN_ERR, "Could not format number");
+ }
+}
+
+PlatformResult CordovaGlobalizationTools::ParseNumber(const std::string& number_str,
+ const std::string& type,
+ double* result) {
+ LoggerD("Entered");
+ UErrorCode ec = U_ZERO_ERROR;
+ Locale l = GetDefaultLocale();
+ UnicodeString str(number_str.c_str());
+ PlatformResult res(ErrorCode::NO_ERROR);
+
+ std::unique_ptr nfmt;
+ if (kNumberTypeCurrency == type) {
+ nfmt.reset(NumberFormat::createCurrencyInstance(l, ec));
+ if (U_ZERO_ERROR >= ec) {
+ ParsePosition ppos;
+ std::unique_ptr ca(nfmt->parseCurrency(str, ppos));
+ // always use functions with error check
+ if (!ca) {
+ LoggerE("parseCurrency failed");
+ res = PlatformResult(ErrorCode::UNKNOWN_ERR, "parseCurrency failed");
+ } else {
+ *result = ca->getNumber().getDouble(ec);
+ if (U_ZERO_ERROR < ec) {
+ res = PlatformResult(ErrorCode::UNKNOWN_ERR, "getting double value failed");
+ }
+ }
+ } else {
+ res = PlatformResult(ErrorCode::UNKNOWN_ERR, "could not create currency parser");
+ }
+ return res;
+ } else if (kNumberTypePercent == type) {
+ nfmt.reset(NumberFormat::createPercentInstance(l, ec));
+ } else {
+ nfmt.reset(NumberFormat::createInstance(l, ec));
+ }
+ if (U_ZERO_ERROR < ec) {
+ LoggerD("could not create number parser: %d", ec);
+ res = PlatformResult(ErrorCode::UNKNOWN_ERR, "could not create number parser");
+ } else {
+ Formattable formatable;
+ nfmt->parse(str, formatable, ec);
+ if (U_ZERO_ERROR >= ec) {
+ *result = formatable.getDouble(ec);
+ if (U_ZERO_ERROR < ec) {
+ res = PlatformResult(ErrorCode::UNKNOWN_ERR, "getting double value failed");
+ }
+ } else {
+ res = PlatformResult(ErrorCode::UNKNOWN_ERR, "parsing failed");
+ }
+ }
+ return res;
+}
+
+PlatformResult CordovaGlobalizationTools::GetNumberPattern(const std::string& type, std::string* pattern,
+ std::string* symbol, double* fraction,
+ double* rounding, std::string* positive,
+ std::string* negative, std::string* decimal,
+ std::string* grouping) {
+ LoggerD("Entered");
+ UErrorCode ec = U_ZERO_ERROR;
+ UnicodeString res;
+ Locale l = GetDefaultLocale();
+
+ std::unique_ptr nfmt;
+ icu::DecimalFormatSymbols dfs = DecimalFormatSymbols(l, ec);
+ if (kNumberTypeCurrency == type) {
+ nfmt.reset(NumberFormat::createCurrencyInstance(l, ec));
+ *symbol = ToUTF8String(dfs.getSymbol(DecimalFormatSymbols::kCurrencySymbol));
+ } else if (kNumberTypePercent == type) {
+ nfmt.reset(NumberFormat::createPercentInstance(l, ec));
+ *symbol = ToUTF8String(dfs.getSymbol(DecimalFormatSymbols::kPercentSymbol));
+ } else {
+ nfmt.reset(NumberFormat::createInstance(l, ec));
+ *symbol = ToUTF8String(dfs.getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol));
+ }
+ if (U_ZERO_ERROR >= ec) {
+ if (DecimalFormat::getStaticClassID() != nfmt->getDynamicClassID()) {
+ LoggerE("Could not cast to DecimalFormat, operation failed");
+ return PlatformResult(ErrorCode::UNKNOWN_ERR, "Could not cast to DecimalFormat");
+ } else {
+ LoggerE("Casting to DecimalFormat is allowed");
+ }
+ DecimalFormat* df = dynamic_cast(nfmt.get());
+ if (!df) {
+ LoggerE("Casting failed");
+ *pattern = "";
+ }
+ *pattern = ToUTF8String(df->toLocalizedPattern(res));
+ *fraction = df->getMaximumFractionDigits();
+ *rounding = df->getRoundingIncrement();
+ *positive = ToUTF8String(dfs.getSymbol(DecimalFormatSymbols::kPlusSignSymbol));
+ *negative = ToUTF8String(dfs.getSymbol(DecimalFormatSymbols::kMinusSignSymbol));
+ *decimal = ToUTF8String(dfs.getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol));
+ *grouping = ToUTF8String(dfs.getSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol));
+
+ return PlatformResult(ErrorCode::NO_ERROR);
+ } else {
+ return PlatformResult(ErrorCode::UNKNOWN_ERR, "Could not get number pattern");
+ }
+}
+
+PlatformResult CordovaGlobalizationTools::GetCurrencyPattern(const std::string& code, std::string* pattern,
+ double* fraction, double* rounding,
+ std::string* decimal, std::string* grouping) {
+ LoggerD("Entered");
+ UErrorCode ec = U_ZERO_ERROR;
+ UnicodeString res;
+ Locale l = GetDefaultLocale();
+
+ if (code.length() >= 3) {
+ std::unique_ptr nfmt(NumberFormat::createCurrencyInstance(l, ec));
+ if (U_ZERO_ERROR >= ec) {
+ UChar currency[3] = {code[0], code[1], code[2]};
+ nfmt->setCurrency(currency,ec);
+ if (U_ZERO_ERROR >= ec) {
+ icu::DecimalFormatSymbols dfs = DecimalFormatSymbols(l, ec);
+ if (U_ZERO_ERROR >= ec) {
+ if (DecimalFormat::getStaticClassID() != nfmt->getDynamicClassID()) {
+ LoggerE("Could not cast to DecimalFormat, operation failed");
+ return PlatformResult(ErrorCode::UNKNOWN_ERR, "Could not cast to DecimalFormat");
+ } else {
+ LoggerE("Casting to DecimalFormat is allowed");
+ }
+ DecimalFormat* df = dynamic_cast(nfmt.get());
+ if (df) {
+ *pattern = ToUTF8String(df->toLocalizedPattern(res));
+
+ // find currency symbol
+ UnicodeString str;
+ nfmt->format(123, str); // use fake value just to get currency symbol
+ std::string formatted_currency = ToUTF8String(str);
+ std::string currency_symbol = formatted_currency.substr(0, formatted_currency.find("123"));
+ LoggerD("currency_symbol %s", currency_symbol.c_str());
+
+ // replacing stub given from platform with correct symbol
+ std::string currency_stub = "¤"; // core API returns it instead of currency symbol
+ size_t found_pos = pattern->find(currency_stub, 0);
+ while (string::npos != found_pos) {
+ pattern->replace(found_pos, currency_stub.length(), currency_symbol);
+ found_pos = pattern->find(currency_stub, found_pos);
+ }
+
+ LoggerD("new pattern %s", pattern->c_str());
+ *fraction = df->getMaximumFractionDigits();
+ *rounding = df->getRoundingIncrement();
+ *decimal = ToUTF8String(dfs.getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol));
+ *grouping = ToUTF8String(dfs.getSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol));
+ return PlatformResult(ErrorCode::NO_ERROR);
+ }
+ }
+ }
+ }
+ }
+ return PlatformResult(ErrorCode::UNKNOWN_ERR, "Could not get currency pattern");
+}
+
+} // globalization
+} // cordova
+} // extension
diff --git a/src/globalization/cordova_globalization_tools.h b/src/globalization/cordova_globalization_tools.h
new file mode 100644
index 0000000..9703d55
--- /dev/null
+++ b/src/globalization/cordova_globalization_tools.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GLOBALIZATION_CORDOVA_GLOBALIZATION_TOOLS_H_
+#define GLOBALIZATION_CORDOVA_GLOBALIZATION_TOOLS_H_
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+namespace extension {
+namespace cordova {
+namespace globalization {
+
+extern const std::string kSelectorDateStr;
+extern const std::string kSelectorTimeStr;
+
+extern const std::string kFormatShortStr;
+extern const std::string kFormatMediumStr;
+extern const std::string kFormatLongStr;
+extern const std::string kFormatFullStr;
+
+extern const std::string kItemMonths;
+extern const std::string kItemDays;
+
+extern const std::string kTypeWide;
+extern const std::string kTypeNarrow;
+
+extern const std::string kNumberTypeDecimal;
+extern const std::string kNumberTypePercent;
+extern const std::string kNumberTypeCurrency;
+
+class CordovaGlobalizationTools{
+ public:
+ static Locale GetDefaultLocale();
+ static std::string ToUTF8String(const UnicodeString& uni_str);
+ static std::unique_ptr GetDateFormatPtr(DateFormat::EStyle format,
+ const std::string& selector);
+ static DateFormat::EStyle GetDateFormat(const std::string& length);
+ static std::string GetDateString(UDate date, DateFormat::EStyle format,
+ const std::string& selector);
+ static common::PlatformResult GetUDateFromString(const std::string& date,
+ DateFormat::EStyle format,
+ const std::string& selector,
+ UDate* result);
+ static common::PlatformResult GetDatePattern(DateFormat::EStyle format,
+ const std::string& selector,
+ std::string* result);
+ static common::PlatformResult GetNames(const std::string& item, const std::string& type,
+ std::vector* result);
+ static common::PlatformResult GetFirstDayOfWeek(double* result);
+ static common::PlatformResult FormatNumber(double number, const std::string& type,
+ std::string* result);
+ static common::PlatformResult ParseNumber(const std::string& number_str, const std::string& type,
+ double* result);
+ static common::PlatformResult GetNumberPattern(const std::string& type, std::string* pattern,
+ std::string* symbol, double* fraction,
+ double* rounding, std::string* positive,
+ std::string* negative, std::string* decimal,
+ std::string* grouping);
+ static common::PlatformResult GetCurrencyPattern(const std::string& code, std::string* pattern,
+ double* fraction, double* rounding,
+ std::string* decimal, std::string* grouping);
+};
+} // globalization
+} // cordova
+} // extension
+
+#endif // GLOBALIZATION_CORDOVA_GLOBALIZATION_TOOLS_H_
--
2.7.4