- use getPage for site dialog

- add events and users dialog and backend
- add some values to preferences/settings dialog
- more migration of backend to new query api
This commit is contained in:
j 2011-09-25 01:09:48 +02:00
parent a6a285367b
commit 52df791560
20 changed files with 604 additions and 131 deletions

View File

@ -29,7 +29,7 @@
], ],
"itemKeys": [ "itemKeys": [
{ {
"id": "all", "id": "*",
"title": "All", "title": "All",
"type": "text", "type": "text",
"find": true "find": true

View File

@ -15,7 +15,6 @@ def parseCondition(condition, user):
value: "1970-1980, value: "1970-1980,
operator: "!=" operator: "!="
} }
...
''' '''
k = condition.get('key', 'name') k = condition.get('key', 'name')
k = { k = {
@ -48,27 +47,18 @@ def parseCondition(condition, user):
key = k key = k
elif k in ('lat', 'lng', 'area', 'south', 'west', 'north', 'east', 'matches', elif k in ('lat', 'lng', 'area', 'south', 'west', 'north', 'east', 'matches',
'id', 'places__id'): 'id', 'places__id'):
if op == '>': key = "%s%s" % (k, {
key = '%s__gt'%k '>': '__gt',
elif op == '>=': '>=': '__gte',
key = '%s__gte'%k '<': '__lt',
elif op == '<': '<=': '__lte',
key = '%s__lt'%k }.get(op, ''))
elif op == '<=':
key = '%s__lte'%k
else: #default is exact match
key = k
else: else:
if op == '=' or op == '^$': key = "%s%s" % (k, {
key = '%s__iexact'%k '==': '__iexact',
elif op == '^': '^': '__istartswith',
v = v[1:] '$': '__iendswith',
key = '%s__istartswith'%k }.get(op, '__icontains'))
elif op == '$':
v = v[:-1]
key = '%s__iendswith'%k
else: # default
key = '%s__icontains'%k
key = str(key) key = str(key)
if exclude: if exclude:

View File

@ -385,6 +385,13 @@ class Volume(models.Model):
def __unicode__(self): def __unicode__(self):
return u"%s's %s"% (self.user, self.name) return u"%s's %s"% (self.user, self.name)
def json(self):
return {
'name': self.name,
'path': 'unknown',
'items': self.files.count()
}
class Instance(models.Model): class Instance(models.Model):
class Meta: class Meta:

View File

@ -3,14 +3,73 @@
from django.db.models import Q, Manager from django.db.models import Q, Manager
def parseCondition(condition, user):
k = condition.get('key', 'name')
k = {
'user': 'user__username',
}.get(k, k)
v = condition['value']
op = condition.get('operator')
if not op:
op = '='
if op.startswith('!'):
op = op[1:]
exclude = True
else:
exclude = False
key = '%s%s' % (k, {
'==': '__iexact',
'^': '__istartswith',
'$': '__iendswith',
}.get(op,'__icontains'))
key = str(key)
if exclude:
q = ~Q(**{k: v})
else:
q = Q(**{k: v})
return q
def parseConditions(conditions, operator, user):
'''
conditions: [
],
operator: "&"
'''
conn = []
for condition in conditions:
if 'conditions' in condition:
q = parseConditions(condition['conditions'],
condition.get('operator', '&'), user)
if q:
conn.append(q)
pass
else:
if condition.get('value', '') != '' or \
condition.get('operator', '') == '=':
conn.append(parseCondition(condition, user))
if conn:
q = conn[0]
for c in conn[1:]:
if operator == '|':
q = q | c
else:
q = q & c
return q
return None
class EventManager(Manager): class EventManager(Manager):
def get_query_set(self): def get_query_set(self):
return super(EventManager, self).get_query_set() return super(EventManager, self).get_query_set()
def find(self, q=''): def find(self, data, user):
qs = self.get_query_set() qs = self.get_query_set()
if q: query = data.get('query', {})
qs = qs.filter(Q(name_find__icontains=q)) conditions = parseConditions(query.get('conditions', []),
query.get('operator', '&'),
user)
if conditions:
qs = qs.filter(conditions)
return qs return qs

View File

@ -6,8 +6,10 @@ from ox.utils import json
from ox.django.decorators import login_required_json from ox.django.decorators import login_required_json
from ox.django.shortcuts import render_to_json_response, get_object_or_404_json, json_response from ox.django.shortcuts import render_to_json_response, get_object_or_404_json, json_response
import models
from api.actions import actions from api.actions import actions
from item import utils
import models
@login_required_json @login_required_json
@ -88,6 +90,33 @@ def removeEvent(request):
return render_to_json_response(response) return render_to_json_response(response)
actions.register(removeEvent, cache=False) actions.register(removeEvent, cache=False)
def parse_query(data, user):
query = {}
query['range'] = [0, 100]
query['sort'] = [{'key':'name', 'operator':'+'}]
for key in ('keys', 'group', 'list', 'range', 'sort', 'query'):
if key in data:
query[key] = data[key]
query['qs'] = models.Event.objects.find(query, user)
if 'itemQuery' in data:
item_query = models.Item.objects.find({'query': data['itemQuery']}, user)
query['qs'] = query['qs'].filter(items__in=item_query)
return query
def order_query(qs, sort):
order_by = []
for e in sort:
operator = e['operator']
if operator != '-':
operator = ''
key = {
'name': 'name_sort',
}.get(e['key'], e['key'])
order = '%s%s' % (operator, key)
order_by.append(order)
if order_by:
qs = qs.order_by(*order_by, nulls_last=True)
return qs
def findEvents(request): def findEvents(request):
''' '''
@ -126,11 +155,30 @@ Positions
https://wiki.0x2620.org/wiki/pandora/QuerySyntax https://wiki.0x2620.org/wiki/pandora/QuerySyntax
ids: ids of events for which positions are required ids: ids of events for which positions are required
''' '''
data = json.loads(request.POST['data'])
response = json_response(status=200, text='ok') response = json_response(status=200, text='ok')
response['data']['events'] = []
#FIXME: add coordinates to limit search data = json.loads(request.POST['data'])
for p in models.Event.objects.find(data['query']): query = parse_query(data, request.user)
response['data']['events'].append(p.json()) qs = query['qs']
if 'keys' in data:
qs = qs[query['range'][0]:query['range'][1]]
response['data']['items'] = [p.json(request.user) for p in qs]
elif 'position' in query:
ids = [i.get_id() for i in qs]
data['conditions'] = data['conditions'] + {
'value': data['position'],
'key': query['sort'][0]['key'],
'operator': '^'
}
query = parse_query(data, request.user)
qs = order_query(query['qs'], query['sort'])
if qs.count() > 0:
response['data']['position'] = utils.get_positions(ids, [qs[0].itemId])[0]
elif 'positions' in data:
ids = [i.get_id() for i in qs]
response['data']['positions'] = utils.get_positions(ids, data['positions'])
else:
response['data']['items'] = qs.count()
return render_to_json_response(response) return render_to_json_response(response)
actions.register(findEvents) actions.register(findEvents)

View File

@ -18,15 +18,15 @@ def parseCondition(condition):
or or
condition: { condition: {
key: "year", key: "year",
value: "1970-1980, value: [1970, 1980],
operator: "!=" operator: "="
} }
... ...
''' '''
k = condition.get('key', 'all') k = condition.get('key', '*')
k = {'id': 'itemId'}.get(k, k) k = {'id': 'itemId'}.get(k, k)
if not k: if not k:
k = 'all' k = '*'
v = condition['value'] v = condition['value']
op = condition.get('operator') op = condition.get('operator')
if not op: if not op:
@ -65,23 +65,20 @@ def parseCondition(condition):
value_key = 'find__value' value_key = 'find__value'
if k in models.Item.facet_keys + ['title']: if k in models.Item.facet_keys + ['title']:
in_find = False in_find = False
if op == '==': facet_value = 'facets__value%s' % {
v = models.Item.objects.filter(facets__key=k, facets__value=v) '==': '__iexact',
elif op == '^': '^': '__istartswith',
v = models.Item.objects.filter(facets__key=k, facets__value__istartswith=v) '$': '__iendswith',
elif op == '$': }.get(op, '__icontains')
v = models.Item.objects.filter(facets__key=k, facets__value__iendswith=v) v = models.Item.objects.filter(**{'facets__key':k, facet_value:v})
else:
v = models.Item.objects.filter(facets__key=k, facets__value__icontains=v)
k = 'id__in' k = 'id__in'
elif op == '==': else:
value_key = 'find__value__iexact' value_key = 'find__value%s' % {
elif op == '^': '==': '__iexact',
value_key = 'find__value__istartswith' '^': '__istartswith',
elif op == '$': '$': '__iendswith',
value_key = 'find__value__iendswith' }.get(op, '__icontains')
else: # default
value_key = 'find__value__icontains'
k = str(k) k = str(k)
if exclude: if exclude:
if k == '*': if k == '*':
@ -121,21 +118,18 @@ def parseCondition(condition):
if key_type == "date": if key_type == "date":
v = parseDate(v.split('.')) v = parseDate(v.split('.'))
if op == '==': else:
vk = 'value__exact' vk = 'value%s' % ({
elif op == '>': '==': '__exact',
vk = 'value__gt' '>': '__gt',
elif op == '>=': '>=': '__gte',
vk = 'value__gte' '<': '__lt',
elif op == '<': '<=': '__lte',
vk = 'value__lt' '^': '__istartswith',
elif op == '<=': '$': '__iendswith',
vk = 'value__lte' }.get(op,'__exact'))
else:
vk = 'value__exact'
vk = 'find__%s' % vk vk = str('find__%s' % vk)
vk = str(vk)
if exclude: #!1960 if exclude: #!1960
return ~Q(**{'find__key': k, vk: v}) return ~Q(**{'find__key': k, vk: v})
@ -192,7 +186,7 @@ class ItemManager(Manager):
return QuerySet(self.model) return QuerySet(self.model)
def filter_list(self, qs, l, user): def filter_list(self, qs, l, user):
if l != "all": if l != "*":
l = l.split(":") l = l.split(":")
only_public = True only_public = True
if not user.is_anonymous(): if not user.is_anonymous():

View File

@ -499,7 +499,7 @@ class Item(models.Model):
elif key['type'] == 'layer': elif key['type'] == 'layer':
qs = Annotation.objects.filter(layer__name=i, item=self).order_by('start') qs = Annotation.objects.filter(layer__name=i, item=self).order_by('start')
save(i, '\n'.join([l.value for l in qs])) save(i, '\n'.join([l.value for l in qs]))
elif i != 'all' and i not in self.facet_keys: elif i != '*' and i not in self.facet_keys:
value = self.get(i) value = self.get(i)
if isinstance(value, list): if isinstance(value, list):
value = u'\n'.join(value) value = u'\n'.join(value)

View File

@ -18,7 +18,6 @@ def parseCondition(condition, user):
value: "1970-1980, value: "1970-1980,
operator: "!=" operator: "!="
} }
...
''' '''
k = condition.get('key', 'name') k = condition.get('key', 'name')
k = { k = {
@ -49,16 +48,11 @@ def parseCondition(condition, user):
elif isinstance(v, bool): #featured and public flag elif isinstance(v, bool): #featured and public flag
key = k key = k
else: else:
if op == '=': key = "%s%s" % (k, {
key = '%s__iexact'%k '==': '__iexact',
elif op == '^': '^': '__istartswith',
v = v[1:] '$': '__iendswith',
key = '%s__istartswith'%k }.get(op, '__icontains'))
elif op == '$':
v = v[:-1]
key = '%s__iendswith'%k
else: # default
key = '%s__icontains'%k
key = str(key) key = str(key)
if exclude: if exclude:

View File

@ -26,7 +26,7 @@ def parseCondition(condition, user):
v = condition['value'] v = condition['value']
op = condition.get('operator') op = condition.get('operator')
if not op: if not op:
op = '' op = '='
if op.startswith('!'): if op.startswith('!'):
op = op[1:] op = op[1:]
exclude = True exclude = True
@ -44,27 +44,18 @@ def parseCondition(condition, user):
if isinstance(v, bool): #featured and public flag if isinstance(v, bool): #featured and public flag
key = k key = k
elif k in ('lat', 'lng', 'area', 'south', 'west', 'north', 'east', 'matches', 'id'): elif k in ('lat', 'lng', 'area', 'south', 'west', 'north', 'east', 'matches', 'id'):
if op == '>': key = '%s%s' % (k, {
key = '%s__gt'%k '>': '__gt',
elif op == '>=': '>=': '__gte',
key = '%s__gte'%k '<': '__lt',
elif op == '<': '<=': '__lte',
key = '%s__lt'%k }.get(op,''))
elif op == '<=':
key = '%s__lte'%k
else: #default is exact match
key = k
else: else:
if op == '=' or op == '^$': key = '%s%s' % (k, {
key = '%s__iexact'%k '==': '__iexact',
elif op == '^': '^': '__istartswith',
v = v[1:] '$': '__iendswith',
key = '%s__istartswith'%k }.get(op,'__icontains'))
elif op == '$':
v = v[:-1]
key = '%s__iendswith'%k
else: # default
key = '%s__icontains'%k
key = str(key) key = str(key)
if exclude: if exclude:
@ -146,8 +137,9 @@ class PlaceManager(Manager):
#join query with operator #join query with operator
qs = self.get_query_set() qs = self.get_query_set()
conditions = parseConditions(data.get('query', {}).get('conditions', []), query = data.get('query', {})
data.get('query', {}).get('operator', '&'), conditions = parseConditions(query.get('conditions', []),
query.get('operator', '&'),
user) user)
if conditions: if conditions:
qs = qs.filter(conditions) qs = qs.filter(conditions)

71
pandora/user/managers.py Normal file
View File

@ -0,0 +1,71 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from django.contrib.auth.models import User
from django.db.models import Q
def parseCondition(condition, user):
k = condition.get('key', 'name')
k = {
'user': 'user__username',
}.get(k, k)
v = condition['value']
op = condition.get('operator')
if not op:
op = '='
if op.startswith('!'):
op = op[1:]
exclude = True
else:
exclude = False
key = '%s%s' % (k, {
'==': '__iexact',
'^': '__istartswith',
'$': '__iendswith',
}.get(op,'__icontains'))
key = str(key)
if exclude:
q = ~Q(**{k: v})
else:
q = Q(**{k: v})
return q
def parseConditions(conditions, operator, user):
'''
conditions: [
],
operator: "&"
'''
conn = []
for condition in conditions:
if 'conditions' in condition:
q = parseConditions(condition['conditions'],
condition.get('operator', '&'), user)
if q:
conn.append(q)
pass
else:
if condition.get('value', '') != '' or \
condition.get('operator', '') == '=':
conn.append(parseCondition(condition, user))
if conn:
q = conn[0]
for c in conn[1:]:
if operator == '|':
q = q | c
else:
q = q & c
return q
return None
def find_user(data, user):
qs = User.objects.all()
query = data.get('query', {})
conditions = parseConditions(query.get('conditions', []),
query.get('operator', '&'),
user)
if conditions:
qs = qs.filter(conditions)
return qs

View File

@ -91,6 +91,12 @@ def user_post_save(sender, instance, **kwargs):
models.signals.post_save.connect(user_post_save, sender=User) models.signals.post_save.connect(user_post_save, sender=User)
#FIXME: this should be one function
def user_json(user, keys, request_user=None):
return {
'username': user.username,
'level': user.get_profile().get_level()
}
def get_user_json(user): def get_user_json(user):
profile = user.get_profile() profile = user.get_profile()
@ -101,4 +107,6 @@ def get_user_json(user):
result['groups'] = [g.name for g in user.groups.all()] result['groups'] = [g.name for g in user.groups.all()]
result['preferences'] = profile.get_preferences() result['preferences'] = profile.get_preferences()
result['ui'] = profile.get_ui() result['ui'] = profile.get_ui()
result['volumes'] = [v.json() for v in user.volumes.all()]
return result return result

View File

@ -15,10 +15,14 @@ from ox.django.shortcuts import render_to_json_response, json_response, get_obje
from ox.django.decorators import login_required_json from ox.django.decorators import login_required_json
import ox import ox
import models
from api.actions import actions from api.actions import actions
from item.models import Access, Item from item.models import Access, Item
from item import utils
import models
import managers
class SigninForm(forms.Form): class SigninForm(forms.Form):
username = forms.TextInput() username = forms.TextInput()
@ -318,28 +322,142 @@ def findUser(request):
} }
} }
''' '''
#admins should be able to find all users, other users only exact matches
#FIXME: support other operators and keys #FIXME: support other operators and keys
data = json.loads(request.POST['data']) data = json.loads(request.POST['data'])
response = json_response(status=200, text='ok') response = json_response(status=200, text='ok')
keys = data.get('keys') keys = data.get('keys')
if not keys: if not keys:
keys = ['username', 'level'] keys = ['username', 'level']
def user_json(user, keys):
return {
'usernname': user.username,
'level': user.get_profile().get_level()
}
if data['key'] == 'email': if data['key'] == 'email':
response['data']['users'] = [user_json(u, keys) response['data']['users'] = [models.user_json(u, keys)
for u in User.objects.filter(email__iexact=data['value'])] for u in User.objects.filter(email__iexact=data['value'])]
else: else:
response['data']['users'] = [user_json(u, keys) response['data']['users'] = [models.user_json(u, keys)
for u in User.objects.filter(username__iexact=data['value'])] for u in User.objects.filter(username__iexact=data['value'])]
return render_to_json_response(response) return render_to_json_response(response)
actions.register(findUser) actions.register(findUser)
def parse_query(data, user):
query = {}
query['range'] = [0, 100]
query['sort'] = [{'key':'name', 'operator':'+'}]
for key in ('keys', 'range', 'sort', 'query'):
if key in data:
query[key] = data[key]
query['qs'] = managers.find_user(query, user)
return query
def order_query(qs, sort):
order_by = []
for e in sort:
operator = e['operator']
if operator != '-':
operator = ''
key = {
}.get(e['key'], e['key'])
order = '%s%s' % (operator, key)
order_by.append(order)
if order_by:
qs = qs.order_by(*order_by, nulls_last=True)
return qs
def findUsers(request):
'''
param data {
query: {
conditions: [
{
key: 'user',
value: 'something',
operator: '='
}
]
operator: ","
},
sort: [{key: 'username', operator: '+'}],
range: [0, 100]
keys: []
}
possible query keys:
username, email, lastLogin, browser
return {
status: {
code: int,
text: string
},
data: {
items: [
{name:, user:, featured:, public...}
]
}
}
param data
{'query': query, 'sort': array, 'range': array}
query: query object, more on query syntax at
https://wiki.0x2620.org/wiki/pandora/QuerySyntax
sort: array of key, operator dics
[
{
key: "year",
operator: "-"
},
{
key: "director",
operator: ""
}
]
range: result range, array [from, to]
with keys, items is list of dicts with requested properties:
return {'status': {'code': int, 'text': string},
'data': {items: array}}
Positions
param data
{'query': query, 'positions': []}
query: query object, more on query syntax at
https://wiki.0x2620.org/wiki/pandora/QuerySyntax
positions: ids of places for which positions are required
'''
if request.user.is_anonymous() or request.user.get_profile().get_level() != 'admin':
response = json_response(status=403, text='permission denied')
return
response = json_response(status=200, text='ok')
data = json.loads(request.POST['data'])
query = parse_query(data, request.user)
qs = query['qs']
if 'keys' in data:
qs = qs[query['range'][0]:query['range'][1]]
response['data']['items'] = [models.user_json(p, data['keys'], request.user) for p in qs]
elif 'position' in query:
ids = [i.get_id() for i in qs]
data['conditions'] = data['conditions'] + {
'value': data['position'],
'key': query['sort'][0]['key'],
'operator': '^'
}
query = parse_query(data, request.user)
qs = order_query(query['qs'], query['sort'])
if qs.count() > 0:
response['data']['position'] = utils.get_positions(ids, [qs[0].itemId])[0]
elif 'positions' in data:
ids = [i.get_id() for i in qs]
response['data']['positions'] = utils.get_positions(ids, data['positions'])
else:
response['data']['items'] = qs.count()
return render_to_json_response(response)
actions.register(findUsers)
class ContactForm(forms.Form): class ContactForm(forms.Form):
email = forms.EmailField() email = forms.EmailField()
subject = forms.TextInput() subject = forms.TextInput()

