forked from Acode-Foundation/Acode
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathcolorView.js
157 lines (129 loc) · 3.81 KB
/
colorView.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/**
* This piece of code belongs to github.com/easylogic and is licensed under MIT
* @see https://github.com/easylogic/ace-colorpicker/blob/main/src/extension/ace/colorview.js
*/
import Color from "utils/color";
import { HEX, HSL, HSLA, RGB, RGBA, isValidColor } from "utils/color/regex";
const COLORPICKER_TOKEN_CLASS = ".ace_color";
const changedRules = [];
let editor = null;
/**
* Initialize color view
* @param {AceAjax.Editor} e Editor instance
* @param {boolean} [force=false] Force update color view
*/
export default function initColorView(e, force = false) {
editor = e;
const { renderer } = editor;
editor.on("changeMode", onChangeMode);
renderer.on("afterRender", afterRender);
if (force) {
const { files } = editorManager;
if (Array.isArray(files)) {
files.forEach((file) => {
if (file.session) {
file.session._addedColorRule = false;
}
});
}
onChangeMode();
}
}
export function deactivateColorView() {
const { renderer } = editor;
changedRules.forEach((rule) => rule.shift());
changedRules.length = 0;
forceTokenizer();
editor.off("changeMode", onChangeMode);
renderer.off("afterRender", afterRender);
}
/**
* Checks if the session supports color
* @param {AceAjax.IEditSession} session
* @returns
*/
function sessionSupportsColor(session) {
const mode = session.getMode().$id.split("/").pop();
return /css|less|scss|sass|stylus|html|dart/.test(mode) ? mode : false;
}
function onChangeMode() {
const session = editor.session;
let forceUpdate = false;
// if mode is not css, scss, sass, less, stylus, or html, return
const mode = sessionSupportsColor(session);
if (session._addedColorRule || !mode) {
return;
}
let rules = session.$mode.$highlightRules.getRules();
if (mode === "css") {
rules = { ruleset: rules["ruleset"] };
} else if (mode === "html") {
rules = { "css-ruleset": rules["css-ruleset"] };
}
Object.keys(rules).forEach((key) => {
const rule = rules[key];
if (Array.isArray(rule)) {
const ruleExists = rule.some((r) => r.token === "color");
if (ruleExists) return;
forceUpdate = true;
rule.unshift({
token: "color",
regex: `${HEX}|${RGB}|${RGBA}|${HSL}|${HSLA}`,
});
changedRules.push(rule);
return;
}
});
if (!forceUpdate) return;
forceTokenizer();
}
function afterRender() {
const { session, renderer } = editor;
const { content } = renderer;
let classes = COLORPICKER_TOKEN_CLASS;
// if session is css, scss, less, sass, stylus, or html (with css mode), continue
const mode = sessionSupportsColor(session);
if (!mode) {
return;
}
if (mode === "scss") {
classes += ",.ace_function";
}
content
.getAll(COLORPICKER_TOKEN_CLASS)
.forEach((/**@type {HTMLElement} */ el, i, els) => {
let content = el.textContent;
const previousContent = els[i - 1]?.textContent;
const nextContent = els[i + 1]?.textContent;
const multiLinePrev = previousContent + content;
const multiLineNext = content + nextContent;
if (el.dataset.modified === "true") return;
el.dataset.modified = "true";
if (!isValidColor(content)) {
if (isValidColor(multiLinePrev)) {
content = multiLinePrev;
} else if (isValidColor(multiLineNext)) {
content = multiLineNext;
} else {
return;
}
}
try {
const fontColorString =
Color(content).luminance > 0.5 ? "#000" : "#fff";
el.classList.add("ace_color");
el.style.cssText = `background-color: ${content}; color: ${fontColorString}; pointer-events: all;`;
} catch (error) {
window.log("error", `Invalid color: ${content}`);
window.log("error", error);
}
});
}
function forceTokenizer() {
const { session } = editor;
// force recreation of tokenizer
session.$mode.$tokenizer = null;
session.bgTokenizer.setTokenizer(session.$mode.getTokenizer());
// force re-highlight whole document
session.bgTokenizer.start(0);
}