add sort names/titles

This commit is contained in:
Jan Gerber 2015-05-14 13:03:49 +02:00
parent 984a354cf8
commit 6bce40ad3a
8 changed files with 579 additions and 0 deletions

View file

@ -17,6 +17,9 @@ import settings
import state
import utils
from . import person_api
from . import title_api
import logging
logger = logging.getLogger('oml.item.api')

View file

@ -46,3 +46,9 @@ class Person(db.Model):
state.db.session.add(self)
state.db.session.commit()
def json(self, keys=None):
r = {}
r['name'] = self.name
r['sortname'] = self.sortname
r['numberofnames'] = self.numberofnames
return r

113
oml/item/person_api.py Normal file
View file

@ -0,0 +1,113 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
import unicodedata
from oxtornado import actions
from queryparser import get_operator
from .person import Person
import logging
logger = logging.getLogger('oml.item.person_api')
def parse(data, model):
query = {}
query['range'] = [0, 100]
if not 'group' in data:
query['sort'] = [{'key':'sortname', 'operator':'+'}]
for key in ('keys', 'group', 'list', 'range', 'sort', 'query'):
if key in data:
query[key] = data[key]
# print(data)
query['qs'] = model.query
if 'query' in data and data['query'].get('conditions'):
conditions = []
for c in data['query']['conditions']:
op = get_operator(c['operator'])
conditions.append(op(getattr(model, c['key']), c['value']))
if data['query'].get('operator') == '|':
q = conditions[0]
for c in conditions[1:]:
q = q | c
q = [q]
else:
q = conditions
for c in q:
query['qs'] = query['qs'].filter(c)
query['qs'] = order(query['qs'], query['sort'])
return query
def order(qs, sort):
order_by = []
for e in sort:
operator = e['operator']
if operator != '-':
operator = ''
else:
operator = ' DESC'
key = {}.get(e['key'], e['key'])
order = '%s%s' % (key, operator)
order_by.append(order)
if order_by:
#nulllast not supported in sqlite, use IS NULL hack instead
#order_by = map(nullslast, order_by)
_order_by = []
for order in order_by:
nulls = "%s IS NULL" % order.split(' ')[0]
_order_by.append(nulls)
_order_by.append(order)
order_by = _order_by
qs = qs.order_by(*order_by)
return qs
def editName(data):
'''
takes {
name string
sortanme string
}
'''
response = {}
person = Person.get(data['name'])
person.sortname = unicodedata.normalize('NFKD', data['sortname'])
person.save()
response['name'] = person.name
response['sortname'] = person.sortname
return response
actions.register(editName)
def findNames(data):
'''
takes {
query {
conditions [{}]
operator string
}
keys [string]
sort [{}]
range [int, int]
}
'''
response = {}
q = parse(data, Person)
if 'position' in data:
pass
#ids = [i.id for i in q['qs'].options(load_only('id'))]
#response['position'] = utils.get_positions(ids, [data['qs'][0].id])[0]
print('fixme', data)
elif 'positions' in data:
#ids = [i.id for i in q['qs'].options(load_only('id'))]
#response['positions'] = utils.get_positions(ids, data['positions'])
response['positions'] = []
print('fixme', data)
elif 'keys' in data:
response['items'] = []
for i in q['qs'][q['range'][0]:q['range'][1]]:
j = i.json()
response['items'].append({k:j[k] for k in j if not data['keys'] or k in data['keys']})
else:
response['items'] = q['qs'].count()
return response
actions.register(findNames)

74
oml/item/title_api.py Normal file
View file

@ -0,0 +1,74 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from oxtornado import actions
from . import models
from . import query
import logging
logger = logging.getLogger('oml.item.title_api')
def editTitle(data):
'''
takes {
id string
sortname string
}
'''
response = {}
'''
item = models.Item.get(data['id'])
item.sortname = unicodedata.normalize('NFKD', data['sortname'])
item.save()
response['name'] = item.name
response['sortname'] = item.sortname
'''
return response
actions.register(editTitle)
def findTitles(data):
'''
takes {
query {
conditions [{}]
operator string
}
keys [string]
sort [{}]
range [int, int]
}
'''
response = {}
#q = query.parse(data)
q = {
'qs': models.Item.query,
}
if 'range' in data:
q['range'] = data['range']
if 'position' in data:
pass
#ids = [i.id for i in q['qs'].options(load_only('id'))]
#response['position'] = utils.get_positions(ids, [data['qs'][0].id])[0]
print('fixme', data)
elif 'positions' in data:
#ids = [i.id for i in q['qs'].options(load_only('id'))]
#response['positions'] = utils.get_positions(ids, data['positions'])
response['positions'] = []
print('fixme', data)
elif 'keys' in data:
response['items'] = []
for i in q['qs'][q['range'][0]:q['range'][1]]:
j = {}
for key in (data['keys'] or ['title', 'sorttitle']):
if key == 'title':
j[key] = i.info.get(key)
elif key == 'sorttitle':
j[key] = i.sort[0].title
response['items'].append(j)
else:
response['items'] = q['qs'].count()
return response
actions.register(findTitles)

