From: Piotr Dabrowski Date: Wed, 2 Oct 2013 08:19:21 +0000 (+0200) Subject: application sources from tizen_2.2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1b6705fe17b337214ad267da072f40c4b28ea6f8;p=apps%2Fweb%2Fsample%2FContactsExchanger.git application sources from tizen_2.2 Change-Id: Ib186d41a7c9d25cb8fd077f2a2b5d88674da9723 --- diff --git a/contactsexchanger-snapshot.png b/contactsexchanger-snapshot.png new file mode 100644 index 0000000..6479aa0 Binary files /dev/null and b/contactsexchanger-snapshot.png differ diff --git a/description.xml b/description.xml new file mode 100755 index 0000000..6a3a4c0 --- /dev/null +++ b/description.xml @@ -0,0 +1,10 @@ + + + + ContactsExchanger + 1.0.0 + contactsexchanger-snapshot.png + + A sample application demonstrating the tizen device API usage. + + diff --git a/description.xsl b/description.xsl new file mode 100755 index 0000000..1f4f57f --- /dev/null +++ b/description.xsl @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + +
+ + + +
+ Type: JavaScript +

+ +

+
+ + + + + +
+ + +
+ +
diff --git a/project/.project b/project/.project new file mode 100644 index 0000000..8352d79 --- /dev/null +++ b/project/.project @@ -0,0 +1,57 @@ + + + ContactsExchanger + + + + + + org.eclipse.wst.common.project.facet.core.builder + + + + + org.eclipse.wst.jsdt.core.javascriptValidator + + + + + json.validation.builder + + + + + org.tizen.web.jslint.nature.JSLintBuilder + + + + + org.tizen.web.css.nature.CSSBuilder + + + + + org.eclipse.wst.validation.validationbuilder + + + + + org.tizen.web.project.builder.WebBuilder + + + usedLibraryType + WebUIFramework + + + + + + json.validation.nature + org.tizen.web.jslint.nature.JSLintNature + org.tizen.web.css.nature.CSSNature + org.eclipse.wst.jsdt.core.jsNature + org.eclipse.wst.common.project.facet.core.nature + org.eclipse.wst.common.modulecore.ModuleCoreNature + org.tizen.web.project.builder.WebNature + + diff --git a/project/AUTHORS b/project/AUTHORS new file mode 100644 index 0000000..e7736a8 --- /dev/null +++ b/project/AUTHORS @@ -0,0 +1,6 @@ +Dariusz Paziewski +Pawel Sierszen +Tomasz Lukawski +Piotr Wronski +Piotr Szydelko +Tomasz Paciorek diff --git a/project/LICENSE.Flora b/project/LICENSE.Flora new file mode 100644 index 0000000..4a0af40 --- /dev/null +++ b/project/LICENSE.Flora @@ -0,0 +1,206 @@ +Flora License + +Version 1.1, April, 2013 + +http://floralicense.org/license/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, +and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by +the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and +all other entities that control, are controlled by, or are +under common control with that entity. For the purposes of +this definition, "control" means (i) the power, direct or indirect, +to cause the direction or management of such entity, +whether by contract or otherwise, or (ii) ownership of fifty percent (50%) +or more of the outstanding shares, or (iii) beneficial ownership of +such entity. + +"You" (or "Your") shall mean an individual or Legal Entity +exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, +including but not limited to software source code, documentation source, +and configuration files. + +"Object" form shall mean any form resulting from mechanical +transformation or translation of a Source form, including but +not limited to compiled object code, generated documentation, +and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, +made available under the License, as indicated by a copyright notice +that is included in or attached to the work (an example is provided +in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, +that is based on (or derived from) the Work and for which the editorial +revisions, annotations, elaborations, or other modifications represent, +as a whole, an original work of authorship. For the purposes of this License, +Derivative Works shall not include works that remain separable from, +or merely link (or bind by name) to the interfaces of, the Work and +Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original +version of the Work and any modifications or additions to that Work or +Derivative Works thereof, that is intentionally submitted to Licensor +for inclusion in the Work by the copyright owner or by an individual or +Legal Entity authorized to submit on behalf of the copyright owner. +For the purposes of this definition, "submitted" means any form of +electronic, verbal, or written communication sent to the Licensor or +its representatives, including but not limited to communication on +electronic mailing lists, source code control systems, and issue +tracking systems that are managed by, or on behalf of, the Licensor +for the purpose of discussing and improving the Work, but excluding +communication that is conspicuously marked or otherwise designated +in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity +on behalf of whom a Contribution has been received by Licensor and +subsequently incorporated within the Work. + +"Tizen Certified Platform" shall mean a software platform that complies +with the standards set forth in the Tizen Compliance Specification +and passes the Tizen Compliance Tests as defined from time to time +by the Tizen Technical Steering Group and certified by the Tizen +Association or its designated agent. + +2. Grant of Copyright License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the +Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +(except as stated in this section) patent license to make, have made, +use, offer to sell, sell, import, and otherwise transfer the Work +solely as incorporated into a Tizen Certified Platform, where such +license applies only to those patent claims licensable by such +Contributor that are necessarily infringed by their Contribution(s) +alone or by combination of their Contribution(s) with the Work solely +as incorporated into a Tizen Certified Platform to which such +Contribution(s) was submitted. If You institute patent litigation +against any entity (including a cross-claim or counterclaim +in a lawsuit) alleging that the Work or a Contribution incorporated +within the Work constitutes direct or contributory patent infringement, +then any patent licenses granted to You under this License for that +Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the +Work or Derivative Works thereof pursuant to the copyright license +above, in any medium, with or without modifications, and in Source or +Object form, provided that You meet the following conditions: + + 1. You must give any other recipients of the Work or Derivative Works + a copy of this License; and + 2. You must cause any modified files to carry prominent notices stating + that You changed the files; and + 3. You must retain, in the Source form of any Derivative Works that + You distribute, all copyright, patent, trademark, and attribution + notices from the Source form of the Work, excluding those notices + that do not pertain to any part of the Derivative Works; and + 4. If the Work includes a "NOTICE" text file as part of its distribution, + then any Derivative Works that You distribute must include a readable + copy of the attribution notices contained within such NOTICE file, + excluding those notices that do not pertain to any part of + the Derivative Works, in at least one of the following places: + within a NOTICE text file distributed as part of the Derivative Works; + within the Source form or documentation, if provided along with the + Derivative Works; or, within a display generated by the Derivative Works, + if and wherever such third-party notices normally appear. + The contents of the NOTICE file are for informational purposes only + and do not modify the License. You may add Your own attribution notices + within Derivative Works that You distribute, alongside or as an addendum + to the NOTICE text from the Work, provided that such additional attribution + notices cannot be construed as modifying the License. You may add Your own + copyright statement to Your modifications and may provide additional or + different license terms and conditions for use, reproduction, or + distribution of Your modifications, or for any such Derivative Works + as a whole, provided Your use, reproduction, and distribution of + the Work otherwise complies with the conditions stated in this License + and your own copyright statement or terms and conditions do not conflict + the conditions stated in the License including section 3. + +5. Submission of Contributions. Unless You explicitly state otherwise, +any Contribution intentionally submitted for inclusion in the Work +by You to the Licensor shall be under the terms and conditions of +this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify +the terms of any separate license agreement you may have executed +with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade +names, trademarks, service marks, or product names of the Licensor, +except as required for reasonable and customary use in describing the +origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or +agreed to in writing, Licensor provides the Work (and each +Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied, including, without limitation, any warranties or conditions +of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +PARTICULAR PURPOSE. You are solely responsible for determining the +appropriateness of using or redistributing the Work and assume any +risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, +whether in tort (including negligence), contract, or otherwise, +unless required by applicable law (such as deliberate and grossly +negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, +incidental, or consequential damages of any character arising as a +result of this License or out of the use or inability to use the +Work (including but not limited to damages for loss of goodwill, +work stoppage, computer failure or malfunction, or any and all +other commercial damages or losses), even if such Contributor +has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing +the Work or Derivative Works thereof, You may choose to offer, +and charge a fee for, acceptance of support, warranty, indemnity, +or other liability obligations and/or rights consistent with this +License. However, in accepting such obligations, You may act only +on Your own behalf and on Your sole responsibility, not on behalf +of any other Contributor, and only if You agree to indemnify, +defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason +of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Flora License to your work + +To apply the Flora License to your work, attach the following +boilerplate notice, with the fields enclosed by brackets "[]" +replaced with your own identifying information. (Don't include +the brackets!) The text should be enclosed in the appropriate +comment syntax for the file format. We also recommend that a +file or class name and description of purpose be included on the +same "printed page" as the copyright notice for easier +identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Flora License, Version 1.1 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://floralicense.org/license/ + + 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. + diff --git a/project/NOTICE b/project/NOTICE new file mode 100644 index 0000000..092bc04 --- /dev/null +++ b/project/NOTICE @@ -0,0 +1,4 @@ +Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved. +Except as noted, this software is licensed under Flora License, Version 1.1 +Please, see the LICENSE.Flora file for Flora License, Version 1.1 terms and conditions. + diff --git a/project/config.xml b/project/config.xml new file mode 100644 index 0000000..b6a73ff --- /dev/null +++ b/project/config.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Contacts Exchanger + + + + + + + + + + diff --git a/project/css/style.css b/project/css/style.css new file mode 100644 index 0000000..b459631 --- /dev/null +++ b/project/css/style.css @@ -0,0 +1,144 @@ +.ui-btn-start { + margin: 0px auto; + margin-top: 10px; + padding: 40px 0px 0px 0px; + width: 90%; + height: 50px; + font-size: 16px; +} + +.defaultText { + font-size: 20px; + text-align: center; +} + +.comment { + font-size: 16px; + text-align: center; + color: black; + padding: 0px; + margin: 0px 0px 12px 0px; + white-space: nowrap; + width: 300px; + overflow: hidden; + text-overflow: ellipsis; +} + +#content-start { + display: table; +} + +#comment { + left: 0px; + margin: 0 auto; + right: 0px; + width: inherit; +} + +.box { + margin: 0px; + padding: 0 32px; + width: 296px; + text-align: center; + display: table-cell; + vertical-align: middle; +} + +#waitingBox { + height: inherit; +} + +.gap { + width: 100%; + height: 10px; +} + +#list-choose li a { + white-space: nowrap; + overflow: hidden !important; + text-overflow: ellipsis; + width: 60%; + float: left; +} + +#list-choose li .ui-li-text-sub { + white-space: nowrap; + overflow: hidden !important; + text-overflow: ellipsis; + width: 40%; +} + +#list-choose li.ui-btn-down-s a { + color: black; +} + +#comment-userName { + line-height: 30px; + font-size: 24px; +} + +#comment-name { + overflow: hidden !important; + text-overflow: ellipsis; + width: 90%; + margin-left: 5%; + font-size: 1rem; + font-weight: bold; +} + +#comment-phone { + color: #85837E; + line-height: 20px; +} + +#accept-choose { + width: auto; +} + +.defaultVeryBigText { + font-size: 30px; + margin: 0px; + padding: 0px; + text-align: center; + line-height: 30px; +} + +.defaultCounterText { + margin-top: 10px; + margin-bottom: 10px; + font-size: 100px; + padding: 0px; + text-align: center; + line-height: 100px; +} + +.ui-btn-create span.ui-btn-text { + font-size: .8rem; +} + +#header-start .ui-title, #header-choose .ui-title, #header-contact .ui-title { + font-size: 1.1rem; +} + +/* overwrite web-ui-fw styles for popupwindow button */ +.ui-popupwindow .center_basic_1btn .popup-button-bg .ui-btn { + width: 90%; + height: auto; +} +#list-choose li.selected { + background-color: #ccc; + margin-top: -1px; +} + +.ui-content { + padding: 0; +} + +.ui-btn-back { + visibility:hidden; +} +/* temporary workaround for N_SE-46139 */ +.ui-listview .ui-li > .ui-btn-inner { + padding: 0 0.5909090909090909rem !important; + margin: 0 !important; +} diff --git a/project/icon.png b/project/icon.png new file mode 100644 index 0000000..5934757 Binary files /dev/null and b/project/icon.png differ diff --git a/project/index.html b/project/index.html new file mode 100644 index 0000000..050679e --- /dev/null +++ b/project/index.html @@ -0,0 +1,83 @@ + + + + + + + + + Contacts exchanger + + + + + + + + + + + + + + + + + +
+
+

