1 /*jslint devel: true */
2 /*global $, app, TemplateManager, Helpers */
11 (function () { // strict mode wrapper
24 lockedFolders: ['ringtones'],
33 * @type {bool} block taps until the page change is completed
38 * @type {TemplateManager}
40 templateManager: null,
55 SELECT_ALL_HEIGHT: 32,
58 * @const {number} header height, set on domReady
63 * name of row gradient class
65 CSS_GRADIENT_CLASS: 'gradientBackground',
68 * Standard tabbar actions
71 STD_TABBAR_EDIT_ACTION: 0,
72 STD_TABBAR_MORE_ACTION: 1,
73 STD_TABBAR_EXIT_ACTION: 2,
79 EDIT_TABBAR_DELETE_ACTION: 0,
80 EDIT_TABBAR_MOVE_ACTION: 1,
81 EDIT_TABBAR_COPY_ACTION: 2,
82 EDIT_TABBAR_CANCEL_ACTION: 3,
84 currentHeaderHeight: null,
85 currentScrollPosition: null,
90 init: function Ui_init(storages) {
91 this.templateManager = new TemplateManager();
92 this.helpers = new Helpers();
93 // Disable text selection
94 $.mobile.tizen.disableSelection(document);
95 $(document).ready(this.initDom.bind(this, storages));
98 initDom: function Ui_initDom(storages) {
101 this.templateManager.loadToCache(['main', 'fileRow', 'folderRow', 'levelUpRow', 'emptyFolder'], function () {
102 $('#main').append($(self.templateManager.get('main')).children()).trigger('pagecreate');
104 self.displayStorages(storages);
111 addEvents: function Ui_addEvents() {
114 document.addEventListener('webkitvisibilitychange', function () {
115 if (document.webkitVisibilityState === 'visible') {
116 app.ui.editMode = false;
117 app.refreshCurrentPage(true);
121 window.addEventListener('tizenhwkey', function(e) {
122 var uri = $('#navbar span+span').attr('uri');
123 if (e.keyName == "back") {
124 if ($.mobile.popup.active) {
125 $.mobile.popup.active.close();
126 } else if (self.editMode === true) {
127 self.handleCancelEditAction();
129 if ( app.ui.root === false ) {
130 $('#fileList').empty();
131 app.ui.prepareFolderRow(0, "root");
134 tizen.application.getCurrentApplication().exit();
142 $(window).resize( function () {
143 $.mobile.activePage.page('refresh')
146 // touch events for all nodes
148 .on('tap', 'li.levelUp', function () {
149 if (self.editMode === true) {
150 self.handleCancelEditAction();
154 .on('tap', 'li.node', function (e) {
155 self.handleNodeClick($(this), true);
157 .on('change', 'input[type=checkbox]', function (e) {
158 self.handleNodeClick($(this).closest('li.node'), false);
160 .on('touchstart', 'li', function (event) {
161 $(this).addClass(self.CSS_GRADIENT_CLASS);
163 .on('touchend touchmove', 'li', function (event) {
164 $(this).removeClass(self.CSS_GRADIENT_CLASS);
167 $('.selectAll input').on('change', this.handleSelectAllChange.bind(this));
170 $('#navbar').on('tap', 'span', function () {
171 var uri = $(this).attr('uri');
172 if (uri === 'home') {
173 if (app.currentPath !== '') {
174 app.displayStorages();
176 } else if (uri === app.model.currentPath) {
177 app.displayFolder(uri,true);
179 if (self.editMode === true) {
180 self.handleCancelEditAction();
182 app.displayFolder(uri);
187 $('#levelUpBtn').on('tap', function () {
188 if (self.editMode === true) {
189 self.handleCancelEditAction();
194 $('#homeBtn').on('tap', app.displayStorages.bind(app));
197 $('#editActionBtn').on('tap', this.handleEditAction.bind(this));
200 $('#deleteActionBtn').on('tap', this.handleDeleteAction.bind(this));
203 $('#cancelActionBtn').on('tap', function (e) {
206 self.handleCancelEditAction();
210 $('#copyActionBtn').on('tap', this.handleCopyAction.bind(this));
213 $('#moveActionBtn').on('tap', this.handleMoveAction.bind(this));
216 $('a#pasteActionBtn').on('tap', function () {
217 app.pasteClipboard.bind(app)();
218 $("#morePopup").popup('close');
221 // remove active class
222 $('[data-role = "tabbar"] li > a').on('click', function () {
223 $(this).removeClass('ui-focus, ui-btn-active');
226 $('.ui-myExit').on('tap', app.exit);
228 // add folder popup actions
229 $('#addFolderPopup').on("popupafterclose", function () {
231 $('#newFolderName').val('New folder');
234 $('#newFolderName').on('tap', function () {
235 if ($(this).attr('value') === 'New folder') {
236 $(this).attr('value', '');
240 $('#saveNewFolder').on('tap', this.saveNewFolder.bind(this));
241 $('#newFolderForm').on('submit', this.saveNewFolder.bind(this));
244 saveNewFolder: function Ui_saveNewFolder(e) {
245 var folderName = $('#newFolderName').val().trim(), status = true,
247 $("#addFolderPopup").popup('open', {
253 $("#addFolderPopup").one("popupafterclose", function () {
254 if (folderName === '') {
255 self.alertPopup("Empty folder name", open);
257 } else if (folderName.match(/[\*\.\/\\\?\"\'\:<>|]/)) {
258 self.alertPopup("The following special characters "
259 +"are not allowed: *./\\?:<>|'\"", open);
262 status = app.createDir(folderName, open);
265 $("#addFolderPopup").popup('close');
269 alertPopup: function (text, callback) {
270 $("#alertPopup .text").text(text);
271 $("#alertPopup").popup('open', {'positionTo': 'window'});
272 if (callback instanceof Function) {
273 $("#alertPopup").one("popupafterclose", function () {
279 confirmPopup: function (text, confirmCallback, completeCallback) {
280 $("#confirmPopup .text").text(text);
281 setTimeout(function () {
282 $("#confirmPopup").popup('close');
283 setTimeout(function () {
284 $("#confirmPopup").popup('open');
285 $("#confirmPopup .confirm").one("tap", function () {
286 $("#confirmPopup").popup('close');
287 if (confirmCallback instanceof Function) {
291 if (completeCallback instanceof Function) {
292 $("#confirmPopup").one('popupafterclose', function () {
300 clearTabbars: function Ui_clearTabbars() {
301 $('[data-role = "tabbar"] li > a').removeClass('ui-focus, ui-btn-active');
305 * Handler for node click
307 * @param {boolean} toggleCheckbox
309 handleNodeClick: function Ui_handleNodeClick(node, toggleCheckbox) {
311 app.model.loadInternalStorages(function () { app.displayStorages(); });
313 } else if (this.editMode === true) {
314 //if edit mode is on toggle checkbox state
315 if (toggleCheckbox === true) {
316 this.toggleCheckBoxState(node); // select the checkbox
319 this.refreshSelectAllStatus();
320 this.refreshEditMenu();
321 } else if (node.hasClass('folder')) {
322 // otherwise display folder
323 app.displayFolder(node.attr('uri'));
326 app.openFile(node.attr('uri'), node.attr('fullUri'));
331 * Handler for edit action
333 handleEditAction: function Ui_handleEditAction() {
334 this.editMode = true;
336 $('.standardTabbar').hide();
337 $('div.editTabbar').show();
338 this.disableControlBarButtons($('div.editTabbar'), [this.EDIT_TABBAR_DELETE_ACTION, this.EDIT_TABBAR_COPY_ACTION, this.EDIT_TABBAR_MOVE_ACTION]);
339 $('#fileList .folder .nodename').animate({'width': '70%'});
340 this.showEditCheckBoxes();
344 * Handler for cancel edit action
346 handleCancelEditAction: function Ui_handleCancelEditAction() {
347 this.editMode = false;
349 $('div.editTabbar').hide();
350 $('.standardTabbar').show();
351 $('#fileList .folder .nodename').animate({'width': '75%'});
352 this.hideEditCheckBoxes();
353 if (this.isFileListEmpty()) {
354 $('#editActionBtn').addClass('vhidden');
359 * Handler for delete action
361 handleDeleteAction: function Ui_handleDeleteAction(e) {
362 var nodesToDelete = [],
370 this.confirmPopup('Selected nodes will be deleted. Are you sure?',
372 $('ul#fileList input:checkbox:checked').each(function (index) {
373 $rowElement = $(this).closest('li');
375 id: $rowElement.attr('id'),
376 uri: $rowElement.attr('uri'),
377 name: $rowElement.attr('label'),
378 folder: $rowElement.hasClass('folder')
381 if (nodesToDelete.length > 0) {
382 app.deleteNodes(nodesToDelete);
383 self.scrollContentTo(0);
384 $('ul#fileList input:checkbox:checked').remove();
385 self.refreshEditMenu();
395 * Handler for copy action
397 handleCopyAction: function Ui_handleCopyAction(e) {
403 if (this.editMode === true) {
404 $('ul#fileList input:checkbox:checked').each(function (index) {
405 paths.push($(this).closest('li').attr('uri'));
407 app.saveToClipboard(paths, app.clipboard.COPY_MODE_ID);
412 * Handler for move action
414 handleMoveAction: function Ui_handleMoveAction(e) {
420 if (this.editMode === true) {
421 $('ul#fileList input:checkbox:checked').each(function (index) {
422 paths.push($(this).closest('li').attr('uri'));
424 app.saveToClipboard(paths, app.clipboard.MOVE_MODE_ID);
429 * Handler for paste action
431 handlePasteAction: function Ui_handlePasteAction() {
435 * Scrolls content to the specified position
437 scrollContentTo: function scrollContentTo(value) {
438 $('#main [data-role="content"]').scrollview('scrollTo', 0, value);
442 * @param {FileSystemStorage[]} nodes Storage elements
444 displayStorages: function Ui_displayStorages(nodes) {
445 var len = nodes.length, nodeName, i;
447 this.updateNavbar('');
448 $('#fileList').empty();
450 for (i = 0; i < len; i = i + 1) {
451 nodeName = nodes[i].label.trim();
453 && (nodes[i].type === 0 || nodes[i].type === 'INTERNAL')
454 && nodeName.indexOf('wgt-') === -1
455 && $.inArray(nodeName, this.lockedFolders) === -1
458 app.model.isStorageExists(nodeName,
459 app.ui.prepareFolderRow.bind(app.ui, i, nodeName), null);
461 this.prepareFolderRow(i, nodeName);
466 $('#levelUpBtn').addClass('vhidden');
467 $('#homeBtn').addClass('vhidden');
469 $('#editActionBtn').addClass('vhidden');
470 $('#moreActionBtn').addClass('vhidden');
471 $('h1#mainTitle').html('Media');
474 this.scrollContentTo(0);
477 this.resetDefaultCheckBoxLabelEvents();
478 this.hideSelectAllArea();
479 this.handleCancelEditAction();
482 prepareFolderRow: function (id, name) {
483 $(this.templateManager.get('folderRow', {
488 })).appendTo('#fileList');
492 * File comparison function using their names (case insensitive)
498 fileComparison: function fileComparison(x, y) {
499 var a = x.name.toLowerCase(),
500 b = y.name.toLowerCase();
512 * renders node list for folder
513 * @param {string} folderName
514 * @param {File[]} nodes
515 * @param {bool} [refresh=false]
517 displayFolder: function Ui_displayFolder(folderName, nodes, refresh) {
518 var len = nodes.length,
519 listElements = [this.templateManager.get('levelUpRow')],
524 refresh = refresh || false;
527 this.updateTitle(this.templateManager.modifiers.escape(folderName));
529 this.updateNavbar(this.templateManager.modifiers.escape(folderName));
530 this.refreshPasteActionBtn();
532 nodes.sort(this.fileComparison);
535 for (i = 0; i < len; i = i + 1) {
536 nodeName = nodes[i].name.trim();
537 if (nodeName !== '') {
538 if (nodes[i].isDirectory) {
540 listElements.push(this.templateManager.get('folderRow', {
543 uri: nodes[i].fullPath,
544 fullUri: nodes[i].toURI()
548 listElements.push(this.templateManager.get('fileRow', {
551 uri: nodes[i].fullPath,
552 fullUri: nodes[i].toURI(),
553 thumbnailURI: this.helpers.getThumbnailURI(nodeName, nodes[i])
559 if (listElements.length === 1) {
560 // set content for empty folder
561 listElements.push(this.templateManager.get('emptyFolder'));
562 // hide edit button for empty content
563 $('#editActionBtn').addClass('vhidden');
565 $('#editActionBtn').removeClass('vhidden');
568 // scroll to top of list
569 this.scrollContentTo(0);
571 $('#levelUpBtn').removeClass('vhidden');
572 $('#homeBtn').removeClass('vhidden');
573 $('#moreActionBtn').removeClass('vhidden');
575 if (refresh === true && this.editMode === true) {
576 $.each($('#fileList .ui-checkbox input:checked'), function () {
577 checkedRows.push($(this).closest('li').attr('id'));
582 $('#fileList').html(listElements.join(''))
587 if (this.editMode === true) {
588 $('.selectAll').show();
589 $('ul#fileList > li').css('paddingLeft', '2rem');
590 $('.my-ui-checkbox').removeClass('hidden');
592 if (refresh === true) {
593 // restore checked checkboxes
594 for (i = 0; i < checkedRows.length; i += 1) {
595 $('#' + checkedRows[i] + ' input:checkbox')
596 .attr('checked', 'checked')
597 .data('checkboxradio').refresh();
601 $('.selectAll').hide();
602 $('ul#fileList > li').css('paddingLeft', '0');
603 $('.my-ui-checkbox').addClass('hidden');
605 if (!refresh) this.hideSelectAllArea();
609 * Toggle a checkbox associated with a given list element
610 * @param {jQuery} listElement
612 toggleCheckBoxState: function Ui_toggleCheckBoxState(listElement) {
614 var checkboxInput = null;
616 checkboxInput = listElement.find('form > div.ui-checkbox input');
618 .attr('checked', !checkboxInput.attr('checked'))
619 .data('checkboxradio').refresh();
623 * Shows item checkboxes and topbar with select all option
625 showEditCheckBoxes: function Ui_showEditCheckBoxes() {
628 this.showSelectAllArea();
630 $('ul#fileList > li').animate({paddingLeft: '2rem'}, 500, 'swing', function () {
631 self.editMode = true;
632 $('.my-ui-checkbox').removeClass('hidden');
637 * Hides item checkboxes and topbar with select all option
638 * All checkboxes are auto uncheked
640 hideEditCheckBoxes: function Ui_hideEditCheckBoxes() {
643 this.hideSelectAllArea(); // hide select all option topbar
645 $('ul#fileList > li').animate({paddingLeft: '0'}, 200, 'swing', function () {
646 $('.my-ui-checkbox').addClass('hidden');
647 $.mobile.activePage.page('refresh');
650 // uncheck all checkboxes
651 $('ul#fileList input[type=checkbox]').each(function (index) {
652 var checkboxradio = $(this).data('checkboxradio');
654 $(this).attr('checked', false);
657 checkboxradio.refresh();
661 //uncheck select all input
662 $('.ui-header .selectAll .ui-checkbox input')
663 .attr('checked', false)
664 .data('checkboxradio')
669 * Save current header and content height
671 saveHeights: function Ui_saveHeights() {
672 this.currentHeaderHeight = $('#main div[data-role="header"]').height();
673 this.currentScrollPosition = $('#main div[data-role="content"]').scrollview('getScrollPosition').y;
677 * Changes content scroll position after showing/hiding selectAllArea
679 changeContentScrollPosition: function Ui_changeContentScrollPosition() {
681 if (this.currentScrollPosition !== 0) {
682 diff = $('#main div[data-role="header"]').height() - this.currentHeaderHeight;
683 $('#main div[data-role="content"]').scrollview('scrollTo', 0, -(this.currentScrollPosition + diff));
688 * Shows topbar with select all option
690 showSelectAllArea: function Ui_showSelectAllArea() {
692 $('.selectAll').show();
693 $.mobile.activePage.page('refresh');
694 this.changeContentScrollPosition();
698 * Hides topbar with select all option
700 hideSelectAllArea: function Ui_hideSelectAllArea() {
702 $('.selectAll').hide();
703 $.mobile.activePage.page('refresh');
704 this.changeContentScrollPosition();
708 * Enable specified options for tabbar
709 * @param {object} tabbar
710 * @param {array} enableOptions options to enable
712 enableControlBarButtons: function Ui_enableControlBarButtons(tabbar, enableOptions) {
714 len = enableOptions.length;
716 for (i = 0; i < len; i += 1) {
717 tabbar.tabbar('enable', enableOptions[i]);
722 * Disable specified options for tabbar
723 * @param {object} tabbar controlbar
724 * @param {array} disableOptions options to enable
726 disableControlBarButtons: function Ui_disableControlBarButtons(tabbar, disableOptions) {
728 len = disableOptions.length;
730 for (i = 0; i < len; i += 1) {
731 tabbar.tabbar('disable', disableOptions[i]);
736 * @param {string} path
738 updateTitle: function Ui_updateTitle(path) {
739 var regexp = new RegExp('([^\/])+$', 'g'),
740 match = path.match(regexp),
741 lastDir = match[0] || '(dir)';
742 $('h1#mainTitle').html(lastDir);
746 * @param {string} path
748 updateNavbar: function Ui_updateNavbar(path) {
749 var html = ['<span uri="home">Media</span>'],
754 if (typeof path === 'string' && path !== '') {
755 splitted = path.split('/');
756 len = splitted.length;
758 for (i = 0; i < len; i = i + 1) {
759 html.push('<span uri="' + splitted.slice(0, i + 1).join('/') + '">' + splitted[i] + '</span>');
762 $('#navbar').html(html.join(' > '));
765 handleSelectAllChange: function Ui_handleSelectAllChange() {
766 var $selectAllInput = $('.ui-header .selectAll .ui-checkbox input');
767 $selectAllInput.data('checkboxradio').refresh();
769 if ($selectAllInput.is(':checked')) {
770 // check all checkboxes
771 $('ul#fileList input[type=checkbox]').each(function (index) {
772 $(this).attr('checked', true);
773 $(this).data('checkboxradio').refresh();
776 this.enableControlBarButtons($('.editTabbar'), [this.EDIT_TABBAR_DELETE_ACTION, this.EDIT_TABBAR_COPY_ACTION, this.EDIT_TABBAR_MOVE_ACTION]);
778 $('ul#fileList input[type=checkbox]').each(function (index) {
779 $(this).attr('checked', false);
780 $(this).data('checkboxradio').refresh();
783 this.disableControlBarButtons($('.editTabbar'), [this.EDIT_TABBAR_DELETE_ACTION, this.EDIT_TABBAR_COPY_ACTION, this.EDIT_TABBAR_MOVE_ACTION]);
790 refreshSelectAllStatus: function Ui_refreshSelectAllStatus() {
791 var $selectAllInput = $('.ui-header .selectAll .ui-checkbox input');
792 // update status of select all checkbox
793 if ($('ul#fileList input:checkbox:not(:checked)').length === 0) {
795 $selectAllInput.attr('checked', true).data('checkboxradio').refresh();
797 // some node is not checked
798 $selectAllInput.attr('checked', false).data('checkboxradio').refresh();
803 * Refresh activity of edit menu
805 refreshEditMenu: function () {
806 if ($('ul#fileList input:checkbox:checked').length > 0) {
807 this.enableControlBarButtons($('.editTabbar'),
808 [this.EDIT_TABBAR_DELETE_ACTION, this.EDIT_TABBAR_COPY_ACTION, this.EDIT_TABBAR_MOVE_ACTION]);
810 this.disableControlBarButtons($('.editTabbar'),
811 [this.EDIT_TABBAR_DELETE_ACTION, this.EDIT_TABBAR_COPY_ACTION, this.EDIT_TABBAR_MOVE_ACTION]);
816 * Unbinds default events for checkbox labels
818 resetDefaultCheckBoxLabelEvents: function Ui_resetDefaultCheckBoxLabelEvents() {
819 $('div.ui-checkbox > label')
820 .unbind('vmousedown')
822 .unbind('vmouseover')
827 * Remove html node element from list
828 * @param {string} nodeId node id
830 removeNodeFromList: function Ui_removeNodeFromList(nodeId) {
831 $('ul#fileList > li#' + nodeId).remove();
833 // hide select All checkbox if removed all elements;
834 if ($('ul#fileList > li.node').length === 0) {
835 this.hideSelectAllArea();
842 refreshPasteActionBtn: function Ui_refreshPasteActionBtn() {
843 if (app.emptyClipboard()) {
844 $('#pasteActionBtnRow').addClass('hidden');
846 $('#pasteActionBtnRow').removeClass('hidden');
850 isFileListEmpty: function Ui_isFileListEmpty() {
851 return ($('ul#fileList').children('.node').length < 1);