Tizen 2.0 Release tizen_2.0 submit/tizen_2.0/20130215.192323
authorHyungKyu Song <hk76.song@samsung.com>
Fri, 15 Feb 2013 15:57:36 +0000 (00:57 +0900)
committerHyungKyu Song <hk76.song@samsung.com>
Fri, 15 Feb 2013 15:57:36 +0000 (00:57 +0900)
30 files changed:
AUTHORS [new file with mode: 0644]
LICENSE.Flora [new file with mode: 0644]
NOTICE.Flora [new file with mode: 0644]
config.xml [new file with mode: 0644]
css/style.css [new file with mode: 0644]
icon.png [new file with mode: 0755]
images/00_winset_Back.png [new file with mode: 0644]
images/etc.png [new file with mode: 0755]
images/folder.png [new file with mode: 0755]
images/img.png [new file with mode: 0755]
images/music.png [new file with mode: 0755]
images/pdf.png [new file with mode: 0755]
images/ppt.png [new file with mode: 0755]
images/text.png [new file with mode: 0755]
images/video.png [new file with mode: 0755]
index.html [new file with mode: 0644]
js/app.clipboard.js [new file with mode: 0644]
js/app.config.js [new file with mode: 0644]
js/app.helpers.js [new file with mode: 0644]
js/app.js [new file with mode: 0644]
js/app.model.js [new file with mode: 0644]
js/app.systemIO.js [new file with mode: 0644]
js/app.ui.js [new file with mode: 0644]
js/app.ui.templateManager.js [new file with mode: 0644]
js/main.js [new file with mode: 0644]
templates/emptyFolder.tpl [new file with mode: 0644]
templates/fileRow.tpl [new file with mode: 0644]
templates/folderRow.tpl [new file with mode: 0644]
templates/levelUpRow.tpl [new file with mode: 0644]
templates/main.tpl [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..a447a9f
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,6 @@
+Pawel Sierszen <p.sierszen at samsung dot com>
+Piotr Wronski <p.wronski at samsung dot com>
+Dariusz Paziewski <d.paziewski at samsung dot com>
+Tomasz Lukawski <t.lukawski at samsung dot com>
+Tomasz Paciorek <t.paciorek at samsung dot com>
+Aniela Rudy-Gawecka <a.rudy-gawec at samsung dot com>
diff --git a/LICENSE.Flora b/LICENSE.Flora
new file mode 100644 (file)
index 0000000..9c95663
--- /dev/null
@@ -0,0 +1,206 @@
+Flora License
+
+Version 1.0, May, 2012
+
+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 Compatibility Definition Document
+and passes the Compatibility Test Suite 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.
+
+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.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://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/NOTICE.Flora b/NOTICE.Flora
new file mode 100644 (file)
index 0000000..fdb699a
--- /dev/null
@@ -0,0 +1,4 @@
+Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
+Except as noted, this software is licensed under Flora License, Version 1.
+Please, see the LICENSE file for Flora License terms and conditions.
+
diff --git a/config.xml b/config.xml
new file mode 100644 (file)
index 0000000..3bc4bb5
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<widget xmlns="http://www.w3.org/ns/widgets" xmlns:tizen="http://tizen.org/ns/widgets" id="http://sample-web-application.tizen.org/file-manager" version="2.1.0" viewmodes="maximized">
+       <tizen:application id="DncjwaRfgh" required_version="1.0"/>
+       <icon src="icon.png"/>
+       <name>FileManager</name>
+       <tizen:privilege name="http://tizen.org/privilege/tizen"/>
+       <tizen:privilege name="http://tizen.org/privilege/content.read"/>
+       <tizen:privilege name="http://tizen.org/privilege/content.write"/>
+       <tizen:privilege name="http://tizen.org/privilege/systeminfo"/>
+       <tizen:privilege name="http://tizen.org/privilege/application.launch"/>
+       <tizen:privilege name="http://tizen.org/privilege/application.read"/>
+       <tizen:privilege name="http://tizen.org/privilege/filesystem.read"/>
+       <tizen:privilege name="http://tizen.org/privilege/filesystem.write"/>
+       <tizen:setting screen-orientation="portrait" context-menu="disable" background-support="enable" encryption="disable" nodisplay="false"/>
+</widget>
diff --git a/css/style.css b/css/style.css
new file mode 100644 (file)
index 0000000..f81279e
--- /dev/null
@@ -0,0 +1,166 @@
+* {
+       margin: 0px;
+       padding: 0px;
+}
+
+body {
+       overflow: hidden;
+}
+
+#fileList {
+       margin: 0;
+}
+
+#mainTitle {
+       width: 260px;
+}
+
+#fileList > li {
+       padding-top: 0.3rem;
+       padding-bottom: 0.3rem;
+       border-top: solid 1px #ddd;
+}
+
+#fileList > li > span.nodename {
+       display: inline-block;
+       position: absolute;
+       line-height: 32px;
+       white-space: nowrap;
+       text-overflow: ellipsis;
+       width: 75%;
+       overflow: hidden;
+       margin-top: 5px;
+}
+
+#fileList > li.gradientBackground > span.nodename {
+       color: #fff !important;
+}
+
+#fileList > li.file img {
+       width: 32px;
+       height: 32px;
+}
+
+#fileList > li.folder img {
+       margin-top: 0.1rem;
+}
+
+#fileList > li.levelUp {
+       padding-left: 47px !important;
+       height: 32px;
+}
+
+.selectAll {
+       padding-left: 10px;
+       display: inline-block;
+}
+
+.selectAll span.ui-icon {
+       top: 40% !important;
+}
+
+.selectAll span.ui-btn-text {
+       padding-left: 1.5rem !important;
+}
+
+#navbar {
+       height: 16px;
+       padding: 2px 10px;
+       font-size: 14px;
+       white-space: nowrap;
+       overflow: hidden;
+       text-overflow: ellipsis;
+       background-color: #EEE;
+       border-top: solid 1px #DDD;
+       direction: rtl;
+       text-align: left;
+}
+
+.ui-pathDiv {
+       position: absolute;
+       top: 49px;
+       left: 0px;
+       right: 0px;
+       bottom: 0px;
+}
+
+#pathDiv {
+       padding: 2px 0px 0px 5px;
+       border: 0px;
+}
+
+#pathDiv .ui-li-text-main {
+       font-size: 18px;
+}
+
+#morePopup td.text {
+       padding: 5px;
+}
+
+.ui-header.ui-bar-s .ui-btn.standard {
+       width: 100%;
+       height: 100%;
+}
+
+.ui-li-1line-bigicon1.ui-li.ui-li-static.ui-body-s.ui-li-has-thumb {
+       padding-left: 0.7rem;
+       padding-right: 0rem;
+}
+
+.my-ui-checkbox {
+       display: inline-block;
+       margin-top: 0rem;
+       margin-right: 0rem;
+       position: relative !important;
+       top: -0.7rem;
+       left: -1.5rem;
+}
+
+ul.ui-listview > li.ui-li-1line-bigicon1 img.ui-li-bigicon {
+       display: inline-block;
+       margin-top: 0rem;
+       margin-right: 0.7rem;
+       position: relative;
+       left: 5px;
+}
+
+.ui-checkbox .ui-btn.ui-btn-icon-left .ui-btn-inner {
+       line-height: 1.1rem;
+       padding: 0 0 0 0rem;
+       width: 30px;
+}
+
+.ui-checkbox .ui-btn.ui-btn-icon-left .ui-btn-inner.ui-btn-hastxt {
+       width: 100%;
+}
+
+.ui-btn-corner-all {
+       -webkit-border-radius: 0px;
+       bordert-radius: 0px;
+}
+
+.ui-content.ui-scrollview-clip > div.ui-scrollview-view {
+       padding: 0px;
+}
+
+input.ui-input-text.new_folder {
+       width: 100%;
+       height: 50px;
+       padding: 0 0 0 .4em;
+}
+
+.gradientBackground {
+       background: -webkit-linear-gradient(top, #5A99BA 0%, #205473 100%) !important; /* from tizen-white */
+}
+
+.hidden {
+       display: none !important;
+}
+
+.vhidden {
+       visibility: hidden !important;
+}
+
+.ui-tabbar a {
+       color: #999 !important;
+}
\ No newline at end of file
diff --git a/icon.png b/icon.png
new file mode 100755 (executable)
index 0000000..983c883
Binary files /dev/null and b/icon.png differ
diff --git a/images/00_winset_Back.png b/images/00_winset_Back.png
new file mode 100644 (file)
index 0000000..780e24e
Binary files /dev/null and b/images/00_winset_Back.png differ
diff --git a/images/etc.png b/images/etc.png
new file mode 100755 (executable)
index 0000000..26748d8
Binary files /dev/null and b/images/etc.png differ
diff --git a/images/folder.png b/images/folder.png
new file mode 100755 (executable)
index 0000000..c8395f5
Binary files /dev/null and b/images/folder.png differ
diff --git a/images/img.png b/images/img.png
new file mode 100755 (executable)
index 0000000..4dd3be3
Binary files /dev/null and b/images/img.png differ
diff --git a/images/music.png b/images/music.png
new file mode 100755 (executable)
index 0000000..449d29d
Binary files /dev/null and b/images/music.png differ
diff --git a/images/pdf.png b/images/pdf.png
new file mode 100755 (executable)
index 0000000..2480d81
Binary files /dev/null and b/images/pdf.png differ
diff --git a/images/ppt.png b/images/ppt.png
new file mode 100755 (executable)
index 0000000..42c1100
Binary files /dev/null and b/images/ppt.png differ
diff --git a/images/text.png b/images/text.png
new file mode 100755 (executable)
index 0000000..c937ef8
Binary files /dev/null and b/images/text.png differ
diff --git a/images/video.png b/images/video.png
new file mode 100755 (executable)
index 0000000..9786439
Binary files /dev/null and b/images/video.png differ
diff --git a/index.html b/index.html
new file mode 100644 (file)
index 0000000..3b69ba6
--- /dev/null
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+       <meta charset="utf-8"/>
+       <meta name="description" content="file manager"/>
+       <title>file manager</title>
+       <script src="/usr/share/tizen-web-ui-fw/latest/js/jquery.js"></script>
+       <script src="/usr/share/tizen-web-ui-fw/latest/js/tizen-web-ui-fw-libs.js"></script>
+       <script src="/usr/share/tizen-web-ui-fw/latest/js/tizen-web-ui-fw.js" data-framework-theme="tizen-white" data-framework-viewport-scale="false"></script>
+       <script type="text/javascript" src="./js/main.js"></script>
+       <link rel="stylesheet" type="text/css" href="./css/style.css"/>
+</head>
+<body>
+       <div data-role="page" data-footer-Exist="false" id="main"></div>
+</body>
+</html>
\ No newline at end of file
diff --git a/js/app.clipboard.js b/js/app.clipboard.js
new file mode 100644 (file)
index 0000000..a944925
--- /dev/null
@@ -0,0 +1,116 @@
+/*jslint browser: true, devel: true */
+/*global $*/
+
+/**
+ * @class Config
+ */
+function Clipboard() {
+       'use strict';
+       this.mode = this.INACTIVE_MODE;
+}
+
+(function () { // strict mode wrapper
+       'use strict';
+       Clipboard.prototype = {
+               /**
+                * Clipboard mode for copying
+                */
+               COPY_MODE_ID: 0,
+
+               /**
+                * Clipboard mode for moving
+                */
+               MOVE_MODE_ID: 1,
+
+               /**
+                * Clipbboard inactive mode
+                */
+               INACTIVE_MODE: -1,
+
+               /**
+                * Clipboard data
+                */
+               data: [],
+
+               /**
+                * Clipboard mode: [copy | move | inactive]
+                */
+               mode: undefined,
+
+               /**
+                * Returns all paths in clipboard
+                * @returns {array}
+                */
+               get: function Clipboard_get() {
+                       return this.data;
+               },
+
+               /**
+                * Add new path to clipboard
+                * @param {array} full path
+                * @returns {number} current length of clipboard objects
+                */
+               add: function Clipboard_add(paths) {
+                       var len = paths.length,
+                               i;
+
+                       // clear clipboard
+                       this.clear();
+                       for (i = 0; i < len; i += 1) {
+                               if (this.has(paths[i]) === false) {
+                                       console.log('Adding file ' + paths[i] + ' to clipboard');
+                                       this.data.push(paths[i]);
+                               }
+                       }
+
+                       return this.data.length;
+               },
+
+               /**
+                * Checks if specified path is already in clipboard
+                * @param {string} full path
+                * @returns {boolean}
+                */
+               has: function Clipboard_has(path) {
+                       console.log('Clipboard_has', path);
+                       return $.inArray(path, this.data) === -1 ? false : true;
+               },
+
+               /**
+                * Clears all clipboard data and reset clipboard mode
+                */
+               clear: function Clipboard_clear() {
+                       console.log('Clipboard_clear');
+                       this.data = [];
+                       this.mode = this.INACTIVE_MODE;
+               },
+
+               /**
+                * Sets clipboard mode
+                * @param {number} mode
+                * @returns {boolean}
+                */
+               setMode: function Clipboard_setMode(mode) {
+                       if ($.inArray(mode, [this.MOVE_MODE_ID, this.COPY_MODE_ID]) === false) {
+                               console.error('Incorrect clipboard mode');
+                               return false;
+                       }
+                       this.mode = mode;
+                       return true;
+               },
+
+               /**
+                * @returns {number} mode Clipboard mode
+                */
+               getMode: function Clipboard_getMode() {
+                       return this.mode;
+               },
+
+               /**
+                * @returns {boolean}
+                */
+               isEmpty: function Clipboard_isEmpty() {
+                       return this.data.length === 0;
+               }
+       };
+}());
diff --git a/js/app.config.js b/js/app.config.js
new file mode 100644 (file)
index 0000000..32b92f5
--- /dev/null
@@ -0,0 +1,30 @@
+/*jslint devel: true */
+
+/**
+ * @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/js/app.helpers.js b/js/app.helpers.js
new file mode 100644 (file)
index 0000000..43687e1
--- /dev/null
@@ -0,0 +1,121 @@
+/*jslint devel: true */
+/*global $ */
+
+/**
+ * @class Helpers
+ */
+function Helpers() {
+       'use strict';
+}
+
+(function () { // strict mode wrapper
+       'use strict';
+       Helpers.prototype = {
+
+               /**
+                * Capitalise the first letter
+                *
+                * @param {string} text
+                * @returns {string}
+                */
+               UCFirst: function Helpers_UCFirst(text) {
+                       return text.charAt(0).toUpperCase() + text.slice(1);
+               },
+
+               /**
+                * @param {string} fileName
+                * @returns {string} extension for specified file name
+                */
+               getFileExtension: function Helpers_getFileExtension(fileName) {
+                       console.log('Helpers_getFileExtension', fileName);
+                       var splittedFileName = fileName.split('.'),
+                               ext = '';
+
+                       if (splittedFileName.length > 1) {
+                               ext = '.' + splittedFileName.pop();
+                       }
+                       return ext;
+               },
+
+               /**
+                * Return icon filename for the given extension.
+                * For example, for '.mp3' returns 'music.png'
+                *
+                * @param {string} ext
+                * @return {string}
+                */
+               resolveFileIcon: function Helpers_resolveFileIcon(ext) {
+                       console.log('Helpers_resolveFileIcon', ext);
+                       switch (ext) {
+                       case '.jpg':
+                               return 'img.png';
+                       case '.png':
+                               return 'img.png';
+                       case '.gif':
+                               return 'img.png';
+                       case '.pdf':
+                               return 'pdf.png';
+                       case '.mp3':
+                               return 'music.png';
+                       case '.mp4':
+                               return 'video.png';
+                       case '.ppt':
+                               return 'ppt.png';
+                       case '.txt':
+                               return 'text.png';
+                       case '.doc':
+                               return 'text.png';
+                       case '.xls':
+                               return 'text.png';
+                       case '.directory':
+                               return 'folder.png';
+                       default:
+                               return 'etc.png';
+                       }
+               },
+
+               /**
+                * Resolve file extension to MIME type
+                *
+                * @param {string} ext File extension
+                * @returns {string}
+                */
+               resolveMimeType: function Helpers_resolveMimeType(ext) {
+                       console.log('Helpers_resolveMimeType', ext);
+                       var mime = '';
+
+                       if (ext === '.jpg' || ext === '.png' || ext === '.gif') {
+                               mime = 'image/*';
+                       } else if (ext === '.mp4' || ext === '.ogv') {
+                               mime = 'video/*';
+                       } else if (ext === '.mp3') {
+                               mime = 'audio/*';
+                       } else if (ext === '.txt' || ext === '.doc' || ext === '.html' || ext === '.ppt' || ext === '.xls' || ext === '.pdf') {
+                               mime = 'text/*';
+                       }
+
+                       return mime;
+               },
+
+               /**
+                * Returns thumbnail URI for specified file
+                * @param {string} fileName
+                * @param {File} node
+                * @returns {string}
+                */
+               getThumbnailURI: function Helpers_getThumbnailURI(fileName, node) {
+                       console.log('Helpers_getThumbnailURI', fileName, node);
+                       var ext = this.getFileExtension(fileName),
+                               thumbnailURI = '';
+
+                       if (!node.thumbnailURIs) {
+                               console.log('getFileListItem: get icon');
+                               thumbnailURI = 'images/' + this.resolveFileIcon(ext);
+                       } else if (node.thumbnailURIs[0] && $.inArray(ext, ['.mp4', '.jpg', '.png', '.gif'])) {
+                               thumbnailURI = node.thumbnailURIs[0];
+                       }
+
+                       return thumbnailURI;
+               }
+       };
+}());
\ No newline at end of file
diff --git a/js/app.js b/js/app.js
new file mode 100644 (file)
index 0000000..08bd63a
--- /dev/null
+++ b/js/app.js
@@ -0,0 +1,244 @@
+/*jslint devel: true */
+/*global tizen, $, app, Ui, Model, Helpers, Config, Clipboard*/
+
+var App = null;
+
+(function () { // strict mode wrapper
+       'use strict';
+
+       /**
+        * Creates a new application object
+        *
+        * @class Application
+        * @constructor
+        */
+       App = function App() {
+       };
+
+       App.prototype = {
+               /**
+                * @type Array
+                */
+               requires: ['js/app.config.js', 'js/app.model.js', 'js/app.ui.js', 'js/app.ui.templateManager.js', 'js/app.systemIO.js', 'js/app.helpers.js', 'js/app.clipboard.js'],
+
+               /**
+                * @type Model
+                */
+               model: null,
+
+               /**
+                * @type Ui
+                */
+               ui: null,
+
+               /**
+                * @type Config
+                */
+               config: null,
+
+               /**
+                * @type SystemIO
+                */
+               systemIO: null,
+
+               /**
+                * @type Helpers
+                */
+               helpers: null,
+
+               /**
+                * @type {string}
+                */
+               currentPath: '',
+
+               /**
+                *
+                */
+               currentDirHandle: null,
+
+               /**
+                * @type {Clipboard}
+                */
+               clipboard: null,
+
+               /**
+                * Initialization
+                */
+               init: function App_init() {
+                       console.log('App_init');
+                       this.config = new Config();
+                       this.model = new Model();
+                       this.ui = new Ui();
+                       this.helpers = new Helpers();
+                       this.clipboard = new Clipboard();
+
+                       this.model.loadInternalStorages(this.initUi.bind(this));
+                       this.addEvents();
+               },
+
+               /**
+                * UI initialization
+                */
+               initUi: function App_initUi() {
+                       console.log('App_initUi');
+                       this.ui.init(this.model.getInternalStorages());
+               },
+
+               /**
+                * Add pages events
+                */
+               addEvents: function App_addEvents() {
+                       console.log('App_addEvents');
+                       var self = this;
+                       document.addEventListener('webkitvisibilitychange', function() { self.refreshCurrentPage(); } );
+               },
+
+               /**
+                * Displays media storages
+                */
+               displayStorages: function App_displayStorages() {
+                       this.ui.displayStorages(this.model.getInternalStorages());
+               },
+
+               /**
+                * Displays specified folder
+                * @param {string} path
+                */
+               displayFolder: function App_displayFolder(path) {
+                       console.log('App_displayFolder', path);
+                       var self = this;
+
+                       // get folder data and push into rendering method
+                       this.model.getFolderData(path, function (dir, nodes) {
+                               // on success
+                               console.log('App_displayFolder success', dir, nodes);
+
+                               // update current path
+                               self.currentPath = path;
+
+                               // update current dir handle
+                               self.currentDirHandle = dir;
+
+                               // display folder UI
+                               self.ui.displayFolder(path, nodes);
+                       });
+               },
+
+               /**
+                * Opens specified file
+                * @params {string} uri File URI
+                */
+               openFile: function App_openFile(uri, fullUri) {
+                       console.log('App_openFile', uri);
+                       var ext = this.helpers.getFileExtension(uri),
+                               mime = this.helpers.resolveMimeType(ext);
+
+                       if (mime !== '') {
+                               this.model.openFile(fullUri, mime);
+                       } else {
+                               console.error('Unsupported mime type', mime);
+                       }
+               },
+
+               /**
+                * Displays parent location
+                */
+               goLevelUp: function App_goLevelUp() {
+                       // split current path and get proper path for parent location
+                       var newPath = this.currentPath.split('/').slice(0, -1).join('/');
+
+                       if (newPath !== '') {
+                               this.displayFolder(newPath);
+                       } else {
+                               this.displayStorages();
+                       }
+               },
+
+               /**
+                * creates new dir in currently viewed dir
+                * @param {string} dirName
+                */
+               createDir: function App_createDir(dirName) {
+                       console.log('App_createDir', dirName);
+
+                       if (this.currentDirPath !== '') {
+                               try {
+                                       this.currentDirHandle.createDirectory(dirName);
+                               } catch (e) {
+                                       console.error('App_createDir error', e);
+                               }
+                               this.refreshCurrentPage();
+                       } else {
+                               alert("you can't create new nodes in main view");
+                       }
+               },
+
+               /**
+                * Triggers refresh current page
+                */
+               refreshCurrentPage: function App_refreshCurrentPage() {
+                       console.log('App_refreshCurrentPage');
+                       if (this.currentPath !== '') {
+                               this.displayFolder(this.currentPath);
+                       } else {
+                               this.displayStorages();
+                       }
+               },
+
+               /**
+                * Deletes nodes with specified paths
+                * @param {string[]} nodePaths
+                */
+               deleteNodes: function App_deleteNodes(nodes) {
+                       console.log('App_deleteNodes', nodes);
+                       this.model.deleteNodes(nodes, this.currentDirHandle, this.ui.removeNodeFromList.bind(this.ui));
+               },
+
+               /**
+                * @param {string[]} filepaths
+                * @param {number} clipboard mode
+                */
+               saveToClipboard: function App_saveToClipboard(paths, mode) {
+                       this.clipboard.add(paths);
+                       this.clipboard.setMode(mode);
+                       this.ui.refreshPasteActionBtn(this.clipboard.isEmpty());
+               },
+
+               /**
+                * Paste nodes from clipboard to current dir
+                */
+               pasteClipboard: function App_pasteClipboard() {
+                       console.log('App_pasteClipboard');
+                       var clipboardData = this.clipboard.get();
+
+                       if (clipboardData.length === 0) {
+                               alert('Clipboard is empty');
+                               return false;
+                       }
+
+                       if (this.clipboard.getMode() === this.clipboard.COPY_MODE_ID) {
+                               this.model.copyNodes(this.currentDirHandle, clipboardData, this.currentPath, this.onPasteClipboardSuccess.bind(this));
+                       } else {
+                               this.model.moveNodes(this.currentDirHandle, clipboardData, this.currentPath, this.onPasteClipboardSuccess.bind(this));
+                       }
+
+                       this.ui.refreshPasteActionBtn(this.clipboard.isEmpty());
+               },
+
+               /**
+                * Handler for paste clipboard success
+                */
+               onPasteClipboardSuccess: function App_onPasteClipboardSuccess() {
+                       console.log('App_onPasteClipboardSuccess');
+                       this.clipboard.clear();
+                       this.refreshCurrentPage();
+               },
+
+               /**
+                * App exit
+                */
+               exit: function App_exit() {
+                       tizen.application.getCurrentApplication().exit();
+               }
+       };
+}());
diff --git a/js/app.model.js b/js/app.model.js
new file mode 100644 (file)
index 0000000..fa1223d
--- /dev/null
@@ -0,0 +1,222 @@
+/*jslint devel: true */
+/*global tizen, SystemIO */
+
+/**
+ * @class Model
+ */
+function Model() {
+       'use strict';
+       this.init();
+}
+
+(function () { // strict mode wrapper
+       'use strict';
+       Model.prototype = {
+
+               /**
+                * @type SystemIO
+                */
+               systemIO: null,
+
+               /**
+                * @type Array
+                */
+               storages: [],
+
+               /**
+                * @type MediaSource
+                */
+               mediaSource: null,
+
+               /**
+                * API module initialisation
+                */
+               init: function Model_init() {
+                       console.log('Model_init');
+                       this.systemIO = new SystemIO();
+                       //this.mediaSource = tizen.mediacontent.getLocalMediaSource();
+               },
+
+               /**
+                * @returns {FileSystemStorage[]} storages
+                */
+               getInternalStorages: function Model_getInternalStorages() {
+                       console.log('Model_getInternalStorages');
+                       return this.storages;
+               },
+
+               /**
+                * Saves storages
+                * @param {function} callback
+                */
+               loadInternalStorages: function Model_loadInternalStorages(onSuccess) {
+                       console.log('Model_loadInternalStorages', onSuccess);
+                       var self = this;
+
+                       this.systemIO.getStorages('INTERNAL', function (storages) {
+                               self.storages = storages;
+                               if (typeof onSuccess === 'function') {
+                                       console.log('Storages loaded successfully');
+                                       onSuccess();
+                               }
+                       });
+               },
+
+               /**
+                * Returns folder data
+                * @param {string} node Node path
+                * @param {function} onSuccess Success callback
+                */
+               getFolderData: function Model_getFolderData(path, onSuccess, onError) {
+                       console.log('Model_getFolderData', path);
+
+                       var onOpenSuccess = function (dir) {
+                               dir.listFiles(
+                                       function (files) {
+                                               console.log('Model_getFolderData listFiles success', files);
+                                               onSuccess(dir, files);
+                                       },
+                                       function (e) {
+                                               console.error('Model_getFolderData listFiles error', e);
+                                       }
+                               );
+                       },
+                               onOpenError = function (e) {
+                                       console.error('Model_getFolderData openDir error', e);
+                               };
+
+                       this.systemIO.openDir(path, onOpenSuccess, onOpenError);
+               },
+
+               /**
+                * Launch a service associated with 'ext' to launch the 'uri'
+                * @param  {string} ext
+                * @param  {string} uri
+                * @returns {ApplicationSevice}
+                */
+               openFile: function Model_openFile(fullUri, mime) {
+                       var serviceReplyCB = {
+                               onsuccess: function (reply) {
+                                       var num = 0;
+                                       for (num = 0; num < reply.data.length; num += 1) {
+                                               console.log('reply.data[' + num + '].key = ' + reply.data[num].key);
+                                               console.log('reply.data[' + num + '].value = ' + reply.data[num].value);
+                                       }
+                               },
+                               onfailure: function () {
+                                       console.log('Launch service failed');
+                               }
+                       };
+
+                       try {
+                               tizen.application.launchAppControl(new tizen.ApplicationControl(
+                                       'http://tizen.org/appcontrol/operation/view',
+                                       fullUri,
+                                       mime
+                               ),
+                                       null,
+                                       function () { },
+                                       function (e) {
+                                               alert('launch sevice failed. reason :' + e.message);
+                                       },
+                                       serviceReplyCB
+                                       );
+                       } catch (e) {
+                               console.error('openFile error:', e);
+                       }
+               },
+
+               /**
+                * @param {File[]} nodes Collection of node objects
+                * @param {File} dir Directory handle
+                * @param {function} onSuccess
+                * @param {function} onError
+                */
+               deleteNodes: function Model_deleteNodes(nodes, dir, onSuccess, onError) {
+                       console.log('Model_deleteNodes', nodes, dir);
+                       var len = nodes.length,
+                               onDeleteNodeSuccess = function (nodeId, isDir) {
+                                       console.log((isDir ? 'Folder' : 'File') + nodeId + ' deleted successfully');
+                                       if (typeof onSuccess === 'function') {
+                                               onSuccess(nodeId);
+                                       }
+                               },
+                               onDeleteNodeError = function (e) {
+                                       console.log('Folder delete error', e);
+                                       if (typeof onError === 'function') {
+                                               onError();
+                                       }
+                               },
+                               i;
+
+                       for (i = 0; i < len; i = i + 1) {
+                               if (nodes[i].folder) {
+                                       dir.deleteDirectory(
+                                               nodes[i].uri,
+                                               true,
+                                               onDeleteNodeSuccess.bind(this, nodes[i].id, true),
+                                               onDeleteNodeError
+                                       );
+                               } else {
+                                       dir.deleteFile(
+                                               nodes[i].uri,
+                                               onDeleteNodeSuccess.bind(this, nodes[i].id, false),
+                                               onDeleteNodeError
+                                       );
+                               }
+                       }
+               },
+
+               /**
+                * Copy specified files to destination path
+                * Overwrites existing files
+                *
+                * @param {File} dir Directory handle
+                * @param {string[]} paths Array with absolute virtual file paths
+                * @param {string} destinationPath
+                * @param {function} onSuccess callback
+                */
+               copyNodes: function Model_copyNodes(dir, paths, destinationPath, onSuccess) {
+                       console.log('Model_copyNodes', dir, paths, destinationPath);
+                       var len = paths.length,
+                               copied = 0,
+                               onCopyNodeSuccess = function () {
+                                       copied += 1;
+                                       if (copied === len) {
+                                               onSuccess();
+                                       }
+                               },
+                               i;
+
+                       for (i = 0; i < len; i = i + 1) {
+                               dir.copyTo(paths[i], destinationPath, true, onCopyNodeSuccess);
+                       }
+               },
+
+               /**
+                * Move specified files to destination path
+                * Overwrites existing files
+                *
+                * @param {File} dir Directory handle
+                * @param {string[]} paths Array with absolute virtual file paths
+                * @param {string} destinationPath
+                * @param {function} onSuccess callback
+                */
+               moveNodes: function Model_moveNodes(dir, paths, destinationPath, onSuccess) {
+                       console.log('Model_moveNodes', dir, paths, destinationPath);
+                       var len = paths.length,
+                               moved = 0,
+                               onMoveNodeSuccess = function () {
+                                       moved += 1;
+                                       if (moved === len) {
+                                               onSuccess();
+                                       }
+                               },
+                               i;
+
+                       for (i = 0; i < len; i = i + 1) {
+                               dir.moveTo(paths[i], destinationPath, true, onMoveNodeSuccess);
+                       }
+               }
+       };
+}());
diff --git a/js/app.systemIO.js b/js/app.systemIO.js
new file mode 100644 (file)
index 0000000..41c6c96
--- /dev/null
@@ -0,0 +1,247 @@
+/*jslint devel: true */
+/*global tizen, localStorage */
+
+/**
+ * @class SystemIO
+ */
+function SystemIO() {
+       'use strict';
+}
+
+(function () { // strict mode wrapper
+       'use strict';
+       SystemIO.prototype = {
+               /**
+                * Creates new empty file in specified location
+                *
+                * @param {File} directoryHandle
+                * @param {string} fileName
+                */
+               createFile: function SystemIO_createFile(directoryHandle, fileName) {
+                       console.log('SystemIO_createFile', directoryHandle, fileName);
+
+                       try {
+                               return directoryHandle.createFile(fileName);
+                       } catch (e) {
+                               console.error('SystemIO_createFile error:', e);
+                               return false;
+                       }
+               },
+
+               /**
+                * Writes content to file stream
+                *
+                * @param {File} file handler
+                * @param {string} file content
+                * @param {function} on success callback
+                * @param {string} content encoding
+                */
+               writeFile: function SystemIO_writeFile(fileHandle, fileContent, onSuccess, onError, contentEncoding) {
+                       console.log('SystemIO_writeFile', fileHandle, fileContent.length, contentEncoding);
+                       onError = onError || function () {};
+
+                       fileHandle.openStream('w', function (fileStream) {
+                               console.log('SystemIO_writeFile:_onOpenStreamSuccess', fileStream);
+                               if (contentEncoding === 'base64') {
+                                       fileStream.writeBase64(fileContent);
+                               } else {
+                                       fileStream.write(fileContent);
+                               }
+
+                               fileStream.close();
+
+                               // launch onSuccess callback
+                               if (typeof onSuccess === 'function') {
+                                       onSuccess();
+                               }
+                       }, onError, 'UTF-8');
+               },
+
+               /**
+                * Opens specified location
+                *
+                * @param {string} directory path
+                * @param {function} on success callback
+                * @param {function} on error callback
+                * @param {string} mode
+                */
+               openDir: function SystemIO_openDir(directoryPath, onSuccess, onError, openMode) {
+                       console.log('SystemIO_openDir', directoryPath, openMode);
+                       openMode = openMode || 'rw';
+                       onSuccess = onSuccess || function () {};
+
+                       try {
+                               tizen.filesystem.resolve(directoryPath, onSuccess, onError, openMode);
+                       } catch (e) {
+                               console.log('SystemIO_openDir error:' + e.message);
+                       }
+               },
+
+               /**
+                * Parse specified filepath and returns data parts
+                *
+                * @param {string} filePath
+                * @returns {array}
+                */
+               getPathData: function SystemIO_getPathData(filePath) {
+                       console.log('SystemIO_getPathData', filePath);
+                       var path = {
+                               originalPath: filePath,
+                               fileName: '',
+                               dirName: ''
+                       },
+                               splittedPath = filePath.split('/');
+
+                       path.fileName = splittedPath.pop();
+                       path.dirName = splittedPath.join('/') || '/';
+
+                       return path;
+               },
+
+               /**
+                * Save specified content to file
+                *
+                * @param {string} file path
+                * @param {string} file content
+                * @param {string} file encoding
+                */
+               saveFileContent: function SystemIO_saveFileContent(filePath, fileContent, onSaveSuccess, fileEncoding) {
+                       console.log('SystemIO_saveFileContent', filePath, fileContent.length, fileEncoding);
+                       var pathData = this.getPathData(filePath),
+                               self = this,
+                               fileHandle;
+
+                       function onOpenDirSuccess(dir) {
+                               console.log('SystemIO_saveFileContent:_onOpenDirSuccess', dir);
+                               // create new file
+                               fileHandle = self.createFile(dir, pathData.fileName);
+                               if (fileHandle !== false) {
+                                       // save data into this file
+                                       self.writeFile(fileHandle, fileContent, onSaveSuccess, false, fileEncoding);
+                               }
+                       }
+
+                       // open directory
+                       this.openDir(pathData.dirName, onOpenDirSuccess);
+               },
+
+               /**
+                * Deletes node with specified path
+                *
+                * @param {string} node path
+                * @param {function} success callback
+                */
+               deleteNode: function SystemIO_deleteNode(nodePath, onSuccess) {
+                       console.log('SystemIO_deleteNode', nodePath);
+                       var pathData = this.getPathData(nodePath),
+                               self = this;
+
+                       function onDeleteSuccess() {
+                               console.log('SystemIO_deleteNode:_onDeleteSuccess');
+                               onSuccess();
+                       }
+
+                       function onDeleteError(e) {
+                               console.log('SystemIO_deleteNode:_onDeleteError', e);
+                       }
+
+                       function onOpenDirSuccess(dir) {
+                               console.log('SystemIO_deleteNode:_onOpenDirSuccess', dir);
+                               var onListFiles = function (files) {
+                                       console.log('SystemIO_deleteNode:_onListFiles', files);
+                                       if (files.length > 0) {
+                                               // file exists;
+                                               if (files[0].isDirectory) {
+                                                       self.deleteDir(dir, files[0].fullPath, onDeleteSuccess, onDeleteError);
+                                               } else {
+                                                       self.deleteFile(dir, files[0].fullPath, onDeleteSuccess, onDeleteError);
+                                               }
+                                       } else {
+                                               onDeleteSuccess();
+                                       }
+                               };
+
+                               // check file exists;
+                               dir.listFiles(onListFiles, function (e) {
+                                       console.error(e);
+                               }, {
+                                       name: pathData.fileName
+                               });
+                       }
+
+                       this.openDir(pathData.dirName, onOpenDirSuccess, function (e) {
+                               console.error('openDir error:' + e.message);
+                       });
+               },
+
+               /**
+                * Deletes specified file
+                *
+                * @param {File} dir
+                * @param {string} file path
+                * @param {function} delete success callback
+                * @param {function} delete error callback
+                */
+               deleteFile: function SystemIO_deleteFile(dir, filePath, onDeleteSuccess, onDeleteError) {
+                       console.log('SystemIO_deleteFile', filePath);
+                       try {
+                               dir.deleteFile(filePath, onDeleteSuccess, onDeleteError);
+                       } catch (e) {
+                               console.error('SystemIO_deleteFile error:' + e.message);
+                               return false;
+                       }
+               },
+
+               /**
+                * Deletes specified directory
+                *
+                * @param {File} dir
+                * @param {string} dir path
+                * @param {function} delete success callback
+                * @param {function} delete error callback
+                * @returns {boolean}
+                */
+               deleteDir: function SystemIO_deleteDir(dir, dirPath, onDeleteSuccess, onDeleteError) {
+                       console.log('SystemIO_deleteDir', dir, dirPath);
+                       try {
+                               dir.deleteDirectory(dirPath, false, onDeleteSuccess, onDeleteError);
+                       } catch (e) {
+                               console.error('SystemIO_deleteDir error:' + e.message);
+                               return false;
+                       }
+
+                       return true;
+               },
+
+               /**
+                * @param {string} storage type
+                */
+               getStorages: function SystemIO_getStorages(type, onSuccess) {
+                       console.log('SystemIO_getStorages', type);
+                       try {
+                               tizen.filesystem.listStorages(function (storages) {
+                                       console.log('...listStorages success', storages);
+                                       var tmp = [],
+                                               len = storages.length,
+                                               i;
+
+                                       if (type !== undefined) {
+                                               for (i = 0; i < len; i += 1) {
+                                                       if (storages[i].type === 0 || storages[i].type === type) {
+                                                               tmp.push(storages[i]);
+                                                       }
+                                               }
+                                       } else {
+                                               tmp = storages;
+                                       }
+
+                                       if (typeof onSuccess === 'function') {
+                                               onSuccess(tmp);
+                                       }
+                               });
+                       } catch (e) {
+                               console.error('SystemIO_getStorages error:', e);
+                       }
+               }
+       };
+}());
\ No newline at end of file
diff --git a/js/app.ui.js b/js/app.ui.js
new file mode 100644 (file)
index 0000000..f931c02
--- /dev/null
@@ -0,0 +1,623 @@
+/*jslint devel: true */
+/*global $, app, TemplateManager, Helpers */
+
+/**
+ * @class Ui
+ */
+function Ui() {
+       'use strict';
+}
+
+(function () { // strict mode wrapper
+       'use strict';
+       Ui.prototype = {
+               /**
+                * UI edit mode
+                * @type {boolean}
+                */
+               editMode: false,
+
+               /**
+                * @type {bool} block taps until the page change is completed
+                */
+               nodeTapBlock: false,
+
+               /**
+                * @type {TemplateManager}
+                */
+               templateManager: null,
+
+               /**
+                * @type Helpers
+                */
+               helpers: null,
+
+               /**
+                * @const {number}
+                */
+               PATH_DIV_HEIGHT: 20,
+
+               /**
+                * @const {number}
+                */
+               SELECT_ALL_HEIGHT: 32,
+
+               /**
+                * @const {number} header height, set on domReady
+                */
+               HEADER_HEIGHT: 53,
+
+               /**
+                * name of row gradient class
+                */
+               CSS_GRADIENT_CLASS: 'gradientBackground',
+
+               /**
+                * Standard tabbar actions
+                * @type {number}
+                */
+               STD_TABBAR_EDIT_ACTION: 0,
+               STD_TABBAR_MORE_ACTION: 1,
+               STD_TABBAR_EXIT_ACTION: 2,
+
+               /**
+                * Edit tabbar actions
+                * @type {number}
+                */
+               EDIT_TABBAR_DELETE_ACTION: 0,
+               EDIT_TABBAR_MOVE_ACTION: 1,
+               EDIT_TABBAR_COPY_ACTION: 2,
+               EDIT_TABBAR_CANCEL_ACTION: 3,
+
+               /**
+                * UI Initialization
+                */
+               init: function Ui_init(storages) {
+                       console.log('Ui_init', storages);
+                       this.templateManager = new TemplateManager();
+                       this.helpers = new Helpers();
+                       // Disable text selection
+                       $.mobile.tizen.disableSelection(document);
+                       $(document).ready(this.initDom.bind(this, storages));
+               },
+
+               initDom: function Ui_initDom(storages) {
+                       console.log('Ui_initDom', storages);
+                       var self = this;
+
+                       this.templateManager.loadToCache(['main', 'fileRow', 'folderRow', 'levelUpRow', 'emptyFolder'], function () {
+                               $('#main').append($(self.templateManager.get('main')).children()).trigger('pagecreate');
+                               self.addEvents();
+                               self.displayStorages(storages);
+                       });
+               },
+
+               /**
+                * Add UI events
+                */
+               addEvents: function Ui_addEvents() {
+                       console.log('Ui_addEvents');
+                       var self = this;
+                       // touch events for all nodes
+                       $('ul#fileList')
+                               .on('tap', 'li.levelUp', function () {
+                                       if (self.editMode === true) {
+                                               self.handleCancelEditAction();
+                                       }
+                                       app.goLevelUp();
+                               })
+                               .on('tap', 'li.node', function (e) {
+                                       self.handleNodeClick($(this), true);
+                               })
+                               .on('change', 'input[type=checkbox]', function (e) {
+                                       self.handleNodeClick($(this).closest('li.node'), false);
+                               })
+                               .on('touchstart', 'li', function (event) {
+                                       $(this).addClass(self.CSS_GRADIENT_CLASS);
+                               })
+                               .on('touchend touchmove', 'li', function (event) {
+                                       $(this).removeClass(self.CSS_GRADIENT_CLASS);
+                               });
+
+                       $('.selectAll input').on('change', this.handleSelectAllChange.bind(this));
+
+                       // navbar
+                       $('#navbar').on('tap', 'span', function () {
+                               var uri = $(this).attr('uri');
+                               if (uri === 'home') {
+                                       app.displayStorages();
+                               } else {
+                                       app.displayFolder(uri);
+                               }
+                       });
+
+                       // level up
+                       $('#levelUpBtn').on('tap', app.goLevelUp.bind(app));
+
+                       $('#homeBtn').on('tap', app.displayStorages.bind(app));
+
+                       // edit action
+                       $('#editActionBtn').on('tap', this.handleEditAction.bind(this));
+
+                       // delete action
+                       $('#deleteActionBtn').on('tap', this.handleDeleteAction.bind(this));
+
+                       // cancel edit
+                       $('#cancelActionBtn').on('tap', this.handleCancelEditAction.bind(this));
+
+                       // copy action
+                       $('#copyActionBtn').on('tap', this.handleCopyAction.bind(this));
+
+                       // move action
+                       $('#moveActionBtn').on('tap', this.handleMoveAction.bind(this));
+
+                       // paste action
+                       $('a#pasteActionBtn').on('tap', app.pasteClipboard.bind(app));
+
+                       // exit
+                       $('.ui-myExit').on('tap', app.exit);
+
+                       // add folder popup actions
+                       $('#addFolderPopup').on("popupafterclose", function () {
+                               // clear input value
+                               $('#newFolderName').val('New folder');
+                       });
+
+                       $('#newFolderName').on('tap', function () {
+                               if ($(this).attr('value') === 'New folder') {
+                                       $(this).attr('value', '');
+                               }
+                       });
+
+                       $('#cancelNewFolder').on('tap', function () {
+                               $('#addFolderPopup').popup('close');
+                               $('#morePopup').popupwindow('close');
+                       });
+
+                       $('#saveNewFolder').on('tap', function () {
+                               var folderName = $('#newFolderName').val().trim();
+                               $('#addFolderPopup').popup('close');
+                               $('#morePopup').popupwindow('close');
+
+                               if (folderName !== '') {
+                                       app.createDir(folderName);
+                               } else {
+                                       alert("Wrong name of folder");
+                               }
+                       });
+
+                       $('#newFolderActionBtn, #pasteActionBtn').on('tap', function (e) {
+                               setTimeout(function () {
+                                       $('#morePopup').popupwindow('close');
+                               }, 700);
+                       });
+
+               },
+
+               /**
+                * Handler for node click
+                * @param {File} node
+                * @param {boolean} toggleCheckbox
+                */
+               handleNodeClick: function Ui_handleNodeClick(node, toggleCheckbox) {
+                       console.log('Ui_handleNodeClick', node);
+                       if (this.editMode === true) {
+                               //if edit mode is on toggle checkbox state
+                               if (toggleCheckbox === true) {
+                                       this.toggleCheckBoxState(node); // select the checkbox
+                               }
+
+                               this.refreshSelectAllStatus();
+
+                               if ($('ul#fileList input:checkbox:checked').length > 0) {
+                                       this.enableControlBarButtons($('.editTabbar'), [this.EDIT_TABBAR_DELETE_ACTION, this.EDIT_TABBAR_COPY_ACTION, this.EDIT_TABBAR_MOVE_ACTION]);
+                               } else {
+                                       this.disableControlBarButtons($('.editTabbar'), [this.EDIT_TABBAR_DELETE_ACTION, this.EDIT_TABBAR_COPY_ACTION, this.EDIT_TABBAR_MOVE_ACTION]);
+                               }
+                       } else if (node.hasClass('folder')) {
+                               // otherwise display folder
+                               app.displayFolder(node.attr('uri'));
+                       } else {
+                               // file
+                               app.openFile(node.attr('uri'), node.attr('fullUri'));
+                       }
+               },
+
+               /**
+                * Handler for edit action
+                */
+               handleEditAction: function Ui_handleEditAction() {
+                       console.log('Ui_handleEditAction');
+                       this.editMode = true;
+                       $('.standardTabbar').hide();
+                       $('div.editTabbar').show();
+                       this.disableControlBarButtons($('div.editTabbar'), [this.EDIT_TABBAR_DELETE_ACTION, this.EDIT_TABBAR_COPY_ACTION, this.EDIT_TABBAR_MOVE_ACTION]);
+                       this.showEditCheckBoxes();
+               },
+
+               /**
+                * Handler for cancel edit action
+                */
+               handleCancelEditAction: function Ui_handleCancelEditAction() {
+                       console.log('Ui_handleCancelEditAction');
+                       $('div.editTabbar').hide();
+                       $('.standardTabbar').show();
+                       this.hideEditCheckBoxes();
+               },
+
+               /**
+                * Handler for delete action
+                */
+               handleDeleteAction: function Ui_handleDeleteAction() {
+                       console.log('Ui_handleDeleteAction');
+                       var nodesToDelete = [],
+                               $rowElement;
+
+                       $('ul#fileList input:checkbox:checked').each(function (index) {
+                               $rowElement = $(this).closest('li');
+                               nodesToDelete.push({
+                                       id: $rowElement.attr('id'),
+                                       uri: $rowElement.attr('uri'),
+                                       name: $rowElement.attr('label'),
+                                       folder: $rowElement.hasClass('folder')
+                               });
+                       });
+
+                       if (nodesToDelete.length > 0 && confirm('Selected nodes will be deleted. Are you sure?')) {
+                               app.deleteNodes(nodesToDelete);
+                       }
+               },
+
+               /**
+                * Handler for copy action
+                */
+               handleCopyAction: function Ui_handleCopyAction() {
+                       console.log('Ui_handleCopyAction');
+                       var paths = [];
+                       if (this.editMode === true) {
+                               $('ul#fileList input:checkbox:checked').each(function (index) {
+                                       paths.push($(this).closest('li').attr('uri'));
+                               });
+                               app.saveToClipboard(paths, app.clipboard.COPY_MODE_ID);
+                       }
+               },
+
+               /**
+                * Handler for move action
+                */
+               handleMoveAction: function Ui_handleMoveAction() {
+                       console.log('Ui_handleMoveAction');
+                       var paths = [];
+                       if (this.editMode === true) {
+                               $('ul#fileList input:checkbox:checked').each(function (index) {
+                                       paths.push($(this).closest('li').attr('uri'));
+                               });
+                               app.saveToClipboard(paths, app.clipboard.MOVE_MODE_ID);
+                       }
+               },
+
+               /**
+                * Handler for paste action
+                */
+               handlePasteAction: function Ui_handlePasteAction() {
+                       console.log('Ui_handlePasteAction');
+               },
+
+               /**
+                * @param {FileSystemStorage[]} nodes Storage elements
+                */
+               displayStorages: function Ui_displayStorages(nodes) {
+                       console.log('Ui_displayStorages', nodes, nodes.length);
+                       var len = nodes.length,
+                               listElements = [],
+                               nodeName,
+                               listTemplate = '',
+                               i;
+
+                       this.updateNavbar('');
+
+                       for (i = 0; i < len; i = i + 1) {
+                               nodeName = nodes[i].label.trim();
+                               if (nodeName !== '' && (nodes[i].type === 0 || nodes[i].type === 'INTERNAL') && nodeName.indexOf('wgt-') === -1) {
+                                       listElements.push(this.templateManager.get('folderRow', {
+                                               id: i,
+                                               name: nodeName,
+                                               uri: nodeName,
+                                               fullUri: nodeName
+                                       }));
+                               }
+                       }
+
+                       $('#levelUpBtn').addClass('vhidden');
+                       $('#homeBtn').addClass('vhidden');
+
+                       $('#editActionBtn').addClass('vhidden');
+                       $('#moreActionBtn').addClass('vhidden');
+                       $('h1#mainTitle').html('Media');
+
+                       // update file list
+                       $('#fileList').empty();
+                       listTemplate = listElements.join('');
+                       $(listTemplate).appendTo('#fileList');
+                       // reset scrollview position
+                       $('#main .ui-scrollview-view').css('-webkit-transform','none');
+                       $('#fileList')
+                               .trigger("refresh");
+
+                       this.resetDefaultCheckBoxLabelEvents();
+                       this.hideSelectAllArea();
+                       this.handleCancelEditAction();
+               },
+
+               /**
+                * renders node list for folder
+                * @param {File[]} nodes
+                */
+               displayFolder: function Ui_displayFolder(folderName, nodes) {
+                       console.log('Ui_displayFolder', nodes, nodes.length);
+                       var len = nodes.length,
+                               listElements = [this.templateManager.get('levelUpRow')],
+                               nodeName,
+                               i;
+
+                       // update title
+                       this.updateTitle(folderName);
+                       // update navbar
+                       this.updateNavbar(folderName);
+
+                       // render nodes
+                       for (i = 0; i < len; i = i + 1) {
+                               nodeName = nodes[i].name.trim();
+                               console.log('node:', nodeName);
+                               if (nodeName !== '') {
+                                       if (nodes[i].isDirectory) {
+                                               // folder
+                                               listElements.push(this.templateManager.get('folderRow', {
+                                                       id: i,
+                                                       name: nodeName,
+                                                       uri: nodes[i].fullPath,
+                                                       fullUri: nodes[i].toURI()
+                                               }));
+                                       } else {
+                                               // file
+                                               listElements.push(this.templateManager.get('fileRow', {
+                                                       id: i,
+                                                       name: nodeName,
+                                                       uri: nodes[i].fullPath,
+                                                       fullUri: nodes[i].toURI(),
+                                                       thumbnailURI: this.helpers.getThumbnailURI(nodeName, nodes[i])
+                                               }));
+                                       }
+                               }
+                       }
+
+                       if (listElements.length === 1) {
+                               // set content for empty folder
+                               listElements.push(this.templateManager.get('emptyFolder'));
+                       }
+
+                       $('#levelUpBtn').removeClass('vhidden');
+                       $('#homeBtn').removeClass('vhidden');
+                       $('#editActionBtn').removeClass('vhidden');
+                       $('#moreActionBtn').removeClass('vhidden');
+                       this.hideSelectAllArea();
+
+                       // update file list
+                       $('#fileList').html(listElements.join(''))
+                               .trigger('refresh')
+                               .trigger('create');
+               },
+
+               /**
+                * Toggle a checkbox associated with a given list element
+                * @param {jQuery} listElement
+                */
+               toggleCheckBoxState: function Ui_toggleCheckBoxState(listElement) {
+                       console.log('Ui_toggleCheckBoxState', listElement);
+                       var checkboxInput = null,
+                               checkboxesInputChecked = null,
+                               editTabbar = null;
+
+                       checkboxInput = listElement.find('form > div.ui-checkbox input');
+                       checkboxInput
+                               .attr('checked', !checkboxInput.attr('checked'))
+                               .data('checkboxradio').refresh();
+               },
+
+               /**
+                * Shows item checkboxes and topbar with select all option
+                */
+               showEditCheckBoxes: function Ui_showEditCheckBoxes() {
+                       console.log('Ui_showEditCheckBoxes');
+                       var self = this;
+
+                       this.showSelectAllArea();
+
+                       $('ul#fileList > li').animate({paddingLeft: '2rem'}, 500, 'swing', function () {
+                               self.editMode = true;
+                               $('.my-ui-checkbox').removeClass('hidden');
+                       });
+               },
+
+               /**
+                * Hides item checkboxes and topbar with select all option
+                * All checkboxes are auto uncheked
+                */
+               hideEditCheckBoxes: function Ui_hideEditCheckBoxes() {
+                       console.log('Ui_hideEditCheckBoxes');
+                       var self = this;
+
+                       this.hideSelectAllArea(); // hide select all option topbar
+
+                       $('ul#fileList > li').animate({paddingLeft: '0'}, 200, 'swing', function () {
+                               self.editMode = false;
+                               $('.my-ui-checkbox').addClass('hidden');
+                               $.mobile.activePage.page('refresh');
+                       });
+
+                       // uncheck all checkboxes
+                       $('ul#fileList input[type=checkbox]').each(function (index) {
+                               $(this).attr('checked', false);
+                               //$(this).data('checkboxradio').refresh();      // element undefined
+                       });
+
+                       //uncheck select all input
+                       $('.ui-header .selectAll .ui-checkbox input')
+                               .attr('checked', false)
+                               .data('checkboxradio')
+                               .refresh();
+               },
+
+               /**
+                * Shows topbar with select all option
+                */
+               showSelectAllArea: function Ui_showSelectAllArea() {
+                       console.log('showSelectAllArea');
+                       $('.selectAll').show();
+                       $.mobile.activePage.page('refresh');
+               },
+
+               /**
+                * Hides topbar with select all option
+                */
+               hideSelectAllArea: function Ui_hideSelectAllArea() {
+                       console.log('hideSelectAllArea');
+                       $('.selectAll').hide();
+                       $.mobile.activePage.page('refresh');
+               },
+
+               /**
+                * Enable specified options for tabbar
+                * @param {object} tabbar
+                * @param {array} options to enable
+                */
+               enableControlBarButtons: function Ui_enableControlBarButtons(tabbar, enableOptions) {
+                       console.log('Ui_enableControlBarButtons', tabbar, enableOptions);
+                       var i = 0,
+                               len = enableOptions.length;
+
+                       for (i = 0; i < len; i += 1) {
+                               tabbar.tabbar('enable', enableOptions[i]);
+                       }
+               },
+
+               /**
+                * Disable specified options for tabbar
+                * @param {object} controlbar
+                * @param {array} options to enable
+                */
+               disableControlBarButtons: function Ui_disableControlBarButtons(tabbar, disableOptions) {
+                       console.log('Ui_disableControlBarButtons', tabbar, disableOptions);
+                       var i = 0,
+                               len = disableOptions.length;
+
+                       for (i = 0; i < len; i += 1) {
+                               tabbar.tabbar('disable', disableOptions[i]);
+                       }
+               },
+
+               /**
+                * @param {string} path
+                */
+               updateTitle: function Ui_updateTitle(path) {
+                       console.log('Ui_updateTitle', path);
+                       var regexp = new RegExp('([^\/])+$', 'g'),
+                               match = path.match(regexp),
+                               lastDir = match[0] || '(dir)';
+                       $('h1#mainTitle').html(lastDir);
+               },
+
+               /**
+                * @param {string} path
+                */
+               updateNavbar: function Ui_updateNavbar(path) {
+                       console.log('Ui_updateNavbar', path);
+                       var html = ['<span uri="home">Media</span>'],
+                               splitted,
+                               len,
+                               i;
+
+                       if (typeof path === 'string' && path !== '') {
+                               splitted = path.split('/');
+                               len = splitted.length;
+
+                               for (i = 0; i < len; i = i + 1) {
+                                       html.push('<span uri="' + splitted.slice(0, i + 1).join('/') + '">' + splitted[i] + '</span>');
+                               }
+                       }
+                       $('#navbar').html(html.join(' > '));
+               },
+
+               handleSelectAllChange: function Ui_handleSelectAllChange() {
+                       console.log('Ui_handleSelectAllChange');
+                       var $selectAllInput = $('.ui-header .selectAll .ui-checkbox input');
+                       $selectAllInput.data('checkboxradio').refresh();
+
+                       if ($selectAllInput.is(':checked')) {
+                               this.enableControlBarButtons($('.editTabbar'), [this.EDIT_TABBAR_DELETE_ACTION, this.EDIT_TABBAR_COPY_ACTION, this.EDIT_TABBAR_MOVE_ACTION]);
+
+                               // check all checkboxes
+                               $('ul#fileList input[type=checkbox]').each(function (index) {
+                                       $(this).attr('checked', true);
+                                       $(this).data('checkboxradio').refresh();
+                               });
+                       } else {
+                               this.disableControlBarButtons($('.editTabbar'), [this.EDIT_TABBAR_DELETE_ACTION, this.EDIT_TABBAR_COPY_ACTION, this.EDIT_TABBAR_MOVE_ACTION]);
+
+                               $('ul#fileList input[type=checkbox]').each(function (index) {
+                                       $(this).attr('checked', false);
+                                       $(this).data('checkboxradio').refresh();
+                               });
+                       }
+               },
+
+               /**
+                *
+                */
+               refreshSelectAllStatus: function Ui_refreshSelectAllStatus() {
+                       console.log('Ui_refreshSelectAllStatus');
+                       var $selectAllInput = $('.ui-header .selectAll .ui-checkbox input');
+                       // update status of select all checkbox
+                       if ($('ul#fileList input:checkbox:not(:checked)').length === 0) {
+                               // all nodes checked
+                               $selectAllInput.attr('checked', true).data('checkboxradio').refresh();
+                       } else {
+                               // some node is not checked
+                               $selectAllInput.attr('checked', false).data('checkboxradio').refresh();
+                       }
+               },
+
+               /**
+                * Unbinds default events for checkbox labels
+                */
+               resetDefaultCheckBoxLabelEvents: function Ui_resetDefaultCheckBoxLabelEvents() {
+                       console.log('Ui_resetDefaultCheckBoxLabelEvents');
+                       $('div.ui-checkbox > label')
+                               .unbind('vmousedown')
+                               .unbind('vmouseup')
+                               .unbind('vmouseover')
+                               .unbind('vclick');
+               },
+
+               /**
+                * Remove html node element from list
+                * @param {string} node id
+                */
+               removeNodeFromList: function Ui_removeNodeFromList(nodeId) {
+                       console.log('Ui_removeNodeFromList', nodeId);
+                       $('ul#fileList > li#' + nodeId).remove();
+               },
+
+               /**
+                * Enable/Disable
+                */
+               refreshPasteActionBtn: function Ui_refreshPasteActionBtn(clipboardEmpty) {
+                       console.log('Ui_refreshPasteActionBtn', clipboardEmpty);
+                       if (clipboardEmpty === true) {
+                               $('#pasteActionBtnRow').addClass('hidden');
+                       } else {
+                               $('#pasteActionBtnRow').removeClass('hidden');
+                       }
+               }
+       };
+}());
diff --git a/js/app.ui.templateManager.js b/js/app.ui.templateManager.js
new file mode 100644 (file)
index 0000000..bfe2b73
--- /dev/null
@@ -0,0 +1,110 @@
+/*jslint devel: true*/
+/*global $, 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)
+                */
+               get: function TemplateManager_get(tplName, tplParams) {
+                       console.log('TemplateManager_get:' + tplName);
+
+                       if (this.cache[tplName] !== undefined) {
+                               return this.getCompleted(this.cache[tplName], tplParams);
+                       }
+                       return '';
+               },
+
+               /**
+                * Load templates to cache
+                */
+               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;
+                                                               console.log('Cached template: ' + fileName);
+
+                                                               // if all templates are cached launch callback
+                                                               if (cachedTemplates >= tplNames.length && typeof onSuccess === 'function') {
+                                                                       onSuccess();
+                                                               }
+                                                       },
+                                                       error: function (jqXHR, textStatus, errorThrown) {
+                                                               alert(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
+                */
+               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/js/main.js b/js/main.js
new file mode 100644 (file)
index 0000000..e3440f4
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ *      Copyright 2012  Samsung Electronics Co., Ltd
+ *
+ *      Licensed under the Flora License, Version 1.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://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, App  */
+
+/**
+ * This file acts as a loader for the application and its dependencies
+ *
+ * First, the 'app.js' script is loaded .
+ * Then, scripts defined in 'app.requires' are loaded.
+ * Finally, the app is initialised - the app is instantiated ('app = new App()')
+ * and 'app.init()' is called.
+ */
+
+
+var app = null;
+
+(function () { // strict mode wrapper
+       'use strict';
+
+       ({
+               /**
+                * Loader init - load the App constructor
+                */
+               init: function init() {
+                       var self = this;
+                       $.getScript('js/app.js')
+                               .done(function () {
+                                       console.log('Loaded app.js');
+                                       // once the app is loaded, create the app object
+                                       // and load the libraries
+                                       app = new App();
+                                       self.loadLibs();
+                               })
+                               .fail(this.onGetScriptError);
+               },
+
+               /**
+                * Load dependencies
+                */
+               loadLibs: function loadLibs() {
+                       var loadedLibs = 0;
+                       if ($.isArray(app.requires)) {
+                               $.each(app.requires, function (index, filename) {
+                                       $.getScript(filename)
+                                               .done(function () {
+                                                       loadedLibs += 1;
+                                                       console.log('Loaded subscript: ' + filename + ' : ' + loadedLibs);
+                                                       if (loadedLibs >= app.requires.length) {
+                                                               // All dependencies are loaded - initialise the app
+                                                               app.init();
+                                                       }
+                                               })
+                                               .fail(this.onGetScriptError);
+                               });
+                       }
+               },
+
+               /**
+                * Handle ajax errors
+                */
+               onGetScriptError: function onGetScriptError(e, jqxhr, setting, exception) {
+                       alert('An error occurred: ' + e.message);
+               }
+       }).init(); // run the loader
+}());
\ No newline at end of file
diff --git a/templates/emptyFolder.tpl b/templates/emptyFolder.tpl
new file mode 100644 (file)
index 0000000..da09356
--- /dev/null
@@ -0,0 +1 @@
+<div data-role="nocontents" id="nocontents" data-text1="Folder is empty"></div>
\ No newline at end of file
diff --git a/templates/fileRow.tpl b/templates/fileRow.tpl
new file mode 100644 (file)
index 0000000..47e30f2
--- /dev/null
@@ -0,0 +1,5 @@
+<li class="node file ui-li-1line-bigicon1" id="row%id%" label="%name%" uri="%uri%" fullUri="%fullUri%">
+       <form class="my-ui-checkbox hidden"><input type="checkbox" /></form>
+       <img src="%thumbnailURI%" class="ui-li-bigicon"/>
+       <span class="ui-li-text-main nodename">%name%</span>
+</li>
\ No newline at end of file
diff --git a/templates/folderRow.tpl b/templates/folderRow.tpl
new file mode 100644 (file)
index 0000000..c4e91e3
--- /dev/null
@@ -0,0 +1,6 @@
+<li class="node folder ui-li-1line-bigicon1" id="row%id%" label="%name%" uri="%uri%" fullUri="%fullUri%">
+       <form class="my-ui-checkbox hidden"><input type="checkbox" /></form>
+       <img src="images/folder.png" class="ui-li-bigicon" />
+       <span class="ui-li-text-main nodename">%name%</span>
+       </div>
+</li>
\ No newline at end of file
diff --git a/templates/levelUpRow.tpl b/templates/levelUpRow.tpl
new file mode 100644 (file)
index 0000000..ddbc7cf
--- /dev/null
@@ -0,0 +1,3 @@
+<li class="levelUp">
+       <span class="ui-li-text-main nodename">..</span>
+</li>
\ No newline at end of file
diff --git a/templates/main.tpl b/templates/main.tpl
new file mode 100644 (file)
index 0000000..1069bb3
--- /dev/null
@@ -0,0 +1,64 @@
+       <div data-role="page" id="main">
+               <div data-role="header" data-position="fixed">
+                       <h1 id="mainTitle"></h1>
+                       <a id="homeBtn">Home</a>
+                       <a id="levelUpBtn">Up</a>
+                       <div id="navbar"></div>
+                       <div class="selectAll" style="display: none">
+                               <form>
+                                       <input type="checkbox" name="tizen-check1-1" id="normal-check1" />
+                                       <label for="normal-check1" class="select_all">&nbsp;Select&nbsp;all</label>
+                               </form>
+                       </div>
+               </div>
+
+               <div data-role="content">
+                       <ul id="fileList" data-role="listview"></ul>
+               </div>
+
+               <div data-role="footer" data-position="fixed">
+                       <div class="ui-myToolBar">
+                               <div data-role="tabbar" class="standardTabbar">
+                                       <ul>
+                                               <li><a id="editActionBtn" href="#">Edit</a></li>
+                                               <li><a id="moreActionBtn" href="#morePopup" data-rel="popupwindow">More</a></li>
+                                               <li id="li-myExit">
+                                                       <a id="a-myExit" href="#" class="ui-myExit">Exit</a>
+                                               </li>
+                                       </ul>
+                               </div>
+                               <div data-role="tabbar" class="editTabbar" style="display: none">
+                                       <ul>
+                                               <li><a id="deleteActionBtn" href="#">Delete</a></li>
+                                               <li><a id="moveActionBtn" href="#">Move</a></li>
+                                               <li><a id="copyActionBtn" href="#">Copy</a></li>
+                                               <li><a id="cancelActionBtn" href="#">Cancel</a></li>
+                                       </ul>
+                               </div>
+                               <div class="horizontal" id="morePopup" data-role="popupwindow" data-show-arrow="true">
+                                       <table>
+                                               <tr id="newFolderActionBtnRow">
+                                                       <td class="text">
+                                                               <a id="newFolderActionBtn" href="#addFolderPopup" class="newFolder" data-rel="popup" data-position-to="window" data-shadow="true">New folder</a>
+                                                       </td>
+                                               </tr>
+                                               <tr id="pasteActionBtnRow">
+                                                       <td class="text">
+                                                               <a id="pasteActionBtn" data-position-to="window" data-shadow="true">Paste to folder</a>
+                                                       </td>
+                                               </tr>
+                                       </table>
+                               </div>
+                               <div class="horizontal" id="addFolderPopup" data-role="popup" data-style="center_title_2btn" data-corners="true" >
+                                       <p data-role="title">Add new folder</p>
+                                       <p data-role="text">
+                                               <input id="newFolderName" type="text" value="New folder" class="newFolder" />
+                                       </p>
+                                       <p data-role="text">
+                                               <input type="button" id="saveNewFolder" value="Save" data-inline="true" />
+                                               <input type="button" id="cancelNewFolder" value="Cancel" data-inline="true" />
+                                       </p>
+                               </div>
+                       </div>
+               </div>
+       </div>
\ No newline at end of file