Contacts exchanger

+
+
+
+

Warning

+
+ If you want to use "Contact Exchanger" you must agree to access + Contacts and NFC by this application. +
+
+ OK +
+
+
+ +
+
+

Contacts list

+
+ +
+
+ +
+
+

+
+ +
+
+ +
+
+

Add contact

+ Save +
+ +
+ + +
+
+
+
+ +
+
+ + + diff --git a/project/js/app.config.js b/project/js/app.config.js new file mode 100644 index 0000000..e0332c3 --- /dev/null +++ b/project/js/app.config.js @@ -0,0 +1,28 @@ +/** + * @class Config + */ +function Config() { + 'use strict'; +} + +(function () { // strict mode wrapper + 'use strict'; + Config.prototype = { + + properties: { + 'templateDir': 'templates', + 'templateExtension': '.tpl' + }, + + /** + * Returns config value + */ + get: function (value, defaultValue) { + + if (this.properties.hasOwnProperty(value)) { + return this.properties[value]; + } + return defaultValue; + } + }; +}()); diff --git a/project/js/app.js b/project/js/app.js new file mode 100644 index 0000000..c38e777 --- /dev/null +++ b/project/js/app.js @@ -0,0 +1,235 @@ +/* + * Copyright 2013 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * 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. + */ + +/*jslint devel: true*/ +/*global $, tizen, Config */ + +var App = null; + +// App instance +var app = null; + +(function () { // strict mode wrapper + 'use strict'; + + /** + * Creates a new application object + * + * @class Application + */ + App = function App() {}; + + App.prototype = { + nfcAdapter: null, + addressBook: null, + started: false, + timeOutHandler: null, + counterState: true, + nfc: null, + + init: function appInit() { + this.config = new Config(); + this.ui = new App.Ui(this); + this.nfc = new App.NFCControl(this); + this.ui.defineEvents(); + this.initAddressBook(this.nfc.startNFC.bind(this.nfc)); + }, + + saveDefaultCard: function saveDefaultCard() { + var elementSelected = $('#list-choose li.selected'); + localStorage.started = true; + localStorage.id = elementSelected.data('id'); + localStorage.caller = elementSelected.data('caller'); + localStorage.firstName = elementSelected.data('firstName'); + localStorage.lastName = elementSelected.data('lastName'); + localStorage.phoneNumber = elementSelected.data('phoneNumber'); + localStorage.vCard = elementSelected.data('vCard'); + this.started = true; + $.mobile.changePage('#start'); + }, + + updateDefaultCard: function updateDefaultCard (contact) { + localStorage.caller = this.ui.prepareCallerName(contact); + localStorage.firstName = contact.name.firstName || ''; + localStorage.lastName = contact.name.lastName || ''; + localStorage.phoneNumber = contact.phoneNumbers[0].number; + localStorage.id = contact.id; + localStorage.vCard = contact.convertToString('VCARD_30'); + }, + + /** + * @param {Array} addressbooks + */ + getAddressBooksSuccess: function getAddressBooksSuccess(addressbooks) { + if (addressbooks.length > 0) { + var self = this, + resetLocalSorage = function () { + // Reset localStorage + localStorage.clear(); + self.started = false; + + // Load start page with temporary content + self.ui.moveToStartPage(); + self.ui.loadTemporaryContent(); + }; + this.addressBook = addressbooks[0]; + + if (localStorage.id) { + try { + this.updateDefaultCard( + this.addressBook.get(localStorage.id) + ); + } catch (err) { + if (err.name === "NotFoundError") { + resetLocalSorage(); + } + } + } + + // Registers to be notified when the address book changes + this.addressBook.addChangeListener({ + oncontactsadded: function(contacts) { + // Refresh if choose page active + self.ui.refreshIfActivePage("choose"); + }, + oncontactsremoved: function(ids) { + // Refresh localStorage if default contact was deleted + if (ids.indexOf(localStorage.id) >= 0) { + resetLocalSorage(); + alert("Your default contact has been removed. Please choose another one."); + } else { + // Refresh if choose page active + self.ui.refreshIfActivePage("choose"); + } + }, + oncontactsupdated: function (contacts) { + var index = contacts.length; + + // check if default contact was updated + while (index--) { + if (contacts[index].id === localStorage.id) { + self.updateDefaultCard(contacts[index]); + break; + } + } + + self.ui.refreshIfActivePage("start"); + } + }); + } else { + console.error('initAddressBook failed'); + } + }, + + /** + * + * @param {Error} e + */ + getAddressBooksError: function getAddressBooksError(e) { + console.error('getAddressBooks() error: ' + e.message); + }, + + initAddressBook: function initAddressBook(callback) { + try { + tizen.contact.getAddressBooks( + function (addressbook) { + this.getAddressBooksSuccess(addressbook) + callback(); + }.bind(this), + this.getAddressBooksError.bind(this) + ); + } catch (e) { + if (e.name === "SecurityError") { + this.ui.showPopupWarning(); + } + console.error('getAddressBooks() error: ' + e.message); + } + }, + + countDown: function countDown(time, obj) { + if (!this.counterState) { + setTimeout(function () { + this.countDown(time, obj); + }.bind(this), 500); + return; + } + + obj.text(time); + if (time > 0) { + if (this.nfc.isPowered()) { + time -= 1; + this.timeOutHandler = setTimeout(function () { + this.countDown(time, obj); + }.bind(this), 1000); + } else { + this.nfc.timeExpired(); + } + } else { + this.nfc.timeExpired(); + } + }, + + saveContact: function saveContact() { + var contact = null, i, empty = true, + data = $('#contact').data('contactsData'); + + for (i in data) { + if (data.hasOwnProperty(i) && empty) { + if (data[i] !== '') { + empty = false; + } + } + } + + if (empty) { + this.ui.moveToStartPage('Cannot add empty contact'); + console.error('saveContact error: empty contact'); + } else { + try { + contact = new tizen.Contact({ + name: new tizen.ContactName({ + caller: data.caller, + firstName: data.first, + lastName: data.last + }), + phoneNumbers: [new tizen.ContactPhoneNumber(data.phone)] + }); + this.addressBook.add(contact); + this.ui.moveToStartPage('New contact added'); + } catch (err) { + this.ui.moveToStartPage('Problem with new contact adding'); + console.error('saveContact error:' + err.name); + } + } + }, + + /** + * Load contacts from the address book and pass the result to a callback + * + * @param {function} successCallback + * @param {function} errorCallback + */ + loadContacts: function loadContacts(successCallback, errorCallback) { + this.addressBook.find(successCallback, errorCallback); + } + + }; + +}()); + +app = new App(); + +$(document).ready(app.init.bind(app)); diff --git a/project/js/app.nfc.card.js b/project/js/app.nfc.card.js new file mode 100644 index 0000000..d6ad313 --- /dev/null +++ b/project/js/app.nfc.card.js @@ -0,0 +1,99 @@ +/*jslint devel: true*/ +/*global $, tizen, App, app */ + +(function () { // strict mode wrapper + 'use strict'; + + /** + * Constructs NFCCard + * @constructor + * @param {NFCControl} nfc + */ + App.NFCCard = function nfc_NFCCard(nfc) { + this.nfc = nfc; + }; + + App.NFCCard.prototype = { + + readMessageErr: function nfc_card_readMessageErr(e) { + console.error('Read error! ' + e.message, e); + this.nfc.timeExpired('Read error! ' + e.message); + }, + + /** + * Read contents from a tag + * @param {NFCTag} tag + */ + sucTagReadAttach: function nfc_card_sucTagReadAttach(tag) { + try { + if (!tag.isSupportedNDEF) { + throw {message: "This tag doesn't support NDEF"}; + } + tag.readNDEF( + this.nfc.readMessage.bind(this.nfc), + this.readMessageErr.bind(this) + ); + } catch (e) { + this.readMessageErr(e); + } + }, + + /** + * Set tag listener + */ + setTagDetectRead: function nfc_card_setTagDetectRead() { + try { + this.nfc.nfcAdapter.setTagListener({ + onattach: this.sucTagReadAttach.bind(this), + ondetach: this.nfc.sucDetach.bind(this.nfc) + }); + } catch (error) { + this.readMessageErr(error); + } + }, + + sucSend: function nfc_card_sucSend() { + this.nfc.timeExpired('Send success!'); + }, + + errSend: function nfc_card_errSend(e) { + console.warn('errSend', e); + this.nfc.timeExpired('Write error! ' + e.message); + }, + + sucTagWriteAttach: function nfc_card_sucTagWriteAttach(tag) { + var newMessage = null, + fullContact = ''; + + try { + fullContact = this.nfc.prepareForNFC(localStorage); + newMessage = this.nfc.phoneNumber2NDEF(fullContact); + if (!tag.isSupportedNDEF) { + throw {message: "This tag doesn't support NDEF"}; + } + tag.writeNDEF( + newMessage, + this.sucSend.bind(this), + this.errSend.bind(this) + ); + } catch (e) { + this.errSend(e); + } + }, + + setTagDetectWrite: function nfc_card_setTagDetectWrite() { + var suc = { + onattach: this.sucTagWriteAttach.bind(this), + ondetach: this.nfc.sucDetach.bind(this.nfc) + }; + + try { + this.nfc.nfcAdapter.setTagListener(suc); + } catch (error) { + console.error(error); + } + } + + }; + +}()); diff --git a/project/js/app.nfc.js b/project/js/app.nfc.js new file mode 100644 index 0000000..4d86ffb --- /dev/null +++ b/project/js/app.nfc.js @@ -0,0 +1,288 @@ +/*jslint devel: true*/ +/*global $, tizen, App, app */ + +(function () { // strict mode wrapper + 'use strict'; + + /** + * Constructs NFCControl + * @constructor + * @param {App} app + */ + App.NFCControl = function NFCControl(app) { + this.app = app; + this.init(); + }; + + App.NFCControl.prototype = { + nfcTarget: null, + nfcStateMemory: false, + + /** + * Initialize NFC application module + */ + init: function nfc_init() { + this.card = new App.NFCCard(this); + this.peer = new App.NFCPeer(this); + this.separator = String.fromCharCode(30); + this.endOfText = String.fromCharCode(3); + }, + /** + * Disable tag/target detection and move to start page + * + * @param {string} monit message text to be displayed + */ + timeExpired: function nfc_timeExpired(monit) { + clearTimeout(this.app.timeOutHandler); + this.unsetTargetDetect(); + this.unsetTagDetect(); + this.app.ui.moveToStartPage(monit); + }, + + /** + * Get the field separator + * + * @returns {string} + */ + getSeparator: function nfc_getSeparator() { + return this.separator; + }, + + /** + * Get the end of text marker + * + * @returns {string} + */ + getEndOfText: function nfc_getEndOfText() { + return this.endOfText; + }, + + createContactString: function createContactString(contact) { + var contactString; + contactString = contact.phoneNumber + this.getSeparator(); + contactString += contact.firstName + this.getSeparator(); + contactString += contact.lastName; + return contactString; + }, + + /** + * + * @param {string|object} contact + * @returns {string} + */ + prepareForNFC: function nfc_prepareForNFC(contact) { + if ($.type(contact) !== 'string') { + contact = this.createContactString(contact); + } + if (contact.length > 31) { + contact = contact.substring(0, 31); + if (contact[29] !== this.getSeparator()) { + contact = contact.substring(0, 30) + this.getEndOfText(); + } + } + return contact; + }, + + resolveData: function nfc_resolveData(value, endOfText) { + if (!value) { + return ''; + } + + endOfText = endOfText || this.getEndOfText(); + + return value.replace(endOfText, '…'); + }, + + resolveContact: function nfc_resolveContact(contactsString) { + var separator = this.getSeparator(), + contactsArray = contactsString.split(separator); + + return { + phone: this.resolveData(contactsArray[0]), + first: this.resolveData(contactsArray[1]), + last: this.resolveData(contactsArray[2]) + }; + }, + + /** + * + * @param {type} record + * @returns {undefined} + */ + fillRecordInfo: function nfc_fillRecordInfo(record) { + try { + var contactsData = this.resolveContact(this.convertNDEF2phoneNumber(record.payload)); + this.app.nfc.displayContact(contactsData); + } catch (error) { + console.error(error); + } + }, + + /** + * + * @param {NDEFMessage} message + */ + readMessage: function nfc_readMessage(message) { + try { + this.fillRecordInfo(message.records[0]); + } catch (e) { + console.error(e.message); + } + }, + + /** + * + * @param {string|object} contact + * @returns {NDEFMessage} + */ + contact2NDEF: function nfc_contact2NDEF(contact) { + var t, a = [], len, i, newMessage = new tizen.NDEFMessage(); + if (typeof contact === 'string') { + t = contact; + } else { + t = contact.convertToString("VCARD_30"); + } + len = t.length; + for (i = 0; i < len; i += 1) { + a[i] = t.charCodeAt(i); + } + newMessage.records[0] = new tizen.NDEFRecordMedia('text/x-vcard', a); + return newMessage; + }, + + /** + * + * @param {string} contact + * @returns {NDEFMessage} + */ + phoneNumber2NDEF: function nfc_phoneNumber2NDEF(contact) { + var phoneNumberArray = [], i, length = contact.length, newMessage = new tizen.NDEFMessage(); + for (i = 0; i < length; i += 1) { + phoneNumberArray.push(contact.charCodeAt(i)); + } + newMessage.records[0] = new tizen.NDEFRecordMedia('text/x-vcard', phoneNumberArray); + return newMessage; + }, + + /** + * + * @param {string} contact + * @returns {string} + */ + convertNDEF2phoneNumber: function nfc_convertNDEF2phoneNumber(contact) { + var i, length = contact.length, phoneNumber = ''; + for (i = 0; i < length; i += 1) { + phoneNumber += String.fromCharCode(contact[i]); + } + return phoneNumber; + }, + + /** + * NFC setPowered success callback + * @returns {undefined} + */ + onPowerOn: function nfc_onPowerOn() { + console.log('Power On succeeded.'); + this.app.started = true; + this.app.ui.loadStartPage(); + }, + + /** + * NFC setPowered error callback + * @param {Error} err + * @returns {undefined} + */ + onPowerOnFails: function nfc_onPowerOnFails(err) { + console.error('Power On error: ' + err.message); + this.app.ui.showPopupWarning(); + }, + + /** + * NFC setPowered success callback + * @returns {undefined} + */ + onPowerOff: function nfc_onPowerOff() { + tizen.application.getCurrentApplication().exit(); + }, + + /** + * NFC setPowered error callback + * @param {Error} err + * @returns {undefined} + */ + onPowerOffFails: function nfc_onPowerOffFails(err) { + console.error('Power Off error', err); + tizen.application.getCurrentApplication().exit(); + }, + + isPowered: function nfc_isPowered() { + return this.nfcAdapter.powered; + }, + + startNFC: function nfc_startNFC() { + try { + this.nfcAdapter = tizen.nfc.getDefaultAdapter(); + if (this.nfcAdapter.powered) { + this.nfcStateMemory = true; + this.onPowerOn(); + return; + } + this.nfcStateMemory = false; + console.log('Turning NFC adapter On...'); + this.nfcAdapter.setPowered(true, this.onPowerOn.bind(this), this.onPowerOnFails.bind(this)); + } catch (e) { + console.error('startNFC problem', e); + this.app.ui.showPopupWarning(); + } + }, + + stopNFC: function nfc_stopNFC() { + try { + if (this.nfcStateMemory) { + this.onPowerOff(); + } else { + this.nfcAdapter.setPowered(false, this.onPowerOff.bind(this), this.onPowerOffFails.bind(this)); + } + } catch (err) { + console.error('setPowered(false) problem', err); + } + }, + + unsetTargetDetect: function nfc_unsetTargetDetect() { + try { + if (this.nfcTarget) { + this.nfcTarget.unsetReceiveNDEFListener(); + this.nfcTarget = null; + } else { + //console.warn("app.nfc.nfcTarget not set"); + } + } catch (error) { + console.error('error: ' + error.message); + } + try { + this.nfcAdapter.unsetPeerListener(); + } catch (e) { + console.error('error: ' + e.message); + } + }, + + unsetTagDetect: function nfc_unsetTagDetect() { + try { + this.nfcAdapter.unsetTagListener(); + } catch (error) { + console.error('error: ' + error.message); + } + }, + + displayContact: function nfc_displayContact(obj) { + clearTimeout(this.app.timeOutHandler); + this.unsetTargetDetect(); + this.unsetTagDetect(); + this.app.ui.moveToContactPage(obj); + }, + + sucDetach: function nfc_sucDetach() { + } + }; + +}()); diff --git a/project/js/app.nfc.peer.js b/project/js/app.nfc.peer.js new file mode 100644 index 0000000..f1999b7 --- /dev/null +++ b/project/js/app.nfc.peer.js @@ -0,0 +1,72 @@ +/*jslint devel: true*/ +/*global $, tizen, App, app */ + +(function () { // strict mode wrapper + 'use strict'; + + /** + * Constructs NFCPeer + * @constructor + * @param {NFCControl} nfc + */ + App.NFCPeer = function (nfc) { + this.nfc = nfc; + }; + + App.NFCPeer.prototype = { + + sucSendToTarget: function nfc_peer_sucSendToTarget() { + }, + + errSendToTarget: function nfc_peer_errSendToTarget(e) { + this.nfc.timeExpired('Send problem! ' + e.message); + }, + + setReceiveFromTarget: function nfc_peer_setReceiveFromTarget() { + try { + if (!this.nfc.nfcTarget) { + console.warn("app.nfc.nfcTarget not set"); + return; + } + this.nfc.nfcTarget.setReceiveNDEFListener( + this.nfc.readMessage.bind(this.nfc) + ); + } catch (error) { + console.error('setReceiveFromTarget error: ' + error.message); + } + }, + + sucTargetAttach: function nfc_peer_sucTargetAttach(target) { + var newMessage = null, + fullContact = this.nfc.prepareForNFC(localStorage); + + this.nfc.nfcTarget = target; + this.setReceiveFromTarget(); + + try { + newMessage = this.nfc.phoneNumber2NDEF(fullContact); + target.sendNDEF( + newMessage, + this.sucSendToTarget.bind(this), + this.errSendToTarget.bind(this) + ); + } catch (e) { + console.error("NDEFMessage problem: " + e.message); + } + }, + + setTargetDetect: function nfc_peer_setTargetDetect() { + var successCallbacks = { + onattach: this.sucTargetAttach.bind(this), + ondetach: this.nfc.sucDetach.bind(this.nfc) + }; + + try { + this.nfc.nfcAdapter.setPeerListener(successCallbacks); + } catch (error) { + console.error(error.message); + } + } + }; + +}()); diff --git a/project/js/app.ui.js b/project/js/app.ui.js new file mode 100644 index 0000000..3f7b1b7 --- /dev/null +++ b/project/js/app.ui.js @@ -0,0 +1,571 @@ +/*jslint devel: true*/ +/*global $, tizen, App, app, localStorage: true, TemplateManager, document, window, setTimeout */ + +App.Ui = null; + +(function () { // strict mode wrapper + 'use strict'; + + App.Ui = function App_Ui(app) { + this.app = app; + this.templateManager = new TemplateManager(app.config); + }; + + App.Ui.prototype = { + prepareCallerName: function ui_prepareCallerName(contact) { + var callerName, firstName, lastName; + + callerName = ''; + firstName = contact.name.firstName; + lastName = contact.name.lastName; + + if (firstName !== '' && firstName !== null) { + callerName = firstName; + } + if (lastName !== '' && lastName !== null) { + if (callerName !== '') { + callerName += ' '; + } + callerName += lastName; + } + if (callerName === '') { + callerName = 'No Name'; + } + return callerName; + }, + + /** + * Show a popup + * @param {string} message + */ + showPopup: function ui_showPopup(message) { + var popup = $("#alertPopup"); + if(!popup.hasClass('ui-popup')) { + popup.popup().trigger('create'); + } + $(".ui-popup-text", popup).text(message); + popup.popup("open", {positionTo: 'window'}); + }, + + closePopup: function ui_closePopup() { + var activePopup = $.mobile.popup.active; + if (activePopup) { + if (activePopup.attr('id') === 'alertPopup') { + activePopup.close(); + } + } + }, + + createListRecord: function ui_createListRecord() { + $.mobile.changePage('#choose'); + }, + + /** + * + * @param {string} text + * @returns {string} + */ + getWaitingContentHtml: function getWaitingContentHtml(text) { + var html; + html += '

'; + html += text; + html += '

'; + + html += '

'; + + return html; + }, + + /** + * + * @param {string} title + * @param {string} text + */ + prepareWaitingPage: function ui_prepareWaitingPage(title, text) { + var waitingBox, waitingContent, + contentTransfer = $('#content-transfer'); + waitingBox = $('
'); + waitingContent = $(this.getWaitingContentHtml(text)); + $('#header-transfer H1').text(title); + contentTransfer.empty(); + waitingBox.append(waitingContent); + contentTransfer.append(waitingBox); + $('#content-start').trigger('create'); + this.app.countDown(10, $('#counter')); + }, + + /** + * @returns {string} + */ + getTemporaryBoxHtml: function ui_getTemporaryBoxHtml() { + return '
'; + }, + + /** + * @returns {string} + */ + showPopupWarning: function ui_showPopupWarning(){ + setTimeout(function(){ + $("#contact-nfc-error").popup("open",{"positionTo":"window"}); + },500); + }, + + getTemporaryBoxContentHtml: function ui_getTemporaryBoxContentHtml() { + return '

' + + 'Default card is not defined yet!
' + + 'Do you want to define it now?' + + '

'; + }, + + loadTemporaryContent: function ui_loadTemporaryContent() { + var temporaryBox, temporaryContent, temporaryButton; + + temporaryBox = $(this.getTemporaryBoxHtml()); + temporaryContent = $(this.getTemporaryBoxContentHtml()); + temporaryButton = $(this.getButtonHtml('Create default card')); + + temporaryButton.on('click', function (event) { + event.preventDefault(); + $.mobile.changePage('#choose'); + }); + + temporaryBox.append(temporaryContent).append(temporaryButton); + + $('#content-start').empty().append(temporaryBox).trigger('create'); + }, + /** + * + * @param {string} text button text + * @returns {string} + */ + getButtonHtml: function ui_getButtonHtml(text) { + return '
' + + text + + '
'; + }, + + /** + * + * @param {string} firstName + * @param {string} lastName + * @returns {string} + */ + getCommentHtml: function ui_getCommentHtml(data) { + var def_name = $('

') + .text(data.caller).html(); + return '

' + + '

Your default contact

' + + '

' + + def_name + '

' + + '

' + + data.phoneNumber + '

' + + '
'; + }, + + + /** + * Change Contact button action + * @event + * @param {Event} event + */ + changeContact: function ui_changeContact(event) { + event.preventDefault(); + $.mobile.changePage('#choose'); + }, + + /** + * @returns {jQuery} + */ + getChangeContactButton: function ui_getChangeContactButton() { + var changeContactButton; + changeContactButton = $(this.getButtonHtml('Change your default contact')); + changeContactButton.on('click', this.changeContact); + return changeContactButton; + }, + + /** + * Read From Card button action + * @event + * @param {Event} event + */ + readFromCard: function ui_readFromCard(event) { + event.preventDefault(); + if (tizen.nfc.getDefaultAdapter().powered) { + try { + $('#transfer').data('option', 'read'); + $.mobile.changePage('#transfer'); + } catch (e) { + console.error(e.message); + } + } else { + $.mobile.changePage('#start'); + alert('Please turn on NFC adapter'); + } + }, + + /** + * @returns {jQuery} + */ + getReadFromCardButton: function ui_getReadFromCardButton() { + var readFromCardButton; + readFromCardButton = $(this.getButtonHtml('Read from card')); + readFromCardButton.on('click', this.readFromCard); + return readFromCardButton; + }, + + /** + * Write To Card button action + * @param {Event} event + */ + writeToCard: function ui_writeToCard(event) { + event.preventDefault(); + if (tizen.nfc.getDefaultAdapter().powered) { + try { + $('#transfer').data('option', 'write'); + $.mobile.changePage('#transfer'); + } catch (e) { + console.error(e.message); + } + } else { + alert('Please turn on NFC adapter'); + } + }, + + /** + * @returns {jQuery} + */ + getWriteToCardButton: function ui_getWriteToCardButton() { + var writeToCardButton; + writeToCardButton = $(this.getButtonHtml('Write to card')); + writeToCardButton.on('click', this.writeToCard); + return writeToCardButton; + }, + + /** + * Communicate With Other Device button action + * @param {type} event + */ + communicateWithOtherDevice: function ui_communicateWithOtherDevice(event) { + event.preventDefault(); + if (tizen.nfc.getDefaultAdapter().powered) { + try { + $('#transfer').data('option', 'communicate'); + $.mobile.changePage('#transfer'); + } catch (e) { + console.error(e.message); + } + } else { + alert('Please turn on NFC adapter'); + } + }, + + /** + * @returns {jQuery} + */ + getCommunicateWithOtherDeviceButton: function ui_getCommunicateWithOtherDeviceButton() { + var communicateWithOtherDeviceButton; + communicateWithOtherDeviceButton = $(this.getButtonHtml('Communicate with another device')); + communicateWithOtherDeviceButton.on('click', this.communicateWithOtherDevice); + return communicateWithOtherDeviceButton; + }, + + loadStartContent: function ui_loadStartContent() { + var startBox, contentStart, gap, comment; + contentStart = $('#content-start'); + startBox = $('
'); + gap = $('
'); + comment = $(this.getCommentHtml(localStorage)); + + contentStart.empty(); + startBox + .append(this.getChangeContactButton()) + .append(gap.clone()) + .append(this.getReadFromCardButton()) + .append(gap.clone()) + .append(this.getWriteToCardButton()) + .append(gap.clone()) + .append(this.getCommunicateWithOtherDeviceButton()) + .prepend(comment); + + contentStart.append(startBox); + contentStart.trigger('create'); + }, + + loadStartPage: function ui_loadStartPage() { + if (localStorage.started === undefined) { + this.loadTemporaryContent(); + } else { + this.loadStartContent(); + } + }, + + /** + * + * @param {string} value + * @param {string} label + * @returns {string} + */ + getLiHtml: function ui_getLiHtml(value, label) { + var html; + html = '
  • ' + + '' + + '' + label + '' + + '' + + ((!value) ? '...' : value) + + '' + + '' + + '
  • '; + return html; + }, + + /** + * + * @param {string} phone + * @param {string} first + * @param {string} last + * @returns {string} + */ + getContactsUlHtml: function ui_getContactsUlHtml(phone, first, last) { + var html; + html = '
      '; + html += this.getLiHtml(first, 'First Name'); + html += this.getLiHtml(last, 'Last Name'); + html += this.getLiHtml(phone, 'Phone'); + html += '
    '; + return html; + }, + + /** + * @param {object} contact + * @returns {string} + */ + getContactsListElement: function ui_getContactsListElement(contact) { + var caller = $('') + .text(contact.caller).html(), + phoneNumber = contact.phoneNumber, + html = + '
  • ' + + '' + caller + + '' + phoneNumber + '' + + '' + + '
  • '; + return html; + }, + + prepareContactsTemplate: function ui_prepareContactsTemplate(phone, first, last) { + $('#content-contact > .ui-scrollview-view') + .empty() + .append(this.getContactsUlHtml(phone, first, last)); + $('#content-contact').trigger('create'); + }, + + contactsCompare: function ui_contactsCompare(a, b) { + if (a.caller < b.caller) { + return -1; + } + if (a.caller > b.caller) { + return 1; + } + return 0; + }, + + createSortedContactArray: function ui_createSortedContactArray(contacts) { + var i, len, sortedContactList = [], contact, phoneNumber; + + for (i = 0, len = contacts.length; i < len; i += 1) { + contact = contacts[i]; + if (contact.phoneNumbers.length === 0) { + phoneNumber = ''; + } else { + phoneNumber = contact.phoneNumbers[0].number; + } + sortedContactList.push({ + caller: this.prepareCallerName(contact), + firstName: contact.name.firstName || '', + lastName: contact.name.lastName || '', + phoneNumber: phoneNumber, + id: contact.id, + vCard: contact.convertToString('VCARD_30'), + contact: contact + }); + } + sortedContactList.sort(this.contactsSort); + + return sortedContactList; + }, + + createSortedContactList: function ui_createSortedContactList(contacts) { + var sortedContactList = this.createSortedContactArray(contacts), + ul = $('
      '), + i, + len, + listElement, + listElementTap, + self = this, + contact; + + listElementTap = function (event) { + event.preventDefault(); + $(this).addClass('selected').siblings().removeClass('selected'); + self.app.saveDefaultCard(); + }; + + for (i = 0, len = sortedContactList.length; i < len; i += 1) { + contact = sortedContactList[i]; + if (contact.phoneNumber !== '') { + listElement = $(this.getContactsListElement(contact)); + listElement + .data('caller', contact.caller) + .data('firstName', contact.firstName) + .data('lastName', contact.lastName) + .data('phoneNumber', contact.phoneNumber) + .data('id', contact.id) + .data('vCard', contact.vCard); + if (localStorage.id === listElement.data('id')) { + listElement.addClass('selected'); + } + ul.append(listElement); + } + } + ul.on('tap taphold click', 'li', listElementTap); + return ul; + }, + + showContactsList: function ui_showContactsList(contacts) { + var ul = this.createSortedContactList(contacts); + $('#content-choose > .ui-scrollview-view').empty().append(ul); + $('#content-choose').trigger('create'); + }, + + moveToStartPage: function ui_moveToStartPage(monit) { + $('#start').data('monit', monit || ''); + $.mobile.changePage('#start'); + }, + + isActivePage: function ui_isActivePage(id) { + return (id === $.mobile.activePage.attr("id")); + }, + + refreshIfActivePage: function ui_refreshIfActivePage(id) { + if (this.isActivePage(id)) { + $.mobile.activePage + .trigger("pagebeforeshow") + .trigger("pageshow"); + } + }, + + moveToContactPage: function ui_moveToContactPage(obj) { + $('#start').data('monit', ''); + $('#contact').data('contactsData', obj); + $.mobile.changePage('#contact'); + }, + + defineEvents: function ui_defineEvents() { + var self = this; + + $('#header-start .ui-btn-back').on('click', function (event) { + event.preventDefault(); + self.app.nfc.stopNFC(); + }); + + $('#header-start').on('click', '.ui-btn-back.ui-focus', function () { + return false; + }); + + $('#footer-contact').on('click', '.ui-btn-back', function (event) { + event.preventDefault(); + $.mobile.changePage('#start'); + }); + + $('#footer-choose').on('click', '.ui-btn-back', function (event) { + event.preventDefault(); + $.mobile.changePage('#start'); + }); + + $('#choose').on('pageshow', function (event) { + self.app.loadContacts(self.showContactsList.bind(self), function (e) { + alert('Cannot load the contacts list: ' + e.message); + console.error(e.message, e); + }); + }); + + $('#contact').on('pageshow', function (event) { + var data = $(this).data('contactsData'); + self.prepareContactsTemplate(data.phone, data.first, data.last); + }); + + $('#save-contact').on('click', function (event) { + event.preventDefault(); + self.app.saveContact(); + }); + + $('#start').on('pagebeforeshow', function () { + if (self.app.started) { + self.loadStartPage(); + } + }); + + $('#start').on('pageshow', function () { + var obj = $(this), monit = obj.data('monit'); + if (monit !== '' && monit !== undefined) { + self.showPopup(obj.data('monit')); + obj.data('monit', ''); + } + }); + + $( "#contact-nfc-error" ).bind({ + popupafterclose: function(){ + tizen.application.getCurrentApplication().exit(); + } + }); + + window.addEventListener('tizenhwkey', function(e) { + if (e.keyName == "back") { + if ($.mobile.popup.active) { + $.mobile.popup.active.close(); + } else if ($.mobile.activePage.attr('id') === 'start') { + tizen.application.getCurrentApplication().exit(); + } else { + self.app.nfc.timeExpired(); + } + } + }); + + document.addEventListener('webkitvisibilitychange', function () { + if(document.webkitVisibilityState === "visible") { + if ($.mobile.activePage.attr('id') === "choose") { + $.mobile.activePage.trigger('pageshow'); + } + app.counterState = true; + } else { + app.counterState = false; + } + }); + + $('#transfer').on('pageshow', function () { + if (tizen.nfc.getDefaultAdapter().powered) { + try { + var option = $(this).data('option'); + if (option === 'read') { + self.prepareWaitingPage('Card to device', 'PUT WIRELESS TAG
      CLOSE TO
      YOUR DEVICE'); + self.app.nfc.card.setTagDetectRead(); + } else if (option === 'write') { + self.prepareWaitingPage('Device to card', 'PUT WIRELESS TAG
      CLOSE TO
      YOUR DEVICE'); + self.app.nfc.card.setTagDetectWrite(); + } else { + self.prepareWaitingPage('Device to device', 'PUT YOUR DEVICE
      CLOSE TO
      OTHER DEVICE'); + self.app.nfc.peer.setTargetDetect(); + } + } catch (e) { + console.error(e.message); + } + } else { + $.mobile.changePage('#start'); + alert('Please turn on NFC adapter'); + } + }); + } + + }; + +}()); diff --git a/project/js/app.ui.templateManager.js b/project/js/app.ui.templateManager.js new file mode 100644 index 0000000..68c6678 --- /dev/null +++ b/project/js/app.ui.templateManager.js @@ -0,0 +1,111 @@ +/*global tizen, $, app */ +/** + * @class TemplateManager + */ +function TemplateManager() { + 'use strict'; + this.init(); +} + +(function () { // strict mode wrapper + 'use strict'; + TemplateManager.prototype = { + + /** + * Template cache + */ + cache: {}, + + /** + * UI module initialisation + */ + init: function init() { + }, + + /** + * Returns template html (from cache) + * @param {string} tplName + * @param {string} tplParams + */ + get: function TemplateManager_get(tplName, tplParams) { + if (this.cache[tplName] !== undefined) { + return this.getCompleted(this.cache[tplName], tplParams); + } + return ''; + }, + + /** + * Load templates to cache + * @param {string} tplNames + * @param {function} onSuccess + */ + loadToCache: function TemplateManager_loadToCache(tplNames, onSuccess) { + var self = this, + cachedTemplates = 0, + tplName, + tplPath; + + if ($.isArray(tplNames)) { + + // for each template + $.each(tplNames, function (index, fileName) { + + // cache template html + if (self.cache[fileName] === undefined) { + tplName = [fileName, app.config.get('templateExtension')].join(''); + tplPath = [app.config.get('templateDir'), tplName].join('/'); + + $.ajax({ + url: tplPath, + cache: true, + dataType: 'html', + async: true, + success: function (data) { + // increase counter + cachedTemplates += 1; + + // save to cache + self.cache[fileName] = data; + + // if all templates are cached launch callback + if (cachedTemplates >= tplNames.length && typeof onSuccess === 'function') { + onSuccess(); + } + }, + error: function (jqXHR, textStatus, errorThrown) { + console.error('templateManagerError: ' + errorThrown); + } + }); + } else { + // template is already cached + cachedTemplates += 1; + // if all templates are cached launch callback + if (cachedTemplates >= tplNames.length && typeof onSuccess === 'function') { + onSuccess(); + } + } + }); + + } + }, + + /** + * Returns template completed by specified params + * @param {string} tplHtml + * @param {string} tplParams + */ + getCompleted: function TemplateManager_getCompleted(tplHtml, tplParams) { + var tplParam, replaceRegExp; + + for (tplParam in tplParams) { + if (tplParams.hasOwnProperty(tplParam)) { + replaceRegExp = new RegExp(['%', tplParam, '%'].join(''), 'g'); + tplHtml = tplHtml.replace(replaceRegExp, tplParams[tplParam]); + } + } + + return tplHtml; + } + }; + +}()); \ No newline at end of file diff --git a/tizen-app-template.xml b/tizen-app-template.xml new file mode 100755 index 0000000..92633c5 --- /dev/null +++ b/tizen-app-template.xml @@ -0,0 +1,12 @@ + + + ContactsExchanger + TIZEN + + description.xml + + + + + + diff --git a/tizen_32.png b/tizen_32.png new file mode 100644 index 0000000..61f35c0 Binary files /dev/null and b/tizen_32.png differ diff --git a/tizen_64.png b/tizen_64.png new file mode 100644 index 0000000..b188083 Binary files /dev/null and b/tizen_64.png differ