diff --git a/pandora/0xdb.json b/pandora/0xdb.json index 4d25cd96..0640dfe7 100644 --- a/pandora/0xdb.json +++ b/pandora/0xdb.json @@ -29,7 +29,7 @@ ], "itemKeys": [ { - "id": "all", + "id": "*", "title": "All", "type": "text", "find": true diff --git a/pandora/annotation/managers.py b/pandora/annotation/managers.py index efb9930e..787ad04b 100644 --- a/pandora/annotation/managers.py +++ b/pandora/annotation/managers.py @@ -15,7 +15,6 @@ def parseCondition(condition, user): value: "1970-1980, operator: "!=" } - ... ''' k = condition.get('key', 'name') k = { @@ -48,27 +47,18 @@ def parseCondition(condition, user): key = k elif k in ('lat', 'lng', 'area', 'south', 'west', 'north', 'east', 'matches', 'id', 'places__id'): - if op == '>': - key = '%s__gt'%k - elif op == '>=': - key = '%s__gte'%k - elif op == '<': - key = '%s__lt'%k - elif op == '<=': - key = '%s__lte'%k - else: #default is exact match - key = k + key = "%s%s" % (k, { + '>': '__gt', + '>=': '__gte', + '<': '__lt', + '<=': '__lte', + }.get(op, '')) else: - if op == '=' or op == '^$': - key = '%s__iexact'%k - elif op == '^': - v = v[1:] - key = '%s__istartswith'%k - elif op == '$': - v = v[:-1] - key = '%s__iendswith'%k - else: # default - key = '%s__icontains'%k + key = "%s%s" % (k, { + '==': '__iexact', + '^': '__istartswith', + '$': '__iendswith', + }.get(op, '__icontains')) key = str(key) if exclude: diff --git a/pandora/archive/models.py b/pandora/archive/models.py index 7b639370..83dc6335 100644 --- a/pandora/archive/models.py +++ b/pandora/archive/models.py @@ -385,6 +385,13 @@ class Volume(models.Model): def __unicode__(self): 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 Meta: diff --git a/pandora/event/managers.py b/pandora/event/managers.py index fcd9cf00..1bf7c218 100644 --- a/pandora/event/managers.py +++ b/pandora/event/managers.py @@ -3,14 +3,73 @@ 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): def get_query_set(self): return super(EventManager, self).get_query_set() - def find(self, q=''): + def find(self, data, user): qs = self.get_query_set() - if q: - qs = qs.filter(Q(name_find__icontains=q)) + query = data.get('query', {}) + conditions = parseConditions(query.get('conditions', []), + query.get('operator', '&'), + user) + if conditions: + qs = qs.filter(conditions) return qs diff --git a/pandora/event/views.py b/pandora/event/views.py index ff11a9ce..17fc8bc6 100644 --- a/pandora/event/views.py +++ b/pandora/event/views.py @@ -6,8 +6,10 @@ from ox.utils import 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 -import models from api.actions import actions +from item import utils + +import models @login_required_json @@ -88,6 +90,33 @@ def removeEvent(request): return render_to_json_response(response) 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): ''' @@ -126,11 +155,30 @@ Positions https://wiki.0x2620.org/wiki/pandora/QuerySyntax ids: ids of events for which positions are required ''' - data = json.loads(request.POST['data']) response = json_response(status=200, text='ok') - response['data']['events'] = [] - #FIXME: add coordinates to limit search - for p in models.Event.objects.find(data['query']): - response['data']['events'].append(p.json()) + + 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'] = [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) actions.register(findEvents) diff --git a/pandora/item/managers.py b/pandora/item/managers.py index 429de901..0e137a58 100644 --- a/pandora/item/managers.py +++ b/pandora/item/managers.py @@ -18,15 +18,15 @@ def parseCondition(condition): or condition: { key: "year", - value: "1970-1980, - operator: "!=" + value: [1970, 1980], + operator: "=" } ... ''' - k = condition.get('key', 'all') + k = condition.get('key', '*') k = {'id': 'itemId'}.get(k, k) if not k: - k = 'all' + k = '*' v = condition['value'] op = condition.get('operator') if not op: @@ -65,23 +65,20 @@ def parseCondition(condition): value_key = 'find__value' if k in models.Item.facet_keys + ['title']: in_find = False - if op == '==': - v = models.Item.objects.filter(facets__key=k, facets__value=v) - elif op == '^': - v = models.Item.objects.filter(facets__key=k, facets__value__istartswith=v) - elif op == '$': - v = models.Item.objects.filter(facets__key=k, facets__value__iendswith=v) - else: - v = models.Item.objects.filter(facets__key=k, facets__value__icontains=v) + facet_value = 'facets__value%s' % { + '==': '__iexact', + '^': '__istartswith', + '$': '__iendswith', + }.get(op, '__icontains') + v = models.Item.objects.filter(**{'facets__key':k, facet_value:v}) k = 'id__in' - elif op == '==': - value_key = 'find__value__iexact' - elif op == '^': - value_key = 'find__value__istartswith' - elif op == '$': - value_key = 'find__value__iendswith' - else: # default - value_key = 'find__value__icontains' + else: + value_key = 'find__value%s' % { + '==': '__iexact', + '^': '__istartswith', + '$': '__iendswith', + }.get(op, '__icontains') + k = str(k) if exclude: if k == '*': @@ -121,21 +118,18 @@ def parseCondition(condition): if key_type == "date": v = parseDate(v.split('.')) - if op == '==': - vk = 'value__exact' - elif op == '>': - vk = 'value__gt' - elif op == '>=': - vk = 'value__gte' - elif op == '<': - vk = 'value__lt' - elif op == '<=': - vk = 'value__lte' - else: - vk = 'value__exact' + else: + vk = 'value%s' % ({ + '==': '__exact', + '>': '__gt', + '>=': '__gte', + '<': '__lt', + '<=': '__lte', + '^': '__istartswith', + '$': '__iendswith', + }.get(op,'__exact')) - vk = 'find__%s' % vk - vk = str(vk) + vk = str('find__%s' % vk) if exclude: #!1960 return ~Q(**{'find__key': k, vk: v}) @@ -192,7 +186,7 @@ class ItemManager(Manager): return QuerySet(self.model) def filter_list(self, qs, l, user): - if l != "all": + if l != "*": l = l.split(":") only_public = True if not user.is_anonymous(): diff --git a/pandora/item/models.py b/pandora/item/models.py index 468d5f37..2c4440fc 100644 --- a/pandora/item/models.py +++ b/pandora/item/models.py @@ -499,7 +499,7 @@ class Item(models.Model): elif key['type'] == 'layer': qs = Annotation.objects.filter(layer__name=i, item=self).order_by('start') 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) if isinstance(value, list): value = u'\n'.join(value) diff --git a/pandora/itemlist/managers.py b/pandora/itemlist/managers.py index 48917a2c..8e10601a 100644 --- a/pandora/itemlist/managers.py +++ b/pandora/itemlist/managers.py @@ -18,7 +18,6 @@ def parseCondition(condition, user): value: "1970-1980, operator: "!=" } - ... ''' k = condition.get('key', 'name') k = { @@ -49,16 +48,11 @@ def parseCondition(condition, user): elif isinstance(v, bool): #featured and public flag key = k else: - if op == '=': - key = '%s__iexact'%k - elif op == '^': - v = v[1:] - key = '%s__istartswith'%k - elif op == '$': - v = v[:-1] - key = '%s__iendswith'%k - else: # default - key = '%s__icontains'%k + key = "%s%s" % (k, { + '==': '__iexact', + '^': '__istartswith', + '$': '__iendswith', + }.get(op, '__icontains')) key = str(key) if exclude: diff --git a/pandora/place/managers.py b/pandora/place/managers.py index a0545c98..eeb0e7f8 100644 --- a/pandora/place/managers.py +++ b/pandora/place/managers.py @@ -26,7 +26,7 @@ def parseCondition(condition, user): v = condition['value'] op = condition.get('operator') if not op: - op = '' + op = '=' if op.startswith('!'): op = op[1:] exclude = True @@ -44,27 +44,18 @@ def parseCondition(condition, user): if isinstance(v, bool): #featured and public flag key = k elif k in ('lat', 'lng', 'area', 'south', 'west', 'north', 'east', 'matches', 'id'): - if op == '>': - key = '%s__gt'%k - elif op == '>=': - key = '%s__gte'%k - elif op == '<': - key = '%s__lt'%k - elif op == '<=': - key = '%s__lte'%k - else: #default is exact match - key = k + key = '%s%s' % (k, { + '>': '__gt', + '>=': '__gte', + '<': '__lt', + '<=': '__lte', + }.get(op,'')) else: - if op == '=' or op == '^$': - key = '%s__iexact'%k - elif op == '^': - v = v[1:] - key = '%s__istartswith'%k - elif op == '$': - v = v[:-1] - key = '%s__iendswith'%k - else: # default - key = '%s__icontains'%k + key = '%s%s' % (k, { + '==': '__iexact', + '^': '__istartswith', + '$': '__iendswith', + }.get(op,'__icontains')) key = str(key) if exclude: @@ -146,8 +137,9 @@ class PlaceManager(Manager): #join query with operator qs = self.get_query_set() - conditions = parseConditions(data.get('query', {}).get('conditions', []), - data.get('query', {}).get('operator', '&'), + query = data.get('query', {}) + conditions = parseConditions(query.get('conditions', []), + query.get('operator', '&'), user) if conditions: qs = qs.filter(conditions) diff --git a/pandora/user/managers.py b/pandora/user/managers.py new file mode 100644 index 00000000..3cb9084c --- /dev/null +++ b/pandora/user/managers.py @@ -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 diff --git a/pandora/user/models.py b/pandora/user/models.py index 76aeeabf..4d3bf2ab 100644 --- a/pandora/user/models.py +++ b/pandora/user/models.py @@ -91,6 +91,12 @@ def user_post_save(sender, instance, **kwargs): 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): profile = user.get_profile() @@ -101,4 +107,6 @@ def get_user_json(user): result['groups'] = [g.name for g in user.groups.all()] result['preferences'] = profile.get_preferences() result['ui'] = profile.get_ui() + result['volumes'] = [v.json() for v in user.volumes.all()] return result + diff --git a/pandora/user/views.py b/pandora/user/views.py index 827c938e..d80ffe33 100644 --- a/pandora/user/views.py +++ b/pandora/user/views.py @@ -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 import ox -import models from api.actions import actions from item.models import Access, Item +from item import utils + +import models +import managers + class SigninForm(forms.Form): 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 data = json.loads(request.POST['data']) response = json_response(status=200, text='ok') keys = data.get('keys') if not keys: keys = ['username', 'level'] - def user_json(user, keys): - return { - 'usernname': user.username, - 'level': user.get_profile().get_level() - } 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'])] 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'])] return render_to_json_response(response) 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): email = forms.EmailField() subject = forms.TextInput() diff --git a/static/js/pandora/ui/eventsDialog.js b/static/js/pandora/ui/eventsDialog.js new file mode 100644 index 00000000..a32be08f --- /dev/null +++ b/static/js/pandora/ui/eventsDialog.js @@ -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; +}; + diff --git a/static/js/pandora/ui/item.js b/static/js/pandora/ui/item.js index c7b0521d..1d0ee505 100644 --- a/static/js/pandora/ui/item.js +++ b/static/js/pandora/ui/item.js @@ -39,11 +39,49 @@ pandora.ui.item = function() { ); } 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, ' + result.data.title + + ' currently doesn\'t have a ' + + pandora.user.ui.itemView + ' view.' + )); + } + }); } else if (pandora.user.ui.itemView == 'clips') { var ratio = result.data.stream.aspectRatio; - Ox.print('RATIO', ratio) pandora.$ui.contentPanel.replaceElement(1, pandora.$ui.clips = Ox.IconList({ fixedRatio: ratio, item: function(data, sort, size) { diff --git a/static/js/pandora/ui/list.js b/static/js/pandora/ui/list.js index 50896790..d9686fc6 100644 --- a/static/js/pandora/ui/list.js +++ b/static/js/pandora/ui/list.js @@ -499,18 +499,17 @@ pandora.ui.list = function() { // fixme: remove view argument }); pandora.api.findEvents({ - query: '', - itemQuery: pandora.user.ui.query + itemQuery: pandora.user.ui.query, + keys: ['id', 'name', 'start', 'end'], + query: {} }, function(result) { - Ox.print(">>>>>>>", result); - that.replaceElement(0, - pandora.$ui.calendar = Ox.Calendar({ - date: new Date(0), - events: result.data.events, - 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 + that.replaceElement(0, pandora.$ui.calendar = Ox.Calendar({ + date: new Date(0), + events: result.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 })); }); } else { diff --git a/static/js/pandora/ui/menu.js b/static/js/pandora/ui/menu.js index ba1ecdbc..feeef677 100644 --- a/static/js/pandora/ui/menu.js +++ b/static/js/pandora/ui/menu.js @@ -521,6 +521,12 @@ pandora.ui.mainMenu = function() { overflow: 'hidden' }).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') { var $dialog = Ox.Dialog({ buttons: [ diff --git a/static/js/pandora/ui/preferencesDialog.js b/static/js/pandora/ui/preferencesDialog.js index 5aa98cd5..bdc6e728 100644 --- a/static/js/pandora/ui/preferencesDialog.js +++ b/static/js/pandora/ui/preferencesDialog.js @@ -6,6 +6,36 @@ pandora.ui.preferencesDialog = function() { ]; var $tabPanel = Ox.TabPanel({ 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({ elements: [ { @@ -19,9 +49,7 @@ pandora.ui.preferencesDialog = function() { size: 144 }, { - element: Ox.Element() - .css({padding: '16px', overflowY: 'auto'}) - .html(Ox.repeat(Ox.getObjectById(tabs, id).title + ' ', 200)) + element: content } ], orientation: 'horizontal' @@ -52,4 +80,4 @@ pandora.ui.preferencesDialog = function() { return $dialog; -}; \ No newline at end of file +}; diff --git a/static/js/pandora/ui/siteDialog.js b/static/js/pandora/ui/siteDialog.js index 22d59ef3..98be68ec 100644 --- a/static/js/pandora/ui/siteDialog.js +++ b/static/js/pandora/ui/siteDialog.js @@ -12,6 +12,10 @@ pandora.ui.siteDialog = function(section) { Ox.getObjectById(tabs, section).selected = true; var $tabPanel = Ox.TabPanel({ 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({ elements: [ { @@ -27,9 +31,7 @@ pandora.ui.siteDialog = function(section) { size: 272 }, { - element: Ox.Element() - .css({padding: '16px', overflowY: 'auto'}) - .html(Ox.repeat(Ox.getObjectById(tabs, id).title + ' ', 200)) + element: content } ], orientation: 'horizontal' @@ -68,4 +70,4 @@ pandora.ui.siteDialog = function(section) { return $dialog; -}; \ No newline at end of file +}; diff --git a/static/js/pandora/ui/usersDialog.js b/static/js/pandora/ui/usersDialog.js new file mode 100644 index 00000000..c4e8bffc --- /dev/null +++ b/static/js/pandora/ui/usersDialog.js @@ -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; +}; + diff --git a/static/json/pandora.json b/static/json/pandora.json index 3216b778..11f30fe0 100644 --- a/static/json/pandora.json +++ b/static/json/pandora.json @@ -44,5 +44,7 @@ "js/pandora/ui/home.js", "js/pandora/ui/preferencesDialog.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" ]