1
0
mirror of https://github.com/stolksdorf/homebrewery.git synced 2025-12-15 23:05:57 +00:00

Merge branch 'v2.1'

This commit is contained in:
Scott Tolksdorf
2016-05-29 13:46:47 -04:00
202 changed files with 31419 additions and 31216 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,5 +1,12 @@
# changelog # changelog
### Sunday, 29/05/2016 - v2.1.0
- Finally added a syntax for doing spell lists. A bit in-depth about why this took so long. Essentially I'm running out of syntax to use in stardard Markdown. There are too many unique elements in the PHB-style to be mapped. I solved this earlier by stacking certain elements together (eg. an `<hr>` before a `blockquote` turns it into moster state block), but those are getting unweildly. I would like to simply wrap these in `div`s with classes, but unfortunately Markdown stops processing when within HTML blocks. To get around this I wrote my own override to the Markdown parser and lexer to process Markdown within a simple div class wrapper. This should open the door for more unique syntaxes in the future. Big step!
- Override Ctrl+P (and cmd+P) to launch to the print page. Many people try to just print either the editing or share page to get a PDF. While this dones;t make much sense, I do get a ton of issues about it. So now if you try to do this, it'll just bring you imediately to the print page. Everybody wins!
- The onboarding flow has also been confusing a few users (Homepage -> new -> save -> edit page). If you edit the Homepage text now, a Call to Action to save your work will pop-up.
- Added a 'Recently Edited' and 'Recently Viewed' nav item to the edit and share page respectively. Each will remember the last 8 items you edited or viewed and when you viewed it. Makes use of the new title attribute of brews to easy navigatation.
- Paragraphs now indent properly after lists (thanks u/slitjen!)
### Friday, 27/05/2016 - v2.0.6 ### Friday, 27/05/2016 - v2.0.6
- Updated the issue template for (hopefully) better reporting - Updated the issue template for (hopefully) better reporting
- Added suggestion to use chrome while PDF printing - Added suggestion to use chrome while PDF printing
@@ -17,7 +24,7 @@
- Bumped up the allowed entity size for extra-large brew (Thanks for reporting it dickboner93) - Bumped up the allowed entity size for extra-large brew (Thanks for reporting it dickboner93)
- Added a little error box when a save fails with a custom link to reporting the issue on github. - Added a little error box when a save fails with a custom link to reporting the issue on github.
/page \page
### Saturday, 14/05/2016 - v2.0.0 (finally!) ### Saturday, 14/05/2016 - v2.0.0 (finally!)

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