View file

@ -456,6 +456,14 @@ oml.ui.mainMenu = function() {
oml.localStorage('enableDebugMode', true);
}
window.location.reload();
} else if (id == 'sortnames') {
(oml.$ui.namesDialog || (
oml.$ui.namesDialog = oml.ui.namesDialog()
)).open();
} else if (id == 'sorttitles') {
(oml.$ui.titlesDialog || (
oml.$ui.titlesDialog = oml.ui.titlesDialog()
)).open();
} else {
Ox.print('MAIN MENU DOES NOT YET HANDLE', id);
}

183
static/js/namesDialog.js Normal file
View file

@ -0,0 +1,183 @@
'use strict';
oml.ui.namesDialog = function() {
var height = Math.round((window.innerHeight - 48) * 0.9),
width = 576 + Ox.UI.SCROLLBAR_SIZE,
$findInput = Ox.Input({
changeOnKeypress: true,
clear: true,
placeholder: Ox._('Find'),
width: 192
})
.css({float: 'right', margin: '4px'})
.bindEvent({
change: function(data) {
var query = {
conditions: [
{
key: 'name',
operator: '=',
value: data.value
},
{
key: 'sortname',
operator: '=',
value: data.value
}
],
operator: '|'
};
$list.options({
query: query,
});
}
}),
$list = Ox.TableList({
columns: [
{
id: 'name',
operator: '+',
removable: false,
title: Ox._('Name'),
visible: true,
width: 256
},
{
editable: true,
id: 'sortname',
operator: '+',
title: Ox._('Sort Name'),
tooltip: Ox._('Edit Sort Name'),
visible: true,
width: 256
},
{
id: 'numberofnames',
align: 'right',
operator: '-',
title: Ox._('Names'),
visible: true,
width: 64
},
],
columnsVisible: true,
items: oml.api.findNames,
max: 1,
scrollbarVisible: true,
sort: [{key: 'sortname', operator: '+'}],
unique: 'name'
})
.bindEvent({
init: function(data) {
$status.html(
Ox.toTitleCase(Ox.formatCount(data.items, 'name'))
);
},
open: function(data) {
$list.find('.OxItem.OxSelected > .OxCell.OxColumnSortname')
.trigger('mousedown')
.trigger('mouseup');
},
select: function(data) {
$findButton.options({disabled: !data.ids.length});
},
submit: function(data) {
Ox.Request.clearCache('findNames');
oml.api.editName({
name: data.id,
sortname: data.value
});
}
}),
$findButton = Ox.Button({
disabled: true,
title: Ox._('Find'),
width: 48
}).bindEvent({
click: function() {
that.close();
oml.URL.push('/author=='
+ $list.value($list.options('selected'), 'name'));
}
}),
that = Ox.Dialog({
buttons: [
Ox.Button({
title: Ox._('Sort Titles...')
}).bindEvent({
click: function() {
that.close();
(oml.$ui.titlesDialog || (
oml.$ui.titlesDialog = oml.ui.titlesDialog()
)).open();
}
}),
{},
$findButton,
Ox.Button({
title: Ox._('Done'),
width: 48
}).bindEvent({
click: function() {
that.close();
}
})
],
closeButton: true,
content: Ox.SplitPanel({
elements: [
{
element: Ox.Bar({size: 24})
.append($status)
.append(
$findInput
),
size: 24
},
{
element: $list
}
],
orientation: 'vertical'
}),
height: height,
maximizeButton: true,
minHeight: 256,
minWidth: 512,
padding: 0,
title: Ox._('Sort Names'),
width: width
})
.bindEvent({
resizeend: function(data) {
var width = (data.width - 64 - Ox.UI.SCROLLBAR_SIZE) / 2;
[
{id: 'name', width: Math.ceil(width)},
{id: 'sortname', width: Math.floor(width)}
].forEach(function(column) {
$list.resizeColumn(column.id, column.width);
});
}
}),
$status = $('<div>')
.css({
position: 'absolute',
top: '4px',
left: '128px',
right: '128px',
bottom: '4px',
paddingTop: '2px',
fontSize: '9px',
textAlign: 'center'
})
.appendTo(that.find('.OxButtonsbar'));
return that;
};

