From 63a17df6c0e09e46136832f77292ffaac5be98f6 Mon Sep 17 00:00:00 2001 From: xiejiayun Date: Fri, 4 Jan 2019 09:59:36 +0800 Subject: [PATCH 1/3] support link inserter --- example/App.js | 2 +- lib/Link.js | 227 ++++++++++++++++++++++++++++++++++++++ lib/ReactUeditor.js | 42 ++++++- src/Link.js | 128 +++++++++++++++++++++ src/ReactUeditor.js | 37 ++++++- ueditor/ueditor.config.js | 1 - 6 files changed, 433 insertions(+), 4 deletions(-) create mode 100644 lib/Link.js create mode 100644 src/Link.js diff --git a/example/App.js b/example/App.js index f418fb6d..806f2beb 100644 --- a/example/App.js +++ b/example/App.js @@ -73,7 +73,7 @@ class App extends React.Component { ueditorPath='../vendor/ueditor' config={{zIndex: 1001}} value={this.editorResult} - plugins={['uploadImage', 'insertCode', 'uploadVideo', 'uploadAudio']} + plugins={['uploadImage', 'insertCode', 'uploadVideo', 'uploadAudio', 'insertLink']} uploadImage={this.uploadImage} uploadVideo={this.uploadVideo} uploadAudio={this.uploadAudio} diff --git a/lib/Link.js b/lib/Link.js new file mode 100644 index 00000000..7c97b5e2 --- /dev/null +++ b/lib/Link.js @@ -0,0 +1,227 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _Button = _interopRequireDefault(require("./Button")); + +var _Input = _interopRequireDefault(require("./Input")); + +var _Label = _interopRequireDefault(require("./Label")); + +var _Select = _interopRequireDefault(require("./Select")); + +var _rcDialog = _interopRequireDefault(require("rc-dialog")); + +var _react = _interopRequireDefault(require("react")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } + +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } + +function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } + +function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } + +function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } + +function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } + +var inputStyle = { + width: '300px' +}; +var spanStyle = { + fontSize: '14px', + color: 'rgba(0, 0, 0, 0.65)', + display: 'inline-block', + width: '80px' +}; +var formItmeStyle = { + marginBottom: '5px' +}; + +var Link = +/*#__PURE__*/ +function (_React$Component) { + _inherits(Link, _React$Component); + + function Link() { + var _getPrototypeOf2; + + var _temp, _this; + + _classCallCheck(this, Link); + + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + return _possibleConstructorReturn(_this, (_temp = _this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(Link)).call.apply(_getPrototypeOf2, [this].concat(args))), _this.state = { + text: '', + link: '', + title: '', + newTab: false, + showTips: false + }, _this.closeModal = function () { + _this.setState({ + text: '', + link: '', + title: '', + newTab: false, + showTips: false + }); + + _this.props.closeModal(); + }, _this.hasProtocol = function (link) { + if (link.match(/^http:|https:/) || link.match(/^\/\//)) { + return true; + } + + return false; + }, _this.insert = function () { + var _this$state = _this.state, + text = _this$state.text, + link = _this$state.link, + title = _this$state.title, + newTab = _this$state.newTab; + + if (link) { + var html = ''; + + if (!_this.hasProtocol(link)) { + link = 'http://' + link; + } + + html += "").concat(text || link, ""); + + _this.props.insert(html); + } + + _this.closeModal(); + }, _this.changeConfig = function (e, type) { + var value = e.target.value; + var boolType = ['newTab']; + + if (boolType.indexOf(type) !== -1) { + value = !!value; + } + + if (type == 'link') { + if (!_this.hasProtocol(value)) { + _this.setState({ + showTips: true + }); + } else { + _this.setState({ + showTips: false + }); + } + } + + if (type == 'newTab') { + return _this.setState({ + newTab: !_this.state.newTab + }); + } + + _this.setState(_defineProperty({}, type, value)); + }, _temp)); + } + + _createClass(Link, [{ + key: "render", + value: function render() { + var _this2 = this; + + var _this$state2 = this.state, + text = _this$state2.text, + link = _this$state2.link, + title = _this$state2.title, + newTab = _this$state2.newTab, + showTips = _this$state2.showTips; + var visible = this.props.visible; + return _react.default.createElement(_rcDialog.default, { + title: "\u8D85\u94FE\u63A5", + onClose: this.closeModal, + visible: visible, + footer: [_react.default.createElement(_Button.default, { + key: "close", + onClick: this.closeModal + }, "\u53D6\u6D88"), _react.default.createElement(_Button.default, { + key: "insert", + onClick: this.insert + }, "\u63D2\u5165")], + animation: "zome", + maskAnimation: "fade" + }, _react.default.createElement("form", null, _react.default.createElement("div", { + style: formItmeStyle + }, _react.default.createElement("span", { + style: spanStyle + }, "\u6587\u672C\u5185\u5BB9\uFF1A"), _react.default.createElement(_Input.default, { + type: "text", + style: inputStyle, + value: text, + onChange: function onChange(e) { + return _this2.changeConfig(e, 'text'); + } + })), _react.default.createElement("div", { + style: formItmeStyle + }, _react.default.createElement("span", { + style: spanStyle + }, "\u94FE\u63A5\u5730\u5740\uFF1A"), _react.default.createElement(_Input.default, { + type: "text", + style: inputStyle, + value: link, + onChange: function onChange(e) { + return _this2.changeConfig(e, 'link'); + } + })), _react.default.createElement("div", { + style: formItmeStyle + }, _react.default.createElement("span", { + style: spanStyle + }, "\u6807\u9898\uFF1A"), _react.default.createElement(_Input.default, { + type: "text", + style: inputStyle, + value: title, + onChange: function onChange(e) { + return _this2.changeConfig(e, 'title'); + } + })), _react.default.createElement("div", { + style: formItmeStyle + }, _react.default.createElement("span", { + style: { + color: 'rgba(0, 0, 0, 0.65)', + fontSize: '14px' + } + }, "\u662F\u5426\u5728\u65B0\u7A97\u53E3\u6253\u5F00\uFF1A"), _react.default.createElement("input", { + type: "checkbox", + checked: newTab, + onChange: function onChange(e) { + return _this2.changeConfig(e, 'newTab'); + } + })), showTips && _react.default.createElement("p", { + style: { + fontSize: '14px', + color: 'red' + } + }, "\u60A8\u8F93\u5165\u7684\u8D85\u94FE\u63A5\u4E2D\u4E0D\u5305\u542Bhttp\u7B49\u534F\u8BAE\u540D\u79F0\uFF0C\u9ED8\u8BA4\u5C06\u4E3A\u60A8\u6DFB\u52A0http://\u524D\u7F00"))); + } + }]); + + return Link; +}(_react.default.Component); + +var _default = Link; +exports.default = _default; \ No newline at end of file diff --git a/lib/ReactUeditor.js b/lib/ReactUeditor.js index dcefc33a..e9e6df7b 100644 --- a/lib/ReactUeditor.js +++ b/lib/ReactUeditor.js @@ -11,6 +11,8 @@ var _react = _interopRequireDefault(require("react")); var _UploadModal = _interopRequireDefault(require("./UploadModal")); +var _Link = _interopRequireDefault(require("./Link")); + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } @@ -48,6 +50,7 @@ function (_React$Component) { _this.state = { videoModalVisible: false, audioModalVisible: false, + linkModalVisible: false, videoSource: '', audioSource: '' }; @@ -121,6 +124,22 @@ function (_React$Component) { }); }; + _this.registerLink = function () { + window.UE.registerUI('insertLink', function (editor, uiName) { + var btn = new window.UE.ui.Button({ + name: uiName, + title: '超链接', + cssRules: 'background-position: -504px 0px;', + onclick: function onclick() { + editor._react_ref.setState({ + linkModalVisible: true + }); + } + }); + return btn; + }); + }; + _this.uploadImage = function (e) { var uploadImage = _this.props.uploadImage; @@ -163,6 +182,12 @@ function (_React$Component) { } }; + _this.insertLink = function (html) { + if (_this.ueditor) { + _this.ueditor.execCommand('inserthtml', html, true); + } + }; + _this.closeModal = function (type) { switch (type) { case 'video': @@ -177,6 +202,13 @@ function (_React$Component) { audioModalVisible: false }); + break; + + case 'link': + _this.setState({ + linkModalVisible: false + }); + break; } }; @@ -197,6 +229,7 @@ function (_React$Component) { if (plugins.indexOf('insertCode') !== -1) _this.registerSimpleInsertCode(); if (plugins.indexOf('uploadVideo') !== -1) _this.registerUploadVideo(); if (plugins.indexOf('uploadAudio') !== -1) _this.registerUploadAudio(); + if (plugins.indexOf('insertLink') !== -1) _this.registerLink(); } getRef && getRef(_this.ueditor); @@ -307,7 +340,8 @@ function (_React$Component) { var _this$state = this.state, videoModalVisible = _this$state.videoModalVisible, - audioModalVisible = _this$state.audioModalVisible; + audioModalVisible = _this$state.audioModalVisible, + linkModalVisible = _this$state.linkModalVisible; var _this$props2 = this.props, uploadVideo = _this$props2.uploadVideo, uploadAudio = _this$props2.uploadAudio, @@ -345,6 +379,12 @@ function (_React$Component) { insert: this.insert, upload: uploadAudio, progress: progress + }), _react.default.createElement(_Link.default, { + visible: linkModalVisible, + closeModal: function closeModal() { + _this4.closeModal('link'); + }, + insert: this.insertLink })); } }]); diff --git a/src/Link.js b/src/Link.js new file mode 100644 index 00000000..082486a1 --- /dev/null +++ b/src/Link.js @@ -0,0 +1,128 @@ +import Button from './Button' +import Input from './Input' +import Label from './Label' +import Select from './Select' +import Modal from 'rc-dialog' +import React from 'react' + +let inputStyle = { + width: '300px', +} +let spanStyle = { + fontSize: '14px', + color: 'rgba(0, 0, 0, 0.65)', + display: 'inline-block', + width: '80px', +} +let formItmeStyle = { + marginBottom: '5px', +} + +class Link extends React.Component { + state = { + text: '', + link: '', + title: '', + newTab: false, + showTips: false, + } + + closeModal = () => { + this.setState({ + text: '', + link: '', + title: '', + newTab: false, + showTips: false, + }) + this.props.closeModal() + } + + hasProtocol = link => { + if (link.match(/^http:|https:/) || link.match(/^\/\//)) { + return true + } + return false + } + + insert = () => { + let {text, link, title, newTab} = this.state + + if (link) { + let html = '' + + if (!this.hasProtocol(link)) { + link = 'http://' + link + } + + html += `${text || link}` + + this.props.insert(html) + } + this.closeModal() + } + + changeConfig = (e, type) => { + let value = e.target.value + let boolType = ['newTab'] + if (boolType.indexOf(type) !== -1) { + value = !!value + } + + if (type == 'link') { + if (!this.hasProtocol(value)) { + this.setState({ + showTips: true, + }) + } else { + this.setState({ + showTips: false, + }) + } + } + if (type == 'newTab') { + return this.setState({newTab: !this.state.newTab}) + } + this.setState({[type]: value}) + } + + render() { + let {text, link, title, newTab, showTips} = this.state + let {visible} = this.props + + return ( + 取消, + , + ]} + animation='zome' + maskAnimation='fade' > +
+
+ 文本内容: + this.changeConfig(e, 'text')} /> +
+
+ 链接地址: + this.changeConfig(e, 'link')} /> +
+
+ 标题: + this.changeConfig(e, 'title')} /> +
+
+ 是否在新窗口打开: + this.changeConfig(e, 'newTab')} /> +
+ {showTips &&

您输入的超链接中不包含http等协议名称,默认将为您添加http://前缀

} +
+
+ ) + } +} + +export default Link diff --git a/src/ReactUeditor.js b/src/ReactUeditor.js index 8e427650..2bfdb976 100644 --- a/src/ReactUeditor.js +++ b/src/ReactUeditor.js @@ -1,6 +1,7 @@ import PropTypes from 'prop-types' import React from 'react' import UploadModal from './UploadModal' +import Link from './Link' const simpleInsertCodeIcon = 'data:img/jpg;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAB9klEQVRYR+2Wy' + '23CQBCGZxwUASdKgA7IIdIukhF0QCoI6YAS6CB0EDpIOgjCEbs3nApCB+EEKFI80ToYgR/7IEhIEb4hvPN/8/jHi3DmB8+sDxeA/1GBdosNi' + @@ -33,6 +34,7 @@ class ReactUeditor extends React.Component { state = { videoModalVisible: false, audioModalVisible: false, + linkModalVisible: false, videoSource: '', audioSource: '', } @@ -172,6 +174,23 @@ class ReactUeditor extends React.Component { }) } + registerLink = () => { + window.UE.registerUI('insertLink', (editor, uiName) => { + var btn = new window.UE.ui.Button({ + name: uiName, + title: '超链接', + cssRules: 'background-position: -504px 0px;', + onclick: () => { + editor._react_ref.setState({ + linkModalVisible: true, + }) + }, + }) + + return btn + }) + } + uploadImage = e => { let {uploadImage} = this.props if (uploadImage) { @@ -207,6 +226,12 @@ class ReactUeditor extends React.Component { } } + insertLink = html => { + if (this.ueditor) { + this.ueditor.execCommand('inserthtml', html, true) + } + } + closeModal = type => { switch (type) { case 'video': @@ -215,6 +240,9 @@ class ReactUeditor extends React.Component { case 'audio': this.setState({audioModalVisible: false}) break + case 'link': + this.setState({linkModalVisible: false}) + break } } @@ -227,6 +255,7 @@ class ReactUeditor extends React.Component { if (plugins.indexOf('insertCode') !== -1) this.registerSimpleInsertCode() if (plugins.indexOf('uploadVideo') !== -1) this.registerUploadVideo() if (plugins.indexOf('uploadAudio') !== -1) this.registerUploadAudio() + if (plugins.indexOf('insertLink') !== -1) this.registerLink() } getRef && getRef(this.ueditor) this.ueditor.ready(() => { @@ -252,7 +281,7 @@ class ReactUeditor extends React.Component { } render() { - let {videoModalVisible, audioModalVisible} = this.state + let {videoModalVisible, audioModalVisible, linkModalVisible} = this.state let {uploadVideo, uploadAudio, multipleImagesUpload, progress} = this.props return (
@@ -282,6 +311,12 @@ class ReactUeditor extends React.Component { insert={this.insert} upload={uploadAudio} progress={progress} /> + { + this.closeModal('link') + }} + insert={this.insertLink} />
) } diff --git a/ueditor/ueditor.config.js b/ueditor/ueditor.config.js index 5dd7cbc1..ec4d3006 100755 --- a/ueditor/ueditor.config.js +++ b/ueditor/ueditor.config.js @@ -493,4 +493,3 @@ }; })(); - \ No newline at end of file From 7d1a26c98c168c6efeda468ff309ae10079132fb Mon Sep 17 00:00:00 2001 From: xiejiayun Date: Fri, 4 Jan 2019 15:19:57 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E8=B0=83=E6=95=B4=E8=B6=85=E9=93=BE?= =?UTF-8?q?=E6=8E=A5=E7=BC=96=E8=BE=91=E6=A1=86=E4=B8=8A=E4=B8=8B=E9=97=B4?= =?UTF-8?q?=E8=B7=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Link.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Link.js b/src/Link.js index 082486a1..fc41e7c1 100644 --- a/src/Link.js +++ b/src/Link.js @@ -15,7 +15,7 @@ let spanStyle = { width: '80px', } let formItmeStyle = { - marginBottom: '5px', + marginBottom: '10px', } class Link extends React.Component { From 9ca6a858e43004ac5fc7c4db59c5ec25400a41bd Mon Sep 17 00:00:00 2001 From: xiejiayun Date: Fri, 4 Jan 2019 15:27:50 +0800 Subject: [PATCH 3/3] fixed lint error & built --- lib/Link.js | 6 +----- src/Link.js | 2 -- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/Link.js b/lib/Link.js index 7c97b5e2..c18b8d83 100644 --- a/lib/Link.js +++ b/lib/Link.js @@ -9,10 +9,6 @@ var _Button = _interopRequireDefault(require("./Button")); var _Input = _interopRequireDefault(require("./Input")); -var _Label = _interopRequireDefault(require("./Label")); - -var _Select = _interopRequireDefault(require("./Select")); - var _rcDialog = _interopRequireDefault(require("rc-dialog")); var _react = _interopRequireDefault(require("react")); @@ -49,7 +45,7 @@ var spanStyle = { width: '80px' }; var formItmeStyle = { - marginBottom: '5px' + marginBottom: '10px' }; var Link = diff --git a/src/Link.js b/src/Link.js index fc41e7c1..1968f282 100644 --- a/src/Link.js +++ b/src/Link.js @@ -1,7 +1,5 @@ import Button from './Button' import Input from './Input' -import Label from './Label' -import Select from './Select' import Modal from 'rc-dialog' import React from 'react'