Compare commits
112 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 973bb4a16f | |||
| 2fa54f069c | |||
| b11260d2e2 | |||
| a6a9b004ea | |||
| 6ed204301d | |||
| 52392a10ae | |||
| 6d68a40ddf | |||
| 51bf802978 | |||
| 34267b7673 | |||
| 26eb5e6f38 | |||
| 13964c2c9b | |||
| 6a876fffc2 | |||
| cd7850cc36 | |||
| e4705dd48a | |||
| 2ef079289b | |||
| 76e95a9f1c | |||
| 4c5664f701 | |||
| cafba3fbe2 | |||
| 8cb6678505 | |||
| 9fabfaac96 | |||
| 797ade202f | |||
| dda81d1b95 | |||
| 13ed29ffc3 | |||
| 785276d294 | |||
| 52f634cb58 | |||
| f921b24a95 | |||
| 753c54dbfc | |||
| 89cf314358 | |||
| 9299ecb64d | |||
| 94afe61477 | |||
| a22f56ca0c | |||
| 656c490a21 | |||
| 8859ef04d3 | |||
| 5cf835d856 | |||
| 6a569bf56e | |||
| bd6115ad62 | |||
| 3a265e3111 | |||
| 78fc14df81 | |||
| 4311820494 | |||
| d1094e7b0c | |||
| dbbbd44642 | |||
| fa9d1ccb8b | |||
| e6fad4f007 | |||
| 23292754e3 | |||
| dcd7f8b46c | |||
| 7fd67c4e2e | |||
| ec3ae8211f | |||
| e8c0e0df92 | |||
| 7f9262f8f8 | |||
| 11da1ed19a | |||
| 9735477c35 | |||
| f6f946f867 | |||
| 8683b0680d | |||
| fbb5776432 | |||
| 92b4bc4f94 | |||
| d886bf759e | |||
| d5d25e8110 | |||
| 86c70df1e7 | |||
| b6d923753a | |||
| d4cad7634c | |||
| 45c28b1d76 | |||
| b978bb90de | |||
| e76ecec14f | |||
| 8ce528327c | |||
| fe0e23f4b9 | |||
| e05da97b1d | |||
| 5290308dea | |||
| 5817a1893b | |||
| aa2e302936 | |||
| d02755eac2 | |||
| d037eaab44 | |||
| 9aa5995924 | |||
| a981ca52e8 | |||
| 327c40cd17 | |||
| f9745e8a63 | |||
| 51ce35c4e5 | |||
| 0f7e4d774b | |||
| 6e6612a57d | |||
| 83a3149849 | |||
| 98d33bdded | |||
| f370187332 | |||
| 1b15b0c6dc | |||
| 507c3d6c33 | |||
| e62069c8b7 | |||
| d94ea6b295 | |||
| 9533978b37 | |||
| 9706d125b4 | |||
| 01aa9de919 | |||
| 55994c489b | |||
| 983627daa4 | |||
| 7c299936e4 | |||
| df55f52d8f | |||
| c81f1fd6c8 | |||
| f15dd4b6e5 | |||
| e9e61cbca4 | |||
| 700821e372 | |||
| 1d04f8837e | |||
| a375e047e9 | |||
| fe6b222aaf | |||
| 0b5bb9b996 | |||
| be4df0dee7 | |||
| d877e8b6d0 | |||
| 2531c2c640 | |||
| eca300af32 | |||
| 43c60df371 | |||
| cdac608efc | |||
| 3311486b14 | |||
| 038d0d17a4 | |||
| 3999fd80f8 | |||
| 2db3975a32 | |||
| ebe3434a86 | |||
| dc1c85928d |
@@ -1,10 +1,28 @@
|
||||
## trunk
|
||||
## 2.14.1
|
||||
|
||||
|
||||
- fixed two major security issues that caused the examples app to leak information
|
||||
- new Auth(…,host_names=[…]) to prevent host header injection
|
||||
- improved scheduler
|
||||
- pep8 enhancements
|
||||
- many bug fixes
|
||||
- restored GAE support that was broken in 2.13.*
|
||||
- improved fabfile for deployment
|
||||
- refactored examples with stupid.css
|
||||
- new JWT implementation (experimental)
|
||||
- new gluon.contrib.redis_scheduler
|
||||
- BREAKING: changes to gluon.contrib.redis_cache
|
||||
- myconf.get
|
||||
- LDAP groups (experimental)
|
||||
- .flash -> .w2p_flash
|
||||
- Updated feedparser.py 5.2.1
|
||||
- Updated jQuery 1.12.2
|
||||
- welcome app now checks for version number
|
||||
- Redis improvements. The old syntax still works but we recommend moving to new syntax:
|
||||
|
||||
BEFORE:
|
||||
from gluon.contrib.redis_cache import RedisCache
|
||||
cache.redis = RedisCache('localhost:6379',db=None, debug=True)
|
||||
|
||||
NOW:
|
||||
from gluon.contrib.redis_utils import RConn
|
||||
from gluon.contrib.redis_cache import RedisCache
|
||||
@@ -14,11 +32,12 @@
|
||||
# socket_connect_timeout=None, .....)
|
||||
# exactly as a redis.StrictRedis instance
|
||||
cache.redis = RedisCache(redis_conn=rconn, debug=True)
|
||||
- BREAKING: changes to gluon.contrib.redis_session
|
||||
|
||||
BEFORE:
|
||||
from gluon.contrib.redis_session import RedisSession
|
||||
sessiondb = RedisSession('localhost:6379',db=0, session_expiry=False)
|
||||
session.connect(request, response, db = sessiondb)
|
||||
|
||||
NOW:
|
||||
from gluon.contrib.redis_utils import RConn
|
||||
from gluon.contrib.redis_session import RedisSession
|
||||
@@ -27,7 +46,7 @@
|
||||
session.connect(request, response, db = sessiondb)
|
||||
|
||||
|
||||
## 2.13.1-2
|
||||
## 2.13.*
|
||||
|
||||
- fixed a security issue in request_reset_password
|
||||
- added fabfile.py
|
||||
|
||||
@@ -32,7 +32,7 @@ update:
|
||||
echo "remember that pymysql was tweaked"
|
||||
src:
|
||||
### Use semantic versioning
|
||||
echo 'Version 2.13.4-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION
|
||||
echo 'Version 2.14.1-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION
|
||||
### rm -f all junk files
|
||||
make clean
|
||||
### clean up baisc apps
|
||||
|
||||
@@ -1 +1 @@
|
||||
Version 2.13.4-stable+timestamp.2016.02.10.15.41.11
|
||||
Version 2.14.1-stable+timestamp.2016.03.24.12.19.17
|
||||
|
||||
@@ -268,7 +268,7 @@ def site():
|
||||
raise Exception("404 file not found")
|
||||
except Exception, e:
|
||||
session.flash = \
|
||||
DIV(T('Unable to download app because:'), PRE(str(e)))
|
||||
DIV(T('Unable to download app because:'), PRE(repr(e)))
|
||||
redirect(URL(r=request))
|
||||
fname = form_update.vars.url
|
||||
|
||||
@@ -740,7 +740,7 @@ def edit():
|
||||
B(ex_name), ' ' + T('at line %s', e.lineno),
|
||||
offset and ' ' +
|
||||
T('at char %s', offset) or '',
|
||||
PRE(str(e)))
|
||||
PRE(repr(e)))
|
||||
if data_or_revert and request.args[1] == 'modules':
|
||||
# Lets try to reload the modules
|
||||
try:
|
||||
@@ -751,7 +751,7 @@ def edit():
|
||||
% (request.args[0], mopath)])
|
||||
except Exception, e:
|
||||
response.flash = DIV(
|
||||
T('failed to reload module because:'), PRE(str(e)))
|
||||
T('failed to reload module because:'), PRE(repr(e)))
|
||||
|
||||
edit_controller = None
|
||||
editviewlinks = None
|
||||
|
||||
+340
-104
@@ -2,89 +2,131 @@
|
||||
{
|
||||
'!langcode!': 'cs-cz',
|
||||
'!langname!': 'čeština',
|
||||
'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': 'Kolonka "Upravit" je nepovinný výraz, například "pole1=\'nováhodnota\'". Výsledky databázového JOINu nemůžete mazat ani upravovat.',
|
||||
'"User Exception" debug mode. An error ticket could be issued!': '"User Exception" debug mode. An error ticket could be issued!',
|
||||
'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': 'Kolonka "Upravit" je nepovinný výraz, například "pole1=\'nováhodnota\'". (Avšak výsledky databázového JOINu nelze mazat ani upravovat.)',
|
||||
'"User Exception" debug mode. ': '"Uživatelská výjimka", Debug mód.',
|
||||
'"User Exception" debug mode. An error ticket could be issued!': '"Uživatelská výjimka", Debug mód. Může být vystaven chybový tiket.',
|
||||
'%%{Row} in Table': '%%{řádek} v tabulce',
|
||||
'%%{Row} selected': 'označených %%{řádek}',
|
||||
'%s': '%s',
|
||||
'%s %%{row} deleted': '%s smazaných %%{záznam}',
|
||||
'%s %%{row} updated': '%s upravených %%{záznam}',
|
||||
'%s selected': '%s označených',
|
||||
'%s students registered': '%s studentů registrováno',
|
||||
'%Y-%m-%d': '%d.%m.%Y',
|
||||
'%Y-%m-%d %H:%M:%S': '%d.%m.%Y %H:%M:%S',
|
||||
'(requires internet access)': '(vyžaduje připojení k internetu)',
|
||||
'(requires internet access, experimental)': '(requires internet access, experimental)',
|
||||
'(requires internet access, experimental)': '(vyžaduje internetové připojení, experimentální)',
|
||||
'(something like "it-it")': '(například "cs-cs")',
|
||||
'(version %s)': '(verze %s)',
|
||||
'?': '?',
|
||||
'@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(soubor **gluon/contrib/plural_rules/%s.py** nenalezen)',
|
||||
'@markmin\x01An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page',
|
||||
'@markmin\x01Searching: **%s** %%{file}': 'Hledání: **%s** %%{soubor}',
|
||||
'Abort': 'Ukončit',
|
||||
'About': 'O programu',
|
||||
'About application': 'O aplikaci',
|
||||
'Accept Terms': 'Souhlasit s podmínkami',
|
||||
'Access Control': 'Řízení přístupu',
|
||||
'Add breakpoint': 'Přidat bod přerušení',
|
||||
'Additional code for your application': 'Další kód pro Vaši aplikaci',
|
||||
'Admin design page': 'Admin design page',
|
||||
'Additional code for your application': 'Další kód pro Vaši aplikaci (pro příkaz import). Neběží ve specifickém režimu ani ve vláknech jako model/kontrolér/šablona, ale jako standardní python moduly. Ty tedy můžete umístit sem (pouze pro tuto aplikaci) nebo používat systémově dostupné.',
|
||||
'Admin design page': 'Admin design stránka',
|
||||
'admin disabled because no admin password': 'admin je zakázán, protože chybí heslo administrátora',
|
||||
'admin disabled because not supported on google app engine': 'admin je zakázán kvůli chybějící podpoře na Google App Engine',
|
||||
'admin disabled because too many invalid login attempts': 'Admin je zakázán po příliš mnoha nesprávných pokusech o přihlášení',
|
||||
'admin disabled because unable to access password file': 'Admin je zakázán, protože nelze číst soubor s heslem',
|
||||
'Admin is disabled because insecure channel': 'Admin je zakázán na nezabezpečeném připojení',
|
||||
'Admin language': 'jazyk rozhraní',
|
||||
'Admin versioning page': 'Admin verzovací stránka',
|
||||
'Administrative interface': 'pro administrátorské rozhraní klikněte sem',
|
||||
'Administrative Interface': 'Administrátorské rozhraní',
|
||||
'administrative interface': 'rozhraní pro správu',
|
||||
'Administrator Password:': 'Administrátorské heslo:',
|
||||
'Ajax Recipes': 'Recepty s ajaxem',
|
||||
'An error occured, please %s the page': 'An error occured, please %s the page',
|
||||
'An error occured, please %s the page': 'Došlo k chybě, prosím %s stránku',
|
||||
'and rename it:': 'a přejmenovat na:',
|
||||
'App does not exist or you are not authorized': 'Aplikace neexistuje nebo vám chybí oprávnění',
|
||||
'appadmin': 'appadmin',
|
||||
'appadmin is disabled because insecure channel': 'appadmin je zakázaná bez zabezpečeného spojení',
|
||||
'Application': 'Application',
|
||||
'Application': 'Aplikace',
|
||||
'application "%s" uninstalled': 'application "%s" odinstalována',
|
||||
'Application cannot be generated in demo mode': 'Aplikace nemůže být vytvořena v demo módu',
|
||||
'application compiled': 'aplikace zkompilována',
|
||||
'Application exists already': 'Aplikace již existuje',
|
||||
'application is compiled and cannot be designed': 'aplikace je přeložena a nelze ji editovat',
|
||||
'Application name:': 'Název aplikace:',
|
||||
'Application updated via git pull': 'Aplikace byla aktualizována pomocí git pull',
|
||||
'are not used': 'nepoužita',
|
||||
'are not used yet': 'ještě nepoužita',
|
||||
'Are you sure you want to delete file "%s"?': 'Skutečně chcete smazat soubor "%s"?',
|
||||
'Are you sure you want to delete plugin "%s"?': 'Skutečně chcete smazat plugin "%s"?',
|
||||
'Are you sure you want to delete this object?': 'Opravdu chcete odstranit tento objekt?',
|
||||
'Are you sure you want to uninstall application "%s"?': 'Opravdu chcete odinstalovat aplikaci "%s"?',
|
||||
'arguments': 'arguments',
|
||||
'at char %s': 'at char %s',
|
||||
'at line %s': 'at line %s',
|
||||
'ATTENTION:': 'ATTENTION:',
|
||||
'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.',
|
||||
'Are you sure?': 'Jste si jist(a)?',
|
||||
'arguments': 'argumenty',
|
||||
'at char %s': 'na pozici znaku %s',
|
||||
'at line %s': 'na řádku %s',
|
||||
'ATTENTION:': 'POZOR:',
|
||||
'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'POZOR: Přihlášení vyžaduje zabezpečené (HTTPS) připojení nebo spouštění na localhost.',
|
||||
'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'POZOR: TESTOVÁNÍ NENÍ BEZPEČNÉ PŘI SOUBĚŽNÝCH VLÁKNECH. NESPOUŠTĚJ VÍCE TESTŮ SOUBĚŽNĚ.',
|
||||
'ATTENTION: you cannot edit the running application!': 'POZOR: Nelze editovat spuštěnou aplikaci.',
|
||||
'Autocomplete Python Code': 'Autocomplete Python kód',
|
||||
'Available Databases and Tables': 'Dostupné databáze a tabulky',
|
||||
'back': 'zpět',
|
||||
'Back to wizard': 'Back to wizard',
|
||||
'Basics': 'Basics',
|
||||
'Back to the plugins list': 'Zpět do seznamu pluginů',
|
||||
'Back to wizard': 'Zpátky do průvodce',
|
||||
'Basics': 'Základy',
|
||||
'Begin': 'Začít',
|
||||
'breakpoint': 'bod přerušení',
|
||||
'Breakpoints': 'Body přerušení',
|
||||
'breakpoints': 'body přerušení',
|
||||
'Bulk Register': 'Hromadná registrace',
|
||||
'Bulk Student Registration': 'Hromadná registrace studentů',
|
||||
'Buy this book': 'Koupit web2py knihu',
|
||||
'Cache': 'Cache',
|
||||
'cache': 'cache',
|
||||
'Cache Cleared': 'Cache byla vymazána',
|
||||
'Cache Keys': 'Klíče cache',
|
||||
'cache, errors and sessions cleaned': 'cache, chyby a relace byly pročištěny',
|
||||
'can be a git repo': 'může to být git repo',
|
||||
'Cancel': 'Storno',
|
||||
'Cannot be empty': 'Nemůže být prázdné',
|
||||
'Cannot compile: there are errors in your app:': 'Nelze zkompilovat: ve vaší aplikaci jsou chyby:',
|
||||
'cannot create file': 'nelze vytvořit soubor',
|
||||
'cannot upload file "%(filename)s"': 'nelze nahrát soubor "%(filename)s"',
|
||||
'Change Admin Password': 'Změnit heslo pro správu',
|
||||
'Change admin password': 'Změnit heslo pro správu aplikací',
|
||||
'change editor settings': 'změnit nastavení editoru',
|
||||
'Change password': 'Změna hesla',
|
||||
'Changelog': 'Žurnál změn',
|
||||
'check all': 'vše označit',
|
||||
'Check for upgrades': 'Zkusit aktualizovat',
|
||||
'Check to delete': 'Označit ke smazání',
|
||||
'Check to delete:': 'Označit ke smazání:',
|
||||
'Checking for upgrades...': 'Zjišťuji, zda jsou k dispozici aktualizace...',
|
||||
'Clean': 'Pročistit',
|
||||
'Clear': 'Inicializovat',
|
||||
'Clear CACHE?': 'Vymazat CACHE?',
|
||||
'Clear DISK': 'Vymazat DISK',
|
||||
'Clear RAM': 'Vymazat RAM',
|
||||
'Click row to expand traceback': 'Pro rozbalení stopy, klikněte na řádek',
|
||||
'Click row to view a ticket': 'Pro zobrazení chyby (ticketu), klikněte na řádku...',
|
||||
'Client IP': 'IP adresa klienta',
|
||||
'code': 'code',
|
||||
'Code listing': 'Code listing',
|
||||
'code': 'kód',
|
||||
'Code listing': 'Výpis kódu',
|
||||
'collapse/expand all': 'vše sbalit/rozbalit',
|
||||
'Command': 'Příkaz',
|
||||
'Comment:': 'Komentář:',
|
||||
'Commit': 'Potvrdit',
|
||||
'Commit form': 'Potvrdit formulář',
|
||||
'Committed files': 'Potvrzené soubory',
|
||||
'Community': 'Komunita',
|
||||
'Compile': 'Zkompilovat',
|
||||
'Compile (all or nothing)': 'Přeložit (vše nebo nic)',
|
||||
'Compile (skip failed views)': 'Přeložit (přeskočit chybné šablony)',
|
||||
'compiled application removed': 'zkompilovaná aplikace smazána',
|
||||
'Components and Plugins': 'Komponenty a zásuvné moduly',
|
||||
'Condition': 'Podmínka',
|
||||
'continue': 'continue',
|
||||
'continue': 'pokračovat',
|
||||
'Controller': 'Kontrolér (Controller)',
|
||||
'Controllers': 'Kontroléry',
|
||||
'controllers': 'kontroléry',
|
||||
@@ -92,9 +134,12 @@
|
||||
'Count': 'Počet',
|
||||
'Create': 'Vytvořit',
|
||||
'create file with filename:': 'vytvořit soubor s názvem:',
|
||||
'Create/Upload': 'Vytvořit/Nahrát',
|
||||
'created by': 'vytvořil',
|
||||
'Created By': 'Vytvořeno - kým',
|
||||
'Created by:': 'Vytvořil:',
|
||||
'Created On': 'Vytvořeno - kdy',
|
||||
'Created on:': 'Vytvořeno:',
|
||||
'crontab': 'crontab',
|
||||
'Current request': 'Aktuální požadavek',
|
||||
'Current response': 'Aktuální odpověď',
|
||||
@@ -105,18 +150,19 @@
|
||||
'data uploaded': 'data nahrána',
|
||||
'Database': 'Rozhraní databáze',
|
||||
'Database %s select': 'databáze %s výběr',
|
||||
'Database administration': 'Database administration',
|
||||
'Database administration': 'Administrace databáze',
|
||||
'database administration': 'správa databáze',
|
||||
'Database Administration (appadmin)': 'Administrace databáze (appadmin)',
|
||||
'Date and Time': 'Datum a čas',
|
||||
'day': 'den',
|
||||
'db': 'db',
|
||||
'DB Model': 'Databázový model',
|
||||
'Debug': 'Ladění',
|
||||
'defines tables': 'defines tables',
|
||||
'defines tables': 'definuje tabulky',
|
||||
'Delete': 'Smazat',
|
||||
'delete': 'smazat',
|
||||
'delete all checked': 'smazat vše označené',
|
||||
'delete plugin': 'delete plugin',
|
||||
'delete plugin': 'zrušit plugin',
|
||||
'Delete this file (you will be asked to confirm deletion)': 'Smazat tento soubor (budete požádán o potvrzení mazání)',
|
||||
'Delete:': 'Smazat:',
|
||||
'deleted after first hit': 'smazat po prvním dosažení',
|
||||
@@ -124,166 +170,265 @@
|
||||
'Deploy': 'Nahrát',
|
||||
'Deploy on Google App Engine': 'Nahrát na Google App Engine',
|
||||
'Deploy to OpenShift': 'Nahrát na OpenShift',
|
||||
'Deploy to pythonanywhere': 'Nahrát na PythonAnywhere',
|
||||
'Deploy to PythonAnywhere': 'Nahrát na PythonAnywhere',
|
||||
'Deployment form': 'Forumlář pro deployment (nasazení)',
|
||||
'Deployment Interface': 'Rozhraní pro deployment (nasazení)',
|
||||
'Deployment Recipes': 'Postupy pro deployment',
|
||||
'Description': 'Popis',
|
||||
'Description:': 'Popis:',
|
||||
'design': 'návrh',
|
||||
'Detailed traceback description': 'Podrobný výpis prostředí',
|
||||
'details': 'podrobnosti',
|
||||
'direction: ltr': 'směr: ltr',
|
||||
'directory not found': 'adresář nebyl nalezen',
|
||||
'Disable': 'Zablokovat',
|
||||
'Disabled': 'Blokováno',
|
||||
'disabled in demo mode': 'zakázáno v demo módu',
|
||||
'disabled in GAE mode': 'zakázáno v GAE módu',
|
||||
'disabled in multi user mode': 'zakázáno ve víceuživatelském módu',
|
||||
'DISK': 'DISK',
|
||||
'Disk Cache Keys': 'Klíče diskové cache',
|
||||
'Disk Cleared': 'Disk smazán',
|
||||
'Display line numbers': 'Zobrazit čísla řádků',
|
||||
'DO NOT use the "Pack compiled" feature.': 'NEPOUŽÍVEJ vlastnost "Zabalit zkompilované".',
|
||||
'docs': 'dokumentace',
|
||||
'Docs': 'Dokumentace',
|
||||
'Documentation': 'Dokumentace',
|
||||
"Don't know what to do?": 'Nevíte kudy kam?',
|
||||
'done!': 'hotovo!',
|
||||
'Downgrade': 'Downgrade (vrácení verze)',
|
||||
'Download': 'Stáhnout',
|
||||
'Download .w2p': 'Stažení .w2p',
|
||||
'Download as .exe': 'Stáhnout jako .exe',
|
||||
'download layouts': 'stáhnout moduly rozvržení stránky',
|
||||
'Download layouts from repository': 'Stáhnout moduly rozvržení z repozitáře',
|
||||
'download plugins': 'stáhnout zásuvné moduly',
|
||||
'Download plugins from repository': 'Stáhnout pluginy z repozitáře',
|
||||
'E-mail': 'E-mail',
|
||||
'Edit': 'Upravit',
|
||||
'edit all': 'edit all',
|
||||
'edit all': 'editovat vše',
|
||||
'Edit application': 'Správa aplikace',
|
||||
'edit controller': 'edit controller',
|
||||
'edit controller': 'editovat controller',
|
||||
'edit controller:': 'editovat kontrolér:',
|
||||
'Edit current record': 'Upravit aktuální záznam',
|
||||
'Edit Profile': 'Upravit profil',
|
||||
'edit views:': 'upravit pohled:',
|
||||
'edit views:': 'upravit šablonu (view):',
|
||||
'Editing %s': 'Editace %s',
|
||||
'Editing file "%s"': 'Úprava souboru "%s"',
|
||||
'Editing Language file': 'Úprava jazykového souboru',
|
||||
'Editing Plural Forms File': 'Editing Plural Forms File',
|
||||
'Editing Plural Forms File': 'Editování souboru množných čísel',
|
||||
'Editor': 'Editor',
|
||||
'Email Address': 'Emailová adresa',
|
||||
'Email and SMS': 'Email a SMS',
|
||||
'Enable': 'Odblokovat',
|
||||
'Enable Close-Tag': 'Povolit Close-Tag',
|
||||
'Enable Code Folding': 'Povolit sdružování kódu',
|
||||
'enter a number between %(min)g and %(max)g': 'zadejte číslo mezi %(min)g a %(max)g',
|
||||
'enter an integer between %(min)g and %(max)g': 'zadejte celé číslo mezi %(min)g a %(max)g',
|
||||
'Error': 'Chyba',
|
||||
'Error logs for "%(app)s"': 'Seznam výskytu chyb pro aplikaci "%(app)s"',
|
||||
'Error snapshot': 'Snapshot chyby',
|
||||
'Error ticket': 'Ticket chyby',
|
||||
'Error ticket': 'Tiket chyby',
|
||||
'Errors': 'Chyby',
|
||||
'Exception %(extype)s: %(exvalue)s': 'Exception %(extype)s: %(exvalue)s',
|
||||
'Exception %s': 'Exception %s',
|
||||
'Exception %(extype)s: %(exvalue)s': 'Výjimka %(extype)s: %(exvalue)s',
|
||||
'Exception %s': 'Výjimka %s',
|
||||
'Exception instance attributes': 'Prvky instance výjimky',
|
||||
'Expand Abbreviation': 'Expand Abbreviation',
|
||||
'Exit Fullscreen': 'Ukončit režim celé obrazovky',
|
||||
'Expand Abbreviation': 'Rozvinout zkratku',
|
||||
'Expand Abbreviation (html files only)': 'Rozvinout zkratku (pouze html soubory)',
|
||||
'export as csv file': 'exportovat do .csv souboru',
|
||||
'Exports:': 'Exporty:',
|
||||
'exposes': 'vystavuje',
|
||||
'exposes:': 'vystavuje funkce:',
|
||||
'extends': 'rozšiřuje',
|
||||
'failed to compile file because:': 'soubor se nepodařilo zkompilovat, protože:',
|
||||
'failed to reload module because:': 'nepodařilo se restartovat modul, protože:',
|
||||
'FAQ': 'Často kladené dotazy',
|
||||
'File': 'Soubor',
|
||||
'file': 'soubor',
|
||||
'file "%(filename)s" created': 'file "%(filename)s" created',
|
||||
'file "%(filename)s" created': 'soubor "%(filename)s" byl vytvořen',
|
||||
'file "%(filename)s" deleted': 'soubor "%(filename)s" byl zrušen',
|
||||
'file "%(filename)s" uploaded': 'soubor "%(filename)s" byl nahrán',
|
||||
'file "%s" of %s restored': 'soubor "%s" z %s byl obnoven',
|
||||
'file changed on disk': 'soubor se na disku změnil',
|
||||
'file does not exist': 'soubor neexistuje',
|
||||
'file not found': 'soubor nebyl nalezen',
|
||||
'file saved on %(time)s': 'soubor uložen %(time)s',
|
||||
'file saved on %s': 'soubor uložen %s',
|
||||
'filename': 'jméno souboru',
|
||||
'Filename': 'Název souboru',
|
||||
'Files added': 'Soubory byly přidány',
|
||||
'filter': 'filtr',
|
||||
'Find Next': 'Najít další',
|
||||
'Find Previous': 'Najít předchozí',
|
||||
'First name': 'Křestní jméno',
|
||||
'Forgot username?': 'Zapomněl jste svoje přihlašovací jméno?',
|
||||
'forgot username?': 'zapomněl jste svoje přihlašovací jméno?',
|
||||
'Form has errors': 'Ve formuláři jsou chyby',
|
||||
'Forms and Validators': 'Formuláře a validátory',
|
||||
'Frames': 'Frames',
|
||||
'Frames': 'Framy',
|
||||
'Free Applications': 'Aplikace zdarma',
|
||||
'Functions with no doctests will result in [passed] tests.': 'Functions with no doctests will result in [passed] tests.',
|
||||
'Functions with no doctests will result in [passed] tests.': 'Funkce bez doctestů se projeví jako [úspěšný] test.',
|
||||
'GAE Email': 'GAE e-mail',
|
||||
'GAE Output': 'GAE výstup',
|
||||
'GAE Password': 'GAE heslo',
|
||||
'Generate': 'Vytvořit',
|
||||
'Get from URL:': 'Stáhnout z internetu:',
|
||||
'Git Pull': 'Git Pull',
|
||||
'Git Push': 'Git Push',
|
||||
'Globals##debug': 'Globální proměnné',
|
||||
'go!': 'OK!',
|
||||
'Goto': 'Goto',
|
||||
'graph model': 'graph model',
|
||||
'Google App Engine Deployment Interface': 'Google App Engine - rozhraní pro nasazení',
|
||||
'Google Application Id': 'ID Google Aplikace',
|
||||
'Goto': 'Přejít na',
|
||||
'graph model': 'grafický model',
|
||||
'Graph Model': 'Grafický model',
|
||||
'Group %(group_id)s created': 'Skupina %(group_id)s vytvořena',
|
||||
'Group ID': 'ID skupiny',
|
||||
'Groups': 'Skupiny',
|
||||
'Hello World': 'Ahoj světe',
|
||||
'Help': 'Nápověda',
|
||||
'here': 'zde',
|
||||
'Hide/Show Translated strings': 'Skrýt/Zobrazit přeložené texty',
|
||||
'Highlight current line': 'Zvýraznit aktuální řádek',
|
||||
'Hits': 'Kolikrát dosaženo',
|
||||
'Home': 'Domovská stránka',
|
||||
'honored only if the expression evaluates to true': 'brát v potaz jen když se tato podmínka vyhodnotí kladně',
|
||||
'How did you get here?': 'Jak jste se sem vlastně dostal?',
|
||||
'If start the upgrade, be patient, it may take a while to download': 'If start the upgrade, be patient, it may take a while to download',
|
||||
'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.',
|
||||
'If start the downgrade, be patient, it may take a while to rollback': 'Spustíte-li downgrade verze, vyčkejte, protože vrácení změn může trvat dlouho',
|
||||
'If start the upgrade, be patient, it may take a while to download': 'Spustíte-li upgrade, vyčkejte, protože stahování může trvat dlouho',
|
||||
'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.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'Jestliže přehled výše obsahuje číslo chybového tiketu, znamená to chybu v kontroléru, ještě před pokusem vykonat doctesty. (Často je to způsobeno chybou odsazení nebo chybou mimo kód funkce.) Zelený nadpis označuje, že žádný test nehavaroval. (V tom případě dílčí výsledky nejsou uvedeny.)',
|
||||
'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.': 'Jestliže přehled výše obsahuje číslo chybového tiketu, znamená to chybu v kontroléru, ještě před pokusem vykonat doctesty. (Často je to způsobeno chybou odsazení nebo chybou mimo kód funkce.) Zelený nadpis označuje, že žádný test nehavaroval. (V tom případě dílčí výsledky nejsou uvedeny.)',
|
||||
'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.': 'Jestliže vaše aplikace používá jinou databázi než SQLite, budete muset na PythonAnywhere konfigurovat její DAL() připojení.',
|
||||
'import': 'import',
|
||||
'Import/Export': 'Import/Export',
|
||||
'In development, use the default Rocket webserver that is currently supported by this debugger.': 'Při vývoji je doporučeno použít předvolený webserver Rocket, se kterým tento debugger spolupracuje.',
|
||||
'includes': 'zahrnuje',
|
||||
'Indent with tabs': 'Odsazení tabelátory',
|
||||
'Index': 'Index',
|
||||
'insert new': 'vložit nový záznam ',
|
||||
'insert new %s': 'vložit nový záznam %s',
|
||||
'inspect attributes': 'inspect attributes',
|
||||
'inspect attributes': 'prohlédnout atributy',
|
||||
'Install': 'Instalovat',
|
||||
'Installation of %(plugin)s for %(app)s': 'Instalace %(plugin)s pro %(app)s',
|
||||
'Installed applications': 'Nainstalované aplikace',
|
||||
'Interaction at %s line %s': 'Interakce v %s, na řádce %s',
|
||||
'Interactive console': 'Interaktivní příkazová řádka',
|
||||
'internal error': 'vnitřní chyba',
|
||||
'internal error: %s': 'vnitřní chyba: %s',
|
||||
'Internal State': 'Vnitřní stav',
|
||||
'Introduction': 'Úvod',
|
||||
'Invalid action': 'Chybná akce',
|
||||
'Invalid application name': 'Nesprávné jméno aplikace',
|
||||
'invalid circular reference': 'nepovolený kruhový odkaz',
|
||||
'Invalid email': 'Neplatný email',
|
||||
'Invalid git repository specified.': 'Byl zadán nesprávný git repozitář.',
|
||||
'Invalid password': 'Nesprávné heslo',
|
||||
'invalid password': 'nesprávné heslo',
|
||||
'invalid password.': 'neplatné heslo',
|
||||
'Invalid Query': 'Neplatný dotaz',
|
||||
'invalid request': 'Neplatný požadavek',
|
||||
'Invalid request': 'Nesprávný požadavek (request)',
|
||||
'invalid table names (auth_* tables already defined)': 'chybná jména tabulek (auth_* tabulky už byly definovány)',
|
||||
'invalid ticket': 'chybný tiket',
|
||||
'Is Active': 'Je aktivní',
|
||||
'It is %s %%{day} today.': 'Dnes je to %s %%{den}.',
|
||||
'Key': 'Klíč',
|
||||
'Key bindings': 'Vazby klíčů',
|
||||
'Key bindings for ZenCoding Plugin': 'Key bindings for ZenCoding Plugin',
|
||||
'Key bindings': 'Vazby kláves',
|
||||
'Key bindings for ZenCoding Plugin': 'Vazby kláves pro ZenCoding Plugin',
|
||||
'Keyboard shortcuts': 'Klávesové zkratky',
|
||||
'kill process': 'likvidovat proces',
|
||||
'language file "%(filename)s" created/updated': 'jazykový soubor "%(filename)s" byl vytvořen/aktualizován',
|
||||
'Language files (static strings) updated': 'Jazykové soubory (statické řetězce) byly aktualizovány',
|
||||
'languages': 'jazyky',
|
||||
'Languages': 'Jazyky',
|
||||
'Last name': 'Příjmení',
|
||||
'Last Revision': 'Minulá verze',
|
||||
'Last saved on:': 'Naposledy uloženo:',
|
||||
'Layout': 'Rozvržení stránky (layout)',
|
||||
'Layout Plugins': 'Moduly rozvržení stránky (Layout Plugins)',
|
||||
'Layouts': 'Rozvržení stránek',
|
||||
'License for': 'Licence pro',
|
||||
'License:': 'Licence:',
|
||||
'Line Nr': 'Č.řádku',
|
||||
'Line number': 'Číslo řádku',
|
||||
'LineNo': 'Č.řádku',
|
||||
'Live Chat': 'Online pokec',
|
||||
'lists by exception': 'výpis podle výjimky',
|
||||
'lists by ticket': 'výpis podle tiketu',
|
||||
'Live Chat': 'Online chat',
|
||||
'Loading...': 'Nahrávám...',
|
||||
'loading...': 'nahrávám...',
|
||||
'locals': 'locals',
|
||||
'Local Apps': 'Lokální aplikace',
|
||||
'locals': 'lokální proměnné',
|
||||
'Locals##debug': 'Lokální proměnné',
|
||||
'Logged in': 'Přihlášení proběhlo úspěšně',
|
||||
'Logged out': 'Odhlášení proběhlo úspěšně',
|
||||
'Login': 'Přihlásit se',
|
||||
'login': 'přihlásit se',
|
||||
'Login': 'Přihlásit se',
|
||||
'Login successful': 'Přihlášení bylo úspěšné',
|
||||
'Login to the Administrative Interface': 'Přihlásit se do Správce aplikací',
|
||||
'Login/Register': 'Přihlásit se / Registrovat',
|
||||
'logout': 'odhlásit se',
|
||||
'Logout': 'Odhlásit se',
|
||||
'lost password': 'ztracené heslo',
|
||||
'Lost Password': 'Zapomněl jste heslo',
|
||||
'Lost password?': 'Zapomněl jste heslo?',
|
||||
'lost password?': 'zapomněl jste heslo?',
|
||||
'Manage': 'Manage',
|
||||
'Manage Cache': 'Manage Cache',
|
||||
'Main Menu': 'Hlavní nabídka',
|
||||
'Manage': 'Spravovat',
|
||||
'Manage %(action)s': 'Spravovat %(action)s',
|
||||
'Manage Access Control': 'Spravovat řízení přístupu',
|
||||
'Manage Admin Users/Students': 'Spravovat Admin uživatele / Studenty',
|
||||
'Manage Cache': 'Spravovat cache',
|
||||
'Manage Students': 'Spravovat studenty',
|
||||
'Memberships': 'Členství ve skupinách',
|
||||
'Menu Model': 'Model rozbalovací nabídky',
|
||||
'merge': 'sloučit',
|
||||
'Models': 'Modely',
|
||||
'models': 'modely',
|
||||
'Modified By': 'Změněno - kým',
|
||||
'Modified On': 'Změněno - kdy',
|
||||
'Modules': 'Moduly',
|
||||
'modules': 'moduly',
|
||||
'Multi User Mode': 'Víceuživatelský mód',
|
||||
'My Sites': 'Správa aplikací',
|
||||
'Name': 'Jméno',
|
||||
'new application "%s" created': 'nová aplikace "%s" vytvořena',
|
||||
'new application "%s" imported': 'nová aplikace "%s" byla importována',
|
||||
'New Application Wizard': 'Nový průvodce aplikací',
|
||||
'New application wizard': 'Nový průvodce aplikací',
|
||||
'New password': 'Nové heslo',
|
||||
'new plugin installed': 'nový plugin byl instalován',
|
||||
'New plugin installed: %s': 'Nový plugin byl instalován: %s',
|
||||
'New Record': 'Nový záznam',
|
||||
'new record inserted': 'nový záznam byl založen',
|
||||
'New simple application': 'Vytvořit primitivní aplikaci',
|
||||
'next': 'next',
|
||||
'New simple application': 'Vytvořit novou aplikaci',
|
||||
'next': 'další',
|
||||
'next %s rows': 'dalších %s řádků',
|
||||
'next 100 rows': 'dalších 100 řádků',
|
||||
'NO': 'NE',
|
||||
'no changes': 'beze změn',
|
||||
'No databases in this application': 'V této aplikaci nejsou žádné databáze',
|
||||
'No Interaction yet': 'Ještě žádná interakce nenastala',
|
||||
'no match': 'nenalezena shoda',
|
||||
'no package selected': 'nebyla vybrána žádná package',
|
||||
'no permission to uninstall "%s"': 'chybí oprávnění odinstalovat "%s"',
|
||||
'No ticket_storage.txt found under /private folder': 'Soubor ticket_storage.txt v adresáři /private nenalezen',
|
||||
'Node:': 'Uzel (node):',
|
||||
'Not Authorized': 'Chybí autorizace',
|
||||
'Not supported': 'Není podporováno',
|
||||
'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.': 'Poznámka: Dostanete-li chybu s github status code = 128, ujistěte se, že systém a účet z něhož provádíte nasazení má odpovídající ssh klíč, konfigurovaný v OpenShift účtu.',
|
||||
'Object or table name': 'Objekt či tabulka',
|
||||
'Old password': 'Původní heslo',
|
||||
"On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.": 'Pro použití tohoto debuggeru na produkci je potřeba konfigurovat webserver, aby používal jeden proces a více vláken.',
|
||||
'online designer': 'online návrhář',
|
||||
'Online examples': 'Příklady online',
|
||||
'Open new app in new window': 'Open new app in new window',
|
||||
'or alternatively': 'or alternatively',
|
||||
'Or Get from URL:': 'Or Get from URL:',
|
||||
'Open new app in new window': 'Otevřít novou aplikaci v novém okně',
|
||||
'OpenShift Deployment Interface': 'OpenShift rozhraní pro nasazení aplikace',
|
||||
'OpenShift Output': 'OpenShift výstup',
|
||||
'or alternatively': 'nebo případně',
|
||||
'Or Get from URL:': 'Nebo získat z URL adresy:',
|
||||
'or import from csv file': 'nebo importovat z .csv souboru',
|
||||
'Origin': 'Původ',
|
||||
'Original/Translation': 'Originál/Překlad',
|
||||
@@ -293,30 +438,53 @@
|
||||
'Overwrite installed app': 'Přepsat instalovanou aplikaci',
|
||||
'Pack all': 'Zabalit',
|
||||
'Pack compiled': 'Zabalit zkompilované',
|
||||
'pack plugin': 'pack plugin',
|
||||
'password': 'heslo',
|
||||
'Pack custom': 'Zabalit volitelně (custom)',
|
||||
'pack plugin': 'zabalit plugin',
|
||||
'Password': 'Heslo',
|
||||
'password': 'heslo',
|
||||
'password changed': 'heslo bylo změněno',
|
||||
"Password fields don't match": 'Hesla se neshodují',
|
||||
'Peeking at file': 'Peeking at file',
|
||||
'Past revisions': 'Minulá verze',
|
||||
'Path to appcfg.py': 'Cesta ke appcfg.py',
|
||||
'Path to local openshift repo root.': 'Cesta ke kořenu (rootu) lokálního OpenShift repozitáře.',
|
||||
'Peeking at file': 'Sledování souboru',
|
||||
'Permission': 'Oprávnění',
|
||||
'Permissions': 'Oprávnění',
|
||||
'Please': 'Prosím',
|
||||
'Plugin "%s" in application': 'Plugin "%s" in application',
|
||||
'Please wait, giving pythonanywhere a moment...': 'Prosím, čekejte na dokončení činnosti PythonAnywhere...',
|
||||
'plugin "%(plugin)s" deleted': 'plugin "%(plugin)s" byl odstraněn',
|
||||
'Plugin "%s" in application': 'Plugin "%s" v aplikaci',
|
||||
'plugin not specified': 'plugin nebyl určen',
|
||||
'Plugin page': 'Stránka pluginů',
|
||||
'plugins': 'zásuvné moduly',
|
||||
'Plugins': 'Zásuvné moduly',
|
||||
'Plural Form #%s': 'Plural Form #%s',
|
||||
'Plural Form #%s': 'Množné číslo #%s',
|
||||
'Plural-Forms:': 'Množná čísla:',
|
||||
'Powered by': 'Poháněno',
|
||||
'Powered by': 'používá technologii',
|
||||
'Preface': 'Předmluva',
|
||||
'Preferences saved correctly': 'Nastavení byla úspěšně uložena',
|
||||
'Preferences saved on session only': 'Nastavení byla uložena pouze pro toto sezení',
|
||||
'previous %s rows': 'předchozích %s řádků',
|
||||
'previous 100 rows': 'předchozích 100 řádků',
|
||||
'Private files': 'Soukromé soubory',
|
||||
'private files': 'soukromé soubory',
|
||||
'profile': 'profil',
|
||||
'Project Progress': 'Vývoj projektu',
|
||||
'Pull': 'Pull',
|
||||
'Pull failed, certain files could not be checked out. Check logs for details.': 'Pull selhal, některé soubory nelze zkopírovat. Pro podrobnosti zkontrolujte logy.',
|
||||
'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.': 'Pull nelze provést, protože máte nesloučené soubory. Vyřešte tyto konflikty a pak akci opakujte.',
|
||||
'Push': 'Push',
|
||||
'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.': 'Push selhal, protože máte nesloučené soubory. Vyřešte tyto konflikty a pak akci opakujte.',
|
||||
'pygraphviz library not found': 'pygraphviz knihovna nebyla nalezena',
|
||||
'Python': 'Python',
|
||||
'PythonAnywhere Apps': 'PythonAnywhere aplikace',
|
||||
'PythonAnywhere Password': 'PythonAnywhere heslo',
|
||||
'Query:': 'Dotaz:',
|
||||
'Quick Examples': 'Krátké příklady',
|
||||
'RAM': 'RAM',
|
||||
'RAM Cache Keys': 'Klíče RAM Cache',
|
||||
'Ram Cleared': 'RAM smazána',
|
||||
'Rapid Search': 'Rychlé hledání',
|
||||
'Readme': 'Nápověda',
|
||||
'Recipes': 'Postupy jak na to',
|
||||
'Record': 'Záznam',
|
||||
@@ -335,114 +503,167 @@
|
||||
'Removed Breakpoint on %s at line %s': 'Bod přerušení smazán - soubor %s na řádce %s',
|
||||
'Replace': 'Zaměnit',
|
||||
'Replace All': 'Zaměnit vše',
|
||||
'request': 'request',
|
||||
'Repository (%s)': 'Repozitář (%s)',
|
||||
'request': 'požadavek (request)',
|
||||
'requires distutils, but not installed': 'vyžaduje distutils, jenže ty nejsou instalovány',
|
||||
'requires python-git, but not installed': 'vyžaduje python-git, který ale není nainstalován',
|
||||
'Reset Password key': 'Reset registračního klíče',
|
||||
'response': 'response',
|
||||
'Resolve Conflict file': 'Vyřešit konflikty',
|
||||
'response': 'odpověď (response)',
|
||||
'restart': 'restart',
|
||||
'restore': 'obnovit',
|
||||
'Retrieve username': 'Získat přihlašovací jméno',
|
||||
'return': 'return',
|
||||
'Revert': 'Vrátit se k původnímu',
|
||||
'revert': 'vrátit se k původnímu',
|
||||
'reverted to revision %s': 'vráceno k verzi %s',
|
||||
'Revision %s': 'Verze %s',
|
||||
'Revision:': 'Verze:',
|
||||
'Role': 'Role',
|
||||
'Roles': 'Role',
|
||||
'Rows in Table': 'Záznamy v tabulce',
|
||||
'Rows selected': 'Záznamů zobrazeno',
|
||||
'rules are not defined': 'pravidla nejsou definována',
|
||||
'Run tests': 'Spustit testy',
|
||||
'Run tests in this file': 'Spustit testy v souboru',
|
||||
"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Spustí testy v tomto souboru (ke spuštění všech testů, použijte tlačítko 'test')",
|
||||
'Running on %s': 'Běží na %s',
|
||||
'Save': 'Uložit',
|
||||
'Save file:': 'Save file:',
|
||||
'Save file:': 'Uložit soubor:',
|
||||
'Save file: %s': 'Uložit soubor: %s',
|
||||
'Save model as...': 'Uložit model jako...',
|
||||
'Save via Ajax': 'Uložit pomocí Ajaxu',
|
||||
'Saved file hash:': 'hash uloženého souboru:',
|
||||
'Screenshot %s': 'Screenshot %s',
|
||||
'Search': 'Hledání',
|
||||
'Select Files to Package': 'Vybrat soubory pro package',
|
||||
'Semantic': 'Modul semantic',
|
||||
'Services': 'Služby',
|
||||
'session': 'session',
|
||||
'session expired': 'session expired',
|
||||
'session': 'session (sezení)',
|
||||
'session expired': 'vypršela session',
|
||||
'Session saved correctly': 'Session byla úspěšně uložena',
|
||||
'Session saved on session only': 'Session byla uložena jen pro toto sezení',
|
||||
'Set Breakpoint on %s at line %s: %s': 'Bod přerušení nastaven v souboru %s na řádce %s: %s',
|
||||
'shell': 'příkazová řádka',
|
||||
'Singular Form': 'Singular Form',
|
||||
'Showing %s to %s of %s %s found': 'Zobrazuji %s až %s z %s %s nalezených',
|
||||
'Singular Form': 'Jednotné číslo',
|
||||
'Site': 'Správa aplikací',
|
||||
'Size of cache:': 'Velikost cache:',
|
||||
'skip to generate': 'skip to generate',
|
||||
'skip to generate': 'přeskočit pro vytvoření',
|
||||
'some files could not be removed': 'některé soubory nelze odstranit',
|
||||
'Something went wrong please wait a few minutes before retrying': 'Něco se nepodařilo. Vyčkejte několik minut a pak zkuste znova',
|
||||
'Sorry, could not find mercurial installed': 'Bohužel mercurial není nainstalován.',
|
||||
'source : db': 'zdroj : db',
|
||||
'source : filesystem': 'zdroj : souborový systém',
|
||||
'Start a new app': 'Vytvořit novou aplikaci',
|
||||
'Start searching': 'Začít hledání',
|
||||
'Start wizard': 'Spustit průvodce',
|
||||
'state': 'stav',
|
||||
'Static': 'Static',
|
||||
'Static': 'Statické soubory',
|
||||
'static': 'statické soubory',
|
||||
'Static files': 'Statické soubory',
|
||||
'Statistics': 'Statistika',
|
||||
'Step': 'Step',
|
||||
'step': 'step',
|
||||
'stop': 'stop',
|
||||
'Step': 'Krok',
|
||||
'step': 'krok',
|
||||
'stop': 'zastavit',
|
||||
'Stylesheet': 'CSS styly',
|
||||
'submit': 'odeslat',
|
||||
'Submit': 'Odeslat',
|
||||
'successful': 'úspěšně',
|
||||
'Support': 'Podpora',
|
||||
'Sure you want to delete this object?': 'Opravdu chcete smazat tento objekt?',
|
||||
'switch to : db': 'přepnout na : db',
|
||||
'switch to : filesystem': 'přepnout na : souborový systém',
|
||||
'Tab width (# characters)': 'Šířka tabelátoru (# znaků)',
|
||||
'Table': 'tabulka',
|
||||
'Table name': 'Název tabulky',
|
||||
'Temporary': 'Dočasný',
|
||||
'test': 'test',
|
||||
'Testing application': 'Testing application',
|
||||
'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"Dotaz" je podmínka, například "db.tabulka1.pole1==\'hodnota\'". Podmínka "db.tabulka1.pole1==db.tabulka2.pole2" pak vytvoří SQL JOIN.',
|
||||
'Testing application': 'Zkušební aplikace',
|
||||
'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"Dotaz" je například "db.tabulka1.pole1==\'hodnota\'". Dotaz se dvěma tabulkami "db.tabulka1.pole1==db.tabulka2.pole2" vytvoří SQL JOIN.',
|
||||
'The app exists, was created by wizard, continue to overwrite!': 'Aplikace existuje, byla vytvořena průvodcem. Pokračováním ji přepíšete !',
|
||||
'The app exists, was NOT created by wizard, continue to overwrite!': 'Aplikace existuje, a NEBYLA vytvořena průvodcem. Pokračováním ji přepíšete !',
|
||||
'The application logic, each URL path is mapped in one exposed function in the controller': 'Logika aplikace: každá URL je mapována na funkci vystavovanou kontrolérem.',
|
||||
'The Core': 'Jádro (The Core)',
|
||||
'The data representation, define database tables and sets': 'Reprezentace dat: definovat tabulky databáze a záznamy',
|
||||
'The output of the file is a dictionary that was rendered by the view %s': 'Výstup ze souboru je slovník, který se zobrazil v pohledu %s.',
|
||||
'The presentations layer, views are also known as templates': 'Prezentační vrstva: pohledy či templaty (šablony)',
|
||||
'The data representation, define database tables and sets': 'Modely se vykonají při každém přístupu. Zde se obvykle definuje především reprezentace dat: Připojení k databázi a struktura tabulek databáze',
|
||||
'The output of the file is a dictionary that was rendered by the view %s': 'Výstup ze souboru je dictionary (slovník), který se zobrazil pomocí šablony (view) %s.',
|
||||
'The presentations layer, views are also known as templates': 'Prezentační vrstva: šablony (neboli pohledy, templaty, view). Mixuje Html, Python kód a Python data.',
|
||||
'The Views': 'Pohledy (The Views)',
|
||||
'There are no controllers': 'There are no controllers',
|
||||
'There are no modules': 'There are no modules',
|
||||
'Theme': 'Téma',
|
||||
'There are no controllers': 'Nejsou vytvořeny žádné controllery',
|
||||
'There are no models': 'Není vytvořen žádný model',
|
||||
'There are no modules': 'Nejsou přidány žádné moduly',
|
||||
'There are no plugins': 'Žádné moduly nejsou instalovány.',
|
||||
'There are no private files': 'Žádné soukromé soubory neexistují.',
|
||||
'There are no static files': 'There are no static files',
|
||||
'There are no translators, only default language is supported': 'There are no translators, only default language is supported',
|
||||
'There are no views': 'There are no views',
|
||||
'These files are not served, they are only available from within your app': 'Tyto soubory jsou klientům nepřístupné. K dispozici jsou pouze v rámci aplikace.',
|
||||
'These files are served without processing, your images go here': 'Tyto soubory jsou servírovány bez přídavné logiky, sem patří např. obrázky.',
|
||||
'There are no static files': 'Nejsou přidány žádné statické soubory',
|
||||
'There are no translators': 'Není vytvořen žádný překlad',
|
||||
'There are no translators, only default language is supported': 'Není vytvořen žádný překlad, je podporován jen defaultní jazyk',
|
||||
'There are no views': 'Nejsou vytvořeny žádné šablony (views)',
|
||||
'These files are not served, they are only available from within your app': 'Tyto soubory jsou přístupné jen běžící aplikaci. Nejsou dostupné uživatelům, ani se nekopírují do případného vývojového repozitáře. Hesla a citlivá nastavení nedávejte nikam jinam.',
|
||||
'These files are served without processing, your images go here': 'Tyto soubory jsou stahovány přímo, bez jakékoli přídavné logiky, sem patří např. obrázky.',
|
||||
'This App': 'Tato aplikace',
|
||||
'This is a copy of the scaffolding application': 'Toto je kopie aplikace skelet.',
|
||||
'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk',
|
||||
'This is the %(filename)s template': 'This is the %(filename)s template',
|
||||
"This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.": 'Tento debugger nebude pracovat správně, jestliže váš webový server nepracuje pomocí vláken nebo když používáte více procesů démonů.',
|
||||
'This is a copy of the scaffolding application': 'Toto je kopie vzorové aplikace.',
|
||||
'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk': 'Toto je experimentální vlastnost, která vyžaduje další testování. Návrat verze jen na vlastní riziko.',
|
||||
'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'Toto je experimentální vlastnost, která vyžaduje další testování. Upgrade verze jen na vlastní riziko.',
|
||||
'This is the %(filename)s template': 'Toto je šablona %(filename)s',
|
||||
"This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.": 'Tato stránka umožňuje potvrdit vaše změny do OpenShift aplikačního repozitáře a odeslat je do vaší cloud instance. Předpokladem je, že jste už vytvořili aplikační instanci pomocí Web2py předlohy a že tento repozitář máte někde na disku tak, aby k němu Web2py mělo přístup. Tato funkcionalita vyžaduje, aby byl instalován GitPython a aby mohl být nalezen pomocí cesty, se kterou Web2py pracuje.',
|
||||
'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.': 'Tato stránka umožňuje zkopírovat vaši aplikaci do Google App Engine cloudu. Pamatujte, že nejprve je třeba vytvořit indexy lokálně, čehož dosáhnete instalací Google appserver a jedním lokálním spuštěním aplikace. V opačném případě bude docházet k chybám vyhledávání. Pozor: v závislosti na rychlosti sítě může nasazení trvat dlouhou dobu. Pozor: bude přepsán váš soubor app.yaml. BĚHEM SPUŠTĚNÍ NESPOUŠTĚJTE PODRUHÉ.',
|
||||
'this page to see if a breakpoint was hit and debug interaction is required.': 'tuto stránku, abyste uviděli, zda se dosáhlo bodu přerušení.',
|
||||
'Ticket': 'Ticket',
|
||||
'Ticket ID': 'Ticket ID',
|
||||
'This will pull changes from the remote repo for application "%s"?': 'Toto stáhne (pull) změny ze vzdáleného repozitáře pro aplikaci "%s"?',
|
||||
'This will push changes to the remote repo for application "%s".': 'Toto nahraje (push) změny do vzdáleného repozitáře pro aplikaci "%s".',
|
||||
'Ticket': 'Tiket',
|
||||
'Ticket ID': 'ID tiketu',
|
||||
'Ticket Missing': 'Chybový tiket chybí',
|
||||
'Time in Cache (h:m:s)': 'Čas v Cache (h:m:s)',
|
||||
'Timestamp': 'Časové razítko',
|
||||
'to previous version.': 'k předchozí verzi.',
|
||||
'To create a plugin, name a file/folder plugin_[name]': 'Zásuvný modul vytvoříte tak, že pojmenujete soubor/adresář plugin_[jméno modulu]',
|
||||
'To create a plugin, name a file/folder plugin_[name]': 'Zásuvný modul vytvoříte tak, že pojmenujete skupinu souborů nebo adresář(e) plugin_[jméno modulu]',
|
||||
'To emulate a breakpoint programatically, write:': 'K nastavení bodu přerušení v kódu programu, napište:',
|
||||
'to use the debugger!': ', abyste mohli ladící program používat!',
|
||||
'toggle breakpoint': 'vyp./zap. bod přerušení',
|
||||
'Toggle comment': 'Přepnout komentář',
|
||||
'Toggle Fullscreen': 'Na celou obrazovku a zpět',
|
||||
'too short': 'Příliš krátké',
|
||||
'Traceback': 'Traceback',
|
||||
'Traceback': 'Hierarchie volání',
|
||||
'Translation strings for the application': 'Překlad textů pro aplikaci',
|
||||
'try something like': 'try something like',
|
||||
'try something like': 'zkuste něco jako',
|
||||
'Try the mobile interface': 'Zkuste rozhraní pro mobilní zařízení',
|
||||
'try view': 'try view',
|
||||
'try view': 'vyzkoušet šablonu (view)',
|
||||
'Twitter': 'Twitter',
|
||||
'Type python statement in here and hit Return (Enter) to execute it.': 'Type python statement in here and hit Return (Enter) to execute it.',
|
||||
'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.',
|
||||
'Unable to check for upgrades': 'Unable to check for upgrades',
|
||||
'Type PDB debugger command in here and hit Return (Enter) to execute it.': 'Zapište příkaz PDB debuggeru a stiskněte Return (Enter) pro jeho provedení.',
|
||||
'Type python statement in here and hit Return (Enter) to execute it.': 'Zapište příkaz pythonu a stiskněte Return (Enter) pro jeho provedení.',
|
||||
'Type some Python code in here and hit Return (Enter) to execute it.': 'Zapište kód v jazyce python a stiskněte Return (Enter) pro jeho provedení.',
|
||||
'Unable to check for upgrades': 'Nelze zjistit informaci o aktualizacích',
|
||||
'unable to create application "%s"': 'nelze vytvořit aplikaci "%s"',
|
||||
'unable to delete file "%(filename)s"': 'nelze zrušit soubor "%(filename)s"',
|
||||
'unable to delete file plugin "%(plugin)s"': 'nelze zrušit plugin "%(plugin)s"',
|
||||
'Unable to determine the line number!': 'Nelze určit číslo řádky!',
|
||||
'Unable to download app because:': 'Nelze stáhnout aplikaci, protože:',
|
||||
'unable to download layout': 'nelze stáhnout šablonu (layout)',
|
||||
'unable to download plugin: %s': 'nelze stáhnout plugin: %s',
|
||||
'Unable to download the list of plugins': 'Nelze stáhnout seznam pluginů',
|
||||
'unable to install plugin "%s"': 'nelze instalovat plugin "%s"',
|
||||
'unable to parse csv file': 'csv soubor nedá sa zpracovat',
|
||||
'unable to uninstall "%s"': 'nelze instalovat "%s"',
|
||||
'unable to upgrade because "%s"': 'nelze upgradovat, protože "%s"',
|
||||
'uncheck all': 'vše odznačit',
|
||||
'Uninstall': 'Odinstalovat',
|
||||
'Unsupported webserver working mode: %s': 'Nepodporovaný mód webového serveru: %s',
|
||||
'update': 'aktualizovat',
|
||||
'update all languages': 'aktualizovat všechny jazyky',
|
||||
'update all languages': 'aktualizovat všechny jazyky o nové texty ze zdrojových souborů',
|
||||
'Update:': 'Upravit:',
|
||||
'Upgrade': 'Upgrade',
|
||||
'upgrade now': 'upgrade now',
|
||||
'upgrade now to %s': 'upgrade now to %s',
|
||||
'upgrade now': 'upgradovat nyní',
|
||||
'upgrade now to %s': 'upgradovat nyní na %s',
|
||||
'upload': 'nahrát',
|
||||
'Upload': 'Upload',
|
||||
'Upload': 'Upload (nahrát)',
|
||||
'Upload a package:': 'Nahrát balík:',
|
||||
'Upload and install packed application': 'Nahrát a instalovat zabalenou aplikaci',
|
||||
'upload file:': 'nahrát soubor:',
|
||||
'upload plugin file:': 'nahrát soubor modulu:',
|
||||
'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Použijte (...)&(...) pro AND, (...)|(...) pro OR a ~(...) pro NOT pro sestavení složitějších dotazů.',
|
||||
'User': 'Uživatel',
|
||||
'User %(id)s Logged-in': 'Uživatel %(id)s přihlášen',
|
||||
'User %(id)s Logged-out': 'Uživatel %(id)s odhlášen',
|
||||
'User %(id)s Password changed': 'Uživatel %(id)s změnil heslo',
|
||||
@@ -451,30 +672,45 @@
|
||||
'User %(id)s Username retrieved': 'Uživatel %(id)s si nachal zaslat přihlašovací jméno',
|
||||
'User ID': 'ID uživatele',
|
||||
'Username': 'Přihlašovací jméno',
|
||||
'variables': 'variables',
|
||||
'Users': 'Uživatelé',
|
||||
'Using the shell may lock the database to other users of this app.': 'Použití příkazového shellu může uzamknout databázi ostatním uživatelům této aplikace.',
|
||||
'variables': 'proměnné',
|
||||
'Verify Password': 'Zopakujte heslo',
|
||||
'Version': 'Verze',
|
||||
'Version %s.%s.%s (%s) %s': 'Verze %s.%s.%s (%s) %s',
|
||||
'Versioning': 'Verzování',
|
||||
'Videos': 'Videa',
|
||||
'View': 'Pohled (View)',
|
||||
'Views': 'Pohledy',
|
||||
'views': 'pohledy',
|
||||
'Web Framework': 'Web Framework',
|
||||
'View': 'Šablona (View)',
|
||||
'Views': 'Šablony (Views)',
|
||||
'views': 'šablony (views)',
|
||||
'Warning!': 'Pozor!',
|
||||
'WARNING:': 'POZOR:',
|
||||
'WARNING: The following views could not be compiled:': 'POZOR: Následující šablony se nepodařilo zkompilovat:',
|
||||
'Web Framework': 'Webový framework',
|
||||
'web2py Admin Password': 'web2py Heslo administrátora',
|
||||
'web2py apps to deploy': 'web2py aplikace k nasazení',
|
||||
'web2py Debugger': 'web2py Debugger',
|
||||
'web2py downgrade': 'web2py downgrade',
|
||||
'web2py is up to date': 'Máte aktuální verzi web2py.',
|
||||
'web2py online debugger': 'Ladící online web2py program',
|
||||
'web2py Recent Tweets': 'Štěbetání na Twitteru o web2py',
|
||||
'web2py upgrade': 'web2py upgrade',
|
||||
'web2py upgraded; please restart it': 'web2py upgraded; please restart it',
|
||||
'web2py Recent Tweets': 'Nedávné tweety na Twitteru o web2py',
|
||||
'web2py upgrade': 'aktualizace Web2py',
|
||||
'web2py upgraded; please restart it': 'Web2py bylo aktualizováno; prosím restarujte jej',
|
||||
'Welcome': 'Vítejte',
|
||||
'Welcome to web2py': 'Vitejte ve web2py',
|
||||
'Welcome to web2py!': 'Vítejte ve web2py!',
|
||||
'Welcome to web2py': 'Vitejte ve Web2py aplikaci.',
|
||||
'Welcome to web2py!': 'Vítejte ve Web2py aplikaci.',
|
||||
'Which called the function %s located in the file %s': 'která zavolala funkci %s v souboru (kontroléru) %s.',
|
||||
'WSGI reference name': 'jméno WSGI reference',
|
||||
'YES': 'ANO',
|
||||
'Yes': 'Ano',
|
||||
'You are successfully running web2py': 'Úspěšně jste spustili web2py.',
|
||||
'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': 'Nastavovat a mazat body přerušení je též možno v rámci editování zdrojového souboru přes tlačítko Vyp./Zap. bod přerušení',
|
||||
'You can inspect variables using the console bellow': 'Níže pomocí příkazové řádky si můžete prohlédnout proměnné',
|
||||
'You can inspect variables using the console below': 'You can inspect variables using the console below',
|
||||
'You can modify this application and adapt it to your needs': 'Tuto aplikaci si můžete upravit a přizpůsobit ji svým potřebám.',
|
||||
'You have one more login attempt before you are locked out': 'Máte jen jeden další pokus k přihlášení před zablokováním',
|
||||
'You need to set up and reach a': 'Je třeba nejprve nastavit a dojít až na',
|
||||
'You only need these if you have already registered': 'Toto potřebujete jen tehdy, jestliže jste se už registroval(a)',
|
||||
'You visited the url %s': 'Navštívili jste stránku %s,',
|
||||
'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Aplikace bude blokována než se klikne na jedno z tlačítek (další, krok, pokračovat, atd.)',
|
||||
'You can inspect variables using the console bellow': 'Níže pomocí příkazové řádky si můžete prohlédnout proměnné',
|
||||
}
|
||||
|
||||
@@ -12,24 +12,29 @@ def button(href, label):
|
||||
if is_mobile:
|
||||
ret = A_button(SPAN(label), _href=href)
|
||||
else:
|
||||
ret = A(SPAN(label), _class='btn rounded', _href=href)
|
||||
ret = A(SPAN(label), _class='button btn', _href=href)
|
||||
return ret
|
||||
|
||||
def button_enable(href, app):
|
||||
if os.path.exists(os.path.join(apath(app, r=request), 'DISABLED')):
|
||||
text, classes = T("Enable"), "btn rounded red"
|
||||
label = SPAN(T('Enable'), _style='color:red')
|
||||
else:
|
||||
text, classes = T("Disable"), "btn rounded gree"
|
||||
label = SPAN(T('Disable'), _style='color:green')
|
||||
id = 'enable_' + app
|
||||
return A(text, _class=classes, _id=id, callback=href, target=id)
|
||||
return A(label, _class='button btn', _id=id, callback=href, target=id)
|
||||
|
||||
def sp_button(href, label):
|
||||
if request.user_agent().get('is_mobile'):
|
||||
ret = A_button(SPAN(label), _href=href)
|
||||
else:
|
||||
ret = A(SPAN(label), _class='btn pink rounded', _href=href)
|
||||
ret = A(SPAN(label), _class='button special btn btn-inverse', _href=href)
|
||||
return ret
|
||||
|
||||
def helpicon():
|
||||
return IMG(_src=URL('static', 'images/help.png'), _alt='help')
|
||||
|
||||
def searchbox(elementid):
|
||||
return SPAN(LABEL(IMG(_id="search_start", _src=URL('static', 'images/search.png'), _alt=T('filter')),
|
||||
_class='icon', _for=elementid), ' ',
|
||||
INPUT(_id=elementid, _type='text', _size=12, _class="input-medium"),
|
||||
_class="searchbox")
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,489 @@
|
||||
|
||||
/*=============================================================
|
||||
GENERAL
|
||||
==============================================================*/
|
||||
body { /*remember to account for the hidden area underneath
|
||||
fixed navbar by adding at least 40px padding to the <body>.
|
||||
Be sure to add this after the core Bootstrap CSS
|
||||
and before the optional responsive CSS.
|
||||
An alternative solution is to set top-margin to div#main padding-top:60px; comment this for alternative solution*/ height:auto; /*uncomment this for alternative solution*/ }
|
||||
|
||||
/*=============================================================
|
||||
BOOTSTRAP ICONS FOLDER FIX
|
||||
==============================================================*/
|
||||
[class^="icon-"], [class*=" icon-"] { /* right folder for bootstrap black images/icons*/ background-image:url("../images/glyphicons-halflings.png") }
|
||||
|
||||
.icon-white, .nav-tabs>.active >a>[class^="icon-"], .nav-tabs>.active>a>[class*=" icon-"], .nav-pills>.active>a>[class^="icon-"], .nav-pills>.active>a>[class*=" icon-"], .nav-list>.active>a>[class^="icon-"], .nav-list>.active>a>[class*=" icon-"], .navbar-inverse .nav>.active>a>[class^="icon-"], .navbar-inverse .nav>.active>a>[class*=" icon-"], .dropdown-menu>li>a:hover>[class^="icon-"], .dropdown-menu>li>a:hover>[class*=" icon-"], .dropdown-menu>.active>a>[class^="icon-"], .dropdown-menu>.active>a>[class*=" icon-"] { /* right folder for bootstrap white images/icons*/ background-image:url("../images/glyphicons-halflings-white.png"); }
|
||||
|
||||
/*=============================================================
|
||||
INPUT BORDER HIGHLIGHT WHEN INPUT IS FOCUSED
|
||||
==============================================================*/
|
||||
textarea:focus, input[type="text"]:focus, input[type="password"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="date"]:focus, input[type="month"]:focus, input[type="time"]:focus, input[type="week"]:focus, input[type="number"]:focus, input[type="email"]:focus, input[type="url"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="color"]:focus, input[type="file"]:focus, select:focus, .uneditable-input:focus { /* outline color*/ border-color:rgba(232, 149, 60, 0.8); outline:0; /*outline:thin dotted \9;*/ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(232, 149, 60, 0.6); -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(232, 149, 60, 0.6); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(232, 149, 60, 0.6); }
|
||||
|
||||
.web2py_grid .dropdown-menu li > a:hover, .web2py_grid .dropdown-menu li > a:focus { filter:progid:DXImageTransform.Microsoft.gradient(enabled=false); /* IE6-9*/ background-image:none; background-color:#E8953C; }
|
||||
|
||||
/*=============================================================
|
||||
COLOR OF LINKS
|
||||
==============================================================*/
|
||||
a, a:hover { color:#E8953C; text-decoration:none; }
|
||||
|
||||
a:hover { color:#e2821b; }
|
||||
|
||||
/*=============================================================
|
||||
CONTROLS and CONTAINERS
|
||||
==============================================================*/
|
||||
.row-buttons .btn { margin-bottom:7px; }
|
||||
|
||||
.sidebar .box { clear:right; margin-top:2em; border-top:1px solid #d1d1d1; padding:0 1em; }
|
||||
|
||||
.pwdchange>.button { margin-bottom:10px; }
|
||||
|
||||
input[type="file"] { margin-bottom:9px; }
|
||||
|
||||
.form-inline input[type="file"] { margin-bottom:0px; }
|
||||
|
||||
input + .help-block { margin-top:-10px; margin-bottom:4px; }
|
||||
|
||||
#confirm_form input.btn, .generatedbyw2p input { margin-right:4px; }
|
||||
|
||||
a[rel='tooltip'] span, div[rel='tooltip'] span { display:none; margin-left:-9999px; }
|
||||
|
||||
/*in-page browsing*/
|
||||
[rel="pagebookmark"] { position:relative; }
|
||||
|
||||
[rel="pagebookmark"]>.component { cursor:pointer; }
|
||||
|
||||
[rel="pagebookmark"]>.hashstick { position:absolute; top:-54px; left:-9999px; visibility:visible; }
|
||||
|
||||
/* following 2 rules set the style of a small button for going to top of page*/
|
||||
.tophashlink.btn { padding:2px 3px; visibility:hidden; }
|
||||
|
||||
.hashstick:target+.tophashlink.btn { visibility:visible; }
|
||||
|
||||
ul.act_edit { margin-top:4px; margin-left:20px; }
|
||||
|
||||
ul.act_edit .btn { margin-top:4px; margin-bottom:4px; }
|
||||
|
||||
ul.act_edit .file>a { white-space:pre; }
|
||||
|
||||
.right-full { text-align:right; }
|
||||
|
||||
.searchbox, .searchbox label, .searchbox input { display:inline-block; }
|
||||
|
||||
.buttons-row .btn { margin-bottom:9px; }
|
||||
|
||||
.li-controls { display:inline-block; width:180px; vertical-align:middle; }
|
||||
|
||||
.celled { display:inline-block; padding: 0 0 0 4px; vertical-align:top; margin-top:4px; width:700px; }
|
||||
|
||||
.folder { list-style-type:none; #border-left: 1px dotted #AAA; }
|
||||
|
||||
.folder li { list-style-type:none; }
|
||||
|
||||
.folder>i { display:inline-block; width:5px; height:5px; border:1px solid; background-color:#FAA732; margin-left:-4px; margin-top:-2px; border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); border-radius:1px; }
|
||||
|
||||
.folder>i+a { padding-left:0.5em; }
|
||||
|
||||
.folder ul { margin-top:0.5em; margin-bottom:0.5em; }
|
||||
|
||||
.controls-inline .btn { margin-right:5px; }
|
||||
|
||||
div.web2py_counter.span6 { min-height:24px; text-align:right; }
|
||||
|
||||
.pagination { margin:0; }
|
||||
|
||||
.table { margin-bottom:10px; }
|
||||
|
||||
.row_buttons .btn { margin-right:4px; }
|
||||
|
||||
.editor-bar-column { display:inline-block; vertical-align:top; margin-right:4px; }
|
||||
|
||||
.editor-bar-column .input-long { width:270px; }
|
||||
|
||||
.editor-bar-column .input-normal { width:206px; }
|
||||
|
||||
.keybindings li { margin-bottom:0.5em; }
|
||||
|
||||
.keybindings span { padding:0.3em; border:1px solid transparent; vertical-align:middle; }
|
||||
|
||||
.teletype-text { font-family:monospace; font-weight:bold; font-style:normal; border-color:#999; background:#333; color:#DDD; -moz-border-radius:0.3em; border-radius:0.3em; }
|
||||
|
||||
.edit_language .tab_row div { display:inline-block; vertical-align:top; margin-right:4px; }
|
||||
|
||||
.edit_language .fake-input { height:18px; padding:4px; font-size:13px; line-height:18px; overflow:hidden; white-space:nowrap; display:inline-block; margin-bottom:9px; }
|
||||
|
||||
.test h3 { padding-left:9px; margin:0; font-size:16px; line-height:1; border-left:9px solid transparent; }
|
||||
|
||||
.test h3.passed { border-color:#009900; }
|
||||
|
||||
.test h3.failed { border-color:#CC0000; }
|
||||
|
||||
.test h3.nodoctests { border-color:#CCCC99; }
|
||||
|
||||
.test .test_report { width:100%; overflow:auto; }
|
||||
|
||||
.test_report pre { white-space:pre; }
|
||||
|
||||
.test div[id^="output_"]>h2 { font-size:18px; line-height:1; color:grey; }
|
||||
|
||||
div.center { text-align:center; }
|
||||
|
||||
.delete h2 { word-wrap:break-word; }
|
||||
|
||||
/*=============================================================
|
||||
SHELL
|
||||
==============================================================*/
|
||||
.shell .output-wrapper { width:100%; height:30em; border:1px solid #333; }
|
||||
|
||||
.shell .prompt-wrapper { float:left; width:100%; overflow:hidden; height:auto; border:1px solid #333; }
|
||||
|
||||
.shell .prompt-container { margin-left:2.5em; }
|
||||
|
||||
.shell #caret { width:2.5em; float:left; margin-left:-100%; }
|
||||
|
||||
.shell #shellwrapper { background:white; color:#E8953C; width:100%; margin:1em 0; border:0; }
|
||||
|
||||
.shell #output, .shell .prompt { color:#E8953C; background:white; resize:none; border:none; width:100%; height:100%; cursor:default; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; }
|
||||
|
||||
.shell #output:focus, .shell .prompt:focus { border-color:transparent; outline:0; -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; }
|
||||
|
||||
.shell #output pre { color: #E8953C; }
|
||||
|
||||
.shell #autoscroll { cursor:pointer; float:right; }
|
||||
|
||||
.shell .prompt, .shell #output, .shell #caret { font-size: 11pt; padding: 6px; padding-right: 0em; }
|
||||
|
||||
.shell #caret { padding-top:9px; }
|
||||
|
||||
.shell .prompt, .shell #output, .shell pre, .shell #caret { font-family: monospace; }
|
||||
|
||||
.shell a[rel="tooltip"] { margin-left:8px; }
|
||||
|
||||
/*=============================================================
|
||||
PEEK
|
||||
==============================================================*/
|
||||
.peek .code-wrapper { width:100%; overflow:auto; white-space:pre; }
|
||||
|
||||
.peek table td pre { word-break:normal; white-space:pre; }
|
||||
|
||||
/*=============================================================
|
||||
FOOTER
|
||||
==============================================================*/
|
||||
#footer { border-top:1px solid; text-align:center; padding:1em 0; }
|
||||
|
||||
#footer span, #footer select { display:inline-block; margin-bottom:0; vertical-align:middle; }
|
||||
|
||||
#footer select { width:auto; }
|
||||
|
||||
/*=============================================================
|
||||
MAIN
|
||||
==============================================================*/
|
||||
#main { margin-top:60px; /*uncomment this for alternative solution to hidden area underneath fixed navbar issue*/ margin-bottom:60px; }
|
||||
|
||||
/*=============================================================
|
||||
WIZARD
|
||||
==============================================================*/
|
||||
#wizard_nav .box { border-bottom:1px dotted; }
|
||||
|
||||
#wizard_nav li { margin-left:1em; margin-top:0.5em; }
|
||||
|
||||
.step textarea { width:auto; }
|
||||
|
||||
select[name='layout_theme'] { vertical-align:top; }
|
||||
|
||||
img#preview { margin-bottom:9px; }
|
||||
|
||||
/* multiselect customization*/
|
||||
.ms-container { margin-bottom:5px; }
|
||||
|
||||
.ms-selectable, .step .ms-selection { text-align:center; }
|
||||
|
||||
.ms-list { text-align:left; background:white; }
|
||||
|
||||
.ms-container li.ms-elem-selectable:not(.disabled).ms-hover, .ms-container .ms-selection li:not(.disabled).ms-hover { background-color:#E8953C; }
|
||||
|
||||
.ms-container .ms-selectable { margin-right:25px; }
|
||||
|
||||
.ms-container .ms-selectable, .ms-container .ms-selection { background:transparent; }
|
||||
|
||||
.ms-container .ms-list.ms-focus { border-color:rgba(232, 149, 60, 0.8); -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(232, 149, 60, 0.6); -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(232, 149, 60, 0.6); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(232, 149, 60, 0.6); }
|
||||
|
||||
/* grow_input*/
|
||||
ul[id$="_grow_input"] { margin-left:0; }
|
||||
|
||||
/* generate_form*/
|
||||
#generate_form .control-group { margin-bottom:0; }
|
||||
|
||||
#generate_form .control-label { text-align:left; }
|
||||
|
||||
#generate_form .controls { padding-left:18px; margin-left:0; }
|
||||
|
||||
#generate_form .control-label.empty { width:142px; }
|
||||
|
||||
.step [rel="pagebookmark"]>.hashstick { display:none; }
|
||||
|
||||
/*generated page*/
|
||||
.generated iframe { border:1px inset #e3e3e3; }
|
||||
|
||||
/*=============================================================
|
||||
ERRORS TABLE / TICKET PAGE
|
||||
==============================================================*/
|
||||
.tablebar { margin:7px 0 7px 0; }
|
||||
|
||||
.tablebar input { margin-right:27px; }
|
||||
|
||||
.tablebar span { vertical-align:bottom; }
|
||||
|
||||
.table th { background: #e9e9e9; background: -moz-linear-gradient(top, #FAFAFA 0%, #E9E9E9 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #FAFAFA), color-stop(100%, #E9E9E9)); background: -webkit-linear-gradient(top, #FAFAFA 0%, #E9E9E9 100%); background: -o-linear-gradient(top, #FAFAFA 0%, #E9E9E9 100%); background: -ms-linear-gradient(top, #FAFAFA 0%, #E9E9E9 100%); background: linear-gradient(top, #FAFAFA 0%, #E9E9E9 100%); filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FAFAFA', endColorstr='#E9E9E9'); -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#FAFAFA', endColorstr='#E9E9E9')"; /*font-size:10px; color:#444; text-transform:uppercase;*/ }
|
||||
|
||||
td.cbcentered, th.cbcentered { text-align:center; }
|
||||
|
||||
td.cbcentered>input, th.cbcentered>input { margin-top:-1px; }
|
||||
|
||||
.traceback div { }
|
||||
|
||||
.ticket_code>table td:first-child { border-left:0; }
|
||||
|
||||
#trck_errors table td pre { word-break:normal; white-space:pre; }
|
||||
|
||||
.inspect pre, .errorsource pre { word-break:normal; white-space:pre; }
|
||||
|
||||
.ticket_code { background-color:lightyellow; }
|
||||
|
||||
.ticket_code table, .ticket_code td { border-width:0px; border-collapse:collapse; width:100%; }
|
||||
|
||||
.ticket_code tbody tr:hover td { background-color:transparent; }
|
||||
|
||||
/*=============================================================
|
||||
FLOT GRAPHS
|
||||
==============================================================*/
|
||||
.about #placeholder { width:auto; max-width:600px; height:300px; position:relative; margin:0 auto; /* for centering*/ }
|
||||
|
||||
/*=============================================================
|
||||
THE GRID
|
||||
==============================================================*/
|
||||
#w2p_query_panel { min-width:20px; min-height:20px; padding:10px; margin-top:1em; background-color:#f5f5f5; border: 1px solid #e3e3e3; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); }
|
||||
|
||||
#w2p_query_panel select, #w2p_query_panel input { margin-bottom:0; margin-right:4px; }
|
||||
|
||||
.web2py_grid .hidden { visibility:visible; }
|
||||
|
||||
.qry_pnl_btns { display:inline-block; }
|
||||
|
||||
#w2p_grid_addbtn, #w2p_search-form { margin-top:9px; margin-bottom:9px; }
|
||||
|
||||
#w2p_search-form { margin-bottom:0; }
|
||||
|
||||
#w2p_search-form form { margin-bottom:0; }
|
||||
|
||||
/*----- translate page ---*/
|
||||
.languageform input { margin-bottom:0; }
|
||||
|
||||
.languageform input.untranslated { background-color:#FC0; }
|
||||
|
||||
/*=============================================================
|
||||
MASKED UPLOAD INPUT (NO BOOTSTRAP RELATED)
|
||||
==============================================================*/
|
||||
#appupdate_file.masked {
|
||||
margin: 0;
|
||||
opacity: 0;
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; /* IE 8 */
|
||||
filter: alpha(opacity=0); /* IE 7 */
|
||||
font-size: 100px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 410;
|
||||
}
|
||||
|
||||
#fileselect {
|
||||
padding: 4px 6px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
color: #555;
|
||||
cursor: default;
|
||||
position: relative;
|
||||
z-index: 400;
|
||||
font-size: 14px;
|
||||
background-color: #fff;
|
||||
margin-bottom: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#fileselect span {
|
||||
position: absolute;
|
||||
left: 6px;
|
||||
top: 4px;
|
||||
}
|
||||
|
||||
.uploadbtn {
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
right: 3px;
|
||||
}
|
||||
|
||||
.txtPlaceholder {
|
||||
font-style: italic;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
/*=============================================================
|
||||
EDIT PAGE SLIDING FILES MENU
|
||||
==============================================================*/
|
||||
@media (max-width: 979px) {
|
||||
body.edit div#header {position:relative; z-index: 1030 !important;}
|
||||
}
|
||||
|
||||
#editor_area, #edit_placeholder {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#editor_area {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#files {
|
||||
width: auto;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
z-index: 1031;
|
||||
border-right: 3px solid #000;
|
||||
/* animation (it doesn't work in IE<10) */
|
||||
-moz-transition: all 0.4s;
|
||||
-webkit-transition: all 0.4s;
|
||||
-o-transition: all 0.4s;
|
||||
transition: all 0.4s;
|
||||
}
|
||||
|
||||
#files:hover, #files:focus {
|
||||
left: 0px !important;
|
||||
}
|
||||
|
||||
#files, .files-toggle {
|
||||
background: #1b1b1b;
|
||||
opacity: 0.98;
|
||||
}
|
||||
|
||||
.files-toggle {
|
||||
width: 18px;
|
||||
height: 86px;
|
||||
border-radius: 0px 4px 4px 0px;
|
||||
color: #999;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: -18px;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
width: 18px;
|
||||
height: 70px;
|
||||
background: url(../images/files_toggle.png) no-repeat;
|
||||
}
|
||||
|
||||
.files-menu {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#filelist {
|
||||
position: relative;
|
||||
top: 60px;
|
||||
padding-bottom: 60px;
|
||||
}
|
||||
|
||||
#filelist li {
|
||||
padding-right: 8px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#filelist li>a {
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
/*=============================================================
|
||||
MEDIA QUERIES
|
||||
==============================================================*/
|
||||
@media (max-width: 800px) { .step [rel="pagebookmark"]>.hashstick { /*top:-54px;*/ display:block; }
|
||||
|
||||
}
|
||||
|
||||
@media (max-width: 767px) { [rel="pagebookmark"]>.hashstick { top:0; }
|
||||
|
||||
/*-----------------------------------
|
||||
main
|
||||
-------------------------------------*/
|
||||
#main { margin-top:0; }
|
||||
|
||||
/*-----------------------------------
|
||||
footer
|
||||
-------------------------------------*/
|
||||
#footer { margin-left: -20px; margin-right: -20px; padding-left: 20px; padding-right: 20px; }
|
||||
|
||||
/*-----------------------------------
|
||||
errors page
|
||||
-------------------------------------*/
|
||||
#trck_errors { table-layout:fixed; }
|
||||
|
||||
#trck_errors .column1 { width:20px; }
|
||||
|
||||
#trck_errors .column2 { width:45px; }
|
||||
|
||||
#trck_errors .column3 { width:150px; }
|
||||
|
||||
#trck_errors .columnN { width:55px; }
|
||||
|
||||
#trck_errors .columnN1 { width:138px; }
|
||||
|
||||
.ticket_code, .inspect.resp1, .inspect.controls pre, .errorsource { width:100%; overflow:auto; }
|
||||
|
||||
.ticket_code>table { width:100%; }
|
||||
|
||||
.celled { width:320px; }
|
||||
|
||||
}
|
||||
|
||||
@media (max-width: 480px) { .qry_pnl_btns { display:block; margin-top:4px; }
|
||||
|
||||
/*-----------------------------------
|
||||
wizard
|
||||
-------------------------------------*/
|
||||
#generate_form .control-label { float:left; width:160px; padding-top:5px; }
|
||||
|
||||
.inspect>code { display:block; white-space:normal; }
|
||||
|
||||
.li-controls { }
|
||||
|
||||
.celled { width:165px; }
|
||||
|
||||
}
|
||||
|
||||
/*-----------------------------------
|
||||
miscellaneous
|
||||
-------------------------------------*/
|
||||
h4.editableapp, h4.currentapp { padding: 5px 0 5px 54px; display: inline; }
|
||||
|
||||
h4.editableapp { background: #fff url(../images/folder.png) no-repeat; }
|
||||
|
||||
h4.currentapp { background: #fff url(../images/folder_locked.png) no-repeat; }
|
||||
|
||||
.w2p_flash { position:fixed; width:50%; top:49px; left:25%; right:25%; cursor:default; text-align:center; z-index:5620; }
|
||||
span#closeflash {position:absolute; top:1px; right:-1px; font-size:150%; border:1px solid black; border-color: transparent transparent #fbeed5 #fbeed5; border-radius: 0 0 0 4px; width:22px; }
|
||||
span#closeflash:hover {font-weight:bold; cursor:pointer; }
|
||||
|
||||
table.twitter{ background-color: transparent; }
|
||||
table.twitter tr td {vertical-align: top; padding: 5px; }
|
||||
table.twitter tr { border-bottom: 1px solid #a0a0a0; }
|
||||
|
||||
div.error_wrapper {margin-top:-10px; margin-bottom:8px; padding-left:2px; color:#d62e2b; }
|
||||
|
||||
.twitter-timeline >iframe{padding: 1em 0;}
|
||||
@@ -1,11 +1,7 @@
|
||||
.calendar {z-index:2000;position:relative;margin-top:140px;display:none;background-color:white;border:1px solid #000;color:#000;cursor:default;box-shadow:0 0 10px #666}.calendar * {text-align: center;font-size:10px!important}
|
||||
.calendar table {border-collapse:collapse}
|
||||
.calendar tbody tr:hover {background-color:#fbf6d9}
|
||||
.calendar td, th {padding:5px; vertical-align:top; text-align:left; border:0}
|
||||
.calendar thead tr {background-color:#f1f1f1}
|
||||
.calendar tbody tr {border-bottom:2px solid #f1f1f1}
|
||||
.calendar th {font-weight:string; padding:5px; vertical-align:bottom; text-align:left}
|
||||
.calendar thead th {vertical-align:bottom}
|
||||
.calendar tbody th {vertical-align:top}
|
||||
.calendar{z-index:99;position:relative;display:none;background:#fff;border:2px solid #000;font-size:11px;color:#000;cursor:default;font-family:Arial,Helvetica,sans-serif;
|
||||
border-radius: 10px;
|
||||
-moz-border-radius: 10px;
|
||||
-webkit-border-radius: 10px;
|
||||
}.calendar table{margin:0px;font-size:11px;color:#000;cursor:default;font-family:tahoma,verdana,sans-serif;}.calendar .button{text-align:center;padding:1px;color:#fff;background:#000;}.calendar .nav{background:#000;color:#fff}.calendar thead .title{font-weight:bold;padding:1px;background:#000;color:#fff;text-align:center;}.calendar thead .name{padding:2px;text-align:center;background:#bbb;}.calendar thead .weekend{color:#f00;}.calendar thead .hilite {background-color:#666;}.calendar thead .active{padding:2px 0 0 2px;background-color:#c4c0b8;}.calendar tbody .day{width:2em;text-align:right;padding:2px 4px 2px 2px;}.calendar tbody .day.othermonth{color:#aaa;}.calendar tbody .day.othermonth.oweekend{color:#faa;}.calendar table .wn{padding:2px 3px 2px 2px;background:#bbb;}.calendar tbody .rowhilite td{background:#ddd;}.calendar tbody td.hilite{background:#bbb;}.calendar tbody td.active{background:#bbb;}.calendar tbody td.selected{font-weight:bold;background:#ddd;}.calendar tbody td.weekend{color:#f00;}.calendar tbody td.today{font-weight:bold;color:#00f;}.calendar tbody .disabled{color:#999;}.calendar tbody .emptycell{visibility:hidden;}.calendar tbody .emptyrow{display:none;}.calendar tfoot .ttip{background:#bbb;padding:1px;background:#000;color:#fff;text-align:center;}.calendar tfoot .hilite{background:#ddd;}.calendar tfoot .active{}.calendar .combo{position:absolute;display:none;width:4em;top:0;left:0;cursor:default;background:#e4e0d8;padding:1px;z-index:100;}.calendar .combo .label,.calendar .combo .label-IEfix{text-align:center;padding:1px;}.calendar .combo .label-IEfix{width:4em;}.calendar .combo .active{background:#c4c0b8;}.calendar .combo .hilite{background:#048;color:#fea;}.calendar td.time{padding:1px 0;text-align:center;background-color:#bbb;}.calendar td.time .hour,.calendar td.time .minute,.calendar td.time .ampm{padding:0 3px 0 4px;font-weight:bold;}.calendar td.time .ampm{text-align:center;}.calendar td.time .colon{padding:0 2px 0 3px;font-weight:bold;}.calendar td.time span.hilite{}.calendar td.time span.active{border-color:#f00;background-color:#000;color:#0f0;}.hour,.minute{font-size:2em;}
|
||||
|
||||
#CP_hourcont{z-index:2000;padding:0;position:absolute;border:1px dashed #666;background-color:#eee;display:none;}#CP_minutecont{z-index:2000;background-color:#ddd;padding:1px;position:absolute;width:45px;display:none;}.floatleft{float:left;}.CP_hour{z-index:2000;padding:1px;font-family:Arial,Helvetica,sans-serif;font-size:9px;white-space:nowrap;cursor:pointer;width:35px;}.CP_minute{z-index:2000;padding:1px;font-family:Arial,Helvetica,sans-serif;font-size:9px;white-space:nowrap;cursor:pointer;width:auto;}.CP_over{background-color:#fff;z-index:2000}
|
||||
#CP_hourcont{z-index:99;padding:0;position:absolute;border:1px dashed #666;background-color:#eee;display:none;}#CP_minutecont{z-index:99;background-color:#ddd;padding:1px;position:absolute;width:45px;display:none;}.floatleft{float:left;}.CP_hour{z-index:99;padding:1px;font-family:Arial,Helvetica,sans-serif;font-size:9px;white-space:nowrap;cursor:pointer;width:35px;}.CP_minute{z-index:99;padding:1px;font-family:Arial,Helvetica,sans-serif;font-size:9px;white-space:nowrap;cursor:pointer;width:auto;}.CP_over{background-color:#fff;z-index:99}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 8.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+5
-5
File diff suppressed because one or more lines are too long
@@ -0,0 +1,33 @@
|
||||
// this code improves bootstrap menus and adds dropdown support
|
||||
jQuery(function(){
|
||||
jQuery('.nav>li>a').each(function(){
|
||||
if(jQuery(this).parent().find('ul').length)
|
||||
jQuery(this).attr({'class':'dropdown-toggle','data-toggle':'dropdown'}).append('<b class="caret"></b>');
|
||||
});
|
||||
jQuery('.nav li li').each(function(){
|
||||
if(jQuery(this).find('ul').length)
|
||||
jQuery(this).addClass('dropdown-submenu');
|
||||
});
|
||||
function adjust_height_of_collapsed_nav() {
|
||||
var cn = jQuery('div.collapse');
|
||||
if (cn.get(0)) {
|
||||
var cnh = cn.get(0).style.height;
|
||||
if (cnh>'0px'){
|
||||
cn.css('height','auto');
|
||||
}
|
||||
}
|
||||
}
|
||||
function hoverMenu(){
|
||||
jQuery('ul.nav a.dropdown-toggle').parent().hover(function(){
|
||||
adjust_height_of_collapsed_nav();
|
||||
var mi = jQuery(this).addClass('open');
|
||||
mi.children('.dropdown-menu').stop(true, true).delay(200).fadeIn(400);
|
||||
}, function(){
|
||||
var mi = jQuery(this);
|
||||
mi.children('.dropdown-menu').stop(true, true).delay(200).fadeOut(function(){mi.removeClass('open')});
|
||||
});
|
||||
}
|
||||
hoverMenu(); // first page load
|
||||
jQuery(window).resize(hoverMenu); // on resize event
|
||||
jQuery('ul.nav li.dropdown a').click(function(){window.location=jQuery(this).attr('href');});
|
||||
});
|
||||
@@ -1,4 +1,5 @@
|
||||
{{extend 'layout.html'}}
|
||||
{{block sectionclass}}about{{end}}
|
||||
<!-- begin "about" block -->
|
||||
<h2>{{=T("About application")}} "{{=app}}"</h2>
|
||||
<h3>{{=T("About")}} {{=app}}</h3>
|
||||
@@ -22,4 +23,4 @@ jQuery(document).ready(function() {
|
||||
jQuery.plot(jQuery("#placeholder"), [ {{=progress}} ]);
|
||||
})
|
||||
</script>
|
||||
<!-- end "about" block -->
|
||||
<!-- end "about" block -->
|
||||
@@ -9,16 +9,19 @@ def peekfile(path,file,vars={},title=None):
|
||||
return A(file.replace('\\\\','/'),_title=title,_href=URL('peek', args=args, vars=vars))
|
||||
def editfile(path,file,vars={}):
|
||||
args=(path,file) if 'app' in vars else (app,path,file)
|
||||
return A(T('Edit'),_class='btn small rounded black',_href=URL('edit', args=args, vars=vars))
|
||||
return A(SPAN(T('Edit')),_class='button editbutton btn btn-mini',_href=URL('edit', args=args, vars=vars))
|
||||
def testfile(path,file):
|
||||
return A(I(_class="fa fa-cog"),**{
|
||||
'_class':'btn small rounded black',
|
||||
'_data-tooltip':T("Run tests in this file (to run all files, you may also use the but\
|
||||
ton labelled 'test')")})
|
||||
return A(TAG[''](IMG(_src=URL('static', 'images/test_icon.png'), _alt=T('test')),
|
||||
SPAN(T("Run tests in this file (to run all files, you may also use the button labelled 'test')"))),
|
||||
_class='icon test',
|
||||
_href=URL('test', args=(app, file)),
|
||||
_rel="tooltip",
|
||||
**{'_data-placement':'right',
|
||||
'_data-original-title':T("Run tests in this file (to run all files, you may also use the button labelled 'test')")})
|
||||
def editlanguagefile(path,file,vars={}):
|
||||
return A(T('Edit'),_class='button editbutton btn rounded small',_href=URL('edit_language', args=(app, path, file), vars=vars))
|
||||
return A(SPAN(T('Edit')),_class='button editbutton btn btn-mini',_href=URL('edit_language', args=(app, path, file), vars=vars))
|
||||
def editpluralsfile(path,file,vars={}):
|
||||
return A(T('Edit'),_class='button editbutton btn rounded small',_href=URL('edit_plurals', args=(app, path, file), vars=vars))
|
||||
return A(SPAN(T('Edit')),_class='button editbutton btn btn-mini',_href=URL('edit_plurals', args=(app, path, file), vars=vars))
|
||||
def file_upload_form(location, anchor=None):
|
||||
form=FORM(
|
||||
LABEL(T("upload file:")),
|
||||
@@ -56,8 +59,13 @@ def upload_plugin_form(app, anchor=None):
|
||||
return form
|
||||
def deletefile(arglist, vars={}):
|
||||
vars.update({'sender':request.function+'/'+app})
|
||||
return A(I(_class='fa fa-trash'),_class="red rounded small btn",
|
||||
_href=URL('delete',args=arglist,vars=vars))
|
||||
return A(TAG[''](IMG(_src=URL('static', 'images/delete_icon.png')),
|
||||
SPAN(T('Delete this file (you will be asked to confirm deletion)'))),
|
||||
_href=URL('delete',args=arglist,vars=vars),
|
||||
_class='icon delete',
|
||||
_rel="tooltip",
|
||||
**{'_data-placement':'right',
|
||||
'_data-original-title':T('Delete this file (you will be asked to confirm deletion)')})
|
||||
}}
|
||||
|
||||
{{block sectionclass}}design{{end}}
|
||||
@@ -66,66 +74,64 @@ def deletefile(arglist, vars={}):
|
||||
<h2>{{=T("Edit application")}} "{{=A(app,_href=URL(app,'default','index'),_target="_blank")}}"</h2>
|
||||
|
||||
<!-- COLLAPSE/JUMP-TO BUTTONS -->
|
||||
<div class="container">
|
||||
<div class="fill">
|
||||
<input placeholder="filter" id="search" style="left:100px"/>
|
||||
</div>
|
||||
<div class="fill">
|
||||
<div class="padded">
|
||||
<a class="btn rounded small black" href="#" onclick="jQuery('.accordion>[type=checkbox]').click();return false">{{=T("collapse/expand all")}}</a>
|
||||
<a href="#models" class="btn small rounded orange">{{=T("models")}}</a>
|
||||
<a href="#controllers" class="btn small rounded orange">{{=T("controllers")}}</a>
|
||||
<a href="#views" class="btn small rounded orange">{{=T("views")}}</a>
|
||||
<a href="#models" class="btn small rounded orange">{{=T("languages")}}</a>
|
||||
<a href="#static" class="btn small rounded orange">{{=T("static")}}</a>
|
||||
<a href="#models" class="btn small rounded orange">{{=T("modules")}}</a>
|
||||
<a href="#private" class="btn small rounded orange">{{=T("private files")}}</a>
|
||||
<a href="#plugins" class="btn small rounded orange">{{=T("plugins")}}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right-full controls">
|
||||
<p class="buttons-row">
|
||||
{{=searchbox('search')}}
|
||||
<a class="button special btn btn-inverse" href="#" onclick="jQuery('h3>span').click();return false"><span>{{=T("collapse/expand all")}}</span></a>
|
||||
<span class="buttongroup">
|
||||
{{=button('#models', T("models"))}}
|
||||
{{=button('#controllers', T("controllers"))}}
|
||||
{{=button('#views', T("views"))}}
|
||||
{{=button('#languages', T("languages"))}}
|
||||
{{=button('#static', T("static"))}}
|
||||
{{=button('#modules', T("modules"))}}
|
||||
{{=button('#private', T("private files"))}}
|
||||
{{=button('#plugins', T("plugins"))}}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- MODELS -->
|
||||
<h5 id="_models">
|
||||
<label class="component" for="models_inner" data-tooltip="{{=T('The data representation, define database tables and sets')}}">{{=T("Models")}}</label>
|
||||
</h5>
|
||||
<div class="accordion">
|
||||
<input type="checkbox" id="models_inner" checked>
|
||||
<div>
|
||||
<a href="#" class="right btn rounded small yellow">top</a>
|
||||
<h3 id="_models" rel="pagebookmark">
|
||||
<span class="component" onclick="collapse('models_inner');">{{=T("Models")}}</span>
|
||||
<a href="#models" rel="tooltip" data-placement="right" data-original-title="{{=T('The data representation, define database tables and sets')}}">
|
||||
{{=helpicon()}}
|
||||
<span>{{=T("The data representation, define database tables and sets")}}</span>
|
||||
</a><span id="models" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||
</h3>
|
||||
<div id="models_inner" class="component_contents">
|
||||
{{if not models:}}<p><strong>{{=T("There are no models")}}</strong></p>{{else:}}
|
||||
<div class="controls comptools">
|
||||
{{=button(URL(a=app,c='appadmin',f='index'), T('database administration'))}}
|
||||
{{if os.access(os.path.join(request.folder,'..',app,'databases','sql.log'),os.R_OK):}}
|
||||
{{=button(URL('peek/%s/databases/sql.log'%app), 'sql.log')}}
|
||||
{{pass}}
|
||||
{{=button(URL(a=app, c='appadmin',f='graph_model'), T('graph model'))}}
|
||||
{{=button(URL(a=app,c='appadmin',f='index'), T('database administration'))}}
|
||||
{{if os.access(os.path.join(request.folder,'..',app,'databases','sql.log'),os.R_OK):}}
|
||||
{{=button(URL('peek/%s/databases/sql.log'%app), 'sql.log')}}
|
||||
{{pass}}
|
||||
{{=button(URL(a=app, c='appadmin',f='graph_model'), T('graph model'))}}
|
||||
</div>
|
||||
<ul class="unstyled act_edit">
|
||||
{{for m in models:}}
|
||||
{{id="models__"+m.replace('.','__')}}
|
||||
<li id="{{='_'+id}}"><span id="{{=id}}" class="hashstick"> </span>
|
||||
<span class="filetools controls">
|
||||
{{=editfile('models',m, dict(id=id))}}
|
||||
{{=deletefile([app, 'models', m], dict(id=id, id2='models'))}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('models',m, dict(id=id))}}
|
||||
</span>
|
||||
<span class="extras">
|
||||
{{if len(defines[m]):}}{{=T("defines tables")}} {{pass}}{{=XML(', '.join([B(table).xml() for table in defines[m]]))}}
|
||||
</span>
|
||||
</li>
|
||||
{{pass}}
|
||||
{{for m in models:}}
|
||||
{{id="models__"+m.replace('.','__')}}
|
||||
<li id="{{='_'+id}}" rel="pagebookmark"><span id="{{=id}}" class="hashstick"> </span>
|
||||
<span class="filetools controls">
|
||||
{{=editfile('models',m, dict(id=id))}}
|
||||
{{=deletefile([app, 'models', m], dict(id=id, id2='models'))}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('models',m, dict(id=id))}}
|
||||
</span>
|
||||
<span class="extras">
|
||||
{{if len(defines[m]):}}{{=T("defines tables")}} {{pass}}{{=XML(', '.join([B(table).xml() for table in defines[m]]))}}
|
||||
</span>
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
{{pass}}
|
||||
<div class="silver rounded padded">
|
||||
<button onclick="jQuery('#form1').slideToggle()" class="btn rounded small">{{=T('Create')}}</button>
|
||||
<div class="controls formfield">
|
||||
<button onclick="jQuery('#form1').slideToggle()" class="btn btn-mini">{{=T('Create')}}</button>
|
||||
<div id="form1" class="row-fluid" style="display:none">
|
||||
<div class="span3">{{=file_create_form('%s/models/' % app, 'models')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- FIND CONTROLLER FUNCTIONS -->
|
||||
@@ -135,162 +141,163 @@ for c in controllers: controller_functions+=[c[:-3]+'/%s.html'%x for x in functi
|
||||
}}
|
||||
|
||||
<!-- CONTROLLERS -->
|
||||
<h5 id="_controllers">
|
||||
<label class="component" for="controllers_inner" data-tooltip="{{=T('The application logic, each URL path is mapped in one exposed function in the controller')}}">{{=T("Controllers")}}</label>
|
||||
</h5>
|
||||
<div class="accordion">
|
||||
<input type="checkbox" id="controllers_inner" checked>
|
||||
<div>
|
||||
<a href="#" class="right btn rounded small yellow">top</a>
|
||||
<h3 id="_controllers" rel="pagebookmark">
|
||||
<span class="component" onclick="collapse('controllers_inner');">{{=T("Controllers")}}</span>
|
||||
<a href="#controllers" rel="tooltip" data-placement="right" data-original-title="{{=T('The application logic, each URL path is mapped in one exposed function in the controller')}}">
|
||||
{{=helpicon()}}
|
||||
<span>{{=T("The application logic, each URL path is mapped in one exposed function in the controller")}}</span>
|
||||
</a><span id="controllers" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||
</h3>
|
||||
<div id="controllers_inner" class="component_contents">
|
||||
{{if not controllers:}}<p><strong>{{=T("There are no controllers")}}</strong></p>{{else:}}
|
||||
<div class="controls comptools">
|
||||
{{=button(URL(r=request,c='shell',f='index',args=app), T("shell"))}}
|
||||
{{=button(URL('test',args=app), T("test"))}}
|
||||
{{=button(URL('edit',args=[app,'cron','crontab']), T("crontab"))}}
|
||||
{{=button(URL(r=request,c='shell',f='index',args=app), T("shell"))}}
|
||||
{{=button(URL('test',args=app), T("test"))}}
|
||||
{{=button(URL('edit',args=[app,'cron','crontab']), T("crontab"))}}
|
||||
</div>
|
||||
<ul class="unstyled act_edit">
|
||||
{{for c in controllers:}}
|
||||
{{id="controllers__"+c.replace('.','__')}}
|
||||
<li id="{{='_'+id}}"><span id="{{=id}}" class="hashstick"> </span>
|
||||
{{for c in controllers:}}
|
||||
{{id="controllers__"+c.replace('.','__')}}
|
||||
<li id="{{='_'+id}}" rel="pagebookmark"><span id="{{=id}}" class="hashstick"> </span>
|
||||
<span class="filetools controls">
|
||||
{{=editfile('controllers',c, dict(id=id))}}
|
||||
{{=deletefile([app, 'controllers', c], dict(id=id, id2='controllers'))}}
|
||||
{{=testfile('controllers',c)}}
|
||||
{{=editfile('controllers',c, dict(id=id))}}
|
||||
{{=deletefile([app, 'controllers', c], dict(id=id, id2='controllers'))}}
|
||||
{{=testfile('controllers',c)}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('controllers',c, dict(id=id))}}
|
||||
{{=peekfile('controllers',c, dict(id=id))}}
|
||||
</span>
|
||||
<span class="extras celled">
|
||||
{{if functions[c]:}}{{=T("exposes")}}{{pass}} {{=XML(', '.join([A(f,_href=URL(a=app,c=c[:-3],f=f)).xml() for f in functions[c]]))}}
|
||||
{{if functions[c]:}}{{=T("exposes")}}{{pass}} {{=XML(', '.join([A(f,_href=URL(a=app,c=c[:-3],f=f)).xml() for f in functions[c]]))}}
|
||||
</span>
|
||||
</li>
|
||||
{{pass}}
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
{{pass}}
|
||||
<div class="silver rounded padded">
|
||||
<button onclick="jQuery('#form2').slideToggle()" class="btn rounded small">{{=T('Create')}}</button>
|
||||
<div class="controls formfield">
|
||||
<button onclick="jQuery('#form2').slideToggle()" class="btn btn-mini">{{=T('Create')}}</button>
|
||||
<div id="form2" class="row-fluid" style="display:none">
|
||||
<div class="span3">{{=file_create_form('%s/controllers/' % app, 'controllers')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- VIEWS -->
|
||||
<h5 id="_views">
|
||||
<label class="component" for="views_inner" data-tooltip="{{=T('The presentations layer, views are also known as templates')}}">{{=T("Views")}}</label>
|
||||
</h5>
|
||||
<div class="accordion">
|
||||
<input type="checkbox" id="views_inner" checked>
|
||||
<div>
|
||||
<a href="#" class="right btn rounded small yellow">top</a>
|
||||
{{if not views:}}<p><strong>{{=T("There are no views")}}</strong></p>{{else:}}
|
||||
<h3 id="_views" rel="pagebookmark">
|
||||
<span class="component" onclick="collapse('views_inner');">{{=T("Views")}}</span>
|
||||
<a href="#views" rel="tooltip" data-placement="right" data-original-title="{{=T('The presentations layer, views are also known as templates')}}">
|
||||
{{=helpicon()}}
|
||||
<span>{{=T("The presentations layer, views are also known as templates")}}</span>
|
||||
</a><span id="views" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||
</h3>
|
||||
<div id="views_inner" class="component_contents">
|
||||
{{if not views:}}<p><strong>{{=T("There are no views")}}</strong></p>{{else:}}
|
||||
<div class="controls comptools">
|
||||
{{=button(LAYOUTS_APP, T("Download layouts from repository"))}}
|
||||
{{=button(LAYOUTS_APP, T("Download layouts from repository"))}}
|
||||
</div>
|
||||
<ul class="unstyled act_edit">
|
||||
{{for c in views:}}
|
||||
{{id="views__"+c.replace('/','__').replace('.','__')}}
|
||||
<li id="{{='_'+id}}"><span id="{{=id}}" class="hashstick"> </span>
|
||||
<span class="filetools controls">
|
||||
{{=editfile('views',c, dict(id=id))}}
|
||||
{{=deletefile([app, 'views', c], dict(id=id, id2='views'))}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('views',c, dict(id=id))}}
|
||||
</span>
|
||||
<span class="extras celled celled-one">
|
||||
{{if c in extend:}}{{=T("extends")}} <b>{{=extend[c]}}</b> {{pass}}
|
||||
{{if include[c]:}}{{=T("includes")}} {{pass}}{{=XML(', '.join([B(f).xml() for f in include[c]]))}}
|
||||
</span>
|
||||
</li>
|
||||
{{pass}}
|
||||
{{for c in views:}}
|
||||
{{id="views__"+c.replace('/','__').replace('.','__')}}
|
||||
<li id="{{='_'+id}}" rel="pagebookmark"><span id="{{=id}}" class="hashstick"> </span>
|
||||
<span class="filetools controls">
|
||||
{{=editfile('views',c, dict(id=id))}}
|
||||
{{=deletefile([app, 'views', c], dict(id=id, id2='views'))}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('views',c, dict(id=id))}}
|
||||
</span>
|
||||
<span class="extras celled celled-one">
|
||||
{{if c in extend:}}{{=T("extends")}} <b>{{=extend[c]}}</b> {{pass}}
|
||||
{{if include[c]:}}{{=T("includes")}} {{pass}}{{=XML(', '.join([B(f).xml() for f in include[c]]))}}
|
||||
</span>
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
{{pass}}
|
||||
<div class="silver rounded padded">
|
||||
<button onclick="jQuery('#form3').slideToggle()" class="btn rounded small">{{=T('Create')}}</button>
|
||||
{{pass}}
|
||||
<div class="controls formfield">
|
||||
<button onclick="jQuery('#form3').slideToggle()" class="btn btn-mini">{{=T('Create')}}</button>
|
||||
<div id="form3" class="row-fluid" style="display:none">
|
||||
<div class="span3">{{=file_create_form('%s/views/' % app, 'views')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- LANGUAGES -->
|
||||
<h5 id="_languages">
|
||||
<label class="component" for="languages_inner" data-tooltip="{{=T('Translation strings for the application')}}">{{=T("Languages")}}</label>
|
||||
</h5>
|
||||
<div class="accordion">
|
||||
<input type="checkbox" id="languages_inner" checked>
|
||||
<div>
|
||||
<a href="#" class="right btn rounded small yellow">top</a>
|
||||
<h3 id="_languages" rel="pagebookmark">
|
||||
<span class="component" onclick="collapse('languages_inner');">{{=T("Languages")}}</span>
|
||||
<a href="#languages" rel="tooltip" data-placement="right" data-original-title="{{=T('Translation strings for the application')}}">
|
||||
{{=helpicon()}}
|
||||
<span>{{=T("Translation strings for the application")}}</span>
|
||||
</a><span id="languages" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||
</h3>
|
||||
<div id="languages_inner" class="component_contents">
|
||||
{{if not languages:}}<p><strong>{{=T("There are no translators, only default language is supported")}}</strong></p>{{else:}}
|
||||
<div class="controls comptools">
|
||||
{{=button(URL('update_languages/'+app), T('update all languages'))}}
|
||||
{{=button(URL('update_languages/'+app), T('update all languages'))}}
|
||||
</div>
|
||||
<ul class="unstyled act_edit">
|
||||
{{for lang in sorted(languages):
|
||||
file = lang+'.py'
|
||||
id = "languages__"+file.replace('.','__')}}
|
||||
<li id="{{='_'+id}}" class="li-row"><span id="{{=id}}" class="hashstick"> </span>
|
||||
<span class="li-controls">
|
||||
<span class="filetools controls">
|
||||
{{=editlanguagefile('languages',file)}}
|
||||
{{=deletefile([app, 'languages', file], dict(id=id, id2='languages'))}}
|
||||
</span>
|
||||
<span class="">
|
||||
{{=peekfile('languages',file, dict(id=id))}}
|
||||
</span>
|
||||
</span> <!-- /li-row -->
|
||||
<span class="extras celled">
|
||||
(
|
||||
{{=T("Plural-Forms:")}}
|
||||
{{p=languages[lang][3:7]}}
|
||||
{{if p[2] == 'default':}}
|
||||
<span class='error text-error'>{{=T("rules are not defined")}}</span> {{=T.M("(file **gluon/contrib/plural_rules/%s.py** is not found)",lang[:2])}}
|
||||
{{else:}}
|
||||
{{if p[3] == 1:}}
|
||||
{{=B(T("are not used"))}}
|
||||
{{else:}}
|
||||
{{pfile=p[0]}}
|
||||
{{if p[1]!=0:}}<span style="display:inline-block;margin-top:-10px;">
|
||||
<span class="filetools controls">
|
||||
{{=editpluralsfile('languages',pfile,dict(nplurals=p[3]))}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('languages',pfile,dict(id=id))}}
|
||||
</span></span>
|
||||
{{else:}}
|
||||
<b>{{=T("are not used yet")}}</b>
|
||||
{{for lang in sorted(languages):
|
||||
file = lang+'.py'
|
||||
id = "languages__"+file.replace('.','__')}}
|
||||
<li id="{{='_'+id}}" rel="pagebookmark" class="li-row"><span id="{{=id}}" class="hashstick"> </span>
|
||||
<span class="li-controls">
|
||||
<span class="filetools controls">
|
||||
{{=editlanguagefile('languages',file)}}
|
||||
{{=deletefile([app, 'languages', file], dict(id=id, id2='languages'))}}
|
||||
</span>
|
||||
<span class="">
|
||||
{{=peekfile('languages',file, dict(id=id))}}
|
||||
</span>
|
||||
</span> <!-- /li-row -->
|
||||
<span class="extras celled">
|
||||
(
|
||||
{{=T("Plural-Forms:")}}
|
||||
{{p=languages[lang][3:7]}}
|
||||
{{if p[2] == 'default':}}
|
||||
<span class='error text-error'>{{=T("rules are not defined")}}</span> {{=T.M("(file **gluon/contrib/plural_rules/%s.py** is not found)",lang[:2])}}
|
||||
{{else:}}
|
||||
{{if p[3] == 1:}}
|
||||
{{=B(T("are not used"))}}
|
||||
{{else:}}
|
||||
{{pfile=p[0]}}
|
||||
{{if p[1]!=0:}}<span style="display:inline-block;margin-top:-10px;">
|
||||
<span class="filetools controls">
|
||||
{{=editpluralsfile('languages',pfile,dict(nplurals=p[3]))}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('languages',pfile,dict(id=id))}}
|
||||
</span></span>
|
||||
{{else:}}
|
||||
<b>{{=T("are not used yet")}}</b>
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
)
|
||||
</span>
|
||||
</li>
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
)
|
||||
</span>
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
{{pass}}
|
||||
<div class="silver rounded padded">
|
||||
<button onclick="jQuery('#form4').slideToggle()" class="btn rounded small">{{=T('Create')}}</button>
|
||||
{{pass}}
|
||||
<div class="controls formfield">
|
||||
<button onclick="jQuery('#form4').slideToggle()" class="btn btn-mini">{{=T('Create')}}</button>
|
||||
<div id="form4" class="row-fluid" style="display:none">
|
||||
<div class="span3">{{=file_create_form('%s/languages/' % app, 'languages', T('(something like "it-it")'))}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- STATIC -->
|
||||
<h5 id="_static">
|
||||
<label class="component" for="static_inner" data-tooltip="{{=T('These files are served without processing, your images go here')}}">{{=T("Static")}}</label>
|
||||
</h5>
|
||||
<div class="accordion">
|
||||
<input type="checkbox" id="static_inner" checked>
|
||||
<div>
|
||||
<a href="#" class="right btn rounded small yellow">top</a>
|
||||
<h3 id="_static" rel="pagebookmark">
|
||||
<span class="component" onclick="collapse('static_inner');">{{=T("Static")}}</span>
|
||||
<a href="#static" rel="tooltip" data-placement="right" data-original-title="{{=T('These files are served without processing, your images go here')}}">
|
||||
{{=helpicon()}}
|
||||
<span>{{=T("These files are served without processing, your images go here")}}</span>
|
||||
</a><span id="static" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||
</h3>
|
||||
<div id="static_inner" class="component_contents">
|
||||
{{if not statics:}}<p><strong>{{=T("There are no static files")}}</strong></p>{{else:}}
|
||||
<ul class="unstyled act_edit">
|
||||
{{
|
||||
{{
|
||||
path=[]
|
||||
for file in statics+['']:
|
||||
items=file.split('/')
|
||||
@@ -301,89 +308,88 @@ for c in controllers: controller_functions+=[c[:-3]+'/%s.html'%x for x in functi
|
||||
path.append(file_path[len(path)])
|
||||
thispath = regex_space.sub('-', 'static__'+'__'.join(path))
|
||||
}}
|
||||
<li class="folder"><i> </i>
|
||||
<a href="javascript:collapse('{{=thispath}}');" class="file">{{=path[-1]}}/</a>
|
||||
<ul id="{{=thispath}}" style="display: none;" class="sublist">{{
|
||||
else:
|
||||
path = path[:-1]
|
||||
}}
|
||||
</ul>
|
||||
</li>
|
||||
<li class="folder"><i> </i>
|
||||
<a href="javascript:collapse('{{=thispath}}');" class="file">{{=path[-1]}}/</a>
|
||||
<ul id="{{=thispath}}" style="display: none;" class="sublist">{{
|
||||
else:
|
||||
path = path[:-1]
|
||||
}}
|
||||
</ul></li>
|
||||
{{
|
||||
pass
|
||||
pass
|
||||
if filename:
|
||||
}}
|
||||
<li>
|
||||
<span class="filetools controls">
|
||||
{{=editfile('static',file, dict(id="static"))}} {{=deletefile([app,'static',file], dict(id="static",id2="static"))}}
|
||||
</span>
|
||||
<span class="file">
|
||||
<a href="{{=URL(a=app,c='static',f=file)}}">{{=filename}}</a>
|
||||
</span>
|
||||
</li>{{
|
||||
pass
|
||||
pass
|
||||
}}
|
||||
<li>
|
||||
<span class="filetools controls">
|
||||
{{=editfile('static',file, dict(id="static"))}} {{=deletefile([app,'static',file], dict(id="static",id2="static"))}}
|
||||
</span>
|
||||
<span class="file">
|
||||
<a href="{{=URL(a=app,c='static',f=file)}}">{{=filename}}</a>
|
||||
</span>
|
||||
</li>{{
|
||||
pass
|
||||
pass
|
||||
}}
|
||||
</ul>
|
||||
{{pass}}
|
||||
<div class="silver rounded padded">
|
||||
<button onclick="jQuery('#form5').slideToggle()" class="btn rounded small">{{=T('Create/Upload')}}</button>
|
||||
<div class="controls formfield">
|
||||
<button onclick="jQuery('#form5').slideToggle()" class="btn btn-mini">{{=T('Create/Upload')}}</button>
|
||||
<div id="form5" class="row-fluid" style="display:none">
|
||||
<div class="span3">{{=file_create_form('%s/static/' % app, 'static')}}<em>{{=T('or alternatively')}}</em></div>
|
||||
<div class="span3">{{=file_upload_form('%s/static/' % app, 'static')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MODULES -->
|
||||
<h5 id="_modules">
|
||||
<label class="component" for="modules_inner" data-tooltip="{{=T('Additional code for your application')}}">{{=T("Modules")}}</label>
|
||||
</h5>
|
||||
<div class="accordion">
|
||||
<input type="checkbox" id="modules_inner" checked>
|
||||
<div>
|
||||
<a href="#" class="right btn rounded small yellow">top</a>
|
||||
<h3 id="_modules" rel="pagebookmark">
|
||||
<span class="component" onclick="collapse('modules_inner');">{{=T("Modules")}}</span>
|
||||
<a href="#modules" rel="tooltip" data-placement="right" data-original-title="{{=T('Additional code for your application')}}">
|
||||
{{=helpicon()}}
|
||||
<span>{{=T("Additional code for your application")}}</span>
|
||||
</a><span id="modules" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||
</h3>
|
||||
<div id="modules_inner" class="component_contents">
|
||||
{{if not modules:}}<p><strong>{{=T("There are no modules")}}</strong></p>{{else:}}
|
||||
<ul class="unstyled act_edit">
|
||||
{{for m in modules:}}
|
||||
{{id="modules__"+m.replace('/','__').replace('.','__')}}
|
||||
<li id="{{='_'+id}}"><span id="{{=id}}" class="hashstick"> </span>
|
||||
<span>
|
||||
{{=editfile('modules',m,dict(id=id))}}
|
||||
{{if m!='__init__.py':}}
|
||||
{{=deletefile([app, 'modules', m], dict(id=id, id2='modules'))}}
|
||||
{{pass}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('modules',m, dict(id=id))}}
|
||||
</span>
|
||||
</li>
|
||||
{{pass}}
|
||||
{{for m in modules:}}
|
||||
{{id="modules__"+m.replace('/','__').replace('.','__')}}
|
||||
<li id="{{='_'+id}}" rel="pagebookmark"><span id="{{=id}}" class="hashstick"> </span>
|
||||
<span class="filetols controls">
|
||||
{{=editfile('modules',m,dict(id=id))}}
|
||||
{{if m!='__init__.py':}}
|
||||
{{=deletefile([app, 'modules', m], dict(id=id, id2='modules'))}}
|
||||
{{pass}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('modules',m, dict(id=id))}}
|
||||
</span>
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
{{pass}}
|
||||
<div class="silver rounded padded">
|
||||
<button onclick="jQuery('#form6').slideToggle()" class="btn rounded small">{{=T('Create/Upload')}}</button>
|
||||
<div class="controls formfield">
|
||||
<button onclick="jQuery('#form6').slideToggle()" class="btn btn-mini">{{=T('Create/Upload')}}</button>
|
||||
<div id="form6" class="row-fluid" style="display:none">
|
||||
<div class="span3">{{=file_create_form('%s/modules/' % app, 'modules')}}<em>{{=T('or alternatively')}}</em></div>
|
||||
<div class="span3">{{=file_upload_form('%s/modules/' % app, 'modules')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- PRIVATE -->
|
||||
<h5 id="_private">
|
||||
<label class="component" for="private_inner" data-tooltip="{{=T('These files are not served, they are only available from within your app')}}">{{=T("Private files")}}</label>
|
||||
</h5>
|
||||
<div class="accordion">
|
||||
<input type="checkbox" id="private_inner" checked>
|
||||
<div>
|
||||
<a href="#" class="right btn rounded small yellow">top</a>
|
||||
<h3 id="_private" rel="pagebookmark">
|
||||
<span class="component" onclick="collapse('private_inner');">{{=T("Private files")}}</span>
|
||||
<a href="#private" rel="tooltip" data-placement="right" data-original-title="{{=T('These files are not served, they are only available from within your app')}}">
|
||||
{{=helpicon()}}
|
||||
<span>{{=T("These files are not served, they are only available from within your app")}}</span>
|
||||
</a><span id="private" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||
</h3>
|
||||
<div id="private_inner" class="component_contents">
|
||||
{{if not privates:}}<p><strong>{{=T("There are no private files")}}</strong></p>{{else:}}
|
||||
<ul class="unstyled act_edit">
|
||||
{{
|
||||
{{
|
||||
path=[]
|
||||
for file in privates+['']:
|
||||
items=file.split('/')
|
||||
@@ -394,74 +400,72 @@ for c in controllers: controller_functions+=[c[:-3]+'/%s.html'%x for x in functi
|
||||
path.append(file_path[len(path)])
|
||||
thispath='private__'+'__'.join(path)
|
||||
}}
|
||||
<li class="folder">
|
||||
<a href="javascript:collapse('{{=thispath}}');" class="file">{{=path[-1]}}/</a>
|
||||
<ul id="{{=thispath}}" style="display: none;" class="sublist">{{
|
||||
else:
|
||||
path = path[:-1]
|
||||
}}
|
||||
</ul>
|
||||
</li>
|
||||
{{
|
||||
<li class="folder">
|
||||
<a href="javascript:collapse('{{=thispath}}');" class="file">{{=path[-1]}}/</a>
|
||||
<ul id="{{=thispath}}" style="display: none;" class="sublist">{{
|
||||
else:
|
||||
path = path[:-1]
|
||||
}}
|
||||
</ul>
|
||||
</li>
|
||||
{{
|
||||
pass
|
||||
pass
|
||||
if filename:
|
||||
}}
|
||||
<li>
|
||||
<span class="filetools controls">
|
||||
{{=editfile('private',file, dict(id="private"))}} {{=deletefile([app,'private',file], dict(id="private",id2="private"))}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('private',file, dict(id="private"))}}
|
||||
</span>
|
||||
</li>{{
|
||||
pass
|
||||
pass
|
||||
}}
|
||||
}}
|
||||
<li>
|
||||
<span class="filetools controls">
|
||||
{{=editfile('private',file, dict(id="private"))}} {{=deletefile([app,'private',file], dict(id="private",id2="private"))}}
|
||||
</span>
|
||||
<span class="file">
|
||||
{{=peekfile('private',file, dict(id="private"))}}
|
||||
</span>
|
||||
</li>{{
|
||||
pass
|
||||
pass
|
||||
}}
|
||||
{{pass}}
|
||||
</ul>
|
||||
<div class="silver rounded padded">
|
||||
<button onclick="jQuery('#form7').slideToggle()" class="btn rounded small">{{=T('Create/Upload')}}</button>
|
||||
<div class="controls formfield">
|
||||
<button onclick="jQuery('#form7').slideToggle()" class="btn btn-mini">{{=T('Create/Upload')}}</button>
|
||||
<div id="form7" class="row-fluid" style="display:none">
|
||||
<div class="span3">{{=file_create_form('%s/private/' % app, 'private')}}<em>{{=T('or alternatively')}}</em></div>
|
||||
<div class="span3">{{=file_upload_form('%s/private/' % app, 'private')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- PLUGINS -->
|
||||
<h5 id="_plugins">
|
||||
<label class="component" for="plugins_inner" data-tooltip="{{=T('To create a plugin, name a file/folder plugin_[name]')}}">{{=T("Plugins files")}}</label>
|
||||
</h5>
|
||||
<div class="accordion">
|
||||
<input type="checkbox" id="plugins_inner" checked>
|
||||
<div>
|
||||
<a href="#" class="right btn rounded small yellow">top</a>
|
||||
<h3 id="_plugins" rel="pagebookmark">
|
||||
<span class="component" onclick="collapse('plugins_inner');">{{=T("Plugins")}}</span>
|
||||
<a href="#plugins" rel="tooltip" data-placement="right" data-original-title="{{=T('To create a plugin, name a file/folder plugin_[name]')}}">
|
||||
{{=helpicon()}}
|
||||
<span>{{=T("To create a plugin, name a file/folder plugin_[name]")}}</span>
|
||||
</a><span id="plugins" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||
</h3>
|
||||
<div id="plugins_inner" class="component_contents">
|
||||
{{if plugins:}}
|
||||
<ul class="unstyled act_edit">
|
||||
{{for plugin in plugins:}}
|
||||
{{id="plugins__"+plugin.replace('/','__').replace('.','__')}}
|
||||
<li id="{{=id}}">
|
||||
{{=A('plugin_%s' % plugin, _class='file', _href=URL('plugin', args=[app, plugin], vars=dict(id=id, id2='plugins')))}}
|
||||
</li>
|
||||
{{pass}}
|
||||
{{for plugin in plugins:}}
|
||||
{{id="plugins__"+plugin.replace('/','__').replace('.','__')}}
|
||||
<li id="{{=id}}">
|
||||
{{=A('plugin_%s' % plugin, _class='file', _href=URL('plugin', args=[app, plugin], vars=dict(id=id, id2='plugins')))}}
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
{{else:}}
|
||||
<p><strong>{{=T('There are no plugins')}}</strong></p>
|
||||
{{pass}}
|
||||
<div class="controls comptools">
|
||||
{{=button(URL(c="default", f="plugins", args=[app,]), T('Download plugins from repository'))}}
|
||||
{{=button(URL(c="default", f="plugins", args=[app,]), T('Download plugins from repository'))}}
|
||||
</div>
|
||||
<div class="silver rounded padded">
|
||||
<button onclick="jQuery('#form8').slideToggle()" class="btn rounded small">{{=T('Upload')}}</button>
|
||||
<div class="controls formfield">
|
||||
<button onclick="jQuery('#form8').slideToggle()" class="btn btn-mini">{{=T('Upload')}}</button>
|
||||
<div id="form8" class="row-fluid" style="display:none">
|
||||
<div class="row-fluid">
|
||||
<div class="span3">{{=upload_plugin_form(app, 'plugins')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
@@ -486,7 +490,6 @@ jQuery(document).ready(function(){
|
||||
if(code==13) filter_files();
|
||||
});
|
||||
jQuery('#search_start').click(function(e){ filter_files(); });
|
||||
});
|
||||
</script>
|
||||
});
|
||||
</script>
|
||||
<!-- end "design" block -->
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ def file_create_form(location, anchor=None, helptext=""):
|
||||
<!-- begin "edit" block -->
|
||||
{{
|
||||
def shortcut(combo, description):
|
||||
return XML('<li><span class="teletype-text">%s</span><span>%s</span></li>' % (combo, description))
|
||||
return XML('<li class="span5"><span class="teletype-text">%s</span><span>%s</span></li>' % (combo, description))
|
||||
def listfiles(app, dir, regexp='.*\.py$'):
|
||||
files = sorted(
|
||||
listdir(apath('%(app)s/%(dir)s/' % {'app':app, 'dir':dir}, r=request), regexp))
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
{{extend 'layout.html'}}
|
||||
{{block sectionclass}}login{{end}}
|
||||
<!-- begin "index" block -->
|
||||
<h2>web2py™ {{=T('Web Framework')}}</h2>
|
||||
<div class="twothirds padded lifted">
|
||||
<h3>{{=T('Login to the Administrative Interface')}}</h3>
|
||||
<div class="form row-fluid">
|
||||
{{if request.is_https or request.is_local:}}
|
||||
<form action="{{=URL(r=request)}}" method="post" class="span4 well">
|
||||
<h5>{{=T('Login to the Administrative Interface')}}</h5>
|
||||
<label class="spaced" for="password">{{=T('Administrator Password:')}}</label>
|
||||
<input class="spaced" type="password" name="password" id="password"/>
|
||||
<input class="spaced" type="hidden" name="send" value="{{=send}}"/>
|
||||
<button class="spaced" type="submit" name="login">{{=T('Login')}}</button>
|
||||
</form>
|
||||
<form action="{{=URL(r=request)}}" method="post" class="span4 well">
|
||||
<label for="password">{{=T('Administrator Password:')}}</label>
|
||||
<input type="password" name="password" id="password"/>
|
||||
<input type="hidden" name="send" value="{{=send}}"/>
|
||||
<div class="controls"><button type="submit" name="login" class="btn">{{=T('Login')}}</button></div>
|
||||
</form>
|
||||
{{else:}}
|
||||
<p class="help span7 alert alert-block alert-warning">{{=T('ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.')}}</p>
|
||||
{{pass}}
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
jQuery(document).ready(function(){
|
||||
jQuery("#password").focus();
|
||||
});
|
||||
jQuery(document).ready(function(){
|
||||
jQuery("#password").focus();
|
||||
});
|
||||
</script>
|
||||
<!-- end "index" block -->
|
||||
<!-- end "index" block -->
|
||||
@@ -1,19 +1,19 @@
|
||||
{{extend 'layout.html'}}
|
||||
{{import os, glob}}
|
||||
{{block sectionclass}}site{{end}}
|
||||
<!-- begin "site" block -->
|
||||
<div class="container">
|
||||
<div class="twothirds">
|
||||
<div class="padded">
|
||||
<div class="row-fluid">
|
||||
<div class="applist f60 span7">
|
||||
<div class="applist_inner">
|
||||
<h2>{{=T("Installed applications")}}</h2>
|
||||
<table>
|
||||
<tbody>
|
||||
{{for a in apps:}}
|
||||
<tr>{{buttons = []}}
|
||||
<td>
|
||||
<table width="100%" class="table">
|
||||
{{for a in apps:}}
|
||||
<tr>{{buttons = []}}
|
||||
<td>
|
||||
{{if a==request.application:}}
|
||||
<a class="btn rounded gray">{{=a}} ({{=T('currently running')}})</a>
|
||||
<h4 class="currentapp">{{=a}} ({{=T('currently running')}})</h4>
|
||||
{{else:}}
|
||||
<a class="btn rounded orange" href="{{=URL(a,'default','index')}}">{{=a}}</a>
|
||||
<h4 class="editableapp">{{=A(a,_href=URL(a,'default','index'))}}</h4>
|
||||
{{if MULTI_USER_MODE and db.app(name=a):}}(created by {{="%(first_name)s %(last_name)s" % db.auth_user[db.app(name=a).owner]}}){{pass}}
|
||||
{{if not os.path.exists('applications/%s/compiled' % a):}}
|
||||
{{buttons.append((URL('design',args=a), T("Edit")))}}
|
||||
@@ -43,30 +43,28 @@
|
||||
{{if a!=request.application:}}
|
||||
{{buttons.append((URL('uninstall',args=a), T("Uninstall")))}}
|
||||
{{pass}}
|
||||
</td>
|
||||
<td>
|
||||
<ul class="menu">
|
||||
<li>
|
||||
<a class="btn white rounded">{{=T('Manage')}}</a>
|
||||
<ul>
|
||||
{{for link,name in buttons:}}
|
||||
{{=LI(A(name,_href=link))}}
|
||||
{{pass}}
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
{{=button_enable(URL('enable',args=a), a) if a!='admin' else ''}}
|
||||
</td>
|
||||
</tr>
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-group">
|
||||
<a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
{{=T('Manage')}}
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
{{for link,name in buttons:}}
|
||||
{{=LI(A(name,_href=link))}}
|
||||
{{pass}}
|
||||
</tbody>
|
||||
</ul>
|
||||
</div>
|
||||
{{=button_enable(URL('enable',args=a), a) if a!='admin' else ''}}
|
||||
</td>
|
||||
</tr>
|
||||
{{pass}}
|
||||
</table>
|
||||
</div>
|
||||
</div> <!-- /applist -->
|
||||
<div class="third black">
|
||||
<div class="padded">
|
||||
<div class="sidebar fl60 span5">
|
||||
<div class="sidebar_inner controls well well-small">
|
||||
<!-- CHANGE ADMIN PWD -->
|
||||
<div class="pwdchange pull-right">
|
||||
{{if MULTI_USER_MODE:}}
|
||||
@@ -79,77 +77,77 @@
|
||||
{{if is_manager():}}
|
||||
<!-- VERSION -->
|
||||
<div class="box">
|
||||
<h6>{{=T("Version")}}</h6>
|
||||
<p>
|
||||
<tt>{{=myversion}}</tt><br/>
|
||||
{{running_on = T("Running on %s", request.env.server_software or 'Unknown')}}
|
||||
({{="%s, Python %s" % (running_on, myplatform)}})
|
||||
</p>
|
||||
<p id="check_version" class="row-buttons">
|
||||
{{if session.check_version:}}
|
||||
{{=T('Checking for upgrades...')}}
|
||||
<script>ajax('{{=URL('check_version')}}',[],'check_version');</script>
|
||||
{{session.check_version=False}}
|
||||
{{else:}}
|
||||
{{=button("javascript:ajax('"+URL('check_version')+"',[],'check_version')", T('Check for upgrades'))}}
|
||||
{{pass}}
|
||||
</p>
|
||||
{{if session.is_mobile=='auto':}}
|
||||
<p>{{=A(T('Try the mobile interface'),_href=URL('plugin_jqmobile','about'))}}</p>
|
||||
{{pass}}
|
||||
<h4>{{=T("Version")}}</h4>
|
||||
<p>
|
||||
<tt>{{=myversion}}</tt><br/>
|
||||
{{running_on = T("Running on %s", request.env.server_software or 'Unknown')}}
|
||||
({{="%s, Python %s" % (running_on, myplatform)}})
|
||||
</p>
|
||||
<p id="check_version" class="row-buttons">
|
||||
{{if session.check_version:}}
|
||||
{{=T('Checking for upgrades...')}}
|
||||
<script>ajax('{{=URL('check_version')}}',[],'check_version');</script>
|
||||
{{session.check_version=False}}
|
||||
{{else:}}
|
||||
{{=button("javascript:ajax('"+URL('check_version')+"',[],'check_version')", T('Check for upgrades'))}}
|
||||
{{pass}}
|
||||
</p>
|
||||
{{if session.is_mobile=='auto':}}
|
||||
<p>{{=A(T('Try the mobile interface'),_href=URL('plugin_jqmobile','about'))}}</p>
|
||||
{{pass}}
|
||||
</div> <!-- /VERSION -->
|
||||
{{pass}}
|
||||
{{if MULTI_USER_MODE and is_manager():}}
|
||||
<!-- MULTI_USER_INTERFACE -->
|
||||
<div class="box">
|
||||
<h6>{{=T("Multi User Mode")}}</h6>
|
||||
<p class="row-buttons">
|
||||
{{=button(URL('bulk_register'),T('Bulk Register'))}}
|
||||
{{=button(URL('manage_students',vars={'order':'auth_user.id'}),T('Manage Students'))}}
|
||||
</p>
|
||||
<h4>{{=T("Multi User Mode")}}</h4>
|
||||
<p class="row-buttons">
|
||||
{{=button(URL('bulk_register'),T('Bulk Register'))}}
|
||||
{{=button(URL('manage_students',vars={'order':'auth_user.id'}),T('Manage Students'))}}
|
||||
</p>
|
||||
</div> <!-- /MULTI_USER_INTERFACE -->
|
||||
{{pass}}
|
||||
<!-- SCAFFOLD APP -->
|
||||
<div class="box">
|
||||
<h6>{{=T("New simple application")}}</h6>
|
||||
{{=form_create.custom.begin}}
|
||||
{{=LABEL(T("Application name:"))}}
|
||||
{{=form_create.custom.widget.name}}
|
||||
<div class="controls"><button type="submit" class="btn">{{=T('Create')}}</button></div>
|
||||
{{=form_create.custom.end}}
|
||||
<h4>{{=T("New simple application")}}</h4>
|
||||
{{=form_create.custom.begin}}
|
||||
{{=LABEL(T("Application name:"))}}
|
||||
{{=form_create.custom.widget.name}}
|
||||
<div class="controls"><button type="submit" class="btn">{{=T('Create')}}</button></div>
|
||||
{{=form_create.custom.end}}
|
||||
</div> <!-- /SCAFFOLD APP -->
|
||||
<!-- UPLOAD PACKAGE -->
|
||||
<div class="box">
|
||||
<h6>{{=T("Upload and install packed application")}}</h6>
|
||||
{{=form_update.custom.begin}}
|
||||
<label for="appupdate_name">{{=T("Application name:")}}</label>
|
||||
{{=form_update.custom.widget.name}}
|
||||
<label for="appupdate_file">{{=T("Upload a package:")}}</label>
|
||||
{{=form_update.custom.widget.file}}
|
||||
<label for="appupdate_url">{{=T("Or Get from URL:")}}</label>
|
||||
{{=form_update.custom.widget.url}}<small class="help-block">({{=T('can be a git repo')}})</small>
|
||||
<div class="controls">
|
||||
<label class="checkbox">
|
||||
{{=form_update.custom.widget.overwrite}} {{=T("Overwrite installed app")}}
|
||||
</label>
|
||||
<button type="submit" class='btn'>{{=T('Install')}}</button>
|
||||
</div>
|
||||
{{=form_update.custom.end}}
|
||||
<h4>{{=T("Upload and install packed application")}}</h4>
|
||||
{{=form_update.custom.begin}}
|
||||
<label for="appupdate_name">{{=T("Application name:")}}</label>
|
||||
{{=form_update.custom.widget.name}}
|
||||
<label for="appupdate_file">{{=T("Upload a package:")}}</label>
|
||||
{{=form_update.custom.widget.file}}
|
||||
<label for="appupdate_url">{{=T("Or Get from URL:")}}</label>
|
||||
{{=form_update.custom.widget.url}}<small class="help-block">({{=T('can be a git repo')}})</small>
|
||||
<div class="controls">
|
||||
<label class="checkbox">
|
||||
{{=form_update.custom.widget.overwrite}} {{=T("Overwrite installed app")}}
|
||||
</label>
|
||||
<button type="submit" class='btn'>{{=T('Install')}}</button>
|
||||
</div>
|
||||
{{=form_update.custom.end}}
|
||||
</div> <!-- /UPLOAD PACKAGE -->
|
||||
<!-- DEPLOY ON GAE -->
|
||||
<div class="box">
|
||||
<h6>{{=T("Deploy")}}</h6>
|
||||
<p class="row-buttons">
|
||||
{{=button(URL('gae','deploy'), T('Deploy on Google App Engine'))}}
|
||||
{{=button(URL('openshift','deploy'),T('Deploy to OpenShift'))}}
|
||||
{{=button(URL('pythonanywhere','deploy'), T('Deploy to PythonAnywhere'))}}
|
||||
</p>
|
||||
<h4>{{=T("Deploy")}}</h4>
|
||||
<p class="row-buttons">
|
||||
{{=button(URL('gae','deploy'), T('Deploy on Google App Engine'))}}
|
||||
{{=button(URL('openshift','deploy'),T('Deploy to OpenShift'))}}
|
||||
{{=button(URL('pythonanywhere','deploy'), T('Deploy to PythonAnywhere'))}}
|
||||
</p>
|
||||
</div> <!-- /DEPLOY ON GAE -->
|
||||
<!-- APP WIZARD -->
|
||||
<div class="box">
|
||||
<h6>{{=T("New application wizard")}}</h6>
|
||||
<p>{{=button(URL('wizard','index'), T('Start wizard'))}}<br/>
|
||||
{{=T("(requires internet access, experimental)")}}</p>
|
||||
<h4>{{=T("New application wizard")}}</h4>
|
||||
<p>{{=button(URL('wizard','index'), T('Start wizard'))}}<br/>
|
||||
{{=T("(requires internet access, experimental)")}}</p>
|
||||
</div> <!-- /APP WIZARD -->
|
||||
<!-- TWITTER TIMELINE -->
|
||||
<div class="box twitter-timeline">
|
||||
|
||||
@@ -1,69 +1,114 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<link href="{{=URL('static','css/stupid.css')}}" rel="stylesheet" type="text/css"/>
|
||||
<link href="{{=URL('static','css/calendar.css')}}" rel="stylesheet" type="text/css"/>
|
||||
<link href="{{=URL('static','css/web2py.css')}}" rel="stylesheet" type="text/css"/>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
|
||||
<style>
|
||||
th, td {color: black}
|
||||
tbody tr:hover {background-color:transparent}
|
||||
tbody tr {border-bottom: none}
|
||||
p {text-align: left}
|
||||
pre {background-color: black!important;border-radius:5px; color:white; padding:10px}
|
||||
a.btn.btn180 {padding:20px; font-size:1.2em; width:200px!important}
|
||||
[type=submit], [type=button] {border-radius:5px!important;padding:5px 10px;margin-top:10px}
|
||||
</style>
|
||||
{{
|
||||
left_sidebar_enabled = globals().get('left_sidebar_enabled', False)
|
||||
right_sidebar_enabled = globals().get('right_sidebar_enabled', False)
|
||||
middle_column = {0: 'fill', 1: 'threequarters', 2: 'half'}[
|
||||
(left_sidebar_enabled and 1 or 0)+(right_sidebar_enabled and 1 or 0)]
|
||||
}}
|
||||
{{include "web2py_ajax.html"}}
|
||||
</head>
|
||||
<body class="black">
|
||||
<header class="black padded">
|
||||
<div class="container middle max900">
|
||||
<div class="fill middle">
|
||||
<label class="ham padded fa fa-bars" for="menu"></label>
|
||||
<div class="burger accordion">
|
||||
<input type="checkbox" id="menu"/>
|
||||
{{=MENU(response.menu,_class='menu')}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
{{if response.flash:}}
|
||||
<div class="w2p_flash">
|
||||
{{=response.flash}}
|
||||
</div>
|
||||
{{pass}}
|
||||
<main class="white">
|
||||
<div class="hidden">{{block sectionclass}}design{{end}}</div>
|
||||
<div class="container max900">
|
||||
{{if left_sidebar_enabled:}}
|
||||
<div class="quarter padded">{{block left_sidebar}}{{end}}</div>
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="P3P" content="CP=\"IDC DSP COR CURa ADMa OUR IND PHY ONL COM STA\"" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{=response.title or URL()}}</title>
|
||||
{{
|
||||
response.files.append(URL('static','css/bootstrap.min.css'))
|
||||
response.files.append(URL('static','css/bootstrap_essentials.css'))
|
||||
response.files.append(URL('static','css/bootstrap-responsive.min.css'))
|
||||
}}
|
||||
{{include 'web2py_ajax.html'}}
|
||||
</head>
|
||||
|
||||
<body class="{{=T('direction: ltr') == 'direction: rtl' and 'RTLbody' or ''}} {{block sectionclass}}home{{end}}">
|
||||
|
||||
<!-- NAVBAR
|
||||
============== -->
|
||||
<div id="header" class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<div id="start" class="brand_wrapper">
|
||||
<a href="{{=URL('default', 'index')}}" class="button brand" ><span>web2py™ {{=T('administrative interface')}}</span></a>
|
||||
</div>
|
||||
<div class="nav-collapse">
|
||||
{{if response.menu is not None:}}
|
||||
<ul id="menu" class="nav pull-right">
|
||||
{{for _name,_active,_link in response.menu:}}
|
||||
<li>{{=A(SPAN(_name), _href=_link, _class=_active and 'button select' or 'button')}}</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
{{pass}}
|
||||
</div><!--/.nav-collapse -->
|
||||
</div><!-- /container-fluid -->
|
||||
</div><!-- /navbar-inner -->
|
||||
</div><!-- /#header -->
|
||||
|
||||
<!-- MAIN
|
||||
=========== -->
|
||||
<div id="{{=globals().get('main_id', 'main')}}" class="container-fluid">
|
||||
<div id="main_inner" class="row-fluid">
|
||||
<div class="span12">
|
||||
<div class="w2p_flash alert">{{=response.flash or ''}}</div>
|
||||
{{include}}
|
||||
</div><!-- /main span12 -->
|
||||
</div><!-- /main row-fluid -->
|
||||
</div><!-- /#main -->
|
||||
|
||||
<!-- FOOTER
|
||||
============== -->
|
||||
{{block footer}}
|
||||
<footer id="footer" class="fixed">
|
||||
<p><span>{{=T('Powered by')}} {{=A('web2py', _href='http://www.web2py.com')}}™ {{=T('created by')}} Massimo Di Pierro ©2007-{{=request.now.year}}
|
||||
{{if hasattr(T,'get_possible_languages_info'):}}
|
||||
- {{=T('Admin language')}}</span>
|
||||
<select name="adminlanguage" onchange="var date = new Date();cookieDate=date.setTime(date.getTime()+(100*24*60*60*1000));document.cookie='adminLanguage='+this.options[this.selectedIndex].id+'; expires='+cookieDate+'; path=/';window.location.reload()">
|
||||
{{for langinfo in sorted([(code,info[1]) for code,info in T.get_possible_languages_info().iteritems() if code != 'default']):}}
|
||||
<option {{=T.accepted_language==langinfo[0] and 'selected' or ''}} {{='id='+langinfo[0]}} >{{=langinfo[1]}}</option>
|
||||
{{pass}}
|
||||
</select>
|
||||
{{else:}}
|
||||
</span>{{pass}}
|
||||
</p>
|
||||
</footer><!-- /#footer -->
|
||||
{{end}}
|
||||
|
||||
<!-- BS JAVASCRIPT
|
||||
====================== -->
|
||||
<script src="{{=URL('static','js/bootstrap.min.js')}}"></script>
|
||||
<script type="text/javascript">
|
||||
jQuery(document).ready(function(){
|
||||
jQuery("[rel=tooltip]").tooltip();
|
||||
jQuery(":input").attr("autocomplete","off");
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
// ====================
|
||||
// upload input mask
|
||||
// ====================
|
||||
|
||||
function FileSelectHandler(e) {
|
||||
e.stopPropagation();
|
||||
var filename = e.target.value.split(/\\|\//).pop();
|
||||
jQuery('#fileselect>span').removeClass('txtPlaceholder').text(filename)
|
||||
}
|
||||
|
||||
jQuery(document).ready(function(){
|
||||
var iupload = jQuery('#appupdate_file');
|
||||
var ow = 300, oh = 20;
|
||||
var iplaceholder = jQuery('<span class="txtPlaceholder">{{=T("no package selected")}}</span>'),
|
||||
iuploadbtn = jQuery('<button class="btn btn-inverse btn-mini uploadbtn"><i class="icon-white icon-circle-arrow-up"></i></button>');
|
||||
iupload
|
||||
.addClass('masked')
|
||||
.wrap('<div id="fileselect" style="width:'+ow+'px;height:'+oh+'px"></div>')
|
||||
.on('change', function(event){FileSelectHandler(event)});
|
||||
jQuery('#fileselect').append(iplaceholder, iuploadbtn);
|
||||
});
|
||||
</script>
|
||||
|
||||
{{if request.function in ('index','site'):}}
|
||||
<a style="position:fixed;bottom:0;left:0;z-index:1000" href="https://groups.google.com/forum/?fromgroups#!forum/web2py" target="_blank">
|
||||
<!-- http://webchat.freenode.net/?channels=web2py" //-->
|
||||
<img src="{{=URL('static','images/questions.png')}}" />
|
||||
</a>
|
||||
{{pass}}
|
||||
<div class="{{=middle_column}} padded">{{include}}</div>
|
||||
{{if right_sidebar_enabled:}}
|
||||
<div class="quarter padded">{{block right_sidebar}}{{end}}</div>
|
||||
{{pass}}
|
||||
</div>
|
||||
</main>
|
||||
<footer class="black">
|
||||
<div class="container padded max900">
|
||||
<div class="fill">
|
||||
Copyright @ 2016 - Powered by Web2py
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
<script>
|
||||
// prevent android horizontal scrolling
|
||||
window.addEventListener("scroll", function(){window.scroll(0, window.pageYOffset);}, false);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
var w2p_ajax_confirm_message = "{{=T('Are you sure you want to delete this object?')}}";
|
||||
var w2p_ajax_date_format = "{{=T('%Y-%m-%d')}}";
|
||||
var w2p_ajax_datetime_format = "{{=T('%Y-%m-%d %H:%M:%S')}}";
|
||||
var w2p_ajax_disable_with_message = "{{=T('Working...')}}";
|
||||
var ajax_error_500 = '{{=T.M('An error occured, please [[reload %s]] the page') % URL(args=request.args, vars=request.get_vars) }}'
|
||||
//--></script>
|
||||
{{
|
||||
|
||||
@@ -10,7 +10,7 @@ session.forget()
|
||||
cache_expire = not request.is_local and 300 or 0
|
||||
|
||||
|
||||
@cache.action(time_expire=300, cache_model=cache.ram, quick='P')
|
||||
#@cache.action(time_expire=300, cache_model=cache.ram, quick='P')
|
||||
def index():
|
||||
return response.render()
|
||||
|
||||
|
||||
@@ -35,12 +35,6 @@ def hello6():
|
||||
response.flash = 'Hello World in a flash!'
|
||||
return dict(message=T('Hello World'))
|
||||
|
||||
|
||||
def status():
|
||||
""" page that shows internal status"""
|
||||
return dict(toolbar=response.toolbar())
|
||||
|
||||
|
||||
def redirectme():
|
||||
""" redirects to /{{=request.application}}/{{=request.controller}}/hello3 """
|
||||
|
||||
|
||||
@@ -27,4 +27,4 @@ def xml():
|
||||
|
||||
|
||||
def beautify():
|
||||
return dict(message=BEAUTIFY(request))
|
||||
return dict(message=BEAUTIFY(dict(a=1,b=[2,3,dict(hello='world')])))
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
- [[Intro video http://www.youtube.com/watch?v=BXzqmHx6edY]] and [[code examples https://github.com/mjhea0/web2py]]
|
||||
- [[Step by step tutorial https://milesm.pythonanywhere.com/wiki]]
|
||||
- [[web2py Reference Project http://www.web2pyref.com/]]
|
||||
- [[An advanced tutorial https://milesm.pythonanywhere.com/wiki]]
|
||||
- [[Killer Web Development Tutorial http://killer-web-development.com/]]
|
||||
- [[Real Python for the Web http://www.realpython.com]] (web development with web2py and more!)
|
||||
- [[Admin Demo http://www.web2py.com/demo_admin popup]] (web-based IDE)
|
||||
@@ -19,9 +20,9 @@
|
||||
|
||||
#### Code
|
||||
- [[web2pyslices (recipes) http://www.web2pyslices.com popup]]
|
||||
- [[Layouts http://www.web2py.com/layouts popup]]
|
||||
- [[Dashboard welcome app https://github.com/mjbeller/web2py-starter]]
|
||||
- [[stupid.css theme https://github.com/mdipierro/web2py-welcome-theme-stupid]]
|
||||
- [[Plugins http://www.web2py.com/plugins popup]]
|
||||
- [[More Plugins http://dev.s-cubism.com/web2py_plugins]]
|
||||
- [[Appliances http://www.web2py.com/appliances popup]]
|
||||
- [[web2py utils http://packages.python.org/web2py_utils/ popup]]
|
||||
- [[Sublime text 3 plugin https://bitbucket.org/kfog/w2p popup]]
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
@import url(http://fonts.googleapis.com/css?family=Economica);
|
||||
@@import url(http://fonts.googleapis.com/css?family=Belleza);
|
||||
|
||||
body { font-family: Arial, Helvetica; }
|
||||
a, a:visited, a:hover, h1,h2,h3,h4,h5 {color: #658883}
|
||||
a.btn-danger, a.btn-warning, a.btn-success {color:white}
|
||||
h1,h2,h3,h4,h5 { font-family: "Economica", Arial, Helevtica; }
|
||||
body {
|
||||
background: url('../images/stripes.png') repeat-x;
|
||||
}
|
||||
#header {
|
||||
margin-top: 40px;
|
||||
}
|
||||
.btn-180 {
|
||||
width: 180px;
|
||||
}
|
||||
.page-header {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
************/
|
||||
|
||||
/*** basic styles ***/
|
||||
* {border:0; margin:0; padding:0; font-familiy:Helvetica}
|
||||
html, body {max-width: 100vw !important;overflow-x: hidden !important}
|
||||
*, *:after, *:before {border:0; margin:0; padding:0; -webkit-box-sizing:border-box; -moz-box-sizing:border-box; box-sizing:border-box}
|
||||
html, body {max-width: 100vw !important; overflow-x: hidden !important}
|
||||
body {font-family:"HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif}
|
||||
p, li {margin-bottom:0.5em}
|
||||
p {text-align:justify}
|
||||
@@ -49,14 +49,14 @@ header, footer {with:100%}
|
||||
|
||||
/*** helpers ***/
|
||||
.rounded {-moz-border-radius:5px; border-radius:5px}
|
||||
.padded {padding:10px 20px !important; -webkit-box-sizing:border-box; -moz-box-sizing:border-box; box-sizing:border-box}
|
||||
.padded {padding:10px 20px !important}
|
||||
.center {text-align:center !important; margin-left:auto; margin-right:auto}
|
||||
.center>div {text-align:left}
|
||||
.right {right:0; text-align:right}
|
||||
.middle div {vertical-align:middle !important}
|
||||
.bottom div {vertical-align:bottom !important}
|
||||
.xscroll {overflow-x:scroll; width:100%}
|
||||
.yscroll {overflow-y:scroll; width:100%}
|
||||
.xscroll {overflow-x:scroll}
|
||||
.yscroll {overflow-y:scroll}
|
||||
.nowrap {white-space:nowrap; overflow-x:hidden}
|
||||
.fill {width:100%}
|
||||
.lifted {box-shadow:5px 5px 10px #666}
|
||||
@@ -66,15 +66,16 @@ header, footer {with:100%}
|
||||
.hidden {display:none}
|
||||
|
||||
/*** forms ***/
|
||||
input:not([type]), input:not([type=checkbox]):not([type=radio]):not([type=submit]), [type=file]:before {outline:none; padding:0.5em 1em; margin:0.5px; border-bottom:1px solid #ddd; width:100%}
|
||||
input:not([type]), input:not([type=checkbox]):not([type=radio]):not([type=button]):not([type=submit]), [type=file]:before {outline:none; padding:0.5em 1em; margin:0.5px; border-bottom:1px solid #ddd; width:100%}
|
||||
textarea {width:100%; border:1px solid #ddd; padding:4px 8px; outline:none; outline:none}
|
||||
select {-webkit-appearance:none; outline:none; padding:0.5em 1em; border-radius:0; margin:0.5px; border-bottom:1px solid #ddd}
|
||||
select {-webkit-appearance:none; outline:none; padding:0.5em 1em; border-radius:0; margin:0.5px; border-bottom:1px solid #ddd; width:100%;background-color:transparent}
|
||||
input, textarea, select, button {font-size:12px}
|
||||
input:not([type]), input:not([type=checkbox]):not([type=radio]):not([type=submit]):hover, select:hover, textarea:hover {background-color:#fbf6d9; transition:background-color 1s ease}
|
||||
input:not([type]):hover, input:not([type=checkbox]):not([type=radio]):not([type=button]):not([type=submit]):hover, select:hover, textarea:hover {background-color:#fbf6d9; transition:background-color 1s ease}
|
||||
input:invalid, input.error {background:#cc1f00!important;color:white}
|
||||
|
||||
/*** grid ***/
|
||||
.container {margin-right:-20px}
|
||||
.container>.quarter, .container>.half, .container>.third, .container>.twothirds, .container>.threequarters, .container>.fill{display:inline-block; padding:5px 20px 5px 0; -webkit-box-sizing:border-box; -moz-box-sizing:border-box; box-sizing:border-box; vertical-align:top}
|
||||
.container>.quarter, .container>.half, .container>.third, .container>.twothirds, .container>.threequarters, .container>.fill{display:inline-block; padding:5px 20px 5px 0; vertical-align:top}
|
||||
.container>.fill {width:100%; margin-right:-20px}
|
||||
.container img, .container video {max-width:100%}
|
||||
@media (min-width:800px) {
|
||||
@@ -189,7 +190,7 @@ input:not([type]), input:not([type=checkbox]):not([type=radio]):not([type=submit
|
||||
.menu ul {background:white; border:1px solid #e1e1e1; visibility:hidden; opacity:0; position:absolute; top:110%; padding:0; z-index:1000; transition:all 0.2s ease-out; list-style-type:none; box-shadow:5px 5px 10px #666}
|
||||
.menu ul a {padding:10px 15px; color:#333; font-weight:700; font-size:12px; line-height:16px; display: block}
|
||||
.menu ul li {float:none; width:200px}
|
||||
.menu ul ul {top:0; left:80%; z-index:2000}
|
||||
.menu ul ul {top:0; left:80%; z-index:1100}
|
||||
.menu li:hover > ul {visibility:visible; opacity:1}
|
||||
.menu>li>ul>li:first-child:before{content:''; position:absolute; width:1px; height:1px; border:10px solid transparent; left:50px; top:-20px; margin-left:-10px; border-bottom-color:white}
|
||||
.menu.dark ul {background:black; border:1px solid black}
|
||||
@@ -199,7 +200,7 @@ input:not([type]), input:not([type=checkbox]):not([type=radio]):not([type=submit
|
||||
@media (max-width:599px) {
|
||||
header .menu li, header .menu ul {width: 100%}
|
||||
header .menu.right {float:left; text-align:left}
|
||||
header .menu ul ul {top:2.5em; left:-1px; z-index:2000}
|
||||
header .menu ul ul {top:2.5em; left:-1px}
|
||||
}
|
||||
|
||||
@media (min-width:600px) {
|
||||
@@ -264,24 +265,30 @@ a:not(.btn):not(.noeffect):after {
|
||||
|
||||
/*** tooltips from http://codepen.io/trezy/pen/Khnzy ***/
|
||||
[data-tooltip] {position:relative}
|
||||
[data-tooltip]:hover:after,[data-tooltip]:hover:before {display:block}
|
||||
[data-tooltip]:before, [data-tooltip]:after {display:none; position:absolute; top:0}
|
||||
[data-tooltip]:before {
|
||||
[data-tooltip]:hover:after,[data-tooltip]:hover:before {display:block}
|
||||
[data-tooltip]:hover:before {
|
||||
border-bottom:.6em solid black;
|
||||
border-bottom:.6em solid black;
|
||||
border-left:7px solid transparent;
|
||||
border-right:7px solid transparent;
|
||||
content:"";
|
||||
left:20px;
|
||||
margin-top:1em;
|
||||
left:0;
|
||||
margin-top:12px;
|
||||
z-index:2000;
|
||||
}
|
||||
[data-tooltip]:after {
|
||||
[data-tooltip]:hover:after {
|
||||
z-index:2000;
|
||||
background-color:rgba(0,0,0,0.8);
|
||||
border:4px solid rgba(0,0,0,0.8);
|
||||
border-radius:7px;
|
||||
color:white;
|
||||
text-transform:none;
|
||||
font-size: 12px;
|
||||
content:attr(data-tooltip);
|
||||
left:0;
|
||||
top:2px;
|
||||
margin-left:-20;
|
||||
margin-top:1.5em;
|
||||
padding:5px 15px;
|
||||
white-space:pre-wrap;
|
||||
@@ -336,24 +343,17 @@ a:not(.btn):not(.noeffect):after {
|
||||
.navy{background-color:#001f3f!important;color:white}.blue{background-color:#0074d9!important;color:white}.aqua{background-color:#7fdbff!important;color:black}.teal{background-color:#39cccc!important;color:white}.olive{background-color:#3d9970!important;color:white}.green{background-color:#2ecc40!important;color:white}.aquamarine{background-color:#26a69a!important;color:white}.lime{background-color:#01ff70!important;color:black}.yellow{background-color:#ffdc00!important;color:black}.orange{background-color:#ff851b!important;color:white}.red{background-color:#cc1f00!important;color:white}.fuchsia{background-color:#f012be!important;color:white}.pink{background-color:#ee6e73!important;color:white}.purple{background-color:#b10dc9!important;color:white}.maroon{background-color:#85144b!important;color:white}.white{background-color:#fff!important;color:black;-webkit-box-shadow:inset 0px 0px 0px 1px #ddd;-moz-box-shadow:inset 0px 0px 0px 1px #ddd;box-shadow:inset 0px 0px 0px 1px #ddd}.gray{background-color:#aaa!important;color:white}.silver{background-color:#f1f1f1!important;color:black}.black{background-color:#000!important;color:white}.glass{background:rgba(255,255,255,0.5)!important;color:black}
|
||||
|
||||
/**** tags ****/
|
||||
.tags > span, .tags > span.off:hover {
|
||||
height: 30px;
|
||||
.tags > span {
|
||||
padding: 4px 9px;
|
||||
text-decoration: none;
|
||||
margin: 0 5px 30px 0 !important;
|
||||
white-space: nowrap;
|
||||
color: white;
|
||||
background-color: #26a69a;
|
||||
border-radius: 5px;
|
||||
font-size:12px;
|
||||
margin: 5px 5px 5px 0 !important;
|
||||
line-height: 32px;
|
||||
}
|
||||
.tags.dismissible > span:not(.off):hover {
|
||||
background-color: #ccc !important;
|
||||
}
|
||||
.tags.dismissible > span:not(.off):after {
|
||||
content: " \f00d";
|
||||
font-family: FontAwesome;
|
||||
}
|
||||
.tags > span.off {
|
||||
background-color: #ccc;
|
||||
}
|
||||
.tags.dismissible > span:hover {opacity: 0.5}
|
||||
.tags.dismissible > span:not(.off):after {content:" ✕"}
|
||||
.tags > span.off {background-color: #ccc}
|
||||
.tags.dismissible > span.off:hover {background-color:#26a69a}
|
||||
|
||||
+5
-5
File diff suppressed because one or more lines are too long
@@ -1,11 +1,10 @@
|
||||
{{extend 'layout.html'}}
|
||||
|
||||
<center>
|
||||
<iframe src="//player.vimeo.com/hubnut/album/3016728?color=ff6600&background=ffffff&slideshow=1&video_title=1&video_byline=1" width="400" height="300" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>
|
||||
</center>
|
||||
|
||||
<div>
|
||||
{{=get_content('main')}}
|
||||
<center>
|
||||
<iframe src="//player.vimeo.com/hubnut/album/3016728?color=ff6600&background=ffffff&slideshow=1&video_title=1&video_byline=1" width="400" height="300" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>
|
||||
</center>
|
||||
{{=get_content('official')}}
|
||||
{{=get_content('community')}}
|
||||
{{=get_content('more')}}
|
||||
|
||||
@@ -94,7 +94,6 @@ def status():
|
||||
return dict(toobar=response.toolbar())
|
||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
||||
<p>Here we are showing the request, session and response objects using the generic.html template.
|
||||
<br/>Try it here: <a class="btn" href="/{{=request.application}}/simple_examples/status">status</a></p>
|
||||
|
||||
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
|
||||
{{=CODE("""
|
||||
@@ -278,7 +277,7 @@ def xml():
|
||||
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: template_examples.py </b>
|
||||
{{=CODE("""
|
||||
def beautify():
|
||||
return dict(message=BEAUTIFY(request))
|
||||
dict(message=BEAUTIFY(dict(a=1,b=[2,3,dict(hello='world')])))
|
||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: template_examples/beautify.html</b>
|
||||
{{=CODE(open(os.path.join(request.folder,'views/template_examples/beautify.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
||||
<p>You can use BEAUTIFY to turn lists and dictionaries into organized HTML.
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
<a class="btn rounded red fill" href="{{=URL('download')}}">
|
||||
Download Now
|
||||
</a>
|
||||
<a class="btn rounded red fill" href="{{=URL('examples')}}">
|
||||
Quick Examples
|
||||
</a>
|
||||
<a class="btn rounded red fill" href="https://www.pythonanywhere.com/try-web2py">
|
||||
Try it now online
|
||||
</a>
|
||||
@@ -60,12 +63,7 @@
|
||||
<div class="third">
|
||||
<div class="padded">
|
||||
<h5><a href="{{=URL('documentation')}}">Extensive Docs</a></h5>
|
||||
<p>Start with some <a href="{{=URL('examples')}}">quick examples</a>, then read the <a href="http://www.web2py.com/book" target="_blank">manual</a> and the <a href="http://web2py.readthedocs.org/en/latest/" target="_blank">Sphinx docs</a>, watch <a href="http://vimeo.com/album/178500" target="_blank">videos</a>, and join a <a href="{{=URL('default', 'usergroups')}}">user group</a> for discussion. Take advantage of the <a href="http://www.web2py.com/layouts" target="_blank">layouts</a>, <a href="http://dev.s-cubism.com/web2py_plugins" target="_blank">plugins</a>, <a href="http://www.web2py.com/appliances" target="_blank">appliances</a>, and <a href="http://web2pyslices.com" target="_blank">recipes</a>.</p>
|
||||
<p>Start with some <a href="{{=URL('examples')}}">quick examples</a>, then read the <a href="http://www.web2py.com/book" target="_blank">manual</a> and the <a href="http://web2py.readthedocs.org/en/latest/" target="_blank">Sphinx docs</a>, watch <a href="http://vimeo.com/album/178500" target="_blank">videos</a>, and join a <a href="{{=URL('default', 'usergroups')}}">user group</a> for discussion. Take advantage of the <a href="http://www.web2py.com/layouts" target="_blank">layouts</a>, <a href="http://www.web2pyslices.com/home?content_type=Package" target="_blank">plugins</a>, <a href="http://www.web2py.com/appliances" target="_blank">appliances</a>, and <a href="http://web2pyslices.com" target="_blank">recipes</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="fill padded">
|
||||
<img class="scale-with-grid centered" src="/examples/static/images/shadow-bottom.png">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -9,12 +9,13 @@
|
||||
<link href="{{=URL('static','css/web2py.css')}}" rel="stylesheet" type="text/css"/>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
|
||||
<style>
|
||||
th {color: black}
|
||||
th, td {color: black!important}
|
||||
tbody tr:hover {background-color:transparent}
|
||||
tbody tr {border-bottom: none}
|
||||
p {text-align: left}
|
||||
p, li { line-height: 1.6em}
|
||||
pre {background-color: black!important;border-radius:5px; color:white; padding:10px}
|
||||
a.btn.btn180 {padding:20px; font-size:1.2em; width:200px!important}
|
||||
a.btn.btn180 {padding:20px; font-size:1.2em; width:200px!important}
|
||||
</style>
|
||||
{{
|
||||
left_sidebar_enabled = globals().get('left_sidebar_enabled', False)
|
||||
@@ -51,6 +52,10 @@
|
||||
<div class="quarter padded">{{block right_sidebar}}{{end}}</div>
|
||||
{{pass}}
|
||||
</div>
|
||||
<div class="silver center padded">
|
||||
<a class="fa fa-twitter" href="https://twitter.com/web2py/"></a>
|
||||
<a class="fa fa-facebook" href="https://www.facebook.com/web2py/"></a>
|
||||
</div>
|
||||
</main>
|
||||
<footer class="black">
|
||||
<div class="container padded max900">
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
{{extend 'layout.html'}}
|
||||
|
||||
{{=toolbar}}
|
||||
@@ -1,480 +1,491 @@
|
||||
# coding: utf8
|
||||
{
|
||||
'!langcode!': 'cs-cz',
|
||||
'!langname!': 'čeština',
|
||||
'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': 'Kolonka "Upravit" je nepovinný výraz, například "pole1=\'nováhodnota\'". Výsledky databázového JOINu nemůžete mazat ani upravovat.',
|
||||
'"User Exception" debug mode. An error ticket could be issued!': '"User Exception" debug mode. An error ticket could be issued!',
|
||||
'%%{Row} in Table': '%%{řádek} v tabulce',
|
||||
'%%{Row} selected': 'označených %%{řádek}',
|
||||
'%s %%{row} deleted': '%s smazaných %%{záznam}',
|
||||
'%s %%{row} updated': '%s upravených %%{záznam}',
|
||||
'%s selected': '%s označených',
|
||||
'%Y-%m-%d': '%d.%m.%Y',
|
||||
'%Y-%m-%d %H:%M:%S': '%d.%m.%Y %H:%M:%S',
|
||||
'(requires internet access)': '(vyžaduje připojení k internetu)',
|
||||
'(requires internet access, experimental)': '(requires internet access, experimental)',
|
||||
'(something like "it-it")': '(například "cs-cs")',
|
||||
'@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(soubor **gluon/contrib/plural_rules/%s.py** nenalezen)',
|
||||
'@markmin\x01Searching: **%s** %%{file}': 'Hledání: **%s** %%{soubor}',
|
||||
'About': 'O programu',
|
||||
'About application': 'O aplikaci',
|
||||
'Access Control': 'Řízení přístupu',
|
||||
'Add breakpoint': 'Přidat bod přerušení',
|
||||
'Additional code for your application': 'Další kód pro Vaši aplikaci',
|
||||
'Admin design page': 'Admin design page',
|
||||
'Admin language': 'jazyk rozhraní',
|
||||
'Administrative interface': 'pro administrátorské rozhraní klikněte sem',
|
||||
'Administrative Interface': 'Administrátorské rozhraní',
|
||||
'administrative interface': 'rozhraní pro správu',
|
||||
'Administrator Password:': 'Administrátorské heslo:',
|
||||
'Ajax Recipes': 'Recepty s ajaxem',
|
||||
'An error occured, please %s the page': 'An error occured, please %s the page',
|
||||
'and rename it:': 'a přejmenovat na:',
|
||||
'appadmin': 'appadmin',
|
||||
'appadmin is disabled because insecure channel': 'appadmin je zakázaná bez zabezpečeného spojení',
|
||||
'Application': 'Application',
|
||||
'application "%s" uninstalled': 'application "%s" odinstalována',
|
||||
'application compiled': 'aplikace zkompilována',
|
||||
'Application name:': 'Název aplikace:',
|
||||
'are not used': 'nepoužita',
|
||||
'are not used yet': 'ještě nepoužita',
|
||||
'Are you sure you want to delete this object?': 'Opravdu chcete odstranit tento objekt?',
|
||||
'Are you sure you want to uninstall application "%s"?': 'Opravdu chcete odinstalovat aplikaci "%s"?',
|
||||
'arguments': 'arguments',
|
||||
'at char %s': 'at char %s',
|
||||
'at line %s': 'at line %s',
|
||||
'ATTENTION:': 'ATTENTION:',
|
||||
'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.',
|
||||
'Available Databases and Tables': 'Dostupné databáze a tabulky',
|
||||
'back': 'zpět',
|
||||
'Back to wizard': 'Back to wizard',
|
||||
'Basics': 'Basics',
|
||||
'Begin': 'Začít',
|
||||
'breakpoint': 'bod přerušení',
|
||||
'Breakpoints': 'Body přerušení',
|
||||
'breakpoints': 'body přerušení',
|
||||
'Buy this book': 'Koupit web2py knihu',
|
||||
'Cache': 'Cache',
|
||||
'cache': 'cache',
|
||||
'Cache Keys': 'Klíče cache',
|
||||
'cache, errors and sessions cleaned': 'cache, chyby a relace byly pročištěny',
|
||||
'can be a git repo': 'může to být git repo',
|
||||
'Cancel': 'Storno',
|
||||
'Cannot be empty': 'Nemůže být prázdné',
|
||||
'Change Admin Password': 'Změnit heslo pro správu',
|
||||
'Change admin password': 'Změnit heslo pro správu aplikací',
|
||||
'Change password': 'Změna hesla',
|
||||
'check all': 'vše označit',
|
||||
'Check for upgrades': 'Zkusit aktualizovat',
|
||||
'Check to delete': 'Označit ke smazání',
|
||||
'Check to delete:': 'Označit ke smazání:',
|
||||
'Checking for upgrades...': 'Zjišťuji, zda jsou k dispozici aktualizace...',
|
||||
'Clean': 'Pročistit',
|
||||
'Clear CACHE?': 'Vymazat CACHE?',
|
||||
'Clear DISK': 'Vymazat DISK',
|
||||
'Clear RAM': 'Vymazat RAM',
|
||||
'Click row to expand traceback': 'Pro rozbalení stopy, klikněte na řádek',
|
||||
'Click row to view a ticket': 'Pro zobrazení chyby (ticketu), klikněte na řádku...',
|
||||
'Client IP': 'IP adresa klienta',
|
||||
'code': 'code',
|
||||
'Code listing': 'Code listing',
|
||||
'collapse/expand all': 'vše sbalit/rozbalit',
|
||||
'Community': 'Komunita',
|
||||
'Compile': 'Zkompilovat',
|
||||
'compiled application removed': 'zkompilovaná aplikace smazána',
|
||||
'Components and Plugins': 'Komponenty a zásuvné moduly',
|
||||
'Condition': 'Podmínka',
|
||||
'continue': 'continue',
|
||||
'Controller': 'Kontrolér (Controller)',
|
||||
'Controllers': 'Kontroléry',
|
||||
'controllers': 'kontroléry',
|
||||
'Copyright': 'Copyright',
|
||||
'Count': 'Počet',
|
||||
'Create': 'Vytvořit',
|
||||
'create file with filename:': 'vytvořit soubor s názvem:',
|
||||
'created by': 'vytvořil',
|
||||
'Created By': 'Vytvořeno - kým',
|
||||
'Created On': 'Vytvořeno - kdy',
|
||||
'crontab': 'crontab',
|
||||
'Current request': 'Aktuální požadavek',
|
||||
'Current response': 'Aktuální odpověď',
|
||||
'Current session': 'Aktuální relace',
|
||||
'currently running': 'právě běží',
|
||||
'currently saved or': 'uloženo nebo',
|
||||
'customize me!': 'upravte mě!',
|
||||
'data uploaded': 'data nahrána',
|
||||
'Database': 'Rozhraní databáze',
|
||||
'Database %s select': 'databáze %s výběr',
|
||||
'Database administration': 'Database administration',
|
||||
'database administration': 'správa databáze',
|
||||
'Date and Time': 'Datum a čas',
|
||||
'day': 'den',
|
||||
'db': 'db',
|
||||
'DB Model': 'Databázový model',
|
||||
'Debug': 'Ladění',
|
||||
'defines tables': 'defines tables',
|
||||
'Delete': 'Smazat',
|
||||
'delete': 'smazat',
|
||||
'delete all checked': 'smazat vše označené',
|
||||
'delete plugin': 'delete plugin',
|
||||
'Delete this file (you will be asked to confirm deletion)': 'Smazat tento soubor (budete požádán o potvrzení mazání)',
|
||||
'Delete:': 'Smazat:',
|
||||
'deleted after first hit': 'smazat po prvním dosažení',
|
||||
'Demo': 'Demo',
|
||||
'Deploy': 'Nahrát',
|
||||
'Deploy on Google App Engine': 'Nahrát na Google App Engine',
|
||||
'Deploy to OpenShift': 'Nahrát na OpenShift',
|
||||
'Deployment Recipes': 'Postupy pro deployment',
|
||||
'Description': 'Popis',
|
||||
'design': 'návrh',
|
||||
'Detailed traceback description': 'Podrobný výpis prostředí',
|
||||
'details': 'podrobnosti',
|
||||
'direction: ltr': 'směr: ltr',
|
||||
'Disable': 'Zablokovat',
|
||||
'DISK': 'DISK',
|
||||
'Disk Cache Keys': 'Klíče diskové cache',
|
||||
'Disk Cleared': 'Disk smazán',
|
||||
'docs': 'dokumentace',
|
||||
'Documentation': 'Dokumentace',
|
||||
"Don't know what to do?": 'Nevíte kudy kam?',
|
||||
'done!': 'hotovo!',
|
||||
'Download': 'Stáhnout',
|
||||
'download layouts': 'stáhnout moduly rozvržení stránky',
|
||||
'download plugins': 'stáhnout zásuvné moduly',
|
||||
'E-mail': 'E-mail',
|
||||
'Edit': 'Upravit',
|
||||
'edit all': 'edit all',
|
||||
'Edit application': 'Správa aplikace',
|
||||
'edit controller': 'edit controller',
|
||||
'Edit current record': 'Upravit aktuální záznam',
|
||||
'Edit Profile': 'Upravit profil',
|
||||
'edit views:': 'upravit pohled:',
|
||||
'Editing file "%s"': 'Úprava souboru "%s"',
|
||||
'Editing Language file': 'Úprava jazykového souboru',
|
||||
'Editing Plural Forms File': 'Editing Plural Forms File',
|
||||
'Email and SMS': 'Email a SMS',
|
||||
'Enable': 'Odblokovat',
|
||||
'enter a number between %(min)g and %(max)g': 'zadejte číslo mezi %(min)g a %(max)g',
|
||||
'enter an integer between %(min)g and %(max)g': 'zadejte celé číslo mezi %(min)g a %(max)g',
|
||||
'Error': 'Chyba',
|
||||
'Error logs for "%(app)s"': 'Seznam výskytu chyb pro aplikaci "%(app)s"',
|
||||
'Error snapshot': 'Snapshot chyby',
|
||||
'Error ticket': 'Ticket chyby',
|
||||
'Errors': 'Chyby',
|
||||
'Exception %(extype)s: %(exvalue)s': 'Exception %(extype)s: %(exvalue)s',
|
||||
'Exception %s': 'Exception %s',
|
||||
'Exception instance attributes': 'Prvky instance výjimky',
|
||||
'Expand Abbreviation': 'Expand Abbreviation',
|
||||
'export as csv file': 'exportovat do .csv souboru',
|
||||
'exposes': 'vystavuje',
|
||||
'exposes:': 'vystavuje funkce:',
|
||||
'extends': 'rozšiřuje',
|
||||
'failed to compile file because:': 'soubor se nepodařilo zkompilovat, protože:',
|
||||
'FAQ': 'Často kladené dotazy',
|
||||
'File': 'Soubor',
|
||||
'file': 'soubor',
|
||||
'file "%(filename)s" created': 'file "%(filename)s" created',
|
||||
'file saved on %(time)s': 'soubor uložen %(time)s',
|
||||
'file saved on %s': 'soubor uložen %s',
|
||||
'Filename': 'Název souboru',
|
||||
'filter': 'filtr',
|
||||
'Find Next': 'Najít další',
|
||||
'Find Previous': 'Najít předchozí',
|
||||
'First name': 'Křestní jméno',
|
||||
'Forgot username?': 'Zapomněl jste svoje přihlašovací jméno?',
|
||||
'forgot username?': 'zapomněl jste svoje přihlašovací jméno?',
|
||||
'Forms and Validators': 'Formuláře a validátory',
|
||||
'Frames': 'Frames',
|
||||
'Free Applications': 'Aplikace zdarma',
|
||||
'Functions with no doctests will result in [passed] tests.': 'Functions with no doctests will result in [passed] tests.',
|
||||
'Generate': 'Vytvořit',
|
||||
'Get from URL:': 'Stáhnout z internetu:',
|
||||
'Git Pull': 'Git Pull',
|
||||
'Git Push': 'Git Push',
|
||||
'Globals##debug': 'Globální proměnné',
|
||||
'go!': 'OK!',
|
||||
'Goto': 'Goto',
|
||||
'graph model': 'graph model',
|
||||
'Group %(group_id)s created': 'Skupina %(group_id)s vytvořena',
|
||||
'Group ID': 'ID skupiny',
|
||||
'Groups': 'Skupiny',
|
||||
'Hello World': 'Ahoj světe',
|
||||
'Help': 'Nápověda',
|
||||
'Hide/Show Translated strings': 'Skrýt/Zobrazit přeložené texty',
|
||||
'Hits': 'Kolikrát dosaženo',
|
||||
'Home': 'Domovská stránka',
|
||||
'honored only if the expression evaluates to true': 'brát v potaz jen když se tato podmínka vyhodnotí kladně',
|
||||
'How did you get here?': 'Jak jste se sem vlastně dostal?',
|
||||
'If start the upgrade, be patient, it may take a while to download': 'If start the upgrade, be patient, it may take a while to download',
|
||||
'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.',
|
||||
'import': 'import',
|
||||
'Import/Export': 'Import/Export',
|
||||
'includes': 'zahrnuje',
|
||||
'Index': 'Index',
|
||||
'insert new': 'vložit nový záznam ',
|
||||
'insert new %s': 'vložit nový záznam %s',
|
||||
'inspect attributes': 'inspect attributes',
|
||||
'Install': 'Instalovat',
|
||||
'Installed applications': 'Nainstalované aplikace',
|
||||
'Interaction at %s line %s': 'Interakce v %s, na řádce %s',
|
||||
'Interactive console': 'Interaktivní příkazová řádka',
|
||||
'Internal State': 'Vnitřní stav',
|
||||
'Introduction': 'Úvod',
|
||||
'Invalid email': 'Neplatný email',
|
||||
'Invalid password': 'Nesprávné heslo',
|
||||
'invalid password.': 'neplatné heslo',
|
||||
'Invalid Query': 'Neplatný dotaz',
|
||||
'invalid request': 'Neplatný požadavek',
|
||||
'Is Active': 'Je aktivní',
|
||||
'It is %s %%{day} today.': 'Dnes je to %s %%{den}.',
|
||||
'Key': 'Klíč',
|
||||
'Key bindings': 'Vazby klíčů',
|
||||
'Key bindings for ZenCoding Plugin': 'Key bindings for ZenCoding Plugin',
|
||||
'languages': 'jazyky',
|
||||
'Languages': 'Jazyky',
|
||||
'Last name': 'Příjmení',
|
||||
'Last saved on:': 'Naposledy uloženo:',
|
||||
'Layout': 'Rozvržení stránky (layout)',
|
||||
'Layout Plugins': 'Moduly rozvržení stránky (Layout Plugins)',
|
||||
'Layouts': 'Rozvržení stránek',
|
||||
'License for': 'Licence pro',
|
||||
'Line number': 'Číslo řádku',
|
||||
'LineNo': 'Č.řádku',
|
||||
'Live Chat': 'Online pokec',
|
||||
'loading...': 'nahrávám...',
|
||||
'locals': 'locals',
|
||||
'Locals##debug': 'Lokální proměnné',
|
||||
'Logged in': 'Přihlášení proběhlo úspěšně',
|
||||
'Logged out': 'Odhlášení proběhlo úspěšně',
|
||||
'Login': 'Přihlásit se',
|
||||
'login': 'přihlásit se',
|
||||
'Login to the Administrative Interface': 'Přihlásit se do Správce aplikací',
|
||||
'logout': 'odhlásit se',
|
||||
'Logout': 'Odhlásit se',
|
||||
'Lost Password': 'Zapomněl jste heslo',
|
||||
'Lost password?': 'Zapomněl jste heslo?',
|
||||
'lost password?': 'zapomněl jste heslo?',
|
||||
'Manage': 'Manage',
|
||||
'Manage Cache': 'Manage Cache',
|
||||
'Menu Model': 'Model rozbalovací nabídky',
|
||||
'Models': 'Modely',
|
||||
'models': 'modely',
|
||||
'Modified By': 'Změněno - kým',
|
||||
'Modified On': 'Změněno - kdy',
|
||||
'Modules': 'Moduly',
|
||||
'modules': 'moduly',
|
||||
'My Sites': 'Správa aplikací',
|
||||
'Name': 'Jméno',
|
||||
'new application "%s" created': 'nová aplikace "%s" vytvořena',
|
||||
'New Application Wizard': 'Nový průvodce aplikací',
|
||||
'New application wizard': 'Nový průvodce aplikací',
|
||||
'New password': 'Nové heslo',
|
||||
'New Record': 'Nový záznam',
|
||||
'new record inserted': 'nový záznam byl založen',
|
||||
'New simple application': 'Vytvořit primitivní aplikaci',
|
||||
'next': 'next',
|
||||
'next 100 rows': 'dalších 100 řádků',
|
||||
'No databases in this application': 'V této aplikaci nejsou žádné databáze',
|
||||
'No Interaction yet': 'Ještě žádná interakce nenastala',
|
||||
'No ticket_storage.txt found under /private folder': 'Soubor ticket_storage.txt v adresáři /private nenalezen',
|
||||
'Object or table name': 'Objekt či tabulka',
|
||||
'Old password': 'Původní heslo',
|
||||
'online designer': 'online návrhář',
|
||||
'Online examples': 'Příklady online',
|
||||
'Open new app in new window': 'Open new app in new window',
|
||||
'or alternatively': 'or alternatively',
|
||||
'Or Get from URL:': 'Or Get from URL:',
|
||||
'or import from csv file': 'nebo importovat z .csv souboru',
|
||||
'Origin': 'Původ',
|
||||
'Original/Translation': 'Originál/Překlad',
|
||||
'Other Plugins': 'Ostatní moduly',
|
||||
'Other Recipes': 'Ostatní zásuvné moduly',
|
||||
'Overview': 'Přehled',
|
||||
'Overwrite installed app': 'Přepsat instalovanou aplikaci',
|
||||
'Pack all': 'Zabalit',
|
||||
'Pack compiled': 'Zabalit zkompilované',
|
||||
'pack plugin': 'pack plugin',
|
||||
'password': 'heslo',
|
||||
'Password': 'Heslo',
|
||||
"Password fields don't match": 'Hesla se neshodují',
|
||||
'Peeking at file': 'Peeking at file',
|
||||
'Please': 'Prosím',
|
||||
'Plugin "%s" in application': 'Plugin "%s" in application',
|
||||
'plugins': 'zásuvné moduly',
|
||||
'Plugins': 'Zásuvné moduly',
|
||||
'Plural Form #%s': 'Plural Form #%s',
|
||||
'Plural-Forms:': 'Množná čísla:',
|
||||
'Powered by': 'Poháněno',
|
||||
'Preface': 'Předmluva',
|
||||
'previous 100 rows': 'předchozích 100 řádků',
|
||||
'Private files': 'Soukromé soubory',
|
||||
'private files': 'soukromé soubory',
|
||||
'profile': 'profil',
|
||||
'Project Progress': 'Vývoj projektu',
|
||||
'Python': 'Python',
|
||||
'Query:': 'Dotaz:',
|
||||
'Quick Examples': 'Krátké příklady',
|
||||
'RAM': 'RAM',
|
||||
'RAM Cache Keys': 'Klíče RAM Cache',
|
||||
'Ram Cleared': 'RAM smazána',
|
||||
'Readme': 'Nápověda',
|
||||
'Recipes': 'Postupy jak na to',
|
||||
'Record': 'Záznam',
|
||||
'record does not exist': 'záznam neexistuje',
|
||||
'Record ID': 'ID záznamu',
|
||||
'Record id': 'id záznamu',
|
||||
'refresh': 'obnovte',
|
||||
'register': 'registrovat',
|
||||
'Register': 'Zaregistrovat se',
|
||||
'Registration identifier': 'Registrační identifikátor',
|
||||
'Registration key': 'Registrační klíč',
|
||||
'reload': 'reload',
|
||||
'Reload routes': 'Znovu nahrát cesty',
|
||||
'Remember me (for 30 days)': 'Zapamatovat na 30 dní',
|
||||
'Remove compiled': 'Odstranit zkompilované',
|
||||
'Removed Breakpoint on %s at line %s': 'Bod přerušení smazán - soubor %s na řádce %s',
|
||||
'Replace': 'Zaměnit',
|
||||
'Replace All': 'Zaměnit vše',
|
||||
'request': 'request',
|
||||
'Reset Password key': 'Reset registračního klíče',
|
||||
'response': 'response',
|
||||
'restart': 'restart',
|
||||
'restore': 'obnovit',
|
||||
'Retrieve username': 'Získat přihlašovací jméno',
|
||||
'return': 'return',
|
||||
'revert': 'vrátit se k původnímu',
|
||||
'Role': 'Role',
|
||||
'Rows in Table': 'Záznamy v tabulce',
|
||||
'Rows selected': 'Záznamů zobrazeno',
|
||||
'rules are not defined': 'pravidla nejsou definována',
|
||||
"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Spustí testy v tomto souboru (ke spuštění všech testů, použijte tlačítko 'test')",
|
||||
'Running on %s': 'Běží na %s',
|
||||
'Save': 'Uložit',
|
||||
'Save file:': 'Save file:',
|
||||
'Save via Ajax': 'Uložit pomocí Ajaxu',
|
||||
'Saved file hash:': 'hash uloženého souboru:',
|
||||
'Semantic': 'Modul semantic',
|
||||
'Services': 'Služby',
|
||||
'session': 'session',
|
||||
'session expired': 'session expired',
|
||||
'Set Breakpoint on %s at line %s: %s': 'Bod přerušení nastaven v souboru %s na řádce %s: %s',
|
||||
'shell': 'příkazová řádka',
|
||||
'Singular Form': 'Singular Form',
|
||||
'Site': 'Správa aplikací',
|
||||
'Size of cache:': 'Velikost cache:',
|
||||
'skip to generate': 'skip to generate',
|
||||
'Sorry, could not find mercurial installed': 'Bohužel mercurial není nainstalován.',
|
||||
'Start a new app': 'Vytvořit novou aplikaci',
|
||||
'Start searching': 'Začít hledání',
|
||||
'Start wizard': 'Spustit průvodce',
|
||||
'state': 'stav',
|
||||
'Static': 'Static',
|
||||
'static': 'statické soubory',
|
||||
'Static files': 'Statické soubory',
|
||||
'Statistics': 'Statistika',
|
||||
'Step': 'Step',
|
||||
'step': 'step',
|
||||
'stop': 'stop',
|
||||
'Stylesheet': 'CSS styly',
|
||||
'submit': 'odeslat',
|
||||
'Submit': 'Odeslat',
|
||||
'successful': 'úspěšně',
|
||||
'Support': 'Podpora',
|
||||
'Sure you want to delete this object?': 'Opravdu chcete smazat tento objekt?',
|
||||
'Table': 'tabulka',
|
||||
'Table name': 'Název tabulky',
|
||||
'Temporary': 'Dočasný',
|
||||
'test': 'test',
|
||||
'Testing application': 'Testing application',
|
||||
'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"Dotaz" je podmínka, například "db.tabulka1.pole1==\'hodnota\'". Podmínka "db.tabulka1.pole1==db.tabulka2.pole2" pak vytvoří SQL JOIN.',
|
||||
'The application logic, each URL path is mapped in one exposed function in the controller': 'Logika aplikace: každá URL je mapována na funkci vystavovanou kontrolérem.',
|
||||
'The Core': 'Jádro (The Core)',
|
||||
'The data representation, define database tables and sets': 'Reprezentace dat: definovat tabulky databáze a záznamy',
|
||||
'The output of the file is a dictionary that was rendered by the view %s': 'Výstup ze souboru je slovník, který se zobrazil v pohledu %s.',
|
||||
'The presentations layer, views are also known as templates': 'Prezentační vrstva: pohledy či templaty (šablony)',
|
||||
'The Views': 'Pohledy (The Views)',
|
||||
'There are no controllers': 'There are no controllers',
|
||||
'There are no modules': 'There are no modules',
|
||||
'There are no plugins': 'Žádné moduly nejsou instalovány.',
|
||||
'There are no private files': 'Žádné soukromé soubory neexistují.',
|
||||
'There are no static files': 'There are no static files',
|
||||
'There are no translators, only default language is supported': 'There are no translators, only default language is supported',
|
||||
'There are no views': 'There are no views',
|
||||
'These files are not served, they are only available from within your app': 'Tyto soubory jsou klientům nepřístupné. K dispozici jsou pouze v rámci aplikace.',
|
||||
'These files are served without processing, your images go here': 'Tyto soubory jsou servírovány bez přídavné logiky, sem patří např. obrázky.',
|
||||
'This App': 'Tato aplikace',
|
||||
'This is a copy of the scaffolding application': 'Toto je kopie aplikace skelet.',
|
||||
'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk',
|
||||
'This is the %(filename)s template': 'This is the %(filename)s template',
|
||||
'this page to see if a breakpoint was hit and debug interaction is required.': 'tuto stránku, abyste uviděli, zda se dosáhlo bodu přerušení.',
|
||||
'Ticket': 'Ticket',
|
||||
'Ticket ID': 'Ticket ID',
|
||||
'Time in Cache (h:m:s)': 'Čas v Cache (h:m:s)',
|
||||
'Timestamp': 'Časové razítko',
|
||||
'to previous version.': 'k předchozí verzi.',
|
||||
'To create a plugin, name a file/folder plugin_[name]': 'Zásuvný modul vytvoříte tak, že pojmenujete soubor/adresář plugin_[jméno modulu]',
|
||||
'To emulate a breakpoint programatically, write:': 'K nastavení bodu přerušení v kódu programu, napište:',
|
||||
'to use the debugger!': ', abyste mohli ladící program používat!',
|
||||
'toggle breakpoint': 'vyp./zap. bod přerušení',
|
||||
'Toggle Fullscreen': 'Na celou obrazovku a zpět',
|
||||
'too short': 'Příliš krátké',
|
||||
'Traceback': 'Traceback',
|
||||
'Translation strings for the application': 'Překlad textů pro aplikaci',
|
||||
'try something like': 'try something like',
|
||||
'Try the mobile interface': 'Zkuste rozhraní pro mobilní zařízení',
|
||||
'try view': 'try view',
|
||||
'Twitter': 'Twitter',
|
||||
'Type python statement in here and hit Return (Enter) to execute it.': 'Type python statement in here and hit Return (Enter) to execute it.',
|
||||
'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.',
|
||||
'Unable to check for upgrades': 'Unable to check for upgrades',
|
||||
'unable to parse csv file': 'csv soubor nedá sa zpracovat',
|
||||
'uncheck all': 'vše odznačit',
|
||||
'Uninstall': 'Odinstalovat',
|
||||
'update': 'aktualizovat',
|
||||
'update all languages': 'aktualizovat všechny jazyky',
|
||||
'Update:': 'Upravit:',
|
||||
'Upgrade': 'Upgrade',
|
||||
'upgrade now': 'upgrade now',
|
||||
'upgrade now to %s': 'upgrade now to %s',
|
||||
'upload': 'nahrát',
|
||||
'Upload': 'Upload',
|
||||
'Upload a package:': 'Nahrát balík:',
|
||||
'Upload and install packed application': 'Nahrát a instalovat zabalenou aplikaci',
|
||||
'upload file:': 'nahrát soubor:',
|
||||
'upload plugin file:': 'nahrát soubor modulu:',
|
||||
'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Použijte (...)&(...) pro AND, (...)|(...) pro OR a ~(...) pro NOT pro sestavení složitějších dotazů.',
|
||||
'User %(id)s Logged-in': 'Uživatel %(id)s přihlášen',
|
||||
'User %(id)s Logged-out': 'Uživatel %(id)s odhlášen',
|
||||
'User %(id)s Password changed': 'Uživatel %(id)s změnil heslo',
|
||||
'User %(id)s Profile updated': 'Uživatel %(id)s upravil profil',
|
||||
'User %(id)s Registered': 'Uživatel %(id)s se zaregistroval',
|
||||
'User %(id)s Username retrieved': 'Uživatel %(id)s si nachal zaslat přihlašovací jméno',
|
||||
'User ID': 'ID uživatele',
|
||||
'Username': 'Přihlašovací jméno',
|
||||
'variables': 'variables',
|
||||
'Verify Password': 'Zopakujte heslo',
|
||||
'Version': 'Verze',
|
||||
'Version %s.%s.%s (%s) %s': 'Verze %s.%s.%s (%s) %s',
|
||||
'Versioning': 'Verzování',
|
||||
'Videos': 'Videa',
|
||||
'View': 'Pohled (View)',
|
||||
'Views': 'Pohledy',
|
||||
'views': 'pohledy',
|
||||
'Web Framework': 'Web Framework',
|
||||
'web2py is up to date': 'Máte aktuální verzi web2py.',
|
||||
'web2py online debugger': 'Ladící online web2py program',
|
||||
'web2py Recent Tweets': 'Štěbetání na Twitteru o web2py',
|
||||
'web2py upgrade': 'web2py upgrade',
|
||||
'web2py upgraded; please restart it': 'web2py upgraded; please restart it',
|
||||
'Welcome': 'Vítejte',
|
||||
'Welcome to web2py': 'Vitejte ve web2py',
|
||||
'Welcome to web2py!': 'Vítejte ve web2py!',
|
||||
'Which called the function %s located in the file %s': 'která zavolala funkci %s v souboru (kontroléru) %s.',
|
||||
'You are successfully running web2py': 'Úspěšně jste spustili web2py.',
|
||||
'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': 'Nastavovat a mazat body přerušení je též možno v rámci editování zdrojového souboru přes tlačítko Vyp./Zap. bod přerušení',
|
||||
'You can modify this application and adapt it to your needs': 'Tuto aplikaci si můžete upravit a přizpůsobit ji svým potřebám.',
|
||||
'You need to set up and reach a': 'Je třeba nejprve nastavit a dojít až na',
|
||||
'You visited the url %s': 'Navštívili jste stránku %s,',
|
||||
'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Aplikace bude blokována než se klikne na jedno z tlačítek (další, krok, pokračovat, atd.)',
|
||||
'You can inspect variables using the console bellow': 'Níže pomocí příkazové řádky si můžete prohlédnout proměnné',
|
||||
}
|
||||
# -*- coding: utf-8 -*-
|
||||
{
|
||||
'!langcode!': 'cs-cz',
|
||||
'!langname!': 'čeština',
|
||||
'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': 'Kolonka "Upravit" je nepovinný výraz, například "pole1=\'nováhodnota\'". Výsledky databázového JOINu nemůžete mazat ani upravovat.',
|
||||
'"User Exception" debug mode. An error ticket could be issued!': '"User Exception" debug mode. An error ticket could be issued!',
|
||||
'%%{Row} in Table': '%%{řádek} v tabulce',
|
||||
'%%{Row} selected': 'označených %%{řádek}',
|
||||
'%s %%{row} deleted': '%s smazaných %%{záznam}',
|
||||
'%s %%{row} updated': '%s upravených %%{záznam}',
|
||||
'%s selected': '%s označených',
|
||||
'%Y-%m-%d': '%d.%m.%Y',
|
||||
'%Y-%m-%d %H:%M:%S': '%d.%m.%Y %H:%M:%S',
|
||||
'(requires internet access)': '(vyžaduje připojení k internetu)',
|
||||
'(requires internet access, experimental)': '(vyžaduje internetové připojení, experimentální)',
|
||||
'(something like "it-it")': '(například "cs-cz")',
|
||||
'@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '@markmin\x01(soubor **gluon/contrib/plural_rules/%s.py** nenalezen)',
|
||||
'@markmin\x01An error occured, please [[reload %s]] the page': '@markmin\x01Došlo k chybě, prosím [[obnovte stránku %s]]',
|
||||
'@markmin\x01Searching: **%s** %%{file}': '@markmin\x01Hledání: **%s** %%{soubor}',
|
||||
'About': 'O programu',
|
||||
'About application': 'O aplikaci',
|
||||
'Access Control': 'Řízení přístupu',
|
||||
'Add breakpoint': 'Přidat bod přerušení',
|
||||
'Additional code for your application': 'Další kód pro Vaši aplikaci',
|
||||
'admin': 'admin',
|
||||
'Admin design page': 'Admin design page',
|
||||
'Admin language': 'jazyk rozhraní',
|
||||
'Administrative interface': 'pro administrátorské rozhraní klikněte sem',
|
||||
'Administrative Interface': 'Administrátorské rozhraní',
|
||||
'administrative interface': 'rozhraní pro správu',
|
||||
'Administrator Password:': 'Administrátorské heslo:',
|
||||
'Ajax Recipes': 'Recepty s ajaxem',
|
||||
'An error occured, please %s the page': 'Došlo k chybě, prosím %s stránku',
|
||||
'and rename it:': 'a přejmenovat na:',
|
||||
'appadmin': 'appadmin',
|
||||
'appadmin is disabled because insecure channel': 'appadmin je zakázaná bez zabezpečeného spojení',
|
||||
'Application': 'Aplikace',
|
||||
'application "%s" uninstalled': 'application "%s" odinstalována',
|
||||
'application compiled': 'aplikace zkompilována',
|
||||
'Application name:': 'Název aplikace:',
|
||||
'are not used': 'nepoužita',
|
||||
'are not used yet': 'ještě nepoužita',
|
||||
'Are you sure you want to delete this object?': 'Opravdu chcete odstranit tento objekt?',
|
||||
'Are you sure you want to uninstall application "%s"?': 'Opravdu chcete odinstalovat aplikaci "%s"?',
|
||||
'arguments': 'argumenty',
|
||||
'at char %s': 'na pozici znaku %s',
|
||||
'at line %s': 'na řádku %s',
|
||||
'ATTENTION:': 'POZOR:',
|
||||
'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.',
|
||||
'Available Databases and Tables': 'Dostupné databáze a tabulky',
|
||||
'back': 'zpět',
|
||||
'Back to wizard': 'Zpátky do průvodce',
|
||||
'Basics': 'Základy',
|
||||
'Begin': 'Začít',
|
||||
'breakpoint': 'bod přerušení',
|
||||
'Breakpoints': 'Body přerušení',
|
||||
'breakpoints': 'body přerušení',
|
||||
'Buy this book': 'Koupit Web2py knihu',
|
||||
"Buy web2py's book": 'Koupit Web2py knihu',
|
||||
'Cache': 'Cache',
|
||||
'cache': 'cache',
|
||||
'Cache Keys': 'Klíče cache',
|
||||
'cache, errors and sessions cleaned': 'cache, chyby a relace byly pročištěny',
|
||||
'can be a git repo': 'může to být git repo',
|
||||
'Cancel': 'Storno',
|
||||
'Cannot be empty': 'Nemůže být prázdné',
|
||||
'Change Admin Password': 'Změnit heslo pro správu',
|
||||
'Change admin password': 'Změnit heslo pro správu aplikací',
|
||||
'Change password': 'Změna hesla',
|
||||
'check all': 'vše označit',
|
||||
'Check for upgrades': 'Zkusit aktualizovat',
|
||||
'Check to delete': 'Označit ke smazání',
|
||||
'Check to delete:': 'Označit ke smazání:',
|
||||
'Checking for upgrades...': 'Zjišťuji, zda jsou k dispozici aktualizace...',
|
||||
'Clean': 'Pročistit',
|
||||
'Clear CACHE?': 'Vymazat CACHE?',
|
||||
'Clear DISK': 'Vymazat DISK',
|
||||
'Clear RAM': 'Vymazat RAM',
|
||||
'Click row to expand traceback': 'Pro rozbalení stopy, klikněte na řádek',
|
||||
'Click row to view a ticket': 'Pro zobrazení chyby (ticketu), klikněte na řádku...',
|
||||
'Client IP': 'IP adresa klienta',
|
||||
'code': 'kód',
|
||||
'Code listing': 'Výpis kódu',
|
||||
'collapse/expand all': 'vše sbalit/rozbalit',
|
||||
'Community': 'Komunita',
|
||||
'Compile': 'Zkompilovat',
|
||||
'compiled application removed': 'zkompilovaná aplikace smazána',
|
||||
'Components and Plugins': 'Komponenty a zásuvné moduly',
|
||||
'Condition': 'Podmínka',
|
||||
'Config.ini': 'Config.ini',
|
||||
'continue': 'pokračovat',
|
||||
'Controller': 'Kontrolér (Controller)',
|
||||
'Controllers': 'Kontroléry',
|
||||
'controllers': 'kontroléry',
|
||||
'Copyright': 'Copyright',
|
||||
'Count': 'Počet',
|
||||
'Create': 'Vytvořit',
|
||||
'create file with filename:': 'vytvořit soubor s názvem:',
|
||||
'created by': 'vytvořil',
|
||||
'Created By': 'Vytvořeno - kým',
|
||||
'Created On': 'Vytvořeno - kdy',
|
||||
'crontab': 'crontab',
|
||||
'Current request': 'Aktuální požadavek',
|
||||
'Current response': 'Aktuální odpověď',
|
||||
'Current session': 'Aktuální relace',
|
||||
'currently running': 'právě běží',
|
||||
'currently saved or': 'uloženo nebo',
|
||||
'customize me!': 'upravte mě!',
|
||||
'data uploaded': 'data nahrána',
|
||||
'Database': 'Rozhraní databáze',
|
||||
'Database %s select': 'databáze %s výběr',
|
||||
'Database administration': 'Administrace databáze',
|
||||
'database administration': 'správa databáze',
|
||||
'Date and Time': 'Datum a čas',
|
||||
'day': 'den',
|
||||
'db': 'db',
|
||||
'DB Model': 'Databázový model',
|
||||
'Debug': 'Ladění',
|
||||
'defines tables': 'definuje tabulky',
|
||||
'Delete': 'Smazat',
|
||||
'delete': 'smazat',
|
||||
'delete all checked': 'smazat vše označené',
|
||||
'delete plugin': 'zrušit plugin',
|
||||
'Delete this file (you will be asked to confirm deletion)': 'Smazat tento soubor (budete požádán o potvrzení mazání)',
|
||||
'Delete:': 'Smazat:',
|
||||
'deleted after first hit': 'smazat po prvním dosažení',
|
||||
'Demo': 'Demo',
|
||||
'Deploy': 'Nahrát',
|
||||
'Deploy on Google App Engine': 'Nahrát na Google App Engine',
|
||||
'Deploy to OpenShift': 'Nahrát na OpenShift',
|
||||
'Deployment Recipes': 'Postupy pro deployment',
|
||||
'Description': 'Popis',
|
||||
'design': 'návrh',
|
||||
'Design': 'Design',
|
||||
'Detailed traceback description': 'Podrobný výpis prostředí',
|
||||
'details': 'podrobnosti',
|
||||
'direction: ltr': 'směr: ltr',
|
||||
'Disable': 'Zablokovat',
|
||||
'DISK': 'DISK',
|
||||
'Disk Cache Keys': 'Klíče diskové cache',
|
||||
'Disk Cleared': 'Disk smazán',
|
||||
'docs': 'dokumentace',
|
||||
'Documentation': 'Dokumentace',
|
||||
"Don't know what to do?": 'Kde najdu další informace ?',
|
||||
'done!': 'hotovo!',
|
||||
'Download': 'Stáhnout',
|
||||
'download layouts': 'stáhnout moduly rozvržení stránky',
|
||||
'download plugins': 'stáhnout zásuvné moduly',
|
||||
'E-mail': 'E-mail',
|
||||
'Edit': 'Upravit',
|
||||
'edit all': 'editovat vše',
|
||||
'Edit application': 'Správa aplikace',
|
||||
'edit controller': 'editovat controller',
|
||||
'Edit current record': 'Upravit aktuální záznam',
|
||||
'Edit Profile': 'Upravit profil',
|
||||
'edit views:': 'upravit pohled:',
|
||||
'Editing file "%s"': 'Úprava souboru "%s"',
|
||||
'Editing Language file': 'Úprava jazykového souboru',
|
||||
'Editing Plural Forms File': 'Editování souboru množných čísel',
|
||||
'Email and SMS': 'Email a SMS',
|
||||
'Enable': 'Odblokovat',
|
||||
'enter a number between %(min)g and %(max)g': 'zadejte číslo mezi %(min)g a %(max)g',
|
||||
'Enter an integer between %(min)g and %(max)g': 'Enter an integer between %(min)g and %(max)g',
|
||||
'enter an integer between %(min)g and %(max)g': 'zadejte celé číslo mezi %(min)g a %(max)g',
|
||||
'Error': 'Chyba',
|
||||
'Error logs for "%(app)s"': 'Seznam výskytu chyb pro aplikaci "%(app)s"',
|
||||
'Error snapshot': 'Snapshot chyby',
|
||||
'Error ticket': 'Ticket chyby',
|
||||
'Errors': 'Chyby',
|
||||
'Exception %(extype)s: %(exvalue)s': 'Výjimka %(extype)s: %(exvalue)s',
|
||||
'Exception %s': 'Výjimka %s',
|
||||
'Exception instance attributes': 'Prvky instance výjimky',
|
||||
'Expand Abbreviation': 'Expandovat zkratku',
|
||||
'export as csv file': 'exportovat do .csv souboru',
|
||||
'exposes': 'vystavuje',
|
||||
'exposes:': 'vystavuje funkce:',
|
||||
'extends': 'rozšiřuje',
|
||||
'failed to compile file because:': 'soubor se nepodařilo zkompilovat, protože:',
|
||||
'FAQ': 'Často kladené dotazy',
|
||||
'File': 'Soubor',
|
||||
'file': 'soubor',
|
||||
'file "%(filename)s" created': 'soubor "%(filename)s" byl vytvořen',
|
||||
'file saved on %(time)s': 'soubor uložen %(time)s',
|
||||
'file saved on %s': 'soubor uložen %s',
|
||||
'Filename': 'Název souboru',
|
||||
'filter': 'filtr',
|
||||
'Find Next': 'Najít další',
|
||||
'Find Previous': 'Najít předchozí',
|
||||
'First name': 'Křestní jméno',
|
||||
'Forgot username?': 'Zapomněl jste svoje přihlašovací jméno?',
|
||||
'forgot username?': 'zapomněl jste svoje přihlašovací jméno?',
|
||||
'Forms and Validators': 'Formuláře a validátory',
|
||||
'Frames': 'Framy',
|
||||
'Free Applications': 'Aplikace zdarma',
|
||||
'Functions with no doctests will result in [passed] tests.': 'Functions with no doctests will result in [passed] tests.',
|
||||
'Generate': 'Vytvořit',
|
||||
'Get from URL:': 'Stáhnout z internetu:',
|
||||
'Git Pull': 'Git Pull',
|
||||
'Git Push': 'Git Push',
|
||||
'Globals##debug': 'Globální proměnné',
|
||||
'go!': 'OK!',
|
||||
'Goto': 'Přejít na',
|
||||
'graph model': 'grafický model',
|
||||
'Group %(group_id)s created': 'Skupina %(group_id)s vytvořena',
|
||||
'Group ID': 'ID skupiny',
|
||||
'Groups': 'Skupiny',
|
||||
'Hello World': 'Ahoj všichni',
|
||||
'Help': 'Nápověda',
|
||||
'Helping web2py': 'Podpořte Web2py',
|
||||
'Hide/Show Translated strings': 'Skrýt/Zobrazit přeložené texty',
|
||||
'Hits': 'Kolikrát dosaženo',
|
||||
'Home': 'Domovská stránka',
|
||||
'honored only if the expression evaluates to true': 'brát v potaz jen když se tato podmínka vyhodnotí kladně',
|
||||
'How did you get here?': 'Jak se Ti tato stránka vlastně zobrazila?',
|
||||
'If start the upgrade, be patient, it may take a while to download': 'If start the upgrade, be patient, it may take a while to download',
|
||||
'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\r\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.',
|
||||
'import': 'import',
|
||||
'Import/Export': 'Import/Export',
|
||||
'includes': 'zahrnuje',
|
||||
'Index': 'Index',
|
||||
'insert new': 'vložit nový záznam ',
|
||||
'insert new %s': 'vložit nový záznam %s',
|
||||
'inspect attributes': 'prohlédnout atributy',
|
||||
'Install': 'Instalovat',
|
||||
'Installed applications': 'Nainstalované aplikace',
|
||||
'Interaction at %s line %s': 'Interakce v %s, na řádce %s',
|
||||
'Interactive console': 'Interaktivní příkazová řádka',
|
||||
'Internal State': 'Vnitřní stav',
|
||||
'Introduction': 'Úvod',
|
||||
'Invalid email': 'Neplatný email',
|
||||
'Invalid password': 'Nesprávné heslo',
|
||||
'invalid password.': 'neplatné heslo',
|
||||
'Invalid Query': 'Neplatný dotaz',
|
||||
'invalid request': 'Neplatný požadavek',
|
||||
'Is Active': 'Je aktivní',
|
||||
'It is %s %%{day} today.': 'Dnes je to %s %%{den}.',
|
||||
'Key': 'Klíč',
|
||||
'Key bindings': 'Vazby klíčů',
|
||||
'Key bindings for ZenCoding Plugin': 'Key bindings pro ZenCoding Plugin',
|
||||
'languages': 'jazyky',
|
||||
'Languages': 'Jazyky',
|
||||
'Last name': 'Příjmení',
|
||||
'Last saved on:': 'Naposledy uloženo:',
|
||||
'Layout': 'Rozvržení stránky (layout)',
|
||||
'Layout Plugins': 'Moduly rozvržení stránky (Layout Plugins)',
|
||||
'Layouts': 'Rozvržení stránek',
|
||||
'License for': 'Licence pro',
|
||||
'Line number': 'Číslo řádku',
|
||||
'LineNo': 'Č.řádku',
|
||||
'Live Chat': 'Online chat',
|
||||
'loading...': 'nahrávám...',
|
||||
'locals': 'locals',
|
||||
'Locals##debug': 'Lokální proměnné',
|
||||
'Log In': 'Přihlásit se',
|
||||
'Logged in': 'Přihlášení proběhlo úspěšně',
|
||||
'Logged out': 'Odhlášení proběhlo úspěšně',
|
||||
'Login': 'Přihlásit se',
|
||||
'login': 'přihlásit se',
|
||||
'Login to the Administrative Interface': 'Přihlásit se do Správce aplikací',
|
||||
'logout': 'odhlásit se',
|
||||
'Logout': 'Odhlásit se',
|
||||
'Lost Password': 'Zapomněl jste heslo',
|
||||
'Lost password?': 'Zapomněl jste heslo?',
|
||||
'lost password?': 'zapomněl jste heslo?',
|
||||
'Manage': 'Spravovat',
|
||||
'Manage Cache': 'Spravovat cache',
|
||||
'Menu Model': 'Model rozbalovací nabídky',
|
||||
'Models': 'Modely',
|
||||
'models': 'modely',
|
||||
'Modified By': 'Změněno - kým',
|
||||
'Modified On': 'Změněno - kdy',
|
||||
'Modules': 'Moduly',
|
||||
'modules': 'moduly',
|
||||
'My Sites': 'Správa aplikací',
|
||||
'Name': 'Jméno',
|
||||
'new application "%s" created': 'nová aplikace "%s" vytvořena',
|
||||
'New application wizard': 'Nový průvodce aplikací',
|
||||
'New Application Wizard': 'Nový průvodce aplikací',
|
||||
'New password': 'Nové heslo',
|
||||
'New Record': 'Nový záznam',
|
||||
'new record inserted': 'nový záznam byl založen',
|
||||
'New simple application': 'Vytvořit novou aplikaci',
|
||||
'next': 'další',
|
||||
'next 100 rows': 'dalších 100 řádků',
|
||||
'No databases in this application': 'V této aplikaci nejsou žádné databáze',
|
||||
'No Interaction yet': 'Ještě žádná interakce nenastala',
|
||||
'No ticket_storage.txt found under /private folder': 'Soubor ticket_storage.txt v adresáři /private nenalezen',
|
||||
'Object or table name': 'Objekt či tabulka',
|
||||
'Old password': 'Původní heslo',
|
||||
'Online book': 'Online kniha',
|
||||
'online designer': 'online návrhář',
|
||||
'Online examples': 'Ukázka aplikace: web2py stránky',
|
||||
'Open new app in new window': 'Otevřít novou aplikaci v novém okně',
|
||||
'or alternatively': 'nebo případně',
|
||||
'Or Get from URL:': 'Nebo získat z URL adresy:',
|
||||
'or import from csv file': 'nebo importovat z .csv souboru',
|
||||
'Origin': 'Původ',
|
||||
'Original/Translation': 'Originál/Překlad',
|
||||
'Other Plugins': 'Ostatní moduly',
|
||||
'Other Recipes': 'Ostatní zásuvné moduly',
|
||||
'Overview': 'Přehled',
|
||||
'Overwrite installed app': 'Přepsat instalovanou aplikaci',
|
||||
'Pack all': 'Zabalit',
|
||||
'Pack compiled': 'Zabalit zkompilované',
|
||||
'pack plugin': 'pack (zabalit) plugin',
|
||||
'password': 'heslo',
|
||||
'Password': 'Heslo',
|
||||
"Password fields don't match": 'Hesla se neshodují',
|
||||
'Peeking at file': 'Sledování souboru',
|
||||
'Please': 'Prosím',
|
||||
'Plugin "%s" in application': 'Plugin "%s" v aplikaci',
|
||||
'plugins': 'zásuvné moduly',
|
||||
'Plugins': 'Zásuvné moduly',
|
||||
'Plural Form #%s': 'Množné číslo #%s',
|
||||
'Plural-Forms:': 'Množná čísla:',
|
||||
'Powered by': 'Používá technologii',
|
||||
'Preface': 'Předmluva',
|
||||
'previous 100 rows': 'předchozích 100 řádků',
|
||||
'Private files': 'Soukromé soubory',
|
||||
'private files': 'soukromé soubory',
|
||||
'profile': 'profil',
|
||||
'Project Progress': 'Vývoj projektu',
|
||||
'Python': 'Python',
|
||||
'Query:': 'Dotaz:',
|
||||
'Quick Examples': 'Krátké příklady',
|
||||
'RAM': 'RAM',
|
||||
'RAM Cache Keys': 'Klíče RAM Cache',
|
||||
'Ram Cleared': 'RAM smazána',
|
||||
'Readme': 'Nápověda',
|
||||
'Recipes': 'Postupy jak na to',
|
||||
'Record': 'Záznam',
|
||||
'record does not exist': 'záznam neexistuje',
|
||||
'Record ID': 'ID záznamu',
|
||||
'Record id': 'id záznamu',
|
||||
'refresh': 'obnovte',
|
||||
'register': 'registrovat',
|
||||
'Register': 'Zaregistrovat se',
|
||||
'Registration identifier': 'Registrační identifikátor',
|
||||
'Registration key': 'Registrační klíč',
|
||||
'reload': 'reload',
|
||||
'Reload routes': 'Znovu nahrát cesty',
|
||||
'Remember me (for 30 days)': 'Zapamatovat na 30 dní',
|
||||
'Remove compiled': 'Odstranit zkompilované',
|
||||
'Removed Breakpoint on %s at line %s': 'Bod přerušení smazán - soubor %s na řádce %s',
|
||||
'Replace': 'Zaměnit',
|
||||
'Replace All': 'Zaměnit vše',
|
||||
'request': 'request',
|
||||
'Reset Password key': 'Reset registračního klíče',
|
||||
'response': 'response',
|
||||
'restart': 'restart',
|
||||
'restore': 'obnovit',
|
||||
'Retrieve username': 'Získat přihlašovací jméno',
|
||||
'return': 'return',
|
||||
'revert': 'vrátit se k původnímu',
|
||||
'Role': 'Role',
|
||||
'Rows in Table': 'Záznamy v tabulce',
|
||||
'Rows selected': 'Záznamů zobrazeno',
|
||||
'rules are not defined': 'pravidla nejsou definována',
|
||||
"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Spustí testy v tomto souboru (ke spuštění všech testů, použijte tlačítko 'test')",
|
||||
'Running on %s': 'Běží na %s',
|
||||
'Save': 'Uložit',
|
||||
'Save file:': 'Uložit soubor:',
|
||||
'Save via Ajax': 'Uložit pomocí Ajaxu',
|
||||
'Saved file hash:': 'hash uloženého souboru:',
|
||||
'Semantic': 'Modul semantic',
|
||||
'Services': 'Služby',
|
||||
'session': 'session',
|
||||
'session expired': 'vypršela session',
|
||||
'Set Breakpoint on %s at line %s: %s': 'Bod přerušení nastaven v souboru %s na řádce %s: %s',
|
||||
'shell': 'příkazová řádka',
|
||||
'Sign Up': 'Registrovat se',
|
||||
'Singular Form': 'Jednotné číslo',
|
||||
'Site': 'Správa aplikací',
|
||||
'Size of cache:': 'Velikost cache:',
|
||||
'skip to generate': 'přeskočit pro vytvoření',
|
||||
'Sorry, could not find mercurial installed': 'Bohužel mercurial není nainstalován.',
|
||||
'Start a new app': 'Vytvořit novou aplikaci',
|
||||
'Start searching': 'Začít hledání',
|
||||
'Start wizard': 'Spustit průvodce',
|
||||
'state': 'stav',
|
||||
'Static': 'Statické soubory',
|
||||
'static': 'statické soubory',
|
||||
'Static files': 'Statické soubory',
|
||||
'Statistics': 'Statistika',
|
||||
'Step': 'Krok',
|
||||
'step': 'krok',
|
||||
'stop': 'zastavit',
|
||||
'Stylesheet': 'CSS styly',
|
||||
'submit': 'odeslat',
|
||||
'Submit': 'Odeslat',
|
||||
'successful': 'úspěšně',
|
||||
'Support': 'Podpora',
|
||||
'Sure you want to delete this object?': 'Opravdu chcete smazat tento objekt?',
|
||||
'Table': 'tabulka',
|
||||
'Table name': 'Název tabulky',
|
||||
'Temporary': 'Dočasný',
|
||||
'test': 'test',
|
||||
'Testing application': 'Zkušební aplikace',
|
||||
'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"Dotaz" je podmínka, například "db.tabulka1.pole1==\'hodnota\'". Podmínka "db.tabulka1.pole1==db.tabulka2.pole2" pak vytvoří SQL JOIN.',
|
||||
'The application logic, each URL path is mapped in one exposed function in the controller': 'Logika aplikace: každá URL je mapována na funkci vystavovanou kontrolérem.',
|
||||
'The Core': 'Jádro (The Core)',
|
||||
'The data representation, define database tables and sets': 'Reprezentace dat: definovat tabulky databáze a záznamy',
|
||||
'The output of the file is a dictionary that was rendered by the view %s': 'Funkce vrátila dictionary (slovník) hodnot, a ty se vypsaly pomocí šablony %s.',
|
||||
'The presentations layer, views are also known as templates': 'Prezentační vrstva: pohledy či templaty (šablony)',
|
||||
'The Views': 'Pohledy (The Views)',
|
||||
'There are no controllers': 'Nejsou vytvořeny žádné controllery',
|
||||
'There are no modules': 'Nejsou přidány žádné moduly',
|
||||
'There are no plugins': 'Žádné pluginy nejsou instalovány.',
|
||||
'There are no private files': 'Žádné soukromé soubory neexistují.',
|
||||
'There are no static files': 'Nejsou přidány žádné statické soubory',
|
||||
'There are no translators, only default language is supported': 'There are no translators, only default language is supported',
|
||||
'There are no views': 'Nejsou vytvořeny žádné šablony (views)',
|
||||
'These files are not served, they are only available from within your app': 'Tyto soubory jsou klientům nepřístupné. K dispozici jsou pouze v rámci aplikace.',
|
||||
'These files are served without processing, your images go here': 'Tyto soubory jsou servírovány bez přídavné logiky, sem patří např. obrázky.',
|
||||
'This App': 'Tato aplikace',
|
||||
'This is a copy of the scaffolding application': 'Toto je kopie aplikace skelet.',
|
||||
'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk',
|
||||
'This is the %(filename)s template': 'Toto je šablona %(filename)s',
|
||||
'this page to see if a breakpoint was hit and debug interaction is required.': 'tuto stránku, abyste uviděli, zda se dosáhlo bodu přerušení.',
|
||||
'Ticket': 'Tiket',
|
||||
'Ticket ID': 'ID tiketu',
|
||||
'Time in Cache (h:m:s)': 'Čas v Cache (h:m:s)',
|
||||
'Timestamp': 'Časové razítko',
|
||||
'to previous version.': 'k předchozí verzi.',
|
||||
'To create a plugin, name a file/folder plugin_[name]': 'Zásuvný modul vytvoříte tak, že pojmenujete soubor/adresář plugin_[jméno modulu]',
|
||||
'To emulate a breakpoint programatically, write:': 'K nastavení bodu přerušení v kódu programu, napište:',
|
||||
'to use the debugger!': ', abyste mohli ladící program používat!',
|
||||
'toggle breakpoint': 'vyp./zap. bod přerušení',
|
||||
'Toggle Fullscreen': 'Na celou obrazovku a zpět',
|
||||
'too short': 'Příliš krátké',
|
||||
'Traceback': 'Hierarchie volání',
|
||||
'Translation strings for the application': 'Překlad textů pro aplikaci',
|
||||
'try something like': 'zkuste něco jako',
|
||||
'Try the mobile interface': 'Zkuste rozhraní pro mobilní zařízení',
|
||||
'try view': 'vyzkoušet šablonu (view)',
|
||||
'Twitter': 'Twitter',
|
||||
'Type python statement in here and hit Return (Enter) to execute it.': 'Type python statement in here and hit Return (Enter) to execute it.',
|
||||
'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.',
|
||||
'Unable to check for upgrades': 'Nelze zjistit informaci o aktualizacích',
|
||||
'unable to parse csv file': 'csv soubor nedá sa zpracovat',
|
||||
'uncheck all': 'vše odznačit',
|
||||
'Uninstall': 'Odinstalovat',
|
||||
'update': 'aktualizovat',
|
||||
'update all languages': 'aktualizovat všechny jazyky',
|
||||
'Update:': 'Upravit:',
|
||||
'Upgrade': 'Upgrade',
|
||||
'upgrade now': 'upgradovat nyní',
|
||||
'upgrade now to %s': 'upgradovat nyní na %s',
|
||||
'upload': 'nahrát',
|
||||
'Upload': 'Upload (nahrát)',
|
||||
'Upload a package:': 'Nahrát balík:',
|
||||
'Upload and install packed application': 'Nahrát a instalovat zabalenou aplikaci',
|
||||
'upload file:': 'nahrát soubor:',
|
||||
'upload plugin file:': 'nahrát soubor modulu:',
|
||||
'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Použijte (...)&(...) pro AND, (...)|(...) pro OR a ~(...) pro NOT pro sestavení složitějších dotazů.',
|
||||
'User %(id)s Logged-in': 'Uživatel %(id)s přihlášen',
|
||||
'User %(id)s Logged-out': 'Uživatel %(id)s odhlášen',
|
||||
'User %(id)s Password changed': 'Uživatel %(id)s změnil heslo',
|
||||
'User %(id)s Profile updated': 'Uživatel %(id)s upravil profil',
|
||||
'User %(id)s Registered': 'Uživatel %(id)s se zaregistroval',
|
||||
'User %(id)s Username retrieved': 'Uživatel %(id)s si nachal zaslat přihlašovací jméno',
|
||||
'User ID': 'ID uživatele',
|
||||
'Username': 'Přihlašovací jméno',
|
||||
'variables': 'proměnné',
|
||||
'Verify Password': 'Zopakujte heslo',
|
||||
'Version': 'Verze',
|
||||
'Version %s.%s.%s (%s) %s': 'Verze %s.%s.%s (%s) %s',
|
||||
'Versioning': 'Verzování',
|
||||
'Videos': 'Videa',
|
||||
'View': 'Pohled (View)',
|
||||
'Views': 'Pohledy',
|
||||
'views': 'pohledy',
|
||||
'Web Framework': 'Webový framework',
|
||||
'web2py is up to date': 'Máte aktuální verzi web2py.',
|
||||
'web2py online debugger': 'Ladící online web2py program',
|
||||
'web2py Recent Tweets': 'Štěbetání na Twitteru o web2py',
|
||||
'web2py upgrade': 'aktualizace Web2py',
|
||||
'web2py upgraded; please restart it': 'Web2py bylo aktualizováno; prosím restarujte jej',
|
||||
'Welcome': 'Vítejte',
|
||||
'Welcome to web2py': 'Vitejte ve Web2py aplikaci',
|
||||
'Welcome to web2py!': 'Vítejte ve Web2py aplikaci.',
|
||||
'Which called the function %s located in the file %s': 'Tím byla zavolána funkce %s ze souboru (kontroléru) %s.',
|
||||
'Working...': 'Pracuji...',
|
||||
'You are successfully running web2py': 'Spustil(a) jsi webový server a Web2py.',
|
||||
'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': 'Nastavovat a mazat body přerušení je též možno v rámci editování zdrojového souboru přes tlačítko Vyp./Zap. bod přerušení',
|
||||
'You can inspect variables using the console bellow': 'Níže pomocí příkazové řádky si můžete prohlédnout proměnné',
|
||||
'You can modify this application and adapt it to your needs': 'V ADMIN rozhraní můžeš Vytvořit novou aplikaci jako kopii ukázkové Welcome aplikace. A začít upravovat: modely, kontroléry, šablony pro URL adresy, které požaduješ.',
|
||||
'You need to set up and reach a': 'Je třeba nejprve nastavit a dojít až na',
|
||||
'You visited the url %s': 'Zadal jsi URL adresu %s.',
|
||||
'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Aplikace bude blokována než se klikne na jedno z tlačítek (další, krok, pokračovat, atd.)',
|
||||
}
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
## File is released under public domain and you can use without limitations
|
||||
#########################################################################
|
||||
|
||||
if request.global_settings.web2py_version < "2.14.1":
|
||||
raise HTTP(500, "Requires web2py 2.13.3 or newer")
|
||||
|
||||
## if SSL/HTTPS is properly configured and you want all HTTP requests to
|
||||
## be redirected to HTTPS, uncomment the line below:
|
||||
# request.requires_https()
|
||||
@@ -55,7 +58,8 @@ response.form_label_separator = myconf.get('forms.separator') or ''
|
||||
|
||||
from gluon.tools import Auth, Service, PluginManager
|
||||
|
||||
auth = Auth(db, host=myconf.get('host.name'))
|
||||
# host names must be a list of allowed host names (glob syntax allowed)
|
||||
auth = Auth(db, host_names=myconf.get('host.names'))
|
||||
service = Service()
|
||||
plugins = PluginManager()
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ generator = Web2py Web Framework
|
||||
|
||||
; Host configuration
|
||||
[host]
|
||||
name = localhost
|
||||
names = localhost:*, 127.0.0.1:*, *:*, *
|
||||
|
||||
; db configuration
|
||||
[db]
|
||||
|
||||
+5
-5
File diff suppressed because one or more lines are too long
@@ -69,8 +69,8 @@ class AppConfigDict(dict):
|
||||
return False
|
||||
elif value.isdigit() or (value[0]=='-' and value[1:].isdigit()):
|
||||
return int(value)
|
||||
elif ', ' in value:
|
||||
return value.split(', ')
|
||||
elif ',' in value:
|
||||
return map(lambda x:x.strip(),value.split(','))
|
||||
else:
|
||||
try:
|
||||
return float(value)
|
||||
|
||||
+743
-749
File diff suppressed because it is too large
Load Diff
@@ -36,11 +36,13 @@ def ldap_auth(server='ldap',
|
||||
user_lastname_attrib='cn:2',
|
||||
user_mail_attrib='mail',
|
||||
manage_groups=False,
|
||||
manage_groups_callback=[],
|
||||
db=None,
|
||||
group_dn=None,
|
||||
group_name_attrib='cn',
|
||||
group_member_attrib='memberUid',
|
||||
group_filterstr='objectClass=*',
|
||||
group_mapping={},
|
||||
tls=False,
|
||||
logging_level='error'):
|
||||
|
||||
@@ -207,6 +209,7 @@ def ldap_auth(server='ldap',
|
||||
user_mail_attrib=user_mail_attrib,
|
||||
manage_groups=manage_groups,
|
||||
allowed_groups=allowed_groups,
|
||||
group_mapping=group_mapping,
|
||||
db=db):
|
||||
if password == '': # http://tools.ietf.org/html/rfc4513#section-5.1.2
|
||||
logger.warning('blank password not allowed')
|
||||
@@ -262,6 +265,7 @@ def ldap_auth(server='ldap',
|
||||
requested_attrs = ['sAMAccountName']
|
||||
if manage_user:
|
||||
requested_attrs.extend([user_firstname_attrib, user_lastname_attrib, user_mail_attrib])
|
||||
|
||||
result = con.search_ext_s(
|
||||
ldap_basedn, ldap.SCOPE_SUBTREE,
|
||||
"(&(sAMAccountName=%s)(%s))" % (ldap.filter.escape_filter_chars(username_bare), filterstr),
|
||||
@@ -444,7 +448,7 @@ def ldap_auth(server='ldap',
|
||||
con.unbind()
|
||||
|
||||
if manage_groups:
|
||||
if not do_manage_groups(username, password):
|
||||
if not do_manage_groups(username, password, group_mapping):
|
||||
return False
|
||||
return True
|
||||
except ldap.INVALID_CREDENTIALS, e:
|
||||
@@ -482,7 +486,7 @@ def ldap_auth(server='ldap',
|
||||
# No match
|
||||
return False
|
||||
|
||||
def do_manage_groups(username, password=None, db=db):
|
||||
def do_manage_groups(username, password=None, group_mapping={}, db=db):
|
||||
"""
|
||||
Manage user groups
|
||||
|
||||
@@ -498,6 +502,14 @@ def ldap_auth(server='ldap',
|
||||
ldap_groups_of_the_user = get_user_groups_from_ldap(
|
||||
username, password)
|
||||
|
||||
if group_mapping != {}:
|
||||
l = []
|
||||
for group in ldap_groups_of_the_user:
|
||||
if group in group_mapping:
|
||||
l += group_mapping[group]
|
||||
ldap_groups_of_the_user = l
|
||||
logging.info("User groups after remapping: %s" % str(l))
|
||||
|
||||
#
|
||||
# Get all group name where the user is in actually in local db
|
||||
# #############################################################
|
||||
@@ -540,6 +552,7 @@ def ldap_auth(server='ldap',
|
||||
db_groups_of_the_user.append(group.role)
|
||||
logging.debug('db groups of user %s: %s' % (username, str(db_groups_of_the_user)))
|
||||
|
||||
auth_membership_changed = False
|
||||
#
|
||||
# Delete user membership from groups where user is not anymore
|
||||
# #############################################################
|
||||
@@ -547,6 +560,7 @@ def ldap_auth(server='ldap',
|
||||
if ldap_groups_of_the_user.count(group_to_del) == 0:
|
||||
db((db.auth_membership.user_id == db_user_id) &
|
||||
(db.auth_membership.group_id == db_group_id[group_to_del])).delete()
|
||||
auth_membership_changed = True
|
||||
|
||||
#
|
||||
# Create user membership in groups where user is not in already
|
||||
@@ -558,6 +572,12 @@ def ldap_auth(server='ldap',
|
||||
else:
|
||||
gid = db(db.auth_group.role == group_to_add).select(db.auth_group.id).first().id
|
||||
db.auth_membership.insert(user_id=db_user_id, group_id=gid)
|
||||
auth_membership_changed = True
|
||||
|
||||
if auth_membership_changed:
|
||||
for callback in manage_groups_callback:
|
||||
callback()
|
||||
|
||||
except:
|
||||
logger.warning("[%s] Groups are not managed successfully!" % str(username))
|
||||
import traceback
|
||||
|
||||
@@ -22,7 +22,7 @@ logger = logging.getLogger("web2py.cache.redis")
|
||||
locker = thread.allocate_lock()
|
||||
|
||||
|
||||
def RedisCache(*args, **vars):
|
||||
def RedisCache(redis_conn=None, debug=False, with_lock=False, fail_gracefully=False, db=None):
|
||||
"""
|
||||
Usage example: put in models::
|
||||
|
||||
@@ -85,7 +85,9 @@ def RedisCache(*args, **vars):
|
||||
try:
|
||||
instance_name = 'redis_instance_' + current.request.application
|
||||
if not hasattr(RedisCache, instance_name):
|
||||
setattr(RedisCache, instance_name, RedisClient(*args, **vars))
|
||||
setattr(RedisCache, instance_name,
|
||||
RedisClient(redis_conn=redis_conn, debug=debug,
|
||||
with_lock=with_lock, fail_gracefully=fail_gracefully))
|
||||
return getattr(RedisCache, instance_name)
|
||||
finally:
|
||||
locker.release()
|
||||
|
||||
@@ -358,20 +358,20 @@ class RScheduler(Scheduler):
|
||||
(sd.can_visit == False) &
|
||||
(~sd.task_child.belongs(
|
||||
db(sd.can_visit == False)._select(sd.task_parent)
|
||||
)
|
||||
)
|
||||
)._select(sd.task_child)
|
||||
)
|
||||
)._select(sd.task_child)
|
||||
no_deps = db(
|
||||
(st.status.belongs((QUEUED, ASSIGNED))) &
|
||||
(
|
||||
(sd.id == None) | (st.id.belongs(deps_with_no_deps))
|
||||
|
||||
)
|
||||
)._select(st.id, distinct=True, left=sd.on(
|
||||
(st.id == sd.task_parent) &
|
||||
(sd.can_visit == False)
|
||||
)
|
||||
)
|
||||
)._select(st.id, distinct=True, left=sd.on(
|
||||
(st.id == sd.task_parent) &
|
||||
(sd.can_visit == False)
|
||||
)
|
||||
)
|
||||
|
||||
all_available = db(
|
||||
(st.status.belongs((QUEUED, ASSIGNED))) &
|
||||
@@ -449,8 +449,9 @@ class RScheduler(Scheduler):
|
||||
self.w_stats.status = POLLING
|
||||
# polling for 1 minute in total. If more groups are in,
|
||||
# polling is 1 minute in total
|
||||
logger.debug(' polling on %s' , group)
|
||||
task_id = r_server.brpoplpush(queued_list, running_list, timeout=60/len(self.group_names))
|
||||
logger.debug(' polling on %s', group)
|
||||
task_id = r_server.brpoplpush(queued_list, running_list,
|
||||
timeout=60 / len(self.group_names))
|
||||
logger.debug(' finished polling')
|
||||
self.w_stats.status = ACTIVE
|
||||
if task_id:
|
||||
@@ -464,7 +465,8 @@ class RScheduler(Scheduler):
|
||||
r_server.lrem(running_list, 0, task_id)
|
||||
r_server.hdel(running_dict, task_id)
|
||||
r_server.lrem(queued_list, 0, task_id)
|
||||
logger.error("we received a task that isn't there (%s)" % task_id)
|
||||
logger.error("we received a task that isn't there (%s)",
|
||||
task_id)
|
||||
return None
|
||||
break
|
||||
now = self.now()
|
||||
@@ -474,7 +476,7 @@ class RScheduler(Scheduler):
|
||||
db.commit()
|
||||
logger.debug(' work to do %s', task.id)
|
||||
else:
|
||||
logger.info('nothing to do (%s)' % self.w_stats.status)
|
||||
logger.info('nothing to do')
|
||||
return None
|
||||
times_run = task.times_run + 1
|
||||
if not task.prevent_drift:
|
||||
@@ -482,9 +484,13 @@ class RScheduler(Scheduler):
|
||||
seconds=task.period
|
||||
)
|
||||
else:
|
||||
next_run_time = task.start_time + datetime.timedelta(
|
||||
seconds=task.period * times_run
|
||||
)
|
||||
# calc next_run_time based on available slots
|
||||
# see #1191
|
||||
next_run_time = task.start_time
|
||||
secondspassed = self.total_seconds(now - next_run_time)
|
||||
steps = secondspassed // task.period + 1
|
||||
next_run_time += datetime.timedelta(seconds=task.period * steps)
|
||||
|
||||
if times_run < task.repeats or task.repeats == 0:
|
||||
# need to run (repeating task)
|
||||
run_again = True
|
||||
@@ -578,7 +584,7 @@ class RScheduler(Scheduler):
|
||||
and QUEUED or task.retry_failed == -1
|
||||
and QUEUED or st_mapping)
|
||||
db(st.id == task.task_id).update(
|
||||
times_failed=db.scheduler_task.times_failed + 1,
|
||||
times_failed=st.times_failed + 1,
|
||||
next_run_time=task.next_run_time,
|
||||
status=status,
|
||||
assigned_worker_name=self.worker_name
|
||||
|
||||
@@ -19,13 +19,13 @@ logger = logging.getLogger("web2py.session.redis")
|
||||
locker = thread.allocate_lock()
|
||||
|
||||
|
||||
def RedisSession(*args, **vars):
|
||||
def RedisSession(redis_conn, session_expiry=False, with_lock=False, db=None):
|
||||
"""
|
||||
Usage example: put in models::
|
||||
|
||||
from gluon.contrib.redis_utils import RConn
|
||||
rconn = RConn()
|
||||
from gluon.contrib.redis_session
|
||||
from gluon.contrib.redis_session import RedisSession
|
||||
sessiondb = RedisSession(redis_conn=rconn, with_lock=True, session_expiry=False)
|
||||
session.connect(request, response, db = sessiondb)
|
||||
|
||||
@@ -43,7 +43,8 @@ def RedisSession(*args, **vars):
|
||||
try:
|
||||
instance_name = 'redis_instance_' + current.request.application
|
||||
if not hasattr(RedisSession, instance_name):
|
||||
setattr(RedisSession, instance_name, RedisClient(*args, **vars))
|
||||
setattr(RedisSession, instance_name,
|
||||
RedisClient(redis_conn, session_expiry=session_expiry, with_lock=with_lock))
|
||||
return getattr(RedisSession, instance_name)
|
||||
finally:
|
||||
locker.release()
|
||||
|
||||
+6
-5
@@ -72,12 +72,13 @@ def _default_validators(db, field):
|
||||
if not field.notnull:
|
||||
requires = validators.IS_EMPTY_OR(requires)
|
||||
return requires
|
||||
# does not get here for reference and list:reference
|
||||
if field.unique:
|
||||
requires.append(validators.IS_NOT_IN_DB(db, field))
|
||||
sff = ['in', 'do', 'da', 'ti', 'de', 'bo']
|
||||
if field.notnull and not field_type[:2] in sff:
|
||||
requires.append(validators.IS_NOT_EMPTY())
|
||||
elif not field.notnull and field_type[:2] in sff and requires:
|
||||
requires.insert(0,validators.IS_NOT_IN_DB(db, field))
|
||||
excluded_fields = ['string','upload','text','password','boolean']
|
||||
if (field.notnull or field.unique) and not field_type in excluded_fields:
|
||||
requires.insert(0,validators.IS_NOT_EMPTY())
|
||||
elif not field.notnull and not field.unique and requires:
|
||||
requires[0] = validators.IS_EMPTY_OR(requires[0])
|
||||
return requires
|
||||
|
||||
|
||||
+4
-9
@@ -377,12 +377,7 @@ class Request(Storage):
|
||||
and callable(rest_action)):
|
||||
raise HTTP(405, "method not allowed")
|
||||
try:
|
||||
vars = request.vars
|
||||
if method == 'POST' and is_json:
|
||||
body = request.body.read()
|
||||
if len(body):
|
||||
vars = sj.loads(body)
|
||||
res = rest_action(*request.args, **vars)
|
||||
res = rest_action(*request.args, **request.vars)
|
||||
if is_json and not isinstance(res, str):
|
||||
res = json(res)
|
||||
return res
|
||||
@@ -817,7 +812,7 @@ class Session(Storage):
|
||||
response.session_data_name = 'session_data_%s' % masterapp.lower()
|
||||
response.session_cookie_expires = cookie_expires
|
||||
response.session_client = str(request.client).replace(':', '.')
|
||||
response.session_cookie_key = cookie_key
|
||||
current._session_cookie_key = cookie_key
|
||||
response.session_cookie_compression_level = compression_level
|
||||
|
||||
# check if there is a session_id in cookies
|
||||
@@ -1070,7 +1065,7 @@ class Session(Storage):
|
||||
|
||||
# if not cookie_key, but session_data_name in cookies
|
||||
# expire session_data_name from cookies
|
||||
if not response.session_cookie_key:
|
||||
if not current._session_cookie_key:
|
||||
if response.session_data_name in cookies:
|
||||
rcookies[response.session_data_name] = 'expired'
|
||||
rcookies[response.session_data_name]['path'] = '/'
|
||||
@@ -1133,7 +1128,7 @@ class Session(Storage):
|
||||
name = response.session_data_name
|
||||
compression_level = response.session_cookie_compression_level
|
||||
value = secure_dumps(dict(self),
|
||||
response.session_cookie_key,
|
||||
current._session_cookie_key,
|
||||
compression_level=compression_level)
|
||||
rcookies = response.cookies
|
||||
rcookies.pop(name, None)
|
||||
|
||||
+101
-90
@@ -116,6 +116,7 @@ __all__ = [
|
||||
|
||||
DEFAULT_PASSWORD_DISPLAY = '*' * 8
|
||||
|
||||
|
||||
def xmlescape(data, quote=True):
|
||||
"""
|
||||
Returns an escaped string of the provided data
|
||||
@@ -139,12 +140,14 @@ def xmlescape(data, quote=True):
|
||||
data = cgi.escape(data, quote).replace("'", "'")
|
||||
return data
|
||||
|
||||
|
||||
def call_as_list(f, *a, **b):
|
||||
if not isinstance(f, (list, tuple)):
|
||||
f = [f]
|
||||
for item in f:
|
||||
item(*a, **b)
|
||||
|
||||
|
||||
def truncate_string(text, length, dots='...'):
|
||||
text = text.decode('utf-8')
|
||||
if len(text) > length:
|
||||
@@ -152,27 +155,26 @@ def truncate_string(text, length, dots='...'):
|
||||
return text
|
||||
|
||||
|
||||
def URL(
|
||||
a=None,
|
||||
c=None,
|
||||
f=None,
|
||||
r=None,
|
||||
args=None,
|
||||
vars=None,
|
||||
anchor='',
|
||||
extension=None,
|
||||
env=None,
|
||||
hmac_key=None,
|
||||
hash_vars=True,
|
||||
salt=None,
|
||||
user_signature=None,
|
||||
scheme=None,
|
||||
host=None,
|
||||
port=None,
|
||||
encode_embedded_slash=False,
|
||||
url_encode=True,
|
||||
language=None,
|
||||
):
|
||||
def URL(a=None,
|
||||
c=None,
|
||||
f=None,
|
||||
r=None,
|
||||
args=None,
|
||||
vars=None,
|
||||
anchor='',
|
||||
extension=None,
|
||||
env=None,
|
||||
hmac_key=None,
|
||||
hash_vars=True,
|
||||
salt=None,
|
||||
user_signature=None,
|
||||
scheme=None,
|
||||
host=None,
|
||||
port=None,
|
||||
encode_embedded_slash=False,
|
||||
url_encode=True,
|
||||
language=None
|
||||
):
|
||||
"""
|
||||
generates a url '/a/c/f' corresponding to application a, controller c
|
||||
and function f. If r=request is passed, a, c, f are set, respectively,
|
||||
@@ -256,10 +258,6 @@ def URL(
|
||||
|
||||
>>> str(URL(a='a', c='c', f='f', anchor='%(id)d', url_encode=True))
|
||||
'/a/c/f#%25%28id%29d'
|
||||
|
||||
|
||||
|
||||
|
||||
"""
|
||||
|
||||
from rewrite import url_out # done here in case used not-in web2py
|
||||
@@ -439,7 +437,7 @@ def verifyURL(request, hmac_key=None, hash_vars=True, salt=None, user_signature=
|
||||
|
||||
"""
|
||||
|
||||
if not '_signature' in request.get_vars:
|
||||
if '_signature' not in request.get_vars:
|
||||
return False # no signature in the request URL
|
||||
|
||||
# check if user_signature requires
|
||||
@@ -539,19 +537,24 @@ class XmlComponent(object):
|
||||
return CAT(*components)
|
||||
|
||||
def add_class(self, name):
|
||||
""" add a class to _class attribute """
|
||||
"""
|
||||
add a class to _class attribute
|
||||
"""
|
||||
c = self['_class']
|
||||
classes = (set(c.split()) if c else set()) | set(name.split())
|
||||
self['_class'] = ' '.join(classes) if classes else None
|
||||
return self
|
||||
|
||||
def remove_class(self, name):
|
||||
""" remove a class from _class attribute """
|
||||
"""
|
||||
remove a class from _class attribute
|
||||
"""
|
||||
c = self['_class']
|
||||
classes = (set(c.split()) if c else set()) - set(name.split())
|
||||
self['_class'] = ' '.join(classes) if classes else None
|
||||
return self
|
||||
|
||||
|
||||
class XML(XmlComponent):
|
||||
"""
|
||||
use it to wrap a string that contains XML/HTML so that it will not be
|
||||
@@ -664,7 +667,7 @@ class XML(XmlComponent):
|
||||
"""
|
||||
return []
|
||||
|
||||
### important to allow safe session.flash=T(....)
|
||||
# ## important to allow safe session.flash=T(....)
|
||||
|
||||
|
||||
def XML_unpickle(data):
|
||||
@@ -1172,7 +1175,7 @@ class DIV(XmlComponent):
|
||||
# loop the components
|
||||
if find_text or find_components:
|
||||
i = 0
|
||||
while i<len(self.components):
|
||||
while i < len(self.components):
|
||||
c = self[i]
|
||||
j = i+1
|
||||
if check and find_text and isinstance(c, str) and \
|
||||
@@ -1265,6 +1268,7 @@ class __tag_div__(DIV):
|
||||
|
||||
copy_reg.pickle(__tag_div__, TAG_pickler, TAG_unpickler)
|
||||
|
||||
|
||||
class __TAG__(XmlComponent):
|
||||
|
||||
"""
|
||||
@@ -1589,6 +1593,7 @@ class A(DIV):
|
||||
self['_data-w2p_pre_call'] = self['pre_call']
|
||||
return DIV.xml(self)
|
||||
|
||||
|
||||
class BUTTON(DIV):
|
||||
|
||||
tag = 'button'
|
||||
@@ -1863,11 +1868,11 @@ class INPUT(DIV):
|
||||
print traceback.format_exc()
|
||||
msg = "Validation error, field:%s %s" % (name,validator)
|
||||
raise Exception(msg)
|
||||
if not errors is None:
|
||||
if errors is not None:
|
||||
self.vars[name] = value
|
||||
self.errors[name] = errors
|
||||
break
|
||||
if not name in self.errors:
|
||||
if name not in self.errors:
|
||||
self.vars[name] = value
|
||||
return True
|
||||
return False
|
||||
@@ -1882,7 +1887,7 @@ class INPUT(DIV):
|
||||
_value = None
|
||||
else:
|
||||
_value = str(self['_value'])
|
||||
if '_checked' in self.attributes and not 'value' in self.attributes:
|
||||
if '_checked' in self.attributes and 'value' not in self.attributes:
|
||||
pass
|
||||
elif t == 'checkbox':
|
||||
if not _value:
|
||||
@@ -1912,8 +1917,7 @@ class INPUT(DIV):
|
||||
if name and hasattr(self, 'errors') \
|
||||
and self.errors.get(name, None) \
|
||||
and self['hideerror'] != True:
|
||||
self['_class'] = (self['_class'] and self['_class']
|
||||
+ ' ' or '') + 'invalidinput'
|
||||
self['_class'] = (self['_class'] and self['_class'] + ' ' or '') + 'invalidinput'
|
||||
return DIV.xml(self) + DIV(
|
||||
DIV(
|
||||
self.errors[name], _class='error',
|
||||
@@ -1941,11 +1945,11 @@ class TEXTAREA(INPUT):
|
||||
tag = 'textarea'
|
||||
|
||||
def _postprocessing(self):
|
||||
if not '_rows' in self.attributes:
|
||||
if '_rows' not in self.attributes:
|
||||
self['_rows'] = 10
|
||||
if not '_cols' in self.attributes:
|
||||
if '_cols' not in self.attributes:
|
||||
self['_cols'] = 40
|
||||
if not self['value'] is None:
|
||||
if self['value'] is not None:
|
||||
self.components = [self['value']]
|
||||
elif self.components:
|
||||
self['value'] = self.components[0]
|
||||
@@ -1956,7 +1960,7 @@ class OPTION(DIV):
|
||||
tag = 'option'
|
||||
|
||||
def _fixup(self):
|
||||
if not '_value' in self.attributes:
|
||||
if '_value' not in self.attributes:
|
||||
self.attributes['_value'] = str(self.components[0])
|
||||
|
||||
|
||||
@@ -2012,11 +2016,10 @@ class SELECT(INPUT):
|
||||
options = itertools.chain(*component_list)
|
||||
|
||||
value = self['value']
|
||||
if not value is None:
|
||||
if value is not None:
|
||||
if not self['_multiple']:
|
||||
for c in options: # my patch
|
||||
if ((value is not None) and
|
||||
(str(c['_value']) == str(value))):
|
||||
if ((value is not None) and (str(c['_value']) == str(value))):
|
||||
c['_selected'] = 'selected'
|
||||
else:
|
||||
c['_selected'] = None
|
||||
@@ -2026,8 +2029,7 @@ class SELECT(INPUT):
|
||||
else:
|
||||
values = [str(value)]
|
||||
for c in options: # my patch
|
||||
if ((value is not None) and
|
||||
(str(c['_value']) in values)):
|
||||
if ((value is not None) and (str(c['_value']) in values)):
|
||||
c['_selected'] = 'selected'
|
||||
else:
|
||||
c['_selected'] = None
|
||||
@@ -2077,16 +2079,15 @@ class FORM(DIV):
|
||||
def assert_status(self, status, request_vars):
|
||||
return status
|
||||
|
||||
def accepts(
|
||||
self,
|
||||
request_vars,
|
||||
session=None,
|
||||
formname='default',
|
||||
keepvalues=False,
|
||||
onvalidation=None,
|
||||
hideerror=False,
|
||||
**kwargs
|
||||
):
|
||||
def accepts(self,
|
||||
request_vars,
|
||||
session=None,
|
||||
formname='default',
|
||||
keepvalues=False,
|
||||
onvalidation=None,
|
||||
hideerror=False,
|
||||
**kwargs
|
||||
):
|
||||
"""
|
||||
kwargs is not used but allows to specify the same interface for FORM and SQLFORM
|
||||
"""
|
||||
@@ -2128,8 +2129,7 @@ class FORM(DIV):
|
||||
onsuccess = onvalidation.get('onsuccess', None)
|
||||
onfailure = onvalidation.get('onfailure', None)
|
||||
onchange = onvalidation.get('onchange', None)
|
||||
if [k for k in onvalidation if not k in (
|
||||
'onsuccess', 'onfailure', 'onchange')]:
|
||||
if [k for k in onvalidation if k not in ('onsuccess', 'onfailure', 'onchange')]:
|
||||
raise RuntimeError('Invalid key in onvalidate dict')
|
||||
if onsuccess and status:
|
||||
call_as_list(onsuccess, self)
|
||||
@@ -2144,7 +2144,7 @@ class FORM(DIV):
|
||||
call_as_list(onvalidation, self)
|
||||
if self.errors:
|
||||
status = False
|
||||
if not session is None:
|
||||
if session is not None:
|
||||
if hasattr(self, 'record_hash'):
|
||||
formkey = self.record_hash + ':' + web2py_uuid()
|
||||
else:
|
||||
@@ -2158,25 +2158,22 @@ class FORM(DIV):
|
||||
return status
|
||||
|
||||
def _postprocessing(self):
|
||||
if not '_action' in self.attributes:
|
||||
if '_action' not in self.attributes:
|
||||
self['_action'] = '#'
|
||||
if not '_method' in self.attributes:
|
||||
if '_method' not in self.attributes:
|
||||
self['_method'] = 'post'
|
||||
if not '_enctype' in self.attributes:
|
||||
if '_enctype' not in self.attributes:
|
||||
self['_enctype'] = 'multipart/form-data'
|
||||
|
||||
def hidden_fields(self):
|
||||
c = []
|
||||
attr = self.attributes.get('hidden', {})
|
||||
if 'hidden' in self.attributes:
|
||||
c = [INPUT(_type='hidden', _name=key, _value=value)
|
||||
for (key, value) in attr.iteritems()]
|
||||
c = [INPUT(_type='hidden', _name=key, _value=value) for (key, value) in attr.iteritems()]
|
||||
if hasattr(self, 'formkey') and self.formkey:
|
||||
c.append(INPUT(_type='hidden', _name='_formkey',
|
||||
_value=self.formkey))
|
||||
c.append(INPUT(_type='hidden', _name='_formkey', _value=self.formkey))
|
||||
if hasattr(self, 'formname') and self.formname:
|
||||
c.append(INPUT(_type='hidden', _name='_formname',
|
||||
_value=self.formname))
|
||||
c.append(INPUT(_type='hidden', _name='_formname', _value=self.formname))
|
||||
return DIV(c, _style="display:none;")
|
||||
|
||||
def xml(self):
|
||||
@@ -2221,8 +2218,7 @@ class FORM(DIV):
|
||||
kwargs['request_vars'] = kwargs.get(
|
||||
'request_vars', current.request.post_vars)
|
||||
kwargs['session'] = kwargs.get('session', current.session)
|
||||
kwargs['dbio'] = kwargs.get('dbio', False)
|
||||
# necessary for SQLHTML forms
|
||||
kwargs['dbio'] = kwargs.get('dbio', False) # necessary for SQLHTML forms
|
||||
|
||||
onsuccess = kwargs.get('onsuccess', 'flash')
|
||||
onfailure = kwargs.get('onfailure', 'flash')
|
||||
@@ -2301,8 +2297,7 @@ class FORM(DIV):
|
||||
|
||||
|
||||
"""
|
||||
kwargs['dbio'] = kwargs.get('dbio', True)
|
||||
# necessary for SQLHTML forms
|
||||
kwargs['dbio'] = kwargs.get('dbio', True) # necessary for SQLHTML forms
|
||||
self.validate(**kwargs)
|
||||
return self
|
||||
|
||||
@@ -2348,10 +2343,9 @@ class FORM(DIV):
|
||||
def sanitizer(obj):
|
||||
if isinstance(obj, dict):
|
||||
for k in obj.keys():
|
||||
if any([unsafe in str(k).upper() for
|
||||
unsafe in UNSAFE]):
|
||||
# erease unsafe pair
|
||||
obj.pop(k)
|
||||
if any([unsafe in str(k).upper() for unsafe in UNSAFE]):
|
||||
# erease unsafe pair
|
||||
obj.pop(k)
|
||||
else:
|
||||
# not implemented
|
||||
pass
|
||||
@@ -2377,8 +2371,10 @@ class FORM(DIV):
|
||||
return [flatten(item) for item in newobj]
|
||||
else:
|
||||
return newobj
|
||||
else: return str(newobj)
|
||||
else: return newobj
|
||||
else:
|
||||
return str(newobj)
|
||||
else:
|
||||
return newobj
|
||||
return flatten(d)
|
||||
|
||||
def as_json(self, sanitize=True):
|
||||
@@ -2505,19 +2501,19 @@ class MENU(DIV):
|
||||
self.data = data
|
||||
self.attributes = args
|
||||
self.components = []
|
||||
if not '_class' in self.attributes:
|
||||
if '_class' not in self.attributes:
|
||||
self['_class'] = 'web2py-menu web2py-menu-vertical'
|
||||
if not 'ul_class' in self.attributes:
|
||||
if 'ul_class' not in self.attributes:
|
||||
self['ul_class'] = 'web2py-menu-vertical'
|
||||
if not 'li_class' in self.attributes:
|
||||
if 'li_class' not in self.attributes:
|
||||
self['li_class'] = 'web2py-menu-expand'
|
||||
if not 'li_first' in self.attributes:
|
||||
if 'li_first' not in self.attributes:
|
||||
self['li_first'] = 'web2py-menu-first'
|
||||
if not 'li_last' in self.attributes:
|
||||
if 'li_last' not in self.attributes:
|
||||
self['li_last'] = 'web2py-menu-last'
|
||||
if not 'li_active' in self.attributes:
|
||||
if 'li_active' not in self.attributes:
|
||||
self['li_active'] = 'web2py-menu-active'
|
||||
if not 'mobile' in self.attributes:
|
||||
if 'mobile' not in self.attributes:
|
||||
self['mobile'] = False
|
||||
|
||||
def serialize(self, data, level=0):
|
||||
@@ -2587,12 +2583,11 @@ class MENU(DIV):
|
||||
return self.serialize(self.data, 0).xml()
|
||||
|
||||
|
||||
def embed64(
|
||||
filename=None,
|
||||
file=None,
|
||||
data=None,
|
||||
extension='image/gif',
|
||||
):
|
||||
def embed64(filename=None,
|
||||
file=None,
|
||||
data=None,
|
||||
extension='image/gif'
|
||||
):
|
||||
"""
|
||||
helper to encode the provided (binary) data into base64.
|
||||
|
||||
@@ -2610,6 +2605,7 @@ def embed64(
|
||||
return 'data:%s;base64,%s' % (extension, data)
|
||||
|
||||
|
||||
# TODO: Check if this test() is still relevant now that we have gluon/tests/test_html.py
|
||||
def test():
|
||||
"""
|
||||
Example:
|
||||
@@ -2833,11 +2829,26 @@ class MARKMIN(XmlComponent):
|
||||
def __str__(self):
|
||||
return self.xml()
|
||||
|
||||
|
||||
def ASSIGNJS(**kargs):
|
||||
"""
|
||||
Example:
|
||||
ASSIGNJS(var1='1', var2='2') will return the following javascript variables assignations :
|
||||
|
||||
var var1 = "1";
|
||||
var var2 = "2";
|
||||
|
||||
Args:
|
||||
**kargs: Any keywords arguments and assigned values.
|
||||
|
||||
Returns:
|
||||
Javascript vars assignations for the key/value passed.
|
||||
|
||||
"""
|
||||
from gluon.serializers import json
|
||||
s = ""
|
||||
for key, value in kargs.items():
|
||||
s+='var %s = %s;\n' % (key, json(value))
|
||||
s += 'var %s = %s;\n' % (key, json(value))
|
||||
return XML(s)
|
||||
|
||||
|
||||
|
||||
@@ -61,7 +61,13 @@ PY_STRING_LITERAL_RE = r'(?<=[^\w]T\()(?P<name>'\
|
||||
+ r"(?:'(?:[^'\\]|\\.)*')|" + r'(?:"""(?:[^"]|"{1,2}(?!"))*""")|'\
|
||||
+ r'(?:"(?:[^"\\]|\\.)*"))'
|
||||
|
||||
PY_M_STRING_LITERAL_RE = r'(?<=[^\w]T\.M\()(?P<name>'\
|
||||
+ r"[uU]?[rR]?(?:'''(?:[^']|'{1,2}(?!'))*''')|"\
|
||||
+ r"(?:'(?:[^'\\]|\\.)*')|" + r'(?:"""(?:[^"]|"{1,2}(?!"))*""")|'\
|
||||
+ r'(?:"(?:[^"\\]|\\.)*"))'
|
||||
|
||||
regex_translate = re.compile(PY_STRING_LITERAL_RE, re.DOTALL)
|
||||
regex_translate_m = re.compile(PY_M_STRING_LITERAL_RE, re.DOTALL)
|
||||
regex_param = re.compile(r'{(?P<s>.+?)}')
|
||||
|
||||
# pattern for a valid accept_language
|
||||
@@ -960,6 +966,7 @@ def findT(path, language=DEFAULT_LANGUAGE):
|
||||
+ listdir(vp, '^.+\.html$', 0) + listdir(mop, '^.+\.py$', 0):
|
||||
data = read_locked(filename)
|
||||
items = regex_translate.findall(data)
|
||||
items += regex_translate_m.findall(data)
|
||||
for item in items:
|
||||
try:
|
||||
message = safe_eval(item)
|
||||
@@ -995,6 +1002,23 @@ def update_all_languages(application_path):
|
||||
findT(application_path, language[:-3])
|
||||
|
||||
|
||||
def update_from_langfile(target, source):
|
||||
"""this will update untranslated messages in target from source (where both are language files)
|
||||
this can be used as first step when creating language file for new but very similar language
|
||||
or if you want update your app from welcome app of newer web2py version
|
||||
or in non-standard scenarios when you work on target and from any reason you have partial translation in source
|
||||
"""
|
||||
src = read_dict(source)
|
||||
sentences = read_dict(target)
|
||||
for key in sentences:
|
||||
val = sentences[key]
|
||||
if not val or val == key:
|
||||
new_val = src.get(key)
|
||||
if new_val and new_val != val:
|
||||
sentences[key] = new_val
|
||||
write_dict(target, sentences)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
|
||||
+3
-4
@@ -80,10 +80,9 @@ locale.setlocale(locale.LC_CTYPE, "C") # IMPORTANT, web2py requires locale "C"
|
||||
exists = os.path.exists
|
||||
pjoin = os.path.join
|
||||
|
||||
logpath = abspath("logging.conf")
|
||||
if exists(logpath):
|
||||
try:
|
||||
logging.config.fileConfig(abspath("logging.conf"))
|
||||
else:
|
||||
except: # fails on GAE or when logfile is missing
|
||||
logging.basicConfig()
|
||||
logger = logging.getLogger("web2py")
|
||||
|
||||
@@ -361,7 +360,7 @@ def wsgibase(environ, responder):
|
||||
local_hosts = global_settings.local_hosts
|
||||
client = get_client(env)
|
||||
x_req_with = str(env.http_x_requested_with).lower()
|
||||
cmd_opts = request.global_settings.cmd_options
|
||||
cmd_opts = global_settings.cmd_options
|
||||
|
||||
request.update(
|
||||
client = client,
|
||||
|
||||
+1
-1
Submodule gluon/packages/dal updated: 4b37722a22...60e97e7cfd
+4
-4
@@ -642,7 +642,7 @@ def regex_url_in(request, environ):
|
||||
items = filename.split('/', 1)
|
||||
if regex_version.match(items[0]):
|
||||
version, filename = items
|
||||
static_folder = pjoin(request.env.applications_parent,
|
||||
static_folder = pjoin(global_settings.applications_parent,
|
||||
'applications', application, 'static')
|
||||
static_file = os.path.abspath(pjoin(static_folder, filename))
|
||||
if not static_file.startswith(static_folder):
|
||||
@@ -947,7 +947,7 @@ class MapUrlIn(object):
|
||||
|
||||
if len(self.args) == 1 and self.arg0 in self.router.root_static:
|
||||
self.controller = self.request.controller = 'static'
|
||||
root_static_file = pjoin(self.request.env.applications_parent,
|
||||
root_static_file = pjoin(global_settings.applications_parent,
|
||||
'applications', self.application,
|
||||
self.controller, self.arg0)
|
||||
log_rewrite("route: root static=%s" % root_static_file)
|
||||
@@ -1016,11 +1016,11 @@ class MapUrlIn(object):
|
||||
# if language-specific file doesn't exist, try same file in static
|
||||
#
|
||||
if self.language:
|
||||
static_file = pjoin(self.request.env.applications_parent,
|
||||
static_file = pjoin(global_settings.applications_parent,
|
||||
'applications', self.application,
|
||||
'static', self.language, file)
|
||||
if not self.language or not isfile(static_file):
|
||||
static_file = pjoin(self.request.env.applications_parent,
|
||||
static_file = pjoin(global_settings.applications_parent,
|
||||
'applications', self.application,
|
||||
'static', file)
|
||||
self.extension = None
|
||||
|
||||
+10
-7
@@ -677,7 +677,7 @@ class AutocompleteWidget(object):
|
||||
def callback(self):
|
||||
if self.keyword in self.request.vars:
|
||||
field = self.fields[0]
|
||||
if type(field) is FieldVirtual:
|
||||
if type(field) is Field.Virtual:
|
||||
records = []
|
||||
table_rows = self.db(self.db[field.tablename]).select(orderby=self.orderby)
|
||||
count = 0
|
||||
@@ -741,7 +741,7 @@ class AutocompleteWidget(object):
|
||||
del attr['requires']
|
||||
attr['_name'] = key2
|
||||
value = attr['value']
|
||||
if type(self.fields[0]) is FieldVirtual:
|
||||
if type(self.fields[0]) is Field.Virtual:
|
||||
record = None
|
||||
table_rows = self.db(self.db[self.fields[0].tablename]).select(orderby=self.orderby)
|
||||
for row in table_rows:
|
||||
@@ -901,6 +901,7 @@ def formstyle_bootstrap3_stacked(form, fields):
|
||||
elif controls['_type'] == 'checkbox':
|
||||
label['_for'] = None
|
||||
label.insert(0, controls)
|
||||
label.insert(0, ' ')
|
||||
_controls = DIV(label, _help, _class="checkbox")
|
||||
label = ''
|
||||
elif isinstance(controls, (SELECT, TEXTAREA)):
|
||||
@@ -950,6 +951,7 @@ def formstyle_bootstrap3_inline_factory(col_label_size=3):
|
||||
elif controls['_type'] == 'checkbox':
|
||||
label['_for'] = None
|
||||
label.insert(0, controls)
|
||||
label.insert(1, ' ')
|
||||
_controls = DIV(DIV(label, _help, _class="checkbox"),
|
||||
_class="%s %s" % (offset_class, col_class))
|
||||
label = ''
|
||||
@@ -2183,7 +2185,7 @@ class SQLFORM(FORM):
|
||||
buttonurl=url(args=[]), callback=None,
|
||||
delete=None, trap=True, noconfirm=None, title=None):
|
||||
if showbuttontext:
|
||||
return A(SPAN(_class=ui.get(buttonclass)),
|
||||
return A(SPAN(_class=ui.get(buttonclass)), CAT(' '),
|
||||
SPAN(T(buttontext), _title=title or T(buttontext),
|
||||
_class=ui.get('buttontext')),
|
||||
_href=buttonurl,
|
||||
@@ -2204,15 +2206,12 @@ class SQLFORM(FORM):
|
||||
|
||||
dbset = db(query, ignore_common_filters=ignore_common_filters)
|
||||
tablenames = db._adapter.tables(dbset.query)
|
||||
print dbset.query
|
||||
print tablenames
|
||||
if left is not None:
|
||||
if not isinstance(left, (list, tuple)):
|
||||
left = [left]
|
||||
for join in left:
|
||||
tablenames += db._adapter.tables(join)
|
||||
tables = [db[tablename] for tablename in tablenames]
|
||||
print tables
|
||||
if fields:
|
||||
# add missing tablename to virtual fields
|
||||
for table in tables:
|
||||
@@ -2744,7 +2743,11 @@ class SQLFORM(FORM):
|
||||
if field.type == 'blob':
|
||||
continue
|
||||
if isinstance(field, Field.Virtual) and field.tablename in row:
|
||||
value = dbset.db[field.tablename][row[field.tablename][field_id]][field.name]
|
||||
try:
|
||||
# fast path, works for joins
|
||||
value = row[field.tablename][field.name]
|
||||
except KeyError:
|
||||
value = dbset.db[field.tablename][row[field.tablename][field_id]][field.name]
|
||||
else:
|
||||
value = row[str(field)]
|
||||
maxlength = maxtextlengths.get(str(field), maxtextlength)
|
||||
|
||||
@@ -12,13 +12,19 @@ from fileutils import parse_version
|
||||
|
||||
class TestFileUtils(unittest.TestCase):
|
||||
|
||||
def testParseVersion(self):
|
||||
rtn = parse_version('Version 1.99.0-rc.1+timestamp.2011.09.19.08.23.26')
|
||||
self.assertEqual(rtn, (1, 99, 0, 'rc.1', datetime.datetime(2011, 9, 19, 8, 23, 26)))
|
||||
rtn = parse_version('Version 2.9.11-stable+timestamp.2014.09.15.18.31.17')
|
||||
self.assertEqual(rtn, (2, 9, 11, 'stable', datetime.datetime(2014, 9, 15, 18, 31, 17)))
|
||||
def test_parse_version(self):
|
||||
# Legacy
|
||||
rtn = parse_version('Version 1.99.0 (2011-09-19 08:23:26)')
|
||||
self.assertEqual(rtn, (1, 99, 0, 'dev', datetime.datetime(2011, 9, 19, 8, 23, 26)))
|
||||
# Semantic
|
||||
rtn = parse_version('Version 1.99.0-rc.1+timestamp.2011.09.19.08.23.26')
|
||||
self.assertEqual(rtn, (1, 99, 0, 'rc.1', datetime.datetime(2011, 9, 19, 8, 23, 26)))
|
||||
# Semantic Stable
|
||||
rtn = parse_version('Version 2.9.11-stable+timestamp.2014.09.15.18.31.17')
|
||||
self.assertEqual(rtn, (2, 9, 11, 'stable', datetime.datetime(2014, 9, 15, 18, 31, 17)))
|
||||
# Semantic Beta
|
||||
rtn = parse_version('Version 2.14.1-beta+timestamp.2016.03.21.22.35.26')
|
||||
self.assertEqual(rtn, (2, 14, 1, 'beta', datetime.datetime(2016, 3, 21, 22, 35, 26)))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
+519
-320
@@ -12,314 +12,25 @@ fix_sys_path(__file__)
|
||||
|
||||
from html import *
|
||||
from html import verifyURL
|
||||
from html import truncate_string
|
||||
from storage import Storage
|
||||
|
||||
|
||||
class TestBareHelpers(unittest.TestCase):
|
||||
|
||||
def testBR(self):
|
||||
self.assertEqual(BR(_a='1', _b='2').xml(), '<br a="1" b="2" />')
|
||||
# TODO: def test_xmlescape(self):
|
||||
# TODO: def test_call_as_list(self):
|
||||
|
||||
def testEMBED(self):
|
||||
self.assertEqual(EMBED(_a='1', _b='2').xml(),
|
||||
'<embed a="1" b="2" />')
|
||||
def test_truncate_string(self):
|
||||
# Ascii text
|
||||
self.assertEqual(truncate_string('Lorem ipsum dolor sit amet, consectetur adipiscing elit, '
|
||||
'sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
|
||||
length=30), 'Lorem ipsum dolor sit amet,...')
|
||||
# French text
|
||||
self.assertEqual(truncate_string('Un texte en français avec des accents et des caractères bizarre.', length=30),
|
||||
'Un texte en français avec d...')
|
||||
|
||||
def testHR(self):
|
||||
self.assertEqual(HR(_a='1', _b='2').xml(), '<hr a="1" b="2" />')
|
||||
|
||||
def testIMG(self):
|
||||
self.assertEqual(IMG(_a='1', _b='2').xml(),
|
||||
'<img a="1" b="2" />')
|
||||
|
||||
def testINPUT(self):
|
||||
self.assertEqual(INPUT(_a='1', _b='2').xml(),
|
||||
'<input a="1" b="2" type="text" />')
|
||||
|
||||
def testLINK(self):
|
||||
self.assertEqual(LINK(_a='1', _b='2').xml(),
|
||||
'<link a="1" b="2" />')
|
||||
|
||||
def testMETA(self):
|
||||
self.assertEqual(META(_a='1', _b='2').xml(),
|
||||
'<meta a="1" b="2" />')
|
||||
|
||||
def testA(self):
|
||||
self.assertEqual(
|
||||
A('<>', _a='1', _b='2').xml(),
|
||||
'<a a="1" b="2"><></a>'
|
||||
)
|
||||
self.assertEqual(
|
||||
A('a', cid='b').xml(),
|
||||
'<a data-w2p_disable_with="default" data-w2p_method="GET" data-w2p_target="b">a</a>'
|
||||
)
|
||||
self.assertEqual(
|
||||
A('a', callback='b', _id='c').xml(),
|
||||
'<a data-w2p_disable_with="default" data-w2p_method="POST" href="b" id="c">a</a>'
|
||||
)
|
||||
self.assertEqual(
|
||||
A('a', delete='tr').xml(),
|
||||
'<a data-w2p_disable_with="default" data-w2p_remove="tr">a</a>'
|
||||
)
|
||||
self.assertEqual(
|
||||
A('a', _id='b', target='<self>').xml(),
|
||||
'<a data-w2p_disable_with="default" data-w2p_target="b" id="b">a</a>'
|
||||
)
|
||||
self.assertEqual(
|
||||
A('a', component='b').xml(),
|
||||
'<a data-w2p_disable_with="default" data-w2p_method="GET" href="b">a</a>'
|
||||
)
|
||||
self.assertEqual(
|
||||
A('a', _id='b', callback='c', noconfirm=True).xml(),
|
||||
'<a data-w2p_disable_with="default" data-w2p_method="POST" href="c" id="b">a</a>'
|
||||
)
|
||||
self.assertEqual(
|
||||
A('a', cid='b').xml(),
|
||||
'<a data-w2p_disable_with="default" data-w2p_method="GET" data-w2p_target="b">a</a>'
|
||||
)
|
||||
self.assertEqual(
|
||||
A('a', cid='b', _disable_with='processing...').xml(),
|
||||
'<a data-w2p_disable_with="processing..." data-w2p_method="GET" data-w2p_target="b">a</a>'
|
||||
)
|
||||
self.assertEqual(
|
||||
A('a', callback='b', delete='tr', noconfirm=True, _id='c').xml(),
|
||||
'<a data-w2p_disable_with="default" data-w2p_method="POST" data-w2p_remove="tr" href="b" id="c">a</a>'
|
||||
)
|
||||
self.assertEqual(
|
||||
A('a', callback='b', delete='tr', confirm='Are you sure?', _id='c').xml(),
|
||||
'<a data-w2p_confirm="Are you sure?" data-w2p_disable_with="default" data-w2p_method="POST" data-w2p_remove="tr" href="b" id="c">a</a>'
|
||||
)
|
||||
|
||||
def testB(self):
|
||||
self.assertEqual(B('<>', _a='1', _b='2').xml(),
|
||||
'<b a="1" b="2"><></b>')
|
||||
|
||||
def testBODY(self):
|
||||
self.assertEqual(BODY('<>', _a='1', _b='2').xml(),
|
||||
'<body a="1" b="2"><></body>')
|
||||
|
||||
def testCENTER(self):
|
||||
self.assertEqual(CENTER('<>', _a='1', _b='2').xml(),
|
||||
'<center a="1" b="2"><></center>')
|
||||
|
||||
def testDIV(self):
|
||||
self.assertEqual(DIV('<>', _a='1', _b='2').xml(),
|
||||
'<div a="1" b="2"><></div>')
|
||||
# attributes can be updated like in a dict
|
||||
div = DIV('<>', _a='1')
|
||||
div['_b'] = '2'
|
||||
self.assertEqual(div.xml(),
|
||||
'<div a="1" b="2"><></div>')
|
||||
# also with a mapping
|
||||
div.update(_b=2, _c=3)
|
||||
self.assertEqual(div.xml(),
|
||||
'<div a="1" b="2" c="3"><></div>')
|
||||
# length of the DIV is the number of components
|
||||
self.assertEqual(len(DIV('a', 'bc')), 2)
|
||||
# also if empty, DIV is True in a boolean evaluation
|
||||
self.assertTrue(True if DIV() else False)
|
||||
# parent and siblings
|
||||
a = DIV(SPAN('a'), DIV('b'))
|
||||
s = a.element('span')
|
||||
d = s.parent
|
||||
d['_class'] = 'abc'
|
||||
self.assertEqual(a.xml(), '<div class="abc"><span>a</span><div>b</div></div>')
|
||||
self.assertEqual([el.xml() for el in s.siblings()], ['<div>b</div>'])
|
||||
self.assertEqual(s.sibling().xml(), '<div>b</div>')
|
||||
self.assertEqual(s.siblings('a'), [])
|
||||
|
||||
def testEM(self):
|
||||
self.assertEqual(EM('<>', _a='1', _b='2').xml(),
|
||||
'<em a="1" b="2"><></em>')
|
||||
|
||||
def testFIELDSET(self):
|
||||
self.assertEqual(FIELDSET('<>', _a='1', _b='2').xml(),
|
||||
'<fieldset a="1" b="2"><></fieldset>')
|
||||
|
||||
def testFORM(self):
|
||||
self.assertEqual(FORM('<>', _a='1', _b='2').xml(),
|
||||
'<form a="1" action="#" b="2" enctype="multipart/form-data" method="post"><></form>')
|
||||
|
||||
def testH1(self):
|
||||
self.assertEqual(H1('<>', _a='1', _b='2').xml(),
|
||||
'<h1 a="1" b="2"><></h1>')
|
||||
|
||||
def testH2(self):
|
||||
self.assertEqual(H2('<>', _a='1', _b='2').xml(),
|
||||
'<h2 a="1" b="2"><></h2>')
|
||||
|
||||
def testH3(self):
|
||||
self.assertEqual(H3('<>', _a='1', _b='2').xml(),
|
||||
'<h3 a="1" b="2"><></h3>')
|
||||
|
||||
def testH4(self):
|
||||
self.assertEqual(H4('<>', _a='1', _b='2').xml(),
|
||||
'<h4 a="1" b="2"><></h4>')
|
||||
|
||||
def testH5(self):
|
||||
self.assertEqual(H5('<>', _a='1', _b='2').xml(),
|
||||
'<h5 a="1" b="2"><></h5>')
|
||||
|
||||
def testH6(self):
|
||||
self.assertEqual(H6('<>', _a='1', _b='2').xml(),
|
||||
'<h6 a="1" b="2"><></h6>')
|
||||
|
||||
def testHEAD(self):
|
||||
self.assertEqual(HEAD('<>', _a='1', _b='2').xml(),
|
||||
'<head a="1" b="2"><></head>')
|
||||
|
||||
def testHTML(self):
|
||||
self.assertEqual(HTML('<>', _a='1', _b='2').xml(),
|
||||
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n<html a="1" b="2" lang="en"><></html>')
|
||||
|
||||
def testIFRAME(self):
|
||||
self.assertEqual(IFRAME('<>', _a='1', _b='2').xml(),
|
||||
'<iframe a="1" b="2"><></iframe>')
|
||||
|
||||
def testLABEL(self):
|
||||
self.assertEqual(LABEL('<>', _a='1', _b='2').xml(),
|
||||
'<label a="1" b="2"><></label>')
|
||||
|
||||
def testLI(self):
|
||||
self.assertEqual(LI('<>', _a='1', _b='2').xml(),
|
||||
'<li a="1" b="2"><></li>')
|
||||
|
||||
def testOBJECT(self):
|
||||
self.assertEqual(OBJECT('<>', _a='1', _b='2').xml(),
|
||||
'<object a="1" b="2"><></object>')
|
||||
|
||||
def testOL(self):
|
||||
self.assertEqual(OL('<>', _a='1', _b='2').xml(),
|
||||
'<ol a="1" b="2"><li><></li></ol>')
|
||||
|
||||
def testOPTION(self):
|
||||
self.assertEqual(OPTION('<>', _a='1', _b='2').xml(),
|
||||
'<option a="1" b="2" value="<>"><>' +
|
||||
'</option>')
|
||||
|
||||
def testP(self):
|
||||
self.assertEqual(P('<>', _a='1', _b='2').xml(),
|
||||
'<p a="1" b="2"><></p>')
|
||||
# test cr2br
|
||||
self.assertEqual(P('a\nb').xml(), '<p>a\nb</p>')
|
||||
self.assertEqual(P('a\nb', cr2br=True).xml(), '<p>a<br />b</p>')
|
||||
|
||||
def testPRE(self):
|
||||
self.assertEqual(PRE('<>', _a='1', _b='2').xml(),
|
||||
'<pre a="1" b="2"><></pre>')
|
||||
|
||||
def testSCRIPT(self):
|
||||
self.assertEqual(SCRIPT('<>', _a='1', _b='2').xml(),
|
||||
'''<script a="1" b="2"><!--
|
||||
<>
|
||||
//--></script>''')
|
||||
self.assertEqual(SCRIPT('<>').xml(),
|
||||
'''<script><!--
|
||||
<>
|
||||
//--></script>''')
|
||||
self.assertEqual(SCRIPT().xml(), '<script></script>')
|
||||
|
||||
def testSELECT(self):
|
||||
self.assertEqual(SELECT('<>', _a='1', _b='2').xml(),
|
||||
'<select a="1" b="2">' +
|
||||
'<option value="<>"><></option></select>')
|
||||
|
||||
def testSPAN(self):
|
||||
self.assertEqual(SPAN('<>', _a='1', _b='2').xml(),
|
||||
'<span a="1" b="2"><></span>')
|
||||
|
||||
def testSTYLE(self):
|
||||
self.assertEqual(STYLE('<>', _a='1', _b='2').xml(),
|
||||
'<style a="1" b="2"><!--/*--><![CDATA[/*><!--*/\n<>\n/*]]>*/--></style>')
|
||||
|
||||
def testTABLE(self):
|
||||
self.assertEqual(TABLE('<>', _a='1', _b='2').xml(),
|
||||
'<table a="1" b="2"><tr><td><></td></tr>' +
|
||||
'</table>')
|
||||
|
||||
def testTBODY(self):
|
||||
self.assertEqual(TBODY('<>', _a='1', _b='2').xml(),
|
||||
'<tbody a="1" b="2"><tr><td><></td></tr></tbody>')
|
||||
|
||||
def testTD(self):
|
||||
self.assertEqual(TD('<>', _a='1', _b='2').xml(),
|
||||
'<td a="1" b="2"><></td>')
|
||||
|
||||
def testTEXTAREA(self):
|
||||
self.assertEqual(TEXTAREA('<>', _a='1', _b='2').xml(),
|
||||
'<textarea a="1" b="2" cols="40" rows="10"><>' +
|
||||
'</textarea>')
|
||||
# override _rows and _cols
|
||||
self.assertEqual(TEXTAREA('<>', _a='1', _b='2', _rows=5, _cols=20).xml(),
|
||||
'<textarea a="1" b="2" cols="20" rows="5"><>' +
|
||||
'</textarea>')
|
||||
|
||||
def testTFOOT(self):
|
||||
self.assertEqual(TFOOT('<>', _a='1', _b='2').xml(),
|
||||
'<tfoot a="1" b="2"><tr><td><></td></tr></tfoot>')
|
||||
|
||||
def testTH(self):
|
||||
self.assertEqual(TH('<>', _a='1', _b='2').xml(),
|
||||
'<th a="1" b="2"><></th>')
|
||||
|
||||
def testTHEAD(self):
|
||||
self.assertEqual(THEAD('<>', _a='1', _b='2').xml(),
|
||||
'<thead a="1" b="2"><tr><th><></th></tr></thead>')
|
||||
#self.assertEqual(THEAD(TRHEAD('<>'), _a='1', _b='2').xml(),
|
||||
# '<thead a="1" b="2"><tr><th><></th></tr></thead>')
|
||||
self.assertEqual(THEAD(TR('<>'), _a='1', _b='2').xml(),
|
||||
'<thead a="1" b="2"><tr><td><></td></tr></thead>')
|
||||
|
||||
def testTITLE(self):
|
||||
self.assertEqual(TITLE('<>', _a='1', _b='2').xml(),
|
||||
'<title a="1" b="2"><></title>')
|
||||
|
||||
def testTR(self):
|
||||
self.assertEqual(TR('<>', _a='1', _b='2').xml(),
|
||||
'<tr a="1" b="2"><td><></td></tr>')
|
||||
|
||||
def testTT(self):
|
||||
self.assertEqual(TT('<>', _a='1', _b='2').xml(),
|
||||
'<tt a="1" b="2"><></tt>')
|
||||
|
||||
def testUL(self):
|
||||
self.assertEqual(UL('<>', _a='1', _b='2').xml(),
|
||||
'<ul a="1" b="2"><li><></li></ul>')
|
||||
|
||||
def testXML(self):
|
||||
# sanitization process
|
||||
self.assertEqual(XML('<h1>Hello<a data-hello="world">World</a></h1>').xml(),
|
||||
'<h1>Hello<a data-hello="world">World</a></h1>')
|
||||
# with sanitize, data-attributes are not permitted
|
||||
self.assertEqual(XML('<h1>Hello<a data-hello="world">World</a></h1>', sanitize=True).xml(),
|
||||
'<h1>HelloWorld</h1>')
|
||||
# stringify by default
|
||||
self.assertEqual(XML(1.3), '1.3')
|
||||
self.assertEqual(XML(u'<div>è</div>').xml(), '<div>\xc3\xa8</div>')
|
||||
# you can calc len on the class, that equals the xml() and the str()
|
||||
self.assertEqual(len(XML('1.3')), len('1.3'))
|
||||
self.assertEqual(len(XML('1.3').xml()), len('1.3'))
|
||||
self.assertEqual(len(str(XML('1.3'))), len('1.3'))
|
||||
# you can concatenate them to strings (check for __add__ and __radd__ methods)
|
||||
self.assertEqual(XML('a') + 'b', 'ab')
|
||||
self.assertEqual(XML('a') + XML('b'), 'ab')
|
||||
self.assertEqual('a' + XML('b'), 'ab')
|
||||
# you can compare them
|
||||
self.assertEqual(XML('a') == XML('a'), True)
|
||||
# beware that the comparison is made on the XML repr
|
||||
self.assertEqual(XML('<h1>Hello<a data-hello="world">World</a></h1>', sanitize=True),
|
||||
XML('<h1>HelloWorld</h1>'))
|
||||
#bug check for the sanitizer for closing no-close tags
|
||||
self.assertEqual(XML('<p>Test</p><br/><p>Test</p><br/>', sanitize=True),
|
||||
XML('<p>Test</p><br /><p>Test</p><br />'))
|
||||
|
||||
def testTAG(self):
|
||||
self.assertEqual(TAG.first(TAG.second('test'), _key=3).xml(),
|
||||
'<first key="3"><second>test</second></first>')
|
||||
# ending in underscore "triggers" <input /> style
|
||||
self.assertEqual(TAG.first_(TAG.second('test'), _key=3).xml(),
|
||||
'<first key="3" />')
|
||||
|
||||
def testStaticURL(self):
|
||||
def test_StaticURL(self):
|
||||
# test response.static_version coupled with response.static_version_urls
|
||||
self.assertEqual(URL('a', 'c', 'f'), '/a/c/f')
|
||||
self.assertEqual(URL('a', 'static', 'design.css'), '/a/static/design.css')
|
||||
@@ -331,62 +42,62 @@ class TestBareHelpers(unittest.TestCase):
|
||||
response.static_version_urls = True
|
||||
self.assertEqual(URL('a', 'static', 'design.css'), '/a/static/_1.2.3/design.css')
|
||||
|
||||
def testURL(self):
|
||||
def test_URL(self):
|
||||
self.assertEqual(URL('a', 'c', 'f', args='1'), '/a/c/f/1')
|
||||
self.assertEqual(URL('a', 'c', 'f', args=('1', '2')), '/a/c/f/1/2')
|
||||
self.assertEqual(URL('a', 'c', 'f', args=['1', '2']), '/a/c/f/1/2')
|
||||
self.assertEqual(URL('a', 'c', '/f'), '/a/c/f')
|
||||
self.assertEqual(URL('a', 'c', 'f.json'), '/a/c/f.json')
|
||||
self.assertRaises(SyntaxError, URL, *['a'])
|
||||
|
||||
request = Storage()
|
||||
request.application = 'a'
|
||||
request.controller = 'c'
|
||||
request.function = 'f'
|
||||
request.env = {}
|
||||
from globals import current
|
||||
|
||||
from globals import current # Can't be moved with other import
|
||||
current.request = request
|
||||
|
||||
must_return = '/a/c/f'
|
||||
self.assertEqual(URL(), must_return)
|
||||
self.assertEqual(URL('f'), must_return)
|
||||
self.assertEqual(URL('c', 'f'), must_return)
|
||||
self.assertEqual(URL('a', 'c', 'f'), must_return)
|
||||
self.assertEqual(URL('a', 'c', 'f', extension='json'), '/a/c/f.json')
|
||||
|
||||
def weird():
|
||||
pass
|
||||
self.assertEqual(URL('a', 'c', weird), '/a/c/weird')
|
||||
self.assertRaises(SyntaxError, URL, *['a', 'c', 1])
|
||||
# test signature
|
||||
rtn = URL(
|
||||
a='a', c='c', f='f', args=['x', 'y', 'z'],
|
||||
vars={'p': (1, 3), 'q': 2}, anchor='1', hmac_key='key'
|
||||
)
|
||||
rtn = URL(a='a', c='c', f='f', args=['x', 'y', 'z'],
|
||||
vars={'p': (1, 3), 'q': 2}, anchor='1', hmac_key='key')
|
||||
self.assertEqual(rtn, '/a/c/f/x/y/z?p=1&p=3&q=2&_signature=a32530f0d0caa80964bb92aad2bedf8a4486a31f#1')
|
||||
# test _signature exclusion
|
||||
rtn = URL(
|
||||
a='a', c='c', f='f', args=['x', 'y', 'z'],
|
||||
vars={'p': (1, 3), 'q': 2, '_signature': 'abc'},
|
||||
anchor='1', hmac_key='key'
|
||||
)
|
||||
rtn = URL(a='a', c='c', f='f', args=['x', 'y', 'z'],
|
||||
vars={'p': (1, 3), 'q': 2, '_signature': 'abc'},
|
||||
anchor='1', hmac_key='key')
|
||||
self.assertEqual(rtn, '/a/c/f/x/y/z?p=1&p=3&q=2&_signature=a32530f0d0caa80964bb92aad2bedf8a4486a31f#1')
|
||||
# emulate user_signature
|
||||
current.session = Storage(auth=Storage(hmac_key='key'))
|
||||
self.assertEqual(URL(user_signature=True), '/a/c/f?_signature=c4aed53c08cff08f369dbf8b5ba51889430cf2c2')
|
||||
# hash_vars combination
|
||||
rtn = URL('a','c','f', args=['x', 'y', 'z'], vars={'p' : (1,3), 'q' : 2}, hmac_key='key')
|
||||
rtn = URL('a', 'c', 'f', args=['x', 'y', 'z'], vars={'p': (1, 3), 'q': 2}, hmac_key='key')
|
||||
self.assertEqual(rtn, '/a/c/f/x/y/z?p=1&p=3&q=2&_signature=a32530f0d0caa80964bb92aad2bedf8a4486a31f')
|
||||
rtn = URL('a','c','f', args=['x', 'y', 'z'], vars={'p' : (1,3), 'q' : 2}, hmac_key='key', hash_vars=True)
|
||||
rtn = URL('a', 'c', 'f', args=['x', 'y', 'z'], vars={'p': (1, 3), 'q': 2}, hmac_key='key', hash_vars=True)
|
||||
self.assertEqual(rtn, '/a/c/f/x/y/z?p=1&p=3&q=2&_signature=a32530f0d0caa80964bb92aad2bedf8a4486a31f')
|
||||
rtn = URL('a','c','f', args=['x', 'y', 'z'], vars={'p' : (1,3), 'q' : 2}, hmac_key='key', hash_vars=False)
|
||||
rtn = URL('a', 'c', 'f', args=['x', 'y', 'z'], vars={'p': (1, 3), 'q': 2}, hmac_key='key', hash_vars=False)
|
||||
self.assertEqual(rtn, '/a/c/f/x/y/z?p=1&p=3&q=2&_signature=0b5a0702039992aad23c82794b8496e5dcd59a5b')
|
||||
rtn = URL('a','c','f', args=['x', 'y', 'z'], vars={'p' : (1,3), 'q' : 2}, hmac_key='key', hash_vars=['p'])
|
||||
rtn = URL('a', 'c', 'f', args=['x', 'y', 'z'], vars={'p': (1, 3), 'q': 2}, hmac_key='key', hash_vars=['p'])
|
||||
self.assertEqual(rtn, '/a/c/f/x/y/z?p=1&p=3&q=2&_signature=5d01b982fd72b39674b012e0288071034e156d7a')
|
||||
rtn = URL('a','c','f', args=['x', 'y', 'z'], vars={'p' : (1,3), 'q' : 2}, hmac_key='key', hash_vars='p')
|
||||
rtn = URL('a', 'c', 'f', args=['x', 'y', 'z'], vars={'p': (1, 3), 'q': 2}, hmac_key='key', hash_vars='p')
|
||||
self.assertEqual(rtn, '/a/c/f/x/y/z?p=1&p=3&q=2&_signature=5d01b982fd72b39674b012e0288071034e156d7a')
|
||||
# test CRLF detection
|
||||
self.assertRaises(SyntaxError, URL, *['a\n', 'c', 'f'])
|
||||
self.assertRaises(SyntaxError, URL, *['a\r', 'c', 'f'])
|
||||
|
||||
def testverifyURL(self):
|
||||
def test_verifyURL(self):
|
||||
r = Storage()
|
||||
r.application = 'a'
|
||||
r.controller = 'c'
|
||||
@@ -429,12 +140,500 @@ class TestBareHelpers(unittest.TestCase):
|
||||
rtn = verifyURL(r, user_signature=True)
|
||||
self.assertEqual(rtn, True)
|
||||
|
||||
# TODO: def test_XmlComponent(self):
|
||||
|
||||
def test_XML(self):
|
||||
# sanitization process
|
||||
self.assertEqual(XML('<h1>Hello<a data-hello="world">World</a></h1>').xml(),
|
||||
'<h1>Hello<a data-hello="world">World</a></h1>')
|
||||
# with sanitize, data-attributes are not permitted
|
||||
self.assertEqual(XML('<h1>Hello<a data-hello="world">World</a></h1>', sanitize=True).xml(),
|
||||
'<h1>HelloWorld</h1>')
|
||||
# stringify by default
|
||||
self.assertEqual(XML(1.3), '1.3')
|
||||
self.assertEqual(XML(u'<div>è</div>').xml(), '<div>\xc3\xa8</div>')
|
||||
# you can calc len on the class, that equals the xml() and the str()
|
||||
self.assertEqual(len(XML('1.3')), len('1.3'))
|
||||
self.assertEqual(len(XML('1.3').xml()), len('1.3'))
|
||||
self.assertEqual(len(str(XML('1.3'))), len('1.3'))
|
||||
# you can concatenate them to strings (check for __add__ and __radd__ methods)
|
||||
self.assertEqual(XML('a') + 'b', 'ab')
|
||||
self.assertEqual(XML('a') + XML('b'), 'ab')
|
||||
self.assertEqual('a' + XML('b'), 'ab')
|
||||
# you can compare them
|
||||
self.assertEqual(XML('a') == XML('a'), True)
|
||||
# beware that the comparison is made on the XML repr
|
||||
self.assertEqual(XML('<h1>Hello<a data-hello="world">World</a></h1>', sanitize=True),
|
||||
XML('<h1>HelloWorld</h1>'))
|
||||
# bug check for the sanitizer for closing no-close tags
|
||||
self.assertEqual(XML('<p>Test</p><br/><p>Test</p><br/>', sanitize=True),
|
||||
XML('<p>Test</p><br /><p>Test</p><br />'))
|
||||
|
||||
# TODO: def test_XML_unpickle(self):
|
||||
|
||||
# TODO: def test_XML_pickle(self):
|
||||
|
||||
def test_DIV(self):
|
||||
# Empty DIV()
|
||||
self.assertEqual(DIV().xml(), '<div></div>')
|
||||
self.assertEqual(DIV('<>', _a='1', _b='2').xml(),
|
||||
'<div a="1" b="2"><></div>')
|
||||
# attributes can be updated like in a dict
|
||||
div = DIV('<>', _a='1')
|
||||
div['_b'] = '2'
|
||||
self.assertEqual(div.xml(),
|
||||
'<div a="1" b="2"><></div>')
|
||||
# also with a mapping
|
||||
div.update(_b=2, _c=3)
|
||||
self.assertEqual(div.xml(),
|
||||
'<div a="1" b="2" c="3"><></div>')
|
||||
# length of the DIV is the number of components
|
||||
self.assertEqual(len(DIV('a', 'bc')), 2)
|
||||
# also if empty, DIV is True in a boolean evaluation
|
||||
self.assertTrue(True if DIV() else False)
|
||||
# parent and siblings
|
||||
a = DIV(SPAN('a'), DIV('b'))
|
||||
s = a.element('span')
|
||||
d = s.parent
|
||||
d['_class'] = 'abc'
|
||||
self.assertEqual(a.xml(), '<div class="abc"><span>a</span><div>b</div></div>')
|
||||
self.assertEqual([el.xml() for el in s.siblings()], ['<div>b</div>'])
|
||||
self.assertEqual(s.sibling().xml(), '<div>b</div>')
|
||||
self.assertEqual(s.siblings('a'), [])
|
||||
# Corner case for raise coverage of one line
|
||||
# I think such assert fail cause of python 2.6
|
||||
# Work under python 2.7
|
||||
# with self.assertRaises(SyntaxError) as cm:
|
||||
# DIV(BR('<>')).xml()
|
||||
# self.assertEqual(cm.exception[0], '<br/> tags cannot have components')
|
||||
|
||||
def test_CAT(self):
|
||||
# Empty CAT()
|
||||
self.assertEqual(CAT().xml(), '')
|
||||
# CAT('')
|
||||
self.assertEqual(CAT('').xml(), '')
|
||||
# CAT(' ')
|
||||
self.assertEqual(CAT(' ').xml(), ' ')
|
||||
|
||||
# TODO: def test_TAG_unpickler(self):
|
||||
|
||||
# TODO: def test_TAG_pickler(self):
|
||||
|
||||
def test_TAG(self):
|
||||
self.assertEqual(TAG.first(TAG.second('test'), _key=3).xml(),
|
||||
'<first key="3"><second>test</second></first>')
|
||||
# ending in underscore "triggers" <input /> style
|
||||
self.assertEqual(TAG.first_(TAG.second('test'), _key=3).xml(),
|
||||
'<first key="3" />')
|
||||
|
||||
def test_HTML(self):
|
||||
self.assertEqual(HTML('<>', _a='1', _b='2').xml(),
|
||||
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n<html a="1" b="2" lang="en"><></html>')
|
||||
self.assertEqual(HTML('<>', _a='1', _b='2', doctype='strict').xml(),
|
||||
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n<html a="1" b="2" lang="en"><></html>')
|
||||
self.assertEqual(HTML('<>', _a='1', _b='2', doctype='transitional').xml(),
|
||||
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n<html a="1" b="2" lang="en"><></html>')
|
||||
self.assertEqual(HTML('<>', _a='1', _b='2', doctype='frameset').xml(),
|
||||
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">\n<html a="1" b="2" lang="en"><></html>')
|
||||
self.assertEqual(HTML('<>', _a='1', _b='2', doctype='html5').xml(),
|
||||
'<!DOCTYPE HTML>\n<html a="1" b="2" lang="en"><></html>')
|
||||
self.assertEqual(HTML('<>', _a='1', _b='2', doctype='').xml(),
|
||||
'<html a="1" b="2" lang="en"><></html>')
|
||||
self.assertEqual(HTML('<>', _a='1', _b='2', doctype='CustomDocType').xml(),
|
||||
'CustomDocType\n<html a="1" b="2" lang="en"><></html>')
|
||||
|
||||
def test_XHTML(self):
|
||||
# Empty XHTML test
|
||||
self.assertEqual(XHTML().xml(),
|
||||
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml"></html>')
|
||||
# Not Empty XHTML test
|
||||
self.assertEqual(XHTML('<>', _a='1', _b='2').xml(),
|
||||
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n<html a="1" b="2" lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml"><></html>')
|
||||
self.assertEqual(XHTML('<>', _a='1', _b='2', doctype='').xml(),
|
||||
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n<html a="1" b="2" lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml"><></html>')
|
||||
self.assertEqual(XHTML('<>', _a='1', _b='2', doctype='strict').xml(),
|
||||
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n<html a="1" b="2" lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml"><></html>')
|
||||
self.assertEqual(XHTML('<>', _a='1', _b='2', doctype='transitional').xml(),
|
||||
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n<html a="1" b="2" lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml"><></html>')
|
||||
self.assertEqual(XHTML('<>', _a='1', _b='2', doctype='frameset').xml(),
|
||||
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">\n<html a="1" b="2" lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml"><></html>')
|
||||
self.assertEqual(XHTML('<>', _a='1', _b='2', doctype='xmlns').xml(),
|
||||
'xmlns\n<html a="1" b="2" lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml"><></html>')
|
||||
|
||||
def test_HEAD(self):
|
||||
self.assertEqual(HEAD('<>', _a='1', _b='2').xml(),
|
||||
'<head a="1" b="2"><></head>')
|
||||
|
||||
def test_TITLE(self):
|
||||
self.assertEqual(TITLE('<>', _a='1', _b='2').xml(),
|
||||
'<title a="1" b="2"><></title>')
|
||||
|
||||
def test_META(self):
|
||||
self.assertEqual(META(_a='1', _b='2').xml(),
|
||||
'<meta a="1" b="2" />')
|
||||
|
||||
def test_LINK(self):
|
||||
self.assertEqual(LINK(_a='1', _b='2').xml(),
|
||||
'<link a="1" b="2" />')
|
||||
|
||||
def test_SCRIPT(self):
|
||||
self.assertEqual(SCRIPT('<>', _a='1', _b='2').xml(),
|
||||
'''<script a="1" b="2"><!--
|
||||
<>
|
||||
//--></script>''')
|
||||
self.assertEqual(SCRIPT('<>').xml(),
|
||||
'''<script><!--
|
||||
<>
|
||||
//--></script>''')
|
||||
self.assertEqual(SCRIPT().xml(), '<script></script>')
|
||||
|
||||
def test_STYLE(self):
|
||||
self.assertEqual(STYLE('<>', _a='1', _b='2').xml(),
|
||||
'<style a="1" b="2"><!--/*--><![CDATA[/*><!--*/\n<>\n/*]]>*/--></style>')
|
||||
|
||||
def test_IMG(self):
|
||||
self.assertEqual(IMG(_a='1', _b='2').xml(),
|
||||
'<img a="1" b="2" />')
|
||||
|
||||
def test_SPAN(self):
|
||||
self.assertEqual(SPAN('<>', _a='1', _b='2').xml(),
|
||||
'<span a="1" b="2"><></span>')
|
||||
|
||||
def test_BODY(self):
|
||||
self.assertEqual(BODY('<>', _a='1', _b='2').xml(),
|
||||
'<body a="1" b="2"><></body>')
|
||||
|
||||
def test_H1(self):
|
||||
self.assertEqual(H1('<>', _a='1', _b='2').xml(),
|
||||
'<h1 a="1" b="2"><></h1>')
|
||||
|
||||
def test_H2(self):
|
||||
self.assertEqual(H2('<>', _a='1', _b='2').xml(),
|
||||
'<h2 a="1" b="2"><></h2>')
|
||||
|
||||
def test_H3(self):
|
||||
self.assertEqual(H3('<>', _a='1', _b='2').xml(),
|
||||
'<h3 a="1" b="2"><></h3>')
|
||||
|
||||
def test_H4(self):
|
||||
self.assertEqual(H4('<>', _a='1', _b='2').xml(),
|
||||
'<h4 a="1" b="2"><></h4>')
|
||||
|
||||
def test_H5(self):
|
||||
self.assertEqual(H5('<>', _a='1', _b='2').xml(),
|
||||
'<h5 a="1" b="2"><></h5>')
|
||||
|
||||
def test_H6(self):
|
||||
self.assertEqual(H6('<>', _a='1', _b='2').xml(),
|
||||
'<h6 a="1" b="2"><></h6>')
|
||||
|
||||
def test_P(self):
|
||||
self.assertEqual(P('<>', _a='1', _b='2').xml(),
|
||||
'<p a="1" b="2"><></p>')
|
||||
# test cr2br
|
||||
self.assertEqual(P('a\nb').xml(), '<p>a\nb</p>')
|
||||
self.assertEqual(P('a\nb', cr2br=True).xml(), '<p>a<br />b</p>')
|
||||
|
||||
def test_STRONG(self):
|
||||
self.assertEqual(STRONG('<>', _a='1', _b='2').xml(),
|
||||
'<strong a="1" b="2"><></strong>')
|
||||
|
||||
def test_B(self):
|
||||
self.assertEqual(B('<>', _a='1', _b='2').xml(),
|
||||
'<b a="1" b="2"><></b>')
|
||||
|
||||
def test_BR(self):
|
||||
# empty BR()
|
||||
self.assertEqual(BR().xml(), '<br />')
|
||||
self.assertEqual(BR(_a='1', _b='2').xml(), '<br a="1" b="2" />')
|
||||
|
||||
def test_HR(self):
|
||||
self.assertEqual(HR(_a='1', _b='2').xml(), '<hr a="1" b="2" />')
|
||||
|
||||
def test_A(self):
|
||||
self.assertEqual(
|
||||
A('<>', _a='1', _b='2').xml(),
|
||||
'<a a="1" b="2"><></a>'
|
||||
)
|
||||
self.assertEqual(
|
||||
A('a', cid='b').xml(),
|
||||
'<a data-w2p_disable_with="default" data-w2p_method="GET" data-w2p_target="b">a</a>'
|
||||
)
|
||||
self.assertEqual(
|
||||
A('a', callback='b', _id='c').xml(),
|
||||
'<a data-w2p_disable_with="default" data-w2p_method="POST" href="b" id="c">a</a>'
|
||||
)
|
||||
# Callback with no id trigger web2py_uuid() call
|
||||
from html import web2pyHTMLParser
|
||||
a = A('a', callback='b').xml()
|
||||
for tag in web2pyHTMLParser(a).tree.elements('a'):
|
||||
uuid_generated = tag.attributes['_id']
|
||||
self.assertEqual(a,
|
||||
'<a data-w2p_disable_with="default" data-w2p_method="POST" href="b" id="{id}">a</a>'.format(id=uuid_generated))
|
||||
self.assertEqual(
|
||||
A('a', delete='tr').xml(),
|
||||
'<a data-w2p_disable_with="default" data-w2p_remove="tr">a</a>'
|
||||
)
|
||||
self.assertEqual(
|
||||
A('a', _id='b', target='<self>').xml(),
|
||||
'<a data-w2p_disable_with="default" data-w2p_target="b" id="b">a</a>'
|
||||
)
|
||||
self.assertEqual(
|
||||
A('a', component='b').xml(),
|
||||
'<a data-w2p_disable_with="default" data-w2p_method="GET" href="b">a</a>'
|
||||
)
|
||||
self.assertEqual(
|
||||
A('a', _id='b', callback='c', noconfirm=True).xml(),
|
||||
'<a data-w2p_disable_with="default" data-w2p_method="POST" href="c" id="b">a</a>'
|
||||
)
|
||||
self.assertEqual(
|
||||
A('a', cid='b').xml(),
|
||||
'<a data-w2p_disable_with="default" data-w2p_method="GET" data-w2p_target="b">a</a>'
|
||||
)
|
||||
self.assertEqual(
|
||||
A('a', cid='b', _disable_with='processing...').xml(),
|
||||
'<a data-w2p_disable_with="processing..." data-w2p_method="GET" data-w2p_target="b">a</a>'
|
||||
)
|
||||
self.assertEqual(
|
||||
A('a', callback='b', delete='tr', noconfirm=True, _id='c').xml(),
|
||||
'<a data-w2p_disable_with="default" data-w2p_method="POST" data-w2p_remove="tr" href="b" id="c">a</a>'
|
||||
)
|
||||
self.assertEqual(
|
||||
A('a', callback='b', delete='tr', confirm='Are you sure?', _id='c').xml(),
|
||||
'<a data-w2p_confirm="Are you sure?" data-w2p_disable_with="default" data-w2p_method="POST" data-w2p_remove="tr" href="b" id="c">a</a>'
|
||||
)
|
||||
|
||||
def test_BUTTON(self):
|
||||
self.assertEqual(BUTTON('test', _type='button').xml(),
|
||||
'<button type="button">test</button>')
|
||||
|
||||
def test_EM(self):
|
||||
self.assertEqual(EM('<>', _a='1', _b='2').xml(),
|
||||
'<em a="1" b="2"><></em>')
|
||||
|
||||
def test_EMBED(self):
|
||||
self.assertEqual(EMBED(_a='1', _b='2').xml(),
|
||||
'<embed a="1" b="2" />')
|
||||
|
||||
def test_TT(self):
|
||||
self.assertEqual(TT('<>', _a='1', _b='2').xml(),
|
||||
'<tt a="1" b="2"><></tt>')
|
||||
|
||||
def test_PRE(self):
|
||||
self.assertEqual(PRE('<>', _a='1', _b='2').xml(),
|
||||
'<pre a="1" b="2"><></pre>')
|
||||
|
||||
def test_CENTER(self):
|
||||
self.assertEqual(CENTER('<>', _a='1', _b='2').xml(),
|
||||
'<center a="1" b="2"><></center>')
|
||||
|
||||
def test_CODE(self):
|
||||
self.assertEqual(CODE("print 'hello world'",
|
||||
language='python',
|
||||
link=None,
|
||||
counter=1,
|
||||
styles={},
|
||||
highlight_line=None).xml(),
|
||||
'<table><tr style="vertical-align:top;"><td style="min-width:40px; text-align: right;"><pre style="\n font-size: 11px;\n font-family: Bitstream Vera Sans Mono,monospace;\n background-color: transparent;\n margin: 0;\n padding: 5px;\n border: none;\n color: #A0A0A0;\n">1.</pre></td><td><pre style="\n font-size: 11px;\n font-family: Bitstream Vera Sans Mono,monospace;\n background-color: transparent;\n margin: 0;\n padding: 5px;\n border: none;\n overflow: auto;\n white-space: pre !important;\n"><span style="color:#185369; font-weight: bold">print </span><span style="color: #FF9966">\'hello world\'</span></pre></td></tr></table>')
|
||||
|
||||
def test_LABEL(self):
|
||||
self.assertEqual(LABEL('<>', _a='1', _b='2').xml(),
|
||||
'<label a="1" b="2"><></label>')
|
||||
|
||||
def test_LI(self):
|
||||
self.assertEqual(LI('<>', _a='1', _b='2').xml(),
|
||||
'<li a="1" b="2"><></li>')
|
||||
|
||||
def test_UL(self):
|
||||
self.assertEqual(UL('<>', _a='1', _b='2').xml(),
|
||||
'<ul a="1" b="2"><li><></li></ul>')
|
||||
|
||||
def test_OL(self):
|
||||
self.assertEqual(OL('<>', _a='1', _b='2').xml(),
|
||||
'<ol a="1" b="2"><li><></li></ol>')
|
||||
|
||||
def test_TD(self):
|
||||
self.assertEqual(TD('<>', _a='1', _b='2').xml(),
|
||||
'<td a="1" b="2"><></td>')
|
||||
|
||||
def test_TH(self):
|
||||
self.assertEqual(TH('<>', _a='1', _b='2').xml(),
|
||||
'<th a="1" b="2"><></th>')
|
||||
|
||||
def test_TR(self):
|
||||
self.assertEqual(TR('<>', _a='1', _b='2').xml(),
|
||||
'<tr a="1" b="2"><td><></td></tr>')
|
||||
|
||||
def test_THEAD(self):
|
||||
self.assertEqual(THEAD('<>', _a='1', _b='2').xml(),
|
||||
'<thead a="1" b="2"><tr><th><></th></tr></thead>')
|
||||
# self.assertEqual(THEAD(TRHEAD('<>'), _a='1', _b='2').xml(),
|
||||
# '<thead a="1" b="2"><tr><th><></th></tr></thead>')
|
||||
self.assertEqual(THEAD(TR('<>'), _a='1', _b='2').xml(),
|
||||
'<thead a="1" b="2"><tr><td><></td></tr></thead>')
|
||||
|
||||
def test_TBODY(self):
|
||||
self.assertEqual(TBODY('<>', _a='1', _b='2').xml(),
|
||||
'<tbody a="1" b="2"><tr><td><></td></tr></tbody>')
|
||||
|
||||
def test_TFOOT(self):
|
||||
self.assertEqual(TFOOT('<>', _a='1', _b='2').xml(),
|
||||
'<tfoot a="1" b="2"><tr><td><></td></tr></tfoot>')
|
||||
|
||||
def test_COL(self):
|
||||
# Empty COL test
|
||||
self.assertEqual(COL().xml(), '<col />')
|
||||
# Not Empty COL test
|
||||
self.assertEqual(COL(_span='2').xml(), '<col span="2" />')
|
||||
# Commented for now not so sure how to make it pass properly was passing locally
|
||||
# I think this test is interesting and add value
|
||||
# This fail relate to python 2.6 limitation I think
|
||||
# Failing COL test
|
||||
# with self.assertRaises(SyntaxError) as cm:
|
||||
# COL('<>').xml()
|
||||
# self.assertEqual(cm.exception[0], '<col/> tags cannot have components')
|
||||
# For now
|
||||
self.assertRaises(SyntaxError, COL, '<>')
|
||||
|
||||
def test_COLGROUP(self):
|
||||
# Empty COLGROUP test
|
||||
self.assertEqual(COLGROUP().xml(), '<colgroup></colgroup>')
|
||||
# Not Empty COLGROUP test
|
||||
self.assertEqual(COLGROUP('<>', _a='1', _b='2').xml(), '<colgroup a="1" b="2"><></colgroup>')
|
||||
|
||||
def test_TABLE(self):
|
||||
self.assertEqual(TABLE('<>', _a='1', _b='2').xml(),
|
||||
'<table a="1" b="2"><tr><td><></td></tr>' +
|
||||
'</table>')
|
||||
|
||||
def test_I(self):
|
||||
self.assertEqual(I('<>', _a='1', _b='2').xml(),
|
||||
'<i a="1" b="2"><></i>')
|
||||
|
||||
def test_IFRAME(self):
|
||||
self.assertEqual(IFRAME('<>', _a='1', _b='2').xml(),
|
||||
'<iframe a="1" b="2"><></iframe>')
|
||||
|
||||
def test_INPUT(self):
|
||||
self.assertEqual(INPUT(_a='1', _b='2').xml(),
|
||||
'<input a="1" b="2" type="text" />')
|
||||
|
||||
def test_TEXTAREA(self):
|
||||
self.assertEqual(TEXTAREA('<>', _a='1', _b='2').xml(),
|
||||
'<textarea a="1" b="2" cols="40" rows="10"><>' +
|
||||
'</textarea>')
|
||||
# override _rows and _cols
|
||||
self.assertEqual(TEXTAREA('<>', _a='1', _b='2', _rows=5, _cols=20).xml(),
|
||||
'<textarea a="1" b="2" cols="20" rows="5"><>' +
|
||||
'</textarea>')
|
||||
self.assertEqual(TEXTAREA('<>', value='bla bla bla...', _rows=10, _cols=40).xml(),
|
||||
'<textarea cols="40" rows="10">bla bla bla...</textarea>')
|
||||
|
||||
def test_OPTION(self):
|
||||
self.assertEqual(OPTION('<>', _a='1', _b='2').xml(),
|
||||
'<option a="1" b="2" value="<>"><>' +
|
||||
'</option>')
|
||||
|
||||
def test_OBJECT(self):
|
||||
self.assertEqual(OBJECT('<>', _a='1', _b='2').xml(),
|
||||
'<object a="1" b="2"><></object>')
|
||||
|
||||
def test_OPTGROUP(self):
|
||||
# Empty OPTGROUP test
|
||||
self.assertEqual(OPTGROUP().xml(),
|
||||
'<optgroup></optgroup>')
|
||||
# Not Empty OPTGROUP test
|
||||
self.assertEqual(OPTGROUP('<>', _a='1', _b='2').xml(),
|
||||
'<optgroup a="1" b="2"><option value="<>"><></option></optgroup>')
|
||||
# With an OPTION
|
||||
self.assertEqual(OPTGROUP(OPTION('Option 1', _value='1'), _label='Group 1').xml(),
|
||||
'<optgroup label="Group 1"><option value="1">Option 1</option></optgroup>')
|
||||
|
||||
def test_SELECT(self):
|
||||
self.assertEqual(SELECT('<>', _a='1', _b='2').xml(),
|
||||
'<select a="1" b="2">' +
|
||||
'<option value="<>"><></option></select>')
|
||||
self.assertEqual(SELECT(OPTION('option 1', _value='1'),
|
||||
OPTION('option 2', _value='2')).xml(),
|
||||
'<select><option value="1">option 1</option><option value="2">option 2</option></select>')
|
||||
self.assertEqual(SELECT(OPTION('option 1', _value='1', _selected='selected'),
|
||||
OPTION('option 2', _value='2'),
|
||||
_multiple='multiple').xml(),
|
||||
'<select multiple="multiple"><option selected="selected" value="1">option 1</option><option value="2">option 2</option></select>')
|
||||
# OPTGROUP
|
||||
self.assertEqual(SELECT(OPTGROUP(OPTION('option 1', _value='1'),
|
||||
OPTION('option 2', _value='2'),
|
||||
_label='Group 1',)).xml(),
|
||||
'<select><optgroup label="Group 1"><option value="1">option 1</option><option value="2">option 2</option></optgroup></select>')
|
||||
# List
|
||||
self.assertEqual(SELECT([1, 2, 3, 4, 5]).xml(),
|
||||
'<select><option value="1">1</option><option value="2">2</option><option value="3">3</option><option value="4">4</option><option value="5">5</option></select>')
|
||||
# Tuple
|
||||
self.assertEqual(SELECT((1, 2, 3, 4, 5)).xml(),
|
||||
'<select><option value="1">1</option><option value="2">2</option><option value="3">3</option><option value="4">4</option><option value="5">5</option></select>')
|
||||
# String value
|
||||
self.assertEqual(SELECT('Option 1', 'Option 2').xml(),
|
||||
'<select><option value="Option 1">Option 1</option><option value="Option 2">Option 2</option></select>')
|
||||
|
||||
def test_FIELDSET(self):
|
||||
self.assertEqual(FIELDSET('<>', _a='1', _b='2').xml(),
|
||||
'<fieldset a="1" b="2"><></fieldset>')
|
||||
|
||||
def test_LEGEND(self):
|
||||
self.assertEqual(LEGEND('<>', _a='1', _b='2').xml(),
|
||||
'<legend a="1" b="2"><></legend>')
|
||||
|
||||
def test_FORM(self):
|
||||
self.assertEqual(FORM('<>', _a='1', _b='2').xml(),
|
||||
'<form a="1" action="#" b="2" enctype="multipart/form-data" method="post"><></form>')
|
||||
|
||||
def test_BEAUTIFY(self):
|
||||
self.assertEqual(BEAUTIFY(['a', 'b', {'hello': 'world'}]).xml(),
|
||||
'<div><table><tr><td><div>a</div></td></tr><tr><td><div>b</div></td></tr><tr><td><div><table><tr><td style="font-weight:bold;vertical-align:top;">hello</td><td style="vertical-align:top;">:</td><td><div>world</div></td></tr></table></div></td></tr></table></div>')
|
||||
|
||||
def test_MENU(self):
|
||||
self.assertEqual(MENU([('Home', False, '/welcome/default/index', [])]).xml(),
|
||||
'<ul class="web2py-menu web2py-menu-vertical"><li class="web2py-menu-first"><a href="/welcome/default/index">Home</a></li></ul>')
|
||||
# mobile=True
|
||||
self.assertEqual(MENU([('Home', False, '/welcome/default/index', [])], mobile=True).xml(),
|
||||
'<select class="web2py-menu web2py-menu-vertical" onchange="window.location=this.value"><option value="/welcome/default/index">Home</option></select>')
|
||||
|
||||
# TODO: def test_embed64(self):
|
||||
|
||||
# TODO: def test_web2pyHTMLParser(self):
|
||||
|
||||
# TODO: def test_markdown_serializer(self):
|
||||
|
||||
# TODO: def test_markmin_serializer(self):
|
||||
|
||||
def test_MARKMIN(self):
|
||||
# This test pass with python 2.7 but expected to fail under 2.6
|
||||
# with self.assertRaises(TypeError) as cm:
|
||||
# MARKMIN().xml()
|
||||
# self.assertEqual(cm.exception[0], '__init__() takes at least 2 arguments (1 given)')
|
||||
# For now
|
||||
self.assertRaises(TypeError, MARKMIN)
|
||||
self.assertEqual(MARKMIN('').xml(), '')
|
||||
self.assertEqual(MARKMIN('<>').xml(),
|
||||
'<p><></p>')
|
||||
self.assertEqual(MARKMIN("``hello_world = 'Hello World!'``:python").xml(),
|
||||
'<code class="python">hello_world = \'Hello World!\'</code>')
|
||||
self.assertEqual(MARKMIN('<>').flatten(), '<>')
|
||||
|
||||
def test_ASSIGNJS(self):
|
||||
# empty assignation
|
||||
self.assertEqual(ASSIGNJS().xml(), '')
|
||||
# text assignation
|
||||
self.assertEqual(ASSIGNJS(var1='1', var2='2').xml(), 'var var1 = "1";\nvar var2 = "2";\n')
|
||||
# int assignation
|
||||
self.assertEqual(ASSIGNJS(var1=1, var2=2).xml(), 'var var1 = 1;\nvar var2 = 2;\n')
|
||||
|
||||
|
||||
class TestData(unittest.TestCase):
|
||||
|
||||
def testAdata(self):
|
||||
def test_Adata(self):
|
||||
self.assertEqual(A('<>', data=dict(abc='<def?asd>', cde='standard'), _a='1', _b='2').xml(),
|
||||
'<a a="1" b="2" data-abc="<def?asd>" data-cde="standard"><></a>')
|
||||
'<a a="1" b="2" data-abc="<def?asd>" data-cde="standard"><></a>')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# TODO : I think we should continue to use pathoc (http://pathod.net/docs/pathoc) for tests but integrate the call in
|
||||
# gluon/tests so they run automatically. No need to make our own tests.
|
||||
# ref: https://groups.google.com/d/msg/web2py-developers/Cjye8_hXZk8/AXbftS3sCgAJ
|
||||
+141
-2
@@ -6,6 +6,7 @@
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import smtplib
|
||||
if sys.version < "2.7":
|
||||
import unittest2 as unittest
|
||||
else:
|
||||
@@ -19,7 +20,7 @@ DEFAULT_URI = os.getenv('DB', 'sqlite:memory')
|
||||
|
||||
from gluon.dal import DAL, Field
|
||||
from pydal.objects import Table
|
||||
from tools import Auth
|
||||
from tools import Auth, Mail
|
||||
from gluon.globals import Request, Response, Session
|
||||
from storage import Storage
|
||||
from languages import translator
|
||||
@@ -29,7 +30,7 @@ python_version = sys.version[:3]
|
||||
IS_IMAP = "imap" in DEFAULT_URI
|
||||
|
||||
@unittest.skipIf(IS_IMAP, "TODO: Imap raises 'Connection refused'")
|
||||
class testAuth(unittest.TestCase):
|
||||
class TestAuth(unittest.TestCase):
|
||||
|
||||
def testRun(self):
|
||||
# setup
|
||||
@@ -79,5 +80,143 @@ class testAuth(unittest.TestCase):
|
||||
pass
|
||||
return
|
||||
|
||||
|
||||
class TestMail(unittest.TestCase):
|
||||
"""
|
||||
Test the Mail class.
|
||||
"""
|
||||
|
||||
class Message(object):
|
||||
def __init__(self, sender, to, payload):
|
||||
self.sender = sender
|
||||
self.to = to
|
||||
self.payload = payload
|
||||
|
||||
class DummySMTP(object):
|
||||
"""
|
||||
Dummy smtp server
|
||||
|
||||
NOTE: Test methods should take care of always leaving inbox and users empty when they finish.
|
||||
"""
|
||||
inbox = []
|
||||
users = {}
|
||||
|
||||
def __init__(self, address, port, **kwargs):
|
||||
self.address=address
|
||||
self.port = port
|
||||
self.has_quit = False
|
||||
self.tls = False
|
||||
|
||||
def login(self, username, password):
|
||||
if username not in self.users or self.users[username] != password:
|
||||
raise smtplib.SMTPAuthenticationError
|
||||
self.username=username
|
||||
self.password=password
|
||||
|
||||
def sendmail(self, sender, to, payload):
|
||||
self.inbox.append(TestMail.Message(sender, to, payload))
|
||||
|
||||
def quit(self):
|
||||
self.has_quit=True
|
||||
|
||||
def ehlo(self, hostname=None):
|
||||
pass
|
||||
|
||||
def starttls(self):
|
||||
self.tls = True
|
||||
|
||||
|
||||
def setUp(self):
|
||||
self.original_SMTP = smtplib.SMTP
|
||||
self.original_SMTP_SSL = smtplib.SMTP_SSL
|
||||
smtplib.SMTP = TestMail.DummySMTP
|
||||
smtplib.SMTP_SSL = TestMail.DummySMTP
|
||||
|
||||
def tearDown(self):
|
||||
smtplib.SMTP = self.original_SMTP
|
||||
smtplib.SMTP_SSL = self.original_SMTP_SSL
|
||||
|
||||
def test_hello_world(self):
|
||||
mail = Mail()
|
||||
mail.settings.server = 'smtp.example.com:25'
|
||||
mail.settings.sender = 'you@example.com'
|
||||
self.assertTrue(mail.send(to=['somebody@example.com'],
|
||||
subject='hello',
|
||||
# If reply_to is omitted, then mail.settings.sender is used
|
||||
reply_to='us@example.com',
|
||||
message='world'))
|
||||
message = TestMail.DummySMTP.inbox.pop()
|
||||
self.assertEqual(message.sender, mail.settings.sender)
|
||||
self.assertEqual(message.to, ['somebody@example.com'])
|
||||
header = "To: somebody@example.com\nReply-To: us@example.com\nSubject: hello\n"
|
||||
self.assertTrue(header in message.payload)
|
||||
self.assertTrue(message.payload.endswith('world'))
|
||||
|
||||
def test_failed_login(self):
|
||||
mail = Mail()
|
||||
mail.settings.server = 'smtp.example.com:25'
|
||||
mail.settings.sender = 'you@example.com'
|
||||
mail.settings.login = 'username:password'
|
||||
self.assertFalse(mail.send(to=['somebody@example.com'],
|
||||
subject='hello',
|
||||
# If reply_to is omitted, then mail.settings.sender is used
|
||||
reply_to='us@example.com',
|
||||
message='world'))
|
||||
|
||||
def test_login(self):
|
||||
TestMail.DummySMTP.users['username'] = 'password'
|
||||
mail = Mail()
|
||||
mail.settings.server = 'smtp.example.com:25'
|
||||
mail.settings.sender = 'you@example.com'
|
||||
mail.settings.login = 'username:password'
|
||||
self.assertTrue(mail.send(to=['somebody@example.com'],
|
||||
subject='hello',
|
||||
# If reply_to is omitted, then mail.settings.sender is used
|
||||
reply_to='us@example.com',
|
||||
message='world'))
|
||||
del TestMail.DummySMTP.users['username']
|
||||
TestMail.DummySMTP.inbox.pop()
|
||||
|
||||
def test_html(self):
|
||||
mail = Mail()
|
||||
mail.settings.server = 'smtp.example.com:25'
|
||||
mail.settings.sender = 'you@example.com'
|
||||
self.assertTrue(mail.send(to=['somebody@example.com'],
|
||||
subject='hello',
|
||||
# If reply_to is omitted, then mail.settings.sender is used
|
||||
reply_to='us@example.com',
|
||||
message='<html><head></head><body></body></html>'))
|
||||
message = TestMail.DummySMTP.inbox.pop()
|
||||
self.assertTrue('Content-Type: text/html' in message.payload)
|
||||
|
||||
def test_ssl(self):
|
||||
mail = Mail()
|
||||
mail.settings.server = 'smtp.example.com:25'
|
||||
mail.settings.sender = 'you@example.com'
|
||||
mail.settings.ssl = True
|
||||
self.assertTrue(mail.send(to=['somebody@example.com'],
|
||||
subject='hello',
|
||||
# If reply_to is omitted, then mail.settings.sender is used
|
||||
reply_to='us@example.com',
|
||||
message='world'))
|
||||
TestMail.DummySMTP.inbox.pop()
|
||||
|
||||
def test_tls(self):
|
||||
mail = Mail()
|
||||
mail.settings.server = 'smtp.example.com:25'
|
||||
mail.settings.sender = 'you@example.com'
|
||||
mail.settings.tls = True
|
||||
self.assertTrue(mail.send(to=['somebody@example.com'],
|
||||
subject='hello',
|
||||
# If reply_to is omitted, then mail.settings.sender is used
|
||||
reply_to='us@example.com',
|
||||
message='world'))
|
||||
TestMail.DummySMTP.inbox.pop()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
+72
-12
@@ -10,6 +10,8 @@ fix_sys_path(__file__)
|
||||
|
||||
from utils import md5_hash
|
||||
from utils import compare
|
||||
from utils import is_valid_ip_address
|
||||
from utils import web2py_uuid
|
||||
|
||||
import hashlib
|
||||
from hashlib import md5, sha1, sha224, sha256, sha384, sha512
|
||||
@@ -19,11 +21,7 @@ from utils import simple_hash, get_digest, secure_dumps, secure_loads
|
||||
class TestUtils(unittest.TestCase):
|
||||
""" Tests the utils.py module """
|
||||
|
||||
def test_md5_hash(self):
|
||||
""" Tests the md5_hash function """
|
||||
|
||||
data = md5_hash("web2py rocks")
|
||||
self.assertEqual(data, '79509f3246a2824dee64635303e99204')
|
||||
# TODO: def test_AES_new(self):
|
||||
|
||||
def test_compare(self):
|
||||
""" Tests the compare funciton """
|
||||
@@ -36,35 +34,62 @@ class TestUtils(unittest.TestCase):
|
||||
compare_result_false = compare(a, b)
|
||||
self.assertFalse(compare_result_false)
|
||||
|
||||
def test_md5_hash(self):
|
||||
""" Tests the md5_hash function """
|
||||
|
||||
data = md5_hash("web2py rocks")
|
||||
self.assertEqual(data, '79509f3246a2824dee64635303e99204')
|
||||
|
||||
def test_simple_hash(self):
|
||||
""" Tests the simple_hash function """
|
||||
|
||||
# no key, no salt, md5
|
||||
# no key, no salt, digest_alg=None
|
||||
self.assertRaises(RuntimeError, simple_hash, 'web2py rocks!', key='', salt='', digest_alg=None)
|
||||
|
||||
# no key, no salt, digest_alg = md5
|
||||
data_md5 = simple_hash('web2py rocks!', key='', salt='', digest_alg=md5)
|
||||
self.assertEqual(data_md5, '37d95defba6c8834cb8cae86ee888568')
|
||||
|
||||
# no key, no salt, 'md5'
|
||||
data_md5 = simple_hash('web2py rocks!', key='', salt='', digest_alg='md5')
|
||||
self.assertEqual(data_md5, '37d95defba6c8834cb8cae86ee888568')
|
||||
|
||||
# no key, no salt, sha1
|
||||
# no key, no salt, 'sha1'
|
||||
data_sha1 = simple_hash('web2py rocks!', key='', salt='', digest_alg='sha1')
|
||||
self.assertEqual(data_sha1, '00489a46753d8db260c71542611cdef80652c4b7')
|
||||
|
||||
# no key, no salt, sha224
|
||||
# no key, no salt, 'sha224'
|
||||
data_sha224 = simple_hash('web2py rocks!', key='', salt='', digest_alg='sha224')
|
||||
self.assertEqual(data_sha224, '84d7054271842c2c17983baa2b1447e0289d101140a8c002d49d60da')
|
||||
|
||||
# no key, no salt, sha256
|
||||
# no key, no salt, 'sha256'
|
||||
data_sha256 = simple_hash('web2py rocks!', key='', salt='', digest_alg='sha256')
|
||||
self.assertEqual(data_sha256, '0849f224d8deb267e4598702aaec1bd749e6caec90832469891012a4be24af08')
|
||||
|
||||
# no key, no salt, sha384
|
||||
# no key, no salt, 'sha384'
|
||||
data_sha384 = simple_hash('web2py rocks!', key='', salt='', digest_alg='sha384')
|
||||
self.assertEqual(data_sha384,
|
||||
'3cffaf39371adbe84eb10f588d2718207d8e965e9172a27a278321b86977351376ae79f92e91d8c58cad86c491282d5f')
|
||||
'3cffaf39371adbe84eb10f588d2718207d8e965e9172a27a278321b86977351376ae79f92e91d8c58cad86c491282d5f')
|
||||
|
||||
# no key, no salt, sha512
|
||||
# no key, no salt, 'sha512'
|
||||
data_sha512 = simple_hash('web2py rocks!', key='', salt='', digest_alg='sha512')
|
||||
self.assertEqual(data_sha512, 'fa3237f594743e1d7b6c800bb134b3255cf4a98ab8b01e2ec23256328c9f8059'
|
||||
'64fdef25a038d6cc3fda1b2fb45d66461eeed5c4669e506ec8bdfee71348db7e')
|
||||
|
||||
# NOTE : get_digest() is covered by simple_hash tests above except raise error...
|
||||
def test_get_digest(self):
|
||||
# Bad algorithm
|
||||
# Option 1, think not working with python 2.6
|
||||
# with self.assertRaises(ValueError) as cm:
|
||||
# get_digest('123')
|
||||
# self.assertEqual(cm.exception[0], 'Invalid digest algorithm: 123')
|
||||
# Option 2
|
||||
self.assertRaises(ValueError, get_digest, '123')
|
||||
|
||||
# TODO: def test_get_callable_argspec(self):
|
||||
|
||||
# TODO: def test_pad(self):
|
||||
|
||||
def test_secure_dumps_and_loads(self):
|
||||
""" Tests secure_dumps and secure_loads"""
|
||||
testobj = {'a': 1, 'b': 2}
|
||||
@@ -96,5 +121,40 @@ class TestUtils(unittest.TestCase):
|
||||
wrong4 = secure_loads('abc', 'a', 'b')
|
||||
self.assertEqual(wrong4, None)
|
||||
|
||||
# TODO: def test_initialize_urandom(self):
|
||||
|
||||
# TODO: def test_fast_urandom16(self):
|
||||
|
||||
def test_web2py_uuid(self):
|
||||
from uuid import UUID
|
||||
self.assertTrue(UUID(web2py_uuid()))
|
||||
|
||||
def test_is_valid_ip_address(self):
|
||||
# IPv4
|
||||
# False
|
||||
# self.assertEqual(is_valid_ip_address('127.0'), False) # Fail with AppVeyor?? should pass
|
||||
self.assertEqual(is_valid_ip_address('unknown'), False)
|
||||
self.assertEqual(is_valid_ip_address(''), False)
|
||||
# True
|
||||
self.assertEqual(is_valid_ip_address('127.0.0.1'), True)
|
||||
self.assertEqual(is_valid_ip_address('localhost'), True)
|
||||
self.assertEqual(is_valid_ip_address('::1'), True)
|
||||
# IPv6
|
||||
# True
|
||||
# Compressed
|
||||
self.assertEqual(is_valid_ip_address('::ffff:7f00:1'), True) # IPv6 127.0.0.1 compressed
|
||||
self.assertEqual(is_valid_ip_address('2001:660::1'), True)
|
||||
# Expanded
|
||||
self.assertEqual(is_valid_ip_address('0:0:0:0:0:ffff:7f00:1'), True) # IPv6 127.0.0.1 expanded
|
||||
self.assertEqual(is_valid_ip_address('2607:fa48:6d50:69f1:21f:3cff:fe9d:9be3'), True) # Any address
|
||||
# False
|
||||
# self.assertEqual(is_valid_ip_address('2607:fa48:6d50:69f1:21f:3cff:fe9d:'), False) # Any address with mistake
|
||||
# The above pass locally but fail with AppVeyor
|
||||
|
||||
# TODO: def test_is_loopback_ip_address(self):
|
||||
|
||||
# TODO: def test_getipaddrinfo(self):
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
+717
-531
File diff suppressed because it is too large
Load Diff
+11
-9
@@ -22,20 +22,21 @@ from urllib2 import HTTPError
|
||||
|
||||
webserverprocess = None
|
||||
|
||||
|
||||
def startwebserver():
|
||||
global webserverprocess
|
||||
path = path = os.path.dirname(os.path.abspath(__file__))
|
||||
if not os.path.isfile(os.path.join(path,'web2py.py')):
|
||||
if not os.path.isfile(os.path.join(path, 'web2py.py')):
|
||||
i = 0
|
||||
while i<10:
|
||||
while i < 10:
|
||||
i += 1
|
||||
if os.path.exists(os.path.join(path,'web2py.py')):
|
||||
if os.path.exists(os.path.join(path, 'web2py.py')):
|
||||
break
|
||||
path = os.path.abspath(os.path.join(path, '..'))
|
||||
web2py_exec = os.path.join(path, 'web2py.py')
|
||||
webserverprocess = subprocess.Popen([sys.executable, web2py_exec, '-a', 'testpass'])
|
||||
print 'Sleeping before web2py starts...'
|
||||
for a in range(1,11):
|
||||
for a in range(1, 11):
|
||||
time.sleep(1)
|
||||
print a, '...'
|
||||
try:
|
||||
@@ -46,10 +47,11 @@ def startwebserver():
|
||||
continue
|
||||
print ''
|
||||
|
||||
|
||||
def terminate_process(pid):
|
||||
#Taken from http://stackoverflow.com/questions/1064335/in-python-2-5-how-do-i-kill-a-subprocess
|
||||
# Taken from http://stackoverflow.com/questions/1064335/in-python-2-5-how-do-i-kill-a-subprocess
|
||||
# all this **blah** is because we are stuck with Python 2.5 and \
|
||||
#we cannot use Popen.terminate()
|
||||
# we cannot use Popen.terminate()
|
||||
if sys.platform.startswith('win'):
|
||||
import ctypes
|
||||
PROCESS_TERMINATE = 1
|
||||
@@ -59,10 +61,11 @@ def terminate_process(pid):
|
||||
else:
|
||||
os.kill(pid, signal.SIGKILL)
|
||||
|
||||
|
||||
def stopwebserver():
|
||||
global webserverprocess
|
||||
print 'Killing webserver'
|
||||
if sys.version_info < (2,6):
|
||||
if sys.version_info < (2, 6):
|
||||
terminate_process(webserverprocess.pid)
|
||||
else:
|
||||
webserverprocess.terminate()
|
||||
@@ -108,7 +111,6 @@ class TestWeb(LiveTest):
|
||||
# check registration and login were successful
|
||||
client.get('index')
|
||||
|
||||
# COMMENTED BECAUSE FAILS BUT WHY?
|
||||
self.assertTrue('Welcome Homer' in client.text)
|
||||
|
||||
client = WebClient('http://127.0.0.1:8000/admin/default/')
|
||||
@@ -153,7 +155,7 @@ class TestWeb(LiveTest):
|
||||
try:
|
||||
s.post('examples/soap_examples/call/soap', data=xml_request, method="POST")
|
||||
except HTTPError, e:
|
||||
assert(e.msg=='INTERNAL SERVER ERROR')
|
||||
assert(e.msg == 'INTERNAL SERVER ERROR')
|
||||
# check internal server error returned (issue 153)
|
||||
assert(s.status == 500)
|
||||
assert(s.text == xml_response)
|
||||
|
||||
+25
-6
@@ -23,6 +23,7 @@ import glob
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
import fnmatch
|
||||
import traceback
|
||||
import smtplib
|
||||
import urllib
|
||||
@@ -1717,11 +1718,29 @@ class Auth(object):
|
||||
def here(self):
|
||||
return URL(args=current.request.args, vars=current.request.get_vars)
|
||||
|
||||
def select_host(self, host, host_names=None):
|
||||
"""
|
||||
checks that host is valid, i.e. in the list of glob host_names
|
||||
if the host is missing, then is it selects the first entry from host_names
|
||||
read more here: https://github.com/web2py/web2py/issues/1196
|
||||
"""
|
||||
if host:
|
||||
if host_names:
|
||||
for item in host_names:
|
||||
if fnmatch.fnmatch(host, item):
|
||||
break
|
||||
else:
|
||||
raise HTTP(403, "Invalid Hostname")
|
||||
elif host_names:
|
||||
host = host_names[0]
|
||||
else:
|
||||
host = 'localhost'
|
||||
|
||||
def __init__(self, environment=None, db=None, mailer=True,
|
||||
hmac_key=None, controller='default', function='user',
|
||||
cas_provider=None, signature=True, secure=False,
|
||||
csrf_prevention=True, propagate_extension=None,
|
||||
url_index=None, jwt=None, host=None):
|
||||
url_index=None, jwt=None, host_names=None):
|
||||
|
||||
## next two lines for backward compatibility
|
||||
if not db and environment and isinstance(environment, DAL):
|
||||
@@ -1765,7 +1784,7 @@ class Auth(object):
|
||||
|
||||
settings = self.settings = Settings()
|
||||
settings.update(Auth.default_settings)
|
||||
host = host or request.env.http_host
|
||||
host = self.select_host(request.env.http_host, host_names)
|
||||
settings.update(
|
||||
cas_domains=[host],
|
||||
enable_tokens=False,
|
||||
@@ -2559,8 +2578,8 @@ class Auth(object):
|
||||
if not 'first_name' in keys and 'first_name' in table_user.fields:
|
||||
guess = keys.get('email', 'anonymous').split('@')[0]
|
||||
keys['first_name'] = keys.get('username', guess)
|
||||
form = table_user._filter_fields(keys)
|
||||
user_id = table_user.insert(**form)
|
||||
vars = table_user._filter_fields(keys)
|
||||
user_id = table_user.insert(**vars)
|
||||
user = table_user[user_id]
|
||||
if self.settings.create_user_groups:
|
||||
group_id = self.add_group(
|
||||
@@ -2571,7 +2590,7 @@ class Auth(object):
|
||||
if login:
|
||||
self.user = user
|
||||
if self.settings.register_onaccept:
|
||||
callback(self.settings.register_onaccept, form)
|
||||
callback(self.settings.register_onaccept, Storage(vars=user))
|
||||
return user
|
||||
|
||||
def basic(self, basic_auth_realm=False):
|
||||
@@ -3297,7 +3316,7 @@ class Auth(object):
|
||||
if self.settings.register_verify_password:
|
||||
if self.settings.register_fields is None:
|
||||
self.settings.register_fields = [f.name for f in table_user if f.writable]
|
||||
k = self.settings.register_fields.index("password")
|
||||
k = self.settings.register_fields.index(passfield)
|
||||
self.settings.register_fields.insert(k+1, "password_two")
|
||||
extra_fields = [
|
||||
Field("password_two", "password",
|
||||
|
||||
+3
-19
@@ -141,7 +141,6 @@ class Validator(object):
|
||||
|
||||
def __call__(self, value):
|
||||
raise NotImplementedError
|
||||
return (value, None)
|
||||
|
||||
|
||||
class IS_MATCH(Validator):
|
||||
@@ -2246,7 +2245,7 @@ class IS_DATE(Validator):
|
||||
y = '%.4i' % year
|
||||
format = format.replace('%y', y[-2:])
|
||||
format = format.replace('%Y', y)
|
||||
if year < 1900:
|
||||
if year < 1900:
|
||||
year = 2000
|
||||
d = datetime.date(year, value.month, value.day)
|
||||
return d.strftime(format)
|
||||
@@ -2642,8 +2641,8 @@ class IS_EMPTY_OR(Validator):
|
||||
if hasattr(other, 'options'):
|
||||
self.options = self._options
|
||||
|
||||
def _options(self):
|
||||
options = self.other.options()
|
||||
def _options(self, *args, **kwargs):
|
||||
options = self.other.options(*args, **kwargs)
|
||||
if (not options or options[0][0] != '') and not self.multiple:
|
||||
options.insert(0, ('', ''))
|
||||
return options
|
||||
@@ -3063,21 +3062,6 @@ class IS_STRONG(object):
|
||||
return (value, translate(self.error_message))
|
||||
|
||||
|
||||
class IS_IN_SUBSET(IS_IN_SET):
|
||||
|
||||
REGEX_W = re.compile('\w+')
|
||||
|
||||
def __init__(self, *a, **b):
|
||||
IS_IN_SET.__init__(self, *a, **b)
|
||||
|
||||
def __call__(self, value):
|
||||
values = self.REGEX_W.findall(str(value))
|
||||
failures = [x for x in values if IS_IN_SET.__call__(self, x)[1]]
|
||||
if failures:
|
||||
return (value, translate(self.error_message))
|
||||
return (value, None)
|
||||
|
||||
|
||||
class IS_IMAGE(Validator):
|
||||
"""
|
||||
Checks if file uploaded through file input was saved in one of selected
|
||||
|
||||
+5
-9
@@ -17,6 +17,7 @@ import time
|
||||
import thread
|
||||
import threading
|
||||
import os
|
||||
import copy
|
||||
import socket
|
||||
import signal
|
||||
import math
|
||||
@@ -940,7 +941,10 @@ def console():
|
||||
sys.argv, other_args = sys.argv[:k], sys.argv[k + 1:]
|
||||
(options, args) = parser.parse_args()
|
||||
options.args = [options.run] + other_args
|
||||
global_settings.cmd_options = options
|
||||
|
||||
copy_options = copy.deepcopy(options)
|
||||
copy_options.password = '******'
|
||||
global_settings.cmd_options = copy_options
|
||||
global_settings.cmd_args = args
|
||||
|
||||
if options.gae:
|
||||
@@ -1126,14 +1130,6 @@ def start(cron=True):
|
||||
if hasattr(options, key):
|
||||
setattr(options, key, getattr(options2, key))
|
||||
|
||||
logfile0 = os.path.join('examples', 'logging.example.conf')
|
||||
logfile1 = os.path.join(options.folder, 'logging.conf')
|
||||
if not os.path.exists(logfile1) and os.path.exists(logfile0):
|
||||
import shutil
|
||||
sys.stdout.write("Copying logging.conf.example to logging.conf ... ")
|
||||
shutil.copyfile(logfile0, logfile1)
|
||||
sys.stdout.write("OK\n")
|
||||
|
||||
# ## if -T run doctests (no cron)
|
||||
if hasattr(options, 'test') and options.test:
|
||||
test(options.test, verbose=options.verbose)
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
import time
|
||||
import sys
|
||||
import urllib2
|
||||
import urllib2
|
||||
|
||||
n = int(sys.argv[1])
|
||||
url = sys.argv[2]
|
||||
headers = {"Accept-Language": "en"}
|
||||
req = urllib2.Request(url, None, headers)
|
||||
|
||||
t0 = time.time()
|
||||
for k in xrange(n):
|
||||
data = urllib2.urlopen(req).read()
|
||||
print (time.time() - t0) / n
|
||||
if n == 1:
|
||||
print data
|
||||
@@ -1,32 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys
|
||||
import re
|
||||
|
||||
filename = sys.argv[1]
|
||||
|
||||
datafile = open(filename, 'r')
|
||||
try:
|
||||
data = '\n' + datafile.read()
|
||||
finally:
|
||||
datafile.close()
|
||||
SPACE = '\n ' if '-n' in sys.argv[1:] else ' '
|
||||
|
||||
data = re.compile('(?<!\:)//(?P<a>.*)').sub('/* \g<a> */', data)
|
||||
data = re.compile('[ ]+').sub(' ', data)
|
||||
data = re.compile('\s*{\s*').sub(' {' + SPACE, data)
|
||||
data = re.compile('\s*;\s*').sub(';' + SPACE, data)
|
||||
data = re.compile(',\s*').sub(', ', data)
|
||||
data = re.compile('\s*\*/\s*').sub('*/' + SPACE, data)
|
||||
data = re.compile('\s*}\s*').sub(SPACE + '}\n', data)
|
||||
data = re.compile('\n\s*\n').sub('\n', data)
|
||||
data = re.compile(';\s+/\*').sub('; /*', data)
|
||||
data = re.compile('\*/\s+/\*').sub(' ', data)
|
||||
data = re.compile('[ ]+\n').sub('\n', data)
|
||||
data = re.compile('\n\s*/[\*]+(?P<a>.*?)[\*]+/', re.DOTALL).sub(
|
||||
'\n/*\g<a>*/\n', data)
|
||||
data = re.compile('[ \t]+(?P<a>\S.+?){').sub(' \g<a>{', data)
|
||||
data = data.replace('}', '}\n')
|
||||
|
||||
print data
|
||||
@@ -1,67 +0,0 @@
|
||||
import sys
|
||||
import re
|
||||
|
||||
|
||||
def cleancss(text):
|
||||
text = re.compile('\s+').sub(' ', text)
|
||||
text = re.compile('\s*(?P<a>,|:)\s*').sub('\g<a> ', text)
|
||||
text = re.compile('\s*;\s*').sub(';\n ', text)
|
||||
text = re.compile('\s*\{\s*').sub(' {\n ', text)
|
||||
text = re.compile('\s*\}\s*').sub('\n}\n\n', text)
|
||||
return text
|
||||
|
||||
|
||||
def cleanhtml(text):
|
||||
text = text.lower()
|
||||
r = re.compile('\<script.+?/script\>', re.DOTALL)
|
||||
scripts = r.findall(text)
|
||||
text = r.sub('<script />', text)
|
||||
r = re.compile('\<style.+?/style\>', re.DOTALL)
|
||||
styles = r.findall(text)
|
||||
text = r.sub('<style />', text)
|
||||
text = re.compile(
|
||||
'<(?P<tag>(input|meta|link|hr|br|img|param))(?P<any>[^\>]*)\s*(?<!/)>')\
|
||||
.sub('<\g<tag>\g<any> />', text)
|
||||
text = text.replace('\n', ' ')
|
||||
text = text.replace('>', '>\n')
|
||||
text = text.replace('<', '\n<')
|
||||
text = re.compile('\s*\n\s*').sub('\n', text)
|
||||
lines = text.split('\n')
|
||||
(indent, newlines) = (0, [])
|
||||
for line in lines:
|
||||
if line[:2] == '</': indent = indent - 1
|
||||
newlines.append(indent * ' ' + line)
|
||||
if not line[:2] == '</' and line[-1:] == '>' and \
|
||||
not line[-2:] in ['/>', '->']: indent = indent + 1
|
||||
text = '\n'.join(newlines)
|
||||
text = re.compile(
|
||||
'\<div(?P<a>( .+)?)\>\s+\</div\>').sub('<div\g<a>></div>', text)
|
||||
text = re.compile('\<a(?P<a>( .+)?)\>\s+(?P<b>[\w\s\(\)\/]+?)\s+\</a\>').sub('<a\g<a>>\g<b></a>', text)
|
||||
text = re.compile('\<b(?P<a>( .+)?)\>\s+(?P<b>[\w\s\(\)\/]+?)\s+\</b\>').sub('<b\g<a>>\g<b></b>', text)
|
||||
text = re.compile('\<i(?P<a>( .+)?)\>\s+(?P<b>[\w\s\(\)\/]+?)\s+\</i\>').sub('<i\g<a>>\g<b></i>', text)
|
||||
text = re.compile('\<span(?P<a>( .+)?)\>\s+(?P<b>[\w\s\(\)\/]+?)\s+\</span\>').sub('<span\g<a>>\g<b></span>', text)
|
||||
text = re.compile('\s+\<br(?P<a>.*?)\/\>').sub('<br\g<a>/>', text)
|
||||
text = re.compile('\>(?P<a>\s+)(?P<b>[\.\,\:\;])').sub('>\g<b>\g<a>', text)
|
||||
text = re.compile('\n\s*\n').sub('\n', text)
|
||||
for script in scripts:
|
||||
text = text.replace('<script />', script, 1)
|
||||
for style in styles:
|
||||
text = text.replace('<style />', cleancss(style), 1)
|
||||
return text
|
||||
|
||||
|
||||
def read_file(filename):
|
||||
f = open(filename, 'r')
|
||||
try:
|
||||
return f.read()
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
for file in sys.argv[1:]:
|
||||
data = read_file(file)
|
||||
open(file+'.bak2', 'w').write(data)
|
||||
if file[-4:] == '.css':
|
||||
data = cleancss(data)
|
||||
if file[-5:] == '.html':
|
||||
data = cleanhtml(data)
|
||||
open(file, 'w').write(data)
|
||||
@@ -1,17 +0,0 @@
|
||||
import re
|
||||
|
||||
|
||||
def cleanjs(text):
|
||||
text = re.sub('\s*}\s*', '\n}\n', text)
|
||||
text = re.sub('\s*{\s*', ' {\n', text)
|
||||
text = re.sub('\s*;\s*', ';\n', text)
|
||||
text = re.sub('\s*,\s*', ', ', text)
|
||||
text = re.sub('\s*(?P<a>[\+\-\*/\=]+)\s*', ' \g<a> ', text)
|
||||
lines = text.split('\n')
|
||||
text = ''
|
||||
indent = 0
|
||||
for line in lines:
|
||||
rline = line.strip()
|
||||
if rline:
|
||||
pass
|
||||
return text
|
||||
@@ -1,3 +1,6 @@
|
||||
"""
|
||||
converts a static file to a web2py view. needs work
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import glob
|
||||
@@ -97,6 +100,4 @@ def convert(source, destination,prefix='imported'):
|
||||
os.makedirs(os.path.split(fullname)[0])
|
||||
open(fullname,'w').write(views[name])
|
||||
|
||||
|
||||
|
||||
convert(sys.argv[1],sys.argv[2])
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
This script will update untranslated messages in target from source (target and source are both language files)
|
||||
Usage:
|
||||
this can be used as first step when creating language file for new but very similar language
|
||||
or if you want update your app from welcome app of newer web2py version
|
||||
or in non-standard scenarios when you work on target and from any reason you have partial translation in source
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
sys.path.append(os.path.join(*__file__.split(os.sep)[:-2] or ['.']))
|
||||
|
||||
from gluon.languages import update_from_langfile
|
||||
import argparse
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='Use to set untranslated messages in the translation file from another one.')
|
||||
parser.add_argument(
|
||||
'-t', '--target',
|
||||
required=True,
|
||||
dest="target",
|
||||
help="Specify language file (rw) where untranslated messages will be updated if possible"
|
||||
)
|
||||
parser.add_argument(
|
||||
'-s', '--source',
|
||||
required=True,
|
||||
dest="source",
|
||||
help="Specify language file (ro) where seek for translations"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
update_from_langfile(args.target, args.source)
|
||||
|
||||
print '%s was updated.' % args.target
|
||||
@@ -1,103 +0,0 @@
|
||||
import glob
|
||||
import os
|
||||
import zipfile
|
||||
import sys
|
||||
import re
|
||||
from BeautifulSoup import BeautifulSoup as BS
|
||||
|
||||
|
||||
def head(styles):
|
||||
title = '<title>{{=response.title or request.application}}</title>'
|
||||
items = '\n'.join(["{{response.files.append(URL(request.application,'static','%s'))}}" % (style) for style in styles])
|
||||
loc = """<style>
|
||||
div.flash {
|
||||
position: absolute;
|
||||
float: right;
|
||||
padding: 10px;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
opacity: 0.75;
|
||||
margin: 10px 10px 10px 10px;
|
||||
text-align: center;
|
||||
clear: both;
|
||||
color: #fff;
|
||||
font-size: 11pt;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
background: black;
|
||||
border: 2px solid #fff;
|
||||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
z-index: 2;
|
||||
}
|
||||
div.error {
|
||||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
background-color: red;
|
||||
color: white;
|
||||
padding: 3px;
|
||||
border: 1px solid #666;
|
||||
}
|
||||
</style>"""
|
||||
return "\n%s\n%s\n{{include 'web2py_ajax.html'}}\n%s" % (title, items, loc)
|
||||
|
||||
|
||||
def content():
|
||||
return """<div class="flash">{{=response.flash or ''}}</div>{{include}}"""
|
||||
|
||||
|
||||
def process(folder):
|
||||
indexfile = open(os.path.join(folder, 'index.html'), 'rb')
|
||||
try:
|
||||
soup = BS(indexfile.read())
|
||||
finally:
|
||||
indexfile.close()
|
||||
styles = [x['href'] for x in soup.findAll('link')]
|
||||
soup.find('head').contents = BS(head(styles))
|
||||
try:
|
||||
soup.find(
|
||||
'h1').contents = BS('{{=response.title or request.application}}')
|
||||
soup.find('h2').contents = BS(
|
||||
"{{=response.subtitle or '=response.subtitle'}}")
|
||||
except:
|
||||
pass
|
||||
for match in (soup.find('div', id='menu'),
|
||||
soup.find('div', {'class': 'menu'}),
|
||||
soup.find('div', id='nav'),
|
||||
soup.find('div', {'class': 'nav'})):
|
||||
if match:
|
||||
match.contents = BS('{{=MENU(response.menu)}}')
|
||||
break
|
||||
done = False
|
||||
for match in (soup.find('div', id='content'),
|
||||
soup.find('div', {'class': 'content'}),
|
||||
soup.find('div', id='main'),
|
||||
soup.find('div', {'class': 'main'})):
|
||||
if match:
|
||||
match.contents = BS(content())
|
||||
done = True
|
||||
break
|
||||
if done:
|
||||
page = soup.prettify()
|
||||
page = re.compile("\s*\{\{=response\.flash or ''\}\}\s*", re.MULTILINE)\
|
||||
.sub("{{=response.flash or ''}}", page)
|
||||
print page
|
||||
else:
|
||||
raise Exception("Unable to convert")
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 2:
|
||||
print """USAGE:
|
||||
1) start a new web2py application
|
||||
2) Download a sample free layout from the web into the static/ folder of
|
||||
your web2py application (make sure a sample index.html is there)
|
||||
3) run this script with
|
||||
|
||||
python layout_make.py /path/to/web2py/applications/app/static/
|
||||
> /path/to/web2py/applications/app/views/layout.html
|
||||
"""
|
||||
elif not os.path.exists(sys.argv[1]):
|
||||
print 'Folder %s does not exist' % sys.argv[1]
|
||||
else:
|
||||
process(sys.argv[1])
|
||||
@@ -1,116 +0,0 @@
|
||||
import os
|
||||
import glob
|
||||
import zipfile
|
||||
import urllib
|
||||
import tempfile
|
||||
import shutil
|
||||
|
||||
def copytree(src, dst):
|
||||
names = os.listdir(src)
|
||||
ignored_names = set()
|
||||
errors = []
|
||||
if not os.path.exists(dst):
|
||||
os.makedirs(dst)
|
||||
for name in names:
|
||||
srcname = os.path.join(src, name)
|
||||
dstname = os.path.join(dst, name)
|
||||
if os.path.isdir(srcname):
|
||||
copytree(srcname, dstname)
|
||||
else:
|
||||
shutil.copy2(srcname, dstname)
|
||||
|
||||
class W2PInstance(object):
|
||||
|
||||
SOURCES = {'stable':'http://web2py.com/examples/static/web2py_src.zip',
|
||||
'nightly':'http://web2py.com/examples/static/nightly/web2py_src.zip',
|
||||
'trunk':'https://github.com/web2py/web2py/archive/master.zip'}
|
||||
|
||||
def __init__(self,path):
|
||||
self.path = path
|
||||
|
||||
def warn(self,message="system going down soon"):
|
||||
apps = glob.glob(os.path.join(self.path,'applications','*'))
|
||||
for app in apps:
|
||||
if os.path.isdir(app):
|
||||
open(os.path.join(app,'notifications.txt'),'w').write(message)
|
||||
|
||||
def install(self,source='stable'):
|
||||
if not os.path.exists(self.path):
|
||||
os.mkdir(self.path)
|
||||
tmpdir = tempfile.mkdtemp()
|
||||
link = self.SOURCES[source]
|
||||
srcfile = os.path.join(tmpdir,'web2py_src.zip')
|
||||
print 'downloading...'
|
||||
open(srcfile,'wb').write(urllib.urlopen(link).read())
|
||||
print 'extracing...'
|
||||
zipfile.ZipFile(srcfile,'r').extractall(tmpdir)
|
||||
print 'copying...'
|
||||
copytree(os.path.join(tmpdir,'web2py'),self.path)
|
||||
|
||||
def upgrade(self,source='stable'):
|
||||
self.install(source)
|
||||
|
||||
def upgrade_tmp(self,source,common=False):
|
||||
tmpdir = tempfile.mkdtemp()
|
||||
link = self.SOURCES[source]
|
||||
srcfile = os.path.join(tmpdir,'web2py_src.zip')
|
||||
print 'copying production...'
|
||||
copytree(self.path,os.path.join(tmpdir,'web2py'))
|
||||
tmpdir_web2py = os.path.join(tmpdir,'web2py')
|
||||
tmp_web2py = W2PInstance(tempdir_web2py)
|
||||
tmp_web2py.clear_sessions()
|
||||
tmp_web2py.clear_cache()
|
||||
tmp_web2py.clear_error()
|
||||
print 'downloading...'
|
||||
open(srcfile,'wb').write(urllib.urlopen(link).read())
|
||||
print 'extracing...'
|
||||
zipfile.ZipFile(srcfile,'r').extractall(tmpdir)
|
||||
print 'running tests...'
|
||||
try:
|
||||
olddir = os.getcwd()
|
||||
os.chdir(tempdir_web2py)
|
||||
ret = os.system("PYTHONPATH=. python -m unittest -v gluon.tests")
|
||||
# eventually start web2py and run functional tests
|
||||
finally:
|
||||
os.chrid(olddir)
|
||||
if ret:
|
||||
sys.exit(ret and 1)
|
||||
copytree(os.path.join(tmpdir,'web2py'),self.path)
|
||||
|
||||
def clear_sessions(self):
|
||||
files = glob.glob(os.path.join(self.path,'applications','*','sessions','*'))
|
||||
for file in files:
|
||||
try:
|
||||
os.unlink(file)
|
||||
except:
|
||||
pass
|
||||
|
||||
def clear_cache(self):
|
||||
files = glob.glob(os.path.join(self.path,'applications','*','cache','*'))
|
||||
for file in files:
|
||||
try:
|
||||
os.unlink(file)
|
||||
except:
|
||||
pass
|
||||
|
||||
def clear_errors(self):
|
||||
files = glob.glob(os.path.join(self.path,'applications','*','errors','*'))
|
||||
for file in files:
|
||||
try:
|
||||
os.unlink(file)
|
||||
except:
|
||||
pass
|
||||
|
||||
web2py = W2PInstance('/Users/massimodipierro/Downloads/web2py')
|
||||
#web2py.install()
|
||||
web2py.clear_sessions()
|
||||
|
||||
"""
|
||||
{{
|
||||
import os
|
||||
_notifications = os.path.join(request.folder,'notifications.txt')
|
||||
if os.path.exixts(_notifications):
|
||||
response.flash = response.flash or open(_notifications).read()
|
||||
pass
|
||||
}}
|
||||
"""
|
||||
@@ -1,220 +0,0 @@
|
||||
from service import ServiceBase
|
||||
import os, sys, time, subprocess, atexit
|
||||
from signal import SIGTERM
|
||||
|
||||
class LinuxService(ServiceBase):
|
||||
def __init__(self, name, label, stdout='/dev/null', stderr='/dev/null'):
|
||||
ServiceBase.__init__(self, name, label, stdout, stderr)
|
||||
self.pidfile = '/tmp/%s.pid' % name
|
||||
self.config_file = '/etc/%s.conf' % name
|
||||
|
||||
def daemonize(self):
|
||||
"""
|
||||
do the UNIX double-fork magic, see Stevens' "Advanced
|
||||
Programming in the UNIX Environment" for details (ISBN 0201563177)
|
||||
http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
|
||||
"""
|
||||
try:
|
||||
pid = os.fork()
|
||||
if pid > 0:
|
||||
# exit first parent
|
||||
sys.exit(0)
|
||||
except OSError, e:
|
||||
sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
|
||||
return
|
||||
|
||||
# decouple from parent environment
|
||||
os.chdir("/")
|
||||
os.setsid()
|
||||
os.umask(0)
|
||||
|
||||
# do second fork
|
||||
try:
|
||||
pid = os.fork()
|
||||
if pid > 0:
|
||||
# exit from second parent
|
||||
sys.exit(0)
|
||||
except OSError, e:
|
||||
sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
|
||||
return
|
||||
|
||||
# redirect standard file descriptors
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
si = file('/dev/null', 'r')
|
||||
so = file(self.stdout or '/dev/null', 'a+')
|
||||
se = file(self.stderr or '/dev/null', 'a+')
|
||||
os.dup2(si.fileno(), sys.stdin.fileno())
|
||||
os.dup2(so.fileno(), sys.stdout.fileno())
|
||||
os.dup2(se.fileno(), sys.stderr.fileno())
|
||||
|
||||
def getpid(self):
|
||||
# Check for a pidfile to see if the daemon already runs
|
||||
try:
|
||||
pf = file(self.pidfile,'r')
|
||||
pid = int(pf.read().strip())
|
||||
pf.close()
|
||||
except IOError:
|
||||
pid = None
|
||||
|
||||
return pid
|
||||
|
||||
def status(self):
|
||||
pid = self.getpid()
|
||||
if pid:
|
||||
return 'Service running with PID %s.' % pid
|
||||
else:
|
||||
return 'Service is not running.'
|
||||
|
||||
def check_permissions(self):
|
||||
if not os.geteuid() == 0:
|
||||
return (False, 'This script must be run with root permissions.')
|
||||
else:
|
||||
return (True, '')
|
||||
|
||||
def start(self):
|
||||
"""
|
||||
Start the daemon
|
||||
"""
|
||||
pid = self.getpid()
|
||||
|
||||
if pid:
|
||||
message = "Service already running under PID %s\n"
|
||||
sys.stderr.write(message % self.pidfile)
|
||||
return
|
||||
|
||||
# Start the daemon
|
||||
self.daemonize()
|
||||
self.run()
|
||||
|
||||
def stop(self):
|
||||
"""
|
||||
Stop the daemon
|
||||
"""
|
||||
pid = self.getpid()
|
||||
|
||||
if not pid:
|
||||
message = "Service is not running\n"
|
||||
sys.stderr.write(message)
|
||||
return # not an error in a restart
|
||||
|
||||
# Try killing the daemon process
|
||||
try:
|
||||
while 1:
|
||||
os.kill(pid, SIGTERM)
|
||||
time.sleep(0.5)
|
||||
except OSError, err:
|
||||
err = str(err)
|
||||
if err.find("No such process") > 0:
|
||||
if os.path.exists(self.pidfile):
|
||||
os.remove(self.pidfile)
|
||||
else:
|
||||
print str(err)
|
||||
return
|
||||
|
||||
def restart(self):
|
||||
"""
|
||||
Restart the daemon
|
||||
"""
|
||||
self.stop()
|
||||
self.start()
|
||||
|
||||
def run(self):
|
||||
atexit.register(self.terminate)
|
||||
|
||||
args = self.load_configuration()[0]
|
||||
stdout = open(self.stdout, 'a+')
|
||||
stderr = open(self.stderr, 'a+')
|
||||
process = subprocess.Popen(args, stdout=stdout, stderr=stderr)
|
||||
file(self.pidfile,'w+').write("%s\n" % process.pid)
|
||||
process.wait()
|
||||
|
||||
self.terminate()
|
||||
|
||||
def terminate(self):
|
||||
try:
|
||||
os.remove(self.pidfile)
|
||||
except:
|
||||
pass
|
||||
|
||||
def install(self):
|
||||
env = self.detect_environment()
|
||||
src_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'service.py')
|
||||
|
||||
# make sure this script is executable
|
||||
self.run_command('chmod', '+x', src_path)
|
||||
|
||||
# link this daemon to the service directory
|
||||
dest_path = env['rc.d-path'] + self.name
|
||||
os.symlink(src_path, dest_path)
|
||||
|
||||
# start the service at boot
|
||||
install_command = self.get_service_installer_command(env)
|
||||
result = self.run_command(*install_command)
|
||||
self.start()
|
||||
|
||||
def uninstall(self):
|
||||
self.stop()
|
||||
env = self.detect_environment()
|
||||
|
||||
# stop the service from autostarting
|
||||
uninstall_command = self.get_service_uninstaller_command(env)
|
||||
result = self.run_command(*uninstall_command)
|
||||
|
||||
# remove link to the script from the service directory
|
||||
path = env['rc.d-path'] + self.name
|
||||
os.remove(path)
|
||||
|
||||
def detect_environment(self):
|
||||
"""
|
||||
Returns a dictionary of command/path to the required command-line applications.
|
||||
One key is 'dist' which will either be 'debian' or 'redhat', which is the best
|
||||
guess as to which Linux distribution the current system is based on.
|
||||
"""
|
||||
check_for = [
|
||||
'chkconfig',
|
||||
'service',
|
||||
'update-rc.d',
|
||||
'rpm',
|
||||
'dpkg',
|
||||
]
|
||||
|
||||
env = dict()
|
||||
for cmd in check_for:
|
||||
result = self.run_command('which', cmd)
|
||||
if result[0]:
|
||||
env[cmd] = result[0].replace('\n', '')
|
||||
|
||||
if 'rpm' in env:
|
||||
env['dist'] = 'redhat'
|
||||
env['rc.d-path'] = '/etc/rc.d/init.d/'
|
||||
elif 'dpkg' in env:
|
||||
env['dist'] = 'debian'
|
||||
env['rc.d-path'] = '/etc/init.d/'
|
||||
else:
|
||||
env['dist'] = 'unknown'
|
||||
env['rc.d-path'] = '/dev/null/'
|
||||
|
||||
return env
|
||||
|
||||
def get_service_installer_command(self, env):
|
||||
"""
|
||||
Returns list of args required to set a service to run on boot.
|
||||
"""
|
||||
if env['dist'] == 'redhat':
|
||||
cmd = env['chkconfig']
|
||||
return [cmd, self.name, 'on']
|
||||
else:
|
||||
cmd = env['update-rc.d']
|
||||
return [cmd, self.name, 'defaults']
|
||||
|
||||
def get_service_uninstaller_command(self, env):
|
||||
"""
|
||||
Returns list of arge required to stop a service from running at boot.
|
||||
"""
|
||||
if env['dist'] == 'redhat':
|
||||
cmd = env['chkconfig']
|
||||
return [cmd, self.name, 'off']
|
||||
else:
|
||||
cmd = env['update-rc.d']
|
||||
return [cmd, self.name, 'remove']
|
||||
@@ -1,201 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import sys, os, time, subprocess
|
||||
|
||||
class Base:
|
||||
def run_command(self, *args):
|
||||
"""
|
||||
Returns the output of a command as a tuple (output, error).
|
||||
"""
|
||||
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
return p.communicate()
|
||||
|
||||
class ServiceBase(Base):
|
||||
def __init__(self, name, label, stdout=None, stderr=None):
|
||||
self.name = name
|
||||
self.label = label
|
||||
self.stdout = stdout
|
||||
self.stderr = stderr
|
||||
self.config_file = None
|
||||
|
||||
def load_configuration(self):
|
||||
"""
|
||||
Loads the configuration required to build the command-line string
|
||||
for running web2py. Returns a tuple (command_args, config_dict).
|
||||
"""
|
||||
s = os.path.sep
|
||||
|
||||
default = dict(
|
||||
python = 'python',
|
||||
web2py = os.path.join(s.join(__file__.split(s)[:-3]), 'web2py.py'),
|
||||
http_enabled = True,
|
||||
http_ip = '0.0.0.0',
|
||||
http_port = 8000,
|
||||
https_enabled = True,
|
||||
https_ip = '0.0.0.0',
|
||||
https_port = 8001,
|
||||
https_key = '',
|
||||
https_cert = '',
|
||||
password = '<recycle>',
|
||||
)
|
||||
|
||||
config = default
|
||||
if self.config_file:
|
||||
try:
|
||||
f = open(self.config_file, 'r')
|
||||
lines = f.readlines()
|
||||
f.close()
|
||||
|
||||
for line in lines:
|
||||
fields = line.split('=', 1)
|
||||
if len(fields) == 2:
|
||||
key, value = fields
|
||||
key = key.strip()
|
||||
value = value.strip()
|
||||
config[key] = value
|
||||
except:
|
||||
pass
|
||||
|
||||
web2py_path = os.path.dirname(config['web2py'])
|
||||
os.chdir(web2py_path)
|
||||
|
||||
args = [config['python'], config['web2py']]
|
||||
interfaces = []
|
||||
ports = []
|
||||
|
||||
if config['http_enabled']:
|
||||
ip = config['http_ip']
|
||||
port = config['http_port']
|
||||
interfaces.append('%s:%s' % (ip, port))
|
||||
ports.append(port)
|
||||
if config['https_enabled']:
|
||||
ip = config['https_ip']
|
||||
port = config['https_port']
|
||||
key = config['https_key']
|
||||
cert = config['https_cert']
|
||||
if key != '' and cert != '':
|
||||
interfaces.append('%s:%s:%s:%s' % (ip, port, key, cert))
|
||||
ports.append(ports)
|
||||
if len(interfaces) == 0:
|
||||
sys.exit('Configuration error. Must have settings for http and/or https')
|
||||
|
||||
password = config['password']
|
||||
if not password == '<recycle>':
|
||||
from gluon import main
|
||||
for port in ports:
|
||||
main.save_password(password, port)
|
||||
|
||||
password = '<recycle>'
|
||||
|
||||
args.append('-a "%s"' % password)
|
||||
|
||||
interfaces = ';'.join(interfaces)
|
||||
args.append('--interfaces=%s' % interfaces)
|
||||
|
||||
if 'log_filename' in config.keys():
|
||||
log_filename = config['log_filename']
|
||||
args.append('--log_filename=%s' % log_filename)
|
||||
|
||||
return (args, config)
|
||||
|
||||
def start(self):
|
||||
pass
|
||||
|
||||
def stop(self):
|
||||
pass
|
||||
|
||||
def restart(self):
|
||||
pass
|
||||
|
||||
def status(self):
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
pass
|
||||
|
||||
def install(self):
|
||||
pass
|
||||
|
||||
def uninstall(self):
|
||||
pass
|
||||
|
||||
def check_permissions(self):
|
||||
"""
|
||||
Does the script have permissions to install, uninstall, start, and stop services?
|
||||
Return value must be a tuple (True/False, error_message_if_False).
|
||||
"""
|
||||
return (False, 'Permissions check not implemented')
|
||||
|
||||
class WebServerBase(Base):
|
||||
def install(self):
|
||||
pass
|
||||
|
||||
def uninstall(self):
|
||||
pass
|
||||
|
||||
|
||||
def get_service():
|
||||
service_name = 'web2py'
|
||||
service_label = 'web2py Service'
|
||||
|
||||
if sys.platform == 'linux2':
|
||||
from linux import LinuxService as Service
|
||||
elif sys.platform == 'darwin':
|
||||
# from mac import MacService as Service
|
||||
sys.exit('Mac OS X is not yet supported.\n')
|
||||
elif sys.platform == 'win32':
|
||||
# from windows import WindowsService as Service
|
||||
sys.exit('Windows is not yet supported.\n')
|
||||
else:
|
||||
sys.exit('The following platform is not supported: %s.\n' % sys.platform)
|
||||
|
||||
service = Service(service_name, service_label)
|
||||
return service
|
||||
|
||||
if __name__ == '__main__':
|
||||
service = get_service()
|
||||
is_root, error_message = service.check_permissions()
|
||||
if not is_root:
|
||||
sys.exit(error_message)
|
||||
|
||||
if len(sys.argv) >= 2:
|
||||
command = sys.argv[1]
|
||||
if command == 'start':
|
||||
service.start()
|
||||
elif command == 'stop':
|
||||
service.stop()
|
||||
elif command == 'restart':
|
||||
service.restart()
|
||||
elif command == 'status':
|
||||
print service.status() + '\n'
|
||||
elif command == 'run':
|
||||
service.run()
|
||||
elif command == 'install':
|
||||
service.install()
|
||||
elif command == 'uninstall':
|
||||
service.uninstall()
|
||||
elif command == 'install-apache':
|
||||
# from apache import Apache
|
||||
# server = Apache()
|
||||
# server.install()
|
||||
sys.exit('Configuring Apache is not yet supported.\n')
|
||||
elif command == 'uninstall-apache':
|
||||
# from apache import Apache
|
||||
# server = Apache()
|
||||
# server.uninstall()
|
||||
sys.exit('Configuring Apache is not yet supported.\n')
|
||||
else:
|
||||
sys.exit('Unknown command: %s' % command)
|
||||
else:
|
||||
print 'Usage: %s [command] \n' % sys.argv[0] + \
|
||||
'\tCommands:\n' + \
|
||||
'\t\tstart Starts the service\n' + \
|
||||
'\t\tstop Stop the service\n' + \
|
||||
'\t\trestart Restart the service\n' + \
|
||||
'\t\tstatus Check if the service is running\n' + \
|
||||
'\t\trun Run service is blocking mode\n' + \
|
||||
'\t\t (Press Ctrl + C to exit)\n' + \
|
||||
'\t\tinstall Install the service\n' + \
|
||||
'\t\tuninstall Uninstall the service\n' + \
|
||||
'\t\tinstall-apache Install as an Apache site\n' + \
|
||||
'\t\tuninstall-apache Uninstall from Apache\n'
|
||||
@@ -1,11 +0,0 @@
|
||||
# install virtualenv
|
||||
easy_install virtualenv
|
||||
python virtualenv.py w2env
|
||||
# install missing modules
|
||||
w2env/bin/easy_install -U pysqlite hashlib
|
||||
# donwload web2py and unpack
|
||||
wget http://web2py.com/examples/static/web2py_src.zip
|
||||
unzip web2py_src.zip
|
||||
cd web2py
|
||||
# start web2py using command-line script
|
||||
w2env/bin/python web2py.py -i 0.0.0.0 -p 8123 -a 'adminpasswd'
|
||||
@@ -1,462 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Description : Installation and basic configuration of web2py, uWSGI, Redmine,
|
||||
# Unicorn, Nginx and PostgreSQL.
|
||||
# Usage : Copy the script in /home/username and run it as root, you may
|
||||
# need to allow exectuion (chmod +x). Ex.:
|
||||
# sudo ./setup-ubuntu-12-04-redmine-unicorn-web2py-uwsgi-nginx.sh
|
||||
# File : setup-ubuntu-12-04-redmine-unicorn-web2py-uwsgi-nginx.sh
|
||||
# Author : Richard V?zina
|
||||
# Email : ml.richard.vezina@gmail.com
|
||||
# Copyright : Richard V?zina
|
||||
# Date : ven 28 d?c 2012 13:27:11 EST
|
||||
# Disclaimers : This script is provided "as is", without warranty of any kind.
|
||||
# Licence : CC BY-NC 2.5 CA
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
echo 'setup-ubuntu-12-04-redmine-unicorn-web2py-uwsgi-nginx.sh'
|
||||
echo 'Requires Ubuntu = 12.04 (May works with 12.10 not tested) and installs Redmine + Unicorn + Web2py + uWSGI + Nginx + PostgreSQL'
|
||||
# Check if user has root privileges
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo "You must run the script as root or using sudo"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# We concentrate here user prompts!!
|
||||
# Get Redmine Postgres Database Password
|
||||
echo -e "Redmine Postgres Database Password: \c "
|
||||
read REDMINEPASSWORD
|
||||
# Get Web2py Admin Password
|
||||
echo -e "Web2py Admin Password: \c "
|
||||
read PW
|
||||
|
||||
cd ~
|
||||
openssl genrsa 1024 > self_signed.key
|
||||
chmod 400 self_signed.key
|
||||
openssl req -new -x509 -nodes -sha1 -days 1780 -key self_signed.key > self_signed.cert
|
||||
openssl x509 -noout -fingerprint -text < self_signed.cert > self_signed.info
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
apt-get update
|
||||
apt-get -y upgrade
|
||||
apt-get autoremove
|
||||
apt-get autoclean
|
||||
apt-get -y install postgresql
|
||||
apt-get -y install nginx-full
|
||||
apt-get -y install build-essential python-dev libxml2-dev python-pip unzip
|
||||
apt-get -y install ruby1.9.3 # Ref.: http://askubuntu.com/questions/137485/rails-3-not-using-rvm
|
||||
apt-get -y install libpq-dev # Required for gem1.9.3 install pg Ref.: http://stackoverflow.com/questions/6040583/unable-to-install-pg-gem-on-ubuntu-cant-find-the-libpq-fe-h-header
|
||||
|
||||
gem1.9.3 install rails --no-rdoc --no-ri # For testing (faster) --no-rdoc --no-ri
|
||||
gem1.9.3 install unicorn --no-rdoc --no-ri # For testing (faster) --no-rdoc --no-ri
|
||||
gem1.9.3 install pg --no-rdoc --no-ri # For testing (faster) --no-rdoc --no-ri
|
||||
cd /opt
|
||||
wget http://rubyforge.org/frs/download.php/76627/redmine-2.2.0.tar.gz
|
||||
wget http://rubyforge.org/frs/download.php/76628/redmine-2.2.0.tar.gz.md5
|
||||
md5sum --check redmine-2.2.0.tar.gz.md5 > redmine_md5_checked_successfully
|
||||
if [ -f redmine_md5_checked_successfully ]
|
||||
then
|
||||
tar xvfz redmine-2.2.0.tar.gz
|
||||
rm redmine_md5_checked_successfully
|
||||
else
|
||||
echo "Redmine md5 check sum failed..."
|
||||
exit 1
|
||||
fi
|
||||
cd redmine-2.2.0
|
||||
bundle install --without development test rmagick sqlite mysql
|
||||
mkdir /var/www
|
||||
ln -s /opt/redmine-2.2.0/public /var/www/redmine
|
||||
chown -R www-data.www-data /var/www
|
||||
chown -R www-data.www-data /opt/redmine-2.2.0/public
|
||||
# To avoid prompt during execution of the script use psql instead of createuser
|
||||
#echo "Enter a postgres redmine user password twice:"
|
||||
#createuser -P -S -D -R -l -e redmine
|
||||
# createuser switch: -P --pwprompt -S --no-superuser -D --no-createdb -R --no-createrole -l --login -e --echo
|
||||
sudo -u postgres psql -c "CREATE ROLE redmine LOGIN; ALTER ROLE redmine WITH ENCRYPTED PASSWORD '$REDMINEPASSWORD';"
|
||||
# createdb wouldn't work without having root password
|
||||
#createdb -U postgres -w -E UTF8 -O redmine -e redmine
|
||||
# createdb switch: -U username --username=username -w --no-password -E Encoding -O owner --owner=owner -e --echo
|
||||
sudo -u postgres psql -c "CREATE DATABASE redmine WITH ENCODING='UTF8' OWNER=redmine;"
|
||||
cd /opt/redmine-2.2.0/config
|
||||
# Here we change related to an issue with new rails version as far as I understand
|
||||
# Ref1.: http://www.redmine.org/projects/redmine/wiki/HowTo_Install_Redmine_in_a_sub-URI # Preferred solution used
|
||||
# Ref2.: http://www.redmine.org/issues/12102 # JS and CSS was not working until I add this line 'RedmineApp::Application.routes.default_scope = { :path => "/redmine", :shallow_path => "/redmine" }' before 'RedmineApp::Application.initialize!'
|
||||
cp environment.rb environment.rb_original # Backup default environment.rb
|
||||
sed '/RedmineApp::Application.initialize!/c \RedmineApp::Application.routes.default_scope = { :path => "/redmine", :shallow_path => "/redmine" }\nRedmineApp::Application.initialize!\nRedmine::Utils::relative_url_root = "/redmine"' environment.rb_original > environment.rb
|
||||
# Now we configure Redmine database access
|
||||
#nano database.yml
|
||||
# paste :
|
||||
echo 'production:
|
||||
adapter: postgresql
|
||||
database: redmine
|
||||
host: localhost
|
||||
username: redmine
|
||||
password: "'$REDMINEPASSWORD'"
|
||||
encoding: utf8' > database.yml
|
||||
rake generate_secret_token
|
||||
RAILS_ENV=production rake db:migrate
|
||||
RAILS_ENV=production rake redmine:load_default_data
|
||||
mkdir /opt/redmine-2.2.0/tmp/pids
|
||||
#mkdir /opt/redmine-2.2.0/log # if not there
|
||||
cd /opt/redmine-2.2.0/config
|
||||
# Create Unicorn specific Redmine config in /opt/redmine-2.2.0/config/unicorn.rb
|
||||
echo '#unicorn.rb Starts here
|
||||
worker_processes 1
|
||||
working_directory "/opt/redmine-2.2.0" # needs to be the correct directory for redmine
|
||||
|
||||
# This loads the application in the master process before forking
|
||||
# worker processes
|
||||
# Read more about it here:
|
||||
# http://unicorn.bogomips.org/Unicorn/Configurator.html
|
||||
preload_app true
|
||||
timeout 45
|
||||
|
||||
# This is where we specify the socket.
|
||||
# We will point the upstream Nginx module to this socket later on
|
||||
listen "/tmp/unicorn_rails.socket", :backlog => 64 #directory structure needs to be created.
|
||||
pid "/opt/redmine-2.2.0/tmp/pids/unicorn_rails.pid" # make sure this points to a valid directory. Make sure it is named the same as the real process name in order to allow init.d script start-stop-daemon command to kill unicorn process properly
|
||||
|
||||
# Set the path of the log files inside the log folder of the testapp
|
||||
stderr_path "/opt/redmine-2.2.0/log/unicorn_rails.stderr.log"
|
||||
stdout_path "/opt/redmine-2.2.0/log/unicorn_rails.stdout.log"
|
||||
|
||||
before_fork do |server, worker|
|
||||
# This option works in together with preload_app true setting
|
||||
# What is does is prevent the master process from holding
|
||||
# the database connection
|
||||
defined?(ActiveRecord::Base) and
|
||||
ActiveRecord::Base.connection.disconnect!
|
||||
end
|
||||
|
||||
after_fork do |server, worker|
|
||||
# Here we are establishing the connection after forking worker
|
||||
# processes
|
||||
defined?(ActiveRecord::Base) and
|
||||
ActiveRecord::Base.establish_connection
|
||||
# change below if your redmine instance is running differently
|
||||
worker.user('\''www-data'\'', '\''www-data'\'') if Process.euid == 0
|
||||
end
|
||||
#unicorn.rb Ends here' > unicorn.rb
|
||||
chown www-data:www-data unicorn.rb
|
||||
chown -R www-data:www-data /opt/redmine-2.2.0/tmp
|
||||
mkdir /etc/unicorn
|
||||
# Set some config for Unicorn in /etc/unicorn/redmine
|
||||
echo 'RAILS_ROOT=/opt/redmine-2
|
||||
RAILS_ENV=production' > /etc/unicorn/redmine
|
||||
# Create a Unicorn Redmine start script in /etc/init.d/redmine
|
||||
echo '#! /bin/sh
|
||||
### BEGIN INIT INFO
|
||||
# Provides: redmine
|
||||
# Required-Start: $remote_fs $syslog
|
||||
# Required-Stop: $remote_fs $syslog
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: redmine initscript
|
||||
# Description: This script startup unicorn server and redmine and should
|
||||
# be placed in /etc/init.d.
|
||||
### END INIT INFO
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Author: Richard V?zina <ml.richard.vezina@gmail.com>
|
||||
# Base on Ubuntu 12.04 : /etc/init.d/skeleton
|
||||
# ven 21 d?c 2012 11:08:31 EST
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# Do NOT "set -e"
|
||||
|
||||
# PATH should only include /usr/* if it runs after the mountnfs.sh script
|
||||
APP=/opt/redmine-2.2.0/
|
||||
PATH=/sbin:/usr/sbin:/bin:/usr/bin
|
||||
DESC="Unicorn and Redmine"
|
||||
NAME=unicorn_rails
|
||||
DAEMON=/usr/local/bin/$NAME
|
||||
DAEMON_ARGS=" -E production -c $APP/config/unicorn.rb -D"
|
||||
PIDFILE=/opt/redmine-2.2.0/tmp/pids/$NAME.pid
|
||||
SCRIPTNAME=/etc/init.d/redmine
|
||||
|
||||
# Exit if the package is not installed
|
||||
[ -x "$DAEMON" ] || exit 0
|
||||
|
||||
# Read configuration variable file if it is present
|
||||
[ -r /etc/default/$NAME ] && . /etc/default/$NAME
|
||||
|
||||
# Load the VERBOSE setting and other rcS variables
|
||||
. /lib/init/vars.sh
|
||||
|
||||
# Define LSB log_* functions.
|
||||
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
|
||||
# and status_of_proc is working.
|
||||
. /lib/lsb/init-functions
|
||||
|
||||
#
|
||||
# Function that starts the daemon/service
|
||||
#
|
||||
do_start()
|
||||
{
|
||||
# Return
|
||||
# 0 if daemon has been started
|
||||
# 1 if daemon was already running
|
||||
# 2 if daemon could not be started
|
||||
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
|
||||
|| return 1
|
||||
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \
|
||||
$DAEMON_ARGS \
|
||||
|| return 2
|
||||
# Add code here, if necessary, that waits for the process to be ready
|
||||
# to handle requests from services started subsequently which depend
|
||||
# on this one. As a last resort, sleep for some time.
|
||||
}
|
||||
|
||||
#
|
||||
# Function that stops the daemon/service
|
||||
#
|
||||
do_stop()
|
||||
{
|
||||
# Return
|
||||
# 0 if daemon has been stopped
|
||||
# 1 if daemon was already stopped
|
||||
# 2 if daemon could not be stopped
|
||||
# other if a failure occurred
|
||||
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
|
||||
RETVAL="$?"
|
||||
[ "$RETVAL" = 2 ] && return 2
|
||||
# Wait for children to finish too if this is a daemon that forks
|
||||
# and if the daemon is only ever run from this initscript.
|
||||
# If the above conditions are not satisfied then add some other code
|
||||
# that waits for the process to drop all resources that could be
|
||||
# needed by services started subsequently. A last resort is to
|
||||
# sleep for some time.
|
||||
start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
|
||||
[ "$?" = 2 ] && return 2
|
||||
# Many daemons don'\''t delete their pidfiles when they exit.
|
||||
rm -f $PIDFILE
|
||||
return "$RETVAL"
|
||||
}
|
||||
|
||||
#
|
||||
# Function that sends a SIGHUP to the daemon/service
|
||||
#
|
||||
do_reload() {
|
||||
#
|
||||
# If the daemon can reload its configuration without
|
||||
# restarting (for example, when it is sent a SIGHUP),
|
||||
# then implement that here.
|
||||
#
|
||||
start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
|
||||
return 0
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
|
||||
do_start
|
||||
case "$?" in
|
||||
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
|
||||
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
|
||||
esac
|
||||
;;
|
||||
stop)
|
||||
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
|
||||
do_stop
|
||||
case "$?" in
|
||||
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
|
||||
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
|
||||
esac
|
||||
;;
|
||||
status)
|
||||
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
|
||||
;;
|
||||
#reload|force-reload)
|
||||
#
|
||||
# If do_reload() is not implemented then leave this commented out
|
||||
# and leave '\''force-reload'\'' as an alias for '\''restart'\''.
|
||||
#
|
||||
#log_daemon_msg "Reloading $DESC" "$NAME"
|
||||
#do_reload
|
||||
#log_end_msg $?
|
||||
#;;
|
||||
restart|force-reload)
|
||||
#
|
||||
# If the "reload" option is implemented then remove the
|
||||
# '\''force-reload'\'' alias
|
||||
#
|
||||
log_daemon_msg "Restarting $DESC" "$NAME"
|
||||
do_stop
|
||||
case "$?" in
|
||||
0|1)
|
||||
do_start
|
||||
case "$?" in
|
||||
0) log_end_msg 0 ;;
|
||||
1) log_end_msg 1 ;; # Old process is still running
|
||||
*) log_end_msg 1 ;; # Failed to start
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
# Failed to stop
|
||||
log_end_msg 1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
#echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
|
||||
echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
|
||||
exit 3
|
||||
;;
|
||||
esac
|
||||
|
||||
:' > /etc/init.d/redmine
|
||||
chmod +x /etc/init.d/redmine
|
||||
# Backup default Nginx site and replace it
|
||||
cp /etc/nginx/sites-available/default /etc/nginx/sites-available/default_original
|
||||
rm /etc/nginx/sites-available/default
|
||||
# Create configuration file /etc/nginx/sites-available/default
|
||||
echo 'upstream unicorn_server {
|
||||
# This is the socket we configured in unicorn.rb
|
||||
server unix:/tmp/unicorn_rails.socket
|
||||
fail_timeout=0;
|
||||
}
|
||||
server {
|
||||
listen 80;
|
||||
#return 301 https://192.168.1.126$request_uri; # http://$hostname$request_uri; # idem #http://wiki.nginx.org/Pitfalls#Taxing_Rewrites
|
||||
charset utf-8;
|
||||
server_name localhost; # $hostname;
|
||||
root /var/www;
|
||||
access_log /var/log/nginx/yoursite.access.log;
|
||||
error_log /var/log/nginx/yoursite.error.log;
|
||||
#to enable correct use of response.static_version
|
||||
location ~* /(\w+)/static(?:/_[\d]+\.[\d]+\.[\d]+)?/(.*)$ {
|
||||
alias /home/www-data/web2py/applications/$1/static/$2;
|
||||
expires max;
|
||||
}
|
||||
location ~^\/(?!redmine(.*)) {
|
||||
#uwsgi_pass 127.0.0.1:9001;
|
||||
uwsgi_pass unix:///tmp/web2py.socket;
|
||||
include uwsgi_params;
|
||||
uwsgi_param UWSGI_SCHEME $scheme;
|
||||
uwsgi_param SERVER_SOFTWARE nginx/$nginx_version;
|
||||
}
|
||||
location / {
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_redirect off;
|
||||
|
||||
if (!-f $request_filename) {
|
||||
proxy_pass http://unicorn_server;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
server {
|
||||
listen 443 default_server ssl;
|
||||
charset utf-8;
|
||||
server_name localhost; # $hostname;
|
||||
root /var/www;
|
||||
ssl_certificate /etc/nginx/ssl/self_signed.cert;
|
||||
ssl_certificate_key /etc/nginx/ssl/self_signed.key;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 10m;
|
||||
ssl_ciphers ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA;
|
||||
ssl_protocols SSLv3 TLSv1;
|
||||
keepalive_timeout 70;
|
||||
location ~* /(\w+)/static(?:/_[\d]+\.[\d]+\.[\d]+)?/(.*)$ {
|
||||
alias /home/www-data/web2py/applications/$1/static/$2;
|
||||
expires max;
|
||||
}
|
||||
location ~^\/(?!redmine(.*)) {
|
||||
#uwsgi_pass 127.0.0.1:9001;
|
||||
uwsgi_pass unix:///tmp/web2py.socket;
|
||||
include uwsgi_params;
|
||||
uwsgi_param UWSGI_SCHEME $scheme;
|
||||
uwsgi_param SERVER_SOFTWARE nginx/$nginx_version;
|
||||
}
|
||||
location / {
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_redirect off;
|
||||
|
||||
if (!-f $request_filename) {
|
||||
proxy_pass http://unicorn_server;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}' >/etc/nginx/sites-available/default
|
||||
|
||||
#ln -s /etc/nginx/sites-available/web2py /etc/nginx/sites-enabled/web2py
|
||||
#rm /etc/nginx/sites-enabled/default
|
||||
|
||||
# We copy ssl files we previously created
|
||||
if [ -f /etc/nginx/ssl ]
|
||||
then
|
||||
cp ~/self_signed.* /etc/nginx/ssl/
|
||||
rm ~/self_signed.*
|
||||
else
|
||||
mkdir /etc/nginx/ssl
|
||||
cp ~/self_signed.* /etc/nginx/ssl/
|
||||
rm ~/self_signed.*
|
||||
fi
|
||||
|
||||
pip install setuptools --no-use-wheel --upgrade
|
||||
PIPPATH=`which pip`
|
||||
$PIPPATH install --upgrade uwsgi
|
||||
|
||||
# Prepare folders for uwsgi
|
||||
sudo mkdir /etc/uwsgi
|
||||
sudo mkdir /var/log/uwsgi
|
||||
|
||||
# Create configuration file /etc/uwsgi/web2py.xml
|
||||
echo '<uwsgi>
|
||||
<socket>/tmp/web2py.socket</socket>
|
||||
<pythonpath>/home/www-data/web2py/</pythonpath>
|
||||
<mount>/=wsgihandler:application</mount>
|
||||
<master/>
|
||||
<processes>4</processes>
|
||||
<harakiri>60</harakiri>
|
||||
<reload-mercy>8</reload-mercy>
|
||||
<cpu-affinity>1</cpu-affinity>
|
||||
<stats>/tmp/stats.socket</stats>
|
||||
<max-requests>2000</max-requests>
|
||||
<limit-as>512</limit-as>
|
||||
<reload-on-as>256</reload-on-as>
|
||||
<reload-on-rss>192</reload-on-rss>
|
||||
<uid>www-data</uid>
|
||||
<gid>www-data</gid>
|
||||
<cron>0 0 -1 -1 -1 python /home/www-data/web2py/web2py.py -Q -S welcome -M -R scripts/sessions2trash.py -A -o</cron>
|
||||
<no-orphans/>
|
||||
</uwsgi>' > /etc/uwsgi/web2py.xml
|
||||
|
||||
#Create a configuration file for uwsgi in emperor-mode
|
||||
#for Upstart in /etc/init/uwsgi-emperor.conf
|
||||
echo '# Emperor uWSGI script
|
||||
|
||||
description "uWSGI Emperor"
|
||||
start on runlevel [2345]
|
||||
stop on runlevel [06]
|
||||
##
|
||||
#remove the comments in the next section to enable static file compression for the welcome app
|
||||
#in that case, turn on gzip_static on; on /etc/nginx/nginx.conf
|
||||
##
|
||||
#pre-start script
|
||||
# python /home/www-data/web2py/web2py.py -S welcome -R scripts/zip_static_files.py
|
||||
# chown -R www-data:www-data /home/www-data/web2py/*
|
||||
#end script
|
||||
respawn
|
||||
exec uwsgi --master --die-on-term --emperor /etc/uwsgi --logto /var/log/uwsgi/uwsgi.log
|
||||
' > /etc/init/uwsgi-emperor.conf
|
||||
# Install Web2py
|
||||
mkdir /home/www-data
|
||||
cd /home/www-data
|
||||
wget http://web2py.com/examples/static/web2py_src.zip
|
||||
unzip web2py_src.zip
|
||||
rm web2py_src.zip
|
||||
chown -R www-data:www-data web2py
|
||||
cd /home/www-data/web2py
|
||||
mv handlers/wsgihandler.py wsgihandler.py
|
||||
sudo -u www-data python -c "from gluon.main import save_password; save_password('$PW',443)"
|
||||
/etc/init.d/redmine start
|
||||
start uwsgi-emperor
|
||||
/etc/init.d/nginx restart
|
||||
ufw allow 80 # Or check your firewall configuration
|
||||
@@ -1,96 +0,0 @@
|
||||
#
|
||||
# Author: Christopher Steel
|
||||
# Organization: Voice of Access
|
||||
# Date: 2010-11-24
|
||||
# License: Same as Web2py, MIT / GNU
|
||||
# Email: Christopher DOT Steel AT Voice of Access DOT org
|
||||
#
|
||||
# This script will :
|
||||
# download and install virtualenv
|
||||
# start a virtual environment
|
||||
# move into the virtual environment
|
||||
# download and install latest stable version of web2py
|
||||
# start web2py in the virtual environment
|
||||
#
|
||||
# To disactivate the virtual environment, shut down web2py
|
||||
# and type 'disactivate' at the command line.
|
||||
#
|
||||
# Testing:
|
||||
# OS X
|
||||
# should work on POSIX systems
|
||||
#
|
||||
# Usage:
|
||||
# create a directory to hold your virtual environments, for example
|
||||
# /home/user_name/virtual_environments
|
||||
# place this script in the directory and make it executable
|
||||
# chmod +x web2py-install-virtualenv.sh
|
||||
customize the variables below to meet your needs
|
||||
# execute from terminal
|
||||
# ./web2py-install-virtualenv.sh
|
||||
# relax...
|
||||
|
||||
################ VARIABLES
|
||||
# Change to reflect version changes etc.
|
||||
#
|
||||
# name for your virtual environment
|
||||
ENV=VIRTUAL_ENV
|
||||
# version to install
|
||||
APP_NAME=virtualenv
|
||||
VER=1.5.1
|
||||
DIR=${APP_NAME}-${VER}
|
||||
EXT=tar.gz
|
||||
ARCHIVE=${APP_NAME}-${VER}.${EXT}
|
||||
# md5 sum, see end of url from pypi
|
||||
MD5_SUM=3daa1f449d5d2ee03099484cecb1c2b7
|
||||
################
|
||||
#
|
||||
echo 'downloading' ${ARCHIVE}
|
||||
echo '================================'
|
||||
echo `wget http://pypi.python.org/packages/source/v/virtualenv/${ARCHIVE}`
|
||||
md5 ${ARCHIVE}
|
||||
echo 'MD5 ('${ARCHIVE}') =' ${MD5_SUM}
|
||||
echo 'unarchive' ${ARCHIVE}
|
||||
echo '================================='
|
||||
tar xvfz ${ARCHIVE}
|
||||
|
||||
echo ' comparing md5 sums'
|
||||
echo '================================='
|
||||
md5 ${ARCHIVE}
|
||||
echo 'MD5 ('${ARCHIVE}') =' ${MD5_SUM}
|
||||
|
||||
#echo 'installing compatibility modules'
|
||||
#echo '================================'
|
||||
#virtualenv/bin/easy_install -U pysqlite hashlib
|
||||
|
||||
#echo 'Installing distribute'
|
||||
#echo '====================='
|
||||
#echo 'Creating Environment'
|
||||
#echo '====================='
|
||||
#echo `python ./${DIRAPP_NAME}-${VER}/virtualenv.py --distribute ${ENV}`
|
||||
|
||||
echo 'Start virtual environment'
|
||||
echo '========================='
|
||||
virtualenv --no-site-packages ${ENV}
|
||||
|
||||
RUN_THIS='source ${ENV}/bin/activate'
|
||||
`echo source ${ENV}/bin/activate`
|
||||
|
||||
echo 'Moving into virtual environment directory'
|
||||
echo '========================================='
|
||||
cd ${ENV}
|
||||
|
||||
echo 'downloading web2py'
|
||||
echo '=================='
|
||||
wget http://web2py.com/examples/static/web2py_src.zip
|
||||
unzip web2py_src.zip
|
||||
cd web2py
|
||||
|
||||
echo 'to deactivate your virtual environment'
|
||||
echo 'shutdown web2py and then type "deactivate"'
|
||||
echo '=========================================='
|
||||
read -p "Press any key to start web2py…"
|
||||
|
||||
|
||||
echo 'starting web2py'
|
||||
echo '==============='
|
||||
../bin/python2.5 web2py.py
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
echo 'setup-web2py-nginx-uwsgi-ubuntu-precise.sh'
|
||||
echo 'Requires Ubuntu > 12.04 and installs Nginx + uWSGI + Web2py'
|
||||
echo 'Requires Ubuntu > 12.04 or Debian >= 8 and installs Nginx + uWSGI + Web2py'
|
||||
# Check if user has root privileges
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo "You must run the script as root or using sudo"
|
||||
@@ -137,6 +137,26 @@ fi
|
||||
# Prepare folders for uwsgi
|
||||
sudo mkdir /etc/uwsgi
|
||||
sudo mkdir /var/log/uwsgi
|
||||
sudo mkdir /etc/systemd
|
||||
sudo mkdir /etc/systemd/system
|
||||
|
||||
#uWSGI Emperor
|
||||
echo '[Unit]
|
||||
Description = uWSGI Emperor
|
||||
After = syslog.target
|
||||
|
||||
[Service]
|
||||
ExecStart = /usr/local/bin/uwsgi --ini /etc/uwsgi/web2py.ini
|
||||
RuntimeDirectory = uwsgi
|
||||
Restart = always
|
||||
KillSignal = SIGQUIT
|
||||
Type = notify
|
||||
StandardError = syslog
|
||||
NotifyAccess = all
|
||||
|
||||
[Install]
|
||||
WantedBy = multi-user.target
|
||||
' > /etc/systemd/system/emperor.uwsgi.service
|
||||
|
||||
# Create configuration file /etc/uwsgi/web2py.ini
|
||||
echo '[uwsgi]
|
||||
@@ -192,17 +212,18 @@ if [ "$nopassword" -eq 0 ]
|
||||
then
|
||||
sudo -u www-data python -c "from gluon.main import save_password; save_password('$PW',443)"
|
||||
fi
|
||||
start uwsgi-emperor
|
||||
systemctl enable emperor.uwsgi.service
|
||||
systemctl start emperor.uwsgi.service
|
||||
/etc/init.d/nginx restart
|
||||
|
||||
echo <<EOF
|
||||
you can reload uwsgi with
|
||||
|
||||
restart uwsgi-emperor
|
||||
systemctl restart emperor.uwsgi
|
||||
|
||||
and stop it with
|
||||
|
||||
stop uwsgi-emperor
|
||||
systemctl stop emperor.uwsgi
|
||||
|
||||
to reload web2py only (without restarting uwsgi)
|
||||
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
crontab -e
|
||||
* 3 * * * root path/to/this/file
|
||||
"""
|
||||
|
||||
USER = 'www-data'
|
||||
TMPFILENAME = 'web2py_src_update.zip'
|
||||
|
||||
import sys
|
||||
import os
|
||||
import urllib
|
||||
import zipfile
|
||||
|
||||
if len(sys.argv) > 1 and sys.argv[1] == 'nightly':
|
||||
version = 'http://web2py.com/examples/static/nightly/web2py_src.zip'
|
||||
else:
|
||||
version = 'http://web2py.com/examples/static/web2py_src.zip'
|
||||
|
||||
realpath = os.path.realpath(__file__)
|
||||
path = os.path.dirname(os.path.dirname(os.path.dirname(realpath)))
|
||||
os.chdir(path)
|
||||
try:
|
||||
old_version = open('web2py/VERSION', 'r').read().strip()
|
||||
except IOError:
|
||||
old_version = ''
|
||||
open(TMPFILENAME, 'wb').write(urllib.urlopen(version).read())
|
||||
new_version = zipfile.ZipFile(TMPFILENAME).read('web2py/VERSION').strip()
|
||||
if new_version > old_version:
|
||||
os.system('sudo -u %s unzip -o %s' % (USER, TMPFILENAME))
|
||||
os.system('apachectl restart | apache2ctl restart')
|
||||
@@ -1,41 +0,0 @@
|
||||
import os
|
||||
import sys
|
||||
import glob
|
||||
sys.path.append(os.path.join(os.path.split(__file__)[0],'..'))
|
||||
from gluon.html import CODE
|
||||
|
||||
def main(path):
|
||||
models = glob.glob(os.path.join(path,'models','*.py'))
|
||||
controllers = glob.glob(os.path.join(path,'controllers','*.py'))
|
||||
views = glob.glob(os.path.join(path,'views','*.html'))
|
||||
modules = glob.glob(os.path.join(path,'modules','*.py'))
|
||||
models.sort()
|
||||
controllers.sort()
|
||||
views.sort()
|
||||
modules.sort()
|
||||
print '<html><body>'
|
||||
print '<h1>Models</h1>'
|
||||
for filename in models:
|
||||
print '<h2>%s</h2>' % filename[len(path):]
|
||||
print CODE(open(filename).read(),language='web2py').xml()
|
||||
print '<h1>Layout Views</h1>'
|
||||
for filename in views:
|
||||
print '<h2>%s</h2>' % filename[len(path):]
|
||||
print CODE(open(filename).read(),language='html').xml()
|
||||
print '<h1>Controllers and Views</h1>'
|
||||
for filename in controllers:
|
||||
print '<h2>%s</h2>' % filename[len(path):]
|
||||
print CODE(open(filename).read(),language='web2py')
|
||||
views = glob.glob(os.path.join(path,'views','*','*.html'))
|
||||
views.sort()
|
||||
for filename in views:
|
||||
print '<h2>%s</h2>' % filename[len(path):]
|
||||
print CODE(open(filename).read(),language='html').xml()
|
||||
print '<h1>Modules</h1>'
|
||||
for filename in modules:
|
||||
print '<h2>%s</h2>' % filename[len(path):]
|
||||
print CODE(open(filename).read(),language='python').xml()
|
||||
print '</body></html>'
|
||||
|
||||
if __name__=='__main__':
|
||||
main(sys.argv[1])
|
||||
Reference in New Issue
Block a user