diff --git a/app/application/lang/en/editor.php b/app/application/lang/en/editor.php new file mode 100644 index 0000000..a5059ff --- /dev/null +++ b/app/application/lang/en/editor.php @@ -0,0 +1,6 @@ + 'Do not translate', + 'Mark as not to translate' => 'Mark as not to translate', +]; diff --git a/app/application/lang/ru/editor.php b/app/application/lang/ru/editor.php new file mode 100644 index 0000000..05facaf --- /dev/null +++ b/app/application/lang/ru/editor.php @@ -0,0 +1,6 @@ + 'Не переводить', + 'Mark as not to translate' => 'Пометить как не переводить', +]; diff --git a/app/application/resources/views/components/volt/forms/textarea-wysiwyg.blade.php b/app/application/resources/views/components/volt/forms/textarea-wysiwyg.blade.php index 4a9b130..b63bddf 100644 --- a/app/application/resources/views/components/volt/forms/textarea-wysiwyg.blade.php +++ b/app/application/resources/views/components/volt/forms/textarea-wysiwyg.blade.php @@ -95,14 +95,96 @@ xhr.send(formData); }); @endif + + tinymce.PluginManager.add('translateNo', (editor) => { + const ATTR = 'translate'; + const VALUE = 'no'; + + const isTranslateNo = (node) => + node && node.nodeType === 1 && node.getAttribute(ATTR) === VALUE; + + const toggleTranslateNo = () => { + const selectedNode = editor.selection.getNode(); + + if (isTranslateNo(selectedNode)) { + // Remove translate="no", expand span + if (selectedNode.tagName === 'SPAN') { + editor.dom.remove(selectedNode, true); // true = сохранить детей + } else { + editor.dom.setAttrib(selectedNode, ATTR, null); + } + return; + } + + // If inside translate="no", remove the mark + const wrapper = editor.dom.getParent(selectedNode, `[${ATTR}="${VALUE}"]`); + if (wrapper) { + if (wrapper.tagName === 'SPAN') { + editor.dom.remove(wrapper, true); + } else { + editor.dom.setAttrib(wrapper, ATTR, null); + } + return; + } + + // Otherwise, wrap the selection + editor.formatter.register('translateNo', { + inline: 'span', + attributes: { [ATTR]: VALUE }, + remove: 'all' + }); + editor.formatter.apply('translateNo'); + }; + + editor.ui.registry.addToggleButton('translateNo', { + icon: 'translate', + tooltip: '{{ __('editor.Do not translate') }}', + onAction: toggleTranslateNo, + onSetup: (api) => { + const setActive = () => { + const node = editor.selection.getNode(); + api.setActive( + isTranslateNo(node) || + !!editor.dom.getParent(node, `[${ATTR}="${VALUE}"]`) + ); + }; + editor.on('NodeChange', setActive); + return () => editor.off('NodeChange', setActive); + } + }); + + editor.ui.registry.addMenuItem('translateNo', { + text: '{{ __('editor.Mark as not to translate') }}', + icon: 'translate', + onAction: toggleTranslateNo + }); + }); + tinymce.init({ + content_style: ` + span[translate="no"] { + background: rgba(255, 215, 0, 0.35); + outline: 1px dashed #e0a800; + position: relative; + } + span[translate="no"]:hover::before { + position: absolute; + content: "{{ __('editor.Do not translate') }}"; + left: 0; + bottom: 100%; + background: #e0a800; + white-space: nowrap; + padding: 0.25rem; + border: 1px solid #ddd; + } + `, selector: '#{{ $tinyId }}', @if(in_array(app()->getLocale(), ['ru'], true)) language: '{{ app()->getLocale() }}', @endif license_key: '{{ $tinymceLicenseKey }}', - plugins: 'advlist code emoticons link lists table codesample media my-image', - toolbar: 'bold italic | bullist numlist | link image emoticons media codesample', + plugins: 'advlist code emoticons link lists table codesample media my-image translateNo', + toolbar: 'bold italic | bullist numlist | link image emoticons media codesample translateNo', referrer_policy: 'origin', @if($storageUpload !== null) images_upload_handler: imageUpload,