@neonwilderness/moveskins 1.1.3 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -1
- package/dist/index.js +788 -650
- package/package.json +13 -11
- package/skins/skinRegister.json +12 -0
- package/src/_download.js +63 -1
- package/src/_upload.js +34 -12
- package/src/index.js +17 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neonwilderness/moveskins",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Download/Upload/Compare modified skins for selected aliases on Twoday",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"antville",
|
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
],
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"author": "NeonWilderness",
|
|
13
|
+
"bin": {
|
|
14
|
+
"moveskins": "./dist/index.js"
|
|
15
|
+
},
|
|
13
16
|
"files": [
|
|
14
17
|
"dist",
|
|
15
18
|
"skins/skinRegister.json",
|
|
@@ -22,24 +25,23 @@
|
|
|
22
25
|
],
|
|
23
26
|
"type": "module",
|
|
24
27
|
"exports": "./dist/index.js",
|
|
25
|
-
"bin": {
|
|
26
|
-
"moveskins": "./dist/index.js"
|
|
27
|
-
},
|
|
28
28
|
"scripts": {
|
|
29
29
|
"update": "ncu -u && npm i",
|
|
30
30
|
"backup": "node ./src/index --backup --alias=www --from=prod",
|
|
31
31
|
"dev": "vp run node ./src/index.js",
|
|
32
32
|
"build": "vp build",
|
|
33
33
|
"check": "vp check",
|
|
34
|
+
"check:fix": "vp check --fix",
|
|
34
35
|
"create": "node ./src/create --skin=Site.testskin --alias=talkstraight",
|
|
35
36
|
"//": "For compare function, live-server module must be installed globally!",
|
|
36
37
|
"compare": "node ./src/index --compare --alias=help --to=dev && npm run report",
|
|
37
38
|
"compare:blogs": "node ./src/index --compare --alias=foundation:info --to=prod && npm run report",
|
|
38
|
-
"download": "node ./src/index --alias=
|
|
39
|
+
"download": "node ./src/index --alias=www --from=prod --modules",
|
|
39
40
|
"download2": "node ./src/index --alias=info,help --from=prod",
|
|
40
|
-
"download:
|
|
41
|
-
"download:
|
|
42
|
-
"download:core
|
|
41
|
+
"download:toolbar": "node ./src/index --alias=www --from=prod --toolbar --skin=modToolbar",
|
|
42
|
+
"download:clean": "node ./src/index --alias=www --from=prod --clean --modules",
|
|
43
|
+
"download:core": "node ./src/index --alias=* --from=prod --modules",
|
|
44
|
+
"download:core:clean": "node ./src/index --alias=* --from=prod --clean --modules",
|
|
43
45
|
"report": "live-server --open=./report.html --quiet",
|
|
44
46
|
"restore": "node ./src/index --backup --alias=www --to=dev",
|
|
45
47
|
"upload": "node ./src/index --alias=neonwilderness --to=dev",
|
|
@@ -51,16 +53,16 @@
|
|
|
51
53
|
"test:ui": "vp test --ui"
|
|
52
54
|
},
|
|
53
55
|
"dependencies": {
|
|
54
|
-
"@neonwilderness/twoday": "^0.
|
|
56
|
+
"@neonwilderness/twoday": "^0.8.0",
|
|
55
57
|
"chalk": "^5.6.2",
|
|
56
58
|
"del": "^8.0.1",
|
|
57
59
|
"dotenv-safe": "^9.1.0",
|
|
58
60
|
"yargs": "^18.0.0"
|
|
59
61
|
},
|
|
60
62
|
"devDependencies": {
|
|
61
|
-
"@vitest/ui": "4.1.
|
|
63
|
+
"@vitest/ui": "4.1.5",
|
|
62
64
|
"slash": "^5.1.0",
|
|
63
|
-
"vite-plus": "^0.1.
|
|
65
|
+
"vite-plus": "^0.1.20"
|
|
64
66
|
},
|
|
65
67
|
"engines": {
|
|
66
68
|
"node": ">=20"
|
package/skins/skinRegister.json
CHANGED
|
@@ -218,5 +218,17 @@
|
|
|
218
218
|
"Site.flagReasons": {
|
|
219
219
|
"title": "Globale Texte für Beitragsmarkierungen",
|
|
220
220
|
"description": "In diesem Systemskin werden die gültigen Beitragsmarkierungsgründe mit ihren jeweiligen Texten in Deutsch (de) und Englisch (en) hinterlegt."
|
|
221
|
+
},
|
|
222
|
+
"Site.adminnavigation": {
|
|
223
|
+
"title": "Navigationsleiste für Site Administratoren",
|
|
224
|
+
"description": "Dieses Skin beinhaltet die zusätzlichen Navigationselemente für Site Administratoren. (z.B. »Einstellungen bearbeiten«, »Skins bearbeiten«, ...)"
|
|
225
|
+
},
|
|
226
|
+
"Site.modToolbarMain": {
|
|
227
|
+
"title": "Toolbar HTML-Code",
|
|
228
|
+
"description": "HTML-Code der toolbar Zeile, jedoch ohne die Dropdowns."
|
|
229
|
+
},
|
|
230
|
+
"Site.modToolbarClosed": {
|
|
231
|
+
"title": "Closed Toolbar",
|
|
232
|
+
"description": "Geschlossene Version der Toolbar."
|
|
221
233
|
}
|
|
222
234
|
}
|
package/src/_download.js
CHANGED
|
@@ -8,6 +8,28 @@ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
|
8
8
|
import { resolve } from "node:path";
|
|
9
9
|
import { aliasSkinFolder, skinRegister } from "./_utils.js";
|
|
10
10
|
|
|
11
|
+
const capitalize = (text) => text.charAt(0).toUpperCase() + text.slice(1);
|
|
12
|
+
|
|
13
|
+
const findEmbeddedSkinMacros = async (td, alias, skinContent, skinContainer) => {
|
|
14
|
+
const skinMacros = skinContent.match(/<%\s.*?\.skin name=".*?"\s%>/g);
|
|
15
|
+
if (skinMacros) {
|
|
16
|
+
for (let macro of skinMacros) {
|
|
17
|
+
// example: '<% Site.skin name="legalRefs" %>'
|
|
18
|
+
const s = macro.match(/(\w+)\.skin name="(\w+)"/);
|
|
19
|
+
if (!s) continue;
|
|
20
|
+
const skinName = `${capitalize(s[1])}.${s[2]}`;
|
|
21
|
+
const layoutUrl = await td.getActiveLayoutUrl(alias);
|
|
22
|
+
const { skin } = await td.getSkin({
|
|
23
|
+
name: skinName,
|
|
24
|
+
url: `${layoutUrl}/skins/edit?key=${skinName}`,
|
|
25
|
+
});
|
|
26
|
+
skinContainer[skinName] = skin;
|
|
27
|
+
skinContainer = await findEmbeddedSkinMacros(td, alias, skin, skinContainer);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return skinContainer;
|
|
31
|
+
};
|
|
32
|
+
|
|
11
33
|
/**
|
|
12
34
|
* Downloads all customized skins of one or more aliases and stores them in appropriate
|
|
13
35
|
* subdirectories for subsequent manual edits (or just as backup)
|
|
@@ -22,6 +44,7 @@ const downloadModifiedSkins = async (td, aliases, options) => {
|
|
|
22
44
|
console.log(chalk.green(`\nNow processing alias "${alias}"...`));
|
|
23
45
|
const aliasSkinDir = aliasSkinFolder(alias, options.backup);
|
|
24
46
|
const modifiedSkins = await td.getModifiedSkins(alias);
|
|
47
|
+
let skinContainer = {};
|
|
25
48
|
|
|
26
49
|
if (modifiedSkins.length && !existsSync(aliasSkinDir)) mkdirSync(aliasSkinDir);
|
|
27
50
|
console.log(
|
|
@@ -37,7 +60,46 @@ const downloadModifiedSkins = async (td, aliases, options) => {
|
|
|
37
60
|
const { title, description, skin } = await td.getSkin(modSkin);
|
|
38
61
|
|
|
39
62
|
skinRegister.setData(modSkin.name, title, description);
|
|
40
|
-
|
|
63
|
+
skinContainer[modSkin.name] = skin;
|
|
64
|
+
skinContainer = await findEmbeddedSkinMacros(td, alias, skin, skinContainer);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (options.modules) {
|
|
68
|
+
console.log(chalk.yellow(`Exporting sidebar freetext modules as requested.`));
|
|
69
|
+
const sidebar = await td.getSidebarModules(alias);
|
|
70
|
+
const moduleNames = [...sidebar.sidebar01, ...sidebar.sidebar02];
|
|
71
|
+
for (let module of moduleNames) {
|
|
72
|
+
if (td.isValidFreeTextModule(module)) {
|
|
73
|
+
console.log(chalk.gray(`Reading sidebar module "${module}".`));
|
|
74
|
+
const { heading, content } = await td.getFreeTextModule(alias, module);
|
|
75
|
+
skinContainer[`Sidebar.${module}`] = `${heading}\n${content}`;
|
|
76
|
+
} else {
|
|
77
|
+
const { skins } = await td.getModuleSkins(alias, module);
|
|
78
|
+
for (let s of skins) {
|
|
79
|
+
const { title, description, skin } = await td.getSkin(s);
|
|
80
|
+
skinRegister.setData(s.name, title, description);
|
|
81
|
+
skinContainer[s.name] = skin;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (options.toolbar) {
|
|
88
|
+
const layoutUrl = await td.getActiveLayoutUrl(alias);
|
|
89
|
+
for (const s of ["Main", "DropDowns", "Closed"]) {
|
|
90
|
+
const name = `Site.modToolbar${s}`;
|
|
91
|
+
console.log(chalk.gray(`Reading "${name}".`));
|
|
92
|
+
const { title, description, skin } = await td.getSkin({
|
|
93
|
+
name,
|
|
94
|
+
url: `${layoutUrl}/skins/edit?key=${name}`,
|
|
95
|
+
});
|
|
96
|
+
skinRegister.setData(name, title, description);
|
|
97
|
+
skinContainer[name] = skin;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
for (const [name, content] of Object.entries(skinContainer)) {
|
|
102
|
+
writeFileSync(resolve(aliasSkinDir, `${name}.skin`), content);
|
|
41
103
|
}
|
|
42
104
|
}
|
|
43
105
|
console.log(chalk.green("Download completed."));
|
package/src/_upload.js
CHANGED
|
@@ -35,19 +35,41 @@ const uploadModifiedSkins = async (td, aliases, options) => {
|
|
|
35
35
|
if (!skinFile.endsWith(".skin")) continue;
|
|
36
36
|
if (options.skin && !options.skin.test(skinFile)) continue;
|
|
37
37
|
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
const [hoptype, name] = skinFile.split(".");
|
|
39
|
+
if (hoptype === "Sidebar") {
|
|
40
|
+
const module = readFileSync(resolve(aliasSkinDir, skinFile))
|
|
41
|
+
.toString()
|
|
42
|
+
.replace(/\r\n/g, "\n");
|
|
43
|
+
let splitAt = module.indexOf("\n");
|
|
44
|
+
const heading = module.slice(0, splitAt);
|
|
45
|
+
const content = module.slice(++splitAt);
|
|
46
|
+
console.log(chalk.blue(`Now updating sidebar module ${name} (len=${content.length}).`));
|
|
47
|
+
await td.updateFreeTextModule(alias, name, { heading, content });
|
|
48
|
+
console.log(chalk.green(`Update request completed for module: ${name}`));
|
|
49
|
+
} else {
|
|
50
|
+
const { isValid, prototype } = td.isValidHoptype(skinFile.slice(0, -5));
|
|
51
|
+
if (!isValid) {
|
|
52
|
+
console.log(
|
|
53
|
+
chalk.red(
|
|
54
|
+
`Skipping upload for invalid skin hoptype "${prototype}" (Skin file ${skinFile}).`,
|
|
55
|
+
),
|
|
56
|
+
);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
const skin = skinRegister.getData(skinFile);
|
|
60
|
+
skin.content = readFileSync(resolve(aliasSkinDir, skinFile))
|
|
61
|
+
.toString()
|
|
62
|
+
.replace(/\r\n/g, "\n");
|
|
42
63
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
64
|
+
console.log(chalk.blue(`Now updating skin ${skin.name} (len=${skin.content.length}).`));
|
|
65
|
+
await td.updateSkin(alias, skin.name, {
|
|
66
|
+
title: skin.title,
|
|
67
|
+
description: skin.description,
|
|
68
|
+
skin: skin.content,
|
|
69
|
+
diff: options.debug,
|
|
70
|
+
});
|
|
71
|
+
console.log(chalk.green(`Update request completed for skin: ${skin.name}`));
|
|
72
|
+
}
|
|
51
73
|
|
|
52
74
|
if (currentSkins.has(skin.name)) currentSkins.delete(skin.name);
|
|
53
75
|
}
|
package/src/index.js
CHANGED
|
@@ -33,6 +33,17 @@ const argv = yargs(process.argv.slice(2)).options({
|
|
|
33
33
|
description: "Skin selection string (regex) to filter the skins to upload",
|
|
34
34
|
type: "string",
|
|
35
35
|
},
|
|
36
|
+
modules: {
|
|
37
|
+
alias: "m",
|
|
38
|
+
description: "Download sidebar module skins/freetext as well",
|
|
39
|
+
default: false,
|
|
40
|
+
type: "boolean",
|
|
41
|
+
},
|
|
42
|
+
toolbar: {
|
|
43
|
+
description: "Download modToolbar skins, too",
|
|
44
|
+
default: false,
|
|
45
|
+
type: "boolean",
|
|
46
|
+
},
|
|
36
47
|
backup: {
|
|
37
48
|
alias: "b",
|
|
38
49
|
description: "Backup skins to the local /backup folder to preserve their former status",
|
|
@@ -99,7 +110,10 @@ if (argv.compare) {
|
|
|
99
110
|
const direction = argv.from ? "from" : "to";
|
|
100
111
|
const execTask = argv.from ? downloadModifiedSkins : uploadModifiedSkins;
|
|
101
112
|
|
|
102
|
-
if (action === "down" && argv.clean)
|
|
113
|
+
if (action === "down" && argv.clean) {
|
|
114
|
+
cleanupAliasFolder(aliases, argv.backup);
|
|
115
|
+
console.log(chalk.yellow(`Cleaning target download folder/s for "${aliases}".`));
|
|
116
|
+
}
|
|
103
117
|
|
|
104
118
|
console.log(
|
|
105
119
|
`Start ${action}loading modified skins of alias${aliases.length > 1 ? "es" : ""} ${chalk.yellow(
|
|
@@ -109,6 +123,8 @@ if (argv.compare) {
|
|
|
109
123
|
execTask(td, aliases, {
|
|
110
124
|
backup: argv.backup,
|
|
111
125
|
debug: argv.debug,
|
|
126
|
+
modules: argv.modules,
|
|
112
127
|
skin: argv.skin ? new RegExp(argv.skin) : null,
|
|
128
|
+
toolbar: argv.toolbar,
|
|
113
129
|
});
|
|
114
130
|
}
|