190
static/js/titlesDialog.js Normal file
View file

@ -0,0 +1,190 @@
'use strict';
oml.ui.titlesDialog = function() {
var height = Math.round((window.innerHeight - 48) * 0.9),
width = 512 + Ox.UI.SCROLLBAR_SIZE,
$findInput = Ox.Input({
changeOnKeypress: true,
clear: true,
placeholder: Ox._('Find'),
width: 192
})
.css({float: 'right', margin: '4px'})
.bindEvent({
change: function(data) {
var query = {
conditions: [
{
key: 'title',
operator: '=',
value: data.value
},
{
key: 'sorttitle',
operator: '=',
value: data.value
}
],
operator: '|'
};
$list.options({
query: query
});
}
}),
$list = Ox.TableList({
columns: [
{
id: 'id',
title: Ox._('ID'),
visible: false
},
{
id: 'title',
operator: '+',
removable: false,
title: Ox._('Title'),
visible: true,
width: 256
},
{
editable: true,
id: 'sorttitle',
operator: '+',
title: Ox._('Sort Title'),
visible: true,
width: 256
},
],
columnsVisible: true,
items: oml.api.findTitles,
keys: [],
max: 1,
scrollbarVisible: true,
sort: [{key: 'sorttitle', operator: '+'}],
unique: 'id'
})
.bindEvent({
init: function(data) {
$status.html(
Ox.toTitleCase(Ox.formatCount(data.items, 'title'))
);
},
open: function(data) {
$list.find('.OxItem.OxSelected > .OxCell.OxColumnSorttitle')
.trigger('mousedown')
.trigger('mouseup');
},
select: function(data) {
$findButton.options({disabled: !data.ids.length});
},
submit: function(data) {
Ox.Request.clearCache('findTitles');
oml.api.editTitle({
id: data.id,
sorttitle: data.value
});
}
}),
$findButton = Ox.Button({
disabled: true,
title: Ox._('Find'),
width: 48
}).bindEvent({
click: function() {
that.close();
oml.UI.set({find: {
conditions: [{
key: 'title',
value: $list.value(
$list.options('selected'), 'title'
),
operator: '='
}],
operator: '&'
}});
oml.$ui.findElement.updateElement();
}
}),
that = Ox.Dialog({
buttons: [
Ox.Button({
title: Ox._('Sort Names...')
}).bindEvent({
click: function() {
that.close();
(oml.$ui.namesDialog || (
oml.$ui.namesDialog = oml.ui.namesDialog()
)).open();
}
}),
{},
$findButton,
Ox.Button({
title: Ox._('Done'),
width: 48
}).bindEvent({
click: function() {
that.close();
}
})
],
closeButton: true,
content: Ox.SplitPanel({
elements: [
{
element: Ox.Bar({size: 24})
.append($status)
.append(
$findInput
),
size: 24
},
{
element: $list
}
],
orientation: 'vertical'
}),
height: height,
maximizeButton: true,
minHeight: 256,
minWidth: 512,
padding: 0,
title: Ox._('Sort Titles'),
width: width
})
.bindEvent({
resizeend: function(data) {
var width = (data.width - Ox.UI.SCROLLBAR_SIZE) / 2;
[
{id: 'title', width: Math.ceil(width)},
{id: 'sorttitle', width: Math.floor(width)}
].forEach(function(column) {
$list.resizeColumn(column.id, column.width);
});
}
}),
$status = $('<div>')
.css({
position: 'absolute',
top: '4px',
left: '128px',
right: '128px',
bottom: '4px',
paddingTop: '2px',
fontSize: '9px',
textAlign: 'center'
})
.appendTo(that.find('.OxButtonsbar'));
return that;
};

View file

@ -46,6 +46,7 @@
"loadingIcon.js",
"mainMenu.js",
"mainPanel.js",
"namesDialog.js",
"notificationsButton.js",
"openButton.js",
"preferencesDialog.js",
@ -58,6 +59,7 @@
"sortElement.js",
"statusIcon.js",
"statusbar.js",
"titlesDialog.js",
"transfersDialog.js",
"updateBotton.js",
"userButton.js",