feat: améliorer la synchronisation des métadonnées asynchrones avec indicateurs de chargement visuels, polling pour synchroniser textarea vers Toast UI Editor, correction du chemin du script metadata.min.js avec base_path, et ajout de conteneurs d'icônes loader pour titre, description et tags avec activation conditionnelle selon retrieve_description
This commit is contained in:
parent
5bf384a8d6
commit
9150877d57
@ -54,13 +54,15 @@
|
||||
<label class="form-label" for="lf_title{$index}">{'Title'|t}</label>
|
||||
<div class="{$asyncLoadClass}">
|
||||
<input type="text" class="form-control lf_input{if="empty($batch_mode) && $link.title==''"} autofocus{/if}" name="lf_title" id="lf_title{$index}" value="{$link.title}" placeholder="Page title">
|
||||
<div class="icon-container"><i class="loader"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group bookmark-field-group">
|
||||
<label class="form-label" for="lf_description{$index}">{'Description'|t} (Markdown)</label>
|
||||
<div class="{$asyncLoadClass}">
|
||||
<div class="{if="$retrieve_description"}{$asyncLoadClass}{/if}">
|
||||
<textarea class="form-control bookmark-editor-source{if="empty($batch_mode) && $link.description==''"} autofocus{/if}" name="lf_description" id="lf_description{$index}" placeholder="Add a description..." rows="6">{$link.description}</textarea>
|
||||
<div id="lf_description_editor{$index}" class="bookmark-markdown-editor" aria-label="Markdown editor"></div>
|
||||
<div class="icon-container"><i class="loader"></i></div>
|
||||
</div>
|
||||
{if="$formatter==='markdown'"}
|
||||
<div class="sublabel bookmark-editor-sublabel">
|
||||
@ -70,12 +72,13 @@
|
||||
</div>
|
||||
<div class="form-group bookmark-field-group">
|
||||
<label class="form-label" for="lf_tags{$index}">{'Tags'|t}</label>
|
||||
<div class="{$asyncLoadClass}">
|
||||
<div class="{if="$retrieve_description"}{$asyncLoadClass}{/if}">
|
||||
<input type="text" class="bookmark-tags-hidden-input" id="lf_tags{$index}" name="lf_tags" value="{$effectiveTags}" data-tag-options="{loop="$tags"}{$key},{/loop}" autocomplete="off" />
|
||||
<div class="bookmark-tags-input" data-tags-container="lf_tags{$index}">
|
||||
<div class="bookmark-tags-list" id="bookmark-tags-list{$index}"></div>
|
||||
<input type="text" class="bookmark-tags-text-input" id="bookmark-tags-text{$index}" placeholder="Type a tag and press Enter or Space" autocomplete="off" />
|
||||
</div>
|
||||
<div class="icon-container"><i class="loader"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -121,7 +124,7 @@
|
||||
</div>
|
||||
{if="empty($batch_mode)"}
|
||||
{include="page.footer"}
|
||||
{if="$link_is_new && $async_metadata"}<script src="{$index_url}js/metadata.min.js?v={$version_hash}"></script>{/if}
|
||||
{if="$link_is_new && $async_metadata"}<script src="{$base_path}/{function="ltrim($asset_path, '/')"}/js/metadata.min.js?v={$version_hash}"></script>{/if}
|
||||
{/if}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
62
shaarli-pro/js/metadata.min.js
vendored
Normal file
62
shaarli-pro/js/metadata.min.js
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
(function () {
|
||||
var loaded = false;
|
||||
var tried = {};
|
||||
|
||||
function toAbsolute(url) {
|
||||
try {
|
||||
return new URL(url, window.location.href).toString();
|
||||
} catch (e) {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
function loadNext(candidates, index) {
|
||||
if (loaded || index >= candidates.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var src = toAbsolute(candidates[index]);
|
||||
if (tried[src]) {
|
||||
loadNext(candidates, index + 1);
|
||||
return;
|
||||
}
|
||||
tried[src] = true;
|
||||
|
||||
var script = document.createElement('script');
|
||||
script.src = src;
|
||||
script.async = false;
|
||||
script.onload = function () {
|
||||
loaded = true;
|
||||
};
|
||||
script.onerror = function () {
|
||||
script.remove();
|
||||
loadNext(candidates, index + 1);
|
||||
};
|
||||
document.head.appendChild(script);
|
||||
}
|
||||
|
||||
var rootPath = (window.shaarli && window.shaarli.rootPath) || '';
|
||||
var basePath = (window.shaarli && window.shaarli.basePath) || '';
|
||||
var assetPath = (window.shaarli && window.shaarli.assetPath) || '';
|
||||
|
||||
var candidates = [];
|
||||
|
||||
if (assetPath) {
|
||||
candidates.push(assetPath.replace(/\/tpl\/shaarli-pro\/?$/, '/tpl/default') + '/js/metadata.min.js');
|
||||
}
|
||||
|
||||
if (basePath) {
|
||||
candidates.push(basePath + '/tpl/default/js/metadata.min.js');
|
||||
candidates.push(basePath + '/js/metadata.min.js');
|
||||
}
|
||||
|
||||
if (rootPath) {
|
||||
candidates.push(rootPath + '/tpl/default/js/metadata.min.js');
|
||||
candidates.push(rootPath + '/js/metadata.min.js');
|
||||
}
|
||||
|
||||
candidates.push('/js/metadata.min.js');
|
||||
candidates.push('/tpl/default/js/metadata.min.js');
|
||||
|
||||
loadNext(candidates, 0);
|
||||
})();
|
||||
@ -1177,6 +1177,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
// Markdown editor
|
||||
if (descriptionSource && editorMount && window.toastui && window.toastui.Editor) {
|
||||
const previewStyle = window.innerWidth < 992 ? 'tab' : 'vertical';
|
||||
let sourceSyncTimer = null;
|
||||
|
||||
const markdownEditor = new window.toastui.Editor({
|
||||
el: editorMount,
|
||||
@ -1189,7 +1190,26 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
usageStatistics: false,
|
||||
});
|
||||
|
||||
// Shaarli metadata script updates the textarea value asynchronously.
|
||||
// Mirror that value into Toast UI only if the editor is still empty.
|
||||
sourceSyncTimer = window.setInterval(() => {
|
||||
const sourceValue = (descriptionSource.value || '').trim();
|
||||
if (!sourceValue) return;
|
||||
|
||||
const editorValue = (markdownEditor.getMarkdown() || '').trim();
|
||||
if (!editorValue) {
|
||||
markdownEditor.setMarkdown(descriptionSource.value || '', false);
|
||||
}
|
||||
|
||||
window.clearInterval(sourceSyncTimer);
|
||||
sourceSyncTimer = null;
|
||||
}, 250);
|
||||
|
||||
form.addEventListener('submit', () => {
|
||||
if (sourceSyncTimer) {
|
||||
window.clearInterval(sourceSyncTimer);
|
||||
sourceSyncTimer = null;
|
||||
}
|
||||
descriptionSource.value = markdownEditor.getMarkdown();
|
||||
});
|
||||
} else if (editorMount) {
|
||||
|
||||
@ -43,6 +43,8 @@
|
||||
});
|
||||
</script>
|
||||
{/if}
|
||||
|
||||
<input type="hidden" name="js_base_path" value="{$base_path}" />
|
||||
</footer>
|
||||
</div>
|
||||
<!-- Bulk Actions Bar (for multi-select) -->
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user