Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b9d80fcdc7 | ||
|
|
3f7d085f73 | ||
|
|
d57dd72780 | ||
|
|
a8d1d5cfcf | ||
|
|
8857e3d521 | ||
|
|
3b1a5be1be | ||
|
|
c9a63a8524 | ||
|
|
cd967d2551 | ||
|
|
92b5247f9f | ||
|
|
45a5b436c8 | ||
|
|
bfd385f969 | ||
|
|
f693fe6b2a | ||
|
|
b040159a9b | ||
|
|
f3af2a1999 | ||
|
|
f613a4cc99 | ||
|
|
e4a96125a6 | ||
|
|
e48074ff54 | ||
|
|
2ed122a534 | ||
|
|
65c0d9b18b | ||
|
|
6702694590 | ||
|
|
6f0d4d039e | ||
|
|
1325b0e48f | ||
|
|
7421eb8068 | ||
|
|
6c7a9a4030 | ||
|
|
ba0a143717 | ||
|
|
28bcb5ed6c | ||
|
|
44fd637a1f | ||
|
|
f13aed1a84 | ||
|
|
cb3de825f2 | ||
|
|
fd4c775710 | ||
|
|
3e550b3e97 | ||
|
|
7a543250f9 | ||
|
|
a071f07634 | ||
|
|
a078f860d2 | ||
|
|
2bfd7a2467 | ||
|
|
55c9392de4 | ||
|
|
7991b555ff | ||
|
|
eab7815c24 | ||
|
|
79c09de103 | ||
|
|
24daa335b6 | ||
|
|
812ba9d52b | ||
|
|
00fb3b56cc | ||
|
|
3644d081f6 | ||
|
|
f05c46b3f1 | ||
|
|
13e76fe278 | ||
|
|
0906ae28c1 | ||
|
|
04905adb89 | ||
|
|
9767109d4e | ||
|
|
a57919bc4d | ||
|
|
c7c94d1f8f | ||
|
|
817e6c3313 | ||
|
|
a23f4c5c88 | ||
|
|
eac9768549 | ||
|
|
a42fb6b558 | ||
|
|
879e825b61 | ||
|
|
07f4310153 | ||
|
|
10c67e5be3 | ||
|
|
1279d5ddaa | ||
|
|
2af15e4b27 | ||
|
|
3096fcf045 | ||
|
|
831492448a | ||
|
|
a5284e846c | ||
|
|
22accaced3 | ||
|
|
f92d97f36e | ||
|
|
4f0a16a24c | ||
|
|
72dade793a | ||
|
|
8addc54015 | ||
|
|
25ab6f9a07 | ||
|
|
b853f72e0c | ||
|
|
449a658521 | ||
|
|
7776a22533 | ||
|
|
554eccc14a | ||
|
|
8cd6928da3 | ||
|
|
8c28be1041 | ||
|
|
810aa8f4f3 | ||
|
|
8e5be952bf | ||
|
|
5a560fee8a | ||
|
|
21819ffc5d | ||
|
|
1f8bdd6061 | ||
|
|
523c813439 | ||
|
|
7ee638bc36 | ||
|
|
76c515d3af | ||
|
|
1c8ce00657 | ||
|
|
0f4bbecd2a | ||
|
|
e292f5a869 | ||
|
|
da25c6f843 | ||
|
|
5122fbe110 | ||
|
|
dee3a3b655 | ||
|
|
4e2bcd22d9 | ||
|
|
17890027a6 | ||
|
|
5e93804525 | ||
|
|
778070dd8a | ||
|
|
74ecc762f3 | ||
|
|
63f7b35cf8 | ||
|
|
0c3f4601cc | ||
|
|
101b74398f |
@@ -0,0 +1,25 @@
|
|||||||
|
language: python
|
||||||
|
|
||||||
|
python:
|
||||||
|
- '2.5'
|
||||||
|
- '2.6'
|
||||||
|
- '2.7'
|
||||||
|
env:
|
||||||
|
- DB=sqlite:memory
|
||||||
|
- DB=mysql://root:@localhost/test_w2p
|
||||||
|
- DB=postgres://postgres:@localhost/test_w2p
|
||||||
|
before_script:
|
||||||
|
- pip install unittest2
|
||||||
|
- if [[ $DB == postgres* ]]; then pip install --use-mirrors psycopg2; fi
|
||||||
|
- if [[ $TRAVIS_PYTHON_VERSION == '2.5' ]]; then pip install --use-mirrors pysqlite; fi
|
||||||
|
- if [[ $DB == mysql* ]]; then mysql -e 'create database test_w2p;'; fi
|
||||||
|
- if [[ $DB == postgres* ]]; then psql -c 'create database test_w2p;' -U postgres; fi
|
||||||
|
#Temporal solution to travis issue #155
|
||||||
|
- sudo chmod 777 /dev/shm
|
||||||
|
- sudo rm -rf /dev/shm && sudo ln -s /run/shm /dev/shm
|
||||||
|
script: PYTHONPATH=. unit2 -v gluon.tests
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
email: false
|
||||||
|
irc:
|
||||||
|
channels: "irc.freenode.org#web2py"
|
||||||
@@ -1,4 +1,9 @@
|
|||||||
## 2.4.1- 2.4.2
|
## 2.4.5
|
||||||
|
|
||||||
|
- travis.ci integration (thanks Marc Abramowitz and Niphlod). Passes all tests (thanks Niplod).
|
||||||
|
- IS_DATE and IS_DATETIME can specify timezone
|
||||||
|
|
||||||
|
## 2.4.1- 2.4.3
|
||||||
|
|
||||||
- 2D GEO API: geoPoint, getLine, geoPolygon
|
- 2D GEO API: geoPoint, getLine, geoPolygon
|
||||||
- support for 'json' field type in DAL
|
- support for 'json' field type in DAL
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
Web2py is Licensed under the LGPL license version 3
|
Web2py is Licensed under the LGPL license version 3
|
||||||
(http://www.gnu.org/licenses/lgpl.html)
|
(http://www.gnu.org/licenses/lgpl.html)
|
||||||
|
|
||||||
Copyrighted (c) by Massimo Di Pierro (2007-2011)
|
Copyrighted (c) by Massimo Di Pierro (2007-2013)
|
||||||
|
|
||||||
### On Commercial Redistribution
|
### On Commercial Redistribution
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ all:
|
|||||||
clean:
|
clean:
|
||||||
rm -f httpserver.log
|
rm -f httpserver.log
|
||||||
rm -f parameters*.py
|
rm -f parameters*.py
|
||||||
rm -f -r applications/*/compiled
|
rm -f -r applications/*/compiled
|
||||||
find ./ -name '*~' -exec rm -f {} \;
|
find ./ -name '*~' -exec rm -f {} \;
|
||||||
find ./ -name '*.orig' -exec rm -f {} \;
|
find ./ -name '*.orig' -exec rm -f {} \;
|
||||||
find ./ -name '*.rej' -exec rm -f {} \;
|
find ./ -name '*.rej' -exec rm -f {} \;
|
||||||
@@ -30,7 +30,7 @@ update:
|
|||||||
echo "remember that pymysql was tweaked"
|
echo "remember that pymysql was tweaked"
|
||||||
src:
|
src:
|
||||||
### Use semantic versioning
|
### Use semantic versioning
|
||||||
echo 'Version 2.4.2-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION
|
echo 'Version 2.4.5-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION
|
||||||
### rm -f all junk files
|
### rm -f all junk files
|
||||||
make clean
|
make clean
|
||||||
### clean up baisc apps
|
### clean up baisc apps
|
||||||
|
|||||||
@@ -6,6 +6,11 @@ It is written and programmable in Python. LGPLv3 License
|
|||||||
|
|
||||||
Learn more at http://web2py.com
|
Learn more at http://web2py.com
|
||||||
|
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
[](https://travis-ci.org/web2py/web2py)
|
||||||
|
|
||||||
## Installation Instructions
|
## Installation Instructions
|
||||||
|
|
||||||
To start web2py there is NO NEED to install it. Just unzip and do:
|
To start web2py there is NO NEED to install it. Just unzip and do:
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
Version 2.4.2-stable+timestamp.2013.03.03.21.22.42
|
Version 2.4.5-stable+timestamp.2013.03.18.17.37.19
|
||||||
|
|||||||
@@ -319,6 +319,9 @@ def state():
|
|||||||
|
|
||||||
|
|
||||||
def ccache():
|
def ccache():
|
||||||
|
cache.ram.initialize()
|
||||||
|
cache.disk.initialize()
|
||||||
|
|
||||||
form = FORM(
|
form = FORM(
|
||||||
P(TAG.BUTTON(
|
P(TAG.BUTTON(
|
||||||
T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
|
T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
|
||||||
@@ -385,7 +388,7 @@ def ccache():
|
|||||||
|
|
||||||
return (hours, minutes, seconds)
|
return (hours, minutes, seconds)
|
||||||
|
|
||||||
for key, value in cache.ram.storage.items():
|
for key, value in cache.ram.storage.iteritems():
|
||||||
if isinstance(value, dict):
|
if isinstance(value, dict):
|
||||||
ram['hits'] = value['hit_total'] - value['misses']
|
ram['hits'] = value['hit_total'] - value['misses']
|
||||||
ram['misses'] = value['misses']
|
ram['misses'] = value['misses']
|
||||||
|
|||||||
@@ -148,9 +148,7 @@ def check_version():
|
|||||||
elif platform.system().lower() in ('windows', 'win32', 'win64') and os.path.exists("web2py.exe"):
|
elif platform.system().lower() in ('windows', 'win32', 'win64') and os.path.exists("web2py.exe"):
|
||||||
return SPAN('You should upgrade to version %s.%s.%s' % version_number[:3])
|
return SPAN('You should upgrade to version %s.%s.%s' % version_number[:3])
|
||||||
else:
|
else:
|
||||||
return sp_button(URL('upgrade_web2py'), T('upgrade now')) \
|
return sp_button(URL('upgrade_web2py'), T('upgrade now to %s') % version_number.split('-')[0])
|
||||||
+ XML(' <strong class="upgrade_version">%s.%s.%s</strong>'
|
|
||||||
% version_number[:3])
|
|
||||||
|
|
||||||
|
|
||||||
def logout():
|
def logout():
|
||||||
@@ -205,14 +203,12 @@ def site():
|
|||||||
|
|
||||||
is_appname = IS_VALID_APPNAME()
|
is_appname = IS_VALID_APPNAME()
|
||||||
form_create = SQLFORM.factory(Field('name', requires=is_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),
|
form_update = SQLFORM.factory(Field('name', requires=is_appname),
|
||||||
Field('file', 'upload', uploadfield=False),
|
Field('file', 'upload', uploadfield=False),
|
||||||
Field('url'),
|
Field('url'),
|
||||||
Field('overwrite', 'boolean'),
|
Field('overwrite', 'boolean'),
|
||||||
table_name='appupdate',
|
table_name='appupdate')
|
||||||
_class='well well-small')
|
|
||||||
form_create.process()
|
form_create.process()
|
||||||
form_update.process()
|
form_update.process()
|
||||||
|
|
||||||
@@ -1430,7 +1426,7 @@ def errors():
|
|||||||
hash2error[hash]['count'] += 1
|
hash2error[hash]['count'] += 1
|
||||||
except KeyError:
|
except KeyError:
|
||||||
error_lines = error['traceback'].split("\n")
|
error_lines = error['traceback'].split("\n")
|
||||||
last_line = error_lines[-2]
|
last_line = error_lines[-2] if len(error_lines)>1 else 'unknown'
|
||||||
error_causer = os.path.split(error['layer'])[1]
|
error_causer = os.path.split(error['layer'])[1]
|
||||||
hash2error[hash] = dict(count=1, pickel=error,
|
hash2error[hash] = dict(count=1, pickel=error,
|
||||||
causer=error_causer,
|
causer=error_causer,
|
||||||
@@ -1667,7 +1663,7 @@ def twitter():
|
|||||||
d = dict()
|
d = dict()
|
||||||
for e in data:
|
for e in data:
|
||||||
d[e["id"]] = e
|
d[e["id"]] = e
|
||||||
r = reversed(sorted(d))
|
r = reversed(sorted(d))
|
||||||
return dict(tweets=[d[k] for k in r])
|
return dict(tweets=[d[k] for k in r])
|
||||||
else:
|
else:
|
||||||
return 'disabled'
|
return 'disabled'
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ if request.vars.app or request.args:
|
|||||||
|
|
||||||
if os.path.exists('applications/examples'):
|
if os.path.exists('applications/examples'):
|
||||||
response.menu.append(
|
response.menu.append(
|
||||||
(T('Help'), False, URL('examples', 'default', 'index')))
|
(T('Help'), False, URL('examples', 'default', 'documentation')))
|
||||||
else:
|
else:
|
||||||
response.menu.append((T('Help'), False, 'http://web2py.com/examples'))
|
response.menu.append((T('Help'), False, 'http://web2py.com/examples/default/documentation'))
|
||||||
|
|
||||||
if not session.authorized:
|
if not session.authorized:
|
||||||
response.menu = [(T('Login'), True, URL('site'))]
|
response.menu = [(T('Login'), True, URL('site'))]
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ td.w2p_fl,td.w2p_fc {padding:0;}
|
|||||||
==============================================================*/
|
==============================================================*/
|
||||||
|
|
||||||
/* because web2py handles this via js */
|
/* because web2py handles this via js */
|
||||||
|
textarea { width:90%}
|
||||||
.hidden{visibility:visible;}
|
.hidden{visibility:visible;}
|
||||||
/* right folder for bootstrap black images/icons */
|
/* right folder for bootstrap black images/icons */
|
||||||
[class^="icon-"],[class*=" icon-"]{
|
[class^="icon-"],[class*=" icon-"]{
|
||||||
|
|||||||
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
@@ -1,69 +1,69 @@
|
|||||||
{{extend 'layout.html'}}
|
{{extend 'layout.html'}}
|
||||||
{{
|
{{
|
||||||
def all(items):
|
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):
|
def peekfile(path,file,vars={},title=None):
|
||||||
args=(path,file) if 'app' in vars else (app,path,file)
|
args=(path,file) if 'app' in vars else (app,path,file)
|
||||||
return A(file.replace('\\\\','/'),_title=title,_href=URL('peek', args=args, vars=vars))
|
return A(file.replace('\\\\','/'),_title=title,_href=URL('peek', args=args, vars=vars))
|
||||||
def editfile(path,file,vars={}):
|
def editfile(path,file,vars={}):
|
||||||
args=(path,file) if 'app' in vars else (app,path,file)
|
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))
|
return A(SPAN(T('Edit')),_class='button editbutton btn btn-mini',_href=URL('edit', args=args, vars=vars))
|
||||||
def testfile(path,file):
|
def testfile(path,file):
|
||||||
return A(TAG[''](IMG(_src=URL('static', 'images/test_icon.png'), _alt=T('test')),
|
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')"))),
|
SPAN(T("Run tests in this file (to run all files, you may also use the button labelled 'test')"))),
|
||||||
_class='icon test',
|
_class='icon test',
|
||||||
_href=URL('test', args=(app, file)),
|
_href=URL('test', args=(app, file)),
|
||||||
_rel="tooltip",
|
_rel="tooltip",
|
||||||
**{'_data-placement':'right',
|
**{'_data-placement':'right',
|
||||||
'_data-original-title':T("Run tests in this file (to run all files, you may also use the button labelled 'test')")})
|
'_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={}):
|
def editlanguagefile(path,file,vars={}):
|
||||||
return A(SPAN(T('Edit')),_class='button editbutton btn',_href=URL('edit_language', args=(app, path, file), vars=vars))
|
return A(SPAN(T('Edit')),_class='button editbutton btn btn-mini',_href=URL('edit_language', args=(app, path, file), vars=vars))
|
||||||
def editpluralsfile(path,file,vars={}):
|
def editpluralsfile(path,file,vars={}):
|
||||||
return A(SPAN(T('Edit')),_class='button editbutton btn',_href=URL('edit_plurals', args=(app, path, file), vars=vars))
|
return A(SPAN(T('Edit')),_class='button editbutton btn btn-mini',_href=URL('edit_plurals', args=(app, path, file), vars=vars))
|
||||||
def file_upload_form(location, anchor=None):
|
def file_upload_form(location, anchor=None):
|
||||||
form=FORM(
|
form=FORM(
|
||||||
LABEL(T("upload file:")),
|
LABEL(T("upload file:")),
|
||||||
INPUT(_type="file",_name="file"),
|
INPUT(_type="file",_name="file"),
|
||||||
LABEL(T("and rename it:")),
|
LABEL(T("and rename it:")),
|
||||||
INPUT(_type="text",_name="filename",requires=IS_NOT_EMPTY,_class=""),
|
INPUT(_type="text",_name="filename",requires=IS_NOT_EMPTY,_class=""),
|
||||||
DIV(TAG['BUTTON'](T("Upload"),_type="submit",_class="btn"),_class="controls"),
|
DIV(TAG['BUTTON'](T("Upload"),_type="submit",_class="btn"),_class="controls"),
|
||||||
INPUT(_type="hidden",_name="location",_value=location),
|
INPUT(_type="hidden",_name="location",_value=location),
|
||||||
INPUT(_type="hidden",_name="token",_value=session.token),
|
INPUT(_type="hidden",_name="token",_value=session.token),
|
||||||
INPUT(_type="hidden",_name="sender",_value=URL('design',args=app, anchor=anchor)),
|
INPUT(_type="hidden",_name="sender",_value=URL('design',args=app, anchor=anchor)),
|
||||||
_action=URL('upload_file'),
|
_action=URL('upload_file'),
|
||||||
_class="generatedbyw2p well well-small")
|
_class="generatedbyw2p well well-small")
|
||||||
return form
|
return form
|
||||||
def file_create_form(location, anchor=None, helptext=""):
|
def file_create_form(location, anchor=None, helptext=""):
|
||||||
form=FORM(
|
form=FORM(
|
||||||
LABEL(T("create file with filename:")),
|
LABEL(T("create file with filename:")),
|
||||||
INPUT(_type="text",_name="filename",requires=IS_NOT_EMPTY,_class=''),
|
INPUT(_type="text",_name="filename",requires=IS_NOT_EMPTY,_class=''),
|
||||||
TAG['SMALL'](helptext,_class="help-block"),
|
TAG['SMALL'](helptext,_class="help-block"),
|
||||||
DIV(TAG['BUTTON'](T("Create"),_type="submit",_class="btn"),_class="controls"),
|
DIV(TAG['BUTTON'](T("Create"),_type="submit",_class="btn"),_class="controls"),
|
||||||
INPUT(_type="hidden",_name="location",_value=location),
|
INPUT(_type="hidden",_name="location",_value=location),
|
||||||
INPUT(_type="hidden",_name="sender",_value=URL('design',args=app)),
|
INPUT(_type="hidden",_name="sender",_value=URL('design',args=app)),
|
||||||
INPUT(_type="hidden",_name="token",_value=session.token),
|
INPUT(_type="hidden",_name="token",_value=session.token),
|
||||||
INPUT(_type="hidden",_name="id",_value=anchor),
|
INPUT(_type="hidden",_name="id",_value=anchor),
|
||||||
_action=URL('create_file'),
|
_action=URL('create_file'),
|
||||||
_class="generatedbyw2p well well-small")
|
_class="generatedbyw2p well well-small")
|
||||||
return form
|
return form
|
||||||
def upload_plugin_form(app, anchor=None):
|
def upload_plugin_form(app, anchor=None):
|
||||||
form=FORM(
|
form=FORM(
|
||||||
LABEL(T("upload plugin file:")),
|
LABEL(T("upload plugin file:")),
|
||||||
INPUT(_type="file",_name="pluginfile"),
|
INPUT(_type="file",_name="pluginfile"),
|
||||||
INPUT(_type="hidden",_name="id",_value=anchor),
|
INPUT(_type="hidden",_name="id",_value=anchor),
|
||||||
INPUT(_type="hidden",_name="token",_value=session.token),
|
INPUT(_type="hidden",_name="token",_value=session.token),
|
||||||
DIV(TAG['BUTTON'](T("Upload"),_type="submit",_class="btn"),_class="controls"),
|
DIV(TAG['BUTTON'](T("Upload"),_type="submit",_class="btn"),_class="controls"),
|
||||||
_class="generatedbyw2p well well-small")
|
_class="generatedbyw2p well well-small")
|
||||||
return form
|
return form
|
||||||
def deletefile(arglist, vars={}):
|
def deletefile(arglist, vars={}):
|
||||||
vars.update({'sender':request.function+'/'+app})
|
vars.update({'sender':request.function+'/'+app})
|
||||||
return A(TAG[''](IMG(_src=URL('static', 'images/delete_icon.png')),
|
return A(TAG[''](IMG(_src=URL('static', 'images/delete_icon.png')),
|
||||||
SPAN(T('Delete this file (you will be asked to confirm deletion)'))),
|
SPAN(T('Delete this file (you will be asked to confirm deletion)'))),
|
||||||
_href=URL('delete',args=arglist,vars=vars),
|
_href=URL('delete',args=arglist,vars=vars),
|
||||||
_class='icon delete',
|
_class='icon delete',
|
||||||
_rel="tooltip",
|
_rel="tooltip",
|
||||||
**{'_data-placement':'right',
|
**{'_data-placement':'right',
|
||||||
'_data-original-title':T('Delete this file (you will be asked to confirm deletion)')})
|
'_data-original-title':T('Delete this file (you will be asked to confirm deletion)')})
|
||||||
}}
|
}}
|
||||||
|
|
||||||
{{block sectionclass}}design{{end}}
|
{{block sectionclass}}design{{end}}
|
||||||
@@ -91,44 +91,45 @@ def deletefile(arglist, vars={}):
|
|||||||
|
|
||||||
<!-- MODELS -->
|
<!-- MODELS -->
|
||||||
<h3 id="_models" rel="pagebookmark">
|
<h3 id="_models" rel="pagebookmark">
|
||||||
<span class="component" onclick="collapse('models_inner');">{{=T("Models")}}</span>
|
<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')}}">
|
<a href="#models" rel="tooltip" data-placement="right" data-original-title="{{=T('The data representation, define database tables and sets')}}">
|
||||||
{{=helpicon()}}
|
{{=helpicon()}}
|
||||||
<span>{{=T("The data representation, define database tables and sets")}}</span>
|
<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>
|
</a><span id="models" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||||
</h3>
|
</h3>
|
||||||
<div id="models_inner" class="component_contents">
|
<div id="models_inner" class="component_contents">
|
||||||
{{if not models:}}<p><strong>{{=T("There are no models")}}</strong></p>{{else:}}
|
{{if not models:}}<p><strong>{{=T("There are no models")}}</strong></p>{{else:}}
|
||||||
<div class="controls comptools">
|
<div class="controls comptools">
|
||||||
{{=button(URL(a=app,c='appadmin',f='index'), T('database administration'))}}
|
{{=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):}}
|
{{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')}}
|
{{=button(URL('peek/%s/databases/sql.log'%app), 'sql.log')}}
|
||||||
{{pass}}
|
{{pass}}
|
||||||
{{=button(URL(a=app, c='appadmin',f='graph_model'), T('graph model'))}}
|
{{=button(URL(a=app, c='appadmin',f='graph_model'), T('graph model'))}}
|
||||||
</div>
|
</div>
|
||||||
<ul class="unstyled act_edit">
|
<ul class="unstyled act_edit">
|
||||||
{{for m in models:}}
|
{{for m in models:}}
|
||||||
{{id="models__"+m.replace('.','__')}}
|
{{id="models__"+m.replace('.','__')}}
|
||||||
<li id="{{='_'+id}}" rel="pagebookmark"><span id="{{=id}}" class="hashstick"> </span>
|
<li id="{{='_'+id}}" rel="pagebookmark"><span id="{{=id}}" class="hashstick"> </span>
|
||||||
<span class="filetools controls">
|
<span class="filetools controls">
|
||||||
{{=editfile('models',m, dict(id=id))}}
|
{{=editfile('models',m, dict(id=id))}}
|
||||||
{{=deletefile([app, 'models', m], dict(id=id, id2='models'))}}
|
{{=deletefile([app, 'models', m], dict(id=id, id2='models'))}}
|
||||||
</span>
|
</span>
|
||||||
<span class="file">
|
<span class="file">
|
||||||
{{=peekfile('models',m, dict(id=id))}}
|
{{=peekfile('models',m, dict(id=id))}}
|
||||||
</span>
|
</span>
|
||||||
<span class="extras">
|
<span class="extras">
|
||||||
{{if len(defines[m]):}}{{=T("defines tables")}} {{pass}}{{=XML(', '.join([B(table).xml() for table in defines[m]]))}}
|
{{if len(defines[m]):}}{{=T("defines tables")}} {{pass}}{{=XML(', '.join([B(table).xml() for table in defines[m]]))}}
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
</ul>
|
</ul>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
<div class="controls formfield">
|
<div class="controls formfield">
|
||||||
<div class="row-fluid">
|
<button onclick="jQuery('#form1').slideToggle()" class="btn btn-mini">Create</button>
|
||||||
<div class="span3">{{=file_create_form('%s/models/' % app, 'models')}}</div>
|
<div id="form1" class="row-fluid" style="display:none">
|
||||||
</div>
|
<div class="span3">{{=file_create_form('%s/models/' % app, 'models')}}</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- FIND CONTROLLER FUNCTIONS -->
|
<!-- FIND CONTROLLER FUNCTIONS -->
|
||||||
@@ -139,322 +140,330 @@ for c in controllers: controller_functions+=[c[:-3]+'/%s.html'%x for x in functi
|
|||||||
|
|
||||||
<!-- CONTROLLERS -->
|
<!-- CONTROLLERS -->
|
||||||
<h3 id="_controllers" rel="pagebookmark">
|
<h3 id="_controllers" rel="pagebookmark">
|
||||||
<span class="component" onclick="collapse('controllers_inner');">{{=T("Controllers")}}</span>
|
<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')}}">
|
<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()}}
|
{{=helpicon()}}
|
||||||
<span>{{=T("The application logic, each URL path is mapped in one exposed function in the controller")}}</span>
|
<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>
|
</a><span id="controllers" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||||
</h3>
|
</h3>
|
||||||
<div id="controllers_inner" class="component_contents">
|
<div id="controllers_inner" class="component_contents">
|
||||||
{{if not controllers:}}<p><strong>{{=T("There are no controllers")}}</strong></p>{{else:}}
|
{{if not controllers:}}<p><strong>{{=T("There are no controllers")}}</strong></p>{{else:}}
|
||||||
<div class="controls comptools">
|
<div class="controls comptools">
|
||||||
{{=button(URL(r=request,c='shell',f='index',args=app), T("shell"))}}
|
{{=button(URL(r=request,c='shell',f='index',args=app), T("shell"))}}
|
||||||
{{=button(URL('test',args=app), T("test"))}}
|
{{=button(URL('test',args=app), T("test"))}}
|
||||||
{{=button(URL('edit',args=[app,'cron','crontab']), T("crontab"))}}
|
{{=button(URL('edit',args=[app,'cron','crontab']), T("crontab"))}}
|
||||||
</div>
|
</div>
|
||||||
<ul class="unstyled act_edit">
|
<ul class="unstyled act_edit">
|
||||||
{{for c in controllers:}}
|
{{for c in controllers:}}
|
||||||
{{id="controllers__"+c.replace('.','__')}}
|
{{id="controllers__"+c.replace('.','__')}}
|
||||||
<li id="{{='_'+id}}" rel="pagebookmark"><span id="{{=id}}" class="hashstick"> </span>
|
<li id="{{='_'+id}}" rel="pagebookmark"><span id="{{=id}}" class="hashstick"> </span>
|
||||||
<span class="filetools controls">
|
<span class="filetools controls">
|
||||||
{{=editfile('controllers',c, dict(id=id))}}
|
{{=editfile('controllers',c, dict(id=id))}}
|
||||||
{{=deletefile([app, 'controllers', c], dict(id=id, id2='controllers'))}}
|
{{=deletefile([app, 'controllers', c], dict(id=id, id2='controllers'))}}
|
||||||
{{=testfile('controllers',c)}}
|
{{=testfile('controllers',c)}}
|
||||||
</span>
|
</span>
|
||||||
<span class="file">
|
<span class="file">
|
||||||
{{=peekfile('controllers',c, dict(id=id))}}
|
{{=peekfile('controllers',c, dict(id=id))}}
|
||||||
</span>
|
</span>
|
||||||
<span class="extras celled">
|
<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]]))}}
|
{{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>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
</ul>
|
</ul>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
<div class="controls formfield">
|
<div class="controls formfield">
|
||||||
<div class="row-fluid">
|
<button onclick="jQuery('#form2').slideToggle()" class="btn btn-mini">Create</button>
|
||||||
<div class="span3">{{=file_create_form('%s/controllers/' % app, 'controllers')}}</div>
|
<div id="form2" class="row-fluid" style="display:none">
|
||||||
</div>
|
<div class="span3">{{=file_create_form('%s/controllers/' % app, 'controllers')}}</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- VIEWS -->
|
<!-- VIEWS -->
|
||||||
<h3 id="_views" rel="pagebookmark">
|
<h3 id="_views" rel="pagebookmark">
|
||||||
<span class="component" onclick="collapse('views_inner');">{{=T("Views")}}</span>
|
<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')}}">
|
<a href="#views" rel="tooltip" data-placement="right" data-original-title="{{=T('The presentations layer, views are also known as templates')}}">
|
||||||
{{=helpicon()}}
|
{{=helpicon()}}
|
||||||
<span>{{=T("The presentations layer, views are also known as templates")}}</span>
|
<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>
|
</a><span id="views" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||||
</h3>
|
</h3>
|
||||||
<div id="views_inner" class="component_contents">
|
<div id="views_inner" class="component_contents">
|
||||||
{{if not views:}}<p><strong>{{=T("There are no views")}}</strong></p>{{else:}}
|
{{if not views:}}<p><strong>{{=T("There are no views")}}</strong></p>{{else:}}
|
||||||
<div class="controls comptools">
|
<div class="controls comptools">
|
||||||
{{=button(LAYOUTS_APP, T("download layouts"))}}
|
{{=button(LAYOUTS_APP, T("download layouts"))}}
|
||||||
</div>
|
</div>
|
||||||
<ul class="unstyled act_edit">
|
<ul class="unstyled act_edit">
|
||||||
{{for c in views:}}
|
{{for c in views:}}
|
||||||
{{id="views__"+c.replace('/','__').replace('.','__')}}
|
{{id="views__"+c.replace('/','__').replace('.','__')}}
|
||||||
<li id="{{='_'+id}}" rel="pagebookmark"><span id="{{=id}}" class="hashstick"> </span>
|
<li id="{{='_'+id}}" rel="pagebookmark"><span id="{{=id}}" class="hashstick"> </span>
|
||||||
<span class="filetools controls">
|
<span class="filetools controls">
|
||||||
{{=editfile('views',c, dict(id=id))}}
|
{{=editfile('views',c, dict(id=id))}}
|
||||||
{{=deletefile([app, 'views', c], dict(id=id, id2='views'))}}
|
{{=deletefile([app, 'views', c], dict(id=id, id2='views'))}}
|
||||||
</span>
|
</span>
|
||||||
<span class="file">
|
<span class="file">
|
||||||
{{=peekfile('views',c, dict(id=id))}}
|
{{=peekfile('views',c, dict(id=id))}}
|
||||||
</span>
|
</span>
|
||||||
<span class="extras celled celled-one">
|
<span class="extras celled celled-one">
|
||||||
{{if extend.has_key(c):}}{{=T("extends")}} <b>{{=extend[c]}}</b> {{pass}}
|
{{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]]))}}
|
{{if include[c]:}}{{=T("includes")}} {{pass}}{{=XML(', '.join([B(f).xml() for f in include[c]]))}}
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
</ul>
|
</ul>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
<div class="controls formfield">
|
<div class="controls formfield">
|
||||||
<div class="row-fluid">
|
<button onclick="jQuery('#form3').slideToggle()" class="btn btn-mini">Create</button>
|
||||||
<div class="span3">{{=file_create_form('%s/views/' % app, 'views')}}</div>
|
<div id="form3" class="row-fluid" style="display:none">
|
||||||
</div>
|
<div class="span3">{{=file_create_form('%s/views/' % app, 'views')}}</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- LANGUAGES -->
|
<!-- LANGUAGES -->
|
||||||
<h3 id="_languages" rel="pagebookmark">
|
<h3 id="_languages" rel="pagebookmark">
|
||||||
<span class="component" onclick="collapse('languages_inner');">{{=T("Languages")}}</span>
|
<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')}}">
|
<a href="#languages" rel="tooltip" data-placement="right" data-original-title="{{=T('Translation strings for the application')}}">
|
||||||
{{=helpicon()}}
|
{{=helpicon()}}
|
||||||
<span>{{=T("Translation strings for the application")}}</span>
|
<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>
|
</a><span id="languages" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||||
</h3>
|
</h3>
|
||||||
<div id="languages_inner" class="component_contents">
|
<div id="languages_inner" class="component_contents">
|
||||||
{{if not languages:}}<p><strong>{{=T("There are no translators, only default language is supported")}}</strong></p>{{else:}}
|
{{if not languages:}}<p><strong>{{=T("There are no translators, only default language is supported")}}</strong></p>{{else:}}
|
||||||
<div class="controls comptools">
|
<div class="controls comptools">
|
||||||
{{=button(URL('update_languages/'+app), T('update all languages'))}}
|
{{=button(URL('update_languages/'+app), T('update all languages'))}}
|
||||||
</div>
|
</div>
|
||||||
<ul class="unstyled act_edit">
|
<ul class="unstyled act_edit">
|
||||||
{{for lang in sorted(languages):
|
{{for lang in sorted(languages):
|
||||||
file = lang+'.py'
|
file = lang+'.py'
|
||||||
id = "languages__"+file.replace('.','__')}}
|
id = "languages__"+file.replace('.','__')}}
|
||||||
<li id="{{='_'+id}}" rel="pagebookmark" class="li-row"><span id="{{=id}}" class="hashstick"> </span>
|
<li id="{{='_'+id}}" rel="pagebookmark" class="li-row"><span id="{{=id}}" class="hashstick"> </span>
|
||||||
<span class="li-controls">
|
<span class="li-controls">
|
||||||
<span class="filetools controls">
|
<span class="filetools controls">
|
||||||
{{=editlanguagefile('languages',file)}}
|
{{=editlanguagefile('languages',file)}}
|
||||||
{{=deletefile([app, 'languages', file], dict(id=id, id2='languages'))}}
|
{{=deletefile([app, 'languages', file], dict(id=id, id2='languages'))}}
|
||||||
</span>
|
</span>
|
||||||
<span class="">
|
<span class="">
|
||||||
{{=peekfile('languages',file, dict(id=id))}}
|
{{=peekfile('languages',file, dict(id=id))}}
|
||||||
</span>
|
</span>
|
||||||
</span> <!-- /li-row -->
|
</span> <!-- /li-row -->
|
||||||
<span class="extras celled">
|
<span class="extras celled">
|
||||||
(
|
(
|
||||||
{{=T("Plural-Forms:")}}
|
{{=T("Plural-Forms:")}}
|
||||||
{{p=languages[lang][3:7]}}
|
{{p=languages[lang][3:7]}}
|
||||||
{{if p[2] == 'default':}}
|
{{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])}}
|
<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:}}
|
{{else:}}
|
||||||
{{if p[3] == 1:}}
|
{{if p[3] == 1:}}
|
||||||
{{=B(T("are not used"))}}
|
{{=B(T("are not used"))}}
|
||||||
{{else:}}
|
{{else:}}
|
||||||
{{pfile=p[0]}}
|
{{pfile=p[0]}}
|
||||||
{{if p[1]!=0:}}<span style="display:inline-block;margin-top:-10px;">
|
{{if p[1]!=0:}}<span style="display:inline-block;margin-top:-10px;">
|
||||||
<span class="filetools controls">
|
<span class="filetools controls">
|
||||||
{{=editpluralsfile('languages',pfile,dict(nplurals=p[3]))}}
|
{{=editpluralsfile('languages',pfile,dict(nplurals=p[3]))}}
|
||||||
</span>
|
</span>
|
||||||
<span class="file">
|
<span class="file">
|
||||||
{{=peekfile('languages',pfile,dict(id=id))}}
|
{{=peekfile('languages',pfile,dict(id=id))}}
|
||||||
</span></span>
|
</span></span>
|
||||||
{{else:}}
|
{{else:}}
|
||||||
<b>{{=T("are not used yet")}}</b>
|
<b>{{=T("are not used yet")}}</b>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
{{pass}}
|
{{pass}}
|
||||||
{{pass}}
|
{{pass}}
|
||||||
)
|
)
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
</ul>
|
</ul>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
<div class="controls formfield">
|
<div class="controls formfield">
|
||||||
<div class="row-fluid">
|
<button onclick="jQuery('#form4').slideToggle()" class="btn btn-mini">Create</button>
|
||||||
<div class="span3">{{=file_create_form('%s/languages/' % app, 'languages', T('(something like "it-it")'))}}</div>
|
<div id="form4" class="row-fluid" style="display:none">
|
||||||
</div>
|
<div class="span3">{{=file_create_form('%s/languages/' % app, 'languages', T('(something like "it-it")'))}}</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- STATIC -->
|
<!-- STATIC -->
|
||||||
<h3 id="_static" rel="pagebookmark">
|
<h3 id="_static" rel="pagebookmark">
|
||||||
<span class="component" onclick="collapse('static_inner');">{{=T("Static")}}</span>
|
<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')}}">
|
<a href="#static" rel="tooltip" data-placement="right" data-original-title="{{=T('These files are served without processing, your images go here')}}">
|
||||||
{{=helpicon()}}
|
{{=helpicon()}}
|
||||||
<span>{{=T("These files are served without processing, your images go here")}}</span>
|
<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>
|
</a><span id="static" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||||
</h3>
|
</h3>
|
||||||
<div id="static_inner" class="component_contents">
|
<div id="static_inner" class="component_contents">
|
||||||
{{if not statics:}}<p><strong>{{=T("There are no static files")}}</strong></p>{{else:}}
|
{{if not statics:}}<p><strong>{{=T("There are no static files")}}</strong></p>{{else:}}
|
||||||
<ul class="unstyled act_edit">
|
<ul class="unstyled act_edit">
|
||||||
{{
|
{{
|
||||||
path=[]
|
path=[]
|
||||||
for file in statics+['']:
|
for file in statics+['']:
|
||||||
items=file.split('/')
|
items=file.split('/')
|
||||||
file_path=items[:-1]
|
file_path=items[:-1]
|
||||||
filename=items[-1]
|
filename=items[-1]
|
||||||
while path!=file_path:
|
while path!=file_path:
|
||||||
if len(file_path)>=len(path) and all([v==file_path[k] for k,v in enumerate(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)])
|
path.append(file_path[len(path)])
|
||||||
thispath='static__'+'__'.join(path)
|
thispath='static__'+'__'.join(path)
|
||||||
}}
|
}}
|
||||||
<li class="folder"><i> </i>
|
<li class="folder"><i> </i>
|
||||||
<a href="javascript:collapse('{{=thispath}}');" class="file">{{=path[-1]}}/</a>
|
<a href="javascript:collapse('{{=thispath}}');" class="file">{{=path[-1]}}/</a>
|
||||||
<ul id="{{=thispath}}" style="display: none;" class="sublist">{{
|
<ul id="{{=thispath}}" style="display: none;" class="sublist">{{
|
||||||
else:
|
else:
|
||||||
path = path[:-1]
|
path = path[:-1]
|
||||||
}}
|
}}
|
||||||
</ul></li>
|
</ul></li>
|
||||||
{{
|
{{
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
if filename:
|
if filename:
|
||||||
}}
|
}}
|
||||||
<li>
|
<li>
|
||||||
<span class="filetools controls">
|
<span class="filetools controls">
|
||||||
{{=editfile('static',file, dict(id="static"))}} {{=deletefile([app,'static',file], dict(id="static",id2="static"))}}
|
{{=editfile('static',file, dict(id="static"))}} {{=deletefile([app,'static',file], dict(id="static",id2="static"))}}
|
||||||
</span>
|
</span>
|
||||||
<span class="file">
|
<span class="file">
|
||||||
<a href="{{=URL(a=app,c='static',f=file)}}">{{=filename}}</a>
|
<a href="{{=URL(a=app,c='static',f=file)}}">{{=filename}}</a>
|
||||||
</span>
|
</span>
|
||||||
</li>{{
|
</li>{{
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
}}
|
}}
|
||||||
</ul>
|
</ul>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
<div class="controls formfield">
|
<div class="controls formfield">
|
||||||
<div class="row-fluid">
|
<button onclick="jQuery('#form5').slideToggle()" class="btn btn-mini">Create/Upload</button>
|
||||||
<div class="span3">{{=file_create_form('%s/static/' % app, 'static')}}<em>{{=T('or alternatively')}}</em></div>
|
<div id="form5" class="row-fluid" style="display:none">
|
||||||
<div class="span3">{{=file_upload_form('%s/static/' % app, 'static')}}</div>
|
<div class="span3">{{=file_create_form('%s/static/' % app, 'static')}}<em>{{=T('or alternatively')}}</em></div>
|
||||||
</div>
|
<div class="span3">{{=file_upload_form('%s/static/' % app, 'static')}}</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- MODULES -->
|
<!-- MODULES -->
|
||||||
<h3 id="_modules" rel="pagebookmark">
|
<h3 id="_modules" rel="pagebookmark">
|
||||||
<span class="component" onclick="collapse('modules_inner');">{{=T("Modules")}}</span>
|
<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')}}">
|
<a href="#modules" rel="tooltip" data-placement="right" data-original-title="{{=T('Additional code for your application')}}">
|
||||||
{{=helpicon()}}
|
{{=helpicon()}}
|
||||||
<span>{{=T("Additional code for your application")}}</span>
|
<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>
|
</a><span id="modules" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||||
</h3>
|
</h3>
|
||||||
<div id="modules_inner" class="component_contents">
|
<div id="modules_inner" class="component_contents">
|
||||||
{{if not modules:}}<p><strong>{{=T("There are no modules")}}</strong></p>{{else:}}
|
{{if not modules:}}<p><strong>{{=T("There are no modules")}}</strong></p>{{else:}}
|
||||||
<ul class="unstyled act_edit">
|
<ul class="unstyled act_edit">
|
||||||
{{for m in modules:}}
|
{{for m in modules:}}
|
||||||
{{id="modules__"+m.replace('/','__').replace('.','__')}}
|
{{id="modules__"+m.replace('/','__').replace('.','__')}}
|
||||||
<li id="{{='_'+id}}" rel="pagebookmark"><span id="{{=id}}" class="hashstick"> </span>
|
<li id="{{='_'+id}}" rel="pagebookmark"><span id="{{=id}}" class="hashstick"> </span>
|
||||||
<span class="filetols controls">
|
<span class="filetols controls">
|
||||||
{{=editfile('modules',m,dict(id=id))}}
|
{{=editfile('modules',m,dict(id=id))}}
|
||||||
{{if m!='__init__.py':}}
|
{{if m!='__init__.py':}}
|
||||||
{{=deletefile([app, 'modules', m], dict(id=id, id2='modules'))}}
|
{{=deletefile([app, 'modules', m], dict(id=id, id2='modules'))}}
|
||||||
{{pass}}
|
{{pass}}
|
||||||
</span>
|
</span>
|
||||||
<span class="file">
|
<span class="file">
|
||||||
{{=peekfile('modules',m, dict(id=id))}}
|
{{=peekfile('modules',m, dict(id=id))}}
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
</ul>
|
</ul>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
<div class="controls formfield">
|
<div class="controls formfield">
|
||||||
<div class="row-fluid">
|
<button onclick="jQuery('#form6').slideToggle()" class="btn btn-mini">Create/Upload</button>
|
||||||
<div class="span3">{{=file_create_form('%s/modules/' % app, 'modules')}}<em>{{=T('or alternatively')}}</em></div>
|
<div id="form6" class="row-fluid" style="display:none">
|
||||||
<div class="span3">{{=file_upload_form('%s/modules/' % app, 'modules')}}</div>
|
<div class="span3">{{=file_create_form('%s/modules/' % app, 'modules')}}<em>{{=T('or alternatively')}}</em></div>
|
||||||
</div>
|
<div class="span3">{{=file_upload_form('%s/modules/' % app, 'modules')}}</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- PRIVATE -->
|
<!-- PRIVATE -->
|
||||||
<h3 id="_private" rel="pagebookmark">
|
<h3 id="_private" rel="pagebookmark">
|
||||||
<span class="component" onclick="collapse('private_inner');">{{=T("Private files")}}</span>
|
<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')}}">
|
<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()}}
|
{{=helpicon()}}
|
||||||
<span>{{=T("These files are not served, they are only available from within your app")}}</span>
|
<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>
|
</a><span id="private" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||||
</h3>
|
</h3>
|
||||||
<div id="private_inner" class="component_contents">
|
<div id="private_inner" class="component_contents">
|
||||||
{{if not privates:}}<p><strong>{{=T("There are no private files")}}</strong></p>{{else:}}
|
{{if not privates:}}<p><strong>{{=T("There are no private files")}}</strong></p>{{else:}}
|
||||||
<ul class="unstyled act_edit">
|
<ul class="unstyled act_edit">
|
||||||
{{
|
{{
|
||||||
path=[]
|
path=[]
|
||||||
for file in privates+['']:
|
for file in privates+['']:
|
||||||
items=file.split('/')
|
items=file.split('/')
|
||||||
file_path=items[:-1]
|
file_path=items[:-1]
|
||||||
filename=items[-1]
|
filename=items[-1]
|
||||||
while path!=file_path:
|
while path!=file_path:
|
||||||
if len(file_path)>=len(path) and all([v==file_path[k] for k,v in enumerate(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)])
|
path.append(file_path[len(path)])
|
||||||
thispath='private__'+'__'.join(path)
|
thispath='private__'+'__'.join(path)
|
||||||
}}
|
}}
|
||||||
<li class="folder">
|
<li class="folder">
|
||||||
<a href="javascript:collapse('{{=thispath}}');" class="file">{{=path[-1]}}/</a>
|
<a href="javascript:collapse('{{=thispath}}');" class="file">{{=path[-1]}}/</a>
|
||||||
<ul id="{{=thispath}}" style="display: none;" class="sublist">{{
|
<ul id="{{=thispath}}" style="display: none;" class="sublist">{{
|
||||||
else:
|
else:
|
||||||
path = path[:-1]
|
path = path[:-1]
|
||||||
}}
|
}}
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
{{
|
{{
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
if filename:
|
if filename:
|
||||||
}}
|
}}
|
||||||
<li>
|
<li>
|
||||||
<span class="filetools controls">
|
<span class="filetools controls">
|
||||||
{{=editfile('private',file, dict(id="private"))}} {{=deletefile([app,'private',file], dict(id="private",id2="private"))}}
|
{{=editfile('private',file, dict(id="private"))}} {{=deletefile([app,'private',file], dict(id="private",id2="private"))}}
|
||||||
</span>
|
</span>
|
||||||
<span class="file">
|
<span class="file">
|
||||||
{{=peekfile('private',file, dict(id="private"))}}
|
{{=peekfile('private',file, dict(id="private"))}}
|
||||||
</span>
|
</span>
|
||||||
</li>{{
|
</li>{{
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
}}
|
}}
|
||||||
{{pass}}
|
{{pass}}
|
||||||
</ul>
|
</ul>
|
||||||
<div class="controls formfield">
|
<div class="controls formfield">
|
||||||
<div class="row-fluid">
|
<button onclick="jQuery('#form7').slideToggle()" class="btn btn-mini">Create/Upload</button>
|
||||||
<div class="span3">{{=file_create_form('%s/private/' % app, 'private')}}<em>{{=T('or alternatively')}}</em></div>
|
<div id="form7" class="row-fluid" style="display:none">
|
||||||
<div class="span3">{{=file_upload_form('%s/private/' % app, 'private')}}</div>
|
<div class="span3">{{=file_create_form('%s/private/' % app, 'private')}}<em>{{=T('or alternatively')}}</em></div>
|
||||||
</div>
|
<div class="span3">{{=file_upload_form('%s/private/' % app, 'private')}}</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- PLUGINS -->
|
<!-- PLUGINS -->
|
||||||
<h3 id="_plugins" rel="pagebookmark">
|
<h3 id="_plugins" rel="pagebookmark">
|
||||||
<span class="component" onclick="collapse('plugins_inner');">{{=T("Plugins")}}</span>
|
<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]')}}">
|
<a href="#plugins" rel="tooltip" data-placement="right" data-original-title="{{=T('To create a plugin, name a file/folder plugin_[name]')}}">
|
||||||
{{=helpicon()}}
|
{{=helpicon()}}
|
||||||
<span>{{=T("To create a plugin, name a file/folder plugin_[name]")}}</span>
|
<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>
|
</a><span id="plugins" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||||
</h3>
|
</h3>
|
||||||
<div id="plugins_inner" class="component_contents">
|
<div id="plugins_inner" class="component_contents">
|
||||||
<div class="controls comptools">
|
<div class="controls comptools">
|
||||||
{{=button(PLUGINS_APP, T('download plugins'))}}
|
{{=button(PLUGINS_APP, T('download plugins'))}}
|
||||||
</div>
|
</div>
|
||||||
{{if plugins:}}
|
{{if plugins:}}
|
||||||
<ul class="unstyled act_edit">
|
<ul class="unstyled act_edit">
|
||||||
{{for plugin in plugins:}}
|
{{for plugin in plugins:}}
|
||||||
{{id="plugins__"+plugin.replace('/','__').replace('.','__')}}
|
{{id="plugins__"+plugin.replace('/','__').replace('.','__')}}
|
||||||
<li id="{{=id}}">
|
<li id="{{=id}}">
|
||||||
{{=A('plugin_%s' % plugin, _class='file', _href=URL('plugin', args=[app, plugin], vars=dict(id=id, id2='plugins')))}}
|
{{=A('plugin_%s' % plugin, _class='file', _href=URL('plugin', args=[app, plugin], vars=dict(id=id, id2='plugins')))}}
|
||||||
</li>
|
</li>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
</ul>
|
</ul>
|
||||||
{{else:}}
|
{{else:}}
|
||||||
<p><strong>{{=T('There are no plugins')}}</strong></p>
|
<p><strong>{{=T('There are no plugins')}}</strong></p>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
<div class="controls formfield">
|
<div class="controls formfield">
|
||||||
<div class="row-fluid">
|
<button onclick="jQuery('#form8').slideToggle()" class="btn btn-mini">Upload</button>
|
||||||
<div class="span3">{{=upload_plugin_form(app, 'plugins')}}</div>
|
<div id="form8" class="row-fluid" style="display:none">
|
||||||
</div>
|
<div class="row-fluid">
|
||||||
</div>
|
<div class="span3">{{=upload_plugin_form(app, 'plugins')}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -465,7 +474,7 @@ function filter_files() {
|
|||||||
files=data['files'];
|
files=data['files'];
|
||||||
message=data['message'];
|
message=data['message'];
|
||||||
for(var i=0; i<files.length; i++)
|
for(var i=0; i<files.length; i++)
|
||||||
jQuery('li#'+files[i].replace(/\//g,'__').replace('.','__')).slideDown();
|
jQuery('li#_'+files[i].replace(/\//g,'__').replace('.','__')).slideDown();
|
||||||
jQuery('.flash').html(message).slideDown();
|
jQuery('.flash').html(message).slideDown();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ jQuery(document).ready(function(){
|
|||||||
<form action="{{=URL('edit',args=filename)}}" method="post" name="editform" id="editform">
|
<form action="{{=URL('edit',args=filename)}}" method="post" name="editform" id="editform">
|
||||||
<div class="editor-bar-column">
|
<div class="editor-bar-column">
|
||||||
<label>{{=T('Save file:')}}</label>
|
<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);">
|
<a value="save" name="save" onclick="return doClickSave();" class="icon saveicon" style="background-image: -webkit-linear-gradient(top,white,#E6E6E6);">
|
||||||
{{=IMG(_src=URL('static', 'images/save_icon.png'), _alt=T('Save'))}}
|
{{=IMG(_src=URL('static', 'images/save_icon.png'), _alt=T('Save'))}}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ def all(items):
|
|||||||
def peekfile(path,file):
|
def peekfile(path,file):
|
||||||
return A(file.replace('\\\\','/'),_href=URL('peek', args=(app, path, file)))
|
return A(file.replace('\\\\','/'),_href=URL('peek', args=(app, path, file)))
|
||||||
def editfile(path,file):
|
def editfile(path,file):
|
||||||
return A(SPAN(T('Edit')),_class='button editbutton btn',_href=URL('edit', args=(app, path, file)))
|
return A(SPAN(T('Edit')),_class='button editbutton btn btn-mini',_href=URL('edit', args=(app, path, file)))
|
||||||
def testfile(path,file):
|
def testfile(path,file):
|
||||||
return A(TAG[''](IMG(_src=URL('static', 'images/test_icon.png'), _alt=T('test')),
|
return A(TAG[''](IMG(_src=URL('static', 'images/test_icon.png'), _alt=T('test')),
|
||||||
SPAN(T("Run tests in this file"))),
|
SPAN(T("Run tests in this file"))),
|
||||||
@@ -16,7 +16,7 @@ def testfile(path,file):
|
|||||||
**{'_data-placement':'right',
|
**{'_data-placement':'right',
|
||||||
'_data-original-title':T("Run tests in this file")})
|
'_data-original-title':T("Run tests in this file")})
|
||||||
def editlanguagefile(path,file):
|
def editlanguagefile(path,file):
|
||||||
return A(SPAN(T('Edit')),_class='button editbutton',_href=URL('edit_language', args=(app, path, file)))
|
return A(SPAN(T('Edit')),_class='button editbutton btn-mini',_href=URL('edit_language', args=(app, path, file)))
|
||||||
def file_upload_form(location):
|
def file_upload_form(location):
|
||||||
form=FORM(T("upload file:")," ",
|
form=FORM(T("upload file:")," ",
|
||||||
INPUT(_type="file",_name="file")," ",T("and rename it:")," ",
|
INPUT(_type="file",_name="file")," ",T("and rename it:")," ",
|
||||||
@@ -220,4 +220,4 @@ for c in controllers: controller_functions+=[c[:-3]+'/%s.html'%x for x in functi
|
|||||||
</ul>
|
</ul>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
</div>
|
</div>
|
||||||
<!-- end "plugin" block -->
|
<!-- end "plugin" block -->
|
||||||
|
|||||||
@@ -3,143 +3,157 @@
|
|||||||
{{block sectionclass}}site{{end}}
|
{{block sectionclass}}site{{end}}
|
||||||
<!-- begin "site" block -->
|
<!-- begin "site" block -->
|
||||||
<div class="row-fluid">
|
<div class="row-fluid">
|
||||||
<div class="applist f60 span7">
|
<div class="applist f60 span7">
|
||||||
<div class="applist_inner">
|
<div class="applist_inner">
|
||||||
<h2>{{=T("Installed applications")}}</h2>
|
<h2>{{=T("Installed applications")}}</h2>
|
||||||
<ul class="unstyled">
|
<table width="100%" class="table">
|
||||||
{{for a in apps:}}
|
{{for a in apps:}}
|
||||||
<li class="application"> <!-- onmouseover="jQuery(this).children('p').show()" onmouseout="jQuery(this).children('p').hide()"-->
|
<tr>{{buttons = []}}
|
||||||
{{if a==request.application:}}
|
<td>
|
||||||
<h3 class="currentapp muted">{{=a}} ({{=T('currently running')}})</h3>
|
{{if a==request.application:}}
|
||||||
<p class="controls row-buttons">
|
<h4 class="currentapp">{{=a}} ({{=T('currently running')}})</h4>
|
||||||
{{else:}}
|
{{else:}}
|
||||||
<h3 class="editableapp muted">{{=A(a,_href=URL(a,'default','index'))}}</h3>
|
<h4 class="editableapp">{{=A(a,_href=URL(a,'default','index'))}}</h4>
|
||||||
{{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}}
|
{{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):}}
|
||||||
{{if not os.path.exists('applications/%s/compiled' % a):}}
|
{{buttons.append((URL('design',args=a), T("Edit")))}}
|
||||||
{{=sp_button(URL('design',args=a), T("Edit"))}}
|
{{else:}}
|
||||||
{{else:}}
|
{{buttons.append((URL(a,'appadmin','index'), T("appadmin")))}}
|
||||||
{{=button(URL(a,'appadmin','index'), T("appadmin"))}}
|
{{pass}}
|
||||||
{{pass}}
|
{{buttons.append((URL('about',args=a), T("About")))}}
|
||||||
{{=button(URL('about',args=a), T("About"))}}
|
{{pass}}
|
||||||
{{pass}}
|
{{buttons.append((URL('errors',args=a), T("Errors")))}}
|
||||||
{{=button(URL('errors',args=a), T("Errors"))}}
|
{{buttons.append((URL('cleanup',args=a), T("Clean")))}}
|
||||||
{{=button(URL('cleanup',args=a), T("Clean"))}}
|
{{buttons.append((URL('pack',args=a), T("Pack all")))}}
|
||||||
{{=button(URL('pack',args=a), T("Pack all"))}}
|
{{if not os.path.exists('applications/%s/compiled' % a):}}
|
||||||
{{if not os.path.exists('applications/%s/compiled' % a):}}
|
{{buttons.append((URL('compile_app',args=a), T("Compile")))}}
|
||||||
{{=button(URL('compile_app',args=a), T("Compile"))}}
|
{{else:}}
|
||||||
{{else:}}
|
{{buttons.append((URL('pack',args=(a, 'compiled')), T("Pack compiled")))}}
|
||||||
{{=button(URL('pack',args=(a, 'compiled')), T("Pack compiled"))}}
|
{{if glob.glob('applications/%s/controllers/*.py' % a):}}
|
||||||
{{if glob.glob('applications/%s/controllers/*.py' % a):}}
|
{{buttons.append((URL('remove_compiled_app',args=a), T("Remove compiled")))}}
|
||||||
{{=button(URL('remove_compiled_app',args=a), T("Remove compiled"))}}
|
{{pass}}
|
||||||
{{pass}}
|
{{pass}}
|
||||||
{{pass}}
|
{{if os.path.exists(os.path.join(apath(r=request),a,'.git')): }}
|
||||||
{{if os.path.exists(os.path.join(apath(r=request),a,'.git')): }}
|
{{buttons.append((URL('git_pull',args=a), T("Git Pull")))}}
|
||||||
{{=button(URL('git_pull',args=a), T("Git Pull"))}}
|
{{buttons.append((URL('git_push',args=a), T("Git Push")))}}
|
||||||
{{=button(URL('git_push',args=a), T("Git Push"))}}
|
{{pass}}
|
||||||
{{pass}}
|
{{if a!=request.application:}}
|
||||||
{{if a!=request.application:}}
|
{{buttons.append((URL('uninstall',args=a), T("Uninstall")))}}
|
||||||
{{=button(URL('uninstall',args=a), T("Uninstall"))}}
|
{{pass}}
|
||||||
{{=button_enable(URL('enable',args=a), a)}}
|
</td>
|
||||||
{{pass}}
|
<td>
|
||||||
</p>
|
<div class="btn-group">
|
||||||
</li>
|
<a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
|
||||||
{{pass}}
|
{{=T('Manage')}}
|
||||||
</ul>
|
<span class="caret"></span>
|
||||||
</div>
|
</a>
|
||||||
</div> <!-- /applist -->
|
<ul class="dropdown-menu">
|
||||||
<div class="sidebar fl60 span5">
|
{{for link,name in buttons:}}
|
||||||
<div class="sidebar_inner controls well well-small">
|
{{=LI(A(name,_href=link))}}
|
||||||
<!-- CHANGE ADMIN PWD -->
|
{{pass}}
|
||||||
<div class="pwdchange pull-right">
|
</ul>
|
||||||
{{if MULTI_USER_MODE:}}
|
</div>
|
||||||
{{=auth.navbar()}}
|
{{=button_enable(URL('enable',args=a), a)}}
|
||||||
{{else:}}
|
</td>
|
||||||
{{=sp_button(URL('change_password'), T('Change admin password'))}}
|
</tr>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
</div> <!-- /CHANGE ADMIN PWD -->
|
</table>
|
||||||
{{if is_manager():}}
|
</div>
|
||||||
<!-- VERSION -->
|
</div> <!-- /applist -->
|
||||||
<div class="box">
|
<div class="sidebar fl60 span5">
|
||||||
<h3>{{=T("Version %s.%s.%s %s (%s)", myversion)}}</h3>
|
<div class="sidebar_inner controls well well-small">
|
||||||
<p id="check_version" class="row-buttons">
|
<!-- CHANGE ADMIN PWD -->
|
||||||
{{if session.check_version:}}
|
<div class="pwdchange pull-right">
|
||||||
{{=T('Checking for upgrades...')}}
|
{{if MULTI_USER_MODE:}}
|
||||||
</p>
|
{{=auth.navbar()}}
|
||||||
<script>ajax('{{=URL('check_version')}}',[],'check_version');</script>
|
{{else:}}
|
||||||
{{session.check_version=False}}
|
{{=sp_button(URL('change_password'), T('Change admin password'))}}
|
||||||
{{else:}}
|
{{=button(URL('default','reload_routes'), T('Reload routes'))}}
|
||||||
{{=button("javascript:ajax('"+URL('check_version')+"',[],'check_version')", T('Check for upgrades'))}}
|
{{pass}}
|
||||||
{{=button(URL('default','reload_routes'), T('Reload routes'))}}
|
</div> <!-- /CHANGE ADMIN PWD -->
|
||||||
</p>
|
{{if is_manager():}}
|
||||||
{{pass}}
|
<!-- VERSION -->
|
||||||
<p>{{=T("Running on %s", request.env.server_software)}}</p>
|
<div class="box">
|
||||||
{{if session.is_mobile=='auto':}}
|
<h4>{{=T("Version")}}</h4>
|
||||||
<p>{{=A(T('Try the mobile interface'),_href=URL('plugin_jqmobile','about'))}}</p>
|
<p>
|
||||||
{{pass}}
|
<tt>{{=myversion}}</tt><br/>
|
||||||
</div> <!-- /VERSION -->
|
({{=T("Running on %s", request.env.server_software)}})
|
||||||
{{pass}}
|
</p>
|
||||||
{{if MULTI_USER_MODE and is_manager():}}
|
<p id="check_version" class="row-buttons">
|
||||||
<!-- MULTI_USER_INTERFACE -->
|
{{if session.check_version:}}
|
||||||
<div class="box">
|
{{=T('Checking for upgrades...')}}
|
||||||
<h3>{{=T("Multi User Mode")}}</h3>
|
<script>ajax('{{=URL('check_version')}}',[],'check_version');</script>
|
||||||
<p class="row-buttons">
|
{{session.check_version=False}}
|
||||||
{{=button(URL('bulk_register'),T('Bulk Register'))}}
|
{{else:}}
|
||||||
{{=button(URL('manage_students',vars={'order':'auth_user.id'}),T('Manage Students'))}}
|
{{=button("javascript:ajax('"+URL('check_version')+"',[],'check_version')", T('Check for upgrades'))}}
|
||||||
</p>
|
{{pass}}
|
||||||
</div> <!-- /MULTI_USER_INTERFACE -->
|
</p>
|
||||||
{{pass}}
|
{{if session.is_mobile=='auto':}}
|
||||||
<!-- APP WIZARD -->
|
<p>{{=A(T('Try the mobile interface'),_href=URL('plugin_jqmobile','about'))}}</p>
|
||||||
<div class="box">
|
{{pass}}
|
||||||
<h3>{{=T("New application wizard")}}</h3>
|
</div> <!-- /VERSION -->
|
||||||
<p>{{=button(URL('wizard','index'), T('Start wizard'))}}
|
{{pass}}
|
||||||
{{=T("(requires internet access)")}}</p>
|
{{if MULTI_USER_MODE and is_manager():}}
|
||||||
</div> <!-- /APP WIZARD -->
|
<!-- MULTI_USER_INTERFACE -->
|
||||||
<!-- SCAFFOLD APP -->
|
<div class="box">
|
||||||
<div class="box">
|
<h4>{{=T("Multi User Mode")}}</h4>
|
||||||
<h3>{{=T("New simple application")}}</h3>
|
<p class="row-buttons">
|
||||||
{{=form_create.custom.begin}}
|
{{=button(URL('bulk_register'),T('Bulk Register'))}}
|
||||||
{{=LABEL(T("Application name:"))}}
|
{{=button(URL('manage_students',vars={'order':'auth_user.id'}),T('Manage Students'))}}
|
||||||
{{=form_create.custom.widget.name}}
|
</p>
|
||||||
<div class="controls"><button type="submit" class="btn">{{=T('Create')}}</button></div>
|
</div> <!-- /MULTI_USER_INTERFACE -->
|
||||||
{{=form_create.custom.end}}
|
{{pass}}
|
||||||
</div> <!-- /SCAFFOLD APP -->
|
<!-- SCAFFOLD APP -->
|
||||||
<!-- UPLOAD PACKAGE -->
|
<div class="box">
|
||||||
<div class="box">
|
<h4>{{=T("New simple application")}}</h4>
|
||||||
<h3>{{=T("Upload and install packed application")}}</h3>
|
{{=form_create.custom.begin}}
|
||||||
{{=form_update.custom.begin}}
|
{{=LABEL(T("Application name:"))}}
|
||||||
<label for="appupdate_name">{{=T("Application name:")}}</label>
|
{{=form_create.custom.widget.name}}
|
||||||
{{=form_update.custom.widget.name}}
|
<div class="controls"><button type="submit" class="btn">{{=T('Create')}}</button></div>
|
||||||
<label for="appupdate_file">{{=T("Upload a package:")}}</label>
|
{{=form_create.custom.end}}
|
||||||
{{=form_update.custom.widget.file}}
|
</div> <!-- /SCAFFOLD APP -->
|
||||||
<label for="appupdate_url">{{=T("Or Get from URL:")}}</label>
|
<!-- UPLOAD PACKAGE -->
|
||||||
{{=form_update.custom.widget.url}}<small class="help-block">({{=T('can be a git repo')}})</small>
|
<div class="box">
|
||||||
<div class="controls">
|
<h4>{{=T("Upload and install packed application")}}</h4>
|
||||||
<label class="checkbox">
|
{{=form_update.custom.begin}}
|
||||||
{{=form_update.custom.widget.overwrite}} {{=T("Overwrite installed app")}}
|
<label for="appupdate_name">{{=T("Application name:")}}</label>
|
||||||
</label>
|
{{=form_update.custom.widget.name}}
|
||||||
<button type="submit" class='btn'>{{=T('Install')}}</button>
|
<label for="appupdate_file">{{=T("Upload a package:")}}</label>
|
||||||
</div>
|
{{=form_update.custom.widget.file}}
|
||||||
{{=form_update.custom.end}}
|
<label for="appupdate_url">{{=T("Or Get from URL:")}}</label>
|
||||||
</div> <!-- /UPLOAD PACKAGE -->
|
{{=form_update.custom.widget.url}}<small class="help-block">({{=T('can be a git repo')}})</small>
|
||||||
<!-- DEPLOY ON GAE -->
|
<div class="controls">
|
||||||
<div class="box">
|
<label class="checkbox">
|
||||||
<h3>{{=T("Deploy")}}</h3>
|
{{=form_update.custom.widget.overwrite}} {{=T("Overwrite installed app")}}
|
||||||
<p class="row-buttons">
|
</label>
|
||||||
{{=button(URL('gae','deploy'), T('Deploy on Google App Engine'))}}
|
<button type="submit" class='btn'>{{=T('Install')}}</button>
|
||||||
{{=button(URL('openshift','deploy'),T('Deploy to OpenShift'))}}
|
</div>
|
||||||
</p>
|
{{=form_update.custom.end}}
|
||||||
</div> <!-- /DEPLOY ON GAE -->
|
</div> <!-- /UPLOAD PACKAGE -->
|
||||||
<br/>
|
<!-- DEPLOY ON GAE -->
|
||||||
{{if TWITTER_HASH:}}
|
<div class="box">
|
||||||
<!-- TWITTER -->
|
<h4>{{=T("Deploy")}}</h4>
|
||||||
<div class="box">
|
<p class="row-buttons">
|
||||||
<h3>{{=T("%s Recent Tweets"%TWITTER_HASH)}}</h3>
|
{{=button(URL('gae','deploy'), T('Deploy on Google App Engine'))}}
|
||||||
<div id="tweets">{{=T('loading...')}}</div>
|
{{=button(URL('openshift','deploy'),T('Deploy to OpenShift'))}}
|
||||||
<script>jQuery(document).ready(function(){jQuery('#tweets').load('{{=URL('twitter.load')}}');});</script>
|
</p>
|
||||||
</div> <!-- /TWITTER -->
|
</div> <!-- /DEPLOY ON GAE -->
|
||||||
{{pass}}
|
<!-- APP WIZARD -->
|
||||||
</div>
|
<div class="box">
|
||||||
</div> <!-- /sidebar -->
|
<h4>{{=T("New application wizard")}}</h4>
|
||||||
|
<p>{{=button(URL('wizard','index'), T('Start wizard'))}}<br/>
|
||||||
|
{{=T("(requires internet access, experimental)")}}</p>
|
||||||
|
</div> <!-- /APP WIZARD -->
|
||||||
|
{{if TWITTER_HASH:}}
|
||||||
|
<!-- TWITTER -->
|
||||||
|
<div class="box">
|
||||||
|
<h4>{{=T("%s Recent Tweets"%TWITTER_HASH)}}</h4>
|
||||||
|
<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
|
</div> <!-- /row-fluid
|
||||||
<!-- end "site" block -->
|
<!-- end "site" block -->
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<th>web2py™</th>
|
<th>web2py™</th>
|
||||||
<td>{{=myversion}}</td>
|
<td>Version {{=myversion}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{if snapshot:}}
|
{{if snapshot:}}
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -27,8 +27,17 @@ Tweet attributes
|
|||||||
"""
|
"""
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
{{import re}}
|
||||||
|
{{hashtag = re.compile('([#@])(\w+)')}}
|
||||||
|
{{link = re.compile('(?!<")https?\:\/\/[\w\./?&]+')}}
|
||||||
|
<table class="twitter">
|
||||||
{{ for t in tweets: }}
|
{{ for t in tweets: }}
|
||||||
{{ =DIV(H5(t["from_user_name"])) }}
|
<tr class="tweet">
|
||||||
{{ =DIV(t["text"]) }}
|
<td><img src="{{=t['profile_image_url_https']}}"/></td>
|
||||||
{{ =BR() }}
|
<td>
|
||||||
|
<a href="http://twitter.com/{{=t['from_user']}}">{{=t["from_user_name"]}}</a>:
|
||||||
|
{{=XML(hashtag.sub('<a href="http://twitter.com/\\g<2>">\\g<1>\\g<2></a>',link.sub('<a href="\\g<0>">\\g<0></a>',t["text"].encode('utf8'))),sanitize=True)}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
{{ pass }}
|
{{ pass }}
|
||||||
|
</table>
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
<title>{{=response.title or URL()}}</title>
|
<title>{{=response.title or URL()}}</title>
|
||||||
{{
|
{{
|
||||||
response.files.append(URL('static','css/bootstrap.min.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_essentials.css'))
|
||||||
# response.files.append(URL('static','css/bootstrap_adapters.css'))
|
# response.files.append(URL('static','css/bootstrap_adapters.css'))
|
||||||
response.files.append(URL('static','css/bootstrap-responsive.min.css'))
|
response.files.append(URL('static','css/bootstrap-responsive.min.css'))
|
||||||
@@ -79,6 +80,11 @@
|
|||||||
jQuery("[rel=tooltip]").tooltip();
|
jQuery("[rel=tooltip]").tooltip();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
{{if request.function in ('index','site'):}}
|
||||||
|
<a style="position:fixed;bottom:0;left:0;z-index:1000" href="https://groups.google.com/forum/?fromgroups#!forum/web2py" target="_blank">
|
||||||
|
<!-- http://webchat.freenode.net/?channels=web2py" //-->
|
||||||
|
<img src="{{=URL('static','images/questions.png')}}" />
|
||||||
|
</a>
|
||||||
|
{{pass}}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ for application "{{=request.args[0]}}"</h2>
|
|||||||
<h3>Commit form</h3>
|
<h3>Commit form</h3>
|
||||||
{{=form}}
|
{{=form}}
|
||||||
|
|
||||||
|
|
||||||
{{if repo['.'].rev()>=0:}}
|
{{if repo['.'].rev()>=0:}}
|
||||||
<h3>Last Revision</h3>
|
<h3>Last Revision</h3>
|
||||||
<table>
|
<table>
|
||||||
|
|||||||
@@ -319,6 +319,9 @@ def state():
|
|||||||
|
|
||||||
|
|
||||||
def ccache():
|
def ccache():
|
||||||
|
cache.ram.initialize()
|
||||||
|
cache.disk.initialize()
|
||||||
|
|
||||||
form = FORM(
|
form = FORM(
|
||||||
P(TAG.BUTTON(
|
P(TAG.BUTTON(
|
||||||
T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
|
T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
|
||||||
@@ -385,7 +388,7 @@ def ccache():
|
|||||||
|
|
||||||
return (hours, minutes, seconds)
|
return (hours, minutes, seconds)
|
||||||
|
|
||||||
for key, value in cache.ram.storage.items():
|
for key, value in cache.ram.storage.iteritems():
|
||||||
if isinstance(value, dict):
|
if isinstance(value, dict):
|
||||||
ram['hits'] = value['hit_total'] - value['misses']
|
ram['hits'] = value['hit_total'] - value['misses']
|
||||||
ram['misses'] = value['misses']
|
ram['misses'] = value['misses']
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ def what():
|
|||||||
import urllib
|
import urllib
|
||||||
try:
|
try:
|
||||||
images = XML(urllib.urlopen(
|
images = XML(urllib.urlopen(
|
||||||
'http://web2py.com/poweredby/default/images').read())
|
'http://www.web2py.com/poweredby/default/images').read())
|
||||||
except:
|
except:
|
||||||
images = []
|
images = []
|
||||||
return response.render(images=images)
|
return response.render(images=images)
|
||||||
@@ -61,11 +61,11 @@ def videos():
|
|||||||
|
|
||||||
|
|
||||||
def security():
|
def security():
|
||||||
redirect('http://www.web2py.com/book/default/chapter/01#security')
|
redirect('http://www.web2py.com/book/default/chapter/01#Security')
|
||||||
|
|
||||||
|
|
||||||
def api():
|
def api():
|
||||||
redirect('http://web2py.com/book/default/chapter/04#API')
|
redirect('http://www.web2py.com/book/default/chapter/04#API')
|
||||||
|
|
||||||
|
|
||||||
@cache('license', time_expire=cache_expire)
|
@cache('license', time_expire=cache_expire)
|
||||||
@@ -74,10 +74,14 @@ def license():
|
|||||||
filename = os.path.join(request.env.gluon_parent, 'LICENSE')
|
filename = os.path.join(request.env.gluon_parent, 'LICENSE')
|
||||||
return response.render(dict(license=MARKMIN(read_file(filename))))
|
return response.render(dict(license=MARKMIN(read_file(filename))))
|
||||||
|
|
||||||
|
|
||||||
def version():
|
def version():
|
||||||
return 'Version %s.%s.%s (%s) %s' % request.env.web2py_version
|
if request.args(0)=='raw':
|
||||||
|
return request.env.web2py_version
|
||||||
|
from gluon.fileutils import parse_version
|
||||||
|
(a, b, c, pre_release, build) = parse_version(request.env.web2py_version)
|
||||||
|
return 'Version %i.%i.%i (%.4i-%.2i-%.2i %.2i:%.2i:%.2i) %s' % (
|
||||||
|
a,b,c,build.year,build.month,build.day,
|
||||||
|
build.hour,build.minute,build.second,pre_release)
|
||||||
|
|
||||||
@cache('examples', time_expire=cache_expire)
|
@cache('examples', time_expire=cache_expire)
|
||||||
def examples():
|
def examples():
|
||||||
|
|||||||
@@ -1,75 +1,49 @@
|
|||||||
session.forget()
|
session.forget()
|
||||||
|
|
||||||
response.menu = [['home', False, '/%s/default/index'
|
def get(args):
|
||||||
% request.application], ['docs', True,
|
if args[0].startswith('__'):
|
||||||
'/%s/global/vars' % request.application]]
|
return None
|
||||||
|
try:
|
||||||
|
obj = globals(),get(args[0])
|
||||||
|
for k in range(1,len(args)):
|
||||||
|
obj = getattr(obj,args[k])
|
||||||
|
return obj
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
def vars():
|
def vars():
|
||||||
"""the running controller function!"""
|
"""the running controller function!"""
|
||||||
|
title = '.'.join(request.args)
|
||||||
|
attributes = {}
|
||||||
if not request.args:
|
if not request.args:
|
||||||
(
|
(doc,keys,t,c,d,value)=('Global variables',globals(),None,None,[],None)
|
||||||
doc,
|
|
||||||
keys,
|
|
||||||
t,
|
|
||||||
c,
|
|
||||||
d,
|
|
||||||
value,
|
|
||||||
) = (
|
|
||||||
'Global variables',
|
|
||||||
globals(),
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
(),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
(title, args) = ('globals()', '')
|
|
||||||
elif len(request.args) < 3:
|
elif len(request.args) < 3:
|
||||||
args = '.'.join(request.args)
|
obj = get(request.args)
|
||||||
try:
|
if obj:
|
||||||
doc = eval(args + '.__doc__')
|
doc = getattr(obj,'__doc__','no documentation')
|
||||||
except:
|
keys = dir(obj)
|
||||||
doc = 'no documentation'
|
t = type(obj)
|
||||||
try:
|
c = getattr(obj,'__class__',None)
|
||||||
keys = eval('dir(%s)' % args)
|
d = getattr(obj,'__bases__',None)
|
||||||
except:
|
|
||||||
|
for key in keys:
|
||||||
|
a = getattr(obj,key,None)
|
||||||
|
if a and not isinstance(a,DAL):
|
||||||
|
doc1 = getattr(a, '__doc__', '')
|
||||||
|
t1 = type(a)
|
||||||
|
c1 = getattr(a,'__class__',None)
|
||||||
|
d1 = getattr(a,'__bases__',None)
|
||||||
|
key = '.'.join(request.args)+'.'+key
|
||||||
|
attributes[key] = (doc1, t1, c1, d1)
|
||||||
|
else:
|
||||||
|
doc = 'Unkown'
|
||||||
keys = []
|
keys = []
|
||||||
t = eval('type(%s)' % args)
|
t = c = d = None
|
||||||
try:
|
|
||||||
c = eval('%s.__class__' % args)
|
|
||||||
except:
|
|
||||||
c = None
|
|
||||||
try:
|
|
||||||
d = eval('%s.__bases__' % args)
|
|
||||||
except:
|
|
||||||
d = None
|
|
||||||
title = args
|
|
||||||
args += '.'
|
|
||||||
else:
|
else:
|
||||||
raise HTTP(400)
|
raise HTTP(400)
|
||||||
attributes = {}
|
|
||||||
for key in keys:
|
|
||||||
a = args + key
|
|
||||||
if eval('isinstance(%s,SQLDB)' % a) or a == 'vars':
|
|
||||||
continue
|
|
||||||
try:
|
|
||||||
doc1 = eval(a + '.__doc__')
|
|
||||||
except:
|
|
||||||
doc1 = 'no documentation'
|
|
||||||
t1 = eval('type(%s)' % a)
|
|
||||||
try:
|
|
||||||
c1 = eval('%s.__class__' % a)
|
|
||||||
except:
|
|
||||||
c1 = None
|
|
||||||
try:
|
|
||||||
d1 = eval('%s.__bases__' % a)
|
|
||||||
except:
|
|
||||||
d1 = ()
|
|
||||||
attributes[a] = (doc1, t1, c1, d1)
|
|
||||||
return dict(
|
return dict(
|
||||||
title=title,
|
title=title,
|
||||||
args=args,
|
args=request.args,
|
||||||
t=t,
|
t=t,
|
||||||
c=c,
|
c=c,
|
||||||
d=d,
|
d=d,
|
||||||
|
|||||||
@@ -54,13 +54,6 @@ def raisehttp():
|
|||||||
raise HTTP(400, 'internal error')
|
raise HTTP(400, 'internal error')
|
||||||
|
|
||||||
|
|
||||||
def raiseexception():
|
|
||||||
""" generates an exeption, logs the event and returns a ticket number """
|
|
||||||
|
|
||||||
1 / 0
|
|
||||||
return 'oops'
|
|
||||||
|
|
||||||
|
|
||||||
def servejs():
|
def servejs():
|
||||||
""" serves a js document """
|
""" serves a js document """
|
||||||
|
|
||||||
@@ -69,7 +62,6 @@ def servejs():
|
|||||||
gluon.contenttype.contenttype('.js')
|
gluon.contenttype.contenttype('.js')
|
||||||
return 'alert("This is a Javascript document, it is not supposed to run!");'
|
return 'alert("This is a Javascript document, it is not supposed to run!");'
|
||||||
|
|
||||||
|
|
||||||
def makejson():
|
def makejson():
|
||||||
import gluon.contrib.simplejson as sj
|
import gluon.contrib.simplejson as sj
|
||||||
return sj.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}])
|
return sj.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}])
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
from gluon.contrib.spreadsheet import Sheet
|
from gluon.contrib.spreadsheet import Sheet
|
||||||
|
|
||||||
|
|
||||||
def callback():
|
def callback():
|
||||||
return cache.ram('sheet1', lambda: None, None).process(request)
|
return cache.ram('sheet1', lambda: None, None).process(request)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
session.connect(request,response,cookie_key='yoursecret')
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
403
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
404
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
500
|
||||||
@@ -1,117 +1,16 @@
|
|||||||
footer-content {position: relative; bottom: 0; width: 100%;}
|
@import url(http://fonts.googleapis.com/css?family=Economica);
|
||||||
|
@@import url(http://fonts.googleapis.com/css?family=Belleza);
|
||||||
.statusbar {
|
|
||||||
padding: 2px 0;
|
|
||||||
border: 0;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
background-color: #C1CDCD;
|
|
||||||
/*background: url('../images/menu.png') repeat-x;*/
|
|
||||||
}
|
|
||||||
.statusbar a, .statusbar a:visited {
|
|
||||||
color: #406361;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.footer-content {
|
|
||||||
height: 100%;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
body { font-family: Arial, Helvetica; }
|
||||||
a, a:visited, a:hover, h1,h2,h3,h4,h5 {color: #658883}
|
a, a:visited, a:hover, h1,h2,h3,h4,h5 {color: #658883}
|
||||||
a.button {color: #658883}
|
a.btn-danger, a.btn-warning, a.btn-success {color:white}
|
||||||
|
h1,h2,h3,h4,h5 { font-family: "Economica", Arial, Helevtica; }
|
||||||
.sf-menu li, .sf-menu li a { border-radius: 5px;}
|
body {
|
||||||
|
background: url('../images/stripes.png') repeat-x;
|
||||||
.wrapper {
|
|
||||||
background: url('../images/back-02.png') repeat-x;
|
|
||||||
padding-top:10px;
|
|
||||||
}
|
}
|
||||||
h1 { font-size: 32px }
|
#header {
|
||||||
h2 { font-size: 24px }
|
margin-top: 40px;
|
||||||
h3 { font-size: 20px }
|
|
||||||
h4 { font-size: 14px }
|
|
||||||
sup {
|
|
||||||
font-size: 0.5em;
|
|
||||||
line-height: 2em;
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
ul { list-style: circle outside; padding-left: 30px;}
|
|
||||||
|
|
||||||
.frame {
|
|
||||||
border: 3px solid #959595;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header h5 {
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
.logo: {
|
|
||||||
float:left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.announce {
|
|
||||||
text-align: center;
|
|
||||||
color: white;
|
|
||||||
top: 0;
|
|
||||||
font-weight: bold;
|
|
||||||
text-align: center;
|
|
||||||
left: 0;
|
|
||||||
position: relative;
|
|
||||||
background: #000;
|
|
||||||
border-radius: 5px;
|
|
||||||
margin: 7px 0 15px;
|
|
||||||
}
|
|
||||||
.announce a {color: white}
|
|
||||||
|
|
||||||
input:focus, textarea:focus {background:#f0f0f0}
|
|
||||||
|
|
||||||
table.downloads { width:100%; }
|
|
||||||
table.downloads th, table.downloads td {text-align:center;}
|
|
||||||
table.downloads a.button { width: 150px; }
|
|
||||||
th,td {padding-right: 10px;}
|
|
||||||
|
|
||||||
p {text-align: left;}
|
|
||||||
|
|
||||||
p + p {
|
|
||||||
margin-bottom: .75em;
|
|
||||||
}
|
|
||||||
|
|
||||||
strong {color: inherit;}
|
|
||||||
|
|
||||||
img.centered {
|
|
||||||
margin: 0 auto;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tagCloud {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 489px;
|
|
||||||
}
|
|
||||||
.mainbody {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
.aboutW2P {
|
|
||||||
margin-top: 23px;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
|
||||||
.aboutW2P p {
|
|
||||||
padding: 0 0.5em;
|
|
||||||
font-size: 1.15em;
|
|
||||||
}
|
|
||||||
.aboutW2P h3 {
|
|
||||||
padding: 0 0.3em;
|
|
||||||
}
|
|
||||||
.userQuotes {
|
|
||||||
/*border-top: #eee 2px solid;*/
|
|
||||||
padding-top: 15px;
|
|
||||||
}
|
|
||||||
.userQuotes p {
|
|
||||||
text-align: left;
|
|
||||||
font-size: 111%;
|
|
||||||
color: #777;
|
|
||||||
}
|
|
||||||
#menu {
|
|
||||||
padding: 0.1em 0.5em;
|
|
||||||
}
|
}
|
||||||
|
.btn-180 {
|
||||||
|
width: 180px;
|
||||||
|
}
|
||||||
@@ -1,629 +0,0 @@
|
|||||||
/*
|
|
||||||
* Skeleton V1.1
|
|
||||||
* Copyright 2011, Dave Gamache
|
|
||||||
* www.getskeleton.com
|
|
||||||
* Free to use under the MIT license.
|
|
||||||
* http://www.opensource.org/licenses/mit-license.php
|
|
||||||
* 8/17/2011
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/* Table of Content
|
|
||||||
==================================================
|
|
||||||
#Reset & Basics
|
|
||||||
#Basic Styles
|
|
||||||
#Site Styles
|
|
||||||
#Typography
|
|
||||||
#Links
|
|
||||||
#Lists
|
|
||||||
#Images
|
|
||||||
#Buttons
|
|
||||||
#Tabs
|
|
||||||
#Forms
|
|
||||||
#Misc */
|
|
||||||
|
|
||||||
|
|
||||||
/* #Reset & Basics (Inspired by E. Meyers)
|
|
||||||
================================================== */
|
|
||||||
html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
border: 0;
|
|
||||||
font-size: 100%;
|
|
||||||
font: inherit;
|
|
||||||
vertical-align: baseline; }
|
|
||||||
article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section {
|
|
||||||
display: block; }
|
|
||||||
body {
|
|
||||||
line-height: 1; }
|
|
||||||
// ol, ul { list-style: none; } /* WEB2PY EDIT */
|
|
||||||
blockquote, q {
|
|
||||||
quotes: none; }
|
|
||||||
blockquote:before, blockquote:after,
|
|
||||||
q:before, q:after {
|
|
||||||
content: '';
|
|
||||||
content: none; }
|
|
||||||
table {
|
|
||||||
border-collapse: collapse;
|
|
||||||
border-spacing: 0; }
|
|
||||||
|
|
||||||
|
|
||||||
/* #Basic Styles
|
|
||||||
================================================== */
|
|
||||||
body {
|
|
||||||
background: #fff;
|
|
||||||
font: 14px/21px "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
|
||||||
color: #444;
|
|
||||||
-webkit-font-smoothing: antialiased; /* Fix for webkit rendering */
|
|
||||||
-webkit-text-size-adjust: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* #Typography
|
|
||||||
================================================== */
|
|
||||||
h1, h2, h3, h4, h5, h6 {
|
|
||||||
color: #181818;
|
|
||||||
font-family: "Georgia", "Times New Roman", Helvetica, Arial, sans-serif;
|
|
||||||
font-weight: normal; }
|
|
||||||
h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { font-weight: inherit; }
|
|
||||||
h1 { font-size: 46px; line-height: 50px; }
|
|
||||||
h2 { font-size: 35px; line-height: 40px; }
|
|
||||||
h3 { font-size: 28px; line-height: 34px; }
|
|
||||||
h4 { font-size: 21px; line-height: 30px; }
|
|
||||||
h5 { font-size: 17px; line-height: 24px; }
|
|
||||||
h6 { font-size: 14px; line-height: 21px; }
|
|
||||||
|
|
||||||
.subheader { color: #777; }
|
|
||||||
|
|
||||||
p { margin: 0 0 20px 0; }
|
|
||||||
p img { margin: 0; }
|
|
||||||
p.lead { font-size: 21px; line-height: 27px; color: #777; }
|
|
||||||
|
|
||||||
em { font-style: italic; }
|
|
||||||
strong { font-weight: bold; color: #333; }
|
|
||||||
small { font-size: 80%; }
|
|
||||||
|
|
||||||
/* Blockquotes */
|
|
||||||
blockquote, blockquote p { font-size: 17px; line-height: 24px; color: #777; font-style: italic; }
|
|
||||||
blockquote { margin: 0 0 20px; padding: 9px 20px 0 19px;} /* WEB2PY EDIT */
|
|
||||||
blockquote cite { display: block; font-size: 12px; color: #555; }
|
|
||||||
blockquote cite:before { content: "\2014 \0020"; }
|
|
||||||
blockquote cite a, blockquote cite a:visited, blockquote cite a:visited { color: #555; }
|
|
||||||
|
|
||||||
hr { border: solid #ddd; border-width: 1px 0 0; clear: both; margin: 10px 0 30px; height: 0; }
|
|
||||||
|
|
||||||
|
|
||||||
/* #Links
|
|
||||||
================================================== */
|
|
||||||
a, a:visited { color: #333; text-decoration: underline; outline: 0; }
|
|
||||||
a:hover, a:focus { color: #000; }
|
|
||||||
p a, p a:visited { line-height: inherit; }
|
|
||||||
|
|
||||||
|
|
||||||
/* #Lists
|
|
||||||
================================================== */
|
|
||||||
ul, ol { margin-bottom: 20px; }
|
|
||||||
// ul { list-style: none outside; } /* WEB2PY EDIT */
|
|
||||||
ol { list-style: decimal; }
|
|
||||||
ol, ul.square, ul.circle, ul.disc { margin-left: 30px; }
|
|
||||||
ul.square { list-style: square outside; }
|
|
||||||
ul.circle { list-style: circle outside; }
|
|
||||||
ul.disc { list-style: disc outside; }
|
|
||||||
ul ul, ul ol,
|
|
||||||
ol ol, ol ul { margin: 4px 0 5px 30px; font-size: 90%; }
|
|
||||||
ul ul li, ul ol li,
|
|
||||||
ol ol li, ol ul li { margin-bottom: 6px; }
|
|
||||||
li { line-height: 18px; margin-bottom: 12px; }
|
|
||||||
ul.large li { line-height: 21px; }
|
|
||||||
li p { line-height: 21px; }
|
|
||||||
|
|
||||||
/* #Images
|
|
||||||
================================================== */
|
|
||||||
|
|
||||||
img.scale-with-grid {
|
|
||||||
max-width: 100%;
|
|
||||||
height: auto; }
|
|
||||||
|
|
||||||
|
|
||||||
/* #Buttons
|
|
||||||
================================================== */
|
|
||||||
|
|
||||||
a.button,
|
|
||||||
button,
|
|
||||||
input[type="submit"],
|
|
||||||
input[type="reset"],
|
|
||||||
input[type="button"] {
|
|
||||||
background: #eee; /* Old browsers */
|
|
||||||
background: #eee -moz-linear-gradient(top, rgba(255,255,255,.2) 0%, rgba(0,0,0,.2) 100%); /* FF3.6+ */
|
|
||||||
background: #eee -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,.2)), color-stop(100%,rgba(0,0,0,.2))); /* Chrome,Safari4+ */
|
|
||||||
background: #eee -webkit-linear-gradient(top, rgba(255,255,255,.2) 0%,rgba(0,0,0,.2) 100%); /* Chrome10+,Safari5.1+ */
|
|
||||||
background: #eee -o-linear-gradient(top, rgba(255,255,255,.2) 0%,rgba(0,0,0,.2) 100%); /* Opera11.10+ */
|
|
||||||
background: #eee -ms-linear-gradient(top, rgba(255,255,255,.2) 0%,rgba(0,0,0,.2) 100%); /* IE10+ */
|
|
||||||
background: #eee linear-gradient(top, rgba(255,255,255,.2) 0%,rgba(0,0,0,.2) 100%); /* W3C */
|
|
||||||
border: 1px solid #aaa;
|
|
||||||
border-top: 1px solid #ccc;
|
|
||||||
border-left: 1px solid #ccc;
|
|
||||||
padding: 4px 12px;
|
|
||||||
-moz-border-radius: 3px;
|
|
||||||
-webkit-border-radius: 3px;
|
|
||||||
border-radius: 3px;
|
|
||||||
color: #444;
|
|
||||||
display: inline-block;
|
|
||||||
font-size: 1em; /** WEB2PY EDIT **/
|
|
||||||
font-weight: bold;
|
|
||||||
text-decoration: none;
|
|
||||||
text-shadow: 0 1px rgba(255, 255, 255, .75);
|
|
||||||
cursor: pointer;
|
|
||||||
margin-bottom: 5px; /** WEB2PY EDIT **/
|
|
||||||
line-height: 21px;
|
|
||||||
font-family: "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif; }
|
|
||||||
|
|
||||||
a.button:hover,
|
|
||||||
button:hover,
|
|
||||||
input[type="submit"]:hover,
|
|
||||||
input[type="reset"]:hover,
|
|
||||||
input[type="button"]:hover {
|
|
||||||
color: #222;
|
|
||||||
background: #ddd; /* Old browsers */
|
|
||||||
background: #ddd -moz-linear-gradient(top, rgba(255,255,255,.3) 0%, rgba(0,0,0,.3) 100%); /* FF3.6+ */
|
|
||||||
background: #ddd -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,.3)), color-stop(100%,rgba(0,0,0,.3))); /* Chrome,Safari4+ */
|
|
||||||
background: #ddd -webkit-linear-gradient(top, rgba(255,255,255,.3) 0%,rgba(0,0,0,.3) 100%); /* Chrome10+,Safari5.1+ */
|
|
||||||
background: #ddd -o-linear-gradient(top, rgba(255,255,255,.3) 0%,rgba(0,0,0,.3) 100%); /* Opera11.10+ */
|
|
||||||
background: #ddd -ms-linear-gradient(top, rgba(255,255,255,.3) 0%,rgba(0,0,0,.3) 100%); /* IE10+ */
|
|
||||||
background: #ddd linear-gradient(top, rgba(255,255,255,.3) 0%,rgba(0,0,0,.3) 100%); /* W3C */
|
|
||||||
border: 1px solid #888;
|
|
||||||
border-top: 1px solid #aaa;
|
|
||||||
border-left: 1px solid #aaa; }
|
|
||||||
|
|
||||||
a.button:active,
|
|
||||||
button:active,
|
|
||||||
input[type="submit"]:active,
|
|
||||||
input[type="reset"]:active,
|
|
||||||
input[type="button"]:active {
|
|
||||||
border: 1px solid #666;
|
|
||||||
background: #ccc; /* Old browsers */
|
|
||||||
background: #ccc -moz-linear-gradient(top, rgba(255,255,255,.35) 0%, rgba(10,10,10,.4) 100%); /* FF3.6+ */
|
|
||||||
background: #ccc -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,.35)), color-stop(100%,rgba(10,10,10,.4))); /* Chrome,Safari4+ */
|
|
||||||
background: #ccc -webkit-linear-gradient(top, rgba(255,255,255,.35) 0%,rgba(10,10,10,.4) 100%); /* Chrome10+,Safari5.1+ */
|
|
||||||
background: #ccc -o-linear-gradient(top, rgba(255,255,255,.35) 0%,rgba(10,10,10,.4) 100%); /* Opera11.10+ */
|
|
||||||
background: #ccc -ms-linear-gradient(top, rgba(255,255,255,.35) 0%,rgba(10,10,10,.4) 100%); /* IE10+ */
|
|
||||||
background: #ccc linear-gradient(top, rgba(255,255,255,.35) 0%,rgba(10,10,10,.4) 100%); /* W3C */ }
|
|
||||||
|
|
||||||
.button.full-width,
|
|
||||||
button.full-width,
|
|
||||||
input[type="submit"].full-width,
|
|
||||||
input[type="reset"].full-width,
|
|
||||||
input[type="button"].full-width {
|
|
||||||
width: 100%;
|
|
||||||
padding-left: 0 !important;
|
|
||||||
padding-right: 0 !important;
|
|
||||||
text-align: center; }
|
|
||||||
|
|
||||||
|
|
||||||
/* #Tabs (activate in tabs.js)
|
|
||||||
================================================== */
|
|
||||||
ul.tabs {
|
|
||||||
display: block;
|
|
||||||
margin: 0 0 20px 0;
|
|
||||||
padding: 0;
|
|
||||||
border-bottom: solid 1px #ddd; }
|
|
||||||
ul.tabs li {
|
|
||||||
display: block;
|
|
||||||
width: auto;
|
|
||||||
height: 30px;
|
|
||||||
padding: 0;
|
|
||||||
float: left;
|
|
||||||
margin-bottom: 0; }
|
|
||||||
ul.tabs li a {
|
|
||||||
display: block;
|
|
||||||
text-decoration: none;
|
|
||||||
width: auto;
|
|
||||||
height: 29px;
|
|
||||||
padding: 0px 20px;
|
|
||||||
line-height: 30px;
|
|
||||||
border: solid 1px #ddd;
|
|
||||||
border-width: 1px 1px 0 0;
|
|
||||||
margin: 0;
|
|
||||||
background: #f5f5f5;
|
|
||||||
font-size: 13px; }
|
|
||||||
ul.tabs li a.active {
|
|
||||||
background: #fff;
|
|
||||||
height: 30px;
|
|
||||||
position: relative;
|
|
||||||
top: -4px;
|
|
||||||
padding-top: 4px;
|
|
||||||
border-left-width: 1px;
|
|
||||||
margin: 0 0 0 -1px;
|
|
||||||
color: #111;
|
|
||||||
-moz-border-radius-topleft: 2px;
|
|
||||||
-webkit-border-top-left-radius: 2px;
|
|
||||||
border-top-left-radius: 2px;
|
|
||||||
-moz-border-radius-topright: 2px;
|
|
||||||
-webkit-border-top-right-radius: 2px;
|
|
||||||
border-top-right-radius: 2px; }
|
|
||||||
ul.tabs li:first-child a.active {
|
|
||||||
margin-left: 0; }
|
|
||||||
ul.tabs li:first-child a {
|
|
||||||
border-width: 1px 1px 0 1px;
|
|
||||||
-moz-border-radius-topleft: 2px;
|
|
||||||
-webkit-border-top-left-radius: 2px;
|
|
||||||
border-top-left-radius: 2px; }
|
|
||||||
ul.tabs li:last-child a {
|
|
||||||
-moz-border-radius-topright: 2px;
|
|
||||||
-webkit-border-top-right-radius: 2px;
|
|
||||||
border-top-right-radius: 2px; }
|
|
||||||
|
|
||||||
ul.tabs-content { margin: 0; display: block; }
|
|
||||||
ul.tabs-content > li { display:none; }
|
|
||||||
ul.tabs-content > li.active { display: block; }
|
|
||||||
|
|
||||||
/* Clearfixing tabs for beautiful stacking */
|
|
||||||
ul.tabs:before,
|
|
||||||
ul.tabs:after {
|
|
||||||
content: '\0020';
|
|
||||||
display: block;
|
|
||||||
overflow: hidden;
|
|
||||||
visibility: hidden;
|
|
||||||
width: 0;
|
|
||||||
height: 0; }
|
|
||||||
ul.tabs:after {
|
|
||||||
clear: both; }
|
|
||||||
ul.tabs {
|
|
||||||
zoom: 1; }
|
|
||||||
|
|
||||||
|
|
||||||
/* #Forms
|
|
||||||
================================================== */
|
|
||||||
|
|
||||||
form {
|
|
||||||
margin-bottom: 5px; } /** WEB2PY EDIT **/
|
|
||||||
fieldset {
|
|
||||||
margin-bottom: 5px; } /** WEB2PY EDIT **/
|
|
||||||
input[type="text"],
|
|
||||||
input[type="password"],
|
|
||||||
input[type="email"],
|
|
||||||
textarea,
|
|
||||||
select {
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
padding: 6px 4px;
|
|
||||||
outline: none;
|
|
||||||
-moz-border-radius: 2px;
|
|
||||||
-webkit-border-radius: 2px;
|
|
||||||
border-radius: 2px;
|
|
||||||
font: 13px "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
|
||||||
color: #777;
|
|
||||||
margin: 0;
|
|
||||||
width: 210px;
|
|
||||||
max-width: 100%;
|
|
||||||
// display: block; /** WEB2PY EDIT **/
|
|
||||||
margin-bottom: 0; /** WEB2PY EDIT **/
|
|
||||||
background: #fff; }
|
|
||||||
select {
|
|
||||||
padding: 0; }
|
|
||||||
input[type="text"]:focus,
|
|
||||||
input[type="password"]:focus,
|
|
||||||
input[type="email"]:focus,
|
|
||||||
textarea:focus {
|
|
||||||
border: 1px solid #aaa;
|
|
||||||
color: #444;
|
|
||||||
-moz-box-shadow: 0 0 3px rgba(0,0,0,.2);
|
|
||||||
-webkit-box-shadow: 0 0 3px rgba(0,0,0,.2);
|
|
||||||
box-shadow: 0 0 3px rgba(0,0,0,.2); }
|
|
||||||
textarea {
|
|
||||||
min-height: 60px; }
|
|
||||||
label,
|
|
||||||
legend {
|
|
||||||
display: block;
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 13px; }
|
|
||||||
select {
|
|
||||||
width: 220px; }
|
|
||||||
input[type="checkbox"] {
|
|
||||||
display: inline; }
|
|
||||||
label span,
|
|
||||||
legend span {
|
|
||||||
font-weight: normal;
|
|
||||||
font-size: 13px;
|
|
||||||
color: #444; }
|
|
||||||
|
|
||||||
/* #Misc
|
|
||||||
================================================== */
|
|
||||||
.remove-bottom { margin-bottom: 0 !important; }
|
|
||||||
.half-bottom { margin-bottom: 10px !important; }
|
|
||||||
.add-bottom { margin-bottom: 20px !important; }
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Skeleton V1.1
|
|
||||||
* Copyright 2011, Dave Gamache
|
|
||||||
* www.getskeleton.com
|
|
||||||
* Free to use under the MIT license.
|
|
||||||
* http://www.opensource.org/licenses/mit-license.php
|
|
||||||
* 8/17/2011
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Table of Content
|
|
||||||
==================================================
|
|
||||||
#Site Styles
|
|
||||||
#Page Styles
|
|
||||||
#Media Queries
|
|
||||||
#Font-Face */
|
|
||||||
|
|
||||||
/* #Site Styles
|
|
||||||
================================================== */
|
|
||||||
|
|
||||||
/* #Page Styles
|
|
||||||
================================================== */
|
|
||||||
|
|
||||||
/* #Media Queries
|
|
||||||
================================================== */
|
|
||||||
|
|
||||||
/* Smaller than standard 960 (devices and browsers) */
|
|
||||||
@media only screen and (max-width: 959px) {}
|
|
||||||
|
|
||||||
/* Tablet Portrait size to standard 960 (devices and browsers) */
|
|
||||||
@media only screen and (min-width: 768px) and (max-width: 959px) {}
|
|
||||||
|
|
||||||
/* All Mobile Sizes (devices and browser) */
|
|
||||||
@media only screen and (max-width: 767px) {}
|
|
||||||
|
|
||||||
/* Mobile Landscape Size to Tablet Portrait (devices and browsers) */
|
|
||||||
@media only screen and (min-width: 480px) and (max-width: 767px) {}
|
|
||||||
|
|
||||||
/* Mobile Portrait Size to Mobile Landscape Size (devices and browsers) */
|
|
||||||
@media only screen and (max-width: 479px) {}
|
|
||||||
|
|
||||||
|
|
||||||
/* #Font-Face
|
|
||||||
================================================== */
|
|
||||||
/* This is the proper syntax for an @font-face file
|
|
||||||
Just create a "fonts" folder at the root,
|
|
||||||
copy your FontName into code below and remove
|
|
||||||
comment brackets */
|
|
||||||
|
|
||||||
/* @font-face {
|
|
||||||
font-family: 'FontName';
|
|
||||||
src: url('../fonts/FontName.eot');
|
|
||||||
src: url('../fonts/FontName.eot?iefix') format('eot'),
|
|
||||||
url('../fonts/FontName.woff') format('woff'),
|
|
||||||
url('../fonts/FontName.ttf') format('truetype'),
|
|
||||||
url('../fonts/FontName.svg#webfontZam02nTh') format('svg');
|
|
||||||
font-weight: normal;
|
|
||||||
font-style: normal; }
|
|
||||||
*//*
|
|
||||||
* Skeleton V1.1
|
|
||||||
* Copyright 2011, Dave Gamache
|
|
||||||
* www.getskeleton.com
|
|
||||||
* Free to use under the MIT license.
|
|
||||||
* http://www.opensource.org/licenses/mit-license.php
|
|
||||||
* 8/17/2011
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/* Table of Contents
|
|
||||||
==================================================
|
|
||||||
#Base 960 Grid
|
|
||||||
#Tablet (Portrait)
|
|
||||||
#Mobile (Portrait)
|
|
||||||
#Mobile (Landscape)
|
|
||||||
#Clearing */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* #Base 960 Grid
|
|
||||||
================================================== */
|
|
||||||
|
|
||||||
.container { position: relative; width: 960px; margin: 0 auto; padding: 0; }
|
|
||||||
.column, .columns { float: left; display: inline; margin-left: 10px; margin-right: 10px; }
|
|
||||||
.row { margin-bottom: 20px; }
|
|
||||||
|
|
||||||
/* Nested Column Classes */
|
|
||||||
.column.alpha, .columns.alpha { margin-left: 0; }
|
|
||||||
.column.omega, .columns.omega { margin-right: 0; }
|
|
||||||
|
|
||||||
/* Base Grid */
|
|
||||||
.container .one.column { width: 40px; }
|
|
||||||
.container .two.columns { width: 100px; }
|
|
||||||
.container .three.columns { width: 160px; }
|
|
||||||
.container .four.columns { width: 220px; }
|
|
||||||
.container .five.columns { width: 280px; }
|
|
||||||
.container .six.columns { width: 340px; }
|
|
||||||
.container .seven.columns { width: 400px; }
|
|
||||||
.container .eight.columns { width: 460px; }
|
|
||||||
.container .nine.columns { width: 520px; }
|
|
||||||
.container .ten.columns { width: 580px; }
|
|
||||||
.container .eleven.columns { width: 640px; }
|
|
||||||
.container .twelve.columns { width: 700px; }
|
|
||||||
.container .thirteen.columns { width: 760px; }
|
|
||||||
.container .fourteen.columns { width: 820px; }
|
|
||||||
.container .fifteen.columns { width: 880px; }
|
|
||||||
.container .sixteen.columns { width: 940px; }
|
|
||||||
|
|
||||||
.container .one-third.column { width: 300px; }
|
|
||||||
.container .two-thirds.column { width: 620px; }
|
|
||||||
|
|
||||||
/* Offsets */
|
|
||||||
.container .offset-by-one { padding-left: 60px; }
|
|
||||||
.container .offset-by-two { padding-left: 120px; }
|
|
||||||
.container .offset-by-three { padding-left: 180px; }
|
|
||||||
.container .offset-by-four { padding-left: 240px; }
|
|
||||||
.container .offset-by-five { padding-left: 300px; }
|
|
||||||
.container .offset-by-six { padding-left: 360px; }
|
|
||||||
.container .offset-by-seven { padding-left: 420px; }
|
|
||||||
.container .offset-by-eight { padding-left: 480px; }
|
|
||||||
.container .offset-by-nine { padding-left: 540px; }
|
|
||||||
.container .offset-by-ten { padding-left: 600px; }
|
|
||||||
.container .offset-by-eleven { padding-left: 660px; }
|
|
||||||
.container .offset-by-twelve { padding-left: 720px; }
|
|
||||||
.container .offset-by-thirteen { padding-left: 780px; }
|
|
||||||
.container .offset-by-fourteen { padding-left: 840px; }
|
|
||||||
.container .offset-by-fifteen { padding-left: 900px; }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* #Tablet (Portrait)
|
|
||||||
================================================== */
|
|
||||||
|
|
||||||
/* Note: Design for a width of 768px */
|
|
||||||
|
|
||||||
@media only screen and (min-width: 768px) and (max-width: 959px) {
|
|
||||||
.container { width: 768px; }
|
|
||||||
.container .column,
|
|
||||||
.container .columns { margin-left: 10px; margin-right: 10px; }
|
|
||||||
.column.alpha, .columns.alpha { margin-left: 0; margin-right: 10px; }
|
|
||||||
.column.omega, .columns.omega { margin-right: 0; margin-left: 10px; }
|
|
||||||
|
|
||||||
.container .one.column { width: 28px; }
|
|
||||||
.container .two.columns { width: 76px; }
|
|
||||||
.container .three.columns { width: 124px; }
|
|
||||||
.container .four.columns { width: 172px; }
|
|
||||||
.container .five.columns { width: 220px; }
|
|
||||||
.container .six.columns { width: 268px; }
|
|
||||||
.container .seven.columns { width: 316px; }
|
|
||||||
.container .eight.columns { width: 364px; }
|
|
||||||
.container .nine.columns { width: 412px; }
|
|
||||||
.container .ten.columns { width: 460px; }
|
|
||||||
.container .eleven.columns { width: 508px; }
|
|
||||||
.container .twelve.columns { width: 556px; }
|
|
||||||
.container .thirteen.columns { width: 604px; }
|
|
||||||
.container .fourteen.columns { width: 652px; }
|
|
||||||
.container .fifteen.columns { width: 700px; }
|
|
||||||
.container .sixteen.columns { width: 748px; }
|
|
||||||
|
|
||||||
.container .one-third.column { width: 236px; }
|
|
||||||
.container .two-thirds.column { width: 492px; }
|
|
||||||
|
|
||||||
/* Offsets */
|
|
||||||
.container .offset-by-one { padding-left: 48px; }
|
|
||||||
.container .offset-by-two { padding-left: 96px; }
|
|
||||||
.container .offset-by-three { padding-left: 144px; }
|
|
||||||
.container .offset-by-four { padding-left: 192px; }
|
|
||||||
.container .offset-by-five { padding-left: 240px; }
|
|
||||||
.container .offset-by-six { padding-left: 288px; }
|
|
||||||
.container .offset-by-seven { padding-left: 336px; }
|
|
||||||
.container .offset-by-eight { padding-left: 348px; }
|
|
||||||
.container .offset-by-nine { padding-left: 432px; }
|
|
||||||
.container .offset-by-ten { padding-left: 480px; }
|
|
||||||
.container .offset-by-eleven { padding-left: 528px; }
|
|
||||||
.container .offset-by-twelve { padding-left: 576px; }
|
|
||||||
.container .offset-by-thirteen { padding-left: 624px; }
|
|
||||||
.container .offset-by-fourteen { padding-left: 672px; }
|
|
||||||
.container .offset-by-fifteen { padding-left: 720px; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* #Mobile (Portrait)
|
|
||||||
================================================== */
|
|
||||||
|
|
||||||
/* Note: Design for a width of 320px */
|
|
||||||
|
|
||||||
@media only screen and (max-width: 767px) {
|
|
||||||
.container { width: 300px; }
|
|
||||||
.columns, .column { margin: 0; }
|
|
||||||
|
|
||||||
.container .one.column,
|
|
||||||
.container .two.columns,
|
|
||||||
.container .three.columns,
|
|
||||||
.container .four.columns,
|
|
||||||
.container .five.columns,
|
|
||||||
.container .six.columns,
|
|
||||||
.container .seven.columns,
|
|
||||||
.container .eight.columns,
|
|
||||||
.container .nine.columns,
|
|
||||||
.container .ten.columns,
|
|
||||||
.container .eleven.columns,
|
|
||||||
.container .twelve.columns,
|
|
||||||
.container .thirteen.columns,
|
|
||||||
.container .fourteen.columns,
|
|
||||||
.container .fifteen.columns,
|
|
||||||
.container .sixteen.columns,
|
|
||||||
.container .one-third.column,
|
|
||||||
.container .two-thirds.column { width: 300px; }
|
|
||||||
|
|
||||||
/* Offsets */
|
|
||||||
.container .offset-by-one,
|
|
||||||
.container .offset-by-two,
|
|
||||||
.container .offset-by-three,
|
|
||||||
.container .offset-by-four,
|
|
||||||
.container .offset-by-five,
|
|
||||||
.container .offset-by-six,
|
|
||||||
.container .offset-by-seven,
|
|
||||||
.container .offset-by-eight,
|
|
||||||
.container .offset-by-nine,
|
|
||||||
.container .offset-by-ten,
|
|
||||||
.container .offset-by-eleven,
|
|
||||||
.container .offset-by-twelve,
|
|
||||||
.container .offset-by-thirteen,
|
|
||||||
.container .offset-by-fourteen,
|
|
||||||
.container .offset-by-fifteen { padding-left: 0; }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* #Mobile (Landscape)
|
|
||||||
================================================== */
|
|
||||||
|
|
||||||
/* Note: Design for a width of 480px */
|
|
||||||
|
|
||||||
@media only screen and (min-width: 480px) and (max-width: 767px) {
|
|
||||||
.container { width: 420px; }
|
|
||||||
.columns, .column { margin: 0; }
|
|
||||||
|
|
||||||
.container .one.column,
|
|
||||||
.container .two.columns,
|
|
||||||
.container .three.columns,
|
|
||||||
.container .four.columns,
|
|
||||||
.container .five.columns,
|
|
||||||
.container .six.columns,
|
|
||||||
.container .seven.columns,
|
|
||||||
.container .eight.columns,
|
|
||||||
.container .nine.columns,
|
|
||||||
.container .ten.columns,
|
|
||||||
.container .eleven.columns,
|
|
||||||
.container .twelve.columns,
|
|
||||||
.container .thirteen.columns,
|
|
||||||
.container .fourteen.columns,
|
|
||||||
.container .fifteen.columns,
|
|
||||||
.container .sixteen.columns,
|
|
||||||
.container .one-third.column,
|
|
||||||
.container .two-thirds.column { width: 420px; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* #Clearing
|
|
||||||
================================================== */
|
|
||||||
|
|
||||||
/* Self Clearing Goodness */
|
|
||||||
.container:after { content: "\0020"; display: block; height: 0; clear: both; visibility: hidden; }
|
|
||||||
|
|
||||||
/* Use clearfix class on parent to clear nested columns,
|
|
||||||
or wrap each row of columns in a <div class="row"> */
|
|
||||||
.clearfix:before,
|
|
||||||
.clearfix:after,
|
|
||||||
.row:before,
|
|
||||||
.row:after {
|
|
||||||
content: '\0020';
|
|
||||||
display: block;
|
|
||||||
overflow: hidden;
|
|
||||||
visibility: hidden;
|
|
||||||
width: 0;
|
|
||||||
height: 0; }
|
|
||||||
.row:after,
|
|
||||||
.clearfix:after {
|
|
||||||
clear: both; }
|
|
||||||
.row,
|
|
||||||
.clearfix {
|
|
||||||
zoom: 1; }
|
|
||||||
|
|
||||||
/* You can also use a <br class="clear" /> to clear columns */
|
|
||||||
.clear {
|
|
||||||
clear: both;
|
|
||||||
display: block;
|
|
||||||
overflow: hidden;
|
|
||||||
visibility: hidden;
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
|
|
||||||
/*** ESSENTIAL STYLES ***/
|
|
||||||
.sf-menu, .sf-menu * {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
.sf-menu {
|
|
||||||
line-height: 1.0;
|
|
||||||
}
|
|
||||||
.sf-menu ul {
|
|
||||||
position: absolute;
|
|
||||||
top: -999em;
|
|
||||||
width: 10em; /* left offset of submenus need to match (see below) */
|
|
||||||
}
|
|
||||||
.sf-menu ul li {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.sf-menu li:hover {
|
|
||||||
visibility: inherit; /* fixes IE7 'sticky bug' */
|
|
||||||
}
|
|
||||||
.sf-menu li {
|
|
||||||
float: left;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.sf-menu a {
|
|
||||||
padding: 5px;
|
|
||||||
display: block;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.sf-menu li:hover ul,
|
|
||||||
.sf-menu li.sfHover ul {
|
|
||||||
left: 0;
|
|
||||||
top: 26px; /* match top ul list item height */
|
|
||||||
z-index: 99;
|
|
||||||
}
|
|
||||||
ul.sf-menu li:hover li ul,
|
|
||||||
ul.sf-menu li.sfHover li ul {
|
|
||||||
top: -999em;
|
|
||||||
}
|
|
||||||
ul.sf-menu li li:hover ul,
|
|
||||||
ul.sf-menu li li.sfHover ul {
|
|
||||||
left: 10em; /* match ul width */
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
ul.sf-menu li li:hover li ul,
|
|
||||||
ul.sf-menu li li.sfHover li ul {
|
|
||||||
top: -999em;
|
|
||||||
}
|
|
||||||
ul.sf-menu li li li:hover ul,
|
|
||||||
ul.sf-menu li li li.sfHover ul {
|
|
||||||
left: 10em; /* match ul width */
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*** DEMO SKIN ***/
|
|
||||||
.sf-menu {
|
|
||||||
float: left;
|
|
||||||
/*margin-bottom: 1em;*/
|
|
||||||
}
|
|
||||||
.sf-menu a {
|
|
||||||
padding-left: 1em;
|
|
||||||
padding-right: 1em;
|
|
||||||
text-decoration:none;
|
|
||||||
}
|
|
||||||
.sf-menu a, .sf-menu a:visited { /* visited pseudo selector so IE6 applies text colour*/
|
|
||||||
// color: #959595;
|
|
||||||
background-color: transparent;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
.sf-menu li {
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
.sf-menu li li {
|
|
||||||
background: #232323;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
.sf-menu li li a {
|
|
||||||
padding-top: 0.25em;
|
|
||||||
padding-bottom: 0.25em;
|
|
||||||
color: #959595;
|
|
||||||
}
|
|
||||||
.sf-menu li li li {
|
|
||||||
background: #232323;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
.sf-menu li li li a {
|
|
||||||
padding-top: 0.25em;
|
|
||||||
padding-bottom: 0.25em;
|
|
||||||
color: #959595;
|
|
||||||
}
|
|
||||||
.sf-menu li:hover, .sf-menu a:focus, .sf-menu a:active, .sf-menu li.sfHover, .sf-menu a:hover {
|
|
||||||
color: #FFFFFF;
|
|
||||||
background-color: #303030;
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*** arrows **/
|
|
||||||
.sf-menu a.sf-with-ul {
|
|
||||||
padding-right: 2.25em;
|
|
||||||
min-width: 1px; /* trigger IE7 hasLayout so spans position accurately */
|
|
||||||
}
|
|
||||||
.sf-sub-indicator {
|
|
||||||
position: absolute;
|
|
||||||
display: block;
|
|
||||||
right: .75em;
|
|
||||||
top: 1.05em; /* IE6 only */
|
|
||||||
width: 10px;
|
|
||||||
height: 10px;
|
|
||||||
text-indent: -999em;
|
|
||||||
overflow: hidden;
|
|
||||||
background: url('../images/arrows-ffffff.png') no-repeat -10px -100px; /* 8-bit indexed alpha png. IE6 gets solid image only */
|
|
||||||
}
|
|
||||||
a > .sf-sub-indicator { /* give all except IE6 the correct values */
|
|
||||||
top: .8em;
|
|
||||||
background-position: 0 -100px; /* use translucent arrow for modern browsers*/
|
|
||||||
}
|
|
||||||
/* apply hovers to modern browsers */
|
|
||||||
a:focus > .sf-sub-indicator,
|
|
||||||
a:hover > .sf-sub-indicator,
|
|
||||||
a:active > .sf-sub-indicator,
|
|
||||||
li:hover > a > .sf-sub-indicator,
|
|
||||||
li.sfHover > a > .sf-sub-indicator {
|
|
||||||
background-position: -10px -100px; /* arrow hovers for modern browsers*/
|
|
||||||
}
|
|
||||||
|
|
||||||
/* point right for anchors in subs */
|
|
||||||
.sf-menu ul .sf-sub-indicator { background-position: -10px 0; }
|
|
||||||
.sf-menu ul a > .sf-sub-indicator { background-position: 0 0; }
|
|
||||||
/* apply hovers to modern browsers */
|
|
||||||
.sf-menu ul a:focus > .sf-sub-indicator,
|
|
||||||
.sf-menu ul a:hover > .sf-sub-indicator,
|
|
||||||
.sf-menu ul a:active > .sf-sub-indicator,
|
|
||||||
.sf-menu ul li:hover > a > .sf-sub-indicator,
|
|
||||||
.sf-menu ul li.sfHover > a > .sf-sub-indicator {
|
|
||||||
background-position: -10px 0; /* arrow hovers for modern browsers*/
|
|
||||||
}
|
|
||||||
|
|
||||||
/*** shadows for all but IE6 ***/
|
|
||||||
.sf-shadow ul {
|
|
||||||
background: url('../images/shadow.png') no-repeat bottom right;
|
|
||||||
padding: 0 8px 9px 0;
|
|
||||||
-moz-border-radius-bottomleft: 17px;
|
|
||||||
-moz-border-radius-topright: 17px;
|
|
||||||
-webkit-border-top-right-radius: 17px;
|
|
||||||
-webkit-border-bottom-left-radius: 17px;
|
|
||||||
}
|
|
||||||
.sf-shadow ul.sf-shadow-off {
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -0,0 +1,232 @@
|
|||||||
|
/*=============================================================
|
||||||
|
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 */
|
||||||
|
textarea { width:90%}
|
||||||
|
.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%;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;}
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 478 B |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 991 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 198 B |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 323 B |
|
After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
@@ -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;
|
||||||
|
} );
|
||||||
|
});
|
||||||
@@ -1,223 +0,0 @@
|
|||||||
|
|
||||||
/*
|
|
||||||
* Superfish v1.4.8 - jQuery menu widget
|
|
||||||
* Copyright (c) 2008 Joel Birch
|
|
||||||
*
|
|
||||||
* Dual licensed under the MIT and GPL licenses:
|
|
||||||
* http://www.opensource.org/licenses/mit-license.php
|
|
||||||
* http://www.gnu.org/licenses/gpl.html
|
|
||||||
*
|
|
||||||
* CHANGELOG: http://users.tpg.com.au/j_birch/plugins/superfish/changelog.txt
|
|
||||||
*/
|
|
||||||
|
|
||||||
;(function($){
|
|
||||||
$.fn.superfish = function(op){
|
|
||||||
|
|
||||||
var sf = $.fn.superfish,
|
|
||||||
c = sf.c,
|
|
||||||
$arrow = $(['<span class="',c.arrowClass,'"> »</span>'].join('')),
|
|
||||||
over = function(){
|
|
||||||
var $$ = $(this), menu = getMenu($$);
|
|
||||||
clearTimeout(menu.sfTimer);
|
|
||||||
$$.showSuperfishUl().siblings().hideSuperfishUl();
|
|
||||||
},
|
|
||||||
out = function(){
|
|
||||||
var $$ = $(this), menu = getMenu($$), o = sf.op;
|
|
||||||
clearTimeout(menu.sfTimer);
|
|
||||||
menu.sfTimer=setTimeout(function(){
|
|
||||||
o.retainPath=($.inArray($$[0],o.$path)>-1);
|
|
||||||
$$.hideSuperfishUl();
|
|
||||||
if (o.$path.length && $$.parents(['li.',o.hoverClass].join('')).length<1){over.call(o.$path);}
|
|
||||||
},o.delay);
|
|
||||||
},
|
|
||||||
getMenu = function($menu){
|
|
||||||
var menu = $menu.parents(['ul.',c.menuClass,':first'].join(''))[0];
|
|
||||||
sf.op = sf.o[menu.serial];
|
|
||||||
return menu;
|
|
||||||
},
|
|
||||||
addArrow = function($a){ $a.addClass(c.anchorClass).append($arrow.clone()); };
|
|
||||||
|
|
||||||
return this.each(function() {
|
|
||||||
var s = this.serial = sf.o.length;
|
|
||||||
var o = $.extend({},sf.defaults,op);
|
|
||||||
o.$path = $('li.'+o.pathClass,this).slice(0,o.pathLevels).each(function(){
|
|
||||||
$(this).addClass([o.hoverClass,c.bcClass].join(' '))
|
|
||||||
.filter('li:has(ul)').removeClass(o.pathClass);
|
|
||||||
});
|
|
||||||
sf.o[s] = sf.op = o;
|
|
||||||
|
|
||||||
$('li:has(ul)',this)[($.fn.hoverIntent && !o.disableHI) ? 'hoverIntent' : 'hover'](over,out).each(function() {
|
|
||||||
if (o.autoArrows) addArrow( $('>a:first-child',this) );
|
|
||||||
})
|
|
||||||
.not('.'+c.bcClass)
|
|
||||||
.hideSuperfishUl();
|
|
||||||
|
|
||||||
var $a = $('a',this);
|
|
||||||
$a.each(function(i){
|
|
||||||
var $li = $a.eq(i).parents('li');
|
|
||||||
$a.eq(i).focus(function(){over.call($li);}).blur(function(){out.call($li);});
|
|
||||||
});
|
|
||||||
o.onInit.call(this);
|
|
||||||
|
|
||||||
}).each(function() {
|
|
||||||
var menuClasses = [c.menuClass];
|
|
||||||
if (sf.op.dropShadows && !($.browser.msie && $.browser.version < 7)) menuClasses.push(c.shadowClass);
|
|
||||||
$(this).addClass(menuClasses.join(' '));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
var sf = $.fn.superfish;
|
|
||||||
sf.o = [];
|
|
||||||
sf.op = {};
|
|
||||||
sf.IE7fix = function(){
|
|
||||||
var o = sf.op;
|
|
||||||
if ($.browser.msie && $.browser.version > 6 && o.dropShadows && o.animation.opacity!=undefined)
|
|
||||||
this.toggleClass(sf.c.shadowClass+'-off');
|
|
||||||
};
|
|
||||||
sf.c = {
|
|
||||||
bcClass : 'sf-breadcrumb',
|
|
||||||
menuClass : 'sf-js-enabled',
|
|
||||||
anchorClass : 'sf-with-ul',
|
|
||||||
arrowClass : 'sf-sub-indicator',
|
|
||||||
shadowClass : 'sf-shadow'
|
|
||||||
};
|
|
||||||
sf.defaults = {
|
|
||||||
hoverClass : 'sfHover',
|
|
||||||
pathClass : 'overideThisToUse',
|
|
||||||
pathLevels : 1,
|
|
||||||
delay : 800,
|
|
||||||
animation : {opacity:'show'},
|
|
||||||
speed : 'normal',
|
|
||||||
autoArrows : true,
|
|
||||||
dropShadows : true,
|
|
||||||
disableHI : false, // true disables hoverIntent detection
|
|
||||||
onInit : function(){}, // callback functions
|
|
||||||
onBeforeShow: function(){},
|
|
||||||
onShow : function(){},
|
|
||||||
onHide : function(){}
|
|
||||||
};
|
|
||||||
$.fn.extend({
|
|
||||||
hideSuperfishUl : function(){
|
|
||||||
var o = sf.op,
|
|
||||||
not = (o.retainPath===true) ? o.$path : '';
|
|
||||||
o.retainPath = false;
|
|
||||||
var $ul = $(['li.',o.hoverClass].join(''),this).add(this).not(not).removeClass(o.hoverClass)
|
|
||||||
.find('>ul').hide().css('visibility','hidden');
|
|
||||||
o.onHide.call($ul);
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
showSuperfishUl : function(){
|
|
||||||
var o = sf.op,
|
|
||||||
sh = sf.c.shadowClass+'-off',
|
|
||||||
$ul = this.addClass(o.hoverClass)
|
|
||||||
.find('>ul:hidden').css('visibility','visible');
|
|
||||||
sf.IE7fix.call($ul);
|
|
||||||
o.onBeforeShow.call($ul);
|
|
||||||
$ul.animate(o.animation,o.speed,function(){ sf.IE7fix.call($ul); o.onShow.call($ul); });
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
})(jQuery);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Supersubs v0.2b - jQuery plugin
|
|
||||||
* Copyright (c) 2008 Joel Birch
|
|
||||||
*
|
|
||||||
* Dual licensed under the MIT and GPL licenses:
|
|
||||||
* http://www.opensource.org/licenses/mit-license.php
|
|
||||||
* http://www.gnu.org/licenses/gpl.html
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* This plugin automatically adjusts submenu widths of suckerfish-style menus to that of
|
|
||||||
* their longest list item children. If you use this, please expect bugs and report them
|
|
||||||
* to the jQuery Google Group with the word 'Superfish' in the subject line.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
;(function($){ // $ will refer to jQuery within this closure
|
|
||||||
|
|
||||||
$.fn.supersubs = function(options){
|
|
||||||
var opts = $.extend({}, $.fn.supersubs.defaults, options);
|
|
||||||
// return original object to support chaining
|
|
||||||
return this.each(function() {
|
|
||||||
// cache selections
|
|
||||||
var $$ = $(this);
|
|
||||||
// support metadata
|
|
||||||
var o = $.meta ? $.extend({}, opts, $$.data()) : opts;
|
|
||||||
// get the font size of menu.
|
|
||||||
// .css('fontSize') returns various results cross-browser, so measure an em dash instead
|
|
||||||
var fontsize = $('<li id="menu-fontsize">—</li>').css({
|
|
||||||
'padding' : 0,
|
|
||||||
'position' : 'absolute',
|
|
||||||
'top' : '-999em',
|
|
||||||
'width' : 'auto'
|
|
||||||
}).appendTo($$).width(); //clientWidth is faster, but was incorrect here
|
|
||||||
// remove em dash
|
|
||||||
$('#menu-fontsize').remove();
|
|
||||||
// cache all ul elements
|
|
||||||
$ULs = $$.find('ul');
|
|
||||||
// loop through each ul in menu
|
|
||||||
$ULs.each(function(i) {
|
|
||||||
// cache this ul
|
|
||||||
var $ul = $ULs.eq(i);
|
|
||||||
// get all (li) children of this ul
|
|
||||||
var $LIs = $ul.children();
|
|
||||||
// get all anchor grand-children
|
|
||||||
var $As = $LIs.children('a');
|
|
||||||
// force content to one line and save current float property
|
|
||||||
var liFloat = $LIs.css('white-space','nowrap').css('float');
|
|
||||||
// remove width restrictions and floats so elements remain vertically stacked
|
|
||||||
var emWidth = $ul.add($LIs).add($As).css({
|
|
||||||
'float' : 'none',
|
|
||||||
'width' : 'auto'
|
|
||||||
})
|
|
||||||
// this ul will now be shrink-wrapped to longest li due to position:absolute
|
|
||||||
// so save its width as ems. Clientwidth is 2 times faster than .width() - thanks Dan Switzer
|
|
||||||
.end().end()[0].clientWidth / fontsize;
|
|
||||||
// add more width to ensure lines don't turn over at certain sizes in various browsers
|
|
||||||
emWidth += o.extraWidth;
|
|
||||||
// restrict to at least minWidth and at most maxWidth
|
|
||||||
if (emWidth > o.maxWidth) { emWidth = o.maxWidth; }
|
|
||||||
else if (emWidth < o.minWidth) { emWidth = o.minWidth; }
|
|
||||||
emWidth += 'em';
|
|
||||||
// set ul to width in ems
|
|
||||||
$ul.css('width',emWidth);
|
|
||||||
// restore li floats to avoid IE bugs
|
|
||||||
// set li width to full width of this ul
|
|
||||||
// revert white-space to normal
|
|
||||||
$LIs.css({
|
|
||||||
'float' : liFloat,
|
|
||||||
'width' : '100%',
|
|
||||||
'white-space' : 'normal'
|
|
||||||
})
|
|
||||||
// update offset position of descendant ul to reflect new width of parent
|
|
||||||
.each(function(){
|
|
||||||
var $childUl = $('>ul',this);
|
|
||||||
var offsetDirection = $childUl.css('left')!==undefined ? 'left' : 'right';
|
|
||||||
$childUl.css(offsetDirection,$ul.width());
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
};
|
|
||||||
// expose defaults
|
|
||||||
$.fn.supersubs.defaults = {
|
|
||||||
minWidth : 9, // requires em unit.
|
|
||||||
maxWidth : 25, // requires em unit.
|
|
||||||
extraWidth : 0 // extra width can ensure lines don't sometimes turn over due to slight browser differences in how they round-off values
|
|
||||||
};
|
|
||||||
|
|
||||||
})(jQuery); // plugin code ends
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hoverIntent r6 // 2011.02.26 // jQuery 1.5.1+
|
|
||||||
* <http://cherne.net/brian/resources/jquery.hoverIntent.html>
|
|
||||||
*
|
|
||||||
* @param f onMouseOver function || An object with configuration options
|
|
||||||
* @param g onMouseOut function || Nothing (use configuration options object)
|
|
||||||
* @author Brian Cherne brian(at)cherne(dot)net
|
|
||||||
*/
|
|
||||||
(function($){$.fn.hoverIntent=function(f,g){var cfg={sensitivity:7,interval:100,timeout:0};cfg=$.extend(cfg,g?{over:f,out:g}:f);var cX,cY,pX,pY;var track=function(ev){cX=ev.pageX;cY=ev.pageY};var compare=function(ev,ob){ob.hoverIntent_t=clearTimeout(ob.hoverIntent_t);if((Math.abs(pX-cX)+Math.abs(pY-cY))<cfg.sensitivity){$(ob).unbind("mousemove",track);ob.hoverIntent_s=1;return cfg.over.apply(ob,[ev])}else{pX=cX;pY=cY;ob.hoverIntent_t=setTimeout(function(){compare(ev,ob)},cfg.interval)}};var delay=function(ev,ob){ob.hoverIntent_t=clearTimeout(ob.hoverIntent_t);ob.hoverIntent_s=0;return cfg.out.apply(ob,[ev])};var handleHover=function(e){var ev=jQuery.extend({},e);var ob=this;if(ob.hoverIntent_t){ob.hoverIntent_t=clearTimeout(ob.hoverIntent_t)}if(e.type=="mouseenter"){pX=ev.pageX;pY=ev.pageY;$(ob).bind("mousemove",track);if(ob.hoverIntent_s!=1){ob.hoverIntent_t=setTimeout(function(){compare(ev,ob)},cfg.interval)}}else{$(ob).unbind("mousemove",track);if(ob.hoverIntent_s==1){ob.hoverIntent_t=setTimeout(function(){delay(ev,ob)},cfg.timeout)}}};return this.bind('mouseenter',handleHover).bind('mouseleave',handleHover)}})(jQuery);
|
|
||||||
|
|
||||||
@@ -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');
|
||||||
|
});
|
||||||
@@ -5,38 +5,32 @@
|
|||||||
|
|
||||||
<h2>web2py<sup style="font-size:0.5em;">TM</sup> Download</h2>
|
<h2>web2py<sup style="font-size:0.5em;">TM</sup> Download</h2>
|
||||||
|
|
||||||
<div style="width: 90%; margin: 0 auto;">
|
<center style="padding:20px">
|
||||||
<center>
|
|
||||||
<table class="downloads">
|
<table class="downloads">
|
||||||
<tr>
|
<tr>
|
||||||
<th>Current ({{="%s.%s.%s %s" % (version[0],version[1],version[2],version[4])}})</th>
|
<th>For Normal Users</th>
|
||||||
<th>Nightly Build (for testers)</th>
|
<th>For Testers</th>
|
||||||
<th>Trunk (for developers)</th>
|
<th>For Developers</th>
|
||||||
<th>plugin_wiki (add-on)</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><a class="button" href="http://www.web2py.com/examples/static/web2py_win.zip">For Windows</a></td>
|
<td><a class="btn btn-180 btn-success" href="http://www.web2py.com/examples/static/web2py_win.zip">For Windows</a></td>
|
||||||
<td><a class="button" href="http://www.web2py.com/examples/static/nightly/web2py_win.zip">For Windows</a></td>
|
<td><a class="btn btn-180 btn-warning" href="http://www.web2py.com/examples/static/nightly/web2py_win.zip">For Windows</a></td>
|
||||||
<td><a class="button" href="http://github.com/web2py/web2py/" target="_blank">Git Repository</a></td>
|
<td><a class="btn btn-180 btn-danger" href="http://github.com/web2py/web2py/">Git Repository</a></td>
|
||||||
<td><a class="button" href="http://web2py.com/examples/static/web2py.plugin.wiki.w2p">Download</a></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><a class="button" href="http://www.web2py.com/examples/static/web2py_osx.zip">For Mac</a></td>
|
<td><a class="btn btn-180 btn-success" href="http://www.web2py.com/examples/static/web2py_osx.zip">For Mac</a></td>
|
||||||
<td><a class="button" href="http://www.web2py.com/examples/static/nightly/web2py_osx.zip">For Mac</a></td>
|
<td><a class="btn btn-180 btn-warning" href="http://www.web2py.com/examples/static/nightly/web2py_osx.zip">For Mac</a></td>
|
||||||
<td><a class="button" href="http://code.google.com/p/web2py/" target="_blank">Mercurial Repository</a></td>
|
<td><a class="btn btn-180 btn-danger" href="http://code.google.com/p/web2py/">Mercurial Repository</a></td>
|
||||||
<td><a class="button" href="http://code.google.com/p/cube2py/" target="_blank">Mercurial Repository</a>
|
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><a class="button" href="http://www.web2py.com/examples/static/web2py_src.zip">Source Code</a></td>
|
<td><a class="btn btn-180 btn-success" href="http://www.web2py.com/examples/static/web2py_src.zip">Source Code</a></td>
|
||||||
<td><a class="button" href="http://www.web2py.com/examples/static/nightly/web2py_src.zip">Source Code</a></td>
|
<td><a class="btn btn-180 btn-warning" href="http://www.web2py.com/examples/static/nightly/web2py_src.zip">Source Code</a></td>
|
||||||
<td><a class="button" href="{{=URL('static', 'epydoc/index.html')}}" target="_blank">Source Code Docs</a></td>
|
<td><a class="btn btn-180 btn-danger" href="{{=URL('static', 'epydoc/index.html')}}">Epydoc</a></td>
|
||||||
<td><a class="button" href="http://vimeo.com/13485916" target="_blank">What is plugin_wiki?</a></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><a class="button" href="{{=URL('changelog')}}">Change Log</a></td>
|
<td><a class="btn btn-180 btn-success" href="https://dl.dropbox.com/u/18065445/web2py/web2py_manual_5th.pdf">Manual</a></td>
|
||||||
<td><a class="button" href="http://www.web2py.com/examples/static/nightly/tests.log">Unittest Log</a></td>
|
<td><a class="btn btn-180" href="{{=URL('changelog')}}">Change Log</a></td>
|
||||||
<td><a class="button" href="http://code.google.com/p/web2py/issues/list" target="_blank">Issue Tracker</a></td>
|
<td><a class="btn btn-180" href="http://code.google.com/p/web2py/issues/list">Report a Bug</a></td>
|
||||||
<td></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</center>
|
</center>
|
||||||
@@ -64,28 +58,28 @@
|
|||||||
<p>Applications built with web2py can be released under any license the author wishes as long they do not contain web2py code. They can link unmodified web2py libraries and they can be distributed with official web2py binaries. In particular web2py applications can be distributed in closed source. The admin interface provides a button to byte-code compile.</p>
|
<p>Applications built with web2py can be released under any license the author wishes as long they do not contain web2py code. They can link unmodified web2py libraries and they can be distributed with official web2py binaries. In particular web2py applications can be distributed in closed source. The admin interface provides a button to byte-code compile.</p>
|
||||||
<p>It is fine to distribute web2py (source or compiled) with your applications as long as you make it clear in the license where your application ends and web2py starts.</p>
|
<p>It is fine to distribute web2py (source or compiled) with your applications as long as you make it clear in the license where your application ends and web2py starts.</p>
|
||||||
<p>web2py is copyrighted by Massimo Di Pierro. The web2py trademark is owned by Massimo Di Pierro.</p>
|
<p>web2py is copyrighted by Massimo Di Pierro. The web2py trademark is owned by Massimo Di Pierro.</p>
|
||||||
[<a href="{{=URL('license')}}">read more</a>]
|
<a class="btn btn-small" href="{{=URL('license')}}">read more</a>
|
||||||
|
|
||||||
<h3>Artwork</h3>
|
<h3>Artwork</h3>
|
||||||
<center>
|
<center>
|
||||||
<a href="{{=URL('static', 'images/logo_lb.png')}}"><img src="{{=URL('static', 'images/logo_lb.png')}}" width="200px"/></a>
|
<a href="{{=URL('static', 'images/logo_lb.png')}}"><img src="{{=URL('static', 'images/logo_lb.png')}}" width="200px"/></a>
|
||||||
<a href="{{=URL('static', 'images/logo_db.png')}}"><img src="{{=URL('static', '\
|
<a href="{{=URL('static', 'images/logo_db.png')}}"><img src="{{=URL('static', '\
|
||||||
images/logo_db.png')}}" width="200px"/></a>
|
images/logo_db.png')}}" width="200px"/></a>
|
||||||
<a href="{{=URL('static', 'images/logo_bw.png')}}"><img src="{{=URL('static', '\
|
<a href="{{=URL('static', 'images/logo_bw.png')}}"><img src="{{=URL('static', '\
|
||||||
images/logo_bw.png')}}" width="200px"/></a>
|
images/logo_bw.png')}}" width="200px"/></a>
|
||||||
</center>
|
</center>
|
||||||
<h3>Stickers</h3>
|
<h3>Stickers</h3>
|
||||||
<center>
|
<center>
|
||||||
<a href="{{=URL('static', 'images/Stickers1.png')}}"><img src="{{=URL('static', 'images/Stickers1.png')}}" /></a>
|
<a href="{{=URL('static', 'images/Stickers1.png')}}"><img src="{{=URL('static', 'images/Stickers1.png')}}" /></a>
|
||||||
<a href="{{=URL('static', 'images/Stickers2.png')}}"><img src="{{=URL('static', 'images/Stickers2.png')}}" /></a>
|
<a href="{{=URL('static', 'images/Stickers2.png')}}"><img src="{{=URL('static', 'images/Stickers2.png')}}" /></a>
|
||||||
<a href="{{=URL('static', 'images/Stickers3.png')}}"><img src="{{=URL('static', 'images/Stickers3.png')}}" /></a>
|
<a href="{{=URL('static', 'images/Stickers3.png')}}"><img src="{{=URL('static', 'images/Stickers3.png')}}" /></a>
|
||||||
<a href="{{=URL('static', 'images/Stickers4.png')}}"><img src="{{=URL('static', 'images/Stickers4.png')}}" /></a>
|
<a href="{{=URL('static', 'images/Stickers4.png')}}"><img src="{{=URL('static', 'images/Stickers4.png')}}" /></a>
|
||||||
<a href="{{=URL('static', 'images/Stickers5.png')}}"><img src="{{=URL('static', 'images/Stickers5.png')}}" /></a>
|
<a href="{{=URL('static', 'images/Stickers5.png')}}"><img src="{{=URL('static', 'images/Stickers5.png')}}" /></a>
|
||||||
<a href="{{=URL('static', 'images/Stickers6.png')}}"><img src="{{=URL('static', 'images/Stickers6.png')}}" /></a>
|
<a href="{{=URL('static', 'images/Stickers6.png')}}"><img src="{{=URL('static', 'images/Stickers6.png')}}" /></a>
|
||||||
<a href="{{=URL('static', 'images/Stickers7.png')}}"><img src="{{=URL('static', 'images/Stickers7.png')}}" /></a>
|
<a href="{{=URL('static', 'images/Stickers7.png')}}"><img src="{{=URL('static', 'images/Stickers7.png')}}" /></a>
|
||||||
<a href="{{=URL('static', 'images/Stickers8.png')}}"><img src="{{=URL('static', 'images/Stickers8.png')}}" /></a>
|
<a href="{{=URL('static', 'images/Stickers8.png')}}"><img src="{{=URL('static', 'images/Stickers8.png')}}" /></a>
|
||||||
</center>
|
</center>
|
||||||
|
<p></p>
|
||||||
<p>
|
<p>
|
||||||
<a href="{{=URL('static', 'artwork.tar.gz')}}" >Download WEB2PY artwork pack in editable .png format</a>
|
<a href="{{=URL('static', 'artwork.tar.gz')}}" >Download WEB2PY artwork pack in editable .png format</a>
|
||||||
</p>
|
</p>
|
||||||
@@ -99,6 +93,3 @@
|
|||||||
Icon set made by <a href="http://chrfb.deviantart.com">Christian Burprich</a> licensed under a <a rel="license" target="_blank" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Creative Commons Attribution-Noncommercial-Share Alike 3.0 License</a>
|
Icon set made by <a href="http://chrfb.deviantart.com">Christian Burprich</a> licensed under a <a rel="license" target="_blank" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Creative Commons Attribution-Noncommercial-Share Alike 3.0 License</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{{block sidebar}}{{end}}
|
|
||||||
{{block leftbadges}}{{end}}
|
|
||||||
</div>
|
|
||||||
|
|||||||
@@ -119,7 +119,6 @@ def raiseexception():
|
|||||||
return 'oops'
|
return 'oops'
|
||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>If an exception occurs (other than HTTP) a ticket is generated and the event is logged for the administrator. These tickets and logs can be accessed, reviewed and deleted at any later time.
|
<p>If an exception occurs (other than HTTP) a ticket is generated and the event is logged for the administrator. These tickets and logs can be accessed, reviewed and deleted at any later time.
|
||||||
<br/>Try it here: <a href="/{{=request.application}}/simple_examples/raiseexception">raiseexception</a></p>
|
|
||||||
|
|
||||||
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
|
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
|
||||||
{{=CODE("""
|
{{=CODE("""
|
||||||
@@ -605,7 +604,7 @@ def fade():
|
|||||||
|
|
||||||
<h3>Excel-like spreadsheet via Ajax</h3>
|
<h3>Excel-like spreadsheet via Ajax</h3>
|
||||||
Web2py includes a widget that acts like an Excel-like spreadsheet and can be used to build forms
|
Web2py includes a widget that acts like an Excel-like spreadsheet and can be used to build forms
|
||||||
[<a href="{{=URL('spreadsheet','index')}}">read more</a>].
|
<a class="btn btn-small" href="{{=URL('spreadsheet','index')}}">read more</a>.
|
||||||
|
|
||||||
<h2 id="testing_examples">Testing Examples</h2>
|
<h2 id="testing_examples">Testing Examples</h2>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
{{right_sidebar_enabled=True}}
|
|
||||||
{{extend 'layout.html'}}
|
{{extend 'layout.html'}}
|
||||||
{{
|
{{
|
||||||
import random
|
import random
|
||||||
@@ -14,73 +13,70 @@ quotes = [
|
|||||||
random.shuffle(quotes)
|
random.shuffle(quotes)
|
||||||
}}
|
}}
|
||||||
|
|
||||||
<table width="100%">
|
<div class="row-fluid">
|
||||||
<tr>
|
<div class="span12">
|
||||||
<td>
|
<div class="span8">
|
||||||
<a href="http://web2py.com/book">
|
<h3>web2py<sup>TM</sup> Web Framework</h3>
|
||||||
<img src="{{=URL('static','images/book-4th.png')}}" />
|
<p>Free open source full-stack framework for rapid development of fast, scalable, <a href="http://www.web2py.com/book/default/chapter/01#Security" target="_blank">secure</a> and portable database-driven web-based applications. Written and programmable in <a href="http://www.python.org" target="_blank">Python</a>.</p>
|
||||||
</a>
|
<table width="100%">
|
||||||
</td>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<a href="http://link.packtpub.com/SUlnrN">
|
<a href="http://web2py.com/book">
|
||||||
<img src="{{=URL('static','images/book-recipes.png')}}" />
|
<img src="{{=URL('static','images/book-5th.png')}}" />
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="http://www.youtube.com/playlist?list=PL5E2E223FE3777851">
|
<a href="http://link.packtpub.com/SUlnrN">
|
||||||
<img src="{{=URL('static','images/videos.png')}}" />
|
<img src="{{=URL('static','images/book-recipes.png')}}" />
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
<td>
|
||||||
</table>
|
<a href="http://www.youtube.com/playlist?list=PL5E2E223FE3777851">
|
||||||
|
<img src="{{=URL('static','images/videos.png')}}" />
|
||||||
|
</a>
|
||||||
<h3>WEB2PY<sup>TM</sup> WEB FRAMEWORK</h3>
|
</td>
|
||||||
<p>Free open source full-stack framework for rapid development of fast, scalable, <a href="http://www.web2py.com/book/default/chapter/01#security" target="_blank">secure</a> and portable database-driven web-based applications. Written and programmable in <a href="http://www.python.org" target="_blank">Python</a>. <a href="http://www.gnu.org/licenses/lgpl.html">LGPLv3 License</a>.
|
</tr>
|
||||||
Current version: {{="%s.%s.%s (%s) %s" % request.env.web2py_version}}</p>
|
</table>
|
||||||
|
<p>Current version: <a href="{{=URL('download')}}">{{=request.env.web2py_version}} (<a href="http://www.gnu.org/licenses/lgpl.html">LGPLv3 License</a>)</p>
|
||||||
{{block extra}}
|
|
||||||
<div class="container aboutW2P">
|
|
||||||
<div class="sixteen columns">
|
|
||||||
<div class="one-third column alpha">
|
|
||||||
<h3><a href="{{=URL('what')}}">BATTERIES INCLUDED</a></h3>
|
|
||||||
<p>Everything you need in one package including fast multi-threaded web server, SQL database and web-based interface. No third party dependencies but works with <a href={{=URL('what')}}>third party tools</a>.</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="one-third column">
|
<div class="span4" style="text-align:center">
|
||||||
<h3><a href="http://web2py.com/demo_admin">WEB-BASED IDE</a></h3>
|
<a href="http://www.infoworld.com/slideshow/24605/infoworlds-2012-technology-of-the-year-award-winners-183313#slide23"><img src="{{=URL('static','images/infoworld2012.jpeg')}}" width="200px"/></a><br/>
|
||||||
<p>Create, modify, deploy and manage application from anywhere using your browser. One web2py instance can run multiple web sites using different databases. Try the <a href="http://web2py.com/demo_admin">interactive demo</a>.</p>
|
<a class="btn btn-danger" href="{{=URL('download')}}" style="margin-top:10px; width:180px; color:white">Download Now</a><br/>
|
||||||
</div>
|
<a class="btn btn-danger" href="http://web2py.com/demo_admin" style="margin-top:10px; width:180px; color:white">Online Demo</a><br/>
|
||||||
<div class="one-third column omega">
|
<a class="btn btn-danger" href="http://web2py.com/poweredby" style="margin-top:10px; width:180px; color:white">Sites Powered by web2py</a>
|
||||||
<h3><a href="{{=URL('documentation')}}">EXTENSIVE DOCS</a></h3>
|
|
||||||
<p>Start with some <a href="{{=URL('examples')}}">quick examples</a>, then read the <a href="http://web2py.com/book" target="_blank">manual</a>, watch <a href="http://vimeo.com/album/178500" target="_blank">videos</a>, and join a <a href="{{=URL('default', 'usergroups')}}">user group</a> for discussion. Take advantage of the <a href="http://web2py.com/layouts" target="_blank">layouts</a>, <a href="http://dev.s-cubism.com/web2py_plugins" target="_blank">plugins</a>, <a href="http://www.web2py.com/appliances" target="_blank">appliances</a>, and <a href="http://web2pyslices.com" target="_blank">recipes</a>.</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<img class="scale-with-grid centered" src="/examples/static/images/shadow-bottom.png">
|
<div class="row-fluid">
|
||||||
<div class="container userQuotes">
|
<div class="span12">
|
||||||
<div class="sixteen columns">
|
<div class="span4">
|
||||||
<!-- img src="{{=URL('static','images/shadow-bottom.png')}}" width="100%"/ -->
|
<h3><a href="{{=URL('what')}}">Batteries Included</a></h3>
|
||||||
|
<p>Everything you need in one package including fast multi-threaded web server, SQL database and web-based interface. No third party dependencies but works with <a href={{=URL('what')}}>third party tools</a>.</p>
|
||||||
|
</div>
|
||||||
|
<div class="span4">
|
||||||
|
<h3><a href="http://web2py.com/demo_admin">Web-Based IDE</a></h3>
|
||||||
|
<p>Create, modify, deploy and manage application from anywhere using your browser. One web2py instance can run multiple web sites using different databases. Try the <a href="http://www.web2py.com/demo_admin">interactive demo</a>.</p>
|
||||||
|
</div>
|
||||||
|
<div class="span4">
|
||||||
|
<h3><a href="{{=URL('documentation')}}">Extensive Docs</a></h3>
|
||||||
|
<p>Start with some <a href="{{=URL('examples')}}">quick examples</a>, then read the <a href="http://www.web2py.com/book" target="_blank">manual</a>, watch <a href="http://vimeo.com/album/178500" target="_blank">videos</a>, and join a <a href="{{=URL('default', 'usergroups')}}">user group</a> for discussion. Take advantage of the <a href="http://www.web2py.com/layouts" target="_blank">layouts</a>, <a href="http://dev.s-cubism.com/web2py_plugins" target="_blank">plugins</a>, <a href="http://www.web2py.com/appliances" target="_blank">appliances</a>, and <a href="http://web2pyslices.com" target="_blank">recipes</a>.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row-fluid">
|
||||||
|
<div class="span12">
|
||||||
|
<img class="scale-with-grid centered" src="/examples/static/images/shadow-bottom.png">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row-fluid">
|
||||||
|
<div class="span12">
|
||||||
{{for k,quote in enumerate(quotes[:3]):}}
|
{{for k,quote in enumerate(quotes[:3]):}}
|
||||||
<div class="one-third column {{=[' alpha', '', ' omega'][k]}}">
|
<div class="span4">
|
||||||
<em>
|
<p style="text-align: left"><em>{{=quote[0]}}</em></p>
|
||||||
<p>{{=quote[0]}}</p>
|
|
||||||
</em>
|
|
||||||
<span class="right">
|
<span class="right">
|
||||||
<a href="{{=quote[2]}}"><em>—{{=quote[1]}}</em></a>
|
<a href="{{=quote[2]}}">{{=quote[1]}}</a>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
|
||||||
|
|
||||||
{{block right_sidebar}}
|
|
||||||
<div class="one-third column" style="text-align:center">
|
|
||||||
<img class="scale-with-grid centered" src="{{=URL('static','images/tag-cloud-color-small.png')}}" width="300px"/>
|
|
||||||
<br/>
|
|
||||||
<a class="button" href="{{=URL('download')}}" style="width:90%">DOWNLOAD NOW</a><br/>
|
|
||||||
<a class="button" href="http://web2py.com/demo_admin" style="width:90%">ONLINE DEMO</a><br/>
|
|
||||||
<a class="button" href="http://web2py.com/poweredby" style="width:90%">SITES POWERED BY WEB2PY</a><br/>
|
|
||||||
<a class="button" href="http://www.chipin.com/contribute/id/dcd384d58839aa4d" style="width:90%">SUPPORT/DONATE</a></br>
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
|
|||||||
@@ -147,8 +147,7 @@
|
|||||||
|
|
||||||
<li><a href="http://www.python.org">Python</a> created by Guido van Rossum.</li>
|
<li><a href="http://www.python.org">Python</a> created by Guido van Rossum.</li>
|
||||||
<li>Rocket Web Server developed by Timothy Farrell.</li>
|
<li>Rocket Web Server developed by Timothy Farrell.</li>
|
||||||
<li><a href="http://www.cdolivet.com/index.php?page=editArea">EditArea</a> developed by Christophe Dolivet</li>
|
<li><a href="http://codemirror.net/">CodeMirror</a></li>
|
||||||
<li><a href="http://nicedit.com">nicEdit</a> developed by <a href="http://bkirchoff.com">Brian Kirchoff</a></li>
|
|
||||||
<li><a href="http://cheeseshop.python.org/pypi/simplejson">simplejson</a> developed by Bob Ippolito</li>
|
<li><a href="http://cheeseshop.python.org/pypi/simplejson">simplejson</a> developed by Bob Ippolito</li>
|
||||||
<li><a href="http://pyrtf.sourceforge.net/">PyRTF</a> developed by Simon Cusack and revised by Grant Edwards</li>
|
<li><a href="http://pyrtf.sourceforge.net/">PyRTF</a> developed by Simon Cusack and revised by Grant Edwards</li>
|
||||||
<li><a href="http://www.dalkescientific.com/Python/PyRSS2Gen.html">PyRSS2Gen</a> developed by Dalke Scientific Software</li>
|
<li><a href="http://www.dalkescientific.com/Python/PyRSS2Gen.html">PyRSS2Gen</a> developed by Dalke Scientific Software</li>
|
||||||
@@ -159,8 +158,8 @@
|
|||||||
<li><a href="http://jquery.com/">jQuery</a> developed by John Resig</li>
|
<li><a href="http://jquery.com/">jQuery</a> developed by John Resig</li>
|
||||||
<li>A syntax highlighter inspired by the code of <a href="http://www.petersblog.org/node/763">Peter Wilkinson</a></li>
|
<li>A syntax highlighter inspired by the code of <a href="http://www.petersblog.org/node/763">Peter Wilkinson</a></li>
|
||||||
<li><a href="https://github.com/jtauber/pyuca">pyUCA</a> developed by <a href="http://jtauber.com/blog/2006/01/27/python_unicode_collation_algorithm/">James Tauber</a></li>
|
<li><a href="https://github.com/jtauber/pyuca">pyUCA</a> developed by <a href="http://jtauber.com/blog/2006/01/27/python_unicode_collation_algorithm/">James Tauber</a></li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
(... and other third party modules in the contrib folder).
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -2,46 +2,53 @@
|
|||||||
{{import cgi}}
|
{{import cgi}}
|
||||||
|
|
||||||
<div class="contentleft">
|
<div class="contentleft">
|
||||||
<h1>{{=T('Docs for')}} {{=title}}</h1>
|
<h1>{{=T('Docs for')}} {{=title}}</h1>
|
||||||
|
|
||||||
<div align="right">
|
<div align="right">
|
||||||
[ <a href="http://docs.python.org/tut/">Python Tutorial</a> ]
|
[ <a href="http://docs.python.org/tut/">Python Tutorial</a> ]
|
||||||
[ <a href="http://docs.python.org/lib/">Python Libraries</a> ]
|
[ <a href="http://docs.python.org/lib/">Python Libraries</a> ]
|
||||||
[ <a href="/{{=request.application}}/static/epydoc/index.html">web2py epydoc</a> ]
|
[ <a href="/{{=request.application}}/static/epydoc/index.html">web2py epydoc</a> ]
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2>{{=T('Description')}}</h2>
|
<h2>{{=T('Description')}}</h2>
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
{{if t:}}
|
{{if t:}}
|
||||||
{{=t}}{{if d:}} extends {{=d}}{{pass}}
|
{{=t}}{{if d:}} extends {{=d}}{{pass}}
|
||||||
{{pass}}
|
{{pass}}
|
||||||
<br/>
|
<br/>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
|
|
||||||
{{if doc:}}<br/><br/>{{=CODE(str(doc),language=None,counter=None,_class='boxCode')}}{{pass}}
|
{{if doc:}}<br/><br/>{{=MARKMIN(doc)}}{{pass}}
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
<div class="boxInfo">
|
<div class="boxInfo">
|
||||||
|
{{if attributes:}}
|
||||||
<h2>{{=T('Attributes')}}</h2>
|
<h2>{{=T('Attributes')}}</h2>
|
||||||
|
|
||||||
{{keys=attributes.keys(); keys.sort()}}
|
|
||||||
<table>
|
<table>
|
||||||
<tr><td colspan=2><hr/></td></tr>
|
<tr><td colspan=2><hr/></td></tr>
|
||||||
{{for a in keys:}}
|
{{for key in sorted(attributes):}}
|
||||||
{{doc1,t1,c1,d1=attributes[a]}}
|
{{doc1,t1,c1,d1=attributes[key]}}
|
||||||
<tr>
|
<tr>
|
||||||
<td><b>{{#=a}}</b>{{=A(a,_href=URL(r=request,args=a.split('.')))}}</td>
|
<td>
|
||||||
<td>
|
{{if key.count('.')<2:}}
|
||||||
{{if t1:}}
|
{{=A(key,_rel="nofollow",_href=URL(args=key.split('.')))}}
|
||||||
{{=t1}}{{if d1:}} extends {{=d1}}{{pass}}
|
{{else:}}
|
||||||
{{if c1:}} belongs to class {{=c1}}{{pass}}
|
{{=key}}
|
||||||
<br/>
|
{{pass}}
|
||||||
{{pass}}
|
</td>
|
||||||
{{if doc1:}}{{=XML(cgi.escape(str(doc1)).replace(chr(13),'<br/>'))}}{{pass}}
|
<td>
|
||||||
|
{{if t1:}}
|
||||||
|
{{=t1}}{{if d1:}} extends {{=d1}}{{pass}}
|
||||||
|
{{if c1:}} belongs to class {{=c1}}{{pass}}
|
||||||
|
<br/>
|
||||||
|
{{pass}}
|
||||||
|
{{if doc1:}}{{=MARKMIN(doc1)}}{{pass}}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr><td colspan=2><hr/></td></tr>
|
<tr><td colspan=2><hr/></td></tr>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
{{pass}}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
<!--[if HTML5]><![endif]-->
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<!-- paulirish.com/2008/conditional-stylesheets-vs-css-hacks-answer-neither/ -->
|
<!-- paulirish.com/2008/conditional-stylesheets-vs-css-hacks-answer-neither/ -->
|
||||||
<!--[if lt IE 7]><html class="ie ie6 ie-lte9 ie-lte8 ie-lte7 no-js" lang="{{=T.accepted_language or 'en'}}"> <![endif]-->
|
<!--[if lt IE 7]><html class="ie ie6 ie-lte9 ie-lte8 ie-lte7 no-js" lang="{{=T.accepted_language or 'en'}}"> <![endif]-->
|
||||||
@@ -6,139 +7,167 @@
|
|||||||
<!--[if IE 9]><html class="ie9 ie-lte9 no-js" lang="{{=T.accepted_language or 'en'}}"> <![endif]-->
|
<!--[if IE 9]><html class="ie9 ie-lte9 no-js" lang="{{=T.accepted_language or 'en'}}"> <![endif]-->
|
||||||
<!--[if (gt IE 9)|!(IE)]><!--> <html class="no-js" lang="{{=T.accepted_language or 'en'}}"> <!--<![endif]-->
|
<!--[if (gt IE 9)|!(IE)]><!--> <html class="no-js" lang="{{=T.accepted_language or 'en'}}"> <!--<![endif]-->
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<title>{{=response.title or request.application}}</title>
|
||||||
|
<!--[if !HTML5]>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge{{=not request.is_local and ',chrome=1' or ''}}">
|
||||||
|
<![endif]-->
|
||||||
<!-- www.phpied.com/conditional-comments-block-downloads/ -->
|
<!-- www.phpied.com/conditional-comments-block-downloads/ -->
|
||||||
<!-- Always force latest IE rendering engine
|
<!-- Always force latest IE rendering engine
|
||||||
(even in intranet) & Chrome Frame
|
(even in intranet) & Chrome Frame
|
||||||
Remove this if you use the .htaccess -->
|
Remove this if you use the .htaccess -->
|
||||||
<!--[if IE]>
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta charset="utf-8" />
|
||||||
<![endif]-->
|
|
||||||
|
|
||||||
<title>{{=response.title or request.application}}</title>
|
|
||||||
|
|
||||||
<!-- http://dev.w3.org/html5/markup/meta.name.html -->
|
<!-- http://dev.w3.org/html5/markup/meta.name.html -->
|
||||||
<meta name="application-name" content="{{=request.application}}" />
|
<meta name="application-name" content="{{=request.application}}" />
|
||||||
|
|
||||||
<!-- Speaking of Google, don't forget to set your site up:
|
<!-- Speaking of Google, don't forget to set your site up:
|
||||||
http://google.com/webmasters -->
|
http://google.com/webmasters -->
|
||||||
<meta name="google-site-verification" content="" />
|
<meta name="google-site-verification" content="" />
|
||||||
|
|
||||||
<!-- Mobile Viewport Fix
|
<!-- Mobile Viewport Fix
|
||||||
j.mp/mobileviewport & davidbcalhoun.com/2010/viewport-metatag
|
j.mp/mobileviewport & davidbcalhoun.com/2010/viewport-metatag
|
||||||
device-width: Occupy full width of the screen in its current orientation
|
device-width: Occupy full width of the screen in its current orientation
|
||||||
initial-scale = 1.0 retains dimensions instead of zooming out if page height > device height
|
initial-scale = 1.0 retains dimensions instead of zooming out if page height > device height
|
||||||
user-scalable = yes allows the user to zoom in -->
|
user-scalable = yes allows the user to zoom in -->
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
|
||||||
<!-- Place favicon.ico and apple-touch-icon.png in the root of your domain and delete these references -->
|
|
||||||
<link rel="shortcut icon" href="{{=URL('static','favicon.ico')}}" type="image/x-icon">
|
|
||||||
<link rel="apple-touch-icon" href="{{=URL('static','favicon.png')}}">
|
|
||||||
|
|
||||||
<!-- All JavaScript at the bottom, except for Modernizr which enables
|
<link rel="shortcut icon" href="{{=URL('static','images/favicon.ico')}}" type="image/x-icon">
|
||||||
HTML5 elements & feature detects -->
|
<link rel="apple-touch-icon" href="{{=URL('static','images/favicon.png')}}">
|
||||||
<script src="{{=URL('static','js/modernizr.custom.js')}}"></script>
|
|
||||||
|
<!-- All JavaScript at the bottom, except for Modernizr which enables
|
||||||
|
HTML5 elements & feature detects -->
|
||||||
|
<script src="{{=URL('static','js/modernizr.custom.js')}}"></script>
|
||||||
|
|
||||||
<!-- include stylesheets -->
|
<!-- include stylesheets -->
|
||||||
{{
|
{{
|
||||||
response.files.append(URL('static','css/skeleton.css'))
|
|
||||||
response.files.append(URL('static','css/web2py.css'))
|
response.files.append(URL('static','css/web2py.css'))
|
||||||
|
response.files.append(URL('static','css/bootstrap.min.css'))
|
||||||
|
response.files.append(URL('static','css/bootstrap-responsive.min.css'))
|
||||||
|
response.files.append(URL('static','css/web2py_bootstrap.css'))
|
||||||
response.files.append(URL('static','css/examples.css'))
|
response.files.append(URL('static','css/examples.css'))
|
||||||
response.files.append(URL('static','css/superfish.css'))
|
|
||||||
response.files.append(URL('static','js/superfish.js'))
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
{{include 'web2py_ajax.html'}}
|
{{include 'web2py_ajax.html'}}
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
jQuery(function(){jQuery('.sf-menu').superfish();});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{{
|
{{
|
||||||
|
# using sidebars need to know what sidebar you want to use
|
||||||
|
left_sidebar_enabled = globals().get('left_sidebar_enabled',False)
|
||||||
right_sidebar_enabled = globals().get('right_sidebar_enabled',False)
|
right_sidebar_enabled = globals().get('right_sidebar_enabled',False)
|
||||||
|
middle_columns = {0:'span12',1:'span9',2:'span6'}[
|
||||||
|
(left_sidebar_enabled and 1 or 0)+(right_sidebar_enabled and 1 or 0)]
|
||||||
}}
|
}}
|
||||||
|
|
||||||
<!-- uncomment here to load jquery-ui
|
<!-- uncomment here to load jquery-ui
|
||||||
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/themes/base/jquery-ui.css" type="text/css" media="all" />
|
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/themes/base/jquery-ui.css" type="text/css" media="all" />
|
||||||
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js" type="text/javascript"></script>
|
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js" type="text/javascript"></script>
|
||||||
uncomment to load jquery-ui //-->
|
uncomment to load jquery-ui //-->
|
||||||
</style>
|
<noscript><link href="{{=URL('static', 'css/web2py_bootstrap_nojs.css')}}" rel="stylesheet" type="text/css" /></noscript>
|
||||||
|
{{block head}}{{end}}
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="wrapper"><!-- for sticky footer -->
|
<!-- Navbar ================================================== -->
|
||||||
<div class="flash">{{=response.flash or ''}}</div>
|
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||||
<div class="header">
|
<div class="flash">{{=response.flash or ''}}</div>
|
||||||
|
<div class="navbar-inner">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="sixteen columns">
|
<!-- the next tag is necessary for bootstrap menus, do not remove -->
|
||||||
<img src="{{=URL('static','images/web2py_logo.png')}}" class="logo" alt="web2py logo" />
|
<button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
|
||||||
<h5>{{=response.subtitle or ''}}</h5>
|
<span class="icon-bar"></span>
|
||||||
</div>
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
<div class="sixteen columns statusbar">
|
</button>
|
||||||
{{block statusbar}}
|
{{=response.logo or ''}}
|
||||||
{{is_mobile=request.user_agent().is_mobile}}
|
<ul id="navbar" class="nav pull-right">{{='auth' in globals() and auth.navbar(mode="dropdown") or ''}}</ul>
|
||||||
<div id="menu" class="clearfix">{{=MENU(response.menu,_class='mobile-menu' if is_mobile else 'sf-menu',mobile=is_mobile)}}
|
<div class="nav-collapse">
|
||||||
{{end}}
|
{{is_mobile=request.user_agent().is_mobile}}
|
||||||
<!-- AddToAny BEGIN -->
|
{{if response.menu:}}
|
||||||
<div style="float:right;padding-top:6px;" class="a2a_kit a2a_default_style">
|
{{=MENU(response.menu, _class='mobile-menu nav' if is_mobile else 'nav',mobile=is_mobile,li_class='dropdown',ul_class='dropdown-menu')}}
|
||||||
<a class="a2a_dd" href="http://www.addtoany.com/share_save">Share</a></div>
|
{{pass}}
|
||||||
<script type="text/javascript" src="http://static.addtoany.com/menu/page.js"></script>
|
</div><!--/.nav-collapse -->
|
||||||
<!-- AddToAny END -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="sixteen columns announce">
|
|
||||||
<a href="http://www.infoworld.com/slideshow/24605/infoworlds-2012-technology-of-the-year-award-winners-183313#slide23"target="_blank">InfoWorld's 2012 Technology of the Year Award Winner</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="main">
|
</div><!--/top navbar -->
|
||||||
<div class="container mainbody">
|
|
||||||
<div class="sixteen columns">
|
<div class="container">
|
||||||
<div class="{{=right_sidebar_enabled and 'two-thirds column alpha' or 'sixteen columns alpha omega'}}">
|
<!-- Masthead ================================================== -->
|
||||||
|
<header class="mastheader" id="header">
|
||||||
|
<div class="span4">
|
||||||
|
<div class="page-header">
|
||||||
|
<img src="{{=URL('static','images/web2py_logo.png')}}" class="logo" alt="web2py logo" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
</div>
|
||||||
|
<div class="container">
|
||||||
|
|
||||||
|
<section id="main" class="main row">
|
||||||
|
{{if left_sidebar_enabled:}}
|
||||||
|
<div class="span3 left-sidebar">
|
||||||
|
{{block left_sidebar}}
|
||||||
|
<h3>Left Sidebar</h3>
|
||||||
|
<p></p>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
{{pass}}
|
||||||
|
|
||||||
|
<div class="{{=middle_columns}}">
|
||||||
{{block center}}
|
{{block center}}
|
||||||
{{include}}
|
{{include}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{if right_sidebar_enabled:}}
|
{{if right_sidebar_enabled:}}
|
||||||
<div class="one-third column omega">
|
<div class="span3">
|
||||||
{{block right_sidebar}}
|
{{block right_sidebar}}
|
||||||
<h3>Right Sidebar</h3>
|
<h3>Right Sidebar</h3>
|
||||||
<p></p>
|
<p></p>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
|
||||||
{{pass}}
|
|
||||||
</div>
|
</div>
|
||||||
</div><!-- container -->
|
{{pass}}
|
||||||
{{block extra}}{{end}}
|
</section><!--/main-->
|
||||||
|
|
||||||
</div><!-- main -->
|
|
||||||
|
|
||||||
<div class="push"></div>
|
|
||||||
</div><!-- wrapper -->
|
|
||||||
|
|
||||||
<div class="footer">
|
<!-- Footer ================================================== -->
|
||||||
<div class="container header">
|
<div class="row">
|
||||||
<div class="sixteen columns">
|
<footer class="footer span12" id="footer">
|
||||||
{{block footer}} <!-- this is default footer -->
|
<div class="footer-content">
|
||||||
<div class="footer-content" >
|
{{block footer}} <!-- this is default footer -->
|
||||||
{{=T('Copyright')}} © {{=request.now.year}}
|
<div id="poweredBy" class="pull-right">
|
||||||
- User communities in <a href="https://groups.google.com/forum/?fromgroups#!forum/web2py" target="_blank">English<a>, <a href="https://groups.google.com/forum/?fromgroups#!forum/web2py-fr" target="_blank">French</a>, <a href="https://groups.google.com/forum/?fromgroups#!forum/web2py-japan" target="_blank">Japanese</a>, <a href="https://groups.google.com/forum/?fromgroups#!forum/web2py-users-brazil" target="_blank">Portuguese</a>, and <a href="https://groups.google.com/forum/?fromgroups#!forum/web2py-usuarios" target="_blank">Spanish</a>.
|
{{=T('Copyright')}} © {{=request.now.year}} -
|
||||||
<div style="float: right;">
|
{{=T('Powered by')}}
|
||||||
<a href="http://www.web2py.com/" style="float: left; padding-right: 6px;">
|
<a href="http://www.web2py.com/">web2py</a> -
|
||||||
<img style="padding-bottom: 0;" src="{{=URL('static','images/poweredby.png')}}"/>
|
{{=T('Hosted by')}}
|
||||||
</a>
|
<a href="http://pythonanywhere.com">PythonAnywhere</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{{end}}
|
||||||
{{end}}
|
</div>
|
||||||
</div>
|
</footer>
|
||||||
</div><!-- container -->
|
</div>
|
||||||
</div><!-- footer -->
|
|
||||||
|
</div> <!-- /container -->
|
||||||
|
|
||||||
|
<!-- The javascript =============================================
|
||||||
|
(Placed at the end of the document so the pages load faster) -->
|
||||||
|
<script src="{{=URL('static','js/bootstrap.min.js')}}"></script>
|
||||||
|
<script src="{{=URL('static','js/web2py_bootstrap.js')}}"></script>
|
||||||
<!--[if lt IE 7 ]>
|
<!--[if lt IE 7 ]>
|
||||||
<script src="{{=URL('static','js/dd_belatedpng.js')}}"></script>
|
<script src="{{=URL('static','js/dd_belatedpng.js')}}"></script>
|
||||||
<script> DD_belatedPNG.fix('img, .png_bg'); //fix any <img> or .png_bg background-images </script>
|
<script> DD_belatedPNG.fix('img, .png_bg'); //fix any <img> or .png_bg background-images </script>
|
||||||
<![endif]-->
|
<![endif]-->
|
||||||
{{if response.google_analytics_id:}}<script>/* http://mathiasbynens.be/notes/async-analytics-snippet */ var _gaq=[['_setAccount','{{=response.google_analytics_id}}'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script')) </script>{{pass}}
|
|
||||||
|
{{if response.google_analytics_id:}}
|
||||||
|
<script src="{{=URL('static','js/analytics.min.js')}}"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
analytics.initialize({
|
||||||
|
'Google Analytics':{trackingId:'{{=response.google_analytics_id}}'}
|
||||||
|
});</script>
|
||||||
|
{{pass}}
|
||||||
|
<script src="{{=URL('static','js/share.js',vars=dict(static=URL('static','images')))}}"></script>
|
||||||
|
<a style="position:fixed;bottom:0;left:0;z-index:1000" href="https://groups.google.com/forum/?fromgroups#!forum/web2py" target="_blank">
|
||||||
|
<img src="{{=URL('static','images/questions.png')}}" />
|
||||||
|
</a>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
{{extend 'layout.html'}}
|
{{extend 'layout.html'}}
|
||||||
|
<style>
|
||||||
|
input {width: 70px;}
|
||||||
|
input:focus {background-color: yellow}
|
||||||
|
table, td, tr { border: 0; margin: 0; padding: 0}
|
||||||
|
</style>
|
||||||
<h1>Excel-like spreadsheet widget</h1>
|
<h1>Excel-like spreadsheet widget</h1>
|
||||||
|
|
||||||
Try insert "=r0c1+1" in cell r0c0 and "2" in r0c1. Formulas start with "=" as in Excel. You can use a subset of python commands and math function, and reference cells by r[row]c[col]. All computations are performed serverside via Ajax (input is validated for security). Cell values and formulas can be set and locked serverside. The shape of the spreadsheet can be modifed serverside and does not need to be tabular (think of it as a graph of css-friendly widgets you can place where you want). Cells can be given arbistrary names. This example is distributed with web2py so look at the source code of the example to learn more.
|
Try insert "=r0c1+1" in cell r0c0 and "2" in r0c1. Formulas start with "=" as in Excel. You can use a subset of python commands and math function, and reference cells by r[row]c[col]. All computations are performed serverside via Ajax (input is validated for security). Cell values and formulas can be set and locked serverside. The shape of the spreadsheet can be modifed serverside and does not need to be tabular (think of it as a graph of css-friendly widgets you can place where you want). Cells can be given arbistrary names. This example is distributed with web2py so look at the source code of the example to learn more.
|
||||||
|
|||||||
@@ -319,6 +319,9 @@ def state():
|
|||||||
|
|
||||||
|
|
||||||
def ccache():
|
def ccache():
|
||||||
|
cache.ram.initialize()
|
||||||
|
cache.disk.initialize()
|
||||||
|
|
||||||
form = FORM(
|
form = FORM(
|
||||||
P(TAG.BUTTON(
|
P(TAG.BUTTON(
|
||||||
T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
|
T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
|
||||||
@@ -385,7 +388,7 @@ def ccache():
|
|||||||
|
|
||||||
return (hours, minutes, seconds)
|
return (hours, minutes, seconds)
|
||||||
|
|
||||||
for key, value in cache.ram.storage.items():
|
for key, value in cache.ram.storage.iteritems():
|
||||||
if isinstance(value, dict):
|
if isinstance(value, dict):
|
||||||
ram['hits'] = value['hit_total'] - value['misses']
|
ram['hits'] = value['hit_total'] - value['misses']
|
||||||
ram['misses'] = value['misses']
|
ram['misses'] = value['misses']
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
'!langcode!': 'it',
|
'!langcode!': 'it',
|
||||||
'!langname!': 'Italiano',
|
'!langname!': 'Italiano',
|
||||||
'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" è un\'espressione opzionale come "campo1=\'nuovo valore\'". Non si può fare "update" o "delete" dei risultati di un JOIN ',
|
'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" è un\'espressione opzionale come "campo1=\'nuovo valore\'". Non si può fare "update" o "delete" dei risultati di un JOIN ',
|
||||||
'%(nrows)s records found': '%(nrows)s records found',
|
'%(nrows)s records found': '%(nrows)s record trovati',
|
||||||
'%d seconds ago': '%d seconds ago',
|
'%d seconds ago': '%d secondi fa',
|
||||||
'%s %%{row} deleted': '%s righe ("record") cancellate',
|
'%s %%{row} deleted': '%s righe ("record") cancellate',
|
||||||
'%s %%{row} updated': '%s righe ("record") modificate',
|
'%s %%{row} updated': '%s righe ("record") modificate',
|
||||||
'%s selected': '%s selezionato',
|
'%s selected': '%s selezionato',
|
||||||
@@ -16,40 +16,41 @@
|
|||||||
'=': '=',
|
'=': '=',
|
||||||
'>': '>',
|
'>': '>',
|
||||||
'>=': '>=',
|
'>=': '>=',
|
||||||
'@markmin\x01Number of entries: **%s**': 'Number of entries: **%s**',
|
'@markmin\x01Number of entries: **%s**': 'Numero di entità: **%s**',
|
||||||
'About': 'About',
|
'About': 'About',
|
||||||
'Access Control': 'Access Control',
|
'Access Control': 'Controllo Accessi',
|
||||||
'Add': 'Add',
|
'Add': 'Aggiungi',
|
||||||
'Administrative Interface': 'Administrative Interface',
|
'Administrative Interface': 'Interfaccia Amministrativa',
|
||||||
'Administrative interface': 'Interfaccia amministrativa',
|
'Administrative interface': 'Interfaccia amministrativa',
|
||||||
'Ajax Recipes': 'Ajax Recipes',
|
'Ajax Recipes': 'Ajax Recipes',
|
||||||
'And': 'And',
|
'An error occured, please %s the page': "E' stato rilevato un errore, prego %s la pagina",
|
||||||
|
'And': 'E',
|
||||||
'appadmin is disabled because insecure channel': 'Amministrazione (appadmin) disabilitata: comunicazione non sicura',
|
'appadmin is disabled because insecure channel': 'Amministrazione (appadmin) disabilitata: comunicazione non sicura',
|
||||||
'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?',
|
'Are you sure you want to delete this object?': 'Sicuro di voler cancellare questo oggetto ?',
|
||||||
'Available Databases and Tables': 'Database e tabelle disponibili',
|
'Available Databases and Tables': 'Database e tabelle disponibili',
|
||||||
'Back': 'Back',
|
'Back': 'Indietro',
|
||||||
'Buy this book': 'Buy this book',
|
'Buy this book': 'Compra questo libro',
|
||||||
'cache': 'cache',
|
'cache': 'cache',
|
||||||
'Cache': 'Cache',
|
'Cache': 'Cache',
|
||||||
'Cache Keys': 'Cache Keys',
|
'Cache Keys': 'Cache Keys',
|
||||||
'Cannot be empty': 'Non può essere vuoto',
|
'Cannot be empty': 'Non può essere vuoto',
|
||||||
'Change password': 'Change password',
|
'Change password': 'Cambia Password',
|
||||||
'change password': 'Cambia password',
|
'change password': 'Cambia password',
|
||||||
'Check to delete': 'Seleziona per cancellare',
|
'Check to delete': 'Seleziona per cancellare',
|
||||||
'Clear': 'Clear',
|
'Clear': 'Resetta',
|
||||||
'Clear CACHE?': 'Clear CACHE?',
|
'Clear CACHE?': 'Resetta CACHE?',
|
||||||
'Clear DISK': 'Clear DISK',
|
'Clear DISK': 'Resetta DISK',
|
||||||
'Clear RAM': 'Clear RAM',
|
'Clear RAM': 'Resetta RAM',
|
||||||
'Client IP': 'Client IP',
|
'Client IP': 'Client IP',
|
||||||
'Close': 'Close',
|
'Close': 'Chiudi',
|
||||||
'Cognome': 'Cognome',
|
'Cognome': 'Cognome',
|
||||||
'Community': 'Community',
|
'Community': 'Community',
|
||||||
'Components and Plugins': 'Components and Plugins',
|
'Components and Plugins': 'Componenti and Plugin',
|
||||||
'contains': 'contains',
|
'contains': 'contiene',
|
||||||
'Controller': 'Controller',
|
'Controller': 'Controller',
|
||||||
'Copyright': 'Copyright',
|
'Copyright': 'Copyright',
|
||||||
'Created By': 'Created By',
|
'Created By': 'Creato Da',
|
||||||
'Created On': 'Created On',
|
'Created On': 'Creato Il',
|
||||||
'CSV': 'CSV',
|
'CSV': 'CSV',
|
||||||
'CSV (hidden cols)': 'CSV (hidden cols)',
|
'CSV (hidden cols)': 'CSV (hidden cols)',
|
||||||
'Current request': 'Richiesta (request) corrente',
|
'Current request': 'Richiesta (request) corrente',
|
||||||
@@ -61,7 +62,7 @@
|
|||||||
'Database %s select': 'Database %s select',
|
'Database %s select': 'Database %s select',
|
||||||
'db': 'db',
|
'db': 'db',
|
||||||
'DB Model': 'Modello di DB',
|
'DB Model': 'Modello di DB',
|
||||||
'Delete': 'Delete',
|
'Delete': 'Cancella',
|
||||||
'Delete:': 'Cancella:',
|
'Delete:': 'Cancella:',
|
||||||
'Demo': 'Demo',
|
'Demo': 'Demo',
|
||||||
'Deployment Recipes': 'Deployment Recipes',
|
'Deployment Recipes': 'Deployment Recipes',
|
||||||
@@ -71,7 +72,7 @@
|
|||||||
'Disk Cache Keys': 'Disk Cache Keys',
|
'Disk Cache Keys': 'Disk Cache Keys',
|
||||||
'Disk Cleared': 'Disk Cleared',
|
'Disk Cleared': 'Disk Cleared',
|
||||||
'Documentation': 'Documentazione',
|
'Documentation': 'Documentazione',
|
||||||
"Don't know what to do?": "Don't know what to do?",
|
"Don't know what to do?": 'Non sai cosa fare?',
|
||||||
'done!': 'fatto!',
|
'done!': 'fatto!',
|
||||||
'Download': 'Download',
|
'Download': 'Download',
|
||||||
'E-mail': 'E-mail',
|
'E-mail': 'E-mail',
|
||||||
@@ -79,18 +80,19 @@
|
|||||||
'Edit current record': 'Modifica record corrente',
|
'Edit current record': 'Modifica record corrente',
|
||||||
'edit profile': 'modifica profilo',
|
'edit profile': 'modifica profilo',
|
||||||
'Edit This App': 'Modifica questa applicazione',
|
'Edit This App': 'Modifica questa applicazione',
|
||||||
'Email and SMS': 'Email and SMS',
|
'Email and SMS': 'Email e SMS',
|
||||||
'Email non valida': 'Email non valida',
|
'Email non valida': 'Email non valida',
|
||||||
'enter an integer between %(min)g and %(max)g': 'enter an integer between %(min)g and %(max)g',
|
'enter an integer between %(min)g and %(max)g': 'inserisci un intero tra %(min)g e %(max)g',
|
||||||
'Errors': 'Errors',
|
'Errors': 'Errori',
|
||||||
'Errors in form, please check it out.': 'Errors in form, please check it out.',
|
'Errors in form, please check it out.': 'Errori nel form, ricontrollalo',
|
||||||
'export as csv file': 'esporta come file CSV',
|
'export as csv file': 'esporta come file CSV',
|
||||||
'Export:': 'Export:',
|
'Export:': 'Esporta:',
|
||||||
'FAQ': 'FAQ',
|
'FAQ': 'FAQ',
|
||||||
'First name': 'Nome',
|
'First name': 'Nome',
|
||||||
'Forgot username?': 'Forgot username?',
|
'Forgot username?': 'Dimenticato lo username?',
|
||||||
'Forms and Validators': 'Forms and Validators',
|
'Forms and Validators': 'Forms and Validators',
|
||||||
'Free Applications': 'Free Applications',
|
'Free Applications': 'Free Applications',
|
||||||
|
'Graph Model': 'Graph Model',
|
||||||
'Group %(group_id)s created': 'Group %(group_id)s created',
|
'Group %(group_id)s created': 'Group %(group_id)s created',
|
||||||
'Group ID': 'ID Gruppo',
|
'Group ID': 'ID Gruppo',
|
||||||
'Group uniquely assigned to user %(id)s': 'Group uniquely assigned to user %(id)s',
|
'Group uniquely assigned to user %(id)s': 'Group uniquely assigned to user %(id)s',
|
||||||
@@ -100,69 +102,70 @@
|
|||||||
'Hello World': 'Salve Mondo',
|
'Hello World': 'Salve Mondo',
|
||||||
'Hello World in a flash!': 'Salve Mondo in un flash!',
|
'Hello World in a flash!': 'Salve Mondo in un flash!',
|
||||||
'Home': 'Home',
|
'Home': 'Home',
|
||||||
'How did you get here?': 'How did you get here?',
|
'How did you get here?': 'Come sei arrivato qui?',
|
||||||
'HTML': 'HTML',
|
'HTML': 'HTML',
|
||||||
'import': 'import',
|
'import': 'importa',
|
||||||
'Import/Export': 'Importa/Esporta',
|
'Import/Export': 'Importa/Esporta',
|
||||||
'Index': 'Indice',
|
'Index': 'Indice',
|
||||||
'insert new': 'inserisci nuovo',
|
'insert new': 'inserisci nuovo',
|
||||||
'insert new %s': 'inserisci nuovo %s',
|
'insert new %s': 'inserisci nuovo %s',
|
||||||
'Internal State': 'Stato interno',
|
'Internal State': 'Stato interno',
|
||||||
'Introduction': 'Introduction',
|
'Introduction': 'Introduzione',
|
||||||
'Invalid email': 'Email non valida',
|
'Invalid email': 'Email non valida',
|
||||||
'Invalid login': 'Invalid login',
|
'Invalid login': 'Login non valido',
|
||||||
'Invalid Query': 'Richiesta (query) non valida',
|
'Invalid Query': 'Richiesta (query) non valida',
|
||||||
'invalid request': 'richiesta non valida',
|
'invalid request': 'richiesta non valida',
|
||||||
'Is Active': 'Is Active',
|
'Is Active': "E' attivo",
|
||||||
'Key': 'Key',
|
'Key': 'Chiave',
|
||||||
'Last name': 'Cognome',
|
'Last name': 'Cognome',
|
||||||
'Layout': 'Layout',
|
'Layout': 'Layout',
|
||||||
'Layout Plugins': 'Layout Plugins',
|
'Layout Plugins': 'Layout Plugins',
|
||||||
'Layouts': 'Layouts',
|
'Layouts': 'Layouts',
|
||||||
'Live Chat': 'Live Chat',
|
'Live Chat': 'Live Chat',
|
||||||
'Logged in': 'Logged in',
|
'Logged in': 'Loggato',
|
||||||
'Logged out': 'Logged out',
|
'Logged out': 'Disconnesso',
|
||||||
'login': 'accesso',
|
'login': 'accesso',
|
||||||
'Login': 'Login',
|
'Login': 'Login',
|
||||||
'logout': 'uscita',
|
'logout': 'uscita',
|
||||||
'Logout': 'Logout',
|
'Logout': 'Logout',
|
||||||
'Lost Password': 'Lost Password',
|
'Lost Password': 'Password Smarrita',
|
||||||
'Lost password?': 'Lost password?',
|
'Lost password?': 'Password smarrita?',
|
||||||
'lost password?': 'dimenticato la password?',
|
'lost password?': 'dimenticato la password?',
|
||||||
'Main Menu': 'Menu principale',
|
'Main Menu': 'Menu principale',
|
||||||
'Manage Cache': 'Manage Cache',
|
'Manage Cache': 'Manage Cache',
|
||||||
'Menu Model': 'Menu Modelli',
|
'Menu Model': 'Menu Modelli',
|
||||||
'Modified By': 'Modified By',
|
'Modified By': 'Modificato da',
|
||||||
'Modified On': 'Modified On',
|
'Modified On': 'Modificato il',
|
||||||
'My Sites': 'My Sites',
|
'My Sites': 'My Sites',
|
||||||
'Name': 'Nome',
|
'Name': 'Nome',
|
||||||
'New': 'New',
|
'New': 'Nuovo',
|
||||||
'New password': 'New password',
|
'New password': 'Nuova password',
|
||||||
'New Record': 'Nuovo elemento (record)',
|
'New Record': 'Nuovo elemento (record)',
|
||||||
'new record inserted': 'nuovo record inserito',
|
'new record inserted': 'nuovo record inserito',
|
||||||
'next 100 rows': 'prossime 100 righe',
|
'next 100 rows': 'prossime 100 righe',
|
||||||
'No databases in this application': 'Nessun database presente in questa applicazione',
|
'No databases in this application': 'Nessun database presente in questa applicazione',
|
||||||
'No records found': 'No records found',
|
'No records found': 'Nessun record trovato',
|
||||||
'Nome': 'Nome',
|
'Nome': 'Nome',
|
||||||
'Non può essere vuoto': 'Non può essere vuoto',
|
'Non può essere vuoto': 'Non può essere vuoto',
|
||||||
'not authorized': 'non autorizzato',
|
'not authorized': 'non autorizzato',
|
||||||
'Object or table name': 'Object or table name',
|
'Object or table name': 'Oggeto o nome tabella',
|
||||||
'Old password': 'Old password',
|
'Old password': 'Vecchia password',
|
||||||
'Online examples': 'Vedere gli esempi',
|
'Online examples': 'Vedere gli esempi',
|
||||||
'Or': 'Or',
|
'Or': 'O',
|
||||||
'or import from csv file': 'oppure importa da file CSV',
|
'or import from csv file': 'oppure importa da file CSV',
|
||||||
'Origin': 'Origine',
|
'Origin': 'Origine',
|
||||||
'Other Plugins': 'Other Plugins',
|
'Other Plugins': 'Other Plugins',
|
||||||
'Other Recipes': 'Other Recipes',
|
'Other Recipes': 'Other Recipes',
|
||||||
'Overview': 'Overview',
|
'Overview': 'Overview',
|
||||||
'Password': 'Password',
|
'Password': 'Password',
|
||||||
"Password fields don't match": "Password fields don't match",
|
"Password fields don't match": 'I campi password non sono uguali',
|
||||||
'please input your password again': 'please input your password again',
|
'please input your password again': 'perfavore reimmeti la tua password',
|
||||||
'Plugins': 'Plugins',
|
'Plugins': 'Plugins',
|
||||||
'Powered by': 'Powered by',
|
'Powered by': 'Powered by',
|
||||||
'Preface': 'Preface',
|
'Preface': 'Preface',
|
||||||
'previous 100 rows': '100 righe precedenti',
|
'previous 100 rows': '100 righe precedenti',
|
||||||
'Profile': 'Profile',
|
'Profile': 'Profilo',
|
||||||
|
'pygraphviz library not found': 'pygraphviz library not found',
|
||||||
'Python': 'Python',
|
'Python': 'Python',
|
||||||
'Query:': 'Richiesta (query):',
|
'Query:': 'Richiesta (query):',
|
||||||
'Quick Examples': 'Quick Examples',
|
'Quick Examples': 'Quick Examples',
|
||||||
@@ -174,28 +177,30 @@
|
|||||||
'record does not exist': 'il record non esiste',
|
'record does not exist': 'il record non esiste',
|
||||||
'Record ID': 'Record ID',
|
'Record ID': 'Record ID',
|
||||||
'Record id': 'Record id',
|
'Record id': 'Record id',
|
||||||
'Register': 'Register',
|
'Register': 'Registrati',
|
||||||
'register': 'registrazione',
|
'register': 'registrazione',
|
||||||
'Registration identifier': 'Registration identifier',
|
'Registration identifier': 'Registration identifier',
|
||||||
'Registration key': 'Chiave di Registazione',
|
'Registration key': 'Chiave di Registazione',
|
||||||
'Registration successful': 'Registration successful',
|
'Registration successful': 'Registrazione avvenuta',
|
||||||
'Remember me (for 30 days)': 'Remember me (for 30 days)',
|
'reload': 'reload',
|
||||||
'Request reset password': 'Request reset password',
|
'Remember me (for 30 days)': 'Ricordami (per 30 giorni)',
|
||||||
|
'Request reset password': 'Richiedi il reset della password',
|
||||||
'Reset Password key': 'Resetta chiave Password ',
|
'Reset Password key': 'Resetta chiave Password ',
|
||||||
'Role': 'Ruolo',
|
'Role': 'Ruolo',
|
||||||
'Rows in Table': 'Righe nella tabella',
|
'Rows in Table': 'Righe nella tabella',
|
||||||
'Rows selected': 'Righe selezionate',
|
'Rows selected': 'Righe selezionate',
|
||||||
'Save profile': 'Save profile',
|
'Save model as...': 'Salva modello come...',
|
||||||
'Search': 'Search',
|
'Save profile': 'Salva profilo',
|
||||||
|
'Search': 'Ricerca',
|
||||||
'Semantic': 'Semantic',
|
'Semantic': 'Semantic',
|
||||||
'Services': 'Services',
|
'Services': 'Servizi',
|
||||||
'Size of cache:': 'Size of cache:',
|
'Size of cache:': 'Size of cache:',
|
||||||
'starts with': 'starts with',
|
'starts with': 'comincia con',
|
||||||
'state': 'stato',
|
'state': 'stato',
|
||||||
'Statistics': 'Statistics',
|
'Statistics': 'Statistics',
|
||||||
'Stylesheet': 'Foglio di stile (stylesheet)',
|
'Stylesheet': 'Foglio di stile (stylesheet)',
|
||||||
'submit': 'submit',
|
'submit': 'Inviai',
|
||||||
'Submit': 'Submit',
|
'Submit': 'Invia',
|
||||||
'Support': 'Support',
|
'Support': 'Support',
|
||||||
'Sure you want to delete this object?': 'Vuoi veramente cancellare questo oggetto?',
|
'Sure you want to delete this object?': 'Vuoi veramente cancellare questo oggetto?',
|
||||||
'Table': 'tabella',
|
'Table': 'tabella',
|
||||||
@@ -208,12 +213,13 @@
|
|||||||
'This is a copy of the scaffolding application': "Questa è una copia dell'applicazione di base (scaffold)",
|
'This is a copy of the scaffolding application': "Questa è una copia dell'applicazione di base (scaffold)",
|
||||||
'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)',
|
'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)',
|
||||||
'Timestamp': 'Ora (timestamp)',
|
'Timestamp': 'Ora (timestamp)',
|
||||||
'too short': 'too short',
|
'too short': 'troppo corto',
|
||||||
'TSV (Excel compatible)': 'TSV (Excel compatible)',
|
'Traceback': 'Traceback',
|
||||||
'TSV (Excel compatible, hidden cols)': 'TSV (Excel compatible, hidden cols)',
|
'TSV (Excel compatible)': 'TSV (Excel compatibile)',
|
||||||
|
'TSV (Excel compatible, hidden cols)': 'TSV (Excel compatibile, hidden cols)',
|
||||||
'Twitter': 'Twitter',
|
'Twitter': 'Twitter',
|
||||||
'unable to parse csv file': 'non riesco a decodificare questo file CSV',
|
'unable to parse csv file': 'non riesco a decodificare questo file CSV',
|
||||||
'Update': 'Update',
|
'Update': 'Aggiorna',
|
||||||
'Update:': 'Aggiorna:',
|
'Update:': 'Aggiorna:',
|
||||||
'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Per costruire richieste (query) più complesse si usano (...)&(...) come "e" (AND), (...)|(...) come "o" (OR), e ~(...) come negazione (NOT).',
|
'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Per costruire richieste (query) più complesse si usano (...)&(...) come "e" (AND), (...)|(...) come "o" (OR), e ~(...) come negazione (NOT).',
|
||||||
'User %(id)s Logged-in': 'User %(id)s Logged-in',
|
'User %(id)s Logged-in': 'User %(id)s Logged-in',
|
||||||
@@ -223,14 +229,14 @@
|
|||||||
'User %(id)s Profile updated': 'User %(id)s Profile updated',
|
'User %(id)s Profile updated': 'User %(id)s Profile updated',
|
||||||
'User %(id)s Registered': 'User %(id)s Registered',
|
'User %(id)s Registered': 'User %(id)s Registered',
|
||||||
'User ID': 'ID Utente',
|
'User ID': 'ID Utente',
|
||||||
'value already in database or empty': 'value already in database or empty',
|
'value already in database or empty': 'valore già presente nel database o vuoto',
|
||||||
'Verify Password': 'Verify Password',
|
'Verify Password': 'Verifica Password',
|
||||||
'Videos': 'Videos',
|
'Videos': 'Videos',
|
||||||
'View': 'Vista',
|
'View': 'Vista',
|
||||||
'Welcome': 'Welcome',
|
'Welcome': 'Welcome',
|
||||||
'Welcome %s': 'Benvenuto %s',
|
'Welcome %s': 'Benvenuto %s',
|
||||||
'Welcome to web2py': 'Benvenuto su web2py',
|
'Welcome to web2py': 'Benvenuto su web2py',
|
||||||
'Welcome to web2py!': 'Welcome to web2py!',
|
'Welcome to web2py!': 'Benvenuto in web2py!',
|
||||||
'Which called the function %s located in the file %s': 'che ha chiamato la funzione %s presente nel file %s',
|
'Which called the function %s located in the file %s': 'che ha chiamato la funzione %s presente nel file %s',
|
||||||
'XML': 'XML',
|
'XML': 'XML',
|
||||||
'You are successfully running web2py': 'Stai eseguendo web2py con successo',
|
'You are successfully running web2py': 'Stai eseguendo web2py con successo',
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ td.w2p_fl,td.w2p_fc {padding:0;}
|
|||||||
==============================================================*/
|
==============================================================*/
|
||||||
|
|
||||||
/* because web2py handles this via js */
|
/* because web2py handles this via js */
|
||||||
|
textarea { width:90%}
|
||||||
.hidden{visibility:visible;}
|
.hidden{visibility:visible;}
|
||||||
/* right folder for bootstrap black images/icons */
|
/* right folder for bootstrap black images/icons */
|
||||||
[class^="icon-"],[class*=" icon-"]{
|
[class^="icon-"],[class*=" icon-"]{
|
||||||
|
|||||||
@@ -373,12 +373,16 @@ def check_new_version(myversion, version_URL):
|
|||||||
the most up-to-version available
|
the most up-to-version available
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
from urllib import urlopen
|
from urllib import urlopen
|
||||||
version = parse_version(urlopen(version_URL).read())
|
version = urlopen(version_URL).read()
|
||||||
except Exception:
|
pversion = parse_version(version)
|
||||||
|
pmyversion = parse_version(myversion)
|
||||||
|
except Exception,e:
|
||||||
|
import traceback
|
||||||
|
print traceback.format_exc()
|
||||||
return -1, myversion
|
return -1, myversion
|
||||||
|
|
||||||
if version > myversion:
|
if pversion[:3]+pversion[-6:] > pmyversion[:3]+pmyversion[-6:]:
|
||||||
return True, version
|
return True, version
|
||||||
else:
|
else:
|
||||||
return False, version
|
return False, version
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ import thread
|
|||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
|
import hashlib
|
||||||
|
import datetime
|
||||||
try:
|
try:
|
||||||
import settings
|
import settings
|
||||||
have_settings = True
|
have_settings = True
|
||||||
@@ -241,7 +243,7 @@ class CacheOnDisk(CacheAbstract):
|
|||||||
|
|
||||||
This is implemented as a shelve object and it is shared by multiple web2py
|
This is implemented as a shelve object and it is shared by multiple web2py
|
||||||
processes (and threads) as long as they share the same filesystem.
|
processes (and threads) as long as they share the same filesystem.
|
||||||
The file is locked wen accessed.
|
The file is locked when accessed.
|
||||||
|
|
||||||
Disk cache provides persistance when web2py is started/stopped but it slower
|
Disk cache provides persistance when web2py is started/stopped but it slower
|
||||||
than `CacheInRam`
|
than `CacheInRam`
|
||||||
@@ -376,7 +378,6 @@ class CacheOnDisk(CacheAbstract):
|
|||||||
self._close_shelve_and_unlock()
|
self._close_shelve_and_unlock()
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
class CacheAction(object):
|
class CacheAction(object):
|
||||||
def __init__(self, func, key, time_expire, cache, cache_model):
|
def __init__(self, func, key, time_expire, cache, cache_model):
|
||||||
self.__name__ = func.__name__
|
self.__name__ = func.__name__
|
||||||
@@ -436,6 +437,89 @@ class Cache(object):
|
|||||||
# been accounted for
|
# been accounted for
|
||||||
logger.warning('no cache.disk (AttributeError)')
|
logger.warning('no cache.disk (AttributeError)')
|
||||||
|
|
||||||
|
def client(self, time_expire=DEFAULT_TIME_EXPIRE, cache_model=None,
|
||||||
|
prefix=None, session=False, vars=True, lang=True,
|
||||||
|
user_agent=False, public=True, valid_statuses=None,
|
||||||
|
quick=None):
|
||||||
|
"""
|
||||||
|
Experimental!
|
||||||
|
Currently only HTTP 1.1 compliant
|
||||||
|
reference : http://code.google.com/p/doctype-mirror/wiki/ArticleHttpCaching
|
||||||
|
time_expire: same as @cache
|
||||||
|
cache_model: same as @cache
|
||||||
|
prefix: add a prefix to the calculated key
|
||||||
|
session: adds response.session_id to the key
|
||||||
|
vars: adds request.env.query_string
|
||||||
|
lang: adds T.accepted_language
|
||||||
|
user_agent: if True, adds is_mobile and is_tablet to the key.
|
||||||
|
Pass a dict to use all the needed values (uses str(.items())) (e.g. user_agent=request.user_agent())
|
||||||
|
used only if session is not True
|
||||||
|
public: if False forces the Cache-Control to be 'private'
|
||||||
|
valid_statuses: by default only status codes starting with 1,2,3 will be cached.
|
||||||
|
pass an explicit list of statuses on which turn the cache on
|
||||||
|
quick: Session,Vars,Lang,User-agent,Public,duration:
|
||||||
|
fast overrides with initial strings, e.g. 'SVLP' or 'VLP', or 'VLP'
|
||||||
|
"""
|
||||||
|
from gluon import current
|
||||||
|
def wrap(func):
|
||||||
|
def wrapped_f():
|
||||||
|
if current.request.env.request_method == 'GET':
|
||||||
|
if time_expire:
|
||||||
|
cache_control = 'max-age=%(time_expire)s, s-maxage=%(time_expire)s' % dict(time_expire=time_expire)
|
||||||
|
if quick:
|
||||||
|
session_ = True if 'S' in quick else False
|
||||||
|
vars_ = True if 'V' in quick else False
|
||||||
|
lang_ = True if 'L' in quick else False
|
||||||
|
user_agent_ = True if 'U' in quick else False
|
||||||
|
public_ = True if 'P' in quick else False
|
||||||
|
else:
|
||||||
|
session_, vars_, lang_, user_agent_, public_ = session, vars, lang, user_agent, public
|
||||||
|
if not session_ and public_:
|
||||||
|
cache_control += ', public'
|
||||||
|
expires = (current.request.utcnow + datetime.timedelta(seconds=time_expire)).strftime('%a, %d %b %Y %H:%M:%S GMT')
|
||||||
|
vary = None
|
||||||
|
else:
|
||||||
|
cache_control += ', private'
|
||||||
|
expires = 'Fri, 01 Jan 1990 00:00:00 GMT'
|
||||||
|
if cache_model:
|
||||||
|
cache_key = [current.request.env.path_info, current.response.view]
|
||||||
|
if session_:
|
||||||
|
cache_key.append(current.response.session_id)
|
||||||
|
elif user_agent_:
|
||||||
|
if user_agent_ is True:
|
||||||
|
cache_key.append("%(is_mobile)s_%(is_tablet)s" % current.request.user_agent())
|
||||||
|
else:
|
||||||
|
cache_key.append(str(user_agent_.items()))
|
||||||
|
if vars_:
|
||||||
|
cache_key.append(current.request.env.query_string)
|
||||||
|
if lang_:
|
||||||
|
cache_key.append(current.T.accepted_language)
|
||||||
|
cache_key = hashlib.md5('__'.join(cache_key)).hexdigest()
|
||||||
|
if prefix:
|
||||||
|
cache_key = prefix + cache_key
|
||||||
|
rtn = cache_model(cache_key, lambda : func(), time_expire=time_expire)
|
||||||
|
else:
|
||||||
|
rtn = func()
|
||||||
|
send_headers = False
|
||||||
|
if isinstance(valid_statuses, list):
|
||||||
|
if current.response.status in valid_statuses:
|
||||||
|
send_headers = True
|
||||||
|
elif valid_statuses is None:
|
||||||
|
if str(current.response.status)[0] in '123':
|
||||||
|
send_headers = True
|
||||||
|
if send_headers:
|
||||||
|
current.response.headers['Pragma'] = None
|
||||||
|
current.response.headers['Expires'] = expires
|
||||||
|
current.response.headers['Cache-Control'] = cache_control
|
||||||
|
if cache_model and not send_headers:
|
||||||
|
cache_model.clear(cache_key)
|
||||||
|
return rtn
|
||||||
|
return func()
|
||||||
|
wrapped_f.__name__ = func.__name__
|
||||||
|
wrapped_f.__doc__ = func.__doc__
|
||||||
|
return wrapped_f
|
||||||
|
return wrap
|
||||||
|
|
||||||
def __call__(self,
|
def __call__(self,
|
||||||
key=None,
|
key=None,
|
||||||
time_expire=DEFAULT_TIME_EXPIRE,
|
time_expire=DEFAULT_TIME_EXPIRE,
|
||||||
@@ -469,7 +553,7 @@ class Cache(object):
|
|||||||
refresh.
|
refresh.
|
||||||
|
|
||||||
If the function `f` is an action, we suggest using
|
If the function `f` is an action, we suggest using
|
||||||
`request.env.path_info` as key.
|
@cache.client instead
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def tmp(func, cache=self, cache_model=cache_model):
|
def tmp(func, cache=self, cache_model=cache_model):
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ def set_global(var, val):
|
|||||||
|
|
||||||
class FPDF(object):
|
class FPDF(object):
|
||||||
"PDF Generation class"
|
"PDF Generation class"
|
||||||
|
|
||||||
def __init__(self, orientation='P',unit='mm',format='A4'):
|
def __init__(self, orientation='P',unit='mm',format='A4'):
|
||||||
# Some checks
|
# Some checks
|
||||||
self._dochecks()
|
self._dochecks()
|
||||||
@@ -356,7 +356,7 @@ class FPDF(object):
|
|||||||
elif (self.current_font['desc']['MissingWidth']) :
|
elif (self.current_font['desc']['MissingWidth']) :
|
||||||
w += self.current_font['desc']['MissingWidth']
|
w += self.current_font['desc']['MissingWidth']
|
||||||
#elif (isset($this->CurrentFont['MissingWidth'])) { $w += $this->CurrentFont['MissingWidth']; }
|
#elif (isset($this->CurrentFont['MissingWidth'])) { $w += $this->CurrentFont['MissingWidth']; }
|
||||||
else:
|
else:
|
||||||
w += 500
|
w += 500
|
||||||
else:
|
else:
|
||||||
for i in xrange(0, l):
|
for i in xrange(0, l):
|
||||||
@@ -373,6 +373,21 @@ class FPDF(object):
|
|||||||
"Draw a line"
|
"Draw a line"
|
||||||
self._out(sprintf('%.2f %.2f m %.2f %.2f l S',x1*self.k,(self.h-y1)*self.k,x2*self.k,(self.h-y2)*self.k))
|
self._out(sprintf('%.2f %.2f m %.2f %.2f l S',x1*self.k,(self.h-y1)*self.k,x2*self.k,(self.h-y2)*self.k))
|
||||||
|
|
||||||
|
def _set_dash(self, dash_length=False, space_length=False):
|
||||||
|
if(dash_length and space_length):
|
||||||
|
s = sprintf('[%.3f %.3f] 0 d', dash_length*self.k, space_length*self.k)
|
||||||
|
else:
|
||||||
|
s = '[] 0 d'
|
||||||
|
self._out(s)
|
||||||
|
|
||||||
|
def dashed_line(self, x1,y1,x2,y2, dash_length=1, space_length=1):
|
||||||
|
"""Draw a dashed line. Same interface as line() except:
|
||||||
|
- dash_length: Length of the dash
|
||||||
|
- space_length: Length of the space between dashes"""
|
||||||
|
self._set_dash(dash_length, space_length)
|
||||||
|
self.line(x1, y1, x2, y2)
|
||||||
|
self._set_dash()
|
||||||
|
|
||||||
def rect(self, x,y,w,h,style=''):
|
def rect(self, x,y,w,h,style=''):
|
||||||
"Draw a rectangle"
|
"Draw a rectangle"
|
||||||
if(style=='F'):
|
if(style=='F'):
|
||||||
@@ -401,10 +416,10 @@ class FPDF(object):
|
|||||||
global SYSTEM_TTFONTS
|
global SYSTEM_TTFONTS
|
||||||
if os.path.exists(fname):
|
if os.path.exists(fname):
|
||||||
ttffilename = fname
|
ttffilename = fname
|
||||||
elif (FPDF_FONT_DIR and
|
elif (FPDF_FONT_DIR and
|
||||||
os.path.exists(os.path.join(FPDF_FONT_DIR, fname))):
|
os.path.exists(os.path.join(FPDF_FONT_DIR, fname))):
|
||||||
ttffilename = os.path.join(FPDF_FONT_DIR, fname)
|
ttffilename = os.path.join(FPDF_FONT_DIR, fname)
|
||||||
elif (SYSTEM_TTFONTS and
|
elif (SYSTEM_TTFONTS and
|
||||||
os.path.exists(os.path.join(SYSTEM_TTFONTS, fname))):
|
os.path.exists(os.path.join(SYSTEM_TTFONTS, fname))):
|
||||||
ttffilename = os.path.join(SYSTEM_TTFONTS, fname)
|
ttffilename = os.path.join(SYSTEM_TTFONTS, fname)
|
||||||
else:
|
else:
|
||||||
@@ -450,7 +465,7 @@ class FPDF(object):
|
|||||||
fh = open(unifilename, "w")
|
fh = open(unifilename, "w")
|
||||||
pickle.dump(font_dict, fh)
|
pickle.dump(font_dict, fh)
|
||||||
fh.close()
|
fh.close()
|
||||||
except IOError as e:
|
except IOError, e:
|
||||||
if not e.errno == errno.EACCES:
|
if not e.errno == errno.EACCES:
|
||||||
raise # Not a permission error.
|
raise # Not a permission error.
|
||||||
del ttf
|
del ttf
|
||||||
@@ -459,11 +474,11 @@ class FPDF(object):
|
|||||||
else:
|
else:
|
||||||
sbarr = range(0,32)
|
sbarr = range(0,32)
|
||||||
self.fonts[fontkey] = {
|
self.fonts[fontkey] = {
|
||||||
'i': len(self.fonts)+1, 'type': font_dict['type'],
|
'i': len(self.fonts)+1, 'type': font_dict['type'],
|
||||||
'name': font_dict['name'], 'desc': font_dict['desc'],
|
'name': font_dict['name'], 'desc': font_dict['desc'],
|
||||||
'up': font_dict['up'], 'ut': font_dict['ut'],
|
'up': font_dict['up'], 'ut': font_dict['ut'],
|
||||||
'cw': font_dict['cw'],
|
'cw': font_dict['cw'],
|
||||||
'ttffile': font_dict['ttffile'], 'fontkey': fontkey,
|
'ttffile': font_dict['ttffile'], 'fontkey': fontkey,
|
||||||
'subset': sbarr, 'unifilename': unifilename,
|
'subset': sbarr, 'unifilename': unifilename,
|
||||||
}
|
}
|
||||||
self.font_files[fontkey] = {'length1': font_dict['originalsize'],
|
self.font_files[fontkey] = {'length1': font_dict['originalsize'],
|
||||||
@@ -494,7 +509,7 @@ class FPDF(object):
|
|||||||
if (type == 'TrueType'):
|
if (type == 'TrueType'):
|
||||||
self.font_files[filename]={'length1': originalsize}
|
self.font_files[filename]={'length1': originalsize}
|
||||||
else:
|
else:
|
||||||
self.font_files[filename]={'length1': size1,
|
self.font_files[filename]={'length1': size1,
|
||||||
'length2': size2}
|
'length2': size2}
|
||||||
|
|
||||||
def set_font(self, family,style='',size=0):
|
def set_font(self, family,style='',size=0):
|
||||||
@@ -660,7 +675,7 @@ class FPDF(object):
|
|||||||
dx=self.c_margin
|
dx=self.c_margin
|
||||||
if(self.color_flag):
|
if(self.color_flag):
|
||||||
s+='q '+self.text_color+' '
|
s+='q '+self.text_color+' '
|
||||||
|
|
||||||
# If multibyte, Tw has no effect - do word spacing using an adjustment before each space
|
# If multibyte, Tw has no effect - do word spacing using an adjustment before each space
|
||||||
if (self.ws and self.unifontsubset):
|
if (self.ws and self.unifontsubset):
|
||||||
for uni in UTF8StringToArray(txt):
|
for uni in UTF8StringToArray(txt):
|
||||||
@@ -686,7 +701,7 @@ class FPDF(object):
|
|||||||
else:
|
else:
|
||||||
txt2 = self._escape(txt)
|
txt2 = self._escape(txt)
|
||||||
s += sprintf('BT %.2f %.2f Td (%s) Tj ET',(self.x+dx)*k,(self.h-(self.y+.5*h+.3*self.font_size))*k,txt2)
|
s += sprintf('BT %.2f %.2f Td (%s) Tj ET',(self.x+dx)*k,(self.h-(self.y+.5*h+.3*self.font_size))*k,txt2)
|
||||||
|
|
||||||
if(self.underline):
|
if(self.underline):
|
||||||
s+=' '+self._dounderline(self.x+dx,self.y+.5*h+.3*self.font_size,txt)
|
s+=' '+self._dounderline(self.x+dx,self.y+.5*h+.3*self.font_size,txt)
|
||||||
if(self.color_flag):
|
if(self.color_flag):
|
||||||
@@ -764,7 +779,7 @@ class FPDF(object):
|
|||||||
sep=i
|
sep=i
|
||||||
ls=l
|
ls=l
|
||||||
ns+=1
|
ns+=1
|
||||||
if self.unifontsubset:
|
if self.unifontsubset:
|
||||||
l += self.get_string_width(c) / self.font_size*1000.0
|
l += self.get_string_width(c) / self.font_size*1000.0
|
||||||
else:
|
else:
|
||||||
l += cw.get(c,0)
|
l += cw.get(c,0)
|
||||||
@@ -848,7 +863,7 @@ class FPDF(object):
|
|||||||
continue
|
continue
|
||||||
if(c==' '):
|
if(c==' '):
|
||||||
sep=i
|
sep=i
|
||||||
if self.unifontsubset:
|
if self.unifontsubset:
|
||||||
l += self.get_string_width(c) / self.font_size*1000.0
|
l += self.get_string_width(c) / self.font_size*1000.0
|
||||||
else:
|
else:
|
||||||
l += cw.get(c,0)
|
l += cw.get(c,0)
|
||||||
@@ -900,6 +915,24 @@ class FPDF(object):
|
|||||||
info=self._parsepng(name)
|
info=self._parsepng(name)
|
||||||
else:
|
else:
|
||||||
#Allow for additional formats
|
#Allow for additional formats
|
||||||
|
#maybe the image is not showing the correct extension,
|
||||||
|
#but the header is OK,
|
||||||
|
succeed_parsing = False
|
||||||
|
#try all the parsing functions
|
||||||
|
parsing_functions = [self._parsejpg,self._parsepng,self._parsegif]
|
||||||
|
for pf in parsing_functions:
|
||||||
|
try:
|
||||||
|
info = pf(name)
|
||||||
|
succeed_parsing = True
|
||||||
|
break;
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
#last resource
|
||||||
|
if not succeed_parsing:
|
||||||
|
mtd='_parse'+type
|
||||||
|
if not hasattr(self,mtd):
|
||||||
|
self.error('Unsupported image type: '+type)
|
||||||
|
info=getattr(self, mtd)(name)
|
||||||
mtd='_parse'+type
|
mtd='_parse'+type
|
||||||
if not hasattr(self,mtd):
|
if not hasattr(self,mtd):
|
||||||
self.error('Unsupported image type: '+type)
|
self.error('Unsupported image type: '+type)
|
||||||
@@ -1202,7 +1235,7 @@ class FPDF(object):
|
|||||||
self._out('<</Type /Font');
|
self._out('<</Type /Font');
|
||||||
self._out('/Subtype /Type0');
|
self._out('/Subtype /Type0');
|
||||||
self._out('/BaseFont /' + fontname + '');
|
self._out('/BaseFont /' + fontname + '');
|
||||||
self._out('/Encoding /Identity-H');
|
self._out('/Encoding /Identity-H');
|
||||||
self._out('/DescendantFonts [' + str(self.n + 1) + ' 0 R]')
|
self._out('/DescendantFonts [' + str(self.n + 1) + ' 0 R]')
|
||||||
self._out('/ToUnicode ' + str(self.n + 2) + ' 0 R')
|
self._out('/ToUnicode ' + str(self.n + 2) + ' 0 R')
|
||||||
self._out('>>')
|
self._out('>>')
|
||||||
@@ -1264,7 +1297,7 @@ class FPDF(object):
|
|||||||
for kd in ('Ascent', 'Descent', 'CapHeight', 'Flags', 'FontBBox', 'ItalicAngle', 'StemV', 'MissingWidth'):
|
for kd in ('Ascent', 'Descent', 'CapHeight', 'Flags', 'FontBBox', 'ItalicAngle', 'StemV', 'MissingWidth'):
|
||||||
v = font['desc'][kd]
|
v = font['desc'][kd]
|
||||||
if (kd == 'Flags'):
|
if (kd == 'Flags'):
|
||||||
v = v | 4;
|
v = v | 4;
|
||||||
v = v & ~32; # SYMBOLIC font flag
|
v = v & ~32; # SYMBOLIC font flag
|
||||||
self._out(' /%s %s' % (kd, v))
|
self._out(' /%s %s' % (kd, v))
|
||||||
self._out('/FontFile2 ' + str(self.n + 2) + ' 0 R')
|
self._out('/FontFile2 ' + str(self.n + 2) + ' 0 R')
|
||||||
@@ -1286,7 +1319,7 @@ class FPDF(object):
|
|||||||
self._putstream(cidtogidmap)
|
self._putstream(cidtogidmap)
|
||||||
self._out('endobj')
|
self._out('endobj')
|
||||||
|
|
||||||
#Font file
|
#Font file
|
||||||
self._newobj()
|
self._newobj()
|
||||||
self._out('<</Length ' + str(len(fontstream)))
|
self._out('<</Length ' + str(len(fontstream)))
|
||||||
self._out('/Filter /FlateDecode')
|
self._out('/Filter /FlateDecode')
|
||||||
@@ -1341,14 +1374,14 @@ class FPDF(object):
|
|||||||
font_dict['range'] = range_
|
font_dict['range'] = range_
|
||||||
pickle.dump(font_dict, fh)
|
pickle.dump(font_dict, fh)
|
||||||
fh.close()
|
fh.close()
|
||||||
except IOError as e:
|
except IOError, e:
|
||||||
if not e.errno == errno.EACCES:
|
if not e.errno == errno.EACCES:
|
||||||
raise # Not a permission error.
|
raise # Not a permission error.
|
||||||
if (font['cw'][cid] == 0):
|
if (font['cw'][cid] == 0):
|
||||||
continue
|
continue
|
||||||
width = font['cw'][cid]
|
width = font['cw'][cid]
|
||||||
if (width == 65535): width = 0
|
if (width == 65535): width = 0
|
||||||
if (cid > 255 and (cid not in font['subset']) or not cid): #
|
if (cid > 255 and (cid not in font['subset']) or not cid): #
|
||||||
continue
|
continue
|
||||||
if ('dw' not in font or (font['dw'] and width != font['dw'])):
|
if ('dw' not in font or (font['dw'] and width != font['dw'])):
|
||||||
if (cid == (prevcid + 1)):
|
if (cid == (prevcid + 1)):
|
||||||
@@ -1400,7 +1433,7 @@ class FPDF(object):
|
|||||||
if (len(set(ws)) == 1):
|
if (len(set(ws)) == 1):
|
||||||
w.append(' %s %s %s' % (k, k + len(ws) - 1, ws[0]))
|
w.append(' %s %s %s' % (k, k + len(ws) - 1, ws[0]))
|
||||||
else:
|
else:
|
||||||
w.append(' %s [ %s ]\n' % (k, ' '.join([str(int(h)) for h in ws]))) ##
|
w.append(' %s [ %s ]\n' % (k, ' '.join([str(int(h)) for h in ws]))) ##
|
||||||
self._out('/W [%s]' % ''.join(w))
|
self._out('/W [%s]' % ''.join(w))
|
||||||
|
|
||||||
def _putimages(self):
|
def _putimages(self):
|
||||||
@@ -1412,7 +1445,7 @@ class FPDF(object):
|
|||||||
del info['data']
|
del info['data']
|
||||||
if 'smask' in info:
|
if 'smask' in info:
|
||||||
del info['smask']
|
del info['smask']
|
||||||
|
|
||||||
def _putimage(self, info):
|
def _putimage(self, info):
|
||||||
if 'data' in info:
|
if 'data' in info:
|
||||||
self._newobj()
|
self._newobj()
|
||||||
@@ -1791,20 +1824,20 @@ class FPDF(object):
|
|||||||
|
|
||||||
def interleaved2of5(self, txt, x, y, w=1.0, h=10.0):
|
def interleaved2of5(self, txt, x, y, w=1.0, h=10.0):
|
||||||
"Barcode I2of5 (numeric), adds a 0 if odd lenght"
|
"Barcode I2of5 (numeric), adds a 0 if odd lenght"
|
||||||
narrow = w / 3.0
|
narrow = w / 3.0
|
||||||
wide = w
|
wide = w
|
||||||
|
|
||||||
# wide/narrow codes for the digits
|
# wide/narrow codes for the digits
|
||||||
bar_char={'0': 'nnwwn', '1': 'wnnnw', '2': 'nwnnw', '3': 'wwnnn',
|
bar_char={'0': 'nnwwn', '1': 'wnnnw', '2': 'nwnnw', '3': 'wwnnn',
|
||||||
'4': 'nnwnw', '5': 'wnwnn', '6': 'nwwnn', '7': 'nnnww',
|
'4': 'nnwnw', '5': 'wnwnn', '6': 'nwwnn', '7': 'nnnww',
|
||||||
'8': 'wnnwn', '9': 'nwnwn', 'A': 'nn', 'Z': 'wn'}
|
'8': 'wnnwn', '9': 'nwnwn', 'A': 'nn', 'Z': 'wn'}
|
||||||
|
|
||||||
self.set_fill_color(0)
|
self.set_fill_color(0)
|
||||||
code = txt
|
code = txt
|
||||||
# add leading zero if code-length is odd
|
# add leading zero if code-length is odd
|
||||||
if len(code) % 2 != 0:
|
if len(code) % 2 != 0:
|
||||||
code = '0' + code
|
code = '0' + code
|
||||||
|
|
||||||
# add start and stop codes
|
# add start and stop codes
|
||||||
code = 'AA' + code.lower() + 'ZA'
|
code = 'AA' + code.lower() + 'ZA'
|
||||||
|
|
||||||
@@ -1843,7 +1876,7 @@ class FPDF(object):
|
|||||||
narrow = w / 3.0
|
narrow = w / 3.0
|
||||||
gap = narrow
|
gap = narrow
|
||||||
|
|
||||||
bar_char={'0': 'nnnwwnwnn', '1': 'wnnwnnnnw', '2': 'nnwwnnnnw',
|
bar_char={'0': 'nnnwwnwnn', '1': 'wnnwnnnnw', '2': 'nnwwnnnnw',
|
||||||
'3': 'wnwwnnnnn', '4': 'nnnwwnnnw', '5': 'wnnwwnnnn',
|
'3': 'wnwwnnnnn', '4': 'nnnwwnnnw', '5': 'wnnwwnnnn',
|
||||||
'6': 'nnwwwnnnn', '7': 'nnnwnnwnw', '8': 'wnnwnnwnn',
|
'6': 'nnwwwnnnn', '7': 'nnnwnnwnw', '8': 'wnnwnnwnn',
|
||||||
'9': 'nnwwnnwnn', 'A': 'wnnnnwnnw', 'B': 'nnwnnwnnw',
|
'9': 'nnwwnnwnn', 'A': 'wnnnnwnnw', 'B': 'nnwnnwnnw',
|
||||||
@@ -1860,8 +1893,8 @@ class FPDF(object):
|
|||||||
'+': 'nwnnnwnwn', '%': 'nnnwnwnwn'}
|
'+': 'nwnnnwnwn', '%': 'nnnwnwnwn'}
|
||||||
|
|
||||||
self.set_fill_color(0)
|
self.set_fill_color(0)
|
||||||
code = txt
|
code = txt
|
||||||
|
|
||||||
code = code.upper()
|
code = code.upper()
|
||||||
for i in xrange (0, len(code), 2):
|
for i in xrange (0, len(code), 2):
|
||||||
char_bar = code[i]
|
char_bar = code[i]
|
||||||
@@ -1871,7 +1904,7 @@ class FPDF(object):
|
|||||||
|
|
||||||
seq= ''
|
seq= ''
|
||||||
for s in xrange(0, len(bar_char[char_bar])):
|
for s in xrange(0, len(bar_char[char_bar])):
|
||||||
seq += bar_char[char_bar][s]
|
seq += bar_char[char_bar][s]
|
||||||
|
|
||||||
for bar in xrange(0, len(seq)):
|
for bar in xrange(0, len(seq)):
|
||||||
if seq[bar] == 'n':
|
if seq[bar] == 'n':
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ Dependencies:
|
|||||||
import oauth2 as oauth
|
import oauth2 as oauth
|
||||||
import cgi
|
import cgi
|
||||||
|
|
||||||
from urllib2 import urlopen
|
|
||||||
import urllib2
|
|
||||||
from urllib import urlencode
|
from urllib import urlencode
|
||||||
|
|
||||||
from gluon import current
|
from gluon import current
|
||||||
@@ -64,9 +62,7 @@ class OAuthAccount(object):
|
|||||||
Appends the _next action to the generated url so the flows continues.
|
Appends the _next action to the generated url so the flows continues.
|
||||||
"""
|
"""
|
||||||
r = self.request
|
r = self.request
|
||||||
http_host = r.env.http_x_forwarded_for
|
http_host = r.env.http_host
|
||||||
if not http_host:
|
|
||||||
http_host = r.env.http_host
|
|
||||||
|
|
||||||
url_scheme = r.env.wsgi_url_scheme
|
url_scheme = r.env.wsgi_url_scheme
|
||||||
if next:
|
if next:
|
||||||
|
|||||||
@@ -103,9 +103,7 @@ server for requests. It can be used for the optional"scope" parameters for Face
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
r = current.request
|
r = current.request
|
||||||
http_host = r.env.http_x_forwarded_for
|
http_host = r.env.http_host
|
||||||
if not http_host:
|
|
||||||
http_host = r.env.http_host
|
|
||||||
|
|
||||||
if r.env.https == 'on':
|
if r.env.https == 'on':
|
||||||
url_scheme = 'https'
|
url_scheme = 'https'
|
||||||
@@ -163,7 +161,7 @@ server for requests. It can be used for the optional"scope" parameters for Face
|
|||||||
open_url = None
|
open_url = None
|
||||||
opener = self.__build_url_opener(self.token_url)
|
opener = self.__build_url_opener(self.token_url)
|
||||||
try:
|
try:
|
||||||
open_url = opener.open(self.token_url, urlencode(data))
|
open_url = opener.open(self.token_url, urlencode(data), self.socket_timeout)
|
||||||
except urllib2.HTTPError, e:
|
except urllib2.HTTPError, e:
|
||||||
tmp = e.read()
|
tmp = e.read()
|
||||||
raise Exception(tmp)
|
raise Exception(tmp)
|
||||||
@@ -208,7 +206,7 @@ server for requests. It can be used for the optional"scope" parameters for Face
|
|||||||
|
|
||||||
def __init__(self, g=None,
|
def __init__(self, g=None,
|
||||||
client_id=None, client_secret=None,
|
client_id=None, client_secret=None,
|
||||||
auth_url=None, token_url=None, **args):
|
auth_url=None, token_url=None, socket_timeout=60, **args):
|
||||||
"""
|
"""
|
||||||
first argument is unused. Here only for legacy reasons.
|
first argument is unused. Here only for legacy reasons.
|
||||||
"""
|
"""
|
||||||
@@ -224,6 +222,7 @@ server for requests. It can be used for the optional"scope" parameters for Face
|
|||||||
self.auth_url = auth_url
|
self.auth_url = auth_url
|
||||||
self.token_url = token_url
|
self.token_url = token_url
|
||||||
self.args = args
|
self.args = args
|
||||||
|
self.socket_timeout = socket_timeout
|
||||||
|
|
||||||
def login_url(self, next="/"):
|
def login_url(self, next="/"):
|
||||||
self.__oauth_login(next)
|
self.__oauth_login(next)
|
||||||
|
|||||||
@@ -117,6 +117,7 @@ Supported DAL URI strings:
|
|||||||
'firebird_embedded://username:password@c://path'
|
'firebird_embedded://username:password@c://path'
|
||||||
'informix://user:password@server:3050/database'
|
'informix://user:password@server:3050/database'
|
||||||
'informixu://user:password@server:3050/database' # unicode informix
|
'informixu://user:password@server:3050/database' # unicode informix
|
||||||
|
'ingres://database' # or use an ODBC connection string, e.g. 'ingres://dsn=dsn_name'
|
||||||
'google:datastore' # for google app engine datastore
|
'google:datastore' # for google app engine datastore
|
||||||
'google:sql' # for google app engine with sql (mysql compatible)
|
'google:sql' # for google app engine with sql (mysql compatible)
|
||||||
'teradata://DSN=dsn;UID=user;PWD=pass; DATABASE=database' # experimental
|
'teradata://DSN=dsn;UID=user;PWD=pass; DATABASE=database' # experimental
|
||||||
@@ -350,8 +351,9 @@ if not 'google' in DRIVERS:
|
|||||||
DRIVERS.append('MSSQL(pyodbc)')
|
DRIVERS.append('MSSQL(pyodbc)')
|
||||||
DRIVERS.append('DB2(pyodbc)')
|
DRIVERS.append('DB2(pyodbc)')
|
||||||
DRIVERS.append('Teradata(pyodbc)')
|
DRIVERS.append('Teradata(pyodbc)')
|
||||||
|
DRIVERS.append('Ingres(pyodbc)')
|
||||||
except ImportError:
|
except ImportError:
|
||||||
LOGGER.debug('no MSSQL/DB2/Teradata driver pyodbc')
|
LOGGER.debug('no MSSQL/DB2/Teradata/Ingres driver pyodbc')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import Sybase
|
import Sybase
|
||||||
@@ -368,7 +370,7 @@ if not 'google' in DRIVERS:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
import fdb
|
import fdb
|
||||||
DRIVERS.append('Firbird(fdb)')
|
DRIVERS.append('Firebird(fdb)')
|
||||||
except ImportError:
|
except ImportError:
|
||||||
LOGGER.debug('no Firebird driver fdb')
|
LOGGER.debug('no Firebird driver fdb')
|
||||||
#####
|
#####
|
||||||
@@ -413,13 +415,6 @@ if not 'google' in DRIVERS:
|
|||||||
LOGGER.debug('no SQLite/PostgreSQL driver zxJDBC')
|
LOGGER.debug('no SQLite/PostgreSQL driver zxJDBC')
|
||||||
is_jdbc = False
|
is_jdbc = False
|
||||||
|
|
||||||
try:
|
|
||||||
import ingresdbi
|
|
||||||
DRIVERS.append('Ingres(ingresdbi)')
|
|
||||||
except ImportError:
|
|
||||||
LOGGER.debug('no Ingres driver ingresdbi')
|
|
||||||
# NOTE could try JDBC.......
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import couchdb
|
import couchdb
|
||||||
DRIVERS.append('CouchDB(couchdb)')
|
DRIVERS.append('CouchDB(couchdb)')
|
||||||
@@ -638,6 +633,7 @@ class BaseAdapter(ConnectionPool):
|
|||||||
|
|
||||||
TRUE = 'T'
|
TRUE = 'T'
|
||||||
FALSE = 'F'
|
FALSE = 'F'
|
||||||
|
T_SEP = ' '
|
||||||
types = {
|
types = {
|
||||||
'boolean': 'CHAR(1)',
|
'boolean': 'CHAR(1)',
|
||||||
'string': 'CHAR(%(length)s)',
|
'string': 'CHAR(%(length)s)',
|
||||||
@@ -1815,7 +1811,7 @@ class BaseAdapter(ConnectionPool):
|
|||||||
obj = str(obj)
|
obj = str(obj)
|
||||||
elif fieldtype == 'datetime':
|
elif fieldtype == 'datetime':
|
||||||
if isinstance(obj, datetime.datetime):
|
if isinstance(obj, datetime.datetime):
|
||||||
obj = obj.isoformat()[:19].replace('T',' ')
|
obj = obj.isoformat(self.T_SEP)[:19]
|
||||||
elif isinstance(obj, datetime.date):
|
elif isinstance(obj, datetime.date):
|
||||||
obj = obj.isoformat()[:10]+' 00:00:00'
|
obj = obj.isoformat()[:10]+' 00:00:00'
|
||||||
else:
|
else:
|
||||||
@@ -2423,6 +2419,9 @@ class MySQLAdapter(BaseAdapter):
|
|||||||
return ['SET FOREIGN_KEY_CHECKS=0;','DROP TABLE %s;' % table,
|
return ['SET FOREIGN_KEY_CHECKS=0;','DROP TABLE %s;' % table,
|
||||||
'SET FOREIGN_KEY_CHECKS=1;']
|
'SET FOREIGN_KEY_CHECKS=1;']
|
||||||
|
|
||||||
|
def _insert_empty(self, table):
|
||||||
|
return 'INSERT INTO %s VALUES (DEFAULT);' % table
|
||||||
|
|
||||||
def distributed_transaction_begin(self,key):
|
def distributed_transaction_begin(self,key):
|
||||||
self.execute('XA START;')
|
self.execute('XA START;')
|
||||||
|
|
||||||
@@ -2664,11 +2663,11 @@ class PostgreSQLAdapter(BaseAdapter):
|
|||||||
|
|
||||||
def CONTAINS(self,first,second,case_sensitive=False):
|
def CONTAINS(self,first,second,case_sensitive=False):
|
||||||
if first.type in ('string','text', 'json'):
|
if first.type in ('string','text', 'json'):
|
||||||
key = '%'+str(second).replace('%','%%')+'%'
|
second = '%'+str(second).replace('%','%%')+'%'
|
||||||
elif first.type.startswith('list:'):
|
elif first.type.startswith('list:'):
|
||||||
key = '%|'+str(second).replace('|','||').replace('%','%%')+'|%'
|
second = '%|'+str(second).replace('|','||').replace('%','%%')+'|%'
|
||||||
op = case_sensitive and self.LIKE or self.ILIKE
|
op = case_sensitive and self.LIKE or self.ILIKE
|
||||||
return op(first,key)
|
return op(first,second)
|
||||||
|
|
||||||
# GIS functions
|
# GIS functions
|
||||||
|
|
||||||
@@ -3038,6 +3037,7 @@ class OracleAdapter(BaseAdapter):
|
|||||||
|
|
||||||
class MSSQLAdapter(BaseAdapter):
|
class MSSQLAdapter(BaseAdapter):
|
||||||
drivers = ('pyodbc',)
|
drivers = ('pyodbc',)
|
||||||
|
T_SEP = 'T'
|
||||||
|
|
||||||
types = {
|
types = {
|
||||||
'boolean': 'BIT',
|
'boolean': 'BIT',
|
||||||
@@ -3455,9 +3455,9 @@ class FireBirdAdapter(BaseAdapter):
|
|||||||
|
|
||||||
def CONTAINS(self, first, second, case_sensitive=False):
|
def CONTAINS(self, first, second, case_sensitive=False):
|
||||||
if first.type in ('string','text'):
|
if first.type in ('string','text'):
|
||||||
key = str(second).replace('%','%%')
|
second = str(second).replace('%','%%')
|
||||||
elif first.type.startswith('list:'):
|
elif first.type.startswith('list:'):
|
||||||
key = '|'+str(second).replace('|','||').replace('%','%%')+'|'
|
second = '|'+str(second).replace('|','||').replace('%','%%')+'|'
|
||||||
return self.CONTAINING(first,second)
|
return self.CONTAINING(first,second)
|
||||||
|
|
||||||
def _drop(self,table,mode):
|
def _drop(self,table,mode):
|
||||||
@@ -3862,7 +3862,7 @@ INGRES_SEQNAME='ii***lineitemsequence' # NOTE invalid database object name
|
|||||||
# to be a delimited identifier)
|
# to be a delimited identifier)
|
||||||
|
|
||||||
class IngresAdapter(BaseAdapter):
|
class IngresAdapter(BaseAdapter):
|
||||||
drivers = ('ingresdbi',)
|
drivers = ('pyodbc',)
|
||||||
|
|
||||||
types = {
|
types = {
|
||||||
'boolean': 'CHAR(1)',
|
'boolean': 'CHAR(1)',
|
||||||
@@ -3913,6 +3913,7 @@ class IngresAdapter(BaseAdapter):
|
|||||||
adapter_args={}, do_connect=True, after_connection=None):
|
adapter_args={}, do_connect=True, after_connection=None):
|
||||||
self.db = db
|
self.db = db
|
||||||
self.dbengine = "ingres"
|
self.dbengine = "ingres"
|
||||||
|
self._driver = pyodbc
|
||||||
self.uri = uri
|
self.uri = uri
|
||||||
if do_connect: self.find_driver(adapter_args,uri)
|
if do_connect: self.find_driver(adapter_args,uri)
|
||||||
self.pool_size = pool_size
|
self.pool_size = pool_size
|
||||||
@@ -3920,22 +3921,27 @@ class IngresAdapter(BaseAdapter):
|
|||||||
self.db_codec = db_codec
|
self.db_codec = db_codec
|
||||||
self._after_connection = after_connection
|
self._after_connection = after_connection
|
||||||
self.find_or_make_work_folder()
|
self.find_or_make_work_folder()
|
||||||
connstr = self._uri.split(':', 1)[1]
|
connstr = uri.split(':', 1)[1]
|
||||||
# Simple URI processing
|
# Simple URI processing
|
||||||
connstr = connstr.lstrip()
|
connstr = connstr.lstrip()
|
||||||
while connstr.startswith('/'):
|
while connstr.startswith('/'):
|
||||||
connstr = connstr[1:]
|
connstr = connstr[1:]
|
||||||
database_name=connstr # Assume only (local) dbname is passed in
|
if '=' in connstr:
|
||||||
vnode = '(local)'
|
# Assume we have a regular ODBC connection string and just use it
|
||||||
servertype = 'ingres'
|
ruri = connstr
|
||||||
trace = (0, None) # No tracing
|
else:
|
||||||
driver_args.update(database=database_name,
|
# Assume only (local) dbname is passed in with OS auth
|
||||||
vnode=vnode,
|
database_name = connstr
|
||||||
servertype=servertype,
|
default_driver_name = 'Ingres'
|
||||||
trace=trace)
|
vnode = '(local)'
|
||||||
def connector(driver_args=driver_args):
|
servertype = 'ingres'
|
||||||
return self.driver.connect(**driver_args)
|
ruri = 'Driver={%s};Server=%s;Database=%s' % (default_driver_name, vnode, database_name)
|
||||||
|
def connector(cnxn=ruri,driver_args=driver_args):
|
||||||
|
return self.driver.connect(cnxn,**driver_args)
|
||||||
|
|
||||||
self.connector = connector
|
self.connector = connector
|
||||||
|
|
||||||
|
# TODO if version is >= 10, set types['id'] to Identity column, see http://community.actian.com/wiki/Using_Ingres_Identity_Columns
|
||||||
if do_connect: self.reconnect()
|
if do_connect: self.reconnect()
|
||||||
|
|
||||||
def create_sequence_and_triggers(self, query, table, **args):
|
def create_sequence_and_triggers(self, query, table, **args):
|
||||||
@@ -3961,12 +3967,12 @@ class IngresAdapter(BaseAdapter):
|
|||||||
return int(self.cursor.fetchone()[0]) # don't really need int type cast here...
|
return int(self.cursor.fetchone()[0]) # don't really need int type cast here...
|
||||||
|
|
||||||
def integrity_error_class(self):
|
def integrity_error_class(self):
|
||||||
return ingresdbi.IntegrityError
|
return self._driver.IntegrityError
|
||||||
|
|
||||||
|
|
||||||
class IngresUnicodeAdapter(IngresAdapter):
|
class IngresUnicodeAdapter(IngresAdapter):
|
||||||
|
|
||||||
drivers = ('ingresdbi',)
|
drivers = ('pyodbc',)
|
||||||
|
|
||||||
types = {
|
types = {
|
||||||
'boolean': 'CHAR(1)',
|
'boolean': 'CHAR(1)',
|
||||||
@@ -4464,7 +4470,7 @@ class GoogleDatastoreAdapter(NoSQLAdapter):
|
|||||||
adapter_args={}, do_connect=True, after_connection=None):
|
adapter_args={}, do_connect=True, after_connection=None):
|
||||||
self.types.update({
|
self.types.update({
|
||||||
'boolean': gae.BooleanProperty,
|
'boolean': gae.BooleanProperty,
|
||||||
'string': (lambda: gae.StringProperty(multiline=True)),
|
'string': (lambda **kwargs: gae.StringProperty(multiline=True, **kwargs)),
|
||||||
'text': gae.TextProperty,
|
'text': gae.TextProperty,
|
||||||
'json': gae.TextProperty,
|
'json': gae.TextProperty,
|
||||||
'password': gae.StringProperty,
|
'password': gae.StringProperty,
|
||||||
@@ -4480,9 +4486,9 @@ class GoogleDatastoreAdapter(NoSQLAdapter):
|
|||||||
'datetime': gae.DateTimeProperty,
|
'datetime': gae.DateTimeProperty,
|
||||||
'id': None,
|
'id': None,
|
||||||
'reference': gae.IntegerProperty,
|
'reference': gae.IntegerProperty,
|
||||||
'list:string': (lambda: gae.StringListProperty(default=None)),
|
'list:string': (lambda **kwargs: gae.StringListProperty(default=None, **kwargs)),
|
||||||
'list:integer': (lambda: gae.ListProperty(int,default=None)),
|
'list:integer': (lambda **kwargs: gae.ListProperty(int,default=None, **kwargs)),
|
||||||
'list:reference': (lambda: gae.ListProperty(int,default=None)),
|
'list:reference': (lambda **kwargs: gae.ListProperty(int,default=None, **kwargs)),
|
||||||
})
|
})
|
||||||
self.db = db
|
self.db = db
|
||||||
self.uri = uri
|
self.uri = uri
|
||||||
@@ -4505,7 +4511,7 @@ class GoogleDatastoreAdapter(NoSQLAdapter):
|
|||||||
if isinstance(polymodel,Table) and field.name in polymodel.fields():
|
if isinstance(polymodel,Table) and field.name in polymodel.fields():
|
||||||
continue
|
continue
|
||||||
attr = {}
|
attr = {}
|
||||||
if isinstance(field.custom_qaulifier, dict):
|
if isinstance(field.custom_qualifier, dict):
|
||||||
#this is custom properties to add to the GAE field declartion
|
#this is custom properties to add to the GAE field declartion
|
||||||
attr = field.custom_qualifier
|
attr = field.custom_qualifier
|
||||||
field_type = field.type
|
field_type = field.type
|
||||||
@@ -4653,7 +4659,7 @@ class GoogleDatastoreAdapter(NoSQLAdapter):
|
|||||||
return self.expand(first)
|
return self.expand(first)
|
||||||
|
|
||||||
def truncate(self,table,mode):
|
def truncate(self,table,mode):
|
||||||
self.db(table._id).delete()
|
self.db(self.db._adapter.id_query(table)).delete()
|
||||||
|
|
||||||
def select_raw(self,query,fields=None,attributes=None):
|
def select_raw(self,query,fields=None,attributes=None):
|
||||||
db = self.db
|
db = self.db
|
||||||
@@ -7051,15 +7057,13 @@ class DAL(object):
|
|||||||
Example::
|
Example::
|
||||||
|
|
||||||
db = DAL('sqlite://test.db')
|
db = DAL('sqlite://test.db')
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
db = DAL({"uri": ..., "items": ...}) # experimental
|
||||||
|
|
||||||
db.define_table('tablename', Field('fieldname1'),
|
db.define_table('tablename', Field('fieldname1'),
|
||||||
Field('fieldname2'))
|
Field('fieldname2'))
|
||||||
|
|
||||||
(experimental)
|
|
||||||
you can pass a dict object as uri with the uri string
|
|
||||||
and table/field definitions. For an example of valid data check
|
|
||||||
the output of:
|
|
||||||
|
|
||||||
>>> db.as_dict(flat=True, sanitize=False)
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __new__(cls, uri='sqlite://dummy.db', *args, **kwargs):
|
def __new__(cls, uri='sqlite://dummy.db', *args, **kwargs):
|
||||||
@@ -7180,6 +7184,28 @@ class DAL(object):
|
|||||||
|
|
||||||
:uri: string that contains information for connecting to a database.
|
:uri: string that contains information for connecting to a database.
|
||||||
(default: 'sqlite://dummy.db')
|
(default: 'sqlite://dummy.db')
|
||||||
|
|
||||||
|
experimental: you can specify a dictionary as uri
|
||||||
|
parameter i.e. with
|
||||||
|
db = DAL({"uri": "sqlite://storage.sqlite",
|
||||||
|
"items": {...}, ...})
|
||||||
|
|
||||||
|
for an example of dict input you can check the output
|
||||||
|
of the scaffolding db model with
|
||||||
|
|
||||||
|
db.as_dict()
|
||||||
|
|
||||||
|
Note that for compatibility with Python older than
|
||||||
|
version 2.6.5 you should cast your dict input keys
|
||||||
|
to str due to a syntax limitation on kwarg names.
|
||||||
|
for proper DAL dictionary input you can use one of:
|
||||||
|
|
||||||
|
obj = serializers.cast_keys(dict, [encoding="utf-8"])
|
||||||
|
|
||||||
|
or else (for parsing json input)
|
||||||
|
|
||||||
|
obj = serializers.loads_json(data, unicode_keys=False)
|
||||||
|
|
||||||
:pool_size: How many open connections to make to the database object.
|
:pool_size: How many open connections to make to the database object.
|
||||||
:folder: where .table files will be created.
|
:folder: where .table files will be created.
|
||||||
automatically set within web2py
|
automatically set within web2py
|
||||||
@@ -8816,6 +8842,8 @@ class Expression(object):
|
|||||||
result_type = 'integer'
|
result_type = 'integer'
|
||||||
elif self.type in ['date','time','datetime','double','float']:
|
elif self.type in ['date','time','datetime','double','float']:
|
||||||
result_type = 'double'
|
result_type = 'double'
|
||||||
|
elif self.type.startswith('decimal('):
|
||||||
|
result_type = self.type
|
||||||
else:
|
else:
|
||||||
raise SyntaxError("subtraction operation not supported for type")
|
raise SyntaxError("subtraction operation not supported for type")
|
||||||
return Expression(db,db._adapter.SUB,self,other,result_type)
|
return Expression(db,db._adapter.SUB,self,other,result_type)
|
||||||
@@ -9036,7 +9064,7 @@ class FieldVirtual(object):
|
|||||||
(self.name, self.f) = (name, f) if f else ('unkown', name)
|
(self.name, self.f) = (name, f) if f else ('unkown', name)
|
||||||
self.type = ftype
|
self.type = ftype
|
||||||
self.label = label or self.name.capitalize().replace('_',' ')
|
self.label = label or self.name.capitalize().replace('_',' ')
|
||||||
self.represent = IDENTITY
|
self.represent = IDENTITY
|
||||||
self.formatter = IDENTITY
|
self.formatter = IDENTITY
|
||||||
self.comment = None
|
self.comment = None
|
||||||
self.readable = True
|
self.readable = True
|
||||||
@@ -9234,7 +9262,11 @@ class Field(Expression):
|
|||||||
dest_file.close()
|
dest_file.close()
|
||||||
return newfilename
|
return newfilename
|
||||||
|
|
||||||
def retrieve(self, name, path=None):
|
def retrieve(self, name, path=None, nameonly=False):
|
||||||
|
"""
|
||||||
|
if nameonly==True return (filename, fullfilename) instead of
|
||||||
|
(filename, stream)
|
||||||
|
"""
|
||||||
self_uploadfield = self.uploadfield
|
self_uploadfield = self.uploadfield
|
||||||
if self.custom_retrieve:
|
if self.custom_retrieve:
|
||||||
return self.custom_retrieve(name, path)
|
return self.custom_retrieve(name, path)
|
||||||
@@ -9262,7 +9294,12 @@ class Field(Expression):
|
|||||||
stream = self.uploadfs.open(name, 'rb')
|
stream = self.uploadfs.open(name, 'rb')
|
||||||
else:
|
else:
|
||||||
# ## if file is on regular filesystem
|
# ## if file is on regular filesystem
|
||||||
stream = pjoin(file_properties['path'], name)
|
# this is intentially a sting with filename and not a stream
|
||||||
|
# this propagates and allows stream_file_or_304_or_206 to be called
|
||||||
|
fullname = pjoin(file_properties['path'],name)
|
||||||
|
if nameonly:
|
||||||
|
return (filename, fullname)
|
||||||
|
stream = open(fullname,'rb')
|
||||||
return (filename, stream)
|
return (filename, stream)
|
||||||
|
|
||||||
def retrieve_file_properties(self, name, path=None):
|
def retrieve_file_properties(self, name, path=None):
|
||||||
@@ -9389,7 +9426,7 @@ class Field(Expression):
|
|||||||
if k == "other":
|
if k == "other":
|
||||||
if isinstance(v, dict):
|
if isinstance(v, dict):
|
||||||
otype, other = v.popitem()
|
otype, other = v.popitem()
|
||||||
else:
|
else:
|
||||||
otype = flatten(type(v))
|
otype = flatten(type(v))
|
||||||
other = v
|
other = v
|
||||||
newr[k] = {otype: filter_requires(otype, other,
|
newr[k] = {otype: filter_requires(otype, other,
|
||||||
@@ -9535,6 +9572,10 @@ class Query(object):
|
|||||||
newd[k] = loop(v.__dict__)
|
newd[k] = loop(v.__dict__)
|
||||||
elif isinstance(v, SERIALIZABLE_TYPES):
|
elif isinstance(v, SERIALIZABLE_TYPES):
|
||||||
newd[k] = v
|
newd[k] = v
|
||||||
|
elif isinstance(v, (datetime.date,
|
||||||
|
datetime.time,
|
||||||
|
datetime.datetime)):
|
||||||
|
newd[k] = unicode(v)
|
||||||
elif k == "op":
|
elif k == "op":
|
||||||
if callable(v):
|
if callable(v):
|
||||||
newd[k] = v.__name__
|
newd[k] = v.__name__
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ __all__ = [
|
|||||||
|
|
||||||
def parse_semantic(version="Version 1.99.0-rc.1+timestamp.2011.09.19.08.23.26"):
|
def parse_semantic(version="Version 1.99.0-rc.1+timestamp.2011.09.19.08.23.26"):
|
||||||
"http://semver.org/"
|
"http://semver.org/"
|
||||||
re_version = re.compile('Version (\d+)\.(\d+)\.(\d+)(\-(?P<pre>[^\s+]*))?(\+(?P<build>\S*))')
|
re_version = re.compile('(\d+)\.(\d+)\.(\d+)(\-(?P<pre>[^\s+]*))?(\+(?P<build>\S*))')
|
||||||
m = re_version.match(version)
|
m = re_version.match(version.strip().split()[-1])
|
||||||
if not m:
|
if not m:
|
||||||
return None
|
return None
|
||||||
a, b, c = int(m.group(1)), int(m.group(2)), int(m.group(3))
|
a, b, c = int(m.group(1)), int(m.group(2)), int(m.group(3))
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ current = threading.local() # thread-local storage for request-scope globals
|
|||||||
css_template = '<link href="%s" rel="stylesheet" type="text/css" />'
|
css_template = '<link href="%s" rel="stylesheet" type="text/css" />'
|
||||||
js_template = '<script src="%s" type="text/javascript"></script>'
|
js_template = '<script src="%s" type="text/javascript"></script>'
|
||||||
coffee_template = '<script src="%s" type="text/coffee"></script>'
|
coffee_template = '<script src="%s" type="text/coffee"></script>'
|
||||||
|
typescript_template = '<script src="%s" type="text/typescript"></script>'
|
||||||
less_template = '<link href="%s" rel="stylesheet/less" type="text/css" />'
|
less_template = '<link href="%s" rel="stylesheet/less" type="text/css" />'
|
||||||
css_inline = '<style type="text/css">\n%s\n</style>'
|
css_inline = '<style type="text/css">\n%s\n</style>'
|
||||||
js_inline = '<script type="text/javascript">\n%s\n</script>'
|
js_inline = '<script type="text/javascript">\n%s\n</script>'
|
||||||
@@ -292,6 +293,9 @@ class Response(Storage):
|
|||||||
s += js_template % item
|
s += js_template % item
|
||||||
elif f.endswith('.coffee'):
|
elif f.endswith('.coffee'):
|
||||||
s += coffee_template % item
|
s += coffee_template % item
|
||||||
|
elif f.endswith('.ts'):
|
||||||
|
# http://www.typescriptlang.org/
|
||||||
|
s += typescript_template % item
|
||||||
elif f.endswith('.less'):
|
elif f.endswith('.less'):
|
||||||
s += less_template % item
|
s += less_template % item
|
||||||
elif isinstance(item, (list, tuple)):
|
elif isinstance(item, (list, tuple)):
|
||||||
@@ -400,7 +404,7 @@ class Response(Storage):
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise HTTP(404)
|
raise HTTP(404)
|
||||||
try:
|
try:
|
||||||
(filename, stream) = field.retrieve(name)
|
(filename, stream) = field.retrieve(name,nameonly=True)
|
||||||
except IOError:
|
except IOError:
|
||||||
raise HTTP(404)
|
raise HTTP(404)
|
||||||
headers = self.headers
|
headers = self.headers
|
||||||
|
|||||||
@@ -887,9 +887,8 @@ class DIV(XmlComponent):
|
|||||||
|
|
||||||
# get the attributes for this component
|
# get the attributes for this component
|
||||||
# (they start with '_', others may have special meanings)
|
# (they start with '_', others may have special meanings)
|
||||||
fa = ''
|
attr = []
|
||||||
for key in sorted(self.attributes):
|
for key, value in self.attributes.iteritems():
|
||||||
value = self[key]
|
|
||||||
if key[:1] != '_':
|
if key[:1] != '_':
|
||||||
continue
|
continue
|
||||||
name = key[1:]
|
name = key[1:]
|
||||||
@@ -897,8 +896,16 @@ class DIV(XmlComponent):
|
|||||||
value = name
|
value = name
|
||||||
elif value is False or value is None:
|
elif value is False or value is None:
|
||||||
continue
|
continue
|
||||||
|
attr.append((name, value))
|
||||||
|
data = self.attributes.get('data',{})
|
||||||
|
for key, value in data.iteritems():
|
||||||
|
name = 'data-' + key
|
||||||
|
value = data[key]
|
||||||
|
attr.append((name,value))
|
||||||
|
attr.sort()
|
||||||
|
fa = ''
|
||||||
|
for name,value in attr:
|
||||||
fa += ' %s="%s"' % (name, xmlescape(value, True))
|
fa += ' %s="%s"' % (name, xmlescape(value, True))
|
||||||
|
|
||||||
# get the xml for the inner components
|
# get the xml for the inner components
|
||||||
co = join([xmlescape(component) for component in
|
co = join([xmlescape(component) for component in
|
||||||
self.components])
|
self.components])
|
||||||
@@ -1479,7 +1486,7 @@ class A(DIV):
|
|||||||
self['_href'] = self['_href'] or '#null'
|
self['_href'] = self['_href'] or '#null'
|
||||||
elif self['callback']:
|
elif self['callback']:
|
||||||
returnfalse = "var e = arguments[0] || window.event; e.cancelBubble=true; if (e.stopPropagation) {e.stopPropagation(); e.stopImmediatePropagation(); e.preventDefault();}"
|
returnfalse = "var e = arguments[0] || window.event; e.cancelBubble=true; if (e.stopPropagation) {e.stopPropagation(); e.stopImmediatePropagation(); e.preventDefault();}"
|
||||||
if d:
|
if d and not self['noconfirm']:
|
||||||
self['_onclick'] = "if(confirm(w2p_ajax_confirm_message||'Are you sure you want to delete this object?')){ajax('%s',[],'%s');%s};%s" % \
|
self['_onclick'] = "if(confirm(w2p_ajax_confirm_message||'Are you sure you want to delete this object?')){ajax('%s',[],'%s');%s};%s" % \
|
||||||
(self['callback'], self['target'] or '', d, returnfalse)
|
(self['callback'], self['target'] or '', d, returnfalse)
|
||||||
else:
|
else:
|
||||||
@@ -2305,7 +2312,7 @@ class BEAUTIFY(DIV):
|
|||||||
for c in self.components:
|
for c in self.components:
|
||||||
if hasattr(c, 'value') and not callable(c.value):
|
if hasattr(c, 'value') and not callable(c.value):
|
||||||
if c.value:
|
if c.value:
|
||||||
components.append(c.value)
|
components.append(c.value)
|
||||||
if hasattr(c, 'xml') and callable(c.xml):
|
if hasattr(c, 'xml') and callable(c.xml):
|
||||||
components.append(c)
|
components.append(c)
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -237,7 +237,8 @@ def read_possible_languages_aux(langdir):
|
|||||||
construct_plural_form) # construct_plural_form() for current language
|
construct_plural_form) # construct_plural_form() for current language
|
||||||
|
|
||||||
plurals = {}
|
plurals = {}
|
||||||
flist = oslistdir(langdir)
|
flist = oslistdir(langdir) if isdir(langdir) else []
|
||||||
|
|
||||||
# scan languages directory for plural dict files:
|
# scan languages directory for plural dict files:
|
||||||
for pname in flist:
|
for pname in flist:
|
||||||
if regex_plural_file.match(pname):
|
if regex_plural_file.match(pname):
|
||||||
|
|||||||
@@ -102,16 +102,14 @@ requests = 0 # gc timer
|
|||||||
# pattern used to validate client address
|
# pattern used to validate client address
|
||||||
regex_client = re.compile('[\w\-:]+(\.[\w\-]+)*\.?') # ## to account for IPV6
|
regex_client = re.compile('[\w\-:]+(\.[\w\-]+)*\.?') # ## to account for IPV6
|
||||||
|
|
||||||
#try:
|
try:
|
||||||
if 1:
|
|
||||||
version_info = open(pjoin(global_settings.gluon_parent, 'VERSION'), 'r')
|
version_info = open(pjoin(global_settings.gluon_parent, 'VERSION'), 'r')
|
||||||
raw_version_string = version_info.read().strip()
|
raw_version_string = version_info.read().split()[-1].strip()
|
||||||
version_info.close()
|
version_info.close()
|
||||||
global_settings.web2py_version = parse_version(raw_version_string)
|
global_settings.web2py_version = raw_version_string
|
||||||
#except:
|
web2py_version = global_settings.web2py_version
|
||||||
# raise RuntimeError("Cannot determine web2py version")
|
except:
|
||||||
|
raise RuntimeError("Cannot determine web2py version")
|
||||||
web2py_version = global_settings.web2py_version
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import rocket
|
import rocket
|
||||||
@@ -133,7 +131,7 @@ def get_client(env):
|
|||||||
"""
|
"""
|
||||||
g = regex_client.search(env.get('http_x_forwarded_for', ''))
|
g = regex_client.search(env.get('http_x_forwarded_for', ''))
|
||||||
client = (g.group() or '').split(',')[0] if g else None
|
client = (g.group() or '').split(',')[0] if g else None
|
||||||
if client in (None, '', 'unkown'):
|
if client in (None, '', 'unknown'):
|
||||||
g = regex_client.search(env.get('remote_addr', ''))
|
g = regex_client.search(env.get('remote_addr', ''))
|
||||||
if g:
|
if g:
|
||||||
client = g.group()
|
client = g.group()
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ from settings import global_settings
|
|||||||
|
|
||||||
logger = logging.getLogger("web2py.cron")
|
logger = logging.getLogger("web2py.cron")
|
||||||
_cron_stopping = False
|
_cron_stopping = False
|
||||||
|
_cron_subprocs = []
|
||||||
|
|
||||||
|
|
||||||
def absolute_path_link(path):
|
def absolute_path_link(path):
|
||||||
@@ -42,7 +43,8 @@ def stopcron():
|
|||||||
"graceful shutdown of cron"
|
"graceful shutdown of cron"
|
||||||
global _cron_stopping
|
global _cron_stopping
|
||||||
_cron_stopping = True
|
_cron_stopping = True
|
||||||
|
while _cron_subprocs:
|
||||||
|
_cron_subprocs.pop().terminate()
|
||||||
|
|
||||||
class extcron(threading.Thread):
|
class extcron(threading.Thread):
|
||||||
|
|
||||||
@@ -232,6 +234,7 @@ class cronlauncher(threading.Thread):
|
|||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
import subprocess
|
import subprocess
|
||||||
|
global _cron_subprocs
|
||||||
if isinstance(self.cmd, (list, tuple)):
|
if isinstance(self.cmd, (list, tuple)):
|
||||||
cmd = self.cmd
|
cmd = self.cmd
|
||||||
else:
|
else:
|
||||||
@@ -241,6 +244,7 @@ class cronlauncher(threading.Thread):
|
|||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE,
|
stderr=subprocess.PIPE,
|
||||||
shell=self.shell)
|
shell=self.shell)
|
||||||
|
_cron_subprocs.append(proc)
|
||||||
(stdoutdata, stderrdata) = proc.communicate()
|
(stdoutdata, stderrdata) = proc.communicate()
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ class XssCleaner(HTMLParser):
|
|||||||
# The only schemes allowed in URLs (for href and src attributes).
|
# The only schemes allowed in URLs (for href and src attributes).
|
||||||
# Adding "javascript" or "vbscript" to this list would not be smart.
|
# Adding "javascript" or "vbscript" to this list would not be smart.
|
||||||
|
|
||||||
self.allowed_schemes = ['http', 'https', 'ftp']
|
self.allowed_schemes = ['http', 'https', 'ftp', 'mailto']
|
||||||
|
|
||||||
#to strip or escape disallowed tags?
|
#to strip or escape disallowed tags?
|
||||||
self.strip_disallowed = strip_disallowed
|
self.strip_disallowed = strip_disallowed
|
||||||
@@ -151,11 +151,12 @@ class XssCleaner(HTMLParser):
|
|||||||
|
|
||||||
def url_is_acceptable(self, url):
|
def url_is_acceptable(self, url):
|
||||||
"""
|
"""
|
||||||
Accepts relative and absolute urls
|
Accepts relative, absolute, and mailto urls
|
||||||
"""
|
"""
|
||||||
|
|
||||||
parsed = urlparse(url)
|
parsed = urlparse(url)
|
||||||
return (parsed[0] in self.allowed_schemes and '.' in parsed[1]) \
|
return (parsed[0] in self.allowed_schemes and '.' in parsed[1]) \
|
||||||
|
or (parsed[0] in self.allowed_schemes and '@' in parsed[2]) \
|
||||||
or (parsed[0] == '' and parsed[2].startswith('/'))
|
or (parsed[0] == '' and parsed[2].startswith('/'))
|
||||||
|
|
||||||
def strip(self, rawstring, escape=True):
|
def strip(self, rawstring, escape=True):
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ TERMINATE = 'TERMINATE'
|
|||||||
DISABLED = 'DISABLED'
|
DISABLED = 'DISABLED'
|
||||||
KILL = 'KILL'
|
KILL = 'KILL'
|
||||||
PICK = 'PICK'
|
PICK = 'PICK'
|
||||||
|
STOP_TASK = 'STOP_TASK'
|
||||||
EXPIRED = 'EXPIRED'
|
EXPIRED = 'EXPIRED'
|
||||||
SECONDS = 1
|
SECONDS = 1
|
||||||
HEARTBEAT = 3 * SECONDS
|
HEARTBEAT = 3 * SECONDS
|
||||||
@@ -398,7 +399,7 @@ class MetaScheduler(threading.Thread):
|
|||||||
|
|
||||||
TASK_STATUS = (QUEUED, RUNNING, COMPLETED, FAILED, TIMEOUT, STOPPED, EXPIRED)
|
TASK_STATUS = (QUEUED, RUNNING, COMPLETED, FAILED, TIMEOUT, STOPPED, EXPIRED)
|
||||||
RUN_STATUS = (RUNNING, COMPLETED, FAILED, TIMEOUT, STOPPED)
|
RUN_STATUS = (RUNNING, COMPLETED, FAILED, TIMEOUT, STOPPED)
|
||||||
WORKER_STATUS = (ACTIVE, PICK, DISABLED, TERMINATE, KILL)
|
WORKER_STATUS = (ACTIVE, PICK, DISABLED, TERMINATE, KILL, STOP_TASK)
|
||||||
|
|
||||||
|
|
||||||
class TYPE(object):
|
class TYPE(object):
|
||||||
@@ -746,7 +747,7 @@ class Scheduler(MetaScheduler):
|
|||||||
# keep sleeping
|
# keep sleeping
|
||||||
self.worker_status[0] = DISABLED
|
self.worker_status[0] = DISABLED
|
||||||
if self.worker_status[1] == MAXHIBERNATION:
|
if self.worker_status[1] == MAXHIBERNATION:
|
||||||
logger.debug('........recording heartbeat')
|
logger.debug('........recording heartbeat (%s)', self.worker_status[0])
|
||||||
db(sw.worker_name == self.worker_name).update(
|
db(sw.worker_name == self.worker_name).update(
|
||||||
last_heartbeat=now)
|
last_heartbeat=now)
|
||||||
elif mybackedstatus == TERMINATE:
|
elif mybackedstatus == TERMINATE:
|
||||||
@@ -758,6 +759,9 @@ class Scheduler(MetaScheduler):
|
|||||||
self.worker_status[0] = KILL
|
self.worker_status[0] = KILL
|
||||||
self.die()
|
self.die()
|
||||||
else:
|
else:
|
||||||
|
if mybackedstatus == STOP_TASK:
|
||||||
|
logger.info('Asked to kill the current task')
|
||||||
|
self.terminate_process()
|
||||||
logger.debug('........recording heartbeat (%s)', self.worker_status[0])
|
logger.debug('........recording heartbeat (%s)', self.worker_status[0])
|
||||||
db(sw.worker_name == self.worker_name).update(
|
db(sw.worker_name == self.worker_name).update(
|
||||||
last_heartbeat=now, status=ACTIVE)
|
last_heartbeat=now, status=ACTIVE)
|
||||||
@@ -1007,6 +1011,40 @@ class Scheduler(MetaScheduler):
|
|||||||
object_hook=_decode_dict) or None
|
object_hook=_decode_dict) or None
|
||||||
return row
|
return row
|
||||||
|
|
||||||
|
def stop_task(self, ref):
|
||||||
|
"""
|
||||||
|
Experimental!!!
|
||||||
|
Shortcut for task termination.
|
||||||
|
If the task is RUNNING it will terminate it --> execution will be set as FAILED
|
||||||
|
If the task is QUEUED, its stop_time will be set as to "now",
|
||||||
|
the enabled flag will be set to False, status to STOPPED
|
||||||
|
|
||||||
|
:param ref: can be
|
||||||
|
- integer --> lookup will be done by scheduler_task.id
|
||||||
|
- string --> lookup will be done by scheduler_task.uuid
|
||||||
|
Returns:
|
||||||
|
- 1 if task was stopped (meaning an update has been done)
|
||||||
|
- None if task was not found, or if task was not RUNNING or QUEUED
|
||||||
|
"""
|
||||||
|
from gluon.dal import Query
|
||||||
|
st, sw = self.db.scheduler_task, self.db.scheduler_worker
|
||||||
|
if isinstance(ref, int):
|
||||||
|
q = st.id == ref
|
||||||
|
elif isinstance(ref, str):
|
||||||
|
q = st.uuid == ref
|
||||||
|
else:
|
||||||
|
raise SyntaxError(
|
||||||
|
"You can retrieve results only by id or uuid")
|
||||||
|
task = self.db(q).select(st.id, st.status, st.assigned_worker_name).first()
|
||||||
|
rtn = None
|
||||||
|
if not task:
|
||||||
|
return rtn
|
||||||
|
if task.status == 'RUNNING':
|
||||||
|
rtn = self.db(sw.worker_name == task.assigned_worker_name).update(status=STOP_TASK)
|
||||||
|
elif task.status == 'QUEUED':
|
||||||
|
rtn = self.db(q).update(stop_time=self.now(), enabled=False, status=STOPPED)
|
||||||
|
return rtn
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -25,9 +25,52 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
have_yaml = False
|
have_yaml = False
|
||||||
|
|
||||||
def loads_json(o):
|
def cast_keys(o, cast=str, encoding="utf-8"):
|
||||||
|
""" Builds a new object with <cast> type keys
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
o is the object input
|
||||||
|
cast (defaults to str) is an object type or function
|
||||||
|
which supports conversion such as:
|
||||||
|
|
||||||
|
>>> converted = cast(o)
|
||||||
|
|
||||||
|
encoding (defaults to utf-8) is the encoding for unicode
|
||||||
|
keys. This is not used for custom cast functions
|
||||||
|
|
||||||
|
Use this funcion if you are in Python < 2.6.5
|
||||||
|
This avoids syntax errors when unpacking dictionary arguments.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if isinstance(o, (dict, Storage)):
|
||||||
|
if isinstance(o, dict):
|
||||||
|
newobj = dict()
|
||||||
|
else:
|
||||||
|
newobj = Storage()
|
||||||
|
|
||||||
|
for k, v in o.items():
|
||||||
|
if (cast == str) and isinstance(k, unicode):
|
||||||
|
key = k.encode(encoding)
|
||||||
|
else:
|
||||||
|
key = cast(k)
|
||||||
|
if isinstance(v, (dict, Storage)):
|
||||||
|
value = cast_keys(v, cast=cast, encoding=encoding)
|
||||||
|
else:
|
||||||
|
value = v
|
||||||
|
newobj[key] = value
|
||||||
|
else:
|
||||||
|
raise TypeError("Cannot cast keys: %s is not supported" % \
|
||||||
|
type(o))
|
||||||
|
return newobj
|
||||||
|
|
||||||
|
def loads_json(o, unicode_keys=True, **kwargs):
|
||||||
# deserialize a json string
|
# deserialize a json string
|
||||||
return json_parser.loads(o)
|
result = json_parser.loads(o, **kwargs)
|
||||||
|
if not unicode_keys:
|
||||||
|
# filter non-str keys in dictionary objects
|
||||||
|
result = cast_keys(result,
|
||||||
|
encoding=kwargs.get("encoding", "utf-8"))
|
||||||
|
return result
|
||||||
|
|
||||||
def custom_json(o):
|
def custom_json(o):
|
||||||
if hasattr(o, 'custom_json') and callable(o.custom_json):
|
if hasattr(o, 'custom_json') and callable(o.custom_json):
|
||||||
|
|||||||
@@ -286,9 +286,9 @@ jQuery.fn.grow_input = function() {
|
|||||||
function pe(ul, e) {
|
function pe(ul, e) {
|
||||||
var new_line = ml(ul);
|
var new_line = ml(ul);
|
||||||
rel(ul);
|
rel(ul);
|
||||||
if ($(e.target).parent().is(':visible')) {
|
if (jQuery(e.target).parent().is(':visible')) {
|
||||||
//make sure we didn't delete the element before we insert after
|
//make sure we didn't delete the element before we insert after
|
||||||
new_line.insertAfter($(e.target).parent());
|
new_line.insertAfter(jQuery(e.target).parent());
|
||||||
} else {
|
} else {
|
||||||
//the line we clicked on was deleted, just add to end of list
|
//the line we clicked on was deleted, just add to end of list
|
||||||
new_line.appendTo(ul);
|
new_line.appendTo(ul);
|
||||||
@@ -299,7 +299,7 @@ function pe(ul, e) {
|
|||||||
function rl(ul, e) {
|
function rl(ul, e) {
|
||||||
if (jQuery(ul).children().length > 1) {
|
if (jQuery(ul).children().length > 1) {
|
||||||
//only remove if we have more than 1 item so the list is never empty
|
//only remove if we have more than 1 item so the list is never empty
|
||||||
$(e.target).parent().remove();
|
jQuery(e.target).parent().remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function ml(ul) {
|
function ml(ul) {
|
||||||
@@ -461,8 +461,8 @@ class CheckboxesWidget(OptionsWidget):
|
|||||||
if opts:
|
if opts:
|
||||||
opts.append(
|
opts.append(
|
||||||
INPUT(requires=attr.get('requires', None),
|
INPUT(requires=attr.get('requires', None),
|
||||||
_style="display:none;",
|
_style="display:none;",
|
||||||
_disabled="disabled",
|
_disabled="disabled",
|
||||||
_name=field.name,
|
_name=field.name,
|
||||||
hideerror=False))
|
hideerror=False))
|
||||||
return parent(*opts, **attr)
|
return parent(*opts, **attr)
|
||||||
@@ -542,7 +542,7 @@ class UploadWidget(FormWidget):
|
|||||||
|
|
||||||
requires = attr["requires"]
|
requires = attr["requires"]
|
||||||
if requires == [] or isinstance(requires, IS_EMPTY_OR):
|
if requires == [] or isinstance(requires, IS_EMPTY_OR):
|
||||||
inp = DIV(inp,
|
inp = DIV(inp,
|
||||||
SPAN('[',
|
SPAN('[',
|
||||||
A(current.T(
|
A(current.T(
|
||||||
UploadWidget.GENERIC_DESCRIPTION), _href=url),
|
UploadWidget.GENERIC_DESCRIPTION), _href=url),
|
||||||
@@ -553,13 +553,13 @@ class UploadWidget(FormWidget):
|
|||||||
LABEL(current.T(cls.DELETE_FILE),
|
LABEL(current.T(cls.DELETE_FILE),
|
||||||
_for=field.name + cls.ID_DELETE_SUFFIX,
|
_for=field.name + cls.ID_DELETE_SUFFIX,
|
||||||
_style='display:inline'),
|
_style='display:inline'),
|
||||||
']', _style='white-space:nowrap'),
|
']', _style='white-space:nowrap'),
|
||||||
br, image)
|
br, image)
|
||||||
else:
|
else:
|
||||||
inp = DIV(inp,
|
inp = DIV(inp,
|
||||||
SPAN('[',
|
SPAN('[',
|
||||||
A(cls.GENERIC_DESCRIPTION, _href=url),
|
A(cls.GENERIC_DESCRIPTION, _href=url),
|
||||||
']', _style='white-space:nowrap'),
|
']', _style='white-space:nowrap'),
|
||||||
br, image)
|
br, image)
|
||||||
return inp
|
return inp
|
||||||
|
|
||||||
@@ -1180,7 +1180,7 @@ class SQLFORM(FORM):
|
|||||||
widget,
|
widget,
|
||||||
col3.get(self.FIELDKEY_DELETE_RECORD, '')))
|
col3.get(self.FIELDKEY_DELETE_RECORD, '')))
|
||||||
self.custom.delete = self.custom.deletable = widget
|
self.custom.delete = self.custom.deletable = widget
|
||||||
|
|
||||||
|
|
||||||
# when writable, add submit button
|
# when writable, add submit button
|
||||||
self.custom.submit = ''
|
self.custom.submit = ''
|
||||||
@@ -1440,7 +1440,8 @@ class SQLFORM(FORM):
|
|||||||
f = self.table[fieldname].default or ''
|
f = self.table[fieldname].default or ''
|
||||||
fields[fieldname] = f
|
fields[fieldname] = f
|
||||||
else:
|
else:
|
||||||
fields[fieldname] = ''
|
f = self.table[fieldname].default or ''
|
||||||
|
fields[fieldname] = f
|
||||||
self.vars[fieldname] = fields[fieldname]
|
self.vars[fieldname] = fields[fieldname]
|
||||||
if not f:
|
if not f:
|
||||||
continue
|
continue
|
||||||
@@ -1654,7 +1655,7 @@ class SQLFORM(FORM):
|
|||||||
value_input = SQLFORM.widgets.date.widget(field,field.default,_id=_id)
|
value_input = SQLFORM.widgets.date.widget(field,field.default,_id=_id)
|
||||||
elif field.type == 'datetime':
|
elif field.type == 'datetime':
|
||||||
value_input = SQLFORM.widgets.datetime.widget(field,field.default,_id=_id)
|
value_input = SQLFORM.widgets.datetime.widget(field,field.default,_id=_id)
|
||||||
elif (field.type.startswith('reference ') or
|
elif (field.type.startswith('reference ') or
|
||||||
field.type.startswith('list:reference ')) and \
|
field.type.startswith('list:reference ')) and \
|
||||||
hasattr(field.requires,'options'):
|
hasattr(field.requires,'options'):
|
||||||
value_input = SELECT(
|
value_input = SELECT(
|
||||||
@@ -1669,7 +1670,7 @@ class SQLFORM(FORM):
|
|||||||
else:
|
else:
|
||||||
value_input = INPUT(
|
value_input = INPUT(
|
||||||
_type='text', _id=_id, _class=field.type)
|
_type='text', _id=_id, _class=field.type)
|
||||||
|
|
||||||
new_button = INPUT(
|
new_button = INPUT(
|
||||||
_type="button", _value=T('New'), _class="btn",
|
_type="button", _value=T('New'), _class="btn",
|
||||||
_onclick="%s_build_query('new','%s')" % (prefix,field))
|
_onclick="%s_build_query('new','%s')" % (prefix,field))
|
||||||
@@ -1760,7 +1761,8 @@ class SQLFORM(FORM):
|
|||||||
editargs={},
|
editargs={},
|
||||||
viewargs={},
|
viewargs={},
|
||||||
buttons_placement = 'right',
|
buttons_placement = 'right',
|
||||||
links_placement = 'right'
|
links_placement = 'right',
|
||||||
|
noconfirm=False
|
||||||
):
|
):
|
||||||
|
|
||||||
# jQuery UI ThemeRoller classes (empty if ui is disabled)
|
# jQuery UI ThemeRoller classes (empty if ui is disabled)
|
||||||
@@ -1816,7 +1818,7 @@ class SQLFORM(FORM):
|
|||||||
|
|
||||||
def url(**b):
|
def url(**b):
|
||||||
b['args'] = args + b.get('args', [])
|
b['args'] = args + b.get('args', [])
|
||||||
localvars = request.vars.copy()
|
localvars = request.get_vars.copy()
|
||||||
localvars.update(b.get('vars', {}))
|
localvars.update(b.get('vars', {}))
|
||||||
b['vars'] = localvars
|
b['vars'] = localvars
|
||||||
b['hash_vars'] = False
|
b['hash_vars'] = False
|
||||||
@@ -1825,7 +1827,7 @@ class SQLFORM(FORM):
|
|||||||
|
|
||||||
def url2(**b):
|
def url2(**b):
|
||||||
b['args'] = request.args + b.get('args', [])
|
b['args'] = request.args + b.get('args', [])
|
||||||
localvars = request.vars.copy()
|
localvars = request.get_vars.copy()
|
||||||
localvars.update(b.get('vars', {}))
|
localvars.update(b.get('vars', {}))
|
||||||
b['vars'] = localvars
|
b['vars'] = localvars
|
||||||
b['hash_vars'] = False
|
b['hash_vars'] = False
|
||||||
@@ -1849,7 +1851,7 @@ class SQLFORM(FORM):
|
|||||||
|
|
||||||
def gridbutton(buttonclass='buttonadd', buttontext=T('Add'),
|
def gridbutton(buttonclass='buttonadd', buttontext=T('Add'),
|
||||||
buttonurl=url(args=[]), callback=None,
|
buttonurl=url(args=[]), callback=None,
|
||||||
delete=None, trap=True):
|
delete=None, trap=True, noconfirm=None):
|
||||||
if showbuttontext:
|
if showbuttontext:
|
||||||
return A(SPAN(_class=ui.get(buttonclass)),
|
return A(SPAN(_class=ui.get(buttonclass)),
|
||||||
SPAN(T(buttontext), _title=buttontext,
|
SPAN(T(buttontext), _title=buttontext,
|
||||||
@@ -1857,12 +1859,14 @@ class SQLFORM(FORM):
|
|||||||
_href=buttonurl,
|
_href=buttonurl,
|
||||||
callback=callback,
|
callback=callback,
|
||||||
delete=delete,
|
delete=delete,
|
||||||
|
noconfirm=noconfirm,
|
||||||
_class=trap_class(ui.get('button'), trap))
|
_class=trap_class(ui.get('button'), trap))
|
||||||
else:
|
else:
|
||||||
return A(SPAN(_class=ui.get(buttonclass)),
|
return A(SPAN(_class=ui.get(buttonclass)),
|
||||||
_href=buttonurl,
|
_href=buttonurl,
|
||||||
callback=callback,
|
callback=callback,
|
||||||
delete=delete,
|
delete=delete,
|
||||||
|
noconfirm=noconfirm,
|
||||||
_title=buttontext,
|
_title=buttontext,
|
||||||
_class=trap_class(ui.get('buttontext'), trap))
|
_class=trap_class(ui.get('buttontext'), trap))
|
||||||
|
|
||||||
@@ -2056,7 +2060,8 @@ class SQLFORM(FORM):
|
|||||||
elif not request.vars.records:
|
elif not request.vars.records:
|
||||||
request.vars.records = []
|
request.vars.records = []
|
||||||
|
|
||||||
session['_web2py_grid_referrer_' + formname] = url2(vars=request.vars)
|
session['_web2py_grid_referrer_' + formname] = \
|
||||||
|
url2(vars=request.get_vars)
|
||||||
console = DIV(_class='web2py_console %(header)s %(cornertop)s' % ui)
|
console = DIV(_class='web2py_console %(header)s %(cornertop)s' % ui)
|
||||||
error = None
|
error = None
|
||||||
if create:
|
if create:
|
||||||
@@ -2341,6 +2346,7 @@ class SQLFORM(FORM):
|
|||||||
'buttondelete', 'Delete',
|
'buttondelete', 'Delete',
|
||||||
url(args=['delete', tablename, id]),
|
url(args=['delete', tablename, id]),
|
||||||
callback=url(args=['delete', tablename, id]),
|
callback=url(args=['delete', tablename, id]),
|
||||||
|
noconfirm=noconfirm,
|
||||||
delete='tr'))
|
delete='tr'))
|
||||||
if buttons_placement in ['right', 'both']:
|
if buttons_placement in ['right', 'both']:
|
||||||
trcols.append(row_buttons)
|
trcols.append(row_buttons)
|
||||||
@@ -2458,6 +2464,16 @@ class SQLFORM(FORM):
|
|||||||
if constraints is None:
|
if constraints is None:
|
||||||
constraints = {}
|
constraints = {}
|
||||||
field = None
|
field = None
|
||||||
|
name = None
|
||||||
|
def format(table,row):
|
||||||
|
if not row:
|
||||||
|
return 'Unknown'
|
||||||
|
elif isinstance(table._format,str):
|
||||||
|
return table._format % row
|
||||||
|
elif callable(table._format):
|
||||||
|
return table._format(row)
|
||||||
|
else:
|
||||||
|
return '#'+str(row.id)
|
||||||
try:
|
try:
|
||||||
nargs = len(args) + 1
|
nargs = len(args) + 1
|
||||||
previous_tablename, previous_fieldname, previous_id = \
|
previous_tablename, previous_fieldname, previous_id = \
|
||||||
@@ -2484,14 +2500,7 @@ class SQLFORM(FORM):
|
|||||||
raise HTTP(400)
|
raise HTTP(400)
|
||||||
previous_tablename, previous_fieldname, previous_id = \
|
previous_tablename, previous_fieldname, previous_id = \
|
||||||
tablename, fieldname, id
|
tablename, fieldname, id
|
||||||
try:
|
name = format(db[referee],record)
|
||||||
format = db[referee]._format
|
|
||||||
if callable(format):
|
|
||||||
name = format(record)
|
|
||||||
else:
|
|
||||||
name = format % record
|
|
||||||
except TypeError:
|
|
||||||
name = id
|
|
||||||
breadcrumbs.append(
|
breadcrumbs.append(
|
||||||
LI(A(T(db[referee]._plural),
|
LI(A(T(db[referee]._plural),
|
||||||
_class=trap_class(),
|
_class=trap_class(),
|
||||||
@@ -2553,13 +2562,27 @@ class SQLFORM(FORM):
|
|||||||
grid = SQLFORM.grid(query, args=request.args[:nargs], links=links,
|
grid = SQLFORM.grid(query, args=request.args[:nargs], links=links,
|
||||||
links_in_grid=links_in_grid,
|
links_in_grid=links_in_grid,
|
||||||
user_signature=user_signature, **kwargs)
|
user_signature=user_signature, **kwargs)
|
||||||
|
|
||||||
if isinstance(grid, DIV):
|
if isinstance(grid, DIV):
|
||||||
header = table._plural + (field and ' for ' + field.label or '')
|
header = table._plural
|
||||||
breadcrumbs.append(LI(A(T(header), _class=trap_class(),
|
next = grid.create_form or grid.update_form or grid.view_form
|
||||||
_href=url()), _class='active w2p_grid_breadcrumb_elem'))
|
breadcrumbs.append(LI(
|
||||||
|
A(T(header), _class=trap_class(),_href=url()),
|
||||||
|
SPAN(divider, _class='divider') if next else '',
|
||||||
|
_class='active w2p_grid_breadcrumb_elem'))
|
||||||
|
if grid.create_form:
|
||||||
|
header = T('New %s' % table._singular)
|
||||||
|
elif grid.update_form:
|
||||||
|
header = T('Edit %s' % format(table,grid.update_form.record))
|
||||||
|
elif grid.view_form:
|
||||||
|
header = T('View %s' % format(table,grid.view_form.record))
|
||||||
|
if next:
|
||||||
|
breadcrumbs.append(LI(
|
||||||
|
A(T(header), _class=trap_class(),_href=url()),
|
||||||
|
_class='active w2p_grid_breadcrumb_elem'))
|
||||||
grid.insert(
|
grid.insert(
|
||||||
0, DIV(UL(*breadcrumbs, **{'_class': breadcrumbs_class}),
|
0, DIV(UL(*breadcrumbs, **{'_class': breadcrumbs_class}),
|
||||||
_class='web2py_breadcrumbs'))
|
_class='web2py_breadcrumbs'))
|
||||||
return grid
|
return grid
|
||||||
|
|
||||||
|
|
||||||
@@ -2994,4 +3017,3 @@ class ExporterJSON(ExportClass):
|
|||||||
return self.rows.as_json()
|
return self.rows.as_json()
|
||||||
else:
|
else:
|
||||||
return 'null'
|
return 'null'
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
import glob
|
||||||
|
|
||||||
if os.path.isdir('gluon'):
|
if os.path.isdir('gluon'):
|
||||||
sys.path.append(os.path.realpath('gluon'))
|
sys.path.append(os.path.realpath('gluon'))
|
||||||
else:
|
else:
|
||||||
@@ -19,6 +21,11 @@ except:
|
|||||||
from io import StringIO
|
from io import StringIO
|
||||||
from dal import DAL, Field, Table, SQLALL
|
from dal import DAL, Field, Table, SQLALL
|
||||||
|
|
||||||
|
#for travis-ci
|
||||||
|
DEFAULT_URI = os.environ.get('DB', 'sqlite:memory')
|
||||||
|
print 'Testing against %s engine (%s)' % (DEFAULT_URI.partition(':')[0], DEFAULT_URI)
|
||||||
|
|
||||||
|
|
||||||
ALLOWED_DATATYPES = [
|
ALLOWED_DATATYPES = [
|
||||||
'string',
|
'string',
|
||||||
'text',
|
'text',
|
||||||
@@ -41,6 +48,8 @@ def setUpModule():
|
|||||||
def tearDownModule():
|
def tearDownModule():
|
||||||
if os.path.isfile('sql.log'):
|
if os.path.isfile('sql.log'):
|
||||||
os.unlink('sql.log')
|
os.unlink('sql.log')
|
||||||
|
for a in glob.glob('*.table'):
|
||||||
|
os.unlink(a)
|
||||||
|
|
||||||
|
|
||||||
class TestFields(unittest.TestCase):
|
class TestFields(unittest.TestCase):
|
||||||
@@ -96,35 +105,35 @@ class TestFields(unittest.TestCase):
|
|||||||
isinstance(f.formatter(datetime.datetime.now()), str)
|
isinstance(f.formatter(datetime.datetime.now()), str)
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
for ft in ['string', 'text', 'password', 'upload', 'blob']:
|
for ft in ['string', 'text', 'password', 'upload', 'blob']:
|
||||||
db.define_table('t', Field('a', ft, default=''))
|
db.define_table('tt', Field('aa', ft, default=''))
|
||||||
self.assertEqual(db.t.insert(a='x'), 1)
|
self.assertEqual(db.tt.insert(aa='x'), 1)
|
||||||
self.assertEqual(db().select(db.t.a)[0].a, 'x')
|
self.assertEqual(db().select(db.tt.aa)[0].aa, 'x')
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
db.define_table('t', Field('a', 'integer', default=1))
|
db.define_table('tt', Field('aa', 'integer', default=1))
|
||||||
self.assertEqual(db.t.insert(a=3), 1)
|
self.assertEqual(db.tt.insert(aa=3), 1)
|
||||||
self.assertEqual(db().select(db.t.a)[0].a, 3)
|
self.assertEqual(db().select(db.tt.aa)[0].aa, 3)
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
db.define_table('t', Field('a', 'double', default=1))
|
db.define_table('tt', Field('aa', 'double', default=1))
|
||||||
self.assertEqual(db.t.insert(a=3.1), 1)
|
self.assertEqual(db.tt.insert(aa=3.1), 1)
|
||||||
self.assertEqual(db().select(db.t.a)[0].a, 3.1)
|
self.assertEqual(db().select(db.tt.aa)[0].aa, 3.1)
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
db.define_table('t', Field('a', 'boolean', default=True))
|
db.define_table('tt', Field('aa', 'boolean', default=True))
|
||||||
self.assertEqual(db.t.insert(a=True), 1)
|
self.assertEqual(db.tt.insert(aa=True), 1)
|
||||||
self.assertEqual(db().select(db.t.a)[0].a, True)
|
self.assertEqual(db().select(db.tt.aa)[0].aa, True)
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
db.define_table('t', Field('a', 'json', default={}))
|
db.define_table('tt', Field('aa', 'json', default={}))
|
||||||
self.assertEqual(db.t.insert(a={}), 1)
|
self.assertEqual(db.tt.insert(aa={}), 1)
|
||||||
self.assertEqual(db().select(db.t.a)[0].a, {})
|
self.assertEqual(db().select(db.tt.aa)[0].aa, {})
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
db.define_table('t', Field('a', 'date',
|
db.define_table('tt', Field('aa', 'date',
|
||||||
default=datetime.date.today()))
|
default=datetime.date.today()))
|
||||||
t0 = datetime.date.today()
|
t0 = datetime.date.today()
|
||||||
self.assertEqual(db.t.insert(a=t0), 1)
|
self.assertEqual(db.tt.insert(aa=t0), 1)
|
||||||
self.assertEqual(db().select(db.t.a)[0].a, t0)
|
self.assertEqual(db().select(db.tt.aa)[0].aa, t0)
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
db.define_table('t', Field('a', 'datetime',
|
db.define_table('tt', Field('aa', 'datetime',
|
||||||
default=datetime.datetime.today()))
|
default=datetime.datetime.today()))
|
||||||
t0 = datetime.datetime(
|
t0 = datetime.datetime(
|
||||||
1971,
|
1971,
|
||||||
@@ -135,34 +144,34 @@ class TestFields(unittest.TestCase):
|
|||||||
55,
|
55,
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
self.assertEqual(db.t.insert(a=t0), 1)
|
self.assertEqual(db.tt.insert(aa=t0), 1)
|
||||||
self.assertEqual(db().select(db.t.a)[0].a, t0)
|
self.assertEqual(db().select(db.tt.aa)[0].aa, t0)
|
||||||
|
|
||||||
## Row APIs
|
## Row APIs
|
||||||
row = db().select(db.t.a)[0]
|
row = db().select(db.tt.aa)[0]
|
||||||
self.assertEqual(db.t[1].a,t0)
|
self.assertEqual(db.tt[1].aa,t0)
|
||||||
self.assertEqual(db.t['a'],db.t.a)
|
self.assertEqual(db.tt['aa'],db.tt.aa)
|
||||||
self.assertEqual(db.t(1).a,t0)
|
self.assertEqual(db.tt(1).aa,t0)
|
||||||
self.assertTrue(db.t(1,a=None)==None)
|
self.assertTrue(db.tt(1,aa=None)==None)
|
||||||
self.assertFalse(db.t(1,a=t0)==None)
|
self.assertFalse(db.tt(1,aa=t0)==None)
|
||||||
self.assertEqual(row.a,t0)
|
self.assertEqual(row.aa,t0)
|
||||||
self.assertEqual(row['a'],t0)
|
self.assertEqual(row['aa'],t0)
|
||||||
self.assertEqual(row['t.a'],t0)
|
self.assertEqual(row['tt.aa'],t0)
|
||||||
self.assertEqual(row('t.a'),t0)
|
self.assertEqual(row('tt.aa'),t0)
|
||||||
|
|
||||||
## Lazy and Virtual fields
|
## Lazy and Virtual fields
|
||||||
db.t.b = Field.Virtual(lambda row: row.t.a)
|
db.tt.b = Field.Virtual(lambda row: row.tt.aa)
|
||||||
db.t.c = Field.Lazy(lambda row: row.t.a)
|
db.tt.c = Field.Lazy(lambda row: row.tt.aa)
|
||||||
row = db().select(db.t.a)[0]
|
row = db().select(db.tt.aa)[0]
|
||||||
self.assertEqual(row.b,t0)
|
self.assertEqual(row.b,t0)
|
||||||
self.assertEqual(row.c(),t0)
|
self.assertEqual(row.c(),t0)
|
||||||
|
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
db.define_table('t', Field('a', 'time', default='11:30'))
|
db.define_table('tt', Field('aa', 'time', default='11:30'))
|
||||||
t0 = datetime.time(10, 30, 55)
|
t0 = datetime.time(10, 30, 55)
|
||||||
self.assertEqual(db.t.insert(a=t0), 1)
|
self.assertEqual(db.tt.insert(aa=t0), 1)
|
||||||
self.assertEqual(db().select(db.t.a)[0].a, t0)
|
self.assertEqual(db().select(db.tt.aa)[0].aa, t0)
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
|
|
||||||
|
|
||||||
class TestAll(unittest.TestCase):
|
class TestAll(unittest.TestCase):
|
||||||
@@ -198,7 +207,7 @@ class TestTable(unittest.TestCase):
|
|||||||
in str(persons.ALL))
|
in str(persons.ALL))
|
||||||
|
|
||||||
def testTableAlias(self):
|
def testTableAlias(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
persons = Table(db, 'persons', Field('firstname',
|
persons = Table(db, 'persons', Field('firstname',
|
||||||
'string'), Field('lastname', 'string'))
|
'string'), Field('lastname', 'string'))
|
||||||
aliens = persons.with_alias('aliens')
|
aliens = persons.with_alias('aliens')
|
||||||
@@ -221,276 +230,278 @@ class TestTable(unittest.TestCase):
|
|||||||
class TestInsert(unittest.TestCase):
|
class TestInsert(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a'))
|
db.define_table('tt', Field('aa'))
|
||||||
self.assertEqual(db.t.insert(a='1'), 1)
|
self.assertEqual(db.tt.insert(aa='1'), 1)
|
||||||
self.assertEqual(db.t.insert(a='1'), 2)
|
self.assertEqual(db.tt.insert(aa='1'), 2)
|
||||||
self.assertEqual(db.t.insert(a='1'), 3)
|
self.assertEqual(db.tt.insert(aa='1'), 3)
|
||||||
self.assertEqual(db(db.t.a == '1').count(), 3)
|
self.assertEqual(db(db.tt.aa == '1').count(), 3)
|
||||||
self.assertEqual(db(db.t.a == '1').update(a='2'), 3)
|
self.assertEqual(db(db.tt.aa == '1').update(aa='2'), 3)
|
||||||
self.assertEqual(db(db.t.a == '2').count(), 3)
|
self.assertEqual(db(db.tt.aa == '2').count(), 3)
|
||||||
self.assertEqual(db(db.t.a == '2').delete(), 3)
|
self.assertEqual(db(db.tt.aa == '2').delete(), 3)
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
|
|
||||||
|
|
||||||
class TestSelect(unittest.TestCase):
|
class TestSelect(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a'))
|
db.define_table('tt', Field('aa'))
|
||||||
self.assertEqual(db.t.insert(a='1'), 1)
|
self.assertEqual(db.tt.insert(aa='1'), 1)
|
||||||
self.assertEqual(db.t.insert(a='2'), 2)
|
self.assertEqual(db.tt.insert(aa='2'), 2)
|
||||||
self.assertEqual(db.t.insert(a='3'), 3)
|
self.assertEqual(db.tt.insert(aa='3'), 3)
|
||||||
self.assertEqual(len(db(db.t.id > 0).select()), 3)
|
self.assertEqual(len(db(db.tt.id > 0).select()), 3)
|
||||||
self.assertEqual(db(db.t.id > 0).select(orderby=~db.t.a
|
self.assertEqual(db(db.tt.id > 0).select(orderby=~db.tt.aa
|
||||||
| db.t.id)[0].a, '3')
|
| db.tt.id)[0].aa, '3')
|
||||||
self.assertEqual(len(db(db.t.id > 0).select(limitby=(1, 2))), 1)
|
self.assertEqual(len(db(db.tt.id > 0).select(limitby=(1, 2))), 1)
|
||||||
self.assertEqual(db(db.t.id > 0).select(limitby=(1, 2))[0].a,
|
self.assertEqual(db(db.tt.id > 0).select(limitby=(1, 2))[0].aa,
|
||||||
'2')
|
'2')
|
||||||
self.assertEqual(len(db().select(db.t.ALL)), 3)
|
self.assertEqual(len(db().select(db.tt.ALL)), 3)
|
||||||
self.assertEqual(len(db(db.t.a == None).select()), 0)
|
self.assertEqual(len(db(db.tt.aa == None).select()), 0)
|
||||||
self.assertEqual(len(db(db.t.a != None).select()), 3)
|
self.assertEqual(len(db(db.tt.aa != None).select()), 3)
|
||||||
self.assertEqual(len(db(db.t.a > '1').select()), 2)
|
self.assertEqual(len(db(db.tt.aa > '1').select()), 2)
|
||||||
self.assertEqual(len(db(db.t.a >= '1').select()), 3)
|
self.assertEqual(len(db(db.tt.aa >= '1').select()), 3)
|
||||||
self.assertEqual(len(db(db.t.a == '1').select()), 1)
|
self.assertEqual(len(db(db.tt.aa == '1').select()), 1)
|
||||||
self.assertEqual(len(db(db.t.a != '1').select()), 2)
|
self.assertEqual(len(db(db.tt.aa != '1').select()), 2)
|
||||||
self.assertEqual(len(db(db.t.a < '3').select()), 2)
|
self.assertEqual(len(db(db.tt.aa < '3').select()), 2)
|
||||||
self.assertEqual(len(db(db.t.a <= '3').select()), 3)
|
self.assertEqual(len(db(db.tt.aa <= '3').select()), 3)
|
||||||
self.assertEqual(len(db(db.t.a > '1')(db.t.a < '3').select()), 1)
|
self.assertEqual(len(db(db.tt.aa > '1')(db.tt.aa < '3').select()), 1)
|
||||||
self.assertEqual(len(db((db.t.a > '1') & (db.t.a < '3')).select()), 1)
|
self.assertEqual(len(db((db.tt.aa > '1') & (db.tt.aa < '3')).select()), 1)
|
||||||
self.assertEqual(len(db((db.t.a > '1') | (db.t.a < '3')).select()), 3)
|
self.assertEqual(len(db((db.tt.aa > '1') | (db.tt.aa < '3')).select()), 3)
|
||||||
self.assertEqual(len(db((db.t.a > '1') & ~(db.t.a > '2')).select()), 1)
|
self.assertEqual(len(db((db.tt.aa > '1') & ~(db.tt.aa > '2')).select()), 1)
|
||||||
self.assertEqual(len(db(~(db.t.a > '1') & (db.t.a > '2')).select()), 0)
|
self.assertEqual(len(db(~(db.tt.aa > '1') & (db.tt.aa > '2')).select()), 0)
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
|
|
||||||
|
|
||||||
class TestBelongs(unittest.TestCase):
|
class TestBelongs(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a'))
|
db.define_table('tt', Field('aa'))
|
||||||
self.assertEqual(db.t.insert(a='1'), 1)
|
self.assertEqual(db.tt.insert(aa='1'), 1)
|
||||||
self.assertEqual(db.t.insert(a='2'), 2)
|
self.assertEqual(db.tt.insert(aa='2'), 2)
|
||||||
self.assertEqual(db.t.insert(a='3'), 3)
|
self.assertEqual(db.tt.insert(aa='3'), 3)
|
||||||
self.assertEqual(len(db(db.t.a.belongs(('1', '3'))).select()),
|
self.assertEqual(len(db(db.tt.aa.belongs(('1', '3'))).select()),
|
||||||
2)
|
2)
|
||||||
self.assertEqual(len(db(db.t.a.belongs(db(db.t.id
|
self.assertEqual(len(db(db.tt.aa.belongs(db(db.tt.id
|
||||||
> 2)._select(db.t.a))).select()), 1)
|
> 2)._select(db.tt.aa))).select()), 1)
|
||||||
self.assertEqual(len(db(db.t.a.belongs(db(db.t.a.belongs(('1',
|
self.assertEqual(len(db(db.tt.aa.belongs(db(db.tt.aa.belongs(('1',
|
||||||
'3')))._select(db.t.a))).select()), 2)
|
'3')))._select(db.tt.aa))).select()), 2)
|
||||||
self.assertEqual(len(db(db.t.a.belongs(db(db.t.a.belongs(db
|
self.assertEqual(len(db(db.tt.aa.belongs(db(db.tt.aa.belongs(db
|
||||||
(db.t.a.belongs(('1', '3')))._select(db.t.a)))._select(
|
(db.tt.aa.belongs(('1', '3')))._select(db.tt.aa)))._select(
|
||||||
db.t.a))).select()),
|
db.tt.aa))).select()),
|
||||||
2)
|
2)
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
|
|
||||||
|
|
||||||
class TestContains(unittest.TestCase):
|
class TestContains(unittest.TestCase):
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a', 'list:string'))
|
db.define_table('tt', Field('aa', 'list:string'))
|
||||||
self.assertEqual(db.t.insert(a=['aaa','bbb']), 1)
|
self.assertEqual(db.tt.insert(aa=['aaa','bbb']), 1)
|
||||||
self.assertEqual(db.t.insert(a=['bbb','ddd']), 2)
|
self.assertEqual(db.tt.insert(aa=['bbb','ddd']), 2)
|
||||||
self.assertEqual(db.t.insert(a=['eee','aaa']), 3)
|
self.assertEqual(db.tt.insert(aa=['eee','aaa']), 3)
|
||||||
self.assertEqual(len(db(db.t.a.contains('aaa')).select()),
|
self.assertEqual(len(db(db.tt.aa.contains('aaa')).select()),
|
||||||
2)
|
2)
|
||||||
self.assertEqual(len(db(db.t.a.contains('bbb')).select()),
|
self.assertEqual(len(db(db.tt.aa.contains('bbb')).select()),
|
||||||
2)
|
2)
|
||||||
self.assertEqual(len(db(db.t.a.contains('aa')).select()),
|
self.assertEqual(len(db(db.tt.aa.contains('aa')).select()),
|
||||||
0)
|
0)
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
|
|
||||||
|
|
||||||
class TestLike(unittest.TestCase):
|
class TestLike(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a'))
|
db.define_table('tt', Field('aa'))
|
||||||
self.assertEqual(db.t.insert(a='abc'), 1)
|
self.assertEqual(db.tt.insert(aa='abc'), 1)
|
||||||
self.assertEqual(len(db(db.t.a.like('a%')).select()), 1)
|
self.assertEqual(len(db(db.tt.aa.like('a%')).select()), 1)
|
||||||
self.assertEqual(len(db(db.t.a.like('%b%')).select()), 1)
|
self.assertEqual(len(db(db.tt.aa.like('%b%')).select()), 1)
|
||||||
self.assertEqual(len(db(db.t.a.like('%c')).select()), 1)
|
self.assertEqual(len(db(db.tt.aa.like('%c')).select()), 1)
|
||||||
self.assertEqual(len(db(db.t.a.like('%d%')).select()), 0)
|
self.assertEqual(len(db(db.tt.aa.like('%d%')).select()), 0)
|
||||||
self.assertEqual(len(db(db.t.a.lower().like('A%')).select()), 1)
|
self.assertEqual(len(db(db.tt.aa.lower().like('A%')).select()), 1)
|
||||||
self.assertEqual(len(db(db.t.a.lower().like('%B%')).select()),
|
self.assertEqual(len(db(db.tt.aa.lower().like('%B%')).select()),
|
||||||
1)
|
1)
|
||||||
self.assertEqual(len(db(db.t.a.lower().like('%C')).select()), 1)
|
self.assertEqual(len(db(db.tt.aa.lower().like('%C')).select()), 1)
|
||||||
self.assertEqual(len(db(db.t.a.upper().like('A%')).select()), 1)
|
self.assertEqual(len(db(db.tt.aa.upper().like('A%')).select()), 1)
|
||||||
self.assertEqual(len(db(db.t.a.upper().like('%B%')).select()),
|
self.assertEqual(len(db(db.tt.aa.upper().like('%B%')).select()),
|
||||||
1)
|
1)
|
||||||
self.assertEqual(len(db(db.t.a.upper().like('%C')).select()), 1)
|
self.assertEqual(len(db(db.tt.aa.upper().like('%C')).select()), 1)
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
db.define_table('t', Field('a', 'integer'))
|
db.define_table('tt', Field('aa', 'integer'))
|
||||||
self.assertEqual(db.t.insert(a=1111111111), 1)
|
self.assertEqual(db.tt.insert(aa=1111111111), 1)
|
||||||
self.assertEqual(len(db(db.t.a.like('1%')).select()), 1)
|
self.assertEqual(len(db(db.tt.aa.like('1%')).select()), 1)
|
||||||
self.assertEqual(len(db(db.t.a.like('2%')).select()), 0)
|
self.assertEqual(len(db(db.tt.aa.like('2%')).select()), 0)
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
|
|
||||||
|
|
||||||
class TestDatetime(unittest.TestCase):
|
class TestDatetime(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a', 'datetime'))
|
db.define_table('tt', Field('aa', 'datetime'))
|
||||||
self.assertEqual(db.t.insert(a=datetime.datetime(1971, 12, 21,
|
self.assertEqual(db.tt.insert(aa=datetime.datetime(1971, 12, 21,
|
||||||
11, 30)), 1)
|
11, 30)), 1)
|
||||||
self.assertEqual(db.t.insert(a=datetime.datetime(1971, 11, 21,
|
self.assertEqual(db.tt.insert(aa=datetime.datetime(1971, 11, 21,
|
||||||
10, 30)), 2)
|
10, 30)), 2)
|
||||||
self.assertEqual(db.t.insert(a=datetime.datetime(1970, 12, 21,
|
self.assertEqual(db.tt.insert(aa=datetime.datetime(1970, 12, 21,
|
||||||
9, 30)), 3)
|
9, 30)), 3)
|
||||||
self.assertEqual(len(db(db.t.a == datetime.datetime(1971, 12,
|
self.assertEqual(len(db(db.tt.aa == datetime.datetime(1971, 12,
|
||||||
21, 11, 30)).select()), 1)
|
21, 11, 30)).select()), 1)
|
||||||
self.assertEqual(db(db.t.a.year() == 1971).count(), 2)
|
self.assertEqual(db(db.tt.aa.year() == 1971).count(), 2)
|
||||||
self.assertEqual(db(db.t.a.month() == 12).count(), 2)
|
self.assertEqual(db(db.tt.aa.month() == 12).count(), 2)
|
||||||
self.assertEqual(db(db.t.a.day() == 21).count(), 3)
|
self.assertEqual(db(db.tt.aa.day() == 21).count(), 3)
|
||||||
self.assertEqual(db(db.t.a.hour() == 11).count(), 1)
|
self.assertEqual(db(db.tt.aa.hour() == 11).count(), 1)
|
||||||
self.assertEqual(db(db.t.a.minutes() == 30).count(), 3)
|
self.assertEqual(db(db.tt.aa.minutes() == 30).count(), 3)
|
||||||
self.assertEqual(db(db.t.a.seconds() == 0).count(), 3)
|
self.assertEqual(db(db.tt.aa.seconds() == 0).count(), 3)
|
||||||
self.assertEqual(db(db.t.a.epoch()<365*24*3600).count(),1)
|
self.assertEqual(db(db.tt.aa.epoch()<365*24*3600).count(),1)
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
|
|
||||||
|
|
||||||
class TestExpressions(unittest.TestCase):
|
class TestExpressions(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a', 'integer'))
|
db.define_table('tt', Field('aa', 'integer'))
|
||||||
self.assertEqual(db.t.insert(a=1), 1)
|
self.assertEqual(db.tt.insert(aa=1), 1)
|
||||||
self.assertEqual(db.t.insert(a=2), 2)
|
self.assertEqual(db.tt.insert(aa=2), 2)
|
||||||
self.assertEqual(db.t.insert(a=3), 3)
|
self.assertEqual(db.tt.insert(aa=3), 3)
|
||||||
self.assertEqual(db(db.t.a == 3).update(a=db.t.a + 1), 1)
|
self.assertEqual(db(db.tt.aa == 3).update(aa=db.tt.aa + 1), 1)
|
||||||
self.assertEqual(db(db.t.a == 4).count(), 1)
|
self.assertEqual(db(db.tt.aa == 4).count(), 1)
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
|
|
||||||
|
|
||||||
class TestJoin(unittest.TestCase):
|
class TestJoin(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t1', Field('a'))
|
db.define_table('t1', Field('aa'))
|
||||||
db.define_table('t2', Field('a'), Field('b', db.t1))
|
db.define_table('t2', Field('aa'), Field('b', db.t1))
|
||||||
i1 = db.t1.insert(a='1')
|
i1 = db.t1.insert(aa='1')
|
||||||
i2 = db.t1.insert(a='2')
|
i2 = db.t1.insert(aa='2')
|
||||||
i3 = db.t1.insert(a='3')
|
i3 = db.t1.insert(aa='3')
|
||||||
db.t2.insert(a='4', b=i1)
|
db.t2.insert(aa='4', b=i1)
|
||||||
db.t2.insert(a='5', b=i2)
|
db.t2.insert(aa='5', b=i2)
|
||||||
db.t2.insert(a='6', b=i2)
|
db.t2.insert(aa='6', b=i2)
|
||||||
self.assertEqual(len(db(db.t1.id
|
self.assertEqual(len(db(db.t1.id
|
||||||
== db.t2.b).select(orderby=db.t1.a
|
== db.t2.b).select(orderby=db.t1.aa
|
||||||
| db.t2.a)), 3)
|
| db.t2.aa)), 3)
|
||||||
self.assertEqual(db(db.t1.id == db.t2.b).select(orderby=db.t1.a
|
self.assertEqual(db(db.t1.id == db.t2.b).select(orderby=db.t1.aa
|
||||||
| db.t2.a)[2].t1.a, '2')
|
| db.t2.aa)[2].t1.aa, '2')
|
||||||
self.assertEqual(db(db.t1.id == db.t2.b).select(orderby=db.t1.a
|
self.assertEqual(db(db.t1.id == db.t2.b).select(orderby=db.t1.aa
|
||||||
| db.t2.a)[2].t2.a, '6')
|
| db.t2.aa)[2].t2.aa, '6')
|
||||||
self.assertEqual(len(db().select(db.t1.ALL, db.t2.ALL,
|
self.assertEqual(len(db().select(db.t1.ALL, db.t2.ALL,
|
||||||
left=db.t2.on(db.t1.id == db.t2.b),
|
left=db.t2.on(db.t1.id == db.t2.b),
|
||||||
orderby=db.t1.a | db.t2.a)), 4)
|
orderby=db.t1.aa | db.t2.aa)), 4)
|
||||||
self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
|
self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
|
||||||
left=db.t2.on(db.t1.id == db.t2.b),
|
left=db.t2.on(db.t1.id == db.t2.b),
|
||||||
orderby=db.t1.a | db.t2.a)[2].t1.a, '2')
|
orderby=db.t1.aa | db.t2.aa)[2].t1.aa, '2')
|
||||||
self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
|
self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
|
||||||
left=db.t2.on(db.t1.id == db.t2.b),
|
left=db.t2.on(db.t1.id == db.t2.b),
|
||||||
orderby=db.t1.a | db.t2.a)[2].t2.a, '6')
|
orderby=db.t1.aa | db.t2.aa)[2].t2.aa, '6')
|
||||||
self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
|
self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
|
||||||
left=db.t2.on(db.t1.id == db.t2.b),
|
left=db.t2.on(db.t1.id == db.t2.b),
|
||||||
orderby=db.t1.a | db.t2.a)[3].t1.a, '3')
|
orderby=db.t1.aa | db.t2.aa)[3].t1.aa, '3')
|
||||||
self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
|
self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
|
||||||
left=db.t2.on(db.t1.id == db.t2.b),
|
left=db.t2.on(db.t1.id == db.t2.b),
|
||||||
orderby=db.t1.a | db.t2.a)[3].t2.a, None)
|
orderby=db.t1.aa | db.t2.aa)[3].t2.aa, None)
|
||||||
self.assertEqual(len(db().select(db.t1.ALL, db.t2.id.count(),
|
self.assertEqual(len(db().select(db.t1.aa, db.t2.id.count(),
|
||||||
left=db.t2.on(db.t1.id == db.t2.b),
|
left=db.t2.on(db.t1.id == db.t2.b),
|
||||||
orderby=db.t1.a | db.t2.a, groupby=db.t1.a)),
|
orderby=db.t1.aa, groupby=db.t1.aa)),
|
||||||
3)
|
3)
|
||||||
self.assertEqual(db().select(db.t1.ALL, db.t2.id.count(),
|
self.assertEqual(db().select(db.t1.aa, db.t2.id.count(),
|
||||||
left=db.t2.on(db.t1.id == db.t2.b),
|
left=db.t2.on(db.t1.id == db.t2.b),
|
||||||
orderby=db.t1.a | db.t2.a,
|
orderby=db.t1.aa,
|
||||||
groupby=db.t1.a)[0]._extra[db.t2.id.count()],
|
groupby=db.t1.aa)[0]._extra[db.t2.id.count()],
|
||||||
1)
|
1)
|
||||||
self.assertEqual(db().select(db.t1.ALL, db.t2.id.count(),
|
self.assertEqual(db().select(db.t1.aa, db.t2.id.count(),
|
||||||
left=db.t2.on(db.t1.id == db.t2.b),
|
left=db.t2.on(db.t1.id == db.t2.b),
|
||||||
orderby=db.t1.a | db.t2.a,
|
orderby=db.t1.aa,
|
||||||
groupby=db.t1.a)[1]._extra[db.t2.id.count()],
|
groupby=db.t1.aa)[1]._extra[db.t2.id.count()],
|
||||||
2)
|
2)
|
||||||
self.assertEqual(db().select(db.t1.ALL, db.t2.id.count(),
|
self.assertEqual(db().select(db.t1.aa, db.t2.id.count(),
|
||||||
left=db.t2.on(db.t1.id == db.t2.b),
|
left=db.t2.on(db.t1.id == db.t2.b),
|
||||||
orderby=db.t1.a | db.t2.a,
|
orderby=db.t1.aa,
|
||||||
groupby=db.t1.a)[2]._extra[db.t2.id.count()],
|
groupby=db.t1.aa)[2]._extra[db.t2.id.count()],
|
||||||
0)
|
0)
|
||||||
db.t1.drop()
|
|
||||||
db.t2.drop()
|
db.t2.drop()
|
||||||
|
db.t1.drop()
|
||||||
|
|
||||||
db.define_table('person',Field('name'))
|
db.define_table('person',Field('name'))
|
||||||
id = db.person.insert(name="max")
|
id = db.person.insert(name="max")
|
||||||
self.assertEqual(id.name,'max')
|
self.assertEqual(id.name,'max')
|
||||||
db.define_table('dog',Field('name'),Field('owner','reference person'))
|
db.define_table('dog',Field('name'),Field('ownerperson','reference person'))
|
||||||
db.dog.insert(name='skipper',owner=1)
|
db.dog.insert(name='skipper',ownerperson=1)
|
||||||
row = db(db.person.id==db.dog.owner).select().first()
|
row = db(db.person.id==db.dog.ownerperson).select().first()
|
||||||
self.assertEqual(row[db.person.name],'max')
|
self.assertEqual(row[db.person.name],'max')
|
||||||
self.assertEqual(row['person.name'],'max')
|
self.assertEqual(row['person.name'],'max')
|
||||||
db.dog.drop()
|
db.dog.drop()
|
||||||
self.assertEqual(len(db.person._referenced_by),0)
|
self.assertEqual(len(db.person._referenced_by),0)
|
||||||
db.person.drop()
|
db.person.drop()
|
||||||
|
|
||||||
class TestMinMaxSum(unittest.TestCase):
|
class TestMinMaxSumAvg(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a', 'integer'))
|
db.define_table('tt', Field('aa', 'integer'))
|
||||||
self.assertEqual(db.t.insert(a=1), 1)
|
self.assertEqual(db.tt.insert(aa=1), 1)
|
||||||
self.assertEqual(db.t.insert(a=2), 2)
|
self.assertEqual(db.tt.insert(aa=2), 2)
|
||||||
self.assertEqual(db.t.insert(a=3), 3)
|
self.assertEqual(db.tt.insert(aa=3), 3)
|
||||||
s = db.t.a.min()
|
s = db.tt.aa.min()
|
||||||
self.assertEqual(db(db.t.id > 0).select(s)[0]._extra[s], 1)
|
self.assertEqual(db(db.tt.id > 0).select(s)[0]._extra[s], 1)
|
||||||
self.assertEqual(db(db.t.id > 0).select(s).first()[s], 1)
|
self.assertEqual(db(db.tt.id > 0).select(s).first()[s], 1)
|
||||||
self.assertEqual(db().select(s).first()[s], 1)
|
self.assertEqual(db().select(s).first()[s], 1)
|
||||||
s = db.t.a.max()
|
s = db.tt.aa.max()
|
||||||
self.assertEqual(db().select(s).first()[s], 3)
|
self.assertEqual(db().select(s).first()[s], 3)
|
||||||
s = db.t.a.sum()
|
s = db.tt.aa.sum()
|
||||||
self.assertEqual(db().select(s).first()[s], 6)
|
self.assertEqual(db().select(s).first()[s], 6)
|
||||||
s = db.t.a.count()
|
s = db.tt.aa.count()
|
||||||
self.assertEqual(db().select(s).first()[s], 3)
|
self.assertEqual(db().select(s).first()[s], 3)
|
||||||
db.t.drop()
|
s = db.tt.aa.avg()
|
||||||
|
self.assertEqual(db().select(s).first()[s], 2)
|
||||||
|
db.tt.drop()
|
||||||
|
|
||||||
|
|
||||||
class TestCache(unittest.TestCase):
|
class TestCache(unittest.TestCase):
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
from cache import CacheInRam
|
from cache import CacheInRam
|
||||||
cache = CacheInRam()
|
cache = CacheInRam()
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a'))
|
db.define_table('tt', Field('aa'))
|
||||||
db.t.insert(a='1')
|
db.tt.insert(aa='1')
|
||||||
r0 = db().select(db.t.ALL)
|
r0 = db().select(db.tt.ALL)
|
||||||
r1 = db().select(db.t.ALL, cache=(cache, 1000))
|
r1 = db().select(db.tt.ALL, cache=(cache, 1000))
|
||||||
self.assertEqual(len(r0),len(r1))
|
self.assertEqual(len(r0),len(r1))
|
||||||
r2 = db().select(db.t.ALL, cache=(cache, 1000))
|
r2 = db().select(db.tt.ALL, cache=(cache, 1000))
|
||||||
self.assertEqual(len(r0),len(r2))
|
self.assertEqual(len(r0),len(r2))
|
||||||
r3 = db().select(db.t.ALL, cache=(cache, 1000), cacheable=True)
|
r3 = db().select(db.tt.ALL, cache=(cache, 1000), cacheable=True)
|
||||||
self.assertEqual(len(r0),len(r3))
|
self.assertEqual(len(r0),len(r3))
|
||||||
r4 = db().select(db.t.ALL, cache=(cache, 1000), cacheable=True)
|
r4 = db().select(db.tt.ALL, cache=(cache, 1000), cacheable=True)
|
||||||
self.assertEqual(len(r0),len(r4))
|
self.assertEqual(len(r0),len(r4))
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
|
|
||||||
|
|
||||||
class TestMigrations(unittest.TestCase):
|
class TestMigrations(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite://.storage.db')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a'), migrate='.storage.table')
|
db.define_table('tt', Field('aa'), migrate='.storage.table')
|
||||||
db.commit()
|
db.commit()
|
||||||
db.close()
|
db.close()
|
||||||
db = DAL('sqlite://.storage.db')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a'), Field('b'),
|
db.define_table('tt', Field('aa'), Field('b'),
|
||||||
migrate='.storage.table')
|
migrate='.storage.table')
|
||||||
db.commit()
|
db.commit()
|
||||||
db.close()
|
db.close()
|
||||||
db = DAL('sqlite://.storage.db')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a'), Field('b', 'text'),
|
db.define_table('tt', Field('aa'), Field('b', 'text'),
|
||||||
migrate='.storage.table')
|
migrate='.storage.table')
|
||||||
db.commit()
|
db.commit()
|
||||||
db.close()
|
db.close()
|
||||||
db = DAL('sqlite://.storage.db')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a'), migrate='.storage.table')
|
db.define_table('tt', Field('aa'), migrate='.storage.table')
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
db.commit()
|
db.commit()
|
||||||
db.close()
|
db.close()
|
||||||
|
|
||||||
@@ -500,81 +511,81 @@ class TestMigrations(unittest.TestCase):
|
|||||||
if os.path.exists('.storage.table'):
|
if os.path.exists('.storage.table'):
|
||||||
os.unlink('.storage.table')
|
os.unlink('.storage.table')
|
||||||
|
|
||||||
class TestReferece(unittest.TestCase):
|
class TestReference(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('name'), Field('a','reference t'))
|
db.define_table('tt', Field('name'), Field('aa','reference tt'))
|
||||||
db.commit()
|
db.commit()
|
||||||
x = db.t.insert(name='max')
|
x = db.tt.insert(name='max')
|
||||||
assert x.id == 1
|
assert x.id == 1
|
||||||
assert x['id'] == 1
|
assert x['id'] == 1
|
||||||
x.a = x
|
x.aa = x
|
||||||
assert x.a == 1
|
assert x.aa == 1
|
||||||
x.update_record()
|
x.update_record()
|
||||||
y = db.t[1]
|
y = db.tt[1]
|
||||||
assert y.a == 1
|
assert y.aa == 1
|
||||||
assert y.a.a.a.a.a.a.name == 'max'
|
assert y.aa.aa.aa.aa.aa.aa.name == 'max'
|
||||||
z=db.t.insert(name='xxx', a = y)
|
z=db.tt.insert(name='xxx', aa = y)
|
||||||
assert z.a == y.id
|
assert z.aa == y.id
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
class TestClientLevelOps(unittest.TestCase):
|
class TestClientLevelOps(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a'))
|
db.define_table('tt', Field('aa'))
|
||||||
db.commit()
|
db.commit()
|
||||||
db.t.insert(a="test")
|
db.tt.insert(aa="test")
|
||||||
rows1 = db(db.t.id>0).select()
|
rows1 = db(db.tt.id>0).select()
|
||||||
rows2 = db(db.t.id>0).select()
|
rows2 = db(db.tt.id>0).select()
|
||||||
rows3 = rows1 & rows2
|
rows3 = rows1 & rows2
|
||||||
assert len(rows3) == 2
|
assert len(rows3) == 2
|
||||||
rows4 = rows1 | rows2
|
rows4 = rows1 | rows2
|
||||||
assert len(rows4) == 1
|
assert len(rows4) == 1
|
||||||
rows5 = rows1.find(lambda row: row.a=="test")
|
rows5 = rows1.find(lambda row: row.aa=="test")
|
||||||
assert len(rows5) == 1
|
assert len(rows5) == 1
|
||||||
rows6 = rows2.exclude(lambda row: row.a=="test")
|
rows6 = rows2.exclude(lambda row: row.aa=="test")
|
||||||
assert len(rows6) == 1
|
assert len(rows6) == 1
|
||||||
rows7 = rows5.sort(lambda row: row.a)
|
rows7 = rows5.sort(lambda row: row.aa)
|
||||||
assert len(rows7) == 1
|
assert len(rows7) == 1
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
|
|
||||||
class TestVirtualFields(unittest.TestCase):
|
class TestVirtualFields(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a'))
|
db.define_table('tt', Field('aa'))
|
||||||
db.commit()
|
db.commit()
|
||||||
db.t.insert(a="test")
|
db.tt.insert(aa="test")
|
||||||
class Compute:
|
class Compute:
|
||||||
def a_upper(row): return row.t.a.upper()
|
def a_upper(row): return row.tt.aa.upper()
|
||||||
db.t.virtualfields.append(Compute())
|
db.tt.virtualfields.append(Compute())
|
||||||
assert db(db.t.id>0).select().first().a_upper == 'TEST'
|
assert db(db.tt.id>0).select().first().a_upper == 'TEST'
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
class TestComputedFields(unittest.TestCase):
|
class TestComputedFields(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t',
|
db.define_table('tt',
|
||||||
Field('a'),
|
Field('aa'),
|
||||||
Field('b',default='x'),
|
Field('bb',default='x'),
|
||||||
Field('c',compute=lambda r: r.a+r.b))
|
Field('cc',compute=lambda r: r.aa+r.bb))
|
||||||
db.commit()
|
db.commit()
|
||||||
id = db.t.insert(a="z")
|
id = db.tt.insert(aa="z")
|
||||||
self.assertEqual(db.t[id].c,'zx')
|
self.assertEqual(db.tt[id].cc,'zx')
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
class TestImportExportFields(unittest.TestCase):
|
class TestImportExportFields(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('person', Field('name'))
|
db.define_table('person', Field('name'))
|
||||||
db.define_table('pet',Field('friend',db.person),Field('name'))
|
db.define_table('pet',Field('friend',db.person),Field('name'))
|
||||||
for n in range(2):
|
for n in range(2):
|
||||||
@@ -598,7 +609,7 @@ class TestImportExportFields(unittest.TestCase):
|
|||||||
class TestImportExportUuidFields(unittest.TestCase):
|
class TestImportExportUuidFields(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('person', Field('name'),Field('uuid'))
|
db.define_table('person', Field('name'),Field('uuid'))
|
||||||
db.define_table('pet',Field('friend',db.person),Field('name'))
|
db.define_table('pet',Field('friend',db.person),Field('name'))
|
||||||
for n in range(2):
|
for n in range(2):
|
||||||
@@ -622,7 +633,7 @@ class TestImportExportUuidFields(unittest.TestCase):
|
|||||||
class TestDALDictImportExport(unittest.TestCase):
|
class TestDALDictImportExport(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('person', Field('name', default="Michael"),Field('uuid'))
|
db.define_table('person', Field('name', default="Michael"),Field('uuid'))
|
||||||
db.define_table('pet',Field('friend',db.person),Field('name'))
|
db.define_table('pet',Field('friend',db.person),Field('name'))
|
||||||
dbdict = db.as_dict(flat=True, sanitize=False)
|
dbdict = db.as_dict(flat=True, sanitize=False)
|
||||||
@@ -635,77 +646,88 @@ class TestDALDictImportExport(unittest.TestCase):
|
|||||||
assert dbdict["items"]["person"]["items"]["name"]["default"] == db.person.name.default
|
assert dbdict["items"]["person"]["items"]["name"]["default"] == db.person.name.default
|
||||||
assert dbdict
|
assert dbdict
|
||||||
|
|
||||||
db2 = DAL(dbdict)
|
db2 = DAL(dbdict, check_reserved=['all'])
|
||||||
assert len(db.tables) == len(db2.tables)
|
assert len(db.tables) == len(db2.tables)
|
||||||
assert hasattr(db2, "pet") and isinstance(db2.pet, Table)
|
assert hasattr(db2, "pet") and isinstance(db2.pet, Table)
|
||||||
assert hasattr(db2.pet, "friend") and isinstance(db2.pet.friend, Field)
|
assert hasattr(db2.pet, "friend") and isinstance(db2.pet.friend, Field)
|
||||||
|
db.pet.drop()
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
db2.commit()
|
||||||
|
|
||||||
have_serializers = True
|
have_serializers = True
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import serializers
|
import serializers
|
||||||
dbjson = db.as_json(sanitize=False)
|
dbjson = db.as_json(sanitize=False)
|
||||||
assert isinstance(dbjson, basestring) and len(dbjson) > 0
|
assert isinstance(dbjson, basestring) and len(dbjson) > 0
|
||||||
db3 = DAL(serializers.loads_json(dbjson))
|
|
||||||
|
unicode_keys = True
|
||||||
|
if sys.version < "2.6.5":
|
||||||
|
unicode_keys = False
|
||||||
|
db3 = DAL(serializers.loads_json(dbjson,
|
||||||
|
unicode_keys=unicode_keys))
|
||||||
assert hasattr(db3, "person") and hasattr(db3.person, "uuid") and\
|
assert hasattr(db3, "person") and hasattr(db3.person, "uuid") and\
|
||||||
db3.person.uuid.type == db.person.uuid.type
|
db3.person.uuid.type == db.person.uuid.type
|
||||||
db3.pet.drop()
|
|
||||||
db3.person.drop()
|
db3.person.drop()
|
||||||
db3.commit()
|
db3.commit()
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
mpfc = "Monty Python's Flying Circus"
|
mpfc = "Monty Python's Flying Circus"
|
||||||
dbdict4 = {"uri": 'sqlite:memory:',
|
dbdict4 = {"uri": DEFAULT_URI,
|
||||||
"items":{"staff":{"items": {"name":
|
"items":{"staff":{"items": {"name":
|
||||||
{"default":"Michael"},
|
{"default":"Michael"},
|
||||||
"food":
|
"food":
|
||||||
{"default":"Spam"},
|
{"default":"Spam"},
|
||||||
"show":
|
"tvshow":
|
||||||
{"type": "reference show"}
|
{"type": "reference tvshow"}
|
||||||
}},
|
}},
|
||||||
"show":{"items": {"name":
|
"tvshow":{"items": {"name":
|
||||||
{"default":mpfc},
|
{"default":mpfc},
|
||||||
"rating":
|
"rating":
|
||||||
{"type":"double"}}}}}
|
{"type":"double"}}}}}
|
||||||
db4 = DAL(dbdict4)
|
db4 = DAL(dbdict4, check_reserved=['all'])
|
||||||
assert "staff" in db4.tables
|
assert "staff" in db4.tables
|
||||||
assert "name" in db4.staff
|
assert "name" in db4.staff
|
||||||
assert db4.show.rating.type == "double"
|
assert db4.tvshow.rating.type == "double"
|
||||||
assert (db4.show.insert(), db4.show.insert(name="Loriot"),
|
assert (db4.tvshow.insert(), db4.tvshow.insert(name="Loriot"),
|
||||||
db4.show.insert(name="Il Mattatore")) == (1, 2, 3)
|
db4.tvshow.insert(name="Il Mattatore")) == (1, 2, 3)
|
||||||
assert db4(db4.show).select().first().id == 1
|
assert db4(db4.tvshow).select().first().id == 1
|
||||||
assert db4(db4.show).select().first().name == mpfc
|
assert db4(db4.tvshow).select().first().name == mpfc
|
||||||
|
|
||||||
dbdict5 = {"uri": 'sqlite:memory:'}
|
db4.staff.drop()
|
||||||
db5 = DAL(dbdict5)
|
db4.tvshow.drop()
|
||||||
|
db4.commit()
|
||||||
|
|
||||||
|
dbdict5 = {"uri": DEFAULT_URI}
|
||||||
|
db5 = DAL(dbdict5, check_reserved=['all'])
|
||||||
assert db5.tables in ([], None)
|
assert db5.tables in ([], None)
|
||||||
assert not (str(db5) in ("", None))
|
assert not (str(db5) in ("", None))
|
||||||
|
|
||||||
dbdict6 = {"uri": 'sqlite:memory:',
|
dbdict6 = {"uri": DEFAULT_URI,
|
||||||
"items":{"staff":{},
|
"items":{"staff":{},
|
||||||
"show":{"items": {"name": {},
|
"tvshow":{"items": {"name": {},
|
||||||
"rating":
|
"rating":
|
||||||
{"type":"double"}}}}}
|
{"type":"double"}
|
||||||
db6 = DAL(dbdict6)
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
db6 = DAL(dbdict6, check_reserved=['all'])
|
||||||
|
|
||||||
assert len(db6["staff"].fields) == 1
|
assert len(db6["staff"].fields) == 1
|
||||||
assert "name" in db6["show"].fields
|
assert "name" in db6["tvshow"].fields
|
||||||
|
|
||||||
assert db6.staff.insert() is not None
|
assert db6.staff.insert() is not None
|
||||||
assert db6(db6.staff).select().first().id == 1
|
assert db6(db6.staff).select().first().id == 1
|
||||||
|
|
||||||
|
|
||||||
db6.staff.drop()
|
db6.staff.drop()
|
||||||
db6.show.drop()
|
db6.tvshow.drop()
|
||||||
db6.commit()
|
db6.commit()
|
||||||
db4.staff.drop()
|
|
||||||
db4.show.drop()
|
|
||||||
db4.commit()
|
|
||||||
db2.pet.drop()
|
|
||||||
db2.person.drop()
|
|
||||||
db2.commit()
|
|
||||||
db.pet.drop()
|
|
||||||
db.person.drop()
|
|
||||||
db.commit()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import urllib
|
|||||||
import urllib2
|
import urllib2
|
||||||
import Cookie
|
import Cookie
|
||||||
import cStringIO
|
import cStringIO
|
||||||
from email import MIMEBase, MIMEMultipart, MIMEText, Encoders, Header, message_from_string
|
from email import MIMEBase, MIMEMultipart, MIMEText, Encoders, Header, message_from_string, Charset
|
||||||
|
|
||||||
from gluon.contenttype import contenttype
|
from gluon.contenttype import contenttype
|
||||||
from gluon.storage import Storage, StorageList, Settings, Messages
|
from gluon.storage import Storage, StorageList, Settings, Messages
|
||||||
@@ -347,7 +347,10 @@ class Mail(object):
|
|||||||
mail.send_mail() method
|
mail.send_mail() method
|
||||||
self.error: Exception message or None if above was successful
|
self.error: Exception message or None if above was successful
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# We don't want to use base64 encoding for unicode mail
|
||||||
|
Charset.add_charset('utf-8', Charset.QP, Charset.QP, 'utf-8')
|
||||||
|
|
||||||
def encode_header(key):
|
def encode_header(key):
|
||||||
if [c for c in key if 32 > ord(c) or ord(c) > 127]:
|
if [c for c in key if 32 > ord(c) or ord(c) > 127]:
|
||||||
return Header.Header(key.encode('utf-8'), 'utf-8')
|
return Header.Header(key.encode('utf-8'), 'utf-8')
|
||||||
@@ -1752,19 +1755,45 @@ class Auth(object):
|
|||||||
self.add_membership(self.settings.everybody_group_id, user_id)
|
self.add_membership(self.settings.everybody_group_id, user_id)
|
||||||
return user
|
return user
|
||||||
|
|
||||||
def basic(self):
|
def basic(self, basic_auth_realm=False):
|
||||||
"""
|
"""
|
||||||
perform basic login.
|
perform basic login.
|
||||||
|
|
||||||
|
:param basic_auth_realm: optional basic http authentication realm.
|
||||||
|
:type basic_auth_realm: str or unicode or function or callable or boolean.
|
||||||
|
|
||||||
reads current.request.env.http_authorization
|
reads current.request.env.http_authorization
|
||||||
and returns basic_allowed,basic_accepted,user
|
and returns basic_allowed,basic_accepted,user.
|
||||||
|
|
||||||
|
if basic_auth_realm is defined is a callable it's return value
|
||||||
|
is used to set the basic authentication realm, if it's a string
|
||||||
|
its content is used instead. Otherwise basic authentication realm
|
||||||
|
is set to the application name.
|
||||||
|
If basic_auth_realm is None or False (the default) the behavior
|
||||||
|
is to skip sending any challenge.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not self.settings.allow_basic_login:
|
if not self.settings.allow_basic_login:
|
||||||
return (False, False, False)
|
return (False, False, False)
|
||||||
basic = current.request.env.http_authorization
|
basic = current.request.env.http_authorization
|
||||||
|
if basic_auth_realm:
|
||||||
|
if callable(basic_auth_realm):
|
||||||
|
basic_auth_realm = basic_auth_auth()
|
||||||
|
elif isinstance(basic_auth_realm, (unicode, str)):
|
||||||
|
basic_realm = unicode(basic_auth_realm)
|
||||||
|
elif basic_auth_realm is True:
|
||||||
|
basic_realm = u'' + current.request.application
|
||||||
|
http_401 = HTTP(401, u'Not Authorized',
|
||||||
|
**{'WWW-Authenticate': u'Basic realm="' + basic_realm + '"'})
|
||||||
if not basic or not basic[:6].lower() == 'basic ':
|
if not basic or not basic[:6].lower() == 'basic ':
|
||||||
|
if basic_auth_realm:
|
||||||
|
raise http_401
|
||||||
return (True, False, False)
|
return (True, False, False)
|
||||||
(username, password) = base64.b64decode(basic[6:]).split(':')
|
(username, sep, password) = base64.b64decode(basic[6:]).partition(':')
|
||||||
return (True, True, self.login_bare(username, password))
|
is_valid_user = sep and self.login_bare(username, password)
|
||||||
|
if not is_valid_user and basic_auth_realm:
|
||||||
|
raise http_401
|
||||||
|
return (True, True, is_valid_user)
|
||||||
|
|
||||||
def login_user(self, user):
|
def login_user(self, user):
|
||||||
"""
|
"""
|
||||||
@@ -4402,9 +4431,9 @@ class Service(object):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
request = current.request
|
||||||
|
response = current.response
|
||||||
if not data:
|
if not data:
|
||||||
request = current.request
|
|
||||||
response = current.response
|
|
||||||
response.headers['Content-Type'] = 'application/json; charset=utf-8'
|
response.headers['Content-Type'] = 'application/json; charset=utf-8'
|
||||||
try:
|
try:
|
||||||
data = json_parser.loads(request.body.read())
|
data = json_parser.loads(request.body.read())
|
||||||
@@ -4446,6 +4475,8 @@ class Service(object):
|
|||||||
return return_response(id, s)
|
return return_response(id, s)
|
||||||
else:
|
else:
|
||||||
return ''
|
return ''
|
||||||
|
except HTTP, e:
|
||||||
|
raise e
|
||||||
except Service.JsonRpcException, e:
|
except Service.JsonRpcException, e:
|
||||||
return return_error(id, e.code, e.info)
|
return return_error(id, e.code, e.info)
|
||||||
except BaseException:
|
except BaseException:
|
||||||
@@ -4868,7 +4899,7 @@ class Wiki(object):
|
|||||||
everybody = 'everybody'
|
everybody = 'everybody'
|
||||||
rows_page = 25
|
rows_page = 25
|
||||||
def markmin_base(self,body):
|
def markmin_base(self,body):
|
||||||
return MARKMIN(body, extra=self.extra,
|
return MARKMIN(body, extra=self.settings.extra,
|
||||||
url=True, environment=self.env,
|
url=True, environment=self.env,
|
||||||
autolinks=lambda link: expand_one(link, {})).xml()
|
autolinks=lambda link: expand_one(link, {})).xml()
|
||||||
|
|
||||||
@@ -4902,29 +4933,43 @@ class Wiki(object):
|
|||||||
controller, function, args = items[0], items[1], items[2:]
|
controller, function, args = items[0], items[1], items[2:]
|
||||||
return LOAD(controller, function, args=args, ajax=True).xml()
|
return LOAD(controller, function, args=args, ajax=True).xml()
|
||||||
|
|
||||||
|
def get_render(self):
|
||||||
|
if isinstance(self.settings.render, basestring):
|
||||||
|
r = getattr(self, "%s_render" % self.settings.render)
|
||||||
|
elif callable(self.settings.render):
|
||||||
|
r = self.settings.render
|
||||||
|
else:
|
||||||
|
raise ValueError("Invalid render type %s" % type(render))
|
||||||
|
return r
|
||||||
|
|
||||||
def __init__(self, auth, env=None, render='markmin',
|
def __init__(self, auth, env=None, render='markmin',
|
||||||
manage_permissions=False, force_prefix='',
|
manage_permissions=False, force_prefix='',
|
||||||
restrict_search=False, extra=None,
|
restrict_search=False, extra=None,
|
||||||
menu_groups=None, templates=None):
|
menu_groups=None, templates=None):
|
||||||
|
|
||||||
|
settings = self.settings = Settings()
|
||||||
|
|
||||||
|
# render: "markmin", "html", ..., <function>
|
||||||
|
settings.render = render
|
||||||
|
perms = settings.manage_permissions = manage_permissions
|
||||||
|
|
||||||
|
settings.force_prefix = force_prefix
|
||||||
|
settings.restrict_search = restrict_search
|
||||||
|
settings.extra = extra or {}
|
||||||
|
settings.menu_groups = menu_groups
|
||||||
|
settings.templates = templates
|
||||||
|
|
||||||
db = auth.db
|
db = auth.db
|
||||||
self.env = env or {}
|
self.env = env or {}
|
||||||
self.env['component'] = Wiki.component
|
self.env['component'] = Wiki.component
|
||||||
if render == 'markmin':
|
|
||||||
render = self.markmin_render
|
|
||||||
elif render == 'html':
|
|
||||||
render = self.html_render
|
|
||||||
self.render = render
|
|
||||||
self.auth = auth
|
self.auth = auth
|
||||||
self.menu_groups = menu_groups
|
|
||||||
if self.auth.user:
|
if self.auth.user:
|
||||||
self.force_prefix = force_prefix % self.auth.user
|
self.settings.force_prefix = force_prefix % self.auth.user
|
||||||
else:
|
else:
|
||||||
self.force_prefix = force_prefix
|
self.settings.force_prefix = force_prefix
|
||||||
|
|
||||||
self.host = current.request.env.http_host
|
self.host = current.request.env.http_host
|
||||||
perms = self.manage_permissions = manage_permissions
|
|
||||||
self.restrict_search = restrict_search
|
|
||||||
self.extra = extra or {}
|
|
||||||
self.templates = templates
|
|
||||||
|
|
||||||
table_definitions = [
|
table_definitions = [
|
||||||
('wiki_page', {
|
('wiki_page', {
|
||||||
@@ -4944,7 +4989,8 @@ class Wiki(object):
|
|||||||
writable=perms, readable=perms,
|
writable=perms, readable=perms,
|
||||||
default=[Wiki.everybody]),
|
default=[Wiki.everybody]),
|
||||||
Field('changelog'),
|
Field('changelog'),
|
||||||
Field('html', 'text', compute=render,
|
Field('html', 'text',
|
||||||
|
compute=self.get_render(),
|
||||||
readable=False, writable=False),
|
readable=False, writable=False),
|
||||||
auth.signature],
|
auth.signature],
|
||||||
'vars':{'format':'%(title)s'}}),
|
'vars':{'format':'%(title)s'}}),
|
||||||
@@ -4977,8 +5023,9 @@ class Wiki(object):
|
|||||||
args += value['args']
|
args += value['args']
|
||||||
db.define_table(key, *args, **value['vars'])
|
db.define_table(key, *args, **value['vars'])
|
||||||
|
|
||||||
if self.templates is None and not self.manage_permissions:
|
if self.settings.templates is None and not \
|
||||||
self.templates = db.wiki_page.tags.contains('template')&\
|
self.settings.manage_permissions:
|
||||||
|
self.settings.templates = db.wiki_page.tags.contains('template')&\
|
||||||
db.wiki_page.can_read.contains('everybody')
|
db.wiki_page.can_read.contains('everybody')
|
||||||
|
|
||||||
def update_tags_insert(page, id, db=db):
|
def update_tags_insert(page, id, db=db):
|
||||||
@@ -5002,13 +5049,17 @@ class Wiki(object):
|
|||||||
gid = group.id if group else db.auth_group.insert(
|
gid = group.id if group else db.auth_group.insert(
|
||||||
role='wiki_editor')
|
role='wiki_editor')
|
||||||
auth.add_membership(gid)
|
auth.add_membership(gid)
|
||||||
|
|
||||||
|
settings.lock_keys = True
|
||||||
|
|
||||||
# WIKI ACCESS POLICY
|
# WIKI ACCESS POLICY
|
||||||
|
|
||||||
def not_authorized(self, page=None):
|
def not_authorized(self, page=None):
|
||||||
raise HTTP(401)
|
raise HTTP(401)
|
||||||
|
|
||||||
def can_read(self, page):
|
def can_read(self, page):
|
||||||
if 'everybody' in page.can_read or not self.manage_permissions:
|
if 'everybody' in page.can_read or not \
|
||||||
|
self.settings.manage_permissions:
|
||||||
return True
|
return True
|
||||||
elif self.auth.user:
|
elif self.auth.user:
|
||||||
groups = self.auth.user_groups.values()
|
groups = self.auth.user_groups.values()
|
||||||
@@ -5038,11 +5089,11 @@ class Wiki(object):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def can_see_menu(self):
|
def can_see_menu(self):
|
||||||
if self.menu_groups is None:
|
if self.settings.menu_groups is None:
|
||||||
return True
|
return True
|
||||||
if self.auth.user:
|
if self.auth.user:
|
||||||
groups = self.auth.user_groups.values()
|
groups = self.auth.user_groups.values()
|
||||||
if any(t in self.menu_groups for t in groups):
|
if any(t in self.settings.menu_groups for t in groups):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -5079,7 +5130,7 @@ class Wiki(object):
|
|||||||
elif zero == '_cloud':
|
elif zero == '_cloud':
|
||||||
return self.cloud()
|
return self.cloud()
|
||||||
elif zero == '_preview':
|
elif zero == '_preview':
|
||||||
return self.preview(self.render)
|
return self.preview(self.get_render())
|
||||||
|
|
||||||
def first_paragraph(self, page):
|
def first_paragraph(self, page):
|
||||||
if not self.can_read(page):
|
if not self.can_read(page):
|
||||||
@@ -5147,9 +5198,9 @@ class Wiki(object):
|
|||||||
title_guess = ' '.join(c.capitalize() for c in slug.split('-'))
|
title_guess = ' '.join(c.capitalize() for c in slug.split('-'))
|
||||||
if not page:
|
if not page:
|
||||||
if not (self.can_manage() or
|
if not (self.can_manage() or
|
||||||
slug.startswith(self.force_prefix)):
|
slug.startswith(self.settings.force_prefix)):
|
||||||
current.session.flash = 'slug must have "%s" prefix' \
|
current.session.flash = 'slug must have "%s" prefix' \
|
||||||
% self.force_prefix
|
% self.settings.force_prefix
|
||||||
redirect(URL(args=('_create')))
|
redirect(URL(args=('_create')))
|
||||||
db.wiki_page.can_read.default = [Wiki.everybody]
|
db.wiki_page.can_read.default = [Wiki.everybody]
|
||||||
db.wiki_page.can_edit.default = [auth.user_group_role()]
|
db.wiki_page.can_edit.default = [auth.user_group_role()]
|
||||||
@@ -5205,7 +5256,10 @@ class Wiki(object):
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
""" % dict(url=URL(args=('_preview')), urlmedia=URL(extension='load',args=('_editmedia'),vars=dict(embedded=1)))
|
""" % dict(url=URL(args=('_preview', slug)),
|
||||||
|
urlmedia=URL(extension='load',
|
||||||
|
args=('_editmedia',slug),
|
||||||
|
vars=dict(embedded=1)))
|
||||||
return dict(content=TAG[''](form, SCRIPT(script)))
|
return dict(content=TAG[''](form, SCRIPT(script)))
|
||||||
|
|
||||||
def editmedia(self, slug):
|
def editmedia(self, slug):
|
||||||
@@ -5251,14 +5305,15 @@ class Wiki(object):
|
|||||||
options=[OPTION(row.slug,_value=row.id) for row in slugs]
|
options=[OPTION(row.slug,_value=row.id) for row in slugs]
|
||||||
options.insert(0, OPTION('',_value=''))
|
options.insert(0, OPTION('',_value=''))
|
||||||
fields = [Field("slug", default=current.request.args(1) or
|
fields = [Field("slug", default=current.request.args(1) or
|
||||||
self.force_prefix,
|
self.settings.force_prefix,
|
||||||
requires=(IS_SLUG(), IS_NOT_IN_DB(db,db.wiki_page.slug))),]
|
requires=(IS_SLUG(), IS_NOT_IN_DB(db,db.wiki_page.slug))),]
|
||||||
if self.templates:
|
if self.settings.templates:
|
||||||
fields.append(
|
fields.append(
|
||||||
Field("from_template", "reference wiki_page",
|
Field("from_template", "reference wiki_page",
|
||||||
requires=IS_EMPTY_OR(IS_IN_DB(db(self.templates),
|
requires=IS_EMPTY_OR(
|
||||||
db.wiki_page._id,
|
IS_IN_DB(db(self.settings.templates),
|
||||||
'%(slug)s')),
|
db.wiki_page._id,
|
||||||
|
'%(slug)s')),
|
||||||
comment=current.T(
|
comment=current.T(
|
||||||
"Choose Template or empty for new Page")))
|
"Choose Template or empty for new Page")))
|
||||||
form = SQLFORM.factory(*fields, **dict(_class="well span6"))
|
form = SQLFORM.factory(*fields, **dict(_class="well span6"))
|
||||||
@@ -5300,7 +5355,7 @@ class Wiki(object):
|
|||||||
request, db = current.request, self.auth.db
|
request, db = current.request, self.auth.db
|
||||||
media = db.wiki_media(id)
|
media = db.wiki_media(id)
|
||||||
if media:
|
if media:
|
||||||
if self.manage_permissions:
|
if self.settings.manage_permissions:
|
||||||
page = db.wiki_page(media.wiki_page)
|
page = db.wiki_page(media.wiki_page)
|
||||||
if not self.can_read(page):
|
if not self.can_read(page):
|
||||||
return self.not_authorized(page)
|
return self.not_authorized(page)
|
||||||
@@ -5399,7 +5454,7 @@ class Wiki(object):
|
|||||||
query = (db.wiki_page.id == db.wiki_tag.wiki_page) &\
|
query = (db.wiki_page.id == db.wiki_tag.wiki_page) &\
|
||||||
(db.wiki_tag.name.belongs(tags))
|
(db.wiki_tag.name.belongs(tags))
|
||||||
query = query | db.wiki_page.title.contains(request.vars.q)
|
query = query | db.wiki_page.title.contains(request.vars.q)
|
||||||
if self.restrict_search and not self.manage():
|
if self.settings.restrict_search and not self.manage():
|
||||||
query = query & (db.wiki_page.created_by == self.auth.user_id)
|
query = query & (db.wiki_page.created_by == self.auth.user_id)
|
||||||
pages = db(query).select(count,
|
pages = db(query).select(count,
|
||||||
*fields, **dict(orderby=orderby or ~count,
|
*fields, **dict(orderby=orderby or ~count,
|
||||||
@@ -5460,6 +5515,7 @@ class Wiki(object):
|
|||||||
request = current.request
|
request = current.request
|
||||||
return render(request.post_vars)
|
return render(request.post_vars)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import doctest
|
import doctest
|
||||||
doctest.testmod()
|
doctest.testmod()
|
||||||
|
|||||||
@@ -171,19 +171,29 @@ class IS_MATCH(Validator):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, expression, error_message='invalid expression',
|
def __init__(self, expression, error_message='invalid expression',
|
||||||
strict=False, search=False, extract=False):
|
strict=False, search=False, extract=False,
|
||||||
|
unicode=False):
|
||||||
if strict or not search:
|
if strict or not search:
|
||||||
if not expression.startswith('^'):
|
if not expression.startswith('^'):
|
||||||
expression = '^(%s)' % expression
|
expression = '^(%s)' % expression
|
||||||
if strict:
|
if strict:
|
||||||
if not expression.endswith('$'):
|
if not expression.endswith('$'):
|
||||||
expression = '(%s)$' % expression
|
expression = '(%s)$' % expression
|
||||||
self.regex = re.compile(expression)
|
if unicode:
|
||||||
|
if not isinstance(expression,unicode):
|
||||||
|
expression = expression.decode('utf8')
|
||||||
|
self.regex = re.compile(expression,re.UNICODE)
|
||||||
|
else:
|
||||||
|
self.regex = re.compile(expression)
|
||||||
self.error_message = error_message
|
self.error_message = error_message
|
||||||
self.extract = extract
|
self.extract = extract
|
||||||
|
self.unicode = unicode
|
||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
match = self.regex.search(value)
|
if self.unicode and not isinstance(value,unicode):
|
||||||
|
match = self.regex.search(str(value).decode('utf8'))
|
||||||
|
else:
|
||||||
|
match = self.regex.search(str(value))
|
||||||
if match is not None:
|
if match is not None:
|
||||||
return (self.extract and match.group() or value, None)
|
return (self.extract and match.group() or value, None)
|
||||||
return (value, translate(self.error_message))
|
return (value, translate(self.error_message))
|
||||||
@@ -2209,22 +2219,29 @@ class IS_DATE(Validator):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, format='%Y-%m-%d',
|
def __init__(self, format='%Y-%m-%d',
|
||||||
error_message='enter date as %(format)s'):
|
error_message='enter date as %(format)s',
|
||||||
|
timezone = None):
|
||||||
self.format = translate(format)
|
self.format = translate(format)
|
||||||
self.error_message = str(error_message)
|
self.error_message = str(error_message)
|
||||||
|
self.timezone = timezone
|
||||||
self.extremes = {}
|
self.extremes = {}
|
||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
|
ovalue = value
|
||||||
if isinstance(value, datetime.date):
|
if isinstance(value, datetime.date):
|
||||||
|
if self.timezone is not None:
|
||||||
|
value = value - datetime.timedelta(seconds=self.timezone*3600)
|
||||||
return (value, None)
|
return (value, None)
|
||||||
try:
|
try:
|
||||||
(y, m, d, hh, mm, ss, t0, t1, t2) = \
|
(y, m, d, hh, mm, ss, t0, t1, t2) = \
|
||||||
time.strptime(value, str(self.format))
|
time.strptime(value, str(self.format))
|
||||||
value = datetime.date(y, m, d)
|
value = datetime.date(y, m, d)
|
||||||
|
if self.timezone is not None:
|
||||||
|
value = value - datetime.timedelta(seconds=self.timezone*3600)
|
||||||
return (value, None)
|
return (value, None)
|
||||||
except:
|
except:
|
||||||
self.extremes.update(IS_DATETIME.nice(self.format))
|
self.extremes.update(IS_DATETIME.nice(self.format))
|
||||||
return (value, translate(self.error_message) % self.extremes)
|
return (ovalue, translate(self.error_message) % self.extremes)
|
||||||
|
|
||||||
def formatter(self, value):
|
def formatter(self, value):
|
||||||
if value is None:
|
if value is None:
|
||||||
@@ -2237,6 +2254,8 @@ class IS_DATE(Validator):
|
|||||||
if year < 1900:
|
if year < 1900:
|
||||||
year = 2000
|
year = 2000
|
||||||
d = datetime.date(year, value.month, value.day)
|
d = datetime.date(year, value.month, value.day)
|
||||||
|
if self.timezone is not None:
|
||||||
|
d = d + datetime.timedelta(seconds=self.timezone*3600)
|
||||||
return d.strftime(format)
|
return d.strftime(format)
|
||||||
|
|
||||||
|
|
||||||
@@ -2269,22 +2288,27 @@ class IS_DATETIME(Validator):
|
|||||||
return dict(format=format)
|
return dict(format=format)
|
||||||
|
|
||||||
def __init__(self, format='%Y-%m-%d %H:%M:%S',
|
def __init__(self, format='%Y-%m-%d %H:%M:%S',
|
||||||
error_message='enter date and time as %(format)s'):
|
error_message='enter date and time as %(format)s',
|
||||||
|
timezone=None):
|
||||||
self.format = translate(format)
|
self.format = translate(format)
|
||||||
self.error_message = str(error_message)
|
self.error_message = str(error_message)
|
||||||
self.extremes = {}
|
self.extremes = {}
|
||||||
|
self.timezone = timezone
|
||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
|
ovalue = value
|
||||||
if isinstance(value, datetime.datetime):
|
if isinstance(value, datetime.datetime):
|
||||||
return (value, None)
|
return (value, None)
|
||||||
try:
|
try:
|
||||||
(y, m, d, hh, mm, ss, t0, t1, t2) = \
|
(y, m, d, hh, mm, ss, t0, t1, t2) = \
|
||||||
time.strptime(value, str(self.format))
|
time.strptime(value, str(self.format))
|
||||||
value = datetime.datetime(y, m, d, hh, mm, ss)
|
value = datetime.datetime(y, m, d, hh, mm, ss)
|
||||||
|
if self.timezone is not None:
|
||||||
|
value = value - datetime.timedelta(seconds=self.timezone*3600)
|
||||||
return (value, None)
|
return (value, None)
|
||||||
except:
|
except:
|
||||||
self.extremes.update(IS_DATETIME.nice(self.format))
|
self.extremes.update(IS_DATETIME.nice(self.format))
|
||||||
return (value, translate(self.error_message) % self.extremes)
|
return (ovalue, translate(self.error_message) % self.extremes)
|
||||||
|
|
||||||
def formatter(self, value):
|
def formatter(self, value):
|
||||||
if value is None:
|
if value is None:
|
||||||
@@ -2298,6 +2322,8 @@ class IS_DATETIME(Validator):
|
|||||||
year = 2000
|
year = 2000
|
||||||
d = datetime.datetime(year, value.month, value.day,
|
d = datetime.datetime(year, value.month, value.day,
|
||||||
value.hour, value.minute, value.second)
|
value.hour, value.minute, value.second)
|
||||||
|
if self.timezone is not None:
|
||||||
|
d = d + datetime.timedelta(seconds=self.timezone*3600)
|
||||||
return d.strftime(format)
|
return d.strftime(format)
|
||||||
|
|
||||||
|
|
||||||
@@ -2326,7 +2352,8 @@ class IS_DATE_IN_RANGE(IS_DATE):
|
|||||||
minimum=None,
|
minimum=None,
|
||||||
maximum=None,
|
maximum=None,
|
||||||
format='%Y-%m-%d',
|
format='%Y-%m-%d',
|
||||||
error_message=None):
|
error_message=None,
|
||||||
|
timezone=None):
|
||||||
self.minimum = minimum
|
self.minimum = minimum
|
||||||
self.maximum = maximum
|
self.maximum = maximum
|
||||||
if error_message is None:
|
if error_message is None:
|
||||||
@@ -2338,17 +2365,19 @@ class IS_DATE_IN_RANGE(IS_DATE):
|
|||||||
error_message = "enter date in range %(min)s %(max)s"
|
error_message = "enter date in range %(min)s %(max)s"
|
||||||
IS_DATE.__init__(self,
|
IS_DATE.__init__(self,
|
||||||
format=format,
|
format=format,
|
||||||
error_message=error_message)
|
error_message=error_message,
|
||||||
|
timezone=timezone)
|
||||||
self.extremes = dict(min=minimum, max=maximum)
|
self.extremes = dict(min=minimum, max=maximum)
|
||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
|
ovalue = value
|
||||||
(value, msg) = IS_DATE.__call__(self, value)
|
(value, msg) = IS_DATE.__call__(self, value)
|
||||||
if msg is not None:
|
if msg is not None:
|
||||||
return (value, msg)
|
return (value, msg)
|
||||||
if self.minimum and self.minimum > value:
|
if self.minimum and self.minimum > value:
|
||||||
return (value, translate(self.error_message) % self.extremes)
|
return (ovalue, translate(self.error_message) % self.extremes)
|
||||||
if self.maximum and value > self.maximum:
|
if self.maximum and value > self.maximum:
|
||||||
return (value, translate(self.error_message) % self.extremes)
|
return (ovalue, translate(self.error_message) % self.extremes)
|
||||||
return (value, None)
|
return (value, None)
|
||||||
|
|
||||||
|
|
||||||
@@ -2376,7 +2405,8 @@ class IS_DATETIME_IN_RANGE(IS_DATETIME):
|
|||||||
minimum=None,
|
minimum=None,
|
||||||
maximum=None,
|
maximum=None,
|
||||||
format='%Y-%m-%d %H:%M:%S',
|
format='%Y-%m-%d %H:%M:%S',
|
||||||
error_message=None):
|
error_message=None,
|
||||||
|
timezone=None):
|
||||||
self.minimum = minimum
|
self.minimum = minimum
|
||||||
self.maximum = maximum
|
self.maximum = maximum
|
||||||
if error_message is None:
|
if error_message is None:
|
||||||
@@ -2388,17 +2418,19 @@ class IS_DATETIME_IN_RANGE(IS_DATETIME):
|
|||||||
error_message = "enter date and time in range %(min)s %(max)s"
|
error_message = "enter date and time in range %(min)s %(max)s"
|
||||||
IS_DATETIME.__init__(self,
|
IS_DATETIME.__init__(self,
|
||||||
format=format,
|
format=format,
|
||||||
error_message=error_message)
|
error_message=error_message,
|
||||||
|
timezone=timezone)
|
||||||
self.extremes = dict(min=minimum, max=maximum)
|
self.extremes = dict(min=minimum, max=maximum)
|
||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
|
ovalue = value
|
||||||
(value, msg) = IS_DATETIME.__call__(self, value)
|
(value, msg) = IS_DATETIME.__call__(self, value)
|
||||||
if msg is not None:
|
if msg is not None:
|
||||||
return (value, msg)
|
return (value, msg)
|
||||||
if self.minimum and self.minimum > value:
|
if self.minimum and self.minimum > value:
|
||||||
return (value, translate(self.error_message) % self.extremes)
|
return (ovalue, translate(self.error_message) % self.extremes)
|
||||||
if self.maximum and value > self.maximum:
|
if self.maximum and value > self.maximum:
|
||||||
return (value, translate(self.error_message) % self.extremes)
|
return (ovalue, translate(self.error_message) % self.extremes)
|
||||||
return (value, None)
|
return (value, None)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -434,6 +434,10 @@ class web2pyDialog(object):
|
|||||||
self.try_stop_scheduler(t)
|
self.try_stop_scheduler(t)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
try:
|
||||||
|
newcron.stopcron()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
try:
|
try:
|
||||||
self.server.stop()
|
self.server.stop()
|
||||||
except:
|
except:
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ data = re.compile('\*/\s+/\*').sub(' ', data)
|
|||||||
data = re.compile('[ ]+\n').sub('\n', data)
|
data = re.compile('[ ]+\n').sub('\n', data)
|
||||||
data = re.compile('\n\s*/[\*]+(?P<a>.*?)[\*]+/', re.DOTALL).sub(
|
data = re.compile('\n\s*/[\*]+(?P<a>.*?)[\*]+/', re.DOTALL).sub(
|
||||||
'\n/*\g<a>*/\n', data)
|
'\n/*\g<a>*/\n', data)
|
||||||
data = re.compile('[ \t]+(?P<a>\S.+?){').sub('\g<a>{', data)
|
data = re.compile('[ \t]+(?P<a>\S.+?){').sub(' \g<a>{', data)
|
||||||
data = data.replace('}', '}\n')
|
data = data.replace('}', '}\n')
|
||||||
|
|
||||||
print data
|
print data
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ a2enmod proxy
|
|||||||
a2enmod proxy_http
|
a2enmod proxy_http
|
||||||
a2enmod headers
|
a2enmod headers
|
||||||
a2enmod expires
|
a2enmod expires
|
||||||
|
a2enmod wsgi
|
||||||
mkdir /etc/apache2/ssl
|
mkdir /etc/apache2/ssl
|
||||||
|
|
||||||
echo "creating a self signed certificate"
|
echo "creating a self signed certificate"
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
language: python
|
|
||||||
|
|
||||||
python:
|
|
||||||
- '2.5'
|
|
||||||
- '2.6'
|
|
||||||
- '2.7'
|
|
||||||
|
|
||||||
before_script:
|
|
||||||
- pip install unittest2
|
|
||||||
- mysql -e 'create database test_pymysql;'
|
|
||||||
- mysql -e 'create database test_pymysql2;'
|
|
||||||
|
|
||||||
script: PYTHONPATH=. unit2 -v gluon.tests
|
|
||||||
|
|
||||||
notifications:
|
|
||||||
irc:
|
|
||||||
channels: "irc.freenode.org#web2py"
|
|
||||||
@@ -4,7 +4,7 @@ import sys
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
Author: Christopher Steel on behalf of Voice of Access
|
Author: Christopher Steel on behalf of Voice of Access
|
||||||
Copyright: Copyrighted (c) by Massimo Di Pierro (2007-2011)
|
Copyright: Copyrighted (c) by Massimo Di Pierro (2007-2013)
|
||||||
|
|
||||||
web2py_clone becomes part of the web2py distribution available
|
web2py_clone becomes part of the web2py distribution available
|
||||||
on Pypi via 'pip install web2py'
|
on Pypi via 'pip install web2py'
|
||||||
|
|||||||