More mobile view improvements, various
This commit is contained in:
		
							parent
							
								
									14ac7aa198
								
							
						
					
					
						commit
						7f14f50ee0
					
				
					 11 changed files with 92 additions and 56 deletions
				
			
		|  | @ -3,21 +3,29 @@ | |||
|  * Global styles for mobile templates | ||||
|  ****************************************/ | ||||
| 
 | ||||
| /* main user menu button when root */ | ||||
| [data-role="header"] a.root-user, | ||||
| [data-role="header"] a.root-user:hover { | ||||
|     background-color: red; | ||||
| } | ||||
| 
 | ||||
| /* become/stop root menu links */ | ||||
| #usermenu .root-user a { | ||||
|     background-color: red; | ||||
| } | ||||
| 
 | ||||
| /* normal flash messages */ | ||||
| .flash { | ||||
|     color: green; | ||||
|     margin-bottom: 1em; | ||||
| } | ||||
| 
 | ||||
| /* error flash messages */ | ||||
| .error { | ||||
|     color: red; | ||||
|     margin-bottom: 1em; | ||||
| } | ||||
| 
 | ||||
| .replacement-header { | ||||
|     display: none; | ||||
| } | ||||
| 
 | ||||
| /* used by login page */ | ||||
| .error { | ||||
|     color: red; | ||||
|     margin-bottom: 1em; | ||||
| } | ||||
|  |  | |||
|  | @ -36,6 +36,11 @@ $(document).on('pageshow', function() { | |||
|     if (el.is(':visible')) { | ||||
|         el.focus(); | ||||
|     } | ||||
| 
 | ||||
|     // TODO: seems like this should be better somehow...
 | ||||
|     // remove all flash messages after 2.5 seconds
 | ||||
|     window.setTimeout(function() { $('.flash, .error').remove(); }, 2500); | ||||
| 
 | ||||
| }); | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -18,11 +18,6 @@ | |||
|     ${form.begin(**{'data-ajax': 'false'})} | ||||
|     ${form.hidden('referrer', value=referrer)} | ||||
| 
 | ||||
|     ## this is used by mobile view | ||||
|     % if error: | ||||
|         <div class="error">${error}</div> | ||||
|     % endif | ||||
| 
 | ||||
|     ${form.field_div('username', form.text('username'))} | ||||
|     ${form.field_div('password', form.password('password'))} | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| ## -*- coding: utf-8 -*- | ||||
| <%inherit file="/mobile/base.mako" /> | ||||
| 
 | ||||
| <%def name="title()">About ${project_title}</%def> | ||||
| <%def name="title()">About ${self.app_title()}</%def> | ||||
| 
 | ||||
| <h2>${project_title} ${project_version}</h2> | ||||
| 
 | ||||
|  |  | |||
|  | @ -22,18 +22,20 @@ | |||
| <%def name="mobile_body()"> | ||||
|   <body> | ||||
| 
 | ||||
|     ## note that our toolbars are *external* (in jqm-speak) by default | ||||
| 
 | ||||
|     ${self.mobile_header()} | ||||
| 
 | ||||
|     <div data-role="page" data-url="${self.page_url()}"${' data-rel="dialog"' if dialog else ''|n}> | ||||
| 
 | ||||
|       ${self.mobile_usermenu()} | ||||
| 
 | ||||
|       ${self.mobile_header()} | ||||
| 
 | ||||
|       ${self.mobile_page_body()} | ||||
| 
 | ||||
|       ${self.mobile_footer()} | ||||
| 
 | ||||
|     </div><!-- page --> | ||||
| 
 | ||||
|     ${self.mobile_footer()} | ||||
| 
 | ||||
|   </body> | ||||
| </%def> | ||||
| 
 | ||||
|  | @ -67,14 +69,14 @@ | |||
|   <div id="usermenu" data-role="panel" data-display="overlay"> | ||||
|     <ul data-role="listview"> | ||||
|       <li data-icon="home">${h.link_to("Home", url('mobile.home'))}</li> | ||||
|       % if request.has_perm('datasync.restart'): | ||||
|           <li>${h.link_to("DataSync", url('datasync.mobile'))}</li> | ||||
|       % endif | ||||
|       % if request.is_root: | ||||
|           <li class="root-user" data-icon="forbidden">${h.link_to("Stop being root", url('stop_root'), **{'data-ajax': 'false'})}</li> | ||||
|       % elif request.is_admin: | ||||
|           <li class="root-user" data-icon="forbidden">${h.link_to("Become root", url('become_root'), **{'data-ajax': 'false'})}</li> | ||||
|       % endif | ||||
|       % if request.has_perm('datasync.restart'): | ||||
|           <li>${h.link_to("DataSync", url('datasync.mobile'))}</li> | ||||
|       % endif | ||||
|       <li data-icon="lock">${h.link_to("Logout", url('logout'), **{'data-ajax': 'false'})}</li> | ||||
|       <li data-icon="info">${h.link_to("About {}".format(capture(self.app_title)), url('mobile.about'))}</li> | ||||
|     </ul> | ||||
|  | @ -83,6 +85,19 @@ | |||
| 
 | ||||
