From a9c5fb43fe62ddc572e6491df167912d6d74a260 Mon Sep 17 00:00:00 2001 From: j Date: Thu, 15 May 2014 01:28:49 +0200 Subject: [PATCH] identify --- config.json | 1 + oml/changelog.py | 11 +- oml/localnodes.py | 4 + oml/settings.py | 3 +- static/js/identifyDialog.js | 523 ++++++++++++++++++++---------------- static/js/infoView.js | 64 +++-- 6 files changed, 353 insertions(+), 253 deletions(-) diff --git a/config.json b/config.json index f218671..e1c8d5e 100644 --- a/config.json +++ b/config.json @@ -164,6 +164,7 @@ "id": "mediastate", "title": "Media State", "type": "string", + "find": true, "sort": true, "values": [ {"id": "available", "title": "Available"}, diff --git a/oml/changelog.py b/oml/changelog.py index 3bb75fe..859267b 100644 --- a/oml/changelog.py +++ b/oml/changelog.py @@ -92,6 +92,14 @@ class Changelog(db.Model): _data = str(self.revision) + str(self.timestamp) + self.data return valid(self.user_id, _data, self.sig) + @classmethod + def _rebuild(cls): + for c in cls.query.filter_by(user_id=settings.USER_ID): + _data = str(c.revision) + str(c.timestamp) + c.data + c.sig = settings.sk.sign(_data, encoding='base64') + db.session.add(c) + db.session.commit() + def json(self): return [self.revision, self.timestamp, self.sig, self.data] @@ -123,7 +131,6 @@ class Changelog(db.Model): i = Item.get_or_create(itemid, info) i.users.append(user) i.update() - trigger_event('itemchange', {'fixme': 'new remote changes'}) return True def action_edititem(self, user, timestamp, itemid, meta): @@ -138,7 +145,6 @@ class Changelog(db.Model): elif meta[key] and (i.meta.get('mainid') != key or meta[key] != i.meta.get(key)): print 'new mapping', key, meta[key], 'currently', i.meta.get('mainid'), i.meta.get(i.meta.get('mainid')) i.update_mainid(key, meta[key]) - trigger_event('itemchange', {'fixme': 'new remote changes'}) return True def action_removeitem(self, user, timestamp, itemid): @@ -152,7 +158,6 @@ class Changelog(db.Model): else: db.session.delete(i) db.session.commit() - trigger_event('itemchange', {'fixme': 'new remote changes'}) return True def action_addlist(self, user, timestamp, name, query=None): diff --git a/oml/localnodes.py b/oml/localnodes.py index 09bc7b5..c24d71f 100644 --- a/oml/localnodes.py +++ b/oml/localnodes.py @@ -33,12 +33,16 @@ class LocalNodes(Thread): def __init__(self, app): self._app = app Thread.__init__(self) + if not server['localnode_discovery']: + return self.daemon = True self.start() self.host = get_public_ipv6() self.send() def send(self): + if not server['localnode_discovery']: + return s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) ttl = struct.pack('@i', self.TTL) diff --git a/oml/settings.py b/oml/settings.py index 00b8788..543cf2f 100644 --- a/oml/settings.py +++ b/oml/settings.py @@ -38,10 +38,11 @@ ui = pdict(os.path.join(config_dir, 'ui.json'), config['user']['ui']) server = pdict(os.path.join(config_dir, 'server.json')) server_defaults = { 'port': 9842, - 'address': '127.0.0.1', + 'address': '::1', 'node_port': 9851, 'node_address': '', 'extract_text': True, + 'localnode_discovery': True, 'directory_service': 'http://[2a01:4f8:120:3201::3]:25519', 'lookup_service': 'http://data.openmedialibrary.com', } diff --git a/static/js/identifyDialog.js b/static/js/identifyDialog.js index d6cfaf9..951ccb4 100644 --- a/static/js/identifyDialog.js +++ b/static/js/identifyDialog.js @@ -34,105 +34,32 @@ oml.ui.identifyDialog = function(data) { originalData = Ox.clone(data, true), + editedData, + + $idInputs, $idButtons = {}, + $idForm = renderIdForm(data), - $preview = data.mainid + $idPreview = data.mainid ? oml.ui.infoView(data) : Ox.Element(), $idPanel = Ox.SplitPanel({ elements: [ {element: Ox.Element().append($idForm), size: 96}, - {element: $preview} + {element: $idPreview} ], orientation: 'vertical' }), - $titleForm = Ox.Element(), + $titleInputs, $titleButtons = {}, - $inputs = keys.map(function(key, index) { - return Ox.Input({ - label: Ox._(key.title), - labelWidth: 64, - value: data[key.id], - width: 360 - }) - .css({ - position: 'absolute', - left: index < 2 ? '16px' : '392px', - top: index % 2 == 0 ? '16px' : '40px' - }) - .bindEvent({ - submit: function(data) { - $findButton.triggerEvent('click'); - } - }) - .appendTo($titleForm); - }), - - $clearButton = Ox.Button({ - title: Ox._('Clear'), - width: 64 - }) - .css({ - position: 'absolute', - right: '160px', - top: '64px' - }) - .bindEvent({ - click: function() { - keys.forEach(function(key) { - inputValue(key.id, ''); - }); - updateButtons(); - } - }) - .appendTo($titleForm), - - $resetButton = Ox.Button({ - disabled: true, - title: Ox._('Reset'), - width: 64 - }) - .css({ - position: 'absolute', - right: '88px', - top: '64px' - }) - .bindEvent({ - click: function() { - keys.forEach(function(key) { - inputValue(key.id, originalData[key.id]); - }); - updateButtons(); - } - }) - .appendTo($titleForm), - - $findButton = Ox.Button({ - title: Ox._('Find'), - width: 64 - }) - .css({ - position: 'absolute', - right: '16px', - top: '64px' - }) - .bindEvent({ - click: function() { - var data = {}; - keys.forEach(function(key) { - data[key.id] = inputValue(key.id); - }); - findMetadata(data); - } - }) - .appendTo($titleForm), + $titleForm = renderTitleForm(), $titlePanel = Ox.SplitPanel({ elements: [ {element: $titleForm, size: 96}, - {element: renderResults([Ox.extend({index: '0'}, data)])} + {element: renderResults([])} ], orientation: 'vertical' }), @@ -195,8 +122,16 @@ oml.ui.identifyDialog = function(data) { }) .bindEvent({ click: function() { - Ox.print('NOT IMPLEMENTED'); - that.close(); + var edit = Ox.extend( + {id: data.id}, + $innerPanel.options('selected') == 'id' + ? Ox.extend({}, 'foo', 'bar') + : {olid: $list.value($list.options('selected'), 'olid')} + ); + that.options({content: Ox.LoadingScreen().start()}); + oml.api.edit(edit, function() { + that.close(); + }); } }) ], @@ -212,11 +147,10 @@ oml.ui.identifyDialog = function(data) { $titlePanel.replaceElement(1, Ox.LoadingScreen().start()); oml.api.findMetadata(data, function(result) { Ox.print('GOT RESULTS', result.data); + // FIXME: CONCAT HERE var items = result.data.items.map(function(item, index) { - return Ox.extend({index: index.toString()}, item); - }).concat([ - Ox.extend({index: result.data.items.length.toString()}, data) - ]); + return Ox.extend({index: (index + 1).toString()}, item); + }); $titlePanel.replaceElement(1, renderResults(items)); }); } @@ -226,19 +160,34 @@ oml.ui.identifyDialog = function(data) { oml.api.getMetadata(Ox.extend({}, key, value), function(result) { Ox.print('GOT RESULT', result.data); $idForm = renderIdForm(result.data); - $preview = oml.ui.infoView(result.data); + $idPreview = oml.ui.infoView(result.data); $idPanel .replaceElement(0, $idForm) - .replaceElement(1, $preview); + .replaceElement(1, $idPreview); }); } - function inputValue(key, value) { - // FIXME: UNELEGANT - Ox.print('INPUTVALUE', key, value) - var $input = $inputs[[ - 'title', 'author', 'publisher', 'date' - ].indexOf(key)]; + function idInputValues(key, values) { + Ox.print('WTF,', $idInputs); + var $input = $idInputs[ids.map(function(id) { + return id.id; + }).indexOf(key)]; + if (Ox.isUndefined(values)) { + values = $input.options('elements').map(function($element) { + return $element.value(); + }); + } else { + $input.options('elements').forEach(function($element, index) { + $element.value(values[index]); + }); + } + return values; + } + + function titleInputValue(key, value) { + var $input = $titleInputs[keys.map(function(key) { + return key.id; + }).indexOf(key)]; if (Ox.isUndefined(value)) { value = $input.value(); if (key == 'author') { @@ -263,136 +212,148 @@ oml.ui.identifyDialog = function(data) { } function renderIdForm(data) { - var $element = Ox.Element(), - $elements = ids.map(function(id, index) { - return Ox.FormElementGroup({ - elements: [ - Ox.Checkbox({ - overlap: 'right', - title: Ox._(id.title), - value: id.id == data.mainid, - width: 80 - }) - .bindEvent({ - change: function(data) { - var value = $elements[index].options('elements')[1].value() - if (data.value) { - if (value) { - $elements.forEach(function($element, i) { - if (i != index) { - $elements[i].options('elements')[0].value(false); - } - }); - getMetadata(id.id, value, function() { - // ... - }); - } else { - this.value(false); - } - } else { - this.value(true); - } - } - }), - Ox.Input({ - value: data[id.id] || '', - width: 160 - }) - .bindEvent({ - submit: function(data) { - if (data.value) { - $elements.forEach(function($element, i) { - $element.options('elements')[0].options({ - disabled: true, - value: i == index - }); - $element.options('elements')[1].options({ - disabled: true - }); + var $element = Ox.Element(); + $idInputs = ids.map(function(id, index) { + return Ox.FormElementGroup({ + elements: [ + Ox.Checkbox({ + overlap: 'right', + title: Ox._(id.title), + value: id.id == data.mainid, + width: 80 + }) + .bindEvent({ + change: function(data) { + var value = $idInputs[index].options('elements')[1].value(); + if (data.value) { + if (value) { + editedData = Ox.extend({}, id.id, value); + $idInputs.forEach(function($input, i) { + if (i != index) { + $input.options('elements')[0].value(false); + } }); - getMetadata(id.id, data.value, function() { + getMetadata(id.id, value, function() { // ... }); + } else { + this.value(false); } + } else { + this.value(true); } - }) - ], - float: 'left' - }) - .css({ - position: 'absolute', - left: 16 + Math.floor(index / 2) * 248 + 'px', - top: 16 + (index % 2) * 24 + 'px' - }) - .appendTo($element); - }), - $resetButton = Ox.Button({ - disabled: true, - title: Ox._('Reset'), - width: 64 - }) - .css({ - position: 'absolute', - right: '16px', - top: '64px' - }) - .bindEvent({ - click: function() { - /* - keys.forEach(function(key) { - inputValue(key.id, originalData[key.id]); - }); - updateButtons(); - */ - } - }) - .appendTo($element); - return $element; - Ox.print('???', data.mainid) - return Ox.Form({ - items: Ox.flatten(ids.map(function(id) { - return [ - Ox.Checkbox({ - disabled: !data[id.id] || id.id == data.mainid, - id: id.id + 'Checkbox', - title: Ox._(id.title), - value: id.id == data.mainid, - width: 128 - }) - .bindEvent({ - change: function() { - getMetadata(id.id, data[id.id]); - } - }), - Ox.Input({ - id: id.id + 'Input', - value: data[id.id] || '', - width: 128 - }) - .css({marginBottom: '16px'}) - .bindEvent({ - change: function(data) { - if (data.value) { - getMetadata(id.id, data.value, function() { - //... - }); - } else { - Ox.print('this', this) - } - } - }) - ]; - })) + } + }), + Ox.Input({ + value: data[id.id] || '', + width: 160 + }) + .bindEvent({ + submit: function(data) { + if (data.value) { + editedData = Ox.extend({}, id.id, data.value); + $idInputs.forEach(function($input, i) { + $input.options('elements')[0].options({ + disabled: true, + value: i == index + }); + $input.options('elements')[1].options({ + disabled: true + }); + }); + getMetadata(id.id, data.value, function() { + // ... + }); + } + } + }) + ], + float: 'left' }) - .css({margin: '16px'}); - return $form; + .css({ + position: 'absolute', + left: 16 + Math.floor(index / 2) * 248 + 'px', + top: 16 + (index % 2) * 24 + 'px' + }) + .appendTo($element); + }); + $idButtons.clear = Ox.Button({ + title: Ox._('Clear'), + width: 64 + }) + .css({ + position: 'absolute', + right: '160px', + top: '64px' + }) + .bindEvent({ + click: function() { + ids.forEach(function(id) { + idInputValues(id.id, [false, '']); + }); + updateIdButtons(); + } + }) + .appendTo($element); + $idButtons.reset = Ox.Button({ + disabled: true, + title: Ox._('Reset'), + width: 64 + }) + .css({ + position: 'absolute', + right: '88px', + top: '64px' + }) + .bindEvent({ + click: function() { + ids.forEach(function(id) { + idInputValues(id.id, [ + id.id == originalData.mainid, + originalData[id.id] + ]); + }); + updateIdButtons(); + } + }) + .appendTo($element); + $idButtons.find = Ox.Button({ + title: Ox._('Look Up'), + width: 64 + }) + .css({ + position: 'absolute', + right: '16px', + top: '64px' + }) + .bindEvent({ + click: function() { + Ox.print('NOT IMPLEMENTED') + } + }) + .appendTo($element); + return $element; } function renderResults(items) { + items = [Ox.extend({index: '0'}, data)].concat(items); Ox.print('LIST ITEMS::::', items); var $list = Ox.TableList({ - columns: Ox.clone(keys, true), + columns: [{ + format: function(value, data) { + return (data.title || '') + ( + data.author + ? ' ' + + data.author.join(', ') + '' + : '' + ); + }, + id: 'index', + visible: true, + width: 192 - Ox.UI.SCROLLBAR_SIZE + }], items: items, + keys: ['author', 'title', 'olid'], min: 1, max: 1, scrollbarVisible: true, @@ -402,37 +363,137 @@ oml.ui.identifyDialog = function(data) { }) .bindEvent({ select: function(data) { - var index = data.ids[0]; - data = Ox.getObject(items, 'index', index); - $results.replaceElement(1, Ox.LoadingScreen().start()); - Ox.print('OLID', data.olid); - oml.api.getMetadata({olid: data.olid}, function(result) { - Ox.print('#### GOT DATA', result.data); - $results.replaceElement(1, oml.ui.infoView(result.data)); - that.options('buttons')[1].options({disabled: false}); - }); + var index = data.ids[0], olid; + if (index == '0') { + $results.replaceElement(1, oml.ui.infoView(data)); + } else { + olid = $list.value(index, 'olid'); + editedData = {olid: olid}; + $results.replaceElement(1, Ox.LoadingScreen().start()); + oml.api.getMetadata({olid: olid}, function(result) { + if (index == $list.options('selected')[0]) { + $results.replaceElement(1, oml.ui.infoView(result.data)); + that.options('buttons')[1].options({disabled: false}); + } + }); + } + } }), $results = Ox.SplitPanel({ elements: [ - {element: $list, size: 80}, + {element: $list, size: 192}, {element: oml.ui.infoView(items[0])} ], - orientation: 'vertical' + orientation: 'horizontal' }); return $results; } - function updateButtons() { + function renderTitleForm() { + var $element = Ox.Element(); + $titleInputs = keys.map(function(key, index) { + return Ox.Input({ + label: Ox._(key.title), + labelWidth: 64, + value: data[key.id], + width: 360 + }) + .css({ + position: 'absolute', + left: index < 2 ? '16px' : '392px', + top: index % 2 == 0 ? '16px' : '40px' + }) + .bindEvent({ + submit: function(data) { + $titleButtons.find.triggerEvent('click'); + } + }) + .appendTo($element); + }); + $titleButtons.clear = Ox.Button({ + title: Ox._('Clear'), + width: 64 + }) + .css({ + position: 'absolute', + right: '160px', + top: '64px' + }) + .bindEvent({ + click: function() { + keys.forEach(function(key) { + titleInputValue(key.id, ''); + }); + updateTitleButtons(); + } + }) + .appendTo($element); + $titleButtons.reset = Ox.Button({ + disabled: true, + title: Ox._('Reset'), + width: 64 + }) + .css({ + position: 'absolute', + right: '88px', + top: '64px' + }) + .bindEvent({ + click: function() { + keys.forEach(function(key) { + titleInputValue(key.id, originalData[key.id]); + }); + updateTitleButtons(); + } + }) + .appendTo($element); + $titleButtons.find = Ox.Button({ + title: Ox._('Find'), + width: 64 + }) + .css({ + position: 'absolute', + right: '16px', + top: '64px' + }) + .bindEvent({ + click: function() { + var data = {}; + keys.forEach(function(key) { + data[key.id] = titleInputValue(key.id); + }); + findMetadata(data); + } + }) + .appendTo($element); + return $element; + } + + function updateIdButtons() { var data = {}, empty, original; - keys.forEach(function(key) { - data[key.id] = inputValue(key.id); + ids.forEach(function(id) { + data[id.id] = idInputValues(id.id)[1]; }); empty = isEmpty(data); original = isOriginal(data); - $clearButton.options({disabled: empty}); - $resetButton.options({disabled: original}); - $findButton.options({disabled: empty}); + $idButtons.clear.options({disabled: empty}); + $idButtons.reset.options({disabled: original}); + $idButtons.find.options({disabled: empty}); + that.options('buttons')[1].options({disabled: original}); + } + + function updateTitleButtons() { + var data = {}, empty, original; + keys.forEach(function(key) { + data[key.id] = titleInputValue(key.id); + }); + empty = isEmpty(data); + original = isOriginal(data); + $titleButtons.clear.options({disabled: empty}); + $titleButtons.reset.options({disabled: original}); + $titleButtons.find.options({disabled: empty}); + that.options('buttons')[1].options({disabled: original}); } return that; diff --git a/static/js/infoView.js b/static/js/infoView.js index 5204d1b..e703bfd 100644 --- a/static/js/infoView.js +++ b/static/js/infoView.js @@ -39,7 +39,9 @@ oml.ui.infoView = function(identifyData) { }) .appendTo(that), - $data; + $data, + + $image, $reflection, $reflectionImage; if (!identifyData) { $data = Ox.Element() @@ -53,6 +55,13 @@ oml.ui.infoView = function(identifyData) { .appendTo(that); } + function getImageSize(size, ratio) { + var width = Math.round(ratio >= 1 ? size : size * ratio), + height = Math.round(ratio <= 1 ? size : size / ratio), + left = Math.floor((size - width) / 2); + return {width: width, height: height, left: left}; + } + function formatLight(str) { return '' + str + ''; } @@ -83,6 +92,7 @@ oml.ui.infoView = function(identifyData) { } function renderMediaButton(data) { + function getListItems() { var items = []; if (ui._lists) { @@ -99,6 +109,7 @@ oml.ui.infoView = function(identifyData) { } return items; } + function setListItems() { if ($element && ui._lists) { $element.options({ @@ -196,6 +207,25 @@ oml.ui.infoView = function(identifyData) { return $element; } + function updateCover(size, ratio) { + var width = Math.round(ratio >= 1 ? size : size * ratio), + height = Math.round(ratio <= 1 ? size : size / ratio), + left = Math.floor((size - width) / 2); + $image.css({ + left: left + 'px', + width: width + 'px', + height: height + 'px' + }).show(); + $reflectionImage.css({ + left: left + 'px', + width: width + 'px', + height: height + 'px' + }); + $reflection.css({ + top: height + 'px' + }).show(); + } + that.update = function(idOrData, $elements) { var data = Ox.isObject(idOrData) ? idOrData : null, @@ -215,16 +245,13 @@ oml.ui.infoView = function(identifyData) { } Ox.print('BOOK DATA', data) - var $reflection, $mediaButton, + var $mediaButton, isEditable = !data.mainid && data.mediastate == 'available', - ratio = data.coverRatio || 0.75, - size = 256, - width = Math.round(ratio >= 1 ? size : size * ratio), - height = Math.round(ratio <= 1 ? size : size / ratio), - left = Math.floor((size - width) / 2), src = !identifyData ? '/' + data.id + '/cover256.jpg' : data.cover, + ratio = data.coverRatio || oml.config.coverRatio, + size = 256, reflectionSize = Math.round(size / 2); $elements.forEach(function($element) { @@ -233,34 +260,35 @@ oml.ui.infoView = function(identifyData) { if ($element == $cover) { - $('') + $image = $('') + .on({ + load: function() { + var ratio = $image[0].width / $image[0].height; + updateCover(size, ratio); + } + }) .attr({src: src}) .css({ - position: 'absolute', - left: left + 'px', - width: width + 'px', - height: height + 'px' + position: 'absolute' }) + .hide() .appendTo($cover); $reflection = $('
') .addClass('OxReflection') .css({ position: 'absolute', - top: height + 'px', width: size + 'px', height: reflectionSize + 'px', overflow: 'hidden' }) + .hide() .appendTo($cover); - $('') + $reflectionImage = $('') .attr({src: src}) .css({ - position: 'absolute', - left: left + 'px', - width: width + 'px', - height: height + 'px' + position: 'absolute' }) .appendTo($reflection);