├── jumptoadmin ├── __init__.py ├── templatetags │ ├── __init__.py │ └── jumptoadmin.py ├── media │ └── jumptoadmin │ │ ├── poof.png │ │ ├── macFFBgHack.png │ │ ├── loadingAnimation.gif │ │ ├── jumptoadmin.js │ │ ├── thickbox-compressed.js │ │ ├── jumptoadmin.css │ │ └── thickbox.js └── context_processors.py ├── .gitignore ├── AUTHORS ├── MANIFEST.in ├── LICENSE ├── setup.py └── README.rst /jumptoadmin/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.pyc -------------------------------------------------------------------------------- /jumptoadmin/templatetags/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Ryan Berg 2 | Jannis Leidel -------------------------------------------------------------------------------- /jumptoadmin/media/jumptoadmin/poof.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanberg/django-jumptoadmin/HEAD/jumptoadmin/media/jumptoadmin/poof.png -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include AUTHORS 2 | include LICENSE 3 | include README.rst 4 | recursive-include jumptoadmin/media/jumptoadmin/* *.css *.js *.gif *.png 5 | -------------------------------------------------------------------------------- /jumptoadmin/media/jumptoadmin/macFFBgHack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanberg/django-jumptoadmin/HEAD/jumptoadmin/media/jumptoadmin/macFFBgHack.png -------------------------------------------------------------------------------- /jumptoadmin/media/jumptoadmin/loadingAnimation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryanberg/django-jumptoadmin/HEAD/jumptoadmin/media/jumptoadmin/loadingAnimation.gif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License/GNU License 2 | 3 | http://www.opensource.org/licenses/mit-license.php 4 | http://www.gnu.org/licenses/gpl.html 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so. -------------------------------------------------------------------------------- /jumptoadmin/context_processors.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | 3 | def media(request): 4 | """ 5 | Returns the URL of jumptoadmin media specified in settings 6 | Defaults to the standard MEDIA_URL setting + '/jumptoadmin/' 7 | """ 8 | 9 | try: 10 | JUMPTOADMIN_MEDIA_URL = settings.JUMPTOADMIN_MEDIA_URL 11 | 12 | except AttributeError: 13 | JUMPTOADMIN_MEDIA_URL = '' 14 | 15 | # Only need to get MEDIA_URL if JUMPTOADMIN_MEDIA_URL is not specified 16 | try: 17 | MEDIA_URL = settings.MEDIA_URL 18 | 19 | # Make sure MEDIA_URL ends in a '/' 20 | if MEDIA_URL[-1] != '/': 21 | MEDIA_URL += '/' 22 | 23 | JUMPTOADMIN_MEDIA_URL = '%sjumptoadmin/' % (MEDIA_URL) 24 | 25 | except AttributeError: 26 | MEDIA_URL = '' 27 | 28 | return {'JUMPTOADMIN_MEDIA_URL': JUMPTOADMIN_MEDIA_URL} -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from distutils.core import setup 3 | 4 | def read(fname): 5 | return open(os.path.join(os.path.dirname(__file__), fname)).read() 6 | 7 | setup( 8 | name='django-jumptoadmin', 9 | version='0.1.0', 10 | description="Django templatetag for admins to easily change/delete objects from the public-facing site.", 11 | long_description=read('README.rst'), 12 | author='Ryan Berg', 13 | author_email='ryan.berg@gmail.com', 14 | license='BSD', 15 | url='http://github.com/ryanberg/django-jumptoadmin/', 16 | packages=[ 17 | 'jumptoadmin', 18 | 'jumptoadmin.templatetags' 19 | ], 20 | classifiers=[ 21 | 'Development Status :: 3 - Alpha', 22 | 'Environment :: Web Environment', 23 | 'Intended Audience :: Developers', 24 | 'License :: OSI Approved :: BSD License', 25 | 'Operating System :: OS Independent', 26 | 'Programming Language :: Python', 27 | 'Framework :: Django', 28 | ], 29 | package_data = { 30 | 'jumptoadmin': [ 31 | 'media/jumptoadmin/css/*.css', 32 | 'media/jumptoadmin/img/*.png', 33 | 'media/jumptoadmin/img/*.gif', 34 | 'media/jumptoadmin/js/*.js', 35 | ] 36 | }, 37 | zip_safe=False, # required to convince setuptools/easy_install to unzip the package data 38 | ) 39 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ==================== 2 | Django JumpToAdmin 3 | ==================== 4 | 5 | Django JumpToAdmin is a library that offers administrators easy access 6 | to the Django admin interface for any object from the public-facing interface. 7 | 8 | (See UI screencast and an overview at `http://ryanberg.net/blog/2009/sep/10/introducing-django-jumptoadmin/ `_, and screenshots at `http://emberapp.com/explore/tags/jumptoadmin `_) 9 | 10 | A Django template tag outputs class names to the template. A Javascript file 11 | parses the rendered template in the browser for these classes 12 | and adds links to Change or Delete any object. 13 | 14 | Links will also be rendered to perform any "Admin actions" specified in your admin.py files. 15 | 16 | When clicked, these links load the Django admin pages in an iframe above the current page for easy access. 17 | 18 | These links only appear for logged in users with admin permissions on each specified object. 19 | 20 | Django JumpToAdmin is very immature software. If you have ideas for other capabilities please fork this project give them a try. 21 | 22 | 23 | 24 | Dependencies 25 | ============= 26 | 27 | * Django JumpToAdmin is developed against Django trunk, but should work on Django 1.0 and newer. 28 | 29 | * Django JumpToAdmin requires jQuery be loaded from templates to display any links 30 | 31 | 32 | 33 | Installation 34 | ============ 35 | 36 | #. Add the following package to your Python path:: 37 | 38 | 'jumptoadmin' 39 | 40 | 41 | #. Add the following to the INSTALLED_APPS list in your settings.py file:: 42 | 43 | 'jumptoadmin', 44 | 45 | 46 | #. Add the following to the TEMPLATE_CONTEXT_PROCESSORS list in your settings.py file to add a {{ JUMPTOADMIN_MEDIA_URL }} variable to the context of each template:: 47 | 48 | 'jumptoadmin.context_processors.media', 49 | 50 | 51 | #. (Optionally) At the command line, create a symbolic link from your project's media folder to the media folder inside the jumptoadmin package:: 52 | 53 | ln -s /path/to/your/media/jumptoadmin/ /path/to/django-jumptoadmin/jumptoadmin/media/jumptoadmin/ 54 | 55 | 56 | #. (Optionally) Specify an JUMPTOADMIN_MEDIA_URL variable in your settings.py file. If not specified, JUMPTOADMIN_MEDIA_URL will default to your MEDIA_URL value + 'jumptoadmin/':: 57 | 58 | JUMPTOADMIN_MEDIA_URL = '/URL/to/your/media/jumptoadmin/' 59 | 60 | 61 | #. In your base.html template (or any specific template you'd like) add the following inside the HTML to bring in the Javascript and CSS needed to show JumpToAdmin links:: 62 | 63 | {% if user.is_staff %}{% endif %} 64 | 65 | {% if user.is_staff %}{% endif %} 66 | 67 | 68 | #. In your base.html template (or any specific template you'd like) add the following just before the to insert a global Javascript variable named 'jumpFlagList' that contains all the information needed to render links for each item:: 69 | 70 | {% render_jumptoadmin_flags %} 71 | 72 | 73 | #. In any template that contains objects for which you'd like JumpToAdmin, load the "jumptoadmin" templatetag library then pass the desired object to the "jumptoadmin_flag" tag inside an HTML class:: 74 | 75 | {% load jumptoadmin %} 76 |
...
77 | 78 | {% for comment in comments %} 79 |
80 | ... 81 |
82 | {% endfor %} 83 | 84 | 85 | Credits 86 | ======= 87 | 88 | * Django JumpToAdmin is designed and developed by `Ryan Berg `_ 89 | * Django JumpToAdmin uses Thickbox Javascript adapted from `ThickBox 3.1 `_ -------------------------------------------------------------------------------- /jumptoadmin/media/jumptoadmin/jumptoadmin.js: -------------------------------------------------------------------------------- 1 | var overlay_reloadOnRemove = false; 2 | 3 | var flagActionsListOpacity = 0.25; 4 | 5 | function showJumpToAdminLinks(flaggedObject) { 6 | /* 7 | flaggedObject should be a jQuery object 8 | */ 9 | 10 | var re = /jumptoadminflag_[\w\d-]+/; 11 | var classString = flaggedObject.attr('class').match(re)[0]; // Will look like jumptoadminflag_app-model-id 12 | 13 | function getFlaggedObjectDetails(classString) { 14 | /* 15 | Loop through each of the flags from the global jumpFlagList variable 16 | Until we find one with a 'class' attribute equal to the above classString 17 | */ 18 | for (var i = 0; i < jumpFlagList.length; i++) { 19 | var flaggedObjectDetails = jumpFlagList[i]; 20 | if (flaggedObjectDetails['class'] == classString) { 21 | return flaggedObjectDetails; 22 | } 23 | } 24 | return null; 25 | } 26 | 27 | flaggedObjectDetails = getFlaggedObjectDetails(classString); 28 | 29 | if (flaggedObjectDetails && flaggedObjectDetails['actions'].length) { 30 | /* 31 | Create the unordered list of actions 32 | flaggedObjectDetails should have 'name', 'class', and 'actions' 33 | */ 34 | var flagActionsList = $(''); 35 | flagActionsList.append($('')); 36 | 37 | // Loop through each action for this flagged object 38 | 39 | for (var a = 0; a < flaggedObjectDetails['actions'].length; a++ ) { 40 | var flagAction = flaggedObjectDetails['actions'][a]; 41 | var flagActionName = flagAction['name']; 42 | var flagActionURL = flagAction['url']; 43 | var flagActionAction = flagAction['action']; 44 | 45 | // This is only used for styling purposes 46 | var lastClass = ''; 47 | if (a == flaggedObjectDetails['actions'].length - 1) { lastClass = ' class="jumptoadmin_li_last"'} 48 | 49 | // Create the string thickbox will use to properly display the admin page 50 | var flagActionURLParameters = '?'; 51 | if (flagActionAction == '') { 52 | // Since there's no post data, an iframe can be used 53 | flagActionURLParameters += 'TB_iframe=true'; 54 | var flagActionPostParameters = null; 55 | } else { 56 | // Admin will be retrieved via AJAX instead of an iframe so we can send POST data 57 | var flagActionPostParameters = { 58 | 'action': flagActionAction, // Name of the registered action 59 | '_selected_action': flaggedObjectDetails['pk'], // PK of the object on which to perform the action 60 | } 61 | } 62 | flagActionURLParameters += 'height=400&width=800'; 63 | 64 | // Create the list item 65 | var flagActionLI = $('' + flagActionName.substr(0,1).toUpperCase() + flagActionName.substring(1) + ''); 66 | 67 | // Handle clicks on the action's link 68 | flagActionLI.children('a:first').click(function() { 69 | var clickedLink = $(this); 70 | clickedLink.parents('.jumptoadminlinks').animate({'opacity': 0}, 100).remove(); // Remove the list 71 | tb_show(null, clickedLink.attr("href"), flagActionPostParameters, false); // Show the thickbox 72 | return false; 73 | }); 74 | 75 | // Append the list item to the list 76 | flagActionsList.append(flagActionLI); 77 | } 78 | 79 | // Handle opacity of the jumptoadminlinks 80 | flagActionsList.css("opacity", 0).hover(function() { 81 | // On hover, set opacity to 1 82 | $(this).animate({'opacity': 1}, 100); 83 | }, function() { 84 | // On hover-off set opacity back to default 85 | $(this).animate({'opacity': flagActionsListOpacity}, 100); 86 | }); 87 | 88 | // Show the jumptoadminlinks 89 | flaggedObject.addClass('jumptoadminflag_display'); 90 | flagActionsList.prependTo(flaggedObject).animate({"opacity": flagActionsListOpacity}, 100); 91 | 92 | // Handle the close button 93 | $('a.jumptoadminlinks_li_close').click(function(e) { 94 | // Set up the poof 95 | var poof = $('
'); 96 | var xOffset = 24; 97 | var yOffset = 24; 98 | 99 | // Unbind the hover for this flag and remove the jumptoadminlinks 100 | $(this).parents('.jumptoadminflag_display').eq(0).unbind('mouseenter mouseleave') 101 | .removeClass('jumptoadminflag_display').children('ul.jumptoadminlinks').remove(); 102 | 103 | poof.css({ 104 | left: e.pageX - xOffset + 'px', 105 | top: e.pageY - yOffset + 'px' 106 | }).appendTo($('body')).show(); 107 | 108 | animatePoof(poof); 109 | 110 | return false; 111 | }); 112 | 113 | } 114 | 115 | } 116 | 117 | $(document).ready(function() { 118 | var flaggedObjects = $('.jumptoadminflag'); 119 | 120 | if (flaggedObjects.length) { 121 | flaggedObjects.hover(function() { 122 | showJumpToAdminLinks($(this)); 123 | }, function() { 124 | $(this).removeClass('jumptoadminflag_display').children('ul.jumptoadminlinks').animate({'opacity': 0}, 100).remove(); 125 | }); 126 | } 127 | }); 128 | 129 | /* Poof effect from http://www.kombine.net/jquery/jquery-poof-effect */ 130 | function animatePoof(poof) { 131 | var bgTop = 0; 132 | var frames = 5; 133 | var frameSize = 32; 134 | var frameRate = 60; 135 | 136 | for(i = 1; i < frames; i ++) { 137 | poof.animate({ 138 | backgroundPosition: '0 ' + (bgTop - frameSize) + 'px' 139 | }, frameRate); 140 | 141 | bgTop -= frameSize; 142 | } 143 | 144 | setTimeout('removePoof()', frames * frameRate); 145 | } 146 | function removePoof(poof) { 147 | $('.poof').remove(); 148 | } -------------------------------------------------------------------------------- /jumptoadmin/media/jumptoadmin/thickbox-compressed.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Thickbox 3 - One Box To Rule Them All. 3 | * By Cody Lindley (http://www.codylindley.com) 4 | * Copyright (c) 2007 cody lindley 5 | * Licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | */ 7 | 8 | var tb_pathToImage = "loadingAnimation.gif"; 9 | 10 | eval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('$(o).2S(9(){1u(\'a.18, 3n.18, 3i.18\');1w=1p 1t();1w.L=2H});9 1u(b){$(b).s(9(){6 t=X.Q||X.1v||M;6 a=X.u||X.23;6 g=X.1N||P;19(t,a,g);X.2E();H P})}9 19(d,f,g){3m{3(2t o.v.J.2i==="2g"){$("v","11").r({A:"28%",z:"28%"});$("11").r("22","2Z");3(o.1Y("1F")===M){$("v").q("<4 5=\'B\'><4 5=\'8\'>");$("#B").s(G)}}n{3(o.1Y("B")===M){$("v").q("<4 5=\'B\'><4 5=\'8\'>");$("#B").s(G)}}3(1K()){$("#B").1J("2B")}n{$("#B").1J("2z")}3(d===M){d=""}$("v").q("<4 5=\'K\'><1I L=\'"+1w.L+"\' />");$(\'#K\').2y();6 h;3(f.O("?")!==-1){h=f.3l(0,f.O("?"))}n{h=f}6 i=/\\.2s$|\\.2q$|\\.2m$|\\.2l$|\\.2k$/;6 j=h.1C().2h(i);3(j==\'.2s\'||j==\'.2q\'||j==\'.2m\'||j==\'.2l\'||j==\'.2k\'){1D="";1G="";14="";1z="";1x="";R="";1n="";1r=P;3(g){E=$("a[@1N="+g+"]").36();25(D=0;((D&1d;&1d;2T &2R;"}n{1D=E[D].Q;1G=E[D].u;14="<1e 5=\'1U\'>&1d;&1d;&2O; 2N"}}n{1r=1b;1n="1t "+(D+1)+" 2L "+(E.1c)}}}S=1p 1t();S.1g=9(){S.1g=M;6 a=2x();6 x=a[0]-1M;6 y=a[1]-1M;6 b=S.z;6 c=S.A;3(b>x){c=c*(x/b);b=x;3(c>y){b=b*(y/c);c=y}}n 3(c>y){b=b*(y/c);c=y;3(b>x){c=c*(x/b);b=x}}13=b+30;1a=c+2G;$("#8").q("<1I 5=\'2F\' L=\'"+f+"\' z=\'"+b+"\' A=\'"+c+"\' 23=\'"+d+"\'/>"+"<4 5=\'2D\'>"+d+"<4 5=\'2C\'>"+1n+14+R+"<4 5=\'2A\'>1l 1k 1j 1s");$("#Z").s(G);3(!(14==="")){9 12(){3($(o).N("s",12)){$(o).N("s",12)}$("#8").C();$("v").q("<4 5=\'8\'>");19(1D,1G,g);H P}$("#1U").s(12)}3(!(R==="")){9 1i(){$("#8").C();$("v").q("<4 5=\'8\'>");19(1z,1x,g);H P}$("#1X").s(1i)}o.1h=9(e){3(e==M){I=2w.2v}n{I=e.2u}3(I==27){G()}n 3(I==3k){3(!(R=="")){o.1h="";1i()}}n 3(I==3j){3(!(14=="")){o.1h="";12()}}};16();$("#K").C();$("#1L").s(G);$("#8").r({Y:"T"})};S.L=f}n{6 l=f.2r(/^[^\\?]+\\??/,\'\');6 m=2p(l);13=(m[\'z\']*1)+30||3h;1a=(m[\'A\']*1)+3g||3f;W=13-30;V=1a-3e;3(f.O(\'2j\')!=-1){1E=f.1B(\'3d\');$("#15").C();3(m[\'1A\']!="1b"){$("#8").q("<4 5=\'2f\'><4 5=\'1H\'>"+d+"<4 5=\'2e\'>1l 1k 1j 1s ")}n{$("#B").N();$("#8").q(" ")}}n{3($("#8").r("Y")!="T"){3(m[\'1A\']!="1b"){$("#8").q("<4 5=\'2f\'><4 5=\'1H\'>"+d+"<4 5=\'2e\'>1l 1k 1j 1s<4 5=\'F\' J=\'z:"+W+"p;A:"+V+"p\'>")}n{$("#B").N();$("#8").q("<4 5=\'F\' 3c=\'3b\' J=\'z:"+W+"p;A:"+V+"p;\'>")}}n{$("#F")[0].J.z=W+"p";$("#F")[0].J.A=V+"p";$("#F")[0].3a=0;$("#1H").11(d)}}$("#Z").s(G);3(f.O(\'37\')!=-1){$("#F").q($(\'#\'+m[\'26\']).1T());$("#8").24(9(){$(\'#\'+m[\'26\']).q($("#F").1T())});16();$("#K").C();$("#8").r({Y:"T"})}n 3(f.O(\'2j\')!=-1){16();3($.1q.35){$("#K").C();$("#8").r({Y:"T"})}}n{$("#F").34(f+="&1y="+(1p 33().32()),9(){16();$("#K").C();1u("#F a.18");$("#8").r({Y:"T"})})}}3(!m[\'1A\']){o.21=9(e){3(e==M){I=2w.2v}n{I=e.2u}3(I==27){G()}}}}31(e){}}9 1m(){$("#K").C();$("#8").r({Y:"T"})}9 G(){$("#2Y").N("s");$("#Z").N("s");$("#8").2X("2W",9(){$(\'#8,#B,#1F\').2V("24").N().C()});$("#K").C();3(2t o.v.J.2i=="2g"){$("v","11").r({A:"1Z",z:"1Z"});$("11").r("22","")}o.1h="";o.21="";H P}9 16(){$("#8").r({2U:\'-\'+20((13/2),10)+\'p\',z:13+\'p\'});3(!(1V.1q.2Q&&1V.1q.2P<7)){$("#8").r({38:\'-\'+20((1a/2),10)+\'p\'})}}9 2p(a){6 b={};3(!a){H b}6 c=a.1B(/[;&]/);25(6 i=0;ivar jumpFlagList = %s' % (context.__getitem__('jumpflags')) 29 | 30 | except KeyError: 31 | return '' 32 | 33 | 34 | @register.tag(name="jumptoadmin_flag") 35 | def do_jumptoadmin_flag(parser, token): 36 | try: 37 | tag_name, jumptoadmin_var = token.split_contents() 38 | 39 | except ValueError: 40 | raise template.TemplateSyntaxError, "%r tag requires exactly two arguments" % token.contents.split()[0] 41 | 42 | return JumpToAdminFlag(jumptoadmin_var) 43 | 44 | class JumpToAdminFlag(template.Node): 45 | def __init__(self, jumptoadmin_var): 46 | self.jumptoadmin_var = template.Variable(jumptoadmin_var) 47 | 48 | def render(self, context): 49 | try: 50 | user = context.__getitem__('user') 51 | 52 | except: 53 | # If we can't find a user, we can't check permissions. Return an empty string. 54 | return '' 55 | 56 | if user.is_authenticated() and user.is_staff: 57 | # User is an administrator 58 | try: 59 | # Get the object passed to the tag from the context 60 | self.jumptoadmin_object = self.jumptoadmin_var.resolve(context) 61 | ct = ContentType.objects.get_for_model(self.jumptoadmin_object) 62 | 63 | except template.VariableDoesNotExist: 64 | # If this object isn't in the context, return an empty string 65 | return '' 66 | 67 | 68 | # NEW WAY BELOW 69 | flagged_object_class = 'jumptoadminflag_%s-%s-%s' % (ct.app_label, ct.model, self.jumptoadmin_object.pk) 70 | flag_string = 'jumptoadminflag %s' % (flagged_object_class) 71 | 72 | actions_list = [] 73 | 74 | actions = [ 75 | { 76 | 'name': 'change', 77 | 'url': str('/admin/%s/%s/%s/' % (ct.app_label, ct.model, self.jumptoadmin_object.pk)), 78 | 'action': '', 79 | 'requires_permission': 1, 80 | }, 81 | { 82 | 'name': 'list', 83 | 'url': str('/admin/%s/%s/' % (ct.app_label, ct.model)), 84 | 'action': '', 85 | 'requires_permission': 0, 86 | }, 87 | { 88 | 'name': 'delete', 89 | 'url': str('/admin/%s/%s/%s/delete/' % (ct.app_label, ct.model, self.jumptoadmin_object.pk)), 90 | 'action': '', 91 | 'requires_perimission': 1, 92 | } 93 | ] 94 | 95 | 96 | 97 | for action in actions: 98 | # Only display links for actions the user has permission to perform 99 | if user.has_perm('%s.%s_%s' % (ct.app_label, action['name'], ct.model)) or not action['requires_permission']: 100 | # User has this permission 101 | actions_list.append(action) 102 | 103 | admin_actions = get_admin_actions(ct) 104 | 105 | if admin_actions: 106 | actions_list.extend(admin_actions) 107 | 108 | flagged_object_dict = { 109 | 'name': str(ct.model), 110 | 'class': str(flagged_object_class), 111 | 'pk': self.jumptoadmin_object.pk, 112 | 'actions': actions_list, 113 | } 114 | 115 | try: 116 | # Get existing jumpflags from the root context 117 | jumpflags = context.__getitem__('jumpflags') 118 | 119 | except KeyError: 120 | # jumpflags doesn't exist so let's create the empty list 121 | jumpflags = [] 122 | 123 | 124 | # Add the newest jumpflag to the dict 125 | jumpflags.append(flagged_object_dict) 126 | 127 | # Update the dict in the context 128 | #context.__setitem__('jumpflags', jumpflags) 129 | context.dicts[-1]['jumpflags'] = jumpflags 130 | 131 | 132 | # Return the string to be used as a class 133 | return flag_string 134 | 135 | else: 136 | # User is not logged in and/or is not an administrator, so return an empty string 137 | return '' 138 | 139 | 140 | def get_admin_actions(content_type): 141 | """ 142 | Pass in a ContentType and this will attempt to return registered admin actions for it 143 | """ 144 | model_class = content_type.model_class() 145 | app_label = content_type.app_label 146 | 147 | try: 148 | from django.contrib import admin 149 | 150 | except ImportError: 151 | # Django admin cannot be imported 152 | return None 153 | 154 | try: 155 | adminpy = __import__('%s.admin' % (app_label)) 156 | 157 | except ImportError: 158 | # No admin.py for this app can be imported 159 | return None 160 | 161 | # Will be a list of action strings, like "make_not_public" 162 | admin_action_strings = admin.site._registry[model_class].actions 163 | 164 | if admin_action_strings: 165 | admin_actions = admin.site._registry[model_class].get_actions(model_class) 166 | admin_actions_list = [] 167 | 168 | for admin_action_string in admin_action_strings: 169 | admin_action = admin_actions[admin_action_string] 170 | 171 | admin_actions_list.append({ 172 | 'name': str(admin_action[2]), 173 | 'url': str('/admin/%s/%s/' % (content_type.app_label, content_type.model)), 174 | 'action': 'remove_hostinfo', 175 | 'requires_perimission': 0, 176 | }) 177 | 178 | return admin_actions_list 179 | 180 | return None -------------------------------------------------------------------------------- /jumptoadmin/media/jumptoadmin/jumptoadmin.css: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------------------------------------------------------------------*/ 2 | /* ---------->>> global settings needed for thickbox <<<-----------------------------------------------------------*/ 3 | /* ----------------------------------------------------------------------------------------------------------------*/ 4 | *{padding: 0; margin: 0;} 5 | 6 | /* ----------------------------------------------------------------------------------------------------------------*/ 7 | /* ---------->>> thickbox specific link and font settings <<<------------------------------------------------------*/ 8 | /* ----------------------------------------------------------------------------------------------------------------*/ 9 | #TB_window { 10 | font: 12px Arial, Helvetica, sans-serif; 11 | color: #333333; 12 | } 13 | 14 | #TB_secondLine { 15 | font: 10px Arial, Helvetica, sans-serif; 16 | color:#666666; 17 | } 18 | 19 | #TB_window a:link {color: #666666;} 20 | #TB_window a:visited {color: #666666;} 21 | #TB_window a:hover {color: #000;} 22 | #TB_window a:active {color: #666666;} 23 | #TB_window a:focus{color: #666666;} 24 | 25 | /* ----------------------------------------------------------------------------------------------------------------*/ 26 | /* ---------->>> thickbox settings <<<-----------------------------------------------------------------------------*/ 27 | /* ----------------------------------------------------------------------------------------------------------------*/ 28 | #TB_overlay { 29 | position: fixed; 30 | z-index:100; 31 | top: 0px; 32 | left: 0px; 33 | height:100%; 34 | width:100%; 35 | } 36 | 37 | .TB_overlayMacFFBGHack {background: url(macFFBgHack.png) repeat;} 38 | .TB_overlayBG { 39 | background-color:#000; 40 | filter:alpha(opacity=75); 41 | -moz-opacity: 0.75; 42 | opacity: 0.75; 43 | } 44 | 45 | * html #TB_overlay { /* ie6 hack */ 46 | position: absolute; 47 | height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px'); 48 | } 49 | 50 | #TB_window { 51 | position: fixed; 52 | background: #ffffff; 53 | z-index: 102; 54 | color:#000000; 55 | display:none; 56 | border: 4px solid #525252; 57 | text-align:left; 58 | top:50%; 59 | left:50%; 60 | } 61 | 62 | * html #TB_window { /* ie6 hack */ 63 | position: absolute; 64 | margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px'); 65 | } 66 | 67 | #TB_window img#TB_Image { 68 | display:block; 69 | margin: 15px 0 0 15px; 70 | border-right: 1px solid #ccc; 71 | border-bottom: 1px solid #ccc; 72 | border-top: 1px solid #666; 73 | border-left: 1px solid #666; 74 | } 75 | 76 | #TB_caption{ 77 | height:25px; 78 | padding:7px 30px 10px 25px; 79 | float:left; 80 | } 81 | 82 | #TB_closeWindow{ 83 | height:25px; 84 | padding:11px 25px 10px 0; 85 | float:right; 86 | } 87 | 88 | #TB_closeAjaxWindow{ 89 | padding:7px 10px 5px 0; 90 | margin-bottom:1px; 91 | text-align:right; 92 | float:right; 93 | } 94 | 95 | #TB_ajaxWindowTitle{ 96 | float:left; 97 | padding:7px 0 5px 10px; 98 | margin-bottom:1px; 99 | } 100 | 101 | #TB_title{ 102 | background-color:#e8e8e8; 103 | height:27px; 104 | } 105 | 106 | #TB_ajaxContent{ 107 | clear:both; 108 | padding:2px 15px 15px 15px; 109 | overflow:auto; 110 | text-align:left; 111 | line-height:1.4em; 112 | } 113 | 114 | #TB_ajaxContent.TB_modal{ 115 | padding:15px; 116 | } 117 | 118 | #TB_ajaxContent p{ 119 | padding:5px 0px 5px 0px; 120 | } 121 | 122 | #TB_load{ 123 | position: fixed; 124 | display:none; 125 | height:13px; 126 | width:208px; 127 | z-index:103; 128 | top: 50%; 129 | left: 50%; 130 | margin: -6px 0 0 -104px; /* -height/2 0 0 -width/2 */ 131 | } 132 | 133 | * html #TB_load { /* ie6 hack */ 134 | position: absolute; 135 | margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px'); 136 | } 137 | 138 | #TB_HideSelect{ 139 | z-index:99; 140 | position:fixed; 141 | top: 0; 142 | left: 0; 143 | background-color:#fff; 144 | border:none; 145 | filter:alpha(opacity=0); 146 | -moz-opacity: 0; 147 | opacity: 0; 148 | height:100%; 149 | width:100%; 150 | } 151 | 152 | * html #TB_HideSelect { /* ie6 hack */ 153 | position: absolute; 154 | height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px'); 155 | } 156 | 157 | #TB_iframeContent{ 158 | clear:both; 159 | border:none; 160 | margin-bottom:-1px; 161 | margin-top:1px; 162 | _margin-bottom:1px; 163 | } 164 | 165 | 166 | /* Adminlinks */ 167 | .jumptoadminflag_display { 168 | position: relative; 169 | } 170 | .jumptoadminlinks { 171 | position: absolute; 172 | top: 5px; 173 | right: 5px; 174 | margin: 0; 175 | padding: 0; 176 | z-index: 50000; 177 | width: 100px; 178 | background: #000; 179 | list-style-type: none; 180 | border: #666 solid 1px; 181 | -moz-border-radius: 0 0 12px 0; 182 | -webkit-border-radius: 0 0 12px 0; 183 | border-radius: 0 0 12px 0; 184 | -moz-box-shadow: 0 2px 4px #000; 185 | -webkit-box-shadow: 0 2px 4px #000; 186 | box-shadow: 0 2px 4px #000; 187 | } 188 | .jumptoadminlinks li { 189 | display: block; 190 | margin: 0; 191 | padding: 0; 192 | line-height: 12px; 193 | font-size: 12px; 194 | color: #999; 195 | border-bottom: #666 solid 1px; 196 | background: none; 197 | } 198 | .jumptoadminlinks li a, .jumptoadminlinks li.jumptoadminlinks_li_title { 199 | display: block; 200 | padding: 6px 0; 201 | font-size: 12px; 202 | line-height: 12px; 203 | text-indent: 5px; 204 | } 205 | .jumptoadminlinks li.jumptoadminlinks_li_title { 206 | position: relative; 207 | text-shadow: 0 1px .5px #000; 208 | text-transform: uppercase; 209 | font-size: 10px; 210 | background: #333; 211 | color: #ccc; 212 | } 213 | .jumptoadminlinks li a { 214 | color: #ccc; 215 | background: none; 216 | text-decoration: none; 217 | } 218 | .jumptoadminlinks li a:hover { 219 | color: #fff; 220 | text-decoration: none; 221 | } 222 | .jumptoadminlinks li.jumptoadmin_li_last { 223 | border-bottom: none; 224 | } 225 | 226 | .jumptoadminlinks li a.jumptoadminlinks_li_close { 227 | position: absolute; 228 | display: block; 229 | top: 0; 230 | right: 0; 231 | margin: 0; 232 | padding: 0; 233 | width: 24px; 234 | height: 24px; 235 | font-size: 10px; 236 | line-height: 24px; 237 | text-indent: 0; 238 | text-align: center; 239 | border-left: #666 solid 1px; 240 | background: #444; 241 | } 242 | .jumptoadminlinks li a.jumptoadminlinks_li_close:hover { 243 | background: #bbb; 244 | color: #000; 245 | text-shadow-color: #eaeaea; 246 | text-decoration: none; 247 | } 248 | /* Poof effect from http://www.kombine.net/jquery/jquery-poof-effect */ 249 | .poof { 250 | background: transparent url(poof.png) no-repeat 0 0; 251 | cursor: pointer; 252 | display: none; 253 | height: 32px; 254 | position: absolute; 255 | width: 32px; 256 | } -------------------------------------------------------------------------------- /jumptoadmin/media/jumptoadmin/thickbox.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Thickbox 3.1 - One Box To Rule Them All. 3 | * By Cody Lindley (http://www.codylindley.com) 4 | * Copyright (c) 2007 cody lindley 5 | * Licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | */ 7 | 8 | var tb_pathToImage = "./loadingAnimation.gif"; 9 | 10 | /*!!!!!!!!!!!!!!!!! edit below this line at your own risk !!!!!!!!!!!!!!!!!!!!!!!*/ 11 | 12 | //on page load call tb_init 13 | $(document).ready(function(){ 14 | //tb_init('a.thickbox, area.thickbox, input.thickbox');//pass where to apply thickbox 15 | //imgLoader = new Image();// preload image 16 | //imgLoader.src = tb_pathToImage; 17 | }); 18 | 19 | //add thickbox to href & area elements that have a class of .thickbox 20 | /* 21 | function tb_init(domChunk){ 22 | $(domChunk).click(function(){ 23 | var t = this.title || this.name || null; 24 | var a = this.href || this.alt; 25 | var g = this.rel || false; 26 | tb_show(t,a,g); 27 | this.blur(); 28 | return false; 29 | }); 30 | } 31 | */ 32 | 33 | function tb_show(caption, url, postParams, imageGroup) {//function called when the user clicks on a thickbox link 34 | 35 | try { 36 | if (typeof document.body.style.maxHeight === "undefined") {//if IE 6 37 | $("body","html").css({height: "100%", width: "100%"}); 38 | $("html").css("overflow","hidden"); 39 | if (document.getElementById("TB_HideSelect") === null) {//iframe to hide select elements in ie6 40 | $("body").append("
"); 41 | $("#TB_overlay").click(tb_remove); 42 | } 43 | }else{//all others 44 | if(document.getElementById("TB_overlay") === null){ 45 | $("body").append("
"); 46 | $("#TB_overlay").click(tb_remove); 47 | } 48 | } 49 | 50 | if(tb_detectMacXFF()){ 51 | $("#TB_overlay").addClass("TB_overlayMacFFBGHack");//use png overlay so hide flash 52 | }else{ 53 | $("#TB_overlay").addClass("TB_overlayBG");//use background and opacity 54 | } 55 | 56 | if(caption===null){caption="";} 57 | $("body").append("
Loading
");//add loader to the page 58 | $('#TB_load').show();//show loader 59 | 60 | var baseURL; 61 | if(url.indexOf("?")!==-1){ //ff there is a query string involved 62 | baseURL = url.substr(0, url.indexOf("?")); 63 | }else{ 64 | baseURL = url; 65 | } 66 | 67 | var urlString = /\.jpg$|\.jpeg$|\.png$|\.gif$|\.bmp$/; 68 | var urlType = baseURL.toLowerCase().match(urlString); 69 | 70 | if(urlType == '.jpg' || urlType == '.jpeg' || urlType == '.png' || urlType == '.gif' || urlType == '.bmp'){//code to show images 71 | 72 | TB_PrevCaption = ""; 73 | TB_PrevURL = ""; 74 | TB_PrevHTML = ""; 75 | TB_NextCaption = ""; 76 | TB_NextURL = ""; 77 | TB_NextHTML = ""; 78 | TB_imageCount = ""; 79 | TB_FoundURL = false; 80 | if(imageGroup){ 81 | TB_TempArray = $("a[@rel="+imageGroup+"]").get(); 82 | for (TB_Counter = 0; ((TB_Counter < TB_TempArray.length) && (TB_NextHTML === "")); TB_Counter++) { 83 | var urlTypeTemp = TB_TempArray[TB_Counter].href.toLowerCase().match(urlString); 84 | if (!(TB_TempArray[TB_Counter].href == url)) { 85 | if (TB_FoundURL) { 86 | TB_NextCaption = TB_TempArray[TB_Counter].title; 87 | TB_NextURL = TB_TempArray[TB_Counter].href; 88 | TB_NextHTML = "  Next >"; 89 | } else { 90 | TB_PrevCaption = TB_TempArray[TB_Counter].title; 91 | TB_PrevURL = TB_TempArray[TB_Counter].href; 92 | TB_PrevHTML = "  < Prev"; 93 | } 94 | } else { 95 | TB_FoundURL = true; 96 | TB_imageCount = "Image " + (TB_Counter + 1) +" of "+ (TB_TempArray.length); 97 | } 98 | } 99 | } 100 | 101 | imgPreloader = new Image(); 102 | imgPreloader.onload = function(){ 103 | imgPreloader.onload = null; 104 | 105 | // Resizing large images - orginal by Christian Montoya edited by me. 106 | var pagesize = tb_getPageSize(); 107 | var x = pagesize[0] - 150; 108 | var y = pagesize[1] - 150; 109 | var imageWidth = imgPreloader.width; 110 | var imageHeight = imgPreloader.height; 111 | if (imageWidth > x) { 112 | imageHeight = imageHeight * (x / imageWidth); 113 | imageWidth = x; 114 | if (imageHeight > y) { 115 | imageWidth = imageWidth * (y / imageHeight); 116 | imageHeight = y; 117 | } 118 | } else if (imageHeight > y) { 119 | imageWidth = imageWidth * (y / imageHeight); 120 | imageHeight = y; 121 | if (imageWidth > x) { 122 | imageHeight = imageHeight * (x / imageWidth); 123 | imageWidth = x; 124 | } 125 | } 126 | // End Resizing 127 | 128 | TB_WIDTH = imageWidth + 30; 129 | TB_HEIGHT = imageHeight + 60; 130 | $("#TB_window").append(""+caption+"" + "
"+caption+"
" + TB_imageCount + TB_PrevHTML + TB_NextHTML + "
close or Esc Key
"); 131 | 132 | $("#TB_closeWindowButton").click(tb_remove); 133 | 134 | if (!(TB_PrevHTML === "")) { 135 | function goPrev(){ 136 | if($(document).unbind("click",goPrev)){$(document).unbind("click",goPrev);} 137 | $("#TB_window").remove(); 138 | $("body").append("
"); 139 | tb_show(TB_PrevCaption, TB_PrevURL, imageGroup); 140 | return false; 141 | } 142 | $("#TB_prev").click(goPrev); 143 | } 144 | 145 | if (!(TB_NextHTML === "")) { 146 | function goNext(){ 147 | $("#TB_window").remove(); 148 | $("body").append("
"); 149 | tb_show(TB_NextCaption, TB_NextURL, imageGroup); 150 | return false; 151 | } 152 | $("#TB_next").click(goNext); 153 | 154 | } 155 | 156 | document.onkeydown = function(e){ 157 | if (e == null) { // ie 158 | keycode = event.keyCode; 159 | } else { // mozilla 160 | keycode = e.which; 161 | } 162 | if(keycode == 27){ // close 163 | tb_remove(); 164 | } else if(keycode == 190){ // display previous image 165 | if(!(TB_NextHTML == "")){ 166 | document.onkeydown = ""; 167 | goNext(); 168 | } 169 | } else if(keycode == 188){ // display next image 170 | if(!(TB_PrevHTML == "")){ 171 | document.onkeydown = ""; 172 | goPrev(); 173 | } 174 | } 175 | }; 176 | 177 | tb_position(); 178 | $("#TB_load").remove(); 179 | $("#TB_ImageOff").click(tb_remove); 180 | $("#TB_window").css({display:"block"}); //for safari using css instead of show 181 | }; 182 | 183 | imgPreloader.src = url; 184 | }else{//code to show html 185 | 186 | var queryString = url.replace(/^[^\?]+\??/,''); 187 | var params = tb_parseQuery( queryString ); 188 | 189 | TB_WIDTH = (params['width']*1) + 30 || 630; //defaults to 630 if no paramaters were added to URL 190 | TB_HEIGHT = (params['height']*1) + 40 || 440; //defaults to 440 if no paramaters were added to URL 191 | ajaxContentW = TB_WIDTH - 30; 192 | ajaxContentH = TB_HEIGHT - 45; 193 | 194 | if(url.indexOf('TB_iframe') != -1){// either iframe or ajax window 195 | urlNoQuery = url.split('TB_'); 196 | $("#TB_iframeContent").remove(); 197 | if(params['modal'] != "true"){//iframe no modal 198 | $("#TB_window").append("
"+caption+"
close or Esc Key
"); 199 | }else{//iframe modal 200 | $("#TB_overlay").unbind(); 201 | $("#TB_window").append(""); 202 | } 203 | }else{// not an iframe, ajax 204 | if($("#TB_window").css("display") != "block"){ 205 | if(params['modal'] != "true"){//ajax no modal 206 | $("#TB_window").append("
"+caption+"
close or Esc Key
"); 207 | }else{//ajax modal 208 | $("#TB_overlay").unbind(); 209 | $("#TB_window").append("
"); 210 | } 211 | }else{//this means the window is already up, we are just loading new content via ajax 212 | $("#TB_ajaxContent")[0].style.width = ajaxContentW +"px"; 213 | $("#TB_ajaxContent")[0].style.height = ajaxContentH +"px"; 214 | $("#TB_ajaxContent")[0].scrollTop = 0; 215 | $("#TB_ajaxWindowTitle").html(caption); 216 | } 217 | } 218 | 219 | $("#TB_closeWindowButton").click(tb_remove); 220 | 221 | if(url.indexOf('TB_inline') != -1){ 222 | $("#TB_ajaxContent").append($('#' + params['inlineId']).children()); 223 | $("#TB_window").unload(function () { 224 | $('#' + params['inlineId']).append( $("#TB_ajaxContent").children() ); // move elements back when you're finished 225 | }); 226 | tb_position(); 227 | $("#TB_load").remove(); 228 | $("#TB_window").css({display:"block"}); 229 | }else if(url.indexOf('TB_iframe') != -1){ 230 | tb_position(); 231 | if($.browser.safari){//safari needs help because it will not fire iframe onload 232 | $("#TB_load").remove(); 233 | $("#TB_window").css({display:"block"}); 234 | } 235 | }else{ 236 | $("#TB_ajaxContent").load(url.split('?')[0], postParams, function(){//to do a post change this load method 237 | tb_position(); 238 | $("#TB_load").remove(); 239 | //tb_init("#TB_ajaxContent a.thickbox"); 240 | //tb_show(caption, url, postParams, imageGroup); 241 | $("#TB_window").css({display:"block"}); 242 | }); 243 | } 244 | 245 | } 246 | 247 | if(!params['modal']){ 248 | document.onkeyup = function(e){ 249 | if (e == null) { // ie 250 | keycode = event.keyCode; 251 | } else { // mozilla 252 | keycode = e.which; 253 | } 254 | if(keycode == 27){ // close 255 | tb_remove(); 256 | } 257 | }; 258 | } 259 | 260 | } catch(e) { 261 | //nothing here 262 | } 263 | } 264 | 265 | //helper functions below 266 | function tb_showIframe(){ 267 | $("#TB_load").remove(); 268 | $("#TB_window").css({display:"block"}); 269 | } 270 | 271 | function tb_remove() { 272 | $("#TB_imageOff").unbind("click"); 273 | $("#TB_closeWindowButton").unbind("click"); 274 | $("#TB_window").fadeOut("fast",function(){$('#TB_window,#TB_overlay,#TB_HideSelect').trigger("unload").unbind().remove();}); 275 | $("#TB_load").remove(); 276 | if (typeof document.body.style.maxHeight == "undefined") {//if IE 6 277 | $("body","html").css({height: "auto", width: "auto"}); 278 | $("html").css("overflow",""); 279 | } 280 | document.onkeydown = ""; 281 | document.onkeyup = ""; 282 | return false; 283 | } 284 | 285 | function tb_position() { 286 | $("#TB_window").css({marginLeft: '-' + parseInt((TB_WIDTH / 2),10) + 'px', width: TB_WIDTH + 'px'}); 287 | if ( !(jQuery.browser.msie && jQuery.browser.version < 7)) { // take away IE6 288 | $("#TB_window").css({marginTop: '-' + parseInt((TB_HEIGHT / 2),10) + 'px'}); 289 | } 290 | } 291 | 292 | function tb_parseQuery ( query ) { 293 | var Params = {}; 294 | if ( ! query ) {return Params;}// return empty object 295 | var Pairs = query.split(/[;&]/); 296 | for ( var i = 0; i < Pairs.length; i++ ) { 297 | var KeyVal = Pairs[i].split('='); 298 | if ( ! KeyVal || KeyVal.length != 2 ) {continue;} 299 | var key = unescape( KeyVal[0] ); 300 | var val = unescape( KeyVal[1] ); 301 | val = val.replace(/\+/g, ' '); 302 | Params[key] = val; 303 | } 304 | return Params; 305 | } 306 | 307 | function tb_getPageSize(){ 308 | var de = document.documentElement; 309 | var w = window.innerWidth || self.innerWidth || (de&&de.clientWidth) || document.body.clientWidth; 310 | var h = window.innerHeight || self.innerHeight || (de&&de.clientHeight) || document.body.clientHeight; 311 | arrayPageSize = [w,h]; 312 | return arrayPageSize; 313 | } 314 | 315 | function tb_detectMacXFF() { 316 | var userAgent = navigator.userAgent.toLowerCase(); 317 | if (userAgent.indexOf('mac') != -1 && userAgent.indexOf('firefox')!=-1) { 318 | return true; 319 | } 320 | } 321 | 322 | --------------------------------------------------------------------------------