diff --git a/pandora/home/models.py b/pandora/home/models.py index 219e6ed1..4031ab9a 100644 --- a/pandora/home/models.py +++ b/pandora/home/models.py @@ -3,6 +3,8 @@ from __future__ import division, print_function, absolute_import from six import string_types +from six.moves.urllib.parse import quote + from django.db import models from django.db.models import Max import ox @@ -42,6 +44,16 @@ class Item(models.Model): return False self.data[key] = data[key] changed = True + if 'type' in data: + if data['type'] == 'custom': + if 'contentid' in self.data: + del self.data['contentid'] + changed = True + else: + for key in list(self.data): + if key not in ('contentid', 'type'): + del self.data[key] + changed = True if 'active' in data: self.active = data['active'] is True changed = True @@ -70,17 +82,29 @@ class Item(models.Model): } j.update(self.data) if 'contentid' in j and (not keys or 'content' in keys): - content_keys = ['description', 'modified', 'name', 'user'] + content_keys = [ + 'description', + 'modified', + 'name', + 'user', + ] type = j.get('type') if type == 'list': from itemlist.models import List - j['content'] = List.get(j['contentid']).json(keys=content_keys) + content = List.get(j['contentid']).json(keys=content_keys) elif type == 'edit': from edit.models import Edit - j['content'] = Edit.get(j['contentid']).json(keys=content_keys) + content = Edit.get(j['contentid']).json(keys=content_keys) elif type == 'collection': from documentcollection.models import Collection - j['content'] = Collection.get(j['contentid']).json(keys=content_keys) + content = Collection.get(j['contentid']).json(keys=content_keys) + j['title'] = content['name'] + j['text'] = content['description'] + + j['image'] = '/' + '/'.join([ + type, quote(content['user'] + ':' + content['name']), + 'icon256.jpg?%s' % content['modified'].strftime('%Y-%m-%dT%H:%M:%SZ') + ]) if keys: for key in list(j): if key not in keys: @@ -88,4 +112,4 @@ class Item(models.Model): return j def __unicode__(self): - return u"%s" %(self.get_id()) + return u"%s" % (self.get_id()) diff --git a/pandora/home/views.py b/pandora/home/views.py index 0ea49307..9f3bde59 100644 --- a/pandora/home/views.py +++ b/pandora/home/views.py @@ -100,7 +100,7 @@ def getHomeItems(request, data): } ''' response = json_response() - qs = models.Item.objects.all().order_by('index', 'created') + qs = models.Item.objects.all().order_by('-active', 'index', 'created') if 'active' in data: qs = qs.filter(active=data['active'] is True) response['data']['items'] = [i.json() for i in qs] diff --git a/static/js/home.indiancinema.js b/static/js/home.indiancinema.js index fc06062c..9f495c10 100644 --- a/static/js/home.indiancinema.js +++ b/static/js/home.indiancinema.js @@ -329,253 +329,67 @@ pandora.ui.home = function() { color = Ox.Theme() == 'oxlight' ? 'rgb(0, 0, 0)' : Ox.Theme() == 'oxmedium' ? 'rgb(0, 0, 0)' : 'rgb(255, 255, 255)', - $label, $icon, $text, + $label, $texts, $featuresBox, $featuresContainer, $featuresContent, $featureBox = [], $featureIcon = [], $previousButton, $nextButton; if (items.length) { - $label = Ox.Label({ - textAlign: 'center', - title: '' + Ox._('Featured ' + ( - lists == 1 && edits == 0 && texts == 0 ? 'List' - : lists == 0 && edits == 1 && texts == 0 ? 'Edit' - : lists == 0 && edits == 0 && texts == 1 ? 'Text' - : edits == 0 && texts == 0 ? 'Lists' - : lists == 0 && texts == 0 ? 'Edits' - : lists == 0 && edits == 0 ? 'Texts' - : texts == 0 ? 'Lists and Edits' - : edits == 0 ? 'Lists and Texts' - : lists == 0 ? 'Edits and Texts' - : 'Lists, Edits and Texts' - )) + '', - width: 512 - }) - .css({ - position: 'absolute', - left: 0, - top: 0, - right: 0, - bottom: 0, - margin: '0 auto 0 auto' - }) - .appendTo($features); - $text = Ox.Label({ - width: 386 - }) - .addClass('OxSelectable') - .css({ - position: 'absolute', - left: '24px', - top: '24px', - right: 0, - height: '104px', - borderTopLeftRadius: '32px', - borderBottomLeftRadius: '32px', - padding: '8px 8px 8px 130px', - overflowY: 'auto', - lineHeight: '14px', - textOverflow: 'ellipsis', - whiteSpace: 'normal' - }) - .html( - getHTML(items[selected]) - ) - .appendTo($features); - pandora.createLinks($text); - $icon = Ox.Element({ - element: '', - tooltip: getTooltip(items[selected]) - }) - .attr({ - src: getImageURL(items[selected]) - }) - .css({ - position: 'absolute', - left: 0, - top: '24px', - right: '390px', - width: '122px', - height: '122px', - borderRadius: '32px', - margin: '0 auto 0 auto', - cursor: 'pointer' - }) - .bindEvent({ - anyclick: function() { - openItem(selected); - } - }) - .appendTo($features); - if (items.length > 1) { - $featuresBox = $('
') + $features.empty(); + $texts = Ox.Element().appendTo($features); + var top = 24; + items.forEach(function(item) { + var $text, $icon; + $icon = Ox.Element({ + element: '', + tooltip: getTooltip(item) + }) + .attr({ + src: item.image + }) .css({ - position: 'absolute', left: 0, - top: '150px', - right: 0, - height: '65px', // 4+57+4 - width: '560px', // 16+8+512+8+16 - margin: '0 auto 0 auto' + right: '390px', + width: '122px', + height: '122px', + borderRadius: '32px', + marginRight: '8px', + cursor: 'pointer', + float: 'left' }) - .appendTo($features); - $featuresContainer = $('
') - .css({ - position: 'absolute', - left: '20px', - right: '20px', - height: '65px', - width: '520px', - overflow: 'hidden' - }) - .appendTo($featuresBox); - $featuresContent = $('
') - .css({ - position: 'absolute', - width: items.length * 65 + 'px', - height: '65px', - marginLeft: items.length < max - ? (max - items.length) * 65 / 2 + 'px' - : 0 - }) - .appendTo($featuresContainer); - if (items.length > max) { - $previousButton = Ox.Button({ - title: 'left', - type: 'image' - }) - .addClass(position > 0 ? 'visible' : '') - .css({ - position: 'absolute', - left: 0, - top: '25px', - opacity: 0 - }) - .hide() - .bindEvent({ - mousedown: function() { - counter = 0; - scrollToPosition(position - 1, true); - }, - mouserepeat: function() { - // fixme: arbitrary - if (counter++ % 5 == 0) { - scrollToPosition(position - 1, false); - } - } - }) - .appendTo($featuresBox); - $nextButton = Ox.Button({ - title: 'right', - type: 'image' - }) - .addClass(position < items.length - 1 ? 'visible' : '') - .css({ - position: 'absolute', - right: 0, - top: '25px', - opacity: 0 - }) - .hide() - .bindEvent({ - mousedown: function() { - counter = 0; - scrollToPosition(position + 1, true); - }, - mouserepeat: function() { - // fixme: arbitrary - if (counter++ % 5 == 0) { - scrollToPosition(position + 1, false); - } - } - }) - .appendTo($featuresBox); - $featuresBox.on({ - mouseenter: function() { - mouse = true; - $('.visible').show().stop().animate({ - opacity: 1 - }, 250); - }, - mouseleave: function() { - mouse = false; - $('.visible').stop().animate({ - opacity: 0 - }, 250, function() { - $(this).hide(); - }); - }, - mousewheel: function(e, delta, deltaX, deltaY) { - // fixme: arbitrary - scrollToPosition(position + Math.round(deltaX * 2), true); + .bindEvent({ + anyclick: function() { + openItem(item); } }); - } - items.forEach(function(item, i) { - $featureBox[i] = $('
') - .css({ - float: 'left', - width: '57px', - height: '57px', - padding: '2px', - margin: '2px', - borderRadius: '16px', - boxShadow: '0 0 2px ' + (i == selected ? color : 'transparent') - }) - .appendTo($featuresContent); - $featureIcon[i] = Ox.Element({ - element: '', - tooltip: ( - (lists && edits) || (lists && texts) || (edits && texts) - ? Ox._(Ox.toTitleCase(item.type)) + ': ' - : '' - ) - + Ox.encodeHTMLEntities(item.name) - }) - .attr({ - src: getImageURL(item) - }) - .css({ - width: '57px', - height: '57px', - borderRadius: '16px', - cursor: 'pointer' - }) - .bindEvent({ - doubleclick: function() { - openItem(i); - }, - singleclick: function() { - selectItem(i); - } - }) - .appendTo($featureBox[i]); - }); - self.keydown = function(e) { - var key = Ox.KEYS[e.keyCode]; - if (!Ox.Focus.focusedElementIsInput()) { - if (key == 'left' && selected > 0) { - selectItem(selected - 1); - } else if (key == 'up' && selected > 0) { - selectItem(0); - } else if (key == 'right' && selected < items.length - 1) { - selectItem(selected + 1); - } else if (key == 'down' && selected < items.length - 1) { - selectItem(items.length - 1); - } - } - }; - Ox.$document.on({keydown: self.keydown}); - } - $space = $('
') - .css({ - position: 'absolute', - top: items.length == 0 ? '0px' - : items.length == 1 ? '150px' - : '215px', - width: '560px', - height: '80px' - }) - .appendTo($features); + $text = Ox.Label({ + //width: 386 + 122 + }) + .addClass('OxSelectable') + .css({ + //position: 'absolute', + left: '24px', + //top: top + 'px', + right: 0, + height: 'auto', + padding: '8px 8px 8px 8px', + borderRadius: '32px', + marginBottom: '16px', + overflowY: 'auto', + lineHeight: '14px', + textOverflow: 'ellipsis', + whiteSpace: 'normal' + }) + .append($icon) + .append( + Ox.Element().css({ + //padding: '8px', + }).html(getHTML(item)) + + ) + .appendTo($texts); + pandora.createLinks($text); + top += 130; + }); $features.animate({opacity: 1}, 250); } @@ -589,44 +403,44 @@ pandora.ui.home = function() { ? Ox._(Ox.toTitleCase(item.type)) + ': ' : '' ) - + Ox.encodeHTMLEntities(item.content.name) + '

' - + item.content.description; - } - - function getImageURL(item) { - if (item.type == 'custom') { - return item.image; - } - return '/' + item.type + '/' + item.user - + ':' + encodeURIComponent(item.name) + '/icon256.jpg?' + item.modified; + + Ox.encodeHTMLEntities(item.title) + '

' + + item.text; } function getTooltip(item) { - return Ox._('View {0}', [Ox._(Ox.toTitleCase(item.type))]) + return Ox._('View {0}', [Ox._(Ox.toTitleCase(item.title))]) } - function openItem(i) { + function openItem(item) { that.fadeOutScreen(); - if (items[i].type == 'custom') { - pandora.URL.push(items[i].link); + if (item.type == 'custom') { + pandora.URL.push(item.link); } else { pandora.UI.set(Ox.extend({ - section: items[i].type == 'list' ? 'items' : items[i].type + 's', + + section: item.type == 'list' ? 'items' : item.type + 's', page: '' - }, items[i].type == 'list' ? { + }, item.type == 'list' ? { find: { conditions: [{ key: 'list', - value: items[i].content.user + ':' - + items[i].content.name, + value: item.contentid, operator: '==' }], operator: '&' } - } : items[i].type == 'edit' ? { - edit: items[i].content.user + ':' + items[i].content.name + } : item.type == 'collection' ? { + findDocuments: { + conditions: [{ + key: 'collection', + value: item.contentid, + operator: '==' + }], + operator: '&' + } + } : item.type == 'edit' ? { + edit: item.contentid } : { - text: items[i].content.user + ':' + items[i].content.name })); } } @@ -661,31 +475,6 @@ pandora.ui.home = function() { }); } } - - function selectItem(i) { - if (i >= 0 && i <= items.length - 1 && i != selected) { - $featureBox[selected].css({ - boxShadow: 'none' - }); - selected = i; - $featureBox[selected].css({ - boxShadow: '0 0 2px ' + color - }); - if (selected < position) { - scrollToPosition(selected, true); - } else if (selected > position + max - 1) { - scrollToPosition(selected - max + 1, true); - } - $icon.attr({ - src: getImageURL(items[selected]) - }).options({ - tooltip: getTooltip(items[selected]) - }); - $text.html( - getHTML(items[selected]) - ); - } - } } } diff --git a/static/js/homeDialog.js b/static/js/homeDialog.js index 1d1657a0..0265116b 100644 --- a/static/js/homeDialog.js +++ b/static/js/homeDialog.js @@ -2,14 +2,23 @@ pandora.ui.homeDialog = function() { - var $lists = Ox.Element(); + var items = []; - var $item = $('
'); + var autocompleteData = {}; + + var $folders = $('
').css({overflowX: 'hidden', overflowY: 'auto'}); + + var $item = $('
').addClass('OxTextPage'); + + var $form = $('
'); + + var $title, $text, $typeSelect, $imageInput, $linkInput, $nameInput; var $dialogPanel = Ox.SplitPanel({ elements: [ - {element: $lists, size: 256}, - {element: $item} + {element: $folders, resizable: true, resize: [256], size: 256}, + {element: $item}, + {element: $form, resizable: true, resize: [256], size: 256} ], orientation: 'horizontal' }) @@ -27,28 +36,131 @@ pandora.ui.homeDialog = function() { ], closeButton: true, content: $dialogPanel, - height: 576, + height: 256, //576, removeOnClose: true, title: Ox._('Manage Home Screen'), - width: 768 + width: 1050 // 256 + 17 + 512 + 17 + 256 }); pandora.api.getHomeItems({}, function(result) { - var $activeList = renderList(result.data.items.filter(function(item) { - return item.active; - })).appendTo($lists); - var $inactiveList = renderList(result.data.items.filter(function(item) { - return !item.active; - }))//.appendTo($lists); - }); + getAutocompleteData(function() { + items = result.data.items; + var selected = items.length ? items[0].id : null; + renderFolders(result.data.items, selected); + if (selected) { + var item = Ox.getObjectById(items, selected) + renderItem(item); + renderForm(item); + } + }); + }); - function renderItem(data) { - var $item = $('
'); - if (!data) { - return $item; + function editItem(id, key, value) { + var title = $title.value(); + var text = $text.value(); + var type = $typeSelect.value(); + if (type == 'custom') { + var image = $imageInput.value(); + var link = $linkInput.value(); + } else { + var name = $nameInput.value(); } - var $form = $('
').appendTo($item); - var $typeSelect = Ox.Select({ + if ( + !title || !text + || (type == 'custom' && (!image || !link)) + || (type != 'custom' && !name) + ) { + return; + } + pandora.api.editHomeItem(Ox.extend({id: id}, key, value), function(result) { + // ... + }); + } + + function getAutocompleteData(callback) { + Ox.parallelForEach( + ['list', 'edit', 'collection'], + function(value, index, array, callback) { + pandora.api['find' + Ox.toTitleCase(value) + 's']({ + keys: ['id'], + query: { + conditions: [ + {key: 'status', operator: '!=', value: 'private'} + ], + operator: '&' + }, + range: [0, 1000] + }, function(result) { + autocompleteData[value] = result.data.items.map(function(item) { + return item.id; + }); + callback(); + }); + }, + callback + ); + } + + function renderFolder(type, items, selected) { + var extras = [ + Ox.MenuButton({ + items: [ + {id: 'newitem', title: Ox._( + 'New ' + (type == 'active' ? 'Active' : 'Inactive') + ' Item' + )}, + {id: 'deleteitem', title: Ox._('Delete Selected Item')} + ], + title: 'edit', + tooltip: Ox._('Manage Items'), + type: 'image' + }).bindEvent({ + click: function(data) { + if (data.id == 'newitem') { + // ... + } else if (data.id == 'deleteitem') { + // ... + } + } + }) + ]; + var $folder = Ox.CollapsePanel({ + collapsed: false, + extras: extras, + size: 16, + title: Ox._((type == 'active' ? 'Active' : 'Inactive') + ' Items') + }).bindEvent({ + toggle: function(data) { + data.collapsed && $list.loseFocus(); + } + }); + var $placeholder = Ox.Element().addClass('OxLight').css({ + height: '14px', + padding: '1px 4px', + }).html(Ox._('No items')).hide().appendTo($folder.$content) + var $list = renderList(items.filter(function(item) { + return item.active == (type == 'active'); + }), selected).bindEventOnce({ + init: function(data) { + $placeholder[data.items ? 'hide' : 'show'](); + $folder.$content.css({ + height: (data.items || 1) * 16 + 'px' + }); + } + }).appendTo($folder.$content); + + return $folder; + } + + function renderFolders(items, selected) { + $folders.empty(); + ['active', 'inactive'].forEach(function(type) { + var $folder = renderFolder(type, items, selected).appendTo($folders); + }); + } + + function renderForm(data, focus) { + $form.empty(); + $typeSelect = Ox.Select({ items: [ {id: 'custom', title: Ox._('Custom')}, {id: 'list', title: Ox._('List')}, @@ -56,78 +168,122 @@ pandora.ui.homeDialog = function() { {id: 'collection', title: Ox._('Collection')} ], label: Ox._('Type'), - labelWidth: 128, - width: 512 + labelWidth: 80, + value: data.type, + width: 240 }).css({ - margin: '4px' + margin: '8px' }).bindEvent({ change: function(data) { - renderItem({type: data.value}) + var item = {type: data.value}; + renderItem(item); + renderForm(item, true); } }).appendTo($form); if (data.type == 'custom') { - var $imageInput = Ox.Input({ + $imageInput = Ox.Input({ label: Ox._('Image URL'), - labelWidth: 128, - width: 512 + labelWidth: 80, + value: data.image || '', + width: 240 }).css({ - margin: '4px' + margin: '8px' + }).bindEvent({ + change: function(data) { + editItem(data.id, 'image', data.value); + } }).appendTo($form); - var $linkInput = Ox.Input({ + $linkInput = Ox.Input({ label: Ox._('Link URL'), - labelWidth: 128, - width: 512 + labelWidth: 80, + value: data.link || '', + width: 240 }).css({ - margin: '4px' + margin: '8px' + }).bindEvent({ + change: function(data) { + editItem(data.id, 'link', data.value); + } }).appendTo($form); } else { - var $nameInput = Ox.Input({ - label: Ox._('List Name'), - labelWidth: 128, - width: 512 + $nameInput = Ox.Input({ + autocomplete: autocompleteData[data.type], + autocompleteSelect: true, + autocompleteSelectMaxWidth: 256, + label: Ox._('Name'), + labelWidth: 80, + value: data.contentid || '', + width: 240 }).css({ - margin: '4px' + margin: '8px' + }).bindEvent({ + change: function(data) { + editItem(data.id, 'name', data.value); + } }).appendTo($form); } - var $preview = $('
').appendTo($item); - var $imageContainer = $('
').css({ - background: 'rgb(0, 0, 0)', // FIXME: make themes - borderRadius: '32px', - height: '128px', - width: '128px' - }).appendTo($preview); + if (focus) { + (data.type == 'custom' ? $imageInput : $nameInput).focusInput(); + } + } + + function renderItem(data) { + $item.empty(); if (data.image) { - $image = $('').attr({ + var $image = $('').attr({ src: data.image }).css({ borderRadius: '32px', + float: 'left', height: '128px', + margin: '12px', width: '128px' - }).appendTo($imageContainer) + }).appendTo($item) + } else { + var $placeholder = $('
').css({ + border: 'dotted 1px rgb(0, 0, 0)', // FIXME: make themes + borderRadius: '32px', + height: '128px', + margin: '8px', + width: '128px' + }).appendTo($item); } - Ox.EditableContent({ + var $container = $('
').css({ + margin: '10px 12px 8px 0' + }).appendTo($item); + var title = data.title ? ( + ( + data.type == 'custom' ? '' + : Ox._('Featured ' + Ox.toTitleCase(data.type) + ': ') + ) + data.title + ) : ''; + $title = Ox.EditableContent({ + editable: data.type == 'custom', placeholder: '' + Ox._('Title') + '', - value: data.title - }) - .bindEvent({ + value: title + }).css({ + fontSize: '13px', + fontWeight: 'bold' + }).bindEvent({ submit: function(data) { - editItem('title', data.value); + editItem(data.id, 'title', data.value); } - }).appendTo($preview); - Ox.EditableContent({ + }).appendTo($container); + $text = Ox.EditableContent({ + editable: data.type == 'custom', placeholder: '' + Ox._('Text') + '', - value: data.text - }) - .bindEvent({ + type: 'textarea', + value: data.text || '' + }).css({ + margin: '0 12px 0 0' + }).bindEvent({ submit: function(data) { - editItem('text', data.value); + editItem(data.id, 'text', data.value); } - }).appendTo($preview); - return $item; + }).appendTo($item); } - function renderList(items) { - console.log('LIST', items) + function renderList(items, selected) { var $list = Ox.TableList({ columns: [ { @@ -167,13 +323,24 @@ pandora.ui.homeDialog = function() { ], items: items, max: 1, + selected: [selected], sort: [{key: 'index', operator: '+'}], sortable: true, unique: 'id' }) .bindEvent({ - select: function() { - + select: function(data) { + if (data.ids.length) { + var item = Ox.getObjectById(items, data.ids[0]) + renderItem(item); + renderForm(item); + } + }, + selectafter: function() { + // ... + }, + selectbefore: function() { + // ... } }) .css({