From d699a3264ce5fb518ff8612d3787d44604354d63 Mon Sep 17 00:00:00 2001 From: Brandon King Date: Sat, 27 Jun 2009 01:59:13 +0000 Subject: [PATCH] Pulling in barcode magic from sample tracker and starting to update it to use ExtJS --- htsworkflow/frontend/bcmagic/__init__.py | 0 htsworkflow/frontend/bcmagic/admin.py | 7 + htsworkflow/frontend/bcmagic/forms.py | 9 + htsworkflow/frontend/bcmagic/models.py | 9 + htsworkflow/frontend/bcmagic/plugin.py | 18 ++ htsworkflow/frontend/bcmagic/urls.py | 7 + htsworkflow/frontend/bcmagic/utils.py | 22 +++ htsworkflow/frontend/bcmagic/views.py | 146 +++++++++++++++ htsworkflow/frontend/samples/views.py | 4 +- htsworkflow/frontend/static/js/bcmagic-ext.js | 169 ++++++++++++++++++ htsworkflow/frontend/static/js/htsw.js | 22 ++- htsworkflow/frontend/static/js/magicbc.js | 4 +- htsworkflow/frontend/templates/app_base.html | 4 +- .../templates/{ => bcmagic}/magic.html | 0 htsworkflow/frontend/urls.py | 1 + 15 files changed, 417 insertions(+), 5 deletions(-) create mode 100644 htsworkflow/frontend/bcmagic/__init__.py create mode 100644 htsworkflow/frontend/bcmagic/admin.py create mode 100644 htsworkflow/frontend/bcmagic/forms.py create mode 100644 htsworkflow/frontend/bcmagic/models.py create mode 100644 htsworkflow/frontend/bcmagic/plugin.py create mode 100644 htsworkflow/frontend/bcmagic/urls.py create mode 100644 htsworkflow/frontend/bcmagic/utils.py create mode 100644 htsworkflow/frontend/bcmagic/views.py create mode 100644 htsworkflow/frontend/static/js/bcmagic-ext.js rename htsworkflow/frontend/templates/{ => bcmagic}/magic.html (100%) diff --git a/htsworkflow/frontend/bcmagic/__init__.py b/htsworkflow/frontend/bcmagic/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/htsworkflow/frontend/bcmagic/admin.py b/htsworkflow/frontend/bcmagic/admin.py new file mode 100644 index 0000000..2dce2ec --- /dev/null +++ b/htsworkflow/frontend/bcmagic/admin.py @@ -0,0 +1,7 @@ +from django.contrib import admin +from htsworkflow.frontend.bcmagic.models import KeywordMap + +class KeywordMapAdmin(admin.ModelAdmin): + list_display = ('keyword','regex', 'url_template') + +admin.site.register(KeywordMap, KeywordMapAdmin) \ No newline at end of file diff --git a/htsworkflow/frontend/bcmagic/forms.py b/htsworkflow/frontend/bcmagic/forms.py new file mode 100644 index 0000000..000acd9 --- /dev/null +++ b/htsworkflow/frontend/bcmagic/forms.py @@ -0,0 +1,9 @@ +from django import forms + +class BarcodeMagicForm(forms.Form): + magic = forms.CharField(label="Barcode Magic", required=False) + bcm_mode = forms.CharField(widget=forms.HiddenInput, initial="default") + + class Media: + js = ('js/jquery.timers-1.0.0.js', + 'js/bcmagic-ext.js') diff --git a/htsworkflow/frontend/bcmagic/models.py b/htsworkflow/frontend/bcmagic/models.py new file mode 100644 index 0000000..12d8736 --- /dev/null +++ b/htsworkflow/frontend/bcmagic/models.py @@ -0,0 +1,9 @@ +from django.db import models + +class KeywordMap(models.Model): + """ + Mapper object maps keyword|arg1|arg2|...|argN to REST urls + """ + keyword = models.CharField(max_length=64) + regex = models.CharField(max_length=1024) + url_template = models.TextField() diff --git a/htsworkflow/frontend/bcmagic/plugin.py b/htsworkflow/frontend/bcmagic/plugin.py new file mode 100644 index 0000000..6653fd9 --- /dev/null +++ b/htsworkflow/frontend/bcmagic/plugin.py @@ -0,0 +1,18 @@ +#from htsworkflow.frontend.samples import bcm_cmds + +#BCM_PLUGINS = {'cmd_move_sample': bcm_cmds.cmd_move_sample} + + +def bcm_plugin_processor(keyword, text, bcm_mode): + """ + Fixme should be made generic plugable, but am hard coding values for proof + of concept. + """ + d = {} + + if bcm_mode not in BCM_PLUGINS: + d['mode'] = 'Error' + d['status'] = 'bcm_mode plugin called "%s" was not found' % (bcm_mode) + return d + + return BCM_PLUGINS[bcm_mode](keyword, text, bcm_mode) \ No newline at end of file diff --git a/htsworkflow/frontend/bcmagic/urls.py b/htsworkflow/frontend/bcmagic/urls.py new file mode 100644 index 0000000..62497d2 --- /dev/null +++ b/htsworkflow/frontend/bcmagic/urls.py @@ -0,0 +1,7 @@ +from django.conf.urls.defaults import * + +urlpatterns = patterns('', + (r'^json_test/$', 'htsworkflow.frontend.bcmagic.views.json_test'), + (r'^magic/$', 'htsworkflow.frontend.bcmagic.views.magic'), + (r'^$', 'htsworkflow.frontend.bcmagic.views.index'), +) \ No newline at end of file diff --git a/htsworkflow/frontend/bcmagic/utils.py b/htsworkflow/frontend/bcmagic/utils.py new file mode 100644 index 0000000..5ee81a9 --- /dev/null +++ b/htsworkflow/frontend/bcmagic/utils.py @@ -0,0 +1,22 @@ + + +def report_error(message): + """ + Return a dictionary with a command to display 'message' + """ + return {'mode': 'Error', 'status': message} + + +def redirect_to_url(url): + """ + Return a bcm dictionary with a command to redirect to 'url' + """ + return {'mode': 'redirect', 'url': url} + + +def autofill(field, value): + """ + Return a bcm dictionary with a command to automatically fill the + corresponding "field" with "value" + """ + return {'mode': 'autofill', 'field': field, 'value': value} \ No newline at end of file diff --git a/htsworkflow/frontend/bcmagic/views.py b/htsworkflow/frontend/bcmagic/views.py new file mode 100644 index 0000000..492d7e5 --- /dev/null +++ b/htsworkflow/frontend/bcmagic/views.py @@ -0,0 +1,146 @@ +from django.http import HttpResponse +from django.template import RequestContext, Template, Context +from django.shortcuts import render_to_response +from django.core.exceptions import ObjectDoesNotExist + +from htsworkflow.frontend.bcmagic import models +from htsworkflow.frontend.bcmagic.utils import report_error, redirect_to_url +from htsworkflow.frontend.bcmagic.plugin import bcm_plugin_processor + +import json +import re + +from htsworkflow.frontend.bcmagic import forms + +def index(request): + """ + Display a barcode magic input box + """ + form = forms.BarcodeMagicForm() + + return render_to_response('bcmagic/magic.html', {'bcmagic': form}, + context_instance=RequestContext(request)) + + +def __magic_process(text): + """ + Based on scanned text, check to see if there is map object to use + for a useful redirect. + """ + # Split text on | + split_text = text.split('|') + + # There should always be at least one | in a valid scan. + if len(split_text) <= 1: + return report_error('Invalid text: %s' % (text)) + + # Keyword is the first element in the list + keyword = split_text[0] + + # Attempt to find a KeywordMap based on keyword + try: + keymap = models.KeywordMap.objects.get(keyword=keyword) + except ObjectDoesNotExist, e: + return report_error('Keyword (%s) is not defined' % (keyword)) + + # Remove keyword and only scan the content + content = '|'.join(split_text[1:]) + + #FIXME: would be faster to cache compiled regex + search = re.compile(keymap.regex) + + mo = search.search(content) + + # if the search was invalid + if not mo: + return report_error('(%s) failed to match (%s)' % (keymap.regex, content)) + + t = Template(keymap.url_template) + c = Context(mo.groupdict()) + + return redirect_to_url(str(t.render(c))) + + + + + +def magic(request): + """ + Let the magic begin + """ + d = {} + + #Retrieve posted text from processing + if 'text' in request.POST: + text = request.POST['text'] + else: + text = None + + #Retrieve bmc_mode for processing + if 'bcm_mode' in request.POST: + bcm_mode = request.POST['bcm_mode'] + else: + bcm_mode = None + + ################################ + # Handle some errors + ################################ + + # Did not receive text error + if text is None or text.strip() == '': + d['mode'] = 'Error' + d['status'] = 'Did not recieve text' + j = json.JSONEncoder() + return HttpResponse(j.encode(d), 'text/plain') + + # Did not receive bcm_mode error + if bcm_mode is None or bcm_mode.strip() == '': + d['mode'] = 'Error' + d['status'] = 'Missing bcm_mode information' + + + ################################ + # Figure out which mode to use + ################################ + keyword = text.split('|')[0] + + # Handle URL mode by default + if keyword == 'url': + d['mode'] = 'redirect' + d['url'] = text.split('|')[1] + + # Pass off processing to plugins + elif bcm_mode != 'default': + d = bcm_plugin_processor(keyword, text, bcm_mode) + + # Try keyword mapper + else: + d = __magic_process(text) + j = json.JSONEncoder() + return HttpResponse(j.encode(d), 'text/plain') + + + +def json_test(request): + d = {} + + if 'text' in request.POST: + text = request.POST['text'] + else: + text = None + + #return HttpResponse(json.write(request.POST.items()), 'text/plain') + if text is None or text.strip() == '': + d['mode'] = 'Error' + d['status'] = 'Did not recieve text' + return HttpResponse(json.write(d), 'text/plain') + + if text.split('|')[0] == 'url': + d['mode'] = 'redirect' + d['url'] = text.split('|')[1] + else: + d['msg'] = 'Recieved text: %s' % (text) + d['mode'] = 'clear' + + j = json.JSONEncoder() + return HttpResponse(j.encode(d), 'text/plain') diff --git a/htsworkflow/frontend/samples/views.py b/htsworkflow/frontend/samples/views.py index 52907ed..669a126 100644 --- a/htsworkflow/frontend/samples/views.py +++ b/htsworkflow/frontend/samples/views.py @@ -3,6 +3,7 @@ from htsworkflow.frontend.experiments.models import FlowCell from htsworkflow.frontend.samples.changelist import ChangeList from htsworkflow.frontend.samples.models import Library from htsworkflow.frontend.samples.results import get_flowcell_result_dict, parse_flowcell_id +from htsworkflow.frontend.bcmagic.forms import BarcodeMagicForm from htsworkflow.pipelines.runfolder import load_pipeline_run_xml from htsworkflow.pipelines import runfolder from htsworkflow.frontend import settings @@ -22,7 +23,8 @@ import os LANE_LIST = [1,2,3,4,5,6,7,8] SAMPLES_CONTEXT_DEFAULTS = { - 'app_name': 'Flowcell/Library Tracker' + 'app_name': 'Flowcell/Library Tracker', + 'bcmagic': BarcodeMagicForm() } def create_library_context(cl): diff --git a/htsworkflow/frontend/static/js/bcmagic-ext.js b/htsworkflow/frontend/static/js/bcmagic-ext.js new file mode 100644 index 0000000..a3d9c6c --- /dev/null +++ b/htsworkflow/frontend/static/js/bcmagic-ext.js @@ -0,0 +1,169 @@ +//----------------------------------------------- +// Barcode Magic JavaScript +// Authors: Brandon W. King +// Feb. 2009 +//----------------------------------------------- + +//--------------------------------------- +// BCMagic Core Processing AJAX Callback +//--------------------------------------- +//var bcmagic_process_callback = function(data, textStatus) { +var bcmagic_process_callback = function(response, opt) { + //FIXME: temp bypass hack + var textStatus = 'success'; + if (textStatus != 'success') + { + bcmagic_message('AJAX Status: '+textStatus); + return; + } + + var data = Ext.decode(response.responseText); + + for (key in data) + { + if (key == 'mode') + { + if (data['mode'] == 'clear') + { + bcmagic_status('',''); + } + else if (data['mode'] == 'redirect') + { + if ('url' in data) + { + bcmagic_redirect(data['url']); + } + else + { + bcmagic_status('Error', 'No redirect URL provided by server'); + } + } + else if (data['mode'] == 'autofill') + { + bcmagic_autofill(data['field'], data['value']) + } + else { + bcmagic_message('Message recieved!'); + bcmagic_status(data['mode'], data['status']); + } + + } + if (key == 'msg') + { + bcmagic_message(data['msg']); + } + } +} + +var bcmagic_callback = function(data, textStatus) +{ + if (textStatus != 'success') + bcmagic_message('Failed!'); + else + bcmagic_message('Success!'); +} + +var bcmagic_process = function(){ + var magic = Ext.get("bcmagic_input_field"); + var text = magic.getValue(); + magic.dom.value = ''; + magic.focus(); + + //var bcm_mode = $("#id_bcm_mode"); + //var mode = bcm_mode.attr('value'); + var mode = 'default'; + + // Show what we have captured + bcmagic_message('Sent command to server'); + //$.post('/bcmagic/magic/', {'text': text, 'bcm_mode': mode}, bcmagic_process_callback, 'json'); + Ext.Ajax.request({ + url: '/bcmagic/magic/', + success: bcmagic_process_callback, + failure: function (r, o) { quick_msg('Some AJAX Fail!'); }, + params: {'text': text, 'bcm_mode': mode} + }); +} + +var bcmagic_keyhandler = function(e) { + //Process upon enter key as input. + if (e.which == 13) + bcmagic_process(); +} + +//--------------------------------------- +// Utility Functions +//--------------------------------------- +var bcmagic_message = function(text) +{ + // Show message + //$("#bcm_msg").html(text); + quick_msg(text); + + // clear message after 3000ms + /* + setTimeout(function() { + $("#bcm_msg").html(''); + }, 3000); + */ +} + +var bcmagic_status = function(state, text) +{ + //var msg = $('#bcm_status'); + if (state.length > 0 || text.length > 0) + quick_msg(state+': '+text); + //else + // msg.html(''); +} + + +var bcmagic_redirect = function(url) +{ + bcmagic_message('Redirecting to:' + url); + window.location = url; +} + +var bcmagic_autofill = function(field, val) +{ + var txtbox = $('#'+field); + txtbox.attr('value', val); + + var input_fields = $('form input').not(':hidden').not('[type=submit]'); + + // Count the number of text fields which have been filled in. + var count = 0; + input_fields.each( function(){ + if(this.value.length > 0){ + count = count + 1; + } + }); + + // If the number of text fields filled in is equal to the number of input_fields in the form, submit the form! + if (count == input_fields.length) + { + bcmagic_status('Form Full', 'Form is now full and ready to process'); + form = $('form'); + form.submit(); + form.reset(); + + } + else + { + bcmagic_status('Form Fill Count', 'Count(' + count +') - Total(' + input_fields.length + ')'); + } +} + +//--------------------------------------- +// Main Ready Function +//--------------------------------------- +/*$(document).ready(function() { + + // Grab initial focus on magic text input + $("#id_magic").focus(); + + // Set some initial text + //$("#id_magic").attr('value','Moo cow!'); + + // Trigger when enterkey is pressed + $("#id_magic").keypress(bcmagic_keyhandler) +});*/ \ No newline at end of file diff --git a/htsworkflow/frontend/static/js/htsw.js b/htsworkflow/frontend/static/js/htsw.js index 83f4ac0..6f00cb1 100644 --- a/htsworkflow/frontend/static/js/htsw.js +++ b/htsworkflow/frontend/static/js/htsw.js @@ -220,6 +220,25 @@ $(document).ready(function(){ // Shifts the remaining toolbar options to the right side. main_tb.add({ xtype: 'tbfill' }); + + //---------------------------------------- + // ExtJS Barcode Magic Implementation + var bcmagic_ext_keyhandler = function(sObj, e){ + //e.preventDefault(); + //Process upon enter key as input. + if (e.getKey() == e.ENTER) + bcmagic_process(); + } + + var bcmagic_input = new Ext.form.TextField({ + id: 'bcmagic_input_field', + emptyText: 'barcode magic' + }); + bcmagic_input.on('specialkey', bcmagic_ext_keyhandler); + + main_tb.add(bcmagic_input); + //-------------------------------------- + var user_info = Ext.fly('login_info'); var logout_url = user_info.getAttribute('logouturl'); var login_url = user_info.getAttribute('loginurl'); @@ -255,5 +274,6 @@ $(document).ready(function(){ add_buttons_from_html(app_tb, 'app_toolbar_east'); app_tb.doLayout(); - + // Focus on barcode magic, because it's awesome and needs attention! ;-) + bcmagic_input.focus(); }); \ No newline at end of file diff --git a/htsworkflow/frontend/static/js/magicbc.js b/htsworkflow/frontend/static/js/magicbc.js index 2044193..b294abd 100644 --- a/htsworkflow/frontend/static/js/magicbc.js +++ b/htsworkflow/frontend/static/js/magicbc.js @@ -140,7 +140,7 @@ var bcmagic_autofill = function(field, val) //--------------------------------------- // Main Ready Function //--------------------------------------- -$(document).ready(function() { +/*$(document).ready(function() { // Grab initial focus on magic text input $("#id_magic").focus(); @@ -150,4 +150,4 @@ $(document).ready(function() { // Trigger when enterkey is pressed $("#id_magic").keypress(bcmagic_keyhandler) -}); \ No newline at end of file +});*/ \ No newline at end of file diff --git a/htsworkflow/frontend/templates/app_base.html b/htsworkflow/frontend/templates/app_base.html index 5338da2..9e03aaa 100644 --- a/htsworkflow/frontend/templates/app_base.html +++ b/htsworkflow/frontend/templates/app_base.html @@ -68,9 +68,11 @@ + {% block east_region %}
{% if east_region_config_div %}{{ east_region_config_div }}{% endif %}
diff --git a/htsworkflow/frontend/templates/magic.html b/htsworkflow/frontend/templates/bcmagic/magic.html similarity index 100% rename from htsworkflow/frontend/templates/magic.html rename to htsworkflow/frontend/templates/bcmagic/magic.html diff --git a/htsworkflow/frontend/urls.py b/htsworkflow/frontend/urls.py index 4be3ed5..1cd34b4 100644 --- a/htsworkflow/frontend/urls.py +++ b/htsworkflow/frontend/urls.py @@ -44,6 +44,7 @@ urlpatterns = patterns('', 'htsworkflow.frontend.samples.views.bedfile_fc_cnm_eland_lane_ucsc'), (r'^results/(?P\w+)/(?PC[1-9]-[0-9]+)/bedfile/(?P[1-8])', 'htsworkflow.frontend.samples.views.bedfile_fc_cnm_eland_lane'), + (r'^bcmagic/', include('htsworkflow.frontend.bcmagic.urls')), # databrowser #(r'^databrowse/(.*)', databrowse.site.root) -- 2.30.2