add sort names/titles
This commit is contained in:
parent
984a354cf8
commit
6bce40ad3a
8 changed files with 579 additions and 0 deletions
|
@ -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')
|
||||
|
||||
|
|
|
@ -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
113
oml/item/person_api.py
Normal 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
74
oml/item/title_api.py
Normal 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)
|
|
@ -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
183
static/js/namesDialog.js
Normal 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
190
static/js/titlesDialog.js
Normal 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;
|
||||
|
||||
};
|
||||
|
|
@ -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",
|
||||
|
|
Loading…
Reference in a new issue