0
0
mirror of https://github.com/naturalcrit/homebrewery.git synced 2026-03-29 01:18:11 +00:00
This commit is contained in:
Scott Tolksdorf
2016-05-28 09:41:05 -04:00
parent 14b7d60856
commit 626cba6062
190 changed files with 31097 additions and 31097 deletions

32
.gitignore vendored
View File

@@ -1,16 +1,16 @@
# Logs # Logs
logs logs
*.log *.log
#Ignore our built files #Ignore our built files
build/* build/*
architecture.json architecture.json
# Ignore sensitive stuff # Ignore sensitive stuff
/config/* /config/*
!/config/default.json !/config/default.json
node_modules node_modules
storage storage
.idea .idea
*.swp *.swp

View File

@@ -1,29 +1,29 @@
FROM node:latest FROM node:latest
MAINTAINER David Hudson <jendave@yahoo.com> MAINTAINER David Hudson <jendave@yahoo.com>
# System update # System update
RUN apt-get -q -y update RUN apt-get -q -y update
RUN apt-get -q -y install npm RUN apt-get -q -y install npm
RUN apt-get -q -y install mongodb RUN apt-get -q -y install mongodb
RUN apt-get clean && rm -r /var/lib/apt/lists/* RUN apt-get clean && rm -r /var/lib/apt/lists/*
EXPOSE 22 EXPOSE 22
EXPOSE 8000 EXPOSE 8000
ADD start.sh /start.sh ADD start.sh /start.sh
RUN chmod +x /start.sh RUN chmod +x /start.sh
VOLUME ["/opt/apps"] VOLUME ["/opt/apps"]
COPY . /opt/apps/naturalcrit/ COPY . /opt/apps/naturalcrit/
WORKDIR /opt/apps/naturalcrit/ WORKDIR /opt/apps/naturalcrit/
RUN npm install RUN npm install
RUN npm install -g gulp-cli RUN npm install -g gulp-cli
RUN npm install gulp RUN npm install gulp
RUN gulp fresh RUN gulp fresh
CMD ["/start.sh"] CMD ["/start.sh"]

View File

@@ -1,33 +1,33 @@
# NaturalCrit # NaturalCrit
A tool suite for DMs to use for D&D. Check it out [here](http://www.naturalcrit.com). A tool suite for DMs to use for D&D. Check it out [here](http://www.naturalcrit.com).
### Getting started ### Getting started
1. Make sure you have [node](https://nodejs.org/en/) 1. Make sure you have [node](https://nodejs.org/en/)
1. Clone down the repo 1. Clone down the repo
1. In your terminal, head to the repo 1. In your terminal, head to the repo
1. Run `npm install` to get all the dependacies 1. Run `npm install` to get all the dependacies
2. Run `npm install -g gulp` to install the gulp build tool 2. Run `npm install -g gulp` to install the gulp build tool
1. Run `gulp fresh`, this will compile and build all the needed libraries (this only has to be done once, unless you add more libs) 1. Run `gulp fresh`, this will compile and build all the needed libraries (this only has to be done once, unless you add more libs)
1. Run `gulp` to run the project locally. Should be accessible at `localhost:8000` 1. Run `gulp` to run the project locally. Should be accessible at `localhost:8000`
2. Any changes to files within the proejct will be detected and the propject will automatically re-build 2. Any changes to files within the proejct will be detected and the propject will automatically re-build
**Notes:** If you'd like to create and edit homebrews, you'll need to have MongoDB installed and running. **Notes:** If you'd like to create and edit homebrews, you'll need to have MongoDB installed and running.
Have fun! Have fun!
### Docker Image ### Docker Image
You can use [Docker](https://docs.docker.com) to get up and running with NaturalCrit. You can use [Docker](https://docs.docker.com) to get up and running with NaturalCrit.
1. Install Docker 1. Install Docker
1. Clone the repo 1. Clone the repo
1. In the terminal, go to the repo 1. In the terminal, go to the repo
1. Build the docker image `docker build -t naturalcrit .` 1. Build the docker image `docker build -t naturalcrit .`
1. Run the docker container `docker run -dit -p 8000:8000 naturalcrit` 1. Run the docker container `docker run -dit -p 8000:8000 naturalcrit`
1. You can check out the website on your computer on port 8000 1. You can check out the website on your computer on port 8000
1. You may have to use `docker-machine env` to get the IP address of your docker instance 1. You may have to use `docker-machine env` to get the IP address of your docker instance
### changelog ### changelog
You can check out the changelog [here](https://github.com/stolksdorf/NaturalCrit/blob/master/changelog.md) You can check out the changelog [here](https://github.com/stolksdorf/NaturalCrit/blob/master/changelog.md)

View File

@@ -1,41 +1,41 @@
var React = require('react'); var React = require('react');
var _ = require('lodash'); var _ = require('lodash');
var cx = require('classnames'); var cx = require('classnames');
var HomebrewAdmin = require('./homebrewAdmin/homebrewAdmin.jsx'); var HomebrewAdmin = require('./homebrewAdmin/homebrewAdmin.jsx');
var Admin = React.createClass({ var Admin = React.createClass({
getDefaultProps: function() { getDefaultProps: function() {
return { return {
url : "", url : "",
admin_key : "", admin_key : "",
homebrews : [], homebrews : [],
}; };
}, },
render : function(){ render : function(){
var self = this; var self = this;
return( return(
<div className='admin'> <div className='admin'>
<header> <header>
<div className='container'> <div className='container'>
<i className='fa fa-rocket' /> <i className='fa fa-rocket' />
naturalcrit admin naturalcrit admin
</div> </div>
</header> </header>
<div className='container'> <div className='container'>
<a target="_blank" href='https://www.google.com/analytics/web/?hl=en#report/defaultid/a72212009w109843310p114529111/'>Link to Google Analytics</a> <a target="_blank" href='https://www.google.com/analytics/web/?hl=en#report/defaultid/a72212009w109843310p114529111/'>Link to Google Analytics</a>
<HomebrewAdmin homebrews={this.props.homebrews} admin_key={this.props.admin_key} /> <HomebrewAdmin homebrews={this.props.homebrews} admin_key={this.props.admin_key} />
</div> </div>
</div> </div>
); );
} }
}); });
module.exports = Admin; module.exports = Admin;

View File

@@ -1,39 +1,39 @@
@import 'naturalcrit/styles/reset.less'; @import 'naturalcrit/styles/reset.less';
@import 'naturalcrit/styles/elements.less'; @import 'naturalcrit/styles/elements.less';
@import 'naturalcrit/styles/animations.less'; @import 'naturalcrit/styles/animations.less';
@import 'naturalcrit/styles/colors.less'; @import 'naturalcrit/styles/colors.less';
@import 'naturalcrit/styles/tooltip.less'; @import 'naturalcrit/styles/tooltip.less';
@import 'font-awesome/css/font-awesome.css'; @import 'font-awesome/css/font-awesome.css';
html,body, #reactContainer, .naturalCrit{ html,body, #reactContainer, .naturalCrit{
min-height : 100%; min-height : 100%;
} }
@sidebarWidth : 250px; @sidebarWidth : 250px;
body{ body{
background-color : #eee; background-color : #eee;
font-family : 'Open Sans', sans-serif; font-family : 'Open Sans', sans-serif;
color : #4b5055; color : #4b5055;
font-weight : 100; font-weight : 100;
text-rendering : optimizeLegibility; text-rendering : optimizeLegibility;
margin : 0; margin : 0;
padding : 0; padding : 0;
height : 100%; height : 100%;
} }
.admin{ .admin{
header{ header{
background-color : @red; background-color : @red;
font-size: 2em; font-size: 2em;
padding : 20px 0px; padding : 20px 0px;
color : white; color : white;
margin-bottom: 30px; margin-bottom: 30px;
i{ i{
margin-right: 30px; margin-right: 30px;
} }
} }
} }

View File

@@ -1,72 +1,72 @@
var React = require('react'); var React = require('react');
var _ = require('lodash'); var _ = require('lodash');
var cx = require('classnames'); var cx = require('classnames');
var request = require('superagent'); var request = require('superagent');
var BrewSearch = React.createClass({ var BrewSearch = React.createClass({
getDefaultProps: function() { getDefaultProps: function() {
return { return {
admin_key : '' admin_key : ''
}; };
}, },
getInitialState: function() { getInitialState: function() {
return { return {
searchTerm: '', searchTerm: '',
brew : null, brew : null,
searching : false searching : false
}; };
}, },
search : function(){ search : function(){
this.setState({ this.setState({
searching : true searching : true
}); });
request.get('/homebrew/api/search?id=' + this.state.searchTerm) request.get('/homebrew/api/search?id=' + this.state.searchTerm)
.query({ .query({
admin_key : this.props.admin_key, admin_key : this.props.admin_key,
}) })
.end((err, res)=>{ .end((err, res)=>{
console.log(err, res, res.body.brews[0]); console.log(err, res, res.body.brews[0]);
this.setState({ this.setState({
brew : res.body.brews[0], brew : res.body.brews[0],
searching : false searching : false
}) })
}); });
}, },
handleChange : function(e){ handleChange : function(e){
this.setState({ this.setState({
searchTerm : e.target.value searchTerm : e.target.value
}); });
}, },
handleSearchClick : function(){ handleSearchClick : function(){
this.search(); this.search();
}, },
renderBrew : function(){ renderBrew : function(){
if(!this.state.brew) return null; if(!this.state.brew) return null;
return <div className='brew'> return <div className='brew'>
<div>Edit id : {this.state.brew.editId}</div> <div>Edit id : {this.state.brew.editId}</div>
<div>Share id : {this.state.brew.shareId}</div> <div>Share id : {this.state.brew.shareId}</div>
</div> </div>
}, },
render : function(){ render : function(){
return <div className='search'> return <div className='search'>
<input type='text' value={this.state.searchTerm} onChange={this.handleChange} /> <input type='text' value={this.state.searchTerm} onChange={this.handleChange} />
<button onClick={this.handleSearchClick}>Search</button> <button onClick={this.handleSearchClick}>Search</button>
{this.renderBrew()} {this.renderBrew()}
</div> </div>
}, },
}); });
module.exports = BrewSearch; module.exports = BrewSearch;

View File

@@ -1,159 +1,159 @@
var React = require('react'); var React = require('react');
var _ = require('lodash'); var _ = require('lodash');
var cx = require('classnames'); var cx = require('classnames');
var request = require('superagent'); var request = require('superagent');
var Moment = require('moment'); var Moment = require('moment');
var BrewSearch = require('./brewSearch.jsx'); var BrewSearch = require('./brewSearch.jsx');
var HomebrewAdmin = React.createClass({ var HomebrewAdmin = React.createClass({
getDefaultProps: function() { getDefaultProps: function() {
return { return {
admin_key : '' admin_key : ''
}; };
}, },
getInitialState: function() { getInitialState: function() {
return { return {
page: 0, page: 0,
count : 20, count : 20,
brewCache : {}, brewCache : {},
total : 0, total : 0,
processingOldBrews : false processingOldBrews : false
}; };
}, },
fetchBrews : function(page){ fetchBrews : function(page){
request.get('/homebrew/api/search') request.get('/homebrew/api/search')
.query({ .query({
admin_key : this.props.admin_key, admin_key : this.props.admin_key,
count : this.state.count, count : this.state.count,
page : page page : page
}) })
.end((err, res)=>{ .end((err, res)=>{
this.state.brewCache[page] = res.body.brews; this.state.brewCache[page] = res.body.brews;
this.setState({ this.setState({
brewCache : this.state.brewCache, brewCache : this.state.brewCache,
total : res.body.total, total : res.body.total,
count : res.body.count count : res.body.count
}) })
}) })
}, },
componentDidMount: function() { componentDidMount: function() {
this.fetchBrews(this.state.page); this.fetchBrews(this.state.page);
}, },
changePageTo : function(page){ changePageTo : function(page){
if(!this.state.brewCache[page]){ if(!this.state.brewCache[page]){
this.fetchBrews(page); this.fetchBrews(page);
} }
this.setState({ this.setState({
page : page page : page
}) })
}, },
clearInvalidBrews : function(){ clearInvalidBrews : function(){
request.get('/homebrew/api/invalid') request.get('/homebrew/api/invalid')
.query({admin_key : this.props.admin_key}) .query({admin_key : this.props.admin_key})
.end((err, res)=>{ .end((err, res)=>{
if(!confirm("This will remove " + res.body.count + " brews. Are you sure?")) return; if(!confirm("This will remove " + res.body.count + " brews. Are you sure?")) return;
request.get('/homebrew/api/invalid') request.get('/homebrew/api/invalid')
.query({admin_key : this.props.admin_key, do_it : true}) .query({admin_key : this.props.admin_key, do_it : true})
.end((err, res)=>{ .end((err, res)=>{
alert("Done!") alert("Done!")
}); });
}); });
}, },
deleteBrew : function(brewId){ deleteBrew : function(brewId){
if(!confirm("Are you sure you want to delete '" + brewId + "'?")) return; if(!confirm("Are you sure you want to delete '" + brewId + "'?")) return;
request.get('/homebrew/api/remove/' + brewId) request.get('/homebrew/api/remove/' + brewId)
.query({admin_key : this.props.admin_key}) .query({admin_key : this.props.admin_key})
.end(function(err, res){ .end(function(err, res){
window.location.reload(); window.location.reload();
}) })
}, },
handlePageChange : function(dir){ handlePageChange : function(dir){
this.changePageTo(this.state.page + dir); this.changePageTo(this.state.page + dir);
}, },
renderPagnination : function(){ renderPagnination : function(){
var outOf; var outOf;
if(this.state.total){ if(this.state.total){
outOf = this.state.page + ' / ' + Math.round(this.state.total/this.state.count); outOf = this.state.page + ' / ' + Math.round(this.state.total/this.state.count);
} }
return <div className='pagnination'> return <div className='pagnination'>
<i className='fa fa-chevron-left' onClick={this.handlePageChange.bind(this, -1)}/> <i className='fa fa-chevron-left' onClick={this.handlePageChange.bind(this, -1)}/>
{outOf} {outOf}
<i className='fa fa-chevron-right' onClick={this.handlePageChange.bind(this, 1)}/> <i className='fa fa-chevron-right' onClick={this.handlePageChange.bind(this, 1)}/>
</div> </div>
}, },
renderBrews : function(){ renderBrews : function(){
var brews = this.state.brewCache[this.state.page] || _.times(this.state.count); var brews = this.state.brewCache[this.state.page] || _.times(this.state.count);
return _.map(brews, (brew)=>{ return _.map(brews, (brew)=>{
return <tr className={cx('brewRow', {'isEmpty' : brew.text == "false"})} key={brew.shareId || brew}> return <tr className={cx('brewRow', {'isEmpty' : brew.text == "false"})} key={brew.shareId || brew}>
<td><a href={'/homebrew/edit/' + brew.editId} target='_blank'>{brew.editId}</a></td> <td><a href={'/homebrew/edit/' + brew.editId} target='_blank'>{brew.editId}</a></td>
<td><a href={'/homebrew/share/' + brew.shareId} target='_blank'>{brew.shareId}</a></td> <td><a href={'/homebrew/share/' + brew.shareId} target='_blank'>{brew.shareId}</a></td>
<td>{Moment(brew.createdAt).fromNow()}</td> <td>{Moment(brew.createdAt).fromNow()}</td>
<td>{Moment(brew.updatedAt).fromNow()}</td> <td>{Moment(brew.updatedAt).fromNow()}</td>
<td>{Moment(brew.lastViewed).fromNow()}</td> <td>{Moment(brew.lastViewed).fromNow()}</td>
<td>{brew.views}</td> <td>{brew.views}</td>
<td> <td>
<div className='deleteButton' onClick={this.deleteBrew.bind(this, brew.editId)}> <div className='deleteButton' onClick={this.deleteBrew.bind(this, brew.editId)}>
<i className='fa fa-trash' /> <i className='fa fa-trash' />
</div> </div>
</td> </td>
</tr> </tr>
}); });
}, },
renderBrewTable : function(){ renderBrewTable : function(){
return <div className='brewTable'> return <div className='brewTable'>
<table> <table>
<thead> <thead>
<tr> <tr>
<th>Edit Id</th> <th>Edit Id</th>
<th>Share Id</th> <th>Share Id</th>
<th>Created At</th> <th>Created At</th>
<th>Last Updated</th> <th>Last Updated</th>
<th>Last Viewed</th> <th>Last Viewed</th>
<th>Views</th> <th>Views</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{this.renderBrews()} {this.renderBrews()}
</tbody> </tbody>
</table> </table>
</div> </div>
}, },
render : function(){ render : function(){
var self = this; var self = this;
return <div className='homebrewAdmin'> return <div className='homebrewAdmin'>
<h2> <h2>
Homebrews - {this.state.total} Homebrews - {this.state.total}
</h2> </h2>
{this.renderPagnination()} {this.renderPagnination()}
{this.renderBrewTable()} {this.renderBrewTable()}
<button className='clearOldButton' onClick={this.clearInvalidBrews}> <button className='clearOldButton' onClick={this.clearInvalidBrews}>
Clear Old Clear Old
</button> </button>
<BrewSearch admin_key={this.props.admin_key} /> <BrewSearch admin_key={this.props.admin_key} />
</div> </div>
} }
}); });
module.exports = HomebrewAdmin; module.exports = HomebrewAdmin;

View File

@@ -1,53 +1,53 @@
.homebrewAdmin{ .homebrewAdmin{
margin-bottom: 80px; margin-bottom: 80px;
.brewTable{ .brewTable{
table{ table{
th{ th{
padding : 10px; padding : 10px;
font-weight : 800; font-weight : 800;
} }
tr:nth-child(even){ tr:nth-child(even){
background-color : fade(@green, 10%); background-color : fade(@green, 10%);
} }
tr.isEmpty{ tr.isEmpty{
background-color : fade(@red, 30%); background-color : fade(@red, 30%);
} }
td{ td{
min-width : 100px; min-width : 100px;
padding : 10px; padding : 10px;
text-align : center; text-align : center;
&.preview{ &.preview{
position : relative; position : relative;
&:hover{ &:hover{
.content{ .content{
display : block; display : block;
} }
} }
.content{ .content{
position : absolute; position : absolute;
display : none; display : none;
top : 100%; top : 100%;
left : 0px; left : 0px;
z-index : 1000; z-index : 1000;
max-height : 500px; max-height : 500px;
width : 300px; width : 300px;
padding : 30px; padding : 30px;
background-color : white; background-color : white;
font-family : monospace; font-family : monospace;
text-align : left; text-align : left;
pointer-events : none; pointer-events : none;
} }
} }
} }
} }
} }
.deleteButton{ .deleteButton{
cursor: pointer; cursor: pointer;
} }
button.clearOldButton{ button.clearOldButton{
float : right; float : right;
} }
} }

View File

@@ -1,97 +1,97 @@
var React = require('react'); var React = require('react');
var _ = require('lodash'); var _ = require('lodash');
var cx = require('classnames'); var cx = require('classnames');
var Markdown = require('marked'); var Markdown = require('marked');
var PAGE_HEIGHT = 1056 + 30; var PAGE_HEIGHT = 1056 + 30;
var BrewRenderer = React.createClass({ var BrewRenderer = React.createClass({
getDefaultProps: function() { getDefaultProps: function() {
return { return {
text : '' text : ''
}; };
}, },
getInitialState: function() { getInitialState: function() {
return { return {
viewablePageNumber: 0, viewablePageNumber: 0,
height : 0, height : 0,
isMounted : false isMounted : false
}; };
}, },
totalPages : 0, totalPages : 0,
height : 0, height : 0,
componentDidMount: function() { componentDidMount: function() {
this.setState({ this.setState({
height : this.refs.main.parentNode.clientHeight, height : this.refs.main.parentNode.clientHeight,
isMounted : true isMounted : true
}); });
}, },
handleScroll : function(e){ handleScroll : function(e){
this.setState({ this.setState({
viewablePageNumber : Math.floor(e.target.scrollTop / PAGE_HEIGHT) viewablePageNumber : Math.floor(e.target.scrollTop / PAGE_HEIGHT)
}); });
}, },
//Implement later //Implement later
scrollToPage : function(pageNumber){ scrollToPage : function(pageNumber){
}, },
shouldRender : function(pageText, index){ shouldRender : function(pageText, index){
if(!this.state.isMounted) return false; if(!this.state.isMounted) return false;
var viewIndex = this.state.viewablePageNumber; var viewIndex = this.state.viewablePageNumber;
if(index == viewIndex - 1) return true; if(index == viewIndex - 1) return true;
if(index == viewIndex) return true; if(index == viewIndex) return true;
if(index == viewIndex + 1) return true; if(index == viewIndex + 1) return true;
//Check for style tages //Check for style tages
if(pageText.indexOf('<style>') !== -1) return true; if(pageText.indexOf('<style>') !== -1) return true;
return false; return false;
}, },
renderPageInfo : function(){ renderPageInfo : function(){
return <div className='pageInfo'> return <div className='pageInfo'>
{this.state.viewablePageNumber + 1} / {this.totalPages} {this.state.viewablePageNumber + 1} / {this.totalPages}
</div> </div>
}, },
renderDummyPage : function(key){ renderDummyPage : function(key){
return <div className='phb' key={key}> return <div className='phb' key={key}>
<i className='fa fa-spinner fa-spin' /> <i className='fa fa-spinner fa-spin' />
</div> </div>
}, },
renderPage : function(pageText, index){ renderPage : function(pageText, index){
return <div className='phb' dangerouslySetInnerHTML={{__html:Markdown(pageText)}} key={index} /> return <div className='phb' dangerouslySetInnerHTML={{__html:Markdown(pageText)}} key={index} />
}, },
renderPages : function(){ renderPages : function(){
var pages = this.props.text.split('\\page'); var pages = this.props.text.split('\\page');
this.totalPages = pages.length; this.totalPages = pages.length;
return _.map(pages, (page, index)=>{ return _.map(pages, (page, index)=>{
if(this.shouldRender(page, index)){ if(this.shouldRender(page, index)){
return this.renderPage(page, index); return this.renderPage(page, index);
}else{ }else{
return this.renderDummyPage(index); return this.renderDummyPage(index);
} }
}); });
}, },
render : function(){ render : function(){
return <div className='brewRenderer' return <div className='brewRenderer'
onScroll={this.handleScroll} onScroll={this.handleScroll}
ref='main' ref='main'
style={{height : this.state.height}}> style={{height : this.state.height}}>
<div className='pages'> <div className='pages'>
{this.renderPages()} {this.renderPages()}
</div> </div>
{this.renderPageInfo()} {this.renderPageInfo()}
</div> </div>
} }
}); });
module.exports = BrewRenderer; module.exports = BrewRenderer;

View File

@@ -1,28 +1,28 @@
@import (less) './client/homebrew/phbStyle/phb.style.less'; @import (less) './client/homebrew/phbStyle/phb.style.less';
.pane{ .pane{
position : relative; position : relative;
} }
.brewRenderer{ .brewRenderer{
overflow-y : scroll; overflow-y : scroll;
.pageInfo{ .pageInfo{
position : absolute; position : absolute;
right : 17px; right : 17px;
bottom : 0; bottom : 0;
z-index : 1000; z-index : 1000;
padding : 8px 10px; padding : 8px 10px;
background-color : #333; background-color : #333;
font-size : 10px; font-size : 10px;
font-weight : 800; font-weight : 800;
color : white; color : white;
} }
.pages{ .pages{
margin : 30px 0px; margin : 30px 0px;
&>.phb{ &>.phb{
margin-right : auto; margin-right : auto;
margin-bottom : 30px; margin-bottom : 30px;
margin-left : auto; margin-left : auto;
box-shadow : 1px 4px 14px #000; box-shadow : 1px 4px 14px #000;
} }
} }
} }

View File

@@ -1,129 +1,129 @@
var React = require('react'); var React = require('react');
var _ = require('lodash'); var _ = require('lodash');
var cx = require('classnames'); var cx = require('classnames');
var CodeEditor = require('naturalcrit/codeEditor/codeEditor.jsx'); var CodeEditor = require('naturalcrit/codeEditor/codeEditor.jsx');
var Snippets = require('./snippets/snippets.js'); var Snippets = require('./snippets/snippets.js');
var splice = function(str, index, inject){ var splice = function(str, index, inject){
return str.slice(0, index) + inject + str.slice(index); return str.slice(0, index) + inject + str.slice(index);
}; };
var execute = function(val){ var execute = function(val){
if(_.isFunction(val)) return val(); if(_.isFunction(val)) return val();
return val; return val;
} }
var Editor = React.createClass({ var Editor = React.createClass({
getDefaultProps: function() { getDefaultProps: function() {
return { return {
value : "", value : "",
onChange : function(){} onChange : function(){}
}; };
}, },
cursorPosition : { cursorPosition : {
line : 0, line : 0,
ch : 0 ch : 0
}, },
componentDidMount: function() { componentDidMount: function() {
var paneHeight = this.refs.main.parentNode.clientHeight; var paneHeight = this.refs.main.parentNode.clientHeight;
paneHeight -= this.refs.snippetBar.clientHeight + 1; paneHeight -= this.refs.snippetBar.clientHeight + 1;
this.refs.codeEditor.codeMirror.setSize(null, paneHeight); this.refs.codeEditor.codeMirror.setSize(null, paneHeight);
}, },
handleTextChange : function(text){ handleTextChange : function(text){
this.props.onChange(text); this.props.onChange(text);
}, },
handleCursorActivty : function(curpos){ handleCursorActivty : function(curpos){
this.cursorPosition = curpos; this.cursorPosition = curpos;
}, },
handleSnippetClick : function(injectText){ handleSnippetClick : function(injectText){
var lines = this.props.value.split('\n'); var lines = this.props.value.split('\n');
lines[this.cursorPosition.line] = splice(lines[this.cursorPosition.line], this.cursorPosition.ch, injectText); lines[this.cursorPosition.line] = splice(lines[this.cursorPosition.line], this.cursorPosition.ch, injectText);
this.handleTextChange(lines.join('\n')); this.handleTextChange(lines.join('\n'));
this.refs.codeEditor.setCursorPosition(this.cursorPosition.line, this.cursorPosition.ch + injectText.length); this.refs.codeEditor.setCursorPosition(this.cursorPosition.line, this.cursorPosition.ch + injectText.length);
}, },
//Called when there are changes to the editor's dimensions //Called when there are changes to the editor's dimensions
update : function(){ update : function(){
this.refs.codeEditor.updateSize(); this.refs.codeEditor.updateSize();
}, },
renderSnippetGroups : function(){ renderSnippetGroups : function(){
return _.map(Snippets, (snippetGroup)=>{ return _.map(Snippets, (snippetGroup)=>{
return <SnippetGroup return <SnippetGroup
groupName={snippetGroup.groupName} groupName={snippetGroup.groupName}
icon={snippetGroup.icon} icon={snippetGroup.icon}
snippets={snippetGroup.snippets} snippets={snippetGroup.snippets}
key={snippetGroup.groupName} key={snippetGroup.groupName}
onSnippetClick={this.handleSnippetClick} onSnippetClick={this.handleSnippetClick}
/> />
}) })
}, },
render : function(){ render : function(){
return( return(
<div className='editor' ref='main'> <div className='editor' ref='main'>
<div className='snippetBar' ref='snippetBar'> <div className='snippetBar' ref='snippetBar'>
{this.renderSnippetGroups()} {this.renderSnippetGroups()}
</div> </div>
<CodeEditor <CodeEditor
ref='codeEditor' ref='codeEditor'
wrap={true} wrap={true}
language='gfm' language='gfm'
value={this.props.value} value={this.props.value}
onChange={this.handleTextChange} onChange={this.handleTextChange}
onCursorActivity={this.handleCursorActivty} /> onCursorActivity={this.handleCursorActivty} />
</div> </div>
); );
} }
}); });
module.exports = Editor; module.exports = Editor;
var SnippetGroup = React.createClass({ var SnippetGroup = React.createClass({
getDefaultProps: function() { getDefaultProps: function() {
return { return {
groupName : '', groupName : '',
icon : 'fa-rocket', icon : 'fa-rocket',
snippets : [], snippets : [],
onSnippetClick : function(){}, onSnippetClick : function(){},
}; };
}, },
handleSnippetClick : function(snippet){ handleSnippetClick : function(snippet){
this.props.onSnippetClick(execute(snippet.gen)); this.props.onSnippetClick(execute(snippet.gen));
}, },
renderSnippets : function(){ renderSnippets : function(){
return _.map(this.props.snippets, (snippet)=>{ return _.map(this.props.snippets, (snippet)=>{
return <div className='snippet' key={snippet.name} onClick={this.handleSnippetClick.bind(this, snippet)}> return <div className='snippet' key={snippet.name} onClick={this.handleSnippetClick.bind(this, snippet)}>
<i className={'fa fa-fw ' + snippet.icon} /> <i className={'fa fa-fw ' + snippet.icon} />
{snippet.name} {snippet.name}
</div> </div>
}) })
}, },
render : function(){ render : function(){
return <div className='snippetGroup'> return <div className='snippetGroup'>
<div className='text'> <div className='text'>
<i className={'fa fa-fw ' + this.props.icon} /> <i className={'fa fa-fw ' + this.props.icon} />
<span className='groupName'>{this.props.groupName}</span> <span className='groupName'>{this.props.groupName}</span>
</div> </div>
<div className='dropdown'> <div className='dropdown'>
{this.renderSnippets()} {this.renderSnippets()}
</div> </div>
</div> </div>
}, },
}); });

View File

@@ -1,56 +1,56 @@
.editor{ .editor{
position : relative; position : relative;
width : 100%; width : 100%;
.snippetBar{ .snippetBar{
display : flex; display : flex;
padding : 5px; padding : 5px;
background-color : #ddd; background-color : #ddd;
align-items : center; align-items : center;
.snippetGroup{ .snippetGroup{
.animate(background-color); .animate(background-color);
margin : 0px 8px; margin : 0px 8px;
padding : 3px; padding : 3px;
font-size : 13px; font-size : 13px;
border-radius : 5px; border-radius : 5px;
&:hover, &.selected{ &:hover, &.selected{
background-color : #999; background-color : #999;
} }
.text{ .text{
line-height : 20px; line-height : 20px;
.groupName{ .groupName{
margin-left : 6px; margin-left : 6px;
font-size : 10px; font-size : 10px;
} }
} }
&:hover{ &:hover{
.dropdown{ .dropdown{
visibility : visible; visibility : visible;
} }
} }
.dropdown{ .dropdown{
position : absolute; position : absolute;
visibility : hidden; visibility : hidden;
z-index : 1000; z-index : 1000;
padding : 5px; padding : 5px;
background-color : #ddd; background-color : #ddd;
.snippet{ .snippet{
.animate(background-color); .animate(background-color);
padding : 10px; padding : 10px;
cursor : pointer; cursor : pointer;
font-size : 10px; font-size : 10px;
i{ i{
margin-right: 8px; margin-right: 8px;
font-size : 13px; font-size : 13px;
} }
&:hover{ &:hover{
background-color : #999; background-color : #999;
} }
} }
} }
} }
} }
.codeEditor{ .codeEditor{
height : 100%; height : 100%;
} }
} }

View File

@@ -1,42 +1,42 @@
var _ = require('lodash'); var _ = require('lodash');
module.exports = function(classname){ module.exports = function(classname){
classname = classname || _.sample(['archivist', 'fancyman', 'linguist', 'fletcher', classname = classname || _.sample(['archivist', 'fancyman', 'linguist', 'fletcher',
'notary', 'berserker-typist', 'fishmongerer', 'manicurist', 'haberdasher', 'concierge']) 'notary', 'berserker-typist', 'fishmongerer', 'manicurist', 'haberdasher', 'concierge'])
classname = classname.toLowerCase(); classname = classname.toLowerCase();
var hitDie = _.sample([4, 6, 8, 10, 12]); var hitDie = _.sample([4, 6, 8, 10, 12]);
var abilityList = ["Strength", "Dexerity", "Constitution", "Wisdom", "Charisma", "Intelligence"]; var abilityList = ["Strength", "Dexerity", "Constitution", "Wisdom", "Charisma", "Intelligence"];
var skillList = ["Acrobatics ", "Animal Handling", "Arcana", "Athletics", "Deception", "History", "Insight", "Intimidation", "Investigation", "Medicine", "Nature", "Perception", "Performance", "Persuasion", "Religion", "Sleight of Hand", "Stealth", "Survival"]; var skillList = ["Acrobatics ", "Animal Handling", "Arcana", "Athletics", "Deception", "History", "Insight", "Intimidation", "Investigation", "Medicine", "Nature", "Perception", "Performance", "Persuasion", "Religion", "Sleight of Hand", "Stealth", "Survival"];
return [ return [
"## Class Features", "## Class Features",
"As a " + classname + ", you gain the following class features", "As a " + classname + ", you gain the following class features",
"#### Hit Points", "#### Hit Points",
"___", "___",
"- **Hit Dice:** 1d" + hitDie + " per " + classname + " level", "- **Hit Dice:** 1d" + hitDie + " per " + classname + " level",
"- **Hit Points at 1st Level:** " + hitDie + " + your Constituion modifier", "- **Hit Points at 1st Level:** " + hitDie + " + your Constituion modifier",
"- **Hit Points at Higher Levels:** 1d" + hitDie + " (or " + (hitDie/2 + 1) + ") + your Constituion modifier per " + classname + " level after 1st", "- **Hit Points at Higher Levels:** 1d" + hitDie + " (or " + (hitDie/2 + 1) + ") + your Constituion modifier per " + classname + " level after 1st",
"", "",
"#### Proficiencies", "#### Proficiencies",
"___", "___",
"- **Armor:** " + (_.sampleSize(["Light armor", "Medium armor", "Heavy armor", "Shields"], _.random(0,3)).join(', ') || "None"), "- **Armor:** " + (_.sampleSize(["Light armor", "Medium armor", "Heavy armor", "Shields"], _.random(0,3)).join(', ') || "None"),
"- **Weapons:** " + (_.sampleSize(["Squeegee", "Rubber Chicken", "Simple weapons", "Martial weapons"], _.random(0,2)).join(', ') || "None"), "- **Weapons:** " + (_.sampleSize(["Squeegee", "Rubber Chicken", "Simple weapons", "Martial weapons"], _.random(0,2)).join(', ') || "None"),
"- **Tools:** " + (_.sampleSize(["Artian's tools", "one musical instrument", "Thieve's tools"], _.random(0,2)).join(', ') || "None"), "- **Tools:** " + (_.sampleSize(["Artian's tools", "one musical instrument", "Thieve's tools"], _.random(0,2)).join(', ') || "None"),
"", "",
"___", "___",
"- **Saving Throws:** " + (_.sampleSize(abilityList, 2).join(', ')), "- **Saving Throws:** " + (_.sampleSize(abilityList, 2).join(', ')),
"- **Skills:** Choose two from " + (_.sampleSize(skillList, _.random(4, 6)).join(', ')), "- **Skills:** Choose two from " + (_.sampleSize(skillList, _.random(4, 6)).join(', ')),
"", "",
"#### Equipment", "#### Equipment",
"You start with the following equipment, in addition to the equipment granted by your background:", "You start with the following equipment, in addition to the equipment granted by your background:",
"- *(a)* a martial weapon and a shield or *(b)* two martial weapons", "- *(a)* a martial weapon and a shield or *(b)* two martial weapons",
"- *(a)* five javelins or *(b)* any simple melee weapon", "- *(a)* five javelins or *(b)* any simple melee weapon",
"- " + (_.sample(["10 lint fluffs", "1 button", "a cherished lost sock"])), "- " + (_.sample(["10 lint fluffs", "1 button", "a cherished lost sock"])),
"\n\n\n" "\n\n\n"
].join('\n'); ].join('\n');
} }

View File

@@ -1,196 +1,196 @@
var _ = require('lodash'); var _ = require('lodash');
var genList = function(list, max){ var genList = function(list, max){
return _.sampleSize(list, _.random(0,max)).join(', ') || "None"; return _.sampleSize(list, _.random(0,max)).join(', ') || "None";
} }
var getMonsterName = function(){ var getMonsterName = function(){
return _.sample([ return _.sample([
"All-devouring Baseball Imp", "All-devouring Baseball Imp",
"All-devouring Gumdrop Wraith", "All-devouring Gumdrop Wraith",
"Chocolate Hydra", "Chocolate Hydra",
"Devouring Peacock", "Devouring Peacock",
"Economy-sized Colossus of the Lemonade Stand", "Economy-sized Colossus of the Lemonade Stand",
"Ghost Pigeon", "Ghost Pigeon",
"Gibbering Duck", "Gibbering Duck",
"Sparklemuffin Peacock Spider", "Sparklemuffin Peacock Spider",
"Gum Elemental", "Gum Elemental",
"Illiterate Construct of the Candy Store", "Illiterate Construct of the Candy Store",
"Ineffable Chihuahua", "Ineffable Chihuahua",
"Irritating Death Hamster", "Irritating Death Hamster",
"Irritating Gold Mouse", "Irritating Gold Mouse",
"Juggernaut Snail", "Juggernaut Snail",
"Juggernaut of the Sock Drawer", "Juggernaut of the Sock Drawer",
"Koala of the Cosmos", "Koala of the Cosmos",
"Mad Koala of the West", "Mad Koala of the West",
"Milk Djinni of the Lemonade Stand", "Milk Djinni of the Lemonade Stand",
"Mind Ferret", "Mind Ferret",
"Mystic Salt Spider", "Mystic Salt Spider",
"Necrotic Halitosis Angel", "Necrotic Halitosis Angel",
"Pinstriped Famine Sheep", "Pinstriped Famine Sheep",
"Ritalin Leech", "Ritalin Leech",
"Shocker Kangaroo", "Shocker Kangaroo",
"Stellar Tennis Juggernaut", "Stellar Tennis Juggernaut",
"Wailing Quail of the Sun", "Wailing Quail of the Sun",
"Angel Pigeon", "Angel Pigeon",
"Anime Sphinx", "Anime Sphinx",
"Bored Avalanche Sheep of the Wasteland", "Bored Avalanche Sheep of the Wasteland",
"Devouring Nougat Sphinx of the Sock Drawer", "Devouring Nougat Sphinx of the Sock Drawer",
"Djinni of the Footlocker", "Djinni of the Footlocker",
"Ectoplasmic Jazz Devil", "Ectoplasmic Jazz Devil",
"Flatuent Angel", "Flatuent Angel",
"Gelatinous Duck of the Dream-Lands", "Gelatinous Duck of the Dream-Lands",
"Gelatinous Mouse", "Gelatinous Mouse",
"Golem of the Footlocker", "Golem of the Footlocker",
"Lich Wombat", "Lich Wombat",
"Mechanical Sloth of the Past", "Mechanical Sloth of the Past",
"Milkshake Succubus", "Milkshake Succubus",
"Puffy Bone Peacock of the East", "Puffy Bone Peacock of the East",
"Rainbow Manatee", "Rainbow Manatee",
"Rune Parrot", "Rune Parrot",
"Sand Cow", "Sand Cow",
"Sinister Vanilla Dragon", "Sinister Vanilla Dragon",
"Snail of the North", "Snail of the North",
"Spider of the Sewer", "Spider of the Sewer",
"Stellar Sawdust Leech", "Stellar Sawdust Leech",
"Storm Anteater of Hell", "Storm Anteater of Hell",
"Stupid Spirit of the Brewery", "Stupid Spirit of the Brewery",
"Time Kangaroo", "Time Kangaroo",
"Tomb Poodle", "Tomb Poodle",
]); ]);
} }
var getType = function(){ var getType = function(){
return _.sample(['Tiny', 'Small', 'Medium', 'Large', 'Gargantuan', 'Stupidly vast']) + " " + _.sample(['beast', 'fiend', 'annoyance', 'guy', 'cutie']) return _.sample(['Tiny', 'Small', 'Medium', 'Large', 'Gargantuan', 'Stupidly vast']) + " " + _.sample(['beast', 'fiend', 'annoyance', 'guy', 'cutie'])
} }
var getAlignment = function(){ var getAlignment = function(){
return _.sample([ return _.sample([
"annoying evil", "annoying evil",
"chaotic gossipy", "chaotic gossipy",
"chaotic sloppy", "chaotic sloppy",
"depressed neutral", "depressed neutral",
"lawful bogus", "lawful bogus",
"lawful coy", "lawful coy",
"manic-depressive evil", "manic-depressive evil",
"narrow-minded neutral", "narrow-minded neutral",
"neutral annoying", "neutral annoying",
"neutral ignorant", "neutral ignorant",
"oedpipal neutral", "oedpipal neutral",
"silly neutral", "silly neutral",
"unoriginal neutral", "unoriginal neutral",
"weird neutral", "weird neutral",
"wordy evil", "wordy evil",
"unaligned" "unaligned"
]); ]);
}; };
var getStats = function(){ var getStats = function(){
return '>|' + _.times(6, function(){ return '>|' + _.times(6, function(){
var num = _.random(1,20); var num = _.random(1,20);
var mod = Math.ceil(num/2 - 5) var mod = Math.ceil(num/2 - 5)
return num + " (" + (mod >= 0 ? '+'+mod : mod ) + ")" return num + " (" + (mod >= 0 ? '+'+mod : mod ) + ")"
}).join('|') + '|'; }).join('|') + '|';
} }
var genAbilities = function(){ var genAbilities = function(){
return _.sample([ return _.sample([
"> ***Pack Tactics.*** These guys work together. Like super well, you don't even know.", "> ***Pack Tactics.*** These guys work together. Like super well, you don't even know.",
"> ***False Appearance. *** While the armor reamin motionless, it is indistinguishable from a normal suit of armor.", "> ***False Appearance. *** While the armor reamin motionless, it is indistinguishable from a normal suit of armor.",
]); ]);
} }
var genAction = function(){ var genAction = function(){
var name = _.sample([ var name = _.sample([
"Abdominal Drop", "Abdominal Drop",
"Airplane Hammer", "Airplane Hammer",
"Atomic Death Throw", "Atomic Death Throw",
"Bulldog Rake", "Bulldog Rake",
"Corkscrew Strike", "Corkscrew Strike",
"Crossed Splash", "Crossed Splash",
"Crossface Suplex", "Crossface Suplex",
"DDT Powerbomb", "DDT Powerbomb",
"Dual Cobra Wristlock", "Dual Cobra Wristlock",
"Dual Throw", "Dual Throw",
"Elbow Hold", "Elbow Hold",
"Gory Body Sweep", "Gory Body Sweep",
"Heel Jawbreaker", "Heel Jawbreaker",
"Jumping Driver", "Jumping Driver",
"Open Chin Choke", "Open Chin Choke",
"Scorpion Flurry", "Scorpion Flurry",
"Somersault Stump Fists", "Somersault Stump Fists",
"Suffering Wringer", "Suffering Wringer",
"Super Hip Submission", "Super Hip Submission",
"Super Spin", "Super Spin",
"Team Elbow", "Team Elbow",
"Team Foot", "Team Foot",
"Tilt-a-whirl Chin Sleeper", "Tilt-a-whirl Chin Sleeper",
"Tilt-a-whirl Eye Takedown", "Tilt-a-whirl Eye Takedown",
"Turnbuckle Roll" "Turnbuckle Roll"
]) ])
return "> ***" + name + ".*** *Melee Weapon Attack:* +4 to hit, reach 5ft., one target. *Hit* 5 (1d6 + 2) "; return "> ***" + name + ".*** *Melee Weapon Attack:* +4 to hit, reach 5ft., one target. *Hit* 5 (1d6 + 2) ";
} }
module.exports = { module.exports = {
full : function(){ full : function(){
return [ return [
"___", "___",
"___", "___",
"> ## " + getMonsterName(), "> ## " + getMonsterName(),
">*" + getType() + ", " + getAlignment() + "*", ">*" + getType() + ", " + getAlignment() + "*",
"> ___", "> ___",
"> - **Armor Class** " + _.random(10,20), "> - **Armor Class** " + _.random(10,20),
"> - **Hit Points** " + _.random(1, 150) + "(1d4 + 5)", "> - **Hit Points** " + _.random(1, 150) + "(1d4 + 5)",
"> - **Speed** " + _.random(0,50) + "ft.", "> - **Speed** " + _.random(0,50) + "ft.",
">___", ">___",
">|STR|DEX|CON|INT|WIS|CHA|", ">|STR|DEX|CON|INT|WIS|CHA|",
">|:---:|:---:|:---:|:---:|:---:|:---:|", ">|:---:|:---:|:---:|:---:|:---:|:---:|",
getStats(), getStats(),
">___", ">___",
"> - **Condition Immunities** " + genList(["groggy", "swagged", "weak-kneed", "buzzed", "groovy", "melancholy", "drunk"], 3), "> - **Condition Immunities** " + genList(["groggy", "swagged", "weak-kneed", "buzzed", "groovy", "melancholy", "drunk"], 3),
"> - **Senses** passive Perception " + _.random(3, 20), "> - **Senses** passive Perception " + _.random(3, 20),
"> - **Languages** " + genList(["Common", "Pottymouth", "Gibberish", "Latin", "Jive"], 2), "> - **Languages** " + genList(["Common", "Pottymouth", "Gibberish", "Latin", "Jive"], 2),
"> - **Challenge** " + _.random(0, 15) + " (" + _.random(10,10000)+ " XP)", "> - **Challenge** " + _.random(0, 15) + " (" + _.random(10,10000)+ " XP)",
"> ___", "> ___",
_.times(_.random(3,6), function(){ _.times(_.random(3,6), function(){
return genAbilities() return genAbilities()
}).join('\n>\n'), }).join('\n>\n'),
"> ### Actions", "> ### Actions",
_.times(_.random(4,6), function(){ _.times(_.random(4,6), function(){
return genAction() return genAction()
}).join('\n>\n'), }).join('\n>\n'),
].join('\n') + '\n\n\n'; ].join('\n') + '\n\n\n';
}, },
half : function(){ half : function(){
return [ return [
"___", "___",
"> ## " + getMonsterName(), "> ## " + getMonsterName(),
">*" + getType() + ", " + getAlignment() + "*", ">*" + getType() + ", " + getAlignment() + "*",
"> ___", "> ___",
"> - **Armor Class** " + _.random(10,20), "> - **Armor Class** " + _.random(10,20),
"> - **Hit Points** " + _.random(1, 150) + "(1d4 + 5)", "> - **Hit Points** " + _.random(1, 150) + "(1d4 + 5)",
"> - **Speed** " + _.random(0,50) + "ft.", "> - **Speed** " + _.random(0,50) + "ft.",
">___", ">___",
">|STR|DEX|CON|INT|WIS|CHA|", ">|STR|DEX|CON|INT|WIS|CHA|",
">|:---:|:---:|:---:|:---:|:---:|:---:|", ">|:---:|:---:|:---:|:---:|:---:|:---:|",
getStats(), getStats(),
">___", ">___",
"> - **Condition Immunities** " + genList(["groggy", "swagged", "weak-kneed", "buzzed", "groovy", "melancholy", "drunk"], 3), "> - **Condition Immunities** " + genList(["groggy", "swagged", "weak-kneed", "buzzed", "groovy", "melancholy", "drunk"], 3),
"> - **Senses** passive Perception " + _.random(3, 20), "> - **Senses** passive Perception " + _.random(3, 20),
"> - **Languages** " + genList(["Common", "Pottymouth", "Gibberish", "Latin", "Jive"], 2), "> - **Languages** " + genList(["Common", "Pottymouth", "Gibberish", "Latin", "Jive"], 2),
"> - **Challenge** " + _.random(0, 15) + " (" + _.random(10,10000)+ " XP)", "> - **Challenge** " + _.random(0, 15) + " (" + _.random(10,10000)+ " XP)",
"> ___", "> ___",
_.times(_.random(0,2), function(){ _.times(_.random(0,2), function(){
return genAbilities() return genAbilities()
}).join('\n>\n'), }).join('\n>\n'),
"> ### Actions", "> ### Actions",
_.times(_.random(1,2), function(){ _.times(_.random(1,2), function(){
return genAction() return genAction()
}).join('\n>\n'), }).join('\n>\n'),
].join('\n') + '\n\n\n'; ].join('\n') + '\n\n\n';
} }
} }

View File

@@ -1,175 +1,175 @@
var SpellGen = require('./spell.gen.js'); var SpellGen = require('./spell.gen.js');
var ClassTableGen = require('./classtable.gen.js'); var ClassTableGen = require('./classtable.gen.js');
var MonsterBlockGen = require('./monsterblock.gen.js'); var MonsterBlockGen = require('./monsterblock.gen.js');
var ClassFeatureGen = require('./classfeature.gen.js'); var ClassFeatureGen = require('./classfeature.gen.js');
var FullClassGen = require('./fullclass.gen.js'); var FullClassGen = require('./fullclass.gen.js');
module.exports = [ module.exports = [
{ {
groupName : 'Editor', groupName : 'Editor',
icon : 'fa-pencil', icon : 'fa-pencil',
snippets : [ snippets : [
{ {
name : "Column Break", name : "Column Break",
icon : 'fa-columns', icon : 'fa-columns',
gen : "```\n```\n\n" gen : "```\n```\n\n"
}, },
{ {
name : "New Page", name : "New Page",
icon : 'fa-file-text', icon : 'fa-file-text',
gen : "\\page\n\n" gen : "\\page\n\n"
}, },
{ {
name : "Vertical Spacing", name : "Vertical Spacing",
icon : 'fa-arrows-v', icon : 'fa-arrows-v',
gen : "<div style='margin-top:140px'></div>\n\n" gen : "<div style='margin-top:140px'></div>\n\n"
}, },
{ {
name : "Image", name : "Image",
icon : 'fa-image', icon : 'fa-image',
gen : [ gen : [
"<img ", "<img ",
" src='https://s-media-cache-ak0.pinimg.com/736x/4a/81/79/4a8179462cfdf39054a418efd4cb743e.jpg' ", " src='https://s-media-cache-ak0.pinimg.com/736x/4a/81/79/4a8179462cfdf39054a418efd4cb743e.jpg' ",
" style='width:325px' />", " style='width:325px' />",
"Credit: Kyounghwan Kim" "Credit: Kyounghwan Kim"
].join('\n') ].join('\n')
}, },
{ {
name : "Background Image", name : "Background Image",
icon : 'fa-tree', icon : 'fa-tree',
gen : [ gen : [
"<img ", "<img ",
" src='http://i.imgur.com/hMna6G0.png' ", " src='http://i.imgur.com/hMna6G0.png' ",
" style='position:absolute; top:50px; right:30px; width:280px' />" " style='position:absolute; top:50px; right:30px; width:280px' />"
].join('\n') ].join('\n')
}, },
{ {
name : "Page Number", name : "Page Number",
icon : 'fa-bookmark', icon : 'fa-bookmark',
gen : "<div class='pageNumber'>1</div>\n<div class='footnote'>PART 1 | FANCINESS</div>\n\n" gen : "<div class='pageNumber'>1</div>\n<div class='footnote'>PART 1 | FANCINESS</div>\n\n"
}, },
] ]
}, },
/************************* PHB ********************/ /************************* PHB ********************/
{ {
groupName : 'PHB', groupName : 'PHB',
icon : 'fa-book', icon : 'fa-book',
snippets : [ snippets : [
{ {
name : 'Spell', name : 'Spell',
icon : 'fa-magic', icon : 'fa-magic',
gen : SpellGen, gen : SpellGen,
}, },
{ {
name : 'Class Feature', name : 'Class Feature',
icon : 'fa-trophy', icon : 'fa-trophy',
gen : ClassFeatureGen, gen : ClassFeatureGen,
}, },
{ {
name : 'Note', name : 'Note',
icon : 'fa-sticky-note', icon : 'fa-sticky-note',
gen : function(){ gen : function(){
return [ return [
"> ##### Time to Drop Knowledge", "> ##### Time to Drop Knowledge",
"> Use notes to point out some interesting information. ", "> Use notes to point out some interesting information. ",
"> ", "> ",
"> **Tables and lists** both work within a note." "> **Tables and lists** both work within a note."
].join('\n'); ].join('\n');
}, },
}, },
{ {
name : 'Monster Stat Block', name : 'Monster Stat Block',
icon : 'fa-bug', icon : 'fa-bug',
gen : MonsterBlockGen.half, gen : MonsterBlockGen.half,
}, },
{ {
name : 'Wide Monster Stat Block', name : 'Wide Monster Stat Block',
icon : 'fa-paw', icon : 'fa-paw',
gen : MonsterBlockGen.full, gen : MonsterBlockGen.full,
} }
] ]
}, },
/********************* TABLES *********************/ /********************* TABLES *********************/
{ {
groupName : 'Tables', groupName : 'Tables',
icon : 'fa-table', icon : 'fa-table',
snippets : [ snippets : [
{ {
name : "Class Table", name : "Class Table",
icon : 'fa-table', icon : 'fa-table',
gen : ClassTableGen.full, gen : ClassTableGen.full,
}, },
{ {
name : "Half Class Table", name : "Half Class Table",
icon : 'fa-list-alt', icon : 'fa-list-alt',
gen : ClassTableGen.half, gen : ClassTableGen.half,
}, },
{ {
name : 'Table', name : 'Table',
icon : 'fa-th-list', icon : 'fa-th-list',
gen : function(){ gen : function(){
return [ return [
"##### Cookie Tastiness", "##### Cookie Tastiness",
"| Tastiness | Cookie Type |", "| Tastiness | Cookie Type |",
"|:----:|:-------------|", "|:----:|:-------------|",
"| -5 | Raisin |", "| -5 | Raisin |",
"| 8th | Chocolate Chip |", "| 8th | Chocolate Chip |",
"| 11th | 2 or lower |", "| 11th | 2 or lower |",
"| 14th | 3 or lower |", "| 14th | 3 or lower |",
"| 17th | 4 or lower |\n\n", "| 17th | 4 or lower |\n\n",
].join('\n'); ].join('\n');
}, },
} }
] ]
}, },
/**************** PRINT *************/ /**************** PRINT *************/
{ {
groupName : 'Print', groupName : 'Print',
icon : 'fa-print', icon : 'fa-print',
snippets : [ snippets : [
{ {
name : "A4 PageSize", name : "A4 PageSize",
icon : 'fa-file-o', icon : 'fa-file-o',
gen : ['<style>', gen : ['<style>',
' .phb{', ' .phb{',
' width : 210mm;', ' width : 210mm;',
' height : 296.8mm;', ' height : 296.8mm;',
' }', ' }',
'</style>' '</style>'
].join('\n') ].join('\n')
}, },
{ {
name : "Ink Friendly", name : "Ink Friendly",
icon : 'fa-tint', icon : 'fa-tint',
gen : ['<style>', gen : ['<style>',
' .phb{ background : white;}', ' .phb{ background : white;}',
' .phb img{ display : none;}', ' .phb img{ display : none;}',
' .phb hr+blockquote{background : white;}', ' .phb hr+blockquote{background : white;}',
'</style>', '</style>',
'' ''
].join('\n') ].join('\n')
}, },
] ]
}, },
] ]

View File

@@ -1,78 +1,78 @@
var _ = require('lodash'); var _ = require('lodash');
module.exports = function(){ module.exports = function(){
var spellNames = [ var spellNames = [
"Astral Rite of Acne", "Astral Rite of Acne",
"Create Acne", "Create Acne",
"Cursed Ramen Erruption", "Cursed Ramen Erruption",
"Dark Chant of the Dentists", "Dark Chant of the Dentists",
"Erruption of Immaturity", "Erruption of Immaturity",
"Flaming Disc of Inconvenience", "Flaming Disc of Inconvenience",
"Heal Bad Hygene", "Heal Bad Hygene",
"Heavenly Transfiguration of the Cream Devil", "Heavenly Transfiguration of the Cream Devil",
"Hellish Cage of Mucus", "Hellish Cage of Mucus",
"Irritate Peanut Butter Fairy", "Irritate Peanut Butter Fairy",
"Luminous Erruption of Tea", "Luminous Erruption of Tea",
"Mystic Spell of the Poser", "Mystic Spell of the Poser",
"Sorcerous Enchantment of the Chimneysweep", "Sorcerous Enchantment of the Chimneysweep",
"Steak Sauce Ray", "Steak Sauce Ray",
"Talk to Groupie", "Talk to Groupie",
"Astonishing Chant of Chocolate", "Astonishing Chant of Chocolate",
"Astounding Pasta Puddle", "Astounding Pasta Puddle",
"Ball of Annoyance", "Ball of Annoyance",
"Cage of Yarn", "Cage of Yarn",
"Control Noodles Elemental", "Control Noodles Elemental",
"Create Nervousness", "Create Nervousness",
"Cure Baldness", "Cure Baldness",
"Cursed Ritual of Bad Hair", "Cursed Ritual of Bad Hair",
"Dispell Piles in Dentist", "Dispell Piles in Dentist",
"Eliminate Florists", "Eliminate Florists",
"Illusionary Transfiguration of the Babysitter", "Illusionary Transfiguration of the Babysitter",
"Necromantic Armor of Salad Dressing", "Necromantic Armor of Salad Dressing",
"Occult Transfiguration of Foot Fetish", "Occult Transfiguration of Foot Fetish",
"Protection from Mucus Giant", "Protection from Mucus Giant",
"Tinsel Blast", "Tinsel Blast",
"Alchemical Evocation of the Goths", "Alchemical Evocation of the Goths",
"Call Fangirl", "Call Fangirl",
"Divine Spell of Crossdressing", "Divine Spell of Crossdressing",
"Dominate Ramen Giant", "Dominate Ramen Giant",
"Eliminate Vindictiveness in Gym Teacher", "Eliminate Vindictiveness in Gym Teacher",
"Extra-Planar Spell of Irritation", "Extra-Planar Spell of Irritation",
"Induce Whining in Babysitter", "Induce Whining in Babysitter",
"Invoke Complaining", "Invoke Complaining",
"Magical Enchantment of Arrogance", "Magical Enchantment of Arrogance",
"Occult Globe of Salad Dressing", "Occult Globe of Salad Dressing",
"Overwhelming Enchantment of the Chocolate Fairy", "Overwhelming Enchantment of the Chocolate Fairy",
"Sorcerous Dandruff Globe", "Sorcerous Dandruff Globe",
"Spiritual Invocation of the Costumers", "Spiritual Invocation of the Costumers",
"Ultimate Rite of the Confetti Angel", "Ultimate Rite of the Confetti Angel",
"Ultimate Ritual of Mouthwash", "Ultimate Ritual of Mouthwash",
]; ];
var level = ["1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th"]; var level = ["1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th"];
var spellSchools = ["abjuration", "conjuration", "divination", "enchantment", "evocation", "illusion", "necromancy", "transmutation"]; var spellSchools = ["abjuration", "conjuration", "divination", "enchantment", "evocation", "illusion", "necromancy", "transmutation"];
var components = _.sampleSize(["V", "S", "M"], _.random(1,3)).join(', '); var components = _.sampleSize(["V", "S", "M"], _.random(1,3)).join(', ');
if(components.indexOf("M") !== -1){ if(components.indexOf("M") !== -1){
components += " (" + _.sampleSize(['a small doll', 'a crushed button worth at least 1cp', 'discarded gum wrapper'], _.random(1,3)).join(', ') + ")" components += " (" + _.sampleSize(['a small doll', 'a crushed button worth at least 1cp', 'discarded gum wrapper'], _.random(1,3)).join(', ') + ")"
} }
return [ return [
"#### " + _.sample(spellNames), "#### " + _.sample(spellNames),
"*" + _.sample(level) + "-level " + _.sample(spellSchools) + "*", "*" + _.sample(level) + "-level " + _.sample(spellSchools) + "*",
"___", "___",
"- **Casting Time:** 1 action", "- **Casting Time:** 1 action",
"- **Range:** " + _.sample(["Self", "Touch", "30 feet", "60 feet"]), "- **Range:** " + _.sample(["Self", "Touch", "30 feet", "60 feet"]),
"- **Components:** " + components, "- **Components:** " + components,
"- **Duration:** " + _.sample(["Until dispelled", "1 round", "Instantaneous", "Concentration, up to 10 minutes", "1 hour"]), "- **Duration:** " + _.sample(["Until dispelled", "1 round", "Instantaneous", "Concentration, up to 10 minutes", "1 hour"]),
"", "",
"A flame, equivalent in brightness to a torch, springs from from an object that you touch. ", "A flame, equivalent in brightness to a torch, springs from from an object that you touch. ",
"The effect look like a regular flame, but it creates no heat and doesn't use oxygen. ", "The effect look like a regular flame, but it creates no heat and doesn't use oxygen. ",
"A *continual flame* can be covered or hidden but not smothered or quenched.", "A *continual flame* can be covered or hidden but not smothered or quenched.",
"\n\n\n" "\n\n\n"
].join('\n'); ].join('\n');
} }

View File

@@ -1,56 +1,56 @@
var React = require('react'); var React = require('react');
var _ = require('lodash'); var _ = require('lodash');
var cx = require('classnames'); var cx = require('classnames');
var CreateRouter = require('pico-router').createRouter; var CreateRouter = require('pico-router').createRouter;
var HomePage = require('./pages/homePage/homePage.jsx'); var HomePage = require('./pages/homePage/homePage.jsx');
var EditPage = require('./pages/editPage/editPage.jsx'); var EditPage = require('./pages/editPage/editPage.jsx');
var SharePage = require('./pages/sharePage/sharePage.jsx'); var SharePage = require('./pages/sharePage/sharePage.jsx');
var NewPage = require('./pages/newPage/newPage.jsx'); var NewPage = require('./pages/newPage/newPage.jsx');
var Router; var Router;
var Homebrew = React.createClass({ var Homebrew = React.createClass({
getDefaultProps: function() { getDefaultProps: function() {
return { return {
url : "", url : "",
welcomeText : "", welcomeText : "",
changelog : "", changelog : "",
brew : { brew : {
title : '', title : '',
text : '', text : '',
shareId : null, shareId : null,
editId : null, editId : null,
createdAt : null, createdAt : null,
updatedAt : null, updatedAt : null,
} }
}; };
}, },
componentWillMount: function() { componentWillMount: function() {
Router = CreateRouter({ Router = CreateRouter({
'/homebrew/edit/:id' : (args) => { '/homebrew/edit/:id' : (args) => {
return <EditPage id={args.id} brew={this.props.brew} /> return <EditPage id={args.id} brew={this.props.brew} />
}, },
'/homebrew/share/:id' : (args) => { '/homebrew/share/:id' : (args) => {
return <SharePage id={args.id} brew={this.props.brew} /> return <SharePage id={args.id} brew={this.props.brew} />
}, },
'/homebrew/changelog' : (args) => { '/homebrew/changelog' : (args) => {
return <SharePage brew={{title : 'Changelog', text : this.props.changelog}} /> return <SharePage brew={{title : 'Changelog', text : this.props.changelog}} />
}, },
'/homebrew/new' : (args) => { '/homebrew/new' : (args) => {
return <NewPage /> return <NewPage />
}, },
'/homebrew*' : <HomePage welcomeText={this.props.welcomeText} />, '/homebrew*' : <HomePage welcomeText={this.props.welcomeText} />,
}); });
}, },
render : function(){ render : function(){
return( return(
<div className='homebrew'> <div className='homebrew'>
<Router initialUrl={this.props.url}/> <Router initialUrl={this.props.url}/>
</div> </div>
); );
} }
}); });
module.exports = Homebrew; module.exports = Homebrew;

View File

@@ -1,17 +1,17 @@
@import 'naturalcrit/styles/core.less'; @import 'naturalcrit/styles/core.less';
.homebrew{ .homebrew{
height : 100%; height : 100%;
//TODO: Consider making backgroudn color lighter //TODO: Consider making backgroudn color lighter
background-color : @steel; background-color : @steel;
.page{ .page{
display : flex; display : flex;
height : 100%; height : 100%;
flex-direction : column; flex-direction : column;
.content{ .content{
position : relative; position : relative;
height : calc(~"100% - 29px"); //Navbar height height : calc(~"100% - 29px"); //Navbar height
flex : auto; flex : auto;
} }
} }
} }

View File

@@ -1,33 +1,33 @@
var React = require('react'); var React = require('react');
var _ = require('lodash'); var _ = require('lodash');
var cx = require('classnames'); var cx = require('classnames');
var Nav = require('naturalcrit/nav/nav.jsx'); var Nav = require('naturalcrit/nav/nav.jsx');
const MAX_TITLE_LENGTH = 50; const MAX_TITLE_LENGTH = 50;
var EditTitle = React.createClass({ var EditTitle = React.createClass({
getDefaultProps: function() { getDefaultProps: function() {
return { return {
title : '', title : '',
onChange : function(){} onChange : function(){}
}; };
}, },
handleChange : function(e){ handleChange : function(e){
if(e.target.value.length > MAX_TITLE_LENGTH) return; if(e.target.value.length > MAX_TITLE_LENGTH) return;
this.props.onChange(e.target.value); this.props.onChange(e.target.value);
}, },
render : function(){ render : function(){
return <Nav.item className='editTitle'> return <Nav.item className='editTitle'>
<input placeholder='Brew Title' type='text' value={this.props.title} onChange={this.handleChange} /> <input placeholder='Brew Title' type='text' value={this.props.title} onChange={this.handleChange} />
<div className={cx('charCount', {'max' : this.props.title.length >= MAX_TITLE_LENGTH})}> <div className={cx('charCount', {'max' : this.props.title.length >= MAX_TITLE_LENGTH})}>
{this.props.title.length}/{MAX_TITLE_LENGTH} {this.props.title.length}/{MAX_TITLE_LENGTH}
</div> </div>
</Nav.item> </Nav.item>
}, },
}); });
module.exports = EditTitle; module.exports = EditTitle;

View File

@@ -1,8 +1,8 @@
var React = require('react'); var React = require('react');
var Nav = require('naturalcrit/nav/nav.jsx'); var Nav = require('naturalcrit/nav/nav.jsx');
module.exports = function(props){ module.exports = function(props){
return <Nav.item newTab={true} href='https://github.com/stolksdorf/naturalcrit/issues' color='red' icon='fa-bug'> return <Nav.item newTab={true} href='https://github.com/stolksdorf/naturalcrit/issues' color='red' icon='fa-bug'>
report issue report issue
</Nav.item> </Nav.item>
}; };

View File

@@ -1,58 +1,58 @@
.homebrew nav{ .homebrew nav{
.homebrewLogo{ .homebrewLogo{
.animate(color); .animate(color);
font-family : CodeBold; font-family : CodeBold;
font-size : 12px; font-size : 12px;
color : white; color : white;
div{ div{
margin-top : 2px; margin-top : 2px;
margin-bottom : -2px; margin-bottom : -2px;
} }
&:hover{ &:hover{
color : @blue; color : @blue;
} }
} }
.editTitle.navItem{ .editTitle.navItem{
padding : 2px 12px; padding : 2px 12px;
input{ input{
margin : 0; margin : 0;
padding : 2px; padding : 2px;
width : 250px; width : 250px;
background-color : #444; background-color : #444;
font-family : 'Open Sans', sans-serif; font-family : 'Open Sans', sans-serif;
font-size : 12px; font-size : 12px;
font-weight : 800; font-weight : 800;
color : white; color : white;
text-align : center; text-align : center;
border : 1px solid @blue; border : 1px solid @blue;
outline : none; outline : none;
} }
.charCount{ .charCount{
display : inline-block; display : inline-block;
vertical-align : bottom; vertical-align : bottom;
margin-left : 8px; margin-left : 8px;
text-align : right; text-align : right;
color : #666; color : #666;
&.max{ &.max{
color : @red; color : @red;
} }
} }
} }
.brewTitle.navItem{ .brewTitle.navItem{
font-size : 12px; font-size : 12px;
font-weight : 800; font-weight : 800;
color : white; color : white;
text-align : center; text-align : center;
text-transform: initial; text-transform: initial;
} }
.patreon.navItem{ .patreon.navItem{
i{ i{
.animate(color); .animate(color);
&:hover{ &:hover{
color : @red; color : @red;
} }
} }
} }
} }

View File

@@ -1,13 +1,13 @@
var React = require('react'); var React = require('react');
var Nav = require('naturalcrit/nav/nav.jsx'); var Nav = require('naturalcrit/nav/nav.jsx');
module.exports = function(props){ module.exports = function(props){
return <Nav.item return <Nav.item
className='patreon' className='patreon'
newTab={true} newTab={true}
href='https://www.patreon.com/stolksdorf' href='https://www.patreon.com/stolksdorf'
color='green' color='green'
icon='fa-heart'> icon='fa-heart'>
help out help out
</Nav.item> </Nav.item>
}; };

View File

@@ -1,8 +1,8 @@
var React = require('react'); var React = require('react');
var Nav = require('naturalcrit/nav/nav.jsx'); var Nav = require('naturalcrit/nav/nav.jsx');
module.exports = function(props){ module.exports = function(props){
return <Nav.item newTab={true} href={'/homebrew/print/' + props.shareId +'?dialog=true'} color='purple' icon='fa-print'> return <Nav.item newTab={true} href={'/homebrew/print/' + props.shareId +'?dialog=true'} color='purple' icon='fa-print'>
print print
</Nav.item> </Nav.item>
}; };

View File

@@ -1,51 +1,51 @@
var React = require('react'); var React = require('react');
var _ = require('lodash'); var _ = require('lodash');
var cx = require('classnames'); var cx = require('classnames');
//var striptags = require('striptags'); //var striptags = require('striptags');
var Nav = require('naturalcrit/nav/nav.jsx'); var Nav = require('naturalcrit/nav/nav.jsx');
const MAX_URL_SIZE = 2083; const MAX_URL_SIZE = 2083;
const MAIN_URL = "https://www.reddit.com/r/UnearthedArcana/submit?selftext=true" const MAIN_URL = "https://www.reddit.com/r/UnearthedArcana/submit?selftext=true"
var RedditShare = React.createClass({ var RedditShare = React.createClass({
getDefaultProps: function() { getDefaultProps: function() {
return { return {
brew : { brew : {
title : '', title : '',
sharedId : '', sharedId : '',
text : '' text : ''
} }
}; };
}, },
getText : function(){ getText : function(){
}, },
handleClick : function(){ handleClick : function(){
var url = [ var url = [
MAIN_URL, MAIN_URL,
'title=' + encodeURIComponent(this.props.brew.title ? this.props.brew.title : 'Check out my brew!'), 'title=' + encodeURIComponent(this.props.brew.title ? this.props.brew.title : 'Check out my brew!'),
'text=' + encodeURIComponent(this.props.brew.text) 'text=' + encodeURIComponent(this.props.brew.text)
].join('&'); ].join('&');
window.open(url, '_blank'); window.open(url, '_blank');
}, },
render : function(){ render : function(){
return <Nav.item icon='fa-reddit-alien' color='red' onClick={this.handleClick}> return <Nav.item icon='fa-reddit-alien' color='red' onClick={this.handleClick}>
share on reddit share on reddit
</Nav.item> </Nav.item>
}, },
}); });
module.exports = RedditShare; module.exports = RedditShare;

View File

@@ -1,27 +1,27 @@
.editPage{ .editPage{
.navItem.save{ .navItem.save{
width : 75px; width : 75px;
text-align : center; text-align : center;
&.saved{ &.saved{
cursor : initial; cursor : initial;
color : #666; color : #666;
} }
&.error{ &.error{
position : relative; position : relative;
background-color : @red; background-color : @red;
.errorContainer{ .errorContainer{
position : absolute; position : absolute;
top : 29px; top : 29px;
left : -20px; left : -20px;
z-index : 1000; z-index : 1000;
width : 120px; width : 120px;
padding : 8px; padding : 8px;
background-color : #333; background-color : #333;
a{ a{
color : @teal; color : @teal;
} }
} }
} }
} }
} }

View File

@@ -1,130 +1,130 @@
var React = require('react'); var React = require('react');
var _ = require('lodash'); var _ = require('lodash');
var cx = require('classnames'); var cx = require('classnames');
var request = require("superagent"); var request = require("superagent");
var Nav = require('naturalcrit/nav/nav.jsx'); var Nav = require('naturalcrit/nav/nav.jsx');
var Navbar = require('../../navbar/navbar.jsx'); var Navbar = require('../../navbar/navbar.jsx');
var EditTitle = require('../../navbar/editTitle.navitem.jsx'); var EditTitle = require('../../navbar/editTitle.navitem.jsx');
var SplitPane = require('naturalcrit/splitPane/splitPane.jsx'); var SplitPane = require('naturalcrit/splitPane/splitPane.jsx');
var Editor = require('../../editor/editor.jsx'); var Editor = require('../../editor/editor.jsx');
var BrewRenderer = require('../../brewRenderer/brewRenderer.jsx'); var BrewRenderer = require('../../brewRenderer/brewRenderer.jsx');
const KEY = 'naturalCrit-homebrew-new'; const KEY = 'naturalCrit-homebrew-new';
var NewPage = React.createClass({ var NewPage = React.createClass({
getInitialState: function() { getInitialState: function() {
return { return {
title : 'My Awesome Brew v99', title : 'My Awesome Brew v99',
text: '', text: '',
isSaving : false isSaving : false
}; };
}, },
componentDidMount: function() { componentDidMount: function() {
var storage = localStorage.getItem(KEY); var storage = localStorage.getItem(KEY);
if(storage){ if(storage){
this.setState({ this.setState({
text : storage text : storage
}) })
} }
window.onbeforeunload = (e)=>{ window.onbeforeunload = (e)=>{
if(this.state.text == '') return; if(this.state.text == '') return;
return "Your homebrew isn't saved. Are you sure you want to leave?"; return "Your homebrew isn't saved. Are you sure you want to leave?";
}; };
}, },
componentWillUnmount: function() { componentWillUnmount: function() {
window.onbeforeunload = function(){}; window.onbeforeunload = function(){};
}, },
handleSplitMove : function(){ handleSplitMove : function(){
this.refs.editor.update(); this.refs.editor.update();
}, },
handleTitleChange : function(title){ handleTitleChange : function(title){
this.setState({ this.setState({
title : title title : title
}); });
}, },
handleTextChange : function(text){ handleTextChange : function(text){
this.setState({ this.setState({
text : text text : text
}); });
localStorage.setItem(KEY, text); localStorage.setItem(KEY, text);
}, },
handleSave : function(){ handleSave : function(){
this.setState({ this.setState({
isSaving : true isSaving : true
}); });
request.post('/homebrew/api') request.post('/homebrew/api')
.send({ .send({
title : this.state.title, title : this.state.title,
text : this.state.text text : this.state.text
}) })
.end((err, res)=>{ .end((err, res)=>{
if(err){ if(err){
this.setState({ this.setState({
isSaving : false isSaving : false
}); });
return; return;
} }
window.onbeforeunload = function(){}; window.onbeforeunload = function(){};
var brew = res.body; var brew = res.body;
localStorage.removeItem(KEY); localStorage.removeItem(KEY);
window.location = '/homebrew/edit/' + brew.editId; window.location = '/homebrew/edit/' + brew.editId;
}) })
}, },
renderSaveButton : function(){ renderSaveButton : function(){
if(this.state.isSaving){ if(this.state.isSaving){
return <Nav.item icon='fa-spinner fa-spin' className='saveButton'> return <Nav.item icon='fa-spinner fa-spin' className='saveButton'>
save... save...
</Nav.item> </Nav.item>
}else{ }else{
return <Nav.item icon='fa-save' className='saveButton' onClick={this.handleSave}> return <Nav.item icon='fa-save' className='saveButton' onClick={this.handleSave}>
save save
</Nav.item> </Nav.item>
} }
}, },
renderNavbar : function(){ renderNavbar : function(){
return <Navbar> return <Navbar>
<Nav.section> <Nav.section>
<EditTitle title={this.state.title} onChange={this.handleTitleChange} /> <EditTitle title={this.state.title} onChange={this.handleTitleChange} />
</Nav.section> </Nav.section>
<Nav.section> <Nav.section>
{this.renderSaveButton()} {this.renderSaveButton()}
<Nav.item newTab={true} href='https://github.com/stolksdorf/naturalcrit/issues' color='red' icon='fa-bug'> <Nav.item newTab={true} href='https://github.com/stolksdorf/naturalcrit/issues' color='red' icon='fa-bug'>
report issue report issue
</Nav.item> </Nav.item>
</Nav.section> </Nav.section>
</Navbar> </Navbar>
}, },
render : function(){ render : function(){
return <div className='newPage page'> return <div className='newPage page'>
{this.renderNavbar()} {this.renderNavbar()}
<div className='content'> <div className='content'>
<SplitPane onDragFinish={this.handleSplitMove} ref='pane'> <SplitPane onDragFinish={this.handleSplitMove} ref='pane'>
<Editor value={this.state.text} onChange={this.handleTextChange} ref='editor'/> <Editor value={this.state.text} onChange={this.handleTextChange} ref='editor'/>
<BrewRenderer text={this.state.text} /> <BrewRenderer text={this.state.text} />
</SplitPane> </SplitPane>
</div> </div>
</div> </div>
} }
}); });
module.exports = NewPage; module.exports = NewPage;

View File

@@ -1,10 +1,10 @@
.newPage{ .newPage{
.saveButton{ .saveButton{
background-color: @orange; background-color: @orange;
&:hover{ &:hover{
background-color: @green; background-color: @green;
} }
} }
} }

View File

@@ -1,3 +1,3 @@
.sharePage{ .sharePage{
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,86 +1,86 @@
var React = require('react'); var React = require('react');
var _ = require('lodash'); var _ = require('lodash');
var cx = require('classnames'); var cx = require('classnames');
var Router = require('pico-router'); var Router = require('pico-router');
var NaturalCritIcon = require('naturalcrit/svg/naturalcrit.svg.jsx'); var NaturalCritIcon = require('naturalcrit/svg/naturalcrit.svg.jsx');
var HomebrewIcon = require('naturalcrit/svg/homebrew.svg.jsx'); var HomebrewIcon = require('naturalcrit/svg/homebrew.svg.jsx');
var Main = React.createClass({ var Main = React.createClass({
getDefaultProps: function() { getDefaultProps: function() {
return { return {
tools : [ tools : [
{ {
id : 'homebrew', id : 'homebrew',
path : '/homebrew', path : '/homebrew',
name : 'The Homebrewery', name : 'The Homebrewery',
icon : <HomebrewIcon />, icon : <HomebrewIcon />,
desc : 'Make authentic-looking 5e homebrews using Markdown', desc : 'Make authentic-looking 5e homebrews using Markdown',
show : true, show : true,
beta : false beta : false
}, },
{ {
id : 'homebrew2', id : 'homebrew2',
path : '/homebrew', path : '/homebrew',
name : 'The Homebrewery', name : 'The Homebrewery',
icon : <HomebrewIcon />, icon : <HomebrewIcon />,
desc : 'Make authentic-looking 5e homebrews using Markdown', desc : 'Make authentic-looking 5e homebrews using Markdown',
show : false, show : false,
beta : true beta : true
}, },
{ {
id : 'homebrewfg2', id : 'homebrewfg2',
path : '/homebrew', path : '/homebrew',
name : 'The Homebrewery', name : 'The Homebrewery',
icon : <HomebrewIcon />, icon : <HomebrewIcon />,
desc : 'Make authentic-looking 5e homebrews using Markdown', desc : 'Make authentic-looking 5e homebrews using Markdown',
show : false, show : false,
beta : false beta : false
} }
] ]
}; };
}, },
renderTool : function(tool){ renderTool : function(tool){
if(!tool.show) return null; if(!tool.show) return null;
return <a href={tool.path} className={cx('tool', tool.id, {beta : tool.beta})} key={tool.id}> return <a href={tool.path} className={cx('tool', tool.id, {beta : tool.beta})} key={tool.id}>
<div className='content'> <div className='content'>
{tool.icon} {tool.icon}
<h2>{tool.name}</h2> <h2>{tool.name}</h2>
<p>{tool.desc}</p> <p>{tool.desc}</p>
</div> </div>
</a>; </a>;
}, },
renderTools : function(){ renderTools : function(){
return _.map(this.props.tools, (tool)=>{ return _.map(this.props.tools, (tool)=>{
return this.renderTool(tool); return this.renderTool(tool);
}); });
}, },
render : function(){ render : function(){
return <div className='main'> return <div className='main'>
<div className='top'> <div className='top'>
<div className='logo'> <div className='logo'>
<NaturalCritIcon /> <NaturalCritIcon />
<span className='name'> <span className='name'>
Natural Natural
<span className='crit'>Crit</span> <span className='crit'>Crit</span>
</span> </span>
</div> </div>
<p>Top-tier tools for the discerning DM</p> <p>Top-tier tools for the discerning DM</p>
</div> </div>
<div className='tools'> <div className='tools'>
{this.renderTools()} {this.renderTools()}
</div> </div>
</div> </div>
} }
}); });
module.exports = Main; module.exports = Main;

View File

@@ -1,136 +1,136 @@
@import 'naturalcrit/styles/core.less'; @import 'naturalcrit/styles/core.less';
.main{ .main{
height : 100vh; height : 100vh;
background-color : white; background-color : white;
.top{ .top{
.fadeInTop(1s); .fadeInTop(1s);
.delay(0.5); .delay(0.5);
margin-bottom : 100px; margin-bottom : 100px;
padding-top : 100px; padding-top : 100px;
text-align : center; text-align : center;
.logo{ .logo{
font-size : 4em; font-size : 4em;
color : black; color : black;
svg{ svg{
height : .9em; height : .9em;
margin-right : .2em; margin-right : .2em;
cursor : pointer; cursor : pointer;
fill : black; fill : black;
} }
.name{ .name{
font-family : 'CodeLight'; font-family : 'CodeLight';
.crit{ .crit{
font-family : 'CodeBold'; font-family : 'CodeBold';
} }
} }
} }
p{ p{
margin-top : 10px; margin-top : 10px;
font-size : 1.3em; font-size : 1.3em;
font-style : italic; font-style : italic;
color : @grey; color : @grey;
} }
} }
.tools{ .tools{
width : 100%; width : 100%;
text-align : center; text-align : center;
.tool{ .tool{
.sequentialDelay(0.5s, 1s); .sequentialDelay(0.5s, 1s);
.fadeInDown(1s); .fadeInDown(1s);
.keep(); .keep();
display : inline-block; display : inline-block;
cursor : pointer; cursor : pointer;
opacity : 0; opacity : 0;
color : black; color : black;
text-align : center; text-align : center;
text-decoration : none; text-decoration : none;
&+.tool{ &+.tool{
border-left : 1px solid #666; border-left : 1px solid #666;
} }
.content{ .content{
.addSketch(360px); .addSketch(360px);
.animateAll(0.5s); .animateAll(0.5s);
position : relative; position : relative;
width : 320px; width : 320px;
padding : 35px; padding : 35px;
&:hover{ &:hover{
svg, h2{ svg, h2{
.transform(scale(1.3)); .transform(scale(1.3));
} }
} }
h2{ h2{
.animateAll(0.5s); .animateAll(0.5s);
font-family : 'CodeBold'; font-family : 'CodeBold';
font-size : 2em; font-size : 2em;
} }
p{ p{
max-width : 300px; max-width : 300px;
margin : 20px auto; margin : 20px auto;
line-height : 1.5em; line-height : 1.5em;
} }
svg{ svg{
.animateAll(0.5s); .animateAll(0.5s);
height : 10em; height : 10em;
} }
} }
.content:hover{ .content:hover{
background-color : fade(@teal, 20%); background-color : fade(@teal, 20%);
} }
//Beta styles //Beta styles
&.beta{ &.beta{
cursor : initial; cursor : initial;
.content{ .content{
&:hover{ &:hover{
svg, h2{ svg, h2{
.transform(scale(1.0)); .transform(scale(1.0));
} }
} }
svg, h2{ svg, h2{
opacity : 0.3; opacity : 0.3;
} }
&:after{ &:after{
.animateAll(); .animateAll();
content : "beta!"; content : "beta!";
position : absolute; position : absolute;
display : block; display : block;
top : 120px; top : 120px;
left : 0px; left : 0px;
width : 100%; width : 100%;
padding : 10px 0px; padding : 10px 0px;
//opacity : 0; //opacity : 0;
background-color : fade(@grey, 50%); background-color : fade(@grey, 50%);
font-size : 2em; font-size : 2em;
font-weight : 800; font-weight : 800;
text-align : center; text-align : center;
text-transform : uppercase; text-transform : uppercase;
} }
} }
} }
} }
} }
} }
.addSketch(@length, @color : black){ .addSketch(@length, @color : black){
path, line, polyline, circle, rect, polygon { path, line, polyline, circle, rect, polygon {
.sketch(@length, @color, 4s); .sketch(@length, @color, 4s);
stroke-dasharray : @length; stroke-dasharray : @length;
stroke-dashoffset : 0px; stroke-dashoffset : 0px;
stroke : @color; stroke : @color;
stroke-width : 0.5px; stroke-width : 0.5px;
fill : @color; fill : @color;
//.animateAll(3s); //.animateAll(3s);
} }
} }
.sketch(@length, @color : black, @duration : 3s, @easing : @defaultEasing){ .sketch(@length, @color : black, @duration : 3s, @easing : @defaultEasing){
.createAnimation(sketch, @duration, @easing); .createAnimation(sketch, @duration, @easing);
.sketchKeyFrames(){ .sketchKeyFrames(){
0% { stroke-dashoffset : @length; fill: transparent;} 0% { stroke-dashoffset : @length; fill: transparent;}
50% { stroke-dashoffset : @length; fill: transparent;} 50% { stroke-dashoffset : @length; fill: transparent;}
80% { stroke-dashoffset : 0px; fill: transparent;} 80% { stroke-dashoffset : 0px; fill: transparent;}
100% { stroke-dashoffset : 0px; fill:@color;} 100% { stroke-dashoffset : 0px; fill:@color;}
} }
@-webkit-keyframes sketch {.sketchKeyFrames();} @-webkit-keyframes sketch {.sketchKeyFrames();}
@-moz-keyframes sketch {.sketchKeyFrames();} @-moz-keyframes sketch {.sketchKeyFrames();}
@-ms-keyframes sketch {.sketchKeyFrames();} @-ms-keyframes sketch {.sketchKeyFrames();}
@-o-keyframes sketch {.sketchKeyFrames();} @-o-keyframes sketch {.sketchKeyFrames();}
@keyframes sketch {.sketchKeyFrames();} @keyframes sketch {.sketchKeyFrames();}
} }

View File

@@ -1,30 +1,30 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<script>global=window</script> <script>global=window</script>
<link href="//netdna.bootstrapcdn.com/font-awesome/4.6.2/css/font-awesome.min.css" rel="stylesheet" /> <link href="//netdna.bootstrapcdn.com/font-awesome/4.6.2/css/font-awesome.min.css" rel="stylesheet" />
<link href="//fonts.googleapis.com/css?family=Open+Sans:400,300,600,700" rel="stylesheet" type="text/css" /> <link href="//fonts.googleapis.com/css?family=Open+Sans:400,300,600,700" rel="stylesheet" type="text/css" />
<link rel="icon" href="/assets/main/favicon.ico" type="image/x-icon" /> <link rel="icon" href="/assets/main/favicon.ico" type="image/x-icon" />
{{=vitreum.css}} {{=vitreum.css}}
{{=vitreum.globals}} {{=vitreum.globals}}
<title>Natural Crit - D&D Tools</title> <title>Natural Crit - D&D Tools</title>
</head> </head>
<body> <body>
<div id="reactContainer">{{=vitreum.component}}</div> <div id="reactContainer">{{=vitreum.component}}</div>
</body> </body>
{{=vitreum.libs}} {{=vitreum.libs}}
{{=vitreum.js}} {{=vitreum.js}}
{{=vitreum.reactRender}} {{=vitreum.reactRender}}
{{? vitreum.inProduction}} {{? vitreum.inProduction}}
<script> <script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','http://www.google-analytics.com/analytics.js','ga'); })(window,document,'script','http://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-72212009-1', 'auto'); ga('create', 'UA-72212009-1', 'auto');
ga('send', 'pageview'); ga('send', 'pageview');
</script> </script>
{{?}} {{?}}
</html> </html>

View File

@@ -1,51 +1,51 @@
"use strict"; "use strict";
var vitreumTasks = require("vitreum/tasks"); var vitreumTasks = require("vitreum/tasks");
var gulp = require("gulp"); var gulp = require("gulp");
var gulp = vitreumTasks(gulp, { var gulp = vitreumTasks(gulp, {
entryPoints: [ entryPoints: [
'./client/main', './client/main',
'./client/homebrew', './client/homebrew',
'./client/admin' './client/admin'
], ],
DEV: true, DEV: true,
buildPath: "./build/", buildPath: "./build/",
pageTemplate: "./client/template.dot", pageTemplate: "./client/template.dot",
projectModules: ["./shared/naturalcrit","./shared/codemirror"], projectModules: ["./shared/naturalcrit","./shared/codemirror"],
additionalRequirePaths : ['./shared', './node_modules'], additionalRequirePaths : ['./shared', './node_modules'],
assetExts: ["*.svg", "*.png", "*.jpg", "*.pdf", "*.eot", "*.otf", "*.woff", "*.woff2", "*.ico", "*.ttf"], assetExts: ["*.svg", "*.png", "*.jpg", "*.pdf", "*.eot", "*.otf", "*.woff", "*.woff2", "*.ico", "*.ttf"],
serverWatchPaths: ["server"], serverWatchPaths: ["server"],
serverScript: "server.js", serverScript: "server.js",
libs: [ libs: [
"react", "react",
"react-dom", "react-dom",
"lodash", "lodash",
"classnames", "classnames",
//From ./shared //From ./shared
"codemirror", "codemirror",
"codemirror/mode/gfm/gfm.js", "codemirror/mode/gfm/gfm.js",
'codemirror/mode/javascript/javascript.js', 'codemirror/mode/javascript/javascript.js',
"moment", "moment",
"superagent", "superagent",
"marked", "marked",
"pico-router", "pico-router",
"pico-flux" "pico-flux"
], ],
clientLibs: [], clientLibs: [],
}); });
var rename = require('gulp-rename'); var rename = require('gulp-rename');
var less = require('gulp-less'); var less = require('gulp-less');
gulp.task('phb', function(){ gulp.task('phb', function(){
gulp.src('./client/homebrew/phbStyle/phb.style.less') gulp.src('./client/homebrew/phbStyle/phb.style.less')
.pipe(less()) .pipe(less())
.pipe(rename('phb.standalone.css')) .pipe(rename('phb.standalone.css'))
.pipe(gulp.dest('./')); .pipe(gulp.dest('./'));
}) })

View File

@@ -1,7 +1,7 @@
{ {
"name": "naturalcrit", "name": "naturalcrit",
"description": "D&D Tools for the discerning DM", "description": "D&D Tools for the discerning DM",
"version": "2.0.6", "version": "2.1.0",
"scripts": { "scripts": {
"postinstall": "gulp prod", "postinstall": "gulp prod",
"start": "node server.js" "start": "node server.js"

132
server.js
View File

@@ -1,67 +1,67 @@
'use strict'; 'use strict';
var _ = require('lodash'); var _ = require('lodash');
require('app-module-path').addPath('./shared'); require('app-module-path').addPath('./shared');
var vitreumRender = require('vitreum/render'); var vitreumRender = require('vitreum/render');
var bodyParser = require('body-parser') var bodyParser = require('body-parser')
var express = require("express"); var express = require("express");
var app = express(); var app = express();
app.use(express.static(__dirname + '/build')); app.use(express.static(__dirname + '/build'));
app.use(bodyParser.json({limit: '25mb'})); app.use(bodyParser.json({limit: '25mb'}));
//Mongoose //Mongoose
var mongoose = require('mongoose'); var mongoose = require('mongoose');
var mongoUri = process.env.MONGOLAB_URI || process.env.MONGOHQ_URL || 'mongodb://localhost/naturalcrit'; var mongoUri = process.env.MONGOLAB_URI || process.env.MONGOHQ_URL || 'mongodb://localhost/naturalcrit';
mongoose.connect(mongoUri); mongoose.connect(mongoUri);
mongoose.connection.on('error', function(){ mongoose.connection.on('error', function(){
console.log(">>>ERROR: Run Mongodb.exe ya goof!"); console.log(">>>ERROR: Run Mongodb.exe ya goof!");
}); });
//Admin route //Admin route
process.env.ADMIN_USER = process.env.ADMIN_USER || 'admin'; process.env.ADMIN_USER = process.env.ADMIN_USER || 'admin';
process.env.ADMIN_PASS = process.env.ADMIN_PASS || 'password'; process.env.ADMIN_PASS = process.env.ADMIN_PASS || 'password';
process.env.ADMIN_KEY = process.env.ADMIN_KEY || 'admin_key'; process.env.ADMIN_KEY = process.env.ADMIN_KEY || 'admin_key';
var auth = require('basic-auth'); var auth = require('basic-auth');
app.get('/admin', function(req, res){ app.get('/admin', function(req, res){
var credentials = auth(req) var credentials = auth(req)
if (!credentials || credentials.name !== process.env.ADMIN_USER || credentials.pass !== process.env.ADMIN_PASS) { if (!credentials || credentials.name !== process.env.ADMIN_USER || credentials.pass !== process.env.ADMIN_PASS) {
res.setHeader('WWW-Authenticate', 'Basic realm="example"') res.setHeader('WWW-Authenticate', 'Basic realm="example"')
return res.status(401).send('Access denied') return res.status(401).send('Access denied')
} }
vitreumRender({ vitreumRender({
page: './build/admin/bundle.dot', page: './build/admin/bundle.dot',
prerenderWith : './client/admin/admin.jsx', prerenderWith : './client/admin/admin.jsx',
clearRequireCache : !process.env.PRODUCTION, clearRequireCache : !process.env.PRODUCTION,
initialProps: { initialProps: {
url: req.originalUrl, url: req.originalUrl,
admin_key : process.env.ADMIN_KEY, admin_key : process.env.ADMIN_KEY,
}, },
}, function (err, page) { }, function (err, page) {
return res.send(page) return res.send(page)
}); });
}); });
//Populate homebrew routes //Populate homebrew routes
app = require('./server/homebrew.api.js')(app); app = require('./server/homebrew.api.js')(app);
app = require('./server/homebrew.server.js')(app); app = require('./server/homebrew.server.js')(app);
app.get('*', function (req, res) { app.get('*', function (req, res) {
vitreumRender({ vitreumRender({
page: './build/main/bundle.dot', page: './build/main/bundle.dot',
globals:{}, globals:{},
prerenderWith : './client/main/main.jsx', prerenderWith : './client/main/main.jsx',
initialProps: { initialProps: {
url: req.originalUrl url: req.originalUrl
}, },
clearRequireCache : !process.env.PRODUCTION, clearRequireCache : !process.env.PRODUCTION,
}, function (err, page) { }, function (err, page) {
return res.send(page) return res.send(page)
}); });
}); });
var port = process.env.PORT || 8000; var port = process.env.PORT || 8000;
app.listen(port); app.listen(port);
console.log('Listening on localhost:' + port); console.log('Listening on localhost:' + port);

View File

@@ -1,133 +1,133 @@
var _ = require('lodash'); var _ = require('lodash');
var Moment = require('moment'); var Moment = require('moment');
var HomebrewModel = require('./homebrew.model.js').model; var HomebrewModel = require('./homebrew.model.js').model;
var homebrewTotal = 0; var homebrewTotal = 0;
var refreshCount = function(){ var refreshCount = function(){
HomebrewModel.count({}, function(err, total){ HomebrewModel.count({}, function(err, total){
homebrewTotal = total; homebrewTotal = total;
}); });
}; };
refreshCount() refreshCount()
var mw = { var mw = {
adminOnly : function(req, res, next){ adminOnly : function(req, res, next){
if(req.query && req.query.admin_key == process.env.ADMIN_KEY){ if(req.query && req.query.admin_key == process.env.ADMIN_KEY){
next(); next();
}else{ }else{
return res.status(401).send('Access denied'); return res.status(401).send('Access denied');
} }
} }
}; };
var getTopBrews = function(cb){ var getTopBrews = function(cb){
HomebrewModel.find().sort({views: -1}).limit(5).exec(function(err, brews) { HomebrewModel.find().sort({views: -1}).limit(5).exec(function(err, brews) {
cb(brews); cb(brews);
}); });
} }
module.exports = function(app){ module.exports = function(app){
app.get('/homebrew/top', function(req, res){ app.get('/homebrew/top', function(req, res){
getTopBrews(function(topBrews){ getTopBrews(function(topBrews){
return res.json(topBrews); return res.json(topBrews);
}); });
}); });
app.post('/homebrew/api', function(req, res){ app.post('/homebrew/api', function(req, res){
var newHomebrew = new HomebrewModel(req.body); var newHomebrew = new HomebrewModel(req.body);
newHomebrew.save(function(err, obj){ newHomebrew.save(function(err, obj){
if(err) return; if(err) return;
return res.json(obj); return res.json(obj);
}) })
}); });
app.put('/homebrew/api/update/:id', function(req, res){ app.put('/homebrew/api/update/:id', function(req, res){
HomebrewModel.find({editId : req.params.id}, function(err, objs){ HomebrewModel.find({editId : req.params.id}, function(err, objs){
if(!objs.length || err) return res.status(404).send("Can not find homebrew with that id"); if(!objs.length || err) return res.status(404).send("Can not find homebrew with that id");
var resEntry = objs[0]; var resEntry = objs[0];
resEntry.text = req.body.text; resEntry.text = req.body.text;
resEntry.title = req.body.title; resEntry.title = req.body.title;
resEntry.updatedAt = new Date(); resEntry.updatedAt = new Date();
resEntry.save(function(err, obj){ resEntry.save(function(err, obj){
if(err) return res.status(500).send("Error while saving"); if(err) return res.status(500).send("Error while saving");
return res.status(200).send(obj); return res.status(200).send(obj);
}) })
}); });
}); });
app.get('/homebrew/api/remove/:id', function(req, res){ app.get('/homebrew/api/remove/:id', function(req, res){
HomebrewModel.find({editId : req.params.id}, function(err, objs){ HomebrewModel.find({editId : req.params.id}, function(err, objs){
if(!objs.length || err) return res.status(404).send("Can not find homebrew with that id"); if(!objs.length || err) return res.status(404).send("Can not find homebrew with that id");
var resEntry = objs[0]; var resEntry = objs[0];
resEntry.remove(function(err){ resEntry.remove(function(err){
if(err) return res.status(500).send("Error while removing"); if(err) return res.status(500).send("Error while removing");
return res.status(200).send(); return res.status(200).send();
}) })
}); });
}); });
//Removes all empty brews that are older than 3 days and that are shorter than a tweet //Removes all empty brews that are older than 3 days and that are shorter than a tweet
app.get('/homebrew/api/invalid', mw.adminOnly, function(req, res){ app.get('/homebrew/api/invalid', mw.adminOnly, function(req, res){
var invalidBrewQuery = HomebrewModel.find({ var invalidBrewQuery = HomebrewModel.find({
'$where' : "this.text.length < 140", '$where' : "this.text.length < 140",
createdAt: { createdAt: {
$lt: Moment().subtract(3, 'days').toDate() $lt: Moment().subtract(3, 'days').toDate()
} }
}); });
if(req.query.do_it){ if(req.query.do_it){
invalidBrewQuery.remove().exec((err, objs)=>{ invalidBrewQuery.remove().exec((err, objs)=>{
refreshCount(); refreshCount();
return res.send(200); return res.send(200);
}) })
}else{ }else{
invalidBrewQuery.exec((err, objs)=>{ invalidBrewQuery.exec((err, objs)=>{
if(err) console.log(err); if(err) console.log(err);
return res.json({ return res.json({
count : objs.length count : objs.length
}) })
}) })
} }
}); });
app.get('/homebrew/api/search', mw.adminOnly, function(req, res){ app.get('/homebrew/api/search', mw.adminOnly, function(req, res){
var page = req.query.page || 0; var page = req.query.page || 0;
var count = req.query.count || 20; var count = req.query.count || 20;
var query = {}; var query = {};
if(req.query && req.query.id){ if(req.query && req.query.id){
query = { query = {
"$or" : [{ "$or" : [{
editId : req.query.id editId : req.query.id
},{ },{
shareId : req.query.id shareId : req.query.id
}] }]
}; };
} }
HomebrewModel.find(query, { HomebrewModel.find(query, {
text : 0 //omit the text text : 0 //omit the text
}, { }, {
skip: page*count, skip: page*count,
limit: count*1 limit: count*1
}, function(err, objs){ }, function(err, objs){
if(err) console.log(err); if(err) console.log(err);
return res.json({ return res.json({
page : page, page : page,
count : count, count : count,
total : homebrewTotal, total : homebrewTotal,
brews : objs brews : objs
}); });
}); });
}) })
return app; return app;
} }

View File

@@ -1,24 +1,24 @@
var mongoose = require('mongoose'); var mongoose = require('mongoose');
var shortid = require('shortid'); var shortid = require('shortid');
var _ = require('lodash'); var _ = require('lodash');
var HomebrewSchema = mongoose.Schema({ var HomebrewSchema = mongoose.Schema({
shareId : {type : String, default: shortid.generate, index: { unique: true }}, shareId : {type : String, default: shortid.generate, index: { unique: true }},
editId : {type : String, default: shortid.generate, index: { unique: true }}, editId : {type : String, default: shortid.generate, index: { unique: true }},
title : {type : String, default : ""}, title : {type : String, default : ""},
text : {type : String, default : ""}, text : {type : String, default : ""},
createdAt : { type: Date, default: Date.now }, createdAt : { type: Date, default: Date.now },
updatedAt : { type: Date, default: Date.now}, updatedAt : { type: Date, default: Date.now},
lastViewed : { type: Date, default: Date.now}, lastViewed : { type: Date, default: Date.now},
views : {type:Number, default:0} views : {type:Number, default:0}
}); });
var Homebrew = mongoose.model('Homebrew', HomebrewSchema); var Homebrew = mongoose.model('Homebrew', HomebrewSchema);
module.exports = { module.exports = {
schema : HomebrewSchema, schema : HomebrewSchema,
model : Homebrew, model : Homebrew,
} }

View File

@@ -1,135 +1,135 @@
var _ = require('lodash'); var _ = require('lodash');
var vitreumRender = require('vitreum/render'); var vitreumRender = require('vitreum/render');
var HomebrewModel = require('./homebrew.model.js').model; var HomebrewModel = require('./homebrew.model.js').model;
module.exports = function(app){ module.exports = function(app){
/* /*
app.get('/homebrew/new', function(req, res){ app.get('/homebrew/new', function(req, res){
var newHomebrew = new HomebrewModel(); var newHomebrew = new HomebrewModel();
newHomebrew.save(function(err, obj){ newHomebrew.save(function(err, obj){
return res.redirect('/homebrew/edit/' + obj.editId); return res.redirect('/homebrew/edit/' + obj.editId);
}) })
}) })
*/ */
//Edit Page //Edit Page
app.get('/homebrew/edit/:id', function(req, res){ app.get('/homebrew/edit/:id', function(req, res){
HomebrewModel.find({editId : req.params.id}, function(err, objs){ HomebrewModel.find({editId : req.params.id}, function(err, objs){
if(err || !objs.length) return res.status(404).send('Could not find Homebrew with that id'); if(err || !objs.length) return res.status(404).send('Could not find Homebrew with that id');
var resObj = null; var resObj = null;
var errObj = {text: "# oops\nCould not find the homebrew."} var errObj = {text: "# oops\nCould not find the homebrew."}
if(objs.length){ if(objs.length){
resObj = objs[0]; resObj = objs[0];
} }
vitreumRender({ vitreumRender({
page: './build/homebrew/bundle.dot', page: './build/homebrew/bundle.dot',
globals:{}, globals:{},
prerenderWith : './client/homebrew/homebrew.jsx', prerenderWith : './client/homebrew/homebrew.jsx',
initialProps: { initialProps: {
url: req.originalUrl, url: req.originalUrl,
brew : resObj || errObj brew : resObj || errObj
}, },
clearRequireCache : !process.env.PRODUCTION, clearRequireCache : !process.env.PRODUCTION,
}, function (err, page) { }, function (err, page) {
return res.send(page) return res.send(page)
}); });
}) })
}); });
//Share Page //Share Page
app.get('/homebrew/share/:id', function(req, res){ app.get('/homebrew/share/:id', function(req, res){
HomebrewModel.find({shareId : req.params.id}, function(err, objs){ HomebrewModel.find({shareId : req.params.id}, function(err, objs){
if(err || !objs.length) return res.status(404).send('Could not find Homebrew with that id'); if(err || !objs.length) return res.status(404).send('Could not find Homebrew with that id');
var resObj = null; var resObj = null;
var errObj = {text: "# oops\nCould not find the homebrew."} var errObj = {text: "# oops\nCould not find the homebrew."}
if(objs.length){ if(objs.length){
resObj = objs[0]; resObj = objs[0];
resObj.lastViewed = new Date(); resObj.lastViewed = new Date();
resObj.views = resObj.views + 1; resObj.views = resObj.views + 1;
resObj.save(); resObj.save();
} }
vitreumRender({ vitreumRender({
page: './build/homebrew/bundle.dot', page: './build/homebrew/bundle.dot',
globals:{}, globals:{},
prerenderWith : './client/homebrew/homebrew.jsx', prerenderWith : './client/homebrew/homebrew.jsx',
initialProps: { initialProps: {
url: req.originalUrl, url: req.originalUrl,
brew : resObj || errObj brew : resObj || errObj
}, },
clearRequireCache : !process.env.PRODUCTION, clearRequireCache : !process.env.PRODUCTION,
}, function (err, page) { }, function (err, page) {
return res.send(page) return res.send(page)
}); });
}) })
}); });
//Print Page //Print Page
var Markdown = require('marked'); var Markdown = require('marked');
var PHBStyle = '<style>' + require('fs').readFileSync('./phb.standalone.css', 'utf8') + '</style>' var PHBStyle = '<style>' + require('fs').readFileSync('./phb.standalone.css', 'utf8') + '</style>'
app.get('/homebrew/print/:id', function(req, res){ app.get('/homebrew/print/:id', function(req, res){
HomebrewModel.find({shareId : req.params.id}, function(err, objs){ HomebrewModel.find({shareId : req.params.id}, function(err, objs){
if(err || !objs.length) return res.status(404).send('Could not find Homebrew with that id'); if(err || !objs.length) return res.status(404).send('Could not find Homebrew with that id');
var brew = null; var brew = null;
if(objs.length){ if(objs.length){
brew = objs[0]; brew = objs[0];
} }
var content = _.map(brew.text.split('\\page'), function(pageText){ var content = _.map(brew.text.split('\\page'), function(pageText){
return '<div class="phb print">' + Markdown(pageText) + '</div>'; return '<div class="phb print">' + Markdown(pageText) + '</div>';
}).join('\n'); }).join('\n');
var dialog = ''; var dialog = '';
if(req.query && req.query.dialog) dialog = 'onload="window.print()"'; if(req.query && req.query.dialog) dialog = 'onload="window.print()"';
var title = '<title>' + brew.title + '</title>'; var title = '<title>' + brew.title + '</title>';
var page = `<html><head>${title} ${PHBStyle}</head><body ${dialog}>${content}</body></html>` var page = `<html><head>${title} ${PHBStyle}</head><body ${dialog}>${content}</body></html>`
return res.send(page) return res.send(page)
}); });
}); });
//Source page //Source page
String.prototype.replaceAll = function(s,r){return this.split(s).join(r)} String.prototype.replaceAll = function(s,r){return this.split(s).join(r)}
app.get('/homebrew/source/:id', function(req, res){ app.get('/homebrew/source/:id', function(req, res){
HomebrewModel.find({shareId : req.params.id}, function(err, objs){ HomebrewModel.find({shareId : req.params.id}, function(err, objs){
if(err || !objs.length) return res.status(404).send('Could not find Homebrew with that id'); if(err || !objs.length) return res.status(404).send('Could not find Homebrew with that id');
var brew = null; var brew = null;
if(objs.length) brew = objs[0]; if(objs.length) brew = objs[0];
var text = brew.text.replaceAll('<', '&lt;').replaceAll('>', '&gt;'); var text = brew.text.replaceAll('<', '&lt;').replaceAll('>', '&gt;');
return res.send(`<code><pre>${text}</pre></code>`); return res.send(`<code><pre>${text}</pre></code>`);
}); });
}); });
//Home and 404, etc. //Home and 404, etc.
var welcomeText = require('fs').readFileSync('./client/homebrew/pages/homePage/welcome_msg.txt', 'utf8'); var welcomeText = require('fs').readFileSync('./client/homebrew/pages/homePage/welcome_msg.txt', 'utf8');
var changelogText = require('fs').readFileSync('./changelog.md', 'utf8'); var changelogText = require('fs').readFileSync('./changelog.md', 'utf8');
app.get('/homebrew*', function (req, res) { app.get('/homebrew*', function (req, res) {
vitreumRender({ vitreumRender({
page: './build/homebrew/bundle.dot', page: './build/homebrew/bundle.dot',
globals:{}, globals:{},
prerenderWith : './client/homebrew/homebrew.jsx', prerenderWith : './client/homebrew/homebrew.jsx',
initialProps: { initialProps: {
url: req.originalUrl, url: req.originalUrl,
welcomeText : welcomeText, welcomeText : welcomeText,
changelog : changelogText changelog : changelogText
}, },
clearRequireCache : !process.env.PRODUCTION, clearRequireCache : !process.env.PRODUCTION,
}, function (err, page) { }, function (err, page) {
return res.send(page) return res.send(page)
}); });
}); });
return app; return app;
} }

View File

@@ -1,203 +1,203 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
var noOptions = {}; var noOptions = {};
var nonWS = /[^\s\u00a0]/; var nonWS = /[^\s\u00a0]/;
var Pos = CodeMirror.Pos; var Pos = CodeMirror.Pos;
function firstNonWS(str) { function firstNonWS(str) {
var found = str.search(nonWS); var found = str.search(nonWS);
return found == -1 ? 0 : found; return found == -1 ? 0 : found;
} }
CodeMirror.commands.toggleComment = function(cm) { CodeMirror.commands.toggleComment = function(cm) {
cm.toggleComment(); cm.toggleComment();
}; };
CodeMirror.defineExtension("toggleComment", function(options) { CodeMirror.defineExtension("toggleComment", function(options) {
if (!options) options = noOptions; if (!options) options = noOptions;
var cm = this; var cm = this;
var minLine = Infinity, ranges = this.listSelections(), mode = null; 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, options)) mode = "un"; if (cm.uncomment(from, to, options)) mode = "un";
else { cm.lineComment(from, to, options); mode = "line"; } else { cm.lineComment(from, to, options); mode = "line"; }
} else if (mode == "un") { } else if (mode == "un") {
cm.uncomment(from, to, options); cm.uncomment(from, to, options);
} else { } else {
cm.lineComment(from, to, options); cm.lineComment(from, to, options);
} }
} }
}); });
// Rough heuristic to try and detect lines that are part of multi-line string // Rough heuristic to try and detect lines that are part of multi-line string
function probablyInsideString(cm, pos, line) { function probablyInsideString(cm, pos, line) {
return /\bstring\b/.test(cm.getTokenTypeAt(Pos(pos.line, 0))) && !/^[\'\"`]/.test(line) return /\bstring\b/.test(cm.getTokenTypeAt(Pos(pos.line, 0))) && !/^[\'\"`]/.test(line)
} }
CodeMirror.defineExtension("lineComment", function(from, to, options) { CodeMirror.defineExtension("lineComment", function(from, to, options) {
if (!options) options = noOptions; if (!options) options = noOptions;
var self = this, mode = self.getModeAt(from); var self = this, mode = self.getModeAt(from);
var firstLine = self.getLine(from.line); var firstLine = self.getLine(from.line);
if (firstLine == null || probablyInsideString(self, from, firstLine)) return; if (firstLine == null || probablyInsideString(self, from, firstLine)) return;
var commentString = options.lineComment || mode.lineComment; var commentString = options.lineComment || mode.lineComment;
if (!commentString) { if (!commentString) {
if (options.blockCommentStart || mode.blockCommentStart) { if (options.blockCommentStart || mode.blockCommentStart) {
options.fullLines = true; options.fullLines = true;
self.blockComment(from, to, options); self.blockComment(from, to, options);
} }
return; return;
} }
var end = Math.min(to.ch != 0 || to.line == from.line ? to.line + 1 : to.line, self.lastLine() + 1); var end = Math.min(to.ch != 0 || to.line == from.line ? to.line + 1 : to.line, self.lastLine() + 1);
var pad = options.padding == null ? " " : options.padding; var pad = options.padding == null ? " " : options.padding;
var blankLines = options.commentBlankLines || from.line == to.line; var blankLines = options.commentBlankLines || from.line == to.line;
self.operation(function() { self.operation(function() {
if (options.indent) { if (options.indent) {
var baseString = null; var baseString = null;
for (var i = from.line; i < end; ++i) { for (var i = from.line; i < end; ++i) {
var line = self.getLine(i); var line = self.getLine(i);
var whitespace = line.slice(0, firstNonWS(line)); var whitespace = line.slice(0, firstNonWS(line));
if (baseString == null || baseString.length > whitespace.length) { if (baseString == null || baseString.length > whitespace.length) {
baseString = whitespace; 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;
if (line.slice(0, cut) != baseString) cut = firstNonWS(line); if (line.slice(0, cut) != baseString) cut = firstNonWS(line);
self.replaceRange(baseString + commentString + pad, Pos(i, 0), Pos(i, cut)); self.replaceRange(baseString + commentString + pad, Pos(i, 0), Pos(i, cut));
} }
} else { } else {
for (var i = from.line; i < end; ++i) { for (var i = from.line; i < end; ++i) {
if (blankLines || nonWS.test(self.getLine(i))) if (blankLines || nonWS.test(self.getLine(i)))
self.replaceRange(commentString + pad, Pos(i, 0)); self.replaceRange(commentString + pad, Pos(i, 0));
} }
} }
}); });
}); });
CodeMirror.defineExtension("blockComment", function(from, to, options) { CodeMirror.defineExtension("blockComment", function(from, to, options) {
if (!options) options = noOptions; if (!options) options = noOptions;
var self = this, mode = self.getModeAt(from); var self = this, mode = self.getModeAt(from);
var startString = options.blockCommentStart || mode.blockCommentStart; var startString = options.blockCommentStart || mode.blockCommentStart;
var endString = options.blockCommentEnd || mode.blockCommentEnd; var endString = options.blockCommentEnd || mode.blockCommentEnd;
if (!startString || !endString) { if (!startString || !endString) {
if ((options.lineComment || mode.lineComment) && options.fullLines != false) if ((options.lineComment || mode.lineComment) && options.fullLines != false)
self.lineComment(from, to, options); self.lineComment(from, to, options);
return; return;
} }
var end = Math.min(to.line, self.lastLine()); var end = Math.min(to.line, self.lastLine());
if (end != from.line && to.ch == 0 && nonWS.test(self.getLine(end))) --end; if (end != from.line && to.ch == 0 && nonWS.test(self.getLine(end))) --end;
var pad = options.padding == null ? " " : options.padding; var pad = options.padding == null ? " " : options.padding;
if (from.line > end) return; if (from.line > end) return;
self.operation(function() { self.operation(function() {
if (options.fullLines != false) { if (options.fullLines != false) {
var lastLineHasText = nonWS.test(self.getLine(end)); var lastLineHasText = nonWS.test(self.getLine(end));
self.replaceRange(pad + endString, Pos(end)); self.replaceRange(pad + endString, Pos(end));
self.replaceRange(startString + pad, Pos(from.line, 0)); self.replaceRange(startString + pad, Pos(from.line, 0));
var lead = options.blockCommentLead || mode.blockCommentLead; var lead = options.blockCommentLead || mode.blockCommentLead;
if (lead != null) for (var i = from.line + 1; i <= end; ++i) if (lead != null) for (var i = from.line + 1; i <= end; ++i)
if (i != end || lastLineHasText) if (i != end || lastLineHasText)
self.replaceRange(lead + pad, Pos(i, 0)); self.replaceRange(lead + pad, Pos(i, 0));
} else { } else {
self.replaceRange(endString, to); self.replaceRange(endString, to);
self.replaceRange(startString, from); self.replaceRange(startString, from);
} }
}); });
}); });
CodeMirror.defineExtension("uncomment", function(from, to, options) { CodeMirror.defineExtension("uncomment", function(from, to, options) {
if (!options) options = noOptions; if (!options) options = noOptions;
var self = this, mode = self.getModeAt(from); var self = this, mode = self.getModeAt(from);
var end = Math.min(to.ch != 0 || to.line == from.line ? to.line : to.line - 1, self.lastLine()), start = Math.min(from.line, end); var end = Math.min(to.ch != 0 || to.line == from.line ? to.line : to.line - 1, self.lastLine()), start = Math.min(from.line, end);
// Try finding line comments // Try finding line comments
var lineString = options.lineComment || mode.lineComment, lines = []; var lineString = options.lineComment || mode.lineComment, lines = [];
var pad = options.padding == null ? " " : options.padding, didSomething; var pad = options.padding == null ? " " : options.padding, didSomething;
lineComment: { lineComment: {
if (!lineString) break lineComment; if (!lineString) break lineComment;
for (var i = start; i <= end; ++i) { for (var i = start; i <= end; ++i) {
var line = self.getLine(i); var line = self.getLine(i);
var found = line.indexOf(lineString); var found = line.indexOf(lineString);
if (found > -1 && !/comment/.test(self.getTokenTypeAt(Pos(i, found + 1)))) found = -1; if (found > -1 && !/comment/.test(self.getTokenTypeAt(Pos(i, found + 1)))) found = -1;
if (found == -1 && (i != end || i == start) && nonWS.test(line)) break lineComment; if (found == -1 && (i != end || i == start) && nonWS.test(line)) break lineComment;
if (found > -1 && nonWS.test(line.slice(0, found))) break lineComment; if (found > -1 && nonWS.test(line.slice(0, found))) break lineComment;
lines.push(line); lines.push(line);
} }
self.operation(function() { self.operation(function() {
for (var i = start; i <= end; ++i) { for (var i = start; i <= end; ++i) {
var line = lines[i - start]; var line = lines[i - start];
var pos = line.indexOf(lineString), endPos = pos + lineString.length; var pos = line.indexOf(lineString), endPos = pos + lineString.length;
if (pos < 0) continue; if (pos < 0) continue;
if (line.slice(endPos, endPos + pad.length) == pad) endPos += pad.length; if (line.slice(endPos, endPos + pad.length) == pad) endPos += pad.length;
didSomething = true; didSomething = true;
self.replaceRange("", Pos(i, pos), Pos(i, endPos)); self.replaceRange("", Pos(i, pos), Pos(i, endPos));
} }
}); });
if (didSomething) return true; if (didSomething) return true;
} }
// Try block comments // Try block comments
var startString = options.blockCommentStart || mode.blockCommentStart; var startString = options.blockCommentStart || mode.blockCommentStart;
var endString = options.blockCommentEnd || mode.blockCommentEnd; var endString = options.blockCommentEnd || mode.blockCommentEnd;
if (!startString || !endString) return false; if (!startString || !endString) return false;
var lead = options.blockCommentLead || mode.blockCommentLead; var lead = options.blockCommentLead || mode.blockCommentLead;
var startLine = self.getLine(start), endLine = end == start ? startLine : self.getLine(end); var startLine = self.getLine(start), endLine = end == start ? startLine : self.getLine(end);
var open = startLine.indexOf(startString), close = endLine.lastIndexOf(endString); var open = startLine.indexOf(startString), close = endLine.lastIndexOf(endString);
if (close == -1 && start != end) { if (close == -1 && start != end) {
endLine = self.getLine(--end); endLine = self.getLine(--end);
close = endLine.lastIndexOf(endString); close = endLine.lastIndexOf(endString);
} }
if (open == -1 || close == -1 || if (open == -1 || close == -1 ||
!/comment/.test(self.getTokenTypeAt(Pos(start, open + 1))) || !/comment/.test(self.getTokenTypeAt(Pos(start, open + 1))) ||
!/comment/.test(self.getTokenTypeAt(Pos(end, close + 1)))) !/comment/.test(self.getTokenTypeAt(Pos(end, close + 1))))
return false; return false;
// Avoid killing block comments completely outside the selection. // Avoid killing block comments completely outside the selection.
// Positions of the last startString before the start of the selection, and the first endString after it. // Positions of the last startString before the start of the selection, and the first endString after it.
var lastStart = startLine.lastIndexOf(startString, from.ch); var lastStart = startLine.lastIndexOf(startString, from.ch);
var firstEnd = lastStart == -1 ? -1 : startLine.slice(0, from.ch).indexOf(endString, lastStart + startString.length); var firstEnd = lastStart == -1 ? -1 : startLine.slice(0, from.ch).indexOf(endString, lastStart + startString.length);
if (lastStart != -1 && firstEnd != -1 && firstEnd + endString.length != from.ch) return false; if (lastStart != -1 && firstEnd != -1 && firstEnd + endString.length != from.ch) return false;
// Positions of the first endString after the end of the selection, and the last startString before it. // Positions of the first endString after the end of the selection, and the last startString before it.
firstEnd = endLine.indexOf(endString, to.ch); firstEnd = endLine.indexOf(endString, to.ch);
var almostLastStart = endLine.slice(to.ch).lastIndexOf(startString, firstEnd - to.ch); var almostLastStart = endLine.slice(to.ch).lastIndexOf(startString, firstEnd - to.ch);
lastStart = (firstEnd == -1 || almostLastStart == -1) ? -1 : to.ch + almostLastStart; lastStart = (firstEnd == -1 || almostLastStart == -1) ? -1 : to.ch + almostLastStart;
if (firstEnd != -1 && lastStart != -1 && lastStart != to.ch) return false; if (firstEnd != -1 && lastStart != -1 && lastStart != to.ch) return false;
self.operation(function() { self.operation(function() {
self.replaceRange("", Pos(end, close - (pad && endLine.slice(close - pad.length, close) == pad ? pad.length : 0)), self.replaceRange("", Pos(end, close - (pad && endLine.slice(close - pad.length, close) == pad ? pad.length : 0)),
Pos(end, close + endString.length)); Pos(end, close + endString.length));
var openEnd = open + startString.length; var openEnd = open + startString.length;
if (pad && startLine.slice(openEnd, openEnd + pad.length) == pad) openEnd += pad.length; if (pad && startLine.slice(openEnd, openEnd + pad.length) == pad) openEnd += pad.length;
self.replaceRange("", Pos(start, open), Pos(start, openEnd)); self.replaceRange("", Pos(start, open), Pos(start, openEnd));
if (lead) for (var i = start + 1; i <= end; ++i) { if (lead) for (var i = start + 1; i <= end; ++i) {
var line = self.getLine(i), found = line.indexOf(lead); var line = self.getLine(i), found = line.indexOf(lead);
if (found == -1 || nonWS.test(line.slice(0, found))) continue; if (found == -1 || nonWS.test(line.slice(0, found))) continue;
var foundEnd = found + lead.length; var foundEnd = found + lead.length;
if (pad && line.slice(foundEnd, foundEnd + pad.length) == pad) foundEnd += pad.length; if (pad && line.slice(foundEnd, foundEnd + pad.length) == pad) foundEnd += pad.length;
self.replaceRange("", Pos(i, found), Pos(i, foundEnd)); self.replaceRange("", Pos(i, found), Pos(i, foundEnd));
} }
}); });
return true; return true;
}); });
}); });

View File

@@ -1,85 +1,85 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
var modes = ["clike", "css", "javascript"]; var modes = ["clike", "css", "javascript"];
for (var i = 0; i < modes.length; ++i) for (var i = 0; i < modes.length; ++i)
CodeMirror.extendMode(modes[i], {blockCommentContinue: " * "}); CodeMirror.extendMode(modes[i], {blockCommentContinue: " * "});
function continueComment(cm) { function continueComment(cm) {
if (cm.getOption("disableInput")) return CodeMirror.Pass; if (cm.getOption("disableInput")) return CodeMirror.Pass;
var ranges = cm.listSelections(), mode, inserts = []; var ranges = cm.listSelections(), mode, inserts = [];
for (var i = 0; i < ranges.length; i++) { for (var i = 0; i < ranges.length; i++) {
var pos = ranges[i].head, token = cm.getTokenAt(pos); var pos = ranges[i].head, token = cm.getTokenAt(pos);
if (token.type != "comment") return CodeMirror.Pass; if (token.type != "comment") return CodeMirror.Pass;
var modeHere = CodeMirror.innerMode(cm.getMode(), token.state).mode; var modeHere = CodeMirror.innerMode(cm.getMode(), token.state).mode;
if (!mode) mode = modeHere; if (!mode) mode = modeHere;
else if (mode != modeHere) return CodeMirror.Pass; else if (mode != modeHere) return CodeMirror.Pass;
var insert = null; var insert = null;
if (mode.blockCommentStart && mode.blockCommentContinue) { if (mode.blockCommentStart && mode.blockCommentContinue) {
var end = token.string.indexOf(mode.blockCommentEnd); var end = token.string.indexOf(mode.blockCommentEnd);
var full = cm.getRange(CodeMirror.Pos(pos.line, 0), CodeMirror.Pos(pos.line, token.end)), found; var full = cm.getRange(CodeMirror.Pos(pos.line, 0), CodeMirror.Pos(pos.line, token.end)), found;
if (end != -1 && end == token.string.length - mode.blockCommentEnd.length && pos.ch >= end) { if (end != -1 && end == token.string.length - mode.blockCommentEnd.length && pos.ch >= end) {
// Comment ended, don't continue it // Comment ended, don't continue it
} else if (token.string.indexOf(mode.blockCommentStart) == 0) { } else if (token.string.indexOf(mode.blockCommentStart) == 0) {
insert = full.slice(0, token.start); insert = full.slice(0, token.start);
if (!/^\s*$/.test(insert)) { if (!/^\s*$/.test(insert)) {
insert = ""; insert = "";
for (var j = 0; j < token.start; ++j) insert += " "; for (var j = 0; j < token.start; ++j) insert += " ";
} }
} else if ((found = full.indexOf(mode.blockCommentContinue)) != -1 && } else if ((found = full.indexOf(mode.blockCommentContinue)) != -1 &&
found + mode.blockCommentContinue.length > token.start && found + mode.blockCommentContinue.length > token.start &&
/^\s*$/.test(full.slice(0, found))) { /^\s*$/.test(full.slice(0, found))) {
insert = full.slice(0, found); insert = full.slice(0, found);
} }
if (insert != null) insert += mode.blockCommentContinue; if (insert != null) insert += mode.blockCommentContinue;
} }
if (insert == null && mode.lineComment && continueLineCommentEnabled(cm)) { if (insert == null && mode.lineComment && continueLineCommentEnabled(cm)) {
var line = cm.getLine(pos.line), found = line.indexOf(mode.lineComment); var line = cm.getLine(pos.line), found = line.indexOf(mode.lineComment);
if (found > -1) { if (found > -1) {
insert = line.slice(0, found); insert = line.slice(0, found);
if (/\S/.test(insert)) insert = null; if (/\S/.test(insert)) insert = null;
else insert += mode.lineComment + line.slice(found + mode.lineComment.length).match(/^\s*/)[0]; else insert += mode.lineComment + line.slice(found + mode.lineComment.length).match(/^\s*/)[0];
} }
} }
if (insert == null) return CodeMirror.Pass; if (insert == null) return CodeMirror.Pass;
inserts[i] = "\n" + insert; inserts[i] = "\n" + insert;
} }
cm.operation(function() { cm.operation(function() {
for (var i = ranges.length - 1; i >= 0; i--) for (var i = ranges.length - 1; i >= 0; i--)
cm.replaceRange(inserts[i], ranges[i].from(), ranges[i].to(), "+insert"); cm.replaceRange(inserts[i], ranges[i].from(), ranges[i].to(), "+insert");
}); });
} }
function continueLineCommentEnabled(cm) { function continueLineCommentEnabled(cm) {
var opt = cm.getOption("continueComments"); var opt = cm.getOption("continueComments");
if (opt && typeof opt == "object") if (opt && typeof opt == "object")
return opt.continueLineComment !== false; return opt.continueLineComment !== false;
return true; return true;
} }
CodeMirror.defineOption("continueComments", null, function(cm, val, prev) { CodeMirror.defineOption("continueComments", null, function(cm, val, prev) {
if (prev && prev != CodeMirror.Init) if (prev && prev != CodeMirror.Init)
cm.removeKeyMap("continueComment"); cm.removeKeyMap("continueComment");
if (val) { if (val) {
var key = "Enter"; var key = "Enter";
if (typeof val == "string") if (typeof val == "string")
key = val; key = val;
else if (typeof val == "object" && val.key) else if (typeof val == "object" && val.key)
key = val.key; key = val.key;
var map = {name: "continueComment"}; var map = {name: "continueComment"};
map[key] = continueComment; map[key] = continueComment;
cm.addKeyMap(map); cm.addKeyMap(map);
} }
}); });
}); });

View File

@@ -1,32 +1,32 @@
.CodeMirror-dialog { .CodeMirror-dialog {
position: absolute; position: absolute;
left: 0; right: 0; left: 0; right: 0;
background: inherit; background: inherit;
z-index: 15; z-index: 15;
padding: .1em .8em; padding: .1em .8em;
overflow: hidden; overflow: hidden;
color: inherit; color: inherit;
} }
.CodeMirror-dialog-top { .CodeMirror-dialog-top {
border-bottom: 1px solid #eee; border-bottom: 1px solid #eee;
top: 0; top: 0;
} }
.CodeMirror-dialog-bottom { .CodeMirror-dialog-bottom {
border-top: 1px solid #eee; border-top: 1px solid #eee;
bottom: 0; bottom: 0;
} }
.CodeMirror-dialog input { .CodeMirror-dialog input {
border: none; border: none;
outline: none; outline: none;
background: transparent; background: transparent;
width: 20em; width: 20em;
color: inherit; color: inherit;
font-family: monospace; font-family: monospace;
} }
.CodeMirror-dialog button { .CodeMirror-dialog button {
font-size: 70%; font-size: 70%;
} }

View File

@@ -1,157 +1,157 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
// Open simple dialogs on top of an editor. Relies on dialog.css. // Open simple dialogs on top of an editor. Relies on dialog.css.
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
function dialogDiv(cm, template, bottom) { function dialogDiv(cm, template, bottom) {
var wrap = cm.getWrapperElement(); var wrap = cm.getWrapperElement();
var dialog; var dialog;
dialog = wrap.appendChild(document.createElement("div")); dialog = wrap.appendChild(document.createElement("div"));
if (bottom) if (bottom)
dialog.className = "CodeMirror-dialog CodeMirror-dialog-bottom"; dialog.className = "CodeMirror-dialog CodeMirror-dialog-bottom";
else else
dialog.className = "CodeMirror-dialog CodeMirror-dialog-top"; dialog.className = "CodeMirror-dialog CodeMirror-dialog-top";
if (typeof template == "string") { if (typeof template == "string") {
dialog.innerHTML = template; dialog.innerHTML = template;
} else { // Assuming it's a detached DOM element. } else { // Assuming it's a detached DOM element.
dialog.appendChild(template); dialog.appendChild(template);
} }
return dialog; return dialog;
} }
function closeNotification(cm, newVal) { function closeNotification(cm, newVal) {
if (cm.state.currentNotificationClose) if (cm.state.currentNotificationClose)
cm.state.currentNotificationClose(); cm.state.currentNotificationClose();
cm.state.currentNotificationClose = newVal; cm.state.currentNotificationClose = newVal;
} }
CodeMirror.defineExtension("openDialog", function(template, callback, options) { CodeMirror.defineExtension("openDialog", function(template, callback, options) {
if (!options) options = {}; if (!options) options = {};
closeNotification(this, null); closeNotification(this, null);
var dialog = dialogDiv(this, template, options.bottom); var dialog = dialogDiv(this, template, options.bottom);
var closed = false, me = this; var closed = false, me = this;
function close(newVal) { function close(newVal) {
if (typeof newVal == 'string') { if (typeof newVal == 'string') {
inp.value = newVal; inp.value = newVal;
} else { } else {
if (closed) return; if (closed) return;
closed = true; closed = true;
dialog.parentNode.removeChild(dialog); dialog.parentNode.removeChild(dialog);
me.focus(); me.focus();
if (options.onClose) options.onClose(dialog); if (options.onClose) options.onClose(dialog);
} }
} }
var inp = dialog.getElementsByTagName("input")[0], button; var inp = dialog.getElementsByTagName("input")[0], button;
if (inp) { if (inp) {
inp.focus(); inp.focus();
if (options.value) { if (options.value) {
inp.value = options.value; inp.value = options.value;
if (options.selectValueOnOpen !== false) { 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);});
if (options.onKeyUp) if (options.onKeyUp)
CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value, close);}); CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value, close);});
CodeMirror.on(inp, "keydown", function(e) { CodeMirror.on(inp, "keydown", function(e) {
if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; } if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; }
if (e.keyCode == 27 || (options.closeOnEnter !== false && e.keyCode == 13)) { if (e.keyCode == 27 || (options.closeOnEnter !== false && e.keyCode == 13)) {
inp.blur(); inp.blur();
CodeMirror.e_stop(e); CodeMirror.e_stop(e);
close(); close();
} }
if (e.keyCode == 13) callback(inp.value, e); if (e.keyCode == 13) callback(inp.value, e);
}); });
if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", close); if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", close);
} 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();
me.focus(); me.focus();
}); });
if (options.closeOnBlur !== false) CodeMirror.on(button, "blur", close); if (options.closeOnBlur !== false) CodeMirror.on(button, "blur", close);
button.focus(); button.focus();
} }
return close; return close;
}); });
CodeMirror.defineExtension("openConfirm", function(template, callbacks, options) { CodeMirror.defineExtension("openConfirm", function(template, callbacks, options) {
closeNotification(this, null); closeNotification(this, null);
var dialog = dialogDiv(this, template, options && options.bottom); var dialog = dialogDiv(this, template, options && options.bottom);
var buttons = dialog.getElementsByTagName("button"); var buttons = dialog.getElementsByTagName("button");
var closed = false, me = this, blurring = 1; var closed = false, me = this, blurring = 1;
function close() { function close() {
if (closed) return; if (closed) return;
closed = true; closed = true;
dialog.parentNode.removeChild(dialog); dialog.parentNode.removeChild(dialog);
me.focus(); me.focus();
} }
buttons[0].focus(); buttons[0].focus();
for (var i = 0; i < buttons.length; ++i) { for (var i = 0; i < buttons.length; ++i) {
var b = buttons[i]; var b = buttons[i];
(function(callback) { (function(callback) {
CodeMirror.on(b, "click", function(e) { CodeMirror.on(b, "click", function(e) {
CodeMirror.e_preventDefault(e); CodeMirror.e_preventDefault(e);
close(); close();
if (callback) callback(me); if (callback) callback(me);
}); });
})(callbacks[i]); })(callbacks[i]);
CodeMirror.on(b, "blur", function() { CodeMirror.on(b, "blur", function() {
--blurring; --blurring;
setTimeout(function() { if (blurring <= 0) close(); }, 200); setTimeout(function() { if (blurring <= 0) close(); }, 200);
}); });
CodeMirror.on(b, "focus", function() { ++blurring; }); CodeMirror.on(b, "focus", function() { ++blurring; });
} }
}); });
/* /*
* openNotification * openNotification
* Opens a notification, that can be closed with an optional timer * Opens a notification, that can be closed with an optional timer
* (default 5000ms timer) and always closes on click. * (default 5000ms timer) and always closes on click.
* *
* If a notification is opened while another is opened, it will close the * If a notification is opened while another is opened, it will close the
* currently opened one and open the new one immediately. * currently opened one and open the new one immediately.
*/ */
CodeMirror.defineExtension("openNotification", function(template, options) { CodeMirror.defineExtension("openNotification", function(template, options) {
closeNotification(this, close); closeNotification(this, close);
var dialog = dialogDiv(this, template, options && options.bottom); var dialog = dialogDiv(this, template, options && options.bottom);
var closed = false, doneTimer; var closed = false, doneTimer;
var duration = options && typeof options.duration !== "undefined" ? options.duration : 5000; var duration = options && typeof options.duration !== "undefined" ? options.duration : 5000;
function close() { function close() {
if (closed) return; if (closed) return;
closed = true; closed = true;
clearTimeout(doneTimer); clearTimeout(doneTimer);
dialog.parentNode.removeChild(dialog); dialog.parentNode.removeChild(dialog);
} }
CodeMirror.on(dialog, 'click', function(e) { CodeMirror.on(dialog, 'click', function(e) {
CodeMirror.e_preventDefault(e); CodeMirror.e_preventDefault(e);
close(); close();
}); });
if (duration) if (duration)
doneTimer = setTimeout(close, duration); doneTimer = setTimeout(close, duration);
return close; return close;
}); });
}); });

View File

@@ -1,47 +1,47 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"))
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod) define(["../../lib/codemirror"], mod)
else // Plain browser env else // Plain browser env
mod(CodeMirror) mod(CodeMirror)
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict" "use strict"
CodeMirror.defineOption("autoRefresh", false, function(cm, val) { CodeMirror.defineOption("autoRefresh", false, function(cm, val) {
if (cm.state.autoRefresh) { if (cm.state.autoRefresh) {
stopListening(cm, cm.state.autoRefresh) stopListening(cm, cm.state.autoRefresh)
cm.state.autoRefresh = null cm.state.autoRefresh = null
} }
if (val && cm.display.wrapper.offsetHeight == 0) if (val && cm.display.wrapper.offsetHeight == 0)
startListening(cm, cm.state.autoRefresh = {delay: val.delay || 250}) startListening(cm, cm.state.autoRefresh = {delay: val.delay || 250})
}) })
function startListening(cm, state) { function startListening(cm, state) {
function check() { function check() {
if (cm.display.wrapper.offsetHeight) { if (cm.display.wrapper.offsetHeight) {
stopListening(cm, state) stopListening(cm, state)
if (cm.display.lastWrapHeight != cm.display.wrapper.clientHeight) if (cm.display.lastWrapHeight != cm.display.wrapper.clientHeight)
cm.refresh() cm.refresh()
} else { } else {
state.timeout = setTimeout(check, state.delay) state.timeout = setTimeout(check, state.delay)
} }
} }
state.timeout = setTimeout(check, state.delay) state.timeout = setTimeout(check, state.delay)
state.hurry = function() { state.hurry = function() {
clearTimeout(state.timeout) clearTimeout(state.timeout)
state.timeout = setTimeout(check, 50) state.timeout = setTimeout(check, 50)
} }
CodeMirror.on(window, "mouseup", state.hurry) CodeMirror.on(window, "mouseup", state.hurry)
CodeMirror.on(window, "keyup", state.hurry) CodeMirror.on(window, "keyup", state.hurry)
} }
function stopListening(_cm, state) { function stopListening(_cm, state) {
clearTimeout(state.timeout) clearTimeout(state.timeout)
CodeMirror.off(window, "mouseup", state.hurry) CodeMirror.off(window, "mouseup", state.hurry)
CodeMirror.off(window, "keyup", state.hurry) CodeMirror.off(window, "keyup", state.hurry)
} }
}); });

View File

@@ -1,6 +1,6 @@
.CodeMirror-fullscreen { .CodeMirror-fullscreen {
position: fixed; position: fixed;
top: 0; left: 0; right: 0; bottom: 0; top: 0; left: 0; right: 0; bottom: 0;
height: auto; height: auto;
z-index: 9; z-index: 9;
} }

View File

@@ -1,41 +1,41 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
CodeMirror.defineOption("fullScreen", false, function(cm, val, old) { CodeMirror.defineOption("fullScreen", false, function(cm, val, old) {
if (old == CodeMirror.Init) old = false; if (old == CodeMirror.Init) old = false;
if (!old == !val) return; if (!old == !val) return;
if (val) setFullscreen(cm); if (val) setFullscreen(cm);
else setNormal(cm); else setNormal(cm);
}); });
function setFullscreen(cm) { function setFullscreen(cm) {
var wrap = cm.getWrapperElement(); var wrap = cm.getWrapperElement();
cm.state.fullScreenRestore = {scrollTop: window.pageYOffset, scrollLeft: window.pageXOffset, cm.state.fullScreenRestore = {scrollTop: window.pageYOffset, scrollLeft: window.pageXOffset,
width: wrap.style.width, height: wrap.style.height}; width: wrap.style.width, height: wrap.style.height};
wrap.style.width = ""; wrap.style.width = "";
wrap.style.height = "auto"; wrap.style.height = "auto";
wrap.className += " CodeMirror-fullscreen"; wrap.className += " CodeMirror-fullscreen";
document.documentElement.style.overflow = "hidden"; document.documentElement.style.overflow = "hidden";
cm.refresh(); cm.refresh();
} }
function setNormal(cm) { function setNormal(cm) {
var wrap = cm.getWrapperElement(); var wrap = cm.getWrapperElement();
wrap.className = wrap.className.replace(/\s*CodeMirror-fullscreen\b/, ""); wrap.className = wrap.className.replace(/\s*CodeMirror-fullscreen\b/, "");
document.documentElement.style.overflow = ""; document.documentElement.style.overflow = "";
var info = cm.state.fullScreenRestore; var info = cm.state.fullScreenRestore;
wrap.style.width = info.width; wrap.style.height = info.height; wrap.style.width = info.width; wrap.style.height = info.height;
window.scrollTo(info.scrollLeft, info.scrollTop); window.scrollTo(info.scrollLeft, info.scrollTop);
cm.refresh(); cm.refresh();
} }
}); });

View File

@@ -1,112 +1,112 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
CodeMirror.defineExtension("addPanel", function(node, options) { CodeMirror.defineExtension("addPanel", function(node, options) {
options = 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;
var wrapper = info.wrapper; var wrapper = info.wrapper;
var cmWrapper = this.getWrapperElement(); var cmWrapper = this.getWrapperElement();
if (options.after instanceof Panel && !options.after.cleared) { if (options.after instanceof Panel && !options.after.cleared) {
wrapper.insertBefore(node, options.before.node.nextSibling); wrapper.insertBefore(node, options.before.node.nextSibling);
} else if (options.before instanceof Panel && !options.before.cleared) { } else if (options.before instanceof Panel && !options.before.cleared) {
wrapper.insertBefore(node, options.before.node); wrapper.insertBefore(node, options.before.node);
} else if (options.replace instanceof Panel && !options.replace.cleared) { } else if (options.replace instanceof Panel && !options.replace.cleared) {
wrapper.insertBefore(node, options.replace.node); wrapper.insertBefore(node, options.replace.node);
options.replace.clear(); options.replace.clear();
} else if (options.position == "bottom") { } else if (options.position == "bottom") {
wrapper.appendChild(node); wrapper.appendChild(node);
} else if (options.position == "before-bottom") { } else if (options.position == "before-bottom") {
wrapper.insertBefore(node, cmWrapper.nextSibling); wrapper.insertBefore(node, cmWrapper.nextSibling);
} else if (options.position == "after-top") { } else if (options.position == "after-top") {
wrapper.insertBefore(node, cmWrapper); wrapper.insertBefore(node, cmWrapper);
} else { } else {
wrapper.insertBefore(node, wrapper.firstChild); 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++;
return new Panel(this, node, options, height); return new Panel(this, node, options, height);
}); });
function Panel(cm, node, options, height) { function Panel(cm, node, options, height) {
this.cm = cm; this.cm = cm;
this.node = node; this.node = node;
this.options = options; this.options = options;
this.height = height; this.height = height;
this.cleared = false; this.cleared = false;
} }
Panel.prototype.clear = function() { Panel.prototype.clear = function() {
if (this.cleared) return; if (this.cleared) return;
this.cleared = true; this.cleared = true;
var info = this.cm.state.panels; var info = this.cm.state.panels;
this.cm._setSize(null, info.heightLeft += this.height); this.cm._setSize(null, info.heightLeft += this.height);
info.wrapper.removeChild(this.node); info.wrapper.removeChild(this.node);
if (--info.panels == 0) removePanels(this.cm); if (--info.panels == 0) removePanels(this.cm);
}; };
Panel.prototype.changed = function(height) { Panel.prototype.changed = function(height) {
var newHeight = height == null ? this.node.offsetHeight : height; var newHeight = height == null ? this.node.offsetHeight : height;
var info = this.cm.state.panels; var info = this.cm.state.panels;
this.cm._setSize(null, info.height += (newHeight - this.height)); this.cm._setSize(null, info.height += (newHeight - this.height));
this.height = newHeight; this.height = newHeight;
}; };
function initPanels(cm) { function initPanels(cm) {
var wrap = cm.getWrapperElement(); var wrap = cm.getWrapperElement();
var style = window.getComputedStyle ? window.getComputedStyle(wrap) : wrap.currentStyle; var style = window.getComputedStyle ? window.getComputedStyle(wrap) : wrap.currentStyle;
var height = parseInt(style.height); var height = parseInt(style.height);
var info = cm.state.panels = { var info = cm.state.panels = {
setHeight: wrap.style.height, setHeight: wrap.style.height,
heightLeft: height, heightLeft: height,
panels: 0, panels: 0,
wrapper: document.createElement("div") wrapper: document.createElement("div")
}; };
wrap.parentNode.insertBefore(info.wrapper, wrap); wrap.parentNode.insertBefore(info.wrapper, wrap);
var hasFocus = cm.hasFocus(); var hasFocus = cm.hasFocus();
info.wrapper.appendChild(wrap); info.wrapper.appendChild(wrap);
if (hasFocus) cm.focus(); if (hasFocus) cm.focus();
cm._setSize = cm.setSize; cm._setSize = cm.setSize;
if (height != null) cm.setSize = function(width, newHeight) { if (height != null) cm.setSize = function(width, newHeight) {
if (newHeight == null) return this._setSize(width, newHeight); if (newHeight == null) return this._setSize(width, newHeight);
info.setHeight = newHeight; info.setHeight = newHeight;
if (typeof newHeight != "number") { if (typeof newHeight != "number") {
var px = /^(\d+\.?\d*)px$/.exec(newHeight); var px = /^(\d+\.?\d*)px$/.exec(newHeight);
if (px) { if (px) {
newHeight = Number(px[1]); newHeight = Number(px[1]);
} else { } else {
info.wrapper.style.height = newHeight; info.wrapper.style.height = newHeight;
newHeight = info.wrapper.offsetHeight; newHeight = info.wrapper.offsetHeight;
info.wrapper.style.height = ""; info.wrapper.style.height = "";
} }
} }
cm._setSize(width, info.heightLeft += (newHeight - height)); cm._setSize(width, info.heightLeft += (newHeight - height));
height = newHeight; height = newHeight;
}; };
} }
function removePanels(cm) { function removePanels(cm) {
var info = cm.state.panels; var info = cm.state.panels;
cm.state.panels = null; cm.state.panels = null;
var wrap = cm.getWrapperElement(); var wrap = cm.getWrapperElement();
info.wrapper.parentNode.replaceChild(wrap, info.wrapper); info.wrapper.parentNode.replaceChild(wrap, info.wrapper);
wrap.style.height = info.setHeight; wrap.style.height = info.setHeight;
cm.setSize = cm._setSize; cm.setSize = cm._setSize;
cm.setSize(); cm.setSize();
} }
}); });

View File

@@ -1,62 +1,62 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
CodeMirror.defineOption("placeholder", "", function(cm, val, old) { CodeMirror.defineOption("placeholder", "", function(cm, val, old) {
var prev = old && old != CodeMirror.Init; var prev = old && old != CodeMirror.Init;
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); 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); 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", "");
} }
if (val && !cm.hasFocus()) onBlur(cm); if (val && !cm.hasFocus()) onBlur(cm);
}); });
function clearPlaceholder(cm) { function clearPlaceholder(cm) {
if (cm.state.placeholder) { if (cm.state.placeholder) {
cm.state.placeholder.parentNode.removeChild(cm.state.placeholder); cm.state.placeholder.parentNode.removeChild(cm.state.placeholder);
cm.state.placeholder = null; cm.state.placeholder = null;
} }
} }
function setPlaceholder(cm) { function setPlaceholder(cm) {
clearPlaceholder(cm); clearPlaceholder(cm);
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";
var placeHolder = cm.getOption("placeholder") var placeHolder = cm.getOption("placeholder")
if (typeof placeHolder == "string") placeHolder = document.createTextNode(placeHolder) if (typeof placeHolder == "string") placeHolder = document.createTextNode(placeHolder)
elt.appendChild(placeHolder) elt.appendChild(placeHolder)
cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild); cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild);
} }
function onBlur(cm) { function onBlur(cm) {
if (isEmpty(cm)) setPlaceholder(cm); if (isEmpty(cm)) setPlaceholder(cm);
} }
function onChange(cm) { function onChange(cm) {
var wrapper = cm.getWrapperElement(), empty = isEmpty(cm); var wrapper = cm.getWrapperElement(), empty = isEmpty(cm);
wrapper.className = wrapper.className.replace(" CodeMirror-empty", "") + (empty ? " CodeMirror-empty" : ""); wrapper.className = wrapper.className.replace(" CodeMirror-empty", "") + (empty ? " CodeMirror-empty" : "");
if (empty) setPlaceholder(cm); if (empty) setPlaceholder(cm);
else clearPlaceholder(cm); else clearPlaceholder(cm);
} }
function isEmpty(cm) { function isEmpty(cm) {
return (cm.lineCount() === 1) && (cm.getLine(0) === ""); return (cm.lineCount() === 1) && (cm.getLine(0) === "");
} }
}); });

View File

@@ -1,63 +1,63 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
CodeMirror.defineOption("rulers", false, function(cm, val, old) { CodeMirror.defineOption("rulers", false, function(cm, val, old) {
if (old && old != CodeMirror.Init) { if (old && old != CodeMirror.Init) {
clearRulers(cm); clearRulers(cm);
cm.off("refresh", refreshRulers); cm.off("refresh", refreshRulers);
} }
if (val && val.length) { if (val && val.length) {
setRulers(cm); setRulers(cm);
cm.on("refresh", refreshRulers); cm.on("refresh", refreshRulers);
} }
}); });
function clearRulers(cm) { function clearRulers(cm) {
for (var i = cm.display.lineSpace.childNodes.length - 1; i >= 0; i--) { for (var i = cm.display.lineSpace.childNodes.length - 1; i >= 0; i--) {
var node = cm.display.lineSpace.childNodes[i]; var node = cm.display.lineSpace.childNodes[i];
if (/(^|\s)CodeMirror-ruler($|\s)/.test(node.className)) if (/(^|\s)CodeMirror-ruler($|\s)/.test(node.className))
node.parentNode.removeChild(node); node.parentNode.removeChild(node);
} }
} }
function setRulers(cm) { function setRulers(cm) {
var val = cm.getOption("rulers"); var val = cm.getOption("rulers");
var cw = cm.defaultCharWidth(); var cw = cm.defaultCharWidth();
var left = cm.charCoords(CodeMirror.Pos(cm.firstLine(), 0), "div").left; var left = cm.charCoords(CodeMirror.Pos(cm.firstLine(), 0), "div").left;
var minH = cm.display.scroller.offsetHeight + 30; var minH = cm.display.scroller.offsetHeight + 30;
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, conf = val[i]; var col, conf = val[i];
if (typeof conf == "number") { if (typeof conf == "number") {
col = conf; col = conf;
} else { } else {
col = conf.column; col = conf.column;
if (conf.className) elt.className += " " + conf.className; if (conf.className) elt.className += " " + conf.className;
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;
} }
elt.style.left = (left + col * cw) + "px"; elt.style.left = (left + col * cw) + "px";
elt.style.top = "-50px"; elt.style.top = "-50px";
elt.style.bottom = "-20px"; elt.style.bottom = "-20px";
elt.style.minHeight = minH + "px"; elt.style.minHeight = minH + "px";
cm.display.lineSpace.insertBefore(elt, cm.display.cursorDiv); cm.display.lineSpace.insertBefore(elt, cm.display.cursorDiv);
} }
} }
function refreshRulers(cm) { function refreshRulers(cm) {
clearRulers(cm); clearRulers(cm);
setRulers(cm); setRulers(cm);
} }
}); });

View File

@@ -1,195 +1,195 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
var defaults = { var defaults = {
pairs: "()[]{}''\"\"", pairs: "()[]{}''\"\"",
triples: "", triples: "",
explode: "[]{}" explode: "[]{}"
}; };
var Pos = CodeMirror.Pos; var Pos = CodeMirror.Pos;
CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) { CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) {
if (old && old != CodeMirror.Init) { if (old && old != CodeMirror.Init) {
cm.removeKeyMap(keyMap); cm.removeKeyMap(keyMap);
cm.state.closeBrackets = null; cm.state.closeBrackets = null;
} }
if (val) { if (val) {
cm.state.closeBrackets = val; cm.state.closeBrackets = val;
cm.addKeyMap(keyMap); cm.addKeyMap(keyMap);
} }
}); });
function getOption(conf, name) { function getOption(conf, name) {
if (name == "pairs" && typeof conf == "string") return conf; if (name == "pairs" && typeof conf == "string") return conf;
if (typeof conf == "object" && conf[name] != null) return conf[name]; if (typeof conf == "object" && conf[name] != null) return conf[name];
return defaults[name]; return defaults[name];
} }
var bind = defaults.pairs + "`"; var bind = defaults.pairs + "`";
var keyMap = {Backspace: handleBackspace, Enter: handleEnter}; var keyMap = {Backspace: handleBackspace, Enter: handleEnter};
for (var i = 0; i < bind.length; i++) for (var i = 0; i < bind.length; i++)
keyMap["'" + bind.charAt(i) + "'"] = handler(bind.charAt(i)); keyMap["'" + bind.charAt(i) + "'"] = handler(bind.charAt(i));
function handler(ch) { function handler(ch) {
return function(cm) { return handleChar(cm, ch); }; return function(cm) { return handleChar(cm, ch); };
} }
function getConfig(cm) { function getConfig(cm) {
var deflt = cm.state.closeBrackets; var deflt = cm.state.closeBrackets;
if (!deflt) return null; if (!deflt) return null;
var mode = cm.getModeAt(cm.getCursor()); var mode = cm.getModeAt(cm.getCursor());
return mode.closeBrackets || deflt; return mode.closeBrackets || deflt;
} }
function handleBackspace(cm) { function handleBackspace(cm) {
var conf = getConfig(cm); var conf = getConfig(cm);
if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass; if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass;
var pairs = getOption(conf, "pairs"); var pairs = getOption(conf, "pairs");
var ranges = cm.listSelections(); var ranges = cm.listSelections();
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 around = charsAround(cm, ranges[i].head); var around = charsAround(cm, ranges[i].head);
if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass; if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass;
} }
for (var i = ranges.length - 1; i >= 0; i--) { for (var i = ranges.length - 1; i >= 0; i--) {
var cur = ranges[i].head; var cur = ranges[i].head;
cm.replaceRange("", Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1), "+delete"); cm.replaceRange("", Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1), "+delete");
} }
} }
function handleEnter(cm) { function handleEnter(cm) {
var conf = getConfig(cm); var conf = getConfig(cm);
var explode = conf && getOption(conf, "explode"); var explode = conf && getOption(conf, "explode");
if (!explode || cm.getOption("disableInput")) return CodeMirror.Pass; if (!explode || cm.getOption("disableInput")) return CodeMirror.Pass;
var ranges = cm.listSelections(); var ranges = cm.listSelections();
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 around = charsAround(cm, ranges[i].head); var around = charsAround(cm, ranges[i].head);
if (!around || explode.indexOf(around) % 2 != 0) return CodeMirror.Pass; if (!around || explode.indexOf(around) % 2 != 0) return CodeMirror.Pass;
} }
cm.operation(function() { cm.operation(function() {
cm.replaceSelection("\n\n", null); cm.replaceSelection("\n\n", null);
cm.execCommand("goCharLeft"); cm.execCommand("goCharLeft");
ranges = cm.listSelections(); ranges = cm.listSelections();
for (var i = 0; i < ranges.length; i++) { for (var i = 0; i < ranges.length; i++) {
var line = ranges[i].head.line; var line = ranges[i].head.line;
cm.indentLine(line, null, true); cm.indentLine(line, null, true);
cm.indentLine(line + 1, null, true); cm.indentLine(line + 1, null, true);
} }
}); });
} }
function contractSelection(sel) { function contractSelection(sel) {
var inverted = CodeMirror.cmpPos(sel.anchor, sel.head) > 0; var inverted = CodeMirror.cmpPos(sel.anchor, sel.head) > 0;
return {anchor: new Pos(sel.anchor.line, sel.anchor.ch + (inverted ? -1 : 1)), return {anchor: new Pos(sel.anchor.line, sel.anchor.ch + (inverted ? -1 : 1)),
head: new Pos(sel.head.line, sel.head.ch + (inverted ? 1 : -1))}; head: new Pos(sel.head.line, sel.head.ch + (inverted ? 1 : -1))};
} }
function handleChar(cm, ch) { function handleChar(cm, ch) {
var conf = getConfig(cm); var conf = getConfig(cm);
if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass; if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass;
var pairs = getOption(conf, "pairs"); var pairs = getOption(conf, "pairs");
var pos = pairs.indexOf(ch); var pos = pairs.indexOf(ch);
if (pos == -1) return CodeMirror.Pass; if (pos == -1) return CodeMirror.Pass;
var triples = getOption(conf, "triples"); var triples = getOption(conf, "triples");
var identical = pairs.charAt(pos + 1) == ch; var identical = pairs.charAt(pos + 1) == ch;
var ranges = cm.listSelections(); var ranges = cm.listSelections();
var opening = pos % 2 == 0; var opening = pos % 2 == 0;
var type, next; var type, next;
for (var i = 0; i < ranges.length; i++) { for (var i = 0; i < ranges.length; i++) {
var range = ranges[i], cur = range.head, curType; var range = ranges[i], cur = range.head, curType;
var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1)); var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1));
if (opening && !range.empty()) { if (opening && !range.empty()) {
curType = "surround"; curType = "surround";
} else if ((identical || !opening) && next == ch) { } else if ((identical || !opening) && next == ch) {
if (triples.indexOf(ch) >= 0 && cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == ch + ch + ch) if (triples.indexOf(ch) >= 0 && cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == ch + ch + ch)
curType = "skipThree"; curType = "skipThree";
else else
curType = "skip"; curType = "skip";
} else if (identical && cur.ch > 1 && triples.indexOf(ch) >= 0 && } else if (identical && cur.ch > 1 && triples.indexOf(ch) >= 0 &&
cm.getRange(Pos(cur.line, cur.ch - 2), cur) == ch + ch && cm.getRange(Pos(cur.line, cur.ch - 2), cur) == ch + ch &&
(cur.ch <= 2 || cm.getRange(Pos(cur.line, cur.ch - 3), Pos(cur.line, cur.ch - 2)) != ch)) { (cur.ch <= 2 || cm.getRange(Pos(cur.line, cur.ch - 3), Pos(cur.line, cur.ch - 2)) != ch)) {
curType = "addFour"; curType = "addFour";
} else if (identical) { } else if (identical) {
if (!CodeMirror.isWordChar(next) && enteringString(cm, cur, ch)) curType = "both"; if (!CodeMirror.isWordChar(next) && enteringString(cm, cur, ch)) curType = "both";
else return CodeMirror.Pass; else return CodeMirror.Pass;
} else if (opening && (cm.getLine(cur.line).length == cur.ch || } else if (opening && (cm.getLine(cur.line).length == cur.ch ||
isClosingBracket(next, pairs) || isClosingBracket(next, pairs) ||
/\s/.test(next))) { /\s/.test(next))) {
curType = "both"; curType = "both";
} else { } else {
return CodeMirror.Pass; return CodeMirror.Pass;
} }
if (!type) type = curType; if (!type) type = curType;
else if (type != curType) return CodeMirror.Pass; else if (type != curType) return CodeMirror.Pass;
} }
var left = pos % 2 ? pairs.charAt(pos - 1) : ch; var left = pos % 2 ? pairs.charAt(pos - 1) : ch;
var right = pos % 2 ? ch : pairs.charAt(pos + 1); var right = pos % 2 ? ch : pairs.charAt(pos + 1);
cm.operation(function() { cm.operation(function() {
if (type == "skip") { if (type == "skip") {
cm.execCommand("goCharRight"); cm.execCommand("goCharRight");
} else if (type == "skipThree") { } else if (type == "skipThree") {
for (var i = 0; i < 3; i++) for (var i = 0; i < 3; i++)
cm.execCommand("goCharRight"); cm.execCommand("goCharRight");
} else if (type == "surround") { } else if (type == "surround") {
var sels = cm.getSelections(); var sels = cm.getSelections();
for (var i = 0; i < sels.length; i++) for (var i = 0; i < sels.length; i++)
sels[i] = left + sels[i] + right; sels[i] = left + sels[i] + right;
cm.replaceSelections(sels, "around"); cm.replaceSelections(sels, "around");
sels = cm.listSelections().slice(); sels = cm.listSelections().slice();
for (var i = 0; i < sels.length; i++) for (var i = 0; i < sels.length; i++)
sels[i] = contractSelection(sels[i]); sels[i] = contractSelection(sels[i]);
cm.setSelections(sels); cm.setSelections(sels);
} else if (type == "both") { } else if (type == "both") {
cm.replaceSelection(left + right, null); cm.replaceSelection(left + right, null);
cm.triggerElectric(left + right); cm.triggerElectric(left + right);
cm.execCommand("goCharLeft"); cm.execCommand("goCharLeft");
} else if (type == "addFour") { } else if (type == "addFour") {
cm.replaceSelection(left + left + left + left, "before"); cm.replaceSelection(left + left + left + left, "before");
cm.execCommand("goCharRight"); cm.execCommand("goCharRight");
} }
}); });
} }
function isClosingBracket(ch, pairs) { function isClosingBracket(ch, pairs) {
var pos = pairs.lastIndexOf(ch); var pos = pairs.lastIndexOf(ch);
return pos > -1 && pos % 2 == 1; return pos > -1 && pos % 2 == 1;
} }
function charsAround(cm, pos) { function charsAround(cm, pos) {
var str = cm.getRange(Pos(pos.line, pos.ch - 1), var str = cm.getRange(Pos(pos.line, pos.ch - 1),
Pos(pos.line, pos.ch + 1)); Pos(pos.line, pos.ch + 1));
return str.length == 2 ? str : null; return str.length == 2 ? str : null;
} }
// Project the token type that will exists after the given char is // Project the token type that will exists after the given char is
// typed, and use it to determine whether it would cause the start // typed, and use it to determine whether it would cause the start
// of a string token. // of a string token.
function enteringString(cm, pos, ch) { function enteringString(cm, pos, ch) {
var line = cm.getLine(pos.line); var line = cm.getLine(pos.line);
var token = cm.getTokenAt(pos); var token = cm.getTokenAt(pos);
if (/\bstring2?\b/.test(token.type)) return false; if (/\bstring2?\b/.test(token.type)) return false;
var stream = new CodeMirror.StringStream(line.slice(0, pos.ch) + ch + line.slice(pos.ch), 4); var stream = new CodeMirror.StringStream(line.slice(0, pos.ch) + ch + line.slice(pos.ch), 4);
stream.pos = stream.start = token.start; stream.pos = stream.start = token.start;
for (;;) { for (;;) {
var type1 = cm.getMode().token(stream, token.state); var type1 = cm.getMode().token(stream, token.state);
if (stream.pos >= pos.ch + 1) return /\bstring2?\b/.test(type1); if (stream.pos >= pos.ch + 1) return /\bstring2?\b/.test(type1);
stream.start = stream.pos; stream.start = stream.pos;
} }
} }
}); });

View File

@@ -1,169 +1,169 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
/** /**
* Tag-closer extension for CodeMirror. * Tag-closer extension for CodeMirror.
* *
* This extension adds an "autoCloseTags" option that can be set to * This extension adds an "autoCloseTags" option that can be set to
* either true to get the default behavior, or an object to further * either true to get the default behavior, or an object to further
* configure its behavior. * configure its behavior.
* *
* These are supported options: * These are supported options:
* *
* `whenClosing` (default true) * `whenClosing` (default true)
* Whether to autoclose when the '/' of a closing tag is typed. * Whether to autoclose when the '/' of a closing tag is typed.
* `whenOpening` (default true) * `whenOpening` (default true)
* Whether to autoclose the tag when the final '>' of an opening * Whether to autoclose the tag when the final '>' of an opening
* tag is typed. * tag is typed.
* `dontCloseTags` (default is empty tags for HTML, none for XML) * `dontCloseTags` (default is empty tags for HTML, none for XML)
* An array of tag names that should not be autoclosed. * An array of tag names that should not be autoclosed.
* `indentTags` (default is block tags for HTML, none for XML) * `indentTags` (default is block tags for HTML, none for XML)
* An array of tag names that should, when opened, cause a * An array of tag names that should, when opened, cause a
* blank line to be added inside the tag, and the blank line and * blank line to be added inside the tag, and the blank line and
* closing line to be indented. * closing line to be indented.
* *
* See demos/closetag.html for a usage example. * See demos/closetag.html for a usage example.
*/ */
(function(mod) { (function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("../fold/xml-fold")); mod(require("../../lib/codemirror"), require("../fold/xml-fold"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "../fold/xml-fold"], mod); define(["../../lib/codemirror", "../fold/xml-fold"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
CodeMirror.defineOption("autoCloseTags", false, function(cm, val, old) { CodeMirror.defineOption("autoCloseTags", false, function(cm, val, old) {
if (old != CodeMirror.Init && old) if (old != CodeMirror.Init && old)
cm.removeKeyMap("autoCloseTags"); cm.removeKeyMap("autoCloseTags");
if (!val) return; if (!val) return;
var map = {name: "autoCloseTags"}; var map = {name: "autoCloseTags"};
if (typeof val != "object" || val.whenClosing) if (typeof val != "object" || val.whenClosing)
map["'/'"] = function(cm) { return autoCloseSlash(cm); }; map["'/'"] = function(cm) { return autoCloseSlash(cm); };
if (typeof val != "object" || val.whenOpening) if (typeof val != "object" || val.whenOpening)
map["'>'"] = function(cm) { return autoCloseGT(cm); }; map["'>'"] = function(cm) { return autoCloseGT(cm); };
cm.addKeyMap(map); cm.addKeyMap(map);
}); });
var htmlDontClose = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", var htmlDontClose = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param",
"source", "track", "wbr"]; "source", "track", "wbr"];
var htmlIndent = ["applet", "blockquote", "body", "button", "div", "dl", "fieldset", "form", "frameset", "h1", "h2", "h3", "h4", var htmlIndent = ["applet", "blockquote", "body", "button", "div", "dl", "fieldset", "form", "frameset", "h1", "h2", "h3", "h4",
"h5", "h6", "head", "html", "iframe", "layer", "legend", "object", "ol", "p", "select", "table", "ul"]; "h5", "h6", "head", "html", "iframe", "layer", "legend", "object", "ol", "p", "select", "table", "ul"];
function autoCloseGT(cm) { function autoCloseGT(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++) {
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 (inner.mode.name != "xml" || !state.tagName) return CodeMirror.Pass; if (inner.mode.name != "xml" || !state.tagName) return CodeMirror.Pass;
var opt = cm.getOption("autoCloseTags"), html = inner.mode.configuration == "html"; var opt = cm.getOption("autoCloseTags"), html = inner.mode.configuration == "html";
var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose); var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose);
var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent); var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent);
var tagName = state.tagName; var tagName = state.tagName;
if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch); if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch);
var lowerTagName = tagName.toLowerCase(); var lowerTagName = tagName.toLowerCase();
// Don't process the '>' at the end of an end-tag or self-closing tag // Don't process the '>' at the end of an end-tag or self-closing tag
if (!tagName || if (!tagName ||
tok.type == "string" && (tok.end != pos.ch || !/[\"\']/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1) || tok.type == "string" && (tok.end != pos.ch || !/[\"\']/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1) ||
tok.type == "tag" && state.type == "closeTag" || tok.type == "tag" && state.type == "closeTag" ||
tok.string.indexOf("/") == (tok.string.length - 1) || // match something like <someTagName /> tok.string.indexOf("/") == (tok.string.length - 1) || // match something like <someTagName />
dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1 || dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1 ||
closingTagExists(cm, tagName, pos, state, true)) closingTagExists(cm, tagName, pos, state, true))
return CodeMirror.Pass; return CodeMirror.Pass;
var indent = indentTags && indexOf(indentTags, lowerTagName) > -1; var indent = indentTags && indexOf(indentTags, lowerTagName) > -1;
replacements[i] = {indent: indent, replacements[i] = {indent: indent,
text: ">" + (indent ? "\n\n" : "") + "</" + tagName + ">", text: ">" + (indent ? "\n\n" : "") + "</" + tagName + ">",
newPos: indent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1)}; newPos: indent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1)};
} }
for (var i = ranges.length - 1; i >= 0; i--) { for (var i = ranges.length - 1; i >= 0; i--) {
var info = replacements[i]; var info = replacements[i];
cm.replaceRange(info.text, ranges[i].head, ranges[i].anchor, "+insert"); cm.replaceRange(info.text, ranges[i].head, ranges[i].anchor, "+insert");
var sel = cm.listSelections().slice(0); var sel = cm.listSelections().slice(0);
sel[i] = {head: info.newPos, anchor: info.newPos}; sel[i] = {head: info.newPos, anchor: info.newPos};
cm.setSelections(sel); cm.setSelections(sel);
if (info.indent) { if (info.indent) {
cm.indentLine(info.newPos.line, null, true); cm.indentLine(info.newPos.line, null, true);
cm.indentLine(info.newPos.line + 1, null, true); cm.indentLine(info.newPos.line + 1, null, true);
} }
} }
} }
function autoCloseCurrent(cm, typingSlash) { function autoCloseCurrent(cm, typingSlash) {
var ranges = cm.listSelections(), replacements = []; var ranges = cm.listSelections(), replacements = [];
var head = typingSlash ? "/" : "</"; 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 (typingSlash && (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; 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")
replacement = head + "script"; replacement = head + "script";
else if (cm.getMode().name == "htmlmixed" && inner.mode.name == "css") else if (cm.getMode().name == "htmlmixed" && inner.mode.name == "css")
replacement = head + "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;
replacement = head + state.context.tagName; replacement = head + state.context.tagName;
} }
if (cm.getLine(pos.line).charAt(tok.end) != ">") replacement += ">"; if (cm.getLine(pos.line).charAt(tok.end) != ">") replacement += ">";
replacements[i] = replacement; replacements[i] = replacement;
} }
cm.replaceSelections(replacements); cm.replaceSelections(replacements);
ranges = cm.listSelections(); ranges = cm.listSelections();
for (var i = 0; i < ranges.length; i++) for (var i = 0; i < ranges.length; i++)
if (i == ranges.length - 1 || ranges[i].head.line < ranges[i + 1].head.line) if (i == ranges.length - 1 || ranges[i].head.line < ranges[i + 1].head.line)
cm.indentLine(ranges[i].head.line); cm.indentLine(ranges[i].head.line);
} }
function autoCloseSlash(cm) { function autoCloseSlash(cm) {
if (cm.getOption("disableInput")) return CodeMirror.Pass; if (cm.getOption("disableInput")) return CodeMirror.Pass;
return autoCloseCurrent(cm, true); return autoCloseCurrent(cm, true);
} }
CodeMirror.commands.closeTag = function(cm) { return autoCloseCurrent(cm); }; 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)
if (collection[i] == elt) return i; if (collection[i] == elt) return i;
return -1; return -1;
} }
// If xml-fold is loaded, we use its functionality to try and verify // If xml-fold is loaded, we use its functionality to try and verify
// whether a given tag is actually unclosed. // whether a given tag is actually unclosed.
function closingTagExists(cm, tagName, pos, state, newTag) { function closingTagExists(cm, tagName, pos, state, newTag) {
if (!CodeMirror.scanForClosingTag) return false; if (!CodeMirror.scanForClosingTag) return false;
var end = Math.min(cm.lastLine() + 1, pos.line + 500); var end = Math.min(cm.lastLine() + 1, pos.line + 500);
var nextClose = CodeMirror.scanForClosingTag(cm, pos, null, end); var nextClose = CodeMirror.scanForClosingTag(cm, pos, null, end);
if (!nextClose || nextClose.tag != tagName) return false; if (!nextClose || nextClose.tag != tagName) return false;
var cx = state.context; var cx = state.context;
// If the immediate wrapping context contains onCx instances of // If the immediate wrapping context contains onCx instances of
// the same tag, a closing tag only exists if there are at least // the same tag, a closing tag only exists if there are at least
// that many closing tags of that type following. // that many closing tags of that type following.
for (var onCx = newTag ? 1 : 0; cx && cx.tagName == tagName; cx = cx.prev) ++onCx; for (var onCx = newTag ? 1 : 0; cx && cx.tagName == tagName; cx = cx.prev) ++onCx;
pos = nextClose.to; pos = nextClose.to;
for (var i = 1; i < onCx; i++) { for (var i = 1; i < onCx; i++) {
var next = CodeMirror.scanForClosingTag(cm, pos, null, end); var next = CodeMirror.scanForClosingTag(cm, pos, null, end);
if (!next || next.tag != tagName) return false; if (!next || next.tag != tagName) return false;
pos = next.to; pos = next.to;
} }
return true; return true;
} }
}); });

View File

@@ -1,51 +1,51 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(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; 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 !== 0; var inQuote = eolState.quote !== 0;
var line = cm.getLine(pos.line), match = listRE.exec(line); var line = cm.getLine(pos.line), match = listRE.exec(line);
if (!ranges[i].empty() || (!inList && !inQuote) || !match) { if (!ranges[i].empty() || (!inList && !inQuote) || !match) {
cm.execCommand("newlineAndIndent"); cm.execCommand("newlineAndIndent");
return; return;
} }
if (emptyListRE.test(line)) { 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[5]; 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) + match[4]; : (parseInt(match[3], 10) + 1) + match[4];
replacements[i] = "\n" + indent + bullet + after; replacements[i] = "\n" + indent + bullet + after;
} }
} }
cm.replaceSelections(replacements); cm.replaceSelections(replacements);
}; };
}); });

View File

@@ -1,120 +1,120 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
var ie_lt8 = /MSIE \d/.test(navigator.userAgent) && var ie_lt8 = /MSIE \d/.test(navigator.userAgent) &&
(document.documentMode == null || document.documentMode < 8); (document.documentMode == null || document.documentMode < 8);
var Pos = CodeMirror.Pos; var Pos = CodeMirror.Pos;
var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"}; var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"};
function findMatchingBracket(cm, where, strict, config) { function findMatchingBracket(cm, where, strict, config) {
var line = cm.getLineHandle(where.line), pos = where.ch - 1; var line = cm.getLineHandle(where.line), pos = where.ch - 1;
var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)]; var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)];
if (!match) return null; if (!match) return null;
var dir = match.charAt(1) == ">" ? 1 : -1; var dir = match.charAt(1) == ">" ? 1 : -1;
if (strict && (dir > 0) != (pos == where.ch)) return null; if (strict && (dir > 0) != (pos == where.ch)) return null;
var style = cm.getTokenTypeAt(Pos(where.line, pos + 1)); var style = cm.getTokenTypeAt(Pos(where.line, pos + 1));
var found = scanForBracket(cm, Pos(where.line, pos + (dir > 0 ? 1 : 0)), dir, style || null, config); var found = scanForBracket(cm, Pos(where.line, pos + (dir > 0 ? 1 : 0)), dir, style || null, config);
if (found == null) return null; if (found == null) return null;
return {from: Pos(where.line, pos), to: found && found.pos, return {from: Pos(where.line, pos), to: found && found.pos,
match: found && found.ch == match.charAt(0), forward: dir > 0}; match: found && found.ch == match.charAt(0), forward: dir > 0};
} }
// bracketRegex is used to specify which type of bracket to scan // bracketRegex is used to specify which type of bracket to scan
// should be a regexp, e.g. /[[\]]/ // should be a regexp, e.g. /[[\]]/
// //
// Note: If "where" is on an open bracket, then this bracket is ignored. // Note: If "where" is on an open bracket, then this bracket is ignored.
// //
// Returns false when no bracket was found, null when it reached // Returns false when no bracket was found, null when it reached
// maxScanLines and gave up // maxScanLines and gave up
function scanForBracket(cm, where, dir, style, config) { function scanForBracket(cm, where, dir, style, config) {
var maxScanLen = (config && config.maxScanLineLength) || 10000; var maxScanLen = (config && config.maxScanLineLength) || 10000;
var maxScanLines = (config && config.maxScanLines) || 1000; var maxScanLines = (config && config.maxScanLines) || 1000;
var stack = []; var stack = [];
var re = config && config.bracketRegex ? config.bracketRegex : /[(){}[\]]/; var re = config && config.bracketRegex ? config.bracketRegex : /[(){}[\]]/;
var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1) var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1)
: Math.max(cm.firstLine() - 1, where.line - maxScanLines); : Math.max(cm.firstLine() - 1, where.line - maxScanLines);
for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) { for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) {
var line = cm.getLine(lineNo); var line = cm.getLine(lineNo);
if (!line) continue; if (!line) continue;
var pos = dir > 0 ? 0 : line.length - 1, end = dir > 0 ? line.length : -1; var pos = dir > 0 ? 0 : line.length - 1, end = dir > 0 ? line.length : -1;
if (line.length > maxScanLen) continue; if (line.length > maxScanLen) continue;
if (lineNo == where.line) pos = where.ch - (dir < 0 ? 1 : 0); if (lineNo == where.line) pos = where.ch - (dir < 0 ? 1 : 0);
for (; pos != end; pos += dir) { for (; pos != end; pos += dir) {
var ch = line.charAt(pos); var ch = line.charAt(pos);
if (re.test(ch) && (style === undefined || cm.getTokenTypeAt(Pos(lineNo, pos + 1)) == style)) { if (re.test(ch) && (style === undefined || cm.getTokenTypeAt(Pos(lineNo, pos + 1)) == style)) {
var match = matching[ch]; var match = matching[ch];
if ((match.charAt(1) == ">") == (dir > 0)) stack.push(ch); if ((match.charAt(1) == ">") == (dir > 0)) stack.push(ch);
else if (!stack.length) return {pos: Pos(lineNo, pos), ch: ch}; else if (!stack.length) return {pos: Pos(lineNo, pos), ch: ch};
else stack.pop(); else stack.pop();
} }
} }
} }
return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null; return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null;
} }
function matchBrackets(cm, autoclear, config) { function matchBrackets(cm, autoclear, config) {
// Disable brace matching in long lines, since it'll cause hugely slow updates // Disable brace matching in long lines, since it'll cause hugely slow updates
var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000; var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000;
var marks = [], ranges = cm.listSelections(); var marks = [], ranges = cm.listSelections();
for (var i = 0; i < ranges.length; i++) { for (var i = 0; i < ranges.length; i++) {
var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, false, config); var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, false, config);
if (match && cm.getLine(match.from.line).length <= maxHighlightLen) { if (match && cm.getLine(match.from.line).length <= maxHighlightLen) {
var style = match.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket"; var style = match.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
marks.push(cm.markText(match.from, Pos(match.from.line, match.from.ch + 1), {className: style})); marks.push(cm.markText(match.from, Pos(match.from.line, match.from.ch + 1), {className: style}));
if (match.to && cm.getLine(match.to.line).length <= maxHighlightLen) if (match.to && cm.getLine(match.to.line).length <= maxHighlightLen)
marks.push(cm.markText(match.to, Pos(match.to.line, match.to.ch + 1), {className: style})); marks.push(cm.markText(match.to, Pos(match.to.line, match.to.ch + 1), {className: style}));
} }
} }
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.focus(); if (ie_lt8 && cm.state.focused) cm.focus();
var clear = function() { var clear = function() {
cm.operation(function() { cm.operation(function() {
for (var i = 0; i < marks.length; i++) marks[i].clear(); for (var i = 0; i < marks.length; i++) marks[i].clear();
}); });
}; };
if (autoclear) setTimeout(clear, 800); if (autoclear) setTimeout(clear, 800);
else return clear; else return clear;
} }
} }
var currentlyHighlighted = null; var currentlyHighlighted = null;
function doMatchBrackets(cm) { function doMatchBrackets(cm) {
cm.operation(function() { cm.operation(function() {
if (currentlyHighlighted) {currentlyHighlighted(); currentlyHighlighted = null;} if (currentlyHighlighted) {currentlyHighlighted(); currentlyHighlighted = null;}
currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets); currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets);
}); });
} }
CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) { CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) {
if (old && old != CodeMirror.Init) if (old && old != CodeMirror.Init)
cm.off("cursorActivity", doMatchBrackets); cm.off("cursorActivity", doMatchBrackets);
if (val) { if (val) {
cm.state.matchBrackets = typeof val == "object" ? val : {}; cm.state.matchBrackets = typeof val == "object" ? val : {};
cm.on("cursorActivity", doMatchBrackets); cm.on("cursorActivity", doMatchBrackets);
} }
}); });
CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);}); CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);});
CodeMirror.defineExtension("findMatchingBracket", function(pos, strict, config){ CodeMirror.defineExtension("findMatchingBracket", function(pos, strict, config){
return findMatchingBracket(this, pos, strict, config); return findMatchingBracket(this, pos, strict, config);
}); });
CodeMirror.defineExtension("scanForBracket", function(pos, dir, style, config){ CodeMirror.defineExtension("scanForBracket", function(pos, dir, style, config){
return scanForBracket(this, pos, dir, style, config); return scanForBracket(this, pos, dir, style, config);
}); });
}); });

View File

@@ -1,66 +1,66 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) { (function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("../fold/xml-fold")); mod(require("../../lib/codemirror"), require("../fold/xml-fold"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "../fold/xml-fold"], mod); define(["../../lib/codemirror", "../fold/xml-fold"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
CodeMirror.defineOption("matchTags", false, function(cm, val, old) { CodeMirror.defineOption("matchTags", false, function(cm, val, old) {
if (old && old != CodeMirror.Init) { if (old && old != CodeMirror.Init) {
cm.off("cursorActivity", doMatchTags); cm.off("cursorActivity", doMatchTags);
cm.off("viewportChange", maybeUpdateMatch); cm.off("viewportChange", maybeUpdateMatch);
clear(cm); clear(cm);
} }
if (val) { if (val) {
cm.state.matchBothTags = typeof val == "object" && val.bothTags; cm.state.matchBothTags = typeof val == "object" && val.bothTags;
cm.on("cursorActivity", doMatchTags); cm.on("cursorActivity", doMatchTags);
cm.on("viewportChange", maybeUpdateMatch); cm.on("viewportChange", maybeUpdateMatch);
doMatchTags(cm); doMatchTags(cm);
} }
}); });
function clear(cm) { function clear(cm) {
if (cm.state.tagHit) cm.state.tagHit.clear(); if (cm.state.tagHit) cm.state.tagHit.clear();
if (cm.state.tagOther) cm.state.tagOther.clear(); if (cm.state.tagOther) cm.state.tagOther.clear();
cm.state.tagHit = cm.state.tagOther = null; cm.state.tagHit = cm.state.tagOther = null;
} }
function doMatchTags(cm) { function doMatchTags(cm) {
cm.state.failedTagMatch = false; cm.state.failedTagMatch = false;
cm.operation(function() { cm.operation(function() {
clear(cm); clear(cm);
if (cm.somethingSelected()) return; if (cm.somethingSelected()) return;
var cur = cm.getCursor(), range = cm.getViewport(); var cur = cm.getCursor(), range = cm.getViewport();
range.from = Math.min(range.from, cur.line); range.to = Math.max(cur.line + 1, range.to); range.from = Math.min(range.from, cur.line); range.to = Math.max(cur.line + 1, range.to);
var match = CodeMirror.findMatchingTag(cm, cur, range); var match = CodeMirror.findMatchingTag(cm, cur, range);
if (!match) return; if (!match) return;
if (cm.state.matchBothTags) { if (cm.state.matchBothTags) {
var hit = match.at == "open" ? match.open : match.close; var hit = match.at == "open" ? match.open : match.close;
if (hit) cm.state.tagHit = cm.markText(hit.from, hit.to, {className: "CodeMirror-matchingtag"}); if (hit) cm.state.tagHit = cm.markText(hit.from, hit.to, {className: "CodeMirror-matchingtag"});
} }
var other = match.at == "close" ? match.open : match.close; var other = match.at == "close" ? match.open : match.close;
if (other) if (other)
cm.state.tagOther = cm.markText(other.from, other.to, {className: "CodeMirror-matchingtag"}); cm.state.tagOther = cm.markText(other.from, other.to, {className: "CodeMirror-matchingtag"});
else else
cm.state.failedTagMatch = true; cm.state.failedTagMatch = true;
}); });
} }
function maybeUpdateMatch(cm) { function maybeUpdateMatch(cm) {
if (cm.state.failedTagMatch) doMatchTags(cm); if (cm.state.failedTagMatch) doMatchTags(cm);
} }
CodeMirror.commands.toMatchingTag = function(cm) { CodeMirror.commands.toMatchingTag = function(cm) {
var found = CodeMirror.findMatchingTag(cm, cm.getCursor()); var found = CodeMirror.findMatchingTag(cm, cm.getCursor());
if (found) { if (found) {
var other = found.at == "close" ? found.open : found.close; var other = found.at == "close" ? found.open : found.close;
if (other) cm.extendSelection(other.to, other.from); if (other) cm.extendSelection(other.to, other.from);
} }
}; };
}); });

View File

@@ -1,27 +1,27 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
CodeMirror.defineOption("showTrailingSpace", false, function(cm, val, prev) { CodeMirror.defineOption("showTrailingSpace", false, function(cm, val, prev) {
if (prev == CodeMirror.Init) prev = false; if (prev == CodeMirror.Init) prev = false;
if (prev && !val) if (prev && !val)
cm.removeOverlay("trailingspace"); cm.removeOverlay("trailingspace");
else if (!prev && val) else if (!prev && val)
cm.addOverlay({ cm.addOverlay({
token: function(stream) { token: function(stream) {
for (var l = stream.string.length, i = l; i && /\s/.test(stream.string.charAt(i - 1)); --i) {} for (var l = stream.string.length, i = l; i && /\s/.test(stream.string.charAt(i - 1)); --i) {}
if (i > stream.pos) { stream.pos = i; return null; } if (i > stream.pos) { stream.pos = i; return null; }
stream.pos = l; stream.pos = l;
return "trailingspace"; return "trailingspace";
}, },
name: "trailingspace" name: "trailingspace"
}); });
}); });
}); });

View File

@@ -1,105 +1,105 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
CodeMirror.registerHelper("fold", "brace", function(cm, start) { CodeMirror.registerHelper("fold", "brace", function(cm, start) {
var line = start.line, lineText = cm.getLine(line); var line = start.line, lineText = cm.getLine(line);
var startCh, tokenType; var startCh, tokenType;
function findOpening(openCh) { function findOpening(openCh) {
for (var at = start.ch, pass = 0;;) { for (var at = start.ch, pass = 0;;) {
var found = at <= 0 ? -1 : lineText.lastIndexOf(openCh, at - 1); var found = at <= 0 ? -1 : lineText.lastIndexOf(openCh, at - 1);
if (found == -1) { if (found == -1) {
if (pass == 1) break; if (pass == 1) break;
pass = 1; pass = 1;
at = lineText.length; at = lineText.length;
continue; continue;
} }
if (pass == 1 && found < start.ch) break; if (pass == 1 && found < start.ch) break;
tokenType = cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1)); tokenType = cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1));
if (!/^(comment|string)/.test(tokenType)) return found + 1; if (!/^(comment|string)/.test(tokenType)) return found + 1;
at = found - 1; at = found - 1;
} }
} }
var startToken = "{", endToken = "}", startCh = findOpening("{"); var startToken = "{", endToken = "}", startCh = findOpening("{");
if (startCh == null) { if (startCh == null) {
startToken = "[", endToken = "]"; startToken = "[", endToken = "]";
startCh = findOpening("["); startCh = findOpening("[");
} }
if (startCh == null) return; if (startCh == null) return;
var count = 1, lastLine = cm.lastLine(), end, endCh; var count = 1, lastLine = cm.lastLine(), end, endCh;
outer: for (var i = line; i <= lastLine; ++i) { outer: for (var i = line; i <= lastLine; ++i) {
var text = cm.getLine(i), pos = i == line ? startCh : 0; var text = cm.getLine(i), pos = i == line ? startCh : 0;
for (;;) { for (;;) {
var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos); var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);
if (nextOpen < 0) nextOpen = text.length; if (nextOpen < 0) nextOpen = text.length;
if (nextClose < 0) nextClose = text.length; if (nextClose < 0) nextClose = text.length;
pos = Math.min(nextOpen, nextClose); pos = Math.min(nextOpen, nextClose);
if (pos == text.length) break; if (pos == text.length) break;
if (cm.getTokenTypeAt(CodeMirror.Pos(i, pos + 1)) == tokenType) { if (cm.getTokenTypeAt(CodeMirror.Pos(i, pos + 1)) == tokenType) {
if (pos == nextOpen) ++count; if (pos == nextOpen) ++count;
else if (!--count) { end = i; endCh = pos; break outer; } else if (!--count) { end = i; endCh = pos; break outer; }
} }
++pos; ++pos;
} }
} }
if (end == null || line == end && endCh == startCh) return; if (end == null || line == end && endCh == startCh) return;
return {from: CodeMirror.Pos(line, startCh), return {from: CodeMirror.Pos(line, startCh),
to: CodeMirror.Pos(end, endCh)}; to: CodeMirror.Pos(end, endCh)};
}); });
CodeMirror.registerHelper("fold", "import", function(cm, start) { CodeMirror.registerHelper("fold", "import", function(cm, start) {
function hasImport(line) { function hasImport(line) {
if (line < cm.firstLine() || line > cm.lastLine()) return null; if (line < cm.firstLine() || line > cm.lastLine()) return null;
var start = cm.getTokenAt(CodeMirror.Pos(line, 1)); var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1)); if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
if (start.type != "keyword" || start.string != "import") return null; if (start.type != "keyword" || start.string != "import") return null;
// Now find closing semicolon, return its position // Now find closing semicolon, return its position
for (var i = line, e = Math.min(cm.lastLine(), line + 10); i <= e; ++i) { for (var i = line, e = Math.min(cm.lastLine(), line + 10); i <= e; ++i) {
var text = cm.getLine(i), semi = text.indexOf(";"); var text = cm.getLine(i), semi = text.indexOf(";");
if (semi != -1) return {startCh: start.end, end: CodeMirror.Pos(i, semi)}; if (semi != -1) return {startCh: start.end, end: CodeMirror.Pos(i, semi)};
} }
} }
var start = start.line, has = hasImport(start), prev; var start = start.line, has = hasImport(start), prev;
if (!has || hasImport(start - 1) || ((prev = hasImport(start - 2)) && prev.end.line == start - 1)) if (!has || hasImport(start - 1) || ((prev = hasImport(start - 2)) && prev.end.line == start - 1))
return null; return null;
for (var end = has.end;;) { for (var end = has.end;;) {
var next = hasImport(end.line + 1); var next = hasImport(end.line + 1);
if (next == null) break; if (next == null) break;
end = next.end; end = next.end;
} }
return {from: cm.clipPos(CodeMirror.Pos(start, has.startCh + 1)), to: end}; return {from: cm.clipPos(CodeMirror.Pos(start, has.startCh + 1)), to: end};
}); });
CodeMirror.registerHelper("fold", "include", function(cm, start) { CodeMirror.registerHelper("fold", "include", function(cm, start) {
function hasInclude(line) { function hasInclude(line) {
if (line < cm.firstLine() || line > cm.lastLine()) return null; if (line < cm.firstLine() || line > cm.lastLine()) return null;
var start = cm.getTokenAt(CodeMirror.Pos(line, 1)); var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1)); if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
if (start.type == "meta" && start.string.slice(0, 8) == "#include") return start.start + 8; if (start.type == "meta" && start.string.slice(0, 8) == "#include") return start.start + 8;
} }
var start = start.line, has = hasInclude(start); var start = start.line, has = hasInclude(start);
if (has == null || hasInclude(start - 1) != null) return null; if (has == null || hasInclude(start - 1) != null) return null;
for (var end = start;;) { for (var end = start;;) {
var next = hasInclude(end + 1); var next = hasInclude(end + 1);
if (next == null) break; if (next == null) break;
++end; ++end;
} }
return {from: CodeMirror.Pos(start, has + 1), return {from: CodeMirror.Pos(start, has + 1),
to: cm.clipPos(CodeMirror.Pos(end))}; to: cm.clipPos(CodeMirror.Pos(end))};
}); });
}); });

View File

@@ -1,59 +1,59 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
CodeMirror.registerGlobalHelper("fold", "comment", function(mode) { CodeMirror.registerGlobalHelper("fold", "comment", function(mode) {
return mode.blockCommentStart && mode.blockCommentEnd; return mode.blockCommentStart && mode.blockCommentEnd;
}, function(cm, start) { }, function(cm, start) {
var mode = cm.getModeAt(start), startToken = mode.blockCommentStart, endToken = mode.blockCommentEnd; var mode = cm.getModeAt(start), startToken = mode.blockCommentStart, endToken = mode.blockCommentEnd;
if (!startToken || !endToken) return; if (!startToken || !endToken) return;
var line = start.line, lineText = cm.getLine(line); var line = start.line, lineText = cm.getLine(line);
var startCh; var startCh;
for (var at = start.ch, pass = 0;;) { for (var at = start.ch, pass = 0;;) {
var found = at <= 0 ? -1 : lineText.lastIndexOf(startToken, at - 1); var found = at <= 0 ? -1 : lineText.lastIndexOf(startToken, at - 1);
if (found == -1) { if (found == -1) {
if (pass == 1) return; if (pass == 1) return;
pass = 1; pass = 1;
at = lineText.length; at = lineText.length;
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 || (lineText.slice(found - endToken.length, found) == endToken ||
!/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found))))) { !/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found))))) {
startCh = found + startToken.length; startCh = found + startToken.length;
break; break;
} }
at = found - 1; at = found - 1;
} }
var depth = 1, lastLine = cm.lastLine(), end, endCh; var depth = 1, lastLine = cm.lastLine(), end, endCh;
outer: for (var i = line; i <= lastLine; ++i) { outer: for (var i = line; i <= lastLine; ++i) {
var text = cm.getLine(i), pos = i == line ? startCh : 0; var text = cm.getLine(i), pos = i == line ? startCh : 0;
for (;;) { for (;;) {
var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos); var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);
if (nextOpen < 0) nextOpen = text.length; if (nextOpen < 0) nextOpen = text.length;
if (nextClose < 0) nextClose = text.length; if (nextClose < 0) nextClose = text.length;
pos = Math.min(nextOpen, nextClose); pos = Math.min(nextOpen, nextClose);
if (pos == text.length) break; if (pos == text.length) break;
if (pos == nextOpen) ++depth; if (pos == nextOpen) ++depth;
else if (!--depth) { end = i; endCh = pos; break outer; } else if (!--depth) { end = i; endCh = pos; break outer; }
++pos; ++pos;
} }
} }
if (end == null || line == end && endCh == startCh) return; if (end == null || line == end && endCh == startCh) return;
return {from: CodeMirror.Pos(line, startCh), return {from: CodeMirror.Pos(line, startCh),
to: CodeMirror.Pos(end, endCh)}; to: CodeMirror.Pos(end, endCh)};
}); });
}); });

View File

@@ -1,149 +1,149 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
function doFold(cm, pos, options, force) { function doFold(cm, pos, options, force) {
if (options && options.call) { if (options && options.call) {
var finder = options; var finder = options;
options = null; options = null;
} else { } else {
var finder = getOption(cm, options, "rangeFinder"); var finder = getOption(cm, options, "rangeFinder");
} }
if (typeof pos == "number") pos = CodeMirror.Pos(pos, 0); if (typeof pos == "number") pos = CodeMirror.Pos(pos, 0);
var minSize = getOption(cm, options, "minFoldSize"); var minSize = getOption(cm, options, "minFoldSize");
function getRange(allowFolded) { function getRange(allowFolded) {
var range = finder(cm, pos); var range = finder(cm, pos);
if (!range || range.to.line - range.from.line < minSize) return null; if (!range || range.to.line - range.from.line < minSize) return null;
var marks = cm.findMarksAt(range.from); var marks = cm.findMarksAt(range.from);
for (var i = 0; i < marks.length; ++i) { for (var i = 0; i < marks.length; ++i) {
if (marks[i].__isFold && force !== "fold") { if (marks[i].__isFold && force !== "fold") {
if (!allowFolded) return null; if (!allowFolded) return null;
range.cleared = true; range.cleared = true;
marks[i].clear(); marks[i].clear();
} }
} }
return range; return range;
} }
var range = getRange(true); var range = getRange(true);
if (getOption(cm, options, "scanUp")) while (!range && pos.line > cm.firstLine()) { if (getOption(cm, options, "scanUp")) while (!range && pos.line > cm.firstLine()) {
pos = CodeMirror.Pos(pos.line - 1, 0); pos = CodeMirror.Pos(pos.line - 1, 0);
range = getRange(false); range = getRange(false);
} }
if (!range || range.cleared || force === "unfold") return; if (!range || range.cleared || force === "unfold") return;
var myWidget = makeWidget(cm, options); var myWidget = makeWidget(cm, options);
CodeMirror.on(myWidget, "mousedown", function(e) { CodeMirror.on(myWidget, "mousedown", function(e) {
myRange.clear(); myRange.clear();
CodeMirror.e_preventDefault(e); CodeMirror.e_preventDefault(e);
}); });
var myRange = cm.markText(range.from, range.to, { var myRange = cm.markText(range.from, range.to, {
replacedWith: myWidget, replacedWith: myWidget,
clearOnEnter: true, clearOnEnter: true,
__isFold: true __isFold: true
}); });
myRange.on("clear", function(from, to) { myRange.on("clear", function(from, to) {
CodeMirror.signal(cm, "unfold", cm, from, to); CodeMirror.signal(cm, "unfold", cm, from, to);
}); });
CodeMirror.signal(cm, "fold", cm, range.from, range.to); CodeMirror.signal(cm, "fold", cm, range.from, range.to);
} }
function makeWidget(cm, options) { function makeWidget(cm, options) {
var widget = getOption(cm, options, "widget"); var widget = getOption(cm, options, "widget");
if (typeof widget == "string") { if (typeof widget == "string") {
var text = document.createTextNode(widget); var text = document.createTextNode(widget);
widget = document.createElement("span"); widget = document.createElement("span");
widget.appendChild(text); widget.appendChild(text);
widget.className = "CodeMirror-foldmarker"; widget.className = "CodeMirror-foldmarker";
} }
return widget; return widget;
} }
// Clumsy backwards-compatible interface // Clumsy backwards-compatible interface
CodeMirror.newFoldFunction = function(rangeFinder, widget) { CodeMirror.newFoldFunction = function(rangeFinder, widget) {
return function(cm, pos) { doFold(cm, pos, {rangeFinder: rangeFinder, widget: widget}); }; return function(cm, pos) { doFold(cm, pos, {rangeFinder: rangeFinder, widget: widget}); };
}; };
// New-style interface // New-style interface
CodeMirror.defineExtension("foldCode", function(pos, options, force) { CodeMirror.defineExtension("foldCode", function(pos, options, force) {
doFold(this, pos, options, force); doFold(this, pos, options, force);
}); });
CodeMirror.defineExtension("isFolded", function(pos) { CodeMirror.defineExtension("isFolded", function(pos) {
var marks = this.findMarksAt(pos); var marks = this.findMarksAt(pos);
for (var i = 0; i < marks.length; ++i) for (var i = 0; i < marks.length; ++i)
if (marks[i].__isFold) return true; if (marks[i].__isFold) return true;
}); });
CodeMirror.commands.toggleFold = function(cm) { CodeMirror.commands.toggleFold = function(cm) {
cm.foldCode(cm.getCursor()); cm.foldCode(cm.getCursor());
}; };
CodeMirror.commands.fold = function(cm) { CodeMirror.commands.fold = function(cm) {
cm.foldCode(cm.getCursor(), null, "fold"); cm.foldCode(cm.getCursor(), null, "fold");
}; };
CodeMirror.commands.unfold = function(cm) { CodeMirror.commands.unfold = function(cm) {
cm.foldCode(cm.getCursor(), null, "unfold"); cm.foldCode(cm.getCursor(), null, "unfold");
}; };
CodeMirror.commands.foldAll = function(cm) { CodeMirror.commands.foldAll = function(cm) {
cm.operation(function() { cm.operation(function() {
for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++) for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)
cm.foldCode(CodeMirror.Pos(i, 0), null, "fold"); cm.foldCode(CodeMirror.Pos(i, 0), null, "fold");
}); });
}; };
CodeMirror.commands.unfoldAll = function(cm) { CodeMirror.commands.unfoldAll = function(cm) {
cm.operation(function() { cm.operation(function() {
for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++) for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)
cm.foldCode(CodeMirror.Pos(i, 0), null, "unfold"); cm.foldCode(CodeMirror.Pos(i, 0), null, "unfold");
}); });
}; };
CodeMirror.registerHelper("fold", "combine", function() { CodeMirror.registerHelper("fold", "combine", function() {
var funcs = Array.prototype.slice.call(arguments, 0); var funcs = Array.prototype.slice.call(arguments, 0);
return function(cm, start) { return function(cm, start) {
for (var i = 0; i < funcs.length; ++i) { for (var i = 0; i < funcs.length; ++i) {
var found = funcs[i](cm, start); var found = funcs[i](cm, start);
if (found) return found; if (found) return found;
} }
}; };
}); });
CodeMirror.registerHelper("fold", "auto", function(cm, start) { CodeMirror.registerHelper("fold", "auto", function(cm, start) {
var helpers = cm.getHelpers(start, "fold"); var helpers = cm.getHelpers(start, "fold");
for (var i = 0; i < helpers.length; i++) { for (var i = 0; i < helpers.length; i++) {
var cur = helpers[i](cm, start); var cur = helpers[i](cm, start);
if (cur) return cur; if (cur) return cur;
} }
}); });
var defaultOptions = { var defaultOptions = {
rangeFinder: CodeMirror.fold.auto, rangeFinder: CodeMirror.fold.auto,
widget: "\u2194", widget: "\u2194",
minFoldSize: 0, minFoldSize: 0,
scanUp: false scanUp: false
}; };
CodeMirror.defineOption("foldOptions", null); CodeMirror.defineOption("foldOptions", null);
function getOption(cm, options, name) { function getOption(cm, options, name) {
if (options && options[name] !== undefined) if (options && options[name] !== undefined)
return options[name]; return options[name];
var editorOptions = cm.options.foldOptions; var editorOptions = cm.options.foldOptions;
if (editorOptions && editorOptions[name] !== undefined) if (editorOptions && editorOptions[name] !== undefined)
return editorOptions[name]; return editorOptions[name];
return defaultOptions[name]; return defaultOptions[name];
} }
CodeMirror.defineExtension("foldOption", function(options, name) { CodeMirror.defineExtension("foldOption", function(options, name) {
return getOption(this, options, name); return getOption(this, options, name);
}); });
}); });

View File

@@ -1,20 +1,20 @@
.CodeMirror-foldmarker { .CodeMirror-foldmarker {
color: blue; color: blue;
text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px; text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px;
font-family: arial; font-family: arial;
line-height: .3; line-height: .3;
cursor: pointer; cursor: pointer;
} }
.CodeMirror-foldgutter { .CodeMirror-foldgutter {
width: .7em; width: .7em;
} }
.CodeMirror-foldgutter-open, .CodeMirror-foldgutter-open,
.CodeMirror-foldgutter-folded { .CodeMirror-foldgutter-folded {
cursor: pointer; cursor: pointer;
} }
.CodeMirror-foldgutter-open:after { .CodeMirror-foldgutter-open:after {
content: "\25BE"; content: "\25BE";
} }
.CodeMirror-foldgutter-folded:after { .CodeMirror-foldgutter-folded:after {
content: "\25B8"; content: "\25B8";
} }

View File

@@ -1,146 +1,146 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) { (function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("./foldcode")); mod(require("../../lib/codemirror"), require("./foldcode"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "./foldcode"], mod); define(["../../lib/codemirror", "./foldcode"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
CodeMirror.defineOption("foldGutter", false, function(cm, val, old) { CodeMirror.defineOption("foldGutter", false, function(cm, val, old) {
if (old && old != CodeMirror.Init) { if (old && old != CodeMirror.Init) {
cm.clearGutter(cm.state.foldGutter.options.gutter); cm.clearGutter(cm.state.foldGutter.options.gutter);
cm.state.foldGutter = null; cm.state.foldGutter = null;
cm.off("gutterClick", onGutterClick); cm.off("gutterClick", onGutterClick);
cm.off("change", onChange); cm.off("change", onChange);
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", onChange); cm.off("swapDoc", onChange);
} }
if (val) { if (val) {
cm.state.foldGutter = new State(parseOptions(val)); cm.state.foldGutter = new State(parseOptions(val));
updateInViewport(cm); updateInViewport(cm);
cm.on("gutterClick", onGutterClick); cm.on("gutterClick", onGutterClick);
cm.on("change", onChange); cm.on("change", onChange);
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", onChange); cm.on("swapDoc", onChange);
} }
}); });
var Pos = CodeMirror.Pos; var Pos = CodeMirror.Pos;
function State(options) { function State(options) {
this.options = options; this.options = options;
this.from = this.to = 0; this.from = this.to = 0;
} }
function parseOptions(opts) { function parseOptions(opts) {
if (opts === true) opts = {}; if (opts === true) opts = {};
if (opts.gutter == null) opts.gutter = "CodeMirror-foldgutter"; if (opts.gutter == null) opts.gutter = "CodeMirror-foldgutter";
if (opts.indicatorOpen == null) opts.indicatorOpen = "CodeMirror-foldgutter-open"; if (opts.indicatorOpen == null) opts.indicatorOpen = "CodeMirror-foldgutter-open";
if (opts.indicatorFolded == null) opts.indicatorFolded = "CodeMirror-foldgutter-folded"; if (opts.indicatorFolded == null) opts.indicatorFolded = "CodeMirror-foldgutter-folded";
return opts; return opts;
} }
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 marks[i]; if (marks[i].__isFold && marks[i].find().from.line == line) return marks[i];
} }
function marker(spec) { function marker(spec) {
if (typeof spec == "string") { if (typeof spec == "string") {
var elt = document.createElement("div"); var elt = document.createElement("div");
elt.className = spec + " CodeMirror-guttermarker-subtle"; elt.className = spec + " CodeMirror-guttermarker-subtle";
return elt; return elt;
} else { } else {
return spec.cloneNode(true); return spec.cloneNode(true);
} }
} }
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 minSize = cm.foldOption(opts, "minFoldSize");
var func = cm.foldOption(opts, "rangeFinder"); 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); var pos = Pos(cur, 0);
var range = func && func(cm, pos); var range = func && func(cm, pos);
if (range && range.to.line - range.from.line >= minSize) 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);
++cur; ++cur;
}); });
} }
function updateInViewport(cm) { function updateInViewport(cm) {
var vp = cm.getViewport(), state = cm.state.foldGutter; var vp = cm.getViewport(), state = cm.state.foldGutter;
if (!state) return; if (!state) return;
cm.operation(function() { cm.operation(function() {
updateFoldInfo(cm, vp.from, vp.to); updateFoldInfo(cm, vp.from, vp.to);
}); });
state.from = vp.from; state.to = vp.to; state.from = vp.from; state.to = vp.to;
} }
function onGutterClick(cm, line, gutter) { function onGutterClick(cm, line, gutter) {
var state = cm.state.foldGutter; var state = cm.state.foldGutter;
if (!state) return; if (!state) return;
var opts = state.options; var opts = state.options;
if (gutter != opts.gutter) return; if (gutter != opts.gutter) return;
var folded = isFolded(cm, line); var folded = isFolded(cm, line);
if (folded) folded.clear(); if (folded) folded.clear();
else cm.foldCode(Pos(line, 0), opts.rangeFinder); else cm.foldCode(Pos(line, 0), opts.rangeFinder);
} }
function onChange(cm) { function onChange(cm) {
var state = cm.state.foldGutter; var state = cm.state.foldGutter;
if (!state) return; if (!state) return;
var opts = state.options; 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; var state = cm.state.foldGutter;
if (!state) return; if (!state) return;
var opts = state.options; 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();
if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) { if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) {
updateInViewport(cm); updateInViewport(cm);
} else { } else {
cm.operation(function() { cm.operation(function() {
if (vp.from < state.from) { if (vp.from < state.from) {
updateFoldInfo(cm, vp.from, state.from); updateFoldInfo(cm, vp.from, state.from);
state.from = vp.from; state.from = vp.from;
} }
if (vp.to > state.to) { if (vp.to > state.to) {
updateFoldInfo(cm, state.to, vp.to); updateFoldInfo(cm, state.to, vp.to);
state.to = vp.to; state.to = vp.to;
} }
}); });
} }
}, opts.updateViewportTimeSpan || 400); }, opts.updateViewportTimeSpan || 400);
} }
function onFold(cm, from) { function onFold(cm, from) {
var state = cm.state.foldGutter; var state = cm.state.foldGutter;
if (!state) return; if (!state) return;
var line = from.line; 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);
} }
}); });

View File

@@ -1,44 +1,44 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
CodeMirror.registerHelper("fold", "indent", function(cm, start) { CodeMirror.registerHelper("fold", "indent", function(cm, start) {
var tabSize = cm.getOption("tabSize"), firstLine = cm.getLine(start.line); var tabSize = cm.getOption("tabSize"), firstLine = cm.getLine(start.line);
if (!/\S/.test(firstLine)) return; if (!/\S/.test(firstLine)) return;
var getIndent = function(line) { var getIndent = function(line) {
return CodeMirror.countColumn(line, null, tabSize); return CodeMirror.countColumn(line, null, tabSize);
}; };
var myIndent = getIndent(firstLine); var myIndent = getIndent(firstLine);
var lastLineInFold = null; var lastLineInFold = null;
// Go through lines until we find a line that definitely doesn't belong in // Go through lines until we find a line that definitely doesn't belong in
// the block we're folding, or to the end. // the block we're folding, or to the end.
for (var i = start.line + 1, end = cm.lastLine(); i <= end; ++i) { for (var i = start.line + 1, end = cm.lastLine(); i <= end; ++i) {
var curLine = cm.getLine(i); var curLine = cm.getLine(i);
var curIndent = getIndent(curLine); var curIndent = getIndent(curLine);
if (curIndent > myIndent) { if (curIndent > myIndent) {
// Lines with a greater indent are considered part of the block. // Lines with a greater indent are considered part of the block.
lastLineInFold = i; lastLineInFold = i;
} else if (!/\S/.test(curLine)) { } else if (!/\S/.test(curLine)) {
// Empty lines might be breaks within the block we're trying to fold. // Empty lines might be breaks within the block we're trying to fold.
} else { } else {
// A non-empty line at an indent equal to or less than ours marks the // A non-empty line at an indent equal to or less than ours marks the
// start of another block. // start of another block.
break; break;
} }
} }
if (lastLineInFold) return { if (lastLineInFold) return {
from: CodeMirror.Pos(start.line, firstLine.length), from: CodeMirror.Pos(start.line, firstLine.length),
to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length) to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length)
}; };
}); });
}); });

View File

@@ -1,49 +1,49 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
CodeMirror.registerHelper("fold", "markdown", function(cm, start) { CodeMirror.registerHelper("fold", "markdown", function(cm, start) {
var maxDepth = 100; var maxDepth = 100;
function isHeader(lineNo) { function isHeader(lineNo) {
var tokentype = cm.getTokenTypeAt(CodeMirror.Pos(lineNo, 0)); var tokentype = cm.getTokenTypeAt(CodeMirror.Pos(lineNo, 0));
return tokentype && /\bheader\b/.test(tokentype); return tokentype && /\bheader\b/.test(tokentype);
} }
function headerLevel(lineNo, line, nextLine) { function headerLevel(lineNo, line, nextLine) {
var match = line && line.match(/^#+/); var match = line && line.match(/^#+/);
if (match && isHeader(lineNo)) return match[0].length; if (match && isHeader(lineNo)) return match[0].length;
match = nextLine && nextLine.match(/^[=\-]+\s*$/); match = nextLine && nextLine.match(/^[=\-]+\s*$/);
if (match && isHeader(lineNo + 1)) return nextLine[0] == "=" ? 1 : 2; if (match && isHeader(lineNo + 1)) return nextLine[0] == "=" ? 1 : 2;
return maxDepth; return maxDepth;
} }
var firstLine = cm.getLine(start.line), nextLine = cm.getLine(start.line + 1); var firstLine = cm.getLine(start.line), nextLine = cm.getLine(start.line + 1);
var level = headerLevel(start.line, firstLine, nextLine); var level = headerLevel(start.line, firstLine, nextLine);
if (level === maxDepth) return undefined; if (level === maxDepth) return undefined;
var lastLineNo = cm.lastLine(); var lastLineNo = cm.lastLine();
var end = start.line, nextNextLine = cm.getLine(end + 2); var end = start.line, nextNextLine = cm.getLine(end + 2);
while (end < lastLineNo) { while (end < lastLineNo) {
if (headerLevel(end + 1, nextLine, nextNextLine) <= level) break; if (headerLevel(end + 1, nextLine, nextNextLine) <= level) break;
++end; ++end;
nextLine = nextNextLine; nextLine = nextNextLine;
nextNextLine = cm.getLine(end + 2); nextNextLine = cm.getLine(end + 2);
} }
return { return {
from: CodeMirror.Pos(start.line, firstLine.length), from: CodeMirror.Pos(start.line, firstLine.length),
to: CodeMirror.Pos(end, cm.getLine(end).length) to: CodeMirror.Pos(end, cm.getLine(end).length)
}; };
}); });
}); });

View File

@@ -1,182 +1,182 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
var Pos = CodeMirror.Pos; var Pos = CodeMirror.Pos;
function cmp(a, b) { return a.line - b.line || a.ch - b.ch; } function cmp(a, b) { return a.line - b.line || a.ch - b.ch; }
var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD"; var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD";
var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040"; var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040";
var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g"); var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g");
function Iter(cm, line, ch, range) { function Iter(cm, line, ch, range) {
this.line = line; this.ch = ch; this.line = line; this.ch = ch;
this.cm = cm; this.text = cm.getLine(line); this.cm = cm; this.text = cm.getLine(line);
this.min = range ? range.from : cm.firstLine(); this.min = range ? range.from : cm.firstLine();
this.max = range ? range.to - 1 : cm.lastLine(); this.max = range ? range.to - 1 : cm.lastLine();
} }
function tagAt(iter, ch) { function tagAt(iter, ch) {
var type = iter.cm.getTokenTypeAt(Pos(iter.line, ch)); var type = iter.cm.getTokenTypeAt(Pos(iter.line, ch));
return type && /\btag\b/.test(type); return type && /\btag\b/.test(type);
} }
function nextLine(iter) { function nextLine(iter) {
if (iter.line >= iter.max) return; if (iter.line >= iter.max) return;
iter.ch = 0; iter.ch = 0;
iter.text = iter.cm.getLine(++iter.line); iter.text = iter.cm.getLine(++iter.line);
return true; return true;
} }
function prevLine(iter) { function prevLine(iter) {
if (iter.line <= iter.min) return; if (iter.line <= iter.min) return;
iter.text = iter.cm.getLine(--iter.line); iter.text = iter.cm.getLine(--iter.line);
iter.ch = iter.text.length; iter.ch = iter.text.length;
return true; return true;
} }
function toTagEnd(iter) { function toTagEnd(iter) {
for (;;) { for (;;) {
var gt = iter.text.indexOf(">", iter.ch); var gt = iter.text.indexOf(">", iter.ch);
if (gt == -1) { if (nextLine(iter)) continue; else return; } if (gt == -1) { if (nextLine(iter)) continue; else return; }
if (!tagAt(iter, gt + 1)) { iter.ch = gt + 1; continue; } if (!tagAt(iter, gt + 1)) { iter.ch = gt + 1; continue; }
var lastSlash = iter.text.lastIndexOf("/", gt); var lastSlash = iter.text.lastIndexOf("/", gt);
var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt)); var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
iter.ch = gt + 1; iter.ch = gt + 1;
return selfClose ? "selfClose" : "regular"; return selfClose ? "selfClose" : "regular";
} }
} }
function toTagStart(iter) { function toTagStart(iter) {
for (;;) { for (;;) {
var lt = iter.ch ? iter.text.lastIndexOf("<", iter.ch - 1) : -1; var lt = iter.ch ? iter.text.lastIndexOf("<", iter.ch - 1) : -1;
if (lt == -1) { if (prevLine(iter)) continue; else return; } if (lt == -1) { if (prevLine(iter)) continue; else return; }
if (!tagAt(iter, lt + 1)) { iter.ch = lt; continue; } if (!tagAt(iter, lt + 1)) { iter.ch = lt; continue; }
xmlTagStart.lastIndex = lt; xmlTagStart.lastIndex = lt;
iter.ch = lt; iter.ch = lt;
var match = xmlTagStart.exec(iter.text); var match = xmlTagStart.exec(iter.text);
if (match && match.index == lt) return match; if (match && match.index == lt) return match;
} }
} }
function toNextTag(iter) { function toNextTag(iter) {
for (;;) { for (;;) {
xmlTagStart.lastIndex = iter.ch; xmlTagStart.lastIndex = iter.ch;
var found = xmlTagStart.exec(iter.text); var found = xmlTagStart.exec(iter.text);
if (!found) { if (nextLine(iter)) continue; else return; } if (!found) { if (nextLine(iter)) continue; else return; }
if (!tagAt(iter, found.index + 1)) { iter.ch = found.index + 1; continue; } if (!tagAt(iter, found.index + 1)) { iter.ch = found.index + 1; continue; }
iter.ch = found.index + found[0].length; iter.ch = found.index + found[0].length;
return found; return found;
} }
} }
function toPrevTag(iter) { function toPrevTag(iter) {
for (;;) { for (;;) {
var gt = iter.ch ? iter.text.lastIndexOf(">", iter.ch - 1) : -1; var gt = iter.ch ? iter.text.lastIndexOf(">", iter.ch - 1) : -1;
if (gt == -1) { if (prevLine(iter)) continue; else return; } if (gt == -1) { if (prevLine(iter)) continue; else return; }
if (!tagAt(iter, gt + 1)) { iter.ch = gt; continue; } if (!tagAt(iter, gt + 1)) { iter.ch = gt; continue; }
var lastSlash = iter.text.lastIndexOf("/", gt); var lastSlash = iter.text.lastIndexOf("/", gt);
var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt)); var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
iter.ch = gt + 1; iter.ch = gt + 1;
return selfClose ? "selfClose" : "regular"; return selfClose ? "selfClose" : "regular";
} }
} }
function findMatchingClose(iter, tag) { function findMatchingClose(iter, tag) {
var stack = []; var stack = [];
for (;;) { for (;;) {
var next = toNextTag(iter), end, startLine = iter.line, startCh = iter.ch - (next ? next[0].length : 0); var next = toNextTag(iter), end, startLine = iter.line, startCh = iter.ch - (next ? next[0].length : 0);
if (!next || !(end = toTagEnd(iter))) return; if (!next || !(end = toTagEnd(iter))) return;
if (end == "selfClose") continue; if (end == "selfClose") continue;
if (next[1]) { // closing tag if (next[1]) { // closing tag
for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) { for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) {
stack.length = i; stack.length = i;
break; break;
} }
if (i < 0 && (!tag || tag == next[2])) return { if (i < 0 && (!tag || tag == next[2])) return {
tag: next[2], tag: next[2],
from: Pos(startLine, startCh), from: Pos(startLine, startCh),
to: Pos(iter.line, iter.ch) to: Pos(iter.line, iter.ch)
}; };
} else { // opening tag } else { // opening tag
stack.push(next[2]); stack.push(next[2]);
} }
} }
} }
function findMatchingOpen(iter, tag) { function findMatchingOpen(iter, tag) {
var stack = []; var stack = [];
for (;;) { for (;;) {
var prev = toPrevTag(iter); var prev = toPrevTag(iter);
if (!prev) return; if (!prev) return;
if (prev == "selfClose") { toTagStart(iter); continue; } if (prev == "selfClose") { toTagStart(iter); continue; }
var endLine = iter.line, endCh = iter.ch; var endLine = iter.line, endCh = iter.ch;
var start = toTagStart(iter); var start = toTagStart(iter);
if (!start) return; if (!start) return;
if (start[1]) { // closing tag if (start[1]) { // closing tag
stack.push(start[2]); stack.push(start[2]);
} else { // opening tag } else { // opening tag
for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == start[2]) { for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == start[2]) {
stack.length = i; stack.length = i;
break; break;
} }
if (i < 0 && (!tag || tag == start[2])) return { if (i < 0 && (!tag || tag == start[2])) return {
tag: start[2], tag: start[2],
from: Pos(iter.line, iter.ch), from: Pos(iter.line, iter.ch),
to: Pos(endLine, endCh) to: Pos(endLine, endCh)
}; };
} }
} }
} }
CodeMirror.registerHelper("fold", "xml", function(cm, start) { CodeMirror.registerHelper("fold", "xml", function(cm, start) {
var iter = new Iter(cm, start.line, 0); var iter = new Iter(cm, start.line, 0);
for (;;) { for (;;) {
var openTag = toNextTag(iter), end; var openTag = toNextTag(iter), end;
if (!openTag || iter.line != start.line || !(end = toTagEnd(iter))) return; if (!openTag || iter.line != start.line || !(end = toTagEnd(iter))) return;
if (!openTag[1] && end != "selfClose") { if (!openTag[1] && end != "selfClose") {
var start = Pos(iter.line, iter.ch); var start = Pos(iter.line, iter.ch);
var close = findMatchingClose(iter, openTag[2]); var close = findMatchingClose(iter, openTag[2]);
return close && {from: start, to: close.from}; return close && {from: start, to: close.from};
} }
} }
}); });
CodeMirror.findMatchingTag = function(cm, pos, range) { CodeMirror.findMatchingTag = function(cm, pos, range) {
var iter = new Iter(cm, pos.line, pos.ch, range); var iter = new Iter(cm, pos.line, pos.ch, range);
if (iter.text.indexOf(">") == -1 && iter.text.indexOf("<") == -1) return; if (iter.text.indexOf(">") == -1 && iter.text.indexOf("<") == -1) return;
var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch); var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch);
var start = end && toTagStart(iter); var start = end && toTagStart(iter);
if (!end || !start || cmp(iter, pos) > 0) return; if (!end || !start || cmp(iter, pos) > 0) return;
var here = {from: Pos(iter.line, iter.ch), to: to, tag: start[2]}; var here = {from: Pos(iter.line, iter.ch), to: to, tag: start[2]};
if (end == "selfClose") return {open: here, close: null, at: "open"}; if (end == "selfClose") return {open: here, close: null, at: "open"};
if (start[1]) { // closing tag if (start[1]) { // closing tag
return {open: findMatchingOpen(iter, start[2]), close: here, at: "close"}; return {open: findMatchingOpen(iter, start[2]), close: here, at: "close"};
} else { // opening tag } else { // opening tag
iter = new Iter(cm, to.line, to.ch, range); iter = new Iter(cm, to.line, to.ch, range);
return {open: here, close: findMatchingClose(iter, start[2]), at: "open"}; return {open: here, close: findMatchingClose(iter, start[2]), at: "open"};
} }
}; };
CodeMirror.findEnclosingTag = function(cm, pos, range) { CodeMirror.findEnclosingTag = function(cm, pos, range) {
var iter = new Iter(cm, pos.line, pos.ch, range); var iter = new Iter(cm, pos.line, pos.ch, range);
for (;;) { for (;;) {
var open = findMatchingOpen(iter); var open = findMatchingOpen(iter);
if (!open) break; if (!open) break;
var forward = new Iter(cm, pos.line, pos.ch, range); var forward = new Iter(cm, pos.line, pos.ch, range);
var close = findMatchingClose(forward, open.tag); var close = findMatchingClose(forward, open.tag);
if (close) return {open: open, close: close}; if (close) return {open: open, close: close};
} }
}; };
// Used by addon/edit/closetag.js // Used by addon/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);
}; };
}); });

View File

@@ -1,41 +1,41 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
var WORD = /[\w$]+/, RANGE = 500; var WORD = /[\w$]+/, RANGE = 500;
CodeMirror.registerHelper("hint", "anyword", function(editor, options) { CodeMirror.registerHelper("hint", "anyword", function(editor, options) {
var word = options && options.word || WORD; var word = options && options.word || WORD;
var range = options && options.range || RANGE; var range = options && options.range || RANGE;
var cur = editor.getCursor(), curLine = editor.getLine(cur.line); var cur = editor.getCursor(), curLine = editor.getLine(cur.line);
var end = cur.ch, start = end; var end = cur.ch, start = end;
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 = options && options.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;
for (; line != endLine; line += dir) { for (; line != endLine; line += dir) {
var text = editor.getLine(line), m; var text = editor.getLine(line), m;
while (m = re.exec(text)) { while (m = re.exec(text)) {
if (line == cur.line && m[0] === curWord) continue; if (line == cur.line && m[0] === curWord) continue;
if ((!curWord || m[0].lastIndexOf(curWord, 0) == 0) && !Object.prototype.hasOwnProperty.call(seen, m[0])) { if ((!curWord || m[0].lastIndexOf(curWord, 0) == 0) && !Object.prototype.hasOwnProperty.call(seen, m[0])) {
seen[m[0]] = true; seen[m[0]] = true;
list.push(m[0]); list.push(m[0]);
} }
} }
} }
} }
return {list: list, from: CodeMirror.Pos(cur.line, start), to: CodeMirror.Pos(cur.line, end)}; return {list: list, from: CodeMirror.Pos(cur.line, start), to: CodeMirror.Pos(cur.line, end)};
}); });
}); });

View File

@@ -1,60 +1,60 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) { (function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("../../mode/css/css")); mod(require("../../lib/codemirror"), require("../../mode/css/css"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "../../mode/css/css"], mod); define(["../../lib/codemirror", "../../mode/css/css"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
var pseudoClasses = {link: 1, visited: 1, active: 1, hover: 1, focus: 1, var pseudoClasses = {link: 1, visited: 1, active: 1, hover: 1, focus: 1,
"first-letter": 1, "first-line": 1, "first-child": 1, "first-letter": 1, "first-line": 1, "first-child": 1,
before: 1, after: 1, lang: 1}; before: 1, after: 1, lang: 1};
CodeMirror.registerHelper("hint", "css", function(cm) { CodeMirror.registerHelper("hint", "css", function(cm) {
var cur = cm.getCursor(), token = cm.getTokenAt(cur); var cur = cm.getCursor(), token = cm.getTokenAt(cur);
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) if (token.type == "keyword" && "!important".indexOf(token.string) == 0)
return {list: ["!important"], from: CodeMirror.Pos(cur.line, token.start), return {list: ["!important"], from: CodeMirror.Pos(cur.line, token.start),
to: CodeMirror.Pos(cur.line, token.end)}; 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;
} }
var spec = CodeMirror.resolveMode("text/css"); var spec = CodeMirror.resolveMode("text/css");
var result = []; var result = [];
function add(keywords) { function add(keywords) {
for (var name in keywords) for (var name in keywords)
if (!word || name.lastIndexOf(word, 0) == 0) if (!word || name.lastIndexOf(word, 0) == 0)
result.push(name); result.push(name);
} }
var st = inner.state.state; var st = inner.state.state;
if (st == "pseudo" || token.type == "variable-3") { if (st == "pseudo" || token.type == "variable-3") {
add(pseudoClasses); add(pseudoClasses);
} else if (st == "block" || st == "maybeprop") { } else if (st == "block" || st == "maybeprop") {
add(spec.propertyKeywords); add(spec.propertyKeywords);
} else if (st == "prop" || st == "parens" || st == "at" || st == "params") { } else if (st == "prop" || st == "parens" || st == "at" || st == "params") {
add(spec.valueKeywords); add(spec.valueKeywords);
add(spec.colorKeywords); add(spec.colorKeywords);
} else if (st == "media" || st == "media_parens") { } else if (st == "media" || st == "media_parens") {
add(spec.mediaTypes); add(spec.mediaTypes);
add(spec.mediaFeatures); add(spec.mediaFeatures);
} }
if (result.length) return { if (result.length) return {
list: result, list: result,
from: CodeMirror.Pos(cur.line, start), from: CodeMirror.Pos(cur.line, start),
to: CodeMirror.Pos(cur.line, end) to: CodeMirror.Pos(cur.line, end)
}; };
}); });
}); });

View File

@@ -1,348 +1,348 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) { (function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("./xml-hint")); mod(require("../../lib/codemirror"), require("./xml-hint"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "./xml-hint"], mod); define(["../../lib/codemirror", "./xml-hint"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
var langs = "ab aa af ak sq am ar an hy as av ae ay az bm ba eu be bn bh bi bs br bg my ca ch ce ny zh cv kw co cr hr cs da dv nl dz en eo et ee fo fj fi fr ff gl ka de el gn gu ht ha he hz hi ho hu ia id ie ga ig ik io is it iu ja jv kl kn kr ks kk km ki rw ky kv kg ko ku kj la lb lg li ln lo lt lu lv gv mk mg ms ml mt mi mr mh mn na nv nb nd ne ng nn no ii nr oc oj cu om or os pa pi fa pl ps pt qu rm rn ro ru sa sc sd se sm sg sr gd sn si sk sl so st es su sw ss sv ta te tg th ti bo tk tl tn to tr ts tt tw ty ug uk ur uz ve vi vo wa cy wo fy xh yi yo za zu".split(" "); var langs = "ab aa af ak sq am ar an hy as av ae ay az bm ba eu be bn bh bi bs br bg my ca ch ce ny zh cv kw co cr hr cs da dv nl dz en eo et ee fo fj fi fr ff gl ka de el gn gu ht ha he hz hi ho hu ia id ie ga ig ik io is it iu ja jv kl kn kr ks kk km ki rw ky kv kg ko ku kj la lb lg li ln lo lt lu lv gv mk mg ms ml mt mi mr mh mn na nv nb nd ne ng nn no ii nr oc oj cu om or os pa pi fa pl ps pt qu rm rn ro ru sa sc sd se sm sg sr gd sn si sk sl so st es su sw ss sv ta te tg th ti bo tk tl tn to tr ts tt tw ty ug uk ur uz ve vi vo wa cy wo fy xh yi yo za zu".split(" ");
var targets = ["_blank", "_self", "_top", "_parent"]; var targets = ["_blank", "_self", "_top", "_parent"];
var charsets = ["ascii", "utf-8", "utf-16", "latin1", "latin1"]; var charsets = ["ascii", "utf-8", "utf-16", "latin1", "latin1"];
var methods = ["get", "post", "put", "delete"]; var methods = ["get", "post", "put", "delete"];
var encs = ["application/x-www-form-urlencoded", "multipart/form-data", "text/plain"]; var encs = ["application/x-www-form-urlencoded", "multipart/form-data", "text/plain"];
var media = ["all", "screen", "print", "embossed", "braille", "handheld", "print", "projection", "screen", "tty", "tv", "speech", var media = ["all", "screen", "print", "embossed", "braille", "handheld", "print", "projection", "screen", "tty", "tv", "speech",
"3d-glasses", "resolution [>][<][=] [X]", "device-aspect-ratio: X/Y", "orientation:portrait", "3d-glasses", "resolution [>][<][=] [X]", "device-aspect-ratio: X/Y", "orientation:portrait",
"orientation:landscape", "device-height: [X]", "device-width: [X]"]; "orientation:landscape", "device-height: [X]", "device-width: [X]"];
var s = { attrs: {} }; // Simple tag, reused for a whole lot of tags var s = { attrs: {} }; // Simple tag, reused for a whole lot of tags
var data = { var data = {
a: { a: {
attrs: { attrs: {
href: null, ping: null, type: null, href: null, ping: null, type: null,
media: media, media: media,
target: targets, target: targets,
hreflang: langs hreflang: langs
} }
}, },
abbr: s, abbr: s,
acronym: s, acronym: s,
address: s, address: s,
applet: s, applet: s,
area: { area: {
attrs: { attrs: {
alt: null, coords: null, href: null, target: null, ping: null, alt: null, coords: null, href: null, target: null, ping: null,
media: media, hreflang: langs, type: null, media: media, hreflang: langs, type: null,
shape: ["default", "rect", "circle", "poly"] shape: ["default", "rect", "circle", "poly"]
} }
}, },
article: s, article: s,
aside: s, aside: s,
audio: { audio: {
attrs: { attrs: {
src: null, mediagroup: null, src: null, mediagroup: null,
crossorigin: ["anonymous", "use-credentials"], crossorigin: ["anonymous", "use-credentials"],
preload: ["none", "metadata", "auto"], preload: ["none", "metadata", "auto"],
autoplay: ["", "autoplay"], autoplay: ["", "autoplay"],
loop: ["", "loop"], loop: ["", "loop"],
controls: ["", "controls"] controls: ["", "controls"]
} }
}, },
b: s, b: s,
base: { attrs: { href: null, target: targets } }, base: { attrs: { href: null, target: targets } },
basefont: s, basefont: s,
bdi: s, bdi: s,
bdo: s, bdo: s,
big: s, big: s,
blockquote: { attrs: { cite: null } }, blockquote: { attrs: { cite: null } },
body: s, body: s,
br: s, br: s,
button: { button: {
attrs: { attrs: {
form: null, formaction: null, name: null, value: null, form: null, formaction: null, name: null, value: null,
autofocus: ["", "autofocus"], autofocus: ["", "autofocus"],
disabled: ["", "autofocus"], disabled: ["", "autofocus"],
formenctype: encs, formenctype: encs,
formmethod: methods, formmethod: methods,
formnovalidate: ["", "novalidate"], formnovalidate: ["", "novalidate"],
formtarget: targets, formtarget: targets,
type: ["submit", "reset", "button"] type: ["submit", "reset", "button"]
} }
}, },
canvas: { attrs: { width: null, height: null } }, canvas: { attrs: { width: null, height: null } },
caption: s, caption: s,
center: s, center: s,
cite: s, cite: s,
code: s, code: s,
col: { attrs: { span: null } }, col: { attrs: { span: null } },
colgroup: { attrs: { span: null } }, colgroup: { attrs: { span: null } },
command: { command: {
attrs: { attrs: {
type: ["command", "checkbox", "radio"], type: ["command", "checkbox", "radio"],
label: null, icon: null, radiogroup: null, command: null, title: null, label: null, icon: null, radiogroup: null, command: null, title: null,
disabled: ["", "disabled"], disabled: ["", "disabled"],
checked: ["", "checked"] checked: ["", "checked"]
} }
}, },
data: { attrs: { value: null } }, data: { attrs: { value: null } },
datagrid: { attrs: { disabled: ["", "disabled"], multiple: ["", "multiple"] } }, datagrid: { attrs: { disabled: ["", "disabled"], multiple: ["", "multiple"] } },
datalist: { attrs: { data: null } }, datalist: { attrs: { data: null } },
dd: s, dd: s,
del: { attrs: { cite: null, datetime: null } }, del: { attrs: { cite: null, datetime: null } },
details: { attrs: { open: ["", "open"] } }, details: { attrs: { open: ["", "open"] } },
dfn: s, dfn: s,
dir: s, dir: s,
div: s, div: s,
dl: s, dl: s,
dt: s, dt: s,
em: s, em: s,
embed: { attrs: { src: null, type: null, width: null, height: null } }, embed: { attrs: { src: null, type: null, width: null, height: null } },
eventsource: { attrs: { src: null } }, eventsource: { attrs: { src: null } },
fieldset: { attrs: { disabled: ["", "disabled"], form: null, name: null } }, fieldset: { attrs: { disabled: ["", "disabled"], form: null, name: null } },
figcaption: s, figcaption: s,
figure: s, figure: s,
font: s, font: s,
footer: s, footer: s,
form: { form: {
attrs: { attrs: {
action: null, name: null, action: null, name: null,
"accept-charset": charsets, "accept-charset": charsets,
autocomplete: ["on", "off"], autocomplete: ["on", "off"],
enctype: encs, enctype: encs,
method: methods, method: methods,
novalidate: ["", "novalidate"], novalidate: ["", "novalidate"],
target: targets target: targets
} }
}, },
frame: s, frame: s,
frameset: s, frameset: s,
h1: s, h2: s, h3: s, h4: s, h5: s, h6: s, h1: s, h2: s, h3: s, h4: s, h5: s, h6: s,
head: { head: {
attrs: {}, attrs: {},
children: ["title", "base", "link", "style", "meta", "script", "noscript", "command"] children: ["title", "base", "link", "style", "meta", "script", "noscript", "command"]
}, },
header: s, header: s,
hgroup: s, hgroup: s,
hr: s, hr: s,
html: { html: {
attrs: { manifest: null }, attrs: { manifest: null },
children: ["head", "body"] children: ["head", "body"]
}, },
i: s, i: s,
iframe: { iframe: {
attrs: { attrs: {
src: null, srcdoc: null, name: null, width: null, height: null, src: null, srcdoc: null, name: null, width: null, height: null,
sandbox: ["allow-top-navigation", "allow-same-origin", "allow-forms", "allow-scripts"], sandbox: ["allow-top-navigation", "allow-same-origin", "allow-forms", "allow-scripts"],
seamless: ["", "seamless"] seamless: ["", "seamless"]
} }
}, },
img: { img: {
attrs: { attrs: {
alt: null, src: null, ismap: null, usemap: null, width: null, height: null, alt: null, src: null, ismap: null, usemap: null, width: null, height: null,
crossorigin: ["anonymous", "use-credentials"] crossorigin: ["anonymous", "use-credentials"]
} }
}, },
input: { input: {
attrs: { attrs: {
alt: null, dirname: null, form: null, formaction: null, alt: null, dirname: null, form: null, formaction: null,
height: null, list: null, max: null, maxlength: null, min: null, height: null, list: null, max: null, maxlength: null, min: null,
name: null, pattern: null, placeholder: null, size: null, src: null, name: null, pattern: null, placeholder: null, size: null, src: null,
step: null, value: null, width: null, step: null, value: null, width: null,
accept: ["audio/*", "video/*", "image/*"], accept: ["audio/*", "video/*", "image/*"],
autocomplete: ["on", "off"], autocomplete: ["on", "off"],
autofocus: ["", "autofocus"], autofocus: ["", "autofocus"],
checked: ["", "checked"], checked: ["", "checked"],
disabled: ["", "disabled"], disabled: ["", "disabled"],
formenctype: encs, formenctype: encs,
formmethod: methods, formmethod: methods,
formnovalidate: ["", "novalidate"], formnovalidate: ["", "novalidate"],
formtarget: targets, formtarget: targets,
multiple: ["", "multiple"], multiple: ["", "multiple"],
readonly: ["", "readonly"], readonly: ["", "readonly"],
required: ["", "required"], required: ["", "required"],
type: ["hidden", "text", "search", "tel", "url", "email", "password", "datetime", "date", "month", type: ["hidden", "text", "search", "tel", "url", "email", "password", "datetime", "date", "month",
"week", "time", "datetime-local", "number", "range", "color", "checkbox", "radio", "week", "time", "datetime-local", "number", "range", "color", "checkbox", "radio",
"file", "submit", "image", "reset", "button"] "file", "submit", "image", "reset", "button"]
} }
}, },
ins: { attrs: { cite: null, datetime: null } }, ins: { attrs: { cite: null, datetime: null } },
kbd: s, kbd: s,
keygen: { keygen: {
attrs: { attrs: {
challenge: null, form: null, name: null, challenge: null, form: null, name: null,
autofocus: ["", "autofocus"], autofocus: ["", "autofocus"],
disabled: ["", "disabled"], disabled: ["", "disabled"],
keytype: ["RSA"] keytype: ["RSA"]
} }
}, },
label: { attrs: { "for": null, form: null } }, label: { attrs: { "for": null, form: null } },
legend: s, legend: s,
li: { attrs: { value: null } }, li: { attrs: { value: null } },
link: { link: {
attrs: { attrs: {
href: null, type: null, href: null, type: null,
hreflang: langs, hreflang: langs,
media: media, media: media,
sizes: ["all", "16x16", "16x16 32x32", "16x16 32x32 64x64"] sizes: ["all", "16x16", "16x16 32x32", "16x16 32x32 64x64"]
} }
}, },
map: { attrs: { name: null } }, map: { attrs: { name: null } },
mark: s, mark: s,
menu: { attrs: { label: null, type: ["list", "context", "toolbar"] } }, menu: { attrs: { label: null, type: ["list", "context", "toolbar"] } },
meta: { meta: {
attrs: { attrs: {
content: null, content: null,
charset: charsets, charset: charsets,
name: ["viewport", "application-name", "author", "description", "generator", "keywords"], name: ["viewport", "application-name", "author", "description", "generator", "keywords"],
"http-equiv": ["content-language", "content-type", "default-style", "refresh"] "http-equiv": ["content-language", "content-type", "default-style", "refresh"]
} }
}, },
meter: { attrs: { value: null, min: null, low: null, high: null, max: null, optimum: null } }, meter: { attrs: { value: null, min: null, low: null, high: null, max: null, optimum: null } },
nav: s, nav: s,
noframes: s, noframes: s,
noscript: s, noscript: s,
object: { object: {
attrs: { attrs: {
data: null, type: null, name: null, usemap: null, form: null, width: null, height: null, data: null, type: null, name: null, usemap: null, form: null, width: null, height: null,
typemustmatch: ["", "typemustmatch"] typemustmatch: ["", "typemustmatch"]
} }
}, },
ol: { attrs: { reversed: ["", "reversed"], start: null, type: ["1", "a", "A", "i", "I"] } }, ol: { attrs: { reversed: ["", "reversed"], start: null, type: ["1", "a", "A", "i", "I"] } },
optgroup: { attrs: { disabled: ["", "disabled"], label: null } }, optgroup: { attrs: { disabled: ["", "disabled"], label: null } },
option: { attrs: { disabled: ["", "disabled"], label: null, selected: ["", "selected"], value: null } }, option: { attrs: { disabled: ["", "disabled"], label: null, selected: ["", "selected"], value: null } },
output: { attrs: { "for": null, form: null, name: null } }, output: { attrs: { "for": null, form: null, name: null } },
p: s, p: s,
param: { attrs: { name: null, value: null } }, param: { attrs: { name: null, value: null } },
pre: s, pre: s,
progress: { attrs: { value: null, max: null } }, progress: { attrs: { value: null, max: null } },
q: { attrs: { cite: null } }, q: { attrs: { cite: null } },
rp: s, rp: s,
rt: s, rt: s,
ruby: s, ruby: s,
s: s, s: s,
samp: s, samp: s,
script: { script: {
attrs: { attrs: {
type: ["text/javascript"], type: ["text/javascript"],
src: null, src: null,
async: ["", "async"], async: ["", "async"],
defer: ["", "defer"], defer: ["", "defer"],
charset: charsets charset: charsets
} }
}, },
section: s, section: s,
select: { select: {
attrs: { attrs: {
form: null, name: null, size: null, form: null, name: null, size: null,
autofocus: ["", "autofocus"], autofocus: ["", "autofocus"],
disabled: ["", "disabled"], disabled: ["", "disabled"],
multiple: ["", "multiple"] multiple: ["", "multiple"]
} }
}, },
small: s, small: s,
source: { attrs: { src: null, type: null, media: null } }, source: { attrs: { src: null, type: null, media: null } },
span: s, span: s,
strike: s, strike: s,
strong: s, strong: s,
style: { style: {
attrs: { attrs: {
type: ["text/css"], type: ["text/css"],
media: media, media: media,
scoped: null scoped: null
} }
}, },
sub: s, sub: s,
summary: s, summary: s,
sup: s, sup: s,
table: s, table: s,
tbody: s, tbody: s,
td: { attrs: { colspan: null, rowspan: null, headers: null } }, td: { attrs: { colspan: null, rowspan: null, headers: null } },
textarea: { textarea: {
attrs: { attrs: {
dirname: null, form: null, maxlength: null, name: null, placeholder: null, dirname: null, form: null, maxlength: null, name: null, placeholder: null,
rows: null, cols: null, rows: null, cols: null,
autofocus: ["", "autofocus"], autofocus: ["", "autofocus"],
disabled: ["", "disabled"], disabled: ["", "disabled"],
readonly: ["", "readonly"], readonly: ["", "readonly"],
required: ["", "required"], required: ["", "required"],
wrap: ["soft", "hard"] wrap: ["soft", "hard"]
} }
}, },
tfoot: s, tfoot: s,
th: { attrs: { colspan: null, rowspan: null, headers: null, scope: ["row", "col", "rowgroup", "colgroup"] } }, th: { attrs: { colspan: null, rowspan: null, headers: null, scope: ["row", "col", "rowgroup", "colgroup"] } },
thead: s, thead: s,
time: { attrs: { datetime: null } }, time: { attrs: { datetime: null } },
title: s, title: s,
tr: s, tr: s,
track: { track: {
attrs: { attrs: {
src: null, label: null, "default": null, src: null, label: null, "default": null,
kind: ["subtitles", "captions", "descriptions", "chapters", "metadata"], kind: ["subtitles", "captions", "descriptions", "chapters", "metadata"],
srclang: langs srclang: langs
} }
}, },
tt: s, tt: s,
u: s, u: s,
ul: s, ul: s,
"var": s, "var": s,
video: { video: {
attrs: { attrs: {
src: null, poster: null, width: null, height: null, src: null, poster: null, width: null, height: null,
crossorigin: ["anonymous", "use-credentials"], crossorigin: ["anonymous", "use-credentials"],
preload: ["auto", "metadata", "none"], preload: ["auto", "metadata", "none"],
autoplay: ["", "autoplay"], autoplay: ["", "autoplay"],
mediagroup: ["movie"], mediagroup: ["movie"],
muted: ["", "muted"], muted: ["", "muted"],
controls: ["", "controls"] controls: ["", "controls"]
} }
}, },
wbr: s wbr: s
}; };
var globalAttrs = { var globalAttrs = {
accesskey: ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], accesskey: ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"],
"class": null, "class": null,
contenteditable: ["true", "false"], contenteditable: ["true", "false"],
contextmenu: null, contextmenu: null,
dir: ["ltr", "rtl", "auto"], dir: ["ltr", "rtl", "auto"],
draggable: ["true", "false", "auto"], draggable: ["true", "false", "auto"],
dropzone: ["copy", "move", "link", "string:", "file:"], dropzone: ["copy", "move", "link", "string:", "file:"],
hidden: ["hidden"], hidden: ["hidden"],
id: null, id: null,
inert: ["inert"], inert: ["inert"],
itemid: null, itemid: null,
itemprop: null, itemprop: null,
itemref: null, itemref: null,
itemscope: ["itemscope"], itemscope: ["itemscope"],
itemtype: null, itemtype: null,
lang: ["en", "es"], lang: ["en", "es"],
spellcheck: ["true", "false"], spellcheck: ["true", "false"],
style: null, style: null,
tabindex: ["1", "2", "3", "4", "5", "6", "7", "8", "9"], tabindex: ["1", "2", "3", "4", "5", "6", "7", "8", "9"],
title: null, title: null,
translate: ["yes", "no"], translate: ["yes", "no"],
onclick: null, onclick: null,
rel: ["stylesheet", "alternate", "author", "bookmark", "help", "license", "next", "nofollow", "noreferrer", "prefetch", "prev", "search", "tag"] rel: ["stylesheet", "alternate", "author", "bookmark", "help", "license", "next", "nofollow", "noreferrer", "prefetch", "prev", "search", "tag"]
}; };
function populate(obj) { function populate(obj) {
for (var attr in globalAttrs) if (globalAttrs.hasOwnProperty(attr)) for (var attr in globalAttrs) if (globalAttrs.hasOwnProperty(attr))
obj.attrs[attr] = globalAttrs[attr]; obj.attrs[attr] = globalAttrs[attr];
} }
populate(s); populate(s);
for (var tag in data) if (data.hasOwnProperty(tag) && data[tag] != s) for (var tag in data) if (data.hasOwnProperty(tag) && data[tag] != s)
populate(data[tag]); populate(data[tag]);
CodeMirror.htmlSchema = data; CodeMirror.htmlSchema = data;
function htmlHint(cm, options) { function htmlHint(cm, options) {
var local = {schemaInfo: data}; var local = {schemaInfo: data};
if (options) for (var opt in options) local[opt] = options[opt]; if (options) for (var opt in options) local[opt] = options[opt];
return CodeMirror.hint.xml(cm, local); return CodeMirror.hint.xml(cm, local);
} }
CodeMirror.registerHelper("hint", "html", htmlHint); CodeMirror.registerHelper("hint", "html", htmlHint);
}); });

View File

@@ -1,146 +1,146 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
var Pos = CodeMirror.Pos; var Pos = CodeMirror.Pos;
function forEach(arr, f) { function forEach(arr, f) {
for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]); for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
} }
function arrayContains(arr, item) { function arrayContains(arr, item) {
if (!Array.prototype.indexOf) { if (!Array.prototype.indexOf) {
var i = arr.length; var i = arr.length;
while (i--) { while (i--) {
if (arr[i] === item) { if (arr[i] === item) {
return true; return true;
} }
} }
return false; return false;
} }
return arr.indexOf(item) != -1; return arr.indexOf(item) != -1;
} }
function scriptHint(editor, keywords, getToken, options) { function scriptHint(editor, keywords, getToken, options) {
// Find the token at the cursor // Find the token at the cursor
var cur = editor.getCursor(), token = getToken(editor, cur); var cur = editor.getCursor(), token = getToken(editor, cur);
if (/\b(?:string|comment)\b/.test(token.type)) return; if (/\b(?:string|comment)\b/.test(token.type)) return;
token.state = CodeMirror.innerMode(editor.getMode(), token.state).state; token.state = CodeMirror.innerMode(editor.getMode(), token.state).state;
// If it's not a 'word-style' token, ignore the token. // If it's not a 'word-style' token, ignore the token.
if (!/^[\w$_]*$/.test(token.string)) { if (!/^[\w$_]*$/.test(token.string)) {
token = {start: cur.ch, end: cur.ch, string: "", state: token.state, token = {start: cur.ch, end: cur.ch, string: "", state: token.state,
type: token.string == "." ? "property" : null}; type: token.string == "." ? "property" : null};
} else if (token.end > cur.ch) { } else if (token.end > cur.ch) {
token.end = cur.ch; token.end = cur.ch;
token.string = token.string.slice(0, cur.ch - token.start); token.string = token.string.slice(0, cur.ch - token.start);
} }
var tprop = token; var tprop = token;
// If it is a property, find out what it is a property of. // If it is a property, find out what it is a property of.
while (tprop.type == "property") { while (tprop.type == "property") {
tprop = getToken(editor, Pos(cur.line, tprop.start)); tprop = getToken(editor, Pos(cur.line, tprop.start));
if (tprop.string != ".") return; if (tprop.string != ".") return;
tprop = getToken(editor, Pos(cur.line, tprop.start)); tprop = getToken(editor, Pos(cur.line, tprop.start));
if (!context) var context = []; if (!context) var context = [];
context.push(tprop); context.push(tprop);
} }
return {list: getCompletions(token, context, keywords, options), return {list: getCompletions(token, context, keywords, options),
from: Pos(cur.line, token.start), from: Pos(cur.line, token.start),
to: Pos(cur.line, token.end)}; to: Pos(cur.line, token.end)};
} }
function javascriptHint(editor, options) { function javascriptHint(editor, options) {
return scriptHint(editor, javascriptKeywords, return scriptHint(editor, javascriptKeywords,
function (e, cur) {return e.getTokenAt(cur);}, function (e, cur) {return e.getTokenAt(cur);},
options); options);
}; };
CodeMirror.registerHelper("hint", "javascript", javascriptHint); CodeMirror.registerHelper("hint", "javascript", javascriptHint);
function getCoffeeScriptToken(editor, cur) { function getCoffeeScriptToken(editor, cur) {
// This getToken, it is for coffeescript, imitates the behavior of // This getToken, it is for coffeescript, imitates the behavior of
// getTokenAt method in javascript.js, that is, returning "property" // getTokenAt method in javascript.js, that is, returning "property"
// type and treat "." as indepenent token. // type and treat "." as indepenent token.
var token = editor.getTokenAt(cur); var token = editor.getTokenAt(cur);
if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') { if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') {
token.end = token.start; token.end = token.start;
token.string = '.'; token.string = '.';
token.type = "property"; token.type = "property";
} }
else if (/^\.[\w$_]*$/.test(token.string)) { else if (/^\.[\w$_]*$/.test(token.string)) {
token.type = "property"; token.type = "property";
token.start++; token.start++;
token.string = token.string.replace(/\./, ''); token.string = token.string.replace(/\./, '');
} }
return token; return token;
} }
function coffeescriptHint(editor, options) { function coffeescriptHint(editor, options) {
return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken, options); return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken, options);
} }
CodeMirror.registerHelper("hint", "coffeescript", coffeescriptHint); CodeMirror.registerHelper("hint", "coffeescript", coffeescriptHint);
var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " + var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " +
"toUpperCase toLowerCase split concat match replace search").split(" "); "toUpperCase toLowerCase split concat match replace search").split(" ");
var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " + var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " +
"lastIndexOf every some filter forEach map reduce reduceRight ").split(" "); "lastIndexOf every some filter forEach map reduce reduceRight ").split(" ");
var funcProps = "prototype apply call bind".split(" "); var funcProps = "prototype apply call bind".split(" ");
var javascriptKeywords = ("break case catch continue debugger default delete do else false finally for function " + var javascriptKeywords = ("break case catch continue debugger default delete do else false finally for function " +
"if in instanceof new null return switch throw true try typeof var void while with").split(" "); "if in instanceof new null return switch throw true try typeof var void while with").split(" ");
var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " + var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " +
"if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes").split(" "); "if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes").split(" ");
function getCompletions(token, context, keywords, options) { function getCompletions(token, context, keywords, options) {
var found = [], start = token.string, global = options && options.globalScope || window; var found = [], start = token.string, global = options && options.globalScope || window;
function maybeAdd(str) { function maybeAdd(str) {
if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str); if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str);
} }
function gatherCompletions(obj) { function gatherCompletions(obj) {
if (typeof obj == "string") forEach(stringProps, maybeAdd); if (typeof obj == "string") forEach(stringProps, maybeAdd);
else if (obj instanceof Array) forEach(arrayProps, maybeAdd); else if (obj instanceof Array) forEach(arrayProps, maybeAdd);
else if (obj instanceof Function) forEach(funcProps, maybeAdd); else if (obj instanceof Function) forEach(funcProps, maybeAdd);
for (var name in obj) maybeAdd(name); for (var name in obj) maybeAdd(name);
} }
if (context && context.length) { if (context && context.length) {
// If this is a property, see if it belongs to some object we can // If this is a property, see if it belongs to some object we can
// find in the current environment. // find in the current environment.
var obj = context.pop(), base; var obj = context.pop(), base;
if (obj.type && obj.type.indexOf("variable") === 0) { if (obj.type && obj.type.indexOf("variable") === 0) {
if (options && options.additionalContext) if (options && options.additionalContext)
base = options.additionalContext[obj.string]; base = options.additionalContext[obj.string];
if (!options || options.useGlobalScope !== false) if (!options || options.useGlobalScope !== false)
base = base || global[obj.string]; base = base || global[obj.string];
} else if (obj.type == "string") { } else if (obj.type == "string") {
base = ""; base = "";
} else if (obj.type == "atom") { } else if (obj.type == "atom") {
base = 1; base = 1;
} else if (obj.type == "function") { } else if (obj.type == "function") {
if (global.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') && if (global.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') &&
(typeof global.jQuery == 'function')) (typeof global.jQuery == 'function'))
base = global.jQuery(); base = global.jQuery();
else if (global._ != null && (obj.string == '_') && (typeof global._ == 'function')) else if (global._ != null && (obj.string == '_') && (typeof global._ == 'function'))
base = global._(); base = global._();
} }
while (base != null && context.length) while (base != null && context.length)
base = base[context.pop().string]; base = base[context.pop().string];
if (base != null) gatherCompletions(base); if (base != null) gatherCompletions(base);
} else { } else {
// If not, just look in the global object and any local scope // If not, just look in the global object and any local scope
// (reading into JS mode internals to get at the local and global variables) // (reading into JS mode internals to get at the local and global variables)
for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name); for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name);
for (var v = token.state.globalVars; v; v = v.next) maybeAdd(v.name); for (var v = token.state.globalVars; v; v = v.next) maybeAdd(v.name);
if (!options || options.useGlobalScope !== false) if (!options || options.useGlobalScope !== false)
gatherCompletions(global); gatherCompletions(global);
forEach(keywords, maybeAdd); forEach(keywords, maybeAdd);
} }
return found; return found;
} }
}); });

View File

@@ -1,38 +1,38 @@
.CodeMirror-hints { .CodeMirror-hints {
position: absolute; position: absolute;
z-index: 10; z-index: 10;
overflow: hidden; overflow: hidden;
list-style: none; list-style: none;
margin: 0; margin: 0;
padding: 2px; padding: 2px;
-webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2); -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
-moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2); -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
box-shadow: 2px 3px 5px rgba(0,0,0,.2); box-shadow: 2px 3px 5px rgba(0,0,0,.2);
border-radius: 3px; border-radius: 3px;
border: 1px solid silver; border: 1px solid silver;
background: white; background: white;
font-size: 90%; font-size: 90%;
font-family: monospace; font-family: monospace;
max-height: 20em; max-height: 20em;
overflow-y: auto; overflow-y: auto;
} }
.CodeMirror-hint { .CodeMirror-hint {
margin: 0; margin: 0;
padding: 0 4px; padding: 0 4px;
border-radius: 2px; border-radius: 2px;
max-width: 19em; max-width: 19em;
overflow: hidden; overflow: hidden;
white-space: pre; white-space: pre;
color: black; color: black;
cursor: pointer; cursor: pointer;
} }
li.CodeMirror-hint-active { li.CodeMirror-hint-active {
background: #08f; background: #08f;
color: white; color: white;
} }

View File

@@ -1,434 +1,434 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
var HINT_ELEMENT_CLASS = "CodeMirror-hint"; var HINT_ELEMENT_CLASS = "CodeMirror-hint";
var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active"; var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active";
// This is the old interface, kept around for now to stay // This is the old interface, kept around for now to stay
// backwards-compatible. // backwards-compatible.
CodeMirror.showHint = function(cm, getHints, options) { CodeMirror.showHint = function(cm, getHints, options) {
if (!getHints) return cm.showHint(options); if (!getHints) return cm.showHint(options);
if (options && options.async) getHints.async = true; if (options && options.async) getHints.async = true;
var newOpts = {hint: getHints}; var newOpts = {hint: getHints};
if (options) for (var prop in options) newOpts[prop] = options[prop]; if (options) for (var prop in options) newOpts[prop] = options[prop];
return cm.showHint(newOpts); return cm.showHint(newOpts);
}; };
CodeMirror.defineExtension("showHint", function(options) { CodeMirror.defineExtension("showHint", function(options) {
options = parseOptions(this, this.getCursor("start"), options); options = parseOptions(this, this.getCursor("start"), options);
var selections = this.listSelections() var selections = this.listSelections()
if (selections.length > 1) return; if (selections.length > 1) return;
// By default, don't allow completion when something is selected. // By default, don't allow completion when something is selected.
// A hint function can have a `supportsSelection` property to // A hint function can have a `supportsSelection` property to
// indicate that it can handle selections. // indicate that it can handle selections.
if (this.somethingSelected()) { if (this.somethingSelected()) {
if (!options.hint.supportsSelection) return; if (!options.hint.supportsSelection) return;
// Don't try with cross-line selections // Don't try with cross-line selections
for (var i = 0; i < selections.length; i++) for (var i = 0; i < selections.length; i++)
if (selections[i].head.line != selections[i].anchor.line) return; if (selections[i].head.line != selections[i].anchor.line) return;
} }
if (this.state.completionActive) this.state.completionActive.close(); if (this.state.completionActive) this.state.completionActive.close();
var completion = this.state.completionActive = new Completion(this, options); var completion = this.state.completionActive = new Completion(this, options);
if (!completion.options.hint) return; if (!completion.options.hint) return;
CodeMirror.signal(this, "startCompletion", this); CodeMirror.signal(this, "startCompletion", this);
completion.update(true); completion.update(true);
}); });
function Completion(cm, options) { function Completion(cm, options) {
this.cm = cm; this.cm = cm;
this.options = options; this.options = options;
this.widget = null; this.widget = null;
this.debounce = 0; this.debounce = 0;
this.tick = 0; this.tick = 0;
this.startPos = this.cm.getCursor("start"); this.startPos = this.cm.getCursor("start");
this.startLen = this.cm.getLine(this.startPos.line).length - this.cm.getSelection().length; this.startLen = this.cm.getLine(this.startPos.line).length - this.cm.getSelection().length;
var self = this; var self = this;
cm.on("cursorActivity", this.activityFunc = function() { self.cursorActivity(); }); cm.on("cursorActivity", this.activityFunc = function() { self.cursorActivity(); });
} }
var requestAnimationFrame = window.requestAnimationFrame || function(fn) { var requestAnimationFrame = window.requestAnimationFrame || function(fn) {
return setTimeout(fn, 1000/60); return setTimeout(fn, 1000/60);
}; };
var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout; var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;
Completion.prototype = { Completion.prototype = {
close: function() { close: function() {
if (!this.active()) return; if (!this.active()) return;
this.cm.state.completionActive = null; this.cm.state.completionActive = null;
this.tick = null; this.tick = null;
this.cm.off("cursorActivity", this.activityFunc); this.cm.off("cursorActivity", this.activityFunc);
if (this.widget && this.data) CodeMirror.signal(this.data, "close"); if (this.widget && this.data) CodeMirror.signal(this.data, "close");
if (this.widget) this.widget.close(); if (this.widget) this.widget.close();
CodeMirror.signal(this.cm, "endCompletion", this.cm); CodeMirror.signal(this.cm, "endCompletion", this.cm);
}, },
active: function() { active: function() {
return this.cm.state.completionActive == this; return this.cm.state.completionActive == this;
}, },
pick: function(data, i) { pick: function(data, i) {
var completion = data.list[i]; var completion = data.list[i];
if (completion.hint) completion.hint(this.cm, data, completion); if (completion.hint) completion.hint(this.cm, data, completion);
else this.cm.replaceRange(getText(completion), completion.from || data.from, else this.cm.replaceRange(getText(completion), completion.from || data.from,
completion.to || data.to, "complete"); completion.to || data.to, "complete");
CodeMirror.signal(data, "pick", completion); CodeMirror.signal(data, "pick", completion);
this.close(); this.close();
}, },
cursorActivity: function() { cursorActivity: function() {
if (this.debounce) { if (this.debounce) {
cancelAnimationFrame(this.debounce); cancelAnimationFrame(this.debounce);
this.debounce = 0; this.debounce = 0;
} }
var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line); var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line);
if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch || if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch ||
pos.ch < this.startPos.ch || this.cm.somethingSelected() || pos.ch < this.startPos.ch || this.cm.somethingSelected() ||
(pos.ch && this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) { (pos.ch && this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) {
this.close(); this.close();
} else { } else {
var self = this; var self = this;
this.debounce = requestAnimationFrame(function() {self.update();}); this.debounce = requestAnimationFrame(function() {self.update();});
if (this.widget) this.widget.disable(); if (this.widget) this.widget.disable();
} }
}, },
update: function(first) { update: function(first) {
if (this.tick == null) return if (this.tick == null) return
var self = this, myTick = ++this.tick var self = this, myTick = ++this.tick
fetchHints(this.options.hint, this.cm, this.options, function(data) { fetchHints(this.options.hint, this.cm, this.options, function(data) {
if (self.tick == myTick) self.finishUpdate(data, first) if (self.tick == myTick) self.finishUpdate(data, first)
}) })
}, },
finishUpdate: function(data, first) { finishUpdate: function(data, first) {
if (this.data) CodeMirror.signal(this.data, "update"); if (this.data) CodeMirror.signal(this.data, "update");
var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle); var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle);
if (this.widget) this.widget.close(); if (this.widget) this.widget.close();
if (data && this.data && isNewCompletion(this.data, data)) return; if (data && this.data && isNewCompletion(this.data, data)) return;
this.data = data; this.data = data;
if (data && data.list.length) { if (data && data.list.length) {
if (picked && data.list.length == 1) { if (picked && data.list.length == 1) {
this.pick(data, 0); this.pick(data, 0);
} else { } else {
this.widget = new Widget(this, data); this.widget = new Widget(this, data);
CodeMirror.signal(data, "shown"); CodeMirror.signal(data, "shown");
} }
} }
} }
}; };
function isNewCompletion(old, nw) { function isNewCompletion(old, nw) {
var moved = CodeMirror.cmpPos(nw.from, old.from) var moved = CodeMirror.cmpPos(nw.from, old.from)
return moved > 0 && old.to.ch - old.from.ch != nw.to.ch - nw.from.ch return moved > 0 && old.to.ch - old.from.ch != nw.to.ch - nw.from.ch
} }
function parseOptions(cm, pos, options) { function parseOptions(cm, pos, options) {
var editor = cm.options.hintOptions; var editor = cm.options.hintOptions;
var out = {}; var out = {};
for (var prop in defaultOptions) out[prop] = defaultOptions[prop]; for (var prop in defaultOptions) out[prop] = defaultOptions[prop];
if (editor) for (var prop in editor) if (editor) for (var prop in editor)
if (editor[prop] !== undefined) out[prop] = editor[prop]; if (editor[prop] !== undefined) out[prop] = editor[prop];
if (options) for (var prop in options) if (options) for (var prop in options)
if (options[prop] !== undefined) out[prop] = options[prop]; if (options[prop] !== undefined) out[prop] = options[prop];
if (out.hint.resolve) out.hint = out.hint.resolve(cm, pos) if (out.hint.resolve) out.hint = out.hint.resolve(cm, pos)
return out; return out;
} }
function getText(completion) { function getText(completion) {
if (typeof completion == "string") return completion; if (typeof completion == "string") return completion;
else return completion.text; else return completion.text;
} }
function buildKeyMap(completion, handle) { function buildKeyMap(completion, handle) {
var baseMap = { var baseMap = {
Up: function() {handle.moveFocus(-1);}, Up: function() {handle.moveFocus(-1);},
Down: function() {handle.moveFocus(1);}, Down: function() {handle.moveFocus(1);},
PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);}, PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);},
PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);}, PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);},
Home: function() {handle.setFocus(0);}, Home: function() {handle.setFocus(0);},
End: function() {handle.setFocus(handle.length - 1);}, End: function() {handle.setFocus(handle.length - 1);},
Enter: handle.pick, Enter: handle.pick,
Tab: handle.pick, Tab: handle.pick,
Esc: handle.close Esc: handle.close
}; };
var custom = completion.options.customKeys; var custom = completion.options.customKeys;
var ourMap = custom ? {} : baseMap; var ourMap = custom ? {} : baseMap;
function addBinding(key, val) { function addBinding(key, val) {
var bound; var bound;
if (typeof val != "string") if (typeof val != "string")
bound = function(cm) { return val(cm, handle); }; bound = function(cm) { return val(cm, handle); };
// This mechanism is deprecated // This mechanism is deprecated
else if (baseMap.hasOwnProperty(val)) else if (baseMap.hasOwnProperty(val))
bound = baseMap[val]; bound = baseMap[val];
else else
bound = val; bound = val;
ourMap[key] = bound; ourMap[key] = bound;
} }
if (custom) if (custom)
for (var key in custom) if (custom.hasOwnProperty(key)) for (var key in custom) if (custom.hasOwnProperty(key))
addBinding(key, custom[key]); addBinding(key, custom[key]);
var extra = completion.options.extraKeys; var extra = completion.options.extraKeys;
if (extra) if (extra)
for (var key in extra) if (extra.hasOwnProperty(key)) for (var key in extra) if (extra.hasOwnProperty(key))
addBinding(key, extra[key]); addBinding(key, extra[key]);
return ourMap; return ourMap;
} }
function getHintElement(hintsElement, el) { function getHintElement(hintsElement, el) {
while (el && el != hintsElement) { while (el && el != hintsElement) {
if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el; if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el;
el = el.parentNode; el = el.parentNode;
} }
} }
function Widget(completion, data) { function Widget(completion, data) {
this.completion = completion; this.completion = completion;
this.data = data; this.data = data;
this.picked = false; this.picked = false;
var widget = this, cm = completion.cm; var widget = this, cm = completion.cm;
var hints = this.hints = document.createElement("ul"); var hints = this.hints = document.createElement("ul");
hints.className = "CodeMirror-hints"; hints.className = "CodeMirror-hints";
this.selectedHint = data.selectedHint || 0; this.selectedHint = data.selectedHint || 0;
var completions = data.list; var completions = data.list;
for (var i = 0; i < completions.length; ++i) { for (var i = 0; i < completions.length; ++i) {
var elt = hints.appendChild(document.createElement("li")), cur = completions[i]; var elt = hints.appendChild(document.createElement("li")), cur = completions[i];
var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS); var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS);
if (cur.className != null) className = cur.className + " " + className; if (cur.className != null) className = cur.className + " " + className;
elt.className = className; elt.className = className;
if (cur.render) cur.render(elt, data, cur); if (cur.render) cur.render(elt, data, cur);
else elt.appendChild(document.createTextNode(cur.displayText || getText(cur))); else elt.appendChild(document.createTextNode(cur.displayText || getText(cur)));
elt.hintId = i; elt.hintId = i;
} }
var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null); var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null);
var left = pos.left, top = pos.bottom, below = true; var left = pos.left, top = pos.bottom, below = true;
hints.style.left = left + "px"; hints.style.left = left + "px";
hints.style.top = top + "px"; hints.style.top = top + "px";
// If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.
var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth); var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth);
var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight); var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight);
(completion.options.container || document.body).appendChild(hints); (completion.options.container || document.body).appendChild(hints);
var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH; var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH;
if (overlapY > 0) { if (overlapY > 0) {
var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top); var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top);
if (curTop - height > 0) { // Fits above cursor if (curTop - height > 0) { // Fits above cursor
hints.style.top = (top = pos.top - height) + "px"; hints.style.top = (top = pos.top - height) + "px";
below = false; below = false;
} else if (height > winH) { } else if (height > winH) {
hints.style.height = (winH - 5) + "px"; hints.style.height = (winH - 5) + "px";
hints.style.top = (top = pos.bottom - box.top) + "px"; hints.style.top = (top = pos.bottom - box.top) + "px";
var cursor = cm.getCursor(); var cursor = cm.getCursor();
if (data.from.ch != cursor.ch) { if (data.from.ch != cursor.ch) {
pos = cm.cursorCoords(cursor); pos = cm.cursorCoords(cursor);
hints.style.left = (left = pos.left) + "px"; hints.style.left = (left = pos.left) + "px";
box = hints.getBoundingClientRect(); box = hints.getBoundingClientRect();
} }
} }
} }
var overlapX = box.right - winW; var overlapX = box.right - winW;
if (overlapX > 0) { if (overlapX > 0) {
if (box.right - box.left > winW) { if (box.right - box.left > winW) {
hints.style.width = (winW - 5) + "px"; hints.style.width = (winW - 5) + "px";
overlapX -= (box.right - box.left) - winW; overlapX -= (box.right - box.left) - winW;
} }
hints.style.left = (left = pos.left - overlapX) + "px"; hints.style.left = (left = pos.left - overlapX) + "px";
} }
cm.addKeyMap(this.keyMap = buildKeyMap(completion, { cm.addKeyMap(this.keyMap = buildKeyMap(completion, {
moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); }, moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); },
setFocus: function(n) { widget.changeActive(n); }, setFocus: function(n) { widget.changeActive(n); },
menuSize: function() { return widget.screenAmount(); }, menuSize: function() { return widget.screenAmount(); },
length: completions.length, length: completions.length,
close: function() { completion.close(); }, close: function() { completion.close(); },
pick: function() { widget.pick(); }, pick: function() { widget.pick(); },
data: data data: data
})); }));
if (completion.options.closeOnUnfocus) { if (completion.options.closeOnUnfocus) {
var closingOnBlur; var closingOnBlur;
cm.on("blur", this.onBlur = function() { closingOnBlur = setTimeout(function() { completion.close(); }, 100); }); cm.on("blur", this.onBlur = function() { closingOnBlur = setTimeout(function() { completion.close(); }, 100); });
cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); }); cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); });
} }
var startScroll = cm.getScrollInfo(); var startScroll = cm.getScrollInfo();
cm.on("scroll", this.onScroll = function() { cm.on("scroll", this.onScroll = function() {
var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect(); var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect();
var newTop = top + startScroll.top - curScroll.top; var newTop = top + startScroll.top - curScroll.top;
var point = newTop - (window.pageYOffset || (document.documentElement || document.body).scrollTop); var point = newTop - (window.pageYOffset || (document.documentElement || document.body).scrollTop);
if (!below) point += hints.offsetHeight; if (!below) point += hints.offsetHeight;
if (point <= editor.top || point >= editor.bottom) return completion.close(); if (point <= editor.top || point >= editor.bottom) return completion.close();
hints.style.top = newTop + "px"; hints.style.top = newTop + "px";
hints.style.left = (left + startScroll.left - curScroll.left) + "px"; hints.style.left = (left + startScroll.left - curScroll.left) + "px";
}); });
CodeMirror.on(hints, "dblclick", function(e) { CodeMirror.on(hints, "dblclick", function(e) {
var t = getHintElement(hints, e.target || e.srcElement); var t = getHintElement(hints, e.target || e.srcElement);
if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();} if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();}
}); });
CodeMirror.on(hints, "click", function(e) { CodeMirror.on(hints, "click", function(e) {
var t = getHintElement(hints, e.target || e.srcElement); var t = getHintElement(hints, e.target || e.srcElement);
if (t && t.hintId != null) { if (t && t.hintId != null) {
widget.changeActive(t.hintId); widget.changeActive(t.hintId);
if (completion.options.completeOnSingleClick) widget.pick(); if (completion.options.completeOnSingleClick) widget.pick();
} }
}); });
CodeMirror.on(hints, "mousedown", function() { CodeMirror.on(hints, "mousedown", function() {
setTimeout(function(){cm.focus();}, 20); setTimeout(function(){cm.focus();}, 20);
}); });
CodeMirror.signal(data, "select", completions[0], hints.firstChild); CodeMirror.signal(data, "select", completions[0], hints.firstChild);
return true; return true;
} }
Widget.prototype = { Widget.prototype = {
close: function() { close: function() {
if (this.completion.widget != this) return; if (this.completion.widget != this) return;
this.completion.widget = null; this.completion.widget = null;
this.hints.parentNode.removeChild(this.hints); this.hints.parentNode.removeChild(this.hints);
this.completion.cm.removeKeyMap(this.keyMap); this.completion.cm.removeKeyMap(this.keyMap);
var cm = this.completion.cm; var cm = this.completion.cm;
if (this.completion.options.closeOnUnfocus) { if (this.completion.options.closeOnUnfocus) {
cm.off("blur", this.onBlur); cm.off("blur", this.onBlur);
cm.off("focus", this.onFocus); cm.off("focus", this.onFocus);
} }
cm.off("scroll", this.onScroll); cm.off("scroll", this.onScroll);
}, },
disable: function() { disable: function() {
this.completion.cm.removeKeyMap(this.keyMap); this.completion.cm.removeKeyMap(this.keyMap);
var widget = this; var widget = this;
this.keyMap = {Enter: function() { widget.picked = true; }}; this.keyMap = {Enter: function() { widget.picked = true; }};
this.completion.cm.addKeyMap(this.keyMap); this.completion.cm.addKeyMap(this.keyMap);
}, },
pick: function() { pick: function() {
this.completion.pick(this.data, this.selectedHint); this.completion.pick(this.data, this.selectedHint);
}, },
changeActive: function(i, avoidWrap) { changeActive: function(i, avoidWrap) {
if (i >= this.data.list.length) if (i >= this.data.list.length)
i = avoidWrap ? this.data.list.length - 1 : 0; i = avoidWrap ? this.data.list.length - 1 : 0;
else if (i < 0) else if (i < 0)
i = avoidWrap ? 0 : this.data.list.length - 1; i = avoidWrap ? 0 : this.data.list.length - 1;
if (this.selectedHint == i) return; if (this.selectedHint == i) return;
var node = this.hints.childNodes[this.selectedHint]; var node = this.hints.childNodes[this.selectedHint];
node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, ""); node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, "");
node = this.hints.childNodes[this.selectedHint = i]; node = this.hints.childNodes[this.selectedHint = i];
node.className += " " + ACTIVE_HINT_ELEMENT_CLASS; node.className += " " + ACTIVE_HINT_ELEMENT_CLASS;
if (node.offsetTop < this.hints.scrollTop) if (node.offsetTop < this.hints.scrollTop)
this.hints.scrollTop = node.offsetTop - 3; this.hints.scrollTop = node.offsetTop - 3;
else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight) else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight)
this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3; this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3;
CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node); CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node);
}, },
screenAmount: function() { screenAmount: function() {
return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1; return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1;
} }
}; };
function applicableHelpers(cm, helpers) { function applicableHelpers(cm, helpers) {
if (!cm.somethingSelected()) return helpers if (!cm.somethingSelected()) return helpers
var result = [] var result = []
for (var i = 0; i < helpers.length; i++) for (var i = 0; i < helpers.length; i++)
if (helpers[i].supportsSelection) result.push(helpers[i]) if (helpers[i].supportsSelection) result.push(helpers[i])
return result return result
} }
function fetchHints(hint, cm, options, callback) { function fetchHints(hint, cm, options, callback) {
if (hint.async) { if (hint.async) {
hint(cm, callback, options) hint(cm, callback, options)
} else { } else {
var result = hint(cm, options) var result = hint(cm, options)
if (result && result.then) result.then(callback) if (result && result.then) result.then(callback)
else callback(result) else callback(result)
} }
} }
function resolveAutoHints(cm, pos) { function resolveAutoHints(cm, pos) {
var helpers = cm.getHelpers(pos, "hint"), words var helpers = cm.getHelpers(pos, "hint"), words
if (helpers.length) { if (helpers.length) {
var resolved = function(cm, callback, options) { var resolved = function(cm, callback, options) {
var app = applicableHelpers(cm, helpers); var app = applicableHelpers(cm, helpers);
function run(i) { function run(i) {
if (i == app.length) return callback(null) if (i == app.length) return callback(null)
fetchHints(app[i], cm, options, function(result) { fetchHints(app[i], cm, options, function(result) {
if (result && result.list.length > 0) callback(result) if (result && result.list.length > 0) callback(result)
else run(i + 1) else run(i + 1)
}) })
} }
run(0) run(0)
} }
resolved.async = true resolved.async = true
resolved.supportsSelection = true resolved.supportsSelection = true
return resolved return resolved
} else if (words = cm.getHelper(cm.getCursor(), "hintWords")) { } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) {
return function(cm) { return CodeMirror.hint.fromList(cm, {words: words}) } return function(cm) { return CodeMirror.hint.fromList(cm, {words: words}) }
} else if (CodeMirror.hint.anyword) { } else if (CodeMirror.hint.anyword) {
return function(cm, options) { return CodeMirror.hint.anyword(cm, options) } return function(cm, options) { return CodeMirror.hint.anyword(cm, options) }
} else { } else {
return function() {} return function() {}
} }
} }
CodeMirror.registerHelper("hint", "auto", { CodeMirror.registerHelper("hint", "auto", {
resolve: resolveAutoHints resolve: resolveAutoHints
}); });
CodeMirror.registerHelper("hint", "fromList", function(cm, options) { CodeMirror.registerHelper("hint", "fromList", function(cm, options) {
var cur = cm.getCursor(), token = cm.getTokenAt(cur); var cur = cm.getCursor(), token = cm.getTokenAt(cur);
var to = CodeMirror.Pos(cur.line, token.end); var to = CodeMirror.Pos(cur.line, token.end);
if (token.string && /\w/.test(token.string[token.string.length - 1])) { if (token.string && /\w/.test(token.string[token.string.length - 1])) {
var term = token.string, from = CodeMirror.Pos(cur.line, token.start); var term = token.string, from = CodeMirror.Pos(cur.line, token.start);
} else { } else {
var term = "", from = to; var term = "", from = to;
} }
var found = []; var found = [];
for (var i = 0; i < options.words.length; i++) { for (var i = 0; i < options.words.length; i++) {
var word = options.words[i]; var word = options.words[i];
if (word.slice(0, term.length) == term) if (word.slice(0, term.length) == term)
found.push(word); found.push(word);
} }
if (found.length) return {list: found, from: from, to: to}; if (found.length) return {list: found, from: from, to: to};
}); });
CodeMirror.commands.autocomplete = CodeMirror.showHint; CodeMirror.commands.autocomplete = CodeMirror.showHint;
var defaultOptions = { var defaultOptions = {
hint: CodeMirror.hint.auto, hint: CodeMirror.hint.auto,
completeSingle: true, completeSingle: true,
alignWithWord: true, alignWithWord: true,
closeCharacters: /[\s()\[\]{};:>,]/, closeCharacters: /[\s()\[\]{};:>,]/,
closeOnUnfocus: true, closeOnUnfocus: true,
completeOnSingleClick: true, completeOnSingleClick: true,
container: null, container: null,
customKeys: null, customKeys: null,
extraKeys: null extraKeys: null
}; };
CodeMirror.defineOption("hintOptions", null); CodeMirror.defineOption("hintOptions", null);
}); });

View File

@@ -1,281 +1,281 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) { (function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("../../mode/sql/sql")); mod(require("../../lib/codemirror"), require("../../mode/sql/sql"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "../../mode/sql/sql"], mod); define(["../../lib/codemirror", "../../mode/sql/sql"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
var tables; var tables;
var defaultTable; var defaultTable;
var keywords; var keywords;
var CONS = { var CONS = {
QUERY_DIV: ";", QUERY_DIV: ";",
ALIAS_KEYWORD: "AS" ALIAS_KEYWORD: "AS"
}; };
var Pos = CodeMirror.Pos; var Pos = CodeMirror.Pos;
function isArray(val) { return Object.prototype.toString.call(val) == "[object Array]" } 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) { function getText(item) {
return typeof item == "string" ? item : item.text; return typeof item == "string" ? item : item.text;
} }
function wrapTable(name, value) { function wrapTable(name, value) {
if (isArray(value)) value = {columns: value} if (isArray(value)) value = {columns: value}
if (!value.text) value.text = name if (!value.text) value.text = name
return value return value
} }
function parseTables(input) { function parseTables(input) {
var result = {} var result = {}
if (isArray(input)) { if (isArray(input)) {
for (var i = input.length - 1; i >= 0; i--) { for (var i = input.length - 1; i >= 0; i--) {
var item = input[i] var item = input[i]
result[getText(item).toUpperCase()] = wrapTable(getText(item), item) result[getText(item).toUpperCase()] = wrapTable(getText(item), item)
} }
} else if (input) { } else if (input) {
for (var name in input) for (var name in input)
result[name.toUpperCase()] = wrapTable(name, input[name]) result[name.toUpperCase()] = wrapTable(name, input[name])
} }
return result return result
} }
function getTable(name) { function getTable(name) {
return tables[name.toUpperCase()] return tables[name.toUpperCase()]
} }
function shallowClone(object) { function shallowClone(object) {
var result = {}; var result = {};
for (var key in object) if (object.hasOwnProperty(key)) for (var key in object) if (object.hasOwnProperty(key))
result[key] = object[key]; result[key] = object[key];
return result; return result;
} }
function match(string, word) { function match(string, word) {
var len = string.length; var len = string.length;
var sub = getText(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) {
if (isArray(wordlist)) { if (isArray(wordlist)) {
for (var i = 0; i < wordlist.length; i++) for (var i = 0; i < wordlist.length; i++)
if (match(search, wordlist[i])) result.push(formatter(wordlist[i])) if (match(search, wordlist[i])) result.push(formatter(wordlist[i]))
} else { } else {
for (var word in wordlist) if (wordlist.hasOwnProperty(word)) { for (var word in wordlist) if (wordlist.hasOwnProperty(word)) {
var val = wordlist[word] var val = wordlist[word]
if (!val || val === true) if (!val || val === true)
val = word val = word
else else
val = val.displayText ? {text: val.text, displayText: val.displayText} : val.text val = val.displayText ? {text: val.text, displayText: val.displayText} : val.text
if (match(search, val)) result.push(formatter(val)) if (match(search, val)) result.push(formatter(val))
} }
} }
} }
function cleanName(name) { function cleanName(name) {
// Get rid name from backticks(`) and preceding dot(.) // Get rid name from backticks(`) and preceding dot(.)
if (name.charAt(0) == ".") { if (name.charAt(0) == ".") {
name = name.substr(1); name = name.substr(1);
} }
return name.replace(/`/g, ""); return name.replace(/`/g, "");
} }
function insertBackticks(name) { function insertBackticks(name) {
var nameParts = getText(name).split("."); var nameParts = getText(name).split(".");
for (var i = 0; i < nameParts.length; i++) for (var i = 0; i < nameParts.length; i++)
nameParts[i] = "`" + nameParts[i] + "`"; nameParts[i] = "`" + nameParts[i] + "`";
var escaped = nameParts.join("."); var escaped = nameParts.join(".");
if (typeof name == "string") return escaped; if (typeof name == "string") return escaped;
name = shallowClone(name); name = shallowClone(name);
name.text = escaped; name.text = escaped;
return name; return name;
} }
function nameCompletion(cur, token, result, editor) { function nameCompletion(cur, token, result, editor) {
// Try to complete table, column names and return start position of completion // Try to complete table, column names and return start position of completion
var useBacktick = false; var useBacktick = false;
var nameParts = []; var nameParts = [];
var start = token.start; var start = token.start;
var cont = true; var cont = true;
while (cont) { while (cont) {
cont = (token.string.charAt(0) == "."); cont = (token.string.charAt(0) == ".");
useBacktick = useBacktick || (token.string.charAt(0) == "`"); useBacktick = useBacktick || (token.string.charAt(0) == "`");
start = token.start; start = token.start;
nameParts.unshift(cleanName(token.string)); nameParts.unshift(cleanName(token.string));
token = editor.getTokenAt(Pos(cur.line, token.start)); token = editor.getTokenAt(Pos(cur.line, token.start));
if (token.string == ".") { if (token.string == ".") {
cont = true; cont = true;
token = editor.getTokenAt(Pos(cur.line, token.start)); token = editor.getTokenAt(Pos(cur.line, token.start));
} }
} }
// Try to complete table names // Try to complete table names
var string = nameParts.join("."); var string = nameParts.join(".");
addMatches(result, string, tables, function(w) { addMatches(result, string, tables, function(w) {
return useBacktick ? insertBackticks(w) : w; return useBacktick ? insertBackticks(w) : w;
}); });
// Try to complete columns from defaultTable // Try to complete columns from defaultTable
addMatches(result, string, defaultTable, function(w) { addMatches(result, string, defaultTable, function(w) {
return useBacktick ? insertBackticks(w) : w; return useBacktick ? insertBackticks(w) : w;
}); });
// Try to complete columns // Try to complete columns
string = nameParts.pop(); string = nameParts.pop();
var table = nameParts.join("."); var table = nameParts.join(".");
var alias = false; var alias = false;
var aliasTable = table; var aliasTable = table;
// Check if table is available. If not, find table by Alias // Check if table is available. If not, find table by Alias
if (!getTable(table)) { if (!getTable(table)) {
var oldTable = table; var oldTable = table;
table = findTableByAlias(table, editor); table = findTableByAlias(table, editor);
if (table !== oldTable) alias = true; if (table !== oldTable) alias = true;
} }
var columns = getTable(table); var columns = getTable(table);
if (columns && columns.columns) if (columns && columns.columns)
columns = columns.columns; columns = columns.columns;
if (columns) { if (columns) {
addMatches(result, string, columns, function(w) { addMatches(result, string, columns, function(w) {
var tableInsert = table; var tableInsert = table;
if (alias == true) tableInsert = aliasTable; if (alias == true) tableInsert = aliasTable;
if (typeof w == "string") { if (typeof w == "string") {
w = tableInsert + "." + w; w = tableInsert + "." + w;
} else { } else {
w = shallowClone(w); w = shallowClone(w);
w.text = tableInsert + "." + w.text; w.text = tableInsert + "." + w.text;
} }
return useBacktick ? insertBackticks(w) : w; return useBacktick ? insertBackticks(w) : w;
}); });
} }
return start; return start;
} }
function eachWord(lineText, f) { function eachWord(lineText, f) {
if (!lineText) return; if (!lineText) return;
var excepted = /[,;]/g; var excepted = /[,;]/g;
var words = lineText.split(" "); var words = lineText.split(" ");
for (var i = 0; i < words.length; i++) { for (var i = 0; i < words.length; i++) {
f(words[i]?words[i].replace(excepted, '') : ''); f(words[i]?words[i].replace(excepted, '') : '');
} }
} }
function convertCurToNumber(cur) { function convertCurToNumber(cur) {
// max characters of a line is 999,999. // max characters of a line is 999,999.
return cur.line + cur.ch / Math.pow(10, 6); return cur.line + cur.ch / Math.pow(10, 6);
} }
function convertNumberToCur(num) { function convertNumberToCur(num) {
return Pos(Math.floor(num), +num.toString().split('.').pop()); return Pos(Math.floor(num), +num.toString().split('.').pop());
} }
function findTableByAlias(alias, editor) { function findTableByAlias(alias, editor) {
var doc = editor.doc; var doc = editor.doc;
var fullQuery = doc.getValue(); var fullQuery = doc.getValue();
var aliasUpperCase = alias.toUpperCase(); var aliasUpperCase = alias.toUpperCase();
var previousWord = ""; var previousWord = "";
var table = ""; var table = "";
var separator = []; var separator = [];
var validRange = { var validRange = {
start: Pos(0, 0), start: Pos(0, 0),
end: Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).length) end: Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).length)
}; };
//add separator //add separator
var indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV); var indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV);
while(indexOfSeparator != -1) { while(indexOfSeparator != -1) {
separator.push(doc.posFromIndex(indexOfSeparator)); separator.push(doc.posFromIndex(indexOfSeparator));
indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV, indexOfSeparator+1); indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV, indexOfSeparator+1);
} }
separator.unshift(Pos(0, 0)); separator.unshift(Pos(0, 0));
separator.push(Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).text.length)); separator.push(Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).text.length));
//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) };
break; break;
} }
prevItem = _v; prevItem = _v;
} }
var query = doc.getRange(validRange.start, validRange.end, false); var query = doc.getRange(validRange.start, validRange.end, false);
for (var i = 0; i < query.length; i++) { for (var i = 0; i < query.length; i++) {
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 && getTable(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;
} }
return table; return table;
} }
CodeMirror.registerHelper("hint", "sql", function(editor, options) { CodeMirror.registerHelper("hint", "sql", function(editor, options) {
tables = parseTables(options && options.tables) tables = parseTables(options && options.tables)
var defaultTableName = options && options.defaultTable; var defaultTableName = options && options.defaultTable;
var disableKeywords = options && options.disableKeywords; var disableKeywords = options && options.disableKeywords;
defaultTable = defaultTableName && getTable(defaultTableName); defaultTable = defaultTableName && getTable(defaultTableName);
keywords = keywords || getKeywords(editor); keywords = keywords || getKeywords(editor);
if (defaultTableName && !defaultTable) if (defaultTableName && !defaultTable)
defaultTable = findTableByAlias(defaultTableName, editor); defaultTable = findTableByAlias(defaultTableName, editor);
defaultTable = defaultTable || []; defaultTable = defaultTable || [];
if (defaultTable.columns) if (defaultTable.columns)
defaultTable = 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;
if (token.end > cur.ch) { if (token.end > cur.ch) {
token.end = cur.ch; token.end = cur.ch;
token.string = token.string.slice(0, cur.ch - token.start); token.string = token.string.slice(0, cur.ch - token.start);
} }
if (token.string.match(/^[.`\w@]\w*$/)) { if (token.string.match(/^[.`\w@]\w*$/)) {
search = token.string; search = token.string;
start = token.start; start = token.start;
end = token.end; end = token.end;
} else { } else {
start = end = cur.ch; start = end = cur.ch;
search = ""; search = "";
} }
if (search.charAt(0) == "." || search.charAt(0) == "`") { if (search.charAt(0) == "." || search.charAt(0) == "`") {
start = 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) if (!disableKeywords)
addMatches(result, search, keywords, function(w) {return w.toUpperCase();}); addMatches(result, search, keywords, function(w) {return w.toUpperCase();});
} }
return {list: result, from: Pos(cur.line, start), to: Pos(cur.line, end)}; return {list: result, from: Pos(cur.line, start), to: Pos(cur.line, end)};
}); });
}); });

View File

@@ -1,110 +1,110 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
var Pos = CodeMirror.Pos; var Pos = CodeMirror.Pos;
function getHints(cm, options) { function getHints(cm, options) {
var tags = options && options.schemaInfo; var tags = options && options.schemaInfo;
var quote = (options && options.quoteChar) || '"'; var quote = (options && options.quoteChar) || '"';
if (!tags) return; if (!tags) return;
var cur = cm.getCursor(), token = cm.getTokenAt(cur); var cur = cm.getCursor(), token = cm.getTokenAt(cur);
if (token.end > cur.ch) { if (token.end > cur.ch) {
token.end = cur.ch; token.end = cur.ch;
token.string = token.string.slice(0, cur.ch - token.start); token.string = token.string.slice(0, cur.ch - token.start);
} }
var inner = CodeMirror.innerMode(cm.getMode(), token.state); var inner = CodeMirror.innerMode(cm.getMode(), token.state);
if (inner.mode.name != "xml") return; if (inner.mode.name != "xml") return;
var result = [], replaceToken = false, prefix; var result = [], replaceToken = false, prefix;
var tag = /\btag\b/.test(token.type) && !/>$/.test(token.string); var tag = /\btag\b/.test(token.type) && !/>$/.test(token.string);
var tagName = tag && /^\w/.test(token.string), tagStart; var tagName = tag && /^\w/.test(token.string), tagStart;
if (tagName) { if (tagName) {
var before = cm.getLine(cur.line).slice(Math.max(0, token.start - 2), token.start); var before = cm.getLine(cur.line).slice(Math.max(0, token.start - 2), token.start);
var tagType = /<\/$/.test(before) ? "close" : /<$/.test(before) ? "open" : null; var tagType = /<\/$/.test(before) ? "close" : /<$/.test(before) ? "open" : null;
if (tagType) tagStart = token.start - (tagType == "close" ? 2 : 1); if (tagType) tagStart = token.start - (tagType == "close" ? 2 : 1);
} else if (tag && token.string == "<") { } else if (tag && token.string == "<") {
tagType = "open"; tagType = "open";
} else if (tag && token.string == "</") { } else if (tag && token.string == "</") {
tagType = "close"; tagType = "close";
} }
if (!tag && !inner.state.tagName || tagType) { if (!tag && !inner.state.tagName || tagType) {
if (tagName) if (tagName)
prefix = token.string; prefix = token.string;
replaceToken = tagType; replaceToken = tagType;
var cx = inner.state.context, curTag = cx && tags[cx.tagName]; var cx = inner.state.context, curTag = cx && tags[cx.tagName];
var childList = cx ? curTag && curTag.children : tags["!top"]; var childList = cx ? curTag && curTag.children : tags["!top"];
if (childList && tagType != "close") { if (childList && tagType != "close") {
for (var i = 0; i < childList.length; ++i) if (!prefix || childList[i].lastIndexOf(prefix, 0) == 0) for (var i = 0; i < childList.length; ++i) if (!prefix || childList[i].lastIndexOf(prefix, 0) == 0)
result.push("<" + childList[i]); result.push("<" + childList[i]);
} else if (tagType != "close") { } else if (tagType != "close") {
for (var name in tags) for (var name in tags)
if (tags.hasOwnProperty(name) && name != "!top" && name != "!attrs" && (!prefix || name.lastIndexOf(prefix, 0) == 0)) if (tags.hasOwnProperty(name) && name != "!top" && name != "!attrs" && (!prefix || name.lastIndexOf(prefix, 0) == 0))
result.push("<" + name); result.push("<" + name);
} }
if (cx && (!prefix || tagType == "close" && cx.tagName.lastIndexOf(prefix, 0) == 0)) if (cx && (!prefix || tagType == "close" && cx.tagName.lastIndexOf(prefix, 0) == 0))
result.push("</" + cx.tagName + ">"); result.push("</" + cx.tagName + ">");
} else { } else {
// Attribute completion // Attribute completion
var curTag = tags[inner.state.tagName], attrs = curTag && curTag.attrs; var curTag = tags[inner.state.tagName], attrs = curTag && curTag.attrs;
var globalAttrs = tags["!attrs"]; var globalAttrs = tags["!attrs"];
if (!attrs && !globalAttrs) return; if (!attrs && !globalAttrs) return;
if (!attrs) { if (!attrs) {
attrs = globalAttrs; attrs = globalAttrs;
} else if (globalAttrs) { // Combine tag-local and global attributes } else if (globalAttrs) { // Combine tag-local and global attributes
var set = {}; var set = {};
for (var nm in globalAttrs) if (globalAttrs.hasOwnProperty(nm)) set[nm] = globalAttrs[nm]; for (var nm in globalAttrs) if (globalAttrs.hasOwnProperty(nm)) set[nm] = globalAttrs[nm];
for (var nm in attrs) if (attrs.hasOwnProperty(nm)) set[nm] = attrs[nm]; for (var nm in attrs) if (attrs.hasOwnProperty(nm)) set[nm] = attrs[nm];
attrs = set; attrs = set;
} }
if (token.type == "string" || token.string == "=") { // A value if (token.type == "string" || token.string == "=") { // A value
var before = cm.getRange(Pos(cur.line, Math.max(0, cur.ch - 60)), var before = cm.getRange(Pos(cur.line, Math.max(0, cur.ch - 60)),
Pos(cur.line, token.type == "string" ? token.start : token.end)); Pos(cur.line, token.type == "string" ? token.start : token.end));
var atName = before.match(/([^\s\u00a0=<>\"\']+)=$/), atValues; var atName = before.match(/([^\s\u00a0=<>\"\']+)=$/), atValues;
if (!atName || !attrs.hasOwnProperty(atName[1]) || !(atValues = attrs[atName[1]])) return; if (!atName || !attrs.hasOwnProperty(atName[1]) || !(atValues = attrs[atName[1]])) return;
if (typeof atValues == 'function') atValues = atValues.call(this, cm); // Functions can be used to supply values for autocomplete widget if (typeof atValues == 'function') atValues = atValues.call(this, cm); // Functions can be used to supply values for autocomplete widget
if (token.type == "string") { if (token.type == "string") {
prefix = token.string; prefix = token.string;
var n = 0; var n = 0;
if (/['"]/.test(token.string.charAt(0))) { if (/['"]/.test(token.string.charAt(0))) {
quote = token.string.charAt(0); quote = token.string.charAt(0);
prefix = token.string.slice(1); prefix = token.string.slice(1);
n++; n++;
} }
var len = token.string.length; var len = token.string.length;
if (/['"]/.test(token.string.charAt(len - 1))) { if (/['"]/.test(token.string.charAt(len - 1))) {
quote = token.string.charAt(len - 1); quote = token.string.charAt(len - 1);
prefix = token.string.substr(n, len - 2); prefix = token.string.substr(n, len - 2);
} }
replaceToken = true; replaceToken = true;
} }
for (var i = 0; i < atValues.length; ++i) if (!prefix || atValues[i].lastIndexOf(prefix, 0) == 0) for (var i = 0; i < atValues.length; ++i) if (!prefix || atValues[i].lastIndexOf(prefix, 0) == 0)
result.push(quote + atValues[i] + quote); result.push(quote + atValues[i] + quote);
} else { // An attribute name } else { // An attribute name
if (token.type == "attribute") { if (token.type == "attribute") {
prefix = token.string; prefix = token.string;
replaceToken = true; replaceToken = true;
} }
for (var attr in attrs) if (attrs.hasOwnProperty(attr) && (!prefix || attr.lastIndexOf(prefix, 0) == 0)) for (var attr in attrs) if (attrs.hasOwnProperty(attr) && (!prefix || attr.lastIndexOf(prefix, 0) == 0))
result.push(attr); result.push(attr);
} }
} }
return { return {
list: result, list: result,
from: replaceToken ? Pos(cur.line, tagStart == null ? token.start : tagStart) : cur, from: replaceToken ? Pos(cur.line, tagStart == null ? token.start : tagStart) : cur,
to: replaceToken ? Pos(cur.line, token.end) : cur to: replaceToken ? Pos(cur.line, token.end) : cur
}; };
} }
CodeMirror.registerHelper("hint", "xml", getHints); CodeMirror.registerHelper("hint", "xml", getHints);
}); });

View File

@@ -1,41 +1,41 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
// Depends on coffeelint.js from http://www.coffeelint.org/js/coffeelint.js // Depends on coffeelint.js from http://www.coffeelint.org/js/coffeelint.js
// declare global: coffeelint // declare global: coffeelint
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
CodeMirror.registerHelper("lint", "coffeescript", function(text) { CodeMirror.registerHelper("lint", "coffeescript", function(text) {
var found = []; var found = [];
var parseError = function(err) { var parseError = function(err) {
var loc = err.lineNumber; var loc = err.lineNumber;
found.push({from: CodeMirror.Pos(loc-1, 0), found.push({from: CodeMirror.Pos(loc-1, 0),
to: CodeMirror.Pos(loc, 0), to: CodeMirror.Pos(loc, 0),
severity: err.level, severity: err.level,
message: err.message}); message: err.message});
}; };
try { try {
var res = coffeelint.lint(text); var res = coffeelint.lint(text);
for(var i = 0; i < res.length; i++) { for(var i = 0; i < res.length; i++) {
parseError(res[i]); parseError(res[i]);
} }
} catch(e) { } catch(e) {
found.push({from: CodeMirror.Pos(e.location.first_line, 0), found.push({from: CodeMirror.Pos(e.location.first_line, 0),
to: CodeMirror.Pos(e.location.last_line, e.location.last_column), to: CodeMirror.Pos(e.location.last_line, e.location.last_column),
severity: 'error', severity: 'error',
message: e.message}); message: e.message});
} }
return found; return found;
}); });
}); });

View File

@@ -1,35 +1,35 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
// Depends on csslint.js from https://github.com/stubbornella/csslint // Depends on csslint.js from https://github.com/stubbornella/csslint
// declare global: CSSLint // declare global: CSSLint
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
CodeMirror.registerHelper("lint", "css", function(text) { CodeMirror.registerHelper("lint", "css", function(text) {
var found = []; var found = [];
if (!window.CSSLint) return found; if (!window.CSSLint) return found;
var results = CSSLint.verify(text), messages = results.messages, message = null; var results = CSSLint.verify(text), messages = results.messages, message = null;
for ( var i = 0; i < messages.length; i++) { for ( var i = 0; i < messages.length; i++) {
message = messages[i]; message = messages[i];
var startLine = message.line -1, endLine = message.line -1, startCol = message.col -1, endCol = message.col; var startLine = message.line -1, endLine = message.line -1, startCol = message.col -1, endCol = message.col;
found.push({ found.push({
from: CodeMirror.Pos(startLine, startCol), from: CodeMirror.Pos(startLine, startCol),
to: CodeMirror.Pos(endLine, endCol), to: CodeMirror.Pos(endLine, endCol),
message: message.message, message: message.message,
severity : message.type severity : message.type
}); });
} }
return found; return found;
}); });
}); });

View File

@@ -1,46 +1,46 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
// Depends on htmlhint.js from http://htmlhint.com/js/htmlhint.js // Depends on htmlhint.js from http://htmlhint.com/js/htmlhint.js
// declare global: HTMLHint // declare global: HTMLHint
(function(mod) { (function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("htmlhint")); mod(require("../../lib/codemirror"), require("htmlhint"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "htmlhint"], mod); define(["../../lib/codemirror", "htmlhint"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
var defaultRules = { var defaultRules = {
"tagname-lowercase": true, "tagname-lowercase": true,
"attr-lowercase": true, "attr-lowercase": true,
"attr-value-double-quotes": true, "attr-value-double-quotes": true,
"doctype-first": false, "doctype-first": false,
"tag-pair": true, "tag-pair": true,
"spec-char-escape": true, "spec-char-escape": true,
"id-unique": true, "id-unique": true,
"src-not-empty": true, "src-not-empty": true,
"attr-no-duplication": true "attr-no-duplication": true
}; };
CodeMirror.registerHelper("lint", "html", function(text, options) { CodeMirror.registerHelper("lint", "html", function(text, options) {
var found = []; var found = [];
if (!window.HTMLHint) return found; if (!window.HTMLHint) return found;
var messages = HTMLHint.verify(text, options && options.rules || defaultRules); var messages = HTMLHint.verify(text, options && options.rules || defaultRules);
for (var i = 0; i < messages.length; i++) { for (var i = 0; i < messages.length; i++) {
var message = messages[i]; var message = messages[i];
var startLine = message.line - 1, endLine = message.line - 1, startCol = message.col - 1, endCol = message.col; var startLine = message.line - 1, endLine = message.line - 1, startCol = message.col - 1, endCol = message.col;
found.push({ found.push({
from: CodeMirror.Pos(startLine, startCol), from: CodeMirror.Pos(startLine, startCol),
to: CodeMirror.Pos(endLine, endCol), to: CodeMirror.Pos(endLine, endCol),
message: message.message, message: message.message,
severity : message.type severity : message.type
}); });
} }
return found; return found;
}); });
}); });

View File

@@ -1,136 +1,136 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
// declare global: JSHINT // declare global: JSHINT
var bogus = [ "Dangerous comment" ]; var bogus = [ "Dangerous comment" ];
var warnings = [ [ "Expected '{'", var warnings = [ [ "Expected '{'",
"Statement body should be inside '{ }' braces." ] ]; "Statement body should be inside '{ }' braces." ] ];
var errors = [ "Missing semicolon", "Extra comma", "Missing property name", var errors = [ "Missing semicolon", "Extra comma", "Missing property name",
"Unmatched ", " and instead saw", " is not defined", "Unmatched ", " and instead saw", " is not defined",
"Unclosed string", "Stopping, unable to continue" ]; "Unclosed string", "Stopping, unable to continue" ];
function validator(text, options) { function validator(text, options) {
if (!window.JSHINT) return []; if (!window.JSHINT) return [];
JSHINT(text, options, options.globals); 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;
} }
CodeMirror.registerHelper("lint", "javascript", validator); CodeMirror.registerHelper("lint", "javascript", validator);
function cleanup(error) { function cleanup(error) {
// All problems are warnings by default // All problems are warnings by default
fixWith(error, warnings, "warning", true); fixWith(error, warnings, "warning", true);
fixWith(error, errors, "error"); fixWith(error, errors, "error");
return isBogus(error) ? null : error; return isBogus(error) ? null : error;
} }
function fixWith(error, fixes, severity, force) { function fixWith(error, fixes, severity, force) {
var description, fix, find, replace, found; var description, fix, find, replace, found;
description = error.description; description = error.description;
for ( var i = 0; i < fixes.length; i++) { for ( var i = 0; i < fixes.length; i++) {
fix = fixes[i]; fix = fixes[i];
find = (typeof fix === "string" ? fix : fix[0]); find = (typeof fix === "string" ? fix : fix[0]);
replace = (typeof fix === "string" ? null : fix[1]); replace = (typeof fix === "string" ? null : fix[1]);
found = description.indexOf(find) !== -1; found = description.indexOf(find) !== -1;
if (force || found) { if (force || found) {
error.severity = severity; error.severity = severity;
} }
if (found && replace) { if (found && replace) {
error.description = replace; error.description = replace;
} }
} }
} }
function isBogus(error) { function isBogus(error) {
var description = error.description; var description = error.description;
for ( var i = 0; i < bogus.length; i++) { for ( var i = 0; i < bogus.length; i++) {
if (description.indexOf(bogus[i]) !== -1) { if (description.indexOf(bogus[i]) !== -1) {
return true; return true;
} }
} }
return false; return false;
} }
function parseErrors(errors, output) { function parseErrors(errors, output) {
for ( var i = 0; i < errors.length; i++) { for ( var i = 0; i < errors.length; i++) {
var error = errors[i]; var error = errors[i];
if (error) { if (error) {
var linetabpositions, index; var linetabpositions, index;
linetabpositions = []; linetabpositions = [];
// This next block is to fix a problem in jshint. Jshint // This next block is to fix a problem in jshint. Jshint
// replaces // replaces
// all tabs with spaces then performs some checks. The error // all tabs with spaces then performs some checks. The error
// positions (character/space) are then reported incorrectly, // positions (character/space) are then reported incorrectly,
// not taking the replacement step into account. Here we look // not taking the replacement step into account. Here we look
// at the evidence line and try to adjust the character position // at the evidence line and try to adjust the character position
// to the correct value. // to the correct value.
if (error.evidence) { if (error.evidence) {
// Tab positions are computed once per line and cached // Tab positions are computed once per line and cached
var tabpositions = linetabpositions[error.line]; var tabpositions = linetabpositions[error.line];
if (!tabpositions) { if (!tabpositions) {
var evidence = error.evidence; var evidence = error.evidence;
tabpositions = []; tabpositions = [];
// ugggh phantomjs does not like this // ugggh phantomjs does not like this
// forEachChar(evidence, function(item, index) { // forEachChar(evidence, function(item, index) {
Array.prototype.forEach.call(evidence, function(item, Array.prototype.forEach.call(evidence, function(item,
index) { index) {
if (item === '\t') { if (item === '\t') {
// First col is 1 (not 0) to match error // First col is 1 (not 0) to match error
// positions // positions
tabpositions.push(index + 1); tabpositions.push(index + 1);
} }
}); });
linetabpositions[error.line] = tabpositions; linetabpositions[error.line] = tabpositions;
} }
if (tabpositions.length > 0) { if (tabpositions.length > 0) {
var pos = error.character; var pos = error.character;
tabpositions.forEach(function(tabposition) { tabpositions.forEach(function(tabposition) {
if (pos > tabposition) pos -= 1; if (pos > tabposition) pos -= 1;
}); });
error.character = pos; error.character = pos;
} }
} }
var start = error.character - 1, end = start + 1; var start = error.character - 1, end = start + 1;
if (error.evidence) { if (error.evidence) {
index = error.evidence.substring(start).search(/.\b/); index = error.evidence.substring(start).search(/.\b/);
if (index > -1) { if (index > -1) {
end += index; end += index;
} }
} }
// Convert to format expected by validation service // Convert to format expected by validation service
error.description = error.reason;// + "(jshint)"; error.description = error.reason;// + "(jshint)";
error.start = error.character; error.start = error.character;
error.end = end; error.end = end;
error = cleanup(error); error = cleanup(error);
if (error) if (error)
output.push({message: error.description, output.push({message: error.description,
severity: error.severity, severity: error.severity,
from: CodeMirror.Pos(error.line - 1, start), from: CodeMirror.Pos(error.line - 1, start),
to: CodeMirror.Pos(error.line - 1, end)}); to: CodeMirror.Pos(error.line - 1, end)});
} }
} }
} }
}); });

View File

@@ -1,31 +1,31 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
// Depends on jsonlint.js from https://github.com/zaach/jsonlint // Depends on jsonlint.js from https://github.com/zaach/jsonlint
// declare global: jsonlint // declare global: jsonlint
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
CodeMirror.registerHelper("lint", "json", function(text) { CodeMirror.registerHelper("lint", "json", function(text) {
var found = []; var found = [];
jsonlint.parseError = function(str, hash) { jsonlint.parseError = function(str, hash) {
var loc = hash.loc; var loc = hash.loc;
found.push({from: CodeMirror.Pos(loc.first_line - 1, loc.first_column), found.push({from: CodeMirror.Pos(loc.first_line - 1, loc.first_column),
to: CodeMirror.Pos(loc.last_line - 1, loc.last_column), to: CodeMirror.Pos(loc.last_line - 1, loc.last_column),
message: str}); message: str});
}; };
try { jsonlint.parse(text); } try { jsonlint.parse(text); }
catch(e) {} catch(e) {}
return found; return found;
}); });
}); });

View File

@@ -1,73 +1,73 @@
/* The lint marker gutter */ /* The lint marker gutter */
.CodeMirror-lint-markers { .CodeMirror-lint-markers {
width: 16px; width: 16px;
} }
.CodeMirror-lint-tooltip { .CodeMirror-lint-tooltip {
background-color: infobackground; background-color: infobackground;
border: 1px solid black; border: 1px solid black;
border-radius: 4px 4px 4px 4px; border-radius: 4px 4px 4px 4px;
color: infotext; color: infotext;
font-family: monospace; font-family: monospace;
font-size: 10pt; font-size: 10pt;
overflow: hidden; overflow: hidden;
padding: 2px 5px; padding: 2px 5px;
position: fixed; position: fixed;
white-space: pre; white-space: pre;
white-space: pre-wrap; white-space: pre-wrap;
z-index: 100; z-index: 100;
max-width: 600px; max-width: 600px;
opacity: 0; opacity: 0;
transition: opacity .4s; transition: opacity .4s;
-moz-transition: opacity .4s; -moz-transition: opacity .4s;
-webkit-transition: opacity .4s; -webkit-transition: opacity .4s;
-o-transition: opacity .4s; -o-transition: opacity .4s;
-ms-transition: opacity .4s; -ms-transition: opacity .4s;
} }
.CodeMirror-lint-mark-error, .CodeMirror-lint-mark-warning { .CodeMirror-lint-mark-error, .CodeMirror-lint-mark-warning {
background-position: left bottom; background-position: left bottom;
background-repeat: repeat-x; background-repeat: repeat-x;
} }
.CodeMirror-lint-mark-error { .CodeMirror-lint-mark-error {
background-image: background-image:
url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==") url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==")
; ;
} }
.CodeMirror-lint-mark-warning { .CodeMirror-lint-mark-warning {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII="); background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII=");
} }
.CodeMirror-lint-marker-error, .CodeMirror-lint-marker-warning { .CodeMirror-lint-marker-error, .CodeMirror-lint-marker-warning {
background-position: center center; background-position: center center;
background-repeat: no-repeat; background-repeat: no-repeat;
cursor: pointer; cursor: pointer;
display: inline-block; display: inline-block;
height: 16px; height: 16px;
width: 16px; width: 16px;
vertical-align: middle; vertical-align: middle;
position: relative; position: relative;
} }
.CodeMirror-lint-message-error, .CodeMirror-lint-message-warning { .CodeMirror-lint-message-error, .CodeMirror-lint-message-warning {
padding-left: 18px; padding-left: 18px;
background-position: top left; background-position: top left;
background-repeat: no-repeat; background-repeat: no-repeat;
} }
.CodeMirror-lint-marker-error, .CodeMirror-lint-message-error { .CodeMirror-lint-marker-error, .CodeMirror-lint-message-error {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII="); background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII=");
} }
.CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning { .CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII="); background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII=");
} }
.CodeMirror-lint-marker-multiple { .CodeMirror-lint-marker-multiple {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC"); background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC");
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: right bottom; background-position: right bottom;
width: 100%; height: 100%; width: 100%; height: 100%;
} }

View File

@@ -1,239 +1,239 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
var GUTTER_ID = "CodeMirror-lint-markers"; var GUTTER_ID = "CodeMirror-lint-markers";
function showTooltip(e, content) { function showTooltip(e, content) {
var tt = document.createElement("div"); var tt = document.createElement("div");
tt.className = "CodeMirror-lint-tooltip"; tt.className = "CodeMirror-lint-tooltip";
tt.appendChild(content.cloneNode(true)); tt.appendChild(content.cloneNode(true));
document.body.appendChild(tt); document.body.appendChild(tt);
function position(e) { function position(e) {
if (!tt.parentNode) return CodeMirror.off(document, "mousemove", position); if (!tt.parentNode) return CodeMirror.off(document, "mousemove", position);
tt.style.top = Math.max(0, e.clientY - tt.offsetHeight - 5) + "px"; tt.style.top = Math.max(0, e.clientY - tt.offsetHeight - 5) + "px";
tt.style.left = (e.clientX + 5) + "px"; tt.style.left = (e.clientX + 5) + "px";
} }
CodeMirror.on(document, "mousemove", position); CodeMirror.on(document, "mousemove", position);
position(e); position(e);
if (tt.style.opacity != null) tt.style.opacity = 1; if (tt.style.opacity != null) tt.style.opacity = 1;
return tt; return tt;
} }
function rm(elt) { function rm(elt) {
if (elt.parentNode) elt.parentNode.removeChild(elt); if (elt.parentNode) elt.parentNode.removeChild(elt);
} }
function hideTooltip(tt) { function hideTooltip(tt) {
if (!tt.parentNode) return; if (!tt.parentNode) return;
if (tt.style.opacity == null) rm(tt); if (tt.style.opacity == null) rm(tt);
tt.style.opacity = 0; tt.style.opacity = 0;
setTimeout(function() { rm(tt); }, 600); setTimeout(function() { rm(tt); }, 600);
} }
function showTooltipFor(e, content, node) { function showTooltipFor(e, content, node) {
var tooltip = showTooltip(e, content); var tooltip = showTooltip(e, content);
function hide() { function hide() {
CodeMirror.off(node, "mouseout", hide); CodeMirror.off(node, "mouseout", hide);
if (tooltip) { hideTooltip(tooltip); tooltip = null; } if (tooltip) { hideTooltip(tooltip); tooltip = null; }
} }
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 && n.nodeType == 11) n = n.host;
if (n == document.body) return; if (n == document.body) return;
if (!n) { hide(); break; } if (!n) { hide(); break; }
} }
if (!tooltip) return clearInterval(poll); if (!tooltip) return clearInterval(poll);
}, 400); }, 400);
CodeMirror.on(node, "mouseout", hide); CodeMirror.on(node, "mouseout", hide);
} }
function LintState(cm, options, hasGutter) { function LintState(cm, options, hasGutter) {
this.marked = []; this.marked = [];
this.options = options; this.options = options;
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 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 = {};
return options; return options;
} }
function clearMarks(cm) { function clearMarks(cm) {
var state = cm.state.lint; var state = cm.state.lint;
if (state.hasGutter) cm.clearGutter(GUTTER_ID); if (state.hasGutter) cm.clearGutter(GUTTER_ID);
for (var i = 0; i < state.marked.length; ++i) for (var i = 0; i < state.marked.length; ++i)
state.marked[i].clear(); state.marked[i].clear();
state.marked.length = 0; state.marked.length = 0;
} }
function makeMarker(labels, severity, multiple, tooltips) { function makeMarker(labels, severity, multiple, tooltips) {
var marker = document.createElement("div"), inner = marker; var marker = document.createElement("div"), inner = marker;
marker.className = "CodeMirror-lint-marker-" + severity; marker.className = "CodeMirror-lint-marker-" + severity;
if (multiple) { if (multiple) {
inner = marker.appendChild(document.createElement("div")); inner = marker.appendChild(document.createElement("div"));
inner.className = "CodeMirror-lint-marker-multiple"; inner.className = "CodeMirror-lint-marker-multiple";
} }
if (tooltips != false) CodeMirror.on(inner, "mouseover", function(e) { if (tooltips != false) CodeMirror.on(inner, "mouseover", function(e) {
showTooltipFor(e, labels, inner); showTooltipFor(e, labels, inner);
}); });
return marker; return marker;
} }
function getMaxSeverity(a, b) { function getMaxSeverity(a, b) {
if (a == "error") return a; if (a == "error") return a;
else return b; else return b;
} }
function groupByLine(annotations) { function groupByLine(annotations) {
var lines = []; var lines = [];
for (var i = 0; i < annotations.length; ++i) { for (var i = 0; i < annotations.length; ++i) {
var ann = annotations[i], line = ann.from.line; var ann = annotations[i], line = ann.from.line;
(lines[line] || (lines[line] = [])).push(ann); (lines[line] || (lines[line] = [])).push(ann);
} }
return lines; return lines;
} }
function annotationTooltip(ann) { function annotationTooltip(ann) {
var severity = ann.severity; var severity = ann.severity;
if (!severity) severity = "error"; if (!severity) severity = "error";
var tip = document.createElement("div"); var tip = document.createElement("div");
tip.className = "CodeMirror-lint-message-" + severity; tip.className = "CodeMirror-lint-message-" + severity;
tip.appendChild(document.createTextNode(ann.message)); tip.appendChild(document.createTextNode(ann.message));
return tip; return tip;
} }
function lintAsync(cm, getAnnotations, passOptions) { function lintAsync(cm, getAnnotations, passOptions) {
var state = cm.state.lint var state = cm.state.lint
var id = ++state.waitingFor var id = ++state.waitingFor
function abort() { function abort() {
id = -1 id = -1
cm.off("change", abort) cm.off("change", abort)
} }
cm.on("change", abort) cm.on("change", abort)
getAnnotations(cm.getValue(), function(annotations, arg2) { getAnnotations(cm.getValue(), function(annotations, arg2) {
cm.off("change", abort) cm.off("change", abort)
if (state.waitingFor != id) return if (state.waitingFor != id) return
if (arg2 && annotations instanceof CodeMirror) annotations = arg2 if (arg2 && annotations instanceof CodeMirror) annotations = arg2
updateLinting(cm, annotations) updateLinting(cm, annotations)
}, passOptions, cm); }, 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
var getAnnotations = options.getAnnotations || cm.getHelper(CodeMirror.Pos(0, 0), "lint"); var getAnnotations = options.getAnnotations || cm.getHelper(CodeMirror.Pos(0, 0), "lint");
if (!getAnnotations) return; if (!getAnnotations) return;
if (options.async || getAnnotations.async) { if (options.async || getAnnotations.async) {
lintAsync(cm, getAnnotations, passOptions) lintAsync(cm, getAnnotations, passOptions)
} else { } else {
updateLinting(cm, getAnnotations(cm.getValue(), passOptions, cm)); updateLinting(cm, getAnnotations(cm.getValue(), passOptions, cm));
} }
} }
function updateLinting(cm, annotationsNotSorted) { function updateLinting(cm, annotationsNotSorted) {
clearMarks(cm); clearMarks(cm);
var state = cm.state.lint, options = state.options; var state = cm.state.lint, options = state.options;
var annotations = groupByLine(annotationsNotSorted); var annotations = groupByLine(annotationsNotSorted);
for (var line = 0; line < annotations.length; ++line) { for (var line = 0; line < annotations.length; ++line) {
var anns = annotations[line]; var anns = annotations[line];
if (!anns) continue; if (!anns) continue;
var maxSeverity = null; var maxSeverity = null;
var tipLabel = state.hasGutter && document.createDocumentFragment(); var tipLabel = state.hasGutter && document.createDocumentFragment();
for (var i = 0; i < anns.length; ++i) { for (var i = 0; i < anns.length; ++i) {
var ann = anns[i]; var ann = anns[i];
var severity = ann.severity; var severity = ann.severity;
if (!severity) severity = "error"; if (!severity) severity = "error";
maxSeverity = getMaxSeverity(maxSeverity, severity); maxSeverity = getMaxSeverity(maxSeverity, severity);
if (options.formatAnnotation) ann = options.formatAnnotation(ann); if (options.formatAnnotation) ann = options.formatAnnotation(ann);
if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann)); if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann));
if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, { if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, {
className: "CodeMirror-lint-mark-" + severity, className: "CodeMirror-lint-mark-" + severity,
__annotation: ann __annotation: ann
})); }));
} }
if (state.hasGutter) if (state.hasGutter)
cm.setGutterMarker(line, GUTTER_ID, makeMarker(tipLabel, maxSeverity, anns.length > 1, cm.setGutterMarker(line, GUTTER_ID, makeMarker(tipLabel, maxSeverity, anns.length > 1,
state.options.tooltips)); state.options.tooltips));
} }
if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm); if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm);
} }
function onChange(cm) { function onChange(cm) {
var state = cm.state.lint; var state = cm.state.lint;
if (!state) return; 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 popupTooltips(annotations, e) { function popupTooltips(annotations, e) {
var target = e.target || e.srcElement; var target = e.target || e.srcElement;
var tooltip = document.createDocumentFragment(); var tooltip = document.createDocumentFragment();
for (var i = 0; i < annotations.length; i++) { for (var i = 0; i < annotations.length; i++) {
var ann = annotations[i]; var ann = annotations[i];
tooltip.appendChild(annotationTooltip(ann)); tooltip.appendChild(annotationTooltip(ann));
} }
showTooltipFor(e, tooltip, target); showTooltipFor(e, tooltip, target);
} }
function onMouseOver(cm, e) { function onMouseOver(cm, e) {
var target = e.target || e.srcElement; var target = e.target || e.srcElement;
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 = []; var annotations = [];
for (var i = 0; i < spans.length; ++i) { for (var i = 0; i < spans.length; ++i) {
var ann = spans[i].__annotation; var ann = spans[i].__annotation;
if (ann) annotations.push(ann); if (ann) annotations.push(ann);
} }
if (annotations.length) popupTooltips(annotations, 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) 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); clearTimeout(cm.state.lint.timeout);
delete cm.state.lint; delete cm.state.lint;
} }
if (val) { if (val) {
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) 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);
startLinting(cm); startLinting(cm);
} }
}); });
CodeMirror.defineExtension("performLint", function() { CodeMirror.defineExtension("performLint", function() {
if (this.state.lint) startLinting(this); if (this.state.lint) startLinting(this);
}); });
}); });

View File

@@ -1,28 +1,28 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
// Depends on js-yaml.js from https://github.com/nodeca/js-yaml // Depends on js-yaml.js from https://github.com/nodeca/js-yaml
// declare global: jsyaml // declare global: jsyaml
CodeMirror.registerHelper("lint", "yaml", function(text) { CodeMirror.registerHelper("lint", "yaml", function(text) {
var found = []; var found = [];
try { jsyaml.load(text); } try { jsyaml.load(text); }
catch(e) { catch(e) {
var loc = e.mark; var loc = e.mark;
found.push({ from: CodeMirror.Pos(loc.line, loc.column), to: CodeMirror.Pos(loc.line, loc.column), message: e.message }); found.push({ from: CodeMirror.Pos(loc.line, loc.column), to: CodeMirror.Pos(loc.line, loc.column), message: e.message });
} }
return found; return found;
}); });
}); });

View File

@@ -1,113 +1,113 @@
.CodeMirror-merge { .CodeMirror-merge {
position: relative; position: relative;
border: 1px solid #ddd; border: 1px solid #ddd;
white-space: pre; white-space: pre;
} }
.CodeMirror-merge, .CodeMirror-merge .CodeMirror { .CodeMirror-merge, .CodeMirror-merge .CodeMirror {
height: 350px; height: 350px;
} }
.CodeMirror-merge-2pane .CodeMirror-merge-pane { width: 47%; } .CodeMirror-merge-2pane .CodeMirror-merge-pane { width: 47%; }
.CodeMirror-merge-2pane .CodeMirror-merge-gap { width: 6%; } .CodeMirror-merge-2pane .CodeMirror-merge-gap { width: 6%; }
.CodeMirror-merge-3pane .CodeMirror-merge-pane { width: 31%; } .CodeMirror-merge-3pane .CodeMirror-merge-pane { width: 31%; }
.CodeMirror-merge-3pane .CodeMirror-merge-gap { width: 3.5%; } .CodeMirror-merge-3pane .CodeMirror-merge-gap { width: 3.5%; }
.CodeMirror-merge-pane { .CodeMirror-merge-pane {
display: inline-block; display: inline-block;
white-space: normal; white-space: normal;
vertical-align: top; vertical-align: top;
} }
.CodeMirror-merge-pane-rightmost { .CodeMirror-merge-pane-rightmost {
position: absolute; position: absolute;
right: 0px; right: 0px;
z-index: 1; z-index: 1;
} }
.CodeMirror-merge-gap { .CodeMirror-merge-gap {
z-index: 2; z-index: 2;
display: inline-block; display: inline-block;
height: 100%; height: 100%;
-moz-box-sizing: border-box; -moz-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
overflow: hidden; overflow: hidden;
border-left: 1px solid #ddd; border-left: 1px solid #ddd;
border-right: 1px solid #ddd; border-right: 1px solid #ddd;
position: relative; position: relative;
background: #f8f8f8; background: #f8f8f8;
} }
.CodeMirror-merge-scrolllock-wrap { .CodeMirror-merge-scrolllock-wrap {
position: absolute; position: absolute;
bottom: 0; left: 50%; bottom: 0; left: 50%;
} }
.CodeMirror-merge-scrolllock { .CodeMirror-merge-scrolllock {
position: relative; position: relative;
left: -50%; left: -50%;
cursor: pointer; cursor: pointer;
color: #555; color: #555;
line-height: 1; line-height: 1;
} }
.CodeMirror-merge-copybuttons-left, .CodeMirror-merge-copybuttons-right { .CodeMirror-merge-copybuttons-left, .CodeMirror-merge-copybuttons-right {
position: absolute; position: absolute;
left: 0; top: 0; left: 0; top: 0;
right: 0; bottom: 0; right: 0; bottom: 0;
line-height: 1; line-height: 1;
} }
.CodeMirror-merge-copy { .CodeMirror-merge-copy {
position: absolute; position: absolute;
cursor: pointer; cursor: pointer;
color: #44c; color: #44c;
z-index: 3; z-index: 3;
} }
.CodeMirror-merge-copy-reverse { .CodeMirror-merge-copy-reverse {
position: absolute; position: absolute;
cursor: pointer; cursor: pointer;
color: #44c; color: #44c;
} }
.CodeMirror-merge-copybuttons-left .CodeMirror-merge-copy { left: 2px; } .CodeMirror-merge-copybuttons-left .CodeMirror-merge-copy { left: 2px; }
.CodeMirror-merge-copybuttons-right .CodeMirror-merge-copy { right: 2px; } .CodeMirror-merge-copybuttons-right .CodeMirror-merge-copy { right: 2px; }
.CodeMirror-merge-r-inserted, .CodeMirror-merge-l-inserted { .CodeMirror-merge-r-inserted, .CodeMirror-merge-l-inserted {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12MwuCXy3+CWyH8GBgYGJgYkAABZbAQ9ELXurwAAAABJRU5ErkJggg==); background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12MwuCXy3+CWyH8GBgYGJgYkAABZbAQ9ELXurwAAAABJRU5ErkJggg==);
background-position: bottom left; background-position: bottom left;
background-repeat: repeat-x; background-repeat: repeat-x;
} }
.CodeMirror-merge-r-deleted, .CodeMirror-merge-l-deleted { .CodeMirror-merge-r-deleted, .CodeMirror-merge-l-deleted {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12M4Kyb2/6yY2H8GBgYGJgYkAABURgPz6Ks7wQAAAABJRU5ErkJggg==); background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12M4Kyb2/6yY2H8GBgYGJgYkAABURgPz6Ks7wQAAAABJRU5ErkJggg==);
background-position: bottom left; background-position: bottom left;
background-repeat: repeat-x; background-repeat: repeat-x;
} }
.CodeMirror-merge-r-chunk { background: #ffffe0; } .CodeMirror-merge-r-chunk { background: #ffffe0; }
.CodeMirror-merge-r-chunk-start { border-top: 1px solid #ee8; } .CodeMirror-merge-r-chunk-start { border-top: 1px solid #ee8; }
.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #ee8; } .CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #ee8; }
.CodeMirror-merge-r-connect { fill: #ffffe0; stroke: #ee8; stroke-width: 1px; } .CodeMirror-merge-r-connect { fill: #ffffe0; stroke: #ee8; stroke-width: 1px; }
.CodeMirror-merge-l-chunk { background: #eef; } .CodeMirror-merge-l-chunk { background: #eef; }
.CodeMirror-merge-l-chunk-start { border-top: 1px solid #88e; } .CodeMirror-merge-l-chunk-start { border-top: 1px solid #88e; }
.CodeMirror-merge-l-chunk-end { border-bottom: 1px solid #88e; } .CodeMirror-merge-l-chunk-end { border-bottom: 1px solid #88e; }
.CodeMirror-merge-l-connect { fill: #eef; stroke: #88e; stroke-width: 1px; } .CodeMirror-merge-l-connect { fill: #eef; stroke: #88e; stroke-width: 1px; }
.CodeMirror-merge-l-chunk.CodeMirror-merge-r-chunk { background: #dfd; } .CodeMirror-merge-l-chunk.CodeMirror-merge-r-chunk { background: #dfd; }
.CodeMirror-merge-l-chunk-start.CodeMirror-merge-r-chunk-start { border-top: 1px solid #4e4; } .CodeMirror-merge-l-chunk-start.CodeMirror-merge-r-chunk-start { border-top: 1px solid #4e4; }
.CodeMirror-merge-l-chunk-end.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #4e4; } .CodeMirror-merge-l-chunk-end.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #4e4; }
.CodeMirror-merge-collapsed-widget:before { .CodeMirror-merge-collapsed-widget:before {
content: "(...)"; content: "(...)";
} }
.CodeMirror-merge-collapsed-widget { .CodeMirror-merge-collapsed-widget {
cursor: pointer; cursor: pointer;
color: #88b; color: #88b;
background: #eef; background: #eef;
border: 1px solid #ddf; border: 1px solid #ddf;
font-size: 90%; font-size: 90%;
padding: 0 3px; padding: 0 3px;
border-radius: 4px; border-radius: 4px;
} }
.CodeMirror-merge-collapsed-line .CodeMirror-gutter-elt { display: none; } .CodeMirror-merge-collapsed-line .CodeMirror-gutter-elt { display: none; }

File diff suppressed because it is too large Load Diff

View File

@@ -1,64 +1,64 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) { (function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), "cjs"); mod(require("../../lib/codemirror"), "cjs");
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], function(CM) { mod(CM, "amd"); }); define(["../../lib/codemirror"], function(CM) { mod(CM, "amd"); });
else // Plain browser env else // Plain browser env
mod(CodeMirror, "plain"); mod(CodeMirror, "plain");
})(function(CodeMirror, env) { })(function(CodeMirror, env) {
if (!CodeMirror.modeURL) CodeMirror.modeURL = "../mode/%N/%N.js"; if (!CodeMirror.modeURL) CodeMirror.modeURL = "../mode/%N/%N.js";
var loading = {}; var loading = {};
function splitCallback(cont, n) { function splitCallback(cont, n) {
var countDown = n; var countDown = n;
return function() { if (--countDown == 0) cont(); }; return function() { if (--countDown == 0) cont(); };
} }
function ensureDeps(mode, cont) { function ensureDeps(mode, cont) {
var deps = CodeMirror.modes[mode].dependencies; var deps = CodeMirror.modes[mode].dependencies;
if (!deps) return cont(); if (!deps) return cont();
var missing = []; var missing = [];
for (var i = 0; i < deps.length; ++i) { for (var i = 0; i < deps.length; ++i) {
if (!CodeMirror.modes.hasOwnProperty(deps[i])) if (!CodeMirror.modes.hasOwnProperty(deps[i]))
missing.push(deps[i]); missing.push(deps[i]);
} }
if (!missing.length) return cont(); if (!missing.length) return cont();
var split = splitCallback(cont, missing.length); var split = splitCallback(cont, missing.length);
for (var i = 0; i < missing.length; ++i) for (var i = 0; i < missing.length; ++i)
CodeMirror.requireMode(missing[i], split); CodeMirror.requireMode(missing[i], split);
} }
CodeMirror.requireMode = function(mode, cont) { CodeMirror.requireMode = function(mode, cont) {
if (typeof mode != "string") mode = mode.name; if (typeof mode != "string") mode = mode.name;
if (CodeMirror.modes.hasOwnProperty(mode)) return ensureDeps(mode, cont); if (CodeMirror.modes.hasOwnProperty(mode)) return ensureDeps(mode, cont);
if (loading.hasOwnProperty(mode)) return loading[mode].push(cont); if (loading.hasOwnProperty(mode)) return loading[mode].push(cont);
var file = CodeMirror.modeURL.replace(/%N/g, mode); var file = CodeMirror.modeURL.replace(/%N/g, mode);
if (env == "plain") { if (env == "plain") {
var script = document.createElement("script"); var script = document.createElement("script");
script.src = file; script.src = file;
var others = document.getElementsByTagName("script")[0]; var others = document.getElementsByTagName("script")[0];
var list = loading[mode] = [cont]; var list = loading[mode] = [cont];
CodeMirror.on(script, "load", function() { CodeMirror.on(script, "load", function() {
ensureDeps(mode, function() { ensureDeps(mode, function() {
for (var i = 0; i < list.length; ++i) list[i](); for (var i = 0; i < list.length; ++i) list[i]();
}); });
}); });
others.parentNode.insertBefore(script, others); others.parentNode.insertBefore(script, others);
} else if (env == "cjs") { } else if (env == "cjs") {
require(file); require(file);
cont(); cont();
} else if (env == "amd") { } else if (env == "amd") {
requirejs([file], cont); requirejs([file], cont);
} }
}; };
CodeMirror.autoLoadMode = function(instance, mode) { CodeMirror.autoLoadMode = function(instance, mode) {
if (!CodeMirror.modes.hasOwnProperty(mode)) if (!CodeMirror.modes.hasOwnProperty(mode))
CodeMirror.requireMode(mode, function() { CodeMirror.requireMode(mode, function() {
instance.setOption("mode", instance.getOption("mode")); instance.setOption("mode", instance.getOption("mode"));
}); });
}; };
}); });

View File

@@ -1,123 +1,123 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
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);
function indexOf(string, pattern, from, returnEnd) { function indexOf(string, pattern, from, returnEnd) {
if (typeof pattern == "string") { if (typeof pattern == "string") {
var found = string.indexOf(pattern, from); var found = string.indexOf(pattern, from);
return returnEnd && found > -1 ? found + pattern.length : found; 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 + (returnEnd ? m[0].length : 0) : -1; return m ? m.index + from + (returnEnd ? m[0].length : 0) : -1;
} }
return { return {
startState: function() { startState: function() {
return { return {
outer: CodeMirror.startState(outer), outer: CodeMirror.startState(outer),
innerActive: null, innerActive: null,
inner: null inner: null
}; };
}, },
copyState: function(state) { copyState: function(state) {
return { return {
outer: CodeMirror.copyState(outer, state.outer), outer: CodeMirror.copyState(outer, state.outer),
innerActive: state.innerActive, innerActive: state.innerActive,
inner: state.innerActive && CodeMirror.copyState(state.innerActive.mode, state.inner) inner: state.innerActive && CodeMirror.copyState(state.innerActive.mode, state.inner)
}; };
}, },
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 < others.length; ++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) {
if (!other.parseDelimiters) 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 && (other.delimStyle + " " + other.delimStyle + "-open"); return other.delimStyle && (other.delimStyle + " " + other.delimStyle + "-open");
} else if (found != -1 && found < cutOff) { } else if (found != -1 && found < cutOff) {
cutOff = found; cutOff = found;
} }
} }
if (cutOff != Infinity) stream.string = oldContent.slice(0, cutOff); if (cutOff != Infinity) stream.string = oldContent.slice(0, cutOff);
var outerToken = outer.token(stream, state.outer); var outerToken = outer.token(stream, state.outer);
if (cutOff != Infinity) stream.string = oldContent; if (cutOff != Infinity) stream.string = oldContent;
return outerToken; return outerToken;
} else { } else {
var curInner = state.innerActive, oldContent = stream.string; var curInner = state.innerActive, oldContent = stream.string;
if (!curInner.close && stream.sol()) { if (!curInner.close && stream.sol()) {
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, curInner.parseDelimiters) : -1; var found = curInner.close ? indexOf(oldContent, curInner.close, stream.pos, curInner.parseDelimiters) : -1;
if (found == stream.pos && !curInner.parseDelimiters) { 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 && (curInner.delimStyle + " " + curInner.delimStyle + "-close"); 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) if (found == stream.pos && curInner.parseDelimiters)
state.innerActive = state.inner = null; 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;
} }
return innerToken; return innerToken;
} }
}, },
indent: function(state, textAfter) { indent: function(state, textAfter) {
var mode = state.innerActive ? state.innerActive.mode : outer; var mode = state.innerActive ? state.innerActive.mode : outer;
if (!mode.indent) return CodeMirror.Pass; if (!mode.indent) return CodeMirror.Pass;
return mode.indent(state.innerActive ? state.inner : state.outer, textAfter); return mode.indent(state.innerActive ? state.inner : state.outer, textAfter);
}, },
blankLine: function(state) { blankLine: function(state) {
var mode = state.innerActive ? state.innerActive.mode : outer; var mode = state.innerActive ? state.innerActive.mode : outer;
if (mode.blankLine) { if (mode.blankLine) {
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 < others.length; ++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;
state.inner = CodeMirror.startState(other.mode, mode.indent ? mode.indent(state.outer, "") : 0); state.inner = CodeMirror.startState(other.mode, mode.indent ? mode.indent(state.outer, "") : 0);
} }
} }
} else if (state.innerActive.close === "\n") { } else if (state.innerActive.close === "\n") {
state.innerActive = state.inner = null; state.innerActive = state.inner = null;
} }
}, },
electricChars: outer.electricChars, electricChars: outer.electricChars,
innerMode: function(state) { innerMode: function(state) {
return state.inner ? {state: state.inner, mode: state.innerActive.mode} : {state: state.outer, mode: outer}; return state.inner ? {state: state.inner, mode: state.innerActive.mode} : {state: state.outer, mode: outer};
} }
}; };
}; };
}); });

View File

@@ -1,33 +1,33 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(function() { (function() {
CodeMirror.defineMode("markdown_with_stex", function(){ CodeMirror.defineMode("markdown_with_stex", function(){
var inner = CodeMirror.getMode({}, "stex"); var inner = CodeMirror.getMode({}, "stex");
var outer = CodeMirror.getMode({}, "markdown"); var outer = CodeMirror.getMode({}, "markdown");
var innerOptions = { var innerOptions = {
open: '$', open: '$',
close: '$', close: '$',
mode: inner, mode: inner,
delimStyle: 'delim', delimStyle: 'delim',
innerStyle: 'inner' innerStyle: 'inner'
}; };
return CodeMirror.multiplexingMode(outer, innerOptions); return CodeMirror.multiplexingMode(outer, innerOptions);
}); });
var mode = CodeMirror.getMode({}, "markdown_with_stex"); var mode = CodeMirror.getMode({}, "markdown_with_stex");
function MT(name) { function MT(name) {
test.mode( test.mode(
name, name,
mode, mode,
Array.prototype.slice.call(arguments, 1), Array.prototype.slice.call(arguments, 1),
'multiplexing'); 'multiplexing');
} }
MT( MT(
"stexInsideMarkdown", "stexInsideMarkdown",
"[strong **Equation:**] [delim&delim-open $][inner&tag \\pi][delim&delim-close $]"); "[strong **Equation:**] [delim&delim-open $][inner&tag \\pi][delim&delim-close $]");
})(); })();

View File

@@ -1,85 +1,85 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
// Utility function that allows modes to be combined. The mode given // Utility function that allows modes to be combined. The mode given
// as the base argument takes care of most of the normal mode // as the base argument takes care of most of the normal mode
// functionality, but a second (typically simple) mode is used, which // functionality, but a second (typically simple) mode is used, which
// can override the style of text. Both modes get to parse all of the // can override the style of text. Both modes get to parse all of the
// text, but when both assign a non-null style to a piece of code, the // text, but when both assign a non-null style to a piece of code, the
// overlay wins, unless the combine argument was true and not overridden, // overlay wins, unless the combine argument was true and not overridden,
// or state.overlay.combineTokens was true, in which case the styles are // or state.overlay.combineTokens was true, in which case the styles are
// combined. // combined.
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
CodeMirror.overlayMode = function(base, overlay, combine) { CodeMirror.overlayMode = function(base, overlay, combine) {
return { return {
startState: function() { startState: function() {
return { return {
base: CodeMirror.startState(base), base: CodeMirror.startState(base),
overlay: CodeMirror.startState(overlay), overlay: CodeMirror.startState(overlay),
basePos: 0, baseCur: null, basePos: 0, baseCur: null,
overlayPos: 0, overlayCur: null, overlayPos: 0, overlayCur: null,
streamSeen: null streamSeen: null
}; };
}, },
copyState: function(state) { copyState: function(state) {
return { return {
base: CodeMirror.copyState(base, state.base), base: CodeMirror.copyState(base, state.base),
overlay: CodeMirror.copyState(overlay, state.overlay), overlay: CodeMirror.copyState(overlay, state.overlay),
basePos: state.basePos, baseCur: null, basePos: state.basePos, baseCur: null,
overlayPos: state.overlayPos, overlayCur: null overlayPos: state.overlayPos, overlayCur: null
}; };
}, },
token: function(stream, state) { token: function(stream, state) {
if (stream != state.streamSeen || if (stream != state.streamSeen ||
Math.min(state.basePos, state.overlayPos) < stream.start) { Math.min(state.basePos, state.overlayPos) < stream.start) {
state.streamSeen = stream; state.streamSeen = stream;
state.basePos = state.overlayPos = stream.start; state.basePos = state.overlayPos = stream.start;
} }
if (stream.start == state.basePos) { if (stream.start == state.basePos) {
state.baseCur = base.token(stream, state.base); state.baseCur = base.token(stream, state.base);
state.basePos = stream.pos; state.basePos = stream.pos;
} }
if (stream.start == state.overlayPos) { if (stream.start == state.overlayPos) {
stream.pos = stream.start; stream.pos = stream.start;
state.overlayCur = overlay.token(stream, state.overlay); state.overlayCur = overlay.token(stream, state.overlay);
state.overlayPos = stream.pos; state.overlayPos = stream.pos;
} }
stream.pos = Math.min(state.basePos, state.overlayPos); stream.pos = Math.min(state.basePos, state.overlayPos);
// state.overlay.combineTokens always takes precedence over combine, // state.overlay.combineTokens always takes precedence over combine,
// unless set to null // unless set to null
if (state.overlayCur == null) return state.baseCur; if (state.overlayCur == null) return state.baseCur;
else if (state.baseCur != null && else if (state.baseCur != null &&
state.overlay.combineTokens || state.overlay.combineTokens ||
combine && state.overlay.combineTokens == null) combine && state.overlay.combineTokens == null)
return state.baseCur + " " + state.overlayCur; return state.baseCur + " " + state.overlayCur;
else return state.overlayCur; else return state.overlayCur;
}, },
indent: base.indent && function(state, textAfter) { indent: base.indent && function(state, textAfter) {
return base.indent(state.base, textAfter); return base.indent(state.base, textAfter);
}, },
electricChars: base.electricChars, electricChars: base.electricChars,
innerMode: function(state) { return {state: state.base, mode: base}; }, innerMode: function(state) { return {state: state.base, mode: base}; },
blankLine: function(state) { blankLine: function(state) {
if (base.blankLine) base.blankLine(state.base); if (base.blankLine) base.blankLine(state.base);
if (overlay.blankLine) overlay.blankLine(state.overlay); if (overlay.blankLine) overlay.blankLine(state.overlay);
} }
}; };
}; };
}); });

View File

@@ -1,213 +1,213 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
CodeMirror.defineSimpleMode = function(name, states) { CodeMirror.defineSimpleMode = function(name, states) {
CodeMirror.defineMode(name, function(config) { CodeMirror.defineMode(name, function(config) {
return CodeMirror.simpleMode(config, states); return CodeMirror.simpleMode(config, states);
}); });
}; };
CodeMirror.simpleMode = function(config, states) { CodeMirror.simpleMode = function(config, states) {
ensureState(states, "start"); ensureState(states, "start");
var states_ = {}, meta = states.meta || {}, hasIndentation = false; var states_ = {}, meta = states.meta || {}, hasIndentation = false;
for (var state in states) if (state != meta && states.hasOwnProperty(state)) { for (var state in states) if (state != meta && states.hasOwnProperty(state)) {
var list = states_[state] = [], orig = states[state]; var list = states_[state] = [], orig = states[state];
for (var i = 0; i < orig.length; i++) { for (var i = 0; i < orig.length; i++) {
var data = orig[i]; var data = orig[i];
list.push(new Rule(data, states)); list.push(new Rule(data, states));
if (data.indent || data.dedent) hasIndentation = true; if (data.indent || data.dedent) hasIndentation = true;
} }
} }
var mode = { var mode = {
startState: function() { startState: function() {
return {state: "start", pending: null, return {state: "start", pending: null,
local: null, localState: null, local: null, localState: null,
indent: hasIndentation ? [] : null}; indent: hasIndentation ? [] : null};
}, },
copyState: function(state) { copyState: function(state) {
var s = {state: state.state, pending: state.pending, var s = {state: state.state, pending: state.pending,
local: state.local, localState: null, local: state.local, localState: null,
indent: state.indent && state.indent.slice(0)}; indent: state.indent && state.indent.slice(0)};
if (state.localState) if (state.localState)
s.localState = CodeMirror.copyState(state.local.mode, state.localState); s.localState = CodeMirror.copyState(state.local.mode, state.localState);
if (state.stack) if (state.stack)
s.stack = state.stack.slice(0); s.stack = state.stack.slice(0);
for (var pers = state.persistentStates; pers; pers = pers.next) for (var pers = state.persistentStates; pers; pers = pers.next)
s.persistentStates = {mode: pers.mode, s.persistentStates = {mode: pers.mode,
spec: pers.spec, spec: pers.spec,
state: pers.state == state.localState ? s.localState : CodeMirror.copyState(pers.mode, pers.state), state: pers.state == state.localState ? s.localState : CodeMirror.copyState(pers.mode, pers.state),
next: s.persistentStates}; next: s.persistentStates};
return s; return s;
}, },
token: tokenFunction(states_, config), token: tokenFunction(states_, config),
innerMode: function(state) { return state.local && {mode: state.local.mode, state: state.localState}; }, innerMode: function(state) { return state.local && {mode: state.local.mode, state: state.localState}; },
indent: indentFunction(states_, meta) indent: indentFunction(states_, meta)
}; };
if (meta) for (var prop in meta) if (meta.hasOwnProperty(prop)) if (meta) for (var prop in meta) if (meta.hasOwnProperty(prop))
mode[prop] = meta[prop]; mode[prop] = meta[prop];
return mode; return mode;
}; };
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) {
if (!val) return /(?:)/; if (!val) return /(?:)/;
var flags = ""; var flags = "";
if (val instanceof RegExp) { if (val instanceof RegExp) {
if (val.ignoreCase) flags = "i"; if (val.ignoreCase) flags = "i";
val = val.source; val = val.source;
} else { } else {
val = String(val); val = String(val);
} }
return new RegExp((caret === false ? "" : "^") + "(?:" + val + ")", flags); return new RegExp((caret === false ? "" : "^") + "(?:" + val + ")", flags);
} }
function asToken(val) { function asToken(val) {
if (!val) return null; if (!val) return null;
if (typeof val == "string") return val.replace(/\./g, " "); if (typeof val == "string") return val.replace(/\./g, " ");
var result = []; var result = [];
for (var i = 0; i < val.length; i++) for (var i = 0; i < val.length; i++)
result.push(val[i] && val[i].replace(/\./g, " ")); result.push(val[i] && val[i].replace(/\./g, " "));
return result; return result;
} }
function Rule(data, states) { function Rule(data, states) {
if (data.next || data.push) ensureState(states, data.next || data.push); if (data.next || data.push) ensureState(states, data.next || data.push);
this.regex = toRegex(data.regex); this.regex = toRegex(data.regex);
this.token = asToken(data.token); this.token = asToken(data.token);
this.data = data; this.data = data;
} }
function tokenFunction(states, config) { function tokenFunction(states, config) {
return function(stream, state) { return function(stream, state) {
if (state.pending) { if (state.pending) {
var pend = state.pending.shift(); var pend = state.pending.shift();
if (state.pending.length == 0) state.pending = null; if (state.pending.length == 0) state.pending = null;
stream.pos += pend.text.length; stream.pos += pend.text.length;
return pend.token; return pend.token;
} }
if (state.local) { if (state.local) {
if (state.local.end && stream.match(state.local.end)) { if (state.local.end && stream.match(state.local.end)) {
var tok = state.local.endToken || null; var tok = state.local.endToken || null;
state.local = state.localState = null; state.local = state.localState = null;
return tok; return tok;
} else { } else {
var tok = state.local.mode.token(stream, state.localState), m; var tok = state.local.mode.token(stream, state.localState), m;
if (state.local.endScan && (m = state.local.endScan.exec(stream.current()))) if (state.local.endScan && (m = state.local.endScan.exec(stream.current())))
stream.pos = stream.start + m.index; stream.pos = stream.start + m.index;
return tok; return tok;
} }
} }
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 = (!rule.data.sol || stream.sol()) && 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;
} else if (rule.data.push) { } else if (rule.data.push) {
(state.stack || (state.stack = [])).push(state.state); (state.stack || (state.stack = [])).push(state.state);
state.state = rule.data.push; state.state = rule.data.push;
} else if (rule.data.pop && state.stack && state.stack.length) { } else if (rule.data.pop && state.stack && state.stack.length) {
state.state = state.stack.pop(); state.state = state.stack.pop();
} }
if (rule.data.mode) if (rule.data.mode)
enterLocalMode(config, state, rule.data.mode, rule.token); enterLocalMode(config, state, rule.data.mode, rule.token);
if (rule.data.indent) if (rule.data.indent)
state.indent.push(stream.indentation() + config.indentUnit); state.indent.push(stream.indentation() + config.indentUnit);
if (rule.data.dedent) if (rule.data.dedent)
state.indent.pop(); state.indent.pop();
if (matches.length > 2) { if (matches.length > 2) {
state.pending = []; state.pending = [];
for (var j = 2; j < matches.length; j++) for (var j = 2; j < matches.length; j++)
if (matches[j]) if (matches[j])
state.pending.push({text: matches[j], token: rule.token[j - 1]}); state.pending.push({text: matches[j], token: rule.token[j - 1]});
stream.backUp(matches[0].length - (matches[1] ? matches[1].length : 0)); stream.backUp(matches[0].length - (matches[1] ? matches[1].length : 0));
return rule.token[0]; return rule.token[0];
} else if (rule.token && rule.token.join) { } else if (rule.token && rule.token.join) {
return rule.token[0]; return rule.token[0];
} else { } else {
return rule.token; return rule.token;
} }
} }
} }
stream.next(); stream.next();
return null; return null;
}; };
} }
function cmp(a, b) { function cmp(a, b) {
if (a === b) return true; if (a === b) return true;
if (!a || typeof a != "object" || !b || typeof b != "object") return false; if (!a || typeof a != "object" || !b || typeof b != "object") return false;
var props = 0; var props = 0;
for (var prop in a) if (a.hasOwnProperty(prop)) { for (var prop in a) if (a.hasOwnProperty(prop)) {
if (!b.hasOwnProperty(prop) || !cmp(a[prop], b[prop])) return false; if (!b.hasOwnProperty(prop) || !cmp(a[prop], b[prop])) return false;
props++; props++;
} }
for (var prop in b) if (b.hasOwnProperty(prop)) props--; for (var prop in b) if (b.hasOwnProperty(prop)) props--;
return props == 0; return props == 0;
} }
function enterLocalMode(config, state, spec, token) { function enterLocalMode(config, state, spec, token) {
var pers; var pers;
if (spec.persistent) for (var p = state.persistentStates; p && !pers; p = p.next) if (spec.persistent) for (var p = state.persistentStates; p && !pers; p = p.next)
if (spec.spec ? cmp(spec.spec, p.spec) : spec.mode == p.mode) pers = p; if (spec.spec ? cmp(spec.spec, p.spec) : spec.mode == p.mode) pers = p;
var mode = pers ? pers.mode : spec.mode || CodeMirror.getMode(config, spec.spec); var mode = pers ? pers.mode : spec.mode || CodeMirror.getMode(config, spec.spec);
var lState = pers ? pers.state : CodeMirror.startState(mode); var lState = pers ? pers.state : CodeMirror.startState(mode);
if (spec.persistent && !pers) if (spec.persistent && !pers)
state.persistentStates = {mode: mode, spec: spec.spec, state: lState, next: state.persistentStates}; state.persistentStates = {mode: mode, spec: spec.spec, state: lState, next: state.persistentStates};
state.localState = lState; state.localState = lState;
state.local = {mode: mode, state.local = {mode: mode,
end: spec.end && toRegex(spec.end), end: spec.end && toRegex(spec.end),
endScan: spec.end && spec.forceEnd !== false && toRegex(spec.end, false), endScan: spec.end && spec.forceEnd !== false && toRegex(spec.end, false),
endToken: token && token.join ? token[token.length - 1] : token}; endToken: token && token.join ? token[token.length - 1] : token};
} }
function indexOf(val, arr) { function indexOf(val, arr) {
for (var i = 0; i < arr.length; i++) if (arr[i] === val) return true; for (var i = 0; i < arr.length; i++) if (arr[i] === val) return true;
} }
function indentFunction(states, meta) { function indentFunction(states, meta) {
return function(state, textAfter, line) { return function(state, textAfter, line) {
if (state.local && state.local.mode.indent) if (state.local && state.local.mode.indent)
return state.local.mode.indent(state.localState, textAfter, line); return state.local.mode.indent(state.localState, textAfter, line);
if (state.indent == null || state.local || meta.dontIndentStates && indexOf(state.state, meta.dontIndentStates) > -1) if (state.indent == null || state.local || meta.dontIndentStates && indexOf(state.state, meta.dontIndentStates) > -1)
return CodeMirror.Pass; return CodeMirror.Pass;
var pos = state.indent.length - 1, rules = states[state.state]; var pos = state.indent.length - 1, rules = states[state.state];
scan: for (;;) { scan: for (;;) {
for (var i = 0; i < rules.length; i++) { for (var i = 0; i < rules.length; i++) {
var rule = rules[i]; var rule = rules[i];
if (rule.data.dedent && rule.data.dedentIfLineStart !== false) { if (rule.data.dedent && rule.data.dedentIfLineStart !== false) {
var m = rule.regex.exec(textAfter); var m = rule.regex.exec(textAfter);
if (m && m[0]) { if (m && m[0]) {
pos--; pos--;
if (rule.next || rule.push) rules = states[rule.next || rule.push]; if (rule.next || rule.push) rules = states[rule.next || rule.push];
textAfter = textAfter.slice(m[0].length); textAfter = textAfter.slice(m[0].length);
continue scan; continue scan;
} }
} }
} }
break; break;
} }
return pos < 0 ? 0 : state.indent[pos]; return pos < 0 ? 0 : state.indent[pos];
}; };
} }
}); });

View File

@@ -1,40 +1,40 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) { (function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("./runmode")); mod(require("../../lib/codemirror"), require("./runmode"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "./runmode"], mod); define(["../../lib/codemirror", "./runmode"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
var isBlock = /^(p|li|div|h\\d|pre|blockquote|td)$/; var isBlock = /^(p|li|div|h\\d|pre|blockquote|td)$/;
function textContent(node, out) { function textContent(node, out) {
if (node.nodeType == 3) return out.push(node.nodeValue); if (node.nodeType == 3) return out.push(node.nodeValue);
for (var ch = node.firstChild; ch; ch = ch.nextSibling) { for (var ch = node.firstChild; ch; ch = ch.nextSibling) {
textContent(ch, out); textContent(ch, out);
if (isBlock.test(node.nodeType)) out.push("\n"); if (isBlock.test(node.nodeType)) out.push("\n");
} }
} }
CodeMirror.colorize = function(collection, defaultMode) { CodeMirror.colorize = function(collection, defaultMode) {
if (!collection) collection = document.body.getElementsByTagName("pre"); if (!collection) collection = document.body.getElementsByTagName("pre");
for (var i = 0; i < collection.length; ++i) { for (var i = 0; i < collection.length; ++i) {
var node = collection[i]; var node = collection[i];
var mode = node.getAttribute("data-lang") || defaultMode; var mode = node.getAttribute("data-lang") || defaultMode;
if (!mode) continue; if (!mode) continue;
var text = []; var text = [];
textContent(node, text); textContent(node, text);
node.innerHTML = ""; node.innerHTML = "";
CodeMirror.runMode(text.join(""), mode, node); CodeMirror.runMode(text.join(""), mode, node);
node.className += " cm-s-default"; node.className += " cm-s-default";
} }
}; };
}); });

View File

@@ -1,157 +1,157 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
window.CodeMirror = {}; window.CodeMirror = {};
(function() { (function() {
"use strict"; "use strict";
function splitLines(string){ return string.split(/\r?\n|\r/); }; function splitLines(string){ return string.split(/\r?\n|\r/); };
function StringStream(string) { function StringStream(string) {
this.pos = this.start = 0; this.pos = this.start = 0;
this.string = string; this.string = string;
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 == 0;},
peek: function() {return this.string.charAt(this.pos) || null;}, peek: function() {return this.string.charAt(this.pos) || null;},
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++);
}, },
eat: function(match) { eat: function(match) {
var ch = this.string.charAt(this.pos); var ch = this.string.charAt(this.pos);
if (typeof match == "string") var ok = ch == match; if (typeof match == "string") var ok = ch == match;
else var ok = ch && (match.test ? match.test(ch) : match(ch)); else var ok = ch && (match.test ? match.test(ch) : match(ch));
if (ok) {++this.pos; return ch;} if (ok) {++this.pos; return ch;}
}, },
eatWhile: function(match) { eatWhile: function(match) {
var start = this.pos; var start = this.pos;
while (this.eat(match)){} while (this.eat(match)){}
return this.pos > start; return this.pos > start;
}, },
eatSpace: function() { eatSpace: function() {
var start = this.pos; var start = this.pos;
while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos; while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;
return this.pos > start; return this.pos > start;
}, },
skipToEnd: function() {this.pos = this.string.length;}, skipToEnd: function() {this.pos = this.string.length;},
skipTo: function(ch) { skipTo: function(ch) {
var found = this.string.indexOf(ch, this.pos); var found = this.string.indexOf(ch, this.pos);
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() {return this.start - this.lineStart;},
indentation: function() {return 0;}, indentation: function() {return 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;};
var substr = this.string.substr(this.pos, pattern.length); var substr = this.string.substr(this.pos, pattern.length);
if (cased(substr) == cased(pattern)) { if (cased(substr) == cased(pattern)) {
if (consume !== false) this.pos += pattern.length; if (consume !== false) this.pos += pattern.length;
return true; return true;
} }
} else { } else {
var match = this.string.slice(this.pos).match(pattern); var match = this.string.slice(this.pos).match(pattern);
if (match && match.index > 0) return null; if (match && match.index > 0) return null;
if (match && consume !== false) this.pos += match[0].length; if (match && consume !== false) this.pos += match[0].length;
return match; return match;
} }
}, },
current: function(){return this.string.slice(this.start, this.pos);}, current: function(){return this.string.slice(this.start, this.pos);},
hideFirstChars: function(n, inner) { hideFirstChars: function(n, inner) {
this.lineStart += n; this.lineStart += n;
try { return inner(); } try { return inner(); }
finally { this.lineStart -= n; } finally { this.lineStart -= n; }
} }
}; };
CodeMirror.StringStream = StringStream; CodeMirror.StringStream = StringStream;
CodeMirror.startState = function (mode, a1, a2) { CodeMirror.startState = function (mode, a1, a2) {
return mode.startState ? mode.startState(a1, a2) : true; return mode.startState ? mode.startState(a1, a2) : true;
}; };
var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {}; var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};
CodeMirror.defineMode = function (name, mode) { CodeMirror.defineMode = function (name, mode) {
if (arguments.length > 2) if (arguments.length > 2)
mode.dependencies = Array.prototype.slice.call(arguments, 2); mode.dependencies = Array.prototype.slice.call(arguments, 2);
modes[name] = mode; modes[name] = mode;
}; };
CodeMirror.defineMIME = function (mime, spec) { mimeModes[mime] = spec; }; CodeMirror.defineMIME = function (mime, spec) { mimeModes[mime] = spec; };
CodeMirror.resolveMode = function(spec) { CodeMirror.resolveMode = function(spec) {
if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
spec = mimeModes[spec]; spec = mimeModes[spec];
} else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
spec = mimeModes[spec.name]; spec = mimeModes[spec.name];
} }
if (typeof spec == "string") return {name: spec}; if (typeof spec == "string") return {name: spec};
else return spec || {name: "null"}; else return spec || {name: "null"};
}; };
CodeMirror.getMode = function (options, spec) { CodeMirror.getMode = function (options, spec) {
spec = CodeMirror.resolveMode(spec); spec = CodeMirror.resolveMode(spec);
var mfactory = modes[spec.name]; var mfactory = modes[spec.name];
if (!mfactory) throw new Error("Unknown mode: " + spec); if (!mfactory) throw new Error("Unknown mode: " + spec);
return mfactory(options, spec); return mfactory(options, spec);
}; };
CodeMirror.registerHelper = CodeMirror.registerGlobalHelper = Math.min; CodeMirror.registerHelper = CodeMirror.registerGlobalHelper = Math.min;
CodeMirror.defineMode("null", function() { CodeMirror.defineMode("null", function() {
return {token: function(stream) {stream.skipToEnd();}}; return {token: function(stream) {stream.skipToEnd();}};
}); });
CodeMirror.defineMIME("text/plain", "null"); CodeMirror.defineMIME("text/plain", "null");
CodeMirror.runMode = function (string, modespec, callback, options) { CodeMirror.runMode = function (string, modespec, callback, options) {
var mode = CodeMirror.getMode({ indentUnit: 2 }, modespec); var mode = CodeMirror.getMode({ indentUnit: 2 }, modespec);
if (callback.nodeType == 1) { if (callback.nodeType == 1) {
var tabSize = (options && options.tabSize) || 4; var tabSize = (options && options.tabSize) || 4;
var node = callback, col = 0; var node = callback, col = 0;
node.innerHTML = ""; node.innerHTML = "";
callback = function (text, style) { callback = function (text, style) {
if (text == "\n") { if (text == "\n") {
node.appendChild(document.createElement("br")); node.appendChild(document.createElement("br"));
col = 0; col = 0;
return; return;
} }
var content = ""; var content = "";
// replace tabs // replace tabs
for (var pos = 0; ;) { for (var pos = 0; ;) {
var idx = text.indexOf("\t", pos); var idx = text.indexOf("\t", pos);
if (idx == -1) { if (idx == -1) {
content += text.slice(pos); content += text.slice(pos);
col += text.length - pos; col += text.length - pos;
break; break;
} else { } else {
col += idx - pos; col += idx - pos;
content += text.slice(pos, idx); content += text.slice(pos, idx);
var size = tabSize - col % tabSize; var size = tabSize - col % tabSize;
col += size; col += size;
for (var i = 0; i < size; ++i) content += " "; for (var i = 0; i < size; ++i) content += " ";
pos = idx + 1; pos = idx + 1;
} }
} }
if (style) { if (style) {
var sp = node.appendChild(document.createElement("span")); var sp = node.appendChild(document.createElement("span"));
sp.className = "cm-" + style.replace(/ +/g, " cm-"); sp.className = "cm-" + style.replace(/ +/g, " cm-");
sp.appendChild(document.createTextNode(content)); sp.appendChild(document.createTextNode(content));
} else { } else {
node.appendChild(document.createTextNode(content)); node.appendChild(document.createTextNode(content));
} }
}; };
} }
var lines = splitLines(string), state = (options && options.state) || CodeMirror.startState(mode); var lines = splitLines(string), state = (options && options.state) || CodeMirror.startState(mode);
for (var i = 0, e = lines.length; i < e; ++i) { for (var i = 0, e = lines.length; i < e; ++i) {
if (i) callback("\n"); if (i) callback("\n");
var stream = new CodeMirror.StringStream(lines[i]); var stream = new CodeMirror.StringStream(lines[i]);
if (!stream.string && mode.blankLine) mode.blankLine(state); if (!stream.string && mode.blankLine) mode.blankLine(state);
while (!stream.eol()) { while (!stream.eol()) {
var style = mode.token(stream, state); var style = mode.token(stream, state);
callback(stream.current(), style, i, stream.start, state); callback(stream.current(), style, i, stream.start, state);
stream.start = stream.pos; stream.start = stream.pos;
} }
} }
}; };
})(); })();

View File

@@ -1,72 +1,72 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
CodeMirror.runMode = function(string, modespec, callback, options) { CodeMirror.runMode = function(string, modespec, callback, options) {
var mode = CodeMirror.getMode(CodeMirror.defaults, modespec); var mode = CodeMirror.getMode(CodeMirror.defaults, modespec);
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.appendChild) { 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 = "";
callback = function(text, style) { callback = function(text, style) {
if (text == "\n") { if (text == "\n") {
// Emitting LF or CRLF on IE8 or earlier results in an incorrect display. // Emitting LF or CRLF on IE8 or earlier results in an incorrect display.
// Emitting a carriage return makes everything ok. // Emitting a carriage return makes everything ok.
node.appendChild(document.createTextNode(ie_lt9 ? '\r' : text)); node.appendChild(document.createTextNode(ie_lt9 ? '\r' : text));
col = 0; col = 0;
return; return;
} }
var content = ""; var content = "";
// replace tabs // replace tabs
for (var pos = 0;;) { for (var pos = 0;;) {
var idx = text.indexOf("\t", pos); var idx = text.indexOf("\t", pos);
if (idx == -1) { if (idx == -1) {
content += text.slice(pos); content += text.slice(pos);
col += text.length - pos; col += text.length - pos;
break; break;
} else { } else {
col += idx - pos; col += idx - pos;
content += text.slice(pos, idx); content += text.slice(pos, idx);
var size = tabSize - col % tabSize; var size = tabSize - col % tabSize;
col += size; col += size;
for (var i = 0; i < size; ++i) content += " "; for (var i = 0; i < size; ++i) content += " ";
pos = idx + 1; pos = idx + 1;
} }
} }
if (style) { if (style) {
var sp = node.appendChild(document.createElement("span")); var sp = node.appendChild(document.createElement("span"));
sp.className = "cm-" + style.replace(/ +/g, " cm-"); sp.className = "cm-" + style.replace(/ +/g, " cm-");
sp.appendChild(document.createTextNode(content)); sp.appendChild(document.createTextNode(content));
} else { } else {
node.appendChild(document.createTextNode(content)); node.appendChild(document.createTextNode(content));
} }
}; };
} }
var lines = CodeMirror.splitLines(string), state = (options && options.state) || CodeMirror.startState(mode); var lines = CodeMirror.splitLines(string), state = (options && options.state) || CodeMirror.startState(mode);
for (var i = 0, e = lines.length; i < e; ++i) { for (var i = 0, e = lines.length; i < e; ++i) {
if (i) callback("\n"); if (i) callback("\n");
var stream = new CodeMirror.StringStream(lines[i]); var stream = new CodeMirror.StringStream(lines[i]);
if (!stream.string && mode.blankLine) mode.blankLine(state); if (!stream.string && mode.blankLine) mode.blankLine(state);
while (!stream.eol()) { while (!stream.eol()) {
var style = mode.token(stream, state); var style = mode.token(stream, state);
callback(stream.current(), style, i, stream.start, state); callback(stream.current(), style, i, stream.start, state);
stream.start = stream.pos; stream.start = stream.pos;
} }
} }
}; };
}); });

View File

@@ -1,179 +1,179 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
/* Just enough of CodeMirror to run runMode under node.js */ /* Just enough of CodeMirror to run runMode under node.js */
function splitLines(string){return string.split(/\r\n?|\n/);}; function splitLines(string){return string.split(/\r\n?|\n/);};
// Counts the column offset in a string, taking tabs into account. // Counts the column offset in a string, taking tabs into account.
// Used mostly to find indentation. // Used mostly to find indentation.
var countColumn = function(string, end, tabSize, startIndex, startValue) { var countColumn = function(string, end, tabSize, startIndex, startValue) {
if (end == null) { if (end == null) {
end = string.search(/[^\s\u00a0]/); end = string.search(/[^\s\u00a0]/);
if (end == -1) end = string.length; if (end == -1) end = string.length;
} }
for (var i = startIndex || 0, n = startValue || 0;;) { for (var i = startIndex || 0, n = startValue || 0;;) {
var nextTab = string.indexOf("\t", i); var nextTab = string.indexOf("\t", i);
if (nextTab < 0 || nextTab >= end) if (nextTab < 0 || nextTab >= end)
return n + (end - i); return n + (end - i);
n += nextTab - i; n += nextTab - i;
n += tabSize - (n % tabSize); n += tabSize - (n % tabSize);
i = nextTab + 1; i = nextTab + 1;
} }
}; };
function StringStream(string, tabSize) { 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.tabSize = tabSize || 8;
this.lastColumnPos = this.lastColumnValue = 0; 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 == this.lineStart;}, sol: function() {return this.pos == this.lineStart;},
peek: function() {return this.string.charAt(this.pos) || undefined;}, 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++);
}, },
eat: function(match) { eat: function(match) {
var ch = this.string.charAt(this.pos); var ch = this.string.charAt(this.pos);
if (typeof match == "string") var ok = ch == match; if (typeof match == "string") var ok = ch == match;
else var ok = ch && (match.test ? match.test(ch) : match(ch)); else var ok = ch && (match.test ? match.test(ch) : match(ch));
if (ok) {++this.pos; return ch;} if (ok) {++this.pos; return ch;}
}, },
eatWhile: function(match) { eatWhile: function(match) {
var start = this.pos; var start = this.pos;
while (this.eat(match)){} while (this.eat(match)){}
return this.pos > start; return this.pos > start;
}, },
eatSpace: function() { eatSpace: function() {
var start = this.pos; var start = this.pos;
while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos; while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;
return this.pos > start; return this.pos > start;
}, },
skipToEnd: function() {this.pos = this.string.length;}, skipToEnd: function() {this.pos = this.string.length;},
skipTo: function(ch) { skipTo: function(ch) {
var found = this.string.indexOf(ch, this.pos); var found = this.string.indexOf(ch, this.pos);
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() { column: function() {
if (this.lastColumnPos < this.start) { if (this.lastColumnPos < this.start) {
this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue); this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
this.lastColumnPos = this.start; this.lastColumnPos = this.start;
} }
return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0); return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
}, },
indentation: function() { indentation: function() {
return countColumn(this.string, null, this.tabSize) - return countColumn(this.string, null, this.tabSize) -
(this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0); (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;};
var substr = this.string.substr(this.pos, pattern.length); var substr = this.string.substr(this.pos, pattern.length);
if (cased(substr) == cased(pattern)) { if (cased(substr) == cased(pattern)) {
if (consume !== false) this.pos += pattern.length; if (consume !== false) this.pos += pattern.length;
return true; return true;
} }
} else { } else {
var match = this.string.slice(this.pos).match(pattern); var match = this.string.slice(this.pos).match(pattern);
if (match && match.index > 0) return null; if (match && match.index > 0) return null;
if (match && consume !== false) this.pos += match[0].length; if (match && consume !== false) this.pos += match[0].length;
return match; return match;
} }
}, },
current: function(){return this.string.slice(this.start, this.pos);}, current: function(){return this.string.slice(this.start, this.pos);},
hideFirstChars: function(n, inner) { hideFirstChars: function(n, inner) {
this.lineStart += n; this.lineStart += n;
try { return inner(); } try { return inner(); }
finally { this.lineStart -= n; } finally { this.lineStart -= n; }
} }
}; };
exports.StringStream = StringStream; exports.StringStream = StringStream;
exports.startState = function(mode, a1, a2) { exports.startState = function(mode, a1, a2) {
return mode.startState ? mode.startState(a1, a2) : true; return mode.startState ? mode.startState(a1, a2) : true;
}; };
var modes = exports.modes = {}, mimeModes = exports.mimeModes = {}; var modes = exports.modes = {}, mimeModes = exports.mimeModes = {};
exports.defineMode = function(name, mode) { exports.defineMode = function(name, mode) {
if (arguments.length > 2) if (arguments.length > 2)
mode.dependencies = Array.prototype.slice.call(arguments, 2); mode.dependencies = Array.prototype.slice.call(arguments, 2);
modes[name] = mode; modes[name] = mode;
}; };
exports.defineMIME = function(mime, spec) { mimeModes[mime] = spec; }; exports.defineMIME = function(mime, spec) { mimeModes[mime] = spec; };
exports.defineMode("null", function() { exports.defineMode("null", function() {
return {token: function(stream) {stream.skipToEnd();}}; return {token: function(stream) {stream.skipToEnd();}};
}); });
exports.defineMIME("text/plain", "null"); exports.defineMIME("text/plain", "null");
exports.resolveMode = function(spec) { exports.resolveMode = function(spec) {
if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
spec = mimeModes[spec]; spec = mimeModes[spec];
} else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
spec = mimeModes[spec.name]; spec = mimeModes[spec.name];
} }
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) { function copyObj(obj, target, overwrite) {
if (!target) target = {}; if (!target) target = {};
for (var prop in obj) for (var prop in obj)
if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop))) if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
target[prop] = obj[prop]; target[prop] = obj[prop];
return target; return target;
} }
// This can be used to attach properties to mode objects from // This can be used to attach properties to mode objects from
// outside the actual mode definition. // outside the actual mode definition.
var modeExtensions = exports.modeExtensions = {}; var modeExtensions = exports.modeExtensions = {};
exports.extendMode = function(mode, properties) { exports.extendMode = function(mode, properties) {
var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {}); var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
copyObj(properties, exts); copyObj(properties, exts);
}; };
exports.getMode = function(options, spec) { exports.getMode = function(options, spec) {
var spec = exports.resolveMode(spec); var spec = exports.resolveMode(spec);
var mfactory = modes[spec.name]; var mfactory = modes[spec.name];
if (!mfactory) return exports.getMode(options, "text/plain"); if (!mfactory) return exports.getMode(options, "text/plain");
var modeObj = mfactory(options, spec); var modeObj = mfactory(options, spec);
if (modeExtensions.hasOwnProperty(spec.name)) { if (modeExtensions.hasOwnProperty(spec.name)) {
var exts = modeExtensions[spec.name]; var exts = modeExtensions[spec.name];
for (var prop in exts) { for (var prop in exts) {
if (!exts.hasOwnProperty(prop)) continue; if (!exts.hasOwnProperty(prop)) continue;
if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop]; if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop];
modeObj[prop] = exts[prop]; modeObj[prop] = exts[prop];
} }
} }
modeObj.name = spec.name; modeObj.name = spec.name;
if (spec.helperType) modeObj.helperType = spec.helperType; if (spec.helperType) modeObj.helperType = spec.helperType;
if (spec.modeProps) for (var prop in spec.modeProps) if (spec.modeProps) for (var prop in spec.modeProps)
modeObj[prop] = spec.modeProps[prop]; modeObj[prop] = spec.modeProps[prop];
return modeObj; return modeObj;
}; };
exports.registerHelper = exports.registerGlobalHelper = Math.min; exports.registerHelper = exports.registerGlobalHelper = Math.min;
exports.runMode = function(string, modespec, callback, options) { exports.runMode = function(string, modespec, callback, options) {
var mode = exports.getMode({indentUnit: 2}, modespec); var mode = exports.getMode({indentUnit: 2}, modespec);
var lines = splitLines(string), state = (options && options.state) || exports.startState(mode); var lines = splitLines(string), state = (options && options.state) || exports.startState(mode);
for (var i = 0, e = lines.length; i < e; ++i) { for (var i = 0, e = lines.length; i < e; ++i) {
if (i) callback("\n"); if (i) callback("\n");
var stream = new exports.StringStream(lines[i]); var stream = new exports.StringStream(lines[i]);
if (!stream.string && mode.blankLine) mode.blankLine(state); if (!stream.string && mode.blankLine) mode.blankLine(state);
while (!stream.eol()) { while (!stream.eol()) {
var style = mode.token(stream, state); var style = mode.token(stream, state);
callback(stream.current(), style, i, stream.start, state); callback(stream.current(), style, i, stream.start, state);
stream.start = stream.pos; stream.start = stream.pos;
} }
} }
}; };
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")]; require.cache[require.resolve("../../addon/runmode/runmode")] = require.cache[require.resolve("./runmode.node")];

View File

@@ -1,118 +1,118 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
CodeMirror.defineExtension("annotateScrollbar", function(options) { CodeMirror.defineExtension("annotateScrollbar", function(options) {
if (typeof options == "string") options = {className: options}; if (typeof options == "string") options = {className: options};
return new Annotation(this, options); return new Annotation(this, options);
}); });
CodeMirror.defineOption("scrollButtonHeight", 0); CodeMirror.defineOption("scrollButtonHeight", 0);
function Annotation(cm, options) { function Annotation(cm, options) {
this.cm = cm; this.cm = cm;
this.options = options; this.options = options;
this.buttonHeight = options.scrollButtonHeight || cm.getOption("scrollButtonHeight"); this.buttonHeight = options.scrollButtonHeight || cm.getOption("scrollButtonHeight");
this.annotations = []; this.annotations = [];
this.doRedraw = this.doUpdate = null; 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) { function scheduleRedraw(delay) {
clearTimeout(self.doRedraw); clearTimeout(self.doRedraw);
self.doRedraw = setTimeout(function() { self.redraw(); }, delay); 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() {
clearTimeout(self.doUpdate); clearTimeout(self.doUpdate);
self.doUpdate = setTimeout(function() { self.doUpdate = setTimeout(function() {
if (self.computeScale()) scheduleRedraw(20); if (self.computeScale()) scheduleRedraw(20);
}, 100); }, 100);
}); });
cm.on("markerAdded", this.resizeHandler); cm.on("markerAdded", this.resizeHandler);
cm.on("markerCleared", this.resizeHandler); cm.on("markerCleared", this.resizeHandler);
if (options.listenForChanges !== false) if (options.listenForChanges !== false)
cm.on("change", this.changeHandler = function() { cm.on("change", this.changeHandler = function() {
scheduleRedraw(250); 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 - this.buttonHeight * 2) / var hScale = (cm.getWrapperElement().clientHeight - cm.display.barHeight - this.buttonHeight * 2) /
cm.getScrollerElement().scrollHeight cm.getScrollerElement().scrollHeight
if (hScale != this.hScale) { if (hScale != this.hScale) {
this.hScale = hScale; this.hScale = hScale;
return true; return true;
} }
}; };
Annotation.prototype.update = function(annotations) { Annotation.prototype.update = function(annotations) {
this.annotations = annotations; this.annotations = annotations;
this.redraw(); this.redraw();
}; };
Annotation.prototype.redraw = function(compute) { Annotation.prototype.redraw = function(compute) {
if (compute !== false) this.computeScale(); if (compute !== false) this.computeScale();
var cm = this.cm, hScale = this.hScale; var cm = this.cm, hScale = this.hScale;
var frag = document.createDocumentFragment(), anns = this.annotations; var frag = document.createDocumentFragment(), anns = this.annotations;
var wrapping = cm.getOption("lineWrapping"); var wrapping = cm.getOption("lineWrapping");
var singleLineH = wrapping && cm.defaultTextHeight() * 1.5; var singleLineH = wrapping && cm.defaultTextHeight() * 1.5;
var curLine = null, curLineObj = null; var curLine = null, curLineObj = null;
function getY(pos, top) { function getY(pos, top) {
if (curLine != pos.line) { if (curLine != pos.line) {
curLine = pos.line; curLine = pos.line;
curLineObj = cm.getLineHandle(curLine); curLineObj = cm.getLineHandle(curLine);
} }
if (wrapping && curLineObj.height > singleLineH) if (wrapping && curLineObj.height > singleLineH)
return cm.charCoords(pos, "local")[top ? "top" : "bottom"]; return cm.charCoords(pos, "local")[top ? "top" : "bottom"];
var topY = cm.heightAtLine(curLineObj, "local"); var topY = cm.heightAtLine(curLineObj, "local");
return topY + (top ? 0 : curLineObj.height); return topY + (top ? 0 : curLineObj.height);
} }
if (cm.display.barWidth) for (var i = 0, nextTop; i < anns.length; i++) { if (cm.display.barWidth) for (var i = 0, nextTop; i < anns.length; i++) {
var ann = anns[i]; var ann = anns[i];
var top = nextTop || getY(ann.from, true) * hScale; var top = nextTop || getY(ann.from, true) * hScale;
var bottom = getY(ann.to, false) * hScale; var bottom = getY(ann.to, false) * hScale;
while (i < anns.length - 1) { while (i < anns.length - 1) {
nextTop = getY(anns[i + 1].from, true) * 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 = getY(ann.to, false) * hScale; bottom = getY(ann.to, false) * hScale;
} }
if (bottom == top) continue; 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: " elt.style.cssText = "position: absolute; right: 0px; width: " + Math.max(cm.display.barWidth - 1, 2) + "px; top: "
+ (top + this.buttonHeight) + "px; height: " + height + "px"; + (top + this.buttonHeight) + "px; height: " + height + "px";
elt.className = this.options.className; elt.className = this.options.className;
if (ann.id) { if (ann.id) {
elt.setAttribute("annotation-id", ann.id); elt.setAttribute("annotation-id", ann.id);
} }
} }
this.div.textContent = ""; this.div.textContent = "";
this.div.appendChild(frag); this.div.appendChild(frag);
}; };
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("markerAdded", this.resizeHandler);
this.cm.off("markerCleared", this.resizeHandler); this.cm.off("markerCleared", this.resizeHandler);
if (this.changeHandler) this.cm.off("change", this.changeHandler); if (this.changeHandler) this.cm.off("change", this.changeHandler);
this.div.parentNode.removeChild(this.div); this.div.parentNode.removeChild(this.div);
}; };
}); });

View File

@@ -1,46 +1,46 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
CodeMirror.defineOption("scrollPastEnd", false, function(cm, val, old) { CodeMirror.defineOption("scrollPastEnd", false, function(cm, val, old) {
if (old && old != CodeMirror.Init) { if (old && old != CodeMirror.Init) {
cm.off("change", onChange); cm.off("change", onChange);
cm.off("refresh", updateBottomMargin); cm.off("refresh", updateBottomMargin);
cm.display.lineSpace.parentNode.style.paddingBottom = ""; cm.display.lineSpace.parentNode.style.paddingBottom = "";
cm.state.scrollPastEndPadding = null; cm.state.scrollPastEndPadding = null;
} }
if (val) { if (val) {
cm.on("change", onChange); cm.on("change", onChange);
cm.on("refresh", updateBottomMargin); cm.on("refresh", updateBottomMargin);
updateBottomMargin(cm); updateBottomMargin(cm);
} }
}); });
function onChange(cm, change) { function onChange(cm, change) {
if (CodeMirror.changeEnd(change).line == cm.lastLine()) if (CodeMirror.changeEnd(change).line == cm.lastLine())
updateBottomMargin(cm); updateBottomMargin(cm);
} }
function updateBottomMargin(cm) { function updateBottomMargin(cm) {
var padding = ""; var padding = "";
if (cm.lineCount() > 1) { if (cm.lineCount() > 1) {
var totalH = cm.display.scroller.clientHeight - 30, var totalH = cm.display.scroller.clientHeight - 30,
lastLineH = cm.getLineHandle(cm.lastLine()).height; lastLineH = cm.getLineHandle(cm.lastLine()).height;
padding = (totalH - lastLineH) + "px"; padding = (totalH - lastLineH) + "px";
} }
if (cm.state.scrollPastEndPadding != padding) { if (cm.state.scrollPastEndPadding != padding) {
cm.state.scrollPastEndPadding = padding; cm.state.scrollPastEndPadding = padding;
cm.display.lineSpace.parentNode.style.paddingBottom = padding; cm.display.lineSpace.parentNode.style.paddingBottom = padding;
cm.setSize(); cm.setSize();
} }
} }
}); });

View File

@@ -1,66 +1,66 @@
.CodeMirror-simplescroll-horizontal div, .CodeMirror-simplescroll-vertical div { .CodeMirror-simplescroll-horizontal div, .CodeMirror-simplescroll-vertical div {
position: absolute; position: absolute;
background: #ccc; background: #ccc;
-moz-box-sizing: border-box; -moz-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
border: 1px solid #bbb; border: 1px solid #bbb;
border-radius: 2px; border-radius: 2px;
} }
.CodeMirror-simplescroll-horizontal, .CodeMirror-simplescroll-vertical { .CodeMirror-simplescroll-horizontal, .CodeMirror-simplescroll-vertical {
position: absolute; position: absolute;
z-index: 6; z-index: 6;
background: #eee; background: #eee;
} }
.CodeMirror-simplescroll-horizontal { .CodeMirror-simplescroll-horizontal {
bottom: 0; left: 0; bottom: 0; left: 0;
height: 8px; height: 8px;
} }
.CodeMirror-simplescroll-horizontal div { .CodeMirror-simplescroll-horizontal div {
bottom: 0; bottom: 0;
height: 100%; height: 100%;
} }
.CodeMirror-simplescroll-vertical { .CodeMirror-simplescroll-vertical {
right: 0; top: 0; right: 0; top: 0;
width: 8px; width: 8px;
} }
.CodeMirror-simplescroll-vertical div { .CodeMirror-simplescroll-vertical div {
right: 0; right: 0;
width: 100%; width: 100%;
} }
.CodeMirror-overlayscroll .CodeMirror-scrollbar-filler, .CodeMirror-overlayscroll .CodeMirror-gutter-filler { .CodeMirror-overlayscroll .CodeMirror-scrollbar-filler, .CodeMirror-overlayscroll .CodeMirror-gutter-filler {
display: none; display: none;
} }
.CodeMirror-overlayscroll-horizontal div, .CodeMirror-overlayscroll-vertical div { .CodeMirror-overlayscroll-horizontal div, .CodeMirror-overlayscroll-vertical div {
position: absolute; position: absolute;
background: #bcd; background: #bcd;
border-radius: 3px; border-radius: 3px;
} }
.CodeMirror-overlayscroll-horizontal, .CodeMirror-overlayscroll-vertical { .CodeMirror-overlayscroll-horizontal, .CodeMirror-overlayscroll-vertical {
position: absolute; position: absolute;
z-index: 6; z-index: 6;
} }
.CodeMirror-overlayscroll-horizontal { .CodeMirror-overlayscroll-horizontal {
bottom: 0; left: 0; bottom: 0; left: 0;
height: 6px; height: 6px;
} }
.CodeMirror-overlayscroll-horizontal div { .CodeMirror-overlayscroll-horizontal div {
bottom: 0; bottom: 0;
height: 100%; height: 100%;
} }
.CodeMirror-overlayscroll-vertical { .CodeMirror-overlayscroll-vertical {
right: 0; top: 0; right: 0; top: 0;
width: 6px; width: 6px;
} }
.CodeMirror-overlayscroll-vertical div { .CodeMirror-overlayscroll-vertical div {
right: 0; right: 0;
width: 100%; width: 100%;
} }

View File

@@ -1,149 +1,149 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
function Bar(cls, orientation, scroll) { function Bar(cls, orientation, scroll) {
this.orientation = orientation; this.orientation = orientation;
this.scroll = scroll; this.scroll = scroll;
this.screen = this.total = this.size = 1; this.screen = this.total = this.size = 1;
this.pos = 0; this.pos = 0;
this.node = document.createElement("div"); this.node = document.createElement("div");
this.node.className = cls + "-" + orientation; this.node.className = cls + "-" + orientation;
this.inner = this.node.appendChild(document.createElement("div")); this.inner = this.node.appendChild(document.createElement("div"));
var self = this; var self = this;
CodeMirror.on(this.inner, "mousedown", function(e) { CodeMirror.on(this.inner, "mousedown", function(e) {
if (e.which != 1) return; if (e.which != 1) return;
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 done() { function done() {
CodeMirror.off(document, "mousemove", move); CodeMirror.off(document, "mousemove", move);
CodeMirror.off(document, "mouseup", done); CodeMirror.off(document, "mouseup", done);
} }
function move(e) { function move(e) {
if (e.which != 1) return done(); 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(document, "mouseup", done);
}); });
CodeMirror.on(this.node, "click", function(e) { CodeMirror.on(this.node, "click", function(e) {
CodeMirror.e_preventDefault(e); CodeMirror.e_preventDefault(e);
var innerBox = self.inner.getBoundingClientRect(), where; var innerBox = self.inner.getBoundingClientRect(), where;
if (self.orientation == "horizontal") if (self.orientation == "horizontal")
where = e.clientX < innerBox.left ? -1 : e.clientX > innerBox.right ? 1 : 0; where = e.clientX < innerBox.left ? -1 : e.clientX > innerBox.right ? 1 : 0;
else else
where = e.clientY < innerBox.top ? -1 : e.clientY > innerBox.bottom ? 1 : 0; where = e.clientY < innerBox.top ? -1 : e.clientY > innerBox.bottom ? 1 : 0;
self.moveTo(self.pos + where * self.screen); self.moveTo(self.pos + where * self.screen);
}); });
function onWheel(e) { function onWheel(e) {
var moved = CodeMirror.wheelEventPixels(e)[self.orientation == "horizontal" ? "x" : "y"]; var moved = CodeMirror.wheelEventPixels(e)[self.orientation == "horizontal" ? "x" : "y"];
var oldPos = self.pos; var oldPos = self.pos;
self.moveTo(self.pos + moved); self.moveTo(self.pos + moved);
if (self.pos != oldPos) CodeMirror.e_preventDefault(e); if (self.pos != oldPos) CodeMirror.e_preventDefault(e);
} }
CodeMirror.on(this.node, "mousewheel", onWheel); CodeMirror.on(this.node, "mousewheel", onWheel);
CodeMirror.on(this.node, "DOMMouseScroll", onWheel); CodeMirror.on(this.node, "DOMMouseScroll", onWheel);
} }
Bar.prototype.setPos = function(pos) { 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 false; 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";
return true return true
}; };
Bar.prototype.moveTo = function(pos) { Bar.prototype.moveTo = function(pos) {
if (this.setPos(pos)) this.scroll(pos, this.orientation); if (this.setPos(pos)) this.scroll(pos, this.orientation);
} }
var minButtonSize = 10; 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;
var buttonSize = this.screen * (this.size / this.total); var buttonSize = this.screen * (this.size / this.total);
if (buttonSize < minButtonSize) { if (buttonSize < minButtonSize) {
this.size -= minButtonSize - buttonSize; this.size -= minButtonSize - buttonSize;
buttonSize = minButtonSize; buttonSize = minButtonSize;
} }
this.inner.style[this.orientation == "horizontal" ? "width" : "height"] = this.inner.style[this.orientation == "horizontal" ? "width" : "height"] =
buttonSize + "px"; buttonSize + "px";
this.setPos(this.pos); this.setPos(this.pos);
}; };
function SimpleScrollbars(cls, place, scroll) { function SimpleScrollbars(cls, place, scroll) {
this.addClass = cls; this.addClass = cls;
this.horiz = new Bar(cls, "horizontal", scroll); this.horiz = new Bar(cls, "horizontal", scroll);
place(this.horiz.node); place(this.horiz.node);
this.vert = new Bar(cls, "vertical", scroll); this.vert = new Bar(cls, "vertical", scroll);
place(this.vert.node); place(this.vert.node);
this.width = null; this.width = null;
} }
SimpleScrollbars.prototype.update = function(measure) { SimpleScrollbars.prototype.update = function(measure) {
if (this.width == null) { if (this.width == null) {
var style = window.getComputedStyle ? window.getComputedStyle(this.horiz.node) : this.horiz.node.currentStyle; var style = window.getComputedStyle ? window.getComputedStyle(this.horiz.node) : this.horiz.node.currentStyle;
if (style) this.width = parseInt(style.height); if (style) this.width = parseInt(style.height);
} }
var width = this.width || 0; var width = this.width || 0;
var needsH = measure.scrollWidth > measure.clientWidth + 1; var needsH = measure.scrollWidth > measure.clientWidth + 1;
var needsV = measure.scrollHeight > measure.clientHeight + 1; var needsV = measure.scrollHeight > measure.clientHeight + 1;
this.vert.node.style.display = needsV ? "block" : "none"; this.vert.node.style.display = needsV ? "block" : "none";
this.horiz.node.style.display = needsH ? "block" : "none"; this.horiz.node.style.display = needsH ? "block" : "none";
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.bottom = needsH ? width + "px" : "0"; this.vert.node.style.bottom = needsH ? width + "px" : "0";
} }
if (needsH) { if (needsH) {
this.horiz.update(measure.scrollWidth, measure.clientWidth, this.horiz.update(measure.scrollWidth, measure.clientWidth,
measure.viewWidth - (needsV ? width : 0) - measure.barLeft); measure.viewWidth - (needsV ? width : 0) - measure.barLeft);
this.horiz.node.style.right = needsV ? width + "px" : "0"; this.horiz.node.style.right = needsV ? width + "px" : "0";
this.horiz.node.style.left = measure.barLeft + "px"; this.horiz.node.style.left = measure.barLeft + "px";
} }
return {right: needsV ? width : 0, bottom: needsH ? width : 0}; return {right: needsV ? width : 0, bottom: needsH ? width : 0};
}; };
SimpleScrollbars.prototype.setScrollTop = function(pos) { SimpleScrollbars.prototype.setScrollTop = function(pos) {
this.vert.setPos(pos); this.vert.setPos(pos);
}; };
SimpleScrollbars.prototype.setScrollLeft = function(pos) { SimpleScrollbars.prototype.setScrollLeft = function(pos) {
this.horiz.setPos(pos); this.horiz.setPos(pos);
}; };
SimpleScrollbars.prototype.clear = function() { SimpleScrollbars.prototype.clear = function() {
var parent = this.horiz.node.parentNode; var parent = this.horiz.node.parentNode;
parent.removeChild(this.horiz.node); parent.removeChild(this.horiz.node);
parent.removeChild(this.vert.node); parent.removeChild(this.vert.node);
}; };
CodeMirror.scrollbarModel.simple = function(place, scroll) { CodeMirror.scrollbarModel.simple = function(place, scroll) {
return new SimpleScrollbars("CodeMirror-simplescroll", place, scroll); return new SimpleScrollbars("CodeMirror-simplescroll", place, scroll);
}; };
CodeMirror.scrollbarModel.overlay = function(place, scroll) { CodeMirror.scrollbarModel.overlay = function(place, scroll) {
return new SimpleScrollbars("CodeMirror-overlayscroll", place, scroll); return new SimpleScrollbars("CodeMirror-overlayscroll", place, scroll);
}; };
}); });

View File

@@ -1,49 +1,49 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
// Defines jumpToLine command. Uses dialog.js if present. // Defines jumpToLine command. Uses dialog.js if present.
(function(mod) { (function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("../dialog/dialog")); mod(require("../../lib/codemirror"), require("../dialog/dialog"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "../dialog/dialog"], mod); define(["../../lib/codemirror", "../dialog/dialog"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
function dialog(cm, text, shortText, deflt, f) { function dialog(cm, text, shortText, deflt, f) {
if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true}); if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true});
else f(prompt(shortText, deflt)); else f(prompt(shortText, deflt));
} }
var jumpDialog = 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>'; '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) { function interpretLine(cm, string) {
var num = Number(string) var num = Number(string)
if (/^[-+]/.test(string)) return cm.getCursor().line + num if (/^[-+]/.test(string)) return cm.getCursor().line + num
else return num - 1 else return num - 1
} }
CodeMirror.commands.jumpToLine = function(cm) { CodeMirror.commands.jumpToLine = function(cm) {
var cur = cm.getCursor(); var cur = cm.getCursor();
dialog(cm, jumpDialog, "Jump to line:", (cur.line + 1) + ":" + cur.ch, function(posStr) { dialog(cm, jumpDialog, "Jump to line:", (cur.line + 1) + ":" + cur.ch, function(posStr) {
if (!posStr) return; if (!posStr) return;
var match; var match;
if (match = /^\s*([\+\-]?\d+)\s*\:\s*(\d+)\s*$/.exec(posStr)) { if (match = /^\s*([\+\-]?\d+)\s*\:\s*(\d+)\s*$/.exec(posStr)) {
cm.setCursor(interpretLine(cm, match[1]), Number(match[2])) cm.setCursor(interpretLine(cm, match[1]), Number(match[2]))
} else if (match = /^\s*([\+\-]?\d+(\.\d+)?)\%\s*/.exec(posStr)) { } else if (match = /^\s*([\+\-]?\d+(\.\d+)?)\%\s*/.exec(posStr)) {
var line = Math.round(cm.lineCount() * Number(match[1]) / 100); var line = Math.round(cm.lineCount() * Number(match[1]) / 100);
if (/^[-+]/.test(match[1])) line = cur.line + line + 1; if (/^[-+]/.test(match[1])) line = cur.line + line + 1;
cm.setCursor(line - 1, cur.ch); cm.setCursor(line - 1, cur.ch);
} else if (match = /^\s*\:?\s*([\+\-]?\d+)\s*/.exec(posStr)) { } else if (match = /^\s*\:?\s*([\+\-]?\d+)\s*/.exec(posStr)) {
cm.setCursor(interpretLine(cm, match[1]), cur.ch); cm.setCursor(interpretLine(cm, match[1]), cur.ch);
} }
}); });
}; };
CodeMirror.keyMap["default"]["Alt-G"] = "jumpToLine"; CodeMirror.keyMap["default"]["Alt-G"] = "jumpToLine";
}); });

View File

@@ -1,146 +1,146 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
// Highlighting text that matches the selection // Highlighting text that matches the selection
// //
// Defines an option highlightSelectionMatches, which, when enabled, // Defines an option highlightSelectionMatches, which, when enabled,
// will style strings that match the selection throughout the // will style strings that match the selection throughout the
// document. // document.
// //
// The option can be set to true to simply enable it, or to a // The option can be set to true to simply enable it, or to a
// {minChars, style, wordsOnly, showToken, delay} object to explicitly // {minChars, style, wordsOnly, showToken, delay} object to explicitly
// configure it. minChars is the minimum amount of characters that should be // configure it. minChars is the minimum amount of characters that should be
// selected for the behavior to occur, and style is the token style to // selected for the behavior to occur, and style is the token style to
// apply to the matches. This will be prefixed by "cm-" to create an // apply to the matches. This will be prefixed by "cm-" to create an
// actual CSS class name. If wordsOnly is enabled, the matches will be // actual CSS class name. If wordsOnly is enabled, the matches will be
// 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. If annotateScrollbar is enabled, the occurences // highlighting the matches. If annotateScrollbar is enabled, the occurences
// will be highlighted on the scrollbar via the matchesonscrollbar addon. // 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"), require("./matchesonscrollbar")); 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", "./matchesonscrollbar"], mod); define(["../../lib/codemirror", "./matchesonscrollbar"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
var defaults = { var defaults = {
style: "matchhighlight", style: "matchhighlight",
minChars: 2, minChars: 2,
delay: 100, delay: 100,
wordsOnly: false, wordsOnly: false,
annotateScrollbar: false, annotateScrollbar: false,
showToken: false, showToken: false,
trim: true trim: true
} }
function State(options) { function State(options) {
this.options = {} this.options = {}
for (var name in defaults) for (var name in defaults)
this.options[name] = (options && options.hasOwnProperty(name) ? options : defaults)[name] this.options[name] = (options && options.hasOwnProperty(name) ? options : defaults)[name]
this.overlay = this.timeout = null; this.overlay = this.timeout = null;
this.matchesonscroll = 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) {
removeOverlay(cm); removeOverlay(cm);
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);
} }
if (val) { if (val) {
cm.state.matchHighlighter = new State(val); cm.state.matchHighlighter = new State(val);
highlightMatches(cm); highlightMatches(cm);
cm.on("cursorActivity", cursorActivity); cm.on("cursorActivity", cursorActivity);
} }
}); });
function cursorActivity(cm) { function cursorActivity(cm) {
var state = cm.state.matchHighlighter; var state = cm.state.matchHighlighter;
clearTimeout(state.timeout); clearTimeout(state.timeout);
state.timeout = setTimeout(function() {highlightMatches(cm);}, state.options.delay); state.timeout = setTimeout(function() {highlightMatches(cm);}, state.options.delay);
} }
function addOverlay(cm, query, hasBoundary, style) { function addOverlay(cm, query, hasBoundary, style) {
var state = cm.state.matchHighlighter; var state = cm.state.matchHighlighter;
cm.addOverlay(state.overlay = makeOverlay(query, hasBoundary, style)); cm.addOverlay(state.overlay = makeOverlay(query, hasBoundary, style));
if (state.options.annotateScrollbar && cm.showMatchesOnScrollbar) { if (state.options.annotateScrollbar && cm.showMatchesOnScrollbar) {
var searchFor = hasBoundary ? new RegExp("\\b" + query + "\\b") : query; var searchFor = hasBoundary ? new RegExp("\\b" + query + "\\b") : query;
state.matchesonscroll = cm.showMatchesOnScrollbar(searchFor, true, state.matchesonscroll = cm.showMatchesOnScrollbar(searchFor, true,
{className: "CodeMirror-selection-highlight-scrollbar"}); {className: "CodeMirror-selection-highlight-scrollbar"});
} }
} }
function removeOverlay(cm) { 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.matchesonscroll) { if (state.matchesonscroll) {
state.matchesonscroll.clear(); state.matchesonscroll.clear();
state.matchesonscroll = null; state.matchesonscroll = null;
} }
} }
} }
function highlightMatches(cm) { function highlightMatches(cm) {
cm.operation(function() { cm.operation(function() {
var state = cm.state.matchHighlighter; var state = cm.state.matchHighlighter;
removeOverlay(cm); removeOverlay(cm);
if (!cm.somethingSelected() && state.options.showToken) { if (!cm.somethingSelected() && state.options.showToken) {
var re = state.options.showToken === true ? /[\w$]/ : state.options.showToken; var re = state.options.showToken === true ? /[\w$]/ : state.options.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)
addOverlay(cm, line.slice(start, end), re, state.options.style); addOverlay(cm, line.slice(start, end), re, state.options.style);
return; return;
} }
var from = cm.getCursor("from"), to = cm.getCursor("to"); var from = cm.getCursor("from"), to = cm.getCursor("to");
if (from.line != to.line) return; if (from.line != to.line) return;
if (state.options.wordsOnly && !isWord(cm, from, to)) return; if (state.options.wordsOnly && !isWord(cm, from, to)) return;
var selection = cm.getRange(from, to) var selection = cm.getRange(from, to)
if (state.options.trim) selection = selection.replace(/^\s+|\s+$/g, "") if (state.options.trim) selection = selection.replace(/^\s+|\s+$/g, "")
if (selection.length >= state.options.minChars) if (selection.length >= state.options.minChars)
addOverlay(cm, selection, false, state.options.style); addOverlay(cm, selection, false, state.options.style);
}); });
} }
function isWord(cm, from, to) { function isWord(cm, from, to) {
var str = cm.getRange(from, to); var str = cm.getRange(from, to);
if (str.match(/^\w+$/) !== null) { if (str.match(/^\w+$/) !== null) {
if (from.ch > 0) { if (from.ch > 0) {
var pos = {line: from.line, ch: from.ch - 1}; var pos = {line: from.line, ch: from.ch - 1};
var chr = cm.getRange(pos, from); var chr = cm.getRange(pos, from);
if (chr.match(/\W/) === null) return false; if (chr.match(/\W/) === null) return false;
} }
if (to.ch < cm.getLine(from.line).length) { if (to.ch < cm.getLine(from.line).length) {
var pos = {line: to.line, ch: to.ch + 1}; var pos = {line: to.line, ch: to.ch + 1};
var chr = cm.getRange(to, pos); var chr = cm.getRange(to, pos);
if (chr.match(/\W/) === null) return false; if (chr.match(/\W/) === null) return false;
} }
return true; return true;
} else return false; } else return false;
} }
function boundariesAround(stream, re) { function boundariesAround(stream, re) {
return (!stream.start || !re.test(stream.string.charAt(stream.start - 1))) && return (!stream.start || !re.test(stream.string.charAt(stream.start - 1))) &&
(stream.pos == stream.string.length || !re.test(stream.string.charAt(stream.pos))); (stream.pos == stream.string.length || !re.test(stream.string.charAt(stream.pos)));
} }
function makeOverlay(query, hasBoundary, style) { function makeOverlay(query, hasBoundary, style) {
return {token: function(stream) { return {token: function(stream) {
if (stream.match(query) && if (stream.match(query) &&
(!hasBoundary || boundariesAround(stream, hasBoundary))) (!hasBoundary || boundariesAround(stream, hasBoundary)))
return style; return style;
stream.next(); stream.next();
stream.skipTo(query.charAt(0)) || stream.skipToEnd(); stream.skipTo(query.charAt(0)) || stream.skipToEnd();
}}; }};
} }
}); });

View File

@@ -1,8 +1,8 @@
.CodeMirror-search-match { .CodeMirror-search-match {
background: gold; background: gold;
border-top: 1px solid orange; border-top: 1px solid orange;
border-bottom: 1px solid orange; border-bottom: 1px solid orange;
-moz-box-sizing: border-box; -moz-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
opacity: .5; opacity: .5;
} }

View File

@@ -1,97 +1,97 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) { (function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("./searchcursor"), require("../scroll/annotatescrollbar")); mod(require("../../lib/codemirror"), require("./searchcursor"), require("../scroll/annotatescrollbar"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "./searchcursor", "../scroll/annotatescrollbar"], mod); define(["../../lib/codemirror", "./searchcursor", "../scroll/annotatescrollbar"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
CodeMirror.defineExtension("showMatchesOnScrollbar", function(query, caseFold, options) { CodeMirror.defineExtension("showMatchesOnScrollbar", function(query, caseFold, options) {
if (typeof options == "string") options = {className: options}; if (typeof options == "string") options = {className: options};
if (!options) options = {}; if (!options) options = {};
return new SearchAnnotation(this, query, caseFold, options); return new SearchAnnotation(this, query, caseFold, options);
}); });
function SearchAnnotation(cm, query, caseFold, options) { function SearchAnnotation(cm, query, caseFold, options) {
this.cm = cm; this.cm = cm;
this.options = options; this.options = options;
var annotateOptions = {listenForChanges: false}; var annotateOptions = {listenForChanges: false};
for (var prop in options) annotateOptions[prop] = options[prop]; for (var prop in options) annotateOptions[prop] = options[prop];
if (!annotateOptions.className) annotateOptions.className = "CodeMirror-search-match"; if (!annotateOptions.className) annotateOptions.className = "CodeMirror-search-match";
this.annotation = cm.annotateScrollbar(annotateOptions); 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};
this.matches = []; this.matches = [];
this.update = null; this.update = null;
this.findMatches(); this.findMatches();
this.annotation.update(this.matches); this.annotation.update(this.matches);
var self = this; var self = this;
cm.on("change", this.changeHandler = function(_cm, change) { self.onChange(change); }); cm.on("change", this.changeHandler = function(_cm, change) { self.onChange(change); });
} }
var MAX_MATCHES = 1000; var MAX_MATCHES = 1000;
SearchAnnotation.prototype.findMatches = function() { SearchAnnotation.prototype.findMatches = function() {
if (!this.gap) return; if (!this.gap) return;
for (var i = 0; i < this.matches.length; i++) { for (var i = 0; i < this.matches.length; i++) {
var match = this.matches[i]; var match = this.matches[i];
if (match.from.line >= this.gap.to) break; if (match.from.line >= this.gap.to) break;
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; 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 > maxMatches) break; if (this.matches.length > maxMatches) break;
} }
this.gap = null; this.gap = null;
}; };
function offsetLine(line, changeStart, sizeChange) { function offsetLine(line, changeStart, sizeChange) {
if (line <= changeStart) return line; if (line <= changeStart) return line;
return Math.max(changeStart, line + sizeChange); return Math.max(changeStart, line + sizeChange);
} }
SearchAnnotation.prototype.onChange = function(change) { SearchAnnotation.prototype.onChange = function(change) {
var startLine = change.from.line; var startLine = change.from.line;
var endLine = CodeMirror.changeEnd(change).line; var endLine = CodeMirror.changeEnd(change).line;
var sizeChange = endLine - change.to.line; var sizeChange = endLine - change.to.line;
if (this.gap) { if (this.gap) {
this.gap.from = Math.min(offsetLine(this.gap.from, startLine, sizeChange), change.from.line); this.gap.from = Math.min(offsetLine(this.gap.from, startLine, sizeChange), change.from.line);
this.gap.to = Math.max(offsetLine(this.gap.to, startLine, sizeChange), change.from.line); this.gap.to = Math.max(offsetLine(this.gap.to, startLine, sizeChange), change.from.line);
} else { } else {
this.gap = {from: change.from.line, to: endLine + 1}; this.gap = {from: change.from.line, to: endLine + 1};
} }
if (sizeChange) for (var i = 0; i < this.matches.length; i++) { if (sizeChange) for (var i = 0; i < this.matches.length; i++) {
var match = this.matches[i]; var match = this.matches[i];
var newFrom = offsetLine(match.from.line, startLine, sizeChange); var newFrom = offsetLine(match.from.line, startLine, sizeChange);
if (newFrom != match.from.line) match.from = CodeMirror.Pos(newFrom, match.from.ch); if (newFrom != match.from.line) match.from = CodeMirror.Pos(newFrom, match.from.ch);
var newTo = offsetLine(match.to.line, startLine, sizeChange); var newTo = offsetLine(match.to.line, startLine, sizeChange);
if (newTo != match.to.line) match.to = CodeMirror.Pos(newTo, match.to.ch); if (newTo != match.to.line) match.to = CodeMirror.Pos(newTo, match.to.ch);
} }
clearTimeout(this.update); clearTimeout(this.update);
var self = this; var self = this;
this.update = setTimeout(function() { self.updateAfterChange(); }, 250); this.update = setTimeout(function() { self.updateAfterChange(); }, 250);
}; };
SearchAnnotation.prototype.updateAfterChange = function() { SearchAnnotation.prototype.updateAfterChange = function() {
this.findMatches(); this.findMatches();
this.annotation.update(this.matches); this.annotation.update(this.matches);
}; };
SearchAnnotation.prototype.clear = function() { SearchAnnotation.prototype.clear = function() {
this.cm.off("change", this.changeHandler); this.cm.off("change", this.changeHandler);
this.annotation.clear(); this.annotation.clear();
}; };
}); });

View File

@@ -1,231 +1,231 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
// Define search commands. Depends on dialog.js or another // Define search commands. Depends on dialog.js or another
// implementation of the openDialog method. // implementation of the openDialog method.
// Replace works a little oddly -- it will do the replace on the next // Replace works a little oddly -- it will do the replace on the next
// Ctrl-G (or whatever is bound to findNext) press. You prevent a // Ctrl-G (or whatever is bound to findNext) press. You prevent a
// replace by making sure the match is no longer selected when hitting // replace by making sure the match is no longer selected when hitting
// Ctrl-G. // Ctrl-G.
(function(mod) { (function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("./searchcursor"), require("../dialog/dialog")); mod(require("../../lib/codemirror"), require("./searchcursor"), require("../dialog/dialog"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "./searchcursor", "../dialog/dialog"], mod); define(["../../lib/codemirror", "./searchcursor", "../dialog/dialog"], mod);
else // Plain browser env else // Plain browser env
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");
else if (!query.global) else if (!query.global)
query = new RegExp(query.source, query.ignoreCase ? "gi" : "g"); query = new RegExp(query.source, query.ignoreCase ? "gi" : "g");
return {token: function(stream) { return {token: function(stream) {
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 || 1; stream.pos += match[0].length || 1;
return "searching"; return "searching";
} else if (match) { } else if (match) {
stream.pos = match.index; stream.pos = match.index;
} else { } else {
stream.skipToEnd(); stream.skipToEnd();
} }
}}; }};
} }
function SearchState() { function SearchState() {
this.posFrom = this.posTo = this.lastQuery = 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) { function persistentDialog(cm, text, deflt, f) {
cm.openDialog(text, f, { cm.openDialog(text, f, {
value: deflt, value: deflt,
selectValueOnOpen: true, selectValueOnOpen: true,
closeOnEnter: false, closeOnEnter: false,
onClose: function() { clearSearch(cm); } 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, selectValueOnOpen: true}); 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) { function parseString(string) {
return string.replace(/\\(.)/g, function(_, ch) { return string.replace(/\\(.)/g, function(_, ch) {
if (ch == "n") return "\n" if (ch == "n") return "\n"
if (ch == "r") return "\r" if (ch == "r") return "\r"
return ch 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 { } else {
query = parseString(query) 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 startSearch(cm, state, query) { function startSearch(cm, state, query) {
state.queryText = query; state.queryText = query;
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));
cm.addOverlay(state.overlay); cm.addOverlay(state.overlay);
if (cm.showMatchesOnScrollbar) { if (cm.showMatchesOnScrollbar) {
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) { function doSearch(cm, rev, persistent) {
var state = getSearchState(cm); var state = getSearchState(cm);
if (state.query) return findNext(cm, rev); if (state.query) return findNext(cm, rev);
var q = cm.getSelection() || state.lastQuery; var q = cm.getSelection() || state.lastQuery;
if (persistent && cm.openDialog) { if (persistent && cm.openDialog) {
var hiding = null var hiding = null
persistentDialog(cm, queryDialog, q, function(query, event) { persistentDialog(cm, queryDialog, q, function(query, event) {
CodeMirror.e_stop(event); CodeMirror.e_stop(event);
if (!query) return; if (!query) return;
if (query != state.queryText) { if (query != state.queryText) {
startSearch(cm, state, query); startSearch(cm, state, query);
state.posFrom = state.posTo = cm.getCursor(); state.posFrom = state.posTo = cm.getCursor();
} }
if (hiding) hiding.style.opacity = 1 if (hiding) hiding.style.opacity = 1
findNext(cm, event.shiftKey, function(_, to) { findNext(cm, event.shiftKey, function(_, to) {
var dialog var dialog
if (to.line < 3 && document.querySelector && if (to.line < 3 && document.querySelector &&
(dialog = cm.display.wrapper.querySelector(".CodeMirror-dialog")) && (dialog = cm.display.wrapper.querySelector(".CodeMirror-dialog")) &&
dialog.getBoundingClientRect().bottom - 4 > cm.cursorCoords(to, "window").top) dialog.getBoundingClientRect().bottom - 4 > cm.cursorCoords(to, "window").top)
(hiding = dialog).style.opacity = .4 (hiding = dialog).style.opacity = .4
}) })
}); });
} else { } else {
dialog(cm, queryDialog, "Search for:", q, function(query) { dialog(cm, queryDialog, "Search for:", q, function(query) {
if (query && !state.query) cm.operation(function() { if (query && !state.query) cm.operation(function() {
startSearch(cm, state, query); 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, callback) {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)) {
cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0)); cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0));
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()}, 20); 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()) 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; state.lastQuery = state.query;
if (!state.query) return; if (!state.query) return;
state.query = state.queryText = 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 =
' <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>All</button> <button>Stop</button>"; var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>All</button> <button>Stop</button>";
function replaceAll(cm, query, text) { function replaceAll(cm, query, text) {
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") {
var match = cm.getRange(cursor.from(), cursor.to()).match(query); var match = cm.getRange(cursor.from(), cursor.to()).match(query);
cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];})); cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
} else cursor.replace(text); } else cursor.replace(text);
} }
}); });
} }
function replace(cm, all) { function replace(cm, all) {
if (cm.getOption("readOnly")) return; if (cm.getOption("readOnly")) return;
var query = cm.getSelection() || getSearchState(cm).lastQuery; var query = cm.getSelection() || getSearchState(cm).lastQuery;
var dialogText = all ? "Replace all:" : "Replace:" var dialogText = all ? "Replace all:" : "Replace:"
dialog(cm, dialogText + replaceQueryDialog, dialogText, query, function(query) { dialog(cm, dialogText + replaceQueryDialog, dialogText, query, function(query) {
if (!query) return; if (!query) return;
query = parseQuery(query); query = parseQuery(query);
dialog(cm, replacementQueryDialog, "Replace with:", "", function(text) { dialog(cm, replacementQueryDialog, "Replace with:", "", function(text) {
text = parseString(text) text = parseString(text)
if (all) { if (all) {
replaceAll(cm, query, text) replaceAll(cm, query, text)
} else { } else {
clearSearch(cm); clearSearch(cm);
var cursor = getSearchCursor(cm, query, cm.getCursor("from")); var cursor = getSearchCursor(cm, query, cm.getCursor("from"));
var advance = function() { var advance = function() {
var start = cursor.from(), match; var start = cursor.from(), match;
if (!(match = cursor.findNext())) { if (!(match = cursor.findNext())) {
cursor = getSearchCursor(cm, query); cursor = getSearchCursor(cm, query);
if (!(match = cursor.findNext()) || if (!(match = cursor.findNext()) ||
(start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return; (start && cursor.from().line == start.line && cursor.from().ch == start.ch)) 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()});
confirmDialog(cm, doReplaceConfirm, "Replace?", confirmDialog(cm, doReplaceConfirm, "Replace?",
[function() {doReplace(match);}, advance, [function() {doReplace(match);}, advance,
function() {replaceAll(cm, query, text)}]); 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 :
text.replace(/\$(\d)/g, function(_, i) {return match[i];})); text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
advance(); advance();
}; };
advance(); advance();
} }
}); });
}); });
} }
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.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;
CodeMirror.commands.replace = replace; CodeMirror.commands.replace = replace;
CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);}; CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);};
}); });

View File

@@ -1,189 +1,189 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
(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"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
var Pos = CodeMirror.Pos; var Pos = CodeMirror.Pos;
function SearchCursor(doc, query, pos, caseFold) { function SearchCursor(doc, query, pos, caseFold) {
this.atOccurrence = false; this.doc = doc; this.atOccurrence = false; this.doc = doc;
if (caseFold == null && typeof query == "string") caseFold = false; if (caseFold == null && typeof query == "string") caseFold = false;
pos = pos ? doc.clipPos(pos) : Pos(0, 0); pos = pos ? doc.clipPos(pos) : Pos(0, 0);
this.pos = {from: pos, to: pos}; this.pos = {from: pos, to: pos};
// The matches method is filled in based on the type of query. // The matches method is filled in based on the type of query.
// It takes a position and a direction, and returns an object // It takes a position and a direction, and returns an object
// describing the next occurrence of the query, or null if no // describing the next occurrence of the query, or null if no
// more matches were found. // more matches were found.
if (typeof query != "string") { // Regexp match if (typeof query != "string") { // Regexp match
if (!query.global) query = new RegExp(query.source, query.ignoreCase ? "ig" : "g"); if (!query.global) query = new RegExp(query.source, query.ignoreCase ? "ig" : "g");
this.matches = function(reverse, pos) { this.matches = function(reverse, pos) {
if (reverse) { if (reverse) {
query.lastIndex = 0; query.lastIndex = 0;
var line = doc.getLine(pos.line).slice(0, pos.ch), cutOff = 0, match, start; var line = doc.getLine(pos.line).slice(0, pos.ch), cutOff = 0, match, start;
for (;;) { for (;;) {
query.lastIndex = cutOff; query.lastIndex = cutOff;
var newMatch = query.exec(line); var newMatch = query.exec(line);
if (!newMatch) break; if (!newMatch) break;
match = newMatch; match = newMatch;
start = match.index; start = match.index;
cutOff = match.index + (match[0].length || 1); cutOff = match.index + (match[0].length || 1);
if (cutOff == line.length) break; if (cutOff == line.length) break;
} }
var matchLen = (match && match[0].length) || 0; var matchLen = (match && match[0].length) || 0;
if (!matchLen) { if (!matchLen) {
if (start == 0 && line.length == 0) {match = undefined;} if (start == 0 && line.length == 0) {match = undefined;}
else if (start != doc.getLine(pos.line).length) { else if (start != doc.getLine(pos.line).length) {
matchLen++; matchLen++;
} }
} }
} else { } else {
query.lastIndex = pos.ch; query.lastIndex = pos.ch;
var line = doc.getLine(pos.line), match = query.exec(line); var line = doc.getLine(pos.line), match = query.exec(line);
var matchLen = (match && match[0].length) || 0; var matchLen = (match && match[0].length) || 0;
var start = match && match.index; var start = match && match.index;
if (start + matchLen != line.length && !matchLen) matchLen = 1; if (start + matchLen != line.length && !matchLen) matchLen = 1;
} }
if (match && matchLen) if (match && matchLen)
return {from: Pos(pos.line, start), return {from: Pos(pos.line, start),
to: Pos(pos.line, start + matchLen), to: Pos(pos.line, start + matchLen),
match: match}; match: match};
}; };
} else { // String query } else { // String query
var origQuery = query; var origQuery = query;
if (caseFold) query = query.toLowerCase(); if (caseFold) query = query.toLowerCase();
var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;}; var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;};
var target = query.split("\n"); var target = query.split("\n");
// Different methods for single-line and multi-line queries // Different methods for single-line and multi-line queries
if (target.length == 1) { if (target.length == 1) {
if (!query.length) { if (!query.length) {
// Empty string would match anything and never progress, so // Empty string would match anything and never progress, so
// we define it to match nothing instead. // we define it to match nothing instead.
this.matches = function() {}; this.matches = function() {};
} else { } else {
this.matches = function(reverse, pos) { this.matches = function(reverse, pos) {
if (reverse) { if (reverse) {
var orig = doc.getLine(pos.line).slice(0, pos.ch), line = fold(orig); var orig = doc.getLine(pos.line).slice(0, pos.ch), line = fold(orig);
var match = line.lastIndexOf(query); var match = line.lastIndexOf(query);
if (match > -1) { if (match > -1) {
match = adjustPos(orig, line, match); match = adjustPos(orig, line, match);
return {from: Pos(pos.line, match), to: Pos(pos.line, match + origQuery.length)}; return {from: Pos(pos.line, match), to: Pos(pos.line, match + origQuery.length)};
} }
} else { } else {
var orig = doc.getLine(pos.line).slice(pos.ch), line = fold(orig); var orig = doc.getLine(pos.line).slice(pos.ch), line = fold(orig);
var match = line.indexOf(query); var match = line.indexOf(query);
if (match > -1) { if (match > -1) {
match = adjustPos(orig, line, match) + pos.ch; match = adjustPos(orig, line, match) + pos.ch;
return {from: Pos(pos.line, match), to: Pos(pos.line, match + origQuery.length)}; return {from: Pos(pos.line, match), to: Pos(pos.line, match + origQuery.length)};
} }
} }
}; };
} }
} else { } else {
var origTarget = origQuery.split("\n"); var origTarget = origQuery.split("\n");
this.matches = function(reverse, pos) { this.matches = function(reverse, pos) {
var last = target.length - 1; var last = target.length - 1;
if (reverse) { if (reverse) {
if (pos.line - (target.length - 1) < doc.firstLine()) return; if (pos.line - (target.length - 1) < doc.firstLine()) return;
if (fold(doc.getLine(pos.line).slice(0, origTarget[last].length)) != target[target.length - 1]) return; if (fold(doc.getLine(pos.line).slice(0, origTarget[last].length)) != target[target.length - 1]) return;
var to = Pos(pos.line, origTarget[last].length); var to = Pos(pos.line, origTarget[last].length);
for (var ln = pos.line - 1, i = last - 1; i >= 1; --i, --ln) for (var ln = pos.line - 1, i = last - 1; i >= 1; --i, --ln)
if (target[i] != fold(doc.getLine(ln))) return; if (target[i] != fold(doc.getLine(ln))) return;
var line = doc.getLine(ln), cut = line.length - origTarget[0].length; var line = doc.getLine(ln), cut = line.length - origTarget[0].length;
if (fold(line.slice(cut)) != target[0]) return; if (fold(line.slice(cut)) != target[0]) return;
return {from: Pos(ln, cut), to: to}; return {from: Pos(ln, cut), to: to};
} else { } else {
if (pos.line + (target.length - 1) > doc.lastLine()) return; if (pos.line + (target.length - 1) > doc.lastLine()) return;
var line = doc.getLine(pos.line), cut = line.length - origTarget[0].length; var line = doc.getLine(pos.line), cut = line.length - origTarget[0].length;
if (fold(line.slice(cut)) != target[0]) return; if (fold(line.slice(cut)) != target[0]) return;
var from = Pos(pos.line, cut); var from = Pos(pos.line, cut);
for (var ln = pos.line + 1, i = 1; i < last; ++i, ++ln) for (var ln = pos.line + 1, i = 1; i < last; ++i, ++ln)
if (target[i] != fold(doc.getLine(ln))) return; if (target[i] != fold(doc.getLine(ln))) return;
if (fold(doc.getLine(ln).slice(0, origTarget[last].length)) != target[last]) return; if (fold(doc.getLine(ln).slice(0, origTarget[last].length)) != target[last]) return;
return {from: from, to: Pos(ln, origTarget[last].length)}; return {from: from, to: Pos(ln, origTarget[last].length)};
} }
}; };
} }
} }
} }
SearchCursor.prototype = { SearchCursor.prototype = {
findNext: function() {return this.find(false);}, findNext: function() {return this.find(false);},
findPrevious: function() {return this.find(true);}, findPrevious: function() {return this.find(true);},
find: function(reverse) { find: function(reverse) {
var self = this, pos = this.doc.clipPos(reverse ? this.pos.from : this.pos.to); var self = this, pos = this.doc.clipPos(reverse ? this.pos.from : this.pos.to);
function savePosAndFail(line) { function savePosAndFail(line) {
var pos = Pos(line, 0); var pos = Pos(line, 0);
self.pos = {from: pos, to: pos}; self.pos = {from: pos, to: pos};
self.atOccurrence = false; self.atOccurrence = false;
return false; return false;
} }
for (;;) { for (;;) {
if (this.pos = this.matches(reverse, pos)) { if (this.pos = this.matches(reverse, pos)) {
this.atOccurrence = true; this.atOccurrence = true;
return this.pos.match || true; return this.pos.match || true;
} }
if (reverse) { if (reverse) {
if (!pos.line) return savePosAndFail(0); if (!pos.line) return savePosAndFail(0);
pos = Pos(pos.line-1, this.doc.getLine(pos.line-1).length); pos = Pos(pos.line-1, this.doc.getLine(pos.line-1).length);
} }
else { else {
var maxLine = this.doc.lineCount(); var maxLine = this.doc.lineCount();
if (pos.line == maxLine - 1) return savePosAndFail(maxLine); if (pos.line == maxLine - 1) return savePosAndFail(maxLine);
pos = Pos(pos.line + 1, 0); pos = Pos(pos.line + 1, 0);
} }
} }
}, },
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, origin) { 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, origin); 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));
} }
}; };
// Maps a position in a case-folded line back to a position in the original line // Maps a position in a case-folded line back to a position in the original line
// (compensating for codepoints increasing in number during folding) // (compensating for codepoints increasing in number during folding)
function adjustPos(orig, folded, pos) { function adjustPos(orig, folded, pos) {
if (orig.length == folded.length) return pos; if (orig.length == folded.length) return pos;
for (var pos1 = Math.min(pos, orig.length);;) { for (var pos1 = Math.min(pos, orig.length);;) {
var len1 = orig.slice(0, pos1).toLowerCase().length; var len1 = orig.slice(0, pos1).toLowerCase().length;
if (len1 < pos) ++pos1; if (len1 < pos) ++pos1;
else if (len1 > pos) --pos1; else if (len1 > pos) --pos1;
else return pos1; else return pos1;
} }
} }
CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) { CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) {
return new SearchCursor(this.doc, query, pos, caseFold); return new SearchCursor(this.doc, query, pos, caseFold);
}); });
CodeMirror.defineDocExtension("getSearchCursor", function(query, pos, caseFold) { CodeMirror.defineDocExtension("getSearchCursor", function(query, pos, caseFold) {
return new SearchCursor(this, query, pos, caseFold); return new SearchCursor(this, query, pos, caseFold);
}); });
CodeMirror.defineExtension("selectMatches", function(query, caseFold) { CodeMirror.defineExtension("selectMatches", function(query, caseFold) {
var ranges = []; var ranges = [];
var cur = this.getSearchCursor(query, this.getCursor("from"), caseFold); var cur = this.getSearchCursor(query, this.getCursor("from"), caseFold);
while (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()});
} }
if (ranges.length) if (ranges.length)
this.setSelections(ranges, 0); this.setSelections(ranges, 0);
}); });
}); });

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