move public lists browser inline

This commit is contained in:
rolux 2011-01-14 06:24:40 +00:00
parent aea8b80f48
commit 6bc39ceada
5 changed files with 193 additions and 73 deletions

View file

@ -85,8 +85,8 @@ def parseCondition(condition):
q = Q(itemId=False) q = Q(itemId=False)
l = v.split(".") l = v.split(".")
if len(l) == 2: if len(l) == 2:
lqs = List.objects.filter(name=l[1], user__username=l[0]) lqs = list(List.objects.filter(name=l[1], user__username=l[0]))
if lqs.count() == 1: if len(lqs) == 1:
l = lqs[0] l = lqs[0]
if l.query.get('static', False) == False: if l.query.get('static', False) == False:
data = l.query data = l.query

View file

@ -24,6 +24,8 @@ class List(models.Model):
_status = ['private', 'public', 'featured'] _status = ['private', 'public', 'featured']
query = DictField(default={"static": True}) query = DictField(default={"static": True})
type= models.CharField(max_length=255, default='static') type= models.CharField(max_length=255, default='static')
icon = models.ImageField(default=None, blank=True, upload_to=lambda i, x: i.path("icon.jpg"))
#is through table still required? #is through table still required?
items = models.ManyToManyField('item.Item', related_name='lists', items = models.ManyToManyField('item.Item', related_name='lists',
@ -82,10 +84,31 @@ class List(models.Model):
elif key == 'query': elif key == 'query':
if not self.query.get('static', False): if not self.query.get('static', False):
response[key] = self.query response[key] = self.query
elif key == 'subscribed':
if user and not user.is_anonymous():
response[key] = self.subscribed_users.filter(id=user.id).exists()
else: else:
response[key] = getattr(self, key) response[key] = getattr(self, key)
return response return response
def path(self, name=''):
h = self.get_id()
return os.path.join('lists', h[:2], h[2:4], h[4:6], h[6:], name)
def make_icon(self):
frames = []
iself.icon.name = self.path('icon.png')
icon = self.icon.path
if frames:
cmd = [
'scripts/list_icon',
'-f', ','.join(frames),
'-o', icon
]
p = subprocess.Popen(cmd)
p.wait()
class ListItem(models.Model): class ListItem(models.Model):
created = models.DateTimeField(auto_now_add=True) created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True) modified = models.DateTimeField(auto_now=True)

View file

@ -22,7 +22,9 @@ def _order_query(qs, sort):
operator = e['operator'] operator = e['operator']
if operator != '-': if operator != '-':
operator = '' operator = ''
key = e['key'] key = {
'subscribed': 'subscribed_users'
}.get(e['key'], e['key'])
order = '%s%s' % (operator, key) order = '%s%s' % (operator, key)
order_by.append(order) order_by.append(order)
if order_by: if order_by:
@ -183,13 +185,16 @@ def addList(request):
} }
''' '''
data = json.loads(request.POST['data']) data = json.loads(request.POST['data'])
name = data['name'] name = data['name'].strip()
if not name:
name = "Untitled"
num = 1 num = 1
while models.List.objects.filter(name=name, user=request.user).count()>0: created = False
while not created:
list, created = models.List.objects.get_or_create(name=name, user=request.user)
num += 1 num += 1
name = data['name'] + ' (%d)' % num name = data['name'] + ' (%d)' % num
list = models.List(name = name, user=request.user)
list.save()
for key in data: for key in data:
if key == 'query' and not data['query']: if key == 'query' and not data['query']:
setattr(list, key, {"static":True}) setattr(list, key, {"static":True})
@ -207,14 +212,19 @@ def addList(request):
value = data[key] value = data[key]
if value not in list._status: if value not in list._status:
value = list._status[0] value = list._status[0]
if not user.request.is_staff and value == 'featured': if not request.user.is_staff and value == 'featured':
value = 'private' value = 'private'
setattr(list, key, value) setattr(list, key, value)
list.save() list.save()
pos, created = models.Position.objects.get_or_create(list=list, if list.status == 'featured':
user=request.user, section='my') pos, created = models.Position.objects.get_or_create(list=list,
qs = models.Position.objects.filter(user=request.user, section='my') user=request.user, section='featured')
qs = models.Position.objects.filter(section='featured')
else:
pos, created = models.Position.objects.get_or_create(list=list,
user=request.user, section='my')
qs = models.Position.objects.filter(user=request.user, section='my')
pos.position = qs.aggregate(Max('position'))['position__max'] + 1 pos.position = qs.aggregate(Max('position'))['position__max'] + 1
pos.save() pos.save()
response = json_response(status=200, text='created') response = json_response(status=200, text='created')
@ -332,7 +342,6 @@ def subscribeToList(request):
''' '''
param data { param data {
id: listId, id: listId,
user: username(only admins)
} }
return { return {
status: {'code': int, 'text': string}, status: {'code': int, 'text': string},
@ -346,8 +355,10 @@ def subscribeToList(request):
if list.subscribed_users.filter(username=user.username).count() == 0: if list.subscribed_users.filter(username=user.username).count() == 0:
list.subscribed_users.add(user) list.subscribed_users.add(user)
pos, created = models.Position.objects.get_or_create(list=list, user=request.user, section='public') pos, created = models.Position.objects.get_or_create(list=list, user=request.user, section='public')
pos.position = data['position'] if created:
pos.save() qs = models.Position.objects.filter(user=request.user, section='public')
pos.position = qs.aggregate(Max('position'))['position__max'] + 1
pos.save()
response = json_response() response = json_response()
return render_to_json_response(response) return render_to_json_response(response)
actions.register(subscribeToList, cache=False) actions.register(subscribeToList, cache=False)
@ -382,6 +393,8 @@ def sortLists(request):
section: 'my', section: 'my',
ids: [1,2,4,3] ids: [1,2,4,3]
} }
known sections: 'my', 'public', 'featured'
featured can only be edited by admins
return { return {
status: {'code': int, 'text': string}, status: {'code': int, 'text': string},
data: { data: {
@ -411,7 +424,7 @@ def sortLists(request):
for i in data['ids']: for i in data['ids']:
list = get_list_or_404_json(i) list = get_list_or_404_json(i)
pos, created = models.Position.objects.get_or_create(list=list, pos, created = models.Position.objects.get_or_create(list=list,
user=request.user, section=section) user=request.user, section=section)
pos.position = position pos.position = position
pos.save() pos.save()
position += 1 position += 1
@ -419,4 +432,3 @@ def sortLists(request):
response = json_response() response = json_response()
return render_to_json_response(response) return render_to_json_response(response)
actions.register(sortLists, cache=False) actions.register(sortLists, cache=False)

View file

@ -179,7 +179,7 @@
"section": "items", "section": "items",
"sections": ["my", "public", "featured"], "sections": ["my", "public", "featured"],
"showAnnotations": true, "showAnnotations": true,
"showGroups": false, "showGroups": true,
"showInfo": true, "showInfo": true,
"showMovies": true, "showMovies": true,
"showSection": { "showSection": {

View file

@ -20,9 +20,11 @@ var pandora = new Ox.App({
requests: {}, requests: {},
ui: { ui: {
infoRatio: 16 / 9, infoRatio: 16 / 9,
scrollbarSize: $.browser.mozilla ? 16 : 12,
sectionElement: 'buttons', sectionElement: 'buttons',
sectionLength: {}, sectionLength: {},
selectedMovies: [] selectedMovies: [],
showAllPublicLists: false
}, },
user: data.user user: data.user
}; };
@ -45,7 +47,7 @@ var pandora = new Ox.App({
function load() { function load() {
$(function() { $(function() {
// fixme: use jquert ajaxStart? // fixme: use jquery ajaxStart?
var $body = $('body'); var $body = $('body');
Ox.Request.requests() && app.$ui.loadingIcon.start(); Ox.Request.requests() && app.$ui.loadingIcon.start();
$body.bind('requestStart', function() { $body.bind('requestStart', function() {
@ -645,7 +647,7 @@ var pandora = new Ox.App({
collapsed: !app.user.ui.showMovies, collapsed: !app.user.ui.showMovies,
collapsible: true, collapsible: true,
element: app.$ui.browser = ui.browser(), element: app.$ui.browser = ui.browser(),
size: 112 + ($.browser.mozilla ? 16 : 12) // fixme: should be app.ui.scrollbarSize size: 112 + app.ui.scrollbarSize
}, },
{ {
element: app.$ui.item = ui.item(app.user.ui.item, app.user.ui.itemView) element: app.$ui.item = ui.item(app.user.ui.item, app.user.ui.itemView)
@ -822,6 +824,7 @@ var pandora = new Ox.App({
query: Query.toObject(id) query: Query.toObject(id)
}), callback); }), callback);
}, },
scrollbarVisible: true,
selected: query ? $.map(query.conditions, function(v) { selected: query ? $.map(query.conditions, function(v) {
return v.value; return v.value;
}) : [], }) : [],
@ -962,6 +965,7 @@ var pandora = new Ox.App({
.bindEvent({ .bindEvent({
toggle: function(event, data) { toggle: function(event, data) {
app.user.ui.showInfo = !data.collapsed; app.user.ui.showInfo = !data.collapsed;
resizeSections();
} }
}); });
return that; return that;
@ -1063,7 +1067,7 @@ var pandora = new Ox.App({
collapsible: true, collapsible: true,
element: app.$ui.browser = ui.browser(), element: app.$ui.browser = ui.browser(),
resizable: false, resizable: false,
size: 112 + ($.browser.mozilla ? 16 : 12) size: 112 + app.ui.scrollbarSize
}, },
{ {
element: new Ox.Element('div') element: new Ox.Element('div')
@ -1149,6 +1153,7 @@ var pandora = new Ox.App({
query: Query.toObject() query: Query.toObject()
}), callback); }), callback);
}, },
scrollbarVisible: true,
sort: app.user.ui.lists[app.user.ui.list].sort sort: app.user.ui.lists[app.user.ui.list].sort
}) })
.bindEvent({ .bindEvent({
@ -2049,7 +2054,37 @@ var pandora = new Ox.App({
}) })
return that; return that;
}, },
publicListsDialog: function() { publicLists: function() {
var that = new Ox.SplitPanel({
elements: [
{
element: ui.publicListsBar(),
size: 24
},
{
element: app.$ui.sectionList[1] = ui.publicListsList()
}
],
orientation: 'vertical'
});
return that;
},
publicListsBar: function() {
var that = new Ox.Bar({
size: 24
});
app.$ui.findListInput = new Ox.Input({
placeholder: 'Find User',
width: 184 - app.ui.scrollbarSize
})
.css({
margin: '4px',
align: 'right'
})
.appendTo(that);
return that;
},
publicListsDialog: function() { // fixme: unused
var that = new Ox.Dialog({ var that = new Ox.Dialog({
buttons: [ buttons: [
new Ox.Button({ new Ox.Button({
@ -2061,7 +2096,21 @@ var pandora = new Ox.App({
} }
}) })
], ],
content: new Ox.TextList({ content: ui.publicListsList(),
height: 320,
keys: {enter: 'close', escape: 'close'},
padding: 0,
title: 'Public Lists',
width: 420
})
.css({
position: 'absolute'
});
return that;
},
publicListsList: function() {
var columnWidth = (app.user.ui.sidebarSize - app.ui.scrollbarSize - 88) / 2,
that = new Ox.TextList({
columns: [ columns: [
{ {
format: function() { format: function() {
@ -2074,6 +2123,7 @@ var pandora = new Ox.App({
title: $('<img>').attr({ title: $('<img>').attr({
src: 'static/oxjs/build/png/ox.ui/icon16.png' src: 'static/oxjs/build/png/ox.ui/icon16.png'
}), }),
unique: true,
visible: true, visible: true,
width: 16 width: 16
}, },
@ -2082,14 +2132,14 @@ var pandora = new Ox.App({
operator: '+', operator: '+',
title: 'User', title: 'User',
visible: true, visible: true,
width: 160 width: Math.floor(columnWidth)
}, },
{ {
id: 'name', id: 'name',
operator: '+', operator: '+',
title: 'Name', title: 'Name',
visible: true, visible: true,
width: 160 width: Math.ceil(columnWidth)
}, },
{ {
align: 'right', align: 'right',
@ -2100,70 +2150,89 @@ var pandora = new Ox.App({
width: 40 width: 40
}, },
{ {
format: function(value) { format: function(value) {
return $('<img>') return $('<img>')
.attr({ .attr({
src: 'static/oxjs/build/png/ox.ui.' + Ox.theme() + src: 'static/oxjs/build/png/ox.ui.' + Ox.theme() +
'/symbolFind.png' '/symbolFind.png'
}) })
.css({ .css({
opacity: value == 'static' ? 0.1 : 1 opacity: value == 'static' ? 0.1 : 1
}); });
}, },
id: 'type', id: 'type',
operator: '+', operator: '+',
title: $('<img>').attr({ title: $('<img>').attr({
src: 'static/oxjs/build/png/ox.ui.' + src: 'static/oxjs/build/png/ox.ui.' +
Ox.theme() + '/symbolFind.png' Ox.theme() + '/symbolFind.png'
}), }),
visible: true, visible: true,
width: 16 width: 16
}, },
{ {
clickable: true, clickable: true,
format: function(value) { format: function(value) {
return $('<img>') return $('<img>')
.attr({ .attr({
src: 'static/oxjs/build/png/ox.ui.' + src: 'static/oxjs/build/png/ox.ui.' +
Ox.theme() + '/symbolCheck.png' Ox.theme() + '/symbolCheck.png'
}) })
.css({ .css({
opacity: value == 'static' ? 0.1 : 1 opacity: value ? 1 : 0.1
}); });
}, },
id: 'status', id: 'subscribed',
operator: '+', operator: '+',
title: $('<img>').attr({ title: $('<img>').attr({
src: 'static/oxjs/build/png/ox.ui.' + src: 'static/oxjs/build/png/ox.ui.' +
Ox.theme() + '/symbolCheck.png' Ox.theme() + '/symbolCheck.png'
}), }),
visible: true, visible: true,
width: 16 width: 16
}, },
], ],
columnsVisible: true, columnsVisible: true,
pageLength: 1000,
request: function(data, callback) { request: function(data, callback) {
var query = {conditions: [ var query = {conditions: [
//{key: 'user', value: app.user.username, operator: '!'}, {key: 'user', value: app.user.username, operator: '!'},
{key: 'status', value: 'public', operator: '='} {key: 'status', value: 'public', operator: '='}
], operator: ''}; ], operator: ''};
return pandora.api.findLists($.extend(data, { return pandora.api.findLists($.extend(data, {
query: query query: query
}), callback); }), callback);
}, },
selected: app.user.ui.list ? [app.user.ui.list] : [],
sort: [ sort: [
{key: 'name', operator: '+'} {key: 'name', operator: '+'}
] ]
}), })
height: 320, .bindEvent({
keys: {enter: 'close', escape: 'close'}, click: function(event, data) {
padding: 0, alert('click')
title: 'Public Lists', },
width: 420 init: function(event, data) {
}) app.ui.sectionLength.public = data.items;
.css({ app.$ui.section[1].$content.css({
position: 'absolute' height: 40 + data.items * 16 + 'px'
}); });
app.$ui.sectionList[1].css({
height: 16 + data.items * 16 + 'px'
});
resizeSections();
},
select: function(event, data) {
// fixme: duplicated
if (data.ids.length) {
app.$ui.sectionList.forEach(function($list, i) {
i != 1 && $list.options('selected', []);
});
URL.set('?find=list:' + data.ids[0]);
} else {
URL.set('');
}
}
});
return that; return that;
}, },
rightPanel: function() { rightPanel: function() {
@ -2232,8 +2301,7 @@ var pandora = new Ox.App({
return that; return that;
}, },
sectionList: function(id, i) { sectionList: function(id, i) {
var width = app.user.ui.sidebarWidth, //getSectionsWidth(), var that = new Ox.TextList({
that = new Ox.TextList({
columns: [ columns: [
{ {
format: function() { format: function() {
@ -2254,7 +2322,7 @@ var pandora = new Ox.App({
operator: '+', operator: '+',
unique: true, unique: true,
visible: id == 'public', visible: id == 'public',
width: width - 88 width: app.user.ui.sidebarWidth - 88
}, },
{ {
editable: function(data) { editable: function(data) {
@ -2267,7 +2335,7 @@ var pandora = new Ox.App({
}, },
operator: '+', operator: '+',
visible: id != 'public', visible: id != 'public',
width: width - 88 width: app.user.ui.sidebarWidth - 88
}, },
{ {
align: 'right', align: 'right',
@ -2343,7 +2411,7 @@ var pandora = new Ox.App({
.css({ .css({
left: 0, left: 0,
top: 0, top: 0,
width: width + 'px', width: app.user.ui.sidebarWidth + 'px',
}) })
.bind({ .bind({
dragenter: function(e) { dragenter: function(e) {
@ -2396,13 +2464,14 @@ var pandora = new Ox.App({
}); });
}, },
init: function(event, data) { init: function(event, data) {
app.ui.sectionLength[id] = data.items; app.ui.sectionLength[id] = data.items; // fixme: why by id, not by i?
app.$ui.section[i].$content.css({ app.$ui.section[i].$content.css({
height: data.items * 16 + 'px' height: data.items * 16 + 'px'
}); });
app.$ui.sectionList[i].css({ app.$ui.sectionList[i].css({
height: data.items * 16 + 'px' height: data.items * 16 + 'px'
}); });
resizeSections();
}, },
move: function(event, data) { move: function(event, data) {
/* /*
@ -2420,8 +2489,10 @@ var pandora = new Ox.App({
app.$ui.sectionList.forEach(function($list, i_) { app.$ui.sectionList.forEach(function($list, i_) {
i != i_ && $list.options('selected', []); i != i_ && $list.options('selected', []);
}); });
app.user.ui.list = data.ids[0];
URL.set('?find=list:' + data.ids[0]); URL.set('?find=list:' + data.ids[0]);
} else { } else {
app.user.ui.list = '';
URL.set(''); URL.set('');
} }
}, },
@ -2476,7 +2547,7 @@ var pandora = new Ox.App({
.bindEvent({ .bindEvent({
click: function(event, data) { click: function(event, data) {
var $list = app.$ui.sectionList[i], var $list = app.$ui.sectionList[i],
id; hasFocus, id;
if (data.id == 'new' || data.id == 'newsmart') { if (data.id == 'new' || data.id == 'newsmart') {
pandora.api.addList({ pandora.api.addList({
name: 'Untitled', name: 'Untitled',
@ -2495,13 +2566,17 @@ var pandora = new Ox.App({
} }
}); });
} else if (data.id == 'browse') { } else if (data.id == 'browse') {
app.$ui.publicListsDialog = ui.publicListsDialog().open(); //hasFocus = app.$ui.app.$ui.sectionList[1].hasFocus();
app.$ui.sectionList[1].replaceWith(app.$ui.publicLists = ui.publicLists());
//hasFocus && app.$ui.publicLists.gainFocus();
//app.$ui.publicListsDialog = ui.publicListsDialog().open();
app.ui.showAllPublicLists = true;
} }
}, },
toggle: function(event, data) { toggle: function(event, data) {
Ox.print('toggle')
data.collapsed && app.$ui.sectionList[i].loseFocus(); data.collapsed && app.$ui.sectionList[i].loseFocus();
app.user.ui.showSection[id] = !data.collapsed; app.user.ui.showSection[id] = !data.collapsed;
resizeSections();
} }
}); });
$sections.push(app.$ui.section[i]); $sections.push(app.$ui.section[i]);
@ -2725,16 +2800,15 @@ var pandora = new Ox.App({
function getGroupWidth(pos, panelWidth) { // fixme: don't pass panelWidth function getGroupWidth(pos, panelWidth) { // fixme: don't pass panelWidth
var width = {}; var width = {};
width.list = Math.floor(panelWidth / 5) + (panelWidth % 5 > pos); width.list = Math.floor(panelWidth / 5) + (panelWidth % 5 > pos);
width.column = width.list - 40 - ($.browser.mozilla ? 16 : 12); width.column = width.list - 40 - app.ui.scrollbarSize;
return width; return width;
} }
function getSectionsWidth() { function getSectionsWidth() {
var width = app.user.ui.sidebarSize; var width = app.user.ui.sidebarSize;
Ox.print(getSectionsHeight(), '>', app.$ui.leftPanel.height() - 24 - 1 - app.$ui.info.height(), getSectionsHeight() > app.$ui.leftPanel.height() - 24 - 1 - app.$ui.info.height())
// fixme: don't use height(), look up in splitpanels // fixme: don't use height(), look up in splitpanels
if (getSectionsHeight() > app.$ui.leftPanel.height() - 24 - 1 - app.$ui.info.height()) { if (getSectionsHeight() > app.$ui.leftPanel.height() - 24 - 1 - app.$ui.info.height()) {
width -= $.browser.mozilla ? 16 : 12; width -= app.ui.scrollbarSize;
} }
return width; return width;
} }
@ -2742,7 +2816,11 @@ var pandora = new Ox.App({
function getSectionsHeight() { function getSectionsHeight() {
var height = 48; var height = 48;
$.each(app.user.ui.showSection, function(id, show) { $.each(app.user.ui.showSection, function(id, show) {
Ox.print('*', id, app.ui.sectionLength[id])
height += show * app.ui.sectionLength[id] * 16; height += show * app.ui.sectionLength[id] * 16;
if (id == 'public' && app.ui.showAllPublicLists) {
height += show * 40
}
}); });
Ox.print('getSectionsHeight', height) Ox.print('getSectionsHeight', height)
return height; return height;
@ -2795,9 +2873,16 @@ var pandora = new Ox.App({
function resizeSections() { function resizeSections() {
var width = getSectionsWidth(); var width = getSectionsWidth();
app.$ui.sectionList.forEach(function($list) { Ox.print('sectionsWidth', width)
app.$ui.sectionList.forEach(function($list, i) {
var id = i == 1 ? 'id' : 'name';
$list.css({width: width + 'px'}); $list.css({width: width + 'px'});
$list.resizeColumn('name', width - 88); if (i == 1 && app.ui.showAllPublicLists) {
$list.resizeColumn('user', Math.floor((width - 88) / 2))
.resizeColumn('name', Math.floor((width - 88) / 2));
} else {
$list.resizeColumn(id, width - 88);
}
}); });
} }