diff --git a/applications/welcome/languages/ca.py b/applications/welcome/languages/ca.py
new file mode 100644
index 00000000..e0f3109e
--- /dev/null
+++ b/applications/welcome/languages/ca.py
@@ -0,0 +1,492 @@
+# -*- coding: utf-8 -*-
+{
+'!langcode!': 'ca',
+'!langname!': 'Català',
+'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"actualizi" és una expressió opcional com "camp1=\'nou_valor\'". No es poden actualitzar o eliminar resultats de un JOIN',
+'%(nrows)s records found': '%(nrows)s registres trobats',
+'%s %%{position}': '%s %%{posició}',
+'%s %%{row} deleted': '%s %%{fila} %%{eliminada}',
+'%s %%{row} updated': '%s %%{fila} %%{actualitzada}',
+'%s selected': '%s %%{seleccionat}',
+'%Y-%m-%d': '%d/%m/%Y',
+'%Y-%m-%d %H:%M:%S': '%d/%m/%Y %H:%M:%S',
+'(something like "it-it")': '(similar a "això-això")',
+'@markmin\x01An error occured, please [[reload %s]] the page': 'Hi ha hagut un error, si us plau [[recarregui %s]] la pàgina',
+'@markmin\x01Number of entries: **%s**': "Nombre d'entrades: **%s**",
+'A new version of web2py is available': 'Hi ha una nova versió de wep2py disponible',
+'A new version of web2py is available: %s': 'Hi ha una nova versió de wep2py disponible: %s',
+'About': 'Sobre',
+'about': 'sobre',
+'About application': "Sobre l'aplicació",
+'Access Control': "Control d'Accés",
+'Add': 'Afegir',
+'Add Record': 'Afegeix registre',
+'additional code for your application': '`codi addicional per a la seva aplicació',
+'admin disabled because no admin password': 'admin inhabilitat per falta de contrasenya',
+'admin disabled because not supported on google app engine': 'admin inhabilitat, no és suportat en GAE',
+'admin disabled because unable to access password file': 'admin inhabilitat, impossible accedir al fitxer con la contrasenya',
+'Admin is disabled because insecure channel': 'Admin inhabilitat, el canal no és segur',
+'Admin is disabled because unsecure channel': 'Admin inhabilitat, el canal no és segur',
+'Administrative interface': 'Interfície administrativa',
+'Administrative Interface': 'Interfície Administrativa',
+'administrative interface': 'interfície administrativa',
+'Administrator Password:': 'Contrasenya del Administrador:',
+'Ajax Recipes': 'Receptes AJAX',
+'An error occured, please %s the page': 'Hi ha hagut un error, per favor %s la pàgina',
+'And': 'I',
+'and rename it (required):': 'i renombri-la (requerit):',
+'and rename it:': " i renombri'l:",
+'appadmin': 'appadmin',
+'appadmin is disabled because insecure channel': 'admin inhabilitat, el canal no és segur',
+'application "%s" uninstalled': 'aplicació "%s" desinstal·lada',
+'application compiled': 'aplicació compilada',
+'application is compiled and cannot be designed': 'la aplicació està compilada i no pot ser modificada',
+'Apply changes': 'Aplicar canvis',
+'Appointment': 'Nomenament',
+'Are you sure you want to delete file "%s"?': 'Està segur que vol eliminar el arxiu "%s"?',
+'Are you sure you want to delete this object?': 'Està segur que vol esborrar aquest objecte?',
+'Are you sure you want to uninstall application "%s"': '¿Està segur que vol desinstalar la aplicació "%s"',
+'Are you sure you want to uninstall application "%s"?': '¿Està segur que vol desinstalar la aplicació "%s"?',
+'at': 'a',
+'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ATENCIÓ: Inici de sessió requereix una connexió segura (HTTPS) o localhost.',
+'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATENCION: NO EJECUTE VARIAS PRUEBAS SIMULTANEAMENTE, NO SON THREAD SAFE.',
+'ATTENTION: you cannot edit the running application!': 'ATENCIO: no pot modificar la aplicació que està ejecutant-se!',
+'Authentication': 'Autenticació',
+'Authentication failed at client DB!': '¡La autenticació ha fallat en la BDD client!',
+'Authentication failed at main DB!': '¡La autenticació ha fallat en la BDD principal!',
+'Available Databases and Tables': 'Bases de dades i taules disponibles',
+'Back': 'Endarrera',
+'Buy this book': 'Compra aquest lllibre',
+'Cache': 'Caché',
+'cache': 'caché',
+'Cache Cleared': 'Caché Netejada',
+'Cache Keys': 'Claus de la Caché',
+'cache, errors and sessions cleaned': 'caché, errors i sessions eliminats',
+'Cannot be empty': 'No pot estar buit',
+'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': 'No se pot compilar: hi ha errors en la seva aplicació. Depuri, corregeixi errors i torni a intentar-ho.',
+'cannot upload file "%(filename)s"': 'no és possible pujar fitxer "%(filename)s"',
+'Change Password': 'Canviï la Contrasenya',
+'Change password': 'Canviï la contrasenya',
+'change password': 'canviï la contrasenya',
+'Changelog': 'Changelog',
+'check all': 'marcar tots',
+'Check to delete': 'Marqui per a eliminar',
+'choose one': 'escolliu un',
+'clean': 'neteja',
+'Clear': 'Netejar',
+'Clear CACHE?': 'Netejar Memòrica Cau?',
+'Clear DISK': 'Netejar DISC',
+'Clear RAM': 'Netejar RAM',
+'Click on the link %(link)s to reset your password': "Cliqui en l'enllaç %(link)s per a reiniciar la seva contrasenya",
+'click to check for upgrades': 'feu clic per buscar actualitzacions',
+'client': 'cliente',
+'Client IP': 'IP del Client',
+'Close': 'Tancar',
+'Comma-separated export including columns not shown; fields from other tables are exported as raw values for faster export': 'Comma-separated export including columns not shown; fields from other tables are exported as raw values for faster export',
+'Comma-separated export of visible columns. Fields from other tables are exported as they appear on-screen but this may be slow for many rows': 'Comma-separated export of visible columns. Fields from other tables are exported as they appear on-screen but this may be slow for many rows',
+'Community': 'Comunitat',
+'compile': 'compilar',
+'compiled application removed': 'aplicació compilada eliminada',
+'Components and Plugins': 'Components i Plugins',
+'contains': 'conté',
+'Controller': 'Controlador',
+'Controllers': 'Controladors',
+'controllers': 'controladors',
+'Copyright': 'Copyright',
+'Correo electrónico invàlid': 'Correu electrònic invàlid',
+'create file with filename:': 'crear el fitxer amb el nom:',
+'Create new application': 'Crear una nova aplicació',
+'create new application:': 'crear una nova aplicació:',
+'Create New Page': 'Crear Pàgina Nova',
+'Create Page from Slug': 'Create Page from Slug',
+'Created By': 'Creat Per',
+'Created On': 'Creat a',
+'CSV': 'CSV',
+'CSV (hidden cols)': 'CSV (columnas ocultes)',
+'Current request': 'Sol·licitud en curs',
+'Current response': 'Resposta en curs',
+'Current session': 'Sessió en curs',
+'currently saved or': 'actualment guardat o',
+'customize me!': "¡Adapta'm!",
+'data uploaded': 'dades pujades',
+'Database': 'Base de dades',
+'Database %s select': 'selecció a base de dades %s',
+'database administration': 'administració de base de dades',
+'Database Administration (appadmin)': 'Administració de Base de Dades (appadmin)',
+'Date and Time': 'Data i Hora',
+'DB': 'BDD',
+'db': 'bdd',
+'DB Model': 'Model BDD',
+'defines tables': 'defineix taules',
+'Delete': 'Eliminar',
+'delete': 'eliminar',
+'delete all checked': 'eliminar marcats',
+'Delete:': 'Eliminar:',
+'Demo': 'Demostració',
+'Deploy on Google App Engine': 'Desplegament a Google App Engine',
+'Deployment Recipes': 'Receptes de desplegament',
+'Description': 'Descripció',
+'design': 'diseny',
+'DESIGN': 'DISENY',
+'Design for': 'Diseny per a',
+'detecting': 'detectant',
+'DISK': 'DISC',
+'Disk Cache Keys': 'Claus de Caché en Disc',
+'Disk Cleared': 'Disc netejat',
+'Documentation': 'Documentació',
+"Don't know what to do?": 'No sap què fer?',
+'done!': '¡fet!',
+'Download': 'Descàrregues',
+'E-mail': 'Correu electrònic',
+'edit': 'editar',
+'EDIT': 'EDITAR',
+'Edit': 'Editar',
+'Edit application': 'Editar aplicació',
+'edit controller': 'editar controlador',
+'Edit current record': 'Editar el registre actual',
+'Edit Menu': 'Editar Menu',
+'Edit Page': 'Editar Pàgina',
+'Edit Page Media': 'Edit Page Media',
+'Edit Profile': 'Editar Perfil',
+'edit profile': 'editar perfil',
+'Edit This App': 'Editi aquesta App',
+'Editing file': 'Editant fitxer',
+'Editing file "%s"': 'Editant fitxer "%s"',
+'El fitxer ha de ser PDF': 'El fitxer ha de ser PDF',
+'El fitxer ha de ser PDF o XML': 'El fitxer ha de ser PDF o XML',
+'Email': 'Email',
+'Email and SMS': 'Correu electrònic i SMS',
+'Email sent': 'Correu electrònic enviat',
+'End of impersonation': 'Fi de suplantació',
+'enter a number between %(min)g and %(max)g': 'introdueixi un número entre %(min)g i %(max)g',
+'Enter a valid email address': 'Entri una adreça email vàlida',
+'enter a value': 'entri un valor',
+'Enter a value': 'Entri un valor',
+'Enter an integer between %(min)g and %(max)g': 'Entri un numero enter entre %(min)g i %(max)g',
+'enter an integer between %(min)g and %(max)g': 'entri numero enter entre %(min)g i %(max)g',
+'enter date and time as %(format)s': 'entri data i hora com %(format)s',
+'Enter from %(min)g to %(max)g characters': 'Entri des de %(min)g a %(max)g caràcters',
+'Enter valid filename': 'Entri nom de fitxer vàlid',
+'Error logs for "%(app)s"': 'Bitàcora de errors a "%(app)s"',
+'errors': 'errors',
+'Errors': 'Errors',
+'Errors in form, please check it out.': 'Hi ha errors en el formulari, per favor comprovi-ho.',
+'export as csv file': 'exportar com fitxer CSV',
+'Export:': 'Exportar:',
+'exposes': 'exposa',
+'extends': 'extén',
+'failed to reload module': 'la recàrrega del mòdul ha fallat',
+'FAQ': 'FAQ',
+'file': 'fitxer',
+'file "%(filename)s" created': 'fitxer "%(filename)s" creat',
+'file "%(filename)s" deleted': 'fitxer "%(filename)s" eliminat',
+'file "%(filename)s" uploaded': 'fitxer "%(filename)s" pujat',
+'file "%(filename)s" was not deleted': 'fitxer "%(filename)s" no fou eliminat',
+'file "%s" of %s restored': 'fitxer "%s" de %s restaurat',
+'file ## download': 'file ',
+'file changed on disk': 'fitxer modificat en el disco',
+'file does not exist': 'fitxer no existeix',
+'file saved on %(time)s': 'fitxer guardat a %(time)s',
+'file saved on %s': 'fitxer guardat a %s',
+'First name': 'Nom',
+'Forgot username?': 'Ha oblidat el nom de usuari?',
+'Forms and Validators': 'Formularis i validadors',
+'Free Applications': 'Aplicacions Lliures',
+'Functions with no doctests will result in [passed] tests.': 'Funcions sense doctests equivalen a pruebas [aceptades].',
+'Group %(group_id)s created': 'Grupo %(group_id)s creat',
+'Group ID': 'ID de Grup',
+'Group uniquely assigned to user %(id)s': 'Grup assignat únicament al usuari %(id)s',
+'Groups': 'Grups',
+'Hello': 'Hola',
+'Hello World': 'Hola Món',
+'help': 'ajuda',
+'Home': 'Inici',
+'Hosted by': 'Hosted by',
+'How did you get here?': 'Com has arribat aquí?',
+'HTML': 'HTML',
+'HTML export of visible columns': 'HTML export de columnes visibles',
+'htmledit': 'htmledit',
+'Impersonate': 'Suplantar',
+'import': 'importar',
+'Import/Export': 'Importar/Exportar',
+'in': 'a',
+'includes': 'inclou',
+'Index': 'Índex',
+'insert new': 'inserti nou',
+'insert new %s': 'inserti nou %s',
+'Installed applications': 'Aplicacions instalades',
+'Insufficient privileges': 'Privilegis insuficients',
+'internal error': 'error intern',
+'Internal State': 'Estat Intern',
+'Introduction': 'Introducció',
+'Invalid action': 'Acció invàlida',
+'Invalid email': 'Correo electrónico invàlid',
+'invalid expression': 'expressió invàlida',
+'Invalid login': 'Inici de sessió invàlida',
+'invalid password': 'contrasenya invàlida',
+'Invalid Query': 'Consulta invàlida',
+'invalid request': 'sol·licitud invàlida',
+'Invalid reset password': 'Reinici de contrasenya invàlid',
+'invalid ticket': 'tiquet invàlid',
+'Is Active': 'Està Actiu',
+'Key': 'Clau',
+'language file "%(filename)s" created/updated': 'fitxer de llenguatge "%(filename)s" creat/actualitzat',
+'Language files (static strings) updated': 'Fitxers de llenguatge (cadenes estàtiques) actualitzats',
+'languages': 'llenguatges',
+'Languages': 'Llenguatges',
+'languages updated': 'llenguatges actualitzats',
+'Last name': 'Cognom',
+'Last saved on:': 'Guardat a:',
+'Layout': 'Diseny de pàgina',
+'Layout Plugins': 'Plugins de disseny',
+'Layouts': 'Dissenys de pàgines',
+'License for': 'Llicència per a',
+'Live Chat': 'Xat en viu',
+'loading...': 'carregant...',
+'Log In': 'Log In',
+'Log Out': 'Log Out',
+'Logged in': 'Sessió iniciada',
+'Logged out': 'Sessió finalitzada',
+'Login': 'Inici de sessió',
+'login': 'inici de sessió',
+'Login disabled by administrator': 'Inici de sessió inhabilitat pel administrador',
+'Login to the Administrative Interface': 'Inici de sessió per a la Interfície Administrativa',
+'logout': 'fi de sessió',
+'Logout': 'Fi de sessió',
+'Lost Password': 'Contrasenya perdida',
+'Lost password?': 'Ha oblidat la contrasenya?',
+'lost password?': '¿ha oblidat la contrasenya?',
+'Main Menu': 'Menú principal',
+'Manage %(action)s': 'Manage %(action)s',
+'Manage Access Control': 'Manage Access Control',
+'Manage Cache': 'Gestionar la Caché',
+'Menu Model': 'Model "menu"',
+'merge': 'combinar',
+'Models': 'Models',
+'models': 'models',
+'Modified By': 'Modificat Per',
+'Modified On': 'Modificat A',
+'Modules': 'Mòduls',
+'modules': 'mòduls',
+'must be YYYY-MM-DD HH:MM:SS!': '¡debe ser DD/MM/YYYY HH:MM:SS!',
+'must be YYYY-MM-DD!': '¡debe ser DD/MM/YYYY!',
+'My Sites': 'Els Meus Llocs',
+'Name': 'Nombre',
+'New': 'Nuevo',
+'New %(entity)s': 'Nou %(entity)s',
+'new application "%s" created': 'nova aplicació "%s" creada',
+'New password': 'Contrasenya nova',
+'New Record': 'Registre nou',
+'new record inserted': 'nou registre insertat',
+'New Search': 'Cerca nova',
+'next %s rows': 'següents %s files',
+'next 100 rows': '100 files següents',
+'NO': 'NO',
+'No databases in this application': 'No hi ha bases de dades en esta aplicació',
+'No records found': "No s'han trobat registres",
+'Not authorized': 'No autoritzat',
+'not in': 'no a',
+'Object or table name': 'Nom del objecte o taula',
+'Old password': 'Contrasenya anterior',
+'Online examples': 'Ejemples en línia',
+'Or': 'O',
+'or import from csv file': 'o importar desde fitxer CSV',
+'or provide application url:': 'o proveeix URL de la aplicació:',
+'Origin': 'Origen',
+'Original/Translation': 'Original/Traducció',
+'Other Plugins': 'Altres Plugins',
+'Other Recipes': 'Altres Receptes',
+'Overview': 'Resum',
+'pack all': 'empaquetar tot',
+'pack compiled': 'empaquetar compilats',
+'Password': 'Contrasenya',
+'Password changed': 'Contrasenya cambiada',
+"Password fields don't match": 'Els camps de contrasenya no coincideixen',
+'Password reset': 'Reinici de contrasenya',
+'Peeking at file': 'Visualitzant fitxer',
+'Permission': 'Permís',
+'Permissions': 'Permisos',
+'Phone': 'Telèfon',
+'please input your password again': 'si us plau, entri un altre cop la seva contrasenya',
+'Plugins': 'Plugins',
+'Powered by': 'Aquest lloc utilitza',
+'Preface': 'Prefaci',
+'Presentar Factures': 'Presentar Factures',
+'Presentar factures': 'Presentar factures',
+'previous %s rows': '%s files prèvies',
+'previous 100 rows': '100 files anteriors',
+'Profile': 'Perfil',
+'Profile updated': 'Perfil actualitzat',
+'pygraphviz library not found': 'pygraphviz library not found',
+'Python': 'Python',
+'Query Not Supported: %s': 'Consulta No Suportada: %s',
+'Query:': 'Consulta:',
+'Quick Examples': 'Exemple Ràpids',
+'RAM': 'RAM',
+'RAM Cache Keys': 'Claus de la Caché en RAM',
+'Ram Cleared': 'Ram Netjeda',
+'Recipes': 'Receptes',
+'Record': 'Registre',
+'Record %(id)s created': 'Registre %(id)s creat',
+'Record Created': 'Registre Creat',
+'record does not exist': 'el registre no existe',
+'Record ID': 'ID de Registre',
+'Record id': 'Id de registre',
+'Ref APB': 'Ref APB',
+'register': "registri's",
+'Register': "Registri's",
+'Registration identifier': 'Identificador de Registre',
+'Registration key': 'Clau de registre',
+'Registration successful': 'Registre amb èxit',
+'reload': 'recarregar',
+'Remember me (for 30 days)': "Recordi'm (durant 30 dies)",
+'remove compiled': 'eliminar compilades',
+'Request reset password': 'Sol·licitud de restabliment de contrasenya',
+'Reset password': 'Reiniciar contrasenya',
+'Reset Password key': 'Restaurar Clau de la Contrasenya',
+'Resolve Conflict file': 'Resolgui el Conflicte de fitxer',
+'restore': 'restaurar',
+'Retrieve username': 'Recuperar nom de usuari',
+'revert': 'revertir',
+'Role': 'Rol',
+'Roles': 'Rols',
+'Rows in Table': 'Files a la taula',
+'Rows selected': 'Files seleccionades',
+'save': 'guardar',
+'Save model as...': 'Save model as...',
+'Saved file hash:': 'Hash del fitxer guardat:',
+'Search': 'Buscar',
+'Search Pages': 'Search Pages',
+'Semantic': 'Semàntica',
+'Services': 'Serveis',
+'session expired': 'sessió expirada',
+'shell': 'terminal',
+'Sign Up': 'Sign Up',
+'site': 'lloc',
+'Size of cache:': 'Mida de la Caché:',
+'Slug': 'Slug',
+'some files could not be removed': 'algunos archivos no pudieron ser removidos',
+'Spreadsheet-optimised export of tab-separated content including hidden columns. May be slow': 'Spreadsheet-optimised export of tab-separated content including hidden columns. May be slow',
+'Spreadsheet-optimised export of tab-separated content, visible columns only. May be slow.': 'Spreadsheet-optimised export of tab-separated content, visible columns only. May be slow.',
+'start': 'inici',
+'Start building a new search': 'Start building a new search',
+'starts with': 'comença per',
+'state': 'estat',
+'static': 'estàtics',
+'Static files': 'Fitxers estàtics',
+'Statistics': 'Estadístiques',
+'Stylesheet': "Fulla d'estil",
+'Submit': 'Enviar',
+'submit': 'enviar',
+'Success!': 'Correcte!',
+'Support': 'Suport',
+'Sure you want to delete this object?': '¿Està segur que vol eliminar aquest objecte?',
+'Table': 'taula',
+'Table name': 'Nom de la taula',
+'test': 'provar',
+'Testing application': 'Provant aplicació',
+'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'La "consulta" és una condición com "db.tabla1.campo1==\'valor\'". Algo com "db.tabla1.campo1==db.tabla2.campo2" resulta en un JOIN SQL.',
+'the application logic, each URL path is mapped in one exposed function in the controller': 'la lògica de la aplicació, cada ruta URL es mapeja en una funció exposada en el controlador',
+'The Core': 'El Nucli',
+'the data representation, define database tables and sets': 'la representació de dades, defineix taules i conjunts de base de dades',
+'The output of the file is a dictionary that was rendered by the view %s': 'El resultat de aquesta funció és un diccionari que és desplegat per la vista %s',
+'the presentations layer, views are also known as templates': 'la capa de presentació, les vistes també són anomenades plantilles',
+'The Views': 'Les Vistes',
+'There are no controllers': 'No hi ha controladors',
+'There are no models': 'No hi ha models',
+'There are no modules': 'No hi ha mòduls',
+'There are no static files': 'No hi ha fitxers estàtics',
+'There are no translators, only default language is supported': 'No hi ha traductors, només el llenguatge per defecte és suportat',
+'There are no views': 'No hi ha vistes',
+'these files are served without processing, your images go here': 'aquests fitxers són servits sense processar, les seves imatges van aquí',
+'This App': 'Aquesta Aplicació',
+'This email already has an account': 'Aquest correu electrònic ja té un compte',
+'This is a copy of the scaffolding application': 'Aquesta és una còpia de la aplicació de bastiment',
+'This is the %(filename)s template': 'Aquesta és la plantilla %(filename)s',
+'Ticket': 'Tiquet',
+'Time in Cache (h:m:s)': 'Temps en Caché (h:m:s)',
+'Timestamp': 'Marca de temps',
+'Title': 'Títol',
+'to previous version.': 'a la versió prèvia.',
+'To emulate a breakpoint programatically, write:': 'Emular un punto de ruptura programàticament, escribir:',
+'to use the debugger!': 'usar el depurador!',
+'toggle breakpoint': 'alternar punt de ruptura',
+'Toggle comment': 'Alternar comentari',
+'Toggle Fullscreen': 'Alternar pantalla completa',
+'too short': 'massa curt',
+'Traceback': 'Traceback',
+'translation strings for the application': 'cadenes de caracters de traducció per a la aplicació',
+'try': 'intenti',
+'try something like': 'intenti algo com',
+'TSV (Excel compatible)': 'TSV (compatible Excel)',
+'TSV (Excel compatible, hidden cols)': 'TSV (compatible Excel, columnes ocultes)',
+'TSV (Spreadsheets)': 'TSV (Fulls de càlcul)',
+'TSV (Spreadsheets, hidden cols)': 'TSV (Fulls de càlcul, columnes amagades)',
+'Twitter': 'Twitter',
+'Unable to check for upgrades': 'No és possible verificar la existencia de actualitzacions',
+'unable to create application "%s"': 'no és possible crear la aplicació "%s"',
+'unable to delete file "%(filename)s"': 'no és possible eliminar el fitxer "%(filename)s"',
+'Unable to download': 'No és possible la descàrrega',
+'Unable to download app': 'No és possible descarregar la aplicació',
+'unable to parse csv file': 'no és possible analitzar el fitxer CSV',
+'unable to uninstall "%s"': 'no és possible instalar "%s"',
+'uncheck all': 'desmarcar tots',
+'uninstall': 'desinstalar',
+'unknown': 'desconocido',
+'update': 'actualitzar',
+'update all languages': 'actualitzar tots els llenguatges',
+'Update:': 'Actualizi:',
+'upload application:': 'pujar aplicació:',
+'Upload existing application': 'Puji aquesta aplicació',
+'upload file:': 'puji fitxer:',
+'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) para AND, (...)|(...) para OR, i ~(...) para NOT, para crear consultas més complexes.',
+'User': 'Usuari',
+'User %(id)s is impersonating %(other_id)s': 'El usuari %(id)s està suplantant %(other_id)s',
+'User %(id)s Logged-in': 'El usuari %(id)s inicià la sessió',
+'User %(id)s Logged-out': 'El usuari %(id)s finalitzà la sessió',
+'User %(id)s Password changed': 'Contrasenya del usuari %(id)s canviada',
+'User %(id)s Password reset': 'Contrasenya del usuari %(id)s reiniciada',
+'User %(id)s Profile updated': 'Actualitzat el perfil del usuari %(id)s',
+'User %(id)s Registered': 'Usuari %(id)s Registrat',
+'User %(id)s Username retrieved': 'Se ha recuperat el nom de usuari del usuari %(id)s',
+'User %(username)s Logged-in': 'El usuari %(username)s inicià la sessió',
+"User '%(username)s' Logged-in": "El usuari '%(username)s' inicià la sessió",
+"User '%(username)s' Logged-out": "El usuari '%(username)s' finalitzà la sessió",
+'User Id': 'Id de Usuari',
+'User ID': 'ID de Usuari',
+'User Logged-out': 'El usuari finalitzà la sessió',
+'Username': 'Nom de usuari',
+'Username retrieve': 'Recuperar nom de usuari',
+'Users': 'Usuaris',
+'Value already in database or empty': 'El valor ya existeix en la base de dades o està buit',
+'value already in database or empty': 'el valor ya existeix en la base de dades o està buit',
+'value not allowed': 'valor no permès',
+'Value not in database': 'El valor no està a la base de dades',
+'value not in database': 'el valor no està a la base de dades',
+'Verify Password': 'Verificar Contrasenya',
+'Version': 'Versió',
+'versioning': 'versions',
+'Videos': 'Videos',
+'View': 'Vista',
+'view': 'vista',
+'View %(entity)s': 'Veure %(entity)s',
+'View Page': 'View Page',
+'Views': 'Vistes',
+'views': 'vistes',
+'web2py is up to date': 'web2py està actualitzat',
+'web2py Recent Tweets': 'Tweets Recents de web2py',
+'Welcome': 'Benvingut',
+'Welcome %s': 'Benvingut %s',
+'Welcome to web2py': 'Benvingut a web2py',
+'Welcome to web2py!': '¡Benvingut a web2py!',
+'Which called the function %s located in the file %s': 'La qual va cridar la funció %s localitzada en el fitxer %s',
+'Wiki Page': 'Wiki Page',
+'Working...': 'Treballant ...',
+'XML': 'XML',
+'XML export of columns shown': 'XML export of columns shown',
+'YES': 'SÍ',
+'You are successfully running web2py': 'Vostè està executant web2py amb èxit',
+'You can modify this application and adapt it to your needs': 'Vostè pot modificar aquesta aplicació i adaptar-la a les seves necessitats',
+'You visited the url %s': 'Vostè va visitar la url %s',
+'Your username is: %(username)s': 'El seu nom de usuari és: %(username)s',
+}
diff --git a/applications/welcome/languages/cs.py b/applications/welcome/languages/cs.py
index 9c8c7b63..f5dd2f6c 100644
--- a/applications/welcome/languages/cs.py
+++ b/applications/welcome/languages/cs.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+# coding: utf8
{
'!langcode!': 'cs-cz',
'!langname!': 'čeština',
diff --git a/applications/welcome/languages/default.py b/applications/welcome/languages/default.py
index 6524a902..5e6e8125 100644
--- a/applications/welcome/languages/default.py
+++ b/applications/welcome/languages/default.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+# coding: utf8
{
'!langcode!': 'en-us',
'!langname!': 'English (US)',
diff --git a/applications/welcome/languages/fr-ca.py b/applications/welcome/languages/fr-ca.py
index 55dfb9ed..7693d5b4 100644
--- a/applications/welcome/languages/fr-ca.py
+++ b/applications/welcome/languages/fr-ca.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+# coding: utf8
{
'!langcode!': 'fr-ca',
'!langname!': 'Français (Canadien)',
diff --git a/applications/welcome/languages/fr.py b/applications/welcome/languages/fr.py
index 048ac1b1..c3922ad3 100644
--- a/applications/welcome/languages/fr.py
+++ b/applications/welcome/languages/fr.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+# coding: utf8
{
'!langcode!': 'fr',
'!langname!': 'Français',
diff --git a/applications/welcome/languages/hi.py b/applications/welcome/languages/hi.py
index 63a7acdc..46a47e86 100644
--- a/applications/welcome/languages/hi.py
+++ b/applications/welcome/languages/hi.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+# coding: utf8
{
'!langcode!': 'hi-in',
'!langname!': 'हिन्दी',
diff --git a/applications/welcome/languages/hu.py b/applications/welcome/languages/hu.py
index 615ee394..bc32c8dd 100644
--- a/applications/welcome/languages/hu.py
+++ b/applications/welcome/languages/hu.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+# coding: utf8
{
'!langcode!': 'hu',
'!langname!': 'Magyar',
diff --git a/applications/welcome/languages/id.py b/applications/welcome/languages/id.py
index 2273ae5a..0bb837dc 100755
--- a/applications/welcome/languages/id.py
+++ b/applications/welcome/languages/id.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+# coding: utf8
{
'!langcode!': 'id',
'!langname!': 'Indonesian',
diff --git a/applications/welcome/languages/it.py b/applications/welcome/languages/it.py
index b44bf2e8..77a706be 100644
--- a/applications/welcome/languages/it.py
+++ b/applications/welcome/languages/it.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+# coding: utf8
{
'!=': '!=',
'!langcode!': 'it',
diff --git a/applications/welcome/languages/my-mm.py b/applications/welcome/languages/my-mm.py
new file mode 100644
index 00000000..36a03029
--- /dev/null
+++ b/applications/welcome/languages/my-mm.py
@@ -0,0 +1,278 @@
+# -*- coding: utf-8 -*-
+{
+'!langcode!': 'my-mm',
+'!langname!': 'မြန်မာ',
+'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN',
+'%s %%{row} deleted': '%s %%{row} ဖျက်ပြီးပြီ',
+'%s %%{row} updated': '%s %%{row} ပြင်ပြီးပြီ',
+'%s selected': '%s ခု ရွေးထားသည်',
+'%Y-%m-%d': '%Y-%m-%d',
+'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S',
+'(requires internet access, experimental)': '(requires internet access, experimental)',
+'(something like "it-it")': '(something like "it-it")',
+'@markmin\x01An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page',
+'About': 'အကြောင်း',
+'Access Control': 'အသုံးပြု ခြင်းဆိုင်ရာ ထိန်းချုပ်ရန်',
+'Additional code for your application': 'Additional code for your application',
+'Admin language': 'Admin language',
+'administrative interface': 'administrative interface',
+'Administrative Interface': 'စီမံခန့်ခွဲရာ အင်တာဖေ့စ်',
+'Administrator Password:': 'Administrator Password:',
+'Ajax Recipes': 'Ajax Recipes',
+'and rename it:': 'and rename it:',
+'appadmin is disabled because insecure channel': 'စိတ်မချရသော လမ်းကြောင်းမှ ဝင်ရောက်သဖြင့် appadmin ကို အသုံးပြု၍ မရပါ',
+'Application name:': 'Application name:',
+'are not used': 'အသုံးမပြုပါ',
+'are not used yet': 'အသုံးမပြုသေးပါ',
+'Are you sure you want to delete this object?': 'သင် ဒီအရာ ဖျက်ရန် သေချာပါသလား။',
+'Available Databases and Tables': 'အသုံးပြုနိုင်သော ဒေတာဘေစ့်များနှင့် ဇယားများ',
+'Buy this book': 'ဒီစာအုပ်ကို ဝယ်ပါ',
+'cache': 'cache',
+'Cache': 'Cache',
+'Cache Keys': 'Cache Keys',
+'can be a git repo': 'can be a git repo',
+'Cannot be empty': 'အလွတ် မဖြစ်ရပါ',
+'Change admin password': 'Change admin password',
+'Check to delete': 'ဖျက်ရန် စစ်ဆေးပါ',
+'Checking for upgrades...': 'အဆင့်မြှင့်တင်မှုများအတွက် စစ်ဆေးနေသည် ...',
+'Clean': 'ရှင်းလင်းရန်',
+'Clear CACHE?': 'CACHE ကို ရှင်းလင်းမည်မှာ ဟုတ်ပါသလား။',
+'Clear DISK': 'DISK ကို ရှင်းလင်းမည်။',
+'Clear RAM': 'RAM ကို ရှင်းလင်းမည်။',
+'Client IP': 'Client IP',
+'collapse/expand all': 'collapse/expand all',
+'Community': 'အသိုင်းအဝိုင်း',
+'Compile': 'Compile',
+'Components and Plugins': 'Components and Plugins',
+'Controller': 'ကွန်ထရိုလာ',
+'Controllers': 'ကွန်ထရိုလာများ',
+'controllers': 'controllers',
+'Copyright': 'မူပိုင်ခွင့်',
+'Create': 'ဖန်တီးရန်',
+'create file with filename:': 'create file with filename:',
+'Create/Upload': 'Create/Upload',
+'created by': 'ဖန်းတီးသူ',
+'Created By': 'ပြုလုပ်ဖန်တီးသူ',
+'Created On': 'ပြုလုပ်ဖန်တီးသည့်အချိန်',
+'crontab': 'crontab',
+'Current request': 'Current request',
+'Current response': 'Current response',
+'Current session': 'Current session',
+'currently running': 'လက်ရှိတွင် လုပ်ဆောင်နေသည်',
+'data uploaded': 'data uploaded',
+'Database': 'ဒေတာဘေစ့်',
+'Database %s select': 'Database %s select',
+'database administration': 'ဒေတာဘေ့(စ်) စီမံခန့်ခွဲခြင်း',
+'Database Administration (appadmin)': 'ဒေတာဘေစ့် စီမံခန့်ခွဲခြင်း (appadmin)',
+'db': 'db',
+'DB Model': 'DB Model',
+'Debug': 'အမှားရှာရန်',
+'Delete this file (you will be asked to confirm deletion)': 'Delete this file (you will be asked to confirm deletion)',
+'Delete:': 'Delete:',
+'Demo': 'အစမ်း၊ သရုပ်ပြမှုများ',
+'Deploy': 'Deploy',
+'Deploy on Google App Engine': 'Deploy on Google App Engine',
+'Deploy to OpenShift': 'Deploy to OpenShift',
+'Deployment Recipes': 'Deployment Recipes',
+'Description': 'ဖော်ပြချက်',
+'design': 'design',
+'direction: ltr': 'direction: ltr',
+'Disable': 'ပိတ်ရန်',
+'DISK': 'DISK',
+'Disk Cache Keys': 'Disk Cache Keys',
+'Disk Cleared': 'Disk ရှင်းလင်းပြီးပြီ',
+'Documentation': 'စာရွက်စာတမ်း အထောက်အကူများ',
+"Don't know what to do?": 'ဘာလုပ်ရမည်မသိ ဖြစ်နေပါသလား။',
+'done!': 'လုပ်ငန်း ဆောင်ရွက်ပြီးပြီ!',
+'Download': 'Download',
+'Download layouts from repository': 'Download layouts from repository',
+'Download plugins from repository': 'Download plugins from repository',
+'E-mail': 'အီးမေးလ်',
+'Edit': 'ပြင်ဆင်ရန်',
+'Edit application': 'Application ကို ပြင်ရန်',
+'Edit current record': 'လက်ရှိ မှတ်တမ်းကို ပြင်ရန်',
+'Email and SMS': 'အီးမေးလ်နှင့် SMS',
+'Enable': 'ဖွင့်ရန်',
+'enter an integer between %(min)g and %(max)g': 'enter an integer between %(min)g and %(max)g',
+'Errors': 'အမှားများ',
+'export as csv file': ' csv file အနေနဲ့ ထုတ်ပေးရန်',
+'exposes': 'exposes',
+'extends': 'extends',
+'FAQ': 'ဖြစ်လေ့ရှိသော ပြဿနာများ',
+'filter': 'filter',
+'First name': 'အမည်၏ ပထမဆုံး စာလုံး',
+'Forms and Validators': 'Forms and Validators',
+'Free Applications': 'အခမဲ့ Applications',
+'graph model': 'graph model',
+'Graph Model': 'Graph Model',
+'Group ID': 'Group ID',
+'Groups': 'အဖွဲ့များ',
+'Hello World': 'မင်္ဂလာပါ ကမ္ဘာကြီး။',
+'Help': 'အကူအညီ',
+'Home': 'မူလသို့',
+'How did you get here?': 'သင် ဘယ်လို ရောက်လာခဲ့သလဲ။',
+'import': 'သွင်းယူရန်',
+'Import/Export': 'သွင်းယူရန်/ထုတ်ယူရန်',
+'includes': 'includes',
+'Install': 'Install',
+'Installed applications': 'ထည့်သွင်းပြီး application များ',
+'Internal State': 'Internal State',
+'Introduction': 'မိတ်ဆက်',
+'Invalid email': 'အီးမေးလ် ဖြည့်သွင်းမှုမှားနေသည်',
+'Invalid Query': 'Invalid Query',
+'invalid request': 'invalid request',
+'Is Active': 'Is Active',
+'Key': 'Key',
+'Language': 'ဘာသာစကား',
+'languages': 'ဘာသာစကားများ',
+'Languages': 'ဘာသာစကားများ',
+'Last name': 'မျိုးနွယ်အမည်',
+'Layout': 'အပြင်အဆင်',
+'Layout Plugins': 'Layout Plugins',
+'Layouts': 'အပြင်အဆင်များ',
+'Live Chat': 'တိုက်ရိုက် ဆက်သွယ် ပြောကြားရန်',
+'Login': 'ဝင်ရောက်အသုံးပြုရန်',
+'Login to the Administrative Interface': 'Login to the Administrative Interface',
+'Logout': 'ထွက်ရန်',
+'Lost Password': 'စကားဝှက် မသိတော့ပါ',
+'Lost password?': 'စကားဝှက် မသိတော့ဘူးလား။',
+'Manage': 'စီမံခန့်ခွဲရန်',
+'Manage %(action)s': '%(action)s ကို စီမံရန်',
+'Manage Access Control': 'အသုံးပြုခြင်းဆိုင်ရာ ထိန်းချုပ်မှု စီမံခန့်ခွဲရန်',
+'Manage Cache': 'Manage Cache',
+'Memberships': 'အသင်းဝင်များ',
+'Menu Model': 'Menu Model',
+'models': 'models',
+'Models': 'Models',
+'Modified By': 'ပြင်ဆင်မွမ်းမံသူ',
+'Modified On': 'ပြင်ဆင်မွမ်းမံသည့် အချိန်',
+'Modules': 'Modules',
+'modules': 'modules',
+'My Sites': 'ကျွန်ုပ်၏ Site များ',
+'Name': 'အမည်',
+'New application wizard': 'New application wizard',
+'New Record': 'မှတ်တမ်း အသစ်',
+'new record inserted': 'မှတ်တမ်း အသစ် ဖြည့်သွင်းပြီးပြီ',
+'New simple application': 'ရိုးရိုး application အသစ်',
+'next %s rows': 'နောက်အတန်း %s တန်း',
+'No databases in this application': 'ဒီ application တွင် မည်သည့် ဒေတာဘေစ့်မှ မရှိပါ',
+'no package selected': 'no package selected',
+'Object or table name': 'Object or table name',
+'Online examples': 'အွန်လိုင်း နမူနာများ',
+'or alternatively': 'or alternatively',
+'Or Get from URL:': 'Or Get from URL:',
+'or import from csv file': 'or import from csv file',
+'Origin': 'မူလ အစ',
+'Other Plugins': 'အခြား Plugins',
+'Other Recipes': 'အခြား Recipes',
+'Overview': 'အပေါ်ယံရှုမြင်ခြင်း',
+'Overwrite installed app': 'Overwrite installed app',
+'Pack all': 'အားလုံးကို ထုပ်ပိုးရန်',
+'Pack custom': 'ရွေးချယ်ထုပ်ပိုးရန်',
+'Password': 'စကားဝှက်',
+"Password fields don't match": 'စကားဝှက်များ ကိုက်ညီမှု မရှိပါ',
+'Permission': 'ခွင့်ပြုချက်',
+'Permissions': 'ခွင့်ပြုချက်များ',
+'please input your password again': 'ကျေးဇူးပြု၍ စကားဝှက်ကို ထပ်မံ ဖြည့်သွင်းပေးပါ',
+'Plugins': 'Plugins',
+'plugins': 'plugins',
+'Plural-Forms:': 'Plural-Forms:',
+'Powered by': 'အားဖြည့်စွမ်းအားပေးသူ',
+'Preface': 'နိဒါန်း',
+'previous %s rows': 'previous %s rows',
+'Private files': 'Private files',
+'private files': 'private files',
+'pygraphviz library not found': 'pygraphviz library ကို မတွေ့ပါ',
+'Python': 'Python',
+'Query:': 'Query:',
+'Quick Examples': 'အမြန် အသုံးပြုနိုင်သော နမူနာများ',
+'RAM': 'RAM',
+'RAM Cache Keys': 'RAM Cache Keys',
+'Ram Cleared': 'Ram ရှင်းလင်းပြီးပြီ',
+'Recipes': 'Recipes',
+'Record': 'မှတ်တမ်း',
+'record does not exist': 'မှတ်တမ်း မရှိပါ',
+'Record ID': 'Record ID',
+'Record id': 'Record id',
+'Register': 'မှတ်ပုံတင်ရန်',
+'Registration identifier': 'Registration identifier',
+'Registration key': 'Registration key',
+'Reload routes': 'Reload routes',
+'Remember me (for 30 days)': 'Remember me (for 30 days)',
+'Request reset password': 'စကားဝှက် အသစ် တောင်းဆိုရန်',
+'Reset Password key': 'Reset Password key',
+'Role': 'Role',
+'Roles': 'Roles',
+'Rows in Table': 'Rows in Table',
+'Rows selected': 'ရွေးထားသော အတန်းများ',
+"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 model as...': 'Save model as...',
+'Semantic': 'Semantic',
+'Services': 'Services',
+'shell': 'shell',
+'Site': 'Site',
+'Size of cache:': 'Size of cache:',
+'Start wizard': 'Start wizard',
+'state': 'state',
+'static': 'static',
+'Static': 'Static',
+'Statistics': 'ကိန်းဂဏန်း အချက်အလက်များ',
+'Stylesheet': 'Stylesheet',
+'submit': 'ပြုလုပ်ပါ',
+'Submit': 'Submit',
+'Support': 'အထောက်အပံ့',
+'Table': 'ဇယား',
+'test': 'test',
+'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.',
+'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 Core': 'The Core',
+'The data representation, define database tables and sets': 'The data representation, define database tables and sets',
+'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 presentations layer, views are also known as templates': 'The presentations layer, views are also known as templates',
+'The Views': 'The Views',
+'There are no plugins': 'There are no plugins',
+'There are no private files': 'There are no private files',
+'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': 'These files are served without processing, your images go here',
+'This App': 'ဒီ App',
+'This email already has an account': 'ဒီအီးမေးလ်တွင် အကောင့် ရှိပြီး ဖြစ်ပါသည်',
+'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)',
+'Timestamp': 'Timestamp',
+'To create a plugin, name a file/folder plugin_[name]': 'To create a plugin, name a file/folder plugin_[name]',
+'Traceback': 'Traceback',
+'Translation strings for the application': 'Translation strings for the application',
+'Try the mobile interface': 'Try the mobile interface',
+'Twitter': 'Twitter',
+'unable to parse csv file': 'unable to parse csv file',
+'Uninstall': 'Uninstall',
+'update all languages': 'update all languages',
+'Update:': 'Update:',
+'Upload': 'Upload',
+'Upload a package:': 'Upload a package:',
+'Upload and install packed application': 'Upload and install packed application',
+'upload file:': 'upload file:',
+'upload plugin file:': 'upload plugin file:',
+'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.',
+'User': 'အသုံးပြုသူ',
+'User ID': 'User ID',
+'Users': 'အသုံးပြုသူများ',
+'Verify Password': 'စကားဝှက်ကို အတည်ပြုပါ',
+'Version': 'Version',
+'Versioning': 'Versioning',
+'Videos': 'ဗွီဒီယိုများ',
+'View': 'ဗျူး',
+'views': 'views',
+'Views': 'ဗျူးများ',
+'Web Framework': 'Web Framework',
+'Welcome': 'ကြိုဆိုပါ၏',
+'Welcome to web2py!': 'web2py မှ ကြိုဆိုပါသည်။',
+'Which called the function %s located in the file %s': 'Which called the function %s located in the file %s',
+'Working...': 'ဆောင်ရွက်နေပါသည် ။ ။ ။',
+'You are successfully running web2py': 'သင်သည် web2py ကို အောင်မြင်စွာ လည်ပတ်မောင်းနှင်စေပါသည်။',
+'You can modify this application and adapt it to your needs': 'သင် ဒီ application ကို ပြုပြင်မွမ်းမံနိုင်ပါသည်။ ထို့အပြင် သင့်လိုအပ်ချက်များနှင့် ကိုက်ညီစေရန် ပြုလုပ်နိုင်ပါသည်။',
+'You visited the url %s': 'သင် လည်ပတ်ခဲ့သော URL %s',
+'စကားဝှက် အသစ် တောင်းဆိုရန်': 'စကားဝှက် အသစ် တောင်းဆိုရန်',
+'မှတ်ပုံတင်ရန်': 'မှတ်ပုံတင်ရန်',
+'ဝင်ရောက်အသုံးပြုရန်': 'ဝင်ရောက်အသုံးပြုရန်',
+}
diff --git a/applications/welcome/languages/my.py b/applications/welcome/languages/my.py
index 8e634d4d..d5b85f95 100755
--- a/applications/welcome/languages/my.py
+++ b/applications/welcome/languages/my.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+# coding: utf8
{
'!langcode!': 'my',
'!langname!': 'Malay',
diff --git a/applications/welcome/languages/nl.py b/applications/welcome/languages/nl.py
index 4b942d52..39892e52 100644
--- a/applications/welcome/languages/nl.py
+++ b/applications/welcome/languages/nl.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+# coding: utf8
{
'!langcode!': 'nl',
'!langname!': 'Nederlands',
diff --git a/applications/welcome/languages/pl.py b/applications/welcome/languages/pl.py
index fa0f3c96..aa1e5701 100644
--- a/applications/welcome/languages/pl.py
+++ b/applications/welcome/languages/pl.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+# coding: utf8
{
'!langcode!': 'pl',
'!langname!': 'Polska',
diff --git a/applications/welcome/languages/pt.py b/applications/welcome/languages/pt.py
index c34aee8a..8d36be6f 100644
--- a/applications/welcome/languages/pt.py
+++ b/applications/welcome/languages/pt.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+# coding: utf8
{
'!langcode!': 'pt',
'!langname!': 'Português',
diff --git a/applications/welcome/languages/ro.py b/applications/welcome/languages/ro.py
index 63c9741b..0f830e3d 100644
--- a/applications/welcome/languages/ro.py
+++ b/applications/welcome/languages/ro.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+# coding: utf8
{
'!=': '!=',
'!langcode!': 'ro',
diff --git a/applications/welcome/languages/ru.py b/applications/welcome/languages/ru.py
index 0487a715..85644ea2 100644
--- a/applications/welcome/languages/ru.py
+++ b/applications/welcome/languages/ru.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+# coding: utf8
{
'!langcode!': 'ru',
'!langname!': 'Русский',
diff --git a/applications/welcome/languages/sk.py b/applications/welcome/languages/sk.py
index e90ccf81..88f8343f 100644
--- a/applications/welcome/languages/sk.py
+++ b/applications/welcome/languages/sk.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+# coding: utf8
{
'!langcode!': 'sk',
'!langname!': 'Slovenský',
diff --git a/applications/welcome/languages/uk.py b/applications/welcome/languages/uk.py
index 3a5f791f..17bfde51 100644
--- a/applications/welcome/languages/uk.py
+++ b/applications/welcome/languages/uk.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+# coding: utf8
{
'!langcode!': 'uk',
'!langname!': 'Українська',
diff --git a/applications/welcome/languages/zh-cn.py b/applications/welcome/languages/zh-cn.py
index d92a8c53..61009f6e 100644
--- a/applications/welcome/languages/zh-cn.py
+++ b/applications/welcome/languages/zh-cn.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+# coding: utf8
{
'!langcode!': 'zh-cn',
'!langname!': '中文',
diff --git a/applications/welcome/languages/zh-tw.py b/applications/welcome/languages/zh-tw.py
index fa805aa4..5b109604 100644
--- a/applications/welcome/languages/zh-tw.py
+++ b/applications/welcome/languages/zh-tw.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+# coding: utf8
{
'!langcode!': 'zh-cn',
'!langname!': '中文',
diff --git a/applications/welcome/languages/zh.py b/applications/welcome/languages/zh.py
index d4790627..263918ce 100644
--- a/applications/welcome/languages/zh.py
+++ b/applications/welcome/languages/zh.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+# coding: utf8
{
'!langcode!': 'zh-tw',
'!langname!': '中文',
diff --git a/applications/welcome/static/js/web2py.js b/applications/welcome/static/js/web2py.js
index b3cc12c0..cd654b82 100644
--- a/applications/welcome/static/js/web2py.js
+++ b/applications/welcome/static/js/web2py.js
@@ -1,4 +1,4 @@
-(function ($, undefined) {
+(function($, undefined) {
/*
* Unobtrusive scripting adapter for jQuery, largely taken from
* the wonderful https://github.com/rails/jquery-ujs
@@ -12,684 +12,697 @@
}
- String.prototype.reverse = function () {
+ 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 = $("[name=" + s[i] + "]").serialize();
- if(q) {
- pcs.push(q);
- }
- }
- if(pcs.length > 0) {
- query = pcs.join("&");
- }
- }
- $.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').addClass('btn-default');
- $('form input[type="submit"], form input[type="button"]', target).addClass('btn').addClass('btn-default');
- /* 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('+ -').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 () {
- var nvalue = this.value.reverse().replace(/[^0-9\-]|\-(?=.)/g, '').reverse();
- if(this.value!=nvalue) this.value = nvalue;
- });
- doc.on('keyup', 'input.double, input.decimal', function () {
- var nvalue = this.value.reverse().replace(/[^0-9\-\.,]|[\-](?=.)|[\.,](?=[0-9]*[\.,])/g, '').reverse();
- if(this.value!=nvalue) this.value = nvalue;
- });
- 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);
- if (form.hasClass('no_trap')) {
- return;
- }
-
- form.attr('data-w2p_target', target);
- var url = form.attr('action');
-
- if ((url === "") || (url === "#")) {
- /* form has no action. Use component url. */
- url = action;
- }
-
- form.submit(function (e) {
- web2py.disableElement(form.find(web2py.formInputClickSelector));
- web2py.hide_flash();
- web2py.ajax_page('post', url, form.serialize(), target, form);
- 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.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);
+ 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 {
- /* run once (no timeout specified) */
- element.reload_counter = Infinity;
- web2py.ajax_page('get', action, null, target, el);
+ pcs = [];
+ 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("&");
+ }
}
- });
- },
- updatePage: function (xhr, target) {
+ $.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('+ -').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) {
+ $('div.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() {
+ var nvalue = this.value.reverse().replace(/[^0-9\-]|\-(?=.)/g, '').reverse();
+ if(this.value != nvalue) this.value = nvalue;
+ });
+ doc.on('keyup', 'input.double, input.decimal', function() {
+ var nvalue = this.value.reverse().replace(/[^0-9\-\.,]|[\-](?=.)|[\.,](?=[0-9]*[\.,])/g, '').reverse();
+ if(this.value != nvalue) this.value = nvalue;
+ });
+ 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);
+ if(form.hasClass('no_trap')) {
+ return;
+ }
+ form.attr('data-w2p_target', target);
+ var url = form.attr('action');
+ if((url === "") || (url === "#") || (typeof url === 'undefined')) {
+ /* form has no action. Use component url. */
+ url = action;
+ }
+ form.submit(function(e) {
+ web2py.disableElement(form.find(web2py.formInputClickSelector));
+ web2py.hide_flash();
+ web2py.ajax_page('post', url, form.serialize(), target, form);
+ e.preventDefault();
+ });
+ form.on('click', web2py.formInputClickSelector, function(e) {
+ e.preventDefault();
+ var input_name = $(this).attr('name');
+ if(input_name != undefined) {
+ $('').attr('name', input_name)
+ .attr('value', $(this).val()).appendTo(form)
+ }
+ form.trigger('submit');
+ });
+ });
+ },
+ 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.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 */
+ 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;
+ },
+ 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;
}
- /*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);
}
- }
- 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;
+ 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 web2py.js */
+ 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.is('input') ? 'val' : 'html';
+ //method = el.attr('name') ? 'html' : 'val';
+ var disable_with_message = (typeof w2p_ajax_disable_with_message != 'undefined') ? w2p_ajax_disable_with_message : "Working...";
+ /*store enabled state if not already disabled */
+ if(el.data('w2p_enable_with') === undefined) {
+ 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.is('input') ? '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(' × ').slideDown();
+ },
+ hide_flash: function() {
+ $('.flash').fadeOut(0).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');
+ // The field exists only when creating/editing a row
+ if($('#' + name).length) {
+ 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 {
- 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 web2py.js */
- formInputClickSelector: 'input[type=submit]:not([name]), input[type=image]:not([name]), button[type=submit]:not([name]), button:not([type]):not([name])',
- /* 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 if not already disabled */
- if (el.data('w2p:enable-with') === undefined) {
- 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(' × ').slideDown();
- },
- hide_flash: function () {
- $('.flash').fadeOut(0).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);
+ if(method == 'GET') {
+ web2py.ajax_page('get', action, [], target, el);
+ } else if(method == 'POST') {
+ web2py.ajax_page('post', action, [], target, el);
}
- 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
+ },
+ 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 'w2p_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]())
- }
- if (element.data('w2p:enable-with') === undefined) {
- element.data('w2p:enable-with', element[method]());
- }
- element[method](element.data('w2p_disable_with'));
- element.prop('disabled', 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]())
+ }
+ if(element.data('w2p_enable_with') === undefined) {
+ 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`)
+ /* Re-enables disabled form elements:
+ - Replaces element text with cached value from 'w2p_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.removeData('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));
- });
- },
- /* Invalidate and force reload of a web2py component
- */
- invalidate: function(target) {
- $('div[data-w2p_remote]', target).each(function () {
- var el = $('#' + $(this).attr('id')).get(0);
- if (el.timing !== undefined) { // Block triggering regular routines
+ 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.removeData('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));
+ });
+ },
+ /* Invalidate and force reload of a web2py component
+ */
+ invalidate: function(target) {
+ $('div[data-w2p_remote]', target).each(function() {
+ var el = $('#' + $(this).attr('id')).get(0);
+ if(el.timing !== undefined) { // Block triggering regular routines
clearInterval(el.timing);
- }
- });
- $.web2py.component_handler(target);
- },
- }
-
- /*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();
+ }
+ });
+ $.web2py.component_handler(target);
+ },
+ 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();
+ }
+ }
+ /*end of functions */
+ /*main hook*/
+ $(function() {
+ web2py.main_hook();
});
})(jQuery);
@@ -718,4 +731,3 @@ web2py_trap_link = jQuery.web2py.trap_link;
web2py_calc_entropy = jQuery.web2py.calc_entropy;
*/
/* compatibility code - end*/
-
diff --git a/applications/welcome/views/appadmin.html b/applications/welcome/views/appadmin.html
index 054efd49..d8341969 100644
--- a/applications/welcome/views/appadmin.html
+++ b/applications/welcome/views/appadmin.html
@@ -12,35 +12,45 @@
{{if request.function=='index':}}
{{=T("Available Databases and Tables")}}
{{if not databases:}}{{=T("No databases in this application")}}{{pass}}
-
- {{for db in sorted(databases):}}
- {{for table in databases[db].tables:}}
- {{qry='%s.%s.id>0'%(db,table)}}
- {{tbl=databases[db][table]}}
- {{if hasattr(tbl,'_primarykey'):}}
- {{if tbl._primarykey:}}
- {{firstkey=tbl[tbl._primarykey[0]]}}
- {{if firstkey.type in ['string','text']:}}
- {{qry='%s.%s.%s!=""'%(db,table,firstkey.name)}}
- {{else:}}
- {{qry='%s.%s.%s>0'%(db,table,firstkey.name)}}
- {{pass}}
- {{else:}}
- {{qry=''}}
- {{pass}}
- {{pass}}
-
- |
- {{=A("%s.%s" % (db,table),_href=URL('select',args=[db],vars=dict(query=qry)))}}
- |
-
- {{=A(str(T('New Record')),_href=URL('insert',args=[db,table]),_class="btn")}}
- |
-
- {{pass}}
- {{pass}}
-
-
+
+
+
+
+ {{for db in sorted(databases):}}
+ {{for table in databases[db].tables:}}
+ {{qry='%s.%s.id>0'%(db,table)}}
+ {{tbl=databases[db][table]}}
+ {{if hasattr(tbl,'_primarykey'):}}
+ {{if tbl._primarykey:}}
+ {{firstkey=tbl[tbl._primarykey[0]]}}
+ {{if firstkey.type in ['string','text']:}}
+ {{qry='%s.%s.%s!=""'%(db,table,firstkey.name)}}
+ {{else:}}
+ {{qry='%s.%s.%s>0'%(db,table,firstkey.name)}}
+ {{pass}}
+ {{else:}}
+ {{qry=''}}
+ {{pass}}
+ {{pass}}
+
+ |
+ {{=A("%s.%s" % (db,table),_href=URL('select',args=[db],vars=dict(query=qry)))}}
+ |
+
+ {{=A(str(T('New Record')),_href=URL('insert',args=[db,table]),_class="btn")}}
+ |
+
+ {{pass}}
+ {{pass}}
+
+
+
+ {{=LOAD('appadmin', 'hooks', ajax=True)}}
+
+
{{elif request.function=='select':}}
{{=XML(str(T("Database %s select"))%A(request.args[0],_href=URL('index'))) }}
@@ -65,7 +75,7 @@
{{if start>0:}}{{=A(T('previous %s rows') % step,_href=URL('select',args=request.args[0],vars=dict(start=start-step)),_class="btn")}}{{pass}}
{{if stop
+
{{linkto = lambda f, t, r: URL('update', args=[request.args[0], r, f]) if f else "#"}}
{{upload=URL('download',args=request.args[0])}}
{{=SQLTABLE(rows,linkto,upload,orderby=True,_class='sortable')}}