first coomit
@ -0,0 +1,3 @@
|
||||
.DS_Store
|
||||
.dropbox
|
||||
*Icon*
|
@ -0,0 +1,48 @@
|
||||
# Introduction
|
||||
|
||||
<canvas id="custom" class="canvas" data-fragment-url="cmyk-halftone.frag" data-textures="vangogh.jpg" width="700px" height="320px"></canvas>
|
||||
|
||||
The images above were made in different ways. The first one was made by Van Gogh's hand applying layer over layer of paint. It took him hours. The second was produced in seconds by the combination of four matrices of pixels: one for cyan, one for magenta, one for yellow and one for black. The key difference is that the second image is produced in a non-serial way (that means not step-by-step, but all at the same time).
|
||||
|
||||
This book is about the revolutionary computational technique, *fragment shaders*, that is taking digitally generated images to the next level. You can think of it as the equivalent of Gutenberg's press for graphics.
|
||||
|
||||
![Gutenberg's press](gutenpress.jpg)
|
||||
|
||||
Fragment shaders give you total control over the pixels rendered on the screen at a super fast speed. This is why they're used in all sort of cases, from video filters on cellphones to incredible 3D video games.
|
||||
|
||||
![Journey by The Game Company](journey.jpg)
|
||||
|
||||
In the following chapters you will discover how incredibly fast and powerful this technique is and how to apply it to your professional and personal work.
|
||||
|
||||
## Who is this book for?
|
||||
|
||||
This book is written for creative coders, game developers and engineers who have coding experience, a basic knowledge of linear algebra and trigonometry, and who want to take their work to an exciting new level of graphical quality. (If you want to learn how to code, I highly recommend you start with [Processing](https://processing.org/) and come back later when you are comfortable with it.)
|
||||
|
||||
This book will teach you how to use and integrate shaders into your projects, improving their performance and graphical quality. Because GLSL (OpenGL Shading Language) shaders compile and run on a variety of platforms, you will be able to apply what you learn here to any enviroment that uses OpenGL, OpenGL ES or WebGL. In other words, you will be able to apply and use your knowledge with [Processing](https://processing.org/) sketches, [openFrameworsk](http://openframeworks.cc/) applications, [Cinder](http://libcinder.org/) interactive installations, [Three.js](http://threejs.org/) websites or iOS/Android games.
|
||||
|
||||
## What does this book cover?
|
||||
|
||||
This book will focus on the use of GLSL pixel shaders. First we'll define what shaders are; then we'll learn how to make procedural shapes, patterns, textures and animations with them. You'll learn the foundations of shading language and apply it to more useful scenarios such as: image processing (image operations, matrix convolutions, blurs, color filters, lookup tables and other effects) and simulations (Conway's game of life, Gray-Scott's reaction-diffusion, water ripples, watercolor effects, Voronoi cells, etc.). Towards the end of the book we'll see a set of advanced techniques based on Ray Marching.
|
||||
|
||||
*There are interactive examples for you to play with in every chapter.* When you change the code, you will see the changes immediately. The concepts can be abstract and confusing, so the interactive examples are essential to helping you learn the material. The faster you put the concepts into motion the easier the learning process will be.
|
||||
|
||||
What this book doesn't cover:
|
||||
|
||||
* This *is not* an openGL or webGL book. OpenGL/webGL is a bigger subject than GLSL or fragment shaders. To learn more about openGL/webGL I recommend taking a look at: [OpenGL Introduction](https://open.gl/introduction), [the 8th edition of the OpenGL Programming Guide](http://www.amazon.com/OpenGL-Programming-Guide-Official-Learning/dp/0321773039/ref=sr_1_1?s=books&ie=UTF8&qid=1424007417&sr=1-1&keywords=open+gl+programming+guide) (also known as the red book) or [WebGL: Up and Running](http://www.amazon.com/WebGL-Up-Running-Tony-Parisi/dp/144932357X/ref=sr_1_4?s=books&ie=UTF8&qid=1425147254&sr=1-4&keywords=webgl)
|
||||
|
||||
* This *is not* a math book. Although we will cover a number of algorithms and techniques that rely on an understanding of algebra and trigonometry, we will not explain them in detail. For questions regarding the math I recommend keeping one of the following books nearby: [3rd Edition of Mathematics for 3D Game Programming and computer Graphics](http://www.amazon.com/Mathematics-Programming-Computer-Graphics-Third/dp/1435458869/ref=sr_1_1?ie=UTF8&qid=1424007839&sr=8-1&keywords=mathematics+for+games) or [2nd Edition of Essential Mathematics for Games and Interactive Applications](http://www.amazon.com/Essential-Mathematics-Games-Interactive-Applications/dp/0123742978/ref=sr_1_1?ie=UTF8&qid=1424007889&sr=8-1&keywords=essentials+mathematics+for+developers).
|
||||
|
||||
## What do you need to start?
|
||||
|
||||
Not much! If you have a modern browser that can do WebGL (like Chrome, Firefox or Safari) and a internet connection, click the “Next” Chapter button at the end of this page to get started.
|
||||
|
||||
Alternatively, based on what you have or what you need from this book you can:
|
||||
|
||||
- [Make a off-line version of this book](../90/)
|
||||
|
||||
- [Run the examples on a RaspberryPi without a browser](../91/)
|
||||
|
||||
- [Make a PDF of the book to print](../92/)
|
||||
|
||||
- Use the [on-line repository](https://github.com/patriciogonzalezvivo/thebookofshaders) to help resolve issues and share code.
|
||||
|
@ -0,0 +1,91 @@
|
||||
// Author: tsone
|
||||
// https://www.shadertoy.com/view/Mdf3Dn
|
||||
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
#define DOTSIZE 1.48
|
||||
#define D2R(d) radians(d)
|
||||
#define MIN_S 07.5
|
||||
#define MAX_S 15.0
|
||||
#define SPEED 0.3
|
||||
|
||||
#define SST 0.888
|
||||
#define SSQ 0.288
|
||||
|
||||
uniform sampler2D u_tex0;
|
||||
uniform vec2 u_resolution;
|
||||
uniform vec2 u_mouse;
|
||||
uniform float u_time;
|
||||
|
||||
vec2 ORIGIN = 0.5*u_resolution.xy;
|
||||
float S = MIN_S+(MAX_S-MIN_S)*(0.5-0.5*cos(SPEED*u_time));
|
||||
float R = SPEED*0.333*u_time;
|
||||
|
||||
vec4 rgb2cmyki (in vec4 c) {
|
||||
float k = max(max(c.r,c.g),c.b);
|
||||
return min(vec4(c.rgb/k,k),1.0);
|
||||
}
|
||||
|
||||
vec4 cmyki2rgb (in vec4 c) {
|
||||
return vec4(c.rgb*c.a,1.0);
|
||||
}
|
||||
|
||||
vec2 px2uv (in vec2 px) {
|
||||
return vec2(px/(u_resolution.xy*vec2(1.0,2.0))-vec2(1.0,0.0) );
|
||||
}
|
||||
|
||||
vec2 grid (in vec2 px) {
|
||||
return px-mod(px,S);
|
||||
}
|
||||
|
||||
vec4 ss(in vec4 v) {
|
||||
return smoothstep(SST-SSQ,SST+SSQ,v);
|
||||
}
|
||||
|
||||
vec4 halftone (in vec2 fc,in mat2 m) {
|
||||
vec2 smp = (grid(m*fc)+0.5*S)*m;
|
||||
float s = min(length(fc-smp)/(DOTSIZE*0.5*S),1.0);
|
||||
vec4 c = rgb2cmyki(texture2D(u_tex0,px2uv(smp+ORIGIN)));
|
||||
return c+s;
|
||||
}
|
||||
|
||||
mat2 rotm (in float r) {
|
||||
float cr = cos(r);
|
||||
float sr = sin(r);
|
||||
return mat2(
|
||||
cr,-sr,
|
||||
sr,cr
|
||||
);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 st = gl_FragCoord.xy/u_resolution.xy;
|
||||
|
||||
if (st.x > 0.5) {
|
||||
R = 3.14-(u_mouse.y/u_resolution.y)*(3.14/180.);
|
||||
S = 12.0-(u_mouse.x/u_resolution.x)*7.0;
|
||||
|
||||
vec2 fc = gl_FragCoord.xy*2.0-ORIGIN;
|
||||
mat2 mc = rotm(R+D2R(15.0));
|
||||
mat2 mm = rotm(R+D2R(75.0));
|
||||
mat2 my = rotm(R);
|
||||
mat2 mk = rotm(R+D2R(45.0));
|
||||
|
||||
float k = halftone(fc,mk).a;
|
||||
vec4 c = cmyki2rgb(ss(vec4(
|
||||
halftone(fc,mc).r,
|
||||
halftone(fc,mm).g,
|
||||
halftone(fc,my).b,
|
||||
halftone(fc,mk).a
|
||||
)));
|
||||
|
||||
gl_FragColor = c;
|
||||
} else {
|
||||
st = vec2(st.x,st.y*0.5)*2.0;
|
||||
gl_FragColor = texture2D(u_tex0,st);
|
||||
}
|
||||
|
||||
|
||||
}
|
After Width: | Height: | Size: 75 KiB |
@ -0,0 +1,63 @@
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
uniform sampler2D u_tex0;
|
||||
uniform vec2 u_resolution;
|
||||
uniform vec2 u_mouse;
|
||||
|
||||
float PI = 3.1415926535897932384626433832795;
|
||||
float PI180 = float(PI / 180.0);
|
||||
|
||||
float sind (float a) {
|
||||
return sin(a * PI180);
|
||||
}
|
||||
|
||||
float cosd (float a) {
|
||||
return cos(a * PI180);
|
||||
}
|
||||
|
||||
float added (vec2 sh, float sa, float ca, vec2 c, float d) {
|
||||
return 0.5 + 0.25 * cos((sh.x * sa + sh.y * ca + c.x) * d) + 0.25 * cos((sh.x * ca - sh.y * sa + c.y) * d);
|
||||
}
|
||||
|
||||
void main () {
|
||||
|
||||
float threshold = clamp(0.5, 0.0, 1.0);
|
||||
|
||||
vec2 st = gl_FragCoord.xy/u_resolution.xy;
|
||||
|
||||
if (st.x > 0.5) {
|
||||
// Halftone dot matrix shader
|
||||
// @author Tomek Augustyn 2010
|
||||
|
||||
// Ported from my old PixelBender experiment
|
||||
// https://github.com/og2t/HiSlope/blob/master/src/hislope/pbk/fx/halftone/Halftone.pbk
|
||||
float ratio = u_resolution.y / u_resolution.x;
|
||||
|
||||
vec2 dstCoord = vec2(st.x-0.5, st.y*0.5)*2.0;
|
||||
vec2 srcCoord = vec2(st.x-0.5, st.y*0.5)*2.0;
|
||||
vec2 rotationCenter = vec2(0.5);
|
||||
vec2 shift = dstCoord - rotationCenter;
|
||||
|
||||
float dotSize = 5.0;
|
||||
float angle = 45.0;
|
||||
|
||||
float rasterPattern = added(shift, sind(angle), cosd(angle), rotationCenter, PI / dotSize * 680.0);
|
||||
vec4 srcPixel = texture2D(u_tex0, srcCoord);
|
||||
|
||||
float avg = 0.2125 * srcPixel.r + 0.7154 * srcPixel.g + 0.0721 * srcPixel.b;
|
||||
float gray = (rasterPattern * threshold + avg - threshold) / (1.0 - threshold);
|
||||
|
||||
// uncomment to see how the raster pattern looks
|
||||
// gray = rasterPattern;
|
||||
|
||||
gl_FragColor = vec4(gray, gray, gray, 1.0);
|
||||
} else {
|
||||
st = vec2(st.x,st.y*0.5)*2.0;
|
||||
gl_FragColor = texture2D(u_tex0, st);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
<!-- Copyright 2015 Patricio Gonzalez Vivo (http://patriciogonzalezvivo.com) -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>About this Book</title>
|
||||
<meta name="keywords" content="shader,shaders,GLSL,book" />
|
||||
<meta name="description" content="This is a gentle step-by-step guide through the abstract and complex universe of Fragment Shaders." />
|
||||
|
||||
<!-- CodeMirror -->
|
||||
<link type='text/css' rel='stylesheet' href="../src/codemirror/css/codemirror.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/fold/foldgutter.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/dialog/dialog.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/hint/show-hint.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/theme/neo.css">
|
||||
<script type="text/javascript" src="../src/codemirror.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/search/searchcursor.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/search/search.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/dialog/dialog.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/edit/matchbrackets.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/edit/closebrackets.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/comment/comment.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/wrap/hardwrap.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/fold/foldcode.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/fold/brace-fold.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/keymap/sublime.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/hint/show-hint.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/mode/clike.js"></script>
|
||||
|
||||
<!-- Highlight -->
|
||||
<link type='text/css' rel='stylesheet' href="../css/github.css">
|
||||
<script type="text/javascript" src="../src/highlight.min.js"></script>
|
||||
|
||||
<!-- Marked -->
|
||||
<script type="text/javascript" src="../src/marked.js"></script>
|
||||
|
||||
<!-- My stuff -->
|
||||
<link type='text/css' rel='stylesheet' href="../css/style.css">
|
||||
<script type="text/javascript" src="../src/glslCanvas.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="header"><p><a href="http://patriciogonzalezvivo.com/2015/thebookofshaders/">The Book of Shaders</a> by <a href="http://patriciogonzalezvivo.com">Patricio Gonzalez Vivo</a></p></div>
|
||||
<hr>
|
||||
<div id="content"> </div>
|
||||
<hr>
|
||||
<ul class="navigationBar" >
|
||||
<li class="navigationBar" onclick="homePage()">< < Previous</li>
|
||||
<li class="navigationBar" onclick="homePage()"> Home </li>
|
||||
<li class="navigationBar" onclick="nextPage()">Next > ></li>
|
||||
</ul>
|
||||
<footer>
|
||||
<p> Copyright 2015 <a href="http://www.patriciogonzalezvivo.com" target="_blank">Patricio Gonzalez Vivo</a> </p>
|
||||
</footer>
|
||||
|
||||
<script type="text/javascript" src="../src/main.js" defer></script>
|
||||
<script>
|
||||
(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),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-18824436-2', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
After Width: | Height: | Size: 110 KiB |
After Width: | Height: | Size: 105 KiB |
After Width: | Height: | Size: 263 KiB |
After Width: | Height: | Size: 269 KiB |
After Width: | Height: | Size: 340 KiB |
@ -0,0 +1,71 @@
|
||||
<!-- Copyright 2015 Patricio Gonzalez Vivo (http://patriciogonzalezvivo.com) -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Introduction</title>
|
||||
<meta name="keywords" content="shader,shaders,GLSL,book,parallel,gpu,graphic cards,openGL,webGL" />
|
||||
<meta name="description" content="This is a gentle step-by-step guide through the abstract and complex universe of Fragment Shaders." />
|
||||
|
||||
<!-- CodeMirror -->
|
||||
<link type='text/css' rel='stylesheet' href="../src/codemirror/css/codemirror.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/fold/foldgutter.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/dialog/dialog.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/hint/show-hint.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/theme/neo.css">
|
||||
<script type="text/javascript" src="../src/codemirror.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/search/searchcursor.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/search/search.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/dialog/dialog.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/edit/matchbrackets.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/edit/closebrackets.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/comment/comment.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/wrap/hardwrap.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/fold/foldcode.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/fold/brace-fold.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/keymap/sublime.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/hint/show-hint.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/mode/clike.js"></script>
|
||||
|
||||
<!-- Highlight -->
|
||||
<link type='text/css' rel='stylesheet' href="../css/github.css">
|
||||
<script type="text/javascript" src="../src/highlight.min.js"></script>
|
||||
|
||||
<!-- Marked -->
|
||||
<script type="text/javascript" src="../src/marked.js"></script>
|
||||
|
||||
<!-- My stuff -->
|
||||
<link type='text/css' rel='stylesheet' href="../css/style.css">
|
||||
<script type="text/javascript" src="../src/glslCanvas.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="header"><p><a href="http://patriciogonzalezvivo.com/2015/thebookofshaders/">The Book of Shaders</a> by <a href="http://patriciogonzalezvivo.com">Patricio Gonzalez Vivo</a></p></div>
|
||||
<hr>
|
||||
<div id="content"> </div>
|
||||
<hr>
|
||||
<ul class="navigationBar" >
|
||||
<li class="navigationBar" onclick="previusPage()">< < Previous</li>
|
||||
<li class="navigationBar" onclick="homePage()"> Home </li>
|
||||
<li class="navigationBar" onclick="nextPage()">Next > ></li>
|
||||
</ul>
|
||||
|
||||
<footer>
|
||||
<p> Copyright 2015 <a href="http://www.patriciogonzalezvivo.com" target="_blank">Patricio Gonzalez Vivo</a> </p>
|
||||
</footer>
|
||||
|
||||
<script type="text/javascript" src="../src/main.js" defer></script>
|
||||
<script>
|
||||
(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),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-18824436-2', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
After Width: | Height: | Size: 674 KiB |
After Width: | Height: | Size: 155 KiB |
@ -0,0 +1,11 @@
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
gl_FragColor = vec4(1.0,0.0,1.0,1.0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,69 @@
|
||||
<!-- Copyright 2015 Patricio Gonzalez Vivo (http://patriciogonzalezvivo.com) -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Hello World</title>
|
||||
<meta name="keywords" content="shader,shaders,GLSL,book,parallel,gpu,graphic cards,openGL,webGL" />
|
||||
<meta name="description" content="This is a gentle step-by-step guide through the abstract and complex universe of Fragment Shaders." />
|
||||
|
||||
<!-- CodeMirror -->
|
||||
<link type='text/css' rel='stylesheet' href="../src/codemirror/css/codemirror.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/fold/foldgutter.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/dialog/dialog.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/hint/show-hint.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/theme/neo.css">
|
||||
<script type="text/javascript" src="../src/codemirror.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/search/searchcursor.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/search/search.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/dialog/dialog.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/edit/matchbrackets.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/edit/closebrackets.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/comment/comment.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/wrap/hardwrap.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/fold/foldcode.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/fold/brace-fold.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/keymap/sublime.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/hint/show-hint.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/mode/clike.js"></script>
|
||||
|
||||
<!-- Highlight -->
|
||||
<link type='text/css' rel='stylesheet' href="../css/github.css">
|
||||
<script type="text/javascript" src="../src/highlight.min.js"></script>
|
||||
|
||||
<!-- Marked -->
|
||||
<script type="text/javascript" src="../src/marked.js"></script>
|
||||
|
||||
<!-- My stuff -->
|
||||
<link type='text/css' rel='stylesheet' href="../css/style.css">
|
||||
<script type="text/javascript" src="../src/glslCanvas.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="header"><p><a href="http://patriciogonzalezvivo.com/2015/thebookofshaders/">The Book of Shaders</a> by <a href="http://patriciogonzalezvivo.com">Patricio Gonzalez Vivo</a></p></div>
|
||||
<hr>
|
||||
<div id="content"> </div>
|
||||
<hr>
|
||||
<ul class="navigationBar" >
|
||||
<li class="navigationBar" onclick="previusPage()">< < Previous</li>
|
||||
<li class="navigationBar" onclick="homePage()"> Home </li>
|
||||
<li class="navigationBar" onclick="nextPage()">Next > ></li>
|
||||
</ul>
|
||||
|
||||
<footer>
|
||||
<p> Copyright 2015 <a href="http://www.patriciogonzalezvivo.com" target="_blank">Patricio Gonzalez Vivo</a> </p>
|
||||
</footer>
|
||||
|
||||
<script type="text/javascript" src="../src/main.js" defer></script>
|
||||
<script>
|
||||
(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),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-18824436-2', 'auto');
|
||||
ga('send', 'pageview');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,70 @@
|
||||
<!-- Copyright 2015 Patricio Gonzalez Vivo (http://patriciogonzalezvivo.com) -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Uniforms</title>
|
||||
<meta name="keywords" content="shader,GLSL,parallel,uniforms,gl_FragCoord,gl_FragColor" />
|
||||
<meta name="description" content="This is a gentle step-by-step guide through the abstract and complex universe of Fragment Shaders." />
|
||||
|
||||
<!-- CodeMirror -->
|
||||
<link type='text/css' rel='stylesheet' href="../src/codemirror/css/codemirror.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/fold/foldgutter.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/dialog/dialog.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/hint/show-hint.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/theme/neo.css">
|
||||
<script type="text/javascript" src="../src/codemirror.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/search/searchcursor.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/search/search.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/dialog/dialog.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/edit/matchbrackets.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/edit/closebrackets.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/comment/comment.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/wrap/hardwrap.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/fold/foldcode.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/fold/brace-fold.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/keymap/sublime.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/hint/show-hint.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/mode/clike.js"></script>
|
||||
|
||||
<!-- Highlight -->
|
||||
<link type='text/css' rel='stylesheet' href="../css/github.css">
|
||||
<script type="text/javascript" src="../src/highlight.min.js"></script>
|
||||
|
||||
<!-- Marked -->
|
||||
<script type="text/javascript" src="../src/marked.js"></script>
|
||||
|
||||
<!-- My stuff -->
|
||||
<link type='text/css' rel='stylesheet' href="../css/style.css">
|
||||
<script type="text/javascript" src="../src/glslCanvas.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="header"><p><a href="http://patriciogonzalezvivo.com/2015/thebookofshaders/">The Book of Shaders</a> by <a href="http://patriciogonzalezvivo.com">Patricio Gonzalez Vivo</a></p></div>
|
||||
<hr>
|
||||
<div id="content"> </div>
|
||||
<hr>
|
||||
<ul class="navigationBar" >
|
||||
<li class="navigationBar" onclick="previusPage()">< < Previous</li>
|
||||
<li class="navigationBar" onclick="homePage()"> Home </li>
|
||||
<li class="navigationBar" onclick="nextPage()">Next > ></li>
|
||||
</ul>
|
||||
|
||||
<footer>
|
||||
<p> Copyright 2015 <a href="http://www.patriciogonzalezvivo.com" target="_blank">Patricio Gonzalez Vivo</a> </p>
|
||||
</footer>
|
||||
|
||||
<script type="text/javascript" src="../src/main.js" defer></script>
|
||||
<script>
|
||||
(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),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-18824436-2', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,12 @@
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
uniform vec2 u_resolution;
|
||||
uniform vec2 u_mouse;
|
||||
uniform float u_time;
|
||||
|
||||
void main() {
|
||||
vec2 st = gl_FragCoord.xy/u_resolution;
|
||||
gl_FragColor = vec4(st.x,st.y,0.0,1.0);
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
uniform float u_time;
|
||||
|
||||
void main() {
|
||||
gl_FragColor = vec4( abs(sin(u_time)) ,0.0,0.0,1.0);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,69 @@
|
||||
<!-- Copyright 2015 Patricio Gonzalez Vivo (http://patriciogonzalezvivo.com) -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Make your own shader tool</title>
|
||||
<meta name="keywords" content="shader,openFrameworks,processing,webgl,threejs" />
|
||||
<meta name="description" content="This is a gentle step-by-step guide through the abstract and complex universe of Fragment Shaders."/>
|
||||
|
||||
<!-- CodeMirror -->
|
||||
<link type='text/css' rel='stylesheet' href="../src/codemirror/css/codemirror.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/fold/foldgutter.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/dialog/dialog.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/hint/show-hint.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/theme/neo.css">
|
||||
<script type="text/javascript" src="../src/codemirror.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/search/searchcursor.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/search/search.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/dialog/dialog.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/edit/matchbrackets.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/edit/closebrackets.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/comment/comment.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/wrap/hardwrap.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/fold/foldcode.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/fold/brace-fold.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/keymap/sublime.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/hint/show-hint.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/mode/clike.js"></script>
|
||||
|
||||
<!-- Highlight -->
|
||||
<link type='text/css' rel='stylesheet' href="../css/github.css">
|
||||
<script type="text/javascript" src="../src/highlight.min.js"></script>
|
||||
|
||||
<!-- Marked -->
|
||||
<script type="text/javascript" src="../src/marked.js"></script>
|
||||
|
||||
<!-- My stuff -->
|
||||
<link type='text/css' rel='stylesheet' href="../css/style.css">
|
||||
<script type="text/javascript" src="../src/glslCanvas.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="header"><p><a href="http://patriciogonzalezvivo.com/2015/thebookofshaders/">The Book of Shaders</a> by <a href="http://patriciogonzalezvivo.com">Patricio Gonzalez Vivo</a></p></div>
|
||||
<hr>
|
||||
<div id="content"> </div>
|
||||
<hr>
|
||||
<ul class="navigationBar" >
|
||||
<li class="navigationBar" onclick="previusPage()">< < Previous</li>
|
||||
<li class="navigationBar" onclick="homePage()"> Home </li>
|
||||
<li class="navigationBar" onclick="nextPage()">Next > ></li>
|
||||
</ul>
|
||||
|
||||
<footer>
|
||||
<p> Copyright 2015 <a href="http://www.patriciogonzalezvivo.com" target="_blank">Patricio Gonzalez Vivo</a> </p>
|
||||
</footer>
|
||||
|
||||
<script type="text/javascript" src="../src/main.js" defer></script>
|
||||
<script>
|
||||
(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),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-18824436-2', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,15 @@
|
||||
// Author @patriciogv - 2015
|
||||
// http://patriciogonzalezvivo.com
|
||||
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
uniform vec2 u_resolution;
|
||||
uniform vec3 u_mouse;
|
||||
uniform float u_time;
|
||||
|
||||
void main() {
|
||||
vec2 st = gl_FragCoord.st/u_resolution;
|
||||
gl_FragColor = vec4(st.x,st.y,0.0,1.0);
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
#include "ofMain.h"
|
||||
#include "ofApp.h"
|
||||
|
||||
//========================================================================
|
||||
int main( ){
|
||||
// ofSetCurrentRenderer(ofGLProgrammableRenderer::TYPE);
|
||||
ofSetupOpenGL(1024,768,OF_WINDOW); // <-------- setup the GL context
|
||||
|
||||
// this kicks off the running of my app
|
||||
// can be OF_WINDOW or OF_FULLSCREEN
|
||||
// pass in width and height too:
|
||||
ofRunApp(new ofApp());
|
||||
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
// Copyright 2015 Patricio Gonzalez Vivo (http://patriciogonzalezvivo.com)
|
||||
|
||||
#include "ofApp.h"
|
||||
|
||||
//--------------------------------------------------------------
|
||||
void ofApp::setup(){
|
||||
|
||||
// Load and compile the shader
|
||||
//
|
||||
shader.load("","shader.frag");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
void ofApp::update(){
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
void ofApp::draw(){
|
||||
|
||||
// Replace the pipeline with our shader
|
||||
shader.begin();
|
||||
|
||||
// Send uniforms
|
||||
shader.setUniform1f("u_time", ofGetElapsedTimef());
|
||||
shader.setUniform2f("u_mouse", mouseX, mouseY);
|
||||
shader.setUniform2f("u_resolution", ofGetWidth(), ofGetHeight());
|
||||
|
||||
// make a billboard
|
||||
ofRect(0,0,ofGetWidth(), ofGetHeight());
|
||||
|
||||
// Default shader pipeline
|
||||
shader.end();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
void ofApp::keyPressed(int key){
|
||||
|
||||
// Reload everytime you press a key
|
||||
//
|
||||
shader.load("","shader.frag");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
void ofApp::keyReleased(int key){
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
void ofApp::mouseMoved(int x, int y ){
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
void ofApp::mouseDragged(int x, int y, int button){
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
void ofApp::mousePressed(int x, int y, int button){
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
void ofApp::mouseReleased(int x, int y, int button){
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
void ofApp::windowResized(int w, int h){
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
void ofApp::gotMessage(ofMessage msg){
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
void ofApp::dragEvent(ofDragInfo dragInfo){
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
// Copyright 2015 Patricio Gonzalez Vivo (http://patriciogonzalezvivo.com)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ofMain.h"
|
||||
|
||||
class ofApp : public ofBaseApp{
|
||||
public:
|
||||
void setup();
|
||||
void update();
|
||||
void draw();
|
||||
|
||||
void keyPressed(int key);
|
||||
void keyReleased(int key);
|
||||
void mouseMoved(int x, int y );
|
||||
void mouseDragged(int x, int y, int button);
|
||||
void mousePressed(int x, int y, int button);
|
||||
void mouseReleased(int x, int y, int button);
|
||||
void windowResized(int w, int h);
|
||||
void dragEvent(ofDragInfo dragInfo);
|
||||
void gotMessage(ofMessage msg);
|
||||
|
||||
ofShader shader;
|
||||
};
|
@ -0,0 +1,17 @@
|
||||
// Author @patriciogv - 2015
|
||||
// http://patriciogonzalezvivo.com
|
||||
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
#define PROCESSING_COLOR_SHADER
|
||||
|
||||
uniform vec2 u_resolution;
|
||||
uniform vec3 u_mouse;
|
||||
uniform float u_time;
|
||||
|
||||
void main() {
|
||||
vec2 st = gl_FragCoord.st/u_resolution;
|
||||
gl_FragColor = vec4(st.x,st.y,0.0,1.0);
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
// Copyright 2015 Patricio Gonzalez Vivo (http://patriciogonzalezvivo.com)
|
||||
|
||||
PShader shader;
|
||||
|
||||
void setup() {
|
||||
size(640, 360, P2D);
|
||||
noStroke();
|
||||
|
||||
// Load and compile shader
|
||||
shader = loadShader("shader.frag");
|
||||
}
|
||||
|
||||
void draw() {
|
||||
// Set uniforms
|
||||
shader.set("u_resolution", float(width), float(height));
|
||||
shader.set("u_mouse", float(mouseX), float(mouseY));
|
||||
shader.set("u_time", millis() / 1000.0);
|
||||
|
||||
// Replace the default pipeline programs with our shader
|
||||
shader(shader);
|
||||
|
||||
// Draw a billboard
|
||||
rect(0,0,width,height);
|
||||
}
|
||||
|
||||
void keyPressed(){
|
||||
// Reload shader everytime a key is press
|
||||
shader = loadShader("shader.frag");
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
<!-- Copyright 2015 Patricio Gonzalez Vivo (http://patriciogonzalezvivo.com) -->
|
||||
<body>
|
||||
<div id="container"></div>
|
||||
<script src="http://threejs.org/build/three.min.js"></script>
|
||||
|
||||
<script id="vertexShader" type="x-shader/x-vertex">
|
||||
void main() {
|
||||
gl_Position = vec4( position, 1.0 );
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="fragmentShader" type="x-shader/x-fragment">
|
||||
uniform vec2 u_resolution;
|
||||
uniform vec2 u_mouse;
|
||||
uniform float u_time;
|
||||
|
||||
void main() {
|
||||
vec2 st = gl_FragCoord.xy/u_resolution.xy;
|
||||
gl_FragColor=vec4(st.x,st.y,0.0,1.0);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
var container;
|
||||
var camera, scene, renderer;
|
||||
var uniforms;
|
||||
var mouse = {x:0, y:0};
|
||||
|
||||
document.onmousemove = getMouseXY;
|
||||
|
||||
init();
|
||||
animate();
|
||||
|
||||
function getMouseXY(e) {
|
||||
mouse.x = e.pageX;
|
||||
mouse.y = e.pageY;
|
||||
}
|
||||
|
||||
function init() {
|
||||
container = document.getElementById( 'container' );
|
||||
|
||||
camera = new THREE.Camera();
|
||||
camera.position.z = 1;
|
||||
|
||||
scene = new THREE.Scene();
|
||||
|
||||
var geometry = new THREE.PlaneBufferGeometry( 2, 2 );
|
||||
|
||||
uniforms = {
|
||||
u_time: { type: "f", value: 1.0 },
|
||||
u_mouse: { type: "v2", value: new THREE.Vector2() },
|
||||
u_resolution: { type: "v2", value: new THREE.Vector2() }
|
||||
};
|
||||
|
||||
var material = new THREE.ShaderMaterial( {
|
||||
uniforms: uniforms,
|
||||
vertexShader: document.getElementById( 'vertexShader' ).textContent,
|
||||
fragmentShader: document.getElementById( 'fragmentShader' ).textContent
|
||||
} );
|
||||
|
||||
var mesh = new THREE.Mesh( geometry, material );
|
||||
scene.add( mesh );
|
||||
|
||||
renderer = new THREE.WebGLRenderer();
|
||||
renderer.setPixelRatio( window.devicePixelRatio );
|
||||
|
||||
container.appendChild( renderer.domElement );
|
||||
|
||||
onWindowResize();
|
||||
window.addEventListener( 'resize', onWindowResize, false );
|
||||
}
|
||||
|
||||
function onWindowResize( event ) {
|
||||
renderer.setSize( window.innerWidth, window.innerHeight );
|
||||
uniforms.u_resolution.value.x = renderer.domElement.width;
|
||||
uniforms.u_resolution.value.y = renderer.domElement.height;
|
||||
uniforms.u_mouse.value.x = mouse.x;
|
||||
uniforms.u_mouse.value.y = mouse.y;
|
||||
}
|
||||
|
||||
function animate() {
|
||||
requestAnimationFrame( animate );
|
||||
render();
|
||||
}
|
||||
|
||||
function render() {
|
||||
uniforms.u_time.value += 0.05;
|
||||
renderer.render( scene, camera );
|
||||
}
|
||||
</script>
|
||||
</body>
|
After Width: | Height: | Size: 61 KiB |
@ -0,0 +1,34 @@
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
uniform vec2 u_resolution;
|
||||
uniform vec2 u_mouse;
|
||||
uniform float u_time;
|
||||
|
||||
// Function from Iñigo Quiles
|
||||
// www.iquilezles.org/www/articles/functions/functions.htm
|
||||
float cubicPulse( float c, float w, float x ){
|
||||
x = abs(x - c);
|
||||
if( x>w ) return 0.0;
|
||||
x /= w;
|
||||
return 1.0 - x*x*(3.0-2.0*x);
|
||||
}
|
||||
|
||||
float plot(vec2 _st, float _pct){
|
||||
return smoothstep( _pct-0.02, _pct, _st.y) -
|
||||
smoothstep( _pct, _pct+0.02, _st.y);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 st = gl_FragCoord.xy/u_resolution;
|
||||
|
||||
float y = cubicPulse(0.5,0.2,st.x);
|
||||
|
||||
vec3 color = vec3(y);
|
||||
|
||||
float pct = plot(st,y);
|
||||
color = (1.0-pct)*color+pct*vec3(0.0,1.0,0.0);
|
||||
|
||||
gl_FragColor = vec4(color,1.0);
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
#define PI 3.14159265359
|
||||
|
||||
uniform vec2 u_resolution;
|
||||
uniform vec2 u_mouse;
|
||||
uniform float u_time;
|
||||
|
||||
float plot(vec2 _st, float _pct){
|
||||
return smoothstep( _pct-0.01, _pct, _st.y) -
|
||||
smoothstep( _pct, _pct+0.01, _st.y);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 st = gl_FragCoord.xy/u_resolution;
|
||||
|
||||
float y = pow(st.x,5.0);
|
||||
|
||||
vec3 color = vec3(y);
|
||||
|
||||
float pct = plot(st,y);
|
||||
color = (1.0-pct)*color+pct*vec3(0.0,1.0,0.0);
|
||||
|
||||
gl_FragColor = vec4(color,1.0);
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
uniform vec2 u_resolution;
|
||||
uniform vec2 u_mouse;
|
||||
uniform float u_time;
|
||||
|
||||
// Function from Iñigo Quiles
|
||||
// www.iquilezles.org/www/articles/functions/functions.htm
|
||||
float expStep( float x, float k, float n ){
|
||||
return exp( -k*pow(x,n) );
|
||||
}
|
||||
|
||||
float plot(vec2 _st, float _pct){
|
||||
return smoothstep( _pct-0.01, _pct, _st.y) -
|
||||
smoothstep( _pct, _pct+0.01, _st.y);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 st = gl_FragCoord.xy/u_resolution;
|
||||
|
||||
float y = expStep(st.x,10.,1.0);
|
||||
|
||||
vec3 color = vec3(y);
|
||||
|
||||
float pct = plot(st,y);
|
||||
color = (1.0-pct)*color+pct*vec3(0.0,1.0,0.0);
|
||||
|
||||
gl_FragColor = vec4(color,1.0);
|
||||
}
|
After Width: | Height: | Size: 132 KiB |
After Width: | Height: | Size: 574 KiB |
After Width: | Height: | Size: 44 KiB |
@ -0,0 +1,32 @@
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
uniform vec2 u_resolution;
|
||||
uniform vec2 u_mouse;
|
||||
uniform float u_time;
|
||||
|
||||
// Function from Iñigo Quiles
|
||||
// www.iquilezles.org/www/articles/functions/functions.htm
|
||||
float impulse( float k, float x ){
|
||||
float h = k*x;
|
||||
return h*exp(1.0-h);
|
||||
}
|
||||
|
||||
float plot(vec2 _st, float _pct){
|
||||
return smoothstep( _pct-0.01, _pct, _st.y) -
|
||||
smoothstep( _pct, _pct+0.01, _st.y);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 st = gl_FragCoord.xy/u_resolution;
|
||||
|
||||
float y = impulse(12.,st.x);
|
||||
|
||||
vec3 color = vec3(y);
|
||||
|
||||
float pct = plot(st,y);
|
||||
color = (1.0-pct)*color+pct*vec3(0.0,1.0,0.0);
|
||||
|
||||
gl_FragColor = vec4(color,1.0);
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
<!-- Copyright 2015 Patricio Gonzalez Vivo (http://patriciogonzalezvivo.com) -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Shaping functions</title>
|
||||
<meta name="keywords" content="shaping,function,math,glsl,shader, parallel, exponent,linear,cuadratic,interpolation" />
|
||||
<meta name="description" content="This is a gentle step-by-step guide through the abstract and complex universe of Fragment Shaders."/>
|
||||
|
||||
<!-- CodeMirror -->
|
||||
<link type='text/css' rel='stylesheet' href="../src/codemirror/css/codemirror.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/fold/foldgutter.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/dialog/dialog.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/hint/show-hint.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/theme/neo.css">
|
||||
<script type="text/javascript" src="../src/codemirror.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/search/searchcursor.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/search/search.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/dialog/dialog.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/edit/matchbrackets.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/edit/closebrackets.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/comment/comment.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/wrap/hardwrap.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/fold/foldcode.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/fold/brace-fold.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/keymap/sublime.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/hint/show-hint.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/mode/clike.js"></script>
|
||||
|
||||
<!-- Highlight -->
|
||||
<link type='text/css' rel='stylesheet' href="../css/github.css">
|
||||
<script type="text/javascript" src="../src/highlight.min.js"></script>
|
||||
|
||||
<!-- Marked -->
|
||||
<script type="text/javascript" src="../src/marked.js"></script>
|
||||
|
||||
<!-- My stuff -->
|
||||
<link type='text/css' rel='stylesheet' href="../css/style.css">
|
||||
<script type="text/javascript" src="../src/glslCanvas.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="header"><p><a href="http://patriciogonzalezvivo.com/2015/thebookofshaders/">The Book of Shaders</a> by <a href="http://patriciogonzalezvivo.com">Patricio Gonzalez Vivo</a></p></div>
|
||||
<hr>
|
||||
<div id="content"> </div>
|
||||
<hr>
|
||||
<ul class="navigationBar" >
|
||||
<li class="navigationBar" onclick="previusPage()">< < Previous</li>
|
||||
<li class="navigationBar" onclick="homePage()"> Home </li>
|
||||
<!-- <li class="navigationBar" onclick="nextPage()">Next > ></li> -->
|
||||
</ul>
|
||||
|
||||
<footer>
|
||||
<p> Copyright 2015 <a href="http://www.patriciogonzalezvivo.com" target="_blank">Patricio Gonzalez Vivo</a> </p>
|
||||
</footer>
|
||||
|
||||
<script type="text/javascript" src="../src/main.js" defer></script>
|
||||
<script>
|
||||
(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),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-18824436-2', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
After Width: | Height: | Size: 42 KiB |
@ -0,0 +1,27 @@
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
uniform vec2 u_resolution;
|
||||
uniform vec2 u_mouse;
|
||||
uniform float u_time;
|
||||
|
||||
// Plot a line on Y using a value between 0.0-1.0
|
||||
float plot(vec2 _st, float _pct){
|
||||
return smoothstep( _pct-0.01, _pct, _st.y) -
|
||||
smoothstep( _pct, _pct+0.01, _st.y);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 st = gl_FragCoord.xy/u_resolution;
|
||||
|
||||
float y = st.x;
|
||||
|
||||
vec3 color = vec3(y);
|
||||
|
||||
// Plot a line
|
||||
float pct = plot(st,y);
|
||||
color = (1.0-pct)*color+pct*vec3(0.0,1.0,0.0);
|
||||
|
||||
gl_FragColor = vec4(color,1.0);
|
||||
}
|
After Width: | Height: | Size: 149 KiB |
@ -0,0 +1,30 @@
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
uniform vec2 u_resolution;
|
||||
uniform float u_time;
|
||||
|
||||
// Function from Iñigo Quiles
|
||||
// www.iquilezles.org/www/articles/functions/functions.htm
|
||||
float parabola( float x, float k ){
|
||||
return pow( 4.0*x*(1.0-x), k );
|
||||
}
|
||||
|
||||
float plot(vec2 _st, float _pct){
|
||||
return smoothstep( _pct-0.01, _pct, _st.y) -
|
||||
smoothstep( _pct, _pct+0.01, _st.y);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 st = gl_FragCoord.xy/u_resolution;
|
||||
|
||||
float y = parabola(st.x,1.0);
|
||||
|
||||
vec3 color = vec3(y);
|
||||
|
||||
float pct = plot(st,y);
|
||||
color = (1.0-pct)*color+pct*vec3(0.0,1.0,0.0);
|
||||
|
||||
gl_FragColor = vec4(color,1.0);
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
uniform vec2 u_resolution;
|
||||
uniform vec2 u_mouse;
|
||||
uniform float u_time;
|
||||
|
||||
// Function from Iñigo Quiles
|
||||
// www.iquilezles.org/www/articles/functions/functions.htm
|
||||
float pcurve( float x, float a, float b ){
|
||||
float k = pow(a+b,a+b) / (pow(a,a)*pow(b,b));
|
||||
return k * pow( x, a ) * pow( 1.0-x, b );
|
||||
}
|
||||
|
||||
float plot(vec2 _st, float _pct){
|
||||
return smoothstep( _pct-0.01, _pct, _st.y) -
|
||||
smoothstep( _pct, _pct+0.01, _st.y);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 st = gl_FragCoord.xy/u_resolution;
|
||||
|
||||
float y = pcurve(st.x,3.0,1.0);
|
||||
|
||||
vec3 color = vec3(y);
|
||||
|
||||
float pct = plot(st,y);
|
||||
color = (1.0-pct)*color+pct*vec3(0.0,1.0,0.0);
|
||||
|
||||
gl_FragColor = vec4(color,1.0);
|
||||
}
|
After Width: | Height: | Size: 273 KiB |
After Width: | Height: | Size: 379 KiB |
After Width: | Height: | Size: 173 KiB |
@ -0,0 +1,28 @@
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
#define PI 3.14159265359
|
||||
|
||||
uniform vec2 u_resolution;
|
||||
uniform vec2 u_mouse;
|
||||
uniform float u_time;
|
||||
|
||||
float plot(vec2 _st, float _pct){
|
||||
return smoothstep( _pct-0.01, _pct, _st.y) -
|
||||
smoothstep( _pct, _pct+0.01, _st.y);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 st = gl_FragCoord.xy/u_resolution;
|
||||
|
||||
// Everthins is over 0.5 will be 1.0 the rest 0.0
|
||||
float y = smoothstep(0.1,0.9,st.x);
|
||||
|
||||
vec3 color = vec3(y);
|
||||
|
||||
float pct = plot(st,y);
|
||||
color = (1.0-pct)*color+pct*vec3(0.0,1.0,0.0);
|
||||
|
||||
gl_FragColor = vec4(color,1.0);
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
#define PI 3.14159265359
|
||||
|
||||
uniform vec2 u_resolution;
|
||||
uniform float u_time;
|
||||
|
||||
float plot(vec2 _st, float _pct){
|
||||
return smoothstep( _pct-0.01, _pct, _st.y) -
|
||||
smoothstep( _pct, _pct+0.01, _st.y);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 st = gl_FragCoord.xy/u_resolution;
|
||||
|
||||
// Step will return 0.0 unless the value is over 0.5,
|
||||
// in that case will return 1.0
|
||||
float y = step(0.5,st.x);
|
||||
|
||||
vec3 color = vec3(y);
|
||||
|
||||
float pct = plot(st,y);
|
||||
color = (1.0-pct)*color+pct*vec3(0.0,1.0,0.0);
|
||||
|
||||
gl_FragColor = vec4(color,1.0);
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
<!-- Copyright 2015 Patricio Gonzalez Vivo (http://patriciogonzalezvivo.com) -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>How to read this book off-line</title>
|
||||
<meta name="keywords" content="glsl,shader,github,repository" />
|
||||
<meta name="description" content="This is a gentle step-by-step guide through the abstract and complex universe of Fragment Shaders."/>
|
||||
|
||||
<!-- CodeMirror -->
|
||||
<link type='text/css' rel='stylesheet' href="../src/codemirror/css/codemirror.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/fold/foldgutter.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/dialog/dialog.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/hint/show-hint.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/theme/neo.css">
|
||||
<script type="text/javascript" src="../src/codemirror.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/search/searchcursor.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/search/search.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/dialog/dialog.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/edit/matchbrackets.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/edit/closebrackets.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/comment/comment.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/wrap/hardwrap.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/fold/foldcode.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/fold/brace-fold.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/keymap/sublime.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/hint/show-hint.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/mode/clike.js"></script>
|
||||
|
||||
<!-- Highlight -->
|
||||
<link type='text/css' rel='stylesheet' href="../css/github.css">
|
||||
<script type="text/javascript" src="../src/highlight.min.js"></script>
|
||||
|
||||
<!-- Marked -->
|
||||
<script type="text/javascript" src="../src/marked.js"></script>
|
||||
|
||||
<!-- My stuff -->
|
||||
<link type='text/css' rel='stylesheet' href="../css/style.css">
|
||||
<script type="text/javascript" src="../src/glslCanvas.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="header"><p><a href="http://patriciogonzalezvivo.com/2015/thebookofshaders/">The Book of Shaders</a> by <a href="http://patriciogonzalezvivo.com">Patricio Gonzalez Vivo</a></p></div>
|
||||
<hr>
|
||||
<div id="content"> </div>
|
||||
<hr>
|
||||
<ul class="navigationBar" >
|
||||
<li class="navigationBar" onclick="homePage()"> Home </li>
|
||||
</ul>
|
||||
|
||||
<footer>
|
||||
<p> Copyright 2015 <a href="http://www.patriciogonzalezvivo.com" target="_blank">Patricio Gonzalez Vivo</a> </p>
|
||||
</footer>
|
||||
|
||||
<script type="text/javascript" src="../src/main.js" defer></script>
|
||||
<script>
|
||||
(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),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-18824436-2', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,22 @@
|
||||
## How to use this book in a classroom with RaspberryPi?
|
||||
|
||||
A classroom can be a hard place to teach shaders because of technical limitations. A few years ago, taking for granted that all the students would have a computer with a modern graphic card was a long shot, but not today. Thanks to the [RaspberryPi project](http://www.raspberrypi.org/) a new type of small and cheap generation of computers ($35) has found its way into classrooms. Most importantly for the purposes of this book, the [RaspberryPi](http://www.raspberrypi.org/) comes with a decent Bradcom GPU card that can be accessed directly from the console. I made a [flexible GLSL live coding tool](https://github.com/patriciogonzalezvivo/glslViewer) that runs all the examples in this book while also updating automatically the changes the user makes when they save it. By making a local copy of the repository of this book (see the above section) and having the [```glslViewer``` app installed](https://github.com/patriciogonzalezvivo/glslViewer), students can read the chapters using any console text reader (like ```less```, ```nano``` or ```vim```), run the examples (with ```glslviewer```), and modify them with their favorite text editor (like ```nano```, ```pico```, ```vi```, ```vim``` or ```emacs```).
|
||||
|
||||
To install and set this all up on the RaspberryPi after installing the OS and logging in, type the following commands:
|
||||
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get upgrade
|
||||
sudo apt-get install git-core libfreeimage
|
||||
cd ~
|
||||
git clone http://github.com/patriciogonzalezvivo/glslViewer.git
|
||||
cd glslViewer
|
||||
make
|
||||
make install
|
||||
cd ~
|
||||
git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git
|
||||
cd GLSL-Book
|
||||
```
|
||||
|
||||
At the end of each section you will find code and non-code based exercises to give to your students. They are designed to help students immediately put concepts into practice, making concrete the abstract principles of parallel programming.
|
||||
|
@ -0,0 +1,68 @@
|
||||
<!-- Copyright 2015 Patricio Gonzalez Vivo (http://patriciogonzalezvivo.com) -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Using this book with a RasbperryPi</title>
|
||||
<meta name="keywords" content="raspberry,pi,glsl,shader,github,glsViewer" />
|
||||
<meta name="description" content="This is a gentle step-by-step guide through the abstract and complex universe of Fragment Shaders."/>
|
||||
|
||||
<!-- CodeMirror -->
|
||||
<link type='text/css' rel='stylesheet' href="../src/codemirror/css/codemirror.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/fold/foldgutter.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/dialog/dialog.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/hint/show-hint.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/theme/neo.css">
|
||||
<script type="text/javascript" src="../src/codemirror.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/search/searchcursor.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/search/search.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/dialog/dialog.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/edit/matchbrackets.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/edit/closebrackets.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/comment/comment.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/wrap/hardwrap.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/fold/foldcode.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/fold/brace-fold.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/keymap/sublime.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/hint/show-hint.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/mode/clike.js"></script>
|
||||
|
||||
<!-- Highlight -->
|
||||
<link type='text/css' rel='stylesheet' href="../css/github.css">
|
||||
<script type="text/javascript" src="../src/highlight.min.js"></script>
|
||||
|
||||
<!-- Marked -->
|
||||
<script type="text/javascript" src="../src/marked.js"></script>
|
||||
|
||||
<!-- My stuff -->
|
||||
<link type='text/css' rel='stylesheet' href="../css/style.css">
|
||||
<script type="text/javascript" src="../src/glslCanvas.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="header"><p><a href="http://patriciogonzalezvivo.com/2015/thebookofshaders/">The Book of Shaders</a> by <a href="http://patriciogonzalezvivo.com">Patricio Gonzalez Vivo</a></p></div>
|
||||
<hr>
|
||||
<div id="content"> </div>
|
||||
<hr>
|
||||
<ul class="navigationBar" >
|
||||
<li class="navigationBar" onclick="homePage()"> Home </li>
|
||||
</ul>
|
||||
|
||||
<footer>
|
||||
<p> Copyright 2015 <a href="http://www.patriciogonzalezvivo.com" target="_blank">Patricio Gonzalez Vivo</a> </p>
|
||||
</footer>
|
||||
|
||||
<script type="text/javascript" src="../src/main.js" defer></script>
|
||||
<script>
|
||||
(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),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-18824436-2', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,68 @@
|
||||
<!-- Copyright 2015 Patricio Gonzalez Vivo (http://patriciogonzalezvivo.com) -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>How to print this book?</title>
|
||||
<meta name="keywords" content="glsl,shader,github,book,pdf,print" />
|
||||
<meta name="description" content="This is a gentle step-by-step guide through the abstract and complex universe of Fragment Shaders."/>
|
||||
|
||||
<!-- CodeMirror -->
|
||||
<link type='text/css' rel='stylesheet' href="../src/codemirror/css/codemirror.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/fold/foldgutter.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/dialog/dialog.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/hint/show-hint.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/theme/neo.css">
|
||||
<script type="text/javascript" src="../src/codemirror.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/search/searchcursor.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/search/search.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/dialog/dialog.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/edit/matchbrackets.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/edit/closebrackets.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/comment/comment.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/wrap/hardwrap.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/fold/foldcode.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/fold/brace-fold.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/keymap/sublime.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/hint/show-hint.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/mode/clike.js"></script>
|
||||
|
||||
<!-- Highlight -->
|
||||
<link type='text/css' rel='stylesheet' href="../css/github.css">
|
||||
<script type="text/javascript" src="../src/highlight.min.js"></script>
|
||||
|
||||
<!-- Marked -->
|
||||
<script type="text/javascript" src="../src/marked.js"></script>
|
||||
|
||||
<!-- My stuff -->
|
||||
<link type='text/css' rel='stylesheet' href="../css/style.css">
|
||||
<script type="text/javascript" src="../src/glslCanvas.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="header"><p><a href="http://patriciogonzalezvivo.com/2015/thebookofshaders/">The Book of Shaders</a> by <a href="http://patriciogonzalezvivo.com">Patricio Gonzalez Vivo</a></p></div>
|
||||
<hr>
|
||||
<div id="content"> </div>
|
||||
<hr>
|
||||
<ul class="navigationBar" >
|
||||
<li class="navigationBar" onclick="homePage()"> Home </li>
|
||||
</ul>
|
||||
|
||||
<footer>
|
||||
<p> Copyright 2015 <a href="http://www.patriciogonzalezvivo.com" target="_blank">Patricio Gonzalez Vivo</a> </p>
|
||||
</footer>
|
||||
|
||||
<script type="text/javascript" src="../src/main.js" defer></script>
|
||||
<script>
|
||||
(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),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-18824436-2', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,20 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Patricio Gonzalez Vivo ( http://www.patriciogonzalezvivo.com )
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@ -0,0 +1,71 @@
|
||||
<canvas id="custom" class="canvas" data-fragment-url="examples/moon.frag" data-textures="examples/images/moon-texture.jpg" width="400px" height="400px"></canvas>
|
||||
|
||||
# The Book of Shaders
|
||||
*by [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/)*
|
||||
|
||||
This is a gentle step-by-step guide through the abstract and complex universe of Fragment Shaders.
|
||||
|
||||
## Contents
|
||||
|
||||
* [About this book](00/)
|
||||
|
||||
* Getting started
|
||||
* [What is a shader?](01/)
|
||||
* [“Hello world!”](02/)
|
||||
* [Uniforms](03/)
|
||||
* [Running your shader](04/)
|
||||
|
||||
* Algorithmic drawing
|
||||
* [Shaping functions](05/)
|
||||
* Colors
|
||||
* Shapes
|
||||
* Matrices
|
||||
* Patterns
|
||||
|
||||
* Generative designs
|
||||
* Random
|
||||
* Noise
|
||||
* Fractional brownian motion
|
||||
|
||||
* Image processing:
|
||||
* What is a texture?
|
||||
* Image operations
|
||||
* Kernel convolutions
|
||||
* Filters
|
||||
* Others effects
|
||||
|
||||
* Simulation
|
||||
* Pingpong
|
||||
* Conway
|
||||
* Ripples
|
||||
* Water color
|
||||
* Reaction diffusion
|
||||
* Voronoi
|
||||
|
||||
* 3D graphics
|
||||
* Lights
|
||||
* Normal-maps
|
||||
* Bump-maps
|
||||
* Ray marching
|
||||
* Environmental-maps (spherical and cube)
|
||||
* Reflect and refract
|
||||
|
||||
* Appendix
|
||||
* [How can I navigate this book offline?](90/)
|
||||
* [How to use this book in a classroom with RaspberryPi?](91/)
|
||||
* [How to print this book?](92/)
|
||||
|
||||
## About the Author
|
||||
|
||||
[Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) (1982, Buenos Aires, Argentina) is a New York based artist and developer. He explores interstitial spaces between organic and synthetic, analog and digital, individual and collective. In his work he uses code as an expressive language with the intention of developing a better together.
|
||||
|
||||
Patricio studied and practiced psychotherapy and expressive art therapy. He holds an MFA in Design & Technology from Parsons The New School, where he now teaches. Currently he works as a Graphic Engineer at Mapzen making openSource mapping tools.
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
Thanks to my wife [Jen Lowe](http://www.datatelling.com/), for her unconditional support, help and time editing this book.
|
||||
|
||||
Thanks [Scott Murray](http://alignedleft.com/) for the inspiration and advice.
|
||||
|
||||
Thanks [Karim Naaji](http://karim.naaji.fr/) for contributing with support, good ideas and code.
|
||||
|
@ -0,0 +1,124 @@
|
||||
/*
|
||||
|
||||
github.com style (c) Vasily Polovnyov <vast@whiteants.net>
|
||||
|
||||
*/
|
||||
|
||||
.hljs {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
padding: 0.5em;
|
||||
color: #333;
|
||||
background: #f8f8f8;
|
||||
-webkit-text-size-adjust: none;
|
||||
}
|
||||
|
||||
.hljs-comment,
|
||||
.diff .hljs-header,
|
||||
.hljs-javadoc {
|
||||
color: #998;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.hljs-keyword,
|
||||
.css .rule .hljs-keyword,
|
||||
.hljs-winutils,
|
||||
.nginx .hljs-title,
|
||||
.hljs-subst,
|
||||
.hljs-request,
|
||||
.hljs-status {
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-number,
|
||||
.hljs-hexcolor,
|
||||
.ruby .hljs-constant {
|
||||
color: #008080;
|
||||
}
|
||||
|
||||
.hljs-string,
|
||||
.hljs-tag .hljs-value,
|
||||
.hljs-phpdoc,
|
||||
.hljs-dartdoc,
|
||||
.tex .hljs-formula {
|
||||
color: #d14;
|
||||
}
|
||||
|
||||
.hljs-title,
|
||||
.hljs-id,
|
||||
.scss .hljs-preprocessor {
|
||||
color: #900;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-list .hljs-keyword,
|
||||
.hljs-subst {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.hljs-class .hljs-title,
|
||||
.hljs-type,
|
||||
.vhdl .hljs-literal,
|
||||
.tex .hljs-command {
|
||||
color: #458;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-tag,
|
||||
.hljs-tag .hljs-title,
|
||||
.hljs-rules .hljs-property,
|
||||
.django .hljs-tag .hljs-keyword {
|
||||
color: #000080;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.hljs-attribute,
|
||||
.hljs-variable,
|
||||
.lisp .hljs-body {
|
||||
color: #008080;
|
||||
}
|
||||
|
||||
.hljs-regexp {
|
||||
color: #009926;
|
||||
}
|
||||
|
||||
.hljs-symbol,
|
||||
.ruby .hljs-symbol .hljs-string,
|
||||
.lisp .hljs-keyword,
|
||||
.clojure .hljs-keyword,
|
||||
.scheme .hljs-keyword,
|
||||
.tex .hljs-special,
|
||||
.hljs-prompt {
|
||||
color: #990073;
|
||||
}
|
||||
|
||||
.hljs-built_in {
|
||||
color: #0086b3;
|
||||
}
|
||||
|
||||
.hljs-preprocessor,
|
||||
.hljs-pragma,
|
||||
.hljs-pi,
|
||||
.hljs-doctype,
|
||||
.hljs-shebang,
|
||||
.hljs-cdata {
|
||||
color: #999;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-deletion {
|
||||
background: #fdd;
|
||||
}
|
||||
|
||||
.hljs-addition {
|
||||
background: #dfd;
|
||||
}
|
||||
|
||||
.diff .hljs-change {
|
||||
background: #0086b3;
|
||||
}
|
||||
|
||||
.hljs-chunk {
|
||||
color: #aaa;
|
||||
}
|
@ -0,0 +1,256 @@
|
||||
/* Copyright 2015 Patricio Gonzalez Vivo ( http://patriciogonzalezvivo.com )
|
||||
|
||||
Based CSS for alignedleft.com
|
||||
Design and code copyright 2011-2012 Scott Murray
|
||||
*/
|
||||
body {
|
||||
font-family: Baskerville, "Times New Roman", serif;
|
||||
font-size: 20px;
|
||||
line-height: 1.3;
|
||||
padding: 0;
|
||||
color: #222;
|
||||
margin-bottom: 60px;
|
||||
margin-left: 60px;
|
||||
margin-right: 60px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 46px;
|
||||
font-style: italic;
|
||||
line-height: 0px;
|
||||
margin-top: 60px;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 34px;
|
||||
font-style: italic;
|
||||
line-height: 0px;
|
||||
margin-top: 60px;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 28px;
|
||||
line-height: 18px;
|
||||
margin-top: 24px;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin-top: 24px;
|
||||
margin-left: 10px;
|
||||
margin-bottom: 10px;
|
||||
font-size: 24px;
|
||||
line-height: 12px;
|
||||
font-weight: normal;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
h1, h2, h3 {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
#content {
|
||||
width: 800px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #555;
|
||||
border-bottom: 1px solid #ccc;
|
||||
-webkit-transition: all ease-out 0.2s;
|
||||
}
|
||||
|
||||
img {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
border-radius: 6px;
|
||||
max-width: 520px;
|
||||
}
|
||||
|
||||
.imgcontainer {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
max-width: 520px;
|
||||
}
|
||||
|
||||
.caption {
|
||||
/*font-family: Baskerville, "Times New Roman", serif;*/
|
||||
font-style: italic;
|
||||
font-size: 16px;
|
||||
line-height: 1.3;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.header {
|
||||
/*font-family: Baskerville, "Times New Roman", serif;*/
|
||||
/*font-style: italic;*/
|
||||
font-size: 16px;
|
||||
line-height: 0px;
|
||||
margin-top: 60px;
|
||||
text-align: right;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.header a{
|
||||
font-size: 18px;
|
||||
font-style: italic;
|
||||
text-decoration: none;
|
||||
border:0!important;
|
||||
|
||||
}
|
||||
|
||||
a:hover, a:visited, a:link, a:active {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
footer {
|
||||
clear: both;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 200;
|
||||
text-align: right;
|
||||
color: #222222;
|
||||
}
|
||||
|
||||
.navigationBar {
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
cursor: hand;
|
||||
}
|
||||
|
||||
li.navigationBar {
|
||||
list-style-type: none;
|
||||
display: inline;
|
||||
margin: 20px;
|
||||
font-size: 24px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
|
||||
/* Regular code blocks
|
||||
----------------------------------
|
||||
*/
|
||||
|
||||
code {
|
||||
font-family: monospace;
|
||||
font-size: 16px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.lang-bash {
|
||||
background-color: #ECECEC;
|
||||
display: block;
|
||||
|
||||
font-size: 14px;
|
||||
line-height: 1.5em;
|
||||
|
||||
padding: 15px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.lang-glsl {
|
||||
background-color: #ECECEC;
|
||||
|
||||
font-size: 14px;
|
||||
line-height: 1.5em;
|
||||
|
||||
padding: 15px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.lang-cpp {
|
||||
background-color: #ECECEC;
|
||||
|
||||
font-size: 14px;
|
||||
line-height: 1.5em;
|
||||
|
||||
padding: 15px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.lang-html {
|
||||
background-color: #ECECEC;
|
||||
|
||||
font-size: 14px;
|
||||
line-height: 1.5em;
|
||||
|
||||
padding: 15px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.lang-processing {
|
||||
background-color: #ECECEC;
|
||||
|
||||
font-size: 14px;
|
||||
line-height: 1.5em;
|
||||
|
||||
padding: 15px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
/* Interactive GLSL Canvas
|
||||
---------------------------------
|
||||
*/
|
||||
|
||||
canvas {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
border-radius: 6px;
|
||||
max-width: 700px;
|
||||
overflow: hidden;
|
||||
-webkit-mask-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC); /* this fixes the overflow:hidden in Chrome/Opera */
|
||||
}
|
||||
|
||||
.codeAndCanvas {
|
||||
background-color: #ECECEC;
|
||||
border-radius: 10px;
|
||||
height:auto;
|
||||
clear:both;
|
||||
}
|
||||
|
||||
.codeAndCanvas canvas {
|
||||
float: right;
|
||||
border-radius: 10px;
|
||||
z-index: 1;
|
||||
overflow: hidden;
|
||||
-webkit-mask-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC); /* this fixes the overflow:hidden in Chrome/Opera */
|
||||
}
|
||||
|
||||
.CodeMirror {
|
||||
background: #ECECEC;
|
||||
font-size: 14px;
|
||||
line-height: 1.5em;
|
||||
border-radius: 10px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.simpleFunction canvas {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
border-radius: 6px;
|
||||
max-width: 700px;
|
||||
|
||||
overflow: hidden;
|
||||
-webkit-mask-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC); /* this fixes the overflow:hidden in Chrome/Opera */
|
||||
}
|
||||
|
||||
.simpleFunction .CodeMirror {
|
||||
background: #F9F9F9;
|
||||
font-size: 14px;
|
||||
line-height: 1.5em;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
border-radius: 6px;
|
||||
max-width: 700px;
|
||||
}
|
@ -0,0 +1,180 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>GLSL Shader Code Editor</title>
|
||||
|
||||
<!-- CodeMirror -->
|
||||
<link type='text/css' rel='stylesheet' href="src/codemirror/css/codemirror.css">
|
||||
<link type='text/css' rel="stylesheet" href="src/codemirror/addon/fold/foldgutter.css">
|
||||
<link type='text/css' rel="stylesheet" href="src/codemirror/addon/dialog/dialog.css">
|
||||
<link type='text/css' rel="stylesheet" href="src/codemirror/addon/hint/show-hint.css">
|
||||
<link type='text/css' rel="stylesheet" href="src/codemirror/theme/monokai.css">
|
||||
|
||||
<script type="text/javascript" src="src/codemirror.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/search/searchcursor.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/search/search.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/dialog/dialog.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/edit/matchbrackets.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/edit/closebrackets.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/comment/comment.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/wrap/hardwrap.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/fold/foldcode.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/fold/brace-fold.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/keymap/sublime.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/hint/show-hint.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/mode/clike.js"></script>
|
||||
|
||||
<!-- GLSL Canvas -->
|
||||
<script type="text/javascript" src="src/glslCanvas.js"></script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
background: #272822;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: white;
|
||||
font-family: Courier, Arial;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-size: 130%;
|
||||
}
|
||||
|
||||
canvas.right {
|
||||
position: fixed;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
background-color: #fff;
|
||||
border-radius: 15px;
|
||||
overflow: hidden;
|
||||
-webkit-mask-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC);
|
||||
}
|
||||
|
||||
.CodeMirror {
|
||||
font-size: 110%;
|
||||
line-height: 1.3;
|
||||
right: 10px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.CodeMirror-linenumbers {
|
||||
padding: 0 8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="title" >FILE NAME.frag</h1>
|
||||
<div id="editor"></div>
|
||||
<canvas id="canvas" class="right" width="500" height="500"></canvas>
|
||||
<script type="text/javascript">
|
||||
window.addEventListener("hashchange", function () {
|
||||
loadTag()
|
||||
}, false);
|
||||
|
||||
var imgs = [];
|
||||
|
||||
function removeElementsByClass(className){
|
||||
var elements = document.getElementsByClassName(className);
|
||||
while(elements.length > 0){
|
||||
elements[0].parentNode.removeChild(elements[0]);
|
||||
}
|
||||
}
|
||||
|
||||
function loadTag(){
|
||||
var fragShader = "";
|
||||
var fragFile = "";
|
||||
|
||||
while(imgs.length > 0) {
|
||||
imgs.pop();
|
||||
}
|
||||
|
||||
removeElementsByClass("CodeMirror");
|
||||
|
||||
if( window.location.hash === "" ){
|
||||
fragShader = "#ifdef GL_ES\n\
|
||||
precision mediump float;\n\
|
||||
#endif\n\
|
||||
\n\
|
||||
uniform vec2 u_resolution;\n\
|
||||
uniform vec2 u_mouse;\n\
|
||||
uniform float u_time;\n\
|
||||
\n\
|
||||
void main(){\n\
|
||||
vec2 st = gl_FragCoord.xy/u_resolution.xy;\n\
|
||||
gl_FragColor = vec4(st.x,st.y,0.0,1.0);\n\
|
||||
}";
|
||||
} else {
|
||||
var hashes = location.hash.split('&');
|
||||
|
||||
for(i in hashes){
|
||||
var ext = hashes[i].substr(hashes[i].lastIndexOf('.') + 1);
|
||||
var name = hashes[i];
|
||||
|
||||
// Extract hash if is present
|
||||
if(name.search("#") === 0){
|
||||
name = name.substr(1);
|
||||
}
|
||||
|
||||
if(ext == "frag"){
|
||||
fragFile = name;
|
||||
fragShader = fetchHTTP(fragFile);
|
||||
} else if (ext == "png" || ext == "jpg" || ext == "PNG" || ext == "JPG" ){
|
||||
imgs.push(hashes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var demoTitle = document.getElementById("title");
|
||||
if(demoTitle){
|
||||
demoTitle.innerText = fragFile;
|
||||
}
|
||||
|
||||
var demoCanvas = document.getElementById("canvas");
|
||||
if(demoCanvas && fragShader !== ""){
|
||||
demoCanvas.setAttribute("data-fragment", fragShader);
|
||||
console.log("data-fragment: " + fragFile);
|
||||
|
||||
if(imgs.length > 0){
|
||||
var textureList = "";
|
||||
for(i in imgs){
|
||||
textureList += imgs[i];
|
||||
textureList += (i < imgs.length-1)?",":"";
|
||||
}
|
||||
demoCanvas.setAttribute("data-textures",textureList);
|
||||
console.log("data-textures: " + textureList);
|
||||
}
|
||||
loadShaders();
|
||||
}
|
||||
|
||||
var demoEditor = document.getElementById("editor");
|
||||
if(demoEditor){
|
||||
var editor = CodeMirror(demoEditor,{
|
||||
value: fragShader,
|
||||
lineNumbers: true,
|
||||
matchBrackets: true,
|
||||
mode: "x-shader/x-fragment",
|
||||
keyMap: "sublime",
|
||||
autoCloseBrackets: true,
|
||||
extraKeys: {"Ctrl-Space": "autocomplete"},
|
||||
showCursorWhenSelecting: true,
|
||||
theme: "monokai",
|
||||
indentUnit: 4
|
||||
});
|
||||
|
||||
editor.on("change", function() {
|
||||
demoCanvas.setAttribute("data-fragment", editor.getValue());
|
||||
loadShaders();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
window.onload = function () {
|
||||
loadTag();
|
||||
renderShaders();
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,2 @@
|
||||
# List of Examples
|
||||
|
After Width: | Height: | Size: 353 KiB |
@ -0,0 +1,65 @@
|
||||
<!-- Copyright 2015 Patricio Gonzalez Vivo (http://patriciogonzalezvivo.com) -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Examples</title>
|
||||
<meta name="keywords" content="shader,GLSL,examples" />
|
||||
<meta name="description" content="This is a gentle step-by-step guide through the abstract and complex universe of Fragment Shaders."/>
|
||||
|
||||
<!-- CodeMirror -->
|
||||
<link type='text/css' rel='stylesheet' href="../src/codemirror/css/codemirror.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/fold/foldgutter.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/dialog/dialog.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/addon/hint/show-hint.css">
|
||||
<link type='text/css' rel="stylesheet" href="../src/codemirror/theme/neo.css">
|
||||
<script type="text/javascript" src="../src/codemirror.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/search/searchcursor.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/search/search.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/dialog/dialog.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/edit/matchbrackets.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/edit/closebrackets.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/comment/comment.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/wrap/hardwrap.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/fold/foldcode.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/fold/brace-fold.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/keymap/sublime.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/addon/hint/show-hint.js"></script>
|
||||
<script type="text/javascript" src="../src/codemirror/mode/clike.js"></script>
|
||||
|
||||
<!-- Highlight -->
|
||||
<link type='text/css' rel='stylesheet' href="../css/github.css">
|
||||
<script type="text/javascript" src="../src/highlight.min.js"></script>
|
||||
|
||||
<!-- Marked -->
|
||||
<script type="text/javascript" src="../src/marked.js"></script>
|
||||
|
||||
<!-- My stuff -->
|
||||
<link type='text/css' rel='stylesheet' href="../css/style.css">
|
||||
<script type="text/javascript" src="../src/glslCanvas.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="header"><p><a href="http://patriciogonzalezvivo.com/2015/thebookofshaders/">The Book of Shaders</a> by <a href="http://patriciogonzalezvivo.com">Patricio Gonzalez Vivo</a></p></div>
|
||||
<hr>
|
||||
<div id="content"> </div>
|
||||
<hr>
|
||||
|
||||
<footer>
|
||||
<p> Copyright 2015 <a href="http://www.patriciogonzalezvivo.com" target="_blank">Patricio Gonzalez Vivo</a> </p>
|
||||
</footer>
|
||||
|
||||
<script type="text/javascript" src="../src/main.js" defer></script>
|
||||
<script>
|
||||
(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),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-18824436-2', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,77 @@
|
||||
// Author @patriciogv - 2015
|
||||
// http://patriciogonzalezvivo.com
|
||||
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
#define PI 3.1415926535
|
||||
#define HALF_PI 1.57079632679
|
||||
|
||||
uniform vec2 u_resolution;
|
||||
uniform float u_time;
|
||||
|
||||
uniform sampler2D u_tex0;
|
||||
uniform vec2 u_tex0Resolution;
|
||||
|
||||
float speedMoon = 0.01;
|
||||
float speedSun = 0.25;
|
||||
|
||||
vec3 sphereNormals(in vec2 uv) {
|
||||
uv = fract(uv)*2.0-1.0;
|
||||
vec3 ret;
|
||||
ret.xy = sqrt(uv * uv) * sign(uv);
|
||||
ret.z = sqrt(abs(1.0 - dot(ret.xy,ret.xy)));
|
||||
ret = ret * 0.5 + 0.5;
|
||||
return mix(vec3(0.0), ret, smoothstep(1.0,0.98,dot(uv,uv)) );
|
||||
}
|
||||
|
||||
vec2 sphereCoords(vec2 _st, float _scale){
|
||||
float maxFactor = sin(1.570796327);
|
||||
vec2 uv = vec2(0.0);
|
||||
vec2 xy = 2.0 * _st.xy - 1.0;
|
||||
float d = length(xy);
|
||||
if (d < (2.0-maxFactor)){
|
||||
d = length(xy * maxFactor);
|
||||
float z = sqrt(1.0 - d * d);
|
||||
float r = atan(d, z) / 3.1415926535 * _scale;
|
||||
float phi = atan(xy.y, xy.x);
|
||||
|
||||
uv.x = r * cos(phi) + 0.5;
|
||||
uv.y = r * sin(phi) + 0.5;
|
||||
} else {
|
||||
uv = _st.xy;
|
||||
}
|
||||
return uv;
|
||||
}
|
||||
|
||||
vec4 sphereTexture(in sampler2D _tex, in vec2 _uv) {
|
||||
vec2 st = sphereCoords(_uv, 1.0);
|
||||
|
||||
float aspect = u_tex0Resolution.y/u_tex0Resolution.x;
|
||||
st.x = fract(st.x*aspect + u_time*speedMoon);
|
||||
|
||||
return texture2D(_tex, st);
|
||||
}
|
||||
|
||||
void main(){
|
||||
vec2 st = gl_FragCoord.xy/u_resolution.xy;
|
||||
vec3 color = vec3(1.0);
|
||||
|
||||
color *= sphereTexture(u_tex0, st).rgb;
|
||||
|
||||
// Calculate sun direction
|
||||
vec3 sunPos = normalize(vec3(cos(u_time*speedSun-HALF_PI),0.0,sin(speedSun*u_time-HALF_PI)));
|
||||
vec3 surface = normalize(sphereNormals(st)*2.0-1.0);
|
||||
|
||||
// Add Shadows
|
||||
color *= dot(sunPos,surface);
|
||||
|
||||
// Blend black the edge of the sphere
|
||||
float radius = 1.0-length( vec2(0.5)-st )*2.0;
|
||||
color *= smoothstep(0.001,0.05,radius);
|
||||
|
||||
color = 1.0-color;
|
||||
|
||||
gl_FragColor = vec4(color,1.0);
|
||||
}
|
@ -0,0 +1,211 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>GLSL Shader Code Editor</title>
|
||||
|
||||
<!-- CodeMirror -->
|
||||
<link type='text/css' rel='stylesheet' href="src/codemirror/css/codemirror.css">
|
||||
<link type='text/css' rel="stylesheet" href="src/codemirror/addon/fold/foldgutter.css">
|
||||
<link type='text/css' rel="stylesheet" href="src/codemirror/addon/dialog/dialog.css">
|
||||
<link type='text/css' rel="stylesheet" href="src/codemirror/addon/hint/show-hint.css">
|
||||
<link type='text/css' rel="stylesheet" href="src/codemirror/theme/neo.css">
|
||||
|
||||
<script type="text/javascript" src="src/codemirror.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/search/searchcursor.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/search/search.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/dialog/dialog.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/edit/matchbrackets.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/edit/closebrackets.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/comment/comment.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/wrap/hardwrap.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/fold/foldcode.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/fold/brace-fold.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/keymap/sublime.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/hint/show-hint.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/mode/clike.js"></script>
|
||||
|
||||
<!-- GLSL Canvas -->
|
||||
<script type="text/javascript" src="src/glslCanvas.js"></script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
background: #FFFFFF;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-size: 130%;
|
||||
}
|
||||
|
||||
canvas {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
border-radius: 6px;
|
||||
max-width: 800px;
|
||||
|
||||
overflow: hidden;
|
||||
-webkit-mask-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC);
|
||||
}
|
||||
|
||||
.CodeMirror {
|
||||
background: #ECECEC;
|
||||
font-size: 14px;
|
||||
line-height: 1.5em;
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
border-radius: 6px;
|
||||
max-width: 700px;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="canvas" class="center" width="800" height="320"></canvas>
|
||||
<div id="editor"></div>
|
||||
<script type="text/javascript">
|
||||
// Graph plotter function take from
|
||||
// From http://blog.hvidtfeldts.net/index.php/2011/07/plotting-high-frequency-functions-using-a-gpu/
|
||||
var preFunction = "\n\
|
||||
#ifdef GL_ES\n\
|
||||
precision mediump float;\n\
|
||||
#endif\n\
|
||||
\n\
|
||||
#define PI 3.14159265359\n\
|
||||
\n\
|
||||
uniform vec2 u_resolution;\n\
|
||||
uniform vec2 u_mouse;\n\
|
||||
uniform float u_time;\n\
|
||||
\n\
|
||||
float lineJitter = 0.5;\n\
|
||||
float lineWidth = 7.0;\n\
|
||||
float gridWidth = 1.7;\n\
|
||||
float scale = 0.0013;\n\
|
||||
float zoom = 2.5;\n\
|
||||
vec2 offset = vec2(0.5);\n\
|
||||
\n";
|
||||
|
||||
var postFunction = "\n\
|
||||
float rand(vec2 co){\n\
|
||||
return fract(sin(dot(co.xy,vec2(12.9898,78.233)))*43758.5453);\n\
|
||||
}\n\
|
||||
\n\
|
||||
vec3 plot2D(in vec2 _st, in float _width ) {\n\
|
||||
const float samples = 3.0;\n\
|
||||
\n\
|
||||
vec2 steping = _width*vec2(scale)/samples;\n\
|
||||
\n\
|
||||
float count = 0.0;\n\
|
||||
float mySamples = 0.0;\n\
|
||||
for (float i = 0.0; i < samples; i++) {\n\
|
||||
for (float j = 0.0;j < samples; j++) {\n\
|
||||
if (i*i+j*j>samples*samples) \n\
|
||||
continue;\n\
|
||||
mySamples++;\n\
|
||||
float ii = i + lineJitter*rand(vec2(_st.x+ i*steping.x,_st.y+ j*steping.y));\n\
|
||||
float jj = j + lineJitter*rand(vec2(_st.y + i*steping.x,_st.x+ j*steping.y));\n\
|
||||
float f = function(_st.x+ ii*steping.x)-(_st.y+ jj*steping.y);\n\
|
||||
count += (f>0.) ? 1.0 : -1.0;\n\
|
||||
}\n\
|
||||
}\n\
|
||||
vec3 color = vec3(1.0);\n\
|
||||
if (abs(count)!=mySamples)\n\
|
||||
color = vec3(abs(float(count))/float(mySamples));\n\
|
||||
return color;\n\
|
||||
}\n\
|
||||
\n\
|
||||
vec3 grid2D( in vec2 _st, in float _width ) {\n\
|
||||
float axisDetail = _width*scale;\n\
|
||||
if (abs(_st.x)<axisDetail || abs(_st.y)<axisDetail) \n\
|
||||
return 1.0-vec3(0.65,0.65,1.0);\n\
|
||||
if (abs(mod(_st.x,1.0))<axisDetail || abs(mod(_st.y,1.0))<axisDetail) \n\
|
||||
return 1.0-vec3(0.80,0.80,1.0);\n\
|
||||
if (abs(mod(_st.x,0.25))<axisDetail || abs(mod(_st.y,0.25))<axisDetail) \n\
|
||||
return 1.0-vec3(0.95,0.95,1.0);\n\
|
||||
return vec3(0.0);\n\
|
||||
}\n\
|
||||
\n\
|
||||
void main(){\n\
|
||||
vec2 st = (gl_FragCoord.xy/u_resolution.xy)-offset;\n\
|
||||
st.x *= u_resolution.x/u_resolution.y;\n\
|
||||
\n\
|
||||
scale *= zoom;\n\
|
||||
st *= zoom;\n\
|
||||
\n\
|
||||
vec3 color = plot2D(st,lineWidth);\n\
|
||||
color -= grid2D(st,gridWidth);\n\
|
||||
\n\
|
||||
gl_FragColor = vec4(color,1.0);\n\
|
||||
}";
|
||||
|
||||
window.addEventListener("hashchange", function () {
|
||||
loadFunction()
|
||||
}, false);
|
||||
|
||||
function removeElementsByClass(className){
|
||||
var elements = document.getElementsByClassName(className);
|
||||
while(elements.length > 0){
|
||||
elements[0].parentNode.removeChild(elements[0]);
|
||||
}
|
||||
}
|
||||
|
||||
function loadFunction(){
|
||||
|
||||
var func = "\n\
|
||||
float function(in float x) {\n\
|
||||
float y = 0.0;\n\
|
||||
";
|
||||
|
||||
var hash = ""
|
||||
if (window.location.hash !== ""){
|
||||
hash = location.hash;
|
||||
if(hash.search("#") === 0){
|
||||
hash = hash.substr(1);
|
||||
}
|
||||
}
|
||||
|
||||
if(hash === ""){
|
||||
hash = "y = x;"
|
||||
}
|
||||
|
||||
func += hash +"\n\
|
||||
return y;\n\
|
||||
}\n"
|
||||
|
||||
removeElementsByClass("CodeMirror");
|
||||
|
||||
var demoCanvas = document.getElementById("canvas");
|
||||
if(demoCanvas){
|
||||
demoCanvas.setAttribute("data-fragment", preFunction + func + postFunction);
|
||||
loadShaders();
|
||||
}
|
||||
|
||||
var demoEditor = document.getElementById("editor");
|
||||
if(demoEditor){
|
||||
var editor = CodeMirror(demoEditor,{
|
||||
value: func,
|
||||
lineNumbers: false,
|
||||
matchBrackets: true,
|
||||
mode: "x-shader/x-fragment",
|
||||
keyMap: "sublime",
|
||||
autoCloseBrackets: true,
|
||||
extraKeys: {"Ctrl-Space": "autocomplete"},
|
||||
showCursorWhenSelecting: true,
|
||||
indentUnit: 4
|
||||
});
|
||||
|
||||
editor.on("change", function() {
|
||||
demoCanvas.setAttribute("data-fragment", preFunction + editor.getValue() + postFunction);
|
||||
loadShaders();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
window.onload = function () {
|
||||
loadFunction();
|
||||
renderShaders();
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,60 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>GLSL Book</title>
|
||||
<meta name="keywords" content="shader,shaders,GLSL,book,pixel,fragment,uniform,texture,procedural,generative,matrix,random,noise" />
|
||||
<meta name="description" content="This is a gentle step-by-step guide through the abstract and complex universe of Fragment Shaders." />
|
||||
|
||||
<!-- CodeMirror -->
|
||||
<link type='text/css' rel='stylesheet' href="src/codemirror/css/codemirror.css">
|
||||
<link type='text/css' rel="stylesheet" href="src/codemirror/addon/fold/foldgutter.css">
|
||||
<link type='text/css' rel="stylesheet" href="src/codemirror/addon/dialog/dialog.css">
|
||||
<link type='text/css' rel="stylesheet" href="src/codemirror/addon/hint/show-hint.css">
|
||||
<link type='text/css' rel="stylesheet" href="src/codemirror/theme/neo.css">
|
||||
<script type="text/javascript" src="src/codemirror.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/search/searchcursor.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/search/search.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/dialog/dialog.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/edit/matchbrackets.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/edit/closebrackets.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/comment/comment.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/wrap/hardwrap.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/fold/foldcode.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/fold/brace-fold.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/keymap/sublime.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/addon/hint/show-hint.js"></script>
|
||||
<script type="text/javascript" src="src/codemirror/mode/clike.js"></script>
|
||||
|
||||
<!-- Highlight -->
|
||||
<link type='text/css' rel='stylesheet' href="css/github.css">
|
||||
<script type="text/javascript" src="src/highlight.min.js"></script>
|
||||
|
||||
<!-- Marked -->
|
||||
<script type="text/javascript" src="src/marked.js"></script>
|
||||
|
||||
<!-- My stuff -->
|
||||
<link type='text/css' rel='stylesheet' href="css/style.css">
|
||||
<script type="text/javascript" src="src/glslCanvas.js"></script>
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content"> </div>
|
||||
|
||||
<footer>
|
||||
<p> Copyright 2015 <a href="http://www.patriciogonzalezvivo.com" target="_blank">Patricio Gonzalez Vivo</a> </p>
|
||||
</footer>
|
||||
|
||||
<script type="text/javascript" src="src/main.js" defer></script>
|
||||
<script>
|
||||
(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),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-18824436-2', 'auto');
|
||||
ga('send', 'pageview');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,9 @@
|
||||
default: clean all
|
||||
|
||||
clean:
|
||||
rm -rf */tmp.md
|
||||
rm -rf */tmp*.png
|
||||
rm -rf book.*
|
||||
|
||||
all:
|
||||
python src/parseBook.py
|
@ -0,0 +1,183 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
var noOptions = {};
|
||||
var nonWS = /[^\s\u00a0]/;
|
||||
var Pos = CodeMirror.Pos;
|
||||
|
||||
function firstNonWS(str) {
|
||||
var found = str.search(nonWS);
|
||||
return found == -1 ? 0 : found;
|
||||
}
|
||||
|
||||
CodeMirror.commands.toggleComment = function(cm) {
|
||||
var minLine = Infinity, ranges = cm.listSelections(), mode = null;
|
||||
for (var i = ranges.length - 1; i >= 0; i--) {
|
||||
var from = ranges[i].from(), to = ranges[i].to();
|
||||
if (from.line >= minLine) continue;
|
||||
if (to.line >= minLine) to = Pos(minLine, 0);
|
||||
minLine = from.line;
|
||||
if (mode == null) {
|
||||
if (cm.uncomment(from, to)) mode = "un";
|
||||
else { cm.lineComment(from, to); mode = "line"; }
|
||||
} else if (mode == "un") {
|
||||
cm.uncomment(from, to);
|
||||
} else {
|
||||
cm.lineComment(from, to);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CodeMirror.defineExtension("lineComment", function(from, to, options) {
|
||||
if (!options) options = noOptions;
|
||||
var self = this, mode = self.getModeAt(from);
|
||||
var commentString = options.lineComment || mode.lineComment;
|
||||
if (!commentString) {
|
||||
if (options.blockCommentStart || mode.blockCommentStart) {
|
||||
options.fullLines = true;
|
||||
self.blockComment(from, to, options);
|
||||
}
|
||||
return;
|
||||
}
|
||||
var firstLine = self.getLine(from.line);
|
||||
if (firstLine == null) return;
|
||||
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 blankLines = options.commentBlankLines || from.line == to.line;
|
||||
|
||||
self.operation(function() {
|
||||
if (options.indent) {
|
||||
var baseString = firstLine.slice(0, firstNonWS(firstLine));
|
||||
for (var i = from.line; i < end; ++i) {
|
||||
var line = self.getLine(i), cut = baseString.length;
|
||||
if (!blankLines && !nonWS.test(line)) continue;
|
||||
if (line.slice(0, cut) != baseString) cut = firstNonWS(line);
|
||||
self.replaceRange(baseString + commentString + pad, Pos(i, 0), Pos(i, cut));
|
||||
}
|
||||
} else {
|
||||
for (var i = from.line; i < end; ++i) {
|
||||
if (blankLines || nonWS.test(self.getLine(i)))
|
||||
self.replaceRange(commentString + pad, Pos(i, 0));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension("blockComment", function(from, to, options) {
|
||||
if (!options) options = noOptions;
|
||||
var self = this, mode = self.getModeAt(from);
|
||||
var startString = options.blockCommentStart || mode.blockCommentStart;
|
||||
var endString = options.blockCommentEnd || mode.blockCommentEnd;
|
||||
if (!startString || !endString) {
|
||||
if ((options.lineComment || mode.lineComment) && options.fullLines != false)
|
||||
self.lineComment(from, to, options);
|
||||
return;
|
||||
}
|
||||
|
||||
var end = Math.min(to.line, self.lastLine());
|
||||
if (end != from.line && to.ch == 0 && nonWS.test(self.getLine(end))) --end;
|
||||
|
||||
var pad = options.padding == null ? " " : options.padding;
|
||||
if (from.line > end) return;
|
||||
|
||||
self.operation(function() {
|
||||
if (options.fullLines != false) {
|
||||
var lastLineHasText = nonWS.test(self.getLine(end));
|
||||
self.replaceRange(pad + endString, Pos(end));
|
||||
self.replaceRange(startString + pad, Pos(from.line, 0));
|
||||
var lead = options.blockCommentLead || mode.blockCommentLead;
|
||||
if (lead != null) for (var i = from.line + 1; i <= end; ++i)
|
||||
if (i != end || lastLineHasText)
|
||||
self.replaceRange(lead + pad, Pos(i, 0));
|
||||
} else {
|
||||
self.replaceRange(endString, to);
|
||||
self.replaceRange(startString, from);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension("uncomment", function(from, to, options) {
|
||||
if (!options) options = noOptions;
|
||||
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);
|
||||
|
||||
// Try finding line comments
|
||||
var lineString = options.lineComment || mode.lineComment, lines = [];
|
||||
var pad = options.padding == null ? " " : options.padding, didSomething;
|
||||
lineComment: {
|
||||
if (!lineString) break lineComment;
|
||||
for (var i = start; i <= end; ++i) {
|
||||
var line = self.getLine(i);
|
||||
var found = line.indexOf(lineString);
|
||||
if (found > -1 && !/comment/.test(self.getTokenTypeAt(Pos(i, found + 1)))) found = -1;
|
||||
if (found == -1 && (i != end || i == start) && nonWS.test(line)) break lineComment;
|
||||
if (found > -1 && nonWS.test(line.slice(0, found))) break lineComment;
|
||||
lines.push(line);
|
||||
}
|
||||
self.operation(function() {
|
||||
for (var i = start; i <= end; ++i) {
|
||||
var line = lines[i - start];
|
||||
var pos = line.indexOf(lineString), endPos = pos + lineString.length;
|
||||
if (pos < 0) continue;
|
||||
if (line.slice(endPos, endPos + pad.length) == pad) endPos += pad.length;
|
||||
didSomething = true;
|
||||
self.replaceRange("", Pos(i, pos), Pos(i, endPos));
|
||||
}
|
||||
});
|
||||
if (didSomething) return true;
|
||||
}
|
||||
|
||||
// Try block comments
|
||||
var startString = options.blockCommentStart || mode.blockCommentStart;
|
||||
var endString = options.blockCommentEnd || mode.blockCommentEnd;
|
||||
if (!startString || !endString) return false;
|
||||
var lead = options.blockCommentLead || mode.blockCommentLead;
|
||||
var startLine = self.getLine(start), endLine = end == start ? startLine : self.getLine(end);
|
||||
var open = startLine.indexOf(startString), close = endLine.lastIndexOf(endString);
|
||||
if (close == -1 && start != end) {
|
||||
endLine = self.getLine(--end);
|
||||
close = endLine.lastIndexOf(endString);
|
||||
}
|
||||
if (open == -1 || close == -1 ||
|
||||
!/comment/.test(self.getTokenTypeAt(Pos(start, open + 1))) ||
|
||||
!/comment/.test(self.getTokenTypeAt(Pos(end, close + 1))))
|
||||
return false;
|
||||
|
||||
// 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.
|
||||
var lastStart = startLine.lastIndexOf(startString, from.ch);
|
||||
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;
|
||||
// Positions of the first endString after the end of the selection, and the last startString before it.
|
||||
firstEnd = endLine.indexOf(endString, to.ch);
|
||||
var almostLastStart = endLine.slice(to.ch).lastIndexOf(startString, firstEnd - to.ch);
|
||||
lastStart = (firstEnd == -1 || almostLastStart == -1) ? -1 : to.ch + almostLastStart;
|
||||
if (firstEnd != -1 && lastStart != -1 && lastStart != to.ch) return false;
|
||||
|
||||
self.operation(function() {
|
||||
self.replaceRange("", Pos(end, close - (pad && endLine.slice(close - pad.length, close) == pad ? pad.length : 0)),
|
||||
Pos(end, close + endString.length));
|
||||
var openEnd = open + startString.length;
|
||||
if (pad && startLine.slice(openEnd, openEnd + pad.length) == pad) openEnd += pad.length;
|
||||
self.replaceRange("", Pos(start, open), Pos(start, openEnd));
|
||||
if (lead) for (var i = start + 1; i <= end; ++i) {
|
||||
var line = self.getLine(i), found = line.indexOf(lead);
|
||||
if (found == -1 || nonWS.test(line.slice(0, found))) continue;
|
||||
var foundEnd = found + lead.length;
|
||||
if (pad && line.slice(foundEnd, foundEnd + pad.length) == pad) foundEnd += pad.length;
|
||||
self.replaceRange("", Pos(i, found), Pos(i, foundEnd));
|
||||
}
|
||||
});
|
||||
return true;
|
||||
});
|
||||
});
|
@ -0,0 +1,85 @@
|
||||
// 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);
|
||||
}
|
||||
});
|
||||
});
|
@ -0,0 +1,32 @@
|
||||
.CodeMirror-dialog {
|
||||
position: absolute;
|
||||
left: 0; right: 0;
|
||||
background: white;
|
||||
z-index: 15;
|
||||
padding: .1em .8em;
|
||||
overflow: hidden;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.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%;
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
// Open simple dialogs on top of an editor. Relies on dialog.css.
|
||||
|
||||
(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) {
|
||||
function dialogDiv(cm, template, bottom) {
|
||||
var wrap = cm.getWrapperElement();
|
||||
var dialog;
|
||||
dialog = wrap.appendChild(document.createElement("div"));
|
||||
if (bottom)
|
||||
dialog.className = "CodeMirror-dialog CodeMirror-dialog-bottom";
|
||||
else
|
||||
dialog.className = "CodeMirror-dialog CodeMirror-dialog-top";
|
||||
|
||||
if (typeof template == "string") {
|
||||
dialog.innerHTML = template;
|
||||
} else { // Assuming it's a detached DOM element.
|
||||
dialog.appendChild(template);
|
||||
}
|
||||
return dialog;
|
||||
}
|
||||
|
||||
function closeNotification(cm, newVal) {
|
||||
if (cm.state.currentNotificationClose)
|
||||
cm.state.currentNotificationClose();
|
||||
cm.state.currentNotificationClose = newVal;
|
||||
}
|
||||
|
||||
CodeMirror.defineExtension("openDialog", function(template, callback, options) {
|
||||
if (!options) options = {};
|
||||
|
||||
closeNotification(this, null);
|
||||
|
||||
var dialog = dialogDiv(this, template, options.bottom);
|
||||
var closed = false, me = this;
|
||||
function close(newVal) {
|
||||
if (typeof newVal == 'string') {
|
||||
inp.value = newVal;
|
||||
} else {
|
||||
if (closed) return;
|
||||
closed = true;
|
||||
dialog.parentNode.removeChild(dialog);
|
||||
me.focus();
|
||||
|
||||
if (options.onClose) options.onClose(dialog);
|
||||
}
|
||||
}
|
||||
|
||||
var inp = dialog.getElementsByTagName("input")[0], button;
|
||||
if (inp) {
|
||||
if (options.value) {
|
||||
inp.value = options.value;
|
||||
inp.select();
|
||||
}
|
||||
|
||||
if (options.onInput)
|
||||
CodeMirror.on(inp, "input", function(e) { options.onInput(e, inp.value, close);});
|
||||
if (options.onKeyUp)
|
||||
CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value, close);});
|
||||
|
||||
CodeMirror.on(inp, "keydown", function(e) {
|
||||
if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; }
|
||||
if (e.keyCode == 27 || (options.closeOnEnter !== false && e.keyCode == 13)) {
|
||||
inp.blur();
|
||||
CodeMirror.e_stop(e);
|
||||
close();
|
||||
}
|
||||
if (e.keyCode == 13) callback(inp.value, e);
|
||||
});
|
||||
|
||||
if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", close);
|
||||
|
||||
inp.focus();
|
||||
} else if (button = dialog.getElementsByTagName("button")[0]) {
|
||||
CodeMirror.on(button, "click", function() {
|
||||
close();
|
||||
me.focus();
|
||||
});
|
||||
|
||||
if (options.closeOnBlur !== false) CodeMirror.on(button, "blur", close);
|
||||
|
||||
button.focus();
|
||||
}
|
||||
return close;
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension("openConfirm", function(template, callbacks, options) {
|
||||
closeNotification(this, null);
|
||||
var dialog = dialogDiv(this, template, options && options.bottom);
|
||||
var buttons = dialog.getElementsByTagName("button");
|
||||
var closed = false, me = this, blurring = 1;
|
||||
function close() {
|
||||
if (closed) return;
|
||||
closed = true;
|
||||
dialog.parentNode.removeChild(dialog);
|
||||
me.focus();
|
||||
}
|
||||
buttons[0].focus();
|
||||
for (var i = 0; i < buttons.length; ++i) {
|
||||
var b = buttons[i];
|
||||
(function(callback) {
|
||||
CodeMirror.on(b, "click", function(e) {
|
||||
CodeMirror.e_preventDefault(e);
|
||||
close();
|
||||
if (callback) callback(me);
|
||||
});
|
||||
})(callbacks[i]);
|
||||
CodeMirror.on(b, "blur", function() {
|
||||
--blurring;
|
||||
setTimeout(function() { if (blurring <= 0) close(); }, 200);
|
||||
});
|
||||
CodeMirror.on(b, "focus", function() { ++blurring; });
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* openNotification
|
||||
* Opens a notification, that can be closed with an optional timer
|
||||
* (default 5000ms timer) and always closes on click.
|
||||
*
|
||||
* If a notification is opened while another is opened, it will close the
|
||||
* currently opened one and open the new one immediately.
|
||||
*/
|
||||
CodeMirror.defineExtension("openNotification", function(template, options) {
|
||||
closeNotification(this, close);
|
||||
var dialog = dialogDiv(this, template, options && options.bottom);
|
||||
var closed = false, doneTimer;
|
||||
var duration = options && typeof options.duration !== "undefined" ? options.duration : 5000;
|
||||
|
||||
function close() {
|
||||
if (closed) return;
|
||||
closed = true;
|
||||
clearTimeout(doneTimer);
|
||||
dialog.parentNode.removeChild(dialog);
|
||||
}
|
||||
|
||||
CodeMirror.on(dialog, 'click', function(e) {
|
||||
CodeMirror.e_preventDefault(e);
|
||||
close();
|
||||
});
|
||||
|
||||
if (duration)
|
||||
doneTimer = setTimeout(close, duration);
|
||||
|
||||
return close;
|
||||
});
|
||||
});
|
@ -0,0 +1,6 @@
|
||||
.CodeMirror-fullscreen {
|
||||
position: fixed;
|
||||
top: 0; left: 0; right: 0; bottom: 0;
|
||||
height: auto;
|
||||
z-index: 9;
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineOption("fullScreen", false, function(cm, val, old) {
|
||||
if (old == CodeMirror.Init) old = false;
|
||||
if (!old == !val) return;
|
||||
if (val) setFullscreen(cm);
|
||||
else setNormal(cm);
|
||||
});
|
||||
|
||||
function setFullscreen(cm) {
|
||||
var wrap = cm.getWrapperElement();
|
||||
cm.state.fullScreenRestore = {scrollTop: window.pageYOffset, scrollLeft: window.pageXOffset,
|
||||
width: wrap.style.width, height: wrap.style.height};
|
||||
wrap.style.width = "";
|
||||
wrap.style.height = "auto";
|
||||
wrap.className += " CodeMirror-fullscreen";
|
||||
document.documentElement.style.overflow = "hidden";
|
||||
cm.refresh();
|
||||
}
|
||||
|
||||
function setNormal(cm) {
|
||||
var wrap = cm.getWrapperElement();
|
||||
wrap.className = wrap.className.replace(/\s*CodeMirror-fullscreen\b/, "");
|
||||
document.documentElement.style.overflow = "";
|
||||
var info = cm.state.fullScreenRestore;
|
||||
wrap.style.width = info.width; wrap.style.height = info.height;
|
||||
window.scrollTo(info.scrollLeft, info.scrollTop);
|
||||
cm.refresh();
|
||||
}
|
||||
});
|
@ -0,0 +1,94 @@
|
||||
// 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) {
|
||||
CodeMirror.defineExtension("addPanel", function(node, options) {
|
||||
if (!this.state.panels) initPanels(this);
|
||||
|
||||
var info = this.state.panels;
|
||||
if (options && options.position == "bottom")
|
||||
info.wrapper.appendChild(node);
|
||||
else
|
||||
info.wrapper.insertBefore(node, info.wrapper.firstChild);
|
||||
var height = (options && options.height) || node.offsetHeight;
|
||||
this._setSize(null, info.heightLeft -= height);
|
||||
info.panels++;
|
||||
return new Panel(this, node, options, height);
|
||||
});
|
||||
|
||||
function Panel(cm, node, options, height) {
|
||||
this.cm = cm;
|
||||
this.node = node;
|
||||
this.options = options;
|
||||
this.height = height;
|
||||
this.cleared = false;
|
||||
}
|
||||
|
||||
Panel.prototype.clear = function() {
|
||||
if (this.cleared) return;
|
||||
this.cleared = true;
|
||||
var info = this.cm.state.panels;
|
||||
this.cm._setSize(null, info.heightLeft += this.height);
|
||||
info.wrapper.removeChild(this.node);
|
||||
if (--info.panels == 0) removePanels(this.cm);
|
||||
};
|
||||
|
||||
Panel.prototype.changed = function(height) {
|
||||
var newHeight = height == null ? this.node.offsetHeight : height;
|
||||
var info = this.cm.state.panels;
|
||||
this.cm._setSize(null, info.height += (newHeight - this.height));
|
||||
this.height = newHeight;
|
||||
};
|
||||
|
||||
function initPanels(cm) {
|
||||
var wrap = cm.getWrapperElement();
|
||||
var style = window.getComputedStyle ? window.getComputedStyle(wrap) : wrap.currentStyle;
|
||||
var height = parseInt(style.height);
|
||||
var info = cm.state.panels = {
|
||||
setHeight: wrap.style.height,
|
||||
heightLeft: height,
|
||||
panels: 0,
|
||||
wrapper: document.createElement("div")
|
||||
};
|
||||
wrap.parentNode.insertBefore(info.wrapper, wrap);
|
||||
var hasFocus = cm.hasFocus();
|
||||
info.wrapper.appendChild(wrap);
|
||||
if (hasFocus) cm.focus();
|
||||
|
||||
cm._setSize = cm.setSize;
|
||||
if (height != null) cm.setSize = function(width, newHeight) {
|
||||
if (newHeight == null) return this._setSize(width, newHeight);
|
||||
info.setHeight = newHeight;
|
||||
if (typeof newHeight != "number") {
|
||||
var px = /^(\d+\.?\d*)px$/.exec(newHeight);
|
||||
if (px) {
|
||||
newHeight = Number(px[1]);
|
||||
} else {
|
||||
info.wrapper.style.height = newHeight;
|
||||
newHeight = info.wrapper.offsetHeight;
|
||||
info.wrapper.style.height = "";
|
||||
}
|
||||
}
|
||||
cm._setSize(width, info.heightLeft += (newHeight - height));
|
||||
height = newHeight;
|
||||
};
|
||||
}
|
||||
|
||||
function removePanels(cm) {
|
||||
var info = cm.state.panels;
|
||||
cm.state.panels = null;
|
||||
|
||||
var wrap = cm.getWrapperElement();
|
||||
info.wrapper.parentNode.replaceChild(wrap, info.wrapper);
|
||||
wrap.style.height = info.setHeight;
|
||||
cm.setSize = cm._setSize;
|
||||
cm.setSize();
|
||||
}
|
||||
});
|
@ -0,0 +1,58 @@
|
||||
// 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) {
|
||||
CodeMirror.defineOption("placeholder", "", function(cm, val, old) {
|
||||
var prev = old && old != CodeMirror.Init;
|
||||
if (val && !prev) {
|
||||
cm.on("blur", onBlur);
|
||||
cm.on("change", onChange);
|
||||
onChange(cm);
|
||||
} else if (!val && prev) {
|
||||
cm.off("blur", onBlur);
|
||||
cm.off("change", onChange);
|
||||
clearPlaceholder(cm);
|
||||
var wrapper = cm.getWrapperElement();
|
||||
wrapper.className = wrapper.className.replace(" CodeMirror-empty", "");
|
||||
}
|
||||
|
||||
if (val && !cm.hasFocus()) onBlur(cm);
|
||||
});
|
||||
|
||||
function clearPlaceholder(cm) {
|
||||
if (cm.state.placeholder) {
|
||||
cm.state.placeholder.parentNode.removeChild(cm.state.placeholder);
|
||||
cm.state.placeholder = null;
|
||||
}
|
||||
}
|
||||
function setPlaceholder(cm) {
|
||||
clearPlaceholder(cm);
|
||||
var elt = cm.state.placeholder = document.createElement("pre");
|
||||
elt.style.cssText = "height: 0; overflow: visible";
|
||||
elt.className = "CodeMirror-placeholder";
|
||||
elt.appendChild(document.createTextNode(cm.getOption("placeholder")));
|
||||
cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild);
|
||||
}
|
||||
|
||||
function onBlur(cm) {
|
||||
if (isEmpty(cm)) setPlaceholder(cm);
|
||||
}
|
||||
function onChange(cm) {
|
||||
var wrapper = cm.getWrapperElement(), empty = isEmpty(cm);
|
||||
wrapper.className = wrapper.className.replace(" CodeMirror-empty", "") + (empty ? " CodeMirror-empty" : "");
|
||||
|
||||
if (empty) setPlaceholder(cm);
|
||||
else clearPlaceholder(cm);
|
||||
}
|
||||
|
||||
function isEmpty(cm) {
|
||||
return (cm.lineCount() === 1) && (cm.getLine(0) === "");
|
||||
}
|
||||
});
|
@ -0,0 +1,64 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineOption("rulers", false, function(cm, val, old) {
|
||||
if (old && old != CodeMirror.Init) {
|
||||
clearRulers(cm);
|
||||
cm.off("refresh", refreshRulers);
|
||||
}
|
||||
if (val && val.length) {
|
||||
setRulers(cm);
|
||||
cm.on("refresh", refreshRulers);
|
||||
}
|
||||
});
|
||||
|
||||
function clearRulers(cm) {
|
||||
for (var i = cm.display.lineSpace.childNodes.length - 1; i >= 0; i--) {
|
||||
var node = cm.display.lineSpace.childNodes[i];
|
||||
if (/(^|\s)CodeMirror-ruler($|\s)/.test(node.className))
|
||||
node.parentNode.removeChild(node);
|
||||
}
|
||||
}
|
||||
|
||||
function setRulers(cm) {
|
||||
var val = cm.getOption("rulers");
|
||||
var cw = cm.defaultCharWidth();
|
||||
var left = cm.charCoords(CodeMirror.Pos(cm.firstLine(), 0), "div").left;
|
||||
var minH = cm.display.scroller.offsetHeight + 30;
|
||||
for (var i = 0; i < val.length; i++) {
|
||||
var elt = document.createElement("div");
|
||||
elt.className = "CodeMirror-ruler";
|
||||
var col, cls = null, conf = val[i];
|
||||
if (typeof conf == "number") {
|
||||
col = conf;
|
||||
} else {
|
||||
col = conf.column;
|
||||
if (conf.className) elt.className += " " + conf.className;
|
||||
if (conf.color) elt.style.borderColor = conf.color;
|
||||
if (conf.lineStyle) elt.style.borderLeftStyle = conf.lineStyle;
|
||||
if (conf.width) elt.style.borderLeftWidth = conf.width;
|
||||
cls = val[i].className;
|
||||
}
|
||||
elt.style.left = (left + col * cw) + "px";
|
||||
elt.style.top = "-50px";
|
||||
elt.style.bottom = "-20px";
|
||||
elt.style.minHeight = minH + "px";
|
||||
cm.display.lineSpace.insertBefore(elt, cm.display.cursorDiv);
|
||||
}
|
||||
}
|
||||
|
||||
function refreshRulers(cm) {
|
||||
clearRulers(cm);
|
||||
setRulers(cm);
|
||||
}
|
||||
});
|
@ -0,0 +1,159 @@
|
||||
// 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 DEFAULT_BRACKETS = "()[]{}''\"\"";
|
||||
var DEFAULT_EXPLODE_ON_ENTER = "[]{}";
|
||||
var SPACE_CHAR_REGEX = /\s/;
|
||||
|
||||
var Pos = CodeMirror.Pos;
|
||||
|
||||
CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) {
|
||||
if (old != CodeMirror.Init && old)
|
||||
cm.removeKeyMap("autoCloseBrackets");
|
||||
if (!val) return;
|
||||
var pairs = DEFAULT_BRACKETS, explode = DEFAULT_EXPLODE_ON_ENTER;
|
||||
if (typeof val == "string") pairs = val;
|
||||
else if (typeof val == "object") {
|
||||
if (val.pairs != null) pairs = val.pairs;
|
||||
if (val.explode != null) explode = val.explode;
|
||||
}
|
||||
var map = buildKeymap(pairs);
|
||||
if (explode) map.Enter = buildExplodeHandler(explode);
|
||||
cm.addKeyMap(map);
|
||||
});
|
||||
|
||||
function charsAround(cm, pos) {
|
||||
var str = cm.getRange(Pos(pos.line, pos.ch - 1),
|
||||
Pos(pos.line, pos.ch + 1));
|
||||
return str.length == 2 ? str : null;
|
||||
}
|
||||
|
||||
// Project the token type that will exists after the given char is
|
||||
// typed, and use it to determine whether it would cause the start
|
||||
// of a string token.
|
||||
function enteringString(cm, pos, ch) {
|
||||
var line = cm.getLine(pos.line);
|
||||
var token = cm.getTokenAt(pos);
|
||||
if (/\bstring2?\b/.test(token.type)) return false;
|
||||
var stream = new CodeMirror.StringStream(line.slice(0, pos.ch) + ch + line.slice(pos.ch), 4);
|
||||
stream.pos = stream.start = token.start;
|
||||
for (;;) {
|
||||
var type1 = cm.getMode().token(stream, token.state);
|
||||
if (stream.pos >= pos.ch + 1) return /\bstring2?\b/.test(type1);
|
||||
stream.start = stream.pos;
|
||||
}
|
||||
}
|
||||
|
||||
function buildKeymap(pairs) {
|
||||
var map = {
|
||||
name : "autoCloseBrackets",
|
||||
Backspace: function(cm) {
|
||||
if (cm.getOption("disableInput")) return CodeMirror.Pass;
|
||||
var ranges = cm.listSelections();
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
if (!ranges[i].empty()) return CodeMirror.Pass;
|
||||
var around = charsAround(cm, ranges[i].head);
|
||||
if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass;
|
||||
}
|
||||
for (var i = ranges.length - 1; i >= 0; i--) {
|
||||
var cur = ranges[i].head;
|
||||
cm.replaceRange("", Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1));
|
||||
}
|
||||
}
|
||||
};
|
||||
var closingBrackets = "";
|
||||
for (var i = 0; i < pairs.length; i += 2) (function(left, right) {
|
||||
closingBrackets += right;
|
||||
map["'" + left + "'"] = function(cm) {
|
||||
if (cm.getOption("disableInput")) return CodeMirror.Pass;
|
||||
var ranges = cm.listSelections(), type, next;
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
var range = ranges[i], cur = range.head, curType;
|
||||
var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1));
|
||||
if (!range.empty()) {
|
||||
curType = "surround";
|
||||
} else if (left == right && next == right) {
|
||||
if (cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == left + left + left)
|
||||
curType = "skipThree";
|
||||
else
|
||||
curType = "skip";
|
||||
} else if (left == right && cur.ch > 1 &&
|
||||
cm.getRange(Pos(cur.line, cur.ch - 2), cur) == left + left &&
|
||||
(cur.ch <= 2 || cm.getRange(Pos(cur.line, cur.ch - 3), Pos(cur.line, cur.ch - 2)) != left)) {
|
||||
curType = "addFour";
|
||||
} else if (left == '"' || left == "'") {
|
||||
if (!CodeMirror.isWordChar(next) && enteringString(cm, cur, left)) curType = "both";
|
||||
else return CodeMirror.Pass;
|
||||
} else if (cm.getLine(cur.line).length == cur.ch || closingBrackets.indexOf(next) >= 0 || SPACE_CHAR_REGEX.test(next)) {
|
||||
curType = "both";
|
||||
} else {
|
||||
return CodeMirror.Pass;
|
||||
}
|
||||
if (!type) type = curType;
|
||||
else if (type != curType) return CodeMirror.Pass;
|
||||
}
|
||||
|
||||
cm.operation(function() {
|
||||
if (type == "skip") {
|
||||
cm.execCommand("goCharRight");
|
||||
} else if (type == "skipThree") {
|
||||
for (var i = 0; i < 3; i++)
|
||||
cm.execCommand("goCharRight");
|
||||
} else if (type == "surround") {
|
||||
var sels = cm.getSelections();
|
||||
for (var i = 0; i < sels.length; i++)
|
||||
sels[i] = left + sels[i] + right;
|
||||
cm.replaceSelections(sels, "around");
|
||||
} else if (type == "both") {
|
||||
cm.replaceSelection(left + right, null);
|
||||
cm.execCommand("goCharLeft");
|
||||
} else if (type == "addFour") {
|
||||
cm.replaceSelection(left + left + left + left, "before");
|
||||
cm.execCommand("goCharRight");
|
||||
}
|
||||
});
|
||||
};
|
||||
if (left != right) map["'" + right + "'"] = function(cm) {
|
||||
var ranges = cm.listSelections();
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
var range = ranges[i];
|
||||
if (!range.empty() ||
|
||||
cm.getRange(range.head, Pos(range.head.line, range.head.ch + 1)) != right)
|
||||
return CodeMirror.Pass;
|
||||
}
|
||||
cm.execCommand("goCharRight");
|
||||
};
|
||||
})(pairs.charAt(i), pairs.charAt(i + 1));
|
||||
return map;
|
||||
}
|
||||
|
||||
function buildExplodeHandler(pairs) {
|
||||
return function(cm) {
|
||||
if (cm.getOption("disableInput")) return CodeMirror.Pass;
|
||||
var ranges = cm.listSelections();
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
if (!ranges[i].empty()) return CodeMirror.Pass;
|
||||
var around = charsAround(cm, ranges[i].head);
|
||||
if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass;
|
||||
}
|
||||
cm.operation(function() {
|
||||
cm.replaceSelection("\n\n", null);
|
||||
cm.execCommand("goCharLeft");
|
||||
ranges = cm.listSelections();
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
var line = ranges[i].head.line;
|
||||
cm.indentLine(line, null, true);
|
||||
cm.indentLine(line + 1, null, true);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
@ -0,0 +1,166 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
/**
|
||||
* Tag-closer extension for CodeMirror.
|
||||
*
|
||||
* This extension adds an "autoCloseTags" option that can be set to
|
||||
* either true to get the default behavior, or an object to further
|
||||
* configure its behavior.
|
||||
*
|
||||
* These are supported options:
|
||||
*
|
||||
* `whenClosing` (default true)
|
||||
* Whether to autoclose when the '/' of a closing tag is typed.
|
||||
* `whenOpening` (default true)
|
||||
* Whether to autoclose the tag when the final '>' of an opening
|
||||
* tag is typed.
|
||||
* `dontCloseTags` (default is empty tags for HTML, none for XML)
|
||||
* An array of tag names that should not be autoclosed.
|
||||
* `indentTags` (default is block tags for HTML, none for XML)
|
||||
* An array of tag names that should, when opened, cause a
|
||||
* blank line to be added inside the tag, and the blank line and
|
||||
* closing line to be indented.
|
||||
*
|
||||
* See demos/closetag.html for a usage example.
|
||||
*/
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"), require("../fold/xml-fold"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror", "../fold/xml-fold"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
CodeMirror.defineOption("autoCloseTags", false, function(cm, val, old) {
|
||||
if (old != CodeMirror.Init && old)
|
||||
cm.removeKeyMap("autoCloseTags");
|
||||
if (!val) return;
|
||||
var map = {name: "autoCloseTags"};
|
||||
if (typeof val != "object" || val.whenClosing)
|
||||
map["'/'"] = function(cm) { return autoCloseSlash(cm); };
|
||||
if (typeof val != "object" || val.whenOpening)
|
||||
map["'>'"] = function(cm) { return autoCloseGT(cm); };
|
||||
cm.addKeyMap(map);
|
||||
});
|
||||
|
||||
var htmlDontClose = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param",
|
||||
"source", "track", "wbr"];
|
||||
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"];
|
||||
|
||||
function autoCloseGT(cm) {
|
||||
if (cm.getOption("disableInput")) return CodeMirror.Pass;
|
||||
var ranges = cm.listSelections(), replacements = [];
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
if (!ranges[i].empty()) return CodeMirror.Pass;
|
||||
var pos = ranges[i].head, tok = cm.getTokenAt(pos);
|
||||
var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
|
||||
if (inner.mode.name != "xml" || !state.tagName) return CodeMirror.Pass;
|
||||
|
||||
var opt = cm.getOption("autoCloseTags"), html = inner.mode.configuration == "html";
|
||||
var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose);
|
||||
var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent);
|
||||
|
||||
var tagName = state.tagName;
|
||||
if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch);
|
||||
var lowerTagName = tagName.toLowerCase();
|
||||
// Don't process the '>' at the end of an end-tag or self-closing tag
|
||||
if (!tagName ||
|
||||
tok.type == "string" && (tok.end != pos.ch || !/[\"\']/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1) ||
|
||||
tok.type == "tag" && state.type == "closeTag" ||
|
||||
tok.string.indexOf("/") == (tok.string.length - 1) || // match something like <someTagName />
|
||||
dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1 ||
|
||||
closingTagExists(cm, tagName, pos, state, true))
|
||||
return CodeMirror.Pass;
|
||||
|
||||
var indent = indentTags && indexOf(indentTags, lowerTagName) > -1;
|
||||
replacements[i] = {indent: indent,
|
||||
text: ">" + (indent ? "\n\n" : "") + "</" + tagName + ">",
|
||||
newPos: indent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1)};
|
||||
}
|
||||
|
||||
for (var i = ranges.length - 1; i >= 0; i--) {
|
||||
var info = replacements[i];
|
||||
cm.replaceRange(info.text, ranges[i].head, ranges[i].anchor, "+insert");
|
||||
var sel = cm.listSelections().slice(0);
|
||||
sel[i] = {head: info.newPos, anchor: info.newPos};
|
||||
cm.setSelections(sel);
|
||||
if (info.indent) {
|
||||
cm.indentLine(info.newPos.line, null, true);
|
||||
cm.indentLine(info.newPos.line + 1, null, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function autoCloseCurrent(cm, typingSlash) {
|
||||
var ranges = cm.listSelections(), replacements = [];
|
||||
var head = typingSlash ? "/" : "</";
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
if (!ranges[i].empty()) return CodeMirror.Pass;
|
||||
var pos = ranges[i].head, tok = cm.getTokenAt(pos);
|
||||
var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
|
||||
if (typingSlash && (tok.type == "string" || tok.string.charAt(0) != "<" ||
|
||||
tok.start != pos.ch - 1))
|
||||
return CodeMirror.Pass;
|
||||
// Kludge to get around the fact that we are not in XML mode
|
||||
// when completing in JS/CSS snippet in htmlmixed mode. Does not
|
||||
// work for other XML embedded languages (there is no general
|
||||
// way to go from a mixed mode to its current XML state).
|
||||
if (inner.mode.name != "xml") {
|
||||
if (cm.getMode().name == "htmlmixed" && inner.mode.name == "javascript")
|
||||
replacements[i] = head + "script>";
|
||||
else if (cm.getMode().name == "htmlmixed" && inner.mode.name == "css")
|
||||
replacements[i] = head + "style>";
|
||||
else
|
||||
return CodeMirror.Pass;
|
||||
} else {
|
||||
if (!state.context || !state.context.tagName ||
|
||||
closingTagExists(cm, state.context.tagName, pos, state))
|
||||
return CodeMirror.Pass;
|
||||
replacements[i] = head + state.context.tagName + ">";
|
||||
}
|
||||
}
|
||||
cm.replaceSelections(replacements);
|
||||
ranges = cm.listSelections();
|
||||
for (var i = 0; i < ranges.length; i++)
|
||||
if (i == ranges.length - 1 || ranges[i].head.line < ranges[i + 1].head.line)
|
||||
cm.indentLine(ranges[i].head.line);
|
||||
}
|
||||
|
||||
function autoCloseSlash(cm) {
|
||||
if (cm.getOption("disableInput")) return CodeMirror.Pass;
|
||||
autoCloseCurrent(cm, true);
|
||||
}
|
||||
|
||||
CodeMirror.commands.closeTag = function(cm) { return autoCloseCurrent(cm); };
|
||||
|
||||
function indexOf(collection, elt) {
|
||||
if (collection.indexOf) return collection.indexOf(elt);
|
||||
for (var i = 0, e = collection.length; i < e; ++i)
|
||||
if (collection[i] == elt) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If xml-fold is loaded, we use its functionality to try and verify
|
||||
// whether a given tag is actually unclosed.
|
||||
function closingTagExists(cm, tagName, pos, state, newTag) {
|
||||
if (!CodeMirror.scanForClosingTag) return false;
|
||||
var end = Math.min(cm.lastLine() + 1, pos.line + 500);
|
||||
var nextClose = CodeMirror.scanForClosingTag(cm, pos, null, end);
|
||||
if (!nextClose || nextClose.tag != tagName) return false;
|
||||
var cx = state.context;
|
||||
// If the immediate wrapping context contains onCx instances of
|
||||
// the same tag, a closing tag only exists if there are at least
|
||||
// that many closing tags of that type following.
|
||||
for (var onCx = newTag ? 1 : 0; cx && cx.tagName == tagName; cx = cx.prev) ++onCx;
|
||||
pos = nextClose.to;
|
||||
for (var i = 1; i < onCx; i++) {
|
||||
var next = CodeMirror.scanForClosingTag(cm, pos, null, end);
|
||||
if (!next || next.tag != tagName) return false;
|
||||
pos = next.to;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
@ -0,0 +1,51 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
var listRE = /^(\s*)(>[> ]*|[*+-]\s|(\d+)\.)(\s*)/,
|
||||
emptyListRE = /^(\s*)(>[> ]*|[*+-]|(\d+)\.)(\s*)$/,
|
||||
unorderedListRE = /[*+-]\s/;
|
||||
|
||||
CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) {
|
||||
if (cm.getOption("disableInput")) return CodeMirror.Pass;
|
||||
var ranges = cm.listSelections(), replacements = [];
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
var pos = ranges[i].head, match;
|
||||
var eolState = cm.getStateAfter(pos.line);
|
||||
var inList = eolState.list !== false;
|
||||
var inQuote = eolState.quote !== false;
|
||||
|
||||
if (!ranges[i].empty() || (!inList && !inQuote) || !(match = cm.getLine(pos.line).match(listRE))) {
|
||||
cm.execCommand("newlineAndIndent");
|
||||
return;
|
||||
}
|
||||
if (cm.getLine(pos.line).match(emptyListRE)) {
|
||||
cm.replaceRange("", {
|
||||
line: pos.line, ch: 0
|
||||
}, {
|
||||
line: pos.line, ch: pos.ch + 1
|
||||
});
|
||||
replacements[i] = "\n";
|
||||
|
||||
} else {
|
||||
var indent = match[1], after = match[4];
|
||||
var bullet = unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0
|
||||
? match[2]
|
||||
: (parseInt(match[3], 10) + 1) + ".";
|
||||
|
||||
replacements[i] = "\n" + indent + bullet + after;
|
||||
}
|
||||
}
|
||||
|
||||
cm.replaceSelections(replacements);
|
||||
};
|
||||
});
|
@ -0,0 +1,120 @@
|
||||
// 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 ie_lt8 = /MSIE \d/.test(navigator.userAgent) &&
|
||||
(document.documentMode == null || document.documentMode < 8);
|
||||
|
||||
var Pos = CodeMirror.Pos;
|
||||
|
||||
var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"};
|
||||
|
||||
function findMatchingBracket(cm, where, strict, config) {
|
||||
var line = cm.getLineHandle(where.line), pos = where.ch - 1;
|
||||
var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)];
|
||||
if (!match) return null;
|
||||
var dir = match.charAt(1) == ">" ? 1 : -1;
|
||||
if (strict && (dir > 0) != (pos == where.ch)) return null;
|
||||
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);
|
||||
if (found == null) return null;
|
||||
return {from: Pos(where.line, pos), to: found && found.pos,
|
||||
match: found && found.ch == match.charAt(0), forward: dir > 0};
|
||||
}
|
||||
|
||||
// bracketRegex is used to specify which type of bracket to scan
|
||||
// should be a regexp, e.g. /[[\]]/
|
||||
//
|
||||
// Note: If "where" is on an open bracket, then this bracket is ignored.
|
||||
//
|
||||
// Returns false when no bracket was found, null when it reached
|
||||
// maxScanLines and gave up
|
||||
function scanForBracket(cm, where, dir, style, config) {
|
||||
var maxScanLen = (config && config.maxScanLineLength) || 10000;
|
||||
var maxScanLines = (config && config.maxScanLines) || 1000;
|
||||
|
||||
var stack = [];
|
||||
var re = config && config.bracketRegex ? config.bracketRegex : /[(){}[\]]/;
|
||||
var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1)
|
||||
: Math.max(cm.firstLine() - 1, where.line - maxScanLines);
|
||||
for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) {
|
||||
var line = cm.getLine(lineNo);
|
||||
if (!line) continue;
|
||||
var pos = dir > 0 ? 0 : line.length - 1, end = dir > 0 ? line.length : -1;
|
||||
if (line.length > maxScanLen) continue;
|
||||
if (lineNo == where.line) pos = where.ch - (dir < 0 ? 1 : 0);
|
||||
for (; pos != end; pos += dir) {
|
||||
var ch = line.charAt(pos);
|
||||
if (re.test(ch) && (style === undefined || cm.getTokenTypeAt(Pos(lineNo, pos + 1)) == style)) {
|
||||
var match = matching[ch];
|
||||
if ((match.charAt(1) == ">") == (dir > 0)) stack.push(ch);
|
||||
else if (!stack.length) return {pos: Pos(lineNo, pos), ch: ch};
|
||||
else stack.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null;
|
||||
}
|
||||
|
||||
function matchBrackets(cm, autoclear, config) {
|
||||
// Disable brace matching in long lines, since it'll cause hugely slow updates
|
||||
var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000;
|
||||
var marks = [], ranges = cm.listSelections();
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, false, config);
|
||||
if (match && cm.getLine(match.from.line).length <= maxHighlightLen) {
|
||||
var style = match.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
|
||||
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)
|
||||
marks.push(cm.markText(match.to, Pos(match.to.line, match.to.ch + 1), {className: style}));
|
||||
}
|
||||
}
|
||||
|
||||
if (marks.length) {
|
||||
// Kludge to work around the IE bug from issue #1193, where text
|
||||
// input stops going to the textare whever this fires.
|
||||
if (ie_lt8 && cm.state.focused) cm.display.input.focus();
|
||||
|
||||
var clear = function() {
|
||||
cm.operation(function() {
|
||||
for (var i = 0; i < marks.length; i++) marks[i].clear();
|
||||
});
|
||||
};
|
||||
if (autoclear) setTimeout(clear, 800);
|
||||
else return clear;
|
||||
}
|
||||
}
|
||||
|
||||
var currentlyHighlighted = null;
|
||||
function doMatchBrackets(cm) {
|
||||
cm.operation(function() {
|
||||
if (currentlyHighlighted) {currentlyHighlighted(); currentlyHighlighted = null;}
|
||||
currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets);
|
||||
});
|
||||
}
|
||||
|
||||
CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) {
|
||||
if (old && old != CodeMirror.Init)
|
||||
cm.off("cursorActivity", doMatchBrackets);
|
||||
if (val) {
|
||||
cm.state.matchBrackets = typeof val == "object" ? val : {};
|
||||
cm.on("cursorActivity", doMatchBrackets);
|
||||
}
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);});
|
||||
CodeMirror.defineExtension("findMatchingBracket", function(pos, strict, config){
|
||||
return findMatchingBracket(this, pos, strict, config);
|
||||
});
|
||||
CodeMirror.defineExtension("scanForBracket", function(pos, dir, style, config){
|
||||
return scanForBracket(this, pos, dir, style, config);
|
||||
});
|
||||
});
|
@ -0,0 +1,66 @@
|
||||
// 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"), require("../fold/xml-fold"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror", "../fold/xml-fold"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineOption("matchTags", false, function(cm, val, old) {
|
||||
if (old && old != CodeMirror.Init) {
|
||||
cm.off("cursorActivity", doMatchTags);
|
||||
cm.off("viewportChange", maybeUpdateMatch);
|
||||
clear(cm);
|
||||
}
|
||||
if (val) {
|
||||
cm.state.matchBothTags = typeof val == "object" && val.bothTags;
|
||||
cm.on("cursorActivity", doMatchTags);
|
||||
cm.on("viewportChange", maybeUpdateMatch);
|
||||
doMatchTags(cm);
|
||||
}
|
||||
});
|
||||
|
||||
function clear(cm) {
|
||||
if (cm.state.tagHit) cm.state.tagHit.clear();
|
||||
if (cm.state.tagOther) cm.state.tagOther.clear();
|
||||
cm.state.tagHit = cm.state.tagOther = null;
|
||||
}
|
||||
|
||||
function doMatchTags(cm) {
|
||||
cm.state.failedTagMatch = false;
|
||||
cm.operation(function() {
|
||||
clear(cm);
|
||||
if (cm.somethingSelected()) return;
|
||||
var cur = cm.getCursor(), range = cm.getViewport();
|
||||
range.from = Math.min(range.from, cur.line); range.to = Math.max(cur.line + 1, range.to);
|
||||
var match = CodeMirror.findMatchingTag(cm, cur, range);
|
||||
if (!match) return;
|
||||
if (cm.state.matchBothTags) {
|
||||
var hit = match.at == "open" ? match.open : match.close;
|
||||
if (hit) cm.state.tagHit = cm.markText(hit.from, hit.to, {className: "CodeMirror-matchingtag"});
|
||||
}
|
||||
var other = match.at == "close" ? match.open : match.close;
|
||||
if (other)
|
||||
cm.state.tagOther = cm.markText(other.from, other.to, {className: "CodeMirror-matchingtag"});
|
||||
else
|
||||
cm.state.failedTagMatch = true;
|
||||
});
|
||||
}
|
||||
|
||||
function maybeUpdateMatch(cm) {
|
||||
if (cm.state.failedTagMatch) doMatchTags(cm);
|
||||
}
|
||||
|
||||
CodeMirror.commands.toMatchingTag = function(cm) {
|
||||
var found = CodeMirror.findMatchingTag(cm, cm.getCursor());
|
||||
if (found) {
|
||||
var other = found.at == "close" ? found.open : found.close;
|
||||
if (other) cm.extendSelection(other.to, other.from);
|
||||
}
|
||||
};
|
||||
});
|
@ -0,0 +1,27 @@
|
||||
// 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) {
|
||||
CodeMirror.defineOption("showTrailingSpace", false, function(cm, val, prev) {
|
||||
if (prev == CodeMirror.Init) prev = false;
|
||||
if (prev && !val)
|
||||
cm.removeOverlay("trailingspace");
|
||||
else if (!prev && val)
|
||||
cm.addOverlay({
|
||||
token: function(stream) {
|
||||
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; }
|
||||
stream.pos = l;
|
||||
return "trailingspace";
|
||||
},
|
||||
name: "trailingspace"
|
||||
});
|
||||
});
|
||||
});
|
@ -0,0 +1,105 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.registerHelper("fold", "brace", function(cm, start) {
|
||||
var line = start.line, lineText = cm.getLine(line);
|
||||
var startCh, tokenType;
|
||||
|
||||
function findOpening(openCh) {
|
||||
for (var at = start.ch, pass = 0;;) {
|
||||
var found = at <= 0 ? -1 : lineText.lastIndexOf(openCh, at - 1);
|
||||
if (found == -1) {
|
||||
if (pass == 1) break;
|
||||
pass = 1;
|
||||
at = lineText.length;
|
||||
continue;
|
||||
}
|
||||
if (pass == 1 && found < start.ch) break;
|
||||
tokenType = cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1));
|
||||
if (!/^(comment|string)/.test(tokenType)) return found + 1;
|
||||
at = found - 1;
|
||||
}
|
||||
}
|
||||
|
||||
var startToken = "{", endToken = "}", startCh = findOpening("{");
|
||||
if (startCh == null) {
|
||||
startToken = "[", endToken = "]";
|
||||
startCh = findOpening("[");
|
||||
}
|
||||
|
||||
if (startCh == null) return;
|
||||
var count = 1, lastLine = cm.lastLine(), end, endCh;
|
||||
outer: for (var i = line; i <= lastLine; ++i) {
|
||||
var text = cm.getLine(i), pos = i == line ? startCh : 0;
|
||||
for (;;) {
|
||||
var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);
|
||||
if (nextOpen < 0) nextOpen = text.length;
|
||||
if (nextClose < 0) nextClose = text.length;
|
||||
pos = Math.min(nextOpen, nextClose);
|
||||
if (pos == text.length) break;
|
||||
if (cm.getTokenTypeAt(CodeMirror.Pos(i, pos + 1)) == tokenType) {
|
||||
if (pos == nextOpen) ++count;
|
||||
else if (!--count) { end = i; endCh = pos; break outer; }
|
||||
}
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
if (end == null || line == end && endCh == startCh) return;
|
||||
return {from: CodeMirror.Pos(line, startCh),
|
||||
to: CodeMirror.Pos(end, endCh)};
|
||||
});
|
||||
|
||||
CodeMirror.registerHelper("fold", "import", function(cm, start) {
|
||||
function hasImport(line) {
|
||||
if (line < cm.firstLine() || line > cm.lastLine()) return null;
|
||||
var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
|
||||
if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
|
||||
if (start.type != "keyword" || start.string != "import") return null;
|
||||
// Now find closing semicolon, return its position
|
||||
for (var i = line, e = Math.min(cm.lastLine(), line + 10); i <= e; ++i) {
|
||||
var text = cm.getLine(i), semi = text.indexOf(";");
|
||||
if (semi != -1) return {startCh: start.end, end: CodeMirror.Pos(i, semi)};
|
||||
}
|
||||
}
|
||||
|
||||
var start = start.line, has = hasImport(start), prev;
|
||||
if (!has || hasImport(start - 1) || ((prev = hasImport(start - 2)) && prev.end.line == start - 1))
|
||||
return null;
|
||||
for (var end = has.end;;) {
|
||||
var next = hasImport(end.line + 1);
|
||||
if (next == null) break;
|
||||
end = next.end;
|
||||
}
|
||||
return {from: cm.clipPos(CodeMirror.Pos(start, has.startCh + 1)), to: end};
|
||||
});
|
||||
|
||||
CodeMirror.registerHelper("fold", "include", function(cm, start) {
|
||||
function hasInclude(line) {
|
||||
if (line < cm.firstLine() || line > cm.lastLine()) return null;
|
||||
var start = cm.getTokenAt(CodeMirror.Pos(line, 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;
|
||||
}
|
||||
|
||||
var start = start.line, has = hasInclude(start);
|
||||
if (has == null || hasInclude(start - 1) != null) return null;
|
||||
for (var end = start;;) {
|
||||
var next = hasInclude(end + 1);
|
||||
if (next == null) break;
|
||||
++end;
|
||||
}
|
||||
return {from: CodeMirror.Pos(start, has + 1),
|
||||
to: cm.clipPos(CodeMirror.Pos(end))};
|
||||
});
|
||||
|
||||
});
|
@ -0,0 +1,57 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.registerGlobalHelper("fold", "comment", function(mode) {
|
||||
return mode.blockCommentStart && mode.blockCommentEnd;
|
||||
}, function(cm, start) {
|
||||
var mode = cm.getModeAt(start), startToken = mode.blockCommentStart, endToken = mode.blockCommentEnd;
|
||||
if (!startToken || !endToken) return;
|
||||
var line = start.line, lineText = cm.getLine(line);
|
||||
|
||||
var startCh;
|
||||
for (var at = start.ch, pass = 0;;) {
|
||||
var found = at <= 0 ? -1 : lineText.lastIndexOf(startToken, at - 1);
|
||||
if (found == -1) {
|
||||
if (pass == 1) return;
|
||||
pass = 1;
|
||||
at = lineText.length;
|
||||
continue;
|
||||
}
|
||||
if (pass == 1 && found < start.ch) return;
|
||||
if (/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1)))) {
|
||||
startCh = found + startToken.length;
|
||||
break;
|
||||
}
|
||||
at = found - 1;
|
||||
}
|
||||
|
||||
var depth = 1, lastLine = cm.lastLine(), end, endCh;
|
||||
outer: for (var i = line; i <= lastLine; ++i) {
|
||||
var text = cm.getLine(i), pos = i == line ? startCh : 0;
|
||||
for (;;) {
|
||||
var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);
|
||||
if (nextOpen < 0) nextOpen = text.length;
|
||||
if (nextClose < 0) nextClose = text.length;
|
||||
pos = Math.min(nextOpen, nextClose);
|
||||
if (pos == text.length) break;
|
||||
if (pos == nextOpen) ++depth;
|
||||
else if (!--depth) { end = i; endCh = pos; break outer; }
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
if (end == null || line == end && endCh == startCh) return;
|
||||
return {from: CodeMirror.Pos(line, startCh),
|
||||
to: CodeMirror.Pos(end, endCh)};
|
||||
});
|
||||
|
||||
});
|
@ -0,0 +1,149 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
function doFold(cm, pos, options, force) {
|
||||
if (options && options.call) {
|
||||
var finder = options;
|
||||
options = null;
|
||||
} else {
|
||||
var finder = getOption(cm, options, "rangeFinder");
|
||||
}
|
||||
if (typeof pos == "number") pos = CodeMirror.Pos(pos, 0);
|
||||
var minSize = getOption(cm, options, "minFoldSize");
|
||||
|
||||
function getRange(allowFolded) {
|
||||
var range = finder(cm, pos);
|
||||
if (!range || range.to.line - range.from.line < minSize) return null;
|
||||
var marks = cm.findMarksAt(range.from);
|
||||
for (var i = 0; i < marks.length; ++i) {
|
||||
if (marks[i].__isFold && force !== "fold") {
|
||||
if (!allowFolded) return null;
|
||||
range.cleared = true;
|
||||
marks[i].clear();
|
||||
}
|
||||
}
|
||||
return range;
|
||||
}
|
||||
|
||||
var range = getRange(true);
|
||||
if (getOption(cm, options, "scanUp")) while (!range && pos.line > cm.firstLine()) {
|
||||
pos = CodeMirror.Pos(pos.line - 1, 0);
|
||||
range = getRange(false);
|
||||
}
|
||||
if (!range || range.cleared || force === "unfold") return;
|
||||
|
||||
var myWidget = makeWidget(cm, options);
|
||||
CodeMirror.on(myWidget, "mousedown", function(e) {
|
||||
myRange.clear();
|
||||
CodeMirror.e_preventDefault(e);
|
||||
});
|
||||
var myRange = cm.markText(range.from, range.to, {
|
||||
replacedWith: myWidget,
|
||||
clearOnEnter: true,
|
||||
__isFold: true
|
||||
});
|
||||
myRange.on("clear", function(from, to) {
|
||||
CodeMirror.signal(cm, "unfold", cm, from, to);
|
||||
});
|
||||
CodeMirror.signal(cm, "fold", cm, range.from, range.to);
|
||||
}
|
||||
|
||||
function makeWidget(cm, options) {
|
||||
var widget = getOption(cm, options, "widget");
|
||||
if (typeof widget == "string") {
|
||||
var text = document.createTextNode(widget);
|
||||
widget = document.createElement("span");
|
||||
widget.appendChild(text);
|
||||
widget.className = "CodeMirror-foldmarker";
|
||||
}
|
||||
return widget;
|
||||
}
|
||||
|
||||
// Clumsy backwards-compatible interface
|
||||
CodeMirror.newFoldFunction = function(rangeFinder, widget) {
|
||||
return function(cm, pos) { doFold(cm, pos, {rangeFinder: rangeFinder, widget: widget}); };
|
||||
};
|
||||
|
||||
// New-style interface
|
||||
CodeMirror.defineExtension("foldCode", function(pos, options, force) {
|
||||
doFold(this, pos, options, force);
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension("isFolded", function(pos) {
|
||||
var marks = this.findMarksAt(pos);
|
||||
for (var i = 0; i < marks.length; ++i)
|
||||
if (marks[i].__isFold) return true;
|
||||
});
|
||||
|
||||
CodeMirror.commands.toggleFold = function(cm) {
|
||||
cm.foldCode(cm.getCursor());
|
||||
};
|
||||
CodeMirror.commands.fold = function(cm) {
|
||||
cm.foldCode(cm.getCursor(), null, "fold");
|
||||
};
|
||||
CodeMirror.commands.unfold = function(cm) {
|
||||
cm.foldCode(cm.getCursor(), null, "unfold");
|
||||
};
|
||||
CodeMirror.commands.foldAll = function(cm) {
|
||||
cm.operation(function() {
|
||||
for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)
|
||||
cm.foldCode(CodeMirror.Pos(i, 0), null, "fold");
|
||||
});
|
||||
};
|
||||
CodeMirror.commands.unfoldAll = function(cm) {
|
||||
cm.operation(function() {
|
||||
for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)
|
||||
cm.foldCode(CodeMirror.Pos(i, 0), null, "unfold");
|
||||
});
|
||||
};
|
||||
|
||||
CodeMirror.registerHelper("fold", "combine", function() {
|
||||
var funcs = Array.prototype.slice.call(arguments, 0);
|
||||
return function(cm, start) {
|
||||
for (var i = 0; i < funcs.length; ++i) {
|
||||
var found = funcs[i](cm, start);
|
||||
if (found) return found;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.registerHelper("fold", "auto", function(cm, start) {
|
||||
var helpers = cm.getHelpers(start, "fold");
|
||||
for (var i = 0; i < helpers.length; i++) {
|
||||
var cur = helpers[i](cm, start);
|
||||
if (cur) return cur;
|
||||
}
|
||||
});
|
||||
|
||||
var defaultOptions = {
|
||||
rangeFinder: CodeMirror.fold.auto,
|
||||
widget: "\u2194",
|
||||
minFoldSize: 0,
|
||||
scanUp: false
|
||||
};
|
||||
|
||||
CodeMirror.defineOption("foldOptions", null);
|
||||
|
||||
function getOption(cm, options, name) {
|
||||
if (options && options[name] !== undefined)
|
||||
return options[name];
|
||||
var editorOptions = cm.options.foldOptions;
|
||||
if (editorOptions && editorOptions[name] !== undefined)
|
||||
return editorOptions[name];
|
||||
return defaultOptions[name];
|
||||
}
|
||||
|
||||
CodeMirror.defineExtension("foldOption", function(options, name) {
|
||||
return getOption(this, options, name);
|
||||
});
|
||||
});
|
@ -0,0 +1,20 @@
|
||||
.CodeMirror-foldmarker {
|
||||
color: blue;
|
||||
text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px;
|
||||
font-family: arial;
|
||||
line-height: .3;
|
||||
cursor: pointer;
|
||||
}
|
||||
.CodeMirror-foldgutter {
|
||||
width: .7em;
|
||||
}
|
||||
.CodeMirror-foldgutter-open,
|
||||
.CodeMirror-foldgutter-folded {
|
||||
cursor: pointer;
|
||||
}
|
||||
.CodeMirror-foldgutter-open:after {
|
||||
content: "\25BE";
|
||||
}
|
||||
.CodeMirror-foldgutter-folded:after {
|
||||
content: "\25B8";
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
// 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"), require("./foldcode"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror", "./foldcode"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineOption("foldGutter", false, function(cm, val, old) {
|
||||
if (old && old != CodeMirror.Init) {
|
||||
cm.clearGutter(cm.state.foldGutter.options.gutter);
|
||||
cm.state.foldGutter = null;
|
||||
cm.off("gutterClick", onGutterClick);
|
||||
cm.off("change", onChange);
|
||||
cm.off("viewportChange", onViewportChange);
|
||||
cm.off("fold", onFold);
|
||||
cm.off("unfold", onFold);
|
||||
cm.off("swapDoc", updateInViewport);
|
||||
}
|
||||
if (val) {
|
||||
cm.state.foldGutter = new State(parseOptions(val));
|
||||
updateInViewport(cm);
|
||||
cm.on("gutterClick", onGutterClick);
|
||||
cm.on("change", onChange);
|
||||
cm.on("viewportChange", onViewportChange);
|
||||
cm.on("fold", onFold);
|
||||
cm.on("unfold", onFold);
|
||||
cm.on("swapDoc", updateInViewport);
|
||||
}
|
||||
});
|
||||
|
||||
var Pos = CodeMirror.Pos;
|
||||
|
||||
function State(options) {
|
||||
this.options = options;
|
||||
this.from = this.to = 0;
|
||||
}
|
||||
|
||||
function parseOptions(opts) {
|
||||
if (opts === true) opts = {};
|
||||
if (opts.gutter == null) opts.gutter = "CodeMirror-foldgutter";
|
||||
if (opts.indicatorOpen == null) opts.indicatorOpen = "CodeMirror-foldgutter-open";
|
||||
if (opts.indicatorFolded == null) opts.indicatorFolded = "CodeMirror-foldgutter-folded";
|
||||
return opts;
|
||||
}
|
||||
|
||||
function isFolded(cm, line) {
|
||||
var marks = cm.findMarksAt(Pos(line));
|
||||
for (var i = 0; i < marks.length; ++i)
|
||||
if (marks[i].__isFold && marks[i].find().from.line == line) return true;
|
||||
}
|
||||
|
||||
function marker(spec) {
|
||||
if (typeof spec == "string") {
|
||||
var elt = document.createElement("div");
|
||||
elt.className = spec + " CodeMirror-guttermarker-subtle";
|
||||
return elt;
|
||||
} else {
|
||||
return spec.cloneNode(true);
|
||||
}
|
||||
}
|
||||
|
||||
function updateFoldInfo(cm, from, to) {
|
||||
var opts = cm.state.foldGutter.options, cur = from;
|
||||
var minSize = cm.foldOption(opts, "minFoldSize");
|
||||
var func = cm.foldOption(opts, "rangeFinder");
|
||||
cm.eachLine(from, to, function(line) {
|
||||
var mark = null;
|
||||
if (isFolded(cm, cur)) {
|
||||
mark = marker(opts.indicatorFolded);
|
||||
} else {
|
||||
var pos = Pos(cur, 0);
|
||||
var range = func && func(cm, pos);
|
||||
if (range && range.to.line - range.from.line >= minSize)
|
||||
mark = marker(opts.indicatorOpen);
|
||||
}
|
||||
cm.setGutterMarker(line, opts.gutter, mark);
|
||||
++cur;
|
||||
});
|
||||
}
|
||||
|
||||
function updateInViewport(cm) {
|
||||
var vp = cm.getViewport(), state = cm.state.foldGutter;
|
||||
if (!state) return;
|
||||
cm.operation(function() {
|
||||
updateFoldInfo(cm, vp.from, vp.to);
|
||||
});
|
||||
state.from = vp.from; state.to = vp.to;
|
||||
}
|
||||
|
||||
function onGutterClick(cm, line, gutter) {
|
||||
var opts = cm.state.foldGutter.options;
|
||||
if (gutter != opts.gutter) return;
|
||||
cm.foldCode(Pos(line, 0), opts.rangeFinder);
|
||||
}
|
||||
|
||||
function onChange(cm) {
|
||||
var state = cm.state.foldGutter, opts = cm.state.foldGutter.options;
|
||||
state.from = state.to = 0;
|
||||
clearTimeout(state.changeUpdate);
|
||||
state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600);
|
||||
}
|
||||
|
||||
function onViewportChange(cm) {
|
||||
var state = cm.state.foldGutter, opts = cm.state.foldGutter.options;
|
||||
clearTimeout(state.changeUpdate);
|
||||
state.changeUpdate = setTimeout(function() {
|
||||
var vp = cm.getViewport();
|
||||
if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) {
|
||||
updateInViewport(cm);
|
||||
} else {
|
||||
cm.operation(function() {
|
||||
if (vp.from < state.from) {
|
||||
updateFoldInfo(cm, vp.from, state.from);
|
||||
state.from = vp.from;
|
||||
}
|
||||
if (vp.to > state.to) {
|
||||
updateFoldInfo(cm, state.to, vp.to);
|
||||
state.to = vp.to;
|
||||
}
|
||||
});
|
||||
}
|
||||
}, opts.updateViewportTimeSpan || 400);
|
||||
}
|
||||
|
||||
function onFold(cm, from) {
|
||||
var state = cm.state.foldGutter, line = from.line;
|
||||
if (line >= state.from && line < state.to)
|
||||
updateFoldInfo(cm, line, line + 1);
|
||||
}
|
||||
});
|
@ -0,0 +1,44 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.registerHelper("fold", "indent", function(cm, start) {
|
||||
var tabSize = cm.getOption("tabSize"), firstLine = cm.getLine(start.line);
|
||||
if (!/\S/.test(firstLine)) return;
|
||||
var getIndent = function(line) {
|
||||
return CodeMirror.countColumn(line, null, tabSize);
|
||||
};
|
||||
var myIndent = getIndent(firstLine);
|
||||
var lastLineInFold = null;
|
||||
// Go through lines until we find a line that definitely doesn't belong in
|
||||
// the block we're folding, or to the end.
|
||||
for (var i = start.line + 1, end = cm.lastLine(); i <= end; ++i) {
|
||||
var curLine = cm.getLine(i);
|
||||
var curIndent = getIndent(curLine);
|
||||
if (curIndent > myIndent) {
|
||||
// Lines with a greater indent are considered part of the block.
|
||||
lastLineInFold = i;
|
||||
} else if (!/\S/.test(curLine)) {
|
||||
// Empty lines might be breaks within the block we're trying to fold.
|
||||
} else {
|
||||
// A non-empty line at an indent equal to or less than ours marks the
|
||||
// start of another block.
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (lastLineInFold) return {
|
||||
from: CodeMirror.Pos(start.line, firstLine.length),
|
||||
to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length)
|
||||
};
|
||||
});
|
||||
|
||||
});
|
@ -0,0 +1,49 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.registerHelper("fold", "markdown", function(cm, start) {
|
||||
var maxDepth = 100;
|
||||
|
||||
function isHeader(lineNo) {
|
||||
var tokentype = cm.getTokenTypeAt(CodeMirror.Pos(lineNo, 0));
|
||||
return tokentype && /\bheader\b/.test(tokentype);
|
||||
}
|
||||
|
||||
function headerLevel(lineNo, line, nextLine) {
|
||||
var match = line && line.match(/^#+/);
|
||||
if (match && isHeader(lineNo)) return match[0].length;
|
||||
match = nextLine && nextLine.match(/^[=\-]+\s*$/);
|
||||
if (match && isHeader(lineNo + 1)) return nextLine[0] == "=" ? 1 : 2;
|
||||
return maxDepth;
|
||||
}
|
||||
|
||||
var firstLine = cm.getLine(start.line), nextLine = cm.getLine(start.line + 1);
|
||||
var level = headerLevel(start.line, firstLine, nextLine);
|
||||
if (level === maxDepth) return undefined;
|
||||
|
||||
var lastLineNo = cm.lastLine();
|
||||
var end = start.line, nextNextLine = cm.getLine(end + 2);
|
||||
while (end < lastLineNo) {
|
||||
if (headerLevel(end + 1, nextLine, nextNextLine) <= level) break;
|
||||
++end;
|
||||
nextLine = nextNextLine;
|
||||
nextNextLine = cm.getLine(end + 2);
|
||||
}
|
||||
|
||||
return {
|
||||
from: CodeMirror.Pos(start.line, firstLine.length),
|
||||
to: CodeMirror.Pos(end, cm.getLine(end).length)
|
||||
};
|
||||
});
|
||||
|
||||
});
|
@ -0,0 +1,182 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
var Pos = CodeMirror.Pos;
|
||||
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 nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040";
|
||||
var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g");
|
||||
|
||||
function Iter(cm, line, ch, range) {
|
||||
this.line = line; this.ch = ch;
|
||||
this.cm = cm; this.text = cm.getLine(line);
|
||||
this.min = range ? range.from : cm.firstLine();
|
||||
this.max = range ? range.to - 1 : cm.lastLine();
|
||||
}
|
||||
|
||||
function tagAt(iter, ch) {
|
||||
var type = iter.cm.getTokenTypeAt(Pos(iter.line, ch));
|
||||
return type && /\btag\b/.test(type);
|
||||
}
|
||||
|
||||
function nextLine(iter) {
|
||||
if (iter.line >= iter.max) return;
|
||||
iter.ch = 0;
|
||||
iter.text = iter.cm.getLine(++iter.line);
|
||||
return true;
|
||||
}
|
||||
function prevLine(iter) {
|
||||
if (iter.line <= iter.min) return;
|
||||
iter.text = iter.cm.getLine(--iter.line);
|
||||
iter.ch = iter.text.length;
|
||||
return true;
|
||||
}
|
||||
|
||||
function toTagEnd(iter) {
|
||||
for (;;) {
|
||||
var gt = iter.text.indexOf(">", iter.ch);
|
||||
if (gt == -1) { if (nextLine(iter)) continue; else return; }
|
||||
if (!tagAt(iter, gt + 1)) { iter.ch = gt + 1; continue; }
|
||||
var lastSlash = iter.text.lastIndexOf("/", gt);
|
||||
var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
|
||||
iter.ch = gt + 1;
|
||||
return selfClose ? "selfClose" : "regular";
|
||||
}
|
||||
}
|
||||
function toTagStart(iter) {
|
||||
for (;;) {
|
||||
var lt = iter.ch ? iter.text.lastIndexOf("<", iter.ch - 1) : -1;
|
||||
if (lt == -1) { if (prevLine(iter)) continue; else return; }
|
||||
if (!tagAt(iter, lt + 1)) { iter.ch = lt; continue; }
|
||||
xmlTagStart.lastIndex = lt;
|
||||
iter.ch = lt;
|
||||
var match = xmlTagStart.exec(iter.text);
|
||||
if (match && match.index == lt) return match;
|
||||
}
|
||||
}
|
||||
|
||||
function toNextTag(iter) {
|
||||
for (;;) {
|
||||
xmlTagStart.lastIndex = iter.ch;
|
||||
var found = xmlTagStart.exec(iter.text);
|
||||
if (!found) { if (nextLine(iter)) continue; else return; }
|
||||
if (!tagAt(iter, found.index + 1)) { iter.ch = found.index + 1; continue; }
|
||||
iter.ch = found.index + found[0].length;
|
||||
return found;
|
||||
}
|
||||
}
|
||||
function toPrevTag(iter) {
|
||||
for (;;) {
|
||||
var gt = iter.ch ? iter.text.lastIndexOf(">", iter.ch - 1) : -1;
|
||||
if (gt == -1) { if (prevLine(iter)) continue; else return; }
|
||||
if (!tagAt(iter, gt + 1)) { iter.ch = gt; continue; }
|
||||
var lastSlash = iter.text.lastIndexOf("/", gt);
|
||||
var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
|
||||
iter.ch = gt + 1;
|
||||
return selfClose ? "selfClose" : "regular";
|
||||
}
|
||||
}
|
||||
|
||||
function findMatchingClose(iter, tag) {
|
||||
var stack = [];
|
||||
for (;;) {
|
||||
var next = toNextTag(iter), end, startLine = iter.line, startCh = iter.ch - (next ? next[0].length : 0);
|
||||
if (!next || !(end = toTagEnd(iter))) return;
|
||||
if (end == "selfClose") continue;
|
||||
if (next[1]) { // closing tag
|
||||
for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) {
|
||||
stack.length = i;
|
||||
break;
|
||||
}
|
||||
if (i < 0 && (!tag || tag == next[2])) return {
|
||||
tag: next[2],
|
||||
from: Pos(startLine, startCh),
|
||||
to: Pos(iter.line, iter.ch)
|
||||
};
|
||||
} else { // opening tag
|
||||
stack.push(next[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
function findMatchingOpen(iter, tag) {
|
||||
var stack = [];
|
||||
for (;;) {
|
||||
var prev = toPrevTag(iter);
|
||||
if (!prev) return;
|
||||
if (prev == "selfClose") { toTagStart(iter); continue; }
|
||||
var endLine = iter.line, endCh = iter.ch;
|
||||
var start = toTagStart(iter);
|
||||
if (!start) return;
|
||||
if (start[1]) { // closing tag
|
||||
stack.push(start[2]);
|
||||
} else { // opening tag
|
||||
for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == start[2]) {
|
||||
stack.length = i;
|
||||
break;
|
||||
}
|
||||
if (i < 0 && (!tag || tag == start[2])) return {
|
||||
tag: start[2],
|
||||
from: Pos(iter.line, iter.ch),
|
||||
to: Pos(endLine, endCh)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CodeMirror.registerHelper("fold", "xml", function(cm, start) {
|
||||
var iter = new Iter(cm, start.line, 0);
|
||||
for (;;) {
|
||||
var openTag = toNextTag(iter), end;
|
||||
if (!openTag || iter.line != start.line || !(end = toTagEnd(iter))) return;
|
||||
if (!openTag[1] && end != "selfClose") {
|
||||
var start = Pos(iter.line, iter.ch);
|
||||
var close = findMatchingClose(iter, openTag[2]);
|
||||
return close && {from: start, to: close.from};
|
||||
}
|
||||
}
|
||||
});
|
||||
CodeMirror.findMatchingTag = function(cm, pos, range) {
|
||||
var iter = new Iter(cm, pos.line, pos.ch, range);
|
||||
if (iter.text.indexOf(">") == -1 && iter.text.indexOf("<") == -1) return;
|
||||
var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch);
|
||||
var start = end && toTagStart(iter);
|
||||
if (!end || !start || cmp(iter, pos) > 0) return;
|
||||
var here = {from: Pos(iter.line, iter.ch), to: to, tag: start[2]};
|
||||
if (end == "selfClose") return {open: here, close: null, at: "open"};
|
||||
|
||||
if (start[1]) { // closing tag
|
||||
return {open: findMatchingOpen(iter, start[2]), close: here, at: "close"};
|
||||
} else { // opening tag
|
||||
iter = new Iter(cm, to.line, to.ch, range);
|
||||
return {open: here, close: findMatchingClose(iter, start[2]), at: "open"};
|
||||
}
|
||||
};
|
||||
|
||||
CodeMirror.findEnclosingTag = function(cm, pos, range) {
|
||||
var iter = new Iter(cm, pos.line, pos.ch, range);
|
||||
for (;;) {
|
||||
var open = findMatchingOpen(iter);
|
||||
if (!open) break;
|
||||
var forward = new Iter(cm, pos.line, pos.ch, range);
|
||||
var close = findMatchingClose(forward, open.tag);
|
||||
if (close) return {open: open, close: close};
|
||||
}
|
||||
};
|
||||
|
||||
// Used by addon/edit/closetag.js
|
||||
CodeMirror.scanForClosingTag = function(cm, pos, name, end) {
|
||||
var iter = new Iter(cm, pos.line, pos.ch, end ? {from: 0, to: end} : null);
|
||||
return findMatchingClose(iter, name);
|
||||
};
|
||||
});
|
@ -0,0 +1,41 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
var WORD = /[\w$]+/, RANGE = 500;
|
||||
|
||||
CodeMirror.registerHelper("hint", "anyword", function(editor, options) {
|
||||
var word = options && options.word || WORD;
|
||||
var range = options && options.range || RANGE;
|
||||
var cur = editor.getCursor(), curLine = editor.getLine(cur.line);
|
||||
var end = cur.ch, start = end;
|
||||
while (start && word.test(curLine.charAt(start - 1))) --start;
|
||||
var curWord = start != end && curLine.slice(start, end);
|
||||
|
||||
var list = [], seen = {};
|
||||
var re = new RegExp(word.source, "g");
|
||||
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;
|
||||
for (; line != endLine; line += dir) {
|
||||
var text = editor.getLine(line), m;
|
||||
while (m = re.exec(text)) {
|
||||
if (line == cur.line && m[0] === curWord) continue;
|
||||
if ((!curWord || m[0].lastIndexOf(curWord, 0) == 0) && !Object.prototype.hasOwnProperty.call(seen, m[0])) {
|
||||
seen[m[0]] = true;
|
||||
list.push(m[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return {list: list, from: CodeMirror.Pos(cur.line, start), to: CodeMirror.Pos(cur.line, end)};
|
||||
});
|
||||
});
|
@ -0,0 +1,56 @@
|
||||
// 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"), require("../../mode/css/css"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror", "../../mode/css/css"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
var pseudoClasses = {link: 1, visited: 1, active: 1, hover: 1, focus: 1,
|
||||
"first-letter": 1, "first-line": 1, "first-child": 1,
|
||||
before: 1, after: 1, lang: 1};
|
||||
|
||||
CodeMirror.registerHelper("hint", "css", function(cm) {
|
||||
var cur = cm.getCursor(), token = cm.getTokenAt(cur);
|
||||
var inner = CodeMirror.innerMode(cm.getMode(), token.state);
|
||||
if (inner.mode.name != "css") return;
|
||||
|
||||
var start = token.start, end = cur.ch, word = token.string.slice(0, end - start);
|
||||
if (/[^\w$_-]/.test(word)) {
|
||||
word = ""; start = end = cur.ch;
|
||||
}
|
||||
|
||||
var spec = CodeMirror.resolveMode("text/css");
|
||||
|
||||
var result = [];
|
||||
function add(keywords) {
|
||||
for (var name in keywords)
|
||||
if (!word || name.lastIndexOf(word, 0) == 0)
|
||||
result.push(name);
|
||||
}
|
||||
|
||||
var st = inner.state.state;
|
||||
if (st == "pseudo" || token.type == "variable-3") {
|
||||
add(pseudoClasses);
|
||||
} else if (st == "block" || st == "maybeprop") {
|
||||
add(spec.propertyKeywords);
|
||||
} else if (st == "prop" || st == "parens" || st == "at" || st == "params") {
|
||||
add(spec.valueKeywords);
|
||||
add(spec.colorKeywords);
|
||||
} else if (st == "media" || st == "media_parens") {
|
||||
add(spec.mediaTypes);
|
||||
add(spec.mediaFeatures);
|
||||
}
|
||||
|
||||
if (result.length) return {
|
||||
list: result,
|
||||
from: CodeMirror.Pos(cur.line, start),
|
||||
to: CodeMirror.Pos(cur.line, end)
|
||||
};
|
||||
});
|
||||
});
|
@ -0,0 +1,348 @@
|
||||
// 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"), require("./xml-hint"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror", "./xml-hint"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"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 targets = ["_blank", "_self", "_top", "_parent"];
|
||||
var charsets = ["ascii", "utf-8", "utf-16", "latin1", "latin1"];
|
||||
var methods = ["get", "post", "put", "delete"];
|
||||
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",
|
||||
"3d-glasses", "resolution [>][<][=] [X]", "device-aspect-ratio: X/Y", "orientation:portrait",
|
||||
"orientation:landscape", "device-height: [X]", "device-width: [X]"];
|
||||
var s = { attrs: {} }; // Simple tag, reused for a whole lot of tags
|
||||
|
||||
var data = {
|
||||
a: {
|
||||
attrs: {
|
||||
href: null, ping: null, type: null,
|
||||
media: media,
|
||||
target: targets,
|
||||
hreflang: langs
|
||||
}
|
||||
},
|
||||
abbr: s,
|
||||
acronym: s,
|
||||
address: s,
|
||||
applet: s,
|
||||
area: {
|
||||
attrs: {
|
||||
alt: null, coords: null, href: null, target: null, ping: null,
|
||||
media: media, hreflang: langs, type: null,
|
||||
shape: ["default", "rect", "circle", "poly"]
|
||||
}
|
||||
},
|
||||
article: s,
|
||||
aside: s,
|
||||
audio: {
|
||||
attrs: {
|
||||
src: null, mediagroup: null,
|
||||
crossorigin: ["anonymous", "use-credentials"],
|
||||
preload: ["none", "metadata", "auto"],
|
||||
autoplay: ["", "autoplay"],
|
||||
loop: ["", "loop"],
|
||||
controls: ["", "controls"]
|
||||
}
|
||||
},
|
||||
b: s,
|
||||
base: { attrs: { href: null, target: targets } },
|
||||
basefont: s,
|
||||
bdi: s,
|
||||
bdo: s,
|
||||
big: s,
|
||||
blockquote: { attrs: { cite: null } },
|
||||
body: s,
|
||||
br: s,
|
||||
button: {
|
||||
attrs: {
|
||||
form: null, formaction: null, name: null, value: null,
|
||||
autofocus: ["", "autofocus"],
|
||||
disabled: ["", "autofocus"],
|
||||
formenctype: encs,
|
||||
formmethod: methods,
|
||||
formnovalidate: ["", "novalidate"],
|
||||
formtarget: targets,
|
||||
type: ["submit", "reset", "button"]
|
||||
}
|
||||
},
|
||||
canvas: { attrs: { width: null, height: null } },
|
||||
caption: s,
|
||||
center: s,
|
||||
cite: s,
|
||||
code: s,
|
||||
col: { attrs: { span: null } },
|
||||
colgroup: { attrs: { span: null } },
|
||||
command: {
|
||||
attrs: {
|
||||
type: ["command", "checkbox", "radio"],
|
||||
label: null, icon: null, radiogroup: null, command: null, title: null,
|
||||
disabled: ["", "disabled"],
|
||||
checked: ["", "checked"]
|
||||
}
|
||||
},
|
||||
data: { attrs: { value: null } },
|
||||
datagrid: { attrs: { disabled: ["", "disabled"], multiple: ["", "multiple"] } },
|
||||
datalist: { attrs: { data: null } },
|
||||
dd: s,
|
||||
del: { attrs: { cite: null, datetime: null } },
|
||||
details: { attrs: { open: ["", "open"] } },
|
||||
dfn: s,
|
||||
dir: s,
|
||||
div: s,
|
||||
dl: s,
|
||||
dt: s,
|
||||
em: s,
|
||||
embed: { attrs: { src: null, type: null, width: null, height: null } },
|
||||
eventsource: { attrs: { src: null } },
|
||||
fieldset: { attrs: { disabled: ["", "disabled"], form: null, name: null } },
|
||||
figcaption: s,
|
||||
figure: s,
|
||||
font: s,
|
||||
footer: s,
|
||||
form: {
|
||||
attrs: {
|
||||
action: null, name: null,
|
||||
"accept-charset": charsets,
|
||||
autocomplete: ["on", "off"],
|
||||
enctype: encs,
|
||||
method: methods,
|
||||
novalidate: ["", "novalidate"],
|
||||
target: targets
|
||||
}
|
||||
},
|
||||
frame: s,
|
||||
frameset: s,
|
||||
h1: s, h2: s, h3: s, h4: s, h5: s, h6: s,
|
||||
head: {
|
||||
attrs: {},
|
||||
children: ["title", "base", "link", "style", "meta", "script", "noscript", "command"]
|
||||
},
|
||||
header: s,
|
||||
hgroup: s,
|
||||
hr: s,
|
||||
html: {
|
||||
attrs: { manifest: null },
|
||||
children: ["head", "body"]
|
||||
},
|
||||
i: s,
|
||||
iframe: {
|
||||
attrs: {
|
||||
src: null, srcdoc: null, name: null, width: null, height: null,
|
||||
sandbox: ["allow-top-navigation", "allow-same-origin", "allow-forms", "allow-scripts"],
|
||||
seamless: ["", "seamless"]
|
||||
}
|
||||
},
|
||||
img: {
|
||||
attrs: {
|
||||
alt: null, src: null, ismap: null, usemap: null, width: null, height: null,
|
||||
crossorigin: ["anonymous", "use-credentials"]
|
||||
}
|
||||
},
|
||||
input: {
|
||||
attrs: {
|
||||
alt: null, dirname: null, form: null, formaction: null,
|
||||
height: null, list: null, max: null, maxlength: null, min: null,
|
||||
name: null, pattern: null, placeholder: null, size: null, src: null,
|
||||
step: null, value: null, width: null,
|
||||
accept: ["audio/*", "video/*", "image/*"],
|
||||
autocomplete: ["on", "off"],
|
||||
autofocus: ["", "autofocus"],
|
||||
checked: ["", "checked"],
|
||||
disabled: ["", "disabled"],
|
||||
formenctype: encs,
|
||||
formmethod: methods,
|
||||
formnovalidate: ["", "novalidate"],
|
||||
formtarget: targets,
|
||||
multiple: ["", "multiple"],
|
||||
readonly: ["", "readonly"],
|
||||
required: ["", "required"],
|
||||
type: ["hidden", "text", "search", "tel", "url", "email", "password", "datetime", "date", "month",
|
||||
"week", "time", "datetime-local", "number", "range", "color", "checkbox", "radio",
|
||||
"file", "submit", "image", "reset", "button"]
|
||||
}
|
||||
},
|
||||
ins: { attrs: { cite: null, datetime: null } },
|
||||
kbd: s,
|
||||
keygen: {
|
||||
attrs: {
|
||||
challenge: null, form: null, name: null,
|
||||
autofocus: ["", "autofocus"],
|
||||
disabled: ["", "disabled"],
|
||||
keytype: ["RSA"]
|
||||
}
|
||||
},
|
||||
label: { attrs: { "for": null, form: null } },
|
||||
legend: s,
|
||||
li: { attrs: { value: null } },
|
||||
link: {
|
||||
attrs: {
|
||||
href: null, type: null,
|
||||
hreflang: langs,
|
||||
media: media,
|
||||
sizes: ["all", "16x16", "16x16 32x32", "16x16 32x32 64x64"]
|
||||
}
|
||||
},
|
||||
map: { attrs: { name: null } },
|
||||
mark: s,
|
||||
menu: { attrs: { label: null, type: ["list", "context", "toolbar"] } },
|
||||
meta: {
|
||||
attrs: {
|
||||
content: null,
|
||||
charset: charsets,
|
||||
name: ["viewport", "application-name", "author", "description", "generator", "keywords"],
|
||||
"http-equiv": ["content-language", "content-type", "default-style", "refresh"]
|
||||
}
|
||||
},
|
||||
meter: { attrs: { value: null, min: null, low: null, high: null, max: null, optimum: null } },
|
||||
nav: s,
|
||||
noframes: s,
|
||||
noscript: s,
|
||||
object: {
|
||||
attrs: {
|
||||
data: null, type: null, name: null, usemap: null, form: null, width: null, height: null,
|
||||
typemustmatch: ["", "typemustmatch"]
|
||||
}
|
||||
},
|
||||
ol: { attrs: { reversed: ["", "reversed"], start: null, type: ["1", "a", "A", "i", "I"] } },
|
||||
optgroup: { attrs: { disabled: ["", "disabled"], label: null } },
|
||||
option: { attrs: { disabled: ["", "disabled"], label: null, selected: ["", "selected"], value: null } },
|
||||
output: { attrs: { "for": null, form: null, name: null } },
|
||||
p: s,
|
||||
param: { attrs: { name: null, value: null } },
|
||||
pre: s,
|
||||
progress: { attrs: { value: null, max: null } },
|
||||
q: { attrs: { cite: null } },
|
||||
rp: s,
|
||||
rt: s,
|
||||
ruby: s,
|
||||
s: s,
|
||||
samp: s,
|
||||
script: {
|
||||
attrs: {
|
||||
type: ["text/javascript"],
|
||||
src: null,
|
||||
async: ["", "async"],
|
||||
defer: ["", "defer"],
|
||||
charset: charsets
|
||||
}
|
||||
},
|
||||
section: s,
|
||||
select: {
|
||||
attrs: {
|
||||
form: null, name: null, size: null,
|
||||
autofocus: ["", "autofocus"],
|
||||
disabled: ["", "disabled"],
|
||||
multiple: ["", "multiple"]
|
||||
}
|
||||
},
|
||||
small: s,
|
||||
source: { attrs: { src: null, type: null, media: null } },
|
||||
span: s,
|
||||
strike: s,
|
||||
strong: s,
|
||||
style: {
|
||||
attrs: {
|
||||
type: ["text/css"],
|
||||
media: media,
|
||||
scoped: null
|
||||
}
|
||||
},
|
||||
sub: s,
|
||||
summary: s,
|
||||
sup: s,
|
||||
table: s,
|
||||
tbody: s,
|
||||
td: { attrs: { colspan: null, rowspan: null, headers: null } },
|
||||
textarea: {
|
||||
attrs: {
|
||||
dirname: null, form: null, maxlength: null, name: null, placeholder: null,
|
||||
rows: null, cols: null,
|
||||
autofocus: ["", "autofocus"],
|
||||
disabled: ["", "disabled"],
|
||||
readonly: ["", "readonly"],
|
||||
required: ["", "required"],
|
||||
wrap: ["soft", "hard"]
|
||||
}
|
||||
},
|
||||
tfoot: s,
|
||||
th: { attrs: { colspan: null, rowspan: null, headers: null, scope: ["row", "col", "rowgroup", "colgroup"] } },
|
||||
thead: s,
|
||||
time: { attrs: { datetime: null } },
|
||||
title: s,
|
||||
tr: s,
|
||||
track: {
|
||||
attrs: {
|
||||
src: null, label: null, "default": null,
|
||||
kind: ["subtitles", "captions", "descriptions", "chapters", "metadata"],
|
||||
srclang: langs
|
||||
}
|
||||
},
|
||||
tt: s,
|
||||
u: s,
|
||||
ul: s,
|
||||
"var": s,
|
||||
video: {
|
||||
attrs: {
|
||||
src: null, poster: null, width: null, height: null,
|
||||
crossorigin: ["anonymous", "use-credentials"],
|
||||
preload: ["auto", "metadata", "none"],
|
||||
autoplay: ["", "autoplay"],
|
||||
mediagroup: ["movie"],
|
||||
muted: ["", "muted"],
|
||||
controls: ["", "controls"]
|
||||
}
|
||||
},
|
||||
wbr: s
|
||||
};
|
||||
|
||||
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"],
|
||||
"class": null,
|
||||
contenteditable: ["true", "false"],
|
||||
contextmenu: null,
|
||||
dir: ["ltr", "rtl", "auto"],
|
||||
draggable: ["true", "false", "auto"],
|
||||
dropzone: ["copy", "move", "link", "string:", "file:"],
|
||||
hidden: ["hidden"],
|
||||
id: null,
|
||||
inert: ["inert"],
|
||||
itemid: null,
|
||||
itemprop: null,
|
||||
itemref: null,
|
||||
itemscope: ["itemscope"],
|
||||
itemtype: null,
|
||||
lang: ["en", "es"],
|
||||
spellcheck: ["true", "false"],
|
||||
style: null,
|
||||
tabindex: ["1", "2", "3", "4", "5", "6", "7", "8", "9"],
|
||||
title: null,
|
||||
translate: ["yes", "no"],
|
||||
onclick: null,
|
||||
rel: ["stylesheet", "alternate", "author", "bookmark", "help", "license", "next", "nofollow", "noreferrer", "prefetch", "prev", "search", "tag"]
|
||||
};
|
||||
function populate(obj) {
|
||||
for (var attr in globalAttrs) if (globalAttrs.hasOwnProperty(attr))
|
||||
obj.attrs[attr] = globalAttrs[attr];
|
||||
}
|
||||
|
||||
populate(s);
|
||||
for (var tag in data) if (data.hasOwnProperty(tag) && data[tag] != s)
|
||||
populate(data[tag]);
|
||||
|
||||
CodeMirror.htmlSchema = data;
|
||||
function htmlHint(cm, options) {
|
||||
var local = {schemaInfo: data};
|
||||
if (options) for (var opt in options) local[opt] = options[opt];
|
||||
return CodeMirror.hint.xml(cm, local);
|
||||
}
|
||||
CodeMirror.registerHelper("hint", "html", htmlHint);
|
||||
});
|
@ -0,0 +1,146 @@
|
||||
// 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 Pos = CodeMirror.Pos;
|
||||
|
||||
function forEach(arr, f) {
|
||||
for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
|
||||
}
|
||||
|
||||
function arrayContains(arr, item) {
|
||||
if (!Array.prototype.indexOf) {
|
||||
var i = arr.length;
|
||||
while (i--) {
|
||||
if (arr[i] === item) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return arr.indexOf(item) != -1;
|
||||
}
|
||||
|
||||
function scriptHint(editor, keywords, getToken, options) {
|
||||
// Find the token at the cursor
|
||||
var cur = editor.getCursor(), token = getToken(editor, cur);
|
||||
if (/\b(?:string|comment)\b/.test(token.type)) return;
|
||||
token.state = CodeMirror.innerMode(editor.getMode(), token.state).state;
|
||||
|
||||
// If it's not a 'word-style' token, ignore the token.
|
||||
if (!/^[\w$_]*$/.test(token.string)) {
|
||||
token = {start: cur.ch, end: cur.ch, string: "", state: token.state,
|
||||
type: token.string == "." ? "property" : null};
|
||||
} else if (token.end > cur.ch) {
|
||||
token.end = cur.ch;
|
||||
token.string = token.string.slice(0, cur.ch - token.start);
|
||||
}
|
||||
|
||||
var tprop = token;
|
||||
// If it is a property, find out what it is a property of.
|
||||
while (tprop.type == "property") {
|
||||
tprop = getToken(editor, Pos(cur.line, tprop.start));
|
||||
if (tprop.string != ".") return;
|
||||
tprop = getToken(editor, Pos(cur.line, tprop.start));
|
||||
if (!context) var context = [];
|
||||
context.push(tprop);
|
||||
}
|
||||
return {list: getCompletions(token, context, keywords, options),
|
||||
from: Pos(cur.line, token.start),
|
||||
to: Pos(cur.line, token.end)};
|
||||
}
|
||||
|
||||
function javascriptHint(editor, options) {
|
||||
return scriptHint(editor, javascriptKeywords,
|
||||
function (e, cur) {return e.getTokenAt(cur);},
|
||||
options);
|
||||
};
|
||||
CodeMirror.registerHelper("hint", "javascript", javascriptHint);
|
||||
|
||||
function getCoffeeScriptToken(editor, cur) {
|
||||
// This getToken, it is for coffeescript, imitates the behavior of
|
||||
// getTokenAt method in javascript.js, that is, returning "property"
|
||||
// type and treat "." as indepenent token.
|
||||
var token = editor.getTokenAt(cur);
|
||||
if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') {
|
||||
token.end = token.start;
|
||||
token.string = '.';
|
||||
token.type = "property";
|
||||
}
|
||||
else if (/^\.[\w$_]*$/.test(token.string)) {
|
||||
token.type = "property";
|
||||
token.start++;
|
||||
token.string = token.string.replace(/\./, '');
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
function coffeescriptHint(editor, options) {
|
||||
return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken, options);
|
||||
}
|
||||
CodeMirror.registerHelper("hint", "coffeescript", coffeescriptHint);
|
||||
|
||||
var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " +
|
||||
"toUpperCase toLowerCase split concat match replace search").split(" ");
|
||||
var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " +
|
||||
"lastIndexOf every some filter forEach map reduce reduceRight ").split(" ");
|
||||
var funcProps = "prototype apply call bind".split(" ");
|
||||
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(" ");
|
||||
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(" ");
|
||||
|
||||
function getCompletions(token, context, keywords, options) {
|
||||
var found = [], start = token.string, global = options && options.globalScope || window;
|
||||
function maybeAdd(str) {
|
||||
if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str);
|
||||
}
|
||||
function gatherCompletions(obj) {
|
||||
if (typeof obj == "string") forEach(stringProps, maybeAdd);
|
||||
else if (obj instanceof Array) forEach(arrayProps, maybeAdd);
|
||||
else if (obj instanceof Function) forEach(funcProps, maybeAdd);
|
||||
for (var name in obj) maybeAdd(name);
|
||||
}
|
||||
|
||||
if (context && context.length) {
|
||||
// If this is a property, see if it belongs to some object we can
|
||||
// find in the current environment.
|
||||
var obj = context.pop(), base;
|
||||
if (obj.type && obj.type.indexOf("variable") === 0) {
|
||||
if (options && options.additionalContext)
|
||||
base = options.additionalContext[obj.string];
|
||||
if (!options || options.useGlobalScope !== false)
|
||||
base = base || global[obj.string];
|
||||
} else if (obj.type == "string") {
|
||||
base = "";
|
||||
} else if (obj.type == "atom") {
|
||||
base = 1;
|
||||
} else if (obj.type == "function") {
|
||||
if (global.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') &&
|
||||
(typeof global.jQuery == 'function'))
|
||||
base = global.jQuery();
|
||||
else if (global._ != null && (obj.string == '_') && (typeof global._ == 'function'))
|
||||
base = global._();
|
||||
}
|
||||
while (base != null && context.length)
|
||||
base = base[context.pop().string];
|
||||
if (base != null) gatherCompletions(base);
|
||||
} else {
|
||||
// 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)
|
||||
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);
|
||||
if (!options || options.useGlobalScope !== false)
|
||||
gatherCompletions(global);
|
||||
forEach(keywords, maybeAdd);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
});
|
@ -0,0 +1,38 @@
|
||||
.CodeMirror-hints {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
overflow: hidden;
|
||||
list-style: none;
|
||||
|
||||
margin: 0;
|
||||
padding: 2px;
|
||||
|
||||
-webkit-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);
|
||||
border-radius: 3px;
|
||||
border: 1px solid silver;
|
||||
|
||||
background: white;
|
||||
font-size: 90%;
|
||||
font-family: monospace;
|
||||
|
||||
max-height: 20em;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.CodeMirror-hint {
|
||||
margin: 0;
|
||||
padding: 0 4px;
|
||||
border-radius: 2px;
|
||||
max-width: 19em;
|
||||
overflow: hidden;
|
||||
white-space: pre;
|
||||
color: black;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
li.CodeMirror-hint-active {
|
||||
background: #08f;
|
||||
color: white;
|
||||
}
|