From 30c11b8f1c25ec09d841d52e118a9f8ff5808f1b Mon Sep 17 00:00:00 2001 From: Jan Szejko Date: Fri, 23 Dec 2016 09:55:27 +0100 Subject: [PATCH] youtube videos --- .../modules/documentCanvas/canvas/canvas.js | 5 + src/editor/plugins/core/canvasElements.js | 6 +- src/editor/plugins/core/img/imgElement.js | 11 +- src/editor/plugins/core/switch.js | 7 +- src/editor/plugins/core/video/box.html | 7 + src/editor/plugins/core/video/videoElement.js | 133 ++++++++++++++++++ 6 files changed, 161 insertions(+), 8 deletions(-) create mode 100644 src/editor/plugins/core/video/box.html create mode 100644 src/editor/plugins/core/video/videoElement.js diff --git a/src/editor/modules/documentCanvas/canvas/canvas.js b/src/editor/modules/documentCanvas/canvas/canvas.js index ebede40..bbdb0d4 100644 --- a/src/editor/modules/documentCanvas/canvas/canvas.js +++ b/src/editor/modules/documentCanvas/canvas/canvas.js @@ -162,6 +162,11 @@ $.extend(Canvas.prototype, Backbone.Events, { //return DocumentTextElement.fromHTMLElement(htmlElement, canvas); return $element.data('canvas-element'); } + + /* experimental */ + if($element.parent().data('canvas-element')) { + return $element.parent().data('canvas-element'); + } }, reloadRoot: function() { diff --git a/src/editor/plugins/core/canvasElements.js b/src/editor/plugins/core/canvasElements.js index ab3332e..ba72c03 100644 --- a/src/editor/plugins/core/canvasElements.js +++ b/src/editor/plugins/core/canvasElements.js @@ -5,7 +5,8 @@ define(function(require) { var $ = require('libs/jquery'), genericElement = require('modules/documentCanvas/canvas/genericElement'), // TODO: This should be accessible via plugin infrastructure linkElement = require('./links/linkElement'), - imgElement = require('./img/imgElement') + imgElement = require('./img/imgElement'), + videoElement = require('./video/videoElement') ; var widgets = { @@ -116,7 +117,8 @@ return [ {tag: 'aside', klass: 'comment', prototype: null}, {tag: 'aside', klass: 'footnote', prototype: footnote}, {tag: 'span', klass: 'link', prototype: linkElement}, - {tag: 'div', klass: 'img', prototype: imgElement} + {tag: 'div', klass: 'img', prototype: imgElement}, + {tag: 'div', klass: 'video', prototype: videoElement} ]; diff --git a/src/editor/plugins/core/img/imgElement.js b/src/editor/plugins/core/img/imgElement.js index 0ec3ca5..be0ff24 100644 --- a/src/editor/plugins/core/img/imgElement.js +++ b/src/editor/plugins/core/img/imgElement.js @@ -20,8 +20,8 @@ _.extend(linkElement, { var linkText = this.wlxmlNode.getAttr('src') || '', linkUrl = this.getUrl(linkText); - - this._container().attr('style', 'background-image: url(\'' + linkUrl + '\');'); + + this.refreshLink(linkUrl); this.box = $(_.template(boxTemplate)({text: linkText, url: linkUrl})); this.box.find('.change').on('click', this.changeLink); @@ -41,10 +41,15 @@ _.extend(linkElement, { link.text(event.meta.newVal); var linkUrl = this.getUrl(event.meta.newVal); link.attr('href', linkUrl); - this._container().attr('style', 'background-image: url(\'' + linkUrl + '\');'); + this.refreshLink(linkUrl); } }, + refreshLink: function(linkUrl) { + this._container().text(''); + this._container().attr('style', 'background-image: url(\'' + linkUrl + '\');'); + }, + changeLink: function(e) { var el = this, //doc = this.wlxmlNode.document, diff --git a/src/editor/plugins/core/switch.js b/src/editor/plugins/core/switch.js index 88544bf..e3ec5c4 100644 --- a/src/editor/plugins/core/switch.js +++ b/src/editor/plugins/core/switch.js @@ -68,12 +68,13 @@ var createSwitchAction = function(createParams) { var headerAction = createSwitchAction({name: 'switchToHeader', from: {tagName: 'div', klass: 'p'}, to: {tagName: 'header', klass: '', name: gettext('header')}}), paragraphAction = createSwitchAction({name: 'switchToParagraph', from: {tagName: 'header'}, to: {tagName: 'div', klass: 'p', name: gettext('paragraph')}}), - imageAction = createSwitchAction({name: 'switchToImage', from: {tagName: 'div'}, to: {tagName: 'div', klass: 'img', name: gettext('image')}}); + imageAction = createSwitchAction({name: 'switchToImage', from: {tagName: 'div'}, to: {tagName: 'div', klass: 'img', name: gettext('image')}}), + videoAction = createSwitchAction({name: 'switchToVideo', from: {tagName: 'div'}, to: {tagName: 'div', klass: 'video', name: gettext('video')}}); return { - actions: [headerAction, paragraphAction, imageAction], + actions: [headerAction, paragraphAction, imageAction, videoAction], canvasActionHandler: { - handles: [headerAction, paragraphAction, imageAction], + handles: [headerAction, paragraphAction, imageAction, videoAction] // handle: function(canvas, action, ret) { // var params = {}, // f; diff --git a/src/editor/plugins/core/video/box.html b/src/editor/plugins/core/video/box.html new file mode 100644 index 0000000..9294581 --- /dev/null +++ b/src/editor/plugins/core/video/box.html @@ -0,0 +1,7 @@ +
+ <%= text %>
-- + + <%= gettext('change') %> + <%= gettext('remove') %> + +
diff --git a/src/editor/plugins/core/video/videoElement.js b/src/editor/plugins/core/video/videoElement.js new file mode 100644 index 0000000..96003d7 --- /dev/null +++ b/src/editor/plugins/core/video/videoElement.js @@ -0,0 +1,133 @@ +define(function(require) { + +'use strict'; +/* globals gettext */ + + +var $ = require('libs/jquery'), + _ = require('libs/underscore'), + genericElement = require('modules/documentCanvas/canvas/genericElement'), + Dialog = require('views/dialog/dialog'), + boxTemplate = require('libs/text!./box.html'), + attachments = require('views/attachments/attachments'), + linkElement = Object.create(genericElement); + +function youtubeParser(url) { + var regExp = /^.*(?:youtu.be\/|v\/|\/u\/\w\/|embed\/|\?v=|&v=|shared\?ci=)([^#&?]*).*/; + var match = url.match(regExp); + return (match && match[1].length == 11) ? match[1] : false; +} + +_.extend(linkElement, { + init: function() { + genericElement.init.call(this); + _.bindAll(this, 'changeLink', 'deleteLink'); + + var linkText = this.wlxmlNode.getAttr('src') || '', + linkUrl = this.getUrl(linkText); + + this.refreshLink(linkUrl); + + this.box = $(_.template(boxTemplate)({text: linkText, url: linkUrl})); + this.box.find('.change').on('click', this.changeLink); + this.box.find('.delete').on('click', this.deleteLink); + this.box.hide(); + this.addWidget(this.box); + }, + onStateChange: function(changes) { + genericElement.onStateChange.call(this, changes); + if(_.isBoolean(changes.active)) { + this.box.toggle(changes.active); + } + }, + onNodeAttrChange: function(event) { + if(event.meta.attr === 'src') { + var link = this.box.find('[link]'); + link.text(event.meta.newVal); + var linkUrl = this.getUrl(event.meta.newVal); + link.attr('href', linkUrl); + this.refreshLink(linkUrl); + } + }, + + refreshLink: function(linkUrl) { + this._container().find('iframe').remove(); + var video_id = youtubeParser(linkUrl); + if (video_id) { + var video_frame = ''; + this._container().text(''); + this._container().append($(video_frame)); + } else { + this._container().text(gettext('No video')); + } + }, + + changeLink: function(e) { + var el = this, + dialog = Dialog.create({ + title: gettext('Edit video url'), + executeButtonText: gettext('Apply'), + cancelButtonText: gettext('Cancel'), + fields: [ + { + label: gettext('YouTube link'), + name: 'src', + type: 'input', + initialValue: el.wlxmlNode.getAttr('src'), + prePasteHandler: + function(text) { + return this.wlxmlNode.document.getLinkForUrl(text); + }.bind(this) + } + ] + }); + e.preventDefault(); + e.stopPropagation(); + + dialog.on('execute', function(event) { + el.wlxmlNode.document.transaction(function() { + el.wlxmlNode.setAttr('src', event.formData.src); + el.wlxmlNode.setAttr('videoid', youtubeParser(event.formData.src)); + event.success(); + }, { + metadata: { + description: gettext('Edit video url') + //fragment: doc.createFragment(doc.CaretFragment, {node: el.wlxmlNode.contents()[0], offset:offset}) + }, + success: function() { + //el.canvas.select(doc.createFragment(doc.CaretFragment, {node: el.wlxmlNode.contents()[0], offset:offset})); + } + }); + }); + dialog.show(); + $(".attachment-library", dialog.$el).on('click', function() { + attachments.select(function(v) {$("input", dialog.$el).val(v);}); + }); + + }, + + deleteLink: function() { + var el = this; + + el.wlxmlNode.document.transaction(function() { + el.wlxmlNode.detach(); + }, { + metadata: { + description: gettext('Remove link') + } + }); + }, + + getUrl: function(link) { + var pattern = /^[a-z]*:\/\//g; + if(!pattern.test(link) && !/^\//.test(link)) { + link = 'http://' + link; + } + return this.wlxmlNode.document.getUrlForLink(link); + } +}); + +return linkElement; + +}); -- 2.20.1