Merge ssh://github.com/web2py/web2py

This commit is contained in:
Michele Comitini
2013-06-30 22:09:16 +02:00
16 changed files with 2200 additions and 950 deletions
+1 -1
View File
@@ -30,7 +30,7 @@ update:
echo "remember that pymysql was tweaked" echo "remember that pymysql was tweaked"
src: src:
### Use semantic versioning ### Use semantic versioning
echo 'Version 2.5.1-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION echo 'Version 2.6.0-development+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION
### rm -f all junk files ### rm -f all junk files
make clean make clean
### clean up baisc apps ### clean up baisc apps
+1 -1
View File
@@ -1 +1 @@
Version 2.5.1-stable+timestamp.2013.06.24.14.23.41 Version 2.6.0-development+timestamp.2013.06.30.10.46.28
+128 -62
View File
@@ -3,54 +3,62 @@
'!langcode!': 'de', '!langcode!': 'de',
'!langname!': 'Deutsch', '!langname!': 'Deutsch',
'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"Update" ist ein optionaler Ausdruck wie "Feld1 = \'newvalue". JOIN Ergebnisse können nicht aktualisiert oder gelöscht werden', '"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"Update" ist ein optionaler Ausdruck wie "Feld1 = \'newvalue". JOIN Ergebnisse können nicht aktualisiert oder gelöscht werden',
'%s %%{row} deleted': '%s Zeilen gelöscht', '%s %%{row} deleted': '%s %%{row} Zeilen gelöscht',
'%s %%{row} updated': '%s Zeilen aktualisiert', '%s %%{row} updated': '%s %%{row} Zeilen aktualisiert',
'%Y-%m-%d': '%Y-%m-%d', '%Y-%m-%d': '%d.%m.%Y',
'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M:%S': '%d.%m.%Y %H:%M:%S',
'(requires internet access)': '(requires internet access)', '(requires internet access)': '(Internet Zugang wir benötigt)',
'(requires internet access, experimental)': '(benötigt Internet Zugang)',
'(something like "it-it")': '(so etwas wie "it-it")', '(something like "it-it")': '(so etwas wie "it-it")',
'@markmin\x01Searching: **%s** %%{file}': 'Searching: **%s** files', '@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(file **gluon/contrib/plural_rules/%s.py** is not found)',
'@markmin\x01Searching: **%s** %%{file}': '@markmin\x01Suche: **%s** Dateien',
'A new version of web2py is available': 'Eine neue Version von web2py ist verfügbar', 'A new version of web2py is available': 'Eine neue Version von web2py ist verfügbar',
'A new version of web2py is available: %s': 'Eine neue Version von web2py ist verfügbar: %s', 'A new version of web2py is available: %s': 'Eine neue Version von web2py ist verfügbar: %s',
'Abort': 'Abbrechen', 'Abort': 'Abbrechen',
'About': 'Über', 'About': 'über',
'About application': 'Über die Anwendung', 'About application': 'über die Anwendung',
'Additional code for your application': 'Additional code for your application', 'Additional code for your application': 'zusätzlicher Code für Ihre Anwendung',
'additional code for your application': 'zusätzlicher Code für Ihre Anwendung', 'admin disabled because no admin password': 'admin ist deaktiviert, weil kein Admin-Passwort gesetzt ist',
'admin disabled because no admin password': ' admin ist deaktiviert, weil kein Admin-Passwort gesetzt ist',
'admin disabled because not supported on google apps engine': 'admin ist deaktiviert, es existiert dafür keine Unterstützung auf der google apps engine', 'admin disabled because not supported on google apps engine': 'admin ist deaktiviert, es existiert dafür keine Unterstützung auf der google apps engine',
'admin disabled because unable to access password file': 'admin ist deaktiviert, weil kein Zugriff auf die Passwortdatei besteht', 'admin disabled because unable to access password file': 'admin ist deaktiviert, weil kein Zugriff auf die Passwortdatei besteht',
'Admin is disabled because insecure channel': 'Appadmin ist deaktiviert, wegen der Benutzung eines unsicheren Kanals', 'Admin is disabled because insecure channel': 'Appadmin ist deaktiviert, wegen der Benutzung eines unsicheren Kanals',
'Admin is disabled because unsecure channel': 'Appadmin ist deaktiviert, wegen der Benutzung eines unsicheren Kanals', 'Admin is disabled because unsecure channel': 'Appadmin ist deaktiviert, wegen der Benutzung eines unsicheren Kanals',
'Admin language': 'Admin language', 'Admin language': 'Admin-Sprache',
'administrative interface': 'administrative interface', 'administrative interface': 'Administrative Schnittstelle',
'Administrator Password:': 'Administrator Passwort:', 'Administrator Password:': 'Administrator Passwort:',
'An error occured, please %s the page': 'Ein Fehler ist aufgetereten, bitte %s die Seite',
'and rename it (required):': 'und benenne sie um (erforderlich):', 'and rename it (required):': 'und benenne sie um (erforderlich):',
'and rename it:': ' und benenne sie um:', 'and rename it:': ' und benenne sie um:',
'appadmin': 'appadmin', 'appadmin': 'appadmin',
'appadmin is disabled because insecure channel': 'Appadmin ist deaktiviert, wegen der Benutzung eines unsicheren Kanals', 'appadmin is disabled because insecure channel': 'Appadmin ist deaktiviert, wegen der Benutzung eines unsicheren Kanals',
'Application': 'Anwendung',
'application "%s" uninstalled': 'Anwendung "%s" deinstalliert', 'application "%s" uninstalled': 'Anwendung "%s" deinstalliert',
'application compiled': 'Anwendung kompiliert', 'application compiled': 'Anwendung kompiliert',
'application is compiled and cannot be designed': 'Die Anwendung ist kompiliert kann deswegen nicht mehr geändert werden', 'application is compiled and cannot be designed': 'Die Anwendung ist kompiliert kann deswegen nicht mehr geändert werden',
'Application name:': 'Application name:', 'Application name:': 'Name der Applikation:',
'are not used': 'wird nicht verwendet',
'are not used yet': 'wird bisher nicht verwendet',
'Are you sure you want to delete file "%s"?': 'Sind Sie sich sicher, dass Sie diese Datei löschen wollen "%s"?', 'Are you sure you want to delete file "%s"?': 'Sind Sie sich sicher, dass Sie diese Datei löschen wollen "%s"?',
'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?', 'Are you sure you want to delete this object?': 'Sind Sie sich sicher, dass Sie dieses Objekt löschen wollen?',
'Are you sure you want to uninstall application "%s"': 'Sind Sie sich sicher, dass Sie diese Anwendung deinstallieren wollen "%s"', 'Are you sure you want to uninstall application "%s"': 'Sind Sie sich sicher, dass Sie diese Anwendung deinstallieren wollen "%s"',
'Are you sure you want to uninstall application "%s"?': 'Sind Sie sich sicher, dass Sie diese Anwendung deinstallieren wollen "%s"?', 'Are you sure you want to uninstall application "%s"?': 'Sind Sie sich sicher, dass Sie diese Anwendung deinstallieren wollen "%s"?',
'Are you sure you want to upgrade web2py now?': 'Sind Sie sich sicher, dass Sie web2py jetzt upgraden möchten?', 'Are you sure you want to upgrade web2py now?': 'Sind Sie sich sicher, dass Sie web2py jetzt upgraden möchten?',
'arguments': 'arguments', 'arguments': 'arguments',
'at char %s': 'at char %s',
'at line %s': 'at line %s',
'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ACHTUNG: Die Einwahl benötigt eine sichere (HTTPS) Verbindung. Es sei denn sie läuft Lokal(localhost).', 'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ACHTUNG: Die Einwahl benötigt eine sichere (HTTPS) Verbindung. Es sei denn sie läuft Lokal(localhost).',
'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ACHTUNG: Testen ist nicht threadsicher. Führen sie also nicht mehrere Tests gleichzeitig aus.', 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ACHTUNG: Testen ist nicht threadsicher. Führen sie also nicht mehrere Tests gleichzeitig aus.',
'ATTENTION: This is an experimental feature and it needs more testing.': 'ACHTUNG: Dies ist eine experimentelle Funktion und benötigt noch weitere Tests.', 'ATTENTION: This is an experimental feature and it needs more testing.': 'ACHTUNG: Dies ist eine experimentelle Funktion und benötigt noch weitere Tests.',
'ATTENTION: you cannot edit the running application!': 'ACHTUNG: Eine laufende Anwendung kann nicht editiert werden!', 'ATTENTION: you cannot edit the running application!': 'ACHTUNG: Eine laufende Anwendung kann nicht editiert werden!',
'Authentication': 'Authentifizierung', 'Authentication': 'Authentifizierung',
'Available databases and tables': 'Verfügbare Datenbanken und Tabellen', 'Available databases and tables': 'verfügbare Datenbanken und Tabellen',
'back': 'zurück', 'back': 'zurück',
'beautify': 'beautify', 'beautify': 'verschönern',
'cache': 'Cache', 'cache': 'Pufferspeicher',
'cache, errors and sessions cleaned': 'Zwischenspeicher (cache), Fehler und Sitzungen (sessions) gelöscht', 'cache, errors and sessions cleaned': 'Zwischenspeicher (cache), Fehler und Sitzungen (sessions) gelöscht',
'call': 'call', 'call': 'Aufruf',
'can be a git repo': 'can be a git repo', 'can be a git repo': 'kann ein git Repository sein',
'Cancel': 'Cancel',
'Cannot be empty': 'Darf nicht leer sein', 'Cannot be empty': 'Darf nicht leer sein',
'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': 'Nicht Kompilierbar:Es sind Fehler in der Anwendung. Beseitigen Sie die Fehler und versuchen Sie es erneut.', 'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': 'Nicht Kompilierbar:Es sind Fehler in der Anwendung. Beseitigen Sie die Fehler und versuchen Sie es erneut.',
'cannot create file': 'Kann Datei nicht erstellen', 'cannot create file': 'Kann Datei nicht erstellen',
@@ -62,29 +70,31 @@
'Check for upgrades': 'check for upgrades', 'Check for upgrades': 'check for upgrades',
'Check to delete': 'Markiere zum löschen', 'Check to delete': 'Markiere zum löschen',
'Checking for upgrades...': 'Auf Updates überprüfen...', 'Checking for upgrades...': 'Auf Updates überprüfen...',
'Clean': 'löschen', 'Clean': 'leeren',
'click here for online examples': 'hier klicken für online Beispiele', 'click here for online examples': 'hier klicken für online Beispiele',
'click here for the administrative interface': 'hier klicken für die Administrationsoberfläche ', 'click here for the administrative interface': 'hier klicken für die Administrationsoberfläche ',
'Click row to expand traceback': 'Klicke auf die Zeile für Fehlerverfolgung',
'click to check for upgrades': 'hier klicken um nach Upgrades zu suchen', 'click to check for upgrades': 'hier klicken um nach Upgrades zu suchen',
'Client IP': 'Client IP', 'Client IP': 'Client IP',
'code': 'code', 'code': 'code',
'collapse/expand all': 'collapse/expand all', 'collapse/expand all': 'alles zu- bzw. aufklappen',
'Compile': 'kompilieren', 'Compile': 'kompilieren',
'compiled application removed': 'kompilierte Anwendung gelöscht', 'compiled application removed': 'kompilierte Anwendung gelöscht',
'Controller': 'Controller', 'Controller': 'Controller',
'Controllers': 'Controller', 'Controllers': 'Controller',
'controllers': 'Controllers', 'controllers': 'Controllers',
'Copyright': 'Urheberrecht', 'Copyright': 'Urheberrecht',
'Count': 'Anzahl',
'Create': 'erstellen', 'Create': 'erstellen',
'create file with filename:': 'erzeuge Datei mit Dateinamen:', 'create file with filename:': 'erzeuge Datei mit Dateinamen:',
'create new application:': 'erzeuge neue Anwendung:', 'create new application:': 'erzeuge neue Anwendung:',
'Create new simple application': 'Erzeuge neue Anwendung', 'Create new simple application': 'Erzeuge neue Anwendung',
'created by': 'created by', 'created by': 'erstellt von',
'crontab': 'crontab', 'crontab': 'crontab',
'Current request': 'Aktuelle Anfrage (request)', 'Current request': 'Aktuelle Anfrage (request)',
'Current response': 'Aktuelle Antwort (response)', 'Current response': 'Aktuelle Antwort (response)',
'Current session': 'Aktuelle Sitzung (session)', 'Current session': 'Aktuelle Sitzung (session)',
'currently running': 'currently running', 'currently running': 'aktuell in Betrieb',
'currently saved or': 'des derzeit gespeicherten oder', 'currently saved or': 'des derzeit gespeicherten oder',
'customize me!': 'pass mich an!', 'customize me!': 'pass mich an!',
'data uploaded': 'Daten hochgeladen', 'data uploaded': 'Daten hochgeladen',
@@ -97,23 +107,27 @@
'DB Model': 'DB Modell', 'DB Model': 'DB Modell',
'Debug': 'Debug', 'Debug': 'Debug',
'defines tables': 'definiere Tabellen', 'defines tables': 'definiere Tabellen',
'Delete': 'Löschen', 'Delete': 'löschen',
'delete': 'löschen', 'delete': 'löschen',
'delete all checked': 'lösche alle markierten', 'delete all checked': 'lösche alle markierten',
'delete plugin': 'Plugin löschen', 'delete plugin': 'Plugin löschen',
'Delete:': 'Löschen:', 'Delete this file (you will be asked to confirm deletion)': 'Delete this file (you will be asked to confirm deletion)',
'Deploy': 'deploy', 'Delete:': 'löschen:',
'Deploy': 'Installieren',
'Deploy on Google App Engine': 'Auf Google App Engine installieren', 'Deploy on Google App Engine': 'Auf Google App Engine installieren',
'Deploy to OpenShift': 'Deploy to OpenShift', 'Deploy to OpenShift': 'Auf OpenShift installieren',
'Description': 'Beschreibung', 'Description': 'Beschreibung',
'design': 'design', 'design': 'design',
'DESIGN': 'design', 'DESIGN': 'design',
'Design for': 'Design für', 'Design for': 'Design für',
'Detailed traceback description': 'Detailed traceback description',
'direction: ltr': 'direction: ltr', 'direction: ltr': 'direction: ltr',
'Disable': 'Disable', 'Disable': 'Deaktivieren',
'docs': 'docs',
'documentation': 'Dokumentation', 'documentation': 'Dokumentation',
'done!': 'fertig!', 'done!': 'fertig!',
'download layouts': 'download layouts', 'Download .w2p': 'Download .w2p',
'download layouts': 'Layouts herunterladen',
'download plugins': 'download plugins', 'download plugins': 'download plugins',
'E-mail': 'E-mail', 'E-mail': 'E-mail',
'EDIT': 'BEARBEITEN', 'EDIT': 'BEARBEITEN',
@@ -128,16 +142,23 @@
'Editing file': 'Bearbeite Datei', 'Editing file': 'Bearbeite Datei',
'Editing file "%s"': 'Bearbeite Datei "%s"', 'Editing file "%s"': 'Bearbeite Datei "%s"',
'Editing Language file': 'Sprachdatei bearbeiten', 'Editing Language file': 'Sprachdatei bearbeiten',
'Enable': 'Enable',
'Enterprise Web Framework': 'Enterprise Web Framework', 'Enterprise Web Framework': 'Enterprise Web Framework',
'Error': 'Fehler',
'Error logs for "%(app)s"': 'Fehlerprotokoll für "%(app)s"', 'Error logs for "%(app)s"': 'Fehlerprotokoll für "%(app)s"',
'Error snapshot': 'Error snapshot',
'Error ticket': 'Error ticket',
'Errors': 'Fehler', 'Errors': 'Fehler',
'escape': 'escape', 'escape': 'escape',
'Exception instance attributes': 'Atribute der Ausnahmeinstanz', 'Exception instance attributes': 'Atribute der Ausnahmeinstanz',
'Expand Abbreviation': 'Kürzel erweitern', 'Expand Abbreviation': 'Kürzel erweitern',
'export as csv file': 'Exportieren als CSV-Datei', 'export as csv file': 'Exportieren als CSV-Datei',
'exposes': 'stellt zur Verfügung', 'exposes': 'stellt zur Verfügung',
'exposes:': 'exposes:',
'extends': 'erweitert', 'extends': 'erweitert',
'failed to compile file because:': 'failed to compile file because:',
'failed to reload module': 'neu laden des Moduls fehlgeschlagen', 'failed to reload module': 'neu laden des Moduls fehlgeschlagen',
'File': 'Datei',
'file "%(filename)s" created': 'Datei "%(filename)s" erstellt', 'file "%(filename)s" created': 'Datei "%(filename)s" erstellt',
'file "%(filename)s" deleted': 'Datei "%(filename)s" gelöscht', 'file "%(filename)s" deleted': 'Datei "%(filename)s" gelöscht',
'file "%(filename)s" uploaded': 'Datei "%(filename)s" hochgeladen', 'file "%(filename)s" uploaded': 'Datei "%(filename)s" hochgeladen',
@@ -148,25 +169,33 @@
'file saved on %(time)s': 'Datei gespeichert am %(time)s', 'file saved on %(time)s': 'Datei gespeichert am %(time)s',
'file saved on %s': 'Datei gespeichert auf %s', 'file saved on %s': 'Datei gespeichert auf %s',
'filter': 'filter', 'filter': 'filter',
'Find Next': 'Find Next',
'Find Previous': 'Find Previous',
'First name': 'Vorname', 'First name': 'Vorname',
'Frames': 'Frames',
'Functions with no doctests will result in [passed] tests.': 'Funktionen ohne doctests erzeugen [passed] in Tests', 'Functions with no doctests will result in [passed] tests.': 'Funktionen ohne doctests erzeugen [passed] in Tests',
'Get from URL:': 'Get from URL:', 'Get from URL:': 'Get from URL:',
'Git Pull': 'Git Pull', 'Git Pull': 'Git Pull',
'Git Push': 'Git Push', 'Git Push': 'Git Push',
'Go to Matching Pair': 'gehe zum übereinstimmenden Paar', 'Go to Matching Pair': 'gehe zum übereinstimmenden Paar',
'Goto': 'Goto',
'graph model': 'graph model',
'Group ID': 'Gruppen ID', 'Group ID': 'Gruppen ID',
'Hello World': 'Hallo Welt', 'Hello World': 'Hallo Welt',
'Help': 'Hilfe', 'Help': 'Hilfe',
'Hide/Show Translated strings': 'Hide/Show Translated strings',
'Home': 'Home',
'htmledit': 'htmledit', 'htmledit': 'htmledit',
'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'Falls der obere Test eine Fehler-Ticketnummer enthält deutet das auf einen Fehler in der Ausführung des Controllers hin, noch bevor der Doctest ausgeführt werden konnte. Gewöhnlich führen fehlerhafte Einrückungen oder fehlerhafter Code ausserhalb der Funktion zu solchen Fehlern. Ein grüner Titel deutet darauf hin, dass alle Test(wenn sie vorhanden sind) erfolgreich durchlaufen wurden. In diesem Fall werden die Testresultate nicht angezeigt.', 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'Falls der obere Test eine Fehler-Ticketnummer enthält deutet das auf einen Fehler in der Ausführung des Controllers hin, noch bevor der Doctest ausgeführt werden konnte. Gewöhnlich Führen fehlerhafte Einrückungen oder fehlerhafter Code ausserhalb der Funktion zu solchen Fehlern. Ein grüner Titel deutet darauf hin, dass alle Test(wenn sie vorhanden sind) erfolgreich durchlaufen wurden. In diesem Fall werden die Testresultate nicht angezeigt.',
'If you answer "yes", be patient, it may take a while to download': '', 'If you answer "yes", be patient, it may take a while to download': '',
'If you answer yes, be patient, it may take a while to download': 'If you answer yes, be patient, it may take a while to download', 'If you answer yes, be patient, it may take a while to download': 'If you answer yes, be patient, it may take a while to download',
'Import/Export': 'Importieren/Exportieren', 'Import/Export': 'Importieren/Exportieren',
'includes': 'Einfügen', 'includes': 'Einfügen',
'Index': 'Index', 'Index': 'Index',
'index': 'index', 'index': 'index',
'insert new': 'neu einfügen', 'insert new': 'neu Einfügen',
'insert new %s': 'neu einfügen %s', 'insert new %s': 'neu Einfügen %s',
'inspect attributes': 'inspect attributes',
'Install': 'installieren', 'Install': 'installieren',
'Installed applications': 'Installierte Anwendungen', 'Installed applications': 'Installierte Anwendungen',
'internal error': 'interner Fehler', 'internal error': 'interner Fehler',
@@ -175,9 +204,10 @@
'Invalid email': 'Ungültige Email', 'Invalid email': 'Ungültige Email',
'invalid password': 'Ungültiges Passwort', 'invalid password': 'Ungültiges Passwort',
'Invalid Query': 'Ungültige Abfrage', 'Invalid Query': 'Ungültige Abfrage',
'invalid request': 'ungültige Anfrage', 'invalid request': 'Ungültige Anfrage',
'invalid ticket': 'ungültiges Ticket', 'invalid ticket': 'Ungültiges Ticket',
'Key bindings': 'Tastenbelegungen', 'Key bindings': 'Tastenbelegungen',
'Key bindings for ZenCoding Plugin': 'Key bindings for ZenCoding Plugin',
'Key bindings for ZenConding Plugin': 'Tastenbelegungen für das ZenConding Plugin', 'Key bindings for ZenConding Plugin': 'Tastenbelegungen für das ZenConding Plugin',
'language file "%(filename)s" created/updated': 'Sprachdatei "%(filename)s" erstellt/aktualisiert', 'language file "%(filename)s" created/updated': 'Sprachdatei "%(filename)s" erstellt/aktualisiert',
'Language files (static strings) updated': 'Sprachdatei (statisch Strings) aktualisiert', 'Language files (static strings) updated': 'Sprachdatei (statisch Strings) aktualisiert',
@@ -189,6 +219,7 @@
'Layout': 'Layout', 'Layout': 'Layout',
'License for': 'Lizenz für', 'License for': 'Lizenz für',
'loading...': 'lade...', 'loading...': 'lade...',
'locals': 'locals',
'located in the file': 'located in Datei', 'located in the file': 'located in Datei',
'Login': 'Anmelden', 'Login': 'Anmelden',
'login': 'anmelden', 'login': 'anmelden',
@@ -196,7 +227,8 @@
'Logout': 'abmelden', 'Logout': 'abmelden',
'Lost Password': 'Passwort vergessen', 'Lost Password': 'Passwort vergessen',
'lost password?': 'Passwort vergessen?', 'lost password?': 'Passwort vergessen?',
'Main Menu': 'Menú principal', 'Main Menu': 'Menü principal',
'Manage': 'Verwalten',
'Match Pair': 'Paare finden', 'Match Pair': 'Paare finden',
'Menu Model': 'Menü Modell', 'Menu Model': 'Menü Modell',
'merge': 'verbinden', 'merge': 'verbinden',
@@ -207,22 +239,28 @@
'modules': 'Module', 'modules': 'Module',
'Name': 'Name', 'Name': 'Name',
'new application "%s" created': 'neue Anwendung "%s" erzeugt', 'new application "%s" created': 'neue Anwendung "%s" erzeugt',
'New application wizard': 'New application wizard', 'New application wizard': 'Neue Anwendung per Assistent',
'new plugin installed': 'new plugin installed',
'New Record': 'Neuer Datensatz', 'New Record': 'Neuer Datensatz',
'new record inserted': 'neuer Datensatz eingefügt', 'new record inserted': 'neuer Datensatz eingefügt',
'New simple application': 'New simple application', 'New simple application': 'Neue einfache Anwendung',
'next 100 rows': 'nächsten 100 Zeilen', 'next 100 rows': 'nächsten 100 Zeilen',
'Next Edit Point': 'nächster Bearbeitungsschritt', 'Next Edit Point': 'nächster Bearbeitungsschritt',
'NO': 'NEIN', 'NO': 'NEIN',
'No databases in this application': 'Keine Datenbank in dieser Anwendung', 'No databases in this application': 'Keine Datenbank in dieser Anwendung',
'No ticket_storage.txt found under /private folder': 'No ticket_storage.txt found under /private folder',
'online designer': 'online designer',
'or alternatively': 'or alternatively',
'Or Get from URL:': 'oder hole es von folgender URL:',
'or import from csv file': 'oder importieren von cvs Datei', 'or import from csv file': 'oder importieren von cvs Datei',
'or provide app url:': 'oder geben Sie eine Anwendungs-URL an:', 'or provide app url:': 'oder geben Sie eine Anwendungs-URL an:',
'or provide application url:': 'oder geben Sie eine Anwendungs-URL an:', 'or provide application url:': 'oder geben Sie eine Anwendungs-URL an:',
'Origin': 'Herkunft', 'Origin': 'Herkunft',
'Original/Translation': 'Original/Übersetzung', 'Original/Translation': 'Original/übersetzung',
'Overwrite installed app': 'installierte Anwendungen überschreiben', 'Overwrite installed app': 'installierte Anwendungen überschreiben',
'Pack all': 'verpacke alles', 'Pack all': 'verpacke alles',
'Pack compiled': 'Verpacke kompiliert', 'Pack compiled': 'Verpacke kompiliert',
'Pack custom': 'Verpacke individuell',
'pack plugin': 'Plugin verpacken', 'pack plugin': 'Plugin verpacken',
'Password': 'Passwort', 'Password': 'Passwort',
'Peeking at file': 'Dateiansicht', 'Peeking at file': 'Dateiansicht',
@@ -230,9 +268,13 @@
'Plugin "%s" in application': 'Plugin "%s" in Anwendung', 'Plugin "%s" in application': 'Plugin "%s" in Anwendung',
'plugins': 'plugins', 'plugins': 'plugins',
'Plugins': 'Plugins', 'Plugins': 'Plugins',
'Plural-Forms:': 'Plural-Forms:',
'Powered by': 'Unterstützt von', 'Powered by': 'Unterstützt von',
'previous 100 rows': 'vorherige 100 zeilen', 'previous 100 rows': 'vorherige 100 zeilen',
'Previous Edit Point': 'vorheriger Bearbeitungsschritt', 'Previous Edit Point': 'vorheriger Bearbeitungsschritt',
'Private files': 'Private files',
'private files': 'private files',
'Project Progress': 'Projekt Fortschritt',
'Query:': 'Abfrage:', 'Query:': 'Abfrage:',
'record': 'Datensatz', 'record': 'Datensatz',
'record does not exist': 'Datensatz existiert nicht', 'record does not exist': 'Datensatz existiert nicht',
@@ -241,26 +283,39 @@
'register': 'Registrierung', 'register': 'Registrierung',
'Register': 'registrieren', 'Register': 'registrieren',
'Registration key': 'Registrierungsschlüssel', 'Registration key': 'Registrierungsschlüssel',
'Reload routes': 'Reload routes', 'reload': 'Neu laden',
'Remove compiled': 'kompilat gelöscht', 'Reload routes': 'Routen neu laden',
'Remove compiled': 'Bytecode löschen',
'Replace': 'Replace',
'Replace All': 'Replace All',
'request': 'request',
'Reset Password key': 'Passwortschlüssel zurücksetzen', 'Reset Password key': 'Passwortschlüssel zurücksetzen',
'Resolve Conflict file': 'bereinige Konflikt-Datei', 'Resolve Conflict file': 'bereinige Konflikt-Datei',
'response': 'Antwort',
'restore': 'wiederherstellen', 'restore': 'wiederherstellen',
'revert': 'zurückkehren', 'revert': 'zurückkehren',
'Role': 'Rolle', 'Role': 'Rolle',
'Rows in table': 'Zeilen in Tabelle', 'Rows in table': 'Zeilen in Tabelle',
'Rows selected': 'Zeilen ausgewählt', 'Rows selected': 'Zeilen ausgewählt',
'Running on %s': 'Running on %s', 'rules are not defined': 'rules are not defined',
"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Run tests in this file (to run all files, you may also use the button labelled 'test')",
'Running on %s': 'läuft auf %s',
'Save': 'Save',
'save': 'sichern', 'save': 'sichern',
'Save file:': 'Save file:',
'Save via Ajax': 'via Ajax sichern', 'Save via Ajax': 'via Ajax sichern',
'Saved file hash:': 'Gespeicherter Datei-Hash:', 'Saved file hash:': 'Gespeicherter Datei-Hash:',
'Select Files to Package': 'Dateien zum Paketieren wählen',
'selected': 'ausgewählt(e)', 'selected': 'ausgewählt(e)',
'session expired': 'Sitzung Abgelaufen', 'session': 'Sitzung',
'session expired': 'Sitzung abgelaufen',
'shell': 'shell', 'shell': 'shell',
'Site': 'Seite', 'Site': 'Seite',
'some files could not be removed': 'einige Dateien konnten nicht gelöscht werden', 'some files could not be removed': 'einige Dateien konnten nicht gelöscht werden',
'Start wizard': 'start wizard', 'Start searching': 'Start searching',
'Start wizard': 'Assistent starten',
'state': 'Status', 'state': 'Status',
'Static': 'Static',
'static': 'statische Dateien', 'static': 'statische Dateien',
'Static files': 'statische Dateien', 'Static files': 'statische Dateien',
'Stylesheet': 'Stylesheet', 'Stylesheet': 'Stylesheet',
@@ -283,27 +338,35 @@
'The data representation, define database tables and sets': 'The data representation, define database tables and sets', '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': 'The output of the file is a dictionary that was rendered by the view', 'The output of the file is a dictionary that was rendered by the view': 'The output of the file is a dictionary that was rendered by the view',
'The presentations layer, views are also known as templates': 'The presentations layer, views are also known as templates', 'The presentations layer, views are also known as templates': 'The presentations layer, views are also known as templates',
'the presentations layer, views are also known as templates': 'Die Präsentationsschicht, Views sind auch bekannt als Vorlagen/Templates', 'the presentations layer, views are also known as templates': 'Die präsentationsschicht, Views sind auch bekannt als Vorlagen/Templates',
'There are no controllers': 'Keine Controller vorhanden', 'There are no controllers': 'Keine Controller vorhanden',
'There are no models': 'Keine Modelle vorhanden', 'There are no models': 'Keine Modelle vorhanden',
'There are no modules': 'Keine Module vorhanden', 'There are no modules': 'Keine Module vorhanden',
'There are no plugins': 'There are no plugins', 'There are no plugins': 'Keine Plugins vorhanden',
'There are no private files': 'There are no private files',
'There are no static files': 'Keine statischen Dateien vorhanden', 'There are no static files': 'Keine statischen Dateien vorhanden',
'There are no translators, only default language is supported': 'Keine Übersetzungen vorhanden, nur die voreingestellte Sprache wird unterstützt', 'There are no translators, only default language is supported': 'Keine übersetzungen vorhanden, nur die voreingestellte Sprache wird Unterstützt',
'There are no views': 'Keine Views vorhanden', 'There are no views': 'Keine Views vorhanden',
'These files are served without processing, your images go here': 'These files are served without processing, your images go here', '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': 'Diese Dateien werden ohne Verarbeitung ausgeliefert. Beispielsweise Bilder kommen hier hin.',
'these files are served without processing, your images go here': 'Diese Dateien werden ohne Verarbeitung ausgeliefert. Beispielsweise Bilder kommen hier hin.', 'these files are served without processing, your images go here': 'Diese Dateien werden ohne Verarbeitung ausgeliefert. Beispielsweise Bilder kommen hier hin.',
'This is a copy of the scaffolding application': 'Dies ist eine Kopie einer Grundgerüst-Anwendung', 'This is a copy of the scaffolding application': 'Dies ist eine Kopie einer Grundgerüst-Anwendung',
'This is the %(filename)s template': 'Dies ist das Template %(filename)s', 'This is the %(filename)s template': 'Dies ist das Template %(filename)s',
'Ticket': 'Ticket', 'Ticket': 'Ticket',
'Timestamp': 'Timestamp', 'Ticket ID': 'Ticket ID',
'Timestamp': 'Zeitstempel',
'TM': 'TM', 'TM': 'TM',
'to previous version.': 'zu einer früheren Version.', 'to previous version.': 'zu einer früheren Version.',
'To create a plugin, name a file/folder plugin_[name]': 'Um ein Plugin zu erstellen benennen Sie eine(n) Datei/Ordner plugin_[Name]', 'To create a plugin, name a file/folder plugin_[name]': 'Um ein Plugin zu erstellen benennen Sie eine(n) Datei/Ordner plugin_[Name]',
'translation strings for the application': 'Übersetzungs-Strings für die Anwendung', 'toggle breakpoint': 'toggle breakpoint',
'Translation strings for the application': 'Translation strings for the application', 'Toggle Fullscreen': 'Toggle Fullscreen',
'Traceback': 'Traceback',
'translation strings for the application': 'übersetzungs-Strings für die Anwendung',
'Translation strings for the application': 'übersetzungs-Strings für die Anwendung',
'try': 'versuche', 'try': 'versuche',
'try something like': 'versuche so etwas wie', 'try something like': 'versuche so etwas wie',
'Try the mobile interface': 'Try the mobile interface',
'try view': 'try view',
'Unable to check for upgrades': 'überprüfen von Upgrades nicht möglich', 'Unable to check for upgrades': 'überprüfen von Upgrades nicht möglich',
'unable to create application "%s"': 'erzeugen von Anwendung "%s" nicht möglich', 'unable to create application "%s"': 'erzeugen von Anwendung "%s" nicht möglich',
'unable to delete file "%(filename)s"': 'löschen von Datein "%(filename)s" nicht möglich', 'unable to delete file "%(filename)s"': 'löschen von Datein "%(filename)s" nicht möglich',
@@ -311,37 +374,40 @@
'Unable to download app': 'herunterladen der Anwendung nicht möglich', 'Unable to download app': 'herunterladen der Anwendung nicht möglich',
'unable to parse csv file': 'analysieren der cvs Datei nicht möglich', 'unable to parse csv file': 'analysieren der cvs Datei nicht möglich',
'unable to uninstall "%s"': 'deinstallieren von "%s" nicht möglich', 'unable to uninstall "%s"': 'deinstallieren von "%s" nicht möglich',
'uncheck all': 'alles demarkieren', 'uncheck all': 'Selektionen entfernen',
'Uninstall': 'deinstallieren', 'Uninstall': 'deinstallieren',
'update': 'aktualisieren', 'update': 'aktualisieren',
'update all languages': 'aktualisiere alle Sprachen', 'update all languages': 'aktualisiere alle Sprachen',
'Update:': 'Aktualisiere:', 'Update:': 'Aktualisiere:',
'upgrade web2py now': 'jetzt web2py upgraden', 'upgrade web2py now': 'jetzt web2py upgraden',
'upload': 'upload', 'upload': 'upload',
'Upload': 'Upload',
'Upload & install packed application': 'Verpackte Anwendung hochladen und installieren', 'Upload & install packed application': 'Verpackte Anwendung hochladen und installieren',
'Upload a package:': 'Upload a package:', 'Upload a package:': 'Ein Packet hochladen:',
'Upload and install packed application': 'Upload and install packed application', 'Upload and install packed application': 'Verpackte Anwendung hochladen und installieren',
'upload application:': 'lade Anwendung hoch:', 'upload application:': 'lade Anwendung hoch:',
'Upload existing application': 'lade existierende Anwendung hoch', 'Upload existing application': 'lade existierende Anwendung hoch',
'upload file:': 'lade Datei hoch:', 'upload file:': 'lade Datei hoch:',
'upload plugin file:': 'Plugin-Datei hochladen:', 'upload plugin file:': 'Plugin-Datei hochladen:',
'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Benutze (...)&(...) für AND, (...)|(...) für OR, und ~(...) für NOT, um komplexe Abfragen zu erstellen.', 'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Benutze (...)&(...) für AND, (...)|(...) für OR, und ~(...) für NOT, um komplexe Abfragen zu erstellen.',
'Use an url:': 'Use an url:', 'Use an url:': 'Verwende URL:',
'user': 'user', 'user': 'Nutzer',
'User ID': 'Benutzer ID', 'User ID': 'Benutzer ID',
'variables': 'variables', 'variables': 'Variablen',
'Version': 'Version', 'Version': 'Version',
'Version %s.%s.%s (%s) %s': 'Version %s.%s.%s (%s) %s', 'Version %s.%s.%s (%s) %s': 'Version %s.%s.%s (%s) %s',
'versioning': 'Versionierung', 'versioning': 'Versionierung',
'View': 'View', 'Versioning': 'Versionierung',
'view': 'View', 'View': 'Ansicht',
'Views': 'Views', 'view': 'Ansicht',
'views': 'Views', 'Views': 'Ansichten',
'views': 'Ansichten',
'Web Framework': 'Web Framework',
'web2py is up to date': 'web2py ist auf dem neuesten Stand', 'web2py is up to date': 'web2py ist auf dem neuesten Stand',
'web2py Recent Tweets': 'neuste Tweets von web2py', 'web2py Recent Tweets': 'neuste Tweets von web2py',
'Welcome %s': 'Willkommen %s', 'Welcome %s': 'Willkommen %s',
'Welcome to web2py': 'Willkommen zu web2py', 'Welcome to web2py': 'Willkommen zu web2py',
'Which called the function': 'Which called the function', 'Which called the function': 'welche die Funktion aufrief',
'Wrap with Abbreviation': 'mit Kürzel einhüllen', 'Wrap with Abbreviation': 'mit Kürzel einhüllen',
'xml': 'xml', 'xml': 'xml',
'YES': 'JA', 'YES': 'JA',
+637 -226
View File
@@ -1,242 +1,653 @@
function popup(url) { (function ($, undefined) {
newwindow=window.open(url,'name','height=400,width=600'); /*
if (window.focus) newwindow.focus(); * Unobtrusive scripting adapter for jQuery, largely taken from
return false; * the wonderful https://github.com/rails/jquery-ujs
} *
function collapse(id) { jQuery('#'+id).slideToggle(); } *
function fade(id,value) { if(value>0) jQuery('#'+id).hide().fadeIn('slow'); else jQuery('#'+id).show().fadeOut('slow'); } * Released under the MIT license
function ajax(u,s,t) { *
query = ''; */
if (typeof s == "string") {
d = jQuery(s).serialize(); String.prototype.reverse = function () {
if(d){ query = d; } return this.split('').reverse().join('');
} else { };
var web2py;
$.web2py = web2py = {
popup: function (url) {
newwindow = window.open(url, 'name', 'height=400,width=600');
if(window.focus) newwindow.focus();
return false;
},
collapse: function (id) {
$('#' + id).slideToggle();
},
fade: function (id, value) {
if(value > 0) $('#' + id).hide().fadeIn('slow');
else $('#' + id).show().fadeOut('slow');
},
ajax: function (u, s, t) {
query = '';
if(typeof s == "string") {
d = $(s).serialize();
if(d) {
query = d;
}
} else {
pcs = []; pcs = [];
if (s != null && s != undefined) for(i=0; i<s.length; i++) { if(s != null && s != undefined) for(i = 0; i < s.length; i++) {
q = jQuery("[name="+s[i]+"]").serialize(); q = $("[name=" + s[i] + "]").serialize();
if(q){pcs.push(q);} 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);
web2py_show_if(target);
};
function web2py_event_handlers() {
var doc = jQuery(document)
doc.on('click', '.flash', function(e){var t=jQuery(this); if(t.css('top')=='0px') t.slideUp('slow'); else t.fadeOut(); e.preventDefault();});
doc.on('keyup', 'input.integer', function(){this.value=this.value.reverse().replace(/[^0-9\-]|\-(?=.)/g,'').reverse();});
doc.on('keyup', 'input.double, input.decimal', function(){this.value=this.value.reverse().replace(/[^0-9\-\.,]|[\-](?=.)|[\.,](?=[0-9]*[\.,])/g,'').reverse();});
var confirm_message = (typeof w2p_ajax_confirm_message != 'undefined') ? w2p_ajax_confirm_message : "Are you sure you want to delete this object?";
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');
var command=xhr.getResponseHeader('web2py-component-command');
var flash=xhr.getResponseHeader('web2py-component-flash');
if (redirect !== null) {
window.location = redirect;
};
if(command !== null){
eval(decodeURIComponent(command));
}
if(flash) {
jQuery('.flash')
.html(decodeURIComponent(flash))
.append('<span id="closeflash">&times;</span>')
.slideDown();
}
});
doc.ajaxError(function(e, xhr, settings, exception) {
doc.off('click', '.flash')
switch(xhr.status){
case 500:
$('.flash').html(ajax_error_500).slideDown();
} }
}); $.ajax({
}; type: "POST",
url: u,
jQuery(function() { data: query,
var flash = jQuery('.flash'); success: function (msg) {
flash.hide(); if(t) {
if(flash.html()) flash.append('<span id="closeflash">&times;</span>').slideDown(); if(t == ':eval') eval(msg);
web2py_ajax_init(document); else if(typeof t == 'string') $("#" + t).html(msg);
web2py_event_handlers(); else t(msg);
}); }
}
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();
}); });
}); },
} ajax_fields: function (target) {
/*this attaches something to a newly loaded fragment/page
function web2py_trap_link(target) { * Ideally all events should be bound to the document, so we can avoid calling
jQuery('#'+target+' a.w2p_trap').each(function(i){ * this over and over... all will be bound to the document
var link=jQuery(this); */
link.click(function(e) { var date_format = (typeof w2p_ajax_date_format != 'undefined') ? w2p_ajax_date_format : "%Y-%m-%d";
jQuery('.flash').hide().html(''); var datetime_format = (typeof w2p_ajax_datetime_format != 'undefined') ? w2p_ajax_datetime_format : "%Y-%m-%d %H:%M:%S";
web2py_ajax_page('get',link.attr('href'),[],target); $("input.date", target).each(function () {
e.preventDefault(); Calendar.setup({
}); inputField: this,
ifFormat: date_format,
showsTime: false
}); });
} });
$("input.datetime", target).each(function () {
Calendar.setup({
inputField: this,
ifFormat: datetime_format,
showsTime: true,
timeFormat: "24"
});
});
$("input.time", target).each(function () {
$(this).timeEntry();
});
/*adds btn class to buttons*/
$('button', target).addClass('btn');
$('form input[type="submit"], form input[type="button"]', target).addClass('btn');
/*no more inline javascript for PasswordWidget*/
$('input[type=password][data-w2p_entropy]', target).each(function () {
web2py.validate_entropy($(this));
});
/*no more inline 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 web2py_ajax_page(method, action, data, target) { function rl(ul, e) {
jQuery.ajax({'type':method, 'url':action, 'data':data, if($(ul).children().length > 1) {
'beforeSend':function(xhr) { //only remove if we have more than 1 item so the list is never empty
xhr.setRequestHeader('web2py-component-location', document.location); $(e.target).parent().remove();
xhr.setRequestHeader('web2py-component-element', target);}, }
'complete':function(xhr,text){ }
var html=xhr.responseText;
var content=xhr.getResponseHeader('web2py-component-content');
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);
}
});
}
function web2py_component(action, target, timeout, times){ function ml(ul) {
jQuery(function(){ var line = $(ul).find("li:first").clone(true);
var jelement = jQuery("#" + target); line.find(':text').val('');
var element = jelement.get(0); return line;
var statement = "jQuery('#" + target + "').get(0).reload();"; }
jelement.reload = function (){
// Continue if times is Infinity or function rel(ul) {
// the times limit is not reached $(ul).find("li").each(function () {
if (element.reload_check()){ var trimmed = $.trim($(this.firstChild).val());
web2py_ajax_page('get', action, null, target);} }; // reload if(trimmed == '') $(this).remove();
// Method to check timing limit else $(this.firstChild).val(trimmed);
element.reload_check = function (){ });
if (jelement.hasClass('w2p_component_stop')) {clearInterval(this.timing);return false;} }
if (this.reload_counter == Infinity){return true;} var ul = this;
else { $(ul).find(":text").after('<a href="#">+</a>&nbsp;<a href="#">-</a>').keypress(function (e) {
if (!isNaN(this.reload_counter)){ return(e.which == 13) ? pe(ul, e) : true;
this.reload_counter -= 1; }).next().click(function (e) {
if (this.reload_counter < 0){ pe(ul, e);
if (!this.run_once){ e.preventDefault();
clearInterval(this.timing); }).next().click(function (e) {
return false; rl(ul, e);
} e.preventDefault();
});
});
},
ajax_init: function (target) {
$('.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');
//$('.error', target).hide().fadeIn('slow');
},
event_handlers: function () {
/* This is called once for page
* Ideally it should bound all the things that are needed
*/
var doc = $(document);
doc.on('click', '.flash', function (e) {
var t = $(this);
if(t.css('top') == '0px') t.slideUp('slow');
else t.fadeOut();
//if I want to display a clickable something
//inside flash, I should not be prevented to follow it
//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(!web2py.confirm(confirm_message)) this.checked = false;
});
doc.ajaxSuccess(function (e, xhr) {
var redirect = xhr.getResponseHeader('web2py-redirect-location');
var command = xhr.getResponseHeader('web2py-component-command');
var flash = xhr.getResponseHeader('web2py-component-flash');
if(redirect !== null) {
window.location = redirect;
};
if(command !== null) {
eval(decodeURIComponent(command));
}
if(flash) {
web2py.flash(decodeURIComponent(flash))
}
});
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) {
$('#' + 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.find('input[type=submit]').attr('data-w2p_disable_with', 'Working...');
form.submit(function (e) {
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(web2py.fire(element, 'ajax:before')) { //test a usecase, should stop here if returns false
$.ajax({
'type': method,
'url': action,
'data': data,
'beforeSend': function (xhr, settings) {
//added
xhr.setRequestHeader('web2py-component-location', document.location);
xhr.setRequestHeader('web2py-component-element', target);
return web2py.fire(element, 'ajax:beforeSend', [xhr, settings]); //test a usecase, should stop here if returns false
},
//added
'success': function (data, status, xhr) {
//bummer for form submissions....the element is not there after complete
//because it gets replaced by the new response....
element.trigger('ajax:success', [data, status, xhr]);
},
//added
'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)
element.trigger('ajax:error', [xhr, status, error]);
},
'complete': function (xhr, status) {
element.trigger('ajax:complete', [xhr, status]);
var html = xhr.responseText;
var content = xhr.getResponseHeader('web2py-component-content');
var t = $('#' + 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);
}
});
}
},
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);
}
}; // reload
// 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;} } else {
} } return true;
return false;}; // reload check }
if (!isNaN(timeout)){ }
element.timeout = timeout; }
element.reload_counter = times; return false;
if (times > 1){ }; // reload check
// Multiple or infinite reload if(!isNaN(timeout)) {
// Run first iteration element.timeout = timeout;
web2py_ajax_page('get', action, null, target); element.reload_counter = times;
element.run_once = false; if(times > 1) {
element.timing = setInterval(statement, timeout); // Multiple or infinite reload
element.reload_counter -= 1; // 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);
} }
else if (times == 1) { });
// Run once with timeout },
element.run_once = true; calc_entropy: function (mystring) {
element.setTimeout = setTimeout; //calculate a simple entropy for a given string
element.timing = setTimeout(statement, timeout); 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;
} }
} else { if(inset != lastset) {
// run once (no timeout specified) score += 1;
element.reload_counter = Infinity; lastset = inset;
web2py_ajax_page('get', action, null, target); }
} }); } }
var entropy = mystring.length * Math.log(score) / 0.6931471805599453;
return Math.round(entropy * 100) / 100
},
validate_entropy: function (myfield, req_entropy) {
//added
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-ujs
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, name, data) {
var event = $.Event(name);
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';
// store enabled state
el.data('w2p:enable-with', el[method]);
/* little addition by default*/
if((el.data('w2p_disable_with') == 'default') || (el.data('w2p_disable_with') === undefined)) {
el.data('w2p_disable_with', 'Working...');
}
// set to disabled state
el[method](el.data('w2p_disable_with'));
function web2py_websocket(url,onmessage,onopen,onclose) { el.bind('click.w2pDisable', function (e) { // prevent further clicking
if ("WebSocket" in window) { return web2py.stopEverything(e);
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
}
// 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'); // clean up cache
}
el.removeClass('disabled');
el.unbind('click.w2pDisable'); // enable element
},
//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');
function web2py_calc_entropy(mystring) { var pre_call = el.data('w2p_pre_call');
//calculate a simple entropy for a given string if(pre_call != undefined) {
var csets = new Array( eval(pre_call);
'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', }
'0123456789', '!@#$\%^&*()', '~`-_=+[]{}\|;:\'",.<>?/', if(confirm_message != undefined) {
'0123456789abcdefghijklmnopqrstuvwxyz'); if(confirm_message == 'default') confirm_message = w2p_ajax_confirm_message || 'Are you sure you want to delete this object?';
var score = 0, other = {}, seen = {}, lastset = null, mystringlist = mystring.split(''); if(!web2py.confirm(confirm_message)) {
for (var i=0;i<mystringlist.length;i++) { // classify this character web2py.stopEverything(e);
var c = mystringlist[i], inset=5; return;
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(target == undefined) {
if(!(inset in seen)) {seen[inset] = 1;score += csets[inset].length;} if(method == 'GET') {
else if (!(c in other)) {score += 1;other[c] = 1;} web2py.simple_component(action, el.attr('id'), el); //not working with original
if (inset != lastset) {score += 1;lastset = inset;} } else if(method == 'POST') {
//should be web2py.ajax(action, [], ''); but it's too simple
web2py.ajax_page('post', action, [], 'bogus', el); //fixme?
}
} else {
if(method == 'GET') {
web2py.simple_component(action, target, el);
} else if(method == 'POST') {
//should be web2py.ajax(action, [], target); but it's too simple
web2py.ajax_page('post', action, [], target, el);
}
}
/*this should happen only on ajaxsuccess
* and should block subsequent clicks until ajaxcomplete
* NB: introduce the first incompatibility because normally
* the element would be removed in either case
/* removal code moved to the ajax:success event - START
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();
}
/* removal code moved to the ajax:success event - END */
},
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));
});
} }
var entropy = mystring.length*Math.log(score)/0.6931471805599453; }
return Math.round(entropy*100)/100
}
function web2py_validate_entropy(myfield, req_entropy) { //end of functions
var validator = function () { //main hook
var v = (web2py_calc_entropy(myfield.val())||0)/req_entropy; $(function () {
var r=0,g=0,b=0,rs=function(x){return Math.round(x*15).toString(16)}; var flash = $('.flash');
if(v<=0.5) {r=1.0; g=2.0*v;} flash.hide();
else {r=(1.0-2.0*(Math.max(v,0)-0.5)); g=1.0;} if(flash.html()) web2py.flash(flash.html());
var color = '#'+rs(r)+rs(g)+rs(b); web2py.ajax_init(document);
myfield.css('background-color',color); web2py.event_handlers();
entropy_callback = myfield.data('entropy_callback'); web2py.a_handlers();
if(entropy_callback) entropy_callback(v); web2py.form_handlers();
} });
if(!myfield.hasClass('entropy_check')) myfield.on('keyup', validator).on('keydown', validator).addClass('entropy_check');
}
function web2py_show_if(target) { })(jQuery);
var triggers = {};
var show_if = function () { /* compatibility code - start */
var t = jQuery(this); ajax = $.web2py.ajax;
var id = t.attr('id'); web2py_component = $.web2py.component;
t.attr('value', t.val()); web2py_websocket = $.web2py.websocket;
for(var k = 0; k < triggers[id].length; k++) { web2py_ajax_page = $.web2py.ajax_page;
var dep = jQuery('#' + triggers[id][k], target); //needed for IS_STRONG(entropy)
var tr = jQuery('#' + triggers[id][k] + '__row', target); web2py_validate_entropy = $.web2py.validate_entropy;
if(t.is(dep.attr('data-show-if'))) tr.slideDown(); //needed for crud.search and SQLFORM.grid's search
else tr.hide(); web2py_ajax_fields = $.web2py.ajax_fields;
} //used for LOAD(ajax=False)
}; web2py_trap_form = $.web2py.trap_form;
jQuery('[data-show-trigger]', target).each(function () {
var name = jQuery(this).attr('data-show-trigger'); /*undocumented - rare*/
if(!triggers[name]) triggers[name] = []; popup = $.web2py.popup;
triggers[name].push(jQuery(this).attr('id')); collapse = $.web2py.collapse;
}); fade = $.web2py.fade;
for(var name in triggers) {
jQuery('#' + name, target).change(show_if).keyup(show_if); /* internals - shouldn't be needed
show_if.call(jQuery('#' + name, target));
}; web2py_ajax_init = $.web2py.ajax_init;
} web2py_event_handlers = $.web2py.event_handlers;
web2py_trap_link = $.web2py.trap_link;
web2py_calc_entropy = $.web2py.calc_entropy;
*/
/* compatibility code - end*/
+637 -226
View File
@@ -1,242 +1,653 @@
function popup(url) { (function ($, undefined) {
newwindow=window.open(url,'name','height=400,width=600'); /*
if (window.focus) newwindow.focus(); * Unobtrusive scripting adapter for jQuery, largely taken from
return false; * the wonderful https://github.com/rails/jquery-ujs
} *
function collapse(id) { jQuery('#'+id).slideToggle(); } *
function fade(id,value) { if(value>0) jQuery('#'+id).hide().fadeIn('slow'); else jQuery('#'+id).show().fadeOut('slow'); } * Released under the MIT license
function ajax(u,s,t) { *
query = ''; */
if (typeof s == "string") {
d = jQuery(s).serialize(); String.prototype.reverse = function () {
if(d){ query = d; } return this.split('').reverse().join('');
} else { };
var web2py;
$.web2py = web2py = {
popup: function (url) {
newwindow = window.open(url, 'name', 'height=400,width=600');
if(window.focus) newwindow.focus();
return false;
},
collapse: function (id) {
$('#' + id).slideToggle();
},
fade: function (id, value) {
if(value > 0) $('#' + id).hide().fadeIn('slow');
else $('#' + id).show().fadeOut('slow');
},
ajax: function (u, s, t) {
query = '';
if(typeof s == "string") {
d = $(s).serialize();
if(d) {
query = d;
}
} else {
pcs = []; pcs = [];
if (s != null && s != undefined) for(i=0; i<s.length; i++) { if(s != null && s != undefined) for(i = 0; i < s.length; i++) {
q = jQuery("[name="+s[i]+"]").serialize(); q = $("[name=" + s[i] + "]").serialize();
if(q){pcs.push(q);} 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);
web2py_show_if(target);
};
function web2py_event_handlers() {
var doc = jQuery(document)
doc.on('click', '.flash', function(e){var t=jQuery(this); if(t.css('top')=='0px') t.slideUp('slow'); else t.fadeOut(); e.preventDefault();});
doc.on('keyup', 'input.integer', function(){this.value=this.value.reverse().replace(/[^0-9\-]|\-(?=.)/g,'').reverse();});
doc.on('keyup', 'input.double, input.decimal', function(){this.value=this.value.reverse().replace(/[^0-9\-\.,]|[\-](?=.)|[\.,](?=[0-9]*[\.,])/g,'').reverse();});
var confirm_message = (typeof w2p_ajax_confirm_message != 'undefined') ? w2p_ajax_confirm_message : "Are you sure you want to delete this object?";
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');
var command=xhr.getResponseHeader('web2py-component-command');
var flash=xhr.getResponseHeader('web2py-component-flash');
if (redirect !== null) {
window.location = redirect;
};
if(command !== null){
eval(decodeURIComponent(command));
}
if(flash) {
jQuery('.flash')
.html(decodeURIComponent(flash))
.append('<span id="closeflash">&times;</span>')
.slideDown();
}
});
doc.ajaxError(function(e, xhr, settings, exception) {
doc.off('click', '.flash')
switch(xhr.status){
case 500:
$('.flash').html(ajax_error_500).slideDown();
} }
}); $.ajax({
}; type: "POST",
url: u,
jQuery(function() { data: query,
var flash = jQuery('.flash'); success: function (msg) {
flash.hide(); if(t) {
if(flash.html()) flash.append('<span id="closeflash">&times;</span>').slideDown(); if(t == ':eval') eval(msg);
web2py_ajax_init(document); else if(typeof t == 'string') $("#" + t).html(msg);
web2py_event_handlers(); else t(msg);
}); }
}
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();
}); });
}); },
} ajax_fields: function (target) {
/*this attaches something to a newly loaded fragment/page
function web2py_trap_link(target) { * Ideally all events should be bound to the document, so we can avoid calling
jQuery('#'+target+' a.w2p_trap').each(function(i){ * this over and over... all will be bound to the document
var link=jQuery(this); */
link.click(function(e) { var date_format = (typeof w2p_ajax_date_format != 'undefined') ? w2p_ajax_date_format : "%Y-%m-%d";
jQuery('.flash').hide().html(''); var datetime_format = (typeof w2p_ajax_datetime_format != 'undefined') ? w2p_ajax_datetime_format : "%Y-%m-%d %H:%M:%S";
web2py_ajax_page('get',link.attr('href'),[],target); $("input.date", target).each(function () {
e.preventDefault(); Calendar.setup({
}); inputField: this,
ifFormat: date_format,
showsTime: false
}); });
} });
$("input.datetime", target).each(function () {
Calendar.setup({
inputField: this,
ifFormat: datetime_format,
showsTime: true,
timeFormat: "24"
});
});
$("input.time", target).each(function () {
$(this).timeEntry();
});
/*adds btn class to buttons*/
$('button', target).addClass('btn');
$('form input[type="submit"], form input[type="button"]', target).addClass('btn');
/*no more inline javascript for PasswordWidget*/
$('input[type=password][data-w2p_entropy]', target).each(function () {
web2py.validate_entropy($(this));
});
/*no more inline 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 web2py_ajax_page(method, action, data, target) { function rl(ul, e) {
jQuery.ajax({'type':method, 'url':action, 'data':data, if($(ul).children().length > 1) {
'beforeSend':function(xhr) { //only remove if we have more than 1 item so the list is never empty
xhr.setRequestHeader('web2py-component-location', document.location); $(e.target).parent().remove();
xhr.setRequestHeader('web2py-component-element', target);}, }
'complete':function(xhr,text){ }
var html=xhr.responseText;
var content=xhr.getResponseHeader('web2py-component-content');
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);
}
});
}
function web2py_component(action, target, timeout, times){ function ml(ul) {
jQuery(function(){ var line = $(ul).find("li:first").clone(true);
var jelement = jQuery("#" + target); line.find(':text').val('');
var element = jelement.get(0); return line;
var statement = "jQuery('#" + target + "').get(0).reload();"; }
jelement.reload = function (){
// Continue if times is Infinity or function rel(ul) {
// the times limit is not reached $(ul).find("li").each(function () {
if (element.reload_check()){ var trimmed = $.trim($(this.firstChild).val());
web2py_ajax_page('get', action, null, target);} }; // reload if(trimmed == '') $(this).remove();
// Method to check timing limit else $(this.firstChild).val(trimmed);
element.reload_check = function (){ });
if (jelement.hasClass('w2p_component_stop')) {clearInterval(this.timing);return false;} }
if (this.reload_counter == Infinity){return true;} var ul = this;
else { $(ul).find(":text").after('<a href="#">+</a>&nbsp;<a href="#">-</a>').keypress(function (e) {
if (!isNaN(this.reload_counter)){ return(e.which == 13) ? pe(ul, e) : true;
this.reload_counter -= 1; }).next().click(function (e) {
if (this.reload_counter < 0){ pe(ul, e);
if (!this.run_once){ e.preventDefault();
clearInterval(this.timing); }).next().click(function (e) {
return false; rl(ul, e);
} e.preventDefault();
});
});
},
ajax_init: function (target) {
$('.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');
//$('.error', target).hide().fadeIn('slow');
},
event_handlers: function () {
/* This is called once for page
* Ideally it should bound all the things that are needed
*/
var doc = $(document);
doc.on('click', '.flash', function (e) {
var t = $(this);
if(t.css('top') == '0px') t.slideUp('slow');
else t.fadeOut();
//if I want to display a clickable something
//inside flash, I should not be prevented to follow it
//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(!web2py.confirm(confirm_message)) this.checked = false;
});
doc.ajaxSuccess(function (e, xhr) {
var redirect = xhr.getResponseHeader('web2py-redirect-location');
var command = xhr.getResponseHeader('web2py-component-command');
var flash = xhr.getResponseHeader('web2py-component-flash');
if(redirect !== null) {
window.location = redirect;
};
if(command !== null) {
eval(decodeURIComponent(command));
}
if(flash) {
web2py.flash(decodeURIComponent(flash))
}
});
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) {
$('#' + 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.find('input[type=submit]').attr('data-w2p_disable_with', 'Working...');
form.submit(function (e) {
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(web2py.fire(element, 'ajax:before')) { //test a usecase, should stop here if returns false
$.ajax({
'type': method,
'url': action,
'data': data,
'beforeSend': function (xhr, settings) {
//added
xhr.setRequestHeader('web2py-component-location', document.location);
xhr.setRequestHeader('web2py-component-element', target);
return web2py.fire(element, 'ajax:beforeSend', [xhr, settings]); //test a usecase, should stop here if returns false
},
//added
'success': function (data, status, xhr) {
//bummer for form submissions....the element is not there after complete
//because it gets replaced by the new response....
element.trigger('ajax:success', [data, status, xhr]);
},
//added
'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)
element.trigger('ajax:error', [xhr, status, error]);
},
'complete': function (xhr, status) {
element.trigger('ajax:complete', [xhr, status]);
var html = xhr.responseText;
var content = xhr.getResponseHeader('web2py-component-content');
var t = $('#' + 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);
}
});
}
},
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);
}
}; // reload
// 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;} } else {
} } return true;
return false;}; // reload check }
if (!isNaN(timeout)){ }
element.timeout = timeout; }
element.reload_counter = times; return false;
if (times > 1){ }; // reload check
// Multiple or infinite reload if(!isNaN(timeout)) {
// Run first iteration element.timeout = timeout;
web2py_ajax_page('get', action, null, target); element.reload_counter = times;
element.run_once = false; if(times > 1) {
element.timing = setInterval(statement, timeout); // Multiple or infinite reload
element.reload_counter -= 1; // 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);
} }
else if (times == 1) { });
// Run once with timeout },
element.run_once = true; calc_entropy: function (mystring) {
element.setTimeout = setTimeout; //calculate a simple entropy for a given string
element.timing = setTimeout(statement, timeout); 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;
} }
} else { if(inset != lastset) {
// run once (no timeout specified) score += 1;
element.reload_counter = Infinity; lastset = inset;
web2py_ajax_page('get', action, null, target); }
} }); } }
var entropy = mystring.length * Math.log(score) / 0.6931471805599453;
return Math.round(entropy * 100) / 100
},
validate_entropy: function (myfield, req_entropy) {
//added
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-ujs
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, name, data) {
var event = $.Event(name);
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';
// store enabled state
el.data('w2p:enable-with', el[method]);
/* little addition by default*/
if((el.data('w2p_disable_with') == 'default') || (el.data('w2p_disable_with') === undefined)) {
el.data('w2p_disable_with', 'Working...');
}
// set to disabled state
el[method](el.data('w2p_disable_with'));
function web2py_websocket(url,onmessage,onopen,onclose) { el.bind('click.w2pDisable', function (e) { // prevent further clicking
if ("WebSocket" in window) { return web2py.stopEverything(e);
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
}
// 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'); // clean up cache
}
el.removeClass('disabled');
el.unbind('click.w2pDisable'); // enable element
},
//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');
function web2py_calc_entropy(mystring) { var pre_call = el.data('w2p_pre_call');
//calculate a simple entropy for a given string if(pre_call != undefined) {
var csets = new Array( eval(pre_call);
'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', }
'0123456789', '!@#$\%^&*()', '~`-_=+[]{}\|;:\'",.<>?/', if(confirm_message != undefined) {
'0123456789abcdefghijklmnopqrstuvwxyz'); if(confirm_message == 'default') confirm_message = w2p_ajax_confirm_message || 'Are you sure you want to delete this object?';
var score = 0, other = {}, seen = {}, lastset = null, mystringlist = mystring.split(''); if(!web2py.confirm(confirm_message)) {
for (var i=0;i<mystringlist.length;i++) { // classify this character web2py.stopEverything(e);
var c = mystringlist[i], inset=5; return;
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(target == undefined) {
if(!(inset in seen)) {seen[inset] = 1;score += csets[inset].length;} if(method == 'GET') {
else if (!(c in other)) {score += 1;other[c] = 1;} web2py.simple_component(action, el.attr('id'), el); //not working with original
if (inset != lastset) {score += 1;lastset = inset;} } else if(method == 'POST') {
//should be web2py.ajax(action, [], ''); but it's too simple
web2py.ajax_page('post', action, [], 'bogus', el); //fixme?
}
} else {
if(method == 'GET') {
web2py.simple_component(action, target, el);
} else if(method == 'POST') {
//should be web2py.ajax(action, [], target); but it's too simple
web2py.ajax_page('post', action, [], target, el);
}
}
/*this should happen only on ajaxsuccess
* and should block subsequent clicks until ajaxcomplete
* NB: introduce the first incompatibility because normally
* the element would be removed in either case
/* removal code moved to the ajax:success event - START
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();
}
/* removal code moved to the ajax:success event - END */
},
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));
});
} }
var entropy = mystring.length*Math.log(score)/0.6931471805599453; }
return Math.round(entropy*100)/100
}
function web2py_validate_entropy(myfield, req_entropy) { //end of functions
var validator = function () { //main hook
var v = (web2py_calc_entropy(myfield.val())||0)/req_entropy; $(function () {
var r=0,g=0,b=0,rs=function(x){return Math.round(x*15).toString(16)}; var flash = $('.flash');
if(v<=0.5) {r=1.0; g=2.0*v;} flash.hide();
else {r=(1.0-2.0*(Math.max(v,0)-0.5)); g=1.0;} if(flash.html()) web2py.flash(flash.html());
var color = '#'+rs(r)+rs(g)+rs(b); web2py.ajax_init(document);
myfield.css('background-color',color); web2py.event_handlers();
entropy_callback = myfield.data('entropy_callback'); web2py.a_handlers();
if(entropy_callback) entropy_callback(v); web2py.form_handlers();
} });
if(!myfield.hasClass('entropy_check')) myfield.on('keyup', validator).on('keydown', validator).addClass('entropy_check');
}
function web2py_show_if(target) { })(jQuery);
var triggers = {};
var show_if = function () { /* compatibility code - start */
var t = jQuery(this); ajax = $.web2py.ajax;
var id = t.attr('id'); web2py_component = $.web2py.component;
t.attr('value', t.val()); web2py_websocket = $.web2py.websocket;
for(var k = 0; k < triggers[id].length; k++) { web2py_ajax_page = $.web2py.ajax_page;
var dep = jQuery('#' + triggers[id][k], target); //needed for IS_STRONG(entropy)
var tr = jQuery('#' + triggers[id][k] + '__row', target); web2py_validate_entropy = $.web2py.validate_entropy;
if(t.is(dep.attr('data-show-if'))) tr.slideDown(); //needed for crud.search and SQLFORM.grid's search
else tr.hide(); web2py_ajax_fields = $.web2py.ajax_fields;
} //used for LOAD(ajax=False)
}; web2py_trap_form = $.web2py.trap_form;
jQuery('[data-show-trigger]', target).each(function () {
var name = jQuery(this).attr('data-show-trigger'); /*undocumented - rare*/
if(!triggers[name]) triggers[name] = []; popup = $.web2py.popup;
triggers[name].push(jQuery(this).attr('id')); collapse = $.web2py.collapse;
}); fade = $.web2py.fade;
for(var name in triggers) {
jQuery('#' + name, target).change(show_if).keyup(show_if); /* internals - shouldn't be needed
show_if.call(jQuery('#' + name, target));
}; web2py_ajax_init = $.web2py.ajax_init;
} web2py_event_handlers = $.web2py.event_handlers;
web2py_trap_link = $.web2py.trap_link;
web2py_calc_entropy = $.web2py.calc_entropy;
*/
/* compatibility code - end*/
+637 -226
View File
@@ -1,242 +1,653 @@
function popup(url) { (function ($, undefined) {
newwindow=window.open(url,'name','height=400,width=600'); /*
if (window.focus) newwindow.focus(); * Unobtrusive scripting adapter for jQuery, largely taken from
return false; * the wonderful https://github.com/rails/jquery-ujs
} *
function collapse(id) { jQuery('#'+id).slideToggle(); } *
function fade(id,value) { if(value>0) jQuery('#'+id).hide().fadeIn('slow'); else jQuery('#'+id).show().fadeOut('slow'); } * Released under the MIT license
function ajax(u,s,t) { *
query = ''; */
if (typeof s == "string") {
d = jQuery(s).serialize(); String.prototype.reverse = function () {
if(d){ query = d; } return this.split('').reverse().join('');
} else { };
var web2py;
$.web2py = web2py = {
popup: function (url) {
newwindow = window.open(url, 'name', 'height=400,width=600');
if(window.focus) newwindow.focus();
return false;
},
collapse: function (id) {
$('#' + id).slideToggle();
},
fade: function (id, value) {
if(value > 0) $('#' + id).hide().fadeIn('slow');
else $('#' + id).show().fadeOut('slow');
},
ajax: function (u, s, t) {
query = '';
if(typeof s == "string") {
d = $(s).serialize();
if(d) {
query = d;
}
} else {
pcs = []; pcs = [];
if (s != null && s != undefined) for(i=0; i<s.length; i++) { if(s != null && s != undefined) for(i = 0; i < s.length; i++) {
q = jQuery("[name="+s[i]+"]").serialize(); q = $("[name=" + s[i] + "]").serialize();
if(q){pcs.push(q);} 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);
web2py_show_if(target);
};
function web2py_event_handlers() {
var doc = jQuery(document)
doc.on('click', '.flash', function(e){var t=jQuery(this); if(t.css('top')=='0px') t.slideUp('slow'); else t.fadeOut(); e.preventDefault();});
doc.on('keyup', 'input.integer', function(){this.value=this.value.reverse().replace(/[^0-9\-]|\-(?=.)/g,'').reverse();});
doc.on('keyup', 'input.double, input.decimal', function(){this.value=this.value.reverse().replace(/[^0-9\-\.,]|[\-](?=.)|[\.,](?=[0-9]*[\.,])/g,'').reverse();});
var confirm_message = (typeof w2p_ajax_confirm_message != 'undefined') ? w2p_ajax_confirm_message : "Are you sure you want to delete this object?";
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');
var command=xhr.getResponseHeader('web2py-component-command');
var flash=xhr.getResponseHeader('web2py-component-flash');
if (redirect !== null) {
window.location = redirect;
};
if(command !== null){
eval(decodeURIComponent(command));
}
if(flash) {
jQuery('.flash')
.html(decodeURIComponent(flash))
.append('<span id="closeflash">&times;</span>')
.slideDown();
}
});
doc.ajaxError(function(e, xhr, settings, exception) {
doc.off('click', '.flash')
switch(xhr.status){
case 500:
$('.flash').html(ajax_error_500).slideDown();
} }
}); $.ajax({
}; type: "POST",
url: u,
jQuery(function() { data: query,
var flash = jQuery('.flash'); success: function (msg) {
flash.hide(); if(t) {
if(flash.html()) flash.append('<span id="closeflash">&times;</span>').slideDown(); if(t == ':eval') eval(msg);
web2py_ajax_init(document); else if(typeof t == 'string') $("#" + t).html(msg);
web2py_event_handlers(); else t(msg);
}); }
}
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();
}); });
}); },
} ajax_fields: function (target) {
/*this attaches something to a newly loaded fragment/page
function web2py_trap_link(target) { * Ideally all events should be bound to the document, so we can avoid calling
jQuery('#'+target+' a.w2p_trap').each(function(i){ * this over and over... all will be bound to the document
var link=jQuery(this); */
link.click(function(e) { var date_format = (typeof w2p_ajax_date_format != 'undefined') ? w2p_ajax_date_format : "%Y-%m-%d";
jQuery('.flash').hide().html(''); var datetime_format = (typeof w2p_ajax_datetime_format != 'undefined') ? w2p_ajax_datetime_format : "%Y-%m-%d %H:%M:%S";
web2py_ajax_page('get',link.attr('href'),[],target); $("input.date", target).each(function () {
e.preventDefault(); Calendar.setup({
}); inputField: this,
ifFormat: date_format,
showsTime: false
}); });
} });
$("input.datetime", target).each(function () {
Calendar.setup({
inputField: this,
ifFormat: datetime_format,
showsTime: true,
timeFormat: "24"
});
});
$("input.time", target).each(function () {
$(this).timeEntry();
});
/*adds btn class to buttons*/
$('button', target).addClass('btn');
$('form input[type="submit"], form input[type="button"]', target).addClass('btn');
/*no more inline javascript for PasswordWidget*/
$('input[type=password][data-w2p_entropy]', target).each(function () {
web2py.validate_entropy($(this));
});
/*no more inline 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 web2py_ajax_page(method, action, data, target) { function rl(ul, e) {
jQuery.ajax({'type':method, 'url':action, 'data':data, if($(ul).children().length > 1) {
'beforeSend':function(xhr) { //only remove if we have more than 1 item so the list is never empty
xhr.setRequestHeader('web2py-component-location', document.location); $(e.target).parent().remove();
xhr.setRequestHeader('web2py-component-element', target);}, }
'complete':function(xhr,text){ }
var html=xhr.responseText;
var content=xhr.getResponseHeader('web2py-component-content');
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);
}
});
}
function web2py_component(action, target, timeout, times){ function ml(ul) {
jQuery(function(){ var line = $(ul).find("li:first").clone(true);
var jelement = jQuery("#" + target); line.find(':text').val('');
var element = jelement.get(0); return line;
var statement = "jQuery('#" + target + "').get(0).reload();"; }
jelement.reload = function (){
// Continue if times is Infinity or function rel(ul) {
// the times limit is not reached $(ul).find("li").each(function () {
if (element.reload_check()){ var trimmed = $.trim($(this.firstChild).val());
web2py_ajax_page('get', action, null, target);} }; // reload if(trimmed == '') $(this).remove();
// Method to check timing limit else $(this.firstChild).val(trimmed);
element.reload_check = function (){ });
if (jelement.hasClass('w2p_component_stop')) {clearInterval(this.timing);return false;} }
if (this.reload_counter == Infinity){return true;} var ul = this;
else { $(ul).find(":text").after('<a href="#">+</a>&nbsp;<a href="#">-</a>').keypress(function (e) {
if (!isNaN(this.reload_counter)){ return(e.which == 13) ? pe(ul, e) : true;
this.reload_counter -= 1; }).next().click(function (e) {
if (this.reload_counter < 0){ pe(ul, e);
if (!this.run_once){ e.preventDefault();
clearInterval(this.timing); }).next().click(function (e) {
return false; rl(ul, e);
} e.preventDefault();
});
});
},
ajax_init: function (target) {
$('.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');
//$('.error', target).hide().fadeIn('slow');
},
event_handlers: function () {
/* This is called once for page
* Ideally it should bound all the things that are needed
*/
var doc = $(document);
doc.on('click', '.flash', function (e) {
var t = $(this);
if(t.css('top') == '0px') t.slideUp('slow');
else t.fadeOut();
//if I want to display a clickable something
//inside flash, I should not be prevented to follow it
//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(!web2py.confirm(confirm_message)) this.checked = false;
});
doc.ajaxSuccess(function (e, xhr) {
var redirect = xhr.getResponseHeader('web2py-redirect-location');
var command = xhr.getResponseHeader('web2py-component-command');
var flash = xhr.getResponseHeader('web2py-component-flash');
if(redirect !== null) {
window.location = redirect;
};
if(command !== null) {
eval(decodeURIComponent(command));
}
if(flash) {
web2py.flash(decodeURIComponent(flash))
}
});
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) {
$('#' + 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.find('input[type=submit]').attr('data-w2p_disable_with', 'Working...');
form.submit(function (e) {
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(web2py.fire(element, 'ajax:before')) { //test a usecase, should stop here if returns false
$.ajax({
'type': method,
'url': action,
'data': data,
'beforeSend': function (xhr, settings) {
//added
xhr.setRequestHeader('web2py-component-location', document.location);
xhr.setRequestHeader('web2py-component-element', target);
return web2py.fire(element, 'ajax:beforeSend', [xhr, settings]); //test a usecase, should stop here if returns false
},
//added
'success': function (data, status, xhr) {
//bummer for form submissions....the element is not there after complete
//because it gets replaced by the new response....
element.trigger('ajax:success', [data, status, xhr]);
},
//added
'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)
element.trigger('ajax:error', [xhr, status, error]);
},
'complete': function (xhr, status) {
element.trigger('ajax:complete', [xhr, status]);
var html = xhr.responseText;
var content = xhr.getResponseHeader('web2py-component-content');
var t = $('#' + 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);
}
});
}
},
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);
}
}; // reload
// 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;} } else {
} } return true;
return false;}; // reload check }
if (!isNaN(timeout)){ }
element.timeout = timeout; }
element.reload_counter = times; return false;
if (times > 1){ }; // reload check
// Multiple or infinite reload if(!isNaN(timeout)) {
// Run first iteration element.timeout = timeout;
web2py_ajax_page('get', action, null, target); element.reload_counter = times;
element.run_once = false; if(times > 1) {
element.timing = setInterval(statement, timeout); // Multiple or infinite reload
element.reload_counter -= 1; // 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);
} }
else if (times == 1) { });
// Run once with timeout },
element.run_once = true; calc_entropy: function (mystring) {
element.setTimeout = setTimeout; //calculate a simple entropy for a given string
element.timing = setTimeout(statement, timeout); 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;
} }
} else { if(inset != lastset) {
// run once (no timeout specified) score += 1;
element.reload_counter = Infinity; lastset = inset;
web2py_ajax_page('get', action, null, target); }
} }); } }
var entropy = mystring.length * Math.log(score) / 0.6931471805599453;
return Math.round(entropy * 100) / 100
},
validate_entropy: function (myfield, req_entropy) {
//added
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-ujs
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, name, data) {
var event = $.Event(name);
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';
// store enabled state
el.data('w2p:enable-with', el[method]);
/* little addition by default*/
if((el.data('w2p_disable_with') == 'default') || (el.data('w2p_disable_with') === undefined)) {
el.data('w2p_disable_with', 'Working...');
}
// set to disabled state
el[method](el.data('w2p_disable_with'));
function web2py_websocket(url,onmessage,onopen,onclose) { el.bind('click.w2pDisable', function (e) { // prevent further clicking
if ("WebSocket" in window) { return web2py.stopEverything(e);
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
}
// 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'); // clean up cache
}
el.removeClass('disabled');
el.unbind('click.w2pDisable'); // enable element
},
//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');
function web2py_calc_entropy(mystring) { var pre_call = el.data('w2p_pre_call');
//calculate a simple entropy for a given string if(pre_call != undefined) {
var csets = new Array( eval(pre_call);
'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', }
'0123456789', '!@#$\%^&*()', '~`-_=+[]{}\|;:\'",.<>?/', if(confirm_message != undefined) {
'0123456789abcdefghijklmnopqrstuvwxyz'); if(confirm_message == 'default') confirm_message = w2p_ajax_confirm_message || 'Are you sure you want to delete this object?';
var score = 0, other = {}, seen = {}, lastset = null, mystringlist = mystring.split(''); if(!web2py.confirm(confirm_message)) {
for (var i=0;i<mystringlist.length;i++) { // classify this character web2py.stopEverything(e);
var c = mystringlist[i], inset=5; return;
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(target == undefined) {
if(!(inset in seen)) {seen[inset] = 1;score += csets[inset].length;} if(method == 'GET') {
else if (!(c in other)) {score += 1;other[c] = 1;} web2py.simple_component(action, el.attr('id'), el); //not working with original
if (inset != lastset) {score += 1;lastset = inset;} } else if(method == 'POST') {
//should be web2py.ajax(action, [], ''); but it's too simple
web2py.ajax_page('post', action, [], 'bogus', el); //fixme?
}
} else {
if(method == 'GET') {
web2py.simple_component(action, target, el);
} else if(method == 'POST') {
//should be web2py.ajax(action, [], target); but it's too simple
web2py.ajax_page('post', action, [], target, el);
}
}
/*this should happen only on ajaxsuccess
* and should block subsequent clicks until ajaxcomplete
* NB: introduce the first incompatibility because normally
* the element would be removed in either case
/* removal code moved to the ajax:success event - START
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();
}
/* removal code moved to the ajax:success event - END */
},
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));
});
} }
var entropy = mystring.length*Math.log(score)/0.6931471805599453; }
return Math.round(entropy*100)/100
}
function web2py_validate_entropy(myfield, req_entropy) { //end of functions
var validator = function () { //main hook
var v = (web2py_calc_entropy(myfield.val())||0)/req_entropy; $(function () {
var r=0,g=0,b=0,rs=function(x){return Math.round(x*15).toString(16)}; var flash = $('.flash');
if(v<=0.5) {r=1.0; g=2.0*v;} flash.hide();
else {r=(1.0-2.0*(Math.max(v,0)-0.5)); g=1.0;} if(flash.html()) web2py.flash(flash.html());
var color = '#'+rs(r)+rs(g)+rs(b); web2py.ajax_init(document);
myfield.css('background-color',color); web2py.event_handlers();
entropy_callback = myfield.data('entropy_callback'); web2py.a_handlers();
if(entropy_callback) entropy_callback(v); web2py.form_handlers();
} });
if(!myfield.hasClass('entropy_check')) myfield.on('keyup', validator).on('keydown', validator).addClass('entropy_check');
}
function web2py_show_if(target) { })(jQuery);
var triggers = {};
var show_if = function () { /* compatibility code - start */
var t = jQuery(this); ajax = $.web2py.ajax;
var id = t.attr('id'); web2py_component = $.web2py.component;
t.attr('value', t.val()); web2py_websocket = $.web2py.websocket;
for(var k = 0; k < triggers[id].length; k++) { web2py_ajax_page = $.web2py.ajax_page;
var dep = jQuery('#' + triggers[id][k], target); //needed for IS_STRONG(entropy)
var tr = jQuery('#' + triggers[id][k] + '__row', target); web2py_validate_entropy = $.web2py.validate_entropy;
if(t.is(dep.attr('data-show-if'))) tr.slideDown(); //needed for crud.search and SQLFORM.grid's search
else tr.hide(); web2py_ajax_fields = $.web2py.ajax_fields;
} //used for LOAD(ajax=False)
}; web2py_trap_form = $.web2py.trap_form;
jQuery('[data-show-trigger]', target).each(function () {
var name = jQuery(this).attr('data-show-trigger'); /*undocumented - rare*/
if(!triggers[name]) triggers[name] = []; popup = $.web2py.popup;
triggers[name].push(jQuery(this).attr('id')); collapse = $.web2py.collapse;
}); fade = $.web2py.fade;
for(var name in triggers) {
jQuery('#' + name, target).change(show_if).keyup(show_if); /* internals - shouldn't be needed
show_if.call(jQuery('#' + name, target));
}; web2py_ajax_init = $.web2py.ajax_init;
} web2py_event_handlers = $.web2py.event_handlers;
web2py_trap_link = $.web2py.trap_link;
web2py_calc_entropy = $.web2py.calc_entropy;
*/
/* compatibility code - end*/
+10 -10
View File
@@ -167,15 +167,15 @@ def LOAD(c=None, f='index', args=None, vars=None,
elif timeout <= 0: elif timeout <= 0:
raise ValueError( raise ValueError(
"Timeout argument must be greater than zero or None") "Timeout argument must be greater than zero or None")
statement = "web2py_component('%s','%s', %s, %s);" \ statement = "$.web2py.component('%s','%s', %s, %s);" \
% (url, target, timeout, times) % (url, target, timeout, times)
attr['_data-w2p_timeout'] = timeout
attr['_data-w2p_times'] = times
else: else:
statement = "web2py_component('%s','%s');" % (url, target) statement = "$.web2py.component('%s','%s');" % (url, target)
script = SCRIPT(statement, _type="text/javascript") attr['_data-w2p_remote'] = url
if not content is None: if not target is None:
return TAG[''](script, DIV(content, **attr)) return DIV(content, **attr)
else:
return TAG[''](script)
else: else:
if not isinstance(args, (list, tuple)): if not isinstance(args, (list, tuple)):
@@ -226,7 +226,7 @@ def LOAD(c=None, f='index', args=None, vars=None,
link = URL(request.application, c, f, r=request, link = URL(request.application, c, f, r=request,
args=args, vars=vars, extension=extension, args=args, vars=vars, extension=extension,
user_signature=user_signature) user_signature=user_signature)
js = "web2py_trap_form('%s','%s');" % (link, target) js = "$.web2py.trap_form('%s','%s');" % (link, target)
script = js and SCRIPT(js, _type="text/javascript") or '' script = js and SCRIPT(js, _type="text/javascript") or ''
return TAG[''](DIV(XML(page), **attr), script) return TAG[''](DIV(XML(page), **attr), script)
@@ -254,7 +254,7 @@ class LoadFactory(object):
url = url or html.URL(request.application, c, f, r=request, url = url or html.URL(request.application, c, f, r=request,
args=args, vars=vars, extension=extension, args=args, vars=vars, extension=extension,
user_signature=user_signature) user_signature=user_signature)
script = html.SCRIPT('web2py_component("%s","%s")' % (url, target), script = html.SCRIPT('$.web2py.component("%s","%s")' % (url, target),
_type="text/javascript") _type="text/javascript")
return html.TAG[''](script, html.DIV(content, **attr)) return html.TAG[''](script, html.DIV(content, **attr))
else: else:
@@ -305,7 +305,7 @@ class LoadFactory(object):
link = html.URL(request.application, c, f, r=request, link = html.URL(request.application, c, f, r=request,
args=args, vars=vars, extension=extension, args=args, vars=vars, extension=extension,
user_signature=user_signature) user_signature=user_signature)
js = "web2py_trap_form('%s','%s');" % (link, target) js = "$.web2py.trap_form('%s','%s');" % (link, target)
script = js and html.SCRIPT(js, _type="text/javascript") or '' script = js and html.SCRIPT(js, _type="text/javascript") or ''
return html.TAG[''](html.DIV(html.XML(page), **attr), script) return html.TAG[''](html.DIV(html.XML(page), **attr), script)
+45 -50
View File
@@ -594,9 +594,9 @@ class ConnectionPool(object):
if f is None: if f is None:
f = self.connector f = self.connector
if not hasattr(self, "driver") or self.driver is None: # if not hasattr(self, "driver") or self.driver is None:
LOGGER.debug("Skipping connection since there's no driver") # LOGGER.debug("Skipping connection since there's no driver")
return # return
if not self.pool_size: if not self.pool_size:
self.connection = f() self.connection = f()
@@ -644,6 +644,8 @@ class BaseAdapter(ConnectionPool):
TRUE = 'T' TRUE = 'T'
FALSE = 'F' FALSE = 'F'
T_SEP = ' ' T_SEP = ' '
QUOTE_TEMPLATE = '"%s"'
types = { types = {
'boolean': 'CHAR(1)', 'boolean': 'CHAR(1)',
'string': 'CHAR(%(length)s)', 'string': 'CHAR(%(length)s)',
@@ -1067,12 +1069,13 @@ class BaseAdapter(ConnectionPool):
drop_expr = 'ALTER TABLE %s DROP %s;' drop_expr = 'ALTER TABLE %s DROP %s;'
else: else:
drop_expr = 'ALTER TABLE %s DROP COLUMN %s;' drop_expr = 'ALTER TABLE %s DROP COLUMN %s;'
query = ['ALTER TABLE %s ADD %s__tmp %s;' % (t, key, tt), key_tmp = key + '__tmp'
'UPDATE %s SET %s__tmp=%s;' % (t, key, key), query = ['ALTER TABLE %s ADD %s %s;' % (t, key_tmp, tt),
'UPDATE %s SET %s=%s;' % (t, key_tmp, key),
drop_expr % (t, key), drop_expr % (t, key),
'ALTER TABLE %s ADD %s %s;' % (t, key, tt), 'ALTER TABLE %s ADD %s %s;' % (t, key, tt),
'UPDATE %s SET %s=%s__tmp;' % (t, key, key), 'UPDATE %s SET %s=%s;' % (t, key, key_tmp),
drop_expr % (t, key)] drop_expr % (t, key_tmp)]
metadata_change = True metadata_change = True
elif sql_fields[key]['type'] != sql_fields_old[key]['type']: elif sql_fields[key]['type'] != sql_fields_old[key]['type']:
sql_fields_current[key] = sql_fields[key] sql_fields_current[key] = sql_fields[key]
@@ -1361,7 +1364,7 @@ class BaseAdapter(ConnectionPool):
def expand(self, expression, field_type=None): def expand(self, expression, field_type=None):
if isinstance(expression, Field): if isinstance(expression, Field):
out = '%s.%s' % (expression.tablename, expression.name) out = '%s.%s' % (expression.table, expression.name)
if field_type == 'string' and not expression.type in ( if field_type == 'string' and not expression.type in (
'string','text','json','password'): 'string','text','json','password'):
out = 'CAST(%s AS %s)' % (out, self.types['text']) out = 'CAST(%s AS %s)' % (out, self.types['text'])
@@ -1448,6 +1451,7 @@ class BaseAdapter(ConnectionPool):
sql_v = ','.join(['%s=%s' % (field.name, sql_v = ','.join(['%s=%s' % (field.name,
self.expand(value, field.type)) \ self.expand(value, field.type)) \
for (field, value) in fields]) for (field, value) in fields])
tablename = "%s" % self.db[tablename]
return 'UPDATE %s SET %s%s;' % (tablename, sql_v, sql_w) return 'UPDATE %s SET %s%s;' % (tablename, sql_v, sql_w)
def update(self, tablename, query, fields): def update(self, tablename, query, fields):
@@ -2433,6 +2437,8 @@ class MySQLAdapter(BaseAdapter):
'big-reference': 'BIGINT, INDEX %(index_name)s (%(field_name)s), FOREIGN KEY (%(field_name)s) REFERENCES %(foreign_key)s ON DELETE %(on_delete_action)s', 'big-reference': 'BIGINT, INDEX %(index_name)s (%(field_name)s), FOREIGN KEY (%(field_name)s) REFERENCES %(foreign_key)s ON DELETE %(on_delete_action)s',
} }
QUOTE_TEMPLATE = "`%s`"
def varquote(self,name): def varquote(self,name):
return varquote_aux(name,'`%s`') return varquote_aux(name,'`%s`')
@@ -3082,6 +3088,8 @@ class MSSQLAdapter(BaseAdapter):
drivers = ('pyodbc',) drivers = ('pyodbc',)
T_SEP = 'T' T_SEP = 'T'
QUOTE_TEMPLATE = "[%s]"
types = { types = {
'boolean': 'BIT', 'boolean': 'BIT',
'string': 'VARCHAR(%(length)s)', 'string': 'VARCHAR(%(length)s)',
@@ -6857,23 +6865,24 @@ class Row(object):
this is only used to store a Row this is only used to store a Row
""" """
def __init__(self,*args,**kwargs): __init__ = lambda self,*args,**kwargs: self.__dict__.update(*args,**kwargs)
self.__dict__.update(*args,**kwargs)
def __getitem__(self, key): def __getitem__(self, k):
key=str(key) key=str(k)
_extra = getattr(self, '_extra', None)
if _extra:
return _extra.get(key)
if v:
return v
m = REGEX_TABLE_DOT_FIELD.match(key) m = REGEX_TABLE_DOT_FIELD.match(key)
if key in self.get('_extra',{}): if m:
return self._extra[key]
elif m:
try: try:
return ogetattr(self, m.group(1))[m.group(2)] return ogetattr(self, m.group(1))[m.group(2)]
except (KeyError,AttributeError,TypeError): except (KeyError,AttributeError,TypeError):
key = m.group(2) key = m.group(2)
return ogetattr(self, key) return ogetattr(self, key)
def __setitem__(self, key, value): __setitem__ = lambda self, key, value: setattr(self, str(key), value)
setattr(self, str(key), value)
__delitem__ = object.__delattr__ __delitem__ = object.__delattr__
@@ -6881,47 +6890,31 @@ class Row(object):
__call__ = __getitem__ __call__ = __getitem__
def get(self,key,default=None): get = lambda self, key, default=None: self.__dict__.get(key,default)
return self.__dict__.get(key,default)
def __contains__(self,key):
return key in self.__dict__
has_key = __contains__ has_key = __contains__ = lambda self, key: key in self.__dict__
def __nonzero__(self): __nonzero__ = lambda self: len(self.__dict__)>0
return len(self.__dict__)>0
def update(self, *args, **kwargs): update = lambda self, *args, **kwargs: self.__dict__.update(*args, **kwargs)
self.__dict__.update(*args, **kwargs)
def keys(self): keys = lambda self: self.__dict__.keys()
return self.__dict__.keys()
def items(self): items = lambda self: self.__dict__.items()
return self.__dict__.items()
def values(self): values = lambda self: self.__dict__.values()
return self.__dict__.values()
def __iter__(self): __iter__ = lambda self: self.__dict__.__iter__()
return self.__dict__.__iter__()
def iteritems(self): iteritems = lambda self: self.__dict__.iteritems()
return self.__dict__.iteritems()
def __str__(self): __str__ = __repr__ = lambda self: '<Row %s>' % self.as_dict()
### this could be made smarter
return '<Row %s>' % self.as_dict()
def __repr__(self): __int__ = lambda self: object.__getattribute__(self,'id')
return '<Row %s>' % self.as_dict()
def __int__(self): __long__ = lambda self: long(object.__getattribute__(self,'id'))
return object.__getattribute__(self,'id')
def __long__(self):
return long(object.__getattribute__(self,'id'))
def __eq__(self,other): def __eq__(self,other):
try: try:
@@ -8492,9 +8485,10 @@ class Table(object):
def __str__(self): def __str__(self):
if self._ot is not None: if self._ot is not None:
if 'Oracle' in str(type(self._db._adapter)): # <<< patch return self._db._adapter.QUOTE_TEMPLATE % self._ot
return '%s %s' % (self._ot, self._tablename) # <<< patch #if 'Oracle' in str(type(self._db._adapter)): # <<< patch
return '%s AS %s' % (self._ot, self._tablename) # return '%s %s' % (self._ot, self._tablename) # <<< patch
#return '%s AS %s' % (self._ot, self._tablename)
return self._tablename return self._tablename
def _drop(self, mode = ''): def _drop(self, mode = ''):
@@ -9959,7 +9953,7 @@ class Set(object):
fields = table._listify(update_fields,update=True) fields = table._listify(update_fields,update=True)
if not fields: if not fields:
raise SyntaxError("No fields to update") raise SyntaxError("No fields to update")
ret = db._adapter.update(tablename,self.query,fields) ret = db._adapter.update("%s" % table,self.query,fields)
ret and [f(self,update_fields) for f in table._after_update] ret and [f(self,update_fields) for f in table._after_update]
return ret return ret
@@ -9971,7 +9965,8 @@ class Set(object):
table = self.db[tablename] table = self.db[tablename]
fields = table._listify(update_fields,update=True) fields = table._listify(update_fields,update=True)
if not fields: raise SyntaxError("No fields to update") if not fields: raise SyntaxError("No fields to update")
ret = self.db._adapter.update(tablename,self.query,fields)
ret = self.db._adapter.update("%s" % table,self.query,fields)
return ret return ret
def validate_and_update(self, **update_fields): def validate_and_update(self, **update_fields):
-1
View File
@@ -83,7 +83,6 @@ class Request(Storage):
def __init__(self): def __init__(self):
Storage.__init__(self) Storage.__init__(self)
self.wsgi = Storage() # hooks to environ and start_response
self.env = Storage() self.env = Storage()
self.cookies = Cookie.SimpleCookie() self.cookies = Cookie.SimpleCookie()
self.get_vars = Storage() self.get_vars = Storage()
+19 -19
View File
@@ -1479,30 +1479,30 @@ class A(DIV):
def xml(self): def xml(self):
if not self.components and self['_href']: if not self.components and self['_href']:
self.append(self['_href']) self.append(self['_href'])
if not self['_disable_with']:
self['_data-w2p_disable_with'] = 'default'
if self['delete']: if self['delete']:
d = "jQuery(this).closest('%s').remove();" % self['delete'] self['_data-w2p_remove'] = self['delete']
else: if self['target']:
d = '' self['_data-w2p_target'] = self['target']
if self['component']: if self['component']:
self['_onclick'] = "web2py_component('%s','%s');%sreturn false;" % \ self['_data-w2p_method'] = 'GET'
(self['component'], self['target'] or '', d) self['_href'] = self['component']
self['_href'] = self['_href'] or '#null'
elif self['callback']: elif self['callback']:
returnfalse = "var e = arguments[0] || window.event; e.cancelBubble=true; if (e.stopPropagation) {e.stopPropagation(); e.stopImmediatePropagation(); e.preventDefault();}" self['_data-w2p_method'] = 'POST'
if d and not self['noconfirm']: self['_href'] = self['callback']
self['_onclick'] = "if(confirm(w2p_ajax_confirm_message||'Are you sure you want to delete this object?')){ajax('%s',[],'%s');%s};%s" % \ if self['delete'] and not self['noconfirm']:
(self['callback'], self['target'] or '', d, returnfalse) if not self['confirm']:
else: self['_data-w2p_confirm'] = 'default'
self['_onclick'] = "ajax('%s',[],'%s');%sreturn false" % \ else:
(self['callback'], self['target'] or '', d) self['_data-w2p_confirm'] = self['confirm']
self['_href'] = self['_href'] or '#null'
elif self['cid']: elif self['cid']:
pre = self['pre_call'] + ';' if self['pre_call'] else '' self['_data-w2p_method'] = 'GET'
self['_onclick'] = '%sweb2py_component("%s","%s");%sreturn false;' % \ self['_data-w2p_target'] = self['cid']
(pre,self['_href'], self['cid'], d) if self['pre_call']:
self['_data-w2p_pre_call'] = self['pre_call']
return DIV.xml(self) return DIV.xml(self)
class BUTTON(DIV): class BUTTON(DIV):
tag = 'button' tag = 'button'
@@ -2481,7 +2481,7 @@ def test():
>>> from validators import * >>> from validators import *
>>> print DIV(A('click me', _href=URL(a='a', c='b', f='c')), BR(), HR(), DIV(SPAN(\"World\"), _class='unknown')).xml() >>> print DIV(A('click me', _href=URL(a='a', c='b', f='c')), BR(), HR(), DIV(SPAN(\"World\"), _class='unknown')).xml()
<div><a href=\"/a/b/c\">click me</a><br /><hr /><div class=\"unknown\"><span>World</span></div></div> <div><a data-w2p_disable_with="default" href="/a/b/c">click me</a><br /><hr /><div class=\"unknown\"><span>World</span></div></div>
>>> print DIV(UL(\"doc\",\"cat\",\"mouse\")).xml() >>> print DIV(UL(\"doc\",\"cat\",\"mouse\")).xml()
<div><ul><li>doc</li><li>cat</li><li>mouse</li></ul></div> <div><ul><li>doc</li><li>cat</li><li>mouse</li></ul></div>
>>> print DIV(UL(\"doc\", LI(\"cat\", _class='feline'), 18)).xml() >>> print DIV(UL(\"doc\", LI(\"cat\", _class='feline'), 18)).xml()
+49 -50
View File
@@ -257,51 +257,55 @@ def serve_controller(request, response, session):
raise HTTP(response.status, page, **response.headers) raise HTTP(response.status, page, **response.headers)
def start_response_aux(status, headers, exc_info, response=None): class LazyWSGI(object):
""" def __init__(self, environ, request, response):
in controller you can use:: self.wsgi_environ = environ
self.request = request
self.response = response
@property
def environ(self):
if not hasattr(self,'_environ'):
new_environ = self.wsgi_environ
new_environ['wsgi.input'] = self.request.body
new_environ['wsgi.version'] = 1
self._environ = new_environ
return self._environ
def start_response(self,status='200', headers=[], exec_info=None):
"""
in controller you can use::
- request.wsgi.environ - request.wsgi.environ
- request.wsgi.start_response - request.wsgi.start_response
to call third party WSGI applications to call third party WSGI applications
""" """
response.status = str(status).split(' ', 1)[0] self.response.status = str(status).split(' ', 1)[0]
response.headers = dict(headers) self.response.headers = dict(headers)
return lambda *args, **kargs: response.write(escape=False, *args, **kargs) return lambda *args, **kargs: \
self.response.write(escape=False, *args, **kargs)
def middleware(self,*a):
def middleware_aux(request, response, *middleware_apps): """
""" In you controller use::
In you controller use::
@request.wsgi.middleware(middleware1, middleware2, ...) @request.wsgi.middleware(middleware1, middleware2, ...)
to decorate actions with WSGI middleware. actions must return strings. to decorate actions with WSGI middleware. actions must return strings.
uses a simulated environment so it may have weird behavior in some cases uses a simulated environment so it may have weird behavior in some cases
""" """
def middleware(f): def middleware(f):
def app(environ, start_response): def app(environ, start_response):
data = f() data = f()
start_response(response.status, response.headers.items()) start_response(self.response.status,
if isinstance(data, list): self.response.headers.items())
return data if isinstance(data, list):
return [data] return data
for item in middleware_apps: return [data]
app = item(app) for item in middleware_apps:
app = item(app)
def caller(app): def caller(app):
wsgi = request.wsgi return app(self.environ, self.start_response)
return app(wsgi.environ, wsgi.start_response) return lambda caller=caller, app=app: caller(app)
return lambda caller=caller, app=app: caller(app) return middleware
return middleware
def environ_aux(environ, request):
new_environ = copy.copy(environ)
new_environ['wsgi.input'] = request.body
new_environ['wsgi.version'] = 1
return new_environ
ISLE25 = sys.version_info[1] <= 5 ISLE25 = sys.version_info[1] <= 5
@@ -339,8 +343,9 @@ def parse_get_post_vars(request, environ):
json_vars = {} json_vars = {}
pass pass
# update vars and get_vars with what was posted as json # update vars and get_vars with what was posted as json
request.get_vars.update(json_vars) if isinstance(json_vars,dict):
request.vars.update(json_vars) request.get_vars.update(json_vars)
request.vars.update(json_vars)
# parse POST variables on POST, PUT, BOTH only in post_vars # parse POST variables on POST, PUT, BOTH only in post_vars
@@ -386,7 +391,7 @@ def parse_get_post_vars(request, environ):
if len(pvalue): if len(pvalue):
request.post_vars[key] = (len(pvalue) > request.post_vars[key] = (len(pvalue) >
1 and pvalue) or pvalue[0] 1 and pvalue) or pvalue[0]
if is_json: if is_json and isinstance(json_vars,dict):
# update post_vars with what was posted as json # update post_vars with what was posted as json
request.post_vars.update(json_vars) request.post_vars.update(json_vars)
@@ -536,13 +541,7 @@ def wsgibase(environ, responder):
# expose wsgi hooks for convenience # expose wsgi hooks for convenience
# ################################################## # ##################################################
request.wsgi.environ = environ_aux(environ, request) request.wsgi = LazyWSGI(environ, request, response)
request.wsgi.start_response = \
lambda status='200', headers=[], \
exec_info=None, response=response: \
start_response_aux(status, headers, exec_info, response)
request.wsgi.middleware = \
lambda *a: middleware_aux(request, response, *a)
# ################################################## # ##################################################
# load cookies # load cookies
+2
View File
@@ -638,6 +638,8 @@ def regex_url_in(request, environ):
if match.group('c') == 'static': if match.group('c') == 'static':
application = match.group('a') application = match.group('a')
version, filename = None, match.group('z') version, filename = None, match.group('z')
if not filename:
raise HTTP(404)
items = filename.split('/', 1) items = filename.split('/', 1)
if regex_version.match(items[0]): if regex_version.match(items[0]):
version, filename = items version, filename = items
+3 -2
View File
@@ -480,7 +480,8 @@ class Scheduler(MetaScheduler):
Field('function_name', Field('function_name',
requires=IS_IN_SET(sorted(self.tasks.keys())) requires=IS_IN_SET(sorted(self.tasks.keys()))
if self.tasks else DEFAULT), if self.tasks else DEFAULT),
Field('uuid', requires=IS_NOT_IN_DB(db, 'scheduler_task.uuid'), Field('uuid', length=255,
requires=IS_NOT_IN_DB(db, 'scheduler_task.uuid'),
unique=True, default=web2py_uuid), unique=True, default=web2py_uuid),
Field('args', 'text', default='[]', requires=TYPE(list)), Field('args', 'text', default='[]', requires=TYPE(list)),
Field('vars', 'text', default='{}', requires=TYPE(dict)), Field('vars', 'text', default='{}', requires=TYPE(dict)),
@@ -521,7 +522,7 @@ class Scheduler(MetaScheduler):
db.define_table( db.define_table(
'scheduler_worker', 'scheduler_worker',
Field('worker_name', unique=True), Field('worker_name', length=255, unique=True),
Field('first_heartbeat', 'datetime'), Field('first_heartbeat', 'datetime'),
Field('last_heartbeat', 'datetime'), Field('last_heartbeat', 'datetime'),
Field('status', requires=IS_IN_SET(WORKER_STATUS)), Field('status', requires=IS_IN_SET(WORKER_STATUS)),
+5 -50
View File
@@ -295,57 +295,15 @@ class ListWidget(StringWidget):
_class = 'string' _class = 'string'
requires = field.requires if isinstance( requires = field.requires if isinstance(
field.requires, (IS_NOT_EMPTY, IS_LIST_OF)) else None field.requires, (IS_NOT_EMPTY, IS_LIST_OF)) else None
attributes['_style'] = 'list-style:none'
nvalue = value or [''] nvalue = value or ['']
items = [LI(INPUT(_id=_id, _class=_class, _name=_name, items = [LI(INPUT(_id=_id, _class=_class, _name=_name,
value=v, hideerror=k < len(nvalue) - 1, value=v, hideerror=k < len(nvalue) - 1,
requires=requires), requires=requires),
**attributes) for (k, v) in enumerate(nvalue)] **attributes) for (k, v) in enumerate(nvalue)]
script = SCRIPT("""
// from http://refactormycode.com/codes/694-expanding-input-list-using-jquery
(function(){
jQuery.fn.grow_input = function() {
return this.each(function() {
var ul = this;
jQuery(ul).find(":text").after('<a href="javascript:void(0)">+</a>&nbsp;<a href="javascript:void(0)">-</a>').keypress(function (e) { return (e.which == 13) ? pe(ul, e) : true; }).next().click(function(e){ pe(ul, e) }).next().click(function(e){ rl(ul, e)});
});
};
function pe(ul, e) {
var new_line = ml(ul);
rel(ul);
if (jQuery(e.target).parent().is(':visible')) {
//make sure we didn't delete the element before we insert after
new_line.insertAfter(jQuery(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 (jQuery(ul).children().length > 1) {
//only remove if we have more than 1 item so the list is never empty
jQuery(e.target).parent().remove();
}
}
function ml(ul) {
var line = jQuery(ul).find("li:first").clone(true);
line.find(':text').val('');
return line;
}
function rel(ul) {
jQuery(ul).find("li").each(function() {
var trimmed = jQuery.trim(jQuery(this.firstChild).val());
if (trimmed=='') jQuery(this).remove(); else jQuery(this.firstChild).val(trimmed);
});
}
})();
jQuery(document).ready(function(){jQuery('#%s_grow_input').grow_input();});
""" % _id)
attributes['_id'] = _id + '_grow_input' attributes['_id'] = _id + '_grow_input'
attributes['_style'] = 'list-style:none' attributes['_style'] = 'list-style:none'
return TAG[''](UL(*items, **attributes), script) attributes['_class'] = 'w2p_list'
return TAG[''](UL(*items, **attributes))
class MultipleOptionsWidget(OptionsWidget): class MultipleOptionsWidget(OptionsWidget):
@@ -521,7 +479,6 @@ class PasswordWidget(FormWidget):
_value=(value and cls.DEFAULT_PASSWORD_DISPLAY) or '', _value=(value and cls.DEFAULT_PASSWORD_DISPLAY) or '',
) )
attr = cls._attributes(field, default, **attributes) attr = cls._attributes(field, default, **attributes)
output = CAT(INPUT(**attr))
# deal with entropy check! # deal with entropy check!
requires = field.requires requires = field.requires
@@ -529,10 +486,9 @@ class PasswordWidget(FormWidget):
requires = [requires] requires = [requires]
is_strong = [r for r in requires if isinstance(r, IS_STRONG)] is_strong = [r for r in requires if isinstance(r, IS_STRONG)]
if is_strong: if is_strong:
output.append(SCRIPT("web2py_validate_entropy(jQuery('#%s'),%s);" % ( attr['_data-w2p_entropy'] = is_strong[0].entropy if is_strong[0].entropy else "null"
attr['_id'], is_strong[0].entropy
if is_strong[0].entropy else "null")))
# end entropy check # end entropy check
output = INPUT(**attr)
return output return output
@@ -2615,7 +2571,7 @@ class SQLFORM(FORM):
except (KeyError, ValueError, TypeError): except (KeyError, ValueError, TypeError):
redirect(URL(args=table._tablename)) redirect(URL(args=table._tablename))
if nargs == len(args) + 1: if nargs == len(args) + 1:
query = table._id != None query = table._db._adapter.id_query(table)
# filter out data info for displayed table # filter out data info for displayed table
if table._tablename in constraints: if table._tablename in constraints:
@@ -3136,4 +3092,3 @@ class ExporterJSON(ExportClass):
return self.rows.as_json() return self.rows.as_json()
else: else:
return 'null' return 'null'
+2 -3
View File
@@ -46,7 +46,7 @@ class TestBareHelpers(unittest.TestCase):
def testA(self): def testA(self):
self.assertEqual(A('<>', _a='1', _b='2').xml(), self.assertEqual(A('<>', _a='1', _b='2').xml(),
'<a a="1" b="2">&lt;&gt;</a>') '<a a="1" b="2" data-w2p_disable_with="default">&lt;&gt;</a>')
def testB(self): def testB(self):
self.assertEqual(B('<>', _a='1', _b='2').xml(), self.assertEqual(B('<>', _a='1', _b='2').xml(),
@@ -209,8 +209,7 @@ class TestBareHelpers(unittest.TestCase):
class TestData(unittest.TestCase): class TestData(unittest.TestCase):
def testAdata(self): def testAdata(self):
self.assertEqual(A('<>', data=dict(abc='<def?asd>', cde='standard'), _a='1', _b='2').xml(), self.assertEqual(A('<>', data=dict(abc='<def?asd>', cde='standard'), _a='1', _b='2').xml(),'<a a="1" b="2" data-abc="&lt;def?asd&gt;" data-cde="standard" data-w2p_disable_with="default">&lt;&gt;</a>')
'<a a="1" b="2" data-abc="&lt;def?asd&gt;" data-cde="standard">&lt;&gt;</a>')
if __name__ == '__main__': if __name__ == '__main__':
+7 -6
View File
@@ -1545,7 +1545,7 @@ class Auth(object):
settings.table_user_name, []) + signature_list settings.table_user_name, []) + signature_list
if username or settings.cas_provider: if username or settings.cas_provider:
is_unique_username = \ is_unique_username = \
[IS_MATCH('[\w\.\-]+'), [IS_MATCH('[\w\.\-]+', strict=True),
IS_NOT_IN_DB(db, '%s.username' % settings.table_user_name)] IS_NOT_IN_DB(db, '%s.username' % settings.table_user_name)]
if not settings.username_case_sensitive: if not settings.username_case_sensitive:
is_unique_username.insert(1, IS_LOWER()) is_unique_username.insert(1, IS_LOWER())
@@ -1824,7 +1824,7 @@ class Auth(object):
basic = current.request.env.http_authorization basic = current.request.env.http_authorization
if basic_auth_realm: if basic_auth_realm:
if callable(basic_auth_realm): if callable(basic_auth_realm):
basic_auth_realm = basic_auth_auth() basic_auth_realm = basic_auth_realm()
elif isinstance(basic_auth_realm, (unicode, str)): elif isinstance(basic_auth_realm, (unicode, str)):
basic_realm = unicode(basic_auth_realm) basic_realm = unicode(basic_auth_realm)
elif basic_auth_realm is True: elif basic_auth_realm is True:
@@ -5201,12 +5201,13 @@ class Wiki(object):
return True return True
def can_see_menu(self): def can_see_menu(self):
if self.settings.menu_groups is None:
return True
if self.auth.user: if self.auth.user:
groups = self.auth.user_groups.values() if self.settings.menu_groups is None:
if any(t in self.settings.menu_groups for t in groups):
return True return True
else:
groups = self.auth.user_groups.values()
if any(t in self.settings.menu_groups for t in groups):
return True
return False return False
### END POLICY ### END POLICY