vue-editify 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,136 @@
1
+ <template>
2
+ <div class="editify-link">
3
+ <div class="editify-link-label">{{ $editTrans('linkAddress') }}</div>
4
+ <input @focus="handleInputFocus" @blur="handleInputBlur" :placeholder="$editTrans('linkTextEnterPlaceholder')" v-model.trim="linkText" type="text" />
5
+ <input @focus="handleInputFocus" @blur="handleInputBlur" :placeholder="$editTrans('linkUrlEnterPlaceholder')" v-model.trim="linkUrl" type="url" />
6
+ <div class="editify-link-footer">
7
+ <Checkbox v-model="newOpen" :label="$editTrans('newWindowOpen')" :color="color" :size="10"></Checkbox>
8
+ <div class="editify-link-operations">
9
+ <span :style="{ color: color }" @click="insertLink">{{ $editTrans('insertLink') }}</span>
10
+ </div>
11
+ </div>
12
+ </div>
13
+ </template>
14
+ <script>
15
+ import Checkbox from '../base/Checkbox'
16
+ export default {
17
+ name: 'InsertLink',
18
+ emits: ['insert'],
19
+ inject: ['$editTrans'],
20
+ props: {
21
+ //主题色
22
+ color: {
23
+ type: String,
24
+ default: ''
25
+ },
26
+ //预置的链接文本值
27
+ text: {
28
+ type: String,
29
+ default: ''
30
+ }
31
+ },
32
+ data() {
33
+ return {
34
+ //链接地址
35
+ linkUrl: '',
36
+ //链接文本
37
+ linkText: '',
38
+ //是否新窗口打开
39
+ newOpen: false
40
+ }
41
+ },
42
+ watch: {
43
+ text: {
44
+ immediate: true,
45
+ handler: function (newValue) {
46
+ this.linkText = newValue
47
+ }
48
+ }
49
+ },
50
+ components: {
51
+ Checkbox
52
+ },
53
+ methods: {
54
+ //输入框获取焦点
55
+ handleInputFocus(e) {
56
+ if (this.color) {
57
+ e.currentTarget.style.borderColor = this.color
58
+ }
59
+ },
60
+ //输入框失去焦点
61
+ handleInputBlur(e) {
62
+ e.currentTarget.style.borderColor = ''
63
+ },
64
+ //插入链接
65
+ insertLink() {
66
+ this.$emit('insert', this.linkText, this.linkUrl, this.newOpen)
67
+ }
68
+ }
69
+ }
70
+ </script>
71
+ <style lang="less" scoped>
72
+ .editify-link {
73
+ display: block;
74
+ width: 280px;
75
+ padding: 10px 14px;
76
+
77
+ .editify-link-label {
78
+ display: block;
79
+ text-align: left;
80
+ margin-bottom: 10px;
81
+ font-size: @font-size;
82
+ color: @font-color;
83
+ }
84
+
85
+ input {
86
+ appearance: none;
87
+ -webkit-appearance: none;
88
+ -moz-appearance: none;
89
+ display: block;
90
+ width: 100%;
91
+ margin: 0 0 10px 0;
92
+ padding: 4px 2px;
93
+ border: none;
94
+ font-size: @font-size;
95
+ color: @font-color;
96
+ border-bottom: 1px solid @border-color;
97
+ line-height: 1.5;
98
+ transition: border-color 500ms;
99
+ background-color: transparent;
100
+ outline: none;
101
+ box-sizing: border-box;
102
+
103
+ &::-webkit-input-placeholder,
104
+ &::placeholder {
105
+ color: @font-color-disabled;
106
+ font-family: inherit;
107
+ font-size: inherit;
108
+ vertical-align: middle;
109
+ }
110
+ }
111
+
112
+ .editify-link-footer {
113
+ display: flex;
114
+ justify-content: space-between;
115
+ align-items: center;
116
+ width: 100%;
117
+
118
+ .editify-link-operations {
119
+ display: flex;
120
+ justify-content: flex-start;
121
+ align-items: center;
122
+
123
+ & > span {
124
+ cursor: pointer;
125
+ opacity: 0.8;
126
+ transition: all 200ms;
127
+ font-size: @font-size;
128
+
129
+ &:hover {
130
+ opacity: 1;
131
+ }
132
+ }
133
+ }
134
+ }
135
+ }
136
+ </style>
@@ -0,0 +1,113 @@
1
+ <template>
2
+ <div class="editify-table">
3
+ <table>
4
+ <tr v-for="row in tableGrids">
5
+ <td :class="{ inside: column.inside }" v-for="column in row" @mouseenter="changeTableSize(column)" @click="createTable(column)">
6
+ <span></span>
7
+ </td>
8
+ </tr>
9
+ </table>
10
+ </div>
11
+ </template>
12
+ <script>
13
+ export default {
14
+ name: 'InsertTable',
15
+ emits: ['insert'],
16
+ props: {
17
+ //主题色
18
+ color: {
19
+ type: String,
20
+ default: ''
21
+ },
22
+ //最大行数
23
+ maxRows: {
24
+ type: Number,
25
+ default: 10
26
+ },
27
+ //最大列数
28
+ maxColumns: {
29
+ type: Number,
30
+ default: 10
31
+ }
32
+ },
33
+ data() {
34
+ return {
35
+ tableGrids: this.getTableGrids()
36
+ }
37
+ },
38
+ methods: {
39
+ //确认创立表格
40
+ createTable(data) {
41
+ this.$emit('insert', data.x, data.y)
42
+ },
43
+ //改变表格大小
44
+ changeTableSize(data) {
45
+ for (let i in this.tableGrids) {
46
+ const grid = this.tableGrids[i]
47
+ for (let j in grid) {
48
+ if (grid[j].x <= data.x && grid[j].y <= data.y) {
49
+ this.tableGrids[i][j].inside = true
50
+ } else {
51
+ this.tableGrids[i][j].inside = false
52
+ }
53
+ }
54
+ }
55
+ },
56
+ //获取表格
57
+ getTableGrids() {
58
+ const grids = []
59
+ for (let i = 1; i <= this.maxRows; i++) {
60
+ let row = []
61
+ for (let j = 1; j <= this.maxColumns; j++) {
62
+ row.push({
63
+ x: i,
64
+ y: j,
65
+ inside: false //是否被选中
66
+ })
67
+ }
68
+ grids.push(row)
69
+ }
70
+ return grids
71
+ }
72
+ }
73
+ }
74
+ </script>
75
+ <style lang="less" scoped>
76
+ .editify-table {
77
+ display: block;
78
+ position: relative;
79
+ padding: 10px;
80
+
81
+ table {
82
+ border: 1px solid @border-color;
83
+ margin: 0;
84
+ padding: 0;
85
+ border-collapse: collapse;
86
+
87
+ tr {
88
+ margin: 0;
89
+ padding: 0;
90
+
91
+ td {
92
+ margin: 0;
93
+ padding: 0;
94
+ border: 1px solid @border-color;
95
+
96
+ span {
97
+ display: block;
98
+ width: 15px;
99
+ height: 15px;
100
+ }
101
+
102
+ &:hover {
103
+ cursor: pointer;
104
+ }
105
+
106
+ &.inside {
107
+ background-color: @background-darker;
108
+ }
109
+ }
110
+ }
111
+ }
112
+ }
113
+ </style>
@@ -0,0 +1,316 @@
1
+ <template>
2
+ <div class="editify-video">
3
+ <div class="editify-video-header">
4
+ <div @click="current = 'upload'" class="editify-video-header-item" :class="{ active: current == 'upload' }" :style="activeStyle('upload')">{{ $editTrans('uploadVideo') }}</div>
5
+ <div @click="current = 'remote'" class="editify-video-header-item" :class="{ active: current == 'remote' }" :style="activeStyle('remote')">{{ $editTrans('remoteVideo') }}</div>
6
+ <div class="editify-video-header-slider" :class="current" :style="{ backgroundColor: color || '' }"></div>
7
+ </div>
8
+ <!-- 网络视频 -->
9
+ <div class="editify-video-remote" v-if="current == 'remote'">
10
+ <input v-model.trim="remoteUrl" :placeholder="$editTrans('videoUrlPlaceholder')" @blur="handleInputBlur" @focus="handleInputFocus" />
11
+ <div class="editify-video-remote-footer" :style="{ color: color }">
12
+ <span @click="insertRemoteVideo">{{ $editTrans('insert') }}</span>
13
+ </div>
14
+ </div>
15
+ <!-- 上传视频 -->
16
+ <div class="editify-video-upload" v-else>
17
+ <Icon value="upload"></Icon>
18
+ <input :multiple="multiple" accept="video/*" @change="selectFile" type="file" />
19
+ </div>
20
+ </div>
21
+ </template>
22
+ <script>
23
+ import Dap from 'dap-util'
24
+ import Icon from '../base/Icon'
25
+ export default {
26
+ name: 'InsertVideo',
27
+ emits: ['change', 'insert'],
28
+ props: {
29
+ //主题色
30
+ color: {
31
+ type: String,
32
+ default: ''
33
+ },
34
+ //支持的视频类型数组
35
+ accept: {
36
+ type: Array,
37
+ default: null
38
+ },
39
+ //是否支持多选
40
+ multiple: {
41
+ type: Boolean,
42
+ default: false
43
+ },
44
+ //单个文件最大值
45
+ maxSize: {
46
+ type: Number,
47
+ default: null
48
+ },
49
+ //单个文件最小值
50
+ minSize: {
51
+ type: Number,
52
+ default: null
53
+ },
54
+ //是否自定义上传视频
55
+ customUpload: {
56
+ type: Function,
57
+ default: null
58
+ },
59
+ //处理上传视频异常
60
+ handleError: {
61
+ type: Function,
62
+ default: null
63
+ }
64
+ },
65
+ inject: ['$editTrans'],
66
+ data() {
67
+ return {
68
+ current: 'upload', //当前展示的面板,取值remote和upload
69
+ remoteUrl: '' //远程视频链接
70
+ }
71
+ },
72
+ computed: {
73
+ activeStyle() {
74
+ return name => {
75
+ if (this.current == name) {
76
+ return {
77
+ color: this.color
78
+ }
79
+ }
80
+ return {}
81
+ }
82
+ }
83
+ },
84
+ components: {
85
+ Icon
86
+ },
87
+ watch: {
88
+ //监听current变更触发change事件
89
+ current() {
90
+ this.$emit('change')
91
+ }
92
+ },
93
+ methods: {
94
+ //选择文件
95
+ async selectFile(e) {
96
+ const inputEle = e.currentTarget
97
+ const files = inputEle.files
98
+ if (!files.length) {
99
+ return
100
+ }
101
+ let filterFiles = []
102
+ for (let i = 0; i < files.length; i++) {
103
+ const file = files[i]
104
+ const suffix = this.getSuffix(file)
105
+ const isMatch = this.accept.some(item => {
106
+ return item.toLocaleLowerCase() == suffix.toLocaleLowerCase()
107
+ })
108
+ //后缀不符合
109
+ if (!isMatch) {
110
+ //如果自定义了异常处理
111
+ if (typeof this.handleError == 'function') {
112
+ this.handleError.apply(this, ['suffixError', file])
113
+ }
114
+ continue
115
+ }
116
+ //超过最大值
117
+ if (this.maxSize && file.size / 1024 > this.maxSize) {
118
+ //如果自定义了异常处理
119
+ if (typeof this.handleError == 'function') {
120
+ this.handleError.apply(this, ['maxSizeError', file])
121
+ }
122
+ continue
123
+ }
124
+ //没达到最小值
125
+ if (this.minSize && file.size / 1024 < this.minSize) {
126
+ //如果自定义了异常处理
127
+ if (typeof this.handleError == 'function') {
128
+ this.handleError.apply(this, ['minSizeError', file])
129
+ }
130
+ continue
131
+ }
132
+ filterFiles.push(file)
133
+ }
134
+ //有文件可上传
135
+ if (filterFiles.length) {
136
+ //自定义上传方法
137
+ if (typeof this.customUpload == 'function') {
138
+ this.customUpload.apply(this, [filterFiles])
139
+ }
140
+ //默认上传方法
141
+ else {
142
+ let videos = []
143
+ for (let i = 0; i < filterFiles.length; i++) {
144
+ const url = await Dap.file.dataFileToBase64(filterFiles[i])
145
+ videos.push(url)
146
+ }
147
+ videos.forEach(url => {
148
+ this.$emit('insert', url)
149
+ })
150
+ }
151
+ }
152
+ //清空文件选择框
153
+ inputEle.value = ''
154
+ },
155
+ //获取文件后缀
156
+ getSuffix(file) {
157
+ const index = file.name.lastIndexOf('.')
158
+ if (index <= 0) {
159
+ return ''
160
+ }
161
+ return file.name.substring(index + 1)
162
+ },
163
+ //输入框获取焦点
164
+ handleInputFocus(e) {
165
+ if (this.color) {
166
+ e.currentTarget.style.borderColor = this.color
167
+ }
168
+ },
169
+ //输入框失去焦点
170
+ handleInputBlur(e) {
171
+ e.currentTarget.style.borderColor = ''
172
+ },
173
+ //插入网络视频
174
+ insertRemoteVideo() {
175
+ this.$emit('insert', this.remoteUrl)
176
+ }
177
+ }
178
+ }
179
+ </script>
180
+ <style lang="less" scoped>
181
+ .editify-video {
182
+ display: block;
183
+ width: 280px;
184
+ padding: 10px 14px;
185
+
186
+ .editify-video-header {
187
+ display: flex;
188
+ justify-content: flex-start;
189
+ align-items: center;
190
+ width: 100%;
191
+ margin-bottom: 20px;
192
+ position: relative;
193
+ padding-bottom: 6px;
194
+
195
+ .editify-video-header-slider {
196
+ position: absolute;
197
+ width: 50px;
198
+ height: 2px;
199
+ border-radius: 2px;
200
+ left: 0;
201
+ bottom: 0;
202
+ transition: left 200ms;
203
+
204
+ &.upload {
205
+ left: 5px;
206
+ }
207
+
208
+ &.remote {
209
+ left: 85px;
210
+ }
211
+ }
212
+
213
+ .editify-video-header-item {
214
+ display: block;
215
+ text-align: center;
216
+ font-size: @font-size;
217
+ color: @font-color;
218
+ opacity: 0.8;
219
+ transition: all 200ms;
220
+ width: 60px;
221
+ overflow: hidden;
222
+ white-space: nowrap;
223
+ text-overflow: ellipsis;
224
+
225
+ &:hover {
226
+ opacity: 1;
227
+ cursor: pointer;
228
+ }
229
+
230
+ &:first-child {
231
+ margin-right: 20px;
232
+ }
233
+
234
+ &.active {
235
+ opacity: 1;
236
+ color: @font-color-dark;
237
+ }
238
+ }
239
+ }
240
+
241
+ .editify-video-remote {
242
+ display: block;
243
+ width: 100%;
244
+
245
+ input {
246
+ appearance: none;
247
+ -webkit-appearance: none;
248
+ -moz-appearance: none;
249
+ display: block;
250
+ width: 100%;
251
+ margin: 0 0 10px 0;
252
+ padding: 4px 2px;
253
+ border: none;
254
+ font-size: @font-size;
255
+ color: @font-color;
256
+ border-bottom: 1px solid @border-color;
257
+ line-height: 1.5;
258
+ transition: border-color 500ms;
259
+ background-color: transparent;
260
+ outline: none;
261
+ box-sizing: border-box;
262
+
263
+ &::-webkit-input-placeholder,
264
+ &::placeholder {
265
+ color: @font-color-disabled;
266
+ font-family: inherit;
267
+ font-size: inherit;
268
+ vertical-align: middle;
269
+ }
270
+ }
271
+
272
+ .editify-video-remote-footer {
273
+ display: flex;
274
+ justify-content: flex-end;
275
+ align-items: center;
276
+ width: 100%;
277
+ font-size: @font-size;
278
+ opacity: 0.8;
279
+ transition: all 200ms;
280
+
281
+ &:hover {
282
+ cursor: pointer;
283
+ opacity: 1;
284
+ }
285
+ }
286
+ }
287
+
288
+ .editify-video-upload {
289
+ display: flex;
290
+ justify-content: center;
291
+ align-items: center;
292
+ width: 100%;
293
+ padding: 15px 0;
294
+ font-size: 36px;
295
+ opacity: 0.8;
296
+ transition: all 200ms;
297
+ position: relative;
298
+
299
+ &:hover {
300
+ cursor: pointer;
301
+ opacity: 1;
302
+ }
303
+
304
+ input {
305
+ opacity: 0;
306
+ position: absolute;
307
+ left: 0;
308
+ top: 0;
309
+ width: 100%;
310
+ height: 100%;
311
+ z-index: 1;
312
+ cursor: pointer;
313
+ }
314
+ }
315
+ }
316
+ </style>