Compare commits

..

490 Commits

Author SHA1 Message Date
mdipierro 2802e29945 2.9.5 2014-03-15 21:25:04 -05:00
mdipierro e9eb8cbfc7 Merge pull request #403 from pyner/master
Update default.py
2014-03-15 21:09:44 -05:00
mdipierro d343d8380c Merge pull request #401 from niphlod/docs/n-p
sphinx-compatible docstrings
2014-03-15 21:08:05 -05:00
mdipierro 02906fa39f Merge pull request #400 from timrichardson/issues/1898s
better error handling in jsonrpc requests
2014-03-15 21:07:31 -05:00
mdipierro c1e797fe24 removed gluon/contrib/translitcodec because of backward compatibility issues and because it breaks Pypy 2014-03-15 10:54:48 -05:00
Massimo d7a42d8445 fixed problem with groups 2014-03-14 09:00:19 -05:00
samuel bonilla 4f82bed52e Update default.py
new alert: it's a plugin is not an application
2014-03-13 20:04:00 -05:00
mdipierro 84365f6721 fixed problem with circular imputs on GAE? 2014-03-13 08:41:31 -05:00
niphlod e209dcc8d3 sphinx-compatible docstrings 2014-03-12 22:03:42 +01:00
Tim Richardson cd15a0f983 better error handling in jsonrpc requests 2014-03-13 07:29:42 +11:00
mdipierro eb435e785c Merge pull request #399 from timrichardson/issues/1898
jsonrpc2 requests need mandatory key/pair jsonrpc:'2.0'
2014-03-12 13:39:05 -05:00
mdipierro f03e521120 Merge pull request #398 from niphlod/docs/h-m
sphinx-compatible docstrings
2014-03-12 13:37:42 -05:00
mdipierro 883909af4b reverted s.encode('translit/long') which breaks Pypy 2014-03-12 13:31:09 -05:00
Tim Richardson 13d66433e7 jsonrpc2 requests need mandatory key/pair jsonrpc:'2.0' 2014-03-12 22:38:29 +11:00
niphlod c44cfcb27c sphinx-compatible docstrings 2014-03-11 22:18:33 +01:00
mdipierro c14e5cbae5 Merge pull request #396 from niphlod/docs/html
sphinx-compatible docstrings
2014-03-11 10:51:31 -05:00
niphlod f09e0b4205 sphinx-compatible docstrings 2014-03-10 22:21:33 +01:00
mdipierro ad72cea9a6 fixed issue 1891:Remove response.meta.description from menu.py in welcome app, thanks sourcingp 2014-03-09 17:29:41 -05:00
mdipierro c289bc4239 fixed issue 1893:backwards compatibility problem with grid parameter exportclasses, thanks mweissen 2014-03-09 17:26:40 -05:00
mdipierro 733fa01b7e fixed issue 1894:represent requires 2 arguments in dal.py, thanks mweissen 2014-03-09 17:22:39 -05:00
mdipierro 4d03460944 fixed startup message, thanks mweissen 2014-03-09 17:19:03 -05:00
mdipierro b3ba5d9eaa Merge pull request #393 from niphlod/fix/tests
fix travis.yml to fetch the latest release of gae
2014-03-09 09:11:03 -05:00
mdipierro 9e8ef3585e fixed problem with login bare when registration_key is None 2014-03-09 08:55:22 -05:00
niphlod 5c9cf44720 fix travis.yml to fetch the latest release of gae (needs manual update whenever a version changes) 2014-03-09 14:11:53 +01:00
mdipierro 05a0d19ee9 cleanup 2014-03-08 14:40:34 -06:00
mdipierro d38adbe6ca Merge pull request #392 from apa-1/master
Fix for session unique_key query
2014-03-08 14:32:27 -06:00
mdipierro 871981cec7 Merge pull request #391 from michele-comitini/oauth_content-type
oauth strip encoding part in content-type response from server.
2014-03-08 14:31:32 -06:00
mdipierro 8a54001e11 Merge pull request #390 from dokime7/master
Fix DAL ADD method
2014-03-08 14:30:42 -06:00
mdipierro 1e59f6e8be Merge pull request #389 from timrichardson/issues/1888
add Recaptcha(...ajax=True) to use ajax api, fix Recaptcha in LOAD issue/1888
2014-03-08 14:29:58 -06:00
mdipierro 0e1eb5b56e Merge branch 'master' of github.com:web2py/web2py 2014-03-08 14:28:49 -06:00
mdipierro e43df945b4 no more pypy test for today 2014-03-08 14:28:18 -06:00
mdipierro c23706b794 Merge pull request #388 from gitanoqevaporelmundoentero/master
dal.py: Table class: validate_and_update_or_insert method created, validate_and_update minor changes
2014-03-08 14:15:43 -06:00
alex 98cd10c6f5 Fix for session unique_key query 2014-03-08 14:37:15 -05:00
Michele Comitini 55b92e854c use mimemessage method gettype() to extract content-type 2014-03-07 18:01:41 +01:00
Michele Comitini 0c926d60b8 oauth strip encoding part in content-type response from server. 2014-03-07 17:31:20 +01:00
Oscar Rodriguez d4d91fd003 dal.py: Table class: validate_and_update_or_insert method created 2014-03-07 16:22:09 +01:00
Jeremie Dokime 89c4efbac3 Fix DAL ADD method
Fix regression of ADD method:
NameError: global name 'gluon' is not defined
2014-03-06 17:56:11 +01:00
Oscar Rodriguez 3a5a34da0a dal.py: Table class: validate_and_update_or_insert method created, and minor changes in validate_and_update 2014-03-06 12:06:57 +01:00
Tim Richardson cf3992545d add Recaptcha(...ajax=True) to use ajax api, fix Recaptcha in LOAD 2014-03-06 09:40:48 +11:00
Oscar Rodriguez 0b7f663d43 dal.py: Table class: validate_and_update_or_insert method created, and minor changes in validate_and_update 2014-03-05 19:46:19 +01:00
Oscar Rodriguez abd72f8df0 dal.py: Table class: validate_and_update_or_insert method created, and minor changes in validate_and_update 2014-03-05 17:44:56 +01:00
mdipierro 1abdf72a04 2.9.4 2014-03-04 22:42:22 -06:00
mdipierro 7c536b66d0 Merge branch 'master' of github.com:web2py/web2py 2014-03-04 22:40:00 -06:00
mdipierro cc1c019216 Merge pull request #387 from apa-1/master
Added 'from_address' to allow for separation of 'envelope sender' and 'f...
2014-03-04 22:39:40 -06:00
mdipierro d20f231b34 fixed memdb anc session issue 1885 2014-03-04 22:33:50 -06:00
mdipierro 8b03bf5fd9 fixed gae_memacache issue 1887, thanks mjwatson 2014-03-04 22:28:35 -06:00
alex af4025731a Added 'from_address' to allow for separation of 'envelope sender' and 'from' in email 2014-03-04 13:10:08 -05:00
mdipierro 77bbb405fb 2.9.3 2014-03-03 08:50:52 -06:00
mdipierro 7592cd2fe0 always reset the session when auth session expires 2014-03-03 08:44:02 -06:00
mdipierro c5b996c8b1 fixed problem with too many sessions 2014-03-03 08:14:36 -06:00
mdipierro ae0749d6b8 reverted some bs3 changes 2014-03-03 08:13:37 -06:00
mdipierro 666a389718 2.9.2 2014-03-02 17:47:33 -06:00
mdipierro 6cd2bf9fea better transliteration in slugs, thanks winniehell 2014-03-02 17:45:45 -06:00
mdipierro 3ad7ea6df8 Merge branch 'master' of github.com:web2py/web2py 2014-03-02 17:24:42 -06:00
mdipierro cb75a96e2c Merge pull request #315 from winniehell/patch_urlify_translitcodec
Use translitcodec for urlify
2014-03-02 17:24:07 -06:00
mdipierro 70965f4b69 alterante solution for https://github.com/web2py/web2py/pull/215 2014-03-02 17:19:33 -06:00
mdipierro 29042f08a1 back to bs2 2014-03-02 17:17:21 -06:00
mdipierro 379db55111 Merge branch 'master' of github.com:web2py/web2py 2014-03-02 16:54:05 -06:00
mdipierro 4a65e773ce Merge pull request #386 from timrichardson/bs3_grid
change button & icon classes for bootstrap 3 (SQLFORM.grid)
2014-03-02 16:53:53 -06:00
mdipierro 2829a91ff7 Merge branch 'master' of github.com:web2py/web2py 2014-03-02 16:51:39 -06:00
mdipierro 083e75bfb1 Merge pull request #385 from mcamel/patch-2
Update es.py
2014-03-02 16:51:28 -06:00
mdipierro 8f95e6ebb3 Merge branch 'master' of github.com:web2py/web2py 2014-03-02 16:50:49 -06:00
mdipierro 6b1826e8da Merge pull request #384 from mcamel/patch-1
Update tools.py
2014-03-02 16:50:40 -06:00
mdipierro f76598232a Merge branch 'master' of github.com:web2py/web2py 2014-03-02 16:49:57 -06:00
mdipierro 193149abac Merge pull request #383 from leonelcamara/master
Fix email date header format
2014-03-02 16:49:50 -06:00
mdipierro 8c155d9f76 Merge branch 'master' of github.com:web2py/web2py 2014-03-02 16:48:25 -06:00
mdipierro 2061cc3674 Merge pull request #382 from apa-1/master
Added password option for redis_cache and redis_session
2014-03-02 16:48:16 -06:00
Tim Richardson 832d6c2e97 bootstrap 3 icons for SQLFORM.grid 2014-03-03 06:16:09 +11:00
Tim Richardson e0870bbdb2 change buttons classes for bootstrap 3 2014-03-01 12:25:08 +11:00
mdipierro 297983f411 some minor changes 2014-02-28 18:38:06 -06:00
mdipierro 1e9872c015 welcome more bootstrap3 compliant, thanks Paolo Caruccio 2014-02-27 09:33:26 -06:00
mcamel 7ddf0af81b Update es.py
Major spanish language revision.
2014-02-27 12:35:41 +01:00
mcamel 359bae6d30 Update tools.py
Internationalize 'ACCESS DENIED' message.
2014-02-27 12:09:34 +01:00
Leonel Câmara d01add8f2b Revert "convert session to dict before pickling"
This reverts commit 36303e338d.
2014-02-25 12:54:31 +00:00
Leonel Câmara 752a1c7df6 Update tools.py
Fixed email date header not respecting the RFC2822 defined format

