@ajaxjs/ui 1.1.2 → 1.1.3
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/README.md +4 -24
- package/dist/css/app.11ca79dd.css +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.html +1 -0
- package/dist/index.js +56 -3
- package/dist/index.js.map +1 -1
- package/dist/js/app.44da9bce.js +2 -0
- package/dist/js/app.44da9bce.js.map +1 -0
- package/dist/js/chunk-vendors.0d9e9c3a.js +8 -0
- package/dist/js/chunk-vendors.0d9e9c3a.js.map +1 -0
- package/dist/main.d.ts +1 -0
- package/dist/main.js +14 -9
- package/dist/main.js.map +1 -1
- package/dist/router/index.d.ts +3 -0
- package/dist/router/index.js +36 -28
- package/dist/router/index.js.map +1 -1
- package/dist/shims-vue.d.ts +4 -0
- package/dist/util/cookies.d.ts +18 -0
- package/dist/util/cookies.js +46 -0
- package/dist/util/cookies.js.map +1 -0
- package/dist/util/dom.d.ts +17 -0
- package/dist/util/dom.js +44 -0
- package/dist/util/dom.js.map +1 -0
- package/dist/util/system/config.d.ts +13 -0
- package/dist/util/system/config.js +84 -0
- package/dist/util/system/config.js.map +1 -0
- package/dist/util/utils.d.ts +44 -0
- package/dist/util/utils.js +140 -0
- package/dist/util/utils.js.map +1 -0
- package/dist/util/xhr-config.d.ts +22 -0
- package/dist/util/xhr-config.js +3 -0
- package/dist/util/xhr-config.js.map +1 -0
- package/dist/util/xhr.d.ts +71 -0
- package/dist/util/xhr.js +262 -0
- package/dist/util/xhr.js.map +1 -0
- package/dist/{components/widgets → widget}/AccordionMenu.vue +139 -137
- package/dist/{components/widgets → widget}/AdjustFontSize.vue +65 -65
- package/dist/{components/widgets → widget}/Article.vue +58 -48
- package/dist/{components/widgets → widget}/BaiduSearch.vue +49 -49
- package/dist/widget/EmptyContent.d.ts +5 -0
- package/dist/widget/EmptyContent.js +7 -0
- package/dist/widget/EmptyContent.js.map +1 -0
- package/dist/{components/widgets → widget}/Expander.vue +64 -64
- package/dist/widget/FileUploader/FileUploader.d.ts +70 -0
- package/dist/{components/form → widget}/FileUploader/FileUploader.js +40 -5
- package/dist/widget/FileUploader/FileUploader.js.map +1 -0
- package/dist/{components/form → widget}/FileUploader/FileUploader.less +67 -54
- package/dist/{components/form → widget}/FileUploader/FileUploader.ts +155 -120
- package/dist/widget/FileUploader/FileUploader.vue +43 -0
- package/dist/widget/HtmlEditor/HtmlEditor.d.ts +70 -0
- package/dist/{components/form → widget}/HtmlEditor/HtmlEditor.js +10 -7
- package/dist/widget/HtmlEditor/HtmlEditor.js.map +1 -0
- package/dist/{components/form → widget}/HtmlEditor/HtmlEditor.less +344 -344
- package/dist/{components/form → widget}/HtmlEditor/HtmlEditor.ts +338 -336
- package/dist/{components/form → widget}/HtmlEditor/HtmlEditor.vue +69 -69
- package/dist/{components/form → widget}/HtmlEditor/html-editor-HtmlSanitizer.js +102 -102
- package/dist/{components/widgets → widget}/ImageEnlarger.vue +104 -98
- package/dist/{components/widgets → widget}/OpacityBanner.vue +124 -123
- package/dist/{components/widgets → widget}/ProcessLine.vue +132 -132
- package/dist/widget/Resize.d.ts +51 -0
- package/dist/widget/Resize.js +133 -0
- package/dist/widget/Resize.js.map +1 -0
- package/dist/widget/Resize.ts +152 -0
- package/dist/widget/Resize.vue +104 -0
- package/dist/widget/TreeSelector.vue +4 -0
- package/dist/widget/calendar/BetweenDate.vue +63 -0
- package/dist/widget/calendar/Calendar.d.ts +55 -0
- package/dist/widget/calendar/Calendar.js +145 -0
- package/dist/widget/calendar/Calendar.js.map +1 -0
- package/dist/widget/calendar/Calendar.less +208 -0
- package/dist/widget/calendar/Calendar.ts +167 -0
- package/dist/widget/calendar/Calendar.vue +52 -0
- package/dist/widget/calendar/CalendarInput.vue +71 -0
- package/dist/widget/form/validator.d.ts +72 -0
- package/dist/widget/form/validator.js +222 -0
- package/dist/widget/form/validator.js.map +1 -0
- package/dist/widget/form/validator.ts +290 -0
- package/dist/widget/play-ground/sku.vue +93 -0
- package/package.json +36 -33
- package/dist/components/form/AjSelect.vue +0 -33
- package/dist/components/form/FileUploader/FileUploader.js.map +0 -1
- package/dist/components/form/FileUploader/FileUploader.vue +0 -26
- package/dist/components/form/HtmlEditor/HtmlEditor.js.map +0 -1
- package/dist/components/form/TreeLikeSelect.vue +0 -125
|
@@ -1,70 +1,70 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="aj-form-html-editor">
|
|
3
|
-
<ul class="toolbar">
|
|
4
|
-
<li class="dorpdown">
|
|
5
|
-
<i title="字体" class="text-icon">A</i>
|
|
6
|
-
<div class="fontfamilyChoser" @click="onFontfamilyChoserClk">
|
|
7
|
-
<a style="font-family: '宋体'">宋体</a>
|
|
8
|
-
<a style="font-family: '黑体'">黑体</a>
|
|
9
|
-
<a style="font-family: '楷体'">楷体</a>
|
|
10
|
-
<a style="font-family: '隶书'">隶书</a>
|
|
11
|
-
<a style="font-family: '幼圆'">幼圆</a>
|
|
12
|
-
<a style="font-family: 'Microsoft YaHei'">Microsoft YaHei</a>
|
|
13
|
-
<a style="font-family: Arial">Arial</a>
|
|
14
|
-
<a style="font-family: 'Arial Narrow'">Arial Narrow</a>
|
|
15
|
-
<a style="font-family: 'Arial Black'">Arial Black</a>
|
|
16
|
-
<a style="font-family: 'Comic Sans MS'">Comic Sans MS</a>
|
|
17
|
-
<a style="font-family: Courier">Courier</a>
|
|
18
|
-
<a style="font-family: System">System</a>
|
|
19
|
-
<a style="font-family: 'Times New Roman'">Times New Roman</a>
|
|
20
|
-
<a style="font-family: Verdana">Verdana</a>
|
|
21
|
-
</div>
|
|
22
|
-
</li>
|
|
23
|
-
<li class="dorpdown">
|
|
24
|
-
<i title="字号" class="text-icon">H</i>
|
|
25
|
-
<div class="fontsizeChoser" @click="onFontsizeChoserClk">
|
|
26
|
-
<a style="font-size: xx-small; ">极小</a>
|
|
27
|
-
<a style="font-size: x-small; ">特小</a>
|
|
28
|
-
<a style="font-size: small; ">小</a>
|
|
29
|
-
<a style="font-size: medium; ">中</a>
|
|
30
|
-
<a style="font-size: large; ">大</a>
|
|
31
|
-
<a style="font-size: x-large; ">特大</a>
|
|
32
|
-
<a style="font-size: xx-large; line-height: 140%">极大</a>
|
|
33
|
-
</div>
|
|
34
|
-
</li>
|
|
35
|
-
<li @click="onCmdClk"><i title="加粗" class="bold text-icon">B</i></li>
|
|
36
|
-
<li @click="onCmdClk"><i title="斜体" class="italic text-icon" style="font-style:italic">I</i></li>
|
|
37
|
-
<li @click="onCmdClk"><i title="下划线" class="underline text-icon" style="text-decoration: underline;">U</i></li>
|
|
38
|
-
<li @click="onCmdClk"><i title="左对齐" :class="'justifyleft '+ (isIonicons ? 'ivu-icon ivu-icon-bingo-menu-fold' : 'fontAwesome fa-align-left')"></i></li>
|
|
39
|
-
<li @click="onCmdClk"><i title="中间对齐" :class="'justifycenter '+ (isIonicons ? 'ivu-icon ivu-icon-md-menu' : 'fontAwesome fa-align-center')"></i></li>
|
|
40
|
-
<li @click="onCmdClk"><i title="右对齐" :class="'justifyright '+ (isIonicons ? 'ivu-icon ivu-icon-bingo-menu-unfold' : 'fontAwesome fa-align-right')"></i></li>
|
|
41
|
-
<li @click="onCmdClk"><i title="数字编号" :class="'insertorderedlist '+ (isIonicons ? 'ivu-icon ivu-icon-md-list' : 'fontAwesome fa-list-ol')"></i></li>
|
|
42
|
-
<li @click="onCmdClk"><i title="项目编号" :class="'insertunorderedlist '+ (isIonicons ? 'ivu-icon ivu-icon-ios-list' : 'fontAwesome fa-list-ul')"></i></li>
|
|
43
|
-
<li @click="onCmdClk"><i title="增加缩进" :class="'outdent '+ (isIonicons ? 'ivu-icon ivu-icon-ios-return-left' : 'fontAwesome fa-outdent')"></i></li>
|
|
44
|
-
<li @click="onCmdClk"><i title="减少缩进" :class="'indent '+ (isIonicons ? 'ivu-icon ivu-icon-ios-return-right' : 'fontAwesome fa-indent')"></i></li>
|
|
45
|
-
<li class="dorpdown">
|
|
46
|
-
<i title="字体颜色" :class="isIonicons ? 'ivu-icon ivu-icon-md-brush' : 'fontAwesome fa-paint-brush'"></i>
|
|
47
|
-
<div class="colorPicker" v-html="createColorPickerHTML()" @click="format('foreColor', $event.target.title)"></div>
|
|
48
|
-
</li>
|
|
49
|
-
<li class="dorpdown">
|
|
50
|
-
<i title="背景颜色" :class="isIonicons ? 'ivu-icon ivu-icon-ios-brush-outline' : 'fontAwesome fa-pencil'"></i>
|
|
51
|
-
<div class="colorPicker" v-html="createColorPickerHTML()" @click="format('backColor', $event.target.title)"></div>
|
|
52
|
-
</li>
|
|
53
|
-
<li @click="createLink"><i title="增加链接" :class="isIonicons ? 'ivu-icon ivu-icon-ios-link' : 'fontAwesome fa-link'"></i></li>
|
|
54
|
-
<li @click="insertImage"><i title="增加图片" :class="isIonicons ? 'ivu-icon ivu-icon-md-images' : 'fontAwesome fa-file-image-o'"></i></li>
|
|
55
|
-
<li @click="saveRemoteImage2Local"><i title="一键存图" :class="isIonicons ? 'ivu-icon ivu-icon-md-photos' : 'fontAwesome fa-hdd-o'"></i></li>
|
|
56
|
-
<li @click="cleanHTML"><i title="清理 HTML" :class="isIonicons ? 'ivu-icon ivu-icon-md-done-all' : 'fontAwesome fa-eraser'"></i></li>
|
|
57
|
-
<li @click="isShowCode = !isShowCode"><i title="切换到代码" :class="(isIonicons ? 'ivu-icon ivu-icon-md-code' : 'fontAwesome fa-code')+ ' switchMode'"></i></li>
|
|
58
|
-
</ul>
|
|
59
|
-
|
|
60
|
-
<div class="editorBody">
|
|
61
|
-
<iframe srcdoc="<html><body></body></html>"></iframe>
|
|
62
|
-
<textarea></textarea>
|
|
63
|
-
</div>
|
|
64
|
-
<!-- <aj-form-popup-upload ref="uploadLayer" :upload-url="uploadImageActionUrl"></aj-form-popup-upload> -->
|
|
65
|
-
</div>
|
|
66
|
-
</template>
|
|
67
|
-
|
|
68
|
-
<script lang="ts" src="./HtmlEditor.ts"></script>
|
|
69
|
-
|
|
1
|
+
<template>
|
|
2
|
+
<div class="aj-form-html-editor">
|
|
3
|
+
<ul class="toolbar">
|
|
4
|
+
<li class="dorpdown">
|
|
5
|
+
<i title="字体" class="text-icon">A</i>
|
|
6
|
+
<div class="fontfamilyChoser" @click="onFontfamilyChoserClk">
|
|
7
|
+
<a style="font-family: '宋体'">宋体</a>
|
|
8
|
+
<a style="font-family: '黑体'">黑体</a>
|
|
9
|
+
<a style="font-family: '楷体'">楷体</a>
|
|
10
|
+
<a style="font-family: '隶书'">隶书</a>
|
|
11
|
+
<a style="font-family: '幼圆'">幼圆</a>
|
|
12
|
+
<a style="font-family: 'Microsoft YaHei'">Microsoft YaHei</a>
|
|
13
|
+
<a style="font-family: Arial">Arial</a>
|
|
14
|
+
<a style="font-family: 'Arial Narrow'">Arial Narrow</a>
|
|
15
|
+
<a style="font-family: 'Arial Black'">Arial Black</a>
|
|
16
|
+
<a style="font-family: 'Comic Sans MS'">Comic Sans MS</a>
|
|
17
|
+
<a style="font-family: Courier">Courier</a>
|
|
18
|
+
<a style="font-family: System">System</a>
|
|
19
|
+
<a style="font-family: 'Times New Roman'">Times New Roman</a>
|
|
20
|
+
<a style="font-family: Verdana">Verdana</a>
|
|
21
|
+
</div>
|
|
22
|
+
</li>
|
|
23
|
+
<li class="dorpdown">
|
|
24
|
+
<i title="字号" class="text-icon">H</i>
|
|
25
|
+
<div class="fontsizeChoser" @click="onFontsizeChoserClk">
|
|
26
|
+
<a style="font-size: xx-small; ">极小</a>
|
|
27
|
+
<a style="font-size: x-small; ">特小</a>
|
|
28
|
+
<a style="font-size: small; ">小</a>
|
|
29
|
+
<a style="font-size: medium; ">中</a>
|
|
30
|
+
<a style="font-size: large; ">大</a>
|
|
31
|
+
<a style="font-size: x-large; ">特大</a>
|
|
32
|
+
<a style="font-size: xx-large; line-height: 140%">极大</a>
|
|
33
|
+
</div>
|
|
34
|
+
</li>
|
|
35
|
+
<li @click="onCmdClk"><i title="加粗" class="bold text-icon">B</i></li>
|
|
36
|
+
<li @click="onCmdClk"><i title="斜体" class="italic text-icon" style="font-style:italic">I</i></li>
|
|
37
|
+
<li @click="onCmdClk"><i title="下划线" class="underline text-icon" style="text-decoration: underline;">U</i></li>
|
|
38
|
+
<li @click="onCmdClk"><i title="左对齐" :class="'justifyleft '+ (isIonicons ? 'ivu-icon ivu-icon-bingo-menu-fold' : 'fontAwesome fa-align-left')"></i></li>
|
|
39
|
+
<li @click="onCmdClk"><i title="中间对齐" :class="'justifycenter '+ (isIonicons ? 'ivu-icon ivu-icon-md-menu' : 'fontAwesome fa-align-center')"></i></li>
|
|
40
|
+
<li @click="onCmdClk"><i title="右对齐" :class="'justifyright '+ (isIonicons ? 'ivu-icon ivu-icon-bingo-menu-unfold' : 'fontAwesome fa-align-right')"></i></li>
|
|
41
|
+
<li @click="onCmdClk"><i title="数字编号" :class="'insertorderedlist '+ (isIonicons ? 'ivu-icon ivu-icon-md-list' : 'fontAwesome fa-list-ol')"></i></li>
|
|
42
|
+
<li @click="onCmdClk"><i title="项目编号" :class="'insertunorderedlist '+ (isIonicons ? 'ivu-icon ivu-icon-ios-list' : 'fontAwesome fa-list-ul')"></i></li>
|
|
43
|
+
<li @click="onCmdClk"><i title="增加缩进" :class="'outdent '+ (isIonicons ? 'ivu-icon ivu-icon-ios-return-left' : 'fontAwesome fa-outdent')"></i></li>
|
|
44
|
+
<li @click="onCmdClk"><i title="减少缩进" :class="'indent '+ (isIonicons ? 'ivu-icon ivu-icon-ios-return-right' : 'fontAwesome fa-indent')"></i></li>
|
|
45
|
+
<li class="dorpdown">
|
|
46
|
+
<i title="字体颜色" :class="isIonicons ? 'ivu-icon ivu-icon-md-brush' : 'fontAwesome fa-paint-brush'"></i>
|
|
47
|
+
<div class="colorPicker" v-html="createColorPickerHTML()" @click="format('foreColor', $event.target.title)"></div>
|
|
48
|
+
</li>
|
|
49
|
+
<li class="dorpdown">
|
|
50
|
+
<i title="背景颜色" :class="isIonicons ? 'ivu-icon ivu-icon-ios-brush-outline' : 'fontAwesome fa-pencil'"></i>
|
|
51
|
+
<div class="colorPicker" v-html="createColorPickerHTML()" @click="format('backColor', $event.target.title)"></div>
|
|
52
|
+
</li>
|
|
53
|
+
<li @click="createLink"><i title="增加链接" :class="isIonicons ? 'ivu-icon ivu-icon-ios-link' : 'fontAwesome fa-link'"></i></li>
|
|
54
|
+
<li @click="insertImage"><i title="增加图片" :class="isIonicons ? 'ivu-icon ivu-icon-md-images' : 'fontAwesome fa-file-image-o'"></i></li>
|
|
55
|
+
<li @click="saveRemoteImage2Local"><i title="一键存图" :class="isIonicons ? 'ivu-icon ivu-icon-md-photos' : 'fontAwesome fa-hdd-o'"></i></li>
|
|
56
|
+
<li @click="cleanHTML"><i title="清理 HTML" :class="isIonicons ? 'ivu-icon ivu-icon-md-done-all' : 'fontAwesome fa-eraser'"></i></li>
|
|
57
|
+
<li @click="isShowCode = !isShowCode"><i title="切换到代码" :class="(isIonicons ? 'ivu-icon ivu-icon-md-code' : 'fontAwesome fa-code')+ ' switchMode'"></i></li>
|
|
58
|
+
</ul>
|
|
59
|
+
|
|
60
|
+
<div class="editorBody">
|
|
61
|
+
<iframe srcdoc="<html><body></body></html>"></iframe>
|
|
62
|
+
<textarea></textarea>
|
|
63
|
+
</div>
|
|
64
|
+
<!-- <aj-form-popup-upload ref="uploadLayer" :upload-url="uploadImageActionUrl"></aj-form-popup-upload> -->
|
|
65
|
+
</div>
|
|
66
|
+
</template>
|
|
67
|
+
|
|
68
|
+
<script lang="ts" src="./HtmlEditor.ts"></script>
|
|
69
|
+
|
|
70
70
|
<style lang="less" src="./HtmlEditor.less"></style>
|
|
@@ -1,103 +1,103 @@
|
|
|
1
|
-
// https://github.com/jitbit/HtmlSanitizer/blob/master/HtmlSanitizer.js
|
|
2
|
-
// @ts-ignore
|
|
3
|
-
HtmlSanitizer = new (function foo() {
|
|
4
|
-
var tagWhitelist_ = {
|
|
5
|
-
'A': true, 'ABBR': true, 'B': true, 'BLOCKQUOTE': true, 'BODY': true, 'BR': true, 'CENTER': true, 'CODE': true, 'DIV': true, 'EM': true, 'FONT': true,
|
|
6
|
-
'H1': true, 'H2': true, 'H3': true, 'H4': true, 'H5': true, 'H6': true, 'HR': true, 'I': true, 'IMG': true, 'LABEL': true, 'LI': true, 'OL': true, 'P': true, 'PRE': true,
|
|
7
|
-
'SMALL': true, 'SOURCE': true, 'SPAN': true, 'STRONG': true, 'TABLE': true, 'TBODY': true, 'TR': true, 'TD': true, 'TH': true, 'THEAD': true, 'UL': true, 'U': true, 'VIDEO': true
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
var contentTagWhiteList_ = { 'FORM': true }; //tags that will be converted to DIVs
|
|
11
|
-
var attributeWhitelist_ = { 'align': true, 'color': true, 'controls': true, 'height': true, 'href': true, 'src': true, 'style': false, 'target': true, 'title': true, 'type': true, 'width': true };
|
|
12
|
-
var cssWhitelist_ = { 'color': true, 'background-color': true, 'font-size': true, 'text-align': true, 'text-decoration': true, 'font-weight': true };
|
|
13
|
-
var schemaWhiteList_ = ['http:', 'https:', 'data:', 'm-files:', 'file:', 'ftp:']; //which "protocols" are allowed in "href", "src" etc
|
|
14
|
-
var uriAttributes_ = { 'href': true, 'action': true };
|
|
15
|
-
// @ts-ignore
|
|
16
|
-
this.SanitizeHtml = function (input) {
|
|
17
|
-
input = input.trim();
|
|
18
|
-
if (input == "") return ""; //to save performance and not create iframe
|
|
19
|
-
|
|
20
|
-
//firefox "bogus node" workaround
|
|
21
|
-
if (input == "<br>") return "";
|
|
22
|
-
|
|
23
|
-
var iframe = document.createElement('iframe');
|
|
24
|
-
if (iframe['sandbox'] === undefined) {
|
|
25
|
-
alert('Your browser does not support sandboxed iframes. Please upgrade to a modern browser.');
|
|
26
|
-
return '';
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
iframe['sandbox'] = 'allow-same-origin';
|
|
30
|
-
iframe.style.display = 'none';
|
|
31
|
-
document.body.appendChild(iframe); // necessary so the iframe contains a document
|
|
32
|
-
|
|
33
|
-
var iframedoc = iframe.contentDocument || iframe.contentWindow.document;
|
|
34
|
-
if (iframedoc.body == null) iframedoc.write("<body></body>"); // null in IE
|
|
35
|
-
iframedoc.body.innerHTML = input;
|
|
36
|
-
|
|
37
|
-
function makeSanitizedCopy(node) {
|
|
38
|
-
if (node.nodeType == Node.TEXT_NODE) {
|
|
39
|
-
var newNode = node.cloneNode(true);
|
|
40
|
-
} else if (node.nodeType == Node.ELEMENT_NODE && (tagWhitelist_[node.tagName] || contentTagWhiteList_[node.tagName])) {
|
|
41
|
-
|
|
42
|
-
//remove useless empty spans (lots of those when pasting from MS Outlook)
|
|
43
|
-
if ((node.tagName == "SPAN" || node.tagName == "B" || node.tagName == "I" || node.tagName == "U")
|
|
44
|
-
&& node.innerHTML.trim() == "") {
|
|
45
|
-
return document.createDocumentFragment();
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (contentTagWhiteList_[node.tagName])
|
|
49
|
-
newNode = iframedoc.createElement('DIV'); //convert to DIV
|
|
50
|
-
else
|
|
51
|
-
newNode = iframedoc.createElement(node.tagName);
|
|
52
|
-
|
|
53
|
-
for (var i = 0; i < node.attributes.length; i++) {
|
|
54
|
-
var attr = node.attributes[i];
|
|
55
|
-
if (attributeWhitelist_[attr.name]) {
|
|
56
|
-
if (attr.name == "style") {
|
|
57
|
-
for (s = 0; s < node.style.length; s++) {
|
|
58
|
-
var styleName = node.style[s];
|
|
59
|
-
if (cssWhitelist_[styleName])
|
|
60
|
-
newNode.style.setProperty(styleName, node.style.getPropertyValue(styleName));
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
else {
|
|
64
|
-
if (uriAttributes_[attr.name]) { //if this is a "uri" attribute, that can have "javascript:" or something
|
|
65
|
-
if (attr.value.indexOf(":") > -1 && !startsWithAny(attr.value, schemaWhiteList_))
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
newNode.setAttribute(attr.name, attr.value);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
for (i = 0; i < node.childNodes.length; i++) {
|
|
73
|
-
var subCopy = makeSanitizedCopy(node.childNodes[i]);
|
|
74
|
-
newNode.appendChild(subCopy, false);
|
|
75
|
-
}
|
|
76
|
-
} else {
|
|
77
|
-
newNode = document.createDocumentFragment();
|
|
78
|
-
}
|
|
79
|
-
return newNode;
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
var resultElement = makeSanitizedCopy(iframedoc.body);
|
|
83
|
-
document.body.removeChild(iframe);
|
|
84
|
-
return resultElement.innerHTML
|
|
85
|
-
.replace(/<br[^>]*>(\S)/g, "<br>\n$1")
|
|
86
|
-
.replace(/div><div/g, "div>\n<div"); //replace is just for cleaner code
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function startsWithAny(str, substrings) {
|
|
90
|
-
for (var i = 0; i < substrings.length; i++) {
|
|
91
|
-
if (str.indexOf(substrings[i]) == 0) {
|
|
92
|
-
return true;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return false;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
this.AllowedTags = tagWhitelist_;
|
|
100
|
-
this.AllowedAttributes = attributeWhitelist_;
|
|
101
|
-
this.AllowedCssStyles = cssWhitelist_;
|
|
102
|
-
this.AllowedSchemas = schemaWhiteList_;
|
|
1
|
+
// https://github.com/jitbit/HtmlSanitizer/blob/master/HtmlSanitizer.js
|
|
2
|
+
// @ts-ignore
|
|
3
|
+
HtmlSanitizer = new (function foo() {
|
|
4
|
+
var tagWhitelist_ = {
|
|
5
|
+
'A': true, 'ABBR': true, 'B': true, 'BLOCKQUOTE': true, 'BODY': true, 'BR': true, 'CENTER': true, 'CODE': true, 'DIV': true, 'EM': true, 'FONT': true,
|
|
6
|
+
'H1': true, 'H2': true, 'H3': true, 'H4': true, 'H5': true, 'H6': true, 'HR': true, 'I': true, 'IMG': true, 'LABEL': true, 'LI': true, 'OL': true, 'P': true, 'PRE': true,
|
|
7
|
+
'SMALL': true, 'SOURCE': true, 'SPAN': true, 'STRONG': true, 'TABLE': true, 'TBODY': true, 'TR': true, 'TD': true, 'TH': true, 'THEAD': true, 'UL': true, 'U': true, 'VIDEO': true
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
var contentTagWhiteList_ = { 'FORM': true }; //tags that will be converted to DIVs
|
|
11
|
+
var attributeWhitelist_ = { 'align': true, 'color': true, 'controls': true, 'height': true, 'href': true, 'src': true, 'style': false, 'target': true, 'title': true, 'type': true, 'width': true };
|
|
12
|
+
var cssWhitelist_ = { 'color': true, 'background-color': true, 'font-size': true, 'text-align': true, 'text-decoration': true, 'font-weight': true };
|
|
13
|
+
var schemaWhiteList_ = ['http:', 'https:', 'data:', 'm-files:', 'file:', 'ftp:']; //which "protocols" are allowed in "href", "src" etc
|
|
14
|
+
var uriAttributes_ = { 'href': true, 'action': true };
|
|
15
|
+
// @ts-ignore
|
|
16
|
+
this.SanitizeHtml = function (input) {
|
|
17
|
+
input = input.trim();
|
|
18
|
+
if (input == "") return ""; //to save performance and not create iframe
|
|
19
|
+
|
|
20
|
+
//firefox "bogus node" workaround
|
|
21
|
+
if (input == "<br>") return "";
|
|
22
|
+
|
|
23
|
+
var iframe = document.createElement('iframe');
|
|
24
|
+
if (iframe['sandbox'] === undefined) {
|
|
25
|
+
alert('Your browser does not support sandboxed iframes. Please upgrade to a modern browser.');
|
|
26
|
+
return '';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
iframe['sandbox'] = 'allow-same-origin';
|
|
30
|
+
iframe.style.display = 'none';
|
|
31
|
+
document.body.appendChild(iframe); // necessary so the iframe contains a document
|
|
32
|
+
|
|
33
|
+
var iframedoc = iframe.contentDocument || iframe.contentWindow.document;
|
|
34
|
+
if (iframedoc.body == null) iframedoc.write("<body></body>"); // null in IE
|
|
35
|
+
iframedoc.body.innerHTML = input;
|
|
36
|
+
|
|
37
|
+
function makeSanitizedCopy(node) {
|
|
38
|
+
if (node.nodeType == Node.TEXT_NODE) {
|
|
39
|
+
var newNode = node.cloneNode(true);
|
|
40
|
+
} else if (node.nodeType == Node.ELEMENT_NODE && (tagWhitelist_[node.tagName] || contentTagWhiteList_[node.tagName])) {
|
|
41
|
+
|
|
42
|
+
//remove useless empty spans (lots of those when pasting from MS Outlook)
|
|
43
|
+
if ((node.tagName == "SPAN" || node.tagName == "B" || node.tagName == "I" || node.tagName == "U")
|
|
44
|
+
&& node.innerHTML.trim() == "") {
|
|
45
|
+
return document.createDocumentFragment();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (contentTagWhiteList_[node.tagName])
|
|
49
|
+
newNode = iframedoc.createElement('DIV'); //convert to DIV
|
|
50
|
+
else
|
|
51
|
+
newNode = iframedoc.createElement(node.tagName);
|
|
52
|
+
|
|
53
|
+
for (var i = 0; i < node.attributes.length; i++) {
|
|
54
|
+
var attr = node.attributes[i];
|
|
55
|
+
if (attributeWhitelist_[attr.name]) {
|
|
56
|
+
if (attr.name == "style") {
|
|
57
|
+
for (s = 0; s < node.style.length; s++) {
|
|
58
|
+
var styleName = node.style[s];
|
|
59
|
+
if (cssWhitelist_[styleName])
|
|
60
|
+
newNode.style.setProperty(styleName, node.style.getPropertyValue(styleName));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
if (uriAttributes_[attr.name]) { //if this is a "uri" attribute, that can have "javascript:" or something
|
|
65
|
+
if (attr.value.indexOf(":") > -1 && !startsWithAny(attr.value, schemaWhiteList_))
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
newNode.setAttribute(attr.name, attr.value);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
for (i = 0; i < node.childNodes.length; i++) {
|
|
73
|
+
var subCopy = makeSanitizedCopy(node.childNodes[i]);
|
|
74
|
+
newNode.appendChild(subCopy, false);
|
|
75
|
+
}
|
|
76
|
+
} else {
|
|
77
|
+
newNode = document.createDocumentFragment();
|
|
78
|
+
}
|
|
79
|
+
return newNode;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
var resultElement = makeSanitizedCopy(iframedoc.body);
|
|
83
|
+
document.body.removeChild(iframe);
|
|
84
|
+
return resultElement.innerHTML
|
|
85
|
+
.replace(/<br[^>]*>(\S)/g, "<br>\n$1")
|
|
86
|
+
.replace(/div><div/g, "div>\n<div"); //replace is just for cleaner code
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function startsWithAny(str, substrings) {
|
|
90
|
+
for (var i = 0; i < substrings.length; i++) {
|
|
91
|
+
if (str.indexOf(substrings[i]) == 0) {
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
this.AllowedTags = tagWhitelist_;
|
|
100
|
+
this.AllowedAttributes = attributeWhitelist_;
|
|
101
|
+
this.AllowedCssStyles = cssWhitelist_;
|
|
102
|
+
this.AllowedSchemas = schemaWhiteList_;
|
|
103
103
|
});
|
|
@@ -1,99 +1,105 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<a class="aj-img-thumb" :href="imgUrl" v-if="imgUrl" target="_blank">
|
|
3
|
-
<img :src="imgUrl" @mouseenter="current = imgUrl" @mouseleave="current = null" />
|
|
4
|
-
</a>
|
|
5
|
-
</template>
|
|
6
|
-
|
|
7
|
-
<script>
|
|
8
|
-
/**
|
|
9
|
-
* 悬浮显示大图
|
|
10
|
-
*/
|
|
11
|
-
export default {
|
|
12
|
-
props: {
|
|
13
|
-
imgUrl: { type: String, required: true },// 图片地址
|
|
14
|
-
},
|
|
15
|
-
|
|
16
|
-
data() {
|
|
17
|
-
return { current: '' }
|
|
18
|
-
},
|
|
19
|
-
watch: {
|
|
20
|
-
current(v) {
|
|
21
|
-
let el = document.querySelector("body > div.aj-image-large-view");
|
|
22
|
-
|
|
23
|
-
if (v) {
|
|
24
|
-
el.querySelector('img').src = v;
|
|
25
|
-
setTimeout(() => el.style.display = 'block', 700);
|
|
26
|
-
} else
|
|
27
|
-
el.style.display = 'none';
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
mounted() {
|
|
31
|
-
// 初始化
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
div
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* @
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
.aj-
|
|
91
|
-
|
|
92
|
-
max-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
1
|
+
<template>
|
|
2
|
+
<a class="aj-img-thumb" :href="imgUrl" v-if="imgUrl" target="_blank">
|
|
3
|
+
<img :src="imgUrl" @mouseenter="current = imgUrl" @mouseleave="current = null" />
|
|
4
|
+
</a>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script>
|
|
8
|
+
/**
|
|
9
|
+
* 悬浮显示大图
|
|
10
|
+
*/
|
|
11
|
+
export default {
|
|
12
|
+
props: {
|
|
13
|
+
imgUrl: { type: String, required: true },// 图片地址
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
data() {
|
|
17
|
+
return { current: '' }
|
|
18
|
+
},
|
|
19
|
+
watch: {
|
|
20
|
+
current(v) {
|
|
21
|
+
let el = document.querySelector("body > div.aj-image-large-view");
|
|
22
|
+
|
|
23
|
+
if (v) {
|
|
24
|
+
el.querySelector('img').src = v;
|
|
25
|
+
setTimeout(() => el.style.display = 'block', 700);
|
|
26
|
+
} else
|
|
27
|
+
el.style.display = 'none';
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
mounted() {
|
|
31
|
+
// 初始化
|
|
32
|
+
let div = document.querySelector("body > div.aj-image-large-view");
|
|
33
|
+
|
|
34
|
+
if (!div) {
|
|
35
|
+
div = document.createElement("div");
|
|
36
|
+
div.className = "aj-image-large-view";
|
|
37
|
+
div.innerHTML = "<img />";
|
|
38
|
+
|
|
39
|
+
document.body.appendChild(div);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
this.$el.addEventListener("mousemove", throttle(e => {
|
|
43
|
+
if (this.imgUrl) {
|
|
44
|
+
let w = 0, imgWidth = div.querySelector("img").clientWidth;
|
|
45
|
+
|
|
46
|
+
if (imgWidth > e.pageX)
|
|
47
|
+
w = imgWidth;
|
|
48
|
+
|
|
49
|
+
div.style.top = e.pageY + 20 + "px";
|
|
50
|
+
div.style.left = e.pageX - div.clientWidth + w + "px";
|
|
51
|
+
}
|
|
52
|
+
}, 50, 5000), false);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 函数节流
|
|
58
|
+
*
|
|
59
|
+
* @author https://www.cnblogs.com/moqiutao/p/6875955.html
|
|
60
|
+
* @param fn
|
|
61
|
+
* @param delay
|
|
62
|
+
* @param mustRunDelay
|
|
63
|
+
*/
|
|
64
|
+
function throttle(fn, delay, mustRunDelay) {
|
|
65
|
+
var timer, t_start;
|
|
66
|
+
return function () {
|
|
67
|
+
var _this = this;
|
|
68
|
+
var t_curr = +new Date();
|
|
69
|
+
window.clearTimeout(timer);
|
|
70
|
+
|
|
71
|
+
if (!t_start)
|
|
72
|
+
t_start = t_curr;
|
|
73
|
+
|
|
74
|
+
if (t_curr - t_start >= mustRunDelay) {
|
|
75
|
+
// @ts-ignore
|
|
76
|
+
fn.apply(this, arguments);
|
|
77
|
+
t_start = t_curr;
|
|
78
|
+
} else {
|
|
79
|
+
var args = arguments;
|
|
80
|
+
// @ts-ignore
|
|
81
|
+
timer = window.setTimeout(function () {
|
|
82
|
+
return fn.apply(_this, args);
|
|
83
|
+
}, delay);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
</script>
|
|
88
|
+
|
|
89
|
+
<style lang="less">
|
|
90
|
+
.aj-img-thumb img {
|
|
91
|
+
max-width: 50px;
|
|
92
|
+
max-height: 60px;
|
|
93
|
+
vertical-align: middle;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.aj-image-large-view {
|
|
97
|
+
position: fixed;
|
|
98
|
+
max-width: 400px;
|
|
99
|
+
transition: top ease-in 200ms, left ease-in 200ms;
|
|
100
|
+
|
|
101
|
+
img {
|
|
102
|
+
width: 100%;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
99
105
|
</style>
|