Skip to content

Commit faa5154

Browse files
committed
Merge branch 'b-7.5.x-wysiwyg-summernote-extension-OXDEV-10119' into b-7.5.x
2 parents 8eaef9c + 24998b5 commit faa5154

8 files changed

Lines changed: 587 additions & 2 deletions

File tree

.github/oxid-esales/examples-module.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ install:
1717
vendor/bin/oe-console oe:module:install ./
1818
vendor/bin/oe-eshop-doctrine_migration migrations:migrate
1919
vendor/bin/oe-console oe:module:activate oe_examples_module
20+
vendor/bin/oe-console oe:module:activate ddoemedialibrary
21+
vendor/bin/oe-console oe:module:activate ddoewysiwyg
2022
vendor/bin/oe-console oe:theme:activate apex
2123
2224
runscript: &runscript

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](http://keepachangelog.com/)
55
and this project adheres to [Semantic Versioning](http://semver.org/).
66

7-
## [Undecided] - Unreleased
7+
## [v2.1.0] - Unreleased
88

99
### Changed
1010
- Updated for OXID eShop 7.5.x compatibility
1111
- PHP 8.3-8.5 support (removed PHP 8.2)
1212

13+
### Added
14+
- `ddoe/wysiwyg-editor-module` dependency
15+
- Example of extending another module's Twig blocks - customizing the Summernote WYSIWYG editor with additional plugins and options
16+
1317
## [v2.0.0] - 2025-11-27
1418

1519
### Added

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,10 @@ The repository contains examples of following cases and more:
122122
* [extending of oxid theme templates or blocks](views/twig/extensions/themes)
123123
* extending a shop admin template block (`admin_user_main_form` - only an extension of a block, without functionality)
124124
* extending a shop template block (`start_newest_articles`)
125+
* [extending another module's template blocks](views/twig/extensions/modules/ddoewysiwyg/ddoewysiwyg.html.twig)
126+
* extending the `ddoe/wysiwyg-editor-module` (Summernote editor) to add custom plugins and options
127+
* `ddoe_wysiwyg_plugins` block - load additional Summernote plugin scripts via `{{ script() }}`
128+
* `ddoe_wysiwyg_summernote_options` block - customize editor options (toolbar, fonts, etc.) via `Object.assign()`
125129

126130
* Using the translations for your module specific phrases
127131
* [in admin](views/admin_twig)

assets/out/src/js/summernote-cleaner.js

Lines changed: 362 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/*!
2+
* summernote-ext-print
3+
* Copyright (c) lqez (https://github.com/lqez/summernote-ext-print)
4+
* Licensed under the MIT License
5+
*/
6+
(function (factory) {
7+
/* global define */
8+
if (typeof define === 'function' && define.amd) {
9+
// AMD. Register as an anonymous module.
10+
define(['jquery'], factory);
11+
} else if (typeof module === 'object' && module.exports) {
12+
// Node/CommonJS
13+
module.exports = factory(require('jquery'));
14+
} else {
15+
// Browser globals
16+
factory(window.jQuery);
17+
}
18+
}(function ($) {
19+
// Extends lang for print plugin.
20+
$.extend(true, $.summernote.lang, {
21+
'en-US': {
22+
print: {
23+
print: 'Print'
24+
}
25+
},
26+
'ko-KR': {
27+
print: {
28+
print: '인쇄'
29+
}
30+
},
31+
'pt-BR': {
32+
print: {
33+
print: 'Imprimir'
34+
}
35+
},
36+
'fr-FR': {
37+
print: {
38+
print: 'Imprimer'
39+
}
40+
}
41+
});
42+
43+
// Extends plugins for print plugin.
44+
$.extend($.summernote.plugins, {
45+
/**
46+
* @param {Object} context - context object has status of editor.
47+
*/
48+
'print': function (context) {
49+
var self = this;
50+
51+
// ui has renders to build ui elements.
52+
// - you can create a button with `ui.button`
53+
var ui = $.summernote.ui;
54+
var $editor = context.layoutInfo.editor;
55+
var options = context.options;
56+
var lang = options.langInfo;
57+
58+
var isFF = function () {
59+
const userAgent = navigator.userAgent;
60+
const isEdge = /Edge\/\d+/.test(userAgent);
61+
return !isEdge && /firefox/i.test(userAgent)
62+
}
63+
64+
var fillContentAndPrint = function($frame, content) {
65+
$frame.contents().find('body').html(content);
66+
67+
setTimeout(function () {
68+
$frame[0].contentWindow.focus();
69+
$frame[0].contentWindow.print();
70+
$frame.remove();
71+
$frame = null;
72+
}, 250);
73+
}
74+
75+
var getPrintframe = function ($container) {
76+
var $frame = $(
77+
'<iframe name="summernotePrintFrame"' +
78+
'width="0" height="0" frameborder="0" src="about:blank" style="visibility:hidden">' +
79+
'</iframe>');
80+
$frame.appendTo($editor.parent());
81+
82+
var $head = $frame.contents().find('head');
83+
if (options.print && options.print.stylesheetUrl) {
84+
// Use dedicated styles
85+
var css = document.createElement('link');
86+
css.href = options.print.stylesheetUrl;
87+
css.rel = 'stylesheet';
88+
css.type = 'text/css';
89+
$head.append(css);
90+
} else {
91+
// Inherit styles from document
92+
$('style, link[rel=stylesheet]', document).each(function () {
93+
$head.append($(this).clone());
94+
});
95+
}
96+
97+
return $frame;
98+
};
99+
100+
// add print button
101+
context.memo('button.print', function () {
102+
// create button
103+
var button = ui.button({
104+
contents: '<i class="fa fa-print"/> ' + lang.print.print,
105+
tooltip: lang.print.print,
106+
container: options.container,
107+
click: function () {
108+
var $frame = getPrintframe();
109+
var content = context.invoke('code');
110+
111+
if (isFF()) {
112+
$frame[0].onload = function () {
113+
fillContentAndPrint($frame, content);
114+
};
115+
} else {
116+
fillContentAndPrint($frame, content);
117+
}
118+
}
119+
});
120+
return button.render();
121+
});
122+
}
123+
});
124+
}));

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
],
1313
"require": {
1414
"php": "^8.3",
15-
"symfony/filesystem": "^6.4"
15+
"symfony/filesystem": "^6.4",
16+
"ddoe/wysiwyg-editor-module": "dev-b-7.5.x"
1617
},
1718
"minimum-stability": "dev",
1819
"prefer-stable": true,
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
/**
4+
* Copyright © . All rights reserved.
5+
* See LICENSE file for license details.
6+
*/
7+
8+
declare(strict_types=1);
9+
10+
namespace OxidEsales\ExamplesModule\Tests\Codeception\Acceptance;
11+
12+
use OxidEsales\ExamplesModule\Tests\Codeception\Support\AcceptanceTester;
13+
14+
/**
15+
* @group oe_examples_module
16+
* @group oe_examples_module_summernote_extension
17+
*/
18+
final class SummernoteExtensionCest
19+
{
20+
private const string TOOLBAR = '//div[contains(@class,"note-toolbar")]';
21+
private const string FORMATTING = self::TOOLBAR . '//div[contains(@class,"note-formatting")]';
22+
private const string FONT = self::TOOLBAR . '//div[contains(@class,"note-font")]';
23+
private const string MISC = self::TOOLBAR . '//div[contains(@class,"note-misc")]';
24+
private const string DROPDOWN = self::FONT . '//div[contains(@class,"dropdown-fontname")]';
25+
26+
public function testModuleCanOverrideSummernoteOptions(AcceptanceTester $I): void
27+
{
28+
$I->wantToTest('Module can override Summernote toolbar and font names');
29+
30+
$adminPanel = $I->loginAdmin();
31+
$adminPanel->openProducts();
32+
$I->selectEditFrame();
33+
34+
$I->waitForElement('.note-editor', 15);
35+
$I->wait(3);
36+
37+
// toolbar groups
38+
$I->seeNumberOfElements(self::TOOLBAR . '/div[contains(@class,"note-btn-group")]', 4);
39+
40+
// formatting
41+
$I->seeElement(self::FORMATTING . '//button[contains(@class,"note-btn-bold")]');
42+
$I->seeElement(self::FORMATTING . '//button[contains(@class,"note-btn-italic")]');
43+
$I->seeNumberOfElements(self::FORMATTING . '//button[contains(@class,"note-btn")]', 2);
44+
45+
// font
46+
$I->seeElement(self::FONT . '//*[@aria-label="Font Family"]');
47+
$I->seeElement(self::FONT . '//*[@aria-label="Font Size"]');
48+
$I->seeNumberOfElements(self::FONT . '//button[contains(@class,"note-btn")]', 2);
49+
50+
// misc
51+
$I->seeElement(self::MISC . '//*[@aria-label="Cleaner"]');
52+
$I->seeElement(self::MISC . '//*[@aria-label="Print"]');
53+
$I->seeElement(self::MISC . '//button[contains(@class,"btn-codeview")]');
54+
$I->seeNumberOfElements(self::MISC . '//button[contains(@class,"note-btn")]', 3);
55+
56+
// font names dropdown
57+
$I->click(self::FONT . '//button[@aria-label="Font Family"]');
58+
$I->wait(1);
59+
60+
$I->seeNumberOfElements(self::DROPDOWN . '//a[contains(@class,"dropdown-item")]', 3);
61+
$I->see('Arial', self::DROPDOWN);
62+
$I->see('Courier New', self::DROPDOWN);
63+
$I->see('Custom Font', self::DROPDOWN);
64+
}
65+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{% extends '@ddoewysiwyg/ddoewysiwyg.html.twig' %}
2+
3+
{% block ddoe_wysiwyg_plugins %}
4+
{{ parent() }}
5+
{{ script({ include: oViewConf.getModuleUrl('oe_examples_module', 'out/src/js/summernote-ext-print.js'), priority: 1, dynamic: __oxid_include_dynamic }) }}
6+
{{ script({ include: oViewConf.getModuleUrl('oe_examples_module', 'out/src/js/summernote-cleaner.js'), priority: 1, dynamic: __oxid_include_dynamic }) }}
7+
{% endblock %}
8+
9+
{% block ddoe_wysiwyg_summernote_options %}
10+
{{ parent() }}
11+
Object.assign(summernoteOptions, {
12+
fontNames: [
13+
'Arial', 'Courier New', 'Custom Font'
14+
],
15+
fontNamesIgnoreCheck: ['Custom Font'],
16+
addDefaultFonts: false,
17+
toolbar: [
18+
['formatting', ['bold', 'italic']],
19+
['font', ['fontname', 'fontsize']],
20+
['misc', ['cleaner', 'print', 'codeview']]
21+
],
22+
});
23+
{% endblock %}

0 commit comments

Comments
 (0)