0.1.7-RC-1: fixed PDF exports

This commit is contained in:
Elvanos 2021-05-20 18:49:54 +02:00
parent ac21593f08
commit 318ef09d19
10 changed files with 799 additions and 235 deletions

View file

@ -585,7 +585,7 @@ export default class DocumentControl extends BaseClass {
}
/****************************************************************/
// Export project
// Save project
/****************************************************************/
retrieveCurrentProjectName = retrieveCurrentProjectName

View file

@ -10,6 +10,13 @@
@trigger-dialog-close="deleteObjectDialogClose"
/>
<!-- Export project dialog -->
<exportProjectDialog
:dialog-trigger="exportProjectDialogTrigger"
:prepicked-ids="[prepickedID]"
@trigger-dialog-close="exportProjectDialogClose"
/>
<div
class="treeSearchWrapper"
:class="{'fullWidth': disableDocumentControlBar}"
@ -252,6 +259,13 @@
</q-item-section>
</q-item>
<q-separator dark />
<q-item clickable v-close-popup @click="commenceExport(prop.node)">
<q-item-section>Export document</q-item-section>
<q-item-section avatar>
<q-icon name="mdi-database-export-outline" />
</q-item-section>
</q-item>
<q-separator dark />
<q-item clickable v-close-popup @click="deleteTabDocument(prop.node)">
<q-item-section class="text-secondary"><b>Delete this document</b></q-item-section>
<q-item-section avatar class="text-secondary">
@ -309,10 +323,12 @@ import { retrieveCurrentProjectName } from "src/scripts/projectManagement/projec
import { createNewWithParent } from "src/scripts/documentActions/createNewWithParent"
import { copyDocumentName, copyDocumentTextColor, copyDocumentBackgroundColor } from "src/scripts/documentActions/uniqueFieldCopy"
import { copyDocument } from "src/scripts/documentActions/copyDocument"
import exportProjectDialog from "src/components/dialogs/ExportProject.vue"
@Component({
components: {
deleteDocumentCheckDialog,
exportProjectDialog,
documentPreview: () => import("src/components/DocumentPreview.vue")
}
})
@ -1136,6 +1152,27 @@ export default class ObjectTree extends BaseClass {
createNewWithParent(currentDoc, this)
}
/****************************************************************/
// Export project dialog
/****************************************************************/
exportProjectDialogTrigger: string | false = false
exportProjectDialogClose () {
this.exportProjectDialogTrigger = false
}
exportProjectAssignUID () {
this.exportProjectDialogTrigger = this.generateUID()
}
prepickedID = ""
commenceExport (node: {_id: string}) {
this.prepickedID = node._id
this.exportProjectAssignUID()
}
/****************************************************************/
// Delete dialog
/****************************************************************/

View file

