1 /*jslint devel: true */
2 /*global $, app, TemplateManager, Helpers */
11 (function () { // strict mode wrapper
24 lockedFolders: ['ringtones'],
33 * @type {bool} block clicks 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 self.refreshSelectAllStatus();
142 app.refreshCurrentPage(true);
146 window.addEventListener('tizenhwkey', function(e) {
147 var uri = $('#navbar span+span').attr('uri');
148 if (e.keyName == "back") {
149 if (self.infoPopupVisibility) {
151 } else if ($.mobile.popup.active) {
152 $.mobile.popup.active.close();
153 } else if (self.editMode === true) {
154 self.handleCancelEditAction();
156 if ( app.ui.root === false ) {
157 $('#fileList').empty();
158 app.ui.prepareFolderRow(0, "root");
161 tizen.application.getCurrentApplication().exit();
169 $(window).resize( function () {
170 $.mobile.activePage.page('refresh')
173 // touch events for all nodes
175 .on('click', 'li.levelUp', function () {
176 if (self.editMode === true) {
177 self.handleCancelEditAction();
181 .on('click', 'li.node', function (e) {
184 self.handleNodeClick($(this), true);
186 .on('change', 'input[type=checkbox]', function (e) {
187 self.handleNodeClick($(this).closest('li.node'), false);
189 .on('touchstart', 'li', function (event) {
190 $(this).addClass(self.CSS_GRADIENT_CLASS);
192 .on('touchend touchmove', 'li', function (event) {
193 $(this).removeClass(self.CSS_GRADIENT_CLASS);
196 $('.selectAll input').on('change', this.handleSelectAllChange.bind(this));
199 $('#navbar').on('click', 'span', function () {
200 var uri = $(this).attr('uri');
201 if (uri === 'home') {
202 if (app.currentPath !== '') {
203 app.displayStorages();
205 } else if (uri === app.model.currentPath) {
206 app.displayFolder(uri,true);
208 if (self.editMode === true) {
209 self.handleCancelEditAction();
211 app.displayFolder(uri);
216 $('#levelUpBtn').on('click', function () {
217 if (self.editMode === true) {
218 self.handleCancelEditAction();
223 $('#homeBtn').on('click', app.displayStorages.bind(app));
226 $('#editActionBtn').on('click', this.handleEditAction.bind(this));
229 $('#deleteActionBtn').on('click', this.handleDeleteAction.bind(this));
232 $('#cancelActionBtn').on('click', function (e) {
235 self.handleCancelEditAction();
239 $('#copyActionBtn').on('click', this.handleCopyAction.bind(this));
242 $('#moveActionBtn').on('click', this.handleMoveAction.bind(this));
245 $('a#pasteActionBtn').on('click', function () {
246 if (!self.infoPopupVisibility) {
247 self.toggleInfoPopup();
248 setTimeout(app.pasteClipboard.bind(app), 100);
250 $("#morePopup").popup('close');
253 // remove active class
254 $('[data-role = "tabbar"] li > a').on('click', function () {
255 $(this).removeClass('ui-focus, ui-btn-active');
258 $('.ui-myExit').on('click', app.exit);
260 // add folder popup actions
261 $('#addFolderPopup').on("popupafterclose", function () {
263 $('#newFolderName').val('New folder');
266 $('#newFolderName').on('click', function () {
267 if ($(this).attr('value') === 'New folder') {
268 $(this).attr('value', '');
272 $('#saveNewFolder').on('click', this.saveNewFolder.bind(this));
273 $('#newFolderForm').on('submit', this.saveNewFolder.bind(this));
276 saveNewFolder: function Ui_saveNewFolder(e) {
277 var folderName = $('#newFolderName').val().trim(), status = true,
279 $("#addFolderPopup").popup('open', {
284 buttons = $("#addFolderPopup .ui-popup-button-bg a"),
288 buttons.addClass('ui-disabled');
289 $("#addFolderPopup").one("popupafterclose", function () {
290 if (folderName === '') {
291 self.alertPopup("Empty folder name", open);
293 } else if (folderName.match(/[\*\.\/\\\?\"\'\:<>|]/)) {
294 self.alertPopup("The following special characters "
295 +"are not allowed: *./\\?:<>|'\"", open);
298 status = app.createDir(folderName, open);
300 buttons.removeClass('ui-disabled');
302 activePopup = $.mobile.popup.active;
305 activePopup.element.attr('id') === 'addFolderPopup'
312 toggleInfoPopup: function () {
313 var overlay = $('#overlay');
315 if (this.infoPopupVisibility) {
317 document.onkeydown = null;
319 document.onkeydown = function(){return false;}
323 this.infoPopupVisibility = !this.infoPopupVisibility;
326 alertPopup: function (text, callback) {
327 $("#alertPopup .text").text(text);
328 $("#alertPopup").popup('open', {'positionTo': 'window'});
329 if (callback instanceof Function) {
330 $("#alertPopup").one("popupafterclose", function () {
334 if (this.infoPopupVisibility) {
335 this.toggleInfoPopup();
339 confirmPopup: function (text, confirmCallback, completeCallback) {
340 var popup = $("#confirmPopup");
341 popup.find(".text").text(text);
342 popup.popup('open', {positionTo: 'window'});
343 popup.find(".confirm").one("click", function () {
344 if (confirmCallback instanceof Function) {
348 if (completeCallback instanceof Function) {
349 popup.one('popupafterclose', function () {
355 clearTabbars: function Ui_clearTabbars() {
356 $('[data-role = "tabbar"] li > a').removeClass('ui-focus, ui-btn-active');
360 * Handler for node click
362 * @param {boolean} toggleCheckbox
364 handleNodeClick: function Ui_handleNodeClick(node, toggleCheckbox) {
366 app.model.loadInternalStorages(function () { app.displayStorages(); });
368 } else if (this.editMode === true) {
369 //if edit mode is on toggle checkbox state
370 if (toggleCheckbox === true) {
371 this.toggleCheckBoxState(node); // select the checkbox
374 this.refreshSelectAllStatus();
375 this.refreshEditMenu();
376 } else if (node.hasClass('folder')) {
377 // otherwise display folder
378 app.displayFolder(node.attr('uri'));
381 app.openFile(node.attr('uri'), node.attr('fullUri'));
386 * Handler for edit action
388 handleEditAction: function Ui_handleEditAction() {
389 this.editMode = true;
391 $('.standardTabbar').hide();
392 $('div.editTabbar').show();
393 this.disableControlBarButtons($('div.editTabbar'), [this.EDIT_TABBAR_DELETE_ACTION, this.EDIT_TABBAR_COPY_ACTION, this.EDIT_TABBAR_MOVE_ACTION]);
394 $('#fileList .folder .nodename, #fileList > li > span.nodename')
395 .animate({'width': '70%'});
396 this.showEditCheckBoxes();
400 * Handler for cancel edit action
402 handleCancelEditAction: function Ui_handleCancelEditAction() {
403 this.editMode = false;
405 $('div.editTabbar').hide();
406 $('.standardTabbar').show();
407 $('#fileList .folder .nodename, #fileList > li > span.nodename')
408 .animate({'width': '75%'});
409 this.hideEditCheckBoxes();
410 if (this.isFileListEmpty()) {
411 $('#editActionBtn').addClass('vhidden').blur();
416 * Handler for delete action
418 handleDeleteAction: function Ui_handleDeleteAction(e) {
419 var nodesToDelete = [],
427 this.confirmPopup('Selected nodes will be deleted. Are you sure?',
429 $('ul#fileList input:checkbox:checked').each(function (index) {
430 $rowElement = $(this).closest('li');
432 id: $rowElement.attr('id'),
433 uri: $rowElement.attr('uri'),
434 name: $rowElement.attr('label'),
435 folder: $rowElement.hasClass('folder')
438 if (nodesToDelete.length > 0) {
439 app.deleteNodes(nodesToDelete);
440 self.scrollContentTo(0);
441 $('ul#fileList input:checkbox:checked').remove();
442 self.refreshEditMenu();
452 * Handler for copy action
454 handleCopyAction: function Ui_handleCopyAction(e) {
460 if (this.editMode === true) {
461 $('ul#fileList input:checkbox:checked').each(function (index) {
462 paths.push($(this).closest('li').attr('uri'));
464 app.saveToClipboard(paths, app.clipboard.COPY_MODE_ID);
469 * Handler for move action
471 handleMoveAction: function Ui_handleMoveAction(e) {
477 if (this.editMode === true) {
478 $('ul#fileList input:checkbox:checked').each(function (index) {
479 paths.push($(this).closest('li').attr('uri'));
481 app.saveToClipboard(paths, app.clipboard.MOVE_MODE_ID);
486 * Handler for paste action
488 handlePasteAction: function Ui_handlePasteAction() {
492 * Scrolls content to the specified position
494 scrollContentTo: function scrollContentTo(value) {
495 $('#main [data-role="content"]').scrollview('scrollTo', 0, value);
499 * @param {FileSystemStorage[]} nodes Storage elements
501 displayStorages: function Ui_displayStorages(nodes) {
502 var len = nodes.length, nodeName, i;
504 this.updateNavbar('');
505 $('#fileList').empty();
507 for (i = 0; i < len; i = i + 1) {
508 nodeName = nodes[i].label.trim();
510 && (nodes[i].type === 0 || nodes[i].type === 'INTERNAL')
511 && nodeName.indexOf('wgt-') === -1
512 && $.inArray(nodeName, this.lockedFolders) === -1
515 app.model.isStorageExists(nodeName,
516 app.ui.prepareFolderRow.bind(app.ui, i, nodeName), null);
518 this.prepareFolderRow(i, nodeName);
523 $('#levelUpBtn').addClass('vhidden');
524 $('#homeBtn').addClass('vhidden');
526 $('#editActionBtn').addClass('vhidden').blur();
527 $('#moreActionBtn').addClass('vhidden').blur();
528 $('h1#mainTitle').html('Media');
531 this.scrollContentTo(0);
534 this.resetDefaultCheckBoxLabelEvents();
535 this.hideSelectAllArea();
536 this.handleCancelEditAction();
538 if (this.infoPopupVisibility) {
539 this.toggleInfoPopup();
543 prepareFolderRow: function (id, name) {
544 $(this.templateManager.get('folderRow', {
549 })).appendTo('#fileList');
553 * File comparison function using their names (case insensitive)
559 fileComparison: function fileComparison(x, y) {
560 if(x.isDirectory !== y.isDirectory) {
561 return x.isDirectory ? -1 : 1;
563 var a = x.name.toLowerCase(),
564 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')],
587 refresh = refresh || false;
590 this.updateTitle(this.templateManager.modifiers.escape(folderName));
592 this.updateNavbar(this.templateManager.modifiers.escape(folderName));
593 this.refreshPasteActionBtn();
595 nodes.sort(this.fileComparison);
598 for (i = 0; i < len; i = i + 1) {
599 nodeName = nodes[i].name;
600 if (nodeName !== '') {
601 if (nodes[i].isDirectory) {
603 listElements.push(this.templateManager.get('folderRow', {
606 uri: nodes[i].fullPath,
607 fullUri: nodes[i].toURI()
611 listElements.push(this.templateManager.get('fileRow', {
614 uri: nodes[i].fullPath,
615 fullUri: nodes[i].toURI(),
616 thumbnailURI: this.helpers.getThumbnailURI(nodeName, nodes[i])
622 if (listElements.length === 1) {
623 // set content for empty folder
624 listElements.push(this.templateManager.get('emptyFolder'));
625 // hide edit button for empty content
626 $('#editActionBtn').addClass('vhidden').blur();
627 this.handleCancelEditAction();
629 $('#editActionBtn').removeClass('vhidden');
632 // scroll to top of list
633 this.scrollContentTo(0);
635 $('#levelUpBtn').removeClass('vhidden');
636 $('#homeBtn').removeClass('vhidden');
637 $('#moreActionBtn').removeClass('vhidden');
639 if (refresh === true && this.editMode === true) {
640 $.each($('#fileList .ui-checkbox input:checked'), function () {
641 checkedRows.push($(this).closest('li').attr('uri'));
646 $('#fileList').html(listElements.join(''))
650 if (this.editMode === true) {
651 $('.selectAll').show();
652 $('#fileList .folder .nodename, #fileList > li > span.nodename')
653 .css('width', '70%');
654 $('ul#fileList > li').css('paddingLeft', '2rem');
655 $('.my-ui-checkbox').removeClass('hidden');
657 if (refresh === true) {
658 checkedRowsLen = checkedRows.length;
659 if (checkedRowsLen) {
660 if (checkedRowsLen !== $('#fileList .ui-checkbox input').length) {
661 this.setCheckboxValue('.selectAll input', false);
663 // restore checked checkboxes
664 for (i = 0; i < checkedRowsLen; i += 1) {
665 this.setCheckboxValue(
667 $('[uri="'+ checkedRows[i] +'"]').attr('id') +
673 // if there are no checked checkboxes
674 if (!$('#fileList .ui-checkbox input:checked').length) {
675 this.clearDeleteMode();
678 this.clearDeleteMode();
682 $('.selectAll').hide();
683 $('#fileList .folder .nodename, #fileList > li > span.nodename')
684 .css('width', '75%');
685 $('ul#fileList > li').css('paddingLeft', '0');
686 $('.my-ui-checkbox').addClass('hidden');
687 this.clearDeleteMode();
689 if (!refresh) this.hideSelectAllArea();
691 if (this.infoPopupVisibility) {
692 this.toggleInfoPopup();
695 this.refreshSelectAllStatus();
699 * Clear confirm popup and disable action buttons
701 clearDeleteMode: function Ui_clearDeleteMode () {
703 $.mobile.popup.active &&
704 $.mobile.popup.active.element.attr('id') === 'confirmPopup'
706 $.mobile.popup.active.close();
708 this.disableControlBarButtons($('div.editTabbar'),
709 [this.EDIT_TABBAR_DELETE_ACTION,
710 this.EDIT_TABBAR_COPY_ACTION,
711 this.EDIT_TABBAR_MOVE_ACTION]
716 * Toggle a checkbox associated with a given list element
717 * @param {jQuery} listElement
719 toggleCheckBoxState: function Ui_toggleCheckBoxState(listElement) {
720 var checkboxInput = null;
722 checkboxInput = listElement.find('form > div.ui-checkbox input');
723 this.setCheckboxValue(checkboxInput, !checkboxInput.attr('checked'));
727 * Shows item checkboxes and topbar with select all option
729 showEditCheckBoxes: function Ui_showEditCheckBoxes() {
732 this.showSelectAllArea();
734 $('ul#fileList > li').animate({paddingLeft: '2rem'}, 500, 'swing', function () {
735 self.editMode = true;
736 $('.my-ui-checkbox').removeClass('hidden');
741 * Hides item checkboxes and topbar with select all option
742 * All checkboxes are auto uncheked
744 hideEditCheckBoxes: function Ui_hideEditCheckBoxes() {
747 this.hideSelectAllArea(); // hide select all option topbar
749 $('ul#fileList > li').animate({paddingLeft: '0'}, 200, 'swing', function () {
750 $('.my-ui-checkbox').addClass('hidden');
751 $.mobile.activePage.page('refresh');
754 // uncheck all checkboxes
755 $('ul#fileList input[type=checkbox]').each(function (index) {
756 self.setCheckboxValue(this, false);
759 //uncheck select all input
760 this.setCheckboxValue('.ui-header .selectAll input', false);
764 * Save current header and content height
766 saveHeights: function Ui_saveHeights() {
767 this.currentHeaderHeight = $('#main div[data-role="header"]').height();
768 this.currentScrollPosition = $('#main div[data-role="content"]').scrollview('getScrollPosition').y;
772 * Changes content scroll position after showing/hiding selectAllArea
774 changeContentScrollPosition: function Ui_changeContentScrollPosition() {
776 if (this.currentScrollPosition !== 0) {
777 diff = $('#main div[data-role="header"]').height() - this.currentHeaderHeight;
778 $('#main div[data-role="content"]').scrollview('scrollTo', 0, -(this.currentScrollPosition + diff));
783 * Shows topbar with select all option
785 showSelectAllArea: function Ui_showSelectAllArea() {
787 $('.selectAll').show();
788 $.mobile.activePage.page('refresh');
789 this.changeContentScrollPosition();
793 * Hides topbar with select all option
795 hideSelectAllArea: function Ui_hideSelectAllArea() {
797 $('.selectAll').hide();
798 $.mobile.activePage.page('refresh');
799 this.changeContentScrollPosition();
803 * Enable specified options for tabbar
804 * @param {object} tabbar
805 * @param {array} enableOptions options to enable
807 enableControlBarButtons: function Ui_enableControlBarButtons(tabbar, enableOptions) {
809 len = enableOptions.length;
811 for (i = 0; i < len; i += 1) {
812 tabbar.tabbar('enable', enableOptions[i]);
817 * Disable specified options for tabbar
818 * @param {object} tabbar controlbar
819 * @param {array} disableOptions options to enable
821 disableControlBarButtons: function Ui_disableControlBarButtons(tabbar, disableOptions) {
823 len = disableOptions.length;
825 for (i = 0; i < len; i += 1) {
826 tabbar.tabbar('disable', disableOptions[i]);
831 * @param {string} path
833 updateTitle: function Ui_updateTitle(path) {
834 var regexp = new RegExp('([^\/])+$', 'g'),
835 match = path.match(regexp),
836 lastDir = match[0] || '(dir)';
837 $('h1#mainTitle').html(lastDir);
841 * @param {string} path
843 updateNavbar: function Ui_updateNavbar(path) {
844 var html = ['<span uri="home">Media</span>'],
849 if (typeof path === 'string' && path !== '') {
850 splitted = path.split('/');
851 len = splitted.length;
853 for (i = 0; i < len; i = i + 1) {
854 html.push('<span uri="' + splitted.slice(0, i + 1).join('/') + '">' + splitted[i] + '</span>');
857 $('#navbar').html(html.join(' > '));
860 handleSelectAllChange: function Ui_handleSelectAllChange() {
861 var $selectAllInput = $('.ui-header .selectAll .ui-checkbox input'),
863 $selectAllInput.data('checkboxradio').refresh();
865 if ($selectAllInput.is(':checked')) {
866 // check all checkboxes
867 $('ul#fileList input[type=checkbox]').each(function (index) {
868 self.setCheckboxValue(this, true);
871 this.enableControlBarButtons($('.editTabbar'), [this.EDIT_TABBAR_DELETE_ACTION, this.EDIT_TABBAR_COPY_ACTION, this.EDIT_TABBAR_MOVE_ACTION]);
873 $('ul#fileList input[type=checkbox]').each(function (index) {
874 self.setCheckboxValue(this, false);
877 this.disableControlBarButtons($('.editTabbar'), [this.EDIT_TABBAR_DELETE_ACTION, this.EDIT_TABBAR_COPY_ACTION, this.EDIT_TABBAR_MOVE_ACTION]);
884 refreshSelectAllStatus: function Ui_refreshSelectAllStatus() {
885 var $selectAllInput = $('.ui-header .selectAll .ui-checkbox input');
886 // update status of select all checkbox
887 if ($('ul#fileList input:checkbox:not(:checked)').length === 0) {
889 this.setCheckboxValue($selectAllInput, true);
891 // some node is not checked
892 this.setCheckboxValue($selectAllInput, false);
897 * Refresh activity of edit menu
899 refreshEditMenu: function () {
900 if ($('ul#fileList input:checkbox:checked').length > 0) {
901 this.enableControlBarButtons($('.editTabbar'),
902 [this.EDIT_TABBAR_DELETE_ACTION, this.EDIT_TABBAR_COPY_ACTION, this.EDIT_TABBAR_MOVE_ACTION]);
904 this.disableControlBarButtons($('.editTabbar'),
905 [this.EDIT_TABBAR_DELETE_ACTION, this.EDIT_TABBAR_COPY_ACTION, this.EDIT_TABBAR_MOVE_ACTION]);
910 * Unbinds default events for checkbox labels
912 resetDefaultCheckBoxLabelEvents: function Ui_resetDefaultCheckBoxLabelEvents() {
913 $('div.ui-checkbox > label')
914 .unbind('vmousedown')
916 .unbind('vmouseover')
921 * Remove html node element from list
922 * @param {string} nodeId node id
924 removeNodeFromList: function Ui_removeNodeFromList(nodeId) {
925 $('ul#fileList > li#' + nodeId).remove();
927 // hide select All checkbox if removed all elements;
928 if ($('ul#fileList > li.node').length === 0) {
929 this.hideSelectAllArea();
936 refreshPasteActionBtn: function Ui_refreshPasteActionBtn() {
937 if (app.emptyClipboard()) {
938 $('#pasteActionBtnRow').addClass('hidden');
940 $('#pasteActionBtnRow').removeClass('hidden');
944 isFileListEmpty: function Ui_isFileListEmpty() {
945 return ($('ul#fileList').children('.node').length < 1);
948 setCheckboxValue: function Ui_setCheckboxValue (element, value) {
949 var $element = $(element),
950 checkboxradio = $element.data('checkboxradio');
952 $(element).attr('checked', value);
954 checkboxradio.refresh();