View File

@ -0,0 +1,65 @@
// vim: et:ts=4:sw=4:sts=4:ft=javascript
pandora.ui.eventsDialog = function() {
var height = Math.round((window.innerHeight - 48) * 0.9),
width = Math.round(window.innerWidth * 0.9),
that = Ox.Dialog({
buttons: [
Ox.Button({
id: 'done',
title: 'Done'
}).bindEvent({
click: function() {
that.close();
}
})
],
closeButton: true,
content: pandora.$ui.eventsElement = Ox.TextList({
columns: [
{
id: 'id',
title: 'ID',
operator: '+',
unique: true,
visible: false,
width: 16
},
{
id: 'name',
title: 'Name',
operator: '+',
visible: true,
width: 256
},
{
id: 'start',
operator: '+',
visible: true,
width: 256
},
{
id: 'end',
operator: '+',
visible: true,
width: 256
}
],
items: function(data, callback) {
pandora.api.findEvents(data, callback);
},
keys: ['name', 'start', 'end'],
sort: [
{key: 'name', operator: '+'}
]
}),
height: height,
maximizeButton: true,
minHeight: 256,
minWidth: 512,
padding: 0,
title: 'Manage Events',
width: width
});
return that;
};

View File

@ -39,11 +39,49 @@ pandora.ui.item = function() {
); );
} else if (pandora.user.ui.itemView == 'calendar') { } else if (pandora.user.ui.itemView == 'calendar') {
pandora.$ui.contentPanel.replaceElement(1, Ox.Element().html('Calendar')); pandora.api.findEvents({
itemQuery: {conditions: [{key: 'id', value: pandora.user.ui.item, operator:'='}]},
keys: ['id', 'name', 'start', 'end'],
query: {}
}, function(r) {
if (r.data.items.length>0) {
pandora.$ui.contentPanel.replaceElement(1, Ox.SplitPanel({
elements: [
{
element: pandora.$ui.calendar = Ox.Calendar({
date: new Date(0),
events: r.data.items,
height: window.innerHeight - pandora.user.ui.showGroups * pandora.user.ui.groupsSize - 61,
range: [-5000, 5000],
width: window.innerWidth - pandora.user.ui.showSidebar * pandora.user.ui.sidebarSize - 2 - 144 - Ox.UI.SCROLLBAR_SIZE,
zoom: 4
})
},
{
element: Ox.Element(),
id: 'place',
size: 144 + Ox.UI.SCROLLBAR_SIZE
}
],
orientation: 'horizontal'
})
.bindEvent('resize', function(data) {
}));
} else {
pandora.$ui.contentPanel.replaceElement(1,
Ox.Element()
.css({marginTop: '32px', fontSize: '12px', textAlign: 'center'})
.html(
'Sorry, <i>' + result.data.title
+ '</i> currently doesn\'t have a '
+ pandora.user.ui.itemView + ' view.'
));
}
});
} else if (pandora.user.ui.itemView == 'clips') { } else if (pandora.user.ui.itemView == 'clips') {
var ratio = result.data.stream.aspectRatio; var ratio = result.data.stream.aspectRatio;
Ox.print('RATIO', ratio)
pandora.$ui.contentPanel.replaceElement(1, pandora.$ui.clips = Ox.IconList({ pandora.$ui.contentPanel.replaceElement(1, pandora.$ui.clips = Ox.IconList({
fixedRatio: ratio, fixedRatio: ratio,
item: function(data, sort, size) { item: function(data, sort, size) {

View File

@ -499,18 +499,17 @@ pandora.ui.list = function() { // fixme: remove view argument
}); });
pandora.api.findEvents({ pandora.api.findEvents({
query: '', itemQuery: pandora.user.ui.query,
itemQuery: pandora.user.ui.query keys: ['id', 'name', 'start', 'end'],
query: {}
}, function(result) { }, function(result) {
Ox.print(">>>>>>>", result); that.replaceElement(0, pandora.$ui.calendar = Ox.Calendar({
that.replaceElement(0, date: new Date(0),
pandora.$ui.calendar = Ox.Calendar({ events: result.data.items,
date: new Date(0), height: window.innerHeight - pandora.user.ui.showGroups * pandora.user.ui.groupsSize - 61,
events: result.data.events, range: [-5000, 5000],
height: window.innerHeight - pandora.user.ui.showGroups * pandora.user.ui.groupsSize - 61, width: window.innerWidth - pandora.user.ui.showSidebar * pandora.user.ui.sidebarSize - 2 - 144 - Ox.UI.SCROLLBAR_SIZE,
range: [-5000, 5000], zoom: 4
width: window.innerWidth - pandora.user.ui.showSidebar * pandora.user.ui.sidebarSize - 2 - 144 - Ox.UI.SCROLLBAR_SIZE,
zoom: 4
})); }));
}); });
} else { } else {

View File

@ -521,6 +521,12 @@ pandora.ui.mainMenu = function() {
overflow: 'hidden' overflow: 'hidden'
}).append($manage).open(); }).append($manage).open();
*/ */
} else if (data.id == 'events') {
pandora.$ui.eventsDialog = pandora.ui.eventsDialog().open();
} else if (data.id == 'users') {
pandora.$ui.eventsDialog = pandora.ui.usersDialog().open();
} else if (data.id == 'lists') {
pandora.$ui.eventsDialog = pandora.ui.listsDialog().open();
} else if (data.id == 'query') { } else if (data.id == 'query') {
var $dialog = Ox.Dialog({ var $dialog = Ox.Dialog({
buttons: [ buttons: [

View File

@ -6,6 +6,36 @@ pandora.ui.preferencesDialog = function() {
]; ];
var $tabPanel = Ox.TabPanel({ var $tabPanel = Ox.TabPanel({
content: function(id) { content: function(id) {
var content = Ox.Element().css({padding: '16px', overflowY: 'auto'});
if (id == 'account') {
content.append(Ox.FormElementGroup({
elements: Ox.values(Ox.map(pandora.user.preferences, function(v, k) {
return Ox.Input({
id: k,
width: 400,
label: Ox.toTitleCase(k),
value: v
});
}))
}));
} else {
content.append(Ox.FormElementGroup({
elements: [
Ox.Checkbox({
checked: true ,
id: 'showEpisodes',
title: 'Show Episodes',
width: 400
}),
Ox.Checkbox({
checked: true ,
id: 'newsletter',
title: 'Receive Newsletter',
width: 400
})
]
}));
}
return Ox.SplitPanel({ return Ox.SplitPanel({
elements: [ elements: [
{ {
@ -19,9 +49,7 @@ pandora.ui.preferencesDialog = function() {
size: 144 size: 144
}, },
{ {
element: Ox.Element() element: content
.css({padding: '16px', overflowY: 'auto'})
.html(Ox.repeat(Ox.getObjectById(tabs, id).title + ' ', 200))
} }
], ],
orientation: 'horizontal' orientation: 'horizontal'
@ -52,4 +80,4 @@ pandora.ui.preferencesDialog = function() {
return $dialog; return $dialog;
}; };

View File

@ -12,6 +12,10 @@ pandora.ui.siteDialog = function(section) {
Ox.getObjectById(tabs, section).selected = true; Ox.getObjectById(tabs, section).selected = true;
var $tabPanel = Ox.TabPanel({ var $tabPanel = Ox.TabPanel({
content: function(id) { content: function(id) {
var content = Ox.Element().css({padding: '16px', overflowY: 'auto'});
pandora.api.getPage({name:id}, function(result) {
content.html(result.data.body);
});
return Ox.SplitPanel({ return Ox.SplitPanel({
elements: [ elements: [
{ {
@ -27,9 +31,7 @@ pandora.ui.siteDialog = function(section) {
size: 272 size: 272
}, },
{ {
element: Ox.Element() element: content
.css({padding: '16px', overflowY: 'auto'})
.html(Ox.repeat(Ox.getObjectById(tabs, id).title + ' ', 200))
} }
], ],
orientation: 'horizontal' orientation: 'horizontal'
@ -68,4 +70,4 @@ pandora.ui.siteDialog = function(section) {
return $dialog; return $dialog;
}; };

View File

@ -0,0 +1,52 @@
// vim: et:ts=4:sw=4:sts=4:ft=javascript
pandora.ui.usersDialog = function() {
var height = Math.round((window.innerHeight - 48) * 0.9),
width = Math.round(window.innerWidth * 0.9),
that = Ox.Dialog({
buttons: [
Ox.Button({
id: 'done',
title: 'Done'
}).bindEvent({
click: function() {
that.close();
}
})
],
closeButton: true,
content: pandora.$ui.usersElement = Ox.TextList({
columns: [
{
id: 'username',
title: 'Name',
operator: '+',
visible: true,
unique: true,
width: 256
},
{
id: 'level',
operator: '+',
visible: true,
width: 256
}
],
items: function(data, callback) {
pandora.api.findUsers(data, callback);
},
keys: [],
sort: [
{key: 'username', operator: '+'}
]
}),
height: height,
maximizeButton: true,
minHeight: 256,
minWidth: 512,
padding: 0,
title: 'Manage Users',
width: width
});
return that;
};

View File

@ -44,5 +44,7 @@
"js/pandora/ui/home.js", "js/pandora/ui/home.js",
"js/pandora/ui/preferencesDialog.js", "js/pandora/ui/preferencesDialog.js",
"js/pandora/ui/listDialog.js", "js/pandora/ui/listDialog.js",
"js/pandora/ui/siteDialog.js" "js/pandora/ui/siteDialog.js",
"js/pandora/ui/eventsDialog.js",
"js/pandora/ui/usersDialog.js"
] ]