initial round of text section

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

View file

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

View file

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

View file

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

View file

@ -207,7 +207,9 @@ def addList(request):
return { return {
status: {'code': int, 'text': string}, status: {'code': int, 'text': string},
data: { 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 # vi:si:et:sw=4:sts=4:ts=4
from __future__ import division, with_statement from __future__ import division, with_statement
from datetime import datetime from datetime import datetime
import os
import subprocess
from glob import glob
from django.db import models from django.db import models
from django.contrib.auth.models import User 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 Text(models.Model):
class Meta:
unique_together = ("user", "name")
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)
published = models.DateTimeField(default=datetime.now, editable=False) user = models.ForeignKey(User, related_name='texts')
public = models.BooleanField(default=False) 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) icon = models.ImageField(default=None, blank=True,
slug = models.SlugField() upload_to=lambda i, x: i.path("icon.jpg"))
title = models.CharField(null=True, max_length=1000)
text = models.TextField(default='') 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): def __unicode__(self):
return u"%s <%s>" % (self.title, self.slug) return self.get_id()
def get_absolute_url(self): def get_id(self):
return '/text/%s' % self.slug 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): def editable(self, user):
image = models.ImageField(upload_to='text/image') if user.is_anonymous():
caption = models.CharField(max_length=255, default="") 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): def json(self, keys=None, user=None):
return self.image.url 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): def update_icon(self):
file = models.FileField(upload_to='text/attachment') frames = []
caption = models.CharField(max_length=255, default="") 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 -*- # -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4 # vi:si:et:sw=4:sts=4:ts=4
from __future__ import division from __future__ import division
import os
import re
import ox
from ox.utils import json 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.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): def getText(request):
''' '''
param data param data {
string id id: textid
}
return page return {
id:
text:
...
}
''' '''
response = json_response({}) response = json_response()
itemId = json.loads(request.POST['data']) data = json.loads(request.POST['data'])
item = get_object_or_404_json(models.Text, pk=itemId) public_id = data['id']
response['data']['page'] = item.html() 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) return render_to_json_response(response)
actions.register(getText) actions.register(getText)
@ -29,22 +98,355 @@ actions.register(getText)
@login_required_json @login_required_json
def editText(request): def editText(request):
''' '''
param data param data {
string id id:
text:
return page public: boolean
}
return {
id:
text:
...
}
''' '''
response = json_response({}) response = json_response()
itemId = json.loads(request.POST['data']) data = json.loads(request.POST['data'])
item = get_object_or_404_json(models.Text, pk=itemId) if data['id']:
response['data']['page'] = item.html() 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) return render_to_json_response(response)
actions.register(editText, cache=False) 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) 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'^api/?$', include(ox.django.api.urls)),
(r'^resetUI$', 'user.views.reset_ui'), (r'^resetUI$', 'user.views.reset_ui'),
(r'^list/(?P<id>.*?)/icon(?P<size>\d*).jpg$', 'itemlist.views.icon'), (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'^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'^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'), (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 ox.utils import json
from itemlist.models import List, Position from itemlist.models import List, Position
import text
import managers import managers
import tasks import tasks
@ -262,6 +263,29 @@ def get_ui(user_ui, user=None):
ids.append(id) ids.append(id)
return ids 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 = [''] ids = ['']
if user: if user:
ids += add(user.lists.exclude(status="featured"), 'personal') 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(): for i in ui['lists'].keys():
if i not in ids: if i not in ids:
del ui['lists'][i] 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 return ui
def init_user(user, request=None): def init_user(user, request=None):

View file

@ -54,102 +54,106 @@ pandora.UI = (function() {
self.previousUI = Ox.clone(pandora.user.ui, true); self.previousUI = Ox.clone(pandora.user.ui, true);
self.previousUI._list = pandora.getListState(self.previousUI.find); self.previousUI._list = pandora.getListState(self.previousUI.find);
if (args.section == 'texts') {
if ('find' in args) { trigger['section'] = args['section'];
// the challenge here is that find may change list, trigger['text'] = args['text'];
// and list may then change listSort and listView,
// which we don't want to trigger, since find triggers
// (values we put in add will be changed, but won't trigger)
list = pandora.getListState(args.find);
pandora.user.ui._list = list;
pandora.user.ui._filterState = pandora.getFilterState(args.find);
pandora.user.ui._findState = pandora.getFindState(args.find);
if (pandora.$ui.appPanel && !pandora.stayInItemView) {
// if we're not on page load, and if find isn't a context change
// caused by an edit, then switch from item view to list view
args['item'] = '';
}
if (list != self.previousUI._list) {
Ox.Log('UI', 'FIND HAS CHANGED LIST')
// if find has changed list
Ox.forEach(listSettings, function(listSetting, setting) {
// then for each setting that corresponds to a list setting
if (!pandora.user.ui.lists[list]) {
// either add the default setting
add[setting] = pandora.site.user.ui[setting];
} else {
// or the existing list setting
add[setting] = pandora.user.ui.lists[list][listSetting]
}
});
}
add.itemFind = pandora.getItemFind(args.find);
} else { } else {
list = self.previousUI._list; if ('find' in args) {
} // the challenge here is that find may change list,
// it is important to check for find first, so that // and list may then change listSort and listView,
// if find changes list, list is correct here // which we don't want to trigger, since find triggers
item = args.item || pandora.user.ui.item; // (values we put in add will be changed, but won't trigger)
listView = add.listView || args.listView; list = pandora.getListState(args.find);
pandora.user.ui._list = list;
if (listView) { pandora.user.ui._filterState = pandora.getFilterState(args.find);
if (pandora.isClipView(listView)) { pandora.user.ui._findState = pandora.getFindState(args.find);
// when switching to a clip view, clear list selection if (pandora.$ui.appPanel && !pandora.stayInItemView) {
// (but don't trigger an additional event) // if we're not on page load, and if find isn't a context change
add.listSelection = []; // caused by an edit, then switch from item view to list view
} else if (['text', 'position'].indexOf(pandora.user.ui.listSort[0].key) > -1) { args['item'] = '';
// when switching to a non-clip view, with a sort key }
// that only exists in clip view, reset sort to default if (list != self.previousUI._list) {
args.listSort = pandora.site.user.ui.listSort; Ox.Log('UI', 'FIND HAS CHANGED LIST')
// if find has changed list
Ox.forEach(listSettings, function(listSetting, setting) {
// then for each setting that corresponds to a list setting
if (!pandora.user.ui.lists[list]) {
// either add the default setting
add[setting] = pandora.site.user.ui[setting];
} else {
// or the existing list setting
add[setting] = pandora.user.ui.lists[list][listSetting]
}
});
}
add.itemFind = pandora.getItemFind(args.find);
} else {
list = self.previousUI._list;
} }
} // it is important to check for find first, so that
// if find changes list, list is correct here
item = args.item || pandora.user.ui.item;
listView = add.listView || args.listView;
if (!pandora.user.ui.lists[list]) { if (listView) {
add['lists.' + that.encode(list)] = {}; if (pandora.isClipView(listView)) {
} // when switching to a clip view, clear list selection
Ox.forEach(listSettings, function(listSetting, setting) { // (but don't trigger an additional event)
// for each setting that corresponds to a list setting add.listSelection = [];
// set that list setting to } else if (['text', 'position'].indexOf(pandora.user.ui.listSort[0].key) > -1) {
var key = 'lists.' + that.encode(list) + '.' + listSetting; // when switching to a non-clip view, with a sort key
if (setting in args) { // that only exists in clip view, reset sort to default
// the setting passed to UI.set args.listSort = pandora.site.user.ui.listSort;
add[key] = args[setting]; }
} else if (setting in add) {
// or the setting changed via find
add[key] = add[setting];
} else if (!pandora.user.ui.lists[list]) {
// or the default setting
add[key] = pandora.site.user.ui[setting];
} }
});
if (args.item) { if (!pandora.user.ui.lists[list]) {
// when switching to an item, update list selection add['lists.' + that.encode(list)] = {};
add['listSelection'] = [args.item];
add['lists.' + that.encode(list) + '.selection'] = [args.item];
if (
!args.itemView
&& ['timeline', 'player', 'editor'].indexOf(pandora.user.ui.itemView) > -1
&& !pandora.user.ui.videoPoints[item]
&& !args['videoPoints.' + item]
) {
// if the item view doesn't change, remains a video view,
// video points don't exist yet, and won't be set,
// add default video points
add['videoPoints.' + item] = {annotation: '', 'in': 0, out: 0, position: 0};
} }
} Ox.forEach(listSettings, function(listSetting, setting) {
// for each setting that corresponds to a list setting
// set that list setting to
var key = 'lists.' + that.encode(list) + '.' + listSetting;
if (setting in args) {
// the setting passed to UI.set
add[key] = args[setting];
} else if (setting in add) {
// or the setting changed via find
add[key] = add[setting];
} else if (!pandora.user.ui.lists[list]) {
// or the default setting
add[key] = pandora.site.user.ui[setting];
}
});
if (['timeline', 'player', 'editor'].indexOf(args.itemView) > -1) { if (args.item) {
// when switching to a video view, add it as default video view // when switching to an item, update list selection
args.videoView = args.itemView; add['listSelection'] = [args.item];
if ( add['lists.' + that.encode(list) + '.selection'] = [args.item];
!pandora.user.ui.videoPoints[item] if (
&& !args['videoPoints.' + item] !args.itemView
) { && ['timeline', 'player', 'editor'].indexOf(pandora.user.ui.itemView) > -1
// if video points don't exist yet, and won't be set, && !pandora.user.ui.videoPoints[item]
// add default video points && !args['videoPoints.' + item]
add['videoPoints.' + item] = {annotation: '', 'in': 0, out: 0, position: 0}; ) {
// if the item view doesn't change, remains a video view,
// video points don't exist yet, and won't be set,
// add default video points
add['videoPoints.' + item] = {annotation: '', 'in': 0, out: 0, position: 0};
}
}
if (['timeline', 'player', 'editor'].indexOf(args.itemView) > -1) {
// when switching to a video view, add it as default video view
args.videoView = args.itemView;
if (
!pandora.user.ui.videoPoints[item]
&& !args['videoPoints.' + item]
) {
// if video points don't exist yet, and won't be set,
// add default video points
add['videoPoints.' + item] = {annotation: '', 'in': 0, out: 0, position: 0};
}
} }
} }

View file

@ -16,17 +16,18 @@ pandora.URL = (function() {
var state = {}; var state = {};
state.type = pandora.site.itemsSection; 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)];
state.item = pandora.user.ui.item; if(pandora.user.ui.section == 'items') {
if (!pandora.user.ui.item) {
if (!pandora.user.ui.item) { state.view = pandora.user.ui.listView;
state.view = pandora.user.ui.listView; state.sort = pandora.user.ui.listSort;
state.sort = pandora.user.ui.listSort; state.find = pandora.user.ui.find;
state.find = pandora.user.ui.find; } else {
} else { state.view = pandora.user.ui.itemView;
state.view = pandora.user.ui.itemView; state.sort = pandora.user.ui.itemSort;
state.sort = pandora.user.ui.itemSort; }
} }
if (state.view == 'map') { if (state.view == 'map') {
@ -79,56 +80,58 @@ pandora.URL = (function() {
var set = { var set = {
section: state.type == pandora.site.itemsSection ? 'items' : state.type, section: state.type == pandora.site.itemsSection ? 'items' : state.type,
item: state.item,
page: '' page: ''
}; };
set[set.section.slice(0, -1)] = state.item;
if (state.view) { if (set.section == 'items') {
set[!state.item ? 'listView' : 'itemView'] = state.view; if (state.view) {
} set[!state.item ? 'listView' : 'itemView'] = state.view;
if (state.span) {
if (['timeline', 'player', 'editor'].indexOf(state.view) > -1) {
if (Ox.isArray(state.span)) {
set['videoPoints.' + state.item] = {
annotation: '',
'in': state.span[state.span.length - 2] || 0,
out: state.span.length == 1 ? 0 : Math.max(
state.span[state.span.length - 2],
state.span[state.span.length - 1]
),
position: state.span[0]
};
} else {
set['videoPoints.' + state.item + '.annotation'] = state.span;
}
} else if (state.view == 'map') {
// fixme: this doesn't handle map coordinates
if (state.span[0] != '@') {
//pandora.user.ui.mapSelection = state.span;
set['mapSelection'] = state.span;
set['mapFind'] = '';
} else {
//pandora.user.ui.mapFind = state.span.slice(1);
set['mapFind'] = state.span.slice(1);
set['mapSelection'] = '';
}
} else if (state.view == 'calendar') {
// ...
} }
}
if (state.sort) { if (state.span) {
set[!state.item ? 'listSort' : 'itemSort'] = state.sort; if (['timeline', 'player', 'editor'].indexOf(state.view) > -1) {
} if (Ox.isArray(state.span)) {
set['videoPoints.' + state.item] = {
annotation: '',
'in': state.span[state.span.length - 2] || 0,
out: state.span.length == 1 ? 0 : Math.max(
state.span[state.span.length - 2],
state.span[state.span.length - 1]
),
position: state.span[0]
};
} else {
set['videoPoints.' + state.item + '.annotation'] = state.span;
}
} else if (state.view == 'map') {
// fixme: this doesn't handle map coordinates
if (state.span[0] != '@') {
//pandora.user.ui.mapSelection = state.span;
set['mapSelection'] = state.span;
set['mapFind'] = '';
} else {
//pandora.user.ui.mapFind = state.span.slice(1);
set['mapFind'] = state.span.slice(1);
set['mapSelection'] = '';
}
} else if (state.view == 'calendar') {
// ...
}
}
if (!state.item) { if (state.sort) {
if (state.find) { set[!state.item ? 'listSort' : 'itemSort'] = state.sort;
set.find = state.find; }
} else if (!pandora.$ui.appPanel) {
// when loading results without find, clear find, so that if (!state.item) {
// removing a query and reloading works as expected if (state.find) {
set.find = pandora.site.user.ui.find; set.find = state.find;
} else if (!pandora.$ui.appPanel) {
// when loading results without find, clear find, so that
// removing a query and reloading works as expected
set.find = pandora.site.user.ui.find;
}
} }
} }
@ -246,6 +249,19 @@ pandora.URL = (function() {
calendar: 'date' 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); findKeys = [{id: 'list', type: 'string'}].concat(pandora.site.itemKeys);

View file

@ -12,7 +12,11 @@ pandora.ui.allItems = function() {
.on({ .on({
click: function() { click: function() {
that.gainFocus(); that.gainFocus();
pandora.user.ui._list && pandora.UI.set('find', {conditions: [], operator: '&'}); 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({ .bindEvent({
@ -33,35 +37,38 @@ pandora.ui.allItems = function() {
overflow: 'hidden', overflow: 'hidden',
whiteSpace: 'nowrap' whiteSpace: 'nowrap'
}) })
.html('All ' + pandora.site.itemName.plural) .html(pandora.user.ui.section == 'items' ? 'All ' + pandora.site.itemName.plural
.appendTo(that), : pandora.site.site.name + ' ' + Ox.toTitleCase(pandora.user.ui.section))
$items = $('<div>')
.css({
float: 'left',
width: '42px',
margin: '1px 4px 1px 3px',
textAlign: 'right'
})
.appendTo(that),
$clickButton = Ox.Button({
style: 'symbol',
title: 'click',
type: 'image'
})
.css({opacity: 0.25})
.appendTo(that),
$uploadButton = Ox.Button({
style: 'symbol',
title: 'upload',
type: 'image'
})
.appendTo(that); .appendTo(that);
pandora.api.find({ if (pandora.user.ui.section == 'items') {
query: {conditions: [], operator: '&'} var $items = $('<div>')
}, function(result) { .css({
that.update(result.data.items); float: 'left',
}); width: '42px',
margin: '1px 4px 1px 3px',
textAlign: 'right'
})
.appendTo(that),
$clickButton = Ox.Button({
style: 'symbol',
title: 'click',
type: 'image'
})
.css({opacity: 0.25})
.appendTo(that),
$uploadButton = Ox.Button({
style: 'symbol',
title: 'upload',
type: 'image'
})
.appendTo(that);
pandora.api.find({
query: {conditions: [], operator: '&'}
}, function(result) {
that.update(result.data.items);
});
}
that.update = function(items) { that.update = function(items) {
$items.html(Ox.formatNumber(items)); $items.html(Ox.formatNumber(items));

View file

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

View file

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

View file

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

View file

@ -1,382 +1,386 @@
// vim: et:ts=4:sw=4:sts=4:ft=javascript // vim: et:ts=4:sw=4:sts=4:ft=javascript
'use strict'; '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],
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);
},
format: function(value, data) {
return $('<img>').attr({
src: '/list/' + data.id + '/icon.jpg'
}).css({
width: '14px',
height: '14px',
borderRadius: '4px',
margin: '0 0 0 -3px'
});
},
id: 'user',
operator: '+',
tooltip: function(data) {
return data.user == pandora.user.username
|| (id == 'featured' && canEditFeaturedLists)
? 'Edit Icon'
: '';
},
visible: true,
width: 16
},
{
format: function(value) {
return Ox.encodeHTMLEntities(value.split(':').join(': '));
},
id: 'id',
operator: '+',
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
},
{
editable: function(data) {
return data.user == pandora.user.username;
},
format: function(value) {
return Ox.encodeHTMLEntities(value);
},
id: 'name',
input: {
autovalidate: pandora.ui.autovalidateListname
},
operator: '+',
tooltip: id == 'personal' ? 'Edit Title' : '',
unformat: function(value) {
return Ox.decodeHTMLEntities(value);
},
visible: id != 'favorite',
width: pandora.user.ui.sidebarWidth - 96
},
{
align: 'right',
id: 'items',
format: {type: 'number'},
operator: '-',
visible: true,
width: 48
},
{
clickable: function(data) {
return data.type == 'smart' || data.user == pandora.user.username;
},
format: function(value, data) {
return $('<img>')
.attr({
src: Ox.UI.getImageURL(value == 'static' ? 'symbolClick' : 'symbolFind')
})
.css({
width: '10px',
height: '10px',
padding: '3px',
opacity: data.user == pandora.user.username ? 1 : 0.25
});
},
id: 'type',
operator: '+',
tooltip: function(data) {
return data.type == 'smart'
? (data.user == pandora.user.username ? 'Edit Query' : 'Show Query')
: (data.user == pandora.user.username ? 'Edit Default View' : 'Default View: ...');
},
visible: true,
width: 16
},
{
clickable: id == 'personal',
format: function(value) {
var symbols = {personal: 'Publish', favorite: 'Like', featured: 'Star'};
return $('<img>')
.attr({
src: Ox.UI.getImageURL(
'symbol' + symbols[id]
)
})
.css({
width: '10px',
height: '10px',
padding: '3px',
opacity: value == 'private' ? 0.25 : 1
});
},
id: 'status',
operator: '+',
tooltip: id == 'personal' ? function(data) {
return data.status == 'private' ? 'Make Public' : 'Make Private';
} : null,
visible: true,
width: 16
}
];
items = function(data, callback) {
var query;
if (id == 'personal') {
query = {conditions: [
{key: 'user', value: pandora.user.username, operator: '=='},
{key: 'status', value: 'featured', operator: '!='}
], operator: '&'};
} else if (id == 'favorite') {
query = {conditions: [
{key: 'subscribed', value: true, operator: '='},
{key: 'status', value: 'featured', operator: '!='}
], operator: '&'};
} else if (id == 'featured') {
query = {conditions: [
{key: 'status', value: 'featured', operator: '='} // fixme: '==' performs better
], operator: '&'};
}
return pandora.api.findLists(Ox.extend(data, {
query: query
}), callback);
};
} else {
columns = [
{
format: function() {
return $('<img>').attr({
src: Ox.UI.getImageURL('symbolVolume')
}).css({
width: '10px',
height: '10px',
padding: '3px'
});
},
id: 'user',
operator: '+',
visible: true,
width: 16
},
{
editable: true,
id: 'name',
operator: '+',
tooltip: 'Edit Title',
visible: true,
width: pandora.user.ui.sidebarWidth - 96
},
{
align: 'right',
id: 'items',
format: {type: 'number'},
operator: '-',
visible: true,
width: 48
},
{
clickable: function(data) {
return data.mounted;
},
format: function(value, data) {
return $('<img>')
.attr({
src: Ox.UI.getImageURL(data.mounted ? 'symbolSync' : 'symbolEdit')
})
.css({
width: '10px',
height: '10px',
padding: '3px'
});
},
id: 'path',
operator: '+',
tooltip: function(data) {
return data.mounted ? 'Scan Volume' : 'Edit Path';
},
visible: true,
width: 16
},
{
clickable: true,
format: function(value, data) {
return $('<img>')
.attr({
src: Ox.UI.getImageURL('symbolMount')
})
.css({
width: '10px',
height: '10px',
padding: '3px 2px 1px 2px',
opacity: data.mounted ? 1 : 0.25
});
},
id: 'mounted',
operator: '+',
tooltip: function(data) {
return data.mounted ? 'Unmount Volume' : 'Mount Volume';
},
visible: true,
width: 16
}
];
items = function(data, callback) {
var volumes = pandora.user.volumes || [];
if (!data.keys) {
data = {items: volumes.length};
} else {
data = {items: volumes.map(function(volume) {
return Ox.extend({id: volume.name, user: pandora.user.username}, volume);
})};
}
// fixme: ridiculous (we're binding to init too late)
setTimeout(function() {
callback({data: data});
}, 1000);
};
}
that = Ox.TableList({
columns: columns,
items: items,
keys: ['query'],
max: 1,
min: 0,
pageLength: 1000,
//selected: pandora.getListData().folder == id ? [pandora.user.ui._list] : [],
sort: [{key: 'position', operator: '+'}],
sortable: id != 'featured' || canEditFeaturedLists,
unique: id != 'volumes' ? 'id' : 'name'
})
.css({
left: 0,
top: 0,
width: pandora.user.ui.sidebarWidth + 'px'
})
.bindEvent({
add: function(event) {
// fixme: this is duplicated,
// see folder collapse panel menu handler
var i = ['personal', 'favorite', 'featured'].indexOf(id);
if (id == 'personal') {
if (event.keys == '' || event.keys == 'alt') {
pandora.api.addList({
name: 'Untitled',
status: 'private',
type: event.keys == '' ? 'static' : 'smart'
}, function(result) {
var id = result.data.id;
pandora.UI.set({
find: {
conditions: [{key: 'list', value: id, operator: '=='}],
operator: '&'
}
});
Ox.Request.clearCache(); // fixme: remove
that.reloadList().bindEventOnce({
load: function(data) {
that.gainFocus()
.options({selected: [id]})
.editCell(id, 'name');
}
});
});
}
} else if (id == 'favorite' || (id == 'featured' && canEditFeaturedLists)) {
// this makes the button trigger a change event,
// which is already being handled in folders.js
pandora.$ui.manageListsButton[id].options({value: true});
/*
if (!pandora.site.sectionFolders.items[i].showBrowser) {
pandora.site.sectionFolders.items[i].showBrowser = true;
pandora.$ui.manageListsButton[id].options({selected: true});
pandora.$ui.folderList[id].replaceWith(
pandora.$ui.folderBrowser[id] = pandora.ui.folderBrowser(id)
);
}
*/
}
},
click: function(data) {
//var $list = pandora.$ui.folderList[id];
if (data.key == 'user') {
pandora.$ui.listDialog = pandora.ui.listDialog('icon').open();
} else if (data.key == 'type') {
if (that.value(data.id, 'type') == 'smart') {
pandora.$ui.listDialog = pandora.ui.listDialog('query').open();
}
} else if (data.key == 'status') {
var status = that.value(data.id, data.key) == 'private' ? 'public' : 'private';
pandora.changeListStatus(data.id, status, function(result) {
that.value(result.data.id, 'status', result.data.status);
});
} else if (data.key == 'path') {
} else if (data.key == 'mounted') { pandora.ui.folderList = function(id) {
alert(JSON.stringify(data)); 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;
var columns, items;
if (id != 'volumes') {
columns = [
{
clickable: function(data) {
return data.user == pandora.user.username || (id == 'featured' && canEditFeatured);
},
format: function(value, data) {
return $('<img>').attr({
src: '/' + folderItem.toLowerCase() + '/' + data.id + '/icon.jpg'
}).css({
width: '14px',
height: '14px',
borderRadius: '4px',
margin: '0 0 0 -3px'
});
},
id: 'user',
operator: '+',
tooltip: function(data) {
return data.user == pandora.user.username
|| (id == 'featured' && canEditFeatured)
? 'Edit Icon'
: '';
},
visible: true,
width: 16
}, },
'delete': function(data) { {
if (id == 'personal') { format: function(value) {
pandora.ui.deleteListDialog(data.ids[0]).open(); return Ox.encodeHTMLEntities(value.split(':').join(': '));
} else if (id == 'favorite') { },
that.options({selected: []}); id: 'id',
pandora.api.unsubscribeFromList({ operator: '+',
id: data.ids[0] visible: id == 'favorite',
// fixme: user and name are set to the same width here,
// but resizeFolders will set them to different widths
width: ui.sidebarWidth - 96
},
{
editable: function(data) {
return data.user == pandora.user.username;
},
format: function(value) {
return Ox.encodeHTMLEntities(value);
},
id: 'name',
input: {
autovalidate: pandora.ui.autovalidateListname
},
operator: '+',
tooltip: id == 'personal' ? 'Edit Title' : '',
unformat: function(value) {
return Ox.decodeHTMLEntities(value);
},
visible: id != 'favorite',
width: ui.sidebarWidth - 96
},
{
align: 'right',
id: 'items',
format: {type: 'number'},
operator: '-',
visible: true,
width: 48
},
{
clickable: function(data) {
return data.type == 'smart' || data.user == pandora.user.username;
},
format: function(value, data) {
return $('<img>')
.attr({
src: Ox.UI.getImageURL(value == 'smart' ? 'symbolFind' : value == 'pdf' ? 'symbolFiles' : value == 'html' ? 'symbolFile' : 'symbolClick')
})
.css({
width: '10px',
height: '10px',
padding: '3px',
opacity: data.user == pandora.user.username ? 1 : 0.25
});
},
id: 'type',
operator: '+',
tooltip: function(data) {
return data.type == 'smart'
? (data.user == pandora.user.username ? 'Edit Query' : 'Show Query')
: (data.user == pandora.user.username ? 'Edit Default View' : 'Default View: ...');
},
visible: true,
width: 16
},
{
clickable: id == 'personal',
format: function(value) {
var symbols = {personal: 'Publish', favorite: 'Like', featured: 'Star'};
return $('<img>')
.attr({
src: Ox.UI.getImageURL(
'symbol' + symbols[id]
)
})
.css({
width: '10px',
height: '10px',
padding: '3px',
opacity: value == 'private' ? 0.25 : 1
});
},
id: 'status',
operator: '+',
tooltip: id == 'personal' ? function(data) {
return data.status == 'private' ? 'Make Public' : 'Make Private';
} : null,
visible: true,
width: 16
}
];
items = function(data, callback) {
var query;
if (id == 'personal') {
query = {conditions: [
{key: 'user', value: pandora.user.username, operator: '=='},
{key: 'status', value: 'featured', operator: '!='}
], operator: '&'};
} else if (id == 'favorite') {
query = {conditions: [
{key: 'subscribed', value: true, operator: '='},
{key: 'status', value: 'featured', operator: '!='}
], operator: '&'};
} else if (id == 'featured') {
query = {conditions: [
{key: 'status', value: 'featured', operator: '='} // fixme: '==' performs better
], operator: '&'};
}
return pandora.api['find' + folderItems](Ox.extend(data, {
query: query
}), callback);
};
} else {
columns = [
{
format: function() {
return $('<img>').attr({
src: Ox.UI.getImageURL('symbolVolume')
}).css({
width: '10px',
height: '10px',
padding: '3px'
});
},
id: 'user',
operator: '+',
visible: true,
width: 16
},
{
editable: true,
id: 'name',
operator: '+',
tooltip: 'Edit Title',
visible: true,
width: ui.sidebarWidth - 96
},
{
align: 'right',
id: 'items',
format: {type: 'number'},
operator: '-',
visible: true,
width: 48
},
{
clickable: function(data) {
return data.mounted;
},
format: function(value, data) {
return $('<img>')
.attr({
src: Ox.UI.getImageURL(data.mounted ? 'symbolSync' : 'symbolEdit')
})
.css({
width: '10px',
height: '10px',
padding: '3px'
});
},
id: 'path',
operator: '+',
tooltip: function(data) {
return data.mounted ? 'Scan Volume' : 'Edit Path';
},
visible: true,
width: 16
},
{
clickable: true,
format: function(value, data) {
return $('<img>')
.attr({
src: Ox.UI.getImageURL('symbolMount')
})
.css({
width: '10px',
height: '10px',
padding: '3px 2px 1px 2px',
opacity: data.mounted ? 1 : 0.25
});
},
id: 'mounted',
operator: '+',
tooltip: function(data) {
return data.mounted ? 'Unmount Volume' : 'Mount Volume';
},
visible: true,
width: 16
}
];
items = function(data, callback) {
var volumes = pandora.user.volumes || [];
if (!data.keys) {
data = {items: volumes.length};
} else {
data = {items: volumes.map(function(volume) {
return Ox.extend({id: volume.name, user: pandora.user.username}, volume);
})};
}
// fixme: ridiculous (we're binding to init too late)
setTimeout(function() {
callback({data: data});
}, 1000);
};
}
that = Ox.TableList({
columns: columns,
items: items,
keys: ui.section == 'items' ? ['query'] : [],
max: 1,
min: 0,
pageLength: 1000,
//selected: pandora.getListData().folder == id ? [ui._list] : [],
sort: [{key: 'position', operator: '+'}],
sortable: id != 'featured' || canEditFeatured,
unique: id != 'volumes' ? 'id' : 'name'
})
.css({
left: 0,
top: 0,
width: ui.sidebarWidth + 'px'
})
.bindEvent({
add: function(event) {
// fixme: this is duplicated,
// see folder collapse panel menu handler
var i = ['personal', 'favorite', 'featured'].indexOf(id);
if (id == 'personal') {
if (event.keys == '' || event.keys == 'alt') {
pandora.api.addList({
name: 'Untitled',
status: 'private',
type: event.keys == '' ? 'static' : 'smart'
}, function(result) { }, function(result) {
var id = result.data.id;
pandora.UI.set({
find: {
conditions: [{key: 'list', value: id, operator: '=='}],
operator: '&'
}
});
Ox.Request.clearCache(); // fixme: remove Ox.Request.clearCache(); // fixme: remove
that.reloadList(); that.reloadList().bindEventOnce({
}); load: function(data) {
} else if (id == 'featured' && canEditFeaturedLists) { that.gainFocus()
that.options({selected: []}); .options({selected: [id]})
pandora.api.editList({ .editCell(id, 'name');
id: data.ids[0], }
status: 'public' });
}, function(result) {
// fixme: duplicated
if (result.data.user == pandora.user.username || result.data.subscribed) {
Ox.Request.clearCache(); // fixme: remove
pandora.$ui.folderList[
result.data.user == pandora.user.username ? 'personal' : 'favorite'
].reloadList();
}
that.reloadList();
}); });
} }
}, } else if (id == 'favorite' || (id == 'featured' && canEditFeatured)) {
/* // this makes the button trigger a change event,
edit: function() { // which is already being handled in folders.js
pandora.ui.listDialog().open(); pandora.$ui.manageListsButton[id].options({value: true});
}, /*
*/ if (!pandora.site.sectionFolders.items[i].showBrowser) {
init: function(data) { pandora.site.sectionFolders.items[i].showBrowser = true;
pandora.site.sectionFolders[pandora.user.ui.section][i].items = data.items; pandora.$ui.manageListsButton[id].options({selected: true});
pandora.$ui.folder[i].$content.css({ pandora.$ui.folderList[id].replaceWith(
height: data.items * 16 + 'px' pandora.$ui.folderBrowser[id] = pandora.ui.folderBrowser(id)
}); );
pandora.$ui.folderList[id].css({
height: data.items * 16 + 'px'
});
pandora.resizeFolders();
},
move: function(data) {
pandora.api.sortLists({
section: id,
ids: data.ids
});
},
paste: function(data) {
pandora.$ui.list.triggerEvent('paste', data);
},
select: function(data) {
var list = data.ids.length ? data.ids[0] : '';
if (list) {
Ox.forEach(pandora.$ui.folderList, function($list, id_) {
id != id_ && $list.options('selected', []);
});
} }
*/
}
},
click: function(data) {
//var $list = pandora.$ui.folderList[id];
if (data.key == 'user') {
pandora.$ui.listDialog = pandora.ui.listDialog('icon').open();
} else if (data.key == 'type') {
if (that.value(data.id, 'type') == 'smart') {
pandora.$ui.listDialog = pandora.ui.listDialog('query').open();
}
} else if (data.key == 'status') {
var status = that.value(data.id, data.key) == 'private' ? 'public' : 'private';
pandora.changeFolderItemStatus(data.id, status, function(result) {
that.value(result.data.id, 'status', result.data.status);
});
} else if (data.key == 'path') {
} else if (data.key == 'mounted') {
alert(JSON.stringify(data));
}
},
'delete': function(data) {
if (id == 'personal') {
pandora.ui.deleteListDialog(data.ids[0]).open();
} else if (id == 'favorite') {
that.options({selected: []});
pandora.api['unsubscribeFrom' + folderItem]({
id: data.ids[0]
}, function(result) {
Ox.Request.clearCache(); // fixme: remove
that.reloadList();
});
} else if (id == 'featured' && canEditFeatured) {
that.options({selected: []});
pandora.api['edit' + folderItem]({
id: data.ids[0],
status: 'public'
}, function(result) {
// fixme: duplicated
if (result.data.user == pandora.user.username || result.data.subscribed) {
Ox.Request.clearCache(); // fixme: remove
pandora.$ui.folderList[
result.data.user == pandora.user.username ? 'personal' : 'favorite'
].reloadList();
}
that.reloadList();
});
}
},
/*
edit: function() {
pandora.ui.listDialog().open();
},
*/
init: function(data) {
pandora.site.sectionFolders[ui.section][i].items = data.items;
pandora.$ui.folder[i].$content.css({
height: data.items * 16 + 'px'
});
pandora.$ui.folderList[id].css({
height: data.items * 16 + 'px'
});
pandora.resizeFolders();
},
move: function(data) {
pandora.api['sort' + foldeItem]({
section: id,
ids: data.ids
});
},
paste: function(data) {
pandora.$ui.list.triggerEvent('paste', data);
},
select: function(data) {
var list = data.ids.length ? data.ids[0] : '';
if (list) {
Ox.forEach(pandora.$ui.folderList, function($list, id_) {
id != id_ && $list.options('selected', []);
});
}
if (ui.section == 'items') {
pandora.UI.set({ pandora.UI.set({
find: { find: {
conditions: list ? [ conditions: list ? [
@ -385,18 +389,20 @@ pandora.ui.folderList = function(id) {
operator: '&' operator: '&'
} }
}); });
}, } else {
submit: function(data) { pandora.UI.set(ui.section.slice(0, -1), list);
var data_ = {id: data.id};
data_[data.key] = data.value;
pandora.api.editList(data_, function(result) {
if (result.data.id != data.id) {
pandora.renameList(data.id, result.data.id, result.data.name, id);
pandora.$ui.info.updateListInfo();
}
});
} }
}); },
} submit: function(data) {
var data_ = {id: data.id};
data_[data.key] = data.value;
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();
}
});
}
});
return that; return that;
}; };

View file

@ -7,7 +7,9 @@ pandora.ui.folders = function() {
.css({overflowX: 'hidden', overflowY: 'auto'}) .css({overflowX: 'hidden', overflowY: 'auto'})
.bindEvent({ .bindEvent({
resize: pandora.resizeFolders resize: pandora.resizeFolders
}); }),
folderItems = ui.section == 'items' ? 'Lists' : Ox.toTitleCase(ui.section),
folderItem = folderItems.slice(0, -1);
//var $sections = []; //var $sections = [];
pandora.$ui.allItems = pandora.ui.allItems().appendTo(that); pandora.$ui.allItems = pandora.ui.allItems().appendTo(that);
@ -18,15 +20,17 @@ pandora.ui.folders = function() {
pandora.$ui.findListSelect = {}; pandora.$ui.findListSelect = {};
pandora.$ui.findListInput = {}; pandora.$ui.findListInput = {};
pandora.$ui.manageListsButton = {}; pandora.$ui.manageListsButton = {};
if (ui.section == 'items') { pandora.site.sectionFolders[ui.section].forEach(function(folder, i) {
pandora.site.sectionFolders.items.forEach(function(folder, i) { var extras, $select;
var extras, $select; if (folder.id == 'personal') {
if (folder.id == 'personal') { if (pandora.user.level == 'guest') {
if (pandora.user.level == 'guest') { extras = [
extras = [ infoButton('Personal ' + folderItems, 'To create and share your own ' + (ui.section == 'items'
infoButton('Personal Lists', 'To create and share your own lists of movies, please sign up or sign in.') ? 'lists of ' + pandora.site.itemName.plural.toLowerCase()
]; : ui.section) + ', please sign up or sign in.')
} else { ];
} else {
if (ui.section == 'items') {
extras = [ extras = [
pandora.$ui.personalListsMenu = Ox.MenuButton({ pandora.$ui.personalListsMenu = Ox.MenuButton({
items: [ items: [
@ -78,195 +82,225 @@ pandora.ui.folders = function() {
} }
}) })
]; ];
}
} 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.')];
} else { } else {
extras = [pandora.$ui.manageListsButton['favorite'] = Ox.Button({ extras = [
selectable: true, pandora.$ui.personalListsMenu = Ox.MenuButton({
style: 'symbol', items: [
title: 'Edit', { id: 'new' + folderItem.toLowerCase(), title: 'New ' + folderItem },
tooltip: 'Manage Favorite Lists', {},
type: 'image' { id: 'delete' + folderItem.toLowerCase(), title: 'Delete Selected ' + folderItem + '...', disabled: !ui[ui.section.slice(0,-1)] }
}) ],
.bindEvent({ title: 'edit',
change: function(data) { tooltip: 'Manage Personal ' + folderItems,
var listData; type: 'image'
Ox.Request.clearCache(); // fixme: remove })
pandora.site.sectionFolders.items[i].showBrowser = !pandora.site.sectionFolders.items[i].showBrowser; .bindEvent({
if (pandora.site.sectionFolders.items[i].showBrowser) { click: function(data) {
pandora.$ui.folderList.favorite.replaceWith( var $list = pandora.$ui.folderList[folder.id];
pandora.$ui.folderBrowser.favorite = pandora.ui.folderBrowser('favorite') // fixme: duplicated
); if (data.id == 'new' + folderItem.toLowerCase()) {
} else { pandora['add' + folderItem]();
listData = pandora.getListData(); } else if (data.id == 'delete' + folderItem.toLowerCase()) {
if ( pandora.ui.deleteListDialog().open();
pandora.$ui.folderList.favorite.options('selected').length
&& !listData.subscribed
) {
// 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) {
// but in the featured browser
pandora.$ui.folderList.featured.options({selected: [listData.id]});
} else {
// and nowhere else
pandora.UI.set({
find: pandora.site.user.ui.find
});
}
} }
pandora.$ui.folderBrowser.favorite.replaceWith(
pandora.$ui.folderList.favorite = pandora.ui.folderList('favorite')
);
} }
pandora.resizeFolders(); })
} .bindEvent('pandora_' + ui.section.slice(0,-1), function(data) {
})]; pandora.$ui.personalListsMenu[
} data.value && data.value.length ? 'enableItem' : 'disableItem'
} else if (folder.id == 'featured') { ]('delete' + folderItem.toLowerCase());
if (pandora.user.level != 'admin') { })
extras = [infoButton('Featured Lists', 'Featured lists are selected public lists, 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',
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.$ui.folderList.featured.replaceWith(
pandora.$ui.folderBrowser.featured = pandora.ui.folderBrowser('featured')
);
} else {
listData = pandora.getListData();
Ox.Log('', 'FEATURED', listData)
if (
pandora.$ui.folderList.featured.options('selected').length
&& listData.status != 'featured'
) {
// the selected list in the featured browser is not in the featured folder
pandora.$ui.folderList.featured.options({selected: []});
if (listData.user == pandora.user.username) {
// but in the personal folder
pandora.$ui.folderList.personal.options({selected: [listData.id]});
} else if (
listData.subscribed
|| Ox.getObjectById(pandora.site.sectionFolders.items, 'favorite').showBrowser
) {
// but in the favorites folder or browser
pandora.$ui.folderList.favorite.options({selected: [listData.id]});
} else {
// and nowhere else
pandora.UI.set({
find: pandora.site.user.ui.find
});
}
}
pandora.$ui.folderBrowser.featured.replaceWith(
pandora.$ui.folderList.featured = pandora.ui.folderList('featured')
);
}
pandora.resizeFolders();
}
})];
}
} else if (folder.id == 'volumes') {
if (pandora.user.level == 'guest') {
extras = [infoButton('Local Volumes', 'To import movies from a local disk, please sign up or sign in.')];
} else {
extras = [Ox.MenuButton({
items: [
{ id: 'add', title: 'Add Volume...', disabled: true },
{ id: 'scan', title: 'Scan Selected Volume...', disabled: true },
{ id: 'remove', title: 'Remove Selected Volume...', disabled: true },
{},
{ id: 'import', title: 'Import Movies...', disabled: true }
],
title: 'edit',
tooltip: 'Manage Volumes',
type: 'image'
})
.bindEvent({
click: function(data) {
}
})];
} }
} }
pandora.$ui.folder[i] = Ox.CollapsePanel({ } else if (folder.id == 'favorite') {
id: folder.id, if (pandora.user.level == 'guest') {
collapsed: !ui.showFolder.items[folder.id], extras = [infoButton('Favorite ' + folderItems,
extras: extras, 'To browse and subscribe to shared ' + folderItems.toLowerCase() + ' from other users, please sign up or sign in.')];
size: 16, } else {
title: folder.title extras = [pandora.$ui.manageListsButton['favorite'] = Ox.Button({
selectable: true,
style: 'symbol',
title: 'Edit',
tooltip: 'Manage Favorite ' + folderItems,
type: 'image'
}) })
.bindEvent({ .bindEvent({
// fixme: duplicated change: function(data) {
click: function(data) { var listData;
var $list = pandora.$ui.folderList[i], Ox.Request.clearCache(); // fixme: remove
hasFocus, id; pandora.site.sectionFolders[ui.section][i].showBrowser = !pandora.site.sectionFolders[ui.section][i].showBrowser;
if (data.id == 'new' || data.id == 'newsmart') { if (pandora.site.sectionFolders[ui.section][i].showBrowser) {
pandora.api.addList({ pandora.$ui.folderList.favorite.replaceWith(
name: 'Untitled', pandora.$ui.folderBrowser.favorite = pandora.ui.folderBrowser('favorite')
status: 'private', );
type: data.id == 'new' ? 'static' : 'smart' } else {
}, function(result) { listData = pandora.getListData();
id = result.data.id; if (
pandora.URL.set('?find=list:' + id) pandora.$ui.folderList.favorite.options('selected').length
Ox.Request.clearCache(); // fixme: remove && !listData.subscribed
$list.reloadList().bindEventOnce({ ) {
load: function(data) { // the selected list in the favorites browser is not in the favorites folder
$list.gainFocus() pandora.$ui.folderList.favorite.options({selected: []});
.options({selected: [id]}) if (Ox.getObjectById(pandora.site.sectionFolders[ui.section], 'featured').showBrowser) {
.editCell(id, 'name'); // but in the featured browser
} pandora.$ui.folderList.featured.options({selected: [listData.id]});
}); } else {
}); // and nowhere else
} else if (data.id == 'browse') { pandora.UI.set({
// alert('??') find: pandora.site.user.ui.find
/* });
pandora.$ui.sectionList[1].replaceWith(pandora.$ui.publicLists = pandora.ui.publicLists()); }
pandora.site.showAllPublicLists = true; }
*/ pandora.$ui.folderBrowser.favorite.replaceWith(
pandora.$ui.folderList.favorite = pandora.ui.folderList('favorite')
);
} }
},
toggle: function(data) {
data.collapsed && pandora.$ui.folderList[folder.id].loseFocus();
pandora.UI.set('showFolder.items.' + folder.id, !data.collapsed);
pandora.resizeFolders(); pandora.resizeFolders();
} }
}); })];
//$sections.push(pandora.$ui.section[i]); }
pandora.$ui.folderList[folder.id] = pandora.ui.folderList(folder.id) } else if (folder.id == 'featured') {
if (pandora.user.level != 'admin') {
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 ' + folderItems,
type: 'image'
})
.bindEvent({ .bindEvent({
selectafter: function() { change: function(data) {
// ... var listData;
}, Ox.Request.clearCache(); // fixme: remove
selectbefore: function() { 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')
.bindEventOnce({ );
init: function(data) { } else {
if (++counter == 4) { listData = pandora.getListData();
pandora.$ui.folder.forEach(function($folder) { Ox.Log('', 'FEATURED', listData)
that.append($folder); if (
}); pandora.$ui.folderList.featured.options('selected').length
pandora.resizeFolders(); && listData.status != 'featured'
pandora.selectList(); ) {
// the selected list in the featured browser is not in the featured folder
pandora.$ui.folderList.featured.options({selected: []});
if (listData.user == pandora.user.username) {
// but in the personal folder
pandora.$ui.folderList.personal.options({selected: [listData.id]});
} else if (
listData.subscribed
|| Ox.getObjectById(pandora.site.sectionFolders[ui.section], 'favorite').showBrowser
) {
// but in the favorites folder or browser
pandora.$ui.folderList.favorite.options({selected: [listData.id]});
} else {
// and nowhere else
pandora.UI.set({
find: pandora.site.user.ui.find
});
}
}
pandora.$ui.folderBrowser.featured.replaceWith(
pandora.$ui.folderList.featured = pandora.ui.folderList('featured')
);
} }
pandora.resizeFolders();
} }
})];
}
} else if (folder.id == 'volumes') {
if (pandora.user.level == 'guest') {
extras = [infoButton('Local Volumes', 'To import movies from a local disk, please sign up or sign in.')];
} else {
extras = [Ox.MenuButton({
items: [
{ id: 'add', title: 'Add Volume...', disabled: true },
{ id: 'scan', title: 'Scan Selected Volume...', disabled: true },
{ id: 'remove', title: 'Remove Selected Volume...', disabled: true },
{},
{ id: 'import', title: 'Import Movies...', disabled: true }
],
title: 'edit',
tooltip: 'Manage Volumes',
type: 'image'
}) })
.appendTo(pandora.$ui.folder[i].$content); .bindEvent({
}); click: function(data) {
} }
})];
}
}
pandora.$ui.folder[i] = Ox.CollapsePanel({
id: folder.id,
collapsed: !ui.showFolder.items[folder.id],
extras: extras,
size: 16,
title: folder.title
})
.bindEvent({
// fixme: duplicated
click: function(data) {
var $list = pandora.$ui.folderList[i],
hasFocus, id;
if (data.id == 'new' || data.id == 'newsmart') {
pandora.api.addList({
name: 'Untitled',
status: 'private',
type: data.id == 'new' ? 'static' : 'smart'
}, function(result) {
id = result.data.id;
pandora.URL.set('?find=list:' + id)
Ox.Request.clearCache(); // fixme: remove
$list.reloadList().bindEventOnce({
load: function(data) {
$list.gainFocus()
.options({selected: [id]})
.editCell(id, 'name');
}
});
});
} else if (data.id == 'browse') {
// alert('??')
/*
pandora.$ui.sectionList[1].replaceWith(pandora.$ui.publicLists = pandora.ui.publicLists());
pandora.site.showAllPublicLists = true;
*/
}
},
toggle: function(data) {
data.collapsed && pandora.$ui.folderList[folder.id].loseFocus();
pandora.UI.set('showFolder.items.' + folder.id, !data.collapsed);
pandora.resizeFolders();
}
});
//$sections.push(pandora.$ui.section[i]);
pandora.$ui.folderList[folder.id] = pandora.ui.folderList(folder.id)
.bindEvent({
selectafter: function() {
// ...
},
selectbefore: function() {
// ...
}
})
.bindEventOnce({
init: function(data) {
if (++counter == pandora.site.sectionFolders[ui.section].length) {
pandora.$ui.folder.forEach(function($folder) {
that.append($folder);
});
pandora.resizeFolders();
pandora.selectList();
}
}
})
.appendTo(pandora.$ui.folder[i].$content);
});
function infoButton(title, text) { function infoButton(title, text) {
return Ox.Button({ return Ox.Button({
style: 'symbol', 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; return that;

View file

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

View file

@ -5,7 +5,7 @@ pandora.ui.sectionButtons = function() {
buttons: [ buttons: [
{id: 'items', title: pandora.site.itemName.plural}, {id: 'items', title: pandora.site.itemName.plural},
{id: 'edits', title: 'Edits', disabled: true}, {id: 'edits', title: 'Edits', disabled: true},
{id: 'texts', title: 'Texts', disabled: true} {id: 'texts', title: 'Texts', disabled: pandora.user.level != 'admin'}
], ],
id: 'sectionButtons', id: 'sectionButtons',
selectable: true, selectable: true,
@ -17,13 +17,7 @@ pandora.ui.sectionButtons = function() {
.bindEvent({ .bindEvent({
change: function(data) { change: function(data) {
var section = data.value; var section = data.value;
if (section == 'items') { pandora.UI.set({section: section});
pandora.URL.set(pandora.Query.toString());
} else if (section == 'clips') {
pandora.URL.set('clips');
} else if (section == 'texts') {
pandora.URL.set('texts');
}
} }
}); });
return that; 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(); }).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') { if (status == 'private') {
pandora.api.findLists({ pandora.api['find' + folderItems]({
query: {conditions: [{key: 'id', value: id, operator: '=='}]}, query: {conditions: [{key: 'id', value: id, operator: '=='}]},
keys: ['name', 'subscribers'] keys: ['name', 'subscribers']
}, function(result) { }, function(result) {
@ -168,14 +189,14 @@ pandora.changeListStatus = function(id, status, callback) {
} }
}).open(); }).open();
} else { } else {
changeListStatus(); changeFolderItemStatus();
} }
}); });
} else { } else {
changeListStatus(); changeFolderItemStatus();
} }
function changeListStatus() { function changeFolderItemStatus() {
pandora.api.editList({ pandora.api['edit' + folderItem]({
id: id, id: id,
status: status status: status
}, callback); }, callback);
@ -606,42 +627,46 @@ pandora.getInfoHeight = function(includeHidden) {
return height; return height;
} }
pandora.getItemByIdOrTitle = function(str, callback) { pandora.getItemByIdOrTitle = function(type, str, callback) {
var sortKey = Ox.getObjectById(pandora.site.itemKeys, 'votes') if (type == pandora.site.itemName.plural.toLowerCase()) {
? 'votes' var sortKey = Ox.getObjectById(pandora.site.itemKeys, 'votes')
: 'timesaccessed'; ? 'votes'
pandora.api.get({id: str, keys: ['id']}, function(result) { : 'timesaccessed';
if (result.status.code == 200) { pandora.api.get({id: str, keys: ['id']}, function(result) {
callback(result.data.id); if (result.status.code == 200) {
} else { callback(result.data.id);
pandora.api.find({ } else {
query: { pandora.api.find({
conditions: [{key: 'title', value: str, operator: '='}], query: {
operator: '&' conditions: [{key: 'title', value: str, operator: '='}],
}, operator: '&'
sort: [{key: sortKey, operator: ''}], },
range: [0, 100], sort: [{key: sortKey, operator: ''}],
keys: ['id', 'title', sortKey] range: [0, 100],
}, function(result) { keys: ['id', 'title', sortKey]
var id = ''; }, function(result) {
if (result.data.items.length) { var id = '';
var items = Ox.filter(Ox.map(result.data.items, function(item) { if (result.data.items.length) {
// test if exact match or word match var items = Ox.filter(Ox.map(result.data.items, function(item) {
var sort = new RegExp('^' + str + '$', 'i').test(item.title) ? 2000000 // test if exact match or word match
: new RegExp('\\b' + str + '\\b', 'i').test(item.title) ? 1000000 : 0; var sort = new RegExp('^' + str + '$', 'i').test(item.title) ? 2000000
return sort ? {id: item.id, sort: sort + (parseInt(item[sortKey]) || 0)} : null; : new RegExp('\\b' + str + '\\b', 'i').test(item.title) ? 1000000 : 0;
// fixme: remove the (...|| 0) check once the backend sends correct data return sort ? {id: item.id, sort: sort + (parseInt(item[sortKey]) || 0)} : null;
})); // fixme: remove the (...|| 0) check once the backend sends correct data
if (items.length) { }));
id = items.sort(function(a, b) { if (items.length) {
return b.sort - a.sort; id = items.sort(function(a, b) {
})[0].id; return b.sort - a.sort;
})[0].id;
}
} }
} callback(id);
callback(id); });
}); }
} });
}); } else {
callback(str);
}
} }
pandora.getItemFind = function(find) { pandora.getItemFind = function(find) {
@ -706,7 +731,11 @@ pandora.getItemIdAndPosition = function() {
pandora.getListData = function(list) { pandora.getListData = function(list) {
var data = {}, folder; var data = {}, folder;
list = Ox.isUndefined(list) ? pandora.user.ui._list : list; 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) { if (list) {
Ox.forEach(pandora.$ui.folderList, function($list, id) { Ox.forEach(pandora.$ui.folderList, function($list, id) {
var ret = true; var ret = true;
@ -726,8 +755,12 @@ pandora.getListData = function(list) {
// FIXME: Is there a `return ret` statement missing here? // FIXME: Is there a `return ret` statement missing here?
}); });
if (folder) { if (folder) {
data = pandora.$ui.folderList[folder].value(pandora.user.ui._list); data = pandora.$ui.folderList[folder].value(list);
data.editable = data.user == pandora.user.username && data.type == 'static'; 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; data.folder = folder;
} }
} }
@ -1076,24 +1109,28 @@ pandora.renameList = function(oldId, newId, newName, folder) {
folder = folder || pandora.getListData(oldId).folder; folder = folder || pandora.getListData(oldId).folder;
pandora.$ui.folderList[folder].value(oldId, 'name', newName); pandora.$ui.folderList[folder].value(oldId, 'name', newName);
pandora.$ui.folderList[folder].value(oldId, 'id', newId); pandora.$ui.folderList[folder].value(oldId, 'id', newId);
pandora.$ui.toolbar.updateListName(newId); if (pandora.user.ui.section == 'items') {
pandora.UI.set({ pandora.$ui.toolbar.updateListName(newId);
find: { pandora.UI.set({
conditions: [{key: 'list', value: newId, operator: '=='}], find: {
operator: '&' conditions: [{key: 'list', value: newId, operator: '=='}],
} operator: '&'
}, false); }
}, false);
} else {
pandora.UI.set(pandora.user.ui.section.slice(0, -1), newId);
}
}; };
pandora.resizeFilters = function(width) { pandora.resizeFilters = function(width) {
pandora.user.ui.filterSizes = pandora.getFilterSizes(); pandora.user.ui.filterSizes = pandora.getFilterSizes();
pandora.$ui.browser pandora.$ui.browser && pandora.$ui.browser
.size(0, pandora.user.ui.filterSizes[0]) .size(0, pandora.user.ui.filterSizes[0])
.size(2, pandora.user.ui.filterSizes[4]); .size(2, pandora.user.ui.filterSizes[4]);
pandora.$ui.filtersInnerPanel pandora.$ui.filtersInnerPanel && pandora.$ui.filtersInnerPanel
.size(0, pandora.user.ui.filterSizes[1]) .size(0, pandora.user.ui.filterSizes[1])
.size(2, pandora.user.ui.filterSizes[3]); .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); $list.resizeColumn('name', pandora.user.ui.filterSizes[i] - 44 - Ox.UI.SCROLLBAR_SIZE);
if (pandora.user.ui.showFlags) { if (pandora.user.ui.showFlags) {
$list.find('.flagname').css({width: pandora.user.ui.filterSizes[i] - 68 - Ox.UI.SCROLLBAR_SIZE}) $list.find('.flagname').css({width: pandora.user.ui.filterSizes[i] - 68 - Ox.UI.SCROLLBAR_SIZE})
@ -1103,27 +1140,24 @@ pandora.resizeFilters = function(width) {
pandora.resizeFolders = function() { pandora.resizeFolders = function() {
var width = pandora.getFoldersWidth(), var width = pandora.getFoldersWidth(),
columnWidth = {}; columnWidth = {},
if (pandora.user.ui.section == 'items') { sectionWidth = pandora.user.ui.section == 'items'? 96 : 32;
columnWidth = {user: parseInt((width - 96) * 0.4)}; columnWidth = {user: parseInt((width - (sectionWidth)) * 0.4)};
columnWidth.name = (width - 96) - columnWidth.user; columnWidth.name = (width - sectionWidth) - columnWidth.user;
}
Ox.Log('', 'RESIZE FOLDERS', width); Ox.Log('', 'RESIZE FOLDERS', width);
pandora.$ui.allItems.resizeElement(width - 104); pandora.$ui.allItems.resizeElement(width - 104);
Ox.forEach(pandora.$ui.folderList, function($list, id) { Ox.forEach(pandora.$ui.folderList, function($list, id) {
var pos = Ox.getIndexById(pandora.site.sectionFolders[pandora.user.ui.section], id); var pos = Ox.getIndexById(pandora.site.sectionFolders[pandora.user.ui.section], id);
pandora.$ui.folder[pos].css({width: width + 'px'}); pandora.$ui.folder[pos].css({width: width + 'px'});
$list.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) {
if (pandora.site.sectionFolders[pandora.user.ui.section][pos].showBrowser) { pandora.$ui.findListInput[id].options({
pandora.$ui.findListInput[id].options({ width: width - 24
width: width - 24 });
}); $list.resizeColumn('user', columnWidth.user)
$list.resizeColumn('user', columnWidth.user) .resizeColumn('name', columnWidth.name);
.resizeColumn('name', columnWidth.name); } else {
} else { $list.resizeColumn(id == 'favorite' ? 'id' : 'name', width - 96);
$list.resizeColumn(id == 'favorite' ? 'id' : 'name', width - 96);
}
} }
if (!pandora.user.ui.showFolder[pandora.user.ui.section][id]) { if (!pandora.user.ui.showFolder[pandora.user.ui.section][id]) {
pandora.$ui.folder[pos].updatePanel(); pandora.$ui.folder[pos].updatePanel();
@ -1135,88 +1169,105 @@ pandora.resizeWindow = function() {
// FIXME: a lot of this throws errors on load // FIXME: a lot of this throws errors on load
pandora.$ui.leftPanel && pandora.$ui.leftPanel.size(2, pandora.getInfoHeight(true)); pandora.$ui.leftPanel && pandora.$ui.leftPanel.size(2, pandora.getInfoHeight(true));
pandora.resizeFolders(); pandora.resizeFolders();
if (!pandora.user.ui.item) { if (pandora.user.ui.section == 'item') {
pandora.resizeFilters(pandora.$ui.rightPanel.width()); if (!pandora.user.ui.item) {
if (pandora.user.ui.listView == 'clips') { pandora.resizeFilters(pandora.$ui.rightPanel.width());
var clipsItems = pandora.getClipsItems(), if (pandora.user.ui.listView == 'clips') {
previousClipsItems = pandora.getClipsItems(pandora.$ui.list.options('width')); var clipsItems = pandora.getClipsItems(),
pandora.$ui.list.options({ previousClipsItems = pandora.getClipsItems(pandora.$ui.list.options('width'));
width: window.innerWidth pandora.$ui.list.options({
- pandora.user.ui.showSidebar * pandora.user.ui.sidebarSize - 1 width: window.innerWidth
- Ox.UI.SCROLLBAR_SIZE - pandora.user.ui.showSidebar * pandora.user.ui.sidebarSize - 1
}); - Ox.UI.SCROLLBAR_SIZE
if (clipsItems != previousClipsItems) { });
Ox.Request.clearCache(); // fixme if (clipsItems != previousClipsItems) {
pandora.$ui.list.reloadList(true); Ox.Request.clearCache(); // fixme
pandora.$ui.list.reloadList(true);
}
} else if (pandora.user.ui.listView == 'timelines') {
pandora.$ui.list.options({
width: window.innerWidth
- pandora.user.ui.showSidebar * pandora.user.ui.sidebarSize - 1
- Ox.UI.SCROLLBAR_SIZE
});
} else if (pandora.user.ui.listView == 'map') {
pandora.$ui.map && pandora.$ui.map.resizeMap();
} else if (pandora.user.ui.listView == 'calendar') {
pandora.$ui.calendar && pandora.$ui.calendar.resizeCalendar();
} else {
pandora.$ui.list && pandora.$ui.list.size();
} }
} else if (pandora.user.ui.listView == 'timelines') {
pandora.$ui.list.options({
width: window.innerWidth
- pandora.user.ui.showSidebar * pandora.user.ui.sidebarSize - 1
- Ox.UI.SCROLLBAR_SIZE
});
} else if (pandora.user.ui.listView == 'map') {
pandora.$ui.map && pandora.$ui.map.resizeMap();
} else if (pandora.user.ui.listView == 'calendar') {
pandora.$ui.calendar && pandora.$ui.calendar.resizeCalendar();
} else { } else {
pandora.$ui.list && pandora.$ui.list.size(); pandora.$ui.browser.scrollToSelection();
} if (pandora.user.ui.itemView == 'info') {
} else { pandora.$ui.item.resize();
pandora.$ui.browser.scrollToSelection(); } else if (pandora.user.ui.itemView == 'clips') {
if (pandora.user.ui.itemView == 'info') { pandora.$ui.clipList.size();
pandora.$ui.item.resize(); } else if (pandora.user.ui.itemView == 'timeline') {
} else if (pandora.user.ui.itemView == 'clips') { pandora.$ui.timeline && pandora.$ui.timeline.options({
pandora.$ui.clipList.size(); // fixme: duplicated
} else if (pandora.user.ui.itemView == 'timeline') { height: pandora.$ui.contentPanel.size(1),
pandora.$ui.timeline && pandora.$ui.timeline.options({ width: pandora.$ui.document.width() - pandora.$ui.mainPanel.size(0) - 1
// fixme: duplicated });
height: pandora.$ui.contentPanel.size(1), } else if (pandora.user.ui.itemView == 'player') {
width: pandora.$ui.document.width() - pandora.$ui.mainPanel.size(0) - 1 pandora.$ui.player && pandora.$ui.player.options({
}); // fixme: duplicated
} else if (pandora.user.ui.itemView == 'player') { height: pandora.$ui.contentPanel.size(1),
pandora.$ui.player && pandora.$ui.player.options({ width: pandora.$ui.document.width() - pandora.$ui.mainPanel.size(0) - 1
// fixme: duplicated });
height: pandora.$ui.contentPanel.size(1), } else if (pandora.user.ui.itemView == 'editor') {
width: pandora.$ui.document.width() - pandora.$ui.mainPanel.size(0) - 1 pandora.$ui.editor && pandora.$ui.editor.options({
}); // fixme: duplicated
} else if (pandora.user.ui.itemView == 'editor') { height: pandora.$ui.contentPanel.size(1),
pandora.$ui.editor && pandora.$ui.editor.options({ width: pandora.$ui.document.width() - pandora.$ui.mainPanel.size(0) - 1
// fixme: duplicated });
height: pandora.$ui.contentPanel.size(1), } else if (pandora.user.ui.itemView == 'map') {
width: pandora.$ui.document.width() - pandora.$ui.mainPanel.size(0) - 1 pandora.$ui.map.resizeMap();
}); } else if (pandora.user.ui.itemView == 'calendar') {
} else if (pandora.user.ui.itemView == 'map') { pandora.$ui.calendar.resizeCalendar();
pandora.$ui.map.resizeMap(); }
} else if (pandora.user.ui.itemView == 'calendar') {
pandora.$ui.calendar.resizeCalendar();
} }
} }
}; };
pandora.selectList = function() { pandora.selectList = function() {
if (pandora.user.ui._list) { if (pandora.user.ui.section == 'items') {
pandora.api.findLists({ if (pandora.user.ui._list) {
keys: ['status', 'user'], pandora.api.findLists({
query: { keys: ['status', 'user'],
conditions: [{key: 'id', value: pandora.user.ui._list, operator: '=='}], query: {
operator: '' conditions: [{key: 'id', value: pandora.user.ui._list, operator: '=='}],
}, operator: ''
range: [0, 1] },
}, function(result) { range: [0, 1]
var folder, list; }, function(result) {
if (result.data.items.length) { var folder, list;
list = result.data.items[0]; if (result.data.items.length) {
folder = list.status == 'featured' ? 'featured' : ( list = result.data.items[0];
list.user == pandora.user.username ? 'personal' : 'favorite' folder = list.status == 'featured' ? 'featured' : (
); list.user == pandora.user.username ? 'personal' : 'favorite'
pandora.$ui.folderList[folder] );
.options({selected: [pandora.user.ui._list]}); pandora.$ui.folderList[folder]
if (!pandora.hasDialogOrScreen() && !pandora.hasFocusedInput()) { .options({selected: [pandora.user.ui._list]});
pandora.$ui.folderList[folder].gainFocus(); if (!pandora.hasDialogOrScreen() && !pandora.hasFocusedInput()) {
pandora.$ui.folderList[folder].gainFocus();
}
} }
} });
}); }
} 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]});
}
});
}
} }
}; };