Skip to content

Commit

Permalink
Fix: Add row needs to initialize new editor instances for inline admi…
Browse files Browse the repository at this point in the history
…ns (#37)
  • Loading branch information
fsbraun authored Dec 10, 2024
1 parent 696b3ee commit 6ce2d5f
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 51 deletions.
1 change: 1 addition & 0 deletions djangocms_text/static/djangocms_text/css/cms.normalize.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ body.change-form .cms-editor-inline-wrapper.fixed {
line-height: 1.5 !important;
h1, h2, h3, h4, h5, h6, p {
margin: 0 0 0.8rem 0 !important;
text-transform: none;
}
h1, h2, h3, h4, h5, h6 {
font-weight: bold;
Expand Down
6 changes: 6 additions & 0 deletions private/css/cms.reset.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,27 @@
}
h1 {
font-size: 1.7rem;
text-transform: none;
}
h2 {
font-size: 1.42rem;
text-transform: none;
}
h3 {
font-size: 1.2rem;
text-transform: none;
}
h4, p {
font-size: 1rem;
text-transform: none;
}
h5 {
font-size: 0.83rem;
text-transform: none;
}
h6 {
font-size: 0.7rem;
text-transform: none;
}
img.float-start {
float: left;
Expand Down
25 changes: 24 additions & 1 deletion private/js/cms.editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ class CMSEditor {
this._generic_editors = [];
this._global_settings = {};
this._editor_settings = {};
this._admin_selector = 'textarea.CMS_Editor';
this._admin_add_row_selector = 'body.change-form .add-row a';
this._inline_admin_selector = 'body.change-form .form-row';

document.addEventListener('DOMContentLoaded', () => {
// Get the CMS object from the parent window
Expand All @@ -39,6 +42,11 @@ class CMSEditor {
}
});
}

if (document.querySelector(this._inline_admin_selector + '.empty-form')) {
// Marker for inline admin form: do **not** initialize empty form templates
this._admin_selector = this._inline_admin_selector + ':not(.empty-form) ' + this._admin_selector;
}
this.initAll();
});
}
Expand All @@ -54,11 +62,26 @@ class CMSEditor {
}

// All textareas with class CMS_Editor: typically on admin site
document.querySelectorAll('textarea.CMS_Editor').forEach(
document.querySelectorAll(this._admin_selector).forEach(
(el) => this.init(el), this
);
// Register all plugins on the page for inline editing
this.initInlineEditors();

// Listen to the add row click for inline admin in a change form
if (this._admin_add_row_selector) {
setTimeout(() => {
for (const el of document.querySelectorAll(this._admin_add_row_selector)) {
el.addEventListener('click', (event) => {
setTimeout(() => {
document.querySelectorAll(this._admin_selector).forEach(
(el) => this.init(el), this
);
}, 0);
});
}
}, 0);
}
}

// CMS Editor: init
Expand Down
4 changes: 1 addition & 3 deletions private/js/cms.linkfield.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,7 @@ class LinkField {
}

