initial round of text section

This commit is contained in:
j 2013-02-16 01:20:40 +00:00
commit c8af45e7cf
25 changed files with 2243 additions and 984 deletions

View file

@ -31,6 +31,8 @@
"canEditAnnotations": {"staff": true, "admin": true},
"canEditEvents": {"staff": true, "admin": true},
"canEditFeaturedLists": {"staff": true, "admin": true},
"canEditFeaturedTexts": {"staff": true, "admin": true},
"canEditFeaturedEdits": {"staff": true, "admin": true},
"canEditMetadata": {"staff": true, "admin": true},
"canEditPlaces": {"staff": true, "admin": true},
"canEditSitePages": {"staff": true, "admin": true},
@ -712,6 +714,8 @@
"icons": "posters",
"infoIconSize": 256,
"item": "",
"text": "",
"edit": "",
"itemFind": "",
"itemSort": [{"key": "position", "operator": "+"}],
"itemView": "info",
@ -749,6 +753,11 @@
"featured": true,
"volumes": true
}
"texts": {
"personal": true,
"favorite": true,
"featured": true
}
},
"showSidebar": true,
"showSitePosters": false,

View file

@ -29,6 +29,8 @@
"canEditAnnotations": {"staff": true, "admin": true},
"canEditEvents": {"staff": true, "admin": true},
"canEditFeaturedLists": {"staff": true, "admin": true},
"canEditFeaturedTexts": {"staff": true, "admin": true},
"canEditFeaturedEdits": {"staff": true, "admin": true},
"canEditMetadata": {"staff": true, "admin": true},
"canEditPlaces": {"staff": true, "admin": true},
"canEditSitePages": {"staff": true, "admin": true},
@ -630,6 +632,8 @@
"icons": "frames",
"infoIconSize": 256,
"item": "",
"text": "",
"edit": "",
"itemFind": "",
"itemSort": [{"key": "position", "operator": "+"}],
"itemView": "info",
@ -670,6 +674,11 @@
"favorite": true,
"featured": true,
"volumes": true
},
"texts": {
"personal": true,
"favorite": true,
"featured": true
}
},
"showSidebar": true,

View file

@ -29,6 +29,8 @@
"canEditAnnotations": {"staff": true, "admin": true},
"canEditEvents": {"staff": true, "admin": true},
"canEditFeaturedLists": {"staff": true, "admin": true},
"canEditFeaturedTexts": {"staff": true, "admin": true},
"canEditFeaturedEdits": {"staff": true, "admin": true},
"canEditMetadata": {"staff": true, "admin": true},
"canEditPlaces": {"staff": true, "admin": true},
"canEditSitePages": {"staff": true, "admin": true},
@ -549,6 +551,8 @@
"icons": "posters",
"infoIconSize": 256,
"item": "",
"text": "",
"edit": "",
"itemFind": "",
"itemSort": [{"key": "position", "operator": "+"}],
"itemView": "info",
@ -589,6 +593,11 @@
"featured": true,
"volumes": true
}
"texts": {
"personal": true,
"favorite": true,
"featured": true
}
},
"showSidebar": true,
"showSitePosters": false,

View file

@ -207,7 +207,9 @@ def addList(request):
return {
status: {'code': int, 'text': string},
data: {
list:
id:
name:
...
}
}
'''

136
pandora/text/managers.py Normal file
View file

@ -0,0 +1,136 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from datetime import datetime
from django.db.models import Q, Manager
import models
def parseCondition(condition, user):
'''
'''
k = condition.get('key', 'name')
k = {
'user': 'user__username',
'position': 'position__position',
'posterFrames': 'poster_frames',
}.get(k, k)
if not k:
k = 'name'
v = condition['value']
op = condition.get('operator')
if not op:
op = '='
if op.startswith('!'):
op = op[1:]
exclude = True
else:
exclude = False
if k == 'id':
v = v.split(":")
if len(v) >= 2:
v = (v[0], ":".join(v[1:]))
q = Q(user__username=v[0], name=v[1])
else:
q = Q(id__in=[])
return q
if k == 'subscribed':
key = 'subscribed_users__username'
v = user.username
elif isinstance(v, bool): #featured and public flag
key = k
else:
key = "%s%s" % (k, {
'==': '__iexact',
'^': '__istartswith',
'$': '__iendswith',
}.get(op, '__icontains'))
key = str(key)
if exclude:
q = ~Q(**{key: v})
else:
q = Q(**{key: v})
return q
def parseConditions(conditions, operator, user):
'''
conditions: [
{
value: "war"
}
{
key: "year",
value: "1970-1980,
operator: "!="
},
{
key: "country",
value: "f",
operator: "^"
}
],
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:
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 TextManager(Manager):
def get_query_set(self):
return super(TextManager, self).get_query_set()
def find(self, data, user):
'''
query: {
conditions: [
{
value: "war"
}
{
key: "year",
value: "1970-1980,
operator: "!="
},
{
key: "country",
value: "f",
operator: "^"
}
],
operator: "&"
}
'''
#join query with operator
qs = self.get_query_set()
conditions = parseConditions(data['query'].get('conditions', []),
data['query'].get('operator', '&'),
user)
if conditions:
qs = qs.filter(conditions)
if user.is_anonymous():
qs = qs.filter(Q(status='public') | Q(status='featured'))
else:
qs = qs.filter(Q(status='public') | Q(status='featured') | Q(user=user))
return qs

View file