| <%def name="mobile_page_body()"> | ||||
|   <div role="main" class="ui-content"> | ||||
| 
 | ||||
|     % if request.session.peek_flash('error'): | ||||
|         % for error in request.session.pop_flash('error'): | ||||
|             <div class="error">${error}</div> | ||||
|         % endfor | ||||
|     % endif | ||||
| 
 | ||||
|     % if request.session.peek_flash(): | ||||
|         % for msg in request.session.pop_flash(): | ||||
|             <div class="flash">${msg|n}</div> | ||||
|         % endfor | ||||
|     % endif | ||||
| 
 | ||||
|     % if capture(self.page_title): | ||||
|         <h2>${self.page_title()}</h2> | ||||
|     % endif | ||||
|  |  | |||
|  | @ -4,17 +4,17 @@ | |||
| <%def name="mobile_body()"> | ||||
|   <body> | ||||
| 
 | ||||
|     ${self.mobile_header()} | ||||
| 
 | ||||
|     <div data-role="page" data-url="${self.page_url()}"${' data-rel="dialog"' if dialog else ''|n}> | ||||
| 
 | ||||
|       ${self.mobile_usermenu()} | ||||
| 
 | ||||
|       ${self.mobile_header()} | ||||
| 
 | ||||
|       ${self.mobile_page_body()} | ||||
| 
 | ||||
|       ${self.mobile_footer()} | ||||
| 
 | ||||
|     </div><!-- page --> | ||||
| 
 | ||||
|     ${self.mobile_footer()} | ||||
| 
 | ||||
|   </body> | ||||
| </%def> | ||||
|  | @ -4,5 +4,5 @@ | |||
| <%def name="title()">DataSync</%def> | ||||
| 
 | ||||
| ${h.form(url('datasync.restart'))} | ||||
| ${h.submit('restart', "Restart DataSync", id='datasync-restart')} | ||||
| ${h.submit('restart', "Restart DataSync Daemon", id='datasync-restart')} | ||||
| ${h.end_form()} | ||||
|  |  | |||
|  | @ -27,36 +27,24 @@ Pyramid Views | |||
| from __future__ import unicode_literals, absolute_import | ||||
| 
 | ||||
