add line highlighting and linking (#654)
This commit is contained in:
parent
1b9ce5e64f
commit
f24e7428df
|
@ -107,7 +107,7 @@ else if (Model.PasteID != null)
|
|||
@foreach (JsonValidatorErrorModel error in Model.Errors)
|
||||
{
|
||||
<tr>
|
||||
<td>@error.Line</td>
|
||||
<td><a href="#L@(error.Line)">@error.Line</a></td>
|
||||
<td>@error.Path</td>
|
||||
<td>@error.Message</td>
|
||||
</tr>
|
||||
|
@ -121,6 +121,6 @@ else if (Model.PasteID != null)
|
|||
}
|
||||
|
||||
<h2>Raw content</h2>
|
||||
<pre class="sunlight-highlight-javascript">@Model.Content</pre>
|
||||
<pre id="raw-content" class="sunlight-highlight-javascript">@Model.Content</pre>
|
||||
</div>
|
||||
}
|
||||
|
|
|
@ -72,6 +72,10 @@
|
|||
background: #fff;
|
||||
}
|
||||
|
||||
#output div.sunlight-line-highlight-active {
|
||||
background-color: #eeeacc;
|
||||
}
|
||||
|
||||
/*********
|
||||
** Upload form
|
||||
*********/
|
||||
|
|
|
@ -1,20 +1,139 @@
|
|||
/* globals $ */
|
||||
|
||||
var smapi = smapi || {};
|
||||
|
||||
/**
|
||||
* Manages the logic for line range selections.
|
||||
* @param {int} maxLines The maximum number of lines in the content.
|
||||
*/
|
||||
smapi.LineNumberRange = function (maxLines) {
|
||||
var self = this;
|
||||
|
||||
/**
|
||||
* @var {int} minLine The first line in the selection, or null if no lines selected.
|
||||
*/
|
||||
self.minLine = null;
|
||||
|
||||
/**
|
||||
* @var {int} maxLine The last line in the selection, or null if no lines selected.
|
||||
*/
|
||||
self.maxLine = null;
|
||||
|
||||
/**
|
||||
* Parse line numbers from a URL hash.
|
||||
* @param {string} hash the URL hash to parse.
|
||||
*/
|
||||
self.parseFromUrlHash = function (hash) {
|
||||
self.minLine = null;
|
||||
self.maxLine = null;
|
||||
|
||||
// parse hash
|
||||
var hashParts = hash.match(/^#L(\d+)(?:-L(\d+))?$/);
|
||||
if (!hashParts || hashParts.length <= 1)
|
||||
return;
|
||||
|
||||
// extract min/max lines
|
||||
self.minLine = parseInt(hashParts[1]);
|
||||
self.maxLine = parseInt(hashParts[2]) || self.minLine;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate a URL hash for the current line range.
|
||||
* @returns {string} The generated URL hash.
|
||||
*/
|
||||
self.buildHash = function() {
|
||||
if (!self.minLine)
|
||||
return "";
|
||||
else if (self.minLine === self.maxLine)
|
||||
return "#L" + self.minLine;
|
||||
else
|
||||
return "#L" + self.minLine + "-L" + self.maxLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all selected lines.
|
||||
* @returns {Array<int>} The selected line numbers.
|
||||
*/
|
||||
self.getLinesSelected = function() {
|
||||
// format
|
||||
if (!self.minLine)
|
||||
return [];
|
||||
|
||||
var lines = [];
|
||||
for (var i = self.minLine; i <= self.maxLine; i++)
|
||||
lines.push(i);
|
||||
return lines;
|
||||
};
|
||||
|
||||
return self;
|
||||
};
|
||||
|
||||
/**
|
||||
* UI logic for the JSON validator page.
|
||||
* @param {any} sectionUrl The base JSON validator page URL.
|
||||
* @param {any} pasteID The Pastebin paste ID for the content being viewed, if any.
|
||||
*/
|
||||
smapi.jsonValidator = function (sectionUrl, pasteID) {
|
||||
/**
|
||||
* The original content element.
|
||||
*/
|
||||
var originalContent = $("#raw-content").clone();
|
||||
|
||||
/**
|
||||
* The currently highlighted lines.
|
||||
*/
|
||||
var selection = new smapi.LineNumberRange();
|
||||
|
||||
/**
|
||||
* Rebuild the syntax-highlighted element.
|
||||
*/
|
||||
var formatCode = function () {
|
||||
Sunlight.highlightAll();
|
||||
// reset if needed
|
||||
$(".sunlight-container").replaceWith(originalContent.clone());
|
||||
|
||||
// apply default highlighting
|
||||
Sunlight.highlightAll({
|
||||
lineHighlight: selection.getLinesSelected()
|
||||
});
|
||||
|
||||
// fix line links
|
||||
$(".sunlight-line-number-margin a").each(function() {
|
||||
var link = $(this);
|
||||
var lineNumber = parseInt(link.text());
|
||||
link
|
||||
.attr("id", "L" + lineNumber)
|
||||
.attr("href", "#L" + lineNumber)
|
||||
.removeAttr("name")
|
||||
.data("line-number", lineNumber);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Scroll the page so the selected range is visible.
|
||||
*/
|
||||
var scrollToRange = function() {
|
||||
if (!selection.minLine)
|
||||
return;
|
||||
|
||||
var targetLine = Math.max(1, selection.minLine - 5);
|
||||
$("#L" + targetLine).get(0).scrollIntoView();
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialise the JSON validator page.
|
||||
*/
|
||||
var init = function () {
|
||||
// code formatting
|
||||
// set initial code formatting
|
||||
selection.parseFromUrlHash(location.hash);
|
||||
formatCode();
|
||||
scrollToRange();
|
||||
|
||||
// update code formatting on hash change
|
||||
$(window).on("hashchange", function() {
|
||||
selection.parseFromUrlHash(location.hash);
|
||||
formatCode();
|
||||
scrollToRange();
|
||||
});
|
||||
|
||||
// change format
|
||||
$("#output #format").on("change", function() {
|
||||
|
|
Loading…
Reference in New Issue