Commit 11d821c7 authored by Jérome Perrin's avatar Jérome Perrin

codemirror: update Codemirror to 5.13.4

This is newer codemirror with support to jump to line keybinding https://github.com/codemirror/CodeMirror/issues/3030


/cc @isabelle I don't know if this interfere with 53a4b813 

/reviewed-on !98
parents be003c1a f84beaab
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
<script type="text/javascript" src="&dtml-portal_url;/codemirror/addon/dialog/dialog.js"></script>\n <script type="text/javascript" src="&dtml-portal_url;/codemirror/addon/dialog/dialog.js"></script>\n
<script type="text/javascript" src="&dtml-portal_url;/codemirror/addon/search/searchcursor.js"></script>\n <script type="text/javascript" src="&dtml-portal_url;/codemirror/addon/search/searchcursor.js"></script>\n
<script type="text/javascript" src="&dtml-portal_url;/codemirror/addon/search/search.js"></script>\n <script type="text/javascript" src="&dtml-portal_url;/codemirror/addon/search/search.js"></script>\n
<script type="text/javascript" src="&dtml-portal_url;/codemirror/addon/search/jump-to-line.js"></script>\n
\n \n
<!-- Python autocomplete (Ctrl-Space, see below)\n <!-- Python autocomplete (Ctrl-Space, see below)\n
TODO-arnau: Add ERP5 autocompletion?\n TODO-arnau: Add ERP5 autocompletion?\n
......
*.txt text
*.js text
*.html text
*.md text
*.json text
*.yml text
*.css text
*.svg text
...@@ -24,6 +24,11 @@ Alexander Solovyov ...@@ -24,6 +24,11 @@ Alexander Solovyov
Alexandre Bique Alexandre Bique
alexey-k alexey-k
Alex Piggott Alex Piggott
Aliaksei Chapyzhenka
Allen Sarkisyan
Amin Shali
Amin Ullah Khan
amshali@google.com
Amsul Amsul
amuntean amuntean
Amy Amy
...@@ -32,8 +37,10 @@ anaran ...@@ -32,8 +37,10 @@ anaran
AndersMad AndersMad
Anders Nawroth Anders Nawroth
Anderson Mesquita Anderson Mesquita
Anders Wåglund
Andrea G Andrea G
Andreas Reischuck Andreas Reischuck
Andres Taylor
Andre von Houck Andre von Houck
Andrey Fedorov Andrey Fedorov
Andrey Klyuchnikov Andrey Klyuchnikov
...@@ -41,23 +48,34 @@ Andrey Lushnikov ...@@ -41,23 +48,34 @@ Andrey Lushnikov
Andy Joslin Andy Joslin
Andy Kimball Andy Kimball
Andy Li Andy Li
Angelo
angelozerr angelozerr
angelo.zerr@gmail.com angelo.zerr@gmail.com
Ankit
Ankit Ahuja Ankit Ahuja
Ansel Santosa Ansel Santosa
Anthony Dugois
anthonygego
Anthony Gégo
Anthony Grimes Anthony Grimes
Anton Kovalyov Anton Kovalyov
AQNOUCH Mohammed
areos areos
Arnab Bose
as3boyan as3boyan
AtomicPages LLC AtomicPages LLC
Atul Bhouraskar Atul Bhouraskar
Aurelian Oancea Aurelian Oancea
Barret Rennie
Basarat Ali Syed
Bastian Müller Bastian Müller
belhaj
Bem Jones-Bey Bem Jones-Bey
benbro benbro
Beni Cherniavsky-Paskin Beni Cherniavsky-Paskin
Benjamin DeCoste Benjamin DeCoste
Ben Keen Ben Keen
Ben Mosher
Bernhard Sirlinger Bernhard Sirlinger
Bert Chang Bert Chang
Billy Moon Billy Moon
...@@ -67,23 +85,35 @@ Blaine G ...@@ -67,23 +85,35 @@ Blaine G
blukat29 blukat29
boomyjee boomyjee
borawjm borawjm
Brad Metcalf
Brandon Frohs Brandon Frohs
Brandon Wamboldt Brandon Wamboldt
Brett Zamir Brett Zamir
Brian Grinstead Brian Grinstead
Brian Sletten Brian Sletten
Bruce Mitchener Bruce Mitchener
Caitlin Potter
Calin Barbat
Chad Jolly
Chandra Sekhar Pydi Chandra Sekhar Pydi
Charles Skelton Charles Skelton
Cheah Chu Yeow Cheah Chu Yeow
Chris Coyier Chris Coyier
Chris Ford
Chris Granger Chris Granger
Chris Houseknecht Chris Houseknecht
Chris Lohfink
Chris Morgan Chris Morgan
Christian Oyarzun Christian Oyarzun
Christian Petrov
Christopher Brown Christopher Brown
Christopher Mitchell
Christopher Pfohl
Chunliang Lyu
ciaranj ciaranj
CodeAnimal CodeAnimal
coderaiser
Cole R Lawrence
ComFreek ComFreek
Curtis Gagliardi Curtis Gagliardi
dagsta dagsta
...@@ -95,21 +125,27 @@ Daniel, Dao Quang Minh ...@@ -95,21 +125,27 @@ Daniel, Dao Quang Minh
Daniele Di Sarli Daniele Di Sarli
Daniel Faust Daniel Faust
Daniel Huigens Daniel Huigens
Daniel Kesler
Daniel KJ Daniel KJ
Daniel Neel Daniel Neel
Daniel Parnell Daniel Parnell
Danny Yoo Danny Yoo
darealshinji darealshinji
Darius Roberts Darius Roberts
Dave Brondsema
Dave Myers Dave Myers
David Barnett
David Mignot David Mignot
David Pathakjee David Pathakjee
David Vázquez David Vázquez
David Whittington
deebugger deebugger
Deep Thought Deep Thought
Devin Abbott
Devon Carew Devon Carew
dignifiedquire dignifiedquire
Dimage Sapelkin Dimage Sapelkin
Dmitry Kiselyov
domagoj412 domagoj412
Dominator008 Dominator008
Domizio Demichelis Domizio Demichelis
...@@ -117,13 +153,16 @@ Doug Wikle ...@@ -117,13 +153,16 @@ Doug Wikle
Drew Bratcher Drew Bratcher
Drew Hintz Drew Hintz
Drew Khoury Drew Khoury
Drini Cami
Dror BG Dror BG
duralog duralog
eborden eborden
edsharp edsharp
ekhaled ekhaled
Elisée
Enam Mijbah Noor Enam Mijbah Noor
Eric Allam Eric Allam
Erik Welander
eustas eustas
Fabien O'Carroll Fabien O'Carroll
Fabio Zendhi Nagao Fabio Zendhi Nagao
...@@ -138,43 +177,54 @@ flack ...@@ -138,43 +177,54 @@ flack
ForbesLindesay ForbesLindesay
Forbes Lindesay Forbes Lindesay
Ford_Lawnmower Ford_Lawnmower
Forrest Oliphant
Frank Wiegand Frank Wiegand
Gabriel Gheorghian Gabriel Gheorghian
Gabriel Horner Gabriel Horner
Gabriel Nahmias Gabriel Nahmias
galambalazs galambalazs
Gautam Mehta Gautam Mehta
Gavin Douglas
gekkoe gekkoe
geowarin
Gerard Braad Gerard Braad
Gergely Hegykozi Gergely Hegykozi
Giovanni Calò
Glebov Boris
Glenn Jorde Glenn Jorde
Glenn Ruehle Glenn Ruehle
Golevka Golevka
Google Inc.
Gordon Smith Gordon Smith
Grant Skinner Grant Skinner
greengiant greengiant
Gregory Koberger Gregory Koberger
Guillaume Massé Guillaume Massé
Guillaume Massé Guillaume Massé
guraga
Gustavo Rodrigues Gustavo Rodrigues
Hakan Tunc Hakan Tunc
Hans Engel Hans Engel
Hardest Hardest
Hasan Karahan Hasan Karahan
Hector Oswaldo Caballero
Herculano Campos Herculano Campos
Hiroyuki Makino Hiroyuki Makino
hitsthings hitsthings
Hocdoc Hocdoc
Hugues Malphettes
Ian Beck Ian Beck
Ian Dickinson Ian Dickinson
Ian Wehrman Ian Wehrman
Ian Wetherbee Ian Wetherbee
Ice White Ice White
ICHIKAWA, Yuji ICHIKAWA, Yuji
idleberg
ilvalle ilvalle
Ingo Richter Ingo Richter
Irakli Gozalishvili Irakli Gozalishvili
Ivan Kurnosov Ivan Kurnosov
Ivoah
Jacob Lee Jacob Lee
Jakob Miland Jakob Miland
Jakub Vrana Jakub Vrana
...@@ -186,6 +236,7 @@ Jan Jongboom ...@@ -186,6 +236,7 @@ Jan Jongboom
jankeromnes jankeromnes
Jan Keromnes Jan Keromnes
Jan Odvarko Jan Odvarko
Jan Schär
Jan T. Sott Jan T. Sott
Jared Forsyth Jared Forsyth
Jason Jason
...@@ -196,34 +247,49 @@ Jason San Jose ...@@ -196,34 +247,49 @@ Jason San Jose
Jason Siefken Jason Siefken
Jaydeep Solanki Jaydeep Solanki
Jean Boussier Jean Boussier
Jeff Blaisdell
jeffkenton jeffkenton
Jeff Pickhardt Jeff Pickhardt
jem (graphite) jem (graphite)
Jeremy Parmenter Jeremy Parmenter
Jim
JobJob
jochenberger
Jochen Berger Jochen Berger
Johan Ask Johan Ask
John Connor John Connor
John Engler
John Lees-Miller John Lees-Miller
John Snelson John Snelson
John Van Der Loo John Van Der Loo
Jon Ander Peñalba
Jonas Döbertin
Jonathan Malmaud Jonathan Malmaud
jongalloway jongalloway
Jon Malmaud Jon Malmaud
Jon Sangster Jon Sangster
Joost-Wim Boekesteijn Joost-Wim Boekesteijn
Joseph Pecoraro Joseph Pecoraro
Josh Cohen
Joshua Newman Joshua Newman
Josh Watzman Josh Watzman
jots jots
jsoojeon jsoojeon
ju1ius
Juan Benavides Romero Juan Benavides Romero
Jucovschi Constantin Jucovschi Constantin
Juho Vuori Juho Vuori
Julien Rebetez
Justin Andresen
Justin Hileman Justin Hileman
jwallers@gmail.com jwallers@gmail.com
kaniga kaniga
karevn
Kayur Patel
Ken Newman Ken Newman
ken restivo
Ken Rockot Ken Rockot
Kevin Earls
Kevin Sawicki Kevin Sawicki
Kevin Ushey Kevin Ushey
Klaus Silveira Klaus Silveira
...@@ -233,6 +299,7 @@ Konstantin Lopuhin ...@@ -233,6 +299,7 @@ Konstantin Lopuhin
koops koops
ks-ifware ks-ifware
kubelsmieci kubelsmieci
KwanEsq
Lanfei Lanfei
Lanny Lanny
Laszlo Vidacs Laszlo Vidacs
...@@ -241,12 +308,16 @@ Leonid Khachaturov ...@@ -241,12 +308,16 @@ Leonid Khachaturov
Leon Sorokin Leon Sorokin
Leonya Khachaturov Leonya Khachaturov
Liam Newman Liam Newman
Libo Cannici
LloydMilligan
LM LM
lochel lochel
Lorenzo Stoakes Lorenzo Stoakes
Luciano Longo Luciano Longo
Luke Stagner Luke Stagner
lynschinzer lynschinzer
M1cha
Madhura Jayaratne
Maksim Lin Maksim Lin
Maksym Taran Maksym Taran
Malay Majithia Malay Majithia
...@@ -256,19 +327,28 @@ Marcel Gerber ...@@ -256,19 +327,28 @@ Marcel Gerber
Marco Aurélio Marco Aurélio
Marco Munizaga Marco Munizaga
Marcus Bointon Marcus Bointon
Marek Rudnicki
Marijn Haverbeke Marijn Haverbeke
Mário Gonçalves Mário Gonçalves
Mario Pietsch Mario Pietsch
Mark Anderson
Mark Lentczner Mark Lentczner
Marko Bonaci Marko Bonaci
Markus Bordihn
Martin Balek Martin Balek
Martín Gaitán Martín Gaitán
Martin Hasoň Martin Hasoň
Martin Hunt
Martin Laine
Martin Zagora
Mason Malone Mason Malone
Mateusz Paprocki Mateusz Paprocki
Mathias Bynens Mathias Bynens
mats cronqvist mats cronqvist
Matt Gaide
Matthew Bauer
Matthew Beale Matthew Beale
Matthew Rathbone
Matthias Bussonnier Matthias Bussonnier
Matthias BUSSONNIER Matthias BUSSONNIER
Matt McDonald Matt McDonald
...@@ -278,14 +358,23 @@ mauricio ...@@ -278,14 +358,23 @@ mauricio
Maximilian Hils Maximilian Hils
Maxim Kraev Maxim Kraev
Max Kirsch Max Kirsch
Max Schaefer
Max Xiantu Max Xiantu
mbarkhau mbarkhau
McBrainy
melpon
Metatheos Metatheos
Micah Dubinko Micah Dubinko
Michael
Michael Goderbauer
Michael Grey
Michael Kaminsky
Michael Lehenbauer Michael Lehenbauer
Michael Zhou Michael Zhou
Michal Dorner
Mighty Guava Mighty Guava
Miguel Castillo Miguel Castillo
mihailik
Mike Mike
Mike Brevoort Mike Brevoort
Mike Diaz Mike Diaz
...@@ -294,20 +383,25 @@ Mike Kadin ...@@ -294,20 +383,25 @@ Mike Kadin
MinRK MinRK
Miraculix87 Miraculix87
misfo misfo
mkaminsky11
mloginov mloginov
Moritz Schwörer Moritz Schwörer
mps mps
ms
mtaran-google mtaran-google
Narciso Jaramillo Narciso Jaramillo
Nathan Williams Nathan Williams
ndr ndr
nerbert nerbert
nextrevision nextrevision
ngn
nguillaumin nguillaumin
Ng Zhi An Ng Zhi An
Nicholas Bollweg Nicholas Bollweg
Nicholas Bollweg (Nick) Nicholas Bollweg (Nick)
Nick Kreeger
Nick Small Nick Small
Nicolò Ribaudo
Niels van Groningen Niels van Groningen
nightwing nightwing
Nikita Beloglazov Nikita Beloglazov
...@@ -316,37 +410,54 @@ Nikolay Kostov ...@@ -316,37 +410,54 @@ Nikolay Kostov
nilp0inter nilp0inter
Nisarg Jhaveri Nisarg Jhaveri
nlwillia nlwillia
noragrossman
Norman Rzepka Norman Rzepka
Oreoluwa Onatemowo
pablo pablo
pabloferz
Page Page
Panupong Pasupat Panupong Pasupat
paris paris
Paris
Patil Arpith Patil Arpith
Patrick Stoica Patrick Stoica
Patrick Strawderman Patrick Strawderman
Paul Garvin Paul Garvin
Paul Ivanov Paul Ivanov
Pavel
Pavel Feldman Pavel Feldman
Pavel Strashkin Pavel Strashkin
Paweł Bartkiewicz Paweł Bartkiewicz
peteguhl peteguhl
peter
Peter Flynn Peter Flynn
peterkroon peterkroon
Peter Kroon Peter Kroon
Philipp A
Philip Stadermann
Pierre Gerold
Piët Delport
prasanthj prasanthj
Prasanth J Prasanth J
Prayag Verma
Radek Piórkowski Radek Piórkowski
Rahul Rahul
Rahul Anand
ramwin1
Randall Mason Randall Mason
Randy Burden Randy Burden
Randy Edmunds Randy Edmunds
Rasmus Erik Voel Jensen Rasmus Erik Voel Jensen
ray ratchup
Ray Ratchup
Richard Denton
Richard van der Meer Richard van der Meer
Richard Z.H. Wang Richard Z.H. Wang
Robert Crossfield Robert Crossfield
Roberto Abdelkader Martínez Pérez Roberto Abdelkader Martínez Pérez
robertop23 robertop23
Robert Plummer Robert Plummer
Rrandom
Ruslan Osmanov Ruslan Osmanov
Ryan Prior Ryan Prior
sabaca sabaca
...@@ -355,20 +466,26 @@ sandeepshetty ...@@ -355,20 +466,26 @@ sandeepshetty
Sander AKA Redsandro Sander AKA Redsandro
santec santec
Sascha Peilicke Sascha Peilicke
satamas
satchmorun satchmorun
sathyamoorthi sathyamoorthi
S. Chris Colbert
SCLINIC\jdecker SCLINIC\jdecker
Scott Aikin Scott Aikin
Scott Goodhew Scott Goodhew
Sebastian Zaha Sebastian Zaha
Sergey Goder
Se-Won Kim
shaund shaund
shaun gilchrist shaun gilchrist
Shawn A Shawn A
Shea Bunge
sheopory sheopory
Shiv Deepak Shiv Deepak
Shmuel Englard Shmuel Englard
Shubham Jain Shubham Jain
silverwind silverwind
sinkuu
snasa snasa
soliton4 soliton4
sonson sonson
...@@ -378,13 +495,23 @@ Stanislav Oaserele ...@@ -378,13 +495,23 @@ Stanislav Oaserele
Stas Kobzar Stas Kobzar
Stefan Borsje Stefan Borsje
Steffen Beyer Steffen Beyer
Steffen Bruchmann
Stephen Lavelle
Steve Champagne
Steve O'Hara Steve O'Hara
stoskov stoskov
Stu Kennedy
Sungho Kim
sverweij
Taha Jahangir Taha Jahangir
Tako Schotanus
Takuji Shimokawa Takuji Shimokawa
Tarmil Tarmil
TDaglis
tel
tfjgeorge tfjgeorge
Thaddee Tyl Thaddee Tyl
thanasis
TheHowl TheHowl
think think
Thomas Dvornik Thomas Dvornik
...@@ -401,23 +528,31 @@ Tom MacWright ...@@ -401,23 +528,31 @@ Tom MacWright
Tony Jian Tony Jian
Travis Heppe Travis Heppe
Triangle717 Triangle717
Tristan Tarrant
TSUYUSATO Kitsune
twifkak twifkak
Vestimir Markov Vestimir Markov
vf vf
Victor Bocharsky
Vincent Woo Vincent Woo
Volker Mische Volker Mische
wenli wenli
Wes Cossick
Wesley Wiser Wesley Wiser
Will Binns-Smith Will Binns-Smith
Will Dean
William Jamieson William Jamieson
William Stein William Stein
Willy Willy
Wojtek Ptak Wojtek Ptak
Wu Cheng-Han
Xavier Mendez Xavier Mendez
Yassin N. Hassan Yassin N. Hassan
YNH Webdev YNH Webdev
Yunchi Luo Yunchi Luo
Yuvi Panda Yuvi Panda
Zac Anger
Zachary Dremann Zachary Dremann
Zhang Hao
zziuni zziuni
魏鹏刚 魏鹏刚
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
<dictionary> <dictionary>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
<value> <string>.travis.yml</string> </value> <value> <string>CHANGELOG.md</string> </value>
</item> </item>
<item> <item>
<key> <string>_vars</string> </key> <key> <string>_vars</string> </key>
......
# How to contribute # How to contribute
- [Getting help](#getting-help-) - [Getting help](#getting-help)
- [Submitting bug reports](#submitting-bug-reports-) - [Submitting bug reports](#submitting-bug-reports)
- [Contributing code](#contributing-code-) - [Contributing code](#contributing-code)
## Getting help ## Getting help
...@@ -61,12 +61,24 @@ should be asked on the ...@@ -61,12 +61,24 @@ should be asked on the
- Make sure all tests pass. Visit `test/index.html` in your browser to - Make sure all tests pass. Visit `test/index.html` in your browser to
run them. run them.
- Submit a pull request - Submit a pull request
([how to create a pull request](https://help.github.com/articles/fork-a-repo)) ([how to create a pull request](https://help.github.com/articles/fork-a-repo)).
Don't put more than one feature/fix in a single pull request.
By contributing code to CodeMirror you
- agree to license the contributed code under CodeMirror's [MIT
license](http://codemirror.net/LICENSE).
- confirm that you have the right to contribute and license the code
in question. (Either you hold all rights on the code, or the rights
holder has explicitly granted the right to use it like this,
through a compatible open source license or through a direct
agreement with you.)
### Coding standards ### Coding standards
- 2 spaces per indentation level, no tabs. - 2 spaces per indentation level, no tabs.
- Include semicolons after statements.
- Note that the linter (`bin/lint`) which is run after each commit - Note that the linter (`bin/lint`) which is run after each commit
complains about unused variables and functions. Prefix their names complains about unused variables and functions. Prefix their names
with an underscore to muffle it. with an underscore to muffle it.
......
Copyright (C) 2014 by Marijn Haverbeke <marijnh@gmail.com> and others Copyright (C) 2016 by Marijn Haverbeke <marijnh@gmail.com> and others
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
......
# CodeMirror
[![Build Status](https://travis-ci.org/codemirror/CodeMirror.svg)](https://travis-ci.org/codemirror/CodeMirror)
[![NPM version](https://img.shields.io/npm/v/codemirror.svg)](https://www.npmjs.org/package/codemirror)
CodeMirror is a JavaScript component that provides a code editor in
the browser. When a mode is available for the language you are coding
in, it will color your code, and optionally help with indentation.
The project page is http://codemirror.net
The manual is at http://codemirror.net/doc/manual.html
The contributing guidelines are in [CONTRIBUTING.md](https://github.com/codemirror/CodeMirror/blob/master/CONTRIBUTING.md)
# CodeMirror
[![Build Status](https://travis-ci.org/codemirror/CodeMirror.svg)](https://travis-ci.org/codemirror/CodeMirror)
[![NPM version](https://img.shields.io/npm/v/codemirror.svg)](https://www.npmjs.org/package/codemirror)
[![Join the chat at https://gitter.im/codemirror/CodeMirror](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/codemirror/CodeMirror)
[Funding status: ![maintainer happiness](https://marijnhaverbeke.nl/fund/status_s.png?again)](https://marijnhaverbeke.nl/fund/)
CodeMirror is a versatile text editor implemented in JavaScript for
the browser. It is specialized for editing code, and comes with over
100 language modes and various addons that implement more advanced
editing functionality.
A rich programming API and a CSS theming system are available for
customizing CodeMirror to fit your application, and extending it with
new functionality.
You can find more information (and the
[manual](http://codemirror.net/doc/manual.html)) on the [project
page](http://codemirror.net). For questions and discussion, use the
[discussion forum](https://discuss.codemirror.net/).
See
[CONTRIBUTING.md](https://github.com/codemirror/CodeMirror/blob/master/CONTRIBUTING.md)
for contributing guidelines.
The CodeMirror community aims to be welcoming to everybody. We use the
[Contributor Covenant
(1.1)](http://contributor-covenant.org/version/1/1/0/) as our code of
conduct.
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897295.56</string> </value> <value> <string>ts60604371.88</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>6302</int> </value> <value> <int>6945</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -94,33 +94,36 @@ ...@@ -94,33 +94,36 @@
} }
} }
function autoCloseSlash(cm) { function autoCloseCurrent(cm, typingSlash) {
if (cm.getOption("disableInput")) return CodeMirror.Pass;
var ranges = cm.listSelections(), replacements = []; var ranges = cm.listSelections(), replacements = [];
var head = typingSlash ? "/" : "</";
for (var i = 0; i < ranges.length; i++) { for (var i = 0; i < ranges.length; i++) {
if (!ranges[i].empty()) return CodeMirror.Pass; if (!ranges[i].empty()) return CodeMirror.Pass;
var pos = ranges[i].head, tok = cm.getTokenAt(pos); var pos = ranges[i].head, tok = cm.getTokenAt(pos);
var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state; var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
if (tok.type == "string" || tok.string.charAt(0) != "<" || if (typingSlash && (tok.type == "string" || tok.string.charAt(0) != "<" ||
tok.start != pos.ch - 1) tok.start != pos.ch - 1))
return CodeMirror.Pass; return CodeMirror.Pass;
// Kludge to get around the fact that we are not in XML mode // Kludge to get around the fact that we are not in XML mode
// when completing in JS/CSS snippet in htmlmixed mode. Does not // when completing in JS/CSS snippet in htmlmixed mode. Does not
// work for other XML embedded languages (there is no general // work for other XML embedded languages (there is no general
// way to go from a mixed mode to its current XML state). // way to go from a mixed mode to its current XML state).
var replacement;
if (inner.mode.name != "xml") { if (inner.mode.name != "xml") {
if (cm.getMode().name == "htmlmixed" && inner.mode.name == "javascript") if (cm.getMode().name == "htmlmixed" && inner.mode.name == "javascript")
replacements[i] = "/script>"; replacement = head + "script";
else if (cm.getMode().name == "htmlmixed" && inner.mode.name == "css") else if (cm.getMode().name == "htmlmixed" && inner.mode.name == "css")
replacements[i] = "/style>"; replacement = head + "style";
else else
return CodeMirror.Pass; return CodeMirror.Pass;
} else { } else {
if (!state.context || !state.context.tagName || if (!state.context || !state.context.tagName ||
closingTagExists(cm, state.context.tagName, pos, state)) closingTagExists(cm, state.context.tagName, pos, state))
return CodeMirror.Pass; return CodeMirror.Pass;
replacements[i] = "/" + state.context.tagName + ">"; replacement = head + state.context.tagName;
} }
if (cm.getLine(pos.line).charAt(tok.end) != ">") replacement += ">";
replacements[i] = replacement;
} }
cm.replaceSelections(replacements); cm.replaceSelections(replacements);
ranges = cm.listSelections(); ranges = cm.listSelections();
...@@ -129,6 +132,13 @@ ...@@ -129,6 +132,13 @@
cm.indentLine(ranges[i].head.line); cm.indentLine(ranges[i].head.line);
} }
function autoCloseSlash(cm) {
if (cm.getOption("disableInput")) return CodeMirror.Pass;
return autoCloseCurrent(cm, true);
}
CodeMirror.commands.closeTag = function(cm) { return autoCloseCurrent(cm); };
function indexOf(collection, elt) { function indexOf(collection, elt) {
if (collection.indexOf) return collection.indexOf(elt); if (collection.indexOf) return collection.indexOf(elt);
for (var i = 0, e = collection.length; i < e; ++i) for (var i = 0, e = collection.length; i < e; ++i)
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897295.63</string> </value> <value> <string>ts60604371.94</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>7331</int> </value> <value> <int>7705</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -11,36 +11,36 @@ ...@@ -11,36 +11,36 @@
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
var listRE = /^(\s*)(>[> ]*|[*+-]\s|(\d+)\.)(\s*)/, var listRE = /^(\s*)(>[> ]*|[*+-]\s|(\d+)([.)]))(\s*)/,
emptyListRE = /^(\s*)(>[> ]*|[*+-]|(\d+)\.)(\s*)$/, emptyListRE = /^(\s*)(>[> ]*|[*+-]|(\d+)[.)])(\s*)$/,
unorderedListRE = /[*+-]\s/; unorderedListRE = /[*+-]\s/;
CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) { CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) {
if (cm.getOption("disableInput")) return CodeMirror.Pass; if (cm.getOption("disableInput")) return CodeMirror.Pass;
var ranges = cm.listSelections(), replacements = []; var ranges = cm.listSelections(), replacements = [];
for (var i = 0; i < ranges.length; i++) { for (var i = 0; i < ranges.length; i++) {
var pos = ranges[i].head, match; var pos = ranges[i].head;
var eolState = cm.getStateAfter(pos.line); var eolState = cm.getStateAfter(pos.line);
var inList = eolState.list !== false; var inList = eolState.list !== false;
var inQuote = eolState.quote !== false; var inQuote = eolState.quote !== 0;
if (!ranges[i].empty() || (!inList && !inQuote) || !(match = cm.getLine(pos.line).match(listRE))) { var line = cm.getLine(pos.line), match = listRE.exec(line);
if (!ranges[i].empty() || (!inList && !inQuote) || !match) {
cm.execCommand("newlineAndIndent"); cm.execCommand("newlineAndIndent");
return; return;
} }
if (cm.getLine(pos.line).match(emptyListRE)) { if (emptyListRE.test(line)) {
cm.replaceRange("", { cm.replaceRange("", {
line: pos.line, ch: 0 line: pos.line, ch: 0
}, { }, {
line: pos.line, ch: pos.ch + 1 line: pos.line, ch: pos.ch + 1
}); });
replacements[i] = "\n"; replacements[i] = "\n";
} else { } else {
var indent = match[1], after = match[4]; var indent = match[1], after = match[5];
var bullet = unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0 var bullet = unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0
? match[2] ? match[2]
: (parseInt(match[3], 10) + 1) + "."; : (parseInt(match[3], 10) + 1) + match[4];
replacements[i] = "\n" + indent + bullet + after; replacements[i] = "\n" + indent + bullet + after;
} }
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897295.78</string> </value> <value> <string>ts60604371.99</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>1752</int> </value> <value> <int>1761</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -81,7 +81,7 @@ ...@@ -81,7 +81,7 @@
if (marks.length) { if (marks.length) {
// Kludge to work around the IE bug from issue #1193, where text // 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 textare whever this fires.
if (ie_lt8 && cm.state.focused) cm.display.input.focus(); if (ie_lt8 && cm.state.focused) cm.focus();
var clear = function() { var clear = function() {
cm.operation(function() { cm.operation(function() {
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897295.92</string> </value> <value> <string>ts60604372.04</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>5268</int> </value> <value> <int>5254</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897296.03</string> </value> <value> <string>ts60604372.1</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897285.4</string> </value> <value> <string>ts60604372.11</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
......
...@@ -21,22 +21,28 @@ ...@@ -21,22 +21,28 @@
} }
CodeMirror.commands.toggleComment = function(cm) { CodeMirror.commands.toggleComment = function(cm) {
var minLine = Infinity, ranges = cm.listSelections(), mode = null; cm.toggleComment();
};
CodeMirror.defineExtension("toggleComment", function(options) {
if (!options) options = noOptions;
var cm = this;
var minLine = Infinity, ranges = this.listSelections(), mode = null;
for (var i = ranges.length - 1; i >= 0; i--) { for (var i = ranges.length - 1; i >= 0; i--) {
var from = ranges[i].from(), to = ranges[i].to(); var from = ranges[i].from(), to = ranges[i].to();
if (from.line >= minLine) continue; if (from.line >= minLine) continue;
if (to.line >= minLine) to = Pos(minLine, 0); if (to.line >= minLine) to = Pos(minLine, 0);
minLine = from.line; minLine = from.line;
if (mode == null) { if (mode == null) {
if (cm.uncomment(from, to)) mode = "un"; if (cm.uncomment(from, to, options)) mode = "un";
else { cm.lineComment(from, to); mode = "line"; } else { cm.lineComment(from, to, options); mode = "line"; }
} else if (mode == "un") { } else if (mode == "un") {
cm.uncomment(from, to); cm.uncomment(from, to, options);
} else { } else {
cm.lineComment(from, to); cm.lineComment(from, to, options);
} }
} }
}; });
CodeMirror.defineExtension("lineComment", function(from, to, options) { CodeMirror.defineExtension("lineComment", function(from, to, options) {
if (!options) options = noOptions; if (!options) options = noOptions;
...@@ -57,7 +63,14 @@ ...@@ -57,7 +63,14 @@
self.operation(function() { self.operation(function() {
if (options.indent) { if (options.indent) {
var baseString = firstLine.slice(0, firstNonWS(firstLine)); var baseString = null;
for (var i = from.line; i < end; ++i) {
var line = self.getLine(i);
var whitespace = line.slice(0, firstNonWS(line));
if (baseString == null || baseString.length > whitespace.length) {
baseString = whitespace;
}
}
for (var i = from.line; i < end; ++i) { for (var i = from.line; i < end; ++i) {
var line = self.getLine(i), cut = baseString.length; var line = self.getLine(i), cut = baseString.length;
if (!blankLines && !nonWS.test(line)) continue; if (!blankLines && !nonWS.test(line)) continue;
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897117.58</string> </value> <value> <string>ts60604372.17</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>8008</int> </value> <value> <int>8446</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897117.72</string> </value> <value> <string>ts60604372.22</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
......
.CodeMirror-dialog { .CodeMirror-dialog {
position: absolute; position: absolute;
left: 0; right: 0; left: 0; right: 0;
background: white; background: inherit;
z-index: 15; z-index: 15;
padding: .1em .8em; padding: .1em .8em;
overflow: hidden; overflow: hidden;
color: #333; color: inherit;
} }
.CodeMirror-dialog-top { .CodeMirror-dialog-top {
......
...@@ -56,10 +56,14 @@ ...@@ -56,10 +56,14 @@
var inp = dialog.getElementsByTagName("input")[0], button; var inp = dialog.getElementsByTagName("input")[0], button;
if (inp) { if (inp) {
inp.focus();
if (options.value) { if (options.value) {
inp.value = options.value; inp.value = options.value;
if (options.selectValueOnOpen !== false) {
inp.select(); inp.select();
} }
}
if (options.onInput) if (options.onInput)
CodeMirror.on(inp, "input", function(e) { options.onInput(e, inp.value, close);}); CodeMirror.on(inp, "input", function(e) { options.onInput(e, inp.value, close);});
...@@ -77,8 +81,6 @@ ...@@ -77,8 +81,6 @@
}); });
if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", close); if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", close);
inp.focus();
} else if (button = dialog.getElementsByTagName("button")[0]) { } else if (button = dialog.getElementsByTagName("button")[0]) {
CodeMirror.on(button, "click", function() { CodeMirror.on(button, "click", function() {
close(); close();
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897119.98</string> </value> <value> <string>ts60604372.34</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>4875</int> </value> <value> <int>4938</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"))
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod)
else // Plain browser env
mod(CodeMirror)
})(function(CodeMirror) {
"use strict"
CodeMirror.defineOption("autoRefresh", false, function(cm, val) {
if (cm.state.autoRefresh) {
stopListening(cm, cm.state.autoRefresh)
cm.state.autoRefresh = null
}
if (val && cm.display.wrapper.offsetHeight == 0)
startListening(cm, cm.state.autoRefresh = {delay: val.delay || 250})
})
function startListening(cm, state) {
function check() {
if (cm.display.wrapper.offsetHeight) {
stopListening(cm, state)
if (cm.display.lastWrapHeight != cm.display.wrapper.clientHeight)
cm.refresh()
} else {
state.timeout = setTimeout(check, state.delay)
}
}
state.timeout = setTimeout(check, state.delay)
state.hurry = function() {
clearTimeout(state.timeout)
state.timeout = setTimeout(check, 50)
}
CodeMirror.on(window, "mouseup", state.hurry)
CodeMirror.on(window, "keyup", state.hurry)
}
function stopListening(_cm, state) {
clearTimeout(state.timeout)
CodeMirror.off(window, "mouseup", state.hurry)
CodeMirror.off(window, "keyup", state.hurry)
}
});
...@@ -12,11 +12,11 @@ ...@@ -12,11 +12,11 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897148.81</string> </value> <value> <string>ts60604372.39</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
<value> <string>smartymixed.js</string> </value> <value> <string>autorefresh.js</string> </value>
</item> </item>
<item> <item>
<key> <string>content_type</string> </key> <key> <string>content_type</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>6638</int> </value> <value> <int>1543</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897117.34</string> </value> <value> <string>ts60604372.5</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
......
...@@ -10,13 +10,31 @@ ...@@ -10,13 +10,31 @@
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
CodeMirror.defineExtension("addPanel", function(node, options) { CodeMirror.defineExtension("addPanel", function(node, options) {
options = options || {};
if (!this.state.panels) initPanels(this); if (!this.state.panels) initPanels(this);
var info = this.state.panels; var info = this.state.panels;
if (options && options.position == "bottom") var wrapper = info.wrapper;
info.wrapper.appendChild(node); var cmWrapper = this.getWrapperElement();
else
info.wrapper.insertBefore(node, info.wrapper.firstChild); if (options.after instanceof Panel && !options.after.cleared) {
wrapper.insertBefore(node, options.before.node.nextSibling);
} else if (options.before instanceof Panel && !options.before.cleared) {
wrapper.insertBefore(node, options.before.node);
} else if (options.replace instanceof Panel && !options.replace.cleared) {
wrapper.insertBefore(node, options.replace.node);
options.replace.clear();
} else if (options.position == "bottom") {
wrapper.appendChild(node);
} else if (options.position == "before-bottom") {
wrapper.insertBefore(node, cmWrapper.nextSibling);
} else if (options.position == "after-top") {
wrapper.insertBefore(node, cmWrapper);
} else {
wrapper.insertBefore(node, wrapper.firstChild);
}
var height = (options && options.height) || node.offsetHeight; var height = (options && options.height) || node.offsetHeight;
this._setSize(null, info.heightLeft -= height); this._setSize(null, info.heightLeft -= height);
info.panels++; info.panels++;
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897117.22</string> </value> <value> <string>ts60604372.55</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>3102</int> </value> <value> <int>3844</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -14,10 +14,12 @@ ...@@ -14,10 +14,12 @@
if (val && !prev) { if (val && !prev) {
cm.on("blur", onBlur); cm.on("blur", onBlur);
cm.on("change", onChange); cm.on("change", onChange);
cm.on("swapDoc", onChange);
onChange(cm); onChange(cm);
} else if (!val && prev) { } else if (!val && prev) {
cm.off("blur", onBlur); cm.off("blur", onBlur);
cm.off("change", onChange); cm.off("change", onChange);
cm.off("swapDoc", onChange);
clearPlaceholder(cm); clearPlaceholder(cm);
var wrapper = cm.getWrapperElement(); var wrapper = cm.getWrapperElement();
wrapper.className = wrapper.className.replace(" CodeMirror-empty", ""); wrapper.className = wrapper.className.replace(" CodeMirror-empty", "");
...@@ -37,7 +39,9 @@ ...@@ -37,7 +39,9 @@
var elt = cm.state.placeholder = document.createElement("pre"); var elt = cm.state.placeholder = document.createElement("pre");
elt.style.cssText = "height: 0; overflow: visible"; elt.style.cssText = "height: 0; overflow: visible";
elt.className = "CodeMirror-placeholder"; elt.className = "CodeMirror-placeholder";
elt.appendChild(document.createTextNode(cm.getOption("placeholder"))); var placeHolder = cm.getOption("placeholder")
if (typeof placeHolder == "string") placeHolder = document.createTextNode(placeHolder)
elt.appendChild(placeHolder)
cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild); cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild);
} }
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897116.97</string> </value> <value> <string>ts60604372.61</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>1971</int> </value> <value> <int>2139</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
for (var i = 0; i < val.length; i++) { for (var i = 0; i < val.length; i++) {
var elt = document.createElement("div"); var elt = document.createElement("div");
elt.className = "CodeMirror-ruler"; elt.className = "CodeMirror-ruler";
var col, cls = null, conf = val[i]; var col, conf = val[i];
if (typeof conf == "number") { if (typeof conf == "number") {
col = conf; col = conf;
} else { } else {
...@@ -47,7 +47,6 @@ ...@@ -47,7 +47,6 @@
if (conf.color) elt.style.borderColor = conf.color; if (conf.color) elt.style.borderColor = conf.color;
if (conf.lineStyle) elt.style.borderLeftStyle = conf.lineStyle; if (conf.lineStyle) elt.style.borderLeftStyle = conf.lineStyle;
if (conf.width) elt.style.borderLeftWidth = conf.width; if (conf.width) elt.style.borderLeftWidth = conf.width;
cls = val[i].className;
} }
elt.style.left = (left + col * cw) + "px"; elt.style.left = (left + col * cw) + "px";
elt.style.top = "-50px"; elt.style.top = "-50px";
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897117.47</string> </value> <value> <string>ts60604372.67</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>2134</int> </value> <value> <int>2090</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897116.87</string> </value> <value> <string>ts60604372.72</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
......
...@@ -28,7 +28,9 @@ CodeMirror.registerGlobalHelper("fold", "comment", function(mode) { ...@@ -28,7 +28,9 @@ CodeMirror.registerGlobalHelper("fold", "comment", function(mode) {
continue; continue;
} }
if (pass == 1 && found < start.ch) return; if (pass == 1 && found < start.ch) return;
if (/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1)))) { if (/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1))) &&
(lineText.slice(found - endToken.length, found) == endToken ||
!/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found))))) {
startCh = found + startToken.length; startCh = found + startToken.length;
break; break;
} }
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897116.29</string> </value> <value> <string>ts60604372.78</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>1999</int> </value> <value> <int>2147</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -142,4 +142,8 @@ ...@@ -142,4 +142,8 @@
return editorOptions[name]; return editorOptions[name];
return defaultOptions[name]; return defaultOptions[name];
} }
CodeMirror.defineExtension("foldOption", function(options, name) {
return getOption(this, options, name);
});
}); });
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897116.45</string> </value> <value> <string>ts60604372.84</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>4574</int> </value> <value> <int>4693</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
cm.off("viewportChange", onViewportChange); cm.off("viewportChange", onViewportChange);
cm.off("fold", onFold); cm.off("fold", onFold);
cm.off("unfold", onFold); cm.off("unfold", onFold);
cm.off("swapDoc", updateInViewport); cm.off("swapDoc", onChange);
} }
if (val) { if (val) {
cm.state.foldGutter = new State(parseOptions(val)); cm.state.foldGutter = new State(parseOptions(val));
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
cm.on("viewportChange", onViewportChange); cm.on("viewportChange", onViewportChange);
cm.on("fold", onFold); cm.on("fold", onFold);
cm.on("unfold", onFold); cm.on("unfold", onFold);
cm.on("swapDoc", updateInViewport); cm.on("swapDoc", onChange);
} }
}); });
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
function isFolded(cm, line) { function isFolded(cm, line) {
var marks = cm.findMarksAt(Pos(line)); var marks = cm.findMarksAt(Pos(line));
for (var i = 0; i < marks.length; ++i) for (var i = 0; i < marks.length; ++i)
if (marks[i].__isFold && marks[i].find().from.line == line) return true; if (marks[i].__isFold && marks[i].find().from.line == line) return marks[i];
} }
function marker(spec) { function marker(spec) {
...@@ -67,14 +67,16 @@ ...@@ -67,14 +67,16 @@
function updateFoldInfo(cm, from, to) { function updateFoldInfo(cm, from, to) {
var opts = cm.state.foldGutter.options, cur = from; var opts = cm.state.foldGutter.options, cur = from;
var minSize = cm.foldOption(opts, "minFoldSize");
var func = cm.foldOption(opts, "rangeFinder");
cm.eachLine(from, to, function(line) { cm.eachLine(from, to, function(line) {
var mark = null; var mark = null;
if (isFolded(cm, cur)) { if (isFolded(cm, cur)) {
mark = marker(opts.indicatorFolded); mark = marker(opts.indicatorFolded);
} else { } else {
var pos = Pos(cur, 0), func = opts.rangeFinder || CodeMirror.fold.auto; var pos = Pos(cur, 0);
var range = func && func(cm, pos); var range = func && func(cm, pos);
if (range && range.from.line + 1 < range.to.line) if (range && range.to.line - range.from.line >= minSize)
mark = marker(opts.indicatorOpen); mark = marker(opts.indicatorOpen);
} }
cm.setGutterMarker(line, opts.gutter, mark); cm.setGutterMarker(line, opts.gutter, mark);
...@@ -92,20 +94,28 @@ ...@@ -92,20 +94,28 @@
} }
function onGutterClick(cm, line, gutter) { function onGutterClick(cm, line, gutter) {
var opts = cm.state.foldGutter.options; var state = cm.state.foldGutter;
if (!state) return;
var opts = state.options;
if (gutter != opts.gutter) return; if (gutter != opts.gutter) return;
cm.foldCode(Pos(line, 0), opts.rangeFinder); var folded = isFolded(cm, line);
if (folded) folded.clear();
else cm.foldCode(Pos(line, 0), opts.rangeFinder);
} }
function onChange(cm) { function onChange(cm) {
var state = cm.state.foldGutter, opts = cm.state.foldGutter.options; var state = cm.state.foldGutter;
if (!state) return;
var opts = state.options;
state.from = state.to = 0; state.from = state.to = 0;
clearTimeout(state.changeUpdate); clearTimeout(state.changeUpdate);
state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600); state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600);
} }
function onViewportChange(cm) { function onViewportChange(cm) {
var state = cm.state.foldGutter, opts = cm.state.foldGutter.options; var state = cm.state.foldGutter;
if (!state) return;
var opts = state.options;
clearTimeout(state.changeUpdate); clearTimeout(state.changeUpdate);
state.changeUpdate = setTimeout(function() { state.changeUpdate = setTimeout(function() {
var vp = cm.getViewport(); var vp = cm.getViewport();
...@@ -127,7 +137,9 @@ ...@@ -127,7 +137,9 @@
} }
function onFold(cm, from) { function onFold(cm, from) {
var state = cm.state.foldGutter, line = from.line; var state = cm.state.foldGutter;
if (!state) return;
var line = from.line;
if (line >= state.from && line < state.to) if (line >= state.from && line < state.to)
updateFoldInfo(cm, line, line + 1); updateFoldInfo(cm, line, line + 1);
} }
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897116.36</string> </value> <value> <string>ts60604372.95</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>4372</int> </value> <value> <int>4612</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897116.2</string> </value> <value> <string>ts60604373.0</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897116.73</string> </value> <value> <string>ts60604373.06</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
......
...@@ -174,7 +174,7 @@ ...@@ -174,7 +174,7 @@
} }
}; };
// Used by addon/edit/closetag.js // Used by addon/cm_edit/closetag.js
CodeMirror.scanForClosingTag = function(cm, pos, name, end) { CodeMirror.scanForClosingTag = function(cm, pos, name, end) {
var iter = new Iter(cm, pos.line, pos.ch, end ? {from: 0, to: end} : null); var iter = new Iter(cm, pos.line, pos.ch, end ? {from: 0, to: end} : null);
return findMatchingClose(iter, name); return findMatchingClose(iter, name);
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897116.59</string> </value> <value> <string>ts60604373.08</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>6570</int> </value> <value> <int>6573</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
while (start && word.test(curLine.charAt(start - 1))) --start; while (start && word.test(curLine.charAt(start - 1))) --start;
var curWord = start != end && curLine.slice(start, end); var curWord = start != end && curLine.slice(start, end);
var list = [], seen = {}; var list = options && options.list || [], seen = {};
var re = new RegExp(word.source, "g"); var re = new RegExp(word.source, "g");
for (var dir = -1; dir <= 1; dir += 2) { for (var dir = -1; dir <= 1; dir += 2) {
var line = cur.line, endLine = Math.min(Math.max(line + dir * range, editor.firstLine()), editor.lastLine()) + dir; var line = cur.line, endLine = Math.min(Math.max(line + dir * range, editor.firstLine()), editor.lastLine()) + dir;
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897118.73</string> </value> <value> <string>ts60604373.14</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>1653</int> </value> <value> <int>1680</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -20,6 +20,10 @@ ...@@ -20,6 +20,10 @@
var inner = CodeMirror.innerMode(cm.getMode(), token.state); var inner = CodeMirror.innerMode(cm.getMode(), token.state);
if (inner.mode.name != "css") return; if (inner.mode.name != "css") return;
if (token.type == "keyword" && "!important".indexOf(token.string) == 0)
return {list: ["!important"], from: CodeMirror.Pos(cur.line, token.start),
to: CodeMirror.Pos(cur.line, token.end)};
var start = token.start, end = cur.ch, word = token.string.slice(0, end - start); var start = token.start, end = cur.ch, word = token.string.slice(0, end - start);
if (/[^\w$_-]/.test(word)) { if (/[^\w$_-]/.test(word)) {
word = ""; start = end = cur.ch; word = ""; start = end = cur.ch;
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897119.18</string> </value> <value> <string>ts60604373.19</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>1951</int> </value> <value> <int>2165</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897119.52</string> </value> <value> <string>ts60604373.25</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897119.08</string> </value> <value> <string>ts60604373.27</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897118.88</string> </value> <value> <string>ts60604373.38</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>14333</int> </value> <value> <int>16422</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -20,77 +20,153 @@ ...@@ -20,77 +20,153 @@
}; };
var Pos = CodeMirror.Pos; var Pos = CodeMirror.Pos;
function isArray(val) { return Object.prototype.toString.call(val) == "[object Array]" }
function getKeywords(editor) { function getKeywords(editor) {
var mode = editor.doc.modeOption; var mode = editor.doc.modeOption;
if (mode === "sql") mode = "text/x-sql"; if (mode === "sql") mode = "text/x-sql";
return CodeMirror.resolveMode(mode).keywords; return CodeMirror.resolveMode(mode).keywords;
} }
function getText(item) {
return typeof item == "string" ? item : item.text;
}
function wrapTable(name, value) {
if (isArray(value)) value = {columns: value}
if (!value.text) value.text = name
return value
}
function parseTables(input) {
var result = {}
if (isArray(input)) {
for (var i = input.length - 1; i >= 0; i--) {
var item = input[i]
result[getText(item).toUpperCase()] = wrapTable(getText(item), item)
}
} else if (input) {
for (var name in input)
result[name.toUpperCase()] = wrapTable(name, input[name])
}
return result
}
function getTable(name) {
return tables[name.toUpperCase()]
}
function shallowClone(object) {
var result = {};
for (var key in object) if (object.hasOwnProperty(key))
result[key] = object[key];
return result;
}
function match(string, word) { function match(string, word) {
var len = string.length; var len = string.length;
var sub = word.substr(0, len); var sub = getText(word).substr(0, len);
return string.toUpperCase() === sub.toUpperCase(); return string.toUpperCase() === sub.toUpperCase();
} }
function addMatches(result, search, wordlist, formatter) { function addMatches(result, search, wordlist, formatter) {
for (var word in wordlist) { if (isArray(wordlist)) {
if (!wordlist.hasOwnProperty(word)) continue; for (var i = 0; i < wordlist.length; i++)
if (Array.isArray(wordlist)) { if (match(search, wordlist[i])) result.push(formatter(wordlist[i]))
word = wordlist[word]; } else {
} for (var word in wordlist) if (wordlist.hasOwnProperty(word)) {
if (match(search, word)) { var val = wordlist[word]
result.push(formatter(word)); if (!val || val === true)
val = word
else
val = val.displayText ? {text: val.text, displayText: val.displayText} : val.text
if (match(search, val)) result.push(formatter(val))
} }
} }
} }
function nameCompletion(cur, token, result, editor) { function cleanName(name) {
var useBacktick = (token.string.charAt(0) == "`"); // Get rid name from backticks(`) and preceding dot(.)
var string = token.string.substr(1); if (name.charAt(0) == ".") {
var prevToken = editor.getTokenAt(Pos(cur.line, token.start)); name = name.substr(1);
if (token.string.charAt(0) == "." || prevToken.string == "."){
//Suggest colunm names
if (prevToken.string == ".") {
var prevToken = editor.getTokenAt(Pos(cur.line, token.start - 1));
}
var table = prevToken.string;
//Check if backtick is used in table name. If yes, use it for columns too.
var useBacktickTable = false;
if (table.match(/`/g)) {
useBacktickTable = true;
table = table.replace(/`/g, "");
}
//Check if table is available. If not, find table by Alias
if (!tables.hasOwnProperty(table))
table = findTableByAlias(table, editor);
var columns = tables[table];
if (!columns) return;
if (useBacktick) {
addMatches(result, string, columns, function(w) {return "`" + w + "`";});
} }
else if(useBacktickTable) { return name.replace(/`/g, "");
addMatches(result, string, columns, function(w) {return ".`" + w + "`";});
} }
else {
addMatches(result, string, columns, function(w) {return "." + w;}); function insertBackticks(name) {
var nameParts = getText(name).split(".");
for (var i = 0; i < nameParts.length; i++)
nameParts[i] = "`" + nameParts[i] + "`";
var escaped = nameParts.join(".");
if (typeof name == "string") return escaped;
name = shallowClone(name);
name.text = escaped;
return name;
} }
function nameCompletion(cur, token, result, editor) {
// Try to complete table, colunm names and return start position of completion
var useBacktick = false;
var nameParts = [];
var start = token.start;
var cont = true;
while (cont) {
cont = (token.string.charAt(0) == ".");
useBacktick = useBacktick || (token.string.charAt(0) == "`");
start = token.start;
nameParts.unshift(cleanName(token.string));
token = editor.getTokenAt(Pos(cur.line, token.start));
if (token.string == ".") {
cont = true;
token = editor.getTokenAt(Pos(cur.line, token.start));
} }
else {
//Suggest table names or colums in defaultTable
while (token.start && string.charAt(0) == ".") {
token = editor.getTokenAt(Pos(cur.line, token.start - 1));
string = token.string + string;
} }
if (useBacktick) {
addMatches(result, string, tables, function(w) {return "`" + w + "`";}); // Try to complete table names
addMatches(result, string, defaultTable, function(w) {return "`" + w + "`";}); var string = nameParts.join(".");
addMatches(result, string, tables, function(w) {
return useBacktick ? insertBackticks(w) : w;
});
// Try to complete columns from defaultTable
addMatches(result, string, defaultTable, function(w) {
return useBacktick ? insertBackticks(w) : w;
});
// Try to complete columns
string = nameParts.pop();
var table = nameParts.join(".");
var alias = false;
var aliasTable = table;
// Check if table is available. If not, find table by Alias
if (!getTable(table)) {
var oldTable = table;
table = findTableByAlias(table, editor);
if (table !== oldTable) alias = true;
} }
else {
addMatches(result, string, tables, function(w) {return w;}); var columns = getTable(table);
addMatches(result, string, defaultTable, function(w) {return w;}); if (columns && columns.columns)
columns = columns.columns;
if (columns) {
addMatches(result, string, columns, function(w) {
var tableInsert = table;
if (alias == true) tableInsert = aliasTable;
if (typeof w == "string") {
w = tableInsert + "." + w;
} else {
w = shallowClone(w);
w.text = tableInsert + "." + w.text;
} }
return useBacktick ? insertBackticks(w) : w;
});
} }
return start;
} }
function eachWord(lineText, f) { function eachWord(lineText, f) {
...@@ -135,7 +211,7 @@ ...@@ -135,7 +211,7 @@
//find valid range //find valid range
var prevItem = 0; var prevItem = 0;
var current = convertCurToNumber(editor.getCursor()); var current = convertCurToNumber(editor.getCursor());
for (var i=0; i< separator.length; i++) { for (var i = 0; i < separator.length; i++) {
var _v = convertCurToNumber(separator[i]); var _v = convertCurToNumber(separator[i]);
if (current > prevItem && current <= _v) { if (current > prevItem && current <= _v) {
validRange = { start: convertNumberToCur(prevItem), end: convertNumberToCur(_v) }; validRange = { start: convertNumberToCur(prevItem), end: convertNumberToCur(_v) };
...@@ -150,12 +226,10 @@ ...@@ -150,12 +226,10 @@
var lineText = query[i]; var lineText = query[i];
eachWord(lineText, function(word) { eachWord(lineText, function(word) {
var wordUpperCase = word.toUpperCase(); var wordUpperCase = word.toUpperCase();
if (wordUpperCase === aliasUpperCase && tables.hasOwnProperty(previousWord)) { if (wordUpperCase === aliasUpperCase && getTable(previousWord))
table = previousWord; table = previousWord;
} if (wordUpperCase !== CONS.ALIAS_KEYWORD)
if (wordUpperCase !== CONS.ALIAS_KEYWORD) {
previousWord = word; previousWord = word;
}
}); });
if (table) break; if (table) break;
} }
...@@ -163,11 +237,20 @@ ...@@ -163,11 +237,20 @@
} }
CodeMirror.registerHelper("hint", "sql", function(editor, options) { CodeMirror.registerHelper("hint", "sql", function(editor, options) {
tables = (options && options.tables) || {}; tables = parseTables(options && options.tables)
var defaultTableName = options && options.defaultTable; var defaultTableName = options && options.defaultTable;
defaultTable = (defaultTableName && tables[defaultTableName] || []); var disableKeywords = options && options.disableKeywords;
defaultTable = defaultTableName && getTable(defaultTableName);
keywords = keywords || getKeywords(editor); keywords = keywords || getKeywords(editor);
if (defaultTableName && !defaultTable)
defaultTable = findTableByAlias(defaultTableName, editor);
defaultTable = defaultTable || [];
if (defaultTable.columns)
defaultTable = defaultTable.columns;
var cur = editor.getCursor(); var cur = editor.getCursor();
var result = []; var result = [];
var token = editor.getTokenAt(cur), start, end, search; var token = editor.getTokenAt(cur), start, end, search;
...@@ -185,10 +268,11 @@ ...@@ -185,10 +268,11 @@
search = ""; search = "";
} }
if (search.charAt(0) == "." || search.charAt(0) == "`") { if (search.charAt(0) == "." || search.charAt(0) == "`") {
nameCompletion(cur, token, result, editor); start = nameCompletion(cur, token, result, editor);
} else { } else {
addMatches(result, search, tables, function(w) {return w;}); addMatches(result, search, tables, function(w) {return w;});
addMatches(result, search, defaultTable, function(w) {return w;}); addMatches(result, search, defaultTable, function(w) {return w;});
if (!disableKeywords)
addMatches(result, search, keywords, function(w) {return w.toUpperCase();}); addMatches(result, search, keywords, function(w) {return w.toUpperCase();});
} }
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897119.32</string> </value> <value> <string>ts60604373.45</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>6499</int> </value> <value> <int>8578</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897118.97</string> </value> <value> <string>ts60604373.5</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897121.01</string> </value> <value> <string>ts60604373.56</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21898625.13</string> </value> <value> <string>ts60604373.61</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
......
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
// Depends on htmlhint.js from http://htmlhint.com/js/htmlhint.js
// declare global: HTMLHint
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("htmlhint"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "htmlhint"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
var defaultRules = {
"tagname-lowercase": true,
"attr-lowercase": true,
"attr-value-double-quotes": true,
"doctype-first": false,
"tag-pair": true,
"spec-char-escape": true,
"id-unique": true,
"src-not-empty": true,
"attr-no-duplication": true
};
CodeMirror.registerHelper("lint", "html", function(text, options) {
var found = [];
if (!window.HTMLHint) return found;
var messages = HTMLHint.verify(text, options && options.rules || defaultRules);
for (var i = 0; i < messages.length; i++) {
var message = messages[i];
var startLine = message.line - 1, endLine = message.line - 1, startCol = message.col - 1, endCol = message.col;
found.push({
from: CodeMirror.Pos(startLine, startCol),
to: CodeMirror.Pos(endLine, endCol),
message: message.message,
severity : message.type
});
}
return found;
});
});
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Cacheable__manager_id</string> </key>
<value> <string>http_cache</string> </value>
</item>
<item>
<key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts60604373.67</string> </value>
</item>
<item>
<key> <string>__name__</string> </key>
<value> <string>html-lint.js</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>application/javascript</string> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>size</string> </key>
<value> <int>1513</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
function validator(text, options) { function validator(text, options) {
if (!window.JSHINT) return []; if (!window.JSHINT) return [];
JSHINT(text, options); JSHINT(text, options, options.globals);
var errors = JSHINT.data().errors, result = []; var errors = JSHINT.data().errors, result = [];
if (errors) parseErrors(errors, result); if (errors) parseErrors(errors, result);
return result; return result;
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897120.51</string> </value> <value> <string>ts60604373.73</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>4452</int> </value> <value> <int>4469</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897120.37</string> </value> <value> <string>ts60604373.79</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
......
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
} }
var poll = setInterval(function() { var poll = setInterval(function() {
if (tooltip) for (var n = node;; n = n.parentNode) { if (tooltip) for (var n = node;; n = n.parentNode) {
if (n && n.nodeType == 11) n = n.host;
if (n == document.body) return; if (n == document.body) return;
if (!n) { hide(); break; } if (!n) { hide(); break; }
} }
...@@ -60,13 +61,12 @@ ...@@ -60,13 +61,12 @@
this.timeout = null; this.timeout = null;
this.hasGutter = hasGutter; this.hasGutter = hasGutter;
this.onMouseOver = function(e) { onMouseOver(cm, e); }; this.onMouseOver = function(e) { onMouseOver(cm, e); };
this.waitingFor = 0
} }
function parseOptions(cm, options) { function parseOptions(_cm, options) {
if (options instanceof Function) return {getAnnotations: options}; if (options instanceof Function) return {getAnnotations: options};
if (!options || options === true) options = {}; if (!options || options === true) options = {};
if (!options.getAnnotations) options.getAnnotations = cm.getHelper(CodeMirror.Pos(0, 0), "lint");
if (!options.getAnnotations) throw new Error("Required option 'getAnnotations' missing (lint addon)");
return options; return options;
} }
...@@ -116,13 +116,32 @@ ...@@ -116,13 +116,32 @@
return tip; return tip;
} }
function lintAsync(cm, getAnnotations, passOptions) {
var state = cm.state.lint
var id = ++state.waitingFor
function abort() {
id = -1
cm.off("change", abort)
}
cm.on("change", abort)
getAnnotations(cm.getValue(), function(annotations, arg2) {
cm.off("change", abort)
if (state.waitingFor != id) return
if (arg2 && annotations instanceof CodeMirror) annotations = arg2
updateLinting(cm, annotations)
}, passOptions, cm);
}
function startLinting(cm) { function startLinting(cm) {
var state = cm.state.lint, options = state.options; var state = cm.state.lint, options = state.options;
var passOptions = options.options || options; // Support deprecated passing of `options` property in options var passOptions = options.options || options; // Support deprecated passing of `options` property in options
if (options.async) var getAnnotations = options.getAnnotations || cm.getHelper(CodeMirror.Pos(0, 0), "lint");
options.getAnnotations(cm.getValue(), updateLinting, passOptions, cm); if (!getAnnotations) return;
else if (options.async || getAnnotations.async) {
updateLinting(cm, options.getAnnotations(cm.getValue(), passOptions, cm)); lintAsync(cm, getAnnotations, passOptions)
} else {
updateLinting(cm, getAnnotations(cm.getValue(), passOptions, cm));
}
} }
function updateLinting(cm, annotationsNotSorted) { function updateLinting(cm, annotationsNotSorted) {
...@@ -162,13 +181,19 @@ ...@@ -162,13 +181,19 @@
function onChange(cm) { function onChange(cm) {
var state = cm.state.lint; var state = cm.state.lint;
if (!state) return;
clearTimeout(state.timeout); clearTimeout(state.timeout);
state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay || 500); state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay || 500);
} }
function popupSpanTooltip(ann, e) { function popupTooltips(annotations, e) {
var target = e.target || e.srcElement; var target = e.target || e.srcElement;
showTooltipFor(e, annotationTooltip(ann), target); var tooltip = document.createDocumentFragment();
for (var i = 0; i < annotations.length; i++) {
var ann = annotations[i];
tooltip.appendChild(annotationTooltip(ann));
}
showTooltipFor(e, tooltip, target);
} }
function onMouseOver(cm, e) { function onMouseOver(cm, e) {
...@@ -176,17 +201,21 @@ ...@@ -176,17 +201,21 @@
if (!/\bCodeMirror-lint-mark-/.test(target.className)) return; if (!/\bCodeMirror-lint-mark-/.test(target.className)) return;
var box = target.getBoundingClientRect(), x = (box.left + box.right) / 2, y = (box.top + box.bottom) / 2; var box = target.getBoundingClientRect(), x = (box.left + box.right) / 2, y = (box.top + box.bottom) / 2;
var spans = cm.findMarksAt(cm.coordsChar({left: x, top: y}, "client")); var spans = cm.findMarksAt(cm.coordsChar({left: x, top: y}, "client"));
var annotations = [];
for (var i = 0; i < spans.length; ++i) { for (var i = 0; i < spans.length; ++i) {
var ann = spans[i].__annotation; annotations.push(spans[i].__annotation);
if (ann) return popupSpanTooltip(ann, e);
} }
if (annotations.length) popupTooltips(annotations, e);
} }
CodeMirror.defineOption("lint", false, function(cm, val, old) { CodeMirror.defineOption("lint", false, function(cm, val, old) {
if (old && old != CodeMirror.Init) { if (old && old != CodeMirror.Init) {
clearMarks(cm); clearMarks(cm);
if (cm.state.lint.options.lintOnChange !== false)
cm.off("change", onChange); cm.off("change", onChange);
CodeMirror.off(cm.getWrapperElement(), "mouseover", cm.state.lint.onMouseOver); CodeMirror.off(cm.getWrapperElement(), "mouseover", cm.state.lint.onMouseOver);
clearTimeout(cm.state.lint.timeout);
delete cm.state.lint; delete cm.state.lint;
} }
...@@ -194,6 +223,7 @@ ...@@ -194,6 +223,7 @@
var gutters = cm.getOption("gutters"), hasLintGutter = false; var gutters = cm.getOption("gutters"), hasLintGutter = false;
for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true; for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true;
var state = cm.state.lint = new LintState(cm, parseOptions(cm, val), hasLintGutter); var state = cm.state.lint = new LintState(cm, parseOptions(cm, val), hasLintGutter);
if (state.options.lintOnChange !== false)
cm.on("change", onChange); cm.on("change", onChange);
if (state.options.tooltips != false) if (state.options.tooltips != false)
CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver); CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver);
...@@ -201,4 +231,8 @@ ...@@ -201,4 +231,8 @@
startLinting(cm); startLinting(cm);
} }
}); });
CodeMirror.defineExtension("performLint", function() {
if (this.state.lint) startLinting(this);
});
}); });
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21898385.1</string> </value> <value> <string>ts60604373.9</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>7036</int> </value> <value> <int>8032</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897120.75</string> </value> <value> <string>ts60604373.96</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
......
...@@ -60,6 +60,7 @@ ...@@ -60,6 +60,7 @@
position: absolute; position: absolute;
cursor: pointer; cursor: pointer;
color: #44c; color: #44c;
z-index: 3;
} }
.CodeMirror-merge-copy-reverse { .CodeMirror-merge-copy-reverse {
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897120.12</string> </value> <value> <string>ts60604374.07</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>24684</int> </value> <value> <int>28660</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897115.91</string> </value> <value> <string>ts60604374.14</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
......
...@@ -14,12 +14,14 @@ ...@@ -14,12 +14,14 @@
CodeMirror.multiplexingMode = function(outer /*, others */) { CodeMirror.multiplexingMode = function(outer /*, others */) {
// Others should be {open, close, mode [, delimStyle] [, innerStyle]} objects // Others should be {open, close, mode [, delimStyle] [, innerStyle]} objects
var others = Array.prototype.slice.call(arguments, 1); var others = Array.prototype.slice.call(arguments, 1);
var n_others = others.length;
function indexOf(string, pattern, from) { function indexOf(string, pattern, from, returnEnd) {
if (typeof pattern == "string") return string.indexOf(pattern, from); if (typeof pattern == "string") {
var found = string.indexOf(pattern, from);
return returnEnd && found > -1 ? found + pattern.length : found;
}
var m = pattern.exec(from ? string.slice(from) : string); var m = pattern.exec(from ? string.slice(from) : string);
return m ? m.index + from : -1; return m ? m.index + from + (returnEnd ? m[0].length : 0) : -1;
} }
return { return {
...@@ -42,14 +44,14 @@ CodeMirror.multiplexingMode = function(outer /*, others */) { ...@@ -42,14 +44,14 @@ CodeMirror.multiplexingMode = function(outer /*, others */) {
token: function(stream, state) { token: function(stream, state) {
if (!state.innerActive) { if (!state.innerActive) {
var cutOff = Infinity, oldContent = stream.string; var cutOff = Infinity, oldContent = stream.string;
for (var i = 0; i < n_others; ++i) { for (var i = 0; i < others.length; ++i) {
var other = others[i]; var other = others[i];
var found = indexOf(oldContent, other.open, stream.pos); var found = indexOf(oldContent, other.open, stream.pos);
if (found == stream.pos) { if (found == stream.pos) {
stream.match(other.open); if (!other.parseDelimiters) stream.match(other.open);
state.innerActive = other; state.innerActive = other;
state.inner = CodeMirror.startState(other.mode, outer.indent ? outer.indent(state.outer, "") : 0); state.inner = CodeMirror.startState(other.mode, outer.indent ? outer.indent(state.outer, "") : 0);
return other.delimStyle; return other.delimStyle && (other.delimStyle + " " + other.delimStyle + "-open");
} else if (found != -1 && found < cutOff) { } else if (found != -1 && found < cutOff) {
cutOff = found; cutOff = found;
} }
...@@ -64,18 +66,21 @@ CodeMirror.multiplexingMode = function(outer /*, others */) { ...@@ -64,18 +66,21 @@ CodeMirror.multiplexingMode = function(outer /*, others */) {
state.innerActive = state.inner = null; state.innerActive = state.inner = null;
return this.token(stream, state); return this.token(stream, state);
} }
var found = curInner.close ? indexOf(oldContent, curInner.close, stream.pos) : -1; var found = curInner.close ? indexOf(oldContent, curInner.close, stream.pos, curInner.parseDelimiters) : -1;
if (found == stream.pos) { if (found == stream.pos && !curInner.parseDelimiters) {
stream.match(curInner.close); stream.match(curInner.close);
state.innerActive = state.inner = null; state.innerActive = state.inner = null;
return curInner.delimStyle; return curInner.delimStyle && (curInner.delimStyle + " " + curInner.delimStyle + "-close");
} }
if (found > -1) stream.string = oldContent.slice(0, found); if (found > -1) stream.string = oldContent.slice(0, found);
var innerToken = curInner.mode.token(stream, state.inner); var innerToken = curInner.mode.token(stream, state.inner);
if (found > -1) stream.string = oldContent; if (found > -1) stream.string = oldContent;
if (found == stream.pos && curInner.parseDelimiters)
state.innerActive = state.inner = null;
if (curInner.innerStyle) { if (curInner.innerStyle) {
if (innerToken) innerToken = innerToken + ' ' + curInner.innerStyle; if (innerToken) innerToken = innerToken + " " + curInner.innerStyle;
else innerToken = curInner.innerStyle; else innerToken = curInner.innerStyle;
} }
...@@ -95,7 +100,7 @@ CodeMirror.multiplexingMode = function(outer /*, others */) { ...@@ -95,7 +100,7 @@ CodeMirror.multiplexingMode = function(outer /*, others */) {
mode.blankLine(state.innerActive ? state.inner : state.outer); mode.blankLine(state.innerActive ? state.inner : state.outer);
} }
if (!state.innerActive) { if (!state.innerActive) {
for (var i = 0; i < n_others; ++i) { for (var i = 0; i < others.length; ++i) {
var other = others[i]; var other = others[i];
if (other.open === "\n") { if (other.open === "\n") {
state.innerActive = other; state.innerActive = other;
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897116.0</string> </value> <value> <string>ts60604374.15</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>4197</int> </value> <value> <int>4624</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -29,5 +29,5 @@ ...@@ -29,5 +29,5 @@
MT( MT(
"stexInsideMarkdown", "stexInsideMarkdown",
"[strong **Equation:**] [delim $][inner&tag \\pi][delim $]"); "[strong **Equation:**] [delim&delim-open $][inner&tag \\pi][delim&delim-close $]");
})(); })();
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897115.81</string> </value> <value> <string>ts60604374.17</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>810</int> </value> <value> <int>833</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897115.72</string> </value> <value> <string>ts60604374.22</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
......
...@@ -60,7 +60,7 @@ ...@@ -60,7 +60,7 @@
function ensureState(states, name) { function ensureState(states, name) {
if (!states.hasOwnProperty(name)) if (!states.hasOwnProperty(name))
throw new Error("Undefined state " + name + "in simple mode"); throw new Error("Undefined state " + name + " in simple mode");
} }
function toRegex(val, caret) { function toRegex(val, caret) {
...@@ -116,7 +116,7 @@ ...@@ -116,7 +116,7 @@
var curState = states[state.state]; var curState = states[state.state];
for (var i = 0; i < curState.length; i++) { for (var i = 0; i < curState.length; i++) {
var rule = curState[i]; var rule = curState[i];
var matches = stream.match(rule.regex); var matches = (!rule.data.sol || stream.sol()) && stream.match(rule.regex);
if (matches) { if (matches) {
if (rule.data.next) { if (rule.data.next) {
state.state = rule.data.next; state.state = rule.data.next;
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897115.63</string> </value> <value> <string>ts60604374.24</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>7862</int> </value> <value> <int>7899</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897122.18</string> </value> <value> <string>ts60604374.3</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897122.07</string> </value> <value> <string>ts60604374.36</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
......
...@@ -16,7 +16,7 @@ CodeMirror.runMode = function(string, modespec, callback, options) { ...@@ -16,7 +16,7 @@ CodeMirror.runMode = function(string, modespec, callback, options) {
var ie = /MSIE \d/.test(navigator.userAgent); var ie = /MSIE \d/.test(navigator.userAgent);
var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9); var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9);
if (callback.nodeType == 1) { if (callback.appendChild) {
var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize; var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize;
var node = callback, col = 0; var node = callback, col = 0;
node.innerHTML = ""; node.innerHTML = "";
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897121.98</string> </value> <value> <string>ts60604374.42</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>2501</int> </value> <value> <int>2499</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -3,19 +3,37 @@ ...@@ -3,19 +3,37 @@
/* Just enough of CodeMirror to run runMode under node.js */ /* Just enough of CodeMirror to run runMode under node.js */
// declare global: StringStream function splitLines(string){return string.split(/\r\n?|\n/);};
function splitLines(string){ return string.split(/\r?\n|\r/); }; // Counts the column offset in a string, taking tabs into account.
// Used mostly to find indentation.
var countColumn = function(string, end, tabSize, startIndex, startValue) {
if (end == null) {
end = string.search(/[^\s\u00a0]/);
if (end == -1) end = string.length;
}
for (var i = startIndex || 0, n = startValue || 0;;) {
var nextTab = string.indexOf("\t", i);
if (nextTab < 0 || nextTab >= end)
return n + (end - i);
n += nextTab - i;
n += tabSize - (n % tabSize);
i = nextTab + 1;
}
};
function StringStream(string) { function StringStream(string, tabSize) {
this.pos = this.start = 0; this.pos = this.start = 0;
this.string = string; this.string = string;
this.tabSize = tabSize || 8;
this.lastColumnPos = this.lastColumnValue = 0;
this.lineStart = 0; this.lineStart = 0;
} };
StringStream.prototype = { StringStream.prototype = {
eol: function() {return this.pos >= this.string.length;}, eol: function() {return this.pos >= this.string.length;},
sol: function() {return this.pos == 0;}, sol: function() {return this.pos == this.lineStart;},
peek: function() {return this.string.charAt(this.pos) || null;}, peek: function() {return this.string.charAt(this.pos) || undefined;},
next: function() { next: function() {
if (this.pos < this.string.length) if (this.pos < this.string.length)
return this.string.charAt(this.pos++); return this.string.charAt(this.pos++);
...@@ -42,8 +60,17 @@ StringStream.prototype = { ...@@ -42,8 +60,17 @@ StringStream.prototype = {
if (found > -1) {this.pos = found; return true;} if (found > -1) {this.pos = found; return true;}
}, },
backUp: function(n) {this.pos -= n;}, backUp: function(n) {this.pos -= n;},
column: function() {return this.start - this.lineStart;}, column: function() {
indentation: function() {return 0;}, if (this.lastColumnPos < this.start) {
this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
this.lastColumnPos = this.start;
}
return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
},
indentation: function() {
return countColumn(this.string, null, this.tabSize) -
(this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
},
match: function(pattern, consume, caseInsensitive) { match: function(pattern, consume, caseInsensitive) {
if (typeof pattern == "string") { if (typeof pattern == "string") {
var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;}; var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};
...@@ -94,11 +121,42 @@ exports.resolveMode = function(spec) { ...@@ -94,11 +121,42 @@ exports.resolveMode = function(spec) {
if (typeof spec == "string") return {name: spec}; if (typeof spec == "string") return {name: spec};
else return spec || {name: "null"}; else return spec || {name: "null"};
}; };
function copyObj(obj, target, overwrite) {
if (!target) target = {};
for (var prop in obj)
if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
target[prop] = obj[prop];
return target;
}
// This can be used to attach properties to mode objects from
// outside the actual mode definition.
var modeExtensions = exports.modeExtensions = {};
exports.extendMode = function(mode, properties) {
var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
copyObj(properties, exts);
};
exports.getMode = function(options, spec) { exports.getMode = function(options, spec) {
spec = exports.resolveMode(spec); var spec = exports.resolveMode(spec);
var mfactory = modes[spec.name]; var mfactory = modes[spec.name];
if (!mfactory) throw new Error("Unknown mode: " + spec); if (!mfactory) return exports.getMode(options, "text/plain");
return mfactory(options, spec); var modeObj = mfactory(options, spec);
if (modeExtensions.hasOwnProperty(spec.name)) {
var exts = modeExtensions[spec.name];
for (var prop in exts) {
if (!exts.hasOwnProperty(prop)) continue;
if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop];
modeObj[prop] = exts[prop];
}
}
modeObj.name = spec.name;
if (spec.helperType) modeObj.helperType = spec.helperType;
if (spec.modeProps) for (var prop in spec.modeProps)
modeObj[prop] = spec.modeProps[prop];
return modeObj;
}; };
exports.registerHelper = exports.registerGlobalHelper = Math.min; exports.registerHelper = exports.registerGlobalHelper = Math.min;
...@@ -118,3 +176,4 @@ exports.runMode = function(string, modespec, callback, options) { ...@@ -118,3 +176,4 @@ exports.runMode = function(string, modespec, callback, options) {
}; };
require.cache[require.resolve("../../lib/codemirror")] = require.cache[require.resolve("./runmode.node")]; require.cache[require.resolve("../../lib/codemirror")] = require.cache[require.resolve("./runmode.node")];
require.cache[require.resolve("../../addon/runmode/runmode")] = require.cache[require.resolve("./runmode.node")];
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897122.25</string> </value> <value> <string>ts60604374.47</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>4289</int> </value> <value> <int>6528</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -11,28 +11,47 @@ ...@@ -11,28 +11,47 @@
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
CodeMirror.defineExtension("annotateScrollbar", function(className) { CodeMirror.defineExtension("annotateScrollbar", function(options) {
return new Annotation(this, className); if (typeof options == "string") options = {className: options};
return new Annotation(this, options);
}); });
function Annotation(cm, className) { CodeMirror.defineOption("scrollButtonHeight", 0);
function Annotation(cm, options) {
this.cm = cm; this.cm = cm;
this.className = className; this.options = options;
this.buttonHeight = options.scrollButtonHeight || cm.getOption("scrollButtonHeight");
this.annotations = []; this.annotations = [];
this.doRedraw = this.doUpdate = null;
this.div = cm.getWrapperElement().appendChild(document.createElement("div")); this.div = cm.getWrapperElement().appendChild(document.createElement("div"));
this.div.style.cssText = "position: absolute; right: 0; top: 0; z-index: 7; pointer-events: none"; this.div.style.cssText = "position: absolute; right: 0; top: 0; z-index: 7; pointer-events: none";
this.computeScale(); this.computeScale();
function scheduleRedraw(delay) {
clearTimeout(self.doRedraw);
self.doRedraw = setTimeout(function() { self.redraw(); }, delay);
}
var self = this; var self = this;
cm.on("refresh", this.resizeHandler = function(){ cm.on("refresh", this.resizeHandler = function() {
if (self.computeScale()) self.redraw(); clearTimeout(self.doUpdate);
self.doUpdate = setTimeout(function() {
if (self.computeScale()) scheduleRedraw(20);
}, 100);
});
cm.on("markerAdded", this.resizeHandler);
cm.on("markerCleared", this.resizeHandler);
if (options.listenForChanges !== false)
cm.on("change", this.changeHandler = function() {
scheduleRedraw(250);
}); });
} }
Annotation.prototype.computeScale = function() { Annotation.prototype.computeScale = function() {
var cm = this.cm; var cm = this.cm;
var hScale = (cm.getWrapperElement().clientHeight - cm.display.barHeight) / var hScale = (cm.getWrapperElement().clientHeight - cm.display.barHeight - this.buttonHeight * 2) /
cm.heightAtLine(cm.lastLine() + 1, "local"); cm.getScrollerElement().scrollHeight
if (hScale != this.hScale) { if (hScale != this.hScale) {
this.hScale = hScale; this.hScale = hScale;
return true; return true;
...@@ -44,26 +63,46 @@ ...@@ -44,26 +63,46 @@
this.redraw(); this.redraw();
}; };
Annotation.prototype.redraw = function() { Annotation.prototype.redraw = function(compute) {
if (compute !== false) this.computeScale();
var cm = this.cm, hScale = this.hScale; var cm = this.cm, hScale = this.hScale;
if (!cm.display.barWidth) return;
var frag = document.createDocumentFragment(), anns = this.annotations; var frag = document.createDocumentFragment(), anns = this.annotations;
for (var i = 0, nextTop; i < anns.length; i++) {
var wrapping = cm.getOption("lineWrapping");
var singleLineH = wrapping && cm.defaultTextHeight() * 1.5;
var curLine = null, curLineObj = null;
function getY(pos, top) {
if (curLine != pos.line) {
curLine = pos.line;
curLineObj = cm.getLineHandle(curLine);
}
if (wrapping && curLineObj.height > singleLineH)
return cm.charCoords(pos, "local")[top ? "top" : "bottom"];
var topY = cm.heightAtLine(curLineObj, "local");
return topY + (top ? 0 : curLineObj.height);
}
if (cm.display.barWidth) for (var i = 0, nextTop; i < anns.length; i++) {
var ann = anns[i]; var ann = anns[i];
var top = nextTop || cm.charCoords(ann.from, "local").top * hScale; var top = nextTop || getY(ann.from, true) * hScale;
var bottom = cm.charCoords(ann.to, "local").bottom * hScale; var bottom = getY(ann.to, false) * hScale;
while (i < anns.length - 1) { while (i < anns.length - 1) {
nextTop = cm.charCoords(anns[i + 1].from, "local").top * hScale; nextTop = getY(anns[i + 1].from, true) * hScale;
if (nextTop > bottom + .9) break; if (nextTop > bottom + .9) break;
ann = anns[++i]; ann = anns[++i];
bottom = cm.charCoords(ann.to, "local").bottom * hScale; bottom = getY(ann.to, false) * hScale;
} }
if (bottom == top) continue;
var height = Math.max(bottom - top, 3); var height = Math.max(bottom - top, 3);
var elt = frag.appendChild(document.createElement("div")); var elt = frag.appendChild(document.createElement("div"));
elt.style.cssText = "position: absolute; right: 0px; width: " + Math.max(cm.display.barWidth - 1, 2) + "px; top: " + top + "px; height: " + height + "px"; elt.style.cssText = "position: absolute; right: 0px; width: " + Math.max(cm.display.barWidth - 1, 2) + "px; top: "
elt.className = this.className; + (top + this.buttonHeight) + "px; height: " + height + "px";
elt.className = this.options.className;
if (ann.id) {
elt.setAttribute("annotation-id", ann.id);
}
} }
this.div.textContent = ""; this.div.textContent = "";
this.div.appendChild(frag); this.div.appendChild(frag);
...@@ -71,6 +110,9 @@ ...@@ -71,6 +110,9 @@
Annotation.prototype.clear = function() { Annotation.prototype.clear = function() {
this.cm.off("refresh", this.resizeHandler); this.cm.off("refresh", this.resizeHandler);
this.cm.off("markerAdded", this.resizeHandler);
this.cm.off("markerCleared", this.resizeHandler);
if (this.changeHandler) this.cm.off("change", this.changeHandler);
this.div.parentNode.removeChild(this.div); this.div.parentNode.removeChild(this.div);
}; };
}); });
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897118.59</string> </value> <value> <string>ts60604374.52</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>2660</int> </value> <value> <int>4250</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897118.22</string> </value> <value> <string>ts60604374.58</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
......
...@@ -27,14 +27,16 @@ ...@@ -27,14 +27,16 @@
CodeMirror.e_preventDefault(e); CodeMirror.e_preventDefault(e);
var axis = self.orientation == "horizontal" ? "pageX" : "pageY"; var axis = self.orientation == "horizontal" ? "pageX" : "pageY";
var start = e[axis], startpos = self.pos; var start = e[axis], startpos = self.pos;
function move(e) { function done() {
if (e.which != 1) {
CodeMirror.off(document, "mousemove", move); CodeMirror.off(document, "mousemove", move);
return; CodeMirror.off(document, "mouseup", done);
} }
function move(e) {
if (e.which != 1) return done();
self.moveTo(startpos + (e[axis] - start) * (self.total / self.size)); self.moveTo(startpos + (e[axis] - start) * (self.total / self.size));
} }
CodeMirror.on(document, "mousemove", move); CodeMirror.on(document, "mousemove", move);
CodeMirror.on(document, "mouseup", done);
}); });
CodeMirror.on(this.node, "click", function(e) { CodeMirror.on(this.node, "click", function(e) {
...@@ -57,26 +59,35 @@ ...@@ -57,26 +59,35 @@
CodeMirror.on(this.node, "DOMMouseScroll", onWheel); CodeMirror.on(this.node, "DOMMouseScroll", onWheel);
} }
Bar.prototype.moveTo = function(pos, update) { Bar.prototype.setPos = function(pos) {
if (pos < 0) pos = 0; if (pos < 0) pos = 0;
if (pos > this.total - this.screen) pos = this.total - this.screen; if (pos > this.total - this.screen) pos = this.total - this.screen;
if (pos == this.pos) return; if (pos == this.pos) return false;
this.pos = pos; this.pos = pos;
this.inner.style[this.orientation == "horizontal" ? "left" : "top"] = this.inner.style[this.orientation == "horizontal" ? "left" : "top"] =
(pos * (this.size / this.total)) + "px"; (pos * (this.size / this.total)) + "px";
if (update !== false) this.scroll(pos, this.orientation); return true
}; };
Bar.prototype.moveTo = function(pos) {
if (this.setPos(pos)) this.scroll(pos, this.orientation);
}
var minButtonSize = 10;
Bar.prototype.update = function(scrollSize, clientSize, barSize) { Bar.prototype.update = function(scrollSize, clientSize, barSize) {
this.screen = clientSize; this.screen = clientSize;
this.total = scrollSize; this.total = scrollSize;
this.size = barSize; this.size = barSize;
// FIXME clip to min size? var buttonSize = this.screen * (this.size / this.total);
if (buttonSize < minButtonSize) {
this.size -= minButtonSize - buttonSize;
buttonSize = minButtonSize;
}
this.inner.style[this.orientation == "horizontal" ? "width" : "height"] = this.inner.style[this.orientation == "horizontal" ? "width" : "height"] =
this.screen * (this.size / this.total) + "px"; buttonSize + "px";
this.inner.style[this.orientation == "horizontal" ? "left" : "top"] = this.setPos(this.pos);
this.pos * (this.size / this.total) + "px";
}; };
function SimpleScrollbars(cls, place, scroll) { function SimpleScrollbars(cls, place, scroll) {
...@@ -103,7 +114,6 @@ ...@@ -103,7 +114,6 @@
if (needsV) { if (needsV) {
this.vert.update(measure.scrollHeight, measure.clientHeight, this.vert.update(measure.scrollHeight, measure.clientHeight,
measure.viewHeight - (needsH ? width : 0)); measure.viewHeight - (needsH ? width : 0));
this.vert.node.style.display = "block";
this.vert.node.style.bottom = needsH ? width + "px" : "0"; this.vert.node.style.bottom = needsH ? width + "px" : "0";
} }
if (needsH) { if (needsH) {
...@@ -117,11 +127,11 @@ ...@@ -117,11 +127,11 @@
}; };
SimpleScrollbars.prototype.setScrollTop = function(pos) { SimpleScrollbars.prototype.setScrollTop = function(pos) {
this.vert.moveTo(pos, false); this.vert.setPos(pos);
}; };
SimpleScrollbars.prototype.setScrollLeft = function(pos) { SimpleScrollbars.prototype.setScrollLeft = function(pos) {
this.horiz.moveTo(pos, false); this.horiz.setPos(pos);
}; };
SimpleScrollbars.prototype.clear = function() { SimpleScrollbars.prototype.clear = function() {
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897118.5</string> </value> <value> <string>ts60604374.69</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>5126</int> </value> <value> <int>5297</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
// Defines jumpToLine command. Uses dialog.js if present.
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("../dialog/dialog"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "../dialog/dialog"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
function dialog(cm, text, shortText, deflt, f) {
if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true});
else f(prompt(shortText, deflt));
}
var jumpDialog =
'Jump to line: <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use line:column or scroll% syntax)</span>';
function interpretLine(cm, string) {
var num = Number(string)
if (/^[-+]/.test(string)) return cm.getCursor().line + num
else return num - 1
}
CodeMirror.commands.jumpToLine = function(cm) {
var cur = cm.getCursor();
dialog(cm, jumpDialog, "Jump to line:", (cur.line + 1) + ":" + cur.ch, function(posStr) {
if (!posStr) return;
var match;
if (match = /^\s*([\+\-]?\d+)\s*\:\s*(\d+)\s*$/.exec(posStr)) {
cm.setCursor(interpretLine(cm, match[1]), Number(match[2]))
} else if (match = /^\s*([\+\-]?\d+(\.\d+)?)\%\s*/.exec(posStr)) {
var line = Math.round(cm.lineCount() * Number(match[1]) / 100);
if (/^[-+]/.test(match[1])) line = cur.line + line + 1;
cm.setCursor(line - 1, cur.ch);
} else if (match = /^\s*\:?\s*([\+\-]?\d+)\s*/.exec(posStr)) {
cm.setCursor(interpretLine(cm, match[1]), cur.ch);
}
});
};
CodeMirror.keyMap["default"]["Alt-G"] = "jumpToLine";
});
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Cacheable__manager_id</string> </key>
<value> <string>http_cache</string> </value>
</item>
<item>
<key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts60604374.75</string> </value>
</item>
<item>
<key> <string>__name__</string> </key>
<value> <string>jump-to-line.js</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>application/javascript</string> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>size</string> </key>
<value> <int>1940</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -16,13 +16,14 @@ ...@@ -16,13 +16,14 @@
// highlighted only if the selected text is a word. showToken, when enabled, // highlighted only if the selected text is a word. showToken, when enabled,
// will cause the current token to be highlighted when nothing is selected. // will cause the current token to be highlighted when nothing is selected.
// delay is used to specify how much time to wait, in milliseconds, before // delay is used to specify how much time to wait, in milliseconds, before
// highlighting the matches. // highlighting the matches. If annotateScrollbar is enabled, the occurances
// will be highlighted on the scrollbar via the matchesonscrollbar addon.
(function(mod) { (function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror")); mod(require("../../lib/codemirror"), require("./matchesonscrollbar"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror", "./matchesonscrollbar"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
...@@ -40,18 +41,19 @@ ...@@ -40,18 +41,19 @@
this.showToken = options.showToken; this.showToken = options.showToken;
this.delay = options.delay; this.delay = options.delay;
this.wordsOnly = options.wordsOnly; this.wordsOnly = options.wordsOnly;
this.annotateScrollbar = options.annotateScrollbar;
} }
if (this.style == null) this.style = DEFAULT_TOKEN_STYLE; if (this.style == null) this.style = DEFAULT_TOKEN_STYLE;
if (this.minChars == null) this.minChars = DEFAULT_MIN_CHARS; if (this.minChars == null) this.minChars = DEFAULT_MIN_CHARS;
if (this.delay == null) this.delay = DEFAULT_DELAY; if (this.delay == null) this.delay = DEFAULT_DELAY;
if (this.wordsOnly == null) this.wordsOnly = DEFAULT_WORDS_ONLY; if (this.wordsOnly == null) this.wordsOnly = DEFAULT_WORDS_ONLY;
this.overlay = this.timeout = null; this.overlay = this.timeout = null;
this.matchesonscroll = null;
} }
CodeMirror.defineOption("highlightSelectionMatches", false, function(cm, val, old) { CodeMirror.defineOption("highlightSelectionMatches", false, function(cm, val, old) {
if (old && old != CodeMirror.Init) { if (old && old != CodeMirror.Init) {
var over = cm.state.matchHighlighter.overlay; removeOverlay(cm);
if (over) cm.removeOverlay(over);
clearTimeout(cm.state.matchHighlighter.timeout); clearTimeout(cm.state.matchHighlighter.timeout);
cm.state.matchHighlighter = null; cm.state.matchHighlighter = null;
cm.off("cursorActivity", cursorActivity); cm.off("cursorActivity", cursorActivity);
...@@ -69,20 +71,39 @@ ...@@ -69,20 +71,39 @@
state.timeout = setTimeout(function() {highlightMatches(cm);}, state.delay); state.timeout = setTimeout(function() {highlightMatches(cm);}, state.delay);
} }
function highlightMatches(cm) { function addOverlay(cm, query, hasBoundary, style) {
cm.operation(function() { var state = cm.state.matchHighlighter;
cm.addOverlay(state.overlay = makeOverlay(query, hasBoundary, style));
if (state.annotateScrollbar) {
var searchFor = hasBoundary ? new RegExp("\\b" + query + "\\b") : query;
state.matchesonscroll = cm.showMatchesOnScrollbar(searchFor, true,
{className: "CodeMirror-selection-highlight-scrollbar"});
}
}
function removeOverlay(cm) {
var state = cm.state.matchHighlighter; var state = cm.state.matchHighlighter;
if (state.overlay) { if (state.overlay) {
cm.removeOverlay(state.overlay); cm.removeOverlay(state.overlay);
state.overlay = null; state.overlay = null;
if (state.annotateScrollbar) {
state.matchesonscroll.clear();
state.matchesonscroll = null;
} }
}
}
function highlightMatches(cm) {
cm.operation(function() {
var state = cm.state.matchHighlighter;
removeOverlay(cm);
if (!cm.somethingSelected() && state.showToken) { if (!cm.somethingSelected() && state.showToken) {
var re = state.showToken === true ? /[\w$]/ : state.showToken; var re = state.showToken === true ? /[\w$]/ : state.showToken;
var cur = cm.getCursor(), line = cm.getLine(cur.line), start = cur.ch, end = start; var cur = cm.getCursor(), line = cm.getLine(cur.line), start = cur.ch, end = start;
while (start && re.test(line.charAt(start - 1))) --start; while (start && re.test(line.charAt(start - 1))) --start;
while (end < line.length && re.test(line.charAt(end))) ++end; while (end < line.length && re.test(line.charAt(end))) ++end;
if (start < end) if (start < end)
cm.addOverlay(state.overlay = makeOverlay(line.slice(start, end), re, state.style)); addOverlay(cm, line.slice(start, end), re, state.style);
return; return;
} }
var from = cm.getCursor("from"), to = cm.getCursor("to"); var from = cm.getCursor("from"), to = cm.getCursor("to");
...@@ -90,7 +111,7 @@ ...@@ -90,7 +111,7 @@
if (state.wordsOnly && !isWord(cm, from, to)) return; if (state.wordsOnly && !isWord(cm, from, to)) return;
var selection = cm.getRange(from, to).replace(/^\s+|\s+$/g, ""); var selection = cm.getRange(from, to).replace(/^\s+|\s+$/g, "");
if (selection.length >= state.minChars) if (selection.length >= state.minChars)
cm.addOverlay(state.overlay = makeOverlay(selection, false, state.style)); addOverlay(cm, selection, false, state.style);
}); });
} }
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897121.25</string> </value> <value> <string>ts60604374.81</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>4943</int> </value> <value> <int>5745</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -11,13 +11,19 @@ ...@@ -11,13 +11,19 @@
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
CodeMirror.defineExtension("showMatchesOnScrollbar", function(query, caseFold, className) { CodeMirror.defineExtension("showMatchesOnScrollbar", function(query, caseFold, options) {
return new SearchAnnotation(this, query, caseFold, className); if (typeof options == "string") options = {className: options};
if (!options) options = {};
return new SearchAnnotation(this, query, caseFold, options);
}); });
function SearchAnnotation(cm, query, caseFold, className) { function SearchAnnotation(cm, query, caseFold, options) {
this.cm = cm; this.cm = cm;
this.annotation = cm.annotateScrollbar(className || "CodeMirror-search-match"); this.options = options;
var annotateOptions = {listenForChanges: false};
for (var prop in options) annotateOptions[prop] = options[prop];
if (!annotateOptions.className) annotateOptions.className = "CodeMirror-search-match";
this.annotation = cm.annotateScrollbar(annotateOptions);
this.query = query; this.query = query;
this.caseFold = caseFold; this.caseFold = caseFold;
this.gap = {from: cm.firstLine(), to: cm.lastLine() + 1}; this.gap = {from: cm.firstLine(), to: cm.lastLine() + 1};
...@@ -41,11 +47,12 @@ ...@@ -41,11 +47,12 @@
if (match.to.line >= this.gap.from) this.matches.splice(i--, 1); if (match.to.line >= this.gap.from) this.matches.splice(i--, 1);
} }
var cursor = this.cm.getSearchCursor(this.query, CodeMirror.Pos(this.gap.from, 0), this.caseFold); var cursor = this.cm.getSearchCursor(this.query, CodeMirror.Pos(this.gap.from, 0), this.caseFold);
var maxMatches = this.options && this.options.maxMatches || MAX_MATCHES;
while (cursor.findNext()) { while (cursor.findNext()) {
var match = {from: cursor.from(), to: cursor.to()}; var match = {from: cursor.from(), to: cursor.to()};
if (match.from.line >= this.gap.to) break; if (match.from.line >= this.gap.to) break;
this.matches.splice(i++, 0, match); this.matches.splice(i++, 0, match);
if (this.matches.length > MAX_MATCHES) break; if (this.matches.length > maxMatches) break;
} }
this.gap = null; this.gap = null;
}; };
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897121.73</string> </value> <value> <string>ts60604374.87</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>3420</int> </value> <value> <int>3808</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
function searchOverlay(query, caseInsensitive) { function searchOverlay(query, caseInsensitive) {
if (typeof query == "string") if (typeof query == "string")
query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), caseInsensitive ? "gi" : "g"); query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), caseInsensitive ? "gi" : "g");
...@@ -28,7 +29,7 @@ ...@@ -28,7 +29,7 @@
query.lastIndex = stream.pos; query.lastIndex = stream.pos;
var match = query.exec(stream.string); var match = query.exec(stream.string);
if (match && match.index == stream.pos) { if (match && match.index == stream.pos) {
stream.pos += match[0].length; stream.pos += match[0].length || 1;
return "searching"; return "searching";
} else if (match) { } else if (match) {
stream.pos = match.index; stream.pos = match.index;
...@@ -39,45 +40,68 @@ ...@@ -39,45 +40,68 @@
} }
function SearchState() { function SearchState() {
this.posFrom = this.posTo = this.query = null; this.posFrom = this.posTo = this.lastQuery = this.query = null;
this.overlay = null; this.overlay = null;
} }
function getSearchState(cm) { function getSearchState(cm) {
return cm.state.search || (cm.state.search = new SearchState()); return cm.state.search || (cm.state.search = new SearchState());
} }
function queryCaseInsensitive(query) { function queryCaseInsensitive(query) {
return typeof query == "string" && query == query.toLowerCase(); return typeof query == "string" && query == query.toLowerCase();
} }
function getSearchCursor(cm, query, pos) { function getSearchCursor(cm, query, pos) {
// Heuristic: if the query string is all lowercase, do a case insensitive search. // Heuristic: if the query string is all lowercase, do a case insensitive search.
return cm.getSearchCursor(query, pos, queryCaseInsensitive(query)); return cm.getSearchCursor(query, pos, queryCaseInsensitive(query));
} }
function persistentDialog(cm, text, deflt, f) {
cm.openDialog(text, f, {
value: deflt,
selectValueOnOpen: true,
closeOnEnter: false,
onClose: function() { clearSearch(cm); }
});
}
function dialog(cm, text, shortText, deflt, f) { function dialog(cm, text, shortText, deflt, f) {
if (cm.openDialog) cm.openDialog(text, f, {value: deflt}); if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true});
else f(prompt(shortText, deflt)); else f(prompt(shortText, deflt));
} }
function confirmDialog(cm, text, shortText, fs) { function confirmDialog(cm, text, shortText, fs) {
if (cm.openConfirm) cm.openConfirm(text, fs); if (cm.openConfirm) cm.openConfirm(text, fs);
else if (confirm(shortText)) fs[0](); else if (confirm(shortText)) fs[0]();
} }
function parseString(string) {
return string.replace(/\\(.)/g, function(_, ch) {
if (ch == "n") return "\n"
if (ch == "r") return "\r"
return ch
})
}
function parseQuery(query) { function parseQuery(query) {
var isRE = query.match(/^\/(.*)\/([a-z]*)$/); var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
if (isRE) { if (isRE) {
try { query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); } try { query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); }
catch(e) {} // Not a regular expression after all, do a string search catch(e) {} // Not a regular expression after all, do a string search
} else {
query = parseString(query)
} }
if (typeof query == "string" ? query == "" : query.test("")) if (typeof query == "string" ? query == "" : query.test(""))
query = /x^/; query = /x^/;
return query; return query;
} }
var queryDialog = var queryDialog =
'Search: <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use /re/ syntax for regexp search)</span>'; 'Search: <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use /re/ syntax for regexp search)</span>';
function doSearch(cm, rev) {
var state = getSearchState(cm); function startSearch(cm, state, query) {
if (state.query) return findNext(cm, rev); state.queryText = query;
dialog(cm, queryDialog, "Search for:", cm.getSelection(), function(query) {
cm.operation(function() {
if (!query || state.query) return;
state.query = parseQuery(query); state.query = parseQuery(query);
cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query)); cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query));
state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query)); state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query));
...@@ -86,12 +110,39 @@ ...@@ -86,12 +110,39 @@
if (state.annotate) { state.annotate.clear(); state.annotate = null; } if (state.annotate) { state.annotate.clear(); state.annotate = null; }
state.annotate = cm.showMatchesOnScrollbar(state.query, queryCaseInsensitive(state.query)); state.annotate = cm.showMatchesOnScrollbar(state.query, queryCaseInsensitive(state.query));
} }
}
function doSearch(cm, rev, persistent) {
var state = getSearchState(cm);
if (state.query) return findNext(cm, rev);
var q = cm.getSelection() || state.lastQuery;
if (persistent && cm.openDialog) {
var hiding = null
persistentDialog(cm, queryDialog, q, function(query, event) {
CodeMirror.e_stop(event);
if (!query) return;
if (query != state.queryText) startSearch(cm, state, query);
if (hiding) hiding.style.opacity = 1
findNext(cm, event.shiftKey, function(_, to) {
var dialog
if (to.line < 3 && document.querySelector &&
(dialog = cm.display.wrapper.querySelector(".CodeMirror-dialog")) &&
dialog.getBoundingClientRect().bottom - 4 > cm.cursorCoords(to, "window").top)
(hiding = dialog).style.opacity = .4
})
});
} else {
dialog(cm, queryDialog, "Search for:", q, function(query) {
if (query && !state.query) cm.operation(function() {
startSearch(cm, state, query);
state.posFrom = state.posTo = cm.getCursor(); state.posFrom = state.posTo = cm.getCursor();
findNext(cm, rev); findNext(cm, rev);
}); });
}); });
} }
function findNext(cm, rev) {cm.operation(function() { }
function findNext(cm, rev, callback) {cm.operation(function() {
var state = getSearchState(cm); var state = getSearchState(cm);
var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo); var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo);
if (!cursor.find(rev)) { if (!cursor.find(rev)) {
...@@ -99,28 +150,26 @@ ...@@ -99,28 +150,26 @@
if (!cursor.find(rev)) return; if (!cursor.find(rev)) return;
} }
cm.setSelection(cursor.from(), cursor.to()); cm.setSelection(cursor.from(), cursor.to());
cm.scrollIntoView({from: cursor.from(), to: cursor.to()}); cm.scrollIntoView({from: cursor.from(), to: cursor.to()}, 20);
state.posFrom = cursor.from(); state.posTo = cursor.to(); state.posFrom = cursor.from(); state.posTo = cursor.to();
if (callback) callback(cursor.from(), cursor.to())
});} });}
function clearSearch(cm) {cm.operation(function() { function clearSearch(cm) {cm.operation(function() {
var state = getSearchState(cm); var state = getSearchState(cm);
state.lastQuery = state.query;
if (!state.query) return; if (!state.query) return;
state.query = null; state.query = state.queryText = null;
cm.removeOverlay(state.overlay); cm.removeOverlay(state.overlay);
if (state.annotate) { state.annotate.clear(); state.annotate = null; } if (state.annotate) { state.annotate.clear(); state.annotate = null; }
});} });}
var replaceQueryDialog = var replaceQueryDialog =
'Replace: <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use /re/ syntax for regexp search)</span>'; ' <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use /re/ syntax for regexp search)</span>';
var replacementQueryDialog = 'With: <input type="text" style="width: 10em" class="CodeMirror-search-field"/>'; var replacementQueryDialog = 'With: <input type="text" style="width: 10em" class="CodeMirror-search-field"/>';
var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>Stop</button>"; var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>All</button> <button>Stop</button>";
function replace(cm, all) {
if (cm.getOption("readOnly")) return; function replaceAll(cm, query, text) {
dialog(cm, replaceQueryDialog, "Replace:", cm.getSelection(), function(query) {
if (!query) return;
query = parseQuery(query);
dialog(cm, replacementQueryDialog, "Replace with:", "", function(text) {
if (all) {
cm.operation(function() { cm.operation(function() {
for (var cursor = getSearchCursor(cm, query); cursor.findNext();) { for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
if (typeof query != "string") { if (typeof query != "string") {
...@@ -129,6 +178,19 @@ ...@@ -129,6 +178,19 @@
} else cursor.replace(text); } else cursor.replace(text);
} }
}); });
}
function replace(cm, all) {
if (cm.getOption("readOnly")) return;
var query = cm.getSelection() || getSearchState(cm).lastQuery;
var dialogText = all ? "Replace all:" : "Replace:"
dialog(cm, dialogText + replaceQueryDialog, dialogText, query, function(query) {
if (!query) return;
query = parseQuery(query);
dialog(cm, replacementQueryDialog, "Replace with:", "", function(text) {
text = parseString(text)
if (all) {
replaceAll(cm, query, text)
} else { } else {
clearSearch(cm); clearSearch(cm);
var cursor = getSearchCursor(cm, query, cm.getCursor()); var cursor = getSearchCursor(cm, query, cm.getCursor());
...@@ -142,7 +204,8 @@ ...@@ -142,7 +204,8 @@
cm.setSelection(cursor.from(), cursor.to()); cm.setSelection(cursor.from(), cursor.to());
cm.scrollIntoView({from: cursor.from(), to: cursor.to()}); cm.scrollIntoView({from: cursor.from(), to: cursor.to()});
confirmDialog(cm, doReplaceConfirm, "Replace?", confirmDialog(cm, doReplaceConfirm, "Replace?",
[function() {doReplace(match);}, advance]); [function() {doReplace(match);}, advance,
function() {replaceAll(cm, query, text)}]);
}; };
var doReplace = function(match) { var doReplace = function(match) {
cursor.replace(typeof query == "string" ? text : cursor.replace(typeof query == "string" ? text :
...@@ -156,6 +219,7 @@ ...@@ -156,6 +219,7 @@
} }
CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);}; CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);};
CodeMirror.commands.findPersistent = function(cm) {clearSearch(cm); doSearch(cm, false, true);};
CodeMirror.commands.findNext = doSearch; CodeMirror.commands.findNext = doSearch;
CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);}; CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);};
CodeMirror.commands.clearSearch = clearSearch; CodeMirror.commands.clearSearch = clearSearch;
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897121.46</string> </value> <value> <string>ts60604374.93</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>7128</int> </value> <value> <int>8957</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
...@@ -148,10 +148,10 @@ ...@@ -148,10 +148,10 @@
from: function() {if (this.atOccurrence) return this.pos.from;}, from: function() {if (this.atOccurrence) return this.pos.from;},
to: function() {if (this.atOccurrence) return this.pos.to;}, to: function() {if (this.atOccurrence) return this.pos.to;},
replace: function(newText) { replace: function(newText, origin) {
if (!this.atOccurrence) return; if (!this.atOccurrence) return;
var lines = CodeMirror.splitLines(newText); var lines = CodeMirror.splitLines(newText);
this.doc.replaceRange(lines, this.pos.from, this.pos.to); this.doc.replaceRange(lines, this.pos.from, this.pos.to, origin);
this.pos.to = Pos(this.pos.from.line + lines.length - 1, this.pos.to = Pos(this.pos.from.line + lines.length - 1,
lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0)); lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0));
} }
...@@ -177,9 +177,9 @@ ...@@ -177,9 +177,9 @@
}); });
CodeMirror.defineExtension("selectMatches", function(query, caseFold) { CodeMirror.defineExtension("selectMatches", function(query, caseFold) {
var ranges = [], next; var ranges = [];
var cur = this.getSearchCursor(query, this.getCursor("from"), caseFold); var cur = this.getSearchCursor(query, this.getCursor("from"), caseFold);
while (next = cur.findNext()) { while (cur.findNext()) {
if (CodeMirror.cmpPos(cur.to(), this.getCursor("to")) > 0) break; if (CodeMirror.cmpPos(cur.to(), this.getCursor("to")) > 0) break;
ranges.push({anchor: cur.from(), head: cur.to()}); ranges.push({anchor: cur.from(), head: cur.to()});
} }
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_EtagSupport__etag</string> </key> <key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts21897121.6</string> </value> <value> <string>ts60604374.95</string> </value>
</item> </item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>size</string> </key> <key> <string>size</string> </key>
<value> <int>7720</int> </value> <value> <int>7723</int> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment