diff --git a/pandora/app/config.py b/pandora/app/config.py index db6093f0..3a9dd36d 100644 --- a/pandora/app/config.py +++ b/pandora/app/config.py @@ -262,6 +262,8 @@ def update_static(): pandora_json = os.path.join(settings.STATIC_ROOT, 'json/pandora.json') for root, folders, files in os.walk(os.path.join(settings.STATIC_ROOT, 'js')): for f in files: + if f.startswith('._'): + continue f = os.path.join(root, f) #ignore old embed js file if 'js/embed/' in f: diff --git a/pandora/document/views.py b/pandora/document/views.py index 63ef06a2..a95ca06e 100644 --- a/pandora/document/views.py +++ b/pandora/document/views.py @@ -132,14 +132,19 @@ def editDocument(request, data): response = json_response() item = 'item' in data and Item.objects.get(public_id=data['item']) or None if data['id']: - document = models.Document.get(data['id']) - if document.editable(request.user, item): - add_changelog(request, data) - document.edit(data, request.user, item) - document.save() - response['data'] = document.json(user=request.user, item=item) + if isinstance(data['id'], list): + documents = models.Document.objects.filter(pk__in=map(ox.fromAZ, data['id'])) else: - response = json_response(status=403, text='permission denied') + documents = [models.Document.get(data['id'])] + for document in documents: + if document.editable(request.user, item): + if document == documents[0]: + add_changelog(request, data) + document.edit(data, request.user, item) + document.save() + response['data'] = document.json(user=request.user, item=item) + else: + response = json_response(status=403, text='permission denied') else: response = json_response(status=500, text='invalid request') return render_to_json_response(response) diff --git a/pandora/item/views.py b/pandora/item/views.py index 3600086e..02d8f924 100644 --- a/pandora/item/views.py +++ b/pandora/item/views.py @@ -622,14 +622,19 @@ def edit(request, data): } see: add, find, get, lookup, remove, upload ''' - item = get_object_or_404_json(models.Item, public_id=data['id']) - if item.editable(request.user): - request_data = data.copy() - response = edit_item(request, item, data) - response['data'] = item.json() - add_changelog(request, request_data) + if isinstance(data['id'], list): + items = models.Item.objects.filter(public_id__in=data['id']) else: - response = json_response(status=403, text='permission denied') + items = [get_object_or_404_json(models.Item, public_id=data['id'])] + for item in items: + if item.editable(request.user): + request_data = data.copy() + response = edit_item(request, item, data) + response['data'] = item.json() + if item == items[0]: + add_changelog(request, request_data) + else: + response = json_response(status=403, text='permission denied') return render_to_json_response(response) actions.register(edit, cache=False) diff --git a/static/js/documentInfoView.js b/static/js/documentInfoView.js index e390da5a..592afd45 100644 --- a/static/js/documentInfoView.js +++ b/static/js/documentInfoView.js @@ -1,9 +1,11 @@ 'use strict'; -pandora.ui.documentInfoView = function(data) { +pandora.ui.documentInfoView = function(data, isMixed) { + isMixed = isMixed || {}; var ui = pandora.user.ui, - canEdit = pandora.hasCapability('canEditMetadata') || data.editable, + isMultiple = arguments.length == 2, + canEdit = pandora.hasCapability('canEditMetadata') || isMultiple || data.editable, canRemove = pandora.hasCapability('canRemoveItems'), css = { marginTop: '4px', @@ -11,8 +13,8 @@ pandora.ui.documentInfoView = function(data) { }, html, iconRatio = data.ratio, - iconSize = ui.infoIconSize, - iconWidth = iconRatio > 1 ? iconSize : Math.round(iconSize * iconRatio), + iconSize = isMultiple ? 0 : ui.infoIconSize, + iconWidth = isMultiple ? 0 : iconRatio > 1 ? iconSize : Math.round(iconSize * iconRatio), iconHeight = iconRatio < 1 ? iconSize : Math.round(iconSize / iconRatio), iconLeft = iconSize == 256 ? Math.floor((iconSize - iconWidth) / 2) : 0, margin = 16, @@ -103,63 +105,65 @@ pandora.ui.documentInfoView = function(data) { that = Ox.SplitPanel({ elements: [ - {element: $bar, size: 16}, + {element: $bar, size: isMultiple ? 0 : 16}, {element: $info} ], orientation: 'vertical' - }), + }); - $icon = Ox.Element({ - element: '', - }) - .attr({ - src: '/documents/' + data.id + '/512p.jpg?' + data.modified - }) - .css({ - position: 'absolute', - left: margin + iconLeft + 'px', - top: margin + 'px', - width: iconWidth + 'px', - height: iconHeight + 'px' - }) - .bindEvent({ - // singleclick: toggleIconSize - }) - .appendTo($info), + if (!isMultiple) { + var $icon = Ox.Element({ + element: '', + }) + .attr({ + src: '/documents/' + data.id + '/512p.jpg?' + data.modified + }) + .css({ + position: 'absolute', + left: margin + iconLeft + 'px', + top: margin + 'px', + width: iconWidth + 'px', + height: iconHeight + 'px' + }) + .bindEvent({ + // singleclick: toggleIconSize + }) + .appendTo($info), - $reflection = $('
') - .addClass('OxReflection') - .css({ - position: 'absolute', - left: margin + 'px', - top: margin + iconHeight + 'px', - width: iconSize + 'px', - height: iconSize / 2 + 'px', - overflow: 'hidden' - }) - .appendTo($info), + $reflection = $('
') + .addClass('OxReflection') + .css({ + position: 'absolute', + left: margin + 'px', + top: margin + iconHeight + 'px', + width: iconSize + 'px', + height: iconSize / 2 + 'px', + overflow: 'hidden' + }) + .appendTo($info), - $reflectionIcon = $('') - .attr({ - src: '/documents/' + data.id + '/512p.jpg?' + data.modified - }) - .css({ - position: 'absolute', - left: iconLeft + 'px', - width: iconWidth + 'px', - height: iconHeight + 'px', - }) - .appendTo($reflection), + $reflectionIcon = $('') + .attr({ + src: '/documents/' + data.id + '/512p.jpg?' + data.modified + }) + .css({ + position: 'absolute', + left: iconLeft + 'px', + width: iconWidth + 'px', + height: iconHeight + 'px', + }) + .appendTo($reflection), - $reflectionGradient = $('
') - .css({ - position: 'absolute', - width: iconSize + 'px', - height: iconSize / 2 + 'px' - }) - .appendTo($reflection), + $reflectionGradient = $('
') + .css({ + position: 'absolute', + width: iconSize + 'px', + height: iconSize / 2 + 'px' + }) + .appendTo($reflection); + } - $text = Ox.Element() + var $text = Ox.Element() .addClass('OxTextPage') .css({ position: 'absolute', @@ -263,13 +267,13 @@ pandora.ui.documentInfoView = function(data) { } // Referenced -------------------------------------------------------------- - if ( + !isMultiple && ( data.referenced.items.length || data.referenced.annotations.length || data.referenced.documents.length || data.referenced.entities.length - ) { + )) { var itemsById = {} data.referenced.items.forEach(function(item) { @@ -287,7 +291,6 @@ pandora.ui.documentInfoView = function(data) { itemsById[itemId].annotations = itemsById[itemId].annotations.concat(annotation); }); var html = Ox.sortBy(Object.values(itemsById), 'title').map(function(item) { - console.log('item', item) return (item.referenced ? '' : '') + item.title //Ox.encodeHTMLEntities(item.title) + (item.referenced ? '' : '') @@ -360,7 +363,9 @@ pandora.ui.documentInfoView = function(data) { function editMetadata(key, value) { if (value != data[key]) { - var edit = {id: data.id}; + var edit = { + id: isMultiple ? ui.collectionSelection : data.id, + }; if (key == 'title') { edit[key] = value; } else if (listKeys.indexOf(key) >= 0) { @@ -369,17 +374,20 @@ pandora.ui.documentInfoView = function(data) { edit[key] = value ? value : null; } pandora.api.editDocument(edit, function(result) { - var src; - data[key] = result.data[key]; - Ox.Request.clearCache(); // fixme: too much? can change filter/list etc - if (result.data.id != data.id) { - pandora.UI.set({document: result.data.id}); - pandora.$ui.browser.value(data.id, 'id', result.data.id); + if (!isMultiple) { + var src; + data[key] = result.data[key]; + Ox.Request.clearCache(); // fixme: too much? can change filter/list etc + if (result.data.id != data.id) { + pandora.UI.set({document: result.data.id}); + pandora.$ui.browser.value(data.id, 'id', result.data.id); + } + //pandora.updateItemContext(); + //pandora.$ui.browser.value(result.data.id, key, result.data[key]); + pandora.$ui.itemTitle + .options({title: '' + (pandora.getDocumentTitle(result.data)) + ''}); } - //pandora.updateItemContext(); - //pandora.$ui.browser.value(result.data.id, key, result.data[key]); - pandora.$ui.itemTitle - .options({title: '' + (pandora.getDocumentTitle(result.data)) + ''}); + that.triggerEvent('change', Ox.extend({}, key, value)); }); } } @@ -421,7 +429,11 @@ pandora.ui.documentInfoView = function(data) { } else if (['type', 'publisher'].indexOf(key) > -1) { ret = formatLink(value, key); } else { - ret = pandora.formatDocumentKey(Ox.getObjectById(pandora.site.documentKeys, key), data); + if (isMixed[key]) { + ret = 'Mixed' + } else { + ret = pandora.formatDocumentKey(Ox.getObjectById(pandora.site.documentKeys, key), data); + } } return ret; } @@ -533,7 +545,7 @@ pandora.ui.documentInfoView = function(data) { format: function(value) { return formatValue(key, value); }, - placeholder: formatLight(Ox._('unknown')), + placeholder: formatLight(Ox._(isMixed[key] ? 'mixed' : 'unknown')), tooltip: canEdit ? pandora.getEditTooltip() : '', value: getValue(key, data[key]) }) @@ -576,8 +588,12 @@ pandora.ui.documentInfoView = function(data) { .css({background: $rightsLevelElement.css('background')}) .data({OxColor: $rightsLevelElement.data('OxColor')}) //renderCapabilities(rightsLevel); - pandora.api.editDocument({id: data.id, rightslevel: rightsLevel}, function(result) { - // ... + var edit = { + id: isMultiple ? ui.collectionSelection : data.id, + rightslevel: rightsLevel + }; + pandora.api.editDocument(edit, function(result) { + that.triggerEvent('change', Ox.extend({}, 'rightslevel', rightsLevel)); }); } }) diff --git a/static/js/editDialog.js b/static/js/editDialog.js new file mode 100644 index 00000000..6ad47d02 --- /dev/null +++ b/static/js/editDialog.js @@ -0,0 +1,124 @@ +'use strict'; + +pandora.ui.editDialog = function() { + + var ui = pandora.user.ui, + hasChanged = false, + ids = ui.listSelection.filter(function(id) { + return pandora.$ui.list.value(id, 'editable'); + }), + keys = pandora.site.itemKeys.filter(function(key) { + return key.id != '*' + }).map(function(key) { + return key.id + }), + listKeys = pandora.site.itemKeys.filter(function(key) { + return Ox.isArray(key.type); + }).map(function(key){ + return key.id; + }), + mixed = ' ', + separator = '; ', + tooltip = Ox._('Doubleclick to edit'), + + $info = Ox.Element() + .addClass('OxSelectable') + .css({padding: '16px'}); + + var that = Ox.Dialog({ + buttons: [ + Ox.Button({ + style: 'squared', + title: Ox._('Done') + }) + .bindEvent({ + click: function() { + if (!ui.updateResults && hasChanged) { + pandora.$ui.list.reloadList() + } + that.close(); + } + }) + ], + closeButton: true, + content: Ox.LoadingScreen().start(), + height: 576, + removeOnClose: true, + title: Ox._('Edit Metadata for {0}', [ + Ox.formatNumber(ids.length) + ' ' + Ox._( + ids.length == 1 ? pandora.site.itemName.singular : pandora.site.itemName.plural + ) + ]), + width: 768 + }), + + $updateCheckbox = Ox.Checkbox({ + style: 'squared', + title: Ox._('Update Results in the Background'), + value: ui.updateResults + }) + .css({ + float: 'left', + margin: '4px' + }) + .bindEvent({ + change: function(data) { + pandora.UI.set({updateResults: data.value}); + } + }); + + /* + $($updateCheckbox.find('.OxButton')[0]).css({margin: 0}); + $(that.find('.OxBar')[1]).append($updateCheckbox); + */ + + getMetadata(); + + function getMetadata(callback) { + pandora.api.find({ + keys: keys, + query: { + conditions: ids.map(function(id) { + return { + key: 'id', + operator: '==', + value: id + }; + }), + operator: '|' + } + }, function(result) { + var data = {}, + isMixed = {}, + items = result.data.items; + keys.forEach(function(key) { + var isArray = Ox.contains(listKeys, key), + values = items.map(function(item) { + return item[key]; + }); + if (isArray) { + values = values.map(function(value) { + return (value || []).join(separator); + }); + } + if (Ox.unique(values).length > 1) { + isMixed[key] = true; + } + data[key] = isMixed[key] ? null + : isArray ? values[0].split(separator) + : values[0]; + }); + that.options({ + content: pandora.ui.infoView(data, isMixed).bindEvent({ + change: function() { + hasChanged = true; + Ox.Request.clearCache(); + } + }) + }); + }); + } + + return that; + +}; diff --git a/static/js/editDocumentsDialog.js b/static/js/editDocumentsDialog.js new file mode 100644 index 00000000..3c5cb1b8 --- /dev/null +++ b/static/js/editDocumentsDialog.js @@ -0,0 +1,124 @@ +'use strict'; + +pandora.ui.editDocumentsDialog = function() { + var ui = pandora.user.ui, + hasChanged = false, + ids = ui.collectionSelection.filter(function(id) { + return pandora.$ui.list.value(id, 'editable'); + }), + keys = pandora.site.documentKeys.filter(function(key) { + return key.id != '*' + }).map(function(key) { + return key.id + }), + listKeys = pandora.site.documentKeys.filter(function(key) { + return Ox.isArray(key.type); + }).map(function(key){ + return key.id; + }), + mixed = ' ', + separator = '; ', + tooltip = Ox._('Doubleclick to edit'), + + $info = Ox.Element() + .addClass('OxSelectable') + .css({padding: '16px'}); + + var that = Ox.Dialog({ + buttons: [ + Ox.Button({ + style: 'squared', + title: Ox._('Done') + }) + .bindEvent({ + click: function() { + if (!ui.updateResults && hasChanged) { + pandora.$ui.list.reloadList() + } + that.close(); + } + }) + ], + closeButton: true, + content: Ox.LoadingScreen().start(), + height: 576, + removeOnClose: true, + title: Ox._('Edit Metadata for {0}', [ + Ox.formatNumber(ids.length) + ' ' + Ox._( + ids.length == 1 ? 'Document' : 'Documents' + ) + ]), + width: 768 + }), + + $updateCheckbox = Ox.Checkbox({ + style: 'squared', + title: Ox._('Update Results in the Background'), + value: ui.updateResults + }) + .css({ + float: 'left', + margin: '4px' + }) + .bindEvent({ + change: function(data) { + pandora.UI.set({updateResults: data.value}); + } + }); + + /* + $($updateCheckbox.find('.OxButton')[0]).css({margin: 0}); + $(that.find('.OxBar')[1]).append($updateCheckbox); + */ + + getMetadata(); + + function getMetadata(callback) { + pandora.api.findDocuments({ + keys: keys, + query: { + conditions: ids.map(function(id) { + return { + key: 'id', + operator: '==', + value: id + }; + }), + operator: '|' + } + }, function(result) { + var data = {}, + isMixed = {}, + items = result.data.items; + keys.forEach(function(key) { + var isArray = Ox.contains(listKeys, key), + values = items.map(function(item) { + return item[key]; + }); + if (isArray) { + values = values.map(function(value) { + return (value || []).join(separator); + }); + } + if (Ox.unique(values).length > 1) { + isMixed[key] = true; + } + console.log(key, values) + data[key] = isMixed[key] ? null + : isArray && values.length ? values[0].split(separator) + : values[0]; + }); + that.options({ + content: pandora.ui.documentInfoView(data, isMixed).bindEvent({ + change: function() { + hasChanged = true; + Ox.Request.clearCache(); + } + }) + }); + }); + } + + return that; + +}; diff --git a/static/js/infoView.0xdb.js b/static/js/infoView.0xdb.js index c6a849ec..273acb62 100644 --- a/static/js/infoView.0xdb.js +++ b/static/js/infoView.0xdb.js @@ -1,14 +1,16 @@ 'use strict'; -pandora.ui.infoView = function(data) { +pandora.ui.infoView = function(data, isMixed) { + isMixed = isMixed || {}; // fixme: given that currently, the info view doesn't scroll into view nicely // when collapsing the movies browser, the info view should become a split panel var ui = pandora.user.ui, - canEdit = pandora.hasCapability('canEditMetadata'), + isMultiple = arguments.length == 2, + canEdit = pandora.hasCapability('canEditMetadata') || isMultiple || data.editable, canRemove = pandora.hasCapability('canRemoveItems'), - canSeeAllMetadata = pandora.user.level != 'guest', + canSeeAllMetadata = pandora.user.level != 'guest' && !isMultiple, css = { marginTop: '4px', textAlign: 'justify' @@ -16,12 +18,15 @@ pandora.ui.infoView = function(data) { iconRatio = ui.icons == 'posters' ? ( ui.showSitePosters ? pandora.site.posters.ratio : data.posterRatio ) : 1, - iconSize = ui.infoIconSize, - iconWidth = iconRatio > 1 ? iconSize : Math.round(iconSize * iconRatio), + iconSize = isMultiple ? 0 : ui.infoIconSize, + iconWidth = isMultiple ? 0 : iconRatio > 1 ? iconSize : Math.round(iconSize * iconRatio), iconHeight = iconRatio < 1 ? iconSize : Math.round(iconSize / iconRatio), iconLeft = iconSize == 256 ? Math.floor((iconSize - iconWidth) / 2) : 0, borderRadius = ui.icons == 'posters' ? 0 : iconSize / 8, - isEditable = canEdit && data.id.slice(0, 2) == '0x', + isEditable = canEdit && (isMultiple + ? !ui.listSelection.some(function(id) { return id.slice(0, 2) != '0x' }) + : data.id.slice(0, 2) == '0x' + ), listWidth = 144 + Ox.UI.SCROLLBAR_SIZE, margin = 16, statisticsWidth = 128, @@ -101,7 +106,7 @@ pandora.ui.infoView = function(data) { that = Ox.SplitPanel({ elements: [ - {element: $bar, size: 16}, + {element: $bar, size: isMultiple ? 0 : 16}, {element: $main} ], orientation: 'vertical' @@ -126,73 +131,75 @@ pandora.ui.infoView = function(data) { right: 0, height: getHeight() + 'px' }) - .appendTo($info), + .appendTo($info); - $icon = Ox.Element({ - element: '', - tooltip: canEdit ? ( - !ui.showIconBrowser - ? Ox._('Doubleclick to edit icon') - : Ox._('Doubleclick to hide icons') - ) : '' - }) - .attr({ - src: pandora.getMediaURL('/' + data.id + '/' + ( - ui.icons == 'posters' - ? (ui.showSitePosters ? 'siteposter' : 'poster') : 'icon' - ) + '512.jpg?' + data.modified) - }) - .css({ - position: 'absolute', - left: margin + iconLeft + 'px', - top: margin + 'px', - width: iconWidth + 'px', - height: iconHeight + 'px', - borderRadius: borderRadius + 'px', - cursor: 'pointer' - }) - .bindEvent({ - singleclick: toggleIconSize - }) - .appendTo($data.$element), + if (!isMultiple) { + var $icon = Ox.Element({ + element: '', + tooltip: canEdit ? ( + !ui.showIconBrowser + ? Ox._('Doubleclick to edit icon') + : Ox._('Doubleclick to hide icons') + ) : '' + }) + .attr({ + src: pandora.getMediaURL('/' + data.id + '/' + ( + ui.icons == 'posters' + ? (ui.showSitePosters ? 'siteposter' : 'poster') : 'icon' + ) + '512.jpg?' + data.modified) + }) + .css({ + position: 'absolute', + left: margin + iconLeft + 'px', + top: margin + 'px', + width: iconWidth + 'px', + height: iconHeight + 'px', + borderRadius: borderRadius + 'px', + cursor: 'pointer' + }) + .bindEvent({ + singleclick: toggleIconSize + }) + .appendTo($data.$element), - $reflection = $('
') - .addClass('OxReflection') - .css({ - position: 'absolute', - left: margin + 'px', - top: margin + iconHeight + 'px', - width: iconSize + 'px', - height: Math.round(iconSize / 2) + 'px', - overflow: 'hidden' - }) - .appendTo($data.$element), + $reflection = $('
') + .addClass('OxReflection') + .css({ + position: 'absolute', + left: margin + 'px', + top: margin + iconHeight + 'px', + width: iconSize + 'px', + height: Math.round(iconSize / 2) + 'px', + overflow: 'hidden' + }) + .appendTo($data.$element), - $reflectionIcon = $('') - .attr({ - src: pandora.getMediaURL('/' + data.id + '/' + ( - ui.icons == 'posters' - ? (ui.showSitePosters ? 'siteposter' : 'poster') : 'icon' - ) + '512.jpg?' + data.modified) - }) - .css({ - position: 'absolute', - left: iconLeft + 'px', - width: iconWidth + 'px', - height: iconHeight + 'px', - borderRadius: borderRadius + 'px' - }) - .appendTo($reflection), + $reflectionIcon = $('') + .attr({ + src: pandora.getMediaURL('/' + data.id + '/' + ( + ui.icons == 'posters' + ? (ui.showSitePosters ? 'siteposter' : 'poster') : 'icon' + ) + '512.jpg?' + data.modified) + }) + .css({ + position: 'absolute', + left: iconLeft + 'px', + width: iconWidth + 'px', + height: iconHeight + 'px', + borderRadius: borderRadius + 'px' + }) + .appendTo($reflection), - $reflectionGradient = $('
') - .css({ - position: 'absolute', - width: iconSize + 'px', - height: Math.round(iconSize / 2) + 'px' - }) - .appendTo($reflection), + $reflectionGradient = $('
') + .css({ + position: 'absolute', + width: iconSize + 'px', + height: Math.round(iconSize / 2) + 'px' + }) + .appendTo($reflection); + } - $text = Ox.Element() + var $text = Ox.Element() .addClass('OxTextPage') .css({ position: 'absolute', @@ -228,7 +235,7 @@ pandora.ui.infoView = function(data) { pandora.createLinks($text); // Title ------------------------------------------------------------------- - + if (!isMultiple) { $('
') .css({ marginTop: '-2px' @@ -255,6 +262,7 @@ pandora.ui.infoView = function(data) { }) ) .appendTo($text); + } // Director ---------------------------------------------------------------- @@ -270,7 +278,7 @@ pandora.ui.infoView = function(data) { format: function(value) { return formatValue(value.split(', '), 'name'); }, - placeholder: formatLight(Ox._('Unknown Director')), + placeholder: formatLight(Ox._(isMixed.director ? 'Mixed Director' : 'Unknown Director')), tooltip: isEditable ? pandora.getEditTooltip() : '', value: data.director ? data.director.join(', ') : '' }) @@ -306,7 +314,7 @@ pandora.ui.infoView = function(data) { format: function(value) { return formatValue(value.split(', '), key) }, - placeholder: formatLight('unknown'), + placeholder: formatLight(isMixed[key] ? 'mixed' : 'unknown'), tooltip: pandora.getEditTooltip(), value: key == 'country' ? (data[key] ? data[key].join(', ') : ['']) @@ -320,7 +328,7 @@ pandora.ui.infoView = function(data) { }) .appendTo($div); }); - } else if (data.country || data.year || data.language || data.runtime || data.color || data.sound) { + } else if (!isMultiple && (data.country || data.year || data.language || data.runtime || data.color || data.sound)) { var html = []; ['country', 'year', 'language', 'runtime', 'color', 'sound'].forEach(function(key) { if (data[key]) { @@ -379,7 +387,7 @@ pandora.ui.infoView = function(data) { key == 'episodeDirector' ? 'name' : 'year' ); }, - placeholder: formatLight('unknown'), + placeholder: formatLight(Ox._(isMixed[key] ? 'mixed' : 'unknown')), tooltip: pandora.getEditTooltip(), value: key == 'episodeDirector' ? (data[key] ? data[key].join(', ') : ['']) @@ -393,7 +401,7 @@ pandora.ui.infoView = function(data) { }) .appendTo($div); }); - } else if (data.episodeDirector || data.writer || data.producer || data.cinematographer || data.editor) { + } else if (!isMultiple && (data.episodeDirector || data.writer || data.producer || data.cinematographer || data.editor)) { $div = $('
') .addClass('OxSelectable') .css(css) @@ -435,7 +443,7 @@ pandora.ui.infoView = function(data) { .appendTo($text); } - if (data.genre || (data.keyword && canSeeAllMetadata)) { + if (!isMultiple && (data.genre || (data.keyword && canSeeAllMetadata))) { $div = $('
') .addClass('OxSelectable') .css(css) @@ -456,8 +464,7 @@ pandora.ui.infoView = function(data) { .html(formatKey('summary') + data.summary) .appendTo($text); - if (canSeeAllMetadata) { - + if (!isMultiple && canSeeAllMetadata) { data.trivia && data.trivia.forEach(function(value) { $('
') .css({ @@ -570,7 +577,7 @@ pandora.ui.infoView = function(data) { $('
').css({height: '16px'}).appendTo($text); // Mainstream Score, Arthouse Score ---------------------------------------- - + if (!isMultiple) { ['votes', 'likes'].forEach(function(key) { var value = data[key] || 0; $('
') @@ -597,7 +604,6 @@ pandora.ui.infoView = function(data) { }); // Duration, Aspect Ratio -------------------------------------------------- - ['duration', 'aspectratio'].forEach(function(key) { var itemKey = Ox.getObjectById(pandora.site.itemKeys, key), value = data[key] || 0; @@ -669,6 +675,7 @@ pandora.ui.infoView = function(data) { ) .appendTo($statistics); }); + } // Rights Level ------------------------------------------------------------ @@ -689,7 +696,7 @@ pandora.ui.infoView = function(data) { .append( Ox.EditableContent({ clickLink: pandora.clickLink, - placeholder: formatLight(Ox._('No notes')), + placeholder: formatLight(Ox._(isMixed.notes ? 'Mixed notes' : 'No notes')), tooltip: pandora.getEditTooltip(), type: 'textarea', value: data.notes || '', @@ -697,12 +704,7 @@ pandora.ui.infoView = function(data) { }) .bindEvent({ submit: function(event) { - pandora.api.edit({ - id: data.id, - notes: event.value - }, function(result) { - // ... - }); + editMetadata('notes', event.value); } }) ) @@ -711,7 +713,7 @@ pandora.ui.infoView = function(data) { $('
').css({height: '16px'}).appendTo($statistics); - if (canEdit) { + if (canEdit && !isMultiple) { $icon.bindEvent({ doubleclick: function() { pandora.UI.set({showIconBrowser: !ui.showIconBrowser}); @@ -730,7 +732,7 @@ pandora.ui.infoView = function(data) { function editMetadata(key, value) { if (value != data[key]) { - var edit = {id: data.id}; + var edit = {id: isMultiple ? ui.listSelection : data.id}; if (key == 'title') { Ox.extend(edit, parseTitle(value)); } else if (['director', 'country'].indexOf(key) > -1) { @@ -739,14 +741,17 @@ pandora.ui.infoView = function(data) { edit[key] = value; } pandora.api.edit(edit, function(result) { - if (result.data.id != data.id) { - Ox.Request.clearCache(); // fixme: too much - pandora.UI.set({item: result.data.id}); - pandora.$ui.browser.value(data.id, 'id', result.data.id); - // FIXME: does this update selected? + if (!isMultiple) { + if (result.data.id != data.id) { + Ox.Request.clearCache(); // fixme: too much + pandora.UI.set({item: result.data.id}); + pandora.$ui.browser.value(data.id, 'id', result.data.id); + // FIXME: does this update selected? + } + pandora.updateItemContext(); + pandora.$ui.browser.value(result.data.id, key, result.data[key]); } - pandora.updateItemContext(); - pandora.$ui.browser.value(result.data.id, key, result.data[key]); + that.triggerEvent('change', Ox.extend({}, key, value)); }); } } @@ -1059,8 +1064,12 @@ pandora.ui.infoView = function(data) { .css({background: $rightsLevelElement.css('background')}) .data({OxColor: $rightsLevelElement.data('OxColor')}) renderCapabilities(rightsLevel); - pandora.api.edit({id: data.id, rightslevel: rightsLevel}, function(result) { - // ... + var edit = { + id: isMultiple ? ui.listSelection : data.id, + rightslevel: rightsLevel + }; + pandora.api.edit(edit, function(result) { + that.triggerEvent('change', Ox.extend({}, 'rightslevel', rightsLevel)); }); } }) diff --git a/static/js/infoView.indiancinema.js b/static/js/infoView.indiancinema.js index 4818be62..ef1e7499 100644 --- a/static/js/infoView.indiancinema.js +++ b/static/js/infoView.indiancinema.js @@ -1,9 +1,11 @@ 'use strict'; -pandora.ui.infoView = function(data) { +pandora.ui.infoView = function(data, isMixed) { + isMixed = isMixed || {}; var ui = pandora.user.ui, - canEdit = pandora.hasCapability('canEditMetadata'), + isMultiple = arguments.length == 2, + canEdit = pandora.hasCapability('canEditMetadata') || isMultiple || data.editable, canRemove = pandora.hasCapability('canRemoveItems'), canSeeAllMetadata = pandora.user.level != 'guest', css = { @@ -13,8 +15,8 @@ pandora.ui.infoView = function(data) { iconRatio = ui.icons == 'posters' ? ( ui.showSitePosters ? pandora.site.posters.ratio : data.posterRatio ) : 1, - iconSize = ui.infoIconSize, - iconWidth = iconRatio > 1 ? iconSize : Math.round(iconSize * iconRatio), + iconSize = isMultiple ? 0 : ui.infoIconSize, + iconWidth = isMultiple ? 0 : iconRatio > 1 ? iconSize : Math.round(iconSize * iconRatio), iconHeight = iconRatio < 1 ? iconSize : Math.round(iconSize / iconRatio), iconLeft = iconSize == 256 ? Math.floor((iconSize - iconWidth) / 2) : 0, borderRadius = ui.icons == 'posters' ? 0 : iconSize / 8, @@ -133,71 +135,73 @@ pandora.ui.infoView = function(data) { that = Ox.SplitPanel({ elements: [ - {element: $bar, size: 16}, + {element: $bar, size: isMultiple ? 0 : 16}, {element: $info} ], orientation: 'vertical' - }), + }); - $icon = Ox.Element({ - element: '' - }) - .attr({ - src: pandora.getMediaURL('/' + data.id + '/' + ( - ui.icons == 'posters' ? 'poster' : 'icon' - ) + '512.jpg?' + data.modified) - }) - .css({ - position: 'absolute', - left: margin + iconLeft + 'px', - top: margin + 'px', - width: iconWidth + 'px', - height: iconHeight + 'px', - borderRadius: borderRadius + 'px', - cursor: 'pointer' - }) - .bindEvent({ - singleclick: toggleIconSize - }) - .appendTo($info), + if (!isMultiple) { + var $icon = Ox.Element({ + element: '' + }) + .attr({ + src: pandora.getMediaURL('/' + data.id + '/' + ( + ui.icons == 'posters' ? 'poster' : 'icon' + ) + '512.jpg?' + data.modified) + }) + .css({ + position: 'absolute', + left: margin + iconLeft + 'px', + top: margin + 'px', + width: iconWidth + 'px', + height: iconHeight + 'px', + borderRadius: borderRadius + 'px', + cursor: 'pointer' + }) + .bindEvent({ + singleclick: toggleIconSize + }) + .appendTo($info), - $reflection = $('
') - .addClass('OxReflection') - .css({ - position: 'absolute', - left: margin + 'px', - top: margin + iconHeight + 'px', - width: iconSize + 'px', - height: Math.round(iconSize / 2) + 'px', - overflow: 'hidden' - }) - .appendTo($info), + $reflection = $('
') + .addClass('OxReflection') + .css({ + position: 'absolute', + left: margin + 'px', + top: margin + iconHeight + 'px', + width: iconSize + 'px', + height: Math.round(iconSize / 2) + 'px', + overflow: 'hidden' + }) + .appendTo($info), - $reflectionIcon = $('') - .attr({ - src: pandora.getMediaURL('/' + data.id + '/' + ( - ui.icons == 'posters' - ? (ui.showSitePosters ? 'siteposter' : 'poster') : 'icon' - ) + '512.jpg?' + data.modified) - }) - .css({ - position: 'absolute', - left: iconLeft + 'px', - width: iconWidth + 'px', - height: iconHeight + 'px', - borderRadius: borderRadius + 'px' - }) - .appendTo($reflection), + $reflectionIcon = $('') + .attr({ + src: pandora.getMediaURL('/' + data.id + '/' + ( + ui.icons == 'posters' + ? (ui.showSitePosters ? 'siteposter' : 'poster') : 'icon' + ) + '512.jpg?' + data.modified) + }) + .css({ + position: 'absolute', + left: iconLeft + 'px', + width: iconWidth + 'px', + height: iconHeight + 'px', + borderRadius: borderRadius + 'px' + }) + .appendTo($reflection), - $reflectionGradient = $('
') - .css({ - position: 'absolute', - width: iconSize + 'px', - height: Math.round(iconSize / 2) + 'px' - }) - .appendTo($reflection), + $reflectionGradient = $('
') + .css({ + position: 'absolute', + width: iconSize + 'px', + height: Math.round(iconSize / 2) + 'px' + }) + .appendTo($reflection); + } - $text = Ox.Element() + var $text = Ox.Element() .addClass('OxTextPage') .css({ position: 'absolute', @@ -243,6 +247,7 @@ pandora.ui.infoView = function(data) { }); // Title ------------------------------------------------------------------- + if (!isMultiple) { $('
') .css({ @@ -270,6 +275,7 @@ pandora.ui.infoView = function(data) { }) ) .appendTo($text); + } // Director ---------------------------------------------------------------- @@ -285,7 +291,7 @@ pandora.ui.infoView = function(data) { format: function(value) { return formatLink(value.split(', '), 'name'); }, - placeholder: formatLight(Ox._('Unknown Director')), + placeholder: formatLight(Ox._(isMixed.director ? 'Mixed Director' : 'Unknown Director')), tooltip: canEdit ? pandora.getEditTooltip() : '', value: data.director ? data.director.join(', ') : '' }) @@ -355,7 +361,7 @@ pandora.ui.infoView = function(data) { '').attr({id: 'descriptions'}).appendTo($text); @@ -550,6 +557,8 @@ pandora.ui.infoView = function(data) { // no video placeholder } + } + // Rights Level ------------------------------------------------------------ var $rightsLevel = $('
'); @@ -581,7 +590,7 @@ pandora.ui.infoView = function(data) { .append( Ox.EditableContent({ clickLink: pandora.clickLink, - placeholder: formatLight(Ox._('No comments')), + placeholder: formatLight(Ox._(isMixed.comments ? 'Mixed comments' : 'No comments')), tooltip: pandora.getEditTooltip(), type: 'textarea', value: data.comments || '', @@ -589,12 +598,7 @@ pandora.ui.infoView = function(data) { }) .bindEvent({ submit: function(event) { - pandora.api.edit({ - id: data.id, - comments: event.value - }, function(result) { - // ... - }); + editMetadata('comments', event.value); } }) ) @@ -605,7 +609,7 @@ pandora.ui.infoView = function(data) { function editMetadata(key, value) { if (value != data[key]) { - var edit = {id: data.id}; + var edit = {id: isMultiple ? ui.listSelection : data.id}; if (key == 'alternativeTitles') { edit[key] = value ? Ox.decodeHTMLEntities(value).split('; ').map(function(value) { return [Ox.encodeHTMLEntities(value), []]; @@ -629,33 +633,36 @@ pandora.ui.infoView = function(data) { edit[key] = value; } pandora.api.edit(edit, function(result) { - var src; - data[key] = result.data[key]; - if (result.data.id != data.id) { - Ox.Request.clearCache(); // fixme: too much - pandora.UI.set({item: result.data.id}); - pandora.$ui.browser.value(data.id, 'id', result.data.id); - } else { - Ox.Request.clearCache('autocomplete'); - } - pandora.updateItemContext(); - pandora.$ui.browser.value(result.data.id, key, result.data[key]); - if (Ox.contains(posterKeys, key) && ui.icons == 'posters') { - src = pandora.getMediaURL('/' + data.id + '/poster512.jpg?' + Ox.uid()); - $icon.attr({src: src}); - $reflectionIcon.attr({src: src}); - } - if (Ox.contains(nameKeys, key)) { - data['namedescription'] = result.data['namedescription']; - descriptions.names = getNames(); - renderDescriptions(); - } else if (key == 'productionCompany') { - data['productionCompanydescription'] = result.data['productionCompanydescription']; - descriptions.studios = getStudios(); - renderDescriptions(); - } else if (key == 'imdbId') { - updateIMDb(); + if (!isMultiple) { + var src; + data[key] = result.data[key]; + if (result.data.id != data.id) { + Ox.Request.clearCache(); // fixme: too much + pandora.UI.set({item: result.data.id}); + pandora.$ui.browser.value(data.id, 'id', result.data.id); + } else { + Ox.Request.clearCache('autocomplete'); + } + pandora.updateItemContext(); + pandora.$ui.browser.value(result.data.id, key, result.data[key]); + if (Ox.contains(posterKeys, key) && ui.icons == 'posters') { + src = pandora.getMediaURL('/' + data.id + '/poster512.jpg?' + Ox.uid()); + $icon.attr({src: src}); + $reflectionIcon.attr({src: src}); + } + if (Ox.contains(nameKeys, key)) { + data['namedescription'] = result.data['namedescription']; + descriptions.names = getNames(); + renderDescriptions(); + } else if (key == 'productionCompany') { + data['productionCompanydescription'] = result.data['productionCompanydescription']; + descriptions.studios = getStudios(); + renderDescriptions(); + } else if (key == 'imdbId') { + updateIMDb(); + } } + that.triggerEvent('change', Ox.extend({}, key, value)); }); } } @@ -1060,7 +1067,7 @@ pandora.ui.infoView = function(data) { format: function(value) { return formatValue(key, value); }, - placeholder: formatLight(Ox._('unknown')), + placeholder: formatLight(Ox._(isMixed[key] ? 'mixed': 'unknown')), tooltip: canEdit ? pandora.getEditTooltip() : '', value: getValue(key, data[key]) }) @@ -1130,8 +1137,12 @@ pandora.ui.infoView = function(data) { .css({background: $rightsLevelElement.css('background')}) .data({OxColor: $rightsLevelElement.data('OxColor')}) // renderCapabilities(rightsLevel); - pandora.api.edit({id: data.id, rightslevel: rightsLevel}, function(result) { - // ... + var edit = { + id: isMultiple ? ui.listSelection : data.id, + rightslevel: rightsLevel + }; + pandora.api.edit(edit, function(result) { + that.triggerEvent('change', Ox.extend({}, 'rightslevel', rightsLevel)); }); } }) diff --git a/static/js/infoView.js b/static/js/infoView.js index 1628681d..a1460148 100644 --- a/static/js/infoView.js +++ b/static/js/infoView.js @@ -1,10 +1,12 @@ 'use strict'; -pandora.ui.infoView = function(data) { +pandora.ui.infoView = function(data, isMixed) { + isMixed = isMixed || {}; var ui = pandora.user.ui, descriptions = [], - canEdit = pandora.hasCapability('canEditMetadata') || data.editable, + isMultiple = arguments.length == 2, + canEdit = pandora.hasCapability('canEditMetadata') || isMultiple || data.editable, canRemove = pandora.hasCapability('canRemoveItems'), css = { marginTop: '4px', @@ -12,10 +14,10 @@ pandora.ui.infoView = function(data) { }, html, iconRatio = ui.icons == 'posters' ? data.posterRatio : 1, - iconSize = ui.infoIconSize, - iconWidth = iconRatio > 1 ? iconSize : Math.round(iconSize * iconRatio), + iconSize = isMultiple ? 0 : ui.infoIconSize, + iconWidth = isMultiple ? 0 : iconRatio > 1 ? iconSize : Math.round(iconSize * iconRatio), iconHeight = iconRatio < 1 ? iconSize : Math.round(iconSize / iconRatio), - iconLeft = iconSize == 256 ? Math.floor((iconSize - iconWidth) / 2) : 0, + iconLeft = isMultiple ? 0 : iconSize == 256 ? Math.floor((iconSize - iconWidth) / 2) : 0, borderRadius = ui.icons == 'posters' ? 0 : iconSize / 8, margin = 16, nameKeys = pandora.site.itemKeys.filter(function(key) { @@ -98,70 +100,72 @@ pandora.ui.infoView = function(data) { that = Ox.SplitPanel({ elements: [ - {element: $bar, size: 16}, + {element: $bar, size: isMultiple ? 0 : 16}, {element: $info} ], orientation: 'vertical' - }), + }); - $icon = Ox.Element({ - element: '', - }) - .attr({ - src: '/' + data.id + '/' + ( - ui.icons == 'posters' ? 'poster' : 'icon' - ) + '512.jpg?' + data.modified - }) - .css({ - position: 'absolute', - left: margin + iconLeft + 'px', - top: margin + 'px', - width: iconWidth + 'px', - height: iconHeight + 'px', - borderRadius: borderRadius + 'px', - cursor: 'pointer' - }) - .bindEvent({ - singleclick: toggleIconSize - }) - .appendTo($info), + if (!isMultiple) { + var $icon = Ox.Element({ + element: '', + }) + .attr({ + src: '/' + data.id + '/' + ( + ui.icons == 'posters' ? 'poster' : 'icon' + ) + '512.jpg?' + data.modified + }) + .css({ + position: 'absolute', + left: margin + iconLeft + 'px', + top: margin + 'px', + width: iconWidth + 'px', + height: iconHeight + 'px', + borderRadius: borderRadius + 'px', + cursor: 'pointer' + }) + .bindEvent({ + singleclick: toggleIconSize + }) + .appendTo($info), - $reflection = $('
') - .addClass('OxReflection') - .css({ - position: 'absolute', - left: margin + 'px', - top: margin + iconHeight + 'px', - width: iconSize + 'px', - height: iconSize / 2 + 'px', - overflow: 'hidden' - }) - .appendTo($info), + $reflection = $('
') + .addClass('OxReflection') + .css({ + position: 'absolute', + left: margin + 'px', + top: margin + iconHeight + 'px', + width: iconSize + 'px', + height: iconSize / 2 + 'px', + overflow: 'hidden' + }) + .appendTo($info), - $reflectionIcon = $('') - .attr({ - src: '/' + data.id + '/' + ( - ui.icons == 'posters' ? 'poster' : 'icon' - ) + '512.jpg?' + data.modified - }) - .css({ - position: 'absolute', - left: iconLeft + 'px', - width: iconWidth + 'px', - height: iconHeight + 'px', - borderRadius: borderRadius + 'px' - }) - .appendTo($reflection), + $reflectionIcon = $('') + .attr({ + src: '/' + data.id + '/' + ( + ui.icons == 'posters' ? 'poster' : 'icon' + ) + '512.jpg?' + data.modified + }) + .css({ + position: 'absolute', + left: iconLeft + 'px', + width: iconWidth + 'px', + height: iconHeight + 'px', + borderRadius: borderRadius + 'px' + }) + .appendTo($reflection), - $reflectionGradient = $('
') - .css({ - position: 'absolute', - width: iconSize + 'px', - height: iconSize / 2 + 'px' - }) - .appendTo($reflection), + $reflectionGradient = $('
') + .css({ + position: 'absolute', + width: iconSize + 'px', + height: iconSize / 2 + 'px' + }) + .appendTo($reflection); + } - $text = Ox.Element() + var $text = Ox.Element() .addClass('OxTextPage') .css({ position: 'absolute', @@ -248,7 +252,7 @@ pandora.ui.infoView = function(data) { ); }, maxHeight: Infinity, - placeholder: formatLight(Ox._('No Summary')), + placeholder: formatLight(Ox._( isMixed.summary ? 'Mixed Summary' : 'No Summary')), tooltip: canEdit ? pandora.getEditTooltip() : '', type: 'textarea', value: data.summary || '' @@ -268,49 +272,50 @@ pandora.ui.infoView = function(data) { } // Duration, Aspect Ratio -------------------------------------------------- + if (!isMultiple) { + ['duration', 'aspectratio'].forEach(function(key) { + var itemKey = Ox.getObjectById(pandora.site.itemKeys, key), + value = data[key] || 0; + $('
') + .css({marginBottom: '4px'}) + .append(formatKey(itemKey.title, 'statistics')) + .append( + Ox.Theme.formatColor(null, 'gradient') + .css({textAlign: 'right'}) + .html( + Ox['format' + Ox.toTitleCase(itemKey.format.type)] + .apply(null, [value].concat(itemKey.format.args)) + ) + ) + .appendTo($statistics); + }); + + // Hue, Saturation, Lightness, Volume -------------------------------------- + + ['hue', 'saturation', 'lightness', 'volume'].forEach(function(key) { + $('
') + .css({marginBottom: '4px'}) + .append(formatKey(key, 'statistics')) + .append( + Ox.Theme.formatColor( + data[key] || 0, key == 'volume' ? 'lightness' : key + ).css({textAlign: 'right'}) + ) + .appendTo($statistics); + }); + + // Cuts per Minute --------------------------------------------------------- - ['duration', 'aspectratio'].forEach(function(key) { - var itemKey = Ox.getObjectById(pandora.site.itemKeys, key), - value = data[key] || 0; $('
') .css({marginBottom: '4px'}) - .append(formatKey(itemKey.title, 'statistics')) + .append(formatKey('cuts per minute', 'statistics')) .append( Ox.Theme.formatColor(null, 'gradient') .css({textAlign: 'right'}) - .html( - Ox['format' + Ox.toTitleCase(itemKey.format.type)] - .apply(null, [value].concat(itemKey.format.args)) - ) + .html(Ox.formatNumber(data['cutsperminute'] || 0, 3)) ) .appendTo($statistics); - }); - - // Hue, Saturation, Lightness, Volume -------------------------------------- - - ['hue', 'saturation', 'lightness', 'volume'].forEach(function(key) { - $('
') - .css({marginBottom: '4px'}) - .append(formatKey(key, 'statistics')) - .append( - Ox.Theme.formatColor( - data[key] || 0, key == 'volume' ? 'lightness' : key - ).css({textAlign: 'right'}) - ) - .appendTo($statistics); - }); - - // Cuts per Minute --------------------------------------------------------- - - $('
') - .css({marginBottom: '4px'}) - .append(formatKey('cuts per minute', 'statistics')) - .append( - Ox.Theme.formatColor(null, 'gradient') - .css({textAlign: 'right'}) - .html(Ox.formatNumber(data['cutsperminute'] || 0, 3)) - ) - .appendTo($statistics); + } // Rights Level ------------------------------------------------------------ @@ -342,7 +347,7 @@ pandora.ui.infoView = function(data) { .append( Ox.EditableContent({ height: 128, - placeholder: formatLight(Ox._('No notes')), + placeholder: formatLight(Ox._(isMixed ? 'Mixed notes' : 'No notes')), tooltip: pandora.getEditTooltip(), type: 'textarea', value: data.notes || '', @@ -361,7 +366,7 @@ pandora.ui.infoView = function(data) { function editMetadata(key, value) { if (value != data[key]) { - var edit = {id: data.id}; + var edit = {id: isMultiple ? ui.listSelection : data.id}; if (key == 'title') { edit[key] = value; } else if (listKeys.indexOf(key) >= 0) { @@ -370,31 +375,34 @@ pandora.ui.infoView = function(data) { edit[key] = value ? value : null; } pandora.api.edit(edit, function(result) { - var src; - data[key] = result.data[key]; - descriptions[key] && descriptions[key].options({ - value: result.data[key + 'description'] - }); - Ox.Request.clearCache(); // fixme: too much? can change filter/list etc - if (result.data.id != data.id) { - pandora.UI.set({item: result.data.id}); - pandora.$ui.browser.value(data.id, 'id', result.data.id); - } - pandora.updateItemContext(); - pandora.$ui.browser.value(result.data.id, key, result.data[key]); - if (Ox.contains(posterKeys, key) && ui.icons == 'posters') { - src = pandora.getMediaURL('/' + data.id + '/poster512.jpg?' + Ox.uid()); - $icon.attr({src: src}); - $reflectionIcon.attr({src: src}); - } - pandora.$ui.itemTitle - .options({ - title: '' + result.data.title - + (Ox.len(result.data.director) - ? ' (' + result.data.director.join(', ') + ')' - : '') - + (result.data.year ? ' ' + result.data.year : '') + '' + if (!isMultiple) { + var src; + data[key] = result.data[key]; + descriptions[key] && descriptions[key].options({ + value: result.data[key + 'description'] }); + Ox.Request.clearCache(); // fixme: too much? can change filter/list etc + if (result.data.id != data.id) { + pandora.UI.set({item: result.data.id}); + pandora.$ui.browser.value(data.id, 'id', result.data.id); + } + pandora.updateItemContext(); + pandora.$ui.browser.value(result.data.id, key, result.data[key]); + if (Ox.contains(posterKeys, key) && ui.icons == 'posters') { + src = pandora.getMediaURL('/' + data.id + '/poster512.jpg?' + Ox.uid()); + $icon.attr({src: src}); + $reflectionIcon.attr({src: src}); + } + pandora.$ui.itemTitle + .options({ + title: '' + result.data.title + + (Ox.len(result.data.director) + ? ' (' + result.data.director.join(', ') + ')' + : '') + + (result.data.year ? ' ' + result.data.year : '') + '' + }); + } + that.triggerEvent('change', Ox.extend({}, key, value)); }); } } @@ -546,7 +554,7 @@ pandora.ui.infoView = function(data) { format: function(value) { return formatValue(key, value); }, - placeholder: formatLight(Ox._('unknown')), + placeholder: formatLight(Ox._( isMixed[key] ? 'mixed' : 'unknown')), tooltip: canEdit ? pandora.getEditTooltip() : '', value: getValue(key, data[key]) }) @@ -588,8 +596,12 @@ pandora.ui.infoView = function(data) { .css({background: $rightsLevelElement.css('background')}) .data({OxColor: $rightsLevelElement.data('OxColor')}) renderCapabilities(rightsLevel); - pandora.api.edit({id: data.id, rightslevel: rightsLevel}, function(result) { - // ... + var edit = { + id: isMultiple ? ui.listSelection : data.id, + rightslevel: rightsLevel + }; + pandora.api.edit(edit, function(result) { + that.triggerEvent('change', Ox.extend({}, 'rightslevel', rightsLevel)); }); } }) diff --git a/static/js/infoView.padma.js b/static/js/infoView.padma.js index 3bc49b35..93125b48 100644 --- a/static/js/infoView.padma.js +++ b/static/js/infoView.padma.js @@ -1,9 +1,11 @@ 'use strict'; -pandora.ui.infoView = function(data) { +pandora.ui.infoView = function(data, isMixed) { + isMixed = isMixed || {}; var ui = pandora.user.ui, - canEdit = pandora.hasCapability('canEditMetadata') || data.editable, + isMultiple = arguments.length == 2, + canEdit = pandora.hasCapability('canEditMetadata') || isMultiple || data.editable, canRemove = pandora.hasCapability('canRemoveItems') || data.editable, css = { marginTop: '4px', @@ -12,8 +14,8 @@ pandora.ui.infoView = function(data) { descriptions = [], html, iconRatio = ui.icons == 'posters' ? data.posterRatio : 1, - iconSize = ui.infoIconSize, - iconWidth = iconRatio > 1 ? iconSize : Math.round(iconSize * iconRatio), + iconSize = isMultiple ? 0 : ui.infoIconSize, + iconWidth = isMultiple ? 0 : iconRatio > 1 ? iconSize : Math.round(iconSize * iconRatio), iconHeight = iconRatio < 1 ? iconSize : Math.round(iconSize / iconRatio), iconLeft = iconSize == 256 ? Math.floor((iconSize - iconWidth) / 2) : 0, borderRadius = ui.icons == 'posters' ? 0 : iconSize / 8, @@ -98,7 +100,7 @@ pandora.ui.infoView = function(data) { that = Ox.SplitPanel({ elements: [ - {element: $bar, size: 16}, + {element: $bar, size: isMultiple ? 0 : 16}, {element: $info} ], orientation: 'vertical' @@ -108,72 +110,74 @@ pandora.ui.infoView = function(data) { .css({ position: 'absolute' }) - .appendTo($info), + .appendTo($info); - $icon = Ox.Element({ - element: '', - tooltip: 'Switch to ' + Ox.getObjectById( - pandora.site.itemViews, - ui.videoView - ).title + ' View' - }) - .attr({ - src: pandora.getMediaURL('/' + data.id + '/' + ( - ui.icons == 'posters' ? 'poster' : 'icon' - ) + '512.jpg?' + data.modified) - }) - .css({ - position: 'absolute', - left: margin + iconLeft + 'px', - top: margin + 'px', - width: iconWidth + 'px', - height: iconHeight + 'px', - borderRadius: borderRadius + 'px', - cursor: 'pointer' - }) - .bindEvent({ - anyclick: function() { - pandora.UI.set({itemView: ui.videoView}); - } - }) - .appendTo($left), + if (!isMultiple) { + var $icon = Ox.Element({ + element: '', + tooltip: 'Switch to ' + Ox.getObjectById( + pandora.site.itemViews, + ui.videoView + ).title + ' View' + }) + .attr({ + src: pandora.getMediaURL('/' + data.id + '/' + ( + ui.icons == 'posters' ? 'poster' : 'icon' + ) + '512.jpg?' + data.modified) + }) + .css({ + position: 'absolute', + left: margin + iconLeft + 'px', + top: margin + 'px', + width: iconWidth + 'px', + height: iconHeight + 'px', + borderRadius: borderRadius + 'px', + cursor: 'pointer' + }) + .bindEvent({ + anyclick: function() { + pandora.UI.set({itemView: ui.videoView}); + } + }) + .appendTo($left), - $reflection = $('
') - .addClass('OxReflection') - .css({ - position: 'absolute', - left: margin + 'px', - top: margin + iconHeight + 'px', - width: iconSize + 'px', - height: Math.round(iconSize / 2) + 'px', - overflow: 'hidden' - }) - .appendTo($left), + $reflection = $('
') + .addClass('OxReflection') + .css({ + position: 'absolute', + left: margin + 'px', + top: margin + iconHeight + 'px', + width: iconSize + 'px', + height: Math.round(iconSize / 2) + 'px', + overflow: 'hidden' + }) + .appendTo($left), - $reflectionIcon = $('') - .attr({ - src: pandora.getMediaURL('/' + data.id + '/' + ( - ui.icons == 'posters' ? 'poster' : 'icon' - ) + '512.jpg?' + data.modified) - }) - .css({ - position: 'absolute', - left: iconLeft + 'px', - width: iconWidth + 'px', - height: iconHeight + 'px', - borderRadius: borderRadius + 'px' - }) - .appendTo($reflection), + $reflectionIcon = $('') + .attr({ + src: pandora.getMediaURL('/' + data.id + '/' + ( + ui.icons == 'posters' ? 'poster' : 'icon' + ) + '512.jpg?' + data.modified) + }) + .css({ + position: 'absolute', + left: iconLeft + 'px', + width: iconWidth + 'px', + height: iconHeight + 'px', + borderRadius: borderRadius + 'px' + }) + .appendTo($reflection), - $reflectionGradient = $('
') - .css({ - position: 'absolute', - width: iconSize + 'px', - height: Math.round(iconSize / 2) + 'px' - }) - .appendTo($reflection), + $reflectionGradient = $('
') + .css({ + position: 'absolute', + width: iconSize + 'px', + height: Math.round(iconSize / 2) + 'px' + }) + .appendTo($reflection); + } - $data = $('
') + var $data = $('
') .addClass('OxTextPage') .css({ position: 'absolute', @@ -223,6 +227,7 @@ pandora.ui.infoView = function(data) { } // Source & Project -------------------------------------------------------- + if (!isMultiple) { ['source', 'project'].forEach(function(key) { if (canEdit || data[key]) { @@ -243,7 +248,7 @@ pandora.ui.infoView = function(data) { format: function(value) { return formatValue(key, value); }, - placeholder: formatLight(Ox._('unknown')), + placeholder: formatLight(Ox._(isMixed[key] ? 'mixed' : 'unknown')), editable: canEdit, tooltip: canEdit ? pandora.getEditTooltip() : '', value: listKeys.indexOf(key) >= 0 @@ -286,8 +291,10 @@ pandora.ui.infoView = function(data) { } } }); + } // Title ------------------------------------------------------------------- + if (!isMultiple) { $('
') .css({ @@ -312,12 +319,16 @@ pandora.ui.infoView = function(data) { }) ) .appendTo($text); + } // Groups ------------------------------------------------------------------ renderGroup(['location', 'date', 'language']); renderGroup(['director', 'cinematographer', 'featuring']); + if (isMultiple) { + renderGroup(['source', 'project']); + } renderGroup(['topic']); @@ -364,14 +375,17 @@ pandora.ui.infoView = function(data) { renderGroup(['license']); + $('
') .addClass('OxSelectable') .css(css) .css({height: '16px'}) .appendTo($text); - // Duration, Aspect Ratio -------------------------------------------------- + + // Duration, Aspect Ratio -------------------------------------------------- + if (!isMultiple) { ['duration', 'aspectratio'].forEach(function(key) { var itemKey = Ox.getObjectById(pandora.site.itemKeys, key), value = data[key] || 0; @@ -414,7 +428,7 @@ pandora.ui.infoView = function(data) { .html(Ox.formatNumber(data['cutsperminute'] || 0, 3)) ) .appendTo($statistics); - + } // Rights Level ------------------------------------------------------------ var $rightsLevel = $('
'); @@ -426,6 +440,7 @@ pandora.ui.infoView = function(data) { renderRightsLevel(); // User and Groups --------------------------------------------------------- + if (!isMultiple) { ['user', 'groups'].forEach(function(key) { var $input; @@ -437,10 +452,10 @@ pandora.ui.infoView = function(data) { .css({margin: '2px 0 0 -1px'}) // fixme: weird .append( $input = Ox.Editable({ - placeholder: key == 'groups' ? formatLight(Ox._('No Groups')) : '', + placeholder: key == 'groups' ? formatLight(Ox._(isMixed[key] ? 'Mixed Groups' : 'No Groups')) : '', editable: key == 'user' && canEdit, tooltip: canEdit ? pandora.getEditTooltip() : '', - value: key == 'user' ? data[key] : data[key].join(', ') + value: key == 'user' ? data[key] : isMixed[key] ? '' : data[key].join(', ') }) .bindEvent(Ox.extend({ submit: function(event) { @@ -474,8 +489,10 @@ pandora.ui.infoView = function(data) { ) .appendTo($statistics); }); - + + } // Created and Modified ---------------------------------------------------- + if (!isMultiple) { ['created', 'modified'].forEach(function(key) { $('
') @@ -487,6 +504,8 @@ pandora.ui.infoView = function(data) { .appendTo($statistics); }); + } + // Notes -------------------------------------------------------------------- if (canEdit) { @@ -526,7 +545,7 @@ pandora.ui.infoView = function(data) { function editMetadata(key, value) { if (value != data[key]) { - var edit = {id: data.id}; + var edit = {id: isMultiple ? ui.listSelection : data.id}; if (key == 'title') { edit[key] = value; } else if (listKeys.indexOf(key) >= 0) { @@ -535,32 +554,35 @@ pandora.ui.infoView = function(data) { edit[key] = value ? value : null; } pandora.api.edit(edit, function(result) { - var src; - data[key] = result.data[key]; - descriptions[key] && descriptions[key].options({ - value: result.data[key + 'description'] - }); Ox.Request.clearCache(); // fixme: too much? can change filter/list etc - if (result.data.id != data.id) { - pandora.UI.set({item: result.data.id}); - pandora.$ui.browser.value(data.id, 'id', result.data.id); - } - pandora.updateItemContext(); - pandora.$ui.browser.value(result.data.id, key, result.data[key]); - if (Ox.contains(posterKeys, key) && ui.icons == 'posters') { - src = pandora.getMediaURL('/' + data.id + '/poster512.jpg?' + Ox.uid()); - $icon.attr({src: src}); - $reflectionIcon.attr({src: src}); - } - pandora.$ui.itemTitle - .options({ - title: '' + result.data.title - + (Ox.len(result.data.director) - ? ' (' + result.data.director.join(', ') + ')' - : '') - + (result.data.year ? ' ' + result.data.year : '') + '' + if (!isMultiple) { + var src; + data[key] = result.data[key]; + descriptions[key] && descriptions[key].options({ + value: result.data[key + 'description'] }); - //pandora.$ui.contentPanel.replaceElement(0, pandora.$ui.browser = pandora.ui.browser()); + if (result.data.id != data.id) { + pandora.UI.set({item: result.data.id}); + pandora.$ui.browser.value(data.id, 'id', result.data.id); + } + pandora.updateItemContext(); + pandora.$ui.browser.value(result.data.id, key, result.data[key]); + if (Ox.contains(posterKeys, key) && ui.icons == 'posters') { + src = pandora.getMediaURL('/' + data.id + '/poster512.jpg?' + Ox.uid()); + $icon.attr({src: src}); + $reflectionIcon.attr({src: src}); + } + pandora.$ui.itemTitle + .options({ + title: '' + result.data.title + + (Ox.len(result.data.director) + ? ' (' + result.data.director.join(', ') + ')' + : '') + + (result.data.year ? ' ' + result.data.year : '') + '' + }); + //pandora.$ui.contentPanel.replaceElement(0, pandora.$ui.browser = pandora.ui.browser()); + } + that.triggerEvent('change', Ox.extend({}, key, value)); }); } } @@ -719,7 +741,7 @@ pandora.ui.infoView = function(data) { format: function(value) { return formatValue(key, value); }, - placeholder: formatLight(Ox._('unknown')), + placeholder: formatLight(Ox._(isMixed[key] ? 'mixed' : 'unknown')), tooltip: canEdit ? pandora.getEditTooltip() : '', value: getValue(key, data[key]) }) @@ -761,8 +783,12 @@ pandora.ui.infoView = function(data) { .css({background: $rightsLevelElement.css('background')}) .data({OxColor: $rightsLevelElement.data('OxColor')}) renderCapabilities(rightsLevel); - pandora.api.edit({id: data.id, rightslevel: rightsLevel}, function(result) { - // ... + var edit = { + id: isMultiple ? ui.listSelection : data.id, + rightslevel: rightsLevel + }; + pandora.api.edit(edit, function(result) { + that.triggerEvent('change', Ox.extend({}, 'rightslevel', rightsLevel)); }); } }) diff --git a/static/js/mainMenu.js b/static/js/mainMenu.js index bb3e0488..02193851 100644 --- a/static/js/mainMenu.js +++ b/static/js/mainMenu.js @@ -433,6 +433,12 @@ pandora.ui.mainMenu = function() { } } else if (data.id == 'edit') { pandora.ui.editItemDialog().open(); + } else if (data.id == 'batchedit') { + if (ui.section == 'documents') { + pandora.ui.editDocumentsDialog().open(); + } else { + pandora.ui.editDialog().open(); + } } else if (data.id == 'deletelist') { pandora.ui.deleteListDialog().open(); } else if (data.id == 'print') { @@ -929,6 +935,20 @@ pandora.ui.mainMenu = function() { key_control_p: function() { window.open(document.location.href + '#?print=true', '_blank'); }, + key_control_shift_e: function() { + console.log('!!', ui.section, pandora.enableBatchEdit(ui.section)) + if ( + !pandora.hasDialogOrScreen() && + pandora.enableBatchEdit(ui.section) + ) { + console.log('!!>>', ui.section) + if (ui.section == 'documents') { + pandora.ui.editDocumentsDialog().open(); + } else { + pandora.ui.editDialog().open(); + } + } + }, key_control_shift_f: function() { if (!pandora.hasDialogOrScreen()) { pandora.$ui.filterDialog = pandora.ui.filterDialog().open(); @@ -1146,6 +1166,7 @@ pandora.ui.mainMenu = function() { return { id: 'itemMenu', title: Ox._('Item'), items: [ { id: 'add', title: Ox._('Add {0}...', [Ox._('Document')]), disabled: !pandora.hasCapability('canAddItems') }, { id: 'edit', title: Ox._('Edit {0}...', [Ox._('Document')]), disabled: true /*fixme: !canEdit */ }, + { id: 'batchedit', title: Ox._('Batch Edit {0}...', [Ox._('Documents')]), disabled: !pandora.enableBatchEdit(ui.section), keyboard: 'shift control e' }, {}, { id: 'selectall', title: Ox._('Select All {0}', [listItemsName]), disabled: !canSelect, keyboard: 'control a' }, { id: 'selectnone', title: Ox._('Select None'), disabled: !canSelect, keyboard: 'shift control a' }, @@ -1423,6 +1444,7 @@ pandora.ui.mainMenu = function() { return { id: 'itemMenu', title: Ox._('Item'), items: [ { id: 'add', title: Ox._('Add {0}...', [Ox._(pandora.site.itemName.singular)]), disabled: !pandora.hasCapability('canAddItems') }, { id: 'edit', title: Ox._('Edit {0}...', [Ox._(pandora.site.itemName.singular)]), disabled: true /*fixme: !canEdit */ }, + { id: 'batchedit', title: Ox._('Batch Edit {0}...', [Ox._(pandora.site.itemName.plural)]), disabled: !pandora.enableBatchEdit(ui.section), keyboard: 'shift control e' }, {}, { id: 'selectall', title: Ox._('Select All {0}', [listItemsName]), disabled: !canSelect, keyboard: 'control a' }, { id: 'selectnone', title: Ox._('Select None'), disabled: !canSelect, keyboard: 'shift control a' }, diff --git a/static/js/utils.js b/static/js/utils.js index a1b187db..6e01d2be 100644 --- a/static/js/utils.js +++ b/static/js/utils.js @@ -679,6 +679,19 @@ pandora.createLinks = function($element) { }()); +pandora.enableBatchEdit = function(section) { + var ui = pandora.user.ui; + if (section == 'documents') { + return !ui.document && ui.collectionSelection.length > 1 && ui.collectionSelection.every(function(item) { + return pandora.$ui.list && pandora.$ui.list.value(item, 'editable'); + }) + } else { + return !ui.item && ui.listSelection.length > 1 && ui.listSelection.every(function(item) { + return pandora.$ui.list && pandora.$ui.list.value(item, 'editable'); + }) + } +}; + pandora.enableDragAndDrop = function($list, canMove, section, getItems) { section = section || pandora.user.ui.section;