From dc42c90e2dd2e44b923d0ec072f207783af18f7c Mon Sep 17 00:00:00 2001 From: sanj Date: Tue, 4 Jan 2011 11:57:10 +0530 Subject: [PATCH] buttons, testing, etc --- itf/api/views.py | 15 ++ itf/app/models.py | 108 +++++++++++++- itf/bestpractices/models.py | 30 +++- itf/festival/models.py | 4 +- itf/scriptbank/models.py | 39 ++++- itf/settings.py | 2 + itf/static/js/{ => itf}/itf.js | 260 +++++++++++++++++++++++++++++---- itf/templates/index.html | 3 +- 8 files changed, 426 insertions(+), 35 deletions(-) rename itf/static/js/{ => itf}/itf.js (58%) diff --git a/itf/api/views.py b/itf/api/views.py index cad29ce..3cbaaa5 100644 --- a/itf/api/views.py +++ b/itf/api/views.py @@ -93,6 +93,21 @@ def api_error(request): success = error_is_success return render_to_json_response({}) + +def api_find(request): + data = json.loads(request.POST['data']) + print json.dumps(data) + module = __import__(data['module']) + model = module.models.__getattribute__(data['model']) + response = json_response({}) + l = model.get_list(data) + if data.has_key('range'): + response['data']['items'] = l + else: + response['data']['items'] = len(l) + response['status'] = {'code': 200} + return render_to_json_response(response) + def get_api_doc(f): f = 'api_' + f diff --git a/itf/app/models.py b/itf/app/models.py index 71a8362..cb1a584 100644 --- a/itf/app/models.py +++ b/itf/app/models.py @@ -1,3 +1,109 @@ from django.db import models +import operator +from django.db.models import Q +from ox.text import smartSplit +from django.core.paginator import Paginator, InvalidPage, EmptyPage + +def splitSearch(string): + ret = [] + for s in smartSplit(string): + word = s.replace("'", "").replace('"', '') + ret.append(word) + return ret + +class ItfModel(models.Model): + fts_fields = [] + fk_filters = [] + sort_fields = [] + + class Meta: + abstract = True + + def list_dict(self): + return {} + + def info_dict(self): + return {} + + @classmethod + def fts(kls, qset, search): + terms = splitSearch(search) + qobjects = [] + for t in terms: + for f in kls.fts_fields: + qstring = f + '__icontains' + qobject = Q(**{qstring:t}) + qobjects.append(qobject) + return qset.filter(reduce(operator.or_, qobjects)) + + ''' + eg. fks = { + 'somefield': [1, 5, 7], + 'someotherfield': [3] + } + ''' + @classmethod + def filter_by_fks(kls, qset, fks): + qobjects = [] + for key in fks.keys(): + field = getField(kls._meta.fields, key) + if field: +# rel_class = field.related.parent_model + for i in fks[key]: + qobject = Q(**{field.name: i}) + qobjects.append(qobject) + return qset.filter(reduce(operator.or_, qobjects)) + + @classmethod + def get_fk_objects(kls): + ret = {} + for f in kls.fk_filters: + ret[f] = [] + field = getField(kls._meta.fields, f) + rel_class = field.related.parent_model + for o in rel_class.objects.all(): + ret[f].append({ + 'id': o.id, + 'title': unicode(o) + }) + return ret + + + @classmethod + def get_list(kls, data): + options = { + 'page_no': 1, + 'list_size': 8, + 'search': '', + 'sort': [] + } + options.update(data) + ret = [] + page_no = options['page_no'] + list_size = options['list_size'] + qset = kls.objects.all() + + search = options['search'] + if search != '': + qset = kls.fts(qset, search) + + sort = options['sort'] + if sort != []: + qset = qset.order_by(sort[0]) #FIXME: Do Sort! + + paginator = Paginator(qset, list_size) + try: + results = paginator.page(page_no) + except (EmptyPage, InvalidPage): + results = paginator.page(paginator.num_pages) + + for r in results.object_list: + ret.append(r.list_dict()) + return ret + +def getField(fields, name): + for f in fields: + if f.name == name: + return f + return False -# Create your models here. diff --git a/itf/bestpractices/models.py b/itf/bestpractices/models.py index 1d628da..a6e5c51 100644 --- a/itf/bestpractices/models.py +++ b/itf/bestpractices/models.py @@ -1,7 +1,9 @@ from django.db import models from tagging.fields import TagField +from django.core.paginator import Paginator, InvalidPage, EmptyPage +from app.models import ItfModel -class BestPractice(models.Model): +class BestPractice(ItfModel): title = models.CharField(max_length=512) story = models.TextField() guideline = models.TextField(blank=True) @@ -10,10 +12,34 @@ class BestPractice(models.Model): quick_howto = models.TextField(blank=True) tags = TagField(blank=True, help_text="Enter as many tags as you like, separated by commas.") category = models.ForeignKey("BestPracticeCategory") - + + fts_fields = ['title', 'story', 'guideline', 'law', 'theatre', 'quick_howto'] + fk_filters = ['category'] + sort_fields = ['title'] + def __unicode__(self): return self.title + def info_dict(self): + return { + 'title': self.title, + 'story': self.story, + 'guideline': self.guideline, + 'law': self.law, + 'theatre': self.theatre, + 'quick_howto': self.quick_howto, + 'category': self.category.name, + 'category_id': self.category.id + } + + def list_dict(self): + return { + 'id': self.id, + 'title': self.title, + 'category': self.category.name, + } + + class BestPracticeCategory(models.Model): name = models.CharField(max_length=256) description = models.TextField(blank=True) diff --git a/itf/festival/models.py b/itf/festival/models.py index d716941..f47982f 100644 --- a/itf/festival/models.py +++ b/itf/festival/models.py @@ -2,6 +2,7 @@ from django.db import models import datetime import time from ckeditor.fields import RichTextField +from app.models import ItfModel class Comment(models.Model): name = models.CharField(max_length=255) @@ -30,10 +31,11 @@ class CommentCaptcha(models.Model): # class CommentVote(models.Model): -class Meeting(models.Model): +class Meeting(ItfModel): title = models.CharField(max_length=255) intro = models.TextField(blank=True, null=True) slug = models.SlugField() + fts_fields = ['title', 'intro'] def __unicode__(self): return self.title diff --git a/itf/scriptbank/models.py b/itf/scriptbank/models.py index d736ba4..17ca1f5 100644 --- a/itf/scriptbank/models.py +++ b/itf/scriptbank/models.py @@ -1,6 +1,8 @@ from django.db import models from django.contrib.auth.models import User from tagging.fields import TagField +from django.core.paginator import Paginator, InvalidPage, EmptyPage +from app.models import ItfModel GENRES = ( ('Fiction', 'Fiction'), @@ -14,7 +16,7 @@ LANGUAGE_CHOICES = ( ('be', 'Bengali'), ) -class Script(models.Model): +class Script(ItfModel): user = models.ForeignKey(User) title = models.CharField(max_length=255) synopsis = models.TextField(blank=True) @@ -30,10 +32,45 @@ class Script(models.Model): script = models.FileField(null=True, upload_to='upload/scripts/') license_adapt = models.ForeignKey("LicensePerform", help_text="License for adaptation rights") license_perform = models.ForeignKey("LicenseAdapt", help_text="License for performance rights") + fts_fields = ['title', 'synopsis', 'author'] + fk_fields = ['license_adapt', 'license_perform'] + + #Meta + added = models.DateTimeField(auto_now_add=True) + modified = models.DateTimeField(auto_now=True) def __unicode__(self): return self.title + ''' + @classmethod + def get_list(kls, data): + options = { + 'page_no': 1, + 'list_size': 8 + } + options.update(data) + l = [] + page_no = options['page_no'] + list_size = options['list_size'] + qset = kls.objects.all() + + paginator = Paginator(qset, list_size) + try: + results = paginator.page(page_no) + except (EmptyPage, InvalidPage): + results = paginator.page(paginator.num_pages) + for r in results.object_list: + l.append({ + 'id': r.id, + 'title': r.title + }) + return l + ''' + + + + class License(models.Model): letter = models.CharField(max_length=2) name = models.CharField(max_length=255) diff --git a/itf/settings.py b/itf/settings.py index 4a59a81..58433fa 100644 --- a/itf/settings.py +++ b/itf/settings.py @@ -20,6 +20,8 @@ PROJECT_ROOT = PROJECT_PATH CKEDITOR_MEDIA_PREFIX = "/static/ckeditor/" CKEDITOR_UPLOAD_PATH = join(PROJECT_PATH, "static/upload/images/") +AUTH_PROFILE_MODULE = "profiles.Person" + ADMINS = ( # ('Your Name', 'your_email@domain.com'), ) diff --git a/itf/static/js/itf.js b/itf/static/js/itf/itf.js similarity index 58% rename from itf/static/js/itf.js rename to itf/static/js/itf/itf.js index 4a60bb1..bc6821b 100644 --- a/itf/static/js/itf.js +++ b/itf/static/js/itf/itf.js @@ -1,4 +1,4 @@ - +var ITF = {}; var app = new Ox.App({ apiURL: '/api/', @@ -53,6 +53,143 @@ app.launch(function(data) { }); +app.Query = (function() { + + function constructFind(query) { + Ox.print('cF', query) + return /*encodeURI(*/$.map(query.conditions, function(v, i) { + if (!Ox.isUndefined(v.conditions)) { + return '[' + constructFind(v) + ']'; + } else { + return v.value !== '' ? v.key + (v.key ? ':' : '') + constructValue(v.value, v.operator) : null; + } + }).join(query.operator)/*)*/; + } + + function constructValue(value, operator) { + operator = operator.replace('=', '^$'); + if (operator.indexOf('$') > -1) { + value = operator.substr(0, operator.length - 1) + value + '$' + } else { + value = operator + value; + } + return value; + } + + function mergeFind() { + } + + function parseFind(str) { + var find = { + conditions: [], + operator: '' + }, + subconditions = str.match(/\[.*?\]/g) || []; + $.each(subconditions, function(i, v) { + subconditions[i] = v.substr(1, v.length - 2); + str = str.replace(v, '[' + i + ']'); + }); + if (str.indexOf(',') > -1) { + find.operator = '&'; + } else if (str.indexOf('|') > -1) { + find.operator = '|'; + } + Ox.print('pF', str, find.operator) + find.conditions = $.map(find.operator === '' ? [str] : str.split(find.operator == '&' ? ',' : '|'), function(v, i) { + Ox.print('v', v) + var ret, kv; + if (v[0] == '[') { + Ox.print('recursion', subconditions) + ret = parseFind(subconditions[parseInt(v.substr(1, v.length - 2))]); + } else { + kv = ((v.indexOf(':') > - 1 ? '' : ':') + v).split(':'); + ret = $.extend({ + key: kv[0] + }, parseValue(kv[1])); + } + return ret; + }); + return find; + } + + function parseValue(str) { + var value = { + value: decodeURI(str), + operator: '' + }; + if (value.value[0] == '!') { + value.operator = '!' + value.value = value.value.substr(1); + } + if ('^<>'.indexOf(value.value[0]) > -1) { + value.operator += value.value[0]; + value.value = value.value.substr(1); + } + if (value.value.substr(-1) == '$') { + value.operator += '$'; + value.value = value.value.substr(0, value.value.length - 1); + } + value.operator = value.operator.replace('^$', '='); + return value; + } + + return { + + fromString: function(str) { + var query = Ox.unserialize(str), + sort = []; + if ('find' in query) { + app.user.ui.findQuery = parseFind(query.find); + Ox.print('user.ui.findQuery', app.user.ui.findQuery) + } + if ('sort' in query) { + sort = query.sort.split(',') + app.user.ui.sort = $.map(query.sort.split(','), function(v, i) { + var hasOperator = '+-'.indexOf(v[0]) > -1, + key = hasOperator ? query.sort.substr(1) : query.sort, + operator = hasOperator ? v[0].replace('+', '') : Ox.getObjectById(app.config.sortKeys, key).operator; + return { + key: key, + operator: operator + }; + }); + } + if ('view' in query) { + app.user.ui.listView = query.view; + } + }, + + toObject: function(groupId) { + Ox.print('tO', app.user.ui.findQuery.conditions) + // the inner $.merge() creates a clone + var conditions = $.merge($.merge([], app.user.ui.listQuery.conditions), app.user.ui.findQuery.conditions); + $.merge(conditions, app.ui.groups ? $.map(app.ui.groups, function(v, i) { + if (v.id != groupId && v.query.conditions.length) { + return v.query.conditions.length == 1 ? + v.query.conditions : v.query; + } + }) : []), + operator = conditions.length < 2 ? '' : ','; // fixme: should be & + Ox.print('>>', groupId, app.user.ui.find, conditions); + return { + conditions: conditions, + operator: operator + }; + }, + + toString: function() { + Ox.print('tS', app.user.ui.find) + return Ox.serialize({ + find: constructFind(app.Query.toObject()), + sort: app.user.ui.sort[0].operator + app.user.ui.sort[0].key, + view: app.user.ui.listView + }); + } + + }; + +})(); + app.construct = { /* @@ -148,6 +285,10 @@ BEGIN headerPanel i.bindEvent("submit", function(val) { Ox.print("Should be doing a search"); }); + i.css({ + 'marginRight': '15px', + 'marginTop': '6px' + }); return i; }, @@ -215,10 +356,16 @@ BEGIN mainPanel var id = 'cityPicker'; var i = app.$ui[id] = new Ox.Input({ id: id, - placeholder: 'Chose Your City' + placeholder: 'Chose Your City', + autocomplete: ['Mumbai', 'Gurgaon', 'Agra', 'Delhi', 'Bangalore', 'Calcutta', 'Hyderabad'], + autocompleteSelect: true, + autocompleteSelectHighlight: true, + autocompleteSelectSubmit: true, + autocompleteReplaceCorrect: true }); - i.submit(function(val) { - Ox.Print("should handle submit of city name"); + i.bindEvent("submit", function(event, data) { + Ox.print(data); +// alert(data.value); }); return i; }, @@ -303,7 +450,7 @@ BEGIN mainPanel 'newsfeedBox': function() { var id = 'newsfeedBox'; - var c = app.$ui[id] = new Ox.ItfBox({ + var c = app.$ui[id] = new Ox.Container({ id: id, title: 'ITF NewsFeed' }); @@ -372,20 +519,26 @@ BEGIN mainPanel }, 'scriptArchiveBox': function() { - var id = 'scriptArchiveBox'; - var c = app.$ui[id] = new Ox.Container({ - id: id + var id = 'scriptbankBox'; + var c = app.$ui[id] = new Ox.ItfBox({ + 'id': id, + 'title': 'Script Bank', + 'module': 'scriptbank', + 'model': 'Script' }); - c.$content.html("script archive goes here"); +// c.$content.html("script archive goes here"); return c; }, 'bestPracticesBox': function() { - var id = 'bestPracticesBox'; - var c = app.$ui[id] = new Ox.Container({ - id: id + var id = 'bestpracticesBox'; + var c = app.$ui[id] = new Ox.ItfBox({ + 'id': id, + 'title': 'Best Practices', + 'module': 'bestpractices', + 'model': 'BestPractice' }); - c.$content.html("best practices goes here"); +// c.$content.html("best practices goes here"); return c; }, @@ -534,33 +687,82 @@ Ox.ItfBox = function(options, self) { var title = self.options.title; var $titlebar = new Ox.Bar({ orientation: 'horizontal', - size: 16 + size: 18 }) // .dblclick(dblclickTitlebar) - .appendTo(that), + .appendTo(that); -/* - $switch = new Ox.Button({ - id: options.id + 'Switch', - style: 'symbol', - title: title, - type: 'image', - }) -// .click(toggleCollapsed) - .appendTo($titlebar), -*/ - $title = new Ox.Element() + + var $title = new Ox.Element() .addClass('OxTitle') .html(title/*.toUpperCase()*/) .appendTo($titlebar); + var $search = new Ox.Input({ + 'placeholder': 'Search', + }) + .css({'width': '128px', 'marginLeft': 'auto', 'marginRight': 'auto'}) + .appendTo(that) + .hide(); + + var $switch = new Ox.Button({ + id: options.id + 'Switch', + style: 'symbol', + title: 'collapse', + type: 'image', + tooltip: 'Search' + }) + .css({'position': 'absolute', 'top': '1px', 'right': '1px', 'marginLeft': '6px'}) + .bindEvent("click", function() { +// alert("foo"); +// $search.slideDown(); + $search.is(":visible") ? $search.slideUp() : $search.slideDown(); + }) + .appendTo($title); + + + + + var $list = new Ox.ItfList({ + 'width': 256, + 'itemWidth': 256, + 'orientation': 'horizontal', + 'request': function(data, callback) { +// var queryParams = $.extend(data, {'model': options.id, 'query': app.Query.toObject()}); + var queryParams = $.extend(data, {'model': options.model, 'module': options.module, 'query': {}}); +// alert(JSON.stringify(queryParams)); + return app.api.find(queryParams, callback) + }, + 'id': options.id + 'List', + 'construct': function(data) { + var $a = $('').attr("href", "/" + options.module.toLowerCase() + "/" + data.id).text(data.title); + var $item = $('
').addClass('OxTarget').append($a); + return $item; + } + }) + .appendTo(that); + + // $buttons = new Ox. return that; } +Ox.ItfList = function(options, self) { + var self = self || {}; + var that = new Ox.List(options, self); + return that; +} + +Ox.ItfCalendar = function(options, self) { + var self = self || {}; + var that = new Ox.Element(options, self); + var $titleBar = new Ox.Bar({ + 'size': 'small' + }).addClass('OxTitleBar').appendTo(that); + var $title = new Ox.Element().html("Calendar").appendTo($titleBar); + return that; +} - - - +ITF.templates = {}; diff --git a/itf/templates/index.html b/itf/templates/index.html index fa1f08e..eeaa389 100755 --- a/itf/templates/index.html +++ b/itf/templates/index.html @@ -17,7 +17,8 @@ if(typeof(console)=='undefined') { - + +