@ -129,6 +129,168 @@
>
Project
<q-menu
@show="checkProjectStatus"
anchor="bottom left"
class="bg-gunmetal-light"
dark
square
>
<q-list class="bg-gunmetal-light" dark>
<q-item
v-close-popup
clickable
active
active-class="bg-gunmetal-light text-cultured"
class="noHigh"
@click="newProjectAssignUID"
>
<q-item-section>New project</q-item-section>
<q-item-section avatar>
<q-icon name="mdi-plus" />
</q-item-section>
</q-item>
<q-separator dark />
<q-item
v-close-popup
clickable
active
active-class="bg-gunmetal-light text-cultured"
class="noHigh"
@click="commenceSave"
:disable="!projectExists || isFrontpage"
>
<q-item-section>Save current project</q-item-section>
<q-item-section avatar>
<q-icon name="mdi-package-variant-closed" />
</q-item-section>
</q-item>
<q-item
v-close-popup
clickable
active
active-class="bg-gunmetal-light text-cultured"
class="noHigh"
@click="loadProjectAssignUID"
>
<q-item-section>Load existing project</q-item-section>
<q-item-section avatar>
<q-icon name="mdi-package-variant" />
</q-item-section>
</q-item>
<q-separator dark />
<q-item
v-close-popup
clickable
active
active-class="bg-gunmetal-light text-cultured"
class="noHigh"
@click="exportProjectAssignUID"
:disable="!projectExists || isFrontpage"
>
<q-item-section>Export project/documents</q-item-section>
<q-item-section avatar>
<q-icon name="mdi-database-export-outline" />
</q-item-section>
</q-item>
<q-separator dark />
<q-item
v-close-popup
clickable
active
active-class="bg-gunmetal-light text-cultured"
class="noHigh"
@click="navigateToProjectPage"
:disable="!projectExists || isProjectPage"
>
<q-item-section>Show project overview</q-item-section>
<q-item-section avatar>
<q-icon name="mdi-chart-bar" />
</q-item-section>
</q-item>
<q-item
v-close-popup
clickable
active
active-class="bg-gunmetal-light text-cultured"
class="noHigh"
@click="projectCloseCheckDialogAssignUID"
:disable="!projectExists || isFrontpage"
>
<q-item-section>Close project</q-item-section>
<q-item-section avatar>
<q-icon name="mdi-exit-to-app" />
</q-item-section>
</q-item>
<q-separator dark />
<q-item clickable>
<q-item-section>Advanced project tools</q-item-section>
<q-item-section avatar>
<q-icon name="keyboard_arrow_right" />
</q-item-section>
<q-menu anchor="top end" self="top start">
<q-list class="bg-gunmetal text-accent">
<q-item
v-close-popup
clickable
active
active-class="bg-gunmetal-light text-cultured"
class="noHigh"
@click="mergeProjectAssignUID"
:disable="!projectExists || isFrontpage"
>
<q-item-section>Merge another project into the current one</q-item-section>
<q-item-section avatar>
<q-icon name="mdi-folder-plus-outline" />
</q-item-section>
</q-item>
<q-separator dark />
<q-item
v-close-popup
clickable
active
active-class="bg-gunmetal-light text-cultured"
class="noHigh"
@click="repairProjectAssignUID"
:disable="!projectExists || isFrontpage"
>
<q-item-section>Repair legacy project</q-item-section>
<q-item-section avatar>
<q-icon name="mdi-wrench" />
</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-item>
</q-list>
</q-menu>
</q-btn>
<!-- Tools button-->
<q-btn
flat
:ripple="false"
dark
size='md'
no-caps
>
Tools
<q-menu
@show="checkProjectStatus"
anchor="bottom left"
@ -202,163 +364,6 @@
<q-separator dark />
<q-item
v-close-popup
clickable
active
active-class="bg-gunmetal-light text-cultured"
class="noHigh"
@click="newProjectAssignUID"
>
<q-item-section>New project</q-item-section>
<q-item-section avatar>
<q-icon name="mdi-plus" />
</q-item-section>
</q-item>
<q-separator dark />
<q-item
v-close-popup
clickable
active
active-class="bg-gunmetal-light text-cultured"
class="noHigh"
@click="commenceSave"
:disable="!projectExists || isFrontpage"
>
<q-item-section>Save current project</q-item-section>
<q-item-section avatar>
<q-icon name="mdi-package-variant-closed" />
</q-item-section>
</q-item>
<q-item
v-close-popup
clickable
active
active-class="bg-gunmetal-light text-cultured"
class="noHigh"
@click="loadProjectAssignUID"
>
<q-item-section>Load existing project</q-item-section>
<q-item-section avatar>
<q-icon name="mdi-package-variant" />
</q-item-section>
</q-item>
<q-separator dark />
<q-item clickable>
<q-item-section>Advanced project tools</q-item-section>
<q-item-section avatar>
<q-icon name="keyboard_arrow_right" />
</q-item-section>
<q-menu anchor="top end" self="top start">
<q-list class="bg-gunmetal text-accent">
<q-item
v-close-popup
clickable
active
active-class="bg-gunmetal-light text-cultured"
class="noHigh"
@click="mergeProjectAssignUID"
:disable="!projectExists || isFrontpage"
>
<q-item-section>Merge another project into the current one</q-item-section>
<q-item-section avatar>
<q-icon name="mdi-folder-plus-outline" />
</q-item-section>
</q-item>
<q-item
v-close-popup
clickable
active
active-class="bg-gunmetal-light text-cultured"
class="noHigh"
@click="exportProjectAssignUID"
:disable="!projectExists || isFrontpage"
>
<q-item-section>Export project/documents</q-item-section>
<q-item-section avatar>
<q-icon name="mdi-database-export-outline" />
</q-item-section>
</q-item>
<q-separator dark />
<q-item
v-close-popup
clickable
active
active-class="bg-gunmetal-light text-cultured"
class="noHigh"
@click="repairProjectAssignUID"
:disable="!projectExists || isFrontpage"
>
<q-item-section>Repair legacy project</q-item-section>
<q-item-section avatar>
<q-icon name="mdi-wrench" />
</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-item>
<q-separator dark />
<q-item
v-close-popup
clickable
active
active-class="bg-gunmetal-light text-cultured"
class="noHigh"
@click="navigateToProjectPage"
:disable="!projectExists || isProjectPage"
>
<q-item-section>Show project overview</q-item-section>
<q-item-section avatar>
<q-icon name="mdi-chart-bar" />
</q-item-section>
</q-item>
<q-item
v-close-popup
clickable
active
active-class="bg-gunmetal-light text-cultured"
class="noHigh"
@click="projectCloseCheckDialogAssignUID"
:disable="!projectExists || isFrontpage"
>
<q-item-section>Close project</q-item-section>
<q-item-section avatar>
<q-icon name="mdi-exit-to-app" />
</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
<!-- Help button-->
<q-btn
flat
:ripple="false"
dark
size='md'
no-caps
>
Help, Settings & Info
<q-menu
anchor="bottom left"
class="bg-gunmetal-light"
dark
square
>
<q-list class="bg-gunmetal-light" dark>
<q-item
@click="programSettingsDialogAssignUID"
v-close-popup
@ -373,7 +378,26 @@
</q-item-section>
</q-item>
<q-separator dark />
</q-list>
</q-menu>
</q-btn>
<!-- Help button-->
<q-btn
flat
:ripple="false"
dark
size='md'
no-caps
>
Help & Info
<q-menu
anchor="bottom left"
class="bg-gunmetal-light"
dark
square
>
<q-list class="bg-gunmetal-light" dark>
<q-item
@click="keybindsDialogAssignUID"

