Skip to content

Commit b35b62d

Browse files
committed
Merge branch 'lexical' into development
2 parents 3a058a6 + 1b9310e commit b35b62d

File tree

302 files changed

+65590
-2239
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

302 files changed

+65590
-2239
lines changed

.github/workflows/lint-js.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ on:
1313
jobs:
1414
build:
1515
if: ${{ github.ref != 'refs/heads/l10n_development' }}
16-
runs-on: ubuntu-22.04
16+
runs-on: ubuntu-24.04
1717
steps:
18-
- uses: actions/checkout@v1
18+
- uses: actions/checkout@v4
1919

2020
- name: Install NPM deps
2121
run: npm ci

.github/workflows/test-js.yml

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: test-js
2+
3+
on:
4+
push:
5+
paths:
6+
- '**.js'
7+
- '**.ts'
8+
- '**.json'
9+
pull_request:
10+
paths:
11+
- '**.js'
12+
- '**.ts'
13+
- '**.json'
14+
15+
jobs:
16+
build:
17+
if: ${{ github.ref != 'refs/heads/l10n_development' }}
18+
runs-on: ubuntu-24.04
19+
steps:
20+
- uses: actions/checkout@v4
21+
22+
- name: Install NPM deps
23+
run: npm ci
24+
25+
- name: Run TypeScript type checking
26+
run: npm run ts:lint
27+
28+
- name: Run JavaScript tests
29+
run: npm run test

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
/node_modules
33
/.vscode
44
/composer
5+
/coverage
56
Homestead.yaml
67
.env
78
.idea

app/Entities/Models/Page.php

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace BookStack\Entities\Models;
44

55
use BookStack\Entities\Tools\PageContent;
6+
use BookStack\Entities\Tools\PageEditorType;
67
use BookStack\Permissions\PermissionApplicator;
78
use BookStack\Uploads\Attachment;
89
use Illuminate\Database\Eloquent\Builder;

app/Entities/Repos/PageRepo.php

+7-4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use BookStack\Entities\Tools\BookContents;
1313
use BookStack\Entities\Tools\PageContent;
1414
use BookStack\Entities\Tools\PageEditorData;
15+
use BookStack\Entities\Tools\PageEditorType;
1516
use BookStack\Entities\Tools\TrashCan;
1617
use BookStack\Exceptions\MoveOperationException;
1718
use BookStack\Exceptions\PermissionsException;
@@ -127,7 +128,9 @@ protected function updateTemplateStatusAndContentFromInput(Page $page, array $in
127128
}
128129

129130
$pageContent = new PageContent($page);
130-
$currentEditor = $page->editor ?: PageEditorData::getSystemDefaultEditor();
131+
$defaultEditor = PageEditorType::getSystemDefault();
132+
$currentEditor = PageEditorType::forPage($page) ?: $defaultEditor;
133+
$inputEditor = PageEditorType::fromRequestValue($input['editor'] ?? '') ?? $currentEditor;
131134
$newEditor = $currentEditor;
132135

133136
$haveInput = isset($input['markdown']) || isset($input['html']);
@@ -136,15 +139,15 @@ protected function updateTemplateStatusAndContentFromInput(Page $page, array $in
136139
if ($haveInput && $inputEmpty) {
137140
$pageContent->setNewHTML('', user());
138141
} elseif (!empty($input['markdown']) && is_string($input['markdown'])) {
139-
$newEditor = 'markdown';
142+
$newEditor = PageEditorType::Markdown;
140143
$pageContent->setNewMarkdown($input['markdown'], user());
141144
} elseif (isset($input['html'])) {
142-
$newEditor = 'wysiwyg';
145+
$newEditor = ($inputEditor->isHtmlBased() ? $inputEditor : null) ?? ($defaultEditor->isHtmlBased() ? $defaultEditor : null) ?? PageEditorType::WysiwygTinymce;
143146
$pageContent->setNewHTML($input['html'], user());
144147
}
145148

146149
if ($newEditor !== $currentEditor && userCan('editor-change')) {
147-
$page->editor = $newEditor;
150+
$page->editor = $newEditor->value;
148151
}
149152
}
150153

app/Entities/Tools/PageEditorData.php

+7-15
Original file line numberDiff line numberDiff line change
@@ -74,17 +74,17 @@ protected function build(): array
7474
];
7575
}
7676

