Skip to content
This repository has been archived by the owner on Jun 7, 2024. It is now read-only.

Commit

Permalink
Feat(hightlight): use new highlighter
Browse files Browse the repository at this point in the history
  • Loading branch information
marcoscaceres committed May 18, 2016
1 parent f06ceba commit 636f610
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 46 deletions.
145 changes: 106 additions & 39 deletions js/core/highlight.js
Original file line number Diff line number Diff line change
@@ -1,46 +1,113 @@

// Module core/highlight
// Does syntax highlighting to all pre and code that have a class of "highlight"
// An improvement would be to use web workers to do the highlighting.
"use strict";
define(
[
"core/utils",
"highlight",
"text!highlightStyles/github.css",
],
function(utils, hljs, ghCss) {
// Opportunistically insert the style into the head to reduce FOUC.
var codeStyle = document.createElement("style");
codeStyle.textContent = ghCss;
var swapStyleOwner = utils.makeOwnerSwapper(codeStyle);
swapStyleOwner(document, document.head);

// A potential improvement would be to call cb() immediately and benefit from the asynchronous
// ability of prettyPrint() (but only call msg.pub() in the callback to remain accurate as to
// the end of processing)
function intersecList(list1) {
return function(item) {
return list1.has(item);
};
}

define(
["text!core/css/highlight.css", "google-code-prettify"],
function (css, PR) {
return {
run: function (conf, doc, cb, msg) {
msg.pub("start", "core/highlight");

// fix old classes
var oldies = "sh_css sh_html sh_javascript sh_javascript_dom sh_xml".split(" ");
for (var i = 0, n = oldies.length; i < n; i++) {
var old = oldies[i];
$("." + old).each(function () {
$(this).removeClass(old).addClass("highlight");
msg.pub("warn", "Old highlighting class '" + old + "', use 'highlight' instead.");
});
}

// prettify
var $highs = $("pre.highlight, code.highlight")
, done = function () {
msg.pub("end", "core/highlight");
cb();
}
;
if ($highs.length) {
if (!conf.noHighlightCSS) {
$(doc).find("head link").first().before($("<style/>").text(css));
}
$highs.addClass("prettyprint");
PR.prettyPrint(done);
}
else {
done();
}
function warnAboutDeprecatedClasses(doc, msg){
// Deprecated style classes
var deprecatedClasses = new Set([
"highlight",
"sh_css",
"sh_html",
"sh_javascript",
"sh_javascript_dom",
"sh_xml",
]);
var deprecatedCSSClasses = intersecList(deprecatedClasses);
var cssQuery = Array
.from(deprecatedClasses)
.map(function toCssClasses(item) {
return "." + item;
})
.join(", ");

var offendingElements = Array.from(
doc.querySelectorAll(cssQuery)
);

// Document is clean, so nothing to do.
if(offendingElements.length === 0){
return;
}

var offendingClasses = offendingElements
.map(function(element) {
var offendingClasses = Array
.from(element.classList)
.filter(deprecatedCSSClasses);
return {
element: element,
offendingClasses: offendingClasses,
};
})
.map(function(elementAndOffence) {
var element = elementAndOffence.element;
var offendingSet = elementAndOffence
.offendingClasses
.reduce(function removeOffendingClass(collector, className) {
element.classList.remove(className);
return collector.add(className);
}, new Set());
return Array.from(offendingSet);
})
.reduce(function(collector, offendingItems, index, array) {
collector.push.apply(collector, offendingItems);
// make the final collection unique
if (index === array.length) {
return Array
.from(new Set(collector))
.sort();
}
};
return collector;
}, [])
.join(", ");
if (offendingClasses.length) {
var warning = "pre elements don't need CSS class: " + offendingClasses + ".";
msg.pub("warn", warning);
}
}

return {
run: function(conf, doc, cb, msg) {
var codeBlocks = Array.from(doc.querySelectorAll("pre"));

// If nothing to do
if (conf.noHighlightCSS || codeBlocks.length === 0) {
return cb();
}

if(codeStyle.ownerDocument !== doc){
swapStyleOwner(doc, doc.head);
}

warnAboutDeprecatedClasses(doc, msg);

Array
.from(codeBlocks)
.forEach(function(element) {
hljs.highlightBlock(element);
});

cb();
}
};
}
);
39 changes: 32 additions & 7 deletions tests/spec/core/highlight-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,43 @@ describe("Core — Highlight", function() {
flushIframes();
done();
});
it("should process highlights", function(done) {

it("should automatically highlight", function(done) {
var ops = {
config: makeBasicConfig(),
body: makeDefaultBody() +
"<section><pre class='example sh_javascript'>function () {\n alert('foo');\n}</pre></section>"
"<section><pre class=example>function () {\n alert('foo');\n}</pre></section>"
};
makeRSDoc(ops, function(doc) {
var $ex = $("div.example pre", doc);
expect($ex.hasClass("sh_javascript")).toBeFalsy();
expect($ex.hasClass("highlight")).toBeTruthy();
expect($ex.hasClass("prettyprint")).toBeTruthy();
expect($ex.find("span.str").length).toBeGreaterThan(0);
var pre = doc.querySelector("div.example pre");
expect(pre.classList.contains("hljs")).toBeTruthy();
expect(pre.querySelectorAll("span[class^=hljs-]").length).toBeGreaterThan(0);
}).then(done);
});

it("shouldn't highlight pre elements when told not to", function(done) {
var ops = {
config: makeBasicConfig(),
body: makeDefaultBody() +
"<section><pre class='nohighlight example'>function () {\n alert('foo');\n}</pre></section>"
};
makeRSDoc(ops, function(doc) {
var pre = doc.querySelector("div.example pre");
expect(pre.classList.contains("nohighlight")).toBeTruthy();
expect(pre.querySelectorAll("span[class^=hljs-]").length).toBe(0);
}).then(done);
});

it("should respect the noHighlightCSS by not highlighting anything", function(done) {
var ops = {
config: Object.assign(makeBasicConfig(), { noHighlightCSS: true }),
body: makeDefaultBody() +
"<section><pre id=test>function () {\n alert('foo');\n}</pre></section>"
};
makeRSDoc(ops, function(doc) {
var pre = doc.querySelector("#test");
expect(pre.querySelectorAll("span[class^=hljs-]").length).toBe(0);
}).then(done);
});

});

0 comments on commit 636f610

Please sign in to comment.