This commit is contained in:
j 2014-05-15 01:28:49 +02:00
parent 0e6b9533b4
commit a9c5fb43fe
6 changed files with 353 additions and 253 deletions

View File

@ -164,6 +164,7 @@
"id": "mediastate", "id": "mediastate",
"title": "Media State", "title": "Media State",
"type": "string", "type": "string",
"find": true,
"sort": true, "sort": true,
"values": [ "values": [
{"id": "available", "title": "Available"}, {"id": "available", "title": "Available"},

View File

@ -92,6 +92,14 @@ class Changelog(db.Model):
_data = str(self.revision) + str(self.timestamp) + self.data _data = str(self.revision) + str(self.timestamp) + self.data
return valid(self.user_id, _data, self.sig) 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): def json(self):
return [self.revision, self.timestamp, self.sig, self.data] 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 = Item.get_or_create(itemid, info)
i.users.append(user) i.users.append(user)
i.update() i.update()
trigger_event('itemchange', {'fixme': 'new remote changes'})
return True return True
def action_edititem(self, user, timestamp, itemid, meta): 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)): 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')) print 'new mapping', key, meta[key], 'currently', i.meta.get('mainid'), i.meta.get(i.meta.get('mainid'))
i.update_mainid(key, meta[key]) i.update_mainid(key, meta[key])
trigger_event('itemchange', {'fixme': 'new remote changes'})
return True return True
def action_removeitem(self, user, timestamp, itemid): def action_removeitem(self, user, timestamp, itemid):
@ -152,7 +158,6 @@ class Changelog(db.Model):
else: else:
db.session.delete(i) db.session.delete(i)
db.session.commit() db.session.commit()
trigger_event('itemchange', {'fixme': 'new remote changes'})
return True return True
def action_addlist(self, user, timestamp, name, query=None): def action_addlist(self, user, timestamp, name, query=None):

View File

@ -33,12 +33,16 @@ class LocalNodes(Thread):
def __init__(self, app): def __init__(self, app):
self._app = app self._app = app
Thread.__init__(self) Thread.__init__(self)
if not server['localnode_discovery']:
return
self.daemon = True self.daemon = True
self.start() self.start()
self.host = get_public_ipv6() self.host = get_public_ipv6()
self.send() self.send()
def send(self): def send(self):
if not server['localnode_discovery']:
return
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
ttl = struct.pack('@i', self.TTL) ttl = struct.pack('@i', self.TTL)

View File

@ -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 = pdict(os.path.join(config_dir, 'server.json'))
server_defaults = { server_defaults = {
'port': 9842, 'port': 9842,
'address': '127.0.0.1', 'address': '::1',
'node_port': 9851, 'node_port': 9851,
'node_address': '', 'node_address': '',
'extract_text': True, 'extract_text': True,
'localnode_discovery': True,
'directory_service': 'http://[2a01:4f8:120:3201::3]:25519', 'directory_service': 'http://[2a01:4f8:120:3201::3]:25519',
'lookup_service': 'http://data.openmedialibrary.com', 'lookup_service': 'http://data.openmedialibrary.com',
} }

View File

