@longhongguo/form-create-ant-design-vue 3.3.6 → 3.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@longhongguo/form-create-ant-design-vue",
3
- "version": "3.3.06",
3
+ "version": "3.3.07",
4
4
  "description": "AntDesignVue版本低代码表单|FormCreate 是一个可以通过 JSON 生成具有动态渲染、数据收集、验证和提交功能的低代码表单生成组件。支持6个UI框架,适配移动端,并且支持生成任何 Vue 组件。内置20种常用表单组件和自定义组件,再复杂的表单都可以轻松搞定。",
5
5
  "main": "./dist/form-create.min.js",
6
6
  "module": "./dist/form-create.esm.js",
@@ -54,7 +54,7 @@
54
54
  "@form-create/component-subform": "^3.1.34",
55
55
  "@form-create/core": "^3.2.33",
56
56
  "@form-create/utils": "^3.2.31",
57
- "@longhongguo/component-antdv-upload": "^3.2.41",
57
+ "@longhongguo/component-antdv-upload": "^3.2.42",
58
58
  "@longhongguo/form-create-core": "^3.2.63",
59
59
  "moment": "^2.30.1"
60
60
  },
@@ -1,7 +1,8 @@
1
1
  <template>
2
2
  <FcEditor
3
3
  :model-value="modelValue"
4
- :disabled="disabled"
4
+ :disabled="disabled && !readOnly"
5
+ :readOnly="readOnly"
5
6
  :config="editorConfig"
6
7
  :init="initEditor"
7
8
  @update:model-value="$emit('update:modelValue', $event)"