@@ -3,6 +3,19 @@ var _ = require('lodash');
var cx = require('classnames'); var cx = require('classnames');
var Markdown = require('marked'); var Markdown = require('marked');
var renderer = new Markdown.Renderer();
//Processes the markdown within an HTML block if it's just a class-wrapper
renderer.html = function (html) {
if(_.startsWith(html, '<div class=') && _.endsWith(_.trim(html), '</div>')){
var openTag = html.substring(0, html.indexOf('>')+1);
html = html.substring(html.indexOf('>')+1);
html = html.substring(0, html.lastIndexOf('</div>'));
return `${openTag} ${Markdown(html)} </div>`;
}
return html;
}
var PAGE_HEIGHT = 1056 + 30; var PAGE_HEIGHT = 1056 + 30;
@@ -64,7 +77,7 @@ var BrewRenderer = React.createClass({
}, },
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, {renderer : renderer})}} key={index} />
}, },
renderPages : function(){ renderPages : function(){

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

@@ -0,0 +1,91 @@
var _ = require('lodash');
var spellNames = [
"Astral Rite of Acne",
"Create Acne",
"Cursed Ramen Erruption",
"Dark Chant of the Dentists",
"Erruption of Immaturity",
"Flaming Disc of Inconvenience",
"Heal Bad Hygene",
"Heavenly Transfiguration of the Cream Devil",
"Hellish Cage of Mucus",
"Irritate Peanut Butter Fairy",
"Luminous Erruption of Tea",
"Mystic Spell of the Poser",
"Sorcerous Enchantment of the Chimneysweep",
"Steak Sauce Ray",
"Talk to Groupie",
"Astonishing Chant of Chocolate",
"Astounding Pasta Puddle",
"Ball of Annoyance",
"Cage of Yarn",
"Control Noodles Elemental",
"Create Nervousness",
"Cure Baldness",
"Cursed Ritual of Bad Hair",
"Dispell Piles in Dentist",
"Eliminate Florists",
"Illusionary Transfiguration of the Babysitter",
"Necromantic Armor of Salad Dressing",
"Occult Transfiguration of Foot Fetish",
"Protection from Mucus Giant",
"Tinsel Blast",
"Alchemical Evocation of the Goths",
"Call Fangirl",
"Divine Spell of Crossdressing",
"Dominate Ramen Giant",
"Eliminate Vindictiveness in Gym Teacher",
"Extra-Planar Spell of Irritation",
"Induce Whining in Babysitter",
"Invoke Complaining",
"Magical Enchantment of Arrogance",
"Occult Globe of Salad Dressing",
"Overwhelming Enchantment of the Chocolate Fairy",
"Sorcerous Dandruff Globe",
"Spiritual Invocation of the Costumers",
"Ultimate Rite of the Confetti Angel",
"Ultimate Ritual of Mouthwash",
];
module.exports = {
spellList : function(){
var levels = ['Cantrips (0 Level)', '2nd Level', '3rd Level', '4th Level', '5th Level', '6th Level', '7th Level', '8th Level', '9th Level'];
var content = _.map(levels, (level)=>{
var spells = _.map(_.sampleSize(spellNames, _.random(5, 15)), (spell)=>{
return `- ${spell}`;
}).join('\n');
return `##### ${level} \n${spells} \n`;
}).join('\n');
return `<div class='spellList'>\n${content}\n</div>`;
},
spell : function(){
var level = ["1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th"];
var spellSchools = ["abjuration", "conjuration", "divination", "enchantment", "evocation", "illusion", "necromancy", "transmutation"];
var components = _.sampleSize(["V", "S", "M"], _.random(1,3)).join(', ');
if(components.indexOf("M") !== -1){
components += " (" + _.sampleSize(['a small doll', 'a crushed button worth at least 1cp', 'discarded gum wrapper'], _.random(1,3)).join(', ') + ")"
}
return [
"#### " + _.sample(spellNames),
"*" + _.sample(level) + "-level " + _.sample(spellSchools) + "*",
"___",
"- **Casting Time:** 1 action",
"- **Range:** " + _.sample(["Self", "Touch", "30 feet", "60 feet"]),
"- **Components:** " + components,
"- **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. ",
"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.",
"\n\n\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,11 +1,10 @@
var SpellGen = require('./spell.gen.js'); var MagicGen = require('./magic.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 = [
{ {
@@ -67,7 +66,12 @@ module.exports = [
{ {
name : 'Spell', name : 'Spell',
icon : 'fa-magic', icon : 'fa-magic',
gen : SpellGen, gen : MagicGen.spell,
},
{
name : 'Spell List',
icon : 'fa-list',
gen : MagicGen.spellList,
}, },
{ {
name : 'Class Feature', name : 'Class Feature',
@@ -171,5 +175,3 @@ module.exports = [
}, },
] ]

View File

@@ -1,78 +0,0 @@
var _ = require('lodash');
module.exports = function(){
var spellNames = [
"Astral Rite of Acne",
"Create Acne",
"Cursed Ramen Erruption",
"Dark Chant of the Dentists",
"Erruption of Immaturity",
"Flaming Disc of Inconvenience",
"Heal Bad Hygene",
"Heavenly Transfiguration of the Cream Devil",
"Hellish Cage of Mucus",
"Irritate Peanut Butter Fairy",
"Luminous Erruption of Tea",
"Mystic Spell of the Poser",
"Sorcerous Enchantment of the Chimneysweep",
"Steak Sauce Ray",
"Talk to Groupie",
"Astonishing Chant of Chocolate",
"Astounding Pasta Puddle",
"Ball of Annoyance",
"Cage of Yarn",
"Control Noodles Elemental",
"Create Nervousness",
"Cure Baldness",
"Cursed Ritual of Bad Hair",
"Dispell Piles in Dentist",
"Eliminate Florists",
"Illusionary Transfiguration of the Babysitter",
"Necromantic Armor of Salad Dressing",
"Occult Transfiguration of Foot Fetish",
"Protection from Mucus Giant",
"Tinsel Blast",
"Alchemical Evocation of the Goths",
"Call Fangirl",
"Divine Spell of Crossdressing",
"Dominate Ramen Giant",
"Eliminate Vindictiveness in Gym Teacher",
"Extra-Planar Spell of Irritation",
"Induce Whining in Babysitter",
"Invoke Complaining",
"Magical Enchantment of Arrogance",
"Occult Globe of Salad Dressing",
"Overwhelming Enchantment of the Chocolate Fairy",
"Sorcerous Dandruff Globe",
"Spiritual Invocation of the Costumers",
"Ultimate Rite of the Confetti Angel",
"Ultimate Ritual of Mouthwash",
];
var level = ["1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th"];
var spellSchools = ["abjuration", "conjuration", "divination", "enchantment", "evocation", "illusion", "necromancy", "transmutation"];
var components = _.sampleSize(["V", "S", "M"], _.random(1,3)).join(', ');
if(components.indexOf("M") !== -1){
components += " (" + _.sampleSize(['a small doll', 'a crushed button worth at least 1cp', 'discarded gum wrapper'], _.random(1,3)).join(', ') + ")"
}
return [
"#### " + _.sample(spellNames),
"*" + _.sample(level) + "-level " + _.sample(spellSchools) + "*",
"___",
"- **Casting Time:** 1 action",
"- **Range:** " + _.sample(["Self", "Touch", "30 feet", "60 feet"]),
"- **Components:** " + components,
"- **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. ",
"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.",
"\n\n\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

@@ -11,7 +11,7 @@ var Navbar = React.createClass({
<Nav.item href='/homebrew' className='homebrewLogo'> <Nav.item href='/homebrew' className='homebrewLogo'>
<div>The Homebrewery</div> <div>The Homebrewery</div>
</Nav.item> </Nav.item>
<Nav.item>v2.0.6</Nav.item> <Nav.item>v2.1.0</Nav.item>
</Nav.section> </Nav.section>
{this.props.children} {this.props.children}
</Nav.base> </Nav.base>

View File

@@ -1,58 +1,95 @@
.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; width : 250px;
padding : 2px; margin : 0;
width : 250px; padding : 2px;
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; color : #666;
color : #666; text-align : right;
&.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;
} }
} }
} }
.recent.navItem{
position : relative;
.dropdown{
position : absolute;
top : 28px;
left : 0px;
z-index : 10000;
width : 100%;
.item{
.animate(background-color);
position : relative;
display : block;
box-sizing : border-box;;
padding : 13px 5px;
background-color : #333;
color : white;
text-decoration : none;
border-top : 1px solid #888;
&:hover{
background-color : @blue;
}
.title{
display : inline-block;
overflow : hidden;
width : 100%;
text-overflow : ellipsis;
white-space : nowrap;
}
.time{
position : absolute;
right : 2px;
bottom : 2px;
font-size : 0.7em;
color : #888;
}
}
}
}
} }

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

@@ -0,0 +1,118 @@
var React = require('react');
var _ = require('lodash');
var cx = require('classnames');
var Moment = require('moment');
var Nav = require('naturalcrit/nav/nav.jsx');
var BaseItem = React.createClass({
getDefaultProps: function() {
return {
storageKey : '',
text : '',
currentBrew:{
title : '',
id : '',
url : ''
}
};
},
getInitialState: function() {
return {
showDropdown: false,
brews : []
};
},
componentDidMount: function() {
var brews = JSON.parse(localStorage.getItem(this.props.storageKey) || '[]');
brews = _.filter(brews, (brew)=>{
return brew.id !== this.props.currentBrew.id;
});
brews.unshift({
id : this.props.currentBrew.id,
url : this.props.currentBrew.url,
title : this.props.currentBrew.title,
ts : Date.now()
});
brews = _.slice(brews, 0, 8);
localStorage.setItem(this.props.storageKey, JSON.stringify(brews));
this.setState({
brews : brews
});
},
handleDropdown : function(show){
this.setState({
showDropdown : show
})
},
renderDropdown : function(){
if(!this.state.showDropdown) return null;
var items = _.map(this.state.brews, (brew)=>{
return <a href={brew.url} className='item' key={brew.id} target='_blank'>
<span className='title'>{brew.title}</span>
<span className='time'>{Moment(brew.ts).fromNow()}</span>
</a>
});
return <div className='dropdown'>{items}</div>
},
render : function(){
return <Nav.item icon='fa-clock-o' color='grey' className='recent'
onMouseEnter={this.handleDropdown.bind(null, true)}
onMouseLeave={this.handleDropdown.bind(null, false)}>
{this.props.text}
{this.renderDropdown()}
</Nav.item>
},
});
module.exports = {
viewed : React.createClass({
getDefaultProps: function() {
return {
brew : {
title : '',
shareId : ''
}
};
},
render : function(){
return <BaseItem text='recently viewed' storageKey='naturalCrit-homebrew-recently-viewed'
currentBrew={{
id : this.props.brew.shareId,
title : this.props.brew.title,
url : `/homebrew/share/${this.props.brew.shareId}`
}}
/>
},
}),
edited : React.createClass({
getDefaultProps: function() {
return {
brew : {
title : '',
editId : ''
}
};
},
render : function(){
return <BaseItem text='recently edited' storageKey='naturalCrit-homebrew-recently-edited'
currentBrew={{
id : this.props.brew.editId,
title : this.props.brew.title,
url : `/homebrew/edit/${this.props.brew.editId}`
}}
/>
},
}),
}

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,198 +1,205 @@
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 ReportIssue = require('../../navbar/issue.navitem.jsx'); var ReportIssue = require('../../navbar/issue.navitem.jsx');
var PrintLink = require('../../navbar/print.navitem.jsx'); var PrintLink = require('../../navbar/print.navitem.jsx');
var RecentlyEdited = require('../../navbar/recent.navitem.jsx').edited;
var SplitPane = require('naturalcrit/splitPane/splitPane.jsx');
var Editor = require('../../editor/editor.jsx'); var SplitPane = require('naturalcrit/splitPane/splitPane.jsx');
var BrewRenderer = require('../../brewRenderer/brewRenderer.jsx'); var Editor = require('../../editor/editor.jsx');
var BrewRenderer = require('../../brewRenderer/brewRenderer.jsx');
var HijackPrint = require('../hijackPrint.js');
const SAVE_TIMEOUT = 3000;
const SAVE_TIMEOUT = 3000;
var EditPage = React.createClass({
getDefaultProps: function() {
return {
id : null, var EditPage = React.createClass({
brew : { getDefaultProps: function() {
title : '', return {
text : '', id : null,
shareId : null, brew : {
editId : null, title : '',
createdAt : null, text : '',
updatedAt : null, shareId : null,
} editId : null,
}; createdAt : null,
}, updatedAt : null,
}
getInitialState: function() { };
return { },
title : this.props.brew.title,
text: this.props.brew.text, getInitialState: function() {
isSaving : false, return {
isPending : false, title : this.props.brew.title,
errors : null, text: this.props.brew.text,
lastUpdated : this.props.brew.updatedAt isSaving : false,
}; isPending : false,
}, errors : null,
savedBrew : null, lastUpdated : this.props.brew.updatedAt
};
componentDidMount: function(){ },
this.debounceSave = _.debounce(this.save, SAVE_TIMEOUT); savedBrew : null,
window.onbeforeunload = ()=>{
if(this.state.isSaving || this.state.isPending){ componentDidMount: function(){
return 'You have unsaved changes!'; this.debounceSave = _.debounce(this.save, SAVE_TIMEOUT);
} window.onbeforeunload = ()=>{
} if(this.state.isSaving || this.state.isPending){
}, return 'You have unsaved changes!';
componentWillUnmount: function() { }
window.onbeforeunload = function(){}; };
},
document.onkeydown = HijackPrint(this.props.brew.shareId);
handleSplitMove : function(){ },
this.refs.editor.update(); componentWillUnmount: function() {
}, window.onbeforeunload = function(){};
document.onkeydown = function(){};
handleTitleChange : function(title){ },
this.setState({
title : title, handleSplitMove : function(){
isPending : true this.refs.editor.update();
}); },
(this.hasChanges() ? this.debounceSave() : this.debounceSave.cancel()); handleTitleChange : function(title){
}, this.setState({
title : title,
handleTextChange : function(text){ isPending : true
this.setState({ });
text : text,
isPending : true (this.hasChanges() ? this.debounceSave() : this.debounceSave.cancel());
}); },
(this.hasChanges() ? this.debounceSave() : this.debounceSave.cancel()); handleTextChange : function(text){
}, this.setState({
text : text,
handleDelete : function(){ isPending : true
if(!confirm("are you sure you want to delete this brew?")) return; });
if(!confirm("are you REALLY sure? You will not be able to recover it")) return;
(this.hasChanges() ? this.debounceSave() : this.debounceSave.cancel());
request.get('/homebrew/api/remove/' + this.props.brew.editId) },
.send()
.end(function(err, res){ handleDelete : function(){
window.location.href = '/homebrew'; if(!confirm("are you sure you want to delete this brew?")) return;
}); if(!confirm("are you REALLY sure? You will not be able to recover it")) return;
},
request.get('/homebrew/api/remove/' + this.props.brew.editId)
hasChanges : function(){ .send()
if(this.savedBrew){ .end(function(err, res){
if(this.state.text !== this.savedBrew.text) return true; window.location.href = '/homebrew';
if(this.state.title !== this.savedBrew.title) return true; });
}else{ },
if(this.state.text !== this.props.brew.text) return true;
if(this.state.title !== this.props.brew.title) return true; hasChanges : function(){
} if(this.savedBrew){
return false; if(this.state.text !== this.savedBrew.text) return true;
}, if(this.state.title !== this.savedBrew.title) return true;
}else{
save : function(){ if(this.state.text !== this.props.brew.text) return true;
this.debounceSave.cancel(); if(this.state.title !== this.props.brew.title) return true;
this.setState({ }
isSaving : true, return false;
errors : null },
});
save : function(){
request this.debounceSave.cancel();
.put('/homebrew/api/update/' + this.props.brew.editId) this.setState({
.send({ isSaving : true,
text : this.state.text, errors : null
title : this.state.title });
})
.end((err, res) => { request
if(err){ .put('/homebrew/api/update/' + this.props.brew.editId)
this.setState({ .send({
errors : err, text : this.state.text,
}) title : this.state.title
}else{ })
this.savedBrew = res.body; .end((err, res) => {
this.setState({ if(err){
isPending : false, this.setState({
isSaving : false, errors : err,
lastUpdated : res.body.updatedAt })
}) }else{
} this.savedBrew = res.body;
}) this.setState({
}, isPending : false,
isSaving : false,
renderSaveButton : function(){ lastUpdated : res.body.updatedAt
if(this.state.errors){ })
var errMsg = ''; }
try{ })
errMsg += this.state.errors.toString() + '\n\n'; },
errMsg += '```\n' + JSON.stringify(this.state.errors.response.error, null, ' ') + '\n```';
}catch(e){} renderSaveButton : function(){
if(this.state.errors){
var errMsg = '';
return <Nav.item className='save error' icon="fa-warning"> try{
Oops! errMsg += this.state.errors.toString() + '\n\n';
<div className='errorContainer'> errMsg += '```\n' + JSON.stringify(this.state.errors.response.error, null, ' ') + '\n```';
Looks like there was a problem saving. <br /> }catch(e){}
Report the issue <a target='_blank' href={'https://github.com/stolksdorf/naturalcrit/issues/new?body='+ encodeURIComponent(errMsg)}>
here
</a>. return <Nav.item className='save error' icon="fa-warning">
</div> Oops!
</Nav.item> <div className='errorContainer'>
} Looks like there was a problem saving. <br />
Report the issue <a target='_blank' href={'https://github.com/stolksdorf/naturalcrit/issues/new?body='+ encodeURIComponent(errMsg)}>
if(this.state.isSaving){ here
return <Nav.item className='save' icon="fa-spinner fa-spin">saving...</Nav.item> </a>.
} </div>
if(!this.state.isPending && !this.state.isSaving){ </Nav.item>
return <Nav.item className='save saved'>saved.</Nav.item> }
}
if(this.state.isPending && this.hasChanges()){ if(this.state.isSaving){
return <Nav.item className='save' onClick={this.save} color='blue' icon='fa-save'>Save Now</Nav.item> return <Nav.item className='save' icon="fa-spinner fa-spin">saving...</Nav.item>
} }
}, if(!this.state.isPending && !this.state.isSaving){
renderNavbar : function(){ return <Nav.item className='save saved'>saved.</Nav.item>
return <Navbar> }
<Nav.section> if(this.state.isPending && this.hasChanges()){
<EditTitle title={this.state.title} onChange={this.handleTitleChange} /> return <Nav.item className='save' onClick={this.save} color='blue' icon='fa-save'>Save Now</Nav.item>
</Nav.section> }
<Nav.section> },
{this.renderSaveButton()} renderNavbar : function(){
<Nav.item newTab={true} href={'/homebrew/share/' + this.props.brew.shareId} color='teal' icon='fa-share-alt'> return <Navbar>
Share <Nav.section>
</Nav.item> <EditTitle title={this.state.title} onChange={this.handleTitleChange} />
<PrintLink shareId={this.props.brew.shareId} /> </Nav.section>
<Nav.item color='red' icon='fa-trash' onClick={this.handleDelete}> <Nav.section>
Delete {this.renderSaveButton()}
</Nav.item> <RecentlyEdited brew={this.props.brew} />
</Nav.section> <Nav.item newTab={true} href={'/homebrew/share/' + this.props.brew.shareId} color='teal' icon='fa-share-alt'>
</Navbar> Share
}, </Nav.item>
<PrintLink shareId={this.props.brew.shareId} />
render : function(){ <Nav.item color='red' icon='fa-trash' onClick={this.handleDelete}>
return <div className='editPage page'> Delete
{this.renderNavbar()} </Nav.item>
</Nav.section>
<div className='content'> </Navbar>
<SplitPane onDragFinish={this.handleSplitMove} ref='pane'> },
<Editor value={this.state.text} onChange={this.handleTextChange} ref='editor'/>
<BrewRenderer text={this.state.text} /> render : function(){
</SplitPane> return <div className='editPage page'>
</div> {this.renderNavbar()}
</div>
} <div className='content'>
}); <SplitPane onDragFinish={this.handleSplitMove} ref='pane'>
<Editor value={this.state.text} onChange={this.handleTextChange} ref='editor'/>
module.exports = EditPage; <BrewRenderer text={this.state.text} />
</SplitPane>
</div>
</div>
}
});
module.exports = EditPage;

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

@@ -0,0 +1,10 @@
module.exports = function(shareId){
return function(event){
event = event || window.event;
if((event.ctrlKey || event.metaKey) && event.keyCode == 80){
var win = window.open(`/homebrew/print/${shareId}?dialog=true`, '_blank');
win.focus();
event.preventDefault();
}
};
};

View File

@@ -1,70 +1,87 @@
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 Nav = require('naturalcrit/nav/nav.jsx');
var Navbar = require('../../navbar/navbar.jsx'); var Nav = require('naturalcrit/nav/nav.jsx');
var PatreonNavItem = require('../../navbar/patreon.navitem.jsx'); var Navbar = require('../../navbar/navbar.jsx');
var PatreonNavItem = require('../../navbar/patreon.navitem.jsx');
var SplitPane = require('naturalcrit/splitPane/splitPane.jsx');
var Editor = require('../../editor/editor.jsx'); var SplitPane = require('naturalcrit/splitPane/splitPane.jsx');
var BrewRenderer = require('../../brewRenderer/brewRenderer.jsx'); var Editor = require('../../editor/editor.jsx');
var BrewRenderer = require('../../brewRenderer/brewRenderer.jsx');
var HomePage = React.createClass({
getDefaultProps: function() { var HomePage = React.createClass({
return { getDefaultProps: function() {
welcomeText : "" return {
}; welcomeText : ""
}, };
getInitialState: function() { },
return { getInitialState: function() {
text: this.props.welcomeText return {
}; text: this.props.welcomeText
}, };
handleSplitMove : function(){ },
this.refs.editor.update(); handleSave : function(){
}, request.post('/homebrew/api')
handleTextChange : function(text){ .send({
this.setState({ title : 'Change This',
text : text text : this.state.text
}); })
}, .end((err, res)=>{
renderNavbar : function(){ if(err) return;
return <Navbar> var brew = res.body;
<Nav.section> window.location = '/homebrew/edit/' + brew.editId;
<PatreonNavItem /> });
<Nav.item newTab={true} href='https://github.com/stolksdorf/naturalcrit/issues' color='red' icon='fa-bug'> },
report issue handleSplitMove : function(){
</Nav.item> this.refs.editor.update();
<Nav.item newTab={true} href='/homebrew/changelog' color='purple' icon='fa-file-text-o'> },
Changelog handleTextChange : function(text){
</Nav.item> this.setState({
<Nav.item href='/homebrew/new' color='green' icon='fa-external-link'> text : text
New Brew });
</Nav.item> },
</Nav.section> renderNavbar : function(){
</Navbar> return <Navbar>
}, <Nav.section>
<PatreonNavItem />
render : function(){ <Nav.item newTab={true} href='https://github.com/stolksdorf/naturalcrit/issues' color='red' icon='fa-bug'>
return <div className='homePage page'> report issue
{this.renderNavbar()} </Nav.item>
<Nav.item newTab={true} href='/homebrew/changelog' color='purple' icon='fa-file-text-o'>
<div className='content'> Changelog
<SplitPane onDragFinish={this.handleSplitMove} ref='pane'> </Nav.item>
<Editor value={this.state.text} onChange={this.handleTextChange} ref='editor'/> <Nav.item href='/homebrew/new' color='green' icon='fa-external-link'>
<BrewRenderer text={this.state.text} /> New Brew
</SplitPane> </Nav.item>
</div> </Nav.section>
</Navbar>
<a href='/homebrew/new' className='floatingNewButton'> },
Create your own <i className='fa fa-magic' />
</a> render : function(){
</div> return <div className='homePage page'>
} {this.renderNavbar()}
});
<div className='content'>
module.exports = HomePage; <SplitPane onDragFinish={this.handleSplitMove} ref='pane'>
<Editor value={this.state.text} onChange={this.handleTextChange} ref='editor'/>
<BrewRenderer text={this.state.text} />
</SplitPane>
</div>
<div className={cx('floatingSaveButton', {show : this.props.welcomeText != this.state.text})} onClick={this.handleSave}>
Save current <i className='fa fa-save' />
</div>
<a href='/homebrew/new' className='floatingNewButton'>
Create your own <i className='fa fa-magic' />
</a>
</div>
}
});
module.exports = HomePage;

View File

@@ -1,21 +1,43 @@
.homePage{
.homePage{ position : relative;
position : relative; a.floatingNewButton{
a.floatingNewButton{ .animate(background-color);
.animate(background-color); position : absolute;
position : absolute; display : block;
display : block; right : 70px;
right : 70px; bottom : 70px;
bottom : 70px; z-index : 100;
z-index : 100; z-index : 5001;
padding : 1em; padding : 1em;
background-color : @orange; background-color : @orange;
font-size : 1.5em; font-size : 1.5em;
color : white; color : white;
text-decoration : none; text-decoration : none;
box-shadow : 3px 3px 15px black; box-shadow : 3px 3px 15px black;
&:hover{ &:hover{
background-color : darken(@orange, 20%); background-color : darken(@orange, 20%);
} }
} }
.floatingSaveButton{
.animateAll();
position : absolute;
display : block;
right : 200px;
bottom : 90px;
z-index : 100;
z-index : 5000;
padding : 0.8em;
cursor : pointer;
background-color : @blue;
font-size : 0.8em;
color : white;
text-decoration : none;
box-shadow : 3px 3px 15px black;
&:hover{
background-color : darken(@blue, 20%);
}
&.show{
right : 350px;
}
}
} }

View File

@@ -8,17 +8,6 @@ The Homebrewery makes the creation and sharing of authentic looking Fifth-Editio
#### Features
* Monster Stat Blocks
* Full class tables
* Notes and Tables
* Images
* Page numbering and footers
* Vertical spacing, column breaks, and multiple pages
### Editing and Sharing ### Editing and Sharing
When you create your own homebrew you will be given a *edit url* and a *share url*. Any changes you make will be automatically saved to the database within a few seconds. Anyone with the edit url will be able to make edits to your homebrew. So be careful about who you share it with. When you create your own homebrew you will be given a *edit url* and a *share url*. Any changes you make will be automatically saved to the database within a few seconds. Anyone with the edit url will be able to make edits to your homebrew. So be careful about who you share it with.
@@ -33,20 +22,9 @@ This tool will **always** be free, never have ads, and I will never offer any "p
Have an idea of how to make The Homebrewery better? Or did you find something that wasn't quite right? Head [here](https://github.com/stolksdorf/NaturalCrit/issues/new) and let me know!. Have an idea of how to make The Homebrewery better? Or did you find something that wasn't quite right? Head [here](https://github.com/stolksdorf/NaturalCrit/issues/new) and let me know!.
```
```
## New Things in v2.0.0!
What's new in the latest update? Check out the full changelog [here](/homebrew/changelog)
* **A whole new look** The site has been re-built from the ground up!
* **Better editor and Split Pane** Syntax highlighting will make writing your brews even easier, and now you can customize how large your editor is.
* **More reliable rendering** Lots of work has been put into making the rendering more reliable, not just for web, but also for PDFs
* **PDF Printing on Chrome** You don't need to use Chrome Canary anymore!
* ** Performance Improvements** The site should load faster, save faster, and render large brews *much* faster.
* **Patreon page** If you like this tool and want to show some thanks you can [head here](https://www.patreon.com/stolksdorf).
>##### PDF Exporting >##### PDF Exporting
> PDF Printing works best in Chrome. If you are having quality/consistency issues, try using Chrome to print instead.
>
> After clicking the "Print" item in the navbar a new page will open and a print dialog will pop-up. > After clicking the "Print" item in the navbar a new page will open and a print dialog will pop-up.
> * Set the **Destination** to "Save as PDF" > * Set the **Destination** to "Save as PDF"
> * Set **Paper Size** to "Letter" > * Set **Paper Size** to "Letter"
@@ -54,11 +32,32 @@ What's new in the latest update? Check out the full changelog [here](/homebrew/c
> * In **Options** make sure "Background Images" is selected. > * In **Options** make sure "Background Images" is selected.
> * Hit print and enjoy! You're done! > * Hit print and enjoy! You're done!
> >
> PDF Printing works best in Chrome. If you are having quality/consistency issues, try using Chrome to print instead.
>
> If you want to save ink or have a monochrome printer, add the **Ink Friendly** snippet to your brew before you print > If you want to save ink or have a monochrome printer, add the **Ink Friendly** snippet to your brew before you print
```
```
## New Things in v2.1.0!
What's new in the latest update? Check out the full changelog [here](/homebrew/changelog)
* **Spell Lists** Tweaking the Markdown lexer and parser, I can now do nested Markdown within HTML blocks. Which means the available syntax I can use has vastly increased. Spell Lists are just the first of many new elements.
* **Recently Viewed/Edited** The Homebrewery now remembers which brews you've been editing and viewing. Check the navbar to quickly jump around to these.
* **Print Command Capturing** Pressing ctrl+p/cmd+p on any edit or share page will now jump you straight to the print page. Much more intutive.
## V2 Overhaul
A lot of <i class='fa fa-heart'></i> has been put into version 2 of The Homebrewery. Here are the highlights:
* **A whole new look** The site has been re-built from the ground up!
* **Better editor and split pane** Syntax highlighting will make writing your brews even easier, and now you can customize how large your editor is.
* **More reliable rendering** Lots of work has been put into making the rendering more reliable, not just for web, but also for PDFs
* **PDF Printing on Chrome** You don't need to use Chrome Canary anymore!
* ** Performance Improvements** The site should load faster, save faster, and render large brews *much* faster.
* **Patreon page** If you like this tool and want to show some thanks you can [head here](https://www.patreon.com/stolksdorf).

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,48 +1,58 @@
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');
var Navbar = require('../../navbar/navbar.jsx'); var Navbar = require('../../navbar/navbar.jsx');
var PrintLink = require('../../navbar/print.navitem.jsx');
var PrintLink = require('../../navbar/print.navitem.jsx'); var RecentlyViewed = require('../../navbar/recent.navitem.jsx').viewed;
var BrewRenderer = require('../../brewRenderer/brewRenderer.jsx'); var BrewRenderer = require('../../brewRenderer/brewRenderer.jsx');
var SharePage = React.createClass({ var HijackPrint = require('../hijackPrint.js');
getDefaultProps: function() {
return { var SharePage = React.createClass({
brew : { getDefaultProps: function() {
title : '', return {
text : '', brew : {
shareId : null, title : '',
createdAt : null, text : '',
updatedAt : null, shareId : null,
views : 0 createdAt : null,
} updatedAt : null,
}; views : 0
}, }
};
render : function(){ },
return <div className='sharePage page'>
<Navbar> componentDidMount: function() {
<Nav.section> document.onkeydown = HijackPrint(this.props.brew.shareId);
<Nav.item className='brewTitle'>{this.props.brew.title}</Nav.item> },
</Nav.section> componentWillUnmount: function() {
document.onkeydown = function(){};
<Nav.section> },
<PrintLink shareId={this.props.brew.shareId} />
<Nav.item href={'/homebrew/source/' + this.props.brew.shareId} color='teal' icon='fa-code'> render : function(){
source return <div className='sharePage page'>
</Nav.item> <Navbar>
</Nav.section> <Nav.section>
</Navbar> <Nav.item className='brewTitle'>{this.props.brew.title}</Nav.item>
</Nav.section>
<div className='content'>
<BrewRenderer text={this.props.brew.text} /> <Nav.section>
</div> <RecentlyViewed brew={this.props.brew} />
</div> <PrintLink shareId={this.props.brew.shareId} />
} <Nav.item href={'/homebrew/source/' + this.props.brew.shareId} color='teal' icon='fa-code'>
}); source
</Nav.item>
module.exports = SharePage; </Nav.section>
</Navbar>
<div className='content'>
<BrewRenderer text={this.props.brew.text} />
</div>
</div>
}
});
module.exports = SharePage;

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

@@ -59,22 +59,25 @@
line-height : 1.3em; line-height : 1.3em;
&+p{ &+p{
margin-top : -0.8em; margin-top : -0.8em;
text-indent : 1em;
} }
} }
ul{ ul{
margin-bottom : 0.8em; margin-bottom : 0.8em;
padding-left : 1.4em;
line-height : 1.3em; line-height : 1.3em;
list-style-position : outside; list-style-position : outside;
list-style-type : disc; list-style-type : disc;
padding-left: 1.4em;
} }
ol{ ol{
margin-bottom : 0.8em; margin-bottom : 0.8em;
padding-left : 1.4em;
line-height : 1.3em; line-height : 1.3em;
list-style-position : outside; list-style-position : outside;
list-style-type : decimal; list-style-type : decimal;
padding-left: 1.4em; }
//Indents after p or lists
p+p, ul+p, ol+p{
text-indent : 1em;
} }
img{ img{
z-index : -1; z-index : -1;
@@ -169,15 +172,15 @@
// *****************************/ // *****************************/
blockquote{ blockquote{
.useSansSerif(); .useSansSerif();
box-sizing : border-box; box-sizing : border-box;
margin-bottom : 1em; margin-bottom : 1em;
padding : 5px 10px; padding : 5px 10px;
background-color : @noteGreen; background-color : @noteGreen;
border-style: solid; border-style : solid;
border-width: 11px; border-width : 11px;
border-image: @noteBorderImage 11; border-image : @noteBorderImage 11;
border-image-outset: 9px 0px; border-image-outset : 9px 0px;
box-shadow : 1px 4px 14px #888; box-shadow : 1px 4px 14px #888;
p, ul{ p, ul{
font-size : 0.352cm; font-size : 0.352cm;
line-height : 1.1em; line-height : 1.1em;
@@ -185,7 +188,7 @@
} }
//If a note starts a column, give it space at the top to render border //If a note starts a column, give it space at the top to render border
pre+blockquote{ pre+blockquote{
margin-top: 11px; margin-top : 11px;
} }
//***************************** //*****************************
// * MONSTER STAT BLOCK // * MONSTER STAT BLOCK
@@ -222,8 +225,8 @@
margin : 0; margin : 0;
column-span : 1; column-span : 1;
background-color : transparent; background-color : transparent;
border-style : none;
border-image : none; border-image : none;
border-style : none;
-webkit-column-span : 1; -webkit-column-span : 1;
tbody{ tbody{
tr:nth-child(odd), tr:nth-child(even){ tr:nth-child(odd), tr:nth-child(even){
@@ -339,7 +342,7 @@
-moz-column-span : all; -moz-column-span : all;
} }
//Column Break //Column Break
pre{ pre, code{
visibility : hidden; visibility : hidden;
-webkit-column-break-after : always; -webkit-column-break-after : always;
break-after : always; break-after : always;
@@ -367,6 +370,31 @@
} }
} }
//***************************** //*****************************
// * SPELL LIST
// *****************************/
.phb .spellList{
.useSansSerif();
column-count : 4;
column-span : all;
-webkit-column-span : all;
-moz-column-span : all;
ul+h5{
margin-top : 15px;
}
p, ul{
font-size : 0.352cm;
line-height : 1.3em;
}
ul{
margin-bottom : 0.5em;
padding-left : 1em;
text-indent : -1em;
list-style-type : none;
-webkit-column-break-inside : auto;
column-break-inside : auto;
}
}
//*****************************
// * PRINT // * PRINT
// *****************************/ // *****************************/
.phb.print{ .phb.print{

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"

View File

@@ -208,21 +208,25 @@ table {
} }
.phb p + p { .phb p + p {
margin-top: -0.8em; margin-top: -0.8em;
text-indent: 1em;
} }
.phb ul { .phb ul {
margin-bottom: 0.8em; margin-bottom: 0.8em;
padding-left: 1.4em;
line-height: 1.3em; line-height: 1.3em;
list-style-position: outside; list-style-position: outside;
list-style-type: disc; list-style-type: disc;
padding-left: 1.4em;
} }
.phb ol { .phb ol {
margin-bottom: 0.8em; margin-bottom: 0.8em;
padding-left: 1.4em;
line-height: 1.3em; line-height: 1.3em;
list-style-position: outside; list-style-position: outside;
list-style-type: decimal; list-style-type: decimal;
padding-left: 1.4em; }
.phb p + p,
.phb ul + p,
.phb ol + p {
text-indent: 1em;
} }
.phb img { .phb img {
z-index: -1; z-index: -1;
@@ -384,8 +388,8 @@ table {
margin: 0; margin: 0;
column-span: 1; column-span: 1;
background-color: transparent; background-color: transparent;
border-image: none;
border-style: none; border-style: none;
border-image: none;
-webkit-column-span: 1; -webkit-column-span: 1;
} }
.phb hr + blockquote hr + table tbody tr:nth-child(odd), .phb hr + blockquote hr + table tbody tr:nth-child(odd),
@@ -492,7 +496,8 @@ table {
-webkit-column-span: all; -webkit-column-span: all;
-moz-column-span: all; -moz-column-span: all;
} }
.phb pre { .phb pre,
.phb code {
visibility: hidden; visibility: hidden;
-webkit-column-break-after: always; -webkit-column-break-after: always;
break-after: always; break-after: always;
@@ -521,6 +526,38 @@ table {
margin-bottom: 0px; margin-bottom: 0px;
margin-left: 1.5em; margin-left: 1.5em;
} }
.phb .spellList {
font-family: ScalySans;
column-count: 4;
column-span: all;
-webkit-column-span: all;
-moz-column-span: all;
}
.phb .spellList em {
font-family: ScalySans;
font-style: italic;
}
.phb .spellList strong {
font-family: ScalySans;
font-weight: 800;
letter-spacing: -0.02em;
}
.phb .spellList ul + h5 {
margin-top: 15px;
}
.phb .spellList p,
.phb .spellList ul {
font-size: 0.352cm;
line-height: 1.3em;
}
.phb .spellList ul {
margin-bottom: 0.5em;
padding-left: 1em;
text-indent: -1em;
list-style-type: none;
-webkit-column-break-inside: auto;
column-break-inside: auto;
}
.phb.print blockquote { .phb.print blockquote {
box-shadow: none; box-shadow: none;
} }

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

View File

@@ -1,32 +0,0 @@
.CodeMirror-dialog {
position: absolute;
left: 0; right: 0;
background: inherit;
z-index: 15;
padding: .1em .8em;
overflow: hidden;
color: inherit;
}
.CodeMirror-dialog-top {
border-bottom: 1px solid #eee;
top: 0;
}
.CodeMirror-dialog-bottom {
border-top: 1px solid #eee;
bottom: 0;
}
.CodeMirror-dialog input {
border: none;
outline: none;
background: transparent;
width: 20em;
color: inherit;
font-family: monospace;
}
.CodeMirror-dialog button {
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;
} }
} }
}; };
})(); })();

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