77-
protected function updateContentForEditor(Page $page, string $editorType): void
77+
protected function updateContentForEditor(Page $page, PageEditorType $editorType): void
7878
{
7979
$isHtml = !empty($page->html) && empty($page->markdown);
8080

8181
// HTML to markdown-clean conversion
82-
if ($editorType === 'markdown' && $isHtml && $this->requestedEditor === 'markdown-clean') {
82+
if ($editorType === PageEditorType::Markdown && $isHtml && $this->requestedEditor === 'markdown-clean') {
8383
$page->markdown = (new HtmlToMarkdown($page->html))->convert();
8484
}
8585

8686
// Markdown to HTML conversion if we don't have HTML
87-
if ($editorType === 'wysiwyg' && !$isHtml) {
87+
if ($editorType->isHtmlBased() && !$isHtml) {
8888
$page->html = (new MarkdownToHtml($page->markdown))->convert();
8989
}
9090
}
@@ -94,24 +94,16 @@ protected function updateContentForEditor(Page $page, string $editorType): void
9494
* Defaults based upon the current content of the page otherwise will fall back
9595
* to system default but will take a requested type (if provided) if permissions allow.
9696
*/
97-
protected function getEditorType(Page $page): string
97+
protected function getEditorType(Page $page): PageEditorType
9898
{
99-
$editorType = $page->editor ?: self::getSystemDefaultEditor();
99+
$editorType = PageEditorType::forPage($page) ?: PageEditorType::getSystemDefault();
100100

101101
// Use requested editor if valid and if we have permission
102-
$requestedType = explode('-', $this->requestedEditor)[0];
103-
if (($requestedType === 'markdown' || $requestedType === 'wysiwyg') && userCan('editor-change')) {
102+
$requestedType = PageEditorType::fromRequestValue($this->requestedEditor);
103+
if ($requestedType && userCan('editor-change')) {
104104
$editorType = $requestedType;
105105
}
106106

107107
return $editorType;
108108
}
109-
110-
/**
111-
* Get the configured system default editor.
112-
*/
113-
public static function getSystemDefaultEditor(): string
114-
{
115-
return setting('app-editor') === 'markdown' ? 'markdown' : 'wysiwyg';
116-
}
117109
}

app/Entities/Tools/PageEditorType.php

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
namespace BookStack\Entities\Tools;
4+
5+
use BookStack\Entities\Models\Page;
6+
7+
enum PageEditorType: string
8+
{
9+
case WysiwygTinymce = 'wysiwyg';
10+
case WysiwygLexical = 'wysiwyg2024';
11+
case Markdown = 'markdown';
12+
13+
public function isHtmlBased(): bool
14+
{
15+
return match ($this) {
16+
self::WysiwygTinymce, self::WysiwygLexical => true,
17+
self::Markdown => false,
18+
};
19+
}
20+
21+
public static function fromRequestValue(string $value): static|null
22+
{
23+
$editor = explode('-', $value)[0];
24+
return static::tryFrom($editor);
25+
}
26+
27+
public static function forPage(Page $page): static|null
28+
{
29+
return static::tryFrom($page->editor);
30+
}
31+
32+
public static function getSystemDefault(): static
33+
{
34+
$setting = setting('app-editor');
35+
return static::tryFrom($setting) ?? static::WysiwygTinymce;
36+
}
37+
}

dev/build/esbuild.js

+10
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const entryPoints = {
1414
code: path.join(__dirname, '../../resources/js/code/index.mjs'),
1515
'legacy-modes': path.join(__dirname, '../../resources/js/code/legacy-modes.mjs'),
1616
markdown: path.join(__dirname, '../../resources/js/markdown/index.mjs'),
17+
wysiwyg: path.join(__dirname, '../../resources/js/wysiwyg/index.ts'),
1718
};
1819

1920
// Locate our output directory
@@ -31,6 +32,15 @@ esbuild.build({
3132
format: 'esm',
3233
minify: isProd,
3334
logLevel: 'info',
35+
loader: {
36+
'.svg': 'text',
37+
},
38+
absWorkingDir: path.join(__dirname, '../..'),
39+
alias: {
40+
'@icons': './resources/icons',
41+
lexical: './resources/js/wysiwyg/lexical/core',
42+
'@lexical': './resources/js/wysiwyg/lexical',
43+
},
3444
banner: {
3545
js: '// See the "/licenses" URI for full package license details',
3646
css: '/* See the "/licenses" URI for full package license details */',

0 commit comments

Comments
 (0)