'use strict'; oml.ui.infoView = function(externalData, isMixed) { isMixed = isMixed || {}; var ui = oml.user.ui, arrayKeys = ['author', 'place', 'publisher', 'language', 'categories'], editables = {}, iconSize = externalData ? 256 : ui.iconSize, isMultiple = arguments.length == 2, separator = '; ', css = getCSS(iconSize, oml.config.iconRatio), that = Ox.Element() .addClass('OxTextPage') .css({overflowY: 'auto'}) .bindEvent({ oml_icons: function() { that.updateElement(ui.item, [$icon]) }, oml_item: function() { if (ui.item) { that.updateElement(ui.item); } }, oml_listselection: function(data) { if ( data.value && data.value.length && data.value[0] != ui.item ) { that.updateElement(data.value[0]); } } }), $icon = Ox.Element() .css({ position: 'absolute', left: '16px', top: '16px', width: css.icon.width }) .appendTo(that), $info = Ox.Element() .addClass('OxSelectable') .css({ position: 'absolute', left: !isMultiple ? css.info.left : '16px', right: !externalData && !isMultiple ? '176px' : 16 + Ox.UI.SCROLLBAR_SIZE + 'px', top: '16px' }) [iconSize == 512 ? 'hide' : 'show']() .appendTo(that), $data, $image, $reflection, $reflectionImage; if (!externalData) { $data = Ox.Element() .addClass('OxSelectable') .css({ position: 'absolute', right: '16px', top: '16px', width: '128px' }) .appendTo(that); } function formatLight(string) { return '' + string + ''; } function formatKey(key) { return '' + Ox._(Ox.getObjectById(oml.config.itemKeys, key).title) + ': '; } function formatValue(value, key) { var isEditor = key == 'author' && (value || []).some(function(value) { return Ox.endsWith(value, ' (Ed.)'); }); return value ? (Ox.isArray(value) ? value : [value]).map(function(value) { if (key == 'date' && value) { value = value.slice(0, 4); } return ( key && !externalData ? '' : '' ) + ( key == 'author' ? value.replace(/ \(Ed\.\)$/, '') : value ) + ( key && !externalData ? '' : '' ); }).join(separator) + (isEditor ? ' (Ed.)' : '') : ''; } function getCSS(size, ratio) { var width = Math.round(ratio >= 1 ? size : size * ratio), height = Math.round(ratio <= 1 ? size : size / ratio), left = size == 256 ? Math.floor((size - width) / 2) : 0; return { icon: { width: size + 'px' }, info: { left: (size == 256 ? size + 32 : width + 48) + 'px' }, image: { left: left + 'px', width: width + 'px', height: height + 'px' }, reflection: { top: height + 'px' } }; } function renderIdentifyButton(data) { return Ox.Button({ disabled: data.mediastate != 'available', style: 'squared', title: Ox._('Identify Book...'), width: 128 }) .css({marginTop: '8px'}) .bindEvent({ click: function() { oml.$ui.identifyDialog = oml.ui.identifyDialog(data).open(); } }); } function renderMediaButton(data) { function getListItems() { var items = []; if (ui._lists) { items = ui._lists.filter(function(list) { return list.user === '' && list.type != 'smart'; }).map(function(list) { return { id: list.id, title: Ox._('Download to {0}', [ Ox.encodeHTMLEntities(list.name) ]) }; }); items.splice(1, 0, [{}]); } return items; } function setListItems() { if ($element && ui._lists) { $element.options({ disabled: false }).options('elements')[1].options({ items: getListItems() }); } else { setTimeout(setListItems, 100); } } if (data.mediastate == 'unavailable' && !ui._lists) { setListItems(); } var $element = (data.mediastate == 'unavailable' || Ox.isUndefined(data.mediastate)) ? Ox.FormElementGroup({ elements: [ Ox.Button({ style: 'squared', title: Ox._('Download Book'), width: 112 }) .bindEvent({ click: function() { data.mediastate = 'transferring'; that.updateElement(data, $data); oml.api.addListItems({ items: [ui.item], list: ':' }, function(result) { // ... }); } }), Ox.MenuButton({ disabled: !ui._lists, items: getListItems(), overlap: 'left', style: 'squared', title: 'select', tooltip: Ox._('Download Book to a List'), type: 'image' }) .bindEvent({ click: function(data_) { data.mediastate = 'transferring'; that.updateElement(data, $data); oml.api.addListItems({ items: [ui.item], list: data_.id }, function(result) { // ... }); } }) ], float: 'right' }) : data.mediastate == 'transferring' ? Ox.FormElementGroup({ elements: [ Ox.Button({ style: 'squared', title: Ox._('Transferring...'), width: 112 }) .bindEvent({ click: function() { oml.UI.set({page: 'transfers'}); } }), Ox.Button({ overlap: 'left', style: 'squared', title: 'close', tooltip: Ox._('Cancel Transfer'), type: 'image' }) .bindEvent({ click: function() { data.mediastate = 'unavailable'; that.updateElement(data, $data); oml.api.cancelDownloads({ids: [ui.item]}, function() { that.updateElement(ui.item, $data); }); } }) ], float: 'right' }) : data.missing ? Ox.FormElementGroup({ elements: [ Ox.Button({ style: 'squared', title: Ox._('Book Missing'), width: 112 }) .bindEvent({ click: function() { if (!oml.readOnly) { oml.api.openFolder({id: oml.user.ui.item}); } } }), Ox.MenuButton({ items: [ ].concat(oml.readOnly ? [] : [ {id: 'show', title: Ox._('Show File')} ]), overlap: 'left', style: 'squared', title: 'select', tooltip: Ox._('File was removed'), type: 'image' }) .bindEvent({ click: function(data_) { if (!oml.readOnly) { oml.api.openFolder({id: oml.user.ui.item}); } } }) ], float: 'right' }) : Ox.FormElementGroup({ elements: [ Ox.Button({ style: 'squared', title: Ox._('Read Book'), width: 112 }) .bindEvent({ click: function() { oml.UI.set({itemView: 'book'}); } }), Ox.MenuButton({ items: [ {id: 'read', title: Ox._('Read in Open Media Libary')}, {id: 'open', title: Ox._('Open in External Reader')}, ].concat(oml.readOnly ? [] : [ {}, {id: 'show', title: Ox._('Show File')} ]), overlap: 'left', style: 'squared', title: 'select', tooltip: Ox._('Download Book to a List'), type: 'image' }) .bindEvent({ click: function(data_) { if (data_.id == 'read') { oml.UI.set({itemView: 'book'}); } else if (data_.id == 'open') { if (oml.readOnly) { document.location.href = '/' + oml.user.ui.item + '/get/' } else { oml.api.openFile({id: oml.user.ui.item}); } } else { oml.api.openFolder({id: oml.user.ui.item}); } } }) ], float: 'right' }); return $element; } function renderShareButton(data) { return Ox.Checkbox({ style: 'squared', title: Ox._('Share Metadata'), value: data.sharemetadata, width: 128, }) .css({marginTop: '8px'}) .bindEvent({ change: function(changeData) { oml.api.edit({ id: data.id, sharemetadata: changeData.value }, function(result) { if (!changeData.value) { that.updateElement(result.data, [$icon, $info, $data]); } }); } }); } function splitValue(value, key) { var isEditor = key == 'author' && Ox.decodeHTMLEntities(value).split(separator).some(function(value) { return Ox.endsWith(value, ' (Ed.)'); }); return value ? Ox.unique( Ox.decodeHTMLEntities(value).split(separator).map(function(value) { value = Ox.encodeHTMLEntities(value); return isEditor ? value.replace(/ \(Ed\.\)$/, '') + ' (Ed.)' : value; }) ) : []; } function toggleCoverSize(ratio) { var css; iconSize = iconSize == 256 ? 512 : 256, css = getCSS(iconSize, ratio); //$icon.animate(css.icon, 250); $info.animate(css.info, 250); $image.animate(css.image, 250); $reflectionImage.animate(css.image, 250); $reflection.animate(css.reflection, 250); oml.UI.set({iconSize: iconSize}); } function updateCover(ratio) { var css = getCSS(iconSize, ratio); $image.css(css.image).show(); $reflectionImage.css(css.image); $reflection.css(css.reflection).show(); } that.updateCover = function(url) { Ox.Request.clearCache('get'); that.updateElement(ui.item, $icon); }; that.updateElement = function(idOrData, $elements) { var data = Ox.isObject(idOrData) ? idOrData : null, id = data ? null : idOrData, $elements = $elements ? Ox.makeArray($elements) : [$icon, $info, $data]; (data ? Ox.noop : oml.api.get)({ id: id, keys: [] }, function(result) { if (!externalData && id && id != ui.item) { return; } if (result) { data = result.data; } Ox.print('BOOK DATA', data) var $div, isEditable = !oml.readOnly && (isMultiple || ( data.mediastate == 'available' && !externalData )), src = !externalData ? '/' + data.id + '/' + ui.icons + '512.jpg?' + data.modified : data.cover, ratio = ( ui.icons == 'cover' || externalData ? data.coverRatio : data.previewRatio ) || oml.config.iconRatio, size = iconSize, reflectionSize = Math.round(size / 2); $elements.forEach(function($element) { $element.empty(); if ($element == $icon) { $image = Ox.Element({ element: '', tooltip: isEditable ? Ox._('Doubleclick to edit') : '' }) .on({ error: function() { if (size == 512) { $info.show(); } }, load: function() { ratio = $image[0].width / $image[0].height; updateCover(ratio); if (size == 512) { $info.css({ left: getCSS(512, ratio).info.left }).show(); } } }) .attr({src: src}) .css({ position: 'absolute' }) .hide() .bindEvent({ doubleclick: function() { if (isEditable) { oml.$ui.coverDialog = oml.ui.coverDialog( id, data.cover ).open(); } }, singleclick: function() { if (!externalData) { toggleCoverSize(ratio); } } }) .appendTo($icon); $reflection = $('
') .addClass('OxReflection') .css({ position: 'absolute', width: size + 'px', height: reflectionSize + 'px', overflow: 'hidden' }) .hide() .appendTo($icon); $reflectionImage = $('') .attr({src: src}) .css({ position: 'absolute' }) .appendTo($reflection); $('
') .css({ position: 'absolute', width: size + 'px', height: reflectionSize + 'px' }) .appendTo($reflection); } else if ($element == $info) { // -------- Title -------- $('
') .css({ marginTop: '-2px' }) .append( editables['title'] = Ox.EditableContent({ clickLink: oml.clickLink, editable: isEditable, placeholder: formatLight(Ox._( isMixed.title ? 'Mixed Title' : 'Unknown Title' )), tooltip: isEditable ? oml.getEditTooltip() : '', value: Ox.encodeHTMLEntities(data.title || '') }) .css({ fontWeight: 'bold', fontSize: '13px' }) .bindEvent({ submit: function(event) { editMetadata('title', Ox.decodeHTMLEntities(event.value)); } }) ) .appendTo($info); // -------- Author -------- $('
') .css({ marginTop: '2px' }) .append( editables['author'] = Ox.EditableContent({ clickLink: oml.clickLink, editable: isEditable, format: function(value) { return formatValue(splitValue(value, 'author'), 'author'); }, placeholder: formatLight(Ox._( isMixed.author ? 'Mixed Author' : 'Unknown Author' )), tooltip: isEditable ? oml.getEditTooltip() : '', value: Ox.encodeHTMLEntities( (data.author || []).map(function(value, index) { return index < data.author.length - 1 ? value.replace(/ \(Ed\.\)$/, '') : value; }).join(separator) ) }) .css({ marginBottom: '-3px', fontWeight: 'bold', fontSize: '13px' }) .bindEvent({ submit: function(event) { editMetadata('author', Ox.decodeHTMLEntities(event.value)); } }) ) .appendTo($info); // -------- Publisher, Place, Date -------- $div = $('
') .css({ marginTop: '4px', }) .appendTo($info); ['publisher', 'place', 'date'].forEach(function(key, index) { if (index) { $('').html(', ').appendTo($div); } $('') .html(formatKey(key)) .appendTo($div); editables[key] = Ox.EditableContent({ clickLink: oml.clickLink, editable: isEditable, format: function(value) { return formatValue( Ox.contains(arrayKeys, key) ? splitValue(value) : value, key ); }, placeholder: formatLight(Ox._( isMixed[key] ? 'mixed' : 'unknown' )), tooltip: isEditable ? oml.getEditTooltip() : '', value: Ox.encodeHTMLEntities( Ox.contains(arrayKeys, key) ? (data[key] || []).join(separator) : (data[key] || '') ) }) .bindEvent({ submit: function(event) { editMetadata(key, Ox.decodeHTMLEntities(event.value)); } }) .appendTo($div); }); // -------- Series, Edition, Language, Pages -------- $div = $('
') .css({ marginTop: '4px', }) .appendTo($info); ['series', 'edition', 'language', 'pages'].forEach(function(key, index) { if (index) { $('').html(', ').appendTo($div); } $('') .html(formatKey(key)) .appendTo($div); editables[key] = Ox.EditableContent({ clickLink: oml.clickLink, editable: isEditable, format: function(value) { return ( Ox.contains(['series', 'language'], key) ? formatValue : Ox.identity )( Ox.contains(arrayKeys, key) ? splitValue(value) : value, key ); }, placeholder: formatLight(Ox._( isMixed[key] ? 'mixed' : 'unknown' )), tooltip: isEditable ? oml.getEditTooltip() : '', value: Ox.encodeHTMLEntities( Ox.contains(arrayKeys, key) ? (data[key] || []).join(separator) : (data[key] || '') ) }) .bindEvent({ submit: function(event) { editMetadata(key, Ox.decodeHTMLEntities(event.value)); } }) .appendTo($div); }); // -------- Categories -------- if (data.categories || isEditable) { $div = $('
') .css({ marginTop: '4px', }) .appendTo($info); $('') .html(formatKey('categories')) .appendTo($div); editables['categories'] = Ox.EditableContent({ clickLink: oml.clickLink, editable: isEditable, format: function(value) { return formatValue(splitValue(value), 'categories'); }, placeholder: formatLight(Ox._( isMixed.categories ? 'mixed' : 'unknown' )), tooltip: isEditable ? oml.getEditTooltip() : '', value: Ox.encodeHTMLEntities((data.categories || []).join(separator)) }) .bindEvent({ submit: function(event) { editMetadata('categories', Ox.decodeHTMLEntities(event.value)); } }) .appendTo($div); } // -------- ISBN -------- if (data.isbn || isEditable) { $div = $('
') .css({ marginTop: '4px', }) .appendTo($info); $('') .html(formatKey('isbn')) .appendTo($div); editables['isbn'] = Ox.EditableContent({ editable: isEditable, format: function(value) { return (value ? [ Ox.formatISBN(value, 13, true), Ox.formatISBN(value, 10, true) ] : []).join(separator); }, placeholder: formatLight(Ox._( isMixed.isbn ? 'mixed' : 'unknown' )), tooltip: isEditable ? oml.getEditTooltip() : '', value: Ox.formatISBN(data.isbn || '', 13, true) }) .bindEvent({ submit: function(event) { this.options({ value: Ox.formatISBN(event.value, 13, true) }); editMetadata( 'isbn', Ox.formatISBN(event.value, 13) ); } }) .appendTo($div); } // -------- Description, Table of Contents -------- ['description', 'tableofcontents'].forEach(function(key) { if (data[key] || isEditable) { $('
') .css({ marginTop: '8px', textAlign: 'justify' }) .append( editables[key] = Ox.EditableContent({ clickLink: oml.clickLink, editable: isEditable, format: function(value) { return value.replace(/\n/g, '
'); }, placeholder: formatLight(Ox._( isMixed[key] ? 'Mixed {0}' : 'No {0}', [ Ox.getObjectById(oml.config.itemKeys, key).title ])), tooltip: isEditable ? oml.getEditTooltip() : '', type: 'textarea', value: Ox.encodeHTMLEntities(data[key] || '') }) .bindEvent({ submit: function(event) { editMetadata( key, Ox.decodeHTMLEntities(event.value).replace(/
/g, '\n') ); } }) ) .appendTo($info); } }); $('
').css({height: '16px'}).appendTo($info); oml.createLinks($info); } else if ($element == $data) { renderMediaButton(data).appendTo($data); $('
') .addClass('OxSelectable') .css({ marginTop: '10px', }) .text( [ data.extension.toUpperCase(), Ox.formatValue(data.size, 'B') ].join(', ') ) .appendTo($data); if (!oml.readOnly) { renderIdentifyButton(data).appendTo($data); ['accessed', 'modified', 'added', 'created'].forEach(function(id) { var title; if (data[id]) { title = Ox.getObjectById(oml.config.itemKeys, id).title; $('
') .css({ marginTop: '8px', fontWeight: 'bold' }) .text(title) .appendTo($data); $('
') .text(Ox.formatDate(data[id], '%B %e, %Y')) .appendTo($data); } }); if (data.mediastate == 'available') { renderShareButton(data).appendTo($data); } } $('
').css({height: '16px'}).appendTo($data); } }); function editMetadata(key, value) { var edit = Ox.extend( {id: !isMultiple ? data.id : ui.listSelection}, key, Ox.contains(arrayKeys, key) ? splitValue(value, key).map(Ox.decodeHTMLEntities) : value ); if (!Ox.isEqual(edit[key], data[key])) { data[key] = edit[key]; oml.api.edit(edit, function(result) { if (isMixed[key]) { isMixed[key] = false var placeholder = editables[key].options('placeholder').replace('Mixed', 'Unknown').replace('mixed', 'unknown') editables[key].options({ placeholder: placeholder }) } if (!isMultiple || ui.updateResults) { Ox.Request.clearCache(); if (Ox.contains(['title', 'author', 'description'], key)) { oml.$ui.info.updateElement(); } if (ui.showFilters) { oml.$ui.filters.forEach(function($filter) { $filter.reloadList(true); }); } oml.$ui.list.value( result.data.id, key, result.data[key] ); oml.$ui.browser.value( result.data.id, key, result.data[key] ); } $data && that.updateElement(result.data, [$data]); that.triggerEvent('change', Ox.extend({}, key, value)); }); } } }); }; if (!externalData) { ui.item && that.updateElement(ui.item); } else if (!isMultiple) { that.updateElement(externalData, [$icon, $info]); } else { that.updateElement(externalData, [$info]); } that.bindEvent({ mousedown: function() { setTimeout(function() { !Ox.Focus.focusedElementIsInput() && that.gainFocus(); }); } }) return that; };