Compare commits
272 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
37bc09169f | ||
|
|
1cc2decfdd | ||
|
|
e9eb1689e2 | ||
|
|
0f446833c0 | ||
|
|
cb9c2a8ef9 | ||
|
|
b37ed1c1e0 | ||
|
|
b484955005 | ||
|
|
654626d519 | ||
|
|
ca0313c514 | ||
|
|
fb357eb241 | ||
|
|
1a83487221 | ||
|
|
6cda7a29fc | ||
|
|
17f495e9c5 | ||
|
|
dd32a90844 | ||
|
|
4b2ba185ae | ||
|
|
b716df1a05 | ||
|
|
d552eb2eeb | ||
|
|
de2337dfe3 | ||
|
|
e707cfc67c | ||
|
|
c3c5df6394 | ||
|
|
72739ebb97 | ||
|
|
39c94b8dcf | ||
|
|
5af380223a | ||
|
|
1ea379180a | ||
|
|
ca3d050a0b | ||
|
|
161b2271b3 | ||
|
|
013c94cdf6 | ||
|
|
addbb78151 | ||
|
|
f6789eaf39 | ||
|
|
c13b4f18f7 | ||
|
|
67840e9481 | ||
|
|
41c40974a3 | ||
|
|
9a6ce11f09 | ||
|
|
d404e40508 | ||
|
|
b6a496aae5 | ||
|
|
ecaed07a3d | ||
|
|
30ec8e645b | ||
|
|
3a1ba53a4b | ||
|
|
ab95dfa7cd | ||
|
|
6b9ebb6dc5 | ||
|
|
e2e843d2ed | ||
|
|
d5381d7b36 | ||
|
|
f7c0f0341b | ||
|
|
9f7fd68728 | ||
|
|
c2b6c645ef | ||
|
|
36810aaccc | ||
|
|
8e14d1c92e | ||
|
|
9b7e944dea | ||
|
|
b6429ca5fd | ||
|
|
8607b09e64 | ||
|
|
64151a2c3e | ||
|
|
d5749db0cd | ||
|
|
df7d6847e6 | ||
|
|
c6b5ad8179 | ||
|
|
71ec500fde | ||
|
|
6cf05edf63 | ||
|
|
39c5341dbc | ||
|
|
e2234a8771 | ||
|
|
cac9741cb7 | ||
|
|
648cb296e6 | ||
|
|
5a0ebb7d8c | ||
|
|
b7b534ccf2 | ||
|
|
fab23d210b | ||
|
|
6a18539f7e | ||
|
|
4d87a90c10 | ||
|
|
2c9767e500 | ||
|
|
2b1d9acba5 | ||
|
|
8a2d18b63b | ||
|
|
b59f9f896c | ||
|
|
496e6663fd | ||
|
|
a4fbf9b6b4 | ||
|
|
b8afce746b | ||
|
|
4c239eaf79 | ||
|
|
1d03233c83 | ||
|
|
5358ad271e | ||
|
|
2fa7d72b01 | ||
|
|
f034d83c81 | ||
|
|
b3afa2ab57 | ||
|
|
36fc758690 | ||
|
|
f764eb2653 | ||
|
|
63f56ddecc | ||
|
|
0b2bab3f3d | ||
|
|
66de02929b | ||
|
|
3c4a142f9a | ||
|
|
bf6f090428 | ||
|
|
59ab818f5b | ||
|
|
77847daa77 | ||
|
|
690d2df774 | ||
|
|
643cc9c141 | ||
|
|
562cb58342 | ||
|
|
1c8ef29413 | ||
|
|
8e67c551de | ||
|
|
03e3324a12 | ||
|
|
a3ba3f662a | ||
|
|
2b21678d48 | ||
|
|
09f29257d2 | ||
|
|
62be48decf | ||
|
|
952a29d5da | ||
|
|
db9151b993 | ||
|
|
e1bb2b4556 | ||
|
|
668658b7c9 | ||
|
|
231a3e1278 | ||
|
|
41d234bf48 | ||
|
|
f16c3a394f | ||
|
|
570538042e | ||
|
|
6a97bfe517 | ||
|
|
7b6e5c5270 | ||
|
|
20deb56e33 | ||
|
|
a23a2c52c2 | ||
|
|
3f6fa941cb | ||
|
|
28f914463b | ||
|
|
f0c84b5230 | ||
|
|
dc51abe54c | ||
|
|
f501da74b7 | ||
|
|
c1d14a35ee | ||
|
|
4f4a0318aa | ||
|
|
54a1005af3 | ||
|
|
7b4fac7a7f | ||
|
|
c80a6db604 | ||
|
|
96247eda51 | ||
|
|
433a02537c | ||
|
|
bacff3453b | ||
|
|
b20e74c899 | ||
|
|
efa5ceb6de | ||
|
|
f79660dd2a | ||
|
|
606daabdd3 | ||
|
|
fc1e4ad620 | ||
|
|
54dcf2ead9 | ||
|
|
69cea23cd4 | ||
|
|
083b598c93 | ||
|
|
94f11501ed | ||
|
|
9ac4a11db1 | ||
|
|
a56cf59136 | ||
|
|
12cc81147c | ||
|
|
f70737ddc2 | ||
|
|
1a22497b64 | ||
|
|
6da330a001 | ||
|
|
f6652e7530 | ||
|
|
5148c6ec3a | ||
|
|
954c79abcb | ||
|
|
7ec3fe3bfe | ||
|
|
9ce1cde6ca | ||
|
|
672af73e96 | ||
|
|
67022578e3 | ||
|
|
65fe4c16fc | ||
|
|
b6f9cd1863 | ||
|
|
4908a5e7be | ||
|
|
853c0b1a3a | ||
|
|
d0d8a4827e | ||
|
|
4745ce42f9 | ||
|
|
bba13becd0 | ||
|
|
7712e005c4 | ||
|
|
07c667f469 | ||
|
|
57ad1ec1cf | ||
|
|
60a043479c | ||
|
|
1a43e1671f | ||
|
|
cd955d3603 | ||
|
|
492a0c51d1 | ||
|
|
dd4a4c281f | ||
|
|
41ec6da72c | ||
|
|
e18f38d4da | ||
|
|
bd27df8fa5 | ||
|
|
2f44c2de9b | ||
|
|
ccf154a807 | ||
|
|
837453dd6e | ||
|
|
64bc60cdf0 | ||
|
|
af258c334e | ||
|
|
627fff624a | ||
|
|
bc8127f6de | ||
|
|
19bf43815d | ||
|
|
7709074d7c | ||
|
|
4b73f249dd | ||
|
|
ae9e2c2be0 | ||
|
|
fd8edb5aa2 | ||
|
|
82ab59c46a | ||
|
|
74a63e98b5 | ||
|
|
9e23b3dac5 | ||
|
|
077ce011e2 | ||
|
|
1430bc824f | ||
|
|
722b16e620 | ||
|
|
30727ef9e4 | ||
|
|
0f322f8a69 | ||
|
|
ec5b4dde6f | ||
|
|
630dcb799e | ||
|
|
c6d1e47226 | ||
|
|
aa8315a7c9 | ||
|
|
80040bf8e5 | ||
|
|
8f382f322e | ||
|
|
9ccc7dc59a | ||
|
|
70f6f86827 | ||
|
|
3055c87567 | ||
|
|
473955611a | ||
|
|
21a7ded8e0 | ||
|
|
23347995e2 | ||
|
|
4027a3cda3 | ||
|
|
a9b6c4f1a3 | ||
|
|
c1330662aa | ||
|
|
3e38f8017f | ||
|
|
41bc1cb1e9 | ||
|
|
9fb94008ea | ||
|
|
5f647a46b8 | ||
|
|
69a2e76c3c | ||
|
|
4d6598c645 | ||
|
|
56acb685e9 | ||
|
|
f0be4416b3 | ||
|
|
93ce59f65b | ||
|
|
28b94eceb2 | ||
|
|
e4c63769f2 | ||
|
|
e0fc61932d | ||
|
|
3de3046260 | ||
|
|
b6a96301cd | ||
|
|
480dea23ad | ||
|
|
457ef24c04 | ||
|
|
dbf6ce6d6c | ||
|
|
7686a6fc93 | ||
|
|
afde6efafa | ||
|
|
af53f17f5a | ||
|
|
8f9cf4034d | ||
|
|
31a6c5df9b | ||
|
|
08d1b26738 | ||
|
|
abd739123c | ||
|
|
da8570b560 | ||
|
|
8d238890a2 | ||
|
|
ca29f262e5 | ||
|
|
cffefbeb2e | ||
|
|
52528f9311 | ||
|
|
8b75256281 | ||
|
|
2385ed22b1 | ||
|
|
7a0cf446ba | ||
|
|
586d85cf08 | ||
|
|
f371e72e07 | ||
|
|
8d9bc1cb53 | ||
|
|
29edf94498 | ||
|
|
d7a108ff06 | ||
|
|
5ed41285c0 | ||
|
|
b16d79e654 | ||
|
|
90e5d06d3d | ||
|
|
a1156cae6c | ||
|
|
037a200357 | ||
|
|
e282454bfe | ||
|
|
e499c1d5a4 | ||
|
|
8540b1b113 | ||
|
|
6b5e3f2abf | ||
|
|
f8be550e6a | ||
|
|
6a7b04199f | ||
|
|
2847e0f4df | ||
|
|
eec7f7c687 | ||
|
|
a4253deda3 | ||
|
|
372d639601 | ||
|
|
06e5c6869d | ||
|
|
933189c216 | ||
|
|
c942881f36 | ||
|
|
99e491ca0f | ||
|
|
ea539d50e2 | ||
|
|
497bbf002c | ||
|
|
2629fac624 | ||
|
|
30af5901eb | ||
|
|
42b60d3291 | ||
|
|
9b53fd2302 | ||
|
|
972f64b6f9 | ||
|
|
3eb4627ccf | ||
|
|
2ba88b8951 | ||
|
|
117b04169c | ||
|
|
c56d5bd066 | ||
|
|
00bfde9ce9 | ||
|
|
5f503d0427 | ||
|
|
47bcab6b26 | ||
|
|
ecca0439f1 | ||
|
|
e896be4037 | ||
|
|
b0e4284130 | ||
|
|
3e69889cca | ||
|
|
dfb2e62c6c |
45
CHANGELOG
45
CHANGELOG
@@ -1,4 +1,47 @@
|
||||
## 2.00.1
|
||||
## 2.2.1
|
||||
|
||||
- session.connect(cookie_key='secret', compression_level=9) stores sessions in cookies
|
||||
- T.is_writable = False prevents T from dynamically updating langauge files
|
||||
- all code is more PEP8 compliant
|
||||
- better custom_importer behaviour (now works per app, is smalled and faster)
|
||||
- fixed some bugs
|
||||
- upgraded feedparser.py and rss2.py
|
||||
- codemirror has autoresize
|
||||
|
||||
## 2.1.0
|
||||
|
||||
- overall faster web2py
|
||||
- when apps are deleted, a w2p copy left in deposit folder
|
||||
- change in cron (it is now disabled by default). removed -N option and introduced -Y.
|
||||
- faster web2py_uuid() and request initialization logic, thanks Michele
|
||||
- static asset management, thanks Niphlod
|
||||
- improved mobile admin
|
||||
- request.requires_https and Auth(secure=True), thanks Yarin and Niphlod
|
||||
- better custom_import (works per app and is faster), thanks Michele
|
||||
- redis_sesssion.py, thanks Niphlod
|
||||
- allow entropy computation in IS_STRONG and web2py.js, thanks Jonathan and Niphlod
|
||||
- fixed many aith.wiki problems
|
||||
- support for auth.wiki(render='html')
|
||||
- better welcome layout, thanks Paolo
|
||||
- db.define_table(...,redefine=True)
|
||||
- DAL, Row, and Rows object can now be pickled/unpickled, thanks to zombie DAL.
|
||||
- admin uses codemirror
|
||||
- allow syntax auth = Auth(db).define_tables()
|
||||
- better auth.wiki with preview, thanks Alan
|
||||
- better auth.impersonate, thanks Alan
|
||||
- upgraded jQuery 1.8
|
||||
- upgraded Bootstrap 2.1
|
||||
- fixed problem with dropbox_account.py
|
||||
- many fixes to cache.ram, cache.disk, memcache and gae_memcache
|
||||
- cache.with_prefix(cache.ram,'prefix')
|
||||
- db.table.field.epoch() counts seconds from epoch
|
||||
- DAL support for SQL CASE, example: db().select(...query.case('true','false))
|
||||
- DAL(...,do_connect=False) allows faking connections
|
||||
- DAL(...,auto_import=True) now retieves some fiel attributes
|
||||
- mail can specify a sender: mail.send(...,sender='Mr X <%(sender)s>')
|
||||
- renamed gluon/contrib/comet_messaging.py -> gluon/contrib/websocket_messaging.py
|
||||
|
||||
## 2.0.1-11
|
||||
|
||||
### DAL Improvements
|
||||
|
||||
|
||||
13
Makefile
13
Makefile
@@ -29,7 +29,7 @@ update:
|
||||
wget -O gluon/contrib/simplejsonrpc.py http://rad2py.googlecode.com/hg/ide2py/simplejsonrpc.py
|
||||
echo "remember that pymysql was tweaked"
|
||||
src:
|
||||
echo 'Version 2.0.9 ('`date +%Y-%m-%d\ %H:%M:%S`') stable' > VERSION
|
||||
echo 'Version 2.2.1 ('`date +%Y-%m-%d\ %H:%M:%S`') stable' > VERSION
|
||||
### rm -f all junk files
|
||||
make clean
|
||||
### clean up baisc apps
|
||||
@@ -107,10 +107,6 @@ win:
|
||||
cp applications/__init__.py ../web2py_win/web2py/applications
|
||||
cd ../web2py_win; zip -r web2py_win.zip web2py
|
||||
mv ../web2py_win/web2py_win.zip .
|
||||
pip:
|
||||
# create Web2py distribution for upload to Pypi
|
||||
# after upload clean Web2py sources with rm -R ./dist
|
||||
python setup.py sdist
|
||||
run:
|
||||
python2.5 web2py.py -a hello
|
||||
commit:
|
||||
@@ -129,3 +125,10 @@ tag:
|
||||
hg tag -l '$(S)'
|
||||
make commit S='$(S)'
|
||||
make push
|
||||
pip:
|
||||
# create Web2py distribution for upload to Pypi
|
||||
# after upload clean Web2py sources with rm -R ./dist
|
||||
# http://guide.python-distribute.org/creation.html
|
||||
python setup.py sdist
|
||||
sudo python setup.py register
|
||||
sudo python setup.py sdist upload
|
||||
|
||||
2
VERSION
2
VERSION
@@ -1 +1 @@
|
||||
Version 2.0.9 (2012-09-13 17:48:15) stable
|
||||
Version 2.2.1 (2012-10-21 10:54:10) stable
|
||||
|
||||
10
__init__.py
10
__init__.py
@@ -1,10 +0,0 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
125
anyserver.py
125
anyserver.py
@@ -9,47 +9,54 @@ License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
||||
This file is based, although a rewrite, on MIT-licensed code from the Bottle web framework.
|
||||
"""
|
||||
|
||||
import os, sys, optparse, urllib
|
||||
import os
|
||||
import sys
|
||||
import optparse
|
||||
import urllib
|
||||
|
||||
path = os.path.dirname(os.path.abspath(__file__))
|
||||
os.chdir(path)
|
||||
sys.path = [path]+[p for p in sys.path if not p==path]
|
||||
sys.path = [path] + [p for p in sys.path if not p == path]
|
||||
import gluon.main
|
||||
from gluon.fileutils import read_file, write_file
|
||||
|
||||
|
||||
class Servers:
|
||||
@staticmethod
|
||||
def cgi(app, address=None, **options):
|
||||
from wsgiref.handlers import CGIHandler
|
||||
CGIHandler().run(app) # Just ignore host and port here
|
||||
CGIHandler().run(app) # Just ignore host and port here
|
||||
|
||||
@staticmethod
|
||||
def flup(app,address, **options):
|
||||
def flup(app, address, **options):
|
||||
import flup.server.fcgi
|
||||
flup.server.fcgi.WSGIServer(app, bindAddress=address).run()
|
||||
|
||||
@staticmethod
|
||||
def wsgiref(app,address,**options): # pragma: no cover
|
||||
def wsgiref(app, address, **options): # pragma: no cover
|
||||
from wsgiref.simple_server import make_server, WSGIRequestHandler
|
||||
|
||||
class QuietHandler(WSGIRequestHandler):
|
||||
def log_request(*args, **kw): pass
|
||||
def log_request(*args, **kw):
|
||||
pass
|
||||
options['handler_class'] = QuietHandler
|
||||
srv = make_server(address[0],address[1],app,**options)
|
||||
srv = make_server(address[0], address[1], app, **options)
|
||||
srv.serve_forever()
|
||||
|
||||
@staticmethod
|
||||
def cherrypy(app,address, **options):
|
||||
def cherrypy(app, address, **options):
|
||||
from cherrypy import wsgiserver
|
||||
server = wsgiserver.CherryPyWSGIServer(address, app)
|
||||
server.start()
|
||||
|
||||
@staticmethod
|
||||
def rocket(app,address, **options):
|
||||
def rocket(app, address, **options):
|
||||
from gluon.rocket import CherryPyWSGIServer
|
||||
server = CherryPyWSGIServer(address, app)
|
||||
server.start()
|
||||
|
||||
@staticmethod
|
||||
def rocket_with_repoze_profiler(app,address, **options):
|
||||
def rocket_with_repoze_profiler(app, address, **options):
|
||||
from gluon.rocket import CherryPyWSGIServer
|
||||
from repoze.profile.profiler import AccumulatingProfileMiddleware
|
||||
from gluon.settings import global_settings
|
||||
@@ -59,44 +66,46 @@ class Servers:
|
||||
log_filename='wsgi.prof',
|
||||
discard_first_request=True,
|
||||
flush_at_shutdown=True,
|
||||
path = '/__profile__'
|
||||
)
|
||||
path='/__profile__'
|
||||
)
|
||||
server = CherryPyWSGIServer(address, wrapped)
|
||||
server.start()
|
||||
|
||||
@staticmethod
|
||||
def paste(app,address,**options):
|
||||
def paste(app, address, **options):
|
||||
from paste import httpserver
|
||||
from paste.translogger import TransLogger
|
||||
httpserver.serve(app, host=address[0], port=address[1], **options)
|
||||
|
||||
@staticmethod
|
||||
def fapws(app,address, **options):
|
||||
def fapws(app, address, **options):
|
||||
import fapws._evwsgi as evwsgi
|
||||
from fapws import base
|
||||
evwsgi.start(address[0],str(address[1]))
|
||||
evwsgi.start(address[0], str(address[1]))
|
||||
evwsgi.set_base_module(base)
|
||||
|
||||
def app(environ, start_response):
|
||||
environ['wsgi.multiprocess'] = False
|
||||
return app(environ, start_response)
|
||||
evwsgi.wsgi_cb(('',app))
|
||||
evwsgi.wsgi_cb(('', app))
|
||||
evwsgi.run()
|
||||
|
||||
|
||||
@staticmethod
|
||||
def gevent(app,address, **options):
|
||||
from gevent import monkey; monkey.patch_all()
|
||||
def gevent(app, address, **options):
|
||||
from gevent import monkey
|
||||
monkey.patch_all()
|
||||
from gevent import pywsgi
|
||||
from gevent.pool import Pool
|
||||
pywsgi.WSGIServer(address, app, spawn = 'workers' in options and Pool(int(options.workers)) or 'default').serve_forever()
|
||||
pywsgi.WSGIServer(address, app, spawn='workers' in options and Pool(
|
||||
int(options.workers)) or 'default').serve_forever()
|
||||
|
||||
@staticmethod
|
||||
def bjoern(app,address, **options):
|
||||
def bjoern(app, address, **options):
|
||||
import bjoern
|
||||
bjoern.run(app, *address)
|
||||
|
||||
@staticmethod
|
||||
def tornado(app,address, **options):
|
||||
def tornado(app, address, **options):
|
||||
import tornado.wsgi
|
||||
import tornado.httpserver
|
||||
import tornado.ioloop
|
||||
@@ -106,7 +115,7 @@ class Servers:
|
||||
tornado.ioloop.IOLoop.instance().start()
|
||||
|
||||
@staticmethod
|
||||
def twisted(app,address, **options):
|
||||
def twisted(app, address, **options):
|
||||
from twisted.web import server, wsgi
|
||||
from twisted.python.threadpool import ThreadPool
|
||||
from twisted.internet import reactor
|
||||
@@ -118,42 +127,44 @@ class Servers:
|
||||
reactor.run()
|
||||
|
||||
@staticmethod
|
||||
def diesel(app,address, **options):
|
||||
def diesel(app, address, **options):
|
||||
from diesel.protocols.wsgi import WSGIApplication
|
||||
app = WSGIApplication(app, port=address[1])
|
||||
app.run()
|
||||
|
||||
@staticmethod
|
||||
def gunicorn(app,address, **options):
|
||||
def gunicorn(app, address, **options):
|
||||
from gunicorn.app.base import Application
|
||||
config = {'bind': "%s:%d" % address}
|
||||
config.update(options)
|
||||
sys.argv = ['anyserver.py']
|
||||
|
||||
class GunicornApplication(Application):
|
||||
def init(self, parser, opts, args):
|
||||
return config
|
||||
|
||||
def load(self):
|
||||
return app
|
||||
g = GunicornApplication()
|
||||
g.run()
|
||||
|
||||
@staticmethod
|
||||
def eventlet(app,address, **options):
|
||||
def eventlet(app, address, **options):
|
||||
from eventlet import wsgi, listen
|
||||
wsgi.server(listen(address), app)
|
||||
|
||||
@staticmethod
|
||||
def mongrel2(app,address,**options):
|
||||
def mongrel2(app, address, **options):
|
||||
import uuid
|
||||
sys.path.append(os.path.abspath(os.path.dirname(__file__)))
|
||||
from mongrel2 import handler
|
||||
conn = handler.Connection(str(uuid.uuid4()),
|
||||
"tcp://127.0.0.1:9997",
|
||||
"tcp://127.0.0.1:9996")
|
||||
mongrel2_handler(app,conn,debug=False)
|
||||
mongrel2_handler(app, conn, debug=False)
|
||||
|
||||
|
||||
def run(servername,ip,port,softcron=True,logging=False,profiler=None):
|
||||
def run(servername, ip, port, softcron=True, logging=False, profiler=None):
|
||||
if logging:
|
||||
application = gluon.main.appfactory(wsgiapp=gluon.main.wsgibase,
|
||||
logfilename='httpserver.log',
|
||||
@@ -163,9 +174,10 @@ def run(servername,ip,port,softcron=True,logging=False,profiler=None):
|
||||
if softcron:
|
||||
from gluon.settings import global_settings
|
||||
global_settings.web2py_crontype = 'soft'
|
||||
getattr(Servers,servername)(application,(ip,int(port)))
|
||||
getattr(Servers, servername)(application, (ip, int(port)))
|
||||
|
||||
def mongrel2_handler(application,conn,debug=False):
|
||||
|
||||
def mongrel2_handler(application, conn, debug=False):
|
||||
"""
|
||||
Based on :
|
||||
https://github.com/berry/Mongrel2-WSGI-Handler/blob/master/wsgi-handler.py
|
||||
@@ -190,20 +202,23 @@ def mongrel2_handler(application,conn,debug=False):
|
||||
# and responses. Unless I have missed something.
|
||||
|
||||
while True:
|
||||
if debug: print "WAITING FOR REQUEST"
|
||||
if debug:
|
||||
print "WAITING FOR REQUEST"
|
||||
|
||||
# receive a request
|
||||
req = conn.recv()
|
||||
if debug: print "REQUEST BODY: %r\n" % req.body
|
||||
if debug:
|
||||
print "REQUEST BODY: %r\n" % req.body
|
||||
|
||||
if req.is_disconnect():
|
||||
if debug: print "DISCONNECT"
|
||||
continue #effectively ignore the disconnect from the client
|
||||
if debug:
|
||||
print "DISCONNECT"
|
||||
continue # effectively ignore the disconnect from the client
|
||||
|
||||
# Set a couple of environment attributes a.k.a. header attributes
|
||||
# that are a must according to PEP 333
|
||||
environ = req.headers
|
||||
environ['SERVER_PROTOCOL'] = 'HTTP/1.1' # SimpleHandler expects a server_protocol, lets assume it is HTTP 1.1
|
||||
environ['SERVER_PROTOCOL'] = 'HTTP/1.1' # SimpleHandler expects a server_protocol, lets assume it is HTTP 1.1
|
||||
environ['REQUEST_METHOD'] = environ['METHOD']
|
||||
if ':' in environ['Host']:
|
||||
environ['SERVER_NAME'] = environ['Host'].split(':')[0]
|
||||
@@ -211,17 +226,19 @@ def mongrel2_handler(application,conn,debug=False):
|
||||
else:
|
||||
environ['SERVER_NAME'] = environ['Host']
|
||||
environ['SERVER_PORT'] = ''
|
||||
environ['SCRIPT_NAME'] = '' # empty for now
|
||||
environ['SCRIPT_NAME'] = '' # empty for now
|
||||
environ['PATH_INFO'] = urllib.unquote(environ['PATH'])
|
||||
if '?' in environ['URI']:
|
||||
environ['QUERY_STRING'] = environ['URI'].split('?')[1]
|
||||
else:
|
||||
environ['QUERY_STRING'] = ''
|
||||
if environ.has_key('Content-Length'):
|
||||
environ['CONTENT_LENGTH'] = environ['Content-Length'] # necessary for POST to work with Django
|
||||
if 'Content-Length' in environ:
|
||||
environ['CONTENT_LENGTH'] = environ[
|
||||
'Content-Length'] # necessary for POST to work with Django
|
||||
environ['wsgi.input'] = req.body
|
||||
|
||||
if debug: print "ENVIRON: %r\n" % environ
|
||||
if debug:
|
||||
print "ENVIRON: %r\n" % environ
|
||||
|
||||
# SimpleHandler needs file-like stream objects for
|
||||
# requests, errors and responses
|
||||
@@ -230,7 +247,8 @@ def mongrel2_handler(application,conn,debug=False):
|
||||
respIO = StringIO.StringIO()
|
||||
|
||||
# execute the application
|
||||
handler = SimpleHandler(reqIO, respIO, errIO, environ, multithread = False, multiprocess = False)
|
||||
handler = SimpleHandler(reqIO, respIO, errIO, environ,
|
||||
multithread=False, multiprocess=False)
|
||||
handler.run(application)
|
||||
|
||||
# Get the response and filter out the response (=data) itself,
|
||||
@@ -254,11 +272,15 @@ def mongrel2_handler(application,conn,debug=False):
|
||||
errors = errIO.getvalue()
|
||||
|
||||
# return the response
|
||||
if debug: print "RESPONSE: %r\n" % response
|
||||
if debug:
|
||||
print "RESPONSE: %r\n" % response
|
||||
if errors:
|
||||
if debug: print "ERRORS: %r" % errors
|
||||
if debug:
|
||||
print "ERRORS: %r" % errors
|
||||
data = "%s\r\n\r\n%s" % (data, errors)
|
||||
conn.reply_http(req, data, code = code, status = status, headers = headers)
|
||||
conn.reply_http(
|
||||
req, data, code=code, status=status, headers=headers)
|
||||
|
||||
|
||||
def main():
|
||||
usage = "python anyserver.py -s tornado -i 127.0.0.1 -p 8000 -l -P"
|
||||
@@ -278,7 +300,7 @@ def main():
|
||||
default=False,
|
||||
dest='profiler',
|
||||
help='profiler filename')
|
||||
servers = ', '.join(x for x in dir(Servers) if not x[0]=='_')
|
||||
servers = ', '.join(x for x in dir(Servers) if not x[0] == '_')
|
||||
parser.add_option('-s',
|
||||
'--server',
|
||||
default='rocket',
|
||||
@@ -300,13 +322,10 @@ def main():
|
||||
dest='workers',
|
||||
help='number of workers number')
|
||||
(options, args) = parser.parse_args()
|
||||
print 'starting %s on %s:%s...' % (options.server,options.ip,options.port)
|
||||
run(options.server,options.ip,options.port,logging=options.logging,profiler=options.profiler)
|
||||
print 'starting %s on %s:%s...' % (
|
||||
options.server, options.ip, options.port)
|
||||
run(options.server, options.ip, options.port,
|
||||
logging=options.logging, profiler=options.profiler)
|
||||
|
||||
if __name__=='__main__':
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -80,7 +80,6 @@ skip_files: |
|
||||
|
||||
builtins:
|
||||
- remote_api: on
|
||||
# - datastore_admin: on
|
||||
- appstats: on
|
||||
- admin_redirect: on
|
||||
- deferred: on
|
||||
|
||||
@@ -2,8 +2,3 @@ def webapp_add_wsgi_middleware(app):
|
||||
from google.appengine.ext.appstats import recording
|
||||
app = recording.appstats_wsgi_middleware(app)
|
||||
return app
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ remote_addr = request.env.remote_addr
|
||||
try:
|
||||
hosts = (http_host, socket.gethostname(),
|
||||
socket.gethostbyname(http_host),
|
||||
'::1','127.0.0.1','::ffff:127.0.0.1')
|
||||
'::1', '127.0.0.1', '::ffff:127.0.0.1')
|
||||
except:
|
||||
hosts = (http_host, )
|
||||
|
||||
@@ -32,10 +32,10 @@ if request.env.http_x_forwarded_for or request.is_https:
|
||||
elif (remote_addr not in hosts) and (remote_addr != "127.0.0.1"):
|
||||
raise HTTP(200, T('appadmin is disabled because insecure channel'))
|
||||
|
||||
if (request.application=='admin' and not session.authorized) or \
|
||||
(request.application!='admin' and not gluon.fileutils.check_credentials(request)):
|
||||
if (request.application == 'admin' and not session.authorized) or \
|
||||
(request.application != 'admin' and not gluon.fileutils.check_credentials(request)):
|
||||
redirect(URL('admin', 'default', 'index',
|
||||
vars=dict(send=URL(args=request.args,vars=request.vars))))
|
||||
vars=dict(send=URL(args=request.args, vars=request.vars))))
|
||||
|
||||
ignore_rw = True
|
||||
response.view = 'appadmin.html'
|
||||
@@ -95,25 +95,23 @@ def get_query(request):
|
||||
return None
|
||||
|
||||
|
||||
def query_by_table_type(tablename,db,request=request):
|
||||
keyed = hasattr(db[tablename],'_primarykey')
|
||||
def query_by_table_type(tablename, db, request=request):
|
||||
keyed = hasattr(db[tablename], '_primarykey')
|
||||
if keyed:
|
||||
firstkey = db[tablename][db[tablename]._primarykey[0]]
|
||||
cond = '>0'
|
||||
if firstkey.type in ['string', 'text']:
|
||||
cond = '!=""'
|
||||
qry = '%s.%s.%s%s' % (request.args[0], request.args[1], firstkey.name, cond)
|
||||
qry = '%s.%s.%s%s' % (
|
||||
request.args[0], request.args[1], firstkey.name, cond)
|
||||
else:
|
||||
qry = '%s.%s.id>0' % tuple(request.args[:2])
|
||||
return qry
|
||||
|
||||
|
||||
|
||||
# ##########################################################
|
||||
# ## list all databases and tables
|
||||
# ###########################################################
|
||||
|
||||
|
||||
def index():
|
||||
return dict(databases=databases)
|
||||
|
||||
@@ -128,7 +126,7 @@ def insert():
|
||||
form = SQLFORM(db[table], ignore_rw=ignore_rw)
|
||||
if form.accepts(request.vars, session):
|
||||
response.flash = T('new record inserted')
|
||||
return dict(form=form,table=db[table])
|
||||
return dict(form=form, table=db[table])
|
||||
|
||||
|
||||
# ##########################################################
|
||||
@@ -139,7 +137,8 @@ def insert():
|
||||
def download():
|
||||
import os
|
||||
db = get_database(request)
|
||||
return response.download(request,db)
|
||||
return response.download(request, db)
|
||||
|
||||
|
||||
def csv():
|
||||
import gluon.contenttype
|
||||
@@ -150,26 +149,27 @@ def csv():
|
||||
if not query:
|
||||
return None
|
||||
response.headers['Content-disposition'] = 'attachment; filename=%s_%s.csv'\
|
||||
% tuple(request.vars.query.split('.')[:2])
|
||||
return str(db(query,ignore_common_filters=True).select())
|
||||
% tuple(request.vars.query.split('.')[:2])
|
||||
return str(db(query, ignore_common_filters=True).select())
|
||||
|
||||
|
||||
def import_csv(table, file):
|
||||
table.import_from_csv_file(file)
|
||||
|
||||
|
||||
def select():
|
||||
import re
|
||||
db = get_database(request)
|
||||
dbname = request.args[0]
|
||||
regex = re.compile('(?P<table>\w+)\.(?P<field>\w+)=(?P<value>\d+)')
|
||||
if len(request.args)>1 and hasattr(db[request.args[1]],'_primarykey'):
|
||||
if len(request.args) > 1 and hasattr(db[request.args[1]], '_primarykey'):
|
||||
regex = re.compile('(?P<table>\w+)\.(?P<field>\w+)=(?P<value>.+)')
|
||||
if request.vars.query:
|
||||
match = regex.match(request.vars.query)
|
||||
if match:
|
||||
request.vars.query = '%s.%s.%s==%s' % (request.args[0],
|
||||
match.group('table'), match.group('field'),
|
||||
match.group('value'))
|
||||
match.group('table'), match.group('field'),
|
||||
match.group('value'))
|
||||
else:
|
||||
request.vars.query = session.last_query
|
||||
query = get_query(request)
|
||||
@@ -193,14 +193,17 @@ def select():
|
||||
session.last_query = request.vars.query
|
||||
form = FORM(TABLE(TR(T('Query:'), '', INPUT(_style='width:400px',
|
||||
_name='query', _value=request.vars.query or '',
|
||||
requires=IS_NOT_EMPTY(error_message=T("Cannot be empty")))), TR(T('Update:'),
|
||||
requires=IS_NOT_EMPTY(
|
||||
error_message=T("Cannot be empty")))), TR(T('Update:'),
|
||||
INPUT(_name='update_check', _type='checkbox',
|
||||
value=False), INPUT(_style='width:400px',
|
||||
_name='update_fields', _value=request.vars.update_fields
|
||||
or '')), TR(T('Delete:'), INPUT(_name='delete_check',
|
||||
or '')), TR(T('Delete:'), INPUT(_name='delete_check',
|
||||
_class='delete', _type='checkbox', value=False), ''),
|
||||
TR('', '', INPUT(_type='submit', _value=T('submit')))),
|
||||
_action=URL(r=request,args=request.args))
|
||||
_action=URL(r=request, args=request.args))
|
||||
|
||||
tb = None
|
||||
if form.accepts(request.vars, formname=None):
|
||||
regex = re.compile(request.args[0] + '\.(?P<table>\w+)\..+')
|
||||
match = regex.match(form.vars.query.strip())
|
||||
@@ -210,26 +213,30 @@ def select():
|
||||
nrows = db(query).count()
|
||||
if form.vars.update_check and form.vars.update_fields:
|
||||
db(query).update(**eval_in_global_env('dict(%s)'
|
||||
% form.vars.update_fields))
|
||||
% form.vars.update_fields))
|
||||
response.flash = T('%s %%{row} updated', nrows)
|
||||
elif form.vars.delete_check:
|
||||
db(query).delete()
|
||||
response.flash = T('%s %%{row} deleted', nrows)
|
||||
nrows = db(query).count()
|
||||
if orderby:
|
||||
rows = db(query,ignore_common_filters=True).select(limitby=(start, stop), orderby=eval_in_global_env(orderby))
|
||||
rows = db(query, ignore_common_filters=True).select(limitby=(
|
||||
start, stop), orderby=eval_in_global_env(orderby))
|
||||
else:
|
||||
rows = db(query,ignore_common_filters=True).select(limitby=(start, stop))
|
||||
rows = db(query, ignore_common_filters=True).select(
|
||||
limitby=(start, stop))
|
||||
except Exception, e:
|
||||
import traceback
|
||||
tb = traceback.format_exc()
|
||||
(rows, nrows) = ([], 0)
|
||||
response.flash = DIV(T('Invalid Query'),PRE(str(e)))
|
||||
response.flash = DIV(T('Invalid Query'), PRE(str(e)))
|
||||
# begin handle upload csv
|
||||
csv_table = table or request.vars.table
|
||||
if csv_table:
|
||||
formcsv = FORM(str(T('or import from csv file'))+" ",
|
||||
INPUT(_type='file',_name='csvfile'),
|
||||
INPUT(_type='hidden',_value=csv_table,_name='table'),
|
||||
INPUT(_type='submit',_value=T('import')))
|
||||
formcsv = FORM(str(T('or import from csv file')) + " ",
|
||||
INPUT(_type='file', _name='csvfile'),
|
||||
INPUT(_type='hidden', _value=csv_table, _name='table'),
|
||||
INPUT(_type='submit', _value=T('import')))
|
||||
else:
|
||||
formcsv = None
|
||||
if formcsv and formcsv.process().accepted:
|
||||
@@ -238,7 +245,7 @@ def select():
|
||||
request.vars.csvfile.file)
|
||||
response.flash = T('data uploaded')
|
||||
except Exception, e:
|
||||
response.flash = DIV(T('unable to parse csv file'),PRE(str(e)))
|
||||
response.flash = DIV(T('unable to parse csv file'), PRE(str(e)))
|
||||
# end handle upload csv
|
||||
|
||||
return dict(
|
||||
@@ -249,8 +256,9 @@ def select():
|
||||
nrows=nrows,
|
||||
rows=rows,
|
||||
query=request.vars.query,
|
||||
formcsv = formcsv,
|
||||
)
|
||||
formcsv=formcsv,
|
||||
tb=tb,
|
||||
)
|
||||
|
||||
|
||||
# ##########################################################
|
||||
@@ -260,14 +268,16 @@ def select():
|
||||
|
||||
def update():
|
||||
(db, table) = get_table(request)
|
||||
keyed = hasattr(db[table],'_primarykey')
|
||||
keyed = hasattr(db[table], '_primarykey')
|
||||
record = None
|
||||
if keyed:
|
||||
key = [f for f in request.vars if f in db[table]._primarykey]
|
||||
if key:
|
||||
record = db(db[table][key[0]] == request.vars[key[0]], ignore_common_filters=True).select().first()
|
||||
record = db(db[table][key[0]] == request.vars[key[
|
||||
0]], ignore_common_filters=True).select().first()
|
||||
else:
|
||||
record = db(db[table].id == request.args(2),ignore_common_filters=True).select().first()
|
||||
record = db(db[table].id == request.args(
|
||||
2), ignore_common_filters=True).select().first()
|
||||
|
||||
if not record:
|
||||
qry = query_by_table_type(table, db)
|
||||
@@ -277,20 +287,21 @@ def update():
|
||||
|
||||
if keyed:
|
||||
for k in db[table]._primarykey:
|
||||
db[table][k].writable=False
|
||||
db[table][k].writable = False
|
||||
|
||||
form = SQLFORM(db[table], record, deletable=True, delete_label=T('Check to delete'),
|
||||
ignore_rw=ignore_rw and not keyed,
|
||||
linkto=URL('select',
|
||||
form = SQLFORM(
|
||||
db[table], record, deletable=True, delete_label=T('Check to delete'),
|
||||
ignore_rw=ignore_rw and not keyed,
|
||||
linkto=URL('select',
|
||||
args=request.args[:1]), upload=URL(r=request,
|
||||
f='download', args=request.args[:1]))
|
||||
f='download', args=request.args[:1]))
|
||||
|
||||
if form.accepts(request.vars, session):
|
||||
session.flash = T('done!')
|
||||
qry = query_by_table_type(table, db)
|
||||
redirect(URL('select', args=request.args[:1],
|
||||
vars=dict(query=qry)))
|
||||
return dict(form=form,table=db[table])
|
||||
return dict(form=form, table=db[table])
|
||||
|
||||
|
||||
# ##########################################################
|
||||
@@ -301,11 +312,15 @@ def update():
|
||||
def state():
|
||||
return dict()
|
||||
|
||||
|
||||
def ccache():
|
||||
form = FORM(
|
||||
P(TAG.BUTTON(T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
|
||||
P(TAG.BUTTON(T("Clear RAM"), _type="submit", _name="ram", _value="ram")),
|
||||
P(TAG.BUTTON(T("Clear DISK"), _type="submit", _name="disk", _value="disk")),
|
||||
P(TAG.BUTTON(
|
||||
T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
|
||||
P(TAG.BUTTON(
|
||||
T("Clear RAM"), _type="submit", _name="ram", _value="ram")),
|
||||
P(TAG.BUTTON(
|
||||
T("Clear DISK"), _type="submit", _name="disk", _value="disk")),
|
||||
)
|
||||
|
||||
if form.accepts(request.vars, session):
|
||||
@@ -329,11 +344,16 @@ def ccache():
|
||||
redirect(URL(r=request))
|
||||
|
||||
try:
|
||||
from guppy import hpy; hp=hpy()
|
||||
from guppy import hpy
|
||||
hp = hpy()
|
||||
except ImportError:
|
||||
hp = False
|
||||
|
||||
import shelve, os, copy, time, math
|
||||
import shelve
|
||||
import os
|
||||
import copy
|
||||
import time
|
||||
import math
|
||||
from gluon import portalocker
|
||||
|
||||
ram = {
|
||||
@@ -378,9 +398,10 @@ def ccache():
|
||||
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
|
||||
|
||||
locker = open(os.path.join(request.folder,
|
||||
'cache/cache.lock'), 'a')
|
||||
'cache/cache.lock'), 'a')
|
||||
portalocker.lock(locker, portalocker.LOCK_EX)
|
||||
disk_storage = shelve.open(os.path.join(request.folder, 'cache/cache.shelve'))
|
||||
disk_storage = shelve.open(
|
||||
os.path.join(request.folder, 'cache/cache.shelve'))
|
||||
try:
|
||||
for key, value in disk_storage.items():
|
||||
if isinstance(value, dict):
|
||||
@@ -411,7 +432,8 @@ def ccache():
|
||||
total['misses'] = ram['misses'] + disk['misses']
|
||||
total['keys'] = ram['keys'] + disk['keys']
|
||||
try:
|
||||
total['ratio'] = total['hits'] * 100 / (total['hits'] + total['misses'])
|
||||
total['ratio'] = total['hits'] * 100 / (total['hits'] +
|
||||
total['misses'])
|
||||
except (KeyError, ZeroDivisionError):
|
||||
total['ratio'] = 0
|
||||
|
||||
@@ -437,6 +459,3 @@ def ccache():
|
||||
|
||||
return dict(form=form, total=total,
|
||||
ram=ram, disk=disk, object_stats=hp != False)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -5,35 +5,39 @@ import gluon.contrib.shell
|
||||
import gluon.dal
|
||||
import gluon.html
|
||||
import gluon.validators
|
||||
import code, thread
|
||||
import code
|
||||
import thread
|
||||
from gluon.debug import communicate, web_debugger, qdb_debugger
|
||||
import pydoc
|
||||
|
||||
|
||||
if DEMO_MODE or MULTI_USER_MODE:
|
||||
session.flash = T('disabled in demo mode')
|
||||
redirect(URL('default','site'))
|
||||
redirect(URL('default', 'site'))
|
||||
|
||||
FE = 10 ** 9
|
||||
|
||||
FE=10**9
|
||||
|
||||
def index():
|
||||
app = request.args(0) or 'admin'
|
||||
reset()
|
||||
# read buffer
|
||||
data = communicate()
|
||||
return dict(app=app,data=data)
|
||||
return dict(app=app, data=data)
|
||||
|
||||
|
||||
def callback():
|
||||
app = request.args[0]
|
||||
command = request.vars.statement
|
||||
session['debug_commands:'+app].append(command)
|
||||
session['debug_commands:' + app].append(command)
|
||||
output = communicate(command)
|
||||
k = len(session['debug_commands:'+app]) - 1
|
||||
k = len(session['debug_commands:' + app]) - 1
|
||||
return '[%i] %s%s\n' % (k + 1, command, output)
|
||||
|
||||
|
||||
def reset():
|
||||
app = request.args(0) or 'admin'
|
||||
session['debug_commands:'+app] = []
|
||||
session['debug_commands:' + app] = []
|
||||
return 'done'
|
||||
|
||||
|
||||
@@ -50,9 +54,9 @@ def interact():
|
||||
filename = web_debugger.filename
|
||||
lineno = web_debugger.lineno
|
||||
if filename:
|
||||
lines = dict([(i+1, l) for (i, l) in enumerate(
|
||||
[l.strip("\n").strip("\r") for l
|
||||
in open(filename).readlines()])])
|
||||
lines = dict([(i + 1, l) for (i, l) in enumerate(
|
||||
[l.strip("\n").strip("\r") for l
|
||||
in open(filename).readlines()])])
|
||||
filename = os.path.basename(filename)
|
||||
else:
|
||||
lines = {}
|
||||
@@ -64,8 +68,8 @@ def interact():
|
||||
f_globals = {}
|
||||
for name, value in env['globals'].items():
|
||||
if name not in gluon.html.__all__ and \
|
||||
name not in gluon.validators.__all__ and \
|
||||
name not in gluon.dal.__all__:
|
||||
name not in gluon.validators.__all__ and \
|
||||
name not in gluon.dal.__all__:
|
||||
f_globals[name] = pydoc.text.repr(value)
|
||||
else:
|
||||
f_locals = {}
|
||||
@@ -76,42 +80,48 @@ def interact():
|
||||
response.flash = T('"User Exception" debug mode. '
|
||||
'An error ticket could be issued!')
|
||||
|
||||
return dict(app=app, data="",
|
||||
filename=web_debugger.filename, lines=lines, lineno=lineno,
|
||||
f_globals=f_globals, f_locals=f_locals,
|
||||
return dict(app=app, data="",
|
||||
filename=web_debugger.filename, lines=lines, lineno=lineno,
|
||||
f_globals=f_globals, f_locals=f_locals,
|
||||
exception=web_debugger.exception_info)
|
||||
|
||||
|
||||
def step():
|
||||
web_debugger.do_step()
|
||||
redirect(URL("interact"))
|
||||
|
||||
|
||||
def next():
|
||||
web_debugger.do_next()
|
||||
redirect(URL("interact"))
|
||||
|
||||
|
||||
def cont():
|
||||
web_debugger.do_continue()
|
||||
redirect(URL("interact"))
|
||||
|
||||
|
||||
def ret():
|
||||
web_debugger.do_return()
|
||||
redirect(URL("interact"))
|
||||
|
||||
|
||||
def stop():
|
||||
web_debugger.do_quit()
|
||||
redirect(URL("interact"))
|
||||
|
||||
|
||||
def execute():
|
||||
app = request.args[0]
|
||||
command = request.vars.statement
|
||||
session['debug_commands:'+app].append(command)
|
||||
session['debug_commands:' + app].append(command)
|
||||
try:
|
||||
output = web_debugger.do_exec(command)
|
||||
if output is None:
|
||||
output = ""
|
||||
except Exception, e:
|
||||
output = T("Exception %s") % str(e)
|
||||
k = len(session['debug_commands:'+app]) - 1
|
||||
output = T("Exception %s") % str(e)
|
||||
k = len(session['debug_commands:' + app]) - 1
|
||||
return '[%i] %s%s\n' % (k + 1, command, output)
|
||||
|
||||
|
||||
@@ -120,51 +130,51 @@ def breakpoints():
|
||||
|
||||
# Get all .py files
|
||||
files = listdir(apath('', r=request), '.*\.py$')
|
||||
files = [filename for filename in files
|
||||
if filename and 'languages' not in filename
|
||||
and not filename.startswith("admin")
|
||||
and not filename.startswith("examples")]
|
||||
files = [filename for filename in files
|
||||
if filename and 'languages' not in filename
|
||||
and not filename.startswith("admin")
|
||||
and not filename.startswith("examples")]
|
||||
|
||||
form = SQLFORM.factory(
|
||||
Field('filename', requires=IS_IN_SET(files), label=T("Filename")),
|
||||
Field('lineno', 'integer', label=T("Line number"),
|
||||
requires=IS_NOT_EMPTY()),
|
||||
Field('temporary', 'boolean', label=T("Temporary"),
|
||||
Field('temporary', 'boolean', label=T("Temporary"),
|
||||
comment=T("deleted after first hit")),
|
||||
Field('condition', 'string', label=T("Condition"),
|
||||
comment=T("honored only if the expression evaluates to true")),
|
||||
)
|
||||
)
|
||||
|
||||
if form.accepts(request.vars, session):
|
||||
filename = os.path.join(request.env['applications_parent'],
|
||||
filename = os.path.join(request.env['applications_parent'],
|
||||
'applications', form.vars.filename)
|
||||
err = qdb_debugger.do_set_breakpoint(filename,
|
||||
form.vars.lineno,
|
||||
form.vars.temporary,
|
||||
form.vars.condition)
|
||||
err = qdb_debugger.do_set_breakpoint(filename,
|
||||
form.vars.lineno,
|
||||
form.vars.temporary,
|
||||
form.vars.condition)
|
||||
response.flash = T("Set Breakpoint on %s at line %s: %s") % (
|
||||
filename, form.vars.lineno, err or T('successful'))
|
||||
filename, form.vars.lineno, err or T('successful'))
|
||||
|
||||
for item in request.vars:
|
||||
if item[:7] == 'delete_':
|
||||
qdb_debugger.do_clear(item[7:])
|
||||
|
||||
breakpoints = [{'number': bp[0], 'filename': os.path.basename(bp[1]),
|
||||
'path': bp[1], 'lineno': bp[2],
|
||||
'temporary': bp[3], 'enabled': bp[4], 'hits': bp[5],
|
||||
'condition': bp[6]}
|
||||
for bp in qdb_debugger.do_list_breakpoint()]
|
||||
'path': bp[1], 'lineno': bp[2],
|
||||
'temporary': bp[3], 'enabled': bp[4], 'hits': bp[5],
|
||||
'condition': bp[6]}
|
||||
for bp in qdb_debugger.do_list_breakpoint()]
|
||||
|
||||
return dict(breakpoints=breakpoints, form=form)
|
||||
|
||||
|
||||
def toggle_breakpoint():
|
||||
"Set or clear a breakpoint"
|
||||
|
||||
|
||||
lineno = None
|
||||
ok = None
|
||||
try:
|
||||
filename = os.path.join(request.env['applications_parent'],
|
||||
filename = os.path.join(request.env['applications_parent'],
|
||||
'applications', request.vars.filename)
|
||||
if not request.vars.data:
|
||||
# ace send us the line number!
|
||||
@@ -184,18 +194,17 @@ def toggle_breakpoint():
|
||||
no, bp_filename, bp_lineno, temporary, enabled, hits, cond = bp
|
||||
if filename == bp_filename and lineno == bp_lineno:
|
||||
err = qdb_debugger.do_clear_breakpoint(filename, lineno)
|
||||
response.flash = T("Removed Breakpoint on %s at line %s", (
|
||||
filename, lineno))
|
||||
response.flash = T("Removed Breakpoint on %s at line %s", (
|
||||
filename, lineno))
|
||||
ok = False
|
||||
break
|
||||
else:
|
||||
err = qdb_debugger.do_set_breakpoint(filename, lineno)
|
||||
response.flash = T("Set Breakpoint on %s at line %s: %s") % (
|
||||
filename, lineno, err or T('successful'))
|
||||
filename, lineno, err or T('successful'))
|
||||
ok = True
|
||||
else:
|
||||
response.flash = T("Unable to determine the line number!")
|
||||
except Exception, e:
|
||||
session.flash = str(e)
|
||||
return response.json({'ok': ok, 'lineno': lineno})
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,85 +9,92 @@ try:
|
||||
import shutil
|
||||
from gluon.fileutils import read_file, write_file
|
||||
except:
|
||||
session.flash='sorry, only on Unix systems'
|
||||
redirect(URL(request.application,'default','site'))
|
||||
session.flash = 'sorry, only on Unix systems'
|
||||
redirect(URL(request.application, 'default', 'site'))
|
||||
|
||||
if MULTI_USER_MODE and not is_manager():
|
||||
session.flash = 'Not Authorized'
|
||||
redirect(URL('default','site'))
|
||||
redirect(URL('default', 'site'))
|
||||
|
||||
forever = 10 ** 8
|
||||
|
||||
forever=10**8
|
||||
|
||||
def kill():
|
||||
p = cache.ram('gae_upload',lambda:None,forever)
|
||||
if not p or p.poll()!=None:
|
||||
p = cache.ram('gae_upload', lambda: None, forever)
|
||||
if not p or p.poll() is not None:
|
||||
return 'oops'
|
||||
os.kill(p.pid, signal.SIGKILL)
|
||||
cache.ram('gae_upload',lambda:None,-1)
|
||||
cache.ram('gae_upload', lambda: None, -1)
|
||||
|
||||
|
||||
class EXISTS(object):
|
||||
def __init__(self, error_message='file not found'):
|
||||
self.error_message = error_message
|
||||
|
||||
def __call__(self, value):
|
||||
if os.path.exists(value):
|
||||
return (value,None)
|
||||
return (value,self.error_message)
|
||||
return (value, None)
|
||||
return (value, self.error_message)
|
||||
|
||||
|
||||
def deploy():
|
||||
regex = re.compile('^\w+$')
|
||||
apps = sorted(file for file in os.listdir(apath(r=request)) if regex.match(file))
|
||||
apps = sorted(
|
||||
file for file in os.listdir(apath(r=request)) if regex.match(file))
|
||||
form = SQLFORM.factory(
|
||||
Field('appcfg',default=GAE_APPCFG,label=T('Path to appcfg.py'),
|
||||
Field('appcfg', default=GAE_APPCFG, label=T('Path to appcfg.py'),
|
||||
requires=EXISTS(error_message=T('file not found'))),
|
||||
Field('google_application_id',requires=IS_ALPHANUMERIC(),label=T('Google Application Id')),
|
||||
Field('applications','list:string',
|
||||
requires=IS_IN_SET(apps,multiple=True),
|
||||
Field('google_application_id', requires=IS_MATCH(
|
||||
'[\w\-]+'), label=T('Google Application Id')),
|
||||
Field('applications', 'list:string',
|
||||
requires=IS_IN_SET(apps, multiple=True),
|
||||
label=T('web2py apps to deploy')),
|
||||
Field('email',requires=IS_EMAIL(),label=T('GAE Email')),
|
||||
Field('password','password',requires=IS_NOT_EMPTY(),label=T('GAE Password')))
|
||||
cmd = output = errors= ""
|
||||
if form.accepts(request,session):
|
||||
Field('email', requires=IS_EMAIL(), label=T('GAE Email')),
|
||||
Field('password', 'password', requires=IS_NOT_EMPTY(), label=T('GAE Password')))
|
||||
cmd = output = errors = ""
|
||||
if form.accepts(request, session):
|
||||
try:
|
||||
kill()
|
||||
except:
|
||||
pass
|
||||
ignore_apps = [item for item in apps \
|
||||
if not item in form.vars.applications]
|
||||
ignore_apps = [item for item in apps
|
||||
if not item in form.vars.applications]
|
||||
regex = re.compile('\(applications/\(.*')
|
||||
yaml = apath('../app.yaml', r=request)
|
||||
if not os.path.exists(yaml):
|
||||
example = apath('../app.example.yaml', r=request)
|
||||
shutil.copyfile(example,yaml)
|
||||
shutil.copyfile(example, yaml)
|
||||
data = read_file(yaml)
|
||||
data = re.sub('application:.*','application: %s' % form.vars.google_application_id,data)
|
||||
data = regex.sub('(applications/(%s)/.*)|' % '|'.join(ignore_apps),data)
|
||||
data = re.sub('application:.*', 'application: %s' %
|
||||
form.vars.google_application_id, data)
|
||||
data = regex.sub(
|
||||
'(applications/(%s)/.*)|' % '|'.join(ignore_apps), data)
|
||||
write_file(yaml, data)
|
||||
|
||||
path = request.env.applications_parent
|
||||
cmd = '%s --email=%s --passin update %s' % \
|
||||
(form.vars.appcfg, form.vars.email, path)
|
||||
p = cache.ram('gae_upload',
|
||||
lambda s=subprocess,c=cmd:s.Popen(c, shell=True,
|
||||
stdin=s.PIPE,
|
||||
stdout=s.PIPE,
|
||||
stderr=s.PIPE, close_fds=True),-1)
|
||||
p.stdin.write(form.vars.password+'\n')
|
||||
lambda s=subprocess, c=cmd: s.Popen(c, shell=True,
|
||||
stdin=s.PIPE,
|
||||
stdout=s.PIPE,
|
||||
stderr=s.PIPE, close_fds=True), -1)
|
||||
p.stdin.write(form.vars.password + '\n')
|
||||
fcntl.fcntl(p.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
|
||||
fcntl.fcntl(p.stderr.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
|
||||
return dict(form=form,command=cmd)
|
||||
return dict(form=form, command=cmd)
|
||||
|
||||
|
||||
def callback():
|
||||
p = cache.ram('gae_upload',lambda:None,forever)
|
||||
if not p or p.poll()!=None:
|
||||
p = cache.ram('gae_upload', lambda: None, forever)
|
||||
if not p or p.poll() is not None:
|
||||
return '<done/>'
|
||||
try:
|
||||
output = p.stdout.read()
|
||||
except:
|
||||
output=''
|
||||
output = ''
|
||||
try:
|
||||
errors = p.stderr.read()
|
||||
except:
|
||||
errors=''
|
||||
return (output+errors).replace('\n','<br/>')
|
||||
|
||||
|
||||
errors = ''
|
||||
return (output + errors).replace('\n', '<br/>')
|
||||
|
||||
@@ -2,10 +2,10 @@ from gluon.fileutils import read_file, write_file
|
||||
|
||||
if DEMO_MODE or MULTI_USER_MODE:
|
||||
session.flash = T('disabled in demo mode')
|
||||
redirect(URL('default','site'))
|
||||
redirect(URL('default', 'site'))
|
||||
if not have_mercurial:
|
||||
session.flash=T("Sorry, could not find mercurial installed")
|
||||
redirect(URL('default','design',args=request.args(0)))
|
||||
session.flash = T("Sorry, could not find mercurial installed")
|
||||
redirect(URL('default', 'design', args=request.args(0)))
|
||||
|
||||
_hgignore_content = """\
|
||||
syntax: glob
|
||||
@@ -22,6 +22,7 @@ sessions/*
|
||||
errors/*
|
||||
"""
|
||||
|
||||
|
||||
def hg_repo(path):
|
||||
import os
|
||||
uio = ui.ui()
|
||||
@@ -37,13 +38,14 @@ def hg_repo(path):
|
||||
write_file(hgignore, _hgignore_content)
|
||||
return repo
|
||||
|
||||
|
||||
def commit():
|
||||
app = request.args(0)
|
||||
path = apath(app, r=request)
|
||||
repo = hg_repo(path)
|
||||
form = FORM('Comment:',INPUT(_name='comment',requires=IS_NOT_EMPTY()),
|
||||
INPUT(_type='submit',_value=T('Commit')))
|
||||
if form.accepts(request.vars,session):
|
||||
form = FORM('Comment:', INPUT(_name='comment', requires=IS_NOT_EMPTY()),
|
||||
INPUT(_type='submit', _value=T('Commit')))
|
||||
if form.accepts(request.vars, session):
|
||||
oldid = repo[repo.lookup('.')]
|
||||
addremove(repo)
|
||||
repo.commit(text=form.vars.comment)
|
||||
@@ -51,34 +53,33 @@ def commit():
|
||||
response.flash = 'no changes'
|
||||
try:
|
||||
files = TABLE(*[TR(file) for file in repo[repo.lookup('.')].files()])
|
||||
changes = TABLE(TR(TH('revision'),TH('description')))
|
||||
changes = TABLE(TR(TH('revision'), TH('description')))
|
||||
for change in repo.changelog:
|
||||
ctx=repo.changectx(change)
|
||||
ctx = repo.changectx(change)
|
||||
revision, description = ctx.rev(), ctx.description()
|
||||
changes.append(TR(A(revision,_href=URL('revision',
|
||||
args=(app,revision))),
|
||||
changes.append(TR(A(revision, _href=URL('revision',
|
||||
args=(app, revision))),
|
||||
description))
|
||||
except:
|
||||
files = []
|
||||
changes = []
|
||||
return dict(form=form,files=files,changes=changes,repo=repo)
|
||||
return dict(form=form, files=files, changes=changes, repo=repo)
|
||||
|
||||
|
||||
def revision():
|
||||
app = request.args(0)
|
||||
path = apath(app, r=request)
|
||||
repo = hg_repo(path)
|
||||
revision = request.args(1)
|
||||
ctx=repo.changectx(revision)
|
||||
form=FORM(INPUT(_type='submit',_value=T('Revert')))
|
||||
ctx = repo.changectx(revision)
|
||||
form = FORM(INPUT(_type='submit', _value=T('Revert')))
|
||||
if form.accepts(request.vars):
|
||||
hg.update(repo, revision)
|
||||
session.flash = "reverted to revision %s" % ctx.rev()
|
||||
redirect(URL('default','design',args=app))
|
||||
redirect(URL('default', 'design', args=app))
|
||||
return dict(
|
||||
files=ctx.files(),
|
||||
rev=str(ctx.rev()),
|
||||
desc=ctx.description(),
|
||||
form=form
|
||||
)
|
||||
|
||||
|
||||
)
|
||||
|
||||
@@ -1,29 +1,36 @@
|
||||
import os
|
||||
from distutils import dir_util
|
||||
try:
|
||||
from distutils import dir_util
|
||||
except ImportError:
|
||||
session.flash = T('requires distutils, but not installed')
|
||||
redirect(URL('default', 'site'))
|
||||
try:
|
||||
from git import *
|
||||
except ImportError:
|
||||
session.flash = T('requires python-git, but not installed')
|
||||
redirect(URL('default','site'))
|
||||
redirect(URL('default', 'site'))
|
||||
|
||||
|
||||
def deploy():
|
||||
apps = sorted(file for file in os.listdir(apath(r=request)))
|
||||
form = SQLFORM.factory(
|
||||
Field('osrepo',default='/tmp',label=T('Path to local openshift repo root.'),
|
||||
requires=EXISTS(error_message=T('directory not found'))),
|
||||
Field('osname',default='web2py',label=T('WSGI reference name')),
|
||||
Field('applications','list:string',
|
||||
requires=IS_IN_SET(apps,multiple=True),
|
||||
Field(
|
||||
'osrepo', default='/tmp', label=T('Path to local openshift repo root.'),
|
||||
requires=EXISTS(error_message=T('directory not found'))),
|
||||
Field('osname', default='web2py', label=T('WSGI reference name')),
|
||||
Field('applications', 'list:string',
|
||||
requires=IS_IN_SET(apps, multiple=True),
|
||||
label=T('web2py apps to deploy')))
|
||||
|
||||
cmd = output = errors= ""
|
||||
if form.accepts(request,session):
|
||||
cmd = output = errors = ""
|
||||
if form.accepts(request, session):
|
||||
try:
|
||||
kill()
|
||||
except:
|
||||
pass
|
||||
|
||||
ignore_apps = [item for item in apps if not item in form.vars.applications]
|
||||
|
||||
ignore_apps = [
|
||||
item for item in apps if not item in form.vars.applications]
|
||||
regex = re.compile('\(applications/\(.*')
|
||||
w2p_origin = os.getcwd()
|
||||
osrepo = form.vars.osrepo
|
||||
@@ -34,23 +41,25 @@ def deploy():
|
||||
assert repo.bare == False
|
||||
|
||||
for i in form.vars.applications:
|
||||
appsrc = os.path.join(apath(r=request),i)
|
||||
appdest = os.path.join(osrepo,'wsgi',osname,'applications',i)
|
||||
dir_util.copy_tree(appsrc,appdest)
|
||||
appsrc = os.path.join(apath(r=request), i)
|
||||
appdest = os.path.join(osrepo, 'wsgi', osname, 'applications', i)
|
||||
dir_util.copy_tree(appsrc, appdest)
|
||||
#shutil.copytree(appsrc,appdest)
|
||||
index.add(['wsgi/'+osname+'/applications/'+i])
|
||||
index.add(['wsgi/' + osname + '/applications/' + i])
|
||||
new_commit = index.commit("Deploy from Web2py IDE")
|
||||
|
||||
|
||||
origin = repo.remotes.origin
|
||||
origin.push
|
||||
origin.push()
|
||||
#Git code ends here
|
||||
return dict(form=form,command=cmd)
|
||||
|
||||
return dict(form=form, command=cmd)
|
||||
|
||||
|
||||
class EXISTS(object):
|
||||
def __init__(self, error_message='file not found'):
|
||||
self.error_message = error_message
|
||||
|
||||
def __call__(self, value):
|
||||
if os.path.exists(value):
|
||||
return (value,None)
|
||||
return (value,self.error_message)
|
||||
return (value, None)
|
||||
return (value, self.error_message)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
response.files=response.files[:3]
|
||||
response.menu=[]
|
||||
response.files = response.files[:3]
|
||||
response.menu = []
|
||||
|
||||
|
||||
def index():
|
||||
return locals()
|
||||
|
||||
|
||||
def about():
|
||||
return locals()
|
||||
|
||||
|
||||
|
||||
@@ -1,25 +1,29 @@
|
||||
import sys
|
||||
import cStringIO
|
||||
import gluon.contrib.shell
|
||||
import code, thread
|
||||
import code
|
||||
import thread
|
||||
from gluon.shell import env
|
||||
|
||||
if DEMO_MODE or MULTI_USER_MODE:
|
||||
session.flash = T('disabled in demo mode')
|
||||
redirect(URL('default','site'))
|
||||
redirect(URL('default', 'site'))
|
||||
|
||||
FE = 10 ** 9
|
||||
|
||||
FE=10**9
|
||||
|
||||
def index():
|
||||
app = request.args(0) or 'admin'
|
||||
reset()
|
||||
return dict(app=app)
|
||||
|
||||
|
||||
def callback():
|
||||
app = request.args[0]
|
||||
command = request.vars.statement
|
||||
escape = command[:1]!='!'
|
||||
history = session['history:'+app] = session.get('history:'+app,gluon.contrib.shell.History())
|
||||
escape = command[:1] != '!'
|
||||
history = session['history:' + app] = session.get(
|
||||
'history:' + app, gluon.contrib.shell.History())
|
||||
if not escape:
|
||||
command = command[1:]
|
||||
if command == '%reset':
|
||||
@@ -27,21 +31,20 @@ def callback():
|
||||
return '*** reset ***'
|
||||
elif command[0] == '%':
|
||||
try:
|
||||
command=session['commands:'+app][int(command[1:])]
|
||||
command = session['commands:' + app][int(command[1:])]
|
||||
except ValueError:
|
||||
return ''
|
||||
session['commands:'+app].append(command)
|
||||
environ=env(app,True)
|
||||
output = gluon.contrib.shell.run(history,command,environ)
|
||||
k = len(session['commands:'+app]) - 1
|
||||
session['commands:' + app].append(command)
|
||||
environ = env(app, True)
|
||||
output = gluon.contrib.shell.run(history, command, environ)
|
||||
k = len(session['commands:' + app]) - 1
|
||||
#output = PRE(output)
|
||||
#return TABLE(TR('In[%i]:'%k,PRE(command)),TR('Out[%i]:'%k,output))
|
||||
return 'In [%i] : %s%s\n' % (k + 1, command, output)
|
||||
|
||||
|
||||
def reset():
|
||||
app = request.args(0) or 'admin'
|
||||
session['commands:'+app] = []
|
||||
session['history:'+app] = gluon.contrib.shell.History()
|
||||
session['commands:' + app] = []
|
||||
session['history:' + app] = gluon.contrib.shell.History()
|
||||
return 'done'
|
||||
|
||||
|
||||
|
||||
@@ -2,10 +2,12 @@ import os
|
||||
from gluon.settings import global_settings, read_file
|
||||
#
|
||||
|
||||
|
||||
def index():
|
||||
app = request.args(0)
|
||||
return dict(app=app)
|
||||
|
||||
|
||||
def profiler():
|
||||
"""
|
||||
to use the profiler start web2py with -F profiler.log
|
||||
@@ -19,13 +21,11 @@ def profiler():
|
||||
else:
|
||||
size = 0
|
||||
if os.path.exists(filename):
|
||||
data = read_file('profiler.log','rb')
|
||||
if size<len(data):
|
||||
data = read_file('profiler.log', 'rb')
|
||||
if size < len(data):
|
||||
data = data[size:]
|
||||
else:
|
||||
size=0
|
||||
size = 0
|
||||
size += len(data)
|
||||
response.cookies[KEY] = size
|
||||
return data
|
||||
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ def list_apps():
|
||||
@service.jsonrpc
|
||||
def list_files(app, pattern='.*\.py$'):
|
||||
files = listdir(apath('%s/' % app, r=request), pattern)
|
||||
return [x.replace('\\','/') for x in files]
|
||||
return [x.replace('\\', '/') for x in files]
|
||||
|
||||
|
||||
@service.jsonrpc
|
||||
@@ -43,7 +43,7 @@ def read_file(filename, b64=False):
|
||||
try:
|
||||
data = f.read()
|
||||
if not b64:
|
||||
data = data.replace('\r','')
|
||||
data = data.replace('\r', '')
|
||||
else:
|
||||
data = base64.b64encode(data)
|
||||
finally:
|
||||
@@ -82,6 +82,7 @@ def install(app_name, filename, data, overwrite=True):
|
||||
|
||||
return installed
|
||||
|
||||
|
||||
@service.jsonrpc
|
||||
def attach_debugger(host='localhost', port=6000, authkey='secret password'):
|
||||
import gluon.contrib.qdb as qdb
|
||||
@@ -90,7 +91,7 @@ def attach_debugger(host='localhost', port=6000, authkey='secret password'):
|
||||
|
||||
if isinstance(authkey, unicode):
|
||||
authkey = authkey.encode('utf8')
|
||||
|
||||
|
||||
if not hasattr(gluon.debug, 'qdb_listener'):
|
||||
# create a remote debugger server and wait for connection
|
||||
address = (host, port) # family is deduced to be 'AF_INET'
|
||||
@@ -124,7 +125,7 @@ def detach_debugger():
|
||||
gluon.debug.qdb_debugger = None
|
||||
return True
|
||||
|
||||
|
||||
def call():
|
||||
session.forget()
|
||||
return service()
|
||||
|
||||
|
||||
@@ -1,64 +1,73 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os, uuid, re, pickle, urllib, glob
|
||||
import os
|
||||
import uuid
|
||||
import re
|
||||
import pickle
|
||||
import urllib
|
||||
import glob
|
||||
from gluon.admin import app_create, plugin_install
|
||||
from gluon.fileutils import abspath, read_file, write_file
|
||||
|
||||
def reset(session):
|
||||
session.app={
|
||||
'name':'',
|
||||
'params':[('title','My New App'),
|
||||
('subtitle','powered by web2py'),
|
||||
('author','you'),
|
||||
('author_email','you@example.com'),
|
||||
('keywords',''),
|
||||
('description',''),
|
||||
('layout_theme','Default'),
|
||||
('database_uri','sqlite://storage.sqlite'),
|
||||
('security_key',str(uuid.uuid4())),
|
||||
('email_server','localhost'),
|
||||
('email_sender','you@example.com'),
|
||||
('email_login',''),
|
||||
('login_method','local'),
|
||||
('login_config',''),
|
||||
('plugins',[])],
|
||||
'tables':['auth_user'],
|
||||
'table_auth_user':['username','first_name',
|
||||
'last_name','email','password'],
|
||||
'pages':['index','error'],
|
||||
'page_index':'# Welcome to my new app',
|
||||
'page_error':'# Error: the document does not exist',
|
||||
}
|
||||
|
||||
if not session.app: reset(session)
|
||||
def reset(session):
|
||||
session.app = {
|
||||
'name': '',
|
||||
'params': [('title', 'My New App'),
|
||||
('subtitle', 'powered by web2py'),
|
||||
('author', 'you'),
|
||||
('author_email', 'you@example.com'),
|
||||
('keywords', ''),
|
||||
('description', ''),
|
||||
('layout_theme', 'Default'),
|
||||
('database_uri', 'sqlite://storage.sqlite'),
|
||||
('security_key', str(uuid.uuid4())),
|
||||
('email_server', 'localhost'),
|
||||
('email_sender', 'you@example.com'),
|
||||
('email_login', ''),
|
||||
('login_method', 'local'),
|
||||
('login_config', ''),
|
||||
('plugins', [])],
|
||||
'tables': ['auth_user'],
|
||||
'table_auth_user': ['username', 'first_name',
|
||||
'last_name', 'email', 'password'],
|
||||
'pages': ['index', 'error'],
|
||||
'page_index': '# Welcome to my new app',
|
||||
'page_error': '# Error: the document does not exist',
|
||||
}
|
||||
|
||||
if not session.app:
|
||||
reset(session)
|
||||
|
||||
|
||||
def listify(x):
|
||||
if not isinstance(x,(list,tuple)):
|
||||
if not isinstance(x, (list, tuple)):
|
||||
return x and [x] or []
|
||||
return x
|
||||
|
||||
|
||||
def clean(name):
|
||||
return re.sub('\W+','_',name.strip().lower())
|
||||
return re.sub('\W+', '_', name.strip().lower())
|
||||
|
||||
|
||||
def index():
|
||||
response.view='wizard/step.html'
|
||||
response.view = 'wizard/step.html'
|
||||
reset(session)
|
||||
apps=os.listdir(os.path.join(request.folder,'..'))
|
||||
form=SQLFORM.factory(Field('name',requires=[IS_NOT_EMPTY(),
|
||||
IS_ALPHANUMERIC()]))
|
||||
apps = os.listdir(os.path.join(request.folder, '..'))
|
||||
form = SQLFORM.factory(Field('name', requires=[IS_NOT_EMPTY(),
|
||||
IS_ALPHANUMERIC()]))
|
||||
if form.accepts(request.vars):
|
||||
app = form.vars.name
|
||||
session.app['name'] = app
|
||||
if MULTI_USER_MODE and db(db.app.name==app)\
|
||||
(db.app.owner!=auth.user.id).count():
|
||||
if MULTI_USER_MODE and db(db.app.name == app)(db.app.owner != auth.user.id).count():
|
||||
session.flash = 'App belongs already to other user'
|
||||
elif app in apps:
|
||||
meta = os.path.normpath(\
|
||||
meta = os.path.normpath(
|
||||
os.path.join(os.path.normpath(request.folder),
|
||||
'..',app,'wizard.metadata'))
|
||||
'..', app, 'wizard.metadata'))
|
||||
if os.path.exists(meta):
|
||||
try:
|
||||
metafile = open(meta,'rb')
|
||||
metafile = open(meta, 'rb')
|
||||
try:
|
||||
session.app = pickle.load(metafile)
|
||||
finally:
|
||||
@@ -67,14 +76,14 @@ def index():
|
||||
except:
|
||||
session.flash = T("The app exists, was NOT created by wizard, continue to overwrite!")
|
||||
redirect(URL('step1'))
|
||||
return dict(step='Start',form=form)
|
||||
return dict(step='Start', form=form)
|
||||
|
||||
|
||||
def step1():
|
||||
from gluon.contrib.simplejson import loads
|
||||
import urllib
|
||||
if not session.themes:
|
||||
url=LAYOUTS_APP+'/default/layouts.json'
|
||||
url = LAYOUTS_APP + '/default/layouts.json'
|
||||
try:
|
||||
data = urllib.urlopen(url).read()
|
||||
session.themes = ['Default'] + loads(data)['layouts']
|
||||
@@ -82,145 +91,158 @@ def step1():
|
||||
session.themes = ['Default']
|
||||
themes = session.themes
|
||||
if not session.plugins:
|
||||
url = PLUGINS_APP+'/default/plugins.json'
|
||||
url = PLUGINS_APP + '/default/plugins.json'
|
||||
try:
|
||||
data = urllib.urlopen(url).read()
|
||||
session.plugins = loads(data)['plugins']
|
||||
except:
|
||||
session.plugins = []
|
||||
plugins = [x.split('.')[2] for x in session.plugins]
|
||||
response.view='wizard/step.html'
|
||||
response.view = 'wizard/step.html'
|
||||
params = dict(session.app['params'])
|
||||
form=SQLFORM.factory(
|
||||
Field('title',default=params.get('title',None),
|
||||
requires=IS_NOT_EMPTY()),
|
||||
Field('subtitle',default=params.get('subtitle',None)),
|
||||
Field('author',default=params.get('author',None)),
|
||||
Field('author_email',default=params.get('author_email',None)),
|
||||
Field('keywords',default=params.get('keywords',None)),
|
||||
Field('description','text',
|
||||
default=params.get('description',None)),
|
||||
Field('layout_theme',requires=IS_IN_SET(themes),
|
||||
default=params.get('layout_theme',themes[0])),
|
||||
Field('database_uri',default=params.get('database_uri',None)),
|
||||
Field('security_key',default=params.get('security_key',None)),
|
||||
Field('email_server',default=params.get('email_server',None)),
|
||||
Field('email_sender',default=params.get('email_sender',None)),
|
||||
Field('email_login',default=params.get('email_login',None)),
|
||||
Field('login_method',requires=IS_IN_SET(('local','janrain')),
|
||||
default=params.get('login_method','local')),
|
||||
Field('login_config',default=params.get('login_config',None)),
|
||||
Field('plugins','list:string',requires=IS_IN_SET(plugins,multiple=True)))
|
||||
form = SQLFORM.factory(
|
||||
Field('title', default=params.get('title', None),
|
||||
requires=IS_NOT_EMPTY()),
|
||||
Field('subtitle', default=params.get('subtitle', None)),
|
||||
Field('author', default=params.get('author', None)),
|
||||
Field(
|
||||
'author_email', default=params.get('author_email', None)),
|
||||
Field('keywords', default=params.get('keywords', None)),
|
||||
Field('description', 'text',
|
||||
default=params.get('description', None)),
|
||||
Field('layout_theme', requires=IS_IN_SET(themes),
|
||||
default=params.get('layout_theme', themes[0])),
|
||||
Field(
|
||||
'database_uri', default=params.get('database_uri', None)),
|
||||
Field(
|
||||
'security_key', default=params.get('security_key', None)),
|
||||
Field(
|
||||
'email_server', default=params.get('email_server', None)),
|
||||
Field(
|
||||
'email_sender', default=params.get('email_sender', None)),
|
||||
Field('email_login', default=params.get('email_login', None)),
|
||||
Field('login_method', requires=IS_IN_SET(('local', 'janrain')),
|
||||
default=params.get('login_method', 'local')),
|
||||
Field(
|
||||
'login_config', default=params.get('login_config', None)),
|
||||
Field('plugins', 'list:string', requires=IS_IN_SET(plugins, multiple=True)))
|
||||
|
||||
if form.accepts(request.vars):
|
||||
session.app['params']=[(key,form.vars.get(key,None))
|
||||
for key,value in session.app['params']]
|
||||
session.app['params'] = [(key, form.vars.get(key, None))
|
||||
for key, value in session.app['params']]
|
||||
redirect(URL('step2'))
|
||||
return dict(step='1: Setting Parameters',form=form)
|
||||
return dict(step='1: Setting Parameters', form=form)
|
||||
|
||||
|
||||
def step2():
|
||||
response.view='wizard/step.html'
|
||||
form=SQLFORM.factory(Field('table_names','list:string',
|
||||
default=session.app['tables']))
|
||||
response.view = 'wizard/step.html'
|
||||
form = SQLFORM.factory(Field('table_names', 'list:string',
|
||||
default=session.app['tables']))
|
||||
if form.accepts(request.vars):
|
||||
table_names = [clean(t) for t in listify(form.vars.table_names) \
|
||||
if t.strip()]
|
||||
if [t for t in table_names if t.startswith('auth_') and \
|
||||
not t=='auth_user']:
|
||||
table_names = [clean(t) for t in listify(form.vars.table_names)
|
||||
if t.strip()]
|
||||
if [t for t in table_names if t.startswith('auth_') and
|
||||
not t == 'auth_user']:
|
||||
form.error.table_names = \
|
||||
T('invalid table names (auth_* tables already defined)')
|
||||
else:
|
||||
session.app['tables']=table_names
|
||||
session.app['tables'] = table_names
|
||||
for table in session.app['tables']:
|
||||
if not 'table_'+table in session.app:
|
||||
session.app['table_'+table]=['name']
|
||||
if not table=='auth_user':
|
||||
name = table+'_manage'
|
||||
if not 'table_' + table in session.app:
|
||||
session.app['table_' + table] = ['name']
|
||||
if not table == 'auth_user':
|
||||
name = table + '_manage'
|
||||
if not name in session.app['pages']:
|
||||
session.app['pages'].append(name)
|
||||
session.app['page_'+name] = \
|
||||
session.app['page_' + name] = \
|
||||
'## Manage %s\n\n{{=form}}' % (table)
|
||||
if session.app['tables']:
|
||||
redirect(URL('step3',args=0))
|
||||
redirect(URL('step3', args=0))
|
||||
else:
|
||||
redirect(URL('step4'))
|
||||
return dict(step='2: Tables',form=form)
|
||||
return dict(step='2: Tables', form=form)
|
||||
|
||||
|
||||
def step3():
|
||||
response.view='wizard/step.html'
|
||||
n=int(request.args(0) or 0)
|
||||
m=len(session.app['tables'])
|
||||
if n>=m: redirect(URL('step2'))
|
||||
table=session.app['tables'][n]
|
||||
form=SQLFORM.factory(Field('field_names','list:string',
|
||||
default=session.app.get('table_'+table,[])))
|
||||
response.view = 'wizard/step.html'
|
||||
n = int(request.args(0) or 0)
|
||||
m = len(session.app['tables'])
|
||||
if n >= m:
|
||||
redirect(URL('step2'))
|
||||
table = session.app['tables'][n]
|
||||
form = SQLFORM.factory(Field('field_names', 'list:string',
|
||||
default=session.app.get('table_' + table, [])))
|
||||
if form.accepts(request.vars) and form.vars.field_names:
|
||||
fields=listify(form.vars.field_names)
|
||||
if table=='auth_user':
|
||||
for field in ['first_name','last_name','username','email','password']:
|
||||
fields = listify(form.vars.field_names)
|
||||
if table == 'auth_user':
|
||||
for field in ['first_name', 'last_name', 'username', 'email', 'password']:
|
||||
if not field in fields:
|
||||
fields.append(field)
|
||||
session.app['table_'+table]=[t.strip().lower()
|
||||
for t in listify(form.vars.field_names)
|
||||
if t.strip()]
|
||||
session.app['table_' + table] = [t.strip().lower()
|
||||
for t in listify(form.vars.field_names)
|
||||
if t.strip()]
|
||||
try:
|
||||
tables=sort_tables(session.app['tables'])
|
||||
tables = sort_tables(session.app['tables'])
|
||||
except RuntimeError:
|
||||
response.flash=T('invalid circular reference')
|
||||
response.flash = T('invalid circular reference')
|
||||
else:
|
||||
if n<m-1:
|
||||
redirect(URL('step3',args=n+1))
|
||||
if n < m - 1:
|
||||
redirect(URL('step3', args=n + 1))
|
||||
else:
|
||||
redirect(URL('step4'))
|
||||
return dict(step='3: Fields for table "%s" (%s of %s)' \
|
||||
% (table,n+1,m),table=table,form=form)
|
||||
return dict(step='3: Fields for table "%s" (%s of %s)'
|
||||
% (table, n + 1, m), table=table, form=form)
|
||||
|
||||
|
||||
def step4():
|
||||
response.view='wizard/step.html'
|
||||
form=SQLFORM.factory(Field('pages','list:string',
|
||||
default=session.app['pages']))
|
||||
response.view = 'wizard/step.html'
|
||||
form = SQLFORM.factory(Field('pages', 'list:string',
|
||||
default=session.app['pages']))
|
||||
if form.accepts(request.vars):
|
||||
session.app['pages']=[clean(t)
|
||||
for t in listify(form.vars.pages)
|
||||
if t.strip()]
|
||||
session.app['pages'] = [clean(t)
|
||||
for t in listify(form.vars.pages)
|
||||
if t.strip()]
|
||||
if session.app['pages']:
|
||||
redirect(URL('step5',args=0))
|
||||
redirect(URL('step5', args=0))
|
||||
else:
|
||||
redirect(URL('step6'))
|
||||
return dict(step='4: Pages',form=form)
|
||||
return dict(step='4: Pages', form=form)
|
||||
|
||||
|
||||
def step5():
|
||||
response.view='wizard/step.html'
|
||||
n=int(request.args(0) or 0)
|
||||
m=len(session.app['pages'])
|
||||
if n>=m: redirect(URL('step4'))
|
||||
page=session.app['pages'][n]
|
||||
markmin_url='http://web2py.com/examples/static/markmin.html'
|
||||
form=SQLFORM.factory(Field('content','text',
|
||||
default=session.app.get('page_'+page,[]),
|
||||
comment=A('use markmin',
|
||||
_href=markmin_url,_target='_blank')),
|
||||
formstyle='table2cols')
|
||||
response.view = 'wizard/step.html'
|
||||
n = int(request.args(0) or 0)
|
||||
m = len(session.app['pages'])
|
||||
if n >= m:
|
||||
redirect(URL('step4'))
|
||||
page = session.app['pages'][n]
|
||||
markmin_url = 'http://web2py.com/examples/static/markmin.html'
|
||||
form = SQLFORM.factory(Field('content', 'text',
|
||||
default=session.app.get('page_' + page, []),
|
||||
comment=A('use markmin',
|
||||
_href=markmin_url, _target='_blank')),
|
||||
formstyle='table2cols')
|
||||
if form.accepts(request.vars):
|
||||
session.app['page_'+page]=form.vars.content
|
||||
if n<m-1:
|
||||
redirect(URL('step5',args=n+1))
|
||||
session.app['page_' + page] = form.vars.content
|
||||
if n < m - 1:
|
||||
redirect(URL('step5', args=n + 1))
|
||||
else:
|
||||
redirect(URL('step6'))
|
||||
return dict(step='5: View for page "%s" (%s of %s)' % (page,n+1,m),form=form)
|
||||
return dict(step='5: View for page "%s" (%s of %s)' % (page, n + 1, m), form=form)
|
||||
|
||||
|
||||
def step6():
|
||||
response.view='wizard/step.html'
|
||||
response.view = 'wizard/step.html'
|
||||
params = dict(session.app['params'])
|
||||
app = session.app['name']
|
||||
form=SQLFORM.factory(
|
||||
Field('generate_model','boolean',default=True),
|
||||
Field('generate_controller','boolean',default=True),
|
||||
Field('generate_views','boolean',default=True),
|
||||
Field('generate_menu','boolean',default=True),
|
||||
Field('apply_layout','boolean',default=True),
|
||||
Field('erase_database','boolean',default=True),
|
||||
Field('populate_database','boolean',default=True))
|
||||
form = SQLFORM.factory(
|
||||
Field('generate_model', 'boolean', default=True),
|
||||
Field('generate_controller', 'boolean', default=True),
|
||||
Field('generate_views', 'boolean', default=True),
|
||||
Field('generate_menu', 'boolean', default=True),
|
||||
Field('apply_layout', 'boolean', default=True),
|
||||
Field('erase_database', 'boolean', default=True),
|
||||
Field('populate_database', 'boolean', default=True))
|
||||
if form.accepts(request.vars):
|
||||
if DEMO_MODE:
|
||||
session.flash = T('Application cannot be generated in demo mode')
|
||||
@@ -228,159 +250,173 @@ def step6():
|
||||
create(form.vars)
|
||||
session.flash = 'Application %s created' % app
|
||||
redirect(URL('generated'))
|
||||
return dict(step='6: Generate app "%s"' % app,form=form)
|
||||
return dict(step='6: Generate app "%s"' % app, form=form)
|
||||
|
||||
|
||||
def generated():
|
||||
return dict(app=session.app['name'])
|
||||
|
||||
|
||||
def sort_tables(tables):
|
||||
import re
|
||||
regex = re.compile('(%s)' % '|'.join(tables))
|
||||
is_auth_user = 'auth_user' in tables
|
||||
d={}
|
||||
d = {}
|
||||
for table in tables:
|
||||
d[table]=[]
|
||||
d[table] = []
|
||||
for field in session.app['table_%s' % table]:
|
||||
d[table]+=regex.findall(field)
|
||||
tables=[]
|
||||
d[table] += regex.findall(field)
|
||||
tables = []
|
||||
if is_auth_user:
|
||||
tables.append('auth_user')
|
||||
def append(table,trail=[]):
|
||||
|
||||
def append(table, trail=[]):
|
||||
if table in trail:
|
||||
raise RuntimeError
|
||||
for t in d[table]:
|
||||
# if not t==table: (problem, no dropdown for self references)
|
||||
append(t,trail=trail+[table])
|
||||
append(t, trail=trail + [table])
|
||||
if not table in tables:
|
||||
tables.append(table)
|
||||
for table in d: append(table)
|
||||
for table in d:
|
||||
append(table)
|
||||
return tables
|
||||
|
||||
def make_table(table,fields):
|
||||
rawtable=table
|
||||
if table!='auth_user': table='t_'+table
|
||||
s=''
|
||||
s+='\n'+'#'*40+'\n'
|
||||
s+="db.define_table('%s',\n" % table
|
||||
first_field='id'
|
||||
|
||||
def make_table(table, fields):
|
||||
rawtable = table
|
||||
if table != 'auth_user':
|
||||
table = 't_' + table
|
||||
s = ''
|
||||
s += '\n' + '#' * 40 + '\n'
|
||||
s += "db.define_table('%s',\n" % table
|
||||
first_field = 'id'
|
||||
for field in fields:
|
||||
items=[x.lower() for x in field.split()]
|
||||
items = [x.lower() for x in field.split()]
|
||||
has = {}
|
||||
keys = []
|
||||
for key in ['notnull','unique','integer','double','boolean','float',
|
||||
'boolean', 'date','time','datetime','text','wiki',
|
||||
'html','file','upload','image','true',
|
||||
'hidden','readonly','writeonly','multiple',
|
||||
'notempty','required']:
|
||||
for key in ['notnull', 'unique', 'integer', 'double', 'boolean', 'float',
|
||||
'boolean', 'date', 'time', 'datetime', 'text', 'wiki',
|
||||
'html', 'file', 'upload', 'image', 'true',
|
||||
'hidden', 'readonly', 'writeonly', 'multiple',
|
||||
'notempty', 'required']:
|
||||
if key in items[1:]:
|
||||
keys.append(key)
|
||||
has[key] = True
|
||||
tables = session.app['tables']
|
||||
refs = [t for t in tables if t in items]
|
||||
items = items[:1] + [x for x in items[1:] \
|
||||
if not x in keys and not x in tables]
|
||||
items = items[:1] + [x for x in items[1:]
|
||||
if not x in keys and not x in tables]
|
||||
barename = name = '_'.join(items)
|
||||
if table[:2]=='t_': name='f_'+name
|
||||
if first_field=='id': first_field=name
|
||||
if table[:2] == 't_': name = 'f_' + name
|
||||
if first_field == 'id':
|
||||
first_field = name
|
||||
|
||||
### determine field type
|
||||
ftype='string'
|
||||
deftypes={'integer':'integer','double':'double','boolean':'boolean',
|
||||
'float':'double','bool':'boolean',
|
||||
'date':'date','time':'time','datetime':'datetime',
|
||||
'text':'text','file':'upload','image':'upload',
|
||||
'upload':'upload','wiki':'text', 'html':'text'}
|
||||
for key,t in deftypes.items():
|
||||
ftype = 'string'
|
||||
deftypes = {'integer': 'integer', 'double': 'double', 'boolean': 'boolean',
|
||||
'float': 'double', 'bool': 'boolean',
|
||||
'date': 'date', 'time': 'time', 'datetime': 'datetime',
|
||||
'text': 'text', 'file': 'upload', 'image': 'upload',
|
||||
'upload': 'upload', 'wiki': 'text', 'html': 'text'}
|
||||
for key, t in deftypes.items():
|
||||
if key in has:
|
||||
ftype = t
|
||||
if refs:
|
||||
key = refs[0]
|
||||
if not key=='auth_user': key='t_'+key
|
||||
if not key == 'auth_user':
|
||||
key = 't_' + key
|
||||
if 'multiple' in has:
|
||||
ftype='list:reference %s' % key
|
||||
ftype = 'list:reference %s' % key
|
||||
else:
|
||||
ftype='reference %s' % key
|
||||
if ftype=='string' and 'multiple' in has:
|
||||
ftype='list:string'
|
||||
elif ftype=='integer' and 'multiple' in has:
|
||||
ftype='list:integer'
|
||||
elif name=='password':
|
||||
ftype='password'
|
||||
s+=" Field('%s', type='%s'" % (name, ftype)
|
||||
ftype = 'reference %s' % key
|
||||
if ftype == 'string' and 'multiple' in has:
|
||||
ftype = 'list:string'
|
||||
elif ftype == 'integer' and 'multiple' in has:
|
||||
ftype = 'list:integer'
|
||||
elif name == 'password':
|
||||
ftype = 'password'
|
||||
s += " Field('%s', type='%s'" % (name, ftype)
|
||||
|
||||
### determine field attributes
|
||||
if 'notnull' in has or 'notempty' in has or 'required' in has:
|
||||
s+=', notnull=True'
|
||||
s += ', notnull=True'
|
||||
if 'unique' in has:
|
||||
s+=', unique=True'
|
||||
if ftype=='boolean' and 'true' in has:
|
||||
s+=",\n default=True"
|
||||
s += ', unique=True'
|
||||
if ftype == 'boolean' and 'true' in has:
|
||||
s += ",\n default=True"
|
||||
|
||||
### determine field representation
|
||||
elif 'wiki' in has:
|
||||
s+=",\n represent=lambda x, row: MARKMIN(x)"
|
||||
s+=",\n comment='WIKI (markmin)'"
|
||||
s += ",\n represent=lambda x, row: MARKMIN(x)"
|
||||
s += ",\n comment='WIKI (markmin)'"
|
||||
elif 'html' in has:
|
||||
s+=",\n represent=lambda x, row: XML(x,sanitize=True)"
|
||||
s+=",\n comment='HTML (sanitized)'"
|
||||
s += ",\n represent=lambda x, row: XML(x,sanitize=True)"
|
||||
s += ",\n comment='HTML (sanitized)'"
|
||||
### determine field access
|
||||
if name=='password' or 'writeonly' in has:
|
||||
s+=",\n readable=False"
|
||||
if name == 'password' or 'writeonly' in has:
|
||||
s += ",\n readable=False"
|
||||
elif 'hidden' in has:
|
||||
s+=",\n writable=False, readable=False"
|
||||
s += ",\n writable=False, readable=False"
|
||||
elif 'readonly' in has:
|
||||
s+=",\n writable=False"
|
||||
s += ",\n writable=False"
|
||||
|
||||
### make up a label
|
||||
s+=",\n label=T('%s')),\n" % \
|
||||
s += ",\n label=T('%s')),\n" % \
|
||||
' '.join(x.capitalize() for x in barename.split('_'))
|
||||
if table=='auth_user':
|
||||
s+=" Field('created_on','datetime',default=request.now,\n"
|
||||
s+=" label=T('Created On'),writable=False,readable=False),\n"
|
||||
s+=" Field('modified_on','datetime',default=request.now,\n"
|
||||
s+=" label=T('Modified On'),writable=False,readable=False,\n"
|
||||
s+=" update=request.now),\n"
|
||||
s+=" Field('registration_key',default='',\n"
|
||||
s+=" writable=False,readable=False),\n"
|
||||
s+=" Field('reset_password_key',default='',\n"
|
||||
s+=" writable=False,readable=False),\n"
|
||||
s+=" Field('registration_id',default='',\n"
|
||||
s+=" writable=False,readable=False),\n"
|
||||
if table == 'auth_user':
|
||||
s += " Field('created_on','datetime',default=request.now,\n"
|
||||
s += " label=T('Created On'),writable=False,readable=False),\n"
|
||||
s += " Field('modified_on','datetime',default=request.now,\n"
|
||||
s += " label=T('Modified On'),writable=False,readable=False,\n"
|
||||
s += " update=request.now),\n"
|
||||
s += " Field('registration_key',default='',\n"
|
||||
s += " writable=False,readable=False),\n"
|
||||
s += " Field('reset_password_key',default='',\n"
|
||||
s += " writable=False,readable=False),\n"
|
||||
s += " Field('registration_id',default='',\n"
|
||||
s += " writable=False,readable=False),\n"
|
||||
elif 'auth_user' in session.app['tables']:
|
||||
s+=" auth.signature,\n"
|
||||
s+=" format='%("+first_field+")s',\n"
|
||||
s+=" migrate=settings.migrate)\n\n"
|
||||
if table=='auth_user':
|
||||
s+="""
|
||||
db.auth_user.first_name.requires = IS_NOT_EMPTY(error_message=auth.messages.is_empty)
|
||||
db.auth_user.last_name.requires = IS_NOT_EMPTY(error_message=auth.messages.is_empty)
|
||||
db.auth_user.password.requires = CRYPT(key=auth.settings.hmac_key, min_length=4)
|
||||
s += " auth.signature,\n"
|
||||
s += " format='%(" + first_field + ")s',\n"
|
||||
s += " migrate=settings.migrate)\n\n"
|
||||
if table == 'auth_user':
|
||||
s += """
|
||||
db.auth_user.first_name.requires = IS_NOT_EMPTY(
|
||||
error_message=auth.messages.is_empty)
|
||||
db.auth_user.last_name.requires = IS_NOT_EMPTY(
|
||||
error_message=auth.messages.is_empty)
|
||||
db.auth_user.password.requires = CRYPT(
|
||||
key=auth.settings.hmac_key, min_length=4)
|
||||
db.auth_user.username.requires = IS_NOT_IN_DB(db, db.auth_user.username)
|
||||
db.auth_user.email.requires = (IS_EMAIL(error_message=auth.messages.invalid_email),
|
||||
db.auth_user.email.requires = (
|
||||
IS_EMAIL(error_message=auth.messages.invalid_email),
|
||||
IS_NOT_IN_DB(db, db.auth_user.email))
|
||||
"""
|
||||
else:
|
||||
s+="db.define_table('%s_archive',db.%s,Field('current_record','reference %s',readable=False,writable=False))\n" % (table,table,table)
|
||||
s += "db.define_table('%s_archive',db.%s,Field('current_record','reference %s',readable=False,writable=False))\n" % (table, table, table)
|
||||
return s
|
||||
|
||||
|
||||
def fix_db(filename):
|
||||
params = dict(session.app['params'])
|
||||
content = read_file(filename,'rb')
|
||||
content = read_file(filename, 'rb')
|
||||
if 'auth_user' in session.app['tables']:
|
||||
auth_user = make_table('auth_user',session.app['table_auth_user'])
|
||||
auth_user = make_table('auth_user', session.app['table_auth_user'])
|
||||
content = content.replace('sqlite://storage.sqlite',
|
||||
params['database_uri'])
|
||||
content = content.replace('auth.define_tables()',\
|
||||
auth_user+'auth.define_tables(migrate = settings.migrate)')
|
||||
params['database_uri'])
|
||||
content = content.replace('auth.define_tables()',
|
||||
auth_user + 'auth.define_tables(migrate = settings.migrate)')
|
||||
content += """
|
||||
mail.settings.server = settings.email_server
|
||||
mail.settings.sender = settings.email_sender
|
||||
mail.settings.login = settings.email_login
|
||||
"""
|
||||
if params['login_method']=='janrain':
|
||||
content+="""
|
||||
if params['login_method'] == 'janrain':
|
||||
content += """
|
||||
from gluon.contrib.login_methods.rpx_account import RPXAccount
|
||||
auth.settings.actions_disabled=['register','change_password','request_reset_password']
|
||||
auth.settings.actions_disabled=['register','change_password',
|
||||
'request_reset_password']
|
||||
auth.settings.login_form = RPXAccount(request,
|
||||
api_key = settings.login_config.split(':')[-1],
|
||||
domain = settings.login_config.split(':')[0],
|
||||
@@ -388,14 +424,15 @@ auth.settings.login_form = RPXAccount(request,
|
||||
"""
|
||||
write_file(filename, content, 'wb')
|
||||
|
||||
|
||||
def make_menu(pages):
|
||||
s=''
|
||||
s+='response.title = settings.title\n'
|
||||
s+='response.subtitle = settings.subtitle\n'
|
||||
s+="response.meta.author = '%(author)s <%(author_email)s>' % settings\n"
|
||||
s+='response.meta.keywords = settings.keywords\n'
|
||||
s+='response.meta.description = settings.description\n'
|
||||
s+='response.menu = [\n'
|
||||
s = ''
|
||||
s += 'response.title = settings.title\n'
|
||||
s += 'response.subtitle = settings.subtitle\n'
|
||||
s += "response.meta.author = '%(author)s <%(author_email)s>' % settings\n"
|
||||
s += 'response.meta.keywords = settings.keywords\n'
|
||||
s += 'response.meta.description = settings.description\n'
|
||||
s += 'response.menu = [\n'
|
||||
for page in pages:
|
||||
if not page.startswith('error'):
|
||||
if page.endswith('_manage'):
|
||||
@@ -403,65 +440,70 @@ def make_menu(pages):
|
||||
else:
|
||||
page_name = page
|
||||
page_name = ' '.join(x.capitalize() for x in page_name.split('_'))
|
||||
s+="(T('%s'),URL('default','%s')==URL(),URL('default','%s'),[]),\n" \
|
||||
% (page_name,page,page)
|
||||
s+=']'
|
||||
s += "(T('%s'),URL('default','%s')==URL(),URL('default','%s'),[]),\n" \
|
||||
% (page_name, page, page)
|
||||
s += ']'
|
||||
return s
|
||||
|
||||
def make_page(page,contents):
|
||||
if 'auth_user' in session.app['tables'] and not page in ('index','error'):
|
||||
s="@auth.requires_login()\ndef %s():\n" % page
|
||||
|
||||
def make_page(page, contents):
|
||||
if 'auth_user' in session.app['tables'] and not page in ('index', 'error'):
|
||||
s = "@auth.requires_login()\ndef %s():\n" % page
|
||||
else:
|
||||
s="def %s():\n" % page
|
||||
items = page.rsplit('_',1)
|
||||
if items[0] in session.app['tables'] and len(items)==2 and items[1]=='manage':
|
||||
s+=" form = SQLFORM.smartgrid(db.t_%s,onupdate=auth.archive)\n" % items[0]
|
||||
s+=" return locals()\n\n"
|
||||
s = "def %s():\n" % page
|
||||
items = page.rsplit('_', 1)
|
||||
if items[0] in session.app['tables'] and len(items) == 2 and items[1] == 'manage':
|
||||
s += " form = SQLFORM.smartgrid(db.t_%s,onupdate=auth.archive)\n" % items[0]
|
||||
s += " return locals()\n\n"
|
||||
else:
|
||||
s+=" return dict()\n\n"
|
||||
s += " return dict()\n\n"
|
||||
return s
|
||||
|
||||
def make_view(page,contents):
|
||||
s="{{extend 'layout.html'}}\n\n"
|
||||
s+=str(MARKMIN(contents))
|
||||
|
||||
def make_view(page, contents):
|
||||
s = "{{extend 'layout.html'}}\n\n"
|
||||
s += str(MARKMIN(contents))
|
||||
return s
|
||||
|
||||
|
||||
def populate(tables):
|
||||
s = 'from gluon.contrib.populate import populate\n'
|
||||
s+= 'if db(db.auth_user).isempty():\n'
|
||||
s += 'if db(db.auth_user).isempty():\n'
|
||||
for table in sort_tables(tables):
|
||||
t=table=='auth_user' and 'auth_user' or 't_'+table
|
||||
s+=" populate(db.%s,10)\n" % t
|
||||
t = table == 'auth_user' and 'auth_user' or 't_' + table
|
||||
s += " populate(db.%s,10)\n" % t
|
||||
return s
|
||||
|
||||
|
||||
def create(options):
|
||||
if DEMO_MODE:
|
||||
session.flash = T('disabled in demo mode')
|
||||
redirect(URL('step6'))
|
||||
params = dict(session.app['params'])
|
||||
app = session.app['name']
|
||||
if app_create(app,request,force=True,key=params['security_key']):
|
||||
if app_create(app, request, force=True, key=params['security_key']):
|
||||
if MULTI_USER_MODE:
|
||||
db.app.insert(name=app,owner=auth.user.id)
|
||||
db.app.insert(name=app, owner=auth.user.id)
|
||||
else:
|
||||
session.flash = 'Failure to create application'
|
||||
redirect(URL('step6'))
|
||||
|
||||
### save metadata in newapp/wizard.metadata
|
||||
try:
|
||||
meta = os.path.join(request.folder,'..',app,'wizard.metadata')
|
||||
file=open(meta,'wb')
|
||||
pickle.dump(session.app,file)
|
||||
meta = os.path.join(request.folder, '..', app, 'wizard.metadata')
|
||||
file = open(meta, 'wb')
|
||||
pickle.dump(session.app, file)
|
||||
file.close()
|
||||
except IOError:
|
||||
session.flash = 'Failure to write wizard metadata'
|
||||
redirect(URL('step6'))
|
||||
|
||||
### apply theme
|
||||
if options.apply_layout and params['layout_theme']!='Default':
|
||||
if options.apply_layout and params['layout_theme'] != 'Default':
|
||||
try:
|
||||
fn = 'web2py.plugin.layout_%s.w2p' % params['layout_theme']
|
||||
theme = urllib.urlopen(LAYOUTS_APP+'/static/plugin_layouts/plugins/'+fn)
|
||||
theme = urllib.urlopen(
|
||||
LAYOUTS_APP + '/static/plugin_layouts/plugins/' + fn)
|
||||
plugin_install(app, theme, request, fn)
|
||||
except:
|
||||
session.flash = T("unable to download layout")
|
||||
@@ -469,55 +511,58 @@ def create(options):
|
||||
### apply plugins
|
||||
for plugin in params['plugins']:
|
||||
try:
|
||||
plugin_name = 'web2py.plugin.'+plugin+'.w2p'
|
||||
stream = urllib.urlopen(PLUGINS_APP+'/static/'+plugin_name)
|
||||
plugin_name = 'web2py.plugin.' + plugin + '.w2p'
|
||||
stream = urllib.urlopen(PLUGINS_APP + '/static/' + plugin_name)
|
||||
plugin_install(app, stream, request, plugin_name)
|
||||
except Exception, e:
|
||||
session.flash = T("unable to download plugin: %s" % plugin)
|
||||
|
||||
### write configuration file into newapp/models/0.py
|
||||
model = os.path.join(request.folder,'..',app,'models','0.py')
|
||||
model = os.path.join(request.folder, '..', app, 'models', '0.py')
|
||||
file = open(model, 'wb')
|
||||
try:
|
||||
file.write("from gluon.storage import Storage\n")
|
||||
file.write("settings = Storage()\n\n")
|
||||
file.write("settings.migrate = True\n")
|
||||
for key,value in session.app['params']:
|
||||
file.write("settings.%s = %s\n" % (key,repr(value)))
|
||||
for key, value in session.app['params']:
|
||||
file.write("settings.%s = %s\n" % (key, repr(value)))
|
||||
finally:
|
||||
file.close()
|
||||
|
||||
### write configuration file into newapp/models/menu.py
|
||||
if options.generate_menu:
|
||||
model = os.path.join(request.folder,'..',app,'models','menu.py')
|
||||
file = open(model,'wb')
|
||||
model = os.path.join(request.folder, '..', app, 'models', 'menu.py')
|
||||
file = open(model, 'wb')
|
||||
try:
|
||||
file.write(make_menu(session.app['pages']))
|
||||
finally:
|
||||
file.close()
|
||||
|
||||
### customize the auth_user table
|
||||
model = os.path.join(request.folder,'..',app,'models','db.py')
|
||||
model = os.path.join(request.folder, '..', app, 'models', 'db.py')
|
||||
fix_db(model)
|
||||
|
||||
### create newapp/models/db_wizard.py
|
||||
if options.generate_model:
|
||||
model = os.path.join(request.folder,'..',app,'models','db_wizard.py')
|
||||
file = open(model,'wb')
|
||||
model = os.path.join(
|
||||
request.folder, '..', app, 'models', 'db_wizard.py')
|
||||
file = open(model, 'wb')
|
||||
try:
|
||||
file.write('### we prepend t_ to tablenames and f_ to fieldnames for disambiguity\n\n')
|
||||
tables = sort_tables(session.app['tables'])
|
||||
for table in tables:
|
||||
if table=='auth_user': continue
|
||||
file.write(make_table(table,session.app['table_'+table]))
|
||||
if table == 'auth_user':
|
||||
continue
|
||||
file.write(make_table(table, session.app['table_' + table]))
|
||||
finally:
|
||||
file.close()
|
||||
|
||||
model = os.path.join(request.folder,'..',app,
|
||||
'models','db_wizard_populate.py')
|
||||
if os.path.exists(model): os.unlink(model)
|
||||
model = os.path.join(request.folder, '..', app,
|
||||
'models', 'db_wizard_populate.py')
|
||||
if os.path.exists(model):
|
||||
os.unlink(model)
|
||||
if options.populate_database and session.app['tables']:
|
||||
file = open(model,'wb')
|
||||
file = open(model, 'wb')
|
||||
try:
|
||||
file.write(populate(session.app['tables']))
|
||||
finally:
|
||||
@@ -525,8 +570,9 @@ def create(options):
|
||||
|
||||
### create newapp/controllers/default.py
|
||||
if options.generate_controller:
|
||||
controller = os.path.join(request.folder,'..',app,'controllers','default.py')
|
||||
file = open(controller,'wb')
|
||||
controller = os.path.join(
|
||||
request.folder, '..', app, 'controllers', 'default.py')
|
||||
file = open(controller, 'wb')
|
||||
try:
|
||||
file.write("""# -*- coding: utf-8 -*-
|
||||
### required - do no delete
|
||||
@@ -536,23 +582,24 @@ def call(): return service()
|
||||
### end requires
|
||||
""")
|
||||
for page in session.app['pages']:
|
||||
file.write(make_page(page,session.app.get('page_'+page,'')))
|
||||
file.write(
|
||||
make_page(page, session.app.get('page_' + page, '')))
|
||||
finally:
|
||||
file.close()
|
||||
|
||||
### create newapp/views/default/*.html
|
||||
if options.generate_views:
|
||||
for page in session.app['pages']:
|
||||
view = os.path.join(request.folder,'..',app,'views','default',page+'.html')
|
||||
file = open(view,'wb')
|
||||
view = os.path.join(
|
||||
request.folder, '..', app, 'views', 'default', page + '.html')
|
||||
file = open(view, 'wb')
|
||||
try:
|
||||
file.write(make_view(page,session.app.get('page_'+page,'')))
|
||||
file.write(
|
||||
make_view(page, session.app.get('page_' + page, '')))
|
||||
finally:
|
||||
file.close()
|
||||
|
||||
if options.erase_database:
|
||||
path = os.path.join(request.folder,'..',app,'databases','*')
|
||||
path = os.path.join(request.folder, '..', app, 'databases', '*')
|
||||
for file in glob.glob(path):
|
||||
os.unlink(file)
|
||||
|
||||
|
||||
|
||||
@@ -19,5 +19,3 @@ for filename in os.listdir(path):
|
||||
os.unlink(fullpath)
|
||||
except:
|
||||
logging.exception('failure to check %s'%fullpath)
|
||||
|
||||
|
||||
|
||||
@@ -3,143 +3,26 @@
|
||||
'!langcode!': 'it',
|
||||
'!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 ',
|
||||
'%Y-%m-%d': '%d/%m/%Y',
|
||||
'%Y-%m-%d %H:%M:%S': '%d/%m/%Y %H:%M:%S',
|
||||
'%s %%{row} deleted': '%s righe ("record") cancellate',
|
||||
'%s %%{row} updated': '%s righe ("record") modificate',
|
||||
'%Y-%m-%d': '%d/%m/%Y',
|
||||
'%Y-%m-%d %H:%M:%S': '%d/%m/%Y %H:%M:%S',
|
||||
'(requires internet access)': '(requires internet access)',
|
||||
'(something like "it-it")': '(qualcosa simile a "it-it")',
|
||||
'@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(file **gluon/contrib/plural_rules/%s.py** is not found)',
|
||||
'@markmin\x01Searching: **%s** %%{file}': 'Searching: **%s** files',
|
||||
'A new version of web2py is available: %s': 'È disponibile una nuova versione di web2py: %s',
|
||||
'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': "ATTENZIONE: L'accesso richiede una connessione sicura (HTTPS) o l'esecuzione di web2py in locale (connessione su localhost)",
|
||||
'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATTENTZIONE: NON ESEGUIRE PIÙ TEST IN PARALLELO (I TEST NON SONO "THREAD SAFE")',
|
||||
'ATTENTION: you cannot edit the running application!': "ATTENZIONE: non puoi modificare l'applicazione correntemente in uso ",
|
||||
'About': 'informazioni',
|
||||
'About application': "Informazioni sull'applicazione",
|
||||
'Admin is disabled because insecure channel': 'amministrazione disabilitata: comunicazione non sicura',
|
||||
'Admin language': 'Admin language',
|
||||
'Administrator Password:': 'Password Amministratore:',
|
||||
'Application name:': 'Application name:',
|
||||
'Are you sure you want to delete file "%s"?': 'Confermi di voler cancellare il file "%s"?',
|
||||
'Are you sure you want to delete plugin "%s"?': 'Confermi di voler cancellare il plugin "%s"?',
|
||||
'Are you sure you want to uninstall application "%s"?': 'Confermi di voler disinstallare l\'applicazione "%s"?',
|
||||
'Are you sure you want to upgrade web2py now?': 'Confermi di voler aggiornare web2py ora?',
|
||||
'Available databases and tables': 'Database e tabelle disponibili',
|
||||
'Cannot be empty': 'Non può essere vuoto',
|
||||
'Cannot compile: there are errors in your app:': "Compilazione fallita: ci sono errori nell'applicazione.",
|
||||
'Change admin password': 'change admin password',
|
||||
'Check for upgrades': 'check for upgrades',
|
||||
'Check to delete': 'Seleziona per cancellare',
|
||||
'Checking for upgrades...': 'Controllo aggiornamenti in corso...',
|
||||
'Clean': 'pulisci',
|
||||
'Compile': 'compila',
|
||||
'Controller': 'Controller',
|
||||
'Controllers': 'Controllers',
|
||||
'Copyright': 'Copyright',
|
||||
'Create': 'crea',
|
||||
'Create new simple application': 'Crea nuova applicazione',
|
||||
'Current request': 'Richiesta (request) corrente',
|
||||
'Current response': 'Risposta (response) corrente',
|
||||
'Current session': 'Sessione (session) corrente',
|
||||
'DB Model': 'Modello di DB',
|
||||
'Database': 'Database',
|
||||
'Date and Time': 'Data and Ora',
|
||||
'Delete': 'Cancella',
|
||||
'Delete:': 'Cancella:',
|
||||
'Deploy': 'deploy',
|
||||
'Deploy on Google App Engine': 'Installa su Google App Engine',
|
||||
'EDIT': 'MODIFICA',
|
||||
'Edit': 'modifica',
|
||||
'Edit This App': 'Modifica questa applicazione',
|
||||
'Edit application': 'Modifica applicazione',
|
||||
'Edit current record': 'Modifica record corrente',
|
||||
'Editing Language file': 'Modifica file linguaggio',
|
||||
'Editing file "%s"': 'Modifica del file "%s"',
|
||||
'Enterprise Web Framework': 'Enterprise Web Framework',
|
||||
'Error logs for "%(app)s"': 'Log degli errori per "%(app)s"',
|
||||
'Errors': 'errori',
|
||||
'Exception instance attributes': 'Exception instance attributes',
|
||||
'Functions with no doctests will result in [passed] tests.': 'I test delle funzioni senza "doctests" risulteranno sempre [passed].',
|
||||
'Hello World': 'Salve Mondo',
|
||||
'Help': 'aiuto',
|
||||
'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.',
|
||||
'Import/Export': 'Importa/Esporta',
|
||||
'Index': 'Indice',
|
||||
'Install': 'installa',
|
||||
'Installed applications': 'Applicazioni installate',
|
||||
'Internal State': 'Stato interno',
|
||||
'Invalid Query': 'Richiesta (query) non valida',
|
||||
'Invalid action': 'Azione non valida',
|
||||
'Language files (static strings) updated': 'Linguaggi (documenti con stringhe statiche) aggiornati',
|
||||
'Languages': 'Linguaggi',
|
||||
'Last saved on:': 'Ultimo salvataggio:',
|
||||
'Layout': 'Layout',
|
||||
'License for': 'Licenza relativa a',
|
||||
'Login': 'Accesso',
|
||||
'Login to the Administrative Interface': "Accesso all'interfaccia amministrativa",
|
||||
'Logout': 'uscita',
|
||||
'Main Menu': 'Menu principale',
|
||||
'Menu Model': 'Menu Modelli',
|
||||
'Models': 'Modelli',
|
||||
'Modules': 'Moduli',
|
||||
'NO': 'NO',
|
||||
'New Record': 'Nuovo elemento (record)',
|
||||
'New application wizard': 'New application wizard',
|
||||
'New simple application': 'New simple application',
|
||||
'No databases in this application': 'Nessun database presente in questa applicazione',
|
||||
'Original/Translation': 'Originale/Traduzione',
|
||||
'Overwrite installed app': 'sovrascrivi applicazione installata',
|
||||
'PAM authenticated user, cannot change password here': 'utente autenticato tramite PAM, impossibile modificare password qui',
|
||||
'Pack all': 'crea pacchetto',
|
||||
'Pack compiled': 'crea pacchetto del codice compilato',
|
||||
'Peeking at file': 'Uno sguardo al file',
|
||||
'Plugin "%s" in application': 'Plugin "%s" nell\'applicazione',
|
||||
'Plugins': 'I Plugins',
|
||||
'Powered by': 'Powered by',
|
||||
'Query:': 'Richiesta (query):',
|
||||
'Remove compiled': 'rimozione codice compilato',
|
||||
'Resolve Conflict file': 'File di risoluzione conflitto',
|
||||
'Rows in table': 'Righe nella tabella',
|
||||
'Rows selected': 'Righe selezionate',
|
||||
'Saved file hash:': 'Hash del file salvato:',
|
||||
'Site': 'sito',
|
||||
'Start wizard': 'start wizard',
|
||||
'Static files': 'Files statici',
|
||||
'Stylesheet': 'Foglio di stile (stylesheet)',
|
||||
'Sure you want to delete this object?': 'Vuoi veramente cancellare questo oggetto?',
|
||||
'TM': 'TM',
|
||||
'Testing application': 'Test applicazione in corsg',
|
||||
'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'La richiesta (query) è una condizione come ad esempio "db.tabella1.campo1==\'valore\'". Una condizione come "db.tabella1.campo1==db.tabella2.campo2" produce un "JOIN" SQL.',
|
||||
'There are no controllers': 'Non ci sono controller',
|
||||
'There are no models': 'Non ci sono modelli',
|
||||
'There are no modules': 'Non ci sono moduli',
|
||||
'There are no static files': 'Non ci sono file statici',
|
||||
'There are no translators, only default language is supported': 'Non ci sono traduzioni, viene solo supportato il linguaggio di base',
|
||||
'There are no views': 'Non ci sono viste ("view")',
|
||||
'This is the %(filename)s template': 'Questo è il template %(filename)s',
|
||||
'Ticket': 'Ticket',
|
||||
'To create a plugin, name a file/folder plugin_[name]': 'Per creare un plugin, chiamare un file o cartella plugin_[nome]',
|
||||
'Unable to check for upgrades': 'Impossibile controllare presenza di aggiornamenti',
|
||||
'Unable to download app because:': 'Impossibile scaricare applicazione perché',
|
||||
'Unable to download because': 'Impossibile scaricare perché',
|
||||
'Unable to download because:': 'Unable to download because:',
|
||||
'Uninstall': 'disinstalla',
|
||||
'Update:': 'Aggiorna:',
|
||||
'Upload & install packed application': 'Carica ed installa pacchetto con applicazione',
|
||||
'Upload a package:': 'Upload a package:',
|
||||
'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 an url:': 'Use an url:',
|
||||
'Version': 'Versione',
|
||||
'View': 'Vista',
|
||||
'Views': 'viste',
|
||||
'Welcome %s': 'Benvenuto %s',
|
||||
'Welcome to web2py': 'Benvenuto su web2py',
|
||||
'YES': 'SI',
|
||||
'additional code for your application': 'righe di codice aggiuntive per la tua applicazione',
|
||||
'Additional code for your application': 'Additional code for your application',
|
||||
'admin disabled because no admin password': 'amministrazione disabilitata per mancanza di password amministrativa',
|
||||
'admin disabled because not supported on google app engine': 'amministrazione non supportata da Google Apps Engine',
|
||||
'admin disabled because unable to access password file': 'amministrazione disabilitata per impossibilità di leggere il file delle password',
|
||||
'Admin is disabled because insecure channel': 'amministrazione disabilitata: comunicazione non sicura',
|
||||
'Admin language': 'Admin language',
|
||||
'administrative interface': 'administrative interface',
|
||||
'Administrator Password:': 'Password Amministratore:',
|
||||
'and rename it (required):': 'e rinominala (obbligatorio):',
|
||||
'and rename it:': 'e rinominala:',
|
||||
'appadmin': 'appadmin ',
|
||||
@@ -147,44 +30,104 @@
|
||||
'application "%s" uninstalled': 'applicazione "%s" disinstallata',
|
||||
'application compiled': 'applicazione compilata',
|
||||
'application is compiled and cannot be designed': "l'applicazione è compilata e non si può modificare",
|
||||
'Application name:': 'Application name:',
|
||||
'are not used': 'are not used',
|
||||
'are not used yet': 'are not used yet',
|
||||
'Are you sure you want to delete file "%s"?': 'Confermi di voler cancellare il file "%s"?',
|
||||
'Are you sure you want to delete plugin "%s"?': 'Confermi di voler cancellare il plugin "%s"?',
|
||||
'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?',
|
||||
'Are you sure you want to uninstall application "%s"?': 'Confermi di voler disinstallare l\'applicazione "%s"?',
|
||||
'Are you sure you want to upgrade web2py now?': 'Confermi di voler aggiornare web2py ora?',
|
||||
'arguments': 'arguments',
|
||||
'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': "ATTENZIONE: L'accesso richiede una connessione sicura (HTTPS) o l'esecuzione di web2py in locale (connessione su localhost)",
|
||||
'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATTENTZIONE: NON ESEGUIRE PIÙ TEST IN PARALLELO (I TEST NON SONO "THREAD SAFE")',
|
||||
'ATTENTION: you cannot edit the running application!': "ATTENZIONE: non puoi modificare l'applicazione correntemente in uso ",
|
||||
'Available databases and tables': 'Database e tabelle disponibili',
|
||||
'back': 'indietro',
|
||||
'cache': 'cache',
|
||||
'cache, errors and sessions cleaned': 'pulitura cache, errori and sessioni ',
|
||||
'can be a git repo': 'can be a git repo',
|
||||
'Cannot be empty': 'Non può essere vuoto',
|
||||
'Cannot compile: there are errors in your app:': "Compilazione fallita: ci sono errori nell'applicazione.",
|
||||
'cannot create file': 'impossibile creare il file',
|
||||
'cannot upload file "%(filename)s"': 'impossibile caricare il file "%(filename)s"',
|
||||
'Change admin password': 'change admin password',
|
||||
'change password': 'cambia password',
|
||||
'check all': 'controlla tutto',
|
||||
'Check for upgrades': 'check for upgrades',
|
||||
'Check to delete': 'Seleziona per cancellare',
|
||||
'Checking for upgrades...': 'Controllo aggiornamenti in corso...',
|
||||
'Clean': 'pulisci',
|
||||
'click here for online examples': 'clicca per vedere gli esempi',
|
||||
'click here for the administrative interface': "clicca per l'interfaccia amministrativa",
|
||||
'click to check for upgrades': 'clicca per controllare presenza di aggiornamenti',
|
||||
'code': 'code',
|
||||
'collapse/expand all': 'collapse/expand all',
|
||||
'Compile': 'compila',
|
||||
'compiled application removed': "rimosso il codice compilato dell'applicazione",
|
||||
'Controller': 'Controller',
|
||||
'Controllers': 'Controllers',
|
||||
'controllers': 'controllers',
|
||||
'Copyright': 'Copyright',
|
||||
'Create': 'crea',
|
||||
'create file with filename:': 'crea un file col nome:',
|
||||
'create new application:': 'create new application:',
|
||||
'Create new simple application': 'Crea nuova applicazione',
|
||||
'created by': 'creato da',
|
||||
'crontab': 'crontab',
|
||||
'Current request': 'Richiesta (request) corrente',
|
||||
'Current response': 'Risposta (response) corrente',
|
||||
'Current session': 'Sessione (session) corrente',
|
||||
'currently running': 'currently running',
|
||||
'currently saved or': 'attualmente salvato o',
|
||||
'customize me!': 'Personalizzami!',
|
||||
'data uploaded': 'dati caricati',
|
||||
'Database': 'Database',
|
||||
'database': 'database',
|
||||
'database %s select': 'database %s select',
|
||||
'database administration': 'amministrazione database',
|
||||
'Date and Time': 'Data and Ora',
|
||||
'db': 'db',
|
||||
'DB Model': 'Modello di DB',
|
||||
'Debug': 'Debug',
|
||||
'defines tables': 'defininisce le tabelle',
|
||||
'Delete': 'Cancella',
|
||||
'delete': 'Cancella',
|
||||
'delete all checked': 'cancella tutti i selezionati',
|
||||
'delete plugin': 'cancella plugin',
|
||||
'Delete this file (you will be asked to confirm deletion)': 'Delete this file (you will be asked to confirm deletion)',
|
||||
'Delete:': 'Cancella:',
|
||||
'Deploy': 'deploy',
|
||||
'Deploy on Google App Engine': 'Installa su Google App Engine',
|
||||
'Deploy to OpenShift': 'Deploy to OpenShift',
|
||||
'design': 'progetta',
|
||||
'Detailed traceback description': 'Detailed traceback description',
|
||||
'direction: ltr': 'direction: ltr',
|
||||
'Disable': 'Disable',
|
||||
'docs': 'docs',
|
||||
'done!': 'fatto!',
|
||||
'download layouts': 'download layouts',
|
||||
'download plugins': 'download plugins',
|
||||
'EDIT': 'MODIFICA',
|
||||
'Edit': 'modifica',
|
||||
'Edit application': 'Modifica applicazione',
|
||||
'edit controller': 'modifica controller',
|
||||
'Edit current record': 'Modifica record corrente',
|
||||
'edit profile': 'modifica profilo',
|
||||
'Edit This App': 'Modifica questa applicazione',
|
||||
'edit views:': 'modifica viste (view):',
|
||||
'Editing file "%s"': 'Modifica del file "%s"',
|
||||
'Editing Language file': 'Modifica file linguaggio',
|
||||
'Enterprise Web Framework': 'Enterprise Web Framework',
|
||||
'Error logs for "%(app)s"': 'Log degli errori per "%(app)s"',
|
||||
'Error snapshot': 'Error snapshot',
|
||||
'Error ticket': 'Error ticket',
|
||||
'Errors': 'errori',
|
||||
'Exception instance attributes': 'Exception instance attributes',
|
||||
'Expand Abbreviation': 'Expand Abbreviation',
|
||||
'export as csv file': 'esporta come file CSV',
|
||||
'exposes': 'espone',
|
||||
'exposes:': 'exposes:',
|
||||
'extends': 'estende',
|
||||
'failed to reload module because:': 'ricaricamento modulo fallito perché:',
|
||||
'file "%(filename)s" created': 'creato il file "%(filename)s"',
|
||||
@@ -195,73 +138,188 @@
|
||||
'file does not exist': 'file inesistente',
|
||||
'file saved on %(time)s': "file salvato nell'istante %(time)s",
|
||||
'file saved on %s': 'file salvato: %s',
|
||||
'filter': 'filter',
|
||||
'Frames': 'Frames',
|
||||
'Functions with no doctests will result in [passed] tests.': 'I test delle funzioni senza "doctests" risulteranno sempre [passed].',
|
||||
'Get from URL:': 'Get from URL:',
|
||||
'Git Pull': 'Git Pull',
|
||||
'Git Push': 'Git Push',
|
||||
'Hello World': 'Salve Mondo',
|
||||
'Help': 'aiuto',
|
||||
'htmledit': 'modifica come html',
|
||||
'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.',
|
||||
'Import/Export': 'Importa/Esporta',
|
||||
'includes': 'include',
|
||||
'Index': 'Indice',
|
||||
'insert new': 'inserisci nuovo',
|
||||
'insert new %s': 'inserisci nuovo %s',
|
||||
'inspect attributes': 'inspect attributes',
|
||||
'Install': 'installa',
|
||||
'Installed applications': 'Applicazioni installate',
|
||||
'internal error': 'errore interno',
|
||||
'Internal State': 'Stato interno',
|
||||
'Invalid action': 'Azione non valida',
|
||||
'invalid password': 'password non valida',
|
||||
'Invalid Query': 'Richiesta (query) non valida',
|
||||
'invalid request': 'richiesta non valida',
|
||||
'invalid ticket': 'ticket non valido',
|
||||
'Key bindings': 'Key bindings',
|
||||
'Key bindings for ZenCoding Plugin': 'Key bindings for ZenCoding Plugin',
|
||||
'language file "%(filename)s" created/updated': 'file linguaggio "%(filename)s" creato/aggiornato',
|
||||
'Language files (static strings) updated': 'Linguaggi (documenti con stringhe statiche) aggiornati',
|
||||
'languages': 'linguaggi',
|
||||
'Languages': 'Linguaggi',
|
||||
'Last saved on:': 'Ultimo salvataggio:',
|
||||
'Layout': 'Layout',
|
||||
'License for': 'Licenza relativa a',
|
||||
'loading...': 'caricamento...',
|
||||
'locals': 'locals',
|
||||
'login': 'accesso',
|
||||
'Login': 'Accesso',
|
||||
'Login to the Administrative Interface': "Accesso all'interfaccia amministrativa",
|
||||
'Logout': 'uscita',
|
||||
'Main Menu': 'Menu principale',
|
||||
'Menu Model': 'Menu Modelli',
|
||||
'merge': 'unisci',
|
||||
'models': 'modelli',
|
||||
'Models': 'Modelli',
|
||||
'Modules': 'Moduli',
|
||||
'modules': 'moduli',
|
||||
'new application "%s" created': 'creata la nuova applicazione "%s"',
|
||||
'New application wizard': 'New application wizard',
|
||||
'new plugin installed': 'installato nuovo plugin',
|
||||
'New Record': 'Nuovo elemento (record)',
|
||||
'new record inserted': 'nuovo record inserito',
|
||||
'New simple application': 'New simple application',
|
||||
'next 100 rows': 'prossime 100 righe',
|
||||
'NO': 'NO',
|
||||
'No databases in this application': 'Nessun database presente in questa applicazione',
|
||||
'no match': 'nessuna corrispondenza',
|
||||
'or import from csv file': 'oppure importa da file CSV',
|
||||
'or provide app url:': "oppure fornisci url dell'applicazione:",
|
||||
'Original/Translation': 'Originale/Traduzione',
|
||||
'Overwrite installed app': 'sovrascrivi applicazione installata',
|
||||
'Pack all': 'crea pacchetto',
|
||||
'Pack compiled': 'crea pacchetto del codice compilato',
|
||||
'pack plugin': 'crea pacchetto del plugin',
|
||||
'PAM authenticated user, cannot change password here': 'utente autenticato tramite PAM, impossibile modificare password qui',
|
||||
'password changed': 'password modificata',
|
||||
'Peeking at file': 'Uno sguardo al file',
|
||||
'plugin "%(plugin)s" deleted': 'plugin "%(plugin)s" cancellato',
|
||||
'Plugin "%s" in application': 'Plugin "%s" nell\'applicazione',
|
||||
'plugins': 'plugins',
|
||||
'Plugins': 'I Plugins',
|
||||
'Plural-Forms:': 'Plural-Forms:',
|
||||
'Powered by': 'Powered by',
|
||||
'previous 100 rows': '100 righe precedenti',
|
||||
'private files': 'private files',
|
||||
'Private files': 'Private files',
|
||||
'Query:': 'Richiesta (query):',
|
||||
'record': 'record',
|
||||
'record does not exist': 'il record non esiste',
|
||||
'record id': 'ID del record',
|
||||
'register': 'registrazione',
|
||||
'Remove compiled': 'rimozione codice compilato',
|
||||
'request': 'request',
|
||||
'Resolve Conflict file': 'File di risoluzione conflitto',
|
||||
'response': 'response',
|
||||
'restore': 'ripristino',
|
||||
'revert': 'versione precedente',
|
||||
'Rows in table': 'Righe nella tabella',
|
||||
'Rows selected': 'Righe selezionate',
|
||||
'rules are not defined': 'rules are not defined',
|
||||
"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Run tests in this file (to run all files, you may also use the button labelled 'test')",
|
||||
'Running on %s': 'Running on %s',
|
||||
'Save': 'Save',
|
||||
'Save via Ajax': 'Save via Ajax',
|
||||
'Saved file hash:': 'Hash del file salvato:',
|
||||
'selected': 'selezionato',
|
||||
'session': 'session',
|
||||
'session expired': 'sessions scaduta',
|
||||
'shell': 'shell',
|
||||
'Site': 'sito',
|
||||
'some files could not be removed': 'non è stato possibile rimuovere alcuni files',
|
||||
'Start wizard': 'start wizard',
|
||||
'state': 'stato',
|
||||
'static': 'statico',
|
||||
'Static files': 'Files statici',
|
||||
'Stylesheet': 'Foglio di stile (stylesheet)',
|
||||
'submit': 'invia',
|
||||
'Submit': 'Submit',
|
||||
'Sure you want to delete this object?': 'Vuoi veramente cancellare questo oggetto?',
|
||||
'table': 'tabella',
|
||||
'test': 'test',
|
||||
'Testing application': 'Test applicazione in corsg',
|
||||
'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'La richiesta (query) è una condizione come ad esempio "db.tabella1.campo1==\'valore\'". Una condizione come "db.tabella1.campo1==db.tabella2.campo2" produce un "JOIN" SQL.',
|
||||
'The application logic, each URL path is mapped in one exposed function in the controller': 'The application logic, each URL path is mapped in one exposed function in the controller',
|
||||
'the application logic, each URL path is mapped in one exposed function in the controller': 'logica dell\'applicazione, ogni percorso "URL" corrisponde ad una funzione esposta da un controller',
|
||||
'The data representation, define database tables and sets': 'The data representation, define database tables and sets',
|
||||
'the data representation, define database tables and sets': 'rappresentazione dei dati, definizione di tabelle di database e di "set" ',
|
||||
'The presentations layer, views are also known as templates': 'The presentations layer, views are also known as templates',
|
||||
'the presentations layer, views are also known as templates': 'Presentazione dell\'applicazione, viste (views, chiamate anche "templates")',
|
||||
'There are no controllers': 'Non ci sono controller',
|
||||
'There are no models': 'Non ci sono modelli',
|
||||
'There are no modules': 'Non ci sono moduli',
|
||||
'There are no plugins': 'There are no plugins',
|
||||
'There are no static files': 'Non ci sono file statici',
|
||||
'There are no translators, only default language is supported': 'Non ci sono traduzioni, viene solo supportato il linguaggio di base',
|
||||
'There are no views': 'Non ci sono viste ("view")',
|
||||
'These files are not served, they are only available from within your app': 'These files are not served, they are only available from within your app',
|
||||
'these files are served without processing, your images go here': 'questi files vengono serviti così come sono, le immagini vanno qui',
|
||||
'These files are served without processing, your images go here': 'These files are served without processing, your images go here',
|
||||
'This is the %(filename)s template': 'Questo è il template %(filename)s',
|
||||
'Ticket': 'Ticket',
|
||||
'Ticket ID': 'Ticket ID',
|
||||
'TM': 'TM',
|
||||
'to previous version.': 'torna a versione precedente',
|
||||
'To create a plugin, name a file/folder plugin_[name]': 'Per creare un plugin, chiamare un file o cartella plugin_[nome]',
|
||||
'toggle breakpoint': 'toggle breakpoint',
|
||||
'Toggle Fullscreen': 'Toggle Fullscreen',
|
||||
'Traceback': 'Traceback',
|
||||
'translation strings for the application': "stringhe di traduzioni per l'applicazione",
|
||||
'Translation strings for the application': 'Translation strings for the application',
|
||||
'try': 'prova',
|
||||
'try something like': 'prova qualcosa come',
|
||||
'try view': 'try view',
|
||||
'Unable to check for upgrades': 'Impossibile controllare presenza di aggiornamenti',
|
||||
'unable to create application "%s"': 'impossibile creare applicazione "%s"',
|
||||
'unable to delete file "%(filename)s"': 'impossibile rimuovere file "%(plugin)s"',
|
||||
'unable to delete file plugin "%(plugin)s"': 'impossibile rimuovere file di plugin "%(plugin)s"',
|
||||
'Unable to download app because:': 'Impossibile scaricare applicazione perché',
|
||||
'Unable to download because': 'Impossibile scaricare perché',
|
||||
'Unable to download because:': 'Unable to download because:',
|
||||
'unable to parse csv file': 'non riesco a decodificare questo file CSV',
|
||||
'unable to uninstall "%s"': 'impossibile disinstallare "%s"',
|
||||
'unable to upgrade because "%s"': 'impossibile aggiornare perché "%s"',
|
||||
'uncheck all': 'smarca tutti',
|
||||
'Uninstall': 'disinstalla',
|
||||
'update': 'aggiorna',
|
||||
'update all languages': 'aggiorna tutti i linguaggi',
|
||||
'Update:': 'Aggiorna:',
|
||||
'upgrade web2py now': 'upgrade web2py now',
|
||||
'upload': 'upload',
|
||||
'Upload & install packed application': 'Carica ed installa pacchetto con applicazione',
|
||||
'Upload a package:': 'Upload a package:',
|
||||
'Upload and install packed application': 'Upload and install packed application',
|
||||
'upload application:': 'carica applicazione:',
|
||||
'upload file:': 'carica file:',
|
||||
'upload plugin file:': 'carica file di plugin:',
|
||||
'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 an url:': 'Use an url:',
|
||||
'variables': 'variables',
|
||||
'Version': 'Versione',
|
||||
'Version %s.%s.%s (%s) %s': 'Version %s.%s.%s (%s) %s',
|
||||
'versioning': 'sistema di versioni',
|
||||
'Versioning': 'Versioning',
|
||||
'view': 'vista',
|
||||
'View': 'Vista',
|
||||
'Views': 'viste',
|
||||
'views': 'viste',
|
||||
'web2py Recent Tweets': 'Tweets recenti per web2py',
|
||||
'Web Framework': 'Web Framework',
|
||||
'web2py is up to date': 'web2py è aggiornato',
|
||||
'web2py Recent Tweets': 'Tweets recenti per web2py',
|
||||
'web2py upgraded; please restart it': 'web2py aggiornato; prego riavviarlo',
|
||||
'Welcome %s': 'Benvenuto %s',
|
||||
'Welcome to web2py': 'Benvenuto su web2py',
|
||||
'YES': 'SI',
|
||||
}
|
||||
|
||||
@@ -34,10 +34,12 @@
|
||||
'App does not exist or your are not authorized': 'Додаток не існує, або ви не авторизовані',
|
||||
'appadmin': 'Aдм.панель',
|
||||
'appadmin is disabled because insecure channel': "адмін.панель відключено через використання ненадійного каналу зв'язку",
|
||||
'Application': 'Додаток (Application)',
|
||||
'application "%s" uninstalled': 'додаток "%s" вилучено',
|
||||
'application %(appname)s installed with md5sum: %(digest)s': 'додаток %(appname)s встановлено з md5sum: %(digest)s',
|
||||
'Application cannot be generated in demo mode': 'В демо-режимі генерувати додатки не можна',
|
||||
'application compiled': 'додаток скомпільовано',
|
||||
'Application exists already': 'Додаток вже існує',
|
||||
'application is compiled and cannot be designed': 'додаток скомпільований. налаштування змінювати не можна',
|
||||
'Application name:': 'Назва додатку:',
|
||||
'are not used': 'не використовуються',
|
||||
@@ -160,6 +162,7 @@
|
||||
'Error snapshot': 'Розгорнутий знімок стану (Error snapshot)',
|
||||
'Error ticket': 'Позначка (ticket) про помилку',
|
||||
'Errors': 'Помилки',
|
||||
'Errors in form, please check it out.': 'Помилка у формі, будь-ласка перевірте її.',
|
||||
'Exception %(extype)s: %(exvalue)s': 'Виключення %(extype)s: %(exvalue)s',
|
||||
'Exception %s': 'Виключення %s',
|
||||
'Exception instance attributes': 'Атрибути примірника класу Exception (виключення)',
|
||||
@@ -388,6 +391,7 @@
|
||||
'There are no models': 'Моделей, наразі, нема',
|
||||
'There are no modules': 'Модулів поки що нема',
|
||||
'There are no plugins': 'Жодної втулки, наразі, не встановлено',
|
||||
'There are no private files': 'Приватних файлів поки що нема',
|
||||
'There are no static files': 'Статичних файлів, наразі, нема',
|
||||
'There are no translators': 'Перекладів нема',
|
||||
'There are no translators, only default language is supported': 'Перекладів нема, підтримується тільки мова оригіналу',
|
||||
@@ -418,6 +422,7 @@
|
||||
'Traceback': 'Стек викликів (Traceback)',
|
||||
'Translation strings for the application': 'Пари рядків <оригінал>:<переклад> для вибраної мови',
|
||||
'try something like': 'спробуйте щось схоже на',
|
||||
'Try the mobile interface': 'Спробуйте мобільний інтерфейс',
|
||||
'try view': 'дивитись результат',
|
||||
'Type PDB debugger command in here and hit Return (Enter) to execute it.': 'наберіть тут будь-які команди ладнача PDB і натисніть клавішу [Return] ([Enter]), щоб запустити їх на виконання.',
|
||||
'Type python statement in here and hit Return (Enter) to execute it.': 'Наберіть тут будь-які вирази Python і натисніть клавішу [Return] ([Enter]), щоб запустити їх на виконання.',
|
||||
@@ -463,7 +468,7 @@
|
||||
'Views': 'Відображення (Views)',
|
||||
'views': 'відображення',
|
||||
'WARNING:': 'ПОПЕРЕДЖЕННЯ:',
|
||||
'Web Framework': 'Web Framework',
|
||||
'Web Framework': 'Веб-каркас (Web Framework)',
|
||||
'web2py apps to deploy': 'Готові до розгортання додатки web2py',
|
||||
'web2py Debugger': 'Ладнач web2py',
|
||||
'web2py downgrade': 'повернення на попередню версію web2py',
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
EXPIRATION = 60 * 60 # logout after 60 minutes of inactivity
|
||||
CHECK_VERSION = True
|
||||
WEB2PY_URL = 'http://web2py.com'
|
||||
WEB2PY_VERSION_URL = WEB2PY_URL+'/examples/default/version'
|
||||
WEB2PY_VERSION_URL = WEB2PY_URL + '/examples/default/version'
|
||||
|
||||
###########################################################################
|
||||
# Preferences for EditArea
|
||||
@@ -13,15 +13,15 @@ TEXT_EDITOR = 'codemirror' or 'ace' or 'edit_area' or 'amy'
|
||||
|
||||
## Editor Color scheme (only for ace)
|
||||
TEXT_EDITOR_THEME = (
|
||||
"chrome", "clouds", "clouds_midnight", "cobalt", "crimson_editor", "dawn",
|
||||
"chrome", "clouds", "clouds_midnight", "cobalt", "crimson_editor", "dawn",
|
||||
"dreamweaver", "eclipse", "idle_fingers", "kr_theme", "merbivore",
|
||||
"merbivore_soft", "monokai", "mono_industrial", "pastel_on_dark",
|
||||
"merbivore_soft", "monokai", "mono_industrial", "pastel_on_dark",
|
||||
"solarized_dark", "solarized_light", "textmate", "tomorrow",
|
||||
"tomorrow_night", "tomorrow_night_blue", "tomorrow_night_bright",
|
||||
"tomorrow_night_eighties", "twilight", "vibrant_ink")[0]
|
||||
|
||||
## Editor Keyboard bindings (only for ace and codemirror)
|
||||
TEXT_EDITOR_KEYBINDING = '' # 'emacs' or 'vi'
|
||||
TEXT_EDITOR_KEYBINDING = '' # 'emacs' or 'vi'
|
||||
|
||||
### edit_area only
|
||||
# The default font size, measured in 'points'. The value must be an integer > 0
|
||||
@@ -59,9 +59,9 @@ GAE_APPCFG = os.path.abspath(os.path.join('/usr/local/bin/appcfg.py'))
|
||||
|
||||
# To use web2py as a teaching tool, set MULTI_USER_MODE to True
|
||||
MULTI_USER_MODE = False
|
||||
EMAIL_SERVER = 'localhost'
|
||||
EMAIL_SENDER = 'professor@example.com'
|
||||
EMAIL_LOGIN = None
|
||||
EMAIL_SERVER = 'localhost'
|
||||
EMAIL_SENDER = 'professor@example.com'
|
||||
EMAIL_LOGIN = None
|
||||
|
||||
# configurable twitterbox, set to None/False to suppress
|
||||
TWITTER_HASH = "web2py"
|
||||
@@ -78,5 +78,3 @@ PLUGINS_APP = 'http://web2py.com/plugins'
|
||||
# set the language
|
||||
if 'adminLanguage' in request.cookies and not (request.cookies['adminLanguage'] is None):
|
||||
T.force(request.cookies['adminLanguage'].value)
|
||||
|
||||
|
||||
|
||||
@@ -28,5 +28,3 @@ from gluon.languages import findT, update_all_languages
|
||||
from gluon.myregex import *
|
||||
from gluon.restricted import *
|
||||
from gluon.compileapp import compile_application, remove_compiled_application
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import base64, os, time
|
||||
import base64
|
||||
import os
|
||||
import time
|
||||
from gluon import portalocker
|
||||
from gluon.admin import apath
|
||||
from gluon.fileutils import read_file
|
||||
@@ -24,7 +26,8 @@ elif not request.is_local and not DEMO_MODE:
|
||||
try:
|
||||
_config = {}
|
||||
port = int(request.env.server_port or 0)
|
||||
restricted(read_file(apath('../parameters_%i.py' % port, request)), _config)
|
||||
restricted(
|
||||
read_file(apath('../parameters_%i.py' % port, request)), _config)
|
||||
|
||||
if not 'password' in _config or not _config['password']:
|
||||
raise HTTP(200, T('admin disabled because no admin password'))
|
||||
@@ -38,7 +41,8 @@ except IOError:
|
||||
raise HTTP(200,
|
||||
T('admin disabled because not supported on google app engine'))
|
||||
else:
|
||||
raise HTTP(200, T('admin disabled because unable to access password file'))
|
||||
raise HTTP(
|
||||
200, T('admin disabled because unable to access password file'))
|
||||
|
||||
|
||||
def verify_password(password):
|
||||
@@ -50,7 +54,7 @@ def verify_password(password):
|
||||
elif _config['password'].startswith('pam_user:'):
|
||||
session.pam_user = _config['password'][9:].strip()
|
||||
import gluon.contrib.pam
|
||||
return gluon.contrib.pam.authenticate(session.pam_user,password)
|
||||
return gluon.contrib.pam.authenticate(session.pam_user, password)
|
||||
else:
|
||||
return _config['password'] == CRYPT()(password)[0]
|
||||
|
||||
@@ -63,6 +67,7 @@ deny_file = os.path.join(request.folder, 'private', 'hosts.deny')
|
||||
allowed_number_of_attempts = 5
|
||||
expiration_failed_logins = 3600
|
||||
|
||||
|
||||
def read_hosts_deny():
|
||||
import datetime
|
||||
hosts = {}
|
||||
@@ -75,7 +80,7 @@ def read_hosts_deny():
|
||||
continue
|
||||
fields = line.strip().split()
|
||||
if len(fields) > 2:
|
||||
hosts[fields[0].strip()] = ( # ip
|
||||
hosts[fields[0].strip()] = ( # ip
|
||||
int(fields[1].strip()), # n attemps
|
||||
int(fields[2].strip()) # last attempts
|
||||
)
|
||||
@@ -83,28 +88,30 @@ def read_hosts_deny():
|
||||
f.close()
|
||||
return hosts
|
||||
|
||||
|
||||
def write_hosts_deny(denied_hosts):
|
||||
f = open(deny_file, 'w')
|
||||
portalocker.lock(f, portalocker.LOCK_EX)
|
||||
for key, val in denied_hosts.items():
|
||||
if time.time()-val[1] < expiration_failed_logins:
|
||||
if time.time() - val[1] < expiration_failed_logins:
|
||||
line = '%s %s %s\n' % (key, val[0], val[1])
|
||||
f.write(line)
|
||||
portalocker.unlock(f)
|
||||
f.close()
|
||||
|
||||
|
||||
def login_record(success=True):
|
||||
denied_hosts = read_hosts_deny()
|
||||
val = (0,0)
|
||||
val = (0, 0)
|
||||
if success and request.client in denied_hosts:
|
||||
del denied_hosts[request.client]
|
||||
elif not success and not request.is_local:
|
||||
val = denied_hosts.get(request.client,(0,0))
|
||||
if time.time()-val[1]<expiration_failed_logins \
|
||||
val = denied_hosts.get(request.client, (0, 0))
|
||||
if time.time() - val[1] < expiration_failed_logins \
|
||||
and val[0] >= allowed_number_of_attempts:
|
||||
return val[0] # locked out
|
||||
time.sleep(2**val[0])
|
||||
val = (val[0]+1,int(time.time()))
|
||||
return val[0] # locked out
|
||||
time.sleep(2 ** val[0])
|
||||
val = (val[0] + 1, int(time.time()))
|
||||
denied_hosts[request.client] = val
|
||||
write_hosts_deny(denied_hosts)
|
||||
return val[0]
|
||||
@@ -123,17 +130,32 @@ if session.authorized:
|
||||
else:
|
||||
session.last_time = t0
|
||||
|
||||
|
||||
if request.vars.is_mobile in ('true', 'false', 'auto'):
|
||||
session.is_mobile = request.vars.is_mobile or 'auto'
|
||||
if request.controller == 'default' and request.function == 'index':
|
||||
if not request.vars.is_mobile:
|
||||
session.is_mobile = 'auto'
|
||||
if not session.is_mobile:
|
||||
session.is_mobile = 'auto'
|
||||
if session.is_mobile == 'true':
|
||||
is_mobile = True
|
||||
elif session.is_mobile == 'false':
|
||||
is_mobile = False
|
||||
else:
|
||||
is_mobile = request.user_agent().is_mobile
|
||||
|
||||
if request.controller == "webservices":
|
||||
basic = request.env.http_authorization
|
||||
if not basic or not basic[:6].lower() == 'basic ':
|
||||
raise HTTP(401,"Wrong credentials")
|
||||
raise HTTP(401, "Wrong credentials")
|
||||
(username, password) = base64.b64decode(basic[6:]).split(':')
|
||||
if not verify_password(password) or MULTI_USER_MODE:
|
||||
time.sleep(10)
|
||||
raise HTTP(403,"Not authorized")
|
||||
raise HTTP(403, "Not authorized")
|
||||
elif not session.authorized and not \
|
||||
(request.controller == 'default' and \
|
||||
request.function in ('index','user')):
|
||||
(request.controller + '/' + request.function in
|
||||
('default/index', 'default/user', 'plugin_jqmobile/index', 'plugin_jqmobile/about')):
|
||||
|
||||
if request.env.query_string:
|
||||
query_string = '?' + request.env.query_string
|
||||
@@ -150,8 +172,6 @@ elif session.authorized and \
|
||||
request.function == 'index':
|
||||
redirect(URL(request.application, 'default', 'site'))
|
||||
|
||||
|
||||
if request.controller=='appadmin' and DEMO_MODE:
|
||||
if request.controller == 'appadmin' and DEMO_MODE:
|
||||
session.flash = 'Appadmin disabled in demo mode'
|
||||
redirect(URL('default','sites'))
|
||||
|
||||
redirect(URL('default', 'sites'))
|
||||
|
||||
@@ -2,37 +2,41 @@
|
||||
|
||||
import os
|
||||
|
||||
def A_button(*a,**b):
|
||||
|
||||
def A_button(*a, **b):
|
||||
b['_data-role'] = 'button'
|
||||
b['_data-inline'] = 'true'
|
||||
return A(*a,**b)
|
||||
return A(*a, **b)
|
||||
|
||||
|
||||
def button(href, label):
|
||||
if request.user_agent().is_mobile:
|
||||
if is_mobile:
|
||||
ret = A_button(SPAN(label), _href=href)
|
||||
else:
|
||||
ret = A(SPAN(label),_class='button',_href=href)
|
||||
ret = A(SPAN(label), _class='button', _href=href)
|
||||
return ret
|
||||
|
||||
|
||||
def button_enable(href, app):
|
||||
if os.path.exists(os.path.join(apath(app,r=request),'DISABLED')):
|
||||
label = SPAN(T('Enable'),_style='color:red')
|
||||
if os.path.exists(os.path.join(apath(app, r=request), 'DISABLED')):
|
||||
label = SPAN(T('Enable'), _style='color:red')
|
||||
else:
|
||||
label = SPAN(T('Disable'),_style='color:green')
|
||||
id = 'enable_'+app
|
||||
return A(label,_class='button',_id=id,callback=href,target=id)
|
||||
label = SPAN(T('Disable'), _style='color:green')
|
||||
id = 'enable_' + app
|
||||
return A(label, _class='button', _id=id, callback=href, target=id)
|
||||
|
||||
|
||||
def sp_button(href, label):
|
||||
if request.user_agent().is_mobile:
|
||||
ret = A_button(SPAN(label), _href=href)
|
||||
else:
|
||||
ret = A(SPAN(label),_class='button special',_href=href)
|
||||
ret = A(SPAN(label), _class='button special', _href=href)
|
||||
return ret
|
||||
|
||||
|
||||
def helpicon():
|
||||
return IMG(_src=URL('static', 'images/help.png'), _alt='help')
|
||||
|
||||
|
||||
def searchbox(elementid):
|
||||
return TAG[''](LABEL(IMG(_id="search_start",_src=URL('static', 'images/search.png'), _alt=T('filter')), _class='icon', _for=elementid), ' ', INPUT(_id=elementid, _type='text', _size=12))
|
||||
|
||||
|
||||
return TAG[''](LABEL(IMG(_id="search_start", _src=URL('static', 'images/search.png'), _alt=T('filter')), _class='icon', _for=elementid), ' ', INPUT(_id=elementid, _type='text', _size=12))
|
||||
|
||||
@@ -4,37 +4,39 @@
|
||||
if MULTI_USER_MODE:
|
||||
db = DAL('sqlite://storage.sqlite') # if not, use SQLite or other DB
|
||||
from gluon.tools import *
|
||||
auth = Auth(globals(),db) # authentication/authorization
|
||||
crud = Crud(globals(),db) # for CRUD helpers using auth
|
||||
service = Service(globals()) # for json, xml, jsonrpc, xmlrpc, amfrpc
|
||||
auth = Auth(
|
||||
globals(), db) # authentication/authorization
|
||||
crud = Crud(
|
||||
globals(), db) # for CRUD helpers using auth
|
||||
service = Service(
|
||||
globals()) # for json, xml, jsonrpc, xmlrpc, amfrpc
|
||||
plugins = PluginManager()
|
||||
|
||||
mail = auth.settings.mailer
|
||||
mail.settings.server = EMAIL_SERVER
|
||||
mail.settings.sender = EMAIL_SENDER
|
||||
mail.settings.login = EMAIL_LOGIN
|
||||
mail.settings.login = EMAIL_LOGIN
|
||||
|
||||
auth.settings.extra_fields['auth_user'] = \
|
||||
[Field('is_manager','boolean',default=False,writable=False)]
|
||||
[Field('is_manager', 'boolean', default=False, writable=False)]
|
||||
auth.define_tables() # creates all needed tables
|
||||
auth.settings.registration_requires_verification = False
|
||||
auth.settings.registration_requires_approval = True
|
||||
auth.settings.reset_password_requires_verification = True
|
||||
|
||||
db.define_table('app',Field('name'),Field('owner',db.auth_user))
|
||||
db.define_table('app', Field('name'), Field('owner', db.auth_user))
|
||||
|
||||
if not session.authorized and MULTI_USER_MODE:
|
||||
if auth.user and not request.function=='user':
|
||||
if auth.user and not request.function == 'user':
|
||||
session.authorized = True
|
||||
elif not request.function=='user':
|
||||
redirect(URL('default','user/login'))
|
||||
elif not request.function == 'user':
|
||||
redirect(URL('default', 'user/login'))
|
||||
|
||||
|
||||
def is_manager():
|
||||
if not MULTI_USER_MODE:
|
||||
return True
|
||||
elif auth.user and (auth.user.id==1 or auth.user.is_manager):
|
||||
elif auth.user and (auth.user.id == 1 or auth.user.is_manager):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
|
||||
@@ -7,31 +7,30 @@ _c = request.controller
|
||||
_f = request.function
|
||||
response.title = '%s %s' % (_f, '/'.join(request.args))
|
||||
response.subtitle = 'admin'
|
||||
response.menu = [(T('Site'), _f == 'site', URL(_a,'default','site'))]
|
||||
response.menu = [(T('Site'), _f == 'site', URL(_a, 'default', 'site'))]
|
||||
|
||||
if request.vars.app or request.args:
|
||||
_t = request.vars.app or request.args[0]
|
||||
response.menu.append((T('Edit'), _c == 'default' and _f == 'design',
|
||||
URL(_a,'default','design',args=_t)))
|
||||
URL(_a, 'default', 'design', args=_t)))
|
||||
response.menu.append((T('About'), _c == 'default' and _f == 'about',
|
||||
URL(_a,'default','about',args=_t,)))
|
||||
URL(_a, 'default', 'about', args=_t,)))
|
||||
response.menu.append((T('Errors'), _c == 'default' and _f == 'errors',
|
||||
URL(_a,'default','errors',args=_t)))
|
||||
URL(_a, 'default', 'errors', args=_t)))
|
||||
response.menu.append((T('Versioning'),
|
||||
_c == 'mercurial' and _f == 'commit',
|
||||
URL(_a,'mercurial','commit',args=_t)))
|
||||
URL(_a, 'mercurial', 'commit', args=_t)))
|
||||
|
||||
if not session.authorized:
|
||||
response.menu = [(T('Login'), True, URL('site'))]
|
||||
else:
|
||||
response.menu.append((T('Logout'), False,
|
||||
URL(_a,'default',f='logout')))
|
||||
response.menu.append((T('Debug'), False,
|
||||
URL(_a, 'debug','interact')))
|
||||
URL(_a, 'default', f='logout')))
|
||||
response.menu.append((T('Debug'), False,
|
||||
URL(_a, 'debug', 'interact')))
|
||||
|
||||
if os.path.exists('applications/examples'):
|
||||
response.menu.append((T('Help'), False, URL('examples','default','index')))
|
||||
response.menu.append(
|
||||
(T('Help'), False, URL('examples', 'default', 'index')))
|
||||
else:
|
||||
response.menu.append((T('Help'), False, 'http://web2py.com/examples'))
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
response.files.append(URL('static','plugin_multiselect/jquery.multi-select.js'))
|
||||
response.files.append(URL('static','plugin_multiselect/multi-select.css'))
|
||||
response.files.append(URL('static','plugin_multiselect/start.js'))
|
||||
|
||||
|
||||
response.files.append(
|
||||
URL('static', 'plugin_multiselect/jquery.multi-select.js'))
|
||||
response.files.append(URL('static', 'plugin_multiselect/multi-select.css'))
|
||||
response.files.append(URL('static', 'plugin_multiselect/start.js'))
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -10,7 +10,7 @@ h3 {font-size:2.00em}
|
||||
h4 {font-size:1.50em}
|
||||
h5 {font-size:1.25em}
|
||||
h6 {font-size:1.12em}
|
||||
th,label {font-weight:bold; white-space:nowrap}
|
||||
th,label {font-weight:bold; white-space:nowrap;}
|
||||
td,th {text-align:left; padding:2px 5px 2px 5px}
|
||||
th {vertical-align:middle; border-right:1px solid white}
|
||||
td {vertical-align:top}
|
||||
@@ -69,7 +69,6 @@ fieldset {padding:16px; border-top:1px #DEDEDE solid}
|
||||
fieldset legend {text-transform:uppercase; font-weight:bold; padding:4px 16px 4px 16px; background:#f1f1f1}
|
||||
|
||||
/* fix ie problem with menu */
|
||||
.ie-lte7 .topbar .container {z-index:2}
|
||||
|
||||
td.w2p_fw {padding-bottom:1px}
|
||||
td.w2p_fl,td.w2p_fw,td.w2p_fc {vertical-align:top}
|
||||
@@ -187,10 +186,7 @@ div.error {
|
||||
.web2py_paginator {}
|
||||
.web2py_grid {width:100%}
|
||||
.web2py_grid table {width:100%}
|
||||
.web2py_grid tbody td {
|
||||
padding:2px 5px 2px 5px;
|
||||
vertical-align:middle;
|
||||
}
|
||||
.web2py_grid tbody td {padding:2px 5px 2px 5px; vertical-align: middle;}
|
||||
|
||||
.web2py_grid thead th,.web2py_grid tfoot td {
|
||||
background-color:#EAEAEA;
|
||||
@@ -299,10 +295,16 @@ li.w2p_grid_breadcrumb_elem {
|
||||
.web2py_console input, .web2py_console select,
|
||||
.web2py_console a { margin: 2px; }
|
||||
|
||||
.ie9 #w2p_query_panel {padding-bottom:2px}
|
||||
|
||||
#wiki_page_body {
|
||||
width: 600px;
|
||||
height: auto;
|
||||
min-height: 400px;
|
||||
}
|
||||
}
|
||||
|
||||
/* fix some IE problems */
|
||||
|
||||
.ie-lte7 .topbar .container {z-index:2}
|
||||
.ie-lte8 div.flash{ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#222222', endColorstr='#000000', GradientType=0 ); }
|
||||
.ie-lte8 div.flash:hover {filter:alpha(opacity=25);}
|
||||
.ie9 #w2p_query_panel {padding-bottom:2px}
|
||||
|
||||
4
applications/admin/static/js/modernizr.custom.js
Normal file
4
applications/admin/static/js/modernizr.custom.js
Normal file
File diff suppressed because one or more lines are too long
@@ -39,7 +39,7 @@ function web2py_ajax_init(target) {
|
||||
|
||||
function web2py_event_handlers() {
|
||||
var doc = jQuery(document)
|
||||
doc.on('click', '.flash', function(e){jQuery(this).fadeOut('slow'); e.preventDefault();});
|
||||
doc.on('click', '.flash', function(e){var t=jQuery(this); if(t.css('top')=='0px') t.slideUp('slow'); else t.fadeOut(); e.preventDefault();});
|
||||
doc.on('keyup', 'input.integer', function(){this.value=this.value.reverse().replace(/[^0-9\-]|\-(?=.)/g,'').reverse();});
|
||||
doc.on('keyup', 'input.double, input.decimal', function(){this.value=this.value.reverse().replace(/[^0-9\-\.,]|[\-](?=.)|[\.,](?=[0-9]*[\.,])/g,'').reverse();});
|
||||
var confirm_message = (typeof w2p_ajax_confirm_message != 'undefined') ? w2p_ajax_confirm_message : "Are you sure you want to delete this object?";
|
||||
@@ -55,7 +55,7 @@ function web2py_event_handlers() {
|
||||
jQuery(function() {
|
||||
var flash = jQuery('.flash');
|
||||
flash.hide();
|
||||
if(flash.html()) flash.slideDown();
|
||||
if(flash.html()) flash.append('<span style="float:right;">×</span>').slideDown();
|
||||
web2py_ajax_init(document);
|
||||
web2py_event_handlers();
|
||||
});
|
||||
@@ -67,20 +67,20 @@ function web2py_trap_form(action,target) {
|
||||
form.submit(function(e){
|
||||
jQuery('.flash').hide().html('');
|
||||
web2py_ajax_page('post',action,form.serialize(),target);
|
||||
e.preventDefault();
|
||||
e.preventDefault();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function web2py_trap_link(target) {
|
||||
jQuery('#'+target+' a.w2p_trap').each(function(i){
|
||||
var link=jQuery(this);
|
||||
link.click(function(e) {
|
||||
jQuery('.flash').hide().html('');
|
||||
web2py_ajax_page('get',link.attr('href'),[],target);
|
||||
e.preventDefault();
|
||||
});
|
||||
});
|
||||
var link=jQuery(this);
|
||||
link.click(function(e) {
|
||||
jQuery('.flash').hide().html('');
|
||||
web2py_ajax_page('get',link.attr('href'),[],target);
|
||||
e.preventDefault();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function web2py_ajax_page(method, action, data, target) {
|
||||
@@ -101,9 +101,9 @@ function web2py_ajax_page(method, action, data, target) {
|
||||
web2py_trap_link(target);
|
||||
web2py_ajax_init('#'+target);
|
||||
if(command)
|
||||
eval(decodeURIComponent(command));
|
||||
eval(decodeURIComponent(command));
|
||||
if(flash)
|
||||
jQuery('.flash').html(decodeURIComponent(flash)).slideDown();
|
||||
jQuery('.flash').html(decodeURIComponent(flash)).slideDown();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -151,11 +151,11 @@ function web2py_component(action, target, timeout, times){
|
||||
}
|
||||
} else {
|
||||
// run once (no timeout specified)
|
||||
element.reload_counter = Infinity;
|
||||
element.reload_counter = Infinity;
|
||||
web2py_ajax_page('get', action, null, target);
|
||||
} }); }
|
||||
|
||||
function web2py_comet(url,onmessage,onopen,onclose) {
|
||||
function web2py_websocket(url,onmessage,onopen,onclose) {
|
||||
if ("WebSocket" in window) {
|
||||
var ws = new WebSocket(url);
|
||||
ws.onopen = onopen?onopen:(function(){});
|
||||
@@ -165,3 +165,38 @@ function web2py_comet(url,onmessage,onopen,onclose) {
|
||||
} else return false; // not supported
|
||||
}
|
||||
|
||||
|
||||
function web2py_calc_entropy(mystring) {
|
||||
//calculate a simple entropy for a given string
|
||||
var csets = new Array(
|
||||
'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
||||
'0123456789', '!@#$\%^&*()', '~`-_=+[]{}\|;:\'",.<>?/',
|
||||
'0123456789abcdefghijklmnopqrstuvwxyz');
|
||||
var score = 0, other = {}, seen = {}, lastset = null, mystringlist = mystring.split('');
|
||||
for (var i=0;i<mystringlist.length;i++) { // classify this character
|
||||
var c = mystringlist[i], inset=5;
|
||||
for(var j = 0; j<csets.length; j++)
|
||||
if (csets[j].indexOf(c) != -1) {inset = j; break;}
|
||||
//calculate effect of character on alphabet size
|
||||
if(!(inset in seen)) {seen[inset] = 1;score += csets[inset].length;}
|
||||
else if (!(c in other)) {score += 1;other[c] = 1;}
|
||||
if (inset != lastset) {score += 1;lastset = inset;}
|
||||
}
|
||||
var entropy = mystring.length*Math.log(score)/0.6931471805599453;
|
||||
return Math.round(entropy*100)/100
|
||||
}
|
||||
|
||||
function web2py_validate_entropy(myfield, req_entropy) {
|
||||
var validator = function () {
|
||||
var v = (web2py_calc_entropy(myfield.val())||0)/req_entropy;
|
||||
var r=0,g=0,b=0,rs=function(x){return Math.round(x*15).toString(16)};
|
||||
if(v<=0.5) {r=1.0; g=2.0*v;}
|
||||
else {r=(1.0-2.0*(Math.max(v,0)-0.5)); g=1.0;}
|
||||
var color = '#'+rs(r)+rs(g)+rs(b);
|
||||
myfield.css('background-color',color);
|
||||
entropy_callback = myfield.data('entropy_callback');
|
||||
if(entropy_callback) entropy_callback(v);
|
||||
}
|
||||
if(!myfield.hasClass('entropy_check')) myfield.on('keyup', validator).on('keydown', validator).addClass('entropy_check');
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,173 +0,0 @@
|
||||
/*! jQuery Mobile v1.0 jquerymobile.com | jquery.org/license */
|
||||
(function(a,e){if(a.cleanData){var b=a.cleanData;a.cleanData=function(f){for(var c=0,h;(h=f[c])!=null;c++)a(h).triggerHandler("remove");b(f)}}else{var d=a.fn.remove;a.fn.remove=function(b,c){return this.each(function(){c||(!b||a.filter(b,[this]).length)&&a("*",this).add([this]).each(function(){a(this).triggerHandler("remove")});return d.call(a(this),b,c)})}}a.widget=function(b,c,h){var d=b.split(".")[0],e,b=b.split(".")[1];e=d+"-"+b;if(!h)h=c,c=a.Widget;a.expr[":"][e]=function(c){return!!a.data(c,
|
||||
b)};a[d]=a[d]||{};a[d][b]=function(a,b){arguments.length&&this._createWidget(a,b)};c=new c;c.options=a.extend(true,{},c.options);a[d][b].prototype=a.extend(true,c,{namespace:d,widgetName:b,widgetEventPrefix:a[d][b].prototype.widgetEventPrefix||b,widgetBaseClass:e},h);a.widget.bridge(b,a[d][b])};a.widget.bridge=function(b,c){a.fn[b]=function(d){var g=typeof d==="string",i=Array.prototype.slice.call(arguments,1),k=this,d=!g&&i.length?a.extend.apply(null,[true,d].concat(i)):d;if(g&&d.charAt(0)==="_")return k;
|
||||
g?this.each(function(){var c=a.data(this,b);if(!c)throw"cannot call methods on "+b+" prior to initialization; attempted to call method '"+d+"'";if(!a.isFunction(c[d]))throw"no such method '"+d+"' for "+b+" widget instance";var g=c[d].apply(c,i);if(g!==c&&g!==e)return k=g,false}):this.each(function(){var e=a.data(this,b);e?e.option(d||{})._init():a.data(this,b,new c(d,this))});return k}};a.Widget=function(a,b){arguments.length&&this._createWidget(a,b)};a.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",
|
||||
options:{disabled:false},_createWidget:function(b,c){a.data(c,this.widgetName,this);this.element=a(c);this.options=a.extend(true,{},this.options,this._getCreateOptions(),b);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()});this._create();this._trigger("create");this._init()},_getCreateOptions:function(){var b={};a.metadata&&(b=a.metadata.get(element)[this.widgetName]);return b},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);
|
||||
this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled ui-state-disabled")},widget:function(){return this.element},option:function(b,c){var d=b;if(arguments.length===0)return a.extend({},this.options);if(typeof b==="string"){if(c===e)return this.options[b];d={};d[b]=c}this._setOptions(d);return this},_setOptions:function(b){var c=this;a.each(b,function(a,b){c._setOption(a,b)});return this},_setOption:function(a,b){this.options[a]=b;a==="disabled"&&
|
||||
this.widget()[b?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",b);return this},enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(b,c,d){var e=this.options[b],c=a.Event(c);c.type=(b===this.widgetEventPrefix?b:this.widgetEventPrefix+b).toLowerCase();d=d||{};if(c.originalEvent)for(var b=a.event.props.length,i;b;)i=a.event.props[--b],c[i]=c.originalEvent[i];this.element.trigger(c,
|
||||
d);return!(a.isFunction(e)&&e.call(this.element[0],c,d)===false||c.isDefaultPrevented())}}})(jQuery);
|
||||
(function(a,e){a.widget("mobile.widget",{_createWidget:function(){a.Widget.prototype._createWidget.apply(this,arguments);this._trigger("init")},_getCreateOptions:function(){var b=this.element,d={};a.each(this.options,function(a){var c=b.jqmData(a.replace(/[A-Z]/g,function(a){return"-"+a.toLowerCase()}));c!==e&&(d[a]=c)});return d},enhanceWithin:function(b){var d=a(b).closest(":jqmData(role='page')").data("page"),d=d&&d.keepNativeSelector()||"";a(this.options.initSelector,b).not(d)[this.widgetName]()}})})(jQuery);
|
||||
(function(a){a(window);var e=a("html");a.mobile.media=function(){var b={},d=a("<div id='jquery-mediatest'>"),f=a("<body>").append(d);return function(a){if(!(a in b)){var h=document.createElement("style"),g="@media "+a+" { #jquery-mediatest { position:absolute; } }";h.type="text/css";h.styleSheet?h.styleSheet.cssText=g:h.appendChild(document.createTextNode(g));e.prepend(f).prepend(h);b[a]=d.css("position")==="absolute";f.add(h).remove()}return b[a]}}()})(jQuery);
|
||||
(function(a,e){function b(a){var b=a.charAt(0).toUpperCase()+a.substr(1),a=(a+" "+c.join(b+" ")+b).split(" "),d;for(d in a)if(f[a[d]]!==e)return true}var d=a("<body>").prependTo("html"),f=d[0].style,c=["Webkit","Moz","O"],h="palmGetResource"in window,g=window.operamini&&{}.toString.call(window.operamini)==="[object OperaMini]",i=window.blackberry;a.mobile.browser={};a.mobile.browser.ie=function(){for(var a=3,b=document.createElement("div"),c=b.all||[];b.innerHTML="<\!--[if gt IE "+ ++a+"]><br><![endif]--\>",
|
||||
c[0];);return a>4?a:!a}();a.extend(a.support,{orientation:"orientation"in window&&"onorientationchange"in window,touch:"ontouchend"in document,cssTransitions:"WebKitTransitionEvent"in window,pushState:"pushState"in history&&"replaceState"in history,mediaquery:a.mobile.media("only all"),cssPseudoElement:!!b("content"),touchOverflow:!!b("overflowScrolling"),boxShadow:!!b("boxShadow")&&!i,scrollTop:("pageXOffset"in window||"scrollTop"in document.documentElement||"scrollTop"in d[0])&&!h&&!g,dynamicBaseTag:function(){var b=
|
||||
location.protocol+"//"+location.host+location.pathname+"ui-dir/",c=a("head base"),f=null,e="",h;c.length?e=c.attr("href"):c=f=a("<base>",{href:b}).appendTo("head");h=a("<a href='testurl' />").prependTo(d)[0].href;c[0].href=e||location.pathname;f&&f.remove();return h.indexOf(b)===0}()});d.remove();h=function(){var a=window.navigator.userAgent;return a.indexOf("Nokia")>-1&&(a.indexOf("Symbian/3")>-1||a.indexOf("Series60/5")>-1)&&a.indexOf("AppleWebKit")>-1&&a.match(/(BrowserNG|NokiaBrowser)\/7\.[0-3]/)}();
|
||||
a.mobile.ajaxBlacklist=window.blackberry&&!window.WebKitPoint||g||h;h&&a(function(){a("head link[rel='stylesheet']").attr("rel","alternate stylesheet").attr("rel","stylesheet")});a.support.boxShadow||a("html").addClass("ui-mobile-nosupport-boxshadow")})(jQuery);
|
||||
(function(a,e,b,d){function f(a){for(;a&&typeof a.originalEvent!=="undefined";)a=a.originalEvent;return a}function c(b){for(var c={},f,d;b;){f=a.data(b,n);for(d in f)if(f[d])c[d]=c.hasVirtualBinding=true;b=b.parentNode}return c}function h(){v&&(clearTimeout(v),v=0);v=setTimeout(function(){E=v=0;u.length=0;D=false;y=true},a.vmouse.resetTimerDuration)}function g(b,c,r){var e,h;if(!(h=r&&r[b])){if(r=!r)a:{for(r=c.target;r;){if((h=a.data(r,n))&&(!b||h[b]))break a;r=r.parentNode}r=null}h=r}if(h){e=c;var r=
|
||||
e.type,j,g;e=a.Event(e);e.type=b;h=e.originalEvent;j=a.event.props;if(h)for(g=j.length;g;)b=j[--g],e[b]=h[b];if(r.search(/mouse(down|up)|click/)>-1&&!e.which)e.which=1;if(r.search(/^touch/)!==-1&&(b=f(h),r=b.touches,b=b.changedTouches,r=r&&r.length?r[0]:b&&b.length?b[0]:d))for(h=0,len=z.length;h<len;h++)b=z[h],e[b]=r[b];a(c.target).trigger(e)}return e}function i(b){var c=a.data(b.target,A);if(!D&&(!E||E!==c))if(c=g("v"+b.type,b))c.isDefaultPrevented()&&b.preventDefault(),c.isPropagationStopped()&&
|
||||
b.stopPropagation(),c.isImmediatePropagationStopped()&&b.stopImmediatePropagation()}function k(b){var d=f(b).touches,e;if(d&&d.length===1&&(e=b.target,d=c(e),d.hasVirtualBinding))E=r++,a.data(e,A,E),v&&(clearTimeout(v),v=0),w=y=false,e=f(b).touches[0],x=e.pageX,t=e.pageY,g("vmouseover",b,d),g("vmousedown",b,d)}function l(a){y||(w||g("vmousecancel",a,c(a.target)),w=true,h())}function o(b){if(!y){var d=f(b).touches[0],r=w,e=a.vmouse.moveDistanceThreshold;w=w||Math.abs(d.pageX-x)>e||Math.abs(d.pageY-
|
||||
t)>e;flags=c(b.target);w&&!r&&g("vmousecancel",b,flags);g("vmousemove",b,flags);h()}}function m(a){if(!y){y=true;var b=c(a.target),d;g("vmouseup",a,b);if(!w&&(d=g("vclick",a,b))&&d.isDefaultPrevented())d=f(a).changedTouches[0],u.push({touchID:E,x:d.clientX,y:d.clientY}),D=true;g("vmouseout",a,b);w=false;h()}}function p(b){var b=a.data(b,n),c;if(b)for(c in b)if(b[c])return true;return false}function j(){}function q(b){var c=b.substr(1);return{setup:function(){p(this)||a.data(this,n,{});a.data(this,
|
||||
n)[b]=true;s[b]=(s[b]||0)+1;s[b]===1&&B.bind(c,i);a(this).bind(c,j);if(C)s.touchstart=(s.touchstart||0)+1,s.touchstart===1&&B.bind("touchstart",k).bind("touchend",m).bind("touchmove",o).bind("scroll",l)},teardown:function(){--s[b];s[b]||B.unbind(c,i);C&&(--s.touchstart,s.touchstart||B.unbind("touchstart",k).unbind("touchmove",o).unbind("touchend",m).unbind("scroll",l));var d=a(this),f=a.data(this,n);f&&(f[b]=false);d.unbind(c,j);p(this)||d.removeData(n)}}}var n="virtualMouseBindings",A="virtualTouchID",
|
||||
e="vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel".split(" "),z="clientX clientY pageX pageY screenX screenY".split(" "),s={},v=0,x=0,t=0,w=false,u=[],D=false,y=false,C="addEventListener"in b,B=a(b),r=1,E=0;a.vmouse={moveDistanceThreshold:10,clickDistanceThreshold:10,resetTimerDuration:1500};for(var F=0;F<e.length;F++)a.event.special[e[F]]=q(e[F]);C&&b.addEventListener("click",function(b){var c=u.length,d=b.target,f,r,e,h,j;if(c){f=b.clientX;r=b.clientY;threshold=a.vmouse.clickDistanceThreshold;
|
||||
for(e=d;e;){for(h=0;h<c;h++)if(j=u[h],e===d&&Math.abs(j.x-f)<threshold&&Math.abs(j.y-r)<threshold||a.data(e,A)===j.touchID){b.preventDefault();b.stopPropagation();return}e=e.parentNode}}},true)})(jQuery,window,document);
|
||||
(function(a,e,b){function d(b,c,d){var f=d.type;d.type=c;a.event.handle.call(b,d);d.type=f}a.each("touchstart touchmove touchend orientationchange throttledresize tap taphold swipe swipeleft swiperight scrollstart scrollstop".split(" "),function(b,c){a.fn[c]=function(a){return a?this.bind(c,a):this.trigger(c)};a.attrFn[c]=true});var f=a.support.touch,c=f?"touchstart":"mousedown",h=f?"touchend":"mouseup",g=f?"touchmove":"mousemove";a.event.special.scrollstart={enabled:true,setup:function(){function b(a,
|
||||
e){f=e;d(c,f?"scrollstart":"scrollstop",a)}var c=this,f,e;a(c).bind("touchmove scroll",function(c){a.event.special.scrollstart.enabled&&(f||b(c,true),clearTimeout(e),e=setTimeout(function(){b(c,false)},50))})}};a.event.special.tap={setup:function(){var b=this,c=a(b);c.bind("vmousedown",function(f){function e(){clearTimeout(q)}function h(){e();c.unbind("vclick",g).unbind("vmouseup",e).unbind("vmousecancel",h)}function g(a){h();j==a.target&&d(b,"tap",a)}if(f.which&&f.which!==1)return false;var j=f.target,
|
||||
q;c.bind("vmousecancel",h).bind("vmouseup",e).bind("vclick",g);q=setTimeout(function(){d(b,"taphold",a.Event("taphold"))},750)})}};a.event.special.swipe={scrollSupressionThreshold:10,durationThreshold:1E3,horizontalDistanceThreshold:30,verticalDistanceThreshold:75,setup:function(){var d=a(this);d.bind(c,function(c){function f(b){if(m){var c=b.originalEvent.touches?b.originalEvent.touches[0]:b;p={time:(new Date).getTime(),coords:[c.pageX,c.pageY]};Math.abs(m.coords[0]-p.coords[0])>a.event.special.swipe.scrollSupressionThreshold&&
|
||||
b.preventDefault()}}var e=c.originalEvent.touches?c.originalEvent.touches[0]:c,m={time:(new Date).getTime(),coords:[e.pageX,e.pageY],origin:a(c.target)},p;d.bind(g,f).one(h,function(){d.unbind(g,f);m&&p&&p.time-m.time<a.event.special.swipe.durationThreshold&&Math.abs(m.coords[0]-p.coords[0])>a.event.special.swipe.horizontalDistanceThreshold&&Math.abs(m.coords[1]-p.coords[1])<a.event.special.swipe.verticalDistanceThreshold&&m.origin.trigger("swipe").trigger(m.coords[0]>p.coords[0]?"swipeleft":"swiperight");
|
||||
m=p=b})})}};(function(a,b){function c(){var a=f();a!==e&&(e=a,d.trigger("orientationchange"))}var d=a(b),f,e;a.event.special.orientationchange={setup:function(){if(a.support.orientation&&a.mobile.orientationChangeEnabled)return false;e=f();d.bind("throttledresize",c)},teardown:function(){if(a.support.orientation&&a.mobile.orientationChangeEnabled)return false;d.unbind("throttledresize",c)},add:function(a){var b=a.handler;a.handler=function(a){a.orientation=f();return b.apply(this,arguments)}}};a.event.special.orientationchange.orientation=
|
||||
f=function(){var c=true,c=document.documentElement;return(c=a.support.orientation?b.orientation%180==0:c&&c.clientWidth/c.clientHeight<1.1)?"portrait":"landscape"}})(jQuery,e);(function(){a.event.special.throttledresize={setup:function(){a(this).bind("resize",b)},teardown:function(){a(this).unbind("resize",b)}};var b=function(){f=(new Date).getTime();e=f-c;e>=250?(c=f,a(this).trigger("throttledresize")):(d&&clearTimeout(d),d=setTimeout(b,250-e))},c=0,d,f,e})();a.each({scrollstop:"scrollstart",taphold:"tap",
|
||||
swipeleft:"swipe",swiperight:"swipe"},function(b,c){a.event.special[b]={setup:function(){a(this).bind(c,a.noop)}}})})(jQuery,this);
|
||||
(function(a,e,b){function d(a){a=a||location.href;return"#"+a.replace(/^[^#]*#?(.*)$/,"$1")}var f="hashchange",c=document,h,g=a.event.special,i=c.documentMode,k="on"+f in e&&(i===b||i>7);a.fn[f]=function(a){return a?this.bind(f,a):this.trigger(f)};a.fn[f].delay=50;g[f]=a.extend(g[f],{setup:function(){if(k)return false;a(h.start)},teardown:function(){if(k)return false;a(h.stop)}});h=function(){function h(){var b=d(),c=n(p);if(b!==p)q(p=b,c),a(e).trigger(f);else if(c!==p)location.href=location.href.replace(/#.*/,
|
||||
"")+c;i=setTimeout(h,a.fn[f].delay)}var g={},i,p=d(),j=function(a){return a},q=j,n=j;g.start=function(){i||h()};g.stop=function(){i&&clearTimeout(i);i=b};a.browser.msie&&!k&&function(){var b,e;g.start=function(){if(!b)e=(e=a.fn[f].src)&&e+d(),b=a('<iframe tabindex="-1" title="empty"/>').hide().one("load",function(){e||q(d());h()}).attr("src",e||"javascript:0").insertAfter("body")[0].contentWindow,c.onpropertychange=function(){try{if(event.propertyName==="title")b.document.title=c.title}catch(a){}}};
|
||||
g.stop=j;n=function(){return d(b.location.href)};q=function(d,e){var h=b.document,g=a.fn[f].domain;if(d!==e)h.title=c.title,h.open(),g&&h.write('<script>document.domain="'+g+'"<\/script>'),h.close(),b.location.hash=d}}();return g}()})(jQuery,this);
|
||||
(function(a){a.widget("mobile.page",a.mobile.widget,{options:{theme:"c",domCache:false,keepNativeDefault:":jqmData(role='none'), :jqmData(role='nojs')"},_create:function(){this._trigger("beforecreate");this.element.attr("tabindex","0").addClass("ui-page ui-body-"+this.options.theme)},keepNativeSelector:function(){var e=this.options;return e.keepNative&&a.trim(e.keepNative)&&e.keepNative!==e.keepNativeDefault?[e.keepNative,e.keepNativeDefault].join(", "):e.keepNativeDefault}})})(jQuery);
|
||||
(function(a,e){var b={};a.extend(a.mobile,{ns:"",subPageUrlKey:"ui-page",activePageClass:"ui-page-active",activeBtnClass:"ui-btn-active",ajaxEnabled:true,hashListeningEnabled:true,linkBindingEnabled:true,defaultPageTransition:"slide",minScrollBack:250,defaultDialogTransition:"pop",loadingMessage:"loading",pageLoadErrorMessage:"Error Loading Page",autoInitializePage:true,pushStateEnabled:true,orientationChangeEnabled:true,gradeA:function(){return a.support.mediaquery||a.mobile.browser.ie&&a.mobile.browser.ie>=
|
||||
7},keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91},silentScroll:function(b){if(a.type(b)!=="number")b=a.mobile.defaultHomeScroll;a.event.special.scrollstart.enabled=false;
|
||||
setTimeout(function(){e.scrollTo(0,b);a(document).trigger("silentscroll",{x:0,y:b})},20);setTimeout(function(){a.event.special.scrollstart.enabled=true},150)},nsNormalizeDict:b,nsNormalize:function(c){return!c?void 0:b[c]||(b[c]=a.camelCase(a.mobile.ns+c))},getInheritedTheme:function(a,b){for(var d=a[0],f="",e=/ui-(bar|body)-([a-z])\b/,l,o;d;){l=d.className||"";if((o=e.exec(l))&&(f=o[2]))break;d=d.parentNode}return f||b||"a"}});a.fn.jqmData=function(b,d){var f;typeof b!="undefined"&&(f=this.data(b?
|
||||
a.mobile.nsNormalize(b):b,d));return f};a.jqmData=function(b,d,f){var e;typeof d!="undefined"&&(e=a.data(b,d?a.mobile.nsNormalize(d):d,f));return e};a.fn.jqmRemoveData=function(b){return this.removeData(a.mobile.nsNormalize(b))};a.jqmRemoveData=function(b,d){return a.removeData(b,a.mobile.nsNormalize(d))};a.fn.removeWithDependents=function(){a.removeWithDependents(this)};a.removeWithDependents=function(b){b=a(b);(b.jqmData("dependents")||a()).remove();b.remove()};a.fn.addDependents=function(b){a.addDependents(a(this),
|
||||
b)};a.addDependents=function(b,d){var f=a(b).jqmData("dependents")||a();a(b).jqmData("dependents",a.merge(f,d))};a.fn.getEncodedText=function(){return a("<div/>").text(a(this).text()).html()};var d=a.find,f=/:jqmData\(([^)]*)\)/g;a.find=function(b,e,g,i){b=b.replace(f,"[data-"+(a.mobile.ns||"")+"$1]");return d.call(this,b,e,g,i)};a.extend(a.find,d);a.find.matches=function(b,d){return a.find(b,null,null,d)};a.find.matchesSelector=function(b,d){return a.find(d,null,null,[b]).length>0}})(jQuery,this);
|
||||
(function(a,e){function b(a){var b=a.find(".ui-title:eq(0)");b.length?b.focus():a.focus()}function d(b){q&&(!q.closest(".ui-page-active").length||b)&&q.removeClass(a.mobile.activeBtnClass);q=null}function f(){z=false;A.length>0&&a.mobile.changePage.apply(null,A.pop())}function c(c,d,f,e){var g=a.mobile.urlHistory.getActive(),j=a.support.touchOverflow&&a.mobile.touchOverflowEnabled,i=g.lastScroll||(j?0:a.mobile.defaultHomeScroll),g=h();window.scrollTo(0,a.mobile.defaultHomeScroll);d&&d.data("page")._trigger("beforehide",
|
||||
null,{nextPage:c});j||c.height(g+i);c.data("page")._trigger("beforeshow",null,{prevPage:d||a("")});a.mobile.hidePageLoadingMsg();j&&i&&(c.addClass("ui-mobile-pre-transition"),b(c),c.is(".ui-native-fixed")?c.find(".ui-content").scrollTop(i):c.scrollTop(i));f=(a.mobile.transitionHandlers[f||"none"]||a.mobile.defaultTransitionHandler)(f,e,c,d);f.done(function(){j||(c.height(""),b(c));j||a.mobile.silentScroll(i);d&&(j||d.height(""),d.data("page")._trigger("hide",null,{nextPage:c}));c.data("page")._trigger("show",
|
||||
null,{prevPage:d||a("")})});return f}function h(){var b=a.event.special.orientationchange.orientation()==="portrait",c=b?screen.availHeight:screen.availWidth,b=Math.max(b?480:320,a(window).height());return Math.min(c,b)}function g(){(!a.support.touchOverflow||!a.mobile.touchOverflowEnabled)&&a("."+a.mobile.activePageClass).css("min-height",h())}function i(b,c){c&&b.attr("data-"+a.mobile.ns+"role",c);b.page()}function k(a){for(;a;){if(typeof a.nodeName==="string"&&a.nodeName.toLowerCase()=="a")break;
|
||||
a=a.parentNode}return a}function l(b){var b=a(b).closest(".ui-page").jqmData("url"),c=t.hrefNoHash;if(!b||!j.isPath(b))b=c;return j.makeUrlAbsolute(b,c)}var o=a(window),m=a("html"),p=a("head"),j={urlParseRE:/^(((([^:\/#\?]+:)?(?:(\/\/)((?:(([^:@\/#\?]+)(?:\:([^:@\/#\?]+))?)@)?(([^:\/#\?\]\[]+|\[[^\/\]@#?]+\])(?:\:([0-9]+))?))?)?)?((\/?(?:[^\/\?#]+\/+)*)([^\?#]*)))?(\?[^#]+)?)(#.*)?/,parseUrl:function(b){if(a.type(b)==="object")return b;b=j.urlParseRE.exec(b||"")||[];return{href:b[0]||"",hrefNoHash:b[1]||
|
||||
"",hrefNoSearch:b[2]||"",domain:b[3]||"",protocol:b[4]||"",doubleSlash:b[5]||"",authority:b[6]||"",username:b[8]||"",password:b[9]||"",host:b[10]||"",hostname:b[11]||"",port:b[12]||"",pathname:b[13]||"",directory:b[14]||"",filename:b[15]||"",search:b[16]||"",hash:b[17]||""}},makePathAbsolute:function(a,b){if(a&&a.charAt(0)==="/")return a;for(var a=a||"",c=(b=b?b.replace(/^\/|(\/[^\/]*|[^\/]+)$/g,""):"")?b.split("/"):[],d=a.split("/"),f=0;f<d.length;f++){var e=d[f];switch(e){case ".":break;case "..":c.length&&
|
||||
c.pop();break;default:c.push(e)}}return"/"+c.join("/")},isSameDomain:function(a,b){return j.parseUrl(a).domain===j.parseUrl(b).domain},isRelativeUrl:function(a){return j.parseUrl(a).protocol===""},isAbsoluteUrl:function(a){return j.parseUrl(a).protocol!==""},makeUrlAbsolute:function(a,b){if(!j.isRelativeUrl(a))return a;var c=j.parseUrl(a),d=j.parseUrl(b),f=c.protocol||d.protocol,e=c.protocol?c.doubleSlash:c.doubleSlash||d.doubleSlash,h=c.authority||d.authority,g=c.pathname!=="",i=j.makePathAbsolute(c.pathname||
|
||||
d.filename,d.pathname);return f+e+h+i+(c.search||!g&&d.search||"")+c.hash},addSearchParams:function(b,c){var d=j.parseUrl(b),f=typeof c==="object"?a.param(c):c,e=d.search||"?";return d.hrefNoSearch+e+(e.charAt(e.length-1)!=="?"?"&":"")+f+(d.hash||"")},convertUrlToDataUrl:function(a){var b=j.parseUrl(a);if(j.isEmbeddedPage(b))return b.hash.split(s)[0].replace(/^#/,"");else if(j.isSameDomain(b,t))return b.hrefNoHash.replace(t.domain,"");return a},get:function(a){if(a===e)a=location.hash;return j.stripHash(a).replace(/[^\/]*\.[^\/*]+$/,
|
||||
"")},getFilePath:function(b){var c="&"+a.mobile.subPageUrlKey;return b&&b.split(c)[0].split(s)[0]},set:function(a){location.hash=a},isPath:function(a){return/\//.test(a)},clean:function(a){return a.replace(t.domain,"")},stripHash:function(a){return a.replace(/^#/,"")},cleanHash:function(a){return j.stripHash(a.replace(/\?.*$/,"").replace(s,""))},isExternal:function(a){a=j.parseUrl(a);return a.protocol&&a.domain!==x.domain?true:false},hasProtocol:function(a){return/^(:?\w+:)/.test(a)},isFirstPageUrl:function(b){var b=
|
||||
j.parseUrl(j.makeUrlAbsolute(b,t)),c=a.mobile.firstPage,c=c&&c[0]?c[0].id:e;return(b.hrefNoHash===x.hrefNoHash||w&&b.hrefNoHash===t.hrefNoHash)&&(!b.hash||b.hash==="#"||c&&b.hash.replace(/^#/,"")===c)},isEmbeddedPage:function(a){a=j.parseUrl(a);return a.protocol!==""?a.hash&&(a.hrefNoHash===x.hrefNoHash||w&&a.hrefNoHash===t.hrefNoHash):/^#/.test(a.href)}},q=null,n={stack:[],activeIndex:0,getActive:function(){return n.stack[n.activeIndex]},getPrev:function(){return n.stack[n.activeIndex-1]},getNext:function(){return n.stack[n.activeIndex+
|
||||
1]},addNew:function(a,b,c,d,f){n.getNext()&&n.clearForward();n.stack.push({url:a,transition:b,title:c,pageUrl:d,role:f});n.activeIndex=n.stack.length-1},clearForward:function(){n.stack=n.stack.slice(0,n.activeIndex+1)},directHashChange:function(b){var c,d,f;this.getActive();a.each(n.stack,function(a,e){b.currentUrl===e.url&&(c=a<n.activeIndex,d=!c,f=a)});this.activeIndex=f!==e?f:this.activeIndex;c?(b.either||b.isBack)(true):d&&(b.either||b.isForward)(false)},ignoreNextHashChange:false},A=[],z=false,
|
||||
s="&ui-state=dialog",v=p.children("base"),x=j.parseUrl(location.href),t=v.length?j.parseUrl(j.makeUrlAbsolute(v.attr("href"),x.href)):x,w=x.hrefNoHash!==t.hrefNoHash,u=a.support.dynamicBaseTag?{element:v.length?v:a("<base>",{href:t.hrefNoHash}).prependTo(p),set:function(a){u.element.attr("href",j.makeUrlAbsolute(a,t))},reset:function(){u.element.attr("href",t.hrefNoHash)}}:e,D=true,y,C,B;y=function(){var b=o;a.support.touchOverflow&&a.mobile.touchOverflowEnabled&&(b=a(".ui-page-active"),b=b.is(".ui-native-fixed")?
|
||||
b.find(".ui-content"):b);return b};C=function(b){if(D){var c=a.mobile.urlHistory.getActive();if(c)b=b&&b.scrollTop(),c.lastScroll=b<a.mobile.minScrollBack?a.mobile.defaultHomeScroll:b}};B=function(){setTimeout(C,100,a(this))};o.bind(a.support.pushState?"popstate":"hashchange",function(){D=false});o.one(a.support.pushState?"popstate":"hashchange",function(){D=true});o.one("pagecontainercreate",function(){a.mobile.pageContainer.bind("pagechange",function(){var a=y();D=true;a.unbind("scrollstop",B);
|
||||
a.bind("scrollstop",B)})});y().bind("scrollstop",B);a.mobile.getScreenHeight=h;a.fn.animationComplete=function(b){return a.support.cssTransitions?a(this).one("webkitAnimationEnd",b):(setTimeout(b,0),a(this))};a.mobile.path=j;a.mobile.base=u;a.mobile.urlHistory=n;a.mobile.dialogHashKey=s;a.mobile.noneTransitionHandler=function(b,c,d,f){f&&f.removeClass(a.mobile.activePageClass);d.addClass(a.mobile.activePageClass);return a.Deferred().resolve(b,c,d,f).promise()};a.mobile.defaultTransitionHandler=a.mobile.noneTransitionHandler;
|
||||
a.mobile.transitionHandlers={none:a.mobile.defaultTransitionHandler};a.mobile.allowCrossDomainPages=false;a.mobile.getDocumentUrl=function(b){return b?a.extend({},x):x.href};a.mobile.getDocumentBase=function(b){return b?a.extend({},t):t.href};a.mobile._bindPageRemove=function(){var b=a(this);!b.data("page").options.domCache&&b.is(":jqmData(external-page='true')")&&b.bind("pagehide.remove",function(){var b=a(this),c=new a.Event("pageremove");b.trigger(c);c.isDefaultPrevented()||b.removeWithDependents()})};
|
||||
a.mobile.loadPage=function(b,c){var d=a.Deferred(),f=a.extend({},a.mobile.loadPage.defaults,c),h=null,g=null,m=j.makeUrlAbsolute(b,a.mobile.activePage&&l(a.mobile.activePage)||t.hrefNoHash);if(f.data&&f.type==="get")m=j.addSearchParams(m,f.data),f.data=e;if(f.data&&f.type==="post")f.reloadPage=true;var s=j.getFilePath(m),p=j.convertUrlToDataUrl(m);f.pageContainer=f.pageContainer||a.mobile.pageContainer;h=f.pageContainer.children(":jqmData(url='"+p+"')");h.length===0&&p&&!j.isPath(p)&&(h=f.pageContainer.children("#"+
|
||||
p).attr("data-"+a.mobile.ns+"url",p));if(h.length===0)if(a.mobile.firstPage&&j.isFirstPageUrl(s))a.mobile.firstPage.parent().length&&(h=a(a.mobile.firstPage));else if(j.isEmbeddedPage(s))return d.reject(m,c),d.promise();u&&u.reset();if(h.length){if(!f.reloadPage)return i(h,f.role),d.resolve(m,c,h),d.promise();g=h}var n=f.pageContainer,k=new a.Event("pagebeforeload"),q={url:b,absUrl:m,dataUrl:p,deferred:d,options:f};n.trigger(k,q);if(k.isDefaultPrevented())return d.promise();if(f.showLoadMsg)var v=
|
||||
setTimeout(function(){a.mobile.showPageLoadingMsg()},f.loadMsgDelay);!a.mobile.allowCrossDomainPages&&!j.isSameDomain(x,m)?d.reject(m,c):a.ajax({url:s,type:f.type,data:f.data,dataType:"html",success:function(e,n,k){var o=a("<div></div>"),l=e.match(/<title[^>]*>([^<]*)/)&&RegExp.$1,t=RegExp("\\bdata-"+a.mobile.ns+"url=[\"']?([^\"'>]*)[\"']?");RegExp("(<[^>]+\\bdata-"+a.mobile.ns+"role=[\"']?page[\"']?[^>]*>)").test(e)&&RegExp.$1&&t.test(RegExp.$1)&&RegExp.$1&&(b=s=j.getFilePath(RegExp.$1));u&&u.set(s);
|
||||
o.get(0).innerHTML=e;h=o.find(":jqmData(role='page'), :jqmData(role='dialog')").first();h.length||(h=a("<div data-"+a.mobile.ns+"role='page'>"+e.split(/<\/?body[^>]*>/gmi)[1]+"</div>"));l&&!h.jqmData("title")&&(~l.indexOf("&")&&(l=a("<div>"+l+"</div>").text()),h.jqmData("title",l));if(!a.support.dynamicBaseTag){var x=j.get(s);h.find("[src], link[href], a[rel='external'], :jqmData(ajax='false'), a[target]").each(function(){var b=a(this).is("[href]")?"href":a(this).is("[src]")?"src":"action",c=a(this).attr(b),
|
||||
c=c.replace(location.protocol+"//"+location.host+location.pathname,"");/^(\w+:|#|\/)/.test(c)||a(this).attr(b,x+c)})}h.attr("data-"+a.mobile.ns+"url",j.convertUrlToDataUrl(s)).attr("data-"+a.mobile.ns+"external-page",true).appendTo(f.pageContainer);h.one("pagecreate",a.mobile._bindPageRemove);i(h,f.role);m.indexOf("&"+a.mobile.subPageUrlKey)>-1&&(h=f.pageContainer.children(":jqmData(url='"+p+"')"));f.showLoadMsg&&(clearTimeout(v),a.mobile.hidePageLoadingMsg());q.xhr=k;q.textStatus=n;q.page=h;f.pageContainer.trigger("pageload",
|
||||
q);d.resolve(m,c,h,g)},error:function(b,e,h){u&&u.set(j.get());q.xhr=b;q.textStatus=e;q.errorThrown=h;b=new a.Event("pageloadfailed");f.pageContainer.trigger(b,q);b.isDefaultPrevented()||(f.showLoadMsg&&(clearTimeout(v),a.mobile.hidePageLoadingMsg(),a("<div class='ui-loader ui-overlay-shadow ui-body-e ui-corner-all'><h1>"+a.mobile.pageLoadErrorMessage+"</h1></div>").css({display:"block",opacity:0.96,top:o.scrollTop()+100}).appendTo(f.pageContainer).delay(800).fadeOut(400,function(){a(this).remove()})),
|
||||
d.reject(m,c))}});return d.promise()};a.mobile.loadPage.defaults={type:"get",data:e,reloadPage:false,role:e,showLoadMsg:false,pageContainer:e,loadMsgDelay:50};a.mobile.changePage=function(b,h){if(z)A.unshift(arguments);else{var g=a.extend({},a.mobile.changePage.defaults,h);g.pageContainer=g.pageContainer||a.mobile.pageContainer;g.fromPage=g.fromPage||a.mobile.activePage;var p=g.pageContainer,k=new a.Event("pagebeforechange"),q={toPage:b,options:g};p.trigger(k,q);if(!k.isDefaultPrevented())if(b=q.toPage,
|
||||
z=true,typeof b=="string")a.mobile.loadPage(b,g).done(function(b,c,d,f){z=false;c.duplicateCachedPage=f;a.mobile.changePage(d,c)}).fail(function(){z=false;d(true);f();g.pageContainer.trigger("pagechangefailed",q)});else{if(b[0]===a.mobile.firstPage[0]&&!g.dataUrl)g.dataUrl=x.hrefNoHash;var k=g.fromPage,l=g.dataUrl&&j.convertUrlToDataUrl(g.dataUrl)||b.jqmData("url"),v=l;j.getFilePath(l);var o=n.getActive(),t=n.activeIndex===0,w=0,u=document.title,y=g.role==="dialog"||b.jqmData("role")==="dialog";if(k&&
|
||||
k[0]===b[0]&&!g.allowSamePageTransition)z=false,p.trigger("pagechange",q);else{i(b,g.role);g.fromHashChange&&n.directHashChange({currentUrl:l,isBack:function(){w=-1},isForward:function(){w=1}});try{document.activeElement&&document.activeElement.nodeName.toLowerCase()!="body"?a(document.activeElement).blur():a("input:focus, textarea:focus, select:focus").blur()}catch(B){}y&&o&&(l=(o.url||"")+s);if(g.changeHash!==false&&l)n.ignoreNextHashChange=true,j.set(l);var C=!o?u:b.jqmData("title")||b.children(":jqmData(role='header')").find(".ui-title").getEncodedText();
|
||||
C&&u==document.title&&(u=C);b.jqmData("title")||b.jqmData("title",u);g.transition=g.transition||(w&&!t?o.transition:e)||(y?a.mobile.defaultDialogTransition:a.mobile.defaultPageTransition);w||n.addNew(l,g.transition,u,v,g.role);document.title=n.getActive().title;a.mobile.activePage=b;g.reverse=g.reverse||w<0;c(b,k,g.transition,g.reverse).done(function(){d();g.duplicateCachedPage&&g.duplicateCachedPage.remove();m.removeClass("ui-mobile-rendering");f();p.trigger("pagechange",q)})}}}};a.mobile.changePage.defaults=
|
||||
{transition:e,reverse:false,changeHash:true,fromHashChange:false,role:e,duplicateCachedPage:e,pageContainer:e,showLoadMsg:true,dataUrl:e,fromPage:e,allowSamePageTransition:false};a.mobile._registerInternalEvents=function(){a("form").live("submit",function(b){var c=a(this);if(a.mobile.ajaxEnabled&&!c.is(":jqmData(ajax='false')")){var d=c.attr("method"),f=c.attr("target"),e=c.attr("action");if(!e&&(e=l(c),e===t.hrefNoHash))e=x.hrefNoSearch;e=j.makeUrlAbsolute(e,l(c));!j.isExternal(e)&&!f&&(a.mobile.changePage(e,
|
||||
{type:d&&d.length&&d.toLowerCase()||"get",data:c.serialize(),transition:c.jqmData("transition"),direction:c.jqmData("direction"),reloadPage:true}),b.preventDefault())}});a(document).bind("vclick",function(b){if(!(b.which>1)&&a.mobile.linkBindingEnabled&&(b=k(b.target))&&j.parseUrl(b.getAttribute("href")||"#").hash!=="#")d(true),q=a(b).closest(".ui-btn").not(".ui-disabled"),q.addClass(a.mobile.activeBtnClass),a("."+a.mobile.activePageClass+" .ui-btn").not(b).blur()});a(document).bind("click",function(b){if(a.mobile.linkBindingEnabled){var c=
|
||||
k(b.target);if(c&&!(b.which>1)){var f=a(c),h=function(){window.setTimeout(function(){d(true)},200)};if(f.is(":jqmData(rel='back')"))return window.history.back(),false;var g=l(f),c=j.makeUrlAbsolute(f.attr("href")||"#",g);if(!a.mobile.ajaxEnabled&&!j.isEmbeddedPage(c))h();else{if(c.search("#")!=-1)if(c=c.replace(/[^#]*#/,""))c=j.isPath(c)?j.makeUrlAbsolute(c,g):j.makeUrlAbsolute("#"+c,x.hrefNoHash);else{b.preventDefault();return}var g=f.is("[rel='external']")||f.is(":jqmData(ajax='false')")||f.is("[target]"),
|
||||
i=a.mobile.allowCrossDomainPages&&x.protocol==="file:"&&c.search(/^https?:/)!=-1;g||j.isExternal(c)&&!i?h():(h=f.jqmData("transition"),g=(g=f.jqmData("direction"))&&g==="reverse"||f.jqmData("back"),f=f.attr("data-"+a.mobile.ns+"rel")||e,a.mobile.changePage(c,{transition:h,reverse:g,role:f}),b.preventDefault())}}}});a(".ui-page").live("pageshow.prefetch",function(){var b=[];a(this).find("a:jqmData(prefetch)").each(function(){var c=a(this),f=c.attr("href");f&&a.inArray(f,b)===-1&&(b.push(f),a.mobile.loadPage(f,
|
||||
{role:c.attr("data-"+a.mobile.ns+"rel")}))})});a.mobile._handleHashChange=function(b){var c=j.stripHash(b),f={transition:a.mobile.urlHistory.stack.length===0?"none":e,changeHash:false,fromHashChange:true};if(!a.mobile.hashListeningEnabled||n.ignoreNextHashChange)n.ignoreNextHashChange=false;else{if(n.stack.length>1&&c.indexOf(s)>-1)if(a.mobile.activePage.is(".ui-dialog"))n.directHashChange({currentUrl:c,either:function(b){var d=a.mobile.urlHistory.getActive();c=d.pageUrl;a.extend(f,{role:d.role,transition:d.transition,
|
||||
reverse:b})}});else{n.directHashChange({currentUrl:c,isBack:function(){window.history.back()},isForward:function(){window.history.forward()}});return}c?(c=typeof c==="string"&&!j.isPath(c)?j.makeUrlAbsolute("#"+c,t):c,a.mobile.changePage(c,f)):a.mobile.changePage(a.mobile.firstPage,f)}};o.bind("hashchange",function(){a.mobile._handleHashChange(location.hash)});a(document).bind("pageshow",g);a(window).bind("throttledresize",g)}})(jQuery);
|
||||
(function(a,e){var b={},d=a(e),f=a.mobile.path.parseUrl(location.href);a.extend(b,{initialFilePath:f.pathname+f.search,initialHref:f.hrefNoHash,hashchangeFired:false,state:function(){return{hash:location.hash||"#"+b.initialFilePath,title:document.title,initialHref:b.initialHref}},resetUIKeys:function(b){var f="&"+a.mobile.subPageUrlKey,d=b.indexOf(a.mobile.dialogHashKey);d>-1?b=b.slice(0,d)+"#"+b.slice(d):b.indexOf(f)>-1&&(b=b.split(f).join("#"+f));return b},nextHashChangePrevented:function(c){a.mobile.urlHistory.ignoreNextHashChange=
|
||||
c;b.onHashChangeDisabled=c},onHashChange:function(){if(!b.onHashChangeDisabled){var c,f;c=location.hash;var d=a.mobile.path.isPath(c),e=d?location.href:a.mobile.getDocumentUrl();c=d?c.replace("#",""):c;f=b.state();c=a.mobile.path.makeUrlAbsolute(c,e);d&&(c=b.resetUIKeys(c));history.replaceState(f,document.title,c)}},onPopState:function(c){var f=c.originalEvent.state;f&&(b.nextHashChangePrevented(true),setTimeout(function(){b.nextHashChangePrevented(false);a.mobile._handleHashChange(f.hash)},100))},
|
||||
init:function(){d.bind("hashchange",b.onHashChange);d.bind("popstate",b.onPopState);location.hash===""&&history.replaceState(b.state(),document.title,location.href)}});a(function(){a.mobile.pushStateEnabled&&a.support.pushState&&b.init()})})(jQuery,this);
|
||||
(function(a){function e(b,d,f,c){var e=new a.Deferred,g=d?" reverse":"",i="ui-mobile-viewport-transitioning viewport-"+b;f.animationComplete(function(){f.add(c).removeClass("out in reverse "+b);c&&c[0]!==f[0]&&c.removeClass(a.mobile.activePageClass);f.parent().removeClass(i);e.resolve(b,d,f,c)});f.parent().addClass(i);c&&c.addClass(b+" out"+g);f.addClass(a.mobile.activePageClass+" "+b+" in"+g);return e.promise()}a.mobile.css3TransitionHandler=e;if(a.mobile.defaultTransitionHandler===a.mobile.noneTransitionHandler)a.mobile.defaultTransitionHandler=
|
||||
e})(jQuery,this);
|
||||
(function(a){a.mobile.page.prototype.options.degradeInputs={color:false,date:false,datetime:false,"datetime-local":false,email:false,month:false,number:false,range:"number",search:"text",tel:false,time:false,url:false,week:false};a(document).bind("pagecreate create",function(e){var b=a(e.target).closest(':jqmData(role="page")').data("page"),d;if(b)d=b.options,a(e.target).find("input").not(b.keepNativeSelector()).each(function(){var b=a(this),c=this.getAttribute("type"),e=d.degradeInputs[c]||"text";
|
||||
if(d.degradeInputs[c]){var g=a("<div>").html(b.clone()).html(),i=g.indexOf(" type=")>-1;b.replaceWith(g.replace(i?/\s+type=["']?\w+['"]?/:/\/?>/,' type="'+e+'" data-'+a.mobile.ns+'type="'+c+'"'+(i?"":">")))}})})})(jQuery);
|
||||
(function(a,e){a.widget("mobile.dialog",a.mobile.widget,{options:{closeBtnText:"Close",overlayTheme:"a",initSelector:":jqmData(role='dialog')"},_create:function(){var b=this,d=this.element,f=a("<a href='#' data-"+a.mobile.ns+"icon='delete' data-"+a.mobile.ns+"iconpos='notext'>"+this.options.closeBtnText+"</a>");d.addClass("ui-overlay-"+this.options.overlayTheme);d.attr("role","dialog").addClass("ui-dialog").find(":jqmData(role='header')").addClass("ui-corner-top ui-overlay-shadow").prepend(f).end().find(":jqmData(role='content'),:jqmData(role='footer')").addClass("ui-overlay-shadow").last().addClass("ui-corner-bottom");
|
||||
f.bind("vclick",function(){b.close()});d.bind("vclick submit",function(b){var b=a(b.target).closest(b.type==="vclick"?"a":"form"),f;b.length&&!b.jqmData("transition")&&(f=a.mobile.urlHistory.getActive()||{},b.attr("data-"+a.mobile.ns+"transition",f.transition||a.mobile.defaultDialogTransition).attr("data-"+a.mobile.ns+"direction","reverse"))}).bind("pagehide",function(){a(this).find("."+a.mobile.activeBtnClass).removeClass(a.mobile.activeBtnClass)})},close:function(){e.history.back()}});a(a.mobile.dialog.prototype.options.initSelector).live("pagecreate",
|
||||
function(){a(this).dialog()})})(jQuery,this);
|
||||
(function(a){a.mobile.page.prototype.options.backBtnText="Back";a.mobile.page.prototype.options.addBackBtn=false;a.mobile.page.prototype.options.backBtnTheme=null;a.mobile.page.prototype.options.headerTheme="a";a.mobile.page.prototype.options.footerTheme="a";a.mobile.page.prototype.options.contentTheme=null;a(":jqmData(role='page'), :jqmData(role='dialog')").live("pagecreate",function(){var e=a(this),b=e.data("page").options,d=e.jqmData("role"),f=b.theme;a(":jqmData(role='header'), :jqmData(role='footer'), :jqmData(role='content')",
|
||||
this).each(function(){var c=a(this),e=c.jqmData("role"),g=c.jqmData("theme"),i=g||b.contentTheme||d==="dialog"&&f,k;c.addClass("ui-"+e);if(e==="header"||e==="footer"){var l=g||(e==="header"?b.headerTheme:b.footerTheme)||f;c.addClass("ui-bar-"+l).attr("role",e==="header"?"banner":"contentinfo");g=c.children("a");i=g.hasClass("ui-btn-left");k=g.hasClass("ui-btn-right");i=i||g.eq(0).not(".ui-btn-right").addClass("ui-btn-left").length;k||g.eq(1).addClass("ui-btn-right");b.addBackBtn&&e==="header"&&a(".ui-page").length>
|
||||
1&&c.jqmData("url")!==a.mobile.path.stripHash(location.hash)&&!i&&a("<a href='#' class='ui-btn-left' data-"+a.mobile.ns+"rel='back' data-"+a.mobile.ns+"icon='arrow-l'>"+b.backBtnText+"</a>").attr("data-"+a.mobile.ns+"theme",b.backBtnTheme||l).prependTo(c);c.children("h1, h2, h3, h4, h5, h6").addClass("ui-title").attr({tabindex:"0",role:"heading","aria-level":"1"})}else e==="content"&&(i&&c.addClass("ui-body-"+i),c.attr("role","main"))})})})(jQuery);
|
||||
(function(a){a.widget("mobile.collapsible",a.mobile.widget,{options:{expandCueText:" click to expand contents",collapseCueText:" click to collapse contents",collapsed:true,heading:"h1,h2,h3,h4,h5,h6,legend",theme:null,contentTheme:null,iconTheme:"d",initSelector:":jqmData(role='collapsible')"},_create:function(){var e=this.element,b=this.options,d=e.addClass("ui-collapsible"),f=e.children(b.heading).first(),c=d.wrapInner("<div class='ui-collapsible-content'></div>").find(".ui-collapsible-content"),
|
||||
h=e.closest(":jqmData(role='collapsible-set')").addClass("ui-collapsible-set"),e=h.children(":jqmData(role='collapsible')");f.is("legend")&&(f=a("<div role='heading'>"+f.html()+"</div>").insertBefore(f),f.next().remove());if(h.length){if(!b.theme)b.theme=h.jqmData("theme");if(!b.contentTheme)b.contentTheme=h.jqmData("content-theme")}c.addClass(b.contentTheme?"ui-body-"+b.contentTheme:"");f.insertBefore(c).addClass("ui-collapsible-heading").append("<span class='ui-collapsible-heading-status'></span>").wrapInner("<a href='#' class='ui-collapsible-heading-toggle'></a>").find("a").first().buttonMarkup({shadow:false,
|
||||
corners:false,iconPos:"left",icon:"plus",theme:b.theme});h.length?(h.jqmData("collapsiblebound")||h.jqmData("collapsiblebound",true).bind("expand",function(b){a(b.target).closest(".ui-collapsible").siblings(".ui-collapsible").trigger("collapse")}),e.first().find("a").first().addClass("ui-corner-top").find(".ui-btn-inner").addClass("ui-corner-top"),e.last().jqmData("collapsible-last",true).find("a").first().addClass("ui-corner-bottom").find(".ui-btn-inner").addClass("ui-corner-bottom"),d.jqmData("collapsible-last")&&
|
||||
f.find("a").first().add(f.find(".ui-btn-inner")).addClass("ui-corner-bottom")):f.find("a").first().add(f.find(".ui-btn-inner")).addClass("ui-corner-top ui-corner-bottom");d.bind("expand collapse",function(e){if(!e.isDefaultPrevented()){e.preventDefault();var i=a(this),e=e.type==="collapse",k=b.contentTheme;f.toggleClass("ui-collapsible-heading-collapsed",e).find(".ui-collapsible-heading-status").text(e?b.expandCueText:b.collapseCueText).end().find(".ui-icon").toggleClass("ui-icon-minus",!e).toggleClass("ui-icon-plus",
|
||||
e);i.toggleClass("ui-collapsible-collapsed",e);c.toggleClass("ui-collapsible-content-collapsed",e).attr("aria-hidden",e);if(k&&(!h.length||d.jqmData("collapsible-last")))f.find("a").first().add(f.find(".ui-btn-inner")).toggleClass("ui-corner-bottom",e),c.toggleClass("ui-corner-bottom",!e);c.trigger("updatelayout")}}).trigger(b.collapsed?"collapse":"expand");f.bind("click",function(a){var b=f.is(".ui-collapsible-heading-collapsed")?"expand":"collapse";d.trigger(b);a.preventDefault()})}});a(document).bind("pagecreate create",
|
||||
function(e){a(a.mobile.collapsible.prototype.options.initSelector,e.target).collapsible()})})(jQuery);(function(a){a.fn.fieldcontain=function(){return this.addClass("ui-field-contain ui-body ui-br")};a(document).bind("pagecreate create",function(e){a(":jqmData(role='fieldcontain')",e.target).fieldcontain()})})(jQuery);
|
||||
(function(a){a.fn.grid=function(e){return this.each(function(){var b=a(this),d=a.extend({grid:null},e),f=b.children(),c={solo:1,a:2,b:3,c:4,d:5},d=d.grid;if(!d)if(f.length<=5)for(var h in c)c[h]===f.length&&(d=h);else d="a";c=c[d];b.addClass("ui-grid-"+d);f.filter(":nth-child("+c+"n+1)").addClass("ui-block-a");c>1&&f.filter(":nth-child("+c+"n+2)").addClass("ui-block-b");c>2&&f.filter(":nth-child(3n+3)").addClass("ui-block-c");c>3&&f.filter(":nth-child(4n+4)").addClass("ui-block-d");c>4&&f.filter(":nth-child(5n+5)").addClass("ui-block-e")})}})(jQuery);
|
||||
(function(a,e){a.widget("mobile.navbar",a.mobile.widget,{options:{iconpos:"top",grid:null,initSelector:":jqmData(role='navbar')"},_create:function(){var b=this.element,d=b.find("a"),f=d.filter(":jqmData(icon)").length?this.options.iconpos:e;b.addClass("ui-navbar").attr("role","navigation").find("ul").grid({grid:this.options.grid});f||b.addClass("ui-navbar-noicons");d.buttonMarkup({corners:false,shadow:false,iconpos:f});b.delegate("a","vclick",function(){d.not(".ui-state-persist").removeClass(a.mobile.activeBtnClass);
|
||||
a(this).addClass(a.mobile.activeBtnClass)})}});a(document).bind("pagecreate create",function(b){a(a.mobile.navbar.prototype.options.initSelector,b.target).navbar()})})(jQuery);
|
||||
(function(a){var e={};a.widget("mobile.listview",a.mobile.widget,{options:{theme:null,countTheme:"c",headerTheme:"b",dividerTheme:"b",splitIcon:"arrow-r",splitTheme:"b",inset:false,initSelector:":jqmData(role='listview')"},_create:function(){var a=this;a.element.addClass(function(d,f){return f+" ui-listview "+(a.options.inset?" ui-listview-inset ui-corner-all ui-shadow ":"")});a.refresh(true)},_removeCorners:function(a,d){a=a.add(a.find(".ui-btn-inner, .ui-li-link-alt, .ui-li-thumb"));d==="top"?a.removeClass("ui-corner-top ui-corner-tr ui-corner-tl"):
|
||||
d==="bottom"?a.removeClass("ui-corner-bottom ui-corner-br ui-corner-bl"):a.removeClass("ui-corner-top ui-corner-tr ui-corner-tl ui-corner-bottom ui-corner-br ui-corner-bl")},_refreshCorners:function(a){var d,f;this.options.inset&&(d=this.element.children("li"),f=a?d.not(".ui-screen-hidden"):d.filter(":visible"),this._removeCorners(d),d=f.first().addClass("ui-corner-top"),d.add(d.find(".ui-btn-inner").not(".ui-li-link-alt span:first-child")).addClass("ui-corner-top").end().find(".ui-li-link-alt, .ui-li-link-alt span:first-child").addClass("ui-corner-tr").end().find(".ui-li-thumb").not(".ui-li-icon").addClass("ui-corner-tl"),
|
||||
f=f.last().addClass("ui-corner-bottom"),f.add(f.find(".ui-btn-inner")).find(".ui-li-link-alt").addClass("ui-corner-br").end().find(".ui-li-thumb").not(".ui-li-icon").addClass("ui-corner-bl"));a||this.element.trigger("updatelayout")},_findFirstElementByTagName:function(a,d,f,c){var e={};for(e[f]=e[c]=true;a;){if(e[a.nodeName])return a;a=a[d]}return null},_getChildrenByTagName:function(b,d,f){var c=[],e={};e[d]=e[f]=true;for(b=b.firstChild;b;)e[b.nodeName]&&c.push(b),b=b.nextSibling;return a(c)},_addThumbClasses:function(b){var d,
|
||||
f,c=b.length;for(d=0;d<c;d++)f=a(this._findFirstElementByTagName(b[d].firstChild,"nextSibling","img","IMG")),f.length&&(f.addClass("ui-li-thumb"),a(this._findFirstElementByTagName(f[0].parentNode,"parentNode","li","LI")).addClass(f.is(".ui-li-icon")?"ui-li-has-icon":"ui-li-has-thumb"))},refresh:function(b){this.parentPage=this.element.closest(".ui-page");this._createSubPages();var d=this.options,f=this.element,c=f.jqmData("dividertheme")||d.dividerTheme,e=f.jqmData("splittheme"),g=f.jqmData("spliticon"),
|
||||
i=this._getChildrenByTagName(f[0],"li","LI"),k=a.support.cssPseudoElement||!a.nodeName(f[0],"ol")?0:1,l={},o,m,p,j,q;k&&f.find(".ui-li-dec").remove();if(!d.theme)d.theme=a.mobile.getInheritedTheme(this.element,"c");for(var n=0,A=i.length;n<A;n++){o=i.eq(n);m="ui-li";if(b||!o.hasClass("ui-li"))p=o.jqmData("theme")||d.theme,j=this._getChildrenByTagName(o[0],"a","A"),j.length?(q=o.jqmData("icon"),o.buttonMarkup({wrapperEls:"div",shadow:false,corners:false,iconpos:"right",icon:j.length>1||q===false?false:
|
||||
q||"arrow-r",theme:p}),q!=false&&j.length==1&&o.addClass("ui-li-has-arrow"),j.first().addClass("ui-link-inherit"),j.length>1&&(m+=" ui-li-has-alt",j=j.last(),q=e||j.jqmData("theme")||d.splitTheme,j.appendTo(o).attr("title",j.getEncodedText()).addClass("ui-li-link-alt").empty().buttonMarkup({shadow:false,corners:false,theme:p,icon:false,iconpos:false}).find(".ui-btn-inner").append(a(document.createElement("span")).buttonMarkup({shadow:true,corners:true,theme:q,iconpos:"notext",icon:g||j.jqmData("icon")||
|
||||
d.splitIcon})))):o.jqmData("role")==="list-divider"?(m+=" ui-li-divider ui-btn ui-bar-"+c,o.attr("role","heading"),k&&(k=1)):m+=" ui-li-static ui-body-"+p;k&&m.indexOf("ui-li-divider")<0&&(p=o.is(".ui-li-static:first")?o:o.find(".ui-link-inherit"),p.addClass("ui-li-jsnumbering").prepend("<span class='ui-li-dec'>"+k++ +". </span>"));l[m]||(l[m]=[]);l[m].push(o[0])}for(m in l)a(l[m]).addClass(m).children(".ui-btn-inner").addClass(m);f.find("h1, h2, h3, h4, h5, h6").addClass("ui-li-heading").end().find("p, dl").addClass("ui-li-desc").end().find(".ui-li-aside").each(function(){var b=
|
||||
a(this);b.prependTo(b.parent())}).end().find(".ui-li-count").each(function(){a(this).closest("li").addClass("ui-li-has-count")}).addClass("ui-btn-up-"+(f.jqmData("counttheme")||this.options.countTheme)+" ui-btn-corner-all");this._addThumbClasses(i);this._addThumbClasses(f.find(".ui-link-inherit"));this._refreshCorners(b)},_idStringEscape:function(a){return a.replace(/[^a-zA-Z0-9]/g,"-")},_createSubPages:function(){var b=this.element,d=b.closest(".ui-page"),f=d.jqmData("url"),c=f||d[0][a.expando],
|
||||
h=b.attr("id"),g=this.options,i="data-"+a.mobile.ns,k=this,l=d.find(":jqmData(role='footer')").jqmData("id"),o;typeof e[c]==="undefined"&&(e[c]=-1);h=h||++e[c];a(b.find("li>ul, li>ol").toArray().reverse()).each(function(c){var d=a(this),e=d.attr("id")||h+"-"+c,c=d.parent(),k=a(d.prevAll().toArray().reverse()),k=k.length?k:a("<span>"+a.trim(c.contents()[0].nodeValue)+"</span>"),n=k.first().getEncodedText(),e=(f||"")+"&"+a.mobile.subPageUrlKey+"="+e,A=d.jqmData("theme")||g.theme,z=d.jqmData("counttheme")||
|
||||
b.jqmData("counttheme")||g.countTheme;o=true;d.detach().wrap("<div "+i+"role='page' "+i+"url='"+e+"' "+i+"theme='"+A+"' "+i+"count-theme='"+z+"'><div "+i+"role='content'></div></div>").parent().before("<div "+i+"role='header' "+i+"theme='"+g.headerTheme+"'><div class='ui-title'>"+n+"</div></div>").after(l?a("<div "+i+"role='footer' "+i+"id='"+l+"'>"):"").parent().appendTo(a.mobile.pageContainer).page();d=c.find("a:first");d.length||(d=a("<a/>").html(k||n).prependTo(c.empty()));d.attr("href","#"+e)}).listview();
|
||||
o&&d.is(":jqmData(external-page='true')")&&d.data("page").options.domCache===false&&d.unbind("pagehide.remove").bind("pagehide.remove",function(b,c){var e=c.nextPage;c.nextPage&&(e=e.jqmData("url"),e.indexOf(f+"&"+a.mobile.subPageUrlKey)!==0&&(k.childPages().remove(),d.remove()))})},childPages:function(){var b=this.parentPage.jqmData("url");return a(":jqmData(url^='"+b+"&"+a.mobile.subPageUrlKey+"')")}});a(document).bind("pagecreate create",function(b){a(a.mobile.listview.prototype.options.initSelector,
|
||||
b.target).listview()})})(jQuery);
|
||||
(function(a){a.mobile.listview.prototype.options.filter=false;a.mobile.listview.prototype.options.filterPlaceholder="Filter items...";a.mobile.listview.prototype.options.filterTheme="c";a.mobile.listview.prototype.options.filterCallback=function(a,b){return a.toLowerCase().indexOf(b)===-1};a(":jqmData(role='listview')").live("listviewcreate",function(){var e=a(this),b=e.data("listview");if(b.options.filter){var d=a("<form>",{"class":"ui-listview-filter ui-bar-"+b.options.filterTheme,role:"search"});
|
||||
a("<input>",{placeholder:b.options.filterPlaceholder}).attr("data-"+a.mobile.ns+"type","search").jqmData("lastval","").bind("keyup change",function(){var d=a(this),c=this.value.toLowerCase(),h=null,h=d.jqmData("lastval")+"",g=false,i="";d.jqmData("lastval",c);i=c.substr(0,h.length-1).replace(h,"");h=c.length<h.length||i.length!=c.length-h.length?e.children():e.children(":not(.ui-screen-hidden)");if(c){for(var k=h.length-1;k>=0;k--)d=a(h[k]),i=d.jqmData("filtertext")||d.text(),d.is("li:jqmData(role=list-divider)")?
|
||||
(d.toggleClass("ui-filter-hidequeue",!g),g=false):b.options.filterCallback(i,c)?d.toggleClass("ui-filter-hidequeue",true):g=true;h.filter(":not(.ui-filter-hidequeue)").toggleClass("ui-screen-hidden",false);h.filter(".ui-filter-hidequeue").toggleClass("ui-screen-hidden",true).toggleClass("ui-filter-hidequeue",false)}else h.toggleClass("ui-screen-hidden",false);b._refreshCorners()}).appendTo(d).textinput();a(this).jqmData("inset")&&d.addClass("ui-listview-filter-inset");d.bind("submit",function(){return false}).insertBefore(e)}})})(jQuery);
|
||||
(function(a){a(document).bind("pagecreate create",function(e){a(":jqmData(role='nojs')",e.target).addClass("ui-nojs")})})(jQuery);
|
||||
(function(a,e){a.widget("mobile.checkboxradio",a.mobile.widget,{options:{theme:null,initSelector:"input[type='checkbox'],input[type='radio']"},_create:function(){var b=this,d=this.element,f=d.closest("form,fieldset,:jqmData(role='page')").find("label[for='"+d[0].id+"']"),c=d.attr("type"),h=c+"-on",g=c+"-off",i=d.parents(":jqmData(type='horizontal')").length?e:g;if(!(c!=="checkbox"&&c!=="radio")){a.extend(this,{label:f,inputtype:c,checkedClass:"ui-"+h+(i?"":" "+a.mobile.activeBtnClass),uncheckedClass:"ui-"+
|
||||
g,checkedicon:"ui-icon-"+h,uncheckedicon:"ui-icon-"+g});if(!this.options.theme)this.options.theme=this.element.jqmData("theme");f.buttonMarkup({theme:this.options.theme,icon:i,shadow:false});d.add(f).wrapAll("<div class='ui-"+c+"'></div>");f.bind({vmouseover:function(b){a(this).parent().is(".ui-disabled")&&b.stopPropagation()},vclick:function(a){if(d.is(":disabled"))a.preventDefault();else return b._cacheVals(),d.prop("checked",c==="radio"&&true||!d.prop("checked")),d.triggerHandler("click"),b._getInputSet().not(d).prop("checked",
|
||||
false),b._updateAll(),false}});d.bind({vmousedown:function(){b._cacheVals()},vclick:function(){var c=a(this);c.is(":checked")?(c.prop("checked",true),b._getInputSet().not(c).prop("checked",false)):c.prop("checked",false);b._updateAll()},focus:function(){f.addClass("ui-focus")},blur:function(){f.removeClass("ui-focus")}});this.refresh()}},_cacheVals:function(){this._getInputSet().each(function(){var b=a(this);b.jqmData("cacheVal",b.is(":checked"))})},_getInputSet:function(){return this.inputtype==
|
||||
"checkbox"?this.element:this.element.closest("form,fieldset,:jqmData(role='page')").find("input[name='"+this.element.attr("name")+"'][type='"+this.inputtype+"']")},_updateAll:function(){var b=this;this._getInputSet().each(function(){var d=a(this);(d.is(":checked")||b.inputtype==="checkbox")&&d.trigger("change")}).checkboxradio("refresh")},refresh:function(){var b=this.element,d=this.label,f=d.find(".ui-icon");a(b[0]).prop("checked")?(d.addClass(this.checkedClass).removeClass(this.uncheckedClass),
|
||||
f.addClass(this.checkedicon).removeClass(this.uncheckedicon)):(d.removeClass(this.checkedClass).addClass(this.uncheckedClass),f.removeClass(this.checkedicon).addClass(this.uncheckedicon));b.is(":disabled")?this.disable():this.enable()},disable:function(){this.element.prop("disabled",true).parent().addClass("ui-disabled")},enable:function(){this.element.prop("disabled",false).parent().removeClass("ui-disabled")}});a(document).bind("pagecreate create",function(b){a.mobile.checkboxradio.prototype.enhanceWithin(b.target)})})(jQuery);
|
||||
(function(a,e){a.widget("mobile.button",a.mobile.widget,{options:{theme:null,icon:null,iconpos:null,inline:null,corners:true,shadow:true,iconshadow:true,initSelector:"button, [type='button'], [type='submit'], [type='reset'], [type='image']"},_create:function(){var b=this.element,d=this.options,f,c;this.button=a("<div></div>").text(b.text()||b.val()).insertBefore(b).buttonMarkup({theme:d.theme,icon:d.icon,iconpos:d.iconpos,inline:d.inline,corners:d.corners,shadow:d.shadow,iconshadow:d.iconshadow}).append(b.addClass("ui-btn-hidden"));
|
||||
d=b.attr("type");f=b.attr("name");d!=="button"&&d!=="reset"&&f&&b.bind("vclick",function(){c===e&&(c=a("<input>",{type:"hidden",name:b.attr("name"),value:b.attr("value")}).insertBefore(b),a(document).one("submit",function(){c.remove();c=e}))});this.refresh()},enable:function(){this.element.attr("disabled",false);this.button.removeClass("ui-disabled").attr("aria-disabled",false);return this._setOption("disabled",false)},disable:function(){this.element.attr("disabled",true);this.button.addClass("ui-disabled").attr("aria-disabled",
|
||||
true);return this._setOption("disabled",true)},refresh:function(){var a=this.element;a.prop("disabled")?this.disable():this.enable();this.button.data("textWrapper").text(a.text()||a.val())}});a(document).bind("pagecreate create",function(b){a.mobile.button.prototype.enhanceWithin(b.target)})})(jQuery);
|
||||
(function(a,e){a.widget("mobile.slider",a.mobile.widget,{options:{theme:null,trackTheme:null,disabled:false,initSelector:"input[type='range'], :jqmData(type='range'), :jqmData(role='slider')"},_create:function(){var b=this,d=this.element,f=a.mobile.getInheritedTheme(d,"c"),c=this.options.theme||f,h=this.options.trackTheme||f,g=d[0].nodeName.toLowerCase(),f=g=="select"?"ui-slider-switch":"",i=d.attr("id"),k=i+"-label",i=a("[for='"+i+"']").attr("id",k),l=function(){return g=="input"?parseFloat(d.val()):
|
||||
d[0].selectedIndex},o=g=="input"?parseFloat(d.attr("min")):0,m=g=="input"?parseFloat(d.attr("max")):d.find("option").length-1,p=window.parseFloat(d.attr("step")||1),j=a("<div class='ui-slider "+f+" ui-btn-down-"+h+" ui-btn-corner-all' role='application'></div>"),q=a("<a href='#' class='ui-slider-handle'></a>").appendTo(j).buttonMarkup({corners:true,theme:c,shadow:true}).attr({role:"slider","aria-valuemin":o,"aria-valuemax":m,"aria-valuenow":l(),"aria-valuetext":l(),title:l(),"aria-labelledby":k});
|
||||
a.extend(this,{slider:j,handle:q,dragging:false,beforeStart:null,userModified:false,mouseMoved:false});g=="select"&&(j.wrapInner("<div class='ui-slider-inneroffset'></div>"),q.addClass("ui-slider-handle-snapping"),d.find("option"),d.find("option").each(function(b){var c=!b?"b":"a",d=!b?"right":"left",b=!b?" ui-btn-down-"+h:" "+a.mobile.activeBtnClass;a("<div class='ui-slider-labelbg ui-slider-labelbg-"+c+b+" ui-btn-corner-"+d+"'></div>").prependTo(j);a("<span class='ui-slider-label ui-slider-label-"+
|
||||
c+b+" ui-btn-corner-"+d+"' role='img'>"+a(this).getEncodedText()+"</span>").prependTo(q)}));i.addClass("ui-slider");d.addClass(g==="input"?"ui-slider-input":"ui-slider-switch").change(function(){b.mouseMoved||b.refresh(l(),true)}).keyup(function(){b.refresh(l(),true,true)}).blur(function(){b.refresh(l(),true)});a(document).bind("vmousemove",function(a){if(b.dragging)return b.mouseMoved=true,g==="select"&&q.removeClass("ui-slider-handle-snapping"),b.refresh(a),b.userModified=b.beforeStart!==d[0].selectedIndex,
|
||||
false});j.bind("vmousedown",function(a){b.dragging=true;b.userModified=false;b.mouseMoved=false;if(g==="select")b.beforeStart=d[0].selectedIndex;b.refresh(a);return false});j.add(document).bind("vmouseup",function(){if(b.dragging)return b.dragging=false,g==="select"&&(q.addClass("ui-slider-handle-snapping"),b.mouseMoved?b.userModified?b.refresh(b.beforeStart==0?1:0):b.refresh(b.beforeStart):b.refresh(b.beforeStart==0?1:0)),b.mouseMoved=false});j.insertAfter(d);this.handle.bind("vmousedown",function(){a(this).focus()}).bind("vclick",
|
||||
false);this.handle.bind("keydown",function(c){var d=l();if(!b.options.disabled){switch(c.keyCode){case a.mobile.keyCode.HOME:case a.mobile.keyCode.END:case a.mobile.keyCode.PAGE_UP:case a.mobile.keyCode.PAGE_DOWN:case a.mobile.keyCode.UP:case a.mobile.keyCode.RIGHT:case a.mobile.keyCode.DOWN:case a.mobile.keyCode.LEFT:if(c.preventDefault(),!b._keySliding)b._keySliding=true,a(this).addClass("ui-state-active")}switch(c.keyCode){case a.mobile.keyCode.HOME:b.refresh(o);break;case a.mobile.keyCode.END:b.refresh(m);
|
||||
break;case a.mobile.keyCode.PAGE_UP:case a.mobile.keyCode.UP:case a.mobile.keyCode.RIGHT:b.refresh(d+p);break;case a.mobile.keyCode.PAGE_DOWN:case a.mobile.keyCode.DOWN:case a.mobile.keyCode.LEFT:b.refresh(d-p)}}}).keyup(function(){if(b._keySliding)b._keySliding=false,a(this).removeClass("ui-state-active")});this.refresh(e,e,true)},refresh:function(a,d,f){(this.options.disabled||this.element.attr("disabled"))&&this.disable();var c=this.element,e,g=c[0].nodeName.toLowerCase(),i=g==="input"?parseFloat(c.attr("min")):
|
||||
0,k=g==="input"?parseFloat(c.attr("max")):c.find("option").length-1;if(typeof a==="object"){if(!this.dragging||a.pageX<this.slider.offset().left-8||a.pageX>this.slider.offset().left+this.slider.width()+8)return;e=Math.round((a.pageX-this.slider.offset().left)/this.slider.width()*100)}else a==null&&(a=g==="input"?parseFloat(c.val()):c[0].selectedIndex),e=(parseFloat(a)-i)/(k-i)*100;if(!isNaN(e)&&(e<0&&(e=0),e>100&&(e=100),a=Math.round(e/100*(k-i))+i,a<i&&(a=i),a>k&&(a=k),this.handle.css("left",e+"%"),
|
||||
this.handle.attr({"aria-valuenow":g==="input"?a:c.find("option").eq(a).attr("value"),"aria-valuetext":g==="input"?a:c.find("option").eq(a).getEncodedText(),title:a}),g==="select"&&(a===0?this.slider.addClass("ui-slider-switch-a").removeClass("ui-slider-switch-b"):this.slider.addClass("ui-slider-switch-b").removeClass("ui-slider-switch-a")),!f))f=false,g==="input"?(f=c.val()!==a,c.val(a)):(f=c[0].selectedIndex!==a,c[0].selectedIndex=a),!d&&f&&c.trigger("change")},enable:function(){this.element.attr("disabled",
|
||||
false);this.slider.removeClass("ui-disabled").attr("aria-disabled",false);return this._setOption("disabled",false)},disable:function(){this.element.attr("disabled",true);this.slider.addClass("ui-disabled").attr("aria-disabled",true);return this._setOption("disabled",true)}});a(document).bind("pagecreate create",function(b){a.mobile.slider.prototype.enhanceWithin(b.target)})})(jQuery);
|
||||
(function(a){a.widget("mobile.textinput",a.mobile.widget,{options:{theme:null,initSelector:"input[type='text'], input[type='search'], :jqmData(type='search'), input[type='number'], :jqmData(type='number'), input[type='password'], input[type='email'], input[type='url'], input[type='tel'], textarea, input[type='time'], input[type='date'], input[type='month'], input[type='week'], input[type='datetime'], input[type='datetime-local'], input[type='color'], input:not([type])"},_create:function(){var e=this.element,
|
||||
b=this.options.theme||a.mobile.getInheritedTheme(this.element,"c"),d=" ui-body-"+b,f,c;a("label[for='"+e.attr("id")+"']").addClass("ui-input-text");f=e.addClass("ui-input-text ui-body-"+b);typeof e[0].autocorrect!=="undefined"&&!a.support.touchOverflow&&(e[0].setAttribute("autocorrect","off"),e[0].setAttribute("autocomplete","off"));e.is("[type='search'],:jqmData(type='search')")?(f=e.wrap("<div class='ui-input-search ui-shadow-inset ui-btn-corner-all ui-btn-shadow ui-icon-searchfield"+d+"'></div>").parent(),
|
||||
c=a("<a href='#' class='ui-input-clear' title='clear text'>clear text</a>").tap(function(a){e.val("").focus();e.trigger("change");c.addClass("ui-input-clear-hidden");a.preventDefault()}).appendTo(f).buttonMarkup({icon:"delete",iconpos:"notext",corners:true,shadow:true}),b=function(){setTimeout(function(){c.toggleClass("ui-input-clear-hidden",!e.val())},0)},b(),e.bind("paste cut keyup focus change blur",b)):e.addClass("ui-corner-all ui-shadow-inset"+d);e.focus(function(){f.addClass("ui-focus")}).blur(function(){f.removeClass("ui-focus")});
|
||||
if(e.is("textarea")){var h=function(){var a=e[0].scrollHeight;e[0].clientHeight<a&&e.height(a+15)},g;e.keyup(function(){clearTimeout(g);g=setTimeout(h,100)});a.trim(e.val())&&(a(window).load(h),a(document).one("pagechange",h))}},disable:function(){(this.element.attr("disabled",true).is("[type='search'],:jqmData(type='search')")?this.element.parent():this.element).addClass("ui-disabled")},enable:function(){(this.element.attr("disabled",false).is("[type='search'],:jqmData(type='search')")?this.element.parent():
|
||||
this.element).removeClass("ui-disabled")}});a(document).bind("pagecreate create",function(e){a.mobile.textinput.prototype.enhanceWithin(e.target)})})(jQuery);
|
||||
(function(a){var e=function(b){var d=b.selectID,f=b.label,c=b.select.closest(".ui-page"),e=a("<div>",{"class":"ui-selectmenu-screen ui-screen-hidden"}).appendTo(c),g=b._selectOptions(),i=b.isMultiple=b.select[0].multiple,k=d+"-button",l=d+"-menu",o=a("<div data-"+a.mobile.ns+"role='dialog' data-"+a.mobile.ns+"theme='"+b.options.theme+"' data-"+a.mobile.ns+"overlay-theme='"+b.options.overlayTheme+"'><div data-"+a.mobile.ns+"role='header'><div class='ui-title'>"+f.getEncodedText()+"</div></div><div data-"+
|
||||
a.mobile.ns+"role='content'></div></div>").appendTo(a.mobile.pageContainer).page(),m=a("<div>",{"class":"ui-selectmenu ui-selectmenu-hidden ui-overlay-shadow ui-corner-all ui-body-"+b.options.overlayTheme+" "+a.mobile.defaultDialogTransition}).insertAfter(e),p=a("<ul>",{"class":"ui-selectmenu-list",id:l,role:"listbox","aria-labelledby":k}).attr("data-"+a.mobile.ns+"theme",b.options.theme).appendTo(m),j=a("<div>",{"class":"ui-header ui-bar-"+b.options.theme}).prependTo(m),q=a("<h1>",{"class":"ui-title"}).appendTo(j),
|
||||
n=a("<a>",{text:b.options.closeText,href:"#","class":"ui-btn-left"}).attr("data-"+a.mobile.ns+"iconpos","notext").attr("data-"+a.mobile.ns+"icon","delete").appendTo(j).buttonMarkup(),A=o.find(".ui-content"),z=o.find(".ui-header a");a.extend(b,{select:b.select,selectID:d,buttonId:k,menuId:l,thisPage:c,menuPage:o,label:f,screen:e,selectOptions:g,isMultiple:i,theme:b.options.theme,listbox:m,list:p,header:j,headerTitle:q,headerClose:n,menuPageContent:A,menuPageClose:z,placeholder:"",build:function(){var b=
|
||||
this;b.refresh();b.select.attr("tabindex","-1").focus(function(){a(this).blur();b.button.focus()});b.button.bind("vclick keydown",function(c){if(c.type=="vclick"||c.keyCode&&(c.keyCode===a.mobile.keyCode.ENTER||c.keyCode===a.mobile.keyCode.SPACE))b.open(),c.preventDefault()});b.list.attr("role","listbox").delegate(".ui-li>a","focusin",function(){a(this).attr("tabindex","0")}).delegate(".ui-li>a","focusout",function(){a(this).attr("tabindex","-1")}).delegate("li:not(.ui-disabled, .ui-li-divider)",
|
||||
"click",function(c){var d=b.select[0].selectedIndex,f=b.list.find("li:not(.ui-li-divider)").index(this),e=b._selectOptions().eq(f)[0];e.selected=b.isMultiple?!e.selected:true;b.isMultiple&&a(this).find(".ui-icon").toggleClass("ui-icon-checkbox-on",e.selected).toggleClass("ui-icon-checkbox-off",!e.selected);(b.isMultiple||d!==f)&&b.select.trigger("change");b.isMultiple||b.close();c.preventDefault()}).keydown(function(b){var c=a(b.target),d=c.closest("li");switch(b.keyCode){case 38:return b=d.prev(),
|
||||
b.length&&(c.blur().attr("tabindex","-1"),b.find("a").first().focus()),false;case 40:return b=d.next(),b.length&&(c.blur().attr("tabindex","-1"),b.find("a").first().focus()),false;case 13:case 32:return c.trigger("click"),false}});b.menuPage.bind("pagehide",function(){b.list.appendTo(b.listbox);b._focusButton();a.mobile._bindPageRemove.call(b.thisPage)});b.screen.bind("vclick",function(){b.close()});b.headerClose.click(function(){if(b.menuType=="overlay")return b.close(),false});b.thisPage.addDependents(this.menuPage)},
|
||||
_isRebuildRequired:function(){var a=this.list.find("li");return this._selectOptions().text()!==a.text()},refresh:function(b){var c=this;this._selectOptions();this.selected();var d=this.selectedIndices();(b||this._isRebuildRequired())&&c._buildList();c.setButtonText();c.setButtonCount();c.list.find("li:not(.ui-li-divider)").removeClass(a.mobile.activeBtnClass).attr("aria-selected",false).each(function(b){a.inArray(b,d)>-1&&(b=a(this),b.attr("aria-selected",true),c.isMultiple?b.find(".ui-icon").removeClass("ui-icon-checkbox-off").addClass("ui-icon-checkbox-on"):
|
||||
b.addClass(a.mobile.activeBtnClass))})},close:function(){if(!this.options.disabled&&this.isOpen)this.menuType=="page"?window.history.back():(this.screen.addClass("ui-screen-hidden"),this.listbox.addClass("ui-selectmenu-hidden").removeAttr("style").removeClass("in"),this.list.appendTo(this.listbox),this._focusButton()),this.isOpen=false},open:function(){if(!this.options.disabled){var b=this,c=b.list.parent().outerHeight(),d=b.list.parent().outerWidth(),f=a(".ui-page-active"),e=a.support.touchOverflow&&
|
||||
a.mobile.touchOverflowEnabled,f=f.is(".ui-native-fixed")?f.find(".ui-content"):f;scrollTop=e?f.scrollTop():a(window).scrollTop();btnOffset=b.button.offset().top;screenHeight=window.innerHeight;screenWidth=window.innerWidth;b.button.addClass(a.mobile.activeBtnClass);setTimeout(function(){b.button.removeClass(a.mobile.activeBtnClass)},300);if(c>screenHeight-80||!a.support.scrollTop){b.thisPage.unbind("pagehide.remove");if(scrollTop==0&&btnOffset>screenHeight)b.thisPage.one("pagehide",function(){a(this).jqmData("lastScroll",
|
||||
btnOffset)});b.menuPage.one("pageshow",function(){a(window).one("silentscroll",function(){b.list.find(a.mobile.activeBtnClass).focus()});b.isOpen=true});b.menuType="page";b.menuPageContent.append(b.list);b.menuPage.find("div .ui-title").text(b.label.text());a.mobile.changePage(b.menuPage,{transition:a.mobile.defaultDialogTransition})}else{b.menuType="overlay";b.screen.height(a(document).height()).removeClass("ui-screen-hidden");var f=btnOffset-scrollTop,h=scrollTop+screenHeight-btnOffset,g=c/2,e=
|
||||
parseFloat(b.list.parent().css("max-width")),c=f>c/2&&h>c/2?btnOffset+b.button.outerHeight()/2-g:f>h?scrollTop+screenHeight-c-30:scrollTop+30;d<e?e=(screenWidth-d)/2:(e=b.button.offset().left+b.button.outerWidth()/2-d/2,e<30?e=30:e+d>screenWidth&&(e=screenWidth-d-30));b.listbox.append(b.list).removeClass("ui-selectmenu-hidden").css({top:c,left:e}).addClass("in");b.list.find(a.mobile.activeBtnClass).focus();b.isOpen=true}}},_buildList:function(){var b=this,c=this.options,d=this.placeholder,f=[],e=
|
||||
[],h=b.isMultiple?"checkbox-off":"false";b.list.empty().filter(".ui-listview").listview("destroy");b.select.find("option").each(function(g){var j=a(this),i=j.parent(),m=j.getEncodedText(),p="<a href='#'>"+m+"</a>",k=[],n=[];i.is("optgroup")&&(i=i.attr("label"),a.inArray(i,f)===-1&&(e.push("<li data-"+a.mobile.ns+"role='list-divider'>"+i+"</li>"),f.push(i)));if(!this.getAttribute("value")||m.length==0||j.jqmData("placeholder"))c.hidePlaceholderMenuItems&&k.push("ui-selectmenu-placeholder"),d=b.placeholder=
|
||||
m;this.disabled&&(k.push("ui-disabled"),n.push("aria-disabled='true'"));e.push("<li data-"+a.mobile.ns+"option-index='"+g+"' data-"+a.mobile.ns+"icon='"+h+"' class='"+k.join(" ")+"' "+n.join(" ")+">"+p+"</li>")});b.list.html(e.join(" "));b.list.find("li").attr({role:"option",tabindex:"-1"}).first().attr("tabindex","0");this.isMultiple||this.headerClose.hide();!this.isMultiple&&!d.length?this.header.hide():this.headerTitle.text(this.placeholder);b.list.listview()},_button:function(){return a("<a>",
|
||||
{href:"#",role:"button",id:this.buttonId,"aria-haspopup":"true","aria-owns":this.menuId})}})};a("select").live("selectmenubeforecreate",function(){var b=a(this).data("selectmenu");b.options.nativeMenu||e(b)})})(jQuery);
|
||||
(function(a){a.widget("mobile.selectmenu",a.mobile.widget,{options:{theme:null,disabled:false,icon:"arrow-d",iconpos:"right",inline:null,corners:true,shadow:true,iconshadow:true,menuPageTheme:"b",overlayTheme:"a",hidePlaceholderMenuItems:true,closeText:"Close",nativeMenu:true,initSelector:"select:not(:jqmData(role='slider'))"},_button:function(){return a("<div/>")},_setDisabled:function(a){this.element.attr("disabled",a);this.button.attr("aria-disabled",a);return this._setOption("disabled",a)},_focusButton:function(){var a=
|
||||
this;setTimeout(function(){a.button.focus()},40)},_selectOptions:function(){return this.select.find("option")},_preExtension:function(){this.select=this.element.wrap("<div class='ui-select'>");this.selectID=this.select.attr("id");this.label=a("label[for='"+this.selectID+"']").addClass("ui-select");this.isMultiple=this.select[0].multiple;if(!this.options.theme)this.options.theme=a.mobile.getInheritedTheme(this.select,"c")},_create:function(){this._preExtension();this._trigger("beforeCreate");this.button=
|
||||
this._button();var e=this,b=this.options,d=this.button.text(a(this.select[0].options.item(this.select[0].selectedIndex==-1?0:this.select[0].selectedIndex)).text()).insertBefore(this.select).buttonMarkup({theme:b.theme,icon:b.icon,iconpos:b.iconpos,inline:b.inline,corners:b.corners,shadow:b.shadow,iconshadow:b.iconshadow});b.nativeMenu&&window.opera&&window.opera.version&&this.select.addClass("ui-select-nativeonly");if(this.isMultiple)this.buttonCount=a("<span>").addClass("ui-li-count ui-btn-up-c ui-btn-corner-all").hide().appendTo(d.addClass("ui-li-has-count"));
|
||||
(b.disabled||this.element.attr("disabled"))&&this.disable();this.select.change(function(){e.refresh()});this.build()},build:function(){var e=this;this.select.appendTo(e.button).bind("vmousedown",function(){e.button.addClass(a.mobile.activeBtnClass)}).bind("focus vmouseover",function(){e.button.trigger("vmouseover")}).bind("vmousemove",function(){e.button.removeClass(a.mobile.activeBtnClass)}).bind("change blur vmouseout",function(){e.button.trigger("vmouseout").removeClass(a.mobile.activeBtnClass)}).bind("change blur",
|
||||
function(){e.button.removeClass("ui-btn-down-"+e.options.theme)})},selected:function(){return this._selectOptions().filter(":selected")},selectedIndices:function(){var a=this;return this.selected().map(function(){return a._selectOptions().index(this)}).get()},setButtonText:function(){var e=this,b=this.selected();this.button.find(".ui-btn-text").text(function(){return!e.isMultiple?b.text():b.length?b.map(function(){return a(this).text()}).get().join(", "):e.placeholder})},setButtonCount:function(){var a=
|
||||
this.selected();this.isMultiple&&this.buttonCount[a.length>1?"show":"hide"]().text(a.length)},refresh:function(){this.setButtonText();this.setButtonCount()},open:a.noop,close:a.noop,disable:function(){this._setDisabled(true);this.button.addClass("ui-disabled")},enable:function(){this._setDisabled(false);this.button.removeClass("ui-disabled")}});a(document).bind("pagecreate create",function(e){a.mobile.selectmenu.prototype.enhanceWithin(e.target)})})(jQuery);
|
||||
(function(a,e){function b(b){for(var c;b;){if((c=typeof b.className==="string"&&b.className.split(" "))&&a.inArray("ui-btn",c)>-1&&a.inArray("ui-disabled",c)<0)break;b=b.parentNode}return b}a.fn.buttonMarkup=function(b){for(var b=b||{},c=0;c<this.length;c++){var h=this.eq(c),g=h[0],i=a.extend({},a.fn.buttonMarkup.defaults,{icon:b.icon!==e?b.icon:h.jqmData("icon"),iconpos:b.iconpos!==e?b.iconpos:h.jqmData("iconpos"),theme:b.theme!==e?b.theme:h.jqmData("theme"),inline:b.inline!==e?b.inline:h.jqmData("inline"),
|
||||
shadow:b.shadow!==e?b.shadow:h.jqmData("shadow"),corners:b.corners!==e?b.corners:h.jqmData("corners"),iconshadow:b.iconshadow!==e?b.iconshadow:h.jqmData("iconshadow")},b),k="ui-btn-inner",l,o,m=document.createElement(i.wrapperEls),p=document.createElement(i.wrapperEls),j=i.icon?document.createElement("span"):null;d&&d();if(!i.theme)i.theme=a.mobile.getInheritedTheme(h,"c");l="ui-btn ui-btn-up-"+i.theme;i.inline&&(l+=" ui-btn-inline");if(i.icon)i.icon="ui-icon-"+i.icon,i.iconpos=i.iconpos||"left",
|
||||
o="ui-icon "+i.icon,i.iconshadow&&(o+=" ui-icon-shadow");i.iconpos&&(l+=" ui-btn-icon-"+i.iconpos,i.iconpos=="notext"&&!h.attr("title")&&h.attr("title",h.getEncodedText()));i.corners&&(l+=" ui-btn-corner-all",k+=" ui-btn-corner-all");i.shadow&&(l+=" ui-shadow");g.setAttribute("data-"+a.mobile.ns+"theme",i.theme);h.addClass(l);m.className=k;m.setAttribute("aria-hidden","true");p.className="ui-btn-text";m.appendChild(p);if(j)j.className=o,m.appendChild(j);for(;g.firstChild;)p.appendChild(g.firstChild);
|
||||
g.appendChild(m);a.data(g,"textWrapper",a(p))}return this};a.fn.buttonMarkup.defaults={corners:true,shadow:true,iconshadow:true,inline:false,wrapperEls:"span"};var d=function(){a(document).bind({vmousedown:function(d){var d=b(d.target),c;d&&(d=a(d),c=d.attr("data-"+a.mobile.ns+"theme"),d.removeClass("ui-btn-up-"+c).addClass("ui-btn-down-"+c))},"vmousecancel vmouseup":function(d){var d=b(d.target),c;d&&(d=a(d),c=d.attr("data-"+a.mobile.ns+"theme"),d.removeClass("ui-btn-down-"+c).addClass("ui-btn-up-"+
|
||||
c))},"vmouseover focus":function(d){var d=b(d.target),c;d&&(d=a(d),c=d.attr("data-"+a.mobile.ns+"theme"),d.removeClass("ui-btn-up-"+c).addClass("ui-btn-hover-"+c))},"vmouseout blur":function(d){var d=b(d.target),c;d&&(d=a(d),c=d.attr("data-"+a.mobile.ns+"theme"),d.removeClass("ui-btn-hover-"+c+" ui-btn-down-"+c).addClass("ui-btn-up-"+c))}});d=null};a(document).bind("pagecreate create",function(b){a(":jqmData(role='button'), .ui-bar > a, .ui-header > a, .ui-footer > a, .ui-bar > :jqmData(role='controlgroup') > a",
|
||||
b.target).not(".ui-btn, :jqmData(role='none'), :jqmData(role='nojs')").buttonMarkup()})})(jQuery);
|
||||
(function(a){a.fn.controlgroup=function(e){return this.each(function(){function b(a){a.removeClass("ui-btn-corner-all ui-shadow").eq(0).addClass(h[0]).end().last().addClass(h[1]).addClass("ui-controlgroup-last")}var d=a(this),f=a.extend({direction:d.jqmData("type")||"vertical",shadow:false,excludeInvisible:true},e),c=d.children("legend"),h=f.direction=="horizontal"?["ui-corner-left","ui-corner-right"]:["ui-corner-top","ui-corner-bottom"];d.find("input").first().attr("type");c.length&&(d.wrapInner("<div class='ui-controlgroup-controls'></div>"),
|
||||
a("<div role='heading' class='ui-controlgroup-label'>"+c.html()+"</div>").insertBefore(d.children(0)),c.remove());d.addClass("ui-corner-all ui-controlgroup ui-controlgroup-"+f.direction);b(d.find(".ui-btn"+(f.excludeInvisible?":visible":"")));b(d.find(".ui-btn-inner"));f.shadow&&d.addClass("ui-shadow")})};a(document).bind("pagecreate create",function(e){a(":jqmData(role='controlgroup')",e.target).controlgroup({excludeInvisible:false})})})(jQuery);
|
||||
(function(a){a(document).bind("pagecreate create",function(e){a(e.target).find("a").not(".ui-btn, .ui-link-inherit, :jqmData(role='none'), :jqmData(role='nojs')").addClass("ui-link")})})(jQuery);
|
||||
(function(a,e){a.fn.fixHeaderFooter=function(){return!a.support.scrollTop||a.support.touchOverflow&&a.mobile.touchOverflowEnabled?this:this.each(function(){var b=a(this);b.jqmData("fullscreen")&&b.addClass("ui-page-fullscreen");b.find(".ui-header:jqmData(position='fixed')").addClass("ui-header-fixed ui-fixed-inline fade");b.find(".ui-footer:jqmData(position='fixed')").addClass("ui-footer-fixed ui-fixed-inline fade")})};a.mobile.fixedToolbars=function(){function b(){!i&&g==="overlay"&&(h||a.mobile.fixedToolbars.hide(true),
|
||||
a.mobile.fixedToolbars.startShowTimer())}function d(a){var b=0,c,d;if(a){d=document.body;c=a.offsetParent;for(b=a.offsetTop;a&&a!=d;){b+=a.scrollTop||0;if(a==c)b+=c.offsetTop,c=a.offsetParent;a=a.parentNode}}return b}function f(b){var c=a(window).scrollTop(),e=d(b[0]),f=b.css("top")=="auto"?0:parseFloat(b.css("top")),h=window.innerHeight,g=b.outerHeight(),i=b.parents(".ui-page:not(.ui-page-fullscreen)").length;return b.is(".ui-header-fixed")?(f=c-e+f,f<e&&(f=0),b.css("top",i?f:c)):b.css("top",i?c+
|
||||
h-g-(e-f):c+h-g)}if(a.support.scrollTop&&(!a.support.touchOverflow||!a.mobile.touchOverflowEnabled)){var c,h,g="inline",i=false,k=null,l=false,o=true;a(function(){var c=a(document),d=a(window);c.bind("vmousedown",function(){o&&(k=g)}).bind("vclick",function(b){o&&!a(b.target).closest("a,input,textarea,select,button,label,.ui-header-fixed,.ui-footer-fixed").length&&!l&&(a.mobile.fixedToolbars.toggle(k),k=null)}).bind("silentscroll",b);(c.scrollTop()===0?d:c).bind("scrollstart",function(){l=true;k===
|
||||
null&&(k=g);var b=k=="overlay";if(i=b||!!h)a.mobile.fixedToolbars.clearShowTimer(),b&&a.mobile.fixedToolbars.hide(true)}).bind("scrollstop",function(b){a(b.target).closest("a,input,textarea,select,button,label,.ui-header-fixed,.ui-footer-fixed").length||(l=false,i&&(a.mobile.fixedToolbars.startShowTimer(),i=false),k=null)});d.bind("resize updatelayout",b)});a(".ui-page").live("pagebeforeshow",function(b,d){var e=a(b.target).find(":jqmData(role='footer')"),h=e.data("id"),g=d.prevPage,g=g&&g.find(":jqmData(role='footer')"),
|
||||
g=g.length&&g.jqmData("id")===h;h&&g&&(c=e,f(c.removeClass("fade in out").appendTo(a.mobile.pageContainer)))}).live("pageshow",function(){var b=a(this);c&&c.length&&setTimeout(function(){f(c.appendTo(b).addClass("fade"));c=null},500);a.mobile.fixedToolbars.show(true,this)});a(".ui-collapsible-contain").live("collapse expand",b);return{show:function(b,c){a.mobile.fixedToolbars.clearShowTimer();g="overlay";return(c?a(c):a.mobile.activePage?a.mobile.activePage:a(".ui-page-active")).children(".ui-header-fixed:first, .ui-footer-fixed:not(.ui-footer-duplicate):last").each(function(){var c=
|
||||
a(this),e=a(window).scrollTop(),h=d(c[0]),g=window.innerHeight,i=c.outerHeight(),e=c.is(".ui-header-fixed")&&e<=h+i||c.is(".ui-footer-fixed")&&h<=e+g;c.addClass("ui-fixed-overlay").removeClass("ui-fixed-inline");!e&&!b&&c.animationComplete(function(){c.removeClass("in")}).addClass("in");f(c)})},hide:function(b){g="inline";return(a.mobile.activePage?a.mobile.activePage:a(".ui-page-active")).children(".ui-header-fixed:first, .ui-footer-fixed:not(.ui-footer-duplicate):last").each(function(){var c=a(this),
|
||||
d=c.css("top"),d=d=="auto"?0:parseFloat(d);c.addClass("ui-fixed-inline").removeClass("ui-fixed-overlay");if(d<0||c.is(".ui-header-fixed")&&d!==0)b?c.css("top",0):c.css("top")!=="auto"&&parseFloat(c.css("top"))!==0&&c.animationComplete(function(){c.removeClass("out reverse").css("top",0)}).addClass("out reverse")})},startShowTimer:function(){a.mobile.fixedToolbars.clearShowTimer();var b=[].slice.call(arguments);h=setTimeout(function(){h=e;a.mobile.fixedToolbars.show.apply(null,b)},100)},clearShowTimer:function(){h&&
|
||||
clearTimeout(h);h=e},toggle:function(b){b&&(g=b);return g==="overlay"?a.mobile.fixedToolbars.hide():a.mobile.fixedToolbars.show()},setTouchToggleEnabled:function(a){o=a}}}}();a(document).bind("pagecreate create",function(b){a(":jqmData(position='fixed')",b.target).length&&a(b.target).each(function(){if(!a.support.scrollTop||a.support.touchOverflow&&a.mobile.touchOverflowEnabled)return this;var b=a(this);b.jqmData("fullscreen")&&b.addClass("ui-page-fullscreen");b.find(".ui-header:jqmData(position='fixed')").addClass("ui-header-fixed ui-fixed-inline fade");
|
||||
b.find(".ui-footer:jqmData(position='fixed')").addClass("ui-footer-fixed ui-fixed-inline fade")})})})(jQuery);
|
||||
(function(a){a.mobile.touchOverflowEnabled=false;a.mobile.touchOverflowZoomEnabled=false;a(document).bind("pagecreate",function(e){a.support.touchOverflow&&a.mobile.touchOverflowEnabled&&(e=a(e.target),e.is(":jqmData(role='page')")&&e.each(function(){var b=a(this),d=b.find(":jqmData(role='header'), :jqmData(role='footer')").filter(":jqmData(position='fixed')"),e=b.jqmData("fullscreen"),c=d.length?b.find(".ui-content"):b;b.addClass("ui-mobile-touch-overflow");c.bind("scrollstop",function(){c.scrollTop()>
|
||||
0&&window.scrollTo(0,a.mobile.defaultHomeScroll)});d.length&&(b.addClass("ui-native-fixed"),e&&(b.addClass("ui-native-fullscreen"),d.addClass("fade in"),a(document).bind("vclick",function(){d.removeClass("ui-native-bars-hidden").toggleClass("in out").animationComplete(function(){a(this).not(".in").addClass("ui-native-bars-hidden")})})))}))})})(jQuery);
|
||||
(function(a,e){function b(){var b=a("meta[name='viewport']");b.length?b.attr("content",b.attr("content")+", user-scalable=no"):a("head").prepend("<meta>",{name:"viewport",content:"user-scalable=no"})}var d=a("html");a("head");var f=a(e);a(e.document).trigger("mobileinit");if(a.mobile.gradeA()){if(a.mobile.ajaxBlacklist)a.mobile.ajaxEnabled=false;d.addClass("ui-mobile ui-mobile-rendering");var c=a("<div class='ui-loader ui-body-a ui-corner-all'><span class='ui-icon ui-icon-loading spin'></span><h1></h1></div>");
|
||||
a.extend(a.mobile,{showPageLoadingMsg:function(){if(a.mobile.loadingMessage){var b=a("."+a.mobile.activeBtnClass).first();c.find("h1").text(a.mobile.loadingMessage).end().appendTo(a.mobile.pageContainer).css({top:a.support.scrollTop&&f.scrollTop()+f.height()/2||b.length&&b.offset().top||100})}d.addClass("ui-loading")},hidePageLoadingMsg:function(){d.removeClass("ui-loading")},initializePage:function(){var b=a(":jqmData(role='page')");b.length||(b=a("body").wrapInner("<div data-"+a.mobile.ns+"role='page'></div>").children(0));
|
||||
b.add(":jqmData(role='dialog')").each(function(){var b=a(this);b.jqmData("url")||b.attr("data-"+a.mobile.ns+"url",b.attr("id")||location.pathname+location.search)});a.mobile.firstPage=b.first();a.mobile.pageContainer=b.first().parent().addClass("ui-mobile-viewport");f.trigger("pagecontainercreate");a.mobile.showPageLoadingMsg();!a.mobile.hashListeningEnabled||!a.mobile.path.stripHash(location.hash)?a.mobile.changePage(a.mobile.firstPage,{transition:"none",reverse:true,changeHash:false,fromHashChange:true}):
|
||||
f.trigger("hashchange",[true])}});a.support.touchOverflow&&a.mobile.touchOverflowEnabled&&!a.mobile.touchOverflowZoomEnabled&&b();a.mobile._registerInternalEvents();a(function(){e.scrollTo(0,1);a.mobile.defaultHomeScroll=!a.support.scrollTop||a(e).scrollTop()===1?0:1;a.mobile.autoInitializePage&&a.mobile.initializePage();f.load(a.mobile.silentScroll)})}})(jQuery,this);
|
||||
|
||||
2
applications/admin/static/plugin_jqmobile/jquery.mobile-1.2.0.min.css
vendored
Normal file
2
applications/admin/static/plugin_jqmobile/jquery.mobile-1.2.0.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
2
applications/admin/static/plugin_jqmobile/jquery.mobile-1.2.0.min.js
vendored
Normal file
2
applications/admin/static/plugin_jqmobile/jquery.mobile-1.2.0.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -27,7 +27,7 @@
|
||||
{{pass}}
|
||||
{{else:}}
|
||||
{{qry=''}}
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
<tr>
|
||||
<th style="font-size: 1.75em;">
|
||||
@@ -37,13 +37,19 @@
|
||||
{{=A(str(T('New Record')),_href=URL('insert',args=[db,table]),_class="btn")}}
|
||||
</td>
|
||||
</tr>
|
||||
{{pass}}
|
||||
</table>
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
</table>
|
||||
|
||||
{{elif request.function=='select':}}
|
||||
<h2>{{=XML(str(T("Database %s select"))%A(request.args[0],_href=URL('index'))) }}
|
||||
</h2>
|
||||
{{if tb:}}
|
||||
<h3>{{=T('Traceback')}}</h3>
|
||||
<pre>
|
||||
{{=tb}}
|
||||
</pre>
|
||||
{{pass}}
|
||||
{{if table:}}
|
||||
{{=A(str(T('New Record')),_href=URL('insert',args=[request.args[0],table]),_class="btn")}}<br/><br/>
|
||||
<h3>{{=T("Rows in Table")}}</h3><br/>
|
||||
@@ -149,7 +155,7 @@
|
||||
<h4>{{=T("RAM")}}</h4>
|
||||
<p>{{=T.M("Number of entries: **%s**", ram['entries'])}}</p>
|
||||
{{if ram['entries'] > 0:}}
|
||||
<p>{{=T.M("Hit Ratio: **%(ratio)s%%** (**%(hits)s** %{hit(hits)} and **%(misses)s** %%{miss(misses)})",
|
||||
<p>{{=T.M("Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})",
|
||||
dict( ratio=ram['ratio'], hits=ram['hits'], misses=ram['misses']))}}
|
||||
</p>
|
||||
<p>
|
||||
|
||||
@@ -43,8 +43,7 @@ def file_create_form(location):
|
||||
form=FORM(T("create file with filename:")," ",
|
||||
INPUT(_type="text",_name="filename",requires=IS_NOT_EMPTY),
|
||||
INPUT(_type="hidden",_name="location",_value=location),
|
||||
INPUT(_type="hidden",_name="sender",_value=URL('design',args=app)),
|
||||
INPUT(_type="submit",_value=T("Create")),_action=URL('create_file'))
|
||||
INPUT(_type="hidden",_name="sender",_value=URL('design',args=app)))
|
||||
return form
|
||||
def upload_plugin_form(app):
|
||||
form=FORM(T("upload plugin file:")," ",
|
||||
@@ -207,7 +206,7 @@ for c in controllers: controller_functions+=[c[:-3]+'/%s.html'%x for x in functi
|
||||
{{pass}}
|
||||
</ul>
|
||||
<div data-role="fieldcontain">{{=file_create_form('%s/static/' % app)}}
|
||||
{{=file_upload_form('%s/static/' % app)}}</div>
|
||||
{{#=file_upload_form('%s/static/' % app)}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -225,7 +224,7 @@ for c in controllers: controller_functions+=[c[:-3]+'/%s.html'%x for x in functi
|
||||
</span>
|
||||
{{pass}}
|
||||
<div data-role="fieldcontain">{{=file_create_form('%s/modules/' % app)}}
|
||||
{{=file_upload_form('%s/modules/' % app)}}</div>
|
||||
{{#=file_upload_form('%s/modules/' % app)}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
<div><input type="hidden" name="send" value="{{=send}}"/></div>
|
||||
<table>
|
||||
<tr><td>{{=T('Administrator Password:')}}</td><td><input type="password" name="password" id="password"/></td></tr>
|
||||
<tr><td></td><td><input type="submit" name="login" value="{{=T('Login')}}"/></td></tr>
|
||||
<tr><td></td><td><button name="login">{{=T('Login')}}</button></td></tr>
|
||||
</table>
|
||||
<input type="hidden" name="is_mobile" value="true"/>
|
||||
</form>
|
||||
</div>
|
||||
{{else:}}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
Remove this if you use the .htaccess -->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
|
||||
<title>web2py mobile admin</title>
|
||||
<title>Web2py Mobile Admin</title>
|
||||
|
||||
<!-- http://dev.w3.org/html5/markup/meta.name.html -->
|
||||
<meta name="application-name" content="{{=request.application}}" />
|
||||
@@ -24,16 +24,17 @@
|
||||
initial-scale = 1.0 retains dimensions instead of zooming out if page height > device height
|
||||
maximum-scale = 1.0 retains dimensions instead of zooming in if page width < device width
|
||||
-->
|
||||
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0;">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<!-- 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')}}">
|
||||
|
||||
<!-- For the less-enabled mobile browsers like Opera Mini -->
|
||||
<link rel="stylesheet" href="{{=URL('static','plugin_jqmobile/jquery.mobile-1.0.min.css')}}">
|
||||
<link rel="stylesheet" href="{{=URL('static','plugin_jqmobile/jquery.mobile-1.2.0.min.css')}}">
|
||||
|
||||
<!-- All JavaScript at the bottom, except for Modernizr which enables HTML5 elements & feature detects -->
|
||||
<script src="{{=URL('static','js/modernizr.custom.js')}}"></script>
|
||||
<script src="{{=URL('static','js/modernizr.custom.js')}}"></script!>
|
||||
|
||||
{{include 'web2py_ajax.html'}}
|
||||
|
||||
@@ -60,7 +61,7 @@ $(document).bind("mobileinit", function(){
|
||||
});
|
||||
</script>
|
||||
|
||||
<script src="{{=URL('static','plugin_jqmobile/jquery.mobile-1.0.min.js')}}"></script>
|
||||
<script src="{{=URL('static','plugin_jqmobile/jquery.mobile-1.2.0.min.js')}}"></script>
|
||||
|
||||
<style>
|
||||
.error { color: red; }
|
||||
@@ -75,7 +76,7 @@ $(document).bind("mobileinit", function(){
|
||||
<!--[if (gt IE 9)|!(IE)]><!--> <body> <!--<![endif]-->
|
||||
|
||||
<div data-role="page">
|
||||
<div data-role="header" data-fullscreen="true" data-position="fixed">
|
||||
<div data-role="header">
|
||||
<h1>web2py mobile admin/{{block sectionclass}}{{end}}</h1>
|
||||
{{block header}}
|
||||
{{if 'auth' in globals():}}
|
||||
@@ -85,7 +86,7 @@ $(document).bind("mobileinit", function(){
|
||||
<a rel="external" href="{{=URL('default','user',args='logout')}}" data-icon="logout" class="ui-btn-left">Logout</a>
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
<a rel="external" href="{{=URL('default','index')}}" data-icon="home" class="ui-btn-right">{{=T("Home")}}</a>
|
||||
<a rel="external" href="{{=URL('default','index',vars=dict(is_mobile='true'))}}" data-icon="home" class="ui-btn-right">{{=T("Home")}}</a>
|
||||
{{end}}
|
||||
</div>
|
||||
<div data-role="content">
|
||||
@@ -100,7 +101,7 @@ $(document).bind("mobileinit", function(){
|
||||
{{pass}}
|
||||
{{include}}
|
||||
</div>
|
||||
<div data-role="footer" data-fullscreen="true" data-position="fixed" style="padding: 5px; text-align: center">
|
||||
<div data-role="footer">
|
||||
{{block footer}}
|
||||
powered by web2py - @{{=request.now.year}}
|
||||
{{end}}
|
||||
|
||||
@@ -4,16 +4,16 @@
|
||||
|
||||
<h2>{{=T("Installed applications")}}</h2>
|
||||
|
||||
<ul data-role="listview">
|
||||
<ul data-role="listview" data-inset="true">
|
||||
{{for a in apps:}}
|
||||
<li>
|
||||
{{if a==request.application:}}
|
||||
<h3>{{=a}} ({{=T('currently running')}})</h3>
|
||||
{{else:}}
|
||||
<h3>{{=a}}</h3>
|
||||
<h3>{{=T("Application")}} {{=a}}</h3>
|
||||
{{if MULTI_USER_MODE and db.app(name=a):}}<p>created by {{="%(first_name)s %(last_name)s" % db.auth_user[db.app(name=a).owner]}}</p>{{pass}}
|
||||
{{pass}}
|
||||
<ul>
|
||||
<ul data-role="listview" data-inset="true">
|
||||
{{if a!=request.application:}}
|
||||
{{=LI(A(T('Goto'),_rel="external",_href=URL(a,'default','index')))}}
|
||||
{{if not os.path.exists('applications/%s/compiled' % a):}}
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
<script src="{{=cm}}/mode/css/css.js"></script>
|
||||
<script src="{{=cm}}/mode/javascript/javascript.js"></script>
|
||||
<script src="{{=cm}}/mode/htmlmixed/htmlmixed.js"></script>
|
||||
<script src="{{=cm}}/lib/util/search.js"></script>
|
||||
<script src="{{=cm}}/lib/util/searchcursor.js"></script>
|
||||
<script src="{{=cm}}/lib/util/dialog.js"></script>
|
||||
<link rel="stylesheet" href="{{=cm}}/lib/util/dialog.css">
|
||||
<script src="{{=cm}}/emmet.min.js"></script>
|
||||
<script language="Javascript" type="text/javascript" src="{{=URL('static','js/ajax_editor.js')}}"></script>
|
||||
{{elif TEXT_EDITOR == 'ace':}}
|
||||
@@ -130,7 +134,7 @@ jQuery(document).ready(function(){
|
||||
<textarea style="width: auto; height:400px;direction:ltr;" rows="58" cols="100" -amy-enabled="true" id="body" name="data">{{=data}}</textarea>
|
||||
<script>window.eamy = eamy;</script>
|
||||
{{elif TEXT_EDITOR == 'codemirror':}}
|
||||
<textarea style="width: auto; height:400px;direction:ltr;" id="body" name="data">{{=data}}</textarea>
|
||||
<textarea style="width: auto; height:auto; direction:ltr;" id="body" name="data">{{=data}}</textarea>
|
||||
<script>
|
||||
function isFullScreen(instance) {
|
||||
return /\bCodeMirror-fullscreen\b/.test(instance.getWrapperElement().className);
|
||||
@@ -193,6 +197,7 @@ jQuery(document).ready(function(){
|
||||
document.getElementById("body"),cm_opts);
|
||||
var hlLine = editor.setLineClass(0, "activeline");
|
||||
window.mirror = editor;
|
||||
jQuery(function(){jQuery('.CodeMirror-scroll').css("height","auto").css("overflow-x","auto");});
|
||||
</script>
|
||||
{{elif TEXT_EDITOR == 'ace':}}
|
||||
<div id="editor" style="height: 500px; width: auto; position: relative">{{=data}}</div>
|
||||
@@ -246,6 +251,11 @@ window.onload = function() {
|
||||
<ul>
|
||||
{{=shortcut('Ctrl+S', T('Save via Ajax'))}}
|
||||
{{=shortcut('Ctrl+F11', T('Toggle Fullscreen'))}}
|
||||
{{=shortcut('Ctrl-F / Cmd-F', T('Start searching'))}}
|
||||
{{=shortcut('Ctrl-G / Cmd-G', T('Find Next'))}}
|
||||
{{=shortcut('Shift-Ctrl-G / Shift-Cmd-G', T('Find Previous'))}}
|
||||
{{=shortcut('Shift-Ctrl-F / Cmd-Option-F', T('Replace'))}}
|
||||
{{=shortcut('Shift-Ctrl-R / Shift-Cmd-Option-F', T('Replace All'))}}
|
||||
{{=shortcut('Tab', T('Expand Abbreviation'))}}
|
||||
</ul>
|
||||
{{elif TEXT_EDITOR == 'codemirror':}}
|
||||
@@ -253,6 +263,11 @@ window.onload = function() {
|
||||
<ul>
|
||||
{{=shortcut('Ctrl+S', T('Save via Ajax'))}}
|
||||
{{=shortcut('Ctrl+F11', T('Toggle Fullscreen'))}}
|
||||
{{=shortcut('Ctrl-F / Cmd-F', T('Start searching'))}}
|
||||
{{=shortcut('Ctrl-G / Cmd-G', T('Find Next'))}}
|
||||
{{=shortcut('Shift-Ctrl-G / Shift-Cmd-G', T('Find Previous'))}}
|
||||
{{=shortcut('Shift-Ctrl-F / Cmd-Option-F', T('Replace'))}}
|
||||
{{=shortcut('Shift-Ctrl-R / Shift-Cmd-Option-F', T('Replace All'))}}
|
||||
</ul>
|
||||
{{else:}}
|
||||
<h3>{{=T("Key bindings")}}</h3>
|
||||
|
||||
@@ -76,6 +76,9 @@
|
||||
<p>
|
||||
{{=T("Running on %s", request.env.server_software)}}
|
||||
</p>
|
||||
{{if session.is_mobile=='auto':}}<p>
|
||||
{{=A(T('Try the mobile interface'),_href=URL('plugin_jqmobile','about'))}}</p>
|
||||
{{pass}}
|
||||
</div>
|
||||
{{pass}}
|
||||
<!-- MULTI_USER_INTERFACE -->
|
||||
|
||||
@@ -9,6 +9,13 @@
|
||||
body {
|
||||
background: url('{{=URL('static','plugin_jqmobile/images/iphone.jpg')}}') no-repeat white;
|
||||
}
|
||||
#back {
|
||||
z-index: 1000;
|
||||
padding: 10px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
iframe {
|
||||
position: absolute;
|
||||
margin-left: 320px;
|
||||
@@ -34,7 +41,8 @@
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="{{=URL('index')}}"></iframe>
|
||||
<iframe src="{{=URL('default','index',vars=dict(is_mobile='true'))}}"></iframe>
|
||||
<div id="back"><a href="{{=URL('default','index',vars=dict(is_mobile='false'))}}">Back</a></div>
|
||||
<div id="about">
|
||||
<h1><a href="http://web2py.com">web2py</a> plugin</h1>
|
||||
<h2>for <a href="http://jquerymobile.com/">jQuery Mobile</a></h2>
|
||||
|
||||
@@ -24,17 +24,17 @@
|
||||
initial-scale = 1.0 retains dimensions instead of zooming out if page height > device height
|
||||
maximum-scale = 1.0 retains dimensions instead of zooming in if page width < device width
|
||||
-->
|
||||
<!--meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0;"-->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<!-- 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')}}">
|
||||
|
||||
<!-- For the less-enabled mobile browsers like Opera Mini -->
|
||||
<link rel="stylesheet" href="{{=URL('static','plugin_jqmobile/jquery.mobile-1.0.min.css')}}">
|
||||
<link rel="stylesheet" href="{{=URL('static','plugin_jqmobile/jquery.mobile-1.2.0.min.css')}}">
|
||||
|
||||
<!-- All JavaScript at the bottom, except for Modernizr which enables HTML5 elements & feature detects -->
|
||||
<script src="{{=URL('static','js/modernizr.custom.js')}}"></script>
|
||||
<script src="{{=URL('static','js/modernizr.custom.js')}}"></script!>
|
||||
|
||||
{{include 'web2py_ajax.html'}}
|
||||
|
||||
@@ -61,7 +61,7 @@ $(document).bind("mobileinit", function(){
|
||||
});
|
||||
</script>
|
||||
|
||||
<script src="{{=URL('static','plugin_jqmobile/jquery.mobile-1.0.min.js')}}"></script>
|
||||
<script src="{{=URL('static','plugin_jqmobile/jquery.mobile-1.2.0.min.js')}}"></script>
|
||||
|
||||
<style>
|
||||
.error { color: red; }
|
||||
@@ -76,7 +76,7 @@ $(document).bind("mobileinit", function(){
|
||||
<!--[if (gt IE 9)|!(IE)]><!--> <body> <!--<![endif]-->
|
||||
|
||||
<div data-role="page">
|
||||
<div data-role="header" data-fullscreen="true" data-position="fixed">
|
||||
<div data-role="header">
|
||||
<h1>{{=response.title}}</h1>
|
||||
{{block header}}
|
||||
{{if 'auth' in globals():}}
|
||||
@@ -101,7 +101,7 @@ $(document).bind("mobileinit", function(){
|
||||
{{pass}}
|
||||
{{include}}
|
||||
</div>
|
||||
<div data-role="footer" data-fullscreen="true" data-position="fixed" style="padding: 5px; text-align: center">
|
||||
<div data-role="footer">
|
||||
{{block footer}}
|
||||
powered by web2py - @{{=request.now.year}}
|
||||
{{end}}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
|
||||
@@ -18,6 +18,3 @@ def flash():
|
||||
|
||||
def fade():
|
||||
return dict()
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ remote_addr = request.env.remote_addr
|
||||
try:
|
||||
hosts = (http_host, socket.gethostname(),
|
||||
socket.gethostbyname(http_host),
|
||||
'::1','127.0.0.1','::ffff:127.0.0.1')
|
||||
'::1', '127.0.0.1', '::ffff:127.0.0.1')
|
||||
except:
|
||||
hosts = (http_host, )
|
||||
|
||||
@@ -32,10 +32,10 @@ if request.env.http_x_forwarded_for or request.is_https:
|
||||
elif (remote_addr not in hosts) and (remote_addr != "127.0.0.1"):
|
||||
raise HTTP(200, T('appadmin is disabled because insecure channel'))
|
||||
|
||||
if (request.application=='admin' and not session.authorized) or \
|
||||
(request.application!='admin' and not gluon.fileutils.check_credentials(request)):
|
||||
if (request.application == 'admin' and not session.authorized) or \
|
||||
(request.application != 'admin' and not gluon.fileutils.check_credentials(request)):
|
||||
redirect(URL('admin', 'default', 'index',
|
||||
vars=dict(send=URL(args=request.args,vars=request.vars))))
|
||||
vars=dict(send=URL(args=request.args, vars=request.vars))))
|
||||
|
||||
ignore_rw = True
|
||||
response.view = 'appadmin.html'
|
||||
@@ -95,25 +95,23 @@ def get_query(request):
|
||||
return None
|
||||
|
||||
|
||||
def query_by_table_type(tablename,db,request=request):
|
||||
keyed = hasattr(db[tablename],'_primarykey')
|
||||
def query_by_table_type(tablename, db, request=request):
|
||||
keyed = hasattr(db[tablename], '_primarykey')
|
||||
if keyed:
|
||||
firstkey = db[tablename][db[tablename]._primarykey[0]]
|
||||
cond = '>0'
|
||||
if firstkey.type in ['string', 'text']:
|
||||
cond = '!=""'
|
||||
qry = '%s.%s.%s%s' % (request.args[0], request.args[1], firstkey.name, cond)
|
||||
qry = '%s.%s.%s%s' % (
|
||||
request.args[0], request.args[1], firstkey.name, cond)
|
||||
else:
|
||||
qry = '%s.%s.id>0' % tuple(request.args[:2])
|
||||
return qry
|
||||
|
||||
|
||||
|
||||
# ##########################################################
|
||||
# ## list all databases and tables
|
||||
# ###########################################################
|
||||
|
||||
|
||||
def index():
|
||||
return dict(databases=databases)
|
||||
|
||||
@@ -128,7 +126,7 @@ def insert():
|
||||
form = SQLFORM(db[table], ignore_rw=ignore_rw)
|
||||
if form.accepts(request.vars, session):
|
||||
response.flash = T('new record inserted')
|
||||
return dict(form=form,table=db[table])
|
||||
return dict(form=form, table=db[table])
|
||||
|
||||
|
||||
# ##########################################################
|
||||
@@ -139,7 +137,8 @@ def insert():
|
||||
def download():
|
||||
import os
|
||||
db = get_database(request)
|
||||
return response.download(request,db)
|
||||
return response.download(request, db)
|
||||
|
||||
|
||||
def csv():
|
||||
import gluon.contenttype
|
||||
@@ -150,26 +149,27 @@ def csv():
|
||||
if not query:
|
||||
return None
|
||||
response.headers['Content-disposition'] = 'attachment; filename=%s_%s.csv'\
|
||||
% tuple(request.vars.query.split('.')[:2])
|
||||
return str(db(query,ignore_common_filters=True).select())
|
||||
% tuple(request.vars.query.split('.')[:2])
|
||||
return str(db(query, ignore_common_filters=True).select())
|
||||
|
||||
|
||||
def import_csv(table, file):
|
||||
table.import_from_csv_file(file)
|
||||
|
||||
|
||||
def select():
|
||||
import re
|
||||
db = get_database(request)
|
||||
dbname = request.args[0]
|
||||
regex = re.compile('(?P<table>\w+)\.(?P<field>\w+)=(?P<value>\d+)')
|
||||
if len(request.args)>1 and hasattr(db[request.args[1]],'_primarykey'):
|
||||
if len(request.args) > 1 and hasattr(db[request.args[1]], '_primarykey'):
|
||||
regex = re.compile('(?P<table>\w+)\.(?P<field>\w+)=(?P<value>.+)')
|
||||
if request.vars.query:
|
||||
match = regex.match(request.vars.query)
|
||||
if match:
|
||||
request.vars.query = '%s.%s.%s==%s' % (request.args[0],
|
||||
match.group('table'), match.group('field'),
|
||||
match.group('value'))
|
||||
match.group('table'), match.group('field'),
|
||||
match.group('value'))
|
||||
else:
|
||||
request.vars.query = session.last_query
|
||||
query = get_query(request)
|
||||
@@ -193,14 +193,17 @@ def select():
|
||||
session.last_query = request.vars.query
|
||||
form = FORM(TABLE(TR(T('Query:'), '', INPUT(_style='width:400px',
|
||||
_name='query', _value=request.vars.query or '',
|
||||
requires=IS_NOT_EMPTY(error_message=T("Cannot be empty")))), TR(T('Update:'),
|
||||
requires=IS_NOT_EMPTY(
|
||||
error_message=T("Cannot be empty")))), TR(T('Update:'),
|
||||
INPUT(_name='update_check', _type='checkbox',
|
||||
value=False), INPUT(_style='width:400px',
|
||||
_name='update_fields', _value=request.vars.update_fields
|
||||
or '')), TR(T('Delete:'), INPUT(_name='delete_check',
|
||||
or '')), TR(T('Delete:'), INPUT(_name='delete_check',
|
||||
_class='delete', _type='checkbox', value=False), ''),
|
||||
TR('', '', INPUT(_type='submit', _value=T('submit')))),
|
||||
_action=URL(r=request,args=request.args))
|
||||
_action=URL(r=request, args=request.args))
|
||||
|
||||
tb = None
|
||||
if form.accepts(request.vars, formname=None):
|
||||
regex = re.compile(request.args[0] + '\.(?P<table>\w+)\..+')
|
||||
match = regex.match(form.vars.query.strip())
|
||||
@@ -210,26 +213,30 @@ def select():
|
||||
nrows = db(query).count()
|
||||
if form.vars.update_check and form.vars.update_fields:
|
||||
db(query).update(**eval_in_global_env('dict(%s)'
|
||||
% form.vars.update_fields))
|
||||
% form.vars.update_fields))
|
||||
response.flash = T('%s %%{row} updated', nrows)
|
||||
elif form.vars.delete_check:
|
||||
db(query).delete()
|
||||
response.flash = T('%s %%{row} deleted', nrows)
|
||||
nrows = db(query).count()
|
||||
if orderby:
|
||||
rows = db(query,ignore_common_filters=True).select(limitby=(start, stop), orderby=eval_in_global_env(orderby))
|
||||
rows = db(query, ignore_common_filters=True).select(limitby=(
|
||||
start, stop), orderby=eval_in_global_env(orderby))
|
||||
else:
|
||||
rows = db(query,ignore_common_filters=True).select(limitby=(start, stop))
|
||||
rows = db(query, ignore_common_filters=True).select(
|
||||
limitby=(start, stop))
|
||||
except Exception, e:
|
||||
import traceback
|
||||
tb = traceback.format_exc()
|
||||
(rows, nrows) = ([], 0)
|
||||
response.flash = DIV(T('Invalid Query'),PRE(str(e)))
|
||||
response.flash = DIV(T('Invalid Query'), PRE(str(e)))
|
||||
# begin handle upload csv
|
||||
csv_table = table or request.vars.table
|
||||
if csv_table:
|
||||
formcsv = FORM(str(T('or import from csv file'))+" ",
|
||||
INPUT(_type='file',_name='csvfile'),
|
||||
INPUT(_type='hidden',_value=csv_table,_name='table'),
|
||||
INPUT(_type='submit',_value=T('import')))
|
||||
formcsv = FORM(str(T('or import from csv file')) + " ",
|
||||
INPUT(_type='file', _name='csvfile'),
|
||||
INPUT(_type='hidden', _value=csv_table, _name='table'),
|
||||
INPUT(_type='submit', _value=T('import')))
|
||||
else:
|
||||
formcsv = None
|
||||
if formcsv and formcsv.process().accepted:
|
||||
@@ -238,7 +245,7 @@ def select():
|
||||
request.vars.csvfile.file)
|
||||
response.flash = T('data uploaded')
|
||||
except Exception, e:
|
||||
response.flash = DIV(T('unable to parse csv file'),PRE(str(e)))
|
||||
response.flash = DIV(T('unable to parse csv file'), PRE(str(e)))
|
||||
# end handle upload csv
|
||||
|
||||
return dict(
|
||||
@@ -249,8 +256,9 @@ def select():
|
||||
nrows=nrows,
|
||||
rows=rows,
|
||||
query=request.vars.query,
|
||||
formcsv = formcsv,
|
||||
)
|
||||
formcsv=formcsv,
|
||||
tb=tb,
|
||||
)
|
||||
|
||||
|
||||
# ##########################################################
|
||||
@@ -260,14 +268,16 @@ def select():
|
||||
|
||||
def update():
|
||||
(db, table) = get_table(request)
|
||||
keyed = hasattr(db[table],'_primarykey')
|
||||
keyed = hasattr(db[table], '_primarykey')
|
||||
record = None
|
||||
if keyed:
|
||||
key = [f for f in request.vars if f in db[table]._primarykey]
|
||||
if key:
|
||||
record = db(db[table][key[0]] == request.vars[key[0]], ignore_common_filters=True).select().first()
|
||||
record = db(db[table][key[0]] == request.vars[key[
|
||||
0]], ignore_common_filters=True).select().first()
|
||||
else:
|
||||
record = db(db[table].id == request.args(2),ignore_common_filters=True).select().first()
|
||||
record = db(db[table].id == request.args(
|
||||
2), ignore_common_filters=True).select().first()
|
||||
|
||||
if not record:
|
||||
qry = query_by_table_type(table, db)
|
||||
@@ -277,20 +287,21 @@ def update():
|
||||
|
||||
if keyed:
|
||||
for k in db[table]._primarykey:
|
||||
db[table][k].writable=False
|
||||
db[table][k].writable = False
|
||||
|
||||
form = SQLFORM(db[table], record, deletable=True, delete_label=T('Check to delete'),
|
||||
ignore_rw=ignore_rw and not keyed,
|
||||
linkto=URL('select',
|
||||
form = SQLFORM(
|
||||
db[table], record, deletable=True, delete_label=T('Check to delete'),
|
||||
ignore_rw=ignore_rw and not keyed,
|
||||
linkto=URL('select',
|
||||
args=request.args[:1]), upload=URL(r=request,
|
||||
f='download', args=request.args[:1]))
|
||||
f='download', args=request.args[:1]))
|
||||
|
||||
if form.accepts(request.vars, session):
|
||||
session.flash = T('done!')
|
||||
qry = query_by_table_type(table, db)
|
||||
redirect(URL('select', args=request.args[:1],
|
||||
vars=dict(query=qry)))
|
||||
return dict(form=form,table=db[table])
|
||||
return dict(form=form, table=db[table])
|
||||
|
||||
|
||||
# ##########################################################
|
||||
@@ -301,11 +312,15 @@ def update():
|
||||
def state():
|
||||
return dict()
|
||||
|
||||
|
||||
def ccache():
|
||||
form = FORM(
|
||||
P(TAG.BUTTON(T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
|
||||
P(TAG.BUTTON(T("Clear RAM"), _type="submit", _name="ram", _value="ram")),
|
||||
P(TAG.BUTTON(T("Clear DISK"), _type="submit", _name="disk", _value="disk")),
|
||||
P(TAG.BUTTON(
|
||||
T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
|
||||
P(TAG.BUTTON(
|
||||
T("Clear RAM"), _type="submit", _name="ram", _value="ram")),
|
||||
P(TAG.BUTTON(
|
||||
T("Clear DISK"), _type="submit", _name="disk", _value="disk")),
|
||||
)
|
||||
|
||||
if form.accepts(request.vars, session):
|
||||
@@ -329,11 +344,16 @@ def ccache():
|
||||
redirect(URL(r=request))
|
||||
|
||||
try:
|
||||
from guppy import hpy; hp=hpy()
|
||||
from guppy import hpy
|
||||
hp = hpy()
|
||||
except ImportError:
|
||||
hp = False
|
||||
|
||||
import shelve, os, copy, time, math
|
||||
import shelve
|
||||
import os
|
||||
import copy
|
||||
import time
|
||||
import math
|
||||
from gluon import portalocker
|
||||
|
||||
ram = {
|
||||
@@ -378,9 +398,10 @@ def ccache():
|
||||
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
|
||||
|
||||
locker = open(os.path.join(request.folder,
|
||||
'cache/cache.lock'), 'a')
|
||||
'cache/cache.lock'), 'a')
|
||||
portalocker.lock(locker, portalocker.LOCK_EX)
|
||||
disk_storage = shelve.open(os.path.join(request.folder, 'cache/cache.shelve'))
|
||||
disk_storage = shelve.open(
|
||||
os.path.join(request.folder, 'cache/cache.shelve'))
|
||||
try:
|
||||
for key, value in disk_storage.items():
|
||||
if isinstance(value, dict):
|
||||
@@ -411,7 +432,8 @@ def ccache():
|
||||
total['misses'] = ram['misses'] + disk['misses']
|
||||
total['keys'] = ram['keys'] + disk['keys']
|
||||
try:
|
||||
total['ratio'] = total['hits'] * 100 / (total['hits'] + total['misses'])
|
||||
total['ratio'] = total['hits'] * 100 / (total['hits'] +
|
||||
total['misses'])
|
||||
except (KeyError, ZeroDivisionError):
|
||||
total['ratio'] = 0
|
||||
|
||||
@@ -437,6 +459,3 @@ def ccache():
|
||||
|
||||
return dict(form=form, total=total,
|
||||
ram=ram, disk=disk, object_stats=hp != False)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,25 +1,24 @@
|
||||
|
||||
import time
|
||||
|
||||
|
||||
def cache_in_ram():
|
||||
"""cache the output of the lambda function in ram"""
|
||||
|
||||
t = cache.ram('time', lambda : time.ctime(), time_expire=5)
|
||||
t = cache.ram('time', lambda: time.ctime(), time_expire=5)
|
||||
return dict(time=t, link=A('click to reload', _href=URL(r=request)))
|
||||
|
||||
|
||||
def cache_on_disk():
|
||||
"""cache the output of the lambda function on disk"""
|
||||
|
||||
t = cache.disk('time', lambda : time.ctime(), time_expire=5)
|
||||
t = cache.disk('time', lambda: time.ctime(), time_expire=5)
|
||||
return dict(time=t, link=A('click to reload', _href=URL(r=request)))
|
||||
|
||||
|
||||
def cache_in_ram_and_disk():
|
||||
"""cache the output of the lambda function on disk and in ram"""
|
||||
|
||||
t = cache.ram('time', lambda : cache.disk('time', lambda : \
|
||||
t = cache.ram('time', lambda: cache.disk('time', lambda:
|
||||
time.ctime(), time_expire=5), time_expire=5)
|
||||
return dict(time=t, link=A('click to reload', _href=URL(r=request)))
|
||||
|
||||
@@ -47,5 +46,3 @@ def cache_controller_and_view():
|
||||
t = time.ctime()
|
||||
d = dict(time=t, link=A('click to reload', _href=URL(r=request)))
|
||||
return response.render(d)
|
||||
|
||||
|
||||
|
||||
@@ -9,68 +9,83 @@ response.description = T('web2py Web Framework')
|
||||
session.forget()
|
||||
cache_expire = not request.is_local and 300 or 0
|
||||
|
||||
|
||||
@cache('index', time_expire=cache_expire)
|
||||
def index():
|
||||
return response.render()
|
||||
|
||||
|
||||
@cache('what', time_expire=cache_expire)
|
||||
def what():
|
||||
import urllib;
|
||||
import urllib
|
||||
try:
|
||||
images = XML(urllib.urlopen('http://web2py.com/poweredby/default/images').read())
|
||||
images = XML(urllib.urlopen(
|
||||
'http://web2py.com/poweredby/default/images').read())
|
||||
except:
|
||||
images = []
|
||||
return response.render(images=images)
|
||||
|
||||
|
||||
@cache('download', time_expire=cache_expire)
|
||||
def download():
|
||||
return response.render()
|
||||
|
||||
|
||||
@cache('who', time_expire=cache_expire)
|
||||
def who():
|
||||
return response.render()
|
||||
|
||||
|
||||
@cache('support', time_expire=cache_expire)
|
||||
def support():
|
||||
return response.render()
|
||||
|
||||
|
||||
@cache('documentation', time_expire=cache_expire)
|
||||
def documentation():
|
||||
return response.render()
|
||||
|
||||
|
||||
@cache('usergroups', time_expire=cache_expire)
|
||||
def usergroups():
|
||||
return response.render()
|
||||
|
||||
|
||||
def contact():
|
||||
redirect(URL('default','usergroups'))
|
||||
redirect(URL('default', 'usergroups'))
|
||||
|
||||
|
||||
@cache('videos', time_expire=cache_expire)
|
||||
def videos():
|
||||
return response.render()
|
||||
|
||||
|
||||
def security():
|
||||
redirect('http://www.web2py.com/book/default/chapter/01#security')
|
||||
|
||||
|
||||
def api():
|
||||
redirect('http://web2py.com/book/default/chapter/04#API')
|
||||
|
||||
|
||||
@cache('license', time_expire=cache_expire)
|
||||
def license():
|
||||
import os
|
||||
filename = os.path.join(request.env.gluon_parent, 'LICENSE')
|
||||
return response.render(dict(license=MARKMIN(read_file(filename))))
|
||||
|
||||
|
||||
def version():
|
||||
return 'Version %s.%s.%s (%s) %s' % request.env.web2py_version
|
||||
|
||||
|
||||
@cache('examples', time_expire=cache_expire)
|
||||
def examples():
|
||||
return response.render()
|
||||
|
||||
|
||||
@cache('changelog', time_expire=cache_expire)
|
||||
def changelog():
|
||||
import os
|
||||
filename = os.path.join(request.env.gluon_parent, 'CHANGELOG')
|
||||
return response.render(dict(changelog=MARKMIN(read_file(filename))))
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
|
||||
|
||||
|
||||
def form():
|
||||
""" a simple entry form with various types of objects """
|
||||
|
||||
@@ -15,7 +12,7 @@ def form():
|
||||
TR('Profile', TEXTAREA(_name='profile',
|
||||
value='write something here')),
|
||||
TR('', INPUT(_type='submit', _value='SUBMIT')),
|
||||
))
|
||||
))
|
||||
if form.process().accepted:
|
||||
response.flash = 'form accepted'
|
||||
elif form.errors:
|
||||
@@ -23,6 +20,3 @@ def form():
|
||||
else:
|
||||
response.flash = 'please fill the form'
|
||||
return dict(form=form, vars=form.vars)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
session.forget()
|
||||
|
||||
response.menu = [['home', False, '/%s/default/index'
|
||||
@@ -17,14 +16,14 @@ def vars():
|
||||
c,
|
||||
d,
|
||||
value,
|
||||
) = (
|
||||
) = (
|
||||
'Global variables',
|
||||
globals(),
|
||||
None,
|
||||
None,
|
||||
(),
|
||||
None,
|
||||
)
|
||||
)
|
||||
(title, args) = ('globals()', '')
|
||||
elif len(request.args) < 3:
|
||||
args = '.'.join(request.args)
|
||||
@@ -76,7 +75,4 @@ def vars():
|
||||
d=d,
|
||||
doc=doc,
|
||||
attributes=attributes,
|
||||
)
|
||||
|
||||
|
||||
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
def civilized():
|
||||
response.menu = [['civilized', True, URL('civilized'
|
||||
)], ['slick', False, URL('slick')],
|
||||
)], ['slick', False, URL('slick')],
|
||||
['basic', False, URL('basic')]]
|
||||
response.flash = 'you clicked on civilized'
|
||||
return dict(message='you clicked on civilized')
|
||||
@@ -8,7 +8,7 @@ def civilized():
|
||||
|
||||
def slick():
|
||||
response.menu = [['civilized', False, URL('civilized'
|
||||
)], ['slick', True, URL('slick')],
|
||||
)], ['slick', True, URL('slick')],
|
||||
['basic', False, URL('basic')]]
|
||||
response.flash = 'you clicked on slick'
|
||||
return dict(message='you clicked on slick')
|
||||
@@ -16,10 +16,7 @@ def slick():
|
||||
|
||||
def basic():
|
||||
response.menu = [['civilized', False, URL('civilized'
|
||||
)], ['slick', False, URL('slick')],
|
||||
)], ['slick', False, URL('slick')],
|
||||
['basic', True, URL('basic')]]
|
||||
response.flash = 'you clicked on basic'
|
||||
return dict(message='you clicked on basic')
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
|
||||
|
||||
|
||||
def counter():
|
||||
""" every time you reload, it increases the session.counter """
|
||||
|
||||
@@ -8,6 +5,3 @@ def counter():
|
||||
session.counter = 0
|
||||
session.counter += 1
|
||||
return dict(counter=session.counter)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -38,7 +38,6 @@ def hello6():
|
||||
|
||||
def status():
|
||||
""" page that shows internal status"""
|
||||
response.view = 'generic.html'
|
||||
return dict(toolbar=response.toolbar())
|
||||
|
||||
|
||||
@@ -103,9 +102,8 @@ def rss_aggregator():
|
||||
return rss2.dumps(rss)
|
||||
|
||||
|
||||
|
||||
def ajaxwiki():
|
||||
default="""
|
||||
default = """
|
||||
# section
|
||||
|
||||
## subsection
|
||||
@@ -130,12 +128,12 @@ Quoted text
|
||||
3 | 0 | 0
|
||||
---------
|
||||
"""
|
||||
form = FORM(TEXTAREA(_id='text',_name='text',value=default),
|
||||
form = FORM(TEXTAREA(_id='text', _name='text', value=default),
|
||||
INPUT(_type='button',
|
||||
_value='markmin',
|
||||
_onclick="ajax('ajaxwiki_onclick',['text'],'html')"))
|
||||
return dict(form=form, html=DIV(_id='html'))
|
||||
|
||||
|
||||
def ajaxwiki_onclick():
|
||||
return MARKMIN(request.vars.text).xml()
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
from gluon.contrib.spreadsheet import Sheet
|
||||
|
||||
|
||||
def callback():
|
||||
return cache.ram('sheet1',lambda:None,None).process(request)
|
||||
return cache.ram('sheet1', lambda: None, None).process(request)
|
||||
|
||||
|
||||
def index():
|
||||
sheet = cache.ram('sheet1',lambda:Sheet(10,10,URL('callback')),0)
|
||||
sheet = cache.ram('sheet1', lambda: Sheet(10, 10, URL('callback')), 0)
|
||||
#sheet.cell('r0c3',value='=r0c0+r0c1+r0c2',readonly=True)
|
||||
return dict(sheet=sheet)
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
|
||||
|
||||
|
||||
def variables():
|
||||
return dict(a=10, b=20)
|
||||
|
||||
@@ -31,6 +28,3 @@ def xml():
|
||||
|
||||
def beautify():
|
||||
return dict(message=BEAUTIFY(request))
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,49 +1,44 @@
|
||||
|
||||
def group_feed_reader(group,mode='div',counter='5'):
|
||||
def group_feed_reader(group, mode='div', counter='5'):
|
||||
"""parse group feeds"""
|
||||
|
||||
url = "http://groups.google.com/group/%s/feed/rss_v2_0_topics.xml?num=%s" %\
|
||||
(group,counter)
|
||||
(group, counter)
|
||||
from gluon.contrib import feedparser
|
||||
g = feedparser.parse(url)
|
||||
|
||||
if mode == 'div':
|
||||
html = XML(TAG.BLOCKQUOTE(UL(*[LI(A(entry['title']+' - ' +\
|
||||
entry['author'][entry['author'].rfind('('):],\
|
||||
_href=entry['link'],_target='_blank'))\
|
||||
for entry in g['entries'] ]),\
|
||||
_class="boxInfo",\
|
||||
_style="padding-bottom:5px;"))
|
||||
html = XML(TAG.BLOCKQUOTE(UL(*[LI(A(entry['title'] + ' - ' +
|
||||
entry['author'][
|
||||
entry['author'].rfind('('):],
|
||||
_href=entry['link'], _target='_blank'))
|
||||
for entry in g['entries']]),
|
||||
_class="boxInfo",
|
||||
_style="padding-bottom:5px;"))
|
||||
|
||||
else:
|
||||
html = XML(UL(*[LI(A(entry['title']+' - ' +\
|
||||
entry['author'][entry['author'].rfind('('):],\
|
||||
_href=entry['link'],_target='_blank'))\
|
||||
for entry in g['entries'] ]))
|
||||
html = XML(UL(*[LI(A(entry['title'] + ' - ' +
|
||||
entry['author'][entry['author'].rfind('('):],
|
||||
_href=entry['link'], _target='_blank'))
|
||||
for entry in g['entries']]))
|
||||
|
||||
return html
|
||||
|
||||
|
||||
def code_feed_reader(project,mode='div'):
|
||||
def code_feed_reader(project, mode='div'):
|
||||
"""parse code feeds"""
|
||||
|
||||
url = "http://code.google.com/feeds/p/%s/hgchanges/basic" % project
|
||||
from gluon.contrib import feedparser
|
||||
g = feedparser.parse(url)
|
||||
if mode == 'div':
|
||||
html = XML(DIV(UL(*[LI(A(entry['title'],_href=entry['link'],\
|
||||
_target='_blank'))\
|
||||
for entry in g['entries'][0:5]]),\
|
||||
_class="boxInfo",\
|
||||
html = XML(DIV(UL(*[LI(A(entry['title'], _href=entry['link'],
|
||||
_target='_blank'))
|
||||
for entry in g['entries'][0:5]]),
|
||||
_class="boxInfo",
|
||||
_style="padding-bottom:5px;"))
|
||||
else:
|
||||
html = XML(UL(*[LI(A(entry['title'],_href=entry['link'],\
|
||||
_target='_blank'))\
|
||||
for entry in g['entries'][0:5]]))
|
||||
|
||||
html = XML(UL(*[LI(A(entry['title'], _href=entry['link'],
|
||||
_target='_blank'))
|
||||
for entry in g['entries'][0:5]]))
|
||||
|
||||
return html
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2,18 +2,19 @@ import gluon.template
|
||||
|
||||
markmin_dict = dict(
|
||||
code_python=lambda code: str(CODE(code)),
|
||||
template=lambda \
|
||||
code:gluon.template.render(code,context=globals()),
|
||||
sup=lambda \
|
||||
code:'<sup style="font-size:0.5em;">%s</sup>'%code,
|
||||
br=lambda n:'<br>'*int(n),
|
||||
groupdates=lambda group:group_feed_reader(group),
|
||||
)
|
||||
template=lambda
|
||||
code: gluon.template.render(code, context=globals()),
|
||||
sup=lambda
|
||||
code: '<sup style="font-size:0.5em;">%s</sup>' % code,
|
||||
br=lambda n: '<br>' * int(n),
|
||||
groupdates=lambda group: group_feed_reader(group),
|
||||
)
|
||||
|
||||
def get_content(b=None,\
|
||||
c=request.controller,\
|
||||
f=request.function,\
|
||||
l='en',\
|
||||
|
||||
def get_content(b=None,
|
||||
c=request.controller,
|
||||
f=request.function,
|
||||
l='en',
|
||||
format='markmin'):
|
||||
"""Gets and renders the file in
|
||||
<app>/private/content/<lang>/<controller>/<function>/<block>.<format>
|
||||
@@ -21,20 +22,20 @@ def get_content(b=None,\
|
||||
|
||||
def openfile():
|
||||
import os
|
||||
path = os.path.join(request.folder,'private','content',l,c,f,b+'.'+format)
|
||||
path = os.path.join(
|
||||
request.folder, 'private', 'content', l, c, f, b + '.' + format)
|
||||
return open(path)
|
||||
|
||||
try:
|
||||
openedfile = openfile()
|
||||
except Exception, IOError:
|
||||
l='en'
|
||||
l = 'en'
|
||||
openedfile = openfile()
|
||||
|
||||
if format == 'markmin':
|
||||
html = MARKMIN(str(T(openedfile.read())),markmin_dict)
|
||||
html = MARKMIN(str(T(openedfile.read())), markmin_dict)
|
||||
else:
|
||||
html = str(T(openedfile.read()))
|
||||
openedfile.close()
|
||||
|
||||
return html
|
||||
|
||||
|
||||
@@ -1,28 +1,29 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
response.menu = [
|
||||
(T('Home'),False,URL('default','index')),
|
||||
(T('About'),False,URL('default','what')),
|
||||
(T('Download'),False,URL('default','download')),
|
||||
(T('Docs & Resources'),False,URL('default','documentation')),
|
||||
(T('Support'),False,URL('default','support')),
|
||||
(T('Contributors'),False,URL('default','who'))]
|
||||
(T('Home'), False, URL('default', 'index')),
|
||||
(T('About'), False, URL('default', 'what')),
|
||||
(T('Download'), False, URL('default', 'download')),
|
||||
(T('Docs & Resources'), False, URL('default', 'documentation')),
|
||||
(T('Support'), False, URL('default', 'support')),
|
||||
(T('Contributors'), False, URL('default', 'who'))]
|
||||
|
||||
#########################################################################
|
||||
## Changes the menu active item
|
||||
#########################################################################
|
||||
def toggle_menuclass(cssclass='pressed',menuid='headermenu'):
|
||||
|
||||
|
||||
def toggle_menuclass(cssclass='pressed', menuid='headermenu'):
|
||||
"""This function changes the menu class to put pressed appearance"""
|
||||
|
||||
positions = dict(
|
||||
index='',
|
||||
what='-108px -115px',
|
||||
download='-211px -115px',
|
||||
who='-315px -115px',
|
||||
support='-418px -115px',
|
||||
documentation='-520px -115px'
|
||||
)
|
||||
|
||||
index='',
|
||||
what='-108px -115px',
|
||||
download='-211px -115px',
|
||||
who='-315px -115px',
|
||||
support='-418px -115px',
|
||||
documentation='-520px -115px'
|
||||
)
|
||||
|
||||
if request.function in positions.keys():
|
||||
jscript = """
|
||||
@@ -34,12 +35,11 @@ def toggle_menuclass(cssclass='pressed',menuid='headermenu'):
|
||||
});
|
||||
</script>
|
||||
""" % dict(cssclass=cssclass,
|
||||
menuid=menuid,
|
||||
function=request.function,
|
||||
cssposition=positions[request.function]
|
||||
)
|
||||
menuid=menuid,
|
||||
function=request.function,
|
||||
cssposition=positions[request.function]
|
||||
)
|
||||
|
||||
return XML(jscript)
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ h3 {font-size:2.00em}
|
||||
h4 {font-size:1.50em}
|
||||
h5 {font-size:1.25em}
|
||||
h6 {font-size:1.12em}
|
||||
th,label {font-weight:bold; white-space:nowrap}
|
||||
th,label {font-weight:bold; white-space:nowrap;}
|
||||
td,th {text-align:left; padding:2px 5px 2px 5px}
|
||||
th {vertical-align:middle; border-right:1px solid white}
|
||||
td {vertical-align:top}
|
||||
@@ -69,7 +69,6 @@ fieldset {padding:16px; border-top:1px #DEDEDE solid}
|
||||
fieldset legend {text-transform:uppercase; font-weight:bold; padding:4px 16px 4px 16px; background:#f1f1f1}
|
||||
|
||||
/* fix ie problem with menu */
|
||||
.ie-lte7 .topbar .container {z-index:2}
|
||||
|
||||
td.w2p_fw {padding-bottom:1px}
|
||||
td.w2p_fl,td.w2p_fw,td.w2p_fc {vertical-align:top}
|
||||
@@ -187,10 +186,7 @@ div.error {
|
||||
.web2py_paginator {}
|
||||
.web2py_grid {width:100%}
|
||||
.web2py_grid table {width:100%}
|
||||
.web2py_grid tbody td {
|
||||
padding:2px 5px 2px 5px;
|
||||
vertical-align:middle;
|
||||
}
|
||||
.web2py_grid tbody td {padding:2px 5px 2px 5px; vertical-align: middle;}
|
||||
|
||||
.web2py_grid thead th,.web2py_grid tfoot td {
|
||||
background-color:#EAEAEA;
|
||||
@@ -299,10 +295,16 @@ li.w2p_grid_breadcrumb_elem {
|
||||
.web2py_console input, .web2py_console select,
|
||||
.web2py_console a { margin: 2px; }
|
||||
|
||||
.ie9 #w2p_query_panel {padding-bottom:2px}
|
||||
|
||||
#wiki_page_body {
|
||||
width: 600px;
|
||||
height: auto;
|
||||
min-height: 400px;
|
||||
}
|
||||
}
|
||||
|
||||
/* fix some IE problems */
|
||||
|
||||
.ie-lte7 .topbar .container {z-index:2}
|
||||
.ie-lte8 div.flash{ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#222222', endColorstr='#000000', GradientType=0 ); }
|
||||
.ie-lte8 div.flash:hover {filter:alpha(opacity=25);}
|
||||
.ie9 #w2p_query_panel {padding-bottom:2px}
|
||||
|
||||
@@ -39,7 +39,7 @@ function web2py_ajax_init(target) {
|
||||
|
||||
function web2py_event_handlers() {
|
||||
var doc = jQuery(document)
|
||||
doc.on('click', '.flash', function(e){jQuery(this).fadeOut('slow'); e.preventDefault();});
|
||||
doc.on('click', '.flash', function(e){var t=jQuery(this); if(t.css('top')=='0px') t.slideUp('slow'); else t.fadeOut(); e.preventDefault();});
|
||||
doc.on('keyup', 'input.integer', function(){this.value=this.value.reverse().replace(/[^0-9\-]|\-(?=.)/g,'').reverse();});
|
||||
doc.on('keyup', 'input.double, input.decimal', function(){this.value=this.value.reverse().replace(/[^0-9\-\.,]|[\-](?=.)|[\.,](?=[0-9]*[\.,])/g,'').reverse();});
|
||||
var confirm_message = (typeof w2p_ajax_confirm_message != 'undefined') ? w2p_ajax_confirm_message : "Are you sure you want to delete this object?";
|
||||
@@ -55,7 +55,7 @@ function web2py_event_handlers() {
|
||||
jQuery(function() {
|
||||
var flash = jQuery('.flash');
|
||||
flash.hide();
|
||||
if(flash.html()) flash.slideDown();
|
||||
if(flash.html()) flash.append('<span style="float:right;">×</span>').slideDown();
|
||||
web2py_ajax_init(document);
|
||||
web2py_event_handlers();
|
||||
});
|
||||
@@ -67,20 +67,20 @@ function web2py_trap_form(action,target) {
|
||||
form.submit(function(e){
|
||||
jQuery('.flash').hide().html('');
|
||||
web2py_ajax_page('post',action,form.serialize(),target);
|
||||
e.preventDefault();
|
||||
e.preventDefault();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function web2py_trap_link(target) {
|
||||
jQuery('#'+target+' a.w2p_trap').each(function(i){
|
||||
var link=jQuery(this);
|
||||
link.click(function(e) {
|
||||
jQuery('.flash').hide().html('');
|
||||
web2py_ajax_page('get',link.attr('href'),[],target);
|
||||
e.preventDefault();
|
||||
});
|
||||
});
|
||||
var link=jQuery(this);
|
||||
link.click(function(e) {
|
||||
jQuery('.flash').hide().html('');
|
||||
web2py_ajax_page('get',link.attr('href'),[],target);
|
||||
e.preventDefault();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function web2py_ajax_page(method, action, data, target) {
|
||||
@@ -101,9 +101,9 @@ function web2py_ajax_page(method, action, data, target) {
|
||||
web2py_trap_link(target);
|
||||
web2py_ajax_init('#'+target);
|
||||
if(command)
|
||||
eval(decodeURIComponent(command));
|
||||
eval(decodeURIComponent(command));
|
||||
if(flash)
|
||||
jQuery('.flash').html(decodeURIComponent(flash)).slideDown();
|
||||
jQuery('.flash').html(decodeURIComponent(flash)).slideDown();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -151,11 +151,11 @@ function web2py_component(action, target, timeout, times){
|
||||
}
|
||||
} else {
|
||||
// run once (no timeout specified)
|
||||
element.reload_counter = Infinity;
|
||||
element.reload_counter = Infinity;
|
||||
web2py_ajax_page('get', action, null, target);
|
||||
} }); }
|
||||
|
||||
function web2py_comet(url,onmessage,onopen,onclose) {
|
||||
function web2py_websocket(url,onmessage,onopen,onclose) {
|
||||
if ("WebSocket" in window) {
|
||||
var ws = new WebSocket(url);
|
||||
ws.onopen = onopen?onopen:(function(){});
|
||||
@@ -165,3 +165,38 @@ function web2py_comet(url,onmessage,onopen,onclose) {
|
||||
} else return false; // not supported
|
||||
}
|
||||
|
||||
|
||||
function web2py_calc_entropy(mystring) {
|
||||
//calculate a simple entropy for a given string
|
||||
var csets = new Array(
|
||||
'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
||||
'0123456789', '!@#$\%^&*()', '~`-_=+[]{}\|;:\'",.<>?/',
|
||||
'0123456789abcdefghijklmnopqrstuvwxyz');
|
||||
var score = 0, other = {}, seen = {}, lastset = null, mystringlist = mystring.split('');
|
||||
for (var i=0;i<mystringlist.length;i++) { // classify this character
|
||||
var c = mystringlist[i], inset=5;
|
||||
for(var j = 0; j<csets.length; j++)
|
||||
if (csets[j].indexOf(c) != -1) {inset = j; break;}
|
||||
//calculate effect of character on alphabet size
|
||||
if(!(inset in seen)) {seen[inset] = 1;score += csets[inset].length;}
|
||||
else if (!(c in other)) {score += 1;other[c] = 1;}
|
||||
if (inset != lastset) {score += 1;lastset = inset;}
|
||||
}
|
||||
var entropy = mystring.length*Math.log(score)/0.6931471805599453;
|
||||
return Math.round(entropy*100)/100
|
||||
}
|
||||
|
||||
function web2py_validate_entropy(myfield, req_entropy) {
|
||||
var validator = function () {
|
||||
var v = (web2py_calc_entropy(myfield.val())||0)/req_entropy;
|
||||
var r=0,g=0,b=0,rs=function(x){return Math.round(x*15).toString(16)};
|
||||
if(v<=0.5) {r=1.0; g=2.0*v;}
|
||||
else {r=(1.0-2.0*(Math.max(v,0)-0.5)); g=1.0;}
|
||||
var color = '#'+rs(r)+rs(g)+rs(b);
|
||||
myfield.css('background-color',color);
|
||||
entropy_callback = myfield.data('entropy_callback');
|
||||
if(entropy_callback) entropy_callback(v);
|
||||
}
|
||||
if(!myfield.hasClass('entropy_check')) myfield.on('keyup', validator).on('keydown', validator).addClass('entropy_check');
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
{{pass}}
|
||||
{{else:}}
|
||||
{{qry=''}}
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
<tr>
|
||||
<th style="font-size: 1.75em;">
|
||||
@@ -37,13 +37,19 @@
|
||||
{{=A(str(T('New Record')),_href=URL('insert',args=[db,table]),_class="btn")}}
|
||||
</td>
|
||||
</tr>
|
||||
{{pass}}
|
||||
</table>
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
</table>
|
||||
|
||||
{{elif request.function=='select':}}
|
||||
<h2>{{=XML(str(T("Database %s select"))%A(request.args[0],_href=URL('index'))) }}
|
||||
</h2>
|
||||
{{if tb:}}
|
||||
<h3>{{=T('Traceback')}}</h3>
|
||||
<pre>
|
||||
{{=tb}}
|
||||
</pre>
|
||||
{{pass}}
|
||||
{{if table:}}
|
||||
{{=A(str(T('New Record')),_href=URL('insert',args=[request.args[0],table]),_class="btn")}}<br/><br/>
|
||||
<h3>{{=T("Rows in Table")}}</h3><br/>
|
||||
@@ -149,7 +155,7 @@
|
||||
<h4>{{=T("RAM")}}</h4>
|
||||
<p>{{=T.M("Number of entries: **%s**", ram['entries'])}}</p>
|
||||
{{if ram['entries'] > 0:}}
|
||||
<p>{{=T.M("Hit Ratio: **%(ratio)s%%** (**%(hits)s** %{hit(hits)} and **%(misses)s** %%{miss(misses)})",
|
||||
<p>{{=T.M("Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})",
|
||||
dict( ratio=ram['ratio'], hits=ram['hits'], misses=ram['misses']))}}
|
||||
</p>
|
||||
<p>
|
||||
|
||||
@@ -80,8 +80,7 @@ Current version: {{="%s.%s.%s (%s) %s" % request.env.web2py_version}}</p>
|
||||
<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/>
|
||||
<object width="234" height="60"><param name="movie" value="http://widget.chipin.com/widget/id/dcd384d58839aa4d"></param><param name="allowScriptAccess" value="always"></param><param name="wmode" value="transparent"></param><param name="color_scheme" value="gray"></param><embed src="http://widget.chipin.com/widget/id/dcd384d58839aa4d" flashVars="color_scheme=gray" type="application/x-shockwave-flash" allowScriptAccess="always" wmode="transparent" width="234" height="60"></embed></object>
|
||||
<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}}
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
</li><li>Alvaro Justen (dynamical translations)
|
||||
</li><li>Anders Roos (file locking)
|
||||
</li><li>Andrew Willimott (documentation, TeraData support)
|
||||
</li><li>Andriy Kornatskyy (benchmarks and profiling)
|
||||
</li><li>Angelo Compagnucci (mobile devices)
|
||||
</li><li>Anthony Bastardi (book, poweredby site, multiple contributions)
|
||||
</li><li>Arun K. Rajeevan (plugin_wiki)
|
||||
@@ -70,6 +71,7 @@
|
||||
</li><li>Ian Reinhart Geiser (html helpers)
|
||||
</li><li>Ionel Anton (Romanian translation)
|
||||
</li><li>Jan Beilicke (markmin)
|
||||
</li><li>Jeremy Dillworth
|
||||
</li><li>Jonathan Benn (is_url validator and tests)
|
||||
</li><li>Jonathan Lundell (multiple contributions)
|
||||
</li><li>Josh Goldfoot (xaml/html sanitizer)
|
||||
@@ -156,6 +158,7 @@
|
||||
<li><a href="http://www.danga.com/memcached/">memcache</a> developed by Evan Martin</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 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>
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ remote_addr = request.env.remote_addr
|
||||
try:
|
||||
hosts = (http_host, socket.gethostname(),
|
||||
socket.gethostbyname(http_host),
|
||||
'::1','127.0.0.1','::ffff:127.0.0.1')
|
||||
'::1', '127.0.0.1', '::ffff:127.0.0.1')
|
||||
except:
|
||||
hosts = (http_host, )
|
||||
|
||||
@@ -32,10 +32,10 @@ if request.env.http_x_forwarded_for or request.is_https:
|
||||
elif (remote_addr not in hosts) and (remote_addr != "127.0.0.1"):
|
||||
raise HTTP(200, T('appadmin is disabled because insecure channel'))
|
||||
|
||||
if (request.application=='admin' and not session.authorized) or \
|
||||
(request.application!='admin' and not gluon.fileutils.check_credentials(request)):
|
||||
if (request.application == 'admin' and not session.authorized) or \
|
||||
(request.application != 'admin' and not gluon.fileutils.check_credentials(request)):
|
||||
redirect(URL('admin', 'default', 'index',
|
||||
vars=dict(send=URL(args=request.args,vars=request.vars))))
|
||||
vars=dict(send=URL(args=request.args, vars=request.vars))))
|
||||
|
||||
ignore_rw = True
|
||||
response.view = 'appadmin.html'
|
||||
@@ -95,25 +95,23 @@ def get_query(request):
|
||||
return None
|
||||
|
||||
|
||||
def query_by_table_type(tablename,db,request=request):
|
||||
keyed = hasattr(db[tablename],'_primarykey')
|
||||
def query_by_table_type(tablename, db, request=request):
|
||||
keyed = hasattr(db[tablename], '_primarykey')
|
||||
if keyed:
|
||||
firstkey = db[tablename][db[tablename]._primarykey[0]]
|
||||
cond = '>0'
|
||||
if firstkey.type in ['string', 'text']:
|
||||
cond = '!=""'
|
||||
qry = '%s.%s.%s%s' % (request.args[0], request.args[1], firstkey.name, cond)
|
||||
qry = '%s.%s.%s%s' % (
|
||||
request.args[0], request.args[1], firstkey.name, cond)
|
||||
else:
|
||||
qry = '%s.%s.id>0' % tuple(request.args[:2])
|
||||
return qry
|
||||
|
||||
|
||||
|
||||
# ##########################################################
|
||||
# ## list all databases and tables
|
||||
# ###########################################################
|
||||
|
||||
|
||||
def index():
|
||||
return dict(databases=databases)
|
||||
|
||||
@@ -128,7 +126,7 @@ def insert():
|
||||
form = SQLFORM(db[table], ignore_rw=ignore_rw)
|
||||
if form.accepts(request.vars, session):
|
||||
response.flash = T('new record inserted')
|
||||
return dict(form=form,table=db[table])
|
||||
return dict(form=form, table=db[table])
|
||||
|
||||
|
||||
# ##########################################################
|
||||
@@ -139,7 +137,8 @@ def insert():
|
||||
def download():
|
||||
import os
|
||||
db = get_database(request)
|
||||
return response.download(request,db)
|
||||
return response.download(request, db)
|
||||
|
||||
|
||||
def csv():
|
||||
import gluon.contenttype
|
||||
@@ -150,26 +149,27 @@ def csv():
|
||||
if not query:
|
||||
return None
|
||||
response.headers['Content-disposition'] = 'attachment; filename=%s_%s.csv'\
|
||||
% tuple(request.vars.query.split('.')[:2])
|
||||
return str(db(query,ignore_common_filters=True).select())
|
||||
% tuple(request.vars.query.split('.')[:2])
|
||||
return str(db(query, ignore_common_filters=True).select())
|
||||
|
||||
|
||||
def import_csv(table, file):
|
||||
table.import_from_csv_file(file)
|
||||
|
||||
|
||||
def select():
|
||||
import re
|
||||
db = get_database(request)
|
||||
dbname = request.args[0]
|
||||
regex = re.compile('(?P<table>\w+)\.(?P<field>\w+)=(?P<value>\d+)')
|
||||
if len(request.args)>1 and hasattr(db[request.args[1]],'_primarykey'):
|
||||
if len(request.args) > 1 and hasattr(db[request.args[1]], '_primarykey'):
|
||||
regex = re.compile('(?P<table>\w+)\.(?P<field>\w+)=(?P<value>.+)')
|
||||
if request.vars.query:
|
||||
match = regex.match(request.vars.query)
|
||||
if match:
|
||||
request.vars.query = '%s.%s.%s==%s' % (request.args[0],
|
||||
match.group('table'), match.group('field'),
|
||||
match.group('value'))
|
||||
match.group('table'), match.group('field'),
|
||||
match.group('value'))
|
||||
else:
|
||||
request.vars.query = session.last_query
|
||||
query = get_query(request)
|
||||
@@ -193,14 +193,17 @@ def select():
|
||||
session.last_query = request.vars.query
|
||||
form = FORM(TABLE(TR(T('Query:'), '', INPUT(_style='width:400px',
|
||||
_name='query', _value=request.vars.query or '',
|
||||
requires=IS_NOT_EMPTY(error_message=T("Cannot be empty")))), TR(T('Update:'),
|
||||
requires=IS_NOT_EMPTY(
|
||||
error_message=T("Cannot be empty")))), TR(T('Update:'),
|
||||
INPUT(_name='update_check', _type='checkbox',
|
||||
value=False), INPUT(_style='width:400px',
|
||||
_name='update_fields', _value=request.vars.update_fields
|
||||
or '')), TR(T('Delete:'), INPUT(_name='delete_check',
|
||||
or '')), TR(T('Delete:'), INPUT(_name='delete_check',
|
||||
_class='delete', _type='checkbox', value=False), ''),
|
||||
TR('', '', INPUT(_type='submit', _value=T('submit')))),
|
||||
_action=URL(r=request,args=request.args))
|
||||
_action=URL(r=request, args=request.args))
|
||||
|
||||
tb = None
|
||||
if form.accepts(request.vars, formname=None):
|
||||
regex = re.compile(request.args[0] + '\.(?P<table>\w+)\..+')
|
||||
match = regex.match(form.vars.query.strip())
|
||||
@@ -210,26 +213,30 @@ def select():
|
||||
nrows = db(query).count()
|
||||
if form.vars.update_check and form.vars.update_fields:
|
||||
db(query).update(**eval_in_global_env('dict(%s)'
|
||||
% form.vars.update_fields))
|
||||
% form.vars.update_fields))
|
||||
response.flash = T('%s %%{row} updated', nrows)
|
||||
elif form.vars.delete_check:
|
||||
db(query).delete()
|
||||
response.flash = T('%s %%{row} deleted', nrows)
|
||||
nrows = db(query).count()
|
||||
if orderby:
|
||||
rows = db(query,ignore_common_filters=True).select(limitby=(start, stop), orderby=eval_in_global_env(orderby))
|
||||
rows = db(query, ignore_common_filters=True).select(limitby=(
|
||||
start, stop), orderby=eval_in_global_env(orderby))
|
||||
else:
|
||||
rows = db(query,ignore_common_filters=True).select(limitby=(start, stop))
|
||||
rows = db(query, ignore_common_filters=True).select(
|
||||
limitby=(start, stop))
|
||||
except Exception, e:
|
||||
import traceback
|
||||
tb = traceback.format_exc()
|
||||
(rows, nrows) = ([], 0)
|
||||
response.flash = DIV(T('Invalid Query'),PRE(str(e)))
|
||||
response.flash = DIV(T('Invalid Query'), PRE(str(e)))
|
||||
# begin handle upload csv
|
||||
csv_table = table or request.vars.table
|
||||
if csv_table:
|
||||
formcsv = FORM(str(T('or import from csv file'))+" ",
|
||||
INPUT(_type='file',_name='csvfile'),
|
||||
INPUT(_type='hidden',_value=csv_table,_name='table'),
|
||||
INPUT(_type='submit',_value=T('import')))
|
||||
formcsv = FORM(str(T('or import from csv file')) + " ",
|
||||
INPUT(_type='file', _name='csvfile'),
|
||||
INPUT(_type='hidden', _value=csv_table, _name='table'),
|
||||
INPUT(_type='submit', _value=T('import')))
|
||||
else:
|
||||
formcsv = None
|
||||
if formcsv and formcsv.process().accepted:
|
||||
@@ -238,7 +245,7 @@ def select():
|
||||
request.vars.csvfile.file)
|
||||
response.flash = T('data uploaded')
|
||||
except Exception, e:
|
||||
response.flash = DIV(T('unable to parse csv file'),PRE(str(e)))
|
||||
response.flash = DIV(T('unable to parse csv file'), PRE(str(e)))
|
||||
# end handle upload csv
|
||||
|
||||
return dict(
|
||||
@@ -249,8 +256,9 @@ def select():
|
||||
nrows=nrows,
|
||||
rows=rows,
|
||||
query=request.vars.query,
|
||||
formcsv = formcsv,
|
||||
)
|
||||
formcsv=formcsv,
|
||||
tb=tb,
|
||||
)
|
||||
|
||||
|
||||
# ##########################################################
|
||||
@@ -260,14 +268,16 @@ def select():
|
||||
|
||||
def update():
|
||||
(db, table) = get_table(request)
|
||||
keyed = hasattr(db[table],'_primarykey')
|
||||
keyed = hasattr(db[table], '_primarykey')
|
||||
record = None
|
||||
if keyed:
|
||||
key = [f for f in request.vars if f in db[table]._primarykey]
|
||||
if key:
|
||||
record = db(db[table][key[0]] == request.vars[key[0]], ignore_common_filters=True).select().first()
|
||||
record = db(db[table][key[0]] == request.vars[key[
|
||||
0]], ignore_common_filters=True).select().first()
|
||||
else:
|
||||
record = db(db[table].id == request.args(2),ignore_common_filters=True).select().first()
|
||||
record = db(db[table].id == request.args(
|
||||
2), ignore_common_filters=True).select().first()
|
||||
|
||||
if not record:
|
||||
qry = query_by_table_type(table, db)
|
||||
@@ -277,20 +287,21 @@ def update():
|
||||
|
||||
if keyed:
|
||||
for k in db[table]._primarykey:
|
||||
db[table][k].writable=False
|
||||
db[table][k].writable = False
|
||||
|
||||
form = SQLFORM(db[table], record, deletable=True, delete_label=T('Check to delete'),
|
||||
ignore_rw=ignore_rw and not keyed,
|
||||
linkto=URL('select',
|
||||
form = SQLFORM(
|
||||
db[table], record, deletable=True, delete_label=T('Check to delete'),
|
||||
ignore_rw=ignore_rw and not keyed,
|
||||
linkto=URL('select',
|
||||
args=request.args[:1]), upload=URL(r=request,
|
||||
f='download', args=request.args[:1]))
|
||||
f='download', args=request.args[:1]))
|
||||
|
||||
if form.accepts(request.vars, session):
|
||||
session.flash = T('done!')
|
||||
qry = query_by_table_type(table, db)
|
||||
redirect(URL('select', args=request.args[:1],
|
||||
vars=dict(query=qry)))
|
||||
return dict(form=form,table=db[table])
|
||||
return dict(form=form, table=db[table])
|
||||
|
||||
|
||||
# ##########################################################
|
||||
@@ -301,11 +312,15 @@ def update():
|
||||
def state():
|
||||
return dict()
|
||||
|
||||
|
||||
def ccache():
|
||||
form = FORM(
|
||||
P(TAG.BUTTON(T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
|
||||
P(TAG.BUTTON(T("Clear RAM"), _type="submit", _name="ram", _value="ram")),
|
||||
P(TAG.BUTTON(T("Clear DISK"), _type="submit", _name="disk", _value="disk")),
|
||||
P(TAG.BUTTON(
|
||||
T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
|
||||
P(TAG.BUTTON(
|
||||
T("Clear RAM"), _type="submit", _name="ram", _value="ram")),
|
||||
P(TAG.BUTTON(
|
||||
T("Clear DISK"), _type="submit", _name="disk", _value="disk")),
|
||||
)
|
||||
|
||||
if form.accepts(request.vars, session):
|
||||
@@ -329,11 +344,16 @@ def ccache():
|
||||
redirect(URL(r=request))
|
||||
|
||||
try:
|
||||
from guppy import hpy; hp=hpy()
|
||||
from guppy import hpy
|
||||
hp = hpy()
|
||||
except ImportError:
|
||||
hp = False
|
||||
|
||||
import shelve, os, copy, time, math
|
||||
import shelve
|
||||
import os
|
||||
import copy
|
||||
import time
|
||||
import math
|
||||
from gluon import portalocker
|
||||
|
||||
ram = {
|
||||
@@ -378,9 +398,10 @@ def ccache():
|
||||
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
|
||||
|
||||
locker = open(os.path.join(request.folder,
|
||||
'cache/cache.lock'), 'a')
|
||||
'cache/cache.lock'), 'a')
|
||||
portalocker.lock(locker, portalocker.LOCK_EX)
|
||||
disk_storage = shelve.open(os.path.join(request.folder, 'cache/cache.shelve'))
|
||||
disk_storage = shelve.open(
|
||||
os.path.join(request.folder, 'cache/cache.shelve'))
|
||||
try:
|
||||
for key, value in disk_storage.items():
|
||||
if isinstance(value, dict):
|
||||
@@ -411,7 +432,8 @@ def ccache():
|
||||
total['misses'] = ram['misses'] + disk['misses']
|
||||
total['keys'] = ram['keys'] + disk['keys']
|
||||
try:
|
||||
total['ratio'] = total['hits'] * 100 / (total['hits'] + total['misses'])
|
||||
total['ratio'] = total['hits'] * 100 / (total['hits'] +
|
||||
total['misses'])
|
||||
except (KeyError, ZeroDivisionError):
|
||||
total['ratio'] = 0
|
||||
|
||||
@@ -437,6 +459,3 @@ def ccache():
|
||||
|
||||
return dict(form=form, total=total,
|
||||
ram=ram, disk=disk, object_stats=hp != False)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
## - call exposes all registered services (none by default)
|
||||
#########################################################################
|
||||
|
||||
|
||||
def index():
|
||||
"""
|
||||
example action using the internationalization operator T and flash
|
||||
@@ -20,6 +21,7 @@ def index():
|
||||
response.flash = T("Welcome to web2py!")
|
||||
return dict(message=T('Hello World'))
|
||||
|
||||
|
||||
def user():
|
||||
"""
|
||||
exposes:
|
||||
@@ -42,7 +44,7 @@ def download():
|
||||
allows downloading of uploaded files
|
||||
http://..../[app]/default/download/[filename]
|
||||
"""
|
||||
return response.download(request,db)
|
||||
return response.download(request, db)
|
||||
|
||||
|
||||
def call():
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
'book': ['books'],
|
||||
'is': ['are'],
|
||||
'man': ['men'],
|
||||
'miss': ['misses'],
|
||||
'person': ['people'],
|
||||
'quark': ['quarks'],
|
||||
'shop': ['shops'],
|
||||
|
||||
@@ -89,6 +89,7 @@
|
||||
'export as csv file': 'експортувати як файл csv',
|
||||
'FAQ': 'ЧаПи (FAQ)',
|
||||
'First name': "Ім'я",
|
||||
'Forgot username?': "Забули ім'я користувача?",
|
||||
'Forms and Validators': 'Форми та коректність даних',
|
||||
'Free Applications': 'Вільні додатки',
|
||||
'Group %(group_id)s created': 'Групу %(group_id)s створено',
|
||||
|
||||
@@ -16,7 +16,7 @@ else:
|
||||
## connect to Google BigTable (optional 'google:datastore://namespace')
|
||||
db = DAL('google:datastore')
|
||||
## store sessions and tickets there
|
||||
session.connect(request, response, db = db)
|
||||
session.connect(request, response, db=db)
|
||||
## or store session in Memcache, Redis, etc.
|
||||
## from gluon.contrib.memdb import MEMDB
|
||||
## from google.appengine.api.memcache import Client
|
||||
@@ -47,7 +47,7 @@ crud, service, plugins = Crud(db), Service(), PluginManager()
|
||||
auth.define_tables(username=False, signature=False)
|
||||
|
||||
## configure email
|
||||
mail=auth.settings.mailer
|
||||
mail = auth.settings.mailer
|
||||
mail.settings.server = 'logging' or 'smtp.gmail.com:587'
|
||||
mail.settings.sender = 'you@gmail.com'
|
||||
mail.settings.login = 'username:password'
|
||||
@@ -60,7 +60,7 @@ auth.settings.reset_password_requires_verification = True
|
||||
## if you need to use OpenID, Facebook, MySpace, Twitter, Linkedin, etc.
|
||||
## register with janrain.com, write your domain:api_key in private/janrain.key
|
||||
from gluon.contrib.login_methods.rpx_account import use_janrain
|
||||
use_janrain(auth,filename='private/janrain.key')
|
||||
use_janrain(auth, filename='private/janrain.key')
|
||||
|
||||
#########################################################################
|
||||
## Define your tables below (or better in another model file) for example
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
## Customize your APP title, subtitle and menus here
|
||||
#########################################################################
|
||||
|
||||
response.title = ' '.join(word.capitalize() for word in request.application.split('_'))
|
||||
response.title = ' '.join(
|
||||
word.capitalize() for word in request.application.split('_'))
|
||||
response.subtitle = T('customize me!')
|
||||
|
||||
## read more at http://dev.w3.org/html5/markup/meta.name.html
|
||||
@@ -22,80 +23,114 @@ response.google_analytics_id = None
|
||||
#########################################################################
|
||||
|
||||
response.menu = [
|
||||
(T('Home'), False, URL('default','index'), [])
|
||||
]
|
||||
(T('Home'), False, URL('default', 'index'), [])
|
||||
]
|
||||
|
||||
#########################################################################
|
||||
## provide shortcuts for development. remove in production
|
||||
#########################################################################
|
||||
|
||||
|
||||
def _():
|
||||
# shortcuts
|
||||
app = request.application
|
||||
ctr = request.controller
|
||||
# useful links to internal and external resources
|
||||
response.menu+=[
|
||||
(SPAN('web2py',_style='color:yellow'),False, 'http://web2py.com', [
|
||||
(T('My Sites'),False,URL('admin','default','site')),
|
||||
(T('This App'),False,URL('admin','default','design/%s' % app), [
|
||||
(T('Controller'),False,
|
||||
URL('admin','default','edit/%s/controllers/%s.py' % (app,ctr))),
|
||||
(T('View'),False,
|
||||
URL('admin','default','edit/%s/views/%s' % (app,response.view))),
|
||||
(T('Layout'),False,
|
||||
URL('admin','default','edit/%s/views/layout.html' % app)),
|
||||
(T('Stylesheet'),False,
|
||||
URL('admin','default','edit/%s/static/css/web2py.css' % app)),
|
||||
(T('DB Model'),False,
|
||||
URL('admin','default','edit/%s/models/db.py' % app)),
|
||||
(T('Menu Model'),False,
|
||||
URL('admin','default','edit/%s/models/menu.py' % app)),
|
||||
(T('Database'),False, URL(app,'appadmin','index')),
|
||||
(T('Errors'),False, URL('admin','default','errors/' + app)),
|
||||
(T('About'),False, URL('admin','default','about/' + app)),
|
||||
response.menu += [
|
||||
(SPAN('web2py', _class='highlighted'), False, 'http://web2py.com', [
|
||||
(T('My Sites'), False, URL('admin', 'default', 'site')),
|
||||
(T('This App'), False, URL('admin', 'default', 'design/%s' % app), [
|
||||
(T('Controller'), False,
|
||||
URL(
|
||||
'admin', 'default', 'edit/%s/controllers/%s.py' % (app, ctr))),
|
||||
(T('View'), False,
|
||||
URL(
|
||||
'admin', 'default', 'edit/%s/views/%s' % (app, response.view))),
|
||||
(T('Layout'), False,
|
||||
URL(
|
||||
'admin', 'default', 'edit/%s/views/layout.html' % app)),
|
||||
(T('Stylesheet'), False,
|
||||
URL(
|
||||
'admin', 'default', 'edit/%s/static/css/web2py.css' % app)),
|
||||
(T('DB Model'), False,
|
||||
URL(
|
||||
'admin', 'default', 'edit/%s/models/db.py' % app)),
|
||||
(T('Menu Model'), False,
|
||||
URL(
|
||||
'admin', 'default', 'edit/%s/models/menu.py' % app)),
|
||||
(T('Database'), False, URL(app, 'appadmin', 'index')),
|
||||
(T('Errors'), False, URL(
|
||||
'admin', 'default', 'errors/' + app)),
|
||||
(T('About'), False, URL(
|
||||
'admin', 'default', 'about/' + app)),
|
||||
]),
|
||||
('web2py.com', False, 'http://www.web2py.com', [
|
||||
(T('Download'), False,
|
||||
'http://www.web2py.com/examples/default/download'),
|
||||
(T('Support'), False,
|
||||
'http://www.web2py.com/examples/default/support'),
|
||||
(T('Demo'), False, 'http://web2py.com/demo_admin'),
|
||||
(T('Quick Examples'), False,
|
||||
'http://web2py.com/examples/default/examples'),
|
||||
(T('FAQ'), False, 'http://web2py.com/AlterEgo'),
|
||||
(T('Videos'), False,
|
||||
'http://www.web2py.com/examples/default/videos/'),
|
||||
(T('Free Applications'),
|
||||
False, 'http://web2py.com/appliances'),
|
||||
(T('Plugins'), False, 'http://web2py.com/plugins'),
|
||||
(T('Layouts'), False, 'http://web2py.com/layouts'),
|
||||
(T('Recipes'), False, 'http://web2pyslices.com/'),
|
||||
(T('Semantic'), False, 'http://web2py.com/semantic'),
|
||||
]),
|
||||
(T('Documentation'), False, 'http://www.web2py.com/book', [
|
||||
(T('Preface'), False,
|
||||
'http://www.web2py.com/book/default/chapter/00'),
|
||||
(T('Introduction'), False,
|
||||
'http://www.web2py.com/book/default/chapter/01'),
|
||||
(T('Python'), False,
|
||||
'http://www.web2py.com/book/default/chapter/02'),
|
||||
(T('Overview'), False,
|
||||
'http://www.web2py.com/book/default/chapter/03'),
|
||||
(T('The Core'), False,
|
||||
'http://www.web2py.com/book/default/chapter/04'),
|
||||
(T('The Views'), False,
|
||||
'http://www.web2py.com/book/default/chapter/05'),
|
||||
(T('Database'), False,
|
||||
'http://www.web2py.com/book/default/chapter/06'),
|
||||
(T('Forms and Validators'), False,
|
||||
'http://www.web2py.com/book/default/chapter/07'),
|
||||
(T('Email and SMS'), False,
|
||||
'http://www.web2py.com/book/default/chapter/08'),
|
||||
(T('Access Control'), False,
|
||||
'http://www.web2py.com/book/default/chapter/09'),
|
||||
(T('Services'), False,
|
||||
'http://www.web2py.com/book/default/chapter/10'),
|
||||
(T('Ajax Recipes'), False,
|
||||
'http://www.web2py.com/book/default/chapter/11'),
|
||||
(T('Components and Plugins'), False,
|
||||
'http://www.web2py.com/book/default/chapter/12'),
|
||||
(T('Deployment Recipes'), False,
|
||||
'http://www.web2py.com/book/default/chapter/13'),
|
||||
(T('Other Recipes'), False,
|
||||
'http://www.web2py.com/book/default/chapter/14'),
|
||||
(T('Buy this book'), False,
|
||||
'http://stores.lulu.com/web2py'),
|
||||
]),
|
||||
(T('Community'), False, None, [
|
||||
(T('Groups'), False,
|
||||
'http://www.web2py.com/examples/default/usergroups'),
|
||||
(T('Twitter'), False, 'http://twitter.com/web2py'),
|
||||
(T('Live Chat'), False,
|
||||
'http://webchat.freenode.net/?channels=web2py'),
|
||||
]),
|
||||
('web2py.com',False,'http://www.web2py.com', [
|
||||
(T('Download'),False,'http://www.web2py.com/examples/default/download'),
|
||||
(T('Support'),False,'http://www.web2py.com/examples/default/support'),
|
||||
(T('Demo'),False,'http://web2py.com/demo_admin'),
|
||||
(T('Quick Examples'),False,'http://web2py.com/examples/default/examples'),
|
||||
(T('FAQ'),False,'http://web2py.com/AlterEgo'),
|
||||
(T('Videos'),False,'http://www.web2py.com/examples/default/videos/'),
|
||||
(T('Free Applications'),False,'http://web2py.com/appliances'),
|
||||
(T('Plugins'),False,'http://web2py.com/plugins'),
|
||||
(T('Layouts'),False,'http://web2py.com/layouts'),
|
||||
(T('Recipes'),False,'http://web2pyslices.com/'),
|
||||
(T('Semantic'),False,'http://web2py.com/semantic'),
|
||||
]),
|
||||
(T('Documentation'),False,'http://www.web2py.com/book', [
|
||||
(T('Preface'),False,'http://www.web2py.com/book/default/chapter/00'),
|
||||
(T('Introduction'),False,'http://www.web2py.com/book/default/chapter/01'),
|
||||
(T('Python'),False,'http://www.web2py.com/book/default/chapter/02'),
|
||||
(T('Overview'),False,'http://www.web2py.com/book/default/chapter/03'),
|
||||
(T('The Core'),False,'http://www.web2py.com/book/default/chapter/04'),
|
||||
(T('The Views'),False,'http://www.web2py.com/book/default/chapter/05'),
|
||||
(T('Database'),False,'http://www.web2py.com/book/default/chapter/06'),
|
||||
(T('Forms and Validators'),False,'http://www.web2py.com/book/default/chapter/07'),
|
||||
(T('Email and SMS'),False,'http://www.web2py.com/book/default/chapter/08'),
|
||||
(T('Access Control'),False,'http://www.web2py.com/book/default/chapter/09'),
|
||||
(T('Services'),False,'http://www.web2py.com/book/default/chapter/10'),
|
||||
(T('Ajax Recipes'),False,'http://www.web2py.com/book/default/chapter/11'),
|
||||
(T('Components and Plugins'),False,'http://www.web2py.com/book/default/chapter/12'),
|
||||
(T('Deployment Recipes'),False,'http://www.web2py.com/book/default/chapter/13'),
|
||||
(T('Other Recipes'),False,'http://www.web2py.com/book/default/chapter/14'),
|
||||
(T('Buy this book'),False,'http://stores.lulu.com/web2py'),
|
||||
]),
|
||||
(T('Community'),False, None, [
|
||||
(T('Groups'),False,'http://www.web2py.com/examples/default/usergroups'),
|
||||
(T('Twitter'),False,'http://twitter.com/web2py'),
|
||||
(T('Live Chat'),False,'http://webchat.freenode.net/?channels=web2py'),
|
||||
]),
|
||||
(T('Plugins'),False,None, [
|
||||
('plugin_wiki',False,'http://web2py.com/examples/default/download'),
|
||||
(T('Other Plugins'),False,'http://web2py.com/plugins'),
|
||||
(T('Layout Plugins'),False,'http://web2py.com/layouts'),
|
||||
(T('Plugins'), False, None, [
|
||||
('plugin_wiki', False,
|
||||
'http://web2py.com/examples/default/download'),
|
||||
(T('Other Plugins'), False,
|
||||
'http://web2py.com/plugins'),
|
||||
(T('Layout Plugins'),
|
||||
False, 'http://web2py.com/layouts'),
|
||||
])
|
||||
]
|
||||
)]
|
||||
_()
|
||||
|
||||
|
||||
@@ -37,4 +37,3 @@ routers = {
|
||||
#NOTE! To change language in your application using these rules add this line
|
||||
#in one of your models files:
|
||||
# if request.uri_language: T.force(request.uri_language)
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -61,7 +61,7 @@ input[type=text],input[type=password],select{width:300px; margin-right:5px}
|
||||
border-top:1px #DEDEDE solid;
|
||||
}
|
||||
.header {
|
||||
// background:<fill here for header image>;
|
||||
/* background:<fill here for header image>; */
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,6 @@ fieldset {padding:16px; border-top:1px #DEDEDE solid}
|
||||
fieldset legend {text-transform:uppercase; font-weight:bold; padding:4px 16px 4px 16px; background:#f1f1f1}
|
||||
|
||||
/* fix ie problem with menu */
|
||||
.ie-lte7 .topbar .container {z-index:2}
|
||||
|
||||
td.w2p_fw {padding-bottom:1px}
|
||||
td.w2p_fl,td.w2p_fw,td.w2p_fc {vertical-align:top}
|
||||
@@ -183,7 +182,7 @@ div.error {
|
||||
* will look better with the declarations below
|
||||
* if needed to remove base.css consider keeping these following lines in some css file.
|
||||
*/
|
||||
// .web2py_table {border:1px solid #ccc}
|
||||
/* .web2py_table {border:1px solid #ccc} */
|
||||
.web2py_paginator {}
|
||||
.web2py_grid {width:100%}
|
||||
.web2py_grid table {width:100%}
|
||||
@@ -296,10 +295,16 @@ li.w2p_grid_breadcrumb_elem {
|
||||
.web2py_console input, .web2py_console select,
|
||||
.web2py_console a { margin: 2px; }
|
||||
|
||||
.ie9 #w2p_query_panel {padding-bottom:2px}
|
||||
|
||||
#wiki_page_body {
|
||||
width: 600px;
|
||||
height: auto;
|
||||
min-height: 400px;
|
||||
}
|
||||
}
|
||||
|
||||
/* fix some IE problems */
|
||||
|
||||
.ie-lte7 .topbar .container {z-index:2}
|
||||
.ie-lte8 div.flash{ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#222222', endColorstr='#000000', GradientType=0 ); }
|
||||
.ie-lte8 div.flash:hover {filter:alpha(opacity=25);}
|
||||
.ie9 #w2p_query_panel {padding-bottom:2px}
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
#navbar .auth_navbar, #navbar .auth_navbar a {color:inherit;}
|
||||
/*=============================================================
|
||||
CUSTOM RULES
|
||||
==============================================================*/
|
||||
|
||||
div.flash.flash-center {
|
||||
left: 25%;
|
||||
right: 25%;
|
||||
}
|
||||
|
||||
div.flash.flash-top, div.flash.flash-top:hover {
|
||||
position: relative;
|
||||
display: block;
|
||||
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);
|
||||
text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);
|
||||
color:#865100;
|
||||
background:#feea9a;
|
||||
border:1px solid;
|
||||
@@ -24,154 +23,209 @@ div.flash.flash-top, div.flash.flash-top:hover {
|
||||
border-radius:0;
|
||||
opacity:1;
|
||||
}
|
||||
|
||||
/* bootstrap dropdown */
|
||||
|
||||
.dropdown-menu ul {
|
||||
left: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
visibility: hidden;
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
.dropdown-menu li:hover ul {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
#header {
|
||||
margin-top: 60px;
|
||||
}
|
||||
|
||||
#header{margin-top:60px;}
|
||||
.mastheader h1 {
|
||||
margin-bottom: 9px;
|
||||
font-size: 81px;
|
||||
font-weight: bold;
|
||||
letter-spacing: -1px;
|
||||
line-height: 1;
|
||||
margin-bottom:9px;
|
||||
font-size:81px;
|
||||
font-weight:bold;
|
||||
letter-spacing:-1px;
|
||||
line-height:1;
|
||||
font-size:54px;
|
||||
}
|
||||
|
||||
.mastheader h1 {
|
||||
font-size: 54px;
|
||||
}
|
||||
|
||||
.mastheader small {
|
||||
font-size: 20px;
|
||||
font-weight: 300;
|
||||
font-size:20px;
|
||||
font-weight:300;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.navbar .dropdown-menu ul:after {
|
||||
border-top: 6px solid transparent;
|
||||
border-left: none;
|
||||
border-right: 6px solid #fff;
|
||||
border-bottom: 6px solid transparent;
|
||||
left: 10px;
|
||||
top: 6px;
|
||||
left: -6px;
|
||||
}
|
||||
|
||||
.dropdown-menu span{
|
||||
/* 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;
|
||||
}
|
||||
|
||||
.chevron-right {
|
||||
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-right:-13px;
|
||||
margin-top: 7px;
|
||||
float:right;
|
||||
}
|
||||
|
||||
.open > .dropdown-menu ul { /* fix menu issue when BS2.0.4 is applied */
|
||||
display: block;
|
||||
}
|
||||
|
||||
.ie-lte7 #navbar .auth_navbar, #navbar .auth_navbar a {color:expression(this.parentNode.currentStyle['color']); /* ie7 doesn't support inherit */}
|
||||
|
||||
#navbar .auth_navbar a:hover {color:white;text-decoration:none;} /* this overwrite bootswatch */
|
||||
ul#navbar{padding:0;} /*reset ul padding */
|
||||
ul#navbar>.auth_navbar{display:inline-block;padding:5px;} /* set padding of span.auth_navbar inside ul*/
|
||||
|
||||
body {
|
||||
height:auto; /*to avoid vertical scroll bar*/
|
||||
}
|
||||
|
||||
h1,h2,h3,h4,h5,h6 {font-family: inherit;}
|
||||
|
||||
li {margin-bottom: 0;} /*bootswatch*/
|
||||
|
||||
.auth_navbar, .navbar .btn-group { padding:0; }
|
||||
|
||||
[class^="icon-"],[class*=" icon-"]{background-image:url("../images/glyphicons-halflings.png")} /* right folder for bootstrap black images/icons */
|
||||
.icon-white{background-image:url("../images/glyphicons-halflings-white.png");} /* right folder for bootstrap white images/icons */
|
||||
|
||||
.navbar-inner{
|
||||
-webkit-border-radius: 0;
|
||||
-moz-border-radius: 0;
|
||||
border-radius: 0;
|
||||
position:relative;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 979px) {
|
||||
body {
|
||||
padding-top: 0px;
|
||||
}
|
||||
|
||||
#navbar{bottom:-10px;left:4px;}
|
||||
|
||||
div.flash {
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
.dropdown-menu ul {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
div.error_wrapper {
|
||||
margin-bottom: 9px;
|
||||
}
|
||||
div.error {
|
||||
/* 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 .inline-help{color:#3A87AD;}
|
||||
div.controls .error_wrapper+.inline-help{margin-left:-99999px;}
|
||||
/* 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;}
|
||||
|
||||
input[type="button"], input[type="submit"] {
|
||||
// to be fixed
|
||||
/*=============================================================
|
||||
OVERRIDING WEB2PY.CSS RULES
|
||||
==============================================================*/
|
||||
|
||||
/* reset to default */
|
||||
a{white-space:normal;}
|
||||
li{margin-bottom:0;}
|
||||
textarea,button{display:block;}
|
||||
/*reset ul padding */
|
||||
ul#navbar{padding:0;}
|
||||
/* label aligned to related input */
|
||||
td.w2p_fl,td.w2p_fc {padding:0;}
|
||||
#web2py_user_form td{vertical-align:middle;}
|
||||
|
||||
/*=============================================================
|
||||
OVERRIDING BOOTSTRAP.CSS RULES
|
||||
==============================================================*/
|
||||
|
||||
/* because web2py handles this via js */
|
||||
.hidden{visibility:visible;}
|
||||
/* right folder for bootstrap black images/icons */
|
||||
[class^="icon-"],[class*=" icon-"]{
|
||||
background-image:url("../images/glyphicons-halflings.png")
|
||||
}
|
||||
/* right folder for bootstrap white images/icons */
|
||||
.icon-white,
|
||||
.nav-tabs > .active > a > [class^="icon-"],
|
||||
.nav-tabs > .active > a > [class*=" icon-"],
|
||||
.nav-pills > .active > a > [class^="icon-"],
|
||||
.nav-pills > .active > a > [class*=" icon-"],
|
||||
.nav-list > .active > a > [class^="icon-"],
|
||||
.nav-list > .active > a > [class*=" icon-"],
|
||||
.navbar-inverse .nav > .active > a > [class^="icon-"],
|
||||
.navbar-inverse .nav > .active > a > [class*=" icon-"],
|
||||
.dropdown-menu > li > a:hover > [class^="icon-"],
|
||||
.dropdown-menu > li > a:hover > [class*=" icon-"],
|
||||
.dropdown-menu > .active > a > [class^="icon-"],
|
||||
.dropdown-menu > .active > a > [class*=" icon-"] {
|
||||
background-image:url("../images/glyphicons-halflings-white.png");
|
||||
}
|
||||
/* bootstrap has a label as input's wrapper while web2py has a div */
|
||||
div>input[type="radio"],div>input[type="checkbox"]{margin:0;}
|
||||
/* bootstrap has button instead of input */
|
||||
input[type="button"], input[type="submit"]{margin-right:8px;}
|
||||
|
||||
/*=============================================================
|
||||
RULES FOR SOLVING CONFLICTS BETWEEN WEB2PY.CSS AND BOOTSTRAP.CSS
|
||||
==============================================================*/
|
||||
|
||||
/*when formstyle=table3cols*/
|
||||
tr#auth_user_remember__row>td.w2p_fw>div{padding-bottom:8px;}
|
||||
td.w2p_fw div>label{vertical-align:middle;}
|
||||
td.w2p_fc {padding-bottom:5px;}
|
||||
/*when formstyle=divs*/
|
||||
div#auth_user_remember__row{margin-top:4px;}
|
||||
div#auth_user_remember__row>.w2p_fl{display:none;}
|
||||
div#auth_user_remember__row>.w2p_fw{min-height:39px;}
|
||||
div.w2p_fw,div.w2p_fc{
|
||||
display:inline-block;
|
||||
vertical-align:middle;
|
||||
margin-bottom:0;
|
||||
}
|
||||
div.w2p_fc{
|
||||
padding-left:5px;
|
||||
margin-top:-8px;
|
||||
}
|
||||
/*when formstyle=ul*/
|
||||
form>ul{
|
||||
list-style:none;
|
||||
margin:0;
|
||||
}
|
||||
li#auth_user_remember__row{margin-top:4px;}
|
||||
li#auth_user_remember__row>.w2p_fl{display:none;}
|
||||
li#auth_user_remember__row>.w2p_fw{min-height:39px;}
|
||||
/*when formstyle=bootstrap*/
|
||||
#auth_user_remember__row label.checkbox{display:block;}
|
||||
span.inline-help{display:inline-block;}
|
||||
input[type="text"].input-xlarge,input[type="password"].input-xlarge{width:270px;}
|
||||
/*when recaptcha is used*/
|
||||
#recaptcha{min-height:30px;display:inline-block;margin-bottom:0;line-height:30px;vertical-align:middle;}
|
||||
td>#recaptcha{margin-bottom:6px;}
|
||||
div>#recaptcha{margin-bottom:9px;}
|
||||
div.control-group.error{
|
||||
width:auto;
|
||||
background:transparent;
|
||||
border:0;
|
||||
color:inherit;
|
||||
padding:0;
|
||||
background-repeat:repeat;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 479px) {
|
||||
body {
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
/*=============================================================
|
||||
OTHER RULES
|
||||
==============================================================*/
|
||||
|
||||
.navbar-inner{
|
||||
position:relative; /*unnecessary ??*/
|
||||
}
|
||||
/* 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{bottom:-10px;left:4px;}
|
||||
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;
|
||||
.navbar-fixed-top,.navbar-fixed-bottom {
|
||||
margin-left:-10px;
|
||||
margin-right:-10px;
|
||||
}
|
||||
|
||||
input[type="text"], input[type="password"], select {
|
||||
width: 95%;
|
||||
input[type="text"],input[type="password"],select{
|
||||
width:95%;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,23 @@
|
||||
/*=============================================================
|
||||
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;
|
||||
@@ -15,8 +35,7 @@
|
||||
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;
|
||||
@@ -35,4 +54,69 @@ ul.dropdown-menu li.dropdown > a:after {
|
||||
|
||||
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;}
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.9 KiB |
BIN
applications/welcome/static/images/gplus-32.png
Normal file
BIN
applications/welcome/static/images/gplus-32.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
File diff suppressed because one or more lines are too long
@@ -21,8 +21,8 @@ jQuery(function(){
|
||||
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 buzz = 'http://www.google.com/reader/link?url='+url+'&title='+title+'&srcURL='+host;
|
||||
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="'+buzz+'" id="buzz" title="Share on Buzz"><img src="'+path+'/google-buzz.png" alt="Share on Buzz" width="32" height="32" /></a></div></div>';
|
||||
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');
|
||||
|
||||
@@ -55,7 +55,7 @@ function web2py_event_handlers() {
|
||||
jQuery(function() {
|
||||
var flash = jQuery('.flash');
|
||||
flash.hide();
|
||||
if(flash.html()) flash.append('<span style="float:right;">×<span>').slideDown();
|
||||
if(flash.html()) flash.append('<span style="float:right;">×</span>').slideDown();
|
||||
web2py_ajax_init(document);
|
||||
web2py_event_handlers();
|
||||
});
|
||||
@@ -67,20 +67,20 @@ function web2py_trap_form(action,target) {
|
||||
form.submit(function(e){
|
||||
jQuery('.flash').hide().html('');
|
||||
web2py_ajax_page('post',action,form.serialize(),target);
|
||||
e.preventDefault();
|
||||
e.preventDefault();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function web2py_trap_link(target) {
|
||||
jQuery('#'+target+' a.w2p_trap').each(function(i){
|
||||
var link=jQuery(this);
|
||||
link.click(function(e) {
|
||||
jQuery('.flash').hide().html('');
|
||||
web2py_ajax_page('get',link.attr('href'),[],target);
|
||||
e.preventDefault();
|
||||
});
|
||||
});
|
||||
var link=jQuery(this);
|
||||
link.click(function(e) {
|
||||
jQuery('.flash').hide().html('');
|
||||
web2py_ajax_page('get',link.attr('href'),[],target);
|
||||
e.preventDefault();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function web2py_ajax_page(method, action, data, target) {
|
||||
@@ -101,9 +101,9 @@ function web2py_ajax_page(method, action, data, target) {
|
||||
web2py_trap_link(target);
|
||||
web2py_ajax_init('#'+target);
|
||||
if(command)
|
||||
eval(decodeURIComponent(command));
|
||||
eval(decodeURIComponent(command));
|
||||
if(flash)
|
||||
jQuery('.flash').html(decodeURIComponent(flash)).slideDown();
|
||||
jQuery('.flash').html(decodeURIComponent(flash)).slideDown();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -151,11 +151,11 @@ function web2py_component(action, target, timeout, times){
|
||||
}
|
||||
} else {
|
||||
// run once (no timeout specified)
|
||||
element.reload_counter = Infinity;
|
||||
element.reload_counter = Infinity;
|
||||
web2py_ajax_page('get', action, null, target);
|
||||
} }); }
|
||||
|
||||
function web2py_comet(url,onmessage,onopen,onclose) {
|
||||
function web2py_websocket(url,onmessage,onopen,onclose) {
|
||||
if ("WebSocket" in window) {
|
||||
var ws = new WebSocket(url);
|
||||
ws.onopen = onopen?onopen:(function(){});
|
||||
@@ -165,3 +165,38 @@ function web2py_comet(url,onmessage,onopen,onclose) {
|
||||
} else return false; // not supported
|
||||
}
|
||||
|
||||
|
||||
function web2py_calc_entropy(mystring) {
|
||||
//calculate a simple entropy for a given string
|
||||
var csets = new Array(
|
||||
'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
||||
'0123456789', '!@#$\%^&*()', '~`-_=+[]{}\|;:\'",.<>?/',
|
||||
'0123456789abcdefghijklmnopqrstuvwxyz');
|
||||
var score = 0, other = {}, seen = {}, lastset = null, mystringlist = mystring.split('');
|
||||
for (var i=0;i<mystringlist.length;i++) { // classify this character
|
||||
var c = mystringlist[i], inset=5;
|
||||
for(var j = 0; j<csets.length; j++)
|
||||
if (csets[j].indexOf(c) != -1) {inset = j; break;}
|
||||
//calculate effect of character on alphabet size
|
||||
if(!(inset in seen)) {seen[inset] = 1;score += csets[inset].length;}
|
||||
else if (!(c in other)) {score += 1;other[c] = 1;}
|
||||
if (inset != lastset) {score += 1;lastset = inset;}
|
||||
}
|
||||
var entropy = mystring.length*Math.log(score)/0.6931471805599453;
|
||||
return Math.round(entropy*100)/100
|
||||
}
|
||||
|
||||
function web2py_validate_entropy(myfield, req_entropy) {
|
||||
var validator = function () {
|
||||
var v = (web2py_calc_entropy(myfield.val())||0)/req_entropy;
|
||||
var r=0,g=0,b=0,rs=function(x){return Math.round(x*15).toString(16)};
|
||||
if(v<=0.5) {r=1.0; g=2.0*v;}
|
||||
else {r=(1.0-2.0*(Math.max(v,0)-0.5)); g=1.0;}
|
||||
var color = '#'+rs(r)+rs(g)+rs(b);
|
||||
myfield.css('background-color',color);
|
||||
entropy_callback = myfield.data('entropy_callback');
|
||||
if(entropy_callback) entropy_callback(v);
|
||||
}
|
||||
if(!myfield.hasClass('entropy_check')) myfield.on('keyup', validator).on('keydown', validator).addClass('entropy_check');
|
||||
}
|
||||
|
||||
|
||||
28
applications/welcome/static/js/web2py_bootstrap.js
Normal file
28
applications/welcome/static/js/web2py_bootstrap.js
Normal file
@@ -0,0 +1,28 @@
|
||||
// this code improves bootstrap menus and adds dropdown support
|
||||
jQuery(function(){
|
||||
jQuery('.nav>li>a').each(function(){
|
||||
if(jQuery(this).parent().find('ul').length)
|
||||
jQuery(this).attr({'class':'dropdown-toggle','data-toggle':'dropdown'}).append('<b class="caret"></b>');
|
||||
});
|
||||
jQuery('.nav li li').each(function(){
|
||||
if(jQuery(this).find('ul').length)
|
||||
jQuery(this).addClass('dropdown-submenu');
|
||||
});
|
||||
function hoverMenu(){
|
||||
var wid = document.documentElement.clientWidth; //faster than $(window).width() and cross browser
|
||||
if (wid>=980){
|
||||
jQuery('ul.nav a.dropdown-toggle').parent().hover(function(){
|
||||
mi = jQuery(this).addClass('open');
|
||||
mi.children('.dropdown-menu').stop(true, true).delay(200).fadeIn(400);
|
||||
}, function(){
|
||||
mi = jQuery(this);
|
||||
mi.children('.dropdown-menu').stop(true, true).delay(200).fadeOut(function(){mi.removeClass('open')});
|
||||
});
|
||||
};
|
||||
}
|
||||
hoverMenu(); // first page load
|
||||
jQuery(window).resize(hoverMenu); // on resize event
|
||||
jQuery('ul.nav li.dropdown a').click(function(){window.location=jQuery(this).attr('href');});
|
||||
// make all buttons bootstrap buttons
|
||||
jQuery('button, form input[type="submit"], form input[type="button"]').addClass('btn');
|
||||
});
|
||||
@@ -27,7 +27,7 @@
|
||||
{{pass}}
|
||||
{{else:}}
|
||||
{{qry=''}}
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
<tr>
|
||||
<th style="font-size: 1.75em;">
|
||||
@@ -37,13 +37,19 @@
|
||||
{{=A(str(T('New Record')),_href=URL('insert',args=[db,table]),_class="btn")}}
|
||||
</td>
|
||||
</tr>
|
||||
{{pass}}
|
||||
</table>
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
</table>
|
||||
|
||||
{{elif request.function=='select':}}
|
||||
<h2>{{=XML(str(T("Database %s select"))%A(request.args[0],_href=URL('index'))) }}
|
||||
</h2>
|
||||
{{if tb:}}
|
||||
<h3>{{=T('Traceback')}}</h3>
|
||||
<pre>
|
||||
{{=tb}}
|
||||
</pre>
|
||||
{{pass}}
|
||||
{{if table:}}
|
||||
{{=A(str(T('New Record')),_href=URL('insert',args=[request.args[0],table]),_class="btn")}}<br/><br/>
|
||||
<h3>{{=T("Rows in Table")}}</h3><br/>
|
||||
@@ -149,7 +155,7 @@
|
||||
<h4>{{=T("RAM")}}</h4>
|
||||
<p>{{=T.M("Number of entries: **%s**", ram['entries'])}}</p>
|
||||
{{if ram['entries'] > 0:}}
|
||||
<p>{{=T.M("Hit Ratio: **%(ratio)s%%** (**%(hits)s** %{hit(hits)} and **%(misses)s** %%{miss(misses)})",
|
||||
<p>{{=T.M("Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})",
|
||||
dict( ratio=ram['ratio'], hits=ram['hits'], misses=ram['misses']))}}
|
||||
</p>
|
||||
<p>
|
||||
|
||||
@@ -4,16 +4,20 @@
|
||||
{{
|
||||
if request.args(0)=='login':
|
||||
if not 'register' in auth.settings.actions_disabled:
|
||||
form.add_button(T('Register'),URL(args='register'))
|
||||
form.add_button(T('Register'),URL(args='register'),_class='btn')
|
||||
pass
|
||||
if not 'request_reset_password' in auth.settings.actions_disabled:
|
||||
form.add_button(T('Lost Password'),URL(args='request_reset_password'))
|
||||
form.add_button(T('Lost Password'),URL(args='request_reset_password'),_class='btn')
|
||||
pass
|
||||
pass
|
||||
=form
|
||||
}}
|
||||
</div>
|
||||
<script language="javascript"><!--
|
||||
jQuery("#web2py_user_form input:visible:enabled:first").focus();
|
||||
//--></script>
|
||||
|
||||
jQuery("#web2py_user_form input:visible:enabled:first").focus();
|
||||
{{if request.args(0)=='register':}}
|
||||
web2py_validate_entropy(jQuery('#auth_user_password'),100);
|
||||
{{elif request.args(0)=='change_password':}}
|
||||
web2py_validate_entropy(jQuery('#no_table_new_password'),100);
|
||||
{{pass}}
|
||||
//--></script>
|
||||
|
||||
@@ -1 +1 @@
|
||||
{{from gluon.serializers import xml}}{{=XML(xml(response._vars,quote=False))}}
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>{{from gluon.serializers import xml}}{{=XML(xml(response._vars,quote=False))}}
|
||||
|
||||
@@ -39,10 +39,10 @@
|
||||
<script src="{{=URL('static','js/modernizr.custom.js')}}"></script>
|
||||
|
||||
<!-- include stylesheets -->
|
||||
{{
|
||||
{{
|
||||
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.css'))
|
||||
response.files.append(URL('static','css/web2py_bootstrap.css'))
|
||||
}}
|
||||
|
||||
@@ -66,17 +66,17 @@
|
||||
|
||||
<body>
|
||||
<!-- Navbar ================================================== -->
|
||||
<div class="navbar navbar-fixed-top">
|
||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="flash">{{=response.flash or ''}}</div>
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<!-- the next tag is necessary for bootstrap menus, do not remove -->
|
||||
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
|
||||
<button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</a>
|
||||
<a class="brand" href="#">web2py™ </a>
|
||||
</button>
|
||||
<a class="brand" href="http://www.web2py.com/"><b>web<span>2</span>py</b>™ </a>
|
||||
<ul id="navbar" class="nav pull-right">{{='auth' in globals() and auth.navbar(mode="dropdown") or ''}}</ul>
|
||||
<div class="nav-collapse">
|
||||
{{is_mobile=request.user_agent().is_mobile}}
|
||||
@@ -146,30 +146,8 @@
|
||||
|
||||
<!-- The javascript =============================================
|
||||
(Placed at the end of the document so the pages load faster) -->
|
||||
<script>
|
||||
// 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).children('a').contents().before('<i class="chevron-right"></i>');
|
||||
});
|
||||
if(jQuery(document).width()>=980) {
|
||||
jQuery('ul.nav li.dropdown').hover(function() {
|
||||
jQuery(this).find('.dropdown-menu').stop(true, true).delay(200).fadeIn();
|
||||
}, function() {
|
||||
jQuery(this).find('.dropdown-menu').stop(true, true).delay(200).fadeOut();
|
||||
});
|
||||
}
|
||||
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').css({'margin-right':'2px','margin-bottom':'2px'});
|
||||
});
|
||||
</script>
|
||||
<script src="{{=URL('static','js/bootstrap.min.js')}}"></script>
|
||||
<script src="{{=URL('static','js/web2py_bootstrap.js')}}"></script>
|
||||
<!--[if lt IE 7 ]>
|
||||
<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>
|
||||
|
||||
@@ -56,13 +56,8 @@ import wsgiref.handlers
|
||||
|
||||
path = os.path.dirname(os.path.abspath(__file__))
|
||||
os.chdir(path)
|
||||
sys.path = [path]+[p for p in sys.path if not p==path]
|
||||
sys.path = [path] + [p for p in sys.path if not p == path]
|
||||
|
||||
import gluon.main
|
||||
|
||||
wsgiref.handlers.CGIHandler().run(gluon.main.wsgibase)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ import os
|
||||
|
||||
path = os.path.dirname(os.path.abspath(__file__))
|
||||
os.chdir(path)
|
||||
sys.path = [path]+[p for p in sys.path if not p==path]
|
||||
sys.path = [path] + [p for p in sys.path if not p == path]
|
||||
|
||||
import gluon.main
|
||||
import gluon.contrib.gateways.fcgi as fcgi
|
||||
@@ -51,8 +51,3 @@ if SOFTCRON:
|
||||
global_settings.web2py_crontype = 'soft'
|
||||
|
||||
fcgi.WSGIServer(application, bindAddress='/tmp/fcgi.sock').run()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ import wsgiref.handlers
|
||||
import datetime
|
||||
|
||||
path = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path = [path]+[p for p in sys.path if not p==path]
|
||||
sys.path = [path] + [p for p in sys.path if not p == path]
|
||||
|
||||
sys.modules['cPickle'] = sys.modules['pickle']
|
||||
|
||||
@@ -78,14 +78,18 @@ def wsgiapp(env, res):
|
||||
"""Return the wsgiapp"""
|
||||
env['PATH_INFO'] = env['PATH_INFO'].decode('latin1').encode('utf8')
|
||||
|
||||
#when using the blobstore image uploader GAE dev SDK passes these as unicode
|
||||
# they should be regular strings as they are parts of URLs
|
||||
env['wsgi.url_scheme'] = str(env['wsgi.url_scheme'])
|
||||
env['QUERY_STRING'] = str(env['QUERY_STRING'])
|
||||
env['SERVER_NAME'] = str(env['SERVER_NAME'])
|
||||
|
||||
#this deals with a problem where GAE development server seems to forget
|
||||
# the path between requests
|
||||
if global_settings.web2py_runtime == 'gae:development':
|
||||
gluon.admin.create_missing_folders()
|
||||
|
||||
from gluon.custom_import import custom_import_install
|
||||
web2py_path = global_settings.applications_parent # backward compatibility
|
||||
custom_import_install(web2py_path)
|
||||
web2py_path = global_settings.applications_parent # backward compatibility
|
||||
|
||||
return gluon.main.wsgibase(env, res)
|
||||
|
||||
@@ -93,14 +97,10 @@ def wsgiapp(env, res):
|
||||
if LOG_STATS or DEBUG:
|
||||
wsgiapp = log_stats(wsgiapp)
|
||||
|
||||
|
||||
def main():
|
||||
"""Run the wsgi app"""
|
||||
run_wsgi_app(wsgiapp)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ Web2Py framework modules
|
||||
========================
|
||||
"""
|
||||
|
||||
__all__ = ['A', 'B', 'BEAUTIFY', 'BODY', 'BR', 'CAT', 'CENTER', 'CLEANUP', 'CODE', 'CRYPT', 'DAL', 'DIV', 'EM', 'EMBED', 'FIELDSET', 'FORM', 'Field', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'HEAD', 'HR', 'HTML', 'HTTP', 'I', 'IFRAME', 'IMG', 'INPUT', 'IS_ALPHANUMERIC', 'IS_DATE', 'IS_DATETIME', 'IS_DATETIME_IN_RANGE', 'IS_DATE_IN_RANGE', 'IS_DECIMAL_IN_RANGE', 'IS_EMAIL', 'IS_EMPTY_OR', 'IS_EQUAL_TO', 'IS_EXPR', 'IS_FLOAT_IN_RANGE', 'IS_IMAGE', 'IS_INT_IN_RANGE', 'IS_IN_DB', 'IS_IN_SET', 'IS_IPV4', 'IS_LENGTH', 'IS_LIST_OF', 'IS_LOWER', 'IS_MATCH', 'IS_NOT_EMPTY', 'IS_NOT_IN_DB', 'IS_NULL_OR', 'IS_SLUG', 'IS_STRONG', 'IS_TIME', 'IS_UPLOAD_FILENAME', 'IS_UPPER', 'IS_URL', 'LABEL', 'LEGEND', 'LI', 'LINK', 'LOAD', 'MARKMIN', 'MENU', 'META', 'OBJECT', 'OL', 'ON', 'OPTGROUP', 'OPTION', 'P', 'PRE', 'SCRIPT', 'SELECT', 'SPAN', 'SQLFORM', 'SQLTABLE', 'STRONG', 'STYLE', 'TABLE', 'TAG', 'TBODY', 'TD', 'TEXTAREA', 'TFOOT', 'TH', 'THEAD', 'TITLE', 'TR', 'TT', 'UL', 'URL', 'XHTML', 'XML','redirect','current','embed64']
|
||||
__all__ = ['A', 'B', 'BEAUTIFY', 'BODY', 'BR', 'CAT', 'CENTER', 'CLEANUP', 'CODE', 'CRYPT', 'DAL', 'DIV', 'EM', 'EMBED', 'FIELDSET', 'FORM', 'Field', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'HEAD', 'HR', 'HTML', 'HTTP', 'I', 'IFRAME', 'IMG', 'INPUT', 'IS_ALPHANUMERIC', 'IS_DATE', 'IS_DATETIME', 'IS_DATETIME_IN_RANGE', 'IS_DATE_IN_RANGE', 'IS_DECIMAL_IN_RANGE', 'IS_EMAIL', 'IS_EMPTY_OR', 'IS_EQUAL_TO', 'IS_EXPR', 'IS_FLOAT_IN_RANGE', 'IS_IMAGE', 'IS_INT_IN_RANGE', 'IS_IN_DB', 'IS_IN_SET', 'IS_IPV4', 'IS_LENGTH', 'IS_LIST_OF', 'IS_LOWER', 'IS_MATCH', 'IS_NOT_EMPTY', 'IS_NOT_IN_DB', 'IS_NULL_OR', 'IS_SLUG', 'IS_STRONG', 'IS_TIME', 'IS_UPLOAD_FILENAME', 'IS_UPPER', 'IS_URL', 'LABEL', 'LEGEND', 'LI', 'LINK', 'LOAD', 'MARKMIN', 'MENU', 'META', 'OBJECT', 'OL', 'ON', 'OPTGROUP', 'OPTION', 'P', 'PRE', 'SCRIPT', 'SELECT', 'SPAN', 'SQLFORM', 'SQLTABLE', 'STRONG', 'STYLE', 'TABLE', 'TAG', 'TBODY', 'TD', 'TEXTAREA', 'TFOOT', 'TH', 'THEAD', 'TITLE', 'TR', 'TT', 'UL', 'URL', 'XHTML', 'XML', 'redirect', 'current', 'embed64']
|
||||
|
||||
from globals import current
|
||||
from html import *
|
||||
@@ -42,14 +42,3 @@ if 0:
|
||||
mail = Mail()
|
||||
service = Service()
|
||||
plugins = PluginManager()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ from http import HTTP
|
||||
if not global_settings.web2py_runtime_gae:
|
||||
import site
|
||||
|
||||
|
||||
def apath(path='', r=None):
|
||||
"""
|
||||
Builds a path inside an application folder
|
||||
@@ -60,7 +61,7 @@ def app_pack(app, request, raise_ex=False):
|
||||
"""
|
||||
try:
|
||||
app_cleanup(app, request)
|
||||
filename = apath('../deposit/%s.w2p' % app, request)
|
||||
filename = apath('../deposit/web2py.app.%s.w2p' % app, request)
|
||||
w2p_pack(filename, apath(app, request))
|
||||
return filename
|
||||
except Exception, e:
|
||||
@@ -95,6 +96,7 @@ def app_pack_compiled(app, request, raise_ex=False):
|
||||
raise
|
||||
return None
|
||||
|
||||
|
||||
def app_cleanup(app, request):
|
||||
"""
|
||||
Removes session, cache and error files
|
||||
@@ -113,7 +115,7 @@ def app_cleanup(app, request):
|
||||
if os.path.exists(path):
|
||||
for f in os.listdir(path):
|
||||
try:
|
||||
if f[:1]!='.': os.unlink(os.path.join(path,f))
|
||||
if f[:1] != '.': os.unlink(os.path.join(path, f))
|
||||
except IOError:
|
||||
r = False
|
||||
|
||||
@@ -122,7 +124,7 @@ def app_cleanup(app, request):
|
||||
if os.path.exists(path):
|
||||
for f in os.listdir(path):
|
||||
try:
|
||||
if f[:1]!='.': recursive_unlink(os.path.join(path,f))
|
||||
if f[:1] != '.': recursive_unlink(os.path.join(path, f))
|
||||
except IOError:
|
||||
r = False
|
||||
|
||||
@@ -131,7 +133,7 @@ def app_cleanup(app, request):
|
||||
if os.path.exists(path):
|
||||
for f in os.listdir(path):
|
||||
try:
|
||||
if f[:1]!='.': os.unlink(os.path.join(path,f))
|
||||
if f[:1] != '.': os.unlink(os.path.join(path, f))
|
||||
except IOError:
|
||||
r = False
|
||||
return r
|
||||
@@ -158,7 +160,8 @@ def app_compile(app, request):
|
||||
remove_compiled_application(folder)
|
||||
return tb
|
||||
|
||||
def app_create(app, request,force=False,key=None,info=False):
|
||||
|
||||
def app_create(app, request, force=False, key=None, info=False):
|
||||
"""
|
||||
Create a copy of welcome.w2p (scaffolding) app
|
||||
|
||||
@@ -186,17 +189,17 @@ def app_create(app, request,force=False,key=None,info=False):
|
||||
return False
|
||||
try:
|
||||
w2p_unpack('welcome.w2p', path)
|
||||
for subfolder in ['models','views','controllers', 'databases',
|
||||
'modules','cron','errors','sessions',
|
||||
'languages','static','private','uploads']:
|
||||
subpath = os.path.join(path,subfolder)
|
||||
for subfolder in ['models', 'views', 'controllers', 'databases',
|
||||
'modules', 'cron', 'errors', 'sessions',
|
||||
'languages', 'static', 'private', 'uploads']:
|
||||
subpath = os.path.join(path, subfolder)
|
||||
if not os.path.exists(subpath):
|
||||
os.mkdir(subpath)
|
||||
db = os.path.join(path, 'models', 'db.py')
|
||||
if os.path.exists(db):
|
||||
data = read_file(db)
|
||||
data = data.replace('<your secret key>',
|
||||
'sha512:'+(key or web2py_uuid()))
|
||||
'sha512:' + (key or web2py_uuid()))
|
||||
write_file(db, data)
|
||||
if info:
|
||||
return True, None
|
||||
@@ -283,6 +286,7 @@ def app_uninstall(app, request):
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def plugin_pack(app, plugin_name, request):
|
||||
"""
|
||||
Builds a w2p package for the application
|
||||
@@ -302,12 +306,14 @@ def plugin_pack(app, plugin_name, request):
|
||||
filename of the w2p file or None on error
|
||||
"""
|
||||
try:
|
||||
filename = apath('../deposit/web2py.plugin.%s.w2p' % plugin_name, request)
|
||||
filename = apath(
|
||||
'../deposit/web2py.plugin.%s.w2p' % plugin_name, request)
|
||||
w2p_pack_plugin(filename, apath(app, request), plugin_name)
|
||||
return filename
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def plugin_install(app, fobj, request, filename):
|
||||
"""
|
||||
Installs an application:
|
||||
@@ -345,6 +351,7 @@ def plugin_install(app, fobj, request, filename):
|
||||
os.unlink(upname)
|
||||
return False
|
||||
|
||||
|
||||
def check_new_version(myversion, version_URL):
|
||||
"""
|
||||
Compares current web2py's version with the latest stable web2py version.
|
||||
@@ -375,6 +382,7 @@ def check_new_version(myversion, version_URL):
|
||||
else:
|
||||
return False, version
|
||||
|
||||
|
||||
def unzip(filename, dir, subfolder=''):
|
||||
"""
|
||||
Unzips filename into dir (.zip only, no .gz etc)
|
||||
@@ -382,7 +390,7 @@ def unzip(filename, dir, subfolder=''):
|
||||
"""
|
||||
filename = abspath(filename)
|
||||
if not zipfile.is_zipfile(filename):
|
||||
raise RuntimeError, 'Not a valid zipfile'
|
||||
raise RuntimeError('Not a valid zipfile')
|
||||
zf = zipfile.ZipFile(filename)
|
||||
if not subfolder.endswith('/'):
|
||||
subfolder = subfolder + '/'
|
||||
@@ -392,7 +400,7 @@ def unzip(filename, dir, subfolder=''):
|
||||
continue
|
||||
#print name[n:]
|
||||
if name.endswith('/'):
|
||||
folder = os.path.join(dir,name[n:])
|
||||
folder = os.path.join(dir, name[n:])
|
||||
if not os.path.exists(folder):
|
||||
os.mkdir(folder)
|
||||
else:
|
||||
@@ -421,7 +429,7 @@ def upgrade(request, url='http://web2py.com'):
|
||||
if not gluon_parent.endswith('/'):
|
||||
gluon_parent = gluon_parent + '/'
|
||||
(check, version) = check_new_version(web2py_version,
|
||||
url+'/examples/default/version')
|
||||
url + '/examples/default/version')
|
||||
if not check:
|
||||
return (False, 'Already latest version')
|
||||
if os.path.exists(os.path.join(gluon_parent, 'web2py.exe')):
|
||||
@@ -442,42 +450,40 @@ def upgrade(request, url='http://web2py.com'):
|
||||
file = None
|
||||
try:
|
||||
write_file(filename, urllib.urlopen(full_url).read(), 'wb')
|
||||
except Exception,e:
|
||||
except Exception, e:
|
||||
return False, e
|
||||
try:
|
||||
unzip(filename, destination, subfolder)
|
||||
return True, None
|
||||
except Exception,e:
|
||||
except Exception, e:
|
||||
return False, e
|
||||
|
||||
|
||||
def add_path_first(path):
|
||||
sys.path = [path]+[p for p in sys.path if (not p==path and not p==(path+'/'))]
|
||||
sys.path = [path] + [p for p in sys.path if (
|
||||
not p == path and not p == (path + '/'))]
|
||||
if not global_settings.web2py_runtime_gae:
|
||||
site.addsitedir(path)
|
||||
|
||||
|
||||
def create_missing_folders():
|
||||
if not global_settings.web2py_runtime_gae:
|
||||
for path in ('applications', 'deposit', 'site-packages', 'logs'):
|
||||
path = abspath(path, gluon=True)
|
||||
if not os.path.exists(path):
|
||||
os.mkdir(path)
|
||||
paths = (global_settings.gluon_parent, abspath('site-packages', gluon=True), abspath('gluon', gluon=True), '')
|
||||
paths = (global_settings.gluon_parent, abspath(
|
||||
'site-packages', gluon=True), abspath('gluon', gluon=True), '')
|
||||
[add_path_first(path) for path in paths]
|
||||
|
||||
|
||||
def create_missing_app_folders(request):
|
||||
if not global_settings.web2py_runtime_gae:
|
||||
if request.folder not in global_settings.app_folders:
|
||||
for subfolder in ('models', 'views', 'controllers', 'databases',
|
||||
'modules', 'cron', 'errors', 'sessions',
|
||||
'languages', 'static', 'private', 'uploads'):
|
||||
path = os.path.join(request.folder, subfolder)
|
||||
path = os.path.join(request.folder, subfolder)
|
||||
if not os.path.exists(path):
|
||||
os.mkdir(path)
|
||||
global_settings.app_folders.add(request.folder)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
273
gluon/cache.py
273
gluon/cache.py
@@ -11,7 +11,7 @@ Basic caching classes and methods
|
||||
|
||||
- Cache - The generic caching object interfacing with the others
|
||||
- CacheInRam - providing caching in ram
|
||||
- CacheInDisk - provides caches on disk
|
||||
- CacheOnDisk - provides caches on disk
|
||||
|
||||
Memcache is also available via a different module (see gluon.contrib.memcache)
|
||||
|
||||
@@ -40,12 +40,26 @@ __all__ = ['Cache', 'lazy_cache']
|
||||
|
||||
DEFAULT_TIME_EXPIRE = 300
|
||||
|
||||
|
||||
class CacheAbstract(object):
|
||||
"""
|
||||
Abstract class for cache implementations.
|
||||
Main function is now to provide referenced api documentation.
|
||||
|
||||
Use CacheInRam or CacheOnDisk instead which are derived from this class.
|
||||
|
||||
Attentions, Michele says:
|
||||
|
||||
There are signatures inside gdbm files that are used directly
|
||||
by the python gdbm adapter that often are lagging behind in the
|
||||
detection code in python part.
|
||||
On every occasion that a gdbm store is probed by the python adapter,
|
||||
the probe fails, because gdbm file version is newer.
|
||||
Using gdbm directly from C would work, because there is backward
|
||||
compatibility, but not from python!
|
||||
The .shelve file is discarded and a new one created (with new
|
||||
signature) and it works until it is probed again...
|
||||
The possible consequences are memory leaks and broken sessions.
|
||||
"""
|
||||
|
||||
cache_stats_name = 'web2py_cache_statistics'
|
||||
@@ -60,7 +74,7 @@ class CacheAbstract(object):
|
||||
raise NotImplementedError
|
||||
|
||||
def __call__(self, key, f,
|
||||
time_expire = DEFAULT_TIME_EXPIRE):
|
||||
time_expire=DEFAULT_TIME_EXPIRE):
|
||||
"""
|
||||
Tries retrieve the value corresponding to `key` from the cache of the
|
||||
object exists and if it did not expire, else it called the function `f`
|
||||
@@ -117,6 +131,7 @@ class CacheAbstract(object):
|
||||
if r.match(str(key)):
|
||||
del storage[key]
|
||||
|
||||
|
||||
class CacheInRam(CacheAbstract):
|
||||
"""
|
||||
Ram based caching
|
||||
@@ -130,22 +145,29 @@ class CacheInRam(CacheAbstract):
|
||||
meta_storage = {}
|
||||
|
||||
def __init__(self, request=None):
|
||||
self.locker.acquire()
|
||||
self.initialized = False
|
||||
self.request = request
|
||||
|
||||
def initialize(self):
|
||||
if self.initialized:
|
||||
return
|
||||
else:
|
||||
self.initialized = True
|
||||
self.locker.acquire()
|
||||
request = self.request
|
||||
if request:
|
||||
app = request.application
|
||||
else:
|
||||
app = ''
|
||||
if not app in self.meta_storage:
|
||||
self.storage = self.meta_storage[app] = {CacheAbstract.cache_stats_name: {
|
||||
'hit_total': 0,
|
||||
'misses': 0,
|
||||
}}
|
||||
self.storage = self.meta_storage[app] = {
|
||||
CacheAbstract.cache_stats_name: {'hit_total': 0, 'misses': 0}}
|
||||
else:
|
||||
self.storage = self.meta_storage[app]
|
||||
self.locker.release()
|
||||
|
||||
def clear(self, regex=None):
|
||||
self.initialize()
|
||||
self.locker.acquire()
|
||||
storage = self.storage
|
||||
if regex is None:
|
||||
@@ -155,15 +177,13 @@ class CacheInRam(CacheAbstract):
|
||||
|
||||
if not CacheAbstract.cache_stats_name in storage.keys():
|
||||
storage[CacheAbstract.cache_stats_name] = {
|
||||
'hit_total': 0,
|
||||
'misses': 0,
|
||||
}
|
||||
'hit_total': 0, 'misses': 0}
|
||||
|
||||
self.locker.release()
|
||||
|
||||
def __call__(self, key, f,
|
||||
time_expire = DEFAULT_TIME_EXPIRE,
|
||||
destroyer = None):
|
||||
time_expire=DEFAULT_TIME_EXPIRE,
|
||||
destroyer=None):
|
||||
"""
|
||||
Attention! cache.ram does not copy the cached object. It just stores a reference to it.
|
||||
Turns out the deepcopying the object has some problems:
|
||||
@@ -172,6 +192,7 @@ class CacheInRam(CacheAbstract):
|
||||
3) would work unless we deepcopy no storage and retrival which would make things slow.
|
||||
Anyway. You can deepcopy explicitly in the function generating the value to be cached.
|
||||
"""
|
||||
self.initialize()
|
||||
|
||||
dt = time_expire
|
||||
now = time.time()
|
||||
@@ -200,6 +221,7 @@ class CacheInRam(CacheAbstract):
|
||||
return value
|
||||
|
||||
def increment(self, key, value=1):
|
||||
self.initialize()
|
||||
self.locker.acquire()
|
||||
try:
|
||||
if key in self.storage:
|
||||
@@ -226,58 +248,69 @@ class CacheOnDisk(CacheAbstract):
|
||||
Values stored in disk cache must be pickable.
|
||||
"""
|
||||
|
||||
speedup_checks = set()
|
||||
def _close_shelve_and_unlock(self):
|
||||
try:
|
||||
if self.storage:
|
||||
self.storage.close()
|
||||
finally:
|
||||
if self.locker and self.locked:
|
||||
portalocker.unlock(self.locker)
|
||||
self.locker.close()
|
||||
self.locked = False
|
||||
|
||||
def _open_shelf_with_lock(self):
|
||||
def _open_shelve_and_lock(self):
|
||||
"""Open and return a shelf object, obtaining an exclusive lock
|
||||
on self.locker first. Replaces the close method of the
|
||||
returned shelf instance with one that releases the lock upon
|
||||
closing."""
|
||||
def _close(self):
|
||||
try:
|
||||
shelve.Shelf.close(self)
|
||||
finally:
|
||||
portalocker.unlock(self.locker)
|
||||
self.locker.close()
|
||||
|
||||
storage, locker, locker_locked = None, None, False
|
||||
storage = None
|
||||
locker = None
|
||||
locked = False
|
||||
try:
|
||||
locker = open(self.locker_name, 'a')
|
||||
locker = locker = open(self.locker_name, 'a')
|
||||
portalocker.lock(locker, portalocker.LOCK_EX)
|
||||
locker_locked = True
|
||||
storage = shelve.open(self.shelve_name)
|
||||
storage.close = _close.__get__(storage, shelve.Shelf)
|
||||
storage.locker = locker
|
||||
except Exception:
|
||||
logger.error('corrupted cache file %s, will try to delete and recreate it!' % (self.shelve_name))
|
||||
locked = True
|
||||
try:
|
||||
storage = shelve.open(self.shelve_name)
|
||||
except:
|
||||
logger.error('corrupted cache file %s, will try rebuild it'
|
||||
% (self.shelve_name))
|
||||
storage = None
|
||||
if not storage and os.path.exists(self.shelve_name):
|
||||
os.unlink(self.shelve_name)
|
||||
storage = shelve.open(self.shelve_name)
|
||||
if not CacheAbstract.cache_stats_name in storage.keys():
|
||||
storage[CacheAbstract.cache_stats_name] = {
|
||||
'hit_total': 0, 'misses': 0}
|
||||
storage.sync()
|
||||
except Exception, e:
|
||||
if storage:
|
||||
storage.close()
|
||||
storage = None
|
||||
|
||||
try:
|
||||
os.unlink(self.shelve_name)
|
||||
storage = shelve.open(self.shelve_name)
|
||||
storage.close = _close.__get__(storage, shelve.Shelf)
|
||||
storage.locker = locker
|
||||
if not CacheAbstract.cache_stats_name in storage.keys():
|
||||
storage[CacheAbstract.cache_stats_name] = {
|
||||
'hit_total': 0,
|
||||
'misses': 0,
|
||||
}
|
||||
storage.sync()
|
||||
except (IOError, OSError):
|
||||
logger.warn('unable to delete and recreate cache file %s' % self.shelve_name)
|
||||
if storage:
|
||||
storage.close()
|
||||
storage = None
|
||||
if locker_locked:
|
||||
portalocker.unlock(locker)
|
||||
if locker:
|
||||
locker.close()
|
||||
if locked:
|
||||
portalocker.unlock(locker)
|
||||
locker.close()
|
||||
locked = False
|
||||
raise RuntimeError(
|
||||
'unable to create/re-create cache file %s' % self.shelve_name)
|
||||
self.locker = locker
|
||||
self.locked = locked
|
||||
self.storage = storage
|
||||
return storage
|
||||
|
||||
def __init__(self, request, folder=None):
|
||||
def __init__(self, request=None, folder=None):
|
||||
self.initialized = False
|
||||
self.request = request
|
||||
self.folder = folder
|
||||
|
||||
def initialize(self):
|
||||
if self.initialized:
|
||||
return
|
||||
else:
|
||||
self.initialized = True
|
||||
folder = self.folder
|
||||
request = self.request
|
||||
|
||||
# Lets test if the cache folder exists, if not
|
||||
# we are going to create it
|
||||
@@ -288,100 +321,62 @@ class CacheOnDisk(CacheAbstract):
|
||||
|
||||
### we need this because of a possible bug in shelve that may
|
||||
### or may not lock
|
||||
self.locker_name = os.path.join(folder,'cache.lock')
|
||||
self.shelve_name = os.path.join(folder,'cache.shelve')
|
||||
|
||||
speedup_key = (folder,CacheAbstract.cache_stats_name)
|
||||
if not speedup_key in self.speedup_checks or \
|
||||
not os.path.exists(self.shelve_name):
|
||||
try:
|
||||
storage = self._open_shelf_with_lock()
|
||||
try:
|
||||
if not CacheAbstract.cache_stats_name in storage:
|
||||
storage[CacheAbstract.cache_stats_name] = {
|
||||
'hit_total': 0,
|
||||
'misses': 0,
|
||||
}
|
||||
storage.sync()
|
||||
finally:
|
||||
storage.close()
|
||||
self.speedup_checks.add(speedup_key)
|
||||
except ImportError:
|
||||
pass # no module _bsddb, ignoring exception now so it makes a ticket only if used
|
||||
self.locker_name = os.path.join(folder, 'cache.lock')
|
||||
self.shelve_name = os.path.join(folder, 'cache.shelve')
|
||||
|
||||
def clear(self, regex=None):
|
||||
storage = self._open_shelf_with_lock()
|
||||
self.initialize()
|
||||
storage = self._open_shelve_and_lock()
|
||||
try:
|
||||
if regex is None:
|
||||
storage.clear()
|
||||
else:
|
||||
self._clear(storage, regex)
|
||||
if not CacheAbstract.cache_stats_name in storage.keys():
|
||||
storage[CacheAbstract.cache_stats_name] = {
|
||||
'hit_total': 0,
|
||||
'misses': 0,
|
||||
}
|
||||
storage.sync()
|
||||
finally:
|
||||
storage.close()
|
||||
self._close_shelve_and_unlock()
|
||||
|
||||
def __call__(self, key, f,
|
||||
time_expire = DEFAULT_TIME_EXPIRE):
|
||||
time_expire=DEFAULT_TIME_EXPIRE):
|
||||
self.initialize()
|
||||
dt = time_expire
|
||||
|
||||
storage = self._open_shelf_with_lock()
|
||||
storage = self._open_shelve_and_lock()
|
||||
try:
|
||||
item = storage.get(key, None)
|
||||
storage[CacheAbstract.cache_stats_name]['hit_total'] += 1
|
||||
if item and f is None:
|
||||
del storage[key]
|
||||
|
||||
storage[CacheAbstract.cache_stats_name] = {
|
||||
'hit_total': storage[CacheAbstract.cache_stats_name]['hit_total'] + 1,
|
||||
'misses': storage[CacheAbstract.cache_stats_name]['misses']
|
||||
}
|
||||
|
||||
storage.sync()
|
||||
storage.sync()
|
||||
now = time.time()
|
||||
if f is None:
|
||||
value = None
|
||||
elif item and (dt is None or item[0] > now - dt):
|
||||
value = item[1]
|
||||
else:
|
||||
value = f()
|
||||
storage[key] = (now, value)
|
||||
storage[CacheAbstract.cache_stats_name]['misses'] += 1
|
||||
storage.sync()
|
||||
finally:
|
||||
if storage:
|
||||
storage.close()
|
||||
|
||||
now = time.time()
|
||||
if f is None:
|
||||
return None
|
||||
if item and (dt is None or item[0] > now - dt):
|
||||
return item[1]
|
||||
value = f()
|
||||
|
||||
storage = self._open_shelf_with_lock()
|
||||
try:
|
||||
storage[key] = (now, value)
|
||||
|
||||
storage[CacheAbstract.cache_stats_name] = {
|
||||
'hit_total': storage[CacheAbstract.cache_stats_name]['hit_total'],
|
||||
'misses': storage[CacheAbstract.cache_stats_name]['misses'] + 1
|
||||
}
|
||||
|
||||
storage.sync()
|
||||
finally:
|
||||
if storage:
|
||||
storage.close()
|
||||
self._close_shelve_and_unlock()
|
||||
|
||||
return value
|
||||
|
||||
def increment(self, key, value=1):
|
||||
storage = self._open_shelf_with_lock()
|
||||
self.initialize()
|
||||
storage = self._open_shelve_and_lock()
|
||||
try:
|
||||
if key in storage:
|
||||
value = storage[key][1] + value
|
||||
storage[key] = (time.time(), value)
|
||||
storage.sync()
|
||||
finally:
|
||||
if storage:
|
||||
storage.close()
|
||||
self._close_shelve_and_unlock()
|
||||
return value
|
||||
|
||||
|
||||
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.__doc__ = func.__doc__
|
||||
self.func = func
|
||||
@@ -389,17 +384,18 @@ class CacheAction(object):
|
||||
self.time_expire = time_expire
|
||||
self.cache = cache
|
||||
self.cache_model = cache_model
|
||||
def __call__(self,*a,**b):
|
||||
|
||||
def __call__(self, *a, **b):
|
||||
if not self.key:
|
||||
key2 = self.__name__+':'+repr(a)+':'+repr(b)
|
||||
key2 = self.__name__ + ':' + repr(a) + ':' + repr(b)
|
||||
else:
|
||||
key2 = self.key.replace('%(name)s',self.__name__)\
|
||||
.replace('%(args)s',str(a)).replace('%(vars)s',str(b))
|
||||
key2 = self.key.replace('%(name)s', self.__name__)\
|
||||
.replace('%(args)s', str(a)).replace('%(vars)s', str(b))
|
||||
cache_model = self.cache_model
|
||||
if not cache_model or isinstance(cache_model,str):
|
||||
cache_model = getattr(self.cache,cache_model or 'ram')
|
||||
if not cache_model or isinstance(cache_model, str):
|
||||
cache_model = getattr(self.cache, cache_model or 'ram')
|
||||
return cache_model(key2,
|
||||
lambda a=a,b=b:self.func(*a,**b),
|
||||
lambda a=a, b=b: self.func(*a, **b),
|
||||
self.time_expire)
|
||||
|
||||
|
||||
@@ -423,10 +419,9 @@ class Cache(object):
|
||||
the global request object
|
||||
"""
|
||||
# GAE will have a special caching
|
||||
|
||||
if have_settings and settings.global_settings.web2py_runtime_gae:
|
||||
from contrib.gae_memcache import MemcacheClient
|
||||
self.ram=self.disk=MemcacheClient(request)
|
||||
self.ram = self.disk = MemcacheClient(request)
|
||||
else:
|
||||
# Otherwise use ram (and try also disk)
|
||||
self.ram = CacheInRam(request)
|
||||
@@ -440,9 +435,9 @@ class Cache(object):
|
||||
logger.warning('no cache.disk (AttributeError)')
|
||||
|
||||
def __call__(self,
|
||||
key = None,
|
||||
time_expire = DEFAULT_TIME_EXPIRE,
|
||||
cache_model = None):
|
||||
key=None,
|
||||
time_expire=DEFAULT_TIME_EXPIRE,
|
||||
cache_model=None):
|
||||
"""
|
||||
Decorator function that can be used to cache any function/method.
|
||||
|
||||
@@ -475,11 +470,21 @@ class Cache(object):
|
||||
`request.env.path_info` as key.
|
||||
"""
|
||||
|
||||
def tmp(func,cache=self,cache_model=cache_model):
|
||||
return CacheAction(func,key,time_expire,self,cache_model)
|
||||
def tmp(func, cache=self, cache_model=cache_model):
|
||||
return CacheAction(func, key, time_expire, self, cache_model)
|
||||
return tmp
|
||||
|
||||
def lazy_cache(key=None,time_expire=None,cache_model='ram'):
|
||||
@staticmethod
|
||||
def with_prefix(cache_model, prefix):
|
||||
"""
|
||||
allow replacing cache.ram with cache.with_prefix(cache.ram,'prefix')
|
||||
it will add prefix to all the cache keys used.
|
||||
"""
|
||||
return lambda key, f, time_expire=DEFAULT_TIME_EXPIRE, prefix=prefix:\
|
||||
cache_model(prefix + key, f, time_expire)
|
||||
|
||||
|
||||
def lazy_cache(key=None, time_expire=None, cache_model='ram'):
|
||||
"""
|
||||
can be used to cache any function including in modules,
|
||||
as long as the cached function is only called within a web2py request
|
||||
@@ -487,14 +492,12 @@ def lazy_cache(key=None,time_expire=None,cache_model='ram'):
|
||||
the time_expire defaults to None (no cache expiration)
|
||||
if cache_model is "ram" then the model is current.cache.ram, etc.
|
||||
"""
|
||||
def decorator(f,key=key,time_expire=time_expire,cache_model=cache_model):
|
||||
def decorator(f, key=key, time_expire=time_expire, cache_model=cache_model):
|
||||
key = key or repr(f)
|
||||
def g(*c,**d):
|
||||
|
||||
def g(*c, **d):
|
||||
from gluon import current
|
||||
return current.cache(key,time_expire,cache_model)(f)(*c,**d)
|
||||
return current.cache(key, time_expire, cache_model)(f)(*c, **d)
|
||||
g.__name__ = f.__name__
|
||||
return g
|
||||
return decorator
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -51,10 +51,3 @@ def getcfs(key, filename, filter=None):
|
||||
cfs[key] = (t, data)
|
||||
cfs_lock.release()
|
||||
return data
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ import imp
|
||||
import logging
|
||||
logger = logging.getLogger("web2py")
|
||||
import rewrite
|
||||
from custom_import import custom_import_install
|
||||
|
||||
try:
|
||||
import py_compile
|
||||
@@ -47,7 +48,7 @@ except:
|
||||
logger.warning('unable to import py_compile')
|
||||
|
||||
is_pypy = settings.global_settings.is_pypy
|
||||
is_gae = settings.global_settings.web2py_runtime_gae
|
||||
is_gae = settings.global_settings.web2py_runtime_gae
|
||||
is_jython = settings.global_settings.is_jython
|
||||
|
||||
pjoin = os.path.join
|
||||
@@ -94,6 +95,7 @@ _TEST()
|
||||
CACHED_REGEXES = {}
|
||||
CACHED_REGEXES_MAX_SIZE = 1000
|
||||
|
||||
|
||||
def re_compile(regex):
|
||||
try:
|
||||
return CACHED_REGEXES[regex]
|
||||
@@ -103,6 +105,7 @@ def re_compile(regex):
|
||||
compiled_regex = CACHED_REGEXES[regex] = re.compile(regex)
|
||||
return compiled_regex
|
||||
|
||||
|
||||
class mybuiltin(object):
|
||||
"""
|
||||
NOTE could simple use a dict and populate it,
|
||||
@@ -113,14 +116,16 @@ class mybuiltin(object):
|
||||
try:
|
||||
return getattr(__builtin__, key)
|
||||
except AttributeError:
|
||||
raise KeyError, key
|
||||
raise KeyError(key)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
setattr(self, key, value)
|
||||
|
||||
|
||||
def LOAD(c=None, f='index', args=None, vars=None,
|
||||
extension=None, target=None,ajax=False,ajax_trap=False,
|
||||
url=None,user_signature=False, timeout=None, times=1,
|
||||
content='loading...',**attr):
|
||||
extension=None, target=None, ajax=False, ajax_trap=False,
|
||||
url=None, user_signature=False, timeout=None, times=1,
|
||||
content='loading...', **attr):
|
||||
""" LOAD a component into the action's document
|
||||
|
||||
Timing options:
|
||||
@@ -133,13 +138,14 @@ def LOAD(c=None, f='index', args=None, vars=None,
|
||||
is added on page loading without delay.
|
||||
"""
|
||||
from html import TAG, DIV, URL, SCRIPT, XML
|
||||
if args is None: args = []
|
||||
if args is None:
|
||||
args = []
|
||||
vars = Storage(vars or {})
|
||||
target = target or 'c'+str(random.random())[2:]
|
||||
attr['_id']=target
|
||||
target = target or 'c' + str(random.random())[2:]
|
||||
attr['_id'] = target
|
||||
request = current.request
|
||||
if '.' in f:
|
||||
f, extension = f.rsplit('.',1)
|
||||
f, extension = f.rsplit('.', 1)
|
||||
if url or ajax:
|
||||
url = url or URL(request.application, c, f, r=request,
|
||||
args=args, vars=vars, extension=extension,
|
||||
@@ -159,19 +165,20 @@ def LOAD(c=None, f='index', args=None, vars=None,
|
||||
if not isinstance(timeout, (int, long)):
|
||||
raise ValueError("Timeout argument must be an integer or None")
|
||||
elif timeout <= 0:
|
||||
raise ValueError("Timeout argument must be greater than zero or None")
|
||||
raise ValueError(
|
||||
"Timeout argument must be greater than zero or None")
|
||||
statement = "web2py_component('%s','%s', %s, %s);" \
|
||||
% (url, target, timeout, times)
|
||||
% (url, target, timeout, times)
|
||||
else:
|
||||
statement = "web2py_component('%s','%s');" % (url, target)
|
||||
script = SCRIPT(statement, _type="text/javascript")
|
||||
if not content is None:
|
||||
return TAG[''](script, DIV(content,**attr))
|
||||
return TAG[''](script, DIV(content, **attr))
|
||||
else:
|
||||
return TAG[''](script)
|
||||
|
||||
else:
|
||||
if not isinstance(args,(list,tuple)):
|
||||
if not isinstance(args, (list, tuple)):
|
||||
args = [args]
|
||||
c = c or request.controller
|
||||
other_request = Storage(request)
|
||||
@@ -185,17 +192,17 @@ def LOAD(c=None, f='index', args=None, vars=None,
|
||||
other_request.post_vars = Storage()
|
||||
other_response = Response()
|
||||
other_request.env.path_info = '/' + \
|
||||
'/'.join([request.application,c,f] + \
|
||||
map(str, other_request.args))
|
||||
'/'.join([request.application, c, f] +
|
||||
map(str, other_request.args))
|
||||
other_request.env.query_string = \
|
||||
vars and URL(vars=vars).split('?')[1] or ''
|
||||
other_request.env.http_web2py_component_location = \
|
||||
request.env.path_info
|
||||
other_request.cid = target
|
||||
other_request.env.http_web2py_component_element = target
|
||||
other_response.view = '%s/%s.%s' % (c,f, other_request.extension)
|
||||
other_response.view = '%s/%s.%s' % (c, f, other_request.extension)
|
||||
|
||||
other_environment = copy.copy(current.globalenv) ### NASTY
|
||||
other_environment = copy.copy(current.globalenv) # NASTY
|
||||
|
||||
other_response._view_environment = other_environment
|
||||
other_response.generic_patterns = \
|
||||
@@ -217,40 +224,41 @@ def LOAD(c=None, f='index', args=None, vars=None,
|
||||
js = None
|
||||
if ajax_trap:
|
||||
link = URL(request.application, c, f, r=request,
|
||||
args=args, vars=vars, extension=extension,
|
||||
user_signature=user_signature)
|
||||
args=args, vars=vars, extension=extension,
|
||||
user_signature=user_signature)
|
||||
js = "web2py_trap_form('%s','%s');" % (link, target)
|
||||
script = js and SCRIPT(js,_type="text/javascript") or ''
|
||||
return TAG[''](DIV(XML(page),**attr),script)
|
||||
|
||||
script = js and SCRIPT(js, _type="text/javascript") or ''
|
||||
return TAG[''](DIV(XML(page), **attr), script)
|
||||
|
||||
|
||||
class LoadFactory(object):
|
||||
"""
|
||||
Attention: this helper is new and experimental
|
||||
"""
|
||||
def __init__(self,environment):
|
||||
def __init__(self, environment):
|
||||
self.environment = environment
|
||||
|
||||
def __call__(self, c=None, f='index', args=None, vars=None,
|
||||
extension=None, target=None,ajax=False,ajax_trap=False,
|
||||
url=None,user_signature=False, content='loading...',**attr):
|
||||
if args is None: args = []
|
||||
extension=None, target=None, ajax=False, ajax_trap=False,
|
||||
url=None, user_signature=False, content='loading...', **attr):
|
||||
if args is None:
|
||||
args = []
|
||||
vars = Storage(vars or {})
|
||||
import globals
|
||||
target = target or 'c'+str(random.random())[2:]
|
||||
attr['_id']=target
|
||||
target = target or 'c' + str(random.random())[2:]
|
||||
attr['_id'] = target
|
||||
request = self.environment['request']
|
||||
if '.' in f:
|
||||
f, extension = f.rsplit('.',1)
|
||||
f, extension = f.rsplit('.', 1)
|
||||
if url or ajax:
|
||||
url = url or html.URL(request.application, c, f, r=request,
|
||||
args=args, vars=vars, extension=extension,
|
||||
user_signature=user_signature)
|
||||
script = html.SCRIPT('web2py_component("%s","%s")' % (url, target),
|
||||
_type="text/javascript")
|
||||
return html.TAG[''](script, html.DIV(content,**attr))
|
||||
return html.TAG[''](script, html.DIV(content, **attr))
|
||||
else:
|
||||
if not isinstance(args,(list,tuple)):
|
||||
if not isinstance(args, (list, tuple)):
|
||||
args = [args]
|
||||
c = c or request.controller
|
||||
|
||||
@@ -265,15 +273,15 @@ class LoadFactory(object):
|
||||
other_request.post_vars = Storage()
|
||||
other_response = globals.Response()
|
||||
other_request.env.path_info = '/' + \
|
||||
'/'.join([request.application,c,f] + \
|
||||
map(str, other_request.args))
|
||||
'/'.join([request.application, c, f] +
|
||||
map(str, other_request.args))
|
||||
other_request.env.query_string = \
|
||||
vars and html.URL(vars=vars).split('?')[1] or ''
|
||||
other_request.env.http_web2py_component_location = \
|
||||
request.env.path_info
|
||||
other_request.cid = target
|
||||
other_request.env.http_web2py_component_element = target
|
||||
other_response.view = '%s/%s.%s' % (c,f, other_request.extension)
|
||||
other_response.view = '%s/%s.%s' % (c, f, other_request.extension)
|
||||
other_environment = copy.copy(self.environment)
|
||||
other_response._view_environment = other_environment
|
||||
other_response.generic_patterns = \
|
||||
@@ -298,8 +306,8 @@ class LoadFactory(object):
|
||||
args=args, vars=vars, extension=extension,
|
||||
user_signature=user_signature)
|
||||
js = "web2py_trap_form('%s','%s');" % (link, target)
|
||||
script = js and html.SCRIPT(js,_type="text/javascript") or ''
|
||||
return html.TAG[''](html.DIV(html.XML(page),**attr),script)
|
||||
script = js and html.SCRIPT(js, _type="text/javascript") or ''
|
||||
return html.TAG[''](html.DIV(html.XML(page), **attr), script)
|
||||
|
||||
|
||||
def local_import_aux(name, reload_force=False, app='welcome'):
|
||||
@@ -320,7 +328,7 @@ def local_import_aux(name, reload_force=False, app='welcome'):
|
||||
This prevents conflict between applications and un-necessary execs.
|
||||
It can be used to import any module, including regular Python modules.
|
||||
"""
|
||||
items = name.replace('/','.')
|
||||
items = name.replace('/', '.')
|
||||
name = "applications.%s.modules.%s" % (app, items)
|
||||
module = __import__(name)
|
||||
for item in name.split(".")[1:]:
|
||||
@@ -354,26 +362,43 @@ OLD IMPLEMENTATION:
|
||||
file.close()
|
||||
imp.release_lock()
|
||||
if not module:
|
||||
raise ImportError, "cannot find module %s in %s" % (filename, modulepath)
|
||||
raise ImportError, "cannot find module %s in %s" % (
|
||||
filename, modulepath)
|
||||
return module
|
||||
"""
|
||||
|
||||
_base_environment_ = dict((k, getattr(html, k)) for k in html.__all__)
|
||||
_base_environment_.update(
|
||||
(k, getattr(validators, k)) for k in validators.__all__)
|
||||
_base_environment_['__builtins__'] = __builtins__
|
||||
_base_environment_['HTTP'] = HTTP
|
||||
_base_environment_['redirect'] = redirect
|
||||
_base_environment_['DAL'] = DAL
|
||||
_base_environment_['Field'] = Field
|
||||
_base_environment_['SQLDB'] = SQLDB # for backward compatibility
|
||||
_base_environment_['SQLField'] = SQLField # for backward compatibility
|
||||
_base_environment_['SQLFORM'] = SQLFORM
|
||||
_base_environment_['SQLTABLE'] = SQLTABLE
|
||||
_base_environment_['LOAD'] = LOAD
|
||||
|
||||
|
||||
def build_environment(request, response, session, store_current=True):
|
||||
"""
|
||||
Build the environment dictionary into which web2py files are executed.
|
||||
"""
|
||||
h,v = html,validators
|
||||
environment = dict((k,getattr(h,k)) for k in h.__all__)
|
||||
environment.update((k,getattr(v, k)) for k in v.__all__)
|
||||
#h,v = html,validators
|
||||
environment = dict(_base_environment_)
|
||||
|
||||
if not request.env:
|
||||
request.env = Storage()
|
||||
# Enable standard conditional models (i.e., /*.py, /[controller]/*.py, and
|
||||
# /[controller]/[function]/*.py)
|
||||
response.models_to_run = [r'^\w+\.py$', r'^%s/\w+\.py$' % request.controller,
|
||||
r'^%s/%s/\w+\.py$' % (request.controller, request.function)]
|
||||
|
||||
r'^%s/%s/\w+\.py$' % (request.controller, request.function)]
|
||||
|
||||
t = environment['T'] = translator(request)
|
||||
c = environment['cache'] = Cache(request)
|
||||
|
||||
if store_current:
|
||||
current.globalenv = environment
|
||||
current.request = request
|
||||
@@ -383,30 +408,21 @@ def build_environment(request, response, session, store_current=True):
|
||||
current.cache = c
|
||||
|
||||
global __builtins__
|
||||
if is_jython: # jython hack
|
||||
if is_jython: # jython hack
|
||||
__builtins__ = mybuiltin()
|
||||
elif is_pypy: # apply the same hack to pypy too
|
||||
elif is_pypy: # apply the same hack to pypy too
|
||||
__builtins__ = mybuiltin()
|
||||
else:
|
||||
__builtins__['__import__'] = __builtin__.__import__ ### WHY?
|
||||
environment['__builtins__'] = __builtins__
|
||||
environment['HTTP'] = HTTP
|
||||
environment['redirect'] = redirect
|
||||
__builtins__['__import__'] = __builtin__.__import__ # WHY?
|
||||
environment['request'] = request
|
||||
environment['response'] = response
|
||||
environment['session'] = session
|
||||
environment['DAL'] = DAL
|
||||
environment['Field'] = Field
|
||||
environment['SQLDB'] = SQLDB # for backward compatibility
|
||||
environment['SQLField'] = SQLField # for backward compatibility
|
||||
environment['SQLFORM'] = SQLFORM
|
||||
environment['SQLTABLE'] = SQLTABLE
|
||||
environment['LOAD'] = LOAD
|
||||
environment['local_import'] = \
|
||||
lambda name, reload=False, app=request.application:\
|
||||
local_import_aux(name,reload,app)
|
||||
local_import_aux(name, reload, app)
|
||||
BaseAdapter.set_folder(pjoin(request.folder, 'databases'))
|
||||
response._view_environment = copy.copy(environment)
|
||||
custom_import_install()
|
||||
return environment
|
||||
|
||||
|
||||
@@ -426,7 +442,7 @@ def read_pyc(filename):
|
||||
"""
|
||||
data = read_file(filename, 'rb')
|
||||
if not is_gae and data[:4] != imp.get_magic():
|
||||
raise SystemError, 'compiled code is incompatible'
|
||||
raise SystemError('compiled code is incompatible')
|
||||
return marshal.loads(data[8:])
|
||||
|
||||
|
||||
@@ -437,7 +453,10 @@ def compile_views(folder):
|
||||
|
||||
path = pjoin(folder, 'views')
|
||||
for file in listdir(path, '^[\w/\-]+(\.\w+)+$'):
|
||||
data = parse_template(file, path)
|
||||
try:
|
||||
data = parse_template(file, path)
|
||||
except Exception, e:
|
||||
raise Exception("%s in %s" % (e, file))
|
||||
filename = ('views/%s.py' % file).replace('/', '_').replace('\\', '_')
|
||||
filename = pjoin(folder, 'compiled', filename)
|
||||
write_file(filename, data)
|
||||
@@ -453,7 +472,7 @@ def compile_models(folder):
|
||||
path = pjoin(folder, 'models')
|
||||
for file in listdir(path, '.+\.py$'):
|
||||
data = read_file(pjoin(path, file))
|
||||
filename = pjoin(folder, 'compiled','models',file)
|
||||
filename = pjoin(folder, 'compiled', 'models', file)
|
||||
mktree(filename)
|
||||
write_file(filename, data)
|
||||
save_pyc(filename)
|
||||
@@ -468,14 +487,14 @@ def compile_controllers(folder):
|
||||
path = pjoin(folder, 'controllers')
|
||||
for file in listdir(path, '.+\.py$'):
|
||||
### why is this here? save_pyc(pjoin(path, file))
|
||||
data = read_file(pjoin(path,file))
|
||||
data = read_file(pjoin(path, file))
|
||||
exposed = regex_expose.findall(data)
|
||||
for function in exposed:
|
||||
command = data + "\nresponse._vars=response._caller(%s)\n" % \
|
||||
function
|
||||
filename = pjoin(folder, 'compiled', ('controllers/'
|
||||
+ file[:-3]).replace('/', '_')
|
||||
+ '_' + function + '.py')
|
||||
+ '_' + function + '.py')
|
||||
write_file(filename, command)
|
||||
save_pyc(filename)
|
||||
os.unlink(filename)
|
||||
@@ -495,19 +514,19 @@ def run_models_in(environment):
|
||||
for model in listdir(cpath, '^models_\w+\.pyc$', 0):
|
||||
restricted(read_pyc(model), environment, layer=model)
|
||||
path = pjoin(cpath, 'models')
|
||||
models = listdir(path, '^\w+\.pyc$',0,sort=False)
|
||||
compiled=True
|
||||
models = listdir(path, '^\w+\.pyc$', 0, sort=False)
|
||||
compiled = True
|
||||
else:
|
||||
path = pjoin(folder, 'models')
|
||||
models = listdir(path, '^\w+\.py$',0,sort=False)
|
||||
compiled=False
|
||||
models = listdir(path, '^\w+\.py$', 0, sort=False)
|
||||
compiled = False
|
||||
n = len(path) + 1
|
||||
for model in models:
|
||||
regex = environment['response'].models_to_run
|
||||
if isinstance(regex, list):
|
||||
regex = re_compile('|'.join(regex))
|
||||
file = model[n:].replace(os.path.sep, '/').replace('.pyc', '.py')
|
||||
if not regex.search(file) and c!= 'appadmin':
|
||||
if not regex.search(file) and c != 'appadmin':
|
||||
continue
|
||||
elif compiled:
|
||||
code = read_pyc(model)
|
||||
@@ -527,24 +546,24 @@ def run_controller_in(controller, function, environment):
|
||||
"""
|
||||
|
||||
# if compiled should run compiled!
|
||||
|
||||
folder = environment['request'].folder
|
||||
path = pjoin(folder, 'compiled')
|
||||
badc = 'invalid controller (%s/%s)' % (controller, function)
|
||||
badf = 'invalid function (%s/%s)' % (controller, function)
|
||||
if os.path.exists(path):
|
||||
filename = pjoin(path, 'controllers_%s_%s.pyc'
|
||||
% (controller, function))
|
||||
% (controller, function))
|
||||
if not os.path.exists(filename):
|
||||
raise HTTP(404,
|
||||
rewrite.thread.routes.error_message % badf,
|
||||
rewrite.THREAD_LOCAL.routes.error_message % badf,
|
||||
web2py_error=badf)
|
||||
restricted(read_pyc(filename), environment, layer=filename)
|
||||
elif function == '_TEST':
|
||||
# TESTING: adjust the path to include site packages
|
||||
from settings import global_settings
|
||||
from admin import abspath, add_path_first
|
||||
paths = (global_settings.gluon_parent, abspath('site-packages', gluon=True), abspath('gluon', gluon=True), '')
|
||||
paths = (global_settings.gluon_parent, abspath(
|
||||
'site-packages', gluon=True), abspath('gluon', gluon=True), '')
|
||||
[add_path_first(path) for path in paths]
|
||||
# TESTING END
|
||||
|
||||
@@ -552,7 +571,7 @@ def run_controller_in(controller, function, environment):
|
||||
% controller)
|
||||
if not os.path.exists(filename):
|
||||
raise HTTP(404,
|
||||
rewrite.thread.routes.error_message % badc,
|
||||
rewrite.THREAD_LOCAL.routes.error_message % badc,
|
||||
web2py_error=badc)
|
||||
environment['__symbols__'] = environment.keys()
|
||||
code = read_file(filename)
|
||||
@@ -563,30 +582,30 @@ def run_controller_in(controller, function, environment):
|
||||
% controller)
|
||||
if not os.path.exists(filename):
|
||||
raise HTTP(404,
|
||||
rewrite.thread.routes.error_message % badc,
|
||||
rewrite.THREAD_LOCAL.routes.error_message % badc,
|
||||
web2py_error=badc)
|
||||
code = read_file(filename)
|
||||
exposed = regex_expose.findall(code)
|
||||
if not function in exposed:
|
||||
raise HTTP(404,
|
||||
rewrite.thread.routes.error_message % badf,
|
||||
rewrite.THREAD_LOCAL.routes.error_message % badf,
|
||||
web2py_error=badf)
|
||||
code = "%s\nresponse._vars=response._caller(%s)\n" % (code, function)
|
||||
if is_gae:
|
||||
layer = filename + ':' + function
|
||||
code = getcfs(layer, filename, lambda: compile2(code,layer))
|
||||
code = getcfs(layer, filename, lambda: compile2(code, layer))
|
||||
restricted(code, environment, filename)
|
||||
response = environment['response']
|
||||
vars=response._vars
|
||||
vars = response._vars
|
||||
if response.postprocessing:
|
||||
for p in response.postprocessing:
|
||||
vars = p(vars)
|
||||
if isinstance(vars,unicode):
|
||||
vars = reduce(lambda vars, p: p(vars), response.postprocessing, vars)
|
||||
if isinstance(vars, unicode):
|
||||
vars = vars.encode('utf8')
|
||||
elif hasattr(vars,'xml') and callable(vars.xml):
|
||||
elif hasattr(vars, 'xml') and callable(vars.xml):
|
||||
vars = vars.xml()
|
||||
return vars
|
||||
|
||||
|
||||
def run_view_in(environment):
|
||||
"""
|
||||
Executes the view for the requested action.
|
||||
@@ -594,7 +613,6 @@ def run_view_in(environment):
|
||||
or `view/generic.extension`
|
||||
It tries the pre-compiled views_controller_function.pyc before compiling it.
|
||||
"""
|
||||
|
||||
request = environment['request']
|
||||
response = environment['response']
|
||||
view = response.view
|
||||
@@ -604,7 +622,7 @@ def run_view_in(environment):
|
||||
if response.generic_patterns:
|
||||
patterns = response.generic_patterns
|
||||
regex = re_compile('|'.join(map(fnmatch.translate, patterns)))
|
||||
short_action = '%(controller)s/%(function)s.%(extension)s' % request
|
||||
short_action = '%(controller)s/%(function)s.%(extension)s' % request
|
||||
allow_generic = regex.search(short_action)
|
||||
else:
|
||||
allow_generic = False
|
||||
@@ -624,13 +642,13 @@ def run_view_in(environment):
|
||||
files.append('views_generic.pyc')
|
||||
# end backward compatibility code
|
||||
for f in files:
|
||||
filename = pjoin(path,f)
|
||||
filename = pjoin(path, f)
|
||||
if os.path.exists(filename):
|
||||
code = read_pyc(filename)
|
||||
restricted(code, environment, layer=filename)
|
||||
return
|
||||
raise HTTP(404,
|
||||
rewrite.thread.routes.error_message % badv,
|
||||
rewrite.THREAD_LOCAL.routes.error_message % badv,
|
||||
web2py_error=badv)
|
||||
else:
|
||||
filename = pjoin(folder, 'views', view)
|
||||
@@ -639,20 +657,21 @@ def run_view_in(environment):
|
||||
filename = pjoin(folder, 'views', view)
|
||||
if not os.path.exists(filename):
|
||||
raise HTTP(404,
|
||||
rewrite.thread.routes.error_message % badv,
|
||||
rewrite.THREAD_LOCAL.routes.error_message % badv,
|
||||
web2py_error=badv)
|
||||
layer = filename
|
||||
if is_gae:
|
||||
ccode = getcfs(layer, filename,
|
||||
lambda: compile2(parse_template(view,
|
||||
pjoin(folder, 'views'),
|
||||
context=environment),layer))
|
||||
context=environment), layer))
|
||||
else:
|
||||
ccode = parse_template(view,
|
||||
pjoin(folder, 'views'),
|
||||
context=environment)
|
||||
restricted(ccode, environment, layer)
|
||||
|
||||
|
||||
def remove_compiled_application(folder):
|
||||
"""
|
||||
Deletes the folder `compiled` containing the compiled application.
|
||||
@@ -660,7 +679,7 @@ def remove_compiled_application(folder):
|
||||
try:
|
||||
shutil.rmtree(pjoin(folder, 'compiled'))
|
||||
path = pjoin(folder, 'controllers')
|
||||
for file in listdir(path,'.*\.pyc$',drop=False):
|
||||
for file in listdir(path, '.*\.pyc$', drop=False):
|
||||
os.unlink(file)
|
||||
except OSError:
|
||||
pass
|
||||
@@ -698,10 +717,3 @@ def test():
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user