@ -0,0 +1,205 @@
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Deleting model 'Image'
db.delete_table('text_image')
# Deleting model 'Attachment'
db.delete_table('text_attachment')
# Adding model 'Position'
db.create_table('text_position', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('text', self.gf('django.db.models.fields.related.ForeignKey')(related_name='position', to=orm['text.Text'])),
('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='text_position', to=orm['auth.User'])),
('section', self.gf('django.db.models.fields.CharField')(max_length='255')),
('position', self.gf('django.db.models.fields.IntegerField')(default=0)),
))
db.send_create_signal('text', ['Position'])
# Adding unique constraint on 'Position', fields ['user', 'text', 'section']
db.create_unique('text_position', ['user_id', 'text_id', 'section'])
# Deleting field 'Text.public'
db.delete_column('text_text', 'public')
# Deleting field 'Text.slug'
db.delete_column('text_text', 'slug')
# Deleting field 'Text.title'
db.delete_column('text_text', 'title')
# Deleting field 'Text.published'
db.delete_column('text_text', 'published')
# Adding field 'Text.name'
db.add_column('text_text', 'name',
self.gf('django.db.models.fields.CharField')(default=datetime.datetime(2013, 2, 15, 0, 0), max_length=255),
keep_default=False)
# Adding field 'Text.status'
db.add_column('text_text', 'status',
self.gf('django.db.models.fields.CharField')(default='private', max_length=20),
keep_default=False)
# Adding field 'Text.description'
db.add_column('text_text', 'description',
self.gf('django.db.models.fields.TextField')(default=''),
keep_default=False)
# Adding field 'Text.icon'
db.add_column('text_text', 'icon',
self.gf('django.db.models.fields.files.ImageField')(default='', max_length=100, blank=True),
keep_default=False)
# Adding field 'Text.poster_frames'
db.add_column('text_text', 'poster_frames',
self.gf('ox.django.fields.TupleField')(default=[]),
keep_default=False)
# Adding M2M table for field subscribed_users on 'Text'
db.create_table('text_text_subscribed_users', (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
('text', models.ForeignKey(orm['text.text'], null=False)),
('user', models.ForeignKey(orm['auth.user'], null=False))
))
db.create_unique('text_text_subscribed_users', ['text_id', 'user_id'])
# Adding unique constraint on 'Text', fields ['user', 'name']
db.create_unique('text_text', ['user_id', 'name'])
def backwards(self, orm):
# Removing unique constraint on 'Text', fields ['user', 'name']
db.delete_unique('text_text', ['user_id', 'name'])
# Removing unique constraint on 'Position', fields ['user', 'text', 'section']
db.delete_unique('text_position', ['user_id', 'text_id', 'section'])
# Adding model 'Image'
db.create_table('text_image', (
('caption', self.gf('django.db.models.fields.CharField')(default='', max_length=255)),
('image', self.gf('django.db.models.fields.files.ImageField')(max_length=100)),
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
))
db.send_create_signal('text', ['Image'])
# Adding model 'Attachment'
db.create_table('text_attachment', (
('caption', self.gf('django.db.models.fields.CharField')(default='', max_length=255)),
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('file', self.gf('django.db.models.fields.files.FileField')(max_length=100)),
))
db.send_create_signal('text', ['Attachment'])
# Deleting model 'Position'
db.delete_table('text_position')
# Adding field 'Text.public'
db.add_column('text_text', 'public',
self.gf('django.db.models.fields.BooleanField')(default=False),
keep_default=False)
# Adding field 'Text.slug'
db.add_column('text_text', 'slug',
self.gf('django.db.models.fields.SlugField')(default='', max_length=50),
keep_default=False)
# Adding field 'Text.title'
db.add_column('text_text', 'title',
self.gf('django.db.models.fields.CharField')(max_length=1000, null=True),
keep_default=False)
# Adding field 'Text.published'
db.add_column('text_text', 'published',
self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now),
keep_default=False)
# Deleting field 'Text.name'
db.delete_column('text_text', 'name')
# Deleting field 'Text.status'
db.delete_column('text_text', 'status')
# Deleting field 'Text.description'
db.delete_column('text_text', 'description')
# Deleting field 'Text.icon'
db.delete_column('text_text', 'icon')
# Deleting field 'Text.poster_frames'
db.delete_column('text_text', 'poster_frames')
# Removing M2M table for field subscribed_users on 'Text'
db.delete_table('text_text_subscribed_users')
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'text.position': {
'Meta': {'unique_together': "(('user', 'text', 'section'),)", 'object_name': 'Position'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'position': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'section': ('django.db.models.fields.CharField', [], {'max_length': "'255'"}),
'text': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'position'", 'to': "orm['text.Text']"}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'text_position'", 'to': "orm['auth.User']"})
},
'text.text': {
'Meta': {'unique_together': "(('user', 'name'),)", 'object_name': 'Text'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'description': ('django.db.models.fields.TextField', [], {'default': "''"}),
'icon': ('django.db.models.fields.files.ImageField', [], {'default': 'None', 'max_length': '100', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'poster_frames': ('ox.django.fields.TupleField', [], {'default': '[]'}),
'status': ('django.db.models.fields.CharField', [], {'default': "'private'", 'max_length': '20'}),
'subscribed_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribed_texts'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
'text': ('django.db.models.fields.TextField', [], {'default': "''"}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'texts'", 'to': "orm['auth.User']"})
}
}
complete_apps = ['text']

View file

@ -0,0 +1,93 @@
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'Text.type'
db.add_column('text_text', 'type',
self.gf('django.db.models.fields.CharField')(default='html', max_length=255),
keep_default=False)
# Adding field 'Text.links'
db.add_column('text_text', 'links',
self.gf('ox.django.fields.DictField')(default={}),
keep_default=False)
def backwards(self, orm):
# Deleting field 'Text.type'
db.delete_column('text_text', 'type')
# Deleting field 'Text.links'
db.delete_column('text_text', 'links')
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'text.position': {
'Meta': {'unique_together': "(('user', 'text', 'section'),)", 'object_name': 'Position'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'position': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'section': ('django.db.models.fields.CharField', [], {'max_length': "'255'"}),
'text': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'position'", 'to': "orm['text.Text']"}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'text_position'", 'to': "orm['auth.User']"})
},
'text.text': {
'Meta': {'unique_together': "(('user', 'name'),)", 'object_name': 'Text'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'description': ('django.db.models.fields.TextField', [], {'default': "''"}),
'icon': ('django.db.models.fields.files.ImageField', [], {'default': 'None', 'max_length': '100', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'links': ('ox.django.fields.DictField', [], {'default': '{}'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'poster_frames': ('ox.django.fields.TupleField', [], {'default': '[]'}),
'status': ('django.db.models.fields.CharField', [], {'default': "'private'", 'max_length': '20'}),
'subscribed_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribed_texts'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
'text': ('django.db.models.fields.TextField', [], {'default': "''"}),
'type': ('django.db.models.fields.CharField', [], {'default': "'html'", 'max_length': '255'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'texts'", 'to': "orm['auth.User']"})
}
}
complete_apps = ['text']

View file

@ -2,40 +2,158 @@
# vi:si:et:sw=4:sts=4:ts=4
from __future__ import division, with_statement
from datetime import datetime
import os
import subprocess
from glob import glob
from django.db import models
from django.contrib.auth.models import User
from django.conf import settings
import ox
from ox.django.fields import DictField, TupleField
from archive import extract
import managers
class Text(models.Model):
class Meta:
unique_together = ("user", "name")
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
published = models.DateTimeField(default=datetime.now, editable=False)
public = models.BooleanField(default=False)
user = models.ForeignKey(User, related_name='texts')
name = models.CharField(max_length=255)
status = models.CharField(max_length=20, default='private')
_status = ['private', 'public', 'featured']
type = models.CharField(max_length=255, default='html')
description = models.TextField(default='')
user = models.ForeignKey(User)
slug = models.SlugField()
title = models.CharField(null=True, max_length=1000)
text = models.TextField(default='')
icon = models.ImageField(default=None, blank=True,
upload_to=lambda i, x: i.path("icon.jpg"))
text = models.TextField(default="")
links = DictField(default={}, editable=True)
poster_frames = TupleField(default=[], editable=False)
subscribed_users = models.ManyToManyField(User, related_name='subscribed_texts')
objects = managers.TextManager()
def save(self, *args, **kwargs):
super(Text, self).save(*args, **kwargs)
def __unicode__(self):
return u"%s <%s>" % (self.title, self.slug)
return self.get_id()
def get_absolute_url(self):
return '/text/%s' % self.slug
def get_id(self):
return u'%s:%s' % (self.user.username, self.name)
def accessible(self, user):
return self.user == user or self.status in ('public', 'featured')
class Image(models.Model):
image = models.ImageField(upload_to='text/image')
caption = models.CharField(max_length=255, default="")
def editable(self, user):
if user.is_anonymous():
return False
if self.user == user or \
user.is_staff or \
user.get_profile().capability('canEditFeaturedTexts') == True:
return True
return False
def get_absolute_url(self):
return self.image.url
def json(self, keys=None, user=None):
if not keys:
keys=['id', 'name', 'user', 'status', 'subscribed', 'posterFrames', 'description', 'text', 'type', 'links']
response = {}
_map = {
'posterFrames': 'poster_frames'
}
for key in keys:
if key == 'id':
response[key] = self.get_id()
elif key == 'user':
response[key] = self.user.username
elif key == 'subscribers':
response[key] = self.subscribed_users.all().count()
elif key == 'subscribed':
if user and not user.is_anonymous():
response[key] = self.subscribed_users.filter(id=user.id).exists()
elif hasattr(self, _map.get(key, key)):
response[key] = getattr(self, _map.get(key,key))
return response
def path(self, name=''):
h = "%07d" % self.id
return os.path.join('texts', h[:2], h[2:4], h[4:6], h[6:], name)
class Attachment(models.Model):
file = models.FileField(upload_to='text/attachment')
caption = models.CharField(max_length=255, default="")
def update_icon(self):
frames = []
if not self.poster_frames:
items = self.get_items(self.user).filter(rendered=True)
if items.count():
poster_frames = []
for i in range(0, items.count(), max(1, int(items.count()/4))):
poster_frames.append({
'item': items[int(i)].itemId,
'position': items[int(i)].poster_frame
})
self.poster_frames = tuple(poster_frames)
self.save()
for i in self.poster_frames:
from item.models import Item
qs = Item.objects.filter(itemId=i['item'])
if qs.count() > 0:
frame = qs[0].frame(i['position'])
if frame:
frames.append(frame)
self.icon.name = self.path('icon.jpg')
icon = self.icon.path
if frames:
while len(frames) < 4:
frames += frames
folder = os.path.dirname(icon)
ox.makedirs(folder)
for f in glob("%s/icon*.jpg" % folder):
os.unlink(f)
cmd = [
settings.LIST_ICON,
'-f', ','.join(frames),
'-o', icon
]
p = subprocess.Popen(cmd)
p.wait()
self.save()
def get_icon(self, size=16):
path = self.path('icon%d.jpg' % size)
path = os.path.join(settings.MEDIA_ROOT, path)
if not os.path.exists(path):
folder = os.path.dirname(path)
ox.makedirs(folder)
if self.icon and os.path.exists(self.icon.path):
source = self.icon.path
max_size = min(self.icon.width, self.icon.height)
else:
source = os.path.join(settings.STATIC_ROOT, 'jpg/list256.jpg')
max_size = 256
if size < max_size:
extract.resize_image(source, path, size=size)
else:
path = source
return path
class Position(models.Model):
class Meta:
unique_together = ("user", "text", "section")
text = models.ForeignKey(Text, related_name='position')
user = models.ForeignKey(User, related_name='text_position')
section = models.CharField(max_length='255')
position = models.IntegerField(default=0)
def __unicode__(self):
return u'%s/%s/%s' % (self.section, self.position, self.text)
def get_absolute_url(self):
return self.file.url

View file

@ -1,27 +1,96 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from __future__ import division
import os
import re
import ox
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 ox.django.api import actions
from ox.django.decorators import login_required_json
from ox.django.http import HttpFileResponse
from ox.django.shortcuts import render_to_json_response, get_object_or_404_json, json_response
from django.db.models import Count, Q, Sum, Max
from item import utils
import models
def get_text_or_404_json(id):
id = id.split(':')
username = id[0]
textname = ":".join(id[1:])
return get_object_or_404_json(models.Text, user__username=username, name=textname)
@login_required_json
def addText(request):
'''
param data {
name: value,
}
return {
status: {'code': int, 'text': string},
data: {
id:
name:
...
}
}
'''
data = json.loads(request.POST['data'])
data['name'] = re.sub(' \[\d+\]$', '', data['name']).strip()
name = data['name']
if not name:
name = "Untitled"
num = 1
created = False
while not created:
text, created = models.Text.objects.get_or_create(name=name, user=request.user)
num += 1
name = data['name'] + ' [%d]' % num
text.save()
if text.status == 'featured':
pos, created = models.Position.objects.get_or_create(text=text,
user=request.user, section='featured')
qs = models.Position.objects.filter(section='featured')
else:
pos, created = models.Position.objects.get_or_create(text=text,
user=request.user, section='personal')
qs = models.Position.objects.filter(user=request.user, section='personal')
pos.position = qs.aggregate(Max('position'))['position__max'] + 1
pos.save()
response = json_response(status=200, text='created')
response['data'] = text.json()
return render_to_json_response(response)
actions.register(addText, cache=False)
def getText(request):
'''
param data
string id
return page
param data {
id: textid
}
return {
id:
text:
...
}
'''
response = json_response({})
itemId = json.loads(request.POST['data'])
item = get_object_or_404_json(models.Text, pk=itemId)
response['data']['page'] = item.html()
response = json_response()
data = json.loads(request.POST['data'])
public_id = data['id']
if public_id == '':
qs = models.Text.objects.filter(name='')
if qs.count() == 0:
text = models.Text()
text.name = ''
text.text = 'Please put something here'
text.user = request.user
text.save()
else:
text = qs[0]
else:
text = get_text_or_404_json(data['id'])
response['data'] = text.json()
return render_to_json_response(response)
actions.register(getText)
@ -29,22 +98,355 @@ actions.register(getText)
@login_required_json
def editText(request):
'''
param data
string id
return page
param data {
id:
text:
public: boolean
}
return {
id:
text:
...
}
'''
response = json_response({})
itemId = json.loads(request.POST['data'])
item = get_object_or_404_json(models.Text, pk=itemId)
response['data']['page'] = item.html()
response = json_response()
data = json.loads(request.POST['data'])
if data['id']:
public_id = data['id'].split(':')
username = public_id[0]
name = ":".join(public_id[1:])
text, created = models.Text.objects.get_or_create(name=name, user=models.User.objects.get(username=username))
if created:
text.user = request.user
else:
qs = models.Text.objects.filter(name='')
if qs.count() == 0:
if request.user.get_profile().capability('canEditFeaturedTexts'):
text = models.Text(name='', user=request.user)
text.save()
else:
response = json_response(status=403, text='permission denied')
return render_to_json_response(response)
else:
text = qs[0]
if text.editable(request.user):
for key in data:
if key == 'status':
value = data[key]
if value not in text._status:
value = text._status[0]
if value == 'private':
for user in text.subscribed_users.all():
text.subscribed_users.remove(user)
qs = models.Position.objects.filter(user=request.user,
section='section', text=text)
if qs.count() > 1:
pos = qs[0]
pos.section = 'personal'
pos.save()
elif value == 'featured':
if request.user.get_profile().capability('canEditFeaturedTexts'):
pos, created = models.Position.objects.get_or_create(text=text, user=request.user,
section='featured')
if created:
qs = models.Position.objects.filter(user=request.user, section='featured')
pos.position = qs.aggregate(Max('position'))['position__max'] + 1
pos.save()
models.Position.objects.filter(text=text).exclude(id=pos.id).delete()
else:
value = text.status
elif text.status == 'featured' and value == 'public':
models.Position.objects.filter(text=text).delete()
pos, created = models.Position.objects.get_or_create(text=text,
user=text.user,section='personal')
qs = models.Position.objects.filter(user=text.user,
section='personal')
pos.position = qs.aggregate(Max('position'))['position__max'] + 1
pos.save()
for u in text.subscribed_users.all():
pos, created = models.Position.objects.get_or_create(text=text, user=u,
section='public')
qs = models.Position.objects.filter(user=u, section='public')
pos.position = qs.aggregate(Max('position'))['position__max'] + 1
pos.save()
text.status = value
elif key == 'name':
data['name'] = re.sub(' \[\d+\]$', '', data['name']).strip()
name = data['name']
if not name:
name = "Untitled"
num = 1
while models.Text.objects.filter(name=name, user=text.user).exclude(id=text.id).count()>0:
num += 1
name = data['name'] + ' [%d]' % num
text.name = name
elif key == 'description':
text.description = ox.sanitize_html(data['description'])
elif key == 'text':
text.text = ox.sanitize_html(data['text'])
if 'position' in data:
pos, created = models.Position.objects.get_or_create(text=text, user=request.user)
pos.position = data['position']
pos.section = 'featured'
if text.status == 'private':
pos.section = 'personal'
pos.save()
if 'type' in data:
if data['type'] == 'pdf':
text.type = 'pdf'
else:
text.type = 'html'
if 'posterFrames' in data:
text.poster_frames = tuple(data['posterFrames'])
text.update_icon()
text.save()
response['data'] = text.json(user=request.user)
else:
response = json_response(status=403, text='permission denied')
return render_to_json_response(response)
actions.register(editText, cache=False)
def findText(request):
def _order_query(qs, sort):
order_by = []
for e in sort:
operator = e['operator']
if operator != '-':
operator = ''
key = {
'subscribed': 'subscribed_users',
'items': 'numberofitems'
}.get(e['key'], e['key'])
order = '%s%s' % (operator, key)
order_by.append(order)
if key == 'subscribers':
qs = qs.annotate(subscribers=Sum('subscribed_users'))
if order_by:
qs = qs.order_by(*order_by)
qs = qs.distinct()
return qs
def parse_query(data, user):
query = {}
query['range'] = [0, 100]
query['sort'] = [{'key':'user', 'operator':'+'}, {'key':'name', 'operator':'+'}]
for key in ('keys', 'group', 'text', 'range', 'position', 'positions', 'sort'):
if key in data:
query[key] = data[key]
print data
query['qs'] = models.Text.objects.find(data, user).exclude(name='')
print query
return query
def findTexts(request):
'''
param data {
query: {
conditions: [
{
key: 'user',
value: 'something',
operator: '='
}
]
operator: ","
},
sort: [{key: 'name', operator: '+'}],
range: [0, 100]
keys: []
}
possible query keys:
name, user, featured, subscribed
possible keys:
name, user, featured, subscribed, query
}
return {status: {code: int, text: string},
data: {
items: [
{name:, user:, featured:, public...}
]
}
}
'''
response = json_response({})
data = json.loads(request.POST['data'])
query = parse_query(data, request.user)
#order
is_section_request = query['sort'] == [{u'operator': u'+', u'key': u'position'}]
def is_featured_condition(x):
return x['key'] == 'status' and \
x['value'] == 'featured' and \
x['operator'] in ('=', '==')
is_featured = len(filter(is_featured_condition, data['query'].get('conditions', []))) > 0
if is_section_request:
qs = query['qs']
if not is_featured and not request.user.is_anonymous():
qs = qs.filter(position__in=models.Position.objects.filter(user=request.user))
qs = qs.order_by('position__position')
else:
qs = _order_query(query['qs'], query['sort'])
response = json_response()
if 'keys' in data:
qs = qs[query['range'][0]:query['range'][1]]
response['data']['items'] = [l.json(data['keys'], request.user) for l in qs]
elif 'position' in data:
#FIXME: actually implement position requests
response['data']['position'] = 0
elif 'positions' in data:
ids = [i.get_id() for i in qs]
response['data']['positions'] = utils.get_positions(ids, query['positions'])
else:
response['data']['items'] = qs.count()
return render_to_json_response(response)
actions.register(findText)
actions.register(findTexts)
@login_required_json
def removeText(request):
'''
param data {
id: testId,
}
return {
status: {'code': int, 'text': string},
data: {
}
}
'''
data = json.loads(request.POST['data'])
text = get_text_or_404_json(data['id'])
response = json_response()
if text.editable(request.user):
text.delete()
else:
response = json_response(status=403, text='not allowed')
return render_to_json_response(response)
actions.register(removeText, cache=False)
@login_required_json
def subscribeToText(request):
'''
param data {
id: testId,
}
return {
status: {'code': int, 'text': string},
data: {
}
}
'''
data = json.loads(request.POST['data'])
text = get_text_or_404_json(data['id'])
user = request.user
if text.status == 'public' and \
text.subscribed_users.filter(username=user.username).count() == 0:
text.subscribed_users.add(user)
pos, created = models.Position.objects.get_or_create(text=text, user=user, section='public')
if created:
qs = models.Position.objects.filter(user=user, section='public')
pos.position = qs.aggregate(Max('position'))['position__max'] + 1
pos.save()
response = json_response()
return render_to_json_response(response)
actions.register(subscribeToText, cache=False)
@login_required_json
def unsubscribeFromText(request):
'''
param data {
id: testId,
user: username(only admins)
}
return {
status: {'code': int, 'text': string},
data: {
}
}
'''
data = json.loads(request.POST['data'])
text = get_text_or_404_json(data['id'])
user = request.user
text.subscribed_users.remove(user)
models.Position.objects.filter(text=text, user=user, section='public').delete()
response = json_response()
return render_to_json_response(response)
actions.register(unsubscribeFromText, cache=False)
@login_required_json
def sortTexts(request):
'''
param data {
section: 'personal',
ids: [1,2,4,3]
}
known sections: 'personal', 'public', 'featured'
featured can only be edited by admins
return {
status: {'code': int, 'text': string},
data: {
}
}
'''
data = json.loads(request.POST['data'])
position = 0
section = data['section']
#ids = list(set(data['ids']))
ids = data['ids']
if section == 'featured' and not request.user.get_profile().capability('canEditFeaturedTexts'):
response = json_response(status=403, text='not allowed')
else:
user = request.user
if section == 'featured':
for i in ids:
l = get_text_or_404_json(i)
qs = models.Position.objects.filter(section=section, text=l)
if qs.count() > 0:
pos = qs[0]
else:
pos = models.Position(text=l, user=user, section=section)
if pos.position != position:
pos.position = position
pos.save()
position += 1
models.Position.objects.filter(section=section, text=l).exclude(id=pos.id).delete()
else:
for i in ids:
l = get_text_or_404_json(i)
pos, created = models.Position.objects.get_or_create(text=l,
user=request.user, section=section)
if pos.position != position:
pos.position = position
pos.save()
position += 1
response = json_response()
return render_to_json_response(response)
actions.register(sortTexts, cache=False)
def icon(request, id, size=16):
if not size:
size = 16
id = id.split(':')
username = id[0]
textname = ":".join(id[1:])
qs = models.Text.objects.filter(user__username=username, name=textname)
if qs.count() == 1 and qs[0].accessible(request.user):
text = qs[0]
icon = text.get_icon(int(size))
else:
icon = os.path.join(settings.STATIC_ROOT, 'jpg/list256.jpg')
return HttpFileResponse(icon, content_type='image/jpeg')

View file

@ -28,6 +28,7 @@ urlpatterns = patterns('',
(r'^api/?$', include(ox.django.api.urls)),
(r'^resetUI$', 'user.views.reset_ui'),
(r'^list/(?P<id>.*?)/icon(?P<size>\d*).jpg$', 'itemlist.views.icon'),
(r'^text/(?P<id>.*?)/icon(?P<size>\d*).jpg$', 'text.views.icon'),
(r'^robots.txt$', serve_static_file, {'location': os.path.join(settings.STATIC_ROOT, 'robots.txt'), 'content_type': 'text/plain'}),
(r'^favicon.ico$', serve_static_file, {'location': os.path.join(settings.STATIC_ROOT, 'png/icon.16.png'), 'content_type': 'image/x-icon'}),
(r'^opensearch.xml$', 'app.views.opensearch_xml'),

View file

@ -14,6 +14,7 @@ from ox.django.fields import DictField
from ox.utils import json
from itemlist.models import List, Position
import text
import managers
import tasks
@ -262,6 +263,29 @@ def get_ui(user_ui, user=None):
ids.append(id)
return ids
def add_texts(texts, section):
P = text.models.Position
ids = []
for t in texts:
qs = P.objects.filter(section=section)
if section == 'featured':
try:
pos = P.objects.get(text=t, section=section)
created = False
except P.DoesNotExist:
pos = P(text=t, section=section, user=l.user)
pos.save()
created = True
else:
pos, created = P.objects.get_or_create(text=t, user=user, section=section)
qs = qs.filter(user=user)
if created:
pos.position = qs.aggregate(Max('position'))['position__max'] + 1
pos.save()
ids.append(t.get_id())
return ids
ids = ['']
if user:
ids += add(user.lists.exclude(status="featured"), 'personal')
@ -270,6 +294,11 @@ def get_ui(user_ui, user=None):
for i in ui['lists'].keys():
if i not in ids:
del ui['lists'][i]
tids = ['']
if user:
tids += add_texts(user.texts.exclude(status="featured"), 'personal')
tids += add_texts(user.subscribed_texts.filter(status='public'), 'public')
tids += add_texts(text.models.Text.objects.filter(status='featured'), 'featured')
return ui
def init_user(user, request=None):

View file

@ -54,7 +54,10 @@ pandora.UI = (function() {
self.previousUI = Ox.clone(pandora.user.ui, true);
self.previousUI._list = pandora.getListState(self.previousUI.find);
if (args.section == 'texts') {
trigger['section'] = args['section'];
trigger['text'] = args['text'];
} else {
if ('find' in args) {
// the challenge here is that find may change list,
// and list may then change listSort and listView,
@ -152,6 +155,7 @@ pandora.UI = (function() {
add['videoPoints.' + item] = {annotation: '', 'in': 0, out: 0, position: 0};
}
}
}
// items in args trigger events, items in add do not
[args, add].forEach(function(obj, isAdd) {

View file

@ -16,10 +16,10 @@ pandora.URL = (function() {
var state = {};
state.type = pandora.site.itemsSection;
state.item = pandora.user.ui.item;
state.type = pandora.user.ui.section == 'items' ? pandora.site.itemsSection : pandora.user.ui.section;
state.item = pandora.user.ui[pandora.user.ui.section.slice(0, -1)];
if(pandora.user.ui.section == 'items') {
if (!pandora.user.ui.item) {
state.view = pandora.user.ui.listView;
state.sort = pandora.user.ui.listSort;
@ -28,6 +28,7 @@ pandora.URL = (function() {
state.view = pandora.user.ui.itemView;
state.sort = pandora.user.ui.itemSort;
}
}
if (state.view == 'map') {
state.span = pandora.user.ui.mapFind
@ -79,10 +80,11 @@ pandora.URL = (function() {
var set = {
section: state.type == pandora.site.itemsSection ? 'items' : state.type,
item: state.item,
page: ''
};
set[set.section.slice(0, -1)] = state.item;
if (set.section == 'items') {
if (state.view) {
set[!state.item ? 'listView' : 'itemView'] = state.view;
}
@ -131,6 +133,7 @@ pandora.URL = (function() {
set.find = pandora.site.user.ui.find;
}
}
}
if (state.hash && state.hash.query) {
state.hash.query.forEach(function(kv) {
@ -246,6 +249,19 @@ pandora.URL = (function() {
calendar: 'date'
}
};
//Text
views['texts'] = {
list: [],
item: ['text']
}
spanType['texts'] = {
list: [],
item: {}
}
sortKeys['texts'] = {
list: {},
item: {}
}
findKeys = [{id: 'list', type: 'string'}].concat(pandora.site.itemKeys);

View file

@ -12,7 +12,11 @@ pandora.ui.allItems = function() {
.on({
click: function() {
that.gainFocus();
if (pandora.user.ui.section == 'items') {
pandora.user.ui._list && pandora.UI.set('find', {conditions: [], operator: '&'});
} else {
pandora.UI.set(pandora.user.ui.section.slice(0, -1), '');
}
}
})
.bindEvent({
@ -33,9 +37,12 @@ pandora.ui.allItems = function() {
overflow: 'hidden',
whiteSpace: 'nowrap'
})
.html('All ' + pandora.site.itemName.plural)
.appendTo(that),
$items = $('<div>')
.html(pandora.user.ui.section == 'items' ? 'All ' + pandora.site.itemName.plural
: pandora.site.site.name + ' ' + Ox.toTitleCase(pandora.user.ui.section))
.appendTo(that);
if (pandora.user.ui.section == 'items') {
var $items = $('<div>')
.css({
float: 'left',
width: '42px',
@ -56,12 +63,12 @@ pandora.ui.allItems = function() {
type: 'image'
})
.appendTo(that);
pandora.api.find({
query: {conditions: [], operator: '&'}
}, function(result) {
that.update(result.data.items);
});
}
that.update = function(items) {
$items.html(Ox.formatNumber(items));

View file

@ -3,6 +3,9 @@
'use strict';
pandora.ui.deleteListDialog = function(list) {
var ui = pandora.user.ui,
folderItems = ui.section == 'items' ? 'Lists' : Ox.toTitleCase(ui.section),
folderItem = folderItems.slice(0, -1);
var listData = pandora.getListData(list),
$folderList = pandora.$ui.folderList[listData.folder],
@ -10,7 +13,7 @@ pandora.ui.deleteListDialog = function(list) {
buttons: [
Ox.Button({
id: 'keep',
title: 'Keep List'
title: 'Keep ' + folderItem
}).bindEvent({
click: function() {
that.close();
@ -18,23 +21,27 @@ pandora.ui.deleteListDialog = function(list) {
}),
Ox.Button({
id: 'delete',
title: 'Delete List'
title: 'Delete ' + folderItem
}).bindEvent({
click: function() {
that.close();
pandora.api.removeList({
pandora.api['remove' + folderItem]({
id: listData.id
}, function(result) {
Ox.Request.clearCache('findLists');
Ox.Request.clearCache('find' + folderItems);
Ox.Request.clearCache(listData.id);
$folderList
.options({selected: []})
.bindEventOnce({
load: function() {
if (ui.section == 'items') {
pandora.UI.set('lists.' + listData.id, null);
pandora.UI.set({
find: pandora.site.user.ui.find
});
} else {
pandora.UI.set(folderItem.toLowerCase(), '');
}
}
})
.reloadList();
@ -51,7 +58,7 @@ pandora.ui.deleteListDialog = function(list) {
.append(
$('<div>')
.css({position: 'absolute', left: '96px', top: '16px', width: '192px'})
.html('Are you sure you want to delete the list "' + listData.name + '"?')
.html('Are you sure you want to delete the ' + folderItem.toLowerCase() + ' "' + listData.name + '"?')
),
height: 128,
keys: {enter: 'delete', escape: 'keep'},

View file

@ -1,7 +1,10 @@
// vim: et:ts=4:sw=4:sts=4:ft=javascript
'use strict';
pandora.ui.folderBrowserBar = function(id) {
var that = Ox.Bar({
var ui = pandora.user.ui,
folderItems = ui.section == 'items' ? 'Lists' : Ox.toTitleCase(ui.section),
folderItem = folderItems.slice(0, -1),
that = Ox.Bar({
size: 24
});
pandora.$ui.findListElement[id] = Ox.FormElementGroup({
@ -9,7 +12,7 @@ pandora.ui.folderBrowserBar = function(id) {
pandora.$ui.findListSelect[id] = Ox.Select({
items: [
{id: 'user', title: 'Find: User'},
{id: 'name', title: 'Find: List'}
{id: 'name', title: 'Find: ' + folderItem}
],
overlap: 'right',
type: 'image'
@ -56,7 +59,7 @@ pandora.ui.folderBrowserBar = function(id) {
{key: 'status', value: 'private', operator: '!='},
{key: key, value: value, operator: '='}
], operator: '&'};
return pandora.api.findLists(Ox.extend(data, {
return pandora.api['find' + folderItems](Ox.extend(data, {
query: query
}), callback);
}

View file

@ -3,8 +3,11 @@
pandora.ui.folderBrowserList = function(id) {
// fixme: user and name are set to the same width here,
// but resizeFolders will set them to different widths
var columnWidth = (pandora.user.ui.sidebarSize - Ox.UI.SCROLLBAR_SIZE - 96) / 2,
i = Ox.getIndexById(pandora.site.sectionFolders[pandora.user.ui.section], id),
var ui = pandora.user.ui,
columnWidth = (ui.sidebarSize - Ox.UI.SCROLLBAR_SIZE - (ui.section == 'items' ? 96 : 32)) / 2,
i = Ox.getIndexById(pandora.site.sectionFolders[ui.section], id),
folderItems = ui.section == 'items' ? 'Lists' : Ox.toTitleCase(ui.section),
folderItem = folderItems.slice(0, -1),
that = Ox.TableList({
columns: [
{
@ -52,7 +55,7 @@ pandora.ui.folderBrowserList = function(id) {
},
id: 'name',
operator: '+',
title: 'List',
title: folderItem,
visible: true,
width: Math.ceil(columnWidth)
},
@ -62,7 +65,7 @@ pandora.ui.folderBrowserList = function(id) {
format: {type: 'number'},
operator: '-',
title: 'Items',
visible: true,
visible: ui.section == 'items',
width: 48
},
{
@ -72,7 +75,7 @@ pandora.ui.folderBrowserList = function(id) {
format: function(value, data) {
return $('<img>')
.attr({
src: Ox.UI.getImageURL(value == 'static' ? 'symbolClick' : 'symbolFind')
src: Ox.UI.getImageURL(value == 'smart' ? 'symbolFind' : value == 'pdf' ? 'symbolFiles' : value == 'html' ? 'symbolFile' : 'symbolClick')
})
.css({
width: '10px',
@ -89,7 +92,7 @@ pandora.ui.folderBrowserList = function(id) {
? (data.user == pandora.user.username ? 'Edit Query' : 'Show Query')
: (data.user == pandora.user.username ? 'Edit Default View' : 'Default View: ...');
},
visible: true,
visible: ui.section == 'items',
width: 16
},
{
@ -116,7 +119,7 @@ pandora.ui.folderBrowserList = function(id) {
tooltip: function(data) {
var checked = id == 'favorite' ? data.subscribed : data.status == 'featured';
return (checked ? 'Remove from' : 'Add to')
+ ' ' + Ox.toTitleCase(id) + ' Lists';
+ ' ' + Ox.toTitleCase(id) + ' ' + folderItems;
},
visible: true,
width: 16
@ -130,7 +133,7 @@ pandora.ui.folderBrowserList = function(id) {
], operator: '&'} : {conditions: [
{key: 'status', value: 'private', operator: '!='}
], operator: ''};
return pandora.api.findLists(Ox.extend(data, {
return pandora.api['find' + folderItems](Ox.extend(data, {
query: query
}), callback);
},
@ -139,7 +142,7 @@ pandora.ui.folderBrowserList = function(id) {
// not-featured list may be in the user's favorites folder
keys: id == 'featured' ? ['subscribed'] : [],
pageLength: 1000,
selected: pandora.getListData().folder == id ? [pandora.user.ui._list] : [],
selected: pandora.getListData().folder == id ? [ui.section == 'items' ? ui._list : ui[ui.section.slice(0, -1)]] : [],
sort: [{key: 'name', operator: '+'}],
unique: 'id'
})
@ -153,19 +156,19 @@ pandora.ui.folderBrowserList = function(id) {
*/
} else if (data.key == 'subscribed') {
var subscribed = that.value(data.id, 'subscribed');
pandora.api[subscribed ? 'unsubscribeFromList' : 'subscribeToList']({
pandora.api[subscribed ? 'unsubscribeFrom' + folderItem : 'subscribeTo' + folderItem]({
id: data.id
}, function(result) {
that.value(data.id, 'subscribed', !subscribed);
});
} else if (data.key == 'status') {
pandora.api.editList({
pandora.api['edit' + folderItem]({
id: data.id,
status: that.value(data.id, 'status') == 'featured' ? 'public' : 'featured'
}, function(result) {
Ox.Log('', 'result', result)
if (result.data.user == pandora.user.username || result.data.subscribed) {
Ox.Request.clearCache(); // fixme: remove
Ox.Request.clearCache(); // fixme: removen
pandora.$ui.folderList[
result.data.user == pandora.user.username ? 'personal' : 'favorite'
].reloadList();
@ -175,7 +178,7 @@ pandora.ui.folderBrowserList = function(id) {
}
},
init: function(data) {
pandora.site.sectionFolders[pandora.user.ui.section][i].items = data.items;
pandora.site.sectionFolders[ui.section][i].items = data.items;
pandora.$ui.folder[i].$content.css({
height: 40 + data.items * 16 + 'px'
});
@ -185,7 +188,9 @@ pandora.ui.folderBrowserList = function(id) {
pandora.resizeFolders();
},
paste: function(data) {
if (ui.section == 'items') {
pandora.$ui.list.triggerEvent('paste', data);
}
},
select: function(data) {
// fixme: duplicated
@ -195,6 +200,7 @@ pandora.ui.folderBrowserList = function(id) {
id != id_ && $list.options('selected', []);
});
}
if (ui.section == 'items') {
pandora.UI.set({
find: {
conditions: list ? [
@ -203,6 +209,9 @@ pandora.ui.folderBrowserList = function(id) {
operator: '&'
}
});
} else {
pandora.UI.set(ui.section.slice(0, -1), list);
}
}
});
return that;

View file

@ -1,20 +1,23 @@
// vim: et:ts=4:sw=4:sts=4:ft=javascript
'use strict';
pandora.ui.folderList = function(id) {
var i = Ox.getIndexById(pandora.site.sectionFolders[pandora.user.ui.section], id),
canEditFeaturedLists = pandora.site.capabilities.canEditFeaturedLists[pandora.user.level],
var ui = pandora.user.ui,
i = Ox.getIndexById(pandora.site.sectionFolders[ui.section], id),
folderItems = ui.section == 'items' ? 'Lists' : Ox.toTitleCase(ui.section),
folderItem = folderItems.slice(0, -1),
canEditFeatured = pandora.site.capabilities['canEditFeatured' + folderItems][pandora.user.level],
that;
if (pandora.user.ui.section == 'items') {
var columns, items;
if (id != 'volumes') {
columns = [
{
clickable: function(data) {
return data.user == pandora.user.username || (id == 'featured' && canEditFeaturedLists);
return data.user == pandora.user.username || (id == 'featured' && canEditFeatured);
},
format: function(value, data) {
return $('<img>').attr({
src: '/list/' + data.id + '/icon.jpg'
src: '/' + folderItem.toLowerCase() + '/' + data.id + '/icon.jpg'
}).css({
width: '14px',
height: '14px',
@ -26,7 +29,7 @@ pandora.ui.folderList = function(id) {
operator: '+',
tooltip: function(data) {
return data.user == pandora.user.username
|| (id == 'featured' && canEditFeaturedLists)
|| (id == 'featured' && canEditFeatured)
? 'Edit Icon'
: '';
},
@ -42,7 +45,7 @@ pandora.ui.folderList = function(id) {
visible: id == 'favorite',
// fixme: user and name are set to the same width here,
// but resizeFolders will set them to different widths
width: pandora.user.ui.sidebarWidth - 96
width: ui.sidebarWidth - 96
},
{
editable: function(data) {
@ -61,7 +64,7 @@ pandora.ui.folderList = function(id) {
return Ox.decodeHTMLEntities(value);
},
visible: id != 'favorite',
width: pandora.user.ui.sidebarWidth - 96
width: ui.sidebarWidth - 96
},
{
align: 'right',
@ -78,7 +81,7 @@ pandora.ui.folderList = function(id) {
format: function(value, data) {
return $('<img>')
.attr({
src: Ox.UI.getImageURL(value == 'static' ? 'symbolClick' : 'symbolFind')
src: Ox.UI.getImageURL(value == 'smart' ? 'symbolFind' : value == 'pdf' ? 'symbolFiles' : value == 'html' ? 'symbolFile' : 'symbolClick')
})
.css({
width: '10px',
@ -140,7 +143,7 @@ pandora.ui.folderList = function(id) {
{key: 'status', value: 'featured', operator: '='} // fixme: '==' performs better
], operator: '&'};
}
return pandora.api.findLists(Ox.extend(data, {
return pandora.api['find' + folderItems](Ox.extend(data, {
query: query
}), callback);
};
@ -167,7 +170,7 @@ pandora.ui.folderList = function(id) {
operator: '+',
tooltip: 'Edit Title',
visible: true,
width: pandora.user.ui.sidebarWidth - 96
width: ui.sidebarWidth - 96
},
{
align: 'right',
@ -241,19 +244,19 @@ pandora.ui.folderList = function(id) {
that = Ox.TableList({
columns: columns,
items: items,
keys: ['query'],
keys: ui.section == 'items' ? ['query'] : [],
max: 1,
min: 0,
pageLength: 1000,
//selected: pandora.getListData().folder == id ? [pandora.user.ui._list] : [],
//selected: pandora.getListData().folder == id ? [ui._list] : [],
sort: [{key: 'position', operator: '+'}],
sortable: id != 'featured' || canEditFeaturedLists,
sortable: id != 'featured' || canEditFeatured,
unique: id != 'volumes' ? 'id' : 'name'
})
.css({
left: 0,
top: 0,
width: pandora.user.ui.sidebarWidth + 'px'
width: ui.sidebarWidth + 'px'
})
.bindEvent({
add: function(event) {
@ -284,7 +287,7 @@ pandora.ui.folderList = function(id) {
});
});
}
} else if (id == 'favorite' || (id == 'featured' && canEditFeaturedLists)) {
} else if (id == 'favorite' || (id == 'featured' && canEditFeatured)) {
// this makes the button trigger a change event,
// which is already being handled in folders.js
pandora.$ui.manageListsButton[id].options({value: true});
@ -309,7 +312,7 @@ pandora.ui.folderList = function(id) {
}
} else if (data.key == 'status') {
var status = that.value(data.id, data.key) == 'private' ? 'public' : 'private';
pandora.changeListStatus(data.id, status, function(result) {
pandora.changeFolderItemStatus(data.id, status, function(result) {
that.value(result.data.id, 'status', result.data.status);
});
} else if (data.key == 'path') {
@ -323,15 +326,15 @@ pandora.ui.folderList = function(id) {
pandora.ui.deleteListDialog(data.ids[0]).open();
} else if (id == 'favorite') {
that.options({selected: []});
pandora.api.unsubscribeFromList({
pandora.api['unsubscribeFrom' + folderItem]({
id: data.ids[0]
}, function(result) {
Ox.Request.clearCache(); // fixme: remove
that.reloadList();
});
} else if (id == 'featured' && canEditFeaturedLists) {
} else if (id == 'featured' && canEditFeatured) {
that.options({selected: []});
pandora.api.editList({
pandora.api['edit' + folderItem]({
id: data.ids[0],
status: 'public'
}, function(result) {
@ -352,7 +355,7 @@ pandora.ui.folderList = function(id) {
},
*/
init: function(data) {
pandora.site.sectionFolders[pandora.user.ui.section][i].items = data.items;
pandora.site.sectionFolders[ui.section][i].items = data.items;
pandora.$ui.folder[i].$content.css({
height: data.items * 16 + 'px'
});
@ -362,7 +365,7 @@ pandora.ui.folderList = function(id) {
pandora.resizeFolders();
},
move: function(data) {
pandora.api.sortLists({
pandora.api['sort' + foldeItem]({
section: id,
ids: data.ids
});
@ -377,6 +380,7 @@ pandora.ui.folderList = function(id) {
id != id_ && $list.options('selected', []);
});
}
if (ui.section == 'items') {
pandora.UI.set({
find: {
conditions: list ? [
@ -385,11 +389,14 @@ pandora.ui.folderList = function(id) {
operator: '&'
}
});
} else {
pandora.UI.set(ui.section.slice(0, -1), list);
}
},
submit: function(data) {
var data_ = {id: data.id};
data_[data.key] = data.value;
pandora.api.editList(data_, function(result) {
pandora.api['edit' + folderItem](data_, function(result) {
if (result.data.id != data.id) {
pandora.renameList(data.id, result.data.id, result.data.name, id);
pandora.$ui.info.updateListInfo();
@ -397,6 +404,5 @@ pandora.ui.folderList = function(id) {
});
}
});
}
return that;
};

View file

@ -7,7 +7,9 @@ pandora.ui.folders = function() {
.css({overflowX: 'hidden', overflowY: 'auto'})
.bindEvent({
resize: pandora.resizeFolders
});
}),
folderItems = ui.section == 'items' ? 'Lists' : Ox.toTitleCase(ui.section),
folderItem = folderItems.slice(0, -1);
//var $sections = [];
pandora.$ui.allItems = pandora.ui.allItems().appendTo(that);
@ -18,15 +20,17 @@ pandora.ui.folders = function() {
pandora.$ui.findListSelect = {};
pandora.$ui.findListInput = {};
pandora.$ui.manageListsButton = {};
if (ui.section == 'items') {
pandora.site.sectionFolders.items.forEach(function(folder, i) {
pandora.site.sectionFolders[ui.section].forEach(function(folder, i) {
var extras, $select;
if (folder.id == 'personal') {
if (pandora.user.level == 'guest') {
extras = [
infoButton('Personal Lists', 'To create and share your own lists of movies, please sign up or sign in.')
infoButton('Personal ' + folderItems, 'To create and share your own ' + (ui.section == 'items'
? 'lists of ' + pandora.site.itemName.plural.toLowerCase()
: ui.section) + ', please sign up or sign in.')
];
} else {
if (ui.section == 'items') {
extras = [
pandora.$ui.personalListsMenu = Ox.MenuButton({
items: [
@ -78,24 +82,55 @@ pandora.ui.folders = function() {
}
})
];
} else {
extras = [
pandora.$ui.personalListsMenu = Ox.MenuButton({
items: [
{ id: 'new' + folderItem.toLowerCase(), title: 'New ' + folderItem },
{},
{ id: 'delete' + folderItem.toLowerCase(), title: 'Delete Selected ' + folderItem + '...', disabled: !ui[ui.section.slice(0,-1)] }
],
title: 'edit',
tooltip: 'Manage Personal ' + folderItems,
type: 'image'
})
.bindEvent({
click: function(data) {
var $list = pandora.$ui.folderList[folder.id];
// fixme: duplicated
if (data.id == 'new' + folderItem.toLowerCase()) {
pandora['add' + folderItem]();
} else if (data.id == 'delete' + folderItem.toLowerCase()) {
pandora.ui.deleteListDialog().open();
}
}
})
.bindEvent('pandora_' + ui.section.slice(0,-1), function(data) {
pandora.$ui.personalListsMenu[
data.value && data.value.length ? 'enableItem' : 'disableItem'
]('delete' + folderItem.toLowerCase());
})
];
}
}
} else if (folder.id == 'favorite') {
if (pandora.user.level == 'guest') {
extras = [infoButton('Favorite Lists', 'To browse and subscribe to shared lists from other users, please sign up or sign in.')];
extras = [infoButton('Favorite ' + folderItems,
'To browse and subscribe to shared ' + folderItems.toLowerCase() + ' from other users, please sign up or sign in.')];
} else {
extras = [pandora.$ui.manageListsButton['favorite'] = Ox.Button({
selectable: true,
style: 'symbol',
title: 'Edit',
tooltip: 'Manage Favorite Lists',
tooltip: 'Manage Favorite ' + folderItems,
type: 'image'
})
.bindEvent({
change: function(data) {
var listData;
Ox.Request.clearCache(); // fixme: remove
pandora.site.sectionFolders.items[i].showBrowser = !pandora.site.sectionFolders.items[i].showBrowser;
if (pandora.site.sectionFolders.items[i].showBrowser) {
pandora.site.sectionFolders[ui.section][i].showBrowser = !pandora.site.sectionFolders[ui.section][i].showBrowser;
if (pandora.site.sectionFolders[ui.section][i].showBrowser) {
pandora.$ui.folderList.favorite.replaceWith(
pandora.$ui.folderBrowser.favorite = pandora.ui.folderBrowser('favorite')
);
@ -107,7 +142,7 @@ pandora.ui.folders = function() {
) {
// the selected list in the favorites browser is not in the favorites folder
pandora.$ui.folderList.favorite.options({selected: []});
if (Ox.getObjectById(pandora.site.sectionFolders.items, 'featured').showBrowser) {
if (Ox.getObjectById(pandora.site.sectionFolders[ui.section], 'featured').showBrowser) {
// but in the featured browser
pandora.$ui.folderList.featured.options({selected: [listData.id]});
} else {
@ -127,21 +162,21 @@ pandora.ui.folders = function() {
}
} else if (folder.id == 'featured') {
if (pandora.user.level != 'admin') {
extras = [infoButton('Featured Lists', 'Featured lists are selected public lists, picked by the ' + pandora.site.site.name + ' staff.')];
extras = [infoButton('Featured ' + folderItems, 'Featured ' + folderItems.toLowerCase() + ' are selected public ' + folderItems.toLowerCase() + ', picked by the ' + pandora.site.site.name + ' staff.')];
} else {
extras = [pandora.$ui.manageListsButton['featured'] = Ox.Button({
selectable: true,
style: 'symbol',
title: 'Edit',
tooltip: 'Manage Featured Lists',
tooltip: 'Manage Featured ' + folderItems,
type: 'image'
})
.bindEvent({
change: function(data) {
var listData;
Ox.Request.clearCache(); // fixme: remove
pandora.site.sectionFolders.items[i].showBrowser = !pandora.site.sectionFolders.items[i].showBrowser;
if (pandora.site.sectionFolders.items[i].showBrowser) {
pandora.site.sectionFolders[ui.section][i].showBrowser = !pandora.site.sectionFolders[ui.section][i].showBrowser;
if (pandora.site.sectionFolders[ui.section][i].showBrowser) {
pandora.$ui.folderList.featured.replaceWith(
pandora.$ui.folderBrowser.featured = pandora.ui.folderBrowser('featured')
);
@ -159,7 +194,7 @@ pandora.ui.folders = function() {
pandora.$ui.folderList.personal.options({selected: [listData.id]});
} else if (
listData.subscribed
|| Ox.getObjectById(pandora.site.sectionFolders.items, 'favorite').showBrowser
|| Ox.getObjectById(pandora.site.sectionFolders[ui.section], 'favorite').showBrowser
) {
// but in the favorites folder or browser
pandora.$ui.folderList.favorite.options({selected: [listData.id]});
@ -255,7 +290,7 @@ pandora.ui.folders = function() {
})
.bindEventOnce({
init: function(data) {
if (++counter == 4) {
if (++counter == pandora.site.sectionFolders[ui.section].length) {
pandora.$ui.folder.forEach(function($folder) {
that.append($folder);
});
@ -266,7 +301,6 @@ pandora.ui.folders = function() {
})
.appendTo(pandora.$ui.folder[i].$content);
});
}
function infoButton(title, text) {
return Ox.Button({
style: 'symbol',
@ -340,6 +374,13 @@ pandora.ui.folders = function() {
});
}
*/
},
pandora_text: function() {
if (!pandora.user.ui.text) {
Ox.forEach(pandora.$ui.folderList, function($list, id) {
$list.options('selected', []);
});
}
}
})
return that;

View file

@ -13,7 +13,10 @@ pandora.ui.listDialog = function(section) {
], listData.type == 'smart'
? [{id: 'query', title: 'Query'}]
: []
);
),
ui = pandora.user.ui,
folderItems = ui.section == 'items' ? 'Lists' : Ox.toTitleCase(ui.section),
folderItem = folderItems.slice(0, -1);
Ox.getObjectById(tabs, section).selected = true;
pandora.$ui.listDialogTabPanel = Ox.TabPanel({
@ -103,7 +106,7 @@ pandora.ui.listDialog = function(section) {
height: 312,
// keys: {enter: 'save', escape: 'cancel'},
removeOnClose: true,
title: 'List &mdash; ' + Ox.encodeHTMLEntities(listData.name),
title: folderItem + ' &mdash; ' + Ox.encodeHTMLEntities(listData.name),
width: width
});
@ -117,8 +120,11 @@ pandora.ui.listDialog = function(section) {
};
pandora.ui.listGeneralPanel = function(listData) {
var that = Ox.Element();
pandora.api.findLists({
var that = Ox.Element(),
ui = pandora.user.ui,
folderItems = ui.section == 'items' ? 'Lists' : Ox.toTitleCase(ui.section),
folderItem = folderItems.slice(0, -1);
pandora.api['find' + folderItems]({
query: {conditions: [{key: 'id', value: listData.id, operator: '=='}]},
keys: ['description', 'subscribers']
}, function(result) {
@ -129,7 +135,7 @@ pandora.ui.listGeneralPanel = function(listData) {
tooltip: 'Doubleclick to edit icon'
})
.attr({
src: '/list/' + listData.id + '/icon256.jpg?' + Ox.uid()
src: '/' + folderItem.toLowerCase() + '/' + listData.id + '/icon256.jpg?' + Ox.uid()
})
.css({
position: 'absolute',
@ -157,7 +163,8 @@ pandora.ui.listGeneralPanel = function(listData) {
submit: editName
})
.appendTo(that),
$itemsInput = Ox.Input({
$itemsInput = ui.section == 'items'
? Ox.Input({
disabled: true,
label: 'Items',
labelWidth: 80,
@ -165,6 +172,21 @@ pandora.ui.listGeneralPanel = function(listData) {
width: 320
})
.css({position: 'absolute', left: '160px', top: '40px'})
.appendTo(that)
: Ox.Select({
items: [
{id: 'html', title: 'HMTL'},
{id: 'pdf', title: 'PDF'}
],
label: 'Type',
labelWidth: 80,
value: listData.type,
width: 320
})
.css({position: 'absolute', left: '160px', top: '40px'})
.bindEvent({
change: editType
})
.appendTo(that),
$statusSelect = listData.status == 'featured'
? Ox.Input({
@ -216,19 +238,19 @@ pandora.ui.listGeneralPanel = function(listData) {
.appendTo(that);
function editDescription(data) {
if (data.value != description) {
pandora.api.editList({
pandora.api['edit' + folderItem]({
id: listData.id,
description: data.value
}, function(result) {
description = result.data.description;
Ox.Request.clearCache('findLists');
Ox.Request.clearCache('find' + folderItems);
pandora.$ui.info.updateListInfo();
});
}
}
function editName(data) {
if (data.value != listData.name) {
pandora.api.editList({
pandora.api['edit' + folderItem]({
id: listData.id,
name: data.value
}, function(result) {
@ -236,10 +258,10 @@ pandora.ui.listGeneralPanel = function(listData) {
pandora.renameList(listData.id, result.data.id, result.data.name);
listData.id = result.data.id;
listData.name = result.data.name;
Ox.Request.clearCache('findLists');
Ox.Request.clearCache('find' + folderItems);
pandora.$ui.info.updateListInfo();
pandora.$ui.listDialog.options({
title: 'List &mdash; ' + Ox.encodeHTMLEntities(listData.name)
title: folderItme + ' &mdash; ' + Ox.encodeHTMLEntities(listData.name)
});
}
});
@ -248,7 +270,7 @@ pandora.ui.listGeneralPanel = function(listData) {
function editStatus(data) {
var status = data.value;
$statusSelect.value(status == 'private' ? 'public' : 'private');
pandora.changeListStatus(listData.id, status, function(result) {
pandora.changeFolderItemStatus(listData.id, status, function(result) {
listData.status = result.data.status;
if (result.data.status == 'private') {
subscribers = 0;
@ -264,6 +286,18 @@ pandora.ui.listGeneralPanel = function(listData) {
);
});
}
function editType(data) {
var type = data.value;
$itemsInput.value(type == 'html' ? 'html' : 'pdf');
pandora.api.editText({
id: listData.id,
type: type
}, function(result) {
Ox.Request.clearCache('getText');
//fixme: reload text and folder list
$itemsInput.value(result.data.type);
});
}
function getDescriptionHeight() {
return listData.status == 'private' ? 184 : 160;
}
@ -282,10 +316,14 @@ pandora.ui.listIconPanel = function(listData) {
var quarter = 0,
quarters = ['top-left', 'top-right', 'bottom-left', 'bottom-right'],
ui = pandora.user.ui,
folderItems = ui.section == 'items' ? 'Lists' : Ox.toTitleCase(ui.section),
folderItem = folderItems.slice(0, -1),
$iconPanel = Ox.Element(),
$icon = $('<img>')
.attr({src: '/list/' + listData.id + '/icon256.jpg?' + Ox.uid()})
.attr({src: '/' + folderItem.toLowerCase() + '/' + listData.id + '/icon256.jpg?' + Ox.uid()})
.css({position: 'absolute', borderRadius: '64px', margin: '16px'})
.appendTo($iconPanel),
@ -295,6 +333,10 @@ pandora.ui.listIconPanel = function(listData) {
$list = Ox.Element(),
ui = pandora.user.ui,
folderItems = ui.section == 'items' ? 'Lists' : Ox.toTitleCase(ui.section),
folderItem = folderItems.slice(0, -1),
that = Ox.SplitPanel({
elements: [
{
@ -312,7 +354,7 @@ pandora.ui.listIconPanel = function(listData) {
orientation: 'horizontal'
});
pandora.api.findLists({
pandora.api['find' + folderItems]({
query: {
conditions: [{key: 'id', value: listData.id, operator: '=='}],
operator: '&'
@ -364,7 +406,7 @@ pandora.ui.listIconPanel = function(listData) {
items: function(data, callback) {
pandora.api.find(Ox.extend(data, {
query: {
conditions: [{key: 'list', value: listData.id, operator: '=='}],
conditions: ui.section == 'items' ? [{key: 'list', value: listData.id, operator: '=='}] : [],
operator: '&'
}
}), callback);
@ -375,7 +417,7 @@ pandora.ui.listIconPanel = function(listData) {
//orientation: 'vertical',
selected: posterFrame ? [posterFrame.item] : [],
size: 128,
sort: pandora.user.ui.listSort,
sort: ui.section == 'items' ? pandora.user.ui.listSort : pandora.site.user.ui.listSort,
unique: 'id'
})
//.css({width: '144px'})
@ -461,17 +503,17 @@ pandora.ui.listIconPanel = function(listData) {
} else {
posterFrames = Ox.repeat([posterFrame], 4);
}
pandora.api.editList({
pandora.api['edit' + folderItem]({
id: listData.id,
posterFrames: posterFrames
}, function() {
$icon.attr({
src: '/list/' + listData.id + '/icon256.jpg?' + Ox.uid()
src: '/' + folderItem.toLowerCase() + '/' + listData.id + '/icon256.jpg?' + Ox.uid()
});
pandora.$ui.folderList[listData.folder].$element
.find('img[src*="/' + listData.id + '/"]')
.attr({
src: '/list/' + listData.id + '/icon.jpg?' + Ox.uid()
src: '/' + folderItem.toLowerCase() + '/' + listData.id + '/icon.jpg?' + Ox.uid()
});
pandora.$ui.info.updateListInfo();
pandora.clearListIconCache(listData.id);

View file

@ -65,6 +65,12 @@ pandora.ui.mainPanel = function() {
}
}
},
pandora_section: function(data) {
if (data.value != data.previousValue) {
that.replaceElement(0, pandora.$ui.leftPanel = pandora.ui.leftPanel());
that.replaceElement(1, pandora.$ui.rightPanel = pandora.ui.rightPanel());
}
},
pandora_item: function(data) {
if (!data.value || !data.previousValue) {
that.replaceElement(1, pandora.$ui.rightPanel = pandora.ui.rightPanel());

View file

@ -57,6 +57,8 @@ pandora.ui.rightPanel = function() {
}
}
});
} else if (pandora.user.ui.section == 'texts') {
that = pandora.$ui.text = pandora.ui.text();
}
return that;
};

View file

@ -5,7 +5,7 @@ pandora.ui.sectionButtons = function() {
buttons: [
{id: 'items', title: pandora.site.itemName.plural},
{id: 'edits', title: 'Edits', disabled: true},
{id: 'texts', title: 'Texts', disabled: true}
{id: 'texts', title: 'Texts', disabled: pandora.user.level != 'admin'}
],
id: 'sectionButtons',
selectable: true,
@ -17,13 +17,7 @@ pandora.ui.sectionButtons = function() {
.bindEvent({
change: function(data) {
var section = data.value;
if (section == 'items') {
pandora.URL.set(pandora.Query.toString());
} else if (section == 'clips') {
pandora.URL.set('clips');
} else if (section == 'texts') {
pandora.URL.set('texts');
}
pandora.UI.set({section: section});
}
});
return that;

58
static/js/pandora/text.js Normal file
View file

@ -0,0 +1,58 @@
'use strict';
pandora.ui.text = function() {
var ui = pandora.user.ui,
canEdit = pandora.site.capabilities.canEditSitePages[pandora.user.level],
that,
text,
$text;
getText(ui.text);
that = Ox.Element()
.bindEvent({
pandora_text: function(data) {
if (ui.text != text) {
text = ui.text;
getText(ui.text);
}
}
});
function getText(id) {
pandora.api.getText({id: id}, function(result) {
if (result.data.type == 'pdf') {
$text && $text.remove();
$text = Ox.Editable({
clickLink: pandora.clickLink,
editable: false,
type: 'textarea',
value: 'REPLACE ME WITH PDF VIEWER'
})
.appendTo(that);
} else {
var text = result.data ? result.data.text : '';
$text && $text.remove();
$text = Ox.Editable({
clickLink: pandora.clickLink,
editable: canEdit,
tooltip: canEdit ? 'Doubleclick to edit' : '',
type: 'textarea',
placeholder: 'No text',
value: text
})
.bindEvent({
submit: function(data) {
Ox.Request.clearCache('getText');
pandora.api.editText({
id: ui.text,
text: data.value
});
}
})
.appendTo(that);
}
});
}
return that;
}

View file

@ -147,10 +147,31 @@ pandora.addList = function() {
}).reloadList();
}
};
pandora.addText = function() {
var $folderList = pandora.$ui.folderList.personal;
pandora.api.addText({name: 'Untitled'}, function(result) {
reloadFolder(result.data.id);
});
function reloadFolder(newId) {
pandora.$ui.folder[0].options({collapsed: false});
Ox.Request.clearCache('findTexts');
$folderList.bindEventOnce({
load: function(data) {
$folderList.gainFocus()
.options({selected: [newId]})
.editCell(newId, 'name', true);
pandora.UI.set(pandora.user.ui.section.slice(0, -1), newId);
}
}).reloadList();
}
}
pandora.changeListStatus = function(id, status, callback) {
pandora.changeFolderItemStatus = function(id, status, callback) {
var ui = pandora.user.ui,
folderItems = ui.section == 'items' ? 'Lists' : Ox.toTitleCase(ui.section),
folderItem = folderItems.slice(0, -1);
if (status == 'private') {
pandora.api.findLists({
pandora.api['find' + folderItems]({
query: {conditions: [{key: 'id', value: id, operator: '=='}]},
keys: ['name', 'subscribers']
}, function(result) {
@ -168,14 +189,14 @@ pandora.changeListStatus = function(id, status, callback) {
}
}).open();
} else {
changeListStatus();
changeFolderItemStatus();
}
});
} else {
changeListStatus();
changeFolderItemStatus();
}
function changeListStatus() {
pandora.api.editList({
function changeFolderItemStatus() {
pandora.api['edit' + folderItem]({
id: id,
status: status
}, callback);
@ -606,7 +627,8 @@ pandora.getInfoHeight = function(includeHidden) {
return height;
}
pandora.getItemByIdOrTitle = function(str, callback) {
pandora.getItemByIdOrTitle = function(type, str, callback) {
if (type == pandora.site.itemName.plural.toLowerCase()) {
var sortKey = Ox.getObjectById(pandora.site.itemKeys, 'votes')
? 'votes'
: 'timesaccessed';
@ -642,6 +664,9 @@ pandora.getItemByIdOrTitle = function(str, callback) {
});
}
});
} else {
callback(str);
}
}
pandora.getItemFind = function(find) {
@ -706,7 +731,11 @@ pandora.getItemIdAndPosition = function() {
pandora.getListData = function(list) {
var data = {}, folder;
if (pandora.user.ui.section == 'items') {
list = Ox.isUndefined(list) ? pandora.user.ui._list : list;
} else {
list = Ox.isUndefined(list) ? pandora.user.ui[pandora.user.ui.section.slice(0, -1)] : list;
}
if (list) {
Ox.forEach(pandora.$ui.folderList, function($list, id) {
var ret = true;
@ -726,8 +755,12 @@ pandora.getListData = function(list) {
// FIXME: Is there a `return ret` statement missing here?
});
if (folder) {
data = pandora.$ui.folderList[folder].value(pandora.user.ui._list);
data = pandora.$ui.folderList[folder].value(list);
if (pandora.user.ui.section == 'item') {
data.editable = data.user == pandora.user.username && data.type == 'static';
} else {
data.editable = data.user == pandora.user.username;
}
data.folder = folder;
}
}
@ -1076,6 +1109,7 @@ pandora.renameList = function(oldId, newId, newName, folder) {
folder = folder || pandora.getListData(oldId).folder;
pandora.$ui.folderList[folder].value(oldId, 'name', newName);
pandora.$ui.folderList[folder].value(oldId, 'id', newId);
if (pandora.user.ui.section == 'items') {
pandora.$ui.toolbar.updateListName(newId);
pandora.UI.set({
find: {
@ -1083,17 +1117,20 @@ pandora.renameList = function(oldId, newId, newName, folder) {
operator: '&'
}
}, false);
} else {
pandora.UI.set(pandora.user.ui.section.slice(0, -1), newId);
}
};
pandora.resizeFilters = function(width) {
pandora.user.ui.filterSizes = pandora.getFilterSizes();
pandora.$ui.browser
pandora.$ui.browser && pandora.$ui.browser
.size(0, pandora.user.ui.filterSizes[0])
.size(2, pandora.user.ui.filterSizes[4]);
pandora.$ui.filtersInnerPanel
pandora.$ui.filtersInnerPanel && pandora.$ui.filtersInnerPanel
.size(0, pandora.user.ui.filterSizes[1])
.size(2, pandora.user.ui.filterSizes[3]);
pandora.$ui.filters.forEach(function($list, i) {
pandora.$ui.filters && pandora.$ui.filters.forEach(function($list, i) {
$list.resizeColumn('name', pandora.user.ui.filterSizes[i] - 44 - Ox.UI.SCROLLBAR_SIZE);
if (pandora.user.ui.showFlags) {
$list.find('.flagname').css({width: pandora.user.ui.filterSizes[i] - 68 - Ox.UI.SCROLLBAR_SIZE})
@ -1103,18 +1140,16 @@ pandora.resizeFilters = function(width) {
pandora.resizeFolders = function() {
var width = pandora.getFoldersWidth(),
columnWidth = {};
if (pandora.user.ui.section == 'items') {
columnWidth = {user: parseInt((width - 96) * 0.4)};
columnWidth.name = (width - 96) - columnWidth.user;
}
columnWidth = {},
sectionWidth = pandora.user.ui.section == 'items'? 96 : 32;
columnWidth = {user: parseInt((width - (sectionWidth)) * 0.4)};
columnWidth.name = (width - sectionWidth) - columnWidth.user;
Ox.Log('', 'RESIZE FOLDERS', width);
pandora.$ui.allItems.resizeElement(width - 104);
Ox.forEach(pandora.$ui.folderList, function($list, id) {
var pos = Ox.getIndexById(pandora.site.sectionFolders[pandora.user.ui.section], id);
pandora.$ui.folder[pos].css({width: width + 'px'});
$list.css({width: width + 'px'});
if (pandora.user.ui.section == 'items') {
if (pandora.site.sectionFolders[pandora.user.ui.section][pos].showBrowser) {
pandora.$ui.findListInput[id].options({
width: width - 24
@ -1124,7 +1159,6 @@ pandora.resizeFolders = function() {
} else {
$list.resizeColumn(id == 'favorite' ? 'id' : 'name', width - 96);
}
}
if (!pandora.user.ui.showFolder[pandora.user.ui.section][id]) {
pandora.$ui.folder[pos].updatePanel();
}
@ -1135,6 +1169,7 @@ pandora.resizeWindow = function() {
// FIXME: a lot of this throws errors on load
pandora.$ui.leftPanel && pandora.$ui.leftPanel.size(2, pandora.getInfoHeight(true));
pandora.resizeFolders();
if (pandora.user.ui.section == 'item') {
if (!pandora.user.ui.item) {
pandora.resizeFilters(pandora.$ui.rightPanel.width());
if (pandora.user.ui.listView == 'clips') {
@ -1192,9 +1227,11 @@ pandora.resizeWindow = function() {
pandora.$ui.calendar.resizeCalendar();
}
}
}
};
pandora.selectList = function() {
if (pandora.user.ui.section == 'items') {
if (pandora.user.ui._list) {
pandora.api.findLists({
keys: ['status', 'user'],
@ -1218,6 +1255,20 @@ pandora.selectList = function() {
}
});
}
} else {
var id = pandora.user.ui[pandora.user.ui.section.slice(0,-1)];
if (id) {
pandora.api.getText({id: id}, function(result) {
var folder;
if (result.data.id) {
folder = result.data.status == 'featured' ? 'featured' : (
result.data.user == pandora.user.username ? 'personal' : 'favorite'
);
pandora.$ui.folderList[folder].options({selected: [id]});
}
});
}
}
};
pandora.beforeunloadWindow = function() {