View file

@ -1,5 +1,12 @@
<template>
<q-dialog
<div>
<!-- Export project dialog -->
<exportProjectDialog
:dialog-trigger="exportProjectDialogTrigger"
:prepicked-ids="[prepickedID]"
@trigger-dialog-close="exportProjectDialogClose"
/>
<q-dialog
no-route-dismiss
v-model="dialogModel"
@before-hide="triggerDialogClose"
@ -10,7 +17,7 @@
>
<q-card-section class="row items-center">
<h6 class="text-center q-my-sm">Open existing document</h6>
<h6 class="text-center q-my-sm">Search through existing documents</h6>
</q-card-section>
<q-card-section class="column items-center">
@ -202,6 +209,13 @@
<q-icon color="primary" name="mdi-content-copy" />
</q-item-section>
</q-item>
<q-separator dark />
<q-item clickable v-close-popup @click="commenceExport(opt)">
<q-item-section>Export document</q-item-section>
<q-item-section avatar>
<q-icon name="mdi-database-export-outline" />
</q-item-section>
</q-item>
</template>
</q-list>
@ -220,6 +234,8 @@
</q-card>
</q-dialog>
</div>
</template>
<script lang="ts">
@ -232,6 +248,7 @@ import { extend, uid } from "quasar"
import { createNewWithParent } from "src/scripts/documentActions/createNewWithParent"
import { copyDocumentName, copyDocumentTextColor, copyDocumentBackgroundColor } from "src/scripts/documentActions/uniqueFieldCopy"
import { copyDocument } from "src/scripts/documentActions/copyDocument"
import exportProjectDialog from "src/components/dialogs/ExportProject.vue"
import DialogBase from "src/components/dialogs/_DialogBase"
import { I_Blueprint } from "src/interfaces/I_Blueprint"
@ -239,7 +256,8 @@ import documentPreview from "src/components/DocumentPreview.vue"
@Component({
components: {
documentPreview
documentPreview,
exportProjectDialog
}
})
export default class ExistingDocumentDialog extends DialogBase {
@ -593,6 +611,30 @@ export default class ExistingDocumentDialog extends DialogBase {
}
documentPreviewClose = ""
prepickedID = ""
/****************************************************************/
// Export project dialog
/****************************************************************/
exportProjectDialogTrigger: string | false = false
exportProjectDialogClose () {
this.exportProjectDialogTrigger = false
}
exportProjectAssignUID () {
this.exportProjectDialogTrigger = this.generateUID()
}
commenceExport (node: {_id: string}) {
this.dialogModel = false
// @ts-ignore
this.prepickedID = node._id
this.exportProjectAssignUID()
}
}
</script>

View file

