From eab5b06eacb35d347107fae683c9ffcb7a95a25f Mon Sep 17 00:00:00 2001 From: Golmote Date: Sun, 20 Sep 2015 16:00:59 +0200 Subject: [PATCH 01/17] Add support for Batch (Fix #398) --- components.js | 4 + components/prism-batch.js | 99 ++++++++++++++++++++ components/prism-batch.min.js | 1 + examples/prism-batch.html | 20 ++++ tests/languages/batch/command_feature.test | 103 +++++++++++++++++++++ tests/languages/batch/comment_feature.test | 18 ++++ tests/languages/batch/label_feature.test | 13 +++ 7 files changed, 258 insertions(+) create mode 100644 components/prism-batch.js create mode 100644 components/prism-batch.min.js create mode 100644 examples/prism-batch.html create mode 100644 tests/languages/batch/command_feature.test create mode 100644 tests/languages/batch/comment_feature.test create mode 100644 tests/languages/batch/label_feature.test diff --git a/components.js b/components.js index 51ee723bec..f35bd076b6 100644 --- a/components.js +++ b/components.js @@ -97,6 +97,10 @@ var components = { "title": "BASIC", "owner": "Golmote" }, + "batch": { + "title": "Batch", + "owner": "Golmote" + }, "bison": { "title": "Bison", "require": "c", diff --git a/components/prism-batch.js b/components/prism-batch.js new file mode 100644 index 0000000000..c7ca9ca60d --- /dev/null +++ b/components/prism-batch.js @@ -0,0 +1,99 @@ +(function (Prism) { + var variable = /%%?[~:\w]+%?|!\S+!/; + var parameter = { + pattern: /\/[a-z?]+(?=[ :]|$):?|-[a-z]\b|--[a-z-]+\b/im, + alias: 'attr-name', + inside: { + 'punctuation': /:/ + } + }; + var string = /"[^"]*"/; + var number = /(?:\b|-)\d+\b/; + + Prism.languages.batch = { + 'comment': [ + /^::.*/m, + { + pattern: /((?:^|[&(])[ \t]*)rem\b(?:[^^&)\r\n]|\^(?:\r\n|[\s\S]))*/im, + lookbehind: true + } + ], + 'label': { + pattern: /^:.*/m, + alias: 'property' + }, + 'command': [ + { + // FOR command + pattern: /((?:^|[&(])[ \t]*)for(?: ?\/[a-z?](?:[ :](?:"[^"]*"|\S+))?)* \S+ in \([^)]+\) do/im, + lookbehind: true, + inside: { + 'keyword': /^for\b|\b(?:in|do)\b/i, + 'string': string, + 'parameter': parameter, + 'variable': variable, + 'number': number, + 'punctuation': /[()',]/ + } + }, + { + // IF command + pattern: /((?:^|[&(])[ \t]*)if(?: ?\/[a-z?](?:[ :](?:"[^"]*"|\S+))?)* (?:not )?(?:cmdextversion \d+|defined \w+|errorlevel \d+|exist \S+|(?:"[^"]*"|\S+)?(?:==| (?:equ|neq|lss|leq|gtr|geq) )(?:"[^"]*"|\S+))/im, + lookbehind: true, + inside: { + 'keyword': /^if\b|\b(?:not|cmdextversion|defined|errorlevel|exist)\b/i, + 'string': string, + 'parameter': parameter, + 'variable': variable, + 'number': number, + 'operator': /\^|==|\b(?:equ|neq|lss|leq|gtr|geq)\b/i + } + }, + { + // ELSE command + pattern: /((?:^|[&()])[ \t]*)else\b/im, + lookbehind: true, + inside: { + 'keyword': /^else\b/i + } + }, + { + // SET command + pattern: /((?:^|[&(])[ \t]*)set(?: ?\/[a-z](?:[ :](?:"[^"]*"|\S+))?)* (?:[^^&)\r\n]|\^(?:\r\n|[\s\S]))*/im, + lookbehind: true, + inside: { + 'keyword': /^set\b/i, + 'string': string, + 'parameter': parameter, + 'variable': [ + variable, + /\w+(?=(?:[*\/%+\-&^|]|<<|>>)?=)/ + ], + 'number': number, + 'operator': /[*\/%+\-&^|]=?|<<=?|>>=?|[!~_=]/, + 'punctuation': /[()',]/ + } + }, + { + // Other commands + pattern: /((?:^|[&(])[ \t]*@?)\w+\b(?:[^^&)\r\n]|\^(?:\r\n|[\s\S]))*/im, + lookbehind: true, + inside: { + 'keyword': /^\w+\b/i, + 'string': string, + 'parameter': parameter, + 'label': { + pattern: /(^\s*):\S+/m, + lookbehind: true, + alias: 'property' + }, + 'variable': variable, + 'number': number, + 'operator': /\^/ + } + } + ], + 'operator': /[&@]/, + 'punctuation': /[()']/ + }; +}(Prism)); \ No newline at end of file diff --git a/components/prism-batch.min.js b/components/prism-batch.min.js new file mode 100644 index 0000000000..6ce5085710 --- /dev/null +++ b/components/prism-batch.min.js @@ -0,0 +1 @@ +!function(e){var r=/%%?[~:\w]+%?|!\S+!/,t={pattern:/\/[a-z?]+(?=[ :]|$):?|-[a-z]\b|--[a-z-]+\b/im,alias:"attr-name",inside:{punctuation:/:/}},n=/"[^"]*"/,i=/(?:\b|-)\d+\b/;e.languages.batch={comment:[/^::.*/m,{pattern:/((?:^|[&(])[ \t]*)rem\b(?:[^^&)\r\n]|\^(?:\r\n|[\s\S]))*/im,lookbehind:!0}],label:{pattern:/^:.*/m,alias:"property"},command:[{pattern:/((?:^|[&(])[ \t]*)for(?: ?\/[a-z?](?:[ :](?:"[^"]*"|\S+))?)* \S+ in \([^)]+\) do/im,lookbehind:!0,inside:{keyword:/^for\b|\b(?:in|do)\b/i,string:n,parameter:t,variable:r,number:i,punctuation:/[()',]/}},{pattern:/((?:^|[&(])[ \t]*)if(?: ?\/[a-z?](?:[ :](?:"[^"]*"|\S+))?)* (?:not )?(?:cmdextversion \d+|defined \w+|errorlevel \d+|exist \S+|(?:"[^"]*"|\S+)?(?:==| (?:equ|neq|lss|leq|gtr|geq) )(?:"[^"]*"|\S+))/im,lookbehind:!0,inside:{keyword:/^if\b|\b(?:not|cmdextversion|defined|errorlevel|exist)\b/i,string:n,parameter:t,variable:r,number:i,operator:/\^|==|\b(?:equ|neq|lss|leq|gtr|geq)\b/i}},{pattern:/((?:^|[&()])[ \t]*)else\b/im,lookbehind:!0,inside:{keyword:/^else\b/i}},{pattern:/((?:^|[&(])[ \t]*)set(?: ?\/[a-z](?:[ :](?:"[^"]*"|\S+))?)* (?:[^^&)\r\n]|\^(?:\r\n|[\s\S]))*/im,lookbehind:!0,inside:{keyword:/^set\b/i,string:n,parameter:t,variable:[r,/\w+(?=(?:[*\/%+\-&^|]|<<|>>)?=)/],number:i,operator:/[*\/%+\-&^|]=?|<<=?|>>=?|[!~_=]/,punctuation:/[()',]/}},{pattern:/((?:^|[&(])[ \t]*@?)\w+\b(?:[^^&)\r\n]|\^(?:\r\n|[\s\S]))*/im,lookbehind:!0,inside:{keyword:/^\w+\b/i,string:n,parameter:t,label:{pattern:/(^\s*):\S+/m,lookbehind:!0,alias:"property"},variable:r,number:i,operator:/\^/}}],operator:/[&@]/,punctuation:/[()']/}}(Prism); \ No newline at end of file diff --git a/examples/prism-batch.html b/examples/prism-batch.html new file mode 100644 index 0000000000..5a3ba7e9df --- /dev/null +++ b/examples/prism-batch.html @@ -0,0 +1,20 @@ +

Batch

+

To use this language, use the class "language-batch".

+ +

Comments

+
::
+:: Foo bar
+REM This is a comment too
+REM Multi-line ^
+comment
+ +

Labels

+
:foobar
+GOTO :EOF
+ +

Commands

+
@ECHO OFF
+FOR /l %%a in (5,-1,1) do (TITLE %title% -- closing in %%as)
+SET title=%~n0
+if /i "%InstSize:~0,1%"=="M" set maxcnt=3
+ping -n 2 -w 1 127.0.0.1
\ No newline at end of file diff --git a/tests/languages/batch/command_feature.test b/tests/languages/batch/command_feature.test new file mode 100644 index 0000000000..350788a8bd --- /dev/null +++ b/tests/languages/batch/command_feature.test @@ -0,0 +1,103 @@ +FOR /l %%a in (5,-1,1) do (TITLE %title% -- closing in %%as) +SET title=%~n0 +echo.Hello World +@ECHO OFF +if not defined ProgressFormat set "ProgressFormat=[PPPP]" +EXIT /b +set /a ProgressCnt+=1 +IF "%~1" NEQ "" (SET %~1=%new%) ELSE (echo.%new%) + +---------------------------------------------------- + +[ + ["command", [ + ["keyword", "FOR"], + ["parameter", ["/l"]], + ["variable", "%%a"], + ["keyword", "in"], + ["punctuation", "("], + ["number", "5"], ["punctuation", ","], + ["number", "-1"], ["punctuation", ","], + ["number", "1"], ["punctuation", ")"], + ["keyword", "do"] + ]], + ["punctuation", "("], + ["command", [ + ["keyword", "TITLE"], + ["variable", "%title%"], + " -- closing in ", + ["variable", "%%as"] + ]], + ["punctuation", ")"], + + ["command", [ + ["keyword", "SET"], + ["variable", "title"], + ["operator", "="], + ["variable", "%~n0"] + ]], + + ["command", [ + ["keyword", "echo"], + ".Hello World" + ]], + + ["operator", "@"], + ["command", [ + ["keyword", "ECHO"], + " OFF" + ]], + + ["command", [ + ["keyword", "if"], + ["keyword", "not"], + ["keyword", "defined"], + " ProgressFormat" + ]], + ["command", [ + ["keyword", "set"], + ["string", "\"ProgressFormat=[PPPP]\""] + ]], + + ["command", [ + ["keyword", "EXIT"], + ["parameter", ["/b"]] + ]], + + ["command", [ + ["keyword", "set"], + ["parameter", ["/a"]], + ["variable", "ProgressCnt"], + ["operator", "+="], + ["number", "1"] + ]], + + ["command", [ + ["keyword", "IF"], + ["string", "\"%~1\""], + ["operator", "NEQ"], + ["string", "\"\""] + ]], + ["punctuation", "("], + ["command", [ + ["keyword", "SET"], + ["variable", "%~1"], + ["operator", "="], + ["variable", "%new%"] + ]], + ["punctuation", ")"], + ["command", [ + ["keyword", "ELSE"] + ]], + ["punctuation", "("], + ["command", [ + ["keyword", "echo"], + ".", + ["variable", "%new%"] + ]], + ["punctuation", ")"] +] + +---------------------------------------------------- + +Checks for commands. \ No newline at end of file diff --git a/tests/languages/batch/comment_feature.test b/tests/languages/batch/comment_feature.test new file mode 100644 index 0000000000..83759d8e86 --- /dev/null +++ b/tests/languages/batch/comment_feature.test @@ -0,0 +1,18 @@ +:: +:: Foobar +REM Foobar +rem foo^ +bar + +---------------------------------------------------- + +[ + ["comment", "::"], + ["comment", ":: Foobar"], + ["comment", "REM Foobar"], + ["comment", "rem foo^\r\nbar"] +] + +---------------------------------------------------- + +Checks for comments. \ No newline at end of file diff --git a/tests/languages/batch/label_feature.test b/tests/languages/batch/label_feature.test new file mode 100644 index 0000000000..a672ba0cc3 --- /dev/null +++ b/tests/languages/batch/label_feature.test @@ -0,0 +1,13 @@ +:foo +:Foo_Bar + +---------------------------------------------------- + +[ + ["label", ":foo"], + ["label", ":Foo_Bar"] +] + +---------------------------------------------------- + +Checks for labels. \ No newline at end of file From 1ebac75ad28318779a42627363770f04a49b3346 Mon Sep 17 00:00:00 2001 From: Golmote Date: Wed, 30 Sep 2015 08:54:44 +0200 Subject: [PATCH 02/17] Plugin: gradient previewer --- components.js | 5 + .../previewer-base/prism-previewer-base.js | 12 +- .../prism-previewer-base.min.js | 2 +- plugins/previewer-gradient/index.html | 90 ++++++++ .../prism-previewer-gradient.css | 27 +++ .../prism-previewer-gradient.js | 205 ++++++++++++++++++ .../prism-previewer-gradient.min.js | 1 + 7 files changed, 337 insertions(+), 5 deletions(-) create mode 100644 plugins/previewer-gradient/index.html create mode 100644 plugins/previewer-gradient/prism-previewer-gradient.css create mode 100644 plugins/previewer-gradient/prism-previewer-gradient.js create mode 100644 plugins/previewer-gradient/prism-previewer-gradient.min.js diff --git a/components.js b/components.js index 39e5bdc337..d9526ed740 100644 --- a/components.js +++ b/components.js @@ -519,6 +519,11 @@ var components = { "require": "previewer-base", "owner": "Golmote" }, + "previewer-gradient": { + "title": "Previewer: Gradient", + "require": "previewer-base", + "owner": "Golmote" + }, "previewer-easing": { "title": "Previewer: Easing", "require": "previewer-base", diff --git a/plugins/previewer-base/prism-previewer-base.js b/plugins/previewer-base/prism-previewer-base.js index 570739f409..a735205af4 100644 --- a/plugins/previewer-base/prism-previewer-base.js +++ b/plugins/previewer-base/prism-previewer-base.js @@ -95,11 +95,15 @@ * @param token */ Previewer.prototype.check = function (token) { - if (tokenRegexp.test(token.className) && this._clsRegexp.test(token.className)) { - if (token !== this._token) { - this._token = token; - this.show(); + do { + if (tokenRegexp.test(token.className) && this._clsRegexp.test(token.className)) { + break; } + } while(token = token.parentNode); + + if (token && token !== this._token) { + this._token = token; + this.show(); } }; diff --git a/plugins/previewer-base/prism-previewer-base.min.js b/plugins/previewer-base/prism-previewer-base.min.js index 82bdc180af..830a5a35a8 100644 --- a/plugins/previewer-base/prism-previewer-base.min.js +++ b/plugins/previewer-base/prism-previewer-base.min.js @@ -1 +1 @@ -!function(){if("undefined"!=typeof self&&self.Prism&&self.document){var t=function(t){var e=0,s=0,i=t;if(i.parentNode){do e+=i.offsetLeft,s+=i.offsetTop;while((i=i.offsetParent)&&i.nodeType<9);i=t;do e-=i.scrollLeft,s-=i.scrollTop;while((i=i.parentNode)&&!/body/i.test(i.nodeName))}return{top:s,right:innerWidth-e-t.offsetWidth,bottom:innerHeight-s-t.offsetHeight,left:e}},e=/(?:^|\s)token(?=$|\s)/,s=/(?:^|\s)active(?=$|\s)/g,i=/(?:^|\s)flipped(?=$|\s)/g,o=function(t,e,s,i){this._elt=null,this._type=t,this._clsRegexp=RegExp("(?:^|\\s)"+t+"(?=$|\\s)"),this._token=null,this.updater=e,this._mouseout=this.mouseout.bind(this),this.initializer=i;var n=this;s||(s=["*"]),"Array"!==Prism.util.type(s)&&(s=[s]),s.forEach(function(t){"string"!=typeof t&&(t=t.lang),o.byLanguages[t]||(o.byLanguages[t]=[]),o.byLanguages[t].indexOf(n)<0&&o.byLanguages[t].push(n)})};o.prototype.init=function(){this._elt||(this._elt=document.createElement("div"),this._elt.className="prism-previewer prism-previewer-"+this._type,document.body.appendChild(this._elt),this.initializer&&this.initializer())},o.prototype.check=function(t){e.test(t.className)&&this._clsRegexp.test(t.className)&&t!==this._token&&(this._token=t,this.show())},o.prototype.mouseout=function(){this._token.removeEventListener("mouseout",this._mouseout,!1),this._token=null,this.hide()},o.prototype.show=function(){if(this._elt||this.init(),this._token)if(this.updater.call(this._elt,this._token.textContent)){this._token.addEventListener("mouseout",this._mouseout,!1);var e=t(this._token);this._elt.className+=" active",e.top-this._elt.offsetHeight>0?(this._elt.className=this._elt.className.replace(i,""),this._elt.style.top=e.top+"px",this._elt.style.bottom=""):(this._elt.className+=" flipped",this._elt.style.bottom=e.bottom+"px",this._elt.style.top=""),this._elt.style.left=e.left+Math.min(200,this._token.offsetWidth/2)+"px"}else this.hide()},o.prototype.hide=function(){this._elt.className=this._elt.className.replace(s,"")},o.byLanguages={},o.initEvents=function(t,e){var s=[];o.byLanguages[e]&&(s=s.concat(o.byLanguages[e])),o.byLanguages["*"]&&(s=s.concat(o.byLanguages["*"])),t.addEventListener("mouseover",function(t){var e=t.target;s.forEach(function(t){t.check(e)})},!1)},Prism.plugins.Previewer=o,Prism.hooks.add("after-highlight",function(t){(o.byLanguages["*"]||o.byLanguages[t.language])&&o.initEvents(t.element,t.language)})}}(); \ No newline at end of file +!function(){if("undefined"!=typeof self&&self.Prism&&self.document){var t=function(t){var e=0,s=0,i=t;if(i.parentNode){do e+=i.offsetLeft,s+=i.offsetTop;while((i=i.offsetParent)&&i.nodeType<9);i=t;do e-=i.scrollLeft,s-=i.scrollTop;while((i=i.parentNode)&&!/body/i.test(i.nodeName))}return{top:s,right:innerWidth-e-t.offsetWidth,bottom:innerHeight-s-t.offsetHeight,left:e}},e=/(?:^|\s)token(?=$|\s)/,s=/(?:^|\s)active(?=$|\s)/g,i=/(?:^|\s)flipped(?=$|\s)/g,o=function(t,e,s,i){this._elt=null,this._type=t,this._clsRegexp=RegExp("(?:^|\\s)"+t+"(?=$|\\s)"),this._token=null,this.updater=e,this._mouseout=this.mouseout.bind(this),this.initializer=i;var n=this;s||(s=["*"]),"Array"!==Prism.util.type(s)&&(s=[s]),s.forEach(function(t){"string"!=typeof t&&(t=t.lang),o.byLanguages[t]||(o.byLanguages[t]=[]),o.byLanguages[t].indexOf(n)<0&&o.byLanguages[t].push(n)})};o.prototype.init=function(){this._elt||(this._elt=document.createElement("div"),this._elt.className="prism-previewer prism-previewer-"+this._type,document.body.appendChild(this._elt),this.initializer&&this.initializer())},o.prototype.check=function(t){do if(e.test(t.className)&&this._clsRegexp.test(t.className))break;while(t=t.parentNode);t&&t!==this._token&&(this._token=t,this.show())},o.prototype.mouseout=function(){this._token.removeEventListener("mouseout",this._mouseout,!1),this._token=null,this.hide()},o.prototype.show=function(){if(this._elt||this.init(),this._token)if(this.updater.call(this._elt,this._token.textContent)){this._token.addEventListener("mouseout",this._mouseout,!1);var e=t(this._token);this._elt.className+=" active",e.top-this._elt.offsetHeight>0?(this._elt.className=this._elt.className.replace(i,""),this._elt.style.top=e.top+"px",this._elt.style.bottom=""):(this._elt.className+=" flipped",this._elt.style.bottom=e.bottom+"px",this._elt.style.top=""),this._elt.style.left=e.left+Math.min(200,this._token.offsetWidth/2)+"px"}else this.hide()},o.prototype.hide=function(){this._elt.className=this._elt.className.replace(s,"")},o.byLanguages={},o.initEvents=function(t,e){var s=[];o.byLanguages[e]&&(s=s.concat(o.byLanguages[e])),o.byLanguages["*"]&&(s=s.concat(o.byLanguages["*"])),t.addEventListener("mouseover",function(t){var e=t.target;s.forEach(function(t){t.check(e)})},!1)},Prism.plugins.Previewer=o,Prism.hooks.add("after-highlight",function(t){(o.byLanguages["*"]||o.byLanguages[t.language])&&o.initEvents(t.element,t.language)})}}(); \ No newline at end of file diff --git a/plugins/previewer-gradient/index.html b/plugins/previewer-gradient/index.html new file mode 100644 index 0000000000..e783ca8963 --- /dev/null +++ b/plugins/previewer-gradient/index.html @@ -0,0 +1,90 @@ + + + + + + + Previewer: Gradient ▲ Prism plugins + + + + + + + + + + + + +
+
+ +

Previewer: Gradient

+

Previewer for CSS gradients.

+
+ +
+

How to use

+ +

You don't need to do anything. With this plugin loaded, a previewer will appear on hovering the gradient values in code blocks.

+

Vendor-prefixed gradients are converted to W3C-valid ones, except the old Webkit syntax (-webkit-gradient(linear, ...) and -webkit-gradient(radial, ...)) is not supported.

+

This plugin is compatible with CSS, Less, Sass, Scss and Stylus.

+
+ +
+

Examples

+ +

CSS

+
div {
+	background: -moz-linear-gradient(left,  #cb60b3 0%, #c146a1 50%, #a80077 51%, #db36a4 100%); /* FF3.6+ */
+	background: -webkit-linear-gradient(left,  #cb60b3 0%,#c146a1 50%,#a80077 51%,#db36a4 100%); /* Chrome10+,Safari5.1+ */
+	background: -o-linear-gradient(left,  #cb60b3 0%,#c146a1 50%,#a80077 51%,#db36a4 100%); /* Opera 11.10+ */
+	background: -ms-linear-gradient(left,  #cb60b3 0%,#c146a1 50%,#a80077 51%,#db36a4 100%); /* IE10+ */
+	background: linear-gradient(to right,  #cb60b3 0%,#c146a1 50%,#a80077 51%,#db36a4 100%); /* W3C */
+}
+ +

Less

+
#header a {
+	background: -moz-linear-gradient(-45deg,  #9dd53a 0%, #a1d54f 50%, #80c217 51%, #7cbc0a 100%); /* FF3.6+ */
+	background: -webkit-linear-gradient(-45deg,  #9dd53a 0%,#a1d54f 50%,#80c217 51%,#7cbc0a 100%); /* Chrome10+,Safari5.1+ */
+	background: -o-linear-gradient(-45deg,  #9dd53a 0%,#a1d54f 50%,#80c217 51%,#7cbc0a 100%); /* Opera 11.10+ */
+	background: -ms-linear-gradient(-45deg,  #9dd53a 0%,#a1d54f 50%,#80c217 51%,#7cbc0a 100%); /* IE10+ */
+	background: linear-gradient(135deg,  #9dd53a 0%,#a1d54f 50%,#80c217 51%,#7cbc0a 100%); /* W3C */
+}
+ +

Sass

+
@mixin foobar
+	background: -moz-radial-gradient(center, ellipse cover,  #f2f6f8 0%, #d8e1e7 50%, #b5c6d0 51%, #e0eff9 100%)
+	background: radial-gradient(ellipse at center,  #f2f6f8 0%,#d8e1e7 50%,#b5c6d0 51%,#e0eff9 100%)
+
+ +

Scss

+
$attr: background;
+.foo {
+    #{$attr}-image: repeating-linear-gradient(10deg, rgba(255,0,0,0), rgba(255,0,0,1) 10px, rgba(255,0,0,0) 20px);
+}
+ +

Stylus

+
.foo
+	background-image: repeating-radial-gradient(circle, rgba(255,0,0,0), rgba(255,0,0,1) 10px, rgba(255,0,0,0) 20px)
+
+ +
+ +
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/previewer-gradient/prism-previewer-gradient.css b/plugins/previewer-gradient/prism-previewer-gradient.css new file mode 100644 index 0000000000..6152a6ef41 --- /dev/null +++ b/plugins/previewer-gradient/prism-previewer-gradient.css @@ -0,0 +1,27 @@ +.prism-previewer-gradient { + background-image: linear-gradient(45deg, #bbb 25%, transparent 25%, transparent 75%, #bbb 75%, #bbb), linear-gradient(45deg, #bbb 25%, #eee 25%, #eee 75%, #bbb 75%, #bbb); + background-size: 10px 10px; + background-position: 0 0, 5px 5px; + + width: 64px; + margin-left: -32px; +} +.prism-previewer-gradient:before { + content: none; +} +.prism-previewer-gradient div { + position: absolute; + top: -5px; + left: -5px; + right: -5px; + bottom: -5px; + -webkit-border-radius: 10px; + -moz-border-radius: 10px; + border-radius: 10px; + border: 5px solid #fff; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.5) inset, 0 0 10px rgba(0, 0, 0, 0.75); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.5) inset, 0 0 10px rgba(0, 0, 0, 0.75); + -ms-box-shadow: 0 0 3px rgba(0, 0, 0, 0.5) inset, 0 0 10px rgba(0, 0, 0, 0.75); + -o-box-shadow: 0 0 3px rgba(0, 0, 0, 0.5) inset, 0 0 10px rgba(0, 0, 0, 0.75); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.5) inset, 0 0 10px rgba(0, 0, 0, 0.75); +} \ No newline at end of file diff --git a/plugins/previewer-gradient/prism-previewer-gradient.js b/plugins/previewer-gradient/prism-previewer-gradient.js new file mode 100644 index 0000000000..089ebc772e --- /dev/null +++ b/plugins/previewer-gradient/prism-previewer-gradient.js @@ -0,0 +1,205 @@ +(function() { + + if ( + typeof self !== 'undefined' && !self.Prism || + typeof global !== 'undefined' && !global.Prism + ) { + return; + } + + var languages = { + 'css': true, + 'less': true, + 'sass': { + lang: 'sass', + before: 'punctuation', + inside: 'inside', + root: Prism.languages.sass && Prism.languages.sass['property-line'] + }, + 'scss': true, + 'stylus': [ + { + lang: 'stylus', + before: 'func', + inside: 'rest', + root: Prism.languages.stylus && Prism.languages.stylus['property-declaration'].inside + }, + { + lang: 'stylus', + before: 'hexcode', + inside: 'rest', + root: Prism.languages.stylus && Prism.languages.stylus['variable-declaration'].inside + } + ] + }; + + // Stores already processed gradients so that we don't + // make the conversion every time the previewer is shown + var cache = {}; + + /** + * Returns a W3C-valid linear gradient + * @param {string} prefix Vendor prefix if any ("-moz-", "-webkit-", etc.) + * @param {string} func Gradient function name ("linear-gradient") + * @param {string[]} values Array of the gradient function parameters (["0deg", "red 0%", "blue 100%"]) + */ + var convertToW3CLinearGradient = function(prefix, func, values) { + // Default value for angle + var angle = '180deg'; + + if (/^(?:-?\d*\.?\d+(?:deg|rad)|to\b|top|right|bottom|left)/.test(values[0])) { + angle = values.shift(); + if (angle.indexOf('to ') < 0) { + // Angle uses old keywords + // W3C syntax uses "to" + opposite keywords + if (angle.indexOf('top') >= 0) { + if (angle.indexOf('left') >= 0) { + angle = 'to bottom right'; + } else if (angle.indexOf('right') >= 0) { + angle = 'to bottom left'; + } else { + angle = 'to bottom'; + } + } else if (angle.indexOf('bottom') >= 0) { + if (angle.indexOf('left') >= 0) { + angle = 'to top right'; + } else if (angle.indexOf('right') >= 0) { + angle = 'to top left'; + } else { + angle = 'to top'; + } + } else if (angle.indexOf('left') >= 0) { + angle = 'to right'; + } else if (angle.indexOf('right') >= 0) { + angle = 'to left'; + } else if (prefix) { + // Angle is shifted by 90deg in prefixed gradients + if (angle.indexOf('deg') >= 0) { + angle = (90 - parseFloat(angle)) + 'deg'; + } else if (angle.indexOf('rad') >= 0) { + angle = (Math.PI / 2 - parseFloat(angle)) + 'rad'; + } + } + } + } + + return func + '(' + angle + ',' + values.join(',') + ')'; + }; + + /** + * Returns a W3C-valid radial gradient + * @param {string} prefix Vendor prefix if any ("-moz-", "-webkit-", etc.) + * @param {string} func Gradient function name ("linear-gradient") + * @param {string[]} values Array of the gradient function parameters (["0deg", "red 0%", "blue 100%"]) + */ + var convertToW3CRadialGradient = function(prefix, func, values) { + if (values[0].indexOf('at') < 0) { + // Looks like old syntax + + // Default values + var position = 'center'; + var shape = 'ellipse'; + var size = 'farthest-corner'; + + if (/\bcenter|top|right|bottom|left\b|^\d+/.test(values[0])) { + // Found a position + // Remove angle value, if any + position = values.shift().replace(/\s*-?\d+(?:rad|deg)\s*/, ''); + } + if (/\bcircle|ellipse|closest|farthest|contain|cover\b/.test(values[0])) { + // Found a shape and/or size + var shapeSizeParts = values.shift().split(/\s+/); + if (shapeSizeParts[0] && (shapeSizeParts[0] === 'circle' || shapeSizeParts[0] === 'ellipse')) { + shape = shapeSizeParts.shift(); + } + if (shapeSizeParts[0]) { + size = shapeSizeParts.shift(); + } + + // Old keywords are converted to their synonyms + if (size === 'cover') { + size = 'farthest-corner'; + } else if (size === 'contain') { + size = 'clothest-side'; + } + } + + return func + '(' + shape + ' ' + size + ' at ' + position + ',' + values.join(',') + ')'; + } + return func + '(' + values.join(',') + ')'; + }; + + /** + * Converts a gradient to a W3C-valid one + * Does not support old webkit syntax (-webkit-gradient(linear...) and -webkit-gradient(radial...)) + * @param {string} gradient The CSS gradient + */ + var convertToW3CGradient = function(gradient) { + if (cache[gradient]) { + return cache[gradient]; + } + var parts = gradient.match(/^(\b|\B-[a-z]{1,10}-)((?:repeating-)?(?:linear|radial)-gradient)/); + // "", "-moz-", etc. + var prefix = parts && parts[1]; + // "linear-gradient", "radial-gradient", etc. + var func = parts && parts[2]; + + var values = gradient.replace(/^(?:\b|\B-[a-z]{1,10}-)(?:repeating-)?(?:linear|radial)-gradient\(|\)$/g, '').split(/\s*,\s*/); + + if (func.indexOf('linear') >= 0) { + return cache[gradient] = convertToW3CLinearGradient(prefix, func, values); + } else if (func.indexOf('radial') >= 0) { + return cache[gradient] = convertToW3CRadialGradient(prefix, func, values); + } + return cache[gradient] = func + '(' + values.join(',') + ')'; + }; + + Prism.hooks.add('before-highlight', function (env) { + if (env.language && languages[env.language] && !languages[env.language].initialized) { + var lang = languages[env.language]; + if (Prism.util.type(lang) !== 'Array') { + lang = [lang]; + } + lang.forEach(function(lang) { + var before, inside, root, skip; + if (lang === true) { + before = 'important'; + inside = env.language; + lang = env.language; + } else { + before = lang.before || 'important'; + inside = lang.inside || lang.lang; + root = lang.root || Prism.languages; + skip = lang.skip; + lang = env.language; + } + + if (!skip && Prism.languages[lang]) { + Prism.languages.insertBefore(inside, before, { + 'gradient': { + pattern: /(?:\b|\B-[a-z]{1,10}-)(?:repeating-)?(?:linear|radial)-gradient\((?:(?:rgb|hsl)a?\(.+?\)|[^\)])+\)/gi, + inside: { + 'function': /[\w-]+(?=\()/, + 'punctuation': /[(),]/ + } + } + }, root); + env.grammar = Prism.languages[lang]; + + languages[env.language] = {initialized: true}; + } + }); + } + }); + + if (Prism.plugins.Previewer) { + new Prism.plugins.Previewer('gradient', function(value) { + this.firstChild.style.backgroundImage = ''; + this.firstChild.style.backgroundImage = convertToW3CGradient(value); + return !!this.firstChild.style.backgroundImage; + }, '*', function () { + this._elt.innerHTML = '
'; + }); + } + +}()); \ No newline at end of file diff --git a/plugins/previewer-gradient/prism-previewer-gradient.min.js b/plugins/previewer-gradient/prism-previewer-gradient.min.js new file mode 100644 index 0000000000..c3478e8cb0 --- /dev/null +++ b/plugins/previewer-gradient/prism-previewer-gradient.min.js @@ -0,0 +1 @@ +!function(){if(("undefined"==typeof self||self.Prism)&&("undefined"==typeof global||global.Prism)){var e={css:!0,less:!0,sass:{lang:"sass",inside:"inside",root:Prism.languages.sass&&Prism.languages.sass["property-line"]},scss:!0,stylus:[{lang:"stylus",before:"hexcode",inside:"rest",root:Prism.languages.stylus&&Prism.languages.stylus["property-declaration"].inside},{lang:"stylus",before:"hexcode",inside:"rest",root:Prism.languages.stylus&&Prism.languages.stylus["variable-declaration"].inside}]},i={},t=function(e,i,t){var a="180deg";return/^(?:\d*\.?\d+(?:deg|rad)|to\b|top|right|bottom|left)/.test(t[0])&&(a=t.shift(),a.indexOf("to ")<0&&(a.indexOf("top")>=0?a=a.indexOf("left")>=0?"to bottom right":a.indexOf("right")>=0?"to bottom left":"to bottom":a.indexOf("bottom")>=0?a=a.indexOf("left")>=0?"to top right":a.indexOf("right")>=0?"to top left":"to top":a.indexOf("left")>=0?a="to right":a.indexOf("right")>=0?a="to left":e&&(a.indexOf("deg")>=0?a=90-parseFloat(a)+"deg":a.indexOf("rad")>=0&&(a=Math.PI/2-parseFloat(a)+"rad")))),i+"("+a+","+t.join(",")+")"},a=function(e,i,t){if(t[0].indexOf("at")<0){var a="center",r="ellipse",n="farthest-corner";if(/\bcenter|top|right|bottom|left\b|^\d+/.test(t[0])&&(a=t.shift().replace(/\s*\d+(?:rad|deg)\s*/,"")),/\bcircle|ellipse|closest|farthest|contain|cover\b/.test(t[0])){var s=t.shift().split(/\s+/);!s[0]||"circle"!==s[0]&&"ellipse"!==s[0]||(r=s.shift()),s[0]&&(n=s.shift()),"cover"===n?n="farthest-corner":"contain"===n&&(n="clothest-side")}return i+"("+r+" "+n+" at "+a+","+t.join(",")+")"}return i+"("+t.join(",")+")"},r=function(e){if(i[e])return i[e];var r=e.match(/^(\b|\B-[a-z]{1,10}-)((?:repeating-)?(?:linear|radial)-gradient)/),n=r&&r[1],s=r&&r[2],l=e.replace(/^(?:\b|\B-[a-z]{1,10}-)(?:repeating-)?(?:linear|radial)-gradient\(|\)$/g,"").split(/\s*,\s*/);return i[e]=s.indexOf("linear")>=0?t(n,s,l):s.indexOf("radial")>=0?a(n,s,l):s+"("+l.join(",")+")"};Prism.hooks.add("before-highlight",function(i){if(i.language&&e[i.language]&&!e[i.language].initialized){var t=e[i.language];"Array"!==Prism.util.type(t)&&(t=[t]),t.forEach(function(t){var a,r,n,s;t===!0?(a="important",r=i.language,t=i.language):(a=t.before||"important",r=t.inside||t.lang,n=t.root||Prism.languages,s=t.skip,t=i.language),!s&&Prism.languages[t]&&(Prism.languages.insertBefore(r,a,{gradient:{pattern:/(?:\b|\B-[a-z]{1,10}-)(?:repeating-)?(?:linear|radial)-gradient\((?:(?:rgb|hsl)a?\(.+?\)|[^\)])+\)/gi,inside:{"function":/[\w-]+(?=\()/,punctuation:/[(),]/}}},n),i.grammar=Prism.languages[t],e[i.language]={initialized:!0})})}}),Prism.plugins.Previewer&&new Prism.plugins.Previewer("gradient",function(e){return this.firstChild.style.backgroundImage="",this.firstChild.style.backgroundImage=r(e),!!this.firstChild.style.backgroundImage},"*",function(){this._elt.innerHTML="
"})}}(); \ No newline at end of file From d37d6b86e0d726b618713f9aa0da039dc3e23545 Mon Sep 17 00:00:00 2001 From: Golmote Date: Thu, 1 Oct 2015 09:01:50 +0200 Subject: [PATCH 03/17] Previewer: gradient: Fix stylus var declaration + insert before Color Previewer if it exists --- .../previewer-base/prism-previewer-base.js | 7 ++ .../prism-previewer-base.min.js | 2 +- .../prism-previewer-gradient.js | 77 ++++++++++--------- .../prism-previewer-gradient.min.js | 2 +- 4 files changed, 49 insertions(+), 39 deletions(-) diff --git a/plugins/previewer-base/prism-previewer-base.js b/plugins/previewer-base/prism-previewer-base.js index a735205af4..a5eb59adc6 100644 --- a/plugins/previewer-base/prism-previewer-base.js +++ b/plugins/previewer-base/prism-previewer-base.js @@ -73,6 +73,7 @@ Previewer.byLanguages[lang].push(self); } }); + Previewer.byType[type] = this; }; /** @@ -162,6 +163,12 @@ */ Previewer.byLanguages = {}; + /** + * Map of all registered previewers by type + * @type {{}} + */ + Previewer.byType = {}; + /** * Initializes the mouseover event on the code block. * @param {HTMLElement} elt The code block (env.element) diff --git a/plugins/previewer-base/prism-previewer-base.min.js b/plugins/previewer-base/prism-previewer-base.min.js index 830a5a35a8..90e1b2e462 100644 --- a/plugins/previewer-base/prism-previewer-base.min.js +++ b/plugins/previewer-base/prism-previewer-base.min.js @@ -1 +1 @@ -!function(){if("undefined"!=typeof self&&self.Prism&&self.document){var t=function(t){var e=0,s=0,i=t;if(i.parentNode){do e+=i.offsetLeft,s+=i.offsetTop;while((i=i.offsetParent)&&i.nodeType<9);i=t;do e-=i.scrollLeft,s-=i.scrollTop;while((i=i.parentNode)&&!/body/i.test(i.nodeName))}return{top:s,right:innerWidth-e-t.offsetWidth,bottom:innerHeight-s-t.offsetHeight,left:e}},e=/(?:^|\s)token(?=$|\s)/,s=/(?:^|\s)active(?=$|\s)/g,i=/(?:^|\s)flipped(?=$|\s)/g,o=function(t,e,s,i){this._elt=null,this._type=t,this._clsRegexp=RegExp("(?:^|\\s)"+t+"(?=$|\\s)"),this._token=null,this.updater=e,this._mouseout=this.mouseout.bind(this),this.initializer=i;var n=this;s||(s=["*"]),"Array"!==Prism.util.type(s)&&(s=[s]),s.forEach(function(t){"string"!=typeof t&&(t=t.lang),o.byLanguages[t]||(o.byLanguages[t]=[]),o.byLanguages[t].indexOf(n)<0&&o.byLanguages[t].push(n)})};o.prototype.init=function(){this._elt||(this._elt=document.createElement("div"),this._elt.className="prism-previewer prism-previewer-"+this._type,document.body.appendChild(this._elt),this.initializer&&this.initializer())},o.prototype.check=function(t){do if(e.test(t.className)&&this._clsRegexp.test(t.className))break;while(t=t.parentNode);t&&t!==this._token&&(this._token=t,this.show())},o.prototype.mouseout=function(){this._token.removeEventListener("mouseout",this._mouseout,!1),this._token=null,this.hide()},o.prototype.show=function(){if(this._elt||this.init(),this._token)if(this.updater.call(this._elt,this._token.textContent)){this._token.addEventListener("mouseout",this._mouseout,!1);var e=t(this._token);this._elt.className+=" active",e.top-this._elt.offsetHeight>0?(this._elt.className=this._elt.className.replace(i,""),this._elt.style.top=e.top+"px",this._elt.style.bottom=""):(this._elt.className+=" flipped",this._elt.style.bottom=e.bottom+"px",this._elt.style.top=""),this._elt.style.left=e.left+Math.min(200,this._token.offsetWidth/2)+"px"}else this.hide()},o.prototype.hide=function(){this._elt.className=this._elt.className.replace(s,"")},o.byLanguages={},o.initEvents=function(t,e){var s=[];o.byLanguages[e]&&(s=s.concat(o.byLanguages[e])),o.byLanguages["*"]&&(s=s.concat(o.byLanguages["*"])),t.addEventListener("mouseover",function(t){var e=t.target;s.forEach(function(t){t.check(e)})},!1)},Prism.plugins.Previewer=o,Prism.hooks.add("after-highlight",function(t){(o.byLanguages["*"]||o.byLanguages[t.language])&&o.initEvents(t.element,t.language)})}}(); \ No newline at end of file +!function(){if("undefined"!=typeof self&&self.Prism&&self.document){var t=function(t){var e=0,s=0,i=t;if(i.parentNode){do e+=i.offsetLeft,s+=i.offsetTop;while((i=i.offsetParent)&&i.nodeType<9);i=t;do e-=i.scrollLeft,s-=i.scrollTop;while((i=i.parentNode)&&!/body/i.test(i.nodeName))}return{top:s,right:innerWidth-e-t.offsetWidth,bottom:innerHeight-s-t.offsetHeight,left:e}},e=/(?:^|\s)token(?=$|\s)/,s=/(?:^|\s)active(?=$|\s)/g,i=/(?:^|\s)flipped(?=$|\s)/g,o=function(t,e,s,i){this._elt=null,this._type=t,this._clsRegexp=RegExp("(?:^|\\s)"+t+"(?=$|\\s)"),this._token=null,this.updater=e,this._mouseout=this.mouseout.bind(this),this.initializer=i;var n=this;s||(s=["*"]),"Array"!==Prism.util.type(s)&&(s=[s]),s.forEach(function(t){"string"!=typeof t&&(t=t.lang),o.byLanguages[t]||(o.byLanguages[t]=[]),o.byLanguages[t].indexOf(n)<0&&o.byLanguages[t].push(n)}),o.byType[t]=this};o.prototype.init=function(){this._elt||(this._elt=document.createElement("div"),this._elt.className="prism-previewer prism-previewer-"+this._type,document.body.appendChild(this._elt),this.initializer&&this.initializer())},o.prototype.check=function(t){do if(e.test(t.className)&&this._clsRegexp.test(t.className))break;while(t=t.parentNode);t&&t!==this._token&&(this._token=t,this.show())},o.prototype.mouseout=function(){this._token.removeEventListener("mouseout",this._mouseout,!1),this._token=null,this.hide()},o.prototype.show=function(){if(this._elt||this.init(),this._token)if(this.updater.call(this._elt,this._token.textContent)){this._token.addEventListener("mouseout",this._mouseout,!1);var e=t(this._token);this._elt.className+=" active",e.top-this._elt.offsetHeight>0?(this._elt.className=this._elt.className.replace(i,""),this._elt.style.top=e.top+"px",this._elt.style.bottom=""):(this._elt.className+=" flipped",this._elt.style.bottom=e.bottom+"px",this._elt.style.top=""),this._elt.style.left=e.left+Math.min(200,this._token.offsetWidth/2)+"px"}else this.hide()},o.prototype.hide=function(){this._elt.className=this._elt.className.replace(s,"")},o.byLanguages={},o.byType={},o.initEvents=function(t,e){var s=[];o.byLanguages[e]&&(s=s.concat(o.byLanguages[e])),o.byLanguages["*"]&&(s=s.concat(o.byLanguages["*"])),t.addEventListener("mouseover",function(t){var e=t.target;s.forEach(function(t){t.check(e)})},!1)},Prism.plugins.Previewer=o,Prism.hooks.add("after-highlight",function(t){(o.byLanguages["*"]||o.byLanguages[t.language])&&o.initEvents(t.element,t.language)})}}(); \ No newline at end of file diff --git a/plugins/previewer-gradient/prism-previewer-gradient.js b/plugins/previewer-gradient/prism-previewer-gradient.js index 089ebc772e..b2b6b4a17b 100644 --- a/plugins/previewer-gradient/prism-previewer-gradient.js +++ b/plugins/previewer-gradient/prism-previewer-gradient.js @@ -26,13 +26,52 @@ }, { lang: 'stylus', - before: 'hexcode', + before: 'func', inside: 'rest', root: Prism.languages.stylus && Prism.languages.stylus['variable-declaration'].inside } ] }; + Prism.hooks.add('before-highlight', function (env) { + if (env.language && languages[env.language] && !languages[env.language].initialized) { + var lang = languages[env.language]; + if (Prism.util.type(lang) !== 'Array') { + lang = [lang]; + } + lang.forEach(function(lang) { + var before, inside, root, skip; + if (lang === true) { + // Insert before color previewer if it exists + before = Prism.plugins.Previewer && Prism.plugins.Previewer.byType['color'] ? 'color' : 'important'; + inside = env.language; + lang = env.language; + } else { + before = lang.before || 'important'; + inside = lang.inside || lang.lang; + root = lang.root || Prism.languages; + skip = lang.skip; + lang = env.language; + } + + if (!skip && Prism.languages[lang]) { + Prism.languages.insertBefore(inside, before, { + 'gradient': { + pattern: /(?:\b|\B-[a-z]{1,10}-)(?:repeating-)?(?:linear|radial)-gradient\((?:(?:rgb|hsl)a?\(.+?\)|[^\)])+\)/gi, + inside: { + 'function': /[\w-]+(?=\()/, + 'punctuation': /[(),]/ + } + } + }, root); + env.grammar = Prism.languages[lang]; + + languages[env.language] = {initialized: true}; + } + }); + } + }); + // Stores already processed gradients so that we don't // make the conversion every time the previewer is shown var cache = {}; @@ -154,43 +193,7 @@ return cache[gradient] = func + '(' + values.join(',') + ')'; }; - Prism.hooks.add('before-highlight', function (env) { - if (env.language && languages[env.language] && !languages[env.language].initialized) { - var lang = languages[env.language]; - if (Prism.util.type(lang) !== 'Array') { - lang = [lang]; - } - lang.forEach(function(lang) { - var before, inside, root, skip; - if (lang === true) { - before = 'important'; - inside = env.language; - lang = env.language; - } else { - before = lang.before || 'important'; - inside = lang.inside || lang.lang; - root = lang.root || Prism.languages; - skip = lang.skip; - lang = env.language; - } - - if (!skip && Prism.languages[lang]) { - Prism.languages.insertBefore(inside, before, { - 'gradient': { - pattern: /(?:\b|\B-[a-z]{1,10}-)(?:repeating-)?(?:linear|radial)-gradient\((?:(?:rgb|hsl)a?\(.+?\)|[^\)])+\)/gi, - inside: { - 'function': /[\w-]+(?=\()/, - 'punctuation': /[(),]/ - } - } - }, root); - env.grammar = Prism.languages[lang]; - languages[env.language] = {initialized: true}; - } - }); - } - }); if (Prism.plugins.Previewer) { new Prism.plugins.Previewer('gradient', function(value) { diff --git a/plugins/previewer-gradient/prism-previewer-gradient.min.js b/plugins/previewer-gradient/prism-previewer-gradient.min.js index c3478e8cb0..35322d4b65 100644 --- a/plugins/previewer-gradient/prism-previewer-gradient.min.js +++ b/plugins/previewer-gradient/prism-previewer-gradient.min.js @@ -1 +1 @@ -!function(){if(("undefined"==typeof self||self.Prism)&&("undefined"==typeof global||global.Prism)){var e={css:!0,less:!0,sass:{lang:"sass",inside:"inside",root:Prism.languages.sass&&Prism.languages.sass["property-line"]},scss:!0,stylus:[{lang:"stylus",before:"hexcode",inside:"rest",root:Prism.languages.stylus&&Prism.languages.stylus["property-declaration"].inside},{lang:"stylus",before:"hexcode",inside:"rest",root:Prism.languages.stylus&&Prism.languages.stylus["variable-declaration"].inside}]},i={},t=function(e,i,t){var a="180deg";return/^(?:\d*\.?\d+(?:deg|rad)|to\b|top|right|bottom|left)/.test(t[0])&&(a=t.shift(),a.indexOf("to ")<0&&(a.indexOf("top")>=0?a=a.indexOf("left")>=0?"to bottom right":a.indexOf("right")>=0?"to bottom left":"to bottom":a.indexOf("bottom")>=0?a=a.indexOf("left")>=0?"to top right":a.indexOf("right")>=0?"to top left":"to top":a.indexOf("left")>=0?a="to right":a.indexOf("right")>=0?a="to left":e&&(a.indexOf("deg")>=0?a=90-parseFloat(a)+"deg":a.indexOf("rad")>=0&&(a=Math.PI/2-parseFloat(a)+"rad")))),i+"("+a+","+t.join(",")+")"},a=function(e,i,t){if(t[0].indexOf("at")<0){var a="center",r="ellipse",n="farthest-corner";if(/\bcenter|top|right|bottom|left\b|^\d+/.test(t[0])&&(a=t.shift().replace(/\s*\d+(?:rad|deg)\s*/,"")),/\bcircle|ellipse|closest|farthest|contain|cover\b/.test(t[0])){var s=t.shift().split(/\s+/);!s[0]||"circle"!==s[0]&&"ellipse"!==s[0]||(r=s.shift()),s[0]&&(n=s.shift()),"cover"===n?n="farthest-corner":"contain"===n&&(n="clothest-side")}return i+"("+r+" "+n+" at "+a+","+t.join(",")+")"}return i+"("+t.join(",")+")"},r=function(e){if(i[e])return i[e];var r=e.match(/^(\b|\B-[a-z]{1,10}-)((?:repeating-)?(?:linear|radial)-gradient)/),n=r&&r[1],s=r&&r[2],l=e.replace(/^(?:\b|\B-[a-z]{1,10}-)(?:repeating-)?(?:linear|radial)-gradient\(|\)$/g,"").split(/\s*,\s*/);return i[e]=s.indexOf("linear")>=0?t(n,s,l):s.indexOf("radial")>=0?a(n,s,l):s+"("+l.join(",")+")"};Prism.hooks.add("before-highlight",function(i){if(i.language&&e[i.language]&&!e[i.language].initialized){var t=e[i.language];"Array"!==Prism.util.type(t)&&(t=[t]),t.forEach(function(t){var a,r,n,s;t===!0?(a="important",r=i.language,t=i.language):(a=t.before||"important",r=t.inside||t.lang,n=t.root||Prism.languages,s=t.skip,t=i.language),!s&&Prism.languages[t]&&(Prism.languages.insertBefore(r,a,{gradient:{pattern:/(?:\b|\B-[a-z]{1,10}-)(?:repeating-)?(?:linear|radial)-gradient\((?:(?:rgb|hsl)a?\(.+?\)|[^\)])+\)/gi,inside:{"function":/[\w-]+(?=\()/,punctuation:/[(),]/}}},n),i.grammar=Prism.languages[t],e[i.language]={initialized:!0})})}}),Prism.plugins.Previewer&&new Prism.plugins.Previewer("gradient",function(e){return this.firstChild.style.backgroundImage="",this.firstChild.style.backgroundImage=r(e),!!this.firstChild.style.backgroundImage},"*",function(){this._elt.innerHTML="
"})}}(); \ No newline at end of file +!function(){if(("undefined"==typeof self||self.Prism)&&("undefined"==typeof global||global.Prism)){var e={css:!0,less:!0,sass:{lang:"sass",before:"punctuation",inside:"inside",root:Prism.languages.sass&&Prism.languages.sass["property-line"]},scss:!0,stylus:[{lang:"stylus",before:"func",inside:"rest",root:Prism.languages.stylus&&Prism.languages.stylus["property-declaration"].inside},{lang:"stylus",before:"func",inside:"rest",root:Prism.languages.stylus&&Prism.languages.stylus["variable-declaration"].inside}]};Prism.hooks.add("before-highlight",function(i){if(i.language&&e[i.language]&&!e[i.language].initialized){var t=e[i.language];"Array"!==Prism.util.type(t)&&(t=[t]),t.forEach(function(t){var r,a,n,s;t===!0?(r=Prism.plugins.Previewer&&Prism.plugins.Previewer.byType.color?"color":"important",a=i.language,t=i.language):(r=t.before||"important",a=t.inside||t.lang,n=t.root||Prism.languages,s=t.skip,t=i.language),!s&&Prism.languages[t]&&(Prism.languages.insertBefore(a,r,{gradient:{pattern:/(?:\b|\B-[a-z]{1,10}-)(?:repeating-)?(?:linear|radial)-gradient\((?:(?:rgb|hsl)a?\(.+?\)|[^\)])+\)/gi,inside:{"function":/[\w-]+(?=\()/,punctuation:/[(),]/}}},n),i.grammar=Prism.languages[t],e[i.language]={initialized:!0})})}});var i={},t=function(e,i,t){var r="180deg";return/^(?:-?\d*\.?\d+(?:deg|rad)|to\b|top|right|bottom|left)/.test(t[0])&&(r=t.shift(),r.indexOf("to ")<0&&(r.indexOf("top")>=0?r=r.indexOf("left")>=0?"to bottom right":r.indexOf("right")>=0?"to bottom left":"to bottom":r.indexOf("bottom")>=0?r=r.indexOf("left")>=0?"to top right":r.indexOf("right")>=0?"to top left":"to top":r.indexOf("left")>=0?r="to right":r.indexOf("right")>=0?r="to left":e&&(r.indexOf("deg")>=0?r=90-parseFloat(r)+"deg":r.indexOf("rad")>=0&&(r=Math.PI/2-parseFloat(r)+"rad")))),i+"("+r+","+t.join(",")+")"},r=function(e,i,t){if(t[0].indexOf("at")<0){var r="center",a="ellipse",n="farthest-corner";if(/\bcenter|top|right|bottom|left\b|^\d+/.test(t[0])&&(r=t.shift().replace(/\s*-?\d+(?:rad|deg)\s*/,"")),/\bcircle|ellipse|closest|farthest|contain|cover\b/.test(t[0])){var s=t.shift().split(/\s+/);!s[0]||"circle"!==s[0]&&"ellipse"!==s[0]||(a=s.shift()),s[0]&&(n=s.shift()),"cover"===n?n="farthest-corner":"contain"===n&&(n="clothest-side")}return i+"("+a+" "+n+" at "+r+","+t.join(",")+")"}return i+"("+t.join(",")+")"},a=function(e){if(i[e])return i[e];var a=e.match(/^(\b|\B-[a-z]{1,10}-)((?:repeating-)?(?:linear|radial)-gradient)/),n=a&&a[1],s=a&&a[2],l=e.replace(/^(?:\b|\B-[a-z]{1,10}-)(?:repeating-)?(?:linear|radial)-gradient\(|\)$/g,"").split(/\s*,\s*/);return i[e]=s.indexOf("linear")>=0?t(n,s,l):s.indexOf("radial")>=0?r(n,s,l):s+"("+l.join(",")+")"};Prism.plugins.Previewer&&new Prism.plugins.Previewer("gradient",function(e){return this.firstChild.style.backgroundImage="",this.firstChild.style.backgroundImage=a(e),!!this.firstChild.style.backgroundImage},"*",function(){this._elt.innerHTML="
"})}}(); \ No newline at end of file From 752650e0e48e834c316b96ae3712d3182f71b2db Mon Sep 17 00:00:00 2001 From: Golmote Date: Sat, 3 Oct 2015 09:13:04 +0200 Subject: [PATCH 04/17] Plugin: time previewer --- components.js | 5 + plugins/previewer-time/index.html | 85 ++++++++++++++++ .../previewer-time/prism-previewer-time.css | 90 +++++++++++++++++ .../previewer-time/prism-previewer-time.js | 98 +++++++++++++++++++ .../prism-previewer-time.min.js | 1 + 5 files changed, 279 insertions(+) create mode 100644 plugins/previewer-time/index.html create mode 100644 plugins/previewer-time/prism-previewer-time.css create mode 100644 plugins/previewer-time/prism-previewer-time.js create mode 100644 plugins/previewer-time/prism-previewer-time.min.js diff --git a/components.js b/components.js index 39e5bdc337..6d76047b7e 100644 --- a/components.js +++ b/components.js @@ -524,6 +524,11 @@ var components = { "require": "previewer-base", "owner": "Golmote" }, + "previewer-time": { + "title": "Previewer: Time", + "require": "previewer-base", + "owner": "Golmote" + }, "autoloader": { "title": "Autoloader", "owner": "Golmote", diff --git a/plugins/previewer-time/index.html b/plugins/previewer-time/index.html new file mode 100644 index 0000000000..eb0ac21309 --- /dev/null +++ b/plugins/previewer-time/index.html @@ -0,0 +1,85 @@ + + + + + + + Previewer: Time ▲ Prism plugins + + + + + + + + + + + + +
+
+ +

Previewer: Time

+

Previewer for CSS times.

+
+ +
+

How to use

+ +

You don't need to do anything. With this plugin loaded, a previewer will appear on hovering the time values in code blocks.

+

This plugin is compatible with CSS, Less, Sass, Scss and Stylus.

+
+ +
+

Examples

+ +

CSS

+
div {
+	transition: all linear 3s;
+}
+ +

Less

+
@time: 1s;
+#header a {
+	transition: all linear 2s;
+}
+ +

Sass

+
$time: 3s
+@mixin foobar
+	transition: all linear 800ms
+.foo
+	transition: all linear 0.8s
+
+ +

Scss

+
$time: 1s;
+.foo {
+	transition: all linear 10s
+}
+ +

Stylus

+
time = 3s
+.foo
+	transition: all linear 0.5s
+
+ +
+ +
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/previewer-time/prism-previewer-time.css b/plugins/previewer-time/prism-previewer-time.css new file mode 100644 index 0000000000..d0363a2a3b --- /dev/null +++ b/plugins/previewer-time/prism-previewer-time.css @@ -0,0 +1,90 @@ +@-webkit-keyframes prism-previewer-time { + 0% { + stroke-dasharray: 0, 500; + stroke-dashoffset: 0; + } + 50% { + stroke-dasharray: 100, 500; + stroke-dashoffset: 0; + } + 100% { + stroke-dasharray: 0, 500; + stroke-dashoffset: -100; + } +} + +@-o-keyframes prism-previewer-time { + 0% { + stroke-dasharray: 0, 500; + stroke-dashoffset: 0; + } + 50% { + stroke-dasharray: 100, 500; + stroke-dashoffset: 0; + } + 100% { + stroke-dasharray: 0, 500; + stroke-dashoffset: -100; + } +} + +@-moz-keyframes prism-previewer-time { + 0% { + stroke-dasharray: 0, 500; + stroke-dashoffset: 0; + } + 50% { + stroke-dasharray: 100, 500; + stroke-dashoffset: 0; + } + 100% { + stroke-dasharray: 0, 500; + stroke-dashoffset: -100; + } +} + +@keyframes prism-previewer-time { + 0% { + stroke-dasharray: 0, 500; + stroke-dashoffset: 0; + } + 50% { + stroke-dasharray: 100, 500; + stroke-dashoffset: 0; + } + 100% { + stroke-dasharray: 0, 500; + stroke-dashoffset: -100; + } +} + +.prism-previewer-time:before { + -webkit-border-radius: 50%; + -moz-border-radius: 50%; + border-radius: 50%; + background: #fff; +} +.prism-previewer-time:after { + margin-top: 4px; +} +.prism-previewer-time svg { + width: 32px; + height: 32px; + -webkit-transform: rotate(-90deg); + -moz-transform: rotate(-90deg); + -ms-transform: rotate(-90deg); + -o-transform: rotate(-90deg); + transform: rotate(-90deg); +} +.prism-previewer-time circle { + fill: transparent; + stroke: hsl(200, 10%, 20%); + stroke-opacity: 0.9; + stroke-width: 32; + stroke-dasharray: 0, 500; + stroke-dashoffset: 0; + -webkit-animation: prism-previewer-time linear infinite 3s; + -moz-animation: prism-previewer-time linear infinite 3s; + -o-animation: prism-previewer-time linear infinite 3s; + animation: prism-previewer-time linear infinite 3s; +} \ No newline at end of file diff --git a/plugins/previewer-time/prism-previewer-time.js b/plugins/previewer-time/prism-previewer-time.js new file mode 100644 index 0000000000..c72f8bb230 --- /dev/null +++ b/plugins/previewer-time/prism-previewer-time.js @@ -0,0 +1,98 @@ +(function() { + + if ( + typeof self !== 'undefined' && !self.Prism || + typeof global !== 'undefined' && !global.Prism + ) { + return; + } + + var languages = { + 'css': true, + 'less': true, + 'markup': { + lang: 'markup', + before: 'punctuation', + inside: 'inside', + root: Prism.languages.markup && Prism.languages.markup['tag'].inside['attr-value'] + }, + 'sass': [ + { + lang: 'sass', + inside: 'inside', + root: Prism.languages.sass && Prism.languages.sass['property-line'] + }, + { + lang: 'sass', + before: 'operator', + inside: 'inside', + root: Prism.languages.sass && Prism.languages.sass['variable-line'] + } + ], + 'scss': true, + 'stylus': [ + { + lang: 'stylus', + before: 'hexcode', + inside: 'rest', + root: Prism.languages.stylus && Prism.languages.stylus['property-declaration'].inside + }, + { + lang: 'stylus', + before: 'hexcode', + inside: 'rest', + root: Prism.languages.stylus && Prism.languages.stylus['variable-declaration'].inside + } + ] + }; + + Prism.hooks.add('before-highlight', function (env) { + if (env.language && languages[env.language] && !languages[env.language].initialized) { + var lang = languages[env.language]; + if (Prism.util.type(lang) !== 'Array') { + lang = [lang]; + } + lang.forEach(function(lang) { + var before, inside, root, skip; + if (lang === true) { + before = 'important'; + inside = env.language; + lang = env.language; + } else { + before = lang.before || 'important'; + inside = lang.inside || lang.lang; + root = lang.root || Prism.languages; + skip = lang.skip; + lang = env.language; + } + + if (!skip && Prism.languages[lang]) { + Prism.languages.insertBefore(inside, before, { + 'time': /(?:\b|\B-|(?=\B\.))\d*\.?\d+m?s\b/i + }, root); + env.grammar = Prism.languages[lang]; + + languages[env.language] = {initialized: true}; + } + }); + } + }); + + if (Prism.plugins.Previewer) { + new Prism.plugins.Previewer('time', function(value) { + var num = parseFloat(value); + var unit = value.match(/[a-z]+$/i); + if (!num || !unit) { + return false; + } + unit = unit[0]; + this.querySelector('circle').style.animationDuration = 2 * num + unit; + return true; + }, '*', function () { + this._elt.innerHTML = '' + + '' + + ''; + }); + } + +}()); \ No newline at end of file diff --git a/plugins/previewer-time/prism-previewer-time.min.js b/plugins/previewer-time/prism-previewer-time.min.js new file mode 100644 index 0000000000..0256b4a853 --- /dev/null +++ b/plugins/previewer-time/prism-previewer-time.min.js @@ -0,0 +1 @@ +!function(){if(("undefined"==typeof self||self.Prism)&&("undefined"==typeof global||global.Prism)){var s={css:!0,less:!0,markup:{lang:"markup",before:"punctuation",inside:"inside",root:Prism.languages.markup&&Prism.languages.markup.tag.inside["attr-value"]},sass:[{lang:"sass",inside:"inside",root:Prism.languages.sass&&Prism.languages.sass["property-line"]},{lang:"sass",before:"operator",inside:"inside",root:Prism.languages.sass&&Prism.languages.sass["variable-line"]}],scss:!0,stylus:[{lang:"stylus",before:"hexcode",inside:"rest",root:Prism.languages.stylus&&Prism.languages.stylus["property-declaration"].inside},{lang:"stylus",before:"hexcode",inside:"rest",root:Prism.languages.stylus&&Prism.languages.stylus["variable-declaration"].inside}]};Prism.hooks.add("before-highlight",function(e){if(e.language&&s[e.language]&&!s[e.language].initialized){var a=s[e.language];"Array"!==Prism.util.type(a)&&(a=[a]),a.forEach(function(a){var i,r,n,l;a===!0?(i="important",r=e.language,a=e.language):(i=a.before||"important",r=a.inside||a.lang,n=a.root||Prism.languages,l=a.skip,a=e.language),!l&&Prism.languages[a]&&(Prism.languages.insertBefore(r,i,{time:/(?:\b|\B-|(?=\B\.))\d*\.?\d+m?s\b/i},n),e.grammar=Prism.languages[a],s[e.language]={initialized:!0})})}}),Prism.plugins.Previewer&&new Prism.plugins.Previewer("time",function(s){var e=parseFloat(s),a=s.match(/[a-z]+$/i);return e&&a?(a=a[0],this.querySelector("circle").style.animationDuration=2*e+a,!0):!1},"*",function(){this._elt.innerHTML=''})}}(); \ No newline at end of file From 1d61959b9bb47dd97b22c7ce7d98ba4488bb5192 Mon Sep 17 00:00:00 2001 From: Golmote Date: Mon, 5 Oct 2015 08:47:54 +0200 Subject: [PATCH 05/17] Plugin: gradient previewer: Add variable examples + add support for Sass variables --- plugins/previewer-gradient/index.html | 12 +++++++---- .../prism-previewer-gradient.js | 20 +++++++++++++------ .../prism-previewer-gradient.min.js | 2 +- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/plugins/previewer-gradient/index.html b/plugins/previewer-gradient/index.html index e783ca8963..420bf8a8f5 100644 --- a/plugins/previewer-gradient/index.html +++ b/plugins/previewer-gradient/index.html @@ -45,7 +45,8 @@

CSS

}

Less

-
#header a {
+	
@gradient: linear-gradient(135deg,  #9dd53a 0%,#a1d54f 50%,#80c217 51%,#7cbc0a 100%);
+#header a {
 	background: -moz-linear-gradient(-45deg,  #9dd53a 0%, #a1d54f 50%, #80c217 51%, #7cbc0a 100%); /* FF3.6+ */
 	background: -webkit-linear-gradient(-45deg,  #9dd53a 0%,#a1d54f 50%,#80c217 51%,#7cbc0a 100%); /* Chrome10+,Safari5.1+ */
 	background: -o-linear-gradient(-45deg,  #9dd53a 0%,#a1d54f 50%,#80c217 51%,#7cbc0a 100%); /* Opera 11.10+ */
@@ -54,19 +55,22 @@ 

Less

}

Sass

-
@mixin foobar
+	
$gradient: linear-gradient(135deg,  #9dd53a 0%,#a1d54f 50%,#80c217 51%,#7cbc0a 100%)
+@mixin foobar
 	background: -moz-radial-gradient(center, ellipse cover,  #f2f6f8 0%, #d8e1e7 50%, #b5c6d0 51%, #e0eff9 100%)
 	background: radial-gradient(ellipse at center,  #f2f6f8 0%,#d8e1e7 50%,#b5c6d0 51%,#e0eff9 100%)
 

Scss

-
$attr: background;
+	
$gradient: linear-gradient(135deg,  #9dd53a 0%,#a1d54f 50%,#80c217 51%,#7cbc0a 100%);
+$attr: background;
 .foo {
     #{$attr}-image: repeating-linear-gradient(10deg, rgba(255,0,0,0), rgba(255,0,0,1) 10px, rgba(255,0,0,0) 20px);
 }

Stylus

-
.foo
+	
gradient = linear-gradient(135deg,  #9dd53a 0%,#a1d54f 50%,#80c217 51%,#7cbc0a 100%)
+.foo
 	background-image: repeating-radial-gradient(circle, rgba(255,0,0,0), rgba(255,0,0,1) 10px, rgba(255,0,0,0) 20px)
 
diff --git a/plugins/previewer-gradient/prism-previewer-gradient.js b/plugins/previewer-gradient/prism-previewer-gradient.js index b2b6b4a17b..11c2d0619e 100644 --- a/plugins/previewer-gradient/prism-previewer-gradient.js +++ b/plugins/previewer-gradient/prism-previewer-gradient.js @@ -10,12 +10,20 @@ var languages = { 'css': true, 'less': true, - 'sass': { - lang: 'sass', - before: 'punctuation', - inside: 'inside', - root: Prism.languages.sass && Prism.languages.sass['property-line'] - }, + 'sass': [ + { + lang: 'sass', + before: 'punctuation', + inside: 'inside', + root: Prism.languages.sass && Prism.languages.sass['variable-line'] + }, + { + lang: 'sass', + before: 'punctuation', + inside: 'inside', + root: Prism.languages.sass && Prism.languages.sass['property-line'] + } + ], 'scss': true, 'stylus': [ { diff --git a/plugins/previewer-gradient/prism-previewer-gradient.min.js b/plugins/previewer-gradient/prism-previewer-gradient.min.js index 35322d4b65..28d222d034 100644 --- a/plugins/previewer-gradient/prism-previewer-gradient.min.js +++ b/plugins/previewer-gradient/prism-previewer-gradient.min.js @@ -1 +1 @@ -!function(){if(("undefined"==typeof self||self.Prism)&&("undefined"==typeof global||global.Prism)){var e={css:!0,less:!0,sass:{lang:"sass",before:"punctuation",inside:"inside",root:Prism.languages.sass&&Prism.languages.sass["property-line"]},scss:!0,stylus:[{lang:"stylus",before:"func",inside:"rest",root:Prism.languages.stylus&&Prism.languages.stylus["property-declaration"].inside},{lang:"stylus",before:"func",inside:"rest",root:Prism.languages.stylus&&Prism.languages.stylus["variable-declaration"].inside}]};Prism.hooks.add("before-highlight",function(i){if(i.language&&e[i.language]&&!e[i.language].initialized){var t=e[i.language];"Array"!==Prism.util.type(t)&&(t=[t]),t.forEach(function(t){var r,a,n,s;t===!0?(r=Prism.plugins.Previewer&&Prism.plugins.Previewer.byType.color?"color":"important",a=i.language,t=i.language):(r=t.before||"important",a=t.inside||t.lang,n=t.root||Prism.languages,s=t.skip,t=i.language),!s&&Prism.languages[t]&&(Prism.languages.insertBefore(a,r,{gradient:{pattern:/(?:\b|\B-[a-z]{1,10}-)(?:repeating-)?(?:linear|radial)-gradient\((?:(?:rgb|hsl)a?\(.+?\)|[^\)])+\)/gi,inside:{"function":/[\w-]+(?=\()/,punctuation:/[(),]/}}},n),i.grammar=Prism.languages[t],e[i.language]={initialized:!0})})}});var i={},t=function(e,i,t){var r="180deg";return/^(?:-?\d*\.?\d+(?:deg|rad)|to\b|top|right|bottom|left)/.test(t[0])&&(r=t.shift(),r.indexOf("to ")<0&&(r.indexOf("top")>=0?r=r.indexOf("left")>=0?"to bottom right":r.indexOf("right")>=0?"to bottom left":"to bottom":r.indexOf("bottom")>=0?r=r.indexOf("left")>=0?"to top right":r.indexOf("right")>=0?"to top left":"to top":r.indexOf("left")>=0?r="to right":r.indexOf("right")>=0?r="to left":e&&(r.indexOf("deg")>=0?r=90-parseFloat(r)+"deg":r.indexOf("rad")>=0&&(r=Math.PI/2-parseFloat(r)+"rad")))),i+"("+r+","+t.join(",")+")"},r=function(e,i,t){if(t[0].indexOf("at")<0){var r="center",a="ellipse",n="farthest-corner";if(/\bcenter|top|right|bottom|left\b|^\d+/.test(t[0])&&(r=t.shift().replace(/\s*-?\d+(?:rad|deg)\s*/,"")),/\bcircle|ellipse|closest|farthest|contain|cover\b/.test(t[0])){var s=t.shift().split(/\s+/);!s[0]||"circle"!==s[0]&&"ellipse"!==s[0]||(a=s.shift()),s[0]&&(n=s.shift()),"cover"===n?n="farthest-corner":"contain"===n&&(n="clothest-side")}return i+"("+a+" "+n+" at "+r+","+t.join(",")+")"}return i+"("+t.join(",")+")"},a=function(e){if(i[e])return i[e];var a=e.match(/^(\b|\B-[a-z]{1,10}-)((?:repeating-)?(?:linear|radial)-gradient)/),n=a&&a[1],s=a&&a[2],l=e.replace(/^(?:\b|\B-[a-z]{1,10}-)(?:repeating-)?(?:linear|radial)-gradient\(|\)$/g,"").split(/\s*,\s*/);return i[e]=s.indexOf("linear")>=0?t(n,s,l):s.indexOf("radial")>=0?r(n,s,l):s+"("+l.join(",")+")"};Prism.plugins.Previewer&&new Prism.plugins.Previewer("gradient",function(e){return this.firstChild.style.backgroundImage="",this.firstChild.style.backgroundImage=a(e),!!this.firstChild.style.backgroundImage},"*",function(){this._elt.innerHTML="
"})}}(); \ No newline at end of file +!function(){if(("undefined"==typeof self||self.Prism)&&("undefined"==typeof global||global.Prism)){var e={css:!0,less:!0,sass:[{lang:"sass",before:"punctuation",inside:"inside",root:Prism.languages.sass&&Prism.languages.sass["variable-line"]},{lang:"sass",before:"punctuation",inside:"inside",root:Prism.languages.sass&&Prism.languages.sass["property-line"]}],scss:!0,stylus:[{lang:"stylus",before:"func",inside:"rest",root:Prism.languages.stylus&&Prism.languages.stylus["property-declaration"].inside},{lang:"stylus",before:"func",inside:"rest",root:Prism.languages.stylus&&Prism.languages.stylus["variable-declaration"].inside}]};Prism.hooks.add("before-highlight",function(i){if(i.language&&e[i.language]&&!e[i.language].initialized){var t=e[i.language];"Array"!==Prism.util.type(t)&&(t=[t]),t.forEach(function(t){var r,s,a,n;t===!0?(r=Prism.plugins.Previewer&&Prism.plugins.Previewer.byType.color?"color":"important",s=i.language,t=i.language):(r=t.before||"important",s=t.inside||t.lang,a=t.root||Prism.languages,n=t.skip,t=i.language),!n&&Prism.languages[t]&&(Prism.languages.insertBefore(s,r,{gradient:{pattern:/(?:\b|\B-[a-z]{1,10}-)(?:repeating-)?(?:linear|radial)-gradient\((?:(?:rgb|hsl)a?\(.+?\)|[^\)])+\)/gi,inside:{"function":/[\w-]+(?=\()/,punctuation:/[(),]/}}},a),i.grammar=Prism.languages[t],e[i.language]={initialized:!0})})}});var i={},t=function(e,i,t){var r="180deg";return/^(?:-?\d*\.?\d+(?:deg|rad)|to\b|top|right|bottom|left)/.test(t[0])&&(r=t.shift(),r.indexOf("to ")<0&&(r.indexOf("top")>=0?r=r.indexOf("left")>=0?"to bottom right":r.indexOf("right")>=0?"to bottom left":"to bottom":r.indexOf("bottom")>=0?r=r.indexOf("left")>=0?"to top right":r.indexOf("right")>=0?"to top left":"to top":r.indexOf("left")>=0?r="to right":r.indexOf("right")>=0?r="to left":e&&(r.indexOf("deg")>=0?r=90-parseFloat(r)+"deg":r.indexOf("rad")>=0&&(r=Math.PI/2-parseFloat(r)+"rad")))),i+"("+r+","+t.join(",")+")"},r=function(e,i,t){if(t[0].indexOf("at")<0){var r="center",s="ellipse",a="farthest-corner";if(/\bcenter|top|right|bottom|left\b|^\d+/.test(t[0])&&(r=t.shift().replace(/\s*-?\d+(?:rad|deg)\s*/,"")),/\bcircle|ellipse|closest|farthest|contain|cover\b/.test(t[0])){var n=t.shift().split(/\s+/);!n[0]||"circle"!==n[0]&&"ellipse"!==n[0]||(s=n.shift()),n[0]&&(a=n.shift()),"cover"===a?a="farthest-corner":"contain"===a&&(a="clothest-side")}return i+"("+s+" "+a+" at "+r+","+t.join(",")+")"}return i+"("+t.join(",")+")"},s=function(e){if(i[e])return i[e];var s=e.match(/^(\b|\B-[a-z]{1,10}-)((?:repeating-)?(?:linear|radial)-gradient)/),a=s&&s[1],n=s&&s[2],l=e.replace(/^(?:\b|\B-[a-z]{1,10}-)(?:repeating-)?(?:linear|radial)-gradient\(|\)$/g,"").split(/\s*,\s*/);return i[e]=n.indexOf("linear")>=0?t(a,n,l):n.indexOf("radial")>=0?r(a,n,l):n+"("+l.join(",")+")"};Prism.plugins.Previewer&&new Prism.plugins.Previewer("gradient",function(e){return this.firstChild.style.backgroundImage="",this.firstChild.style.backgroundImage=s(e),!!this.firstChild.style.backgroundImage},"*",function(){this._elt.innerHTML="
"})}}(); \ No newline at end of file From 256c3e12c1e8d72d1fae62431271c42d624ebe00 Mon Sep 17 00:00:00 2001 From: Andreas Rohner Date: Mon, 5 Oct 2015 23:00:25 +0200 Subject: [PATCH 06/17] Fix regression in Bash strings In a recent patch the regex for single-quoted and double-quoted strings of the Bash language was split into two separate regexes to prevent the highlighting of variables inside of single-quoted strings. This causes a bug whenever a double-quoted string apears inside a single-quoted string, because the double-quoted string is matched first. '"foo"' The same problem exists with the newly introduced Here-Documents. This patch fixes the problem by matching Here-Documents first and merging the regexes for single-quoted and double-quoted strings again. This patch also adds testcases for this, to prevent future regressions. --- components/prism-bash.js | 10 ++++----- components/prism-bash.min.js | 2 +- tests/languages/bash/string_feature.test | 26 ++++++++++++++++++++---- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/components/prism-bash.js b/components/prism-bash.js index 64b42f6ce2..6277fc5e02 100644 --- a/components/prism-bash.js +++ b/components/prism-bash.js @@ -12,16 +12,14 @@ lookbehind: true }, 'string': [ + //Support for Here-Documents https://en.wikipedia.org/wiki/Here_document { - pattern: /"(?:\\?[\s\S])*?"/g, + pattern: /((?:^|[^<])<<\s*)(?:"|')?(\w+?)(?:"|')?\s*\r?\n(?:[\s\S])*?\r?\n\2/g, + lookbehind: true, inside: bashVars }, - // Single quote strings cannot have variables inside - /'(?:\\?[\s\S])*?'/g, - // Support for Here-Documents https://en.wikipedia.org/wiki/Here_document { - pattern: /(<<\s*)(\w+?)\s*\r?\n(?:[\s\S])*?\r?\n\2/g, - lookbehind: true, + pattern: /("|')(?:\\?[\s\S])*?\1/g, inside: bashVars } ], diff --git a/components/prism-bash.min.js b/components/prism-bash.min.js index f9902e0a51..ffcd48c48e 100644 --- a/components/prism-bash.min.js +++ b/components/prism-bash.min.js @@ -1 +1 @@ -!function(e){var t=/\$(?:[a-z0-9_#\?\-\*!@]+|\{[^}]+\})/i,o={variable:t};e.languages.bash={shebang:{pattern:/^#!\s*\/bin\/bash|^#!\s*\/bin\/sh/,alias:"important"},comment:{pattern:/(^|[^"{\\])#.*/,lookbehind:!0},string:[{pattern:/"(?:\\?[\s\S])*?"/g,inside:o},/'(?:\\?[\s\S])*?'/g,{pattern:/(<<\s*)(\w+?)\s*\r?\n(?:[\s\S])*?\r?\n\2/g,lookbehind:!0,inside:o}],number:{pattern:/([^\w\.])-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/,lookbehind:!0},variable:t,"function":/\b(?:alias|apropos|apt-get|aptitude|aspell|awk|basename|bash|bc|bg|builtin|bzip2|cal|cat|cd|cfdisk|chgrp|chmod|chown|chroot|chkconfig|cksum|clear|cmp|comm|command|cp|cron|crontab|csplit|cut|date|dc|dd|ddrescue|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|du|egrep|eject|enable|env|ethtool|eval|exec|expand|expect|export|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|getopts|git|grep|groupadd|groupdel|groupmod|groups|gzip|hash|head|help|hg|history|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|jobs|join|kill|killall|less|link|ln|locate|logname|logout|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|make|man|mkdir|mkfifo|mkisofs|mknod|more|most|mount|mtools|mtr|mv|mmv|nano|netstat|nice|nl|nohup|notify-send|nslookup|open|op|passwd|paste|pathchk|ping|pkill|popd|pr|printcap|printenv|printf|ps|pushd|pv|pwd|quota|quotacheck|quotactl|ram|rar|rcp|read|readarray|readonly|reboot|rename|renice|remsync|rev|rm|rmdir|rsync|screen|scp|sdiff|sed|seq|service|sftp|shift|shopt|shutdown|sleep|slocate|sort|source|split|ssh|stat|strace|su|sudo|sum|suspend|sync|tail|tar|tee|test|time|timeout|times|touch|top|traceroute|trap|tr|tsort|tty|type|ulimit|umask|umount|unalias|uname|unexpand|uniq|units|unrar|unshar|uptime|useradd|userdel|usermod|users|uuencode|uudecode|v|vdir|vi|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yes|zip)\b/,keyword:/\b(let|if|then|else|elif|fi|for|break|continue|while|in|case|function|select|do|done|until|echo|exit|return|set|declare)\b/,"boolean":/\b(?:true|false)\b/,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/}}(Prism); \ No newline at end of file +!function(e){var t=/\$(?:[a-z0-9_#\?\-\*!@]+|\{[^}]+\})/i,o={variable:t};e.languages.bash={shebang:{pattern:/^#!\s*\/bin\/bash|^#!\s*\/bin\/sh/,alias:"important"},comment:{pattern:/(^|[^"{\\])#.*/,lookbehind:!0},string:[{pattern:/((?:^|[^<])<<\s*)(?:"|')?(\w+?)(?:"|')?\s*\r?\n(?:[\s\S])*?\r?\n\2/g,lookbehind:!0,inside:o},{pattern:/("|')(?:\\?[\s\S])*?\1/g,inside:o}],number:{pattern:/([^\w\.])-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/,lookbehind:!0},variable:t,"function":/\b(?:alias|apropos|apt-get|aptitude|aspell|awk|basename|bash|bc|bg|builtin|bzip2|cal|cat|cd|cfdisk|chgrp|chmod|chown|chroot|chkconfig|cksum|clear|cmp|comm|command|cp|cron|crontab|csplit|cut|date|dc|dd|ddrescue|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|du|egrep|eject|enable|env|ethtool|eval|exec|expand|expect|export|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|getopts|git|grep|groupadd|groupdel|groupmod|groups|gzip|hash|head|help|hg|history|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|jobs|join|kill|killall|less|link|ln|locate|logname|logout|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|make|man|mkdir|mkfifo|mkisofs|mknod|more|most|mount|mtools|mtr|mv|mmv|nano|netstat|nice|nl|nohup|notify-send|nslookup|open|op|passwd|paste|pathchk|ping|pkill|popd|pr|printcap|printenv|printf|ps|pushd|pv|pwd|quota|quotacheck|quotactl|ram|rar|rcp|read|readarray|readonly|reboot|rename|renice|remsync|rev|rm|rmdir|rsync|screen|scp|sdiff|sed|seq|service|sftp|shift|shopt|shutdown|sleep|slocate|sort|source|split|ssh|stat|strace|su|sudo|sum|suspend|sync|tail|tar|tee|test|time|timeout|times|touch|top|traceroute|trap|tr|tsort|tty|type|ulimit|umask|umount|unalias|uname|unexpand|uniq|units|unrar|unshar|uptime|useradd|userdel|usermod|users|uuencode|uudecode|v|vdir|vi|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yes|zip)\b/,keyword:/\b(let|if|then|else|elif|fi|for|break|continue|while|in|case|function|select|do|done|until|echo|exit|return|set|declare)\b/,"boolean":/\b(?:true|false)\b/,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/}}(Prism); \ No newline at end of file diff --git a/tests/languages/bash/string_feature.test b/tests/languages/bash/string_feature.test index 343ccc4c78..29a10eb56b 100644 --- a/tests/languages/bash/string_feature.test +++ b/tests/languages/bash/string_feature.test @@ -6,6 +6,8 @@ bar" 'foo bar' +"'foo'" +'"bar"' "$@" "${foo}" << STRING_END @@ -16,16 +18,26 @@ STRING_END foo $@ bar EOF +<< 'EOF' +'single quoted string' +"double quoted string" +EOF +<< "EOF" +foo +bar +EOF ---------------------------------------------------- [ ["string", ["\"\""]], - ["string", "''"], + ["string", ["''"]], ["string", ["\"foo\""]], - ["string", "'foo'"], + ["string", ["'foo'"]], ["string", ["\"foo\r\nbar\""]], - ["string", "'foo\r\nbar'"], + ["string", ["'foo\r\nbar'"]], + ["string", ["\"'foo'\""]], + ["string", ["'\"bar\"'"]], ["string", [ "\"", ["variable", "$@"], "\"" ]], @@ -37,7 +49,13 @@ EOF ["string", ["STRING_END\r\nfoo\r\nbar\r\nSTRING_END"]], ["operator", "<"], ["operator", "<"], - ["string", ["EOF\r\nfoo ", ["variable", "$@"], "\r\nbar\r\nEOF"]] + ["string", ["EOF\r\nfoo ", ["variable", "$@"], "\r\nbar\r\nEOF"]], + ["operator", "<"], + ["operator", "<"], + ["string", ["'EOF'\r\n'single quoted string'\r\n\"double quoted string\"\r\nEOF"]], + ["operator", "<"], + ["operator", "<"], + ["string", ["\"EOF\"\r\nfoo\r\nbar\r\nEOF"]] ] ---------------------------------------------------- From 5ade8a58b2500dabdc82d17e9420dca28b38e2ca Mon Sep 17 00:00:00 2001 From: Golmote Date: Tue, 6 Oct 2015 08:25:54 +0200 Subject: [PATCH 07/17] Test runner: Allow to run tests for only some languages --- package.json | 3 +- test-suite.html | 8 ++++++ tests/helper/test-discovery.js | 52 ++++++++++++++++++++++++++++++++++ tests/run.js | 10 +++++-- 4 files changed, 70 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 721b89d7c4..208d2a5aa7 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "gulp-rename": "^1.2.0", "gulp-uglify": "^0.3.1", "gulp-replace": "^0.5.4", - "mocha": "^2.2.5" + "mocha": "^2.2.5", + "yargs": "^3.26.0" } } diff --git a/test-suite.html b/test-suite.html index 906fe81a06..b84ee46c47 100644 --- a/test-suite.html +++ b/test-suite.html @@ -26,6 +26,13 @@

Running the test suite

Running the test suite is simple: just call npm test.

All test files are run in isolation. A new prism instance is created for each test case. This will slow the test runner a bit down, but we can be sure that nothing leaks into the next test case.

+ +
+

Running tests for specific languages

+ +

To run the tests only for one language, you can use the language parameter: npm test -- --language=markup.

+

You can even specify multiple languages: npm test -- --language=markup --language=css.

+
@@ -139,6 +146,7 @@

Internal structure

+ diff --git a/tests/helper/test-discovery.js b/tests/helper/test-discovery.js index 741dc7591b..622b619271 100644 --- a/tests/helper/test-discovery.js +++ b/tests/helper/test-discovery.js @@ -25,6 +25,26 @@ module.exports = { return testSuite; }, + /** + * Loads the list of available tests that match the given languages + * + * @param {string} rootDir + * @param {string|string[]} languages + * @returns {Object.} + */ + loadSomeTests: function (rootDir, languages) { + var testSuite = {}; + var self = this; + + this.getSomeDirectories(rootDir, languages).forEach( + function (language) { + testSuite[language] = self.getAllFiles(path.join(rootDir, language)); + } + ); + + return testSuite; + }, + /** * Returns a list of all (sub)directories (just the directory names, not full paths) @@ -41,6 +61,38 @@ module.exports = { ); }, + /** + * Returns a list of all (sub)directories (just the directory names, not full paths) + * in the given src directory, matching the given languages + * + * @param {string} src + * @param {string|string[]} languages + * @returns {Array.} + */ + getSomeDirectories: function (src, languages) { + var self = this; + return fs.readdirSync(src).filter( + function (file) { + return fs.statSync(path.join(src, file)).isDirectory() && self.directoryMatches(file, languages); + } + ); + }, + + /** + * Returns whether a directory matches one of the given languages. + * @param {string} directory + * @param {string|string[]} languages + */ + directoryMatches: function (directory, languages) { + if (!Array.isArray(languages)) { + languages = [languages]; + } + var dirLanguages = directory.split(/!?\+!?/); + return dirLanguages.some(function (lang) { + return languages.indexOf(lang) >= 0; + }); + }, + /** * Returns a list of all full file paths to all files in the given src directory diff --git a/tests/run.js b/tests/run.js index 5e0050487f..a28350d2a4 100644 --- a/tests/run.js +++ b/tests/run.js @@ -3,9 +3,15 @@ var TestDiscovery = require("./helper/test-discovery"); var TestCase = require("./helper/test-case"); var path = require("path"); +var argv = require("yargs").argv; -// load complete test suite -var testSuite = TestDiscovery.loadAllTests(__dirname + "/languages"); +var testSuite; +if (argv.language) { + testSuite = TestDiscovery.loadSomeTests(__dirname + "/languages", argv.language); +} else { + // load complete test suite + testSuite = TestDiscovery.loadAllTests(__dirname + "/languages"); +} // define tests for all tests in all languages in the test suite for (var language in testSuite) { From 29643f4e462d2fdac353c44c2d826f0c4c5dc62f Mon Sep 17 00:00:00 2001 From: Golmote Date: Tue, 6 Oct 2015 08:48:21 +0200 Subject: [PATCH 08/17] Simplify patterns for