admin based on bootstrap, thanks Paolo
This commit is contained in:
6
ABOUT
Normal file
6
ABOUT
Normal file
@@ -0,0 +1,6 @@
|
||||
web2py is an open source full-stack framework for agile development
|
||||
of secure database-driven web-based applications, written and programmable in
|
||||
Python.
|
||||
|
||||
Created by Massimo Di Pierro <mdipierro@cs.depaul.edu>
|
||||
|
||||
0
Introduction
Normal file
0
Introduction
Normal file
2
VERSION
2
VERSION
@@ -1 +1 @@
|
||||
Version 2.4.1-alpha.1+timestamp.2012.12.24.12.13.23
|
||||
Version 2.4.1-alpha.1+timestamp.2012.12.24.13.48.18
|
||||
|
||||
85
app.yaml
Normal file
85
app.yaml
Normal file
@@ -0,0 +1,85 @@
|
||||
# For Google App Engine deployment, copy this file to app.yaml
|
||||
# and edit as required
|
||||
# See http://code.google.com/appengine/docs/python/config/appconfig.html
|
||||
# and http://web2py.com/book/default/chapter/11?search=app.yaml
|
||||
|
||||
application: web2py
|
||||
version: 1
|
||||
api_version: 1
|
||||
|
||||
# use this line for Python 2.5
|
||||
#
|
||||
runtime: python
|
||||
|
||||
# use these lines for Python 2.7
|
||||
# upload app with: appcfg.py update web2py (where 'web2py' is web2py's root directory)
|
||||
#
|
||||
# runtime: python27
|
||||
# threadsafe: true # true for WSGI & concurrent requests (Python 2.7 only)
|
||||
|
||||
default_expiration: "24h" # for static files
|
||||
|
||||
handlers:
|
||||
|
||||
- url: /(?P<a>.+?)/static/(?P<b>.+)
|
||||
static_files: applications/\1/static/\2
|
||||
upload: applications/(.+?)/static/(.+)
|
||||
secure: optional
|
||||
|
||||
- url: /favicon.ico
|
||||
static_files: applications/welcome/static/favicon.ico
|
||||
upload: applications/welcome/static/favicon.ico
|
||||
|
||||
- url: /robots.txt
|
||||
static_files: applications/welcome/static/robots.txt
|
||||
upload: applications/welcome/static/robots.txt
|
||||
|
||||
- url: .*
|
||||
script: gaehandler.py # CGI
|
||||
# script: gaehandler.wsgiapp # WSGI (Python 2.7 only)
|
||||
secure: optional
|
||||
|
||||
admin_console:
|
||||
pages:
|
||||
- name: Appstats
|
||||
url: /_ah/stats
|
||||
|
||||
skip_files: |
|
||||
^(.*/)?(
|
||||
(app\.yaml)|
|
||||
(app\.yml)|
|
||||
(index\.yaml)|
|
||||
(index\.yml)|
|
||||
(#.*#)|
|
||||
(.*~)|
|
||||
(.*\.py[co])|
|
||||
(.*/RCS/.*)|
|
||||
(\..*)|
|
||||
(applications/(admin|examples)/.*)|
|
||||
((admin|examples|welcome)\.(w2p|tar))|
|
||||
(applications/.*?/(cron|databases|errors|cache|sessions)/.*)|
|
||||
((logs|scripts)/.*)|
|
||||
(anyserver\.py)|
|
||||
(web2py\.py)|
|
||||
((cgi|fcgi|modpython|wsgi)handler\.py)|
|
||||
(epydoc\.(conf|css))|
|
||||
(httpserver\.log)|
|
||||
(logging\.example\.conf)|
|
||||
(route[rs]\.example\.py)|
|
||||
(setup_(app|exe)\.py)|
|
||||
(splashlogo\.gif)|
|
||||
(parameters_\d+\.py)|
|
||||
(options_std.py)|
|
||||
(gluon/tests/.*)|
|
||||
(gluon/(rocket|winservice)\.py)|
|
||||
(contrib/(gateways|markdown|memcache|pymysql)/.*)|
|
||||
(contrib/(populate|taskbar_widget)\.py)|
|
||||
(google_appengine/.*)|
|
||||
(.*\.(bak|orig))|
|
||||
)$
|
||||
|
||||
builtins:
|
||||
- remote_api: on
|
||||
- appstats: on
|
||||
- admin_redirect: on
|
||||
- deferred: on
|
||||
@@ -168,7 +168,8 @@ def change_password():
|
||||
form = SQLFORM.factory(Field('current_admin_password', 'password'),
|
||||
Field('new_admin_password',
|
||||
'password', requires=IS_STRONG()),
|
||||
Field('new_admin_password_again', 'password'))
|
||||
Field('new_admin_password_again', 'password'),
|
||||
_class="span4 well")
|
||||
if form.accepts(request.vars):
|
||||
if not verify_password(request.vars.current_admin_password):
|
||||
form.errors.current_admin_password = T('invalid password')
|
||||
@@ -202,12 +203,14 @@ def site():
|
||||
|
||||
is_appname = IS_VALID_APPNAME()
|
||||
form_create = SQLFORM.factory(Field('name', requires=is_appname),
|
||||
table_name='appcreate')
|
||||
table_name='appcreate',
|
||||
_class='well well-small')
|
||||
form_update = SQLFORM.factory(Field('name', requires=is_appname),
|
||||
Field('file', 'upload', uploadfield=False),
|
||||
Field('url'),
|
||||
Field('overwrite', 'boolean'),
|
||||
table_name='appupdate')
|
||||
table_name='appupdate',
|
||||
_class='well well-small')
|
||||
form_create.process()
|
||||
form_update.process()
|
||||
|
||||
@@ -374,6 +377,10 @@ def uninstall():
|
||||
|
||||
dialog = FORM.confirm(T('Uninstall'),
|
||||
{T('Cancel'): URL('site')})
|
||||
dialog['_id'] = 'confirm_form'
|
||||
dialog['_class'] = 'well'
|
||||
for component in dialog.components:
|
||||
component['_class'] = 'btn'
|
||||
|
||||
if dialog.accepted:
|
||||
if MULTI_USER_MODE:
|
||||
@@ -791,7 +798,8 @@ def resolve():
|
||||
diff = TABLE(*[TR(TD(gen_data(i, item)),
|
||||
TD(item[0]),
|
||||
TD(leading(item[2:]),
|
||||
TT(item[2:].rstrip())), _class=getclass(item))
|
||||
TT(item[2:].rstrip())),
|
||||
_class=getclass(item))
|
||||
for (i, item) in enumerate(d) if item[0] != '?'])
|
||||
|
||||
return dict(diff=diff, filename=filename)
|
||||
@@ -834,10 +842,14 @@ def edit_language():
|
||||
# Making the short circuit compatible with <= python2.4
|
||||
k = (s != k) and k or B(k)
|
||||
|
||||
rows.append(P(prefix, k, BR(), elem, TAG.BUTTON(T('delete'),
|
||||
_onclick='return delkey("%s")' % name), _id=name))
|
||||
new_row = DIV(LABEL(prefix, k, _style="font-weight:normal;"),
|
||||
CAT(elem, '\n', TAG.BUTTON(
|
||||
T('delete'),
|
||||
_onclick='return delkey("%s")' % name,
|
||||
_class='btn')), _id=name, _class='span6 well well-small')
|
||||
|
||||
rows.append(INPUT(_type='submit', _value=T('update')))
|
||||
rows.append(DIV(new_row,_class="row-fluid"))
|
||||
rows.append(DIV(INPUT(_type='submit', _value=T('update'), _class="btn btn-primary"), _class='controls'))
|
||||
form = FORM(*rows)
|
||||
if form.accepts(request.vars, keepvalues=True):
|
||||
strs = dict()
|
||||
@@ -868,29 +880,27 @@ def edit_plurals():
|
||||
|
||||
keys = sorted(plurals.keys(), lambda x, y: cmp(
|
||||
unicode(x, 'utf-8').lower(), unicode(y, 'utf-8').lower()))
|
||||
rows = []
|
||||
|
||||
row = [T("Singular Form")]
|
||||
row.extend([T("Plural Form #%s", n + 1) for n in xnplurals])
|
||||
table = TABLE(THEAD(TR(row)))
|
||||
|
||||
tab_rows = []
|
||||
for key in keys:
|
||||
name = md5_hash(key)
|
||||
forms = plurals[key]
|
||||
|
||||
if len(forms) < nplurals:
|
||||
forms.extend(None for i in xrange(nplurals - len(forms)))
|
||||
tab_col1 = DIV(CAT(LABEL(T("Singular Form")), B(key,
|
||||
_class='fake-input')))
|
||||
tab_inputs = [SPAN(LABEL(T("Plural Form #%s", n + 1)), INPUT(_type='text', _name=name + '_' + str(n), value=forms[n], _size=20), _class='span6') for n in xnplurals]
|
||||
tab_col2 = DIV(CAT(*tab_inputs))
|
||||
tab_col3 = DIV(CAT(LABEL(XML(' ')), TAG.BUTTON(T('delete'), _onclick='return delkey("%s")' % name, _class='btn'), _class='span6'))
|
||||
tab_row = DIV(DIV(tab_col1, '\n', tab_col2, '\n', tab_col3, _class='well well-small'), _id=name, _class='row-fluid tab_row')
|
||||
tab_rows.append(tab_row)
|
||||
|
||||
row = [B(key)]
|
||||
row.extend([INPUT(_type='text', _name=name + '_' + str(n),
|
||||
value=forms[n], _size=20) for n in xnplurals])
|
||||
row.append(TD(
|
||||
TAG.BUTTON(T('delete'), _onclick='return delkey("%s")' % name)))
|
||||
rows.append(TR(row, _id=name))
|
||||
if rows:
|
||||
table.append(TBODY(rows))
|
||||
rows = [table, INPUT(_type='submit', _value=T('update'))]
|
||||
form = FORM(*rows)
|
||||
tab_rows.append(DIV(TAG['button'](T('update'), _type='submit',
|
||||
_class='btn btn-primary'),
|
||||
_class='controls'))
|
||||
tab_container = DIV(*tab_rows, **dict(_class="row-fluid"))
|
||||
|
||||
form = FORM(tab_container)
|
||||
if form.accepts(request.vars, keepvalues=True):
|
||||
new_plurals = dict()
|
||||
for key in keys:
|
||||
|
||||
@@ -55,7 +55,7 @@ def index():
|
||||
reset(session)
|
||||
apps = os.listdir(os.path.join(request.folder, '..'))
|
||||
form = SQLFORM.factory(Field('name', requires=[IS_NOT_EMPTY(),
|
||||
IS_ALPHANUMERIC()]))
|
||||
IS_ALPHANUMERIC()]), _class='span5 well well-small')
|
||||
if form.accepts(request.vars):
|
||||
app = form.vars.name
|
||||
session.app['name'] = app
|
||||
@@ -125,19 +125,20 @@ def step1():
|
||||
default=params.get('login_method', 'local')),
|
||||
Field(
|
||||
'login_config', default=params.get('login_config', None)),
|
||||
Field('plugins', 'list:string', requires=IS_IN_SET(plugins, multiple=True)))
|
||||
Field('plugins', 'list:string', requires=IS_IN_SET(plugins, multiple=True)),
|
||||
_class='span7 well well-small')
|
||||
|
||||
if form.accepts(request.vars):
|
||||
session.app['params'] = [(key, form.vars.get(key, None))
|
||||
for key, value in session.app['params']]
|
||||
redirect(URL('step2'))
|
||||
redirect(URL('step2') + '/#xwizard_form')
|
||||
return dict(step='1: Setting Parameters', form=form)
|
||||
|
||||
|
||||
def step2():
|
||||
response.view = 'wizard/step.html'
|
||||
form = SQLFORM.factory(Field('table_names', 'list:string',
|
||||
default=session.app['tables']))
|
||||
default=session.app['tables']), _class="span7 well well-small")
|
||||
if form.accepts(request.vars):
|
||||
table_names = [clean(t) for t in listify(form.vars.table_names)
|
||||
if t.strip()]
|
||||
@@ -157,21 +158,21 @@ def step2():
|
||||
session.app['page_' + name] = \
|
||||
'## Manage %s\n\n{{=form}}' % (table)
|
||||
if session.app['tables']:
|
||||
redirect(URL('step3', args=0))
|
||||
redirect(URL('step3', args=0) + '/#xwizard_form')
|
||||
else:
|
||||
redirect(URL('step4'))
|
||||
redirect(URL('step4') + '/#xwizard_form')
|
||||
return dict(step='2: Tables', form=form)
|
||||
|
||||
|
||||
def step3():
|
||||
response.view = 'wizard/step.html'
|
||||
n = int(request.args(0) or 0)
|
||||
n = int(request.args(-1) or 0)
|
||||
m = len(session.app['tables'])
|
||||
if n >= m:
|
||||
redirect(URL('step2'))
|
||||
table = session.app['tables'][n]
|
||||
form = SQLFORM.factory(Field('field_names', 'list:string',
|
||||
default=session.app.get('table_' + table, [])))
|
||||
default=session.app.get('table_' + table, [])), _class="span7 well well-small")
|
||||
if form.accepts(request.vars) and form.vars.field_names:
|
||||
fields = listify(form.vars.field_names)
|
||||
if table == 'auth_user':
|
||||
@@ -187,9 +188,9 @@ def step3():
|
||||
response.flash = T('invalid circular reference')
|
||||
else:
|
||||
if n < m - 1:
|
||||
redirect(URL('step3', args=n + 1))
|
||||
redirect(URL('step3', args=n + 1) + '/#xwizard_form')
|
||||
else:
|
||||
redirect(URL('step4'))
|
||||
redirect(URL('step4') + '/#xwizard_form')
|
||||
return dict(step='3: Fields for table "%s" (%s of %s)'
|
||||
% (table, n + 1, m), table=table, form=form)
|
||||
|
||||
@@ -197,21 +198,21 @@ def step3():
|
||||
def step4():
|
||||
response.view = 'wizard/step.html'
|
||||
form = SQLFORM.factory(Field('pages', 'list:string',
|
||||
default=session.app['pages']))
|
||||
default=session.app['pages']), _class="span7 well well-small")
|
||||
if form.accepts(request.vars):
|
||||
session.app['pages'] = [clean(t)
|
||||
for t in listify(form.vars.pages)
|
||||
if t.strip()]
|
||||
if session.app['pages']:
|
||||
redirect(URL('step5', args=0))
|
||||
redirect(URL('step5', args=0) + '/#xwizard_form')
|
||||
else:
|
||||
redirect(URL('step6'))
|
||||
redirect(URL('step6') + '/#xwizard_form')
|
||||
return dict(step='4: Pages', form=form)
|
||||
|
||||
|
||||
def step5():
|
||||
response.view = 'wizard/step.html'
|
||||
n = int(request.args(0) or 0)
|
||||
n = int(request.args(-1) or 0)
|
||||
m = len(session.app['pages'])
|
||||
if n >= m:
|
||||
redirect(URL('step4'))
|
||||
@@ -221,13 +222,13 @@ def step5():
|
||||
default=session.app.get('page_' + page, []),
|
||||
comment=A('use markmin',
|
||||
_href=markmin_url, _target='_blank')),
|
||||
formstyle='table2cols')
|
||||
formstyle='table2cols', _class="span7 well well-small")
|
||||
if form.accepts(request.vars):
|
||||
session.app['page_' + page] = form.vars.content
|
||||
if n < m - 1:
|
||||
redirect(URL('step5', args=n + 1))
|
||||
redirect(URL('step5', args=n + 1) + '/#xwizard_form')
|
||||
else:
|
||||
redirect(URL('step6'))
|
||||
redirect(URL('step6') + '/#xwizard_form')
|
||||
return dict(step='5: View for page "%s" (%s of %s)' % (page, n + 1, m), form=form)
|
||||
|
||||
|
||||
@@ -242,7 +243,8 @@ def step6():
|
||||
Field('generate_menu', 'boolean', default=True),
|
||||
Field('apply_layout', 'boolean', default=True),
|
||||
Field('erase_database', 'boolean', default=True),
|
||||
Field('populate_database', 'boolean', default=True))
|
||||
Field('populate_database', 'boolean', default=True),
|
||||
_id="generate_form", _class="form-horizontal span7 well well-small")
|
||||
if form.accepts(request.vars):
|
||||
if DEMO_MODE:
|
||||
session.flash = T('Application cannot be generated in demo mode')
|
||||
|
||||
@@ -8,35 +8,33 @@ def A_button(*a, **b):
|
||||
b['_data-inline'] = 'true'
|
||||
return A(*a, **b)
|
||||
|
||||
|
||||
def button(href, label):
|
||||
if is_mobile:
|
||||
ret = A_button(SPAN(label), _href=href)
|
||||
else:
|
||||
ret = A(SPAN(label), _class='button', _href=href)
|
||||
ret = A(SPAN(label), _class='button btn', _href=href)
|
||||
return ret
|
||||
|
||||
|
||||
def button_enable(href, app):
|
||||
if os.path.exists(os.path.join(apath(app, r=request), 'DISABLED')):
|
||||
label = SPAN(T('Enable'), _style='color:red')
|
||||
else:
|
||||
label = SPAN(T('Disable'), _style='color:green')
|
||||
id = 'enable_' + app
|
||||
return A(label, _class='button', _id=id, callback=href, target=id)
|
||||
|
||||
return A(label, _class='button btn', _id=id, callback=href, target=id)
|
||||
|
||||
def sp_button(href, label):
|
||||
if request.user_agent().is_mobile:
|
||||
ret = A_button(SPAN(label), _href=href)
|
||||
else:
|
||||
ret = A(SPAN(label), _class='button special', _href=href)
|
||||
ret = A(SPAN(label), _class='button special btn btn-inverse', _href=href)
|
||||
return ret
|
||||
|
||||
|
||||
def helpicon():
|
||||
return IMG(_src=URL('static', 'images/help.png'), _alt='help')
|
||||
|
||||
|
||||
def searchbox(elementid):
|
||||
return TAG[''](LABEL(IMG(_id="search_start", _src=URL('static', 'images/search.png'), _alt=T('filter')), _class='icon', _for=elementid), ' ', INPUT(_id=elementid, _type='text', _size=12))
|
||||
return SPAN(LABEL(IMG(_id="search_start", _src=URL('static', 'images/search.png'), _alt=T('filter')),
|
||||
_class='icon', _for=elementid), ' ',
|
||||
INPUT(_id=elementid, _type='text', _size=12, _class="input-medium"),
|
||||
_class="searchbox")
|
||||
0
applications/admin/private/hosts.deny
Normal file
0
applications/admin/private/hosts.deny
Normal file
9
applications/admin/static/css/bootstrap-responsive.min.css
vendored
Normal file
9
applications/admin/static/css/bootstrap-responsive.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
9
applications/admin/static/css/bootstrap.min.css
vendored
Normal file
9
applications/admin/static/css/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
579
applications/admin/static/css/bootstrap_adapters.css
vendored
Normal file
579
applications/admin/static/css/bootstrap_adapters.css
vendored
Normal file
@@ -0,0 +1,579 @@
|
||||
/*=============================================================
|
||||
GENERAL
|
||||
==============================================================*/
|
||||
html,body{height:auto;background:transparent;}
|
||||
/*=============================================================
|
||||
CONTROLS
|
||||
==============================================================*/
|
||||
label,
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
textarea,
|
||||
button.btn
|
||||
{
|
||||
font-size:13px;
|
||||
font-weight:normal;
|
||||
line-height:18px;
|
||||
}
|
||||
textarea,
|
||||
select
|
||||
{
|
||||
margin-bottom:9px;
|
||||
}
|
||||
select,
|
||||
/*textarea,*/
|
||||
input[type="text"],
|
||||
input[type="password"],
|
||||
input[type="datetime"],
|
||||
input[type="datetime-local"],
|
||||
input[type="date"],
|
||||
input[type="month"],
|
||||
input[type="time"],
|
||||
input[type="week"],
|
||||
input[type="number"],
|
||||
input[type="email"],
|
||||
input[type="url"],
|
||||
input[type="search"],
|
||||
input[type="tel"],
|
||||
input[type="color"],
|
||||
.uneditable-input,
|
||||
a.btn-lnk
|
||||
{
|
||||
height:18px;
|
||||
padding:4px;
|
||||
font-size:13px;
|
||||
line-height:18px;
|
||||
}
|
||||
.design h3,
|
||||
.plugin h3
|
||||
{
|
||||
background-position:0 2px;
|
||||
}
|
||||
|
||||
select,
|
||||
input[type="file"]
|
||||
{
|
||||
height:28px;
|
||||
line-height:28px;
|
||||
}
|
||||
input[type="submit"],
|
||||
input[type="button"]
|
||||
{
|
||||
font-size:13px;
|
||||
height:28px;
|
||||
line-height:18px;
|
||||
padding:4px 10px;
|
||||
}
|
||||
input[type="radio"],
|
||||
input[type="checkbox"]
|
||||
{
|
||||
margin-top:2px;
|
||||
}
|
||||
.button.btn
|
||||
{
|
||||
line-height:1.25em;
|
||||
font-size:inherit;
|
||||
border:none;
|
||||
text-shadow:none;
|
||||
margin-bottom:0px;
|
||||
-webkit-border-radius:0px;
|
||||
-moz-border-radius:0px;
|
||||
border-radius:0px;
|
||||
-webkit-box-shadow:none;
|
||||
-moz-box-shadow:none;
|
||||
box-shadow:none);
|
||||
}
|
||||
.button.btn:hover
|
||||
{
|
||||
background-color:transparent;
|
||||
-webkit-transition: background-position 0s linear;
|
||||
-moz-transition: background-position 0s linear;
|
||||
-o-transition: background-position 0s linear;
|
||||
transition: background-position 0s linear;
|
||||
}
|
||||
form label
|
||||
{
|
||||
font-weight:bold;
|
||||
}
|
||||
.help
|
||||
{
|
||||
border-color:transparent;
|
||||
}
|
||||
/* tree menu */
|
||||
.folder
|
||||
{
|
||||
border:none;
|
||||
}
|
||||
.folder>i
|
||||
{
|
||||
display:none;
|
||||
}
|
||||
.celled
|
||||
{
|
||||
padding-top: 2px;
|
||||
}
|
||||
.celled-one
|
||||
{
|
||||
padding-top: 1px;
|
||||
}
|
||||
|
||||
.test h3
|
||||
{
|
||||
border:0;
|
||||
padding-left:18px;
|
||||
}
|
||||
/*=============================================================
|
||||
FLASH MESSAGEBOX
|
||||
==============================================================*/
|
||||
.flash
|
||||
{
|
||||
position:fixed;
|
||||
width:50%;
|
||||
top:49px;
|
||||
left:25%;
|
||||
right:25%;
|
||||
cursor:default;
|
||||
text-align:center;
|
||||
padding:8px 35px 8px 14px;
|
||||
z-index:5620;
|
||||
}
|
||||
.flash>.close
|
||||
{
|
||||
color:inherit;
|
||||
opacity:0.7;
|
||||
}
|
||||
.flash>.close:hover
|
||||
{
|
||||
opacity:0.9;
|
||||
}
|
||||
/*=============================================================
|
||||
NAVBAR
|
||||
==============================================================*/
|
||||
.navbar-fixed-top .navbar-inner,
|
||||
.navbar-static-top .navbar-inner
|
||||
{
|
||||
/* in place of shadow image */
|
||||
-webkit-box-shadow:0px 10px 20px rgba(195,195,195,1.0);
|
||||
-moz-box-shadow: 0px 10px 20px rgba(195,195,195,1.0);
|
||||
box-shadow: 0px 10px 20px rgba(195,195,195,1.0);
|
||||
//zoom:1; /* IE6-9 */
|
||||
filter:progid:DXImageTransform.Microsoft.DropShadow(OffX=0, OffY=10, Color=#000000); /* IE6-9 */
|
||||
padding:0;
|
||||
}
|
||||
.navbar-inverse .navbar-inner
|
||||
{
|
||||
min-height:33px; /* required - override */
|
||||
height:33px;
|
||||
filter:progid:DXImageTransform.Microsoft.gradient(enabled=false); /* IE6-9 */
|
||||
background:#292929 url(../images/header_bg.png) repeat-x;
|
||||
border:none;
|
||||
}
|
||||
#header
|
||||
{
|
||||
background:transparent;
|
||||
}
|
||||
#header.navbar
|
||||
{
|
||||
overflow:visible;
|
||||
}
|
||||
.navbar-inverse .nav > li > a
|
||||
{
|
||||
padding:0;
|
||||
line-height:1.25;
|
||||
text-shadow:none;
|
||||
}
|
||||
.navbar .btn-navbar
|
||||
{
|
||||
padding:4px;
|
||||
margin:5px 5px 0 5px;
|
||||
}
|
||||
#menu{margin-right:-7px;}
|
||||
/*=============================================================
|
||||
FOOTER
|
||||
==============================================================*/
|
||||
#footer
|
||||
{
|
||||
padding-bottom:0;
|
||||
}
|
||||
/*=============================================================
|
||||
MAIN
|
||||
==============================================================*/
|
||||
#main
|
||||
{
|
||||
position:static;
|
||||
padding-top:0;
|
||||
padding-bottom:0;
|
||||
}
|
||||
/*=============================================================
|
||||
SIDEBAR
|
||||
==============================================================*/
|
||||
.sidebar_inner
|
||||
{
|
||||
background:transparent;
|
||||
padding:0;
|
||||
min-width:auto;
|
||||
}
|
||||
.sidebar .box {
|
||||
border-top:1px solid #EEE;
|
||||
}
|
||||
/*=============================================================
|
||||
WIZARD
|
||||
==============================================================*/
|
||||
.step div.help li
|
||||
{
|
||||
line-height:inherit;
|
||||
}
|
||||
.ms-container .ms-selectable li.ms-elem-selectable,
|
||||
.ms-container .ms-selection li.ms-elem-selected
|
||||
{
|
||||
font-size:13px;
|
||||
}
|
||||
.input-append a.btn
|
||||
{
|
||||
padding:4px;
|
||||
height:18px;
|
||||
font-size:13px;
|
||||
line-height:18px;
|
||||
}
|
||||
/*=============================================================
|
||||
ERRORS TABLE
|
||||
==============================================================*/
|
||||
.errors .table th
|
||||
{
|
||||
filter:progid:DXImageTransform.Microsoft.gradient(enabled=false); /* IE6-9 */
|
||||
}
|
||||
|
||||
.tablebar span.help
|
||||
{
|
||||
font-weight:normal;
|
||||
line-height:1.25em;
|
||||
text-shadow:none;
|
||||
width:auto;
|
||||
}
|
||||
/*=============================================================
|
||||
TOOLTIP
|
||||
==============================================================*/
|
||||
.tooltip.in
|
||||
{
|
||||
opacity:1;
|
||||
filter:alpha(opacity=100);
|
||||
}
|
||||
.tooltip-inner
|
||||
{
|
||||
opacity:1;
|
||||
text-align:left;
|
||||
background:#9fb364;
|
||||
color:#eef1d9;
|
||||
border:1px solid #eef1d9;
|
||||
font-style:italic;
|
||||
padding:0.3em;
|
||||
-moz-border-radius:0.5em;
|
||||
border-radius:0.5em;
|
||||
font-size:13px;
|
||||
text-transform:none;
|
||||
}
|
||||
.tooltip.right .tooltip-arrow,
|
||||
.tooltip.left .tooltip-arrow
|
||||
{
|
||||
border-color:transparent;
|
||||
}
|
||||
|
||||
/*=============================================================
|
||||
THE GRID
|
||||
==============================================================*/
|
||||
.w2p_grid_bottom_bar .w2p_export_menu
|
||||
{
|
||||
line-height:18px;
|
||||
margin-left:0;
|
||||
}
|
||||
.w2p_export_menu .dropdown-toggle
|
||||
{
|
||||
cursor:pointer;
|
||||
margin:0;
|
||||
padding:0;
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(white), to(#E6E6E6));
|
||||
background-image: -webkit-linear-gradient(top, white, #E6E6E6);
|
||||
background-image: -o-linear-gradient(top, white, #E6E6E6);
|
||||
background-image: linear-gradient(to bottom, white, #E6E6E6);
|
||||
background-image: -moz-linear-gradient(top, white, #E6E6E6);
|
||||
}
|
||||
.w2p_export_menu ul
|
||||
{
|
||||
margin-top:2px;
|
||||
display:none;
|
||||
}
|
||||
.w2p_export_menu li
|
||||
{
|
||||
display:list-item;
|
||||
margin:0;
|
||||
}
|
||||
div.web2py_grid
|
||||
{
|
||||
font-size:13px;
|
||||
line-height:18px;
|
||||
}
|
||||
.web2py_grid a.btn
|
||||
{
|
||||
font-size:13px;
|
||||
line-height:18px;
|
||||
padding:4px 10px;
|
||||
margin-left:0;
|
||||
margin-right:4px;
|
||||
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));
|
||||
background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
|
||||
background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);
|
||||
background-image: linear-gradient(to bottom, #ffffff, #e6e6e6);
|
||||
background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
|
||||
}
|
||||
.web2py_grid .input-append .btn
|
||||
{
|
||||
padding:4px 10px;
|
||||
margin-right:0;
|
||||
font-family:inherit;
|
||||
color:#333;
|
||||
text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);
|
||||
border:1px solid #c5c5c5;
|
||||
}
|
||||
.web2py_grid select:focus
|
||||
{
|
||||
border-color:rgba(232,149,60,0.8);
|
||||
outline:0;
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(232, 149, 60, 0.6);
|
||||
-moz-box-shadow: inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(232,149,60,0.6);
|
||||
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(232, 149, 60, 0.6);
|
||||
}
|
||||
.web2py_console input[type="button"],
|
||||
.web2py_grid .row_buttons a.btn
|
||||
{
|
||||
color:#333;
|
||||
line-height:18px;
|
||||
padding:4px 10px;
|
||||
text-shadow:rgba(255, 255, 255, 0.74902) 0px 1px 1px;
|
||||
border-color:rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.25);
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.web2py_console input[type="button"]:hover,
|
||||
.web2py_grid .row_buttons a.btn:hover
|
||||
{
|
||||
color:#333;
|
||||
border-color:rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.25);
|
||||
background:#E6E6E6;
|
||||
background-position: 0 -15px !important;
|
||||
-webkit-transition: background-position .1s linear;
|
||||
-moz-transition: background-position .1s linear;
|
||||
-o-transition: background-position .1s linear;
|
||||
transition: background-position .1s linear;
|
||||
}
|
||||
.web2py_table
|
||||
{
|
||||
border:none;
|
||||
}
|
||||
.web2py_table table
|
||||
{
|
||||
/*table-layout:fixed;*/
|
||||
margin-bottom:4px;
|
||||
}
|
||||
.web2py_table table td
|
||||
{
|
||||
/*word-wrap:break-word;*/ /*uncomment when "table-layout:fixed" is applied */
|
||||
}
|
||||
|
||||
.web2py_grid thead th
|
||||
{
|
||||
background-color:transparent;
|
||||
padding:4px 5px;
|
||||
line-height:18px;
|
||||
vertical-align:bottom;
|
||||
border-right:0;
|
||||
border-bottom:0;
|
||||
word-wrap:break-word;
|
||||
}
|
||||
.web2py_grid .btn-group > .dropdown-menu
|
||||
{
|
||||
font-size:13px;
|
||||
}
|
||||
.web2py_grid .dropdown-menu li > a:hover,
|
||||
.web2py_grid .dropdown-menu li > a:focus
|
||||
{
|
||||
filter:progid:DXImageTransform.Microsoft.gradient(enabled=false); /* IE6-9 */
|
||||
background-image:none;
|
||||
background-color:#E8953C;
|
||||
}
|
||||
.pagination
|
||||
{
|
||||
margin:0;
|
||||
height:30px;
|
||||
}
|
||||
.pagination ul > li > a
|
||||
{
|
||||
line-height:28px;
|
||||
}
|
||||
|
||||
#w2p_grid_addbtn:focus,
|
||||
#w2p_search-form :focus,
|
||||
.btn:focus
|
||||
{
|
||||
outline:none;
|
||||
}
|
||||
.web2py_console input[type="button"]:focus,
|
||||
.web2py_grid .row_buttons a.btn:focus
|
||||
{
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15) inset, 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
div.web2py_counter.span6
|
||||
{
|
||||
min-height:20px;
|
||||
}
|
||||
.web2py_paginator
|
||||
{
|
||||
border:0;
|
||||
margin:0;
|
||||
padding:0;
|
||||
background-color:transparent;
|
||||
}
|
||||
.web2py_paginator ul li a
|
||||
{
|
||||
margin-right:0;
|
||||
padding:0 14px;
|
||||
border:1px solid #DDD;
|
||||
border-left-width:0;
|
||||
color:#E8953C;
|
||||
}
|
||||
.web2py_paginator ul li a:hover
|
||||
{
|
||||
background: whiteSmoke;
|
||||
border: 1px solid #DDD;
|
||||
border-left-width:0;
|
||||
color:#e2821b;
|
||||
}
|
||||
.web2py_paginator ul li:first-child a,
|
||||
.web2py_paginator ul li:first-child a:hover
|
||||
{
|
||||
border-left-width:1px;
|
||||
}
|
||||
.web2py_paginator .current
|
||||
{
|
||||
font-weight:normal;
|
||||
}
|
||||
.web2py_paginator ul li.current a:hover
|
||||
{
|
||||
color:#999;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.editor-bar-column a[name="save"]
|
||||
{
|
||||
background-color: whiteSmoke;
|
||||
background-image: -webkit-gradient(linear,0 0,0 100%,from(white),to(#E6E6E6));
|
||||
background-image: -webkit-linear-gradient(top,white,#E6E6E6);
|
||||
background-image: -o-linear-gradient(top,white,#E6E6E6);
|
||||
background-image: linear-gradient(to bottom,white,#E6E6E6);
|
||||
background-image: -moz-linear-gradient(top,white,#E6E6E6);
|
||||
background-repeat: repeat-x;
|
||||
padding:2px 6px;
|
||||
font-size:11px;
|
||||
line-height:17px;
|
||||
margin:0;
|
||||
}
|
||||
.editor-bar-column a[name="save"]:hover
|
||||
{
|
||||
background-color: #E6E6E6;
|
||||
background-position: 0 -15px;
|
||||
-webkit-transition: background-position .1s linear;
|
||||
-moz-transition: background-position .1s linear;
|
||||
-o-transition: background-position .1s linear;
|
||||
transition: background-position .1s linear;
|
||||
}
|
||||
.keybindings
|
||||
{
|
||||
padding:0 18px 10px;
|
||||
}
|
||||
.keybindings li
|
||||
{
|
||||
margin-bottom:0;
|
||||
}
|
||||
|
||||
/*----- translate page ---*/
|
||||
|
||||
.languageform input
|
||||
{
|
||||
margin-bottom:0;
|
||||
}
|
||||
.languageform div
|
||||
{
|
||||
margin-bottom:9px;
|
||||
}
|
||||
.languageform input.untranslated
|
||||
{
|
||||
background-color:#FC0;
|
||||
}
|
||||
|
||||
.step #wizard_nav .first-box
|
||||
{
|
||||
padding-top:0;
|
||||
}
|
||||
|
||||
/*=============================================================
|
||||
MEDIA QUERIES
|
||||
==============================================================*/
|
||||
@media (max-width: 979px)
|
||||
{
|
||||
/*-----------------------------------
|
||||
Navbar
|
||||
-------------------------------------*/
|
||||
#header .navbar-inner
|
||||
{
|
||||
padding:0;
|
||||
}
|
||||
/*collapsed menu*/
|
||||
.navbar .nav-collapse .nav
|
||||
{
|
||||
background:#222;
|
||||
padding:8px 2px 8px 8px;
|
||||
-webkit-border-bottom-right-radius:8px;
|
||||
-webkit-border-bottom-left-radius:8px;
|
||||
-moz-border-radius-bottomright:8px;
|
||||
-moz-border-radius-bottomleft:8px;
|
||||
border-bottom-right-radius:8px;
|
||||
border-bottom-left-radius:8px;
|
||||
}
|
||||
#menu
|
||||
{
|
||||
margin-right:0;
|
||||
}
|
||||
#menu li
|
||||
{
|
||||
float:none;
|
||||
}
|
||||
#menu a.button,
|
||||
#menu a.button span
|
||||
{
|
||||
background-image:url(../images/menu_responsive.png);
|
||||
}
|
||||
#menu a.button
|
||||
{
|
||||
padding:0 1em 0 0;
|
||||
}
|
||||
}
|
||||
@media(max-width:632px)
|
||||
{
|
||||
/*-----------------------------------
|
||||
footer
|
||||
-------------------------------------*/
|
||||
#footer
|
||||
{
|
||||
height:auto;
|
||||
}
|
||||
|
||||
#footer select
|
||||
{
|
||||
margin-top:8px;
|
||||
}
|
||||
}
|
||||
822
applications/admin/static/css/bootstrap_essentials.css
vendored
Normal file
822
applications/admin/static/css/bootstrap_essentials.css
vendored
Normal file
@@ -0,0 +1,822 @@
|
||||
/*=============================================================
|
||||
GENERAL
|
||||
==============================================================*/
|
||||
body
|
||||
{
|
||||
/*remember to account for the hidden area underneath
|
||||
fixed navbar by adding at least 40px padding to the <body>.
|
||||
Be sure to add this after the core Bootstrap CSS
|
||||
and before the optional responsive CSS.
|
||||
An alternative solution is to set top-margin to div#main*/
|
||||
/*padding-top:60px;*/ /*comment this for alternative solution*/
|
||||
height:auto; /*uncomment this for alternative solution */
|
||||
}
|
||||
/*=============================================================
|
||||
BOOTSTRAP ICONS FOLDER FIX
|
||||
==============================================================*/
|
||||
[class^="icon-"],[class*=" icon-"]
|
||||
{
|
||||
/* right folder for bootstrap black images/icons */
|
||||
background-image:url("../images/glyphicons-halflings.png")
|
||||
}
|
||||
|
||||
.icon-white,
|
||||
.nav-tabs>.active >a>[class^="icon-"],
|
||||
.nav-tabs>.active>a>[class*=" icon-"],
|
||||
.nav-pills>.active>a>[class^="icon-"],
|
||||
.nav-pills>.active>a>[class*=" icon-"],
|
||||
.nav-list>.active>a>[class^="icon-"],
|
||||
.nav-list>.active>a>[class*=" icon-"],
|
||||
.navbar-inverse .nav>.active>a>[class^="icon-"],
|
||||
.navbar-inverse .nav>.active>a>[class*=" icon-"],
|
||||
.dropdown-menu>li>a:hover>[class^="icon-"],
|
||||
.dropdown-menu>li>a:hover>[class*=" icon-"],
|
||||
.dropdown-menu>.active>a>[class^="icon-"],
|
||||
.dropdown-menu>.active>a>[class*=" icon-"]
|
||||
{
|
||||
/* right folder for bootstrap white images/icons */
|
||||
background-image:url("../images/glyphicons-halflings-white.png");
|
||||
}
|
||||
/*=============================================================
|
||||
INPUT BORDER HIGHLIGHT WHEN INPUT IS FOCUSED
|
||||
==============================================================*/
|
||||
textarea:focus,
|
||||
input[type="text"]:focus,
|
||||
input[type="password"]:focus,
|
||||
input[type="datetime"]:focus,
|
||||
input[type="datetime-local"]:focus,
|
||||
input[type="date"]:focus,
|
||||
input[type="month"]:focus,
|
||||
input[type="time"]:focus,
|
||||
input[type="week"]:focus,
|
||||
input[type="number"]:focus,
|
||||
input[type="email"]:focus,
|
||||
input[type="url"]:focus,
|
||||
input[type="search"]:focus,
|
||||
input[type="tel"]:focus,
|
||||
input[type="color"]:focus,
|
||||
input[type="file"]:focus,
|
||||
select:focus,
|
||||
.uneditable-input:focus
|
||||
{
|
||||
/* outline color */
|
||||
border-color:rgba(232,149,60,0.8);
|
||||
outline:0;
|
||||
/*outline:thin dotted \9;*/
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(232, 149, 60, 0.6);
|
||||
-moz-box-shadow: inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(232,149,60,0.6);
|
||||
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(232, 149, 60, 0.6);
|
||||
}
|
||||
.web2py_grid .dropdown-menu li > a:hover,
|
||||
.web2py_grid .dropdown-menu li > a:focus
|
||||
{
|
||||
filter:progid:DXImageTransform.Microsoft.gradient(enabled=false); /* IE6-9 */
|
||||
background-image:none;
|
||||
background-color:#E8953C;
|
||||
}
|
||||
|
||||
/*=============================================================
|
||||
COLOR OF LINKS
|
||||
==============================================================*/
|
||||
a,
|
||||
a:hover
|
||||
{
|
||||
color:#E8953C;
|
||||
text-decoration:none;
|
||||
}
|
||||
a:hover
|
||||
{
|
||||
color:#e2821b;
|
||||
}
|
||||
/*=============================================================
|
||||
CONTROLS and CONTAINERS
|
||||
==============================================================*/
|
||||
.row-buttons .btn
|
||||
{
|
||||
margin-bottom:7px;
|
||||
}
|
||||
.sidebar .box
|
||||
{
|
||||
clear:right;
|
||||
margin-top:2em;
|
||||
border-top:1px dotted;
|
||||
padding:0 1em;
|
||||
}
|
||||
.pwdchange>.button{margin-bottom:10px;}
|
||||
input[type="file"] {
|
||||
margin-bottom:9px;
|
||||
}
|
||||
.form-inline input[type="file"] {
|
||||
margin-bottom:0px;
|
||||
}
|
||||
input + .help-block
|
||||
{
|
||||
margin-top:-5px;
|
||||
margin-bottom:4px;
|
||||
}
|
||||
#confirm_form input.btn,
|
||||
.generatedbyw2p input
|
||||
{
|
||||
margin-right:4px;
|
||||
}
|
||||
a[rel='tooltip'] span,
|
||||
div[rel='tooltip'] span
|
||||
{
|
||||
display:none;
|
||||
margin-left:-9999px;
|
||||
}
|
||||
/*in-page browsing*/
|
||||
[rel="pagebookmark"]
|
||||
{
|
||||
position:relative;
|
||||
}
|
||||
[rel="pagebookmark"]>.component
|
||||
{
|
||||
cursor:pointer;
|
||||
}
|
||||
[rel="pagebookmark"]>.hashstick
|
||||
{
|
||||
position:absolute;
|
||||
top:-54px;
|
||||
left:-9999px;
|
||||
visibility:visible;
|
||||
}
|
||||
/* following 2 rules set the style of a small button for going to top of page */
|
||||
.tophashlink.btn
|
||||
{
|
||||
padding:2px 3px;
|
||||
visibility:hidden;
|
||||
}
|
||||
.hashstick:target+.tophashlink.btn
|
||||
{
|
||||
visibility:visible;
|
||||
}
|
||||
ul.act_edit
|
||||
{
|
||||
margin-top:4px;
|
||||
margin-left:20px;
|
||||
}
|
||||
ul.act_edit .btn
|
||||
{
|
||||
margin-top:4px;
|
||||
margin-bottom:4px;
|
||||
}
|
||||
ul.act_edit .file>a
|
||||
{
|
||||
white-space:pre;
|
||||
}
|
||||
.right-full
|
||||
{
|
||||
text-align:right;
|
||||
}
|
||||
.searchbox,
|
||||
.searchbox label,
|
||||
.searchbox input
|
||||
{
|
||||
display:inline-block;
|
||||
}
|
||||
.buttons-row .btn
|
||||
{
|
||||
margin-bottom:9px;
|
||||
}
|
||||
.li-controls
|
||||
{
|
||||
display:inline-block;
|
||||
width:180px;
|
||||
vertical-align:middle;
|
||||
}
|
||||
.celled
|
||||
{
|
||||
display:inline-block;
|
||||
padding: 4px 0 0 0;
|
||||
vertical-align:top;
|
||||
margin-top:4px;
|
||||
width:700px;
|
||||
}
|
||||
.folder
|
||||
{
|
||||
border-left: 1px dotted #AAA;
|
||||
}
|
||||
.folder li
|
||||
{
|
||||
list-style-type:none;
|
||||
}
|
||||
.folder>i
|
||||
{
|
||||
display:inline-block;
|
||||
width:5px;
|
||||
height:5px;
|
||||
border:1px solid;
|
||||
background-color:#FAA732;
|
||||
margin-left:-4px;
|
||||
margin-top:-2px;
|
||||
border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
||||
border-radius:1px;
|
||||
}
|
||||
.folder>i+a
|
||||
{
|
||||
padding-left:0.5em;
|
||||
}
|
||||
.folder ul
|
||||
{
|
||||
margin-top:0.5em;
|
||||
margin-bottom:0.5em;
|
||||
}
|
||||
.controls-inline .btn
|
||||
{
|
||||
margin-right:5px;
|
||||
}
|
||||
div.web2py_counter.span6
|
||||
{
|
||||
min-height:24px;
|
||||
text-align:right;
|
||||
}
|
||||
.pagination
|
||||
{
|
||||
margin:0;
|
||||
}
|
||||
.table
|
||||
{
|
||||
margin-bottom:10px;
|
||||
}
|
||||
.row_buttons .btn
|
||||
{
|
||||
margin-right:4px;
|
||||
}
|
||||
|
||||
.editor-bar-column
|
||||
{
|
||||
display:inline-block;
|
||||
vertical-align:top;
|
||||
margin-right:4px;
|
||||
}
|
||||
|
||||
.editor-bar-column .input-long
|
||||
{
|
||||
width:270px;
|
||||
}
|
||||
|
||||
.editor-bar-column .input-normal
|
||||
{
|
||||
width:206px;
|
||||
}
|
||||
|
||||
.keybindings li
|
||||
{
|
||||
margin-bottom:0.5em;
|
||||
}
|
||||
.keybindings span
|
||||
{
|
||||
padding:0.3em;
|
||||
border:1px solid transparent;
|
||||
vertical-align:middle;
|
||||
}
|
||||
.teletype-text
|
||||
{
|
||||
font-family:monospace;
|
||||
font-weight:bold;
|
||||
font-style:normal;
|
||||
border-color:#999;
|
||||
background:#333;
|
||||
color:#DDD;
|
||||
-moz-border-radius:0.3em;
|
||||
border-radius:0.3em;
|
||||
}
|
||||
|
||||
.edit_language .tab_row div
|
||||
{
|
||||
display:inline-block;
|
||||
vertical-align:top;
|
||||
margin-right:4px;
|
||||
}
|
||||
.edit_language .fake-input
|
||||
{
|
||||
height:18px;
|
||||
padding:4px;
|
||||
font-size:13px;
|
||||
line-height:18px;
|
||||
overflow:hidden;
|
||||
white-space:nowrap;
|
||||
display:inline-block;
|
||||
margin-bottom:9px;
|
||||
}
|
||||
|
||||
.test h3
|
||||
{
|
||||
padding-left:9px;
|
||||
margin:0;
|
||||
font-size:16px;
|
||||
line-height:1;
|
||||
border-left:9px solid transparent;
|
||||
}
|
||||
.test h3.passed
|
||||
{
|
||||
border-color:#009900;
|
||||
}
|
||||
.test h3.failed
|
||||
{
|
||||
border-color:#CC0000;
|
||||
}
|
||||
.test h3.nodoctests
|
||||
{
|
||||
border-color:#CCCC99;
|
||||
}
|
||||
.test .test_report
|
||||
{
|
||||
width:100%;
|
||||
overflow:auto;
|
||||
}
|
||||
.test_report pre
|
||||
{
|
||||
white-space:pre;
|
||||
}
|
||||
.test div[id^="output_"]>h2
|
||||
{
|
||||
font-size:18px;
|
||||
line-height:1;
|
||||
color:grey;
|
||||
}
|
||||
div.center
|
||||
{
|
||||
text-align:center;
|
||||
}
|
||||
.delete h2
|
||||
{
|
||||
word-wrap:break-word;
|
||||
}
|
||||
/*=============================================================
|
||||
SHELL
|
||||
==============================================================*/
|
||||
.shell .output-wrapper
|
||||
{
|
||||
width:100%;
|
||||
height:30em;
|
||||
border:1px solid #333;
|
||||
}
|
||||
.shell .prompt-wrapper
|
||||
{
|
||||
float:left;
|
||||
width:100%;
|
||||
overflow:hidden;
|
||||
height:auto;
|
||||
border:1px solid #333;
|
||||
}
|
||||
.shell .prompt-container
|
||||
{
|
||||
margin-left:2.5em;
|
||||
}
|
||||
.shell #caret
|
||||
{
|
||||
width:2.5em;
|
||||
float:left;
|
||||
margin-left:-100%;
|
||||
}
|
||||
.shell #shellwrapper
|
||||
{
|
||||
background:white;
|
||||
color:#E8953C;
|
||||
width:100%;
|
||||
margin:1em 0;
|
||||
border:0;
|
||||
}
|
||||
.shell #output,
|
||||
.shell .prompt
|
||||
{
|
||||
color:#E8953C;
|
||||
background:white;
|
||||
resize:none;
|
||||
border:none;
|
||||
width:100%;
|
||||
height:100%;
|
||||
cursor:default;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.shell #output:focus,
|
||||
.shell .prompt:focus
|
||||
{
|
||||
border-color:transparent;
|
||||
outline:0;
|
||||
-webkit-box-shadow: none;
|
||||
-moz-box-shadow: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
.shell #output pre
|
||||
{
|
||||
color: #E8953C;
|
||||
}
|
||||
.shell #autoscroll
|
||||
{
|
||||
cursor:pointer;
|
||||
float:right;
|
||||
}
|
||||
.shell .prompt,
|
||||
.shell #output,
|
||||
.shell #caret
|
||||
{
|
||||
font-size: 11pt;
|
||||
padding: 6px;
|
||||
padding-right: 0em;
|
||||
}
|
||||
.shell #caret
|
||||
{
|
||||
padding-top:9px;
|
||||
}
|
||||
.shell .prompt,
|
||||
.shell #output,
|
||||
.shell pre,
|
||||
.shell #caret
|
||||
{
|
||||
font-family: monospace;
|
||||
}
|
||||
.shell a[rel="tooltip"]
|
||||
{
|
||||
margin-left:8px;
|
||||
}
|
||||
/*=============================================================
|
||||
PEEK
|
||||
==============================================================*/
|
||||
.peek .code-wrapper
|
||||
{
|
||||
width:100%;
|
||||
overflow:auto;
|
||||
white-space:pre;
|
||||
}
|
||||
|
||||
.peek table td pre
|
||||
{
|
||||
word-break:normal;
|
||||
white-space:pre;
|
||||
}
|
||||
|
||||
|
||||
/*=============================================================
|
||||
FOOTER
|
||||
==============================================================*/
|
||||
#footer
|
||||
{
|
||||
border-top:1px solid;
|
||||
text-align:center;
|
||||
padding:1em 0;
|
||||
}
|
||||
#footer span,
|
||||
#footer select
|
||||
{
|
||||
display:inline-block;
|
||||
margin-bottom:0;
|
||||
vertical-align:middle;
|
||||
}
|
||||
#footer select
|
||||
{
|
||||
width:auto;
|
||||
}
|
||||
/*=============================================================
|
||||
MAIN
|
||||
==============================================================*/
|
||||
#main
|
||||
{
|
||||
margin-top:60px; /*uncomment this for alternative solution to hidden area underneath fixed navbar issue*/
|
||||
margin-bottom:60px;
|
||||
}
|
||||
/*=============================================================
|
||||
WIZARD
|
||||
==============================================================*/
|
||||
#wizard_nav .box
|
||||
{
|
||||
border-bottom:1px dotted;
|
||||
}
|
||||
#wizard_nav li
|
||||
{
|
||||
margin-left:1em;
|
||||
margin-top:0.5em;
|
||||
}
|
||||
.step textarea
|
||||
{
|
||||
width:auto;
|
||||
}
|
||||
select[name='layout_theme']
|
||||
{
|
||||
vertical-align:top;
|
||||
}
|
||||
img#preview
|
||||
{
|
||||
margin-bottom:9px;
|
||||
}
|
||||
/* multiselect customization */
|
||||
.ms-container
|
||||
{
|
||||
margin-bottom:5px;
|
||||
}
|
||||
.ms-selectable,
|
||||
.step .ms-selection
|
||||
{
|
||||
text-align:center;
|
||||
}
|
||||
.ms-list
|
||||
{
|
||||
text-align:left;
|
||||
background:white;
|
||||
}
|
||||
.ms-container li.ms-elem-selectable:not(.disabled).ms-hover,
|
||||
.ms-container .ms-selection li:not(.disabled).ms-hover
|
||||
{
|
||||
background-color:#E8953C;
|
||||
}
|
||||
.ms-container .ms-selectable
|
||||
{
|
||||
margin-right:25px;
|
||||
}
|
||||
.ms-container .ms-selectable,
|
||||
.ms-container .ms-selection
|
||||
{
|
||||
background:transparent;
|
||||
}
|
||||
.ms-container .ms-list.ms-focus
|
||||
{
|
||||
border-color:rgba(232,149,60,0.8);
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(232, 149, 60, 0.6);
|
||||
-moz-box-shadow: inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(232,149,60,0.6);
|
||||
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(232, 149, 60, 0.6);
|
||||
}
|
||||
/* grow_input */
|
||||
ul[id$="_grow_input"]
|
||||
{
|
||||
margin-left:0;
|
||||
}
|
||||
/* generate_form*/
|
||||
#generate_form .control-group
|
||||
{
|
||||
margin-bottom:0;
|
||||
}
|
||||
#generate_form .control-label
|
||||
{
|
||||
text-align:left;
|
||||
}
|
||||
#generate_form .controls
|
||||
{
|
||||
padding-left:18px;
|
||||
margin-left:0;
|
||||
}
|
||||
#generate_form .control-label.empty
|
||||
{
|
||||
width:142px;
|
||||
}
|
||||
.step [rel="pagebookmark"]>.hashstick
|
||||
{
|
||||
display:none;
|
||||
}
|
||||
/*generated page*/
|
||||
.generated iframe
|
||||
{
|
||||
border:1px inset #e3e3e3;
|
||||
}
|
||||
/*=============================================================
|
||||
ERRORS TABLE / TICKET PAGE
|
||||
==============================================================*/
|
||||
.tablebar
|
||||
{
|
||||
margin:7px 0 7px 0;
|
||||
}
|
||||
.tablebar input
|
||||
{
|
||||
margin-right:27px;
|
||||
}
|
||||
.tablebar span
|
||||
{
|
||||
vertical-align:bottom;
|
||||
}
|
||||
.table th
|
||||
{
|
||||
background: #e9e9e9;
|
||||
background: -moz-linear-gradient(top, #FAFAFA 0%, #E9E9E9 100%);
|
||||
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#FAFAFA), color-stop(100%,#E9E9E9));
|
||||
background: -webkit-linear-gradient(top, #FAFAFA 0%,#E9E9E9 100%);
|
||||
background: -o-linear-gradient(top, #FAFAFA 0%,#E9E9E9 100%);
|
||||
background: -ms-linear-gradient(top, #FAFAFA 0%,#E9E9E9 100%);
|
||||
background: linear-gradient(top, #FAFAFA 0%,#E9E9E9 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FAFAFA', endColorstr='#E9E9E9');
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#FAFAFA', endColorstr='#E9E9E9')";
|
||||
/*font-size:10px;
|
||||
color:#444;
|
||||
text-transform:uppercase;*/
|
||||
}
|
||||
td.cbcentered,
|
||||
th.cbcentered
|
||||
{
|
||||
text-align:center;
|
||||
}
|
||||
td.cbcentered>input,
|
||||
th.cbcentered>input
|
||||
{
|
||||
margin-top:-1px;
|
||||
}
|
||||
.traceback div
|
||||
{
|
||||
}
|
||||
.ticket_code>table td:first-child
|
||||
{
|
||||
border-left:0;
|
||||
}
|
||||
#trck_errors table td pre
|
||||
{
|
||||
word-break:normal;
|
||||
white-space:pre;
|
||||
}
|
||||
.inspect pre,
|
||||
.errorsource pre
|
||||
{
|
||||
word-break:normal;
|
||||
white-space:pre;
|
||||
}
|
||||
.ticket_code
|
||||
{
|
||||
background-color:lightyellow;
|
||||
}
|
||||
.ticket_code table,
|
||||
.ticket_code td
|
||||
{
|
||||
border-width:0px;
|
||||
border-collapse:collapse;
|
||||
width:100%;
|
||||
}
|
||||
.ticket_code tbody tr:hover td
|
||||
{
|
||||
background-color:transparent;
|
||||
}
|
||||
/*=============================================================
|
||||
FLOT GRAPHS
|
||||
==============================================================*/
|
||||
.about #placeholder
|
||||
{
|
||||
width:auto;
|
||||
max-width:600px;
|
||||
height:300px;
|
||||
position:relative;
|
||||
margin:0 auto; /* for centering */
|
||||
}
|
||||
/*=============================================================
|
||||
THE GRID
|
||||
==============================================================*/
|
||||
#w2p_query_panel
|
||||
{
|
||||
min-width:20px;
|
||||
min-height:20px;
|
||||
padding:10px;
|
||||
margin-top:1em;
|
||||
background-color:#f5f5f5;
|
||||
border: 1px solid #e3e3e3;
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
|
||||
-moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
|
||||
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
#w2p_query_panel select,
|
||||
#w2p_query_panel input
|
||||
{
|
||||
margin-bottom:0;
|
||||
margin-right:4px;
|
||||
}
|
||||
.web2py_grid .hidden
|
||||
{
|
||||
visibility:visible;
|
||||
}
|
||||
.qry_pnl_btns
|
||||
{
|
||||
display:inline-block;
|
||||
}
|
||||
#w2p_grid_addbtn,
|
||||
#w2p_search-form
|
||||
{
|
||||
margin-top:9px;
|
||||
margin-bottom:9px;
|
||||
}
|
||||
#w2p_search-form
|
||||
{
|
||||
margin-bottom:0;
|
||||
}
|
||||
#w2p_search-form form
|
||||
{
|
||||
margin-bottom:0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*----- translate page ---*/
|
||||
|
||||
.languageform input
|
||||
{
|
||||
margin-bottom:0;
|
||||
}
|
||||
.languageform input.untranslated
|
||||
{
|
||||
background-color:#FC0;
|
||||
}
|
||||
|
||||
|
||||
/*=============================================================
|
||||
MEDIA QUERIES
|
||||
==============================================================*/
|
||||
@media (max-width: 800px)
|
||||
{
|
||||
.step [rel="pagebookmark"]>.hashstick
|
||||
{
|
||||
/*top:-54px;*/
|
||||
display:block;
|
||||
}
|
||||
}
|
||||
@media (max-width: 767px)
|
||||
{
|
||||
[rel="pagebookmark"]>.hashstick{top:0;}
|
||||
/*-----------------------------------
|
||||
main
|
||||
-------------------------------------*/
|
||||
#main
|
||||
{
|
||||
margin-top:0;
|
||||
}
|
||||
/*-----------------------------------
|
||||
footer
|
||||
-------------------------------------*/
|
||||
#footer
|
||||
{
|
||||
margin-left: -20px;
|
||||
margin-right: -20px;
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
/*-----------------------------------
|
||||
errors page
|
||||
-------------------------------------*/
|
||||
#trck_errors
|
||||
{
|
||||
table-layout:fixed;
|
||||
}
|
||||
#trck_errors .column1
|
||||
{
|
||||
width:20px;
|
||||
}
|
||||
#trck_errors .column2
|
||||
{
|
||||
width:45px;
|
||||
}
|
||||
#trck_errors .column3
|
||||
{
|
||||
width:150px;
|
||||
}
|
||||
#trck_errors .columnN
|
||||
{
|
||||
width:55px;
|
||||
}
|
||||
#trck_errors .columnN1
|
||||
{
|
||||
width:138px;
|
||||
}
|
||||
.ticket_code,
|
||||
.inspect.resp1,
|
||||
.inspect.controls pre,
|
||||
.errorsource
|
||||
{
|
||||
width:100%;
|
||||
overflow:auto;
|
||||
}
|
||||
.ticket_code>table
|
||||
{
|
||||
width:100%;
|
||||
}
|
||||
.celled
|
||||
{
|
||||
width:320px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 480px)
|
||||
{
|
||||
.qry_pnl_btns
|
||||
{
|
||||
display:block;
|
||||
margin-top:4px;
|
||||
}
|
||||
/*-----------------------------------
|
||||
wizard
|
||||
-------------------------------------*/
|
||||
#generate_form .control-label
|
||||
{
|
||||
float:left;
|
||||
width:160px;
|
||||
padding-top:5px;
|
||||
}
|
||||
.inspect>code
|
||||
{
|
||||
display:block;
|
||||
white-space:normal;
|
||||
}
|
||||
.li-controls
|
||||
{
|
||||
}
|
||||
.celled
|
||||
{
|
||||
width:165px;
|
||||
}
|
||||
}
|
||||
@@ -1166,7 +1166,7 @@ ul#snapshot > li {
|
||||
font-size: 1em;
|
||||
color: #3C3C3D;
|
||||
text-shadow: 1px 1px 0 #FFFFFF;
|
||||
background:#ECECEC;
|
||||
//background:#ECECEC;
|
||||
white-space: nowrap; overflow: visible;
|
||||
cursor: pointer; text-decoration: none;
|
||||
border: 1px solid #CACACA;
|
||||
@@ -1244,8 +1244,64 @@ color: #222;
|
||||
border-radius:2px;
|
||||
}
|
||||
.ie9 #query_panel {padding-bottom:2px;}
|
||||
|
||||
.error, .error a {color:red}
|
||||
.pluralsform thead td {font-weight:bold; font-size:1.2em; padding-bottom:5px}
|
||||
.pluralsform td {padding-left:5px}
|
||||
.tm_ftag {color:blue}
|
||||
|
||||
/*-----------------------------------*/
|
||||
/* due to bootstrap layout
|
||||
/*-----------------------------------*/
|
||||
.navbar .btn-navbar{display:none;}
|
||||
label{display:block;}
|
||||
input{margin-bottom:5px;}
|
||||
.login input{width:210px;}
|
||||
.change_password input{width:210px;}
|
||||
div.flash .close{color:inherit;float:right;}
|
||||
label.checkbox{margin-bottom:5px;}
|
||||
.control-group{margin-bottom:5px;}
|
||||
.step #menu li{margin-left:0;margin-top:0;}
|
||||
.step #wizard_nav{padding-top:0.5em;}
|
||||
.hashstick{visibility:hidden;}
|
||||
#generate_form .control-label{float:left;width:160px;padding-top:5px;text-align:left;}
|
||||
#generate_form .controls > .checkbox:first-child{padding-top:7px;}
|
||||
/* from default/errors.html */
|
||||
table.sortable{border-spacing:0px;}
|
||||
table.sortable td, table.sortable th{padding:2px 5px 2px 5px;}
|
||||
table.sortable thead{background-color:#eee;color:#666666;font-weight:bold;cursor:default;}
|
||||
tr.error_ticket:hover{background-color:#eee;}
|
||||
.controls a.button.unavailable{color:#ff0000;}
|
||||
/* end from default/errors.html */
|
||||
/* new errors table */
|
||||
.tablebar{margin:7px 0 7px 0;}
|
||||
.cbcentered{text-align:center;}
|
||||
/* new tooltip */
|
||||
a[rel='tooltip']:hover{background:transparent;text-decoration:none;}
|
||||
a[rel='tooltip'] span{display:none;padding:5px;margin-left:10px;width:150px;}
|
||||
a[rel='tooltip']:hover span{cursor:default;display:inline;position:absolute;}
|
||||
a[rel='tooltip'] span{background:#9fb364;color:#eef1d9;border:1px solid #eef1d9;font-style:italic;width:20%;padding:0.3em;-moz-border-radius:0.5em;border-radius:0.5em;font-size:13px;text-transform:none;}
|
||||
/* flot graph */
|
||||
.about #placeholder{width:600px;height:300px;margin:0 auto;}
|
||||
.tophashlink.btn{visibility:hidden;}
|
||||
.help-block{display:block;}
|
||||
.w2p_grid_bottom_bar .w2p_export_menu{float:left;line-height:39px;margin-left:10px;}
|
||||
.w2p_export_menu .dropdown-toggle{cursor:default;color:#333;margin:0;padding:0;background-image:none;}
|
||||
.w2p_export_menu ul{display:inline-block;margin:0;vertical-align:middle;}
|
||||
.w2p_export_menu li{list-style:none;display:inline-block;margin-right:4px;margin-left:2px;}
|
||||
.edit_language .tab_row div{display:inline-block;vertical-align:top;margin-right:4px;}
|
||||
.edit_language .tab_row>div{border:1px solid #e3e3e3;margin-bottom:20px;background-color:#f5f5f5;}
|
||||
/* shell*/
|
||||
.shell .output-wrapper{width:75%;height:30em;border:1px solid #333;}
|
||||
.shell .prompt-wrapper{float:left;width:100%;overflow:hidden;height:auto;border:1px solid #333;}
|
||||
.shell .prompt-container{margin-left:2.5em;}
|
||||
.shell #caret{width:2.5em;float:left;margin-left:-100%;}
|
||||
.shell #shellwrapper{background:white;color:#E8953C;width:75%;margin:1em 0;border:0;}
|
||||
.shell #output,.shell .prompt{color:#E8953C;background:white;resize:none;border:none;width:100%;height:100%;cursor:default;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;}
|
||||
.shell #output:focus,.shell .prompt:focus{border-color:transparent;outline:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
|
||||
.shell #output pre{color:#E8953C;}
|
||||
.shell #autoscroll{cursor:pointer;float:right;}
|
||||
.shell .prompt,.shell #output,.shell #caret{font-size:11pt;padding:6px;padding-right:0em;}
|
||||
.shell .prompt,.shell #output,.shell pre,.shell #caret{font-family:monospace;}
|
||||
.shell a[rel="tooltip"]{margin-left:8px;}
|
||||
.shell .clearfix{clear:both;}
|
||||
.shell #caret{padding-top:9px;}
|
||||
231
applications/admin/static/css/web2py_bootstrap.css
Normal file
231
applications/admin/static/css/web2py_bootstrap.css
Normal file
@@ -0,0 +1,231 @@
|
||||
/*=============================================================
|
||||
CUSTOM RULES
|
||||
==============================================================*/
|
||||
|
||||
body{height:auto;} /* to avoid vertical scroll bar */
|
||||
div.flash.flash-center{left:25%;right:25%;}
|
||||
div.flash.flash-top,div.flash.flash-top:hover{
|
||||
position:relative;
|
||||
display:block;
|
||||
margin:0;
|
||||
padding:1em;
|
||||
top:0;
|
||||
left:0;
|
||||
width:100%;
|
||||
text-align:center;
|
||||
text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);
|
||||
color:#865100;
|
||||
background:#feea9a;
|
||||
border:1px solid;
|
||||
border-top:0px;
|
||||
border-left:0px;
|
||||
border-right:0px;
|
||||
border-radius:0;
|
||||
opacity:1;
|
||||
}
|
||||
#header{margin-top:60px;}
|
||||
.mastheader h1 {
|
||||
margin-bottom:9px;
|
||||
font-size:81px;
|
||||
font-weight:bold;
|
||||
letter-spacing:-1px;
|
||||
line-height:1;
|
||||
font-size:54px;
|
||||
}
|
||||
.mastheader small {
|
||||
font-size:20px;
|
||||
font-weight:300;
|
||||
}
|
||||
/* auth navbar - primitive style */
|
||||
.auth_navbar,.auth_navbar a{color:inherit;}
|
||||
.ie-lte7 .auth_navbar,.auth_navbar a{color:expression(this.parentNode.currentStyle['color']); /* ie7 doesn't support inherit */}
|
||||
.auth_navbar a{white-space:nowrap;} /* to avoid the nav split on more lines */
|
||||
.auth_navbar a:hover{color:white;text-decoration:none;}
|
||||
ul#navbar>.auth_navbar{
|
||||
display:inline-block;
|
||||
padding:5px;
|
||||
}
|
||||
/* form errors message box customization */
|
||||
div.error_wrapper{margin-bottom:9px;}
|
||||
div.error_wrapper .error{
|
||||
border-radius: 4px;
|
||||
-o-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
-webkit-border-radius: 4px;
|
||||
}
|
||||
/* below rules are only for formstyle = bootstrap
|
||||
trying to make errors look like bootstrap ones */
|
||||
div.controls .error_wrapper{
|
||||
display:inline-block;
|
||||
margin-bottom:0;
|
||||
vertical-align:middle;
|
||||
}
|
||||
div.controls .error{
|
||||
min-width:5px;
|
||||
background:inherit;
|
||||
color:#B94A48;
|
||||
border:none;
|
||||
padding:0;
|
||||
margin:0;
|
||||
/*display:inline;*/ /* uncommenting this, the animation effect is lost */
|
||||
}
|
||||
div.controls .help-inline{color:#3A87AD;}
|
||||
div.controls .error_wrapper +.help-inline {margin-left:-99999px;}
|
||||
div.controls select +.error_wrapper {margin-left:5px;}
|
||||
.ie-lte7 div.error{color:#fff;}
|
||||
|
||||
/* beautify brand */
|
||||
.navbar-inverse .brand{color:#c6cecc;}
|
||||
.navbar-inverse .brand b{display:inline-block;margin-top:-1px;}
|
||||
.navbar-inverse .brand b>span{font-size:22px;color:white}
|
||||
.navbar-inverse .brand:hover b>span{color:white}
|
||||
/* beautify web2py link in navbar */
|
||||
span.highlighted{color:#d8d800;}
|
||||
.open span.highlighted{color:#ffff00;}
|
||||
|
||||
/*=============================================================
|
||||
OVERRIDING WEB2PY.CSS RULES
|
||||
==============================================================*/
|
||||
|
||||
/* reset to default */
|
||||
a{white-space:normal;}
|
||||
li{margin-bottom:0;}
|
||||
textarea,button{display:block;}
|
||||
/*reset ul padding */
|
||||
ul#navbar{padding:0;}
|
||||
/* label aligned to related input */
|
||||
td.w2p_fl,td.w2p_fc {padding:0;}
|
||||
#web2py_user_form td{vertical-align:middle;}
|
||||
|
||||
/*=============================================================
|
||||
OVERRIDING BOOTSTRAP.CSS RULES
|
||||
==============================================================*/
|
||||
|
||||
/* because web2py handles this via js */
|
||||
.hidden{visibility:visible;}
|
||||
/* right folder for bootstrap black images/icons */
|
||||
[class^="icon-"],[class*=" icon-"]{
|
||||
background-image:url("../images/glyphicons-halflings.png")
|
||||
}
|
||||
/* right folder for bootstrap white images/icons */
|
||||
.icon-white,
|
||||
.nav-tabs > .active > a > [class^="icon-"],
|
||||
.nav-tabs > .active > a > [class*=" icon-"],
|
||||
.nav-pills > .active > a > [class^="icon-"],
|
||||
.nav-pills > .active > a > [class*=" icon-"],
|
||||
.nav-list > .active > a > [class^="icon-"],
|
||||
.nav-list > .active > a > [class*=" icon-"],
|
||||
.navbar-inverse .nav > .active > a > [class^="icon-"],
|
||||
.navbar-inverse .nav > .active > a > [class*=" icon-"],
|
||||
.dropdown-menu > li > a:hover > [class^="icon-"],
|
||||
.dropdown-menu > li > a:hover > [class*=" icon-"],
|
||||
.dropdown-menu > .active > a > [class^="icon-"],
|
||||
.dropdown-menu > .active > a > [class*=" icon-"] {
|
||||
background-image:url("../images/glyphicons-halflings-white.png");
|
||||
}
|
||||
/* bootstrap has a label as input's wrapper while web2py has a div */
|
||||
div>input[type="radio"],div>input[type="checkbox"]{margin:0;}
|
||||
/* bootstrap has button instead of input */
|
||||
input[type="button"], input[type="submit"]{margin-right:8px;}
|
||||
|
||||
/*=============================================================
|
||||
RULES FOR SOLVING CONFLICTS BETWEEN WEB2PY.CSS AND BOOTSTRAP.CSS
|
||||
==============================================================*/
|
||||
|
||||
/*when formstyle=table3cols*/
|
||||
tr#auth_user_remember__row>td.w2p_fw>div{padding-bottom:8px;}
|
||||
td.w2p_fw div>label{vertical-align:middle;}
|
||||
td.w2p_fc {padding-bottom:5px;}
|
||||
/*when formstyle=divs*/
|
||||
div#auth_user_remember__row{margin-top:4px;}
|
||||
div#auth_user_remember__row>.w2p_fl{display:none;}
|
||||
div#auth_user_remember__row>.w2p_fw{min-height:39px;}
|
||||
div.w2p_fw,div.w2p_fc{
|
||||
display:inline-block;
|
||||
vertical-align:middle;
|
||||
margin-bottom:0;
|
||||
}
|
||||
div.w2p_fc{
|
||||
padding-left:5px;
|
||||
margin-top:-8px;
|
||||
}
|
||||
/*when formstyle=ul*/
|
||||
form>ul{
|
||||
list-style:none;
|
||||
margin:0;
|
||||
}
|
||||
li#auth_user_remember__row{margin-top:4px;}
|
||||
li#auth_user_remember__row>.w2p_fl{display:none;}
|
||||
li#auth_user_remember__row>.w2p_fw{min-height:39px;}
|
||||
/*when formstyle=bootstrap*/
|
||||
#auth_user_remember__row label.checkbox{display:block;}
|
||||
span.inline-help{display:inline-block;}
|
||||
input[type="text"].input-xlarge,input[type="password"].input-xlarge{width:270px;}
|
||||
/*when recaptcha is used*/
|
||||
#recaptcha{min-height:30px;display:inline-block;margin-bottom:0;line-height:30px;vertical-align:middle;}
|
||||
td>#recaptcha{margin-bottom:6px;}
|
||||
div>#recaptcha{margin-bottom:9px;}
|
||||
div.control-group.error{
|
||||
width:auto;
|
||||
background:transparent;
|
||||
border:0;
|
||||
color:inherit;
|
||||
padding:0;
|
||||
background-repeat:repeat;
|
||||
}
|
||||
|
||||
/*=============================================================
|
||||
OTHER RULES
|
||||
==============================================================*/
|
||||
|
||||
/* Massimo Di Pierro fixed alignment in forms with list:string */
|
||||
form table tr{margin-bottom:9px;}
|
||||
td.w2p_fw ul{margin-left:0px;}
|
||||
|
||||
/* web2py_console in grid and smartgrid */
|
||||
.hidden{visibility:visible;}
|
||||
.web2py_console input{
|
||||
display: inline-block;
|
||||
margin-bottom: 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.web2py_console input[type="submit"],
|
||||
.web2py_console input[type="button"],
|
||||
.web2py_console button{
|
||||
padding-top:4px;
|
||||
padding-bottom:4px;
|
||||
margin:3px 0 0 2px;
|
||||
}
|
||||
.web2py_console a,
|
||||
.web2py_console select,
|
||||
.web2py_console input
|
||||
{
|
||||
margin:3px 0 0 2px;
|
||||
}
|
||||
.web2py_grid form table{width:auto;}
|
||||
/* auth_user_remember checkbox extrapadding in IE fix */
|
||||
.ie-lte9 input#auth_user_remember.checkbox {padding-left:0;}
|
||||
|
||||
/*=============================================================
|
||||
MEDIA QUERIES
|
||||
==============================================================*/
|
||||
|
||||
@media only screen and (max-width:979px){
|
||||
body{padding-top:0px;}
|
||||
#navbar{top:5px;}
|
||||
div.flash{right:5px;}
|
||||
.dropdown-menu ul{visibility:visible;}
|
||||
}
|
||||
@media only screen and (max-width:479px){
|
||||
body{
|
||||
padding-left:10px;
|
||||
padding-right:10px;
|
||||
}
|
||||
.navbar-fixed-top,.navbar-fixed-bottom {
|
||||
margin-left:-10px;
|
||||
margin-right:-10px;
|
||||
}
|
||||
input[type="text"],input[type="password"],select{
|
||||
width:95%;
|
||||
}
|
||||
}
|
||||
122
applications/admin/static/css/web2py_bootstrap_nojs.css
Normal file
122
applications/admin/static/css/web2py_bootstrap_nojs.css
Normal file
@@ -0,0 +1,122 @@
|
||||
/*=============================================================
|
||||
BOOTSTRAP DROPDOWN MENU
|
||||
==============================================================*/
|
||||
|
||||
.dropdown-menu ul{
|
||||
left:100%;
|
||||
position:absolute;
|
||||
top:0;
|
||||
visibility:hidden;
|
||||
margin-top:-1px;
|
||||
}
|
||||
.dropdown-menu li:hover ul{visibility:visible;}
|
||||
.navbar .dropdown-menu ul:before{
|
||||
border-bottom:7px solid transparent;
|
||||
border-left:none;
|
||||
border-right:7px solid rgba(0, 0, 0, 0.2);
|
||||
border-top:7px solid transparent;
|
||||
left:-7px;
|
||||
top:5px;
|
||||
}
|
||||
.nav > li.dropdown > a:after {
|
||||
border-left: 4px solid transparent;
|
||||
border-right: 4px solid transparent;
|
||||
border-top: 4px solid #000000;
|
||||
content: "";
|
||||
display: inline-block;
|
||||
height: 0;
|
||||
opacity: 0.7;
|
||||
vertical-align: top;
|
||||
width: 0;
|
||||
|
||||
margin-left: 2px;
|
||||
margin-top: 8px;
|
||||
|
||||
border-bottom-color: #FFFFFF;
|
||||
border-top-color: #FFFFFF;
|
||||
}
|
||||
.dropdown-menu span{display:inline-block;}
|
||||
ul.dropdown-menu li.dropdown > a:after {
|
||||
border-left: 4px solid #000;
|
||||
border-right: 4px solid transparent;
|
||||
border-bottom: 4px solid transparent;
|
||||
border-top: 4px solid transparent;
|
||||
content: "";
|
||||
display: inline-block;
|
||||
height: 0;
|
||||
opacity: 0.7;
|
||||
vertical-align: top;
|
||||
width: 0;
|
||||
|
||||
margin-left: 8px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
ul.nav li.dropdown:hover ul.dropdown-menu {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.open >.dropdown-menu ul{display:block;} /* fix menu issue when BS2.0.4 is applied */
|
||||
|
||||
/*=============================================================
|
||||
BOOTSTRAP SUBMIT BUTTON
|
||||
==============================================================*/
|
||||
|
||||
input[type='submit']:not(.btn) {
|
||||
display: inline-block;
|
||||
padding: 4px 14px;
|
||||
margin-bottom: 0;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
background-color: whiteSmoke;
|
||||
background-image: -webkit-gradient(linear,0 0,0 100%,from(white),to(#E6E6E6));
|
||||
background-image: -webkit-linear-gradient(top,white,#E6E6E6);
|
||||
background-image: -o-linear-gradient(top,white,#E6E6E6);
|
||||
background-image: linear-gradient(to bottom,white,#E6E6E6);
|
||||
background-image: -moz-linear-gradient(top,white,#E6E6E6);
|
||||
background-repeat: repeat-x;
|
||||
border: 1px solid #BBB;
|
||||
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
||||
border-bottom-color: #A2A2A2;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);
|
||||
filter: progid:dximagetransform.microsoft.gradient(enabled=false);
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
-moz-box-shadow: inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
input[type='submit']:not(.btn):hover {
|
||||
color: #333;
|
||||
text-decoration: none;
|
||||
background-color: #E6E6E6;
|
||||
background-position: 0 -15px;
|
||||
-webkit-transition: background-position .1s linear;
|
||||
-moz-transition: background-position .1s linear;
|
||||
-o-transition: background-position .1s linear;
|
||||
transition: background-position .1s linear;
|
||||
}
|
||||
|
||||
input[type='submit']:not(.btn).active, input[type='submit']:not(.btn):active {
|
||||
background-color: #E6E6E6;
|
||||
background-color: #D9D9D9 9;
|
||||
background-image: none;
|
||||
outline: 0;
|
||||
-webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
-moz-box-shadow: inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);
|
||||
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
/*=============================================================
|
||||
OTHER
|
||||
==============================================================*/
|
||||
|
||||
.ie-lte8 .navbar-fixed-top {position:static;}
|
||||
|
||||
BIN
applications/admin/static/images/glyphicons-halflings-white.png
Normal file
BIN
applications/admin/static/images/glyphicons-halflings-white.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.6 KiB |
BIN
applications/admin/static/images/glyphicons-halflings.png
Normal file
BIN
applications/admin/static/images/glyphicons-halflings.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
BIN
applications/admin/static/images/menu_responsive.png
Normal file
BIN
applications/admin/static/images/menu_responsive.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
@@ -170,7 +170,11 @@ function doToggleBreakpoint(filename, url) {
|
||||
success: function(json,text,xhr){
|
||||
// show flash message (if any)
|
||||
var flash=xhr.getResponseHeader('web2py-component-flash');
|
||||
if (flash) jQuery('.flash').html(decodeURIComponent(flash)).slideDown();
|
||||
if (flash) {
|
||||
jQuery('.flash').html(decodeURIComponent(flash))
|
||||
.append('<a href="#" class="close">×</a>')
|
||||
.slideDown();
|
||||
}
|
||||
else jQuery('.flash').hide();
|
||||
try {
|
||||
if (json.error) {
|
||||
|
||||
4
applications/admin/static/js/analytics.min.js
vendored
Normal file
4
applications/admin/static/js/analytics.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
6
applications/admin/static/js/bootstrap.min.js
vendored
Normal file
6
applications/admin/static/js/bootstrap.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
13
applications/admin/static/js/dd_belatedpng.js
Normal file
13
applications/admin/static/js/dd_belatedpng.js
Normal file
File diff suppressed because one or more lines are too long
60
applications/admin/static/js/jquery.flot.resize.js
Normal file
60
applications/admin/static/js/jquery.flot.resize.js
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
Flot plugin for automatically redrawing plots when the placeholder
|
||||
size changes, e.g. on window resizes.
|
||||
|
||||
It works by listening for changes on the placeholder div (through the
|
||||
jQuery resize event plugin) - if the size changes, it will redraw the
|
||||
plot.
|
||||
|
||||
There are no options. If you need to disable the plugin for some
|
||||
plots, you can just fix the size of their placeholders.
|
||||
*/
|
||||
|
||||
|
||||
/* Inline dependency:
|
||||
* jQuery resize event - v1.1 - 3/14/2010
|
||||
* http://benalman.com/projects/jquery-resize-plugin/
|
||||
*
|
||||
* Copyright (c) 2010 "Cowboy" Ben Alman
|
||||
* Dual licensed under the MIT and GPL licenses.
|
||||
* http://benalman.com/about/license/
|
||||
*/
|
||||
(function($,h,c){var a=$([]),e=$.resize=$.extend($.resize,{}),i,k="setTimeout",j="resize",d=j+"-special-event",b="delay",f="throttleWindow";e[b]=250;e[f]=true;$.event.special[j]={setup:function(){if(!e[f]&&this[k]){return false}var l=$(this);a=a.add(l);$.data(this,d,{w:l.width(),h:l.height()});if(a.length===1){g()}},teardown:function(){if(!e[f]&&this[k]){return false}var l=$(this);a=a.not(l);l.removeData(d);if(!a.length){clearTimeout(i)}},add:function(l){if(!e[f]&&this[k]){return false}var n;function m(s,o,p){var q=$(this),r=$.data(this,d);r.w=o!==c?o:q.width();r.h=p!==c?p:q.height();n.apply(this,arguments)}if($.isFunction(l)){n=l;return m}else{n=l.handler;l.handler=m}}};function g(){i=h[k](function(){a.each(function(){var n=$(this),m=n.width(),l=n.height(),o=$.data(this,d);if(m!==o.w||l!==o.h){n.trigger(j,[o.w=m,o.h=l])}});g()},e[b])}})(jQuery,this);
|
||||
|
||||
|
||||
(function ($) {
|
||||
var options = { }; // no options
|
||||
|
||||
function init(plot) {
|
||||
function onResize() {
|
||||
var placeholder = plot.getPlaceholder();
|
||||
|
||||
// somebody might have hidden us and we can't plot
|
||||
// when we don't have the dimensions
|
||||
if (placeholder.width() == 0 || placeholder.height() == 0)
|
||||
return;
|
||||
|
||||
plot.resize();
|
||||
plot.setupGrid();
|
||||
plot.draw();
|
||||
}
|
||||
|
||||
function bindEvents(plot, eventHolder) {
|
||||
plot.getPlaceholder().resize(onResize);
|
||||
}
|
||||
|
||||
function shutdown(plot, eventHolder) {
|
||||
plot.getPlaceholder().unbind("resize", onResize);
|
||||
}
|
||||
|
||||
plot.hooks.bindEvents.push(bindEvents);
|
||||
plot.hooks.shutdown.push(shutdown);
|
||||
}
|
||||
|
||||
$.plot.plugins.push({
|
||||
init: init,
|
||||
options: options,
|
||||
name: 'resize',
|
||||
version: '1.0'
|
||||
});
|
||||
})(jQuery);
|
||||
44
applications/admin/static/js/share.js
Normal file
44
applications/admin/static/js/share.js
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
|
||||
Created and copyrighted by Massimo Di Pierro <massimo.dipierro@gmail.com>
|
||||
(MIT license)
|
||||
|
||||
Example:
|
||||
|
||||
<script src="share.js"></script>
|
||||
|
||||
**/
|
||||
|
||||
jQuery(function(){
|
||||
var script_source = jQuery('script[src*="share.js"]').attr('src');
|
||||
var params = function(name,default_value) {
|
||||
var match = RegExp('[?&]' + name + '=([^&]*)').exec(script_source);
|
||||
return match && decodeURIComponent(match[1].replace(/\+/g, ' '))||default_value;
|
||||
}
|
||||
var path = params('static','social');
|
||||
var url = encodeURIComponent(window.location.href);
|
||||
var host = window.location.hostname;
|
||||
var title = escape(jQuery('title').text());
|
||||
var twit = 'http://twitter.com/home?status='+title+'%20'+url;
|
||||
var facebook = 'http://www.facebook.com/sharer.php?u='+url;
|
||||
var gplus = 'https://plus.google.com/share?url='+url;
|
||||
var tbar = '<div id="socialdrawer"><span>Share<br/></span><div id="sicons"><a href="'+twit+'" id="twit" title="Share on twitter"><img src="'+path+'/twitter.png" alt="Share on Twitter" width="32" height="32" /></a><a href="'+facebook+'" id="facebook" title="Share on Facebook"><img src="'+path+'/facebook.png" alt="Share on facebook" width="32" height="32" /></a><a href="'+gplus+'" id="gplus" title="Share on Google Plus"><img src="'+path+'/gplus-32.png" alt="Share on Google Plus" width="32" height="32" /></a></div></div>';
|
||||
// Add the share tool bar.
|
||||
jQuery('body').append(tbar);
|
||||
var st = jQuery('#socialdrawer');
|
||||
st.css({'opacity':'.7','z-index':'3000','background':'#FFF','border':'solid 1px #666','border-width':' 1px 0 0 1px','height':'20px','width':'40px','position':'fixed','bottom':'0','right':'0','padding':'2px 5px','overflow':'hidden','-webkit-border-top-left-radius':' 12px','-moz-border-radius-topleft':' 12px','border-top-left-radius':' 12px','-moz-box-shadow':' -3px -3px 3px rgba(0,0,0,0.5)','-webkit-box-shadow':' -3px -3px 3px rgba(0,0,0,0.5)','box-shadow':' -3px -3px 3px rgba(0,0,0,0.5)'});
|
||||
jQuery('#socialdrawer a').css({'float':'left','width':'32px','margin':'3px 2px 2px 2px','padding':'0','cursor':'pointer'});
|
||||
jQuery('#socialdrawer span').css({'float':'left','margin':'2px 3px','text-shadow':' 1px 1px 1px #FFF','color':'#444','font-size':'12px','line-height':'1em'});
|
||||
jQuery('#socialdrawer img').hide();
|
||||
// hover
|
||||
st.click(function(){
|
||||
jQuery(this).animate({height:'40px', width:'160px', opacity: 0.95}, 300);
|
||||
jQuery('#socialdrawer img').show();
|
||||
});
|
||||
//leave
|
||||
st.mouseleave(function(){
|
||||
st.animate({height:'20px', width: '40px', opacity: .7}, 300);
|
||||
jQuery('#socialdrawer img').hide();
|
||||
return false;
|
||||
} );
|
||||
});
|
||||
28
applications/admin/static/js/web2py_bootstrap.js
Normal file
28
applications/admin/static/js/web2py_bootstrap.js
Normal file
@@ -0,0 +1,28 @@
|
||||
// this code improves bootstrap menus and adds dropdown support
|
||||
jQuery(function(){
|
||||
jQuery('.nav>li>a').each(function(){
|
||||
if(jQuery(this).parent().find('ul').length)
|
||||
jQuery(this).attr({'class':'dropdown-toggle','data-toggle':'dropdown'}).append('<b class="caret"></b>');
|
||||
});
|
||||
jQuery('.nav li li').each(function(){
|
||||
if(jQuery(this).find('ul').length)
|
||||
jQuery(this).addClass('dropdown-submenu');
|
||||
});
|
||||
function hoverMenu(){
|
||||
var wid = document.documentElement.clientWidth; //faster than $(window).width() and cross browser
|
||||
if (wid>=980){
|
||||
jQuery('ul.nav a.dropdown-toggle').parent().hover(function(){
|
||||
mi = jQuery(this).addClass('open');
|
||||
mi.children('.dropdown-menu').stop(true, true).delay(200).fadeIn(400);
|
||||
}, function(){
|
||||
mi = jQuery(this);
|
||||
mi.children('.dropdown-menu').stop(true, true).delay(200).fadeOut(function(){mi.removeClass('open')});
|
||||
});
|
||||
};
|
||||
}
|
||||
hoverMenu(); // first page load
|
||||
jQuery(window).resize(hoverMenu); // on resize event
|
||||
jQuery('ul.nav li.dropdown a').click(function(){window.location=jQuery(this).attr('href');});
|
||||
// make all buttons bootstrap buttons
|
||||
jQuery('button, form input[type="submit"], form input[type="button"]').addClass('btn');
|
||||
});
|
||||
2
applications/admin/static/plugin_jqmobile/jquery.mobile-1.0.min.css
vendored
Normal file
2
applications/admin/static/plugin_jqmobile/jquery.mobile-1.0.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
173
applications/admin/static/plugin_jqmobile/jquery.mobile-1.0.min.js
vendored
Normal file
173
applications/admin/static/plugin_jqmobile/jquery.mobile-1.0.min.js
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
/*! jQuery Mobile v1.0 jquerymobile.com | jquery.org/license */
|
||||
(function(a,e){if(a.cleanData){var b=a.cleanData;a.cleanData=function(f){for(var c=0,h;(h=f[c])!=null;c++)a(h).triggerHandler("remove");b(f)}}else{var d=a.fn.remove;a.fn.remove=function(b,c){return this.each(function(){c||(!b||a.filter(b,[this]).length)&&a("*",this).add([this]).each(function(){a(this).triggerHandler("remove")});return d.call(a(this),b,c)})}}a.widget=function(b,c,h){var d=b.split(".")[0],e,b=b.split(".")[1];e=d+"-"+b;if(!h)h=c,c=a.Widget;a.expr[":"][e]=function(c){return!!a.data(c,
|
||||
b)};a[d]=a[d]||{};a[d][b]=function(a,b){arguments.length&&this._createWidget(a,b)};c=new c;c.options=a.extend(true,{},c.options);a[d][b].prototype=a.extend(true,c,{namespace:d,widgetName:b,widgetEventPrefix:a[d][b].prototype.widgetEventPrefix||b,widgetBaseClass:e},h);a.widget.bridge(b,a[d][b])};a.widget.bridge=function(b,c){a.fn[b]=function(d){var g=typeof d==="string",i=Array.prototype.slice.call(arguments,1),k=this,d=!g&&i.length?a.extend.apply(null,[true,d].concat(i)):d;if(g&&d.charAt(0)==="_")return k;
|
||||
g?this.each(function(){var c=a.data(this,b);if(!c)throw"cannot call methods on "+b+" prior to initialization; attempted to call method '"+d+"'";if(!a.isFunction(c[d]))throw"no such method '"+d+"' for "+b+" widget instance";var g=c[d].apply(c,i);if(g!==c&&g!==e)return k=g,false}):this.each(function(){var e=a.data(this,b);e?e.option(d||{})._init():a.data(this,b,new c(d,this))});return k}};a.Widget=function(a,b){arguments.length&&this._createWidget(a,b)};a.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",
|
||||
options:{disabled:false},_createWidget:function(b,c){a.data(c,this.widgetName,this);this.element=a(c);this.options=a.extend(true,{},this.options,this._getCreateOptions(),b);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()});this._create();this._trigger("create");this._init()},_getCreateOptions:function(){var b={};a.metadata&&(b=a.metadata.get(element)[this.widgetName]);return b},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);
|
||||
this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled ui-state-disabled")},widget:function(){return this.element},option:function(b,c){var d=b;if(arguments.length===0)return a.extend({},this.options);if(typeof b==="string"){if(c===e)return this.options[b];d={};d[b]=c}this._setOptions(d);return this},_setOptions:function(b){var c=this;a.each(b,function(a,b){c._setOption(a,b)});return this},_setOption:function(a,b){this.options[a]=b;a==="disabled"&&
|
||||
this.widget()[b?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",b);return this},enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(b,c,d){var e=this.options[b],c=a.Event(c);c.type=(b===this.widgetEventPrefix?b:this.widgetEventPrefix+b).toLowerCase();d=d||{};if(c.originalEvent)for(var b=a.event.props.length,i;b;)i=a.event.props[--b],c[i]=c.originalEvent[i];this.element.trigger(c,
|
||||
d);return!(a.isFunction(e)&&e.call(this.element[0],c,d)===false||c.isDefaultPrevented())}}})(jQuery);
|
||||
(function(a,e){a.widget("mobile.widget",{_createWidget:function(){a.Widget.prototype._createWidget.apply(this,arguments);this._trigger("init")},_getCreateOptions:function(){var b=this.element,d={};a.each(this.options,function(a){var c=b.jqmData(a.replace(/[A-Z]/g,function(a){return"-"+a.toLowerCase()}));c!==e&&(d[a]=c)});return d},enhanceWithin:function(b){var d=a(b).closest(":jqmData(role='page')").data("page"),d=d&&d.keepNativeSelector()||"";a(this.options.initSelector,b).not(d)[this.widgetName]()}})})(jQuery);
|
||||
(function(a){a(window);var e=a("html");a.mobile.media=function(){var b={},d=a("<div id='jquery-mediatest'>"),f=a("<body>").append(d);return function(a){if(!(a in b)){var h=document.createElement("style"),g="@media "+a+" { #jquery-mediatest { position:absolute; } }";h.type="text/css";h.styleSheet?h.styleSheet.cssText=g:h.appendChild(document.createTextNode(g));e.prepend(f).prepend(h);b[a]=d.css("position")==="absolute";f.add(h).remove()}return b[a]}}()})(jQuery);
|
||||
(function(a,e){function b(a){var b=a.charAt(0).toUpperCase()+a.substr(1),a=(a+" "+c.join(b+" ")+b).split(" "),d;for(d in a)if(f[a[d]]!==e)return true}var d=a("<body>").prependTo("html"),f=d[0].style,c=["Webkit","Moz","O"],h="palmGetResource"in window,g=window.operamini&&{}.toString.call(window.operamini)==="[object OperaMini]",i=window.blackberry;a.mobile.browser={};a.mobile.browser.ie=function(){for(var a=3,b=document.createElement("div"),c=b.all||[];b.innerHTML="<\!--[if gt IE "+ ++a+"]><br><![endif]--\>",
|
||||
c[0];);return a>4?a:!a}();a.extend(a.support,{orientation:"orientation"in window&&"onorientationchange"in window,touch:"ontouchend"in document,cssTransitions:"WebKitTransitionEvent"in window,pushState:"pushState"in history&&"replaceState"in history,mediaquery:a.mobile.media("only all"),cssPseudoElement:!!b("content"),touchOverflow:!!b("overflowScrolling"),boxShadow:!!b("boxShadow")&&!i,scrollTop:("pageXOffset"in window||"scrollTop"in document.documentElement||"scrollTop"in d[0])&&!h&&!g,dynamicBaseTag:function(){var b=
|
||||
location.protocol+"//"+location.host+location.pathname+"ui-dir/",c=a("head base"),f=null,e="",h;c.length?e=c.attr("href"):c=f=a("<base>",{href:b}).appendTo("head");h=a("<a href='testurl' />").prependTo(d)[0].href;c[0].href=e||location.pathname;f&&f.remove();return h.indexOf(b)===0}()});d.remove();h=function(){var a=window.navigator.userAgent;return a.indexOf("Nokia")>-1&&(a.indexOf("Symbian/3")>-1||a.indexOf("Series60/5")>-1)&&a.indexOf("AppleWebKit")>-1&&a.match(/(BrowserNG|NokiaBrowser)\/7\.[0-3]/)}();
|
||||
a.mobile.ajaxBlacklist=window.blackberry&&!window.WebKitPoint||g||h;h&&a(function(){a("head link[rel='stylesheet']").attr("rel","alternate stylesheet").attr("rel","stylesheet")});a.support.boxShadow||a("html").addClass("ui-mobile-nosupport-boxshadow")})(jQuery);
|
||||
(function(a,e,b,d){function f(a){for(;a&&typeof a.originalEvent!=="undefined";)a=a.originalEvent;return a}function c(b){for(var c={},f,d;b;){f=a.data(b,n);for(d in f)if(f[d])c[d]=c.hasVirtualBinding=true;b=b.parentNode}return c}function h(){v&&(clearTimeout(v),v=0);v=setTimeout(function(){E=v=0;u.length=0;D=false;y=true},a.vmouse.resetTimerDuration)}function g(b,c,r){var e,h;if(!(h=r&&r[b])){if(r=!r)a:{for(r=c.target;r;){if((h=a.data(r,n))&&(!b||h[b]))break a;r=r.parentNode}r=null}h=r}if(h){e=c;var r=
|
||||
e.type,j,g;e=a.Event(e);e.type=b;h=e.originalEvent;j=a.event.props;if(h)for(g=j.length;g;)b=j[--g],e[b]=h[b];if(r.search(/mouse(down|up)|click/)>-1&&!e.which)e.which=1;if(r.search(/^touch/)!==-1&&(b=f(h),r=b.touches,b=b.changedTouches,r=r&&r.length?r[0]:b&&b.length?b[0]:d))for(h=0,len=z.length;h<len;h++)b=z[h],e[b]=r[b];a(c.target).trigger(e)}return e}function i(b){var c=a.data(b.target,A);if(!D&&(!E||E!==c))if(c=g("v"+b.type,b))c.isDefaultPrevented()&&b.preventDefault(),c.isPropagationStopped()&&
|
||||
b.stopPropagation(),c.isImmediatePropagationStopped()&&b.stopImmediatePropagation()}function k(b){var d=f(b).touches,e;if(d&&d.length===1&&(e=b.target,d=c(e),d.hasVirtualBinding))E=r++,a.data(e,A,E),v&&(clearTimeout(v),v=0),w=y=false,e=f(b).touches[0],x=e.pageX,t=e.pageY,g("vmouseover",b,d),g("vmousedown",b,d)}function l(a){y||(w||g("vmousecancel",a,c(a.target)),w=true,h())}function o(b){if(!y){var d=f(b).touches[0],r=w,e=a.vmouse.moveDistanceThreshold;w=w||Math.abs(d.pageX-x)>e||Math.abs(d.pageY-
|
||||
t)>e;flags=c(b.target);w&&!r&&g("vmousecancel",b,flags);g("vmousemove",b,flags);h()}}function m(a){if(!y){y=true;var b=c(a.target),d;g("vmouseup",a,b);if(!w&&(d=g("vclick",a,b))&&d.isDefaultPrevented())d=f(a).changedTouches[0],u.push({touchID:E,x:d.clientX,y:d.clientY}),D=true;g("vmouseout",a,b);w=false;h()}}function p(b){var b=a.data(b,n),c;if(b)for(c in b)if(b[c])return true;return false}function j(){}function q(b){var c=b.substr(1);return{setup:function(){p(this)||a.data(this,n,{});a.data(this,
|
||||
n)[b]=true;s[b]=(s[b]||0)+1;s[b]===1&&B.bind(c,i);a(this).bind(c,j);if(C)s.touchstart=(s.touchstart||0)+1,s.touchstart===1&&B.bind("touchstart",k).bind("touchend",m).bind("touchmove",o).bind("scroll",l)},teardown:function(){--s[b];s[b]||B.unbind(c,i);C&&(--s.touchstart,s.touchstart||B.unbind("touchstart",k).unbind("touchmove",o).unbind("touchend",m).unbind("scroll",l));var d=a(this),f=a.data(this,n);f&&(f[b]=false);d.unbind(c,j);p(this)||d.removeData(n)}}}var n="virtualMouseBindings",A="virtualTouchID",
|
||||
e="vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel".split(" "),z="clientX clientY pageX pageY screenX screenY".split(" "),s={},v=0,x=0,t=0,w=false,u=[],D=false,y=false,C="addEventListener"in b,B=a(b),r=1,E=0;a.vmouse={moveDistanceThreshold:10,clickDistanceThreshold:10,resetTimerDuration:1500};for(var F=0;F<e.length;F++)a.event.special[e[F]]=q(e[F]);C&&b.addEventListener("click",function(b){var c=u.length,d=b.target,f,r,e,h,j;if(c){f=b.clientX;r=b.clientY;threshold=a.vmouse.clickDistanceThreshold;
|
||||
for(e=d;e;){for(h=0;h<c;h++)if(j=u[h],e===d&&Math.abs(j.x-f)<threshold&&Math.abs(j.y-r)<threshold||a.data(e,A)===j.touchID){b.preventDefault();b.stopPropagation();return}e=e.parentNode}}},true)})(jQuery,window,document);
|
||||
(function(a,e,b){function d(b,c,d){var f=d.type;d.type=c;a.event.handle.call(b,d);d.type=f}a.each("touchstart touchmove touchend orientationchange throttledresize tap taphold swipe swipeleft swiperight scrollstart scrollstop".split(" "),function(b,c){a.fn[c]=function(a){return a?this.bind(c,a):this.trigger(c)};a.attrFn[c]=true});var f=a.support.touch,c=f?"touchstart":"mousedown",h=f?"touchend":"mouseup",g=f?"touchmove":"mousemove";a.event.special.scrollstart={enabled:true,setup:function(){function b(a,
|
||||
e){f=e;d(c,f?"scrollstart":"scrollstop",a)}var c=this,f,e;a(c).bind("touchmove scroll",function(c){a.event.special.scrollstart.enabled&&(f||b(c,true),clearTimeout(e),e=setTimeout(function(){b(c,false)},50))})}};a.event.special.tap={setup:function(){var b=this,c=a(b);c.bind("vmousedown",function(f){function e(){clearTimeout(q)}function h(){e();c.unbind("vclick",g).unbind("vmouseup",e).unbind("vmousecancel",h)}function g(a){h();j==a.target&&d(b,"tap",a)}if(f.which&&f.which!==1)return false;var j=f.target,
|
||||
q;c.bind("vmousecancel",h).bind("vmouseup",e).bind("vclick",g);q=setTimeout(function(){d(b,"taphold",a.Event("taphold"))},750)})}};a.event.special.swipe={scrollSupressionThreshold:10,durationThreshold:1E3,horizontalDistanceThreshold:30,verticalDistanceThreshold:75,setup:function(){var d=a(this);d.bind(c,function(c){function f(b){if(m){var c=b.originalEvent.touches?b.originalEvent.touches[0]:b;p={time:(new Date).getTime(),coords:[c.pageX,c.pageY]};Math.abs(m.coords[0]-p.coords[0])>a.event.special.swipe.scrollSupressionThreshold&&
|
||||
b.preventDefault()}}var e=c.originalEvent.touches?c.originalEvent.touches[0]:c,m={time:(new Date).getTime(),coords:[e.pageX,e.pageY],origin:a(c.target)},p;d.bind(g,f).one(h,function(){d.unbind(g,f);m&&p&&p.time-m.time<a.event.special.swipe.durationThreshold&&Math.abs(m.coords[0]-p.coords[0])>a.event.special.swipe.horizontalDistanceThreshold&&Math.abs(m.coords[1]-p.coords[1])<a.event.special.swipe.verticalDistanceThreshold&&m.origin.trigger("swipe").trigger(m.coords[0]>p.coords[0]?"swipeleft":"swiperight");
|
||||
m=p=b})})}};(function(a,b){function c(){var a=f();a!==e&&(e=a,d.trigger("orientationchange"))}var d=a(b),f,e;a.event.special.orientationchange={setup:function(){if(a.support.orientation&&a.mobile.orientationChangeEnabled)return false;e=f();d.bind("throttledresize",c)},teardown:function(){if(a.support.orientation&&a.mobile.orientationChangeEnabled)return false;d.unbind("throttledresize",c)},add:function(a){var b=a.handler;a.handler=function(a){a.orientation=f();return b.apply(this,arguments)}}};a.event.special.orientationchange.orientation=
|
||||
f=function(){var c=true,c=document.documentElement;return(c=a.support.orientation?b.orientation%180==0:c&&c.clientWidth/c.clientHeight<1.1)?"portrait":"landscape"}})(jQuery,e);(function(){a.event.special.throttledresize={setup:function(){a(this).bind("resize",b)},teardown:function(){a(this).unbind("resize",b)}};var b=function(){f=(new Date).getTime();e=f-c;e>=250?(c=f,a(this).trigger("throttledresize")):(d&&clearTimeout(d),d=setTimeout(b,250-e))},c=0,d,f,e})();a.each({scrollstop:"scrollstart",taphold:"tap",
|
||||
swipeleft:"swipe",swiperight:"swipe"},function(b,c){a.event.special[b]={setup:function(){a(this).bind(c,a.noop)}}})})(jQuery,this);
|
||||
(function(a,e,b){function d(a){a=a||location.href;return"#"+a.replace(/^[^#]*#?(.*)$/,"$1")}var f="hashchange",c=document,h,g=a.event.special,i=c.documentMode,k="on"+f in e&&(i===b||i>7);a.fn[f]=function(a){return a?this.bind(f,a):this.trigger(f)};a.fn[f].delay=50;g[f]=a.extend(g[f],{setup:function(){if(k)return false;a(h.start)},teardown:function(){if(k)return false;a(h.stop)}});h=function(){function h(){var b=d(),c=n(p);if(b!==p)q(p=b,c),a(e).trigger(f);else if(c!==p)location.href=location.href.replace(/#.*/,
|
||||
"")+c;i=setTimeout(h,a.fn[f].delay)}var g={},i,p=d(),j=function(a){return a},q=j,n=j;g.start=function(){i||h()};g.stop=function(){i&&clearTimeout(i);i=b};a.browser.msie&&!k&&function(){var b,e;g.start=function(){if(!b)e=(e=a.fn[f].src)&&e+d(),b=a('<iframe tabindex="-1" title="empty"/>').hide().one("load",function(){e||q(d());h()}).attr("src",e||"javascript:0").insertAfter("body")[0].contentWindow,c.onpropertychange=function(){try{if(event.propertyName==="title")b.document.title=c.title}catch(a){}}};
|
||||
g.stop=j;n=function(){return d(b.location.href)};q=function(d,e){var h=b.document,g=a.fn[f].domain;if(d!==e)h.title=c.title,h.open(),g&&h.write('<script>document.domain="'+g+'"<\/script>'),h.close(),b.location.hash=d}}();return g}()})(jQuery,this);
|
||||
(function(a){a.widget("mobile.page",a.mobile.widget,{options:{theme:"c",domCache:false,keepNativeDefault:":jqmData(role='none'), :jqmData(role='nojs')"},_create:function(){this._trigger("beforecreate");this.element.attr("tabindex","0").addClass("ui-page ui-body-"+this.options.theme)},keepNativeSelector:function(){var e=this.options;return e.keepNative&&a.trim(e.keepNative)&&e.keepNative!==e.keepNativeDefault?[e.keepNative,e.keepNativeDefault].join(", "):e.keepNativeDefault}})})(jQuery);
|
||||
(function(a,e){var b={};a.extend(a.mobile,{ns:"",subPageUrlKey:"ui-page",activePageClass:"ui-page-active",activeBtnClass:"ui-btn-active",ajaxEnabled:true,hashListeningEnabled:true,linkBindingEnabled:true,defaultPageTransition:"slide",minScrollBack:250,defaultDialogTransition:"pop",loadingMessage:"loading",pageLoadErrorMessage:"Error Loading Page",autoInitializePage:true,pushStateEnabled:true,orientationChangeEnabled:true,gradeA:function(){return a.support.mediaquery||a.mobile.browser.ie&&a.mobile.browser.ie>=
|
||||
7},keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91},silentScroll:function(b){if(a.type(b)!=="number")b=a.mobile.defaultHomeScroll;a.event.special.scrollstart.enabled=false;
|
||||
setTimeout(function(){e.scrollTo(0,b);a(document).trigger("silentscroll",{x:0,y:b})},20);setTimeout(function(){a.event.special.scrollstart.enabled=true},150)},nsNormalizeDict:b,nsNormalize:function(c){return!c?void 0:b[c]||(b[c]=a.camelCase(a.mobile.ns+c))},getInheritedTheme:function(a,b){for(var d=a[0],f="",e=/ui-(bar|body)-([a-z])\b/,l,o;d;){l=d.className||"";if((o=e.exec(l))&&(f=o[2]))break;d=d.parentNode}return f||b||"a"}});a.fn.jqmData=function(b,d){var f;typeof b!="undefined"&&(f=this.data(b?
|
||||
a.mobile.nsNormalize(b):b,d));return f};a.jqmData=function(b,d,f){var e;typeof d!="undefined"&&(e=a.data(b,d?a.mobile.nsNormalize(d):d,f));return e};a.fn.jqmRemoveData=function(b){return this.removeData(a.mobile.nsNormalize(b))};a.jqmRemoveData=function(b,d){return a.removeData(b,a.mobile.nsNormalize(d))};a.fn.removeWithDependents=function(){a.removeWithDependents(this)};a.removeWithDependents=function(b){b=a(b);(b.jqmData("dependents")||a()).remove();b.remove()};a.fn.addDependents=function(b){a.addDependents(a(this),
|
||||
b)};a.addDependents=function(b,d){var f=a(b).jqmData("dependents")||a();a(b).jqmData("dependents",a.merge(f,d))};a.fn.getEncodedText=function(){return a("<div/>").text(a(this).text()).html()};var d=a.find,f=/:jqmData\(([^)]*)\)/g;a.find=function(b,e,g,i){b=b.replace(f,"[data-"+(a.mobile.ns||"")+"$1]");return d.call(this,b,e,g,i)};a.extend(a.find,d);a.find.matches=function(b,d){return a.find(b,null,null,d)};a.find.matchesSelector=function(b,d){return a.find(d,null,null,[b]).length>0}})(jQuery,this);
|
||||
(function(a,e){function b(a){var b=a.find(".ui-title:eq(0)");b.length?b.focus():a.focus()}function d(b){q&&(!q.closest(".ui-page-active").length||b)&&q.removeClass(a.mobile.activeBtnClass);q=null}function f(){z=false;A.length>0&&a.mobile.changePage.apply(null,A.pop())}function c(c,d,f,e){var g=a.mobile.urlHistory.getActive(),j=a.support.touchOverflow&&a.mobile.touchOverflowEnabled,i=g.lastScroll||(j?0:a.mobile.defaultHomeScroll),g=h();window.scrollTo(0,a.mobile.defaultHomeScroll);d&&d.data("page")._trigger("beforehide",
|
||||
null,{nextPage:c});j||c.height(g+i);c.data("page")._trigger("beforeshow",null,{prevPage:d||a("")});a.mobile.hidePageLoadingMsg();j&&i&&(c.addClass("ui-mobile-pre-transition"),b(c),c.is(".ui-native-fixed")?c.find(".ui-content").scrollTop(i):c.scrollTop(i));f=(a.mobile.transitionHandlers[f||"none"]||a.mobile.defaultTransitionHandler)(f,e,c,d);f.done(function(){j||(c.height(""),b(c));j||a.mobile.silentScroll(i);d&&(j||d.height(""),d.data("page")._trigger("hide",null,{nextPage:c}));c.data("page")._trigger("show",
|
||||
null,{prevPage:d||a("")})});return f}function h(){var b=a.event.special.orientationchange.orientation()==="portrait",c=b?screen.availHeight:screen.availWidth,b=Math.max(b?480:320,a(window).height());return Math.min(c,b)}function g(){(!a.support.touchOverflow||!a.mobile.touchOverflowEnabled)&&a("."+a.mobile.activePageClass).css("min-height",h())}function i(b,c){c&&b.attr("data-"+a.mobile.ns+"role",c);b.page()}function k(a){for(;a;){if(typeof a.nodeName==="string"&&a.nodeName.toLowerCase()=="a")break;
|
||||
a=a.parentNode}return a}function l(b){var b=a(b).closest(".ui-page").jqmData("url"),c=t.hrefNoHash;if(!b||!j.isPath(b))b=c;return j.makeUrlAbsolute(b,c)}var o=a(window),m=a("html"),p=a("head"),j={urlParseRE:/^(((([^:\/#\?]+:)?(?:(\/\/)((?:(([^:@\/#\?]+)(?:\:([^:@\/#\?]+))?)@)?(([^:\/#\?\]\[]+|\[[^\/\]@#?]+\])(?:\:([0-9]+))?))?)?)?((\/?(?:[^\/\?#]+\/+)*)([^\?#]*)))?(\?[^#]+)?)(#.*)?/,parseUrl:function(b){if(a.type(b)==="object")return b;b=j.urlParseRE.exec(b||"")||[];return{href:b[0]||"",hrefNoHash:b[1]||
|
||||
"",hrefNoSearch:b[2]||"",domain:b[3]||"",protocol:b[4]||"",doubleSlash:b[5]||"",authority:b[6]||"",username:b[8]||"",password:b[9]||"",host:b[10]||"",hostname:b[11]||"",port:b[12]||"",pathname:b[13]||"",directory:b[14]||"",filename:b[15]||"",search:b[16]||"",hash:b[17]||""}},makePathAbsolute:function(a,b){if(a&&a.charAt(0)==="/")return a;for(var a=a||"",c=(b=b?b.replace(/^\/|(\/[^\/]*|[^\/]+)$/g,""):"")?b.split("/"):[],d=a.split("/"),f=0;f<d.length;f++){var e=d[f];switch(e){case ".":break;case "..":c.length&&
|
||||
c.pop();break;default:c.push(e)}}return"/"+c.join("/")},isSameDomain:function(a,b){return j.parseUrl(a).domain===j.parseUrl(b).domain},isRelativeUrl:function(a){return j.parseUrl(a).protocol===""},isAbsoluteUrl:function(a){return j.parseUrl(a).protocol!==""},makeUrlAbsolute:function(a,b){if(!j.isRelativeUrl(a))return a;var c=j.parseUrl(a),d=j.parseUrl(b),f=c.protocol||d.protocol,e=c.protocol?c.doubleSlash:c.doubleSlash||d.doubleSlash,h=c.authority||d.authority,g=c.pathname!=="",i=j.makePathAbsolute(c.pathname||
|
||||
d.filename,d.pathname);return f+e+h+i+(c.search||!g&&d.search||"")+c.hash},addSearchParams:function(b,c){var d=j.parseUrl(b),f=typeof c==="object"?a.param(c):c,e=d.search||"?";return d.hrefNoSearch+e+(e.charAt(e.length-1)!=="?"?"&":"")+f+(d.hash||"")},convertUrlToDataUrl:function(a){var b=j.parseUrl(a);if(j.isEmbeddedPage(b))return b.hash.split(s)[0].replace(/^#/,"");else if(j.isSameDomain(b,t))return b.hrefNoHash.replace(t.domain,"");return a},get:function(a){if(a===e)a=location.hash;return j.stripHash(a).replace(/[^\/]*\.[^\/*]+$/,
|
||||
"")},getFilePath:function(b){var c="&"+a.mobile.subPageUrlKey;return b&&b.split(c)[0].split(s)[0]},set:function(a){location.hash=a},isPath:function(a){return/\//.test(a)},clean:function(a){return a.replace(t.domain,"")},stripHash:function(a){return a.replace(/^#/,"")},cleanHash:function(a){return j.stripHash(a.replace(/\?.*$/,"").replace(s,""))},isExternal:function(a){a=j.parseUrl(a);return a.protocol&&a.domain!==x.domain?true:false},hasProtocol:function(a){return/^(:?\w+:)/.test(a)},isFirstPageUrl:function(b){var b=
|
||||
j.parseUrl(j.makeUrlAbsolute(b,t)),c=a.mobile.firstPage,c=c&&c[0]?c[0].id:e;return(b.hrefNoHash===x.hrefNoHash||w&&b.hrefNoHash===t.hrefNoHash)&&(!b.hash||b.hash==="#"||c&&b.hash.replace(/^#/,"")===c)},isEmbeddedPage:function(a){a=j.parseUrl(a);return a.protocol!==""?a.hash&&(a.hrefNoHash===x.hrefNoHash||w&&a.hrefNoHash===t.hrefNoHash):/^#/.test(a.href)}},q=null,n={stack:[],activeIndex:0,getActive:function(){return n.stack[n.activeIndex]},getPrev:function(){return n.stack[n.activeIndex-1]},getNext:function(){return n.stack[n.activeIndex+
|
||||
1]},addNew:function(a,b,c,d,f){n.getNext()&&n.clearForward();n.stack.push({url:a,transition:b,title:c,pageUrl:d,role:f});n.activeIndex=n.stack.length-1},clearForward:function(){n.stack=n.stack.slice(0,n.activeIndex+1)},directHashChange:function(b){var c,d,f;this.getActive();a.each(n.stack,function(a,e){b.currentUrl===e.url&&(c=a<n.activeIndex,d=!c,f=a)});this.activeIndex=f!==e?f:this.activeIndex;c?(b.either||b.isBack)(true):d&&(b.either||b.isForward)(false)},ignoreNextHashChange:false},A=[],z=false,
|
||||
s="&ui-state=dialog",v=p.children("base"),x=j.parseUrl(location.href),t=v.length?j.parseUrl(j.makeUrlAbsolute(v.attr("href"),x.href)):x,w=x.hrefNoHash!==t.hrefNoHash,u=a.support.dynamicBaseTag?{element:v.length?v:a("<base>",{href:t.hrefNoHash}).prependTo(p),set:function(a){u.element.attr("href",j.makeUrlAbsolute(a,t))},reset:function(){u.element.attr("href",t.hrefNoHash)}}:e,D=true,y,C,B;y=function(){var b=o;a.support.touchOverflow&&a.mobile.touchOverflowEnabled&&(b=a(".ui-page-active"),b=b.is(".ui-native-fixed")?
|
||||
b.find(".ui-content"):b);return b};C=function(b){if(D){var c=a.mobile.urlHistory.getActive();if(c)b=b&&b.scrollTop(),c.lastScroll=b<a.mobile.minScrollBack?a.mobile.defaultHomeScroll:b}};B=function(){setTimeout(C,100,a(this))};o.bind(a.support.pushState?"popstate":"hashchange",function(){D=false});o.one(a.support.pushState?"popstate":"hashchange",function(){D=true});o.one("pagecontainercreate",function(){a.mobile.pageContainer.bind("pagechange",function(){var a=y();D=true;a.unbind("scrollstop",B);
|
||||
a.bind("scrollstop",B)})});y().bind("scrollstop",B);a.mobile.getScreenHeight=h;a.fn.animationComplete=function(b){return a.support.cssTransitions?a(this).one("webkitAnimationEnd",b):(setTimeout(b,0),a(this))};a.mobile.path=j;a.mobile.base=u;a.mobile.urlHistory=n;a.mobile.dialogHashKey=s;a.mobile.noneTransitionHandler=function(b,c,d,f){f&&f.removeClass(a.mobile.activePageClass);d.addClass(a.mobile.activePageClass);return a.Deferred().resolve(b,c,d,f).promise()};a.mobile.defaultTransitionHandler=a.mobile.noneTransitionHandler;
|
||||
a.mobile.transitionHandlers={none:a.mobile.defaultTransitionHandler};a.mobile.allowCrossDomainPages=false;a.mobile.getDocumentUrl=function(b){return b?a.extend({},x):x.href};a.mobile.getDocumentBase=function(b){return b?a.extend({},t):t.href};a.mobile._bindPageRemove=function(){var b=a(this);!b.data("page").options.domCache&&b.is(":jqmData(external-page='true')")&&b.bind("pagehide.remove",function(){var b=a(this),c=new a.Event("pageremove");b.trigger(c);c.isDefaultPrevented()||b.removeWithDependents()})};
|
||||
a.mobile.loadPage=function(b,c){var d=a.Deferred(),f=a.extend({},a.mobile.loadPage.defaults,c),h=null,g=null,m=j.makeUrlAbsolute(b,a.mobile.activePage&&l(a.mobile.activePage)||t.hrefNoHash);if(f.data&&f.type==="get")m=j.addSearchParams(m,f.data),f.data=e;if(f.data&&f.type==="post")f.reloadPage=true;var s=j.getFilePath(m),p=j.convertUrlToDataUrl(m);f.pageContainer=f.pageContainer||a.mobile.pageContainer;h=f.pageContainer.children(":jqmData(url='"+p+"')");h.length===0&&p&&!j.isPath(p)&&(h=f.pageContainer.children("#"+
|
||||
p).attr("data-"+a.mobile.ns+"url",p));if(h.length===0)if(a.mobile.firstPage&&j.isFirstPageUrl(s))a.mobile.firstPage.parent().length&&(h=a(a.mobile.firstPage));else if(j.isEmbeddedPage(s))return d.reject(m,c),d.promise();u&&u.reset();if(h.length){if(!f.reloadPage)return i(h,f.role),d.resolve(m,c,h),d.promise();g=h}var n=f.pageContainer,k=new a.Event("pagebeforeload"),q={url:b,absUrl:m,dataUrl:p,deferred:d,options:f};n.trigger(k,q);if(k.isDefaultPrevented())return d.promise();if(f.showLoadMsg)var v=
|
||||
setTimeout(function(){a.mobile.showPageLoadingMsg()},f.loadMsgDelay);!a.mobile.allowCrossDomainPages&&!j.isSameDomain(x,m)?d.reject(m,c):a.ajax({url:s,type:f.type,data:f.data,dataType:"html",success:function(e,n,k){var o=a("<div></div>"),l=e.match(/<title[^>]*>([^<]*)/)&&RegExp.$1,t=RegExp("\\bdata-"+a.mobile.ns+"url=[\"']?([^\"'>]*)[\"']?");RegExp("(<[^>]+\\bdata-"+a.mobile.ns+"role=[\"']?page[\"']?[^>]*>)").test(e)&&RegExp.$1&&t.test(RegExp.$1)&&RegExp.$1&&(b=s=j.getFilePath(RegExp.$1));u&&u.set(s);
|
||||
o.get(0).innerHTML=e;h=o.find(":jqmData(role='page'), :jqmData(role='dialog')").first();h.length||(h=a("<div data-"+a.mobile.ns+"role='page'>"+e.split(/<\/?body[^>]*>/gmi)[1]+"</div>"));l&&!h.jqmData("title")&&(~l.indexOf("&")&&(l=a("<div>"+l+"</div>").text()),h.jqmData("title",l));if(!a.support.dynamicBaseTag){var x=j.get(s);h.find("[src], link[href], a[rel='external'], :jqmData(ajax='false'), a[target]").each(function(){var b=a(this).is("[href]")?"href":a(this).is("[src]")?"src":"action",c=a(this).attr(b),
|
||||
c=c.replace(location.protocol+"//"+location.host+location.pathname,"");/^(\w+:|#|\/)/.test(c)||a(this).attr(b,x+c)})}h.attr("data-"+a.mobile.ns+"url",j.convertUrlToDataUrl(s)).attr("data-"+a.mobile.ns+"external-page",true).appendTo(f.pageContainer);h.one("pagecreate",a.mobile._bindPageRemove);i(h,f.role);m.indexOf("&"+a.mobile.subPageUrlKey)>-1&&(h=f.pageContainer.children(":jqmData(url='"+p+"')"));f.showLoadMsg&&(clearTimeout(v),a.mobile.hidePageLoadingMsg());q.xhr=k;q.textStatus=n;q.page=h;f.pageContainer.trigger("pageload",
|
||||
q);d.resolve(m,c,h,g)},error:function(b,e,h){u&&u.set(j.get());q.xhr=b;q.textStatus=e;q.errorThrown=h;b=new a.Event("pageloadfailed");f.pageContainer.trigger(b,q);b.isDefaultPrevented()||(f.showLoadMsg&&(clearTimeout(v),a.mobile.hidePageLoadingMsg(),a("<div class='ui-loader ui-overlay-shadow ui-body-e ui-corner-all'><h1>"+a.mobile.pageLoadErrorMessage+"</h1></div>").css({display:"block",opacity:0.96,top:o.scrollTop()+100}).appendTo(f.pageContainer).delay(800).fadeOut(400,function(){a(this).remove()})),
|
||||
d.reject(m,c))}});return d.promise()};a.mobile.loadPage.defaults={type:"get",data:e,reloadPage:false,role:e,showLoadMsg:false,pageContainer:e,loadMsgDelay:50};a.mobile.changePage=function(b,h){if(z)A.unshift(arguments);else{var g=a.extend({},a.mobile.changePage.defaults,h);g.pageContainer=g.pageContainer||a.mobile.pageContainer;g.fromPage=g.fromPage||a.mobile.activePage;var p=g.pageContainer,k=new a.Event("pagebeforechange"),q={toPage:b,options:g};p.trigger(k,q);if(!k.isDefaultPrevented())if(b=q.toPage,
|
||||
z=true,typeof b=="string")a.mobile.loadPage(b,g).done(function(b,c,d,f){z=false;c.duplicateCachedPage=f;a.mobile.changePage(d,c)}).fail(function(){z=false;d(true);f();g.pageContainer.trigger("pagechangefailed",q)});else{if(b[0]===a.mobile.firstPage[0]&&!g.dataUrl)g.dataUrl=x.hrefNoHash;var k=g.fromPage,l=g.dataUrl&&j.convertUrlToDataUrl(g.dataUrl)||b.jqmData("url"),v=l;j.getFilePath(l);var o=n.getActive(),t=n.activeIndex===0,w=0,u=document.title,y=g.role==="dialog"||b.jqmData("role")==="dialog";if(k&&
|
||||
k[0]===b[0]&&!g.allowSamePageTransition)z=false,p.trigger("pagechange",q);else{i(b,g.role);g.fromHashChange&&n.directHashChange({currentUrl:l,isBack:function(){w=-1},isForward:function(){w=1}});try{document.activeElement&&document.activeElement.nodeName.toLowerCase()!="body"?a(document.activeElement).blur():a("input:focus, textarea:focus, select:focus").blur()}catch(B){}y&&o&&(l=(o.url||"")+s);if(g.changeHash!==false&&l)n.ignoreNextHashChange=true,j.set(l);var C=!o?u:b.jqmData("title")||b.children(":jqmData(role='header')").find(".ui-title").getEncodedText();
|
||||
C&&u==document.title&&(u=C);b.jqmData("title")||b.jqmData("title",u);g.transition=g.transition||(w&&!t?o.transition:e)||(y?a.mobile.defaultDialogTransition:a.mobile.defaultPageTransition);w||n.addNew(l,g.transition,u,v,g.role);document.title=n.getActive().title;a.mobile.activePage=b;g.reverse=g.reverse||w<0;c(b,k,g.transition,g.reverse).done(function(){d();g.duplicateCachedPage&&g.duplicateCachedPage.remove();m.removeClass("ui-mobile-rendering");f();p.trigger("pagechange",q)})}}}};a.mobile.changePage.defaults=
|
||||
{transition:e,reverse:false,changeHash:true,fromHashChange:false,role:e,duplicateCachedPage:e,pageContainer:e,showLoadMsg:true,dataUrl:e,fromPage:e,allowSamePageTransition:false};a.mobile._registerInternalEvents=function(){a("form").live("submit",function(b){var c=a(this);if(a.mobile.ajaxEnabled&&!c.is(":jqmData(ajax='false')")){var d=c.attr("method"),f=c.attr("target"),e=c.attr("action");if(!e&&(e=l(c),e===t.hrefNoHash))e=x.hrefNoSearch;e=j.makeUrlAbsolute(e,l(c));!j.isExternal(e)&&!f&&(a.mobile.changePage(e,
|
||||
{type:d&&d.length&&d.toLowerCase()||"get",data:c.serialize(),transition:c.jqmData("transition"),direction:c.jqmData("direction"),reloadPage:true}),b.preventDefault())}});a(document).bind("vclick",function(b){if(!(b.which>1)&&a.mobile.linkBindingEnabled&&(b=k(b.target))&&j.parseUrl(b.getAttribute("href")||"#").hash!=="#")d(true),q=a(b).closest(".ui-btn").not(".ui-disabled"),q.addClass(a.mobile.activeBtnClass),a("."+a.mobile.activePageClass+" .ui-btn").not(b).blur()});a(document).bind("click",function(b){if(a.mobile.linkBindingEnabled){var c=
|
||||
k(b.target);if(c&&!(b.which>1)){var f=a(c),h=function(){window.setTimeout(function(){d(true)},200)};if(f.is(":jqmData(rel='back')"))return window.history.back(),false;var g=l(f),c=j.makeUrlAbsolute(f.attr("href")||"#",g);if(!a.mobile.ajaxEnabled&&!j.isEmbeddedPage(c))h();else{if(c.search("#")!=-1)if(c=c.replace(/[^#]*#/,""))c=j.isPath(c)?j.makeUrlAbsolute(c,g):j.makeUrlAbsolute("#"+c,x.hrefNoHash);else{b.preventDefault();return}var g=f.is("[rel='external']")||f.is(":jqmData(ajax='false')")||f.is("[target]"),
|
||||
i=a.mobile.allowCrossDomainPages&&x.protocol==="file:"&&c.search(/^https?:/)!=-1;g||j.isExternal(c)&&!i?h():(h=f.jqmData("transition"),g=(g=f.jqmData("direction"))&&g==="reverse"||f.jqmData("back"),f=f.attr("data-"+a.mobile.ns+"rel")||e,a.mobile.changePage(c,{transition:h,reverse:g,role:f}),b.preventDefault())}}}});a(".ui-page").live("pageshow.prefetch",function(){var b=[];a(this).find("a:jqmData(prefetch)").each(function(){var c=a(this),f=c.attr("href");f&&a.inArray(f,b)===-1&&(b.push(f),a.mobile.loadPage(f,
|
||||
{role:c.attr("data-"+a.mobile.ns+"rel")}))})});a.mobile._handleHashChange=function(b){var c=j.stripHash(b),f={transition:a.mobile.urlHistory.stack.length===0?"none":e,changeHash:false,fromHashChange:true};if(!a.mobile.hashListeningEnabled||n.ignoreNextHashChange)n.ignoreNextHashChange=false;else{if(n.stack.length>1&&c.indexOf(s)>-1)if(a.mobile.activePage.is(".ui-dialog"))n.directHashChange({currentUrl:c,either:function(b){var d=a.mobile.urlHistory.getActive();c=d.pageUrl;a.extend(f,{role:d.role,transition:d.transition,
|
||||
reverse:b})}});else{n.directHashChange({currentUrl:c,isBack:function(){window.history.back()},isForward:function(){window.history.forward()}});return}c?(c=typeof c==="string"&&!j.isPath(c)?j.makeUrlAbsolute("#"+c,t):c,a.mobile.changePage(c,f)):a.mobile.changePage(a.mobile.firstPage,f)}};o.bind("hashchange",function(){a.mobile._handleHashChange(location.hash)});a(document).bind("pageshow",g);a(window).bind("throttledresize",g)}})(jQuery);
|
||||
(function(a,e){var b={},d=a(e),f=a.mobile.path.parseUrl(location.href);a.extend(b,{initialFilePath:f.pathname+f.search,initialHref:f.hrefNoHash,hashchangeFired:false,state:function(){return{hash:location.hash||"#"+b.initialFilePath,title:document.title,initialHref:b.initialHref}},resetUIKeys:function(b){var f="&"+a.mobile.subPageUrlKey,d=b.indexOf(a.mobile.dialogHashKey);d>-1?b=b.slice(0,d)+"#"+b.slice(d):b.indexOf(f)>-1&&(b=b.split(f).join("#"+f));return b},nextHashChangePrevented:function(c){a.mobile.urlHistory.ignoreNextHashChange=
|
||||
c;b.onHashChangeDisabled=c},onHashChange:function(){if(!b.onHashChangeDisabled){var c,f;c=location.hash;var d=a.mobile.path.isPath(c),e=d?location.href:a.mobile.getDocumentUrl();c=d?c.replace("#",""):c;f=b.state();c=a.mobile.path.makeUrlAbsolute(c,e);d&&(c=b.resetUIKeys(c));history.replaceState(f,document.title,c)}},onPopState:function(c){var f=c.originalEvent.state;f&&(b.nextHashChangePrevented(true),setTimeout(function(){b.nextHashChangePrevented(false);a.mobile._handleHashChange(f.hash)},100))},
|
||||
init:function(){d.bind("hashchange",b.onHashChange);d.bind("popstate",b.onPopState);location.hash===""&&history.replaceState(b.state(),document.title,location.href)}});a(function(){a.mobile.pushStateEnabled&&a.support.pushState&&b.init()})})(jQuery,this);
|
||||
(function(a){function e(b,d,f,c){var e=new a.Deferred,g=d?" reverse":"",i="ui-mobile-viewport-transitioning viewport-"+b;f.animationComplete(function(){f.add(c).removeClass("out in reverse "+b);c&&c[0]!==f[0]&&c.removeClass(a.mobile.activePageClass);f.parent().removeClass(i);e.resolve(b,d,f,c)});f.parent().addClass(i);c&&c.addClass(b+" out"+g);f.addClass(a.mobile.activePageClass+" "+b+" in"+g);return e.promise()}a.mobile.css3TransitionHandler=e;if(a.mobile.defaultTransitionHandler===a.mobile.noneTransitionHandler)a.mobile.defaultTransitionHandler=
|
||||
e})(jQuery,this);
|
||||
(function(a){a.mobile.page.prototype.options.degradeInputs={color:false,date:false,datetime:false,"datetime-local":false,email:false,month:false,number:false,range:"number",search:"text",tel:false,time:false,url:false,week:false};a(document).bind("pagecreate create",function(e){var b=a(e.target).closest(':jqmData(role="page")').data("page"),d;if(b)d=b.options,a(e.target).find("input").not(b.keepNativeSelector()).each(function(){var b=a(this),c=this.getAttribute("type"),e=d.degradeInputs[c]||"text";
|
||||
if(d.degradeInputs[c]){var g=a("<div>").html(b.clone()).html(),i=g.indexOf(" type=")>-1;b.replaceWith(g.replace(i?/\s+type=["']?\w+['"]?/:/\/?>/,' type="'+e+'" data-'+a.mobile.ns+'type="'+c+'"'+(i?"":">")))}})})})(jQuery);
|
||||
(function(a,e){a.widget("mobile.dialog",a.mobile.widget,{options:{closeBtnText:"Close",overlayTheme:"a",initSelector:":jqmData(role='dialog')"},_create:function(){var b=this,d=this.element,f=a("<a href='#' data-"+a.mobile.ns+"icon='delete' data-"+a.mobile.ns+"iconpos='notext'>"+this.options.closeBtnText+"</a>");d.addClass("ui-overlay-"+this.options.overlayTheme);d.attr("role","dialog").addClass("ui-dialog").find(":jqmData(role='header')").addClass("ui-corner-top ui-overlay-shadow").prepend(f).end().find(":jqmData(role='content'),:jqmData(role='footer')").addClass("ui-overlay-shadow").last().addClass("ui-corner-bottom");
|
||||
f.bind("vclick",function(){b.close()});d.bind("vclick submit",function(b){var b=a(b.target).closest(b.type==="vclick"?"a":"form"),f;b.length&&!b.jqmData("transition")&&(f=a.mobile.urlHistory.getActive()||{},b.attr("data-"+a.mobile.ns+"transition",f.transition||a.mobile.defaultDialogTransition).attr("data-"+a.mobile.ns+"direction","reverse"))}).bind("pagehide",function(){a(this).find("."+a.mobile.activeBtnClass).removeClass(a.mobile.activeBtnClass)})},close:function(){e.history.back()}});a(a.mobile.dialog.prototype.options.initSelector).live("pagecreate",
|
||||
function(){a(this).dialog()})})(jQuery,this);
|
||||
(function(a){a.mobile.page.prototype.options.backBtnText="Back";a.mobile.page.prototype.options.addBackBtn=false;a.mobile.page.prototype.options.backBtnTheme=null;a.mobile.page.prototype.options.headerTheme="a";a.mobile.page.prototype.options.footerTheme="a";a.mobile.page.prototype.options.contentTheme=null;a(":jqmData(role='page'), :jqmData(role='dialog')").live("pagecreate",function(){var e=a(this),b=e.data("page").options,d=e.jqmData("role"),f=b.theme;a(":jqmData(role='header'), :jqmData(role='footer'), :jqmData(role='content')",
|
||||
this).each(function(){var c=a(this),e=c.jqmData("role"),g=c.jqmData("theme"),i=g||b.contentTheme||d==="dialog"&&f,k;c.addClass("ui-"+e);if(e==="header"||e==="footer"){var l=g||(e==="header"?b.headerTheme:b.footerTheme)||f;c.addClass("ui-bar-"+l).attr("role",e==="header"?"banner":"contentinfo");g=c.children("a");i=g.hasClass("ui-btn-left");k=g.hasClass("ui-btn-right");i=i||g.eq(0).not(".ui-btn-right").addClass("ui-btn-left").length;k||g.eq(1).addClass("ui-btn-right");b.addBackBtn&&e==="header"&&a(".ui-page").length>
|
||||
1&&c.jqmData("url")!==a.mobile.path.stripHash(location.hash)&&!i&&a("<a href='#' class='ui-btn-left' data-"+a.mobile.ns+"rel='back' data-"+a.mobile.ns+"icon='arrow-l'>"+b.backBtnText+"</a>").attr("data-"+a.mobile.ns+"theme",b.backBtnTheme||l).prependTo(c);c.children("h1, h2, h3, h4, h5, h6").addClass("ui-title").attr({tabindex:"0",role:"heading","aria-level":"1"})}else e==="content"&&(i&&c.addClass("ui-body-"+i),c.attr("role","main"))})})})(jQuery);
|
||||
(function(a){a.widget("mobile.collapsible",a.mobile.widget,{options:{expandCueText:" click to expand contents",collapseCueText:" click to collapse contents",collapsed:true,heading:"h1,h2,h3,h4,h5,h6,legend",theme:null,contentTheme:null,iconTheme:"d",initSelector:":jqmData(role='collapsible')"},_create:function(){var e=this.element,b=this.options,d=e.addClass("ui-collapsible"),f=e.children(b.heading).first(),c=d.wrapInner("<div class='ui-collapsible-content'></div>").find(".ui-collapsible-content"),
|
||||
h=e.closest(":jqmData(role='collapsible-set')").addClass("ui-collapsible-set"),e=h.children(":jqmData(role='collapsible')");f.is("legend")&&(f=a("<div role='heading'>"+f.html()+"</div>").insertBefore(f),f.next().remove());if(h.length){if(!b.theme)b.theme=h.jqmData("theme");if(!b.contentTheme)b.contentTheme=h.jqmData("content-theme")}c.addClass(b.contentTheme?"ui-body-"+b.contentTheme:"");f.insertBefore(c).addClass("ui-collapsible-heading").append("<span class='ui-collapsible-heading-status'></span>").wrapInner("<a href='#' class='ui-collapsible-heading-toggle'></a>").find("a").first().buttonMarkup({shadow:false,
|
||||
corners:false,iconPos:"left",icon:"plus",theme:b.theme});h.length?(h.jqmData("collapsiblebound")||h.jqmData("collapsiblebound",true).bind("expand",function(b){a(b.target).closest(".ui-collapsible").siblings(".ui-collapsible").trigger("collapse")}),e.first().find("a").first().addClass("ui-corner-top").find(".ui-btn-inner").addClass("ui-corner-top"),e.last().jqmData("collapsible-last",true).find("a").first().addClass("ui-corner-bottom").find(".ui-btn-inner").addClass("ui-corner-bottom"),d.jqmData("collapsible-last")&&
|
||||
f.find("a").first().add(f.find(".ui-btn-inner")).addClass("ui-corner-bottom")):f.find("a").first().add(f.find(".ui-btn-inner")).addClass("ui-corner-top ui-corner-bottom");d.bind("expand collapse",function(e){if(!e.isDefaultPrevented()){e.preventDefault();var i=a(this),e=e.type==="collapse",k=b.contentTheme;f.toggleClass("ui-collapsible-heading-collapsed",e).find(".ui-collapsible-heading-status").text(e?b.expandCueText:b.collapseCueText).end().find(".ui-icon").toggleClass("ui-icon-minus",!e).toggleClass("ui-icon-plus",
|
||||
e);i.toggleClass("ui-collapsible-collapsed",e);c.toggleClass("ui-collapsible-content-collapsed",e).attr("aria-hidden",e);if(k&&(!h.length||d.jqmData("collapsible-last")))f.find("a").first().add(f.find(".ui-btn-inner")).toggleClass("ui-corner-bottom",e),c.toggleClass("ui-corner-bottom",!e);c.trigger("updatelayout")}}).trigger(b.collapsed?"collapse":"expand");f.bind("click",function(a){var b=f.is(".ui-collapsible-heading-collapsed")?"expand":"collapse";d.trigger(b);a.preventDefault()})}});a(document).bind("pagecreate create",
|
||||
function(e){a(a.mobile.collapsible.prototype.options.initSelector,e.target).collapsible()})})(jQuery);(function(a){a.fn.fieldcontain=function(){return this.addClass("ui-field-contain ui-body ui-br")};a(document).bind("pagecreate create",function(e){a(":jqmData(role='fieldcontain')",e.target).fieldcontain()})})(jQuery);
|
||||
(function(a){a.fn.grid=function(e){return this.each(function(){var b=a(this),d=a.extend({grid:null},e),f=b.children(),c={solo:1,a:2,b:3,c:4,d:5},d=d.grid;if(!d)if(f.length<=5)for(var h in c)c[h]===f.length&&(d=h);else d="a";c=c[d];b.addClass("ui-grid-"+d);f.filter(":nth-child("+c+"n+1)").addClass("ui-block-a");c>1&&f.filter(":nth-child("+c+"n+2)").addClass("ui-block-b");c>2&&f.filter(":nth-child(3n+3)").addClass("ui-block-c");c>3&&f.filter(":nth-child(4n+4)").addClass("ui-block-d");c>4&&f.filter(":nth-child(5n+5)").addClass("ui-block-e")})}})(jQuery);
|
||||
(function(a,e){a.widget("mobile.navbar",a.mobile.widget,{options:{iconpos:"top",grid:null,initSelector:":jqmData(role='navbar')"},_create:function(){var b=this.element,d=b.find("a"),f=d.filter(":jqmData(icon)").length?this.options.iconpos:e;b.addClass("ui-navbar").attr("role","navigation").find("ul").grid({grid:this.options.grid});f||b.addClass("ui-navbar-noicons");d.buttonMarkup({corners:false,shadow:false,iconpos:f});b.delegate("a","vclick",function(){d.not(".ui-state-persist").removeClass(a.mobile.activeBtnClass);
|
||||
a(this).addClass(a.mobile.activeBtnClass)})}});a(document).bind("pagecreate create",function(b){a(a.mobile.navbar.prototype.options.initSelector,b.target).navbar()})})(jQuery);
|
||||
(function(a){var e={};a.widget("mobile.listview",a.mobile.widget,{options:{theme:null,countTheme:"c",headerTheme:"b",dividerTheme:"b",splitIcon:"arrow-r",splitTheme:"b",inset:false,initSelector:":jqmData(role='listview')"},_create:function(){var a=this;a.element.addClass(function(d,f){return f+" ui-listview "+(a.options.inset?" ui-listview-inset ui-corner-all ui-shadow ":"")});a.refresh(true)},_removeCorners:function(a,d){a=a.add(a.find(".ui-btn-inner, .ui-li-link-alt, .ui-li-thumb"));d==="top"?a.removeClass("ui-corner-top ui-corner-tr ui-corner-tl"):
|
||||
d==="bottom"?a.removeClass("ui-corner-bottom ui-corner-br ui-corner-bl"):a.removeClass("ui-corner-top ui-corner-tr ui-corner-tl ui-corner-bottom ui-corner-br ui-corner-bl")},_refreshCorners:function(a){var d,f;this.options.inset&&(d=this.element.children("li"),f=a?d.not(".ui-screen-hidden"):d.filter(":visible"),this._removeCorners(d),d=f.first().addClass("ui-corner-top"),d.add(d.find(".ui-btn-inner").not(".ui-li-link-alt span:first-child")).addClass("ui-corner-top").end().find(".ui-li-link-alt, .ui-li-link-alt span:first-child").addClass("ui-corner-tr").end().find(".ui-li-thumb").not(".ui-li-icon").addClass("ui-corner-tl"),
|
||||
f=f.last().addClass("ui-corner-bottom"),f.add(f.find(".ui-btn-inner")).find(".ui-li-link-alt").addClass("ui-corner-br").end().find(".ui-li-thumb").not(".ui-li-icon").addClass("ui-corner-bl"));a||this.element.trigger("updatelayout")},_findFirstElementByTagName:function(a,d,f,c){var e={};for(e[f]=e[c]=true;a;){if(e[a.nodeName])return a;a=a[d]}return null},_getChildrenByTagName:function(b,d,f){var c=[],e={};e[d]=e[f]=true;for(b=b.firstChild;b;)e[b.nodeName]&&c.push(b),b=b.nextSibling;return a(c)},_addThumbClasses:function(b){var d,
|
||||
f,c=b.length;for(d=0;d<c;d++)f=a(this._findFirstElementByTagName(b[d].firstChild,"nextSibling","img","IMG")),f.length&&(f.addClass("ui-li-thumb"),a(this._findFirstElementByTagName(f[0].parentNode,"parentNode","li","LI")).addClass(f.is(".ui-li-icon")?"ui-li-has-icon":"ui-li-has-thumb"))},refresh:function(b){this.parentPage=this.element.closest(".ui-page");this._createSubPages();var d=this.options,f=this.element,c=f.jqmData("dividertheme")||d.dividerTheme,e=f.jqmData("splittheme"),g=f.jqmData("spliticon"),
|
||||
i=this._getChildrenByTagName(f[0],"li","LI"),k=a.support.cssPseudoElement||!a.nodeName(f[0],"ol")?0:1,l={},o,m,p,j,q;k&&f.find(".ui-li-dec").remove();if(!d.theme)d.theme=a.mobile.getInheritedTheme(this.element,"c");for(var n=0,A=i.length;n<A;n++){o=i.eq(n);m="ui-li";if(b||!o.hasClass("ui-li"))p=o.jqmData("theme")||d.theme,j=this._getChildrenByTagName(o[0],"a","A"),j.length?(q=o.jqmData("icon"),o.buttonMarkup({wrapperEls:"div",shadow:false,corners:false,iconpos:"right",icon:j.length>1||q===false?false:
|
||||
q||"arrow-r",theme:p}),q!=false&&j.length==1&&o.addClass("ui-li-has-arrow"),j.first().addClass("ui-link-inherit"),j.length>1&&(m+=" ui-li-has-alt",j=j.last(),q=e||j.jqmData("theme")||d.splitTheme,j.appendTo(o).attr("title",j.getEncodedText()).addClass("ui-li-link-alt").empty().buttonMarkup({shadow:false,corners:false,theme:p,icon:false,iconpos:false}).find(".ui-btn-inner").append(a(document.createElement("span")).buttonMarkup({shadow:true,corners:true,theme:q,iconpos:"notext",icon:g||j.jqmData("icon")||
|
||||
d.splitIcon})))):o.jqmData("role")==="list-divider"?(m+=" ui-li-divider ui-btn ui-bar-"+c,o.attr("role","heading"),k&&(k=1)):m+=" ui-li-static ui-body-"+p;k&&m.indexOf("ui-li-divider")<0&&(p=o.is(".ui-li-static:first")?o:o.find(".ui-link-inherit"),p.addClass("ui-li-jsnumbering").prepend("<span class='ui-li-dec'>"+k++ +". </span>"));l[m]||(l[m]=[]);l[m].push(o[0])}for(m in l)a(l[m]).addClass(m).children(".ui-btn-inner").addClass(m);f.find("h1, h2, h3, h4, h5, h6").addClass("ui-li-heading").end().find("p, dl").addClass("ui-li-desc").end().find(".ui-li-aside").each(function(){var b=
|
||||
a(this);b.prependTo(b.parent())}).end().find(".ui-li-count").each(function(){a(this).closest("li").addClass("ui-li-has-count")}).addClass("ui-btn-up-"+(f.jqmData("counttheme")||this.options.countTheme)+" ui-btn-corner-all");this._addThumbClasses(i);this._addThumbClasses(f.find(".ui-link-inherit"));this._refreshCorners(b)},_idStringEscape:function(a){return a.replace(/[^a-zA-Z0-9]/g,"-")},_createSubPages:function(){var b=this.element,d=b.closest(".ui-page"),f=d.jqmData("url"),c=f||d[0][a.expando],
|
||||
h=b.attr("id"),g=this.options,i="data-"+a.mobile.ns,k=this,l=d.find(":jqmData(role='footer')").jqmData("id"),o;typeof e[c]==="undefined"&&(e[c]=-1);h=h||++e[c];a(b.find("li>ul, li>ol").toArray().reverse()).each(function(c){var d=a(this),e=d.attr("id")||h+"-"+c,c=d.parent(),k=a(d.prevAll().toArray().reverse()),k=k.length?k:a("<span>"+a.trim(c.contents()[0].nodeValue)+"</span>"),n=k.first().getEncodedText(),e=(f||"")+"&"+a.mobile.subPageUrlKey+"="+e,A=d.jqmData("theme")||g.theme,z=d.jqmData("counttheme")||
|
||||
b.jqmData("counttheme")||g.countTheme;o=true;d.detach().wrap("<div "+i+"role='page' "+i+"url='"+e+"' "+i+"theme='"+A+"' "+i+"count-theme='"+z+"'><div "+i+"role='content'></div></div>").parent().before("<div "+i+"role='header' "+i+"theme='"+g.headerTheme+"'><div class='ui-title'>"+n+"</div></div>").after(l?a("<div "+i+"role='footer' "+i+"id='"+l+"'>"):"").parent().appendTo(a.mobile.pageContainer).page();d=c.find("a:first");d.length||(d=a("<a/>").html(k||n).prependTo(c.empty()));d.attr("href","#"+e)}).listview();
|
||||
o&&d.is(":jqmData(external-page='true')")&&d.data("page").options.domCache===false&&d.unbind("pagehide.remove").bind("pagehide.remove",function(b,c){var e=c.nextPage;c.nextPage&&(e=e.jqmData("url"),e.indexOf(f+"&"+a.mobile.subPageUrlKey)!==0&&(k.childPages().remove(),d.remove()))})},childPages:function(){var b=this.parentPage.jqmData("url");return a(":jqmData(url^='"+b+"&"+a.mobile.subPageUrlKey+"')")}});a(document).bind("pagecreate create",function(b){a(a.mobile.listview.prototype.options.initSelector,
|
||||
b.target).listview()})})(jQuery);
|
||||
(function(a){a.mobile.listview.prototype.options.filter=false;a.mobile.listview.prototype.options.filterPlaceholder="Filter items...";a.mobile.listview.prototype.options.filterTheme="c";a.mobile.listview.prototype.options.filterCallback=function(a,b){return a.toLowerCase().indexOf(b)===-1};a(":jqmData(role='listview')").live("listviewcreate",function(){var e=a(this),b=e.data("listview");if(b.options.filter){var d=a("<form>",{"class":"ui-listview-filter ui-bar-"+b.options.filterTheme,role:"search"});
|
||||
a("<input>",{placeholder:b.options.filterPlaceholder}).attr("data-"+a.mobile.ns+"type","search").jqmData("lastval","").bind("keyup change",function(){var d=a(this),c=this.value.toLowerCase(),h=null,h=d.jqmData("lastval")+"",g=false,i="";d.jqmData("lastval",c);i=c.substr(0,h.length-1).replace(h,"");h=c.length<h.length||i.length!=c.length-h.length?e.children():e.children(":not(.ui-screen-hidden)");if(c){for(var k=h.length-1;k>=0;k--)d=a(h[k]),i=d.jqmData("filtertext")||d.text(),d.is("li:jqmData(role=list-divider)")?
|
||||
(d.toggleClass("ui-filter-hidequeue",!g),g=false):b.options.filterCallback(i,c)?d.toggleClass("ui-filter-hidequeue",true):g=true;h.filter(":not(.ui-filter-hidequeue)").toggleClass("ui-screen-hidden",false);h.filter(".ui-filter-hidequeue").toggleClass("ui-screen-hidden",true).toggleClass("ui-filter-hidequeue",false)}else h.toggleClass("ui-screen-hidden",false);b._refreshCorners()}).appendTo(d).textinput();a(this).jqmData("inset")&&d.addClass("ui-listview-filter-inset");d.bind("submit",function(){return false}).insertBefore(e)}})})(jQuery);
|
||||
(function(a){a(document).bind("pagecreate create",function(e){a(":jqmData(role='nojs')",e.target).addClass("ui-nojs")})})(jQuery);
|
||||
(function(a,e){a.widget("mobile.checkboxradio",a.mobile.widget,{options:{theme:null,initSelector:"input[type='checkbox'],input[type='radio']"},_create:function(){var b=this,d=this.element,f=d.closest("form,fieldset,:jqmData(role='page')").find("label[for='"+d[0].id+"']"),c=d.attr("type"),h=c+"-on",g=c+"-off",i=d.parents(":jqmData(type='horizontal')").length?e:g;if(!(c!=="checkbox"&&c!=="radio")){a.extend(this,{label:f,inputtype:c,checkedClass:"ui-"+h+(i?"":" "+a.mobile.activeBtnClass),uncheckedClass:"ui-"+
|
||||
g,checkedicon:"ui-icon-"+h,uncheckedicon:"ui-icon-"+g});if(!this.options.theme)this.options.theme=this.element.jqmData("theme");f.buttonMarkup({theme:this.options.theme,icon:i,shadow:false});d.add(f).wrapAll("<div class='ui-"+c+"'></div>");f.bind({vmouseover:function(b){a(this).parent().is(".ui-disabled")&&b.stopPropagation()},vclick:function(a){if(d.is(":disabled"))a.preventDefault();else return b._cacheVals(),d.prop("checked",c==="radio"&&true||!d.prop("checked")),d.triggerHandler("click"),b._getInputSet().not(d).prop("checked",
|
||||
false),b._updateAll(),false}});d.bind({vmousedown:function(){b._cacheVals()},vclick:function(){var c=a(this);c.is(":checked")?(c.prop("checked",true),b._getInputSet().not(c).prop("checked",false)):c.prop("checked",false);b._updateAll()},focus:function(){f.addClass("ui-focus")},blur:function(){f.removeClass("ui-focus")}});this.refresh()}},_cacheVals:function(){this._getInputSet().each(function(){var b=a(this);b.jqmData("cacheVal",b.is(":checked"))})},_getInputSet:function(){return this.inputtype==
|
||||
"checkbox"?this.element:this.element.closest("form,fieldset,:jqmData(role='page')").find("input[name='"+this.element.attr("name")+"'][type='"+this.inputtype+"']")},_updateAll:function(){var b=this;this._getInputSet().each(function(){var d=a(this);(d.is(":checked")||b.inputtype==="checkbox")&&d.trigger("change")}).checkboxradio("refresh")},refresh:function(){var b=this.element,d=this.label,f=d.find(".ui-icon");a(b[0]).prop("checked")?(d.addClass(this.checkedClass).removeClass(this.uncheckedClass),
|
||||
f.addClass(this.checkedicon).removeClass(this.uncheckedicon)):(d.removeClass(this.checkedClass).addClass(this.uncheckedClass),f.removeClass(this.checkedicon).addClass(this.uncheckedicon));b.is(":disabled")?this.disable():this.enable()},disable:function(){this.element.prop("disabled",true).parent().addClass("ui-disabled")},enable:function(){this.element.prop("disabled",false).parent().removeClass("ui-disabled")}});a(document).bind("pagecreate create",function(b){a.mobile.checkboxradio.prototype.enhanceWithin(b.target)})})(jQuery);
|
||||
(function(a,e){a.widget("mobile.button",a.mobile.widget,{options:{theme:null,icon:null,iconpos:null,inline:null,corners:true,shadow:true,iconshadow:true,initSelector:"button, [type='button'], [type='submit'], [type='reset'], [type='image']"},_create:function(){var b=this.element,d=this.options,f,c;this.button=a("<div></div>").text(b.text()||b.val()).insertBefore(b).buttonMarkup({theme:d.theme,icon:d.icon,iconpos:d.iconpos,inline:d.inline,corners:d.corners,shadow:d.shadow,iconshadow:d.iconshadow}).append(b.addClass("ui-btn-hidden"));
|
||||
d=b.attr("type");f=b.attr("name");d!=="button"&&d!=="reset"&&f&&b.bind("vclick",function(){c===e&&(c=a("<input>",{type:"hidden",name:b.attr("name"),value:b.attr("value")}).insertBefore(b),a(document).one("submit",function(){c.remove();c=e}))});this.refresh()},enable:function(){this.element.attr("disabled",false);this.button.removeClass("ui-disabled").attr("aria-disabled",false);return this._setOption("disabled",false)},disable:function(){this.element.attr("disabled",true);this.button.addClass("ui-disabled").attr("aria-disabled",
|
||||
true);return this._setOption("disabled",true)},refresh:function(){var a=this.element;a.prop("disabled")?this.disable():this.enable();this.button.data("textWrapper").text(a.text()||a.val())}});a(document).bind("pagecreate create",function(b){a.mobile.button.prototype.enhanceWithin(b.target)})})(jQuery);
|
||||
(function(a,e){a.widget("mobile.slider",a.mobile.widget,{options:{theme:null,trackTheme:null,disabled:false,initSelector:"input[type='range'], :jqmData(type='range'), :jqmData(role='slider')"},_create:function(){var b=this,d=this.element,f=a.mobile.getInheritedTheme(d,"c"),c=this.options.theme||f,h=this.options.trackTheme||f,g=d[0].nodeName.toLowerCase(),f=g=="select"?"ui-slider-switch":"",i=d.attr("id"),k=i+"-label",i=a("[for='"+i+"']").attr("id",k),l=function(){return g=="input"?parseFloat(d.val()):
|
||||
d[0].selectedIndex},o=g=="input"?parseFloat(d.attr("min")):0,m=g=="input"?parseFloat(d.attr("max")):d.find("option").length-1,p=window.parseFloat(d.attr("step")||1),j=a("<div class='ui-slider "+f+" ui-btn-down-"+h+" ui-btn-corner-all' role='application'></div>"),q=a("<a href='#' class='ui-slider-handle'></a>").appendTo(j).buttonMarkup({corners:true,theme:c,shadow:true}).attr({role:"slider","aria-valuemin":o,"aria-valuemax":m,"aria-valuenow":l(),"aria-valuetext":l(),title:l(),"aria-labelledby":k});
|
||||
a.extend(this,{slider:j,handle:q,dragging:false,beforeStart:null,userModified:false,mouseMoved:false});g=="select"&&(j.wrapInner("<div class='ui-slider-inneroffset'></div>"),q.addClass("ui-slider-handle-snapping"),d.find("option"),d.find("option").each(function(b){var c=!b?"b":"a",d=!b?"right":"left",b=!b?" ui-btn-down-"+h:" "+a.mobile.activeBtnClass;a("<div class='ui-slider-labelbg ui-slider-labelbg-"+c+b+" ui-btn-corner-"+d+"'></div>").prependTo(j);a("<span class='ui-slider-label ui-slider-label-"+
|
||||
c+b+" ui-btn-corner-"+d+"' role='img'>"+a(this).getEncodedText()+"</span>").prependTo(q)}));i.addClass("ui-slider");d.addClass(g==="input"?"ui-slider-input":"ui-slider-switch").change(function(){b.mouseMoved||b.refresh(l(),true)}).keyup(function(){b.refresh(l(),true,true)}).blur(function(){b.refresh(l(),true)});a(document).bind("vmousemove",function(a){if(b.dragging)return b.mouseMoved=true,g==="select"&&q.removeClass("ui-slider-handle-snapping"),b.refresh(a),b.userModified=b.beforeStart!==d[0].selectedIndex,
|
||||
false});j.bind("vmousedown",function(a){b.dragging=true;b.userModified=false;b.mouseMoved=false;if(g==="select")b.beforeStart=d[0].selectedIndex;b.refresh(a);return false});j.add(document).bind("vmouseup",function(){if(b.dragging)return b.dragging=false,g==="select"&&(q.addClass("ui-slider-handle-snapping"),b.mouseMoved?b.userModified?b.refresh(b.beforeStart==0?1:0):b.refresh(b.beforeStart):b.refresh(b.beforeStart==0?1:0)),b.mouseMoved=false});j.insertAfter(d);this.handle.bind("vmousedown",function(){a(this).focus()}).bind("vclick",
|
||||
false);this.handle.bind("keydown",function(c){var d=l();if(!b.options.disabled){switch(c.keyCode){case a.mobile.keyCode.HOME:case a.mobile.keyCode.END:case a.mobile.keyCode.PAGE_UP:case a.mobile.keyCode.PAGE_DOWN:case a.mobile.keyCode.UP:case a.mobile.keyCode.RIGHT:case a.mobile.keyCode.DOWN:case a.mobile.keyCode.LEFT:if(c.preventDefault(),!b._keySliding)b._keySliding=true,a(this).addClass("ui-state-active")}switch(c.keyCode){case a.mobile.keyCode.HOME:b.refresh(o);break;case a.mobile.keyCode.END:b.refresh(m);
|
||||
break;case a.mobile.keyCode.PAGE_UP:case a.mobile.keyCode.UP:case a.mobile.keyCode.RIGHT:b.refresh(d+p);break;case a.mobile.keyCode.PAGE_DOWN:case a.mobile.keyCode.DOWN:case a.mobile.keyCode.LEFT:b.refresh(d-p)}}}).keyup(function(){if(b._keySliding)b._keySliding=false,a(this).removeClass("ui-state-active")});this.refresh(e,e,true)},refresh:function(a,d,f){(this.options.disabled||this.element.attr("disabled"))&&this.disable();var c=this.element,e,g=c[0].nodeName.toLowerCase(),i=g==="input"?parseFloat(c.attr("min")):
|
||||
0,k=g==="input"?parseFloat(c.attr("max")):c.find("option").length-1;if(typeof a==="object"){if(!this.dragging||a.pageX<this.slider.offset().left-8||a.pageX>this.slider.offset().left+this.slider.width()+8)return;e=Math.round((a.pageX-this.slider.offset().left)/this.slider.width()*100)}else a==null&&(a=g==="input"?parseFloat(c.val()):c[0].selectedIndex),e=(parseFloat(a)-i)/(k-i)*100;if(!isNaN(e)&&(e<0&&(e=0),e>100&&(e=100),a=Math.round(e/100*(k-i))+i,a<i&&(a=i),a>k&&(a=k),this.handle.css("left",e+"%"),
|
||||
this.handle.attr({"aria-valuenow":g==="input"?a:c.find("option").eq(a).attr("value"),"aria-valuetext":g==="input"?a:c.find("option").eq(a).getEncodedText(),title:a}),g==="select"&&(a===0?this.slider.addClass("ui-slider-switch-a").removeClass("ui-slider-switch-b"):this.slider.addClass("ui-slider-switch-b").removeClass("ui-slider-switch-a")),!f))f=false,g==="input"?(f=c.val()!==a,c.val(a)):(f=c[0].selectedIndex!==a,c[0].selectedIndex=a),!d&&f&&c.trigger("change")},enable:function(){this.element.attr("disabled",
|
||||
false);this.slider.removeClass("ui-disabled").attr("aria-disabled",false);return this._setOption("disabled",false)},disable:function(){this.element.attr("disabled",true);this.slider.addClass("ui-disabled").attr("aria-disabled",true);return this._setOption("disabled",true)}});a(document).bind("pagecreate create",function(b){a.mobile.slider.prototype.enhanceWithin(b.target)})})(jQuery);
|
||||
(function(a){a.widget("mobile.textinput",a.mobile.widget,{options:{theme:null,initSelector:"input[type='text'], input[type='search'], :jqmData(type='search'), input[type='number'], :jqmData(type='number'), input[type='password'], input[type='email'], input[type='url'], input[type='tel'], textarea, input[type='time'], input[type='date'], input[type='month'], input[type='week'], input[type='datetime'], input[type='datetime-local'], input[type='color'], input:not([type])"},_create:function(){var e=this.element,
|
||||
b=this.options.theme||a.mobile.getInheritedTheme(this.element,"c"),d=" ui-body-"+b,f,c;a("label[for='"+e.attr("id")+"']").addClass("ui-input-text");f=e.addClass("ui-input-text ui-body-"+b);typeof e[0].autocorrect!=="undefined"&&!a.support.touchOverflow&&(e[0].setAttribute("autocorrect","off"),e[0].setAttribute("autocomplete","off"));e.is("[type='search'],:jqmData(type='search')")?(f=e.wrap("<div class='ui-input-search ui-shadow-inset ui-btn-corner-all ui-btn-shadow ui-icon-searchfield"+d+"'></div>").parent(),
|
||||
c=a("<a href='#' class='ui-input-clear' title='clear text'>clear text</a>").tap(function(a){e.val("").focus();e.trigger("change");c.addClass("ui-input-clear-hidden");a.preventDefault()}).appendTo(f).buttonMarkup({icon:"delete",iconpos:"notext",corners:true,shadow:true}),b=function(){setTimeout(function(){c.toggleClass("ui-input-clear-hidden",!e.val())},0)},b(),e.bind("paste cut keyup focus change blur",b)):e.addClass("ui-corner-all ui-shadow-inset"+d);e.focus(function(){f.addClass("ui-focus")}).blur(function(){f.removeClass("ui-focus")});
|
||||
if(e.is("textarea")){var h=function(){var a=e[0].scrollHeight;e[0].clientHeight<a&&e.height(a+15)},g;e.keyup(function(){clearTimeout(g);g=setTimeout(h,100)});a.trim(e.val())&&(a(window).load(h),a(document).one("pagechange",h))}},disable:function(){(this.element.attr("disabled",true).is("[type='search'],:jqmData(type='search')")?this.element.parent():this.element).addClass("ui-disabled")},enable:function(){(this.element.attr("disabled",false).is("[type='search'],:jqmData(type='search')")?this.element.parent():
|
||||
this.element).removeClass("ui-disabled")}});a(document).bind("pagecreate create",function(e){a.mobile.textinput.prototype.enhanceWithin(e.target)})})(jQuery);
|
||||
(function(a){var e=function(b){var d=b.selectID,f=b.label,c=b.select.closest(".ui-page"),e=a("<div>",{"class":"ui-selectmenu-screen ui-screen-hidden"}).appendTo(c),g=b._selectOptions(),i=b.isMultiple=b.select[0].multiple,k=d+"-button",l=d+"-menu",o=a("<div data-"+a.mobile.ns+"role='dialog' data-"+a.mobile.ns+"theme='"+b.options.theme+"' data-"+a.mobile.ns+"overlay-theme='"+b.options.overlayTheme+"'><div data-"+a.mobile.ns+"role='header'><div class='ui-title'>"+f.getEncodedText()+"</div></div><div data-"+
|
||||
a.mobile.ns+"role='content'></div></div>").appendTo(a.mobile.pageContainer).page(),m=a("<div>",{"class":"ui-selectmenu ui-selectmenu-hidden ui-overlay-shadow ui-corner-all ui-body-"+b.options.overlayTheme+" "+a.mobile.defaultDialogTransition}).insertAfter(e),p=a("<ul>",{"class":"ui-selectmenu-list",id:l,role:"listbox","aria-labelledby":k}).attr("data-"+a.mobile.ns+"theme",b.options.theme).appendTo(m),j=a("<div>",{"class":"ui-header ui-bar-"+b.options.theme}).prependTo(m),q=a("<h1>",{"class":"ui-title"}).appendTo(j),
|
||||
n=a("<a>",{text:b.options.closeText,href:"#","class":"ui-btn-left"}).attr("data-"+a.mobile.ns+"iconpos","notext").attr("data-"+a.mobile.ns+"icon","delete").appendTo(j).buttonMarkup(),A=o.find(".ui-content"),z=o.find(".ui-header a");a.extend(b,{select:b.select,selectID:d,buttonId:k,menuId:l,thisPage:c,menuPage:o,label:f,screen:e,selectOptions:g,isMultiple:i,theme:b.options.theme,listbox:m,list:p,header:j,headerTitle:q,headerClose:n,menuPageContent:A,menuPageClose:z,placeholder:"",build:function(){var b=
|
||||
this;b.refresh();b.select.attr("tabindex","-1").focus(function(){a(this).blur();b.button.focus()});b.button.bind("vclick keydown",function(c){if(c.type=="vclick"||c.keyCode&&(c.keyCode===a.mobile.keyCode.ENTER||c.keyCode===a.mobile.keyCode.SPACE))b.open(),c.preventDefault()});b.list.attr("role","listbox").delegate(".ui-li>a","focusin",function(){a(this).attr("tabindex","0")}).delegate(".ui-li>a","focusout",function(){a(this).attr("tabindex","-1")}).delegate("li:not(.ui-disabled, .ui-li-divider)",
|
||||
"click",function(c){var d=b.select[0].selectedIndex,f=b.list.find("li:not(.ui-li-divider)").index(this),e=b._selectOptions().eq(f)[0];e.selected=b.isMultiple?!e.selected:true;b.isMultiple&&a(this).find(".ui-icon").toggleClass("ui-icon-checkbox-on",e.selected).toggleClass("ui-icon-checkbox-off",!e.selected);(b.isMultiple||d!==f)&&b.select.trigger("change");b.isMultiple||b.close();c.preventDefault()}).keydown(function(b){var c=a(b.target),d=c.closest("li");switch(b.keyCode){case 38:return b=d.prev(),
|
||||
b.length&&(c.blur().attr("tabindex","-1"),b.find("a").first().focus()),false;case 40:return b=d.next(),b.length&&(c.blur().attr("tabindex","-1"),b.find("a").first().focus()),false;case 13:case 32:return c.trigger("click"),false}});b.menuPage.bind("pagehide",function(){b.list.appendTo(b.listbox);b._focusButton();a.mobile._bindPageRemove.call(b.thisPage)});b.screen.bind("vclick",function(){b.close()});b.headerClose.click(function(){if(b.menuType=="overlay")return b.close(),false});b.thisPage.addDependents(this.menuPage)},
|
||||
_isRebuildRequired:function(){var a=this.list.find("li");return this._selectOptions().text()!==a.text()},refresh:function(b){var c=this;this._selectOptions();this.selected();var d=this.selectedIndices();(b||this._isRebuildRequired())&&c._buildList();c.setButtonText();c.setButtonCount();c.list.find("li:not(.ui-li-divider)").removeClass(a.mobile.activeBtnClass).attr("aria-selected",false).each(function(b){a.inArray(b,d)>-1&&(b=a(this),b.attr("aria-selected",true),c.isMultiple?b.find(".ui-icon").removeClass("ui-icon-checkbox-off").addClass("ui-icon-checkbox-on"):
|
||||
b.addClass(a.mobile.activeBtnClass))})},close:function(){if(!this.options.disabled&&this.isOpen)this.menuType=="page"?window.history.back():(this.screen.addClass("ui-screen-hidden"),this.listbox.addClass("ui-selectmenu-hidden").removeAttr("style").removeClass("in"),this.list.appendTo(this.listbox),this._focusButton()),this.isOpen=false},open:function(){if(!this.options.disabled){var b=this,c=b.list.parent().outerHeight(),d=b.list.parent().outerWidth(),f=a(".ui-page-active"),e=a.support.touchOverflow&&
|
||||
a.mobile.touchOverflowEnabled,f=f.is(".ui-native-fixed")?f.find(".ui-content"):f;scrollTop=e?f.scrollTop():a(window).scrollTop();btnOffset=b.button.offset().top;screenHeight=window.innerHeight;screenWidth=window.innerWidth;b.button.addClass(a.mobile.activeBtnClass);setTimeout(function(){b.button.removeClass(a.mobile.activeBtnClass)},300);if(c>screenHeight-80||!a.support.scrollTop){b.thisPage.unbind("pagehide.remove");if(scrollTop==0&&btnOffset>screenHeight)b.thisPage.one("pagehide",function(){a(this).jqmData("lastScroll",
|
||||
btnOffset)});b.menuPage.one("pageshow",function(){a(window).one("silentscroll",function(){b.list.find(a.mobile.activeBtnClass).focus()});b.isOpen=true});b.menuType="page";b.menuPageContent.append(b.list);b.menuPage.find("div .ui-title").text(b.label.text());a.mobile.changePage(b.menuPage,{transition:a.mobile.defaultDialogTransition})}else{b.menuType="overlay";b.screen.height(a(document).height()).removeClass("ui-screen-hidden");var f=btnOffset-scrollTop,h=scrollTop+screenHeight-btnOffset,g=c/2,e=
|
||||
parseFloat(b.list.parent().css("max-width")),c=f>c/2&&h>c/2?btnOffset+b.button.outerHeight()/2-g:f>h?scrollTop+screenHeight-c-30:scrollTop+30;d<e?e=(screenWidth-d)/2:(e=b.button.offset().left+b.button.outerWidth()/2-d/2,e<30?e=30:e+d>screenWidth&&(e=screenWidth-d-30));b.listbox.append(b.list).removeClass("ui-selectmenu-hidden").css({top:c,left:e}).addClass("in");b.list.find(a.mobile.activeBtnClass).focus();b.isOpen=true}}},_buildList:function(){var b=this,c=this.options,d=this.placeholder,f=[],e=
|
||||
[],h=b.isMultiple?"checkbox-off":"false";b.list.empty().filter(".ui-listview").listview("destroy");b.select.find("option").each(function(g){var j=a(this),i=j.parent(),m=j.getEncodedText(),p="<a href='#'>"+m+"</a>",k=[],n=[];i.is("optgroup")&&(i=i.attr("label"),a.inArray(i,f)===-1&&(e.push("<li data-"+a.mobile.ns+"role='list-divider'>"+i+"</li>"),f.push(i)));if(!this.getAttribute("value")||m.length==0||j.jqmData("placeholder"))c.hidePlaceholderMenuItems&&k.push("ui-selectmenu-placeholder"),d=b.placeholder=
|
||||
m;this.disabled&&(k.push("ui-disabled"),n.push("aria-disabled='true'"));e.push("<li data-"+a.mobile.ns+"option-index='"+g+"' data-"+a.mobile.ns+"icon='"+h+"' class='"+k.join(" ")+"' "+n.join(" ")+">"+p+"</li>")});b.list.html(e.join(" "));b.list.find("li").attr({role:"option",tabindex:"-1"}).first().attr("tabindex","0");this.isMultiple||this.headerClose.hide();!this.isMultiple&&!d.length?this.header.hide():this.headerTitle.text(this.placeholder);b.list.listview()},_button:function(){return a("<a>",
|
||||
{href:"#",role:"button",id:this.buttonId,"aria-haspopup":"true","aria-owns":this.menuId})}})};a("select").live("selectmenubeforecreate",function(){var b=a(this).data("selectmenu");b.options.nativeMenu||e(b)})})(jQuery);
|
||||
(function(a){a.widget("mobile.selectmenu",a.mobile.widget,{options:{theme:null,disabled:false,icon:"arrow-d",iconpos:"right",inline:null,corners:true,shadow:true,iconshadow:true,menuPageTheme:"b",overlayTheme:"a",hidePlaceholderMenuItems:true,closeText:"Close",nativeMenu:true,initSelector:"select:not(:jqmData(role='slider'))"},_button:function(){return a("<div/>")},_setDisabled:function(a){this.element.attr("disabled",a);this.button.attr("aria-disabled",a);return this._setOption("disabled",a)},_focusButton:function(){var a=
|
||||
this;setTimeout(function(){a.button.focus()},40)},_selectOptions:function(){return this.select.find("option")},_preExtension:function(){this.select=this.element.wrap("<div class='ui-select'>");this.selectID=this.select.attr("id");this.label=a("label[for='"+this.selectID+"']").addClass("ui-select");this.isMultiple=this.select[0].multiple;if(!this.options.theme)this.options.theme=a.mobile.getInheritedTheme(this.select,"c")},_create:function(){this._preExtension();this._trigger("beforeCreate");this.button=
|
||||
this._button();var e=this,b=this.options,d=this.button.text(a(this.select[0].options.item(this.select[0].selectedIndex==-1?0:this.select[0].selectedIndex)).text()).insertBefore(this.select).buttonMarkup({theme:b.theme,icon:b.icon,iconpos:b.iconpos,inline:b.inline,corners:b.corners,shadow:b.shadow,iconshadow:b.iconshadow});b.nativeMenu&&window.opera&&window.opera.version&&this.select.addClass("ui-select-nativeonly");if(this.isMultiple)this.buttonCount=a("<span>").addClass("ui-li-count ui-btn-up-c ui-btn-corner-all").hide().appendTo(d.addClass("ui-li-has-count"));
|
||||
(b.disabled||this.element.attr("disabled"))&&this.disable();this.select.change(function(){e.refresh()});this.build()},build:function(){var e=this;this.select.appendTo(e.button).bind("vmousedown",function(){e.button.addClass(a.mobile.activeBtnClass)}).bind("focus vmouseover",function(){e.button.trigger("vmouseover")}).bind("vmousemove",function(){e.button.removeClass(a.mobile.activeBtnClass)}).bind("change blur vmouseout",function(){e.button.trigger("vmouseout").removeClass(a.mobile.activeBtnClass)}).bind("change blur",
|
||||
function(){e.button.removeClass("ui-btn-down-"+e.options.theme)})},selected:function(){return this._selectOptions().filter(":selected")},selectedIndices:function(){var a=this;return this.selected().map(function(){return a._selectOptions().index(this)}).get()},setButtonText:function(){var e=this,b=this.selected();this.button.find(".ui-btn-text").text(function(){return!e.isMultiple?b.text():b.length?b.map(function(){return a(this).text()}).get().join(", "):e.placeholder})},setButtonCount:function(){var a=
|
||||
this.selected();this.isMultiple&&this.buttonCount[a.length>1?"show":"hide"]().text(a.length)},refresh:function(){this.setButtonText();this.setButtonCount()},open:a.noop,close:a.noop,disable:function(){this._setDisabled(true);this.button.addClass("ui-disabled")},enable:function(){this._setDisabled(false);this.button.removeClass("ui-disabled")}});a(document).bind("pagecreate create",function(e){a.mobile.selectmenu.prototype.enhanceWithin(e.target)})})(jQuery);
|
||||
(function(a,e){function b(b){for(var c;b;){if((c=typeof b.className==="string"&&b.className.split(" "))&&a.inArray("ui-btn",c)>-1&&a.inArray("ui-disabled",c)<0)break;b=b.parentNode}return b}a.fn.buttonMarkup=function(b){for(var b=b||{},c=0;c<this.length;c++){var h=this.eq(c),g=h[0],i=a.extend({},a.fn.buttonMarkup.defaults,{icon:b.icon!==e?b.icon:h.jqmData("icon"),iconpos:b.iconpos!==e?b.iconpos:h.jqmData("iconpos"),theme:b.theme!==e?b.theme:h.jqmData("theme"),inline:b.inline!==e?b.inline:h.jqmData("inline"),
|
||||
shadow:b.shadow!==e?b.shadow:h.jqmData("shadow"),corners:b.corners!==e?b.corners:h.jqmData("corners"),iconshadow:b.iconshadow!==e?b.iconshadow:h.jqmData("iconshadow")},b),k="ui-btn-inner",l,o,m=document.createElement(i.wrapperEls),p=document.createElement(i.wrapperEls),j=i.icon?document.createElement("span"):null;d&&d();if(!i.theme)i.theme=a.mobile.getInheritedTheme(h,"c");l="ui-btn ui-btn-up-"+i.theme;i.inline&&(l+=" ui-btn-inline");if(i.icon)i.icon="ui-icon-"+i.icon,i.iconpos=i.iconpos||"left",
|
||||
o="ui-icon "+i.icon,i.iconshadow&&(o+=" ui-icon-shadow");i.iconpos&&(l+=" ui-btn-icon-"+i.iconpos,i.iconpos=="notext"&&!h.attr("title")&&h.attr("title",h.getEncodedText()));i.corners&&(l+=" ui-btn-corner-all",k+=" ui-btn-corner-all");i.shadow&&(l+=" ui-shadow");g.setAttribute("data-"+a.mobile.ns+"theme",i.theme);h.addClass(l);m.className=k;m.setAttribute("aria-hidden","true");p.className="ui-btn-text";m.appendChild(p);if(j)j.className=o,m.appendChild(j);for(;g.firstChild;)p.appendChild(g.firstChild);
|
||||
g.appendChild(m);a.data(g,"textWrapper",a(p))}return this};a.fn.buttonMarkup.defaults={corners:true,shadow:true,iconshadow:true,inline:false,wrapperEls:"span"};var d=function(){a(document).bind({vmousedown:function(d){var d=b(d.target),c;d&&(d=a(d),c=d.attr("data-"+a.mobile.ns+"theme"),d.removeClass("ui-btn-up-"+c).addClass("ui-btn-down-"+c))},"vmousecancel vmouseup":function(d){var d=b(d.target),c;d&&(d=a(d),c=d.attr("data-"+a.mobile.ns+"theme"),d.removeClass("ui-btn-down-"+c).addClass("ui-btn-up-"+
|
||||
c))},"vmouseover focus":function(d){var d=b(d.target),c;d&&(d=a(d),c=d.attr("data-"+a.mobile.ns+"theme"),d.removeClass("ui-btn-up-"+c).addClass("ui-btn-hover-"+c))},"vmouseout blur":function(d){var d=b(d.target),c;d&&(d=a(d),c=d.attr("data-"+a.mobile.ns+"theme"),d.removeClass("ui-btn-hover-"+c+" ui-btn-down-"+c).addClass("ui-btn-up-"+c))}});d=null};a(document).bind("pagecreate create",function(b){a(":jqmData(role='button'), .ui-bar > a, .ui-header > a, .ui-footer > a, .ui-bar > :jqmData(role='controlgroup') > a",
|
||||
b.target).not(".ui-btn, :jqmData(role='none'), :jqmData(role='nojs')").buttonMarkup()})})(jQuery);
|
||||
(function(a){a.fn.controlgroup=function(e){return this.each(function(){function b(a){a.removeClass("ui-btn-corner-all ui-shadow").eq(0).addClass(h[0]).end().last().addClass(h[1]).addClass("ui-controlgroup-last")}var d=a(this),f=a.extend({direction:d.jqmData("type")||"vertical",shadow:false,excludeInvisible:true},e),c=d.children("legend"),h=f.direction=="horizontal"?["ui-corner-left","ui-corner-right"]:["ui-corner-top","ui-corner-bottom"];d.find("input").first().attr("type");c.length&&(d.wrapInner("<div class='ui-controlgroup-controls'></div>"),
|
||||
a("<div role='heading' class='ui-controlgroup-label'>"+c.html()+"</div>").insertBefore(d.children(0)),c.remove());d.addClass("ui-corner-all ui-controlgroup ui-controlgroup-"+f.direction);b(d.find(".ui-btn"+(f.excludeInvisible?":visible":"")));b(d.find(".ui-btn-inner"));f.shadow&&d.addClass("ui-shadow")})};a(document).bind("pagecreate create",function(e){a(":jqmData(role='controlgroup')",e.target).controlgroup({excludeInvisible:false})})})(jQuery);
|
||||
(function(a){a(document).bind("pagecreate create",function(e){a(e.target).find("a").not(".ui-btn, .ui-link-inherit, :jqmData(role='none'), :jqmData(role='nojs')").addClass("ui-link")})})(jQuery);
|
||||
(function(a,e){a.fn.fixHeaderFooter=function(){return!a.support.scrollTop||a.support.touchOverflow&&a.mobile.touchOverflowEnabled?this:this.each(function(){var b=a(this);b.jqmData("fullscreen")&&b.addClass("ui-page-fullscreen");b.find(".ui-header:jqmData(position='fixed')").addClass("ui-header-fixed ui-fixed-inline fade");b.find(".ui-footer:jqmData(position='fixed')").addClass("ui-footer-fixed ui-fixed-inline fade")})};a.mobile.fixedToolbars=function(){function b(){!i&&g==="overlay"&&(h||a.mobile.fixedToolbars.hide(true),
|
||||
a.mobile.fixedToolbars.startShowTimer())}function d(a){var b=0,c,d;if(a){d=document.body;c=a.offsetParent;for(b=a.offsetTop;a&&a!=d;){b+=a.scrollTop||0;if(a==c)b+=c.offsetTop,c=a.offsetParent;a=a.parentNode}}return b}function f(b){var c=a(window).scrollTop(),e=d(b[0]),f=b.css("top")=="auto"?0:parseFloat(b.css("top")),h=window.innerHeight,g=b.outerHeight(),i=b.parents(".ui-page:not(.ui-page-fullscreen)").length;return b.is(".ui-header-fixed")?(f=c-e+f,f<e&&(f=0),b.css("top",i?f:c)):b.css("top",i?c+
|
||||
h-g-(e-f):c+h-g)}if(a.support.scrollTop&&(!a.support.touchOverflow||!a.mobile.touchOverflowEnabled)){var c,h,g="inline",i=false,k=null,l=false,o=true;a(function(){var c=a(document),d=a(window);c.bind("vmousedown",function(){o&&(k=g)}).bind("vclick",function(b){o&&!a(b.target).closest("a,input,textarea,select,button,label,.ui-header-fixed,.ui-footer-fixed").length&&!l&&(a.mobile.fixedToolbars.toggle(k),k=null)}).bind("silentscroll",b);(c.scrollTop()===0?d:c).bind("scrollstart",function(){l=true;k===
|
||||
null&&(k=g);var b=k=="overlay";if(i=b||!!h)a.mobile.fixedToolbars.clearShowTimer(),b&&a.mobile.fixedToolbars.hide(true)}).bind("scrollstop",function(b){a(b.target).closest("a,input,textarea,select,button,label,.ui-header-fixed,.ui-footer-fixed").length||(l=false,i&&(a.mobile.fixedToolbars.startShowTimer(),i=false),k=null)});d.bind("resize updatelayout",b)});a(".ui-page").live("pagebeforeshow",function(b,d){var e=a(b.target).find(":jqmData(role='footer')"),h=e.data("id"),g=d.prevPage,g=g&&g.find(":jqmData(role='footer')"),
|
||||
g=g.length&&g.jqmData("id")===h;h&&g&&(c=e,f(c.removeClass("fade in out").appendTo(a.mobile.pageContainer)))}).live("pageshow",function(){var b=a(this);c&&c.length&&setTimeout(function(){f(c.appendTo(b).addClass("fade"));c=null},500);a.mobile.fixedToolbars.show(true,this)});a(".ui-collapsible-contain").live("collapse expand",b);return{show:function(b,c){a.mobile.fixedToolbars.clearShowTimer();g="overlay";return(c?a(c):a.mobile.activePage?a.mobile.activePage:a(".ui-page-active")).children(".ui-header-fixed:first, .ui-footer-fixed:not(.ui-footer-duplicate):last").each(function(){var c=
|
||||
a(this),e=a(window).scrollTop(),h=d(c[0]),g=window.innerHeight,i=c.outerHeight(),e=c.is(".ui-header-fixed")&&e<=h+i||c.is(".ui-footer-fixed")&&h<=e+g;c.addClass("ui-fixed-overlay").removeClass("ui-fixed-inline");!e&&!b&&c.animationComplete(function(){c.removeClass("in")}).addClass("in");f(c)})},hide:function(b){g="inline";return(a.mobile.activePage?a.mobile.activePage:a(".ui-page-active")).children(".ui-header-fixed:first, .ui-footer-fixed:not(.ui-footer-duplicate):last").each(function(){var c=a(this),
|
||||
d=c.css("top"),d=d=="auto"?0:parseFloat(d);c.addClass("ui-fixed-inline").removeClass("ui-fixed-overlay");if(d<0||c.is(".ui-header-fixed")&&d!==0)b?c.css("top",0):c.css("top")!=="auto"&&parseFloat(c.css("top"))!==0&&c.animationComplete(function(){c.removeClass("out reverse").css("top",0)}).addClass("out reverse")})},startShowTimer:function(){a.mobile.fixedToolbars.clearShowTimer();var b=[].slice.call(arguments);h=setTimeout(function(){h=e;a.mobile.fixedToolbars.show.apply(null,b)},100)},clearShowTimer:function(){h&&
|
||||
clearTimeout(h);h=e},toggle:function(b){b&&(g=b);return g==="overlay"?a.mobile.fixedToolbars.hide():a.mobile.fixedToolbars.show()},setTouchToggleEnabled:function(a){o=a}}}}();a(document).bind("pagecreate create",function(b){a(":jqmData(position='fixed')",b.target).length&&a(b.target).each(function(){if(!a.support.scrollTop||a.support.touchOverflow&&a.mobile.touchOverflowEnabled)return this;var b=a(this);b.jqmData("fullscreen")&&b.addClass("ui-page-fullscreen");b.find(".ui-header:jqmData(position='fixed')").addClass("ui-header-fixed ui-fixed-inline fade");
|
||||
b.find(".ui-footer:jqmData(position='fixed')").addClass("ui-footer-fixed ui-fixed-inline fade")})})})(jQuery);
|
||||
(function(a){a.mobile.touchOverflowEnabled=false;a.mobile.touchOverflowZoomEnabled=false;a(document).bind("pagecreate",function(e){a.support.touchOverflow&&a.mobile.touchOverflowEnabled&&(e=a(e.target),e.is(":jqmData(role='page')")&&e.each(function(){var b=a(this),d=b.find(":jqmData(role='header'), :jqmData(role='footer')").filter(":jqmData(position='fixed')"),e=b.jqmData("fullscreen"),c=d.length?b.find(".ui-content"):b;b.addClass("ui-mobile-touch-overflow");c.bind("scrollstop",function(){c.scrollTop()>
|
||||
0&&window.scrollTo(0,a.mobile.defaultHomeScroll)});d.length&&(b.addClass("ui-native-fixed"),e&&(b.addClass("ui-native-fullscreen"),d.addClass("fade in"),a(document).bind("vclick",function(){d.removeClass("ui-native-bars-hidden").toggleClass("in out").animationComplete(function(){a(this).not(".in").addClass("ui-native-bars-hidden")})})))}))})})(jQuery);
|
||||
(function(a,e){function b(){var b=a("meta[name='viewport']");b.length?b.attr("content",b.attr("content")+", user-scalable=no"):a("head").prepend("<meta>",{name:"viewport",content:"user-scalable=no"})}var d=a("html");a("head");var f=a(e);a(e.document).trigger("mobileinit");if(a.mobile.gradeA()){if(a.mobile.ajaxBlacklist)a.mobile.ajaxEnabled=false;d.addClass("ui-mobile ui-mobile-rendering");var c=a("<div class='ui-loader ui-body-a ui-corner-all'><span class='ui-icon ui-icon-loading spin'></span><h1></h1></div>");
|
||||
a.extend(a.mobile,{showPageLoadingMsg:function(){if(a.mobile.loadingMessage){var b=a("."+a.mobile.activeBtnClass).first();c.find("h1").text(a.mobile.loadingMessage).end().appendTo(a.mobile.pageContainer).css({top:a.support.scrollTop&&f.scrollTop()+f.height()/2||b.length&&b.offset().top||100})}d.addClass("ui-loading")},hidePageLoadingMsg:function(){d.removeClass("ui-loading")},initializePage:function(){var b=a(":jqmData(role='page')");b.length||(b=a("body").wrapInner("<div data-"+a.mobile.ns+"role='page'></div>").children(0));
|
||||
b.add(":jqmData(role='dialog')").each(function(){var b=a(this);b.jqmData("url")||b.attr("data-"+a.mobile.ns+"url",b.attr("id")||location.pathname+location.search)});a.mobile.firstPage=b.first();a.mobile.pageContainer=b.first().parent().addClass("ui-mobile-viewport");f.trigger("pagecontainercreate");a.mobile.showPageLoadingMsg();!a.mobile.hashListeningEnabled||!a.mobile.path.stripHash(location.hash)?a.mobile.changePage(a.mobile.firstPage,{transition:"none",reverse:true,changeHash:false,fromHashChange:true}):
|
||||
f.trigger("hashchange",[true])}});a.support.touchOverflow&&a.mobile.touchOverflowEnabled&&!a.mobile.touchOverflowZoomEnabled&&b();a.mobile._registerInternalEvents();a(function(){e.scrollTo(0,1);a.mobile.defaultHomeScroll=!a.support.scrollTop||a(e).scrollTop()===1?0:1;a.mobile.autoInitializePage&&a.mobile.initializePage();f.load(a.mobile.silentScroll)})}})(jQuery,this);
|
||||
|
||||
114
applications/admin/views/debug/breakpoints.html
Normal file
114
applications/admin/views/debug/breakpoints.html
Normal file
@@ -0,0 +1,114 @@
|
||||
{{extend 'layout.html'}}
|
||||
|
||||
{{block sectionclass}}debug{{end}}
|
||||
|
||||
<style>
|
||||
table.sortable {
|
||||
border-spacing:0px;
|
||||
}
|
||||
table.sortable td, table.sortable th {
|
||||
padding: 2px 5px 2px 5px;
|
||||
}
|
||||
table.sortable thead {
|
||||
background-color:#eee;
|
||||
color:#666666;
|
||||
font-weight: bold;
|
||||
cursor: default;
|
||||
}
|
||||
tr.error_ticket:hover {
|
||||
background-color: #eee;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script language="JavaScript">
|
||||
function check(){
|
||||
for (var i = 0; i < document.myform.elements.length; i++) {
|
||||
var e = document.myform.elements[i];
|
||||
if (e.type == 'checkbox') e.checked = true;
|
||||
}
|
||||
}
|
||||
function uncheck(){
|
||||
for (var i = 0; i < document.myform.elements.length; i++) {
|
||||
var e = document.myform.elements[i];
|
||||
if (e.type == 'checkbox') e.checked = false;
|
||||
}
|
||||
}
|
||||
jQuery(document).ready(function() { jQuery('.sourcecode').hide(); });
|
||||
</script>
|
||||
|
||||
<div class="applist f60">
|
||||
<div class="applist_inner">
|
||||
|
||||
<h2>{{=T("Breakpoints")}}</h2>
|
||||
|
||||
<div class="errorform">
|
||||
<form name="myform" method="post">
|
||||
<input name="CheckAll" value="{{=T('check all')}}"
|
||||
onclick="check()" type="button">
|
||||
<input name="CheckAll" value="{{=T('uncheck all')}}"
|
||||
onclick="uncheck()" type="button">
|
||||
<input value="{{=T('delete all checked')}}" type="submit"><br><br>
|
||||
|
||||
<table id="trck_breakpoints" class="sortable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{=T("Delete")}}</th>
|
||||
<th>{{=T("Filename")}}</th>
|
||||
<th>{{=T("LineNo")}}</th>
|
||||
<th>{{=T("Temporary")}}</th>
|
||||
<th>{{=T("Condition")}}</th>
|
||||
<th>{{=T("Hits")}}</th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{for bp in breakpoints:}}
|
||||
<tr class="breakpoint">
|
||||
<td><input type="checkbox" name="delete_{{=bp['number']}}" /></td>
|
||||
<td>{{=bp['filename']}}</td>
|
||||
<td>{{=A(bp['lineno'],_href="#",_onclick="collapse('%s');" % bp['number'])}}</td>
|
||||
<td>{{=bp['temporary']}}</td>
|
||||
<td>{{=bp['condition']}}</td>
|
||||
<td>{{=bp['hits']}}</td>
|
||||
</tr>
|
||||
<tr id="{{=bp['number']}}" class="sourcecode">
|
||||
<td colspan="6">
|
||||
<div>
|
||||
{{=CODE(open(bp['path']).read(), language='python',
|
||||
link=None, highlight_line=bp['lineno'], context_lines=10)}}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{pass}}
|
||||
</tbody>
|
||||
</table>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="help">
|
||||
<ul>
|
||||
<li>{{=T("You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button")}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="sidebar fl60">
|
||||
<div class="sidebar_inner controls">
|
||||
|
||||
<div class="box">
|
||||
|
||||
<h3>{{=T("Add breakpoint")}}</h3>
|
||||
|
||||
{{=form}}
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,24 +1,26 @@
|
||||
{{extend 'layout.html'}}
|
||||
|
||||
{{block sectionclass}}about{{end}}
|
||||
|
||||
<!-- begin "about" block -->
|
||||
<h2>{{=T("About application")}} "{{=app}}"</h2>
|
||||
<h3>{{=T("About")}} {{=app}}</h3>
|
||||
<p class="controls">{{=button(URL('edit/%s/ABOUT' % (app)), T('Edit'))}}</p>
|
||||
<div class="about_text legalese">{{=about}}</div>
|
||||
<div class="about_text legalese well well-small">{{=about}}</div>
|
||||
<h3>{{=T('License for')}} {{=app}}</h3>
|
||||
<p class="controls">{{=button(URL('edit/%s/LICENSE' % (app)), T('Edit'))}}</p>
|
||||
<div class="license_text legalese">{{=license}}</div>
|
||||
</ul>
|
||||
|
||||
<script language="javascript" type="text/javascript" src="{{=URL('static','js/jquery.flot.js')}}"></script>
|
||||
|
||||
<div class="license_text legalese well well-small">{{=license}}</div>
|
||||
<h3>{{=T('Project Progress')}}</h3>
|
||||
<p>
|
||||
<center>
|
||||
<div id="placeholder" style="width:600px;height:300px;"></div>
|
||||
</center>
|
||||
<script language="javascript" type="text/javascript" src="{{=URL('static','js/jquery.flot.js')}}"></script>
|
||||
<script language="javascript" type="text/javascript" src="{{=URL('static','js/jquery.flot.resize.js')}}"></script>
|
||||
<div class="row-fluid">
|
||||
<div class="span2"> </div>
|
||||
<div class="span8 center">
|
||||
<div id="placeholder"></div>
|
||||
</div>
|
||||
<div class="span2"> </div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
jQuery(function () { jQuery.plot(jQuery("#placeholder"), [ {{=progress}} ]); });
|
||||
jQuery(document).ready(function() {
|
||||
jQuery.plot(jQuery("#placeholder"), [ {{=progress}} ]);
|
||||
})
|
||||
</script>
|
||||
</p>
|
||||
<!-- end "about" block -->
|
||||
@@ -1,5 +1,20 @@
|
||||
{{extend 'layout.html'}}
|
||||
|
||||
<h1>{{=T('Bulk Student Registration')}}</h1>
|
||||
|
||||
{{=form}}
|
||||
{{
|
||||
# add bootstrap class to form
|
||||
form['_class']='span4 well well-small'
|
||||
# change form.custom.begin
|
||||
form.custom.begin=XML("<%s %s>" % (form.tag,form._xml()[0]))
|
||||
# new form buttons
|
||||
smt = form.element('input',_type='submit')
|
||||
smt['_class']='btn'
|
||||
form.element('input[type=submit]',replace=lambda button: DIV(button,_class="controls-inline"))
|
||||
}}
|
||||
<h2>{{=T('Bulk Student Registration').capitalize()}}</h2>
|
||||
<div id="web2py_user_form">
|
||||
{{=form.custom.begin}}
|
||||
{{for e in form.components[0]:}}
|
||||
{{= e[0][0]}}
|
||||
{{= e[1][0]}}
|
||||
{{pass}}
|
||||
{{=form.custom.end}}
|
||||
</div>
|
||||
@@ -1,10 +1,22 @@
|
||||
{{extend 'layout.html'}}
|
||||
|
||||
{{block sectionclass}}change_password{{end}}
|
||||
|
||||
<h2>Change Admin Password</h2>
|
||||
|
||||
<!-- begin "change_password" block -->
|
||||
<h2>web2py™ {{=T('Web Framework')}}</h2>
|
||||
<h3>{{=T('Change Admin Password')}}</h3>
|
||||
<div class="pwform">
|
||||
{{=form}}
|
||||
{{=form.custom.begin}}
|
||||
{{ for fieldname in form.table.fields: }}
|
||||
{{if fieldname is not 'id':}}
|
||||
<label>{{=form.custom.label[fieldname]}}</label>
|
||||
{{=form.custom.widget[fieldname]}}
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
<div class="controls"><button type="submit" class="btn">{{=T('Submit')}}</button></div>
|
||||
{{=form.custom.end}}
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
jQuery(document).ready(function() {
|
||||
jQuery(":input:visible:enabled:first").focus();
|
||||
});
|
||||
</script>
|
||||
<!-- end "change_password" block -->
|
||||
@@ -1,9 +1,16 @@
|
||||
{{extend 'layout.html'}}
|
||||
|
||||
{{
|
||||
dlg = dialog
|
||||
smt_button = dlg.element(_type="submit")
|
||||
smt_button['_class'] = 'btn'
|
||||
smt_button['_style'] = 'margin-right:4px;'
|
||||
ccl_button = dlg.element(_type="button")
|
||||
ccl_button['_class'] = 'btn'
|
||||
}}
|
||||
{{block sectionclass}}delete{{end}}
|
||||
|
||||
<!-- begin "delete" block -->
|
||||
<h2>{{=T('Are you sure you want to delete file "%s"?', filename)}}</h2>
|
||||
<div class="center">
|
||||
{{=dialog}}
|
||||
</div>
|
||||
|
||||
<!-- end "delete" block -->
|
||||
@@ -1,9 +1,16 @@
|
||||
{{extend 'layout.html'}}
|
||||
|
||||
{{
|
||||
dlg = dialog
|
||||
smt_button = dlg.element(_type="submit")
|
||||
smt_button['_class'] = 'btn'
|
||||
smt_button['_style'] = 'margin-right:4px;'
|
||||
ccl_button = dlg.element(_type="button")
|
||||
ccl_button['_class'] = 'btn'
|
||||
}}
|
||||
{{block sectionclass}}delete_plugin{{end}}
|
||||
|
||||
<!-- begin "delete_plugin" block -->
|
||||
<h2>{{=T('Are you sure you want to delete plugin "%s"?', plugin)}}</h2>
|
||||
<div class="center">
|
||||
{{=dialog}}
|
||||
</div>
|
||||
|
||||
<!-- end "delete_plugin" block -->
|
||||
@@ -1,58 +1,81 @@
|
||||
{{extend 'layout.html'}}
|
||||
{{
|
||||
def all(items):
|
||||
return reduce(lambda a,b:a and b,items,True)
|
||||
return reduce(lambda a,b:a and b,items,True)
|
||||
def peekfile(path,file,vars={},title=None):
|
||||
args=(path,file) if 'app' in vars else (app,path,file)
|
||||
return A(file.replace('\\\\','/'),_title=title,_href=URL('peek', args=args, vars=vars))
|
||||
args=(path,file) if 'app' in vars else (app,path,file)
|
||||
return A(file.replace('\\\\','/'),_title=title,_href=URL('peek', args=args, vars=vars))
|
||||
def editfile(path,file,vars={}):
|
||||
args=(path,file) if 'app' in vars else (app,path,file)
|
||||
return A(SPAN(T('Edit')),_class='button editbutton',_href=URL('edit', args=args, vars=vars))
|
||||
args=(path,file) if 'app' in vars else (app,path,file)
|
||||
return A(SPAN(T('Edit')),_class='button editbutton btn',_href=URL('edit', args=args, vars=vars))
|
||||
def testfile(path,file):
|
||||
return A(TAG[''](IMG(_src=URL('static', 'images/test_icon.png'), _alt=T('test')), SPAN(T("Run tests in this file (to run all files, you may also use the button labelled 'test')"))), _class='icon test tooltip',_href=URL('test', args=(app, file)))
|
||||
return A(TAG[''](IMG(_src=URL('static', 'images/test_icon.png'), _alt=T('test')),
|
||||
SPAN(T("Run tests in this file (to run all files, you may also use the button labelled 'test')"))),
|
||||
_class='icon test',
|
||||
_href=URL('test', args=(app, file)),
|
||||
_rel="tooltip",
|
||||
**{'_data-placement':'right',
|
||||
'_data-original-title':T("Run tests in this file (to run all files, you may also use the button labelled 'test')")})
|
||||
def editlanguagefile(path,file,vars={}):
|
||||
return A(SPAN(T('Edit')),_class='button editbutton',_href=URL('edit_language', args=(app, path, file), vars=vars))
|
||||
return A(SPAN(T('Edit')),_class='button editbutton btn',_href=URL('edit_language', args=(app, path, file), vars=vars))
|
||||
def editpluralsfile(path,file,vars={}):
|
||||
return A(SPAN(T('Edit')),_class='button editbutton',_href=URL('edit_plurals', args=(app, path, file), vars=vars))
|
||||
return A(SPAN(T('Edit')),_class='button editbutton btn',_href=URL('edit_plurals', args=(app, path, file), vars=vars))
|
||||
def file_upload_form(location, anchor=None):
|
||||
form=FORM(T("upload file:")," ",
|
||||
INPUT(_type="file",_name="file")," ",T("and rename it:")," ",
|
||||
INPUT(_type="text",_name="filename",requires=IS_NOT_EMPTY),
|
||||
INPUT(_type="hidden",_name="location",_value=location),
|
||||
INPUT(_type="hidden",_name="token",_value=session.token),
|
||||
INPUT(_type="hidden",_name="sender",_value=URL('design',args=app, anchor=anchor)),
|
||||
INPUT(_type="submit",_value=T("upload")),_action=URL('upload_file'))
|
||||
return form
|
||||
def file_create_form(location, anchor=None):
|
||||
form=FORM(T("create file with filename:")," ",
|
||||
INPUT(_type="text",_name="filename",requires=IS_NOT_EMPTY),
|
||||
INPUT(_type="hidden",_name="location",_value=location),
|
||||
INPUT(_type="hidden",_name="sender",_value=URL('design',args=app)),
|
||||
INPUT(_type="hidden",_name="token",_value=session.token),
|
||||
INPUT(_type="hidden",_name="id",_value=anchor),
|
||||
INPUT(_type="submit",_value=T("Create")),_action=URL('create_file'))
|
||||
return form
|
||||
form=FORM(
|
||||
LABEL(T("upload file:")),
|
||||
INPUT(_type="file",_name="file"),
|
||||
LABEL(T("and rename it:")),
|
||||
INPUT(_type="text",_name="filename",requires=IS_NOT_EMPTY,_class=""),
|
||||
DIV(TAG['BUTTON'](T("Upload"),_type="submit",_class="btn"),_class="controls"),
|
||||
INPUT(_type="hidden",_name="location",_value=location),
|
||||
INPUT(_type="hidden",_name="token",_value=session.token),
|
||||
INPUT(_type="hidden",_name="sender",_value=URL('design',args=app, anchor=anchor)),
|
||||
_action=URL('upload_file'),
|
||||
_class="generatedbyw2p well well-small")
|
||||
return form
|
||||
def file_create_form(location, anchor=None, helptext=""):
|
||||
form=FORM(
|
||||
LABEL(T("create file with filename:")),
|
||||
INPUT(_type="text",_name="filename",requires=IS_NOT_EMPTY,_class=''),
|
||||
TAG['SMALL'](helptext,_class="help-block"),
|
||||
DIV(TAG['BUTTON'](T("Create"),_type="submit",_class="btn"),_class="controls"),
|
||||
INPUT(_type="hidden",_name="location",_value=location),
|
||||
INPUT(_type="hidden",_name="sender",_value=URL('design',args=app)),
|
||||
INPUT(_type="hidden",_name="token",_value=session.token),
|
||||
INPUT(_type="hidden",_name="id",_value=anchor),
|
||||
_action=URL('create_file'),
|
||||
_class="generatedbyw2p well well-small")
|
||||
return form
|
||||
def upload_plugin_form(app, anchor=None):
|
||||
form=FORM(T("upload plugin file:")," ",
|
||||
INPUT(_type="file",_name="pluginfile"),
|
||||
INPUT(_type="hidden",_name="id",_value=anchor),
|
||||
INPUT(_type="hidden",_name="token",_value=session.token),
|
||||
INPUT(_type="submit",_value=T("upload")))
|
||||
return form
|
||||
form=FORM(
|
||||
LABEL(T("upload plugin file:")),
|
||||
INPUT(_type="file",_name="pluginfile"),
|
||||
INPUT(_type="hidden",_name="id",_value=anchor),
|
||||
INPUT(_type="hidden",_name="token",_value=session.token),
|
||||
DIV(TAG['BUTTON'](T("Upload"),_type="submit",_class="btn"),_class="controls"),
|
||||
_class="generatedbyw2p well well-small")
|
||||
return form
|
||||
def deletefile(arglist, vars={}):
|
||||
vars.update({'sender':request.function+'/'+app})
|
||||
return A(TAG[''](IMG(_src=URL('static', 'images/delete_icon.png')), SPAN(T('Delete this file (you will be asked to confirm deletion)'))), _class='icon delete tooltip', _href=URL('delete',args=arglist,vars=vars))
|
||||
vars.update({'sender':request.function+'/'+app})
|
||||
return A(TAG[''](IMG(_src=URL('static', 'images/delete_icon.png')),
|
||||
SPAN(T('Delete this file (you will be asked to confirm deletion)'))),
|
||||
_href=URL('delete',args=arglist,vars=vars),
|
||||
_class='icon delete',
|
||||
_rel="tooltip",
|
||||
**{'_data-placement':'right',
|
||||
'_data-original-title':T('Delete this file (you will be asked to confirm deletion)')})
|
||||
}}
|
||||
|
||||
{{block sectionclass}}design{{end}}
|
||||
<!-- begin "design" block -->
|
||||
|
||||
<h2>{{=T("Edit application")}} "{{=A(app,_href=URL(app,'default','index'),_target="_blank")}}"</h2>
|
||||
|
||||
<!-- COLLAPSE/JUMP-TO BUTTONS -->
|
||||
<div class="right-full controls">
|
||||
<p>
|
||||
<p class="buttons-row">
|
||||
{{=searchbox('search')}}
|
||||
<a class="button special" href="#" onclick="jQuery('h3').click();return false"><span>{{=T("collapse/expand all")}}</span></a>
|
||||
<a class="button special btn btn-inverse" href="#" onclick="jQuery('h3>span').click();return false"><span>{{=T("collapse/expand all")}}</span></a>
|
||||
<span class="buttongroup">
|
||||
{{=button('#models', T("models"))}}
|
||||
{{=button('#controllers', T("controllers"))}}
|
||||
@@ -63,44 +86,49 @@ def deletefile(arglist, vars={}):
|
||||
{{=button('#private', T("private files"))}}
|
||||
{{=button('#plugins', T("plugins"))}}
|
||||
</span>
|
||||
</p>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- MODELS -->
|
||||
|
||||
<h3 id="models" onclick="collapse('models_inner');" class="component">
|
||||
{{=T("Models")}}
|
||||
<span class="tooltip">{{=helpicon()}} <span>{{=T("The data representation, define database tables and sets")}}</span></span>
|
||||
<h3 id="_models" rel="pagebookmark">
|
||||
<span class="component" onclick="collapse('models_inner');">{{=T("Models")}}</span>
|
||||
<a href="#models" rel="tooltip" data-placement="right" data-original-title="{{=T('The data representation, define database tables and sets')}}">
|
||||
{{=helpicon()}}
|
||||
<span>{{=T("The data representation, define database tables and sets")}}</span>
|
||||
</a><span id="models" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||
</h3>
|
||||
<div id="models_inner" class="component_contents">
|
||||
{{if not models:}}<p><strong>{{=T("There are no models")}}</strong></p>{{else:}}
|
||||
<div class="controls comptools">
|
||||
{{=button(URL(a=app,c='appadmin',f='index'), T('database administration'))}}
|
||||
{{if os.access(os.path.join(request.folder,'..',app,'databases','sql.log'),os.R_OK):}}
|
||||
{{=button(URL('peek/%s/databases/sql.log'%app), 'sql.log')}}
|
||||
{{pass}}
|
||||
{{=button(URL(a=app, c='appadmin',f='graph_model'), T('graph model'))}}
|
||||
</div>
|
||||
{{pass}}
|
||||
|
||||
<ul>
|
||||
{{for m in models:}}
|
||||
{{id="models__"+m.replace('.','__')}}
|
||||
<li id="{{=id}}">
|
||||
<span class="filetools controls">
|
||||
{{=editfile('models',m, dict(id=id))}}
|
||||
{{=deletefile([app, 'models', m], dict(id=id, id2='models'))}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('models',m, dict(id=id))}}
|
||||
</span>
|
||||
<span class="extras">
|
||||
{{if len(defines[m]):}}{{=T("defines tables")}} {{pass}}{{=XML(', '.join([B(table).xml() for table in defines[m]]))}}
|
||||
</span>
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
<div class="controls formfield">{{=file_create_form('%s/models/' % app, 'models')}}</div>
|
||||
{{if not models:}}<p><strong>{{=T("There are no models")}}</strong></p>{{else:}}
|
||||
<div class="controls comptools">
|
||||
{{=button(URL(a=app,c='appadmin',f='index'), T('database administration'))}}
|
||||
{{if os.access(os.path.join(request.folder,'..',app,'databases','sql.log'),os.R_OK):}}
|
||||
{{=button(URL('peek/%s/databases/sql.log'%app), 'sql.log')}}
|
||||
{{pass}}
|
||||
{{=button(URL(a=app, c='appadmin',f='graph_model'), T('graph model'))}}
|
||||
</div>
|
||||
<ul class="unstyled act_edit">
|
||||
{{for m in models:}}
|
||||
{{id="models__"+m.replace('.','__')}}
|
||||
<li id="{{='_'+id}}" rel="pagebookmark"><span id="{{=id}}" class="hashstick"> </span>
|
||||
<span class="filetools controls">
|
||||
{{=editfile('models',m, dict(id=id))}}
|
||||
{{=deletefile([app, 'models', m], dict(id=id, id2='models'))}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('models',m, dict(id=id))}}
|
||||
</span>
|
||||
<span class="extras">
|
||||
{{if len(defines[m]):}}{{=T("defines tables")}} {{pass}}{{=XML(', '.join([B(table).xml() for table in defines[m]]))}}
|
||||
</span>
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
{{pass}}
|
||||
<div class="controls formfield">
|
||||
<div class="row-fluid">
|
||||
<div class="span3">{{=file_create_form('%s/models/' % app, 'models')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- FIND CONTROLLER FUNCTIONS -->
|
||||
@@ -110,289 +138,325 @@ for c in controllers: controller_functions+=[c[:-3]+'/%s.html'%x for x in functi
|
||||
}}
|
||||
|
||||
<!-- CONTROLLERS -->
|
||||
|
||||
<h3 id="controllers" onclick="collapse('controllers_inner');" class="component">
|
||||
{{=T("Controllers")}}
|
||||
<span class="tooltip">{{=helpicon()}} <span>{{=T("The application logic, each URL path is mapped in one exposed function in the controller")}}</span></span>
|
||||
<h3 id="_controllers" rel="pagebookmark">
|
||||
<span class="component" onclick="collapse('controllers_inner');">{{=T("Controllers")}}</span>
|
||||
<a href="#controllers" rel="tooltip" data-placement="right" data-original-title="{{=T('The application logic, each URL path is mapped in one exposed function in the controller')}}">
|
||||
{{=helpicon()}}
|
||||
<span>{{=T("The application logic, each URL path is mapped in one exposed function in the controller")}}</span>
|
||||
</a><span id="controllers" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||
</h3>
|
||||
<div id="controllers_inner" class="component_contents">
|
||||
{{if not controllers:}}<p><strong>{{=T("There are no controllers")}}</strong></p>{{else:}}
|
||||
<div class="controls comptools">
|
||||
{{=button(URL(r=request,c='shell',f='index',args=app), T("shell"))}}
|
||||
{{=button(URL('test',args=app), T("test"))}}
|
||||
{{=button(URL('edit',args=[app,'cron','crontab']), T("crontab"))}}
|
||||
</div>
|
||||
{{pass}}
|
||||
<ul>
|
||||
{{for c in controllers:}}
|
||||
{{id="controllers__"+c.replace('.','__')}}
|
||||
<li id="{{=id}}">
|
||||
<span class="filetools controls">
|
||||
{{=editfile('controllers',c, dict(id=id))}}
|
||||
{{=deletefile([app, 'controllers', c], dict(id=id, id2='controllers'))}}
|
||||
{{=testfile('controllers',c)}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('controllers',c, dict(id=id))}}
|
||||
</span>
|
||||
<span class="extras">
|
||||
{{if functions[c]:}}{{=T("exposes")}} {{pass}}{{=XML(', '.join([A(f,_href=URL(a=app,c=c[:-3],f=f)).xml() for f in functions[c]]))}}
|
||||
</span>
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
<div class="controls formfield">{{=file_create_form('%s/controllers/' % app, 'controllers')}}</div>
|
||||
{{if not controllers:}}<p><strong>{{=T("There are no controllers")}}</strong></p>{{else:}}
|
||||
<div class="controls comptools">
|
||||
{{=button(URL(r=request,c='shell',f='index',args=app), T("shell"))}}
|
||||
{{=button(URL('test',args=app), T("test"))}}
|
||||
{{=button(URL('edit',args=[app,'cron','crontab']), T("crontab"))}}
|
||||
</div>
|
||||
<ul class="unstyled act_edit">
|
||||
{{for c in controllers:}}
|
||||
{{id="controllers__"+c.replace('.','__')}}
|
||||
<li id="{{='_'+id}}" rel="pagebookmark"><span id="{{=id}}" class="hashstick"> </span>
|
||||
<span class="filetools controls">
|
||||
{{=editfile('controllers',c, dict(id=id))}}
|
||||
{{=deletefile([app, 'controllers', c], dict(id=id, id2='controllers'))}}
|
||||
{{=testfile('controllers',c)}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('controllers',c, dict(id=id))}}
|
||||
</span>
|
||||
<span class="extras celled">
|
||||
{{if functions[c]:}}{{=T("exposes")}}{{pass}} {{=XML(', '.join([A(f,_href=URL(a=app,c=c[:-3],f=f)).xml() for f in functions[c]]))}}
|
||||
</span>
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
{{pass}}
|
||||
<div class="controls formfield">
|
||||
<div class="row-fluid">
|
||||
<div class="span3">{{=file_create_form('%s/controllers/' % app, 'controllers')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- VIEWS -->
|
||||
|
||||
<h3 id="views" onclick="collapse('views_inner');" class="component">
|
||||
{{=T("Views")}}
|
||||
<span class="tooltip">{{=helpicon()}} <span>{{=T("The presentations layer, views are also known as templates")}}</span></span>
|
||||
<h3 id="_views" rel="pagebookmark">
|
||||
<span class="component" onclick="collapse('views_inner');">{{=T("Views")}}</span>
|
||||
<a href="#views" rel="tooltip" data-placement="right" data-original-title="{{=T('The presentations layer, views are also known as templates')}}">
|
||||
{{=helpicon()}}
|
||||
<span>{{=T("The presentations layer, views are also known as templates")}}</span>
|
||||
</a><span id="views" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||
</h3>
|
||||
<div id="views_inner" class="component_contents">
|
||||
<div class="controls comptools">
|
||||
{{=button(LAYOUTS_APP, T("download layouts"))}}
|
||||
</div>
|
||||
{{if not views:}}<p><strong>{{=T("There are no views")}}</strong></p>{{pass}}
|
||||
<ul>
|
||||
{{for c in views:}}
|
||||
{{id="views__"+c.replace('/','__').replace('.','__')}}
|
||||
<li id="{{=id}}">
|
||||
<span class="filetools controls">
|
||||
{{=editfile('views',c, dict(id=id))}}
|
||||
{{=deletefile([app, 'views', c], dict(id=id, id2='views'))}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('views',c, dict(id=id))}}
|
||||
</span>
|
||||
<span class="extras">
|
||||
{{if extend.has_key(c):}}{{=T("extends")}} <b>{{=extend[c]}}</b> {{pass}}
|
||||
{{if include[c]:}}{{=T("includes")}} {{pass}}{{=XML(', '.join([B(f).xml() for f in include[c]]))}}
|
||||
</span>
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
<div class="controls formfield">{{=file_create_form('%s/views/' % app, 'views')}}</div>
|
||||
{{if not views:}}<p><strong>{{=T("There are no views")}}</strong></p>{{else:}}
|
||||
<div class="controls comptools">
|
||||
{{=button(LAYOUTS_APP, T("download layouts"))}}
|
||||
</div>
|
||||
<ul class="unstyled act_edit">
|
||||
{{for c in views:}}
|
||||
{{id="views__"+c.replace('/','__').replace('.','__')}}
|
||||
<li id="{{='_'+id}}" rel="pagebookmark"><span id="{{=id}}" class="hashstick"> </span>
|
||||
<span class="filetools controls">
|
||||
{{=editfile('views',c, dict(id=id))}}
|
||||
{{=deletefile([app, 'views', c], dict(id=id, id2='views'))}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('views',c, dict(id=id))}}
|
||||
</span>
|
||||
<span class="extras celled celled-one">
|
||||
{{if extend.has_key(c):}}{{=T("extends")}} <b>{{=extend[c]}}</b> {{pass}}
|
||||
{{if include[c]:}}{{=T("includes")}} {{pass}}{{=XML(', '.join([B(f).xml() for f in include[c]]))}}
|
||||
</span>
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
{{pass}}
|
||||
<div class="controls formfield">
|
||||
<div class="row-fluid">
|
||||
<div class="span3">{{=file_create_form('%s/views/' % app, 'views')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- LANGUAGES -->
|
||||
|
||||
<h3 id="languages" onclick="collapse('languages_inner');" class="component">
|
||||
{{=T("Languages")}}
|
||||
<span class="tooltip">{{=helpicon()}} <span>{{=T("Translation strings for the application")}}</span></span>
|
||||
<h3 id="_languages" rel="pagebookmark">
|
||||
<span class="component" onclick="collapse('languages_inner');">{{=T("Languages")}}</span>
|
||||
<a href="#languages" rel="tooltip" data-placement="right" data-original-title="{{=T('Translation strings for the application')}}">
|
||||
{{=helpicon()}}
|
||||
<span>{{=T("Translation strings for the application")}}</span>
|
||||
</a><span id="languages" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||
</h3>
|
||||
<div id="languages_inner" class="component_contents">
|
||||
<div class="controls comptools">
|
||||
{{=button(URL('update_languages/'+app), T('update all languages'))}}
|
||||
</div>
|
||||
{{if not languages:}}<p><strong>{{=T("There are no translators, only default language is supported")}}</strong></p>{{pass}}
|
||||
<table>
|
||||
{{for lang in sorted(languages):
|
||||
file = lang+'.py'
|
||||
id = "languages__"+file.replace('.','__')}}
|
||||
<tr id="{{=id}}">
|
||||
<td>
|
||||
<span class="filetools controls">
|
||||
{{=editlanguagefile('languages',file)}}
|
||||
{{=deletefile([app, 'languages', file], dict(id=id, id2='languages'))}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('languages',file, dict(id=id))}}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
(
|
||||
{{=T("Plural-Forms:")}}
|
||||
{{p=languages[lang][3:7]}}
|
||||
{{if p[2] == 'default':}}
|
||||
<span class='error'>{{=T("rules are not defined")}}</span> {{=T.M("(file **gluon/contrib/plural_rules/%s.py** is not found)",lang[:2])}}
|
||||
{{else:}}
|
||||
{{if p[3] == 1:}}
|
||||
{{=B(T("are not used"))}}
|
||||
{{else:}}
|
||||
{{pfile=p[0]}}
|
||||
{{if p[1]!=0:}}
|
||||
<span class="filetools controls">
|
||||
{{=editpluralsfile('languages',pfile,dict(nplurals=p[3]))}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('languages',pfile,dict(id=id))}}
|
||||
</span>
|
||||
{{else:}}
|
||||
<b>{{=T("are not used yet")}}</b>
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
)
|
||||
</td>
|
||||
</tr>
|
||||
{{pass}}
|
||||
</table>
|
||||
{{pass}}
|
||||
<div class="controls formfield">{{=file_create_form('%s/languages/' % app, 'languages')}}{{=T('(something like "it-it")')}}</div>
|
||||
{{if not languages:}}<p><strong>{{=T("There are no translators, only default language is supported")}}</strong></p>{{else:}}
|
||||
<div class="controls comptools">
|
||||
{{=button(URL('update_languages/'+app), T('update all languages'))}}
|
||||
</div>
|
||||
<ul class="unstyled act_edit">
|
||||
{{for lang in sorted(languages):
|
||||
file = lang+'.py'
|
||||
id = "languages__"+file.replace('.','__')}}
|
||||
<li id="{{='_'+id}}" rel="pagebookmark" class="li-row"><span id="{{=id}}" class="hashstick"> </span>
|
||||
<span class="li-controls">
|
||||
<span class="filetools controls">
|
||||
{{=editlanguagefile('languages',file)}}
|
||||
{{=deletefile([app, 'languages', file], dict(id=id, id2='languages'))}}
|
||||
</span>
|
||||
<span class="">
|
||||
{{=peekfile('languages',file, dict(id=id))}}
|
||||
</span>
|
||||
</span> <!-- /li-row -->
|
||||
<span class="extras celled">
|
||||
(
|
||||
{{=T("Plural-Forms:")}}
|
||||
{{p=languages[lang][3:7]}}
|
||||
{{if p[2] == 'default':}}
|
||||
<span class='error text-error'>{{=T("rules are not defined")}}</span> {{=T.M("(file **gluon/contrib/plural_rules/%s.py** is not found)",lang[:2])}}
|
||||
{{else:}}
|
||||
{{if p[3] == 1:}}
|
||||
{{=B(T("are not used"))}}
|
||||
{{else:}}
|
||||
{{pfile=p[0]}}
|
||||
{{if p[1]!=0:}}<span style="display:inline-block;margin-top:-10px;">
|
||||
<span class="filetools controls">
|
||||
{{=editpluralsfile('languages',pfile,dict(nplurals=p[3]))}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('languages',pfile,dict(id=id))}}
|
||||
</span></span>
|
||||
{{else:}}
|
||||
<b>{{=T("are not used yet")}}</b>
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
)
|
||||
</span>
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
{{pass}}
|
||||
<div class="controls formfield">
|
||||
<div class="row-fluid">
|
||||
<div class="span3">{{=file_create_form('%s/languages/' % app, 'languages', T('(something like "it-it")'))}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- STATIC -->
|
||||
|
||||
<h3 id="static" onclick="collapse('static_inner');" class="component">
|
||||
{{=T("Static files")}}
|
||||
<span class="tooltip">{{=helpicon()}} <span>{{=T("These files are served without processing, your images go here")}}</span></span>
|
||||
<h3 id="_static" rel="pagebookmark">
|
||||
<span class="component" onclick="collapse('static_inner');">{{=T("Static")}}</span>
|
||||
<a href="#static" rel="tooltip" data-placement="right" data-original-title="{{=T('These files are served without processing, your images go here')}}">
|
||||
{{=helpicon()}}
|
||||
<span>{{=T("These files are served without processing, your images go here")}}</span>
|
||||
</a><span id="static" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||
</h3>
|
||||
<div id="static_inner" class="component_contents">
|
||||
<div class="controls comptools">
|
||||
</div>
|
||||
{{if not statics:}}<p><strong>{{=T("There are no static files")}}</strong></p>{{pass}}
|
||||
<ul>
|
||||
{{
|
||||
path=[]
|
||||
for file in statics+['']:
|
||||
items=file.split('/')
|
||||
file_path=items[:-1]
|
||||
filename=items[-1]
|
||||
while path!=file_path:
|
||||
if len(file_path)>=len(path) and all([v==file_path[k] for k,v in enumerate(path)]):
|
||||
path.append(file_path[len(path)])
|
||||
thispath='static__'+'__'.join(path)
|
||||
}}
|
||||
<li class="folder">
|
||||
<a href="javascript:collapse('{{=thispath}}');" class="file">{{=path[-1]}}/</a>
|
||||
<ul id="{{=thispath}}" style="display: none;" class="sublist">{{
|
||||
else:
|
||||
path = path[:-1]
|
||||
}}
|
||||
</ul></li>
|
||||
{{
|
||||
pass
|
||||
pass
|
||||
if filename:
|
||||
}}<li>
|
||||
<span class="filetools controls">
|
||||
{{=editfile('static',file, dict(id="static"))}} {{=deletefile([app,'static',file], dict(id="static",id2="static"))}}
|
||||
</span>
|
||||
<span class="file">
|
||||
<a href="{{=URL(a=app,c='static',f=file)}}">{{=filename}}</a>
|
||||
</span>
|
||||
</li>{{
|
||||
pass
|
||||
pass
|
||||
}}
|
||||
{{pass}}
|
||||
</ul>
|
||||
<div class="controls formfield">{{=file_create_form('%s/static/' % app, 'static')}}
|
||||
{{=file_upload_form('%s/static/' % app, 'static')}}</div>
|
||||
{{if not statics:}}<p><strong>{{=T("There are no static files")}}</strong></p>{{else:}}
|
||||
<ul class="unstyled act_edit">
|
||||
{{
|
||||
path=[]
|
||||
for file in statics+['']:
|
||||
items=file.split('/')
|
||||
file_path=items[:-1]
|
||||
filename=items[-1]
|
||||
while path!=file_path:
|
||||
if len(file_path)>=len(path) and all([v==file_path[k] for k,v in enumerate(path)]):
|
||||
path.append(file_path[len(path)])
|
||||
thispath='static__'+'__'.join(path)
|
||||
}}
|
||||
<li class="folder"><i> </i>
|
||||
<a href="javascript:collapse('{{=thispath}}');" class="file">{{=path[-1]}}/</a>
|
||||
<ul id="{{=thispath}}" style="display: none;" class="sublist">{{
|
||||
else:
|
||||
path = path[:-1]
|
||||
}}
|
||||
</ul></li>
|
||||
{{
|
||||
pass
|
||||
pass
|
||||
if filename:
|
||||
}}
|
||||
<li>
|
||||
<span class="filetools controls">
|
||||
{{=editfile('static',file, dict(id="static"))}} {{=deletefile([app,'static',file], dict(id="static",id2="static"))}}
|
||||
</span>
|
||||
<span class="file">
|
||||
<a href="{{=URL(a=app,c='static',f=file)}}">{{=filename}}</a>
|
||||
</span>
|
||||
</li>{{
|
||||
pass
|
||||
pass
|
||||
}}
|
||||
</ul>
|
||||
{{pass}}
|
||||
<div class="controls formfield">
|
||||
<div class="row-fluid">
|
||||
<div class="span3">{{=file_create_form('%s/static/' % app, 'static')}}<em>{{=T('or alternatively')}}</em></div>
|
||||
<div class="span3">{{=file_upload_form('%s/static/' % app, 'static')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODULES -->
|
||||
|
||||
<h3 id="modules" onclick="collapse('modules_inner');" class="component">
|
||||
{{=T("Modules")}}
|
||||
<span class="tooltip">{{=helpicon()}} <span>{{=T("Additional code for your application")}}</span></span>
|
||||
<h3 id="_modules" rel="pagebookmark">
|
||||
<span class="component" onclick="collapse('modules_inner');">{{=T("Modules")}}</span>
|
||||
<a href="#modules" rel="tooltip" data-placement="right" data-original-title="{{=T('Additional code for your application')}}">
|
||||
{{=helpicon()}}
|
||||
<span>{{=T("Additional code for your application")}}</span>
|
||||
</a><span id="modules" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||
</h3>
|
||||
<div id="modules_inner" class="component_contents">
|
||||
<div class="controls comptools">
|
||||
</div>
|
||||
{{if not modules:}}<p><strong>{{=T("There are no modules")}}</strong></p>{{pass}}
|
||||
<ul>
|
||||
{{for m in modules:}}
|
||||
{{id="modules__"+m.replace('/','__').replace('.','__')}}
|
||||
<li id="{{=id}}">
|
||||
<span class="filetols controls">
|
||||
{{=editfile('modules',m,dict(id=id))}}
|
||||
{{if m!='__init__.py':}}
|
||||
{{=deletefile([app, 'modules', m], dict(id=id, id2='modules'))}}
|
||||
{{pass}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('modules',m, dict(id=id))}}
|
||||
</span>
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
<div class="controls formfield">{{=file_create_form('%s/modules/' % app, 'modules')}}
|
||||
{{=file_upload_form('%s/modules/' % app, 'modules')}}</div>
|
||||
{{if not modules:}}<p><strong>{{=T("There are no modules")}}</strong></p>{{else:}}
|
||||
<ul class="unstyled act_edit">
|
||||
{{for m in modules:}}
|
||||
{{id="modules__"+m.replace('/','__').replace('.','__')}}
|
||||
<li id="{{='_'+id}}" rel="pagebookmark"><span id="{{=id}}" class="hashstick"> </span>
|
||||
<span class="filetols controls">
|
||||
{{=editfile('modules',m,dict(id=id))}}
|
||||
{{if m!='__init__.py':}}
|
||||
{{=deletefile([app, 'modules', m], dict(id=id, id2='modules'))}}
|
||||
{{pass}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('modules',m, dict(id=id))}}
|
||||
</span>
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
{{pass}}
|
||||
<div class="controls formfield">
|
||||
<div class="row-fluid">
|
||||
<div class="span3">{{=file_create_form('%s/modules/' % app, 'modules')}}<em>{{=T('or alternatively')}}</em></div>
|
||||
<div class="span3">{{=file_upload_form('%s/modules/' % app, 'modules')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- PRIVATE -->
|
||||
|
||||
<h3 id="private" onclick="collapse('private_inner');" class="component">
|
||||
{{=T("Private files")}}
|
||||
<span class="tooltip">{{=helpicon()}} <span>{{=T("These files are not served, they are only available from within your app")}}</span></span>
|
||||
<h3 id="_private" rel="pagebookmark">
|
||||
<span class="component" onclick="collapse('private_inner');">{{=T("Private files")}}</span>
|
||||
<a href="#private" rel="tooltip" data-placement="right" data-original-title="{{=T('These files are not served, they are only available from within your app')}}">
|
||||
{{=helpicon()}}
|
||||
<span>{{=T("These files are not served, they are only available from within your app")}}</span>
|
||||
</a><span id="private" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||
</h3>
|
||||
<div id="private_inner" class="component_contents">
|
||||
<div class="controls comptools">
|
||||
</div>
|
||||
{{if not privates:}}<p><strong>{{=T("There are no private files")}}</strong></p>{{pass}}
|
||||
<ul>
|
||||
{{
|
||||
path=[]
|
||||
for file in privates+['']:
|
||||
items=file.split('/')
|
||||
file_path=items[:-1]
|
||||
filename=items[-1]
|
||||
while path!=file_path:
|
||||
if len(file_path)>=len(path) and all([v==file_path[k] for k,v in enumerate(path)]):
|
||||
path.append(file_path[len(path)])
|
||||
thispath='private__'+'__'.join(path)
|
||||
}}
|
||||
<li class="folder">
|
||||
<a href="javascript:collapse('{{=thispath}}');" class="file">{{=path[-1]}}/</a>
|
||||
<ul id="{{=thispath}}" style="display: none;" class="sublist">{{
|
||||
else:
|
||||
path = path[:-1]
|
||||
}}
|
||||
</ul></li>
|
||||
{{
|
||||
pass
|
||||
pass
|
||||
if filename:
|
||||
}}<li>
|
||||
<span class="filetools controls">
|
||||
{{=editfile('private',file, dict(id="private"))}} {{=deletefile([app,'private',file], dict(id="private",id2="private"))}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('private',file, dict(id="private"))}}
|
||||
</span>
|
||||
</li>{{
|
||||
pass
|
||||
pass
|
||||
}}
|
||||
{{pass}}
|
||||
</ul>
|
||||
<div class="controls formfield">{{=file_create_form('%s/private/' % app, 'private')}}
|
||||
{{=file_upload_form('%s/private/' % app, 'private')}}</div>
|
||||
{{if not privates:}}<p><strong>{{=T("There are no private files")}}</strong></p>{{else:}}
|
||||
<ul class="unstyled act_edit">
|
||||
{{
|
||||
path=[]
|
||||
for file in privates+['']:
|
||||
items=file.split('/')
|
||||
file_path=items[:-1]
|
||||
filename=items[-1]
|
||||
while path!=file_path:
|
||||
if len(file_path)>=len(path) and all([v==file_path[k] for k,v in enumerate(path)]):
|
||||
path.append(file_path[len(path)])
|
||||
thispath='private__'+'__'.join(path)
|
||||
}}
|
||||
<li class="folder">
|
||||
<a href="javascript:collapse('{{=thispath}}');" class="file">{{=path[-1]}}/</a>
|
||||
<ul id="{{=thispath}}" style="display: none;" class="sublist">{{
|
||||
else:
|
||||
path = path[:-1]
|
||||
}}
|
||||
</ul>
|
||||
</li>
|
||||
{{
|
||||
pass
|
||||
pass
|
||||
if filename:
|
||||
}}
|
||||
<li>
|
||||
<span class="filetools controls">
|
||||
{{=editfile('private',file, dict(id="private"))}} {{=deletefile([app,'private',file], dict(id="private",id2="private"))}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('private',file, dict(id="private"))}}
|
||||
</span>
|
||||
</li>{{
|
||||
pass
|
||||
pass
|
||||
}}
|
||||
{{pass}}
|
||||
</ul>
|
||||
<div class="controls formfield">
|
||||
<div class="row-fluid">
|
||||
<div class="span3">{{=file_create_form('%s/private/' % app, 'private')}}<em>{{=T('or alternatively')}}</em></div>
|
||||
<div class="span3">{{=file_upload_form('%s/private/' % app, 'private')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- PLUGINS -->
|
||||
|
||||
<h3 id="plugins" onclick="collapse('plugins_inner');" class="component">
|
||||
{{=T("Plugins")}}
|
||||
<span class="tooltip">{{=helpicon()}} <span>{{=T("To create a plugin, name a file/folder plugin_[name]")}}</span></span>
|
||||
<h3 id="_plugins" rel="pagebookmark">
|
||||
<span class="component" onclick="collapse('plugins_inner');">{{=T("Plugins")}}</span>
|
||||
<a href="#plugins" rel="tooltip" data-placement="right" data-original-title="{{=T('To create a plugin, name a file/folder plugin_[name]')}}">
|
||||
{{=helpicon()}}
|
||||
<span>{{=T("To create a plugin, name a file/folder plugin_[name]")}}</span>
|
||||
</a><span id="plugins" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||
</h3>
|
||||
<div id="plugins_inner" class="component_contents">
|
||||
<div class="controls comptools">
|
||||
{{=button(PLUGINS_APP, T('download plugins'))}}
|
||||
</div>
|
||||
<div class="controls">
|
||||
</div>
|
||||
{{if plugins:}}
|
||||
<ul>
|
||||
{{for plugin in plugins:}}
|
||||
{{id="plugins__"+plugin.replace('/','__').replace('.','__')}}
|
||||
<li id="{{=id}}">
|
||||
{{=A('plugin_%s' % plugin, _class='file', _href=URL('plugin', args=[app, plugin], vars=dict(id=id, id2='plugins')))}}
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
{{else:}}
|
||||
<p><strong>{{=T('There are no plugins')}}</strong></p>
|
||||
{{pass}}
|
||||
<div class="controls formfield">{{=upload_plugin_form(app, 'plugins')}}</div>
|
||||
<div class="controls comptools">
|
||||
{{=button(PLUGINS_APP, T('download plugins'))}}
|
||||
</div>
|
||||
{{if plugins:}}
|
||||
<ul class="unstyled act_edit">
|
||||
{{for plugin in plugins:}}
|
||||
{{id="plugins__"+plugin.replace('/','__').replace('.','__')}}
|
||||
<li id="{{=id}}">
|
||||
{{=A('plugin_%s' % plugin, _class='file', _href=URL('plugin', args=[app, plugin], vars=dict(id=id, id2='plugins')))}}
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
{{else:}}
|
||||
<p><strong>{{=T('There are no plugins')}}</strong></p>
|
||||
{{pass}}
|
||||
<div class="controls formfield">
|
||||
<div class="row-fluid">
|
||||
<div class="span3">{{=upload_plugin_form(app, 'plugins')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
function filter_files() {
|
||||
if(jQuery('#search').val()){
|
||||
@@ -417,4 +481,4 @@ jQuery(document).ready(function(){
|
||||
jQuery('#search_start').click(function(e){ filter_files(); });
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- end "design" block -->
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{{extend 'layout.html'}}
|
||||
|
||||
<!-- begin "edit" block -->
|
||||
{{
|
||||
def shortcut(combo, description):
|
||||
return XML('<li><tt>%s</tt> %s</li>' % (combo, description))
|
||||
return XML('<li><span class="teletype-text">%s</span><span>%s</span></li>' % (combo, description))
|
||||
}}
|
||||
{{if TEXT_EDITOR == 'amy':}}
|
||||
{{include 'default/amy_ajax.html'}}
|
||||
@@ -88,7 +88,7 @@ jQuery(document).ready(function(){
|
||||
<h2>{{=T('Editing file "%s"',filename)}}</h2>
|
||||
|
||||
{{if functions:}}
|
||||
<p class="formfield">
|
||||
<p class="formfield well well-small">
|
||||
<span style="text-align:left;" id="exposed">
|
||||
{{=B(T('exposes:'))}} {{=XML(', '.join([A(f,_href=URL(a=app,c=controller,f=f)).xml() for f in functions]))}}
|
||||
</span>
|
||||
@@ -98,15 +98,15 @@ jQuery(document).ready(function(){
|
||||
{{pass}}
|
||||
</p>
|
||||
{{pass}}
|
||||
|
||||
<p class="right controls">
|
||||
<div class='row-fluid'>
|
||||
<p class="right controls pull-right">
|
||||
{{if filetype=='python':}}
|
||||
{{=A(SPAN(T('toggle breakpoint')),
|
||||
_value="breakpoint", _name="breakpoint",
|
||||
_onclick="return doToggleBreakpoint('%s','%s://%s%s');" % (filename,
|
||||
request.env['wsgi_url_scheme'], request.env['http_host'],
|
||||
URL(c='debug', f='toggle_breakpoint')),
|
||||
_class="button special")}}
|
||||
_class="button special btn btn-inverse")}}
|
||||
{{pass}}
|
||||
{{=button(URL('design',args=request.vars.app if request.vars.app else request.args[0], anchor=request.vars.id), T('back'))}}
|
||||
{{if edit_controller:}}
|
||||
@@ -116,20 +116,31 @@ jQuery(document).ready(function(){
|
||||
{{=button(view_link, T('try view'))}}
|
||||
{{pass}}
|
||||
{{if request.args[1]=='models':}}
|
||||
<a class="button" href="http://www.web2py.com/sqldesigner" target="_blank"><span>{{=T('online designer')}}</span></a>
|
||||
<a class="button btn" href="http://www.web2py.com/sqldesigner" target="_blank"><span>{{=T('online designer')}}</span></a>
|
||||
{{pass}}
|
||||
<a class="button" href="http://www.web2py.com/examples/static/epydoc/index.html" target="_blank"><span>{{=T('docs')}}</span></a>
|
||||
<a class="button btn" href="http://www.web2py.com/examples/static/epydoc/index.html" target="_blank"><span>{{=T('docs')}}</span></a>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
<div id="editor_area">
|
||||
<form action="{{=URL('edit',args=filename)}}" method="post" name="editform" id="editform">
|
||||
<a value="save" name="save" onclick="return doClickSave();" class="icon saveicon">
|
||||
{{=IMG(_src=URL('static', 'images/save_icon.png'), _alt=T('Save'))}}
|
||||
</a>
|
||||
{{=T('Saved file hash:')}}
|
||||
<input type="input" name="file_hash" value="{{=file_hash}}" readonly="readonly"/>
|
||||
{{=T('Last saved on:')}} <input type="input" name="saved_on" value="{{=saved_on}}" readonly="readonly"/>
|
||||
<br><hr>
|
||||
<div class="editor-bar-column">
|
||||
<label>{{=T('Save file:')}}</label>
|
||||
<a value="save" name="save" onclick="return doClickSave();" class="icon saveicon btn btn-mini" style="background-image: -webkit-linear-gradient(top,white,#E6E6E6);">
|
||||
{{=IMG(_src=URL('static', 'images/save_icon.png'), _alt=T('Save'))}}
|
||||
</a>
|
||||
</div>
|
||||
<div class="editor-bar-column">
|
||||
<div class="row-fluid">
|
||||
<div class="span7">
|
||||
<label>{{=T('Saved file hash:')}}</label>
|
||||
<input type="input" name="file_hash" value="{{=file_hash}}" class="input-long uneditable-input" readonly="readonly"/>
|
||||
</div>
|
||||
<div class="span5">
|
||||
<label>{{=T('Last saved on:')}}</label>
|
||||
<input type="input" name="saved_on" value="{{=saved_on}}" class="input-normal uneditable-input" readonly="readonly"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{if TEXT_EDITOR == 'amy':}}
|
||||
<textarea style="width: auto; height:400px;direction:ltr;" rows="58" cols="100" -amy-enabled="true" id="body" name="data">{{=data}}</textarea>
|
||||
<script>window.eamy = eamy;</script>
|
||||
@@ -227,52 +238,59 @@ window.onload = function() {
|
||||
<textarea cols="80" rows="25" id="body" style="direction:ltr;" name="data">{{=data}}</textarea>
|
||||
<script>window.textarea = area.textarea;</script>
|
||||
{{pass}}
|
||||
<button class="editbutton" onclick="window.location.reload(); return false">{{=T('restore')}}</button> {{=T('currently saved or')}} <button class="editbutton" type="submit" name="revert">{{=T('revert')}}</button>
|
||||
{{=T('to previous version.')}}
|
||||
<div class="editor-bar-bottom" style="margin-top:9px;">
|
||||
<button class="editbutton btn" onclick="window.location.reload(); return false">{{=T('restore')}}</button>
|
||||
{{=T('currently saved or')}}
|
||||
<button class="editbutton btn" type="submit" name="revert">{{=T('revert')}}</button>
|
||||
{{=T('to previous version.')}}
|
||||
</div>
|
||||
<br/>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="help">
|
||||
{{if TEXT_EDITOR=='edit_area' and filetype=='html':}}
|
||||
<h3>{{=T('Key bindings for ZenCoding Plugin')}}</h3>
|
||||
<ul>
|
||||
{{=shortcut('Ctrl+S', T('Save via Ajax'))}}
|
||||
{{=shortcut('Ctrl+,', T('Expand Abbreviation'))}}
|
||||
{{=shortcut('Ctrl+M', T('Match Pair'))}}
|
||||
{{=shortcut('Ctrl+H', T('Wrap with Abbreviation'))}}
|
||||
{{=shortcut('Shift+Ctrl+M', T('Merge Lines'))}}
|
||||
{{=shortcut('Ctrl+Shift+←', T('Previous Edit Point'))}}
|
||||
{{=shortcut('Ctrl+Shift+→', T('Next Edit Point'))}}
|
||||
{{=shortcut('Ctrl+Shift+↑', T('Go to Matching Pair'))}}
|
||||
</ul>
|
||||
{{elif TEXT_EDITOR == 'codemirror' and filetype=='html':}}
|
||||
<h3>{{=T('Key bindings for ZenCoding Plugin')}}</h3>
|
||||
<ul>
|
||||
{{=shortcut('Ctrl+S', T('Save via Ajax'))}}
|
||||
{{=shortcut('Ctrl+F11', T('Toggle Fullscreen'))}}
|
||||
{{=shortcut('Ctrl-F / Cmd-F', T('Start searching'))}}
|
||||
{{=shortcut('Ctrl-G / Cmd-G', T('Find Next'))}}
|
||||
{{=shortcut('Shift-Ctrl-G / Shift-Cmd-G', T('Find Previous'))}}
|
||||
{{=shortcut('Shift-Ctrl-F / Cmd-Option-F', T('Replace'))}}
|
||||
{{=shortcut('Shift-Ctrl-R / Shift-Cmd-Option-F', T('Replace All'))}}
|
||||
{{=shortcut('Tab', T('Expand Abbreviation'))}}
|
||||
</ul>
|
||||
{{elif TEXT_EDITOR == 'codemirror':}}
|
||||
<h3>{{=T("Key bindings")}}</h3>
|
||||
<ul>
|
||||
{{=shortcut('Ctrl+S', T('Save via Ajax'))}}
|
||||
{{=shortcut('Ctrl+F11', T('Toggle Fullscreen'))}}
|
||||
{{=shortcut('Ctrl-F / Cmd-F', T('Start searching'))}}
|
||||
{{=shortcut('Ctrl-G / Cmd-G', T('Find Next'))}}
|
||||
{{=shortcut('Shift-Ctrl-G / Shift-Cmd-G', T('Find Previous'))}}
|
||||
{{=shortcut('Shift-Ctrl-F / Cmd-Option-F', T('Replace'))}}
|
||||
{{=shortcut('Shift-Ctrl-R / Shift-Cmd-Option-F', T('Replace All'))}}
|
||||
</ul>
|
||||
{{else:}}
|
||||
<h3>{{=T("Key bindings")}}</h3>
|
||||
<ul>
|
||||
{{=shortcut('Ctrl+S', T('Save via Ajax'))}}
|
||||
</ul>
|
||||
{{pass}}
|
||||
<div class="row-fluid">
|
||||
<div class="help span4 alert alert-block alert-info">
|
||||
{{if TEXT_EDITOR=='edit_area' and filetype=='html':}}
|
||||
<h3>{{=T('Key bindings for ZenCoding Plugin')}}</h3>
|
||||
<ul class="keybindings unstyled">
|
||||
{{=shortcut('Ctrl+S', T('Save via Ajax'))}}
|
||||
{{=shortcut('Ctrl+,', T('Expand Abbreviation'))}}
|
||||
{{=shortcut('Ctrl+M', T('Match Pair'))}}
|
||||
{{=shortcut('Ctrl+H', T('Wrap with Abbreviation'))}}
|
||||
{{=shortcut('Shift+Ctrl+M', T('Merge Lines'))}}
|
||||
{{=shortcut('Ctrl+Shift+←', T('Previous Edit Point'))}}
|
||||
{{=shortcut('Ctrl+Shift+→', T('Next Edit Point'))}}
|
||||
{{=shortcut('Ctrl+Shift+↑', T('Go to Matching Pair'))}}
|
||||
</ul>
|
||||
{{elif TEXT_EDITOR == 'codemirror' and filetype=='html':}}
|
||||
<h3>{{=T('Key bindings for ZenCoding Plugin')}}</h3>
|
||||
<ul class="keybindings unstyled">
|
||||
{{=shortcut('Ctrl+S', T('Save via Ajax'))}}
|
||||
{{=shortcut('Ctrl+F11', T('Toggle Fullscreen'))}}
|
||||
{{=shortcut('Ctrl-F / Cmd-F', T('Start searching'))}}
|
||||
{{=shortcut('Ctrl-G / Cmd-G', T('Find Next'))}}
|
||||
{{=shortcut('Shift-Ctrl-G / Shift-Cmd-G', T('Find Previous'))}}
|
||||
{{=shortcut('Shift-Ctrl-F / Cmd-Option-F', T('Replace'))}}
|
||||
{{=shortcut('Shift-Ctrl-R / Shift-Cmd-Option-F', T('Replace All'))}}
|
||||
{{=shortcut('Tab', T('Expand Abbreviation'))}}
|
||||
</ul>
|
||||
{{elif TEXT_EDITOR == 'codemirror':}}
|
||||
<h3>{{=T("Key bindings")}}</h3>
|
||||
<ul class="keybindings unstyled">
|
||||
{{=shortcut('Ctrl+S', T('Save via Ajax'))}}
|
||||
{{=shortcut('Ctrl+F11', T('Toggle Fullscreen'))}}
|
||||
{{=shortcut('Ctrl-F / Cmd-F', T('Start searching'))}}
|
||||
{{=shortcut('Ctrl-G / Cmd-G', T('Find Next'))}}
|
||||
{{=shortcut('Shift-Ctrl-G / Shift-Cmd-G', T('Find Previous'))}}
|
||||
{{=shortcut('Shift-Ctrl-F / Cmd-Option-F', T('Replace'))}}
|
||||
{{=shortcut('Shift-Ctrl-R / Shift-Cmd-Option-F', T('Replace All'))}}
|
||||
</ul>
|
||||
{{else:}}
|
||||
<h3>{{=T("Key bindings")}}</h3>
|
||||
<ul class="keybindings unstyled">
|
||||
{{=shortcut('Ctrl+S', T('Save via Ajax'))}}
|
||||
</ul>
|
||||
{{pass}}
|
||||
</div>
|
||||
</div>
|
||||
<!-- end "edit" block -->
|
||||
@@ -7,18 +7,19 @@ function delkey(id) {
|
||||
return false;
|
||||
}
|
||||
function hideShowTranslated(){
|
||||
jQuery(".translated").closest("p").toggle();
|
||||
jQuery(".translated").closest("div.row-fluid").toggle();
|
||||
}
|
||||
</script>
|
||||
|
||||
{{block sectionclass}}edit_language{{end}}
|
||||
|
||||
<!-- begin "edit_language" block -->
|
||||
<h2>{{=T('Editing Language file')}} "{{=filename}}"</h2>
|
||||
<a class="button" href="#" onclick="hideShowTranslated(this);">
|
||||
<div class="controls">
|
||||
<a class="button btn" href="#" onclick="hideShowTranslated(this);">
|
||||
<span>{{=T('Hide/Show Translated strings')}}</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="languageform">
|
||||
{{=form}}
|
||||
</div>
|
||||
|
||||
|
||||
<!-- end "edit_language" block -->
|
||||
@@ -6,11 +6,10 @@ function delkey(id) {
|
||||
return false;
|
||||
}
|
||||
</script>
|
||||
|
||||
{{block sectionclass}}edit_language{{end}}
|
||||
|
||||
<!-- begin "edit_language(plurals)" block -->
|
||||
<h2>{{=T("Editing Plural Forms File")}} "{{=filename}}"</h2>
|
||||
<div class="pluralsform">
|
||||
{{=form}}
|
||||
</div>
|
||||
|
||||
<!-- end "edit_language(plurals)" block -->
|
||||
@@ -1,142 +1,124 @@
|
||||
{{extend 'layout.html'}}
|
||||
{{import os, stat, time}}
|
||||
|
||||
{{block sectionclass}}errors{{end}}
|
||||
|
||||
<style>
|
||||
table.sortable {
|
||||
border-spacing:0px;
|
||||
}
|
||||
table.sortable td, table.sortable th {
|
||||
padding: 2px 5px 2px 5px;
|
||||
}
|
||||
table.sortable thead {
|
||||
background-color:#eee;
|
||||
color:#666666;
|
||||
font-weight: bold;
|
||||
cursor: default;
|
||||
}
|
||||
tr.error_ticket:hover {
|
||||
background-color: #eee;
|
||||
}
|
||||
.controls a.button.unavailable {
|
||||
color: #ff0000;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script language="JavaScript">
|
||||
function check(){
|
||||
for (var i = 0; i < document.myform.elements.length; i++) {
|
||||
var e = document.myform.elements[i];
|
||||
if (e.type == 'checkbox') e.checked = true;
|
||||
}
|
||||
}
|
||||
function uncheck(){
|
||||
for (var i = 0; i < document.myform.elements.length; i++) {
|
||||
var e = document.myform.elements[i];
|
||||
if (e.type == 'checkbox') e.checked = false;
|
||||
}
|
||||
}
|
||||
jQuery(document).ready(function() { jQuery('.traceback').hide(); });
|
||||
</script>
|
||||
<!-- begin "errors" block -->
|
||||
{{if db_ready['status'] == False:
|
||||
switchbutton = A(SPAN("switch to : db"), _href=db_ready['errlink'], _class="button unavailable", _title="%s" % (db_ready['errmessage']))
|
||||
switchbutton = A(SPAN("switch to : db"), _href=db_ready['errlink'], _class="button unavailable btn btn-danger", _title="%s" % (db_ready['errmessage']))
|
||||
else:
|
||||
switchbutton = A(SPAN("switch to : db"), _href=URL(args=[app, 'dbnew']), _class="button")
|
||||
switchbutton = A(SPAN("switch to : db"), _href=URL(args=[app, 'dbnew']), _class="button btn")
|
||||
pass}}
|
||||
|
||||
<h2>{{=T('Error logs for "%(app)s"',dict(app=app))}}</h2>
|
||||
|
||||
<div class="errorform">
|
||||
<form name="myform" method="post">
|
||||
<input name="CheckAll" value="{{=T('check all')}}"
|
||||
onclick="check()" type="button">
|
||||
<input name="CheckAll" value="{{=T('uncheck all')}}"
|
||||
onclick="uncheck()" type="button">
|
||||
<input value="{{=T('delete all checked')}}" type="submit"><br><br>
|
||||
|
||||
{{ if 'new' in method: }}
|
||||
{{base_url = 'db' in method and 'ticketdb' or 'ticket' }}
|
||||
<h3>{{=T('Click row to expand traceback')}}</h3>
|
||||
<p class="controls">
|
||||
{{if 'db' in method:}}
|
||||
source : db
|
||||
<a class="button" href="{{=URL(args=[app, 'new'])}}"><span>switch to : filesystem</span></a>
|
||||
<a class="button" href="{{=URL(args=[app, 'dbold'])}}"><span>lists by ticket</span></a>
|
||||
{{else:}}
|
||||
source : filesystem
|
||||
{{=switchbutton}}
|
||||
<a class="button" href="{{=URL(args=[app, 'old'])}}"><span>lists by ticket</span></a>
|
||||
{{pass}}
|
||||
</p>
|
||||
<table id="trck_errors" class="sortable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{=T("Delete")}}</th>
|
||||
<th>{{=T("Count")}}</th>
|
||||
<th>{{=T("File")}}</th>
|
||||
<th>{{=T("Error")}}</th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{for e in errors:}}
|
||||
<tr class="error_ticket">
|
||||
<td><input type="checkbox" name="delete_{{=e['hash']}}" /></td>
|
||||
<td>{{=e['count']}}</td>
|
||||
<td>{{=e['causer']}}</td>
|
||||
<td>{{=A(e['last_line'],_href="#",_onclick="collapse('%s');"%e['hash'])}}</td>
|
||||
<td>+</td>
|
||||
<td>{{=A(T('details'),_href=URL(base_url,args=[app,e['ticket']]))}}</td>
|
||||
</tr>
|
||||
<tr id="{{=e['hash']}}" class="traceback">
|
||||
<td colspan="6">
|
||||
<div>
|
||||
{{=CODE(e['pickel']['traceback'])}}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{pass}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{ else: }}
|
||||
<h3>{{=T('Click row to view a ticket')}}</h3>
|
||||
<p class="controls">
|
||||
{{if 'db' in method:}}
|
||||
source : db
|
||||
<a class="button" href="{{=URL(args=[app, 'old'])}}"><span>switch to : filesystem</span></a>
|
||||
<a class="button" href="{{=URL(args=[app, 'dbnew'])}}"><span>lists by exception</span></a>
|
||||
{{else:}}
|
||||
source : filesystem
|
||||
{{=switchbutton}}
|
||||
<a class="button" href="{{=URL(args=[app, 'new'])}}"><span>lists by exception</span></a>
|
||||
{{pass}}
|
||||
</p>
|
||||
<table class="sortable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{=T("Delete")}}</th>
|
||||
<th>{{=T("Ticket")}}</th>
|
||||
<th>{{=T("Date and Time")}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{for ticket in tickets:}}
|
||||
<tr>
|
||||
<td><input type="checkbox" name="delete_{{=ticket}}"/></td>
|
||||
{{if 'db' in method:}}
|
||||
<td><a href="{{=URL('ticketdb',args=[app,ticket])}}">{{=ticket}}</a></td>
|
||||
<td>{{=time.strftime('%Y-%m-%d %H:%M:%S',times[ticket].timetuple())}}</td>
|
||||
{{else:}}
|
||||
<td><a href="{{=URL('ticket',args=[app,ticket])}}">{{=ticket}}</a></td>
|
||||
<td>{{=time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(os.stat(os.path.join(request.folder,'../%s/errors/%s' % (app,ticket)))[stat.ST_CTIME]))}}</td>
|
||||
{{pass}}
|
||||
</tr>
|
||||
{{pass}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{ pass }}
|
||||
</form>
|
||||
<form name="myform" method="post">
|
||||
{{ if 'new' in method: }}
|
||||
{{base_url = 'db' in method and 'ticketdb' or 'ticket' }}
|
||||
<p class="controls row-fluid">
|
||||
<div class="controls controls-row">
|
||||
{{if 'db' in method:}}
|
||||
<span class="uneditable-input">source : db</span>
|
||||
<a class="button btn" href="{{=URL(args=[app, 'new'])}}"><span>switch to : filesystem</span></a>
|
||||
<a class="button btn" href="{{=URL(args=[app, 'dbold'])}}"><span>lists by ticket</span></a>
|
||||
{{else:}}
|
||||
<span class="uneditable-input">source : filesystem</span>
|
||||
{{=switchbutton}}
|
||||
<a class="button btn" href="{{=URL(args=[app, 'old'])}}"><span>lists by ticket</span></a>
|
||||
{{pass}}
|
||||
</div>
|
||||
</p>
|
||||
<div class="tablebar">
|
||||
<input value="{{=T('delete all checked')}}" type="submit" class="btn"/>
|
||||
<span class="help label label-info">{{=T('Click row to expand traceback')}}</span>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span6">
|
||||
<table id="trck_errors" class="sortable table table-hover table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="column1 cbcentered"><input type="checkbox" name="delete_all}" /></th>
|
||||
<th class="column2">{{=T("Count")}}</th>
|
||||
<th class="column3">{{=T("File")}}</th>
|
||||
<th>{{=T("Error")}}</th>
|
||||
<th class="columnN"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{for e in errors:}}
|
||||
<tr class="error_ticket">
|
||||
<td class="cbcentered"><input type="checkbox" name="delete_{{=e['hash']}}" /></td>
|
||||
<td>{{=e['count']}}</td>
|
||||
<td>{{=e['causer']}}</td>
|
||||
<td>{{=A(e['last_line'],_href="#",_onclick="collapse('%s');return false;"%e['hash'])}}</td>
|
||||
<td>+ {{=A(T('details'),_href=URL(base_url,args=[app,e['ticket']]))}}</td>
|
||||
</tr>
|
||||
<tr id="{{=e['hash']}}" class="traceback">
|
||||
<td colspan="5">
|
||||
<div class="ticket_code">
|
||||
{{=CODE(e['pickel']['traceback'])}}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{pass}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{{ else: }}
|
||||
<p class="controls row-fluid">
|
||||
<div class="controls controls-row">
|
||||
{{if 'db' in method:}}
|
||||
<span class="uneditable-input">source : db</span>
|
||||
<a class="button btn" href="{{=URL(args=[app, 'old'])}}"><span>switch to : filesystem</span></a>
|
||||
<a class="button btn" href="{{=URL(args=[app, 'dbnew'])}}"><span>lists by exception</span></a>
|
||||
{{else:}}
|
||||
<span class="uneditable-input">source : filesystem</span>
|
||||
{{=switchbutton}}
|
||||
<a class="button btn" href="{{=URL(args=[app, 'new'])}}"><span>lists by exception</span></a>
|
||||
{{pass}}
|
||||
</div>
|
||||
</p>
|
||||
<div class="tablebar">
|
||||
<input value="{{=T('delete all checked')}}" type="submit" class="btn"/>
|
||||
<span class="help label label-info">{{=T('Click row to expand traceback')}}</span>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span6">
|
||||
<table id="trck_errors" class="sortable table table-hover table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="column1 cbcentered"><input type="checkbox" name="delete_all}" /></th>
|
||||
<th>{{=T("Ticket")}}</th>
|
||||
<th class="columnN1">{{=T("Date and Time")}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{for ticket in tickets:}}
|
||||
<tr>
|
||||
<td class="cbcentered"><input type="checkbox" name="delete_{{=ticket}}"/></td>
|
||||
{{if 'db' in method:}}
|
||||
<td><a href="{{=URL('ticketdb',args=[app,ticket])}}">{{=ticket}}</a></td>
|
||||
<td>{{=time.strftime('%Y-%m-%d %H:%M:%S',times[ticket].timetuple())}}</td>
|
||||
{{else:}}
|
||||
<td><a href="{{=URL('ticket',args=[app,ticket])}}">{{=ticket}}</a></td>
|
||||
<td>{{=time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(os.stat(os.path.join(request.folder,'../%s/errors/%s' % (app,ticket)))[stat.ST_CTIME]))}}</td>
|
||||
{{pass}}
|
||||
</tr>
|
||||
{{pass}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{{ pass }}
|
||||
</form><!-- /errorform -->
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
jQuery(document).ready(function() {
|
||||
jQuery('.traceback').hide();
|
||||
jQuery("#trck_errors thead tr th:first input[type=checkbox]").click(function() {
|
||||
var checkedStatus = this.checked;
|
||||
jQuery("#trck_errors tbody tr td:first-child input[type=checkbox]").each(function() {
|
||||
this.checked = checkedStatus;
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<!-- end "errors" block -->
|
||||
@@ -1,5 +1,15 @@
|
||||
{{extend 'layout.html'}}
|
||||
|
||||
{{
|
||||
dlg = dialog
|
||||
smt_button = dlg.element(_type="submit")
|
||||
smt_button['_class'] = 'btn'
|
||||
smt_button['_style'] = 'margin-right:4px;'
|
||||
ccl_button = dlg.element(_type="button")
|
||||
ccl_button['_class'] = 'btn'
|
||||
}}
|
||||
<!-- begin "git_pull" block -->
|
||||
<div class="center">
|
||||
<h2>{{=T('This will pull changes from the remote repo for application "%s"?', app)}}</h2>
|
||||
{{=dialog}}
|
||||
</div>
|
||||
<!-- end "git_pull" block -->
|
||||
@@ -1,6 +1,15 @@
|
||||
{{extend 'layout.html'}}
|
||||
|
||||
{{
|
||||
frm = form
|
||||
smt_button = frm.element(_type="submit")
|
||||
smt_button['_class'] = 'btn'
|
||||
smt_button['_style'] = 'margin-right:4px;'
|
||||
ccl_button = frm.element(_type="button")
|
||||
ccl_button['_class'] = 'btn'
|
||||
}}
|
||||
<!-- begin "git_push" block -->
|
||||
<h2>{{=T('This will push changes to the remote repo for application "%s".', app)}}</h2>
|
||||
<center>
|
||||
{{=form}}
|
||||
</center>
|
||||
<!-- end "git_push" block -->
|
||||
@@ -1,26 +1,23 @@
|
||||
{{extend 'layout.html'}}
|
||||
<script type="text/javascript">
|
||||
jQuery(function() {
|
||||
jQuery("#password").focus();
|
||||
});
|
||||
</script>
|
||||
|
||||
{{block sectionclass}}login{{end}}
|
||||
|
||||
<!-- begin "index" block -->
|
||||
<h2>web2py™ {{=T('Web Framework')}}</h2>
|
||||
<h3>{{=T('Login to the Administrative Interface')}}</h3>
|
||||
<div class="form row-fluid">
|
||||
{{if request.is_https or request.is_local:}}
|
||||
<div class="form">
|
||||
<form action="{{=URL(r=request)}}" method="post">
|
||||
<div><input type="hidden" name="send" value="{{=send}}"/></div>
|
||||
<table>
|
||||
<tr><td>{{=T('Administrator Password:')}}</td><td><input type="password" name="password" id="password"/></td></tr>
|
||||
<tr><td></td><td><input type="submit" name="login" value="{{=T('Login')}}"/></td></tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
<form action="{{=URL(r=request)}}" method="post" class="span4 well">
|
||||
<label for="password">{{=T('Administrator Password:')}}</label>
|
||||
<input type="password" name="password" id="password"/>
|
||||
<input type="hidden" name="send" value="{{=send}}"/>
|
||||
<div class="controls"><button type="submit" name="login" class="btn">{{=T('Login')}}</button></div>
|
||||
</form>
|
||||
{{else:}}
|
||||
<p class="help">{{=T('ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.')}}</p>
|
||||
<p class="help span7 alert alert-block alert-warning">{{=T('ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.')}}</p>
|
||||
{{pass}}
|
||||
|
||||
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
jQuery(document).ready(function(){
|
||||
jQuery("#password").focus();
|
||||
});
|
||||
</script>
|
||||
<!-- end "index" block -->
|
||||
@@ -1,5 +1,163 @@
|
||||
{{extend 'layout.html'}}
|
||||
{{
|
||||
#grid['_class'] = 'web2py_grid'
|
||||
if not request.args:
|
||||
add_btn = grid.elements('div.web2py_console a.w2p_trap',replace=None)[0]
|
||||
add_btn['_id'] = 'w2p_grid_addbtn'
|
||||
add_btn['_class'] = 'w2p_trap btn'
|
||||
qry_pnl_rows = grid.elements('div',_class="w2p_query_row hidden")
|
||||
for qry_pnl_row in qry_pnl_rows:
|
||||
qry_pnl_btn1 = qry_pnl_row.elements('input',_value="New",replace=None)[0]
|
||||
qry_pnl_btn2 = qry_pnl_row.elements('input',_value="And",replace=None)[0]
|
||||
qry_pnl_btn3 = qry_pnl_row.elements('input',_value="Or",replace=None)[0]
|
||||
qry_pnl_btngrp = qry_pnl_row.elements('input',_value="Close",replace=lambda me:DIV(qry_pnl_btn1,qry_pnl_btn2,qry_pnl_btn3,me,_class="qry_pnl_btns"))
|
||||
pass
|
||||
qry_pnl = grid.elements('div#w2p_query_panel',replace=None)
|
||||
csl_frm = grid.elements('div.web2py_console form')[0]
|
||||
csl_frm['_class'] = 'form-inline'
|
||||
csl_frm_search = grid.elements('#web2py_keywords',replace=lambda me:DIV(me,TAG['button'](T('Search'),_class='btn',_type='submit'),TAG['button'](T('Clear'),_class='btn',_type='button',_onclick='jQuery("#web2py_keywords").val("");'),_class="input-append"))
|
||||
csl_frm_search_btn1 = grid.elements('input',_value="Search",replace=None)
|
||||
csl_frm_search_btn2 = grid.elements('input',_value="Clear",replace=None)
|
||||
new_console = grid.elements('div.web2py_console form',replace=lambda frm_csl:DIV(SPAN(add_btn,_class='span1'),SPAN(DIV(frm_csl,qry_pnl[0],_id='w2p_search-form'),_class='span5'),_class='row-fluid'))
|
||||
w2p_grid_tbl = grid.element('table')
|
||||
if w2p_grid_tbl:
|
||||
w2p_grid_tbl['_class'] = 'table table-condensed table-hover table-bordered'
|
||||
tbl_button_rows = grid.elements('td',_class="row_buttons")
|
||||
for tbl_button_row in tbl_button_rows:
|
||||
buttons = tbl_button_row.elements('a.w2p_trap')
|
||||
for button in buttons:
|
||||
button['_class'] = 'w2p_trap btn'
|
||||
pass
|
||||
pass
|
||||
export_menu = grid.element('div.w2p_export_menu')
|
||||
export_menu_links = export_menu.elements('a')
|
||||
export_menu_items = []
|
||||
for link in export_menu_links:
|
||||
item = LI(link)
|
||||
export_menu_items.append(item)
|
||||
pass
|
||||
new_export_menu = DIV(A(T('Exports:'),SPAN(_class='caret'),_href='#',_class='btn dropdown-toggle',**{'_data-toggle':"dropdown"}),UL(*export_menu_items,_class='dropdown-menu'),_class='w2p_export_menu btn-group pull-left')
|
||||
grid_pagination = grid.element('div.web2py_paginator')
|
||||
if grid_pagination:
|
||||
export_menu = grid.element('div.w2p_export_menu',replace=None)
|
||||
new_grid_pagination = grid.element('div.web2py_paginator',replace=lambda me:DIV(new_export_menu,me,_class='w2p_grid_bottom_bar'))
|
||||
grid_pagination['_class'] = 'web2py_paginator pagination pagination-right'
|
||||
grid_page_active = grid.element('li.current')
|
||||
grid_page_active['_class'] = 'current active'
|
||||
else:
|
||||
new_grid_pagination = grid.element('div.w2p_export_menu',replace=DIV(new_export_menu))
|
||||
pass
|
||||
records_counter = grid.element('div.web2py_counter')
|
||||
records_found = int(records_counter[0].partition('records')[0].strip())
|
||||
paginate = 5 # TODO: get it from the controller
|
||||
pages = records_found/paginate
|
||||
tot_pages = pages if records_found%paginate == 0 else pages+1
|
||||
current_page = int(request.vars.page) if request.vars.page else 1
|
||||
end_record = paginate*current_page if current_page < tot_pages else records_found
|
||||
begin_record = 1 if current_page == 1 else (paginate*(current_page-1))+1
|
||||
rec = "records" if records_found>1 else "record"
|
||||
record_shown_in_the_page = T("Showing %s to %s of %s %s found")%(begin_record,end_record,records_found,rec)
|
||||
new_record_counter = grid.element('div.web2py_counter',replace=DIV(record_shown_in_the_page,_class="web2py_counter span6 pull-right"))
|
||||
pass
|
||||
elif request.args(0)=='new':
|
||||
bck_btn = grid.element('div.web2py_grid span.leftarrow').parent
|
||||
bck_btn['_id'] = 'w2p_grid_bckbtn'
|
||||
bck_btn['_class'] = 'w2p_trap btn'
|
||||
frm = grid.element('div.web2py_grid form')
|
||||
frm['_class'] = 'web2py_form span4 well well-small'
|
||||
|
||||
checkbox_lbl = frm.element('label',_for='auth_user_is_manager')
|
||||
checkbox_inp = frm.element(_name='is_manager',replace=CAT())
|
||||
checkbox_lbl[0] = checkbox_inp
|
||||
checkbox_lbl[1] = 'Is Manager'
|
||||
checkbox_lbl['_class'] = "checkbox"
|
||||
|
||||
inp_smt = frm.element('input',_type='submit',replace=TAG['button'](T('Submit'),_type='submit',_class='btn'))
|
||||
|
||||
new_form_flds = []
|
||||
frm_trs = frm.elements('tr')
|
||||
for tr in frm_trs:
|
||||
label = tr[0][0]
|
||||
input = tr[1][0]
|
||||
help = tr[2][0]
|
||||
new_form_flds.append(label)
|
||||
new_form_flds.append(input)
|
||||
new_form_flds.append(help)
|
||||
pass
|
||||
new_frm_content = frm.element('table',replace=CAT(*new_form_flds))
|
||||
new_frm = grid.element('div.web2py_grid form',replace=lambda me:DIV(me,_class='row-fluid'))
|
||||
elif request.args(0)=='view':
|
||||
bck_btn = grid.element('div.web2py_grid span.leftarrow').parent
|
||||
bck_btn['_id'] = 'w2p_grid_bckbtn'
|
||||
bck_btn['_class'] = 'w2p_trap btn'
|
||||
pen_btn = grid.element('div.web2py_grid span.pen').parent
|
||||
pen_btn['_id'] = 'w2p_grid_penbtn'
|
||||
pen_btn['_class'] = 'w2p_trap btn'
|
||||
frm = grid.element('div.web2py_grid form')
|
||||
frm['_class'] = 'web2py_form span4 well well-small'
|
||||
|
||||
checkbox_lbl = frm.element('label',_for='auth_user_is_manager')
|
||||
checkbox_inp = frm.element(_name='is_manager',replace=CAT())
|
||||
checkbox_lbl[0] = checkbox_inp
|
||||
checkbox_lbl[1] = 'Is Manager'
|
||||
checkbox_lbl['_class'] = "checkbox"
|
||||
|
||||
new_form_flds = []
|
||||
frm_trs = frm.elements('tr')
|
||||
for tr in frm_trs:
|
||||
label = tr[0][0]
|
||||
input = tr[1][0]
|
||||
help = tr[2][0]
|
||||
new_form_flds.append(label)
|
||||
if len(input) > 0 :
|
||||
new_form_flds.append(SPAN(input,_class='uneditable-input'))
|
||||
pass
|
||||
new_form_flds.append(help)
|
||||
pass
|
||||
new_frm_content = frm.element('table',replace=CAT(*new_form_flds))
|
||||
new_frm = grid.element('div.web2py_grid form',replace=lambda me:DIV(me,_class='row-fluid'))
|
||||
elif request.args(0)=='edit':
|
||||
bck_btn = grid.element('div.web2py_grid span.leftarrow').parent
|
||||
bck_btn['_id'] = 'w2p_grid_bckbtn'
|
||||
bck_btn['_class'] = 'w2p_trap btn'
|
||||
viw_btn = grid.element('div.web2py_grid span.magnifier').parent
|
||||
viw_btn['_id'] = 'w2p_grid_viwbtn'
|
||||
viw_btn['_class'] = 'w2p_trap btn'
|
||||
frm = grid.element('div.web2py_grid form')
|
||||
frm['_class'] = 'web2py_form span4 well well-small'
|
||||
|
||||
checkbox_lbl = frm.element('label',_for='auth_user_is_manager')
|
||||
checkbox_inp = frm.element(_name='is_manager',replace=CAT())
|
||||
checkbox_lbl[0] = checkbox_inp
|
||||
checkbox_lbl[1] = 'Is Manager'
|
||||
checkbox_lbl['_class'] = "checkbox"
|
||||
|
||||
checkbox1_lbl = frm.element('label',_for='delete_record')
|
||||
checkbox1_inp = frm.element(_id='delete_record',replace=CAT())
|
||||
checkbox1_lbl[0] = checkbox1_inp
|
||||
checkbox1_lbl[1] = T('Check to delete')
|
||||
checkbox1_lbl['_class'] = "checkbox"
|
||||
|
||||
inp_smt = frm.element('input',_type='submit',replace=TAG['button'](T('Submit'),_type='submit',_class='btn'))
|
||||
|
||||
id_input = frm.element(_id='auth_user_id')
|
||||
id_input['_class'] = 'uneditable-input'
|
||||
|
||||
new_form_flds = []
|
||||
frm_trs = frm.elements('tr')
|
||||
for tr in frm_trs:
|
||||
label = tr[0][0]
|
||||
input = tr[1][0]
|
||||
help = tr[2][0]
|
||||
new_form_flds.append(label)
|
||||
print label
|
||||
new_form_flds.append(input)
|
||||
new_form_flds.append(help)
|
||||
pass
|
||||
new_frm_content = frm.element('table',replace=CAT(*new_form_flds))
|
||||
new_frm = grid.element('div.web2py_grid form',replace=lambda me:DIV(me,_class='row-fluid'))
|
||||
pass
|
||||
}}
|
||||
|
||||
<h1>{{=T('Manage Admin Users/Students')}}</h1>
|
||||
|
||||
{{=grid}}
|
||||
<h2>{{=T('Manage Admin Users/Students')}}</h2>
|
||||
{{=grid}}
|
||||
@@ -1,17 +1,16 @@
|
||||
{{extend 'layout.html'}}
|
||||
|
||||
{{block sectionclass}}peek{{end}}
|
||||
|
||||
<!-- begin "peek" block -->
|
||||
<h2>{{=T("Peeking at file")}} "{{=filename}}"</h2>
|
||||
|
||||
<p class="controls">
|
||||
{{=button(URL('design',args=request.vars.app if request.vars.app else request.args[0], anchor=request.vars.id), T('back'))}}
|
||||
{{=button(URL('edit',args=request.args, vars=request.vars), T('Edit'))}}
|
||||
</p>
|
||||
|
||||
<div class="code-wrapper">
|
||||
{{
|
||||
if filename[-3:]=='.py': language='python'
|
||||
else: language='html'
|
||||
}}
|
||||
{{=CODE(data,language=language,link='/examples/global/vars/')}}
|
||||
|
||||
</div>
|
||||
<!-- end "peek" block -->
|
||||
@@ -6,9 +6,15 @@ def all(items):
|
||||
def peekfile(path,file):
|
||||
return A(file.replace('\\\\','/'),_href=URL('peek', args=(app, path, file)))
|
||||
def editfile(path,file):
|
||||
return A(SPAN(T('Edit')),_class='button editbutton',_href=URL('edit', args=(app, path, file)))
|
||||
return A(SPAN(T('Edit')),_class='button editbutton btn',_href=URL('edit', args=(app, path, file)))
|
||||
def testfile(path,file):
|
||||
return A(TAG[''](IMG(_src=URL('static', 'images/test_icon.png'), _alt=T('test')), SPAN(T("Run tests in this file"))), _class='icon test tooltip',_href=URL('test', args=(app, file)))
|
||||
return A(TAG[''](IMG(_src=URL('static', 'images/test_icon.png'), _alt=T('test')),
|
||||
SPAN(T("Run tests in this file"))),
|
||||
_class='icon test',
|
||||
_href=URL('test', args=(app, file)),
|
||||
_rel="tooltip",
|
||||
**{'_data-placement':'right',
|
||||
'_data-original-title':T("Run tests in this file")})
|
||||
def editlanguagefile(path,file):
|
||||
return A(SPAN(T('Edit')),_class='button editbutton',_href=URL('edit_language', args=(app, path, file)))
|
||||
def file_upload_form(location):
|
||||
@@ -29,57 +35,62 @@ def file_create_form(location):
|
||||
INPUT(_type="submit",_value=T("submit")),_action=URL('create_file'))
|
||||
return form
|
||||
def deletefile(arglist):
|
||||
return A(TAG[''](IMG(_src=URL('static', 'images/delete_icon.png')), SPAN(T('Delete this file (you will be asked to confirm deletion)'))), _class='icon delete tooltip', _href=URL('delete',args=arglist,vars=dict(sender=request.function+'/'+app+'/'+request.args[1])))
|
||||
return A(TAG[''](IMG(_src=URL('static', 'images/delete_icon.png')),
|
||||
SPAN(T('Delete this file (you will be asked to confirm deletion)'))),
|
||||
_href=URL('delete',args=arglist,vars=dict(sender=request.function+'/'+app+'/'+request.args[1])),
|
||||
_class='icon delete',
|
||||
_rel="tooltip",
|
||||
**{'_data-placement':'right',
|
||||
'_data-original-title':T('Delete this file (you will be asked to confirm deletion)')})
|
||||
}}
|
||||
|
||||
{{block sectionclass}}plugin{{end}}
|
||||
<!-- begin "plugin" block -->
|
||||
<h2>{{=T('Plugin "%s" in application', request.args(1))}} "{{=app}}"</h2>
|
||||
|
||||
<h2>
|
||||
{{=T('Plugin "%s" in application', request.args(1))}} "{{=app}}"
|
||||
</h2>
|
||||
<!-- COLLAPSE/JUMP-TO BUTTONS -->
|
||||
<div class="right-full controls">
|
||||
<a class="button special" href="#" onclick="jQuery('h3').click();return false"><span>{{=T("collapse/expand all")}}</span></a>
|
||||
<span class="buttongroup">
|
||||
{{=button("#models", T("models"))}}
|
||||
{{=button("#controllers", T("controllers"))}}
|
||||
{{=button("#views", T("views"))}}
|
||||
{{=button("#static", T("static"))}}
|
||||
{{=button("#modules", T("modules"))}}
|
||||
</span>
|
||||
<span class="buttongroup">
|
||||
{{=sp_button(URL('design',args=request.args, anchor=request.vars.id), T("back"))}}
|
||||
{{=sp_button(URL('delete_plugin',args=request.args, vars=request.vars), T("delete plugin"))}}
|
||||
{{=sp_button(URL('pack_plugin',args=request.args), T("pack plugin"))}}
|
||||
</span>
|
||||
<p class="buttons-row">
|
||||
<a class="button special btn btn-inverse" href="#" onclick="jQuery('h3>span').click();return false"><span>{{=T("collapse/expand all")}}</span></a>
|
||||
<span class="buttongroup">
|
||||
{{=button('#models', T("models"))}}
|
||||
{{=button('#controllers', T("controllers"))}}
|
||||
{{=button('#views', T("views"))}}
|
||||
{{=button('#static', T("static"))}}
|
||||
{{=button('#modules', T("modules"))}}
|
||||
</span>
|
||||
<span class="buttongroup">
|
||||
{{=sp_button(URL('design',args=request.args, anchor=request.vars.id), T("back"))}}
|
||||
{{=sp_button(URL('delete_plugin',args=request.args, vars=request.vars), T("delete plugin"))}}
|
||||
{{=sp_button(URL('pack_plugin',args=request.args), T("pack plugin"))}}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- MODELS -->
|
||||
|
||||
<h3 id="models" onclick="collapse('models_inner');" class="component">
|
||||
{{=T("Models")}}
|
||||
<h3 id="_models" rel="pagebookmark">
|
||||
<span class="component" onclick="collapse('models_inner');">{{=T("Models")}}</span>
|
||||
<span id="models" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||
</h3>
|
||||
<div id="models_inner" class="component_contents">
|
||||
{{if not models:}}
|
||||
<p><strong>{{=T("There are no models")}}</strong></p>
|
||||
{{pass}}
|
||||
<div class="controls comptools">
|
||||
</div>
|
||||
<ul>
|
||||
{{for m in models:}}
|
||||
<li>
|
||||
<span class="filetools controls">
|
||||
{{=editfile('models',m)}}
|
||||
{{=deletefile([app, 'models', m])}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('models',m)}}
|
||||
</span>
|
||||
<span class="extras">
|
||||
{{if len(defines[m]):}}{{=T("defines tables")}} {{pass}}{{=XML(', '.join([B(table).xml() for table in defines[m]]))}}
|
||||
</span>
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
{{if not models:}}<p><strong>{{=T("There are no models")}}</strong></p>{{else:}}
|
||||
<ul class="unstyled act-edit">
|
||||
{{for m in models:}}
|
||||
<li>
|
||||
<span class="filetools controls">
|
||||
{{=editfile('models',m)}}
|
||||
{{=deletefile([app, 'models', m])}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('models',m)}}
|
||||
</span>
|
||||
<span class="extras">
|
||||
{{if len(defines[m]):}}{{=T("defines tables")}} {{pass}}{{=XML(', '.join([B(table).xml() for table in defines[m]]))}}
|
||||
</span>
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
{{pass}}
|
||||
</div>
|
||||
|
||||
<!-- FIND CONTROLLER FUNCTIONS -->
|
||||
@@ -89,131 +100,124 @@ for c in controllers: controller_functions+=[c[:-3]+'/%s.html'%x for x in functi
|
||||
}}
|
||||
|
||||
<!-- CONTROLLERS -->
|
||||
|
||||
<h3 id="controllers" onclick="collapse('controllers_inner');" class="component">
|
||||
{{=T("Controllers")}}
|
||||
<h3 id="_controllers" rel="pagebookmark">
|
||||
<span class="component" onclick="collapse('controllers_inner');">{{=T("Controllers")}}</span>
|
||||
<span id="controllers" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||
</h3>
|
||||
<div id="controllers_inner" class="component_contents">
|
||||
{{if not controllers:}}
|
||||
<p><strong>{{=T("There are no controllers")}}</strong></p>
|
||||
{{pass}}
|
||||
<div class="controls comptools">
|
||||
</div>
|
||||
<ul>
|
||||
{{for c in controllers:}}
|
||||
<li>
|
||||
<span class="filetools controls">
|
||||
{{=editfile('controllers',c)}}
|
||||
{{=deletefile([app,'controllers',c])}}
|
||||
{{=testfile('controllers',c)}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('controllers',c)}}
|
||||
</span>
|
||||
<span class="extras">
|
||||
{{if functions[c]:}}{{=T("exposes")}} {{pass}}{{=XML(', '.join([A(f,_href=URL(a=app,c=c[:-3],f=f)).xml() for f in functions[c]]))}}
|
||||
</span>
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
{{if not controllers:}}<p><strong>{{=T("There are no controllers")}}</strong></p>{{else:}}
|
||||
<ul class="unstyled act_edit">
|
||||
{{for c in controllers:}}
|
||||
<li>
|
||||
<span class="filetools controls">
|
||||
{{=editfile('controllers',c)}}
|
||||
{{=deletefile([app,'controllers',c])}}
|
||||
{{=testfile('controllers',c)}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('controllers',c)}}
|
||||
</span>
|
||||
<span class="extras celled">
|
||||
{{if functions[c]:}}{{=T("exposes")}} {{pass}}{{=XML(', '.join([A(f,_href=URL(a=app,c=c[:-3],f=f)).xml() for f in functions[c]]))}}
|
||||
</span>
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
{{pass}}
|
||||
</div>
|
||||
|
||||
<!-- VIEWS -->
|
||||
|
||||
<h3 id="views" onclick="collapse('views_inner');" class="component">
|
||||
{{=T("Views")}}
|
||||
<h3 id="_views" rel="pagebookmark">
|
||||
<span class="component" onclick="collapse('views_inner');">{{=T("Views")}}</span>
|
||||
<span id="views" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||
</h3>
|
||||
<div id="views_inner" class="component_contents">
|
||||
{{if not views:}}
|
||||
<p><strong>{{=T("There are no views")}}</strong></p>
|
||||
{{pass}}
|
||||
<div class="controls comptools">
|
||||
</div>
|
||||
<ul>
|
||||
{{for c in views:}}
|
||||
<li>
|
||||
<span class="filetools controls">
|
||||
{{=editfile('views',c)}}
|
||||
{{=deletefile([app,'views',c])}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('views',c)}}
|
||||
</span>
|
||||
<span class="extras">
|
||||
{{if extend.has_key(c):}}{{=T("extends")}} <b>{{=extend[c]}}</b> {{pass}}
|
||||
{{if include[c]:}}{{=T("includes")}} {{pass}}{{=XML(', '.join([B(f).xml() for f in include[c]]))}}
|
||||
</span>
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
{{if not views:}}<p><strong>{{=T("There are no views")}}</strong></p>{{else:}}
|
||||
<ul class="unstyled act_edit">
|
||||
{{for c in views:}}
|
||||
<li>
|
||||
<span class="filetools controls">
|
||||
{{=editfile('views',c)}}
|
||||
{{=deletefile([app, 'views', c])}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('views',c)}}
|
||||
</span>
|
||||
<span class="extras celled">
|
||||
{{if extend.has_key(c):}}{{=T("extends")}} <b>{{=extend[c]}}</b> {{pass}}
|
||||
{{if include[c]:}}{{=T("includes")}} {{pass}}{{=XML(', '.join([B(f).xml() for f in include[c]]))}}
|
||||
</span>
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
{{pass}}
|
||||
</div>
|
||||
|
||||
<!-- STATIC -->
|
||||
|
||||
<h3 id="static" onclick="collapse('static_inner');" class="component">
|
||||
{{=T("Static files")}}
|
||||
<h3 id="_static" rel="pagebookmark">
|
||||
<span class="component" onclick="collapse('static_inner');">{{=T("Static files")}}</span>
|
||||
<span id="static" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||
</h3>
|
||||
<div id="static_inner" class="component_contents">
|
||||
{{if not statics:}}<p><strong>{{=T("There are no static files")}}</strong></p>{{pass}}
|
||||
<ul>
|
||||
{{
|
||||
path=[]
|
||||
for file in statics+['']:
|
||||
items=file.split('/')
|
||||
file_path=items[:-1]
|
||||
filename=items[-1]
|
||||
while path!=file_path:
|
||||
if len(file_path)>=len(path) and all([v==file_path[k] for k,v in enumerate(path)]):
|
||||
path.append(file_path[len(path)])
|
||||
thispath='static__'+'__'.join(path)
|
||||
}}
|
||||
<li class="folder">
|
||||
<a href="javascript:collapse('{{=thispath}}');" class="file">{{=path[-1]}}/</a>
|
||||
<ul id="{{=thispath}}" style="display: none;" class="sublist">{{
|
||||
else:
|
||||
path = path[:-1]
|
||||
}}
|
||||
</ul></li>
|
||||
{{
|
||||
pass
|
||||
pass
|
||||
if filename:
|
||||
}}<li>
|
||||
<span class="filetools controls">
|
||||
{{=editfile('static',file)}} {{=deletefile([app,'static',file])}}
|
||||
</span>
|
||||
<span class="file">
|
||||
<a href="{{=URL(a=app,c='static',f=file)}}">{{=filename}}</a>
|
||||
</span>
|
||||
</li>{{
|
||||
pass
|
||||
pass
|
||||
}}
|
||||
{{pass}}
|
||||
</ul>
|
||||
{{if not statics:}}<p><strong>{{=T("There are no static files")}}</strong></p>{{else:}}
|
||||
<ul class="unstyled act_edit">
|
||||
{{
|
||||
path=[]
|
||||
for file in statics+['']:
|
||||
items=file.split('/')
|
||||
file_path=items[:-1]
|
||||
filename=items[-1]
|
||||
while path!=file_path:
|
||||
if len(file_path)>=len(path) and all([v==file_path[k] for k,v in enumerate(path)]):
|
||||
path.append(file_path[len(path)])
|
||||
thispath='static__'+'__'.join(path)
|
||||
}}
|
||||
<li class="folder"><i> </i>
|
||||
<a href="javascript:collapse('{{=thispath}}');" class="file">{{=path[-1]}}/</a>
|
||||
<ul id="{{=thispath}}" style="display: none;" class="sublist">
|
||||
{{
|
||||
else:
|
||||
path = path[:-1]
|
||||
}}
|
||||
</ul>
|
||||
</li>
|
||||
{{
|
||||
pass
|
||||
pass
|
||||
if filename:
|
||||
}}
|
||||
<li>
|
||||
<span class="filetools controls">
|
||||
{{=editfile('static',file)}} {{=deletefile([app,'static',file])}}
|
||||
</span>
|
||||
<span class="file">
|
||||
<a href="{{=URL(a=app,c='static',f=file)}}">{{=filename}}</a>
|
||||
</span>
|
||||
</li>
|
||||
{{
|
||||
pass
|
||||
pass
|
||||
}}
|
||||
</ul>
|
||||
{{pass}}
|
||||
</div>
|
||||
|
||||
<!-- MODULES -->
|
||||
|
||||
<h3 id="modules" onclick="collapse('modules_inner');" class="component">
|
||||
{{=T("Modules")}}
|
||||
<h3 id="_modules" rel="pagebookmark">
|
||||
<span class="component" onclick="collapse('modules_inner');">{{=T("Modules")}}</span>
|
||||
<span id="modules" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||
</h3>
|
||||
<div id="modules_inner" class="component_contents">
|
||||
{{if not modules:}}
|
||||
<p><strong>{{=T("There are no modules")}}</strong></p>
|
||||
{{pass}}
|
||||
<div class="controls comptools">
|
||||
</div>
|
||||
<ul>
|
||||
{{for m in modules:}}
|
||||
<li>
|
||||
{{=editfile('modules',m)}}
|
||||
{{if m!='__init__.py':}}<a class="button" href="{{=URL('delete',args=[app,'modules',m],vars=dict(sender=request.function+'/'+app))}}">{{=T("delete")}}</a>{{pass}}
|
||||
{{=peekfile('modules',m)}}
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
{{if not modules:}}<p><strong>{{=T("There are no modules")}}</strong></p>{{else:}}
|
||||
<ul class="unstyled act_edit">
|
||||
{{for m in modules:}}
|
||||
<li>
|
||||
{{=editfile('modules',m)}}
|
||||
{{if m!='__init__.py':}}<a class="button btn" href="{{=URL('delete',args=[app,'modules',m],vars=dict(sender=request.function+'/'+app))}}">{{=T("delete")}}</a>{{pass}}
|
||||
{{=peekfile('modules',m)}}
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
{{pass}}
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- end "plugin" block -->
|
||||
@@ -1,25 +1,21 @@
|
||||
{{extend 'layout.html'}}
|
||||
|
||||
{{block sectionclass}}resolve{{end}}
|
||||
|
||||
<!-- begin "resolve" block -->
|
||||
<h2>{{=T('Resolve Conflict file')}} "{{=filename}}"</h2>
|
||||
|
||||
<script>
|
||||
function plus() {jQuery('.plus').show(); jQuery('.minus').hide(); }
|
||||
function minus() {jQuery('.plus').hide(); jQuery('.minus').show(); }
|
||||
function all() {jQuery('.plus').show(); jQuery('.minus').show(); }
|
||||
</script>
|
||||
|
||||
<div class="controls">
|
||||
<button onclick="plus()">new</button>
|
||||
<button onclick="minus()">old</button>
|
||||
<button onclick="all()">all</button>
|
||||
<button class="btn" onclick="plus()">new</button>
|
||||
<button class="btn" onclick="minus()">old</button>
|
||||
<button class="btn" onclick="all()">all</button>
|
||||
</div>
|
||||
|
||||
<div class="form">
|
||||
<form action="{{=URL(r=request,args=request.args)}}" method="post">
|
||||
{{=diff}}
|
||||
<input type="submit" name="merge" value="{{=T('merge')}}" /><br/>
|
||||
<input class="btn" type="submit" name="merge" value="{{=T('merge')}}" /><br/>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- end "resolve" block -->
|
||||
@@ -1,158 +1,145 @@
|
||||
{{extend 'layout.html'}}
|
||||
{{import os, glob}}
|
||||
|
||||
{{block sectionclass}}site{{end}}
|
||||
|
||||
<div class="applist f60">
|
||||
<div class="applist_inner">
|
||||
<h2>{{=T("Installed applications")}}</h2>
|
||||
<ul>
|
||||
{{for a in apps:}}
|
||||
<li class="application"> <!-- onmouseover="jQuery(this).children('p').show()" onmouseout="jQuery(this).children('p').hide()"-->
|
||||
{{if a==request.application:}}
|
||||
<h3 class="currentapp">{{=a}} ({{=T('currently running')}})</h3>
|
||||
<p class="controls">
|
||||
{{else:}}
|
||||
<h3 class="editableapp">{{=A(a,_href=URL(a,'default','index'))}}</h3>
|
||||
{{if MULTI_USER_MODE and db.app(name=a):}}(created by {{="%(first_name)s %(last_name)s" % db.auth_user[db.app(name=a).owner]}}){{pass}}
|
||||
<p class="controls">
|
||||
{{if not os.path.exists('applications/%s/compiled' % a):}}
|
||||
{{=sp_button(URL('design',args=a), T("Edit"))}}
|
||||
{{else:}}
|
||||
{{=button(URL(a,'appadmin','index'), T("appadmin"))}}
|
||||
{{pass}}
|
||||
{{=button(URL('about',args=a), T("About"))}}
|
||||
{{pass}}
|
||||
{{=button(URL('errors',args=a), T("Errors"))}}
|
||||
{{=button(URL('cleanup',args=a), T("Clean"))}}
|
||||
{{=button(URL('pack',args=a), T("Pack all"))}}
|
||||
{{if not os.path.exists('applications/%s/compiled' % a):}}
|
||||
{{=button(URL('compile_app',args=a), T("Compile"))}}
|
||||
{{else:}}
|
||||
{{=button(URL('pack',args=(a, 'compiled')), T("Pack compiled"))}}
|
||||
{{if glob.glob('applications/%s/controllers/*.py' % a):}}
|
||||
{{=button(URL('remove_compiled_app',args=a), T("Remove compiled"))}}
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
{{if os.path.exists(os.path.join(apath(r=request),a,'.git')): }}
|
||||
{{=button(URL('git_pull',args=a), T("Git Pull"))}}
|
||||
{{=button(URL('git_push',args=a), T("Git Push"))}}
|
||||
{{pass}}
|
||||
{{if a!=request.application:}}
|
||||
{{=button(URL('uninstall',args=a), T("Uninstall"))}}
|
||||
{{=button_enable(URL('enable',args=a), a)}}
|
||||
{{pass}}
|
||||
</p>
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sidebar fl60">
|
||||
<div class="sidebar_inner controls">
|
||||
<div class="pwdchange">
|
||||
<!-- CHANGE ADMIN PWD -->
|
||||
{{if MULTI_USER_MODE:}}
|
||||
{{=auth.navbar()}}
|
||||
{{else:}}
|
||||
{{=sp_button(URL('change_password'), T('Change admin password'))}}
|
||||
{{pass}}
|
||||
</div>
|
||||
<!-- VERSION -->
|
||||
{{if is_manager():}}
|
||||
<div class="box">
|
||||
<h3>{{=T("Version %s.%s.%s %s (%s)", myversion)}}</h3>
|
||||
{{if session.check_version:}}
|
||||
<p id="check_version">
|
||||
{{=T('Checking for upgrades...')}}
|
||||
<script>ajax('{{=URL('check_version')}}',[],'check_version');</script>{{session.check_version=False}}
|
||||
{{else:}}
|
||||
<p id="check_version">
|
||||
{{=button("javascript:ajax('"+URL('check_version')+"',[],'check_version')", T('Check for upgrades'))}}
|
||||
{{=button(URL('default','reload_routes'), T('Reload routes'))}}
|
||||
</p>
|
||||
{{pass}}
|
||||
<p>
|
||||
{{=T("Running on %s", request.env.server_software)}}
|
||||
</p>
|
||||
{{if session.is_mobile=='auto':}}<p>
|
||||
{{=A(T('Try the mobile interface'),_href=URL('plugin_jqmobile','about'))}}</p>
|
||||
{{pass}}
|
||||
</div>
|
||||
{{pass}}
|
||||
<!-- MULTI_USER_INTERFACE -->
|
||||
{{if MULTI_USER_MODE and is_manager():}}
|
||||
<div class="box">
|
||||
<h3>{{=T("Multi User Mode")}}</h3>
|
||||
<p>
|
||||
{{=button(URL('bulk_register'),T('Bulk Register'))}}
|
||||
{{=button(URL('manage_students'),T('Manage Students'))}}
|
||||
</p>
|
||||
</div>
|
||||
{{pass}}
|
||||
<!-- APP WIZARD -->
|
||||
<div class="box">
|
||||
<h3>{{=T("New application wizard")}}</h3>
|
||||
<p>{{=button(URL('wizard','index'), T('Start wizard'))}}
|
||||
{{=T("(requires internet access)")}}</p>
|
||||
</div>
|
||||
<!-- SCAFFOLD APP -->
|
||||
<div class="box">
|
||||
<h3>{{=T("New simple application")}}</h3>
|
||||
{{=form_create.custom.begin}}
|
||||
<table><tr><td>
|
||||
{{=LABEL(T("Application name:"))}}
|
||||
</td><td>
|
||||
{{=form_create.custom.widget.name}}
|
||||
</td><td>
|
||||
<button type="submit">{{=T('Create')}}</button>
|
||||
</td></tr></table>
|
||||
{{=form_create.custom.end}}
|
||||
</div>
|
||||
<!-- UPLOAD PACKAGE -->
|
||||
<div class="box">
|
||||
<h3>{{=T("Upload and install packed application")}}</h3>
|
||||
{{=form_update.custom.begin}}
|
||||
<table><tr><td>
|
||||
{{=LABEL(T("Application name:"))}}
|
||||
</td><td>
|
||||
{{=form_update.custom.widget.name}}
|
||||
</td></tr><tr><td>
|
||||
{{=LABEL(T("Upload a package:"))}}
|
||||
</td><td>
|
||||
{{=form_update.custom.widget.file}}
|
||||
</td></tr><tr><td>
|
||||
{{=LABEL('Or ',T("Get from URL:"))}}
|
||||
</td><td>
|
||||
{{=form_update.custom.widget.url}}
|
||||
</td></tr><tr><td>
|
||||
({{=T('can be a git repo')}})
|
||||
</td><td>
|
||||
{{=form_update.custom.widget.overwrite}}
|
||||
{{=LABEL(T("Overwrite installed app"))}}
|
||||
</td></tr><tr><td>
|
||||
</td><td>
|
||||
<button type="submit">{{=T('Install')}}</button>
|
||||
</td></tr></table>
|
||||
{{=form_update.custom.end}}
|
||||
</div>
|
||||
<!-- DEPLOY ON GAE -->
|
||||
<div class="box">
|
||||
<h3>{{=T("Deploy")}}</h3>
|
||||
<p>
|
||||
{{=button(URL('gae','deploy'), T('Deploy on Google App Engine'))}}
|
||||
{{=button(URL('openshift','deploy'),T('Deploy to OpenShift'))}}
|
||||
</p>
|
||||
</div><br/>
|
||||
{{if TWITTER_HASH:}}
|
||||
<div class="box">
|
||||
<h3>{{=T("%s Recent Tweets"%TWITTER_HASH)}}</h3>
|
||||
<div id="tweets">{{=T('loading...')}}</div>
|
||||
<script>
|
||||
jQuery(document).ready(function(){jQuery('#tweets').load('{{=URL('twitter.load')}}');});
|
||||
</script>
|
||||
</div>
|
||||
{{pass}}
|
||||
</div>
|
||||
</div>
|
||||
<!-- begin "site" block -->
|
||||
<div class="row-fluid">
|
||||
<div class="applist f60 span7">
|
||||
<div class="applist_inner">
|
||||
<h2>{{=T("Installed applications")}}</h2>
|
||||
<ul class="unstyled">
|
||||
{{for a in apps:}}
|
||||
<li class="application"> <!-- onmouseover="jQuery(this).children('p').show()" onmouseout="jQuery(this).children('p').hide()"-->
|
||||
{{if a==request.application:}}
|
||||
<h3 class="currentapp muted">{{=a}} ({{=T('currently running')}})</h3>
|
||||
<p class="controls row-buttons">
|
||||
{{else:}}
|
||||
<h3 class="editableapp muted">{{=A(a,_href=URL(a,'default','index'))}}</h3>
|
||||
{{if MULTI_USER_MODE and db.app(name=a):}}(created by {{="%(first_name)s %(last_name)s" % db.auth_user[db.app(name=a).owner]}}){{pass}}
|
||||
<p class="controls row-buttons">
|
||||
{{if not os.path.exists('applications/%s/compiled' % a):}}
|
||||
{{=sp_button(URL('design',args=a), T("Edit"))}}
|
||||
{{else:}}
|
||||
{{=button(URL(a,'appadmin','index'), T("appadmin"))}}
|
||||
{{pass}}
|
||||
{{=button(URL('about',args=a), T("About"))}}
|
||||
{{pass}}
|
||||
{{=button(URL('errors',args=a), T("Errors"))}}
|
||||
{{=button(URL('cleanup',args=a), T("Clean"))}}
|
||||
{{=button(URL('pack',args=a), T("Pack all"))}}
|
||||
{{if not os.path.exists('applications/%s/compiled' % a):}}
|
||||
{{=button(URL('compile_app',args=a), T("Compile"))}}
|
||||
{{else:}}
|
||||
{{=button(URL('pack',args=(a, 'compiled')), T("Pack compiled"))}}
|
||||
{{if glob.glob('applications/%s/controllers/*.py' % a):}}
|
||||
{{=button(URL('remove_compiled_app',args=a), T("Remove compiled"))}}
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
{{if os.path.exists(os.path.join(apath(r=request),a,'.git')): }}
|
||||
{{=button(URL('git_pull',args=a), T("Git Pull"))}}
|
||||
{{=button(URL('git_push',args=a), T("Git Push"))}}
|
||||
{{pass}}
|
||||
{{if a!=request.application:}}
|
||||
{{=button(URL('uninstall',args=a), T("Uninstall"))}}
|
||||
{{=button_enable(URL('enable',args=a), a)}}
|
||||
{{pass}}
|
||||
</p>
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
</div>
|
||||
</div> <!-- /applist -->
|
||||
<div class="sidebar fl60 span5">
|
||||
<div class="sidebar_inner controls well well-small">
|
||||
<!-- CHANGE ADMIN PWD -->
|
||||
<div class="pwdchange pull-right">
|
||||
{{if MULTI_USER_MODE:}}
|
||||
{{=auth.navbar()}}
|
||||
{{else:}}
|
||||
{{=sp_button(URL('change_password'), T('Change admin password'))}}
|
||||
{{pass}}
|
||||
</div> <!-- /CHANGE ADMIN PWD -->
|
||||
{{if is_manager():}}
|
||||
<!-- VERSION -->
|
||||
<div class="box">
|
||||
<h3>{{=T("Version %s.%s.%s %s (%s)", myversion)}}</h3>
|
||||
<p id="check_version" class="row-buttons">
|
||||
{{if session.check_version:}}
|
||||
{{=T('Checking for upgrades...')}}
|
||||
</p>
|
||||
<script>ajax('{{=URL('check_version')}}',[],'check_version');</script>
|
||||
{{session.check_version=False}}
|
||||
{{else:}}
|
||||
{{=button("javascript:ajax('"+URL('check_version')+"',[],'check_version')", T('Check for upgrades'))}}
|
||||
{{=button(URL('default','reload_routes'), T('Reload routes'))}}
|
||||
</p>
|
||||
{{pass}}
|
||||
<p>{{=T("Running on %s", request.env.server_software)}}</p>
|
||||
{{if session.is_mobile=='auto':}}
|
||||
<p>{{=A(T('Try the mobile interface'),_href=URL('plugin_jqmobile','about'))}}</p>
|
||||
{{pass}}
|
||||
</div> <!-- /VERSION -->
|
||||
{{pass}}
|
||||
{{if MULTI_USER_MODE and is_manager():}}
|
||||
<!-- MULTI_USER_INTERFACE -->
|
||||
<div class="box">
|
||||
<h3>{{=T("Multi User Mode")}}</h3>
|
||||
<p class="row-buttons">
|
||||
{{=button(URL('bulk_register'),T('Bulk Register'))}}
|
||||
{{=button(URL('manage_students',vars={'order':'auth_user.id'}),T('Manage Students'))}}
|
||||
</p>
|
||||
</div> <!-- /MULTI_USER_INTERFACE -->
|
||||
{{pass}}
|
||||
<!-- APP WIZARD -->
|
||||
<div class="box">
|
||||
<h3>{{=T("New application wizard")}}</h3>
|
||||
<p>{{=button(URL('wizard','index'), T('Start wizard'))}}
|
||||
{{=T("(requires internet access)")}}</p>
|
||||
</div> <!-- /APP WIZARD -->
|
||||
<!-- SCAFFOLD APP -->
|
||||
<div class="box">
|
||||
<h3>{{=T("New simple application")}}</h3>
|
||||
{{=form_create.custom.begin}}
|
||||
{{=LABEL(T("Application name:"))}}
|
||||
{{=form_create.custom.widget.name}}
|
||||
<div class="controls"><button type="submit" class="btn">{{=T('Create')}}</button></div>
|
||||
{{=form_create.custom.end}}
|
||||
</div> <!-- /SCAFFOLD APP -->
|
||||
<!-- UPLOAD PACKAGE -->
|
||||
<div class="box">
|
||||
<h3>{{=T("Upload and install packed application")}}</h3>
|
||||
{{=form_update.custom.begin}}
|
||||
<label for="appupdate_name">{{=T("Application name:")}}</label>
|
||||
{{=form_update.custom.widget.name}}
|
||||
<label for="appupdate_file">{{=T("Upload a package:")}}</label>
|
||||
{{=form_update.custom.widget.file}}
|
||||
<label for="appupdate_url">{{=T("Or Get from URL:")}}</label>
|
||||
{{=form_update.custom.widget.url}}<small class="help-block">({{=T('can be a git repo')}})</small>
|
||||
<div class="controls">
|
||||
<label class="checkbox">
|
||||
{{=form_update.custom.widget.overwrite}} {{=T("Overwrite installed app")}}
|
||||
</label>
|
||||
<button type="submit" class='btn'>{{=T('Install')}}</button>
|
||||
</div>
|
||||
{{=form_update.custom.end}}
|
||||
</div> <!-- /UPLOAD PACKAGE -->
|
||||
<!-- DEPLOY ON GAE -->
|
||||
<div class="box">
|
||||
<h3>{{=T("Deploy")}}</h3>
|
||||
<p class="row-buttons">
|
||||
{{=button(URL('gae','deploy'), T('Deploy on Google App Engine'))}}
|
||||
{{=button(URL('openshift','deploy'),T('Deploy to OpenShift'))}}
|
||||
</p>
|
||||
</div> <!-- /DEPLOY ON GAE -->
|
||||
<br/>
|
||||
{{if TWITTER_HASH:}}
|
||||
<!-- TWITTER -->
|
||||
<div class="box">
|
||||
<h3>{{=T("%s Recent Tweets"%TWITTER_HASH)}}</h3>
|
||||
<div id="tweets">{{=T('loading...')}}</div>
|
||||
<script>jQuery(document).ready(function(){jQuery('#tweets').load('{{=URL('twitter.load')}}');});</script>
|
||||
</div> <!-- /TWITTER -->
|
||||
{{pass}}
|
||||
</div>
|
||||
</div> <!-- /sidebar -->
|
||||
</div> <!-- /row-fluid
|
||||
<!-- end "site" block -->
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{{extend 'layout.html'}}
|
||||
|
||||
{{block sectionclass}}test{{end}}
|
||||
|
||||
<!-- begin "test" block -->
|
||||
<h2>{{=T('Testing application')}} "{{=app}}"</h2>
|
||||
|
||||
{{for controller in sorted(controllers):}}
|
||||
@@ -14,8 +14,14 @@ ajax('{{=URL(a=app,c=controller[:-3],f='_TEST')}}',[],'output_{{=controller[:-3]
|
||||
//--></script>
|
||||
{{pass}}
|
||||
|
||||
<p class="help">{{=T("""If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.
|
||||
A green title indicates that all tests (if defined) passed. In this case test results are not shown.""")}}</p>
|
||||
<p class="help">{{=T('Functions with no doctests will result in [passed] tests.')}}</p>
|
||||
<p class="help">{{=T('ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.')}}</p>
|
||||
|
||||
<div class="row-fluid">
|
||||
<p class="help alert alert-info span6">{{=T("""If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.
|
||||
A green title indicates that all tests (if defined) passed. In this case test results are not shown.""")}}</p>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<p class="help alert alert-info span6">{{=T('Functions with no doctests will result in [passed] tests.')}}</p>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<p class="help alert alert-info span6">{{=T('ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.')}}</p>
|
||||
</div>
|
||||
<!--end "test" block -->
|
||||
@@ -1,139 +1,154 @@
|
||||
{{extend 'layout.html'}}
|
||||
|
||||
{{block sectionclass}}ticket{{end}}
|
||||
|
||||
<!-- begin "ticket" block -->
|
||||
<h2>{{=T('Error ticket')}} for "{{=app}}"</h2>
|
||||
<h3>{{=T('Ticket ID')}}</h3>
|
||||
<p>{{=ticket}}</p>
|
||||
{{if output:}}<h4>{{=output}}</h4>{{pass}}
|
||||
<h3>{{=T('Version')}}</h3>
|
||||
<table class="versions">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>web2py™</th>
|
||||
<td>{{=myversion}}</td>
|
||||
</tr>
|
||||
{{if snapshot:}}
|
||||
<tr>
|
||||
<th>Python</th>
|
||||
<td>{{=snapshot.get('pyver','')}}</td>
|
||||
</tr>
|
||||
{{pass}}
|
||||
</tbody>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>web2py™</th>
|
||||
<td>{{=myversion}}</td>
|
||||
</tr>
|
||||
{{if snapshot:}}
|
||||
<tr>
|
||||
<th>Python</th>
|
||||
<td>{{=snapshot.get('pyver','')}}</td>
|
||||
</tr>
|
||||
{{pass}}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{{if traceback or code or layer:}}
|
||||
<h3>{{=T('Traceback')}}</h3>
|
||||
<div class="inspect">
|
||||
{{=traceback}}
|
||||
</div>
|
||||
|
||||
{{if snapshot:}}
|
||||
{{try:}}
|
||||
|
||||
<!-- ERROR SNAPSHOT -->
|
||||
|
||||
<h3>
|
||||
{{=T('Error snapshot')}}
|
||||
<span class="tooltip">{{=helpicon()}} <span>{{=T('Detailed traceback description')}}</span></span>
|
||||
</h3>
|
||||
|
||||
<!-- SNAPSHOT LIST -->
|
||||
|
||||
<div id="snapshot">
|
||||
<!-- Exception details -->
|
||||
<p class="exception_object inspect">
|
||||
<code>{{=snapshot['etype']}}({{=snapshot['evalue']}})</code>
|
||||
</p>
|
||||
<p class="controls">
|
||||
<a class="button" onclick="collapse('exception_inner');"><span>{{=T('inspect attributes')}}</span></a>
|
||||
</p>
|
||||
<div id="exception_inner" class="hide">
|
||||
<div class="inspect">
|
||||
<h5>{{=T("Exception instance attributes")}}</h5>
|
||||
<table>
|
||||
<tbody>
|
||||
{{for k,v in snapshot['exception'].items():}}
|
||||
<tr>
|
||||
<th>{{=k}}</th>
|
||||
<td>{{=v}}</td>
|
||||
</tr>
|
||||
{{pass}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- FRAMES -->
|
||||
<div id="frames">
|
||||
<h4>{{=T('Frames')}}</h4>
|
||||
<ul>
|
||||
{{for i, frame in enumerate(snapshot['frames']):}}
|
||||
<li>
|
||||
{{is_hidden = (i != len(snapshot['frames'])-1 and 'hide' or 'inspect')}}
|
||||
<div class="framefile inspect controls">
|
||||
<p>
|
||||
<strong>File {{="%s in %s at line %s" % (frame['file'], frame['func'], frame['lnum'])}}</strong>
|
||||
<a class="button tbbutton" onclick="collapse('{{="%s_code_inner" % i}}');"><span>{{=T("code")}}</span></a>
|
||||
<a class="button tbbutton" onclick="collapse('{{="%s_args_inner" % i}}');"><span>{{=T("arguments")}}</span></a>
|
||||
<a class="button tbbutton" onclick="collapse('{{="%s_vars_inner" % i}}');"><span>{{=T("variables")}}</span></a>
|
||||
</p>
|
||||
<div id="{{="%s_args_inner" % i}}" class="{{=is_hidden}}">
|
||||
<h5>Function argument list</h5>
|
||||
<p>{{=frame['call']}}</p>
|
||||
</div>
|
||||
<div id="{{="%s_code_inner" % i}}" class="{{=is_hidden}}">
|
||||
<h5>Code listing</h5>
|
||||
{{if frame['lines']:}}
|
||||
<pre>{{=CODE('\n'.join([x[1] for x in sorted(frame['lines'].items(),key=lambda x: x[0])]),
|
||||
language='python', link=None, counter=min(frame['lines'].keys()), highlight_line=frame['lnum'])}}</pre>
|
||||
{{pass}}
|
||||
</div>
|
||||
<div id="{{="%s_vars_inner" % i}}" class="{{=is_hidden}}">
|
||||
<h5>Variables</h5>
|
||||
<table>
|
||||
<tbody>
|
||||
{{for k,v in frame['dump'].items():}}
|
||||
<tr>
|
||||
<th>{{=k}}</th>
|
||||
<td>{{=v}}</td>
|
||||
</tr>
|
||||
{{pass}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- VIEW ENVIRONMENT -->
|
||||
<div class="viewenv">
|
||||
<h4>Context</h4>
|
||||
<p class="controls">
|
||||
<a class="button" onclick="jQuery('#locals').slideToggle()"><span>{{=T('locals')}}</span></a>
|
||||
<a class="button" onclick="jQuery('#request').slideToggle()"><span>{{=T('request')}}</span></a>
|
||||
<a class="button" onclick="jQuery('#session').slideToggle()"><span>{{=T('session')}}</span></a>
|
||||
<a class="button" onclick="jQuery('#response').slideToggle()"><span>{{=T('response')}}</span></a>
|
||||
</p>
|
||||
<div class="hide inspect" id="locals"><h6>locals</h6>{{=BEAUTIFY(snapshot['locals'])}}</div>
|
||||
<div class="hide inspect" id="request"><h6>request</h6>{{=BEAUTIFY(snapshot['request'])}}</div>
|
||||
<div class="hide inspect" id="session"><h6>session</h6>{{=BEAUTIFY(snapshot['session'])}}</div>
|
||||
<div class="hide inspect" id="response"><h6>response</h6>{{=BEAUTIFY(snapshot['response'])}}</div>
|
||||
</div>
|
||||
{{except Exception, e:}}
|
||||
<!-- this should not happen, just in case... (cannot output normal hmtl as we don't know current open tags) -->
|
||||
{{import traceback;tb=traceback.format_exc().replace("\n","\\n") }}
|
||||
<script language='javascript'>alert("Exception during snapshot rendering: {{=tb}} ");</script>
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
|
||||
<div class="errorsource">
|
||||
<h3>In file: {{=layer}}</h3>
|
||||
{{=CODE(code.replace('\r',''),language='python',link='/examples/global/vars/')}}
|
||||
</div>
|
||||
<h3>{{=T('Traceback')}}</h3>
|
||||
<div class="inspect resp1">{{=traceback}}</div>
|
||||
{{if snapshot:}}
|
||||
{{try:}}
|
||||
<!-- ERROR SNAPSHOT -->
|
||||
<h3>{{=T('Error snapshot')}}
|
||||
<a href="#" rel="tooltip" data-placement="right" data-original-title="{{=T('Detailed traceback description')}}">
|
||||
{{=helpicon()}}
|
||||
<span>{{=T("Detailed traceback description")}}</span>
|
||||
</a>
|
||||
</h3>
|
||||
<!-- SNAPSHOT LIST -->
|
||||
<div id="snapshot">
|
||||
<!-- Exception details -->
|
||||
<p class="exception_object inspect">
|
||||
<code>{{=snapshot['etype']}}({{=snapshot['evalue']}})</code>
|
||||
</p>
|
||||
<p class="controls">
|
||||
<a class="button btn" onclick="collapse('exception_inner');"><span>{{=T('inspect attributes')}}</span></a>
|
||||
</p>
|
||||
<div id="exception_inner" class="hide">
|
||||
<div class="inspect">
|
||||
<h5>{{=T("Exception instance attributes")}}</h5>
|
||||
<table>
|
||||
<tbody>
|
||||
{{for k,v in snapshot['exception'].items():}}
|
||||
<tr>
|
||||
<th>{{=k}}</th>
|
||||
<td>{{=v}}</td>
|
||||
</tr>
|
||||
{{pass}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- FRAMES -->
|
||||
<div id="frames">
|
||||
<h4>{{=T('Frames')}}</h4>
|
||||
<ul class="unstyled">
|
||||
{{for i, frame in enumerate(snapshot['frames']):}}
|
||||
<li>
|
||||
{{is_hidden = (i != len(snapshot['frames'])-1 and 'hide' or 'inspect')}}
|
||||
<div class="framefile inspect controls">
|
||||
<p>
|
||||
<strong>File {{="%s in %s at line %s" % (frame['file'], frame['func'], frame['lnum'])}}</strong>
|
||||
<a class="button tbbutton btn" onclick="collapse('{{='%s_code_inner' % i}}');"><span>{{=T("code")}}</span></a>
|
||||
<a class="button tbbutton btn" onclick="collapse('{{='%s_args_inner' % i}}');"><span>{{=T("arguments")}}</span></a>
|
||||
<a class="button tbbutton btn" onclick="collapse('{{='%s_vars_inner' % i}}');"><span>{{=T("variables")}}</span></a>
|
||||
</p>
|
||||
<div id="{{='%s_args_inner' % i}}" class="{{=is_hidden}}" style="width:100%;overflow:auto">
|
||||
<h5>Function argument list</h5>
|
||||
<p>{{=frame['call']}}</p>
|
||||
</div>
|
||||
<div id="{{='%s_code_inner' % i}}" class="{{=is_hidden}}" style="width:100%;overflow:auto">
|
||||
<h5>Code listing</h5>
|
||||
{{if frame['lines']:}}
|
||||
<pre>{{=CODE('\n'.join([x[1] for x in sorted(frame['lines'].items(),key=lambda x: x[0])]),
|
||||
language='python', link=None, counter=min(frame['lines'].keys()), highlight_line=frame['lnum'])}}</pre>
|
||||
{{pass}}
|
||||
</div>
|
||||
<div id="{{='%s_vars_inner' % i}}" class="{{=is_hidden}}" style="width:100%;overflow:auto">
|
||||
<h5>Variables</h5>
|
||||
<table>
|
||||
<tbody>
|
||||
{{for k,v in frame['dump'].items():}}
|
||||
<tr>
|
||||
<th>{{=k}}</th>
|
||||
<td>{{=v}}</td>
|
||||
</tr>
|
||||
{{pass}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
</div>
|
||||
<!-- VIEW ENVIRONMENT -->
|
||||
<div class="viewenv">
|
||||
<h4><span>Context</span></h4>
|
||||
<p class="controls">
|
||||
<a class="button btn" onclick="jQuery('#locals').slideToggle()"><span>{{=T('locals')}}</span></a>
|
||||
<a class="button btn" onclick="jQuery('#request').slideToggle()"><span>{{=T('request')}}</span></a>
|
||||
<a class="button btn" onclick="jQuery('#session').slideToggle()"><span>{{=T('session')}}</span></a>
|
||||
<a class="button btn" onclick="jQuery('#response').slideToggle()"><span>{{=T('response')}}</span></a>
|
||||
</p>
|
||||
<div class="hide inspect resp1" id="locals"><h6>locals</h6>
|
||||
{{try:}}
|
||||
{{=BEAUTIFY(snapshot['locals'])}}
|
||||
{{except:}}
|
||||
{{=BEAUTIFY('no locals available in snapshot')}}
|
||||
{{pass}}
|
||||
</div>
|
||||
<div class="hide inspect" id="request"><h6>request</h6>
|
||||
{{try:}}
|
||||
{{=BEAUTIFY(snapshot['request'])}}
|
||||
{{except:}}
|
||||
{{=BEAUTIFY('no request available in snapshot')}}
|
||||
{{pass}}
|
||||
</div>
|
||||
<div class="hide inspect" id="session"><h6>session</h6>
|
||||
{{try:}}
|
||||
{{=BEAUTIFY(snapshot['session'])}}
|
||||
{{except:}}
|
||||
{{=BEAUTIFY('no session available in snapshot')}}
|
||||
{{pass}}
|
||||
</div>
|
||||
<div class="hide inspect" id="response"><h6>response</h6>
|
||||
{{try:}}
|
||||
{{=BEAUTIFY(snapshot['response'])}}
|
||||
{{except:}}
|
||||
{{=BEAUTIFY('no response available in snapshot')}}
|
||||
{{pass}}
|
||||
</div>
|
||||
</div>
|
||||
{{except Exception, e:}}
|
||||
<!-- this should not happen, just in case... (cannot output normal hmtl as we don't know current open tags) -->
|
||||
{{import traceback;tb=traceback.format_exc().replace("\n","\\n") }}
|
||||
<script language='javascript'>alert("Exception during snapshot rendering: {{=tb}} ");</script>
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
<div class="errorsource">
|
||||
<h3>In file: {{=layer}}</h3>
|
||||
{{=CODE(code.replace('\r',''),language='python',link='/examples/global/vars/')}}
|
||||
</div>
|
||||
{{else:}}
|
||||
<h3>{{=T('Ticket Missing')}}</h3>
|
||||
<h3>{{=T('Ticket Missing')}}</h3>
|
||||
{{pass}}
|
||||
<!-- end "ticket" block -->
|
||||
@@ -1,7 +1,7 @@
|
||||
{{extend 'layout.html'}}
|
||||
|
||||
<!-- begin "uninstall" block -->
|
||||
<h2>{{=T('Are you sure you want to uninstall application "%s"?', app)}}</h2>
|
||||
<div class="center">
|
||||
{{=dialog}}
|
||||
</div>
|
||||
|
||||
<!-- end "uninstall" block -->
|
||||
@@ -1,13 +1,17 @@
|
||||
{{extend 'layout.html'}}
|
||||
|
||||
{{
|
||||
dlg = dialog
|
||||
smt_button = dlg.element(_type="submit")
|
||||
smt_button['_class'] = 'btn'
|
||||
smt_button['_style'] = 'margin-right:4px;'
|
||||
ccl_button = dlg.element(_type="button")
|
||||
ccl_button['_class'] = 'btn'
|
||||
}}
|
||||
{{block sectionclass}}upgrade{{end}}
|
||||
|
||||
<!-- begin "shell" block -->
|
||||
<h2>{{=T('web2py upgrade')}}</h2>
|
||||
|
||||
<p class="center"><strong class="att">{{=T('ATTENTION:')}}</strong> {{=T('This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk')}}<br />
|
||||
{{=T('If start the upgrade, be patient, it may take a while to download')}}</p>
|
||||
|
||||
<p class="center"><div class="alert"><strong class="att">{{=T('ATTENTION:')}}</strong> {{=T('This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk')}}<br />
|
||||
{{=T('If start the upgrade, be patient, it may take a while to download')}}</p></div>
|
||||
<div class="center">
|
||||
{{=dialog}}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1,20 +1,67 @@
|
||||
{{extend 'layout.html'}}
|
||||
<!-- begin "user" block -->
|
||||
<h2>{{=T( request.args(0).replace('_',' ').capitalize() )}}</h2>
|
||||
<div id="web2py_user_form">
|
||||
{{if 'auth' in globals():}}
|
||||
{{
|
||||
# add bootstrap class to form
|
||||
form['_class']='span4 well well-small'
|
||||
# change form.custom.begin
|
||||
form.custom.begin=XML("<%s %s>" % (form.tag,form._xml()[0]))
|
||||
if request.args(0)=='login':
|
||||
# delete empty label
|
||||
d = form.elements("tr#auth_user_remember__row")
|
||||
d[0][0] = " "
|
||||
# remake remember checkbox
|
||||
cbx_inp=form.element(_name='remember')
|
||||
cbx_inp['_class']=""
|
||||
cbx_lbl=form.element(_for='auth_user_remember')[0]
|
||||
form.element('div',replace=LABEL(cbx_inp,cbx_lbl,_class="checkbox"))
|
||||
# new form buttons
|
||||
smt = form.element('input',_type='submit')
|
||||
smt['_class']='btn'
|
||||
btns = [smt]
|
||||
if not 'register' in auth.settings.actions_disabled:
|
||||
btns.append(A(T('register'),_href=URL(r=request,args='register'),_class='btn btn-lnk'))
|
||||
pass
|
||||
if not 'request_reset_password' in auth.settings.actions_disabled:
|
||||
btns.append(A(T('lost password'),_href=URL(r=request,args='request_reset_password'),_class='btn btn-lnk'))
|
||||
pass
|
||||
form.element('input[type=submit]',replace=DIV(*btns,_class="controls-inline"))
|
||||
pass
|
||||
if request.args(0)in['register','profile']:
|
||||
# remake is_manager checkbox
|
||||
cbx_inp=form.element(_name='is_manager')
|
||||
cbx_lbl=form.element(_for='auth_user_is_manager')[0]
|
||||
form.element(_name='is_manager',replace=lambda cbx_inp : LABEL(cbx_inp,cbx_lbl,_class="checkbox"))
|
||||
# delete is manager label
|
||||
d = form.elements("tr#auth_user_is_manager__row")
|
||||
d[0][0][0] = " "
|
||||
# new form buttons
|
||||
smt = form.element('input',_type='submit')
|
||||
smt['_class']='btn'
|
||||
form.element('input[type=submit]',replace=lambda button: DIV(button,_class="controls-inline"))
|
||||
pass
|
||||
if request.args(0)in ['request_reset_password','change_password']:
|
||||
# new form buttons
|
||||
smt = form.element('input',_type='submit')
|
||||
smt['_class']='btn'
|
||||
form.element('input[type=submit]',replace=lambda button: DIV(button,_class="controls-inline"))
|
||||
pass
|
||||
}}
|
||||
{{=form.custom.begin}}
|
||||
{{for e in form.components[0]:}}
|
||||
{{= e[0][0]}}
|
||||
{{= e[1][0]}}
|
||||
{{pass}}
|
||||
{{=form.custom.end}}
|
||||
{{else:}}
|
||||
{{=form}}
|
||||
{{if request.args(0)=='login':}}
|
||||
{{if not 'register' in auth.settings.actions_disabled:}}
|
||||
<br/><a href="{{=URL(r=request,args='register')}}">register</a>
|
||||
{{pass}}
|
||||
{{if not 'request_reset_password' in auth.settings.actions_disabled:}}
|
||||
<br/><a href="{{=URL(r=request,args='request_reset_password')}}">lost password</a>
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
</div>
|
||||
|
||||
<script language="javascript">
|
||||
<!--
|
||||
//<!--
|
||||
jQuery("#web2py_user_form input:visible:enabled:first").focus();
|
||||
//-->
|
||||
</script>
|
||||
|
||||
<!-- end "user" block -->
|
||||
|
||||
@@ -1,44 +1,85 @@
|
||||
<!doctype html>
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="P3P" content="CP=\"IDC DSP COR CURa ADMa OUR IND PHY ONL COM STA\"" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{=response.title or URL()}}</title>
|
||||
{{response.files.append(URL('static','css/styles.css'))}}
|
||||
{{
|
||||
response.files.append(URL('static','css/bootstrap.min.css'))
|
||||
response.files.append(URL('static','css/styles.css'))
|
||||
response.files.append(URL('static','css/bootstrap_essentials.css'))
|
||||
response.files.append(URL('static','css/bootstrap_adapters.css'))
|
||||
response.files.append(URL('static','css/bootstrap-responsive.min.css'))
|
||||
}}
|
||||
{{include 'web2py_ajax.html'}}
|
||||
<script>jQuery.noConflict();</script>
|
||||
</head>
|
||||
|
||||
<body class="{{=T('direction: ltr') == 'direction: rtl' and 'RTLbody' or ''}} {{block sectionclass}}home{{end}}">
|
||||
<div id="header">
|
||||
<h1 id="start">
|
||||
<a href="{{=URL('default', 'index')}}" class="button"><span>web2py™ {{=T('administrative interface')}}</span></a>
|
||||
</h1>
|
||||
{{if response.menu is not None:}}
|
||||
<ul id="menu">
|
||||
{{for _name,_active,_link in response.menu:}}
|
||||
<li>{{=A(SPAN(_name), _href=_link, _class=_active and 'button select' or 'button')}}</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
{{pass}}
|
||||
</div>
|
||||
<div id="main">
|
||||
<div id="main_inner">
|
||||
<div class="flash">{{=response.flash or ''}}</div>
|
||||
{{include}}
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer" class="fixed">
|
||||
{{=T('Powered by')}} {{=A('web2py', _href='http://www.web2py.com')}}™ {{=T('created by')}} Massimo Di Pierro ©2007-{{=request.now.year}} -
|
||||
{{if hasattr(T,'get_possible_languages_info'):}}
|
||||
<span>
|
||||
{{=T('Admin language')}}
|
||||
<select name="adminlanguage" onchange="var date = new Date();cookieDate=date.setTime(date.getTime()+(100*24*60*60*1000));document.cookie='adminLanguage='+this.options[this.selectedIndex].id+'; expires='+cookieDate+'; path=/';window.location.reload()">
|
||||
{{for langinfo in sorted([(code,info[1]) for code,info in T.get_possible_languages_info().iteritems() if code != 'default']):}}
|
||||
<option {{=T.accepted_language==langinfo[0] and 'selected' or ''}} {{='id='+langinfo[0]}} >{{=langinfo[1]}}</option>
|
||||
{{pass}}
|
||||
</select>
|
||||
</span>
|
||||
{{pass}}
|
||||
</div>
|
||||
|
||||
<!-- NAVBAR
|
||||
============== -->
|
||||
<div id="header" class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<div id="start" class="brand_wrapper">
|
||||
<a href="{{=URL('default', 'index')}}" class="button brand" ><span>web2py™ {{=T('administrative interface')}}</span></a>
|
||||
</div>
|
||||
<div class="nav-collapse">
|
||||
{{if response.menu is not None:}}
|
||||
<ul id="menu" class="nav pull-right">
|
||||
{{for _name,_active,_link in response.menu:}}
|
||||
<li>{{=A(SPAN(_name), _href=_link, _class=_active and 'button select' or 'button')}}</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
{{pass}}
|
||||
</div><!--/.nav-collapse -->
|
||||
</div><!-- /container-fluid -->
|
||||
</div><!-- /navbar-inner -->
|
||||
</div><!-- /#header -->
|
||||
|
||||
<!-- MAIN
|
||||
=========== -->
|
||||
<div id="main" class="container-fluid">
|
||||
<div id="main_inner" class="row-fluid">
|
||||
<div class="span12">
|
||||
<div class="flash alert">{{=response.flash or ''}}</div>
|
||||
{{include}}
|
||||
</div><!-- /main span12 -->
|
||||
</div><!-- /main row-fluid -->
|
||||
</div><!-- /#main -->
|
||||
|
||||
<!-- FOOTER
|
||||
============== -->
|
||||
<footer id="footer" class="fixed">
|
||||
<p><span>{{=T('Powered by')}} {{=A('web2py', _href='http://www.web2py.com')}}™ {{=T('created by')}} Massimo Di Pierro ©2007-{{=request.now.year}}
|
||||
{{if hasattr(T,'get_possible_languages_info'):}}
|
||||
- {{=T('Admin language')}}</span>
|
||||
<select name="adminlanguage" onchange="var date = new Date();cookieDate=date.setTime(date.getTime()+(100*24*60*60*1000));document.cookie='adminLanguage='+this.options[this.selectedIndex].id+'; expires='+cookieDate+'; path=/';window.location.reload()">
|
||||
{{for langinfo in sorted([(code,info[1]) for code,info in T.get_possible_languages_info().iteritems() if code != 'default']):}}
|
||||
<option {{=T.accepted_language==langinfo[0] and 'selected' or ''}} {{='id='+langinfo[0]}} >{{=langinfo[1]}}</option>
|
||||
{{pass}}
|
||||
</select>
|
||||
{{else:}}
|
||||
</span>{{pass}}
|
||||
</p>
|
||||
</footer><!-- /#footer -->
|
||||
|
||||
<!-- BS JAVASCRIPT
|
||||
====================== -->
|
||||
<script src="{{=URL('static','js/bootstrap.min.js')}}"></script>
|
||||
<script type="text/javascript">
|
||||
jQuery(document).ready(function(){
|
||||
jQuery("[rel=tooltip]").tooltip();
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,92 +1,42 @@
|
||||
{{extend 'layout.html'}}
|
||||
|
||||
{{block sectionclass}}shell{{end}}
|
||||
<!--style type="text/css">
|
||||
|
||||
.prompt, #output {
|
||||
width: 45em;
|
||||
border: 1px solid #CCCCCC;
|
||||
font-size: 10pt;
|
||||
margin: 0.5em;
|
||||
padding: 0.5em;
|
||||
padding-right: 0em;
|
||||
overflow: auto;
|
||||
wrap: hard;
|
||||
}
|
||||
|
||||
#output {
|
||||
height:250px;overflow:auto;
|
||||
}
|
||||
|
||||
#toolbar {
|
||||
margin-left: 0.5em;
|
||||
padding-left: 0.5em;
|
||||
}
|
||||
|
||||
#caret {
|
||||
width: 2.5em;
|
||||
margin-right: 0px;
|
||||
padding-right: 0px;
|
||||
border-right: 0px;
|
||||
}
|
||||
|
||||
#statement {
|
||||
width: 43em;
|
||||
margin-left: -1em;
|
||||
padding-left: 0px;
|
||||
border-left: 0px;
|
||||
background-position: top right;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.processing {
|
||||
background-image: url("{{=URL('static','images/spinner.gif')}}");
|
||||
}
|
||||
|
||||
#ajax-status {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.message {
|
||||
color: #8AD;
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: #F44;
|
||||
}
|
||||
|
||||
.username {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
</style-->
|
||||
|
||||
<!-- begin "shell" block -->
|
||||
<div id="wrapper">
|
||||
<textarea id="output" readonly="readonly">web2py Shell {{=request.env.web2py_version}}</textarea>
|
||||
<div class="row-fluid">
|
||||
<div class="output-wrapper span8">
|
||||
<textarea id="output" readonly="readonly">web2py Shell {{=request.env.web2py_version}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form id="form" action="{{=URL('callback',args=app)}}" method="get">
|
||||
<div id="shellwrapper">
|
||||
<div id="caret">>>></div>
|
||||
<div class="tooltip">
|
||||
<textarea class="prompt" name="statement" id="statement"></textarea>
|
||||
<span>Type some Python code in here and hit Return (Enter) to execute it.</span>
|
||||
</div>
|
||||
<div id="autoscroll" style="cursor:pointer;float:right;">autoscroll</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="row-fluid">
|
||||
<form id="form" action="{{=URL(r=request,f='callback',args=app)}}" method="get" class="span8">
|
||||
<div id="shellwrapper">
|
||||
<div class="prompt-wrapper">
|
||||
<div class="prompt-container">
|
||||
<textarea class="prompt" name="statement" id="statement"></textarea>
|
||||
</div>
|
||||
<a href="#" rel="tooltip" data-placement="right" data-original-title="{{=T('Type some Python code in here and hit Return (Enter) to execute it.')}}">
|
||||
{{=helpicon()}}
|
||||
<span>Type some Python code in here and hit Return (Enter) to execute it.</span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="caret"><span>>>></span></div>
|
||||
<div id="autoscroll">autoscroll</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="row-fluid clearfix">
|
||||
<div class="help alert alert-info span6">
|
||||
<ul>
|
||||
<li>Using the shell may lock the database to other users of this app.</li>
|
||||
<li>Each db statement is automatically committed.</li>
|
||||
<li>Creating new tables dynamically is not allowed.</li>
|
||||
<li>Models are automatically imported in the shell.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="help">
|
||||
<ul>
|
||||
<li>Using the shell may lock the database to other users of this app.</li>
|
||||
<li>Each db statement is automatically committed.</li>
|
||||
<li>Creating new tables dynamically is not allowed.</li>
|
||||
<li>Models are automatically imported in the shell.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="{{=URL('static', 'js/autoscroll.js')}}"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
@@ -103,7 +53,7 @@ jQuery(document).ready(function(){
|
||||
if(s.length>1 && s.substr(s.length-1,1)=='\n' && s.substr(s.length-2,1)!=':' &&
|
||||
(s.indexOf(':\n ')<0 || s.substr(s.length-2,1)=='\n')) {
|
||||
t.val('');
|
||||
jQuery.post("{{=URL('callback',args=app)}}",
|
||||
jQuery.post("{{=URL(r=request,f='callback',args=app)}}",
|
||||
{statement:s},function(data){o.html(o.html()+data).attr('scrollTop',o.attr('scrollHeight'));});
|
||||
} else { };
|
||||
if(event.keyCode==RETURN){
|
||||
@@ -163,4 +113,4 @@ jQuery(document).ready(function(){
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- end "shell" block -->
|
||||
@@ -1,14 +1,15 @@
|
||||
{{extend 'layout.html'}}
|
||||
|
||||
{{block sectionclass}}generated{{end}}
|
||||
|
||||
<a class="button" href="{{=URL(app,'default','index')}}">Open new app in new window</a>
|
||||
<a class="button" href="{{=URL('step1')}}">Back to wizard</a>
|
||||
<a class="button" href="{{=URL('default','design',args=app)}}">Admin design page</a>
|
||||
{{if have_mercurial:}}
|
||||
<a class="button" href="{{=URL('mercurial','commit',args=app)}}">Admin versioning page</a>
|
||||
{{pass}}
|
||||
<a class="button" href="{{=URL(app,'appadmin','index')}}">Database administration</a>
|
||||
<!-- begin "generated" block -->
|
||||
<div class="controls row-buttons">
|
||||
{{=button(URL(app,'default','index'), T('Open new app in new window'))}}
|
||||
{{=button(URL('step1'), T('Back to wizard'))}}
|
||||
{{=button(URL('default','design',args=app), T('Admin design page'))}}
|
||||
{{if have_mercurial:}}
|
||||
{{=button(URL('mercurial','commit',args=app), T('Admin versioning page'))}}
|
||||
{{pass}}
|
||||
{{=button(URL(app,'appadmin','index'), T('Database administration'))}}
|
||||
</div>
|
||||
<br/><br/>
|
||||
<iframe style="width: 100%; height: 100%; min-height:600px" src="{{=URL(app,'default','index')}}"></iframe>
|
||||
|
||||
<!-- end "generated" block -->
|
||||
@@ -1,141 +1,183 @@
|
||||
{{extend 'layout.html'}}
|
||||
|
||||
{{block sectionclass}}step{{end}}
|
||||
|
||||
<!-- begin "step" block -->
|
||||
<h2>{{=T('New Application Wizard')}}</h2>
|
||||
|
||||
<div id="wizard_nav" class="f20 controls">
|
||||
{{if request.function=='index':}}
|
||||
<h3>{{=T('Start a new app')}}</h3>
|
||||
{{else:}}
|
||||
<div class="box">
|
||||
<h3>{{=T('Basics')}}</h3>
|
||||
<p>{{=button(URL('index'), T('restart'))}}</p>
|
||||
<p><strong>App Name:</strong> {{=session.app['name']}}</p>
|
||||
</div>
|
||||
<div class="box">
|
||||
<h3>Current settings</h3>
|
||||
<p>{{=button(URL('step1'), T('Edit'))}}</p>
|
||||
<ul id="current_settings">
|
||||
{{for key,value in session.app['params']:}}
|
||||
<li><b>{{=key}}:</b> {{=value}}</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="box">
|
||||
<h3>Tables</h3>
|
||||
<p>{{=button(URL('step2'), T('edit all'))}}</p>
|
||||
<ul>
|
||||
{{for i,table in enumerate(session.app['tables']):}}
|
||||
<li>{{=button(URL('step3',args=i), T('Edit'))}} <strong>{{=table}}</strong></li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="box">
|
||||
<h3>Pages</h3>
|
||||
<p>{{=button(URL('step4'), T('edit all'))}}</p>
|
||||
<ul>
|
||||
{{for i,page in enumerate(session.app['pages']):}}
|
||||
<li>{{=button(URL('step5',args=i), T('Edit'))}} <strong>{{=page}}</strong></li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="box">
|
||||
<h3>{{=T('Generate')}}</h3>
|
||||
<p>{{=button(URL('step6'), T('go!'))}}</p>
|
||||
</div>
|
||||
{{pass}}
|
||||
<div class='row-fluid'>
|
||||
<div id="wizard_nav" class="f20 controls span3">
|
||||
{{if request.function=='index':}}
|
||||
<h3>{{=T('Start a new app')}}</h3>
|
||||
{{else:}}
|
||||
<div class="box first-box">
|
||||
<h3>{{=T('Basics')}}</h3>
|
||||
<p>{{=button(URL('index'), T('restart'))}}</p>
|
||||
<p><strong>App Name:</strong> {{=session.app['name']}}</p>
|
||||
</div>
|
||||
<div class="box">
|
||||
<h3>Current settings</h3>
|
||||
<p>{{=button(URL('step1')+'/#xwizard_form', T('Edit'))}}</p>
|
||||
<ul id="current_settings" class="unstyled">
|
||||
{{for key,value in session.app['params']:}}
|
||||
<li><b>{{=key}}:</b> {{=value}}</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="box">
|
||||
<h3>Tables</h3>
|
||||
<p>{{=button(URL('step2')+'/#xwizard_form', T('edit all'))}}</p>
|
||||
<ul class="unstyled">
|
||||
{{for i,table in enumerate(session.app['tables']):}}
|
||||
<li>{{=button(URL('step3',args=[i])+'/#xwizard_form', T('Edit'))}} <strong>{{=table}}</strong></li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="box">
|
||||
<h3>Pages</h3>
|
||||
<p>{{=button(URL('step4')+'/#xwizard_form', T('edit all'))}}</p>
|
||||
<ul class="unstyled">
|
||||
{{for i,page in enumerate(session.app['pages']):}}
|
||||
<li>{{=button(URL('step5',args=i)+'/#xwizard_form', T('Edit'))}} <strong>{{=page}}</strong></li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="box">
|
||||
<h3>{{=T('Generate')}}</h3>
|
||||
<p>{{=button(URL('step6')+'/#xwizard_form', T('go!'))}}</p>
|
||||
</div>
|
||||
{{pass}}
|
||||
</div> <!-- /wizard nav -->
|
||||
<div id="wizard_form" class="fl20 controls span9" rel="pagebookmark"><span id="xwizard_form" class="hashstick"> </span>
|
||||
<!-- FORM -->
|
||||
{{if 'step' in request.function:}}
|
||||
<h3>{{=T('Step')}} {{=step}}</h3>
|
||||
{{if request.function!='step1':}}
|
||||
{{=button(URL('step' + str(int(request.function[-1])-1)) + '/#xwizard_form', T('back'))}}
|
||||
{{pass}}
|
||||
{{else:}}
|
||||
<h3>{{=T('Begin')}}</h3>
|
||||
{{pass}}
|
||||
{{if request.function in ('step1','step2','step3','step4','step5'):}}
|
||||
{{=button(URL('step6') + '/#xwizard_form', T('skip to generate'))}}
|
||||
{{pass}}
|
||||
<br /><br />
|
||||
{{if request.function in ('step1','step6'):}}
|
||||
{{pass}}
|
||||
{{if request.function!='step6':}}
|
||||
<div class="form row-fluid">
|
||||
{{=form.custom.begin}}
|
||||
{{ for fieldname in form.table.fields: }}
|
||||
{{if fieldname is not 'id':}}
|
||||
<label>{{=form.custom.label[fieldname]}}:</label>
|
||||
{{=form.custom.widget[fieldname]}}
|
||||
{{if fieldname=='layout_theme':}}
|
||||
<span class="help-inline">
|
||||
<img src="{{=LAYOUTS_APP}}/static/plugin_layouts/layouts/{{=dict(session.app['params'])['layout_theme']}}/preview.png" alt="" align="right" id="preview" class="img-polaroid"/>
|
||||
</span>
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
<div class="controls"><button type="submit" class="btn">{{=T('Submit')}}</button></div>
|
||||
{{=form.custom.end}}
|
||||
</div>
|
||||
<script>
|
||||
jQuery(function(){
|
||||
var t=jQuery('#no_table_layout_theme');
|
||||
t.change(function(){
|
||||
jQuery('#preview').attr('src','{{=LAYOUTS_APP}}/static/plugin_layouts/layouts/'+t.val()+'/preview.png');
|
||||
});
|
||||
jQuery("#preview").error(function (){
|
||||
jQuery('#preview').attr('src','http://placehold.it/190x141&text=no+preview+available');
|
||||
});
|
||||
jQuery('ul[id$="_grow_input"] li').addClass('input-append');
|
||||
jQuery('ul[id$="_grow_input"] li a').addClass('btn');
|
||||
});
|
||||
</script>
|
||||
{{else:}}
|
||||
<div class="form row-fluid">
|
||||
{{=form.custom.begin}}
|
||||
{{ for fieldname in form.table.fields: }}
|
||||
{{if fieldname is not 'id':}}
|
||||
<div class="control-group">
|
||||
<label class="control-label">{{=form.custom.label[fieldname]}}:</label>
|
||||
<div class="controls">
|
||||
<label class="checkbox">{{=form.custom.widget[fieldname]}}</label>
|
||||
</div>
|
||||
</div>
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
<div class="control-group">
|
||||
<label class="control-label empty"> </label>
|
||||
<div class="controls">
|
||||
<button type="submit" class="btn">{{=T('Submit')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
{{=form.custom.end}}
|
||||
</div>
|
||||
{{pass}}
|
||||
<!-- INSTRUCTIONS -->
|
||||
<div class="box">
|
||||
<h4>Instructions</h4>
|
||||
<div class="row-fluid">
|
||||
<div class="help span7 alert alert-block alert-info">
|
||||
{{if request.function=='index':}}
|
||||
<ul class="unstyled">
|
||||
<li>Insert the name of a new app.</li>
|
||||
<li>If the app exists and was created with the wizard, you will be able to edit it, but any manual editing to the app <b>will be lost</b>.</li>
|
||||
</ul>
|
||||
{{elif request.function=='step1':}}
|
||||
<ul class="unstyled">
|
||||
<li>This Wizard will help you build a new web2py app.</li>
|
||||
<li>You can create an app with a name that already exists.</li>
|
||||
<li>If you do not have an email server set email server to "logging".</li>
|
||||
<li>If you want to use Janrain Engage for login: 1) Sign up for a <a href="http://www.janrain.com/products/engage">Janrain Engage</a> account; 2) Register you hostname, domain, and obtain an api key; 3) Set Login Config above to "domain:api_key".</li>
|
||||
<li>ATTENTION: you can use the wizard to download plugins BUT we cannot guarantee the stability or backward compatibility of plugins. Moreover plugins may conflict with each other. Anyway, we do recommend installing plugin "wiki" with adds CMS like capabilities to your app.</li>
|
||||
</ul>
|
||||
{{elif request.function=='step2':}}
|
||||
<ul class="unstyled">
|
||||
<li>List the names of table that you need.</li>
|
||||
<li>If you do not need authentication remove the table "auth_user".</li>
|
||||
<li>Press enter to create a new input row.</li>
|
||||
<li>Empty rows are ignored.</li>
|
||||
<li>Other tables for role based access control will be created automatically, and do not need to be listed.</li>
|
||||
<li>You will be able to add fields later.</li>
|
||||
</ul>
|
||||
{{elif request.function=='step3':}}
|
||||
<ul class="unstyled">
|
||||
<li>List the fields for this table (do not include an id field, it is automatic), for example "name unique" or "birthday date" or "image upload" or "comments multiple" or "description wiki required"</li>
|
||||
<li>The first keyword(s) for each entry will be used to generate a name for the table field and its label. You can use spaces an other unicode characters.</li>
|
||||
<li>Keywords "string" (default), "text", "integer", "boolean", "float", "double", "file", "date", "time", "datetime", "file", "upload" will be used to determine the field type and they will not be made part of the field name.</ li>
|
||||
<li>For a reference field use a field name, followed by the name of the referenced table.</li>
|
||||
<li>Other special keywords are "required", "notnull" or "notempty", "unique". They map into equivalent validators but (at this time) should only be used with string and text types.</li>
|
||||
<li>The keywords "html" and "wiki" force a text type and set a representation for the field value as sanitized HTML and MARKMIN resepectively.</li>
|
||||
<li>string, integer and reference fields can be "multiple", i.e. multiple values will be allowed</li>
|
||||
<li>For the "auth_user" table do not add attributes to the default fields (username, first_name, last_name, password and email). They are handled automatically.</li>
|
||||
<li>Some fields will be added automatically upon creation and handled automatically: "created_by", "created_on", "modified_by", "modified_on", "active" (only active fields can be selected).</li>
|
||||
<li>For every table "table" another table "table_archive" is created and it contains the previous versions of each record. This is only accessible via appadmin or programmatically.</li>
|
||||
</ul>
|
||||
{{elif request.function=='step4':}}
|
||||
<ul class="unstyled">
|
||||
<li>List the names of the pages you want to create.</li>
|
||||
<li>Some pages are listed automatically because they expose Create/Read/Update/Delete for each tables you have created.</li>
|
||||
<li>All pages, except "error" and those with name starting in underscore willbe listed in the menu. You will be able to edit the menu later.</li>
|
||||
<li>You should have page "index", the starting point of your app, and page "error", where web2py will redirect to in case of error.</li>
|
||||
</ul>
|
||||
{{elif request.function=='step5':}}
|
||||
<ul class="unstyled">
|
||||
<li>Use the markmin syntax to add text to your pages.</li>
|
||||
</ul>
|
||||
{{elif request.function=='step6':}}
|
||||
<ul class="unstyled">
|
||||
<li>Almost done. Click on the button above to create your new app.</li>
|
||||
<li>Once done you will be able to edit it as any normal web2py app.</li>
|
||||
</ul>
|
||||
{{pass}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> <!-- /wizard form -->
|
||||
</div>
|
||||
|
||||
<div id="wizard_form" class="fl20 controls">
|
||||
|
||||
<!-- FORM -->
|
||||
|
||||
{{if 'step' in request.function:}}
|
||||
<h3>{{=T('Step')}} {{=step}}</h3>
|
||||
{{if request.function!='step1':}}
|
||||
{{=button(URL('step' + str(int(request.function[-1])-1)), T('back'))}}
|
||||
{{pass}}
|
||||
{{else:}}
|
||||
<h3>{{=T('Begin')}}</h3>
|
||||
{{pass}}
|
||||
{{if request.function in ('step1','step2','step3','step4','step5'):}}
|
||||
{{=button(URL('step6'), T('skip to generate'))}}
|
||||
{{pass}}
|
||||
<br /><br />
|
||||
{{if request.function in ('step1','step6'):}}
|
||||
<img src="{{=LAYOUTS_APP}}/static/plugin_layouts/layouts/{{=dict(session.app['params'])['layout_theme']}}/preview.png" alt="" align="right" id="preview"/>
|
||||
{{pass}}
|
||||
<div class="form">
|
||||
{{=form}}
|
||||
</div>
|
||||
<script>
|
||||
jQuery(function(){
|
||||
var t=jQuery('#no_table_layout_theme');
|
||||
t.change(function(){
|
||||
jQuery('#preview').attr('src','{{=LAYOUTS_APP}}/static/plugin_layouts/layouts/'+t.val()+'/preview.png');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- INSTRUCTIONS -->
|
||||
<div class="box">
|
||||
<h4>Instructions</h4>
|
||||
<div class="help">
|
||||
{{if request.function=='index':}}
|
||||
<ul>
|
||||
<li>Insert the name of a new app.</li>
|
||||
<li>If the app exists and was created with the wizard, you will be able to edit it, but any manual editing to the app <b>will be lost</b>.</li>
|
||||
</ul>
|
||||
{{elif request.function=='step1':}}
|
||||
<ul>
|
||||
<li>This Wizard will help you build a new web2py app.</li>
|
||||
<li>You can create an app with a name that already exists.</li>
|
||||
<li>If you do not have an email server set email server to "logging".</li>
|
||||
<li>If you want to use Janrain Engage for login: 1) Sign up for a <a href="http://www.janrain.com/products/engage">Janrain Engage</a> account; 2) Register you hostname, domain, and obtain an api key; 3) Set Login Config above to "domain:api_key".</li>
|
||||
<li>ATTENTION: you can use the wizard to download plugins BUT we cannot guarantee the stability or backward compatibility of plugins. Moreover plugins may conflict with each other. Anyway, we do recommend installing plugin "wiki" with adds CMS like capabilities to your app.</li>
|
||||
</ul>
|
||||
{{elif request.function=='step2':}}
|
||||
<ul>
|
||||
<li>List the names of table that you need.</li>
|
||||
<li>If you do not need authentication remove the table "auth_user".</li>
|
||||
<li>Press enter to create a new input row.</li>
|
||||
<li>Empty rows are ignored.</li>
|
||||
<li>Other tables for role based access control will be created automatically, and do not need to be listed.</li>
|
||||
<li>You will be able to add fields later.</li>
|
||||
</ul>
|
||||
{{elif request.function=='step3':}}
|
||||
<ul>
|
||||
<li>List the fields for this table (do not include an id field, it is automatic), for example "name unique" or "birthday date" or "image upload" or "comments multiple" or "description wiki required"</li>
|
||||
<li>The first keyword(s) for each entry will be used to generate a name for the table field and its label. You can use spaces an other unicode characters.</li>
|
||||
<li>Keywords "string" (default), "text", "integer", "boolean", "float", "double", "file", "date", "time", "datetime", "file", "upload" will be used to determine the field type and they will not be made part of the field name.</ li>
|
||||
<li>For a reference field use a field name, followed by the name of the referenced table.</li>
|
||||
<li>Other special keywords are "required", "notnull" or "notempty", "unique". They map into equivalent validators but (at this time) should only be used with string and text types.</li>
|
||||
<li>The keywords "html" and "wiki" force a text type and set a representation for the field value as sanitized HTML and MARKMIN resepectively.</li>
|
||||
<li>string, integer and reference fields can be "multiple", i.e. multiple values will be allowed</li>
|
||||
<li>For the "auth_user" table do not add attributes to the default fields (username, first_name, last_name, password and email). They are handled automatically.</li>
|
||||
<li>Some fields will be added automatically upon creation and handled automatically: "created_by", "created_on", "modified_by", "modified_on", "active" (only active fields can be selected).</li>
|
||||
<li>For every table "table" another table "table_archive" is created and it contains the previous versions of each record. This is only accessible via appadmin or programmatically.</li>
|
||||
</ul>
|
||||
{{elif request.function=='step4':}}
|
||||
<ul>
|
||||
<li>List the names of the pages you want to create.</li>
|
||||
<li>Some pages are listed automatically because they expose Create/Read/Update/Delete for each tables you have created.</li>
|
||||
<li>All pages, except "error" and those with name starting in underscore willbe listed in the menu. You will be able to edit the menu later.</li>
|
||||
<li>You should have page "index", the starting point of your app, and page "error", where web2py will redirect to in case of error.</li>
|
||||
</ul>
|
||||
{{elif request.function=='step5':}}
|
||||
<ul>
|
||||
<li>Use the markmin syntax to add text to your pages.</li>
|
||||
</ul>
|
||||
{{elif request.function=='step6':}}
|
||||
<ul>
|
||||
<li>Almost done. Click on the button above to create your new app.</li>
|
||||
<li>Once done you will be able to edit it as any normal web2py app.</li>
|
||||
</ul>
|
||||
{{pass}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
//jQuery(document).ready(function() {
|
||||
//jQuery(":input:visible:enabled:first").focus();
|
||||
//});
|
||||
</script>
|
||||
<!-- end "step" block -->
|
||||
1
applications/welcome/cron/crontab
Normal file
1
applications/welcome/cron/crontab
Normal file
@@ -0,0 +1 @@
|
||||
#crontab
|
||||
1
applications/welcome/static/403.html
Normal file
1
applications/welcome/static/403.html
Normal file
@@ -0,0 +1 @@
|
||||
403
|
||||
1
applications/welcome/static/404.html
Normal file
1
applications/welcome/static/404.html
Normal file
@@ -0,0 +1 @@
|
||||
404
|
||||
1
applications/welcome/static/500.html
Normal file
1
applications/welcome/static/500.html
Normal file
@@ -0,0 +1 @@
|
||||
500
|
||||
18
certificates/web2py.com/new-digitss.csr
Normal file
18
certificates/web2py.com/new-digitss.csr
Normal file
@@ -0,0 +1,18 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIICzjCCAbYCAQAwgYgxCzAJBgNVBAYTAlVTMREwDwYDVQQIEwhJbGxpbm9pczER
|
||||
MA8GA1UEBxMIT2FrIFBhcmsxDzANBgNVBAoTBndlYjJweTEXMBUGA1UEAxMOd3d3
|
||||
LndlYjJweS5jb20xKTAnBgkqhkiG9w0BCQEWGm1hc3NpbW8uZGlwaWVycm9AZ21h
|
||||
aWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6AX4oTjdBThw
|
||||
xdGEDtb+XhvyW58gC9il2z5ewp/AVwYUst1MYPF1jPLv23yn4jkN4c6OExlhgsVi
|
||||
YxsWq8fEg55SEBr3gpH608FOtwicEeIHwufP7OhHiOB1rhUa5B54xIIoh5AMKwIH
|
||||
qvPlLn8Pi8DJGdAoDwUTUsFLWJdt0/XQgjHQOeIrgXRvrGPLWQglQ3/8AqWZ2TLp
|
||||
raBZv9RgXJ8IlArwfEzfdQnfkrmAMOjsBRaf7krQMAF7n+R1SqNWQeFfw//FccC9
|
||||
seHvRkbawjyHL0VezmR/eAUGw8nYZuEjhUEZnrGpD4fRWSxfZuk7nx2EXKh4qOJL
|
||||
kVQHu5/ZOQIDAQABoAAwDQYJKoZIhvcNAQEFBQADggEBANjuO4viE6MpTVyMDJNv
|
||||
Cx60q4fq5ej9QU+KDb9A5wTHl6/KRJNd7EPJl07OP1Mm0D2Krp+GfLh7vVLKvxl1
|
||||
G1f4sDkXeAD1OhcqcUEBdS4CzLCYP0RdW9T77lQ5i43C+XBJH3RGzdgofjS41JNY
|
||||
mswCv66mSMb28PoRPYiGLfW/RKO27g+viYrVoJBikntjR86x7hwBUWjpOv+jBk3a
|
||||
jtE39KDj1ID/3eYrkdz3Hz65VvK4rFSY/TwTYzRrTO/4SZjwCZfgcy1BdFRn5aSK
|
||||
pB2fxDLEg/bydBdI78PtxocFBX7qZfm9VWpj8UfN0D+SAFUyesxEuQDPIKO5FHMm
|
||||
Otk=
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
27
certificates/web2py.com/new-digitss.key
Normal file
27
certificates/web2py.com/new-digitss.key
Normal file
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpgIBAAKCAQEA6AX4oTjdBThwxdGEDtb+XhvyW58gC9il2z5ewp/AVwYUst1M
|
||||
YPF1jPLv23yn4jkN4c6OExlhgsViYxsWq8fEg55SEBr3gpH608FOtwicEeIHwufP
|
||||
7OhHiOB1rhUa5B54xIIoh5AMKwIHqvPlLn8Pi8DJGdAoDwUTUsFLWJdt0/XQgjHQ
|
||||
OeIrgXRvrGPLWQglQ3/8AqWZ2TLpraBZv9RgXJ8IlArwfEzfdQnfkrmAMOjsBRaf
|
||||
7krQMAF7n+R1SqNWQeFfw//FccC9seHvRkbawjyHL0VezmR/eAUGw8nYZuEjhUEZ
|
||||
nrGpD4fRWSxfZuk7nx2EXKh4qOJLkVQHu5/ZOQIDAQABAoIBAQCAyI+wLPfApgsy
|
||||
QZCjDAI0Ch8Da9dFvAKTJpNCQ5lmtCFZBiwWwu8UROONWCt3DWP/Kb8CKtxM0XJC
|
||||
wA5dWoxg4cd62Pz4pD4suucOAOFfq63TKQfn3yWVe8DV1zEN3Tv7FqOYWwPl+0J2
|
||||
SNm0bSIb1+3HPhp9+7s1+8PucF6tfnyRMtZAXN0MURsMLHhxepi1hd1nxEhFt2gg
|
||||
F57CQVTMFnGZd9swSgJhFbMbQeBjBd/KSE8Jf+Gr3jMbpyQoqAsJrmikmz1ONvYA
|
||||
+FlIDxNFJZWXYTXld3amXXjPyDgc4VbmrtTTYHpZHjwecEf/Sj1J7MAGCXJoAwuF
|
||||
7LeByp1hAoGBAPoLl1VFyC0p3Iu2wViW1CxT2inb5eH7IuosPxG41vFKG/wom+Ww
|
||||
bT8BUwGwGXJv/PIMbAKbJ8z7SZtSkY4I+hL51r+rplwwnxW7AfuRB2wK3KEoBtUN
|
||||
EdmNlVW2DNIIJitv2Cszx7z1myRhaOj9xNz6cI5FhkGAMmE+rr8Q1e6LAoGBAO2M
|
||||
gjfu1/iI7QWXG9tS3/TE3n7JVXpt222iJh4Df6oYAa93snU0OAAV3DiURpDmbi43
|
||||
qpryiDgaM5ONCmOgYs3wM7Vpc5PdKtwZdIOcMP78Vk7hwaAsFn1k+WjIXlPcRWLi
|
||||
3iAAzjz+juXa6BGxBcQf2PmPuEEOwBrnVaLfIjPLAoGBAI6Boqs3zSFoVUjPTJxX
|
||||
we7Nj24B5J+JiNmbhApupRn5mb95yXf7uBeLgqpYmfgtuSSeTcSidumNYeMDCO/B
|
||||
T/0WpPyyMGskTtaMsVGV03wRKLM0Y8hy3XR3C+BAlEfz2wUwhiwBI9oexF/UoH0B
|
||||
fHxQw2tiVmToUk438lH0n2iHAoGBAN5iIPIN9j+kqAgIu7pqbmDuAME+6HfR6o9L
|
||||
MlX8voJVMRa8fuO8PATQcjbBkQJLxrAbyup9zMqAtPIYIra7ymOy0CWwD9RIQ7yD
|
||||
VBF1omTDhGUacbLqMy+23MqccboeRxLZAkuBlZGCWfKTKZiOWbCOhAi15C97iJpn
|
||||
IUN1ksZbAoGBANY7zwfUFPeKoChU92Jsub0daLGFBX8IRkRmDGPUvSHtMG2LRUdX
|
||||
s12Y2wCVX9nDwVHvVo1E+Xnc1UeXJZI6r9P0GnJqhTf/4Z9XULCb4E/nJdrd1zcq
|
||||
VYnb6p0ECh1N6syJ+YeBLG6aWKU0sLfri8LNxTFRza2lVP6aRLt+iE6M
|
||||
-----END RSA PRIVATE KEY-----
|
||||
BIN
dist/web2py-2.1.1.tar.gz
vendored
Normal file
BIN
dist/web2py-2.1.1.tar.gz
vendored
Normal file
Binary file not shown.
27
mkweb2pyenv
Executable file
27
mkweb2pyenv
Executable file
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env python
|
||||
import gluon
|
||||
from gluon.fileutils import untar
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
path = gluon.__path__
|
||||
out_path = os.getcwd()
|
||||
try:
|
||||
if sys.argv[1] and os.path.exists(sys.argv[1]):# To untar the web2py env to the selected path
|
||||
out_path = sys.argv[1]
|
||||
else:
|
||||
os.mkdir(sys.argv[1])
|
||||
out_path = sys.argv[1]
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
print "Creating a web2py env in: " + out_path
|
||||
untar(os.path.join(path[0],'env.tar'),out_path)
|
||||
except:
|
||||
print "Failed to create the web2py env"
|
||||
print "Please reinstall web2py from pip"
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
24
runweb2py
Normal file
24
runweb2py
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
path = os.getcwd()
|
||||
try:
|
||||
if sys.argv[1] and os.path.exists(sys.argv[1]):
|
||||
path = sys.argv[1]
|
||||
except:
|
||||
pass
|
||||
|
||||
os.chdir(path)
|
||||
sys.path = [path]+[p for p in sys.path if not p==path]
|
||||
# import gluon.import_all ##### This should be uncommented for py2exe.py
|
||||
import gluon.widget
|
||||
|
||||
def main():
|
||||
# Start Web2py and Web2py cron service!
|
||||
gluon.widget.start(cron=True)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
0
storage.sqlite
Normal file
0
storage.sqlite
Normal file
640
temps/asynwsgi.py
Normal file
640
temps/asynwsgi.py
Normal file
@@ -0,0 +1,640 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
docstring
|
||||
"""
|
||||
|
||||
__author__ = "Gu Yingbo (tensiongyb@gmail.com)"
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
import base64
|
||||
import asyncore
|
||||
import asynchat
|
||||
import rfc822
|
||||
import socket
|
||||
import thread
|
||||
import signal
|
||||
import collections
|
||||
from traceback import format_exc
|
||||
from urllib import unquote, splitquery
|
||||
from urlparse import urlparse
|
||||
try:
|
||||
import cStringIO as StringIO
|
||||
except ImportError:
|
||||
import StringIO
|
||||
|
||||
RN = '\r\n'
|
||||
RNRN = '\r\n\r\n'
|
||||
QUOTED_SLASH = re.compile("(?i)%2F")
|
||||
|
||||
COMMA_SEPARATED_HEADERS = ['ACCEPT', 'ACCEPT-CHARSET', 'ACCEPT-ENCODING',
|
||||
'ACCEPT-LANGUAGE', 'ACCEPT-RANGES', 'ALLOW', 'CACHE-CONTROL',
|
||||
'CONNECTION', 'CONTENT-ENCODING', 'CONTENT-LANGUAGE', 'EXPECT',
|
||||
'IF-MATCH', 'IF-NONE-MATCH', 'PRAGMA', 'PROXY-AUTHENTICATE', 'TE',
|
||||
'TRAILER', 'TRANSFER-ENCODING', 'UPGRADE', 'VARY', 'VIA', 'WARNING',
|
||||
'WWW-AUTHENTICATE']
|
||||
|
||||
class FIFO(list):
|
||||
def is_empty(self):
|
||||
return len(self)==0
|
||||
def push(self,data):
|
||||
self.append(data)
|
||||
def first(self):
|
||||
return self[0] if len(self) else None
|
||||
|
||||
class RequestHandler(asynchat.async_chat):
|
||||
|
||||
def __init__(self, sock, server):
|
||||
asynchat.async_chat.__init__(self, sock)
|
||||
self.server = server
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
self.ac_in_buffer = ''
|
||||
self.ac_out_buffer = ''
|
||||
self.producer_fifo.clear() # = collections.deque()
|
||||
self.set_terminator(RNRN)
|
||||
self.process = "reading headers"
|
||||
self.started_response = False
|
||||
self.status = ""
|
||||
self.outheaders = []
|
||||
self.sent_headers = False
|
||||
self.close_connection = False
|
||||
self.chunked_write = False
|
||||
|
||||
self.rfile = StringIO.StringIO()
|
||||
|
||||
self.environ = {
|
||||
"wsgi.version": (1, 0),
|
||||
"wsgi.url_scheme": "http",
|
||||
"wsgi.multithread": False,
|
||||
"wsgi.multiprocess": False,
|
||||
"wsgi.run_once": False,
|
||||
"wsgi.errors": sys.stderr,
|
||||
}
|
||||
|
||||
def collect_incoming_data(self, data):
|
||||
"""Buffer the data"""
|
||||
if self.process == "reading chunked":
|
||||
self.line_buffer += data
|
||||
else:
|
||||
self.rfile.write(data)
|
||||
|
||||
def found_terminator(self):
|
||||
if self.process == "reading headers":
|
||||
self.rfile.write(RNRN)
|
||||
self.rfile.seek(0)
|
||||
try:
|
||||
self.parse_request()
|
||||
except:
|
||||
self.simple_response("500 Internal Server Error", format_exc())
|
||||
return
|
||||
|
||||
if not self.read_chunked:
|
||||
if self.environ["REQUEST_METHOD"].upper() == "POST":
|
||||
cl = int(self.environ["CONTENT_LENGTH"])
|
||||
self.rfile = StringIO.StringIO()
|
||||
self.environ["wsgi.input"] = self.rfile
|
||||
self.process = "dealing post"
|
||||
self.set_terminator(cl)
|
||||
else:
|
||||
return self.wsgi_response()
|
||||
else:
|
||||
self.rfile = StringIO.StringIO()
|
||||
self.environ["wsgi.input"] = self.rfile
|
||||
self.process = "reading chunked"
|
||||
self.set_terminator(RN)
|
||||
self.line_buffer = ""
|
||||
self.cl = 0
|
||||
elif self.process == "dealing post":
|
||||
self.rfile.seek(0)
|
||||
return self.wsgi_response()
|
||||
elif self.process == "reading chunked":
|
||||
line = self.line_buffer.split(";", 1)
|
||||
chunk_size = int(line.pop(0), 16)
|
||||
if chunk_size <= 0:
|
||||
self.process = "reading tail headers"
|
||||
self.set_terminator(RNRN)
|
||||
else:
|
||||
self.cl += chunk_size
|
||||
self.process = "get chunked"
|
||||
self.set_terminator(self.cl+2) # browsers sometimes over-send
|
||||
elif self.process == "get chunked":
|
||||
crlf = self.rfile.getvalue()[-2:]
|
||||
if not crlf != RN:
|
||||
self.simple_response("400 Bad Request",
|
||||
"Bad chunked transfer coding "
|
||||
"(expected '\\r\\n', got %r)" % crlf)
|
||||
return
|
||||
else:
|
||||
self.process = "reading chunked"
|
||||
self.set_terminator(RN)
|
||||
self.rfile.seek(-2, 2)
|
||||
self.rfile.truncate()
|
||||
elif self.process == "reading tail headers":
|
||||
self.read_headers()
|
||||
self.rfile.seek(0)
|
||||
self.environ["CONTENT_LENGTH"] = str(self.cl) or ""
|
||||
return self.wsgi_response()
|
||||
|
||||
def reset_when_done(self):
|
||||
self.producer_fifo.append('\0')
|
||||
|
||||
def refill_buffer (self):
|
||||
while 1:
|
||||
if len(self.producer_fifo):
|
||||
p = self.producer_fifo.first()
|
||||
# a 'None' in the producer fifo is a sentinel,
|
||||
# telling us to close the channel.
|
||||
if p == 0:
|
||||
if not self.ac_out_buffer:
|
||||
self.producer_fifo.pop()
|
||||
self.reset()
|
||||
return
|
||||
elif p is None:
|
||||
if not self.ac_out_buffer:
|
||||
self.producer_fifo.pop()
|
||||
self.close()
|
||||
return
|
||||
elif isinstance(p, str):
|
||||
self.producer_fifo.pop()
|
||||
self.ac_out_buffer = self.ac_out_buffer + p
|
||||
return
|
||||
data = p.more()
|
||||
if data:
|
||||
self.ac_out_buffer = self.ac_out_buffer + data
|
||||
return
|
||||
else:
|
||||
self.producer_fifo.pop()
|
||||
else:
|
||||
return
|
||||
|
||||
def wsgi_response(self):
|
||||
try:
|
||||
self.respond()
|
||||
except:
|
||||
self.simple_response("500 Internal Server Error", format_exc())
|
||||
else:
|
||||
if self.close_connection or ( not self.server.keep_going ):
|
||||
self.close_when_done()
|
||||
else:
|
||||
self.reset_when_done()
|
||||
|
||||
def readable(self):
|
||||
return self.server.keep_going and not self.writable() and \
|
||||
asynchat.async_chat.readable(self)
|
||||
|
||||
def handle_expt(self):
|
||||
asynchat.async_chat.handle_expt(self)
|
||||
self.close()
|
||||
|
||||
def handle_error(self):
|
||||
asynchat.async_chat.handle_error(self)
|
||||
self.close()
|
||||
|
||||
def parse_request(self):
|
||||
"""
|
||||
Parse the next HTTP request start-line and message-headers.
|
||||
HTTP/1.1 connections are persistent by default. If a client
|
||||
requests a page, then idles (leaves the connection open),
|
||||
then rfile.readline() will raise socket.error("timed out").
|
||||
Note that it does this based on the value given to settimeout(),
|
||||
and doesn't need the client to request or acknowledge the close
|
||||
(although your TCP stack might suffer for it: cf Apache's history
|
||||
with FIN_WAIT_2).
|
||||
"""
|
||||
request_line = self.rfile.readline()
|
||||
if not request_line:
|
||||
# Force self.ready = False so the connection will close.
|
||||
self.ready = False
|
||||
return
|
||||
|
||||
if request_line == RN:
|
||||
# RFC 2616 sec 4.1: "...if the server is reading the protocol
|
||||
# stream at the beginning of a message and receives a CRLF
|
||||
# first, it should ignore the CRLF."
|
||||
# But only ignore one leading line! else we enable a DoS.
|
||||
request_line = self.rfile.readline()
|
||||
if not request_line:
|
||||
self.ready = False
|
||||
return
|
||||
|
||||
server = self.server
|
||||
environ = self.environ
|
||||
environ["SERVER_SOFTWARE"] = "%s WSGI Server" % server.version
|
||||
|
||||
method, path, req_protocol = request_line.strip().split(" ", 2)
|
||||
environ["REQUEST_METHOD"] = method
|
||||
|
||||
# path may be an abs_path (including "http://host.domain.tld");
|
||||
scheme, location, path, params, qs, frag = urlparse(path)
|
||||
|
||||
if frag:
|
||||
self.simple_response("400 Bad Request",
|
||||
"Illegal #fragment in Request-URI.")
|
||||
return
|
||||
|
||||
if scheme:
|
||||
environ["wsgi.url_scheme"] = scheme
|
||||
if params:
|
||||
path = path + ";" + params
|
||||
|
||||
# Unquote the path+params (e.g. "/this%20path" -> "this path").
|
||||
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
|
||||
#
|
||||
# But note that "...a URI must be separated into its components
|
||||
# before the escaped characters within those components can be
|
||||
# safely decoded." http://www.ietf.org/rfc/rfc2396.txt, sec 2.4.2
|
||||
atoms = [unquote(x) for x in QUOTED_SLASH.split(path)]
|
||||
path = "%2F".join(atoms)
|
||||
|
||||
environ["SCRIPT_NAME"] = ""
|
||||
environ["PATH_INFO"] = path
|
||||
##if path == "*":
|
||||
## # This means, of course, that the last wsgi_app (shortest path)
|
||||
## # will always handle a URI of "*".
|
||||
## environ["SCRIPT_NAME"] = ""
|
||||
## environ["PATH_INFO"] = "*"
|
||||
## self.wsgi_app = server.mount_points[-1][1]
|
||||
##else:
|
||||
## for mount_point, wsgi_app in server.mount_points:
|
||||
## # The mount_points list should be sorted by length, descending.
|
||||
## if path.startswith(mount_point + "/") or path == mount_point:
|
||||
## environ["SCRIPT_NAME"] = mount_point
|
||||
## environ["PATH_INFO"] = path[len(mount_point):]
|
||||
## self.wsgi_app = wsgi_app
|
||||
## break
|
||||
## else:
|
||||
## self.simple_response("404 Not Found")
|
||||
## return
|
||||
|
||||
# Note that, like wsgiref and most other WSGI servers,
|
||||
# we unquote the path but not the query string.
|
||||
environ["QUERY_STRING"] = qs
|
||||
|
||||
# Compare request and server HTTP protocol versions, in case our
|
||||
# server does not support the requested protocol. Limit our output
|
||||
# to min(req, server). We want the following output:
|
||||
# request server actual written supported response
|
||||
# protocol protocol response protocol feature set
|
||||
# a 1.0 1.0 1.0 1.0
|
||||
# b 1.0 1.1 1.1 1.0
|
||||
# c 1.1 1.0 1.0 1.0
|
||||
# d 1.1 1.1 1.1 1.1
|
||||
# Notice that, in (b), the response will be "HTTP/1.1" even though
|
||||
# the client only understands 1.0. RFC 2616 10.5.6 says we should
|
||||
# only return 505 if the _major_ version is different.
|
||||
rp = int(req_protocol[5]), int(req_protocol[7])
|
||||
sp = int(server.protocol[5]), int(server.protocol[7])
|
||||
if sp[0] != rp[0]:
|
||||
self.simple_response("505 HTTP Version Not Supported")
|
||||
return
|
||||
# Bah. "SERVER_PROTOCOL" is actually the REQUEST protocol.
|
||||
environ["SERVER_PROTOCOL"] = req_protocol
|
||||
# set a non-standard environ entry so the WSGI app can know what
|
||||
# the *real* server protocol is (and what features to support).
|
||||
# See http://www.faqs.org/rfcs/rfc2145.html.
|
||||
environ["ACTUAL_SERVER_PROTOCOL"] = server.protocol
|
||||
self.response_protocol = "HTTP/%s.%s" % min(rp, sp)
|
||||
|
||||
# If the Request-URI was an absoluteURI, use its location atom.
|
||||
if location:
|
||||
environ["SERVER_NAME"] = location
|
||||
|
||||
# then all the http headers
|
||||
try:
|
||||
self.read_headers()
|
||||
except ValueError, ex:
|
||||
self.simple_response("400 Bad Request", repr(ex.args))
|
||||
return
|
||||
|
||||
creds = environ.get("HTTP_AUTHORIZATION", "").split(" ", 1)
|
||||
environ["AUTH_TYPE"] = creds[0]
|
||||
if creds[0].lower() == 'basic':
|
||||
user, pw = base64.decodestring(creds[1]).split(":", 1)
|
||||
environ["REMOTE_USER"] = user
|
||||
|
||||
# Persistent connection support
|
||||
if self.response_protocol == "HTTP/1.1":
|
||||
if environ.get("HTTP_CONNECTION", "") == "close":
|
||||
self.close_connection = True
|
||||
else:
|
||||
# HTTP/1.0
|
||||
if environ.get("HTTP_CONNECTION", "") != "Keep-Alive":
|
||||
self.close_connection = True
|
||||
|
||||
# Transfer-Encoding support
|
||||
te = None
|
||||
if self.response_protocol == "HTTP/1.1":
|
||||
te = environ.get("HTTP_TRANSFER_ENCODING")
|
||||
if te:
|
||||
te = [x.strip().lower() for x in te.split(",") if x.strip()]
|
||||
|
||||
read_chunked = False
|
||||
|
||||
if te:
|
||||
for enc in te:
|
||||
if enc == "chunked":
|
||||
read_chunked = True
|
||||
else:
|
||||
# Note that, even if we see "chunked", we must reject
|
||||
# if there is an extension we don't recognize.
|
||||
self.simple_response("501 Unimplemented")
|
||||
self.close_connection = True
|
||||
return
|
||||
|
||||
self.read_chunked = read_chunked
|
||||
return
|
||||
|
||||
if read_chunked:
|
||||
if not self.decode_chunked():
|
||||
return
|
||||
|
||||
# From PEP 333:
|
||||
# "Servers and gateways that implement HTTP 1.1 must provide
|
||||
# transparent support for HTTP 1.1's "expect/continue" mechanism.
|
||||
# This may be done in any of several ways:
|
||||
# 1. Respond to requests containing an Expect: 100-continue request
|
||||
# with an immediate "100 Continue" response, and proceed normally.
|
||||
# 2. Proceed with the request normally, but provide the application
|
||||
# with a wsgi.input stream that will send the "100 Continue"
|
||||
# response if/when the application first attempts to read from
|
||||
# the input stream. The read request must then remain blocked
|
||||
# until the client responds.
|
||||
# 3. Wait until the client decides that the server does not support
|
||||
# expect/continue, and sends the request body on its own.
|
||||
# (This is suboptimal, and is not recommended.)
|
||||
#
|
||||
# We used to do 3, but are now doing 1. Maybe we'll do 2 someday,
|
||||
# but it seems like it would be a big slowdown for such a rare case.
|
||||
if environ.get("HTTP_EXPECT", "") == "100-continue":
|
||||
self.simple_response(100)
|
||||
|
||||
self.ready = True
|
||||
|
||||
def new_header(self,k,v):
|
||||
if k:
|
||||
environ = self.environ
|
||||
envname = 'HTTP_'+k
|
||||
if k in COMMA_SEPARATED_HEADERS:
|
||||
existing = environ.get(envname)
|
||||
if existing:
|
||||
v = ", ".join((existing, v))
|
||||
environ[envname] = v
|
||||
|
||||
def read_headers(self):
|
||||
"""Read header lines from the incoming stream."""
|
||||
k = v = None
|
||||
while True:
|
||||
line = self.rfile.readline()
|
||||
if not line or '\0' in line:
|
||||
# No more data--illegal end of headers
|
||||
raise ValueError("Illegal headers")
|
||||
elif line == RN:
|
||||
# Normal end of headers
|
||||
self.new_header(k,v)
|
||||
break
|
||||
elif line[0] in ' \t':
|
||||
v += line.strip()
|
||||
else:
|
||||
self.new_header(k,v)
|
||||
k, v = line.split(":", 1)
|
||||
k, v = k.strip().upper(), v.strip()
|
||||
|
||||
environ = self.environ
|
||||
ct = environ.pop("HTTP_CONTENT_TYPE", None)
|
||||
if ct:
|
||||
environ["CONTENT_TYPE"] = ct
|
||||
cl = environ.pop("HTTP_CONTENT_LENGTH", None)
|
||||
if cl:
|
||||
environ["CONTENT_LENGTH"] = cl
|
||||
|
||||
def decode_chunked(self):
|
||||
"""Decode the 'chunked' transfer coding."""
|
||||
cl = 0
|
||||
data = StringIO.StringIO()
|
||||
while True:
|
||||
line = self.rfile.readline().strip().split(";", 1)
|
||||
chunk_size = int(line.pop(0), 16)
|
||||
if chunk_size <= 0:
|
||||
break
|
||||
## if line: chunk_extension = line[0]
|
||||
cl += chunk_size
|
||||
data.write(self.rfile.read(chunk_size))
|
||||
crlf = self.rfile.read(2)
|
||||
if crlf != RN:
|
||||
self.simple_response("400 Bad Request",
|
||||
"Bad chunked transfer coding "
|
||||
"(expected '\\r\\n', got %r)" % crlf)
|
||||
return
|
||||
|
||||
# Grab any trailer headers
|
||||
self.read_headers()
|
||||
|
||||
data.seek(0)
|
||||
self.environ["wsgi.input"] = data
|
||||
self.environ["CONTENT_LENGTH"] = str(cl) or ""
|
||||
return True
|
||||
|
||||
def respond(self):
|
||||
"""
|
||||
Call the appropriate WSGI app and write its iterable output.
|
||||
"""
|
||||
response = self.server.wsgi_app(self.environ, self.start_response)
|
||||
try:
|
||||
for chunk in response:
|
||||
# "The start_response callable must not actually transmit
|
||||
# the response headers. Instead, it must store them for the
|
||||
# server or gateway to transmit only after the first
|
||||
# iteration of the application return value that yields
|
||||
# a NON-EMPTY string, or upon the application's first
|
||||
# invocation of the write() callable." (PEP 333)
|
||||
if chunk:
|
||||
print 'sending',chunk
|
||||
self.write(chunk)
|
||||
print 'sent!'
|
||||
finally:
|
||||
if hasattr(response, "close"):
|
||||
response.close()
|
||||
|
||||
if not self.sent_headers:
|
||||
self.send_headers()
|
||||
if self.chunked_write:
|
||||
self.push("0\r\n")
|
||||
|
||||
def simple_response(self, status, msg=""):
|
||||
"""Write a simple response back to the client."""
|
||||
status = str(status)
|
||||
buf = ["%s %s\r\n" % (self.server.protocol, status),
|
||||
"Content-Length: %s\r\n" % len(msg)]
|
||||
|
||||
if status[:3] == "413" and self.response_protocol == 'HTTP/1.1':
|
||||
# Request Entity Too Large
|
||||
self.close_connection = True
|
||||
buf.append("Connection: close\r\n")
|
||||
|
||||
buf.append(RN)
|
||||
if msg:
|
||||
buf.append(msg)
|
||||
self.push(''.join(buf))
|
||||
|
||||
if self.close_connection or ( not self.server.keep_going ):
|
||||
self.close_when_done()
|
||||
else:
|
||||
self.reset_when_done()
|
||||
|
||||
def start_response(self, status, headers, exc_info = None):
|
||||
"""WSGI callable to begin the HTTP response."""
|
||||
if self.started_response:
|
||||
if not exc_info:
|
||||
raise AssertionError("WSGI start_response called a second "
|
||||
"time with no exc_info.")
|
||||
else:
|
||||
try:
|
||||
raise exc_info[0], exc_info[1], exc_info[2]
|
||||
finally:
|
||||
exc_info = None
|
||||
self.started_response = True
|
||||
self.status = status
|
||||
self.outheaders.extend(headers)
|
||||
return self.write
|
||||
|
||||
def write(self, chunk):
|
||||
"""
|
||||
WSGI callable to write unbuffered data to the client.
|
||||
|
||||
This method is also used internally by start_response (to write
|
||||
data from the iterable returned by the WSGI application).
|
||||
"""
|
||||
if not self.started_response:
|
||||
raise AssertionError("WSGI write called before start_response.")
|
||||
|
||||
if not self.sent_headers:
|
||||
self.send_headers()
|
||||
|
||||
if self.chunked_write and chunk:
|
||||
buf = [hex(len(chunk))[2:], RN, chunk, RN]
|
||||
self.push(''.join(buf))
|
||||
else:
|
||||
self.push(chunk)
|
||||
|
||||
def send_headers(self):
|
||||
"""
|
||||
Assert, process, and send the HTTP response message-headers.
|
||||
"""
|
||||
self.sent_headers = True
|
||||
hkeys = [key.lower() for key, value in self.outheaders]
|
||||
status = int(self.status[:3])
|
||||
|
||||
if status == 413:
|
||||
# Request Entity Too Large. Close conn to avoid garbage.
|
||||
self.close_connection = True
|
||||
elif "content-length" not in hkeys:
|
||||
# "All 1xx (informational), 204 (no content),
|
||||
# and 304 (not modified) responses MUST NOT
|
||||
# include a message-body." So no point chunking.
|
||||
if status < 200 or status in (204, 205, 304):
|
||||
pass
|
||||
else:
|
||||
if self.response_protocol == 'HTTP/1.1':
|
||||
# Use the chunked transfer-coding
|
||||
self.chunked_write = True
|
||||
self.outheaders.append(("Transfer-Encoding", "chunked"))
|
||||
else:
|
||||
# Closing the conn is the only way to determine len.
|
||||
self.close_connection = True
|
||||
|
||||
if "connection" not in hkeys:
|
||||
if self.response_protocol == 'HTTP/1.1':
|
||||
if self.close_connection:
|
||||
self.outheaders.append(("Connection", "close"))
|
||||
else:
|
||||
if not self.close_connection:
|
||||
self.outheaders.append(("Connection", "Keep-Alive"))
|
||||
|
||||
if "date" not in hkeys:
|
||||
self.outheaders.append(("Date", rfc822.formatdate()))
|
||||
|
||||
server = self.server
|
||||
|
||||
if "server" not in hkeys:
|
||||
self.outheaders.append(("Server", server.version))
|
||||
|
||||
buf = [server.protocol, " ", self.status, RN]
|
||||
try:
|
||||
buf += [k + ": " + v + RN for k, v in self.outheaders]
|
||||
except TypeError:
|
||||
if not isinstance(k, str):
|
||||
raise TypeError("WSGI response header key %r is not a string.")
|
||||
if not isinstance(v, str):
|
||||
raise TypeError("WSGI response header value %r is not a string.")
|
||||
else:
|
||||
raise
|
||||
buf.append(RN)
|
||||
self.push(''.join(buf))
|
||||
|
||||
class WSGIServer(asyncore.dispatcher):
|
||||
version = "Asynwsgi Server/1.0 alpha"
|
||||
protocol = "HTTP/1.1"
|
||||
def __init__(self, bind_addr, wsgi_app, server_name=None):
|
||||
asyncore.dispatcher.__init__ (self)
|
||||
self.create_socket (socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.set_reuse_addr()
|
||||
self.bind(bind_addr)
|
||||
self.listen(1024)
|
||||
self.keep_going = True
|
||||
self.wsgi_app = wsgi_app
|
||||
|
||||
if not server_name:
|
||||
server_name = socket.gethostname()
|
||||
self.server_name = server_name
|
||||
|
||||
def writable(self):
|
||||
return False
|
||||
|
||||
def readable(self):
|
||||
return self.accepting
|
||||
|
||||
def handle_accept(self):
|
||||
try:
|
||||
conn, addr = self.accept()
|
||||
except:
|
||||
return
|
||||
RequestHandler(conn, self)
|
||||
|
||||
def reload(self, signum, frame):
|
||||
print 'reloading...'
|
||||
self.keep_going = False
|
||||
self.close()
|
||||
|
||||
def stop(self, signum, frame):
|
||||
asyncore.close_all()
|
||||
|
||||
def start(self):
|
||||
signal.signal(signal.SIGTERM, self.stop)
|
||||
signal.signal(signal.SIGINT, self.stop)
|
||||
asyncore.loop(timeout=0.1, use_poll=False)
|
||||
|
||||
def demo_app(environ, start_response):
|
||||
write = start_response('200 OK', [('content-type', 'text/html')])
|
||||
return ["<html><body><h1>Hello World!</h1><br />%s</body></html>"%time.ctime()]
|
||||
|
||||
def test_client(address='127.0.0.1:8000'):
|
||||
time.sleep(3)
|
||||
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
ip,port = address.split(':',1)
|
||||
server.connect((ip,int(port)))
|
||||
server.send('GET /\r\n\r\n')
|
||||
while True:
|
||||
sys.stdout.write(server.recv(1))
|
||||
sys.stdout.write('CLOSE\n')
|
||||
|
||||
if __name__ == "__main__":
|
||||
#thread.start_new_thread(test_client,())
|
||||
#thread.start_new_thread(test_client,())
|
||||
#thread.start_new_thread(test_client,())
|
||||
WSGIServer(('127.0.0.1', 8000), demo_app).start()
|
||||
630
temps/asynwsgi2.py
Normal file
630
temps/asynwsgi2.py
Normal file
@@ -0,0 +1,630 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
docstring
|
||||
"""
|
||||
|
||||
__author__ = "Gu Yingbo (tensiongyb@gmail.com)"
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
import base64
|
||||
import asyncore
|
||||
import asynchat
|
||||
import rfc822
|
||||
import socket
|
||||
import thread
|
||||
import signal
|
||||
from traceback import format_exc
|
||||
from urllib import unquote, splitquery
|
||||
from urlparse import urlparse
|
||||
try:
|
||||
import cStringIO as StringIO
|
||||
except ImportError:
|
||||
import StringIO
|
||||
|
||||
RN = '\r\n'
|
||||
RNRN = '\r\n\r\n'
|
||||
QUOTED_SLASH = re.compile("(?i)%2F")
|
||||
|
||||
COMMA_SEPARATED_HEADERS = ['ACCEPT', 'ACCEPT-CHARSET', 'ACCEPT-ENCODING',
|
||||
'ACCEPT-LANGUAGE', 'ACCEPT-RANGES', 'ALLOW', 'CACHE-CONTROL',
|
||||
'CONNECTION', 'CONTENT-ENCODING', 'CONTENT-LANGUAGE', 'EXPECT',
|
||||
'IF-MATCH', 'IF-NONE-MATCH', 'PRAGMA', 'PROXY-AUTHENTICATE', 'TE',
|
||||
'TRAILER', 'TRANSFER-ENCODING', 'UPGRADE', 'VARY', 'VIA', 'WARNING',
|
||||
'WWW-AUTHENTICATE']
|
||||
|
||||
class RequestHandler(asynchat.async_chat):
|
||||
|
||||
def __init__(self, sock, server):
|
||||
asynchat.async_chat.__init__(self, sock)
|
||||
self.server = server
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
self.ac_in_buffer = ''
|
||||
self.ac_out_buffer = ''
|
||||
self.producer_fifo = asynchat.fifo()
|
||||
self.set_terminator(RNRN)
|
||||
self.process = "reading headers"
|
||||
self.started_response = False
|
||||
self.status = ""
|
||||
self.outheaders = []
|
||||
self.sent_headers = False
|
||||
self.close_connection = False
|
||||
self.chunked_write = False
|
||||
|
||||
self.rfile = StringIO.StringIO()
|
||||
|
||||
self.environ = {
|
||||
"wsgi.version": (1, 0),
|
||||
"wsgi.url_scheme": "http",
|
||||
"wsgi.multithread": False,
|
||||
"wsgi.multiprocess": False,
|
||||
"wsgi.run_once": False,
|
||||
"wsgi.errors": sys.stderr,
|
||||
}
|
||||
|
||||
def collect_incoming_data(self, data):
|
||||
"""Buffer the data"""
|
||||
if self.process == "reading chunked":
|
||||
self.line_buffer += data
|
||||
else:
|
||||
self.rfile.write(data)
|
||||
|
||||
def found_terminator(self):
|
||||
if self.process == "reading headers":
|
||||
self.rfile.write(RNRN)
|
||||
self.rfile.seek(0)
|
||||
try:
|
||||
self.parse_request()
|
||||
except:
|
||||
self.simple_response("500 Internal Server Error", format_exc())
|
||||
return
|
||||
|
||||
if not self.read_chunked:
|
||||
if self.environ["REQUEST_METHOD"].upper() == "POST":
|
||||
cl = int(self.environ["CONTENT_LENGTH"])
|
||||
self.rfile = StringIO.StringIO()
|
||||
self.environ["wsgi.input"] = self.rfile
|
||||
self.process = "dealing post"
|
||||
self.set_terminator(cl)
|
||||
else:
|
||||
return self.wsgi_response()
|
||||
else:
|
||||
self.rfile = StringIO.StringIO()
|
||||
self.environ["wsgi.input"] = self.rfile
|
||||
self.process = "reading chunked"
|
||||
self.set_terminator(RN)
|
||||
self.line_buffer = ""
|
||||
self.cl = 0
|
||||
elif self.process == "dealing post":
|
||||
self.rfile.seek(0)
|
||||
return self.wsgi_response()
|
||||
elif self.process == "reading chunked":
|
||||
line = self.line_buffer.split(";", 1)
|
||||
chunk_size = int(line.pop(0), 16)
|
||||
if chunk_size <= 0:
|
||||
self.process = "reading tail headers"
|
||||
self.set_terminator(RNRN)
|
||||
else:
|
||||
self.cl += chunk_size
|
||||
self.process = "get chunked"
|
||||
self.set_terminator(self.cl+2) # browsers sometimes over-send
|
||||
elif self.process == "get chunked":
|
||||
crlf = self.rfile.getvalue()[-2:]
|
||||
if not crlf != RN:
|
||||
self.simple_response("400 Bad Request",
|
||||
"Bad chunked transfer coding "
|
||||
"(expected '\\r\\n', got %r)" % crlf)
|
||||
return
|
||||
else:
|
||||
self.process = "reading chunked"
|
||||
self.set_terminator(RN)
|
||||
self.rfile.seek(-2, 2)
|
||||
self.rfile.truncate()
|
||||
elif self.process == "reading tail headers":
|
||||
self.read_headers()
|
||||
self.rfile.seek(0)
|
||||
self.environ["CONTENT_LENGTH"] = str(self.cl) or ""
|
||||
return self.wsgi_response()
|
||||
|
||||
def reset_when_done(self):
|
||||
self.producer_fifo.push(0)
|
||||
|
||||
def refill_buffer (self):
|
||||
while 1:
|
||||
if len(self.producer_fifo):
|
||||
p = self.producer_fifo.first()
|
||||
# a 'None' in the producer fifo is a sentinel,
|
||||
# telling us to close the channel.
|
||||
if p == 0:
|
||||
if not self.ac_out_buffer:
|
||||
self.producer_fifo.pop()
|
||||
self.reset()
|
||||
return
|
||||
elif p is None:
|
||||
if not self.ac_out_buffer:
|
||||
self.producer_fifo.pop()
|
||||
self.close()
|
||||
return
|
||||
elif isinstance(p, str):
|
||||
self.producer_fifo.pop()
|
||||
self.ac_out_buffer = self.ac_out_buffer + p
|
||||
return
|
||||
data = p.more()
|
||||
if data:
|
||||
self.ac_out_buffer = self.ac_out_buffer + data
|
||||
return
|
||||
else:
|
||||
self.producer_fifo.pop()
|
||||
else:
|
||||
return
|
||||
|
||||
def wsgi_response(self):
|
||||
try:
|
||||
self.respond()
|
||||
except:
|
||||
self.simple_response("500 Internal Server Error", format_exc())
|
||||
else:
|
||||
if self.close_connection or ( not self.server.keep_going ):
|
||||
self.close_when_done()
|
||||
else:
|
||||
self.reset_when_done()
|
||||
|
||||
def readable(self):
|
||||
return self.server.keep_going and not self.writable() and \
|
||||
asynchat.async_chat.readable(self)
|
||||
|
||||
def handle_expt(self):
|
||||
asynchat.async_chat.handle_expt(self)
|
||||
self.close()
|
||||
|
||||
def handle_error(self):
|
||||
asynchat.async_chat.handle_error(self)
|
||||
self.close()
|
||||
|
||||
def parse_request(self):
|
||||
"""
|
||||
Parse the next HTTP request start-line and message-headers.
|
||||
HTTP/1.1 connections are persistent by default. If a client
|
||||
requests a page, then idles (leaves the connection open),
|
||||
then rfile.readline() will raise socket.error("timed out").
|
||||
Note that it does this based on the value given to settimeout(),
|
||||
and doesn't need the client to request or acknowledge the close
|
||||
(although your TCP stack might suffer for it: cf Apache's history
|
||||
with FIN_WAIT_2).
|
||||
"""
|
||||
request_line = self.rfile.readline()
|
||||
if not request_line:
|
||||
# Force self.ready = False so the connection will close.
|
||||
self.ready = False
|
||||
return
|
||||
|
||||
if request_line == RN:
|
||||
# RFC 2616 sec 4.1: "...if the server is reading the protocol
|
||||
# stream at the beginning of a message and receives a CRLF
|
||||
# first, it should ignore the CRLF."
|
||||
# But only ignore one leading line! else we enable a DoS.
|
||||
request_line = self.rfile.readline()
|
||||
if not request_line:
|
||||
self.ready = False
|
||||
return
|
||||
|
||||
server = self.server
|
||||
environ = self.environ
|
||||
environ["SERVER_SOFTWARE"] = "%s WSGI Server" % server.version
|
||||
|
||||
method, path, req_protocol = request_line.strip().split(" ", 2)
|
||||
environ["REQUEST_METHOD"] = method
|
||||
|
||||
# path may be an abs_path (including "http://host.domain.tld");
|
||||
scheme, location, path, params, qs, frag = urlparse(path)
|
||||
|
||||
if frag:
|
||||
self.simple_response("400 Bad Request",
|
||||
"Illegal #fragment in Request-URI.")
|
||||
return
|
||||
|
||||
if scheme:
|
||||
environ["wsgi.url_scheme"] = scheme
|
||||
if params:
|
||||
path = path + ";" + params
|
||||
|
||||
# Unquote the path+params (e.g. "/this%20path" -> "this path").
|
||||
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
|
||||
#
|
||||
# But note that "...a URI must be separated into its components
|
||||
# before the escaped characters within those components can be
|
||||
# safely decoded." http://www.ietf.org/rfc/rfc2396.txt, sec 2.4.2
|
||||
atoms = [unquote(x) for x in QUOTED_SLASH.split(path)]
|
||||
path = "%2F".join(atoms)
|
||||
|
||||
environ["SCRIPT_NAME"] = ""
|
||||
environ["PATH_INFO"] = path
|
||||
##if path == "*":
|
||||
## # This means, of course, that the last wsgi_app (shortest path)
|
||||
## # will always handle a URI of "*".
|
||||
## environ["SCRIPT_NAME"] = ""
|
||||
## environ["PATH_INFO"] = "*"
|
||||
## self.wsgi_app = server.mount_points[-1][1]
|
||||
##else:
|
||||
## for mount_point, wsgi_app in server.mount_points:
|
||||
## # The mount_points list should be sorted by length, descending.
|
||||
## if path.startswith(mount_point + "/") or path == mount_point:
|
||||
## environ["SCRIPT_NAME"] = mount_point
|
||||
## environ["PATH_INFO"] = path[len(mount_point):]
|
||||
## self.wsgi_app = wsgi_app
|
||||
## break
|
||||
## else:
|
||||
## self.simple_response("404 Not Found")
|
||||
## return
|
||||
|
||||
# Note that, like wsgiref and most other WSGI servers,
|
||||
# we unquote the path but not the query string.
|
||||
environ["QUERY_STRING"] = qs
|
||||
|
||||
# Compare request and server HTTP protocol versions, in case our
|
||||
# server does not support the requested protocol. Limit our output
|
||||
# to min(req, server). We want the following output:
|
||||
# request server actual written supported response
|
||||
# protocol protocol response protocol feature set
|
||||
# a 1.0 1.0 1.0 1.0
|
||||
# b 1.0 1.1 1.1 1.0
|
||||
# c 1.1 1.0 1.0 1.0
|
||||
# d 1.1 1.1 1.1 1.1
|
||||
# Notice that, in (b), the response will be "HTTP/1.1" even though
|
||||
# the client only understands 1.0. RFC 2616 10.5.6 says we should
|
||||
# only return 505 if the _major_ version is different.
|
||||
rp = int(req_protocol[5]), int(req_protocol[7])
|
||||
sp = int(server.protocol[5]), int(server.protocol[7])
|
||||
if sp[0] != rp[0]:
|
||||
self.simple_response("505 HTTP Version Not Supported")
|
||||
return
|
||||
# Bah. "SERVER_PROTOCOL" is actually the REQUEST protocol.
|
||||
environ["SERVER_PROTOCOL"] = req_protocol
|
||||
# set a non-standard environ entry so the WSGI app can know what
|
||||
# the *real* server protocol is (and what features to support).
|
||||
# See http://www.faqs.org/rfcs/rfc2145.html.
|
||||
environ["ACTUAL_SERVER_PROTOCOL"] = server.protocol
|
||||
self.response_protocol = "HTTP/%s.%s" % min(rp, sp)
|
||||
|
||||
# If the Request-URI was an absoluteURI, use its location atom.
|
||||
if location:
|
||||
environ["SERVER_NAME"] = location
|
||||
|
||||
# then all the http headers
|
||||
try:
|
||||
self.read_headers()
|
||||
except ValueError, ex:
|
||||
self.simple_response("400 Bad Request", repr(ex.args))
|
||||
return
|
||||
|
||||
creds = environ.get("HTTP_AUTHORIZATION", "").split(" ", 1)
|
||||
environ["AUTH_TYPE"] = creds[0]
|
||||
if creds[0].lower() == 'basic':
|
||||
user, pw = base64.decodestring(creds[1]).split(":", 1)
|
||||
environ["REMOTE_USER"] = user
|
||||
|
||||
# Persistent connection support
|
||||
if self.response_protocol == "HTTP/1.1":
|
||||
if environ.get("HTTP_CONNECTION", "") == "close":
|
||||
self.close_connection = True
|
||||
else:
|
||||
# HTTP/1.0
|
||||
if environ.get("HTTP_CONNECTION", "") != "Keep-Alive":
|
||||
self.close_connection = True
|
||||
|
||||
# Transfer-Encoding support
|
||||
te = None
|
||||
if self.response_protocol == "HTTP/1.1":
|
||||
te = environ.get("HTTP_TRANSFER_ENCODING")
|
||||
if te:
|
||||
te = [x.strip().lower() for x in te.split(",") if x.strip()]
|
||||
|
||||
read_chunked = False
|
||||
|
||||
if te:
|
||||
for enc in te:
|
||||
if enc == "chunked":
|
||||
read_chunked = True
|
||||
else:
|
||||
# Note that, even if we see "chunked", we must reject
|
||||
# if there is an extension we don't recognize.
|
||||
self.simple_response("501 Unimplemented")
|
||||
self.close_connection = True
|
||||
return
|
||||
|
||||
self.read_chunked = read_chunked
|
||||
return
|
||||
|
||||
if read_chunked:
|
||||
if not self.decode_chunked():
|
||||
return
|
||||
|
||||
# From PEP 333:
|
||||
# "Servers and gateways that implement HTTP 1.1 must provide
|
||||
# transparent support for HTTP 1.1's "expect/continue" mechanism.
|
||||
# This may be done in any of several ways:
|
||||
# 1. Respond to requests containing an Expect: 100-continue request
|
||||
# with an immediate "100 Continue" response, and proceed normally.
|
||||
# 2. Proceed with the request normally, but provide the application
|
||||
# with a wsgi.input stream that will send the "100 Continue"
|
||||
# response if/when the application first attempts to read from
|
||||
# the input stream. The read request must then remain blocked
|
||||
# until the client responds.
|
||||
# 3. Wait until the client decides that the server does not support
|
||||
# expect/continue, and sends the request body on its own.
|
||||
# (This is suboptimal, and is not recommended.)
|
||||
#
|
||||
# We used to do 3, but are now doing 1. Maybe we'll do 2 someday,
|
||||
# but it seems like it would be a big slowdown for such a rare case.
|
||||
if environ.get("HTTP_EXPECT", "") == "100-continue":
|
||||
self.simple_response(100)
|
||||
|
||||
self.ready = True
|
||||
|
||||
def new_header(self,k,v):
|
||||
if k:
|
||||
environ = self.environ
|
||||
envname = 'HTTP_'+k
|
||||
if k in COMMA_SEPARATED_HEADERS:
|
||||
existing = environ.get(envname)
|
||||
if existing:
|
||||
v = ", ".join((existing, v))
|
||||
environ[envname] = v
|
||||
|
||||
def read_headers(self):
|
||||
"""Read header lines from the incoming stream."""
|
||||
k = v = None
|
||||
while True:
|
||||
line = self.rfile.readline()
|
||||
if not line or '\0' in line:
|
||||
# No more data--illegal end of headers
|
||||
raise ValueError("Illegal headers")
|
||||
elif line == RN:
|
||||
# Normal end of headers
|
||||
self.new_header(k,v)
|
||||
break
|
||||
elif line[0] in ' \t':
|
||||
v += line.strip()
|
||||
else:
|
||||
self.new_header(k,v)
|
||||
k, v = line.split(":", 1)
|
||||
k, v = k.strip().upper(), v.strip()
|
||||
|
||||
environ = self.environ
|
||||
ct = environ.pop("HTTP_CONTENT_TYPE", None)
|
||||
if ct:
|
||||
environ["CONTENT_TYPE"] = ct
|
||||
cl = environ.pop("HTTP_CONTENT_LENGTH", None)
|
||||
if cl:
|
||||
environ["CONTENT_LENGTH"] = cl
|
||||
|
||||
def decode_chunked(self):
|
||||
"""Decode the 'chunked' transfer coding."""
|
||||
cl = 0
|
||||
data = StringIO.StringIO()
|
||||
while True:
|
||||
line = self.rfile.readline().strip().split(";", 1)
|
||||
chunk_size = int(line.pop(0), 16)
|
||||
if chunk_size <= 0:
|
||||
break
|
||||
## if line: chunk_extension = line[0]
|
||||
cl += chunk_size
|
||||
data.write(self.rfile.read(chunk_size))
|
||||
crlf = self.rfile.read(2)
|
||||
if crlf != RN:
|
||||
self.simple_response("400 Bad Request",
|
||||
"Bad chunked transfer coding "
|
||||
"(expected '\\r\\n', got %r)" % crlf)
|
||||
return
|
||||
|
||||
# Grab any trailer headers
|
||||
self.read_headers()
|
||||
|
||||
data.seek(0)
|
||||
self.environ["wsgi.input"] = data
|
||||
self.environ["CONTENT_LENGTH"] = str(cl) or ""
|
||||
return True
|
||||
|
||||
def respond(self):
|
||||
"""
|
||||
Call the appropriate WSGI app and write its iterable output.
|
||||
"""
|
||||
response = self.server.wsgi_app(self.environ, self.start_response)
|
||||
try:
|
||||
for chunk in response:
|
||||
# "The start_response callable must not actually transmit
|
||||
# the response headers. Instead, it must store them for the
|
||||
# server or gateway to transmit only after the first
|
||||
# iteration of the application return value that yields
|
||||
# a NON-EMPTY string, or upon the application's first
|
||||
# invocation of the write() callable." (PEP 333)
|
||||
if chunk:
|
||||
self.write(chunk)
|
||||
finally:
|
||||
if hasattr(response, "close"):
|
||||
response.close()
|
||||
|
||||
if not self.sent_headers:
|
||||
self.send_headers()
|
||||
if self.chunked_write:
|
||||
self.push("0\r\n")
|
||||
|
||||
def simple_response(self, status, msg=""):
|
||||
"""Write a simple response back to the client."""
|
||||
status = str(status)
|
||||
buf = ["%s %s\r\n" % (self.server.protocol, status),
|
||||
"Content-Length: %s\r\n" % len(msg)]
|
||||
|
||||
if status[:3] == "413" and self.response_protocol == 'HTTP/1.1':
|
||||
# Request Entity Too Large
|
||||
self.close_connection = True
|
||||
buf.append("Connection: close\r\n")
|
||||
|
||||
buf.append(RN)
|
||||
if msg:
|
||||
buf.append(msg)
|
||||
self.push(''.join(buf))
|
||||
|
||||
if self.close_connection or ( not self.server.keep_going ):
|
||||
self.close_when_done()
|
||||
else:
|
||||
self.reset_when_done()
|
||||
|
||||
def start_response(self, status, headers, exc_info = None):
|
||||
"""WSGI callable to begin the HTTP response."""
|
||||
if self.started_response:
|
||||
if not exc_info:
|
||||
raise AssertionError("WSGI start_response called a second "
|
||||
"time with no exc_info.")
|
||||
else:
|
||||
try:
|
||||
raise exc_info[0], exc_info[1], exc_info[2]
|
||||
finally:
|
||||
exc_info = None
|
||||
self.started_response = True
|
||||
self.status = status
|
||||
self.outheaders.extend(headers)
|
||||
return self.write
|
||||
|
||||
def write(self, chunk):
|
||||
"""
|
||||
WSGI callable to write unbuffered data to the client.
|
||||
|
||||
This method is also used internally by start_response (to write
|
||||
data from the iterable returned by the WSGI application).
|
||||
"""
|
||||
if not self.started_response:
|
||||
raise AssertionError("WSGI write called before start_response.")
|
||||
|
||||
if not self.sent_headers:
|
||||
self.send_headers()
|
||||
|
||||
if self.chunked_write and chunk:
|
||||
buf = [hex(len(chunk))[2:], RN, chunk, RN]
|
||||
self.push(''.join(buf))
|
||||
else:
|
||||
self.push(chunk)
|
||||
|
||||
def send_headers(self):
|
||||
"""
|
||||
Assert, process, and send the HTTP response message-headers.
|
||||
"""
|
||||
self.sent_headers = True
|
||||
hkeys = [key.lower() for key, value in self.outheaders]
|
||||
status = int(self.status[:3])
|
||||
|
||||
if status == 413:
|
||||
# Request Entity Too Large. Close conn to avoid garbage.
|
||||
self.close_connection = True
|
||||
elif "content-length" not in hkeys:
|
||||
# "All 1xx (informational), 204 (no content),
|
||||
# and 304 (not modified) responses MUST NOT
|
||||
# include a message-body." So no point chunking.
|
||||
if status < 200 or status in (204, 205, 304):
|
||||
pass
|
||||
else:
|
||||
if self.response_protocol == 'HTTP/1.1':
|
||||
# Use the chunked transfer-coding
|
||||
self.chunked_write = True
|
||||
self.outheaders.append(("Transfer-Encoding", "chunked"))
|
||||
else:
|
||||
# Closing the conn is the only way to determine len.
|
||||
self.close_connection = True
|
||||
|
||||
if "connection" not in hkeys:
|
||||
if self.response_protocol == 'HTTP/1.1':
|
||||
if self.close_connection:
|
||||
self.outheaders.append(("Connection", "close"))
|
||||
else:
|
||||
if not self.close_connection:
|
||||
self.outheaders.append(("Connection", "Keep-Alive"))
|
||||
|
||||
if "date" not in hkeys:
|
||||
self.outheaders.append(("Date", rfc822.formatdate()))
|
||||
|
||||
server = self.server
|
||||
|
||||
if "server" not in hkeys:
|
||||
self.outheaders.append(("Server", server.version))
|
||||
|
||||
buf = [server.protocol, " ", self.status, RN]
|
||||
try:
|
||||
buf += [k + ": " + v + RN for k, v in self.outheaders]
|
||||
except TypeError:
|
||||
if not isinstance(k, str):
|
||||
raise TypeError("WSGI response header key %r is not a string.")
|
||||
if not isinstance(v, str):
|
||||
raise TypeError("WSGI response header value %r is not a string.")
|
||||
else:
|
||||
raise
|
||||
buf.append(RN)
|
||||
self.push(''.join(buf))
|
||||
|
||||
|
||||
class WSGIServer(asyncore.dispatcher):
|
||||
version = "Asynwsgi Server/1.0 alpha"
|
||||
protocol = "HTTP/1.1"
|
||||
def __init__(self, bind_addr, wsgi_app, server_name=None):
|
||||
asyncore.dispatcher.__init__ (self)
|
||||
self.create_socket (socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.set_reuse_addr()
|
||||
self.bind(bind_addr)
|
||||
self.listen(1024)
|
||||
self.keep_going = True
|
||||
self.wsgi_app = wsgi_app
|
||||
|
||||
if not server_name:
|
||||
server_name = socket.gethostname()
|
||||
self.server_name = server_name
|
||||
|
||||
def writable(self):
|
||||
return False
|
||||
|
||||
def readable(self):
|
||||
return self.accepting
|
||||
|
||||
def handle_accept(self):
|
||||
try:
|
||||
conn, addr = self.accept()
|
||||
except:
|
||||
return
|
||||
RequestHandler(conn, self)
|
||||
|
||||
def reload(self, signum, frame):
|
||||
print 'reloading...'
|
||||
self.keep_going = False
|
||||
self.close()
|
||||
|
||||
def stop(self, signum, frame):
|
||||
asyncore.close_all()
|
||||
|
||||
def start(self):
|
||||
signal.signal(signal.SIGTERM, self.stop)
|
||||
signal.signal(signal.SIGINT, self.stop)
|
||||
asyncore.loop(timeout=0.1, use_poll=False)
|
||||
|
||||
def demo_app(environ, start_response):
|
||||
write = start_response('200 OK', [('content-type', 'text/html')])
|
||||
return ["<h1>Hello World!</h1>", "<br />%s"%time.ctime()]
|
||||
|
||||
def test_client(address='127.0.0.1:8000'):
|
||||
time.sleep(3)
|
||||
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
ip,port = address.split(':',1)
|
||||
server.connect((ip,int(port)))
|
||||
server.send('GET /\r\n\r\n')
|
||||
while True:
|
||||
sys.stdout.write(server.recv(1))
|
||||
sys.stdout.write('CLOSE\n')
|
||||
|
||||
if __name__ == "__main__":
|
||||
#thread.start_new_thread(test_client,())
|
||||
#thread.start_new_thread(test_client,())
|
||||
#thread.start_new_thread(test_client,())
|
||||
WSGIServer(('127.0.0.1', 8000), demo_app).start()
|
||||
4
temps/benchmark.py
Normal file
4
temps/benchmark.py
Normal file
@@ -0,0 +1,4 @@
|
||||
import time
|
||||
|
||||
t0 = time.time()
|
||||
|
||||
22
temps/bm_split.py
Normal file
22
temps/bm_split.py
Normal file
@@ -0,0 +1,22 @@
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
N = 100000
|
||||
r = re.compile('^(\S+)\s*\:\s*(.*?)\s*$')
|
||||
|
||||
a = "hello : world\r\n"
|
||||
|
||||
t0 = time.time()
|
||||
for k in xrange(N):
|
||||
items = a.split(':',1)
|
||||
x,y = items[0].strip(),items[1].strip()
|
||||
print (time.time()-t0)/N
|
||||
|
||||
from gluon.utils import fast_urandom16
|
||||
|
||||
t0 = time.time()
|
||||
for k in xrange(N):
|
||||
x,y = a.split(':',1)
|
||||
x,y = x.strip(), y.strip()
|
||||
print (time.time()-t0)/N
|
||||
print x,y
|
||||
15
temps/bm_urandom.py
Normal file
15
temps/bm_urandom.py
Normal file
@@ -0,0 +1,15 @@
|
||||
import os
|
||||
import time
|
||||
N = 100000
|
||||
|
||||
t0 = time.time()
|
||||
for k in xrange(N):
|
||||
os.urandom(16)
|
||||
print (time.time()-t0)/N
|
||||
|
||||
from gluon.utils import fast_urandom16
|
||||
|
||||
t0 = time.time()
|
||||
for k in xrange(N):
|
||||
fast_urandom16()
|
||||
print (time.time()-t0)/N
|
||||
19
temps/case.py
Normal file
19
temps/case.py
Normal file
@@ -0,0 +1,19 @@
|
||||
db =DAL()
|
||||
db.define_table('person',Field('name'))
|
||||
|
||||
from gluon.dal import Expression
|
||||
def IF(a,b,c,t=None):
|
||||
db,f = a.db, a.db._adapter.expand
|
||||
def r(x,represent=db._adapter.represent):
|
||||
if x is None: return 'NULL'
|
||||
elif isinstance(x,Expression): return str(x)
|
||||
types = {type(True): 'boolean',
|
||||
type(0): 'integer',
|
||||
type(1.0): 'double'}
|
||||
return represent(x,types.get(type(x),'string'))
|
||||
return Expression(db,'CASE WHEN %s THEN %s ELSE %s END' % (f(a),r(b),r(c)))
|
||||
|
||||
db.person.insert(name='x')
|
||||
db.person.insert(name='y')
|
||||
db.person.insert(name='z')
|
||||
print db().select(db.person.ALL, (db.person.name=='x').case('A',(db.person.name=='y').case('B','C')))
|
||||
16
temps/check.py
Normal file
16
temps/check.py
Normal file
@@ -0,0 +1,16 @@
|
||||
import re, sys
|
||||
|
||||
regex = re.compile('\w+\.\w+')
|
||||
|
||||
for line in open(sys.argv[1]).read().split(' def '):
|
||||
function = line.split('(',1)[0]
|
||||
links = regex.findall(line)
|
||||
m = {}
|
||||
for link in links: m[link]=m.get(link,0)+1
|
||||
print function
|
||||
for link, count in sorted([(v,k) for v,k in m.iteritems()]):
|
||||
if count>1:
|
||||
print ' ',link, count
|
||||
|
||||
|
||||
|
||||
11
temps/compile_rotator.py
Normal file
11
temps/compile_rotator.py
Normal file
@@ -0,0 +1,11 @@
|
||||
import re
|
||||
|
||||
CACHED_REGEXES = {}
|
||||
|
||||
def re_compile(regex):
|
||||
try:
|
||||
return CACHED_REGEXES[regex]
|
||||
except KeyError:
|
||||
compiled_regex = CACHED_REGEXES[regex] = re.compile(regex)
|
||||
return compiled_regex
|
||||
|
||||
78
temps/cookies.py
Normal file
78
temps/cookies.py
Normal file
@@ -0,0 +1,78 @@
|
||||
import re
|
||||
import urllib
|
||||
import urllib2
|
||||
|
||||
class W2POpener(object):
|
||||
regex = re.compile('\<input name\="_formkey" type\="hidden" value\="(?P<formkey>.+?)" \/\>\<input name\="_formname" type\="hidden" value\="(?P<formname>.+?)" \/\>')
|
||||
|
||||
def __init__(self,app=''):
|
||||
self.app = app
|
||||
self.cookies = {}
|
||||
|
||||
def get(self,url,cookies=None,headers=None,auth=None):
|
||||
return self.post(url,data=None,cookies=cookies,headers=headers)
|
||||
|
||||
def post(self,url,data=None,cookies=None,headers=None,auth=None):
|
||||
self.url = self.app+url
|
||||
if cookies is None: cookies = self.cookies
|
||||
if auth:
|
||||
auth_handler = urllib2.HTTPBasicAuthHandler()
|
||||
auth_handler.add_password(**auth)
|
||||
opener = urllib2.build_opener(auth_handler)
|
||||
else:
|
||||
opener = urllib2.build_opener()
|
||||
headers_list = []
|
||||
for key,value in (headers or {}).iteritems():
|
||||
if isinstance(value,(list,tuple)):
|
||||
for v in value: headers_list.append((key,v))
|
||||
else:
|
||||
headers_list.append((key,value))
|
||||
for key,value in (cookies or {}).iteritems():
|
||||
headers_list.append(('Cookie','%s=%s' % (key,value)))
|
||||
for key,value in headers_list:
|
||||
opener.addheaders.append((key,str(value)))
|
||||
if data is not None:
|
||||
# if there is only one form, set _formname automatically
|
||||
if not '_formname' in data and len(self.forms)==1:
|
||||
data['_formname'] = self.forms.keys()[0]
|
||||
# if there is no formkey but it is known, set it
|
||||
if '_formname' in data and not '_formkey' in data and \
|
||||
data['_formname'] in self.forms:
|
||||
data['_formkey'] = self.forms[data['_formname']]
|
||||
data = urllib.urlencode(data)
|
||||
self.request = opener.open(self.url,data)
|
||||
else:
|
||||
self.request = opener.open(self.url)
|
||||
self.status = self.request.getcode()
|
||||
self.text = self.request.read()
|
||||
self.headers = dict(self.request.headers)
|
||||
self.cookies = dict(item[:item.find(';')].split('=') for item in \
|
||||
self.headers.get('set-cookie','').split(','))
|
||||
|
||||
self.forms = {}
|
||||
for match in W2POpener.regex.finditer(self.text):
|
||||
self.forms[match.group('formname')] = match.group('formkey')
|
||||
|
||||
def test_registration_and_login():
|
||||
session = W2POpener('http://127.0.0.1:8000/welcome/default/')
|
||||
session.get('user/register')
|
||||
data = dict(first_name = 'Homer',
|
||||
last_name = 'Simpson',
|
||||
email = 'homer@web2py.com',
|
||||
password = 'test',
|
||||
password_two = 'test',
|
||||
_formname = 'register')
|
||||
session.post('user/register',data = data)
|
||||
|
||||
session.get('user/login')
|
||||
data = dict(email='homer@web2py.com',
|
||||
password='test',
|
||||
_formname = 'login')
|
||||
session.post('user/login',data = data)
|
||||
|
||||
session.get('index')
|
||||
assert 'Welcome Homer' in session.text
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_registration_and_login()
|
||||
|
||||
165
temps/daemon.py
Normal file
165
temps/daemon.py
Normal file
@@ -0,0 +1,165 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import sys, os, time, atexit, signal, subprocess
|
||||
|
||||
class Daemon:
|
||||
"""
|
||||
A generic daemon class.
|
||||
Usage: subclass the Daemon class and override the run() method
|
||||
From: http://bit.ly/TnPxwp
|
||||
Developed by Sander Marechal
|
||||
Minor modifications by Massimo Di Pierro
|
||||
"""
|
||||
def __init__(self,
|
||||
pidfile,
|
||||
stdin='/dev/null',
|
||||
stdout='/dev/null',
|
||||
stderr=None):
|
||||
|
||||
self.stdin = stdin
|
||||
self.stdout = stdout
|
||||
self.stderr = stderr
|
||||
self.pidfile = pidfile
|
||||
|
||||
def daemonize(self):
|
||||
"""
|
||||
do the UNIX double-fork magic, see Stevens
|
||||
"Advanced Programming in the UNIX Environment"
|
||||
for details (ISBN 0201563177)
|
||||
http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
|
||||
"""
|
||||
try:
|
||||
pid = os.fork()
|
||||
if pid > 0:
|
||||
# exit first parent
|
||||
sys.exit(0)
|
||||
except OSError, e:
|
||||
sys.stderr.write("fork #1 failed: %d (%s)\n" % (
|
||||
e.errno, e.strerror))
|
||||
sys.exit(1)
|
||||
|
||||
# decouple from parent environment
|
||||
os.chdir("/")
|
||||
os.setsid()
|
||||
os.umask(0)
|
||||
|
||||
# do second fork
|
||||
try:
|
||||
pid = os.fork()
|
||||
if pid > 0:
|
||||
# exit from second parent
|
||||
sys.exit(0)
|
||||
except OSError, e:
|
||||
sys.stderr.write("fork #2 failed: %d (%s)\n" % (
|
||||
e.errno, e.strerror))
|
||||
sys.exit(1)
|
||||
|
||||
# redirect standard file descriptors
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
if self.stdin != '/dev/null':
|
||||
os.mkfifo(self.stdin)
|
||||
si = open(self.stdin, 'r')
|
||||
if self.stdout != '/dev/null':
|
||||
os.mkfifo(self.stdout)
|
||||
so = open(self.stdout, 'a+')
|
||||
if self.stderr is None:
|
||||
se = so
|
||||
else:
|
||||
if self.stderr != '/dev/null':
|
||||
os.mkfifo(self.stderr)
|
||||
se = open(self.stderr, 'a+', 0)
|
||||
os.dup2(si.fileno(), sys.stdin.fileno())
|
||||
os.dup2(so.fileno(), sys.stdout.fileno())
|
||||
os.dup2(se.fileno(), sys.stderr.fileno())
|
||||
|
||||
# write pidfile
|
||||
# atexit.register(self.delpid)
|
||||
pid = str(os.getpid())
|
||||
open(self.pidfile,'w+').write("%s\n" % pid)
|
||||
|
||||
def delpid(self):
|
||||
os.remove(self.pidfile)
|
||||
|
||||
def start(self):
|
||||
"""
|
||||
Start the daemon
|
||||
"""
|
||||
# Check for a pidfile to see if the daemon already runs
|
||||
try:
|
||||
pf = open(self.pidfile,'r')
|
||||
pid = int(pf.read().strip())
|
||||
pf.close()
|
||||
except IOError:
|
||||
pid = None
|
||||
|
||||
if pid:
|
||||
message = "pidfile %s already exist. Daemon already running?\n"
|
||||
sys.stderr.write(message % self.pidfile)
|
||||
sys.exit(1)
|
||||
|
||||
# Start the daemon
|
||||
self.daemonize()
|
||||
self.run()
|
||||
|
||||
def stop(self):
|
||||
"""
|
||||
Stop the daemon
|
||||
"""
|
||||
# Get the pid from the pidfile
|
||||
try:
|
||||
pf = open(self.pidfile,'r')
|
||||
pid = int(pf.read().strip())
|
||||
pf.close()
|
||||
except IOError:
|
||||
pid = None
|
||||
|
||||
if not pid:
|
||||
message = "pidfile %s does not exist. Daemon not running?\n"
|
||||
sys.stderr.write(message % self.pidfile)
|
||||
return # not an error in a restart
|
||||
|
||||
# Try killing the daemon process
|
||||
try:
|
||||
while 1:
|
||||
os.kill(pid, signal.SIGTERM)
|
||||
time.sleep(0.1)
|
||||
except OSError, err:
|
||||
err = str(err)
|
||||
if err.find("No such process") > 0:
|
||||
if os.path.exists(self.pidfile):
|
||||
os.remove(self.pidfile)
|
||||
else:
|
||||
print str(err)
|
||||
sys.exit(1)
|
||||
|
||||
def restart(self):
|
||||
"""
|
||||
Restart the daemon
|
||||
"""
|
||||
self.stop()
|
||||
self.start()
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
You should override this method when you subclass Daemon.
|
||||
It will be called after the process has been
|
||||
daemonized by start() or restart().
|
||||
"""
|
||||
if hasattr(self,'args'):
|
||||
subprocess.call(self.args,
|
||||
stdin=sys.stdin,
|
||||
stdout=sys.stdout,
|
||||
stderr=sys.stderr,
|
||||
shell=True)
|
||||
|
||||
|
||||
os.system('rm t1/*')
|
||||
d = Daemon(
|
||||
pidfile = '/Users/massimodipierro/Dropbox/web2py/temps/t1/process.pid',
|
||||
stdin = '/Users/massimodipierro/Dropbox/web2py/temps/t1/fifo.in',
|
||||
stdout = '/Users/massimodipierro/Dropbox/web2py/temps/t1/fifo.out',
|
||||
stderr = None)
|
||||
|
||||
d.args = ['python looping.py']
|
||||
d.start()
|
||||
14
temps/db.py
Normal file
14
temps/db.py
Normal file
@@ -0,0 +1,14 @@
|
||||
import sys
|
||||
sys.path.append('/Users/massimodipierro/Dropbox/web2py/')
|
||||
import pickle
|
||||
from gluon import *
|
||||
db = DAL()
|
||||
print db
|
||||
s = pickle.dumps(db)
|
||||
db.close()
|
||||
del db
|
||||
|
||||
a = pickle.loads(s)
|
||||
print repr(a)
|
||||
print str(a)
|
||||
print BEAUTIFY(a).xml()
|
||||
76
temps/fofo.py
Normal file
76
temps/fofo.py
Normal file
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import sys, os
|
||||
import subprocess
|
||||
import threading
|
||||
import socket
|
||||
import tempfile
|
||||
|
||||
def daemonize():
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
pid = os.fork()
|
||||
if pid<0:
|
||||
raise RuntimeError, "cannot fork"
|
||||
elif pid>0:
|
||||
(pid,status) = os.wait()
|
||||
sys.exit(status)
|
||||
os.chdir("/")
|
||||
os.setsid()
|
||||
os.umask(0)
|
||||
pid = os.fork()
|
||||
if pid<0:
|
||||
raise RuntimeError, "cannot fork"
|
||||
elif pid>0:
|
||||
sys.exit(0)
|
||||
os.dup2(os.open('/dev/null',os.O_RDONLY),sys.stdin.fileno())
|
||||
os.dup2(os.open('/dev/null',os.O_WRONLY),sys.stdout.fileno())
|
||||
os.dup2(os.open('/dev/null',os.O_WRONLY),sys.stderr.fileno())
|
||||
|
||||
class SmokingDaemon(threading.Thread):
|
||||
def __init__(self,
|
||||
cmd,
|
||||
path,
|
||||
tempdir = None):
|
||||
self.cmd = cmd
|
||||
self.path = path
|
||||
self.tempdir = tempdir or tempfile.mkdtemp()
|
||||
self.fifo_in_name = os.path.join(self.tempdir,'in.fifo')
|
||||
self.fifo_out_name = os.path.join(self.tempdir,'out.fifo')
|
||||
self.fifo_err_name = os.path.join(self.tempdir,'err.fifo')
|
||||
daemonize(path)
|
||||
threading.Thread.__init__(self)
|
||||
|
||||
def run(self):
|
||||
try: os.unlink(self.fifo_in_name)
|
||||
except: pass
|
||||
try: os.unlink(self.fifo_out_name)
|
||||
except: pass
|
||||
os.mkfifo(self.fifo_in_name)
|
||||
os.mkfifo(self.fifo_out_name)
|
||||
fifo_in_read = os.fdopen(
|
||||
os.open(self.fifo_in_name,os.O_RDONLY|os.O_NONBLOCK))
|
||||
self.output = os.fdopen(
|
||||
os.open(self.fifo_out_name,os.O_RDONLY|os.O_NONBLOCK))
|
||||
self.input = open(self.fifo_in_name,'a+')
|
||||
fifo_out_write = open(self.fifo_out_name,'a+')
|
||||
process = subprocess.call(self.cmd,
|
||||
shell=True,
|
||||
stdin=fifo_in_read,
|
||||
stdout=fifo_out_write,
|
||||
stderr=fifo_out_write)
|
||||
|
||||
sd = SmokingDaemon('ls -l','fifo.in','fifo.out')
|
||||
sd.start()
|
||||
sd.server()
|
||||
sd.join()
|
||||
open(sd.output.read()
|
||||
|
||||
sd = SmokingDaemon(id)
|
||||
sd.start(command)
|
||||
sd.stop()
|
||||
sd.kill()
|
||||
sd.seek()
|
||||
sd.read(bytes)
|
||||
sd.readline()
|
||||
sd.write('hello world')
|
||||
73
temps/fofo.py.old
Normal file
73
temps/fofo.py.old
Normal file
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import sys, os
|
||||
import subprocess
|
||||
|
||||
def runCmd( cmd, fifo ):
|
||||
try:
|
||||
os.unlink(fifo)
|
||||
except:
|
||||
pass
|
||||
|
||||
os.mkfifo( "out_fifo" )
|
||||
|
||||
try:
|
||||
|
||||
fifo = os.fdopen( os.open( "out_fifo",
|
||||
os.O_RDONLY | os.O_NONBLOCK ) )
|
||||
|
||||
newcmd = "( %s ) 1>out_fifo 2>&1"%( cmd, )
|
||||
|
||||
process = subprocess.Popen( newcmd, shell = True,
|
||||
stdout = subprocess.PIPE,
|
||||
stderr = subprocess.STDOUT )
|
||||
|
||||
_localLog.debug( "Running: %s"%( cmd, ) )
|
||||
|
||||
while process.returncode == None:
|
||||
# None means process is still running
|
||||
|
||||
# need to poll the process once so the returncode
|
||||
# gets set (see docs)
|
||||
process.poll()
|
||||
|
||||
try:
|
||||
line = fifo.readline().strip()
|
||||
except:
|
||||
continue
|
||||
|
||||
if line:
|
||||
log.info( line )
|
||||
|
||||
remaining = fifo.read()
|
||||
|
||||
if remaining:
|
||||
for line in [ line
|
||||
for line in remaining.split( "\n" )
|
||||
if line.strip() ]:
|
||||
log.info( line.strip() )
|
||||
|
||||
if process.returncode:
|
||||
_localLog.critical( "Return Value: %s"%( process.returncode, ) )
|
||||
else:
|
||||
_localLog.debug( "Return Value: %s"%( process.returncode, ) )
|
||||
|
||||
finally:
|
||||
|
||||
os.unlink( "out_fifo" )
|
||||
|
||||
|
||||
mainlog.debug( os.getcwd() )
|
||||
|
||||
print
|
||||
runCmd( "echo 'bye'", mainlog )
|
||||
|
||||
print
|
||||
runCmd( "/usr/bin/false", mainlog )
|
||||
|
||||
print
|
||||
runCmd( "ls -l; sleep 5; echo 'hi!'; sleep 5; ls -l", mainlog )
|
||||
|
||||
print
|
||||
runCmd( "this_should_not_exists", mainlog )
|
||||
|
||||
4
temps/looping.py
Normal file
4
temps/looping.py
Normal file
@@ -0,0 +1,4 @@
|
||||
import time
|
||||
for t in range(1000):
|
||||
print t
|
||||
time.sleep(5)
|
||||
5
temps/mmpy
Normal file
5
temps/mmpy
Normal file
@@ -0,0 +1,5 @@
|
||||
text = """
|
||||
[[https://groups.google.com/forum/?fromgroups#!forum/web2py/ https://groups.google.com/forum/?fromgroups#!forum/web2py/]]
|
||||
"""
|
||||
|
||||
print MARKMIN(text).xml()
|
||||
27
temps/out_fifo
Normal file
27
temps/out_fifo
Normal file
@@ -0,0 +1,27 @@
|
||||
total 184
|
||||
-rw-r--r-- 1 massimodipierro staff 31 Aug 26 22:53 benchmark.py
|
||||
-rw-r--r-- 1 massimodipierro staff 379 Aug 28 17:31 check.py
|
||||
-rw-r--r-- 1 massimodipierro staff 220 Sep 2 12:08 compile_rotator.py
|
||||
-rw-r--r-- 1 massimodipierro staff 3135 Aug 29 17:20 cookies.py
|
||||
-rw-r--r-- 1 massimodipierro staff 4759 Sep 6 16:05 daemon.py
|
||||
prw-r--r-- 1 massimodipierro staff 0 Sep 7 15:43 fifo.1
|
||||
-rw-r--r-- 1 massimodipierro staff 671 Sep 7 15:43 fofo.py
|
||||
-rw-r--r-- 1 massimodipierro staff 1612 Sep 7 15:39 fofo.py.old
|
||||
-rw-r--r-- 1 massimodipierro staff 663 Sep 7 15:42 fofo.py~
|
||||
-rw-r--r-- 1 massimodipierro staff 64 Sep 6 15:11 looping.py
|
||||
-rw-r--r-- 1 massimodipierro staff 0 Sep 7 15:43 out_fifo
|
||||
-rw-r--r-- 1 massimodipierro staff 1218 Sep 6 15:11 process.py
|
||||
-rw-r--r-- 1 massimodipierro staff 475 Sep 6 09:32 read.py
|
||||
-rw-r--r-- 1 massimodipierro staff 3487 Sep 7 15:02 runcmd.log
|
||||
drwxr-xr-x 3 massimodipierro staff 102 Sep 6 16:04 t1
|
||||
-rw-r--r-- 1 massimodipierro staff 170 Aug 26 09:45 test1.py
|
||||
-rw-r--r-- 1 massimodipierro staff 270 Aug 26 10:43 test2.py
|
||||
-rw-r--r-- 1 massimodipierro staff 1434 Aug 28 18:51 test3.py
|
||||
-rw-r--r-- 1 massimodipierro staff 649 Aug 30 15:16 test7.py
|
||||
-rw-r--r-- 1 massimodipierro staff 507 Sep 2 16:41 test8.py
|
||||
-rw-r--r-- 1 massimodipierro staff 118 Aug 28 14:52 test_1.py
|
||||
-rw-r--r-- 1 massimodipierro staff 595 Aug 28 10:42 test_bruno.py
|
||||
-rw-r--r-- 1 massimodipierro staff 515 Aug 28 09:54 test_cache.py
|
||||
-rw-r--r-- 1 massimodipierro staff 304 Aug 28 14:19 test_dominc.py
|
||||
-rw-r--r-- 1 massimodipierro staff 2859 Aug 31 10:17 test_jim.py
|
||||
prw-r--r-- 1 massimodipierro staff 0 Sep 7 13:30 tmp.1
|
||||
3
temps/p.py
Normal file
3
temps/p.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from gluon.contrib.populate import populate
|
||||
populate(db.auth_user,10)
|
||||
print db(db.auth_user).select()
|
||||
37
temps/path.py
Normal file
37
temps/path.py
Normal file
@@ -0,0 +1,37 @@
|
||||
import os
|
||||
|
||||
class Path(object):
|
||||
def __init__(self,s='/',sep=os.path.sep):
|
||||
self.sep = sep
|
||||
self.s = s.split(sep)
|
||||
def __str__(self):
|
||||
return self.sep.join(self.s)
|
||||
def __add__(self,other):
|
||||
if other[0]=='':
|
||||
return Path(other)
|
||||
else:
|
||||
return Path(str(self)+os.sep+str(other))
|
||||
def __getitem__(self,i):
|
||||
return self.s[i]
|
||||
def __setitem__(self,i,v):
|
||||
self.s[i] = v
|
||||
def append(self,v):
|
||||
self.s.append(v)
|
||||
@property
|
||||
def filename(self):
|
||||
return self.s[-1]
|
||||
@property
|
||||
def folder(self):
|
||||
return Path(self.sep.join(self.s[:-1]))
|
||||
|
||||
>>> path = Path('/this/is/an/example.png')
|
||||
>>> print path[-1]
|
||||
example.png
|
||||
>>> print path.filename
|
||||
example.png
|
||||
>>> print path.folder
|
||||
/this/is/an
|
||||
>>> path[1]='that'
|
||||
/that/is/an/example.png
|
||||
>>> print path.folder + 'this'
|
||||
/that/is/an/this
|
||||
6
temps/pg.py
Normal file
6
temps/pg.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from gluon.dal import PostgreSQLAdapter
|
||||
db = DAL()
|
||||
db.define_table('test',Field('name'))
|
||||
db._adapter.close()
|
||||
db._adapter = PostgreSQLAdapter(db,'postgres://a:b@example.com/demo',do_connect=False)
|
||||
print db(db.test)._select()
|
||||
24
temps/pi.py
Normal file
24
temps/pi.py
Normal file
@@ -0,0 +1,24 @@
|
||||
import pickle
|
||||
db=DAL()
|
||||
db.define_table('person',Field('name'))
|
||||
db.define_table('thing',Field('name'),Field('owner','reference person'))
|
||||
id = db.person.insert(name='Tim')
|
||||
db.thing.insert(name='chair',owner=id)
|
||||
rows = db(db.person).select()
|
||||
|
||||
a = pickle.dumps(rows[0])
|
||||
b = pickle.loads(a)
|
||||
print b
|
||||
print type(b)
|
||||
print b.name
|
||||
|
||||
a = pickle.dumps(rows)
|
||||
b = pickle.loads(a)
|
||||
print b
|
||||
print type(b)
|
||||
print b.db == db
|
||||
|
||||
print b[0]['name']
|
||||
print b.first().name
|
||||
b.first().update_record(name='Max')
|
||||
print b.first().thing.select()
|
||||
32
temps/process.py
Normal file
32
temps/process.py
Normal file
@@ -0,0 +1,32 @@
|
||||
import os
|
||||
import subprocess
|
||||
import pickle
|
||||
|
||||
class Process(object):
|
||||
def __init__(self,path):
|
||||
self.path = path
|
||||
self.fifo_in_filename = os.path.join(self.path,'fifo.in')
|
||||
self.fifo_out_filename = os.path.join(self.path,'fifo.out')
|
||||
self.process_filename = os.path.join(self.path,'process.pickle')
|
||||
if not os.path.exists(path):
|
||||
os.mkdir(path)
|
||||
def run(self,command):
|
||||
if os.path.exists(self.fifo_in_filename):
|
||||
os.unlink(self.fifo_in_filename)
|
||||
if os.path.exists(self.fifo_out_filename):
|
||||
os.unlink(self.fifo_out_filename)
|
||||
fifo_in = os.mkfifo(self.fifo_in_filename)
|
||||
fifo_out = os.mkfifo(self.fifo_out_filename)
|
||||
s = subprocess.Popen(command, shell=True,
|
||||
stdin=fifo_in,
|
||||
stdout=fifo_out,
|
||||
stderr=fifo_out,
|
||||
close_fds=True)
|
||||
pickle.dump(s,open(self.process_filename,'wb'))
|
||||
def interact(self):
|
||||
fifo_out = open(self.fifo_out_filename,'rb')
|
||||
while True:
|
||||
print 'x',fifo_out.read(1)
|
||||
|
||||
p = Process('t1').run('python looping.py')
|
||||
q = Process('t1').interact()
|
||||
12
temps/read.py
Normal file
12
temps/read.py
Normal file
@@ -0,0 +1,12 @@
|
||||
import re
|
||||
import urllib
|
||||
import urllib2
|
||||
from BeautifulSoup import BeautifulSoup
|
||||
|
||||
page = urllib2.urlopen('http://www.telegraph.co.uk/technology/internet/9524681/Sir-Tim-Berners-Lee-accuses-government-of-draconian-internet-snooping.html')
|
||||
soup = BeautifulSoup(page)
|
||||
|
||||
items = soup.findAll(['h1','h2','h3','h4','h5','h6','p'])
|
||||
text = '\n'.join(''.join(item.findAll(text=True)) for item in items).encode('utf8')
|
||||
text = re.sub('\s*\n\s*','\n',re.sub('[ \t]+',' ',text))
|
||||
print text
|
||||
34
temps/runcmd.log
Normal file
34
temps/runcmd.log
Normal file
@@ -0,0 +1,34 @@
|
||||
INFO : 2012-09-07 15:02:00,230 : foo : test
|
||||
DEBUG : 2012-09-07 15:02:00,231 : main : /Users/massimodipierro/Dropbox/web2py/temps
|
||||
DEBUG : 2012-09-07 15:02:00,237 : runCmd : Running: echo 'bye'
|
||||
INFO : 2012-09-07 15:02:00,242 : main : bye
|
||||
DEBUG : 2012-09-07 15:02:00,244 : runCmd : Return Value: 0
|
||||
DEBUG : 2012-09-07 15:02:00,251 : runCmd : Running: /usr/bin/false
|
||||
CRITICAL : 2012-09-07 15:02:00,278 : runCmd : Return Value: 1
|
||||
DEBUG : 2012-09-07 15:02:00,290 : runCmd : Running: ls -l; sleep 5; echo 'hi!'; sleep 5; ls -l
|
||||
INFO : 2012-09-07 15:02:00,398 : main : total 176
|
||||
INFO : 2012-09-07 15:02:00,401 : main : -rw-r--r-- 1 massimodipierro staff 31 Aug 26 22:53 benchmark.py
|
||||
INFO : 2012-09-07 15:02:00,402 : main : -rw-r--r-- 1 massimodipierro staff 379 Aug 28 17:31 check.py
|
||||
INFO : 2012-09-07 15:02:00,403 : main : -rw-r--r-- 1 massimodipierro staff 220 Sep 2 12:08 compile_rotator.py
|
||||
INFO : 2012-09-07 15:02:00,403 : main : -rw-r--r-- 1 massimodipierro staff 3135 Aug 29 17:20 cookies.py
|
||||
INFO : 2012-09-07 15:02:00,404 : main : -rw-r--r-- 1 massimodipierro staff 4759 Sep 6 16:05 daemon.py
|
||||
INFO : 2012-09-07 15:02:00,404 : main : -rw-r--r-- 1 massimodipierro staff 2759 Sep 7 15:01 fofo.py
|
||||
INFO : 2012-09-07 15:02:00,405 : main : -rw-r--r-- 1 massimodipierro staff 723 Sep 7 13:43 fofo.py~
|
||||
INFO : 2012-09-07 15:02:00,405 : main : -rw-r--r-- 1 massimodipierro staff 64 Sep 6 15:11 looping.py
|
||||
INFO : 2012-09-07 15:02:00,406 : main : prw-r--r-- 1 massimodipierro staff 0 Sep 7 15:02 out_fifo
|
||||
INFO : 2012-09-07 15:02:00,408 : main : -rw-r--r-- 1 massimodipierro staff 1218 Sep 6 15:11 process.py
|
||||
INFO : 2012-09-07 15:02:00,409 : main : -rw-r--r-- 1 massimodipierro staff 475 Sep 6 09:32 read.py
|
||||
INFO : 2012-09-07 15:02:00,410 : main : -rw-r--r-- 1 massimodipierro staff 581 Sep 7 15:02 runcmd.log
|
||||
INFO : 2012-09-07 15:02:00,410 : main : drwxr-xr-x 3 massimodipierro staff 102 Sep 6 16:04 t1
|
||||
INFO : 2012-09-07 15:02:00,411 : main : -rw-r--r-- 1 massimodipierro staff 170 Aug 26 09:45 test1.py
|
||||
INFO : 2012-09-07 15:02:00,412 : main : -rw-r--r-- 1 massimodipierro staff 270 Aug 26 10:43 test2.py
|
||||
INFO : 2012-09-07 15:02:00,412 : main : -rw-r--r-- 1 massimodipierro staff 1434 Aug 28 18:51 test3.py
|
||||
INFO : 2012-09-07 15:02:00,413 : main : -rw-r--r-- 1 massimodipierro staff 649 Aug 30 15:16 test7.py
|
||||
INFO : 2012-09-07 15:02:00,413 : main : -rw-r--r-- 1 massimodipierro staff 507 Sep 2 16:41 test8.py
|
||||
INFO : 2012-09-07 15:02:00,414 : main : -rw-r--r-- 1 massimodipierro staff 118 Aug 28 14:52 test_1.py
|
||||
INFO : 2012-09-07 15:02:00,414 : main : -rw-r--r-- 1 massimodipierro staff 595 Aug 28 10:42 test_bruno.py
|
||||
INFO : 2012-09-07 15:02:00,415 : main : -rw-r--r-- 1 massimodipierro staff 515 Aug 28 09:54 test_cache.py
|
||||
INFO : 2012-09-07 15:02:00,415 : main : -rw-r--r-- 1 massimodipierro staff 304 Aug 28 14:19 test_dominc.py
|
||||
INFO : 2012-09-07 15:02:00,416 : main : -rw-r--r-- 1 massimodipierro staff 2859 Aug 31 10:17 test_jim.py
|
||||
INFO : 2012-09-07 15:02:00,416 : main : prw-r--r-- 1 massimodipierro staff 0 Sep 7 13:30 tmp.1
|
||||
INFO : 2012-09-07 15:02:05,411 : main : hi!
|
||||
109
temps/server.py
Normal file
109
temps/server.py
Normal file
@@ -0,0 +1,109 @@
|
||||
import asyncore
|
||||
import asynchat
|
||||
import socket
|
||||
import time
|
||||
import sys
|
||||
import thread
|
||||
import string
|
||||
|
||||
RN = '\r\n'
|
||||
STATUS_READING_HEADERS = 0
|
||||
STATUS_READING_BODY = 1
|
||||
STATUS_SENDING_RESPONSE = 2
|
||||
|
||||
class http_request_handler(asynchat.async_chat):
|
||||
|
||||
def __init__(self, sock, addr, sessions, log):
|
||||
asynchat.async_chat.__init__(self, sock=sock)
|
||||
self.addr = addr
|
||||
self.sessions = sessions
|
||||
self.ibuffer = []
|
||||
self.obuffer = ""
|
||||
self.set_terminator(RN+RN)
|
||||
self.reading_headers = True
|
||||
self.handling = False
|
||||
self.cgi_data = None
|
||||
self.log = log
|
||||
self.status = STATUS_READING_HEADERS
|
||||
|
||||
def collect_incoming_data(self, data):
|
||||
"""Buffer the data"""
|
||||
self.ibuffer.append(data)
|
||||
|
||||
def parse_headers(self,data):
|
||||
if '\0' in data:
|
||||
|
||||
first_line, headers = data.split(RM,1)
|
||||
self.op, self.path_info = first_line.split(' ',1)
|
||||
lines = headers.replace(RN+' ',' ').replace(RN+'\t',' ').split(RN)
|
||||
items = [line.split(':',1) for line in lines.split(RN) if ':' in line]
|
||||
self.headers = dict((item[0].upper(),item[1]) for item in items)
|
||||
self.close()
|
||||
|
||||
def found_terminator(self):
|
||||
if self.status==STATUS_READING_HEADERS:
|
||||
self.parse_headers(string.join(self.ibuffer,'')+'\r\n')
|
||||
self.ibuffer = []
|
||||
if self.op.upper() == "POST":
|
||||
clen = self.headers.getheader("content-length")
|
||||
self.set_terminator(int(clen))
|
||||
self.status=STATUS_READ_BODY
|
||||
else:
|
||||
self.status=STATUS_SEND_RESPONSE
|
||||
elif self.status==STATUS_READ_BODY:
|
||||
self.ibuffer
|
||||
|
||||
self.set_terminator(None)
|
||||
for data in self.run_app():
|
||||
self.push(data)
|
||||
time.sleep(1)
|
||||
self.close()
|
||||
elif not self.handling:
|
||||
self.set_terminator(None) # browsers sometimes over-send
|
||||
self.cgi_data = parse(self.headers, "".join(self.ibuffer))
|
||||
self.handling = True
|
||||
self.ibuffer = []
|
||||
self.handle_request()
|
||||
|
||||
def handle_write(self):
|
||||
print 'handle_write', self.buffer
|
||||
self.send(self.buffer)
|
||||
self.buffer = ''
|
||||
|
||||
def run_app(self):
|
||||
return ['200 OK\r\n\r\n','Hello\n','World\n','%s\n' % time.ctime()]
|
||||
|
||||
class HTTPServer(asyncore.dispatcher):
|
||||
def __init__(self, host, port, app):
|
||||
asyncore.dispatcher.__init__(self)
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.app = app
|
||||
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.set_reuse_addr()
|
||||
self.bind((host, port))
|
||||
self.listen(20)
|
||||
|
||||
def handle_accept(self):
|
||||
pair = self.accept()
|
||||
if not pair is None:
|
||||
sock, addr = pair
|
||||
print 'Incoming connection from %s' % repr(addr)
|
||||
handler = http_request_handler(sock, addr, SESSIONS, None)
|
||||
handler.server = self
|
||||
|
||||
def test_client(address='127.0.0.1:8000'):
|
||||
time.sleep(3)
|
||||
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
ip,port = address.split(':',1)
|
||||
server.connect((ip,int(port)))
|
||||
server.send('GET /\r\n\r\nthis the body')
|
||||
while True:
|
||||
sys.stdout.write(server.recv(1))
|
||||
sys.stdout.write('CLOSE\n')
|
||||
|
||||
thread.start_new_thread(test_client,())
|
||||
thread.start_new_thread(test_client,())
|
||||
thread.start_new_thread(test_client,())
|
||||
server = HTTPServer('localhost', 8000, lambda e,r: ['data'])
|
||||
asyncore.loop()
|
||||
31
temps/singleton.py
Normal file
31
temps/singleton.py
Normal file
@@ -0,0 +1,31 @@
|
||||
import threading
|
||||
|
||||
class SingletonPool(object):
|
||||
|
||||
thread_local = threading.local
|
||||
locker = threadling.RLock()
|
||||
pool = dict()
|
||||
|
||||
def __new__(cls, uri, *args, **kwargs):
|
||||
print 'in new'
|
||||
if not hasattr(thread_local,'db_instances'):
|
||||
thread_local.db_instances = {}
|
||||
try:
|
||||
instance = thread_local.db_instances[uri]
|
||||
print 'found existing instance'
|
||||
except KeyError:
|
||||
instance = super(DAL, cls).__new__(cls, uri, *args, **kwargs)
|
||||
thread_local.db_instances[uri] = instance
|
||||
return instance
|
||||
|
||||
def __init__(self,uri,*args, **kwargs):
|
||||
print "INIT"
|
||||
try:
|
||||
self.uri
|
||||
print 'have self.uri',self.uri
|
||||
except:
|
||||
self.uri = uri
|
||||
|
||||
db=DAL('test')
|
||||
print 'here'
|
||||
db=DAL('test')
|
||||
42
temps/static.py
Normal file
42
temps/static.py
Normal file
@@ -0,0 +1,42 @@
|
||||
import re
|
||||
|
||||
regex_url = re.compile(r'''
|
||||
(^( # (/a/c/f.e/s)
|
||||
/(?P<a> [\w\s+]+ ) # /a=app
|
||||
( # (/c.f.e/s)
|
||||
/(?P<c> [\w\s+]+ ) # /a/c=controller
|
||||
( # (/f.e/s)
|
||||
/(?P<f> [\w\s+]+ ) # /a/c/f=function
|
||||
( # (.e)
|
||||
\.(?P<e> [\w\s+]+ ) # /a/c/f.e=extension
|
||||
)?
|
||||
( # (/s)
|
||||
/(?P<r> # /a/c/f.e/r=raw_args
|
||||
.*
|
||||
)
|
||||
)?
|
||||
)?
|
||||
)?
|
||||
)?
|
||||
/?$)
|
||||
''', re.X)
|
||||
|
||||
import time
|
||||
n=100000
|
||||
path = '/app/static/f.e/filename'
|
||||
t0=time.time()
|
||||
for k in range(n):
|
||||
m = regex_url.match(path)
|
||||
m.group('a')
|
||||
m.group('c')
|
||||
m.group('f')
|
||||
print (time.time()-t0)/n
|
||||
|
||||
t0=time.time()
|
||||
for k in range(n):
|
||||
m = path.split('/')
|
||||
lm = len(m)
|
||||
if lm==0: m.append('a')
|
||||
if lm==1: m.append('c')
|
||||
if lm==2: m.append('f')
|
||||
print (time.time()-t0)/n
|
||||
11
temps/test1.py
Normal file
11
temps/test1.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from gluon.storage import Storage as Storage
|
||||
n=10000
|
||||
import time
|
||||
|
||||
s = Storage()
|
||||
t0 = time.time()
|
||||
for k in range(n):
|
||||
s.x = 1
|
||||
y = s.x
|
||||
print (time.time()-t0)/n
|
||||
|
||||
12
temps/test2.py
Normal file
12
temps/test2.py
Normal file
@@ -0,0 +1,12 @@
|
||||
db=DAL()
|
||||
db.define_table('person',Field('name'))
|
||||
db.person.insert(name="max")
|
||||
db.person.insert(name="max")
|
||||
db.person.insert(name="max")
|
||||
print db(db.person).select().xml(strict=True)
|
||||
|
||||
import pickle
|
||||
|
||||
print db.person[1]
|
||||
s = pickle.dumps(db.person[1])
|
||||
print pickle.loads(s)
|
||||
54
temps/test3.py
Normal file
54
temps/test3.py
Normal file
@@ -0,0 +1,54 @@
|
||||
# run with web2py.py -S welcome -N -R thisfile.py
|
||||
import time
|
||||
|
||||
db=DAL()
|
||||
db.define_table('test',Field('one'))
|
||||
db(db.test).delete()
|
||||
for k in range(1000):
|
||||
db.test.insert(one='one')
|
||||
db.commit()
|
||||
|
||||
n = 100
|
||||
t0 = time.time()
|
||||
for k in range(n):
|
||||
y = db.test.one
|
||||
print 'time to access field obj',(time.time()-t0)/n
|
||||
|
||||
t0 = time.time()
|
||||
for k in range(n):
|
||||
rows = db(db.test).select(cacheable=False) # (*)
|
||||
print 'time to select 1000 recods',(time.time()-t0)/n/1000
|
||||
|
||||
row = db(db.test).select().first()
|
||||
t0 = time.time()
|
||||
for k in range(n):
|
||||
y = row.id
|
||||
y = row.one
|
||||
print 'time to access field values',(time.time()-t0)/n
|
||||
|
||||
"""
|
||||
Results:
|
||||
|
||||
web2py 1.99.7
|
||||
|
||||
time to access field obj 5.068 (microseconds)
|
||||
time to select 1000 recods 38.441 (microseconds)
|
||||
time to access field values 7.710 (microseconds)
|
||||
total time to access one field for each of 1000 records: 7748 (microseconds)
|
||||
|
||||
web2py 2.0
|
||||
time to access field obj 0.579 (microseconds)
|
||||
time to select 1000 recods 33.820 (microseconds)
|
||||
time to access field values 0.338 (microseconds)
|
||||
total time to access one field for each of 1000 records: 371 (microseconds)
|
||||
|
||||
web2py 2.0 w cacheable = True (*)
|
||||
|
||||
time to access field obj 0.579 (microseconds)
|
||||
time to select 1000 recods 24.741 (microseconds)
|
||||
time to access field values 0.300 (microseconds)
|
||||
total time to access one field for each of 1000 records: 324 (microseconds)
|
||||
|
||||
(benhcmarks with SQLite on Mac Air and python 2.7)
|
||||
"""
|
||||
|
||||
17
temps/test7.py
Normal file
17
temps/test7.py
Normal file
@@ -0,0 +1,17 @@
|
||||
db=DAL()
|
||||
db.define_table('Meet',Field('name'))
|
||||
db.define_table('Team',Field('name'))
|
||||
db.define_table('Participant_team',
|
||||
Field('Meet',db.Meet),
|
||||
Field('Team',db.Team))
|
||||
|
||||
a=db.Meet.insert(name='here')
|
||||
b=db.Team.insert(name='snakes')
|
||||
db.Participant_team.insert(Meet=a,Team=b)
|
||||
teamStaff = db(db.Meet.id == a).select(
|
||||
db.Meet.ALL, db.Team.ALL,
|
||||
join = db.Team.on(
|
||||
(db.Participant_team.Meet == db.Meet.id) &
|
||||
(db.Participant_team.Team == db.Team.id)))
|
||||
|
||||
print teamStaff
|
||||
9
temps/test8.py
Normal file
9
temps/test8.py
Normal file
@@ -0,0 +1,9 @@
|
||||
db=DAL()
|
||||
db.define_table('t',Field('a'))
|
||||
db.t.insert(a='xxx')
|
||||
rows = db(db.t).select()
|
||||
import pickle
|
||||
print pickle.loads(pickle.dumps(rows))
|
||||
rows = db(db.t).select(cacheable=True)
|
||||
s= pickle.dumps(rows)
|
||||
print pickle.loads(s)
|
||||
17
temps/test9.py
Normal file
17
temps/test9.py
Normal file
@@ -0,0 +1,17 @@
|
||||
db = DAL(lazy_tables = True)
|
||||
|
||||
db.define_table('x',
|
||||
Field('name', 'string')
|
||||
)
|
||||
|
||||
db.define_table('y',
|
||||
Field('x', 'reference x'),
|
||||
Field('age', 'integer', default = 30)
|
||||
)
|
||||
|
||||
x_id = db.x.insert(name = 'barry')
|
||||
db.y.insert(x = x_id, age = 99)
|
||||
|
||||
x = db(db.x.id > 0).select().first()
|
||||
for y in x.y.select():
|
||||
print y
|
||||
5
temps/test_1.py
Normal file
5
temps/test_1.py
Normal file
@@ -0,0 +1,5 @@
|
||||
db=DAL()
|
||||
db.define_table('test',Field('myid','id'),Field('name'))
|
||||
db.test.insert(name='max')
|
||||
row=db.test[1]
|
||||
print row
|
||||
21
temps/test_bruno.py
Normal file
21
temps/test_bruno.py
Normal file
@@ -0,0 +1,21 @@
|
||||
db=DAL()
|
||||
|
||||
db.define_table("article",
|
||||
Field("title"),
|
||||
Field("slug"),
|
||||
Field("number_of_views", "integer", default=0)
|
||||
)
|
||||
def printer(row):
|
||||
print row
|
||||
return True
|
||||
db.article.slug.compute = lambda row: printer(row) and IS_SLUG()(row.title)[0]
|
||||
|
||||
|
||||
article_id = db.article.insert(title='This is a Test')
|
||||
row = db.article[article_id]
|
||||
print 'xxx1'
|
||||
print row.update_record(number_of_views=row.number_of_views + 1)
|
||||
print row.update_record(number_of_views=row.number_of_views + 1)
|
||||
print row.update_record(number_of_views=row.number_of_views + 1)
|
||||
print 'xxx2'
|
||||
print row
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user