Compare commits
250 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
666a389718 | ||
|
|
6cd2bf9fea | ||
|
|
3ad7ea6df8 | ||
|
|
cb75a96e2c | ||
|
|
70965f4b69 | ||
|
|
29042f08a1 | ||
|
|
379db55111 | ||
|
|
4a65e773ce | ||
|
|
2829a91ff7 | ||
|
|
083e75bfb1 | ||
|
|
8f95e6ebb3 | ||
|
|
6b1826e8da | ||
|
|
f76598232a | ||
|
|
193149abac | ||
|
|
8c155d9f76 | ||
|
|
2061cc3674 | ||
|
|
832d6c2e97 | ||
|
|
e0870bbdb2 | ||
|
|
297983f411 | ||
|
|
1e9872c015 | ||
|
|
7ddf0af81b | ||
|
|
359bae6d30 | ||
|
|
d01add8f2b | ||
|
|
752a1c7df6 | ||
|
|
0d24d1e0d2 | ||
|
|
31fcf51506 | ||
|
|
f3c5ed8ee6 | ||
|
|
76d77439b7 | ||
|
|
2b428c7eb9 | ||
|
|
106d4be274 | ||
|
|
8e5d6bc467 | ||
|
|
e21aca045a | ||
|
|
a359afb799 | ||
|
|
41fb55cb01 | ||
|
|
f8cc65dfae | ||
|
|
e94368a356 | ||
|
|
2c8f2173a3 | ||
|
|
65eb1e9cb7 | ||
|
|
69ecbdfecc | ||
|
|
6c622b4100 | ||
|
|
59b645c399 | ||
|
|
134723a54b | ||
|
|
c482fed2c9 | ||
|
|
f60846ea2e | ||
|
|
cb23f8635a | ||
|
|
19f8f6bf3c | ||
|
|
b036cb04ff | ||
|
|
050efa339d | ||
|
|
faeff098fe | ||
|
|
4e298ed7d8 | ||
|
|
c810e4491a | ||
|
|
edbf45e542 | ||
|
|
caee53e778 | ||
|
|
55281650e2 | ||
|
|
ff17b551b4 | ||
|
|
4c3ab339cd | ||
|
|
99d64722a1 | ||
|
|
1b12bcb5d9 | ||
|
|
7a083865dd | ||
|
|
794b6bcb7b | ||
|
|
64ccd9043e | ||
|
|
18af4e92b0 | ||
|
|
cfbae50248 | ||
|
|
20576684dd | ||
|
|
1c2bdd1654 | ||
|
|
93aa1a13c6 | ||
|
|
4cd86a397c | ||
|
|
efcb203dd9 | ||
|
|
c859785edc | ||
|
|
41a4de081f | ||
|
|
82a8d41ac6 | ||
|
|
d274389a33 | ||
|
|
faecb124cc | ||
|
|
ce2d958f9a | ||
|
|
e37c8ff87f | ||
|
|
fd2136875e | ||
|
|
35d56ec3f0 | ||
|
|
310528ea10 | ||
|
|
98ee81606b | ||
|
|
6731eb9b2d | ||
|
|
e833783fb0 | ||
|
|
9d13d297cb | ||
|
|
2967969add | ||
|
|
060eddf812 | ||
|
|
473d2d5d09 | ||
|
|
13cc8df4be | ||
|
|
39edd4679d | ||
|
|
4cd45abfdd | ||
|
|
cc297a06d3 | ||
|
|
341a5e0c40 | ||
|
|
d967e23791 | ||
|
|
98610df1d4 | ||
|
|
7dd99cf3a1 | ||
|
|
9434baba11 | ||
|
|
4cbdf612af | ||
|
|
0c6eaf536a | ||
|
|
48870b1dd1 | ||
|
|
56121a9c9d | ||
|
|
0e0ae1b5be | ||
|
|
e956d83aa2 | ||
|
|
bfce480a91 | ||
|
|
3df446c306 | ||
|
|
e10fd68f90 | ||
|
|
cfd5842538 | ||
|
|
56e95fd640 | ||
|
|
52cf0dd147 | ||
|
|
311404d03c | ||
|
|
5900b3f1c7 | ||
|
|
45bc26f5eb | ||
|
|
45fc08e4a4 | ||
|
|
e3aa776f5a | ||
|
|
7101762082 | ||
|
|
34bbb376be | ||
|
|
391bdf5cd4 | ||
|
|
1e4f533008 | ||
|
|
dfd35b1a62 | ||
|
|
c7f6545f8a | ||
|
|
71c6343aab | ||
|
|
65005ef93a | ||
|
|
7d59bcab72 | ||
|
|
3f200c245c | ||
|
|
378a696bfe | ||
|
|
200a953849 | ||
|
|
0e95fba28d | ||
|
|
907525efd7 | ||
|
|
d490b794db | ||
|
|
f04cc69abe | ||
|
|
c93ce5dbab | ||
|
|
23c65eb518 | ||
|
|
2cf0e4a7ff | ||
|
|
c2a23d03c2 | ||
|
|
09fb170a83 | ||
|
|
20e2d9aa57 | ||
|
|
4192405444 | ||
|
|
6bbafc5920 | ||
|
|
1caf7b5140 | ||
|
|
10e0ff71bf | ||
|
|
5a0aec5b1d | ||
|
|
9964add97c | ||
|
|
d5f04551f2 | ||
|
|
8ba8eb58ed | ||
|
|
14cacefa96 | ||
|
|
6d6a4d3d33 | ||
|
|
e19f280e1b | ||
|
|
40e5e42ecc | ||
|
|
1741a59d3a | ||
|
|
7787317d06 | ||
|
|
76b3906ade | ||
|
|
efcf8c0c95 | ||
|
|
12bb4a8d93 | ||
|
|
e56e376894 | ||
|
|
4b4ada4137 | ||
|
|
eb94780cd4 | ||
|
|
750f963796 | ||
|
|
08639e6691 | ||
|
|
1a959baa72 | ||
|
|
227930e25b | ||
|
|
88ce19d99f | ||
|
|
257733e0cc | ||
|
|
e0b147ead0 | ||
|
|
24283e7eeb | ||
|
|
afe3f306e7 | ||
|
|
c4a68e9e5a | ||
|
|
67c35e5327 | ||
|
|
53f4408652 | ||
|
|
d72d5c64e2 | ||
|
|
9ca4b48f95 | ||
|
|
338331aa54 | ||
|
|
42c0b7b0fa | ||
|
|
28b9d322a2 | ||
|
|
38de99fc9c | ||
|
|
a4416bd11f | ||
|
|
27cbd242b2 | ||
|
|
c790b79393 | ||
|
|
7646dc11fe | ||
|
|
104ec5ba73 | ||
|
|
53a0718a78 | ||
|
|
892f123975 | ||
|
|
461daca00e | ||
|
|
09c0069b43 | ||
|
|
42de43d052 | ||
|
|
6ce51fa099 | ||
|
|
51728fb192 | ||
|
|
d438b510df | ||
|
|
2d669a50b2 | ||
|
|
4aabf3c69c | ||
|
|
69f9cf28df | ||
|
|
81cb51bb8d | ||
|
|
371f97e050 | ||
|
|
3204447a74 | ||
|
|
36303e338d | ||
|
|
b0b2fd7804 | ||
|
|
a37206e259 | ||
|
|
ff94a22826 | ||
|
|
8244472cb2 | ||
|
|
15dd46a91a | ||
|
|
c379b00918 | ||
|
|
9bf856f6e6 | ||
|
|
37df0a9338 | ||
|
|
e6aaca1728 | ||
|
|
bbbee21b0d | ||
|
|
6fb6f441d5 | ||
|
|
cda7c66637 | ||
|
|
53122bfa9f | ||
|
|
1fecd35bb7 | ||
|
|
85058bd847 | ||
|
|
40c02651ae | ||
|
|
8d72dc7bc4 | ||
|
|
46d630a2c0 | ||
|
|
7e040a4177 | ||
|
|
483de0fc30 | ||
|
|
09277868d2 | ||
|
|
86a19c25a8 | ||
|
|
1715b0c378 | ||
|
|
3599863304 | ||
|
|
91dc4f1d03 | ||
|
|
4b124cc214 | ||
|
|
0ed01e5a21 | ||
|
|
b7192d706c | ||
|
|
557e4892b0 | ||
|
|
b61b0bf3ad | ||
|
|
3a6a8af9f6 | ||
|
|
5b7167436b | ||
|
|
8d4b4430de | ||
|
|
9d4cb09fdf | ||
|
|
14bcad629e | ||
|
|
645c3b10dd | ||
|
|
16f9222847 | ||
|
|
b7e7c8caf2 | ||
|
|
15cedc0269 | ||
|
|
b14831613e | ||
|
|
b673593683 | ||
|
|
7703d959ef | ||
|
|
cb47024f2b | ||
|
|
55cbc1830a | ||
|
|
3f61d725c4 | ||
|
|
bc8bc03fd2 | ||
|
|
cbc20782ae | ||
|
|
af290117d4 | ||
|
|
42a662a7ad | ||
|
|
2ead96313b | ||
|
|
fcd9e0d5c6 | ||
|
|
593540e467 | ||
|
|
f66d0e1200 | ||
|
|
fa1c719c96 | ||
|
|
77b66d6015 | ||
|
|
8c14ba01f7 | ||
|
|
ad87d196e5 | ||
|
|
99a6dbeac2 | ||
|
|
b05daddc5c |
24
.travis.yml
24
.travis.yml
@@ -10,6 +10,9 @@ env:
|
||||
- DB=sqlite:memory
|
||||
- DB=mysql://root:@localhost/test_w2p
|
||||
- DB=postgres://postgres:@localhost/test_w2p
|
||||
- DB=google:datastore
|
||||
- DB=mongodb://mongodb:mongodb@localhost/test_w2p
|
||||
- DB=imap://imap:imap@localhost:993
|
||||
before_script:
|
||||
- if [[ $TRAVIS_PYTHON_VERSION != '2.7' ]]; then pip install unittest2; fi
|
||||
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pip install coverage; fi;
|
||||
@@ -18,6 +21,19 @@ before_script:
|
||||
- if [[ $TRAVIS_PYTHON_VERSION == '2.5' ]]; then pip install pysqlite; fi
|
||||
- if [[ $DB == mysql* ]]; then mysql -e 'create database test_w2p;'; fi
|
||||
- if [[ $DB == postgres* ]]; then psql -c 'create database test_w2p;' -U postgres; fi
|
||||
|
||||
# Install last sdk for app engine
|
||||
- if [[ $DB == google* ]]; then wget http://googleappengine.googlecode.com/svn/trunk/python/VERSION -O ./GAEVERSION; fi
|
||||
- if [[ $DB == google* ]]; then GAERELEASE=$(cat ./GAEVERSION | grep -i release); fi
|
||||
- if [[ $DB == google* ]]; then GAERELEASE=${GAERELEASE#*\"}; fi
|
||||
- if [[ $DB == google* ]]; then GAERELEASE=${GAERELEASE%\"}; fi
|
||||
- if [[ $DB == google* ]]; then wget http://googleappengine.googlecode.com/files/google_appengine_$GAERELEASE.zip -nv; fi
|
||||
- if [[ $DB == google* ]]; then unzip -q google_appengine_$GAERELEASE.zip; fi
|
||||
- if [[ $DB == google* ]]; then mv -f ./google_appengine/google ./google; fi
|
||||
|
||||
- if [[ $DB == mongodb* ]]; then pip install pymongo; fi
|
||||
- if [[ $DB == mongodb* ]]; then mongo test_w2p --eval 'db.addUser("mongodb", "mongodb");'; fi
|
||||
|
||||
#Temporal solution to travis issue #155
|
||||
- sudo chmod 777 /dev/shm
|
||||
- sudo rm -rf /dev/shm && sudo ln -s /run/shm /dev/shm
|
||||
@@ -27,6 +43,11 @@ matrix:
|
||||
env: DB=postgres://postgres:@localhost/test_w2p
|
||||
- python: 'pypy'
|
||||
env: DB=mysql://root:@localhost/test_w2p
|
||||
- python: 'pypy'
|
||||
env: DB=google:datastore
|
||||
- python: '2.6'
|
||||
env: DB=google:datastore
|
||||
|
||||
|
||||
script: export COVERAGE_PROCESS_START=gluon/tests/coverage.ini; ./web2py.py --run_system_tests --with_coverage
|
||||
after_success:
|
||||
@@ -35,3 +56,6 @@ after_success:
|
||||
|
||||
notifications:
|
||||
email: true
|
||||
|
||||
services: mongodb
|
||||
|
||||
|
||||
23
CHANGELOG
23
CHANGELOG
@@ -1,3 +1,26 @@
|
||||
## 2.9.1
|
||||
|
||||
- jquery 1.11
|
||||
- codemirror 3.21, thanks Paolo Valleri
|
||||
- fixed a security issue with sessions in database
|
||||
- fixed security issue with redirect after expired login, thanks André Kablu
|
||||
- cleaner DAL and rname integration, thanks niphlod and Michele
|
||||
- added mongodb and imap tests for dal, thanks Alan
|
||||
- NoSQL dal tests, thanks Alan
|
||||
- better docstrings, thanks Niphlod
|
||||
- allow URL(...,language=...) with parametric router, thanks Jonathan
|
||||
- allow non-expiration of gae-memcache, thanks crimsoncantab
|
||||
- MARKMIN(...,_class='...'), thanks Luca
|
||||
- better transliteration in building slugs
|
||||
- autolink emails
|
||||
- new Janrain API, thanks PeterQ2
|
||||
- enable admin app for GAE (experimental), thanks Alan
|
||||
- many bug fixes
|
||||
- invalidate function in web2py.js, thanks Paolo
|
||||
- DAL(...,adapter_args=dict(engine='MyISAM'))
|
||||
- todolist panel in admin editor, thanks Paolo Valleri
|
||||
- enable killing processed in windows, thanks Yair
|
||||
|
||||
## 2.8.1
|
||||
|
||||
- no more winservice (use nssm instead)
|
||||
|
||||
2
Makefile
2
Makefile
@@ -30,7 +30,7 @@ update:
|
||||
echo "remember that pymysql was tweaked"
|
||||
src:
|
||||
### Use semantic versioning
|
||||
echo 'Version 2.8.2-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION
|
||||
echo 'Version 2.9.2-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION
|
||||
### rm -f all junk files
|
||||
make clean
|
||||
### clean up baisc apps
|
||||
|
||||
2
VERSION
2
VERSION
@@ -1 +1 @@
|
||||
Version 2.8.2-stable+timestamp.2013.11.28.07.51.37
|
||||
Version 2.9.2-stable+timestamp.2014.03.02.17.46.39
|
||||
|
||||
@@ -16,6 +16,8 @@ try:
|
||||
except ImportError:
|
||||
pgv = None
|
||||
|
||||
is_gae = request.env.web2py_runtime_gae or False
|
||||
|
||||
# ## critical --- make a copy of the environment
|
||||
|
||||
global_env = copy.copy(globals())
|
||||
@@ -359,36 +361,43 @@ def state():
|
||||
|
||||
|
||||
def ccache():
|
||||
cache.ram.initialize()
|
||||
cache.disk.initialize()
|
||||
if is_gae:
|
||||
form = FORM(
|
||||
P(TAG.BUTTON(T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")))
|
||||
else:
|
||||
cache.ram.initialize()
|
||||
cache.disk.initialize()
|
||||
|
||||
form = FORM(
|
||||
P(TAG.BUTTON(
|
||||
T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
|
||||
P(TAG.BUTTON(
|
||||
T("Clear RAM"), _type="submit", _name="ram", _value="ram")),
|
||||
P(TAG.BUTTON(
|
||||
T("Clear DISK"), _type="submit", _name="disk", _value="disk")),
|
||||
)
|
||||
form = FORM(
|
||||
P(TAG.BUTTON(
|
||||
T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
|
||||
P(TAG.BUTTON(
|
||||
T("Clear RAM"), _type="submit", _name="ram", _value="ram")),
|
||||
P(TAG.BUTTON(
|
||||
T("Clear DISK"), _type="submit", _name="disk", _value="disk")),
|
||||
)
|
||||
|
||||
if form.accepts(request.vars, session):
|
||||
clear_ram = False
|
||||
clear_disk = False
|
||||
session.flash = ""
|
||||
if request.vars.yes:
|
||||
clear_ram = clear_disk = True
|
||||
if request.vars.ram:
|
||||
clear_ram = True
|
||||
if request.vars.disk:
|
||||
clear_disk = True
|
||||
|
||||
if clear_ram:
|
||||
cache.ram.clear()
|
||||
session.flash += T("Ram Cleared")
|
||||
if clear_disk:
|
||||
cache.disk.clear()
|
||||
session.flash += T("Disk Cleared")
|
||||
|
||||
if is_gae:
|
||||
if request.vars.yes:
|
||||
cache.ram.clear()
|
||||
session.flash += T("Cache Cleared")
|
||||
else:
|
||||
clear_ram = False
|
||||
clear_disk = False
|
||||
if request.vars.yes:
|
||||
clear_ram = clear_disk = True
|
||||
if request.vars.ram:
|
||||
clear_ram = True
|
||||
if request.vars.disk:
|
||||
clear_disk = True
|
||||
if clear_ram:
|
||||
cache.ram.clear()
|
||||
session.flash += T("Ram Cleared")
|
||||
if clear_disk:
|
||||
cache.disk.clear()
|
||||
session.flash += T("Disk Cleared")
|
||||
redirect(URL(r=request))
|
||||
|
||||
try:
|
||||
@@ -414,6 +423,7 @@ def ccache():
|
||||
'oldest': time.time(),
|
||||
'keys': []
|
||||
}
|
||||
|
||||
disk = copy.copy(ram)
|
||||
total = copy.copy(ram)
|
||||
disk['keys'] = []
|
||||
@@ -428,72 +438,81 @@ def ccache():
|
||||
|
||||
return (hours, minutes, seconds)
|
||||
|
||||
for key, value in cache.ram.storage.iteritems():
|
||||
if isinstance(value, dict):
|
||||
ram['hits'] = value['hit_total'] - value['misses']
|
||||
ram['misses'] = value['misses']
|
||||
try:
|
||||
ram['ratio'] = ram['hits'] * 100 / value['hit_total']
|
||||
except (KeyError, ZeroDivisionError):
|
||||
ram['ratio'] = 0
|
||||
else:
|
||||
if hp:
|
||||
ram['bytes'] += hp.iso(value[1]).size
|
||||
ram['objects'] += hp.iso(value[1]).count
|
||||
ram['entries'] += 1
|
||||
if value[0] < ram['oldest']:
|
||||
ram['oldest'] = value[0]
|
||||
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
|
||||
folder = os.path.join(request.folder,'cache')
|
||||
if not os.path.exists(folder):
|
||||
os.mkdir(folder)
|
||||
locker = open(os.path.join(folder, 'cache.lock'), 'a')
|
||||
portalocker.lock(locker, portalocker.LOCK_EX)
|
||||
disk_storage = shelve.open(
|
||||
os.path.join(folder, 'cache.shelve'))
|
||||
try:
|
||||
for key, value in disk_storage.items():
|
||||
if is_gae:
|
||||
gae_stats = cache.ram.client.get_stats()
|
||||
try:
|
||||
gae_stats['ratio'] = ((gae_stats['hits'] * 100) /
|
||||
(gae_stats['hits'] + gae_stats['misses']))
|
||||
except ZeroDivisionError:
|
||||
gae_stats['ratio'] = T("?")
|
||||
gae_stats['oldest'] = GetInHMS(time.time() - gae_stats['oldest_item_age'])
|
||||
total.update(gae_stats)
|
||||
else:
|
||||
for key, value in cache.ram.storage.iteritems():
|
||||
if isinstance(value, dict):
|
||||
disk['hits'] = value['hit_total'] - value['misses']
|
||||
disk['misses'] = value['misses']
|
||||
ram['hits'] = value['hit_total'] - value['misses']
|
||||
ram['misses'] = value['misses']
|
||||
try:
|
||||
disk['ratio'] = disk['hits'] * 100 / value['hit_total']
|
||||
ram['ratio'] = ram['hits'] * 100 / value['hit_total']
|
||||
except (KeyError, ZeroDivisionError):
|
||||
disk['ratio'] = 0
|
||||
ram['ratio'] = 0
|
||||
else:
|
||||
if hp:
|
||||
disk['bytes'] += hp.iso(value[1]).size
|
||||
disk['objects'] += hp.iso(value[1]).count
|
||||
disk['entries'] += 1
|
||||
if value[0] < disk['oldest']:
|
||||
disk['oldest'] = value[0]
|
||||
disk['keys'].append((key, GetInHMS(time.time() - value[0])))
|
||||
ram['bytes'] += hp.iso(value[1]).size
|
||||
ram['objects'] += hp.iso(value[1]).count
|
||||
ram['entries'] += 1
|
||||
if value[0] < ram['oldest']:
|
||||
ram['oldest'] = value[0]
|
||||
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
|
||||
folder = os.path.join(request.folder,'cache')
|
||||
if not os.path.exists(folder):
|
||||
os.mkdir(folder)
|
||||
locker = open(os.path.join(folder, 'cache.lock'), 'a')
|
||||
portalocker.lock(locker, portalocker.LOCK_EX)
|
||||
disk_storage = shelve.open(
|
||||
os.path.join(folder, 'cache.shelve'))
|
||||
try:
|
||||
for key, value in disk_storage.items():
|
||||
if isinstance(value, dict):
|
||||
disk['hits'] = value['hit_total'] - value['misses']
|
||||
disk['misses'] = value['misses']
|
||||
try:
|
||||
disk['ratio'] = disk['hits'] * 100 / value['hit_total']
|
||||
except (KeyError, ZeroDivisionError):
|
||||
disk['ratio'] = 0
|
||||
else:
|
||||
if hp:
|
||||
disk['bytes'] += hp.iso(value[1]).size
|
||||
disk['objects'] += hp.iso(value[1]).count
|
||||
disk['entries'] += 1
|
||||
if value[0] < disk['oldest']:
|
||||
disk['oldest'] = value[0]
|
||||
disk['keys'].append((key, GetInHMS(time.time() - value[0])))
|
||||
finally:
|
||||
portalocker.unlock(locker)
|
||||
locker.close()
|
||||
disk_storage.close()
|
||||
|
||||
finally:
|
||||
portalocker.unlock(locker)
|
||||
locker.close()
|
||||
disk_storage.close()
|
||||
|
||||
total['entries'] = ram['entries'] + disk['entries']
|
||||
total['bytes'] = ram['bytes'] + disk['bytes']
|
||||
total['objects'] = ram['objects'] + disk['objects']
|
||||
total['hits'] = ram['hits'] + disk['hits']
|
||||
total['misses'] = ram['misses'] + disk['misses']
|
||||
total['keys'] = ram['keys'] + disk['keys']
|
||||
try:
|
||||
total['ratio'] = total['hits'] * 100 / (total['hits'] +
|
||||
total['entries'] = ram['entries'] + disk['entries']
|
||||
total['bytes'] = ram['bytes'] + disk['bytes']
|
||||
total['objects'] = ram['objects'] + disk['objects']
|
||||
total['hits'] = ram['hits'] + disk['hits']
|
||||
total['misses'] = ram['misses'] + disk['misses']
|
||||
total['keys'] = ram['keys'] + disk['keys']
|
||||
try:
|
||||
total['ratio'] = total['hits'] * 100 / (total['hits'] +
|
||||
total['misses'])
|
||||
except (KeyError, ZeroDivisionError):
|
||||
total['ratio'] = 0
|
||||
except (KeyError, ZeroDivisionError):
|
||||
total['ratio'] = 0
|
||||
|
||||
if disk['oldest'] < ram['oldest']:
|
||||
total['oldest'] = disk['oldest']
|
||||
else:
|
||||
total['oldest'] = ram['oldest']
|
||||
if disk['oldest'] < ram['oldest']:
|
||||
total['oldest'] = disk['oldest']
|
||||
else:
|
||||
total['oldest'] = ram['oldest']
|
||||
|
||||
ram['oldest'] = GetInHMS(time.time() - ram['oldest'])
|
||||
disk['oldest'] = GetInHMS(time.time() - disk['oldest'])
|
||||
total['oldest'] = GetInHMS(time.time() - total['oldest'])
|
||||
ram['oldest'] = GetInHMS(time.time() - ram['oldest'])
|
||||
disk['oldest'] = GetInHMS(time.time() - disk['oldest'])
|
||||
total['oldest'] = GetInHMS(time.time() - total['oldest'])
|
||||
|
||||
def key_table(keys):
|
||||
return TABLE(
|
||||
@@ -502,9 +521,10 @@ def ccache():
|
||||
**dict(_class='cache-keys',
|
||||
_style="border-collapse: separate; border-spacing: .5em;"))
|
||||
|
||||
ram['keys'] = key_table(ram['keys'])
|
||||
disk['keys'] = key_table(disk['keys'])
|
||||
total['keys'] = key_table(total['keys'])
|
||||
if not is_gae:
|
||||
ram['keys'] = key_table(ram['keys'])
|
||||
disk['keys'] = key_table(disk['keys'])
|
||||
total['keys'] = key_table(total['keys'])
|
||||
|
||||
return dict(form=form, total=total,
|
||||
ram=ram, disk=disk, object_stats=hp != False)
|
||||
|
||||
@@ -54,9 +54,13 @@ def interact():
|
||||
filename = web_debugger.filename
|
||||
lineno = web_debugger.lineno
|
||||
if filename:
|
||||
# prevent IOError 2 on some circuntances (EAFP instead of os.access)
|
||||
try:
|
||||
lines = open(filename).readlines()
|
||||
except:
|
||||
lines = ""
|
||||
lines = dict([(i + 1, l) for (i, l) in enumerate(
|
||||
[l.strip("\n").strip("\r") for l
|
||||
in open(filename).readlines()])])
|
||||
[l.strip("\n").strip("\r") for l in lines])])
|
||||
filename = os.path.basename(filename)
|
||||
else:
|
||||
lines = {}
|
||||
|
||||
@@ -13,6 +13,7 @@ from gluon.admin import *
|
||||
from gluon.fileutils import abspath, read_file, write_file
|
||||
from gluon.utils import web2py_uuid
|
||||
from gluon.tools import Config
|
||||
from gluon.compileapp import find_exposed_functions
|
||||
from glob import glob
|
||||
import shutil
|
||||
import platform
|
||||
@@ -30,10 +31,18 @@ from gluon.languages import (read_possible_languages, read_dict, write_dict,
|
||||
read_plural_dict, write_plural_dict)
|
||||
|
||||
|
||||
if DEMO_MODE and request.function in ['change_password', 'pack', 'pack_custom','pack_plugin', 'upgrade_web2py', 'uninstall', 'cleanup', 'compile_app', 'remove_compiled_app', 'delete', 'delete_plugin', 'create_file', 'upload_file', 'update_languages', 'reload_routes', 'git_push', 'git_pull']:
|
||||
if DEMO_MODE and request.function in ['change_password', 'pack',
|
||||
'pack_custom','pack_plugin', 'upgrade_web2py', 'uninstall',
|
||||
'cleanup', 'compile_app', 'remove_compiled_app', 'delete',
|
||||
'delete_plugin', 'create_file', 'upload_file', 'update_languages',
|
||||
'reload_routes', 'git_push', 'git_pull', 'install_plugin']:
|
||||
session.flash = T('disabled in demo mode')
|
||||
redirect(URL('site'))
|
||||
|
||||
if is_gae and request.function in ('edit', 'edit_language',
|
||||
'edit_plurals', 'update_languages', 'create_file', 'install_plugin'):
|
||||
session.flash = T('disabled in GAE mode')
|
||||
redirect(URL('site'))
|
||||
|
||||
if not is_manager() and request.function in ['change_password', 'upgrade_web2py']:
|
||||
session.flash = T('disabled in multi user mode')
|
||||
@@ -63,10 +72,12 @@ def log_progress(app, mode='EDIT', filename=None, progress=0):
|
||||
|
||||
|
||||
def safe_open(a, b):
|
||||
if DEMO_MODE and ('w' in b or 'a' in b):
|
||||
if (DEMO_MODE or is_gae) and ('w' in b or 'a' in b):
|
||||
class tmp:
|
||||
def write(self, data):
|
||||
pass
|
||||
def close(self):
|
||||
pass
|
||||
return tmp()
|
||||
return open(a, b)
|
||||
|
||||
@@ -564,10 +575,10 @@ def edit():
|
||||
# Load json only if it is ajax edited...
|
||||
app = get_app(request.vars.app)
|
||||
app_path = apath(app, r=request)
|
||||
editor_defaults={'theme':'web2py', 'editor': 'default', 'closetag': 'true', 'codefolding': 'false', 'tabwidth':'4', 'indentwithtabs':'false', 'linenumbers':'true', 'highlightline':'true'}
|
||||
preferences={'theme':'web2py', 'editor': 'default', 'closetag': 'true', 'codefolding': 'false', 'tabwidth':'4', 'indentwithtabs':'false', 'linenumbers':'true', 'highlightline':'true'}
|
||||
config = Config(os.path.join(request.folder, 'settings.cfg'),
|
||||
section='editor', default_values=editor_defaults)
|
||||
preferences = config.read()
|
||||
section='editor', default_values={})
|
||||
preferences.update(config.read())
|
||||
|
||||
if not(request.ajax) and not(is_mobile):
|
||||
# return the scaffolding, the rest will be through ajax requests
|
||||
@@ -579,7 +590,7 @@ def edit():
|
||||
if request.post_vars: #save new preferences
|
||||
post_vars = request.post_vars.items()
|
||||
# Since unchecked checkbox are not serialized, we must set them as false by hand to store the correct preference in the settings
|
||||
post_vars+= [(opt, 'false') for opt in editor_defaults if opt not in request.post_vars ]
|
||||
post_vars+= [(opt, 'false') for opt in preferences if opt not in request.post_vars ]
|
||||
if config.save(post_vars):
|
||||
response.headers["web2py-component-flash"] = T('Preferences saved correctly')
|
||||
else:
|
||||
@@ -742,7 +753,7 @@ def edit():
|
||||
|
||||
if len(request.args) > 2 and request.args[1] == 'controllers':
|
||||
controller = (request.args[2])[:-3]
|
||||
functions = regex_expose.findall(data)
|
||||
functions = find_exposed_functions(data)
|
||||
else:
|
||||
(controller, functions) = (None, None)
|
||||
|
||||
@@ -750,6 +761,7 @@ def edit():
|
||||
return response.json({'file_hash': file_hash, 'saved_on': saved_on, 'functions': functions, 'controller': controller, 'application': request.args[0], 'highlight': highlight})
|
||||
else:
|
||||
file_details = dict(app=request.args[0],
|
||||
lineno=request.vars.lineno or 1,
|
||||
editor_settings=preferences,
|
||||
filename=filename,
|
||||
realfilename=realfilename,
|
||||
@@ -773,6 +785,51 @@ def edit():
|
||||
else:
|
||||
return response.json(file_details)
|
||||
|
||||
def todolist():
|
||||
""" Returns all TODO of the requested app
|
||||
"""
|
||||
app = request.vars.app or ''
|
||||
app_path = apath('%(app)s' % {'app':app}, r=request)
|
||||
dirs=['models', 'controllers', 'modules', 'private' ]
|
||||
def listfiles(app, dir, regexp='.*\.py$'):
|
||||
files = sorted( listdir(apath('%(app)s/%(dir)s/' % {'app':app, 'dir':dir}, r=request), regexp))
|
||||
files = [x.replace(os.path.sep, '/') for x in files if not x.endswith('.bak')]
|
||||
return files
|
||||
|
||||
pattern = '#\s*(todo)+\s+(.*)'
|
||||
regex = re.compile(pattern, re.IGNORECASE)
|
||||
|
||||
output = []
|
||||
for d in dirs:
|
||||
for f in listfiles(app, d):
|
||||
matches = []
|
||||
filename= apath(os.path.join(app, d, f), r=request)
|
||||
with open(filename, 'r') as f_s:
|
||||
src = f_s.read()
|
||||
for m in regex.finditer(src):
|
||||
start = m.start()
|
||||
lineno = src.count('\n', 0, start) + 1
|
||||
matches.append({'text':m.group(0), 'lineno':lineno})
|
||||
if len(matches) != 0:
|
||||
output.append({'filename':f,'matches':matches, 'dir':d})
|
||||
|
||||
return {'todo':output, 'app': app}
|
||||
|
||||
def editor_sessions():
|
||||
config = Config(os.path.join(request.folder, 'settings.cfg'),
|
||||
section='editor_sessions', default_values={})
|
||||
preferences = config.read()
|
||||
|
||||
if request.vars.session_name and request.vars.files:
|
||||
session_name = request.vars.session_name
|
||||
files = request.vars.files
|
||||
preferences.update({session_name:','.join(files)})
|
||||
if config.save(preferences.items()):
|
||||
response.headers["web2py-component-flash"] = T('Session saved correctly')
|
||||
else:
|
||||
response.headers["web2py-component-flash"] = T('Session saved on session only')
|
||||
|
||||
return response.render('default/editor_sessions.html', {'editor_sessions':preferences})
|
||||
|
||||
def resolve():
|
||||
"""
|
||||
@@ -1009,7 +1066,7 @@ def design():
|
||||
functions = {}
|
||||
for c in controllers:
|
||||
data = safe_read(apath('%s/controllers/%s' % (app, c), r=request))
|
||||
items = regex_expose.findall(data)
|
||||
items = find_exposed_functions(data)
|
||||
functions[c] = items
|
||||
|
||||
# Get all views
|
||||
@@ -1053,11 +1110,12 @@ def design():
|
||||
|
||||
#Get crontab
|
||||
cronfolder = apath('%s/cron' % app, r=request)
|
||||
if not os.path.exists(cronfolder):
|
||||
os.mkdir(cronfolder)
|
||||
crontab = apath('%s/cron/crontab' % app, r=request)
|
||||
if not os.path.exists(crontab):
|
||||
safe_write(crontab, '#crontab')
|
||||
if not is_gae:
|
||||
if not os.path.exists(cronfolder):
|
||||
os.mkdir(cronfolder)
|
||||
if not os.path.exists(crontab):
|
||||
safe_write(crontab, '#crontab')
|
||||
|
||||
plugins = []
|
||||
|
||||
@@ -1146,7 +1204,7 @@ def plugin():
|
||||
functions = {}
|
||||
for c in controllers:
|
||||
data = safe_read(apath('%s/controllers/%s' % (app, c), r=request))
|
||||
items = regex_expose.findall(data)
|
||||
items = find_exposed_functions(data)
|
||||
functions[c] = items
|
||||
|
||||
# Get all views
|
||||
@@ -1209,7 +1267,6 @@ def plugin():
|
||||
languages=languages,
|
||||
crontab=crontab)
|
||||
|
||||
|
||||
def create_file():
|
||||
""" Create files handler """
|
||||
if request.vars and not request.vars.token == session.token:
|
||||
@@ -1220,6 +1277,8 @@ def create_file():
|
||||
app = get_app(request.vars.app)
|
||||
path = abspath(request.vars.location)
|
||||
else:
|
||||
if request.vars.dir:
|
||||
request.vars.location += request.vars.dir + '/'
|
||||
app = get_app(name=request.vars.location.split('/')[0])
|
||||
path = apath(request.vars.location, r=request)
|
||||
filename = re.sub('[^\w./-]+', '_', request.vars.filename)
|
||||
@@ -1347,7 +1406,11 @@ def create_file():
|
||||
|
||||
safe_write(full_filename, text)
|
||||
log_progress(app, 'CREATE', filename)
|
||||
session.flash = T('file "%(filename)s" created',
|
||||
if request.vars.dir:
|
||||
result = T('file "%(filename)s" created',
|
||||
dict(filename=full_filename[len(path):]))
|
||||
else:
|
||||
session.flash = T('file "%(filename)s" created',
|
||||
dict(filename=full_filename[len(path):]))
|
||||
vars = {}
|
||||
if request.vars.id:
|
||||
@@ -1356,13 +1419,51 @@ def create_file():
|
||||
vars['app'] = request.vars.app
|
||||
redirect(URL('edit',
|
||||
args=[os.path.join(request.vars.location, filename)], vars=vars))
|
||||
|
||||
except Exception, e:
|
||||
if not isinstance(e, HTTP):
|
||||
session.flash = T('cannot create file')
|
||||
|
||||
redirect(request.vars.sender + anchor)
|
||||
if request.vars.dir:
|
||||
response.flash = result
|
||||
response.headers['web2py-component-content'] = 'append'
|
||||
response.headers['web2py-component-command'] = """
|
||||
$.web2py.invalidate('#files_menu');
|
||||
load_file('%s');
|
||||
$.web2py.enableElement($('#form form').find($.web2py.formInputClickSelector));
|
||||
""" % URL('edit', args=[app,request.vars.dir,filename])
|
||||
return ''
|
||||
else:
|
||||
redirect(request.vars.sender + anchor)
|
||||
|
||||
|
||||
def listfiles(app, dir, regexp='.*\.py$'):
|
||||
files = sorted(
|
||||
listdir(apath('%(app)s/%(dir)s/' % {'app':app, 'dir':dir}, r=request), regexp))
|
||||
files = [x.replace('\\', '/') for x in files if not x.endswith('.bak')]
|
||||
return files
|
||||
|
||||
def editfile(path,file,vars={}, app = None):
|
||||
args=(path,file) if 'app' in vars else (app,path,file)
|
||||
url = URL('edit', args=args, vars=vars)
|
||||
return A(file, _class='editor_filelink', _href=url, _style='word-wrap: nowrap;')
|
||||
|
||||
def files_menu():
|
||||
app = request.vars.app or 'welcome'
|
||||
dirs=[{'name':'models', 'reg':'.*\.py$'},
|
||||
{'name':'controllers', 'reg':'.*\.py$'},
|
||||
{'name':'views', 'reg':'[\w/\-]+(\.\w+)+$'},
|
||||
{'name':'modules', 'reg':'.*\.py$'},
|
||||
{'name':'static', 'reg': '[^\.#].*'}]
|
||||
result_files = []
|
||||
for dir in dirs:
|
||||
result_files.append(TAG[''](LI(dir['name'], _class="nav-header component", _onclick="collapse('" + dir['name'] + "_files');"),
|
||||
LI(UL(*[LI(editfile(dir['name'], f, dict(id=dir['name'] + f.replace('.','__')), app), _style="overflow:hidden", _id=dir['name']+"__"+f.replace('.','__'))
|
||||
for f in listfiles(app, dir['name'], regexp=dir['reg'])],
|
||||
_class="nav nav-list small-font"),
|
||||
_id=dir['name'] + '_files', _style="display: none;")))
|
||||
return dict(result_files = result_files)
|
||||
|
||||
def upload_file():
|
||||
""" File uploading handler """
|
||||
if request.vars and not request.vars.token == session.token:
|
||||
@@ -1422,8 +1523,11 @@ def errors():
|
||||
import hashlib
|
||||
|
||||
app = get_app()
|
||||
|
||||
method = request.args(1) or 'new'
|
||||
if is_gae:
|
||||
method = 'dbold' if ('old' in
|
||||
(request.args(1) or '')) else 'dbnew'
|
||||
else:
|
||||
method = request.args(1) or 'new'
|
||||
db_ready = {}
|
||||
db_ready['status'] = get_ticket_storage(app)
|
||||
db_ready['errmessage'] = T(
|
||||
@@ -1490,32 +1594,30 @@ def errors():
|
||||
for fn in tk_db(tk_table.id > 0).select():
|
||||
try:
|
||||
error = pickle.loads(fn.ticket_data)
|
||||
except AttributeError:
|
||||
hash = hashlib.md5(error['traceback']).hexdigest()
|
||||
|
||||
if hash in delete_hashes:
|
||||
tk_db(tk_table.id == fn.id).delete()
|
||||
tk_db.commit()
|
||||
else:
|
||||
try:
|
||||
hash2error[hash]['count'] += 1
|
||||
except KeyError:
|
||||
error_lines = error['traceback'].split("\n")
|
||||
last_line = error_lines[-2]
|
||||
error_causer = os.path.split(error['layer'])[1]
|
||||
hash2error[hash] = dict(count=1,
|
||||
pickel=error, causer=error_causer,
|
||||
last_line=last_line, hash=hash,
|
||||
ticket=fn.ticket_id)
|
||||
except AttributeError, e:
|
||||
tk_db(tk_table.id == fn.id).delete()
|
||||
tk_db.commit()
|
||||
|
||||
hash = hashlib.md5(error['traceback']).hexdigest()
|
||||
|
||||
if hash in delete_hashes:
|
||||
tk_db(tk_table.id == fn.id).delete()
|
||||
tk_db.commit()
|
||||
else:
|
||||
try:
|
||||
hash2error['hash']['count'] += 1
|
||||
except KeyError:
|
||||
error_lines = error['traceback'].split("\n")
|
||||
last_line = error_lines[-2]
|
||||
error_causer = os.path.split(error['layer'])[1]
|
||||
hash2error[hash] = dict(count=1, pickel=error,
|
||||
causer=error_causer,
|
||||
last_line=last_line,
|
||||
hash=hash, ticket=fn.ticket_id)
|
||||
|
||||
decorated = [(x['count'], x) for x in hash2error.values()]
|
||||
|
||||
decorated.sort(key=operator.itemgetter(0), reverse=True)
|
||||
|
||||
return dict(errors=[x[1] for x in decorated], app=app, method=method)
|
||||
return dict(errors=[x[1] for x in decorated], app=app,
|
||||
method=method, db_ready=db_ready)
|
||||
|
||||
elif method == 'dbold':
|
||||
tk_db, tk_table = get_ticket_storage(app)
|
||||
@@ -1523,16 +1625,18 @@ def errors():
|
||||
if item[:7] == 'delete_':
|
||||
tk_db(tk_table.ticket_id == item[7:]).delete()
|
||||
tk_db.commit()
|
||||
tickets_ = tk_db(tk_table.id > 0).select(tk_table.ticket_id, tk_table.created_datetime, orderby=~tk_table.created_datetime)
|
||||
tickets_ = tk_db(tk_table.id > 0).select(tk_table.ticket_id,
|
||||
tk_table.created_datetime,
|
||||
orderby=~tk_table.created_datetime)
|
||||
tickets = [row.ticket_id for row in tickets_]
|
||||
times = dict(
|
||||
[(row.ticket_id, row.created_datetime) for row in tickets_])
|
||||
|
||||
return dict(app=app, tickets=tickets, method=method, times=times)
|
||||
times = dict([(row.ticket_id, row.created_datetime) for
|
||||
row in tickets_])
|
||||
return dict(app=app, tickets=tickets, method=method,
|
||||
times=times, db_ready=db_ready)
|
||||
|
||||
else:
|
||||
for item in request.vars:
|
||||
# delete_all} rows doesn't contain any ticket
|
||||
# delete_all rows doesn't contain any ticket
|
||||
# Remove anything else as requested
|
||||
if item[:7] == 'delete_' and (not item == "delete_all}"):
|
||||
os.unlink(apath('%s/errors/%s' % (app, item[7:]), r=request))
|
||||
@@ -1552,6 +1656,9 @@ def get_ticket_storage(app):
|
||||
if os.path.exists(ticket_file):
|
||||
db_string = open(ticket_file).read()
|
||||
db_string = db_string.strip().replace('\r', '').replace('\n', '')
|
||||
elif is_gae:
|
||||
# use Datastore as fallback if there is no ticket_file
|
||||
db_string = "google:datastore"
|
||||
else:
|
||||
return False
|
||||
tickets_table = 'web2py_ticket'
|
||||
@@ -1800,28 +1907,15 @@ def plugins():
|
||||
app = request.args(0)
|
||||
from serializers import loads_json
|
||||
if not session.plugins:
|
||||
rawlist = urllib.urlopen("http://www.web2pyslices.com/" +
|
||||
"public/api.json/action/list/content/Package?package" +
|
||||
"_type=plugin&search_index=false").read()
|
||||
session.plugins = loads_json(rawlist)
|
||||
plugins = TABLE(
|
||||
*[TR(TD(H5(article["article"]["title"]),
|
||||
A(T("Install"),
|
||||
_href=URL(c="default",
|
||||
f="install_plugin",
|
||||
args=[app,],
|
||||
vars={"source":
|
||||
article["package_data"]["download"],
|
||||
"plugin": article["article"]["title"]}
|
||||
))),
|
||||
TD(article["article"]["description"], BR(),
|
||||
A(T("Plugin page"),
|
||||
_href="http://www.web2pyslices.com/slice/show/%s/" % \
|
||||
article["article"]["id"])),
|
||||
TD(IMG(_src="http://www.web2pyslices.com/download/%s" % \
|
||||
article["article"]["thumbnail"])))
|
||||
for article in session.plugins["results"]])
|
||||
return dict(plugins=plugins, app=request.args(0))
|
||||
try:
|
||||
rawlist = urllib.urlopen("http://www.web2pyslices.com/" +
|
||||
"public/api.json/action/list/content/Package?package" +
|
||||
"_type=plugin&search_index=false").read()
|
||||
session.plugins = loads_json(rawlist)
|
||||
except:
|
||||
response.flash = T('Unable to download the list of plugins')
|
||||
session.plugins = []
|
||||
return dict(plugins=session.plugins["results"], app=request.args(0))
|
||||
|
||||
def install_plugin():
|
||||
app = request.args(0)
|
||||
|
||||
@@ -3,6 +3,7 @@ import cStringIO
|
||||
import gluon.contrib.shell
|
||||
import code
|
||||
import thread
|
||||
import cgi
|
||||
from gluon.shell import env
|
||||
|
||||
if DEMO_MODE or MULTI_USER_MODE:
|
||||
@@ -40,7 +41,7 @@ def callback():
|
||||
k = len(session['commands:' + app]) - 1
|
||||
#output = PRE(output)
|
||||
#return TABLE(TR('In[%i]:'%k,PRE(command)),TR('Out[%i]:'%k,output))
|
||||
return 'In [%i] : %s%s\n' % (k + 1, command, output)
|
||||
return cgi.escape('In [%i] : %s%s\n' % (k + 1, command, output))
|
||||
|
||||
|
||||
def reset():
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# coding: utf8
|
||||
# -*- coding: utf-8 -*-
|
||||
{
|
||||
'!langcode!': 'es',
|
||||
'!langname!': 'Español',
|
||||
@@ -9,8 +9,10 @@
|
||||
'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S',
|
||||
'(requires internet access, experimental)': '(requiere acceso a internet, experimental)',
|
||||
'(something like "it-it")': '(algo como "it-it")',
|
||||
'(version %s)': '(version %s)',
|
||||
'@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(file **gluon/contrib/plural_rules/%s.py** is not found)',
|
||||
'@markmin\x01An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page',
|
||||
'@markmin\x01Number of entries: **%s**': 'Number of entries: **%s**',
|
||||
'@markmin\x01Searching: **%s** %%{file}': 'Searching: **%s** files',
|
||||
'A new version of web2py is available': 'Hay una nueva versión de web2py disponible',
|
||||
'A new version of web2py is available: %s': 'Hay una nueva versión de web2py disponible: %s',
|
||||
@@ -56,11 +58,13 @@
|
||||
'Autocomplete': 'Autocomplete',
|
||||
'Autocomplete Python Code': 'Autocompletar código Python',
|
||||
'Available databases and tables': 'Bases de datos y tablas disponibles',
|
||||
'Available Databases and Tables': 'Available Databases and Tables',
|
||||
'back': 'atrás',
|
||||
'Back to the plugins list': 'Back to the plugins list',
|
||||
'breakpoint': 'breakpoint',
|
||||
'breakpoints': 'breakpoints',
|
||||
'browse': 'buscar',
|
||||
'Cache': 'Cache',
|
||||
'cache': 'cache',
|
||||
'cache, errors and sessions cleaned': 'cache, errores y sesiones eliminados',
|
||||
'can be a git repo': 'puede ser un repositorio git',
|
||||
@@ -78,6 +82,9 @@
|
||||
'Check to delete': 'Marque para eliminar',
|
||||
'Checking for upgrades...': 'Buscando actulizaciones...',
|
||||
'Clean': 'limpiar',
|
||||
'Clear CACHE?': 'Clear CACHE?',
|
||||
'Clear DISK': 'Clear DISK',
|
||||
'Clear RAM': 'Clear RAM',
|
||||
'click here for online examples': 'haga clic aquí para ver ejemplos en línea',
|
||||
'click here for the administrative interface': 'haga clic aquí para usar la interfaz administrativa',
|
||||
'Click row to expand traceback': 'Click row to expand traceback',
|
||||
@@ -112,6 +119,7 @@
|
||||
'database': 'base de datos',
|
||||
'database %s select': 'selección en base de datos %s',
|
||||
'database administration': 'administración base de datos',
|
||||
'Database Administration (appadmin)': 'Database Administration (appadmin)',
|
||||
'Date and Time': 'Fecha y Hora',
|
||||
'db': 'db',
|
||||
'Debug': 'Debug',
|
||||
@@ -122,6 +130,7 @@
|
||||
'delete plugin': 'eliminar plugin',
|
||||
'Delete this file (you will be asked to confirm deletion)': 'Elimine este fichero (se le pedirá confirmación)',
|
||||
'Delete:': 'Elimine:',
|
||||
'Demo': 'Demo',
|
||||
'Deploy': 'Deploy',
|
||||
'Deploy on Google App Engine': 'Instale en Google App Engine',
|
||||
'Deploy to OpenShift': 'Instale en OpenShift',
|
||||
@@ -133,7 +142,9 @@
|
||||
'details': 'detalles',
|
||||
'direction: ltr': 'direction: ltr',
|
||||
'Disable': 'Deshabilitar',
|
||||
'DISK': 'DISK',
|
||||
'docs': 'docs',
|
||||
'Docs': 'Docs',
|
||||
'Done!': 'Done!',
|
||||
'done!': 'listo!',
|
||||
'Download': 'Descargar',
|
||||
@@ -157,6 +168,7 @@
|
||||
'Editing myemail': 'Editing myemail',
|
||||
'Editing rbare': 'Editing rbare',
|
||||
'Editing ul': 'Editing ul',
|
||||
'Enable': 'Enable',
|
||||
'Enterprise Web Framework': 'Armazón Empresarial para Internet',
|
||||
'Error': 'Error',
|
||||
'Error logs for "%(app)s"': 'Bitácora de errores en "%(app)s"',
|
||||
@@ -190,6 +202,8 @@
|
||||
'First name': 'Nombre',
|
||||
'Frames': 'Frames',
|
||||
'Functions with no doctests will result in [passed] tests.': 'Funciones sin doctests equivalen a pruebas [aceptadas].',
|
||||
'Git Pull': 'Git Pull',
|
||||
'Git Push': 'Git Push',
|
||||
'Globals##debug': 'Globals',
|
||||
'graph model': 'graph model',
|
||||
'Group ID': 'ID de Grupo',
|
||||
@@ -213,6 +227,7 @@
|
||||
'internal error': 'error interno',
|
||||
'Internal State': 'Estado Interno',
|
||||
'Invalid action': 'Acción inválida',
|
||||
'Invalid application name': 'Invalid application name',
|
||||
'Invalid email': 'Correo inválido',
|
||||
'invalid password': 'contraseña inválida',
|
||||
'invalid password.': 'invalid password.',
|
||||
@@ -230,6 +245,7 @@
|
||||
'Last name': 'Apellido',
|
||||
'Last saved on:': 'Guardado en:',
|
||||
'License for': 'Licencia para',
|
||||
'License:': 'License:',
|
||||
'lists by ticket': 'lists by ticket',
|
||||
'loading...': 'cargando...',
|
||||
'locals': 'locals',
|
||||
@@ -241,6 +257,7 @@
|
||||
'Lost Password': 'Contraseña perdida',
|
||||
'manage': 'gestionar',
|
||||
'Manage': 'Gestionar',
|
||||
'Manage Cache': 'Manage Cache',
|
||||
'merge': 'combinar',
|
||||
'Models': 'Modelos',
|
||||
'models': 'modelos',
|
||||
@@ -250,6 +267,7 @@
|
||||
'new application "%s" created': 'nueva aplicación "%s" creada',
|
||||
'New application wizard': 'Asistente para nueva aplicación',
|
||||
'new plugin installed': 'nuevo plugin instalado',
|
||||
'New plugin installed: %s': 'New plugin installed: %s',
|
||||
'New plugin installed: web2py.plugin.attachment.w2p': 'New plugin installed: web2py.plugin.attachment.w2p',
|
||||
'New plugin installed: web2py.plugin.dialog.w2p': 'New plugin installed: web2py.plugin.dialog.w2p',
|
||||
'New plugin installed: web2py.plugin.math2py.w2p': 'New plugin installed: web2py.plugin.math2py.w2p',
|
||||
@@ -273,6 +291,7 @@
|
||||
'or provide application url:': 'o provea URL de la aplicación:',
|
||||
'Origin': 'Origen',
|
||||
'Original/Translation': 'Original/Traducción',
|
||||
'Overview': 'Overview',
|
||||
'Overwrite installed app': 'sobreescriba la aplicación instalada',
|
||||
'Pack all': 'empaquetar todo',
|
||||
'Pack compiled': 'empaquete compiladas',
|
||||
@@ -296,6 +315,7 @@
|
||||
'private files': 'archivos privados',
|
||||
'Project Progress': 'Project Progress',
|
||||
'Query:': 'Consulta:',
|
||||
'RAM': 'RAM',
|
||||
'Rapid Search': 'Rapid Search',
|
||||
'record': 'registro',
|
||||
'record does not exist': 'el registro no existe',
|
||||
@@ -310,6 +330,8 @@
|
||||
'Removed Breakpoint on %s at line %s': 'Eliminado punto de ruptura en %s en la línea %s',
|
||||
'Replace': 'Reemplazar',
|
||||
'Replace All': 'Reemplazar todos',
|
||||
'Repository (%s)': 'Repository (%s)',
|
||||
'Repository: %s': 'Repository: %s',
|
||||
'request': 'request',
|
||||
'Resolve Conflict file': 'archivo Resolución de Conflicto',
|
||||
'response': 'response',
|
||||
@@ -329,6 +351,8 @@
|
||||
'Save file: %s': 'Guardar: %s',
|
||||
'Save via Ajax': 'Guardar via Ajax',
|
||||
'Saved file hash:': 'Hash del archivo guardado:',
|
||||
'Screenshot %s': 'Screenshot %s',
|
||||
'Screenshots': 'Screenshots',
|
||||
'selected': 'seleccionado(s)',
|
||||
'session': 'session',
|
||||
'session expired': 'sesión expirada',
|
||||
@@ -336,12 +360,14 @@
|
||||
'shell': 'shell',
|
||||
'Site': 'sitio',
|
||||
'some files could not be removed': 'algunos archivos no pudieron ser removidos',
|
||||
'source : filesystem': 'source : filesystem',
|
||||
'Start searching': 'Iniciar búsqueda',
|
||||
'Start wizard': 'Iniciar asistente',
|
||||
'state': 'estado',
|
||||
'Static': 'Static',
|
||||
'static': 'estáticos',
|
||||
'Static files': 'Archivos estáticos',
|
||||
'Statistics': 'Statistics',
|
||||
'step': 'step',
|
||||
'stop': 'stop',
|
||||
'submit': 'enviar',
|
||||
@@ -355,8 +381,8 @@
|
||||
'test': 'probar',
|
||||
'Testing application': 'Probando aplicación',
|
||||
'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'La "consulta" es una condición como "db.tabla1.campo1==\'valor\'". Algo como "db.tabla1.campo1==db.tabla2.campo2" resulta en un JOIN SQL.',
|
||||
'the application logic, each URL path is mapped in one exposed function in the controller': 'la lógica de la aplicación, cada ruta URL se mapea en una función expuesta en el controlador',
|
||||
'The application logic, each URL path is mapped in one exposed function in the controller': 'La lógica de la aplicación, cada ruta URL se mapea en una función expuesta en el controlador',
|
||||
'the application logic, each URL path is mapped in one exposed function in the controller': 'la lógica de la aplicación, cada ruta URL se mapea en una función expuesta en el controlador',
|
||||
'the data representation, define database tables and sets': 'la representación de datos, define tablas y conjuntos de base de datos',
|
||||
'The data representation, define database tables and sets': 'La representación de datos, define tablas y conjuntos de base de datos',
|
||||
'The presentations layer, views are also known as templates': 'La capa de presentación, las vistas también son llamadas plantillas',
|
||||
@@ -383,6 +409,7 @@
|
||||
'To emulate a breakpoint programatically, write:': 'To emulate a breakpoint programatically, write:',
|
||||
'to use the debugger!': 'to use the debugger!',
|
||||
'toggle breakpoint': 'alternar punto de ruptura',
|
||||
'Toggle comment': 'Toggle comment',
|
||||
'Toggle Fullscreen': 'Alternar pantalla completa',
|
||||
'Traceback': 'Traceback',
|
||||
'translation strings for the application': 'cadenas de caracteres de traducción para la aplicación',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# coding: utf8
|
||||
# -*- coding: utf-8 -*-
|
||||
{
|
||||
'!langcode!': 'it',
|
||||
'!langname!': 'Italiano',
|
||||
@@ -303,6 +303,7 @@
|
||||
'to previous version.': 'torna a versione precedente',
|
||||
'To create a plugin, name a file/folder plugin_[name]': 'Per creare un plugin, chiamare un file o cartella plugin_[nome]',
|
||||
'toggle breakpoint': 'toggle breakpoint',
|
||||
'Toggle comment': 'Toggle comment',
|
||||
'Toggle Fullscreen': 'Toggle Fullscreen',
|
||||
'Traceback': 'Traceback',
|
||||
'translation strings for the application': "stringhe di traduzioni per l'applicazione",
|
||||
|
||||
426
applications/admin/languages/tr.py
Normal file
426
applications/admin/languages/tr.py
Normal file
@@ -0,0 +1,426 @@
|
||||
# coding: utf-8
|
||||
{
|
||||
'!langcode!': 'tr',
|
||||
'!langname!': 'Türkçe',
|
||||
'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"güncelleme" ("update") "field1 = \'yenideğer\'" gibi seçeneğe bağlı bir ifadedir. JOIN sonuçlarını silemez veya silemezsiniz.',
|
||||
'%s %%{row} deleted': '%s %%{row} silindi',
|
||||
'%s %%{row} updated': '%s %%{row} güncellendi',
|
||||
'%Y-%m-%d': '%d-%m-%Y',
|
||||
'%Y-%m-%d %H:%M:%S': '%d-%m-%Y %H:%M:%S',
|
||||
'(requires internet access)': '(Internet erişimi gerekir)',
|
||||
'(requires internet access, experimental)': '(internet erişimi gerekir, deneysel)',
|
||||
'(something like "it-it")': '("it-it" şeklinde birşeyler) ',
|
||||
'1: Setting Parameters': '1: Parametrelerin Yapılandırılması',
|
||||
'@markmin\x01An error occured, please [[reload %s]] the page': '@markmin\x01Bir hata oluştu, lütfen sayfayı [[reload %s]]',
|
||||
"@markmin\x01Mercurial Version Control System Interface[[NEWLINE]]for application '%s'": "'%s' uygulaması için[[NEWLINE]]Mercurial Sürüm Kontrol Sistemi Arayüzü",
|
||||
'@markmin\x01Searching: **%s** %%{file}': '@markmin\x01Aranıyor: **%s** %%{file}',
|
||||
'A new version of web2py is available: %s': "web2py'nin yeni sürümü mevcut: %s ",
|
||||
'A new version of web2py is available: Version 1.68.2 (2009-10-21 09:59:29)\n': "web2py'nin yeni sürümü mevcut: Sürüm 1.68.2 (2009-10-21 09:59:29)\r\n",
|
||||
'About': 'Hakkında',
|
||||
'About application': 'Uygulama hakkında',
|
||||
'Add breakpoint': 'Kesme noktası ekle',
|
||||
'additional code for your application': 'uygulamanız için fazladan kod',
|
||||
'Additional code for your application': 'Uygulamanız için fazladan kod',
|
||||
'Admin design page': 'Yönetici tasarım sayfası',
|
||||
'admin disabled because no admin password': 'yönetici parolası olmadığından admin etkinsiz',
|
||||
'admin disabled because not supported on google app engine': 'Google App Motoru tafaından desteklenmediğinden admin etkinsizleştirildi',
|
||||
'admin disabled because unable to access password file': 'parola dosyasına erişielemdiğinden admin etkinsizleştirildi',
|
||||
'Admin is disabled because insecure channel': 'güvenzis kanal olduğundan admin etkinsizleştirildi',
|
||||
'Admin language': 'Admin dilleri',
|
||||
'Admin versioning page': 'Yönetici sürümleme sayfası',
|
||||
'administrative interface': 'yönetsel arayüz',
|
||||
'Administrator Password:': 'Yönetici Parolası:',
|
||||
'and rename it (required):': 've yeniden adlandır (gerekli):',
|
||||
'and rename it:': 'yeniden adlandır:',
|
||||
'appadmin': 'appadmin',
|
||||
'appadmin is disabled because insecure channel': 'güvenzis kanal olduğundan admin etkinsizleştirildi',
|
||||
'Application': 'Uygulama',
|
||||
'application "%s" uninstalled': '"%s" uygulaması kaldırıldı',
|
||||
'application %(appname)s installed with md5sum: %(digest)s': '%(appname)s uygulaması md5sum %(digest)s ile kuruldu',
|
||||
'application compiled': 'uygulama derlendi',
|
||||
'application is compiled and cannot be designed': 'uygulama derlenmiş ve tasarlanamaz',
|
||||
'Application name:': 'Uygulama adı:',
|
||||
'are not used': 'kullanılamıyor',
|
||||
'are not used yet': 'şimdilik kullanılamıyor',
|
||||
'Are you sure you want to delete file "%s"?': '«%s» dosyasını silmek istediğinize emin misiniz?',
|
||||
'Are you sure you want to delete plugin "%s"?': '"%s" eklentisini kaldırmak istediğinizden emin misiniz?',
|
||||
'Are you sure you want to delete this object?': 'Bu nesneyi silmek istediğinizden emin misiniz?',
|
||||
'Are you sure you want to uninstall application "%s"?': '«%s» uygulamasını kaldırmak istediğinizden emin misiniz?',
|
||||
'Are you sure you want to upgrade web2py now?': "web2py'yi güncellemek istediğinizden emin misiniz?",
|
||||
'arguments': 'argümanlar',
|
||||
'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'UYARI: Giriş günceli bağlantı (HTTPS) gerektirmekte veya yerel makinada çalışılmalıdır.',
|
||||
'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'UYARI: ÇOKLU TEST GÜVENLİ DEĞİL. BİRDEN ÇOK TESTİ AYNI ANDA YAPMAYIN.',
|
||||
'ATTENTION: you cannot edit the running application!': 'UYARI: çalışan uygulamayı düzenleyemezsiniz!',
|
||||
'Autocomplete Python Code': 'Python Kodlarını Otomatik Tamamla',
|
||||
'Available databases and tables': 'Kullanılabilir veritabanları ve tablolar',
|
||||
'back': 'geri',
|
||||
'Back to wizard': 'Sihirbaza geri dön',
|
||||
'Basics': 'Temeller',
|
||||
'Begin': 'Başla',
|
||||
'breakpoint': 'kesme noktası',
|
||||
'Breakpoints': 'Kesme Noktaları',
|
||||
'breakpoints': 'kesme noktaları',
|
||||
'cache': 'zula',
|
||||
'cache, errors and sessions cleaned': 'zula, hatalar ve oturumlar temizlendi',
|
||||
'can be a git repo': 'git deposu olabilir',
|
||||
'Cancel': 'Vazgeç',
|
||||
'Cannot be empty': 'Boş olamaz',
|
||||
'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': 'Derlenemiyor: uygulamanızda hata(lar) var. Hataları düzeltin ve tekrar deneyin.',
|
||||
'Cannot compile: there are errors in your app:': 'Derlenemiyor: uygulamanızda hata(lar) var:',
|
||||
'cannot create file': 'dosya oluşturulamıyor',
|
||||
'cannot upload file "%(filename)s"': '"%(filename)s" dosyalarını yükleyemiyor',
|
||||
'Change admin password': 'admin parolasını değiştir',
|
||||
'change editor settings': 'düzenleyici ayarlarını değiştir',
|
||||
'check all': 'tümünü kontrol et',
|
||||
'Check for upgrades': 'Güncellemeleri kontrol et',
|
||||
'Check to delete': 'Silmek için kontrok et',
|
||||
'Checking for upgrades...': 'Güncellemeler denetleniyor ... ',
|
||||
'Clean': 'Temizle',
|
||||
'Click row to expand traceback': 'Takibi genişletmek için satır üzerine tıkla',
|
||||
'click to check for upgrades': 'güncellemeleri denetlemek için tıklayın',
|
||||
'code': 'kod',
|
||||
'collapse/expand all': 'sıkıştır/tümünü aç',
|
||||
'Comment:': 'Yorum:',
|
||||
'Commit': 'Öneri',
|
||||
'Commit form': 'Tarafından öneri',
|
||||
'Compile': 'Derle',
|
||||
'compiled application removed': 'derlenmiş uygulama kaldırıldı',
|
||||
'Condition': 'Durum',
|
||||
'Controllers': 'Denetçiler',
|
||||
'controllers': 'denetçiler',
|
||||
'Count': 'Sayı',
|
||||
'Create': 'Oluştur',
|
||||
'create file with filename:': 'dosya adı ile dosya oluştur:',
|
||||
'create new application:': 'yeni uygulama oluştur:',
|
||||
'Create new simple application': 'Yeni basit uygulama oluştur',
|
||||
'Create/Upload': 'Oluştur/Yükle',
|
||||
'created by': 'yazan:',
|
||||
'crontab': 'krontab',
|
||||
'Current request': 'Şimdiki istek',
|
||||
'Current response': 'Şimdiki yanıt',
|
||||
'Current session': 'Şimdiki oturum',
|
||||
'currently running': 'şimdiki çalışan',
|
||||
'currently saved or': 'şimdiki kaydedilen veya',
|
||||
'data uploaded': 'veri yüklendi',
|
||||
'database': 'veritabı',
|
||||
'database %s select': '%s veritabanı seçildi',
|
||||
'Database administration': 'Veritabanı yönetimi',
|
||||
'database administration': 'veritabı yönetimi',
|
||||
'Date and Time': 'Tarih ve Zaman',
|
||||
'db': 'db',
|
||||
'Debug': 'Hata Ayıkla',
|
||||
'defines tables': 'tablolar tanımlı',
|
||||
'Delete': 'Sil',
|
||||
'delete': 'sil',
|
||||
'delete all checked': 'tüm kontrol edilenleri sil',
|
||||
'delete plugin': ' eklentiyi sil',
|
||||
'Delete this file (you will be asked to confirm deletion)': 'Bu dosyayı sil (silmek için onay istenecek)',
|
||||
'Delete:': 'Sil:',
|
||||
'deleted after first hit': 'ilk vuruşta silinir',
|
||||
'Deploy': 'Yayımla',
|
||||
'Deploy on Google App Engine': 'Google App Motorunda Yayınla',
|
||||
'Deploy to OpenShift': "OpenShift'e Yayınla ",
|
||||
'Deployment form': 'Yayınlama formu',
|
||||
'design': 'tadarla',
|
||||
'Detailed traceback description': 'Ayrıntılı nedenin bulma tanımı',
|
||||
'direction: ltr': 'yön: ltr',
|
||||
'Disable': 'Devre Dışı',
|
||||
'docs': 'dokümanlar',
|
||||
'done!': 'bitti!',
|
||||
'Download .w2p': '.w2p İndir',
|
||||
'download layouts': 'düzenleri indir',
|
||||
'download plugins': 'eklentileri indir',
|
||||
'EDIT': 'DÜZENLE',
|
||||
'Edit': 'Düzenle',
|
||||
'edit all': 'tümünü düzenle',
|
||||
'Edit application': 'Uygulamayı düzenle',
|
||||
'edit controller': 'denetçiyi düzenle',
|
||||
'edit controller:': 'denetçiyi düzenle:',
|
||||
'Edit current record': 'Şimdiki kaydı düzenle',
|
||||
'edit views:': 'görünümleri düzenle:',
|
||||
'Editing %s': '%s Düzenleniyor',
|
||||
'Editing file': 'Dosya düzenleniyor',
|
||||
'Editing file "%s"': '"%s" dosyası düzenleniyor ',
|
||||
'Editing Language file': 'Dil dosyası düzenleniyor',
|
||||
'Enable': 'Etkinleştir',
|
||||
'enter a valid email address': 'geçerli e-posta adresi girin',
|
||||
'enter a value': 'bir değer girin',
|
||||
'enter only letters, numbers, and underscore': 'sadece harf, sayı ve alt çizgi giriniz',
|
||||
'Enterprise Web Framework': 'Enterprise Web Çatısı',
|
||||
'Error': 'Hata',
|
||||
'Error logs for "%(app)s"': '"%(app)s" uygulaması için hata kayıtları',
|
||||
'Error snapshot': 'Hata resmi',
|
||||
'Error ticket': 'Hata bileti',
|
||||
'Errors': 'Hatalar',
|
||||
'Exception instance attributes': 'Hata durumu özellikleri',
|
||||
'Exit Fullscreen': 'Tam Ekrandan Çık',
|
||||
'Expand Abbreviation': 'Kısıtlamayı Aç',
|
||||
'export as csv file': 'CSV olarak dışa ver',
|
||||
'exposes': 'sergileniyor',
|
||||
'exposes:': 'sergile:',
|
||||
'extends': 'genişlet',
|
||||
'failed to reload module': 'modül yüklenemedi',
|
||||
'failed to reload module because:': 'modü yüklenemedi çünkü:',
|
||||
'File': 'Dosya',
|
||||
'file "%(filename)s" created': '"%(filename)s" dosyaları oluşturuldu',
|
||||
'file "%(filename)s" deleted': '"%(filename)s" dosyaları silindi',
|
||||
'file "%(filename)s" uploaded': '"%(filename)s" dosyaları yüklendi',
|
||||
'file "%s" of %s restored': '"%s" dosyasının %s kısmı geri alındı',
|
||||
'file changed on disk': 'dosya disk üzerinde değişti',
|
||||
'file does not exist': 'dosya bulunamıyor',
|
||||
'file not found': 'dosya bulanamadı',
|
||||
'file saved on %(time)s': 'dosyası %(time)s zamanında kaydedildi',
|
||||
'file saved on %s': 'dosyası kaydedildi: %s',
|
||||
'Filename': 'Dosya adı',
|
||||
'filter': 'filtre',
|
||||
'Find Next': 'Sonrakini Bul',
|
||||
'Find Previous': 'Öncekini Bul',
|
||||
'Frames': 'Çerçeveler',
|
||||
'Functions with no doctests will result in [passed] tests.': '[passed] testlerdeki işlevlerde doctest yok',
|
||||
'GAE Email': 'GAE E-postası',
|
||||
'GAE Password': 'GAE Parolası',
|
||||
'Generate': 'Oluştur',
|
||||
'Git Pull': 'Git Çek',
|
||||
'Git Push': 'Git İtele',
|
||||
'Globals##debug': 'Geneller',
|
||||
'go!': 'git!',
|
||||
'Google App Engine Deployment Interface': 'Google App Motoru Yayınlama Arayüzü',
|
||||
'Google Application Id': 'Google Uygulama Id',
|
||||
'Goto': 'Git',
|
||||
'graph model': 'grafik modeli',
|
||||
'Help': 'Yardım',
|
||||
'Hide/Show Translated strings': 'Çevrilmiş cümleleri Gizle/Görüntüle',
|
||||
'Hits': 'Vuruşlar',
|
||||
'Home': 'Anasayfa',
|
||||
'honored only if the expression evaluates to true': 'sadece deyim doğru sonucunu verirse',
|
||||
'htmledit': 'html dğzenleyici',
|
||||
'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.': 'Doküman testi yapılmadan önce, eğer yukarıdaki rapor bir bilet numarası içeriyorsa bu denetleyici çalıştırılırken bir hata oluşturğunu gösterir. Bu genellikle girinti/çıkıntı (indentation) hatası veya işlev dışındaki bir hatadan kaynaklanır.\nYeşil başlık geçilen tüm testleri (eğer tanımlanmışsa) gösterir. Bu durumda test sonuçları görüntülenmez.',
|
||||
'Import/Export': 'İçe/Dışa Aktarıcı',
|
||||
'includes': 'içerir',
|
||||
'index': 'indeks',
|
||||
'insert new': 'yeni ekle',
|
||||
'insert new %s': '%s yeni ekle',
|
||||
'inspect attributes': 'özellikleri denetleyin',
|
||||
'Install': 'Kurucu',
|
||||
'Installed applications': 'Kurulu uygulamalar',
|
||||
'internal error': 'dahili hata',
|
||||
'Internal State': 'Dahili Durum',
|
||||
'Invalid action': 'Geçersiz eylem',
|
||||
'invalid expression': 'geçersiz ifade',
|
||||
'invalid password': 'Parola geçersiz',
|
||||
'invalid password.': 'geçersiz parola.',
|
||||
'Invalid Query': 'Geçersiz Sorgu',
|
||||
'invalid request': 'geçersiz istek',
|
||||
'invalid ticket': 'geçersiz bilet',
|
||||
'Key bindings': 'Anahtarlar',
|
||||
'Key bindings for ZenCoding Plugin': 'ZenCoding Eklentisi için anahtarlar',
|
||||
'language file "%(filename)s" created/updated': '"%(filename)s" dil dosyası/dosyaları güncellendi',
|
||||
'Language files (static strings) updated': 'Dil dosyası (statik cümleler) güncellendi',
|
||||
'languages': 'diller',
|
||||
'Languages': 'Diller',
|
||||
'Last saved on:': 'Son kaydedilme:',
|
||||
'License for': 'için lisanslanmış',
|
||||
'Line Nr': 'Satır Nr',
|
||||
'Line number': 'Satır numarası',
|
||||
'lists by exception': 'istisnaya göre sırala',
|
||||
'lists by ticket': 'bilete göre sırala',
|
||||
'loading...': 'yükleniyor ...',
|
||||
'locals': 'yereller',
|
||||
'Locals##debug': 'Yereller',
|
||||
'Login': 'Giriş',
|
||||
'login': 'giriş',
|
||||
'Login to the Administrative Interface': 'Yönetsel Arayüze Giriş\t',
|
||||
'Logout': 'Çıkış',
|
||||
'Manage': 'Yönet',
|
||||
'merge': 'birleştir',
|
||||
'Models': 'Modeller',
|
||||
'models': 'modeller',
|
||||
'Modules': 'Modüller',
|
||||
'modules': 'modüller',
|
||||
'new application "%s" created': 'yeni uygulama "%s" oluşturuldu',
|
||||
'New Application Wizard': 'Yeni Uygulama Sihirbazı',
|
||||
'New application wizard': 'Yeni uygulama sihirbazı',
|
||||
'new plugin installed': 'yeni eklenti kuruldu',
|
||||
'New Record': 'Yeni Kayıt',
|
||||
'new record inserted': 'yeni kayıt eklendi',
|
||||
'New simple application': 'Yeni basit uygulama',
|
||||
'next 100 rows': 'sonraki 100 satır',
|
||||
'NO': 'HAYIR',
|
||||
'No databases in this application': 'Bu uygulamada veritabanı yok',
|
||||
'No Interaction yet': 'Henüz etkileşim yok',
|
||||
'no match': 'eşlenen yok',
|
||||
'no package selected': 'hiç paket seçilmemiş',
|
||||
'No ticket_storage.txt found under /private folder': '/private dizininde ticket_storage.txt dosyası bulunamadı',
|
||||
'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.': 'Not: Eğer github hata kodu 128 durumunu bildiren bir ileti alırsanız, OpenShift hesabınızı ait ssh anahtarının doğru yapılandırıldığından emin olun.',
|
||||
'online designer': 'çevirimiçi tasarlayıcı',
|
||||
'Open new app in new window': 'Yeni pencerede yeni uygualama aç',
|
||||
'OpenShift Deployment Interface': 'OpenShift Yayınlama Arayüzü',
|
||||
'or alternatively': 'veya seçenek olarak',
|
||||
'Or Get from URL:': 'Veya şu URL den alın:',
|
||||
'or import from csv file': 'veya CSV dsoyasından içerin',
|
||||
'or provide app url:': "veya uygulama URL'si verin:",
|
||||
'or provide application url:': "veya uygulama URL'si verin:",
|
||||
'Original/Translation': 'Orjinal / Çeviri',
|
||||
'Overwrite installed app': 'Kurulu uygulama üzerine yaz',
|
||||
'Pack all': 'Tümünü paketle',
|
||||
'Pack compiled': 'Derlenenleri paketle',
|
||||
'Pack custom': 'Tercihli paketle',
|
||||
'pack plugin': 'eklentiyi paketle',
|
||||
'PAM authenticated user, cannot change password here': 'PAM onaylı kullanıcı, parola buradan değiştirilemiyor',
|
||||
'password changed': 'parola değiştirilidi',
|
||||
'Path to appcfg.py': 'appcfg.py dosyasının patikası',
|
||||
'Path to local openshift repo root.': 'Yerel openshift repo kökünün patikası.',
|
||||
'Peeking at file': 'Dosya gözetleniyor',
|
||||
'Please': 'Lütfen',
|
||||
'plugin "%(plugin)s" deleted': '"%(plugin)s" eklentisi silindi',
|
||||
'Plugin "%s" in application': '"%s" uygulamasında eklenti',
|
||||
'plugins': 'eklentiler',
|
||||
'Plugins': 'Eklentiler',
|
||||
'Plural-Forms:': 'Çoğul-Kipler:',
|
||||
'Powered by': 'Yazılım Temeli:',
|
||||
'previous 100 rows': 'önceki 100 satır',
|
||||
'Private files': 'Özel dosyalar',
|
||||
'private files': 'özel dosyalar',
|
||||
'Project Progress': 'Proje İlerlemesi',
|
||||
'pygraphviz library not found': 'pygraphviz kütüphanesi yok',
|
||||
'Query:': 'Sorgu: ',
|
||||
'Rapid Search': 'Hızlı Arama',
|
||||
'record': 'kayıt',
|
||||
'record does not exist': 'kayıt bulunamıyor',
|
||||
'record id': 'kayıt id',
|
||||
'refresh': 'yeniden yükle',
|
||||
'Reload routes': 'Yönelendirmeyi yeniden yükle',
|
||||
'Remove compiled': 'Derlemeyi kaldır',
|
||||
'Removed Breakpoint on %s at line %s': ' %s üzerindeki kesme noktası %s satırında değiştrildi.',
|
||||
'Replace': 'Değiştir',
|
||||
'Replace All': 'Tümünü değiştir',
|
||||
'request': 'istek',
|
||||
'requires python-git, but not installed': 'python-git gerekyior, fakat kurulu değil',
|
||||
'Resolve Conflict file': 'Dosyadaki çakışmayı çöz',
|
||||
'response': 'tepki',
|
||||
'restart': 'yeniden başla',
|
||||
'restore': 'geri al',
|
||||
'revert': 'geri al',
|
||||
'Rows in table': 'Tablosundaki satırlar',
|
||||
'Rows selected': 'Seçilen satırlar',
|
||||
"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Bu dosyadaki testleri çalıştırır (tüm dosyaları çalıştırmak için, 'test' etiketli düğmeyi kullanabilirsiniz)",
|
||||
'Running on %s': '%s üzerinde çalışıyor',
|
||||
'Save': 'Kaydet',
|
||||
'save': 'kaydet',
|
||||
'Save file:': 'Dosyayı kaydet:',
|
||||
'Save file: %s': 'Dosyayı farklı kaydet: %s',
|
||||
'Save via Ajax': 'Ajax üzerinden kaydet',
|
||||
'Saved file hash:': 'Kaydedilen dosyanın parmak izi:',
|
||||
'Select Files to Package': 'Paketlenecek Dosyaları Seç',
|
||||
'selected': 'seçildi',
|
||||
'session': 'oturum',
|
||||
'session expired': 'oturum zamanaşımına uğradı',
|
||||
'Set Breakpoint on %s at line %s: %s': "%s'nin %s satırındaki kesme noktasını: %s yap",
|
||||
'shell': 'kabuk',
|
||||
'Site': 'Site',
|
||||
'skip to generate': 'oluşturmak için atla',
|
||||
'some files could not be removed': 'bazı dosyalar kaldırılamadı',
|
||||
'source : filesystem': 'kaynak : dosyasistemi',
|
||||
'Start a new app': 'Yeni uygualama başla',
|
||||
'Start searching': 'Aramaya başla',
|
||||
'Start wizard': 'Başlatma sihirbazı',
|
||||
'state': 'durum',
|
||||
'static': 'statik',
|
||||
'Static': 'Statik',
|
||||
'Static files': 'Statik dosyalar',
|
||||
'Step': 'Basamak',
|
||||
'Submit': 'Gönder',
|
||||
'submit': 'gönder',
|
||||
'successful': 'başarılı',
|
||||
'Sure you want to delete this object?': 'Bu nesneyi silmek istediğinizden emin misiniz? ',
|
||||
'switch to : db': 'geç : db',
|
||||
'table': 'tablo',
|
||||
'Temporary': 'Geçici',
|
||||
'test': 'test',
|
||||
'Testing application': 'Uygulama test ediliyor',
|
||||
'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"sorgulama" "db.table1.field1==\'değer\'" şeklinde bir durumu ifade eder. SQL birleştirmede (JOIN) "db.table1.field1==db.table2.field2" şeklindedir.',
|
||||
'the application logic, each URL path is mapped in one exposed function in the controller': 'uygulama mantığı: her URL denetleyicideki bir işleve eşlenir',
|
||||
'The application logic, each URL path is mapped in one exposed function in the controller': 'Uygulama mantığı: her URL denetleyicideki bir işleve eşlenir',
|
||||
'the data representation, define database tables and sets': 'veri gösterimi, veritabanı tablolarını ve setlerini tanımla',
|
||||
'The data representation, define database tables and sets': 'Veri gösterimi, veritabanı tablolarını ve setlerini tanımla',
|
||||
'The presentations layer, views are also known as templates': 'Sunum katmanı, görünümler şablon olarakda biliniyor.',
|
||||
'the presentations layer, views are also known as templates': 'sunum katmanı, görünümler şablon olarakda biliniyor.',
|
||||
'There are no controllers': 'Denetçiler yok',
|
||||
'There are no models': 'Modeller yok',
|
||||
'There are no modules': 'Modüller yok',
|
||||
'There are no plugins': 'Eklentiler yok',
|
||||
'There are no private files': 'Özel dosyalar yok',
|
||||
'There are no static files': 'Statik dosyalar yok',
|
||||
'There are no translators, only default language is supported': 'Çeviriler, sadeceön tanmlı dil destekleniyor.',
|
||||
'There are no views': 'Görünümler yok',
|
||||
'These files are not served, they are only available from within your app': 'Bu dosyalar servis yapılmıyor, bunlar sadece uygulamanız içerisinden erişilebilir.',
|
||||
'These files are served without processing, your images go here': 'Bu dosyalarda işlem yapılmadan kaydedildi, resimler buraya gidiyor:',
|
||||
'these files are served without processing, your images go here': 'bu dosyalarda işlem yapılmadan kaydedildi, resimler buraya gidiyor:',
|
||||
'This is the %(filename)s template': 'Bu şablonlar %(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.": "Bu sayfa uygulamanızı OpenShif uygulama reposuna koyar. Uygulamanızın web2py iskeleti ile oluşturulduğunuz ve web2py dosya sisteminizdeki ropoya erişilebileceği varsayılmıştır. Bu işlev web2py'nin çalıştığı ortamda GitPython'e ihtiyaç duyar.",
|
||||
'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.': 'Bu sayfa uygulamanızı Google App Motoru bilişim bulutuna yükleyecektir. İndeksleri yerel olarak oluştırmanız gerektiğini aklınızda tutun, Google uygulama sunucusunu yerel olarak kurup çalıştırın, aksi halde bazı kayıtlarda hatalar olacaktır. Uyarı: yayınlama ağ hızınıza bağlı olarak uzun zaman alabilir. Uyarı: bu sizin app.yaml dosyasını yeniden yazar. LÜTFEN BİRDEN FAZLA GÖNDERMEYİN.',
|
||||
'this page to see if a breakpoint was hit and debug interaction is required.': 'bu sayfayı, kesme noktasına geldiğini görmek için ve hata ayıklama etkileşmesi gerekiyor..',
|
||||
'Ticket': 'Bilet',
|
||||
'Ticket ID': 'Bile ID\'si',
|
||||
'TM': 'TM',
|
||||
'to previous version.': 'önceki sürüme.',
|
||||
'To create a plugin, name a file/folder plugin_[name]': 'Eklenti oluşturmak için dosyayı dosya/klasör plugin_[isim] şeklinde isimlendir. ',
|
||||
'To emulate a breakpoint programatically, write:': 'Program ile kesme noktasını öykünmek için, yazın:',
|
||||
'to use the debugger!': 'hata ayıklayıcısını kullanmak için!',
|
||||
'toggle breakpoint': 'kesme noktasını değiştir',
|
||||
'Toggle Fullscreen': 'Tam Ekrana Geç',
|
||||
'Traceback': 'Nedenin bul',
|
||||
'translation strings for the application': 'uygulama için çeviri cümleleri',
|
||||
'Translation strings for the application': 'Uygulama için çeviri cümleleri',
|
||||
'try': 'dene',
|
||||
'try something like': 'gibi birşey dene',
|
||||
'Try the mobile interface': 'Mobil arayüzü dene',
|
||||
'try view': 'görünümü dene',
|
||||
'Unable to check for upgrades': 'Güncellemeler denetlenemiyor',
|
||||
'unable to create application "%s"': '"%s" uygulaması oluşturulamıyor',
|
||||
'unable to delete file "%(filename)s"': '"%(filename)s" dosylaları silinemiyor',
|
||||
'unable to delete file plugin "%(plugin)s"': '"%(plugin)s" eklenti dosyasyaları silenemiyor',
|
||||
'Unable to download': 'İndirilemiyor',
|
||||
'Unable to download app': 'Uygulamanız indirilemiyor',
|
||||
'Unable to download app because:': 'Uygulamanız indirilemiyor çünkü:',
|
||||
'Unable to download because': 'İndirilemiyor çünkü:',
|
||||
'unable to parse csv file': "impossible d'analyser les fichiers CSV",
|
||||
'unable to uninstall "%s"': 'kladıramıyor çünkü "%s"',
|
||||
'unable to upgrade because "%s"': 'güncelleyemiyor çünkü "%s"',
|
||||
'uncheck all': 'tümünü kladır',
|
||||
'Uninstall': 'Kaldır',
|
||||
'update': 'güncelle',
|
||||
'update all languages': 'tüm delleri yükle',
|
||||
'Update:': 'Güncelle:',
|
||||
'upgrade now': 'şimdi güncelle',
|
||||
'upgrade web2py now': "web2py'yi güncelle",
|
||||
'upload': 'yükle',
|
||||
'Upload': 'Yükle',
|
||||
'Upload & install packed application': 'Paketlenmiş uygulamayı yükle ve kur',
|
||||
'Upload a package:': 'Paket yükle:',
|
||||
'Upload and install packed application': 'Paketlenmiş uygulamayı yükle ve kur',
|
||||
'upload application:': 'uygulamayı yükle:',
|
||||
'Upload existing application': 'Var olan uygulamayı yükle',
|
||||
'upload file:': 'dosyayı yükle:',
|
||||
'upload plugin file:': 'eklenti dosyasını yükle:',
|
||||
'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Karmaşık sorgularda Ve (AND) için (...)&(...) kullanın, Veya (OR) için (...)|(...) kullanın ve DEĞİL (NOT) için ~(...) kullanın. ',
|
||||
'Use an url:': "Url'yi kullan:",
|
||||
'user': 'kullanıcı',
|
||||
'variables': 'değişkenler',
|
||||
'Version': 'Sürüm',
|
||||
'versioning': 'sürümleme',
|
||||
'Versioning': 'Sürümleme',
|
||||
'view': 'görüntü',
|
||||
'Views': 'Görüntüler',
|
||||
'views': 'görüntüler',
|
||||
'Web Framework': 'Web Çatısı',
|
||||
'web2py apps to deploy': 'Yayınlanacak web2py uygulaması',
|
||||
'web2py is up to date': 'web2py güncel',
|
||||
'web2py online debugger': 'çevirimiçi web2py hata ayıklayıcı',
|
||||
'web2py Recent Tweets': 'web2py Son Twitler',
|
||||
'web2py upgraded; please restart it': 'web2py güncellendi, lütfen yeniden başlatın',
|
||||
'WSGI reference name': 'WSGI referans ismi',
|
||||
'YES': 'EVET',
|
||||
'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': '"kesme noktaları" düğmesini kullanarak düzenleme penceresine geçebilir ve kesme nokatalarını hem ekeleyebilir hemde kaldırabilirsiniz',
|
||||
'You need to set up and reach a': 'Gelinceye kadar kurmalısınız',
|
||||
}
|
||||
@@ -45,4 +45,4 @@ if 'adminLanguage' in request.cookies and not (request.cookies['adminLanguage']
|
||||
T.force(request.cookies['adminLanguage'].value)
|
||||
|
||||
#set static_version
|
||||
response.static_version = '2.7.3'
|
||||
response.static_version = open('VERSION').read().split(' ',1)[1].split('-')[0]
|
||||
|
||||
@@ -144,7 +144,7 @@ if session.is_mobile == 'true':
|
||||
elif session.is_mobile == 'false':
|
||||
is_mobile = False
|
||||
else:
|
||||
is_mobile = request.user_agent().is_mobile
|
||||
is_mobile = request.user_agent().get('is_mobile',False)
|
||||
|
||||
if DEMO_MODE:
|
||||
session.authorized = True
|
||||
|
||||
@@ -24,7 +24,7 @@ def button_enable(href, app):
|
||||
return A(label, _class='button btn', _id=id, callback=href, target=id)
|
||||
|
||||
def sp_button(href, label):
|
||||
if request.user_agent().is_mobile:
|
||||
if request.user_agent().get('is_mobile'):
|
||||
ret = A_button(SPAN(label), _href=href)
|
||||
else:
|
||||
ret = A(SPAN(label), _class='button special btn btn-inverse', _href=href)
|
||||
@@ -37,4 +37,4 @@ 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")
|
||||
_class="searchbox")
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
[DEFAULT]
|
||||
theme = web2py
|
||||
closetag = true
|
||||
editor = default
|
||||
|
||||
[editor]
|
||||
theme = web2py
|
||||
editor = default
|
||||
closetag = true
|
||||
|
||||
[editor_sessions]
|
||||
welcome = welcome/models/db.py,welcome/controllers/default.py,welcome/views/default/index.html
|
||||
|
||||
|
||||
@@ -96,8 +96,9 @@
|
||||
for (var i = start; i <= end; ++i) {
|
||||
var line = self.getLine(i);
|
||||
var found = line.indexOf(lineString);
|
||||
if (found > -1 && !/comment/.test(self.getTokenTypeAt(Pos(i, found + 1)))) found = -1;
|
||||
if (found == -1 && (i != end || i == start) && nonWS.test(line)) break lineComment;
|
||||
if (i != start && found > -1 && nonWS.test(line.slice(0, found))) break lineComment;
|
||||
if (found > -1 && nonWS.test(line.slice(0, found))) break lineComment;
|
||||
lines.push(line);
|
||||
}
|
||||
self.operation(function() {
|
||||
@@ -124,7 +125,10 @@
|
||||
endLine = self.getLine(--end);
|
||||
close = endLine.lastIndexOf(endString);
|
||||
}
|
||||
if (open == -1 || close == -1) return false;
|
||||
if (open == -1 || close == -1 ||
|
||||
!/comment/.test(self.getTokenTypeAt(Pos(start, open + 1))) ||
|
||||
!/comment/.test(self.getTokenTypeAt(Pos(end, close + 1))))
|
||||
return false;
|
||||
|
||||
self.operation(function() {
|
||||
self.replaceRange("", Pos(end, close - (pad && endLine.slice(close - pad.length, close) == pad ? pad.length : 0)),
|
||||
|
||||
@@ -10,11 +10,22 @@
|
||||
} else {
|
||||
dialog.className = "CodeMirror-dialog CodeMirror-dialog-top";
|
||||
}
|
||||
dialog.innerHTML = template;
|
||||
if (typeof template == "string") {
|
||||
dialog.innerHTML = template;
|
||||
} else { // Assuming it's a detached DOM element.
|
||||
dialog.appendChild(template);
|
||||
}
|
||||
return dialog;
|
||||
}
|
||||
|
||||
function closeNotification(cm, newVal) {
|
||||
if (cm.state.currentNotificationClose)
|
||||
cm.state.currentNotificationClose();
|
||||
cm.state.currentNotificationClose = newVal;
|
||||
}
|
||||
|
||||
CodeMirror.defineExtension("openDialog", function(template, callback, options) {
|
||||
closeNotification(this, null);
|
||||
var dialog = dialogDiv(this, template, options && options.bottom);
|
||||
var closed = false, me = this;
|
||||
function close() {
|
||||
@@ -24,6 +35,7 @@
|
||||
}
|
||||
var inp = dialog.getElementsByTagName("input")[0], button;
|
||||
if (inp) {
|
||||
if (options && options.value) inp.value = options.value;
|
||||
CodeMirror.on(inp, "keydown", function(e) {
|
||||
if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; }
|
||||
if (e.keyCode == 13 || e.keyCode == 27) {
|
||||
@@ -51,6 +63,7 @@
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension("openConfirm", function(template, callbacks, options) {
|
||||
closeNotification(this, null);
|
||||
var dialog = dialogDiv(this, template, options && options.bottom);
|
||||
var buttons = dialog.getElementsByTagName("button");
|
||||
var closed = false, me = this, blurring = 1;
|
||||
@@ -77,4 +90,33 @@
|
||||
CodeMirror.on(b, "focus", function() { ++blurring; });
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* openNotification
|
||||
* Opens a notification, that can be closed with an optional timer
|
||||
* (default 5000ms timer) and always closes on click.
|
||||
*
|
||||
* If a notification is opened while another is opened, it will close the
|
||||
* currently opened one and open the new one immediately.
|
||||
*/
|
||||
CodeMirror.defineExtension("openNotification", function(template, options) {
|
||||
closeNotification(this, close);
|
||||
var dialog = dialogDiv(this, template, options && options.bottom);
|
||||
var duration = options && (options.duration === undefined ? 5000 : options.duration);
|
||||
var closed = false, doneTimer;
|
||||
|
||||
function close() {
|
||||
if (closed) return;
|
||||
closed = true;
|
||||
clearTimeout(doneTimer);
|
||||
dialog.parentNode.removeChild(dialog);
|
||||
}
|
||||
|
||||
CodeMirror.on(dialog, 'click', function(e) {
|
||||
CodeMirror.e_preventDefault(e);
|
||||
close();
|
||||
});
|
||||
if (duration)
|
||||
doneTimer = setTimeout(close, options.duration);
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
var wrap = cm.getWrapperElement();
|
||||
cm.state.fullScreenRestore = {scrollTop: window.pageYOffset, scrollLeft: window.pageXOffset,
|
||||
width: wrap.style.width, height: wrap.style.height};
|
||||
wrap.style.width = wrap.style.height = "";
|
||||
wrap.style.width = "";
|
||||
wrap.style.height = "auto";
|
||||
wrap.className += " CodeMirror-fullscreen";
|
||||
document.documentElement.style.overflow = "hidden";
|
||||
cm.refresh();
|
||||
|
||||
@@ -2,12 +2,10 @@
|
||||
CodeMirror.defineOption("placeholder", "", function(cm, val, old) {
|
||||
var prev = old && old != CodeMirror.Init;
|
||||
if (val && !prev) {
|
||||
cm.on("focus", onFocus);
|
||||
cm.on("blur", onBlur);
|
||||
cm.on("change", onChange);
|
||||
onChange(cm);
|
||||
} else if (!val && prev) {
|
||||
cm.off("focus", onFocus);
|
||||
cm.off("blur", onBlur);
|
||||
cm.off("change", onChange);
|
||||
clearPlaceholder(cm);
|
||||
@@ -33,9 +31,6 @@
|
||||
cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild);
|
||||
}
|
||||
|
||||
function onFocus(cm) {
|
||||
clearPlaceholder(cm);
|
||||
}
|
||||
function onBlur(cm) {
|
||||
if (isEmpty(cm)) setPlaceholder(cm);
|
||||
}
|
||||
@@ -43,7 +38,6 @@
|
||||
var wrapper = cm.getWrapperElement(), empty = isEmpty(cm);
|
||||
wrapper.className = wrapper.className.replace(" CodeMirror-empty", "") + (empty ? " CodeMirror-empty" : "");
|
||||
|
||||
if (cm.hasFocus()) return;
|
||||
if (empty) setPlaceholder(cm);
|
||||
else clearPlaceholder(cm);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
var map = {
|
||||
name : "autoCloseBrackets",
|
||||
Backspace: function(cm) {
|
||||
if (cm.somethingSelected()) return CodeMirror.Pass;
|
||||
if (cm.somethingSelected() || cm.getOption("disableInput")) return CodeMirror.Pass;
|
||||
var cur = cm.getCursor(), around = charsAround(cm, cur);
|
||||
if (around && pairs.indexOf(around) % 2 == 0)
|
||||
cm.replaceRange("", CodeMirror.Pos(cur.line, cur.ch - 1), CodeMirror.Pos(cur.line, cur.ch + 1));
|
||||
@@ -49,7 +49,8 @@
|
||||
else cm.execCommand("goCharRight");
|
||||
}
|
||||
map["'" + left + "'"] = function(cm) {
|
||||
if (left == "'" && cm.getTokenAt(cm.getCursor()).type == "comment")
|
||||
if (left == "'" && cm.getTokenAt(cm.getCursor()).type == "comment" ||
|
||||
cm.getOption("disableInput"))
|
||||
return CodeMirror.Pass;
|
||||
if (cm.somethingSelected()) return surround(cm);
|
||||
if (left == right && maybeOverwrite(cm) != CodeMirror.Pass) return;
|
||||
@@ -70,7 +71,8 @@
|
||||
function buildExplodeHandler(pairs) {
|
||||
return function(cm) {
|
||||
var cur = cm.getCursor(), around = charsAround(cm, cur);
|
||||
if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass;
|
||||
if (!around || pairs.indexOf(around) % 2 != 0 || cm.getOption("disableInput"))
|
||||
return CodeMirror.Pass;
|
||||
cm.operation(function() {
|
||||
var newPos = CodeMirror.Pos(cur.line + 1, 0);
|
||||
cm.replaceSelection("\n\n", {anchor: newPos, head: newPos}, "+input");
|
||||
|
||||
@@ -24,16 +24,15 @@
|
||||
|
||||
(function() {
|
||||
CodeMirror.defineOption("autoCloseTags", false, function(cm, val, old) {
|
||||
if (val && (old == CodeMirror.Init || !old)) {
|
||||
var map = {name: "autoCloseTags"};
|
||||
if (typeof val != "object" || val.whenClosing)
|
||||
map["'/'"] = function(cm) { return autoCloseSlash(cm); };
|
||||
if (typeof val != "object" || val.whenOpening)
|
||||
map["'>'"] = function(cm) { return autoCloseGT(cm); };
|
||||
cm.addKeyMap(map);
|
||||
} else if (!val && (old != CodeMirror.Init && old)) {
|
||||
if (old != CodeMirror.Init && old)
|
||||
cm.removeKeyMap("autoCloseTags");
|
||||
}
|
||||
if (!val) return;
|
||||
var map = {name: "autoCloseTags"};
|
||||
if (typeof val != "object" || val.whenClosing)
|
||||
map["'/'"] = function(cm) { return autoCloseSlash(cm); };
|
||||
if (typeof val != "object" || val.whenOpening)
|
||||
map["'>'"] = function(cm) { return autoCloseGT(cm); };
|
||||
cm.addKeyMap(map);
|
||||
});
|
||||
|
||||
var htmlDontClose = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param",
|
||||
@@ -44,7 +43,7 @@
|
||||
function autoCloseGT(cm) {
|
||||
var pos = cm.getCursor(), tok = cm.getTokenAt(pos);
|
||||
var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
|
||||
if (inner.mode.name != "xml" || !state.tagName) return CodeMirror.Pass;
|
||||
if (inner.mode.name != "xml" || !state.tagName || cm.getOption("disableInput")) return CodeMirror.Pass;
|
||||
|
||||
var opt = cm.getOption("autoCloseTags"), html = inner.mode.configuration == "html";
|
||||
var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose);
|
||||
@@ -54,9 +53,13 @@
|
||||
if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch);
|
||||
var lowerTagName = tagName.toLowerCase();
|
||||
// Don't process the '>' at the end of an end-tag or self-closing tag
|
||||
if (tok.type == "tag" && state.type == "closeTag" ||
|
||||
if (!tagName ||
|
||||
tok.type == "string" && (tok.end != pos.ch || !/[\"\']/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1) ||
|
||||
tok.type == "tag" && state.type == "closeTag" ||
|
||||
tok.string.indexOf("/") == (tok.string.length - 1) || // match something like <someTagName />
|
||||
dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1)
|
||||
dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1 ||
|
||||
CodeMirror.scanForClosingTag && CodeMirror.scanForClosingTag(cm, pos, tagName,
|
||||
Math.min(cm.lastLine() + 1, pos.line + 50)))
|
||||
return CodeMirror.Pass;
|
||||
|
||||
var doIndent = indentTags && indexOf(indentTags, lowerTagName) > -1;
|
||||
@@ -64,15 +67,18 @@
|
||||
cm.replaceSelection(">" + (doIndent ? "\n\n" : "") + "</" + tagName + ">",
|
||||
{head: curPos, anchor: curPos});
|
||||
if (doIndent) {
|
||||
cm.indentLine(pos.line + 1);
|
||||
cm.indentLine(pos.line + 2);
|
||||
cm.indentLine(pos.line + 1, null, true);
|
||||
cm.indentLine(pos.line + 2, null);
|
||||
}
|
||||
}
|
||||
|
||||
function autoCloseSlash(cm) {
|
||||
var pos = cm.getCursor(), tok = cm.getTokenAt(pos);
|
||||
var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
|
||||
if (tok.string.charAt(0) != "<" || tok.start != pos.ch - 1 || inner.mode.name != "xml") return CodeMirror.Pass;
|
||||
if (tok.type == "string" || tok.string.charAt(0) != "<" ||
|
||||
tok.start != pos.ch - 1 || inner.mode.name != "xml" ||
|
||||
cm.getOption("disableInput"))
|
||||
return CodeMirror.Pass;
|
||||
|
||||
var tagName = state.context && state.context.tagName;
|
||||
if (tagName) cm.replaceSelection("/" + tagName + ">", "end");
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
unorderedBullets = '*+-';
|
||||
|
||||
CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) {
|
||||
if (cm.getOption("disableInput")) return CodeMirror.Pass;
|
||||
|
||||
var pos = cm.getCursor(),
|
||||
inList = cm.getStateAfter(pos.line).list !== false,
|
||||
match;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
function findMatchingBracket(cm, where, strict) {
|
||||
var state = cm.state.matchBrackets;
|
||||
var maxScanLen = (state && state.maxScanLineLength) || 10000;
|
||||
var maxScanLines = (state && state.maxScanLines) || 100;
|
||||
|
||||
var cur = where || cm.getCursor(), line = cm.getLineHandle(cur.line), pos = cur.ch - 1;
|
||||
var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)];
|
||||
@@ -32,7 +33,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i = cur.line, found, e = forward ? Math.min(i + 100, cm.lineCount()) : Math.max(-1, i - 100); i != e; i+=d) {
|
||||
for (var i = cur.line, found, e = forward ? Math.min(i + maxScanLines, cm.lineCount()) : Math.max(-1, i - maxScanLines); i != e; i+=d) {
|
||||
if (i == cur.line) found = scan(line, i, pos);
|
||||
else found = scan(cm.getLineHandle(i), i);
|
||||
if (found) break;
|
||||
@@ -53,7 +54,7 @@
|
||||
var one = cm.markText(found.from, Pos(found.from.line, found.from.ch + 1), {className: style});
|
||||
var two = found.to && cm.markText(found.to, Pos(found.to.line, found.to.ch + 1), {className: style});
|
||||
// Kludge to work around the IE bug from issue #1193, where text
|
||||
// input stops going to the textare whever this fires.
|
||||
// input stops going to the textarea whenever this fires.
|
||||
if (ie_lt8 && cm.state.focused) cm.display.input.focus();
|
||||
var clear = function() {
|
||||
cm.operation(function() { one.clear(); two && two.clear(); });
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
CodeMirror.registerHelper("fold", "comment", function(cm, start) {
|
||||
CodeMirror.registerGlobalHelper("fold", "comment", function(mode) {
|
||||
return mode.blockCommentStart && mode.blockCommentEnd;
|
||||
}, function(cm, start) {
|
||||
var mode = cm.getModeAt(start), startToken = mode.blockCommentStart, endToken = mode.blockCommentEnd;
|
||||
if (!startToken || !endToken) return;
|
||||
var line = start.line, lineText = cm.getLine(line);
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
|
||||
function doFold(cm, pos, options, force) {
|
||||
var finder = options && (options.call ? options : options.rangeFinder);
|
||||
if (!finder) finder = cm.getHelper(pos, "fold");
|
||||
if (!finder) return;
|
||||
if (!finder) finder = CodeMirror.fold.auto;
|
||||
if (typeof pos == "number") pos = CodeMirror.Pos(pos, 0);
|
||||
var minSize = options && options.minFoldSize || 0;
|
||||
|
||||
@@ -63,6 +62,10 @@
|
||||
doFold(this, pos, options, force);
|
||||
});
|
||||
|
||||
CodeMirror.commands.fold = function(cm) {
|
||||
cm.foldCode(cm.getCursor());
|
||||
};
|
||||
|
||||
CodeMirror.registerHelper("fold", "combine", function() {
|
||||
var funcs = Array.prototype.slice.call(arguments, 0);
|
||||
return function(cm, start) {
|
||||
@@ -72,4 +75,12 @@
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.registerHelper("fold", "auto", function(cm, start) {
|
||||
var helpers = cm.getHelpers(start, "fold");
|
||||
for (var i = 0; i < helpers.length; i++) {
|
||||
var cur = helpers[i](cm, start);
|
||||
if (cur) return cur;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
if (isFolded(cm, cur)) {
|
||||
mark = marker(opts.indicatorFolded);
|
||||
} else {
|
||||
var pos = Pos(cur, 0), func = opts.rangeFinder || cm.getHelper(pos, "fold");
|
||||
var pos = Pos(cur, 0), func = opts.rangeFinder || CodeMirror.fold.auto;
|
||||
var range = func && func(cm, pos);
|
||||
if (range && range.from.line + 1 < range.to.line)
|
||||
mark = marker(opts.indicatorOpen);
|
||||
@@ -88,14 +88,14 @@
|
||||
}
|
||||
|
||||
function onChange(cm) {
|
||||
var state = cm.state.foldGutter;
|
||||
var state = cm.state.foldGutter, opts = cm.state.foldGutter.options;
|
||||
state.from = state.to = 0;
|
||||
clearTimeout(state.changeUpdate);
|
||||
state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, 600);
|
||||
state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600);
|
||||
}
|
||||
|
||||
function onViewportChange(cm) {
|
||||
var state = cm.state.foldGutter;
|
||||
var state = cm.state.foldGutter, opts = cm.state.foldGutter.options;
|
||||
clearTimeout(state.changeUpdate);
|
||||
state.changeUpdate = setTimeout(function() {
|
||||
var vp = cm.getViewport();
|
||||
@@ -113,7 +113,7 @@
|
||||
}
|
||||
});
|
||||
}
|
||||
}, 400);
|
||||
}, opts.updateViewportTimeSpan || 400);
|
||||
}
|
||||
|
||||
function onFold(cm, from) {
|
||||
|
||||
@@ -1,27 +1,30 @@
|
||||
CodeMirror.registerHelper("fold", "indent", function(cm, start) {
|
||||
var lastLine = cm.lastLine(),
|
||||
tabSize = cm.getOption("tabSize"),
|
||||
firstLine = cm.getLine(start.line);
|
||||
if (!tabSize || !firstLine) return;
|
||||
var myIndent = CodeMirror.countColumn(firstLine, null, tabSize);
|
||||
|
||||
function foldEnded(curColumn, prevColumn) {
|
||||
return curColumn < myIndent ||
|
||||
(curColumn == myIndent && prevColumn >= myIndent) ||
|
||||
(curColumn > myIndent && i == lastLine);
|
||||
}
|
||||
|
||||
for (var i = start.line + 1; i <= lastLine; i++) {
|
||||
var curColumn = CodeMirror.countColumn(cm.getLine(i), null, tabSize);
|
||||
var prevColumn = CodeMirror.countColumn(cm.getLine(i-1), null, tabSize);
|
||||
|
||||
if (foldEnded(curColumn, prevColumn)) {
|
||||
var lastFoldLineNumber = curColumn > myIndent && i == lastLine ? i : i-1;
|
||||
var lastFoldLine = cm.getLine(lastFoldLineNumber);
|
||||
return {from: CodeMirror.Pos(start.line, firstLine.length),
|
||||
to: CodeMirror.Pos(lastFoldLineNumber, lastFoldLine.length)};
|
||||
var tabSize = cm.getOption("tabSize"), firstLine = cm.getLine(start.line);
|
||||
if (!/\S/.test(firstLine)) return;
|
||||
var getIndent = function(line) {
|
||||
return CodeMirror.countColumn(line, null, tabSize);
|
||||
};
|
||||
var myIndent = getIndent(firstLine);
|
||||
var lastLineInFold = null;
|
||||
// Go through lines until we find a line that definitely doesn't belong in
|
||||
// the block we're folding, or to the end.
|
||||
for (var i = start.line + 1, end = cm.lastLine(); i <= end; ++i) {
|
||||
var curLine = cm.getLine(i);
|
||||
var curIndent = getIndent(curLine);
|
||||
if (curIndent > myIndent) {
|
||||
// Lines with a greater indent are considered part of the block.
|
||||
lastLineInFold = i;
|
||||
} else if (!/\S/.test(curLine)) {
|
||||
// Empty lines might be breaks within the block we're trying to fold.
|
||||
} else {
|
||||
// A non-empty line at an indent equal to or less than ours marks the
|
||||
// start of another block.
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (lastLineInFold) return {
|
||||
from: CodeMirror.Pos(start.line, firstLine.length),
|
||||
to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length)
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.indentRangeFinder = CodeMirror.fold.indent; // deprecated
|
||||
|
||||
@@ -164,4 +164,10 @@
|
||||
if (close) return {open: open, close: close};
|
||||
}
|
||||
};
|
||||
|
||||
// Used by addon/edit/closetag.js
|
||||
CodeMirror.scanForClosingTag = function(cm, pos, name, end) {
|
||||
var iter = new Iter(cm, pos.line, pos.ch, end ? {from: 0, to: end} : null);
|
||||
return !!findMatchingClose(iter, name);
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
function scriptHint(editor, keywords, getToken, options) {
|
||||
// Find the token at the cursor
|
||||
var cur = editor.getCursor(), token = getToken(editor, cur), tprop = token;
|
||||
if (/\b(?:string|comment)\b/.test(token.type)) return;
|
||||
token.state = CodeMirror.innerMode(editor.getMode(), token.state).state;
|
||||
|
||||
// If it's not a 'word-style' token, ignore the token.
|
||||
@@ -86,7 +87,7 @@
|
||||
function getCompletions(token, context, keywords, options) {
|
||||
var found = [], start = token.string;
|
||||
function maybeAdd(str) {
|
||||
if (str.indexOf(start) == 0 && !arrayContains(found, str)) found.push(str);
|
||||
if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str);
|
||||
}
|
||||
function gatherCompletions(obj) {
|
||||
if (typeof obj == "string") forEach(stringProps, maybeAdd);
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
function getCompletions(token, context) {
|
||||
var found = [], start = token.string;
|
||||
function maybeAdd(str) {
|
||||
if (str.indexOf(start) == 0 && !arrayContains(found, str)) found.push(str);
|
||||
if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str);
|
||||
}
|
||||
|
||||
function gatherCompletions(obj) {
|
||||
|
||||
@@ -31,10 +31,6 @@
|
||||
|
||||
var completionList = getCompletions(token, context);
|
||||
completionList = completionList.sort();
|
||||
//prevent autocomplete for last word, instead show dropdown with one word
|
||||
if(completionList.length == 1) {
|
||||
completionList.push(" ");
|
||||
}
|
||||
|
||||
return {list: completionList,
|
||||
from: CodeMirror.Pos(cur.line, token.start),
|
||||
@@ -66,7 +62,7 @@
|
||||
function getCompletions(token, context) {
|
||||
var found = [], start = token.string;
|
||||
function maybeAdd(str) {
|
||||
if (str.indexOf(start) == 0 && !arrayContains(found, str)) found.push(str);
|
||||
if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str);
|
||||
}
|
||||
|
||||
function gatherCompletions(_obj) {
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
var HINT_ELEMENT_CLASS = "CodeMirror-hint";
|
||||
var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active";
|
||||
|
||||
CodeMirror.showHint = function(cm, getHints, options) {
|
||||
// We want a single cursor position.
|
||||
if (cm.somethingSelected()) return;
|
||||
if (getHints == null) getHints = cm.getHelper(cm.getCursor(), "hint");
|
||||
if (getHints == null) return;
|
||||
if (getHints == null) {
|
||||
if (options && options.async) return;
|
||||
else getHints = CodeMirror.hint.auto;
|
||||
}
|
||||
|
||||
if (cm.state.completionActive) cm.state.completionActive.close();
|
||||
|
||||
@@ -42,6 +47,7 @@
|
||||
var completion = data.list[i];
|
||||
if (completion.hint) completion.hint(this.cm, data, completion);
|
||||
else this.cm.replaceRange(getText(completion), data.from, data.to);
|
||||
CodeMirror.signal(data, "pick", completion);
|
||||
this.close();
|
||||
},
|
||||
|
||||
@@ -58,10 +64,15 @@
|
||||
this.widget = new Widget(this, data);
|
||||
CodeMirror.signal(data, "shown");
|
||||
|
||||
var debounce = null, completion = this, finished;
|
||||
var debounce = 0, completion = this, finished;
|
||||
var closeOn = this.options.closeCharacters || /[\s()\[\]{};:>,]/;
|
||||
var startPos = this.cm.getCursor(), startLen = this.cm.getLine(startPos.line).length;
|
||||
|
||||
var requestAnimationFrame = window.requestAnimationFrame || function(fn) {
|
||||
return setTimeout(fn, 1000/60);
|
||||
};
|
||||
var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;
|
||||
|
||||
function done() {
|
||||
if (finished) return;
|
||||
finished = true;
|
||||
@@ -85,15 +96,22 @@
|
||||
completion.widget = new Widget(completion, data);
|
||||
}
|
||||
|
||||
function clearDebounce() {
|
||||
if (debounce) {
|
||||
cancelAnimationFrame(debounce);
|
||||
debounce = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function activity() {
|
||||
clearTimeout(debounce);
|
||||
clearDebounce();
|
||||
var pos = completion.cm.getCursor(), line = completion.cm.getLine(pos.line);
|
||||
if (pos.line != startPos.line || line.length - pos.ch != startLen - startPos.ch ||
|
||||
pos.ch < startPos.ch || completion.cm.somethingSelected() ||
|
||||
(pos.ch && closeOn.test(line.charAt(pos.ch - 1)))) {
|
||||
completion.close();
|
||||
} else {
|
||||
debounce = setTimeout(update, 170);
|
||||
debounce = requestAnimationFrame(update);
|
||||
if (completion.widget) completion.widget.close();
|
||||
}
|
||||
}
|
||||
@@ -140,6 +158,13 @@
|
||||
return ourMap;
|
||||
}
|
||||
|
||||
function getHintElement(hintsElement, el) {
|
||||
while (el && el != hintsElement) {
|
||||
if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el;
|
||||
el = el.parentNode;
|
||||
}
|
||||
}
|
||||
|
||||
function Widget(completion, data) {
|
||||
this.completion = completion;
|
||||
this.data = data;
|
||||
@@ -147,12 +172,12 @@
|
||||
|
||||
var hints = this.hints = document.createElement("ul");
|
||||
hints.className = "CodeMirror-hints";
|
||||
this.selectedHint = 0;
|
||||
this.selectedHint = options.getDefaultSelection ? options.getDefaultSelection(cm,options,data) : 0;
|
||||
|
||||
var completions = data.list;
|
||||
for (var i = 0; i < completions.length; ++i) {
|
||||
var elt = hints.appendChild(document.createElement("li")), cur = completions[i];
|
||||
var className = "CodeMirror-hint" + (i ? "" : " CodeMirror-hint-active");
|
||||
var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS);
|
||||
if (cur.className != null) className = cur.className + " " + className;
|
||||
elt.className = className;
|
||||
if (cur.render) cur.render(elt, data, cur);
|
||||
@@ -216,13 +241,18 @@
|
||||
});
|
||||
|
||||
CodeMirror.on(hints, "dblclick", function(e) {
|
||||
var t = e.target || e.srcElement;
|
||||
if (t.hintId != null) {widget.changeActive(t.hintId); widget.pick();}
|
||||
var t = getHintElement(hints, e.target || e.srcElement);
|
||||
if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();}
|
||||
});
|
||||
|
||||
CodeMirror.on(hints, "click", function(e) {
|
||||
var t = e.target || e.srcElement;
|
||||
if (t.hintId != null) widget.changeActive(t.hintId);
|
||||
var t = getHintElement(hints, e.target || e.srcElement);
|
||||
if (t && t.hintId != null) {
|
||||
widget.changeActive(t.hintId);
|
||||
if (options.completeOnSingleClick) widget.pick();
|
||||
}
|
||||
});
|
||||
|
||||
CodeMirror.on(hints, "mousedown", function() {
|
||||
setTimeout(function(){cm.focus();}, 20);
|
||||
});
|
||||
@@ -257,9 +287,9 @@
|
||||
i = avoidWrap ? 0 : this.data.list.length - 1;
|
||||
if (this.selectedHint == i) return;
|
||||
var node = this.hints.childNodes[this.selectedHint];
|
||||
node.className = node.className.replace(" CodeMirror-hint-active", "");
|
||||
node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, "");
|
||||
node = this.hints.childNodes[this.selectedHint = i];
|
||||
node.className += " CodeMirror-hint-active";
|
||||
node.className += " " + ACTIVE_HINT_ELEMENT_CLASS;
|
||||
if (node.offsetTop < this.hints.scrollTop)
|
||||
this.hints.scrollTop = node.offsetTop - 3;
|
||||
else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight)
|
||||
@@ -271,4 +301,35 @@
|
||||
return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1;
|
||||
}
|
||||
};
|
||||
|
||||
CodeMirror.registerHelper("hint", "auto", function(cm, options) {
|
||||
var helpers = cm.getHelpers(cm.getCursor(), "hint");
|
||||
if (helpers.length) {
|
||||
for (var i = 0; i < helpers.length; i++) {
|
||||
var cur = helpers[i](cm, options);
|
||||
if (cur && cur.list.length) return cur;
|
||||
}
|
||||
} else {
|
||||
var words = cm.getHelper(cm.getCursor(), "hintWords");
|
||||
if (words) return CodeMirror.hint.fromList(cm, {words: words});
|
||||
}
|
||||
});
|
||||
|
||||
CodeMirror.registerHelper("hint", "fromList", function(cm, options) {
|
||||
var cur = cm.getCursor(), token = cm.getTokenAt(cur);
|
||||
var found = [];
|
||||
for (var i = 0; i < options.words.length; i++) {
|
||||
var word = options.words[i];
|
||||
if (word.slice(0, token.string.length) == token.string)
|
||||
found.push(word);
|
||||
}
|
||||
|
||||
if (found.length) return {
|
||||
list: found,
|
||||
from: CodeMirror.Pos(cur.line, token.start),
|
||||
to: CodeMirror.Pos(cur.line, token.end)
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.commands.autocomplete = CodeMirror.showHint;
|
||||
})();
|
||||
|
||||
@@ -20,13 +20,13 @@
|
||||
var cx = inner.state.context, curTag = cx && tags[cx.tagName];
|
||||
var childList = cx ? curTag && curTag.children : tags["!top"];
|
||||
if (childList) {
|
||||
for (var i = 0; i < childList.length; ++i) if (!prefix || childList[i].indexOf(prefix) == 0)
|
||||
for (var i = 0; i < childList.length; ++i) if (!prefix || childList[i].lastIndexOf(prefix, 0) == 0)
|
||||
result.push("<" + childList[i]);
|
||||
} else {
|
||||
for (var name in tags) if (tags.hasOwnProperty(name) && name != "!top" && (!prefix || name.indexOf(prefix) == 0))
|
||||
for (var name in tags) if (tags.hasOwnProperty(name) && name != "!top" && (!prefix || name.lastIndexOf(prefix, 0) == 0))
|
||||
result.push("<" + name);
|
||||
}
|
||||
if (cx && (!prefix || ("/" + cx.tagName).indexOf(prefix) == 0))
|
||||
if (cx && (!prefix || ("/" + cx.tagName).lastIndexOf(prefix, 0) == 0))
|
||||
result.push("</" + cx.tagName + ">");
|
||||
} else {
|
||||
// Attribute completion
|
||||
@@ -46,14 +46,14 @@
|
||||
}
|
||||
replaceToken = true;
|
||||
}
|
||||
for (var i = 0; i < atValues.length; ++i) if (!prefix || atValues[i].indexOf(prefix) == 0)
|
||||
for (var i = 0; i < atValues.length; ++i) if (!prefix || atValues[i].lastIndexOf(prefix, 0) == 0)
|
||||
result.push(quote + atValues[i] + quote);
|
||||
} else { // An attribute name
|
||||
if (token.type == "attribute") {
|
||||
prefix = token.string;
|
||||
replaceToken = true;
|
||||
}
|
||||
for (var attr in attrs) if (attrs.hasOwnProperty(attr) && (!prefix || attr.indexOf(prefix) == 0))
|
||||
for (var attr in attrs) if (attrs.hasOwnProperty(attr) && (!prefix || attr.lastIndexOf(prefix, 0) == 0))
|
||||
result.push(attr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
if (options.async)
|
||||
options.getAnnotations(cm, updateLinting, options);
|
||||
else
|
||||
updateLinting(cm, options.getAnnotations(cm.getValue(), options));
|
||||
updateLinting(cm, options.getAnnotations(cm.getValue(), options.options));
|
||||
}
|
||||
|
||||
function updateLinting(cm, annotationsNotSorted) {
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
this.edit = this.mv.edit;
|
||||
this.orig = CodeMirror(pane, copyObj({value: orig, readOnly: true}, copyObj(options)));
|
||||
|
||||
this.diff = getDiff(orig, options.value);
|
||||
this.diff = getDiff(asString(orig), asString(options.value));
|
||||
this.diffOutOfDate = false;
|
||||
|
||||
this.showDifferences = options.showDifferences !== false;
|
||||
@@ -352,6 +352,11 @@
|
||||
}
|
||||
};
|
||||
|
||||
function asString(obj) {
|
||||
if (typeof obj == "string") return obj;
|
||||
else return obj.getValue();
|
||||
}
|
||||
|
||||
// Operations on diffs
|
||||
|
||||
var dmp = new diff_match_patch();
|
||||
|
||||
@@ -47,7 +47,11 @@ CodeMirror.multiplexingMode = function(outer /*, others */) {
|
||||
return outerToken;
|
||||
} else {
|
||||
var curInner = state.innerActive, oldContent = stream.string;
|
||||
var found = indexOf(oldContent, curInner.close, stream.pos);
|
||||
if (!curInner.close && stream.sol()) {
|
||||
state.innerActive = state.inner = null;
|
||||
return this.token(stream, state);
|
||||
}
|
||||
var found = curInner.close ? indexOf(oldContent, curInner.close, stream.pos) : -1;
|
||||
if (found == stream.pos) {
|
||||
stream.match(curInner.close);
|
||||
state.innerActive = state.inner = null;
|
||||
@@ -56,8 +60,6 @@ CodeMirror.multiplexingMode = function(outer /*, others */) {
|
||||
if (found > -1) stream.string = oldContent.slice(0, found);
|
||||
var innerToken = curInner.mode.token(stream, state.inner);
|
||||
if (found > -1) stream.string = oldContent;
|
||||
var cur = stream.current(), found = cur.indexOf(curInner.close);
|
||||
if (found > -1) stream.backUp(cur.length - found);
|
||||
|
||||
if (curInner.innerStyle) {
|
||||
if (innerToken) innerToken = innerToken + ' ' + curInner.innerStyle;
|
||||
|
||||
@@ -10,6 +10,7 @@ function splitLines(string){ return string.split(/\r?\n|\r/); };
|
||||
function StringStream(string) {
|
||||
this.pos = this.start = 0;
|
||||
this.string = string;
|
||||
this.lineStart = 0;
|
||||
}
|
||||
StringStream.prototype = {
|
||||
eol: function() {return this.pos >= this.string.length;},
|
||||
@@ -41,7 +42,7 @@ StringStream.prototype = {
|
||||
if (found > -1) {this.pos = found; return true;}
|
||||
},
|
||||
backUp: function(n) {this.pos -= n;},
|
||||
column: function() {return this.start;},
|
||||
column: function() {return this.start - this.lineStart;},
|
||||
indentation: function() {return 0;},
|
||||
match: function(pattern, consume, caseInsensitive) {
|
||||
if (typeof pattern == "string") {
|
||||
@@ -58,7 +59,12 @@ StringStream.prototype = {
|
||||
return match;
|
||||
}
|
||||
},
|
||||
current: function(){return this.string.slice(this.start, this.pos);}
|
||||
current: function(){return this.string.slice(this.start, this.pos);},
|
||||
hideFirstChars: function(n, inner) {
|
||||
this.lineStart += n;
|
||||
try { return inner(); }
|
||||
finally { this.lineStart -= n; }
|
||||
}
|
||||
};
|
||||
CodeMirror.StringStream = StringStream;
|
||||
|
||||
@@ -69,17 +75,26 @@ CodeMirror.startState = function (mode, a1, a2) {
|
||||
var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};
|
||||
CodeMirror.defineMode = function (name, mode) { modes[name] = mode; };
|
||||
CodeMirror.defineMIME = function (mime, spec) { mimeModes[mime] = spec; };
|
||||
CodeMirror.getMode = function (options, spec) {
|
||||
if (typeof spec == "string" && mimeModes.hasOwnProperty(spec))
|
||||
CodeMirror.resolveMode = function(spec) {
|
||||
if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
|
||||
spec = mimeModes[spec];
|
||||
if (typeof spec == "string")
|
||||
var mname = spec, config = {};
|
||||
else if (spec != null)
|
||||
var mname = spec.name, config = spec;
|
||||
var mfactory = modes[mname];
|
||||
if (!mfactory) throw new Error("Unknown mode: " + spec);
|
||||
return mfactory(options, config || {});
|
||||
} else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
|
||||
spec = mimeModes[spec.name];
|
||||
}
|
||||
if (typeof spec == "string") return {name: spec};
|
||||
else return spec || {name: "null"};
|
||||
};
|
||||
CodeMirror.getMode = function (options, spec) {
|
||||
spec = CodeMirror.resolveMode(spec);
|
||||
var mfactory = modes[spec.name];
|
||||
if (!mfactory) throw new Error("Unknown mode: " + spec);
|
||||
return mfactory(options, spec);
|
||||
};
|
||||
CodeMirror.registerHelper = CodeMirror.registerGlobalHelper = Math.min;
|
||||
CodeMirror.defineMode("null", function() {
|
||||
return {token: function(stream) {stream.skipToEnd();}};
|
||||
});
|
||||
CodeMirror.defineMIME("text/plain", "null");
|
||||
|
||||
CodeMirror.runMode = function (string, modespec, callback, options) {
|
||||
var mode = CodeMirror.getMode({ indentUnit: 2 }, modespec);
|
||||
@@ -122,7 +137,7 @@ CodeMirror.runMode = function (string, modespec, callback, options) {
|
||||
};
|
||||
}
|
||||
|
||||
var lines = splitLines(string), state = CodeMirror.startState(mode);
|
||||
var lines = splitLines(string), state = (options && options.state) || CodeMirror.startState(mode);
|
||||
for (var i = 0, e = lines.length; i < e; ++i) {
|
||||
if (i) callback("\n");
|
||||
var stream = new CodeMirror.StringStream(lines[i]);
|
||||
|
||||
@@ -43,7 +43,7 @@ CodeMirror.runMode = function(string, modespec, callback, options) {
|
||||
};
|
||||
}
|
||||
|
||||
var lines = CodeMirror.splitLines(string), state = CodeMirror.startState(mode);
|
||||
var lines = CodeMirror.splitLines(string), state = (options && options.state) || CodeMirror.startState(mode);
|
||||
for (var i = 0, e = lines.length; i < e; ++i) {
|
||||
if (i) callback("\n");
|
||||
var stream = new CodeMirror.StringStream(lines[i]);
|
||||
|
||||
@@ -5,6 +5,7 @@ function splitLines(string){ return string.split(/\r?\n|\r/); };
|
||||
function StringStream(string) {
|
||||
this.pos = this.start = 0;
|
||||
this.string = string;
|
||||
this.lineStart = 0;
|
||||
}
|
||||
StringStream.prototype = {
|
||||
eol: function() {return this.pos >= this.string.length;},
|
||||
@@ -36,7 +37,7 @@ StringStream.prototype = {
|
||||
if (found > -1) {this.pos = found; return true;}
|
||||
},
|
||||
backUp: function(n) {this.pos -= n;},
|
||||
column: function() {return this.start;},
|
||||
column: function() {return this.start - this.lineStart;},
|
||||
indentation: function() {return 0;},
|
||||
match: function(pattern, consume, caseInsensitive) {
|
||||
if (typeof pattern == "string") {
|
||||
@@ -53,7 +54,12 @@ StringStream.prototype = {
|
||||
return match;
|
||||
}
|
||||
},
|
||||
current: function(){return this.string.slice(this.start, this.pos);}
|
||||
current: function(){return this.string.slice(this.start, this.pos);},
|
||||
hideFirstChars: function(n, inner) {
|
||||
this.lineStart += n;
|
||||
try { return inner(); }
|
||||
finally { this.lineStart -= n; }
|
||||
}
|
||||
};
|
||||
exports.StringStream = StringStream;
|
||||
|
||||
@@ -76,21 +82,26 @@ exports.defineMode("null", function() {
|
||||
});
|
||||
exports.defineMIME("text/plain", "null");
|
||||
|
||||
exports.getMode = function(options, spec) {
|
||||
if (typeof spec == "string" && mimeModes.hasOwnProperty(spec))
|
||||
exports.resolveMode = function(spec) {
|
||||
if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
|
||||
spec = mimeModes[spec];
|
||||
if (typeof spec == "string")
|
||||
var mname = spec, config = {};
|
||||
else if (spec != null)
|
||||
var mname = spec.name, config = spec;
|
||||
var mfactory = modes[mname];
|
||||
if (!mfactory) throw new Error("Unknown mode: " + spec);
|
||||
return mfactory(options, config || {});
|
||||
} else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
|
||||
spec = mimeModes[spec.name];
|
||||
}
|
||||
if (typeof spec == "string") return {name: spec};
|
||||
else return spec || {name: "null"};
|
||||
};
|
||||
exports.getMode = function(options, spec) {
|
||||
spec = exports.resolveMode(mimeModes[spec]);
|
||||
var mfactory = modes[spec.name];
|
||||
if (!mfactory) throw new Error("Unknown mode: " + spec);
|
||||
return mfactory(options, spec);
|
||||
};
|
||||
exports.registerHelper = exports.registerGlobalHelper = Math.min;
|
||||
|
||||
exports.runMode = function(string, modespec, callback) {
|
||||
var mode = exports.getMode({indentUnit: 2}, modespec);
|
||||
var lines = splitLines(string), state = exports.startState(mode);
|
||||
var lines = splitLines(string), state = (options && options.state) || exports.startState(mode);
|
||||
for (var i = 0, e = lines.length; i < e; ++i) {
|
||||
if (i) callback("\n");
|
||||
var stream = new exports.StringStream(lines[i]);
|
||||
|
||||
@@ -7,7 +7,15 @@
|
||||
// Ctrl-G.
|
||||
|
||||
(function() {
|
||||
function searchOverlay(query) {
|
||||
function searchOverlay(query, caseInsensitive) {
|
||||
var startChar;
|
||||
if (typeof query == "string") {
|
||||
startChar = query.charAt(0);
|
||||
query = new RegExp("^" + query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"),
|
||||
caseInsensitive ? "i" : "");
|
||||
} else {
|
||||
query = new RegExp("^(?:" + query.source + ")", query.ignoreCase ? "i" : "");
|
||||
}
|
||||
if (typeof query == "string") return {token: function(stream) {
|
||||
if (stream.match(query)) return "searching";
|
||||
stream.next();
|
||||
@@ -17,6 +25,8 @@
|
||||
if (stream.match(query)) return "searching";
|
||||
while (!stream.eol()) {
|
||||
stream.next();
|
||||
if (startChar)
|
||||
stream.skipTo(startChar) || stream.skipToEnd();
|
||||
if (stream.match(query, false)) break;
|
||||
}
|
||||
}};
|
||||
@@ -29,13 +39,16 @@
|
||||
function getSearchState(cm) {
|
||||
return cm.state.search || (cm.state.search = new SearchState());
|
||||
}
|
||||
function queryCaseInsensitive(query) {
|
||||
return typeof query == "string" && query == query.toLowerCase();
|
||||
}
|
||||
function getSearchCursor(cm, query, pos) {
|
||||
// Heuristic: if the query string is all lowercase, do a case insensitive search.
|
||||
return cm.getSearchCursor(query, pos, typeof query == "string" && query == query.toLowerCase());
|
||||
return cm.getSearchCursor(query, pos, queryCaseInsensitive(query));
|
||||
}
|
||||
function dialog(cm, text, shortText, f) {
|
||||
if (cm.openDialog) cm.openDialog(text, f);
|
||||
else f(prompt(shortText, ""));
|
||||
function dialog(cm, text, shortText, deflt, f) {
|
||||
if (cm.openDialog) cm.openDialog(text, f, {value: deflt});
|
||||
else f(prompt(shortText, deflt));
|
||||
}
|
||||
function confirmDialog(cm, text, shortText, fs) {
|
||||
if (cm.openConfirm) cm.openConfirm(text, fs);
|
||||
@@ -50,11 +63,11 @@
|
||||
function doSearch(cm, rev) {
|
||||
var state = getSearchState(cm);
|
||||
if (state.query) return findNext(cm, rev);
|
||||
dialog(cm, queryDialog, "Search for:", function(query) {
|
||||
dialog(cm, queryDialog, "Search for:", cm.getSelection(), function(query) {
|
||||
cm.operation(function() {
|
||||
if (!query || state.query) return;
|
||||
state.query = parseQuery(query);
|
||||
cm.removeOverlay(state.overlay);
|
||||
cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query));
|
||||
state.overlay = searchOverlay(state.query);
|
||||
cm.addOverlay(state.overlay);
|
||||
state.posFrom = state.posTo = cm.getCursor();
|
||||
@@ -85,10 +98,10 @@
|
||||
var replacementQueryDialog = 'With: <input type="text" style="width: 10em"/>';
|
||||
var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>Stop</button>";
|
||||
function replace(cm, all) {
|
||||
dialog(cm, replaceQueryDialog, "Replace:", function(query) {
|
||||
dialog(cm, replaceQueryDialog, "Replace:", cm.getSelection(), function(query) {
|
||||
if (!query) return;
|
||||
query = parseQuery(query);
|
||||
dialog(cm, replacementQueryDialog, "Replace with:", function(text) {
|
||||
dialog(cm, replacementQueryDialog, "Replace with:", "", function(text) {
|
||||
if (all) {
|
||||
cm.operation(function() {
|
||||
for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
match: match};
|
||||
};
|
||||
} else { // String query
|
||||
var origQuery = query;
|
||||
if (caseFold) query = query.toLowerCase();
|
||||
var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;};
|
||||
var target = query.split("\n");
|
||||
@@ -58,33 +59,45 @@
|
||||
this.matches = function() {};
|
||||
} else {
|
||||
this.matches = function(reverse, pos) {
|
||||
var line = fold(doc.getLine(pos.line)), len = query.length, match;
|
||||
if (reverse ? (pos.ch >= len && (match = line.lastIndexOf(query, pos.ch - len)) != -1)
|
||||
: (match = line.indexOf(query, pos.ch)) != -1)
|
||||
return {from: Pos(pos.line, match),
|
||||
to: Pos(pos.line, match + len)};
|
||||
if (reverse) {
|
||||
var orig = doc.getLine(pos.line).slice(0, pos.ch), line = fold(orig);
|
||||
var match = line.lastIndexOf(query);
|
||||
if (match > -1) {
|
||||
match = adjustPos(orig, line, match);
|
||||
return {from: Pos(pos.line, match), to: Pos(pos.line, match + origQuery.length)};
|
||||
}
|
||||
} else {
|
||||
var orig = doc.getLine(pos.line).slice(pos.ch), line = fold(orig);
|
||||
var match = line.indexOf(query);
|
||||
if (match > -1) {
|
||||
match = adjustPos(orig, line, match) + pos.ch;
|
||||
return {from: Pos(pos.line, match), to: Pos(pos.line, match + origQuery.length)};
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
} else {
|
||||
var origTarget = origQuery.split("\n");
|
||||
this.matches = function(reverse, pos) {
|
||||
var ln = pos.line, idx = (reverse ? target.length - 1 : 0), match = target[idx], line = fold(doc.getLine(ln));
|
||||
var offsetA = (reverse ? line.indexOf(match) + match.length : line.lastIndexOf(match));
|
||||
if (reverse ? offsetA > pos.ch || offsetA != match.length
|
||||
: offsetA < pos.ch || offsetA != line.length - match.length)
|
||||
return;
|
||||
for (;;) {
|
||||
if (reverse ? !ln : ln == doc.lineCount() - 1) return;
|
||||
line = fold(doc.getLine(ln += reverse ? -1 : 1));
|
||||
match = target[reverse ? --idx : ++idx];
|
||||
if (idx > 0 && idx < target.length - 1) {
|
||||
if (line != match) return;
|
||||
else continue;
|
||||
}
|
||||
var offsetB = (reverse ? line.lastIndexOf(match) : line.indexOf(match) + match.length);
|
||||
if (reverse ? offsetB != line.length - match.length : offsetB != match.length)
|
||||
return;
|
||||
var start = Pos(pos.line, offsetA), end = Pos(ln, offsetB);
|
||||
return {from: reverse ? end : start, to: reverse ? start : end};
|
||||
var last = target.length - 1;
|
||||
if (reverse) {
|
||||
if (pos.line - (target.length - 1) < doc.firstLine()) return;
|
||||
if (fold(doc.getLine(pos.line).slice(0, origTarget[last].length)) != target[target.length - 1]) return;
|
||||
var to = Pos(pos.line, origTarget[last].length);
|
||||
for (var ln = pos.line - 1, i = last - 1; i >= 1; --i, --ln)
|
||||
if (target[i] != fold(doc.getLine(ln))) return;
|
||||
var line = doc.getLine(ln), cut = line.length - origTarget[0].length;
|
||||
if (fold(line.slice(cut)) != target[0]) return;
|
||||
return {from: Pos(ln, cut), to: to};
|
||||
} else {
|
||||
if (pos.line + (target.length - 1) > doc.lastLine()) return;
|
||||
var line = doc.getLine(pos.line), cut = line.length - origTarget[0].length;
|
||||
if (fold(line.slice(cut)) != target[0]) return;
|
||||
var from = Pos(pos.line, cut);
|
||||
for (var ln = pos.line + 1, i = 1; i < last; ++i, ++ln)
|
||||
if (target[i] != fold(doc.getLine(ln))) return;
|
||||
if (doc.getLine(ln).slice(0, origTarget[last].length) != target[last]) return;
|
||||
return {from: from, to: Pos(ln, origTarget[last].length)};
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -106,7 +119,6 @@
|
||||
|
||||
for (;;) {
|
||||
if (this.pos = this.matches(reverse, pos)) {
|
||||
if (!this.pos.from || !this.pos.to) { console.log(this.matches, this.pos); }
|
||||
this.atOccurrence = true;
|
||||
return this.pos.match || true;
|
||||
}
|
||||
@@ -134,6 +146,18 @@
|
||||
}
|
||||
};
|
||||
|
||||
// Maps a position in a case-folded line back to a position in the original line
|
||||
// (compensating for codepoints increasing in number during folding)
|
||||
function adjustPos(orig, folded, pos) {
|
||||
if (orig.length == folded.length) return pos;
|
||||
for (var pos1 = Math.min(pos, orig.length);;) {
|
||||
var len1 = orig.slice(0, pos1).toLowerCase().length;
|
||||
if (len1 < pos) ++pos1;
|
||||
else if (len1 > pos) --pos1;
|
||||
else return pos1;
|
||||
}
|
||||
}
|
||||
|
||||
CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) {
|
||||
return new SearchCursor(this.doc, query, pos, caseFold);
|
||||
});
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
CodeMirror.defineOption("styleActiveLine", false, function(cm, val, old) {
|
||||
var prev = old && old != CodeMirror.Init;
|
||||
if (val && !prev) {
|
||||
updateActiveLine(cm);
|
||||
cm.on("cursorActivity", updateActiveLine);
|
||||
updateActiveLine(cm, cm.getCursor().line);
|
||||
cm.on("beforeSelectionChange", selectionChange);
|
||||
} else if (!val && prev) {
|
||||
cm.off("cursorActivity", updateActiveLine);
|
||||
cm.off("beforeSelectionChange", selectionChange);
|
||||
clearActiveLine(cm);
|
||||
delete cm.state.activeLine;
|
||||
}
|
||||
@@ -28,12 +28,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
function updateActiveLine(cm) {
|
||||
var line = cm.getLineHandleVisualStart(cm.getCursor().line);
|
||||
function updateActiveLine(cm, selectedLine) {
|
||||
var line = cm.getLineHandleVisualStart(selectedLine);
|
||||
if (cm.state.activeLine == line) return;
|
||||
clearActiveLine(cm);
|
||||
cm.addLineClass(line, "wrap", WRAP_CLASS);
|
||||
cm.addLineClass(line, "background", BACK_CLASS);
|
||||
cm.state.activeLine = line;
|
||||
cm.operation(function() {
|
||||
clearActiveLine(cm);
|
||||
cm.addLineClass(line, "wrap", WRAP_CLASS);
|
||||
cm.addLineClass(line, "background", BACK_CLASS);
|
||||
cm.state.activeLine = line;
|
||||
});
|
||||
}
|
||||
|
||||
function selectionChange(cm, sel) {
|
||||
updateActiveLine(cm, sel.head.line);
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -201,6 +201,11 @@
|
||||
cm.on("change", function() { cm.setExtending(false); });
|
||||
}
|
||||
|
||||
function clearMark(cm) {
|
||||
cm.setExtending(false);
|
||||
cm.setCursor(cm.getCursor());
|
||||
}
|
||||
|
||||
function getInput(cm, msg, f) {
|
||||
if (cm.openDialog)
|
||||
cm.openDialog(msg + ": <input type=\"text\" style=\"width: 10em\"/>", f, {bottom: true});
|
||||
@@ -234,6 +239,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
function quit(cm) {
|
||||
cm.execCommand("clearSearch");
|
||||
clearMark(cm);
|
||||
}
|
||||
|
||||
// Actual keymap
|
||||
|
||||
var keyMap = CodeMirror.keyMap.emacs = {
|
||||
@@ -249,6 +259,7 @@
|
||||
}),
|
||||
"Alt-W": function(cm) {
|
||||
addToRing(cm.getSelection());
|
||||
clearMark(cm);
|
||||
},
|
||||
"Ctrl-Y": function(cm) {
|
||||
var start = cm.getCursor();
|
||||
@@ -334,7 +345,7 @@
|
||||
"Ctrl-/": repeated("undo"), "Shift-Ctrl--": repeated("undo"),
|
||||
"Ctrl-Z": repeated("undo"), "Cmd-Z": repeated("undo"),
|
||||
"Shift-Alt-,": "goDocStart", "Shift-Alt-.": "goDocEnd",
|
||||
"Ctrl-S": "findNext", "Ctrl-R": "findPrev", "Ctrl-G": "clearSearch", "Shift-Alt-5": "replace",
|
||||
"Ctrl-S": "findNext", "Ctrl-R": "findPrev", "Ctrl-G": quit, "Shift-Alt-5": "replace",
|
||||
"Alt-/": "autocomplete",
|
||||
"Ctrl-J": "newlineAndIndent", "Enter": false, "Tab": "indentAuto",
|
||||
|
||||
|
||||
145
applications/admin/static/codemirror/keymap/vim.js
vendored
145
applications/admin/static/codemirror/keymap/vim.js
vendored
@@ -84,6 +84,7 @@
|
||||
{ keys: ['<End>'], type: 'keyToKey', toKeys: ['$'] },
|
||||
{ keys: ['<PageUp>'], type: 'keyToKey', toKeys: ['<C-b>'] },
|
||||
{ keys: ['<PageDown>'], type: 'keyToKey', toKeys: ['<C-f>'] },
|
||||
{ keys: ['<CR>'], type: 'keyToKey', toKeys: ['j', '^'], context: 'normal' },
|
||||
// Motions
|
||||
{ keys: ['H'], type: 'motion',
|
||||
motion: 'moveToTopLine',
|
||||
@@ -247,6 +248,12 @@
|
||||
actionArgs: { forward: true }},
|
||||
{ keys: ['<C-o>'], type: 'action', action: 'jumpListWalk',
|
||||
actionArgs: { forward: false }},
|
||||
{ keys: ['<C-e>'], type: 'action',
|
||||
action: 'scroll',
|
||||
actionArgs: { forward: true, linewise: true }},
|
||||
{ keys: ['<C-y>'], type: 'action',
|
||||
action: 'scroll',
|
||||
actionArgs: { forward: false, linewise: true }},
|
||||
{ keys: ['a'], type: 'action', action: 'enterInsertMode', isEdit: true,
|
||||
actionArgs: { insertAt: 'charAfter' }},
|
||||
{ keys: ['A'], type: 'action', action: 'enterInsertMode', isEdit: true,
|
||||
@@ -324,12 +331,16 @@
|
||||
CodeMirror.defineOption('vimMode', false, function(cm, val) {
|
||||
if (val) {
|
||||
cm.setOption('keyMap', 'vim');
|
||||
cm.setOption('disableInput', true);
|
||||
CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"});
|
||||
cm.on('beforeSelectionChange', beforeSelectionChange);
|
||||
maybeInitVimState(cm);
|
||||
CodeMirror.on(cm.getInputField(), 'paste', getOnPasteFn(cm));
|
||||
} else if (cm.state.vim) {
|
||||
cm.setOption('keyMap', 'default');
|
||||
cm.setOption('disableInput', false);
|
||||
cm.off('beforeSelectionChange', beforeSelectionChange);
|
||||
CodeMirror.off(cm.getInputField(), 'paste', getOnPasteFn(cm));
|
||||
cm.state.vim = null;
|
||||
}
|
||||
});
|
||||
@@ -342,6 +353,18 @@
|
||||
head.ch--;
|
||||
}
|
||||
}
|
||||
function getOnPasteFn(cm) {
|
||||
var vim = cm.state.vim;
|
||||
if (!vim.onPasteFn) {
|
||||
vim.onPasteFn = function() {
|
||||
if (!vim.insertMode) {
|
||||
cm.setCursor(offsetCursor(cm.getCursor(), 0, 1));
|
||||
actions.enterInsertMode(cm, {}, vim);
|
||||
}
|
||||
};
|
||||
}
|
||||
return vim.onPasteFn;
|
||||
}
|
||||
|
||||
var numberRegex = /[\d]/;
|
||||
var wordRegexp = [(/\w/), (/[^\w\s]/)], bigWordRegexp = [(/\S/)];
|
||||
@@ -549,9 +572,9 @@
|
||||
maybeInitVimState_: maybeInitVimState,
|
||||
|
||||
InsertModeKey: InsertModeKey,
|
||||
map: function(lhs, rhs) {
|
||||
map: function(lhs, rhs, ctx) {
|
||||
// Add user defined key bindings.
|
||||
exCommandDispatcher.map(lhs, rhs);
|
||||
exCommandDispatcher.map(lhs, rhs, ctx);
|
||||
},
|
||||
defineEx: function(name, prefix, func){
|
||||
if (name.indexOf(prefix) !== 0) {
|
||||
@@ -833,11 +856,17 @@
|
||||
} else {
|
||||
// Find the best match in the list of matchedCommands.
|
||||
var context = vim.visualMode ? 'visual' : 'normal';
|
||||
var bestMatch = matchedCommands[0]; // Default to first in the list.
|
||||
var bestMatch; // Default to first in the list.
|
||||
for (var i = 0; i < matchedCommands.length; i++) {
|
||||
if (matchedCommands[i].context == context) {
|
||||
bestMatch = matchedCommands[i];
|
||||
var current = matchedCommands[i];
|
||||
if (current.context == context) {
|
||||
bestMatch = current;
|
||||
break;
|
||||
} else if (!bestMatch && !current.context) {
|
||||
// Only set an imperfect match to best match if no best match is
|
||||
// set and the imperfect match is not restricted to another
|
||||
// context.
|
||||
bestMatch = current;
|
||||
}
|
||||
}
|
||||
return getFullyMatchedCommandOrNull(bestMatch);
|
||||
@@ -1636,6 +1665,43 @@
|
||||
markPos = markPos ? markPos : cm.getCursor();
|
||||
cm.setCursor(markPos);
|
||||
},
|
||||
scroll: function(cm, actionArgs, vim) {
|
||||
if (vim.visualMode) {
|
||||
return;
|
||||
}
|
||||
var repeat = actionArgs.repeat || 1;
|
||||
var lineHeight = cm.defaultTextHeight();
|
||||
var top = cm.getScrollInfo().top;
|
||||
var delta = lineHeight * repeat;
|
||||
var newPos = actionArgs.forward ? top + delta : top - delta;
|
||||
var cursor = cm.getCursor();
|
||||
var cursorCoords = cm.charCoords(cursor, 'local');
|
||||
if (actionArgs.forward) {
|
||||
if (newPos > cursorCoords.top) {
|
||||
cursor.line += (newPos - cursorCoords.top) / lineHeight;
|
||||
cursor.line = Math.ceil(cursor.line);
|
||||
cm.setCursor(cursor);
|
||||
cursorCoords = cm.charCoords(cursor, 'local');
|
||||
cm.scrollTo(null, cursorCoords.top);
|
||||
} else {
|
||||
// Cursor stays within bounds. Just reposition the scroll window.
|
||||
cm.scrollTo(null, newPos);
|
||||
}
|
||||
} else {
|
||||
var newBottom = newPos + cm.getScrollInfo().clientHeight;
|
||||
if (newBottom < cursorCoords.bottom) {
|
||||
cursor.line -= (cursorCoords.bottom - newBottom) / lineHeight;
|
||||
cursor.line = Math.floor(cursor.line);
|
||||
cm.setCursor(cursor);
|
||||
cursorCoords = cm.charCoords(cursor, 'local');
|
||||
cm.scrollTo(
|
||||
null, cursorCoords.bottom - cm.getScrollInfo().clientHeight);
|
||||
} else {
|
||||
// Cursor stays within bounds. Just reposition the scroll window.
|
||||
cm.scrollTo(null, newPos);
|
||||
}
|
||||
}
|
||||
},
|
||||
scrollToCursor: function(cm, actionArgs) {
|
||||
var lineNum = cm.getCursor().line;
|
||||
var charCoords = cm.charCoords({line: lineNum, ch: 0}, 'local');
|
||||
@@ -1691,6 +1757,7 @@
|
||||
cm.setCursor(motions.moveToFirstNonWhiteSpaceCharacter(cm));
|
||||
}
|
||||
cm.setOption('keyMap', 'vim-insert');
|
||||
cm.setOption('disableInput', false);
|
||||
if (actionArgs && actionArgs.replace) {
|
||||
// Handle Replace-mode as a special case of insert mode.
|
||||
cm.toggleOverwrite(true);
|
||||
@@ -2726,10 +2793,9 @@
|
||||
return regexp;
|
||||
}
|
||||
function showConfirm(cm, text) {
|
||||
if (cm.openConfirm) {
|
||||
cm.openConfirm('<span style="color: red">' + text +
|
||||
'</span> <button type="button">OK</button>', function() {},
|
||||
{bottom: true});
|
||||
if (cm.openNotification) {
|
||||
cm.openNotification('<span style="color: red">' + text + '</span>',
|
||||
{bottom: true, duration: 5000});
|
||||
} else {
|
||||
alert(text);
|
||||
}
|
||||
@@ -2897,14 +2963,16 @@
|
||||
// pair of commands that have a shared prefix, at least one of their
|
||||
// shortNames must not match the prefix of the other command.
|
||||
var defaultExCommandMap = [
|
||||
{ name: 'map', type: 'builtIn' },
|
||||
{ name: 'write', shortName: 'w', type: 'builtIn' },
|
||||
{ name: 'undo', shortName: 'u', type: 'builtIn' },
|
||||
{ name: 'redo', shortName: 'red', type: 'builtIn' },
|
||||
{ name: 'sort', shortName: 'sor', type: 'builtIn'},
|
||||
{ name: 'substitute', shortName: 's', type: 'builtIn'},
|
||||
{ name: 'nohlsearch', shortName: 'noh', type: 'builtIn'},
|
||||
{ name: 'delmarks', shortName: 'delm', type: 'builtin'}
|
||||
{ name: 'map' },
|
||||
{ name: 'nmap', shortName: 'nm' },
|
||||
{ name: 'vmap', shortName: 'vm' },
|
||||
{ name: 'write', shortName: 'w' },
|
||||
{ name: 'undo', shortName: 'u' },
|
||||
{ name: 'redo', shortName: 'red' },
|
||||
{ name: 'sort', shortName: 'sor' },
|
||||
{ name: 'substitute', shortName: 's' },
|
||||
{ name: 'nohlsearch', shortName: 'noh' },
|
||||
{ name: 'delmarks', shortName: 'delm' }
|
||||
];
|
||||
Vim.ExCommandDispatcher = function() {
|
||||
this.buildCommandMap_();
|
||||
@@ -2956,6 +3024,7 @@
|
||||
exCommands[commandName](cm, params);
|
||||
} catch(e) {
|
||||
showConfirm(cm, e);
|
||||
throw e;
|
||||
}
|
||||
},
|
||||
parseInput_: function(cm, inputStream, result) {
|
||||
@@ -3038,8 +3107,9 @@
|
||||
this.commandMap_[key] = command;
|
||||
}
|
||||
},
|
||||
map: function(lhs, rhs) {
|
||||
map: function(lhs, rhs, ctx) {
|
||||
if (lhs != ':' && lhs.charAt(0) == ':') {
|
||||
if (ctx) { throw Error('Mode not supported for ex mappings'); }
|
||||
var commandName = lhs.substring(1);
|
||||
if (rhs != ':' && rhs.charAt(0) == ':') {
|
||||
// Ex to Ex mapping
|
||||
@@ -3059,17 +3129,21 @@
|
||||
} else {
|
||||
if (rhs != ':' && rhs.charAt(0) == ':') {
|
||||
// Key to Ex mapping.
|
||||
defaultKeymap.unshift({
|
||||
var mapping = {
|
||||
keys: parseKeyString(lhs),
|
||||
type: 'keyToEx',
|
||||
exArgs: { input: rhs.substring(1) }});
|
||||
exArgs: { input: rhs.substring(1) }};
|
||||
if (ctx) { mapping.context = ctx; }
|
||||
defaultKeymap.unshift(mapping);
|
||||
} else {
|
||||
// Key to key mapping
|
||||
defaultKeymap.unshift({
|
||||
var mapping = {
|
||||
keys: parseKeyString(lhs),
|
||||
type: 'keyToKey',
|
||||
toKeys: parseKeyString(rhs)
|
||||
});
|
||||
};
|
||||
if (ctx) { mapping.context = ctx; }
|
||||
defaultKeymap.unshift(mapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3091,7 +3165,7 @@
|
||||
}
|
||||
|
||||
var exCommands = {
|
||||
map: function(cm, params) {
|
||||
map: function(cm, params, ctx) {
|
||||
var mapArgs = params.args;
|
||||
if (!mapArgs || mapArgs.length < 2) {
|
||||
if (cm) {
|
||||
@@ -3099,8 +3173,10 @@
|
||||
}
|
||||
return;
|
||||
}
|
||||
exCommandDispatcher.map(mapArgs[0], mapArgs[1], cm);
|
||||
exCommandDispatcher.map(mapArgs[0], mapArgs[1], ctx);
|
||||
},
|
||||
nmap: function(cm, params) { this.map(cm, params, 'normal'); },
|
||||
vmap: function(cm, params) { this.map(cm, params, 'visual'); },
|
||||
move: function(cm, params) {
|
||||
commandDispatcher.processCommand(cm, cm.state.vim, {
|
||||
type: 'motion',
|
||||
@@ -3116,7 +3192,7 @@
|
||||
var args = new CodeMirror.StringStream(params.argString);
|
||||
if (args.eat('!')) { reverse = true; }
|
||||
if (args.eol()) { return; }
|
||||
if (!args.eatSpace()) { throw new Error('invalid arguments ' + args.match(/.*/)[0]); }
|
||||
if (!args.eatSpace()) { return 'Invalid arguments'; }
|
||||
var opts = args.match(/[a-z]+/);
|
||||
if (opts) {
|
||||
opts = opts[0];
|
||||
@@ -3125,13 +3201,17 @@
|
||||
var decimal = opts.indexOf('d') != -1 && 1;
|
||||
var hex = opts.indexOf('x') != -1 && 1;
|
||||
var octal = opts.indexOf('o') != -1 && 1;
|
||||
if (decimal + hex + octal > 1) { throw new Error('invalid arguments'); }
|
||||
if (decimal + hex + octal > 1) { return 'Invalid arguments'; }
|
||||
number = decimal && 'decimal' || hex && 'hex' || octal && 'octal';
|
||||
}
|
||||
if (args.eatSpace() && args.match(/\/.*\//)) { throw new Error('patterns not supported'); }
|
||||
if (args.eatSpace() && args.match(/\/.*\//)) { 'patterns not supported'; }
|
||||
}
|
||||
}
|
||||
parseArgs();
|
||||
var err = parseArgs();
|
||||
if (err) {
|
||||
showConfirm(cm, err + ': ' + params.argString);
|
||||
return;
|
||||
}
|
||||
var lineStart = params.line || cm.firstLine();
|
||||
var lineEnd = params.lineEnd || params.line || cm.lastLine();
|
||||
if (lineStart == lineEnd) { return; }
|
||||
@@ -3252,13 +3332,13 @@
|
||||
clearSearchHighlight(cm);
|
||||
},
|
||||
delmarks: function(cm, params) {
|
||||
if (!params.argString || !params.argString.trim()) {
|
||||
if (!params.argString || !trim(params.argString)) {
|
||||
showConfirm(cm, 'Argument required');
|
||||
return;
|
||||
}
|
||||
|
||||
var state = cm.state.vim;
|
||||
var stream = new CodeMirror.StringStream(params.argString.trim());
|
||||
var stream = new CodeMirror.StringStream(trim(params.argString));
|
||||
while (!stream.eol()) {
|
||||
stream.eatSpace();
|
||||
|
||||
@@ -3395,7 +3475,8 @@
|
||||
// Actually do replace.
|
||||
next();
|
||||
if (done) {
|
||||
throw new Error('No matches for ' + query.source);
|
||||
showConfirm(cm, 'No matches for ' + query.source);
|
||||
return;
|
||||
}
|
||||
if (!confirm) {
|
||||
replaceAll();
|
||||
@@ -3446,7 +3527,6 @@
|
||||
|
||||
var cmToVimKeymap = {
|
||||
'nofallthrough': true,
|
||||
'disableInput': true,
|
||||
'style': 'fat-cursor'
|
||||
};
|
||||
function bindKeys(keys, modifier) {
|
||||
@@ -3493,6 +3573,7 @@
|
||||
cm.setCursor(cm.getCursor().line, cm.getCursor().ch-1, true);
|
||||
vim.insertMode = false;
|
||||
cm.setOption('keyMap', 'vim');
|
||||
cm.setOption('disableInput', true);
|
||||
cm.toggleOverwrite(false); // exit replace mode if we were in it.
|
||||
CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"});
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
650
applications/admin/static/codemirror/mode/css/css.js
vendored
650
applications/admin/static/codemirror/mode/css/css.js
vendored
@@ -3,87 +3,80 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
|
||||
|
||||
if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css");
|
||||
|
||||
var indentUnit = config.indentUnit || config.tabSize || 2,
|
||||
hooks = parserConfig.hooks || {},
|
||||
atMediaTypes = parserConfig.atMediaTypes || {},
|
||||
atMediaFeatures = parserConfig.atMediaFeatures || {},
|
||||
var indentUnit = config.indentUnit,
|
||||
tokenHooks = parserConfig.tokenHooks,
|
||||
mediaTypes = parserConfig.mediaTypes || {},
|
||||
mediaFeatures = parserConfig.mediaFeatures || {},
|
||||
propertyKeywords = parserConfig.propertyKeywords || {},
|
||||
colorKeywords = parserConfig.colorKeywords || {},
|
||||
valueKeywords = parserConfig.valueKeywords || {},
|
||||
allowNested = !!parserConfig.allowNested,
|
||||
type = null;
|
||||
fontProperties = parserConfig.fontProperties || {},
|
||||
allowNested = parserConfig.allowNested;
|
||||
|
||||
var type, override;
|
||||
function ret(style, tp) { type = tp; return style; }
|
||||
|
||||
// Tokenizers
|
||||
|
||||
function tokenBase(stream, state) {
|
||||
var ch = stream.next();
|
||||
if (hooks[ch]) {
|
||||
// result[0] is style and result[1] is type
|
||||
var result = hooks[ch](stream, state);
|
||||
if (tokenHooks[ch]) {
|
||||
var result = tokenHooks[ch](stream, state);
|
||||
if (result !== false) return result;
|
||||
}
|
||||
if (ch == "@") {stream.eatWhile(/[\w\\\-]/); return ret("def", stream.current());}
|
||||
else if (ch == "=") ret(null, "compare");
|
||||
else if ((ch == "~" || ch == "|") && stream.eat("=")) return ret(null, "compare");
|
||||
else if (ch == "\"" || ch == "'") {
|
||||
if (ch == "@") {
|
||||
stream.eatWhile(/[\w\\\-]/);
|
||||
return ret("def", stream.current());
|
||||
} else if (ch == "=" || (ch == "~" || ch == "|") && stream.eat("=")) {
|
||||
return ret(null, "compare");
|
||||
} else if (ch == "\"" || ch == "'") {
|
||||
state.tokenize = tokenString(ch);
|
||||
return state.tokenize(stream, state);
|
||||
}
|
||||
else if (ch == "#") {
|
||||
} else if (ch == "#") {
|
||||
stream.eatWhile(/[\w\\\-]/);
|
||||
return ret("atom", "hash");
|
||||
}
|
||||
else if (ch == "!") {
|
||||
} else if (ch == "!") {
|
||||
stream.match(/^\s*\w*/);
|
||||
return ret("keyword", "important");
|
||||
}
|
||||
else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) {
|
||||
} else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) {
|
||||
stream.eatWhile(/[\w.%]/);
|
||||
return ret("number", "unit");
|
||||
}
|
||||
else if (ch === "-") {
|
||||
if (/\d/.test(stream.peek())) {
|
||||
} else if (ch === "-") {
|
||||
if (/[\d.]/.test(stream.peek())) {
|
||||
stream.eatWhile(/[\w.%]/);
|
||||
return ret("number", "unit");
|
||||
} else if (stream.match(/^[^-]+-/)) {
|
||||
return ret("meta", "meta");
|
||||
}
|
||||
}
|
||||
else if (/[,+>*\/]/.test(ch)) {
|
||||
} else if (/[,+>*\/]/.test(ch)) {
|
||||
return ret(null, "select-op");
|
||||
}
|
||||
else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
|
||||
} else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
|
||||
return ret("qualifier", "qualifier");
|
||||
}
|
||||
else if (ch == ":") {
|
||||
return ret("operator", ch);
|
||||
}
|
||||
else if (/[;{}\[\]\(\)]/.test(ch)) {
|
||||
} else if (/[:;{}\[\]\(\)]/.test(ch)) {
|
||||
return ret(null, ch);
|
||||
}
|
||||
else if (ch == "u" && stream.match("rl(")) {
|
||||
} else if (ch == "u" && stream.match("rl(")) {
|
||||
stream.backUp(1);
|
||||
state.tokenize = tokenParenthesized;
|
||||
return ret("property", "variable");
|
||||
}
|
||||
else {
|
||||
return ret("property", "word");
|
||||
} else if (/[\w\\\-]/.test(ch)) {
|
||||
stream.eatWhile(/[\w\\\-]/);
|
||||
return ret("property", "variable");
|
||||
return ret("property", "word");
|
||||
} else {
|
||||
return ret(null, null);
|
||||
}
|
||||
}
|
||||
|
||||
function tokenString(quote, nonInclusive) {
|
||||
function tokenString(quote) {
|
||||
return function(stream, state) {
|
||||
var escaped = false, ch;
|
||||
while ((ch = stream.next()) != null) {
|
||||
if (ch == quote && !escaped)
|
||||
if (ch == quote && !escaped) {
|
||||
if (quote == ")") stream.backUp(1);
|
||||
break;
|
||||
}
|
||||
escaped = !escaped && ch == "\\";
|
||||
}
|
||||
if (!escaped) {
|
||||
if (nonInclusive) stream.backUp(1);
|
||||
state.tokenize = tokenBase;
|
||||
}
|
||||
if (ch == quote || !escaped && quote != ")") state.tokenize = null;
|
||||
return ret("string", "string");
|
||||
};
|
||||
}
|
||||
@@ -91,218 +84,238 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
|
||||
function tokenParenthesized(stream, state) {
|
||||
stream.next(); // Must be '('
|
||||
if (!stream.match(/\s*[\"\']/, false))
|
||||
state.tokenize = tokenString(")", true);
|
||||
state.tokenize = tokenString(")");
|
||||
else
|
||||
state.tokenize = tokenBase;
|
||||
state.tokenize = null;
|
||||
return ret(null, "(");
|
||||
}
|
||||
|
||||
// Context management
|
||||
|
||||
function Context(type, indent, prev) {
|
||||
this.type = type;
|
||||
this.indent = indent;
|
||||
this.prev = prev;
|
||||
}
|
||||
|
||||
function pushContext(state, stream, type) {
|
||||
state.context = new Context(type, stream.indentation() + indentUnit, state.context);
|
||||
return type;
|
||||
}
|
||||
|
||||
function popContext(state) {
|
||||
state.context = state.context.prev;
|
||||
return state.context.type;
|
||||
}
|
||||
|
||||
function pass(type, stream, state) {
|
||||
return states[state.context.type](type, stream, state);
|
||||
}
|
||||
function popAndPass(type, stream, state, n) {
|
||||
for (var i = n || 1; i > 0; i--)
|
||||
state.context = state.context.prev;
|
||||
return pass(type, stream, state);
|
||||
}
|
||||
|
||||
// Parser
|
||||
|
||||
function wordAsValue(stream) {
|
||||
var word = stream.current().toLowerCase();
|
||||
if (valueKeywords.hasOwnProperty(word))
|
||||
override = "atom";
|
||||
else if (colorKeywords.hasOwnProperty(word))
|
||||
override = "keyword";
|
||||
else
|
||||
override = "variable";
|
||||
}
|
||||
|
||||
var states = {};
|
||||
|
||||
states.top = function(type, stream, state) {
|
||||
if (type == "{") {
|
||||
return pushContext(state, stream, "block");
|
||||
} else if (type == "}" && state.context.prev) {
|
||||
return popContext(state);
|
||||
} else if (type == "@media") {
|
||||
return pushContext(state, stream, "media");
|
||||
} else if (type == "@font-face") {
|
||||
return "font_face_before";
|
||||
} else if (type && type.charAt(0) == "@") {
|
||||
return pushContext(state, stream, "at");
|
||||
} else if (type == "hash") {
|
||||
override = "builtin";
|
||||
} else if (type == "word") {
|
||||
override = "tag";
|
||||
} else if (type == "variable-definition") {
|
||||
return "maybeprop";
|
||||
} else if (type == "interpolation") {
|
||||
return pushContext(state, stream, "interpolation");
|
||||
} else if (type == ":") {
|
||||
return "pseudo";
|
||||
} else if (allowNested && type == "(") {
|
||||
return pushContext(state, stream, "params");
|
||||
}
|
||||
return state.context.type;
|
||||
};
|
||||
|
||||
states.block = function(type, stream, state) {
|
||||
if (type == "word") {
|
||||
if (propertyKeywords.hasOwnProperty(stream.current().toLowerCase())) {
|
||||
override = "property";
|
||||
return "maybeprop";
|
||||
} else if (allowNested) {
|
||||
override = stream.match(/^\s*:/, false) ? "property" : "tag";
|
||||
return "block";
|
||||
} else {
|
||||
override += " error";
|
||||
return "maybeprop";
|
||||
}
|
||||
} else if (type == "meta") {
|
||||
return "block";
|
||||
} else if (!allowNested && (type == "hash" || type == "qualifier")) {
|
||||
override = "error";
|
||||
return "block";
|
||||
} else {
|
||||
return states.top(type, stream, state);
|
||||
}
|
||||
};
|
||||
|
||||
states.maybeprop = function(type, stream, state) {
|
||||
if (type == ":") return pushContext(state, stream, "prop");
|
||||
return pass(type, stream, state);
|
||||
};
|
||||
|
||||
states.prop = function(type, stream, state) {
|
||||
if (type == ";") return popContext(state);
|
||||
if (type == "{" && allowNested) return pushContext(state, stream, "propBlock");
|
||||
if (type == "}" || type == "{") return popAndPass(type, stream, state);
|
||||
if (type == "(") return pushContext(state, stream, "parens");
|
||||
|
||||
if (type == "hash" && !/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(stream.current())) {
|
||||
override += " error";
|
||||
} else if (type == "word") {
|
||||
wordAsValue(stream);
|
||||
} else if (type == "interpolation") {
|
||||
return pushContext(state, stream, "interpolation");
|
||||
}
|
||||
return "prop";
|
||||
};
|
||||
|
||||
states.propBlock = function(type, _stream, state) {
|
||||
if (type == "}") return popContext(state);
|
||||
if (type == "word") { override = "property"; return "maybeprop"; }
|
||||
return state.context.type;
|
||||
};
|
||||
|
||||
states.parens = function(type, stream, state) {
|
||||
if (type == "{" || type == "}") return popAndPass(type, stream, state);
|
||||
if (type == ")") return popContext(state);
|
||||
return "parens";
|
||||
};
|
||||
|
||||
states.pseudo = function(type, stream, state) {
|
||||
if (type == "word") {
|
||||
override = "variable-3";
|
||||
return state.context.type;
|
||||
}
|
||||
return pass(type, stream, state);
|
||||
};
|
||||
|
||||
states.media = function(type, stream, state) {
|
||||
if (type == "(") return pushContext(state, stream, "media_parens");
|
||||
if (type == "}") return popAndPass(type, stream, state);
|
||||
if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top");
|
||||
|
||||
if (type == "word") {
|
||||
var word = stream.current().toLowerCase();
|
||||
if (word == "only" || word == "not" || word == "and")
|
||||
override = "keyword";
|
||||
else if (mediaTypes.hasOwnProperty(word))
|
||||
override = "attribute";
|
||||
else if (mediaFeatures.hasOwnProperty(word))
|
||||
override = "property";
|
||||
else
|
||||
override = "error";
|
||||
}
|
||||
return state.context.type;
|
||||
};
|
||||
|
||||
states.media_parens = function(type, stream, state) {
|
||||
if (type == ")") return popContext(state);
|
||||
if (type == "{" || type == "}") return popAndPass(type, stream, state, 2);
|
||||
return states.media(type, stream, state);
|
||||
};
|
||||
|
||||
states.font_face_before = function(type, stream, state) {
|
||||
if (type == "{")
|
||||
return pushContext(state, stream, "font_face");
|
||||
return pass(type, stream, state);
|
||||
};
|
||||
|
||||
states.font_face = function(type, stream, state) {
|
||||
if (type == "}") return popContext(state);
|
||||
if (type == "word") {
|
||||
if (!fontProperties.hasOwnProperty(stream.current().toLowerCase()))
|
||||
override = "error";
|
||||
else
|
||||
override = "property";
|
||||
return "maybeprop";
|
||||
}
|
||||
return "font_face";
|
||||
};
|
||||
|
||||
states.at = function(type, stream, state) {
|
||||
if (type == ";") return popContext(state);
|
||||
if (type == "{" || type == "}") return popAndPass(type, stream, state);
|
||||
if (type == "word") override = "tag";
|
||||
else if (type == "hash") override = "builtin";
|
||||
return "at";
|
||||
};
|
||||
|
||||
states.interpolation = function(type, stream, state) {
|
||||
if (type == "}") return popContext(state);
|
||||
if (type == "{" || type == ";") return popAndPass(type, stream, state);
|
||||
if (type != "variable") override = "error";
|
||||
return "interpolation";
|
||||
};
|
||||
|
||||
states.params = function(type, stream, state) {
|
||||
if (type == ")") return popContext(state);
|
||||
if (type == "{" || type == "}") return popAndPass(type, stream, state);
|
||||
if (type == "word") wordAsValue(stream);
|
||||
return "params";
|
||||
};
|
||||
|
||||
return {
|
||||
startState: function(base) {
|
||||
return {tokenize: tokenBase,
|
||||
baseIndent: base || 0,
|
||||
stack: [],
|
||||
lastToken: null};
|
||||
return {tokenize: null,
|
||||
state: "top",
|
||||
context: new Context("top", base || 0, null)};
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
|
||||
// Use these terms when applicable (see http://www.xanthir.com/blog/b4E50)
|
||||
//
|
||||
// rule** or **ruleset:
|
||||
// A selector + braces combo, or an at-rule.
|
||||
//
|
||||
// declaration block:
|
||||
// A sequence of declarations.
|
||||
//
|
||||
// declaration:
|
||||
// A property + colon + value combo.
|
||||
//
|
||||
// property value:
|
||||
// The entire value of a property.
|
||||
//
|
||||
// component value:
|
||||
// A single piece of a property value. Like the 5px in
|
||||
// text-shadow: 0 0 5px blue;. Can also refer to things that are
|
||||
// multiple terms, like the 1-4 terms that make up the background-size
|
||||
// portion of the background shorthand.
|
||||
//
|
||||
// term:
|
||||
// The basic unit of author-facing CSS, like a single number (5),
|
||||
// dimension (5px), string ("foo"), or function. Officially defined
|
||||
// by the CSS 2.1 grammar (look for the 'term' production)
|
||||
//
|
||||
//
|
||||
// simple selector:
|
||||
// A single atomic selector, like a type selector, an attr selector, a
|
||||
// class selector, etc.
|
||||
//
|
||||
// compound selector:
|
||||
// One or more simple selectors without a combinator. div.example is
|
||||
// compound, div > .example is not.
|
||||
//
|
||||
// complex selector:
|
||||
// One or more compound selectors chained with combinators.
|
||||
//
|
||||
// combinator:
|
||||
// The parts of selectors that express relationships. There are four
|
||||
// currently - the space (descendant combinator), the greater-than
|
||||
// bracket (child combinator), the plus sign (next sibling combinator),
|
||||
// and the tilda (following sibling combinator).
|
||||
//
|
||||
// sequence of selectors:
|
||||
// One or more of the named type of selector chained with commas.
|
||||
|
||||
state.tokenize = state.tokenize || tokenBase;
|
||||
if (state.tokenize == tokenBase && stream.eatSpace()) return null;
|
||||
var style = state.tokenize(stream, state);
|
||||
if (style && typeof style != "string") style = ret(style[0], style[1]);
|
||||
|
||||
// Changing style returned based on context
|
||||
var context = state.stack[state.stack.length-1];
|
||||
if (style == "variable") {
|
||||
if (type == "variable-definition") state.stack.push("propertyValue");
|
||||
return state.lastToken = "variable-2";
|
||||
} else if (style == "property") {
|
||||
var word = stream.current().toLowerCase();
|
||||
if (context == "propertyValue") {
|
||||
if (valueKeywords.hasOwnProperty(word)) {
|
||||
style = "string-2";
|
||||
} else if (colorKeywords.hasOwnProperty(word)) {
|
||||
style = "keyword";
|
||||
} else {
|
||||
style = "variable-2";
|
||||
}
|
||||
} else if (context == "rule") {
|
||||
if (!propertyKeywords.hasOwnProperty(word)) {
|
||||
style += " error";
|
||||
}
|
||||
} else if (context == "block") {
|
||||
// if a value is present in both property, value, or color, the order
|
||||
// of preference is property -> color -> value
|
||||
if (propertyKeywords.hasOwnProperty(word)) {
|
||||
style = "property";
|
||||
} else if (colorKeywords.hasOwnProperty(word)) {
|
||||
style = "keyword";
|
||||
} else if (valueKeywords.hasOwnProperty(word)) {
|
||||
style = "string-2";
|
||||
} else {
|
||||
style = "tag";
|
||||
}
|
||||
} else if (!context || context == "@media{") {
|
||||
style = "tag";
|
||||
} else if (context == "@media") {
|
||||
if (atMediaTypes[stream.current()]) {
|
||||
style = "attribute"; // Known attribute
|
||||
} else if (/^(only|not)$/.test(word)) {
|
||||
style = "keyword";
|
||||
} else if (word == "and") {
|
||||
style = "error"; // "and" is only allowed in @mediaType
|
||||
} else if (atMediaFeatures.hasOwnProperty(word)) {
|
||||
style = "error"; // Known property, should be in @mediaType(
|
||||
} else {
|
||||
// Unknown, expecting keyword or attribute, assuming attribute
|
||||
style = "attribute error";
|
||||
}
|
||||
} else if (context == "@mediaType") {
|
||||
if (atMediaTypes.hasOwnProperty(word)) {
|
||||
style = "attribute";
|
||||
} else if (word == "and") {
|
||||
style = "operator";
|
||||
} else if (/^(only|not)$/.test(word)) {
|
||||
style = "error"; // Only allowed in @media
|
||||
} else {
|
||||
// Unknown attribute or property, but expecting property (preceded
|
||||
// by "and"). Should be in parentheses
|
||||
style = "error";
|
||||
}
|
||||
} else if (context == "@mediaType(") {
|
||||
if (propertyKeywords.hasOwnProperty(word)) {
|
||||
// do nothing, remains "property"
|
||||
} else if (atMediaTypes.hasOwnProperty(word)) {
|
||||
style = "error"; // Known property, should be in parentheses
|
||||
} else if (word == "and") {
|
||||
style = "operator";
|
||||
} else if (/^(only|not)$/.test(word)) {
|
||||
style = "error"; // Only allowed in @media
|
||||
} else {
|
||||
style += " error";
|
||||
}
|
||||
} else if (context == "@import") {
|
||||
style = "tag";
|
||||
} else {
|
||||
style = "error";
|
||||
}
|
||||
} else if (style == "atom") {
|
||||
if(!context || context == "@media{" || context == "block") {
|
||||
style = "builtin";
|
||||
} else if (context == "propertyValue") {
|
||||
if (!/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(stream.current())) {
|
||||
style += " error";
|
||||
}
|
||||
} else {
|
||||
style = "error";
|
||||
}
|
||||
} else if (context == "@media" && type == "{") {
|
||||
style = "error";
|
||||
if (!state.tokenize && stream.eatSpace()) return null;
|
||||
var style = (state.tokenize || tokenBase)(stream, state);
|
||||
if (style && typeof style == "object") {
|
||||
type = style[1];
|
||||
style = style[0];
|
||||
}
|
||||
|
||||
// Push/pop context stack
|
||||
if (type == "{") {
|
||||
if (context == "@media" || context == "@mediaType") {
|
||||
state.stack[state.stack.length-1] = "@media{";
|
||||
}
|
||||
else {
|
||||
var newContext = allowNested ? "block" : "rule";
|
||||
state.stack.push(newContext);
|
||||
}
|
||||
}
|
||||
else if (type == "}") {
|
||||
if (context == "interpolation") style = "operator";
|
||||
// Pop off end of array until { is reached
|
||||
while(state.stack.length){
|
||||
var removed = state.stack.pop();
|
||||
if(removed.indexOf("{") > -1){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type == "interpolation") state.stack.push("interpolation");
|
||||
else if (type == "@media") state.stack.push("@media");
|
||||
else if (type == "@import") state.stack.push("@import");
|
||||
else if (context == "@media" && /\b(keyword|attribute)\b/.test(style))
|
||||
state.stack[state.stack.length-1] = "@mediaType";
|
||||
else if (context == "@mediaType" && stream.current() == ",")
|
||||
state.stack[state.stack.length-1] = "@media";
|
||||
else if (type == "(") {
|
||||
if (context == "@media" || context == "@mediaType") {
|
||||
// Make sure @mediaType is used to avoid error on {
|
||||
state.stack[state.stack.length-1] = "@mediaType";
|
||||
state.stack.push("@mediaType(");
|
||||
}
|
||||
else state.stack.push("(");
|
||||
}
|
||||
else if (type == ")") {
|
||||
// Pop off end of array until ( is reached
|
||||
while(state.stack.length){
|
||||
var removed = state.stack.pop();
|
||||
if(removed.indexOf("(") > -1){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type == ":" && state.lastToken == "property") state.stack.push("propertyValue");
|
||||
else if (context == "propertyValue" && type == ";") state.stack.pop();
|
||||
else if (context == "@import" && type == ";") state.stack.pop();
|
||||
|
||||
return state.lastToken = style;
|
||||
override = style;
|
||||
state.state = states[state.state](type, stream, state);
|
||||
return override;
|
||||
},
|
||||
|
||||
indent: function(state, textAfter) {
|
||||
var n = state.stack.length;
|
||||
if (/^\}/.test(textAfter))
|
||||
n -= state.stack[n-1] == "propertyValue" ? 2 : 1;
|
||||
return state.baseIndent + n * indentUnit;
|
||||
var cx = state.context, ch = textAfter && textAfter.charAt(0);
|
||||
var indent = cx.indent;
|
||||
if (cx.prev &&
|
||||
(ch == "}" && (cx.type == "block" || cx.type == "top" || cx.type == "interpolation" || cx.type == "font_face") ||
|
||||
ch == ")" && (cx.type == "parens" || cx.type == "params" || cx.type == "media_parens") ||
|
||||
ch == "{" && (cx.type == "at" || cx.type == "media"))) {
|
||||
indent = cx.indent - indentUnit;
|
||||
cx = cx.prev;
|
||||
}
|
||||
return indent;
|
||||
},
|
||||
|
||||
electricChars: "}",
|
||||
@@ -321,12 +334,12 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
|
||||
return keys;
|
||||
}
|
||||
|
||||
var atMediaTypes = keySet([
|
||||
var mediaTypes_ = [
|
||||
"all", "aural", "braille", "handheld", "print", "projection", "screen",
|
||||
"tty", "tv", "embossed"
|
||||
]);
|
||||
], mediaTypes = keySet(mediaTypes_);
|
||||
|
||||
var atMediaFeatures = keySet([
|
||||
var mediaFeatures_ = [
|
||||
"width", "min-width", "max-width", "height", "min-height", "max-height",
|
||||
"device-width", "min-device-width", "max-device-width", "device-height",
|
||||
"min-device-height", "max-device-height", "aspect-ratio",
|
||||
@@ -335,9 +348,9 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
|
||||
"max-color", "color-index", "min-color-index", "max-color-index",
|
||||
"monochrome", "min-monochrome", "max-monochrome", "resolution",
|
||||
"min-resolution", "max-resolution", "scan", "grid"
|
||||
]);
|
||||
], mediaFeatures = keySet(mediaFeatures_);
|
||||
|
||||
var propertyKeywords = keySet([
|
||||
var propertyKeywords_ = [
|
||||
"align-content", "align-items", "align-self", "alignment-adjust",
|
||||
"alignment-baseline", "anchor-point", "animation", "animation-delay",
|
||||
"animation-direction", "animation-duration", "animation-iteration-count",
|
||||
@@ -425,9 +438,9 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
|
||||
"stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering",
|
||||
"baseline-shift", "dominant-baseline", "glyph-orientation-horizontal",
|
||||
"glyph-orientation-vertical", "kerning", "text-anchor", "writing-mode"
|
||||
]);
|
||||
], propertyKeywords = keySet(propertyKeywords_);
|
||||
|
||||
var colorKeywords = keySet([
|
||||
var colorKeywords_ = [
|
||||
"aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige",
|
||||
"bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown",
|
||||
"burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue",
|
||||
@@ -454,9 +467,9 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
|
||||
"slateblue", "slategray", "snow", "springgreen", "steelblue", "tan",
|
||||
"teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white",
|
||||
"whitesmoke", "yellow", "yellowgreen"
|
||||
]);
|
||||
], colorKeywords = keySet(colorKeywords_);
|
||||
|
||||
var valueKeywords = keySet([
|
||||
var valueKeywords_ = [
|
||||
"above", "absolute", "activeborder", "activecaption", "afar",
|
||||
"after-white-space", "ahead", "alias", "all", "all-scroll", "alternate",
|
||||
"always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
|
||||
@@ -539,7 +552,15 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
|
||||
"visibleStroke", "visual", "w-resize", "wait", "wave", "wider",
|
||||
"window", "windowframe", "windowtext", "x-large", "x-small", "xor",
|
||||
"xx-large", "xx-small"
|
||||
]);
|
||||
], valueKeywords = keySet(valueKeywords_);
|
||||
|
||||
var fontProperties_ = [
|
||||
"font-family", "src", "unicode-range", "font-variant", "font-feature-settings",
|
||||
"font-stretch", "font-weight", "font-style"
|
||||
], fontProperties = keySet(fontProperties_);
|
||||
|
||||
var allWords = mediaTypes_.concat(mediaFeatures_).concat(propertyKeywords_).concat(colorKeywords_).concat(valueKeywords_);
|
||||
CodeMirror.registerHelper("hintWords", "css", allWords);
|
||||
|
||||
function tokenCComment(stream, state) {
|
||||
var maybeEnd = false, ch;
|
||||
@@ -553,67 +574,47 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
|
||||
return ["comment", "comment"];
|
||||
}
|
||||
|
||||
function tokenSGMLComment(stream, state) {
|
||||
if (stream.skipTo("-->")) {
|
||||
stream.match("-->");
|
||||
state.tokenize = null;
|
||||
} else {
|
||||
stream.skipToEnd();
|
||||
}
|
||||
return ["comment", "comment"];
|
||||
}
|
||||
|
||||
CodeMirror.defineMIME("text/css", {
|
||||
atMediaTypes: atMediaTypes,
|
||||
atMediaFeatures: atMediaFeatures,
|
||||
mediaTypes: mediaTypes,
|
||||
mediaFeatures: mediaFeatures,
|
||||
propertyKeywords: propertyKeywords,
|
||||
colorKeywords: colorKeywords,
|
||||
valueKeywords: valueKeywords,
|
||||
hooks: {
|
||||
fontProperties: fontProperties,
|
||||
tokenHooks: {
|
||||
"<": function(stream, state) {
|
||||
function tokenSGMLComment(stream, state) {
|
||||
var dashes = 0, ch;
|
||||
while ((ch = stream.next()) != null) {
|
||||
if (dashes >= 2 && ch == ">") {
|
||||
state.tokenize = null;
|
||||
break;
|
||||
}
|
||||
dashes = (ch == "-") ? dashes + 1 : 0;
|
||||
}
|
||||
return ["comment", "comment"];
|
||||
}
|
||||
if (stream.eat("!")) {
|
||||
state.tokenize = tokenSGMLComment;
|
||||
return tokenSGMLComment(stream, state);
|
||||
}
|
||||
if (!stream.match("!--")) return false;
|
||||
state.tokenize = tokenSGMLComment;
|
||||
return tokenSGMLComment(stream, state);
|
||||
},
|
||||
"/": function(stream, state) {
|
||||
if (stream.eat("*")) {
|
||||
state.tokenize = tokenCComment;
|
||||
return tokenCComment(stream, state);
|
||||
}
|
||||
return false;
|
||||
if (!stream.eat("*")) return false;
|
||||
state.tokenize = tokenCComment;
|
||||
return tokenCComment(stream, state);
|
||||
}
|
||||
},
|
||||
name: "css"
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/x-scss", {
|
||||
atMediaTypes: atMediaTypes,
|
||||
atMediaFeatures: atMediaFeatures,
|
||||
mediaTypes: mediaTypes,
|
||||
mediaFeatures: mediaFeatures,
|
||||
propertyKeywords: propertyKeywords,
|
||||
colorKeywords: colorKeywords,
|
||||
valueKeywords: valueKeywords,
|
||||
fontProperties: fontProperties,
|
||||
allowNested: true,
|
||||
hooks: {
|
||||
":": function(stream) {
|
||||
if (stream.match(/\s*{/)) {
|
||||
return [null, "{"];
|
||||
}
|
||||
return false;
|
||||
},
|
||||
"$": function(stream) {
|
||||
stream.match(/^[\w-]+/);
|
||||
if (stream.peek() == ":") {
|
||||
return ["variable", "variable-definition"];
|
||||
}
|
||||
return ["variable", "variable"];
|
||||
},
|
||||
",": function(_stream, state) {
|
||||
if (state.stack[state.stack.length - 1] == "propertyValue") {
|
||||
return ["operator", ";"];
|
||||
}
|
||||
},
|
||||
tokenHooks: {
|
||||
"/": function(stream, state) {
|
||||
if (stream.eat("/")) {
|
||||
stream.skipToEnd();
|
||||
@@ -625,15 +626,58 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
|
||||
return ["operator", "operator"];
|
||||
}
|
||||
},
|
||||
":": function(stream) {
|
||||
if (stream.match(/\s*{/))
|
||||
return [null, "{"];
|
||||
return false;
|
||||
},
|
||||
"$": function(stream) {
|
||||
stream.match(/^[\w-]+/);
|
||||
if (stream.match(/^\s*:/, false))
|
||||
return ["variable-2", "variable-definition"];
|
||||
return ["variable-2", "variable"];
|
||||
},
|
||||
"#": function(stream) {
|
||||
if (stream.eat("{")) {
|
||||
return ["operator", "interpolation"];
|
||||
} else {
|
||||
stream.eatWhile(/[\w\\\-]/);
|
||||
return ["atom", "hash"];
|
||||
}
|
||||
if (!stream.eat("{")) return false;
|
||||
return [null, "interpolation"];
|
||||
}
|
||||
},
|
||||
name: "css"
|
||||
name: "css",
|
||||
helperType: "scss"
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/x-less", {
|
||||
mediaTypes: mediaTypes,
|
||||
mediaFeatures: mediaFeatures,
|
||||
propertyKeywords: propertyKeywords,
|
||||
colorKeywords: colorKeywords,
|
||||
valueKeywords: valueKeywords,
|
||||
fontProperties: fontProperties,
|
||||
allowNested: true,
|
||||
tokenHooks: {
|
||||
"/": function(stream, state) {
|
||||
if (stream.eat("/")) {
|
||||
stream.skipToEnd();
|
||||
return ["comment", "comment"];
|
||||
} else if (stream.eat("*")) {
|
||||
state.tokenize = tokenCComment;
|
||||
return tokenCComment(stream, state);
|
||||
} else {
|
||||
return ["operator", "operator"];
|
||||
}
|
||||
},
|
||||
"@": function(stream) {
|
||||
if (stream.match(/^(charset|document|font-face|import|keyframes|media|namespace|page|supports)\b/, false)) return false;
|
||||
stream.eatWhile(/[\w\\\-]/);
|
||||
if (stream.match(/^\s*:/, false))
|
||||
return ["variable-2", "variable-definition"];
|
||||
return ["variable-2", "variable"];
|
||||
},
|
||||
"&": function() {
|
||||
return ["atom", "atom"];
|
||||
}
|
||||
},
|
||||
name: "css",
|
||||
helperType: "less"
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -150,7 +150,7 @@ code {
|
||||
});
|
||||
</script>
|
||||
|
||||
<p><strong>MIME types defined:</strong> <code>text/scss</code>.</p>
|
||||
<p>The SCSS mode is a sub-mode of the <a href="index.html">CSS mode</a> (defined in <code>css.js</code>.</p>
|
||||
|
||||
<p><strong>Parsing/Highlighting Tests:</strong> <a href="../../test/index.html#scss_*">normal</a>, <a href="../../test/index.html#verbose,scss_*">verbose</a>.</p>
|
||||
|
||||
|
||||
@@ -1,34 +1,33 @@
|
||||
(function() {
|
||||
var mode = CodeMirror.getMode({tabSize: 1}, "text/x-scss");
|
||||
var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-scss");
|
||||
function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "scss"); }
|
||||
function IT(name) { test.indentation(name, mode, Array.prototype.slice.call(arguments, 1), "scss"); }
|
||||
|
||||
MT('url_with_quotation',
|
||||
"[tag foo] { [property background][operator :][string-2 url]([string test.jpg]) }");
|
||||
"[tag foo] { [property background]:[atom url]([string test.jpg]) }");
|
||||
|
||||
MT('url_with_double_quotes',
|
||||
"[tag foo] { [property background][operator :][string-2 url]([string \"test.jpg\"]) }");
|
||||
"[tag foo] { [property background]:[atom url]([string \"test.jpg\"]) }");
|
||||
|
||||
MT('url_with_single_quotes',
|
||||
"[tag foo] { [property background][operator :][string-2 url]([string \'test.jpg\']) }");
|
||||
"[tag foo] { [property background]:[atom url]([string \'test.jpg\']) }");
|
||||
|
||||
MT('string',
|
||||
"[def @import] [string \"compass/css3\"]");
|
||||
|
||||
MT('important_keyword',
|
||||
"[tag foo] { [property background][operator :][string-2 url]([string \'test.jpg\']) [keyword !important] }");
|
||||
"[tag foo] { [property background]:[atom url]([string \'test.jpg\']) [keyword !important] }");
|
||||
|
||||
MT('variable',
|
||||
"[variable-2 $blue][operator :][atom #333]");
|
||||
"[variable-2 $blue]:[atom #333]");
|
||||
|
||||
MT('variable_as_attribute',
|
||||
"[tag foo] { [property color][operator :][variable-2 $blue] }");
|
||||
"[tag foo] { [property color]:[variable-2 $blue] }");
|
||||
|
||||
MT('numbers',
|
||||
"[tag foo] { [property padding][operator :][number 10px] [number 10] [number 10em] [number 8in] }");
|
||||
"[tag foo] { [property padding]:[number 10px] [number 10] [number 10em] [number 8in] }");
|
||||
|
||||
MT('number_percentage',
|
||||
"[tag foo] { [property width][operator :][number 80%] }");
|
||||
"[tag foo] { [property width]:[number 80%] }");
|
||||
|
||||
MT('selector',
|
||||
"[builtin #hello][qualifier .world]{}");
|
||||
@@ -40,45 +39,69 @@
|
||||
"[comment /*foobar*/]");
|
||||
|
||||
MT('attribute_with_hyphen',
|
||||
"[tag foo] { [property font-size][operator :][number 10px] }");
|
||||
"[tag foo] { [property font-size]:[number 10px] }");
|
||||
|
||||
MT('string_after_attribute',
|
||||
"[tag foo] { [property content][operator :][string \"::\"] }");
|
||||
"[tag foo] { [property content]:[string \"::\"] }");
|
||||
|
||||
MT('directives',
|
||||
"[def @include] [qualifier .mixin]");
|
||||
|
||||
MT('basic_structure',
|
||||
"[tag p] { [property background][operator :][keyword red]; }");
|
||||
"[tag p] { [property background]:[keyword red]; }");
|
||||
|
||||
MT('nested_structure',
|
||||
"[tag p] { [tag a] { [property color][operator :][keyword red]; } }");
|
||||
"[tag p] { [tag a] { [property color]:[keyword red]; } }");
|
||||
|
||||
MT('mixin',
|
||||
"[def @mixin] [tag table-base] {}");
|
||||
|
||||
MT('number_without_semicolon',
|
||||
"[tag p] {[property width][operator :][number 12]}",
|
||||
"[tag a] {[property color][operator :][keyword red];}");
|
||||
"[tag p] {[property width]:[number 12]}",
|
||||
"[tag a] {[property color]:[keyword red];}");
|
||||
|
||||
MT('atom_in_nested_block',
|
||||
"[tag p] { [tag a] { [property color][operator :][atom #000]; } }");
|
||||
"[tag p] { [tag a] { [property color]:[atom #000]; } }");
|
||||
|
||||
MT('interpolation_in_property',
|
||||
"[tag foo] { [operator #{][variable-2 $hello][operator }:][number 2]; }");
|
||||
"[tag foo] { #{[variable-2 $hello]}:[number 2]; }");
|
||||
|
||||
MT('interpolation_in_selector',
|
||||
"[tag foo][operator #{][variable-2 $hello][operator }] { [property color][operator :][atom #000]; }");
|
||||
"[tag foo]#{[variable-2 $hello]} { [property color]:[atom #000]; }");
|
||||
|
||||
MT('interpolation_error',
|
||||
"[tag foo][operator #{][error foo][operator }] { [property color][operator :][atom #000]; }");
|
||||
"[tag foo]#{[error foo]} { [property color]:[atom #000]; }");
|
||||
|
||||
MT("divide_operator",
|
||||
"[tag foo] { [property width][operator :][number 4] [operator /] [number 2] }");
|
||||
"[tag foo] { [property width]:[number 4] [operator /] [number 2] }");
|
||||
|
||||
MT('nested_structure_with_id_selector',
|
||||
"[tag p] { [builtin #hello] { [property color][operator :][keyword red]; } }");
|
||||
"[tag p] { [builtin #hello] { [property color]:[keyword red]; } }");
|
||||
|
||||
IT('mixin',
|
||||
"@mixin container[1 (][2 $a: 10][1 , ][2 $b: 10][1 , ][2 $c: 10]) [1 {]}");
|
||||
MT('indent_mixin',
|
||||
"[def @mixin] [tag container] (",
|
||||
" [variable-2 $a]: [number 10],",
|
||||
" [variable-2 $b]: [number 10])",
|
||||
"{}");
|
||||
|
||||
MT('indent_nested',
|
||||
"[tag foo] {",
|
||||
" [tag bar] {",
|
||||
" }",
|
||||
"}");
|
||||
|
||||
MT('indent_parentheses',
|
||||
"[tag foo] {",
|
||||
" [property color]: [variable darken]([variable-2 $blue],",
|
||||
" [number 9%]);",
|
||||
"}");
|
||||
|
||||
MT('indent_vardef',
|
||||
"[variable-2 $name]:",
|
||||
" [string 'val'];",
|
||||
"[tag tag] {",
|
||||
" [tag inner] {",
|
||||
" [property margin]: [number 3px];",
|
||||
" }",
|
||||
"}");
|
||||
})();
|
||||
|
||||
@@ -1,68 +1,19 @@
|
||||
(function() {
|
||||
var mode = CodeMirror.getMode({tabSize: 1}, "css");
|
||||
var mode = CodeMirror.getMode({indentUnit: 2}, "css");
|
||||
function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
|
||||
function IT(name) { test.indentation(name, mode, Array.prototype.slice.call(arguments, 1)); }
|
||||
|
||||
// Requires at least one media query
|
||||
MT("atMediaEmpty",
|
||||
"[def @media] [error {] }");
|
||||
|
||||
MT("atMediaMultiple",
|
||||
"[def @media] [keyword not] [attribute screen] [operator and] ([property color]), [keyword not] [attribute print] [operator and] ([property color]) { }");
|
||||
|
||||
MT("atMediaCheckStack",
|
||||
"[def @media] [attribute screen] { } [tag foo] { }");
|
||||
|
||||
MT("atMediaCheckStack",
|
||||
"[def @media] [attribute screen] ([property color]) { } [tag foo] { }");
|
||||
|
||||
MT("atMediaPropertyOnly",
|
||||
"[def @media] ([property color]) { } [tag foo] { }");
|
||||
|
||||
MT("atMediaCheckStackInvalidAttribute",
|
||||
"[def @media] [attribute&error foobarhello] { [tag foo] { } }");
|
||||
|
||||
MT("atMediaCheckStackInvalidAttribute",
|
||||
"[def @media] [attribute&error foobarhello] { } [tag foo] { }");
|
||||
|
||||
// Error, because "and" is only allowed immediately preceding a media expression
|
||||
MT("atMediaInvalidAttribute",
|
||||
"[def @media] [attribute&error foobarhello] { }");
|
||||
|
||||
// Error, because "and" is only allowed immediately preceding a media expression
|
||||
MT("atMediaInvalidAnd",
|
||||
"[def @media] [error and] [attribute screen] { }");
|
||||
|
||||
// Error, because "not" is only allowed as the first item in each media query
|
||||
MT("atMediaInvalidNot",
|
||||
"[def @media] [attribute screen] [error not] ([error not]) { }");
|
||||
|
||||
// Error, because "only" is only allowed as the first item in each media query
|
||||
MT("atMediaInvalidOnly",
|
||||
"[def @media] [attribute screen] [error only] ([error only]) { }");
|
||||
|
||||
// Error, because "foobarhello" is neither a known type or property, but
|
||||
// property was expected (after "and"), and it should be in parenthese.
|
||||
MT("atMediaUnknownType",
|
||||
"[def @media] [attribute screen] [operator and] [error foobarhello] { }");
|
||||
|
||||
// Error, because "color" is not a known type, but is a known property, and
|
||||
// should be in parentheses.
|
||||
MT("atMediaInvalidType",
|
||||
"[def @media] [attribute screen] [operator and] [error color] { }");
|
||||
|
||||
// Error, because "print" is not a known property, but is a known type,
|
||||
// and should not be in parenthese.
|
||||
MT("atMediaInvalidProperty",
|
||||
"[def @media] [attribute screen] [operator and] ([error print]) { }");
|
||||
"[def @media] [attribute screen] [keyword and] [error foobarhello] { }");
|
||||
|
||||
// Soft error, because "foobarhello" is not a known property or type.
|
||||
MT("atMediaUnknownProperty",
|
||||
"[def @media] [attribute screen] [operator and] ([property&error foobarhello]) { }");
|
||||
"[def @media] [attribute screen] [keyword and] ([error foobarhello]) { }");
|
||||
|
||||
// Make sure nesting works with media queries
|
||||
MT("atMediaMaxWidthNested",
|
||||
"[def @media] [attribute screen] [operator and] ([property max-width][operator :] [number 25px]) { [tag foo] { } }");
|
||||
"[def @media] [attribute screen] [keyword and] ([property max-width]: [number 25px]) { [tag foo] { } }");
|
||||
|
||||
MT("tagSelector",
|
||||
"[tag foo] { }");
|
||||
@@ -74,57 +25,95 @@
|
||||
"[builtin #foo] { [error #foo] }");
|
||||
|
||||
MT("tagSelectorUnclosed",
|
||||
"[tag foo] { [property margin][operator :] [number 0] } [tag bar] { }");
|
||||
"[tag foo] { [property margin]: [number 0] } [tag bar] { }");
|
||||
|
||||
MT("tagStringNoQuotes",
|
||||
"[tag foo] { [property font-family][operator :] [variable-2 hello] [variable-2 world]; }");
|
||||
"[tag foo] { [property font-family]: [variable hello] [variable world]; }");
|
||||
|
||||
MT("tagStringDouble",
|
||||
"[tag foo] { [property font-family][operator :] [string \"hello world\"]; }");
|
||||
"[tag foo] { [property font-family]: [string \"hello world\"]; }");
|
||||
|
||||
MT("tagStringSingle",
|
||||
"[tag foo] { [property font-family][operator :] [string 'hello world']; }");
|
||||
"[tag foo] { [property font-family]: [string 'hello world']; }");
|
||||
|
||||
MT("tagColorKeyword",
|
||||
"[tag foo] {" +
|
||||
"[property color][operator :] [keyword black];" +
|
||||
"[property color][operator :] [keyword navy];" +
|
||||
"[property color][operator :] [keyword yellow];" +
|
||||
"}");
|
||||
"[tag foo] {",
|
||||
" [property color]: [keyword black];",
|
||||
" [property color]: [keyword navy];",
|
||||
" [property color]: [keyword yellow];",
|
||||
"}");
|
||||
|
||||
MT("tagColorHex3",
|
||||
"[tag foo] { [property background][operator :] [atom #fff]; }");
|
||||
"[tag foo] { [property background]: [atom #fff]; }");
|
||||
|
||||
MT("tagColorHex6",
|
||||
"[tag foo] { [property background][operator :] [atom #ffffff]; }");
|
||||
"[tag foo] { [property background]: [atom #ffffff]; }");
|
||||
|
||||
MT("tagColorHex4",
|
||||
"[tag foo] { [property background][operator :] [atom&error #ffff]; }");
|
||||
"[tag foo] { [property background]: [atom&error #ffff]; }");
|
||||
|
||||
MT("tagColorHexInvalid",
|
||||
"[tag foo] { [property background][operator :] [atom&error #ffg]; }");
|
||||
"[tag foo] { [property background]: [atom&error #ffg]; }");
|
||||
|
||||
MT("tagNegativeNumber",
|
||||
"[tag foo] { [property margin][operator :] [number -5px]; }");
|
||||
"[tag foo] { [property margin]: [number -5px]; }");
|
||||
|
||||
MT("tagPositiveNumber",
|
||||
"[tag foo] { [property padding][operator :] [number 5px]; }");
|
||||
"[tag foo] { [property padding]: [number 5px]; }");
|
||||
|
||||
MT("tagVendor",
|
||||
"[tag foo] { [meta -foo-][property box-sizing][operator :] [meta -foo-][string-2 border-box]; }");
|
||||
"[tag foo] { [meta -foo-][property box-sizing]: [meta -foo-][atom border-box]; }");
|
||||
|
||||
MT("tagBogusProperty",
|
||||
"[tag foo] { [property&error barhelloworld][operator :] [number 0]; }");
|
||||
"[tag foo] { [property&error barhelloworld]: [number 0]; }");
|
||||
|
||||
MT("tagTwoProperties",
|
||||
"[tag foo] { [property margin][operator :] [number 0]; [property padding][operator :] [number 0]; }");
|
||||
"[tag foo] { [property margin]: [number 0]; [property padding]: [number 0]; }");
|
||||
|
||||
MT("tagTwoPropertiesURL",
|
||||
"[tag foo] { [property background][operator :] [string-2 url]([string //example.com/foo.png]); [property padding][operator :] [number 0]; }");
|
||||
"[tag foo] { [property background]: [atom url]([string //example.com/foo.png]); [property padding]: [number 0]; }");
|
||||
|
||||
MT("commentSGML",
|
||||
"[comment <!--comment-->]");
|
||||
|
||||
IT("tagSelector",
|
||||
"strong, em [1 { background][2 : rgba][3 (255, 255, 0, .2][2 )][1 ;]}");
|
||||
MT("commentSGML2",
|
||||
"[comment <!--comment]",
|
||||
"[comment -->] [tag div] {}");
|
||||
|
||||
MT("indent_tagSelector",
|
||||
"[tag strong], [tag em] {",
|
||||
" [property background]: [atom rgba](",
|
||||
" [number 255], [number 255], [number 0], [number .2]",
|
||||
" );",
|
||||
"}");
|
||||
|
||||
MT("indent_atMedia",
|
||||
"[def @media] {",
|
||||
" [tag foo] {",
|
||||
" [property color]:",
|
||||
" [keyword yellow];",
|
||||
" }",
|
||||
"}");
|
||||
|
||||
MT("indent_comma",
|
||||
"[tag foo] {",
|
||||
" [property font-family]: [variable verdana],",
|
||||
" [atom sans-serif];",
|
||||
"}");
|
||||
|
||||
MT("indent_parentheses",
|
||||
"[tag foo]:[variable-3 before] {",
|
||||
" [property background]: [atom url](",
|
||||
"[string blahblah]",
|
||||
"[string etc]",
|
||||
"[string ]) [keyword !important];",
|
||||
"}");
|
||||
|
||||
MT("font_face",
|
||||
"[def @font-face] {",
|
||||
" [property font-family]: [string 'myfont'];",
|
||||
" [error nonsense]: [string 'abc'];",
|
||||
" [property src]: [atom url]([string http://blah]),",
|
||||
" [atom url]([string http://foo]);",
|
||||
"}");
|
||||
})();
|
||||
|
||||
@@ -58,8 +58,6 @@ CodeMirror.defineMode("htmlembedded", function(config, parserConfig) {
|
||||
};
|
||||
},
|
||||
|
||||
electricChars: "/{}:",
|
||||
|
||||
innerMode: function(state) {
|
||||
if (state.token == scriptingDispatch) return {state: state.scriptState, mode: scriptingMode};
|
||||
else return {state: state.htmlState, mode: htmlMixedMode};
|
||||
|
||||
@@ -44,7 +44,7 @@ CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
|
||||
if (close > -1) stream.backUp(cur.length - close);
|
||||
else if (m = cur.match(/<\/?$/)) {
|
||||
stream.backUp(cur.length);
|
||||
if (!stream.match(pat, false)) stream.match(cur[0]);
|
||||
if (!stream.match(pat, false)) stream.match(cur);
|
||||
}
|
||||
return style;
|
||||
}
|
||||
@@ -93,8 +93,6 @@ CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
|
||||
return CodeMirror.Pass;
|
||||
},
|
||||
|
||||
electricChars: "/{}:",
|
||||
|
||||
innerMode: function(state) {
|
||||
return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode};
|
||||
}
|
||||
|
||||
@@ -15,13 +15,14 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
||||
|
||||
var jsKeywords = {
|
||||
"if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
|
||||
"return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C,
|
||||
"return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C, "debugger": C,
|
||||
"var": kw("var"), "const": kw("var"), "let": kw("var"),
|
||||
"function": kw("function"), "catch": kw("catch"),
|
||||
"for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
|
||||
"in": operator, "typeof": operator, "instanceof": operator,
|
||||
"true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
|
||||
"this": kw("this")
|
||||
"this": kw("this"), "module": kw("module"), "class": kw("class"), "super": kw("atom"),
|
||||
"yield": C, "export": kw("export"), "import": kw("import"), "extends": C
|
||||
};
|
||||
|
||||
// Extend the 'normal' keywords with the TypeScript language extensions
|
||||
@@ -30,7 +31,6 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
||||
var tsKeywords = {
|
||||
// object-like things
|
||||
"interface": kw("interface"),
|
||||
"class": kw("class"),
|
||||
"extends": kw("extends"),
|
||||
"constructor": kw("constructor"),
|
||||
|
||||
@@ -40,8 +40,6 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
||||
"protected": kw("protected"),
|
||||
"static": kw("static"),
|
||||
|
||||
"super": kw("super"),
|
||||
|
||||
// types
|
||||
"string": type, "number": type, "bool": type, "any": type
|
||||
};
|
||||
@@ -56,19 +54,16 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
||||
|
||||
var isOperatorChar = /[+\-*&%=<>!?|~^]/;
|
||||
|
||||
function chain(stream, state, f) {
|
||||
state.tokenize = f;
|
||||
return f(stream, state);
|
||||
}
|
||||
|
||||
function nextUntilUnescaped(stream, end) {
|
||||
var escaped = false, next;
|
||||
function readRegexp(stream) {
|
||||
var escaped = false, next, inSet = false;
|
||||
while ((next = stream.next()) != null) {
|
||||
if (next == end && !escaped)
|
||||
return false;
|
||||
if (!escaped) {
|
||||
if (next == "/" && !inSet) return;
|
||||
if (next == "[") inSet = true;
|
||||
else if (inSet && next == "]") inSet = false;
|
||||
}
|
||||
escaped = !escaped && next == "\\";
|
||||
}
|
||||
return escaped;
|
||||
}
|
||||
|
||||
// Used as scratch variables to communicate multiple values without
|
||||
@@ -78,50 +73,51 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
||||
type = tp; content = cont;
|
||||
return style;
|
||||
}
|
||||
function jsTokenBase(stream, state) {
|
||||
function tokenBase(stream, state) {
|
||||
var ch = stream.next();
|
||||
if (ch == '"' || ch == "'")
|
||||
return chain(stream, state, jsTokenString(ch));
|
||||
else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/))
|
||||
if (ch == '"' || ch == "'") {
|
||||
state.tokenize = tokenString(ch);
|
||||
return state.tokenize(stream, state);
|
||||
} else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) {
|
||||
return ret("number", "number");
|
||||
else if (/[\[\]{}\(\),;\:\.]/.test(ch))
|
||||
} else if (ch == "." && stream.match("..")) {
|
||||
return ret("spread", "meta");
|
||||
} else if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
|
||||
return ret(ch);
|
||||
else if (ch == "0" && stream.eat(/x/i)) {
|
||||
} else if (ch == "=" && stream.eat(">")) {
|
||||
return ret("=>", "operator");
|
||||
} else if (ch == "0" && stream.eat(/x/i)) {
|
||||
stream.eatWhile(/[\da-f]/i);
|
||||
return ret("number", "number");
|
||||
}
|
||||
else if (/\d/.test(ch)) {
|
||||
} else if (/\d/.test(ch)) {
|
||||
stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
|
||||
return ret("number", "number");
|
||||
}
|
||||
else if (ch == "/") {
|
||||
} else if (ch == "/") {
|
||||
if (stream.eat("*")) {
|
||||
return chain(stream, state, jsTokenComment);
|
||||
}
|
||||
else if (stream.eat("/")) {
|
||||
state.tokenize = tokenComment;
|
||||
return tokenComment(stream, state);
|
||||
} else if (stream.eat("/")) {
|
||||
stream.skipToEnd();
|
||||
return ret("comment", "comment");
|
||||
}
|
||||
else if (state.lastType == "operator" || state.lastType == "keyword c" ||
|
||||
/^[\[{}\(,;:]$/.test(state.lastType)) {
|
||||
nextUntilUnescaped(stream, "/");
|
||||
} else if (state.lastType == "operator" || state.lastType == "keyword c" ||
|
||||
state.lastType == "sof" || /^[\[{}\(,;:]$/.test(state.lastType)) {
|
||||
readRegexp(stream);
|
||||
stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla
|
||||
return ret("regexp", "string-2");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
stream.eatWhile(isOperatorChar);
|
||||
return ret("operator", null, stream.current());
|
||||
return ret("operator", "operator", stream.current());
|
||||
}
|
||||
}
|
||||
else if (ch == "#") {
|
||||
} else if (ch == "`") {
|
||||
state.tokenize = tokenQuasi;
|
||||
return tokenQuasi(stream, state);
|
||||
} else if (ch == "#") {
|
||||
stream.skipToEnd();
|
||||
return ret("error", "error");
|
||||
}
|
||||
else if (isOperatorChar.test(ch)) {
|
||||
} else if (isOperatorChar.test(ch)) {
|
||||
stream.eatWhile(isOperatorChar);
|
||||
return ret("operator", null, stream.current());
|
||||
}
|
||||
else {
|
||||
return ret("operator", "operator", stream.current());
|
||||
} else {
|
||||
stream.eatWhile(/[\w\$_]/);
|
||||
var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
|
||||
return (known && state.lastType != ".") ? ret(known.type, known.style, word) :
|
||||
@@ -129,19 +125,23 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
||||
}
|
||||
}
|
||||
|
||||
function jsTokenString(quote) {
|
||||
function tokenString(quote) {
|
||||
return function(stream, state) {
|
||||
if (!nextUntilUnescaped(stream, quote))
|
||||
state.tokenize = jsTokenBase;
|
||||
var escaped = false, next;
|
||||
while ((next = stream.next()) != null) {
|
||||
if (next == quote && !escaped) break;
|
||||
escaped = !escaped && next == "\\";
|
||||
}
|
||||
if (!escaped) state.tokenize = tokenBase;
|
||||
return ret("string", "string");
|
||||
};
|
||||
}
|
||||
|
||||
function jsTokenComment(stream, state) {
|
||||
function tokenComment(stream, state) {
|
||||
var maybeEnd = false, ch;
|
||||
while (ch = stream.next()) {
|
||||
if (ch == "/" && maybeEnd) {
|
||||
state.tokenize = jsTokenBase;
|
||||
state.tokenize = tokenBase;
|
||||
break;
|
||||
}
|
||||
maybeEnd = (ch == "*");
|
||||
@@ -149,6 +149,50 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
||||
return ret("comment", "comment");
|
||||
}
|
||||
|
||||
function tokenQuasi(stream, state) {
|
||||
var escaped = false, next;
|
||||
while ((next = stream.next()) != null) {
|
||||
if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) {
|
||||
state.tokenize = tokenBase;
|
||||
break;
|
||||
}
|
||||
escaped = !escaped && next == "\\";
|
||||
}
|
||||
return ret("quasi", "string-2", stream.current());
|
||||
}
|
||||
|
||||
var brackets = "([{}])";
|
||||
// This is a crude lookahead trick to try and notice that we're
|
||||
// parsing the argument patterns for a fat-arrow function before we
|
||||
// actually hit the arrow token. It only works if the arrow is on
|
||||
// the same line as the arguments and there's no strange noise
|
||||
// (comments) in between. Fallback is to only notice when we hit the
|
||||
// arrow, and not declare the arguments as locals for the arrow
|
||||
// body.
|
||||
function findFatArrow(stream, state) {
|
||||
if (state.fatArrowAt) state.fatArrowAt = null;
|
||||
var arrow = stream.string.indexOf("=>", stream.start);
|
||||
if (arrow < 0) return;
|
||||
|
||||
var depth = 0, sawSomething = false;
|
||||
for (var pos = arrow - 1; pos >= 0; --pos) {
|
||||
var ch = stream.string.charAt(pos);
|
||||
var bracket = brackets.indexOf(ch);
|
||||
if (bracket >= 0 && bracket < 3) {
|
||||
if (!depth) { ++pos; break; }
|
||||
if (--depth == 0) break;
|
||||
} else if (bracket >= 3 && bracket < 6) {
|
||||
++depth;
|
||||
} else if (/[$\w]/.test(ch)) {
|
||||
sawSomething = true;
|
||||
} else if (sawSomething && !depth) {
|
||||
++pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sawSomething && !depth) state.fatArrowAt = pos;
|
||||
}
|
||||
|
||||
// Parser
|
||||
|
||||
var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true};
|
||||
@@ -165,6 +209,10 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
||||
function inScope(state, varname) {
|
||||
for (var v = state.localVars; v; v = v.next)
|
||||
if (v.name == varname) return true;
|
||||
for (var cx = state.context; cx; cx = cx.prev) {
|
||||
for (var v = cx.vars; v; v = v.next)
|
||||
if (v.name == varname) return true;
|
||||
}
|
||||
}
|
||||
|
||||
function parseJS(state, style, type, content, stream) {
|
||||
@@ -211,7 +259,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
||||
state.localVars = {name: varname, next: state.localVars};
|
||||
} else {
|
||||
if (inList(state.globalVars)) return;
|
||||
state.globalVars = {name: varname, next: state.globalVars};
|
||||
if (parserConfig.globalVars)
|
||||
state.globalVars = {name: varname, next: state.globalVars};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,16 +302,15 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
||||
};
|
||||
}
|
||||
|
||||
function statement(type) {
|
||||
if (type == "var") return cont(pushlex("vardef"), vardef1, expect(";"), poplex);
|
||||
function statement(type, value) {
|
||||
if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex);
|
||||
if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
|
||||
if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
|
||||
if (type == "{") return cont(pushlex("}"), block, poplex);
|
||||
if (type == ";") return cont();
|
||||
if (type == "if") return cont(pushlex("form"), expression, statement, poplex, maybeelse);
|
||||
if (type == "function") return cont(functiondef);
|
||||
if (type == "for") return cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"),
|
||||
poplex, statement, poplex);
|
||||
if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
|
||||
if (type == "variable") return cont(pushlex("stat"), maybelabel);
|
||||
if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
|
||||
block, poplex, poplex);
|
||||
@@ -270,6 +318,10 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
||||
if (type == "default") return cont(expect(":"));
|
||||
if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
|
||||
statement, poplex, popcontext);
|
||||
if (type == "module") return cont(pushlex("form"), pushcontext, afterModule, popcontext, poplex);
|
||||
if (type == "class") return cont(pushlex("form"), className, objlit, poplex);
|
||||
if (type == "export") return cont(pushlex("form"), afterExport, poplex);
|
||||
if (type == "import") return cont(pushlex("form"), afterImport, poplex);
|
||||
return pass(pushlex("stat"), expression, expect(";"), poplex);
|
||||
}
|
||||
function expression(type) {
|
||||
@@ -279,14 +331,20 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
||||
return expressionInner(type, true);
|
||||
}
|
||||
function expressionInner(type, noComma) {
|
||||
if (cx.state.fatArrowAt == cx.stream.start) {
|
||||
var body = noComma ? arrowBodyNoComma : arrowBody;
|
||||
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext);
|
||||
else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
|
||||
}
|
||||
|
||||
var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
|
||||
if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
|
||||
if (type == "function") return cont(functiondef);
|
||||
if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
|
||||
if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop);
|
||||
if (type == "operator") return cont(noComma ? expressionNoComma : expression);
|
||||
if (type == "[") return cont(pushlex("]"), commasep(expressionNoComma, "]"), poplex, maybeop);
|
||||
if (type == "{") return cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeop);
|
||||
if (type == "(") return cont(pushlex(")"), maybeexpression, comprehension, expect(")"), poplex, maybeop);
|
||||
if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
|
||||
if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
|
||||
if (type == "{") return contCommasep(objprop, "}", null, maybeop);
|
||||
return cont();
|
||||
}
|
||||
function maybeexpression(type) {
|
||||
@@ -305,16 +363,39 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
||||
function maybeoperatorNoComma(type, value, noComma) {
|
||||
var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;
|
||||
var expr = noComma == false ? expression : expressionNoComma;
|
||||
if (value == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
|
||||
if (type == "operator") {
|
||||
if (/\+\+|--/.test(value)) return cont(me);
|
||||
if (value == "?") return cont(expression, expect(":"), expr);
|
||||
return cont(expr);
|
||||
}
|
||||
if (type == "quasi") { cx.cc.push(me); return quasi(value); }
|
||||
if (type == ";") return;
|
||||
if (type == "(") return cont(pushlex(")", "call"), commasep(expressionNoComma, ")"), poplex, me);
|
||||
if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
|
||||
if (type == ".") return cont(property, me);
|
||||
if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
|
||||
}
|
||||
function quasi(value) {
|
||||
if (value.slice(value.length - 2) != "${") return cont();
|
||||
return cont(expression, continueQuasi);
|
||||
}
|
||||
function continueQuasi(type) {
|
||||
if (type == "}") {
|
||||
cx.marked = "string-2";
|
||||
cx.state.tokenize = tokenQuasi;
|
||||
return cont();
|
||||
}
|
||||
}
|
||||
function arrowBody(type) {
|
||||
findFatArrow(cx.stream, cx.state);
|
||||
if (type == "{") return pass(statement);
|
||||
return pass(expression);
|
||||
}
|
||||
function arrowBodyNoComma(type) {
|
||||
findFatArrow(cx.stream, cx.state);
|
||||
if (type == "{") return pass(statement);
|
||||
return pass(expressionNoComma);
|
||||
}
|
||||
function maybelabel(type) {
|
||||
if (type == ":") return cont(poplex, statement);
|
||||
return pass(maybeoperatorComma, expect(";"), poplex);
|
||||
@@ -328,15 +409,20 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
||||
if (value == "get" || value == "set") return cont(getterSetter);
|
||||
} else if (type == "number" || type == "string") {
|
||||
cx.marked = type + " property";
|
||||
} else if (type == "[") {
|
||||
return cont(expression, expect("]"), afterprop);
|
||||
}
|
||||
if (atomicTypes.hasOwnProperty(type)) return cont(expect(":"), expressionNoComma);
|
||||
if (atomicTypes.hasOwnProperty(type)) return cont(afterprop);
|
||||
}
|
||||
function getterSetter(type) {
|
||||
if (type == ":") return cont(expression);
|
||||
if (type != "variable") return cont(expect(":"), expression);
|
||||
if (type != "variable") return pass(afterprop);
|
||||
cx.marked = "property";
|
||||
return cont(functiondef);
|
||||
}
|
||||
function afterprop(type) {
|
||||
if (type == ":") return cont(expressionNoComma);
|
||||
if (type == "(") return pass(functiondef);
|
||||
}
|
||||
function commasep(what, end) {
|
||||
function proceed(type) {
|
||||
if (type == ",") {
|
||||
@@ -349,75 +435,138 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
||||
}
|
||||
return function(type) {
|
||||
if (type == end) return cont();
|
||||
else return pass(what, proceed);
|
||||
return pass(what, proceed);
|
||||
};
|
||||
}
|
||||
function contCommasep(what, end, info) {
|
||||
for (var i = 3; i < arguments.length; i++)
|
||||
cx.cc.push(arguments[i]);
|
||||
return cont(pushlex(end, info), commasep(what, end), poplex);
|
||||
}
|
||||
function block(type) {
|
||||
if (type == "}") return cont();
|
||||
return pass(statement, block);
|
||||
}
|
||||
function maybetype(type) {
|
||||
if (type == ":") return cont(typedef);
|
||||
return pass();
|
||||
if (isTS && type == ":") return cont(typedef);
|
||||
}
|
||||
function typedef(type) {
|
||||
if (type == "variable"){cx.marked = "variable-3"; return cont();}
|
||||
return pass();
|
||||
}
|
||||
function vardef1(type, value) {
|
||||
if (type == "variable") {
|
||||
function vardef() {
|
||||
return pass(pattern, maybetype, maybeAssign, vardefCont);
|
||||
}
|
||||
function pattern(type, value) {
|
||||
if (type == "variable") { register(value); return cont(); }
|
||||
if (type == "[") return contCommasep(pattern, "]");
|
||||
if (type == "{") return contCommasep(proppattern, "}");
|
||||
}
|
||||
function proppattern(type, value) {
|
||||
if (type == "variable" && !cx.stream.match(/^\s*:/, false)) {
|
||||
register(value);
|
||||
return isTS ? cont(maybetype, vardef2) : cont(vardef2);
|
||||
return cont(maybeAssign);
|
||||
}
|
||||
return pass();
|
||||
if (type == "variable") cx.marked = "property";
|
||||
return cont(expect(":"), pattern, maybeAssign);
|
||||
}
|
||||
function vardef2(type, value) {
|
||||
if (value == "=") return cont(expressionNoComma, vardef2);
|
||||
if (type == ",") return cont(vardef1);
|
||||
function maybeAssign(_type, value) {
|
||||
if (value == "=") return cont(expressionNoComma);
|
||||
}
|
||||
function vardefCont(type) {
|
||||
if (type == ",") return cont(vardef);
|
||||
}
|
||||
function maybeelse(type, value) {
|
||||
if (type == "keyword b" && value == "else") return cont(pushlex("form"), statement, poplex);
|
||||
}
|
||||
function forspec(type) {
|
||||
if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
|
||||
}
|
||||
function forspec1(type) {
|
||||
if (type == "var") return cont(vardef1, expect(";"), forspec2);
|
||||
if (type == "var") return cont(vardef, expect(";"), forspec2);
|
||||
if (type == ";") return cont(forspec2);
|
||||
if (type == "variable") return cont(formaybein);
|
||||
if (type == "variable") return cont(formaybeinof);
|
||||
return pass(expression, expect(";"), forspec2);
|
||||
}
|
||||
function formaybein(_type, value) {
|
||||
if (value == "in") return cont(expression);
|
||||
function formaybeinof(_type, value) {
|
||||
if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
|
||||
return cont(maybeoperatorComma, forspec2);
|
||||
}
|
||||
function forspec2(type, value) {
|
||||
if (type == ";") return cont(forspec3);
|
||||
if (value == "in") return cont(expression);
|
||||
if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
|
||||
return pass(expression, expect(";"), forspec3);
|
||||
}
|
||||
function forspec3(type) {
|
||||
if (type != ")") cont(expression);
|
||||
}
|
||||
function functiondef(type, value) {
|
||||
if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
|
||||
if (type == "variable") {register(value); return cont(functiondef);}
|
||||
if (type == "(") return cont(pushlex(")"), pushcontext, commasep(funarg, ")"), poplex, statement, popcontext);
|
||||
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, statement, popcontext);
|
||||
}
|
||||
function funarg(type, value) {
|
||||
if (type == "variable") {register(value); return isTS ? cont(maybetype) : cont();}
|
||||
function funarg(type) {
|
||||
if (type == "spread") return cont(funarg);
|
||||
return pass(pattern, maybetype);
|
||||
}
|
||||
function className(type, value) {
|
||||
if (type == "variable") {register(value); return cont(classNameAfter);}
|
||||
}
|
||||
function classNameAfter(_type, value) {
|
||||
if (value == "extends") return cont(expression);
|
||||
}
|
||||
function objlit(type) {
|
||||
if (type == "{") return contCommasep(objprop, "}");
|
||||
}
|
||||
function afterModule(type, value) {
|
||||
if (type == "string") return cont(statement);
|
||||
if (type == "variable") { register(value); return cont(maybeFrom); }
|
||||
}
|
||||
function afterExport(_type, value) {
|
||||
if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
|
||||
if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
|
||||
return pass(statement);
|
||||
}
|
||||
function afterImport(type) {
|
||||
if (type == "string") return cont();
|
||||
return pass(importSpec, maybeFrom);
|
||||
}
|
||||
function importSpec(type, value) {
|
||||
if (type == "{") return contCommasep(importSpec, "}");
|
||||
if (type == "variable") register(value);
|
||||
return cont();
|
||||
}
|
||||
function maybeFrom(_type, value) {
|
||||
if (value == "from") { cx.marked = "keyword"; return cont(expression); }
|
||||
}
|
||||
function arrayLiteral(type) {
|
||||
if (type == "]") return cont();
|
||||
return pass(expressionNoComma, maybeArrayComprehension);
|
||||
}
|
||||
function maybeArrayComprehension(type) {
|
||||
if (type == "for") return pass(comprehension, expect("]"));
|
||||
if (type == ",") return cont(commasep(expressionNoComma, "]"));
|
||||
return pass(commasep(expressionNoComma, "]"));
|
||||
}
|
||||
function comprehension(type) {
|
||||
if (type == "for") return cont(forspec, comprehension);
|
||||
if (type == "if") return cont(expression, comprehension);
|
||||
}
|
||||
|
||||
// Interface
|
||||
|
||||
return {
|
||||
startState: function(basecolumn) {
|
||||
return {
|
||||
tokenize: jsTokenBase,
|
||||
lastType: null,
|
||||
var state = {
|
||||
tokenize: tokenBase,
|
||||
lastType: "sof",
|
||||
cc: [],
|
||||
lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
|
||||
localVars: parserConfig.localVars,
|
||||
globalVars: parserConfig.globalVars,
|
||||
context: parserConfig.localVars && {vars: parserConfig.localVars},
|
||||
indented: 0
|
||||
};
|
||||
if (parserConfig.globalVars) state.globalVars = parserConfig.globalVars;
|
||||
return state;
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
@@ -425,8 +574,9 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
||||
if (!state.lexical.hasOwnProperty("align"))
|
||||
state.lexical.align = false;
|
||||
state.indented = stream.indentation();
|
||||
findFatArrow(stream, state);
|
||||
}
|
||||
if (state.tokenize != jsTokenComment && stream.eatSpace()) return null;
|
||||
if (state.tokenize != tokenComment && stream.eatSpace()) return null;
|
||||
var style = state.tokenize(stream, state);
|
||||
if (type == "comment") return style;
|
||||
state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type;
|
||||
@@ -434,21 +584,21 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
||||
},
|
||||
|
||||
indent: function(state, textAfter) {
|
||||
if (state.tokenize == jsTokenComment) return CodeMirror.Pass;
|
||||
if (state.tokenize != jsTokenBase) return 0;
|
||||
if (state.tokenize == tokenComment) return CodeMirror.Pass;
|
||||
if (state.tokenize != tokenBase) return 0;
|
||||
var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
|
||||
// Kludge to prevent 'maybelse' from blocking lexical scope pops
|
||||
for (var i = state.cc.length - 1; i >= 0; --i) {
|
||||
var c = state.cc[i];
|
||||
if (c == poplex) lexical = lexical.prev;
|
||||
else if (c != maybeelse || /^else\b/.test(textAfter)) break;
|
||||
else if (c != maybeelse) break;
|
||||
}
|
||||
if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
|
||||
if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
|
||||
lexical = lexical.prev;
|
||||
var type = lexical.type, closing = firstChar == type;
|
||||
|
||||
if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? 4 : 0);
|
||||
if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0);
|
||||
else if (type == "form" && firstChar == "{") return lexical.indented;
|
||||
else if (type == "form") return lexical.indented + indentUnit;
|
||||
else if (type == "stat")
|
||||
|
||||
@@ -18,6 +18,7 @@ CodeMirror.modeInfo = [
|
||||
{name: 'Eiffel', mime: 'text/x-eiffel', mode: 'eiffel'},
|
||||
{name: 'Erlang', mime: 'text/x-erlang', mode: 'erlang'},
|
||||
{name: 'Fortran', mime: 'text/x-fortran', mode: 'fortran'},
|
||||
{name: 'F#', mime: 'text/x-fsharp', mode: 'mllike'},
|
||||
{name: 'Gas', mime: 'text/x-gas', mode: 'gas'},
|
||||
{name: 'Gherkin', mime: 'text/x-feature', mode: 'gherkin'},
|
||||
{name: 'GitHub Flavored Markdown', mime: 'text/x-gfm', mode: 'gfm'},
|
||||
@@ -36,7 +37,8 @@ CodeMirror.modeInfo = [
|
||||
{name: 'JSON', mime: 'application/x-json', mode: 'javascript'},
|
||||
{name: 'JSON', mime: 'application/json', mode: 'javascript'},
|
||||
{name: 'TypeScript', mime: 'application/typescript', mode: 'javascript'},
|
||||
{name: 'Jinja2', mime: 'jinja2', mode: 'jinja2'},
|
||||
{name: 'Jinja2', mime: null, mode: 'jinja2'},
|
||||
{name: 'Julia', mime: 'text/x-julia', mode: 'julia'},
|
||||
{name: 'LESS', mime: 'text/x-less', mode: 'less'},
|
||||
{name: 'LiveScript', mime: 'text/x-livescript', mode: 'livescript'},
|
||||
{name: 'Lua', mime: 'text/x-lua', mode: 'lua'},
|
||||
@@ -44,9 +46,10 @@ CodeMirror.modeInfo = [
|
||||
{name: 'mIRC', mime: 'text/mirc', mode: 'mirc'},
|
||||
{name: 'Nginx', mime: 'text/x-nginx-conf', mode: 'nginx'},
|
||||
{name: 'NTriples', mime: 'text/n-triples', mode: 'ntriples'},
|
||||
{name: 'OCaml', mime: 'text/x-ocaml', mode: 'ocaml'},
|
||||
{name: 'OCaml', mime: 'text/x-ocaml', mode: 'mllike'},
|
||||
{name: 'Octave', mime: 'text/x-octave', mode: 'octave'},
|
||||
{name: 'Pascal', mime: 'text/x-pascal', mode: 'pascal'},
|
||||
{name: 'PEG.js', mime: null, mode: 'pegjs'},
|
||||
{name: 'Perl', mime: 'text/x-perl', mode: 'perl'},
|
||||
{name: 'PHP', mime: 'text/x-php', mode: 'php'},
|
||||
{name: 'PHP(HTML)', mime: 'application/x-httpd-php', mode: 'php'},
|
||||
|
||||
@@ -11,6 +11,7 @@ CodeMirror.defineMode("python", function(conf, parserConf) {
|
||||
var doubleDelimiters = parserConf.doubleDelimiters || new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))");
|
||||
var tripleDelimiters = parserConf.tripleDelimiters || new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))");
|
||||
var identifiers = parserConf.identifiers|| new RegExp("^[_A-Za-z][_A-Za-z0-9]*");
|
||||
var hangingIndent = parserConf.hangingIndent || parserConf.indentUnit;
|
||||
|
||||
var wordOperators = wordRegexp(['and', 'or', 'not', 'is', 'in']);
|
||||
var commonkeywords = ['as', 'assert', 'break', 'class', 'continue',
|
||||
@@ -211,6 +212,11 @@ CodeMirror.defineMode("python", function(conf, parserConf) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (stream.match(/\s*($|#)/, false)) {
|
||||
// An open paren/bracket/brace with only space or comments after it
|
||||
// on the line will indent the next line a fixed amount, to make it
|
||||
// easier to put arguments, list items, etc. on their own lines.
|
||||
indentUnit = stream.indentation() + hangingIndent;
|
||||
} else {
|
||||
indentUnit = stream.column() + stream.current().length;
|
||||
}
|
||||
|
||||
189
applications/admin/static/codemirror/mode/xml/xml.js
vendored
189
applications/admin/static/codemirror/mode/xml/xml.js
vendored
@@ -45,7 +45,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
|
||||
var alignCDATA = parserConfig.alignCDATA;
|
||||
|
||||
// Return variables for tokenizers
|
||||
var tagName, type;
|
||||
var tagName, type, setStyle;
|
||||
|
||||
function inText(stream, state) {
|
||||
function chain(parser) {
|
||||
@@ -110,6 +110,8 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
|
||||
return null;
|
||||
} else if (ch == "<") {
|
||||
state.tokenize = inText;
|
||||
state.state = baseState;
|
||||
state.tagName = state.tagStart = null;
|
||||
var next = state.tokenize(stream, state);
|
||||
return next ? next + " error" : "error";
|
||||
} else if (/[\'\"]/.test(ch)) {
|
||||
@@ -169,139 +171,124 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
|
||||
};
|
||||
}
|
||||
|
||||
var curState, curStream, setStyle;
|
||||
function pass() {
|
||||
for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]);
|
||||
function Context(state, tagName, startOfLine) {
|
||||
this.prev = state.context;
|
||||
this.tagName = tagName;
|
||||
this.indent = state.indented;
|
||||
this.startOfLine = startOfLine;
|
||||
if (Kludges.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent))
|
||||
this.noIndent = true;
|
||||
}
|
||||
function cont() {
|
||||
pass.apply(null, arguments);
|
||||
return true;
|
||||
function popContext(state) {
|
||||
if (state.context) state.context = state.context.prev;
|
||||
}
|
||||
function maybePopContext(state, nextTagName) {
|
||||
var parentTagName;
|
||||
while (true) {
|
||||
if (!state.context) {
|
||||
return;
|
||||
}
|
||||
parentTagName = state.context.tagName.toLowerCase();
|
||||
if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) ||
|
||||
!Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
|
||||
return;
|
||||
}
|
||||
popContext(state);
|
||||
}
|
||||
}
|
||||
|
||||
function pushContext(tagName, startOfLine) {
|
||||
var noIndent = Kludges.doNotIndent.hasOwnProperty(tagName) || (curState.context && curState.context.noIndent);
|
||||
curState.context = {
|
||||
prev: curState.context,
|
||||
tagName: tagName,
|
||||
indent: curState.indented,
|
||||
startOfLine: startOfLine,
|
||||
noIndent: noIndent
|
||||
};
|
||||
}
|
||||
function popContext() {
|
||||
if (curState.context) curState.context = curState.context.prev;
|
||||
}
|
||||
|
||||
function element(type) {
|
||||
function baseState(type, stream, state) {
|
||||
if (type == "openTag") {
|
||||
curState.tagName = tagName;
|
||||
curState.tagStart = curStream.column();
|
||||
return cont(attributes, endtag(curState.startOfLine));
|
||||
state.tagName = tagName;
|
||||
state.tagStart = stream.column();
|
||||
return attrState;
|
||||
} else if (type == "closeTag") {
|
||||
var err = false;
|
||||
if (curState.context) {
|
||||
if (curState.context.tagName != tagName) {
|
||||
if (Kludges.implicitlyClosed.hasOwnProperty(curState.context.tagName.toLowerCase())) {
|
||||
popContext();
|
||||
}
|
||||
err = !curState.context || curState.context.tagName != tagName;
|
||||
if (state.context) {
|
||||
if (state.context.tagName != tagName) {
|
||||
if (Kludges.implicitlyClosed.hasOwnProperty(state.context.tagName.toLowerCase()))
|
||||
popContext(state);
|
||||
err = !state.context || state.context.tagName != tagName;
|
||||
}
|
||||
} else {
|
||||
err = true;
|
||||
}
|
||||
if (err) setStyle = "error";
|
||||
return cont(endclosetag(err));
|
||||
return err ? closeStateErr : closeState;
|
||||
} else {
|
||||
return baseState;
|
||||
}
|
||||
return cont();
|
||||
}
|
||||
function endtag(startOfLine) {
|
||||
return function(type) {
|
||||
var tagName = curState.tagName;
|
||||
curState.tagName = curState.tagStart = null;
|
||||
if (type == "selfcloseTag" ||
|
||||
(type == "endTag" && Kludges.autoSelfClosers.hasOwnProperty(tagName.toLowerCase()))) {
|
||||
maybePopContext(tagName.toLowerCase());
|
||||
return cont();
|
||||
}
|
||||
if (type == "endTag") {
|
||||
maybePopContext(tagName.toLowerCase());
|
||||
pushContext(tagName, startOfLine);
|
||||
return cont();
|
||||
}
|
||||
return cont();
|
||||
};
|
||||
}
|
||||
function endclosetag(err) {
|
||||
return function(type) {
|
||||
if (err) setStyle = "error";
|
||||
if (type == "endTag") { popContext(); return cont(); }
|
||||
function closeState(type, _stream, state) {
|
||||
if (type != "endTag") {
|
||||
setStyle = "error";
|
||||
return cont(arguments.callee);
|
||||
};
|
||||
}
|
||||
function maybePopContext(nextTagName) {
|
||||
var parentTagName;
|
||||
while (true) {
|
||||
if (!curState.context) {
|
||||
return;
|
||||
}
|
||||
parentTagName = curState.context.tagName.toLowerCase();
|
||||
if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) ||
|
||||
!Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
|
||||
return;
|
||||
}
|
||||
popContext();
|
||||
return closeState;
|
||||
}
|
||||
popContext(state);
|
||||
return baseState;
|
||||
}
|
||||
function closeStateErr(type, stream, state) {
|
||||
setStyle = "error";
|
||||
return closeState(type, stream, state);
|
||||
}
|
||||
|
||||
function attributes(type) {
|
||||
if (type == "word") {setStyle = "attribute"; return cont(attribute, attributes);}
|
||||
if (type == "endTag" || type == "selfcloseTag") return pass();
|
||||
function attrState(type, _stream, state) {
|
||||
if (type == "word") {
|
||||
setStyle = "attribute";
|
||||
return attrEqState;
|
||||
} else if (type == "endTag" || type == "selfcloseTag") {
|
||||
var tagName = state.tagName, tagStart = state.tagStart;
|
||||
state.tagName = state.tagStart = null;
|
||||
if (type == "selfcloseTag" ||
|
||||
Kludges.autoSelfClosers.hasOwnProperty(tagName.toLowerCase())) {
|
||||
maybePopContext(state, tagName.toLowerCase());
|
||||
} else {
|
||||
maybePopContext(state, tagName.toLowerCase());
|
||||
state.context = new Context(state, tagName, tagStart == state.indented);
|
||||
}
|
||||
return baseState;
|
||||
}
|
||||
setStyle = "error";
|
||||
return cont(attributes);
|
||||
return attrState;
|
||||
}
|
||||
function attribute(type) {
|
||||
if (type == "equals") return cont(attvalue, attributes);
|
||||
function attrEqState(type, stream, state) {
|
||||
if (type == "equals") return attrValueState;
|
||||
if (!Kludges.allowMissing) setStyle = "error";
|
||||
else if (type == "word") {setStyle = "attribute"; return cont(attribute, attributes);}
|
||||
return (type == "endTag" || type == "selfcloseTag") ? pass() : cont();
|
||||
return attrState(type, stream, state);
|
||||
}
|
||||
function attvalue(type) {
|
||||
if (type == "string") return cont(attvaluemaybe);
|
||||
if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return cont();}
|
||||
function attrValueState(type, stream, state) {
|
||||
if (type == "string") return attrContinuedState;
|
||||
if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return attrState;}
|
||||
setStyle = "error";
|
||||
return (type == "endTag" || type == "selfCloseTag") ? pass() : cont();
|
||||
return attrState(type, stream, state);
|
||||
}
|
||||
function attvaluemaybe(type) {
|
||||
if (type == "string") return cont(attvaluemaybe);
|
||||
else return pass();
|
||||
function attrContinuedState(type, stream, state) {
|
||||
if (type == "string") return attrContinuedState;
|
||||
return attrState(type, stream, state);
|
||||
}
|
||||
|
||||
return {
|
||||
startState: function() {
|
||||
return {tokenize: inText, cc: [], indented: 0, startOfLine: true, tagName: null, tagStart: null, context: null};
|
||||
return {tokenize: inText,
|
||||
state: baseState,
|
||||
indented: 0,
|
||||
tagName: null, tagStart: null,
|
||||
context: null};
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
if (!state.tagName && stream.sol()) {
|
||||
state.startOfLine = true;
|
||||
if (!state.tagName && stream.sol())
|
||||
state.indented = stream.indentation();
|
||||
}
|
||||
if (stream.eatSpace()) return null;
|
||||
|
||||
setStyle = type = tagName = null;
|
||||
if (stream.eatSpace()) return null;
|
||||
tagName = type = null;
|
||||
var style = state.tokenize(stream, state);
|
||||
state.type = type;
|
||||
if ((style || type) && style != "comment") {
|
||||
curState = state; curStream = stream;
|
||||
while (true) {
|
||||
var comb = state.cc.pop() || element;
|
||||
if (comb(type || style)) break;
|
||||
}
|
||||
setStyle = null;
|
||||
state.state = state.state(type || style, stream, state);
|
||||
if (setStyle)
|
||||
style = setStyle == "error" ? style + " error" : setStyle;
|
||||
}
|
||||
state.startOfLine = false;
|
||||
if (setStyle)
|
||||
style = setStyle == "error" ? style + " error" : setStyle;
|
||||
return style;
|
||||
},
|
||||
|
||||
@@ -311,8 +298,8 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
|
||||
if (state.tokenize.isInAttribute) {
|
||||
return state.stringStartCol + 1;
|
||||
}
|
||||
if ((state.tokenize != inTag && state.tokenize != inText) ||
|
||||
context && context.noIndent)
|
||||
if (context && context.noIndent) return CodeMirror.Pass;
|
||||
if (state.tokenize != inTag && state.tokenize != inText)
|
||||
return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
|
||||
// Indent the starts of attribute names.
|
||||
if (state.tagName) {
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"name": "codemirror",
|
||||
"version":"3.19.0",
|
||||
"main": "lib/codemirror.js",
|
||||
"description": "In-browser code editing made bearable",
|
||||
"licenses": [{"type": "MIT",
|
||||
"url": "http://codemirror.net/LICENSE"}],
|
||||
"directories": {"lib": "./lib"},
|
||||
"scripts": {"test": "node ./test/run.js"},
|
||||
"devDependencies": {"node-static": "0.6.0"},
|
||||
"bugs": "http://github.com/marijnh/CodeMirror/issues",
|
||||
"keywords": ["JavaScript", "CodeMirror", "Editor"],
|
||||
"homepage": "http://codemirror.net",
|
||||
"maintainers":[{"name": "Marijn Haverbeke",
|
||||
"email": "marijnh@gmail.com",
|
||||
"web": "http://marijnhaverbeke.nl"}],
|
||||
"repository": {"type": "git",
|
||||
"url": "http://marijnhaverbeke.nl/git/codemirror"}
|
||||
}
|
||||
@@ -33,7 +33,7 @@
|
||||
.cm-s-ambiance .CodeMirror-selected {
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
}
|
||||
.cm-s-ambiance .CodeMirror-focused .CodeMirror-selected {
|
||||
.cm-s-ambiance.CodeMirror-focused .CodeMirror-selected {
|
||||
background: rgba(255, 255, 255, 0.10);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,11 +24,13 @@
|
||||
|
||||
.cm-s-mbo .CodeMirror-activeline-background {background: #494b41 !important;}
|
||||
.cm-s-mbo .CodeMirror-matchingbracket {
|
||||
text-decoration: underline;
|
||||
text-decoration: underline;
|
||||
color: #f5e107 !important;
|
||||
}
|
||||
|
||||
.cm-s-mbo .CodeMirror-matchingtag {background: #4e4e4e;}
|
||||
|
||||
div.CodeMirror span.CodeMirror-searching {
|
||||
.cm-s-mbo span.cm-searching {
|
||||
background-color: none;
|
||||
background: none;
|
||||
box-shadow: 0 0 0 1px #ffffec;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* Based on the theme at http://bonsaiden.github.com/JavaScript-Garden */
|
||||
|
||||
/*<!--match-->*/
|
||||
.cm-s-midnight span.CodeMirror-matchhighlight { background: #494949 }
|
||||
.cm-s-midnight span.CodeMirror-matchhighlight { background: #494949; }
|
||||
.cm-s-midnight.CodeMirror-focused span.CodeMirror-matchhighlight { background: #314D67 !important; }
|
||||
|
||||
/*<!--activeline-->*/
|
||||
|
||||
49
applications/admin/static/codemirror/theme/pastel-on-dark.css
vendored
Normal file
49
applications/admin/static/codemirror/theme/pastel-on-dark.css
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Pastel On Dark theme ported from ACE editor
|
||||
* @license MIT
|
||||
* @copyright AtomicPages LLC 2014
|
||||
* @author Dennis Thompson, AtomicPages LLC
|
||||
* @version 1.1
|
||||
* @source https://github.com/atomicpages/codemirror-pastel-on-dark-theme
|
||||
*/
|
||||
|
||||
.cm-s-pastel-on-dark.CodeMirror {
|
||||
background: #2c2827;
|
||||
color: #8F938F;
|
||||
line-height: 1.5;
|
||||
font-family: consolas, Courier, monospace;
|
||||
font-size: 14px;
|
||||
}
|
||||
.cm-s-pastel-on-dark div.CodeMirror-selected { background: rgba(221,240,255,0.2) !important; }
|
||||
.cm-s-pastel-on-dark .CodeMirror-gutters {
|
||||
background: #34302f;
|
||||
border-right: 0px;
|
||||
padding: 0 3px;
|
||||
}
|
||||
.cm-s-pastel-on-dark .CodeMirror-linenumber { color: #8F938F; }
|
||||
.cm-s-pastel-on-dark .CodeMirror-cursor { border-left: 1px solid #A7A7A7 !important; }
|
||||
.cm-s-pastel-on-dark span.cm-comment { color: #A6C6FF; }
|
||||
.cm-s-pastel-on-dark span.cm-atom { color: #DE8E30; }
|
||||
.cm-s-pastel-on-dark span.cm-number { color: #CCCCCC; }
|
||||
.cm-s-pastel-on-dark span.cm-property { color: #8F938F; }
|
||||
.cm-s-pastel-on-dark span.cm-attribute { color: #a6e22e; }
|
||||
.cm-s-pastel-on-dark span.cm-keyword { color: #AEB2F8; }
|
||||
.cm-s-pastel-on-dark span.cm-string { color: #66A968; }
|
||||
.cm-s-pastel-on-dark span.cm-variable { color: #AEB2F8; }
|
||||
.cm-s-pastel-on-dark span.cm-variable-2 { color: #BEBF55; }
|
||||
.cm-s-pastel-on-dark span.cm-variable-3 { color: #DE8E30; }
|
||||
.cm-s-pastel-on-dark span.cm-def { color: #757aD8; }
|
||||
.cm-s-pastel-on-dark span.cm-bracket { color: #f8f8f2; }
|
||||
.cm-s-pastel-on-dark span.cm-tag { color: #C1C144; }
|
||||
.cm-s-pastel-on-dark span.cm-link { color: #ae81ff; }
|
||||
.cm-s-pastel-on-dark span.cm-qualifier,.cm-s-pastel-on-dark span.cm-builtin { color: #C1C144; }
|
||||
.cm-s-pastel-on-dark span.cm-error {
|
||||
background: #757aD8;
|
||||
color: #f8f8f0;
|
||||
}
|
||||
.cm-s-pastel-on-dark .CodeMirror-activeline-background { background: rgba(255, 255, 255, 0.031) !important; }
|
||||
.cm-s-pastel-on-dark .CodeMirror-matchingbracket {
|
||||
border: 1px solid rgba(255,255,255,0.25);
|
||||
color: #8F938F !important;
|
||||
margin: -1px -1px 0 -1px;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
.cm-s-the-matrix.CodeMirror { background: #000000; color: #00FF00; }
|
||||
.cm-s-the-matrix span.CodeMirror-selected { background: #a8f !important; }
|
||||
.cm-s-the-matrix div.CodeMirror-selected { background: #2D2D2D !important; }
|
||||
.cm-s-the-matrix .CodeMirror-gutters { background: #060; border-right: 2px solid #00FF00; }
|
||||
.cm-s-the-matrix .CodeMirror-linenumber { color: #FFFFFF; }
|
||||
.cm-s-the-matrix .CodeMirror-cursor { border-left: 1px solid #00FF00 !important; }
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
/* TODO rename this file as web2py-editor.css */
|
||||
/* Fullscreen */
|
||||
.CodeMirror-fullscreen {
|
||||
z-index: 1030;
|
||||
}
|
||||
.CodeMirror {
|
||||
border-top: 1px solid #ddd;
|
||||
/*border-left: 1px solid #ddd;*/
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
/* BREAKPOINTS */
|
||||
|
||||
@@ -36,3 +42,25 @@
|
||||
/*.nav-tabs>li {
|
||||
min-width: 100px;
|
||||
}*/
|
||||
|
||||
#windows_divs > div {
|
||||
position: fixed;
|
||||
height: 30%;
|
||||
left: 0;
|
||||
background: white;
|
||||
right: 0;
|
||||
bottom: 41px;
|
||||
z-index: 1030;
|
||||
overflow: inherit;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
#editor_main {
|
||||
margin-top:40px;
|
||||
margin-bottom:40px;
|
||||
}
|
||||
|
||||
#editform {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
|
||||
@@ -248,7 +248,7 @@ function keepalive(url) {
|
||||
});
|
||||
}
|
||||
|
||||
function load_file(url) {
|
||||
function load_file(url, lineno) {
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
contentType: 'application/json',
|
||||
@@ -260,16 +260,16 @@ function load_file(url) {
|
||||
if(typeof (json['plain_html']) !== undefined) {
|
||||
if($('#' + json['id']).length === 0 || json['force'] === true) {
|
||||
// Create a tab and put the code in it
|
||||
var tab_header = '<li><a title="'+ json['filename'] +'" href="#' + json['id'] + '" data-toggle="tab"><button type="button" class="close">×</button>' + json['realfilename'] + '</a></li>';
|
||||
var tab_header = '<li><a title="'+ json['filename'] +'" data-path="' + json['filename'] + '" href="#' + json['id'] + '" data-toggle="tab"><button type="button" class="close">×</button>' + json['realfilename'] + '</a></li>';
|
||||
var tab_body = '<div id="' + json['id'] + '" class="tab-pane fade in " >' + json['plain_html'] + '</div>';
|
||||
if(json['force'] === false) {
|
||||
$('#filesTab').append($(tab_header));
|
||||
$('#myTabContent').append($(tab_body));
|
||||
$('#myTabContent').append($(tab_body)); // First load the body
|
||||
$('#filesTab').append($(tab_header)); // Then load the header which trigger the shown event
|
||||
} else {
|
||||
$('#' + json['id']).html($(tab_body));
|
||||
}
|
||||
}
|
||||
$("a[href='#" + json['id'] + "']").click();
|
||||
$("a[href='#" + json['id'] + "']").trigger('click', lineno);
|
||||
}
|
||||
},
|
||||
error: function (x) {
|
||||
|
||||
@@ -75,8 +75,8 @@
|
||||
* this over and over... all will be bound to the document
|
||||
*/
|
||||
/*adds btn class to buttons*/
|
||||
$('button', target).addClass('btn');
|
||||
$('form input[type="submit"], form input[type="button"]', target).addClass('btn');
|
||||
$('button', target).addClass('btn').addClass('btn-default');
|
||||
$('form input[type="submit"], form input[type="button"]', target).addClass('btn').addClass('btn-default');
|
||||
/* javascript for PasswordWidget*/
|
||||
$('input[type=password][data-w2p_entropy]', target).each(function () {
|
||||
web2py.validate_entropy($(this));
|
||||
@@ -485,8 +485,10 @@
|
||||
el.addClass('disabled');
|
||||
var method = el.prop('type') == 'submit' ? 'val' : 'html';
|
||||
var disable_with_message = (typeof w2p_ajax_disable_with_message != 'undefined') ? w2p_ajax_disable_with_message : "Working...";
|
||||
/*store enabled state*/
|
||||
el.data('w2p:enable-with', el[method]());
|
||||
/*store enabled state if not already disabled */
|
||||
if (el.data('w2p:enable-with') === undefined) {
|
||||
el.data('w2p:enable-with', el[method]());
|
||||
}
|
||||
/*if you don't want to see "working..." on buttons, replace the following
|
||||
* two lines with this one
|
||||
* el.data('w2p_disable_with', el[method]());
|
||||
@@ -633,7 +635,9 @@
|
||||
if(disable_with == undefined) {
|
||||
element.data('w2p_disable_with', element[method]())
|
||||
}
|
||||
element.data('w2p:enable-with', element[method]());
|
||||
if (element.data('w2p:enable-with') === undefined) {
|
||||
element.data('w2p:enable-with', element[method]());
|
||||
}
|
||||
element[method](element.data('w2p_disable_with'));
|
||||
element.prop('disabled', true);
|
||||
});
|
||||
@@ -647,7 +651,10 @@
|
||||
form.find(web2py.enableSelector).each(function () {
|
||||
var element = $(this),
|
||||
method = element.is('button') ? 'html' : 'val';
|
||||
if(element.data('w2p:enable-with')) element[method](element.data('w2p:enable-with'));
|
||||
if(element.data('w2p:enable-with')) {
|
||||
element[method](element.data('w2p:enable-with'));
|
||||
element.removeData('w2p:enable-with');
|
||||
}
|
||||
element.prop('disabled', false);
|
||||
});
|
||||
},
|
||||
@@ -659,7 +666,18 @@
|
||||
el.on('ajax:complete', 'form[data-w2p_target]', function (e) {
|
||||
web2py.enableFormElements($(this));
|
||||
});
|
||||
}
|
||||
},
|
||||
/* Invalidate and force reload of a web2py component
|
||||
*/
|
||||
invalidate: function(target) {
|
||||
$('div[data-w2p_remote]', target).each(function () {
|
||||
var el = $('#' + $(this).attr('id')).get(0);
|
||||
if (el.timing !== undefined) { // Block triggering regular routines
|
||||
clearInterval(el.timing);
|
||||
}
|
||||
});
|
||||
$.web2py.component_handler(target);
|
||||
},
|
||||
}
|
||||
|
||||
/*end of functions */
|
||||
@@ -679,7 +697,7 @@
|
||||
/* compatibility code - start */
|
||||
ajax = jQuery.web2py.ajax;
|
||||
web2py_component = jQuery.web2py.component;
|
||||
web2py_websocket = jQuery.web2py.websocket;
|
||||
web2py_websocket = jQuery.web2py.web2py_websocket;
|
||||
web2py_ajax_page = jQuery.web2py.ajax_page;
|
||||
/*needed for IS_STRONG(entropy)*/
|
||||
web2py_validate_entropy = jQuery.web2py.validate_entropy;
|
||||
|
||||
@@ -20,14 +20,14 @@ jQuery(function(){
|
||||
function hoverMenu(){
|
||||
jQuery('ul.nav a.dropdown-toggle').parent().hover(function(){
|
||||
adjust_height_of_collapsed_nav();
|
||||
mi = jQuery(this).addClass('open');
|
||||
var mi = jQuery(this).addClass('open');
|
||||
mi.children('.dropdown-menu').stop(true, true).delay(200).fadeIn(400);
|
||||
}, function(){
|
||||
mi = jQuery(this);
|
||||
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');});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -191,7 +191,7 @@ for c in controllers: controller_functions+=[c[:-3]+'/%s.html'%x for x in functi
|
||||
<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"))}}
|
||||
{{=button(LAYOUTS_APP, T("Download layouts from repository"))}}
|
||||
</div>
|
||||
<ul class="unstyled act_edit">
|
||||
{{for c in views:}}
|
||||
@@ -442,9 +442,6 @@ for c in controllers: controller_functions+=[c[:-3]+'/%s.html'%x for x in functi
|
||||
</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">
|
||||
<div class="controls comptools">
|
||||
{{=button(URL(c="default", f="plugins", args=[app,]), T('download plugins'))}}
|
||||
</div>
|
||||
{{if plugins:}}
|
||||
<ul class="unstyled act_edit">
|
||||
{{for plugin in plugins:}}
|
||||
@@ -457,6 +454,9 @@ for c in controllers: controller_functions+=[c[:-3]+'/%s.html'%x for x in functi
|
||||
{{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'))}}
|
||||
</div>
|
||||
<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">
|
||||
|
||||
@@ -1,8 +1,37 @@
|
||||
{{main_id='editor_main'}}
|
||||
{{extend 'layout.html'}}
|
||||
{{
|
||||
dirs=[{'name':'models', 'reg':'.*\.py$'},
|
||||
{'name':'controllers', 'reg':'.*\.py$'},
|
||||
{'name':'views', 'reg':'[\w/\-]+(\.\w+)+$'},
|
||||
{'name':'modules', 'reg':'.*\.py$'},
|
||||
{'name':'static', 'reg': '[^\.#].*'}]
|
||||
|
||||
def file_create_form(location, anchor=None, helptext=""):
|
||||
form=FORM(
|
||||
LABEL(T("create file with filename:")),
|
||||
SELECT(_name='dir', _style='width:100px;',
|
||||
*[OPTION(dir['name'], _value=dir['name']) for dir in dirs]),
|
||||
XML(' '),LABEL('/', _style='display:inline-block;'),XML(' '),
|
||||
INPUT(_type="text",_name="filename",requires=IS_NOT_EMPTY(),_class=''),
|
||||
TAG['SMALL'](helptext,_class="help-block"),
|
||||
INPUT(_type='submit', name=T('filename'), _value=T('Create'), _style='display:block', _id='btn_file_create'),
|
||||
INPUT(_type="hidden",_name="editor"),
|
||||
INPUT(_type="hidden",_name="location",_value=location),
|
||||
INPUT(_type="hidden",_name="sender",_value=URL('design',args=app)),
|
||||
INPUT(_type="hidden",_name="token",_value=session.token),
|
||||
#INPUT(_type="hidden",_name="id",_value=anchor),
|
||||
_action=URL('create_file'),
|
||||
_id='file_create_form',
|
||||
_class="generatedbyw2p well well-small")
|
||||
return form
|
||||
|
||||
}}
|
||||
|
||||
<!-- 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))
|
||||
@@ -45,6 +74,7 @@
|
||||
<script src="{{=cm}}/addon/fold/xml-fold.js"></script>
|
||||
<script src="{{=cm}}/addon/fold/comment-fold.js"></script>
|
||||
<script src="{{=cm}}/addon/fold/indent-fold.js"></script>
|
||||
<script src="{{=cm}}/addon/comment/comment.js"></script>
|
||||
<link rel="stylesheet" href="{{=cm}}/addon/fold/foldgutter.css">
|
||||
<script src="{{=cm}}/emmet.min.js"></script>
|
||||
<script src="{{=js_url}}/ajax_editor.js"></script>
|
||||
@@ -52,12 +82,17 @@
|
||||
<link rel="stylesheet" href="{{=css_url}}/web2py-codemirror.css">
|
||||
<script type="text/javascript">
|
||||
var current_font_incr = 0; // Default font-size, 0 means isn't set
|
||||
$(document).on('shown click', 'a[data-toggle="tab"]', function (e) {
|
||||
$(document).on('shown click', 'a[data-toggle="tab"]', function (e, lineno) {
|
||||
var tab_id = $(this).attr('href');
|
||||
var editor = $(tab_id + " textarea").data('editor');
|
||||
if (editor) {
|
||||
editor.setSize('100%', $(tab_id).height());
|
||||
editor_height = $(window).height() - $(tab_id + " .well-small").offset().top - $(tab_id + " .well-small").outerHeight(true) - $('.navbar-fixed-bottom').outerHeight() - 1;
|
||||
editor.setSize('100%', editor_height);
|
||||
editor.refresh();
|
||||
if (lineno !== undefined) {
|
||||
editor.setCursor(lineno);
|
||||
editor.centerOnCursor();
|
||||
}
|
||||
}
|
||||
var n_li = $('#filesTab li').length;
|
||||
$.each($('#filesTab li'), function(index, element) {
|
||||
@@ -104,7 +139,8 @@ $(document).on('click', '#restore', function (e) {
|
||||
$(document).on('click', 'a.editor_filelink, a#editor_settingslink', function (e) {
|
||||
e.preventDefault();
|
||||
var url = $(this).attr("href");
|
||||
load_file(url);
|
||||
var lineno = $(this).data("lineno");
|
||||
load_file(url, lineno);
|
||||
});
|
||||
|
||||
/* This method updates all editors already instantiated with the selected preferences*/
|
||||
@@ -164,7 +200,7 @@ $(document).on('click', 'a.font_button', function (e) {
|
||||
});
|
||||
|
||||
{{if len(request.args) > 1:}}
|
||||
load_file('{{=URL(f='edit', args=request.args, vars=request.get_vars)}}');
|
||||
load_file('{{=URL(f='edit', args=request.args, vars=request.get_vars)}}', {{=request.vars.lineno or 1}});
|
||||
{{pass}}
|
||||
|
||||
</script>
|
||||
@@ -173,6 +209,9 @@ $(document).on('click', 'a.font_button', function (e) {
|
||||
|
||||
<div class='row-fluid'>
|
||||
<div class="right controls btn-toolbar pull-right">
|
||||
|
||||
{{=LOAD('default', 'editor_sessions', ajax=True, _class='btn-group')}}
|
||||
|
||||
<div class="btn-group">
|
||||
<a class="button btn" onclick="$('#files').toggle(); return false" href="#">Files toggle</a>
|
||||
</div>
|
||||
@@ -197,27 +236,22 @@ $(document).on('click', 'a.font_button', function (e) {
|
||||
<div class="files-menu">
|
||||
<ul class="nav nav-list" rel="pagebookmark" id="filelist">
|
||||
<li><input type="text" placeholder="{{=T('Rapid Search')}}" class="input-block-level typeahead-tw search-query"></li>
|
||||
{{dirs=[{'name':'models', 'reg':'.*\.py$'},
|
||||
{'name':'controllers', 'reg':'.*\.py$'},
|
||||
{'name':'views', 'reg':'[\w/\-]+(\.\w+)+$'},
|
||||
{'name':'modules', 'reg':'.*\.py$'}, ]}}
|
||||
{{auto_complete_list=[]}}
|
||||
{{for dir in dirs:}}
|
||||
<li class="nav-header component" onclick="collapse('{{="%s_files" % dir['name']}}');">{{=dir['name']}}</li>
|
||||
<li id="{{="%s_files" % dir['name']}}">
|
||||
<ul class="nav nav-list small-font">
|
||||
{{for f in listfiles(app, dir['name'], regexp=dir['reg'] ):}}
|
||||
{{id="%s__" % dir['name'] + f.replace('.','__')}}
|
||||
{{current_file = request.args(len(request.args) - 1)}}
|
||||
<li class="{{#='active' if current_file==f else ''}}" style="overflow:hidden">
|
||||
{{a_tag=editfile(dir['name'], f, dict(id=id))}}
|
||||
{{=a_tag}}
|
||||
{{auto_complete_list.append({'value':f, 'tokens':f.split('/'), 'a_tag':a_tag})}}
|
||||
</li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
</li>
|
||||
{{pass}}
|
||||
<br />
|
||||
<div>
|
||||
<button onclick="jQuery('#form').slideToggle()" class="btn btn-mini">{{=T('Create')}}</button>
|
||||
<br />
|
||||
<div id="form">
|
||||
<div>
|
||||
{{=file_create_form('%s/' % app, '')}}
|
||||
</div>
|
||||
</div>
|
||||
<script>jQuery('#form').slideToggle()</script>
|
||||
</div>
|
||||
<br />
|
||||
<div id="files_menu">
|
||||
{{=LOAD('default', 'files_menu', vars={'app':app}, ajax=True)}}
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -227,13 +261,49 @@ $(document).on('click', 'a.font_button', function (e) {
|
||||
<div id="myTabContent" class="tab-content">
|
||||
</div>
|
||||
</div>
|
||||
<section id="windows_divs" class="tab-content ">
|
||||
<div id="window_todo" class="tab-pane container-fluid">
|
||||
{{=LOAD('default', 'todolist.load', vars={'app':app}, ajax=True, timeout=60000, times="infinity")}}
|
||||
</div>
|
||||
<div id="window_shortcuts" class="tab-pane container-fluid">
|
||||
{{include 'default/editor_shortcuts.html'}}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
{{block footer}}
|
||||
<div id="" class="navbar navbar-inverse navbar-fixed-bottom">
|
||||
<div class="navbar-inner">
|
||||
<ul id="windows_hooks" class="nav">
|
||||
<li class=""><a href="#window_todo">TODO</a></li>
|
||||
<li class=""><a href="#window_shortcuts">Shortcuts</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).on('click', '#window_todo li a', function (e) {
|
||||
$(this).find('i').toggleClass('icon-chevron-right');
|
||||
$(this).find('i').toggleClass('icon-chevron-down');
|
||||
});
|
||||
$('#windows_hooks li a').click(function (e) {
|
||||
e.preventDefault();
|
||||
if ( $(this).parent('li').hasClass('active') ) {
|
||||
$(this).parent('li').removeClass('active');
|
||||
$($(this).attr('href')).removeClass('active');
|
||||
} else {
|
||||
$(this).tab('show');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{{end}}
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
var filesMenu = $('#files');
|
||||
var ow = filesMenu.outerWidth();
|
||||
filesMenu.width(ow);
|
||||
$('#files').css('left', '-'+ow+'px');
|
||||
$.web2py.trap_form('url', 'form');
|
||||
$('#form form').addClass('no_trap'); // Let to reuse the same form
|
||||
});
|
||||
</script>
|
||||
<!-- Typeahead scripts here so the page load faster -->
|
||||
@@ -250,5 +320,28 @@ $(document).ready(function() {
|
||||
load_file(datum.link);
|
||||
$(this).val('');
|
||||
});
|
||||
/* handlers to manage editor sessions
|
||||
*/
|
||||
$(document).on('click', '#save_session', function(e) {
|
||||
e.preventDefault();
|
||||
var session_name=prompt("Session name","{{=app}}");
|
||||
|
||||
if (session_name!==null) {
|
||||
files = $("[data-path]").map(function(){return $(this).data("path");}).get();
|
||||
data = JSON.stringify({ files: files, session_name:session_name});
|
||||
$.ajaxSetup({contentType: "application/json"});
|
||||
$.web2py.ajax_page("POST", "{{=URL('default', 'editor_sessions')}}", data, 'manage_sessions');
|
||||
}
|
||||
});
|
||||
$(document).on('click', '#saved_sessions a[data-files]', function(e) {
|
||||
e.preventDefault();
|
||||
files = $(this).data('files');
|
||||
array_files = files.split(',');
|
||||
$.each(array_files, function(index, value) {
|
||||
url = "{{=URL('default','edit')}}/" + value;
|
||||
load_file(url);
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
<!-- end "edit" block -->
|
||||
|
||||
@@ -21,21 +21,23 @@
|
||||
{{if view_link:}}
|
||||
{{=button(view_link, T('try view'))}}
|
||||
{{pass}}
|
||||
<p class="formfield">
|
||||
{{if functions:}}
|
||||
<span style="text-align:left;" class="exposed">
|
||||
{{=B(T('exposes:'))}} {{=XML(', '.join([A(f,_target="_blank", _href=URL(a=app,c=controller,f=f)).xml() for f in functions]))}}
|
||||
</span>
|
||||
{{if editviewlinks:}}<br/>
|
||||
{{=B(T('edit views:'))}}
|
||||
{{=XML(', '.join([v.xml() for v in editviewlinks]))}}
|
||||
{{if functions or edit_controller:}}
|
||||
<p class="formfield">
|
||||
{{if functions:}}
|
||||
<span style="text-align:left;" class="exposed">
|
||||
{{=B(T('exposes:'))}} {{=XML(', '.join([A(f,_target="_blank", _href=URL(a=app,c=controller,f=f)).xml() for f in functions]))}}
|
||||
</span>
|
||||
{{if editviewlinks:}}<br/>
|
||||
{{=B(T('edit views:'))}}
|
||||
{{=XML(', '.join([v.xml() for v in editviewlinks]))}}
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
{{if edit_controller:}}
|
||||
{{=B(T('edit controller:'))}}
|
||||
{{=A(request.args[2]+'.py', _class="editor_filelink", _target="_blank", _href=edit_controller)}}
|
||||
{{pass}}
|
||||
</p>
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
{{if edit_controller:}}
|
||||
{{=B(T('edit controller:'))}}
|
||||
{{=A(request.args[2]+'.py', _class="editor_filelink", _target="_blank", _href=edit_controller)}}
|
||||
{{pass}}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<textarea style=" height:100%; direction:ltr;" id="textarea_{{=id}}" class="input-block-level" name="data" >{{=data}}</textarea>
|
||||
@@ -63,7 +65,6 @@
|
||||
height: "350px",
|
||||
showTrailingSpace: true
|
||||
});
|
||||
editor.foldCode(CodeMirror.Pos(8, 0));
|
||||
|
||||
editor.on("gutterClick", function(cm, n, gutter) {
|
||||
if (gutter !== "breakpoints" ) return;
|
||||
@@ -74,15 +75,15 @@
|
||||
request.env['wsgi_url_scheme'], request.env['http_host'],
|
||||
URL(c='debug', f='toggle_breakpoint')))}}, sel);
|
||||
});
|
||||
function makeMarker() {
|
||||
var marker = document.createElement("div");
|
||||
marker.style.color = "#822";
|
||||
marker.innerHTML = "●";
|
||||
marker.className = "breakpoint";
|
||||
return marker;
|
||||
}
|
||||
function makeMarker() {
|
||||
var marker = document.createElement("div");
|
||||
marker.style.color = "#822";
|
||||
marker.innerHTML = "●";
|
||||
marker.className = "breakpoint";
|
||||
return marker;
|
||||
}
|
||||
|
||||
{{if filetype in ('html', 'javascript', 'css'):}}
|
||||
{{if filetype in ('html', 'javascript', 'css'):}}
|
||||
// must be here or break emmet/zencoding
|
||||
CodeMirror.defaults.extraKeys["Ctrl-S"] =
|
||||
function(instance) {
|
||||
@@ -94,26 +95,27 @@
|
||||
CodeMirror.defaults.extraKeys["Shift-Esc"] = function(cm) {
|
||||
if (cm.getOption("fullScreen")) cm.setOption("fullScreen", false);
|
||||
}
|
||||
{{pass}}
|
||||
{{if filetype=='python':}}
|
||||
// must be here or break emmet/zencoding for python
|
||||
CodeMirror.defaults.extraKeys["Ctrl-S"] =
|
||||
function(instance) {
|
||||
doClickSave();};
|
||||
CodeMirror.defaults.extraKeys["Ctrl-Space"] = "autocomplete";
|
||||
CodeMirror.defaults.extraKeys["Tab"] = "indentMore";
|
||||
CodeMirror.defaults.extraKeys["Shift-Tab"] = "indentLess";
|
||||
CodeMirror.defaults.extraKeys["Ctrl-F11"] = function(cm) {
|
||||
cm.setOption("fullScreen", !cm.getOption("fullScreen"));
|
||||
},
|
||||
CodeMirror.defaults.extraKeys["Shift-Esc"] = function(cm) {
|
||||
if (cm.getOption("fullScreen")) cm.setOption("fullScreen", false);
|
||||
}
|
||||
//for autocomplete
|
||||
CodeMirror.commands.autocomplete = function(cm) {
|
||||
CodeMirror.showHint(cm, CodeMirror.pythonHint);
|
||||
}
|
||||
{{pass}}
|
||||
{{pass}}
|
||||
{{if filetype=='python':}}
|
||||
// must be here or break emmet/zencoding for python
|
||||
CodeMirror.defaults.extraKeys["Ctrl-S"] =
|
||||
function(instance) {
|
||||
doClickSave();};
|
||||
CodeMirror.defaults.extraKeys["Ctrl-Space"] = "autocomplete";
|
||||
CodeMirror.defaults.extraKeys["Tab"] = "indentMore";
|
||||
CodeMirror.defaults.extraKeys["Shift-Tab"] = "indentLess";
|
||||
CodeMirror.defaults.extraKeys["Ctrl-F11"] = function(cm) {
|
||||
cm.setOption("fullScreen", !cm.getOption("fullScreen"));
|
||||
},
|
||||
CodeMirror.defaults.extraKeys["Shift-Esc"] = function(cm) {
|
||||
if (cm.getOption("fullScreen")) cm.setOption("fullScreen", false);
|
||||
}
|
||||
//for autocomplete
|
||||
CodeMirror.commands.autocomplete = function(cm) {
|
||||
CodeMirror.showHint(cm, CodeMirror.pythonHint);
|
||||
}
|
||||
{{pass}}
|
||||
CodeMirror.defaults.extraKeys["Ctrl-/"] = "toggleComment";
|
||||
store_changes_function = function(instance, changeObj) {
|
||||
jQuery(instance).data('saved', false);
|
||||
instance.off("change", store_changes_function);
|
||||
@@ -128,6 +130,19 @@
|
||||
request.env['wsgi_url_scheme'], request.env['http_host'],
|
||||
URL(c='debug', f='list_breakpoints')))}}, editor);
|
||||
|
||||
// TODO move it in a separated file
|
||||
CodeMirror.defineExtension("centerOnCursor", function(limit) {
|
||||
var coords = this.cursorCoords(null, "local");
|
||||
if (this.getScrollerElement().clientHeight === 0 && limit !== 10) {
|
||||
if (limit === undefined) limit = 1;
|
||||
else limit += 1;
|
||||
editor = this;
|
||||
setTimeout(function() {editor.centerOnCursor()}, 100);
|
||||
return;
|
||||
}
|
||||
clientHeight = (this.getScrollerElement().clientHeight / 2)
|
||||
this.scrollTo(null, (coords.top + coords.bottom)/2 - 10);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="editor-bar-bottom" style="margin-top:9px;">
|
||||
@@ -138,37 +153,3 @@
|
||||
</div>
|
||||
<br/>
|
||||
</form>
|
||||
|
||||
<div class="row-fluid">
|
||||
<div class="help alert alert-block alert-info">
|
||||
{{if filetype=='html':}}
|
||||
<h3>{{=T('Key bindings for ZenCoding Plugin')}}</h3>
|
||||
<ul class="keybindings unstyled">
|
||||
{{=shortcut('Ctrl+S', T('Save via Ajax'))}}
|
||||
{{=shortcut('Ctrl+F11', T('Toggle Fullscreen'))}}
|
||||
{{=shortcut('Shift+Esc', T('Exit Fullscreen'))}}
|
||||
{{=shortcut('Ctrl-F / Cmd-F', T('Start searching'))}}
|
||||
{{=shortcut('Ctrl-G / Cmd-G', T('Find Next'))}}
|
||||
{{=shortcut('Shift-Ctrl-G / Shift-Cmd-G', T('Find Previous'))}}
|
||||
{{=shortcut('Shift-Ctrl-F / Cmd-Option-F', T('Replace'))}}
|
||||
{{=shortcut('Shift-Ctrl-R / Shift-Cmd-Option-F', T('Replace All'))}}
|
||||
{{=shortcut('Tab', T('Expand Abbreviation'))}}
|
||||
</ul>
|
||||
{{else:}}
|
||||
<h3>{{=T("Key bindings")}}</h3>
|
||||
<ul class="keybindings unstyled">
|
||||
{{=shortcut('Ctrl+S', T('Save via Ajax'))}}
|
||||
{{=shortcut('Ctrl+F11', T('Toggle Fullscreen'))}}
|
||||
{{=shortcut('Shift+Esc', T('Exit Fullscreen'))}}
|
||||
{{if filetype=='python':}}
|
||||
{{=shortcut('Ctrl-Space', T('Autocomplete Python Code'))}}
|
||||
{{pass}}
|
||||
{{=shortcut('Ctrl-F / Cmd-F', T('Start searching'))}}
|
||||
{{=shortcut('Ctrl-G / Cmd-G', T('Find Next'))}}
|
||||
{{=shortcut('Shift-Ctrl-G / Shift-Cmd-G', T('Find Previous'))}}
|
||||
{{=shortcut('Shift-Ctrl-F / Cmd-Option-F', T('Replace'))}}
|
||||
{{=shortcut('Shift-Ctrl-R / Shift-Cmd-Option-F', T('Replace All'))}}
|
||||
</ul>
|
||||
{{pass}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
11
applications/admin/views/default/editor_sessions.html
Normal file
11
applications/admin/views/default/editor_sessions.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<div class="btn-group" id='manage_sessions'>
|
||||
<a class="btn dropdown-toggle" data-toggle="dropdown" href="#">Saved session <span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" id="saved_sessions">
|
||||
{{for name, files in editor_sessions.items():}}
|
||||
<li><a href="" data-files='{{=files}}'>{{=name}}</a></li>
|
||||
{{pass}}
|
||||
<li class="divider"></li>
|
||||
<li><a id="save_session" href="">Save current session</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
18
applications/admin/views/default/editor_shortcuts.html
Normal file
18
applications/admin/views/default/editor_shortcuts.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<div>
|
||||
<h4>{{=T("Keyboard shortcuts")}}</h4>
|
||||
<ul class="keybindings unstyled">
|
||||
<li></li>
|
||||
{{=shortcut('Ctrl+S', T('Save via Ajax'))}}
|
||||
{{=shortcut('Ctrl+F11', T('Toggle Fullscreen'))}}
|
||||
{{=shortcut('Shift+Esc', T('Exit Fullscreen'))}}
|
||||
{{=shortcut('Ctrl-F / Cmd-F', T('Start searching'))}}
|
||||
{{=shortcut('Ctrl-G / Cmd-G', T('Find Next'))}}
|
||||
{{=shortcut('Shift-Ctrl-G / Shift-Cmd-G', T('Find Previous'))}}
|
||||
{{=shortcut('Shift-Ctrl-F / Cmd-Option-F', T('Replace'))}}
|
||||
{{=shortcut('Shift-Ctrl-R / Shift-Cmd-Option-F', T('Replace All'))}}
|
||||
{{=shortcut('Ctrl-/ ', T('Toggle comment'))}}
|
||||
{{=shortcut('Tab', T('Expand Abbreviation (html files only)'))}}
|
||||
{{=shortcut('Ctrl-Space', T('Autocomplete Python Code'))}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
3
applications/admin/views/default/files_menu.html
Normal file
3
applications/admin/views/default/files_menu.html
Normal file
@@ -0,0 +1,3 @@
|
||||
{{for files in result_files:}}
|
||||
{{=files}}
|
||||
{{pass}}
|
||||
@@ -1,5 +1,21 @@
|
||||
{{extend 'layout.html'}}
|
||||
{{=H3("Available plugins")}}
|
||||
{{=P("Source: web2pyslices")}}
|
||||
{{=plugins}}
|
||||
{{articles = []}}
|
||||
{{for article in plugins:}}
|
||||
{{screenshots = [A(" ", T("Screenshot %s") % (x+1), " ", _href=item) for (x, item) in enumerate(article["package_data"]["screenshots"])]}}
|
||||
{{articles.append(TR(TD(H5(article["article"]["title"]),
|
||||
button(URL(c="default", f="install_plugin", args=[app,], vars={"source": article["package_data"]["download"], "plugin": article["article"]["title"]}), T("Install")),
|
||||
BR(),
|
||||
IMG(_src="http://www.web2pyslices.com/download/%s" % article["article"]["thumbnail"], _style="margin-top: 1em;"), _style="width: 20em;"),
|
||||
TD(article["article"]["description"], BR(),
|
||||
A(T("Plugin page"), _href="http://www.web2pyslices.com/slice/show/%s/" % article["article"]["id"]), " | ",
|
||||
A(T("Demo"), _href=article["package_data"]["demo"]), " | ",
|
||||
A(T("Docs"), _href=article["package_data"]["documentation"]), " | ",
|
||||
A(T("Repository (%s)") % article["package_data"]["repository_brand"], _href=article["package_data"]["repository_page"]), " | ",
|
||||
A(T("License:"), " ", (article["package_data"]["license_type"] or "").upper(), " ", T("(version %s)") % article["package_data"]["license_version"] if article["package_data"]["license_version"] else "", _href=article["package_data"]["license_url"]), " | " if screenshots else "", *screenshots, _style="width: 40em;"))
|
||||
)
|
||||
}}
|
||||
{{pass}}
|
||||
{{=TABLE(*articles)}}
|
||||
|
||||
|
||||
18
applications/admin/views/default/todolist.load
Normal file
18
applications/admin/views/default/todolist.load
Normal file
@@ -0,0 +1,18 @@
|
||||
<div>
|
||||
<!--div class="page-header"-->
|
||||
{{n_todo=reduce(lambda x,y: x + len(y['matches']), todo, 0)}}
|
||||
<h4>{{="%s TODO in %s" % (n_todo, app)}}</h4>
|
||||
<!--/div-->
|
||||
<ul class="nav nav-list cm-s-web2py">
|
||||
{{for pos_file, file in enumerate(todo):}}
|
||||
<li onclick="collapse('{{=pos_file}}_matches');"><a ><i class='icon-chevron-right'></i>{{=file['filename']}} <span class='small'>({{=len(file['matches'])}} TODO)</span></a></li>
|
||||
<li id="{{=pos_file}}_matches" style="display: none;"><ul class="nav nav-list">
|
||||
{{for m in file['matches']:}}
|
||||
<li><a href="{{=URL('edit', args=[app,file['dir'], file['filename']], vars={'lineno':m['lineno']}, extension="")}}" data-lineno="{{=m['lineno']-1}}" class="editor_filelink">
|
||||
<span class='cm-comment'>{{=m['text']}}</span>
|
||||
</a></li>
|
||||
{{pass}}
|
||||
</ul></li>
|
||||
{{pass}}
|
||||
</ul>
|
||||
</div>
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
<!-- MAIN
|
||||
=========== -->
|
||||
<div id="main" class="container-fluid">
|
||||
<div id="{{=globals().get('main_id', 'main')}}" class="container-fluid">
|
||||
<div id="main_inner" class="row-fluid">
|
||||
<div class="span12">
|
||||
<div class="flash alert">{{=response.flash or ''}}</div>
|
||||
@@ -55,6 +55,7 @@
|
||||
|
||||
<!-- 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'):}}
|
||||
@@ -68,6 +69,7 @@
|
||||
</span>{{pass}}
|
||||
</p>
|
||||
</footer><!-- /#footer -->
|
||||
{{end}}
|
||||
|
||||
<!-- BS JAVASCRIPT
|
||||
====================== -->
|
||||
|
||||
@@ -2,40 +2,41 @@
|
||||
{{block sectionclass}}shell{{end}}
|
||||
<!-- begin "shell" block -->
|
||||
<div id="wrapper">
|
||||
<div class="row-fluid">
|
||||
<div class="output-wrapper span8">
|
||||
<textarea id="output" readonly="readonly">web2py Shell {{=request.env.web2py_version}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row-fluid">
|
||||
<form id="form" action="{{=URL(r=request,f='callback',args=app)}}" method="get" class="span8">
|
||||
<div id="shellwrapper">
|
||||
<div class="prompt-wrapper">
|
||||
<div class="prompt-container">
|
||||
<textarea class="prompt" name="statement" id="statement"></textarea>
|
||||
</div>
|
||||
<a href="#" rel="tooltip" data-placement="right" data-original-title="{{=T('Type some Python code in here and hit Return (Enter) to execute it.')}}">
|
||||
{{=helpicon()}}
|
||||
<span>Type some Python code in here and hit Return (Enter) to execute it.</span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="caret"><span>>>></span></div>
|
||||
<div id="autoscroll">autoscroll</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="row-fluid clearfix">
|
||||
<div class="help alert alert-info span6">
|
||||
<ul>
|
||||
<li>Using the shell may lock the database to other users of this app.</li>
|
||||
<li>Each db statement is automatically committed.</li>
|
||||
<li>Creating new tables dynamically is not allowed.</li>
|
||||
<li>Models are automatically imported in the shell.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="output-wrapper span8">
|
||||
<textarea id="output" readonly="readonly">web2py Shell {{=request.env.web2py_version}}
|
||||
</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row-fluid">
|
||||
<form id="form" action="{{=URL(r=request,f='callback',args=app)}}" method="get" class="span8">
|
||||
<div id="shellwrapper">
|
||||
<div class="prompt-wrapper">
|
||||
<div class="prompt-container">
|
||||
<textarea class="prompt" name="statement" id="statement"></textarea>
|
||||
</div>
|
||||
<a href="#" rel="tooltip" data-placement="right" data-original-title="{{=T('Type some Python code in here and hit Return (Enter) to execute it.')}}">
|
||||
{{=helpicon()}}
|
||||
<span>Type some Python code in here and hit Return (Enter) to execute it.</span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="caret"><span>>>></span></div>
|
||||
<div id="autoscroll">autoscroll</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="row-fluid clearfix">
|
||||
<div class="help alert alert-info span6">
|
||||
<ul>
|
||||
<li>Using the shell may lock the database to other users of this app.</li>
|
||||
<li>Each db statement is automatically committed.</li>
|
||||
<li>Creating new tables dynamically is not allowed.</li>
|
||||
<li>Models are automatically imported in the shell.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript" src="{{=URL('static', 'js/autoscroll.js')}}"></script>
|
||||
|
||||
@@ -113,4 +114,4 @@ jQuery(document).ready(function(){
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<!-- end "shell" block -->
|
||||
<!-- end "shell" block -->
|
||||
|
||||
@@ -16,6 +16,8 @@ try:
|
||||
except ImportError:
|
||||
pgv = None
|
||||
|
||||
is_gae = request.env.web2py_runtime_gae or False
|
||||
|
||||
# ## critical --- make a copy of the environment
|
||||
|
||||
global_env = copy.copy(globals())
|
||||
@@ -359,36 +361,43 @@ def state():
|
||||
|
||||
|
||||
def ccache():
|
||||
cache.ram.initialize()
|
||||
cache.disk.initialize()
|
||||
if is_gae:
|
||||
form = FORM(
|
||||
P(TAG.BUTTON(T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")))
|
||||
else:
|
||||
cache.ram.initialize()
|
||||
cache.disk.initialize()
|
||||
|
||||
form = FORM(
|
||||
P(TAG.BUTTON(
|
||||
T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
|
||||
P(TAG.BUTTON(
|
||||
T("Clear RAM"), _type="submit", _name="ram", _value="ram")),
|
||||
P(TAG.BUTTON(
|
||||
T("Clear DISK"), _type="submit", _name="disk", _value="disk")),
|
||||
)
|
||||
form = FORM(
|
||||
P(TAG.BUTTON(
|
||||
T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
|
||||
P(TAG.BUTTON(
|
||||
T("Clear RAM"), _type="submit", _name="ram", _value="ram")),
|
||||
P(TAG.BUTTON(
|
||||
T("Clear DISK"), _type="submit", _name="disk", _value="disk")),
|
||||
)
|
||||
|
||||
if form.accepts(request.vars, session):
|
||||
clear_ram = False
|
||||
clear_disk = False
|
||||
session.flash = ""
|
||||
if request.vars.yes:
|
||||
clear_ram = clear_disk = True
|
||||
if request.vars.ram:
|
||||
clear_ram = True
|
||||
if request.vars.disk:
|
||||
clear_disk = True
|
||||
|
||||
if clear_ram:
|
||||
cache.ram.clear()
|
||||
session.flash += T("Ram Cleared")
|
||||
if clear_disk:
|
||||
cache.disk.clear()
|
||||
session.flash += T("Disk Cleared")
|
||||
|
||||
if is_gae:
|
||||
if request.vars.yes:
|
||||
cache.ram.clear()
|
||||
session.flash += T("Cache Cleared")
|
||||
else:
|
||||
clear_ram = False
|
||||
clear_disk = False
|
||||
if request.vars.yes:
|
||||
clear_ram = clear_disk = True
|
||||
if request.vars.ram:
|
||||
clear_ram = True
|
||||
if request.vars.disk:
|
||||
clear_disk = True
|
||||
if clear_ram:
|
||||
cache.ram.clear()
|
||||
session.flash += T("Ram Cleared")
|
||||
if clear_disk:
|
||||
cache.disk.clear()
|
||||
session.flash += T("Disk Cleared")
|
||||
redirect(URL(r=request))
|
||||
|
||||
try:
|
||||
@@ -414,6 +423,7 @@ def ccache():
|
||||
'oldest': time.time(),
|
||||
'keys': []
|
||||
}
|
||||
|
||||
disk = copy.copy(ram)
|
||||
total = copy.copy(ram)
|
||||
disk['keys'] = []
|
||||
@@ -428,72 +438,81 @@ def ccache():
|
||||
|
||||
return (hours, minutes, seconds)
|
||||
|
||||
for key, value in cache.ram.storage.iteritems():
|
||||
if isinstance(value, dict):
|
||||
ram['hits'] = value['hit_total'] - value['misses']
|
||||
ram['misses'] = value['misses']
|
||||
try:
|
||||
ram['ratio'] = ram['hits'] * 100 / value['hit_total']
|
||||
except (KeyError, ZeroDivisionError):
|
||||
ram['ratio'] = 0
|
||||
else:
|
||||
if hp:
|
||||
ram['bytes'] += hp.iso(value[1]).size
|
||||
ram['objects'] += hp.iso(value[1]).count
|
||||
ram['entries'] += 1
|
||||
if value[0] < ram['oldest']:
|
||||
ram['oldest'] = value[0]
|
||||
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
|
||||
folder = os.path.join(request.folder,'cache')
|
||||
if not os.path.exists(folder):
|
||||
os.mkdir(folder)
|
||||
locker = open(os.path.join(folder, 'cache.lock'), 'a')
|
||||
portalocker.lock(locker, portalocker.LOCK_EX)
|
||||
disk_storage = shelve.open(
|
||||
os.path.join(folder, 'cache.shelve'))
|
||||
try:
|
||||
for key, value in disk_storage.items():
|
||||
if is_gae:
|
||||
gae_stats = cache.ram.client.get_stats()
|
||||
try:
|
||||
gae_stats['ratio'] = ((gae_stats['hits'] * 100) /
|
||||
(gae_stats['hits'] + gae_stats['misses']))
|
||||
except ZeroDivisionError:
|
||||
gae_stats['ratio'] = T("?")
|
||||
gae_stats['oldest'] = GetInHMS(time.time() - gae_stats['oldest_item_age'])
|
||||
total.update(gae_stats)
|
||||
else:
|
||||
for key, value in cache.ram.storage.iteritems():
|
||||
if isinstance(value, dict):
|
||||
disk['hits'] = value['hit_total'] - value['misses']
|
||||
disk['misses'] = value['misses']
|
||||
ram['hits'] = value['hit_total'] - value['misses']
|
||||
ram['misses'] = value['misses']
|
||||
try:
|
||||
disk['ratio'] = disk['hits'] * 100 / value['hit_total']
|
||||
ram['ratio'] = ram['hits'] * 100 / value['hit_total']
|
||||
except (KeyError, ZeroDivisionError):
|
||||
disk['ratio'] = 0
|
||||
ram['ratio'] = 0
|
||||
else:
|
||||
if hp:
|
||||
disk['bytes'] += hp.iso(value[1]).size
|
||||
disk['objects'] += hp.iso(value[1]).count
|
||||
disk['entries'] += 1
|
||||
if value[0] < disk['oldest']:
|
||||
disk['oldest'] = value[0]
|
||||
disk['keys'].append((key, GetInHMS(time.time() - value[0])))
|
||||
ram['bytes'] += hp.iso(value[1]).size
|
||||
ram['objects'] += hp.iso(value[1]).count
|
||||
ram['entries'] += 1
|
||||
if value[0] < ram['oldest']:
|
||||
ram['oldest'] = value[0]
|
||||
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
|
||||
folder = os.path.join(request.folder,'cache')
|
||||
if not os.path.exists(folder):
|
||||
os.mkdir(folder)
|
||||
locker = open(os.path.join(folder, 'cache.lock'), 'a')
|
||||
portalocker.lock(locker, portalocker.LOCK_EX)
|
||||
disk_storage = shelve.open(
|
||||
os.path.join(folder, 'cache.shelve'))
|
||||
try:
|
||||
for key, value in disk_storage.items():
|
||||
if isinstance(value, dict):
|
||||
disk['hits'] = value['hit_total'] - value['misses']
|
||||
disk['misses'] = value['misses']
|
||||
try:
|
||||
disk['ratio'] = disk['hits'] * 100 / value['hit_total']
|
||||
except (KeyError, ZeroDivisionError):
|
||||
disk['ratio'] = 0
|
||||
else:
|
||||
if hp:
|
||||
disk['bytes'] += hp.iso(value[1]).size
|
||||
disk['objects'] += hp.iso(value[1]).count
|
||||
disk['entries'] += 1
|
||||
if value[0] < disk['oldest']:
|
||||
disk['oldest'] = value[0]
|
||||
disk['keys'].append((key, GetInHMS(time.time() - value[0])))
|
||||
finally:
|
||||
portalocker.unlock(locker)
|
||||
locker.close()
|
||||
disk_storage.close()
|
||||
|
||||
finally:
|
||||
portalocker.unlock(locker)
|
||||
locker.close()
|
||||
disk_storage.close()
|
||||
|
||||
total['entries'] = ram['entries'] + disk['entries']
|
||||
total['bytes'] = ram['bytes'] + disk['bytes']
|
||||
total['objects'] = ram['objects'] + disk['objects']
|
||||
total['hits'] = ram['hits'] + disk['hits']
|
||||
total['misses'] = ram['misses'] + disk['misses']
|
||||
total['keys'] = ram['keys'] + disk['keys']
|
||||
try:
|
||||
total['ratio'] = total['hits'] * 100 / (total['hits'] +
|
||||
total['entries'] = ram['entries'] + disk['entries']
|
||||
total['bytes'] = ram['bytes'] + disk['bytes']
|
||||
total['objects'] = ram['objects'] + disk['objects']
|
||||
total['hits'] = ram['hits'] + disk['hits']
|
||||
total['misses'] = ram['misses'] + disk['misses']
|
||||
total['keys'] = ram['keys'] + disk['keys']
|
||||
try:
|
||||
total['ratio'] = total['hits'] * 100 / (total['hits'] +
|
||||
total['misses'])
|
||||
except (KeyError, ZeroDivisionError):
|
||||
total['ratio'] = 0
|
||||
except (KeyError, ZeroDivisionError):
|
||||
total['ratio'] = 0
|
||||
|
||||
if disk['oldest'] < ram['oldest']:
|
||||
total['oldest'] = disk['oldest']
|
||||
else:
|
||||
total['oldest'] = ram['oldest']
|
||||
if disk['oldest'] < ram['oldest']:
|
||||
total['oldest'] = disk['oldest']
|
||||
else:
|
||||
total['oldest'] = ram['oldest']
|
||||
|
||||
ram['oldest'] = GetInHMS(time.time() - ram['oldest'])
|
||||
disk['oldest'] = GetInHMS(time.time() - disk['oldest'])
|
||||
total['oldest'] = GetInHMS(time.time() - total['oldest'])
|
||||
ram['oldest'] = GetInHMS(time.time() - ram['oldest'])
|
||||
disk['oldest'] = GetInHMS(time.time() - disk['oldest'])
|
||||
total['oldest'] = GetInHMS(time.time() - total['oldest'])
|
||||
|
||||
def key_table(keys):
|
||||
return TABLE(
|
||||
@@ -502,9 +521,10 @@ def ccache():
|
||||
**dict(_class='cache-keys',
|
||||
_style="border-collapse: separate; border-spacing: .5em;"))
|
||||
|
||||
ram['keys'] = key_table(ram['keys'])
|
||||
disk['keys'] = key_table(disk['keys'])
|
||||
total['keys'] = key_table(total['keys'])
|
||||
if not is_gae:
|
||||
ram['keys'] = key_table(ram['keys'])
|
||||
disk['keys'] = key_table(disk['keys'])
|
||||
total['keys'] = key_table(total['keys'])
|
||||
|
||||
return dict(form=form, total=total,
|
||||
ram=ram, disk=disk, object_stats=hp != False)
|
||||
|
||||
53
applications/examples/controllers/soap_examples.py
Normal file
53
applications/examples/controllers/soap_examples.py
Normal file
@@ -0,0 +1,53 @@
|
||||
# coding: utf8
|
||||
|
||||
# SOAP webservices (server and client) example and basic test
|
||||
# (using pysimplesoap contrib included in web2py)
|
||||
# for more info see: https://code.google.com/p/pysimplesoap/wiki/Web2Py
|
||||
|
||||
from gluon.tools import Service
|
||||
service = Service(globals())
|
||||
|
||||
# define the procedures to be exposed:
|
||||
|
||||
@service.soap('AddStrings', returns={'AddResult': str}, args={'a': str, 'b': str})
|
||||
@service.soap('AddIntegers', returns={'AddResult': int}, args={'a': int, 'b': int})
|
||||
def add(a, b):
|
||||
"Add two values"
|
||||
return a+b
|
||||
|
||||
@service.soap('SubIntegers', returns={'SubResult': int}, args={'a': int, 'b': int})
|
||||
def sub(a, b):
|
||||
"Substract two values"
|
||||
return a-b
|
||||
|
||||
@service.soap('Division', returns={'divisionResult': float}, args={'a': float, 'b': float})
|
||||
def division(a, b):
|
||||
"Divide two values "
|
||||
return a / b
|
||||
|
||||
|
||||
# expose the soap methods
|
||||
|
||||
def call():
|
||||
return service()
|
||||
|
||||
# sample function to test the SOAP RPC
|
||||
|
||||
def test_soap_sub():
|
||||
from gluon.contrib.pysimplesoap.client import SoapClient, SoapFault
|
||||
# build the url to the WSDL (web service description)
|
||||
# like "http://localhost:8000/webservices/sample/call/soap?WSDL"
|
||||
url = URL(f="call/soap", vars={"WSDL": ""}, scheme=True)
|
||||
# create a SOAP client
|
||||
client = SoapClient(wsdl=url)
|
||||
# call the SOAP remote method
|
||||
try:
|
||||
ret = client.SubIntegers(a=3, b=2)
|
||||
result = ret['SubResult']
|
||||
except SoapFault, sf:
|
||||
result = sf
|
||||
response.view = "soap_examples/generic.html"
|
||||
return dict(xml_request=client.xml_request,
|
||||
xml_response=client.xml_response,
|
||||
result=result)
|
||||
|
||||
@@ -13,4 +13,8 @@ body {
|
||||
}
|
||||
.btn-180 {
|
||||
width: 180px;
|
||||
}
|
||||
}
|
||||
.page-header {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
@@ -75,8 +75,8 @@
|
||||
* this over and over... all will be bound to the document
|
||||
*/
|
||||
/*adds btn class to buttons*/
|
||||
$('button', target).addClass('btn');
|
||||
$('form input[type="submit"], form input[type="button"]', target).addClass('btn');
|
||||
$('button', target).addClass('btn').addClass('btn-default');
|
||||
$('form input[type="submit"], form input[type="button"]', target).addClass('btn').addClass('btn-default');
|
||||
/* javascript for PasswordWidget*/
|
||||
$('input[type=password][data-w2p_entropy]', target).each(function () {
|
||||
web2py.validate_entropy($(this));
|
||||
@@ -485,8 +485,10 @@
|
||||
el.addClass('disabled');
|
||||
var method = el.prop('type') == 'submit' ? 'val' : 'html';
|
||||
var disable_with_message = (typeof w2p_ajax_disable_with_message != 'undefined') ? w2p_ajax_disable_with_message : "Working...";
|
||||
/*store enabled state*/
|
||||
el.data('w2p:enable-with', el[method]());
|
||||
/*store enabled state if not already disabled */
|
||||
if (el.data('w2p:enable-with') === undefined) {
|
||||
el.data('w2p:enable-with', el[method]());
|
||||
}
|
||||
/*if you don't want to see "working..." on buttons, replace the following
|
||||
* two lines with this one
|
||||
* el.data('w2p_disable_with', el[method]());
|
||||
@@ -633,7 +635,9 @@
|
||||
if(disable_with == undefined) {
|
||||
element.data('w2p_disable_with', element[method]())
|
||||
}
|
||||
element.data('w2p:enable-with', element[method]());
|
||||
if (element.data('w2p:enable-with') === undefined) {
|
||||
element.data('w2p:enable-with', element[method]());
|
||||
}
|
||||
element[method](element.data('w2p_disable_with'));
|
||||
element.prop('disabled', true);
|
||||
});
|
||||
@@ -647,7 +651,10 @@
|
||||
form.find(web2py.enableSelector).each(function () {
|
||||
var element = $(this),
|
||||
method = element.is('button') ? 'html' : 'val';
|
||||
if(element.data('w2p:enable-with')) element[method](element.data('w2p:enable-with'));
|
||||
if(element.data('w2p:enable-with')) {
|
||||
element[method](element.data('w2p:enable-with'));
|
||||
element.removeData('w2p:enable-with');
|
||||
}
|
||||
element.prop('disabled', false);
|
||||
});
|
||||
},
|
||||
@@ -659,7 +666,18 @@
|
||||
el.on('ajax:complete', 'form[data-w2p_target]', function (e) {
|
||||
web2py.enableFormElements($(this));
|
||||
});
|
||||
}
|
||||
},
|
||||
/* Invalidate and force reload of a web2py component
|
||||
*/
|
||||
invalidate: function(target) {
|
||||
$('div[data-w2p_remote]', target).each(function () {
|
||||
var el = $('#' + $(this).attr('id')).get(0);
|
||||
if (el.timing !== undefined) { // Block triggering regular routines
|
||||
clearInterval(el.timing);
|
||||
}
|
||||
});
|
||||
$.web2py.component_handler(target);
|
||||
},
|
||||
}
|
||||
|
||||
/*end of functions */
|
||||
@@ -679,7 +697,7 @@
|
||||
/* compatibility code - start */
|
||||
ajax = jQuery.web2py.ajax;
|
||||
web2py_component = jQuery.web2py.component;
|
||||
web2py_websocket = jQuery.web2py.websocket;
|
||||
web2py_websocket = jQuery.web2py.web2py_websocket;
|
||||
web2py_ajax_page = jQuery.web2py.ajax_page;
|
||||
/*needed for IS_STRONG(entropy)*/
|
||||
web2py_validate_entropy = jQuery.web2py.validate_entropy;
|
||||
|
||||
@@ -20,14 +20,14 @@ jQuery(function(){
|
||||
function hoverMenu(){
|
||||
jQuery('ul.nav a.dropdown-toggle').parent().hover(function(){
|
||||
adjust_height_of_collapsed_nav();
|
||||
mi = jQuery(this).addClass('open');
|
||||
var mi = jQuery(this).addClass('open');
|
||||
mi.children('.dropdown-menu').stop(true, true).delay(200).fadeIn(400);
|
||||
}, function(){
|
||||
mi = jQuery(this);
|
||||
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');});
|
||||
});
|
||||
});
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -43,7 +43,8 @@ random.shuffle(quotes)
|
||||
<a href="http://www.infoworld.com/slideshow/24605/infoworlds-2012-technology-of-the-year-award-winners-183313#slide23"><img src="{{=URL('static','images/infoworld2012.jpeg')}}" width="200px"/></a><br/>
|
||||
<a class="btn btn-danger" href="{{=URL('download')}}" style="margin-top:10px; width:180px; color:white">Download Now</a><br/>
|
||||
<a class="btn btn-danger" href="https://www.pythonanywhere.com/try-web2py" style="margin-top:10px; width:180px; color:white">Try it now online</a><br/>
|
||||
<a class="btn btn-danger" href="http://web2py.com/poweredby" style="margin-top:10px; width:180px; color:white">Sites Powered by web2py</a>
|
||||
<a class="btn btn-danger" href="http://web2py.com/poweredby" style="margin-top:10px; width:180px; color:white">Sites Powered by web2py</a><br/><br/>
|
||||
<a class="coinbase-button" data-code="df71ec5c2d5bc3b1c18139ab645f352b" data-button-style="donation_large" href="https://coinbase.com/checkouts/df71ec5c2d5bc3b1c18139ab645f352b">Donate Bitcoins</a><script src="https://coinbase.com/assets/button.js" type="text/javascript"></script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
8
applications/examples/views/soap_examples/generic.html
Normal file
8
applications/examples/views/soap_examples/generic.html
Normal file
@@ -0,0 +1,8 @@
|
||||
{{extend 'layout.html'}}
|
||||
<h1>SOAP Examples</h1>
|
||||
<h2>Result</h2>
|
||||
{{=BEAUTIFY(result)}}
|
||||
<h2>XML Request</h2>
|
||||
{{=BEAUTIFY(xml_request)}}
|
||||
<h2>XML Response</h2>
|
||||
{{=BEAUTIFY(xml_response)}}
|
||||
@@ -16,6 +16,8 @@ try:
|
||||
except ImportError:
|
||||
pgv = None
|
||||
|
||||
is_gae = request.env.web2py_runtime_gae or False
|
||||
|
||||
# ## critical --- make a copy of the environment
|
||||
|
||||
global_env = copy.copy(globals())
|
||||
@@ -359,36 +361,43 @@ def state():
|
||||
|
||||
|
||||
def ccache():
|
||||
cache.ram.initialize()
|
||||
cache.disk.initialize()
|
||||
if is_gae:
|
||||
form = FORM(
|
||||
P(TAG.BUTTON(T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")))
|
||||
else:
|
||||
cache.ram.initialize()
|
||||
cache.disk.initialize()
|
||||
|
||||
form = FORM(
|
||||
P(TAG.BUTTON(
|
||||
T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
|
||||
P(TAG.BUTTON(
|
||||
T("Clear RAM"), _type="submit", _name="ram", _value="ram")),
|
||||
P(TAG.BUTTON(
|
||||
T("Clear DISK"), _type="submit", _name="disk", _value="disk")),
|
||||
)
|
||||
form = FORM(
|
||||
P(TAG.BUTTON(
|
||||
T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
|
||||
P(TAG.BUTTON(
|
||||
T("Clear RAM"), _type="submit", _name="ram", _value="ram")),
|
||||
P(TAG.BUTTON(
|
||||
T("Clear DISK"), _type="submit", _name="disk", _value="disk")),
|
||||
)
|
||||
|
||||
if form.accepts(request.vars, session):
|
||||
clear_ram = False
|
||||
clear_disk = False
|
||||
session.flash = ""
|
||||
if request.vars.yes:
|
||||
clear_ram = clear_disk = True
|
||||
if request.vars.ram:
|
||||
clear_ram = True
|
||||
if request.vars.disk:
|
||||
clear_disk = True
|
||||
|
||||
if clear_ram:
|
||||
cache.ram.clear()
|
||||
session.flash += T("Ram Cleared")
|
||||
if clear_disk:
|
||||
cache.disk.clear()
|
||||
session.flash += T("Disk Cleared")
|
||||
|
||||
if is_gae:
|
||||
if request.vars.yes:
|
||||
cache.ram.clear()
|
||||
session.flash += T("Cache Cleared")
|
||||
else:
|
||||
clear_ram = False
|
||||
clear_disk = False
|
||||
if request.vars.yes:
|
||||
clear_ram = clear_disk = True
|
||||
if request.vars.ram:
|
||||
clear_ram = True
|
||||
if request.vars.disk:
|
||||
clear_disk = True
|
||||
if clear_ram:
|
||||
cache.ram.clear()
|
||||
session.flash += T("Ram Cleared")
|
||||
if clear_disk:
|
||||
cache.disk.clear()
|
||||
session.flash += T("Disk Cleared")
|
||||
redirect(URL(r=request))
|
||||
|
||||
try:
|
||||
@@ -414,6 +423,7 @@ def ccache():
|
||||
'oldest': time.time(),
|
||||
'keys': []
|
||||
}
|
||||
|
||||
disk = copy.copy(ram)
|
||||
total = copy.copy(ram)
|
||||
disk['keys'] = []
|
||||
@@ -428,72 +438,81 @@ def ccache():
|
||||
|
||||
return (hours, minutes, seconds)
|
||||
|
||||
for key, value in cache.ram.storage.iteritems():
|
||||
if isinstance(value, dict):
|
||||
ram['hits'] = value['hit_total'] - value['misses']
|
||||
ram['misses'] = value['misses']
|
||||
try:
|
||||
ram['ratio'] = ram['hits'] * 100 / value['hit_total']
|
||||
except (KeyError, ZeroDivisionError):
|
||||
ram['ratio'] = 0
|
||||
else:
|
||||
if hp:
|
||||
ram['bytes'] += hp.iso(value[1]).size
|
||||
ram['objects'] += hp.iso(value[1]).count
|
||||
ram['entries'] += 1
|
||||
if value[0] < ram['oldest']:
|
||||
ram['oldest'] = value[0]
|
||||
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
|
||||
folder = os.path.join(request.folder,'cache')
|
||||
if not os.path.exists(folder):
|
||||
os.mkdir(folder)
|
||||
locker = open(os.path.join(folder, 'cache.lock'), 'a')
|
||||
portalocker.lock(locker, portalocker.LOCK_EX)
|
||||
disk_storage = shelve.open(
|
||||
os.path.join(folder, 'cache.shelve'))
|
||||
try:
|
||||
for key, value in disk_storage.items():
|
||||
if is_gae:
|
||||
gae_stats = cache.ram.client.get_stats()
|
||||
try:
|
||||
gae_stats['ratio'] = ((gae_stats['hits'] * 100) /
|
||||
(gae_stats['hits'] + gae_stats['misses']))
|
||||
except ZeroDivisionError:
|
||||
gae_stats['ratio'] = T("?")
|
||||
gae_stats['oldest'] = GetInHMS(time.time() - gae_stats['oldest_item_age'])
|
||||
total.update(gae_stats)
|
||||
else:
|
||||
for key, value in cache.ram.storage.iteritems():
|
||||
if isinstance(value, dict):
|
||||
disk['hits'] = value['hit_total'] - value['misses']
|
||||
disk['misses'] = value['misses']
|
||||
ram['hits'] = value['hit_total'] - value['misses']
|
||||
ram['misses'] = value['misses']
|
||||
try:
|
||||
disk['ratio'] = disk['hits'] * 100 / value['hit_total']
|
||||
ram['ratio'] = ram['hits'] * 100 / value['hit_total']
|
||||
except (KeyError, ZeroDivisionError):
|
||||
disk['ratio'] = 0
|
||||
ram['ratio'] = 0
|
||||
else:
|
||||
if hp:
|
||||
disk['bytes'] += hp.iso(value[1]).size
|
||||
disk['objects'] += hp.iso(value[1]).count
|
||||
disk['entries'] += 1
|
||||
if value[0] < disk['oldest']:
|
||||
disk['oldest'] = value[0]
|
||||
disk['keys'].append((key, GetInHMS(time.time() - value[0])))
|
||||
ram['bytes'] += hp.iso(value[1]).size
|
||||
ram['objects'] += hp.iso(value[1]).count
|
||||
ram['entries'] += 1
|
||||
if value[0] < ram['oldest']:
|
||||
ram['oldest'] = value[0]
|
||||
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
|
||||
folder = os.path.join(request.folder,'cache')
|
||||
if not os.path.exists(folder):
|
||||
os.mkdir(folder)
|
||||
locker = open(os.path.join(folder, 'cache.lock'), 'a')
|
||||
portalocker.lock(locker, portalocker.LOCK_EX)
|
||||
disk_storage = shelve.open(
|
||||
os.path.join(folder, 'cache.shelve'))
|
||||
try:
|
||||
for key, value in disk_storage.items():
|
||||
if isinstance(value, dict):
|
||||
disk['hits'] = value['hit_total'] - value['misses']
|
||||
disk['misses'] = value['misses']
|
||||
try:
|
||||
disk['ratio'] = disk['hits'] * 100 / value['hit_total']
|
||||
except (KeyError, ZeroDivisionError):
|
||||
disk['ratio'] = 0
|
||||
else:
|
||||
if hp:
|
||||
disk['bytes'] += hp.iso(value[1]).size
|
||||
disk['objects'] += hp.iso(value[1]).count
|
||||
disk['entries'] += 1
|
||||
if value[0] < disk['oldest']:
|
||||
disk['oldest'] = value[0]
|
||||
disk['keys'].append((key, GetInHMS(time.time() - value[0])))
|
||||
finally:
|
||||
portalocker.unlock(locker)
|
||||
locker.close()
|
||||
disk_storage.close()
|
||||
|
||||
finally:
|
||||
portalocker.unlock(locker)
|
||||
locker.close()
|
||||
disk_storage.close()
|
||||
|
||||
total['entries'] = ram['entries'] + disk['entries']
|
||||
total['bytes'] = ram['bytes'] + disk['bytes']
|
||||
total['objects'] = ram['objects'] + disk['objects']
|
||||
total['hits'] = ram['hits'] + disk['hits']
|
||||
total['misses'] = ram['misses'] + disk['misses']
|
||||
total['keys'] = ram['keys'] + disk['keys']
|
||||
try:
|
||||
total['ratio'] = total['hits'] * 100 / (total['hits'] +
|
||||
total['entries'] = ram['entries'] + disk['entries']
|
||||
total['bytes'] = ram['bytes'] + disk['bytes']
|
||||
total['objects'] = ram['objects'] + disk['objects']
|
||||
total['hits'] = ram['hits'] + disk['hits']
|
||||
total['misses'] = ram['misses'] + disk['misses']
|
||||
total['keys'] = ram['keys'] + disk['keys']
|
||||
try:
|
||||
total['ratio'] = total['hits'] * 100 / (total['hits'] +
|
||||
total['misses'])
|
||||
except (KeyError, ZeroDivisionError):
|
||||
total['ratio'] = 0
|
||||
except (KeyError, ZeroDivisionError):
|
||||
total['ratio'] = 0
|
||||
|
||||
if disk['oldest'] < ram['oldest']:
|
||||
total['oldest'] = disk['oldest']
|
||||
else:
|
||||
total['oldest'] = ram['oldest']
|
||||
if disk['oldest'] < ram['oldest']:
|
||||
total['oldest'] = disk['oldest']
|
||||
else:
|
||||
total['oldest'] = ram['oldest']
|
||||
|
||||
ram['oldest'] = GetInHMS(time.time() - ram['oldest'])
|
||||
disk['oldest'] = GetInHMS(time.time() - disk['oldest'])
|
||||
total['oldest'] = GetInHMS(time.time() - total['oldest'])
|
||||
ram['oldest'] = GetInHMS(time.time() - ram['oldest'])
|
||||
disk['oldest'] = GetInHMS(time.time() - disk['oldest'])
|
||||
total['oldest'] = GetInHMS(time.time() - total['oldest'])
|
||||
|
||||
def key_table(keys):
|
||||
return TABLE(
|
||||
@@ -502,9 +521,10 @@ def ccache():
|
||||
**dict(_class='cache-keys',
|
||||
_style="border-collapse: separate; border-spacing: .5em;"))
|
||||
|
||||
ram['keys'] = key_table(ram['keys'])
|
||||
disk['keys'] = key_table(disk['keys'])
|
||||
total['keys'] = key_table(total['keys'])
|
||||
if not is_gae:
|
||||
ram['keys'] = key_table(ram['keys'])
|
||||
disk['keys'] = key_table(disk['keys'])
|
||||
total['keys'] = key_table(total['keys'])
|
||||
|
||||
return dict(form=form, total=total,
|
||||
ram=ram, disk=disk, object_stats=hp != False)
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
# coding: utf-8
|
||||
# -*- coding: utf-8 -*-
|
||||
{
|
||||
'!langcode!': 'es',
|
||||
'!langname!': 'Español',
|
||||
'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"actualice" es una expresión opcional como "campo1=\'nuevo_valor\'". No se puede actualizar o eliminar resultados de un JOIN',
|
||||
'%(nrows)s records found': '%(nrows)s registros encontrados',
|
||||
'%s %%{position}': '%s %%{posición}',
|
||||
'%s %%{row} deleted': '%s %%{fila} %%{eliminada}',
|
||||
'%s %%{row} updated': '%s %%{fila} %%{actualizada}',
|
||||
'%s selected': '%s %%{seleccionado}',
|
||||
@@ -10,12 +12,14 @@
|
||||
'%Y-%m-%d %H:%M:%S': '%d/%m/%Y %H:%M:%S',
|
||||
'(something like "it-it")': '(algo como "eso-eso")',
|
||||
'@markmin\x01An error occured, please [[reload %s]] the page': 'Ha ocurrido un error, por favor [[recargar %s]] la página',
|
||||
'@markmin\x01Number of entries: **%s**': 'Número de entradas: **%s**',
|
||||
'A new version of web2py is available': 'Hay una nueva versión de web2py disponible',
|
||||
'A new version of web2py is available: %s': 'Hay una nueva versión de web2py disponible: %s',
|
||||
'About': 'Acerca de',
|
||||
'about': 'acerca de',
|
||||
'About application': 'Acerca de la aplicación',
|
||||
'Access Control': 'Control de Acceso',
|
||||
'Add': 'Añadir',
|
||||
'additional code for your application': 'código adicional para su aplicación',
|
||||
'admin disabled because no admin password': 'admin deshabilitado por falta de contraseña',
|
||||
'admin disabled because not supported on google app engine': 'admin deshabilitado, no es soportado en GAE',
|
||||
@@ -27,30 +31,34 @@
|
||||
'Administrator Password:': 'Contraseña del Administrador:',
|
||||
'Ajax Recipes': 'Recetas AJAX',
|
||||
'An error occured, please %s the page': 'Ha ocurrido un error, por favor %s la página',
|
||||
'And': 'Y',
|
||||
'and rename it (required):': 'y renómbrela (requerido):',
|
||||
'and rename it:': ' y renómbrelo:',
|
||||
'Aplicar cambios': 'Aplicar cambios',
|
||||
'appadmin': 'appadmin',
|
||||
'appadmin is disabled because insecure channel': 'admin deshabilitado, el canal no es seguro',
|
||||
'application "%s" uninstalled': 'aplicación "%s" desinstalada',
|
||||
'application compiled': 'aplicación compilada',
|
||||
'application is compiled and cannot be designed': 'la aplicación está compilada y no puede ser modificada',
|
||||
'Apply changes': 'Aplicar cambios',
|
||||
'Appointment': 'Nombramiento',
|
||||
'Are you sure you want to delete file "%s"?': '¿Está seguro que desea eliminar el archivo "%s"?',
|
||||
'Are you sure you want to delete this object?': '¿Está seguro que desea borrar este objeto?',
|
||||
'Are you sure you want to uninstall application "%s"': '¿Está seguro que desea desinstalar la aplicación "%s"',
|
||||
'Are you sure you want to uninstall application "%s"?': '¿Está seguro que desea desinstalar la aplicación "%s"?',
|
||||
'at': 'en',
|
||||
'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ATENCION: Inicio de sesión requiere una conexión segura (HTTPS) o localhost.',
|
||||
'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATENCION: NO EJECUTE VARIAS PRUEBAS SIMULTANEAMENTE, NO SON THREAD SAFE.',
|
||||
'ATTENTION: you cannot edit the running application!': 'ATENCION: no puede modificar la aplicación que está ejecutandose!',
|
||||
'Authentication': 'Autenticación',
|
||||
'Authentication failed at client DB!': '¡La autenticación ha fallado en la BDD cliente!',
|
||||
'Authentication failed at main DB!': '¡La autenticación ha fallado en la BDD principal!',
|
||||
'Available Databases and Tables': 'Bases de datos y tablas disponibles',
|
||||
'Back': 'Atrás',
|
||||
'Buy this book': 'Compra este libro',
|
||||
'Cache': 'Caché',
|
||||
'cache': 'caché',
|
||||
'Cache Keys': 'Llaves de la Caché',
|
||||
'cache, errors and sessions cleaned': 'caché, errores y sesiones eliminados',
|
||||
'Cambie la contraseña': 'Cambie la contraseña',
|
||||
'Cannot be empty': 'No puede estar vacío',
|
||||
'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': 'No se puede compilar: hay errores en su aplicación. Depure, corrija errores y vuelva a intentarlo.',
|
||||
'cannot create file': 'no es posible crear archivo',
|
||||
@@ -60,28 +68,32 @@
|
||||
'change password': 'cambie la contraseña',
|
||||
'check all': 'marcar todos',
|
||||
'Check to delete': 'Marque para eliminar',
|
||||
'choose one': 'escoja uno',
|
||||
'clean': 'limpiar',
|
||||
'Clear': 'Limpiar',
|
||||
'Clear CACHE?': '¿Limpiar CACHÉ?',
|
||||
'Clear DISK': 'Limpiar DISCO',
|
||||
'Clear RAM': 'Limpiar RAM',
|
||||
'Click on the link %(link)s to reset your password': 'Pulse en el enlace %(link)s para reiniciar su contraseña',
|
||||
'click to check for upgrades': 'haga clic para buscar actualizaciones',
|
||||
'client': 'cliente',
|
||||
'Client IP': 'IP del Cliente',
|
||||
'Close': 'Cerrar',
|
||||
'Community': 'Comunidad',
|
||||
'compile': 'compilar',
|
||||
'compiled application removed': 'aplicación compilada eliminada',
|
||||
'Components and Plugins': 'Componentes y Plugins',
|
||||
'contains': 'contiene',
|
||||
'Controller': 'Controlador',
|
||||
'Controllers': 'Controladores',
|
||||
'controllers': 'controladores',
|
||||
'Copyright': 'Copyright',
|
||||
'Correo electrónico inválido': 'Correo electrónico inválido',
|
||||
'create file with filename:': 'cree archivo con nombre:',
|
||||
'Create new application': 'Cree una nueva aplicación',
|
||||
'create new application:': 'nombre de la nueva aplicación:',
|
||||
'Created By': 'Creado Por',
|
||||
'Created On': 'Creado En',
|
||||
'crontab': 'crontab',
|
||||
'CSV (hidden cols)': 'CSV (columnas ocultas)',
|
||||
'Current request': 'Solicitud en curso',
|
||||
'Current response': 'Respuesta en curso',
|
||||
'Current session': 'Sesión en curso',
|
||||
@@ -90,8 +102,10 @@
|
||||
'data uploaded': 'datos subidos',
|
||||
'Database': 'Base de datos',
|
||||
'Database %s select': 'selección en base de datos %s',
|
||||
'database administration': 'administración base de datos',
|
||||
'database administration': 'administración de base de datos',
|
||||
'Database Administration (appadmin)': 'Administración de Base de Datos (appadmin)',
|
||||
'Date and Time': 'Fecha y Hora',
|
||||
'DB': 'BDD',
|
||||
'db': 'bdd',
|
||||
'DB Model': 'Modelo BDD',
|
||||
'defines tables': 'define tablas',
|
||||
@@ -106,6 +120,7 @@
|
||||
'design': 'diseño',
|
||||
'DESIGN': 'DISEÑO',
|
||||
'Design for': 'Diseño por',
|
||||
'detecting': 'detectando',
|
||||
'DISK': 'DISCO',
|
||||
'Disk Cache Keys': 'Llaves de Caché en Disco',
|
||||
'Disk Cleared': 'Disco limpiado',
|
||||
@@ -127,13 +142,17 @@
|
||||
'Editing file "%s"': 'Editando archivo "%s"',
|
||||
'Email and SMS': 'Correo electrónico y SMS',
|
||||
'Email sent': 'Correo electrónico enviado',
|
||||
'End of impersonation': 'Fin de suplantación',
|
||||
'enter a number between %(min)g and %(max)g': 'introduzca un número entre %(min)g y %(max)g',
|
||||
'enter a value': 'introduzca un valor',
|
||||
'enter an integer between %(min)g and %(max)g': 'introduzca un entero entre %(min)g y %(max)g',
|
||||
'enter date and time as %(format)s': 'introduzca fecha y hora como %(format)s',
|
||||
'Error logs for "%(app)s"': 'Bitácora de errores en "%(app)s"',
|
||||
'errors': 'errores',
|
||||
'Errors': 'Errores',
|
||||
'Errors in form, please check it out.': 'Hay errores en el formulario, por favor comprúebelo.',
|
||||
'export as csv file': 'exportar como archivo CSV',
|
||||
'Export:': 'Exportar:',
|
||||
'exposes': 'expone',
|
||||
'extends': 'extiende',
|
||||
'failed to reload module': 'la recarga del módulo ha fallado',
|
||||
@@ -164,9 +183,9 @@
|
||||
'Impersonate': 'Suplantar',
|
||||
'import': 'importar',
|
||||
'Import/Export': 'Importar/Exportar',
|
||||
'in': 'en',
|
||||
'includes': 'incluye',
|
||||
'Index': 'Índice',
|
||||
'Inicio de sesión': 'Inicio de sesión',
|
||||
'insert new': 'inserte nuevo',
|
||||
'insert new %s': 'inserte nuevo %s',
|
||||
'Installed applications': 'Aplicaciones instaladas',
|
||||
@@ -176,6 +195,7 @@
|
||||
'Introduction': 'Introducción',
|
||||
'Invalid action': 'Acción inválida',
|
||||
'Invalid email': 'Correo electrónico inválido',
|
||||
'invalid expression': 'expresión inválida',
|
||||
'Invalid login': 'Inicio de sesión inválido',
|
||||
'invalid password': 'contraseña inválida',
|
||||
'Invalid Query': 'Consulta inválida',
|
||||
@@ -205,7 +225,6 @@
|
||||
'Login to the Administrative Interface': 'Inicio de sesión para la Interfaz Administrativa',
|
||||
'logout': 'fin de sesión',
|
||||
'Logout': 'Fin de sesión',
|
||||
'Los campos de contraseña no coinciden': 'Los campos de contraseña no coinciden',
|
||||
'Lost Password': 'Contraseña perdida',
|
||||
'Lost password?': '¿Olvidó la contraseña?',
|
||||
'lost password?': '¿olvidó la contraseña?',
|
||||
@@ -223,6 +242,8 @@
|
||||
'must be YYYY-MM-DD!': '¡debe ser DD/MM/YYYY!',
|
||||
'My Sites': 'Mis Sitios',
|
||||
'Name': 'Nombre',
|
||||
'New': 'Nuevo',
|
||||
'New %(entity)s': 'Nuevo %(entity)s',
|
||||
'new application "%s" created': 'nueva aplicación "%s" creada',
|
||||
'New password': 'Contraseña nueva',
|
||||
'New Record': 'Registro nuevo',
|
||||
@@ -230,10 +251,13 @@
|
||||
'next 100 rows': '100 filas siguientes',
|
||||
'NO': 'NO',
|
||||
'No databases in this application': 'No hay bases de datos en esta aplicación',
|
||||
'No records found': 'No se han encontrado registros',
|
||||
'Not authorized': 'No autorizado',
|
||||
'not in': 'no en',
|
||||
'Object or table name': 'Nombre del objeto o tabla',
|
||||
'Old password': 'Contraseña vieja',
|
||||
'Online examples': 'Ejemplos en línea',
|
||||
'Or': 'O',
|
||||
'or import from csv file': 'o importar desde archivo CSV',
|
||||
'or provide application url:': 'o provea URL de la aplicación:',
|
||||
'Origin': 'Origen',
|
||||
@@ -242,7 +266,7 @@
|
||||
'Other Recipes': 'Otras Recetas',
|
||||
'Overview': 'Resumen',
|
||||
'pack all': 'empaquetar todo',
|
||||
'pack compiled': 'empaquete compiladas',
|
||||
'pack compiled': 'empaquetar compilados',
|
||||
'Password': 'Contraseña',
|
||||
'Password changed': 'Contraseña cambiada',
|
||||
"Password fields don't match": 'Los campos de contraseña no coinciden',
|
||||
@@ -257,6 +281,7 @@
|
||||
'Profile': 'Perfil',
|
||||
'Profile updated': 'Perfil actualizado',
|
||||
'Python': 'Python',
|
||||
'Query Not Supported: %s': 'Consulta No Soportada: %s',
|
||||
'Query:': 'Consulta:',
|
||||
'Quick Examples': 'Ejemplos Rápidos',
|
||||
'RAM': 'RAM',
|
||||
@@ -264,6 +289,8 @@
|
||||
'Ram Cleared': 'Ram Limpiada',
|
||||
'Recipes': 'Recetas',
|
||||
'Record': 'Registro',
|
||||
'Record %(id)s created': 'Registro %(id)s creado',
|
||||
'Record Created': 'Registro Creado',
|
||||
'record does not exist': 'el registro no existe',
|
||||
'Record ID': 'ID de Registro',
|
||||
'Record id': 'Id de registro',
|
||||
@@ -272,11 +299,11 @@
|
||||
'Registration identifier': 'Identificador de Registro',
|
||||
'Registration key': 'Llave de registro',
|
||||
'Registration successful': 'Registro con éxito',
|
||||
'Regístrese': 'Regístrese',
|
||||
'reload': 'recargar',
|
||||
'Remember me (for 30 days)': 'Recuérdame (durante 30 días)',
|
||||
'remove compiled': 'eliminar compiladas',
|
||||
'Request reset password': 'Solicitar reinicio de contraseña',
|
||||
'Reset password': 'Reiniciar contraseña',
|
||||
'Reset Password key': 'Restaurar Llave de la Contraseña',
|
||||
'Resolve Conflict file': 'archivo Resolución de Conflicto',
|
||||
'restore': 'restaurar',
|
||||
@@ -287,6 +314,7 @@
|
||||
'Rows selected': 'Filas seleccionadas',
|
||||
'save': 'guardar',
|
||||
'Saved file hash:': 'Hash del archivo guardado:',
|
||||
'Search': 'Buscar',
|
||||
'Semantic': 'Semántica',
|
||||
'Services': 'Servicios',
|
||||
'session expired': 'sesión expirada',
|
||||
@@ -294,6 +322,8 @@
|
||||
'site': 'sitio',
|
||||
'Size of cache:': 'Tamaño de la Caché:',
|
||||
'some files could not be removed': 'algunos archivos no pudieron ser removidos',
|
||||
'start': 'inicio',
|
||||
'starts with': 'comienza por',
|
||||
'state': 'estado',
|
||||
'static': 'estáticos',
|
||||
'Static files': 'Archivos estáticos',
|
||||
@@ -301,6 +331,7 @@
|
||||
'Stylesheet': 'Hoja de estilo',
|
||||
'Submit': 'Enviar',
|
||||
'submit': 'enviar',
|
||||
'Success!': '¡Correcto!',
|
||||
'Support': 'Soporte',
|
||||
'Sure you want to delete this object?': '¿Está seguro que desea eliminar este objeto?',
|
||||
'Table': 'tabla',
|
||||
@@ -329,9 +360,17 @@
|
||||
'Time in Cache (h:m:s)': 'Tiempo en Caché (h:m:s)',
|
||||
'Timestamp': 'Marca de tiempo',
|
||||
'to previous version.': 'a la versión previa.',
|
||||
'To emulate a breakpoint programatically, write:': 'Emular un punto de ruptura programáticamente, escribir:',
|
||||
'to use the debugger!': '¡usar el depurador!',
|
||||
'toggle breakpoint': 'alternar punto de ruptura',
|
||||
'Toggle comment': 'Alternar comentario',
|
||||
'Toggle Fullscreen': 'Alternar pantalla completa',
|
||||
'too short': 'demasiado corto',
|
||||
'translation strings for the application': 'cadenas de carácteres de traducción para la aplicación',
|
||||
'try': 'intente',
|
||||
'try something like': 'intente algo como',
|
||||
'TSV (Excel compatible)': 'TSV (compatible Excel)',
|
||||
'TSV (Excel compatible, hidden cols)': 'TSV (compatible Excel, columnas ocultas)',
|
||||
'Twitter': 'Twitter',
|
||||
'Unable to check for upgrades': 'No es posible verificar la existencia de actualizaciones',
|
||||
'unable to create application "%s"': 'no es posible crear la aplicación "%s"',
|
||||
@@ -342,6 +381,7 @@
|
||||
'unable to uninstall "%s"': 'no es posible instalar "%s"',
|
||||
'uncheck all': 'desmarcar todos',
|
||||
'uninstall': 'desinstalar',
|
||||
'unknown': 'desconocido',
|
||||
'update': 'actualizar',
|
||||
'update all languages': 'actualizar todos los lenguajes',
|
||||
'Update:': 'Actualice:',
|
||||
@@ -357,17 +397,24 @@
|
||||
'User %(id)s Profile updated': 'Actualizado el perfil del usuario %(id)s',
|
||||
'User %(id)s Registered': 'Usuario %(id)s Registrado',
|
||||
'User %(id)s Username retrieved': 'Se ha recuperado el nombre de usuario del usuario %(id)s',
|
||||
'User %(username)s Logged-in': 'El usuario %(username)s inició la sesión',
|
||||
"User '%(username)s' Logged-in": "El usuario '%(username)s' inició la sesión",
|
||||
"User '%(username)s' Logged-out": "El usuario '%(username)s' finalizó la sesión",
|
||||
'User Id': 'Id de Usuario',
|
||||
'User ID': 'ID de Usuario',
|
||||
'User Logged-out': 'El usuario finalizó la sesión',
|
||||
'Username': 'Nombre de usuario',
|
||||
'Username retrieve': 'Recuperar nombre de usuario',
|
||||
'value already in database or empty': 'el valor ya existe en la base de datos o está vacío',
|
||||
'value not allowed': 'valor no permitido',
|
||||
'value not in database': 'el valor no está en la base de datos',
|
||||
'Verify Password': 'Verificar Contraseña',
|
||||
'Version': 'Versión',
|
||||
'versioning': 'versiones',
|
||||
'Videos': 'Vídeos',
|
||||
'View': 'Vista',
|
||||
'view': 'vista',
|
||||
'View %(entity)s': 'Ver %(entity)s',
|
||||
'Views': 'Vistas',
|
||||
'views': 'vistas',
|
||||
'web2py is up to date': 'web2py está actualizado',
|
||||
|
||||
@@ -1,25 +1,32 @@
|
||||
# coding: utf8
|
||||
# coding: utf-8
|
||||
{
|
||||
'!langcode!': 'tr',
|
||||
'!langname!': 'Türkçe',
|
||||
'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"güncelle" ("update") "field1=\'yenideğer\'" gibi isteğe bağlı bir ifadedir. JON sonucu güncelleyemez veya silemzsiniz.',
|
||||
'%s %%(shop)': '%s %%(shop)',
|
||||
'%s %%(shop[0])': '%s %%(shop[0])',
|
||||
'%s %%{quark[0]}': '%s %%{quark[0]}',
|
||||
'%s %%{shop[0]}': '%s %%{shop[0]}',
|
||||
'%s %%{shop}': '%s %%{shop}',
|
||||
'%Y-%m-%d': '%Y-%m-%d',
|
||||
'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S',
|
||||
'%s selected': '%s selected',
|
||||
'%Y-%m-%d': '%d-%m-%Y',
|
||||
'%Y-%m-%d %H:%M:%S': '%d-%m-%Y %H:%M:%S',
|
||||
'@markmin\x01**Hello World**': '**Merhaba Dünya**',
|
||||
'@markmin\x01An error occured, please [[reload %s]] the page': 'Bir hata oluştu, lütfen sayfayı [[yenileyin yükleyin %s]] ',
|
||||
'About': 'Hakkında',
|
||||
'Access Control': 'Erişim Denetimi',
|
||||
'Administrative Interface': 'Yönetim Arayüzü',
|
||||
'Ajax Recipes': 'Ajax Tarifleri',
|
||||
'An error occured, please %s the page': 'Bir hata meydana geldi, lütfen sayfayı %s',
|
||||
'Apply changes': 'Değişiklikleri uygula',
|
||||
'Are you sure you want to delete this object?': 'Bu nesneyi silmek istediğinden emin misin?',
|
||||
'Available Databases and Tables': 'Kullanılabilir Varitabanları ve Tablolar',
|
||||
'Buy this book': 'Bu kitabı satın alın',
|
||||
'cache': 'zula',
|
||||
'Cannot be empty': 'Boş bırakılamaz',
|
||||
'Change password': 'Parolayı değiştir',
|
||||
'Check to delete': 'Silmek için denetle',
|
||||
'Client IP': ' IP',
|
||||
'Client IP': 'İstemci IP',
|
||||
'Community': 'Topluluk',
|
||||
'Components and Plugins': 'Bileşenler ve Eklentiler',
|
||||
'Controller': 'Denetçi',
|
||||
@@ -28,33 +35,44 @@
|
||||
'Created On': 'Oluşturma tarihi',
|
||||
'customize me!': 'burayı değiştir!',
|
||||
'Database': 'Veritabanı',
|
||||
'DB Model': 'DB Model',
|
||||
'Demo': 'Demo',
|
||||
'Database %s select': '%s veritabanı seç',
|
||||
'Database Administration (appadmin)': 'Veritabanı Yönetimi (appadmin)',
|
||||
'db': 'db',
|
||||
'DB Model': 'DB Modeli',
|
||||
'Delete:': 'Sil:',
|
||||
'Demo': 'Tanıtım',
|
||||
'Deployment Recipes': 'Yayınlama tarifleri',
|
||||
'Description': 'Açıklama',
|
||||
'design': 'tasarım',
|
||||
'Documentation': 'Kitap',
|
||||
"Don't know what to do?": 'Neleri nasıl yapacağını bilmiyor musun?',
|
||||
'Download': 'İndir',
|
||||
'E-mail': 'E-posta',
|
||||
'Email and SMS': 'E-posta ve kısa mesaj (SMS)',
|
||||
'enter a value': 'bir değer giriniz',
|
||||
'enter an integer between %(min)g and %(max)g': '%(min)g ve %(max)g arasında bir sayı girin',
|
||||
'enter date and time as %(format)s': 'tarih ve saati %(format)s biçiminde girin',
|
||||
'Errors': 'Hatalar',
|
||||
'Errors in form, please check it out.': 'Formda hatalar var, lütfen kontrol edin.',
|
||||
'export as csv file': 'csv dosyası olarak dışa aktar',
|
||||
'FAQ': 'SSS',
|
||||
'First name': 'Ad',
|
||||
'Forgot username?': 'Kullanıcı adını mı unuttun?',
|
||||
'Forms and Validators': 'Biçimler ve Doğrulayıcılar',
|
||||
'Free Applications': 'Ücretsiz uygulamalar',
|
||||
'Giriş': 'Giriş',
|
||||
'Graph Model': 'Grafik Modeli',
|
||||
'Group %(group_id)s created': '%(group_id)s takımı oluşturuldu',
|
||||
'Group ID': 'Takım ID',
|
||||
'Group uniquely assigned to user %(id)s': 'Group uniquely assigned to user %(id)s',
|
||||
'Groups': 'Topluluklar',
|
||||
'Hello World': 'Merhaba Dünyalı',
|
||||
'Hello World ## comment': 'Merhaba Dünyalı ',
|
||||
'Hello World## comment': 'Merhaba Dünyalı',
|
||||
'Group uniquely assigned to user %(id)s': 'Grup özgün olarak %(id)s kullanıcılara atandı',
|
||||
'Groups': 'Gruplar',
|
||||
'Hello World': 'Merhaba Dünya',
|
||||
'Hello World ## comment': 'Merhaba Dünya ## yorum ',
|
||||
'Hello World## comment': 'Merhaba Dünya## yorum ',
|
||||
'Home': 'Anasayfa',
|
||||
'How did you get here?': 'Bu sayfayı görüntüleme uğruna neler mi oldu?',
|
||||
'import': 'import',
|
||||
'Import/Export': 'Dışa/İçe Aktar',
|
||||
'Introduction': 'Giriş',
|
||||
'Invalid email': 'Yanlış eposta',
|
||||
'Is Active': 'Etkin',
|
||||
@@ -70,60 +88,79 @@
|
||||
'Logout': 'Terket',
|
||||
'Lost Password': 'Şifremi unuttum',
|
||||
'Lost password?': 'Şifrenizimi unuttunuz?',
|
||||
'Menu Model': 'Menu Model',
|
||||
'Menu Model': 'Model Menü',
|
||||
'Modified By': 'Değiştiren',
|
||||
'Modified On': 'Değiştirilme tarihi',
|
||||
'My Sites': 'Sitelerim',
|
||||
'Name': 'İsim',
|
||||
'New password': 'Yeni parola',
|
||||
'New Record': 'Yeni Kayıt',
|
||||
'Object or table name': 'Nesne ya da tablo adı',
|
||||
'Old password': 'Eski parola',
|
||||
'Online examples': 'Canlı örnekler',
|
||||
'Origin': 'Origin',
|
||||
'or import from csv file': 'veya csv dosyasından içe aktar',
|
||||
'Origin': 'Asıl',
|
||||
'Other Plugins': 'Diğer eklentiler',
|
||||
'Other Recipes': 'Diğer Tarifler',
|
||||
'Overview': 'Göz gezdir',
|
||||
'Password': 'Şifre',
|
||||
"Password fields don't match": 'Şifreler uyuşmuyor',
|
||||
'please input your password again': 'lütfen şifrenizi tekrar girin',
|
||||
'Password': 'Parola',
|
||||
"Password fields don't match": 'Parolalar uyuşmuyor',
|
||||
'please input your password again': 'lütfen parolanızı tekrar girin',
|
||||
'Plugins': 'Eklentiler',
|
||||
'Powered by': 'Yazılım Temeli',
|
||||
'Preface': 'Preface',
|
||||
'Profile': 'Hakkımda',
|
||||
'Preface': 'Önzös',
|
||||
'Profile': 'Profil',
|
||||
'pygraphviz library not found': 'pygraphviz library not found',
|
||||
'Python': 'Python',
|
||||
'Query:': 'Sorgu:',
|
||||
'Quick Examples': 'Hızlı Örnekler',
|
||||
'Recipes': 'Recipes',
|
||||
'Recipes': 'Tarifeler',
|
||||
'Record ID': 'Kayıt ID',
|
||||
'Register': 'Kayıt ol',
|
||||
'Registration identifier': 'Registration identifier',
|
||||
'Registration identifier': 'Kayıt belirleyicisi',
|
||||
'Registration key': 'Kayıt anahtarı',
|
||||
'Registration successful': 'Kayıt başarılı',
|
||||
'reload': 'reload',
|
||||
'reload': 'yeniden yükle',
|
||||
'Remember me (for 30 days)': 'Beni hatırla (30 gün)',
|
||||
'Request reset password': 'Şifre sıfırla',
|
||||
'Reset Password key': 'Şifre anahtarını sıfırla',
|
||||
'Role': 'Role',
|
||||
'Semantic': 'Semantik',
|
||||
'Request reset password': 'Parolanı sıfırla',
|
||||
'Reset Password key': 'Parola anahtarını sıfırla',
|
||||
'Role': 'Rol',
|
||||
'Rows in Table': 'Tablodaki Satırlar',
|
||||
'Save model as...': 'Modeli farklı kaydet...',
|
||||
'Semantic': 'Anlamsal',
|
||||
'Services': 'Hizmetler',
|
||||
'state': 'durum',
|
||||
'Stylesheet': 'Stil Şablonu',
|
||||
'submit': 'gönder',
|
||||
'Submit': 'Gönder',
|
||||
'Support': 'Destek',
|
||||
'Table': 'Tablo',
|
||||
'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"sorgulama" "db.table1.field1==\'değer\'" şeklinde bir durumu ifade eder. SQL birleştirmede (JOIN) "db.table1.field1==db.table2.field2" şeklindedir.',
|
||||
'The Core': 'Çekirdek',
|
||||
'The output of the file is a dictionary that was rendered by the view %s': 'Son olarak fonksiyonların vs. işlenip %s dosyasıyla tasarıma yedirilmesiyle sayfayı görüntüledin',
|
||||
'The Views': 'The Views',
|
||||
'The Views': 'Görünümler',
|
||||
'This App': 'Bu Uygulama',
|
||||
'This email already has an account': 'Bu e-postaya ait bir hesap zaten var',
|
||||
'Timestamp': 'Zaman damgası',
|
||||
'Twitter': 'Twitter',
|
||||
'Update:': 'Güncelle:',
|
||||
'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Karmaşık sorgularda Ve (AND) için (...)&(...) kullanın, Veya (OR) için (...)|(...) kullanın ve DEĞİL (NOT) için ~(...) kullanın. ',
|
||||
'User %(id)s Logged-in': '%(id)s Giriş yaptı',
|
||||
'User %(id)s Logged-out': '%(id)s çıkış yaptı',
|
||||
'User %(id)s Password reset': 'User %(id)s Password reset',
|
||||
'User %(id)s Password reset': 'Kullanıc %(id)s Parolasını sıfırla',
|
||||
'User %(id)s Registered': '%(id)s Kayıt oldu',
|
||||
'User ID': 'Kullanıcı ID',
|
||||
'value already in database or empty': 'değer boş ya da veritabanında zaten mevcut',
|
||||
'Verify Password': 'Şifreni Onayla',
|
||||
'Verify Password': 'Parolanı Onayla',
|
||||
'Videos': 'Videolar',
|
||||
'View': 'View',
|
||||
'View': 'Görünüm',
|
||||
'Welcome': 'Hoşgeldin',
|
||||
'Welcome to web2py!': 'Welcome to web2py!',
|
||||
'Welcome to web2py!': "web2py'ye hoşgeldiniz!",
|
||||
'Which called the function %s located in the file %s': 'Bu ziyaretle %s fonksiyonunu %s dosyasından çağırmış oldun ',
|
||||
'Working...': 'Çalışıyor...',
|
||||
'You are successfully running web2py': 'web2py çatısını çalıştırmayı başardın',
|
||||
'You can modify this application and adapt it to your needs': 'Artık uygulamayı kafana göre düzenleyebilirsin!',
|
||||
'You can modify this application and adapt it to your needs': 'Artık uygulamayı istediğin gibi düzenleyebilirsin!',
|
||||
'You visited the url %s': '%s adresini ziyaret ettin',
|
||||
'invalid controller': 'geçersiz denetleyici',
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ audio {width:200px}
|
||||
.hidden {display:none;visibility:visible}
|
||||
.right {float:right; text-align:right}
|
||||
.left {float:left; text-align:left}
|
||||
.center {width:100; text-align:center; vertical-align:middle}
|
||||
.center {width:100%; text-align:center; vertical-align:middle}
|
||||
/** end **/
|
||||
|
||||
/* Sticky footer begin */
|
||||
|
||||
9
applications/welcome/static/js/jquery.js
vendored
9
applications/welcome/static/js/jquery.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -485,8 +485,10 @@
|
||||
el.addClass('disabled');
|
||||
var method = el.prop('type') == 'submit' ? 'val' : 'html';
|
||||
var disable_with_message = (typeof w2p_ajax_disable_with_message != 'undefined') ? w2p_ajax_disable_with_message : "Working...";
|
||||
/*store enabled state*/
|
||||
el.data('w2p:enable-with', el[method]());
|
||||
/*store enabled state if not already disabled */
|
||||
if (el.data('w2p:enable-with') === undefined) {
|
||||
el.data('w2p:enable-with', el[method]());
|
||||
}
|
||||
/*if you don't want to see "working..." on buttons, replace the following
|
||||
* two lines with this one
|
||||
* el.data('w2p_disable_with', el[method]());
|
||||
@@ -633,7 +635,9 @@
|
||||
if(disable_with == undefined) {
|
||||
element.data('w2p_disable_with', element[method]())
|
||||
}
|
||||
element.data('w2p:enable-with', element[method]());
|
||||
if (element.data('w2p:enable-with') === undefined) {
|
||||
element.data('w2p:enable-with', element[method]());
|
||||
}
|
||||
element[method](element.data('w2p_disable_with'));
|
||||
element.prop('disabled', true);
|
||||
});
|
||||
@@ -647,7 +651,10 @@
|
||||
form.find(web2py.enableSelector).each(function () {
|
||||
var element = $(this),
|
||||
method = element.is('button') ? 'html' : 'val';
|
||||
if(element.data('w2p:enable-with')) element[method](element.data('w2p:enable-with'));
|
||||
if(element.data('w2p:enable-with')) {
|
||||
element[method](element.data('w2p:enable-with'));
|
||||
element.removeData('w2p:enable-with');
|
||||
}
|
||||
element.prop('disabled', false);
|
||||
});
|
||||
},
|
||||
@@ -659,7 +666,18 @@
|
||||
el.on('ajax:complete', 'form[data-w2p_target]', function (e) {
|
||||
web2py.enableFormElements($(this));
|
||||
});
|
||||
}
|
||||
},
|
||||
/* Invalidate and force reload of a web2py component
|
||||
*/
|
||||
invalidate: function(target) {
|
||||
$('div[data-w2p_remote]', target).each(function () {
|
||||
var el = $('#' + $(this).attr('id')).get(0);
|
||||
if (el.timing !== undefined) { // Block triggering regular routines
|
||||
clearInterval(el.timing);
|
||||
}
|
||||
});
|
||||
$.web2py.component_handler(target);
|
||||
},
|
||||
}
|
||||
|
||||
/*end of functions */
|
||||
@@ -679,7 +697,7 @@
|
||||
/* compatibility code - start */
|
||||
ajax = jQuery.web2py.ajax;
|
||||
web2py_component = jQuery.web2py.component;
|
||||
web2py_websocket = jQuery.web2py.websocket;
|
||||
web2py_websocket = jQuery.web2py.web2py_websocket;
|
||||
web2py_ajax_page = jQuery.web2py.ajax_page;
|
||||
/*needed for IS_STRONG(entropy)*/
|
||||
web2py_validate_entropy = jQuery.web2py.validate_entropy;
|
||||
|
||||
@@ -20,14 +20,14 @@ jQuery(function(){
|
||||
function hoverMenu(){
|
||||
jQuery('ul.nav a.dropdown-toggle').parent().hover(function(){
|
||||
adjust_height_of_collapsed_nav();
|
||||
mi = jQuery(this).addClass('open');
|
||||
var mi = jQuery(this).addClass('open');
|
||||
mi.children('.dropdown-menu').stop(true, true).delay(200).fadeIn(400);
|
||||
}, function(){
|
||||
mi = jQuery(this);
|
||||
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,35 +1,50 @@
|
||||
{{left_sidebar_enabled,right_sidebar_enabled=False,('message' in globals())}}
|
||||
{{extend 'layout.html'}}
|
||||
|
||||
{{if 'message' in globals():}}
|
||||
<h3>{{=message}}</h3>
|
||||
|
||||
<h4>{{=T('How did you get here?')}}</h4>
|
||||
<ol>
|
||||
<li>{{=T('You are successfully running web2py')}}</li>
|
||||
<li>{{=XML(T('You visited the url %s', A(request.env.path_info,_href=request.env.path_info)))}}</li>
|
||||
<li>{{=XML(T('Which called the function %s located in the file %s',
|
||||
(A(request.function+'()',_href='#'),
|
||||
A('web2py/applications/%(application)s/controllers/%(controller)s.py'%request,
|
||||
_href=URL('admin','default','peek', args=(request.application,'controllers',request.controller+'.py'))))))}}</li>
|
||||
<li>{{=XML(T('The output of the file is a dictionary that was rendered by the view %s',
|
||||
A('web2py/applications/%(application)s/views/%(controller)s/index.html'%request,
|
||||
_href=URL('admin','default','peek',args=(request.application,'views',request.controller,'index.html')))))}}</li>
|
||||
<li>{{=T('You can modify this application and adapt it to your needs')}}</li>
|
||||
</ol>
|
||||
{{elif 'content' in globals():}}
|
||||
{{=content}}
|
||||
{{else:}}
|
||||
{{=BEAUTIFY(response._vars)}}
|
||||
{{pass}}
|
||||
|
||||
{{block right_sidebar}}
|
||||
{{=A(T("Administrative Interface"), _href=URL('admin','default','index'), _class='btn',
|
||||
_style='margin-top: 1em;')}}
|
||||
<h6>{{=T("Don't know what to do?")}}</h6>
|
||||
<ul>
|
||||
<li>{{=A(T("Online examples"), _href=URL('examples','default','index'))}}</li>
|
||||
<li><a href="http://web2py.com">web2py.com</a></li>
|
||||
<li><a href="http://web2py.com/book">{{=T('Documentation')}}</a></li>
|
||||
</ul>
|
||||
{{end}}
|
||||
{{left_sidebar_enabled,right_sidebar_enabled=False,('message' in globals())}}
|
||||
{{extend 'layout.html'}}
|
||||
|
||||
{{block head}}
|
||||
<style>
|
||||
#w2padmin-btn {margin:30px 0 30px 0;}
|
||||
</style>
|
||||
{{end head}}
|
||||
|
||||
{{if 'message' in globals():}}
|
||||
<h2>{{=message}}</h2>
|
||||
<p class="lead">{{=T('How did you get here?')}}</p>
|
||||
<ol>
|
||||
<li>{{=T('You are successfully running web2py')}}</li>
|
||||
<li>{{=XML(T('You visited the url %s', A(request.env.path_info,_href=request.env.path_info)))}}</li>
|
||||
<li>{{=XML(T('Which called the function %s located in the file %s',
|
||||
(A(request.function+'()',_href='#'),
|
||||
A('web2py/applications/%(application)s/controllers/%(controller)s.py'%request,
|
||||
_href=URL('admin','default','peek', args=(request.application,'controllers',request.controller+'.py'))))))}}</li>
|
||||
<li>{{=XML(T('The output of the file is a dictionary that was rendered by the view %s',
|
||||
A('web2py/applications/%(application)s/views/%(controller)s/index.html'%request,
|
||||
_href=URL('admin','default','peek',args=(request.application,'views',request.controller,'index.html')))))}}</li>
|
||||
<li>{{=T('You can modify this application and adapt it to your needs')}}</li>
|
||||
</ol>
|
||||
{{elif 'content' in globals():}}
|
||||
{{=content}}
|
||||
{{else:}}
|
||||
{{=BEAUTIFY(response._vars)}}
|
||||
{{pass}}
|
||||
|
||||
{{block right_sidebar}}
|
||||
<button id="w2padmin-btn" class="btn btn-primary btn-lg btn-block">
|
||||
<i class="glyphicon glyphicon-cog"></i> {{=T("Administrative Interface")}}</button>
|
||||
<div class="panel panel-info">
|
||||
<div class="panel-heading">{{=T("Don't know what to do?")}}</div>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">{{=A(T("Online examples"), _href=URL('examples','default','index'))}}</li>
|
||||
<li class="list-group-item"><a href="http://web2py.com">web2py.com</a></li>
|
||||
<li class="list-group-item"><a href="http://web2py.com/book">{{=T('Documentation')}}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{block page_js}}
|
||||
<script>
|
||||
$('#w2padmin-btn').click(function() {
|
||||
window.location = "{{=URL('admin','default','index')}}";
|
||||
});
|
||||
</script>
|
||||
{{end}}
|
||||
|
||||
@@ -65,8 +65,8 @@ skip_files: |
|
||||
(.*\.py[co])|
|
||||
(.*/RCS/.*)|
|
||||
(\..*)|
|
||||
(applications/(admin|examples)/.*)|
|
||||
((admin|examples|welcome)\.(w2p|tar))|
|
||||
(applications/examples/.*)|
|
||||
((examples|welcome)\.(w2p|tar))|
|
||||
(applications/.*?/(cron|databases|errors|cache|sessions)/.*)|
|
||||
((logs|scripts)/.*)|
|
||||
(anyserver\.py)|
|
||||
|
||||
@@ -48,9 +48,11 @@
|
||||
# default_language
|
||||
# The language code (for example: en, it-it) optionally appears in the URL following
|
||||
# the application (which may be omitted). For incoming URLs, the code is copied to
|
||||
# request.language; for outgoing URLs it is taken from request.language.
|
||||
# request.uri_language; for outgoing URLs it is taken from request.uri_language.
|
||||
# If languages=None, language support is disabled.
|
||||
# The default_language, if any, is omitted from the URL.
|
||||
# To use the incoming language in your application, add this line to one of your models files:
|
||||
# if request.uri_language: T.force(request.uri_language)
|
||||
# root_static: list of static files accessed from root (by default, favicon.ico & robots.txt)
|
||||
# (mapped to the default application's static/ directory)
|
||||
# Each default (including domain-mapped) application has its own root-static files.
|
||||
|
||||
257
gluon/admin.py
257
gluon/admin.py
@@ -1,10 +1,13 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
This file is part of the web2py Web Framework
|
||||
Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
|
||||
License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
||||
| This file is part of the web2py Web Framework
|
||||
| Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
|
||||
| License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
||||
|
||||
Utility functions for the Admin application
|
||||
===========================================
|
||||
-------------------------------------------
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
@@ -25,15 +28,11 @@ if not global_settings.web2py_runtime_gae:
|
||||
|
||||
|
||||
def apath(path='', r=None):
|
||||
"""
|
||||
Builds a path inside an application folder
|
||||
"""Builds a path inside an application folder
|
||||
|
||||
Parameters
|
||||
----------
|
||||
path:
|
||||
path within the application folder
|
||||
r:
|
||||
the global request object
|
||||
Args:
|
||||
path(str): path within the application folder
|
||||
r: the global request object
|
||||
|
||||
"""
|
||||
|
||||
@@ -44,20 +43,14 @@ def apath(path='', r=None):
|
||||
|
||||
|
||||
def app_pack(app, request, raise_ex=False, filenames=None):
|
||||
"""
|
||||
Builds a w2p package for the application
|
||||
"""Builds a w2p package for the application
|
||||
|
||||
Parameters
|
||||
----------
|
||||
app:
|
||||
application name
|
||||
request:
|
||||
the global request object
|
||||
|
||||
Returns
|
||||
-------
|
||||
filename:
|
||||
Args:
|
||||
app(str): application name
|
||||
request: the global request object
|
||||
Returns:
|
||||
filename of the w2p file or None on error
|
||||
|
||||
"""
|
||||
try:
|
||||
if filenames is None: app_cleanup(app, request)
|
||||
@@ -71,20 +64,15 @@ def app_pack(app, request, raise_ex=False, filenames=None):
|
||||
|
||||
|
||||
def app_pack_compiled(app, request, raise_ex=False):
|
||||
"""
|
||||
Builds a w2p bytecode-compiled package for the application
|
||||
"""Builds a w2p bytecode-compiled package for the application
|
||||
|
||||
Parameters
|
||||
----------
|
||||
app:
|
||||
application name
|
||||
request:
|
||||
the global request object
|
||||
Args:
|
||||
app(str): application name
|
||||
request: the global request object
|
||||
|
||||
Returns
|
||||
-------
|
||||
filename:
|
||||
Returns:
|
||||
filename of the w2p file or None on error
|
||||
|
||||
"""
|
||||
|
||||
try:
|
||||
@@ -98,15 +86,15 @@ def app_pack_compiled(app, request, raise_ex=False):
|
||||
|
||||
|
||||
def app_cleanup(app, request):
|
||||
"""
|
||||
Removes session, cache and error files
|
||||
"""Removes session, cache and error files
|
||||
|
||||
Args:
|
||||
app(str): application name
|
||||
request: the global request object
|
||||
|
||||
Returns:
|
||||
True if everything went ok, False otherwise
|
||||
|
||||
Parameters
|
||||
----------
|
||||
app:
|
||||
application name
|
||||
request:
|
||||
the global request object
|
||||
"""
|
||||
r = True
|
||||
|
||||
@@ -140,15 +128,15 @@ def app_cleanup(app, request):
|
||||
|
||||
|
||||
def app_compile(app, request):
|
||||
"""
|
||||
Compiles the application
|
||||
"""Compiles the application
|
||||
|
||||
Args:
|
||||
app(str): application name
|
||||
request: the global request object
|
||||
|
||||
Returns:
|
||||
None if everything went ok, traceback text if errors are found
|
||||
|
||||
Parameters
|
||||
----------
|
||||
app:
|
||||
application name
|
||||
request:
|
||||
the global request object
|
||||
"""
|
||||
from compileapp import compile_application, remove_compiled_application
|
||||
folder = apath(app, request)
|
||||
@@ -162,15 +150,11 @@ def app_compile(app, request):
|
||||
|
||||
|
||||
def app_create(app, request, force=False, key=None, info=False):
|
||||
"""
|
||||
Create a copy of welcome.w2p (scaffolding) app
|
||||
"""Create a copy of welcome.w2p (scaffolding) app
|
||||
|
||||
Parameters
|
||||
----------
|
||||
app:
|
||||
application name
|
||||
request:
|
||||
the global request object
|
||||
Args:
|
||||
app(str): application name
|
||||
request: the global request object
|
||||
|
||||
"""
|
||||
path = apath(app, request)
|
||||
@@ -215,28 +199,23 @@ def app_create(app, request, force=False, key=None, info=False):
|
||||
|
||||
|
||||
def app_install(app, fobj, request, filename, overwrite=None):
|
||||
"""
|
||||
Installs an application:
|
||||
"""Installs an application:
|
||||
|
||||
- Identifies file type by filename
|
||||
- Writes `fobj` contents to the `../deposit/` folder
|
||||
- Calls `w2p_unpack()` to do the job.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
app:
|
||||
new application name
|
||||
fobj:
|
||||
file object containing the application to be installed
|
||||
request:
|
||||
the global request object
|
||||
filename:
|
||||
original filename of the `fobj`, required to determine extension
|
||||
Args:
|
||||
app(str): new application name
|
||||
fobj(obj): file object containing the application to be installed
|
||||
request: the global request object
|
||||
filename(str): original filename of the `fobj`,
|
||||
required to determine extension
|
||||
overwrite(bool): force overwrite of existing application
|
||||
|
||||
Returns
|
||||
-------
|
||||
upname:
|
||||
Returns:
|
||||
name of the file where app is temporarily stored or `None` on failure
|
||||
|
||||
"""
|
||||
did_mkdir = False
|
||||
if filename[-4:] == '.w2p':
|
||||
@@ -265,19 +244,15 @@ def app_install(app, fobj, request, filename, overwrite=None):
|
||||
|
||||
|
||||
def app_uninstall(app, request):
|
||||
"""
|
||||
Uninstalls the application.
|
||||
"""Uninstalls the application.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
app:
|
||||
application name
|
||||
request:
|
||||
the global request object
|
||||
Args:
|
||||
app(str): application name
|
||||
request: the global request object
|
||||
|
||||
Returns:
|
||||
`True` on success, `False` on failure
|
||||
|
||||
Returns
|
||||
-------
|
||||
`True` on success, `False` on failure
|
||||
"""
|
||||
try:
|
||||
# Hey App, this is your end...
|
||||
@@ -289,22 +264,16 @@ def app_uninstall(app, request):
|
||||
|
||||
|
||||
def plugin_pack(app, plugin_name, request):
|
||||
"""
|
||||
Builds a w2p package for the application
|
||||
"""Builds a w2p package for the plugin
|
||||
|
||||
Parameters
|
||||
----------
|
||||
app:
|
||||
application name
|
||||
plugin_name:
|
||||
the name of the plugin without plugin_ prefix
|
||||
request:
|
||||
the current request app
|
||||
Args:
|
||||
app(str): application name
|
||||
plugin_name(str): the name of the plugin without `plugin_` prefix
|
||||
request: the current request app
|
||||
|
||||
Returns:
|
||||
filename of the w2p file or False on error
|
||||
|
||||
Returns
|
||||
-------
|
||||
filename:
|
||||
filename of the w2p file or None on error
|
||||
"""
|
||||
try:
|
||||
filename = apath(
|
||||
@@ -316,30 +285,24 @@ def plugin_pack(app, plugin_name, request):
|
||||
|
||||
|
||||
def plugin_install(app, fobj, request, filename):
|
||||
"""
|
||||
Installs an application:
|
||||
"""Installs a plugin:
|
||||
|
||||
- Identifies file type by filename
|
||||
- Writes `fobj` contents to the `../deposit/` folder
|
||||
- Calls `w2p_unpack()` to do the job.
|
||||
- Calls `w2p_unpack_plugin()` to do the job.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
app:
|
||||
new application name
|
||||
fobj:
|
||||
file object containing the application to be installed
|
||||
request:
|
||||
the global request object
|
||||
filename:
|
||||
original filename of the `fobj`, required to determine extension
|
||||
Args:
|
||||
app(str): new application name
|
||||
fobj: file object containing the application to be installed
|
||||
request: the global request object
|
||||
filename: original filename of the `fobj`,
|
||||
required to determine extension
|
||||
|
||||
Returns:
|
||||
name of the file where plugin is temporarily stored
|
||||
or `False` on failure
|
||||
|
||||
Returns
|
||||
-------
|
||||
upname:
|
||||
name of the file where app is temporarily stored or `None` on failure
|
||||
"""
|
||||
|
||||
upname = apath('../deposit/%s' % filename, request)
|
||||
|
||||
try:
|
||||
@@ -354,23 +317,20 @@ def plugin_install(app, fobj, request, filename):
|
||||
|
||||
|
||||
def check_new_version(myversion, version_url):
|
||||
"""
|
||||
Compares current web2py's version with the latest stable web2py version.
|
||||
"""Compares current web2py's version with the latest stable web2py version.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
myversion:
|
||||
the current version as stored in file `web2py/VERSION`
|
||||
version_URL:
|
||||
the URL that contains the version of the latest stable release
|
||||
Args:
|
||||
myversion: the current version as stored in file `web2py/VERSION`
|
||||
version_URL: the URL that contains the version
|
||||
of the latest stable release
|
||||
|
||||
Returns:
|
||||
tuple: state, version
|
||||
|
||||
- state : `True` if upgrade available, `False` if current
|
||||
version is up-to-date, -1 on error
|
||||
- version : the most up-to-version available
|
||||
|
||||
Returns
|
||||
-------
|
||||
state:
|
||||
`True` if upgrade available, `False` if current version if up-to-date,
|
||||
-1 on error
|
||||
version:
|
||||
the most up-to-version available
|
||||
"""
|
||||
try:
|
||||
from urllib import urlopen
|
||||
@@ -389,9 +349,13 @@ def check_new_version(myversion, version_url):
|
||||
|
||||
|
||||
def unzip(filename, dir, subfolder=''):
|
||||
"""
|
||||
Unzips filename into dir (.zip only, no .gz etc)
|
||||
if subfolder!='' it unzip only files in subfolder
|
||||
"""Unzips filename into dir (.zip only, no .gz etc)
|
||||
|
||||
Args:
|
||||
filename(str): archive
|
||||
dir(str): destination
|
||||
subfolder(str): if != '' unzips only files in subfolder
|
||||
|
||||
"""
|
||||
filename = abspath(filename)
|
||||
if not zipfile.is_zipfile(filename):
|
||||
@@ -413,21 +377,22 @@ def unzip(filename, dir, subfolder=''):
|
||||
|
||||
|
||||
def upgrade(request, url='http://web2py.com'):
|
||||
"""
|
||||
Upgrades web2py (src, osx, win) is a new version is posted.
|
||||
"""Upgrades web2py (src, osx, win) if a new version is posted.
|
||||
It detects whether src, osx or win is running and downloads the right one
|
||||
|
||||
Parameters
|
||||
----------
|
||||
request:
|
||||
the current request object, required to determine version and path
|
||||
url:
|
||||
the incomplete url where to locate the latest web2py
|
||||
actual url is url+'/examples/static/web2py_(src|osx|win).zip'
|
||||
Args:
|
||||
request: the current request object
|
||||
(required to determine version and path)
|
||||
url: the incomplete url where to locate the latest web2py
|
||||
(actual url is url+'/examples/static/web2py_(src|osx|win).zip')
|
||||
|
||||
Returns
|
||||
-------
|
||||
True on success, False on failure (network problem or old version)
|
||||
tuple: completed, traceback
|
||||
|
||||
- completed: True on success, False on failure
|
||||
(network problem or old version)
|
||||
- traceback: None on success, raised exception details on failure
|
||||
|
||||
"""
|
||||
web2py_version = request.env.web2py_version
|
||||
gluon_parent = request.env.gluon_parent
|
||||
|
||||
196
gluon/cache.py
196
gluon/cache.py
@@ -2,12 +2,12 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
This file is part of the web2py Web Framework
|
||||
Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
|
||||
License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
||||
| This file is part of the web2py Web Framework
|
||||
| Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
|
||||
| License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
||||
|
||||
Basic caching classes and methods
|
||||
=================================
|
||||
---------------------------------
|
||||
|
||||
- Cache - The generic caching object interfacing with the others
|
||||
- CacheInRam - providing caching in ram
|
||||
@@ -42,57 +42,56 @@ __all__ = ['Cache', 'lazy_cache']
|
||||
DEFAULT_TIME_EXPIRE = 300
|
||||
|
||||
|
||||
|
||||
class CacheAbstract(object):
|
||||
"""
|
||||
Abstract class for cache implementations.
|
||||
Main function is now to provide referenced api documentation.
|
||||
Main function just provides referenced api documentation.
|
||||
|
||||
Use CacheInRam or CacheOnDisk instead which are derived from this class.
|
||||
|
||||
Attentions, Michele says:
|
||||
|
||||
There are signatures inside gdbm files that are used directly
|
||||
by the python gdbm adapter that often are lagging behind in the
|
||||
detection code in python part.
|
||||
On every occasion that a gdbm store is probed by the python adapter,
|
||||
the probe fails, because gdbm file version is newer.
|
||||
Using gdbm directly from C would work, because there is backward
|
||||
compatibility, but not from python!
|
||||
The .shelve file is discarded and a new one created (with new
|
||||
signature) and it works until it is probed again...
|
||||
The possible consequences are memory leaks and broken sessions.
|
||||
Note:
|
||||
Michele says: there are signatures inside gdbm files that are used
|
||||
directly by the python gdbm adapter that often are lagging behind in the
|
||||
detection code in python part.
|
||||
On every occasion that a gdbm store is probed by the python adapter,
|
||||
the probe fails, because gdbm file version is newer.
|
||||
Using gdbm directly from C would work, because there is backward
|
||||
compatibility, but not from python!
|
||||
The .shelve file is discarded and a new one created (with new
|
||||
signature) and it works until it is probed again...
|
||||
The possible consequences are memory leaks and broken sessions.
|
||||
"""
|
||||
|
||||
cache_stats_name = 'web2py_cache_statistics'
|
||||
|
||||
def __init__(self, request=None):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
request:
|
||||
the global request object
|
||||
"""Initializes the object
|
||||
|
||||
Args:
|
||||
request: the global request object
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def __call__(self, key, f,
|
||||
time_expire=DEFAULT_TIME_EXPIRE):
|
||||
"""
|
||||
Tries retrieve the value corresponding to `key` from the cache of the
|
||||
object exists and if it did not expire, else it called the function `f`
|
||||
and stores the output in the cache corresponding to `key`. In the case
|
||||
the output of the function is returned.
|
||||
Tries to retrieve the value corresponding to `key` from the cache if the
|
||||
object exists and if it did not expire, else it calls the function `f`
|
||||
and stores the output in the cache corresponding to `key`. It always
|
||||
returns the function that is returned.
|
||||
|
||||
:param key: the key of the object to be store or retrieved
|
||||
:param f: the function, whose output is to be cached
|
||||
:param time_expire: expiration of the cache in microseconds
|
||||
Args:
|
||||
key(str): the key of the object to be stored or retrieved
|
||||
f(function): the function whose output is to be cached.
|
||||
|
||||
- `time_expire` is used to compare the current time with the time when
|
||||
the requested object was last saved in cache. It does not affect
|
||||
future requests.
|
||||
- Setting `time_expire` to 0 or negative value forces the cache to
|
||||
refresh.
|
||||
If `f` is `None` the cache is cleared.
|
||||
time_expire(int): expiration of the cache in seconds.
|
||||
|
||||
If the function `f` is `None` the cache is cleared.
|
||||
It's used to compare the current time with the time
|
||||
when the requested object was last saved in cache. It does not
|
||||
affect future requests. Setting `time_expire` to 0 or negative
|
||||
value forces the cache to refresh.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@@ -101,11 +100,9 @@ class CacheAbstract(object):
|
||||
Clears the cache of all keys that match the provided regular expression.
|
||||
If no regular expression is provided, it clears all entries in cache.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
regex:
|
||||
if provided, only keys matching the regex will be cleared.
|
||||
Otherwise all keys are cleared.
|
||||
Args:
|
||||
regex: if provided, only keys matching the regex will be cleared,
|
||||
otherwise all keys are cleared.
|
||||
"""
|
||||
|
||||
raise NotImplementedError
|
||||
@@ -114,12 +111,9 @@ class CacheAbstract(object):
|
||||
"""
|
||||
Increments the cached value for the given key by the amount in value
|
||||
|
||||
Parameters
|
||||
----------
|
||||
key:
|
||||
key for the cached object to be incremeneted
|
||||
value:
|
||||
amount of the increment (defaults to 1, can be negative)
|
||||
Args:
|
||||
key(str): key for the cached object to be incremeneted
|
||||
value(int): amount of the increment (defaults to 1, can be negative)
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@@ -187,12 +181,17 @@ class CacheInRam(CacheAbstract):
|
||||
time_expire=DEFAULT_TIME_EXPIRE,
|
||||
destroyer=None):
|
||||
"""
|
||||
Attention! cache.ram does not copy the cached object. It just stores a reference to it.
|
||||
Turns out the deepcopying the object has some problems:
|
||||
1) would break backward compatibility
|
||||
2) would be limiting because people may want to cache live objects
|
||||
3) would work unless we deepcopy no storage and retrival which would make things slow.
|
||||
Anyway. You can deepcopy explicitly in the function generating the value to be cached.
|
||||
Attention! cache.ram does not copy the cached object.
|
||||
It just stores a reference to it. Turns out the deepcopying the object
|
||||
has some problems:
|
||||
|
||||
- would break backward compatibility
|
||||
- would be limiting because people may want to cache live objects
|
||||
- would work unless we deepcopy no storage and retrival which would make
|
||||
things slow.
|
||||
|
||||
Anyway. You can deepcopy explicitly in the function generating the value
|
||||
to be cached.
|
||||
"""
|
||||
self.initialize()
|
||||
|
||||
@@ -419,10 +418,8 @@ class Cache(object):
|
||||
|
||||
def __init__(self, request):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
request:
|
||||
the global request object
|
||||
Args:
|
||||
request: the global request object
|
||||
"""
|
||||
# GAE will have a special caching
|
||||
if have_settings and settings.global_settings.web2py_runtime_gae:
|
||||
@@ -444,24 +441,30 @@ class Cache(object):
|
||||
prefix=None, session=False, vars=True, lang=True,
|
||||
user_agent=False, public=True, valid_statuses=None,
|
||||
quick=None):
|
||||
"""
|
||||
Experimental!
|
||||
"""Better fit for caching an action
|
||||
|
||||
Warning:
|
||||
Experimental!
|
||||
|
||||
Currently only HTTP 1.1 compliant
|
||||
reference : http://code.google.com/p/doctype-mirror/wiki/ArticleHttpCaching
|
||||
time_expire: same as @cache
|
||||
cache_model: same as @cache
|
||||
prefix: add a prefix to the calculated key
|
||||
session: adds response.session_id to the key
|
||||
vars: adds request.env.query_string
|
||||
lang: adds T.accepted_language
|
||||
user_agent: if True, adds is_mobile and is_tablet to the key.
|
||||
Pass a dict to use all the needed values (uses str(.items())) (e.g. user_agent=request.user_agent())
|
||||
used only if session is not True
|
||||
public: if False forces the Cache-Control to be 'private'
|
||||
valid_statuses: by default only status codes starting with 1,2,3 will be cached.
|
||||
pass an explicit list of statuses on which turn the cache on
|
||||
quick: Session,Vars,Lang,User-agent,Public:
|
||||
fast overrides with initial strings, e.g. 'SVLP' or 'VLP', or 'VLP'
|
||||
|
||||
Args:
|
||||
time_expire(int): same as @cache
|
||||
cache_model(str): same as @cache
|
||||
prefix(str): add a prefix to the calculated key
|
||||
session(bool): adds response.session_id to the key
|
||||
vars(bool): adds request.env.query_string
|
||||
lang(bool): adds T.accepted_language
|
||||
user_agent(bool or dict): if True, adds is_mobile and is_tablet to the key.
|
||||
Pass a dict to use all the needed values (uses str(.items()))
|
||||
(e.g. user_agent=request.user_agent()). Used only if session is
|
||||
not True
|
||||
public(bool): if False forces the Cache-Control to be 'private'
|
||||
valid_statuses: by default only status codes starting with 1,2,3 will be cached.
|
||||
pass an explicit list of statuses on which turn the cache on
|
||||
quick: Session,Vars,Lang,User-agent,Public:
|
||||
fast overrides with initials, e.g. 'SVLP' or 'VLP', or 'VLP'
|
||||
"""
|
||||
from gluon import current
|
||||
from gluon.http import HTTP
|
||||
@@ -561,33 +564,32 @@ class Cache(object):
|
||||
"""
|
||||
Decorator function that can be used to cache any function/method.
|
||||
|
||||
Example::
|
||||
Args:
|
||||
key(str) : the key of the object to be store or retrieved
|
||||
time_expire(int) : expiration of the cache in seconds
|
||||
`time_expire` is used to compare the current time with the time
|
||||
when the requested object was last saved in cache.
|
||||
It does not affect future requests.
|
||||
Setting `time_expire` to 0 or negative value forces the cache to
|
||||
refresh.
|
||||
cache_model(str): can be "ram", "disk" or other (like "memcache").
|
||||
Defaults to "ram"
|
||||
|
||||
@cache('key', 5000, cache.ram)
|
||||
def f():
|
||||
return time.ctime()
|
||||
|
||||
When the function f is called, web2py tries to retrieve
|
||||
the value corresponding to `key` from the cache of the
|
||||
When the function `f` is called, web2py tries to retrieve
|
||||
the value corresponding to `key` from the cache if the
|
||||
object exists and if it did not expire, else it calles the function `f`
|
||||
and stores the output in the cache corresponding to `key`. In the case
|
||||
the output of the function is returned.
|
||||
|
||||
:param key: the key of the object to be store or retrieved
|
||||
:param time_expire: expiration of the cache in microseconds
|
||||
:param cache_model: "ram", "disk", or other
|
||||
(like "memcache" if defined). It defaults to "ram".
|
||||
Example: ::
|
||||
|
||||
Notes
|
||||
-----
|
||||
`time_expire` is used to compare the curret time with the time when the
|
||||
requested object was last saved in cache. It does not affect future
|
||||
requests.
|
||||
Setting `time_expire` to 0 or negative value forces the cache to
|
||||
refresh.
|
||||
@cache('key', 5000, cache.ram)
|
||||
def f():
|
||||
return time.ctime()
|
||||
|
||||
If the function `f` is an action, we suggest using
|
||||
@cache.client instead
|
||||
Note:
|
||||
If the function `f` is an action, we suggest using
|
||||
@cache.action instead
|
||||
"""
|
||||
|
||||
def tmp(func, cache=self, cache_model=cache_model):
|
||||
@@ -606,11 +608,13 @@ class Cache(object):
|
||||
|
||||
def lazy_cache(key=None, time_expire=None, cache_model='ram'):
|
||||
"""
|
||||
can be used to cache any function including in modules,
|
||||
Can be used to cache any function including ones in modules,
|
||||
as long as the cached function is only called within a web2py request
|
||||
if a key is not provided, one is generated from the function name
|
||||
the time_expire defaults to None (no cache expiration)
|
||||
if cache_model is "ram" then the model is current.cache.ram, etc.
|
||||
|
||||
If a key is not provided, one is generated from the function name
|
||||
`time_expire` defaults to None (no cache expiration)
|
||||
|
||||
If cache_model is "ram" then the model is current.cache.ram, etc.
|
||||
"""
|
||||
def decorator(f, key=key, time_expire=time_expire, cache_model=cache_model):
|
||||
key = key or repr(f)
|
||||
|
||||
23
gluon/cfs.py
23
gluon/cfs.py
@@ -2,19 +2,19 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
This file is part of the web2py Web Framework
|
||||
Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
|
||||
License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
||||
| This file is part of the web2py Web Framework
|
||||
| Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
|
||||
| License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
||||
|
||||
Functions required to execute app components
|
||||
============================================
|
||||
--------------------------------------------
|
||||
|
||||
FOR INTERNAL USE ONLY
|
||||
Note:
|
||||
FOR INTERNAL USE ONLY
|
||||
"""
|
||||
|
||||
from os import stat
|
||||
import thread
|
||||
import logging
|
||||
from gluon.fileutils import read_file
|
||||
|
||||
cfs = {} # for speed-up
|
||||
@@ -26,11 +26,12 @@ def getcfs(key, filename, filter=None):
|
||||
Caches the *filtered* file `filename` with `key` until the file is
|
||||
modified.
|
||||
|
||||
:param key: the cache key
|
||||
:param filename: the file to cache
|
||||
:param filter: is the function used for filtering. Normally `filename` is a
|
||||
.py file and `filter` is a function that bytecode compiles the file.
|
||||
In this way the bytecode compiled file is cached. (Default = None)
|
||||
Args:
|
||||
key(str): the cache key
|
||||
filename: the file to cache
|
||||
filter: is the function used for filtering. Normally `filename` is a
|
||||
.py file and `filter` is a function that bytecode compiles the file.
|
||||
In this way the bytecode compiled file is cached. (Default = None)
|
||||
|
||||
This is used on Google App Engine since pyc files cannot be saved.
|
||||
"""
|
||||
|
||||
@@ -2,14 +2,15 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
This file is part of the web2py Web Framework
|
||||
Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
|
||||
License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
||||
| This file is part of the web2py Web Framework
|
||||
| Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
|
||||
| License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
||||
|
||||
Functions required to execute app components
|
||||
============================================
|
||||
---------------------------------------------
|
||||
|
||||
FOR INTERNAL USE ONLY
|
||||
Note:
|
||||
FOR INTERNAL USE ONLY
|
||||
"""
|
||||
|
||||
import re
|
||||
@@ -22,7 +23,7 @@ from gluon.storage import Storage, List
|
||||
from gluon.template import parse_template
|
||||
from gluon.restricted import restricted, compile2
|
||||
from gluon.fileutils import mktree, listdir, read_file, write_file
|
||||
from gluon.myregex import regex_expose
|
||||
from gluon.myregex import regex_expose, regex_longcomments
|
||||
from gluon.languages import translator
|
||||
from gluon.dal import BaseAdapter, SQLDB, SQLField, DAL, Field
|
||||
from gluon.sqlhtml import SQLFORM, SQLTABLE
|
||||
@@ -125,16 +126,27 @@ def LOAD(c=None, f='index', args=None, vars=None,
|
||||
extension=None, target=None, ajax=False, ajax_trap=False,
|
||||
url=None, user_signature=False, timeout=None, times=1,
|
||||
content='loading...', **attr):
|
||||
""" LOAD a component into the action's document
|
||||
""" LOADs a component into the action's document
|
||||
|
||||
Timing options:
|
||||
-times: An integer or string ("infinity"/"continuous")
|
||||
specifies how many times the component is requested
|
||||
-timeout (milliseconds): specifies the time to wait before
|
||||
starting the request or the frequency if times is greater than
|
||||
1 or "infinity".
|
||||
Timing options default to the normal behavior. The component
|
||||
is added on page loading without delay.
|
||||
Args:
|
||||
c(str): controller
|
||||
f(str): function
|
||||
args(tuple or list): arguments
|
||||
vars(dict): vars
|
||||
extension(str): extension
|
||||
target(str): id of the target
|
||||
ajax(bool): True to enable AJAX bahaviour
|
||||
ajax_trap(bool): True if `ajax` is set to `True`, traps
|
||||
both links and forms "inside" the target
|
||||
url(str): overrides `c`,`f`,`args` and `vars`
|
||||
user_signature(bool): adds hmac signature to all links
|
||||
with a key that is different for every user
|
||||
timeout(int): in milliseconds, specifies the time to wait before
|
||||
starting the request or the frequency if times is greater than
|
||||
1 or "infinity"
|
||||
times(integer or str): how many times the component will be requested
|
||||
"infinity" or "continuous" are accepted to reload indefinitely the
|
||||
component
|
||||
"""
|
||||
from html import TAG, DIV, URL, SCRIPT, XML
|
||||
if args is None:
|
||||
@@ -440,7 +452,8 @@ def read_pyc(filename):
|
||||
Read the code inside a bytecode compiled file if the MAGIC number is
|
||||
compatible
|
||||
|
||||
:returns: a code object
|
||||
Returns:
|
||||
a code object
|
||||
"""
|
||||
data = read_file(filename, 'rb')
|
||||
if not is_gae and data[:4] != imp.get_magic():
|
||||
@@ -481,6 +494,9 @@ def compile_models(folder):
|
||||
save_pyc(filename)
|
||||
os.unlink(filename)
|
||||
|
||||
def find_exposed_functions(data):
|
||||
data = regex_longcomments.sub('',data)
|
||||
return regex_expose.findall(data)
|
||||
|
||||
def compile_controllers(folder):
|
||||
"""
|
||||
@@ -491,7 +507,7 @@ def compile_controllers(folder):
|
||||
for fname in listdir(path, '.+\.py$'):
|
||||
### why is this here? save_pyc(pjoin(path, file))
|
||||
data = read_file(pjoin(path, fname))
|
||||
exposed = regex_expose.findall(data)
|
||||
exposed = find_exposed_functions(data)
|
||||
for function in exposed:
|
||||
command = data + "\nresponse._vars=response._caller(%s)\n" % \
|
||||
function
|
||||
@@ -515,7 +531,7 @@ def run_models_in(environment):
|
||||
|
||||
folder = environment['request'].folder
|
||||
c = environment['request'].controller
|
||||
f = environment['request'].function
|
||||
f = environment['request'].function
|
||||
response = environment['response']
|
||||
|
||||
path = pjoin(folder, 'models')
|
||||
@@ -525,10 +541,10 @@ def run_models_in(environment):
|
||||
models = sorted(listdir(cpath, '^models[_.][\w.]+\.pyc$', 0), model_cmp)
|
||||
else:
|
||||
models = sorted(listdir(path, '^\w+\.py$', 0, sort=False), model_cmp_sep)
|
||||
models_to_run = None
|
||||
models_to_run = None
|
||||
for model in models:
|
||||
if response.models_to_run != models_to_run:
|
||||
regex = models_to_run = response.models_to_run
|
||||
regex = models_to_run = response.models_to_run[:]
|
||||
if isinstance(regex, list):
|
||||
regex = re_compile('|'.join(regex))
|
||||
if models_to_run:
|
||||
@@ -537,7 +553,7 @@ def run_models_in(environment):
|
||||
fname = model[n:-4].replace('.','/')+'.py'
|
||||
else:
|
||||
n = len(path)+1
|
||||
fname = model[n:].replace(os.path.sep,'/')
|
||||
fname = model[n:].replace(os.path.sep,'/')
|
||||
if not regex.search(fname) and c != 'appadmin':
|
||||
continue
|
||||
elif compiled:
|
||||
@@ -570,7 +586,7 @@ def run_controller_in(controller, function, environment):
|
||||
filename = pjoin(path, 'controllers_%s_%s.pyc'
|
||||
% (controller, function))
|
||||
### end for backward compatibility
|
||||
if not os.path.exists(filename):
|
||||
if not os.path.exists(filename):
|
||||
raise HTTP(404,
|
||||
rewrite.THREAD_LOCAL.routes.error_message % badf,
|
||||
web2py_error=badf)
|
||||
@@ -602,7 +618,7 @@ def run_controller_in(controller, function, environment):
|
||||
rewrite.THREAD_LOCAL.routes.error_message % badc,
|
||||
web2py_error=badc)
|
||||
code = read_file(filename)
|
||||
exposed = regex_expose.findall(code)
|
||||
exposed = find_exposed_functions(code)
|
||||
if not function in exposed:
|
||||
raise HTTP(404,
|
||||
rewrite.THREAD_LOCAL.routes.error_message % badf,
|
||||
|
||||
@@ -2,22 +2,22 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
This file is part of the web2py Web Framework
|
||||
Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
|
||||
License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
||||
| This file is part of the web2py Web Framework
|
||||
| Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
|
||||
| License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
||||
|
||||
CONTENT_TYPE dictionary created against freedesktop.org' shared mime info
|
||||
CONTENT_TYPE dictionary created against freedesktop.org's shared mime info
|
||||
database version 1.1.
|
||||
|
||||
Deviations from official standards:
|
||||
- '.md': 'application/x-genesis-rom' --> 'text/x-markdown'
|
||||
- '.png': 'image/x-apple-ios-png' --> 'image/png'
|
||||
- .md: application/x-genesis-rom --> text/x-markdown
|
||||
- .png: image/x-apple-ios-png --> image/png
|
||||
Additions:
|
||||
- '.load': 'text/html'
|
||||
- '.json': 'application/json'
|
||||
- '.jsonp': 'application/jsonp'
|
||||
- '.pickle': 'application/python-pickle'
|
||||
- '.w2p': 'application/w2p'
|
||||
- .load: text/html
|
||||
- .json: application/json
|
||||
- .jsonp: application/jsonp
|
||||
- .pickle: application/python-pickle
|
||||
- .w2p': application/w2p
|
||||
"""
|
||||
|
||||
__all__ = ['contenttype']
|
||||
|
||||
@@ -159,6 +159,8 @@ def extension(url):
|
||||
|
||||
def expand_one(url, cdict):
|
||||
# try ombed but first check in cache
|
||||
if '@' in url and not '://'in url:
|
||||
return '<a href="mailto:%s">%s</a>' % (url, url)
|
||||
if cdict and url in cdict:
|
||||
r = cdict[url]
|
||||
else:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user