| from .core import View | ||||
| from tailbone.views.grids import ( | ||||
| from .master import MasterView | ||||
| 
 | ||||
| # TODO: deprecate / remove some of this | ||||
| from .autocomplete import AutocompleteView | ||||
| from .crud import CrudView | ||||
| from .grids import ( | ||||
|     GridView, AlchemyGridView, SortableAlchemyGridView, | ||||
|     PagedAlchemyGridView, SearchableAlchemyGridView) | ||||
| from .crud import CrudView | ||||
| from .master import MasterView | ||||
| from tailbone.views.autocomplete import AutocompleteView | ||||
| 
 | ||||
| 
 | ||||
| def home(request): | ||||
|     """ | ||||
|     Default home view. | ||||
|     """ | ||||
| 
 | ||||
|     return {} | ||||
| 
 | ||||
| 
 | ||||
| def add_routes(config): | ||||
|     config.add_route('home', '/') | ||||
| 
 | ||||
| 
 | ||||
| def includeme(config): | ||||
|     add_routes(config) | ||||
| 
 | ||||
|     config.add_view(home, route_name='home', | ||||
|                     renderer='/home.mako') | ||||
| 
 | ||||
|     # core views | ||||
|     config.include('tailbone.views.core') | ||||
|     config.include('tailbone.views.common') | ||||
| 
 | ||||
|     config.include('tailbone.views.auth') | ||||
| 
 | ||||
|     # main table views | ||||
|     config.include('tailbone.views.bouncer') | ||||
|     config.include('tailbone.views.brands') | ||||
|     config.include('tailbone.views.categories') | ||||
|  | @ -87,5 +75,6 @@ def includeme(config): | |||
|     config.include('tailbone.views.users') | ||||
|     config.include('tailbone.views.vendors') | ||||
| 
 | ||||
|     # batch views | ||||
|     config.include('tailbone.views.batches') | ||||
|     config.include('tailbone.views.batch.pricing') | ||||
|  |  | |||
|  | @ -98,8 +98,7 @@ class AuthenticationView(View): | |||
| 
 | ||||
|         # redirect if already logged in | ||||
|         if self.request.user: | ||||
|             if not mobile: | ||||
|                 self.request.session.flash("{} is already logged in".format(self.request.user), 'error') | ||||
|             self.request.session.flash("{} is already logged in".format(self.request.user), 'error') | ||||
|             return self.redirect(referrer) | ||||
| 
 | ||||
|         form = Form(self.request, schema=UserLogin) | ||||
|  | @ -111,14 +110,11 @@ class AuthenticationView(View): | |||
|             if user: | ||||
|                 # okay now they're truly logged in | ||||
|                 headers = remember(self.request, user.uuid) | ||||
|                 # Treat URL from session as referrer, if available. | ||||
|                 # treat URL from session as referrer, if available | ||||
|                 referrer = self.request.session.pop('next_url', referrer) | ||||
|                 return self.redirect(referrer, headers=headers) | ||||
|             else: | ||||
|                 if mobile: | ||||
|                     context['error'] = "Invalid username or password" | ||||
|                 else: | ||||
|                     self.request.session.flash("Invalid username or password") | ||||
|                 self.request.session.flash("Invalid username or password", 'error') | ||||
|         return context | ||||
| 
 | ||||
|     def mobile_login(self): | ||||
|  |  | |||
|  | @ -56,6 +56,18 @@ class CommonView(View): | |||
|     project_title = "Tailbone" | ||||
|     project_version = tailbone.__version__ | ||||
| 
 | ||||
|     def home(self, mobile=False): | ||||
|         """ | ||||
|         Home page view. | ||||
|         """ | ||||
|         return {} | ||||
| 
 | ||||
|     def mobile_home(self): | ||||
|         """ | ||||
|         Home page view for mobile. | ||||
|         """ | ||||
|         return self.home(mobile=True) | ||||
| 
 | ||||
|     def about(self): | ||||
|         """ | ||||
|         Generic view to show "about project" info page. | ||||
|  | @ -90,18 +102,35 @@ class CommonView(View): | |||
|             return httpexceptions.HTTPFound(location=form.data['referrer']) | ||||
|         return {'form': forms.FormRenderer(form)} | ||||
| 
 | ||||
|     def bogus_error(self): | ||||
|         """ | ||||
|         A special view which simply raises an error, for the sake of testing | ||||
|         uncaught exception handling. | ||||
|         """ | ||||
|         raise Exception("Congratulations, you have triggered a bogus error.") | ||||
|      | ||||
|     @classmethod | ||||
|     def defaults(cls, config): | ||||
| 
 | ||||
|         # home | ||||
|         config.add_route('home', '/') | ||||
|         config.add_view(cls, attr='home', route_name='home', renderer='/home.mako') | ||||
|         config.add_route('mobile.home', '/mobile/') | ||||
|         config.add_view(cls, attr='mobile_home', route_name='mobile.home', renderer='/mobile/home.mako') | ||||
| 
 | ||||
|         # about | ||||
|         config.add_route('about', '/about') | ||||
|         config.add_view(cls, attr='about', route_name='about', renderer='/about.mako') | ||||
|         config.add_route('mobile.about', '/mobile/about') | ||||
|         config.add_view(cls, attr='about', route_name='mobile.about', renderer='/mobile/about.mako') | ||||
| 
 | ||||
|         # feedback | ||||
|         config.add_route('feedback', '/feedback') | ||||
|         config.add_view(cls, attr='feedback', route_name='feedback', | ||||
|                         renderer='/feedback.mako') | ||||
|         config.add_view(cls, attr='feedback', route_name='feedback', renderer='/feedback.mako') | ||||
| 
 | ||||
|         # bogus error | ||||
|         config.add_route('bogus_error', '/bogus-error') | ||||
|         config.add_view(cls, attr='bogus_error', route_name='bogus_error', permission='errors.bogus') | ||||
| 
 | ||||
| 
 | ||||
| def includeme(config): | ||||
|  |  | |||
|  | @ -30,7 +30,6 @@ import subprocess | |||
| import logging | ||||
| 
 | ||||
| from rattail.db import model | ||||
| from rattail.config import parse_list | ||||
| 
 | ||||
| from tailbone.views import MasterView | ||||
| 
 | ||||
|  | @ -66,7 +65,7 @@ class DataSyncChangesView(MasterView): | |||
|     def restart(self): | ||||
|         # TODO: Add better validation (e.g. CSRF) here? | ||||
|         if self.request.method == 'POST': | ||||
|             cmd = parse_list(self.rattail_config.require('tailbone', 'datasync.restart')) | ||||
|             cmd = self.rattail_config.getlist('tailbone', 'datasync.restart', default='/bin/sleep 3') # simulate by default | ||||
|             log.debug("attempting datasync restart with command: {}".format(cmd)) | ||||
|             result = subprocess.call(cmd) | ||||
|             if result == 0: | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Lance Edgar
						Lance Edgar