From f24e7428df15ee8bcc9a2a45de98363670e72231 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 4 Aug 2019 15:55:24 -0400 Subject: [PATCH] add line highlighting and linking (#654) --- .../Views/JsonValidator/Index.cshtml | 4 +- .../wwwroot/Content/css/json-validator.css | 4 + .../wwwroot/Content/js/json-validator.js | 123 +++++++++++++++++- 3 files changed, 127 insertions(+), 4 deletions(-) diff --git a/src/SMAPI.Web/Views/JsonValidator/Index.cshtml b/src/SMAPI.Web/Views/JsonValidator/Index.cshtml index cd7ca912..6658e7b9 100644 --- a/src/SMAPI.Web/Views/JsonValidator/Index.cshtml +++ b/src/SMAPI.Web/Views/JsonValidator/Index.cshtml @@ -107,7 +107,7 @@ else if (Model.PasteID != null) @foreach (JsonValidatorErrorModel error in Model.Errors) { - @error.Line + @error.Line @error.Path @error.Message @@ -121,6 +121,6 @@ else if (Model.PasteID != null) }

Raw content

-
@Model.Content
+
@Model.Content
} diff --git a/src/SMAPI.Web/wwwroot/Content/css/json-validator.css b/src/SMAPI.Web/wwwroot/Content/css/json-validator.css index f9aeb18b..d4a43032 100644 --- a/src/SMAPI.Web/wwwroot/Content/css/json-validator.css +++ b/src/SMAPI.Web/wwwroot/Content/css/json-validator.css @@ -72,6 +72,10 @@ background: #fff; } +#output div.sunlight-line-highlight-active { + background-color: #eeeacc; +} + /********* ** Upload form *********/ diff --git a/src/SMAPI.Web/wwwroot/Content/js/json-validator.js b/src/SMAPI.Web/wwwroot/Content/js/json-validator.js index 3f7a1775..265e0c5e 100644 --- a/src/SMAPI.Web/wwwroot/Content/js/json-validator.js +++ b/src/SMAPI.Web/wwwroot/Content/js/json-validator.js @@ -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} 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() {