@simple-reporting/base 1.0.22 → 1.0.24
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/dev/index.html +1 -1
- package/dev/livingdocs.config.json +6 -6
- package/dev/package.json +1 -1
- package/dev/src/Dialog.vue +3 -0
- package/dev/src/assets/scss/general.scss +1 -0
- package/dev/src/assets/scss/pdf.scss +13 -0
- package/dev/src/entries/pdf.ts +14 -1
- package/dev/srl.config.json +21 -0
- package/livingdocs/040.Media/010.table/scss/pdf.scss +20 -0
- package/livingdocs/080.CV/010.cv/cv.html +34 -32
- package/livingdocs/100.Misc/010.anchor/anchor.html +1 -1
- package/livingdocs/100.Misc/020.accordion/accordion.html +7 -5
- package/livingdocs/110.PDF/100.pdf-toc-item/scss/general.scss +1 -1
- package/package.json +2 -1
- package/scripts/beaver.js +14 -18
- package/scripts/build/variables.d.ts +6 -0
- package/scripts/build/variables.js +6 -0
- package/scripts/build.js +56 -16
- package/scripts/dotenv.d.ts +1 -0
- package/scripts/dotenv.js +8 -0
- package/scripts/init.js +1 -1
- package/scripts/ldd/mapLdd.js +2 -2
- package/scripts/utils.d.ts +1 -0
- package/scripts/utils.js +22 -0
- package/scss/colors/functions.scss +2 -10
- package/scss/colors/mixins.scss +0 -18
- package/scss/colors/root.scss +10 -0
- package/scss/core-styles.scss +4 -1
- package/scss/fonts/root.scss +4 -0
- package/scss/grid/functions.scss +8 -6
- package/scss/grid/mixins.scss +0 -77
- package/scss/grid/root.scss +80 -0
- package/scss/helpers/root.scss +4 -0
- package/scss/init-root.scss +12 -0
- package/scss/meta/root.scss +4 -0
- package/scss/spacer/functions.scss +2 -1
- package/scss/spacer/mixins.scss +0 -52
- package/scss/spacer/root.scss +55 -0
- package/scss/system/functions.scss +70 -5
- package/scss/system/root.scss +0 -3
- package/scss/system/variables.scss +1 -0
- package/scss/typography/functions.scss +12 -12
- package/scss/typography/mixins.scss +0 -221
- package/scss/typography/root.scss +226 -0
- package/srl/.srl/App.vue +9 -5
- package/srl/.srl/components/Srl/Article/Accordion.vue +106 -0
- package/srl/.srl/components/Srl/Article/Dialog/Button.vue +39 -18
- package/srl/.srl/components/Srl/Category/Accordion.vue +32 -4
- package/srl/.srl/components/Srl/Page/Dialog.vue +17 -19
- package/srl/.srl/plugins/initProject.ts +12 -7
- package/srl/.srl/utils/html.ts +71 -62
- package/srl/.srl/utils/index.ts +28 -1
- package/srl/.srl/utils/pageState.ts +61 -0
- package/srl/srl/pdf/PDFNotes.ts +71 -0
- package/srl/srl/pdf/PDFSetPageNumbers.ts +25 -0
- package/srl/srl/pdf.scss +0 -2
- /package/srl/srl/{Awesomizr.js → pdf/Awesomizr.js} +0 -0
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed, ref, useId } from 'vue'
|
|
2
|
+
import { computed, nextTick, onMounted, ref, useId } from 'vue'
|
|
3
|
+
import { useRoute } from 'vue-router'
|
|
4
|
+
import { isAccordionAnchored, setAccordionAnchored } from '#utils'
|
|
3
5
|
|
|
4
6
|
const rootEl = ref<HTMLElement | null>(null)
|
|
5
7
|
const id = ref(useId())
|
|
6
8
|
const state = ref(false)
|
|
9
|
+
const route = useRoute()
|
|
7
10
|
function toggle() {
|
|
8
11
|
state.value ?
|
|
9
|
-
|
|
10
|
-
|
|
12
|
+
close() :
|
|
13
|
+
open()
|
|
11
14
|
}
|
|
12
15
|
|
|
13
16
|
function open() {
|
|
@@ -32,10 +35,35 @@ const accordion = computed(() => {
|
|
|
32
35
|
}
|
|
33
36
|
})
|
|
34
37
|
|
|
38
|
+
onMounted(() => {
|
|
39
|
+
if (route.hash) {
|
|
40
|
+
if (rootEl.value.id && rootEl.value.id === route.hash) {
|
|
41
|
+
open()
|
|
42
|
+
isAccordionAnchored() || setAccordionAnchored(true)
|
|
43
|
+
} else {
|
|
44
|
+
const targetEl = rootEl.value?.querySelector<HTMLElement>(route.hash)
|
|
45
|
+
if (targetEl) {
|
|
46
|
+
open()
|
|
47
|
+
if (!isAccordionAnchored()) {
|
|
48
|
+
setAccordionAnchored(true)
|
|
49
|
+
nextTick(() => {
|
|
50
|
+
setTimeout(() => {
|
|
51
|
+
rootEl.value.scrollIntoView({
|
|
52
|
+
behavior: 'smooth',
|
|
53
|
+
block: 'start',
|
|
54
|
+
})
|
|
55
|
+
}, 200)
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
|
|
35
63
|
</script>
|
|
36
64
|
|
|
37
65
|
<template>
|
|
38
|
-
<div ref="rootEl">
|
|
66
|
+
<div ref="rootEl" tabindex="-1">
|
|
39
67
|
<slot :accordion="accordion"/>
|
|
40
68
|
</div>
|
|
41
69
|
</template>
|
|
@@ -1,25 +1,23 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { ref } from 'vue'
|
|
2
|
+
import { computed, ref } from 'vue'
|
|
3
3
|
import SrlPageCustomDialog from '@/Dialog.vue';
|
|
4
4
|
import Autoload from '@/Autoload.ts';
|
|
5
5
|
|
|
6
6
|
const props = withDefaults(
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
defineProps<{
|
|
8
|
+
header?: string;
|
|
9
|
+
content?: string;
|
|
10
|
+
}>(),
|
|
11
|
+
{
|
|
12
|
+
header: '',
|
|
13
|
+
content: '',
|
|
14
|
+
},
|
|
15
15
|
);
|
|
16
16
|
|
|
17
17
|
const $el = ref<HTMLDialogElement | null>(null);
|
|
18
|
-
const dialogState = ref<boolean>(false);
|
|
19
|
-
|
|
20
18
|
const header = ref<string>(props.header);
|
|
21
19
|
const content = ref<string>(props.content);
|
|
22
|
-
|
|
20
|
+
const dialogState = ref<boolean>(false);
|
|
23
21
|
function setDialogContent(template: string) {
|
|
24
22
|
content.value = template;
|
|
25
23
|
}
|
|
@@ -30,15 +28,15 @@ function setDialogContentAndOpen(template: string) {
|
|
|
30
28
|
}
|
|
31
29
|
|
|
32
30
|
function open() {
|
|
33
|
-
$el.value?.showModal();
|
|
34
31
|
dialogState.value = true;
|
|
32
|
+
$el.value?.showModal();
|
|
35
33
|
$el.value?.querySelector('.srl-dialog__main')?.focus();
|
|
36
34
|
Autoload.init($el.value);
|
|
37
35
|
}
|
|
38
36
|
|
|
39
37
|
function close() {
|
|
40
|
-
$el.value?.close();
|
|
41
38
|
dialogState.value = false;
|
|
39
|
+
$el.value?.close();
|
|
42
40
|
}
|
|
43
41
|
|
|
44
42
|
function clearContent() {
|
|
@@ -58,11 +56,11 @@ defineExpose({
|
|
|
58
56
|
|
|
59
57
|
<template>
|
|
60
58
|
<dialog
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
59
|
+
ref="$el"
|
|
60
|
+
id="srl-page__dialog"
|
|
61
|
+
class="srl-page__dialog"
|
|
62
|
+
aria-modal="true"
|
|
63
|
+
@click.stop="close"
|
|
66
64
|
>
|
|
67
65
|
<SrlAriaTabChain @click.stop>
|
|
68
66
|
<SrlPageCustomDialog :header="header" :content="content" @close="close" />
|
|
@@ -2,6 +2,7 @@ import { setConfig } from '#composables/config';
|
|
|
2
2
|
import { createApp } from 'vue';
|
|
3
3
|
import { initI18n } from '@/i18n';
|
|
4
4
|
import srlVuePlugin from '#plugins/vueSrlPlugin';
|
|
5
|
+
import { clearPageState } from '#utils'
|
|
5
6
|
|
|
6
7
|
import '#imports/app.scss';
|
|
7
8
|
|
|
@@ -9,11 +10,15 @@ import SrlPageApp from '../App.vue';
|
|
|
9
10
|
import router from '@/router';
|
|
10
11
|
|
|
11
12
|
export default async function initProject() {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
router.beforeEach((to, from, next) => {
|
|
14
|
+
clearPageState();
|
|
15
|
+
next();
|
|
16
|
+
});
|
|
17
|
+
await setConfig();
|
|
18
|
+
const i18n = initI18n();
|
|
19
|
+
const app = (window.app = createApp(SrlPageApp));
|
|
20
|
+
app.use(i18n);
|
|
21
|
+
app.use(router);
|
|
22
|
+
app.use(srlVuePlugin);
|
|
23
|
+
return app;
|
|
19
24
|
}
|
package/srl/.srl/utils/html.ts
CHANGED
|
@@ -3,83 +3,92 @@ import { useArticles, useLocale, addCssStyles } from '#composables';
|
|
|
3
3
|
|
|
4
4
|
type AttrObj = { [key: string]: string | null };
|
|
5
5
|
function attributesToString(attributes: Record<string, string | null>): string {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
return Object.entries(attributes)
|
|
7
|
+
.map(([key, value]) => (value !== null ? `${key}="${value}"` : key))
|
|
8
|
+
.join(' ');
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export function prepareHtmlContent(text: string): string {
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
const articles = useArticles();
|
|
13
|
+
const locale = useLocale();
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
const regex = /<a\s+([^>]+)>(.*?)<\/a>/gis;
|
|
16
|
+
text = text.replace(regex, (match, attrString, innerText) => {
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
const attrObj: AttrObj = {};
|
|
19
|
+
attrString.replace(/([a-zA-Z0-9\-_]+)(?:="([^"]*)")?/g, (m, key: string, value: string | null) => {
|
|
20
|
+
attrObj[key] = value || null;
|
|
21
|
+
return m;
|
|
22
|
+
});
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
24
|
+
if (
|
|
25
|
+
attrObj['data-note-target'] &&
|
|
26
|
+
attrObj['data-note-target'] === 'popup'
|
|
27
|
+
) {
|
|
28
|
+
attrObj.uuid = attrObj.href;
|
|
29
|
+
delete attrObj.href;
|
|
30
|
+
if (attrObj['data-article-name']) {
|
|
31
|
+
attrObj.uuid = attrObj['data-article-name'];
|
|
32
|
+
delete attrObj['data-article-name'];
|
|
33
|
+
}
|
|
34
|
+
const arrUuid = attrObj.uuid.split('#');
|
|
35
|
+
attrObj.uuid = arrUuid[0];
|
|
36
|
+
if (arrUuid[1]) {
|
|
37
|
+
attrObj.anchor = arrUuid[1];
|
|
38
|
+
}
|
|
39
|
+
const attrs = attributesToString(attrObj);
|
|
40
|
+
return `<srl-article-dialog-button ${attrs}>${innerText}</srl-article-dialog-button>`;
|
|
41
|
+
}
|
|
33
42
|
|
|
34
|
-
|
|
35
|
-
|
|
43
|
+
if (attrObj.href) {
|
|
44
|
+
const arrLink = attrObj.href.split('#');
|
|
36
45
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
46
|
+
if (isRouterPath(arrLink[0])) {
|
|
47
|
+
delete attrObj.href;
|
|
48
|
+
if (arrLink[0].startsWith('./')) {
|
|
49
|
+
arrLink[0] = arrLink[0].substring(1);
|
|
50
|
+
}
|
|
51
|
+
if (arrLink[0] === `/${locale.value}/home`) {
|
|
52
|
+
arrLink[0] = `/${locale.value}`;
|
|
53
|
+
}
|
|
54
|
+
attrObj.to = arrLink[0];
|
|
55
|
+
if (arrLink[1]) {
|
|
56
|
+
attrObj.to += `#${arrLink[1]}`;
|
|
57
|
+
}
|
|
58
|
+
const attrs = attributesToString(attrObj);
|
|
59
|
+
return `<router-link ${attrs}>${innerText}</router-link>`;
|
|
60
|
+
}
|
|
52
61
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
62
|
+
const a = articles.value.find((i) => i.uuid === arrLink[0]);
|
|
63
|
+
if (a) {
|
|
64
|
+
delete attrObj.href;
|
|
65
|
+
attrObj.to = a.index
|
|
66
|
+
? `/${locale.value}`
|
|
67
|
+
: `/${locale.value}/${a.slug}`;
|
|
68
|
+
if (arrLink[1]) {
|
|
69
|
+
attrObj.to += `#${arrLink[1]}`;
|
|
70
|
+
}
|
|
71
|
+
const attrs = attributesToString(attrObj);
|
|
72
|
+
return `<router-link ${attrs}>${innerText}</router-link>`;
|
|
73
|
+
}
|
|
61
74
|
}
|
|
62
|
-
const attrs = attributesToString(attrObj);
|
|
63
|
-
return `<router-link ${attrs}>${innerText}</router-link>`;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
75
|
|
|
67
|
-
|
|
68
|
-
|
|
76
|
+
return match;
|
|
77
|
+
});
|
|
69
78
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
79
|
+
text = text.replace(
|
|
80
|
+
/<template-([a-z]+)>([\s\S]*?)<\/template-\1>/g,
|
|
81
|
+
(_match, name, content) => `<template #${name}>${content}</template>`
|
|
82
|
+
);
|
|
74
83
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
84
|
+
text = text.replace(/<style[^>]*>([\s\S]*?)<\/style>/gi, (match, p1) => {
|
|
85
|
+
addCssStyles(p1);
|
|
86
|
+
return '';
|
|
87
|
+
});
|
|
79
88
|
|
|
80
|
-
|
|
89
|
+
return text;
|
|
81
90
|
}
|
|
82
91
|
|
|
83
92
|
export default {
|
|
84
|
-
|
|
93
|
+
prepareHtmlContent,
|
|
85
94
|
};
|
package/srl/.srl/utils/index.ts
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
import { isRouterPath, isExternalPath } from './uri';
|
|
2
2
|
import { camelCase } from './camelCase';
|
|
3
3
|
import { prepareHtmlContent } from './html';
|
|
4
|
+
import {
|
|
5
|
+
usePageState,
|
|
6
|
+
clearPageState,
|
|
7
|
+
isDialogStored,
|
|
8
|
+
addDialogToStorage,
|
|
9
|
+
getDialogFromStorage,
|
|
10
|
+
getDialogStorage,
|
|
11
|
+
isAccordionAnchored,
|
|
12
|
+
setAccordionAnchored,
|
|
13
|
+
isMounted,
|
|
14
|
+
setMounted
|
|
15
|
+
} from './pageState.ts';
|
|
4
16
|
|
|
5
|
-
export {
|
|
17
|
+
export {
|
|
18
|
+
isRouterPath,
|
|
19
|
+
isExternalPath,
|
|
20
|
+
camelCase,
|
|
21
|
+
prepareHtmlContent,
|
|
22
|
+
usePageState,
|
|
23
|
+
clearPageState,
|
|
24
|
+
isAccordionAnchored,
|
|
25
|
+
setAccordionAnchored,
|
|
26
|
+
isDialogStored,
|
|
27
|
+
addDialogToStorage,
|
|
28
|
+
getDialogFromStorage,
|
|
29
|
+
getDialogStorage,
|
|
30
|
+
setMounted,
|
|
31
|
+
isMounted,
|
|
32
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { type Ref } from 'vue'
|
|
2
|
+
|
|
3
|
+
type DialogStorage = {
|
|
4
|
+
[key: string]: Ref<SrlPageDialog>;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
type PageState = {
|
|
8
|
+
isMounted: boolean;
|
|
9
|
+
dialogStorage: DialogStorage;
|
|
10
|
+
accordionAnchored: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const pageState: PageState = {
|
|
14
|
+
isMounted: false,
|
|
15
|
+
dialogStorage: {},
|
|
16
|
+
accordionAnchored: false,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function usePageState() {
|
|
20
|
+
return pageState;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function setMounted(value: boolean): void {
|
|
24
|
+
pageState.isMounted = value;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function isMounted(): boolean {
|
|
28
|
+
return pageState.isMounted;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function clearPageState() {
|
|
32
|
+
pageState.isMounted = false;
|
|
33
|
+
pageState.dialogStorage = {};
|
|
34
|
+
pageState.accordionAnchored = false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function isDialogStored(uuid: string): boolean {
|
|
38
|
+
return uuid in pageState.dialogStorage
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function addDialogToStorage(uuid: string, refSrlPageDialog: Ref<SrlPageDialog>): void {
|
|
42
|
+
pageState.dialogStorage[uuid] = refSrlPageDialog
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function getDialogFromStorage(uuid: string): Ref<SrlPageDialog> | null {
|
|
46
|
+
return isDialogStored(uuid)?
|
|
47
|
+
pageState.dialogStorage[uuid] : null
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function getDialogStorage() : DialogStorage {
|
|
51
|
+
return pageState.dialogStorage
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function setAccordionAnchored(value: boolean): void {
|
|
55
|
+
pageState.accordionAnchored = value;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function isAccordionAnchored(): boolean {
|
|
59
|
+
return pageState.accordionAnchored;
|
|
60
|
+
}
|
|
61
|
+
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
export interface PDFNotesConfig {
|
|
2
|
+
noteClass: string; // kann mehrere Selektoren per Komma enthalten
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export default class PDFNotes {
|
|
6
|
+
private notesArticles: NodeListOf<HTMLElement>;
|
|
7
|
+
private selectors: string[];
|
|
8
|
+
private excludedClasses = ['srl-grid', 'srl-linkable'];
|
|
9
|
+
|
|
10
|
+
constructor(config: PDFNotesConfig) {
|
|
11
|
+
const { noteClass } = config;
|
|
12
|
+
|
|
13
|
+
if (!noteClass) {
|
|
14
|
+
console.warn("PDFNotes: 'noteClass' ist erforderlich.");
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Selektoren sauber splitten
|
|
19
|
+
this.selectors = noteClass.split(',').map(s => s.trim()).filter(Boolean);
|
|
20
|
+
|
|
21
|
+
// Gesamtliste nur wenn du sie sonst brauchst
|
|
22
|
+
this.notesArticles = document.querySelectorAll(noteClass);
|
|
23
|
+
|
|
24
|
+
if (this.notesArticles.length === 0) {
|
|
25
|
+
console.warn(`PDFNotes: Keine Elemente gefunden mit Selektor '${noteClass}'.`);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
this.markLastNotePerSelector();
|
|
30
|
+
this.setFirstAndLastNoteClass();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
private setFirstAndLastNoteClass(): void {
|
|
34
|
+
this.notesArticles.forEach(container => {
|
|
35
|
+
const children = Array.from(container.children) as HTMLElement[];
|
|
36
|
+
if (children.length === 0) return;
|
|
37
|
+
|
|
38
|
+
const firstChild = children[0];
|
|
39
|
+
const lastChild = children[children.length - 1];
|
|
40
|
+
|
|
41
|
+
const getRelevantClass = (el: HTMLElement): string | null => {
|
|
42
|
+
const classes = Array.from(el.classList);
|
|
43
|
+
const relevant = classes.find(cls => !this.excludedClasses.includes(cls));
|
|
44
|
+
return relevant || null;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const firstClass = getRelevantClass(firstChild);
|
|
48
|
+
const lastClass = getRelevantClass(lastChild);
|
|
49
|
+
|
|
50
|
+
if (firstClass) container.classList.add(`${firstClass}-first`);
|
|
51
|
+
if (lastClass && lastClass !== firstClass) container.classList.add(`${lastClass}-last`);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Neu: letzte Note je Selektor markieren
|
|
56
|
+
private markLastNotePerSelector(): void {
|
|
57
|
+
if (!this.selectors || this.selectors.length === 0) return;
|
|
58
|
+
|
|
59
|
+
this.selectors.forEach(sel => {
|
|
60
|
+
const nodes = document.querySelectorAll<HTMLElement>(sel);
|
|
61
|
+
if (nodes.length === 0) return;
|
|
62
|
+
|
|
63
|
+
const last = nodes[nodes.length - 1];
|
|
64
|
+
last.classList.add('last-note');
|
|
65
|
+
|
|
66
|
+
// Falls du unterschiedliche Klassen pro Typ willst, entkommentieren:
|
|
67
|
+
// const typeKey = sel.replace(/^[.#]/, '').replace(/[^a-zA-Z0-9_]/g, '_');
|
|
68
|
+
// last.classList.add(`last-note-${typeKey}`);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface PDFSetPageNumbersConfig {
|
|
2
|
+
tocItemClass: string;
|
|
3
|
+
tocItemPageNumberClass: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export default class PDFSetPageNumbers {
|
|
7
|
+
private tocItems: NodeListOf<HTMLElement>;
|
|
8
|
+
private pageNumberClass: string;
|
|
9
|
+
|
|
10
|
+
constructor(config: PDFSetPageNumbersConfig) {
|
|
11
|
+
const { tocItemClass, tocItemPageNumberClass } = config;
|
|
12
|
+
|
|
13
|
+
this.tocItems = document.querySelectorAll(tocItemClass);
|
|
14
|
+
this.pageNumberClass = tocItemPageNumberClass;
|
|
15
|
+
|
|
16
|
+
this.tocItems.forEach(item => {
|
|
17
|
+
const link = item.getAttribute('href');
|
|
18
|
+
const num = item.querySelector<HTMLElement>(this.pageNumberClass);
|
|
19
|
+
|
|
20
|
+
if (num && link) {
|
|
21
|
+
num.setAttribute('data-page-number', link);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
package/srl/srl/pdf.scss
DELETED
|
File without changes
|