2014-05-08 17:00:42 +00:00
|
|
|
/*
|
2018-06-20 20:40:10 +00:00
|
|
|
* @Copyright 2014 Vincent Petry <pvince81@owncloud.com>
|
2014-05-08 17:00:42 +00:00
|
|
|
*
|
|
|
|
* @author Vincent Petry
|
2018-06-20 20:40:10 +00:00
|
|
|
* @author Felix Nüsse <felix.nuesse@t-online.de>
|
2014-05-08 17:00:42 +00:00
|
|
|
*
|
2018-06-16 20:44:18 +00:00
|
|
|
*
|
2014-05-08 17:00:42 +00:00
|
|
|
* This file is licensed under the Affero General Public License version 3
|
|
|
|
* or later.
|
|
|
|
*
|
|
|
|
* See the COPYING-README file.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2018-06-20 20:40:10 +00:00
|
|
|
(function () {
|
2014-05-08 17:00:42 +00:00
|
|
|
|
2014-06-23 21:56:10 +00:00
|
|
|
/**
|
|
|
|
* @class OCA.Files.Navigation
|
|
|
|
* @classdesc Navigation control for the files app sidebar.
|
|
|
|
*
|
|
|
|
* @param $el element containing the navigation
|
|
|
|
*/
|
2018-06-20 20:40:10 +00:00
|
|
|
var Navigation = function ($el) {
|
2014-05-08 17:00:42 +00:00
|
|
|
this.initialize($el);
|
|
|
|
};
|
|
|
|
|
2014-06-23 21:56:10 +00:00
|
|
|
/**
|
|
|
|
* @memberof OCA.Files
|
|
|
|
*/
|
2014-05-08 17:00:42 +00:00
|
|
|
Navigation.prototype = {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Currently selected item in the list
|
|
|
|
*/
|
2014-05-08 20:06:30 +00:00
|
|
|
_activeItem: null,
|
2014-05-08 17:00:42 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Currently selected container
|
|
|
|
*/
|
|
|
|
$currentContent: null,
|
|
|
|
|
2018-06-20 20:40:10 +00:00
|
|
|
/**
|
|
|
|
* Key for the quick-acces-list
|
|
|
|
*/
|
|
|
|
$quickAccessListKey: 'sublist-favorites',
|
2014-05-08 17:00:42 +00:00
|
|
|
/**
|
|
|
|
* Initializes the navigation from the given container
|
2014-06-23 21:56:10 +00:00
|
|
|
*
|
|
|
|
* @private
|
2014-05-08 17:00:42 +00:00
|
|
|
* @param $el element containing the navigation
|
|
|
|
*/
|
2018-06-20 20:40:10 +00:00
|
|
|
initialize: function ($el) {
|
2014-05-08 17:00:42 +00:00
|
|
|
this.$el = $el;
|
2014-05-08 20:06:30 +00:00
|
|
|
this._activeItem = null;
|
2014-05-08 17:00:42 +00:00
|
|
|
this.$currentContent = null;
|
|
|
|
this._setupEvents();
|
2018-06-20 20:40:10 +00:00
|
|
|
|
2018-07-20 22:30:04 +00:00
|
|
|
this.setInitialQuickaccessSettings();
|
2014-05-08 17:00:42 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Setup UI events
|
|
|
|
*/
|
2018-06-20 20:40:10 +00:00
|
|
|
_setupEvents: function () {
|
2019-01-31 18:00:06 +00:00
|
|
|
this.$el.on('click', 'li a', _.bind(this._onClickItem, this));
|
2018-06-16 20:44:18 +00:00
|
|
|
this.$el.on('click', 'li button', _.bind(this._onClickMenuButton, this));
|
2018-08-28 16:21:46 +00:00
|
|
|
|
2019-01-31 18:49:22 +00:00
|
|
|
var trashBinElement = $('.nav-trashbin');
|
|
|
|
trashBinElement.droppable({
|
2019-01-31 18:13:08 +00:00
|
|
|
over: function (event, ui) {
|
2019-01-31 18:49:22 +00:00
|
|
|
trashBinElement.addClass('dropzone-background');
|
2018-08-29 09:53:43 +00:00
|
|
|
},
|
2019-01-31 18:13:08 +00:00
|
|
|
out: function (event, ui) {
|
2019-01-31 18:49:22 +00:00
|
|
|
trashBinElement.removeClass('dropzone-background');
|
2018-08-29 09:53:43 +00:00
|
|
|
},
|
2019-01-31 18:13:08 +00:00
|
|
|
activate: function (event, ui) {
|
2019-01-31 18:49:22 +00:00
|
|
|
var element = trashBinElement.find('a').first();
|
|
|
|
element.addClass('nav-icon-trashbin-starred').removeClass('nav-icon-trashbin');
|
2018-08-29 09:53:43 +00:00
|
|
|
},
|
2019-01-31 18:13:08 +00:00
|
|
|
deactivate: function (event, ui) {
|
2019-01-31 18:49:22 +00:00
|
|
|
var element = trashBinElement.find('a').first();
|
|
|
|
element.addClass('nav-icon-trashbin').removeClass('nav-icon-trashbin-starred');
|
2018-08-29 09:53:43 +00:00
|
|
|
},
|
2019-01-31 18:13:08 +00:00
|
|
|
drop: function (event, ui) {
|
2018-12-07 17:33:05 +00:00
|
|
|
trashBinElement.removeClass('dropzone-background');
|
|
|
|
|
2018-08-28 16:21:46 +00:00
|
|
|
var $selectedFiles = $(ui.draggable);
|
|
|
|
|
2019-01-31 19:35:20 +00:00
|
|
|
// FIXME: when there are a lot of selected files the helper
|
|
|
|
// contains only a subset of them; the list of selected
|
|
|
|
// files should be gotten from the file list instead to
|
|
|
|
// ensure that all of them are removed.
|
|
|
|
var item = ui.helper.find('tr');
|
|
|
|
for (var i = 0; i < item.length; i++) {
|
|
|
|
$selectedFiles.trigger('droppedOnTrash', item[i].getAttribute('data-file'), item[i].getAttribute('data-dir'));
|
2018-08-28 16:21:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2014-05-08 17:00:42 +00:00
|
|
|
},
|
|
|
|
|
2014-05-08 20:06:30 +00:00
|
|
|
/**
|
|
|
|
* Returns the container of the currently active app.
|
|
|
|
*
|
|
|
|
* @return app container
|
|
|
|
*/
|
2018-06-20 20:40:10 +00:00
|
|
|
getActiveContainer: function () {
|
2014-05-08 20:06:30 +00:00
|
|
|
return this.$currentContent;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the currently active item
|
2018-06-20 20:40:10 +00:00
|
|
|
*
|
2014-05-08 20:06:30 +00:00
|
|
|
* @return item ID
|
|
|
|
*/
|
2018-06-20 20:40:10 +00:00
|
|
|
getActiveItem: function () {
|
2014-05-08 20:06:30 +00:00
|
|
|
return this._activeItem;
|
|
|
|
},
|
|
|
|
|
2014-05-08 17:00:42 +00:00
|
|
|
/**
|
|
|
|
* Switch the currently selected item, mark it as selected and
|
|
|
|
* make the content container visible, if any.
|
2014-05-08 20:06:30 +00:00
|
|
|
*
|
2014-05-08 17:00:42 +00:00
|
|
|
* @param string itemId id of the navigation item to select
|
2014-05-08 20:06:30 +00:00
|
|
|
* @param array options "silent" to not trigger event
|
2014-05-08 17:00:42 +00:00
|
|
|
*/
|
2018-06-20 20:40:10 +00:00
|
|
|
setActiveItem: function (itemId, options) {
|
2018-08-09 16:31:02 +00:00
|
|
|
var currentItem = this.$el.find('li[data-id="' + itemId + '"]');
|
2018-07-12 07:56:46 +00:00
|
|
|
var itemDir = currentItem.data('dir');
|
|
|
|
var itemView = currentItem.data('view');
|
2014-05-12 17:54:20 +00:00
|
|
|
var oldItemId = this._activeItem;
|
2014-05-08 20:06:30 +00:00
|
|
|
if (itemId === this._activeItem) {
|
2014-05-12 17:54:20 +00:00
|
|
|
if (!options || !options.silent) {
|
|
|
|
this.$el.trigger(
|
2018-06-20 20:40:10 +00:00
|
|
|
new $.Event('itemChanged', {
|
|
|
|
itemId: itemId,
|
2018-07-12 07:56:46 +00:00
|
|
|
previousItemId: oldItemId,
|
|
|
|
dir: itemDir,
|
|
|
|
view: itemView
|
2018-06-20 20:40:10 +00:00
|
|
|
})
|
2014-05-12 17:54:20 +00:00
|
|
|
);
|
|
|
|
}
|
2014-05-08 17:00:42 +00:00
|
|
|
return;
|
|
|
|
}
|
2018-07-12 07:56:46 +00:00
|
|
|
this.$el.find('li a').removeClass('active');
|
2014-05-08 17:00:42 +00:00
|
|
|
if (this.$currentContent) {
|
|
|
|
this.$currentContent.addClass('hidden');
|
2014-05-08 20:06:30 +00:00
|
|
|
this.$currentContent.trigger(jQuery.Event('hide'));
|
2014-05-08 17:00:42 +00:00
|
|
|
}
|
2014-05-12 17:54:20 +00:00
|
|
|
this._activeItem = itemId;
|
2018-07-12 07:56:46 +00:00
|
|
|
currentItem.children('a').addClass('active');
|
2018-07-12 14:49:25 +00:00
|
|
|
this.$currentContent = $('#app-content-' + (typeof itemView === 'string' && itemView !== '' ? itemView : itemId));
|
2014-05-08 17:00:42 +00:00
|
|
|
this.$currentContent.removeClass('hidden');
|
2014-05-08 20:06:30 +00:00
|
|
|
if (!options || !options.silent) {
|
2018-11-20 13:44:20 +00:00
|
|
|
this.$currentContent.trigger(jQuery.Event('show', {
|
|
|
|
itemId: itemId,
|
|
|
|
previousItemId: oldItemId,
|
|
|
|
dir: itemDir,
|
|
|
|
view: itemView
|
|
|
|
}));
|
2014-05-12 17:54:20 +00:00
|
|
|
this.$el.trigger(
|
2018-06-20 20:40:10 +00:00
|
|
|
new $.Event('itemChanged', {
|
|
|
|
itemId: itemId,
|
2018-07-12 07:56:46 +00:00
|
|
|
previousItemId: oldItemId,
|
|
|
|
dir: itemDir,
|
|
|
|
view: itemView
|
2018-06-20 20:40:10 +00:00
|
|
|
})
|
2014-05-12 17:54:20 +00:00
|
|
|
);
|
2014-05-08 20:06:30 +00:00
|
|
|
}
|
2014-05-08 17:00:42 +00:00
|
|
|
},
|
|
|
|
|
2014-05-12 17:54:20 +00:00
|
|
|
/**
|
|
|
|
* Returns whether a given item exists
|
|
|
|
*/
|
2018-06-20 20:40:10 +00:00
|
|
|
itemExists: function (itemId) {
|
2018-08-09 16:31:02 +00:00
|
|
|
return this.$el.find('li[data-id="' + itemId + '"]').length;
|
2014-05-12 17:54:20 +00:00
|
|
|
},
|
|
|
|
|
2014-05-08 17:00:42 +00:00
|
|
|
/**
|
|
|
|
* Event handler for when clicking on an item.
|
|
|
|
*/
|
2018-06-20 20:40:10 +00:00
|
|
|
_onClickItem: function (ev) {
|
2014-05-08 17:00:42 +00:00
|
|
|
var $target = $(ev.target);
|
|
|
|
var itemId = $target.closest('li').attr('data-id');
|
2017-06-09 16:05:23 +00:00
|
|
|
if (!_.isUndefined(itemId)) {
|
|
|
|
this.setActiveItem(itemId);
|
|
|
|
}
|
2015-05-19 12:47:13 +00:00
|
|
|
ev.preventDefault();
|
2018-06-16 20:44:18 +00:00
|
|
|
},
|
2018-06-20 20:40:10 +00:00
|
|
|
|
2018-06-16 20:44:18 +00:00
|
|
|
/**
|
2018-06-20 20:40:10 +00:00
|
|
|
* Event handler for clicking a button
|
2018-06-16 20:44:18 +00:00
|
|
|
*/
|
2018-06-20 20:40:10 +00:00
|
|
|
_onClickMenuButton: function (ev) {
|
|
|
|
var $target = $(ev.target);
|
2018-07-13 07:33:57 +00:00
|
|
|
var $menu = $target.parent('li');
|
2018-06-20 20:40:10 +00:00
|
|
|
var itemId = $target.closest('button').attr('id');
|
2018-06-16 20:44:18 +00:00
|
|
|
|
2018-06-20 20:40:10 +00:00
|
|
|
var collapsibleToggles = [];
|
|
|
|
var dotmenuToggles = [];
|
2018-06-16 20:44:18 +00:00
|
|
|
|
2018-07-13 07:33:57 +00:00
|
|
|
if ($menu.hasClass('collapsible') && $menu.data('expandedstate')) {
|
|
|
|
$menu.toggleClass('open');
|
|
|
|
var show = $menu.hasClass('open') ? 1 : 0;
|
|
|
|
var key = $menu.data('expandedstate');
|
|
|
|
$.post(OC.generateUrl("/apps/files/api/v1/toggleShowFolder/" + key), {show: show});
|
|
|
|
}
|
2018-06-16 20:44:18 +00:00
|
|
|
|
2018-06-20 20:40:10 +00:00
|
|
|
dotmenuToggles.forEach(function foundToggle (item) {
|
|
|
|
if (item[0] === ("#" + itemId)) {
|
|
|
|
document.getElementById(item[1]).classList.toggle('open');
|
2018-06-16 20:44:18 +00:00
|
|
|
}
|
2018-06-20 20:40:10 +00:00
|
|
|
});
|
2018-06-16 20:44:18 +00:00
|
|
|
|
2018-06-20 20:40:10 +00:00
|
|
|
ev.preventDefault();
|
2018-06-16 20:44:18 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sort initially as setup of sidebar for QuickAccess
|
|
|
|
*/
|
2018-06-20 20:40:10 +00:00
|
|
|
setInitialQuickaccessSettings: function () {
|
2018-08-08 09:24:13 +00:00
|
|
|
var quickAccessKey = this.$quickAccessListKey;
|
2019-01-31 18:00:06 +00:00
|
|
|
var quickAccessMenu = document.getElementById(quickAccessKey);
|
2018-08-08 09:24:13 +00:00
|
|
|
if (quickAccessMenu) {
|
|
|
|
var list = quickAccessMenu.getElementsByTagName('li');
|
|
|
|
this.QuickSort(list, 0, list.length - 1);
|
|
|
|
}
|
2018-12-07 17:33:05 +00:00
|
|
|
|
|
|
|
var favoritesListElement = $(quickAccessMenu).parent();
|
|
|
|
favoritesListElement.droppable({
|
|
|
|
over: function (event, ui) {
|
|
|
|
favoritesListElement.addClass('dropzone-background');
|
|
|
|
},
|
|
|
|
out: function (event, ui) {
|
|
|
|
favoritesListElement.removeClass('dropzone-background');
|
|
|
|
},
|
|
|
|
activate: function (event, ui) {
|
|
|
|
var element = favoritesListElement.find('a').first();
|
|
|
|
element.addClass('nav-icon-favorites-starred').removeClass('nav-icon-favorites');
|
|
|
|
},
|
|
|
|
deactivate: function (event, ui) {
|
|
|
|
var element = favoritesListElement.find('a').first();
|
|
|
|
element.addClass('nav-icon-favorites').removeClass('nav-icon-favorites-starred');
|
|
|
|
},
|
|
|
|
drop: function (event, ui) {
|
|
|
|
favoritesListElement.removeClass('dropzone-background');
|
|
|
|
|
|
|
|
var $selectedFiles = $(ui.draggable);
|
|
|
|
|
|
|
|
if (ui.helper.find('tr').size() === 1) {
|
|
|
|
var $tr = $selectedFiles.closest('tr');
|
|
|
|
if ($tr.attr("data-favorite")) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
$selectedFiles.trigger('droppedOnFavorites', $tr.attr('data-file'));
|
|
|
|
} else {
|
|
|
|
// FIXME: besides the issue described for dropping on
|
|
|
|
// the trash bin, for favoriting it is not possible to
|
|
|
|
// use the data from the helper; due to some bugs the
|
|
|
|
// tags are not always added to the selected files, and
|
|
|
|
// thus that data can not be accessed through the helper
|
|
|
|
// to prevent triggering the favorite action on an
|
|
|
|
// already favorited file (which would remove it from
|
|
|
|
// favorites).
|
|
|
|
OC.Notification.showTemporary(t('files', 'You can only favorite a single file or folder at a time'));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2018-06-16 20:44:18 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sorting-Algorithm for QuickAccess
|
|
|
|
*/
|
2018-06-20 20:40:10 +00:00
|
|
|
QuickSort: function (list, start, end) {
|
|
|
|
var lastMatch;
|
|
|
|
if (list.length > 1) {
|
|
|
|
lastMatch = this.quicksort_helper(list, start, end);
|
|
|
|
if (start < lastMatch - 1) {
|
|
|
|
this.QuickSort(list, start, lastMatch - 1);
|
2018-06-16 20:44:18 +00:00
|
|
|
}
|
2018-06-20 20:40:10 +00:00
|
|
|
if (lastMatch < end) {
|
|
|
|
this.QuickSort(list, lastMatch, end);
|
2018-06-16 20:44:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sorting-Algorithm-Helper for QuickAccess
|
|
|
|
*/
|
2018-06-20 20:40:10 +00:00
|
|
|
quicksort_helper: function (list, start, end) {
|
2018-06-16 20:44:18 +00:00
|
|
|
var pivot = Math.floor((end + start) / 2);
|
2018-06-20 20:40:10 +00:00
|
|
|
var pivotElement = this.getCompareValue(list, pivot);
|
|
|
|
var i = start;
|
|
|
|
var j = end;
|
2018-06-16 20:44:18 +00:00
|
|
|
|
2018-06-20 20:40:10 +00:00
|
|
|
while (i <= j) {
|
|
|
|
while (this.getCompareValue(list, i) < pivotElement) {
|
2018-06-16 20:44:18 +00:00
|
|
|
i++;
|
|
|
|
}
|
2018-06-20 20:40:10 +00:00
|
|
|
while (this.getCompareValue(list, j) > pivotElement) {
|
2018-06-16 20:44:18 +00:00
|
|
|
j--;
|
|
|
|
}
|
2018-06-20 20:40:10 +00:00
|
|
|
if (i <= j) {
|
2018-06-16 20:44:18 +00:00
|
|
|
this.swap(list, i, j);
|
|
|
|
i++;
|
|
|
|
j--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return i;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sorting-Algorithm-Helper for QuickAccess
|
|
|
|
* This method allows easy access to the element which is sorted by.
|
|
|
|
*/
|
2018-06-20 20:40:10 +00:00
|
|
|
getCompareValue: function (nodes, int, strategy) {
|
2018-06-18 09:13:52 +00:00
|
|
|
return nodes[int].getElementsByTagName('a')[0].innerHTML.toLowerCase();
|
2018-06-16 20:44:18 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sorting-Algorithm-Helper for QuickAccess
|
|
|
|
* This method allows easy swapping of elements.
|
|
|
|
*/
|
2018-06-20 20:40:10 +00:00
|
|
|
swap: function (list, j, i) {
|
2018-12-21 11:03:34 +00:00
|
|
|
var before = function(node, insertNode) {
|
|
|
|
node.parentNode.insertBefore(insertNode, node);
|
|
|
|
}
|
|
|
|
before(list[i], list[j]);
|
|
|
|
before(list[j], list[i]);
|
2014-05-08 17:00:42 +00:00
|
|
|
}
|
2018-06-16 20:44:18 +00:00
|
|
|
|
2014-05-08 17:00:42 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
OCA.Files.Navigation = Navigation;
|
|
|
|
|
|
|
|
})();
|
2018-06-16 20:44:18 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|