Initial commit
This commit is contained in:
commit
388079e6bb
1108 changed files with 330121 additions and 0 deletions
1
assets/csspageweaver/plugins/.gitignore
vendored
Normal file
1
assets/csspageweaver/plugins/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
# Hi! Just need to ensure folder remain tracked, even empty.
|
||||
1
assets/csspageweaver/plugins/baseline/.gitignore
vendored
Normal file
1
assets/csspageweaver/plugins/baseline/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.DS_Store
|
||||
8
assets/csspageweaver/plugins/baseline/README.md
Normal file
8
assets/csspageweaver/plugins/baseline/README.md
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: baseline
|
||||
tags: recommended, stable, boilerplate, gui
|
||||
description: A simple helper to see custom baseline grid.
|
||||
---
|
||||
|
||||
|
||||
|
||||
21
assets/csspageweaver/plugins/baseline/baseline.css
Normal file
21
assets/csspageweaver/plugins/baseline/baseline.css
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/* BASELINE -------------------------------------------*/
|
||||
|
||||
:root {
|
||||
--pagedjs-baseline: 12px;
|
||||
--pagedjs-baseline-position: 0px;
|
||||
--pagedjs-baseline-color: cyan;
|
||||
}
|
||||
|
||||
@media screen{
|
||||
.pagedjs_pagebox {
|
||||
background: linear-gradient(transparent 0%, transparent calc(var(--pagedjs-baseline) - 1px), var(--pagedjs-baseline-color) calc(var(--pagedjs-baseline) - 1px), var(--pagedjs-baseline-color) var(--pagedjs-baseline)), transparent;
|
||||
background-size: 100% var(--pagedjs-baseline);
|
||||
background-repeat: repeat-y;
|
||||
background-position-y: var(--pagedjs-baseline-position);
|
||||
|
||||
}
|
||||
|
||||
.no-baseline .pagedjs_pagebox{
|
||||
background: none;
|
||||
}
|
||||
}
|
||||
100
assets/csspageweaver/plugins/baseline/baseline.js
Normal file
100
assets/csspageweaver/plugins/baseline/baseline.js
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/**
|
||||
* @name Baseline
|
||||
* @author Julie Blanc <contact@julie-blanc.fr>
|
||||
* @see { @link https://gitlab.com/csspageweaver/plugins/baseline/ }
|
||||
*/
|
||||
|
||||
|
||||
export default function baseline() {
|
||||
let body = cssPageWeaver.ui.body
|
||||
let fileTitle = cssPageWeaver.docTitle;
|
||||
let parameters = cssPageWeaver.features.baseline.parameters || {}
|
||||
let isParametersSet = Object.keys(parameters).length > 0
|
||||
|
||||
/* BASELINE ----------------------------------------------------------------------------------------------------
|
||||
----------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
/* Set baseline onload */
|
||||
let baseline = {}
|
||||
|
||||
// set default value
|
||||
baseline.default = {
|
||||
size: 32 ,
|
||||
position: 0
|
||||
}
|
||||
|
||||
baseline.toggle = {}
|
||||
baseline.toggle.value = localStorage.getItem('baselineToggle_' + fileTitle)
|
||||
baseline.toggle.input = cssPageWeaver.ui.baseline.toggleInput
|
||||
|
||||
baseline.button = cssPageWeaver.ui.baseline.toggleLabel
|
||||
|
||||
baseline.size = {}
|
||||
baseline.size.value = parameters.size || baseline.default.size
|
||||
baseline.size.input = document.querySelector('#size-baseline')
|
||||
|
||||
baseline.position = {}
|
||||
baseline.position.value = parameters.position || baseline.default.position
|
||||
baseline.position.input = document.querySelector('#position-baseline')
|
||||
|
||||
|
||||
/* */
|
||||
/* Retrieve previous sessions */
|
||||
baseline.size.value = localStorage.getItem('baselineSize_' + fileTitle) || baseline.size.value
|
||||
baseline.position.value = localStorage.getItem('baselinePosition_' + fileTitle) || baseline.position.value
|
||||
|
||||
/* */
|
||||
/* DOM edit */
|
||||
|
||||
/* Toggle */
|
||||
if(baseline.toggle.value == "no-baseline"){
|
||||
body.classList.add('no-baseline');
|
||||
baseline.toggle.input.checked = false;
|
||||
}else if(baseline.toggle.value == "baseline"){
|
||||
body.classList.remove('no-baseline');
|
||||
baseline.toggle.input.checked = true;
|
||||
}else{
|
||||
body.classList.add('no-baseline');
|
||||
localStorage.setItem('baselineToggle_' + fileTitle, 'no-baseline'); //baselineButton.querySelector(".button-hide").classList.remove("button-not-selected");
|
||||
baseline.toggle.input.checked = false;
|
||||
}
|
||||
|
||||
/* Set baseline size and position on load */
|
||||
baseline.size.input.value = baseline.size.value
|
||||
document.documentElement.style.setProperty('--pagedjs-baseline', baseline.size.value + 'px');
|
||||
baseline.position.input.value = baseline.position.value
|
||||
document.documentElement.style.setProperty('--pagedjs-baseline-position', baseline.position.value + 'px');
|
||||
|
||||
|
||||
/* */
|
||||
/* Event listenner */
|
||||
|
||||
/* Toggle event */
|
||||
baseline.toggle.input.addEventListener("input", (e) => {
|
||||
if(e.target.checked){
|
||||
/* see baseline */
|
||||
body.classList.remove('no-baseline');
|
||||
localStorage.setItem('baselineToggle_' + fileTitle, 'baseline');
|
||||
}else{
|
||||
/* hide baseline */
|
||||
body.classList.add('no-baseline');
|
||||
localStorage.setItem('baselineToggle_' + fileTitle, 'no-baseline');
|
||||
}
|
||||
});
|
||||
|
||||
/* Change baseline size on input */
|
||||
document.querySelector("#size-baseline").addEventListener("input", (e) => {
|
||||
baseline.size.value = e.target.value
|
||||
document.documentElement.style.setProperty('--pagedjs-baseline', baseline.size.value + 'px');
|
||||
localStorage.setItem('baselineSize_' + fileTitle, baseline.size.value);
|
||||
});
|
||||
|
||||
|
||||
/* Change baseline position on input */
|
||||
document.querySelector("#position-baseline").addEventListener("input", (e) => {
|
||||
baseline.position.value = e.target.value
|
||||
document.documentElement.style.setProperty('--pagedjs-baseline-position', baseline.position.value + 'px');
|
||||
localStorage.setItem('baselinePosition_' + fileTitle, baseline.position.value);
|
||||
});
|
||||
|
||||
}
|
||||
13
assets/csspageweaver/plugins/baseline/config.json
Normal file
13
assets/csspageweaver/plugins/baseline/config.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"name": "Baseline",
|
||||
"description": "",
|
||||
"version": "1.0",
|
||||
"ui": {
|
||||
"title": "Baseline Grid",
|
||||
"description": "This Toogle a baseline on pages",
|
||||
"template": "template.html",
|
||||
"toggle": true
|
||||
},
|
||||
"script": "baseline.js",
|
||||
"stylesheet": "baseline.css"
|
||||
}
|
||||
8
assets/csspageweaver/plugins/baseline/template.html
Normal file
8
assets/csspageweaver/plugins/baseline/template.html
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<div class="panel-group-values">
|
||||
<label for="size-baseline">Size (px)</label>
|
||||
<input type="number" id="size-baseline" name="size-baseline" min="1" max="100" value="12">
|
||||
</div>
|
||||
<div class="panel-group-values">
|
||||
<label for="position-baseline" id="label-position">Position (px)</label>
|
||||
<input type="number" id="position-baseline" name="position-baseline" value="0">
|
||||
</div>
|
||||
1
assets/csspageweaver/plugins/beauDrapeau/.gitignore
vendored
Normal file
1
assets/csspageweaver/plugins/beauDrapeau/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.DS_Store
|
||||
60
assets/csspageweaver/plugins/beauDrapeau/ReadMe.md
Normal file
60
assets/csspageweaver/plugins/beauDrapeau/ReadMe.md
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
# Beau Drapeau
|
||||
|
||||
A interface to manually but easily handle line break and letterspacing of textuals elements, in the browser.
|
||||
|
||||
## How to install the plugin
|
||||
|
||||
Add this folder to `csspageweaver/plugins/`.
|
||||
|
||||
Call the plugin in `csspageweaver/manifest.json`:
|
||||
|
||||
```json
|
||||
"plugins": [
|
||||
"beauDrapeau",
|
||||
// other plugins ...
|
||||
],
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
In `manifest.json`, you can modify/add some parameters:
|
||||
|
||||
```json
|
||||
"plugins":{
|
||||
"beauDrapeau"
|
||||
},
|
||||
"pluginsParameters":{
|
||||
"beauDrapeau": {
|
||||
"data": "/csspageweaver/plugins/beauDrapeau/beauDrapeau-data.js"
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
|
||||
## How to use it
|
||||
|
||||
Edits abilities are enable with a dumb on screen ON / Off Button.
|
||||
When active, two actions can be performs :
|
||||
|
||||
+ Add forced lines breaks in text element. Just add it with `Shift` + `Enter`.
|
||||
|
||||
+ Increase or decrease element letter spacing. Just hover a element press `Shift` + Scroll Wheel
|
||||
|
||||
### Retrieve changes
|
||||
|
||||
When disable, script download an data file named `_beaudrapeau.js`. Placed on page folder, it'll allow script to retrieve current change on next session.
|
||||
|
||||
### Reset
|
||||
|
||||
Enable edition, mouse over an element and press `Shift` + `R`
|
||||
|
||||
|
||||
## Script behavior
|
||||
|
||||
+ `beauDrapeau-hook.js` will extend `PagedJs` class
|
||||
+ retrieve eventuals previous edits as a `_beaudrapeau.js` file in page folder
|
||||
+ act before PagedJs parse content.
|
||||
|
||||
## Licence
|
||||
|
||||
The MIT License (MIT)
|
||||
16
assets/csspageweaver/plugins/beauDrapeau/beauDrapeau-data.js
Normal file
16
assets/csspageweaver/plugins/beauDrapeau/beauDrapeau-data.js
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
[
|
||||
{
|
||||
"id": "c1",
|
||||
"breaking": [
|
||||
415
|
||||
],
|
||||
"letterspacing": "0.25em"
|
||||
},
|
||||
{
|
||||
"id": "c2",
|
||||
"breaking": [
|
||||
574
|
||||
],
|
||||
"letterspacing": null
|
||||
}
|
||||
]
|
||||
130
assets/csspageweaver/plugins/beauDrapeau/beauDrapeau-hook.js
Normal file
130
assets/csspageweaver/plugins/beauDrapeau/beauDrapeau-hook.js
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
/**
|
||||
* @name Beau drapeau
|
||||
* @author Benjamin G. <ecrire@bnjm.eu>
|
||||
* @see { @link https://gitlab.com/csspageweaver/plugins/beauDrapeau }
|
||||
*/
|
||||
|
||||
import { Handler } from 'assets/csspageweaver/lib/paged.esm.js';
|
||||
import { beauDrapeau } from '/csspageweaver/plugins/beauDrapeau/beauDrapeau.js';
|
||||
|
||||
/* */
|
||||
export class PrepareBeauDrapeau extends Handler {
|
||||
|
||||
constructor(chunker, polisher, caller) {
|
||||
super(chunker, polisher, caller);
|
||||
this.parameters = cssPageWeaver.features.beauDrapeau || {}
|
||||
this.parameters.data = cssPageWeaver.features.beauDrapeau?.data || cssPageWeaver.features.beauDrapeau.directory + 'beauDrapeau-data.js'
|
||||
}
|
||||
|
||||
addClassToBreaking(content){
|
||||
let brs = content.querySelectorAll("br")
|
||||
brs.forEach(br => {
|
||||
br.classList.add("canon")
|
||||
})
|
||||
}
|
||||
|
||||
getPageAssetsLocation(){
|
||||
const pathname = window.location.pathname
|
||||
const index = pathname.lastIndexOf('/')
|
||||
const filename = pathname.substring(index + 1)
|
||||
const dotIndex = filename.lastIndexOf('.')
|
||||
const pagename = filename.substring(0, dotIndex)
|
||||
return pagename
|
||||
}
|
||||
|
||||
assignEditableCapabilities(element) {
|
||||
element.setAttribute("contentEditable", false)
|
||||
}
|
||||
|
||||
assignEditableIds(content) {
|
||||
const sections = content.querySelectorAll('section');
|
||||
let sectionCounter = 0;
|
||||
let idCounter = 0;
|
||||
let idPrefix = 'a';
|
||||
|
||||
sections.forEach((section) => {
|
||||
idCounter = 0;
|
||||
idPrefix = String.fromCharCode(sectionCounter + 97);
|
||||
|
||||
const selectors = '*:not(hgroup) p, *:not(hgroup) li, *:not(hgroup) h1, *:not(hgroup) h2, *:not(hgroup) h3, *:not(hgroup) h4, *:not(hgroup) h5, *:not(hgroup) h6'
|
||||
const targetElements = section.querySelectorAll(selectors);
|
||||
|
||||
targetElements.forEach((element) => {
|
||||
idCounter++;
|
||||
const editableId = `${idPrefix}${idCounter}`;
|
||||
element.setAttribute('editable-id', editableId);
|
||||
this.assignEditableCapabilities(element)
|
||||
});
|
||||
|
||||
sectionCounter++;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async applyBackUp(content){
|
||||
console.log("retrieve previous beauDrapeau", beauDrapeau.data )
|
||||
|
||||
// Loop through each object in the beauDrapeauData array
|
||||
beauDrapeau.data.forEach((data) => {
|
||||
|
||||
// Get the corresponding DOM element by ID
|
||||
const element = content.querySelector(`[editable-id="${data.id}"`);
|
||||
if (element) {
|
||||
|
||||
// If the element exists
|
||||
// and has a non-null breaking array, add <br> elements
|
||||
if (data.breaking && data.breaking.length > 0) {
|
||||
let textContent = element.textContent;
|
||||
data.breaking.forEach((index) => {
|
||||
const firstPart = textContent.slice(0, index);
|
||||
const secondPart = textContent.slice(index);
|
||||
element.innerHTML = `${firstPart}<br>${secondPart}`;
|
||||
textContent = element.textContent; // Update the textContent variable to reflect the new <br> element
|
||||
});
|
||||
}
|
||||
|
||||
// If the element exists
|
||||
// and has a non-null letterspacing value, add inline styles
|
||||
if (data.letterspacing !== null) {
|
||||
element.style.letterSpacing = `${data.letterspacing}`;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// new function to load _beauDrapeau.json
|
||||
async loadBackUp() {
|
||||
try {
|
||||
|
||||
let data_location = this.parameters.data ? this.parameters.data : `./${this.getPageAssetsLocation()}/beauDrapeau-data.js`
|
||||
const response = await fetch(data_location);
|
||||
//const response = await fetch(`./${cssPageWeaver.directory.plugins}/beauDrapeau/beauDrapeau-data.js`);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
return data
|
||||
} catch (error) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async beforeParsed(content) {
|
||||
// Canonise existing Breaking Point
|
||||
this.addClassToBreaking(content)
|
||||
|
||||
// Assign ID to all editable element
|
||||
this.assignEditableIds(content)
|
||||
|
||||
// Load previous data
|
||||
beauDrapeau.data = await this.loadBackUp();
|
||||
|
||||
// Break if no data
|
||||
if(!beauDrapeau.data){ return }
|
||||
|
||||
await this.applyBackUp(content)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* @name Beau drapeau
|
||||
* @author Benjamin G. <ecrire@bnjm.eu>
|
||||
* @see { @link https://gitlab.com/csspageweaver/plugins/beauDrapeau }
|
||||
*/
|
||||
|
||||
import { beauDrapeau } from '/csspageweaver/plugins/beauDrapeau/beauDrapeau.js';
|
||||
|
||||
export default function () {
|
||||
|
||||
// Declare selector
|
||||
let toggleInput = cssPageWeaver.ui.beauDrapeau.toggleInput
|
||||
|
||||
// Add event
|
||||
toggleInput.addEventListener('input', () => {
|
||||
|
||||
// Change toggle button style and content
|
||||
//beauDrapeau().ui().toggle().button('edit-button')
|
||||
|
||||
// Run function
|
||||
beauDrapeau().edit()
|
||||
})
|
||||
}
|
||||
335
assets/csspageweaver/plugins/beauDrapeau/beauDrapeau.js
Normal file
335
assets/csspageweaver/plugins/beauDrapeau/beauDrapeau.js
Normal file
|
|
@ -0,0 +1,335 @@
|
|||
/**
|
||||
* @file Manage text alignement
|
||||
* A interface to manually but easily handle line break and letterspacing of textuals elements, in the browser.
|
||||
* @author Benjamin G. <ecrire@bnjm.eu>
|
||||
* @see https://gitlab.com/BenjmnG/beauDrapeau
|
||||
*/
|
||||
|
||||
export const beauDrapeau = () => ({
|
||||
|
||||
isEditMode: false,
|
||||
data: new Array(),
|
||||
|
||||
ui: () => ({
|
||||
|
||||
toggle: () => ({
|
||||
|
||||
button: (id) => {
|
||||
var button = document.getElementById(id);
|
||||
|
||||
if(!button){
|
||||
return
|
||||
}
|
||||
// Toggle button value
|
||||
if (beauDrapeau.isEditMode) {
|
||||
button.classList.add('active')
|
||||
button.value = 'Edit On';
|
||||
} else {
|
||||
button.classList.remove('active')
|
||||
button.value = 'Edit Off';
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggles the `contentEditable` attribute for all elements with the `contentEditable` attribute.
|
||||
*/
|
||||
contentEditable: () => {
|
||||
const editableElements = document.querySelectorAll('[contentEditable]');
|
||||
editableElements.forEach((element) => {
|
||||
element.contentEditable = beauDrapeau.isEditMode;
|
||||
});
|
||||
},
|
||||
}),
|
||||
|
||||
download: (dataBlob) => {
|
||||
// Check if the download link already exists
|
||||
const existingLink = document.getElementById('edit-download');
|
||||
|
||||
if (existingLink) {
|
||||
// If the link exists, update the URL and text content
|
||||
existingLink.href = URL.createObjectURL(dataBlob);
|
||||
} else {
|
||||
// If the link doesn't exist, create a new one and append it to the document body
|
||||
let link = document.createElement('a');
|
||||
link.id = 'edit-download';
|
||||
link.classList = 'button';
|
||||
link.href = URL.createObjectURL(dataBlob);
|
||||
link.download = 'beauDrapeau-data.js';
|
||||
link.innerHTML = '<?xml version="1.0" encoding="UTF-8"?> <svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 0 40 40"> <defs> <style> .a8r7{ fill: none; stroke: currentColor; stroke-miterlimit: 10; stroke-width: 3px; stroke-linecap: round;} </style> </defs> <line class="a8r7" x1="15.49" x2="15.49" y2="27.93"/> <line class="a8r7" y1="34.77" x2="31.31" y2="34.77"/> <polyline class="a8r7" points="22.9 21.02 15.65 28.26 8.41 21.02"/> </svg>'
|
||||
|
||||
let div = document.createElement('div');
|
||||
div.classList = "buttons-group"
|
||||
|
||||
div.append(link)
|
||||
|
||||
console.log(div)
|
||||
|
||||
// Add styles
|
||||
//link = beauDrapeau().ui().style(link, 1)
|
||||
|
||||
document.getElementById('beauDrapeau-form').insertAdjacentElement('beforeEnd', div);
|
||||
}
|
||||
},
|
||||
|
||||
event: () => ({
|
||||
letterSpacing: () => {
|
||||
let letterSpacing = 0;
|
||||
|
||||
const handleScroll = (event) => {
|
||||
if (event.shiftKey && event.target.isContentEditable) {
|
||||
event.preventDefault();
|
||||
const step = 0.01;
|
||||
const newLetterSpacing = event.deltaY > 0 ? letterSpacing - step : letterSpacing + step;
|
||||
event.target.style.letterSpacing = `${newLetterSpacing}em`;
|
||||
letterSpacing = newLetterSpacing;
|
||||
}
|
||||
};
|
||||
|
||||
const handleMouseOver = (event) => {
|
||||
if (event.target.isContentEditable) {
|
||||
event.target.addEventListener('wheel', handleScroll);
|
||||
event.target.addEventListener('mouseleave', handleMouseOut);
|
||||
}
|
||||
};
|
||||
|
||||
const handleMouseOut = (event) => {
|
||||
if (event.target.isContentEditable) {
|
||||
event.target.removeEventListener('wheel', handleScroll);
|
||||
event.target.removeEventListener('mouseleave', handleMouseOut);
|
||||
}
|
||||
};
|
||||
|
||||
if (beauDrapeau.isEditMode) {
|
||||
document.addEventListener('mouseover', handleMouseOver);
|
||||
document.addEventListener('mouseout', handleMouseOut);
|
||||
} else {
|
||||
document.removeEventListener('mouseover', handleMouseOver);
|
||||
document.removeEventListener('mouseout', handleMouseOut);
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
reset: () => {
|
||||
|
||||
const handleKeyDown = (event) => {
|
||||
if (event.shiftKey && event.key === 'R' && event.target.isContentEditable) {
|
||||
event.preventDefault();
|
||||
const id = event.target.getAttribute('editable-id');
|
||||
beauDrapeau().clear(id);
|
||||
}
|
||||
};
|
||||
if (beauDrapeau.isEditMode) {
|
||||
document.addEventListener('keydown', handleKeyDown);
|
||||
} else {
|
||||
document.removeEventListener('keydown', handleKeyDown);
|
||||
}
|
||||
}
|
||||
|
||||
}),
|
||||
|
||||
|
||||
style(el, pos){
|
||||
// Add styles
|
||||
el.style.position = 'fixed';
|
||||
el.style.top = '2rem';
|
||||
el.style.padding = '.75em .5em';
|
||||
el.style.right = `${5.5 * pos + 1}rem`;
|
||||
el.style.backgroundColor = '#f3f3f3';
|
||||
el.style.borderRadius = '3px';
|
||||
el.style.border = '1px solid currentColor';
|
||||
el.style.zIndex = '99';
|
||||
el.style.color = '#0064ff';
|
||||
el.style.textAlign = 'center';
|
||||
el.style.fontFamily = 'sans-serif';
|
||||
el.style.backgroundColor = '#e1e1e1';
|
||||
el.style.cursor = 'pointer';
|
||||
el.classList = 'no-print';
|
||||
|
||||
return el
|
||||
}
|
||||
|
||||
}),
|
||||
|
||||
data: () => ({
|
||||
|
||||
/**
|
||||
* Resets the `breaking` property of the given data object to an empty array.
|
||||
* @param {object} data - The data object to update.
|
||||
*/
|
||||
clearBreaking: (data) => {
|
||||
data.breaking = [];
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if element had breaking point element
|
||||
* @param {Element} editableElement - The editable element to inspect.
|
||||
*/
|
||||
checkBreaking: (editableElement) => {
|
||||
let brs = editableElement.querySelectorAll('br:not(.canon)');
|
||||
return brs.length > 0 ? brs : null
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if element had inline style
|
||||
* @param {Element} editableElement - The editable element to inspect.
|
||||
*/
|
||||
checkInlineStyle: (editableElement) => {
|
||||
const style = editableElement.getAttribute('style');
|
||||
let ls
|
||||
if(style){
|
||||
ls = style.match(/letter-spacing:\s*([^;]+);/);
|
||||
}
|
||||
return ls ? ls[1] : null
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Updates the `breaking` property of the given data object with the indices of the `br` elements in the given editable element.
|
||||
* @param {Element} editableElement - The editable element to inspect.
|
||||
* @param {object} data - The data object to update.
|
||||
*/
|
||||
updateBreaking: (editableElement, breaking, data) => {
|
||||
if(!breaking){return}
|
||||
breaking.forEach((br) => {
|
||||
const textContent = editableElement.innerHTML
|
||||
const brIndex = textContent.indexOf(br.outerHTML);
|
||||
data.breaking.push(brIndex);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the `letterspacing` property of the given data object with the value of the `letter-spacing` style for the given editable element.
|
||||
* @param {Element} editableElement - The editable element to inspect.
|
||||
* @param {object} data - The data object to update.
|
||||
*/
|
||||
updateInlineStyle: (letterSpacing, data) => {
|
||||
if(!letterSpacing) { return }
|
||||
data.letterspacing = letterSpacing;
|
||||
},
|
||||
|
||||
sort: () => {
|
||||
beauDrapeau.data.sort((a, b) => a.id.localeCompare(b.id));
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves the data object for the given editable ID, or creates a new one if it doesn't exist.
|
||||
* @param {string} editableId - The ID of the editable element.
|
||||
* @return {object} The data object for the given editable ID, with `id`, `breaking`, and `letterspacing` properties.
|
||||
*/
|
||||
getOrCreate: (editableId) => {
|
||||
const data_template = { id: editableId, breaking: [], letterspacing: null };
|
||||
|
||||
let data = beauDrapeau.data.find((item) => item.id === editableId);
|
||||
|
||||
if (!data) {
|
||||
data = data_template;
|
||||
beauDrapeau.data.push(data);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
}),
|
||||
|
||||
/**
|
||||
* Saves the `beauDrapeau.data` object to a file called `_beauDrapeau.js`.
|
||||
*/
|
||||
save: () => {
|
||||
// Convert the `beauDrapeau.data` object to a string
|
||||
const dataString = JSON.stringify(beauDrapeau.data, null, 2);
|
||||
|
||||
// Create a new Blob object with the data string
|
||||
const dataBlob = new Blob([dataString], { type: 'application/json' });
|
||||
|
||||
// Pass to download button
|
||||
beauDrapeau().ui().download(dataBlob)
|
||||
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Toggles the edit mode on or off, updates the UI, and saves the data if edit mode is turned off.
|
||||
*/
|
||||
edit: () => {
|
||||
beauDrapeau.isEditMode = !beauDrapeau.isEditMode;
|
||||
|
||||
// update UI
|
||||
beauDrapeau().ui().toggle().button()
|
||||
|
||||
// Toggle the ContentEditable attribute for all elements
|
||||
beauDrapeau().ui().toggle().contentEditable()
|
||||
|
||||
// Initialize event listeners
|
||||
beauDrapeau().ui().event().letterSpacing();
|
||||
beauDrapeau().ui().event().reset();
|
||||
|
||||
// If Edit mode is off, perform the cleanup and save the data
|
||||
if (!beauDrapeau.isEditMode) {
|
||||
|
||||
const editableElements = document.querySelectorAll('[contentEditable]');
|
||||
editableElements.forEach((editableElement) => {
|
||||
|
||||
const editableId = editableElement.getAttribute('editable-id')
|
||||
const letterspacing = beauDrapeau().data().checkInlineStyle(editableElement)
|
||||
const breaking = beauDrapeau().data().checkBreaking(editableElement)
|
||||
|
||||
if(letterspacing || breaking){
|
||||
|
||||
let data = beauDrapeau().data().getOrCreate(editableId);
|
||||
|
||||
// Reset breaking points
|
||||
beauDrapeau().data().clearBreaking(data);
|
||||
|
||||
// Handle breaking elements
|
||||
beauDrapeau().data().updateBreaking(editableElement, breaking, data);
|
||||
|
||||
// Handle inline styles
|
||||
beauDrapeau().data().updateInlineStyle(letterspacing, data);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Sort
|
||||
if(beauDrapeau.data.length > 0){
|
||||
beauDrapeau().data().sort(beauDrapeau.data);
|
||||
}
|
||||
|
||||
// Save
|
||||
console.log(beauDrapeau.data)
|
||||
beauDrapeau().save()
|
||||
}
|
||||
},
|
||||
|
||||
clear: (ids) => {
|
||||
// Convert the `ids` argument to an array if it's not already an array
|
||||
if (!Array.isArray(ids)) {
|
||||
ids = [ids];
|
||||
}
|
||||
|
||||
// Loop through each ID in the `ids` array
|
||||
ids.forEach((id) => {
|
||||
// Get the corresponding DOM element by ID
|
||||
console.log("Clear element ", id)
|
||||
const element = document.querySelector("[editable-id='"+id+"'");
|
||||
|
||||
if (element) {
|
||||
|
||||
// Remove all <br> elements with class "canon"
|
||||
const brElements = element.querySelectorAll('br:not(.canon)');
|
||||
brElements.forEach((br) => {
|
||||
br.remove();
|
||||
});
|
||||
|
||||
// Remove inline letter-spacing styles
|
||||
element.style.letterSpacing = '';
|
||||
|
||||
// Find the corresponding data object in `beauDrapeau.data`
|
||||
const dataIndex = beauDrapeau.data.findIndex((data) => data.id === id);
|
||||
if (dataIndex !== -1) {
|
||||
beauDrapeau.data = beauDrapeau.data.filter((data) => data.id !== id);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
beauDrapeau().save()
|
||||
},
|
||||
})
|
||||
15
assets/csspageweaver/plugins/beauDrapeau/config.json
Normal file
15
assets/csspageweaver/plugins/beauDrapeau/config.json
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "Beau Drapeau",
|
||||
"description": "A interface to manually but easily handle line break and letterspacing of textuals elements, in the browser.",
|
||||
"author": "Benjamin G.",
|
||||
"licence": "MIT",
|
||||
"version": "1.0",
|
||||
"repository": "https://gitlab.com/BenjmnG/beauDrapeau/",
|
||||
"ui": {
|
||||
"title": "Beau Drapeau",
|
||||
"description": "Edit content to force line breaks (click + shift + enter) or change letter spacing (shift + scroll)",
|
||||
"toggle": true
|
||||
},
|
||||
"hook": "beauDrapeau-hook.js",
|
||||
"script": "beauDrapeau-script.js"
|
||||
}
|
||||
8
assets/csspageweaver/plugins/createIndex/config.json
Normal file
8
assets/csspageweaver/plugins/createIndex/config.json
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"name": "Create Index",
|
||||
"description": "Create index from key words",
|
||||
"licence": "MIT",
|
||||
"author": ["Julie Blanc"],
|
||||
"version": "2.0",
|
||||
"hook": "createIndex.js"
|
||||
}
|
||||
140
assets/csspageweaver/plugins/createIndex/createIndex.js
Normal file
140
assets/csspageweaver/plugins/createIndex/createIndex.js
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
import { Handler } from 'assets/csspageweaver/lib/paged.esm.js';
|
||||
|
||||
export default class createIndex extends Handler {
|
||||
constructor(chunker, polisher, caller) {
|
||||
super(chunker, polisher, caller);
|
||||
}
|
||||
|
||||
beforeParsed(content) {
|
||||
newIndex({
|
||||
content: content,
|
||||
spanClassIndex: '.book-index',
|
||||
indexElement: '#book-index',
|
||||
alphabet: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function newIndex(config){
|
||||
const content = config.content;
|
||||
let indexElements = content.querySelectorAll(config.spanClassIndex);
|
||||
let arrayIndex = [];
|
||||
let num = 0;
|
||||
|
||||
for(let i = 0; i < indexElements.length; ++i){
|
||||
let indexElement = indexElements[i];
|
||||
|
||||
// create array with all data-book-index
|
||||
let indexKey = indexElement.dataset.bookIndex;
|
||||
let indexKeyFirst = indexKey.slice(0, 1);
|
||||
let newIndexKey;
|
||||
if(indexKeyFirst == "<"){
|
||||
if(indexKey.slice(0, 3) == "<i>"){
|
||||
newIndexKey = indexKey.replace("<i>", "") + "-iTemp";
|
||||
}else if(indexKey.slice(0, 4) == "<em>"){
|
||||
newIndexKey = indexKey.replace("<em>", "") + "-emTemp";
|
||||
}
|
||||
}else{
|
||||
newIndexKey = indexKey;
|
||||
}
|
||||
|
||||
arrayIndex.push(newIndexKey);
|
||||
|
||||
// create id for span whithout
|
||||
num++;
|
||||
if(indexElement.id == ''){ indexElement.id = 'book-index-' + num; }
|
||||
}
|
||||
|
||||
|
||||
// filter array to remove dublicate and sort by alphabetical order
|
||||
let newArrayIndex = arrayIndex.filter(onlyUnique).sort(function(a,b) {
|
||||
a = a.toLowerCase();
|
||||
b = b.toLowerCase();
|
||||
if( a == b) return 0;
|
||||
return a < b ? -1 : 1;
|
||||
});
|
||||
|
||||
// create <ul> element for the index
|
||||
let indexElementDiv = content.querySelector(config.indexElement);
|
||||
|
||||
if(indexElementDiv != null){
|
||||
let indexUl = document.createElement("ul");
|
||||
indexUl.id = "list-index-generated";
|
||||
indexElementDiv.appendChild(indexUl);
|
||||
|
||||
// create <li> element for the index
|
||||
for(var a = 0; a < newArrayIndex.length; a++){
|
||||
|
||||
// create alphabet
|
||||
if(config.alphabet){
|
||||
let z = a - 1;
|
||||
let firstLetter = newArrayIndex[a].toUpperCase().slice(0, 1);
|
||||
if(a == 0){
|
||||
let alphabetLiFirst = document.createElement("li");
|
||||
alphabetLiFirst.classList.add("list-alphabet-element");
|
||||
alphabetLiFirst.id = "alphabet-element-" + firstLetter;
|
||||
alphabetLiFirst.innerHTML = firstLetter;
|
||||
indexUl.appendChild(alphabetLiFirst);
|
||||
}
|
||||
if(z >= 0){
|
||||
let firstLetterPrevious = newArrayIndex[z].toUpperCase().slice(0, 1);
|
||||
if(firstLetter != firstLetterPrevious){
|
||||
let alphabetLi = document.createElement("li");
|
||||
alphabetLi.classList.add("list-alphabet-element");
|
||||
alphabetLi.id = "alphabet-element-" + firstLetter;
|
||||
alphabetLi.innerHTML = firstLetter;
|
||||
indexUl.appendChild(alphabetLi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create <li> element for the index
|
||||
let indexNewLi = document.createElement("li");
|
||||
indexNewLi.classList.add("list-index-element");
|
||||
|
||||
let dataIndex;
|
||||
if(newArrayIndex[a].substr(newArrayIndex[a].length - 6) == "-iTemp"){
|
||||
dataIndex = "<i>" + newArrayIndex[a].replace("-iTemp", "");
|
||||
}else if(newArrayIndex[a].substr(newArrayIndex[a].length - 7) == "-emTemp"){
|
||||
dataIndex = "<em>" + newArrayIndex[a].replace("-emTemp", "");
|
||||
}else{
|
||||
dataIndex = newArrayIndex[a];
|
||||
}
|
||||
|
||||
indexNewLi.dataset.listIndex = dataIndex;
|
||||
indexUl.appendChild(indexNewLi);
|
||||
}
|
||||
|
||||
let indexLi = content.getElementById('list-index-generated').getElementsByClassName('list-index-element');
|
||||
|
||||
for(var n = 0; n < indexLi.length; n++){
|
||||
|
||||
// find data and add HTML of the list
|
||||
let dataIndex = indexLi[n].dataset.listIndex;
|
||||
let spanIndex = content.querySelectorAll("[data-book-index='" + dataIndex + "']");
|
||||
indexLi[n].innerHTML = '<span class="index-value">' + dataIndex + '</span><span class="links-pages"></span>';
|
||||
|
||||
// add span for link page
|
||||
spanIndex.forEach(function(elem) {
|
||||
let spanIndexId = elem.id;
|
||||
let spanPage = document.createElement("span");
|
||||
spanPage.classList.add("link-page");
|
||||
spanPage.innerHTML = '<a href="#' + spanIndexId + '"></a>';
|
||||
indexLi[n].getElementsByClassName('links-pages')[0].appendChild(spanPage);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// function for filter array to remove dublicate
|
||||
function onlyUnique(value, index, self) {
|
||||
return self.indexOf(value) === index;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
1
assets/csspageweaver/plugins/footnotesFix/.gitignore
vendored
Normal file
1
assets/csspageweaver/plugins/footnotesFix/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.DS_Store
|
||||
95
assets/csspageweaver/plugins/footnotesFix/README.md
Normal file
95
assets/csspageweaver/plugins/footnotesFix/README.md
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
# Plugin to fix footnotes reset issue
|
||||
|
||||
This plugin fix the issue of footnote reset.
|
||||
|
||||
You can use the current method to declare footnotes:
|
||||
|
||||
```CSS
|
||||
@page {
|
||||
@footnote {
|
||||
float: bottom;
|
||||
}
|
||||
}
|
||||
|
||||
.pagedjs_footnote {
|
||||
float: footnote;
|
||||
}
|
||||
```
|
||||
|
||||
This style is also added to the default stylesheet `footnotes.css` of this plugin. You can delete it if you have already declared footnotes in your own stylesheet (don't forget to remove it from the `config.json` as well).
|
||||
|
||||
|
||||
## How to use the plugin
|
||||
|
||||
Add this folder to `csspageweaver/plugins/`.
|
||||
|
||||
Call the plugin in `csspageweaver/manifest.json`:
|
||||
|
||||
```json
|
||||
"plugins": [
|
||||
"footnotesFix",
|
||||
// other plugins ...
|
||||
],
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
In `manifest.json`, you can modify/add some parameters:
|
||||
|
||||
```json
|
||||
"plugins":{
|
||||
"footnotesFix"
|
||||
},
|
||||
"pluginsParameters":{
|
||||
"footnotesFix": {
|
||||
"selector": ".footnote",
|
||||
"reset": ".chapter"
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
All the parameters are optional.
|
||||
|
||||
- `selector` → CSS selector for the note element (must be inline in the HTML), by default is `.footnote`
|
||||
- `reset` → CSS selector where you want reset note counter. If you want to reset on the page: `page`
|
||||
|
||||
|
||||
## Notes in HTML
|
||||
|
||||
In your HTML, the note must be a `<span>` inserted in the text, like this:
|
||||
|
||||
```HTML
|
||||
Donec tincidunt, odio vel vestibulum sollicitudin, nibh dolor tempor sapien, ac laoreet
|
||||
sem felis ut purus. <span class=".footnote">Vestibulum neque ex, ullamcorper sit
|
||||
amet diam sed, pharetra laoreet sem.</span> Morbi cursus bibendum consectetur. Nullam vel
|
||||
lacus congue nibh pulvinar maximus sit amet eu risus. Curabitur semper odio mauris, nec
|
||||
imperdiet velit pharetra non. Aenean accumsan nulla ac ex iaculis interdum.
|
||||
```
|
||||
|
||||
You can use the [inline_notes` plugin](https://gitlab.com/csspageweaver/plugins/inline_notes) to create these span elements from listed notes, which are more common in conversion tools like Pandoc.
|
||||
|
||||
The inline_notes plugin should be called before the footnotes plugin in the `manifest.json`:
|
||||
|
||||
|
||||
```json
|
||||
"plugins": [
|
||||
"inline_notes",
|
||||
"footnotes_fix",
|
||||
// other plugins ...
|
||||
],
|
||||
```
|
||||
|
||||
## Styling call & footer
|
||||
|
||||
It's possible to change the styles of call notes and marker notes directly in your stylesheet like in the following code:
|
||||
|
||||
```CSS
|
||||
::footnote-call{
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
::footnote-marker{
|
||||
font-weight: bold;
|
||||
}
|
||||
```
|
||||
|
||||
9
assets/csspageweaver/plugins/footnotesFix/config.json
Normal file
9
assets/csspageweaver/plugins/footnotesFix/config.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"name": "Footnotes",
|
||||
"description": "Fix footnote reset",
|
||||
"author": ["Julie Blanc"],
|
||||
"licence": "MIT",
|
||||
"version": "1.0",
|
||||
"hook": "footnotes.js",
|
||||
"stylesheet": "footnotes.css"
|
||||
}
|
||||
9
assets/csspageweaver/plugins/footnotesFix/footnotes.css
Normal file
9
assets/csspageweaver/plugins/footnotesFix/footnotes.css
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
@page {
|
||||
@footnote {
|
||||
float: bottom;
|
||||
}
|
||||
}
|
||||
|
||||
.pagedjs_footnote {
|
||||
float: footnote;
|
||||
}
|
||||
84
assets/csspageweaver/plugins/footnotesFix/footnotes.js
Normal file
84
assets/csspageweaver/plugins/footnotesFix/footnotes.js
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
* @name Footnotes
|
||||
* @file Reset the way footnote are counted
|
||||
* @author Julie Blanc <contact@julie-blanc.fr>
|
||||
* @see { @link https://gitlab.com/csspageweaver/plugins/footnotesFix/ }
|
||||
*/
|
||||
|
||||
import { Handler } from 'assets/csspageweaver/lib/paged.esm.js';
|
||||
|
||||
export default class footnotes extends Handler {
|
||||
|
||||
constructor(chunker, polisher, caller) {
|
||||
super(chunker, polisher, caller);
|
||||
this.parameters = cssPageWeaver.features.footnotesFix.parameters;
|
||||
this.reset = this.parameters?.reset ;
|
||||
this.counter = 0;
|
||||
this.selector = this.parameters?.selector || ".footnote";
|
||||
}
|
||||
|
||||
beforeParsed(content) {
|
||||
|
||||
|
||||
let notes = content.querySelectorAll(this.selector);
|
||||
notes.forEach(function (note, index) {
|
||||
note.classList.add("pagedjs_footnote");
|
||||
});
|
||||
|
||||
|
||||
|
||||
if(this.reset){
|
||||
let elems = content.querySelectorAll(this.reset);
|
||||
elems.forEach(function (elem, index) {
|
||||
var span = document.createElement('span');
|
||||
span.classList.add("reset-fix-footnote");
|
||||
span.style.position = "absolute";
|
||||
elem.insertBefore(span, elem.firstChild);
|
||||
});
|
||||
}else{
|
||||
console.log("[footnotesFix] no reset")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
afterPageLayout(pageElement, page, breakToken){
|
||||
|
||||
if(this.reset){
|
||||
|
||||
// reset on pages
|
||||
if(this.reset === "page"){
|
||||
this.counter = 0;
|
||||
}
|
||||
|
||||
// reset on specific element
|
||||
let newchapter = pageElement.querySelector('.reset-fix-footnote');
|
||||
if(newchapter){
|
||||
this.counter = 0;
|
||||
}
|
||||
|
||||
let footnotes = pageElement.querySelectorAll(".pagedjs_footnote_content [data-note]");
|
||||
|
||||
let callnotes = pageElement.querySelectorAll('a.pagedjs_footnote');
|
||||
callnotes.forEach((call, index) => {
|
||||
|
||||
this.counter = this.counter + 1; // increment
|
||||
let num = this.counter - 1;
|
||||
|
||||
// update data-counter for call
|
||||
call.setAttribute('data-counter-footnote-increment', num);
|
||||
call.style.counterReset = "footnote " + num;
|
||||
|
||||
// update data-counter for marker
|
||||
let footnote = footnotes[index];
|
||||
let dataCounter = num + 1;
|
||||
footnote.setAttribute('data-counter-note', dataCounter);
|
||||
footnote.style.counterReset = "footnote-marker " + num;
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
1
assets/csspageweaver/plugins/fullPage/.gitignore
vendored
Normal file
1
assets/csspageweaver/plugins/fullPage/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.DS_Store
|
||||
126
assets/csspageweaver/plugins/fullPage/README.md
Executable file
126
assets/csspageweaver/plugins/fullPage/README.md
Executable file
|
|
@ -0,0 +1,126 @@
|
|||
---
|
||||
name: fullPage
|
||||
tags: recommended, stable
|
||||
description: Create full page elements and full spread elements in the flow of your book.
|
||||
|
||||
---
|
||||
|
||||
|
||||
# Full page elements (paged.js)
|
||||
|
||||
This script help you to create full page elements and full spread elements in the flow of your book.
|
||||
|
||||
You need to use [csstree.js](https://github.com/csstree/csstree) in order to transform custom properties.
|
||||
If you use CSS Page Maker is inclued by default
|
||||
|
||||
|
||||
## How to install
|
||||
|
||||
**With CSS Page Marker**
|
||||
|
||||
Make sure the csstree library is included in the `<head>` of your HTML:
|
||||
|
||||
|
||||
```html
|
||||
<script src="/csspageweaver/lib/csstree.min.js"></script>
|
||||
```
|
||||
|
||||
|
||||
Register the `fullPage` plugin in your `manifest.json`:
|
||||
|
||||
```json
|
||||
[
|
||||
"fullPage",
|
||||
// other plugins
|
||||
|
||||
]
|
||||
|
||||
```
|
||||
|
||||
|
||||
**Without CSS Page Maker**
|
||||
|
||||
Include both csstree and the fullPage script in your HTML `<head>`:
|
||||
|
||||
```html
|
||||
<script src="js/csstree.min.js"></script>
|
||||
<script src="path/to/fullPage/fullPage.js"></script>
|
||||
```
|
||||
|
||||
|
||||
|
||||
## How to use it
|
||||
|
||||
In the CSS, on the element(s) you want in full page add the following custom property(works with id and classes):
|
||||
|
||||
```css
|
||||
elem{
|
||||
--pagedjs-full-page: page
|
||||
}
|
||||
```
|
||||
|
||||
You have multiple keywords for the custom property:
|
||||
- `--pagedjs-full-page: page` → The element will be remove from flow and put in the next page.
|
||||
- `--pagedjs-full-page: left` → The element will be remove from flow and put in the next left page.
|
||||
- `--pagedjs-full-page: right` → The element will be remove from flow and put in the next right page.
|
||||
- `--pagedjs-full-page: spread` → The element will be remove from flow and put in the next spread.
|
||||
- `--pagedjs-full-page: <number>` → The element will be remove from flow and put in the page you specify (with `--pagedjs-full-page: 4`, the element is put on page number 4).
|
||||
|
||||
Note that this script works on any elements, even if the element contains several child elements.
|
||||
|
||||
|
||||
### Images in full page
|
||||
|
||||
If you want an image in full page, we advise you to use the usual `objet-fit` properties.
|
||||
|
||||
```css
|
||||
#figure{
|
||||
--pagedjs-full-page: page;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0px;
|
||||
}
|
||||
img {
|
||||
object-fit: cover;
|
||||
object-position: 0px 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
```
|
||||
|
||||
- To change the size of you image, use `width` and `height`.
|
||||
- To change the position of your image, use `object-position`.
|
||||
- In the case of the `spread` option, all the spread will be considered, i.e. `width: 100%` cover all the spread.
|
||||
|
||||
|
||||
### Spread and central fold
|
||||
|
||||
Sometimes, when a book is binding, the elements that cover the spread need to be offset from the central fold. A custom value can be added to the page to take it into account.
|
||||
|
||||
```css
|
||||
@page {
|
||||
--pagedjs-fold: 10mm;
|
||||
}
|
||||
```
|
||||
|
||||
### Bleeds of full page and full spread elements
|
||||
|
||||
In order to avoid that your elements moves when you change the bleeds and the crop marks of your document, the bleeds of full page elements was set up to `6mm`. This is due to the way Paged.js modifies the DOM (full page elements are contained in the page sheet and depend on the dimensions of this page sheet).
|
||||
If you want to change the dimensions of these specific bleeds, you just have to change the value of the `bleedFull` variable in the first line of the `full-page.js` file
|
||||
|
||||
|
||||
### Examples
|
||||
|
||||
You can find examples of use in `css/full-page.css`.
|
||||
|
||||

|
||||
|
||||
|
||||
## Credits
|
||||
|
||||
- [pagedjs.org](https://www.pagedjs.org/)
|
||||
- [csstree.js](https://github.com/csstree/csstree)
|
||||
|
||||
MIT licence, Julie Blanc, 2021
|
||||
|
||||
|
||||
9
assets/csspageweaver/plugins/fullPage/config.json
Normal file
9
assets/csspageweaver/plugins/fullPage/config.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"name": "Full page",
|
||||
"description": "Create full page elements and full spread elements in the flow of your book",
|
||||
"licence": "MIT",
|
||||
"author": ["Julie Blanc"],
|
||||
"version": "2.0",
|
||||
"hook": "fullPage.js",
|
||||
"stylesheet": "fullPage.css"
|
||||
}
|
||||
49
assets/csspageweaver/plugins/fullPage/fullPage.css
Normal file
49
assets/csspageweaver/plugins/fullPage/fullPage.css
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
.pagedjs_page_fullLeft .pagedjs_full-spread_container{
|
||||
margin: 0;
|
||||
width: calc(var(--pagedjs-pagebox-width) + var(--bleed-images));
|
||||
height: calc(var(--pagedjs-pagebox-height) + var(--bleed-images)*2)!important;
|
||||
position: absolute;
|
||||
top: calc((var(--pagedjs-margin-top) + var(--bleed-images))*-1);
|
||||
left: calc((var(--pagedjs-margin-left) + var(--bleed-images))*-1);
|
||||
overflow: hidden;
|
||||
}
|
||||
.pagedjs_page_fullRight .pagedjs_full-spread_container{
|
||||
margin: 0;
|
||||
width: calc(var(--pagedjs-pagebox-width) + var(--bleed-images));
|
||||
height: calc(var(--pagedjs-pagebox-height) + var(--bleed-images)*2)!important;
|
||||
position: absolute;
|
||||
top: calc((var(--pagedjs-margin-top) + var(--bleed-images))*-1);
|
||||
left: calc(var(--pagedjs-margin-left)*-1);
|
||||
overflow: hidden;
|
||||
}
|
||||
.pagedjs_full-spread_content{
|
||||
margin: 0;
|
||||
width: calc(var(--pagedjs-pagebox-width)*2 + var(--bleed-images)*2);
|
||||
height: calc(var(--pagedjs-pagebox-height) + var(--bleed-images)*2)!important;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
.pagedjs_page_fullLeft .pagedjs_full-spread_content{
|
||||
left: calc(var(--pagedjs-fold)*-1);
|
||||
}
|
||||
.pagedjs_page_fullRight .pagedjs_full-spread_content{
|
||||
left: calc((var(--pagedjs-pagebox-width) + var(--bleed-images))*-1 + var(--pagedjs-fold))
|
||||
}
|
||||
|
||||
.pagedjs_full-page_content {
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
top: calc((var(--pagedjs-margin-top) + var(--bleed-images))*-1);
|
||||
}
|
||||
.pagedjs_left_page .pagedjs_full-page_content {
|
||||
width: calc(var(--pagedjs-pagebox-width) + var(--bleed-images));
|
||||
height: calc(var(--pagedjs-pagebox-height) + var(--bleed-images) + var(--bleed-images))!important;
|
||||
left: calc((var(--pagedjs-margin-left) + var(--bleed-images))*-1);
|
||||
|
||||
}
|
||||
.pagedjs_right_page .pagedjs_full-page_content {
|
||||
width: calc(var(--pagedjs-pagebox-width) + var(--bleed-images));
|
||||
height: calc(var(--pagedjs-pagebox-height) + var(--bleed-images) * 2)!important;
|
||||
left: calc(var(--pagedjs-margin-left)*-1);
|
||||
}
|
||||
294
assets/csspageweaver/plugins/fullPage/fullPage.js
Normal file
294
assets/csspageweaver/plugins/fullPage/fullPage.js
Normal file
|
|
@ -0,0 +1,294 @@
|
|||
/**
|
||||
* @name Full page
|
||||
* @author Julie Blanc <contact@julie-blanc.fr>
|
||||
* @see { @link https://gitlab.com/csspageweaver/plugins/fullPage }
|
||||
*/
|
||||
import { Handler } from 'assets/csspageweaver/lib/paged.esm.js';
|
||||
|
||||
|
||||
let bleedFull = '6mm';
|
||||
|
||||
export default class fullPage extends Handler {
|
||||
|
||||
constructor(chunker, polisher, caller) {
|
||||
super(chunker, polisher, caller);
|
||||
this.selectorFullSpread = new Set();
|
||||
this.fullSpreadEls = new Set();
|
||||
this.selectorFullPage = new Set();
|
||||
this.fullPageEls = new Set();
|
||||
this.selectorFullRight = new Set();
|
||||
this.fullRightEls = new Set();
|
||||
this.selectorFullLeft= new Set();
|
||||
this.fullLeftEls = new Set();
|
||||
this.usedPagedEls = new Set();
|
||||
this.specificPage = new Set();
|
||||
this.specificPageClone = new Set();
|
||||
}
|
||||
|
||||
|
||||
|
||||
onDeclaration(declaration, dItem, dList, rule) {
|
||||
// Read customs properties
|
||||
if (declaration.property == "--pagedjs-full-page") {
|
||||
// get selector of the declaration (NOTE: need csstree.js)
|
||||
let selector = csstree.generate(rule.ruleNode.prelude);
|
||||
// Push selector in correct set
|
||||
if (declaration.value.value.includes("page")) {
|
||||
this.selectorFullPage.add(selector);
|
||||
}else if(declaration.value.value.includes("spread")) {
|
||||
this.selectorFullSpread.add(selector);
|
||||
}else if(declaration.value.value.includes("right")) {
|
||||
this.selectorFullRight.add(selector);
|
||||
}else if(declaration.value.value.includes("left")) {
|
||||
this.selectorFullLeft.add(selector);
|
||||
}else{
|
||||
let obj = { page: declaration.value.value, elem: selector };
|
||||
this.specificPage.add(JSON.stringify(obj));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
afterParsed(parsed){
|
||||
|
||||
console.log("FULL PAGE loaded");
|
||||
|
||||
// ADD pagedjs classes to elements
|
||||
for (let item of this.selectorFullPage) {
|
||||
let elems = parsed.querySelectorAll(item);
|
||||
for (let elem of elems) {
|
||||
elem.classList.add("pagedjs_full-page-elem");
|
||||
}
|
||||
}
|
||||
for (let item of this.selectorFullSpread) {
|
||||
let elems = parsed.querySelectorAll(item);
|
||||
for (let elem of elems) {
|
||||
elem.classList.add("pagedjs_full-spread-elem");
|
||||
}
|
||||
}
|
||||
for (let item of this.selectorFullLeft) {
|
||||
let elems = parsed.querySelectorAll(item);
|
||||
for (let elem of elems) {
|
||||
elem.classList.add("pagedjs_full-page-left-elem");
|
||||
}
|
||||
}
|
||||
for (let item of this.selectorFullRight) {
|
||||
let elems = parsed.querySelectorAll(item);
|
||||
for (let elem of elems) {
|
||||
elem.classList.add("pagedjs_full-page-right-elem");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// SPECIFIC PAGE ------------------------------------
|
||||
this.specificPage.forEach(entry => {
|
||||
const obj = JSON.parse(entry);
|
||||
const elements = parsed.querySelectorAll(obj.elem);
|
||||
if (elements.length > 0) {
|
||||
// pourquoi c’est ajouté même si l’élément n’existe pas ?
|
||||
elements[0].classList.add("pagedjs_full-page-specific");
|
||||
const clone = elements[0].cloneNode(true);
|
||||
obj.elemClone = clone.outerHTML;
|
||||
elements[0].remove();
|
||||
}
|
||||
this.specificPageClone.add(JSON.stringify(obj));
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
renderNode(clone, node) {
|
||||
// FULL SPREAD
|
||||
// if you find a full page element, move it in the array
|
||||
if (node.nodeType == 1 && node.classList.contains("pagedjs_full-spread-elem")) {
|
||||
this.fullSpreadEls.add(node);
|
||||
this.usedPagedEls.add(node);
|
||||
|
||||
// remove the element from the flow by hiding it.
|
||||
clone.style.display = "none";
|
||||
}
|
||||
|
||||
// FULL PAGE
|
||||
if (node.nodeType == 1 && node.classList.contains("pagedjs_full-page-left-elem")) {
|
||||
this.fullLeftEls.add(node);
|
||||
this.usedPagedEls.add(node);
|
||||
clone.style.display = "none";
|
||||
}else if (node.nodeType == 1 && node.classList.contains("pagedjs_full-page-right-elem")) {
|
||||
this.fullRightEls.add(node);
|
||||
this.usedPagedEls.add(node);
|
||||
clone.style.display = "none";
|
||||
}else if (node.nodeType == 1 && node.classList.contains("pagedjs_full-page-elem")) {
|
||||
this.fullPageEls.add(node);
|
||||
this.usedPagedEls.add(node);
|
||||
clone.style.display = "none";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
afterPageLayout(pageElement, page, breakToken, chunker) {
|
||||
|
||||
if(page.id == "page-1"){
|
||||
let allPages = document.querySelector(".pagedjs_pages");
|
||||
allPages.style.setProperty('--bleed-images', bleedFull);
|
||||
}
|
||||
|
||||
// ADD --pagedjs-fold on body if doesn't exist
|
||||
if(pageElement.classList.contains("pagedjs_first_page")){
|
||||
let body = document.getElementsByTagName("body")[0];
|
||||
let style = window.getComputedStyle(body);
|
||||
let fold = style.getPropertyValue('--pagedjs-fold');
|
||||
if(!fold){
|
||||
body.style.setProperty('--pagedjs-fold', '0mm')
|
||||
}
|
||||
}
|
||||
|
||||
// FULL SPREAD
|
||||
// if there is an element in the fullSpreadEls Set, (goodbye arrays!)
|
||||
|
||||
for (let img of this.fullSpreadEls) {
|
||||
|
||||
if (page.element.classList.contains("pagedjs_right_page")) {
|
||||
|
||||
let imgLeft;
|
||||
let imgRight;
|
||||
|
||||
if (img.nodeName == "IMG") {
|
||||
/* Add outside + inside container if the element is an img */
|
||||
let containerLeft = document.createElement("div");
|
||||
containerLeft.classList.add("pagedjs_full-spread_container");
|
||||
let containerLeftInside = document.createElement("div");
|
||||
containerLeftInside.classList.add("pagedjs_full-spread_content");
|
||||
containerLeft.appendChild(containerLeftInside).appendChild(img);
|
||||
imgLeft = containerLeft;
|
||||
|
||||
let containerRight = document.createElement("div");
|
||||
containerRight.classList.add("pagedjs_full-spread_container");
|
||||
let containerRightInside = document.createElement("div");
|
||||
containerRightInside.classList.add("pagedjs_full-spread_content");
|
||||
containerRight.appendChild(containerRightInside).appendChild(img.cloneNode(true));
|
||||
imgRight = containerRight;
|
||||
|
||||
} else {
|
||||
/* Add outside container if the element is an img */
|
||||
let containerLeft = document.createElement("div");
|
||||
containerLeft.classList.add("pagedjs_full-spread_container");
|
||||
img.classList.add("pagedjs_full-spread_content");
|
||||
containerLeft.appendChild(img);
|
||||
imgLeft = containerLeft;
|
||||
let containerRight = document.createElement("div");
|
||||
containerRight.classList.add("pagedjs_full-spread_container");
|
||||
img.classList.add("pagedjs_full-spread_content");
|
||||
containerRight.appendChild(img.cloneNode(true));
|
||||
imgRight = containerRight;
|
||||
|
||||
}
|
||||
|
||||
// put the first element on the page
|
||||
let fullPage = chunker.addPage();
|
||||
fullPage.element
|
||||
.querySelector(".pagedjs_page_content")
|
||||
.insertAdjacentElement("afterbegin", imgLeft);
|
||||
fullPage.element.classList.add("pagedjs_page_fullLeft");
|
||||
|
||||
// page right
|
||||
let fullPageRight = chunker.addPage();
|
||||
fullPageRight.element
|
||||
.querySelector(".pagedjs_page_content")
|
||||
.insertAdjacentElement("afterbegin", imgRight);
|
||||
fullPageRight.element.classList.add("pagedjs_page_fullRight");
|
||||
img.style.removeProperty("display");
|
||||
|
||||
this.fullSpreadEls.delete(img);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// FULL PAGE
|
||||
// if there is an element in the fullPageEls Set
|
||||
for (let img of this.fullPageEls) {
|
||||
let container = document.createElement("div");
|
||||
container.classList.add("pagedjs_full-page_content");
|
||||
container.appendChild(img);
|
||||
let fullPage = chunker.addPage();
|
||||
|
||||
fullPage.element
|
||||
.querySelector(".pagedjs_page_content")
|
||||
.insertAdjacentElement("afterbegin", container);
|
||||
fullPage.element.classList.add("pagedjs_page_fullPage");
|
||||
img.style.removeProperty("display");
|
||||
|
||||
this.fullPageEls.delete(img);
|
||||
}
|
||||
|
||||
// FULL Left PAGE
|
||||
// if there is an element in the fullLeftEls Set
|
||||
for (let img of this.fullLeftEls) {
|
||||
|
||||
if (page.element.classList.contains("pagedjs_right_page")) {
|
||||
let container = document.createElement("div");
|
||||
container.classList.add("pagedjs_full-page_content");
|
||||
container.appendChild(img);
|
||||
let fullPage = chunker.addPage();
|
||||
|
||||
fullPage.element
|
||||
.querySelector(".pagedjs_page_content")
|
||||
.insertAdjacentElement("afterbegin", container);
|
||||
fullPage.element.classList.add("pagedjs_page_fullPage");
|
||||
img.style.removeProperty("display");
|
||||
|
||||
this.fullLeftEls.delete(img);
|
||||
}
|
||||
}
|
||||
|
||||
// FULL RIGHT PAGE
|
||||
// if there is an element in the fullRightEls Set
|
||||
for (let img of this.fullRightEls) {
|
||||
|
||||
if (page.element.classList.contains("pagedjs_left_page")) {
|
||||
let container = document.createElement("div");
|
||||
container.classList.add("pagedjs_full-page_content");
|
||||
container.appendChild(img);
|
||||
let fullPage = chunker.addPage();
|
||||
|
||||
fullPage.element
|
||||
.querySelector(".pagedjs_page_content")
|
||||
.insertAdjacentElement("afterbegin", container);
|
||||
fullPage.element.classList.add("pagedjs_page_fullPage");
|
||||
img.style.removeProperty("display");
|
||||
|
||||
this.fullRightEls.delete(img);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// SPECIFIC PAGE ------------------------------------
|
||||
let pageNum = pageElement.id.split('page-')[1];
|
||||
pageNum = parseInt(pageNum);
|
||||
|
||||
this.specificPageClone.forEach(entry => {
|
||||
const obj = JSON.parse(entry);
|
||||
let targetedPage = obj.page;
|
||||
let prevPage = parseInt(targetedPage) - 1;
|
||||
|
||||
let elem = obj.elemClone;
|
||||
|
||||
if(prevPage == pageNum){
|
||||
let container = document.createElement("div");
|
||||
container.classList.add("pagedjs_full-page_content");
|
||||
container.innerHTML = elem;
|
||||
let fullPage = chunker.addPage();
|
||||
|
||||
fullPage.element
|
||||
.querySelector(".pagedjs_page_content")
|
||||
.insertAdjacentElement("afterbegin", container);
|
||||
fullPage.element.classList.add("pagedjs_page_fullPage");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
1
assets/csspageweaver/plugins/grid/.gitignore
vendored
Normal file
1
assets/csspageweaver/plugins/grid/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.DS_Store
|
||||
7
assets/csspageweaver/plugins/grid/README.md
Normal file
7
assets/csspageweaver/plugins/grid/README.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
name: grid
|
||||
tags: experimental, boilerplate, gui
|
||||
description: A simple helper to see custom grid (1-12 columns)
|
||||
---
|
||||
|
||||
Caution: This plugin is not yet fully functional and requires further work.
|
||||
13
assets/csspageweaver/plugins/grid/config.json
Normal file
13
assets/csspageweaver/plugins/grid/config.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"name": "Grid",
|
||||
"description": "",
|
||||
"version": "1.0",
|
||||
"ui": {
|
||||
"title": "Grid",
|
||||
"description": "This Toogle a 12 columns grid",
|
||||
"toggle": true
|
||||
},
|
||||
"stylesheet": "grid.css",
|
||||
"script": "grid-ui.js",
|
||||
"hook": "grid-hook.js"
|
||||
}
|
||||
36
assets/csspageweaver/plugins/grid/grid-hook.js
Normal file
36
assets/csspageweaver/plugins/grid/grid-hook.js
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
* @name Grid
|
||||
* @author Julie Blanc <contact@julie-blanc.fr>
|
||||
* @see { @link https://gitlab.com/csspageweaver/plugins/grid/ }
|
||||
*/
|
||||
|
||||
import { Handler } from '/csspageweaver/lib/paged.esm.js';
|
||||
|
||||
export default class GridPage extends Handler {
|
||||
constructor(chunker, polisher, caller) {
|
||||
super(chunker, polisher, caller);
|
||||
}
|
||||
|
||||
|
||||
afterPageLayout(pageElement, page, breakToken) {
|
||||
let pageBox = pageElement.querySelector(".pagedjs_pagebox");
|
||||
|
||||
var div = document.createElement('div');
|
||||
div.classList.add("grid-page");
|
||||
div.innerHTML = '<div class="grid-column grid-column-0"></div>\
|
||||
<div class="grid-column grid-column-1"></div>\
|
||||
<div class="grid-column grid-column-2"></div>\
|
||||
<div class="grid-column grid-column-3"></div>\
|
||||
<div class="grid-column grid-column-4"></div>\
|
||||
<div class="grid-column grid-column-5"></div>\
|
||||
<div class="grid-column grid-column-6"></div>\
|
||||
<div class="grid-column grid-column-7"></div>\
|
||||
<div class="grid-column grid-column-8"></div>\
|
||||
<div class="grid-column grid-column-9"></div>\
|
||||
<div class="grid-column grid-column-10"></div>\
|
||||
<div class="grid-column grid-column-11"></div>\
|
||||
<div class="grid-column grid-column-12"></div>';
|
||||
pageBox.appendChild(div);
|
||||
}
|
||||
|
||||
}
|
||||
50
assets/csspageweaver/plugins/grid/grid-ui.js
Normal file
50
assets/csspageweaver/plugins/grid/grid-ui.js
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* @name Grid
|
||||
* @author Julie Blanc <contact@julie-blanc.fr>
|
||||
* @see { @link https://gitlab.com/csspageweaver/plugins/grid/ }
|
||||
*/
|
||||
|
||||
export default function gridEvents(){
|
||||
let body = cssPageWeaver.ui.body;
|
||||
let fileTitle = cssPageWeaver.docTitle;
|
||||
|
||||
|
||||
let grid = {}
|
||||
|
||||
// set default value
|
||||
grid.default = {
|
||||
toggle: 'no-grid'
|
||||
}
|
||||
|
||||
grid.toggle = {}
|
||||
grid.toggle.input = cssPageWeaver.ui.grid.toggleInput
|
||||
grid.toggle.label = cssPageWeaver.ui.grid.toggleLabel
|
||||
|
||||
|
||||
/* Previous session */
|
||||
grid.toggle.value = localStorage.getItem('gridToggle_' + fileTitle) || grid.default.toggle
|
||||
|
||||
if(grid.toggle.value == "no-grid"){
|
||||
body.classList.add('no-grid');
|
||||
grid.toggle.input.checked = false;
|
||||
}else if(grid.toggle.value == "grid"){
|
||||
body.classList.remove('no-grid');
|
||||
grid.toggle.input.checked = true;
|
||||
}else{
|
||||
body.classList.add('no-grid');
|
||||
localStorage.setItem('gridToggle_' + fileTitle, 'no-grid');
|
||||
grid.toggle.input.checked = false;
|
||||
}
|
||||
|
||||
|
||||
/* Grid toggle event */
|
||||
grid.toggle.input.addEventListener("input", (e) => {
|
||||
if(e.target.checked){
|
||||
body.classList.remove('no-grid');
|
||||
localStorage.setItem('gridToggle_' + fileTitle, 'grid');
|
||||
}else{
|
||||
body.classList.add('no-grid');
|
||||
localStorage.setItem('gridToggle_' + fileTitle, 'no-grid');
|
||||
}
|
||||
});
|
||||
}
|
||||
60
assets/csspageweaver/plugins/grid/grid.css
Normal file
60
assets/csspageweaver/plugins/grid/grid.css
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
@media screen{
|
||||
.grid-page{
|
||||
--nbr-columns: 8;
|
||||
width: var(--pagedjs-pagebox-width);
|
||||
height: var(--pagedjs-pagebox-height);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--nbr-columns), calc(100%/var(--nbr-columns)));
|
||||
|
||||
box-shadow: 1px 0px 0px 0px var(--grid-color);
|
||||
|
||||
--grid-color: magenta;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.pagedjs_right_page .grid-page{
|
||||
padding-left: var(--pagedjs-margin-left);
|
||||
padding-right: var(--pagedjs-margin-right);
|
||||
}
|
||||
|
||||
.pagedjs_left_page .grid-page{
|
||||
padding-left: var(--pagedjs-margin-left);
|
||||
padding-right: var(--pagedjs-margin-right);
|
||||
}
|
||||
|
||||
|
||||
.grid-page .grid-column{
|
||||
box-shadow: 1px 0px 0px 0px var(--grid-color);
|
||||
grid-row: 1/end;
|
||||
width: 100%;
|
||||
justify-self: right;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.grid-column-0{
|
||||
grid-column: 1;
|
||||
box-shadow: -1px 0px 0px 0px var(--grid-color)!important;
|
||||
justify-self: left;
|
||||
}
|
||||
|
||||
.grid-column-1{ grid-column: 1; }
|
||||
.grid-column-2{ grid-column: 2; }
|
||||
.grid-column-3{ grid-column: 3; }
|
||||
.grid-column-4{ grid-column: 4; }
|
||||
.grid-column-5{ grid-column: 5; }
|
||||
.grid-column-6{ grid-column: 6; }
|
||||
.grid-column-7{ grid-column: 7; }
|
||||
.grid-column-8{ grid-column: 8; }
|
||||
.grid-column-9{ grid-column: 9; }
|
||||
.grid-column-10{ grid-column: 10; }
|
||||
.grid-column-11{ grid-column: 11; }
|
||||
.grid-column-12{ grid-column: 12; }
|
||||
}
|
||||
|
||||
.no-grid .grid-page{
|
||||
display: none;
|
||||
}
|
||||
1
assets/csspageweaver/plugins/imposition/.gitignore
vendored
Normal file
1
assets/csspageweaver/plugins/imposition/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.DS_Store
|
||||
17
assets/csspageweaver/plugins/imposition/config.json
Normal file
17
assets/csspageweaver/plugins/imposition/config.json
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "Booklet Imposition",
|
||||
"description": " This script re-arrange the pages of your document in order to make an imposed sheet layouts for printing. ",
|
||||
"author": ["Quentin Juhel", "Julien Taquet", "Julien Bidoret", "Julie Blanc"],
|
||||
"licence": "MIT",
|
||||
"repository": "https://gitlab.coko.foundation/pagedjs/pagedjs-plugins/booklet-imposition",
|
||||
"version": "1.0",
|
||||
"ui": {
|
||||
"title": "Imposition",
|
||||
"description": "Re-arrange the pages in order to make an imposed sheet layouts for printing.",
|
||||
"toggle": false,
|
||||
"template": "template.html"
|
||||
},
|
||||
"hook": "index.js"
|
||||
}
|
||||
|
||||
|
||||
363
assets/csspageweaver/plugins/imposition/index.js
Normal file
363
assets/csspageweaver/plugins/imposition/index.js
Normal file
|
|
@ -0,0 +1,363 @@
|
|||
/**
|
||||
* @file Imposition for booklet(s)
|
||||
* This script re-arrange the pages of your document in order to make an imposed sheet layouts for printing.
|
||||
* Two pages per sheet, double-sided
|
||||
* @author Originally developped by Julien Bidoret,Quentin Juhel and Julien Taquet,
|
||||
* @author adapted for this project by Julie Blanc
|
||||
* @see { @link https://gitlab.coko.foundation/pagedjs/pagedjs-plugins/booklet-imposition }
|
||||
* @see { @link https://gitlab.com/csspageweaver/plugins/imposition/}
|
||||
*/
|
||||
|
||||
import { Handler } from '/csspageweaver/lib/paged.esm.js';
|
||||
|
||||
export default class booklet extends Handler {
|
||||
|
||||
constructor(chunker, polisher, caller) {
|
||||
super(chunker, polisher, caller);
|
||||
this.pagedbooklet;
|
||||
this.pagedspread;
|
||||
this.sourceSize;
|
||||
this.pageStart;
|
||||
this.pageEnd;
|
||||
}
|
||||
|
||||
afterRendered(pages) {
|
||||
|
||||
/* Launch when printing */
|
||||
window.addEventListener("beforeprint", (evenement) => {
|
||||
|
||||
let format = document.querySelector(".pagedjs_page");
|
||||
|
||||
/* Width of page without bleed, extract the first number of calc() function */
|
||||
let width = getCSSCustomProp("--pagedjs-width", format);
|
||||
let numbers = width
|
||||
.match(/[0-9]+/g)
|
||||
.map(function (n) {
|
||||
return + (n);
|
||||
});
|
||||
width = parseInt(numbers[0]);
|
||||
|
||||
/* Height of page with bleed, addition of all the numbers of calc() function*/
|
||||
let height = getCSSCustomProp("--pagedjs-height", format);
|
||||
numbers = height
|
||||
.match(/[0-9]+/g)
|
||||
.map(function (n) {
|
||||
return + (n);
|
||||
});
|
||||
const reducer = (previousValue, currentValue) => previousValue + currentValue;
|
||||
height = numbers.reduce(reducer);
|
||||
|
||||
/* Bleed of the page */
|
||||
let bleed = getCSSCustomProp("--pagedjs-bleed-top", format);
|
||||
let bleedNum = parseInt(bleed);
|
||||
|
||||
/* Spread and half-spread*/
|
||||
let spread = width * 2 + bleedNum * 2;
|
||||
let spreadHalf = width + bleedNum;
|
||||
let onePage = width + bleedNum*2;
|
||||
|
||||
// get values
|
||||
let inputBooklet = document.querySelector("#input-booklet");
|
||||
let inputSpread = document.querySelector("#input-spread");
|
||||
let inputRange = document.querySelector("#imposition-range");
|
||||
let inputBookletStart = document.querySelector("#booklet-start").value;
|
||||
let inputBookletEnd = document.querySelector("#booklet-end").value;
|
||||
|
||||
let containerPages = document.querySelector(".pagedjs_pages");
|
||||
|
||||
|
||||
|
||||
if(inputBooklet.checked){
|
||||
this.pagedbooklet = true;
|
||||
this.pageStart = 1;
|
||||
this.pageEnd = pages.length;
|
||||
|
||||
if(inputRange.checked){
|
||||
this.pageStart = parseInt(inputBookletStart);
|
||||
this.pageEnd = parseInt(inputBookletEnd);
|
||||
}
|
||||
}else if(inputSpread.checked){
|
||||
this.pagedspread = true;
|
||||
this.pageStart = 1;
|
||||
this.pageEnd = pages.length;
|
||||
|
||||
if(inputRange.checked){
|
||||
this.pageStart = parseInt(inputBookletStart);
|
||||
this.pageEnd = parseInt(inputBookletEnd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Delete pages we don't want*/
|
||||
pages.forEach(page => {
|
||||
let id = parseInt(page.id.replace('page-', ''));
|
||||
if(id < this.pageStart || id > this.pageEnd){
|
||||
let pageSelect = document.querySelector('#'+ page.id);
|
||||
pageSelect.remove();
|
||||
}
|
||||
});
|
||||
|
||||
/* Reset page counter */
|
||||
let reset = parseInt(this.pageStart) - 1;
|
||||
containerPages.style.counterReset = "page " + reset;
|
||||
|
||||
|
||||
|
||||
|
||||
// Add CSS to have pages in spread
|
||||
//
|
||||
// - change size of the page when printing (actually, sheet size)
|
||||
// - flex properties
|
||||
// - delete bleeds inside spread */
|
||||
|
||||
var newSize =
|
||||
`@media print{
|
||||
@page{
|
||||
size: ${spread}mm ${height}mm;
|
||||
}
|
||||
.pagedjs_pages {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
@media screen{
|
||||
.pagedjs_pages{
|
||||
max-width: calc(var(--pagedjs-width) * 2);
|
||||
}
|
||||
}
|
||||
.pagedjs_pages {
|
||||
display: flex !important;
|
||||
flex-wrap: wrap;
|
||||
transform: none !important;
|
||||
height: 100% !important;
|
||||
min-height: 100%;
|
||||
max-height: 100%;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.pagedjs_page {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
max-height: 100%;
|
||||
min-height: 100%;
|
||||
height: 100% !important;
|
||||
|
||||
}
|
||||
|
||||
.pagedjs_sheet {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
max-height: 100%;
|
||||
min-height: 100%;
|
||||
height: 100% !important;
|
||||
}
|
||||
body{
|
||||
--pagedjs-bleed-right-left: 0mm;
|
||||
}
|
||||
.pagedjs_left_page{
|
||||
z-index: 20;
|
||||
width: calc(var(--pagedjs-bleed-left) + var(--pagedjs-pagebox-width))!important;
|
||||
}
|
||||
|
||||
.pagedjs_left_page .pagedjs_bleed-right .pagedjs_marks-crop {
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.pagedjs_right_page,
|
||||
.pagedjs_right_page .pagedjs_sheet{
|
||||
width: calc(var(--pagedjs-bleed-right-right) + var(--pagedjs-pagebox-width))!important;
|
||||
}
|
||||
|
||||
.pagedjs_right_page .pagedjs_sheet{
|
||||
grid-template-columns: [bleed-left] var(--pagedjs-bleed-right-left) [sheet-center] 1fr [bleed-right] var(--pagedjs-bleed-right-right);
|
||||
}
|
||||
.pagedjs_right_page .pagedjs_bleed-left{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.pagedjs_right_page .pagedjs_bleed-top .pagedjs_marks-crop:nth-child(1),
|
||||
.pagedjs_right_page .pagedjs_bleed-bottom .pagedjs_marks-crop:nth-child(1){
|
||||
width: 0!important;
|
||||
}
|
||||
.pagedjs_first_page {
|
||||
margin-left: 0;
|
||||
}
|
||||
body{
|
||||
margin: 0
|
||||
}
|
||||
.pagedjs_page:nth-of-type(even){
|
||||
break-after: always;
|
||||
}
|
||||
.pagedjs_page,
|
||||
.pagedjs_sheet{
|
||||
width: ${spreadHalf - 0.1}mm!important;
|
||||
}
|
||||
|
||||
`;
|
||||
|
||||
var twoPageView = `.pagedjs_page:nth-of-type(1){
|
||||
bakground-color: red;
|
||||
margin-left: ${spreadHalf}mm!important;
|
||||
}`;
|
||||
|
||||
// Add style for the arrangement of the pages
|
||||
|
||||
if (this.pagedbooklet == true) {
|
||||
let style = document.createElement("style");
|
||||
style.textContent = newSize;
|
||||
document
|
||||
.head
|
||||
.appendChild(style);
|
||||
|
||||
var number_of_pages = document.getElementsByClassName("pagedjs_page").length;
|
||||
var pages_array = [];
|
||||
|
||||
// If the page count isn't a multiple of 4, we need to pad the array with blank
|
||||
// pages so we have the correct number of pages for a booklet.
|
||||
//
|
||||
// ex. [1, 2, 3, 4, 5, 6, 7, 8, 9, blank, blank, blank]
|
||||
|
||||
let modulo = number_of_pages % 4;
|
||||
let additional_pages = 0;
|
||||
if (modulo != 0) {
|
||||
additional_pages = 4 - modulo;
|
||||
}
|
||||
|
||||
for (i = 0; i < additional_pages; i++) {
|
||||
let added_page = document.createElement("div");
|
||||
added_page
|
||||
.classList
|
||||
.add("pagedjs_page", "added");
|
||||
added_page.id = `page-${this.pageEnd + i + 1}`;
|
||||
document
|
||||
.querySelector(".pagedjs_pages")
|
||||
.appendChild(added_page);
|
||||
}
|
||||
|
||||
// Push each page in the array
|
||||
|
||||
for (var i = number_of_pages + additional_pages; i >= 1; i--) {
|
||||
pages_array.push(i);
|
||||
}
|
||||
|
||||
|
||||
// Split the array in half
|
||||
//
|
||||
// ex. [1, 2, 3, 4, 5, 6], [7, 8, 9, blank, blank, blank]
|
||||
|
||||
var split_start = pages_array.length / 2;
|
||||
|
||||
var split_end = pages_array.length;
|
||||
|
||||
var first_array = pages_array.slice(0, split_start);
|
||||
var second_array = pages_array.slice(split_start, split_end);
|
||||
|
||||
// Reverse the second half of the array. This is the beginning of the back half
|
||||
// of the booklet (from the center fold, back to the outside last page)
|
||||
//
|
||||
// ex. [blank, blank, blank, 9, 8, 7]
|
||||
|
||||
var second_array_reversed = second_array.reverse();
|
||||
|
||||
// Zip the two arrays together in groups of 2 These will end up being each '2-up
|
||||
// side' of the final document So, the sub-array at index zero will be the first
|
||||
// side of physical page one and index 1 will be the back side. However, they
|
||||
// won't yet be in the proper order.
|
||||
//
|
||||
// ex. [[1, blank], [2, blank], [3, blank], [4, 9], [5, 8], [6, 7]]
|
||||
|
||||
var page_groups = [];
|
||||
for (var i = 0; i < first_array.length; i++) {
|
||||
page_groups[i] = [
|
||||
first_array[i], second_array_reversed[i]
|
||||
];
|
||||
}
|
||||
|
||||
// We need to reverse every other sub-array starting with the first side. This
|
||||
// is the final step of aligning our booklet pages in the order with which the
|
||||
// booklet gets printed and bound.
|
||||
//
|
||||
// ex. [[blank, 1], [2, blank], [blank, 3], [4, 9], [8, 5], [6, 7]] final_groups
|
||||
// = page_groups.each_with_index { |group, index| group.reverse! if (index %
|
||||
// 2).zero? }
|
||||
var final_groups = [];
|
||||
for (var i = 0; i < page_groups.length; i++) {
|
||||
var group = page_groups[i];
|
||||
if (i % 2 != 0) {
|
||||
final_groups[i] = page_groups[i].reverse();
|
||||
} else {
|
||||
final_groups[i] = page_groups[i];
|
||||
}
|
||||
}
|
||||
console.log("Final Imposition Order: " + final_groups);
|
||||
|
||||
var allPages = document.querySelectorAll(".pagedjs_page");
|
||||
|
||||
var final_flat = final_groups.flat();
|
||||
|
||||
final_flat.forEach((folio, i) => {
|
||||
folio = folio + reset;
|
||||
document.querySelector(`#page-${folio}`).style.order = i;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if (this.pagedspread == true) {
|
||||
console.log("double page view please");
|
||||
let style = document.createElement("style");
|
||||
style.textContent = newSize;
|
||||
document
|
||||
.head
|
||||
.appendChild(style);
|
||||
let styleBis = document.createElement("style");
|
||||
styleBis.textContent = twoPageView;
|
||||
document
|
||||
.head
|
||||
.appendChild(styleBis);
|
||||
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pass in an element and its CSS Custom Property that you want the value of.
|
||||
* Optionally, you can determine what datatype you get back.
|
||||
*
|
||||
* @param {String} propKey
|
||||
* @param {HTMLELement} element=document.documentElement
|
||||
* @param {String} castAs='string'
|
||||
* @returns {*}
|
||||
*/
|
||||
const getCSSCustomProp = (
|
||||
propKey,
|
||||
element = document.documentElement,
|
||||
castAs = "string"
|
||||
) => {
|
||||
let response = getComputedStyle(element).getPropertyValue(propKey);
|
||||
|
||||
// Tidy up the string if there's something to work with
|
||||
if (response.length) {
|
||||
response = response
|
||||
.replace(/\'|"/g, "")
|
||||
.trim();
|
||||
}
|
||||
|
||||
// Convert the response into a whatever type we wanted
|
||||
switch (castAs) {
|
||||
case "number":
|
||||
case "int":
|
||||
return parseInt(response, 10);
|
||||
case "float":
|
||||
return parseFloat(response, 10);
|
||||
case "boolean":
|
||||
case "bool":
|
||||
return response === "true" || response === "1";
|
||||
}
|
||||
|
||||
// Return the string response by default
|
||||
return response;
|
||||
};
|
||||
0
assets/csspageweaver/plugins/imposition/stylesheet.css
Normal file
0
assets/csspageweaver/plugins/imposition/stylesheet.css
Normal file
22
assets/csspageweaver/plugins/imposition/template.html
Normal file
22
assets/csspageweaver/plugins/imposition/template.html
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<input type="radio" id="input-spread" data-open-container="imposition-details" name="radio-imposition">
|
||||
<label for="input-spread" class="label-block">Two-page view</label>
|
||||
|
||||
<input type="radio" id="input-booklet" data-open-container="imposition-details" name="radio-imposition">
|
||||
<label for="input-booklet" class="label-block">Booklet <span></span></label>
|
||||
|
||||
<div id="imposition-details">
|
||||
|
||||
<div id="radio-imposition-pages">
|
||||
<input type="radio" id="imposition-all" name="radio-imposition-pages" value="all" checked />
|
||||
<label for="imposition-all" class="label-block">All pages</label>
|
||||
<input type="radio" id="imposition-range" name="radio-imposition-pages" value="booklet" />
|
||||
<label for="imposition-range" class="label-block">Range</label>
|
||||
</div>
|
||||
|
||||
<div id="booklet-sheets" class="panel-group-values">
|
||||
<p>from</p>
|
||||
<input type="number" id="booklet-start" name="booklet-start" min="1" max="1000" value="1">
|
||||
<p>to</p>
|
||||
<input type="number" id="booklet-end" name="booklet-end" min="1" max="1000" value="16">
|
||||
</div>
|
||||
</div>
|
||||
1
assets/csspageweaver/plugins/marginBox/.gitignore
vendored
Normal file
1
assets/csspageweaver/plugins/marginBox/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.DS_Store
|
||||
10
assets/csspageweaver/plugins/marginBox/config.json
Normal file
10
assets/csspageweaver/plugins/marginBox/config.json
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"version": "1.0",
|
||||
"ui": {
|
||||
"title": "Margin boxes",
|
||||
"description": "This Toogle border around margin box",
|
||||
"toggle": true
|
||||
},
|
||||
"script": "marginBox.js",
|
||||
"stylesheet": "marginBox.css"
|
||||
}
|
||||
7
assets/csspageweaver/plugins/marginBox/marginBox.css
Normal file
7
assets/csspageweaver/plugins/marginBox/marginBox.css
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
:root {
|
||||
--color-marginBox: purple;
|
||||
}
|
||||
|
||||
.no-marginBoxes{
|
||||
--color-marginBox: transparent;
|
||||
}
|
||||
26
assets/csspageweaver/plugins/marginBox/marginBox.js
Normal file
26
assets/csspageweaver/plugins/marginBox/marginBox.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
* @name Margin Box
|
||||
* @author Julie Blanc <contact@julie-blanc.fr>
|
||||
* @see { @link https://gitlab.com/csspageweaver/plugins/marginBox }
|
||||
*/
|
||||
|
||||
export default function marginBoxEvents(){
|
||||
|
||||
let body = cssPageWeaver.ui.body
|
||||
|
||||
/* MARGIN BOXES ----------------------------------------------------------------------------------------------------
|
||||
----------------------------------------------------------------------------------------------------------------*/
|
||||
let marginButton = document.querySelector('#label-marginBox-toggle');
|
||||
|
||||
body.classList.add('no-marginBoxes');
|
||||
|
||||
cssPageWeaver.ui.marginBox.toggleInput.addEventListener("input", (e) => {
|
||||
if(e.target.checked){
|
||||
/* see baseline */
|
||||
body.classList.remove('no-marginBoxes');
|
||||
}else{
|
||||
/* hide baseline */
|
||||
body.classList.add('no-marginBoxes');
|
||||
}
|
||||
});
|
||||
}
|
||||
1
assets/csspageweaver/plugins/marginNotes/.gitignore
vendored
Normal file
1
assets/csspageweaver/plugins/marginNotes/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.DS_Store
|
||||
114
assets/csspageweaver/plugins/marginNotes/README.md
Normal file
114
assets/csspageweaver/plugins/marginNotes/README.md
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
# Plugin for sidenotes
|
||||
|
||||
This plugin proposes a script for sidenotes in Paged.js.
|
||||
|
||||
The plugin creates sidenotes from `span` elements in the text flow. It can be combined with the [inline_notes plugin](https://gitlab.com/csspageweaver/plugins/inline_notes) to create these span elements from listed notes, which are more common in conversion tools like Pandoc.
|
||||
|
||||
Note: The plugin moves notes if they overlap or if the last note overflows at the end of the page.
|
||||
|
||||
## How to use the plugin
|
||||
|
||||
|
||||
Add this folder to `csspageweaver/plugins/`.
|
||||
|
||||
Call the plugin in `csspageweaver/manifest.json`:
|
||||
|
||||
```json
|
||||
"plugins": [
|
||||
"sidenotes",
|
||||
// other plugins ...
|
||||
],
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
In `manifest.json`, you can modify/add some parameters:
|
||||
|
||||
```json
|
||||
"plugins":{
|
||||
"sidenotes"
|
||||
},
|
||||
"pluginsParameters":{
|
||||
"sidenotes": {
|
||||
"selector": ".sidenote",
|
||||
"position": "outside",
|
||||
"reset": ".chapter",
|
||||
"align": ".chapter p:first-of-type"
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
|
||||
All the parameters are optional.
|
||||
|
||||
- `selector` → CSS selector for the note element (must be inline in the HTML), default is `.sidenote`
|
||||
- `position` → Specifies the position of sidenotes relative to the main text: options are "outside", "inside", "left", "right".
|
||||
- 'outside': the left pages notes positonned on the margin left and the right pages notes on the margin right. This is the default value.
|
||||
- 'inside': the left pages notes positonned on the margin right and the right pages notes on the margin left.
|
||||
- 'left': the notes of both pages are positinoned on the margin left.
|
||||
- 'right': the notes of both pages are positinoned on the margin left.
|
||||
- `reset` → CSS selector where you want reset note counter
|
||||
- `align` → Element to align the first note of the page to, if present on the page
|
||||
|
||||
|
||||
|
||||
## Notes in HTML
|
||||
|
||||
In your HTML, the note must be a `<span>` inserted in the text, like this:
|
||||
|
||||
```HTML
|
||||
Donec tincidunt, odio vel vestibulum sollicitudin, nibh dolor tempor sapien, ac laoreet
|
||||
sem felis ut purus. <span class="sidenote">Vestibulum neque ex, ullamcorper sit
|
||||
amet diam sed, pharetra laoreet sem.</span> Morbi cursus bibendum consectetur. Nullam vel
|
||||
lacus congue nibh pulvinar maximus sit amet eu risus. Curabitur semper odio mauris, nec
|
||||
imperdiet velit pharetra non. Aenean accumsan nulla ac ex iaculis interdum.
|
||||
```
|
||||
|
||||
You can use the [inline_notes` plugin](https://gitlab.com/csspageweaver/plugins/inline_notes) to create these span elements from listed notes, which are more common in conversion tools like Pandoc.
|
||||
|
||||
The inline_notes plugin should be called before the sidenotes plugin in the `manifest.json`:
|
||||
|
||||
|
||||
```json
|
||||
"plugins": [
|
||||
"inline_notes",
|
||||
"sidenotes",
|
||||
// other plugins ...
|
||||
],
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Styling notes
|
||||
|
||||
By default, the width of the notes is set on the corresponding margin where the notes are positioned. You can change this width by adjusting the `padding-left` and `padding-right` of your note elements.
|
||||
|
||||
To apply specific style depending on the left or right pages, uses the following CSS (where `sidenote` is the class of your notes):
|
||||
|
||||
```CSS
|
||||
.pagedjs_left_page .sidenote {
|
||||
padding-left: 40px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
.pagedjs_right_page .sidenote {
|
||||
padding-left: 20px;
|
||||
padding-right: 40px;
|
||||
}
|
||||
```
|
||||
|
||||
It's possible to change the styles of call notes and marker notes directly in your stylesheet like in the following code:
|
||||
|
||||
```CSS
|
||||
.pagedjs_sidenote_call{
|
||||
color: blue;
|
||||
}
|
||||
.pagedjs_sidenote_marker{
|
||||
color: violet;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Possible improvement
|
||||
|
||||
|
||||
Currently, there is no way to break a note element across two pages in Paged.js. If all the sidenotes on a page don't fit, the overflowing sidenotes are pushed to the next page. Implementing a feature to split notes across pages would enhance the layout flexibility.
|
||||
8
assets/csspageweaver/plugins/marginNotes/config.json
Normal file
8
assets/csspageweaver/plugins/marginNotes/config.json
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"name": "Margin Notes",
|
||||
"description": "Create margin notes with call & markers",
|
||||
"author": ["Julie Blanc et Sarah Garcin"],
|
||||
"licence": "MIT",
|
||||
"version": "1.0",
|
||||
"hook": "marginNotes.js"
|
||||
}
|
||||
260
assets/csspageweaver/plugins/marginNotes/marginNotes.js
Normal file
260
assets/csspageweaver/plugins/marginNotes/marginNotes.js
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
import { Handler } from '/csspageweaver/lib/paged.esm.js';
|
||||
|
||||
export default class marginNotes extends Handler {
|
||||
|
||||
constructor(chunker, polisher, caller) {
|
||||
super(chunker, polisher, caller);
|
||||
this.parameters = cssPageWeaver.features.marginNotes.parameters;
|
||||
this.notesClass = this.parameters?.selector || ".sidenote";
|
||||
this.position = this.parameters?.position || "outside";
|
||||
this.reset = this.parameters?.reset;
|
||||
this.marker = this.parameters?.marker || ". ";
|
||||
}
|
||||
|
||||
beforeParsed(content) {
|
||||
let classNotes = this.notesClass;
|
||||
let marker = this.marker;
|
||||
if (typeof this.reset === "string" && this.reset.trim() !== "") {
|
||||
let sections = content.querySelectorAll(this.reset);
|
||||
sections.forEach(function (section) {
|
||||
addCallAndMarker(section, classNotes, marker);
|
||||
});
|
||||
} else {
|
||||
addCallAndMarker(content, classNotes, marker);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* NOTE FLOAT ---------------------------------------------------------------------------------- */
|
||||
|
||||
let positionRight = 'left: calc(var(--pagedjs-pagebox-width) - var(--pagedjs-margin-left) - var(--pagedjs-margin-right) - 1px); width: var(--pagedjs-margin-right);';
|
||||
let positionLeft = 'left: calc(var(--pagedjs-margin-left)*-1 - 1px); width: var(--pagedjs-margin-left);'
|
||||
|
||||
let notePosition;
|
||||
|
||||
switch (this.position) {
|
||||
case 'inside':
|
||||
notePosition = '.pagedjs_left_page ' + classNotes + '{' + positionRight + '} \
|
||||
.pagedjs_right_page ' + classNotes + '{' + positionLeft + '}';
|
||||
break;
|
||||
case 'left':
|
||||
notePosition = '.pagedjs_left_page ' + classNotes + '{' + positionLeft + '} \
|
||||
.pagedjs_right_page ' + classNotes + '{' + positionLeft + '}';
|
||||
break;
|
||||
case 'right':
|
||||
notePosition = '.pagedjs_left_page ' + classNotes + '{' + positionRight + '} \
|
||||
.pagedjs_right_page ' + classNotes + '{' + positionRight + '}';
|
||||
break;
|
||||
default:
|
||||
notePosition = '.pagedjs_left_page ' + classNotes + '{' + positionLeft + '} \
|
||||
.pagedjs_right_page ' + classNotes + '{' + positionRight + '}';
|
||||
}
|
||||
|
||||
|
||||
/* SPECIFIC CSS ---------------------------------------------------------------------------------- */
|
||||
|
||||
addcss('\
|
||||
' + classNotes + '{\
|
||||
position: absolute;\
|
||||
text-align-last: initial;\
|
||||
box-sizing: border-box;\
|
||||
}' + notePosition);
|
||||
|
||||
|
||||
} /* end beforeParsed*/
|
||||
|
||||
|
||||
afterPageLayout(pageElement, page, breakToken) {
|
||||
let classNotes = this.notesClass;
|
||||
let marker = this.marker;
|
||||
let notes = pageElement.querySelectorAll(classNotes);
|
||||
let noteOverflow = false;
|
||||
|
||||
let notesHeightAll = [];
|
||||
|
||||
if (typeof (notes) != 'undefined' && notes != null && notes.length != 0) {
|
||||
|
||||
for (let n = 0; n < notes.length; ++n) {
|
||||
// Display notes of the page
|
||||
notes[n].style.display = "inline-block";
|
||||
// Add height of the notes to array notesHeightAll
|
||||
let noteHeight = notes[n].offsetHeight;
|
||||
notesHeightAll.push(noteHeight);
|
||||
// Add margins of the notes to array notesHeightAll
|
||||
if (n >= 1) {
|
||||
let margins = biggestMargin(notes[n - 1], notes[n]);
|
||||
notesHeightAll.push(margins);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* FIT PAGE ------------------------------------------------------------------------------------- */
|
||||
|
||||
// Calculate if all notes fit on the page;
|
||||
let reducer = (accumulator, currentValue) => accumulator + currentValue;
|
||||
let allHeight = notesHeightAll.reduce(reducer);
|
||||
let maxHeight = pageElement.querySelectorAll(".pagedjs_page_content")[0].offsetHeight;
|
||||
|
||||
if (allHeight > maxHeight) {
|
||||
|
||||
/* IF DOESN'T FIT ----------------------------------------------------------------------------- */
|
||||
|
||||
// positions all the notes one after the other starting from the top
|
||||
notes[0].style.top = parseInt(window.getComputedStyle(notes[0]).marginBottom, 10) * -1 + "px";
|
||||
for (let a = 1; a < notes.length; ++a) {
|
||||
let notePrev = notes[a - 1];
|
||||
let newMargin = biggestMargin(notePrev, notes[a]);
|
||||
let newTop = notePrev.offsetTop + notePrev.offsetHeight - marginNoteTop(notes[a]) + newMargin;
|
||||
notes[a].style.top = newTop + "px";
|
||||
}
|
||||
// alert
|
||||
let pageNumber = pageElement.dataset.pageNumber;
|
||||
alert("Rendering issue \n ☞ A marginal note overflow on page " + pageNumber + " (this is because there is too many on this page and paged.js can't breaks notes between pages for now.)");
|
||||
noteOverflow = true;
|
||||
|
||||
} else {
|
||||
|
||||
/* PUSH DOWN ---------------------------------------------------- */
|
||||
for (let i = 0; i < notes.length; ++i) {
|
||||
if (i >= 1) {
|
||||
let noteTop = notes[i].offsetTop;
|
||||
let notePrev = notes[i - 1];
|
||||
let newMargin = biggestMargin(notes[i], notePrev);
|
||||
let notePrevBottom = notePrev.offsetTop - marginNoteTop(notePrev) + notePrev.offsetHeight + newMargin;
|
||||
// Push down the note to bottom if it's over the previous one
|
||||
if (notePrevBottom > noteTop) {
|
||||
notes[i].style.top = notePrevBottom + "px";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* PUSH UP ---------------------------------------------- */
|
||||
|
||||
// Height of the page content
|
||||
let contentHeight = pageElement.querySelectorAll(".pagedjs_page_content")[0].querySelectorAll("div")[0].offsetHeight;
|
||||
|
||||
// Check if last note overflow
|
||||
let nbrLength = notes.length - 1;
|
||||
let lastNote = notes[nbrLength];
|
||||
let lastNoteHeight = lastNote.offsetHeight + marginNoteTop(lastNote);
|
||||
let noteBottom = lastNote.offsetTop + lastNoteHeight;
|
||||
|
||||
if (noteBottom > contentHeight) {
|
||||
|
||||
// Push up the last note
|
||||
lastNote.style.top = contentHeight - lastNoteHeight + "px";
|
||||
|
||||
// Push up previous note(s) if if it's over the note
|
||||
for (let i = nbrLength; i >= 1; --i) {
|
||||
let noteLastTop = notes[i].offsetTop;
|
||||
let notePrev = notes[i - 1];
|
||||
let notePrevHeight = notePrev.offsetHeight;
|
||||
let newMargin = biggestMargin(notePrev, notes[i]);
|
||||
let notePrevBottom = notePrev.offsetTop + notePrev.offsetHeight + newMargin;
|
||||
if (notePrevBottom > noteLastTop) {
|
||||
notePrev.style.top = notes[i].offsetTop - marginNoteTop(notePrev) - notePrevHeight - newMargin + "px";
|
||||
}
|
||||
}
|
||||
|
||||
} /* end push up */
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}/* end afterPageLayout*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* FUNCTIONS --------------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------------------------- */
|
||||
|
||||
//
|
||||
|
||||
|
||||
function addCallAndMarker(section, classNotes, marker){
|
||||
let notes = section.querySelectorAll(classNotes);
|
||||
for (let i = 0; i < notes.length; ++i) {
|
||||
|
||||
let num = i + 1;
|
||||
|
||||
// Add call notes
|
||||
var spanCall = document.createElement("span");
|
||||
spanCall.classList.add("note-call");
|
||||
spanCall.classList.add("note-call_" + classNotes);
|
||||
spanCall.dataset.noteCall = classNotes + '-' + num;
|
||||
spanCall.innerHTML = num;
|
||||
notes[i].parentNode.insertBefore(spanCall, notes[i]);
|
||||
|
||||
|
||||
// Add marker notes
|
||||
var spanMarker = document.createElement("span");
|
||||
spanMarker.classList.add("note-marker");
|
||||
spanMarker.classList.add("note-marker_" + classNotes);
|
||||
spanMarker.dataset.noteMarker = classNotes + '-' + num;
|
||||
spanMarker.innerHTML = num + marker;
|
||||
notes[i].prepend(spanMarker);
|
||||
|
||||
|
||||
// Hide notes to avoid rendering problems
|
||||
notes[i].style.display = "none";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARGINS
|
||||
|
||||
function marginNoteTop(elem) {
|
||||
let marginTop = parseInt(window.getComputedStyle(elem).marginTop, 10)
|
||||
return marginTop;
|
||||
}
|
||||
|
||||
function marginNoteBottom(elem) {
|
||||
let marginBottom = parseInt(window.getComputedStyle(elem).marginBottom, 10)
|
||||
return marginBottom;
|
||||
}
|
||||
|
||||
function biggestMargin(a, b) {
|
||||
let margin;
|
||||
let marginBottom = marginNoteBottom(a);
|
||||
let marginTop = marginNoteTop(b);
|
||||
if (marginBottom > marginTop) {
|
||||
margin = marginBottom;
|
||||
} else {
|
||||
margin = marginTop;
|
||||
}
|
||||
return margin;
|
||||
}
|
||||
|
||||
|
||||
// ADD CSS
|
||||
|
||||
function addcss(css) {
|
||||
var head = document.getElementsByTagName('head')[0];
|
||||
var s = document.createElement('style');
|
||||
s.setAttribute('type', 'text/css');
|
||||
if (s.styleSheet) { // IE
|
||||
s.styleSheet.cssText = css;
|
||||
} else {// the world
|
||||
s.appendChild(document.createTextNode(css));
|
||||
}
|
||||
head.appendChild(s);
|
||||
}
|
||||
|
||||
|
||||
// CAMEL CLASS NOTE
|
||||
|
||||
function toCamelClassNote(elem) {
|
||||
let splitClass = elem.split("-");
|
||||
if (splitClass.length > 1) {
|
||||
for (let s = 1; s < splitClass.length; ++s) {
|
||||
let strCapilize = splitClass[s].charAt(0).toUpperCase() + splitClass[s].slice(1)
|
||||
splitClass[s] = strCapilize;
|
||||
}
|
||||
}
|
||||
let reducer = (accumulator, currentValue) => accumulator + currentValue;
|
||||
let classCamel = splitClass.reduce(reducer);
|
||||
return classCamel;
|
||||
}
|
||||
1
assets/csspageweaver/plugins/previewPage/.gitignore
vendored
Normal file
1
assets/csspageweaver/plugins/previewPage/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.DS_Store
|
||||
19
assets/csspageweaver/plugins/previewPage/config.json
Normal file
19
assets/csspageweaver/plugins/previewPage/config.json
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "Preview",
|
||||
"description": "",
|
||||
"version": "1.0",
|
||||
"ui": {
|
||||
"toggle": false,
|
||||
"template": "template.html",
|
||||
"shortcut": [
|
||||
{
|
||||
"active": true,
|
||||
"tutorial": false,
|
||||
"keys": ["shiftKey", "W"],
|
||||
"description": "Toggle Preview"
|
||||
}
|
||||
]
|
||||
},
|
||||
"stylesheet": "stylesheet.css",
|
||||
"script": "event.js"
|
||||
}
|
||||
52
assets/csspageweaver/plugins/previewPage/event.js
Normal file
52
assets/csspageweaver/plugins/previewPage/event.js
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
* @name Preview page
|
||||
* @author Julie Blanc <contact@julie-blanc.fr>
|
||||
* @see { @link https://gitlab.com/csspageweaver/plugins/previewPage }
|
||||
*/
|
||||
|
||||
export default function previewEvents(){
|
||||
const body = cssPageWeaver.ui.body
|
||||
|
||||
// set a "unique" filename based on title element, in case several books are opened
|
||||
const fileTitle = document.getElementsByTagName("title")[0].text;
|
||||
|
||||
const previewToggle = document.querySelector("#preview-toggle");
|
||||
const previewButton = document.querySelector("#button-preview");
|
||||
|
||||
// Check localStorage for user's preference and apply it
|
||||
const preference = localStorage.getItem('previewToggle' + fileTitle);
|
||||
if (preference === "preview") {
|
||||
body.classList.add('interface-preview');
|
||||
previewToggle.checked = true;
|
||||
} else {
|
||||
body.classList.remove('interface-preview');
|
||||
previewToggle.checked = false;
|
||||
}
|
||||
|
||||
function preview(){
|
||||
const isPreview = body.classList.contains('interface-preview');
|
||||
body.classList.toggle('interface-preview');
|
||||
previewToggle.checked = !isPreview;
|
||||
localStorage.setItem('previewToggle' + fileTitle, isPreview ? 'no-preview' : 'preview');
|
||||
|
||||
}
|
||||
// Toggle preview mode when the button is clicked
|
||||
previewButton.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
preview()
|
||||
});
|
||||
|
||||
// Add keydown listener based on configuration
|
||||
cssPageWeaver.features.previewPage.ui.shortcut.forEach( shortcut => {
|
||||
// if user do not have disable plugin
|
||||
if(shortcut.active){
|
||||
|
||||
// Get shortcut combinaison from config
|
||||
const keys = shortcut.keys
|
||||
|
||||
// CSS Page Weaver has a simple function to help you register your keyboard shortcut
|
||||
cssPageWeaver.helpers.addKeydownListener(keys, preview)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
39
assets/csspageweaver/plugins/previewPage/stylesheet.css
Normal file
39
assets/csspageweaver/plugins/previewPage/stylesheet.css
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/* PREVIEW MODE */
|
||||
|
||||
.interface-preview {
|
||||
background-color: var(--color-preview);
|
||||
--color-pageBox: #999;
|
||||
}
|
||||
|
||||
.interface-preview .pagedjs_page{
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.interface-preview .pagedjs_right_page .pagedjs_bleed,
|
||||
.interface-preview .pagedjs_left_page .pagedjs_bleed-top,
|
||||
.interface-preview .pagedjs_left_page .pagedjs_bleed-bottom,
|
||||
.interface-preview .pagedjs_left_page .pagedjs_bleed-left{
|
||||
background-color: var(--color-preview);
|
||||
z-index:999999;
|
||||
}
|
||||
|
||||
.interface-preview .pagedjs_marks-crop,
|
||||
.interface-preview .pagedjs_marks-crop{
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
|
||||
.interface-preview .pagedjs_pagebox {
|
||||
background: none;
|
||||
}
|
||||
|
||||
|
||||
.button-print{ display: none; }
|
||||
|
||||
.interface-preview{
|
||||
--color-marginBox: transparent;
|
||||
}
|
||||
|
||||
.interface-preview .grid-page{
|
||||
display: none;
|
||||
}
|
||||
31
assets/csspageweaver/plugins/previewPage/template.html
Normal file
31
assets/csspageweaver/plugins/previewPage/template.html
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<div id="buttons-preview" class="buttons-group align-right">
|
||||
|
||||
<input type="checkbox" id="preview-toggle" name="preview-toggle">
|
||||
<button id="button-preview" title="Preview">
|
||||
|
||||
<svg class="icon-preview" width="100%" height="100%" version="1.1" viewBox="0 0 32 32" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g>
|
||||
<polyline fill="none" points=" 649,137.999 675,137.999 675,155.999 661,155.999 " stroke="#FFFFFF" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2"></polyline>
|
||||
<polyline fill="none" points=" 653,155.999 649,155.999 649,141.999 " stroke="#FFFFFF" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2"></polyline>
|
||||
<polyline fill="none" points=" 661,156 653,162 653,156 " stroke="#FFFFFF" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2"></polyline>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M16,25c-4.265,0-8.301-1.807-11.367-5.088c-0.377-0.403-0.355-1.036,0.048-1.413c0.404-0.377,1.036-0.355,1.414,0.048 C8.778,21.419,12.295,23,16,23c4.763,0,9.149-2.605,11.84-7c-2.69-4.395-7.077-7-11.84-7c-4.938,0-9.472,2.801-12.13,7.493 c-0.272,0.481-0.884,0.651-1.363,0.377c-0.481-0.272-0.649-0.882-0.377-1.363C5.147,10.18,10.333,7,16,7 c5.668,0,10.853,3.18,13.87,8.507c0.173,0.306,0.173,0.68,0,0.985C26.853,21.819,21.668,25,16,25z"></path>
|
||||
</g>
|
||||
<g>
|
||||
<path d="M16,21c-2.757,0-5-2.243-5-5s2.243-5,5-5s5,2.243,5,5S18.757,21,16,21z M16,13c-1.654,0-3,1.346-3,3s1.346,3,3,3 s3-1.346,3-3S17.654,13,16,13z"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
</button>
|
||||
<button title="Print" id="button-print" onclick="window.print()" data-ready="false" data-text="Print">
|
||||
<svg class="reset-this icon-printer" width="100%" height="100%" viewBox="0 0 478 478" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<path d="M460.8,119.467L375.467,119.467L375.467,17.067C375.467,7.641 367.826,0 358.4,0L119.467,0C110.041,0 102.4,7.641 102.4,17.067L102.4,119.467L17.067,119.467C7.641,119.467 0,127.108 0,136.533L0,358.4C0,367.826 7.641,375.467 17.067,375.467L102.4,375.467L102.4,460.8C102.4,470.226 110.041,477.867 119.467,477.867L358.4,477.867C367.826,477.867 375.467,470.226 375.467,460.8L375.467,375.467L460.8,375.467C470.226,375.467 477.867,367.826 477.867,358.4L477.867,136.533C477.867,127.108 470.226,119.467 460.8,119.467ZM136.533,34.133L341.333,34.133L341.333,119.466L136.533,119.466L136.533,34.133ZM341.333,443.733L136.533,443.733L136.533,290.133L341.333,290.133L341.333,443.733ZM443.733,341.333L375.466,341.333L375.466,290.133L392.533,290.133C401.959,290.133 409.6,282.492 409.6,273.066C409.6,263.64 401.959,256 392.533,256L85.333,256C75.907,256 68.266,263.641 68.266,273.067C68.266,282.493 75.907,290.134 85.333,290.134L102.4,290.134L102.4,341.334L34.133,341.334L34.133,153.6L443.733,153.6L443.733,341.333Z" style="fill-rule:nonzero;"></path>
|
||||
<path d="M409.6,187.733L392.533,187.733C383.107,187.733 375.466,195.374 375.466,204.8C375.466,214.226 383.107,221.867 392.533,221.867L409.6,221.867C419.026,221.867 426.667,214.226 426.667,204.8C426.667,195.374 419.026,187.733 409.6,187.733Z" style="fill-rule:nonzero;"></path>
|
||||
<path d="M290.133,324.267L187.733,324.267C178.307,324.267 170.666,331.908 170.666,341.334C170.666,350.76 178.307,358.401 187.733,358.401L290.133,358.401C299.559,358.401 307.2,350.76 307.2,341.334C307.2,331.908 299.559,324.267 290.133,324.267Z" style="fill-rule:nonzero;"></path>
|
||||
<path d="M290.133,375.467L187.733,375.467C178.307,375.467 170.666,383.108 170.666,392.534C170.666,401.96 178.307,409.601 187.733,409.601L290.133,409.601C299.559,409.601 307.2,401.96 307.2,392.534C307.2,383.108 299.559,375.467 290.133,375.467Z" style="fill-rule:nonzero;"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
1
assets/csspageweaver/plugins/regexTypo/.gitignore
vendored
Normal file
1
assets/csspageweaver/plugins/regexTypo/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.DS_Store
|
||||
7
assets/csspageweaver/plugins/regexTypo/config.json
Normal file
7
assets/csspageweaver/plugins/regexTypo/config.json
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"name": "Regex Typo",
|
||||
"description": "Script for handling orthotypography.",
|
||||
"author": "Julie Blanc et Sarah Garcin",
|
||||
"repository": "https://gitlab.com/JulieBlanc/typesetting-tools",
|
||||
"hook": "regexTypo-hook.js"
|
||||
}
|
||||
24
assets/csspageweaver/plugins/regexTypo/regexTypo-hook.js
Normal file
24
assets/csspageweaver/plugins/regexTypo/regexTypo-hook.js
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* @name Regex Typo
|
||||
* @file Script for handling orthotypography.
|
||||
* @author Julie Blanc <contact@julie-blanc.fr> modified by Sarah Garcin
|
||||
* @see { @link https://gitlab.com/JulieBlanc/typesetting-tools }
|
||||
* @see { @link https://gitlab.com/csspageweaver/plugins/regexTypo/ }
|
||||
*/
|
||||
|
||||
import { Handler } from '/csspageweaver/lib/paged.esm.js';
|
||||
import { orthotypo, exposants, noHyphens } from '/csspageweaver/plugins/regexTypo/regexTypo.js';
|
||||
|
||||
export default class regextypoHook extends Handler {
|
||||
|
||||
constructor(chunker, polisher, caller) {
|
||||
super(chunker, polisher, caller)
|
||||
}
|
||||
|
||||
beforeParsed(content) {
|
||||
orthotypo(content);
|
||||
exposants(content);
|
||||
noHyphens(content);
|
||||
}
|
||||
|
||||
}
|
||||
312
assets/csspageweaver/plugins/regexTypo/regexTypo.js
Normal file
312
assets/csspageweaver/plugins/regexTypo/regexTypo.js
Normal file
|
|
@ -0,0 +1,312 @@
|
|||
export function orthotypo(content){
|
||||
var nodes = document.createTreeWalker(content, NodeFilter.SHOW_TEXT, null, null);
|
||||
|
||||
let array = [
|
||||
{
|
||||
// XIème = XIe
|
||||
reg: /(X|I|V)ème/g,
|
||||
repl: '$1e'
|
||||
},
|
||||
{
|
||||
// french open quotes
|
||||
reg: /\"([A-Za-zÀ-ÖØ-öø-ÿœŒ])/g,
|
||||
repl: '«$1'
|
||||
},
|
||||
{
|
||||
// french close quotes
|
||||
reg: /([A-Za-zÀ-ÖØ-öø-ÿœŒ])\"/g,
|
||||
repl: '$1»'
|
||||
},
|
||||
{
|
||||
// real apostrophe
|
||||
reg: /\'/g,
|
||||
repl: '’'
|
||||
},
|
||||
{
|
||||
// real suspension points
|
||||
reg: /\.+\.+\./g,
|
||||
repl: '\u2026'
|
||||
},
|
||||
{
|
||||
// delete all spaces before punctuation !?;:»›”)].,
|
||||
reg: /\s+([!?;:»›”)\]\.\,])/g,
|
||||
repl: '$1'
|
||||
},
|
||||
{
|
||||
// add narrow no break space before !?;:»›
|
||||
reg: /([!?;:»›])/g,
|
||||
repl: '\u202F$1'
|
||||
},
|
||||
{
|
||||
// delete all spaces after «‹“[(
|
||||
reg: /([«‹“\[(])\s+/g,
|
||||
repl: '$1'
|
||||
},
|
||||
{
|
||||
// add narrow no break space after «‹
|
||||
reg: /([«‹])/g,
|
||||
repl: '$1\u202F'
|
||||
},
|
||||
{
|
||||
// OPTION 1 : no break space after two letter words (if not follow by an other two letter word)
|
||||
// reg: /\s+([a-zØ-öø-ÿœ]{2})\s+([A-Za-zÀ-ÖØ-öø-ÿœŒ]{3,})/gi,
|
||||
// repl: ' $1\u00A0$2'
|
||||
|
||||
// OPTION 2: no break space after some two letter words
|
||||
reg: /\s(le|la|un|une|ce|ces|il|on|les|des|du|ils)\s+/g,
|
||||
repl: ' $1\u00A0'
|
||||
},
|
||||
{
|
||||
// if prev OPTION 2: no break space after successive two letter words
|
||||
reg: /\s+([a-zØ-öø-ÿœ]{2})\s+([A-Za-zÀ-ÖØ-öø-ÿœŒ]{2})\s+/g,
|
||||
repl: ' $1 $2\u00A0'
|
||||
},
|
||||
{
|
||||
// no break space after one letter words
|
||||
reg: /\s+([a-zà])\s+/gi,
|
||||
repl: ' $1\u00A0'
|
||||
},
|
||||
{
|
||||
// no break space after first word (2-5 letter) of the sentence
|
||||
reg: /\.\s([A-ZÀ-Ö])([A-Za-zÀ-ÖØ-öø-ÿœŒ]{1,5})\s+/g,
|
||||
repl: '. $1$2\u00A0'
|
||||
},
|
||||
{
|
||||
// no break space into names
|
||||
reg: /([A-ZÀ-ÖØŒ])([A-Za-zÀ-ÖØ-öø-ÿœŒ]+)\s+([A-ZÀ-ÖØŒ])([A-Za-zÀ-ÖØ-öø-ÿœŒ]+)/g,
|
||||
repl: '$1$2\u00A0$3$4'
|
||||
},
|
||||
{
|
||||
// no break space before Caps + .
|
||||
reg: /\s([A-ZÀ-ÖØŒ])\./g,
|
||||
repl: '\u00A0$1. '
|
||||
},
|
||||
{
|
||||
// no break space before 'siècles'
|
||||
reg: /(X|I|V)(er|e)\s+siècle/g,
|
||||
repl: '$1$2\u00A0siècles'
|
||||
},
|
||||
|
||||
]
|
||||
|
||||
var node;
|
||||
|
||||
while (node = nodes.nextNode()) {
|
||||
// search if text is into a <code> element
|
||||
if(!node.parentElement){
|
||||
return
|
||||
}
|
||||
var code = node.parentElement.closest("code");
|
||||
// if not, apply replacements
|
||||
if(code == null){
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
node.textContent = node.textContent.replace(array[i].reg, array[i].repl);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function spaces( content ){
|
||||
let all = content.querySelectorAll('p, span');
|
||||
all.forEach(element => {
|
||||
element.innerHTML = spacesRegex(element.innerHTML)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function spacesRegex(elem){
|
||||
let array = [
|
||||
{
|
||||
// french open quotes
|
||||
reg: /\"([A-Za-zÀ-ÖØ-öø-ÿœŒ])/g,
|
||||
repl: '«$1'
|
||||
},
|
||||
{
|
||||
// french close quotes
|
||||
reg: /([A-Za-zÀ-ÖØ-öø-ÿœŒ])\"/g,
|
||||
repl: '$1»'
|
||||
},
|
||||
{
|
||||
// real apostrophe
|
||||
reg: /\'/g,
|
||||
repl: '’'
|
||||
},
|
||||
{
|
||||
// real suspension points
|
||||
reg: /\.+\.+\./g,
|
||||
repl: '\u2026'
|
||||
},
|
||||
{
|
||||
// delete all spaces before punctuation !?;:»›”)].,
|
||||
reg: /\s+([!?;:»›”)\]\.\,])/g,
|
||||
repl: '$1'
|
||||
},
|
||||
{
|
||||
// add narrow no break space before !?;:»›
|
||||
reg: /([!?;:»›])/g,
|
||||
repl: '\u202F$1'
|
||||
},
|
||||
{
|
||||
// delete all spaces after «‹“[(
|
||||
reg: /([«‹“\[(])\s+/g,
|
||||
repl: '$1'
|
||||
},
|
||||
{
|
||||
// add narrow no break space after «‹
|
||||
reg: /([«‹])/g,
|
||||
repl: '$1\u202F'
|
||||
},
|
||||
{
|
||||
// OPTION 1 : no break space after two letter words (if not follow by an other two letter word)
|
||||
// reg: /\s+([a-zØ-öø-ÿœ]{2})\s+([A-Za-zÀ-ÖØ-öø-ÿœŒ]{3,})/gi,
|
||||
// repl: ' $1\u00A0$2'
|
||||
|
||||
// OPTION 2: no break space after some two letter words
|
||||
reg: /\s(le|la|un|une|ce|ces|il|on|les|des|du|ils)\s+/g,
|
||||
repl: ' $1\u00A0'
|
||||
},
|
||||
{
|
||||
// if prev OPTION 2: no break space after successive two letter words
|
||||
reg: /\s+([a-zØ-öø-ÿœ]{2})\s+([A-Za-zÀ-ÖØ-öø-ÿœŒ]{2})\s+/g,
|
||||
repl: ' $1 $2\u00A0'
|
||||
},
|
||||
{
|
||||
// no break space after one letter words
|
||||
reg: /\s+([a-zà])\s+/gi,
|
||||
repl: ' $1\u00A0'
|
||||
},
|
||||
{
|
||||
// no break space after first word (2-5 letter) of the sentence
|
||||
reg: /\.\s([A-ZÀ-Ö])([A-Za-zÀ-ÖØ-öø-ÿœŒ]{1,5})\s+/g,
|
||||
repl: '. $1$2\u00A0'
|
||||
},
|
||||
{
|
||||
// no break space into names
|
||||
reg: /([A-ZÀ-ÖØŒ])([A-Za-zÀ-ÖØ-öø-ÿœŒ]+)\s+([A-ZÀ-ÖØŒ])([A-Za-zÀ-ÖØ-öø-ÿœŒ]+)/g,
|
||||
repl: '$1$2\u00A0$3$4'
|
||||
},
|
||||
{
|
||||
// no break space before Caps + .
|
||||
reg: /\s([A-ZÀ-ÖØŒ])\./g,
|
||||
repl: '\u00A0$1. '
|
||||
},
|
||||
{
|
||||
// no break space before 'siècles'
|
||||
reg: /(X|I|V)(er|e)\s+siècle/g,
|
||||
repl: '$1$2\u00A0siècles'
|
||||
},
|
||||
// {
|
||||
// // no break space after figures table page chapitre ect. + number
|
||||
// reg: /(figures?|tables?|planches?|chapitres?|pages?|parties?|sections?|volumes?|vol\.)\s+(\d|I|X|V)/g,
|
||||
// repl: '$1\u00A0$2'
|
||||
// },
|
||||
// {
|
||||
// // p. and pp. in blibliography
|
||||
// reg: /(\spp?\.)\s?(\d)/g,
|
||||
// repl: '$1\u00A0$2'
|
||||
// }
|
||||
]
|
||||
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
elem = elem.replace(array[i].reg, array[i].repl);
|
||||
console.log(elem);
|
||||
}
|
||||
return elem;
|
||||
|
||||
}
|
||||
|
||||
export function noHyphens( content ){
|
||||
let all = content.querySelectorAll('p');
|
||||
// all french caracteres: [A-Za-zÀ-ÖØ-öø-ÿœŒ]
|
||||
|
||||
all.forEach(element => {
|
||||
element.innerHTML = noHyphensRegex(element.innerHTML)
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
function noHyphensRegex(elem){
|
||||
let array = [
|
||||
{
|
||||
// no break space into names
|
||||
reg: /([A-ZÀ-ÖØŒ])([A-Za-zÀ-ÖØ-öø-ÿœŒ]+)\s+([A-ZÀ-ÖØŒ])([A-Za-zÀ-ÖØ-öø-ÿœŒ]+)/g,
|
||||
repl: '$1$2\u00A0$3$4'
|
||||
},
|
||||
{
|
||||
// no break space before Caps + .
|
||||
reg: /\s([A-ZÀ-ÖØŒ])\./g,
|
||||
repl: '\u00A0$1. '
|
||||
},
|
||||
{
|
||||
// no break space before 'siècles'
|
||||
reg: /(X|I|V)(er|e)\s+siècle/g,
|
||||
repl: '$1$2\u00A0siècles'
|
||||
},
|
||||
{
|
||||
// règles le problème de 1ep qui met le e en exposant
|
||||
reg: '1<sup>e</sup>p',
|
||||
repl: '1ep'
|
||||
}
|
||||
]
|
||||
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
elem = elem.replace(array[i].reg, array[i].repl);
|
||||
}
|
||||
return elem;
|
||||
|
||||
}
|
||||
|
||||
|
||||
export function exposants(content){
|
||||
let all = content.querySelectorAll('p, span');
|
||||
|
||||
all.forEach(element => {
|
||||
element.innerHTML = exposantsRegex(element.innerHTML)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function exposantsRegex(elem){
|
||||
|
||||
let array = [
|
||||
{
|
||||
// numéros
|
||||
reg: /\sno\.?\s?(\d+)/g,
|
||||
repl: ' n<sup>o</sup> $1'
|
||||
},
|
||||
{
|
||||
// siècles + small caps
|
||||
reg: /(XXI|XX|XIX|XVIII|XVII|XVI|XV|xxi|xx|xix|xviii|xvii|xvi|xv)(e|er)/g,
|
||||
repl: '<span style="text-transform: lowercase; font-variant: small-caps;">$1</span><sup>$2</sup>'
|
||||
},
|
||||
{
|
||||
// exposant e après chiffres
|
||||
reg: /(\d+)(er|e)[\s\\u00A0]/g,
|
||||
repl: '$1<sup>$2</sup>'
|
||||
},
|
||||
{
|
||||
// exposant e après chiffres
|
||||
reg: '22e',
|
||||
repl: '22<sup>e</sup>'
|
||||
},
|
||||
{
|
||||
// exposant e après chiffres
|
||||
reg: '4e éd.',
|
||||
repl: '4<sup>e</sup> éd.'
|
||||
},
|
||||
{
|
||||
// exposant e après chiffres
|
||||
reg: 'IVe',
|
||||
repl: 'IV<sup>e</sup>'
|
||||
},
|
||||
]
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
elem = elem.replace(array[i].reg, array[i].repl);
|
||||
}
|
||||
return elem;
|
||||
|
||||
}
|
||||
1
assets/csspageweaver/plugins/reloadInPlace/.gitignore
vendored
Normal file
1
assets/csspageweaver/plugins/reloadInPlace/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.DS_Store
|
||||
17
assets/csspageweaver/plugins/reloadInPlace/Readme.md
Normal file
17
assets/csspageweaver/plugins/reloadInPlace/Readme.md
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# Reload In Place
|
||||
|
||||
## Configuration
|
||||
|
||||
In `manifest.json`
|
||||
|
||||
```json
|
||||
"plugins":{
|
||||
"inlineNotes"
|
||||
},
|
||||
"pluginsParameters":{
|
||||
"reloadInPlace": {
|
||||
"blur": false,
|
||||
"behavior": "instant"
|
||||
}
|
||||
},
|
||||
```
|
||||
9
assets/csspageweaver/plugins/reloadInPlace/config.json
Normal file
9
assets/csspageweaver/plugins/reloadInPlace/config.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"name": "Reload In Place",
|
||||
"description": "A simple script to add your CSS Page Weaver project. On reload, it will make the web browser scroll to the place it was before reload. ",
|
||||
"author": ["Nicolas Taffin", "Sameh Chafik"],
|
||||
"licence": "MIT",
|
||||
"version": 2,
|
||||
"repository": "https://gitlab.com/nicolastaf/pagedjs-reload-in-place",
|
||||
"hook": "reloadInPlace.js"
|
||||
}
|
||||
174
assets/csspageweaver/plugins/reloadInPlace/reloadInPlace.js
Normal file
174
assets/csspageweaver/plugins/reloadInPlace/reloadInPlace.js
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
/**
|
||||
* @name Reload-in-place v2.0
|
||||
* @desc A simple script to add to your pagedjs project. On reload, it will make the web browser scroll to the place it was before reload.
|
||||
* Useful when styling or proof correcting your book. Multi docs compatible and doesn't wait for complete compilation to go.
|
||||
* @author Nicolas Taffin
|
||||
* @author Sameh Chafik
|
||||
* @author (adapted by) Benjamin G. <ecrire@bnjm.eu>
|
||||
* @license MIT
|
||||
* @see { @link https://gitlab.com/csspageweaver/plugins/reloadInPlace }
|
||||
*/
|
||||
|
||||
|
||||
import { Handler } from '/csspageweaver/lib/paged.esm.js';
|
||||
|
||||
|
||||
export default class reloadInPlace extends Handler {
|
||||
constructor(chunker, polisher, caller) {
|
||||
super(chunker, polisher, caller);
|
||||
this.parameters = cssPageWeaver.features.reloadInPlace.parameters || {}
|
||||
this.isScrollBlured = this.parameters.blur || true;
|
||||
this.scrollBehavior = this.parameters.scrollBehavior || 'instant';
|
||||
|
||||
// set a "unique" filename based on title element, in case several books are opened
|
||||
this.fileTitle = document.getElementsByTagName("title")[0].text.replace(/ /g, "");
|
||||
}
|
||||
|
||||
beforeParsed() {
|
||||
// separate human / machine scroll
|
||||
this.parameters.machineScroll = false;
|
||||
|
||||
// check pagedJS ended compilation
|
||||
this.parameters.cssPageWeaverEnd = false;
|
||||
|
||||
// Make it blur if needed
|
||||
this.isBlur()
|
||||
}
|
||||
|
||||
afterParsed() {
|
||||
this.moveFast();
|
||||
}
|
||||
|
||||
afterRendered(pages) {
|
||||
|
||||
this.parameters.cssPageWeaverEnd = true;
|
||||
|
||||
|
||||
|
||||
// slow down a bit save position pace
|
||||
var slowSave = this.debounce(() => {
|
||||
if(!this.parameters.machineScroll) {
|
||||
this.saveAmountScrolled();
|
||||
}
|
||||
}, 100); // save frequency
|
||||
|
||||
setTimeout(function(){
|
||||
window.addEventListener('scroll', slowSave);
|
||||
}, 1000); // wait a bit before starting position save
|
||||
|
||||
}
|
||||
|
||||
getDocHeight() {
|
||||
var D = document;
|
||||
return Math.max(
|
||||
D.body.scrollHeight, D.documentElement.scrollHeight,
|
||||
D.body.offsetHeight, D.documentElement.offsetHeight,
|
||||
D.body.clientHeight, D.documentElement.clientHeight
|
||||
)
|
||||
}
|
||||
|
||||
saveAmountScrolled(){
|
||||
var scrollArray = [];
|
||||
var scrollTop = window.pageYOffset || (document.documentElement || document.body.parentNode || document.body).scrollTop
|
||||
if (!this.parameters.machineScroll) {
|
||||
var scrollLeft = window.pageXOffset || (document.documentElement || document.body.parentNode || document.body).scrollLeft
|
||||
scrollArray.push({ X: Math.round(scrollLeft), Y: Math.round(scrollTop) });
|
||||
//console.log("Saved ", scrollArray);
|
||||
localStorage['reloadInPlace-' + this.fileTitle] = JSON.stringify(scrollArray);
|
||||
}
|
||||
}
|
||||
|
||||
isBlur(){
|
||||
// Apply a blur effect if scroll blurring is enabled
|
||||
if (this.isScrollBlured) {
|
||||
var styleEl = document.createElement('style');
|
||||
styleEl.setAttribute("data-reload-in-place", true)
|
||||
document.head.appendChild(styleEl);
|
||||
this.styleSheet = styleEl.sheet;
|
||||
this.styleSheet.insertRule('.pagedjs_pages { filter: blur(3px); }', 0);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
retrievePosition(){
|
||||
// Retrieve saved scroll data from localStorage
|
||||
var savedData = localStorage.getItem('reloadInPlace-' + this.fileTitle);
|
||||
|
||||
if (savedData) {
|
||||
// Parse the saved data to get the scroll positions
|
||||
var scrollArray = JSON.parse(savedData);
|
||||
this.scrollTop = scrollArray[0].Y;
|
||||
this.scrollLeft = scrollArray[0].X;
|
||||
} else {
|
||||
// Default scroll positions if no saved data is found
|
||||
this.scrollTop = 0;
|
||||
this.scrollLeft = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adjusts the scroll position of the window based on saved data.
|
||||
* This function handles scrolling behavior when the document height changes,
|
||||
* ensuring the view returns to a previously saved scroll position or the bottom of the document.
|
||||
*
|
||||
* @param {Object} _ - ReloadInPlace scope
|
||||
*/
|
||||
moveFast() {
|
||||
// Set the machine scroll flag to true
|
||||
this.parameters.machineScroll = true;
|
||||
|
||||
this.retrievePosition()
|
||||
|
||||
// Get the window height
|
||||
var winheight = window.innerHeight || (document.documentElement || document.body).clientHeight;
|
||||
|
||||
let _ = this
|
||||
|
||||
// Set up an interval to adjust the scroll position
|
||||
_.currentInterval = setInterval(() => {
|
||||
// Get the current document height
|
||||
_.docheight = _.getDocHeight();
|
||||
|
||||
// Check if the saved scroll position is beyond the current document height
|
||||
if ( _.scrollTop > 0 && _.scrollTop > _.docheight - winheight && !_.parameters.cssPageWeaverEnd) {
|
||||
// Scroll to the bottom of the document
|
||||
window.scrollTo(_.scrollLeft, _.docheight, _.scrollBehavior);
|
||||
} else {
|
||||
// Scroll to the saved position
|
||||
window.scrollTo(_.scrollLeft, _.scrollTop, _.scrollBehavior);
|
||||
|
||||
// Clear interval
|
||||
clearInterval(_.currentInterval);
|
||||
|
||||
// set a timeout to finalize the scroll position
|
||||
setTimeout(function () {
|
||||
window.scrollTo(_.scrollLeft, _.scrollTop, _.scrollBehavior);
|
||||
|
||||
// Reset the machine scroll flag
|
||||
_.parameters.machineScroll = false;
|
||||
|
||||
// Remove the blur effect if it was applied
|
||||
if (_.isScrollBlured) {
|
||||
_.styleSheet.deleteRule(0);
|
||||
}
|
||||
}, 50); // Delay to start
|
||||
}
|
||||
}, 50); // Refresh frequency
|
||||
}
|
||||
|
||||
debounce(func, wait, immediate) {
|
||||
var timeout;
|
||||
return function() {
|
||||
var context = this, args = arguments;
|
||||
var later = function() {
|
||||
timeout = null;
|
||||
if (!immediate) func.apply(context, args);
|
||||
};
|
||||
var callNow = immediate && !timeout;
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(later, wait);
|
||||
if (callNow) func.apply(context, args);
|
||||
};
|
||||
};
|
||||
}
|
||||
1
assets/csspageweaver/plugins/spread/.gitignore
vendored
Normal file
1
assets/csspageweaver/plugins/spread/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.DS_Store
|
||||
15
assets/csspageweaver/plugins/spread/config.json
Normal file
15
assets/csspageweaver/plugins/spread/config.json
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "Spread",
|
||||
"description": "",
|
||||
"version": "1.0",
|
||||
"ui": {
|
||||
"title": "Screen view",
|
||||
"description": "This Toogle single page or board view",
|
||||
"toggle": false,
|
||||
"template": "spread.html"
|
||||
},
|
||||
"stylesheet": "spread.css",
|
||||
"hook": "spread-hook.js",
|
||||
"script": "spread-ui.js"
|
||||
|
||||
}
|
||||
25
assets/csspageweaver/plugins/spread/spread-hook.js
Normal file
25
assets/csspageweaver/plugins/spread/spread-hook.js
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import { Handler } from '/csspageweaver/lib/paged.esm.js';
|
||||
|
||||
export default class nrbPages extends Handler {
|
||||
|
||||
constructor(chunker, polisher, caller) {
|
||||
super(chunker, polisher, caller);
|
||||
}
|
||||
|
||||
afterPageLayout(pageElement, page, breakToken) {
|
||||
|
||||
let nbrSpan = document.querySelector("#nrb-pages");
|
||||
let pagesDocument = document.querySelectorAll(".pagedjs_page");
|
||||
if (nbrSpan) {
|
||||
nbrSpan.innerHTML = pagesDocument.length;
|
||||
}
|
||||
}
|
||||
|
||||
afterRendered(pages){
|
||||
let nbrSpan = document.querySelector("#nrb-pages");
|
||||
if (nbrSpan) {
|
||||
nbrSpan.innerHTML = pages.length;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
38
assets/csspageweaver/plugins/spread/spread-ui.js
Normal file
38
assets/csspageweaver/plugins/spread/spread-ui.js
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
* @name Spread
|
||||
* @author Julie Blanc <contact@julie-blanc.fr>
|
||||
* @see { @link https://gitlab.com/csspageweaver/plugins/ }
|
||||
*/
|
||||
|
||||
export default function spreadEvents(){
|
||||
|
||||
const body = cssPageWeaver.ui.body
|
||||
const fileTitle = cssPageWeaver.docTitle;
|
||||
const toggleInput = document.querySelector('#spread-toggle-button')
|
||||
|
||||
/* SPREAD ----------------------------------------------------------------------------------------------------
|
||||
----------------------------------------------------------------------------------------------------------------*/
|
||||
/* Toggle spread or recto-verso */
|
||||
let preference = localStorage.getItem('spreadToggle' + fileTitle);
|
||||
|
||||
|
||||
if(preference == "spread"){
|
||||
body.classList.remove('no-spread');
|
||||
toggleInput.checked = true
|
||||
}else if(preference == "no-spread"){
|
||||
body.classList.add('no-spread');
|
||||
toggleInput.checked = false
|
||||
}
|
||||
document.querySelector("#label-spread-toggle").addEventListener("click", (e) => {
|
||||
//e.preventDefault()
|
||||
|
||||
if(body.classList.contains("no-spread")){
|
||||
body.classList.remove('no-spread');
|
||||
localStorage.setItem('spreadToggle' + fileTitle, 'spread');
|
||||
}else{
|
||||
body.classList.add('no-spread');
|
||||
localStorage.setItem('spreadToggle' + fileTitle, 'no-spread');
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
33
assets/csspageweaver/plugins/spread/spread.css
Normal file
33
assets/csspageweaver/plugins/spread/spread.css
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
|
||||
@media screen, pagedjs-ignore {
|
||||
.no-spread .pagedjs_pages {
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.no-spread .pagedjs_first_page {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.no-spread .pagedjs_page {
|
||||
margin: 0 auto;
|
||||
margin-top: 10mm;
|
||||
}
|
||||
|
||||
.no-spread .pagedjs_left_page{
|
||||
width: calc(var(--pagedjs-bleed-left) + var(--pagedjs-pagebox-width) + var(--pagedjs-bleed-left))!important;
|
||||
}
|
||||
|
||||
.no-spread .pagedjs_left_page .pagedjs_bleed-right .pagedjs_marks-crop{
|
||||
border-color: var(--pagedjs-crop-color);
|
||||
}
|
||||
|
||||
.no-spread .pagedjs_left_page .pagedjs_bleed-right .pagedjs_marks-middle{
|
||||
width: var(--pagedjs-cross-size)!important;
|
||||
}
|
||||
|
||||
.no-spread .pagedjs_right_page{
|
||||
left: 0;
|
||||
}
|
||||
|
||||
}
|
||||
61
assets/csspageweaver/plugins/spread/spread.html
Normal file
61
assets/csspageweaver/plugins/spread/spread.html
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
<input type="checkbox" id="spread-toggle-button" name="spread-toggle">
|
||||
<div class="buttons-group">
|
||||
|
||||
<label for="spread-toggle-button" id="label-spread-toggle">
|
||||
<span id="button-spread" class="button">
|
||||
<svg width="100%" height="100%" viewBox="0 0 480 480" version="1.1" xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/"
|
||||
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g transform="matrix(1,0,0,1,-4,-1084)">
|
||||
<g id="spread-bis" serif:id="spread bis" transform="matrix(0.997921,0,0,1.00209,2.00416,1083)">
|
||||
<rect x="2" y="1" width="481" height="479" style="fill:none;" />
|
||||
<g transform="matrix(0.88709,0,0,0.842432,44.9417,123.556)">
|
||||
<path
|
||||
d="M249.88,336.193L249.88,282.887C249.88,280.925 251.397,279.334 253.269,279.334L275.731,279.334C277.603,279.334 279.12,280.925 279.12,282.887L279.12,336.193L463.88,336.193L463.88,20.807L396.102,20.807C394.23,20.807 392.713,19.216 392.713,17.253L392.713,-5.253C392.713,-7.216 394.23,-8.807 396.102,-8.807L478,-8.807C485.798,-8.807 492.12,-2.178 492.12,6L492.12,351C492.12,359.178 485.798,365.807 478,365.807L265,365.807C264.833,365.807 264.666,365.804 264.501,365.798L264.491,365.798C264.328,365.804 264.164,365.807 264,365.807L51,365.807C43.202,365.807 36.88,359.178 36.88,351L36.88,282.887C36.88,280.925 38.397,279.334 40.269,279.334L61.731,279.334C63.603,279.334 65.12,280.925 65.12,282.887L65.12,336.193L247.905,336.193L249.88,336.193Z" />
|
||||
</g>
|
||||
<g transform="matrix(1.00208,0,0,0.997917,8.0125,46.7815)">
|
||||
<g transform="matrix(0.885246,0,0,0.844191,-38.1475,9.93485)">
|
||||
<path
|
||||
d="M278.12,6L278.12,351C278.12,359.178 271.798,365.807 264,365.807L51,365.807C43.202,365.807 36.88,359.178 36.88,351L36.88,6C36.88,-2.178 43.202,-8.807 51,-8.807L264,-8.807C271.798,-8.807 278.12,-2.178 278.12,6ZM65.12,336.193L249.88,336.193L249.88,20.807L67.095,20.807L65.12,20.807L65.12,330.717L65.12,336.193Z" />
|
||||
</g>
|
||||
<g transform="matrix(0.885246,0,0,0.844191,151.295,9.93485)">
|
||||
<path
|
||||
d="M278.12,6L278.12,351C278.12,359.178 271.798,365.807 264,365.807L51,365.807C43.202,365.807 36.88,359.178 36.88,351L36.88,6C36.88,-2.178 43.202,-8.807 51,-8.807L264,-8.807C271.798,-8.807 278.12,-2.178 278.12,6ZM249.88,336.193L249.88,20.807L67.095,20.807L65.12,20.807L65.12,336.193L247.905,336.193L249.88,336.193Z" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</span>
|
||||
<span id="button-recto" class="button">
|
||||
<svg width="100%" height="100%" viewBox="0 0 480 480" version="1.1" xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/"
|
||||
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g transform="matrix(1,0,0,1,-557,-1103)">
|
||||
<g id="recto-verso-bis" serif:id="recto-verso bis"
|
||||
transform="matrix(0.997921,0,0,1.00209,555.004,1102)">
|
||||
<rect x="2" y="1" width="481" height="479" style="fill:none;" />
|
||||
<g transform="matrix(0.88709,0,0,0.842432,184.453,157.485)">
|
||||
<path
|
||||
d="M249.88,336.193L249.88,20.807L183.231,20.807C181.36,20.807 179.843,19.216 179.843,17.253L179.843,-5.253C179.843,-7.216 181.36,-8.807 183.231,-8.807L264,-8.807C271.798,-8.807 278.12,-2.178 278.12,6L278.12,351C278.12,359.178 271.798,365.807 264,365.807L51,365.807C43.202,365.807 36.88,359.178 36.88,351L36.88,281.703C36.88,279.74 38.397,278.149 40.269,278.149L61.731,278.149C63.603,278.149 65.12,279.74 65.12,281.703L65.12,336.193L247.905,336.193L249.88,336.193Z" />
|
||||
</g>
|
||||
<g transform="matrix(0.88709,0,0,0.842432,103.284,89.6269)">
|
||||
<path
|
||||
d="M249.88,336.193L249.88,20.807L182.102,20.807C180.23,20.807 178.713,19.216 178.713,17.253L178.713,-5.253C178.713,-7.216 180.23,-8.807 182.102,-8.807L264,-8.807C271.798,-8.807 278.12,-2.178 278.12,6L278.12,351C278.12,359.178 271.798,365.807 264,365.807L51,365.807C43.202,365.807 36.88,359.178 36.88,351L36.88,282.887C36.88,280.925 38.397,279.334 40.269,279.334L61.731,279.334C63.603,279.334 65.12,280.925 65.12,282.887L65.12,336.193L247.905,336.193L249.88,336.193Z" />
|
||||
</g>
|
||||
<g transform="matrix(0.88709,0,0,0.842432,21.1135,22.7665)">
|
||||
<path
|
||||
d="M278.12,6L278.12,351C278.12,359.178 271.798,365.807 264,365.807L51,365.807C43.202,365.807 36.88,359.178 36.88,351L36.88,6C36.88,-2.178 43.202,-8.807 51,-8.807L264,-8.807C271.798,-8.807 278.12,-2.178 278.12,6ZM249.88,336.193L249.88,20.807C228.051,20.807 106.85,20.807 65.12,20.807L65.12,336.193L247.905,336.193L249.88,336.193Z" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
</span>
|
||||
|
||||
</label>
|
||||
|
||||
<p class="force-right">
|
||||
<span id="nrb-pages" >xx</span> pages
|
||||
</p>
|
||||
</div>
|
||||
1
assets/csspageweaver/plugins/tableOfContent/.gitignore
vendored
Normal file
1
assets/csspageweaver/plugins/tableOfContent/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.DS_Store
|
||||
90
assets/csspageweaver/plugins/tableOfContent/README.md
Executable file
90
assets/csspageweaver/plugins/tableOfContent/README.md
Executable file
|
|
@ -0,0 +1,90 @@
|
|||
---
|
||||
name: tableOfContent
|
||||
tags: recommended, stable
|
||||
description: A script to generate a table of content.
|
||||
---
|
||||
|
||||
# Table of content
|
||||
|
||||
A script to generate a table of content.
|
||||
|
||||
See pagedjs.org post: [Build a Table of Contents from your HTML](https://pagedjs.org/post/toc/)
|
||||
|
||||
**tags**: recommended, stable
|
||||
|
||||
## Parameters
|
||||
|
||||
The plugin contain also a minimal stylesheet to add the corresponding page numbers with paged.js and add some style to the toc list.
|
||||
|
||||
In `manifest.json`, you can modify/add some parameters:
|
||||
|
||||
```json
|
||||
"plugins":{
|
||||
"tableOfContent"
|
||||
},
|
||||
"pluginsParameters":{
|
||||
"tableOfContent": {
|
||||
"tocContainer": "#toc_container",
|
||||
"tocTitles": ["h1", "h2"]
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
- `tocElement` → define the id element where the toc list will be create (by default: `#toc`)
|
||||
- `titleElements` → array of the title element you want in the toc list. You can add as many as you want and the elements can be classes like `.title-1` or `.my-content h1:not(.unlisted)`. (by default: `["h1", "h2"]`)
|
||||
- `beforePageNumber` (optional) → if you want to add some text before the page number ("page ", "p. ", ...)
|
||||
- `position` → put the page number before or after the toc element, create `::before` or `::after` pseudo-element (by default: `after`)
|
||||
|
||||
|
||||
## Stylesheet
|
||||
|
||||
This plugin have a minimal stylesheet
|
||||
|
||||
```CSS
|
||||
#list-toc-generated{
|
||||
--before-page: "";
|
||||
}
|
||||
```
|
||||
|
||||
`--before-page` refers to the text before the page number ("page ", "p. ", ...), you can change it directly here or in the config.json
|
||||
|
||||
|
||||
If the page number is positionned after the toc element (`"position": "after"` in config.json), this style apply:
|
||||
|
||||
```CSS
|
||||
.toc-element a.toc-page-after::after{
|
||||
content: var(--before-page) target-counter(attr(href), page); /* This line create the page number */
|
||||
float: right; /* put number at the right of the page */
|
||||
}
|
||||
```
|
||||
|
||||
If the page number is positionned before the toc element (`"position": "before"` in config.json), this style apply:
|
||||
|
||||
```CSS
|
||||
.toc-element a.toc-page-before::before{
|
||||
content: var(--before-page) target-counter(attr(href), page);
|
||||
margin-right: 1ch; /* space after number */
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
## How to install
|
||||
|
||||
### Download
|
||||
|
||||
1. Download the ZIP archive via Code > Download ZIP.
|
||||
2. Unzip the archive.
|
||||
3. Rename the extracted folder by removing the branch name suffix: `tableOfContent-main` → `tableOfContent`
|
||||
4. Move the folder into the `csspageweaver/plugins/` directory.
|
||||
5. Add the required parameters to `manifest.json` (see above).
|
||||
|
||||
|
||||
### Git clone
|
||||
|
||||
1. Use git clone
|
||||
2. Move the folder into the `csspageweaver/plugins/` directory.
|
||||
3. Add the required parameters to `manifest.json` (see above).
|
||||
|
||||
|
||||
9
assets/csspageweaver/plugins/tableOfContent/config.json
Normal file
9
assets/csspageweaver/plugins/tableOfContent/config.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"name": "Table of content",
|
||||
"description": "A script to generate a table of content",
|
||||
"author": ["Julie Blanc", "Julien Taquet"],
|
||||
"licence": "MIT",
|
||||
"version": "1.0",
|
||||
"hook": "tableOfContent.js",
|
||||
"stylesheet": "tableOfContent.css"
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
#list-toc-generated{
|
||||
--before-page: "";
|
||||
}
|
||||
|
||||
.toc-element a.toc-page-after::after{
|
||||
content: var(--before-page) target-counter(attr(href), page);
|
||||
float: right; /* put number at the right of the page */
|
||||
}
|
||||
|
||||
.toc-element a.toc-page-before::before{
|
||||
content: var(--before-page) target-counter(attr(href), page);
|
||||
margin-right: 1ch; /* space after number */
|
||||
}
|
||||
121
assets/csspageweaver/plugins/tableOfContent/tableOfContent.js
Normal file
121
assets/csspageweaver/plugins/tableOfContent/tableOfContent.js
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
/**
|
||||
* @name Table of content
|
||||
* @author Julie Blanc <contact@julie-blanc.fr>
|
||||
* @see { @link https://gitlab.com/csspageweaver/plugins/table_of_content/ }
|
||||
*/
|
||||
|
||||
import { Handler } from '/csspageweaver/lib/paged.esm.js';
|
||||
|
||||
export default class tableOfContent extends Handler {
|
||||
|
||||
constructor(chunker, polisher, caller) {
|
||||
super(chunker, polisher, caller);
|
||||
this.tocContainer = cssPageWeaver.features.tableOfContent.parameters?.tocContainer || "#toc_container";
|
||||
this.tocTitles = cssPageWeaver.features.tableOfContent.parameters?.tocTitles || ["h1", "h2"];
|
||||
this.beforePageNumber = cssPageWeaver.features.tableOfContent.parameters?.beforePageNumber;
|
||||
this.position = cssPageWeaver.features.tableOfContent.parameters?.position;
|
||||
}
|
||||
|
||||
beforeParsed(content) {
|
||||
createToc({
|
||||
content: content,
|
||||
container: this.tocContainer,
|
||||
titleElements: this.tocTitles,
|
||||
position: this.position
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function createToc(config) {
|
||||
|
||||
const content = config.content;
|
||||
const tocElement = config.container;
|
||||
const titleElements = config.titleElements;
|
||||
|
||||
let tocElementDiv = content.querySelector(tocElement)
|
||||
if(!tocElementDiv) return console.warn('couldn’t start the toc')
|
||||
tocElementDiv.innerHTML = ''
|
||||
let tocUl = document.createElement('ul')
|
||||
tocUl.id = 'list-toc-generated'
|
||||
|
||||
|
||||
if(config.before){
|
||||
tocUl.style.setProperty('--before-page', '"' + config.before + '"');
|
||||
}
|
||||
|
||||
|
||||
tocElementDiv.appendChild(tocUl)
|
||||
|
||||
// add class to all title elements
|
||||
let tocElementNbr = 0
|
||||
for (var i = 0; i < titleElements.length; i++) {
|
||||
let titleHierarchy = i + 1
|
||||
let titleElement = content.querySelectorAll(titleElements[i])
|
||||
|
||||
titleElement.forEach(function (element) {
|
||||
// check if shouldbe shown
|
||||
if (
|
||||
!element.classList.contains('toc-ignore') ||
|
||||
!element.classList.contains('toc-ignore')
|
||||
) {
|
||||
// add classes to the element
|
||||
element.classList.add('title-element')
|
||||
element.setAttribute('data-title-level', titleHierarchy)
|
||||
|
||||
// add an id if doesn't exist
|
||||
tocElementNbr++
|
||||
|
||||
if (element.id == '') {
|
||||
element.id = 'title-element-' + tocElementNbr
|
||||
}
|
||||
let newIdElement = element.id
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// create toc list
|
||||
let tocElements = content.querySelectorAll('.title-element')
|
||||
|
||||
for (var i = 0; i < tocElements.length; i++) {
|
||||
let tocElement = tocElements[i]
|
||||
|
||||
let tocNewLi = document.createElement('li')
|
||||
|
||||
// Add class for the hierarcy of toc
|
||||
tocNewLi.classList.add('toc-element')
|
||||
tocNewLi.classList.add('toc-element-level-' + tocElement.dataset.titleLevel)
|
||||
|
||||
let classes = [
|
||||
...(tocElement.className ? tocElement.className.split(' ') : []),
|
||||
...(tocElement.closest('section')?.className ? tocElement.closest('section')?.className.split(' ') : []),
|
||||
];
|
||||
|
||||
classes.forEach((meta) => {
|
||||
if (!meta || meta === 'title-element') return;
|
||||
tocNewLi.classList.add(`toc-${meta}`);
|
||||
});
|
||||
|
||||
//get the exisiting class
|
||||
// Keep class of title elements
|
||||
let classTocElement = tocElement.classList
|
||||
for (var n = 0; n < classTocElement.length; n++) {
|
||||
if (classTocElement[n] != 'title-element') {
|
||||
tocNewLi.classList.add(classTocElement[n])
|
||||
}
|
||||
}
|
||||
|
||||
if(config.position && config.position === "before"){
|
||||
tocNewLi.innerHTML =
|
||||
'<a class="toc-page-before" href="#' + tocElement.id + '">' + tocElement.innerHTML + '</a>';
|
||||
}else{
|
||||
tocNewLi.innerHTML =
|
||||
'<a class="toc-page-after" href="#' + tocElement.id + '">' + tocElement.innerHTML + '</a>';
|
||||
}
|
||||
|
||||
|
||||
tocUl.appendChild(tocNewLi)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue