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,
48 * @type Info popup lock
50 infoPopupVisibility: false,
60 SELECT_ALL_HEIGHT: 32,
63 * @const {number} header height, set on domReady
68 * name of row gradient class
70 CSS_GRADIENT_CLASS: 'gradientBackground',
73 * Standard tabbar actions
76 STD_TABBAR_EDIT_ACTION: 0,
77 STD_TABBAR_MORE_ACTION: 1,
78 STD_TABBAR_EXIT_ACTION: 2,
84 EDIT_TABBAR_DELETE_ACTION: 0,
85 EDIT_TABBAR_MOVE_ACTION: 1,
86 EDIT_TABBAR_COPY_ACTION: 2,
87 EDIT_TABBAR_CANCEL_ACTION: 3,
89 currentHeaderHeight: null,
90 currentScrollPosition: null,
95 init: function Ui_init(storages) {
96 this.templateManager = new TemplateManager();
97 this.helpers = new Helpers();
98 // Disable text selection
99 $.mobile.tizen.disableSelection(document);
100 $(document).ready(this.initDom.bind(this, storages));
103 initDom: function Ui_initDom(storages) {
105 overlay = $('#overlay'),
106 popup = $('#infoPopup'),
111 this.templateManager.loadToCache(['main', 'fileRow', 'folderRow', 'levelUpRow', 'emptyFolder'], function () {
112 $('#main').append($(self.templateManager.get('main')).children()).trigger('pagecreate');
114 self.displayStorages(storages);
117 windowWidth = $(window).width();
118 windowHeight = $(window).height();
121 'width': windowWidth + 'px',
122 'height': windowHeight + 'px'
125 popWidth = windowWidth / 2 + 30;
127 'width': popWidth + 'px',
128 'left': (windowWidth / 2 - popWidth / 2) + 'px',
129 'top': (windowHeight / 2 - popup.height() / 2) + 'px'
136 addEvents: function Ui_addEvents() {
139 document.addEventListener('webkitvisibilitychange', function () {
140 if (document.webkitVisibilityState === 'visible') {
141 app.refreshCurrentPage(true);
145 window.addEventListener('tizenhwkey', function(e) {
146 var uri = $('#navbar span+span').attr('uri');
147 if (e.keyName == "back") {
148 if (self.infoPopupVisibility) {
150 } else if ($.mobile.popup.active) {
151 $.mobile.popup.active.close();
152 } else if (self.editMode === true) {
153 self.handleCancelEditAction();
155 if ( app.ui.root === false ) {
156 $('#fileList').empty();
157 app.ui.prepareFolderRow(0, "root");
160 tizen.application.getCurrentApplication().exit();
168 $(window).resize( function () {
169 $.mobile.activePage.page('refresh')
172 // touch events for all nodes
174 .on('tap', 'li.levelUp', function () {
175 if (self.editMode === true) {
176 self.handleCancelEditAction();
180 .on('tap', 'li.node', function (e) {
183 self.handleNodeClick($(this), true);
185 .on('change', 'input[type=checkbox]', function (e) {
186 self.handleNodeClick($(this).closest('li.node'), false);
188 .on('touchstart', 'li', function (event) {
189 $(this).addClass(self.CSS_GRADIENT_CLASS);
191 .on('touchend touchmove', 'li', function (event) {
192 $(this).removeClass(self.CSS_GRADIENT_CLASS);
195 $('.selectAll input').on('change', this.handleSelectAllChange.bind(this));
198 $('#navbar').on('tap', 'span', function () {
199 var uri = $(this).attr('uri');
200 if (uri === 'home') {
201 if (app.currentPath !== '') {
202 app.displayStorages();
204 } else if (uri === app.model.currentPath) {
205 app.displayFolder(uri,true);
207 if (self.editMode === true) {
208 self.handleCancelEditAction();
210 app.displayFolder(uri);
215 $('#levelUpBtn').on('tap', function () {
216 if (self.editMode === true) {
217 self.handleCancelEditAction();
222 $('#homeBtn').on('tap', app.displayStorages.bind(app));
225 $('#editActionBtn').on('tap', this.handleEditAction.bind(this));
228 $('#deleteActionBtn').on('tap', this.handleDeleteAction.bind(this));
231 $('#cancelActionBtn').on('tap', function (e) {
234 self.handleCancelEditAction();
238 $('#copyActionBtn').on('tap', this.handleCopyAction.bind(this));
241 $('#moveActionBtn').on('tap', this.handleMoveAction.bind(this));
244 $('a#pasteActionBtn').on('tap', function () {
245 if (!self.infoPopupVisibility) {
246 self.toggleInfoPopup();
247 setTimeout(app.pasteClipboard.bind(app), 100);
249 $("#morePopup").popup('close');
252 // remove active class
253 $('[data-role = "tabbar"] li > a').on('click', function () {
254 $(this).removeClass('ui-focus, ui-btn-active');
257 $('.ui-myExit').on('tap', app.exit);
259 // add folder popup actions
260 $('#addFolderPopup').on("popupafterclose", function () {
262 $('#newFolderName').val('New folder');
265 $('#newFolderName').on('tap', function () {
266 if ($(this).attr('value') === 'New folder') {
267 $(this).attr('value', '');
271 $('#saveNewFolder').on('tap', this.saveNewFolder.bind(this));
272 $('#newFolderForm').on('submit', this.saveNewFolder.bind(this));
275 saveNewFolder: function Ui_saveNewFolder(e) {
276 var folderName = $('#newFolderName').val().trim(), status = true,
278 $("#addFolderPopup").popup('open', {
283 buttons = $("#addFolderPopup .ui-popup-button-bg a"),
287 buttons.addClass('ui-disabled');
288 $("#addFolderPopup").one("popupafterclose", function () {
289 if (folderName === '') {
290 self.alertPopup("Empty folder name", open);
292 } else if (folderName.match(/[\*\.\/\\\?\"\'\:<>|]/)) {
293 self.alertPopup("The following special characters "
294 +"are not allowed: *./\\?:<>|'\"", open);
297 status = app.createDir(folderName, open);
299 buttons.removeClass('ui-disabled');
301 activePopup = $.mobile.popup.active;
304 activePopup.element.attr('id') === 'addFolderPopup'
311 toggleInfoPopup: function () {
312 var overlay = $('#overlay');
314 if (this.infoPopupVisibility) {
320 this.infoPopupVisibility = !this.infoPopupVisibility;
323 alertPopup: function (text, callback) {
324 $("#alertPopup .text").text(text);
325 $("#alertPopup").popup('open', {'positionTo': 'window'});
326 if (callback instanceof Function) {
327 $("#alertPopup").one("popupafterclose", function () {
331 if (this.infoPopupVisibility) {
332 this.toggleInfoPopup();
336 confirmPopup: function (text, confirmCallback, completeCallback) {
337 $("#confirmPopup .text").text(text);
338 setTimeout(function () {
339 $("#confirmPopup").popup('close');
340 setTimeout(function () {
341 $("#confirmPopup").popup('open');
342 $("#confirmPopup .confirm").one("tap", function () {
343 $("#confirmPopup").popup('close');
344 if (confirmCallback instanceof Function) {
348 if (completeCallback instanceof Function) {
349 $("#confirmPopup").one('popupafterclose', function () {
357 clearTabbars: function Ui_clearTabbars() {
358 $('[data-role = "tabbar"] li > a').removeClass('ui-focus, ui-btn-active');
362 * Handler for node click
364 * @param {boolean} toggleCheckbox
366 handleNodeClick: function Ui_handleNodeClick(node, toggleCheckbox) {
368 app.model.loadInternalStorages(function () { app.displayStorages(); });
370 } else if (this.editMode === true) {
371 //if edit mode is on toggle checkbox state
372 if (toggleCheckbox === true) {
373 this.toggleCheckBoxState(node); // select the checkbox
376 this.refreshSelectAllStatus();
377 this.refreshEditMenu();
378 } else if (node.hasClass('folder')) {
379 // otherwise display folder
380 app.displayFolder(node.attr('uri'));
383 app.openFile(node.attr('uri'), node.attr('fullUri'));
388 * Handler for edit action
390 handleEditAction: function Ui_handleEditAction() {
391 this.editMode = true;
393 $('.standardTabbar').hide();
394 $('div.editTabbar').show();
395 this.disableControlBarButtons($('div.editTabbar'), [this.EDIT_TABBAR_DELETE_ACTION, this.EDIT_TABBAR_COPY_ACTION, this.EDIT_TABBAR_MOVE_ACTION]);
396 $('#fileList .folder .nodename, #fileList > li > span.nodename')
397 .animate({'width': '70%'});
398 this.showEditCheckBoxes();
402 * Handler for cancel edit action
404 handleCancelEditAction: function Ui_handleCancelEditAction() {
405 this.editMode = false;
407 $('div.editTabbar').hide();
408 $('.standardTabbar').show();
409 $('#fileList .folder .nodename, #fileList > li > span.nodename')
410 .animate({'width': '75%'});
411 this.hideEditCheckBoxes();
412 if (this.isFileListEmpty()) {
413 $('#editActionBtn').addClass('vhidden');
418 * Handler for delete action
420 handleDeleteAction: function Ui_handleDeleteAction(e) {
421 var nodesToDelete = [],
429 this.confirmPopup('Selected nodes will be deleted. Are you sure?',
431 $('ul#fileList input:checkbox:checked').each(function (index) {
432 $rowElement = $(this).closest('li');
434 id: $rowElement.attr('id'),
435 uri: $rowElement.attr('uri'),
436 name: $rowElement.attr('label'),
437 folder: $rowElement.hasClass('folder')
440 if (nodesToDelete.length > 0) {
441 app.deleteNodes(nodesToDelete);
442 self.scrollContentTo(0);
443 $('ul#fileList input:checkbox:checked').remove();
444 self.refreshEditMenu();
454 * Handler for copy action
456 handleCopyAction: function Ui_handleCopyAction(e) {
462 if (this.editMode === true) {
463 $('ul#fileList input:checkbox:checked').each(function (index) {
464 paths.push($(this).closest('li').attr('uri'));
466 app.saveToClipboard(paths, app.clipboard.COPY_MODE_ID);
471 * Handler for move action
473 handleMoveAction: function Ui_handleMoveAction(e) {
479 if (this.editMode === true) {
480 $('ul#fileList input:checkbox:checked').each(function (index) {
481 paths.push($(this).closest('li').attr('uri'));
483 app.saveToClipboard(paths, app.clipboard.MOVE_MODE_ID);
488 * Handler for paste action
490 handlePasteAction: function Ui_handlePasteAction() {
494 * Scrolls content to the specified position
496 scrollContentTo: function scrollContentTo(value) {
497 $('#main [data-role="content"]').scrollview('scrollTo', 0, value);
501 * @param {FileSystemStorage[]} nodes Storage elements
503 displayStorages: function Ui_displayStorages(nodes) {
504 var len = nodes.length, nodeName, i;
506 this.updateNavbar('');
507 $('#fileList').empty();
509 for (i = 0; i < len; i = i + 1) {
510 nodeName = nodes[i].label.trim();
512 && (nodes[i].type === 0 || nodes[i].type === 'INTERNAL')
513 && nodeName.indexOf('wgt-') === -1
514 && $.inArray(nodeName, this.lockedFolders) === -1
517 app.model.isStorageExists(nodeName,
518 app.ui.prepareFolderRow.bind(app.ui, i, nodeName), null);
520 this.prepareFolderRow(i, nodeName);
525 $('#levelUpBtn').addClass('vhidden');
526 $('#homeBtn').addClass('vhidden');
528 $('#editActionBtn').addClass('vhidden');
529 $('#moreActionBtn').addClass('vhidden');
530 $('h1#mainTitle').html('Media');
533 this.scrollContentTo(0);
536 this.resetDefaultCheckBoxLabelEvents();
537 this.hideSelectAllArea();
538 this.handleCancelEditAction();
540 if (this.infoPopupVisibility) {
541 this.toggleInfoPopup();
545 prepareFolderRow: function (id, name) {
546 $(this.templateManager.get('folderRow', {
551 })).appendTo('#fileList');
555 * File comparison function using their names (case insensitive)
561 fileComparison: function fileComparison(x, y) {
562 var a = x.name.toLowerCase(),
563 b = y.name.toLowerCase();
575 * renders node list for folder
576 * @param {string} folderName
577 * @param {File[]} nodes
578 * @param {bool} [refresh=false]
580 displayFolder: function Ui_displayFolder(folderName, nodes, refresh) {
581 var len = nodes.length,
582 listElements = [this.templateManager.get('levelUpRow')],
588 refresh = refresh || false;
591 this.updateTitle(this.templateManager.modifiers.escape(folderName));
593 this.updateNavbar(this.templateManager.modifiers.escape(folderName));
594 this.refreshPasteActionBtn();
596 nodes.sort(this.fileComparison);
599 for (i = 0; i < len; i = i + 1) {
600 nodeName = nodes[i].name.trim();
601 if (nodeName !== '') {
602 if (nodes[i].isDirectory) {
604 listElements.push(this.templateManager.get('folderRow', {
607 uri: nodes[i].fullPath,
608 fullUri: nodes[i].toURI()
612 listElements.push(this.templateManager.get('fileRow', {
615 uri: nodes[i].fullPath,
616 fullUri: nodes[i].toURI(),
617 thumbnailURI: this.helpers.getThumbnailURI(nodeName, nodes[i])
623 if (listElements.length === 1) {
624 // set content for empty folder
625 listElements.push(this.templateManager.get('emptyFolder'));
626 // hide edit button for empty content
627 $('#editActionBtn').addClass('vhidden');
628 this.handleCancelEditAction();
630 $('#editActionBtn').removeClass('vhidden');
633 // scroll to top of list
634 this.scrollContentTo(0);
636 $('#levelUpBtn').removeClass('vhidden');
637 $('#homeBtn').removeClass('vhidden');
638 $('#moreActionBtn').removeClass('vhidden');
640 if (refresh === true && this.editMode === true) {
641 $.each($('#fileList .ui-checkbox input:checked'), function () {
642 checkedRows.push($(this).closest('li').attr('uri'));
647 $('#fileList').html(listElements.join(''))
651 if (this.editMode === true) {
652 $('.selectAll').show();
653 $('#fileList .folder .nodename, #fileList > li > span.nodename')
654 .css('width', '70%');
655 $('ul#fileList > li').css('paddingLeft', '2rem');
656 $('.my-ui-checkbox').removeClass('hidden');
658 if (refresh === true) {
659 checkedRowsLen = checkedRows.length;
660 if (checkedRowsLen) {
661 if (checkedRowsLen !== $('#fileList .ui-checkbox input').length) {
662 this.setCheckboxValue('.selectAll input', false);
664 // restore checked checkboxes
665 for (i = 0; i < checkedRowsLen; i += 1) {
666 this.setCheckboxValue(
668 $('[uri="'+ checkedRows[i] +'"]').attr('id') +
674 this.setCheckboxValue('.selectAll input', false);
675 // close confirm popup if visibible
677 $.mobile.popup.active &&
678 $.mobile.popup.active.element.attr('id') === 'confirmPopup'
680 $.mobile.popup.active.close();
685 $('.selectAll').hide();
686 $('#fileList .folder .nodename, #fileList > li > span.nodename')
687 .css('width', '75%');
688 $('ul#fileList > li').css('paddingLeft', '0');
689 $('.my-ui-checkbox').addClass('hidden');
691 if (!refresh) this.hideSelectAllArea();
693 if (this.infoPopupVisibility) {
694 this.toggleInfoPopup();
699 * Toggle a checkbox associated with a given list element
700 * @param {jQuery} listElement
702 toggleCheckBoxState: function Ui_toggleCheckBoxState(listElement) {
703 var checkboxInput = null;
705 checkboxInput = listElement.find('form > div.ui-checkbox input');
706 this.setCheckboxValue(checkboxInput, !checkboxInput.attr('checked'));
710 * Shows item checkboxes and topbar with select all option
712 showEditCheckBoxes: function Ui_showEditCheckBoxes() {
715 this.showSelectAllArea();
717 $('ul#fileList > li').animate({paddingLeft: '2rem'}, 500, 'swing', function () {
718 self.editMode = true;
719 $('.my-ui-checkbox').removeClass('hidden');
724 * Hides item checkboxes and topbar with select all option
725 * All checkboxes are auto uncheked
727 hideEditCheckBoxes: function Ui_hideEditCheckBoxes() {
730 this.hideSelectAllArea(); // hide select all option topbar
732 $('ul#fileList > li').animate({paddingLeft: '0'}, 200, 'swing', function () {
733 $('.my-ui-checkbox').addClass('hidden');
734 $.mobile.activePage.page('refresh');
737 // uncheck all checkboxes
738 $('ul#fileList input[type=checkbox]').each(function (index) {
739 self.setCheckboxValue(this, false);
742 //uncheck select all input
743 this.setCheckboxValue('.ui-header .selectAll input', false);
747 * Save current header and content height
749 saveHeights: function Ui_saveHeights() {
750 this.currentHeaderHeight = $('#main div[data-role="header"]').height();
751 this.currentScrollPosition = $('#main div[data-role="content"]').scrollview('getScrollPosition').y;
755 * Changes content scroll position after showing/hiding selectAllArea
757 changeContentScrollPosition: function Ui_changeContentScrollPosition() {
759 if (this.currentScrollPosition !== 0) {
760 diff = $('#main div[data-role="header"]').height() - this.currentHeaderHeight;
761 $('#main div[data-role="content"]').scrollview('scrollTo', 0, -(this.currentScrollPosition + diff));
766 * Shows topbar with select all option
768 showSelectAllArea: function Ui_showSelectAllArea() {
770 $('.selectAll').show();
771 $.mobile.activePage.page('refresh');
772 this.changeContentScrollPosition();
776 * Hides topbar with select all option
778 hideSelectAllArea: function Ui_hideSelectAllArea() {
780 $('.selectAll').hide();
781 $.mobile.activePage.page('refresh');
782 this.changeContentScrollPosition();
786 * Enable specified options for tabbar
787 * @param {object} tabbar
788 * @param {array} enableOptions options to enable
790 enableControlBarButtons: function Ui_enableControlBarButtons(tabbar, enableOptions) {
792 len = enableOptions.length;
794 for (i = 0; i < len; i += 1) {
795 tabbar.tabbar('enable', enableOptions[i]);
800 * Disable specified options for tabbar
801 * @param {object} tabbar controlbar
802 * @param {array} disableOptions options to enable
804 disableControlBarButtons: function Ui_disableControlBarButtons(tabbar, disableOptions) {
806 len = disableOptions.length;
808 for (i = 0; i < len; i += 1) {
809 tabbar.tabbar('disable', disableOptions[i]);
814 * @param {string} path
816 updateTitle: function Ui_updateTitle(path) {
817 var regexp = new RegExp('([^\/])+$', 'g'),
818 match = path.match(regexp),
819 lastDir = match[0] || '(dir)';
820 $('h1#mainTitle').html(lastDir);
824 * @param {string} path
826 updateNavbar: function Ui_updateNavbar(path) {
827 var html = ['<span uri="home">Media</span>'],
832 if (typeof path === 'string' && path !== '') {
833 splitted = path.split('/');
834 len = splitted.length;
836 for (i = 0; i < len; i = i + 1) {
837 html.push('<span uri="' + splitted.slice(0, i + 1).join('/') + '">' + splitted[i] + '</span>');
840 $('#navbar').html(html.join(' > '));
843 handleSelectAllChange: function Ui_handleSelectAllChange() {
844 var $selectAllInput = $('.ui-header .selectAll .ui-checkbox input'),
846 $selectAllInput.data('checkboxradio').refresh();
848 if ($selectAllInput.is(':checked')) {
849 // check all checkboxes
850 $('ul#fileList input[type=checkbox]').each(function (index) {
851 self.setCheckboxValue(this, true);
854 this.enableControlBarButtons($('.editTabbar'), [this.EDIT_TABBAR_DELETE_ACTION, this.EDIT_TABBAR_COPY_ACTION, this.EDIT_TABBAR_MOVE_ACTION]);
856 $('ul#fileList input[type=checkbox]').each(function (index) {
857 self.setCheckboxValue(this, false);
860 this.disableControlBarButtons($('.editTabbar'), [this.EDIT_TABBAR_DELETE_ACTION, this.EDIT_TABBAR_COPY_ACTION, this.EDIT_TABBAR_MOVE_ACTION]);
867 refreshSelectAllStatus: function Ui_refreshSelectAllStatus() {
868 var $selectAllInput = $('.ui-header .selectAll .ui-checkbox input');
869 // update status of select all checkbox
870 if ($('ul#fileList input:checkbox:not(:checked)').length === 0) {
872 this.setCheckboxValue($selectAllInput, true);
874 // some node is not checked
875 this.setCheckboxValue($selectAllInput, false);
880 * Refresh activity of edit menu
882 refreshEditMenu: function () {
883 if ($('ul#fileList input:checkbox:checked').length > 0) {
884 this.enableControlBarButtons($('.editTabbar'),
885 [this.EDIT_TABBAR_DELETE_ACTION, this.EDIT_TABBAR_COPY_ACTION, this.EDIT_TABBAR_MOVE_ACTION]);
887 this.disableControlBarButtons($('.editTabbar'),
888 [this.EDIT_TABBAR_DELETE_ACTION, this.EDIT_TABBAR_COPY_ACTION, this.EDIT_TABBAR_MOVE_ACTION]);
893 * Unbinds default events for checkbox labels
895 resetDefaultCheckBoxLabelEvents: function Ui_resetDefaultCheckBoxLabelEvents() {
896 $('div.ui-checkbox > label')
897 .unbind('vmousedown')
899 .unbind('vmouseover')
904 * Remove html node element from list
905 * @param {string} nodeId node id
907 removeNodeFromList: function Ui_removeNodeFromList(nodeId) {
908 $('ul#fileList > li#' + nodeId).remove();
910 // hide select All checkbox if removed all elements;
911 if ($('ul#fileList > li.node').length === 0) {
912 this.hideSelectAllArea();
919 refreshPasteActionBtn: function Ui_refreshPasteActionBtn() {
920 if (app.emptyClipboard()) {
921 $('#pasteActionBtnRow').addClass('hidden');
923 $('#pasteActionBtnRow').removeClass('hidden');
927 isFileListEmpty: function Ui_isFileListEmpty() {
928 return ($('ul#fileList').children('.node').length < 1);
931 setCheckboxValue: function Ui_setCheckboxValue (element, value) {
932 var $element = $(element),
933 checkboxradio = $element.data('checkboxradio');
935 $(element).attr('checked', value);
937 checkboxradio.refresh();