tag-browser: use separate <code-block> module for style preview

This commit is contained in:
MrOtherGuy
2022-04-03 15:01:07 +03:00
parent b9e140dbbd
commit 97e42e134a
6 changed files with 991 additions and 286 deletions

View File

@@ -38,7 +38,7 @@ function fetchWithType(url){
.then((obj) => resolve({file:url,content:obj}));
}else{
response.text()
.then((text) => resolve({file:url,content:text}))
.then((text) => resolve({file:url,content:text,name:url}))
}
},except => reject(except))
@@ -103,14 +103,6 @@ function getSecondaryCategories(list){
return ret
}
function clearCodeBlock(){
const pre = document.getElementById("previewBox");
for(let el of Array.from(pre.childNodes)){
pre.removeChild(el)
}
return
}
function showMatchingTargets(fileNames,setSelected = false){
let bonus = 0;
for(let c of Array.from(document.querySelectorAll(".target"))){
@@ -152,13 +144,27 @@ function onCategoryClicked(categoryNode,isSecondary = false){
return
}
async function onTargetClicked(target,append = false){
const text = typeof target === "string"
? target
: getText(target);
fetchWithType(`chrome/${text}`)
.then(obj => Highlighter.parse(obj,append))
.then(obj => {
let box = document.getElementById("previewBox");
if(append){
if(obj.file.endsWith("window_control_placeholder_support.css")){
obj.insertMode = box.InsertModes.Prepend;
box.insertContent(obj);
}else{
obj.insertMode = box.InsertModes.AppendLines;
box.insertContent(obj);
}
}else{
box.value = obj
}
})
.catch(e => console.log(e))
}
@@ -178,7 +184,8 @@ function onFilenameClicked(box,ctrlKey){
}else{
if(ctrlKey){
selectedTarget.deselect(box);
let preview = document.querySelector(`[data-filename="chrome/${box.getAttribute("title")}.css"]`);
let previewbox = document.getElementById("previewBox");
let preview = previewbox.getNamedSection(`chrome/${box.getAttribute("title")}.css`);
if(preview){
preview.remove();
}
@@ -309,260 +316,6 @@ function createCategories(){
}
const Highlighter = new(function(){
const state = new (function(){
let current = 0;
let previous = 0;
this.now = ()=>current;
this.previous = ()=>previous;
this.set = function(a){ previous = current; current = a; return}
})();
let pointer = 0;
let token = "";
const selectorToClassMap = new Map([
[":","pseudo"],
["#","id"],
[".","class"],
["[","attribute"]]);
this.parse = function(info,appendMode){
const targetNode = document.getElementById("previewBox");
!appendMode && clearCodeBlock();
let node = document.createElement("div");
node.setAttribute("data-filename",info.file);
function createNewRuleset(){
let ruleset = document.createElement("span");
ruleset.className = "ruleset";
node.appendChild(ruleset);
return ruleset
}
let rulesetUnderConstruction = createNewRuleset();
function createElementFromToken(type,c){
if(token.length === 0 && !c){
return
}
let n = document.createElement("span");
switch(type){
case "selector":
// This isn't exactly correct, but it works because parser treats \r\n sequences that follow a closed comment as "selector"
rulesetUnderConstruction = createNewRuleset();
let parts = token.split(/([\.#:\[]\w[\w-_"'=\]]*|\s\w[\w-_"'=\]]*)/);
for(let part of parts){
if(part.length === 0){
continue
}
let c = part[0];
switch (c){
case ":":
case "#":
case "[":
case ".":
let p = n.appendChild(document.createElement("span"));
p.className = selectorToClassMap.get(c);
p.textContent = part;
break;
default:
n.append(part);
}
}
break
case "comment":
let linksToFile = token.match(/[\w-\.]+\.css/g);
if(linksToFile && linksToFile.length){
let linkIdx = 0;
let fromIdx = 0;
while(linkIdx < linksToFile.length){
let part = linksToFile[linkIdx++];
let idx = token.indexOf(part);
n.append(token.substring(fromIdx,idx));
let link = document.createElement("a");
link.textContent = part;
link.href = `https://github.com/MrOtherGuy/firefox-csshacks/tree/master/chrome/${part}`;
link.target = "_blank";
n.appendChild(link);
fromIdx = idx + part.length;
}
n.append(token.substring(fromIdx));
}else{
n.textContent = c || token;
}
break;
case "value":
let startImportant = token.indexOf("!");
if(startImportant === -1){
n.textContent = c || token;
}else{
n.textContent = token.substr(0,startImportant);
let importantTag = document.createElement("span");
importantTag.className = "important-tag";
importantTag.textContent = "!important";
n.appendChild(importantTag);
if(token.length > (9 + startImportant)){
n.append(";")
}
}
break;
case "function":
n.textContent = c || token.slice(0,-1);
break
default:
n.textContent = c || token;
}
n.className = (`token ${type}`);
token = "";
rulesetUnderConstruction.appendChild(n);
return
}
let c;
let functionValueLevel = 0;
let curly = false;
while(pointer < info.content.length){
c = info.content[pointer];
const currentState = state.now();
curly = currentState != 2 && (c === "{" || c === "}");
if(!curly){
token+=c;
}
switch(currentState){
case 0:
switch(c){
case "/":
if(info.content[pointer+1] === "*"){
state.set(2);
if(token.length > 1){
token = token.slice(0,-1);
createElementFromToken("selector");
token += "/"
}
}
break;
case "{":
state.set(3);
createElementFromToken("selector");
break;
case "}":
createElementFromToken("text");
break;
case "@":
state.set(5);
}
break;
case 2:
switch(c){
case "*":
if(info.content[pointer+1] === "/"){
token += "/";
pointer++;
state.set(state.previous());
createElementFromToken("comment");
}
}
break;
case 3:
switch(c){
case "/":
if(info.content[pointer+1] === "*"){
state.set(2);
}
break;
case ":":
createElementFromToken("property");
state.set(4);
break;
case "}":
createElementFromToken("text");
state.set(0);
}
break;
case 4:
switch(c){
case ";":
createElementFromToken("value");
state.set(3);
break;
case "}":
createElementFromToken("value");
state.set(0);
break;
case "(":
createElementFromToken("value");
functionValueLevel++;
state.set(7);
}
break;
case 5:
switch(c){
case " ":
createElementFromToken("atrule");
state.set(6);
}
break;
case 6:
switch(c){
case ";":
case "{":
createElementFromToken("atvalue");
state.set(0);
}
break
case 7:
switch(c){
case ")":
functionValueLevel--;
if(functionValueLevel === 0){
createElementFromToken("function");
token = ")";
state.set(4);
}
break;
case "}":
functionValueLevel = 0;
state.set(0)
}
default:
false
}
curly && createElementFromToken("curly",c);
pointer++
}
createElementFromToken("text");
token = "";
state.set(0);
pointer = 0;
if(info.file.endsWith("support.css")){
targetNode.prepend(node);
}else{
targetNode.appendChild(node);
}
return
}
return this
})();
async function handleSearchQuery(){
let params = (new URL(document.location)).searchParams;
let param = params.get("tag");
@@ -579,7 +332,7 @@ async function handleSearchQuery(){
param = params.get("file");
if(param){
let files = param.split(",").filter(a => DB.keys.includes(a));
let box = document.getElementById("previewBox");
if(files.length === 0 ){
return
}
@@ -589,7 +342,10 @@ async function handleSearchQuery(){
Promise.all(promises)
.then(responses => {
showMatchingTargets(files,true);
responses.forEach(Highlighter.parse)
responses.forEach((res)=>{
res.insertMode = res.file.endsWith("window_control_placeholder_support.css") ? box.InsertModes.Prepend : box.InsertModes.AppendLines;
box.insertContent(res)
})
});
}
@@ -611,8 +367,8 @@ document.onreadystatechange = (function () {
if (document.readyState === "complete") {
function linkClicked(ev){
if(ev.target instanceof HTMLAnchorElement){
let ref = ev.target.href;
if(ev.originalTarget instanceof HTMLAnchorElement){
let ref = ev.originalTarget.href;
if(!ref){
return
}