mirror of
https://github.com/BookStackApp/BookStack.git
synced 2026-02-16 19:06:45 +03:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
94c59c1e3d | ||
|
|
4d2205853a | ||
|
|
18bcafaee4 | ||
|
|
8d07b7cf1c | ||
|
|
080f9c3025 | ||
|
|
617fe6bc8c | ||
|
|
bb1f1a9ecd | ||
|
|
d688e43197 | ||
|
|
c82c3023c5 | ||
|
|
d0d75afc66 | ||
|
|
467176ee78 | ||
|
|
521a002001 | ||
|
|
751772b87a | ||
|
|
76e30869e1 | ||
|
|
f3ee8f2d4c | ||
|
|
ea406690f5 | ||
|
|
465d405926 | ||
|
|
1097c61d6d | ||
|
|
def2d61ad8 | ||
|
|
8b0f5e7000 | ||
|
|
1e88e8086f | ||
|
|
d48ac0a37d |
@@ -238,9 +238,9 @@ DISABLE_EXTERNAL_SERVICES=false
|
||||
# Example: AVATAR_URL=https://seccdn.libravatar.org/avatar/${hash}?s=${size}&d=identicon
|
||||
AVATAR_URL=
|
||||
|
||||
# Enable draw.io integration
|
||||
# Enable diagrams.net integration
|
||||
# Can simply be true/false to enable/disable the integration.
|
||||
# Alternatively, It can be URL to the draw.io instance you want to use.
|
||||
# Alternatively, It can be URL to the diagrams.net instance you want to use.
|
||||
# For URLs, The following URL parameters should be included: embed=1&proto=json&spin=1
|
||||
DRAWIO=true
|
||||
|
||||
|
||||
1
.github/translators.txt
vendored
1
.github/translators.txt
vendored
@@ -122,3 +122,4 @@ fadiapp :: Arabic
|
||||
Jakub Bouček (jakubboucek) :: Czech
|
||||
Marco (cdrfun) :: German
|
||||
10935336 :: Chinese Simplified
|
||||
孟繁阳 (FanyangMeng) :: Chinese Simplified
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
use BookStack\Entities\Page;
|
||||
use DOMDocument;
|
||||
use DOMElement;
|
||||
use DOMNodeList;
|
||||
use DOMXPath;
|
||||
|
||||
@@ -44,18 +43,24 @@ class PageContent
|
||||
$container = $doc->documentElement;
|
||||
$body = $container->childNodes->item(0);
|
||||
$childNodes = $body->childNodes;
|
||||
$xPath = new DOMXPath($doc);
|
||||
|
||||
// Set ids on top-level nodes
|
||||
$idMap = [];
|
||||
foreach ($childNodes as $index => $childNode) {
|
||||
$this->setUniqueId($childNode, $idMap);
|
||||
[$oldId, $newId] = $this->setUniqueId($childNode, $idMap);
|
||||
if ($newId && $newId !== $oldId) {
|
||||
$this->updateLinks($xPath, '#' . $oldId, '#' . $newId);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure no duplicate ids within child items
|
||||
$xPath = new DOMXPath($doc);
|
||||
$idElems = $xPath->query('//body//*//*[@id]');
|
||||
foreach ($idElems as $domElem) {
|
||||
$this->setUniqueId($domElem, $idMap);
|
||||
[$oldId, $newId] = $this->setUniqueId($domElem, $idMap);
|
||||
if ($newId && $newId !== $oldId) {
|
||||
$this->updateLinks($xPath, '#' . $oldId, '#' . $newId);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate inner html as a string
|
||||
@@ -67,23 +72,34 @@ class PageContent
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the all links to the $old location to instead point to $new.
|
||||
*/
|
||||
protected function updateLinks(DOMXPath $xpath, string $old, string $new)
|
||||
{
|
||||
$old = str_replace('"', '', $old);
|
||||
$matchingLinks = $xpath->query('//body//*//*[@href="'.$old.'"]');
|
||||
foreach ($matchingLinks as $domElem) {
|
||||
$domElem->setAttribute('href', $new);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a unique id on the given DOMElement.
|
||||
* A map for existing ID's should be passed in to check for current existence.
|
||||
* @param DOMElement $element
|
||||
* @param array $idMap
|
||||
* Returns a pair of strings in the format [old_id, new_id]
|
||||
*/
|
||||
protected function setUniqueId($element, array &$idMap)
|
||||
protected function setUniqueId(\DOMNode $element, array &$idMap): array
|
||||
{
|
||||
if (get_class($element) !== 'DOMElement') {
|
||||
return;
|
||||
return ['', ''];
|
||||
}
|
||||
|
||||
// Overwrite id if not a BookStack custom id
|
||||
// Stop if there's an existing valid id that has not already been used.
|
||||
$existingId = $element->getAttribute('id');
|
||||
if (strpos($existingId, 'bkmrk') === 0 && !isset($idMap[$existingId])) {
|
||||
$idMap[$existingId] = true;
|
||||
return;
|
||||
return [$existingId, $existingId];
|
||||
}
|
||||
|
||||
// Create an unique id for the element
|
||||
@@ -100,6 +116,7 @@ class PageContent
|
||||
|
||||
$element->setAttribute('id', $newId);
|
||||
$idMap[$newId] = true;
|
||||
return [$existingId, $newId];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
24
package-lock.json
generated
24
package-lock.json
generated
@@ -253,9 +253,9 @@
|
||||
}
|
||||
},
|
||||
"esbuild": {
|
||||
"version": "0.6.30",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.6.30.tgz",
|
||||
"integrity": "sha512-ZSZY461UPzTYYC3rqy1QiMtngk2WyXf+58MgC7tC22jkI90FXNgEl0hN3ipfn/UgZYzTW2GBcHiO7t0rSbHT7g==",
|
||||
"version": "0.7.8",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.7.8.tgz",
|
||||
"integrity": "sha512-6UT1nZB+8ja5avctUC6d3kGOUAhy6/ZYHljL4nk3++1ipadghBhUCAcwsTHsmUvdu04CcGKzo13mE+ZQ2O3zrA==",
|
||||
"dev": true
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
@@ -496,9 +496,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"markdown-it": {
|
||||
"version": "11.0.0",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-11.0.0.tgz",
|
||||
"integrity": "sha512-+CvOnmbSubmQFSA9dKz1BRiaSMV7rhexl3sngKqFyXSagoA3fBdJQ8oZWtRy2knXdpDXaBw44euz37DeJQ9asg==",
|
||||
"version": "11.0.1",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-11.0.1.tgz",
|
||||
"integrity": "sha512-aU1TzmBKcWNNYvH9pjq6u92BML+Hz3h5S/QpfTFwiQF852pLT+9qHsrhM9JYipkOXZxGn+sGH8oyJE9FD9WezQ==",
|
||||
"requires": {
|
||||
"argparse": "^1.0.7",
|
||||
"entities": "~2.0.0",
|
||||
@@ -730,9 +730,9 @@
|
||||
}
|
||||
},
|
||||
"sass": {
|
||||
"version": "1.26.10",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.26.10.tgz",
|
||||
"integrity": "sha512-bzN0uvmzfsTvjz0qwccN1sPm2HxxpNI/Xa+7PlUEMS+nQvbyuEK7Y0qFqxlPHhiNHb1Ze8WQJtU31olMObkAMw==",
|
||||
"version": "1.26.11",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.26.11.tgz",
|
||||
"integrity": "sha512-W1l/+vjGjIamsJ6OnTe0K37U2DBO/dgsv2Z4c89XQ8ZOO6l/VwkqwLSqoYzJeJs6CLuGSTRWc91GbQFL3lvrvw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chokidar": ">=2.0.0 <4.0.0"
|
||||
@@ -777,9 +777,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"sortablejs": {
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.10.2.tgz",
|
||||
"integrity": "sha512-YkPGufevysvfwn5rfdlGyrGjt7/CRHwvRPogD/lC+TnvcN29jDpCifKP+rBqf+LRldfXSTh+0CGLcSg0VIxq3A=="
|
||||
"version": "1.12.0",
|
||||
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.12.0.tgz",
|
||||
"integrity": "sha512-bPn57rCjBRlt2sC24RBsu40wZsmLkSo2XeqG8k6DC1zru5eObQUIPPZAQG7W2SJ8FZQYq+BEJmvuw1Zxb3chqg=="
|
||||
},
|
||||
"spdx-correct": {
|
||||
"version": "3.1.1",
|
||||
|
||||
12
package.json
12
package.json
@@ -4,9 +4,9 @@
|
||||
"build:css:dev": "sass ./resources/sass:./public/dist",
|
||||
"build:css:watch": "sass ./resources/sass:./public/dist --watch",
|
||||
"build:css:production": "sass ./resources/sass:./public/dist -s compressed",
|
||||
"build:js:dev": "esbuild --bundle ./resources/js/index.js --outfile=public/dist/app.js --sourcemap --target=es2020",
|
||||
"build:js:dev": "esbuild --bundle ./resources/js/index.js --outfile=public/dist/app.js --sourcemap --target=es2019 --main-fields=module,main",
|
||||
"build:js:watch": "chokidar \"./resources/**/*.js\" -c \"npm run build:js:dev\"",
|
||||
"build:js:production": "NODE_ENV=production esbuild --bundle ./resources/js/index.js --outfile=public/dist/app.js --sourcemap --minify",
|
||||
"build:js:production": "NODE_ENV=production esbuild --bundle ./resources/js/index.js --outfile=public/dist/app.js --sourcemap --target=es2019 --main-fields=module,main --minify",
|
||||
"build": "npm-run-all --parallel build:*:dev",
|
||||
"production": "npm-run-all --parallel build:*:production",
|
||||
"dev": "npm-run-all --parallel watch livereload",
|
||||
@@ -16,18 +16,18 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"chokidar-cli": "^2.1.0",
|
||||
"esbuild": "0.6.30",
|
||||
"esbuild": "0.7.8",
|
||||
"livereload": "^0.9.1",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"punycode": "^2.1.1",
|
||||
"sass": "^1.26.10"
|
||||
"sass": "^1.26.11"
|
||||
},
|
||||
"dependencies": {
|
||||
"clipboard": "^2.0.6",
|
||||
"codemirror": "^5.58.1",
|
||||
"dropzone": "^5.7.2",
|
||||
"markdown-it": "^11.0.0",
|
||||
"markdown-it": "^11.0.1",
|
||||
"markdown-it-task-lists": "^2.1.1",
|
||||
"sortablejs": "^1.10.2"
|
||||
"sortablejs": "^1.12.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,9 +11,10 @@
|
||||
|
||||
# Redirect Trailing Slashes If Not A Folder...
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule ^(.*)/$ /$1 [L,R=301]
|
||||
RewriteCond %{REQUEST_URI} (.+)/$
|
||||
RewriteRule ^ %1 [L,R=301]
|
||||
|
||||
# Handle Front Controller...
|
||||
# Send Requests To Front Controller...
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^ index.php [L]
|
||||
|
||||
88
public/dist/app.js
vendored
88
public/dist/app.js
vendored
File diff suppressed because one or more lines are too long
@@ -168,6 +168,6 @@ These are the great open-source projects used to help build BookStack:
|
||||
* [Snappy (WKHTML2PDF)](https://github.com/barryvdh/laravel-snappy)
|
||||
* [Laravel IDE helper](https://github.com/barryvdh/laravel-ide-helper)
|
||||
* [WKHTMLtoPDF](http://wkhtmltopdf.org/index.html)
|
||||
* [Draw.io](https://github.com/jgraph/drawio)
|
||||
* [diagrams.net](https://github.com/jgraph/drawio)
|
||||
* [Laravel Stats](https://github.com/stefanzweifel/laravel-stats)
|
||||
* [OneLogin's SAML PHP Toolkit](https://github.com/onelogin/php-saml)
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Sortable, MultiDrag} from "sortablejs";
|
||||
import Sortable from "sortablejs";
|
||||
|
||||
// Auto sort control
|
||||
const sortOperations = {
|
||||
@@ -43,7 +43,6 @@ class BookSort {
|
||||
this.input = elem.querySelector('[book-sort-input]');
|
||||
|
||||
const initialSortBox = elem.querySelector('.sort-box');
|
||||
Sortable.mount(new MultiDrag());
|
||||
this.setupBookSortable(initialSortBox);
|
||||
this.setupSortPresets();
|
||||
|
||||
|
||||
@@ -440,10 +440,10 @@ class MarkdownEditor {
|
||||
|
||||
const data = {
|
||||
image: pngData,
|
||||
uploaded_to: Number(document.getElementById('page-editor').getAttribute('page-id'))
|
||||
uploaded_to: Number(this.pageId),
|
||||
};
|
||||
|
||||
window.$http.post(window.baseUrl('/images/drawio'), data).then(resp => {
|
||||
window.$http.post("/images/drawio", data).then(resp => {
|
||||
this.insertDrawing(resp.data, cursorPos);
|
||||
DrawIO.close();
|
||||
}).catch(err => {
|
||||
@@ -476,10 +476,10 @@ class MarkdownEditor {
|
||||
|
||||
let data = {
|
||||
image: pngData,
|
||||
uploaded_to: Number(document.getElementById('page-editor').getAttribute('page-id'))
|
||||
uploaded_to: Number(this.pageId),
|
||||
};
|
||||
|
||||
window.$http.post(window.baseUrl(`/images/drawio`), data).then(resp => {
|
||||
window.$http.post("/images/drawio", data).then(resp => {
|
||||
let newText = `<div drawio-diagram="${resp.data.id}"><img src="${resp.data.url}"></div>`;
|
||||
let newContent = this.cm.getValue().split('\n').map(line => {
|
||||
if (line.indexOf(`drawio-diagram="${drawingId}"`) !== -1) {
|
||||
|
||||
@@ -26,6 +26,7 @@ import 'codemirror/mode/rust/rust';
|
||||
import 'codemirror/mode/shell/shell';
|
||||
import 'codemirror/mode/sql/sql';
|
||||
import 'codemirror/mode/toml/toml';
|
||||
import 'codemirror/mode/vbscript/vbscript';
|
||||
import 'codemirror/mode/xml/xml';
|
||||
import 'codemirror/mode/yaml/yaml';
|
||||
|
||||
@@ -84,6 +85,8 @@ const modeMap = {
|
||||
bash: 'shell',
|
||||
toml: 'toml',
|
||||
sql: 'text/x-sql',
|
||||
vbs: 'vbscript',
|
||||
vbscript: 'vbscript',
|
||||
xml: 'xml',
|
||||
yaml: 'yaml',
|
||||
yml: 'yaml',
|
||||
|
||||
@@ -141,10 +141,14 @@ async function request(url, options = {}) {
|
||||
/**
|
||||
* Get the content from a fetch response.
|
||||
* Checks the content-type header to determine the format.
|
||||
* @param response
|
||||
* @param {Response} response
|
||||
* @returns {Promise<Object|String>}
|
||||
*/
|
||||
async function getResponseContent(response) {
|
||||
if (response.status === 204) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const responseContentType = response.headers.get('Content-Type');
|
||||
const subType = responseContentType.split('/').pop();
|
||||
|
||||
|
||||
@@ -179,7 +179,7 @@ return [
|
||||
'user_api_token_name_desc' => 'Dale a tu token un nombre legible como un recordatorio futuro de su propósito.',
|
||||
'user_api_token_expiry' => 'Fecha de expiración',
|
||||
'user_api_token_expiry_desc' => 'Establece una fecha en la que este token expira. Después de esta fecha, las solicitudes realizadas usando este token ya no funcionarán. Dejar este campo en blanco fijará un vencimiento de 100 años en el futuro.',
|
||||
'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.',
|
||||
'user_api_token_create_secret_message' => 'Inmediatamente después de crear este token se generarán y mostrarán sus correspondientes "Token ID" y "Token Secret". El "Token Secret" sólo se mostrará una vez, así que asegúrese de copiar el valor a un lugar seguro antes de proceder.',
|
||||
'user_api_token_create_success' => 'Token API creado correctamente',
|
||||
'user_api_token_update_success' => 'Token API actualizado correctamente',
|
||||
'user_api_token' => 'Token API',
|
||||
@@ -187,8 +187,8 @@ return [
|
||||
'user_api_token_id_desc' => 'Este es un identificador no editable generado por el sistema y único para este token que necesitará ser proporcionado en solicitudes de API.',
|
||||
'user_api_token_secret' => 'Token Secret',
|
||||
'user_api_token_secret_desc' => 'Esta es una clave no editable generada por el sistema que necesitará ser proporcionada en solicitudes de API. Solo se monstraré esta vez así que guarde su valor en un lugar seguro.',
|
||||
'user_api_token_created' => 'Token created :timeAgo',
|
||||
'user_api_token_updated' => 'Token updated :timeAgo',
|
||||
'user_api_token_created' => 'Token creado :timeAgo',
|
||||
'user_api_token_updated' => 'Token actualizado :timeAgo',
|
||||
'user_api_token_delete' => 'Borrar token',
|
||||
'user_api_token_delete_warning' => 'Esto eliminará completamente este token API con el nombre \':tokenName\' del sistema.',
|
||||
'user_api_token_delete_confirm' => '¿Está seguro de que desea borrar este API token?',
|
||||
|
||||
@@ -57,7 +57,7 @@ return [
|
||||
'reg_enable_desc' => '启用注册后,用户将可以自己注册为站点用户。 注册后,他们将获得一个默认的单一用户角色。',
|
||||
'reg_default_role' => '注册后的默认用户角色',
|
||||
'reg_enable_external_warning' => '当启用外部LDAP或者SAML认证时,上面的选项会被忽略。当使用外部系统认证认证成功时,将自动创建非现有会员的用户账户。',
|
||||
'reg_email_confirmation' => '邮箱确认n',
|
||||
'reg_email_confirmation' => '邮件确认',
|
||||
'reg_email_confirmation_toggle' => '需要电子邮件确认',
|
||||
'reg_confirm_email_desc' => '如果使用域名限制,则需要Email验证,并且该值将被忽略。',
|
||||
'reg_confirm_restrict_domain' => '域名限制',
|
||||
@@ -92,8 +92,8 @@ return [
|
||||
'audit_table_event' => '事件',
|
||||
'audit_table_item' => '相关项目',
|
||||
'audit_table_date' => '活动日期',
|
||||
'audit_date_from' => 'Date Range From',
|
||||
'audit_date_to' => 'Date Range To',
|
||||
'audit_date_from' => '日期范围从',
|
||||
'audit_date_to' => '日期范围至',
|
||||
|
||||
// Role Settings
|
||||
'roles' => '角色',
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<div component="ajax-form"
|
||||
option:ajax-form:url="/attachments/{{ $attachment->id }}"
|
||||
option:ajax-form:method="put"
|
||||
option:ajax-form:response-container=".attachment-edit-container"
|
||||
option:ajax-form:success-message="{{ trans('entities.attachments_updated_success') }}">
|
||||
<h5>{{ trans('entities.attachments_edit_file') }}</h5>
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<div component="ajax-form"
|
||||
option:ajax-form:url="/attachments/link"
|
||||
option:ajax-form:method="post"
|
||||
option:ajax-form:response-container=".link-form-container"
|
||||
option:ajax-form:success-message="{{ trans('entities.attachments_link_attached') }}">
|
||||
<input type="hidden" name="attachment_link_uploaded_to" value="{{ $pageId }}">
|
||||
<p class="text-muted small">{{ trans('entities.attachments_explain_link') }}</p>
|
||||
|
||||
@@ -24,14 +24,14 @@
|
||||
'successMessage' => trans('entities.attachments_file_uploaded'),
|
||||
])
|
||||
</div>
|
||||
<div refs="tabs@contentLinks" class="hidden">
|
||||
<div refs="tabs@contentLinks" class="hidden link-form-container">
|
||||
@include('attachments.manager-link-form', ['pageId' => $page->id])
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div refs="attachments@editContainer" class="hidden">
|
||||
<div refs="attachments@editContainer" class="hidden attachment-edit-container">
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
<a refs="code-editor@languageLink" data-lang="Ruby">Ruby</a>
|
||||
<a refs="code-editor@languageLink" data-lang="shell">Shell/Bash</a>
|
||||
<a refs="code-editor@languageLink" data-lang="SQL">SQL</a>
|
||||
<a refs="code-editor@languageLink" data-lang="VBScript">VBScript</a>
|
||||
<a refs="code-editor@languageLink" data-lang="XML">XML</a>
|
||||
<a refs="code-editor@languageLink" data-lang="YAML">YAML</a>
|
||||
</small>
|
||||
@@ -66,4 +67,4 @@
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div component="page-editor" class="page-editor flex-fill flex"
|
||||
option:page-editor:drafts-enabled="{{ $draftsEnabled ? 'true' : 'false' }}"
|
||||
@if(config('services.drawio'))
|
||||
drawio-url="{{ is_string(config('services.drawio')) ? config('services.drawio') : 'https://www.draw.io/?embed=1&proto=json&spin=1' }}"
|
||||
drawio-url="{{ is_string(config('services.drawio')) ? config('services.drawio') : 'https://embed.diagrams.net/?embed=1&proto=json&spin=1' }}"
|
||||
@endif
|
||||
@if($model->name === trans('entities.pages_initial_name'))
|
||||
option:page-editor:has-default-title="true"
|
||||
|
||||
@@ -196,24 +196,6 @@ class Saml2Test extends TestCase
|
||||
});
|
||||
}
|
||||
|
||||
public function test_user_registration_with_existing_email()
|
||||
{
|
||||
config()->set([
|
||||
'saml2.onelogin.strict' => false,
|
||||
]);
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
$viewer->email = 'user@example.com';
|
||||
$viewer->save();
|
||||
|
||||
$this->withPost(['SAMLResponse' => $this->acsPostData], function () {
|
||||
$acsPost = $this->post('/saml2/acs');
|
||||
$acsPost->assertRedirect('/');
|
||||
$errorMessage = session()->get('error');
|
||||
$this->assertEquals('A user with the email user@example.com already exists but with different credentials.', $errorMessage);
|
||||
});
|
||||
}
|
||||
|
||||
public function test_saml_routes_are_only_active_if_saml_enabled()
|
||||
{
|
||||
config()->set(['auth.method' => 'standard']);
|
||||
|
||||
@@ -262,6 +262,23 @@ class PageContentTest extends TestCase
|
||||
$this->assertEquals(substr_count($updatedPage->html, "bkmrk-test\""), 1);
|
||||
}
|
||||
|
||||
public function test_anchors_referencing_non_bkmrk_ids_rewritten_after_save()
|
||||
{
|
||||
$this->asEditor();
|
||||
$page = Page::first();
|
||||
|
||||
$content = '<h1 id="non-standard-id">test</h1><p><a href="#non-standard-id">link</a></p>';
|
||||
$this->put($page->getUrl(), [
|
||||
'name' => $page->name,
|
||||
'html' => $content,
|
||||
'summary' => ''
|
||||
]);
|
||||
|
||||
$updatedPage = Page::where('id', '=', $page->id)->first();
|
||||
$this->assertStringContainsString('id="bkmrk-test"', $updatedPage->html);
|
||||
$this->assertStringContainsString('href="#bkmrk-test"', $updatedPage->html);
|
||||
}
|
||||
|
||||
public function test_get_page_nav_sets_correct_properties()
|
||||
{
|
||||
$content = '<h1 id="testa">Hello</h1><h2 id="testb">There</h2><h3 id="testc">Donkey</h3>';
|
||||
|
||||
@@ -69,7 +69,7 @@ class DrawioTest extends TestCase
|
||||
$editor = $this->getEditor();
|
||||
|
||||
$resp = $this->actingAs($editor)->get($page->getUrl('/edit'));
|
||||
$resp->assertSee('drawio-url="https://www.draw.io/?embed=1&proto=json&spin=1"');
|
||||
$resp->assertSee('drawio-url="https://embed.diagrams.net/?embed=1&proto=json&spin=1"');
|
||||
|
||||
config()->set('services.drawio', false);
|
||||
$resp = $this->actingAs($editor)->get($page->getUrl('/edit'));
|
||||
|
||||
Reference in New Issue
Block a user