See:
https://groups.google.com/forum/#!topic/web2py/0Mb99H9kJOw
2014-02-25 12:29:51 +00:00
mdipierro 0d24d1e0d2 removed unwanted files, added respond.min.js 2014-02-24 23:57:34 -06:00
alex 31fcf51506 Added password option for redis_cache and redis_session 2014-02-24 19:01:27 -05:00
mdipierro f3c5ed8ee6 added some bs3 files 2014-02-24 00:09:39 -06:00
mdipierro 76d77439b7 2.9.0-beta 2014-02-23 23:33:32 -06:00
mdipierro 2b428c7eb9 fixed navbar menu 2014-02-23 22:42:26 -06:00
mdipierro 106d4be274 fixed the bs3 left menu but not the login menu 2014-02-23 22:18:08 -06:00
Massimo 8e5d6bc467 partial bootstrap3 port, menus broken, thanks Paolo, sorry I broke it 2014-02-21 11:15:43 -06:00
mdipierro e21aca045a fixed possible problem with session 2014-02-20 22:23:39 -06:00
mdipierro a359afb799 Merge branch 'master' of github.com:web2py/web2py 2014-02-19 08:51:03 -06:00
mdipierro 41fb55cb01 Merge pull request #381 from gitanoqevaporelmundoentero/master
dal.py: DAL: parse_as_rest: solved problem when displaying tables containing more than one PK
2014-02-19 08:50:51 -06:00
mdipierro f8cc65dfae Merge branch 'master' of github.com:web2py/web2py 2014-02-19 08:50:41 -06:00
mdipierro e94368a356 Merge pull request #380 from timrichardson/export_widget_bootstrap
added bootstrap class btn to export widget
2014-02-19 08:50:16 -06:00
mdipierro 2c8f2173a3 w2p_even and w2p_odd in grid 2014-02-19 08:43:40 -06:00
Oscar Rodriguez 65eb1e9cb7 DAL: parse_as_rest: solved problem when displaying tables containing more than one primary key 2014-02-18 16:27:55 +01:00
Tim Richardson 69ecbdfecc added bootstrap class btn to export widget 2014-02-18 06:19:57 +11:00
mdipierro 6c622b4100 Merge pull request #374 from carpaIdea/master
greater flexibility for SQLTABLE row customization by using css
2014-02-15 11:35:07 -06:00
mdipierro 59b645c399 Merge pull request #379 from timrichardson/issues/1866
Issues/1866 (grid export): change csv export to use represent, no change to csv hidden cols or others.
2014-02-14 22:35:05 -06:00
mdipierro 134723a54b Merge pull request #378 from mcabo/patch-2
Update dal.py Table:validate_and_update
2014-02-14 22:34:10 -06:00
mdipierro c482fed2c9 Merge pull request #375 from gitanoqevaporelmundoentero/master
dal.py: BaseAdapter: insert: solved problem when creating new record wit...
2014-02-14 22:33:20 -06:00
mdipierro f60846ea2e catch more errors when invalid session cookie, thanks Luca 2014-02-14 22:31:05 -06:00
mdipierro cb23f8635a fixed smartgrid bug, thanks Anthony 2014-02-14 22:27:39 -06:00
mdipierro 19f8f6bf3c SQLCustomType endswith 2014-02-14 21:03:52 -06:00
Tim Richardson b036cb04ff remove blank line 2014-02-15 08:10:42 +11:00
Tim Richardson 050efa339d missed a label 2014-02-15 08:02:53 +11:00
Tim Richardson faeff098fe rows.export_to_csv_file assumes the function field.represent takes only one argument, which was causing a ticket with virtua fields 2014-02-15 07:52:43 +11:00
Tim Richardson 4e298ed7d8 1866: small functionality change, better explanation.
Better 'tooltip' documention for different export formats.
Don't refer to Excel, say spreadsheet instead.
Only functionality change is standard CSV uses the rows.export_to_csv(..., represent=True) to make the output look like the on-screen grid representation.
The other formats are not changed, so both TSV and TSV with hidden columns do represent, and CSV with hidden columns does not (for speed)
2014-02-15 06:30:03 +11:00
mcabo c810e4491a Update dal.py Table:validate_and_update
Validation has been fixed on validate_and_update method
2014-02-14 15:32:58 +01:00
Oscar Rodriguez edbf45e542 dal.py: BaseAdapter: insert: solved problem when creating new record without passing the primary key as argument 2014-02-14 11:20:29 +01:00
mdipierro caee53e778 fixed IS_TIME()('12:00 am') 2014-02-11 08:12:12 -06:00
Oscar Rodriguez 55281650e2 dal.py: BaseAdapter: insert: solved problem when creating new record without passing the primary key as argument 2014-02-10 19:50:18 +01:00
Paolo Caruccio ff17b551b4 greater flexibility for row customization by using css 2014-02-06 16:25:42 +01:00
mdipierro 4c3ab339cd Merge pull request #373 from timrichardson/grid_search_widget_labels
Better button labels for grid search widget
2014-02-02 14:33:08 -08:00
Tim Richardson 99d64722a1 Better button labels for grid search widget
This is a second attempt at search widget buttons.
The create "+Add" is now "+Add Record".
The first search button becomes "New Search", and the And and Or buttons become "+ And" and "+ Or" (to hint that they add terms to the search). There are tool tips on all these buttons now
2014-02-02 18:15:57 +11:00
mdipierro 1b12bcb5d9 Merge pull request #372 from timrichardson/search_widget_button_label_change
Minor usability improvement to grid search widget
2014-01-31 15:09:06 -08:00
mdipierro 7a083865dd Merge pull request #371 from timrichardson/issues/1859
Issues/1859 export from grid fails when virtual fields are present
2014-01-31 15:08:21 -08:00
Tim Richardson 794b6bcb7b Minor usability improvement to grid search widget
changed the button "New" to "Add" and added a title attribute (view on hover) explaining what this button does
2014-01-31 16:45:57 +11:00
Tim Richardson 64ccd9043e fixed comment 2014-01-31 16:26:42 +11:00
Tim Richardson 18af4e92b0 when exporting hidden columns, pick up all virtual fields, even those not on display. 2014-01-31 14:45:45 +11:00
Tim Richardson cfbae50248 step 2 of fixing export from grids when there are virtual fields. Note export hidden columns includes all table fields and any virtual fields which are displayed, but it does not pick up virtual fields which are not displayed. 2014-01-31 13:44:25 +11:00
Tim Richardson 20576684dd Step 1 in fixing 1859: this stops the crashing, but virtual fields are not exported 2014-01-31 12:02:46 +11:00
mdipierro 1c2bdd1654 fixed issue 1862, readline problem in cpdb, thanks kmelevskiy 2014-01-30 08:44:19 -06:00
mdipierro 93aa1a13c6 Merge pull request #370 from niphlod/docs/refactor_c_d_f_g_h
more docstring fixes
2014-01-30 06:07:11 -08:00
mdipierro 4cd86a397c Merge pull request #369 from spametki/issue1828
Fixes issue1828
2014-01-30 06:06:34 -08:00
mdipierro efcb203dd9 Merge pull request #368 from nicozanf/patch-1
Design cleanup
2014-01-30 06:05:48 -08:00
mdipierro c859785edc Merge pull request #367 from timrichardson/issues/1864
fixed a bug in SQLFORM.grid where export would fail if a search filter a...
2014-01-30 06:04:56 -08:00
niphlod 41a4de081f more docstring fixes 2014-01-29 23:01:52 +01:00
Alan Etkin 82a8d41ac6 Fixes issue1828 2014-01-29 10:54:08 -03:00
Nico Zanferrari d274389a33 Design cleanup 2014-01-29 12:06:12 +01:00
Tim Richardson faecb124cc fixed a bug in SQLFORM.grid where export would fail if a search filter applied to a non-visible column 2014-01-29 18:55:32 +11:00
mdipierro ce2d958f9a Merge pull request #366 from spametki/testdalmongodb
Add mongodb and imap tests for dal
2014-01-28 13:43:07 -08:00
mdipierro e37c8ff87f Merge pull request #365 from michele-comitini/entity_quoting_parameter
added entity_quoting (False by default) parameter to DAL
2014-01-28 13:42:37 -08:00
mdipierro fd2136875e Merge pull request #364 from niphlod/enhancement/docstrings
docstrings fixes
2014-01-28 13:41:41 -08:00
Alan Etkin 35d56ec3f0 Add mongodb and imap tests for dal
Added mongodb uri string for tests
2014-01-28 17:46:05 -03:00
Michele Comitini 310528ea10 added entity_quoting (False by default) parameter to DAL to optionally enable entity name quoting by adapters. 2014-01-28 17:45:15 +01:00
niphlod 98ee81606b docstrings fixes 2014-01-27 22:56:58 +01:00
mdipierro 6731eb9b2d min-width in highlight, thanks Andre 2014-01-27 15:50:52 -06:00
mdipierro e833783fb0 col patch, thanks Anthony 2014-01-26 15:52:24 -06:00
mdipierro 9d13d297cb improved Rows methods propagate parameters, thanks Anthony 2014-01-24 20:36:21 -06:00
mdipierro 2967969add Merge pull request #363 from niphlod/docs/admin
docstrings refactored
2014-01-24 18:32:50 -08:00
Massimo 060eddf812 fixed security issue with redirect after expired login, thanks André Kablu 2014-01-24 16:22:42 -06:00
niphlod 473d2d5d09 docstrings refactored 2014-01-24 22:17:43 +01:00
mdipierro 13cc8df4be Merge pull request #362 from niphlod/enhancement/disable_with
remove disable_with if not needed
2014-01-23 20:37:22 -08:00
mdipierro 39edd4679d Merge pull request #360 from spametki/master
NoSQL dal tests
2014-01-23 20:36:09 -08:00
mdipierro 4cd45abfdd Merge pull request #358 from ilvalle/create_view
online editor: shortcuts in a separated frame and style review
2014-01-23 20:34:44 -08:00
mdipierro cc297a06d3 Merge pull request #357 from niphlod/enhancement/scheduler_prevent_drift
added the prevent_drift parameter
2014-01-23 20:33:40 -08:00
niphlod 341a5e0c40 remove disable_with if not needed 2014-01-23 21:59:43 +01:00
ilvalle d967e23791 online editor: fix folding option 2014-01-22 18:24:51 +01:00
Alan Etkin 98610df1d4 NoSQL dal tests 2014-01-22 08:50:03 -03:00
ilvalle 7dd99cf3a1 online editor: shortcuts in a separated frame and style review 2014-01-21 14:45:56 +01:00
niphlod 9434baba11 added the prevent_drift parameter 2014-01-20 22:43:53 +01:00
mdipierro 4cbdf612af Merge pull request #356 from niphlod/fix/tests
someone forgot tests.... grrrr!
2014-01-20 13:14:37 -08:00
niphlod 0c6eaf536a someone forgot tests.... grrrr! 2014-01-20 21:28:44 +01:00
mdipierro 48870b1dd1 Merge pull request #355 from reingart/master
debugger and soap contrib update and fixes
2014-01-19 21:41:25 -08:00
Mariano Reingart 56121a9c9d fixed WebClient contrib to properly send raw data in POST methods 2014-01-19 18:30:29 -03:00
Mariano Reingart 0e0ae1b5be added soap client/server test (including for status 500 to check issue #153) 2014-01-19 18:29:42 -03:00
Mariano Reingart e956d83aa2 fixed issue 153: correct 500 status if there is a SOAP fault 2014-01-19 18:27:56 -03:00
Mariano Reingart bfce480a91 added soap examples app (used in tests) 2014-01-19 18:25:06 -03:00
Mariano Reingart 3df446c306 updated simple soap contrib (pysimplesoap version 1.11) 2014-01-19 16:57:08 -03:00
Mariano Reingart e10fd68f90 fixed issue 1839: catch exception if source code cannot be opened in the debugger 2014-01-19 14:07:00 -03:00
mdipierro cfd5842538 Merge pull request #354 from alfonsodg/master
fix bug related to upgrade setuptools / pip
2014-01-18 10:39:47 -08:00
mdipierro 56e95fd640 Merge pull request #353 from ilvalle/create_view
codemirror 3.21
2014-01-18 10:38:59 -08:00
mdipierro 52cf0dd147 Merge pull request #352 from viniciusban/empty_reference_field
Allow empty reference field in form without IS_EMPTY_OR() validator, avoiding constraint violation exception.
2014-01-18 10:37:39 -08:00
mdipierro 311404d03c Merge pull request #351 from kirsn/master
Update error_messages; capitalize first character
2014-01-18 10:36:33 -08:00
Alfonso de la Guarda Reyes 5900b3f1c7 fix bug related to upgrade setuptools / pip 2014-01-18 08:05:28 -05:00
ilvalle 45bc26f5eb codemirror 3.21 2014-01-18 10:13:56 +01:00
Vinicius Assef 45fc08e4a4 Allow empty reference field in form without IS_EMPTY_OR() validator, avoiding constraint violation exception 2014-01-17 18:20:43 -02:00
Kiran Subbaraman e3aa776f5a Update error_messages; capitalize first character
Result of a discussion: https://groups.google.com/forum/#!topic/web2py/IDkr4w_wKv4
The intent is to convert the first character of all error messages to a capital letter.
2014-01-16 10:57:34 +05:30
mdipierro 7101762082 Merge pull request #346 from dokime7/master
Fix concurrency handling in order to avoid that some workers get the same task at the same time.
2014-01-14 22:17:34 -08:00
mdipierro 34bbb376be allow URL(...,language=...) with parametric router, thanks Jonathan 2014-01-14 22:17:28 -06:00
mdipierro 391bdf5cd4 Merge pull request #349 from mbaser/patch-2
Create tr.py
2014-01-14 20:11:23 -08:00
mdipierro 1e4f533008 Merge pull request #348 from mbaser/patch-1
Update tr.py
2014-01-14 20:10:56 -08:00
mdipierro dfd35b1a62 Merge pull request #347 from niphlod/enhancement/DAL
first steps to a cleaner DAL and rname integration
2014-01-14 20:10:26 -08:00
mdipierro c7f6545f8a Merge pull request #345 from crimsoncantab/master
related to issue 1708 - bugfix to allow no expiration for gae_memcache
2014-01-14 20:08:28 -08:00
Mustafa Baser 71c6343aab Create tr.py 2014-01-14 13:30:59 +02:00
mbaser 65005ef93a Update tr.py 2014-01-14 13:27:10 +02:00
niphlod 7d59bcab72 first steps to a cleaner DAL and rname integration 2014-01-13 23:35:42 +01:00
Jeremie Dokime 3f200c245c Fix concurrency handling in order to avoid that some workers get the same task at the same time. 2014-01-13 15:17:58 +01:00
Loren McGinnis 378a696bfe related to issue 1708 - bugfix to allow no expiration for gae_memcache
When gae_memcache passed expiration time to memcache Client
(see commit 59290534bc),
logic is no longer needed to calculate time delta, since memcache
handles that for us.  Also, time_expire=0 was expiring values
immediately, instead of the documented behavior where 0 signified
no expiration.

Kept timestamp in value for backwards compatibility (is this
necessary since cached data is transient?)
2014-01-12 22:52:52 -07:00
mdipierro 200a953849 MARKMIN(...,_class='...') 2014-01-11 15:31:53 -06:00
mdipierro 0e95fba28d MARKMIN(...,_class='...') 2014-01-11 15:19:38 -06:00
mdipierro 907525efd7 fixed issue 1850, caching errors when unable to obtain plugin list 2014-01-11 15:03:10 -06:00
mdipierro d490b794db Merge pull request #343 from spametki/master
Remove illegal nosql command implementations
2014-01-11 05:07:04 -08:00
Alan Etkin f04cc69abe Remove illegal nosql command implementations 2014-01-11 09:51:10 -03:00
mdipierro c93ce5dbab reverted latest patch 2014-01-10 08:28:09 -06:00
mdipierro 23c65eb518 Merge branch 'master' of github.com:web2py/web2py 2014-01-10 08:26:43 -06:00
mdipierro 2cf0e4a7ff Merge pull request #341 from spametki/master
Added _insert for App Engine
2014-01-10 06:25:21 -08:00
Massimo c2a23d03c2 fixed issues with regex2 in validators? 2014-01-09 11:47:32 -06:00
mdipierro 09fb170a83 possibile regex fix 2014-01-09 08:38:39 -06:00
Alan Etkin 20e2d9aa57 Added _insert for App Engine 2014-01-09 09:41:27 -03:00
mdipierro 4192405444 IS_LIST_OF(other=[..]) 2014-01-08 13:43:49 -06:00
mdipierro 6bbafc5920 fixed 1843, commented functions should not appear as if they are exposed 2014-01-08 11:32:07 -06:00
mdipierro 1caf7b5140 fixed 1845:styling widget divs, thanks Paolo Caruccio 2014-01-08 11:16:51 -06:00
mdipierro 10e0ff71bf fixed login_bare uses registration_key without .strip() for boolean testing which causes failure, thanks Remco 2014-01-08 11:14:02 -06:00
mdipierro 5a0aec5b1d fixed LazyCrypt.__ne__, thanks Jonathan 2014-01-08 10:24:37 -06:00
mdipierro 9964add97c Merge pull request #339 from flavour/master
Fix for orderby_on_limitby with Table aliases
2014-01-08 07:51:41 -08:00
Fran Boon d5f04551f2 Fix for orderby_on_limitby with Table aliases 2014-01-07 22:36:22 +00:00
Fran Boon 8ba8eb58ed Merge branch 'master' of git://github.com/web2py/web2py 2014-01-07 21:26:31 +00:00
mdipierro 14cacefa96 fixed grid export in HTML 2014-01-07 02:14:11 -06:00
mdipierro 6d6a4d3d33 rearranged markmin.html 2014-01-07 02:00:52 -06:00
mdipierro e19f280e1b Merge pull request #338 from timrichardson/issue/1840
fix issue 1840, CAS failing due to redirect loop
2014-01-06 23:58:37 -08:00
Tim Richardson 40e5e42ecc fix issue 1840 2014-01-07 17:05:41 +11:00
mdipierro 1741a59d3a fixed routes.parametric.example.py, thanks Jonathan 2014-01-06 10:56:34 -06:00
mdipierro 7787317d06 fixed a problem with python version compatibility, thanks Anthony 2014-01-05 21:37:31 -06:00
mdipierro 76b3906ade fixed error message, thanks Anthony 2014-01-04 20:19:20 -06:00
mdipierro efcf8c0c95 fixed problem about excutesql(as_dict=True) and ambiguous column names, thanks Anthony 2014-01-03 22:00:02 -06:00
mdipierro 12bb4a8d93 removed 'if count > limits[1]-limits[0]:' in dal.py 2014-01-03 21:31:06 -06:00
mdipierro e56e376894 fixed issue 1836, Problem with IS_IN_DB(label='%(x)3.3s') 2014-01-03 20:58:57 -06:00
mdipierro 4b4ada4137 Merge pull request #337 from spametki/master
Adapted admin cache action for gae
2013-12-28 21:17:15 -08:00
Alan Etkin eb94780cd4 Adapted admin cache action for gae 2013-12-28 07:53:29 -03:00
mdipierro 750f963796 Merge pull request #336 from niphlod/fix/admin_saved_sessions
removed debug print statements
2013-12-27 15:09:50 -08:00
niphlod 08639e6691 removed debug print statements 2013-12-27 21:28:43 +01:00
mdipierro 1a959baa72 fixed problem with static_version in admin, issue 1832 2013-12-23 21:37:27 -06:00
mdipierro 227930e25b Merge pull request #335 from ilvalle/create_view
Save current working session in the online editor
2013-12-23 19:33:07 -08:00
ilvalle 88ce19d99f Save current working session in online editor 2013-12-21 15:32:20 +01:00
mdipierro 257733e0cc fixed a bug in models_to_run, thanks Anthony 2013-12-20 15:09:50 -06:00
mdipierro e0b147ead0 Merge pull request #334 from PeterQ2/master
Changed RPXAccount login_form due to end-of-life for Janrain legacy widget
2013-12-20 12:49:41 -08:00
petergovers 24283e7eeb Modified RPXAccount to be backward compatible with older Web2py versions 2013-12-20 21:28:47 +01:00
petergovers afe3f306e7 Revert "Changed rpxAccount login_form due to end-of-life for Janrain IFRAME/embedded widget"
This reverts commit c4a68e9e5a.
2013-12-20 21:27:56 +01:00
petergovers c4a68e9e5a Changed rpxAccount login_form due to end-of-life for Janrain IFRAME/embedded widget 2013-12-20 20:33:29 +01:00
mdipierro 67c35e5327 Merge pull request #333 from ilvalle/create_view
fix issue 1825
2013-12-19 20:29:10 -08:00
mdipierro 53f4408652 fixed web2py.css 100% thanks DeanK 2013-12-19 20:25:48 -06:00
ilvalle d72d5c64e2 fix issue 1825 2013-12-19 09:52:38 +01:00
Fran Boon 9ca4b48f95 Merge branch 'master' of git://github.com/web2py/web2py 2013-12-19 08:35:12 +00:00
mdipierro 338331aa54 Merge pull request #332 from spametki/master
admin app: enhanced ticket support for gae
2013-12-18 11:50:45 -08:00
Alan Etkin 42c0b7b0fa admin app: enhanced ticket support for gae 2013-12-18 15:44:45 -03:00
mdipierro 28b9d322a2 fixed 1821:RadioWidget and CheckboxesWidget wrong behavior, thanks Paolo Caruccio 2013-12-17 16:50:42 -06:00
mdipierro 38de99fc9c fixed 1820:uncaught pickling error with shell and app engine, thanks Alan 2013-12-17 16:43:07 -06:00
mdipierro a4416bd11f fixed issue 1819:Datastore reconnect problem, thanks Alan 2013-12-17 16:40:44 -06:00
mdipierro 27cbd242b2 Merge pull request #331 from spametki/master
Enable admin app for GAE (experimental)
2013-12-17 12:00:26 -08:00
mdipierro c790b79393 autolink emails 2013-12-16 21:56:28 -06:00
Alan Etkin 7646dc11fe Enable admin app for GAE (experimental) 2013-12-16 17:24:51 -03:00
mdipierro 104ec5ba73 fixed issue 1818, error in wiki/renderer, thanks Alan 2013-12-15 22:23:57 -06:00
mdipierro 53a0718a78 fixed problem with lack of connector in NoSQL 2013-12-15 13:31:56 -06:00
mdipierro 892f123975 Merge branch 'master' of github.com:web2py/web2py 2013-12-15 10:17:37 -06:00
mdipierro 461daca00e Merge pull request #330 from niphlod/fix/dal_quoting
fix mssql quoting issue, disabled some tests
2013-12-15 08:17:21 -08:00
niphlod 09c0069b43 fix mssql quoting issue, disabled some tests
Tests now pass on mssql. I think we need to agree on what's going on
with DAL, or we risk shipping a module with lots of changes that are
breaking backward compatibility. I'll start a thread on
web2py-developers
2013-12-15 15:06:42 +01:00
mdipierro 42de43d052 fixed 1814:session.connect: parameter migrate=False has no effect, thanks lucmurer 2013-12-14 20:03:35 -06:00
mdipierro 6ce51fa099 Merge pull request #329 from ilvalle/create_view
a more harmonic create_file in admin editor
2013-12-14 10:23:28 -08:00
ilvalle 51728fb192 a more harmonic create_file in admin editor 2013-12-14 09:37:30 +01:00
mdipierro d438b510df Merge pull request #328 from ilvalle/create_view
Manage w2p:enable-with in order to reuse form
2013-12-13 18:39:15 -08:00
ilvalle 2d669a50b2 Manage w2p:enable-with in order to reuse form 2013-12-13 12:09:52 +01:00
mdipierro 4aabf3c69c fixed typo, thanks User 2013-12-11 20:36:39 -06:00
mdipierro 69f9cf28df fixed db(((db.table1.field1 + db.table1.field2)>4)).select(), thanks Boris 2013-12-11 20:33:24 -06:00
mdipierro 81cb51bb8d Merge pull request #327 from ilvalle/create_view
invalidate function in web2py.js
2013-12-11 11:12:33 -08:00
ilvalle 371f97e050 invalidate function in web2py.js 2013-12-11 15:50:19 +01:00
mdipierro 3204447a74 Merge pull request #325 from niphlod/fix/web2py_websocket
fixed naming bug. Thanks @Peter Govers for the patch
2013-12-10 18:29:48 -08:00
Leonel Câmara 36303e338d convert session to dict before pickling
Session was constantly being pickled without converting to dict as it
should be.
2013-12-10 23:01:06 +00:00
niphlod b0b2fd7804 fixed naming bug. Thanks @Peter Govers for the patch 2013-12-10 21:08:39 +01:00
mdipierro a37206e259 Merge pull request #323 from ilvalle/comment
select the right app in the file list editor sidebar
2013-12-10 06:34:20 -08:00
ilvalle ff94a22826 fix reload of file list in editor when a new file is created 2013-12-10 11:13:04 +01:00
ilvalle 8244472cb2 select the right app in the file list editor sidebar 2013-12-10 09:53:50 +01:00
mdipierro 15dd46a91a reverted grouping of joined tables 2013-12-09 21:28:26 -06:00
mdipierro c379b00918 Merge branch 'master' of github.com:web2py/web2py 2013-12-09 21:20:49 -06:00
mdipierro 9bf856f6e6 Merge pull request #322 from robertop23/master
Allow create files from editor page in "files toggle"
2013-12-09 19:20:38 -08:00
robertop23 37df0a9338 Allow create files from editor page in "files toggle"
Once file is created show success message and reload using ajax the files

	modified:   applications/admin/controllers/default.py
	modified:   applications/admin/views/default/edit.html
2013-12-09 21:57:57 -04:30
robertop23 e6aaca1728 Allow create files from editor page in "files toggle"
Once file is created show success message and reload using ajax the files
	new file:   applications/admin/views/default/files_menu.html
	modified:   applications/admin/controllers/default.py
	modified:   applications/admin/views/default/edit.html
2013-12-09 21:51:55 -04:30
mdipierro bbbee21b0d DAL(...,adapter_args=dict(engine='MyISAM')) 2013-12-09 18:56:05 -06:00
mdipierro 6fb6f441d5 Merge pull request #321 from ilvalle/comment
toggleComment in admin editor
2013-12-09 16:37:15 -08:00
mdipierro cda7c66637 fixed bug in last commit, thanks User 2013-12-09 17:55:53 -06:00
mdipierro 53122bfa9f possible implementation of st_dwithin, thanks User 2013-12-09 17:06:25 -06:00
ilvalle 1fecd35bb7 toggleComment in admin editor 2013-12-09 14:38:10 +01:00
mdipierro 85058bd847 fixed this issue http://stackoverflow.com/questions/20363043/web2py-dal-left-join-and-operator-precedence 2013-12-08 09:33:30 -06:00
mdipierro 40c02651ae Merge pull request #320 from spametki/master
admin plugins page: show license information and small enhancements
2013-12-08 06:28:08 -08:00
mdipierro 8d72dc7bc4 Merge pull request #319 from ilvalle/todolist
better style for todolist panel (admin editor)
2013-12-08 06:27:26 -08:00
mdipierro 46d630a2c0 ST_DWithin for postgres 2013-12-08 08:26:00 -06:00
Alan Etkin 7e040a4177 admin plugins page: show license information and small enhancements 2013-12-08 11:01:21 -03:00
ilvalle 483de0fc30 better style for todolist panel (admin editor) 2013-12-08 10:18:47 +01:00
mdipierro 09277868d2 accept bitcoin donations 2013-12-07 20:47:08 -06:00
mdipierro 86a19c25a8 fixed issue 1808:HTML Injection on Terminal(shell) online 2013-12-07 18:36:37 -06:00
mdipierro 1715b0c378 fixed 1807:Preserve quote template for NoSQLAdapter and subclasses, thanks Alan and Michele 2013-12-07 10:20:29 -06:00
mdipierro 3599863304 fixed 1801:error in DAL using MongoDB with 'list:reference <table>', thanks Alan 2013-12-07 10:18:33 -06:00
mdipierro 91dc4f1d03 fixed issue 1806:auth.wiki does not create permissions correctly, thanks Florian 2013-12-07 10:16:21 -06:00
mdipierro 4b124cc214 Merge pull request #318 from ilvalle/todolist
Todolist panel in admin editor
2013-12-06 18:28:18 -08:00
mdipierro 0ed01e5a21 enable killing processed in windows, thanks Yair 2013-12-06 20:15:41 -06:00
ilvalle b7192d706c todolist panel (frontend part), by clicking on the TODO the relatve file is opened in a tab and the cursor is placed at the right line 2013-12-06 12:37:33 +01:00
ilvalle 557e4892b0 todo panel view 2013-12-05 11:49:21 +01:00
ilvalle b61b0bf3ad todo panel in admin editor 2013-12-05 11:43:23 +01:00
mdipierro 3a6a8af9f6 fixed typo in spreadsheet, thanks Alan 2013-12-04 19:35:43 -06:00
mdipierro 5b7167436b optional label in checkbox widget, fixed issue 1797, thanks Richard 2013-12-04 10:43:50 -06:00
mdipierro 8d4b4430de Merge pull request #317 from michele-comitini/entity_quoting
quoting of tablenames and field names
2013-12-04 08:34:52 -08:00
mdipierro 9d4cb09fdf fixed typo, thanks Dean 2013-12-03 09:32:42 -06:00
Michele Comitini 14bcad629e quoting of tablenames and field names
fix for wrong sequence name quoting

fix for wrong sequence name quoting 2

reverted test to quoted rname

rname passed asis. freedom in table names and field names. Case sensitivity in field and table names

removed test of allowed char sequence in table and field names, there is no limit anymore

fixed some troubles with postgresql drop(). Better Row.__getitem__(): should not be much slower.  Added a ignore_field_case parameter to allow Field('F')!=Field('f') on databases supporting case sesitivity.

different mysql drivers handled in quoting test.

improved handling of foreing keys

fix with quoted names in SQLTABLE.  fix for ORDER BY

handle references on non "id" fields

check reference expression against table list first
2013-12-03 12:29:30 +01:00
mdipierro 645c3b10dd fixed issue 1783 again, thanks Dean Kleissas 2013-12-03 00:41:51 -06:00
mdipierro 16f9222847 Merge pull request #316 from anssih/fix/ndb-lists
Fix list types in GAE NDB after entity write
2013-12-02 19:41:26 -08:00
Anssi Hannula b7e7c8caf2 Fix list types in GAE NDB after entity write
As per
http://code.google.com/p/appengine-ndb-experiment/issues/detail?id=208
("List items from repeated StringProperty get mutated to _BaseValue on
put") it seems to be expected behavior that lists in NDB models get
mutated to _BaseValue lists after .put() is called.

In web2py this corresponds to:
------------
db.define_table('listintegertest',
	Field('dummy', 'boolean'),
	Field('integerlist', 'list:integer'),
	Field('stringlist', 'list:string'),
)

iidee = db.listintegertest.insert(
	integerlist=[1,2,3,4],
	stringlist=["1","2","3","4"]
)
row = db.listintegertest(iidee)
db.listintegertest[row.id] = dict(dummy=True)

print "type is %s" % (type(row.integerlist[0]))
print "type is %s" % (type(row.stringlist[0]))
------------

The output of the above is currently:
type is <class 'google.appengine.ext.ndb.model._BaseValue'>
type is <class 'google.appengine.ext.ndb.model._BaseValue'>
while this is expected:
type is <type 'int'>
type is <type 'unicode'>

The workaround is to copy the list from the NDB model instead of
relying on it not being changed afterwards.

list:reference is not affected since parse_list_references() already
recreates the list in NoSQLAdapter case.
2013-12-02 23:27:21 +02:00
winniehell 15cedc0269 remove unnecessary imports 2013-12-02 22:22:41 +01:00
winniehell b14831613e use translitcodec for urlify 2013-12-02 21:35:48 +01:00
Jason Kirtland b673593683 add translitcodec to contrib 2013-12-02 21:33:34 +01:00
mdipierro 7703d959ef fixed request.user_agent().get('is_mobile', False), thanks Jonathan 2013-12-02 10:28:13 -06:00
mdipierro cb47024f2b Merge pull request #314 from oscarfonts/oracle-extract
extract_oracle_models.py script
2013-12-02 08:18:44 -08:00
mdipierro 55cbc1830a fixed issue 1795:MongoDB: DAL instantiation dict definition error, thanks Alan 2013-12-02 02:07:17 -06:00
mdipierro 3f61d725c4 Merge branch 'master' of github.com:web2py/web2py 2013-12-02 01:29:31 -06:00
mdipierro bc8bc03fd2 Merge pull request #312 from anssih/fix/ndb-refs
Fix references with GAE in NDB mode
2013-12-01 23:29:14 -08:00
mdipierro cbc20782ae Merge branch 'master' of github.com:web2py/web2py 2013-12-01 19:48:59 -06:00
mdipierro af290117d4 Merge pull request #311 from pyner/patch-2
Update access.py
2013-12-01 17:48:43 -08:00
mdipierro 42a662a7ad Merge branch 'master' of github.com:web2py/web2py 2013-12-01 19:48:28 -06:00
mdipierro 2ead96313b Merge pull request #310 from pyner/patch-1
Update buttons.py
2013-12-01 17:48:05 -08:00
Anssi Hannula fcd9e0d5c6 Fix references with GAE in NDB mode
For reference types the IntegerProperty class (no matter if NDB or
not) constructor is passed the referenced table name as the first
parameter.

For non-NDB, the first parameter is 'verbose_name'. For NDB, the first
parameter is 'name'.

In NDB mode this causes the property to have a wrong identity and
therefore references fail to work properly.

The verbose_name set in non-NDB mode is relatively harmless in
comparison, but seems to be wrong as well as it does not really make
sense.

Do not pass referenced table name to the IntegerProperty constructor in
either case.
2013-12-01 23:36:25 +02:00
samuel bonilla 593540e467 Update access.py
<type 'exceptions.AttributeError'> 'dict' object has no attribute 'is_mobile'"
2013-12-01 11:39:37 -05:00
samuel bonilla f66d0e1200 Update buttons.py
<type 'exceptions.AttributeError'> 'dict' object has no attribute 'is_mobile'"
2013-12-01 11:37:29 -05:00
mdipierro fa1c719c96 removed conflict from languages, thanks Niphlod 2013-12-01 10:00:05 -06:00
mdipierro 77b66d6015 fixed conflict 2013-11-30 16:50:31 -06:00
Fran Boon 8c14ba01f7 Merge branch 'master' of github.com:flavour/web2py 2013-11-29 12:13:55 +00:00
Fran Boon ad87d196e5 Enhance encoding header of languages/*.py 2013-11-29 12:07:36 +00:00
mdipierro aac892364c R-2.8.2 2013-11-28 07:52:24 -06:00
mdipierro 64b670fd8f fixed issue with scheduler and cache.disk introduced in 2.8.1 2013-11-28 07:50:55 -06:00
mdipierro a55c6777d3 R-2.8.1 2013-11-27 13:54:04 -06:00
mdipierro f9e16557c4 Merge pull request #308 from niphlod/issue/1780
fixes issue 1780
2013-11-27 10:00:49 -08:00
mdipierro 165b682e01 no more drawer open in edit mode 2013-11-27 12:00:21 -06:00
niphlod 92ab6dc635 fix issue 1780 2013-11-25 22:46:27 +01:00
mdipierro 0385ce6eb2 allow add_button(...,'javascript:') 2013-11-25 15:22:21 -06:00
mdipierro 5ba6e8fea2 Merge pull request #307 from erikmontes/patch-1
Comment documentation typo correction
2013-11-25 10:50:05 -08:00
mdipierro 8979c0919f Merge pull request #306 from ilvalle/git-fix
fix issue-1789
2013-11-25 10:49:05 -08:00
Erik Montes b9048b6d65 Comment documentation typo correction 2013-11-25 10:34:55 -08:00
ilvalle 3592dba7f5 fix issue-1789 2013-11-25 09:49:43 +01:00
mdipierro a7defed64c no more Tkinter is not necessary 2013-11-24 20:33:31 -06:00
mdipierro ff2f11a706 generic.jsonp raises HTTP(404) 2013-11-24 09:44:08 -06:00
mdipierro 84cc47920b Merge branch 'cm-3.20' of https://github.com/ilvalle/web2py into ilvalle-cm-3.20 2013-11-23 21:49:54 -06:00
mdipierro f57d96d64d no more 2.5 testing on Travis 2013-11-23 21:49:34 -06:00
mdipierro c310627d1b possibly fixed the PyPy testing problem 2013-11-23 21:42:09 -06:00
ilvalle be66f53c7e fix form action 2013-11-24 00:20:13 +01:00
mdipierro 77f32a8f4b wmv in expand all 2013-11-22 21:20:47 -06:00
mdipierro 9b8a24eeb9 fixed undefined form last commit 2013-11-22 12:14:08 -06:00
mdipierro c87bf553f6 fixed issue 1783:Forgot password and forgot username functionality breaks when multiple usernames are created against the same email address 2013-11-22 10:50:29 -06:00
mdipierro 2361eb4a84 fixed issue 1786:Allow formargs to override grid parameters., thanks iiijjjiii 2013-11-22 10:25:22 -06:00
mdipierro 4f4cc8f98f fixed link to download jquery plugin 2013-11-22 10:18:29 -06:00
mdipierro 5f1caf668b colnames in grid, thanks Niphlod, Arnon, and Paolo 2013-11-22 08:38:12 -06:00
mdipierro 054152f162 extract_oracle_models.py 2013-11-20 10:24:08 -06:00
mdipierro 78cf9df6ef Retire the Splash Screen and Beautify GUI., thanks skyscooby 2013-11-20 09:41:04 -06:00
mdipierro 2924b20c92 Merge pull request #303 from skyscooby/master
Retire the Splash Screen and Beautify GUI.
2013-11-20 07:19:50 -08:00
mdipierro f6318ae86c Merge pull request #301 from gi0baro/issue1772
Issue #1772: let the user choose uploads_in_blob with mongodb
2013-11-20 07:17:49 -08:00
Massimo e57907de35 do not truncate on delete 2013-11-19 17:38:13 -06:00
Massimo df2f9e7119 NDB accepts set, list and tuple, thanks Quint 2013-11-19 17:07:19 -06:00
Andrew Greenwood 23d7eb7a43 Retire the Splash Screen and Beautify GUI.
Lets give 5 seconds back to most users on startup by retiring the
artificial Splash Screen. Replace with a prettier server manager window.

-Makes product feel faster.
-Looks much better
-Fixes bug where two windows are created when using (-Q)
-Blocks resize on UI window.
-Window is now labeled ProgramName
2013-11-19 16:49:28 -05:00
Oscar Fonts 99a6dbeac2 extract_oracle_models.py script, for legacy Oracle 11g databases 2013-11-19 19:27:34 +01:00
Oscar Fonts b05daddc5c Copy extract_pgsql_models as extract_oracle_models 2013-11-19 19:17:11 +01:00
mdipierro 6868ddeed5 fixed 1779:Query class __str__ method should cast non string values, thanks Alan 2013-11-18 15:41:32 -06:00
mdipierro 8de6bff2fb fixed (again) issue 1774:CAS client broken when using routes.py, thanks remco.boerma 2013-11-18 15:37:52 -06:00
gi0baro 9028ec9857 Issue #1772: let the user choose uploads_in_blob with mongodb 2013-11-18 01:02:43 +01:00
mdipierro 8696a01eda some GAE optimization, thanks Quint 2013-11-17 13:36:35 -06:00
mdipierro f8f91c6a6a experiment with mongodb and belongs 2013-11-17 12:03:20 -06:00
mdipierro 97739e9e8a in mongodb uploads_in_blob = False, because of https://code.google.com/p/web2py/issues/detail?id=1772, thanks Alan 2013-11-17 09:32:01 -06:00
mdipierro 16b68572cd attempt to support GAE IN operator, thanks Quint 2013-11-17 09:28:46 -06:00
mdipierro d6e63b4d7c simpled int to hex conversion of mongo id, thanks Alan 2013-11-17 09:21:16 -06:00
mdipierro a6e8111484 Merge pull request #300 from spametki/master
MongoDB: fixed object_id function (hex values)
2013-11-17 07:15:33 -08:00
Alan Etkin bdc214f45b MongoDB: fixed object_id function (hex values) 2013-11-16 17:16:59 -03:00
mdipierro a91570768e fixed typo 2013-11-16 11:52:18 -06:00
mdipierro d35321c6c6 improvements to GoogleAdapter, thanks Quint 2013-11-16 04:10:18 -06:00
mdipierro e482cba237 minor dal rewrite in real_referenced 2013-11-16 03:54:30 -06:00
mdipierro c7cf13f8ea minor rewrite of mongoDB adapter 2013-11-16 03:39:39 -06:00
mdipierro e0329ce59a fixed 1771:MongoDBAdapter ILIKE and widget.autocomplete, thanks Francisco 2013-11-16 03:32:36 -06:00
mdipierro de7848ba21 Merge pull request #298 from chuckis/patch-1
Update ru.py
2013-11-16 01:28:14 -08:00
mdipierro d6f5a5684f Merge pull request #297 from xbello/master
Added two libs and icon path to setup.py
2013-11-16 01:27:39 -08:00
mdipierro 9883590a91 Merge pull request #295 from niphlod/enhancement/mssql4
improved performance on mssql4
2013-11-16 01:24:55 -08:00
mdipierro b11bdddfe2 Merge pull request #294 from timrichardson/issue/1773
replace write to stderr with LOGGER in failed database connection attemp...
2013-11-16 01:24:18 -08:00
mdipierro 623cd515de Merge pull request #293 from magnunleno/patch-1
Adds bind capability to OpenLDAP
2013-11-16 01:23:30 -08:00
mdipierro f53da87f6f fixed 1774:CAS client broken when using routes.py, thanks remco.boerma 2013-11-16 03:23:03 -06:00
mdipierro ff7ef47cc7 fix issue 1777:MongoDB: upload representation error, thanks Francisco Betancourt 2013-11-16 03:16:57 -06:00
chuckis 108b24abdd Update ru.py 2013-11-15 12:05:24 +02:00
xbello 2d309c6e81 Added two libs and icon path to setup.py 2013-11-15 10:16:09 +01:00
Massimo 07f0cdadcd memdb conflict check, thanks Luca 2013-11-14 13:29:46 -06:00
niphlod 7c8c9bc3af improved performance on mssql4 2013-11-13 23:18:07 +01:00
mdipierro 948e0b1f43 possible to fix to memdb threading issue 2013-11-13 14:07:26 -06:00
tim be9027f36f replace write to stderr with LOGGER in failed database connection attempt 2013-11-13 17:42:21 +11:00
mdipierro 9bb4155460 adding spanish plurals, thanks Vlad Vladyslav 2013-11-11 17:42:58 -06:00
Magnun Leno ad877b2305 Adds bind capability to OpenLDAP
Adds to OpenLDAP (mode=uid and mode=cn) the capability to bind to the directory with an admin account in order to search it.
2013-11-11 15:53:38 -02:00
mdipierro fb9ad028f8 fixed problem with multiple uris and lazy tables 2013-11-11 10:16:38 -06:00
mdipierro 833694229d Merge pull request #292 from flavour/master
Support HTTP Status 509
2013-11-11 07:43:56 -08:00
mdipierro d6a8a3d410 Espanol language patches, thanks Vladyslav Kozlovskyy 2013-11-11 09:40:57 -06:00
Fran Boon 4e9d228a60 Support HTTP Status 509
Whilst this isn't an official RFC, it's documented on e.g. Wikipedia. http://en.wikipedia.org/wiki/List_of_HTTP_status_codes#5xx_Server_Error
2013-11-08 10:46:47 +00:00
Massimo db0d31260e NDB support for GAE, thanks Quint, needs testing 2013-11-07 11:16:04 -06:00
Massimo 9178b23473 Merge branch 'master' of github.com:web2py/web2py
Conflicts:
	VERSION
2013-11-07 11:06:37 -06:00
Massimo 40d5e5dfe9 fixed 1746:auth.wiki renders multi-line code as single-line, thanks Alan 2013-11-07 11:00:39 -06:00
Massimo f95476c51e fixed colgroup issue in grid, thanks Anthony 2013-11-07 10:47:57 -06:00
Massimo 73ab77ad8b fixed 1765:Verify email message seams to only accept username, key and link 2013-11-07 10:31:54 -06:00
Massimo e6f84c45b9 fixed 1756:scripts/sessions2trash.py doesn't work with 'separate=True', thanks Paolo Valleri 2013-11-07 10:25:29 -06:00
mdipierro 58c22b8ed0 synced web2py.js, thanks Vinicius 2013-11-06 16:57:33 -06:00
mdipierro ee1de04544 Merge pull request #291 from viniciusban/master
Make component forms submit to their own action property
2013-11-06 14:55:12 -08:00
Vinicius Assef 9977aa571a Make component forms submit to their own action property 2013-11-06 19:37:55 -02:00
mdipierro 65b883749a fixed 1757:Broken support for 'belongs' with GAE datastore, thanks Alan 2013-11-06 11:14:56 -06:00
mdipierro 5cee4f8876 fixed issue 1763 user of arrows in numerical fields 2013-11-06 11:13:10 -06:00
mdipierro 3aec2c4568 Merge branch 'master' of github.com:web2py/web2py 2013-11-06 11:11:55 -06:00
mdipierro 3defd7d7b1 fixed issue 1763 user of arrows in numerical fields 2013-11-06 11:11:01 -06:00
mdipierro ac97332393 Merge pull request #290 from erikmontes/patch-1
Closed html commment.
2013-11-06 08:32:01 -08:00
mdipierro 62bda4b917 Merge pull request #289 from michele-comitini/SQLCustomType_in_grid_fix
simple fix for wrong type detection of SQLCustomTypes
2013-11-06 08:31:34 -08:00
mdipierro cb6857c16b Merge pull request #288 from hectord/translate_date_in_range_formatters
Translate the formatters for DATE/DATETIME_IN_RANGE validators
2013-11-06 08:31:06 -08:00
mdipierro 643e945540 fixed web2py.js for trapped non-self-submitting forms, thanks Vinicius 2013-11-06 10:30:41 -06:00
Erik Montes b52b639eed Closed html commment. 2013-11-05 14:09:01 -08:00
Michele Comitini e0ea9b78f8 simple fix for wrong type detection of SQLCustomTypes 2013-11-05 16:09:42 +01:00
mdipierro 8e4f92ac64 fixed TeradataAdapter CLOB, thnaks Andrew Willmott 2013-11-03 22:46:20 -06:00
mdipierro 350bd25404 another iteration to col/colgroup in grid, thanks Anthony for advice 2013-11-03 09:26:26 -06:00
mdipierro 6d3fe6cf89 col in colgroup for grid extracolumns, thanks Anthony 2013-11-02 10:09:11 -05:00
mdipierro a3bf95e423 fixed colgroup wrapping, thanks Anthony 2013-11-02 09:26:19 -05:00
mdipierro fc72cdf3d0 change in way args are parsed and less test_routes.py 2013-11-01 20:11:46 -05:00
mdipierro b619bd3db7 minor rewrite in rewrite.py 2013-11-01 18:49:38 -05:00
mdipierro b1631ae2b3 fixed issue 1758:Missing comment parameter in Recaptcha 2013-11-01 18:07:29 -05:00
mdipierro a01aa78f36 fixed issue 1761:Add <col> elements to the grid for easier column formatting, thanks Anthony 2013-11-01 18:01:02 -05:00
mdipierro 975bc64fd0 fixed 1760:option -p or --port not working at command line 2013-11-01 17:45:43 -05:00
hectord 231fa489cb Translate the formatters for DATE/DATETIME_IN_RANGE validators 2013-11-01 22:43:31 +01:00
mdipierro 123f0f8269 Merge pull request #287 from niphlod/issue/1753
fixes issue 1753, web2py.js doesn't set the disabled state for inputs with name
2013-11-01 07:34:56 -07:00
niphlod a6223cc319 fixes issue 1753, web2py.js doesn't set the disabled state for inputs with name 2013-10-31 21:10:37 +01:00
Massimo 8bdc5f20e7 fixed websocket_messaging.py, thanks Junior Phanter 2013-10-31 10:21:38 -05:00
Massimo bb4f3d6e1a fixed issue 1755:IE11 vs gluon.contrib.user_agent - 'browser' key not existing anymore 2013-10-31 10:19:07 -05:00
Massimo 25f54356d4 fixed issue 1755:IE11 vs gluon.contrib.user_agent - 'browser' key not existing anymore 2013-10-31 09:42:03 -05:00
Massimo 5b3b5b6821 fixed issue 1736, Unable to create/re-create cache file error for cache.disk, thanks arglanir 2013-10-31 09:40:39 -05:00
mdipierro 1474a4fe79 link to pythonanywhere 2013-10-30 08:59:55 -05:00
mdipierro c89ed53be1 Merge pull request #286 from ilvalle/fix-editor
fix for empty python file in admin editor
2013-10-29 14:05:21 -07:00
mdipierro e692beafba Merge pull request #285 from niphlod/enhancement/dal_rname
fixed issue with ordereddict in python < 2.7, added rname support also for fields
2013-10-29 14:03:22 -07:00
mdipierro 850ef39bf7 Merge pull request #284 from spametki/master
Admin app: changed string interpolation in T calls
2013-10-29 14:01:38 -07:00
ilvalle 1bbb99b548 fix codemirror gutter managment 2013-10-29 17:24:46 +01:00
ilvalle 7675d605ea fix width after window resize 2013-10-29 17:02:50 +01:00
ilvalle 7d5cdb9220 fix for empty file in admin editor 2013-10-28 10:17:47 +01:00
mdipierro 78089bc0c4 small aesthetic change 2013-10-27 23:22:55 -05:00
mdipierro eb9d7bf5c3 code simplification in wiki 2013-10-27 23:18:01 -05:00
mdipierro 8ce53e8dfa Wiki(...groups=['x','y']) allows to user groups names other then those set in auth_group.role, completely by-passing auth groups and memberships 2013-10-27 22:55:41 -05:00
niphlod 0f2b2daeab fixed issue with ordereddict in python < 2.7, added rname support also for fields 2013-10-27 14:36:38 +01:00
spametki 68ccf6510d admin app: changed string interpolation in T calls 2013-10-27 10:28:23 -03:00
mdipierro d960513ef2 fixed issues 1742:dal Teradata connection issue. cursors not being closed at the end of sessions, thanks awilliman01 2013-10-26 21:46:48 -05:00
mdipierro 1865c0b1dd Merge pull request #283 from spametki/master
Fixed wiki get render method
2013-10-26 18:25:44 -07:00
mdipierro af412e7e24 Merge pull request #282 from michele-comitini/make_executesql_as_dict_ordered
Make executesql as dict ordered
2013-10-26 18:24:57 -07:00
mdipierro a74b1dd1bf Merge pull request #281 from niphlod/enhancement/update_pypyodbc
update pypyodbc to 1.2.0
2013-10-26 18:24:25 -07:00
mdipierro 7d9c853eeb Merge pull request #280 from gi0baro/mongo-binary
Fixing mongodb binary repr
2013-10-26 18:23:52 -07:00
mdipierro 7caf1c0794 Merge pull request #279 from ilvalle/fix-editor
Dynamic tab width in editor settings
2013-10-26 18:23:16 -07:00
spametki 70b3edcbeb Fixed wiki get render method 2013-10-26 21:39:26 -03:00
Michele Comitini 50543724d4 fix a docstring 2013-10-25 23:12:43 +02:00
Michele Comitini ad81e641b3 optionally use OrderedDict in place of dict in executesql 2013-10-25 23:09:46 +02:00
niphlod 429ee8e423 update pypyodbc to 1.2.0 2013-10-25 21:41:50 +02:00
gi0baro 604795d6fc Fixing mongodb binary repr: if value is not a basestring we got type Exception in converting to Binary 2013-10-25 10:40:56 +02:00
ilvalle 6599e08d32 'Highlight current line' & 'Display line numbers' options in admin editor 2013-10-24 16:16:41 +02:00
ilvalle 94ddb6c11f dynamic tab size in admin editor (all tabs are placed along the same line) 2013-10-24 09:48:03 +02:00
mdipierro a514060402 cleaning up pending references 2013-10-23 20:13:43 -05:00
mdipierro fec5ddd150 Merge pull request #278 from niphlod/fix/dal_references
allow unordered references (NOT recommended but still possible with limitations)
2013-10-23 17:46:09 -07:00
mdipierro 811a44fd14 Merge pull request #277 from ilvalle/fix-editor
codemirror 3.19 and directory cleanup
2013-10-23 17:44:15 -07:00
mdipierro 1c5bad24f3 Merge pull request #276 from niphlod/enhancement/scheduler_current
inject W2P_TASK in current, so you can use current.W2P_TASK in imported ...
2013-10-23 17:43:36 -07:00
niphlod 17b4de18d7 allow unordered references (NOT recommended but still possible with limitations) 2013-10-23 21:42:55 +02:00
ilvalle 290cb2f1a7 simplified editor's options management 2013-10-23 14:33:15 +02:00
ilvalle ff7cb99bfe jQuery -> $ in admin editor 2013-10-23 14:07:51 +02:00
ilvalle 339de2fa41 codemirror 3.19 and directory cleanup 2013-10-23 13:31:57 +02:00
Massimo cafab17ee0 syncing 2013-10-22 17:05:52 -05:00
mdipierro 9fa1757ffb Merge pull request #275 from ilvalle/fix-editor
bootstrapSwitch in admin
2013-10-22 15:04:01 -07:00
Massimo e94921c002 fixed issues with Rows.__or__, thanks Anthony 2013-10-22 17:03:54 -05:00
niphlod d30098d646 inject W2P_TASK in current, so you can use current.W2P_TASK in imported modules. Thanks @Xiaonuo for the feature request 2013-10-23 00:03:04 +02:00
mdipierro fba11869b6 Merge pull request #274 from Jaripekkaf/web2py_bs3
bootstrap3 formstyle
2013-10-22 14:59:48 -07:00
ilvalle 453412fa0c added bootstrap switch in editor settings 2013-10-22 17:36:45 +02:00
ilvalle 607897a1b0 boostrap switch plugin in admin 2013-10-22 17:36:19 +02:00
Jaripekkaf 221fdc51ba bootstrap3 formstyle 2013-10-22 13:15:21 +03:00
mdipierro 37551a8517 Merge pull request #272 from niphlod/enhancement/boostrap_232
bumped bootstrap to 2.3.2
2013-10-21 19:34:58 -07:00
mdipierro 8877eab977 Merge pull request #271 from niphlod/enhancement/windows_build
fix building on windows. New handler for gevented webserver
2013-10-21 19:32:34 -07:00
mdipierro 2d0205714c Merge pull request #270 from niphlod/fix/dal_reference
fix for references, DAL tests pass also on MSSQL now
2013-10-21 19:31:50 -07:00
mdipierro 49111345d1 Merge pull request #269 from ilvalle/fix-editor
Fix config to save checkboxes values when they are unchecked (false)
2013-10-21 19:31:14 -07:00
mdipierro 570564b0c4 fixed bug in compileapp models_to_run, thanks Anthony 2013-10-21 21:30:20 -05:00
niphlod 22dd63d77b bumped bootstrap to 2.3.2 2013-10-21 23:17:07 +02:00
niphlod 736311ff9a fix building on windows. New handler for gevented webserver 2013-10-21 12:52:43 -07:00
Massimo 34b377522a allow as_trees to deal with orphan children 2013-10-21 14:32:49 -05:00
niphlod 9f846dbe3c fix for references, DAL tests pass also on MSSQL now 2013-10-21 12:09:47 -07:00
ilvalle 845694beb6 Fix config to save checkboxes values when they are unchecked (false) 2013-10-21 09:57:36 +02:00
mdipierro 665f728946 db().select().as_trees() 2013-10-20 22:55:17 -05:00
mdipierro d879e4a560 db().select().as_tree() 2013-10-20 22:51:03 -05:00
mdipierro 8e1a68d461 simplified logic 2013-10-20 16:58:08 -05:00
mdipierro 2738d12e0f fixed problem with _ot and rname 2013-10-20 16:51:34 -05:00
mdipierro 25148d06fe reverted to rname 2013-10-20 16:48:22 -05:00
mdipierro 4870b197de revering rname 2013-10-20 16:42:52 -05:00
mdipierro 12377794a6 remove actual_name 2013-10-20 15:48:15 -05:00
mdipierro bf27623756 Merge branch 'master' of github.com:web2py/web2py 2013-10-20 15:47:10 -05:00
mdipierro 9afdf01430 PRAGMA foreign_keys=ON by default 2013-10-20 15:46:41 -05:00
mdipierro 80f16dadde Merge pull request #263 from niphlod/enhancement/dal_rname
add support for rname (meaning "real name") for table names
2013-10-20 13:45:00 -07:00
mdipierro a68ac4fc02 Merge pull request #268 from spametki/master
imap: use common field types plus appadmin support
2013-10-20 07:56:59 -07:00
mdipierro 3dde465427 Merge pull request #267 from ilvalle/fix-editor
Tab width (new option in editor settings)
2013-10-20 07:56:18 -07:00
spametki f77232740c imap: return to common field type for attachment and content plus appadmin imap support 2013-10-20 08:38:07 -03:00
ilvalle 56f251ca0c tab size in editor settings and better options management 2013-10-20 08:40:05 +02:00
mdipierro 9282bfcc60 fixed issue 1732:ignore_common_filters missing in appadmin, thanks mweissen 2013-10-19 17:41:17 -05:00
mdipierro 8d0bbbc9f1 Merge pull request #266 from niphlod/rm/windows_service
remove winservice support
2013-10-19 15:34:56 -07:00
mdipierro ee33f2a4a8 Merge pull request #265 from spametki/master
Fixed imap get_last_message to return positive integer (google code issue 1729)
2013-10-19 15:33:46 -07:00
mdipierro ab313c2d4d Merge pull request #264 from ilvalle/fix-editor
Code folding in admin editor
2013-10-19 15:32:03 -07:00
spametki 4c1de287cd dal imap: strip native folder names (google code issue 1734) 2013-10-19 16:50:20 -03:00
niphlod 9ea9f828bc remove winservice support 2013-10-19 20:44:56 +02:00
spametki 58e4cd91cc Fixed imap get_last_message to return positive integer 2013-10-19 09:57:08 -03:00
ilvalle b5f17b1acb code folding in editor settings 2013-10-19 12:22:24 +02:00
ilvalle e9c884d674 experimental code folding feature in admin editor 2013-10-19 12:18:46 +02:00
Massimo 492953c7f0 t -m "editor cleanup, thanks Paolo"
Merge branch 'master' of github.com:web2py/web2py
2013-10-18 12:31:13 -05:00
mdipierro dd8d9d9d8d Merge pull request #261 from ilvalle/fix-editor
Editor cleanup
2013-10-18 10:30:36 -07:00
Massimo 9ff32ed9cd setup-web2py-debian-sid.sh, thanks Rusy 2013-10-18 12:27:23 -05:00
niphlod c9b0c4547a add support for rname (meaning "real name") for table names 2013-10-18 00:09:32 +02:00
ilvalle 037b499cb2 correct editor's mode when editing javascript 2013-10-17 16:32:22 +02:00
ilvalle f4fc987597 editor cleanup (second pass) 2013-10-17 16:20:06 +02:00
ilvalle 580bc6fd6e editor works again when is_mobile=True (No tabs when is mobile) 2013-10-17 16:10:53 +02:00
ilvalle c91e6160fe initial editor cleanup and html fix 2013-10-17 15:25:12 +02:00
mdipierro 13c6c1ad37 Merge pull request #260 from spametki/master
New admin app plugin download
2013-10-16 07:15:08 -07:00
mdipierro 0faa7d3174 removed print statment, thanks Johann 2013-10-16 09:11:28 -05:00
mdipierro cfe7c65987 fixed issue 1725:No debugging under WingIDE, thanks Joe 2013-10-16 09:09:22 -05:00
mdipierro c5a2706c1b fixed issue 1724:webclient no longer handles integer post data, thanks iiijjjiii 2013-10-16 09:03:19 -05:00
mdipierro a379d7020e fixed issue 1723:Missing translation for the word file in the upload widget, thanks mweissen 2013-10-16 09:00:42 -05:00
mdipierro a74a16cfba fixed issue 1719:decorators ignore routes, thanks vladsalehov 2013-10-16 08:56:53 -05:00
spametki 37e0e1c384 Added missing plugin download views 2013-10-14 15:12:14 -03:00
spametki 62061ae737 admin app plugin download feature 2013-10-14 15:05:20 -03:00
233 changed files with 14356 additions and 7053 deletions
+20 -1
View File
@@ -1,7 +1,6 @@
language: python
python:
- '2.5'
- '2.6'
- '2.7'
- 'pypy'
@@ -11,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;
@@ -19,6 +21,15 @@ 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 (update only whenever a new release is available)
- if [[ $DB == google* ]]; then wget http://googleappengine.googlecode.com/files/google_appengine_1.8.9.zip -nv; fi
- if [[ $DB == google* ]]; then unzip -q google_appengine_1.8.9.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
@@ -28,6 +39,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:
@@ -36,3 +52,6 @@ after_success:
notifications:
email: true
services: mongodb
+40
View File
@@ -1,3 +1,43 @@
## 2.9.1 - 2.9.5
- many small but important bug fixes
- jquery 1.11
- codemirror 3.21, thanks Paolo Valleri
- fixed security issue with sessions in database, thanks Nathan Humphreys
- fixed security issue with persistant data in session, thanks Kiran
- 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
## 2.8.1
- no more winservice (use nssm instead)
- better imap support in DAL
- db().select().as_tree()
- bootstrap 2.3.2
- codemirror 3.19
- improved mongoDB support, thanks Alan
- support for wiki custom render function
- Wiki(...groups=['x','y']) allows bypassing default permissions
- fixed websocket_messaging.py to support newer Tornado
- NDB support for GAE, thanks Quint
- fixed major concurrecy issue with MEMDB
- blocked generic.jsonp for security reasons
- many bug fixes, thanks Niphlod, Michele, Anthony, Tim, and many others.
## 2.7.1 - 2.7.4
- jQuery 1.10.2
+1 -1
View File
@@ -30,7 +30,7 @@ update:
echo "remember that pymysql was tweaked"
src:
### Use semantic versioning
echo 'Version 2.7.4-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION
echo 'Version 2.9.5-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION
### rm -f all junk files
make clean
### clean up baisc apps
+1 -1
View File
@@ -1 +1 @@
Version 2.7.4-stable+timestamp.2013.10.14.10.13.57
Version 2.9.5-stable+timestamp.2014.03.15.21.24.06
+135 -96
View File
@@ -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())
@@ -186,6 +188,10 @@ def select():
import re
db = get_database(request)
dbname = request.args[0]
try:
is_imap = db._uri.startswith("imap://")
except (KeyError, AttributeError, TypeError):
is_imap = False
regex = re.compile('(?P<table>\w+)\.(?P<field>\w+)=(?P<value>\d+)')
if len(request.args) > 1 and hasattr(db[request.args[1]], '_primarykey'):
regex = re.compile('(?P<table>\w+)\.(?P<field>\w+)=(?P<value>.+)')
@@ -203,7 +209,15 @@ def select():
else:
start = 0
nrows = 0
stop = start + 100
step = 100
fields = []
if is_imap:
step = 3
stop = start + step
table = None
rows = []
orderby = request.vars.orderby
@@ -235,21 +249,27 @@ def select():
if match:
table = match.group('table')
try:
nrows = db(query).count()
nrows = db(query, ignore_common_filters=True).count()
if form.vars.update_check and form.vars.update_fields:
db(query).update(**eval_in_global_env('dict(%s)'
% form.vars.update_fields))
db(query, ignore_common_filters=True).update(
**eval_in_global_env('dict(%s)' % form.vars.update_fields))
response.flash = T('%s %%{row} updated', nrows)
elif form.vars.delete_check:
db(query).delete()
db(query, ignore_common_filters=True).delete()
response.flash = T('%s %%{row} deleted', nrows)
nrows = db(query).count()
nrows = db(query, ignore_common_filters=True).count()
if is_imap:
fields = [db[table][name] for name in
("id", "uid", "created", "to",
"sender", "subject")]
if orderby:
rows = db(query, ignore_common_filters=True).select(limitby=(
start, stop), orderby=eval_in_global_env(orderby))
rows = db(query, ignore_common_filters=True).select(
*fields, limitby=(start, stop),
orderby=eval_in_global_env(orderby))
else:
rows = db(query, ignore_common_filters=True).select(
limitby=(start, stop))
*fields, limitby=(start, stop))
except Exception, e:
import traceback
tb = traceback.format_exc()
@@ -278,11 +298,12 @@ def select():
table=table,
start=start,
stop=stop,
step=step,
nrows=nrows,
rows=rows,
query=request.vars.query,
formcsv=formcsv,
tb=tb,
tb=tb
)
@@ -340,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:
@@ -395,6 +423,7 @@ def ccache():
'oldest': time.time(),
'keys': []
}
disk = copy.copy(ram)
total = copy.copy(ram)
disk['keys'] = []
@@ -409,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(
@@ -483,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)
+6 -2
View File
@@ -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 = {}
+221 -71
View File
@@ -1,6 +1,7 @@
# coding: utf8
EXPERIMENTAL_STUFF = True
MAXNFILES = 1000
if EXPERIMENTAL_STUFF:
if is_mobile:
@@ -12,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
@@ -29,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')
@@ -62,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)
@@ -230,7 +242,7 @@ def site():
redirect(URL('design', args=appname))
else:
session.flash = \
DIV(T('unable to create application "%s"' % appname),
DIV(T('unable to create application "%s"', appname),
PRE(error))
redirect(URL(r=request))
@@ -341,7 +353,7 @@ def pack():
response.headers['Content-Disposition'] = disposition
return safe_read(filename, 'rb')
else:
session.flash = T('internal error: %s' % e)
session.flash = T('internal error: %s', e)
redirect(URL('site'))
def pack_plugin():
@@ -375,7 +387,7 @@ def pack_custom():
response.headers['Content-Disposition'] = disposition
return safe_read(filename, 'rb')
else:
session.flash = T('internal error: %s' % e)
session.flash = T('internal error: %s', e)
redirect(URL(args=request.args))
def ignore(fs):
return [f for f in fs if not (
@@ -563,36 +575,30 @@ 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'}
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):
if not(request.ajax) and not(is_mobile):
# return the scaffolding, the rest will be through ajax requests
response.title = T('Editing %s') % app
editarea_preferences = {}
editarea_preferences['FONT_SIZE'] = '10'
editarea_preferences['FULL_SCREEN'] = 'false'
editarea_preferences['ALLOW_TOGGLE'] = 'true'
editarea_preferences['REPLACE_TAB_BY_SPACES'] = '4'
editarea_preferences['DISPLAY'] = 'onload'
for key in editarea_preferences:
if key in globals():
editarea_preferences[key] = globals()[key]
return response.render ('default/edit.html', dict(app=request.args[0], editor_settings=preferences, editarea_preferences=editarea_preferences))
return response.render ('default/edit.html', dict(app=app, editor_settings=preferences))
# show settings tab and save prefernces
if 'settings' in request.vars:
if request.post_vars: #save new preferences
if config.save(request.post_vars.items()):
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 preferences if opt not in request.post_vars ]
if config.save(post_vars):
response.headers["web2py-component-flash"] = T('Preferences saved correctly')
else:
response.headers["web2py-component-flash"] = T('Preferences saved on session only')
response.headers["web2py-component-command"] = "update_editor('%s', '%s', '%s');jQuery('a[href=#editor_settings] button.close').click();" % (config.read()['theme'], config.read()['editor'], config.read()['closetag'])
response.headers["web2py-component-command"] = "update_editor(%s);$('a[href=#editor_settings] button.close').click();" % response.json(config.read())
return
else:
details = {'filename':'settings', 'id':'editor_settings', 'force': False}
details = {'realfilename':'settings', 'filename':'settings', 'id':'editor_settings', 'force': False}
details['plain_html'] = response.render('default/editor_settings.html', {'editor_settings':preferences})
return response.json(details)
@@ -600,7 +606,7 @@ def edit():
# Load json only if it is ajax edited...
app = get_app(request.vars.app)
filename = '/'.join(request.args)
response.title = request.args[-1]
realfilename = request.args[-1]
if request.vars.app:
path = abspath(filename)
else:
@@ -615,7 +621,7 @@ def edit():
elif filename[-4:] == '.css':
filetype = 'css'
elif filename[-3:] == '.js':
filetype = 'js'
filetype = 'javascript'
else:
filetype = 'html'
@@ -747,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)
@@ -755,7 +761,10 @@ 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,
filetype=filetype,
data=data,
edit_controller=edit_controller,
@@ -766,11 +775,61 @@ def edit():
view_link=view_link,
editviewlinks=editviewlinks,
id=IS_SLUG()(filename)[0],
force= True if (request.vars.restore or request.vars.revert) else False)
force= True if (request.vars.restore or
request.vars.revert) else False)
plain_html = response.render('default/edit_js.html', file_details)
file_details['plain_html'] = plain_html
return response.json(file_details)
if is_mobile:
return response.render('default.mobile/edit.html',
file_details, editor_settings=preferences)
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():
"""
@@ -1007,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
@@ -1037,9 +1096,9 @@ def design():
privates.sort()
# Get all static files
MAXNFILES = 1000
statics = listdir(apath('%s/static/' % app, r=request), '[^\.#].*')
statics = [x.replace('\\', '/') for x in statics[:MAXNFILES]]
statics = listdir(apath('%s/static/' % app, r=request), '[^\.#].*',
maxnum = MAXNFILES)
statics = [x.replace(os.path.sep, '/') for x in statics]
statics.sort()
# Get all languages
@@ -1051,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 = []
@@ -1144,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
@@ -1173,8 +1233,9 @@ def plugin():
privates.sort()
# Get all static files
statics = listdir(apath('%s/static/' % app, r=request), '[^\.#].*')
statics = [x.replace('\\', '/') for x in statics]
statics = listdir(apath('%s/static/' % app, r=request), '[^\.#].*',
maxnum = MAXNFILES)
statics = [x.replace(os.path.sep, '/') for x in statics]
statics.sort()
# Get all languages
@@ -1206,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:
@@ -1217,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)
@@ -1325,7 +1387,8 @@ def create_file():
from gluon import *\n""")[1:]
elif (path[-8:] == '/static/') or (path[-9:] == '/private/'):
if request.vars.plugin and not filename.startswith('plugin_%s/' % request.vars.plugin):
if (request.vars.plugin and
not filename.startswith('plugin_%s/' % request.vars.plugin)):
filename = 'plugin_%s/%s' % (request.vars.plugin, filename)
text = ''
@@ -1343,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:
@@ -1352,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:
@@ -1418,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(
@@ -1486,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)
@@ -1519,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))
@@ -1548,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'
@@ -1791,3 +1902,42 @@ def git_push():
session.flash = T("Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.")
redirect(URL('site'))
return dict(app=app, form=form)
def plugins():
app = request.args(0)
from serializers import loads_json
if not session.plugins:
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)
source = request.vars.source
plugin = request.vars.plugin
if not (source and app):
raise HTTP(500, T("Invalid request"))
form = SQLFORM.factory()
result = None
if form.process().accepted:
# get w2p plugin
if "web2py.plugin." in source:
filename = "web2py.plugin.%s.w2p" % \
source.split("web2py.plugin.")[-1].split(".w2p")[0]
else:
filename = "web2py.plugin.%s.w2p" % cleanpath(plugin)
if plugin_install(app, urllib.urlopen(source),
request, filename):
session.flash = T('New plugin installed: %s', filename)
else:
session.flash = \
T('unable to install plugin "%s"', filename)
redirect(URL(f="plugins", args=[app,]))
return dict(form=form, app=app, plugin=plugin, source=source)
+2 -1
View File
@@ -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():
+53 -2
View File
@@ -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',
@@ -29,11 +31,13 @@
'An error occured, please %s the page': 'Ha ocurrido un error, por favor %s la página',
'and rename it (required):': 'y renombrela (requerido):',
'and rename it:': ' y renombrelo:',
'App does not exist or you are not authorized': 'App does not exist or you are not authorized',
'appadmin': 'appadmin',
'appadmin is disabled because insecure channel': 'admin deshabilitado, el canal no es seguro',
'application "%s" uninstalled': 'aplicación "%s" desinstalada',
'application %(appname)s installed with md5sum: %(digest)s': 'application %(appname)s installed with md5sum: %(digest)s',
'application compiled': 'aplicación compilada',
'Application exists already': 'Application exists already',
'application is compiled and cannot be designed': 'la aplicación está compilada y no puede ser modificada',
'Application name:': 'Nombre de la aplicación:',
'are not used': 'are not used',
@@ -44,6 +48,7 @@
'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"?',
'Are you sure you want to upgrade web2py now?': '¿Está seguro que desea actualizar web2py ahora?',
'Are you sure?': 'Are you sure?',
'arguments': 'argumentos',
'at char %s': 'en el caracter %s',
'at line %s': 'en la línea %s',
@@ -53,13 +58,17 @@
'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',
'Cancel': 'Cancel',
'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 compile: there are errors in your app:': 'No se puede compilar: hay errores en su aplicación:',
@@ -73,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',
@@ -107,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',
@@ -117,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',
@@ -128,7 +142,10 @@
'details': 'detalles',
'direction: ltr': 'direction: ltr',
'Disable': 'Deshabilitar',
'DISK': 'DISK',
'docs': 'docs',
'Docs': 'Docs',
'Done!': 'Done!',
'done!': 'listo!',
'Download': 'Descargar',
'download files via http:': 'descargar archivos via http:',
@@ -151,12 +168,14 @@
'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"',
'Error snapshot': 'Error snapshot',
'Error ticket': 'Error ticket',
'Errors': 'errores',
'Errors in form, please check it out.': 'Errors in form, please check it out.',
'Exception instance attributes': 'Atributos de la instancia de Excepción',
'Exit Fullscreen': 'Exit Fullscreen',
'Expand Abbreviation': 'Expand Abbreviation',
@@ -183,30 +202,38 @@
'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',
'Hello World': 'Hola Mundo',
'Help': 'ayuda',
'here': 'here',
'htmledit': 'htmledit',
'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'Si el reporte anterior contiene un número de tiquete este indica un falla en la ejecución del controlador, antes de cualquier intento de ejecutat doctests. Esto generalmente se debe a un error en la indentación o un error por fuera del código de la función.\r\nUn titulo verde indica que todas las pruebas pasaron (si existen). En dicho caso los resultados no se muestran.',
'Image': 'Image',
'Import/Export': 'Importar/Exportar',
'includes': 'incluye',
'insert new': 'inserte nuevo',
'insert new %s': 'inserte nuevo %s',
'inspect attributes': 'inspect attributes',
'Install': 'instalar',
'Installation of %(plugin)s for %(app)s': 'Installation of %(plugin)s for %(app)s',
'Installation of %(plugin)s for %(app)s app': 'Installation of %(plugin)s for %(app)s app',
'Installed applications': 'Aplicaciones instaladas',
'Interaction at %s line %s': 'Interaction at %s line %s',
'Interactive console': 'Interactive console',
'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.',
'Invalid Query': 'Consulta inválida',
'invalid request': 'solicitud inválida',
'Invalid request': 'Invalid request',
'invalid ticket': 'tiquete inválido',
'Key bindings': 'Key bindings',
'Key bindings for ZenCoding Plugin': 'Key bindings for ZenCoding Plugin',
@@ -218,6 +245,8 @@
'Last name': 'Apellido',
'Last saved on:': 'Guardado en:',
'License for': 'Licencia para',
'License:': 'License:',
'lists by ticket': 'lists by ticket',
'loading...': 'cargando...',
'locals': 'locals',
'Locals##debug': 'Locals',
@@ -228,6 +257,7 @@
'Lost Password': 'Contraseña perdida',
'manage': 'gestionar',
'Manage': 'Gestionar',
'Manage Cache': 'Manage Cache',
'merge': 'combinar',
'Models': 'Modelos',
'models': 'modelos',
@@ -237,6 +267,11 @@
'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',
'New plugin installed: web2py.plugin.timezone.w2p': 'New plugin installed: web2py.plugin.timezone.w2p',
'New Record': 'Registro nuevo',
'new record inserted': 'nuevo registro insertado',
'New simple application': 'Nueva aplicación',
@@ -256,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',
@@ -266,8 +302,10 @@
'password changed': 'contraseña cambiada',
'Peeking at file': 'Visualizando archivo',
'Please': 'Please',
'Plugin': 'Plugin',
'plugin "%(plugin)s" deleted': 'plugin "%(plugin)s" eliminado',
'Plugin "%s" in application': 'Plugin "%s" en aplicación',
'Plugin page': 'Plugin page',
'plugins': 'plugins',
'Plugins': 'Plugins',
'Plural-Forms:': 'Plural-Forms:',
@@ -275,7 +313,9 @@
'previous 100 rows': '100 filas anteriores',
'Private files': 'Archivos privados',
'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',
@@ -290,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',
@@ -309,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',
@@ -316,25 +360,29 @@
'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',
'Submit': 'Submit',
'Success!': 'Success!',
'successful': 'exitoso',
'Sure you want to delete this object?': '¿Está seguro que desea eliminar este objeto?',
'switch to : db': 'switch to : db',
'table': 'tabla',
'Table name': 'Nombre de la tabla',
'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',
@@ -361,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',
@@ -412,6 +461,8 @@
'web2py upgraded; please restart it': 'web2py actualizado; favor reiniciar',
'Welcome to web2py': 'Bienvenido a web2py',
'YES': 'SI',
'Yes': 'Yes',
'You are going to install': 'You are going to install',
'You need to set up and reach a': 'You need to set up and reach a',
'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Your application will be blocked until you click an action button (next, step, continue, etc.)',
'Your can inspect variables using the console below': 'Your can inspect variables using the console below',
+2 -1
View File
@@ -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",
+3 -3
View File
@@ -185,8 +185,8 @@
'Invalid Query': 'Неверный запрос',
'invalid request': 'неверный запрос',
'invalid ticket': 'неверный тикет',
'Key bindings': 'Связываник клавиш',
'Key bindings for ZenConding Plugin': 'Связывание клавиш для плагина ZenConding',
'Key bindings': 'Комбинации клавиш',
'Key bindings for ZenConding Plugin': 'Комбинации клавиш для плагина ZenConding',
'language file "%(filename)s" created/updated': 'Языковой файл "%(filename)s" создан/обновлен',
'Language files (static strings) updated': 'Языковые файлы (статичные строки) обновлены',
'languages': 'языки',
@@ -204,7 +204,7 @@
'Login to the Administrative Interface': 'Вход в интерфейс администратора',
'Logout': 'выход',
'Lost Password': 'Забыли пароль',
'lost password?': 'Пароль утерен?',
'lost password?': 'Пароль утерян?',
'Main Menu': 'Главное меню',
'Match Pair': 'Найти пару',
'Menu Model': 'Модель меню',
+426
View 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ı',
'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',
}
+1 -37
View File
@@ -8,42 +8,6 @@ WEB2PY_VERSION_URL = WEB2PY_URL + '/examples/default/version'
# the user-interface feature that allows you to edit files in your web
# browser.
## Default editor (to change editor you need web2py.admin.editors.zip)
## old editors like 'ace' or 'edit_area' or 'amy' are no longer supported
TEXT_EDITOR = 'codemirror'
## Editor Color scheme (only for ace)
TEXT_EDITOR_THEME = (
"chrome", "clouds", "clouds_midnight", "cobalt", "crimson_editor", "dawn",
"dreamweaver", "eclipse", "idle_fingers", "kr_theme", "merbivore",
"merbivore_soft", "monokai", "mono_industrial", "pastel_on_dark",
"solarized_dark", "solarized_light", "textmate", "tomorrow",
"tomorrow_night", "tomorrow_night_blue", "tomorrow_night_bright",
"tomorrow_night_eighties", "twilight", "vibrant_ink")[0]
## Editor Keyboard bindings (only for ace and codemirror)
TEXT_EDITOR_KEYBINDING = '' # 'emacs' or 'vi'
### edit_area only
# The default font size, measured in 'points'. The value must be an integer > 0
FONT_SIZE = 10
# Displays the editor in full screen mode. The value must be 'true' or 'false'
FULL_SCREEN = 'false'
# Display a check box under the editor to allow the user to switch
# between the editor and a simple
# HTML text area. The value must be 'true' or 'false'
ALLOW_TOGGLE = 'true'
# Replaces tab characters with space characters.
# The value can be 'false' (meaning that tabs are not replaced),
# or an integer > 0 that specifies the number of spaces to replace a tab with.
REPLACE_TAB_BY_SPACES = 4
# Toggle on/off the code editor instead of textarea on startup
DISPLAY = "onload" or "later"
# if demo mode is True then admin works readonly and does not require login
DEMO_MODE = False
@@ -81,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]
+1 -1
View File
@@ -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
+2 -2
View File
@@ -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")
@@ -0,0 +1,17 @@
response.files.append(URL('static','plugin_statebutton/js/bootstrap-switch.js'))
response.files.append(URL('static','plugin_statebutton/css/bootstrap-switch.css'))
def stateWidget(field, value, data={'on-label':'Enabled', 'off-label':'Disabled', 'on':"primary", 'off':"default" }):
try:
fieldName = str(field).split('.')[1]
except:
fieldName = field
div = DIV(INPUT( _type='checkbox', _name='%s' % fieldName, _checked= 'checked' if value == 'true' else None, _value='true'),
_class='make-bootstrap-switch',
data=data)
script = SCRIPT("""
jQuery(".make-bootstrap-switch input[name='%s']").parent().bootstrapSwitch();
""" % fieldName)
return DIV(div, script)
+3 -3
View File
@@ -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)),
+43 -1
View File
@@ -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");
+21 -15
View File
@@ -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) != "<" || 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,8 +5,10 @@
unorderedBullets = '*+-';
CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) {
if (cm.getOption("disableInput")) return CodeMirror.Pass;
var pos = cm.getCursor(),
inList = cm.getStateAfter(pos.line).list,
inList = cm.getStateAfter(pos.line).list !== false,
match;
if (!inList || !(match = cm.getLine(pos.line).match(listRE))) {
@@ -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(); });
@@ -0,0 +1,42 @@
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);
var startCh;
for (var at = start.ch, pass = 0;;) {
var found = at <= 0 ? -1 : lineText.lastIndexOf(startToken, at - 1);
if (found == -1) {
if (pass == 1) return;
pass = 1;
at = lineText.length;
continue;
}
if (pass == 1 && found < start.ch) return;
if (/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1)))) {
startCh = found + startToken.length;
break;
}
at = found - 1;
}
var depth = 1, lastLine = cm.lastLine(), end, endCh;
outer: for (var i = line; i <= lastLine; ++i) {
var text = cm.getLine(i), pos = i == line ? startCh : 0;
for (;;) {
var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);
if (nextOpen < 0) nextOpen = text.length;
if (nextClose < 0) nextClose = text.length;
pos = Math.min(nextOpen, nextClose);
if (pos == text.length) break;
if (pos == nextOpen) ++depth;
else if (!--depth) { end = i; endCh = pos; break outer; }
++pos;
}
}
if (end == null || line == end && endCh == startCh) return;
return {from: CodeMirror.Pos(line, startCh),
to: CodeMirror.Pos(end, endCh)};
});
+19 -6
View File
@@ -1,10 +1,9 @@
(function() {
"use strict";
function doFold(cm, pos, options) {
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;
@@ -13,7 +12,7 @@
if (!range || range.to.line - range.from.line < minSize) return null;
var marks = cm.findMarksAt(range.from);
for (var i = 0; i < marks.length; ++i) {
if (marks[i].__isFold) {
if (marks[i].__isFold && force !== "fold") {
if (!allowFolded) return null;
range.cleared = true;
marks[i].clear();
@@ -27,7 +26,7 @@
pos = CodeMirror.Pos(pos.line - 1, 0);
range = getRange(false);
}
if (!range || range.cleared) return;
if (!range || range.cleared || force === "unfold") return;
var myWidget = makeWidget(options);
CodeMirror.on(myWidget, "mousedown", function() { myRange.clear(); });
@@ -59,7 +58,13 @@
};
// New-style interface
CodeMirror.defineExtension("foldCode", function(pos, options) { doFold(this, pos, options); });
CodeMirror.defineExtension("foldCode", function(pos, options, force) {
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);
@@ -70,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;
}
});
})();
@@ -0,0 +1,21 @@
.CodeMirror-foldmarker {
color: blue;
text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px;
font-family: arial;
line-height: .3;
cursor: pointer;
}
.CodeMirror-foldgutter {
width: .7em;
}
.CodeMirror-foldgutter-open,
.CodeMirror-foldgutter-folded {
color: #555;
cursor: pointer;
}
.CodeMirror-foldgutter-open:after {
content: "\25BE";
}
.CodeMirror-foldgutter-folded:after {
content: "\25B8";
}
@@ -0,0 +1,124 @@
(function() {
"use strict";
CodeMirror.defineOption("foldGutter", false, function(cm, val, old) {
if (old && old != CodeMirror.Init) {
cm.clearGutter(cm.state.foldGutter.options.gutter);
cm.state.foldGutter = null;
cm.off("gutterClick", onGutterClick);
cm.off("change", onChange);
cm.off("viewportChange", onViewportChange);
cm.off("fold", onFold);
cm.off("unfold", onFold);
cm.off("swapDoc", updateInViewport);
}
if (val) {
cm.state.foldGutter = new State(parseOptions(val));
updateInViewport(cm);
cm.on("gutterClick", onGutterClick);
cm.on("change", onChange);
cm.on("viewportChange", onViewportChange);
cm.on("fold", onFold);
cm.on("unfold", onFold);
cm.on("swapDoc", updateInViewport);
}
});
var Pos = CodeMirror.Pos;
function State(options) {
this.options = options;
this.from = this.to = 0;
}
function parseOptions(opts) {
if (opts === true) opts = {};
if (opts.gutter == null) opts.gutter = "CodeMirror-foldgutter";
if (opts.indicatorOpen == null) opts.indicatorOpen = "CodeMirror-foldgutter-open";
if (opts.indicatorFolded == null) opts.indicatorFolded = "CodeMirror-foldgutter-folded";
return opts;
}
function isFolded(cm, line) {
var marks = cm.findMarksAt(Pos(line));
for (var i = 0; i < marks.length; ++i)
if (marks[i].__isFold && marks[i].find().from.line == line) return true;
}
function marker(spec) {
if (typeof spec == "string") {
var elt = document.createElement("div");
elt.className = spec;
return elt;
} else {
return spec.cloneNode(true);
}
}
function updateFoldInfo(cm, from, to) {
var opts = cm.state.foldGutter.options, cur = from;
cm.eachLine(from, to, function(line) {
var mark = null;
if (isFolded(cm, cur)) {
mark = marker(opts.indicatorFolded);
} else {
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);
}
cm.setGutterMarker(line, opts.gutter, mark);
++cur;
});
}
function updateInViewport(cm) {
var vp = cm.getViewport(), state = cm.state.foldGutter;
if (!state) return;
cm.operation(function() {
updateFoldInfo(cm, vp.from, vp.to);
});
state.from = vp.from; state.to = vp.to;
}
function onGutterClick(cm, line, gutter) {
var opts = cm.state.foldGutter.options;
if (gutter != opts.gutter) return;
cm.foldCode(Pos(line, 0), opts.rangeFinder);
}
function onChange(cm) {
var state = cm.state.foldGutter, opts = cm.state.foldGutter.options;
state.from = state.to = 0;
clearTimeout(state.changeUpdate);
state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600);
}
function onViewportChange(cm) {
var state = cm.state.foldGutter, opts = cm.state.foldGutter.options;
clearTimeout(state.changeUpdate);
state.changeUpdate = setTimeout(function() {
var vp = cm.getViewport();
if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) {
updateInViewport(cm);
} else {
cm.operation(function() {
if (vp.from < state.from) {
updateFoldInfo(cm, vp.from, state.from);
state.from = vp.from;
}
if (vp.to > state.to) {
updateFoldInfo(cm, state.to, vp.to);
state.to = vp.to;
}
});
}
}, opts.updateViewportTimeSpan || 400);
}
function onFold(cm, from) {
var state = cm.state.foldGutter, line = from.line;
if (line >= state.from && line < state.to)
updateFoldInfo(cm, line, line + 1);
}
})();
@@ -1,12 +1,30 @@
CodeMirror.registerHelper("fold", "indent", function(cm, start) {
var tabSize = cm.getOption("tabSize"), firstLine = cm.getLine(start.line);
var myIndent = CodeMirror.countColumn(firstLine, null, tabSize);
for (var i = start.line + 1, end = cm.lineCount(); i < end; ++i) {
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);
if (CodeMirror.countColumn(curLine, null, tabSize) < myIndent &&
CodeMirror.countColumn(cm.getLine(i-1), null, tabSize) > myIndent)
return {from: CodeMirror.Pos(start.line, firstLine.length),
to: CodeMirror.Pos(i, curLine.length)};
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.
@@ -33,21 +34,6 @@
tprop = getToken(editor, Pos(cur.line, tprop.start));
if (tprop.string != ".") return;
tprop = getToken(editor, Pos(cur.line, tprop.start));
if (tprop.string == ')') {
var level = 1;
do {
tprop = getToken(editor, Pos(cur.line, tprop.start));
switch (tprop.string) {
case ')': level++; break;
case '(': level--; break;
default: break;
}
} while (level > 0);
tprop = getToken(editor, Pos(cur.line, tprop.start));
if (tprop.type.indexOf("variable") === 0)
tprop.type = "function";
else return; // no clue
}
if (!context) var context = [];
context.push(tprop);
}
@@ -101,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);
@@ -110,11 +96,11 @@
for (var name in obj) maybeAdd(name);
}
if (context) {
if (context && context.length) {
// If this is a property, see if it belongs to some object we can
// find in the current environment.
var obj = context.pop(), base;
if (obj.type.indexOf("variable") === 0) {
if (obj.type && obj.type.indexOf("variable") === 0) {
if (options && options.additionalContext)
base = options.additionalContext[obj.string];
base = base || window[obj.string];
@@ -132,8 +118,7 @@
while (base != null && context.length)
base = base[context.pop().string];
if (base != null) gatherCompletions(base);
}
else {
} else {
// If not, just look in the window object and any local scope
// (reading into JS mode internals to get at the local and global variables)
for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name);
@@ -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) {
+74 -13
View File
@@ -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
@@ -37,6 +37,7 @@
Pos(cur.line, token.type == "string" ? token.start : token.end));
var atName = before.match(/([^\s\u00a0=<>\"\']+)=$/), atValues;
if (!atName || !attrs.hasOwnProperty(atName[1]) || !(atValues = attrs[atName[1]])) return;
if (typeof atValues == 'function') atValues = atValues.call(this, cm); // Functions can be used to supply values for autocomplete widget
if (token.type == "string") {
prefix = token.string;
if (/['"]/.test(token.string.charAt(0))) {
@@ -45,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);
}
}
@@ -14,6 +14,7 @@
padding: 2px 5px;
position: fixed;
white-space: pre;
white-space: pre-wrap;
z-index: 100;
max-width: 600px;
opacity: 0;
+1 -1
View File
@@ -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) {
+6 -1
View File
@@ -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]);
+24 -9
View File
@@ -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();
@@ -70,6 +83,7 @@
if (!cursor.find(rev)) return;
}
cm.setSelection(cursor.from(), cursor.to());
cm.scrollIntoView({from: cursor.from(), to: cursor.to()});
state.posFrom = cursor.from(); state.posTo = cursor.to();
});}
function clearSearch(cm) {cm.operation(function() {
@@ -84,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();) {
@@ -108,6 +122,7 @@
(start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
}
cm.setSelection(cursor.from(), cursor.to());
cm.scrollIntoView({from: cursor.from(), to: cursor.to()});
confirmDialog(cm, doReplaceConfirm, "Replace?",
[function() {doReplace(match);}, advance]);
};
@@ -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);
}
})();
+12 -1
View File
@@ -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",
+165 -46
View File
@@ -76,12 +76,15 @@
{ keys: ['<C-p>'], type: 'keyToKey', toKeys: ['k'] },
{ keys: ['C-['], type: 'keyToKey', toKeys: ['<Esc>'] },
{ keys: ['<C-c>'], type: 'keyToKey', toKeys: ['<Esc>'] },
{ keys: ['s'], type: 'keyToKey', toKeys: ['c', 'l'] },
{ keys: ['S'], type: 'keyToKey', toKeys: ['c', 'c'] },
{ keys: ['s'], type: 'keyToKey', toKeys: ['c', 'l'], context: 'normal' },
{ keys: ['s'], type: 'keyToKey', toKeys: ['x', 'i'], context: 'visual'},
{ keys: ['S'], type: 'keyToKey', toKeys: ['c', 'c'], context: 'normal' },
{ keys: ['S'], type: 'keyToKey', toKeys: ['d', 'c', 'c'], context: 'visual' },
{ keys: ['<Home>'], type: 'keyToKey', toKeys: ['0'] },
{ 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',
@@ -245,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,
@@ -322,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;
}
});
@@ -340,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/)];
@@ -547,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) {
@@ -609,6 +634,9 @@
}
commandDispatcher.processCommand(cm, vim, command);
}
},
handleEx: function(cm, input) {
exCommandDispatcher.processCommand(cm, input);
}
};
@@ -695,6 +723,9 @@
if (linewise && text.charAt(0) == '\n') {
text = text.slice(1) + '\n';
}
if(linewise && text.charAt(text.length - 1) !== '\n'){
text += '\n';
}
// Lowercase and uppercase registers refer to the same register.
// Uppercase just means append.
var register = this.isValidRegister(registerName) ?
@@ -766,44 +797,80 @@
matchCommand: function(key, keyMap, vim) {
var inputState = vim.inputState;
var keys = inputState.keyBuffer.concat(key);
var matchedCommands = [];
var selectedCharacter;
for (var i = 0; i < keyMap.length; i++) {
var command = keyMap[i];
if (matchKeysPartial(keys, command.keys)) {
if (keys.length < command.keys.length) {
// Matches part of a multi-key command. Buffer and wait for next
// stroke.
inputState.keyBuffer.push(key);
return null;
}
if (inputState.operator && command.type == 'action') {
// Ignore matched action commands after an operator. Operators
// only operate on motions. This check is really for text
// objects since aW, a[ etcs conflicts with a.
continue;
}
// Matches whole comand. Return the command.
// Match commands that take <character> as an argument.
if (command.keys[keys.length - 1] == 'character') {
inputState.selectedCharacter = keys[keys.length - 1];
if(inputState.selectedCharacter.length>1){
switch(inputState.selectedCharacter){
selectedCharacter = keys[keys.length - 1];
if(selectedCharacter.length>1){
switch(selectedCharacter){
case '<CR>':
inputState.selectedCharacter='\n';
selectedCharacter='\n';
break;
case '<Space>':
inputState.selectedCharacter=' ';
selectedCharacter=' ';
break;
default:
continue;
}
}
}
// Add the command to the list of matched commands. Choose the best
// command later.
matchedCommands.push(command);
}
}
// Returns the command if it is a full match, or null if not.
function getFullyMatchedCommandOrNull(command) {
if (keys.length < command.keys.length) {
// Matches part of a multi-key command. Buffer and wait for next
// stroke.
inputState.keyBuffer.push(key);
return null;
} else {
if (command.keys[keys.length - 1] == 'character') {
inputState.selectedCharacter = selectedCharacter;
}
// Clear the buffer since a full match was found.
inputState.keyBuffer = [];
return command;
}
}
// Clear the buffer since there are no partial matches.
inputState.keyBuffer = [];
return null;
if (!matchedCommands.length) {
// Clear the buffer since there were no matches.
inputState.keyBuffer = [];
return null;
} else if (matchedCommands.length == 1) {
return getFullyMatchedCommandOrNull(matchedCommands[0]);
} else {
// Find the best match in the list of matchedCommands.
var context = vim.visualMode ? 'visual' : 'normal';
var bestMatch; // Default to first in the list.
for (var i = 0; i < matchedCommands.length; 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);
}
},
processCommand: function(cm, vim, command) {
vim.inputState.repeatOverride = command.repeatOverride;
@@ -1598,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');
@@ -1653,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);
@@ -2688,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);
}
@@ -2859,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_();
@@ -2918,6 +3024,7 @@
exCommands[commandName](cm, params);
} catch(e) {
showConfirm(cm, e);
throw e;
}
},
parseInput_: function(cm, inputStream, result) {
@@ -3000,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
@@ -3021,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);
}
}
}
@@ -3053,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) {
@@ -3061,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',
@@ -3078,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];
@@ -3087,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; }
@@ -3214,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();
@@ -3357,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();
@@ -3408,7 +3527,6 @@
var cmToVimKeymap = {
'nofallthrough': true,
'disableInput': true,
'style': 'fat-cursor'
};
function bindKeys(keys, modifier) {
@@ -3455,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"});
}
+1 -1
View File
@@ -74,7 +74,6 @@
.cm-s-default .cm-string {color: #a11;}
.cm-s-default .cm-string-2 {color: #f50;}
.cm-s-default .cm-meta {color: #555;}
.cm-s-default .cm-error {color: #f00;}
.cm-s-default .cm-qualifier {color: #555;}
.cm-s-default .cm-builtin {color: #30a;}
.cm-s-default .cm-bracket {color: #997;}
@@ -91,6 +90,7 @@
.cm-em {font-style: italic;}
.cm-link {text-decoration: underline;}
.cm-s-default .cm-error {color: #f00;}
.cm-invalidchar {color: #f00;}
div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
File diff suppressed because it is too large Load Diff
+346 -290
View File
@@ -4,86 +4,79 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css");
var indentUnit = config.indentUnit,
hooks = parserConfig.hooks || {},
atMediaTypes = parserConfig.atMediaTypes || {},
atMediaFeatures = parserConfig.atMediaFeatures || {},
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,211 +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";
state.stack.pop();
if (context == "propertyValue") state.stack.pop();
}
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 == ")") {
if (context == "propertyValue") {
// In @mediaType( without closing ; after propertyValue
state.stack.pop();
}
state.stack.pop();
}
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: "}",
@@ -314,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",
@@ -328,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",
@@ -418,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",
@@ -447,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",
@@ -532,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;
@@ -546,62 +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"];
},
tokenHooks: {
"/": function(stream, state) {
if (stream.eat("/")) {
stream.skipToEnd();
@@ -613,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"
});
})();
@@ -1,70 +0,0 @@
<!doctype html>
<title>CodeMirror: CSS mode</title>
<meta charset="utf-8"/>
<link rel=stylesheet href="../../doc/docs.css">
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="css.js"></script>
<style>.CodeMirror {background: #f8f8f8;}</style>
<div id=nav>
<a href="http://codemirror.net"><img id=logo src="../../doc/logo.png"></a>
<ul>
<li><a href="../../index.html">Home</a>
<li><a href="../../doc/manual.html">Manual</a>
<li><a href="https://github.com/marijnh/codemirror">Code</a>
</ul>
<ul>
<li><a href="../index.html">Language modes</a>
<li><a class=active href="#">CSS</a>
</ul>
</div>
<article>
<h2>CSS mode</h2>
<form><textarea id="code" name="code">
/* Some example CSS */
@import url("something.css");
body {
margin: 0;
padding: 3em 6em;
font-family: tahoma, arial, sans-serif;
color: #000;
}
#navigation a {
font-weight: bold;
text-decoration: none !important;
}
h1 {
font-size: 2.5em;
}
h2 {
font-size: 1.7em;
}
h1:before, h2:before {
content: "::";
}
code {
font-family: courier, monospace;
font-size: 80%;
color: #418A8A;
}
</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
</script>
<p><strong>MIME types defined:</strong> <code>text/css</code>.</p>
<p><strong>Parsing/Highlighting Tests:</strong> <a href="../../test/index.html#css_*">normal</a>, <a href="../../test/index.html#verbose,css_*">verbose</a>.</p>
</article>
+1 -1
View File
@@ -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>
+48 -21
View File
@@ -1,33 +1,33 @@
(function() {
var mode = CodeMirror.getMode({tabSize: 4}, "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"); }
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]{}");
@@ -39,42 +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]; } }");
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];",
" }",
"}");
})();
+64 -71
View File
@@ -1,67 +1,19 @@
(function() {
var mode = CodeMirror.getMode({tabSize: 4}, "css");
var mode = CodeMirror.getMode({indentUnit: 2}, "css");
function MT(name) { test.mode(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] { }");
@@ -73,54 +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-->]");
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};
@@ -1,60 +0,0 @@
<!doctype html>
<title>CodeMirror: Html Embedded Scripts mode</title>
<meta charset="utf-8"/>
<link rel=stylesheet href="../../doc/docs.css">
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="../xml/xml.js"></script>
<script src="../javascript/javascript.js"></script>
<script src="../css/css.js"></script>
<script src="../htmlmixed/htmlmixed.js"></script>
<script src="htmlembedded.js"></script>
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
<div id=nav>
<a href="http://codemirror.net"><img id=logo src="../../doc/logo.png"></a>
<ul>
<li><a href="../../index.html">Home</a>
<li><a href="../../doc/manual.html">Manual</a>
<li><a href="https://github.com/marijnh/codemirror">Code</a>
</ul>
<ul>
<li><a href="../index.html">Language modes</a>
<li><a class=active href="#">Html Embedded Scripts</a>
</ul>
</div>
<article>
<h2>Html Embedded Scripts mode</h2>
<form><textarea id="code" name="code">
<%
function hello(who) {
return "Hello " + who;
}
%>
This is an example of EJS (embedded javascript)
<p>The program says <%= hello("world") %>.</p>
<script>
alert("And here is some normal JS code"); // also colored
</script>
</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true,
mode: "application/x-ejs",
indentUnit: 4,
indentWithTabs: true,
enterMode: "keep",
tabMode: "shift"
});
</script>
<p>Mode for html embedded scripts like JSP and ASP.NET. Depends on HtmlMixed which in turn depends on
JavaScript, CSS and XML.<br />Other dependancies include those of the scriping language chosen.</p>
<p><strong>MIME types defined:</strong> <code>application/x-aspx</code> (ASP.NET),
<code>application/x-ejs</code> (Embedded Javascript), <code>application/x-jsp</code> (JavaServer Pages)</p>
</article>
@@ -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};
}
@@ -1,85 +0,0 @@
<!doctype html>
<title>CodeMirror: HTML mixed mode</title>
<meta charset="utf-8"/>
<link rel=stylesheet href="../../doc/docs.css">
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="../xml/xml.js"></script>
<script src="../javascript/javascript.js"></script>
<script src="../css/css.js"></script>
<script src="../vbscript/vbscript.js"></script>
<script src="htmlmixed.js"></script>
<style>.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
<div id=nav>
<a href="http://codemirror.net"><img id=logo src="../../doc/logo.png"></a>
<ul>
<li><a href="../../index.html">Home</a>
<li><a href="../../doc/manual.html">Manual</a>
<li><a href="https://github.com/marijnh/codemirror">Code</a>
</ul>
<ul>
<li><a href="../index.html">Language modes</a>
<li><a class=active href="#">HTML mixed</a>
</ul>
</div>
<article>
<h2>HTML mixed mode</h2>
<form><textarea id="code" name="code">
<html style="color: green">
<!-- this is a comment -->
<head>
<title>Mixed HTML Example</title>
<style type="text/css">
h1 {font-family: comic sans; color: #f0f;}
div {background: yellow !important;}
body {
max-width: 50em;
margin: 1em 2em 1em 5em;
}
</style>
</head>
<body>
<h1>Mixed HTML Example</h1>
<script>
function jsFunc(arg1, arg2) {
if (arg1 && arg2) document.body.innerHTML = "achoo";
}
</script>
</body>
</html>
</textarea></form>
<script>
// Define an extended mixed-mode that understands vbscript and
// leaves mustache/handlebars embedded templates in html mode
var mixedMode = {
name: "htmlmixed",
scriptTypes: [{matches: /\/x-handlebars-template|\/x-mustache/i,
mode: null},
{matches: /(text|application)\/(x-)?vb(a|script)/i,
mode: "vbscript"}]
};
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {mode: mixedMode, tabMode: "indent"});
</script>
<p>The HTML mixed mode depends on the XML, JavaScript, and CSS modes.</p>
<p>It takes an optional mode configuration
option, <code>scriptTypes</code>, which can be used to add custom
behavior for specific <code>&lt;script type="..."></code> tags. If
given, it should hold an array of <code>{matches, mode}</code>
objects, where <code>matches</code> is a string or regexp that
matches the script type, and <code>mode</code> is
either <code>null</code>, for script types that should stay in
HTML mode, or a <a href="../../doc/manual.html#option_mode">mode
spec</a> corresponding to the mode that should be used for the
script.</p>
<p><strong>MIME types defined:</strong> <code>text/html</code>
(redefined, only takes effect if you load this parser after the
XML parser).</p>
</article>
@@ -1,107 +0,0 @@
<!doctype html>
<title>CodeMirror: JavaScript mode</title>
<meta charset="utf-8"/>
<link rel=stylesheet href="../../doc/docs.css">
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="../../addon/edit/matchbrackets.js"></script>
<script src="../../addon/comment/continuecomment.js"></script>
<script src="../../addon/comment/comment.js"></script>
<script src="javascript.js"></script>
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
<div id=nav>
<a href="http://codemirror.net"><img id=logo src="../../doc/logo.png"></a>
<ul>
<li><a href="../../index.html">Home</a>
<li><a href="../../doc/manual.html">Manual</a>
<li><a href="https://github.com/marijnh/codemirror">Code</a>
</ul>
<ul>
<li><a href="../index.html">Language modes</a>
<li><a class=active href="#">JavaScript</a>
</ul>
</div>
<article>
<h2>JavaScript mode</h2>
<div><textarea id="code" name="code">
// Demo code (the actual new parser character stream implementation)
function StringStream(string) {
this.pos = 0;
this.string = string;
}
StringStream.prototype = {
done: function() {return this.pos >= this.string.length;},
peek: function() {return this.string.charAt(this.pos);},
next: function() {
if (this.pos &lt; this.string.length)
return this.string.charAt(this.pos++);
},
eat: function(match) {
var ch = this.string.charAt(this.pos);
if (typeof match == "string") var ok = ch == match;
else var ok = ch &amp;&amp; match.test ? match.test(ch) : match(ch);
if (ok) {this.pos++; return ch;}
},
eatWhile: function(match) {
var start = this.pos;
while (this.eat(match));
if (this.pos > start) return this.string.slice(start, this.pos);
},
backUp: function(n) {this.pos -= n;},
column: function() {return this.pos;},
eatSpace: function() {
var start = this.pos;
while (/\s/.test(this.string.charAt(this.pos))) this.pos++;
return this.pos - start;
},
match: function(pattern, consume, caseInsensitive) {
if (typeof pattern == "string") {
function cased(str) {return caseInsensitive ? str.toLowerCase() : str;}
if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) {
if (consume !== false) this.pos += str.length;
return true;
}
}
else {
var match = this.string.slice(this.pos).match(pattern);
if (match &amp;&amp; consume !== false) this.pos += match[0].length;
return match;
}
}
};
</textarea></div>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true,
matchBrackets: true,
continueComments: "Enter",
extraKeys: {"Ctrl-Q": "toggleComment"}
});
</script>
<p>
JavaScript mode supports a two configuration
options:
<ul>
<li><code>json</code> which will set the mode to expect JSON
data rather than a JavaScript program.</li>
<li><code>typescript</code> which will activate additional
syntax highlighting and some other things for TypeScript code
(<a href="typescript.html">demo</a>).</li>
<li><code>statementIndent</code> which (given a number) will
determine the amount of indentation to use for statements
continued on a new line.</li>
</ul>
</p>
<p><strong>MIME types defined:</strong> <code>text/javascript</code>, <code>application/json</code>, <code>text/typescript</code>, <code>application/typescript</code>.</p>
</article>
@@ -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")
+8 -3
View File
@@ -15,11 +15,14 @@ CodeMirror.modeInfo = [
{name: 'diff', mime: 'text/x-diff', mode: 'diff'},
{name: 'DTD', mime: 'application/xml-dtd', mode: 'dtd'},
{name: 'ECL', mime: 'text/x-ecl', mode: 'ecl'},
{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'},
{name: 'GO', mime: 'text/x-go', mode: 'go'},
{name: 'Go', mime: 'text/x-go', mode: 'go'},
{name: 'Groovy', mime: 'text/x-groovy', mode: 'groovy'},
{name: 'HAML', mime: 'text/x-haml', mode: 'haml'},
{name: 'Haskell', mime: 'text/x-haskell', mode: 'haskell'},
@@ -34,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'},
@@ -42,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'},
@@ -1,187 +0,0 @@
<!doctype html>
<title>CodeMirror: Python mode</title>
<meta charset="utf-8"/>
<link rel=stylesheet href="../../doc/docs.css">
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="../../addon/edit/matchbrackets.js"></script>
<script src="python.js"></script>
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
<div id=nav>
<a href="http://codemirror.net"><img id=logo src="../../doc/logo.png"></a>
<ul>
<li><a href="../../index.html">Home</a>
<li><a href="../../doc/manual.html">Manual</a>
<li><a href="https://github.com/marijnh/codemirror">Code</a>
</ul>
<ul>
<li><a href="../index.html">Language modes</a>
<li><a class=active href="#">Python</a>
</ul>
</div>
<article>
<h2>Python mode</h2>
<div><textarea id="code" name="code">
# Literals
1234
0.0e101
.123
0b01010011100
0o01234567
0x0987654321abcdef
7
2147483647
3L
79228162514264337593543950336L
0x100000000L
79228162514264337593543950336
0xdeadbeef
3.14j
10.j
10j
.001j
1e100j
3.14e-10j
# String Literals
'For\''
"God\""
"""so loved
the world"""
'''that he gave
his only begotten\' '''
'that whosoever believeth \
in him'
''
# Identifiers
__a__
a.b
a.b.c
# Operators
+ - * / % & | ^ ~ < >
== != <= >= <> << >> // **
and or not in is
# Delimiters
() [] {} , : ` = ; @ . # Note that @ and . require the proper context.
+= -= *= /= %= &= |= ^=
//= >>= <<= **=
# Keywords
as assert break class continue def del elif else except
finally for from global if import lambda pass raise
return try while with yield
# Python 2 Keywords (otherwise Identifiers)
exec print
# Python 3 Keywords (otherwise Identifiers)
nonlocal
# Types
bool classmethod complex dict enumerate float frozenset int list object
property reversed set slice staticmethod str super tuple type
# Python 2 Types (otherwise Identifiers)
basestring buffer file long unicode xrange
# Python 3 Types (otherwise Identifiers)
bytearray bytes filter map memoryview open range zip
# Some Example code
import os
from package import ParentClass
@nonsenseDecorator
def doesNothing():
pass
class ExampleClass(ParentClass):
@staticmethod
def example(inputStr):
a = list(inputStr)
a.reverse()
return ''.join(a)
def __init__(self, mixin = 'Hello'):
self.mixin = mixin
</textarea></div>
<h2>Cython mode</h2>
<div><textarea id="code-cython" name="code-cython">
import numpy as np
cimport cython
from libc.math cimport sqrt
@cython.boundscheck(False)
@cython.wraparound(False)
def pairwise_cython(double[:, ::1] X):
cdef int M = X.shape[0]
cdef int N = X.shape[1]
cdef double tmp, d
cdef double[:, ::1] D = np.empty((M, M), dtype=np.float64)
for i in range(M):
for j in range(M):
d = 0.0
for k in range(N):
tmp = X[i, k] - X[j, k]
d += tmp * tmp
D[i, j] = sqrt(d)
return np.asarray(D)
</textarea></div>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
mode: {name: "python",
version: 2,
singleLineStringErrors: false},
lineNumbers: true,
indentUnit: 4,
tabMode: "shift",
matchBrackets: true
});
CodeMirror.fromTextArea(document.getElementById("code-cython"), {
mode: {name: "text/x-cython",
version: 2,
singleLineStringErrors: false},
lineNumbers: true,
indentUnit: 4,
tabMode: "shift",
matchBrackets: true
});
</script>
<h2>Configuration Options for Python mode:</h2>
<ul>
<li>version - 2/3 - The version of Python to recognize. Default is 2.</li>
<li>singleLineStringErrors - true/false - If you have a single-line string that is not terminated at the end of the line, this will show subsequent lines as errors if true, otherwise it will consider the newline as the end of the string. Default is false.</li>
</ul>
<h2>Advanced Configuration Options:</h2>
<p>Usefull for superset of python syntax like Enthought enaml, IPython magics and questionmark help</p>
<ul>
<li>singleOperators - RegEx - Regular Expression for single operator matching, default : <pre>^[\\+\\-\\*/%&amp;|\\^~&lt;&gt;!]</pre></li>
<li>singleDelimiters - RegEx - Regular Expression for single delimiter matching, default : <pre>^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]</pre></li>
<li>doubleOperators - RegEx - Regular Expression for double operators matching, default : <pre>^((==)|(!=)|(&lt;=)|(&gt;=)|(&lt;&gt;)|(&lt;&lt;)|(&gt;&gt;)|(//)|(\\*\\*))</pre></li>
<li>doubleDelimiters - RegEx - Regular Expressoin for double delimiters matching, default : <pre>^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&amp;=)|(\\|=)|(\\^=))</pre></li>
<li>tripleDelimiters - RegEx - Regular Expression for triple delimiters matching, default : <pre>^((//=)|(&gt;&gt;=)|(&lt;&lt;=)|(\\*\\*=))</pre></li>
<li>identifiers - RegEx - Regular Expression for identifier, default : <pre>^[_A-Za-z][_A-Za-z0-9]*</pre></li>
<li>extra_keywords - list of string - List of extra words ton consider as keywords</li>
<li>extra_builtins - list of string - List of extra words ton consider as builtins</li>
</ul>
<p><strong>MIME types defined:</strong> <code>text/x-python</code> and <code>text/x-cython</code>.</p>
</article>
@@ -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;
}
@@ -1,57 +0,0 @@
<!doctype html>
<title>CodeMirror: XML mode</title>
<meta charset="utf-8"/>
<link rel=stylesheet href="../../doc/docs.css">
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="xml.js"></script>
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
<div id=nav>
<a href="http://codemirror.net"><img id=logo src="../../doc/logo.png"></a>
<ul>
<li><a href="../../index.html">Home</a>
<li><a href="../../doc/manual.html">Manual</a>
<li><a href="https://github.com/marijnh/codemirror">Code</a>
</ul>
<ul>
<li><a href="../index.html">Language modes</a>
<li><a class=active href="#">XML</a>
</ul>
</div>
<article>
<h2>XML mode</h2>
<form><textarea id="code" name="code">
&lt;html style="color: green"&gt;
&lt;!-- this is a comment --&gt;
&lt;head&gt;
&lt;title&gt;HTML Example&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
The indentation tries to be &lt;em&gt;somewhat &amp;quot;do what
I mean&amp;quot;&lt;/em&gt;... but might not match your style.
&lt;/body&gt;
&lt;/html&gt;
</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
mode: {name: "xml", alignCDATA: true},
lineNumbers: true
});
</script>
<p>The XML mode supports two configuration parameters:</p>
<dl>
<dt><code>htmlMode (boolean)</code></dt>
<dd>This switches the mode to parse HTML instead of XML. This
means attributes do not have to be quoted, and some elements
(such as <code>br</code>) do not require a closing tag.</dd>
<dt><code>alignCDATA (boolean)</code></dt>
<dd>Setting this to true will force the opening tag of CDATA
blocks to not be indented.</dd>
</dl>
<p><strong>MIME types defined:</strong> <code>application/xml</code>, <code>text/html</code>.</p>
</article>
+93 -102
View File
@@ -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) {
@@ -76,7 +76,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
tagName = "";
var c;
while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c;
if (!tagName) return "error";
if (!tagName) return "tag error";
type = isClose ? "closeTag" : "openTag";
state.tokenize = inTag;
return "tag";
@@ -109,7 +109,11 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
type = "equals";
return null;
} else if (ch == "<") {
return "error";
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)) {
state.tokenize = inAttribute(ch);
state.stringStartCol = stream.column();
@@ -167,138 +171,125 @@ 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;
return setStyle || style;
return style;
},
indent: function(state, textAfter, fullLine) {
@@ -307,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.18.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"}
}
+34
View File
@@ -0,0 +1,34 @@
/*
Name: 3024 day
Author: Jan T. Sott (http://github.com/idleberg)
CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)
Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)
*/
.cm-s-3024-day.CodeMirror {background: #f7f7f7; color: #3a3432;}
.cm-s-3024-day div.CodeMirror-selected {background: #d6d5d4 !important;}
.cm-s-3024-day .CodeMirror-gutters {background: #f7f7f7; border-right: 0px;}
.cm-s-3024-day .CodeMirror-linenumber {color: #807d7c;}
.cm-s-3024-day .CodeMirror-cursor {border-left: 1px solid #5c5855 !important;}
.cm-s-3024-day span.cm-comment {color: #cdab53;}
.cm-s-3024-day span.cm-atom {color: #a16a94;}
.cm-s-3024-day span.cm-number {color: #a16a94;}
.cm-s-3024-day span.cm-property, .cm-s-3024-day span.cm-attribute {color: #01a252;}
.cm-s-3024-day span.cm-keyword {color: #db2d20;}
.cm-s-3024-day span.cm-string {color: #fded02;}
.cm-s-3024-day span.cm-variable {color: #01a252;}
.cm-s-3024-day span.cm-variable-2 {color: #01a0e4;}
.cm-s-3024-day span.cm-def {color: #e8bbd0;}
.cm-s-3024-day span.cm-bracket {color: #3a3432;}
.cm-s-3024-day span.cm-tag {color: #db2d20;}
.cm-s-3024-day span.cm-link {color: #a16a94;}
.cm-s-3024-day span.cm-error {background: #db2d20; color: #5c5855;}
.cm-s-3024-day .CodeMirror-activeline-background {background: #e8f2ff !important;}
.cm-s-3024-day .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}
@@ -0,0 +1,34 @@
/*
Name: 3024 night
Author: Jan T. Sott (http://github.com/idleberg)
CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)
Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)
*/
.cm-s-3024-night.CodeMirror {background: #090300; color: #d6d5d4;}
.cm-s-3024-night div.CodeMirror-selected {background: #3a3432 !important;}
.cm-s-3024-night .CodeMirror-gutters {background: #090300; border-right: 0px;}
.cm-s-3024-night .CodeMirror-linenumber {color: #5c5855;}
.cm-s-3024-night .CodeMirror-cursor {border-left: 1px solid #807d7c !important;}
.cm-s-3024-night span.cm-comment {color: #cdab53;}
.cm-s-3024-night span.cm-atom {color: #a16a94;}
.cm-s-3024-night span.cm-number {color: #a16a94;}
.cm-s-3024-night span.cm-property, .cm-s-3024-night span.cm-attribute {color: #01a252;}
.cm-s-3024-night span.cm-keyword {color: #db2d20;}
.cm-s-3024-night span.cm-string {color: #fded02;}
.cm-s-3024-night span.cm-variable {color: #01a252;}
.cm-s-3024-night span.cm-variable-2 {color: #01a0e4;}
.cm-s-3024-night span.cm-def {color: #e8bbd0;}
.cm-s-3024-night span.cm-bracket {color: #d6d5d4;}
.cm-s-3024-night span.cm-tag {color: #db2d20;}
.cm-s-3024-night span.cm-link {color: #a16a94;}
.cm-s-3024-night span.cm-error {background: #db2d20; color: #807d7c;}
.cm-s-3024-night .CodeMirror-activeline-background {background: #2F2F2F !important;}
.cm-s-3024-night .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}
+2 -2
View File
@@ -15,7 +15,6 @@
.cm-s-ambiance .cm-string { color: #8f9d6a; }
.cm-s-ambiance .cm-string-2 { color: #9d937c; }
.cm-s-ambiance .cm-meta { color: #D2A8A1; }
.cm-s-ambiance .cm-error { color: #AF2018; }
.cm-s-ambiance .cm-qualifier { color: yellow; }
.cm-s-ambiance .cm-builtin { color: #9999cc; }
.cm-s-ambiance .cm-bracket { color: #24C2C7; }
@@ -26,6 +25,7 @@
.cm-s-ambiance .cm-hr { color: pink; }
.cm-s-ambiance .cm-link { color: #F4C20B; }
.cm-s-ambiance .cm-special { color: #FF9D00; }
.cm-s-ambiance .cm-error { color: #AF2018; }
.cm-s-ambiance .CodeMirror-matchingbracket { color: #0f0; }
.cm-s-ambiance .CodeMirror-nonmatchingbracket { color: #f22; }
@@ -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);
}
@@ -0,0 +1,34 @@
/*
Name: Base16 Default Dark
Author: Chris Kempson (http://chriskempson.com)
CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-chrome-devtools)
Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)
*/
.cm-s-base16-dark.CodeMirror {background: #151515; color: #e0e0e0;}
.cm-s-base16-dark div.CodeMirror-selected {background: #202020 !important;}
.cm-s-base16-dark .CodeMirror-gutters {background: #151515; border-right: 0px;}
.cm-s-base16-dark .CodeMirror-linenumber {color: #505050;}
.cm-s-base16-dark .CodeMirror-cursor {border-left: 1px solid #b0b0b0 !important;}
.cm-s-base16-dark span.cm-comment {color: #8f5536;}
.cm-s-base16-dark span.cm-atom {color: #aa759f;}
.cm-s-base16-dark span.cm-number {color: #aa759f;}
.cm-s-base16-dark span.cm-property, .cm-s-base16-dark span.cm-attribute {color: #90a959;}
.cm-s-base16-dark span.cm-keyword {color: #ac4142;}
.cm-s-base16-dark span.cm-string {color: #f4bf75;}
.cm-s-base16-dark span.cm-variable {color: #90a959;}
.cm-s-base16-dark span.cm-variable-2 {color: #6a9fb5;}
.cm-s-base16-dark span.cm-def {color: #d28445;}
.cm-s-base16-dark span.cm-bracket {color: #e0e0e0;}
.cm-s-base16-dark span.cm-tag {color: #ac4142;}
.cm-s-base16-dark span.cm-link {color: #aa759f;}
.cm-s-base16-dark span.cm-error {background: #ac4142; color: #b0b0b0;}
.cm-s-base16-dark .CodeMirror-activeline-background {background: #2F2F2F !important;}
.cm-s-base16-dark .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}
@@ -0,0 +1,34 @@
/*
Name: Base16 Default Light
Author: Chris Kempson (http://chriskempson.com)
CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-chrome-devtools)
Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)
*/
.cm-s-base16-light.CodeMirror {background: #f5f5f5; color: #202020;}
.cm-s-base16-light div.CodeMirror-selected {background: #e0e0e0 !important;}
.cm-s-base16-light .CodeMirror-gutters {background: #f5f5f5; border-right: 0px;}
.cm-s-base16-light .CodeMirror-linenumber {color: #b0b0b0;}
.cm-s-base16-light .CodeMirror-cursor {border-left: 1px solid #505050 !important;}
.cm-s-base16-light span.cm-comment {color: #8f5536;}
.cm-s-base16-light span.cm-atom {color: #aa759f;}
.cm-s-base16-light span.cm-number {color: #aa759f;}
.cm-s-base16-light span.cm-property, .cm-s-base16-light span.cm-attribute {color: #90a959;}
.cm-s-base16-light span.cm-keyword {color: #ac4142;}
.cm-s-base16-light span.cm-string {color: #f4bf75;}
.cm-s-base16-light span.cm-variable {color: #90a959;}
.cm-s-base16-light span.cm-variable-2 {color: #6a9fb5;}
.cm-s-base16-light span.cm-def {color: #d28445;}
.cm-s-base16-light span.cm-bracket {color: #202020;}
.cm-s-base16-light span.cm-tag {color: #ac4142;}
.cm-s-base16-light span.cm-link {color: #aa759f;}
.cm-s-base16-light span.cm-error {background: #ac4142; color: #505050;}
.cm-s-base16-light .CodeMirror-activeline-background {background: #DDDCDC !important;}
.cm-s-base16-light .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}
+1 -1
View File
@@ -16,13 +16,13 @@
.cm-s-blackboard .cm-string { color: #61CE3C; }
.cm-s-blackboard .cm-string-2 { color: #61CE3C; }
.cm-s-blackboard .cm-meta { color: #D8FA3C; }
.cm-s-blackboard .cm-error { background: #9D1E15; color: #F8F8F8; }
.cm-s-blackboard .cm-builtin { color: #8DA6CE; }
.cm-s-blackboard .cm-tag { color: #8DA6CE; }
.cm-s-blackboard .cm-attribute { color: #8DA6CE; }
.cm-s-blackboard .cm-header { color: #FF6400; }
.cm-s-blackboard .cm-hr { color: #AEAEAE; }
.cm-s-blackboard .cm-link { color: #8DA6CE; }
.cm-s-blackboard .cm-error { background: #9D1E15; color: #F8F8F8; }
.cm-s-blackboard .CodeMirror-activeline-background {background: #3C3636 !important;}
.cm-s-blackboard .CodeMirror-matchingbracket {outline:1px solid grey;color:white !important}
+1 -1
View File
@@ -12,10 +12,10 @@
.cm-s-cobalt span.cm-meta { color: #ff9d00; }
.cm-s-cobalt span.cm-variable-2, .cm-s-cobalt span.cm-tag { color: #9effff; }
.cm-s-cobalt span.cm-variable-3, .cm-s-cobalt span.cm-def { color: white; }
.cm-s-cobalt span.cm-error { color: #9d1e15; }
.cm-s-cobalt span.cm-bracket { color: #d8d8d8; }
.cm-s-cobalt span.cm-builtin, .cm-s-cobalt span.cm-special { color: #ff9e59; }
.cm-s-cobalt span.cm-link { color: #845dc4; }
.cm-s-cobalt span.cm-error { color: #9d1e15; }
.cm-s-cobalt .CodeMirror-activeline-background {background: #002D57 !important;}
.cm-s-cobalt .CodeMirror-matchingbracket {outline:1px solid grey;color:white !important}
+1 -1
View File
@@ -11,13 +11,13 @@
.cm-s-eclipse span.cm-comment {color: #3F7F5F;}
.cm-s-eclipse span.cm-string {color: #2A00FF;}
.cm-s-eclipse span.cm-string-2 {color: #f50;}
.cm-s-eclipse span.cm-error {color: #f00;}
.cm-s-eclipse span.cm-qualifier {color: #555;}
.cm-s-eclipse span.cm-builtin {color: #30a;}
.cm-s-eclipse span.cm-bracket {color: #cc7;}
.cm-s-eclipse span.cm-tag {color: #170;}
.cm-s-eclipse span.cm-attribute {color: #00c;}
.cm-s-eclipse span.cm-link {color: #219;}
.cm-s-eclipse span.cm-error {color: #f00;}
.cm-s-eclipse .CodeMirror-activeline-background {background: #e8f2ff !important;}
.cm-s-eclipse .CodeMirror-matchingbracket {outline:1px solid grey; color:black !important;}
+1 -1
View File
@@ -6,8 +6,8 @@
.cm-s-elegant span.cm-qualifier {color: #555;}
.cm-s-elegant span.cm-keyword {color: #730;}
.cm-s-elegant span.cm-builtin {color: #30a;}
.cm-s-elegant span.cm-error {background-color: #fdd;}
.cm-s-elegant span.cm-link {color: #762;}
.cm-s-elegant span.cm-error {background-color: #fdd;}
.cm-s-elegant .CodeMirror-activeline-background {background: #e8f2ff !important;}
.cm-s-elegant .CodeMirror-matchingbracket {outline:1px solid grey; color:black !important;}
+1 -1
View File
@@ -10,7 +10,6 @@
.cm-s-erlang-dark span.cm-builtin { color: #eaa; }
.cm-s-erlang-dark span.cm-comment { color: #77f; }
.cm-s-erlang-dark span.cm-def { color: #e7a; }
.cm-s-erlang-dark span.cm-error { color: #9d1e15; }
.cm-s-erlang-dark span.cm-keyword { color: #ffee80; }
.cm-s-erlang-dark span.cm-meta { color: #50fefe; }
.cm-s-erlang-dark span.cm-number { color: #ffd0d0; }
@@ -25,6 +24,7 @@
.cm-s-erlang-dark span.cm-variable { color: #50fe50; }
.cm-s-erlang-dark span.cm-variable-2 { color: #e0e; }
.cm-s-erlang-dark span.cm-variable-3 { color: #ccc; }
.cm-s-erlang-dark span.cm-error { color: #9d1e15; }
.cm-s-erlang-dark .CodeMirror-activeline-background {background: #013461 !important;}
.cm-s-erlang-dark .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;}
+1 -1
View File
@@ -32,7 +32,6 @@ Ported to CodeMirror by Peter Kroon
.cm-s-lesser-dark span.cm-string { color: #BCD279; }
.cm-s-lesser-dark span.cm-string-2 {color: #f50;}
.cm-s-lesser-dark span.cm-meta { color: #738C73; }
.cm-s-lesser-dark span.cm-error { color: #9d1e15; }
.cm-s-lesser-dark span.cm-qualifier {color: #555;}
.cm-s-lesser-dark span.cm-builtin { color: #ff9e59; }
.cm-s-lesser-dark span.cm-bracket { color: #EBEFE7; }
@@ -42,6 +41,7 @@ Ported to CodeMirror by Peter Kroon
.cm-s-lesser-dark span.cm-quote {color: #090;}
.cm-s-lesser-dark span.cm-hr {color: #999;}
.cm-s-lesser-dark span.cm-link {color: #00c;}
.cm-s-lesser-dark span.cm-error { color: #9d1e15; }
.cm-s-lesser-dark .CodeMirror-activeline-background {background: #3C3A3A !important;}
.cm-s-lesser-dark .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;}
+37
View File
@@ -0,0 +1,37 @@
/* Based on mbonaci's Brackets mbo theme */
.cm-s-mbo.CodeMirror {background: #2c2c2c; color: #ffffe9;}
.cm-s-mbo div.CodeMirror-selected {background: #716C62 !important;}
.cm-s-mbo .CodeMirror-gutters {background: #4e4e4e; border-right: 0px;}
.cm-s-mbo .CodeMirror-linenumber {color: #dadada;}
.cm-s-mbo .CodeMirror-cursor {border-left: 1px solid #ffffec !important;}
.cm-s-mbo span.cm-comment {color: #95958a;}
.cm-s-mbo span.cm-atom {color: #00a8c6;}
.cm-s-mbo span.cm-number {color: #00a8c6;}
.cm-s-mbo span.cm-property, .cm-s-mbo span.cm-attribute {color: #9ddfe9;}
.cm-s-mbo span.cm-keyword {color: #ffb928;}
.cm-s-mbo span.cm-string {color: #ffcf6c;}
.cm-s-mbo span.cm-variable {color: #ffffec;}
.cm-s-mbo span.cm-variable-2 {color: #00a8c6;}
.cm-s-mbo span.cm-def {color: #ffffec;}
.cm-s-mbo span.cm-bracket {color: #fffffc; font-weight: bold;}
.cm-s-mbo span.cm-tag {color: #9ddfe9;}
.cm-s-mbo span.cm-link {color: #f54b07;}
.cm-s-mbo span.cm-error {background: #636363; color: #ffffec;}
.cm-s-mbo .CodeMirror-activeline-background {background: #494b41 !important;}
.cm-s-mbo .CodeMirror-matchingbracket {
text-decoration: underline;
color: #f5e107 !important;
}
.cm-s-mbo .CodeMirror-matchingtag {background: #4e4e4e;}
.cm-s-mbo span.cm-searching {
background-color: none;
background: none;
box-shadow: 0 0 0 1px #ffffec;
}
+2 -2
View File
@@ -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-->*/
@@ -32,10 +32,10 @@
.cm-s-midnight span.cm-variable {color: #FFAA3E;}
.cm-s-midnight span.cm-variable-2 {color: #FFAA3E;}
.cm-s-midnight span.cm-def {color: #4DD;}
.cm-s-midnight span.cm-error {background: #F92672; color: #F8F8F0;}
.cm-s-midnight span.cm-bracket {color: #D1EDFF;}
.cm-s-midnight span.cm-tag {color: #449;}
.cm-s-midnight span.cm-link {color: #AE81FF;}
.cm-s-midnight span.cm-error {background: #F92672; color: #F8F8F0;}
.cm-s-midnight .CodeMirror-matchingbracket {
text-decoration: underline;
+1 -1
View File
@@ -17,10 +17,10 @@
.cm-s-monokai span.cm-variable {color: #a6e22e;}
.cm-s-monokai span.cm-variable-2 {color: #9effff;}
.cm-s-monokai span.cm-def {color: #fd971f;}
.cm-s-monokai span.cm-error {background: #f92672; color: #f8f8f0;}
.cm-s-monokai span.cm-bracket {color: #f8f8f2;}
.cm-s-monokai span.cm-tag {color: #f92672;}
.cm-s-monokai span.cm-link {color: #ae81ff;}
.cm-s-monokai span.cm-error {background: #f92672; color: #f8f8f0;}
.cm-s-monokai .CodeMirror-activeline-background {background: #373831 !important;}
.cm-s-monokai .CodeMirror-matchingbracket {
+1 -1
View File
@@ -14,11 +14,11 @@
.cm-s-night span.cm-meta { color: #7678e2; }
.cm-s-night span.cm-variable-2, .cm-s-night span.cm-tag { color: #99b2ff; }
.cm-s-night span.cm-variable-3, .cm-s-night span.cm-def { color: white; }
.cm-s-night span.cm-error { color: #9d1e15; }
.cm-s-night span.cm-bracket { color: #8da6ce; }
.cm-s-night span.cm-comment { color: #6900a1; }
.cm-s-night span.cm-builtin, .cm-s-night span.cm-special { color: #ff9e59; }
.cm-s-night span.cm-link { color: #845dc4; }
.cm-s-night span.cm-error { color: #9d1e15; }
.cm-s-night .CodeMirror-activeline-background {background: #1C005A !important;}
.cm-s-night .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;}
@@ -0,0 +1,34 @@
/*
Name: Paraíso (Dark)
Author: Jan T. Sott
Color scheme by Jan T. Sott (https://github.com/idleberg/Paraiso-CodeMirror)
Inspired by the art of Rubens LP (http://www.rubenslp.com.br)
*/
.cm-s-paraiso-dark.CodeMirror {background: #2f1e2e; color: #b9b6b0;}
.cm-s-paraiso-dark div.CodeMirror-selected {background: #41323f !important;}
.cm-s-paraiso-dark .CodeMirror-gutters {background: #2f1e2e; border-right: 0px;}
.cm-s-paraiso-dark .CodeMirror-linenumber {color: #776e71;}
.cm-s-paraiso-dark .CodeMirror-cursor {border-left: 1px solid #8d8687 !important;}
.cm-s-paraiso-dark span.cm-comment {color: #e96ba8;}
.cm-s-paraiso-dark span.cm-atom {color: #815ba4;}
.cm-s-paraiso-dark span.cm-number {color: #815ba4;}
.cm-s-paraiso-dark span.cm-property, .cm-s-paraiso-dark span.cm-attribute {color: #48b685;}
.cm-s-paraiso-dark span.cm-keyword {color: #ef6155;}
.cm-s-paraiso-dark span.cm-string {color: #fec418;}
.cm-s-paraiso-dark span.cm-variable {color: #48b685;}
.cm-s-paraiso-dark span.cm-variable-2 {color: #06b6ef;}
.cm-s-paraiso-dark span.cm-def {color: #f99b15;}
.cm-s-paraiso-dark span.cm-bracket {color: #b9b6b0;}
.cm-s-paraiso-dark span.cm-tag {color: #ef6155;}
.cm-s-paraiso-dark span.cm-link {color: #815ba4;}
.cm-s-paraiso-dark span.cm-error {background: #ef6155; color: #8d8687;}
.cm-s-paraiso-dark .CodeMirror-activeline-background {background: #4D344A !important;}
.cm-s-paraiso-dark .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}
@@ -0,0 +1,34 @@
/*
Name: Paraíso (Light)
Author: Jan T. Sott
Color scheme by Jan T. Sott (https://github.com/idleberg/Paraiso-CodeMirror)
Inspired by the art of Rubens LP (http://www.rubenslp.com.br)
*/
.cm-s-paraiso-light.CodeMirror {background: #e7e9db; color: #41323f;}
.cm-s-paraiso-light div.CodeMirror-selected {background: #b9b6b0 !important;}
.cm-s-paraiso-light .CodeMirror-gutters {background: #e7e9db; border-right: 0px;}
.cm-s-paraiso-light .CodeMirror-linenumber {color: #8d8687;}
.cm-s-paraiso-light .CodeMirror-cursor {border-left: 1px solid #776e71 !important;}
.cm-s-paraiso-light span.cm-comment {color: #e96ba8;}
.cm-s-paraiso-light span.cm-atom {color: #815ba4;}
.cm-s-paraiso-light span.cm-number {color: #815ba4;}
.cm-s-paraiso-light span.cm-property, .cm-s-paraiso-light span.cm-attribute {color: #48b685;}
.cm-s-paraiso-light span.cm-keyword {color: #ef6155;}
.cm-s-paraiso-light span.cm-string {color: #fec418;}
.cm-s-paraiso-light span.cm-variable {color: #48b685;}
.cm-s-paraiso-light span.cm-variable-2 {color: #06b6ef;}
.cm-s-paraiso-light span.cm-def {color: #f99b15;}
.cm-s-paraiso-light span.cm-bracket {color: #41323f;}
.cm-s-paraiso-light span.cm-tag {color: #ef6155;}
.cm-s-paraiso-light span.cm-link {color: #815ba4;}
.cm-s-paraiso-light span.cm-error {background: #ef6155; color: #776e71;}
.cm-s-paraiso-light .CodeMirror-activeline-background {background: #CFD1C4 !important;}
.cm-s-paraiso-light .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}
@@ -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 -1
View File
@@ -14,10 +14,10 @@
.cm-s-rubyblue span.cm-meta { color: #F0F; }
.cm-s-rubyblue span.cm-variable-2, .cm-s-rubyblue span.cm-tag { color: #7BD827; }
.cm-s-rubyblue span.cm-variable-3, .cm-s-rubyblue span.cm-def { color: white; }
.cm-s-rubyblue span.cm-error { color: #AF2018; }
.cm-s-rubyblue span.cm-bracket { color: #F0F; }
.cm-s-rubyblue span.cm-link { color: #F4C20B; }
.cm-s-rubyblue span.CodeMirror-matchingbracket { color:#F0F !important; }
.cm-s-rubyblue span.cm-builtin, .cm-s-rubyblue span.cm-special { color: #FF9D00; }
.cm-s-rubyblue span.cm-error { color: #AF2018; }
.cm-s-rubyblue .CodeMirror-activeline-background {background: #173047 !important;}
+7 -7
View File
@@ -67,11 +67,6 @@ http://ethanschoonover.com/solarized/img/solarized-palette.png
.cm-s-solarized .cm-string-2 { color: #b58900; }
.cm-s-solarized .cm-meta { color: #859900; }
.cm-s-solarized .cm-error,
.cm-s-solarized .cm-invalidchar {
color: #586e75;
border-bottom: 1px dotted #dc322f;
}
.cm-s-solarized .cm-qualifier { color: #b58900; }
.cm-s-solarized .cm-builtin { color: #d33682; }
.cm-s-solarized .cm-bracket { color: #cb4b16; }
@@ -98,6 +93,11 @@ http://ethanschoonover.com/solarized/img/solarized-palette.png
content: "➤"; /*visualize tab character*/
color: #586e75;
}
.cm-s-solarized .cm-error,
.cm-s-solarized .cm-invalidchar {
color: #586e75;
border-bottom: 1px dotted #dc322f;
}
.cm-s-solarized.cm-s-dark .CodeMirror-selected {
background: #073642;
@@ -165,10 +165,10 @@ Active line. Negative margin compensates left padding of the text in the
view-port
*/
.cm-s-solarized.cm-s-dark .CodeMirror-activeline-background {
background: rgba(255, 255, 255, 0.05);
background: rgba(255, 255, 255, 0.10);
}
.cm-s-solarized.cm-s-light .CodeMirror-activeline-background {
background: rgba(0, 0, 0, 0.05);
background: rgba(0, 0, 0, 0.10);
}
/*
@@ -0,0 +1,26 @@
.cm-s-the-matrix.CodeMirror { background: #000000; color: #00FF00; }
.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; }
.cm-s-the-matrix span.cm-keyword {color: #008803; font-weight: bold;}
.cm-s-the-matrix span.cm-atom {color: #3FF;}
.cm-s-the-matrix span.cm-number {color: #FFB94F;}
.cm-s-the-matrix span.cm-def {color: #99C;}
.cm-s-the-matrix span.cm-variable {color: #F6C;}
.cm-s-the-matrix span.cm-variable-2 {color: #C6F;}
.cm-s-the-matrix span.cm-variable-3 {color: #96F;}
.cm-s-the-matrix span.cm-property {color: #62FFA0;}
.cm-s-the-matrix span.cm-operator {color: #999}
.cm-s-the-matrix span.cm-comment {color: #CCCCCC;}
.cm-s-the-matrix span.cm-string {color: #39C;}
.cm-s-the-matrix span.cm-meta {color: #C9F;}
.cm-s-the-matrix span.cm-qualifier {color: #FFF700;}
.cm-s-the-matrix span.cm-builtin {color: #30a;}
.cm-s-the-matrix span.cm-bracket {color: #cc7;}
.cm-s-the-matrix span.cm-tag {color: #FFBD40;}
.cm-s-the-matrix span.cm-attribute {color: #FFF700;}
.cm-s-the-matrix span.cm-error {color: #FF0000;}
.cm-s-the-matrix .CodeMirror-activeline-background {background: #040;}
@@ -0,0 +1,34 @@
/*
Name: Tomorrow Night - Eighties
Author: Chris Kempson
CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)
Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)
*/
.cm-s-tomorrow-night-eighties.CodeMirror {background: #000000; color: #CCCCCC;}
.cm-s-tomorrow-night-eighties div.CodeMirror-selected {background: #2D2D2D !important;}
.cm-s-tomorrow-night-eighties .CodeMirror-gutters {background: #000000; border-right: 0px;}
.cm-s-tomorrow-night-eighties .CodeMirror-linenumber {color: #515151;}
.cm-s-tomorrow-night-eighties .CodeMirror-cursor {border-left: 1px solid #6A6A6A !important;}
.cm-s-tomorrow-night-eighties span.cm-comment {color: #d27b53;}
.cm-s-tomorrow-night-eighties span.cm-atom {color: #a16a94;}
.cm-s-tomorrow-night-eighties span.cm-number {color: #a16a94;}
.cm-s-tomorrow-night-eighties span.cm-property, .cm-s-tomorrow-night-eighties span.cm-attribute {color: #99cc99;}
.cm-s-tomorrow-night-eighties span.cm-keyword {color: #f2777a;}
.cm-s-tomorrow-night-eighties span.cm-string {color: #ffcc66;}
.cm-s-tomorrow-night-eighties span.cm-variable {color: #99cc99;}
.cm-s-tomorrow-night-eighties span.cm-variable-2 {color: #6699cc;}
.cm-s-tomorrow-night-eighties span.cm-def {color: #f99157;}
.cm-s-tomorrow-night-eighties span.cm-bracket {color: #CCCCCC;}
.cm-s-tomorrow-night-eighties span.cm-tag {color: #f2777a;}
.cm-s-tomorrow-night-eighties span.cm-link {color: #a16a94;}
.cm-s-tomorrow-night-eighties span.cm-error {background: #f2777a; color: #6A6A6A;}
.cm-s-tomorrow-night-eighties .CodeMirror-activeline-background {background: #343600 !important;}
.cm-s-tomorrow-night-eighties .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}
+1 -1
View File
@@ -16,13 +16,13 @@
.cm-s-twilight .cm-string { color:#8f9d6a; font-style:italic; } /**/
.cm-s-twilight .cm-string-2 { color:#bd6b18 } /*?*/
.cm-s-twilight .cm-meta { background-color:#141414; color:#f7f7f7; } /*?*/
.cm-s-twilight .cm-error { border-bottom: 1px solid red; }
.cm-s-twilight .cm-builtin { color: #cda869; } /*?*/
.cm-s-twilight .cm-tag { color: #997643; } /**/
.cm-s-twilight .cm-attribute { color: #d6bb6d; } /*?*/
.cm-s-twilight .cm-header { color: #FF6400; }
.cm-s-twilight .cm-hr { color: #AEAEAE; }
.cm-s-twilight .cm-link { color:#ad9361; font-style:italic; text-decoration:none; } /**/
.cm-s-twilight .cm-error { border-bottom: 1px solid red; }
.cm-s-twilight .CodeMirror-activeline-background {background: #27282E !important;}
.cm-s-twilight .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;}
+1 -1
View File
@@ -18,13 +18,13 @@
.cm-s-vibrant-ink .cm-string { color: #A5C25C }
.cm-s-vibrant-ink .cm-string-2 { color: red }
.cm-s-vibrant-ink .cm-meta { color: #D8FA3C; }
.cm-s-vibrant-ink .cm-error { border-bottom: 1px solid red; }
.cm-s-vibrant-ink .cm-builtin { color: #8DA6CE; }
.cm-s-vibrant-ink .cm-tag { color: #8DA6CE; }
.cm-s-vibrant-ink .cm-attribute { color: #8DA6CE; }
.cm-s-vibrant-ink .cm-header { color: #FF6400; }
.cm-s-vibrant-ink .cm-hr { color: #AEAEAE; }
.cm-s-vibrant-ink .cm-link { color: blue; }
.cm-s-vibrant-ink .cm-error { border-bottom: 1px solid red; }
.cm-s-vibrant-ink .CodeMirror-activeline-background {background: #27282E !important;}
.cm-s-vibrant-ink .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;}
+1 -1
View File
@@ -38,12 +38,12 @@ THE SOFTWARE.
.cm-s-xq-dark span.cm-comment {color: gray;}
.cm-s-xq-dark span.cm-string {color: #9FEE00;}
.cm-s-xq-dark span.cm-meta {color: yellow;}
.cm-s-xq-dark span.cm-error {color: #f00;}
.cm-s-xq-dark span.cm-qualifier {color: #FFF700;}
.cm-s-xq-dark span.cm-builtin {color: #30a;}
.cm-s-xq-dark span.cm-bracket {color: #cc7;}
.cm-s-xq-dark span.cm-tag {color: #FFBD40;}
.cm-s-xq-dark span.cm-attribute {color: #FFF700;}
.cm-s-xq-dark span.cm-error {color: #f00;}
.cm-s-xq-dark .CodeMirror-activeline-background {background: #27282E !important;}
.cm-s-xq-dark .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;}
+1 -1
View File
@@ -32,12 +32,12 @@ THE SOFTWARE.
.cm-s-xq-light span.cm-comment {color: #0080FF; font-style: italic;}
.cm-s-xq-light span.cm-string {color: red;}
.cm-s-xq-light span.cm-meta {color: yellow;}
.cm-s-xq-light span.cm-error {color: #f00;}
.cm-s-xq-light span.cm-qualifier {color: grey}
.cm-s-xq-light span.cm-builtin {color: #7EA656;}
.cm-s-xq-light span.cm-bracket {color: #cc7;}
.cm-s-xq-light span.cm-tag {color: #3F7F7F;}
.cm-s-xq-light span.cm-attribute {color: #7F007F;}
.cm-s-xq-light span.cm-error {color: #f00;}
.cm-s-xq-light .CodeMirror-activeline-background {background: #e8f2ff !important;}
.cm-s-xq-light .CodeMirror-matchingbracket {outline:1px solid grey;color:black !important;background:yellow;}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -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 */
@@ -16,3 +22,45 @@
background-repeat: repeat-x;
}
/* Close button on tab*/
.nav-tabs li a > .close {
font-size: 18px;
padding-left: 5px;
float: right;
margin-right: -10px;
padding-right: 5px;
}
.nav-tabs>li>a {
overflow: hidden;
white-space: nowrap;
word-wrap: normal;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
}
/*.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;
}
+41 -39
View File
@@ -1,3 +1,5 @@
var template_js = '<p class="repo-name">{{{a_tag}}}</p><small>{{address}}</small>';
function prepareDataForSave(name, data) {
var obj = new Object();
obj.Name = name;
@@ -22,8 +24,8 @@ function prepareMultiPartPOST(data) {
}
function on_error() {
jQuery("input[name='saved_on']").attr('style', 'background-color:red');
jQuery("input[name='saved_on']").val('communication error');
$("input[name='saved_on']").attr('style', 'background-color:red');
$("input[name='saved_on']").val('communication error');
}
function doHighlight(highlight) {
@@ -36,24 +38,24 @@ function doHighlight(highlight) {
function doClickSave() {
var currentTabID = '#' + jQuery('#edit_placeholder div.tab-pane.active').attr('id');
var editor = jQuery(currentTabID + ' textarea').data('editor');
var currentTabID = '#' + $('#edit_placeholder div.tab-pane.active').attr('id');
var editor = $(currentTabID + ' textarea').data('editor');
var data = editor.getValue();
var dataForPost = prepareMultiPartPOST(new Array(
prepareDataForSave('data', data),
prepareDataForSave('file_hash',
jQuery(currentTabID + " input[name='file_hash']").val()),
$(currentTabID + " input[name='file_hash']").val()),
prepareDataForSave('saved_on',
jQuery(currentTabID + " input[name='saved_on']").val()),
$(currentTabID + " input[name='saved_on']").val()),
prepareDataForSave('saved_on',
jQuery(currentTabID + " input[name='saved_on']").val()),
$(currentTabID + " input[name='saved_on']").val()),
prepareDataForSave('from_ajax', 'true')));
// console.info(area.textarea.value);
jQuery(currentTabID + " input[name='saved_on']").attr('style',
$(currentTabID + " input[name='saved_on']").attr('style',
'background-color:yellow');
jQuery(currentTabID + " input[name='saved_on']").val('saving now...')
currentUrl = jQuery(currentTabID + ' form').attr('action');
jQuery.ajax({
$(currentTabID + " input[name='saved_on']").val('saving now...')
currentUrl = $(currentTabID + ' form').attr('action');
$.ajax({
type: "POST",
contentType: 'multipart/form-data;boundary="' + dataForPost[1] + '"',
url: currentUrl,
@@ -67,38 +69,38 @@ function doClickSave() {
'doClickSave');
},
success: function (json, text, xhr) {
jQuery(editor).data('saved', true); // Set as saved
$(editor).data('saved', true); // Set as saved
editor.on("change", store_changes_function); // Re-enable change watcher
// reenable disabled submit button
var t = jQuery("input[name='save']");
var t = $("input[name='save']");
t.attr('class', '');
t.attr('disabled', '');
var flash = xhr.getResponseHeader('web2py-component-flash');
if(flash) {
jQuery('.flash').html(decodeURIComponent(flash))
$('.flash').html(decodeURIComponent(flash))
.append('<a href="#" class="close">&times;</a>')
.slideDown();
} else jQuery('.flash').hide();
} else $('.flash').hide();
try {
if(json.error) {
window.location.href = json.redirect;
} else {
// console.info( json.file_hash );
jQuery(currentTabID + " input[name='file_hash']").val(json.file_hash);
jQuery(currentTabID + " input[name='saved_on']").val(json.saved_on);
$(currentTabID + " input[name='file_hash']").val(json.file_hash);
$(currentTabID + " input[name='saved_on']").val(json.saved_on);
if(json.highlight) {
doHighlight(json.highlight);
} else {
jQuery(currentTabID + " input[name='saved_on']").attr('style', 'background-color:#99FF99');
//jQuery(".flash").delay(1000).fadeOut('slow');
$(currentTabID + " input[name='saved_on']").attr('style', 'background-color:#99FF99');
//$(".flash").delay(1000).fadeOut('slow');
}
// console.info(jQuery("input[name='file_hash']").val());
// console.info($("input[name='file_hash']").val());
var output = '<b>exposes:</b> ';
for(var i in json.functions) {
output += ' <a target="_blank" href="/' + json.application + '/' + json.controller + '/' + json.functions[i] + '">' + json.functions[i] + '</a>,';
}
if(output != '<b>exposes:</b> ') {
jQuery(currentTabID + " .exposed").html(output.substring(0, output.length - 1));
$(currentTabID + " .exposed").html(output.substring(0, output.length - 1));
}
}
} catch(e) {
@@ -113,8 +115,8 @@ function doClickSave() {
}
function getActiveEditor() {
var currentTabID = '#' + jQuery('#edit_placeholder div.tab-pane.active').attr('id');
var editor = jQuery(currentTabID + ' textarea').data('editor');
var currentTabID = '#' + $('#edit_placeholder div.tab-pane.active').attr('id');
var editor = $(currentTabID + ' textarea').data('editor');
return editor;
}
@@ -139,7 +141,7 @@ function doToggleBreakpoint(filename, url, sel) {
prepareDataForSave('sel_start', sel["start"]),
prepareDataForSave('sel_end', sel["end"]),
prepareDataForSave('data', sel['data'])));
jQuery.ajax({
$.ajax({
type: "POST",
contentType: 'multipart/form-data;boundary="' + dataForPost[1] + '"',
url: url,
@@ -156,10 +158,10 @@ function doToggleBreakpoint(filename, url, sel) {
// show flash message (if any)
var flash = xhr.getResponseHeader('web2py-component-flash');
if(flash) {
jQuery('.flash').html(decodeURIComponent(flash))
$('.flash').html(decodeURIComponent(flash))
.append('<a href="#" class="close">&times;</a>')
.slideDown();
} else jQuery('.flash').hide();
} else $('.flash').hide();
try {
if(json.error) {
window.location.href = json.redirect;
@@ -189,7 +191,7 @@ function doListBreakpoints(filename, url, editor) {
var dataForPost = prepareMultiPartPOST(new Array(
prepareDataForSave('filename', filename)
));
jQuery.ajax({
$.ajax({
type: "POST",
contentType: 'multipart/form-data;boundary="' + dataForPost[1] + '"',
url: url,
@@ -235,7 +237,7 @@ function makeMarker() {
function keepalive(url) {
jQuery.ajax({
$.ajax({
type: "GET",
url: url,
timeout: 1000,
@@ -246,8 +248,8 @@ function keepalive(url) {
});
}
function load_file(url) {
jQuery.ajax({
function load_file(url, lineno) {
$.ajax({
type: "GET",
contentType: 'application/json',
cache: false,
@@ -256,18 +258,18 @@ function load_file(url) {
timeout: 1000,
success: function (json) {
if(typeof (json['plain_html']) !== undefined) {
if(jQuery('#' + json['id']).length === 0 || json['force'] === true) {
if($('#' + json['id']).length === 0 || json['force'] === true) {
// Create a tab and put the code in it
var tab_header = '<li><a href="#' + json['id'] + '" data-toggle="tab">' + json['filename'] + '<button type="button" class="close">&times;</button></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">&times;</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) {
jQuery('#filesTab').append(jQuery(tab_header));
jQuery('#myTabContent').append(jQuery(tab_body));
$('#myTabContent').append($(tab_body)); // First load the body
$('#filesTab').append($(tab_header)); // Then load the header which trigger the shown event
} else {
jQuery('#' + json['id']).html(jQuery(tab_body));
$('#' + json['id']).html($(tab_body));
}
}
jQuery("a[href='#" + json['id'] + "']").click();
$("a[href='#" + json['id'] + "']").trigger('click', lineno);
}
},
error: function (x) {
@@ -279,11 +281,11 @@ function load_file(url) {
function set_font(editor, incr) {
var fontSize = '';
if(incr !== 0) {
fontSize = parseInt(jQuery(editor.getWrapperElement()).css('font-size'));
fontSize = parseInt($(editor.getWrapperElement()).css('font-size'));
fontSize = fontSize + incr + "px";
}
jQuery(editor.getWrapperElement()).css('font-size', fontSize);
$(editor.getWrapperElement()).css('font-size', fontSize);
editor.refresh();
}
var template_js = '<p class="repo-name">{{{a_tag}}}</p><small>{{address}}</small>';
File diff suppressed because one or more lines are too long
+52 -21
View File
@@ -167,10 +167,12 @@
else t.fadeOut();
});
doc.on('keyup', 'input.integer', function () {
this.value = this.value.reverse().replace(/[^0-9\-]|\-(?=.)/g, '').reverse();
var nvalue = this.value.reverse().replace(/[^0-9\-]|\-(?=.)/g, '').reverse();
if(this.value!=nvalue) this.value = nvalue;
});
doc.on('keyup', 'input.double, input.decimal', function () {
this.value = this.value.reverse().replace(/[^0-9\-\.,]|[\-](?=.)|[\.,](?=[0-9]*[\.,])/g, '').reverse();
var nvalue = this.value.reverse().replace(/[^0-9\-\.,]|[\-](?=.)|[\.,](?=[0-9]*[\.,])/g, '').reverse();
if(this.value!=nvalue) this.value = nvalue;
});
var confirm_message = (typeof w2p_ajax_confirm_message != 'undefined') ? w2p_ajax_confirm_message : "Are you sure you want to delete this object?";
doc.on('click', "input[type='checkbox'].delete", function () {
@@ -248,22 +250,33 @@
});
},
trap_form: function (action, target) {
/* traps any LOADed form */
$('#' + target + ' form').each(function (i) {
var form = $(this);
form.attr('data-w2p_target', target);
if(!form.hasClass('no_trap')) {
/* should be there by default */
form.submit(function (e) {
web2py.disableElement(form.find(web2py.formInputClickSelector));
web2py.hide_flash();
web2py.ajax_page('post', action, form.serialize(), target, form);
e.preventDefault();
});
if (form.hasClass('no_trap')) {
return;
}
form.attr('data-w2p_target', target);
var url = form.attr('action');
if ((url === "") || (url === "#")) {
/* form has no action. Use component url. */
url = action;
}
form.submit(function (e) {
web2py.disableElement(form.find(web2py.formInputClickSelector));
web2py.hide_flash();
web2py.ajax_page('post', url, form.serialize(), target, form);
e.preventDefault();
});
});
},
ajax_page: function (method, action, data, target, element) {
/* element is a new parameter, but should be put be put in front */
if(element == undefined) element = $(document);
@@ -295,7 +308,7 @@
},
'complete': function (xhr, status) {
web2py.fire(element, 'ajax:complete', [xhr, status], target);
web2py.updatePage(xhr, target); /* Parse and load the html received */
web2py.updatePage(xhr, target); /* Parse and load the html received */
web2py.trap_form(action, target);
web2py.ajax_init('#' + target);
web2py.after_ajax(xhr);
@@ -445,8 +458,8 @@
} else return false; /* not supported */
},
/* new from here */
/* Form input elements bound by jquery-uj */
formInputClickSelector: 'input[type=submit], input[type=image], button[type=submit], button:not([type])',
/* Form input elements bound by web2py.js */
formInputClickSelector: 'input[type=submit]:not([name]), input[type=image]:not([name]), button[type=submit]:not([name]), button:not([type]):not([name])',
/* Form input elements disabled during form submission */
disableSelector: 'input, button, textarea, select',
/* Form input elements re-enabled after form submission */
@@ -472,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]());
@@ -513,7 +528,7 @@
if(flash.html()) flash.append('<span id="closeflash"> &times; </span>').slideDown();
},
hide_flash: function () {
$('.flash').hide().html('');
$('.flash').fadeOut(0).html('');
},
show_if_handler: function (target) {
var triggers = {};
@@ -620,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);
});
@@ -634,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);
});
},
@@ -646,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 */
@@ -666,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');});
});
});

Some files were not shown because too many files have changed in this diff Show More