You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
336 lines
9.8 KiB
336 lines
9.8 KiB
/* |
|
* Copyright (c) 2014 Vincent Petry <pvince81@owncloud.com> |
|
* |
|
* This file is licensed under the Affero General Public License version 3 |
|
* or later. |
|
* |
|
* See the COPYING-README file. |
|
* |
|
*/ |
|
|
|
/* global Handlebars */ |
|
|
|
(function (OCA) { |
|
|
|
_.extend(OC.Files.Client, { |
|
PROPERTY_TAGS: '{' + OC.Files.Client.NS_OWNCLOUD + '}tags', |
|
PROPERTY_FAVORITE: '{' + OC.Files.Client.NS_OWNCLOUD + '}favorite' |
|
}); |
|
|
|
/** |
|
* Returns the icon class for the matching state |
|
* |
|
* @param {boolean} state true if starred, false otherwise |
|
* @return {string} icon class for star image |
|
*/ |
|
function getStarIconClass (state) { |
|
return state ? 'icon-starred' : 'icon-star'; |
|
} |
|
|
|
/** |
|
* Render the star icon with the given state |
|
* |
|
* @param {boolean} state true if starred, false otherwise |
|
* @return {Object} jQuery object |
|
*/ |
|
function renderStar (state) { |
|
return OCA.Files.Templates['favorite_mark']({ |
|
isFavorite: state, |
|
altText: state ? t('files', 'Favorited') : t('files', 'Not favorited'), |
|
iconClass: getStarIconClass(state) |
|
}); |
|
} |
|
|
|
/** |
|
* Toggle star icon on favorite mark element |
|
* |
|
* @param {Object} $favoriteMarkEl favorite mark element |
|
* @param {boolean} state true if starred, false otherwise |
|
*/ |
|
function toggleStar ($favoriteMarkEl, state) { |
|
$favoriteMarkEl.removeClass('icon-star icon-starred').addClass(getStarIconClass(state)); |
|
$favoriteMarkEl.toggleClass('permanent', state); |
|
} |
|
|
|
/** |
|
* Remove Item from Quickaccesslist |
|
* |
|
* @param {String} appfolder folder to be removed |
|
*/ |
|
function removeFavoriteFromList (appfolder) { |
|
var quickAccessList = 'sublist-favorites'; |
|
var listULElements = document.getElementById(quickAccessList); |
|
if (!listULElements) { |
|
return; |
|
} |
|
|
|
var apppath=appfolder; |
|
if(appfolder.startsWith("//")){ |
|
apppath=appfolder.substring(1, appfolder.length); |
|
} |
|
|
|
$(listULElements).find('[data-dir="' + _.escape(apppath) + '"]').remove(); |
|
|
|
if (listULElements.childElementCount === 0) { |
|
var collapsibleButton = $(listULElements).parent().find('button.collapse'); |
|
collapsibleButton.hide(); |
|
$("#button-collapse-parent-favorites").removeClass('collapsible'); |
|
} |
|
} |
|
|
|
/** |
|
* Add Item to Quickaccesslist |
|
* |
|
* @param {String} appfolder folder to be added |
|
*/ |
|
function addFavoriteToList (appfolder) { |
|
var quickAccessList = 'sublist-favorites'; |
|
var listULElements = document.getElementById(quickAccessList); |
|
if (!listULElements) { |
|
return; |
|
} |
|
var listLIElements = listULElements.getElementsByTagName('li'); |
|
|
|
var appName = appfolder.substring(appfolder.lastIndexOf("/") + 1, appfolder.length); |
|
var apppath = appfolder; |
|
|
|
if(appfolder.startsWith("//")){ |
|
apppath = appfolder.substring(1, appfolder.length); |
|
} |
|
var url = OC.generateUrl('/apps/files/?dir=' + apppath + '&view=files'); |
|
|
|
var innerTagA = document.createElement('A'); |
|
innerTagA.setAttribute("href", url); |
|
innerTagA.setAttribute("class", "nav-icon-files svg"); |
|
innerTagA.innerHTML = _.escape(appName); |
|
|
|
var length = listLIElements.length + 1; |
|
var innerTagLI = document.createElement('li'); |
|
innerTagLI.setAttribute("data-id", apppath.replace('/', '-')); |
|
innerTagLI.setAttribute("data-dir", apppath); |
|
innerTagLI.setAttribute("data-view", 'files'); |
|
innerTagLI.setAttribute("class", "nav-" + appName); |
|
innerTagLI.setAttribute("folderpos", length.toString()); |
|
innerTagLI.appendChild(innerTagA); |
|
|
|
$.get(OC.generateUrl("/apps/files/api/v1/quickaccess/get/NodeType"),{folderpath: apppath}, function (data, status) { |
|
if (data === "dir") { |
|
if (listULElements.childElementCount <= 0) { |
|
listULElements.appendChild(innerTagLI); |
|
var collapsibleButton = $(listULElements).parent().find('button.collapse'); |
|
collapsibleButton.show(); |
|
$(listULElements).parent().addClass('collapsible'); |
|
} else { |
|
listLIElements[listLIElements.length - 1].after(innerTagLI); |
|
} |
|
} |
|
} |
|
); |
|
} |
|
|
|
OCA.Files = OCA.Files || {}; |
|
|
|
/** |
|
* Extends the file actions and file list to include a favorite mark icon |
|
* and a favorite action in the file actions menu; it also adds "data-tags" |
|
* and "data-favorite" attributes to file elements. |
|
* |
|
* @namespace OCA.Files.TagsPlugin |
|
*/ |
|
OCA.Files.TagsPlugin = { |
|
name: 'Tags', |
|
|
|
allowedLists: [ |
|
'files', |
|
'favorites', |
|
'systemtags', |
|
'shares.self', |
|
'shares.others', |
|
'shares.link' |
|
], |
|
|
|
_extendFileActions: function (fileActions) { |
|
var self = this; |
|
|
|
fileActions.registerAction({ |
|
name: 'Favorite', |
|
displayName: function (context) { |
|
var $file = context.$file; |
|
var isFavorite = $file.data('favorite') === true; |
|
|
|
if (isFavorite) { |
|
return t('files', 'Remove from favorites'); |
|
} |
|
|
|
// As it is currently not possible to provide a context for |
|
// the i18n strings "Add to favorites" was used instead of |
|
// "Favorite" to remove the ambiguity between verb and noun |
|
// when it is translated. |
|
return t('files', 'Add to favorites'); |
|
}, |
|
mime: 'all', |
|
order: -100, |
|
permissions: OC.PERMISSION_NONE, |
|
iconClass: function (fileName, context) { |
|
var $file = context.$file; |
|
var isFavorite = $file.data('favorite') === true; |
|
|
|
if (isFavorite) { |
|
return 'icon-star-dark'; |
|
} |
|
|
|
return 'icon-starred'; |
|
}, |
|
actionHandler: function (fileName, context) { |
|
var $favoriteMarkEl = context.$file.find('.favorite-mark'); |
|
var $file = context.$file; |
|
var fileInfo = context.fileList.files[$file.index()]; |
|
var dir = context.dir || context.fileList.getCurrentDirectory(); |
|
var tags = $file.attr('data-tags'); |
|
|
|
if (_.isUndefined(tags)) { |
|
tags = ''; |
|
} |
|
tags = tags.split('|'); |
|
tags = _.without(tags, ''); |
|
var isFavorite = tags.indexOf(OC.TAG_FAVORITE) >= 0; |
|
if (isFavorite) { |
|
// remove tag from list |
|
tags = _.without(tags, OC.TAG_FAVORITE); |
|
removeFavoriteFromList(dir + '/' + fileName); |
|
} else { |
|
tags.push(OC.TAG_FAVORITE); |
|
addFavoriteToList(dir + '/' + fileName); |
|
} |
|
|
|
// pre-toggle the star |
|
toggleStar($favoriteMarkEl, !isFavorite); |
|
|
|
context.fileInfoModel.trigger('busy', context.fileInfoModel, true); |
|
|
|
self.applyFileTags( |
|
dir + '/' + fileName, |
|
tags, |
|
$favoriteMarkEl, |
|
isFavorite |
|
).then(function (result) { |
|
context.fileInfoModel.trigger('busy', context.fileInfoModel, false); |
|
// response from server should contain updated tags |
|
var newTags = result.tags; |
|
if (_.isUndefined(newTags)) { |
|
newTags = tags; |
|
} |
|
context.fileInfoModel.set({ |
|
'tags': newTags, |
|
'favorite': !isFavorite |
|
}); |
|
}); |
|
} |
|
}); |
|
}, |
|
|
|
_extendFileList: function (fileList) { |
|
// extend row prototype |
|
var oldCreateRow = fileList._createRow; |
|
fileList._createRow = function (fileData) { |
|
var $tr = oldCreateRow.apply(this, arguments); |
|
var isFavorite = false; |
|
if (fileData.tags) { |
|
$tr.attr('data-tags', fileData.tags.join('|')); |
|
if (fileData.tags.indexOf(OC.TAG_FAVORITE) >= 0) { |
|
$tr.attr('data-favorite', true); |
|
isFavorite = true; |
|
} |
|
} |
|
var $icon = $(renderStar(isFavorite)); |
|
$tr.find('td.filename .thumbnail').append($icon); |
|
return $tr; |
|
}; |
|
var oldElementToFile = fileList.elementToFile; |
|
fileList.elementToFile = function ($el) { |
|
var fileInfo = oldElementToFile.apply(this, arguments); |
|
var tags = $el.attr('data-tags'); |
|
if (_.isUndefined(tags)) { |
|
tags = ''; |
|
} |
|
tags = tags.split('|'); |
|
tags = _.without(tags, ''); |
|
fileInfo.tags = tags; |
|
return fileInfo; |
|
}; |
|
|
|
var oldGetWebdavProperties = fileList._getWebdavProperties; |
|
fileList._getWebdavProperties = function () { |
|
var props = oldGetWebdavProperties.apply(this, arguments); |
|
props.push(OC.Files.Client.PROPERTY_TAGS); |
|
props.push(OC.Files.Client.PROPERTY_FAVORITE); |
|
return props; |
|
}; |
|
|
|
fileList.filesClient.addFileInfoParser(function (response) { |
|
var data = {}; |
|
var props = response.propStat[0].properties; |
|
var tags = props[OC.Files.Client.PROPERTY_TAGS]; |
|
var favorite = props[OC.Files.Client.PROPERTY_FAVORITE]; |
|
if (tags && tags.length) { |
|
tags = _.chain(tags).filter(function (xmlvalue) { |
|
return (xmlvalue.namespaceURI === OC.Files.Client.NS_OWNCLOUD && xmlvalue.nodeName.split(':')[1] === 'tag'); |
|
}).map(function (xmlvalue) { |
|
return xmlvalue.textContent || xmlvalue.text; |
|
}).value(); |
|
} |
|
if (tags) { |
|
data.tags = tags; |
|
} |
|
if (favorite && parseInt(favorite, 10) !== 0) { |
|
data.tags = data.tags || []; |
|
data.tags.push(OC.TAG_FAVORITE); |
|
} |
|
return data; |
|
}); |
|
}, |
|
|
|
attach: function (fileList) { |
|
if (this.allowedLists.indexOf(fileList.id) < 0) { |
|
return; |
|
} |
|
this._extendFileActions(fileList.fileActions); |
|
this._extendFileList(fileList); |
|
}, |
|
|
|
/** |
|
* Replaces the given files' tags with the specified ones. |
|
* |
|
* @param {String} fileName path to the file or folder to tag |
|
* @param {Array.<String>} tagNames array of tag names |
|
* @param {Object} $favoriteMarkEl favorite mark element |
|
* @param {boolean} isFavorite Was the item favorited before |
|
*/ |
|
applyFileTags: function (fileName, tagNames, $favoriteMarkEl, isFavorite) { |
|
var encodedPath = OC.encodePath(fileName); |
|
while (encodedPath[0] === '/') { |
|
encodedPath = encodedPath.substr(1); |
|
} |
|
return $.ajax({ |
|
url: OC.generateUrl('/apps/files/api/v1/files/') + encodedPath, |
|
contentType: 'application/json', |
|
data: JSON.stringify({ |
|
tags: tagNames || [] |
|
}), |
|
dataType: 'json', |
|
type: 'POST' |
|
}).fail(function (response) { |
|
var message = ''; |
|
// show message if it is available |
|
if (response.responseJSON && response.responseJSON.message) { |
|
message = ': ' + response.responseJSON.message; |
|
} |
|
OC.Notification.show(t('files', 'An error occurred while trying to update the tags' + message), {type: 'error'}); |
|
toggleStar($favoriteMarkEl, isFavorite); |
|
}); |
|
} |
|
}; |
|
}) |
|
(OCA); |
|
|
|
OC.Plugins.register('OCA.Files.FileList', OCA.Files.TagsPlugin);
|
|
|