@ -34,105 +34,32 @@ oml.ui.identifyDialog = function(data) {
originalData = Ox.clone(data, true), originalData = Ox.clone(data, true),
editedData,
$idInputs, $idButtons = {},
$idForm = renderIdForm(data), $idForm = renderIdForm(data),
$preview = data.mainid $idPreview = data.mainid
? oml.ui.infoView(data) ? oml.ui.infoView(data)
: Ox.Element(), : Ox.Element(),
$idPanel = Ox.SplitPanel({ $idPanel = Ox.SplitPanel({
elements: [ elements: [
{element: Ox.Element().append($idForm), size: 96}, {element: Ox.Element().append($idForm), size: 96},
{element: $preview} {element: $idPreview}
], ],
orientation: 'vertical' orientation: 'vertical'
}), }),
$titleForm = Ox.Element(), $titleInputs, $titleButtons = {},
$inputs = keys.map(function(key, index) { $titleForm = renderTitleForm(),
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),
$titlePanel = Ox.SplitPanel({ $titlePanel = Ox.SplitPanel({
elements: [ elements: [
{element: $titleForm, size: 96}, {element: $titleForm, size: 96},
{element: renderResults([Ox.extend({index: '0'}, data)])} {element: renderResults([])}
], ],
orientation: 'vertical' orientation: 'vertical'
}), }),
@ -195,8 +122,16 @@ oml.ui.identifyDialog = function(data) {
}) })
.bindEvent({ .bindEvent({
click: function() { click: function() {
Ox.print('NOT IMPLEMENTED'); var edit = Ox.extend(
that.close(); {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()); $titlePanel.replaceElement(1, Ox.LoadingScreen().start());
oml.api.findMetadata(data, function(result) { oml.api.findMetadata(data, function(result) {
Ox.print('GOT RESULTS', result.data); Ox.print('GOT RESULTS', result.data);
// FIXME: CONCAT HERE
var items = result.data.items.map(function(item, index) { var items = result.data.items.map(function(item, index) {
return Ox.extend({index: index.toString()}, item); return Ox.extend({index: (index + 1).toString()}, item);
}).concat([ });
Ox.extend({index: result.data.items.length.toString()}, data)
]);
$titlePanel.replaceElement(1, renderResults(items)); $titlePanel.replaceElement(1, renderResults(items));
}); });
} }
@ -226,19 +160,34 @@ oml.ui.identifyDialog = function(data) {
oml.api.getMetadata(Ox.extend({}, key, value), function(result) { oml.api.getMetadata(Ox.extend({}, key, value), function(result) {
Ox.print('GOT RESULT', result.data); Ox.print('GOT RESULT', result.data);
$idForm = renderIdForm(result.data); $idForm = renderIdForm(result.data);
$preview = oml.ui.infoView(result.data); $idPreview = oml.ui.infoView(result.data);
$idPanel $idPanel
.replaceElement(0, $idForm) .replaceElement(0, $idForm)
.replaceElement(1, $preview); .replaceElement(1, $idPreview);
}); });
} }
function inputValue(key, value) { function idInputValues(key, values) {
// FIXME: UNELEGANT Ox.print('WTF,', $idInputs);
Ox.print('INPUTVALUE', key, value) var $input = $idInputs[ids.map(function(id) {
var $input = $inputs[[ return id.id;
'title', 'author', 'publisher', 'date' }).indexOf(key)];
].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)) { if (Ox.isUndefined(value)) {
value = $input.value(); value = $input.value();
if (key == 'author') { if (key == 'author') {
@ -263,136 +212,148 @@ oml.ui.identifyDialog = function(data) {
} }
function renderIdForm(data) { function renderIdForm(data) {
var $element = Ox.Element(), var $element = Ox.Element();
$elements = ids.map(function(id, index) { $idInputs = ids.map(function(id, index) {
return Ox.FormElementGroup({ return Ox.FormElementGroup({
elements: [ elements: [
Ox.Checkbox({ Ox.Checkbox({
overlap: 'right', overlap: 'right',
title: Ox._(id.title), title: Ox._(id.title),
value: id.id == data.mainid, value: id.id == data.mainid,
width: 80 width: 80
}) })
.bindEvent({ .bindEvent({
change: function(data) { change: function(data) {
var value = $elements[index].options('elements')[1].value() var value = $idInputs[index].options('elements')[1].value();
if (data.value) { if (data.value) {
if (value) { if (value) {
$elements.forEach(function($element, i) { editedData = Ox.extend({}, id.id, value);
if (i != index) { $idInputs.forEach(function($input, i) {
$elements[i].options('elements')[0].value(false); if (i != index) {
} $input.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
});
}); });
getMetadata(id.id, data.value, function() { getMetadata(id.id, value, function() {
// ... // ...
}); });
} else {
this.value(false);
} }
} else {
this.value(true);
} }
}) }
], }),
float: 'left' Ox.Input({
}) value: data[id.id] || '',
.css({ width: 160
position: 'absolute', })
left: 16 + Math.floor(index / 2) * 248 + 'px', .bindEvent({
top: 16 + (index % 2) * 24 + 'px' submit: function(data) {
}) if (data.value) {
.appendTo($element); editedData = Ox.extend({}, id.id, data.value);
}), $idInputs.forEach(function($input, i) {
$resetButton = Ox.Button({ $input.options('elements')[0].options({
disabled: true, disabled: true,
title: Ox._('Reset'), value: i == index
width: 64 });
}) $input.options('elements')[1].options({
.css({ disabled: true
position: 'absolute', });
right: '16px', });
top: '64px' getMetadata(id.id, data.value, function() {
}) // ...
.bindEvent({ });
click: function() { }
/* }
keys.forEach(function(key) { })
inputValue(key.id, originalData[key.id]); ],
}); float: 'left'
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)
}
}
})
];
}))
}) })
.css({margin: '16px'}); .css({
return $form; 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) { function renderResults(items) {
items = [Ox.extend({index: '0'}, data)].concat(items);
Ox.print('LIST ITEMS::::', items); Ox.print('LIST ITEMS::::', items);
var $list = Ox.TableList({ var $list = Ox.TableList({
columns: Ox.clone(keys, true), columns: [{
format: function(value, data) {
return (data.title || '') + (
data.author
? ' <span class="OxLight">'
+ data.author.join(', ') + '</span>'
: ''
);
},
id: 'index',
visible: true,
width: 192 - Ox.UI.SCROLLBAR_SIZE
}],
items: items, items: items,
keys: ['author', 'title', 'olid'],
min: 1, min: 1,
max: 1, max: 1,
scrollbarVisible: true, scrollbarVisible: true,
@ -402,37 +363,137 @@ oml.ui.identifyDialog = function(data) {
}) })
.bindEvent({ .bindEvent({
select: function(data) { select: function(data) {
var index = data.ids[0]; var index = data.ids[0], olid;
data = Ox.getObject(items, 'index', index); if (index == '0') {
$results.replaceElement(1, Ox.LoadingScreen().start()); $results.replaceElement(1, oml.ui.infoView(data));
Ox.print('OLID', data.olid); } else {
oml.api.getMetadata({olid: data.olid}, function(result) { olid = $list.value(index, 'olid');
Ox.print('#### GOT DATA', result.data); editedData = {olid: olid};
$results.replaceElement(1, oml.ui.infoView(result.data)); $results.replaceElement(1, Ox.LoadingScreen().start());
that.options('buttons')[1].options({disabled: false}); 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({ $results = Ox.SplitPanel({
elements: [ elements: [
{element: $list, size: 80}, {element: $list, size: 192},
{element: oml.ui.infoView(items[0])} {element: oml.ui.infoView(items[0])}
], ],
orientation: 'vertical' orientation: 'horizontal'
}); });
return $results; 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; var data = {}, empty, original;
keys.forEach(function(key) { ids.forEach(function(id) {
data[key.id] = inputValue(key.id); data[id.id] = idInputValues(id.id)[1];
}); });
empty = isEmpty(data); empty = isEmpty(data);
original = isOriginal(data); original = isOriginal(data);
$clearButton.options({disabled: empty}); $idButtons.clear.options({disabled: empty});
$resetButton.options({disabled: original}); $idButtons.reset.options({disabled: original});
$findButton.options({disabled: empty}); $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; return that;

View File

@ -39,7 +39,9 @@ oml.ui.infoView = function(identifyData) {
}) })
.appendTo(that), .appendTo(that),
$data; $data,
$image, $reflection, $reflectionImage;
if (!identifyData) { if (!identifyData) {
$data = Ox.Element() $data = Ox.Element()
@ -53,6 +55,13 @@ oml.ui.infoView = function(identifyData) {
.appendTo(that); .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) { function formatLight(str) {
return '<span class="OxLight">' + str + '</span>'; return '<span class="OxLight">' + str + '</span>';
} }
@ -83,6 +92,7 @@ oml.ui.infoView = function(identifyData) {
} }
function renderMediaButton(data) { function renderMediaButton(data) {
function getListItems() { function getListItems() {
var items = []; var items = [];
if (ui._lists) { if (ui._lists) {
@ -99,6 +109,7 @@ oml.ui.infoView = function(identifyData) {
} }
return items; return items;
} }
function setListItems() { function setListItems() {
if ($element && ui._lists) { if ($element && ui._lists) {
$element.options({ $element.options({
@ -196,6 +207,25 @@ oml.ui.infoView = function(identifyData) {
return $element; 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) { that.update = function(idOrData, $elements) {
var data = Ox.isObject(idOrData) ? idOrData : null, var data = Ox.isObject(idOrData) ? idOrData : null,
@ -215,16 +245,13 @@ oml.ui.infoView = function(identifyData) {
} }
Ox.print('BOOK DATA', data) Ox.print('BOOK DATA', data)
var $reflection, $mediaButton, var $mediaButton,
isEditable = !data.mainid && data.mediastate == 'available', 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 src = !identifyData
? '/' + data.id + '/cover256.jpg' ? '/' + data.id + '/cover256.jpg'
: data.cover, : data.cover,
ratio = data.coverRatio || oml.config.coverRatio,
size = 256,
reflectionSize = Math.round(size / 2); reflectionSize = Math.round(size / 2);
$elements.forEach(function($element) { $elements.forEach(function($element) {
@ -233,34 +260,35 @@ oml.ui.infoView = function(identifyData) {
if ($element == $cover) { if ($element == $cover) {
$('<img>') $image = $('<img>')
.on({
load: function() {
var ratio = $image[0].width / $image[0].height;
updateCover(size, ratio);
}
})
.attr({src: src}) .attr({src: src})
.css({ .css({
position: 'absolute', position: 'absolute'
left: left + 'px',
width: width + 'px',
height: height + 'px'
}) })
.hide()
.appendTo($cover); .appendTo($cover);
$reflection = $('<div>') $reflection = $('<div>')
.addClass('OxReflection') .addClass('OxReflection')
.css({ .css({
position: 'absolute', position: 'absolute',
top: height + 'px',
width: size + 'px', width: size + 'px',
height: reflectionSize + 'px', height: reflectionSize + 'px',
overflow: 'hidden' overflow: 'hidden'
}) })
.hide()
.appendTo($cover); .appendTo($cover);
$('<img>') $reflectionImage = $('<img>')
.attr({src: src}) .attr({src: src})
.css({ .css({
position: 'absolute', position: 'absolute'
left: left + 'px',
width: width + 'px',
height: height + 'px'
}) })
.appendTo($reflection); .appendTo($reflection);