vue-froala-wysiwyg
Version:
Vue plugin for Froala WYSIWYG HTML rich text editor.
330 lines (319 loc) • 11.1 kB
JavaScript
"use strict";
var _Object$keys = require("@babel/runtime-corejs2/core-js/object/keys");
var _Object$getOwnPropertySymbols = require("@babel/runtime-corejs2/core-js/object/get-own-property-symbols");
var _Object$getOwnPropertyDescriptor = require("@babel/runtime-corejs2/core-js/object/get-own-property-descriptor");
var _Object$getOwnPropertyDescriptors = require("@babel/runtime-corejs2/core-js/object/get-own-property-descriptors");
var _Object$defineProperties = require("@babel/runtime-corejs2/core-js/object/define-properties");
var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");
var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
_Object$defineProperty(exports, "__esModule", {
value: true
});
exports.FroalaView = exports.Froala = void 0;
var _typeof2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/typeof"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/defineProperty"));
var _stringify = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/json/stringify"));
var _froalaEditor = _interopRequireDefault(require("froala-editor"));
var _vue = require("vue");
function ownKeys(e, r) { var t = _Object$keys(e); if (_Object$getOwnPropertySymbols) { var o = _Object$getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return _Object$getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2["default"])(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(e, _Object$getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { _Object$defineProperty(e, r, _Object$getOwnPropertyDescriptor(t, r)); }); } return e; }
var Froala = exports.Froala = (0, _vue.defineComponent)({
name: 'froala',
props: ['tag', 'value', 'config', 'onManualControllerReady', 'modelValue'],
emits: ['update:value', 'manual-controller-ready'],
watch: {
value: function value() {
this.model = this.value;
this.updateValue();
}
},
render: function render() {
return (0, _vue.h)(this.currentTag, [this.$slots["default"] ? this.$slots["default"]()[0] : null]);
},
created: function created() {
this.currentTag = this.tag || this.currentTag;
this.model = this.value;
},
// After first time render.
mounted: function mounted() {
if (this.SPECIAL_TAGS.indexOf(this.currentTag) != -1) {
this.hasSpecialTag = true;
}
if (this.onManualControllerReady) {
this.generateManualController();
} else {
this.createEditor();
}
},
beforeUnmount: function beforeUnmount() {
this.destroyEditor();
},
data: function data() {
return {
initEvents: [],
// Tag on which the editor is initialized.
currentTag: 'div',
// Editor element.
_editor: null,
// Current config.
currentConfig: null,
// Editor options config
defaultConfig: {
immediateVueModelUpdate: false,
vueIgnoreAttrs: null
},
editorInitialized: false,
SPECIAL_TAGS: ['img', 'button', 'input', 'a'],
INNER_HTML_ATTR: 'innerHTML',
hasSpecialTag: false,
model: null,
oldModel: null
};
},
methods: {
updateValue: function updateValue() {
if ((0, _stringify["default"])(this.oldModel) == (0, _stringify["default"])(this.model)) {
return;
}
this.setContent();
},
createEditor: function createEditor() {
if (this.editorInitialized) {
return;
}
this.currentConfig = this.clone(this.config || this.defaultConfig);
this.currentConfig = _objectSpread({}, this.currentConfig);
this.setContent(true);
// Bind editor events.
this.registerEvents();
this.initListeners();
this._editor = new _froalaEditor["default"](this.$el, this.currentConfig);
this.editorInitialized = true;
},
// Return clone object
clone: function clone(item) {
var me = this;
if (!item) {
return item;
} // null, undefined values check
var types = [Number, String, Boolean],
result;
// normalizing primitives if someone did new String('aaa'), or new Number('444');
types.forEach(function (type) {
if (item instanceof type) {
result = type(item);
}
});
if (typeof result == "undefined") {
if (Object.prototype.toString.call(item) === "[object Array]") {
result = [];
item.forEach(function (child, index, array) {
result[index] = me.clone(child);
});
} else if ((0, _typeof2["default"])(item) == "object") {
// testing that this is DOM
if (item.nodeType && typeof item.cloneNode == "function") {
result = item.cloneNode(true);
} else if (!item.prototype) {
// check that this is a literal
if (item instanceof Date) {
result = new Date(item);
} else {
// it is an object literal
result = {};
for (var i in item) {
result[i] = me.clone(item[i]);
}
}
} else {
if (false && item.constructor) {
result = new item.constructor();
} else {
result = item;
}
}
} else {
result = item;
}
}
return result;
},
setContent: function setContent(firstTime) {
if (!this.editorInitialized && !firstTime) {
return;
}
if (this.model || this.model == '') {
this.oldModel = this.model;
if (this.hasSpecialTag) {
this.setSpecialTagContent();
} else {
this.setNormalTagContent(firstTime);
}
}
},
setNormalTagContent: function setNormalTagContent(firstTime) {
var self = this;
function htmlSet() {
self._editor.html.set(self.model || '');
//This will reset the undo stack everytime the model changes externally. Can we fix this?
self._editor.undo.saveStep();
self._editor.undo.reset();
}
if (firstTime) {
this.registerEvent('initialized', function () {
htmlSet();
});
} else {
htmlSet();
}
},
setSpecialTagContent: function setSpecialTagContent() {
var tags = this.model;
// add tags on element
if (tags) {
for (var attr in tags) {
if (tags.hasOwnProperty(attr) && attr != this.INNER_HTML_ATTR) {
this.$el.setAttribute(attr, tags[attr]);
}
}
if (tags.hasOwnProperty(this.INNER_HTML_ATTR)) {
this.$el.innerHTML = tags[this.INNER_HTML_ATTR];
}
}
},
destroyEditor: function destroyEditor() {
if (this._editor) {
this._editor.destroy();
this.editorInitialized = false;
this._editor = null;
}
},
getEditor: function getEditor() {
return this._editor;
},
generateManualController: function generateManualController() {
var controls = {
initialize: this.createEditor,
destroy: this.destroyEditor,
getEditor: this.getEditor
};
this.onManualControllerReady(controls);
},
updateModel: function updateModel() {
var modelContent = '';
if (this.hasSpecialTag) {
var attributeNodes = this.$el.attributes;
var attrs = {};
for (var i = 0; i < attributeNodes.length; i++) {
var attrName = attributeNodes[i].name;
if (this.currentConfig.vueIgnoreAttrs && this.currentConfig.vueIgnoreAttrs.indexOf(attrName) != -1) {
continue;
}
attrs[attrName] = attributeNodes[i].value;
}
if (this.$el.innerHTML) {
attrs[this.INNER_HTML_ATTR] = this.$el.innerHTML;
}
modelContent = attrs;
} else {
var returnedHtml = this._editor.html.get();
if (typeof returnedHtml === 'string') {
modelContent = returnedHtml;
}
}
this.oldModel = modelContent;
this.$emit('update:value', modelContent);
},
initListeners: function initListeners() {
var self = this;
this.registerEvent('initialized', function () {
if (self._editor.events) {
// bind contentChange and keyup event to froalaModel
self._editor.events.on('contentChanged', function () {
self.updateModel();
});
if (self.currentConfig.immediateVueModelUpdate) {
self._editor.events.on('keyup', function () {
self.updateModel();
});
}
}
});
},
// register event on editor element
registerEvent: function registerEvent(eventName, callback) {
if (!eventName || !callback) {
return;
}
// Initialized event.
if (eventName == 'initialized') {
this.initEvents.push(callback);
} else {
if (!this.currentConfig.events) {
this.currentConfig.events = {};
}
this.currentConfig.events[eventName] = callback;
}
},
registerEvents: function registerEvents() {
// Handle initialized on its own.
this.registerInitialized();
// Get current events.
var events = this.currentConfig.events;
if (!events) {
return;
}
for (var event in events) {
if (events.hasOwnProperty(event) && event != 'initialized') {
this.registerEvent(event, events[event]);
}
}
},
registerInitialized: function registerInitialized() {
var _this = this;
// Bind initialized.
if (!this.currentConfig.events) {
this.currentConfig.events = {};
}
// Set original initialized event.
if (this.currentConfig.events.initialized) {
this.registerEvent('initialized', this.currentConfig.events.initialized);
}
// Bind initialized event.
this.currentConfig.events.initialized = function () {
for (var i = 0; i < _this.initEvents.length; i++) {
_this.initEvents[i].call(_this._editor);
}
};
}
}
});
var FroalaView = exports.FroalaView = (0, _vue.defineComponent)({
props: ['tag', 'value'],
watch: {
value: function value(newValue) {
this._element.innerHTML = newValue;
}
},
created: function created() {
this.currentTag = this.tag || this.currentTag;
},
render: function render() {
return (0, _vue.h)(this.currentTag, {
"class": 'fr-view'
});
},
// After first time render.
mounted: function mounted() {
this._element = this.$el;
if (this.value) {
this._element.innerHTML = this.value;
}
},
data: function data() {
return {
currentTag: 'div',
_element: null
};
}
});