diff --git a/.coveragerc b/.coveragerc index e7ca5551..46a3d86d 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,6 +1,8 @@ [run] branch = True -source = djangocms_text_ckeditor +source = + djangocms_text + djangocms_text_ckeditor omit = migrations/* tests/* diff --git a/.github/workflows/publish-to-live-pypi.yml b/.github/workflows/publish-to-live-pypi.yml index 1607f772..e20962ed 100644 --- a/.github/workflows/publish-to-live-pypi.yml +++ b/.github/workflows/publish-to-live-pypi.yml @@ -22,6 +22,13 @@ jobs: pip install build --user + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Install dependencies + run: npm install + - name: Build client + run: webpack --mode production - name: Build a binary wheel and a source tarball run: >- python -m diff --git a/.github/workflows/publish-to-test-pypi.yml b/.github/workflows/publish-to-test-pypi.yml index d590f480..9ab14a10 100644 --- a/.github/workflows/publish-to-test-pypi.yml +++ b/.github/workflows/publish-to-test-pypi.yml @@ -3,7 +3,7 @@ name: Publish Python 🐍 distributions 📦 to TestPyPI on: push: branches: - - master + - main jobs: build-n-publish: @@ -11,10 +11,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@master - - name: Set up Python 3.9 + - name: Set up Python 3.12 uses: actions/setup-python@v1 with: - python-version: 3.9 + python-version: 3.12 - name: Install pypa/build run: >- @@ -22,6 +22,14 @@ jobs: pip install build --user + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Install dependencies + run: npm install + - name: Build client + run: webpack --mode production + - name: Build a binary wheel and a source tarball run: >- python -m diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8647eebd..b25a8d1f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,10 +8,8 @@ jobs: strategy: fail-fast: false matrix: - python-version: [ "3.10", "3.11"] + python-version: [ "3.10", "3.11", "3.12"] requirements-file: [ - dj32_cms311.txt, - dj32_cms41.txt, dj42_cms311.txt, dj42_cms41.txt, dj50_cms41.txt diff --git a/README.rst b/README.rst index 04d07575..bfa484b6 100644 --- a/README.rst +++ b/README.rst @@ -731,7 +731,7 @@ Old djangocms-text-ckeditor readme: :target: http://badge.fury.io/py/djangocms-text .. |coverage| image:: https://codecov.io/gh/django-cms/djangocms-text/branch/main/graph/badge.svg :target: https://codecov.io/gh/django-cms/djangocms-text -.. |python| image:: https://img.shields.io/badge/python-3.7+-blue.svg +.. |python| image:: https://img.shields.io/badge/python-3.10+-blue.svg :target: https://pypi.org/project/djangocms-text/ .. |django| image:: https://img.shields.io/badge/django-3.2--5.0-blue.svg :target: https://www.djangoproject.com/ diff --git a/djangocms_text/cms_plugins.py b/djangocms_text/cms_plugins.py index 2d7eaabf..3b4869b8 100644 --- a/djangocms_text/cms_plugins.py +++ b/djangocms_text/cms_plugins.py @@ -587,6 +587,14 @@ def get_child_plugin_candidates(cls, slot, page): ] return text_enabled_plugins + def render_plugin_icon(self, plugin): + icon = getattr(plugin, "text_icon", None) + if icon is None: + return + if "cms-icon" in icon: + return f'' + return icon + def get_plugins(self, obj=None): plugin = getattr(self, "cms_plugin_instance", None) or obj if not plugin: @@ -614,7 +622,7 @@ def get_plugins(self, obj=None): { "value": plugin.value, "name": names.get(plugin.value, plugin.name), - "icon": getattr(plugin, "text_icon", None), + "icon": self.render_plugin_icon(plugin), "module": modules.get(plugin.value, plugin.module), } ) diff --git a/djangocms_text/editors.py b/djangocms_text/editors.py index 3780f124..a757fa7c 100644 --- a/djangocms_text/editors.py +++ b/djangocms_text/editors.py @@ -183,20 +183,6 @@ def default(self, obj): + ' \n' + "", }, - "LinkPlugin": { - "title": _("Link"), - "icon": '\n' - + ' \n' - + ' \n' - + "", - }, - "ImagePlugin": { - "title": _("Image"), - "icon": '\n' - + ' \n' - + ' \n' - + "", - }, "Unlink": { "title": _("Unlink"), "icon": '', } } diff --git a/djangocms_text/widgets.py b/djangocms_text/widgets.py index c085cd1d..9c2f67a8 100644 --- a/djangocms_text/widgets.py +++ b/djangocms_text/widgets.py @@ -100,7 +100,13 @@ def render_textarea(self, name, value, attrs=None, renderer=None): return super().render(name, value, attrs, renderer) def get_toolbar_setting(self, toolbar): - return get_editor_base_config() + toolbar_setting = get_editor_base_config() + for plugin in self.installed_plugins: + toolbar_setting[plugin["value"]] = { + "title": plugin["name"], + "icon": plugin["icon"], + } + return toolbar_setting def get_editor_settings(self, language): configuration = deepcopy(self.configuration) diff --git a/private/css/cms.balloon-toolbar.css b/private/css/cms.balloon-toolbar.css index 998d9406..7014e76e 100644 --- a/private/css/cms.balloon-toolbar.css +++ b/private/css/cms.balloon-toolbar.css @@ -7,7 +7,7 @@ border-radius: 3px; box-shadow: none; /* box-shadow: 0 1.5px 1.5px rgba(var(--dca-shadow),.4); */ - right: calc(100% + 1rem); + inset-inline-end: calc(100% + 1rem); width: calc(1.6*var(--size)); height: calc(1.6*var(--size)); line-height: calc(1.3*var(--size)); @@ -23,7 +23,8 @@ [role="menubar"] { padding: 3px; position: absolute; - top: 100%; + inset-block-start: 100%; + inset-block-end: unset; bottom: unset; width: unset; max-width: 100vw; diff --git a/private/css/cms.linkfield.css b/private/css/cms.linkfield.css index 282c7fb2..c2d432a6 100644 --- a/private/css/cms.linkfield.css +++ b/private/css/cms.linkfield.css @@ -3,8 +3,8 @@ font-size: 0.8rem; position: relative; input[type="text"] { - padding-right: 3em; - background: var(--dca-white) url('data:image/svg+xml;utf8,') no-repeat right center; + padding-inline-end: 3em; + background: var(--dca-white) url('data:image/svg+xml;utf8,') no-repeat inline-end center; background-size: auto 1em; } .cms-linkfield-selected { @@ -18,16 +18,16 @@ z-index: 1; visibility: hidden; position: absolute; - max-height: 400px; + max-block-size: 400px; overflow: auto; - left: 0; - top: 100%; + inset-inline-start: 0; + inset-block-start: 100%; border: 1px solid var(--dca-gray-lighter); background: var(--dca-white); - width: 120%; + inline-size: 120%; resize: both; - border-bottom-left-radius: 4px; - border-bottom-right-radius: 4px; + border-end-start-radius: 4px; + border-end-end-radius: 4px; box-shadow: 0 1.5px 1.5px rgba(var(--dca-shadow),.4); .cms-linkfield-error { color: red; @@ -37,7 +37,7 @@ padding: 0.5rem 6px; white-space: nowrap; font-weight: normal; - border-bottom: 1px solid var(--dca-gray-lighter); + border-block-end: 1px solid var(--dca-gray-lighter); &:last-child { border-bottom: none; } diff --git a/private/css/cms.tiptap.css b/private/css/cms.tiptap.css index cd0d2ab2..4834a432 100644 --- a/private/css/cms.tiptap.css +++ b/private/css/cms.tiptap.css @@ -16,7 +16,7 @@ .ProseMirror { overflow-y: scroll; padding: 1rem 0.8rem 0.2rem 0.2rem; - border-top: 2px solid var(--dca-gray-lighter); + border-top: 2px solid var(--dca-gray-lighter, var(--hairline-color)); &:focus-visible { outline: none; } @@ -30,7 +30,7 @@ p:not(.is-empty) > br.ProseMirror-trailingBreak { .cms-editor-inline-wrapper { &.textarea .tiptap { - border: 1px solid var(--dca-gray-lighter); + border: 1px solid var(--dca-gray-lighter, var(--hairline-color)); padding: 6px; min-height: 3rem; border-radius: 3px; @@ -71,10 +71,10 @@ p:not(.is-empty) > br.ProseMirror-trailingBreak { pointer-events: all; display: flex; flex-flow: row wrap; - border: solid 1px var(--dca-gray-light); + border: solid 1px var(--dca-gray-light, var(--hairline-color)); box-shadow: 0 1.5px 1.5px rgba(var(--dca-shadow),.4); - color: var(--dca-black); - background: var(--dca-white); + color: var(--dca-black, var(--body-fg)); + background: var(--dca-white, var(--body-bg)); opacity: 1; div.grouper { padding: 0; @@ -94,11 +94,11 @@ p:not(.is-empty) > br.ProseMirror-trailingBreak { outline: none; border-top-left-radius: 3px; border-top-right-radius: 3px; - border: 1px solid var(--dca-gray-lighter); + border: 1px solid var(--dca-gray-lighter, var(--hairline-color)); border-bottom: none; .dropdown-content { - top: 100%; - left: 0; + inset-block-start: 100%; + inset-inline-start: 0; } } button, [role="button"] { @@ -112,18 +112,19 @@ p:not(.is-empty) > br.ProseMirror-trailingBreak { justify-content: center; cursor: pointer; border: none !important; - background: var(--dca-white); + color: var(--dca-black, var(--body-fg)); + background: var(--dca-white, var(--body-bg)); border-radius: 2px; text-align: center; vertical-align: middle; line-height: 1.2; padding: 6px 4px !important; &:active, &.active { - background: var(--dca-gray-lighter) !important; + background: var(--dca-gray-lighter, var(--selected-bg)) !important; } &:hover:not(:disabled),&.show { - color: var(--dca-white) !important; - background: var(--dca-primary) !important; + color: var(--dca-white, var(--button-fg)) !important; + background: var(--dca-primary, var(--button-bg)) !important; } &:disabled { color: var(--dca-gray-light); @@ -133,7 +134,13 @@ p:not(.is-empty) > br.ProseMirror-trailingBreak { &.dropdown { position: relative; font-size: 0.8rem; - padding: 6px 8px !important; + padding: 6px 4px !important; + &:after{ + content: "▼"; + margin-block-start: 3px; + margin-inline-start: 6px; + font-size: 0.8rem; + } } svg { zoom: 120%; @@ -142,31 +149,51 @@ p:not(.is-empty) > br.ProseMirror-trailingBreak { } } .dropdown-content { - color: var(--dca-black); + color: var(--dca-black, var(--body-fg)); border-radius: 0; visibility: hidden; position: absolute; - top: 100%; - left: 0; + inset-block-start: 100%; + inset-inline-start: 0; display: flex; flex-flow: row; - border: solid 1px var(--dca-gray-light); + border: solid 1px var(--dca-gray-light, var(--hairline-color)); box-shadow: 0 1.5px 1.5px rgba(var(--dca-shadow),.4); - background: var(--dca-white); + background: var(--dca-white, var(--body-bg)); padding: 6px 0.8rem; &.vertical { flex-flow: column; font-size: 1rem; padding: 0; button { - text-align: left; - justify-content: left; + text-align: start; + justify-content: start; padding: 8px 1.2rem !important; small { margin: 0; } } } + &.plugins { + max-height: 16rem; + overflow-y: auto; + text-align: start; + .header { + background: var(--dca-gray-lighter, var(--hairline-color)); + padding-top: 0.4rem; + padding-bottom: 0.4rem; + padding-inline-start: 6px; + } + button { + > * { + width: 1rem; + margin-inline-end: 0.8rem; + margin-inline-start: -0.3rem; + } + text-align: start; + white-space: nowrap; + } + } } span:empty { margin-left: 4px; @@ -181,8 +208,8 @@ p:not(.is-empty) > br.ProseMirror-trailingBreak { } .dropback, .toolbar-dropback { position: fixed; - top: 0; - left: 0; + inset-block-start: 0; + inset-inline-start: 0; width: 100%; height: 100%; z-index: -1; diff --git a/private/js/cms.editor.js b/private/js/cms.editor.js index 7d57ecca..ba3d3b85 100644 --- a/private/js/cms.editor.js +++ b/private/js/cms.editor.js @@ -185,8 +185,15 @@ class CMSEditor { }); } - // CMS Editor: get_settings - // Get settings from json script element + /** + * Retrieves the settings for the given editor. + * If the element is a string, it will be treated as an element's ID. + * Reads settings from a json script element. + * + * @param {string|HTMLElement} el - The element or element's ID to retrieve the settings for. + * + * @return {Object} - The settings object for the element. + */ getSettings(el) { if (typeof el === "string") { if (this._editor_settings[el]) { @@ -205,6 +212,18 @@ class CMSEditor { return {}; } + /** + * Retrieves the list of installed plugins. (Returns empty list of no editor has been initialized.) + * + * @returns {Array} - The list of installed plugins. + */ + getInstalledPlugins() { + if (this._editor_settings) { + return this.getSettings(Object.keys(this._editor_settings)[0]).installed_plugins; + } + return []; + } + // CMS Editor: init_all initAll () { // Get global options from script element diff --git a/private/js/cms.tiptap.js b/private/js/cms.tiptap.js index 887aa5ce..c4977f9d 100644 --- a/private/js/cms.tiptap.js +++ b/private/js/cms.tiptap.js @@ -201,7 +201,7 @@ class CMSTipTapPlugin { } _createBlockToolbar(el, editor, options) { - const toolbar = this._populateToolbar(options.toolbar || this.settings.toolbar_HTMLField, 'block'); + const toolbar = this._populateToolbar(editor,options.toolbar || this.settings.toolbar_HTMLField, 'block'); const ballonToolbar = new CmsBalloonToolbar(editor, toolbar, (event) => this._handleToolbarClick(event, editor), (el) => this._updateToolbar(editor, el)); @@ -213,7 +213,7 @@ class CMSTipTapPlugin { toolbarElement.classList.add('cms-toolbar'); // create the toolbar html from the settings - toolbarElement.innerHTML = `
${this._populateToolbar(toolbar, filter)}`; + toolbarElement.innerHTML = `
${this._populateToolbar(editor, toolbar, filter)}`; toolbarElement.querySelector('.toolbar-dropback').addEventListener('click', (event) => { console.log(toolbarElement.querySelector('.dropdown.show')); @@ -319,7 +319,7 @@ class CMSTipTapPlugin { editor.commands.focus(); } } else if (TiptapToolbar[action]) { - TiptapToolbar[action].action(editor, event); + TiptapToolbar[action].action(editor, button); this._updateToolbar(editor); // Close dropdowns after command execution this._closeAllDropdowns(event, editor); @@ -353,7 +353,7 @@ class CMSTipTapPlugin { .forEach((el) => el.classList.remove('show')); } - _populateToolbar(array, filter) { + _populateToolbar(editor, array, filter) { let html = ''; for (let item of array) { if (item in TiptapToolbar && TiptapToolbar[item].insitu) { @@ -366,12 +366,12 @@ class CMSTipTapPlugin { item.icon = repr.icon; } if (Array.isArray(item)) { - const group = this._populateToolbar(item, filter); + const group = this._populateToolbar(editor, item, filter); if (group.length > 0) { - html += this._populateToolbar(item, filter) + this.separator_markup; + html += this._populateToolbar(editor, item, filter) + this.separator_markup; } } else if (item.constructor === Object) { - const dropdown = this._populateToolbar(item.items, filter); + const dropdown = this._populateToolbar(editor, item.items, filter); // Are there any items in the dropdown? if (dropdown.replaceAll(this.separator_markup, '').replaceAll(this.space_markup, '').length > 0) { const title = item.title && item.icon ? `title='${item.title}' ` : ''; @@ -400,7 +400,12 @@ class CMSTipTapPlugin { break; default: // Button - html += this._createToolbarButton(item, filter); + if (item in TiptapToolbar && TiptapToolbar[item].render) { + html += TiptapToolbar[item].render(editor, TiptapToolbar[item], filter); + } else { + html += this._createToolbarButton(editor, item, filter); + } + break; } } } @@ -418,21 +423,39 @@ class CMSTipTapPlugin { * @param {string} item - The item to get the representation for. * @return {string} - The representation of the specified item, or the "failed" representation from the TiptapToolbar. */ - _getRepresentation(item) { - if (this.lang && item in this.lang) { + _getRepresentation(item, filter) { + if (item.endsWith('Plugin')) { + for (const plugin of window.CMS_Editor.getInstalledPlugins()) { + if (plugin.value === item && filter !== 'block') { + return { + title: plugin.name, + icon: plugin.icon, + cmsplugin: plugin.value, + dataaction: 'CMSPlugins', + }; + } + } + return null; + } + if (this.lang && item in this.lang && item in TiptapToolbar) { + if (filter && filter !== TiptapToolbar[item].type) { + return null; + } return Object.assign({}, TiptapToolbar[item] || {}, this.lang[item]); } return TiptapToolbar.failed; } // create the html for a toolbar button - _createToolbarButton(itemName, filter) { + _createToolbarButton(editor, itemName, filter) { const item = itemName.split(' ')[0]; - if (TiptapToolbar[item] && (!filter || TiptapToolbar[item].type === filter)) { - const repr = this._getRepresentation(item); + const repr = this._getRepresentation(item, filter); + if (repr) { + repr.dataaction = repr.dataaction || item; const title = repr && repr.icon ? `title='${repr.title}' ` : ''; const position = repr.position ? `style="float :${repr.position};" ` : ''; + const cmsplugin = repr.cmsplugin ? `data-cmsplugin="${repr.cmsplugin}" ` : ''; let form = ''; let classes = 'button'; if (repr.toolbarForm) { @@ -449,7 +472,7 @@ class CMSTipTapPlugin { `; } - return ``; } @@ -472,9 +495,9 @@ class CMSTipTapPlugin { if (TiptapToolbar[action]) { const toolbarItem = this._getRepresentation(action); try { - button.disabled = !toolbarItem.enabled(editor); + button.disabled = !toolbarItem.enabled(editor, button); try { - if (toolbarItem.active(editor)) { + if (toolbarItem.active(editor, button)) { button.classList.add('active'); } else { button.classList.remove('active'); @@ -520,7 +543,7 @@ class CMSTipTapPlugin { this._closeAllDropdowns(event, editor); const action = form.closest('[role=button]').dataset.action; if (TiptapToolbar[action]) { - TiptapToolbar[action].action(editor, event, new FormData(form)); + TiptapToolbar[action].action(editor, event.target.closest('button, [role="button"]'), new FormData(form)); } } } diff --git a/private/js/tiptap_plugins/cms.balloon-toolbar.js b/private/js/tiptap_plugins/cms.balloon-toolbar.js index bbae8951..5282a05a 100644 --- a/private/js/tiptap_plugins/cms.balloon-toolbar.js +++ b/private/js/tiptap_plugins/cms.balloon-toolbar.js @@ -114,7 +114,7 @@ export default class CmsBalloonToolbar { const startPos = resolvedPos.start(depth); this.toolbar.dataset.block = startPos; const pos = this.editor.view.coordsAtPos(startPos); - this.toolbar.style.top = `${pos.top + window.scrollY - this.ref.top}px`; + this.toolbar.style.insetBlockStart = `${pos.top + window.scrollY - this.ref.top}px`; // TODO: Set the size of the balloon according to the fontsize // this.toolbar.style.setProperty('--size', this.editor.view. ...) } diff --git a/private/js/tiptap_plugins/cms.plugin.js b/private/js/tiptap_plugins/cms.plugin.js index 0b30cd7e..932cf284 100644 --- a/private/js/tiptap_plugins/cms.plugin.js +++ b/private/js/tiptap_plugins/cms.plugin.js @@ -2,9 +2,9 @@ /* jshint esversion: 6 */ /* global document, window, console */ -import { Node, mergeAttributes } from '@tiptap/core'; +import { Node } from '@tiptap/core'; import CmsDialog from "../cms.dialog.js"; - +import TiptapToolbar from "./cms.tiptap.toolbar"; function addCmsPluginDialog(editor, pluginType, selectionText) { 'use strict'; @@ -27,7 +27,7 @@ function addCmsPluginDialog(editor, pluginType, selectionText) { attrs: { HTMLAttributes: attrs, HTMLContent: plugin.innerHTML, - type: attrs["type"] + type: attrs.type }, }).run(); }) @@ -41,6 +41,8 @@ function addCmsPluginDialog(editor, pluginType, selectionText) { function editCmsPluginDialog(editor, id, position) { + "use strict"; + new CmsDialog(editor.options.el, saveSuccess => { if (saveSuccess) { window.CMS_Editor.requestPluginMarkup(id, editor.options.el) @@ -59,7 +61,7 @@ function editCmsPluginDialog(editor, id, position) { transaction.setNodeMarkup(position, null, { HTMLAttributes: attrs, HTMLContent: plugin.innerHTML, - type: attrs["type"] + type: attrs.type }); editor.view.dispatch(transaction); @@ -73,6 +75,39 @@ function editCmsPluginDialog(editor, id, position) { }, () => editor.commands.focus()).editDialog(id); } + +function renderCmsPluginMenu(editor, item, filter) { + "use strict"; + + if (filter === 'block') { + return ''; + } + const title = item.title && item.icon ? `title='${item.title}' ` : ''; + const icon = item.icon || item.title; + let dropdown = ''; + + const plugins = window.CMS_Editor.getInstalledPlugins(); + + if (!plugins) { + return ''; + } + let module = ''; + + for (const plugin of plugins) { + if (module !== plugin.module) { + module = plugin.module; + dropdown += `${module}`; + } + dropdown += ``; + console.log(plugin); + } + return `${icon}`; + +} + +TiptapToolbar['CMSPlugins'].render = renderCmsPluginMenu; + + export default Node.create({ name: 'cmsPlugin', @@ -132,7 +167,7 @@ export default Node.create({ return { HTMLAttributes: attrs, HTMLContent: dom.innerHTML, - type: attrs["type"] || "CMSPlugin" + type: attrs.type || "CMSPlugin" }; } }, @@ -190,7 +225,7 @@ export default Node.create({ if (editor.isActive('cmsPlugin', {type: pluginType})) { // Already plugin of this type active? Edit it. - const position = editor.state.doc.resolve(editor.state.selection.from); + // const position = editor.state.doc.resolve(editor.state.selection.from); editCmsPluginDialog( editor, editor.state.selection.node.attrs.HTMLAttributes.id, diff --git a/private/js/tiptap_plugins/cms.tiptap.toolbar.js b/private/js/tiptap_plugins/cms.tiptap.toolbar.js index 4e60b065..3a5e640a 100644 --- a/private/js/tiptap_plugins/cms.tiptap.toolbar.js +++ b/private/js/tiptap_plugins/cms.tiptap.toolbar.js @@ -145,18 +145,6 @@ const TiptapToolbar = { }, type: 'mark', }, - LinkPlugin: { - action: (editor) => editor.chain().addCmsPlugin('LinkPlugin').run(), - enabled: (editor) => editor.can().addCmsPlugin('LinkPlugin', true), - active: (editor) => editor.isActive('cmsPlugin', {type: 'LinkPlugin'}), - type: 'mark', - }, - ImagePlugin: { - action: (editor) => editor.chain().addCmsPlugin('ImagePlugin').run(), - enabled: (editor) => editor.can().addCmsPlugin('ImagePlugin', true), - active: (editor) => editor.isActive('cmsPlugin', {type: 'ImagePlugin'}), - type: 'mark', - }, Unlink: { action: (editor) => editor.chain().focus().unsetLink().run(), enabled: (editor) => editor.can().unsetLink(), @@ -272,6 +260,15 @@ const TiptapToolbar = { ' \n' + '' }, + CMSPlugins: { + icon: '\n' + + ' \n' + + '', + action: (editor, button) => editor.chain().addCmsPlugin(button.dataset.cmsplugin).run(), + enabled: (editor, button) => editor.can().addCmsPlugin(button.dataset.cmsplugin, true), + active: (editor, button) => editor.isActive('cmsPlugin', {type: button.dataset.cmsplugin}), + type: 'mark', + } }; ['primary', 'secondary', 'success', 'danger', 'warning', 'light', 'info', 'dark', 'muted'].forEach((style) => { diff --git a/pyproject.toml b/pyproject.toml index 907cca28..34dfd88b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,13 +23,13 @@ classifiers = [ "Framework :: Django :: 5.0", "Framework :: Django CMS", "Framework :: Django CMS :: 3.11", + "Framework :: Django CMS :: 4.0", "Framework :: Django CMS :: 4.1", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", @@ -50,7 +50,7 @@ dependencies = [ packages = ["djangocms_text", "djangocms_text_ckeditor"] [project.urls] -Homepage = "https://github.com/fsbraun/djangocms-text-rte" +Homepage = "https://github.com/django-cms/djangocms-text" [tool.hatch.version] path = "djangocms_text/__init__.py" diff --git a/tests/requirements/base.txt b/tests/requirements/base.txt index 38a7dabf..d364ab63 100644 --- a/tests/requirements/base.txt +++ b/tests/requirements/base.txt @@ -5,6 +5,7 @@ djangocms-link>=2.2.1 django-polymorphic>=2.0.3 Pillow html5lib>=0.999999999 +setuptools # other requirements coverage diff --git a/tests/requirements/dj22_cms37.txt b/tests/requirements/dj22_cms37.txt deleted file mode 100644 index 43bb6035..00000000 --- a/tests/requirements/dj22_cms37.txt +++ /dev/null @@ -1,6 +0,0 @@ --r base.txt -django-mptt -django-treebeard<4.5 - -Django>=2.2,<3.0 -django-cms>=3.7,<3.8 diff --git a/tests/requirements/dj22_cms38.txt b/tests/requirements/dj22_cms38.txt deleted file mode 100644 index d4ef4b71..00000000 --- a/tests/requirements/dj22_cms38.txt +++ /dev/null @@ -1,6 +0,0 @@ --r base.txt -django-mptt -django-treebeard<4.5 - -Django>=2.2,<3.0 -django-cms>=3.8,<3.9 diff --git a/tests/requirements/dj22_cms40.txt b/tests/requirements/dj22_cms40.txt deleted file mode 100644 index da3a056b..00000000 --- a/tests/requirements/dj22_cms40.txt +++ /dev/null @@ -1,6 +0,0 @@ --r base.txt -django-mptt -django-treebeard<4.5 - -Django>=2.2,<2.3 -git+https://github.com/django-cms/django-cms@release/4.0.x#egg=django-cms diff --git a/tests/requirements/dj31_cms38.txt b/tests/requirements/dj31_cms38.txt deleted file mode 100644 index c7905e52..00000000 --- a/tests/requirements/dj31_cms38.txt +++ /dev/null @@ -1,5 +0,0 @@ --r base.txt -django-mptt - -Django>=3.1,<3.2 -django-cms>=3.8,<3.9 diff --git a/tests/requirements/dj32_cms310.txt b/tests/requirements/dj32_cms310.txt deleted file mode 100644 index 4b2996fa..00000000 --- a/tests/requirements/dj32_cms310.txt +++ /dev/null @@ -1,4 +0,0 @@ --r base.txt - -Django>=3.2,<3.3 -django-cms>=3.10,<3.11 diff --git a/tests/requirements/dj32_cms311.txt b/tests/requirements/dj32_cms311.txt deleted file mode 100644 index f54dae0e..00000000 --- a/tests/requirements/dj32_cms311.txt +++ /dev/null @@ -1,4 +0,0 @@ --r base.txt - -Django>=3.2,<3.3 -django-cms>=3.11,<3.12 diff --git a/tests/requirements/dj32_cms39.txt b/tests/requirements/dj32_cms39.txt deleted file mode 100644 index cdd62d4d..00000000 --- a/tests/requirements/dj32_cms39.txt +++ /dev/null @@ -1,4 +0,0 @@ --r base.txt - -Django>=3.2,<3.3 -django-cms>=3.9,<3.10 diff --git a/tests/requirements/dj32_cms41.txt b/tests/requirements/dj32_cms41.txt deleted file mode 100644 index e62655f0..00000000 --- a/tests/requirements/dj32_cms41.txt +++ /dev/null @@ -1,4 +0,0 @@ --r base.txt - -Django>=3.2,<3.3 -git+https://github.com/django-cms/django-cms@develop-4#egg=django-cms diff --git a/tests/requirements/dj40_cms311.txt b/tests/requirements/dj40_cms311.txt deleted file mode 100644 index 0575f71c..00000000 --- a/tests/requirements/dj40_cms311.txt +++ /dev/null @@ -1,4 +0,0 @@ --r base.txt - -Django>=4.0,<4.1 -django-cms>=3.11,<3.12 diff --git a/tests/requirements/dj40_cms41.txt b/tests/requirements/dj40_cms41.txt deleted file mode 100644 index 96116287..00000000 --- a/tests/requirements/dj40_cms41.txt +++ /dev/null @@ -1,4 +0,0 @@ --r base.txt - -Django>=4.0,<4.1 -git+https://github.com/django-cms/django-cms@develop-4#egg=django-cms diff --git a/tests/requirements/dj41_cms311.txt b/tests/requirements/dj41_cms311.txt deleted file mode 100644 index 4882e497..00000000 --- a/tests/requirements/dj41_cms311.txt +++ /dev/null @@ -1,4 +0,0 @@ --r base.txt - -Django>=4.1,<4.2 -django-cms>=3.11,<3.12 diff --git a/tests/requirements/dj41_cms41.txt b/tests/requirements/dj41_cms41.txt deleted file mode 100644 index 3c7d239e..00000000 --- a/tests/requirements/dj41_cms41.txt +++ /dev/null @@ -1,4 +0,0 @@ --r base.txt - -Django>=4.1,<4.2 -git+https://github.com/django-cms/django-cms@develop-4#egg=django-cms diff --git a/tox.ini b/tox.ini index 72133588..799b5c21 100644 --- a/tox.ini +++ b/tox.ini @@ -2,21 +2,20 @@ envlist = ruff frontend - py{39,310,311}-dj{40}-cms{311,41} - py{39,310,311}-dj{41}-cms{311,41} - py{39,310,311}-dj{42}-cms{311,41} - py{311}-dj{50}-cms{41} + py{310,311,312}-dj{42}-cms{311,41} + py{310,311,312}-dj{50}-cms{311,41} skip_missing_interpreters=True [testenv] deps = -r{toxinidir}/tests/requirements/base.txt - dj32: Django>=3.2,<3.3 dj42: Django>=4.2,<5.0 - dj50: Django~=5.0rc1,<5.1 + dj50: Django>=5.0,<5.1 + dj51: Django>=5.1,<5.2 + dj52: Django>=5.2,<6.0 cms311: django-cms>=3.11,<4 - cms40: git+https://github.com/django-cms/django-cms@release/4.0.x + cms40: git+https://github.com/django-cms/django-cms@release/4.0.1.x cms41: git+https://github.com/django-cms/django-cms@develop-4 commands =