@ -19,16 +19,41 @@
<div class="row justify-center">
<div class="col-4">
<div class="q-mx-lg">
<q-select
class="exportTypeSelect"
dark
popup-content-class="menuResizer"
:options="exportFormats"
label="Export file format"
filled
input-debounce="0"
v-model="selectedExportFormat"
/>
<div class="row">
<div class="col">
<q-select
class="exportTypeSelect"
dark
popup-content-class="menuResizer"
:options="exportFormats"
label="Export file format"
filled
input-debounce="0"
v-model="selectedExportFormat"
/>
</div>
<div class="col-auto self-center q-ml-sm" v-if="selectedExportFormat === 'Adobe Reader - PDF'">
<q-icon name="mdi-alert-circle" size="20px">
<q-tooltip :delay="500">
Please note that the PDF export doesn't play nice
<br>
with underlined text if different parts of the same paragraph
<br>
have increased/decreased font sizes
<br>
OR
<br>
if you have underlines in headings.
<br>
<br>
If your document contains such text,
<br>
then the result might not very appealing aesthetically.
</q-tooltip>
</q-icon>
</div>
</div>
<q-checkbox
class="q-mt-lg"
@ -40,12 +65,29 @@
<q-checkbox
class="q-mt-lg"
dark color="primary"
v-model="writerMode"
label="Export only text editors and document name?"
/>
<q-checkbox
class="q-mt-lg"
dark color="primary"
v-if='writerMode'
v-model="writerModeTitles"
label="Include text editor field titles?"
/>
<q-checkbox
class="q-mt-lg"
v-if='!writerMode'
dark color="primary"
v-model="includeTags"
label="Include tags in the export?"
/>
<q-checkbox
class="q-mt-lg"
v-if='!writerMode'
dark color="primary"
v-model="includeHierarchyPath"
label="Include hierarchical path in the export?"
@ -53,13 +95,14 @@
<q-checkbox
class="q-mt-lg"
v-if='!writerMode'
dark color="primary"
v-model="includeIsDead"
label="Include dead/gone/destroyed documents in the export?"
/>
<q-checkbox
v-if="includeIsDead"
v-if='!writerMode && includeIsDead'
class="q-mt-lg"
dark color="primary"
v-model="hideDeadInformation"
@ -294,6 +337,8 @@ export default class ExportProject extends DialogBase {
this.includeHierarchyPath = false
this.hideDeadInformation = false
this.includeIsDead = true
this.writerMode = false
this.writerModeTitles = false
this.exportDocumentsModel = []
this.exportOngoing = false
this.exportList = []
@ -316,6 +361,10 @@ export default class ExportProject extends DialogBase {
exportWholeProject = false
writerMode = false
writerModeTitles = false
includeTags = false
includeHierarchyPath = false
@ -776,39 +825,68 @@ export default class ExportProject extends DialogBase {
JSONExport[0] = `${JSONExport[0]} - Category`
}
// Document type
JSONExport.push({ h2: "Document type" })
JSONExport.push({ ul: [input.documentType] })
if (!this.writerMode) {
// Document type
JSONExport.push({ h2: "Document type" })
JSONExport.push({ ul: [input.documentType] })
}
if (!this.writerMode) {
// Status
if (!this.hideDeadInformation) {
JSONExport.push({ h2: "Status" })
JSONExport.push({ ul: [(input.isDead) ? "Dead/Gone/Destroyed" : "Active/Alive"] })
if (!this.hideDeadInformation) {
JSONExport.push({ h2: "Status" })
JSONExport.push({ ul: [(input.isDead) ? "Dead/Gone/Destroyed" : "Active/Alive"] })
}
}
if (!this.writerMode) {
// Hierarchy path
if (this.includeHierarchyPath) {
JSONExport.push({ h2: "Hierarchical path" })
JSONExport.push({ ul: [input.hierarchicalPath] })
if (this.includeHierarchyPath) {
JSONExport.push({ h2: "Hierarchical path" })
JSONExport.push({ ul: [input.hierarchicalPath] })
}
}
if (!this.writerMode) {
// Tags
if (this.includeTags) {
JSONExport.push({ h2: "Tags" })
JSONExport.push({ ul: (Array.isArray(input.tags) ? input.tags : []) })
if (this.includeTags) {
JSONExport.push({ h2: "Tags" })
JSONExport.push({ ul: (Array.isArray(input.tags) ? input.tags : []) })
}
}
// Other fields
input.fieldValues.forEach(field => {
if (field.type === "break") {
if (field.type === "break" && !this.writerMode) {
JSONExport.push({ hr: "" })
JSONExport.push({ h1: field.label })
}
else if (field.type === "wysiwyg") {
JSONExport.push({ h2: field.label })
JSONExport.push({ p: field.value })
if (!this.writerMode || this.writerModeTitles) {
JSONExport.push({ h2: field.label })
}
let localValue = field.value as unknown as string
var replacements = [
[/\*/g, "\\*", "asterisks"],
[/#/g, "\\#", "number signs"],
[/\(/g, "\\(", "parentheses"],
[/\)/g, "\\)", "parentheses"],
[/\[/g, "\\[", "square brackets"],
[/\]/g, "\\]", "square brackets"],
[/_/g, "\\_", "underscores"]
]
// Escape special Characters
replacements.forEach(rep => {
// @ts-ignore
localValue = localValue.replace(rep[0], rep[1])
})
JSONExport.push({ p: localValue })
}
else {
else if (!this.writerMode) {
JSONExport.push({ h2: field.label })
if (Array.isArray(field.value)) {
JSONExport.push({ ul: field.value })
@ -865,62 +943,75 @@ export default class ExportProject extends DialogBase {
// Next line
doc.fontSize(textFont).moveDown().moveDown()
// Document type
doc.font("Times-Bold").fillColor("#000000").fontSize(textFont)
.text("Document type", textPadding, undefined, paragraphOptions)
doc.font("Times-Roman").fillColor("#000000").fontSize(textFont)
.list([input.documentType], listPadding, undefined, paragraphOptions)
.moveDown()
if (!this.writerMode) {
// Document type
doc.font("Times-Bold").fillColor("#000000").fontSize(textFont)
.text("Document type", textPadding, undefined, paragraphOptions)
doc.font("Times-Roman").fillColor("#000000").fontSize(textFont)
.list([input.documentType], listPadding, undefined, paragraphOptions)
.moveDown()
}
if (!this.writerMode) {
// Status
if (!this.hideDeadInformation) {
doc.font("Times-Bold").fillColor("#000000").fontSize(textFont)
.text("Status", textPadding, undefined, paragraphOptions)
doc.font("Times-Roman").fillColor("#000000").fontSize(textFont)
.list([((input.isDead) ? "Dead/Gone/Destroyed" : "Active/Alive")], listPadding, undefined, paragraphOptions)
.moveDown()
if (!this.hideDeadInformation) {
doc.font("Times-Bold").fillColor("#000000").fontSize(textFont)
.text("Status", textPadding, undefined, paragraphOptions)
doc.font("Times-Roman").fillColor("#000000").fontSize(textFont)
.list([((input.isDead) ? "Dead/Gone/Destroyed" : "Active/Alive")], listPadding, undefined, paragraphOptions)
.moveDown()
}
}
// Hierarchy path
if (this.includeHierarchyPath) {
doc.font("Times-Bold").fillColor("#000000").fontSize(textFont)
.text("Hierarchical path", textPadding, undefined, paragraphOptions)
doc.font("Times-Roman").fillColor("#000000").fontSize(textFont)
.list([input.hierarchicalPath], listPadding)
.moveDown()
if (!this.writerMode) {
// Hierarchy path
if (this.includeHierarchyPath) {
doc.font("Times-Bold").fillColor("#000000").fontSize(textFont)
.text("Hierarchical path", textPadding, undefined, paragraphOptions)
doc.font("Times-Roman").fillColor("#000000").fontSize(textFont)
.list([input.hierarchicalPath], listPadding)
.moveDown()
}
}
if (!this.writerMode) {
// Tags
if (this.includeTags) {
doc.font("Times-Bold").fillColor("#000000").fontSize(textFont)
.text("Tags", textPadding, undefined, paragraphOptions)
doc.font("Times-Roman").fillColor("#000000").fontSize(textFont)
.list((Array.isArray(input.tags) ? input.tags : []), listPadding, undefined, paragraphOptions)
.moveDown()
if (this.includeTags) {
doc.font("Times-Bold").fillColor("#000000").fontSize(textFont)
.text("Tags", textPadding, undefined, paragraphOptions)
doc.font("Times-Roman").fillColor("#000000").fontSize(textFont)
.list((Array.isArray(input.tags) ? input.tags : []), listPadding, undefined, paragraphOptions)
.moveDown()
}
}
// Other fields
input.fieldValues.forEach(field => {
if (field.type === "break") {
if (field.type === "break" && !this.writerMode) {
doc.moveDown()
.font("Times-Bold").fillColor("#000000").fontSize(subTitleFont)
.text(field.label, textPadding, undefined, paragraphOptions)
.moveDown()
}
else if (field.type === "wysiwyg") {
doc.font("Times-Bold").fillColor("#000000").fontSize(textFont)
.text(field.label, textPadding, undefined, paragraphOptions)
.moveDown()
if (!this.writerMode || this.writerModeTitles) {
doc.font("Times-Bold").fillColor("#000000").fontSize(textFont)
.text(field.label, textPadding, undefined, paragraphOptions)
.moveDown()
}
// @ts-ignore
const returnList = this.buildPDFWysiwygContent(field.value)
doc.font("Times-Roman").fillColor("#000000").fontSize(textFont)
const wysiwygOptions: {[key:string]: any} = extend(true, {}, paragraphOptions)
returnList.forEach(node => {
if (node.type === "text") {
const wysiwygOptions: {[key:string]: any} = extend(true, {}, paragraphOptions)
wysiwygOptions.baseline = "alphabetic"
doc.fontSize(textFont)
// Italic
wysiwygOptions.oblique = node.attrs.italic
@ -930,6 +1021,23 @@ export default class ExportProject extends DialogBase {
// Bold
doc.font((node?.attrs?.bold) ? "Times-Bold" : "Times-Roman")
// Heading font sizing
if (node?.attrs?.hasHeadingFontSize) {
// @ts-ignore
doc.fontSize(node.attrs.nodeHeadingSize)
// @ts-ignore
wysiwygOptions.lineGap = node.attrs.nodeHeadingSize / 3
doc.font("Times-Bold")
}
// Custom font sizing
if (node?.attrs?.hasSpecialFontSize) {
// @ts-ignore
doc.fontSize(node.attrs.specialFontSize)
// @ts-ignore
wysiwygOptions.lineGap = node.attrs.specialFontSize / 3
}
// Continued
wysiwygOptions.continued = node.attrs.continued
@ -948,7 +1056,7 @@ export default class ExportProject extends DialogBase {
// @ts-ignore
doc.moveDown()
}
else {
else if (!this.writerMode) {
doc.font("Times-Bold").fillColor("#000000").fontSize(textFont)
.text(field.label, textPadding, undefined, paragraphOptions)
doc.font("Times-Roman").fillColor("#000000").fontSize(textFont)
@ -961,6 +1069,27 @@ export default class ExportProject extends DialogBase {
}
buildPDFWysiwygContent (input: string) {
const blockTagList = [
"div",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6",
"li",
"blockquote"
]
const headingsList = [
"h1",
"h2",
"h3",
"h4",
"h5",
"h6"
]
const returnNodeList: I_HtmlParserNode[] = []
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
@ -977,6 +1106,60 @@ export default class ExportProject extends DialogBase {
}
}
const processHeadingFontSize = (heading: string) => {
switch (heading) {
case "h1":
return 24
case "h2":
return 20
case "h3":
return 18
case "h4":
return 16
case "h5":
return 14
case "h6":
return 12
default:
return 11
}
}
const processNodeFontSize = (fontString: string) => {
const fontNumber = parseInt(fontString)
switch (fontNumber) {
case 1:
return 7
case 2:
return 9
case 3:
return 11
case 4:
return 13
case 5:
return 16
case 6:
return 19
case 7:
return 23
default:
return 11
}
}
const processNode = (node: I_HtmlParserNode) => {
// ------------- NODE EXTRA ATTRIBUTES ------------------
let nodeStyles: false|string = false
@ -985,6 +1168,12 @@ export default class ExportProject extends DialogBase {
nodeStyles = (processNodeStyles(snapshot.style)) ? snapshot.style : false
}
let nodeFontSize: false|string = false
if (node?.attrs?.size) {
const snapshot: {size:string} = extend(true, {}, node.attrs)
nodeFontSize = (snapshot.size) || false
}
let parentIsBlockquote = false
if (node.parentNode?.attrs?.blockquotePadding) {
parentIsBlockquote = true
@ -997,11 +1186,39 @@ export default class ExportProject extends DialogBase {
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
const nextNode = node.selfNodeList[node.selfIndex + 1]
// @ts-ignore
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
const nextParentNode = node?.parentNode?.selfNodeList[node?.parentNode?.selfIndex + 1]
// If it is the last one, obviously dont continue anything
if (!nextNode) {
node.isLast = true
}
// Text modifier - Headings
if ((node.type === "tag" && headingsList.includes(node.name)) || node?.parentNode?.attrs.hasHeadingFontSize === true) {
node.attrs.hasHeadingFontSize = true
if (headingsList.includes(node.name)) {
node.attrs.nodeHeadingSize = processHeadingFontSize(node.name)
}
else if (node?.parentNode?.attrs?.nodeHeadingSize) {
node.attrs.nodeHeadingSize = node?.parentNode?.attrs?.nodeHeadingSize
}
node.attrs.continued = false
}
else {
node.attrs.hasHeadingFontSize = false
}
// If next if bold, italic or underline
if (nextNode) {
if ((nextNode.type === "tag" && nextNode.name === "i") ||
(nextNode.type === "tag" && nextNode.name === "b") ||
(nextNode.type === "tag" && nextNode.name === "u")
(nextNode.type === "tag" && nextNode.name === "u") ||
(nextNode.type === "tag" && nextNode.name === "font") ||
(nextNode.type === "tag" && nextNode.name === "span")
) {
node.attrs.continued = true
}
@ -1018,6 +1235,15 @@ export default class ExportProject extends DialogBase {
node.attrs.align = node.parentNode.attrs.align
}
// Temporary fix for spans
if ((node.type === "tag" && node.name === "span") || node?.parentNode?.attrs.isSpan === true) {
node.attrs.isSpan = true
node.attrs.continued = true
}
else {
node.attrs.isSpan = false
}
// Text modifier - Italic
if ((node.type === "tag" && node.name === "i") || node?.parentNode?.attrs.italic === true) {
node.attrs.italic = true
@ -1045,13 +1271,33 @@ export default class ExportProject extends DialogBase {
node.attrs.underline = false
}
// If it is the last one, obviously dont continue anything
if (!nextNode && node.type !== "text") {
node.isLast = true
// Text modifier - Font size
if ((node.type === "tag" && node.name === "font") || node?.parentNode?.attrs.hasSpecialFontSize === true) {
node.attrs.hasSpecialFontSize = true
// @ts-ignore
node.attrs.specialFontSize = (nodeFontSize)
// @ts-ignore
? processNodeFontSize(nodeFontSize)
: node?.parentNode?.attrs?.specialFontSize
node.attrs.continued = true
}
else {
node.attrs.hasSpecialFontSize = false
}
// Don't continue is this lack a continuing node
if (node.parentNode?.isLast && !nextNode) {
// Don't continue is this lack a continuing node OR if next node is 'div'
if ((node.parentNode?.isLast && !nextNode) ||
(nextNode && nextNode.type === "tag" && blockTagList.includes(nextNode.name)) ||
(node.isLast && nextParentNode?.type === "tag" && blockTagList.includes(nextParentNode?.name)) ||
(node.isLast && node.parentNode?.isLast)
) {
if (node.content === "great and brilliant Lord Demarcus Katari'") {
console.log((node.parentNode?.isLast && !nextNode))
console.log((nextNode && nextNode.type === "tag" && blockTagList.includes(nextNode.name)))
console.log((node.isLast && nextParentNode?.type === "tag" && blockTagList.includes(nextParentNode?.name)))
console.log((node.isLast && node.parentNode?.isLast))
}
node.attrs.continued = false
}
@ -1063,29 +1309,36 @@ export default class ExportProject extends DialogBase {
// ------------- NODE PROCESSING ----------------------
// Return text node value OR a break
if ((node.type === "text" && node.content) || node.type === "br") {
if ((node.type === "text" && node.content)) {
const returnNode = node
// @ts-ignore
returnNode.content = returnNode.content.replace(/&nbsp;/g, "").replace(/(\r\n|\n|\r)/gm, "")
if (node.attrs.isSpan) {
returnNode.content = returnNode.content + " "
}
returnNodeList.push(returnNode)
}
// Process subnodes
else if (node?.children?.length > 0) {
node.children.forEach((childNode, i) => {
childNode.selfIndex = i
childNode.selfNodeList = node.children
childNode.selfNodeList = node.children.filter(subNode => subNode.name !== "br")
childNode.parentNode = node
if (node.name === "span") {
console.log((childNode))
}
processNode(childNode)
})
}
}
// Generate return value
parsedHTML[0].selfNodeList = [parsedHTML[0]]
parsedHTML[0].selfNodeList = [parsedHTML[0]].filter(subNode => subNode.name !== "br")
parsedHTML[0].selfIndex = 0
parsedHTML[0].attrs = {}
processNode(parsedHTML[0])
return returnNodeList

View file

@ -190,6 +190,70 @@ a {
> div {
margin: 12.5px 0;
}
font[size="1"] {
font-size: 10px;
}
font[size="2"] {
font-size: 13px;
}
font[size="3"] {
font-size: 16px;
}
font[size="4"] {
font-size: 20px;
}
font[size="5"] {
font-size: 24px;
}
font[size="6"] {
font-size: 28px;
}
font[size="7"] {
font-size: 34px;
}
h1 {
font-size: 50px;
font-weight: 400;
line-height: 1.4;
}
h2 {
font-size: 40px;
font-weight: 400;
line-height: 1.6;
}
h3 {
font-size: 35px;
font-weight: 400;
line-height: 1.6;
}
h4 {
font-size: 30px;
font-weight: 400;
line-height: 1.8;
}
h5 {
font-size: 25px;
font-weight: 400;
line-height: 1.8;
}
h6 {
font-size: 20px;
font-weight: 400;
line-height: 1.8;
}
}
.q-editor__toolbars-container {
@ -693,3 +757,73 @@ body .q-tooltip {
right: 0;
top: 0;
}
font[size="1"] {
font-size: 10px;
}
font[size="2"] {
font-size: 13px;
}
font[size="3"] {
font-size: 16px;
}
font[size="4"] {
font-size: 20px;
}
font[size="5"] {
font-size: 24px;
}
font[size="6"] {
font-size: 28px;
}
font[size="7"] {
font-size: 34px;
}
.q-menu.q-position-engine .q-list {
h1 {
font-size: 50px;
font-weight: 400;
line-height: 1.4;
}
h2 {
font-size: 40px;
font-weight: 400;
line-height: 1.6;
}
h3 {
font-size: 35px;
font-weight: 400;
line-height: 1.6;
}
h4 {
font-size: 30px;
font-weight: 400;
line-height: 1.8;
}
h5 {
font-size: 25px;
font-weight: 400;
line-height: 1.8;
}
h6 {
font-size: 20px;
font-weight: 400;
line-height: 1.8;
}
.text-no-wrap {
font-size: 16px;
}
}

View file

@ -24,6 +24,7 @@
### New features
- **Added export support for Markdown**
- **Added export support for PDF**
- **Added on-the-fly relationship documents generation**
- **Added stat/attribute support for multiple RPG systems**
- **Added option to search through the `Other names` field via `@` modifier**
@ -60,6 +61,8 @@
- Added a tiny bit of color to help discern which relationship is one-way and which is two-way
- Adjusted the single and multi relationship fields not showing suggestion popups when a value is removed the list
- Adjusted the single relationship fields to hide the suggest list when a value is selected from the list
- Adjust font sizes for titles and "sizes" in text editor field to be actually useable without looks ridiculous
- Rearanged the menu and added a new `Tools` category to make finding stuff a bit easier
## 0.1.6a

View file

@ -4,7 +4,7 @@ export interface I_HtmlParserNode {
voidElement: boolean;
name: string;
attrs: {
[key: string]: string|boolean
[key: string]: string|boolean|number
};
children: I_HtmlParserNode[];
selfIndex?: number;

View file

@ -524,6 +524,74 @@ export const RPGSystemsStats = [
"Reflexes (ref) - Speed (spd)"
]
},
{
title: "Fallout",
values: [
"Strength",
"Perception",
"Endurance",
"Charisma",
"Intelligence",
"Agility",
"Luck"
]
},
{
title: "Star Trek Adventures - Personnel (Modiphius 2d20 System)",
values: [
"Control - Attribute",
"Daring - Attribute",
"Fitness - Attribute",
"Insight - Attribute",
"Presence - Attribute",
"Reason - Attribute",
"Command - Discipline",
"Conn - Discipline",
"Security - Discipline",
"Engineering - Discipline",
"Science - Discipline",
"Medicine - Discipline"
]
},
{
title: "Star Trek Adventures - Ships (Modiphius 2d20 System)",
values: [
"Engines - Systems",
"Structure - Systems",
"Computers - Systems",
"Sensors - Systems",
"Weapons - Systems",
"Communications - Systems",
"Command - Department",
"Conn - Department",
"Security - Department",
"Engineering - Department",
"Science - Department",
"Medicine - Department"
]
},
{
title: "Warhammer 40k (Dark Heresy 2)",
values: [
"Weapon Skill",
"Ballistic Skill",
"Strength",
"Toughness",
"Agility",
"Intelligence",
"Perception",
"Willpower",
"Fellowship",
"Psy Rating",
"Wounds",
"Fatigue",
"Insanity",
"Corruption",
"Influence",
"Profit Factor",
"Infamy"
]
},
"Absorption",
"Alertness",

View file

@ -1,14 +1,15 @@
## THE GM BATCH START - 0.1.7
- "Save all" keybind and "Save all and exit" option on the exiting
- Export for MD/PDF/ODT/DOCX
- Add `Font` and `hX` elements to PDF support... maybe something else
Suggestion: In Species/Races/Flora/Fauna docs, move Related Species/Races/Flora/Fauna and Characters of Species/Races/Flora/Fauna down and move the text fields (Description & History and Traditions & Customs) up. I have a lot of characters and have to scroll quite a bit to get down to the text fields to read them.
## THE GM BATCH END - 0.1.7
## PROJECT SETTINGS BATCH 1 START - 0.1.8
- Add `SHIFT + ENTER` add mode to relationship searches to add documents without deleting the entered text
- Rewrite document display algortithmn and add option to show description (text editor fields) on top of the section (under break)
- Breaks/titles in lists
- Pin document preview floating window
- Project setting dialog/options
- Project rename
@ -71,6 +72,7 @@
### High priority
- Export for ODT/DOCX
- Dynamic table field
- Add subtabs (character stats, general info, etc)
- Global text find/replace
@ -82,6 +84,7 @@
### Low priority
- Double decimals (dates) in order field
- Horizontal fields (title AND value next to each other. Might need a designer)
- Simple data imports (maybe?)
- Vanity project-wide word count