
That is, albums can now contain other albums, which are shown at the top of the album view. This required some changes to album.js and the contextMenu.js, because this view contains now both photos and albums. The contextMenu on this view has been kept simple by requiring the user to select either only albums or only photos, but not a mixture of both. This feature required a database change, so that the version has been updated to 3.1.3. At the moment, album and photo operations (make public, download, delete, merge) are still "flat", i.e. don't respect the album hierarchy.
368 lines
11 KiB
JavaScript
368 lines
11 KiB
JavaScript
/**
|
|
* @description This module is used for the context menu.
|
|
* @copyright 2015 by Tobias Reich
|
|
*/
|
|
|
|
function buildAlbumList(albums, albumID, action, parent = 0, layer = 0) {
|
|
let items = []
|
|
|
|
for (i in albums) {
|
|
if ((layer == 0 && !albums[i].parent) || albums[i].parent == parent) {
|
|
let album = albums[i]
|
|
|
|
let thumb = 'src/images/no_cover.svg'
|
|
if (album.thumbs && album.thumbs[0])
|
|
thumb = album.thumbs[0]
|
|
else if(album.thumbUrl)
|
|
thumb = album.thumbUrl
|
|
if (album.title==='') album.title = 'Untitled'
|
|
|
|
let prefix = layer > 0 ? " ".repeat(layer - 1) + "└ " : ""
|
|
let html = prefix + lychee.html`<img class='cover' width='16' height='16' src='$${ thumb }'><div class='title'>$${ album.title }</div>`
|
|
|
|
if (album.id!=albumID) {
|
|
items.push({
|
|
title: html,
|
|
fn: () => action(album)
|
|
})
|
|
}
|
|
else {
|
|
html = "<div class='disabled'>" + html + "</div>"
|
|
items.push({
|
|
title: html,
|
|
fn: () => {}
|
|
})
|
|
}
|
|
|
|
items = items.concat(buildAlbumList(albums, albumID, action, album.id, layer + 1))
|
|
}
|
|
}
|
|
|
|
return items
|
|
}
|
|
|
|
contextMenu = {}
|
|
|
|
contextMenu.add = function(albumID, e) {
|
|
|
|
let items = [
|
|
{ title: build.iconic('image') + 'Upload Photo', fn: () => $('#upload_files').click() },
|
|
{ },
|
|
{ title: build.iconic('link-intact') + 'Import from Link', fn: upload.start.url },
|
|
{ title: build.iconic('dropbox', 'ionicons') + 'Import from Dropbox', fn: upload.start.dropbox },
|
|
{ title: build.iconic('terminal') + 'Import from Server', fn: upload.start.server },
|
|
{ },
|
|
{ title: build.iconic('folder') + 'New Album', fn: () => album.add(albumID) }
|
|
]
|
|
|
|
basicContext.show(items, e.originalEvent)
|
|
|
|
upload.notify()
|
|
|
|
}
|
|
|
|
contextMenu.settings = function(e) {
|
|
|
|
let items = [
|
|
{ title: build.iconic('person') + 'Change Login', fn: settings.setLogin },
|
|
{ title: build.iconic('sort-ascending') + 'Change Sorting', fn: settings.setSorting },
|
|
{ title: build.iconic('dropbox', 'ionicons') + 'Set Dropbox', fn: settings.setDropboxKey },
|
|
{ },
|
|
{ title: build.iconic('info') + 'About Lychee', fn: () => window.open(lychee.website) },
|
|
{ title: build.iconic('wrench') + 'Diagnostics', fn: () => window.open('plugins/Diagnostics/') },
|
|
{ title: build.iconic('align-left') + 'Show Log', fn: () => window.open('plugins/Log/') },
|
|
{ },
|
|
{ title: build.iconic('account-logout') + 'Sign Out', fn: lychee.logout }
|
|
]
|
|
|
|
basicContext.show(items, e.originalEvent)
|
|
|
|
}
|
|
|
|
contextMenu.album = function(albumID, e) {
|
|
|
|
// Notice for 'Merge':
|
|
// fn must call basicContext.close() first,
|
|
// in order to keep the selection
|
|
|
|
if (album.isSmartID(albumID)) return false
|
|
|
|
// Show merge-item when there's more than one album
|
|
let showMerge = (albums.json && albums.json.albums && Object.keys(albums.json.albums).length>1)
|
|
|
|
let items = [
|
|
{ title: build.iconic('pencil') + 'Rename', fn: () => album.setTitle([ albumID ]) },
|
|
{ title: build.iconic('collapse-left') + 'Merge', visible: showMerge, fn: () => { basicContext.close(); contextMenu.mergeAlbum(albumID, e) } },
|
|
{ title: build.iconic('trash') + 'Delete', fn: () => album.delete([ albumID ]) }
|
|
]
|
|
|
|
$('.album[data-id="' + albumID + '"]').addClass('active')
|
|
|
|
basicContext.show(items, e.originalEvent, contextMenu.close)
|
|
|
|
}
|
|
|
|
contextMenu.albumMulti = function(albumIDs, e) {
|
|
|
|
multiselect.stopResize()
|
|
|
|
// Automatically merge selected albums when albumIDs contains more than one album
|
|
// Show list of albums otherwise
|
|
let autoMerge = (albumIDs.length>1 ? true : false)
|
|
|
|
// Show merge-item when there's more than one album
|
|
let showMerge = (albums.json && albums.json.albums && Object.keys(albums.json.albums).length>1)
|
|
|
|
let items = [
|
|
{ title: build.iconic('pencil') + 'Rename All', fn: () => album.setTitle(albumIDs) },
|
|
{ title: build.iconic('collapse-left') + 'Merge All', visible: showMerge && autoMerge, fn: () => album.merge(albumIDs) },
|
|
{ title: build.iconic('collapse-left') + 'Merge', visible: showMerge && !autoMerge, fn: () => { basicContext.close(); contextMenu.mergeAlbum(albumIDs[0], e) } },
|
|
{ title: build.iconic('trash') + 'Delete All', fn: () => album.delete(albumIDs) }
|
|
]
|
|
|
|
items.push()
|
|
|
|
basicContext.show(items, e.originalEvent, contextMenu.close)
|
|
|
|
}
|
|
|
|
contextMenu.albumTitle = function(albumID, e) {
|
|
|
|
api.post('Albums::get', { parent: -1 }, function(data) {
|
|
|
|
let items = []
|
|
|
|
if (data.albums && data.num>1) {
|
|
|
|
items = buildAlbumList(data.albums, albumID, (a) => lychee.goto(a.id))
|
|
|
|
items.unshift({ })
|
|
|
|
}
|
|
|
|
items.unshift({ title: build.iconic('pencil') + 'Rename', fn: () => album.setTitle([ albumID ]) })
|
|
|
|
basicContext.show(items, e.originalEvent, contextMenu.close)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
contextMenu.mergeAlbum = function(albumID, e) {
|
|
|
|
api.post('Albums::get', { parent: -1 }, function(data) {
|
|
|
|
let items = []
|
|
|
|
if (data.albums && data.num>1) {
|
|
|
|
let title = albums.getByID(albumID).title
|
|
|
|
items = buildAlbumList(data.albums, albumID, (a) => album.merge([ albumID, a.id ], [title, a.title]))
|
|
|
|
}
|
|
|
|
if (items.length===0) return false
|
|
|
|
basicContext.show(items, e.originalEvent, contextMenu.close)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
contextMenu.photo = function(photoID, e) {
|
|
|
|
// Notice for 'Move':
|
|
// fn must call basicContext.close() first,
|
|
// in order to keep the selection
|
|
|
|
let items = [
|
|
{ title: build.iconic('star') + 'Star', fn: () => photo.setStar([ photoID ]) },
|
|
{ title: build.iconic('tag') + 'Tags', fn: () => photo.editTags([ photoID ]) },
|
|
{ },
|
|
{ title: build.iconic('pencil') + 'Rename', fn: () => photo.setTitle([ photoID ]) },
|
|
{ title: build.iconic('layers') + 'Duplicate', fn: () => photo.duplicate([ photoID ]) },
|
|
{ title: build.iconic('folder') + 'Move', fn: () => { basicContext.close(); contextMenu.move([ photoID ], e) } },
|
|
{ title: build.iconic('trash') + 'Delete', fn: () => photo.delete([ photoID ]) }
|
|
]
|
|
|
|
$('.photo[data-id="' + photoID + '"]').addClass('active')
|
|
|
|
basicContext.show(items, e.originalEvent, contextMenu.close)
|
|
|
|
}
|
|
|
|
function countSubAlbums(photoIDs) {
|
|
let count = 0
|
|
for (i in photoIDs) {
|
|
for (j in album.subjson.albums) {
|
|
if (album.subjson.albums[j].id == photoIDs[i]) {
|
|
count++
|
|
break
|
|
}
|
|
}
|
|
}
|
|
return count
|
|
}
|
|
|
|
contextMenu.photoMulti = function(photoIDs, e) {
|
|
|
|
let subcount = countSubAlbums(photoIDs)
|
|
let photocount = photoIDs.length - subcount
|
|
|
|
if (subcount && photocount) {
|
|
$('.photo.active, .album.active').removeClass('active')
|
|
multiselect.close()
|
|
lychee.error("Please select either albums or photos!")
|
|
return
|
|
}
|
|
if (subcount) {
|
|
contextMenu.albumMulti(photoIDs, e)
|
|
return
|
|
}
|
|
|
|
multiselect.stopResize()
|
|
|
|
// Notice for 'Move All':
|
|
// fn must call basicContext.close() first,
|
|
// in order to keep the selection and multiselect
|
|
|
|
let items = [
|
|
{ title: build.iconic('star') + 'Star All', fn: () => photo.setStar(photoIDs) },
|
|
{ title: build.iconic('tag') + 'Tag All', fn: () => photo.editTags(photoIDs) },
|
|
{ },
|
|
{ title: build.iconic('pencil') + 'Rename All', fn: () => photo.setTitle(photoIDs) },
|
|
{ title: build.iconic('layers') + 'Duplicate All', fn: () => photo.duplicate(photoIDs) },
|
|
{ title: build.iconic('folder') + 'Move All', fn: () => { basicContext.close(); contextMenu.move(photoIDs, e) } },
|
|
{ title: build.iconic('trash') + 'Delete All', fn: () => photo.delete(photoIDs) }
|
|
]
|
|
|
|
basicContext.show(items, e.originalEvent, contextMenu.close)
|
|
|
|
}
|
|
|
|
contextMenu.photoTitle = function(albumID, photoID, e) {
|
|
|
|
let items = [
|
|
{ title: build.iconic('pencil') + 'Rename', fn: () => photo.setTitle([ photoID ]) }
|
|
]
|
|
|
|
let data = album.json
|
|
|
|
if (data.content!==false && data.num>1) {
|
|
|
|
items.push({ })
|
|
|
|
items = items.concat(buildAlbumList(data.content, photoID, (a) => lychee.goto(albumID + '/' + a.id)))
|
|
|
|
}
|
|
|
|
basicContext.show(items, e.originalEvent, contextMenu.close)
|
|
|
|
}
|
|
|
|
contextMenu.photoMore = function(photoID, e) {
|
|
|
|
// Show download-item when
|
|
// a) Public mode is off
|
|
// b) Downloadable is 1 and public mode is on
|
|
let showDownload = lychee.publicMode===false || ((album.json && album.json.downloadable && album.json.downloadable==='1') && lychee.publicMode===true)
|
|
|
|
let items = [
|
|
{ title: build.iconic('fullscreen-enter') + 'Full Photo', fn: () => window.open(photo.getDirectLink()) },
|
|
{ title: build.iconic('cloud-download') + 'Download', visible: showDownload, fn: () => photo.getArchive(photoID) }
|
|
]
|
|
|
|
basicContext.show(items, e.originalEvent)
|
|
|
|
}
|
|
|
|
contextMenu.move = function(photoIDs, e) {
|
|
|
|
let items = []
|
|
|
|
api.post('Albums::get', { parent: -1 }, function(data) {
|
|
|
|
if (data.num===0) {
|
|
|
|
// Show only 'Add album' when no album available
|
|
items = [
|
|
{ title: 'New Album', fn: album.add }
|
|
]
|
|
|
|
} else {
|
|
|
|
items = buildAlbumList(data.albums, album.getID(), (a) => photo.setAlbum(photoIDs, a.id))
|
|
|
|
// Show Unsorted when unsorted is not the current album
|
|
if (album.getID()!=='0') {
|
|
|
|
items.unshift({ })
|
|
items.unshift({ title: 'Unsorted', fn: () => photo.setAlbum(photoIDs, 0) })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
basicContext.show(items, e.originalEvent, contextMenu.close)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
contextMenu.sharePhoto = function(photoID, e) {
|
|
|
|
let link = photo.getViewLink(photoID)
|
|
let iconClass = 'ionicons'
|
|
|
|
let items = [
|
|
{ title: `<input readonly id="link" value="${ link }">`, fn: () => {}, class: 'basicContext__item--noHover' },
|
|
{ },
|
|
{ title: build.iconic('twitter', iconClass) + 'Twitter', fn: () => photo.share(photoID, 'twitter') },
|
|
{ title: build.iconic('facebook', iconClass) + 'Facebook', fn: () => photo.share(photoID, 'facebook') },
|
|
{ title: build.iconic('envelope-closed') + 'Mail', fn: () => photo.share(photoID, 'mail') },
|
|
{ title: build.iconic('dropbox', iconClass) + 'Dropbox', visible: lychee.publicMode===false, fn: () => photo.share(photoID, 'dropbox') },
|
|
{ title: build.iconic('link-intact') + 'Direct Link', fn: () => window.open(photo.getDirectLink()) },
|
|
{ },
|
|
{ title: build.iconic('ban') + 'Make Private', visible: lychee.publicMode===false, fn: () => photo.setPublic(photoID) }
|
|
]
|
|
|
|
if (lychee.publicMode===true) items.splice(7, 1)
|
|
|
|
basicContext.show(items, e.originalEvent)
|
|
$('.basicContext input#link').focus().select()
|
|
|
|
}
|
|
|
|
contextMenu.shareAlbum = function(albumID, e) {
|
|
|
|
let iconClass = 'ionicons'
|
|
|
|
let items = [
|
|
{ title: `<input readonly id="link" value="${ location.href }">`, fn: () => {}, class: 'basicContext__item--noHover' },
|
|
{ },
|
|
{ title: build.iconic('twitter', iconClass) + 'Twitter', fn: () => album.share('twitter') },
|
|
{ title: build.iconic('facebook', iconClass) + 'Facebook', fn: () => album.share('facebook') },
|
|
{ title: build.iconic('envelope-closed') + 'Mail', fn: () => album.share('mail') },
|
|
{ },
|
|
{ title: build.iconic('pencil') + 'Edit Sharing', visible: lychee.publicMode===false, fn: () => album.setPublic(albumID, true, e) },
|
|
{ title: build.iconic('ban') + 'Make Private', visible: lychee.publicMode===false, fn: () => album.setPublic(albumID, false) }
|
|
]
|
|
|
|
if (lychee.publicMode===true) items.splice(5, 1)
|
|
|
|
basicContext.show(items, e.originalEvent)
|
|
$('.basicContext input#link').focus().select()
|
|
|
|
}
|
|
|
|
contextMenu.close = function() {
|
|
|
|
if (!visible.contextMenu()) return false
|
|
|
|
basicContext.close()
|
|
|
|
$('.photo.active, .album.active').removeClass('active')
|
|
if (visible.multiselect()) multiselect.close()
|
|
|
|
} |