"@codemirror/view": "^6.1.2",
"@ssddanbrown/codemirror-lang-smarty": "^1.0.0",
"@ssddanbrown/codemirror-lang-twig": "^1.0.0",
- "clipboard": "^2.0.11",
"codemirror": "^6.0.1",
"dropzone": "^5.9.3",
"markdown-it": "^13.0.1",
"node": ">= 8.10.0"
}
},
- "node_modules/clipboard": {
- "version": "2.0.11",
- "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.11.tgz",
- "integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==",
- "dependencies": {
- "good-listener": "^1.2.2",
- "select": "^1.1.2",
- "tiny-emitter": "^2.0.0"
- }
- },
"node_modules/cliui": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/delegate": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz",
- "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw=="
- },
"node_modules/dropzone": {
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/dropzone/-/dropzone-5.9.3.tgz",
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/good-listener": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz",
- "integrity": "sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==",
- "dependencies": {
- "delegate": "^3.1.2"
- }
- },
"node_modules/gopd": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
"node": ">=12.0.0"
}
},
- "node_modules/select": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
- "integrity": "sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA=="
- },
"node_modules/semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/tiny-emitter": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
- "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="
- },
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"@codemirror/view": "^6.1.2",
"@ssddanbrown/codemirror-lang-smarty": "^1.0.0",
"@ssddanbrown/codemirror-lang-twig": "^1.0.0",
- "clipboard": "^2.0.11",
"codemirror": "^6.0.1",
"dropzone": "^5.9.3",
"markdown-it": "^13.0.1",
* [Sortable](https://github.com/SortableJS/Sortable) - _[MIT](https://github.com/SortableJS/Sortable/blob/master/LICENSE)_
* [Google Material Icons](https://github.com/google/material-design-icons) - _[Apache-2.0](https://github.com/google/material-design-icons/blob/master/LICENSE)_
* [Dropzone.js](http://www.dropzonejs.com/) - _[MIT](https://github.com/dropzone/dropzone/blob/main/LICENSE)_
-* [clipboard.js](https://clipboardjs.com/) - _[MIT](https://github.com/zenorocha/clipboard.js/blob/master/LICENSE)_
* [markdown-it](https://github.com/markdown-it/markdown-it) and [markdown-it-task-lists](https://github.com/revin/markdown-it-task-lists) - _[MIT](https://github.com/markdown-it/markdown-it/blob/master/LICENSE) and [ISC](https://github.com/revin/markdown-it-task-lists/blob/master/LICENSE)_
* [Dompdf](https://github.com/dompdf/dompdf) - _[LGPL v2.1](https://github.com/dompdf/dompdf/blob/master/LICENSE.LGPL)_
* [BarryVD/Dompdf](https://github.com/barryvdh/laravel-dompdf) - _[MIT](https://github.com/barryvdh/laravel-dompdf/blob/master/LICENSE)_
-import {EditorView, keymap} from "@codemirror/view"
-import Clipboard from "clipboard/dist/clipboard.min";
+import {EditorView, keymap} from "@codemirror/view";
+import {copyTextToClipboard} from "../services/clipboard.js"
// Modes
import {viewer, editor} from "./setups.js";
/**
* Add a button to a CodeMirror instance which copies the contents to the clipboard upon click.
- * @param cmInstance
+ * @param {EditorView} editorView
*/
-function addCopyIcon(cmInstance) {
- // TODO
- // const copyIcon = `<svg viewBox="0 0 24 24" width="16" height="16" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"/><path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/></svg>`;
- // const copyButton = document.createElement('div');
- // copyButton.classList.add('CodeMirror-copy');
- // copyButton.innerHTML = copyIcon;
- // cmInstance.display.wrapper.appendChild(copyButton);
- //
- // const clipboard = new Clipboard(copyButton, {
- // text: function(trigger) {
- // return cmInstance.getValue()
- // }
- // });
- //
- // clipboard.on('success', event => {
- // copyButton.classList.add('success');
- // setTimeout(() => {
- // copyButton.classList.remove('success');
- // }, 240);
- // });
+function addCopyIcon(editorView) {
+ const copyIcon = `<svg viewBox="0 0 24 24" width="16" height="16" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"/><path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/></svg>`;
+ const copyButton = document.createElement('button');
+ copyButton.setAttribute('type', 'button')
+ copyButton.classList.add('cm-copy-button');
+ copyButton.innerHTML = copyIcon;
+ editorView.dom.appendChild(copyButton);
+
+ copyButton.addEventListener('click', event => {
+ copyTextToClipboard(editorView.state.doc.toString());
+ copyButton.classList.add('success');
+ setTimeout(() => {
+ copyButton.classList.remove('success');
+ }, 240);
+ });
}
/**
*/
export function markdownEditor(elem, onChange, domEventHandlers, keyBindings) {
const content = elem.textContent;
-
- // TODO - Change to pass something else that's useful, probably extension array?
- // window.$events.emitPublic(elem, 'editor-markdown-cm::pre-init', {config});
-
- const ev = createView({
+ const config = {
parent: elem.parentNode,
doc: content,
extensions: [
EditorView.domEventHandlers(domEventHandlers),
keymap.of(keyBindings),
],
- });
+ };
+
+ // Emit a pre-event public event to allow tweaking of the configure before view creation.
+ window.$events.emitPublic(elem, 'editor-markdown-cm::pre-init', {cmEditorViewConfig: config});
+ // Create editor view, hide original input
+ const ev = createView(config);
elem.style.display = 'none';
return ev;
...historyKeymap,
]),
getLanguageExtension(language, ''),
+ EditorView.lineWrapping,
];
}
\ No newline at end of file
-import {debounce} from "../services/util";
import {Component} from "./component";
import {init as initEditor} from "../markdown/editor";
window.$events.emitPublic(this.elem, 'editor-markdown::setup', {
markdownIt: this.editor.markdown.getRenderer(),
displayEl: this.display,
- // TODO - change to codeMirrorView?
- // codeMirrorInstance: this.editor.cm,
+ cmEditorView: this.editor.cm,
});
}
toolbarLabel.closest('.markdown-editor-wrap').classList.add('active');
});
- // Refresh CodeMirror on container resize
- // TODO
- // const resizeDebounced = debounce(() => this.editor.cm.refresh(), 100, false);
- // const observer = new ResizeObserver(resizeDebounced);
- // observer.observe(this.elem);
-
this.handleDividerDrag();
}
window.removeEventListener('pointerup', upListener);
this.display.style.pointerEvents = null;
document.body.style.userSelect = null;
- // TODO
- // this.editor.cm.refresh();
};
this.display.style.pointerEvents = 'none';
import * as DOM from "../services/dom";
-import Clipboard from "clipboard/dist/clipboard.min";
import {Component} from "./component";
+import {copyTextToClipboard} from "../services/clipboard";
export class Pointer extends Component {
setup() {
this.container = this.$el;
+ this.input = this.$refs.input;
+ this.button = this.$refs.button;
this.pageId = this.$opts.pageId;
// Instance variables
this.pointerSectionId = '';
this.setupListeners();
-
- // Set up clipboard
- new Clipboard(this.container.querySelector('button'));
}
setupListeners() {
+ // Copy on copy button click
+ this.button.addEventListener('click', event => {
+ copyTextToClipboard(this.input.value);
+ });
+
// Select all contents on input click
- DOM.onChildEvent(this.container, 'input', 'click', (event, input) => {
- input.select();
+ this.input.addEventListener('click', event => {
+ this.input.select();
event.stopPropagation();
});
inputText = window.location.protocol + "//" + window.location.host + inputText;
}
- this.container.querySelector('input').value = inputText;
+ this.input.value = inputText;
// Update anchor if present
const editAnchor = this.container.querySelector('#pointer-edit');
domEventHandlers,
provideKeyBindings(editor),
);
- window.cm = cm;
- // Will force to remain as ltr for now due to issues when HTML is in editor.
- // TODO
- // cm.setOption('direction', 'ltr');
+ // Add editor view to window for easy access/debugging.
+ // Not part of official API/Docs
+ window.mdEditorView = cm;
return cm;
}
\ No newline at end of file
-class Clipboard {
+export class Clipboard {
/**
* Constructor
}
}
+export function copyTextToClipboard(text) {
+ return navigator.clipboard.writeText(text);
+}
+
export default Clipboard;
\ No newline at end of file
/**
* Custom Copy Button
*/
-.CodeMirror-copy {
+.cm-copy-button {
position: absolute;
top: -1px;
right: -1px;
}
}
}
-.CodeMirror:hover .CodeMirror-copy {
+.cm-editor:hover .cm-copy-button {
user-select: all;
opacity: 1;
pointer-events: all;
</div>
</div>
- <div markdown-input class="flex flex-fill">
+ <div class="flex flex-fill" dir="ltr">
<textarea id="markdown-editor-input"
refs="markdown-editor@input"
@if($errors->has('markdown')) class="text-neg" @endif
<div class="pointer anim {{ userCan('page-update', $page) ? 'is-page-editable' : ''}}" >
<span class="icon mr-xxs">@icon('link') @icon('include', ['style' => 'display:none;'])</span>
<div class="input-group inline block">
- <input readonly="readonly" type="text" id="pointer-url" placeholder="url">
- <button class="button outline icon" data-clipboard-target="#pointer-url" type="button" title="{{ trans('entities.pages_copy_link') }}">@icon('copy')</button>
+ <input refs="pointer@input" readonly="readonly" type="text" id="pointer-url" placeholder="url">
+ <button refs="pointer@button" class="button outline icon" data-clipboard-target="#pointer-url" type="button" title="{{ trans('entities.pages_copy_link') }}">@icon('copy')</button>
</div>
@if(userCan('page-update', $page))
<a href="{{ $page->getUrl('/edit') }}" id="pointer-edit" data-edit-href="{{ $page->getUrl('/edit') }}"