@@ -21,6 +22,7 @@ export default defineComponent({
21
22
  props: {
22
23
  modelValue: String,
23
24
  disabled: Boolean,
25
+ readOnly: Boolean,
24
26
  // 图片上传相关配置
25
27
  uploadImgServer: String,
26
28
  uploadImgFieldName: {
@@ -37,10 +39,30 @@ export default defineComponent({
37
39
  formCreateInject: Object
38
40
  },
39
41
  emits: ['update:modelValue'],
42
+ watch: {
43
+ readOnly(newVal) {
44
+ // 当只读状态变化时,更新编辑器状态
45
+ if (this._editor) {
46
+ this.setReadOnlyMode(newVal)
47
+ }
48
+ }
49
+ },
40
50
  computed: {
41
51
  editorConfig() {
42
52
  const config = {}
43
53
 
54
+ // 如果设置了 readOnly,配置只读模式
55
+ if (this.readOnly) {
56
+ // readOnly: true // 启用只读模式
57
+ // 注意:实际只读效果主要通过 setReadOnlyMode 方法实现
58
+ // (设置 contenteditable="false" 和阻止编辑事件)
59
+ // 只读模式允许复制文本和点击链接,但禁止编辑
60
+ config.readOnly = true
61
+ // 禁用自动聚焦,避免在只读模式下获得焦点
62
+ config.focus = false
63
+ config.autoFocus = false
64
+ }
65
+
44
66
  // 如果设置了 uploadImgServer,配置图片上传
45
67
  if (this.uploadImgServer) {
46
68
  // wangeditor 4.x 使用这些配置项
@@ -154,9 +176,603 @@ export default defineComponent({
154
176
  return config
155
177
  }
156
178
  },
179
+ beforeUnmount() {
180
+ // 清理粘贴事件监听器
181
+ if (this._pasteHandler && this._pasteHandlerContainer) {
182
+ this._pasteHandlerContainer.removeEventListener(
183
+ 'paste',
184
+ this._pasteHandler,
185
+ true
186
+ )
187
+ this._pasteHandler = null
188
+ this._pasteHandlerContainer = null
189
+ }
190
+
191
+ // 清理只读模式相关的监听器和定时器
192
+ if (this._editor) {
193
+ this.$nextTick(() => {
194
+ let textContainer = null
195
+ if (this._editor.$textElem && this._editor.$textElem[0]) {
196
+ textContainer = this._editor.$textElem[0]
197
+ } else {
198
+ const editorId = this._editor.id
199
+ if (editorId) {
200
+ const editorEl = document.getElementById(editorId)
201
+ if (editorEl) {
202
+ textContainer = editorEl.querySelector('.w-e-text')
203
+ }
204
+ }
205
+ }
206
+
207
+ if (textContainer) {
208
+ // 清除定时器
209
+ if (textContainer._readOnlyInterval) {
210
+ clearInterval(textContainer._readOnlyInterval)
211
+ delete textContainer._readOnlyInterval
212
+ }
213
+
214
+ // 停止观察器
215
+ if (textContainer._readOnlyAttributeObserver) {
216
+ textContainer._readOnlyAttributeObserver.disconnect()
217
+ delete textContainer._readOnlyAttributeObserver
218
+ }
219
+ if (textContainer._readOnlyLinkObserver) {
220
+ textContainer._readOnlyLinkObserver.disconnect()
221
+ delete textContainer._readOnlyLinkObserver
222
+ }
223
+
224
+ // 移除事件监听器
225
+ if (textContainer._readOnlyHandlers) {
226
+ const handlers = textContainer._readOnlyHandlers
227
+ if (handlers.preventEdit) {
228
+ textContainer.removeEventListener(
229
+ 'keydown',
230
+ handlers.preventEdit,
231
+ true
232
+ )
233
+ }
234
+ if (handlers.preventAllEdit) {
235
+ textContainer.removeEventListener(
236
+ 'keypress',
237
+ handlers.preventAllEdit,
238
+ true
239
+ )
240
+ textContainer.removeEventListener(
241
+ 'paste',
242
+ handlers.preventAllEdit,
243
+ true
244
+ )
245
+ textContainer.removeEventListener(
246
+ 'drop',
247
+ handlers.preventAllEdit,
248
+ true
249
+ )
250
+ textContainer.removeEventListener(
251
+ 'input',
252
+ handlers.preventAllEdit,
253
+ true
254
+ )
255
+ textContainer.removeEventListener(
256
+ 'beforeinput',
257
+ handlers.preventAllEdit,
258
+ true
259
+ )
260
+ textContainer.removeEventListener(
261
+ 'compositionstart',
262
+ handlers.preventAllEdit,
263
+ true
264
+ )
265
+ textContainer.removeEventListener(
266
+ 'compositionupdate',
267
+ handlers.preventAllEdit,
268
+ true
269
+ )
270
+ textContainer.removeEventListener(
271
+ 'compositionend',
272
+ handlers.preventAllEdit,
273
+ true
274
+ )
275
+ }
276
+ delete textContainer._readOnlyHandlers
277
+ }
278
+ }
279
+ })
280
+ }
281
+ },
157
282
  methods: {
158
283
  initEditor(editor) {
159
- // 可以在这里添加额外的编辑器初始化逻辑
284
+ if (!editor) return
285
+
286
+ // 保存编辑器引用
287
+ this._editor = editor
288
+
289
+ // 如果设置了只读模式,配置编辑器为只读
290
+ // 使用多重延迟和监听,确保编辑器完全创建后再设置
291
+ if (this.readOnly) {
292
+ // 立即设置一次
293
+ this.$nextTick(() => {
294
+ this.setReadOnlyMode(true)
295
+ })
296
+
297
+ // 第一次延迟:等待编辑器 DOM 创建
298
+ setTimeout(() => {
299
+ this.setReadOnlyMode(true)
300
+ // 第二次延迟:确保设置生效
301
+ setTimeout(() => {
302
+ this.setReadOnlyMode(true)
303
+ // 第三次延迟:确保完全生效
304
+ setTimeout(() => {
305
+ this.setReadOnlyMode(true)
306
+ }, 300)
307
+ }, 200)
308
+ }, 100)
309
+ }
310
+
311
+ // 等待编辑器完全创建后,监听粘贴事件
312
+ this.$nextTick(() => {
313
+ // 尝试多种方式查找编辑器容器
314
+ let editorContainer = null
315
+
316
+ // 方式1: 通过编辑器实例属性查找
317
+ if (editor.$textContainerElem && editor.$textContainerElem[0]) {
318
+ editorContainer = editor.$textContainerElem[0]
319
+ } else if (editor.$textElem && editor.$textElem[0]) {
320
+ editorContainer = editor.$textElem[0]
321
+ }
322
+
323
+ // 方式2: 通过编辑器 ID 查找
324
+ if (!editorContainer && editor.id) {
325
+ const editorEl = document.getElementById(editor.id)
326
+ if (editorEl) {
327
+ editorContainer =
328
+ editorEl.querySelector('.w-e-text-container') ||
329
+ editorEl.querySelector('.w-e-text')
330
+ }
331
+ }
332
+
333
+ // 方式3: 通过 class 查找(通用方法)
334
+ if (!editorContainer) {
335
+ const textContainer = document.querySelector('.w-e-text-container')
336
+ if (textContainer) {
337
+ editorContainer = textContainer
338
+ }
339
+ }
340
+
341
+ if (editorContainer) {
342
+ this.setupPasteHandler(editor, editorContainer)
343
+ } else {
344
+ // 延迟重试,等待编辑器完全渲染
345
+ setTimeout(() => {
346
+ const textContainer =
347
+ document.querySelector('.w-e-text-container') ||
348
+ document.querySelector('.w-e-text')
349
+ if (textContainer && editor) {
350
+ this.setupPasteHandler(editor, textContainer)
351
+ } else {
352
+ console.warn(
353
+ '无法找到 wangEditor 文本容器,链接自动转换功能可能无法正常工作'
354
+ )
355
+ }
356
+ }, 500)
357
+ }
358
+ })
359
+ },
360
+ // 设置粘贴事件处理器
361
+ setupPasteHandler(editor, container) {
362
+ const handlePaste = (event) => {
363
+ // 获取粘贴的文本内容
364
+ const pasteText = (
365
+ event.clipboardData || window.clipboardData
366
+ )?.getData('text')
367
+
368
+ // 检查是否为纯链接(URL格式)
369
+ if (pasteText && this.isValidUrl(pasteText.trim())) {
370
+ // 阻止默认粘贴行为
371
+ event.preventDefault()
372
+ event.stopPropagation()
373
+
374
+ try {
375
+ const url = pasteText.trim()
376
+ // 确保 URL 有协议
377
+ const fullUrl =
378
+ url.startsWith('http://') || url.startsWith('https://')
379
+ ? url
380
+ : `http://${url}`
381
+
382
+ // 尝试使用 wangEditor 的命令插入链接
383
+ // wangEditor 4.x 支持通过 cmd.do 执行命令
384
+ if (editor.cmd && editor.cmd.do) {
385
+ try {
386
+ // 先插入文本,然后选中并转换为链接
387
+ editor.cmd.do(
388
+ 'insertHTML',
389
+ `<a href="${fullUrl}" target="_blank" rel="noopener noreferrer">${url}</a>`
390
+ )
391
+ return false
392
+ } catch (e) {
393
+ // 如果 cmd.do 失败,继续使用 DOM 方式
394
+ console.debug('使用 cmd.do 插入链接失败,尝试 DOM 方式:', e)
395
+ }
396
+ }
397
+
398
+ // 使用 DOM 方式插入链接
399
+ const selection = window.getSelection()
400
+ if (selection && selection.rangeCount > 0) {
401
+ const range = selection.getRangeAt(0)
402
+
403
+ // 删除选中的内容
404
+ range.deleteContents()
405
+
406
+ // 创建链接元素
407
+ const linkElement = document.createElement('a')
408
+ linkElement.href = fullUrl
409
+ linkElement.textContent = url
410
+ linkElement.target = '_blank'
411
+ linkElement.rel = 'noopener noreferrer'
412
+
413
+ // 插入链接
414
+ range.insertNode(linkElement)
415
+
416
+ // 移动光标到链接后面,并添加一个空格
417
+ const textNode = document.createTextNode(' ')
418
+ range.setStartAfter(linkElement)
419
+ range.insertNode(textNode)
420
+ range.setStartAfter(textNode)
421
+ range.collapse(true)
422
+ selection.removeAllRanges()
423
+ selection.addRange(range)
424
+
425
+ // 触发编辑器内容变化
426
+ // 尝试多种方式触发更新
427
+ if (editor.txt) {
428
+ // 方式1: 触发 change 事件
429
+ if (
430
+ editor.txt.eventHooks &&
431
+ editor.txt.eventHooks.changeEvents
432
+ ) {
433
+ editor.txt.eventHooks.changeEvents.forEach((fn) => {
434
+ if (typeof fn === 'function') {
435
+ try {
436
+ fn()
437
+ } catch (e) {
438
+ console.debug('触发编辑器变化事件失败:', e)
439
+ }
440
+ }
441
+ })
442
+ }
443
+
444
+ // 方式2: 手动触发 input 事件
445
+ const inputEvent = new Event('input', {
446
+ bubbles: true,
447
+ cancelable: true
448
+ })
449
+ container.dispatchEvent(inputEvent)
450
+
451
+ // 方式3: 触发 change 事件
452
+ const changeEvent = new Event('change', {
453
+ bubbles: true,
454
+ cancelable: true
455
+ })
456
+ container.dispatchEvent(changeEvent)
457
+ }
458
+ }
459
+ } catch (error) {
460
+ console.error('插入链接失败:', error)
461
+ // 如果出错,回退到普通粘贴
462
+ setTimeout(() => {
463
+ const textNode = document.createTextNode(pasteText)
464
+ const selection = window.getSelection()
465
+ if (selection && selection.rangeCount > 0) {
466
+ const range = selection.getRangeAt(0)
467
+ range.deleteContents()
468
+ range.insertNode(textNode)
469
+ range.setStartAfter(textNode)
470
+ range.collapse(true)
471
+ selection.removeAllRanges()
472
+ selection.addRange(range)
473
+ }
474
+ }, 0)
475
+ }
476
+
477
+ return false
478
+ }
479
+ }
480
+
481
+ // 在捕获阶段监听粘贴事件
482
+ container.addEventListener('paste', handlePaste, true)
483
+
484
+ // 保存处理器引用,以便在组件销毁时移除
485
+ this._pasteHandler = handlePaste
486
+ this._pasteHandlerContainer = container
487
+ },
488
+ // 设置只读模式:允许选择和点击链接,但禁止编辑
489
+ setReadOnlyMode(readOnly) {
490
+ if (!this._editor) return
491
+
492
+ // 使用 wangEditor 的 disable/enable 方法
493
+ if (readOnly) {
494
+ // 禁用编辑器
495
+ if (
496
+ this._editor.disable &&
497
+ typeof this._editor.disable === 'function'
498
+ ) {
499
+ this._editor.disable()
500
+ }
501
+ } else {
502
+ // 启用编辑器
503
+ if (this._editor.enable && typeof this._editor.enable === 'function') {
504
+ this._editor.enable()
505
+ }
506
+ }
507
+
508
+ this.$nextTick(() => {
509
+ // 查找编辑器的文本容器
510
+ let textContainer = null
511
+ if (this._editor.$textElem && this._editor.$textElem[0]) {
512
+ textContainer = this._editor.$textElem[0]
513
+ } else {
514
+ const editorId = this._editor.id
515
+ if (editorId) {
516
+ const editorEl = document.getElementById(editorId)
517
+ if (editorEl) {
518
+ textContainer = editorEl.querySelector('.w-e-text')
519
+ }
520
+ }
521
+ }
522
+
523
+ // 也尝试查找容器
524
+ if (!textContainer) {
525
+ if (
526
+ this._editor.$textContainerElem &&
527
+ this._editor.$textContainerElem[0]
528
+ ) {
529
+ textContainer = this._editor.$textContainerElem[0]
530
+ }
531
+ }
532
+
533
+ if (textContainer) {
534
+ if (readOnly) {
535
+ // 强制设置为只读:禁用编辑,但允许选择和点击链接
536
+ const forceReadOnly = () => {
537
+ // 强制设置 contenteditable
538
+ textContainer.setAttribute('contenteditable', 'false')
539
+ // 确保文本可以选择
540
+ textContainer.style.userSelect = 'text'
541
+ textContainer.style.webkitUserSelect = 'text'
542
+ textContainer.style.mozUserSelect = 'text'
543
+ textContainer.style.msUserSelect = 'text'
544
+ textContainer.style.cursor = 'text'
545
+ }
546
+
547
+ forceReadOnly()
548
+
549
+ // 监听 contenteditable 属性的变化,强制保持只读
550
+ const attributeObserver = new MutationObserver(() => {
551
+ if (textContainer.getAttribute('contenteditable') !== 'false') {
552
+ forceReadOnly()
553
+ }
554
+ })
555
+ attributeObserver.observe(textContainer, {
556
+ attributes: true,
557
+ attributeFilter: ['contenteditable']
558
+ })
559
+
560
+ // 阻止所有编辑操作的事件处理器
561
+ const preventAllEdit = (e) => {
562
+ // 阻止所有输入操作
563
+ e.preventDefault()
564
+ e.stopPropagation()
565
+ e.stopImmediatePropagation()
566
+ return false
567
+ }
568
+
569
+ // 阻止键盘输入(但允许选择快捷键如 Ctrl+A, Ctrl+C)
570
+ const preventEdit = (e) => {
571
+ // 允许复制、全选等快捷键
572
+ if (
573
+ (e.ctrlKey || e.metaKey) &&
574
+ (e.key === 'a' || e.key === 'c' || e.key === 'x')
575
+ ) {
576
+ return true
577
+ }
578
+ // 阻止所有其他键盘输入
579
+ if (e.key && e.key.length === 1) {
580
+ e.preventDefault()
581
+ e.stopPropagation()
582
+ return false
583
+ }
584
+ // 阻止删除键(当没有选中内容时)
585
+ if (
586
+ (e.key === 'Delete' || e.key === 'Backspace') &&
587
+ !e.ctrlKey &&
588
+ !e.metaKey
589
+ ) {
590
+ const selection = window.getSelection()
591
+ if (
592
+ !selection ||
593
+ selection.rangeCount === 0 ||
594
+ selection.isCollapsed
595
+ ) {
596
+ e.preventDefault()
597
+ e.stopPropagation()
598
+ return false
599
+ }
600
+ }
601
+ }
602
+
603
+ // 添加事件监听器(使用捕获阶段,优先级最高)
604
+ textContainer.addEventListener('keydown', preventEdit, true)
605
+ textContainer.addEventListener('keypress', preventAllEdit, true)
606
+ textContainer.addEventListener('paste', preventAllEdit, true)
607
+ textContainer.addEventListener('drop', preventAllEdit, true)
608
+ textContainer.addEventListener('input', preventAllEdit, true)
609
+ textContainer.addEventListener('beforeinput', preventAllEdit, true)
610
+ textContainer.addEventListener(
611
+ 'compositionstart',
612
+ preventAllEdit,
613
+ true
614
+ )
615
+ textContainer.addEventListener(
616
+ 'compositionupdate',
617
+ preventAllEdit,
618
+ true
619
+ )
620
+ textContainer.addEventListener(
621
+ 'compositionend',
622
+ preventAllEdit,
623
+ true
624
+ )
625
+
626
+ // 保存事件处理器引用,以便清理
627
+ if (!textContainer._readOnlyHandlers) {
628
+ textContainer._readOnlyHandlers = {}
629
+ }
630
+ textContainer._readOnlyHandlers.preventEdit = preventEdit
631
+ textContainer._readOnlyHandlers.preventAllEdit = preventAllEdit
632
+ textContainer._readOnlyAttributeObserver = attributeObserver
633
+
634
+ // 允许链接点击
635
+ const enableLinks = () => {
636
+ const links = textContainer.querySelectorAll('a')
637
+ links.forEach((link) => {
638
+ link.style.pointerEvents = 'auto'
639
+ link.style.cursor = 'pointer'
640
+ })
641
+ }
642
+ enableLinks()
643
+
644
+ // 监听新添加的链接
645
+ const linkObserver = new MutationObserver(() => {
646
+ enableLinks()
647
+ // 确保 contenteditable 保持为 false
648
+ forceReadOnly()
649
+ })
650
+ linkObserver.observe(textContainer, {
651
+ childList: true,
652
+ subtree: true,
653
+ attributes: true,
654
+ attributeFilter: ['contenteditable']
655
+ })
656
+ textContainer._readOnlyLinkObserver = linkObserver
657
+
658
+ // 定期检查并强制设置(防止被覆盖)
659
+ if (!textContainer._readOnlyInterval) {
660
+ textContainer._readOnlyInterval = setInterval(() => {
661
+ if (textContainer.getAttribute('contenteditable') !== 'false') {
662
+ forceReadOnly()
663
+ }
664
+ }, 100)
665
+ }
666
+ } else {
667
+ // 取消只读:恢复编辑功能
668
+ textContainer.setAttribute('contenteditable', 'true')
669
+
670
+ // 清除定时器
671
+ if (textContainer._readOnlyInterval) {
672
+ clearInterval(textContainer._readOnlyInterval)
673
+ delete textContainer._readOnlyInterval
674
+ }
675
+
676
+ // 移除事件监听器
677
+ if (textContainer._readOnlyHandlers) {
678
+ const handlers = textContainer._readOnlyHandlers
679
+ textContainer.removeEventListener(
680
+ 'keydown',
681
+ handlers.preventEdit,
682
+ true
683
+ )
684
+ textContainer.removeEventListener(
685
+ 'keypress',
686
+ handlers.preventAllEdit,
687
+ true
688
+ )
689
+ textContainer.removeEventListener(
690
+ 'paste',
691
+ handlers.preventAllEdit,
692
+ true
693
+ )
694
+ textContainer.removeEventListener(
695
+ 'drop',
696
+ handlers.preventAllEdit,
697
+ true
698
+ )
699
+ textContainer.removeEventListener(
700
+ 'input',
701
+ handlers.preventAllEdit,
702
+ true
703
+ )
704
+ textContainer.removeEventListener(
705
+ 'beforeinput',
706
+ handlers.preventAllEdit,
707
+ true
708
+ )
709
+ textContainer.removeEventListener(
710
+ 'compositionstart',
711
+ handlers.preventAllEdit,
712
+ true
713
+ )
714
+ textContainer.removeEventListener(
715
+ 'compositionupdate',
716
+ handlers.preventAllEdit,
717
+ true
718
+ )
719
+ textContainer.removeEventListener(
720
+ 'compositionend',
721
+ handlers.preventAllEdit,
722
+ true
723
+ )
724
+ delete textContainer._readOnlyHandlers
725
+ }
726
+
727
+ // 停止观察
728
+ if (textContainer._readOnlyAttributeObserver) {
729
+ textContainer._readOnlyAttributeObserver.disconnect()
730
+ delete textContainer._readOnlyAttributeObserver
731
+ }
732
+ if (textContainer._readOnlyLinkObserver) {
733
+ textContainer._readOnlyLinkObserver.disconnect()
734
+ delete textContainer._readOnlyLinkObserver
735
+ }
736
+ }
737
+ }
738
+ })
739
+ },
740
+ // 验证是否为有效的URL
741
+ isValidUrl(str) {
742
+ if (!str || typeof str !== 'string') return false
743
+
744
+ const trimmed = str.trim()
745
+ if (!trimmed) return false
746
+
747
+ try {
748
+ // 检查是否包含常见协议
749
+ const urlPattern = /^(https?|ftp|file):\/\//i
750
+ if (urlPattern.test(trimmed)) {
751
+ new URL(trimmed)
752
+ return true
753
+ }
754
+
755
+ // 检查是否看起来像URL(包含域名)
756
+ // 匹配形如 www.example.com 或 example.com 的格式
757
+ const domainPattern =
758
+ /^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}(\/.*)?$/i
759
+ // 或者简单的 http/https URL 格式
760
+ const simpleUrlPattern = /^[a-zA-Z0-9][a-zA-Z0-9\-]*\.[a-zA-Z]{2,}/
761
+
762
+ if (domainPattern.test(trimmed) || simpleUrlPattern.test(trimmed)) {
763
+ // 尝试添加 http:// 前缀来验证
764
+ try {
765
+ new URL(`http://${trimmed}`)
766
+ return true
767
+ } catch (e) {
768
+ return false
769
+ }
770
+ }
771
+
772
+ return false
773
+ } catch (e) {
774
+ return false
775
+ }
160
776
  },
161
777
  handleDefaultResponse(res, insertImgFn) {
162
778
  // 处理标准响应格式: {errno: 0, data: {url: "...", alt: "...", href: "..."}}
package/src/core/alias.js CHANGED
@@ -40,6 +40,9 @@ export default {
40
40
  object: 'fcSubForm',
41
41
  image: PRE + 'Image',
42
42
  aImage: PRE + 'Image',
43
+ alert: PRE + 'Alert',
44
+ aAlert: PRE + 'Alert',
45
+ Alert: PRE + 'Alert',
43
46
  accTable: PRE + 'Table',
44
47
  accTableTable: PRE + 'Table'
45
48
  }