From 91f55c27def2012409a3ceda04cef255b16a9919 Mon Sep 17 00:00:00 2001 From: willfranklyn Date: Thu, 4 Jun 2020 10:45:05 -0600 Subject: [PATCH 1/4] Add Video Component --- examples/Components/Routes/Videos/index.vue | 65 ++++++++++ examples/main.js | 7 ++ packages/tiptap-extensions/src/index.js | 1 + packages/tiptap-extensions/src/nodes/Video.js | 118 ++++++++++++++++++ 4 files changed, 191 insertions(+) create mode 100644 examples/Components/Routes/Videos/index.vue create mode 100644 packages/tiptap-extensions/src/nodes/Video.js diff --git a/examples/Components/Routes/Videos/index.vue b/examples/Components/Routes/Videos/index.vue new file mode 100644 index 0000000000..7988bd064e --- /dev/null +++ b/examples/Components/Routes/Videos/index.vue @@ -0,0 +1,65 @@ + + + diff --git a/examples/main.js b/examples/main.js index e873023f68..d4b0851031 100644 --- a/examples/main.js +++ b/examples/main.js @@ -46,6 +46,13 @@ const routes = [ githubUrl: 'https://github.com/scrumpy/tiptap/tree/master/examples/Components/Routes/Images', }, }, + { + path: '/videos', + component: () => import('Components/Routes/Videos'), + meta: { + githubUrl: 'https://github.com/scrumpy/tiptap/tree/master/examples/Components/Routes/Images', + }, + }, { path: '/hiding-menu-bar', component: () => import('Components/Routes/HidingMenuBar'), diff --git a/packages/tiptap-extensions/src/index.js b/packages/tiptap-extensions/src/index.js index 557f008a5b..6787694ef7 100644 --- a/packages/tiptap-extensions/src/index.js +++ b/packages/tiptap-extensions/src/index.js @@ -6,6 +6,7 @@ export { default as HardBreak } from './nodes/HardBreak' export { default as Heading } from './nodes/Heading' export { default as HorizontalRule } from './nodes/HorizontalRule' export { default as Image } from './nodes/Image' +export { default as Video } from './nodes/Video' export { default as ListItem } from './nodes/ListItem' export { default as Mention } from './nodes/Mention' export { default as OrderedList } from './nodes/OrderedList' diff --git a/packages/tiptap-extensions/src/nodes/Video.js b/packages/tiptap-extensions/src/nodes/Video.js new file mode 100644 index 0000000000..584299f84b --- /dev/null +++ b/packages/tiptap-extensions/src/nodes/Video.js @@ -0,0 +1,118 @@ +import { + Node, + Plugin +} from 'tiptap' +import { + nodeInputRule +} from 'tiptap-commands' + +const VIDEO_INPUT_REGEX = /!\[(.+|:?)]\((\S+)(?:(?:\s+)["'](\S+)["'])?\)/ + +export default class Video extends Node { + + get name() { + return 'video' + } + + get schema() { + return { + inline: true, + attrs: { + src: {}, + }, + group: 'inline', + draggable: true, + parseDOM: [{ + tag: 'video', + getAttrs: dom => ({ + src: dom.getAttribute('src'), + }), + },], + toDOM: node => ['video', { + 'controls': true, + 'style': 'width: 100%', + }, + ['source', node.attrs] + ], + } + } + + commands({ + type + }) { + return attrs => (state, dispatch) => { + const { + selection + } = state + const position = selection.$cursor ? selection.$cursor.pos : selection.$to.pos + const node = type.create(attrs) + const transaction = state.tr.insert(position, node) + dispatch(transaction) + } + } + + inputRules({ + type + }) { + return [ + nodeInputRule(VIDEO_INPUT_REGEX, type, match => { + const [, src,] = match + return { + src, + } + }), + ] + } + + get plugins() { + return [ + new Plugin({ + props: { + handleDOMEvents: { + drop(view, event) { + const hasFiles = event.dataTransfer && + event.dataTransfer.files && + event.dataTransfer.files.length + + if (!hasFiles) { + return + } + + const videos = Array + .from(event.dataTransfer.files) + .filter(file => (/video/i).test(file.type)) + + if (videos.length === 0) { + return + } + + event.preventDefault() + + const { + schema + } = view.state + const coordinates = view.posAtCoords({ + left: event.clientX, + top: event.clientY + }) + + videos.forEach(video => { + const reader = new FileReader() + + reader.onload = readerEvent => { + const node = schema.nodes.video.create({ + src: readerEvent.target.result, + }) + const transaction = view.state.tr.insert(coordinates.pos, node) + view.dispatch(transaction) + } + reader.readAsDataURL(video) + }) + }, + }, + }, + }), + ] + } + +} From 3f6b9f078081fbe5f44586287ee385b73814590a Mon Sep 17 00:00:00 2001 From: willfranklyn Date: Thu, 4 Jun 2020 10:59:12 -0600 Subject: [PATCH 2/4] Remove Video from example default --- examples/Components/Routes/Videos/index.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/Components/Routes/Videos/index.vue b/examples/Components/Routes/Videos/index.vue index 7988bd064e..8fc54a1105 100644 --- a/examples/Components/Routes/Videos/index.vue +++ b/examples/Components/Routes/Videos/index.vue @@ -48,7 +48,6 @@ export default {

This is basic example of implementing videos. Try to drop new videos here. Reordering also works.

- `, }), } From 512ca794d459665c4225f10e481d8d0e39bbea31 Mon Sep 17 00:00:00 2001 From: willfranklyn Date: Thu, 4 Jun 2020 11:20:44 -0600 Subject: [PATCH 3/4] Updated Video Prompt --- examples/Components/Routes/Videos/index.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Components/Routes/Videos/index.vue b/examples/Components/Routes/Videos/index.vue index 8fc54a1105..9ccc9a214a 100644 --- a/examples/Components/Routes/Videos/index.vue +++ b/examples/Components/Routes/Videos/index.vue @@ -54,7 +54,7 @@ export default { }, methods: { showImagePrompt(command) { - const src = prompt('Enter the url of your image here') + const src = prompt('Enter the url of your video here') if (src !== null) { command({ src }) } From aa59fb1596d1c7fa9b80d412ede4d30e38e87361 Mon Sep 17 00:00:00 2001 From: willfranklyn Date: Thu, 4 Jun 2020 11:36:55 -0600 Subject: [PATCH 4/4] Updated Video Prompt Function Name --- examples/Components/Routes/Videos/index.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/Components/Routes/Videos/index.vue b/examples/Components/Routes/Videos/index.vue index 9ccc9a214a..a50620424c 100644 --- a/examples/Components/Routes/Videos/index.vue +++ b/examples/Components/Routes/Videos/index.vue @@ -2,7 +2,7 @@
@@ -53,7 +53,7 @@ export default { } }, methods: { - showImagePrompt(command) { + showVideoPrompt(command) { const src = prompt('Enter the url of your video here') if (src !== null) { command({ src })