handleChange(event) {
console.log("handleChange", event);
if (this.selectElement.value) {
if (this.selectElement.value && this.options.url) {
fetch(this.options.url + '?g=' + encodeURIComponent(this.selectElement.value))
.then(response => response.json())
.then(data => {
Expand All @@ -178,7 +177,6 @@ class LinkField {
}

search(page = 1) {
console.log("search", page);
this.openDropdown();
const searchText = this.inputElement.value.toLowerCase();
this.fetchData(searchText, page).then(response => {
Expand Down
6 changes: 3 additions & 3 deletions tests/integration/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,18 @@ def page(browser_context):


@pytest.fixture
def user(db):
def superuser(db):
from django.contrib.auth import get_user_model

User = get_user_model()
return User.objects.create_user(username="admin", password="admin", is_staff=True, is_superuser=True)


@pytest.fixture
def cms_page(db, user):
def cms_page(db, superuser):
from cms.api import create_page

return create_page("Test Page", "page.html", "en", created_by=user)
return create_page("Test Page", "page.html", "en", created_by=superuser)


@pytest.fixture
Expand Down
28 changes: 28 additions & 0 deletions tests/integration/test_admin_editor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import pytest
from django.urls import reverse

from tests.fixtures import DJANGO_CMS4
from tests.integration.utils import login


@pytest.fixture
def pizza():
from tests.test_app.models import Pizza

return Pizza.objects.create(description="<p>Test pizza</p>")


@pytest.mark.django_db
@pytest.mark.skipif(not DJANGO_CMS4, reason="Integration tests only work on Django CMS 4")
def test_inline_admin_add_row(live_server, page, pizza, superuser):
"""Test that editor loads and initializes properly after user clicks add row button for inline admin"""
login(live_server, page, superuser)

endpoint = reverse("admin:test_app_pizza_change", args=(pizza.pk,))
page.goto(f"{live_server.url}{endpoint}")

assert page.locator(".cms-editor-inline-wrapper.textarea.fixed").count() == 3

page.locator(".add-row a").click()

assert page.locator(".cms-editor-inline-wrapper.textarea.fixed").count() == 4
48 changes: 4 additions & 44 deletions tests/integration/test_text_editor.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,17 @@
from unittest import skipIf

import pytest
from cms.utils.urlutils import admin_reverse
from playwright.sync_api import expect

from tests.fixtures import DJANGO_CMS4


def login(page, live_server):
page.goto(f"{live_server.url}/en/admin/")
page.fill("input[name='username']", "admin")
page.fill("input[name='password']", "admin")
page.click("input[type='submit']")
# Ensure success
expect(page.locator("h1", has_text="Site administration")).to_be_visible()


def get_pagecontent(cms_page):
return cms_page.pagecontent_set(manager="admin_manager").current_content(language="en").first()
from tests.integration.utils import login


@pytest.mark.django_db
@skipIf(not DJANGO_CMS4, reason="Integration tests only work on Django CMS 4")
def test_editor_loads(live_server, page, text_plugin):
@pytest.mark.skipif(not DJANGO_CMS4, reason="Integration tests only work on Django CMS 4")
def test_editor_loads(live_server, page, text_plugin, superuser):
"""Test that tiptap editor loads and initializes properly"""
# Navigate to the text plugin add view
login(page, live_server)
login(live_server, page, superuser)

page.goto(f"{live_server.url}{admin_reverse('cms_placeholder_edit_plugin', args=(text_plugin.pk,))}")

Expand All @@ -39,29 +25,3 @@ def test_editor_loads(live_server, page, text_plugin):
expect(page.locator('button[title="Bold"]')).to_be_visible() # a button in the menu bar

assert tiptap.inner_text() == "Test content"


@pytest.mark.django_db
@skipIf(not DJANGO_CMS4, reason="Integration tests only work on Django CMS 4")
def _test_text_plugin_saves(live_server, page):
"""Test that text plugin content saves correctly"""
# Navigate and login (reusing steps from above)
page.goto(f"{live_server.url}/admin/cms/page/add/")
page.fill("input[name='username']", "admin")
page.fill("input[name='password']", "admin")
page.click("input[type='submit']")

# Add and fill text plugin
page.click("text=Add plugin")
page.click("text=Text")

iframe_locator = page.frame_locator(".cke_wysiwyg_frame")
iframe_locator.locator("body").fill("Content to save")

# Save the plugin
page.click("text=Save")

# Verify saved content
page.reload()
saved_content = iframe_locator.locator("body").inner_text()
assert saved_content == "Content to save"
15 changes: 15 additions & 0 deletions tests/integration/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from playwright.sync_api import expect


def login(live_server, page, superuser):
page.goto(f"{live_server.url}/en/admin/")
if page.locator("input[name='username']").is_visible():
page.fill("input[name='username']", superuser.username)
page.fill("input[name='password']", "admin")
page.click("input[type='submit']")
# Ensure success
expect(page.locator("h1", has_text="Site administration")).to_be_visible()


def get_pagecontent(cms_page):
return cms_page.pagecontent_set(manager="admin_manager").current_content(language="en").first()

0 comments on commit 6ce2d5f

Please sign in to comment.