Skip to content
Browse files

upgraded web2py.js and jquery.js

  • Loading branch information...
1 parent ca46bf0 commit 3071bd317925d9679026576f7ca0ff53e3fb86e9 @mdipierro committed
Showing with 1,043 additions and 291 deletions.
  1. +248 −54 controllers/appadmin.py
  2. +92 −73 languages/pt-br.py
  3. +5 −2 static/js/jquery.js
  4. +698 −162 static/js/web2py.js
View
302 controllers/appadmin.py
@@ -11,7 +11,10 @@
import gluon.contenttype
import gluon.fileutils
-response.subtitle = 'Database Administration (appadmin)'
+try:
+ import pygraphviz as pgv
+except ImportError:
+ pgv = None
# ## critical --- make a copy of the environment
@@ -23,23 +26,41 @@
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, )
if request.env.http_x_forwarded_for or request.is_https:
session.secure()
-elif (remote_addr not in hosts) and (remote_addr != "127.0.0.1"):
+elif (remote_addr not in hosts) and (remote_addr != "127.0.0.1") and \
+ (request.function != 'manage'):
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.function == 'manage':
+ if not 'auth' in globals() or not request.args:
+ redirect(URL(request.controller, 'index'))
+ manager_action = auth.settings.manager_actions.get(request.args(0), None)
+ if manager_action is None and request.args(0) == 'auth':
+ manager_action = dict(role=auth.settings.auth_manager_role,
+ heading=T('Manage Access Control'),
+ tables=[auth.table_user(),
+ auth.table_group(),
+ auth.table_permission()])
+ manager_role = manager_action.get('role', None) if manager_action else None
+ auth.requires_membership(manager_role)(lambda: None)()
+ menu = False
+elif (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))))
+else:
+ response.subtitle = 'Database Administration (appadmin)'
+ menu = True
ignore_rw = True
response.view = 'appadmin.html'
-response.menu = [[T('design'), False, URL('admin', 'default', 'design',
+if menu:
+ response.menu = [[T('design'), False, URL('admin', 'default', 'design',
args=[request.application])], [T('db'), False,
URL('index')], [T('state'), False,
URL('state')], [T('cache'), False,
@@ -49,6 +70,10 @@
# ## auxiliary functions
# ###########################################################
+if False and request.tickets_db:
+ from gluon.restricted import TicketStorage
+ ts = TicketStorage()
+ ts._get_table(request.tickets_db, ts.tablename, request.application)
def get_databases(request):
dbs = {}
@@ -95,25 +120,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 +151,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 +162,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 +174,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 +218,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 +238,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 +270,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 +281,9 @@ def select():
nrows=nrows,
rows=rows,
query=request.vars.query,
- formcsv = formcsv,
- )
+ formcsv=formcsv,
+ tb=tb,
+ )
# ##########################################################
@@ -260,14 +293,17 @@ def select():
def update():
(db, table) = get_table(request)
- keyed = hasattr(db[table],'_primarykey')
+ keyed = hasattr(db[table], '_primarykey')
record = None
+ db[table]._common_filter = 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]]).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)).select().first()
if not record:
qry = query_by_table_type(table, db)
@@ -277,20 +313,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 +338,18 @@ def update():
def state():
return dict()
+
def ccache():
+ cache.ram.initialize()
+ cache.disk.initialize()
+
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 +373,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 = {
@@ -360,7 +409,7 @@ def GetInHMS(seconds):
return (hours, minutes, seconds)
- for key, value in cache.ram.storage.items():
+ for key, value in cache.ram.storage.iteritems():
if isinstance(value, dict):
ram['hits'] = value['hit_total'] - value['misses']
ram['misses'] = value['misses']
@@ -376,11 +425,13 @@ def GetInHMS(seconds):
if value[0] < ram['oldest']:
ram['oldest'] = value[0]
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
-
- locker = open(os.path.join(request.folder,
- 'cache/cache.lock'), 'a')
+ folder = os.path.join(request.folder,'cache')
+ if not os.path.exists(folder):
+ os.mkdir(folder)
+ locker = open(os.path.join(folder, '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(folder, 'cache.shelve'))
try:
for key, value in disk_storage.items():
if isinstance(value, dict):
@@ -411,7 +462,8 @@ def GetInHMS(seconds):
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,3 +489,145 @@ def key_table(keys):
return dict(form=form, total=total,
ram=ram, disk=disk, object_stats=hp != False)
+
+
+def table_template(table):
+ from gluon.html import TR, TD, TABLE, TAG
+
+ def FONT(*args, **kwargs):
+ return TAG.font(*args, **kwargs)
+
+ def types(field):
+ f_type = field.type
+ if not isinstance(f_type,str):
+ return ' '
+ elif f_type == 'string':
+ return field.length
+ elif f_type == 'id':
+ return B('pk')
+ elif f_type.startswith('reference') or \
+ f_type.startswith('list:reference'):
+ return B('fk')
+ else:
+ return ' '
+
+ # This is horribe HTML but the only one graphiz understands
+ rows = []
+ cellpadding = 4
+ color = "#000000"
+ bgcolor = "#FFFFFF"
+ face = "Helvetica"
+ face_bold = "Helvetica Bold"
+ border = 0
+
+ rows.append(TR(TD(FONT(table, _face=face_bold, _color=bgcolor),
+ _colspan=3, _cellpadding=cellpadding,
+ _align="center", _bgcolor=color)))
+ for row in db[table]:
+ rows.append(TR(TD(FONT(row.name, _color=color, _face=face_bold),
+ _align="left", _cellpadding=cellpadding,
+ _border=border),
+ TD(FONT(row.type, _color=color, _face=face),
+ _align="left", _cellpadding=cellpadding,
+ _border=border),
+ TD(FONT(types(row), _color=color, _face=face),
+ _align="center", _cellpadding=cellpadding,
+ _border=border)))
+ return "< %s >" % TABLE(*rows, **dict(_bgcolor=bgcolor, _border=1,
+ _cellborder=0, _cellspacing=0)
+ ).xml()
+
+
+def bg_graph_model():
+ graph = pgv.AGraph(layout='dot', directed=True, strict=False, rankdir='LR')
+
+ subgraphs = dict()
+ for tablename in db.tables:
+ if hasattr(db[tablename],'_meta_graphmodel'):
+ meta_graphmodel = db[tablename]._meta_graphmodel
+ else:
+ meta_graphmodel = dict(group='Undefined', color='#ECECEC')
+
+ group = meta_graphmodel['group'].replace(' ', '')
+ if not subgraphs.has_key(group):
+ subgraphs[group] = dict(meta=meta_graphmodel, tables=[])
+ subgraphs[group]['tables'].append(tablename)
+ else:
+ subgraphs[group]['tables'].append(tablename)
+
+ graph.add_node(tablename, name=tablename, shape='plaintext',
+ label=table_template(tablename))
+
+ for n, key in enumerate(subgraphs.iterkeys()):
+ graph.subgraph(nbunch=subgraphs[key]['tables'],
+ name='cluster%d' % n,
+ style='filled',
+ color=subgraphs[key]['meta']['color'],
+ label=subgraphs[key]['meta']['group'])
+
+ for tablename in db.tables:
+ for field in db[tablename]:
+ f_type = field.type
+ if isinstance(f_type,str) and (
+ f_type.startswith('reference') or
+ f_type.startswith('list:reference')):
+ referenced_table = f_type.split()[1].split('.')[0]
+ n1 = graph.get_node(tablename)
+ n2 = graph.get_node(referenced_table)
+ graph.add_edge(n1, n2, color="#4C4C4C", label='')
+
+ graph.layout()
+ #return graph.draw(format='png', prog='dot')
+ if not request.args:
+ return graph.draw(format='png', prog='dot')
+ else:
+ response.headers['Content-Disposition']='attachment;filename=graph.%s'%request.args(0)
+ if request.args(0) == 'dot':
+ return graph.string()
+ else:
+ return graph.draw(format=request.args(0), prog='dot')
+
+def graph_model():
+ return dict(databases=databases, pgv=pgv)
+
+def manage():
+ tables = manager_action['tables']
+ if isinstance(tables[0], str):
+ db = manager_action.get('db', auth.db)
+ db = globals()[db] if isinstance(db, str) else db
+ tables = [db[table] for table in tables]
+ if request.args(0) == 'auth':
+ auth.table_user()._plural = T('Users')
+ auth.table_group()._plural = T('Roles')
+ auth.table_membership()._plural = T('Memberships')
+ auth.table_permission()._plural = T('Permissions')
+ if request.extension != 'load':
+ return dict(heading=manager_action.get('heading',
+ T('Manage %(action)s') % dict(action=request.args(0).replace('_', ' ').title())),
+ tablenames=[table._tablename for table in tables],
+ labels=[table._plural.title() for table in tables])
+
+ table = tables[request.args(1, cast=int)]
+ formname = '%s_grid' % table._tablename
+ linked_tables = orderby = None
+ if request.args(0) == 'auth':
+ auth.table_group()._id.readable = \
+ auth.table_membership()._id.readable = \
+ auth.table_permission()._id.readable = False
+ auth.table_membership().user_id.label = T('User')
+ auth.table_membership().group_id.label = T('Role')
+ auth.table_permission().group_id.label = T('Role')
+ auth.table_permission().name.label = T('Permission')
+ if table == auth.table_user():
+ linked_tables=[auth.settings.table_membership_name]
+ elif table == auth.table_group():
+ orderby = 'role' if not request.args(3) or '.group_id' not in request.args(3) else None
+ elif table == auth.table_permission():
+ orderby = 'group_id'
+ kwargs = dict(user_signature=True, maxtextlength=1000,
+ orderby=orderby, linked_tables=linked_tables)
+ smartgrid_args = manager_action.get('smartgrid_args', {})
+ kwargs.update(**smartgrid_args.get('DEFAULT', {}))
+ kwargs.update(**smartgrid_args.get(table._tablename, {}))
+ grid = SQLFORM.smartgrid(table, args=request.args[:2], formname=formname, **kwargs)
+ return grid
View
165 languages/pt-br.py
@@ -3,107 +3,154 @@
'!langcode!': 'pt-br',
'!langname!': 'Português (do Brasil)',
'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" é uma expressão opcional como "campo1=\'novovalor\'". Você não pode atualizar ou apagar os resultados de um JOIN',
-'%Y-%m-%d': '%d-%m-%Y',
-'%Y-%m-%d %H:%M:%S': '%d-%m-%Y %H:%M:%S',
'%s %%{row} deleted': '%s linhas apagadas',
'%s %%{row} updated': '%s linhas atualizadas',
'%s selected': '%s selecionado',
-'About': 'Sobre',
-'Access Control': 'Controle de acesso',
+'%Y-%m-%d': '%d-%m-%Y',
+'%Y-%m-%d %H:%M:%S': '%d-%m-%Y %H:%M:%S',
+'About': 'About',
+'Access Control': 'Access Control',
+'Administrative Interface': 'Administrative Interface',
'Administrative interface': 'Interface administrativa',
'Ajax Recipes': 'Ajax Recipes',
+'appadmin is disabled because insecure channel': 'Administração desativada devido ao canal inseguro',
+'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?',
'Available Databases and Tables': 'Bancos de dados e tabelas disponíveis',
-'Buy this book': 'Compre este livro',
+'Buy this book': 'Buy this book',
+'cache': 'cache',
+'Cache': 'Cache',
+'Cache Keys': 'Cache Keys',
'Cannot be empty': 'Não pode ser vazio',
+'change password': 'modificar senha',
'Check to delete': 'Marque para apagar',
-'Client IP': 'IP do cliente',
+'Clear CACHE?': 'Clear CACHE?',
+'Clear DISK': 'Clear DISK',
+'Clear RAM': 'Clear RAM',
+'Client IP': 'Client IP',
'Community': 'Community',
+'Components and Plugins': 'Components and Plugins',
'Controller': 'Controlador',
'Copyright': 'Copyright',
'Current request': 'Requisição atual',
'Current response': 'Resposta atual',
'Current session': 'Sessão atual',
+'customize me!': 'Personalize-me!',
+'data uploaded': 'dados enviados',
+'Database': 'banco de dados',
+'Database %s select': 'Selecionar banco de dados %s',
+'db': 'bd',
'DB Model': 'Modelo BD',
-'Database': 'Banco de dados',
'Delete:': 'Apagar:',
'Demo': 'Demo',
-'Deployment Recipes': 'Ambiente de produção',
-'Description': 'Descrição',
-'Documentation': 'Documentação',
+'Deployment Recipes': 'Deployment Recipes',
+'Description': 'Description',
+'design': 'design',
+'DISK': 'DISK',
+'Disk Cache Keys': 'Disk Cache Keys',
+'Disk Cleared': 'Disk Cleared',
+'Documentation': 'Documentation',
+"Don't know what to do?": "Don't know what to do?",
+'done!': 'concluído!',
'Download': 'Download',
'E-mail': 'E-mail',
'Edit': 'Editar',
-'Edit This App': 'Edite este app',
-'Edit current record': 'Editar o registro atual',
-'Errors': 'Errors',
-'FAQ': 'FAQ',
-'First name': 'Primeiro nome',
-'Forms and Validators': 'Formulários e Validadores',
-'Free Applications': 'Applicações Livres',
-=======
-'Edit This App': 'Editar Esta Aplicação',
'Edit current record': 'Editar o registro atual',
+'edit profile': 'editar perfil',
+'Edit This App': 'Edit This App',
+'Email and SMS': 'Email and SMS',
'Errors': 'Errors',
+'export as csv file': 'exportar como um arquivo csv',
'FAQ': 'FAQ',
'First name': 'First name',
-'Forms and Validators': 'Formulários e Validadores',
+'Forms and Validators': 'Forms and Validators',
'Free Applications': 'Free Applications',
->>>>>>> 7f24c01f622f05d3c0e0161cd1a90f384a3bada1
'Group ID': 'Group ID',
-'Groups': 'Grupos',
+'Groups': 'Groups',
'Hello World': 'Olá Mundo',
'Home': 'Home',
+'How did you get here?': 'How did you get here?',
+'import': 'import',
'Import/Export': 'Importar/Exportar',
'Index': 'Início',
+'insert new': 'inserir novo',
+'insert new %s': 'inserir novo %s',
'Internal State': 'Estado Interno',
-'Introduction': 'Introdução',
+'Introduction': 'Introduction',
+'Invalid email': 'Invalid email',
'Invalid Query': 'Consulta Inválida',
-'Invalid email': 'E-mail inválido',
-'Last name': 'Sobrenome',
+'invalid request': 'requisição inválida',
+'Key': 'Key',
+'Last name': 'Last name',
'Layout': 'Layout',
+'Layout Plugins': 'Layout Plugins',
'Layouts': 'Layouts',
'Live chat': 'Live chat',
+'Live Chat': 'Live Chat',
+'login': 'Entrar',
'Login': 'Autentique-se',
+'logout': 'Sair',
'Lost Password': 'Esqueceu sua senha?',
+'lost password?': 'lost password?',
'Main Menu': 'Menu Principal',
+'Manage Cache': 'Manage Cache',
'Menu Model': 'Modelo de Menu',
-'Name': 'Nome',
+'My Sites': 'My Sites',
+'Name': 'Name',
'New Record': 'Novo Registro',
+'new record inserted': 'novo registro inserido',
+'next 100 rows': 'próximas 100 linhas',
'No databases in this application': 'Sem bancos de dados nesta aplicação',
'Online examples': 'Alguns exemplos',
+'or import from csv file': 'ou importar de um arquivo csv',
'Origin': 'Origin',
-'Other Recipes': 'Outros ambientes',
+'Other Plugins': 'Other Plugins',
+'Other Recipes': 'Other Recipes',
'Overview': 'Overview',
-'Password': 'Senha',
+'Password': 'Password',
'Plugins': 'Plugins',
'Powered by': 'Powered by',
-'Preface': 'Prefácio',
+'Preface': 'Preface',
+'previous 100 rows': '100 linhas anteriores',
'Python': 'Python',
'Query:': 'Consulta:',
-'Quick Examples': 'Exemplos rápidos',
-'Recipes': 'Ambientes',
-'Record ID': 'lembrar ID',
+'Quick Examples': 'Quick Examples',
+'RAM': 'RAM',
+'RAM Cache Keys': 'RAM Cache Keys',
+'Ram Cleared': 'Ram Cleared',
+'Recipes': 'Recipes',
+'Record': 'registro',
+'record does not exist': 'registro não existe',
+'Record ID': 'Record ID',
+'Record id': 'id do registro',
'Register': 'Registre-se',
+'register': 'Registre-se',
'Registration key': 'Registration key',
'Reset Password key': 'Reset Password key',
'Resources': 'Resources',
-'Role': 'Função',
+'Role': 'Role',
'Rows in Table': 'Linhas na tabela',
'Rows selected': 'Linhas selecionadas',
-'Semantic': 'Semantico',
+'Semantic': 'Semantic',
'Services': 'Services',
-'Stylesheet': 'Folhas de estilo',
-'Support': 'Suporte',
+'Size of cache:': 'Size of cache:',
+'state': 'estado',
+'Statistics': 'Statistics',
+'Stylesheet': 'Stylesheet',
+'submit': 'submit',
+'Support': 'Support',
'Sure you want to delete this object?': 'Está certo(a) que deseja apagar esse objeto ?',
-'Table name': 'nome da Tabela',
+'Table': 'tabela',
+'Table name': 'Table name',
'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'Uma "consulta" é uma condição como "db.tabela1.campo1==\'valor\'". Expressões como "db.tabela1.campo1==db.tabela2.campo2" resultam em um JOIN SQL.',
'The Core': 'The Core',
+'The output of the file is a dictionary that was rendered by the view %s': 'The output of the file is a dictionary that was rendered by the view %s',
'The Views': 'The Views',
-'The output of the file is a dictionary that was rendered by the view %s': 'A saída do arquivo é um dicionário que foi renderizada pela view %s',
'This App': 'This App',
-'This is a copy of the scaffolding application': 'Esta é uma cópia da aplicação scaffolding',
+'This is a copy of the scaffolding application': 'This is a copy of the scaffolding application',
+'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)',
'Timestamp': 'Timestamp',
'Twitter': 'Twitter',
+'unable to parse csv file': 'não foi possível analisar arquivo csv',
'Update:': 'Atualizar:',
'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) para AND, (...)|(...) para OR, e ~(...) para NOT para construir consultas mais complexas.',
'User ID': 'User ID',
@@ -114,38 +161,10 @@
'Welcome': 'Welcome',
'Welcome %s': 'Vem vindo %s',
'Welcome to web2py': 'Bem vindo ao web2py',
-'Which called the function %s located in the file %s': 'Que chamou a função %s localizada no arquivo %s',
-'You are successfully running web2py': 'Você está rodando web2py com sucesso',
-'You are successfully running web2py.': 'Você está rodando web2py com sucesso.',
-'You can modify this application and adapt it to your needs': 'Você pode modificar esta aplicação e adapta-las segundo suas necessidades',
-'You visited the url %s': 'Você acessou a url %s',
-'appadmin is disabled because insecure channel': 'Administração desativada devido ao canal inseguro',
-'cache': 'cache',
-'change password': 'modificar senha',
-'customize me!': 'Personalize-me!',
-'data uploaded': 'dados enviados',
-'Database': 'banco de dados',
-'Database %s select': 'Selecionar banco de dados %s',
-'db': 'bd',
-'design': 'design',
-'done!': 'concluído!',
-'edit profile': 'editar perfil',
-'export as csv file': 'exportar como um arquivo csv',
-'insert new': 'inserir novo',
-'insert new %s': 'inserir novo %s',
-'invalid request': 'requisição inválida',
-'login': 'Entrar',
-'logout': 'Sair',
-'lost password?': 'esqueceu sua senha?',
-'new record inserted': 'novo registro inserido',
-'next 100 rows': 'próximas 100 linhas',
-'or import from csv file': 'ou importar de um arquivo csv',
-'previous 100 rows': '100 linhas anteriores',
-'Record': 'registro',
-'record does not exist': 'registro não existe',
-'Record id': 'id do registro',
-'register': 'Registre-se',
-'state': 'estado',
-'Table': 'tabela',
-'unable to parse csv file': 'não foi possível analisar arquivo csv',
+'Welcome to web2py!': 'Welcome to web2py!',
+'Which called the function %s located in the file %s': 'Which called the function %s located in the file %s',
+'You are successfully running web2py': 'You are successfully running web2py',
+'You are successfully running web2py.': 'You are successfully running web2py.',
+'You can modify this application and adapt it to your needs': 'You can modify this application and adapt it to your needs',
+'You visited the url %s': 'You visited the url %s',
}
View
7 static/js/jquery.js
5 additions, 2 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
860 static/js/web2py.js
@@ -1,167 +1,703 @@
-function popup(url) {
- newwindow=window.open(url,'name','height=400,width=600');
- if (window.focus) newwindow.focus();
- return false;
-}
-function collapse(id) { jQuery('#'+id).slideToggle(); }
-function fade(id,value) { if(value>0) jQuery('#'+id).hide().fadeIn('slow'); else jQuery('#'+id).show().fadeOut('slow'); }
-function ajax(u,s,t) {
- query = '';
- if (typeof s == "string") {
- d = jQuery(s).serialize();
- if(d){ query = d; }
- } else {
+(function ($, undefined) {
+ /*
+ * Unobtrusive scripting adapter for jQuery, largely taken from
+ * the wonderful https://github.com/rails/jquery-ujs
+ *
+ *
+ * Released under the MIT license
+ *
+ */
+ if($.web2py !== undefined) {
+ $.error('web2py.js has already been loaded!');
+ }
+
+
+ String.prototype.reverse = function () {
+ return this.split('').reverse().join('');
+ };
+ var web2py;
+
+ $.web2py = web2py = {
+
+ popup: function (url) {
+ /* popup a window */
+ newwindow = window.open(url, 'name', 'height=400,width=600');
+ if(window.focus) newwindow.focus();
+ return false;
+ },
+ collapse: function (id) {
+ /* toggle an element */
+ $('#' + id).slideToggle();
+ },
+ fade: function (id, value) {
+ /*fade something*/
+ if(value > 0) $('#' + id).hide().fadeIn('slow');
+ else $('#' + id).show().fadeOut('slow');
+ },
+ ajax: function (u, s, t) {
+ /*simple ajax function*/
+ query = '';
+ if(typeof s == "string") {
+ d = $(s).serialize();
+ if(d) {
+ query = d;
+ }
+ } else {
pcs = [];
- if (s != null && s != undefined) for(i=0; i<s.length; i++) {
- q = jQuery("[name="+s[i]+"]").serialize();
- if(q){pcs.push(q);}
+ if(s != null && s != undefined)
+ for(i = 0; i < s.length; i++) {
+ q = $("[name=" + s[i] + "]").serialize();
+ if(q) {
+ pcs.push(q);
+ }
+ }
+ if(pcs.length > 0) {
+ query = pcs.join("&");
}
- if (pcs.length>0){query = pcs.join("&");}
- }
- jQuery.ajax({type: "POST", url: u, data: query, success: function(msg) { if(t) { if(t==':eval') eval(msg); else if(typeof t=='string') jQuery("#"+t).html(msg); else t(msg); } } });
-}
-
-String.prototype.reverse = function () { return this.split('').reverse().join('');};
-function web2py_ajax_fields(target) {
- var date_format = (typeof w2p_ajax_date_format != 'undefined') ? w2p_ajax_date_format : "%Y-%m-%d";
- var datetime_format = (typeof w2p_ajax_datetime_format != 'undefined') ? w2p_ajax_datetime_format : "%Y-%m-%d %H:%M:%S";
- jQuery("input.date",target).each(function() {Calendar.setup({inputField:this, ifFormat:date_format, showsTime:false });});
- jQuery("input.datetime",target).each(function() {Calendar.setup({inputField:this, ifFormat:datetime_format, showsTime: true, timeFormat: "24" });});
- jQuery("input.time",target).each(function(){jQuery(this).timeEntry();});
-
-};
-
-function web2py_ajax_init(target) {
- jQuery('.hidden', target).hide();
- jQuery('.error', target).hide().slideDown('slow');
- web2py_ajax_fields(target);
-};
-
-function web2py_event_handlers() {
- var doc = jQuery(document)
- doc.on('click', '.flash', function(e){jQuery(this).fadeOut('slow'); 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?";
- doc.on('click', "input[type='checkbox'].delete", function(){if(this.checked) if(!confirm(confirm_message)) this.checked=false;});
- doc.ajaxSuccess(function(e, xhr) {
- var redirect=xhr.getResponseHeader('web2py-redirect-location');
- if (redirect != null) {
- window.location = redirect;
- };
- });
-};
-
-jQuery(function() {
- var flash = jQuery('.flash');
- flash.hide();
- if(flash.html()) flash.slideDown();
- web2py_ajax_init(document);
- web2py_event_handlers();
-});
-
-function web2py_trap_form(action,target) {
- jQuery('#'+target+' form').each(function(i){
- var form=jQuery(this);
- if(!form.hasClass('no_trap'))
- form.submit(function(e){
- jQuery('.flash').hide().html('');
- web2py_ajax_page('post',action,form.serialize(),target);
- 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();
- });
- });
-}
-
-function web2py_ajax_page(method, action, data, target) {
- jQuery.ajax({'type':method, 'url':action, 'data':data,
- 'beforeSend':function(xhr) {
- xhr.setRequestHeader('web2py-component-location', document.location);
- xhr.setRequestHeader('web2py-component-element', target);},
- 'complete':function(xhr,text){
- var html=xhr.responseText;
- var content=xhr.getResponseHeader('web2py-component-content');
- var command=xhr.getResponseHeader('web2py-component-command');
- var flash=xhr.getResponseHeader('web2py-component-flash');
- var t = jQuery('#'+target);
- if(content=='prepend') t.prepend(html);
- else if(content=='append') t.append(html);
- else if(content!='hide') t.html(html);
- web2py_trap_form(action,target);
- web2py_trap_link(target);
- web2py_ajax_init('#'+target);
- if(command)
- eval(decodeURIComponent(command));
- if(flash)
- jQuery('.flash').html(decodeURIComponent(flash)).slideDown();
+ }
+ $.ajax({
+ type: "POST",
+ url: u,
+ data: query,
+ success: function (msg) {
+ if(t) {
+ if(t == ':eval') eval(msg);
+ else if(typeof t == 'string') $("#" + t).html(msg);
+ else t(msg);
+ }
+ }
+ });
+ },
+ ajax_fields: function (target) {
+ /*
+ *this attaches something to a newly loaded fragment/page
+ * Ideally all events should be bound to the document, so we can avoid calling
+ * this over and over... all will be bound to the document
+ */
+ /*adds btn class to buttons*/
+ $('button', target).addClass('btn');
+ $('form input[type="submit"], form input[type="button"]', target).addClass('btn');
+ /* javascript for PasswordWidget*/
+ $('input[type=password][data-w2p_entropy]', target).each(function () {
+ web2py.validate_entropy($(this));
+ });
+ /* javascript for ListWidget*/
+ $('ul.w2p_list', target).each(function () {
+ function pe(ul, e) {
+ var new_line = ml(ul);
+ rel(ul);
+ if($(e.target).parent().is(':visible')) {
+ /* make sure we didn't delete the element before we insert after */
+ new_line.insertAfter($(e.target).parent());
+ } else {
+ /* the line we clicked on was deleted, just add to end of list */
+ new_line.appendTo(ul);
+ }
+ new_line.find(":text").focus();
+ return false;
+ }
+
+ function rl(ul, e) {
+ if($(ul).children().length > 1) {
+ /* only remove if we have more than 1 item so the list is never empty */
+ $(e.target).parent().remove();
+ }
+ }
+
+ function ml(ul) {
+ /* clone the first field */
+ var line = $(ul).find("li:first").clone(true);
+ line.find(':text').val('');
+ return line;
+ }
+
+ function rel(ul) {
+ /* keep only as many as needed*/
+ $(ul).find("li").each(function () {
+ var trimmed = $.trim($(this.firstChild).val());
+ if(trimmed == '') $(this).remove();
+ else $(this.firstChild).val(trimmed);
+ });
+ }
+ var ul = this;
+ $(ul).find(":text").after('<a href="#">+</a>&nbsp;<a href="#">-</a>').keypress(function (e) {
+ return(e.which == 13) ? pe(ul, e) : true;
+ }).next().click(function (e) {
+ pe(ul, e);
+ e.preventDefault();
+ }).next().click(function (e) {
+ rl(ul, e);
+ e.preventDefault();
+ });
+ });
+ },
+ ajax_init: function (target) {
+ /*called whenever a fragment gets loaded */
+ $('.hidden', target).hide();
+ web2py.manage_errors(target);
+ web2py.ajax_fields(target);
+ web2py.show_if_handler(target);
+ web2py.component_handler(target);
+ },
+ /* manage errors in forms */
+ manage_errors: function (target) {
+ $('.error', target).hide().slideDown('slow');
+ },
+ after_ajax: function (xhr) {
+ /* called whenever an ajax request completes */
+ var command = xhr.getResponseHeader('web2py-component-command');
+ var flash = xhr.getResponseHeader('web2py-component-flash');
+ if(command !== null) {
+ eval(decodeURIComponent(command));
+ }
+ if(flash) {
+ web2py.flash(decodeURIComponent(flash))
+ }
+ },
+ event_handlers: function () {
+ /*
+ * This is called once for page
+ * Ideally it should bound all the things that are needed
+ * and require no dom manipulations
+ */
+ var doc = $(document);
+ doc.on('click', '.flash', function (e) {
+ var t = $(this);
+ if(t.css('top') == '0px') t.slideUp('slow');
+ else t.fadeOut();
+ });
+ 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?";
+ doc.on('click', "input[type='checkbox'].delete", function () {
+ if(this.checked)
+ if(!web2py.confirm(confirm_message)) this.checked = false;
+ });
+ var datetime_format = (typeof w2p_ajax_datetime_format != 'undefined') ? w2p_ajax_datetime_format : "%Y-%m-%d %H:%M:%S";
+ doc.on('click', "input.datetime", function () {
+ var tformat = $(this).data('w2p_datetime_format');
+ var active = $(this).data('w2p_datetime');
+ var format = (typeof tformat != 'undefined') ? tformat : datetime_format;
+ if(active === undefined) {
+ Calendar.setup({
+ inputField: this,
+ ifFormat: format,
+ showsTime: true,
+ timeFormat: "24"
+ });
+ $(this).attr('autocomplete', 'off');
+ $(this).data('w2p_datetime', 1);
+ $(this).trigger('click');
+ }
+ });
+ var date_format = (typeof w2p_ajax_date_format != 'undefined') ? w2p_ajax_date_format : "%Y-%m-%d";
+ doc.on('click', "input.date", function () {
+ var tformat = $(this).data('w2p_date_format');
+ var active = $(this).data('w2p_date');
+ var format = (typeof tformat != 'undefined') ? tformat : date_format;
+ if(active === undefined) {
+ Calendar.setup({
+ inputField: this,
+ ifFormat: format,
+ showsTime: false
+ });
+ $(this).data('w2p_date', 1);
+ $(this).attr('autocomplete', 'off');
+ $(this).trigger('click');
+ }
+ });
+ doc.on('focus', "input.time", function () {
+ var active = $(this).data('w2p_time');
+ if(active === undefined) {
+ $(this).timeEntry({
+ spinnerImage: ''
+ }).attr('autocomplete', 'off');
+ $(this).data('w2p_time', 1);
+ }
+ });
+ /* help preventing double form submission for normal form (not LOADed) */
+ $(doc).on('submit', 'form', function () {
+ var submit_button = $(this).find(web2py.formInputClickSelector);
+ web2py.disableElement(submit_button);
+ });
+ doc.ajaxSuccess(function (e, xhr) {
+ var redirect = xhr.getResponseHeader('web2py-redirect-location');
+ if(redirect !== null) {
+ window.location = redirect;
+ };
+ /* run this here only if this Ajax request is NOT for a web2py component. */
+ if(xhr.getResponseHeader('web2py-component-content') == null) {
+ web2py.after_ajax(xhr);
+ };
+ });
+
+ doc.ajaxError(function (e, xhr, settings, exception) {
+ /*personally I don't like it.
+ *if there's an error it it flashed and can be removed
+ *as any other message
+ *doc.off('click', '.flash')
+ */
+ switch(xhr.status) {
+ case 500:
+ web2py.flash(ajax_error_500);
+ }
+ });
+
+ },
+ trap_form: function (action, target) {
+ /* traps any LOADed form */
+ $('#' + target + ' form').each(function (i) {
+ var form = $(this);
+ form.attr('data-w2p_target', target);
+ if(!form.hasClass('no_trap')) {
+ /* should be there by default */
+ form.submit(function (e) {
+ web2py.disableElement(form.find(web2py.formInputClickSelector));
+ web2py.hide_flash();
+ web2py.ajax_page('post', action, form.serialize(), target, form);
+ e.preventDefault();
+ });
+ }
+ });
+ },
+ trap_link: function (target) {
+ $('#' + target + ' a.w2p_trap').each(function (i) {
+ var link = $(this);
+ link.click(function (e) {
+ web2py.hide_flash();
+ web2py.ajax_page('get', link.attr('href'), [], target);
+ e.preventDefault();
+ });
+ });
+ },
+ ajax_page: function (method, action, data, target, element) {
+ /* element is a new parameter, but should be put be put in front */
+ if(element == undefined) element = $(document);
+ /* if target is not there, fill it with something that there isn't in the page*/
+ if(target == undefined || target == '') target = 'w2p_none';
+ if(web2py.fire(element, 'ajax:before', null, target )) { /*test a usecase, should stop here if returns false */
+ $.ajax({
+ 'type': method,
+ 'url': action,
+ 'data': data,
+ 'beforeSend': function (xhr, settings) {
+ xhr.setRequestHeader('web2py-component-location', document.location);
+ xhr.setRequestHeader('web2py-component-element', target);
+ return web2py.fire(element, 'ajax:beforeSend', [xhr, settings], target); //test a usecase, should stop here if returns false
+ },
+ 'success': function (data, status, xhr) {
+ /*bummer for form submissions....the element is not there after complete
+ *because it gets replaced by the new response....
+ */
+ web2py.fire(element, 'ajax:success', [data, status, xhr], target);
+ },
+ 'error': function (xhr, status, error) {
+ /*bummer for form submissions....in addition to the element being not there after
+ *complete because it gets replaced by the new response, standard form
+ *handling just returns the same status code for good and bad
+ *form submissions (i.e. that triggered a validator error)
+ */
+ web2py.fire(element, 'ajax:error', [xhr, status, error], target);
+ },
+ 'complete': function (xhr, status) {
+ web2py.fire(element, 'ajax:complete', [xhr, status], target);
+ web2py.updatePage(xhr, target); /* Parse and load the html received */
+ web2py.trap_form(action, target);
+ web2py.trap_link(target);
+ web2py.ajax_init('#' + target);
+ web2py.after_ajax(xhr);
+ }
+ });
+ }
+ },
+ component: function (action, target, timeout, times, el) {
+ /* element is a new parameter, but should be put in front */
+ $(function () {
+ var jelement = $("#" + target);
+ var element = jelement.get(0);
+ var statement = "jQuery('#" + target + "').get(0).reload();";
+ element.reload = function () {
+ /* Continue if times is Infinity or
+ * the times limit is not reached
+ */
+ if(element.reload_check()) {
+ web2py.ajax_page('get', action, null, target, el);
+ }
+ };
+ /* Method to check timing limit */
+ element.reload_check = function () {
+ if(jelement.hasClass('w2p_component_stop')) {
+ clearInterval(this.timing);
+ return false;
+ }
+ if(this.reload_counter == Infinity) {
+ return true;
+ } else {
+ if(!isNaN(this.reload_counter)) {
+ this.reload_counter -= 1;
+ if(this.reload_counter < 0) {
+ if(!this.run_once) {
+ clearInterval(this.timing);
+ return false;
+ }
+ } else {
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+ if(!isNaN(timeout)) {
+ element.timeout = timeout;
+ element.reload_counter = times;
+ if(times > 1) {
+ /* Multiple or infinite reload
+ * Run first iteration
+ */
+ web2py.ajax_page('get', action, null, target, el);
+ element.run_once = false;
+ element.timing = setInterval(statement, timeout);
+ element.reload_counter -= 1;
+ } else if(times == 1) {
+ /* Run once with timeout */
+ element.run_once = true;
+ element.setTimeout = setTimeout;
+ element.timing = setTimeout(statement, timeout);
+ }
+ } else {
+ /* run once (no timeout specified) */
+ element.reload_counter = Infinity;
+ web2py.ajax_page('get', action, null, target, el);
+ }
+ });
+ },
+ updatePage: function (xhr, target) {
+ var t = $('#' + target);
+ var html = $.parseHTML(xhr.responseText, document, true);
+ var title_elements = $(html).filter('title').add($(html).find('title'));
+ var title = title_elements.last().text();
+ if (title) {
+ title_elements.remove(); /* Remove any title elements from the response */
+ document.title = $.trim(title); /* Set the new document title */
+ }
+ var content = xhr.getResponseHeader('web2py-component-content');
+ if(content == 'prepend') t.prepend(xhr.responseText);
+ else if(content == 'append') t.append(xhr.responseText);
+ else if(content != 'hide') t.html(html);
+ },
+ calc_entropy: function (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
+ },
+ validate_entropy: function (myfield, req_entropy) {
+ if(myfield.data('w2p_entropy') != undefined) req_entropy = myfield.data('w2p_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');
+ },
+ web2py_websocket: function (url, onmessage, onopen, onclose) {
+ if("WebSocket" in window) {
+ var ws = new WebSocket(url);
+ ws.onopen = onopen ? onopen : (function () {});
+ ws.onmessage = onmessage;
+ ws.onclose = onclose ? onclose : (function () {});
+ return true; /* supported */
+ } else return false; /* not supported */
+ },
+ /* new from here */
+ /* Form input elements bound by jquery-uj */
+ formInputClickSelector: 'input[type=submit], input[type=image], button[type=submit], button:not([type])',
+ /* Form input elements disabled during form submission */
+ disableSelector: 'input, button, textarea, select',
+ /* Form input elements re-enabled after form submission */
+ enableSelector: 'input:disabled, button:disabled, textarea:disabled, select:disabled',
+ /* Triggers an event on an element and returns false if the event result is false */
+ fire: function (obj, type, data, target) {
+ var event = $.Event(type, {'containerTarget': $('#' + target)[0]});
+ obj.trigger(event, data);
+ return event.result !== false;
+ },
+ /* Helper function, needed to provide consistent behavior in IE */
+ stopEverything: function (e) {
+ $(e.target).trigger('w2p:everythingStopped');
+ e.stopImmediatePropagation();
+ return false;
+ },
+ confirm: function (message) {
+ return confirm(message);
+ },
+ /* replace element's html with the 'data-disable-with' after storing original html
+ * and prevent clicking on it */
+ disableElement: function (el) {
+ el.addClass('disabled');
+ var method = el.prop('type') == 'submit' ? 'val' : 'html';
+ var disable_with_message = (typeof w2p_ajax_disable_with_message != 'undefined') ? w2p_ajax_disable_with_message : "Working...";
+ /*store enabled state*/
+ el.data('w2p:enable-with', el[method]());
+ /*if you don't want to see "working..." on buttons, replace the following
+ * two lines with this one
+ * el.data('w2p_disable_with', el[method]());
+ */
+ if((el.data('w2p_disable_with') == 'default') || (el.data('w2p_disable_with') === undefined)) {
+ el.data('w2p_disable_with', disable_with_message);
+ }
+
+ /* set to disabled state*/
+ el[method](el.data('w2p_disable_with'));
+
+ el.bind('click.w2pDisable', function (e) { /* prevent further clicking*/
+ return web2py.stopEverything(e);
+ });
+ },
+
+ /* restore element to its original state which was disabled by 'disableElement' above*/
+ enableElement: function (el) {
+ var method = el.prop('type') == 'submit' ? 'val' : 'html';
+ if(el.data('w2p:enable-with') !== undefined) {
+ /* set to old enabled state */
+ el[method](el.data('w2p:enable-with'));
+ el.removeData('w2p:enable-with');
+ }
+ el.removeClass('disabled');
+ el.unbind('click.w2pDisable');
+ },
+ /*convenience wrapper, internal use only */
+ simple_component: function (action, target, element) {
+ web2py.component(action, target, 0, 1, element);
+ },
+ /*helper for flash messages*/
+ flash: function (message, status) {
+ var flash = $('.flash');
+ web2py.hide_flash();
+ flash.html(message).addClass(status);
+ if(flash.html()) flash.append('<span id="closeflash"> &times; </span>').slideDown();
+ },
+ hide_flash: function () {
+ $('.flash').hide().html('');
+ },
+ show_if_handler: function (target) {
+ var triggers = {};
+ var show_if = function () {
+ var t = $(this);
+ var id = t.attr('id');
+ t.attr('value', t.val());
+ for(var k = 0; k < triggers[id].length; k++) {
+ var dep = $('#' + triggers[id][k], target);
+ var tr = $('#' + triggers[id][k] + '__row', target);
+ if(t.is(dep.attr('data-show-if'))) tr.slideDown();
+ else tr.hide();
+ }
+ };
+ $('[data-show-trigger]', target).each(function () {
+ var name = $(this).attr('data-show-trigger');
+ if(!triggers[name]) triggers[name] = [];
+ triggers[name].push($(this).attr('id'));
+ });
+ for(var name in triggers) {
+ $('#' + name, target).change(show_if).keyup(show_if);
+ show_if.call($('#' + name, target));
+ };
+ },
+ component_handler: function (target) {
+ $('div[data-w2p_remote]', target).each(function () {
+ var remote, times, timeout, target;
+ var el = $(this);
+ remote = el.data('w2p_remote');
+ times = el.data('w2p_times');
+ timeout = el.data('w2p_timeout');
+ target = el.attr('id');
+ web2py.component(remote, target, timeout, times, $(this));
+ })
+ },
+ a_handler: function (el, e) {
+ e.preventDefault();
+ var method = el.data('w2p_method');
+ var action = el.attr('href');
+ var target = el.data('w2p_target');
+ var confirm_message = el.data('w2p_confirm');
+
+ var pre_call = el.data('w2p_pre_call');
+ if(pre_call != undefined) {
+ eval(pre_call);
+ }
+ if(confirm_message != undefined) {
+ if(confirm_message == 'default') confirm_message = w2p_ajax_confirm_message || 'Are you sure you want to delete this object?';
+ if(!web2py.confirm(confirm_message)) {
+ web2py.stopEverything(e);
+ return;
+ }
+ }
+ if(target == undefined) {
+ if(method == 'GET') {
+ web2py.ajax_page('get', action, [], '', el);
+ } else if(method == 'POST') {
+ web2py.ajax_page('post', action, [], '', el);
+ }
+ } else {
+ if(method == 'GET') {
+ web2py.ajax_page('get', action, [], target, el);
+ } else if(method == 'POST') {
+ web2py.ajax_page('post', action, [], target, el);
+ }
+ }
+ },
+ a_handlers: function () {
+ var el = $(document);
+ el.on('click', 'a[data-w2p_method]', function (e) {
+ web2py.a_handler($(this), e);
+ });
+ /* removal of element should happen only on success */
+ el.on('ajax:success', 'a[data-w2p_method][data-w2p_remove]', function (e) {
+ var el = $(this);
+ var toremove = el.data('w2p_remove');
+ if(toremove != undefined) {
+ toremove = el.closest(toremove);
+ if(!toremove.length) {
+ /*this enables removal of whatever selector if a closest is not found */
+ toremove = $(toremove);
+ }
+ toremove.remove();
+ }
+ });
+ el.on('ajax:beforeSend', 'a[data-w2p_method][data-w2p_disable_with]', function (e) {
+ web2py.disableElement($(this));
+ });
+ /*re-enable click on completion*/
+ el.on('ajax:complete', 'a[data-w2p_method][data-w2p_disable_with]', function (e) {
+ web2py.enableElement($(this));
+ });
+ },
+ /* Disables form elements:
+ - Caches element value in 'ujs:enable-with' data store
+ - Replaces element text with value of 'data-disable-with' attribute
+ - Sets disabled property to true
+ */
+ disableFormElements: function (form) {
+ form.find(web2py.disableSelector).each(function () {
+ var element = $(this),
+ method = element.is('button') ? 'html' : 'val';
+ var disable_with = element.data('w2p_disable_with');
+ if(disable_with == undefined) {
+ element.data('w2p_disable_with', element[method]())
+ }
+ element.data('w2p:enable-with', element[method]());
+ element[method](element.data('w2p_disable_with'));
+ element.prop('disabled', true);
+ });
+ },
+
+ /* Re-enables disabled form elements:
+ - Replaces element text with cached value from 'ujs:enable-with' data store (created in `disableFormElements`)
+ - Sets disabled property to false
+ */
+ enableFormElements: function (form) {
+ form.find(web2py.enableSelector).each(function () {
+ var element = $(this),
+ method = element.is('button') ? 'html' : 'val';
+ if(element.data('w2p:enable-with')) element[method](element.data('w2p:enable-with'));
+ element.prop('disabled', false);
+ });
+ },
+ form_handlers: function () {
+ var el = $(document);
+ el.on('ajax:beforeSend', 'form[data-w2p_target]', function (e) {
+ web2py.disableFormElements($(this));
+ });
+ el.on('ajax:complete', 'form[data-w2p_target]', function (e) {
+ web2py.enableFormElements($(this));
+ });
}
+ }
+
+ /*end of functions */
+ /*main hook*/
+ $(function () {
+ var flash = $('.flash');
+ flash.hide();
+ if(flash.html()) web2py.flash(flash.html());
+ web2py.ajax_init(document);
+ web2py.event_handlers();
+ web2py.a_handlers();
+ web2py.form_handlers();
});
-}
-
-function web2py_component(action, target, timeout, times){
- jQuery(function(){
- var element = jQuery("#" + target).get(0);
- var statement = "jQuery('#" + target + "').get(0).reload();";
- element.reload = function (){
- // Continue if times is Infinity or
- // the times limit is not reached
- if (this.reload_check()){
- web2py_ajax_page('get', action, null, target);} }; // reload
- // Method to check timing limit
- element.reload_check = function (){
- if (this.reload_counter == Infinity){return true;}
- else {
- if (!isNaN(this.reload_counter)){
- this.reload_counter -= 1;
- if (this.reload_counter < 0){
- if (!this.run_once){
- clearInterval(this.timing);
- return false;
- }
- }
- else{return true;}
- } }
- return false;}; // reload check
- if (!isNaN(timeout)){
- element.timeout = timeout;
- element.reload_counter = times;
- if (times > 1){
- // Multiple or infinite reload
- // Run first iteration
- web2py_ajax_page('get', action, null, target);
- element.run_once = false;
- element.timing = setInterval(statement, timeout);
- element.reload_counter -= 1;
- }
- else if (times == 1) {
- // Run once with timeout
- element.run_once = true;
- element.setTimeout = setTimeout;
- element.timing = setTimeout(statement, timeout);
- }
- } else {
- // run once (no timeout specified)
- element.reload_counter = Infinity;
- web2py_ajax_page('get', action, null, target);
- } }); }
-
-function web2py_comet(url,onmessage,onopen,onclose) {
- if ("WebSocket" in window) {
- var ws = new WebSocket(url);
- ws.onopen = onopen?onopen:(function(){});
- ws.onmessage = onmessage;
- ws.onclose = onclose?onclose:(function(){});
- return true; // supported
- } else return false; // not supported
-}
+
+})(jQuery);
+
+/* compatibility code - start */
+ajax = jQuery.web2py.ajax;
+web2py_component = jQuery.web2py.component;
+web2py_websocket = jQuery.web2py.websocket;
+web2py_ajax_page = jQuery.web2py.ajax_page;
+/*needed for IS_STRONG(entropy)*/
+web2py_validate_entropy = jQuery.web2py.validate_entropy;
+/*needed for crud.search and SQLFORM.grid's search*/
+web2py_ajax_fields = jQuery.web2py.ajax_fields;
+/*used for LOAD(ajax=False)*/
+web2py_trap_form = jQuery.web2py.trap_form;
+
+/*undocumented - rare*/
+popup = jQuery.web2py.popup;
+collapse = jQuery.web2py.collapse;
+fade = jQuery.web2py.fade;
+
+/* internals - shouldn't be needed
+
+web2py_ajax_init = jQuery.web2py.ajax_init;
+web2py_event_handlers = jQuery.web2py.event_handlers;
+
+web2py_trap_link = jQuery.web2py.trap_link;
+web2py_calc_entropy = jQuery.web2py.calc_entropy;
+*/
+/* compatibility code - end*/

0 comments on commit 3071bd3

Please sign in to comment.
Something went wrong with that request. Please try again.