Hacky "fix" for 4.1.1 support for now
This commit is contained in:
parent
c32a8d7498
commit
ad7facef5c
4 changed files with 342 additions and 225 deletions
|
@ -1,13 +1,13 @@
|
|||
from django.apps import apps
|
||||
from django.template.loader import render_to_string
|
||||
|
||||
from draftjs_exporter.dom import DOM
|
||||
from wagtail.admin.rich_text.converters.contentstate_models import Entity
|
||||
from wagtail.admin.rich_text.converters.html_to_contentstate import LinkElementHandler, AtomicBlockEntityElementHandler
|
||||
from wagtail.admin.rich_text.converters.html_to_contentstate import (
|
||||
AtomicBlockEntityElementHandler, LinkElementHandler)
|
||||
from wagtail.core.rich_text import EmbedHandler, LinkHandler
|
||||
|
||||
from .utils import get_snippet_link_frontend_template, get_snippet_embed_frontend_template
|
||||
|
||||
from .utils import (get_snippet_embed_frontend_template,
|
||||
get_snippet_link_frontend_template)
|
||||
|
||||
# Snippet Link
|
||||
|
||||
|
|
|
@ -1,13 +1,19 @@
|
|||
SNIPPET_MODEL_CHOOSER_MODAL_ONLOAD_HANDLERS = {
|
||||
'choose': function(modal, jsonData) {
|
||||
choose: function (modal, jsonData) {
|
||||
function getSelectedModelMeta(context) {
|
||||
$('a.snippet-model-choice', modal.body).on('click', function(event) {
|
||||
$("a.snippet-model-choice", modal.body).on(
|
||||
"click",
|
||||
function (event) {
|
||||
event.preventDefault();
|
||||
let modelMeta = {'appName': this.dataset.appName, 'modelName': this.dataset.modelName};
|
||||
modal.respond('snippetModelChosen', modelMeta);
|
||||
let modelMeta = {
|
||||
appName: this.dataset.appName,
|
||||
modelName: this.dataset.modelName,
|
||||
};
|
||||
modal.respond("snippetModelChosen", modelMeta);
|
||||
modal.close();
|
||||
$(".modal-backdrop").remove();
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
getSelectedModelMeta(modal.body);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
(() => {
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
const React = window.React;
|
||||
const Modifier = window.DraftJS.Modifier;
|
||||
|
@ -12,29 +12,103 @@
|
|||
const global = globalThis;
|
||||
const $ = global.jQuery;
|
||||
|
||||
global.TEST_SNIPPET_CHOOSER_MODAL_ONLOAD_HANDLERS = {
|
||||
choose: function (modal, jsonData) {
|
||||
function ajaxifyLinks(context) {
|
||||
$("a.snippet-choice", modal.body).on("click", function () {
|
||||
modal.loadUrl(this.href);
|
||||
return false;
|
||||
});
|
||||
|
||||
$("[data-chooser-modal-choice]", context).on(
|
||||
"click",
|
||||
function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
global.TEST_SNIPPET_CHOOSER_MODAL_ONLOAD_HANDLERS.chosen(
|
||||
modal,
|
||||
modal.loadUrl(this.href)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
$(".pagination a", context).on("click", function () {
|
||||
loadResults(this.href);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
var searchForm$ = $("form.search-bar", modal.body);
|
||||
var searchUrl = searchForm$.attr("action");
|
||||
var request;
|
||||
|
||||
function search() {
|
||||
loadResults(searchUrl, searchForm$.serialize());
|
||||
return false;
|
||||
}
|
||||
|
||||
function loadResults(url, data) {
|
||||
var opts = {
|
||||
url: url,
|
||||
success: function (data, status) {
|
||||
request = null;
|
||||
$("#search-results").html(data);
|
||||
ajaxifyLinks($("#search-results"));
|
||||
},
|
||||
error: function () {
|
||||
request = null;
|
||||
},
|
||||
};
|
||||
if (data) {
|
||||
opts.data = data;
|
||||
}
|
||||
request = $.ajax(opts);
|
||||
}
|
||||
|
||||
searchForm$.on("submit", search);
|
||||
$("#snippet-chooser-locale", modal.body).on("change", search);
|
||||
|
||||
$("#id_q").on("input", function () {
|
||||
if (request) {
|
||||
request.abort();
|
||||
}
|
||||
clearTimeout($.data(this, "timer"));
|
||||
var wait = setTimeout(search, 200);
|
||||
$(this).data("timer", wait);
|
||||
});
|
||||
|
||||
ajaxifyLinks(modal.body);
|
||||
},
|
||||
chosen: function (modal, jsonData) {
|
||||
// alert(`SNIPPET CHOSEN`);
|
||||
if (jsonData) {
|
||||
modal.respond("snippetChosen", jsonData["result"]);
|
||||
modal.close();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const MUTABILITY = {};
|
||||
MUTABILITY['SNIPPET'] = 'MUTABLE';
|
||||
MUTABILITY['SNIPPET-EMBED'] = 'IMMUTABLE';
|
||||
MUTABILITY["SNIPPET"] = "MUTABLE";
|
||||
MUTABILITY["SNIPPET-EMBED"] = "IMMUTABLE";
|
||||
|
||||
const getSnippetModelChooserConfig = (entityType) => {
|
||||
let url;
|
||||
let urlParams;
|
||||
|
||||
if (entityType.type === 'SNIPPET') {
|
||||
if (entityType.type === "SNIPPET") {
|
||||
return {
|
||||
url: global.chooserUrls.snippetLinkModelChooser,
|
||||
urlParams: {},
|
||||
onload: global.SNIPPET_MODEL_CHOOSER_MODAL_ONLOAD_HANDLERS,
|
||||
};
|
||||
}
|
||||
else if (entityType.type === 'SNIPPET-EMBED') {
|
||||
} else if (entityType.type === "SNIPPET-EMBED") {
|
||||
return {
|
||||
url: global.chooserUrls.snippetEmbedModelChooser,
|
||||
urlParams: {},
|
||||
onload: global.SNIPPET_MODEL_CHOOSER_MODAL_ONLOAD_HANDLERS,
|
||||
};
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return {
|
||||
url: null,
|
||||
urlParams: {},
|
||||
|
@ -48,9 +122,14 @@
|
|||
let urlParams;
|
||||
|
||||
return {
|
||||
url: global.chooserUrls.snippetChooser.concat(window.snippetModelMeta.appName, '/', window.snippetModelMeta.modelName, '/'),
|
||||
url: global.chooserUrls.snippetChooser.concat(
|
||||
window.snippetModelMeta.appName,
|
||||
"/",
|
||||
window.snippetModelMeta.modelName,
|
||||
"/"
|
||||
),
|
||||
urlParams: {},
|
||||
onload: global.SNIPPET_CHOOSER_MODAL_ONLOAD_HANDLERS,
|
||||
onload: TEST_SNIPPET_CHOOSER_MODAL_ONLOAD_HANDLERS,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -79,9 +158,10 @@
|
|||
|
||||
componentDidMount() {
|
||||
const { onClose, entityType, entity, editorState } = this.props;
|
||||
const { url, urlParams, onload } = getSnippetModelChooserConfig(entityType);
|
||||
const { url, urlParams, onload } =
|
||||
getSnippetModelChooserConfig(entityType);
|
||||
|
||||
$(document.body).on('hidden.bs.modal', this.onClose);
|
||||
$(document.body).on("hidden.bs.modal", this.onClose);
|
||||
|
||||
// eslint-disable-next-line new-cap
|
||||
this.model_workflow = global.ModalWorkflow({
|
||||
|
@ -103,12 +183,13 @@
|
|||
this.model_workflow = null;
|
||||
this.workflow = null;
|
||||
|
||||
$(document.body).off('hidden.bs.modal', this.onClose);
|
||||
$(document.body).off("hidden.bs.modal", this.onClose);
|
||||
}
|
||||
|
||||
onModelChosen(snippetModelMeta) {
|
||||
window.snippetModelMeta = snippetModelMeta;
|
||||
const { url, urlParams, onload } = getSnippetModelObjectChooserConfig();
|
||||
const { url, urlParams, onload } =
|
||||
getSnippetModelObjectChooserConfig();
|
||||
|
||||
this.model_workflow.close();
|
||||
|
||||
|
@ -119,6 +200,7 @@
|
|||
onload,
|
||||
responses: {
|
||||
snippetChosen: this.onChosen,
|
||||
chosen: this.onChosen,
|
||||
},
|
||||
onError: () => {
|
||||
// eslint-disable-next-line no-alert
|
||||
|
@ -135,7 +217,11 @@
|
|||
|
||||
const entityData = filterSnippetEntityData(entityType, data);
|
||||
const mutability = MUTABILITY[entityType.type];
|
||||
const contentWithEntity = content.createEntity(entityType.type, mutability, entityData);
|
||||
const contentWithEntity = content.createEntity(
|
||||
entityType.type,
|
||||
mutability,
|
||||
entityData
|
||||
);
|
||||
const entityKey = contentWithEntity.getLastCreatedEntityKey();
|
||||
|
||||
let nextState;
|
||||
|
@ -144,18 +230,38 @@
|
|||
// Only supports adding entities at the moment, not editing existing ones.
|
||||
// See https://github.com/springload/draftail/blob/cdc8988fe2e3ac32374317f535a5338ab97e8637/examples/sources/ImageSource.js#L44-L62.
|
||||
// See https://github.com/springload/draftail/blob/cdc8988fe2e3ac32374317f535a5338ab97e8637/examples/sources/EmbedSource.js#L64-L91
|
||||
nextState = AtomicBlockUtils.insertAtomicBlock(editorState, entityKey, ' ');
|
||||
nextState = AtomicBlockUtils.insertAtomicBlock(
|
||||
editorState,
|
||||
entityKey,
|
||||
" "
|
||||
);
|
||||
} else {
|
||||
// Replace text if the chooser demands it, or if there is no selected text in the first place.
|
||||
const shouldReplaceText = data.prefer_this_title_as_link_text || selection.isCollapsed();
|
||||
const shouldReplaceText =
|
||||
data.prefer_this_title_as_link_text ||
|
||||
selection.isCollapsed();
|
||||
|
||||
if (shouldReplaceText) {
|
||||
// If there is a title attribute, use it. Otherwise we inject the URL.
|
||||
const newText = data.string;
|
||||
const newContent = Modifier.replaceText(content, selection, newText, null, entityKey);
|
||||
nextState = EditorState.push(editorState, newContent, 'insert-characters');
|
||||
const newContent = Modifier.replaceText(
|
||||
content,
|
||||
selection,
|
||||
newText,
|
||||
null,
|
||||
entityKey
|
||||
);
|
||||
nextState = EditorState.push(
|
||||
editorState,
|
||||
newContent,
|
||||
"insert-characters"
|
||||
);
|
||||
} else {
|
||||
nextState = RichUtils.toggleLink(editorState, selection, entityKey);
|
||||
nextState = RichUtils.toggleLink(
|
||||
editorState,
|
||||
selection,
|
||||
entityKey
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -181,12 +287,14 @@
|
|||
}
|
||||
}
|
||||
|
||||
const SnippetLink = props => {
|
||||
const SnippetLink = (props) => {
|
||||
const { entityKey, contentState } = props;
|
||||
const data = contentState.getEntity(entityKey).getData();
|
||||
|
||||
let icon = React.createElement(window.wagtail.components.Icon, {name: 'snippet'});
|
||||
let label = data.string || '';
|
||||
let icon = React.createElement(window.wagtail.components.Icon, {
|
||||
name: "snippet",
|
||||
});
|
||||
let label = data.string || "";
|
||||
|
||||
return React.createElement(TooltipEntity, {
|
||||
entityKey: props.entityKey,
|
||||
|
@ -194,30 +302,37 @@
|
|||
onEdit: props.onEdit,
|
||||
onRemove: props.onRemove,
|
||||
icon: icon,
|
||||
label: label
|
||||
label: label,
|
||||
});
|
||||
};
|
||||
|
||||
const SnippetEmbed = props => {
|
||||
const SnippetEmbed = (props) => {
|
||||
const { entity, onRemoveEntity, entityKey } = props.blockProps;
|
||||
const data = entity.getData();
|
||||
|
||||
let icon = React.createElement(window.wagtail.components.Icon, {name: 'snippet'});
|
||||
let label = data.string || '';
|
||||
let icon = React.createElement(window.wagtail.components.Icon, {
|
||||
name: "snippet",
|
||||
});
|
||||
let label = data.string || "";
|
||||
|
||||
return React.createElement("div", {
|
||||
class: "MediaBlock"
|
||||
}, icon, `${label}`);
|
||||
return React.createElement(
|
||||
"div",
|
||||
{
|
||||
class: "MediaBlock",
|
||||
},
|
||||
icon,
|
||||
`${label}`
|
||||
);
|
||||
};
|
||||
|
||||
window.draftail.registerPlugin({
|
||||
type: 'SNIPPET',
|
||||
type: "SNIPPET",
|
||||
source: SnippetModalWorkflowSource,
|
||||
decorator: SnippetLink,
|
||||
});
|
||||
|
||||
window.draftail.registerPlugin({
|
||||
type: 'SNIPPET-EMBED',
|
||||
type: "SNIPPET-EMBED",
|
||||
source: SnippetModalWorkflowSource,
|
||||
block: SnippetEmbed,
|
||||
});
|
||||
|
|
|
@ -1,18 +1,14 @@
|
|||
from django.urls import include, path
|
||||
from django.urls import reverse
|
||||
from django.urls import include, path, reverse
|
||||
from django.utils.html import format_html
|
||||
from django.utils.translation import gettext
|
||||
|
||||
from wagtail.admin.rich_text.editors.draftail import features as draftail_features
|
||||
from wagtail.admin.rich_text.editors.draftail import \
|
||||
features as draftail_features
|
||||
from wagtail.core import hooks
|
||||
|
||||
from . import urls
|
||||
from .richtext import (
|
||||
from .richtext import (ContentstateSnippetEmbedConversionRule,
|
||||
ContentstateSnippetLinkConversionRule,
|
||||
ContentstateSnippetEmbedConversionRule,
|
||||
SnippetLinkHandler,
|
||||
SnippetEmbedHandler,
|
||||
)
|
||||
SnippetEmbedHandler, SnippetLinkHandler)
|
||||
|
||||
|
||||
@hooks.register("register_rich_text_features")
|
||||
|
@ -28,7 +24,7 @@ def register_snippet_link_feature(features):
|
|||
draftail_features.EntityFeature(
|
||||
{"type": type_, "icon": "snippet", "description": gettext("Snippet Link")},
|
||||
js=[
|
||||
"wagtailsnippets/js/snippet-chooser-modal.js",
|
||||
"wagtailsnippets/js/snippet-chooser.js",
|
||||
"wagtail_draftail_snippet/js/snippet-model-chooser-modal.js",
|
||||
"wagtail_draftail_snippet/js/wagtail-draftail-snippet.js",
|
||||
],
|
||||
|
@ -53,7 +49,7 @@ def register_snippet_embed_feature(features):
|
|||
draftail_features.EntityFeature(
|
||||
{"type": type_, "icon": "code", "description": gettext("Snippet Embed")},
|
||||
js=[
|
||||
"wagtailsnippets/js/snippet-chooser-modal.js",
|
||||
"wagtailsnippets/js/snippet-chooser.js",
|
||||
"wagtail_draftail_snippet/js/snippet-model-chooser-modal.js",
|
||||
"wagtail_draftail_snippet/js/wagtail-draftail-snippet.js",
|
||||
],
|
||||
|
|
Reference in a new issue