Merge pull request #591 from hrniels/subalbums
Some cleanup, fixes and a new feature for subalbums.
This commit is contained in:
commit
55ae8a4be2
@ -28,6 +28,7 @@ final class Admin extends Access {
|
|||||||
case 'Album::setPublic': self::setAlbumPublicAction(); break;
|
case 'Album::setPublic': self::setAlbumPublicAction(); break;
|
||||||
case 'Album::delete': self::deleteAlbumAction(); break;
|
case 'Album::delete': self::deleteAlbumAction(); break;
|
||||||
case 'Album::merge': self::mergeAlbumsAction(); break;
|
case 'Album::merge': self::mergeAlbumsAction(); break;
|
||||||
|
case 'Album::move': self::moveAlbumsAction(); break;
|
||||||
|
|
||||||
// Photo functions
|
// Photo functions
|
||||||
case 'Photo::get': self::getPhotoAction(); break;
|
case 'Photo::get': self::getPhotoAction(); break;
|
||||||
@ -143,6 +144,14 @@ final class Admin extends Access {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static function moveAlbumsAction() {
|
||||||
|
|
||||||
|
Validator::required(isset($_POST['albumIDs']), __METHOD__);
|
||||||
|
$album = new Album($_POST['albumIDs']);
|
||||||
|
Response::json($album->move());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Photo functions
|
// Photo functions
|
||||||
|
|
||||||
private static function getPhotoAction() {
|
private static function getPhotoAction() {
|
||||||
|
@ -637,13 +637,6 @@ final class Album {
|
|||||||
$albumID = array_splice($albumIDs, 0, 1);
|
$albumID = array_splice($albumIDs, 0, 1);
|
||||||
$albumID = $albumID[0];
|
$albumID = $albumID[0];
|
||||||
|
|
||||||
// Ensure that we don't merge an album into its own subalbum
|
|
||||||
foreach($albumIDs as $id) {
|
|
||||||
foreach($this->getSubAlbums($id) as $sid) {
|
|
||||||
if($sid == $albumID) return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move photos
|
// Move photos
|
||||||
$query = Database::prepare(Database::get(), "UPDATE ? SET album = ? WHERE album IN (?)", array(LYCHEE_TABLE_PHOTOS, $albumID, $this->albumIDs));
|
$query = Database::prepare(Database::get(), "UPDATE ? SET album = ? WHERE album IN (?)", array(LYCHEE_TABLE_PHOTOS, $albumID, $this->albumIDs));
|
||||||
$result = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
$result = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||||
@ -672,6 +665,40 @@ final class Album {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return boolean Returns true when successful.
|
||||||
|
*/
|
||||||
|
public function move() {
|
||||||
|
|
||||||
|
// Check dependencies
|
||||||
|
Validator::required(isset($this->albumIDs), __METHOD__);
|
||||||
|
|
||||||
|
// Call plugins
|
||||||
|
Plugins::get()->activate(__METHOD__, 0, func_get_args());
|
||||||
|
|
||||||
|
// Convert to array
|
||||||
|
$albumIDs = explode(',', $this->albumIDs);
|
||||||
|
|
||||||
|
// Get first albumID
|
||||||
|
$albumID = array_splice($albumIDs, 0, 1);
|
||||||
|
$albumID = $albumID[0];
|
||||||
|
|
||||||
|
// $albumIDs contains all IDs without the first albumID
|
||||||
|
// Convert to string
|
||||||
|
$filteredIDs = implode(',', $albumIDs);
|
||||||
|
|
||||||
|
// Move albums
|
||||||
|
$query = Database::prepare(Database::get(), "UPDATE ? SET parent = ? WHERE id IN (?)", array(LYCHEE_TABLE_ALBUMS, $albumID, $filteredIDs));
|
||||||
|
$result = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
|
||||||
|
|
||||||
|
// Call plugins
|
||||||
|
Plugins::get()->activate(__METHOD__, 1, func_get_args());
|
||||||
|
|
||||||
|
if ($result===false) return false;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return boolean Returns true when successful.
|
* @return boolean Returns true when successful.
|
||||||
*/
|
*/
|
||||||
|
@ -3,6 +3,26 @@
|
|||||||
* @copyright 2015 by Tobias Reich
|
* @copyright 2015 by Tobias Reich
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const buildAlbumOptions = function(albums, select, parent = 0, layer = 0) {
|
||||||
|
|
||||||
|
var cmbxOptions = ''
|
||||||
|
|
||||||
|
for (i in albums) {
|
||||||
|
if (albums[i].parent==parent) {
|
||||||
|
|
||||||
|
let title = (layer>0 ? ' '.repeat(layer - 1) + '└ ' : '') + albums[i].title
|
||||||
|
let selected = select==albums[i].id ? ' selected="selected"' : ''
|
||||||
|
|
||||||
|
cmbxOptions += `<option${ selected } value='${ albums[i].id }'>${ title }</option>`
|
||||||
|
cmbxOptions += buildAlbumOptions(albums, select, albums[i].id, layer + 1)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmbxOptions
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
album = {
|
album = {
|
||||||
|
|
||||||
json: null,
|
json: null,
|
||||||
@ -146,21 +166,6 @@ album.parse = function() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildAlbumOptions(albums, select, parent = 0, layer = 0) {
|
|
||||||
var cmbxOptions = ''
|
|
||||||
for (i in albums) {
|
|
||||||
if (albums[i].parent == parent) {
|
|
||||||
let title = (layer > 0 ? " ".repeat(layer - 1) + "└ " : "") + albums[i].title
|
|
||||||
cmbxOptions += `<option `;
|
|
||||||
if (select == albums[i].id)
|
|
||||||
cmbxOptions += `selected="selected" `
|
|
||||||
cmbxOptions += `value='` + albums[i].id + `'>` + title + `</option>`
|
|
||||||
cmbxOptions += buildAlbumOptions(albums, select, albums[i].id, layer + 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cmbxOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
album.add = function(albumID = 0) {
|
album.add = function(albumID = 0) {
|
||||||
|
|
||||||
const action = function(data) {
|
const action = function(data) {
|
||||||
@ -249,6 +254,21 @@ album.delete = function(albumIDs) {
|
|||||||
albums.deleteByID(id)
|
albums.deleteByID(id)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
} else if (visible.album()) {
|
||||||
|
|
||||||
|
// if we deleted the current album, go to its parent
|
||||||
|
if (albumIDs.length==1 && album.json.id==albumIDs[0]) {
|
||||||
|
|
||||||
|
let id = album.getParent()
|
||||||
|
album.refresh()
|
||||||
|
lychee.goto(id)
|
||||||
|
|
||||||
|
}
|
||||||
|
// otherwise, we deleted a subalbum
|
||||||
|
else {
|
||||||
|
album.reload()
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
albums.refresh()
|
albums.refresh()
|
||||||
@ -628,7 +648,7 @@ album.getArchive = function(albumID) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
album.merge = function(albumIDs, titles = []) {
|
const getMessage = function(albumIDs, titles, operation) {
|
||||||
|
|
||||||
let title = ''
|
let title = ''
|
||||||
let sTitle = ''
|
let sTitle = ''
|
||||||
@ -653,14 +673,20 @@ album.merge = function(albumIDs, titles = []) {
|
|||||||
// Fallback for second album without a title
|
// Fallback for second album without a title
|
||||||
if (sTitle==='') sTitle = 'Untitled'
|
if (sTitle==='') sTitle = 'Untitled'
|
||||||
|
|
||||||
msg = lychee.html`<p>Are you sure you want to merge the album '$${ sTitle }' into the album '$${ title }'?</p>`
|
msg = lychee.html`<p>Are you sure you want to ${ operation } the album '$${ sTitle }' into '$${ title }'?</p>`
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
msg = lychee.html`<p>Are you sure you want to merge all selected albums into the album '$${ title }'?</p>`
|
msg = lychee.html`<p>Are you sure you want to ${ operation } all selected albums into '$${ title }'?</p>`
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return msg
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
album.merge = function(albumIDs, titles = []) {
|
||||||
|
|
||||||
const action = function() {
|
const action = function() {
|
||||||
|
|
||||||
basicModal.close()
|
basicModal.close()
|
||||||
@ -671,19 +697,15 @@ album.merge = function(albumIDs, titles = []) {
|
|||||||
|
|
||||||
api.post('Album::merge', params, function(data) {
|
api.post('Album::merge', params, function(data) {
|
||||||
|
|
||||||
if (data!==true) {
|
if (data!==true) lychee.error(null, params, data)
|
||||||
lychee.error(null, params, data)
|
else album.reload()
|
||||||
} else {
|
|
||||||
albums.refresh()
|
|
||||||
lychee.goto()
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
basicModal.show({
|
basicModal.show({
|
||||||
body: msg,
|
body: getMessage(albumIDs, titles, 'merge'),
|
||||||
buttons: {
|
buttons: {
|
||||||
action: {
|
action: {
|
||||||
title: 'Merge Albums',
|
title: 'Merge Albums',
|
||||||
@ -697,4 +719,59 @@ album.merge = function(albumIDs, titles = []) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
album.move = function(albumIDs, titles = []) {
|
||||||
|
|
||||||
|
const action = function() {
|
||||||
|
|
||||||
|
basicModal.close()
|
||||||
|
|
||||||
|
let params = {
|
||||||
|
albumIDs: albumIDs.join()
|
||||||
|
}
|
||||||
|
|
||||||
|
api.post('Album::move', params, function(data) {
|
||||||
|
|
||||||
|
if (data!==true) lychee.error(null, params, data)
|
||||||
|
else album.reload()
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
basicModal.show({
|
||||||
|
body: getMessage(albumIDs, titles, 'move'),
|
||||||
|
buttons: {
|
||||||
|
action: {
|
||||||
|
title: 'Move Albums',
|
||||||
|
fn: action,
|
||||||
|
class: 'red'
|
||||||
|
},
|
||||||
|
cancel: {
|
||||||
|
title: "Don't Move",
|
||||||
|
fn: basicModal.close
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
album.reload = function() {
|
||||||
|
|
||||||
|
let albumID = album.getID()
|
||||||
|
|
||||||
|
album.refresh()
|
||||||
|
albums.refresh()
|
||||||
|
|
||||||
|
if (visible.album()) lychee.goto(albumID)
|
||||||
|
else lychee.goto()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
album.refresh = function() {
|
||||||
|
|
||||||
|
album.json = null
|
||||||
|
album.subjson = null
|
||||||
|
|
||||||
}
|
}
|
@ -15,11 +15,11 @@ build.iconic = function(icon, classes = '') {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
build.divider = function(title) {
|
build.divider = function(title, id = '') {
|
||||||
|
|
||||||
let html = ''
|
let html = ''
|
||||||
|
|
||||||
html += lychee.html`<div class='divider'><h1>$${ title }</h1></div>`
|
html += lychee.html`<div class='divider' id='$${ id }'><h1>$${ title }</h1></div>`
|
||||||
|
|
||||||
return html
|
return html
|
||||||
|
|
||||||
|
@ -51,6 +51,24 @@ const getAlbumFrom = function(albums, id) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getSubIDs = function(albums, albumID) {
|
||||||
|
|
||||||
|
let ids = [ albumID ]
|
||||||
|
|
||||||
|
for (a in albums) {
|
||||||
|
if (albums[a].parent==albumID) {
|
||||||
|
|
||||||
|
let sub = getSubIDs(albums, albums[a].id)
|
||||||
|
for (id in sub)
|
||||||
|
ids.push(sub[id])
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ids
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
const countSubAlbums = function(photoIDs) {
|
const countSubAlbums = function(photoIDs) {
|
||||||
|
|
||||||
let count = 0
|
let count = 0
|
||||||
@ -117,12 +135,10 @@ contextMenu.album = function(albumID, e) {
|
|||||||
|
|
||||||
if (album.isSmartID(albumID)) return false
|
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 = [
|
let items = [
|
||||||
{ title: build.iconic('pencil') + 'Rename', fn: () => album.setTitle([ albumID ]) },
|
{ 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('collapse-left') + 'Merge', fn: () => { basicContext.close(); contextMenu.mergeAlbum(albumID, e) } },
|
||||||
|
{ title: build.iconic('folder') + 'Move', fn: () => { basicContext.close(); contextMenu.moveAlbum([ albumID ], e) } },
|
||||||
{ title: build.iconic('trash') + 'Delete', fn: () => album.delete([ albumID ]) }
|
{ title: build.iconic('trash') + 'Delete', fn: () => album.delete([ albumID ]) }
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -140,13 +156,11 @@ contextMenu.albumMulti = function(albumIDs, e) {
|
|||||||
// Show list of albums otherwise
|
// Show list of albums otherwise
|
||||||
let autoMerge = (albumIDs.length>1 ? true : false)
|
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 = [
|
let items = [
|
||||||
{ title: build.iconic('pencil') + 'Rename All', fn: () => album.setTitle(albumIDs) },
|
{ 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 All', visible: 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('collapse-left') + 'Merge', visible: !autoMerge, fn: () => { basicContext.close(); contextMenu.mergeAlbum(albumIDs[0], e) } },
|
||||||
|
{ title: build.iconic('folder') + 'Move All', fn: () => { basicContext.close(); contextMenu.moveAlbum(albumIDs, e) } },
|
||||||
{ title: build.iconic('trash') + 'Delete All', fn: () => album.delete(albumIDs) }
|
{ title: build.iconic('trash') + 'Delete All', fn: () => album.delete(albumIDs) }
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -193,7 +207,7 @@ contextMenu.mergeAlbum = function(albumID, e) {
|
|||||||
// It's not possible to move them into us
|
// It's not possible to move them into us
|
||||||
let exclude = [ albumID ]
|
let exclude = [ albumID ]
|
||||||
let a = getAlbumFrom(data.albums, selalbum.parent)
|
let a = getAlbumFrom(data.albums, selalbum.parent)
|
||||||
while (a != null) {
|
while (a!=null) {
|
||||||
exclude.push(a.id)
|
exclude.push(a.id)
|
||||||
a = getAlbumFrom(data.albums, a.parent)
|
a = getAlbumFrom(data.albums, a.parent)
|
||||||
}
|
}
|
||||||
@ -210,6 +224,38 @@ contextMenu.mergeAlbum = function(albumID, e) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
contextMenu.moveAlbum = function(albumIDs, e) {
|
||||||
|
|
||||||
|
api.post('Albums::get', { parent: -1 }, function(data) {
|
||||||
|
|
||||||
|
let items = []
|
||||||
|
|
||||||
|
if (data.albums && data.num>1) {
|
||||||
|
|
||||||
|
let title = albums.getByID(albumIDs[0]).title
|
||||||
|
// Disable all childs
|
||||||
|
// It's not possible to move us into them
|
||||||
|
let exclude = []
|
||||||
|
for (i in albumIDs) {
|
||||||
|
let sub = getSubIDs(data.albums, String(albumIDs[i]))
|
||||||
|
for (s in sub)
|
||||||
|
exclude.push(sub[s])
|
||||||
|
}
|
||||||
|
|
||||||
|
items = buildAlbumList(data.albums, exclude, (a) => album.move([ a.id ].concat(albumIDs), [ a.title, title ]), 0, 1)
|
||||||
|
|
||||||
|
items.unshift({ title: 'Root', fn: () => album.move([ 0 ].concat(albumIDs), [ 'Root', title ]) })
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (items.length===0) return false
|
||||||
|
|
||||||
|
basicContext.show(items, e.originalEvent, contextMenu.close)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
contextMenu.photo = function(photoID, e) {
|
contextMenu.photo = function(photoID, e) {
|
||||||
|
|
||||||
// Notice for 'Move':
|
// Notice for 'Move':
|
||||||
|
@ -141,8 +141,8 @@ header.setMode = function(mode) {
|
|||||||
header.dom('.header__toolbar--album').addClass('header__toolbar--visible')
|
header.dom('.header__toolbar--album').addClass('header__toolbar--visible')
|
||||||
|
|
||||||
// Hide download button when album empty
|
// Hide download button when album empty
|
||||||
if (album.json.content===false) $('#button_archive').hide()
|
if (album.json.content===false && album.subjson.num==0) $('#button_archive').hide()
|
||||||
else $('#button_archive').show()
|
else $('#button_archive').show()
|
||||||
|
|
||||||
// Hide download button when not logged in and album not downloadable
|
// Hide download button when not logged in and album not downloadable
|
||||||
if (lychee.publicMode===true && album.json.downloadable==='0') $('#button_archive').hide()
|
if (lychee.publicMode===true && album.json.downloadable==='0') $('#button_archive').hide()
|
||||||
|
@ -158,7 +158,7 @@ view.album = {
|
|||||||
|
|
||||||
if (album.json.content && album.json.content!==false) {
|
if (album.json.content && album.json.content!==false) {
|
||||||
|
|
||||||
photosData += build.divider('Photos')
|
photosData += build.divider('Photos', 'divider-photos')
|
||||||
|
|
||||||
// Build photos
|
// Build photos
|
||||||
$.each(album.json.content, function() {
|
$.each(album.json.content, function() {
|
||||||
@ -236,6 +236,7 @@ view.album = {
|
|||||||
if (!visible.albums()) {
|
if (!visible.albums()) {
|
||||||
album.json.num--
|
album.json.num--
|
||||||
view.album.num()
|
view.album.num()
|
||||||
|
if (album.json.num == 0) $('#divider-photos').hide()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user