narro 5 years ago
parent
commit
18a031a996
11 changed files with 40 additions and 12 deletions
  1. 3
    0
      CHANGELOG.md
  2. 1
    1
      README.md
  3. 1
    1
      lib/Comment.js.map
  4. 2
    0
      lib/constant.js
  5. 1
    1
      lib/constant.js.map
  6. 13
    3
      lib/helper.js
  7. 1
    1
      lib/helper.js.map
  8. 1
    1
      lib/registerServiceWorker.js.map
  9. 1
    1
      package.json
  10. 2
    0
      src/constant.js
  11. 14
    3
      src/helper.js

+ 3
- 0
CHANGELOG.md View File

@@ -1,5 +1,8 @@
1 1
 # CHANGELOG
2 2
 
3
+## 0.5.11
4
+- [x] 增加链接解析功能
5
+
3 6
 ## 0.5.10
4 7
 - [x] 扩展表情包
5 8
 

+ 1
- 1
README.md View File

@@ -2,7 +2,7 @@
2 2
 
3 3
 通用评论系统及编辑器
4 4
 
5
-**`version 0.5.10`**
5
+**`version 0.5.11`**
6 6
 
7 7
 ```js
8 8
 import Comment, { Editor, RenderText } from 'comment';

+ 1
- 1
lib/Comment.js.map View File

@@ -1 +1 @@
1
-{"version":3,"sources":["../src/Comment.js"],"names":["Comment","CommentContext","React","createContext","Component","props","app"],"mappings":";;;;;;;;;QAKgBA,O,GAAAA,O;;AALhB;;;;;;AAEA,IAAMC,iBAAiBC,gBAAMC,aAAN,EAAvB;;AAEA;AACO,SAASH,OAAT,CAAiBI,SAAjB,EAA4B;AACjC;AACA,SAAO,UAASC,KAAT,EAAgB;AACrB;AACA;AACA,WACE;AAAC,oBAAD,CAAgB,QAAhB;AAAA;AACG;AAAA,eAAO,8BAAC,SAAD,eAAeA,KAAf,IAAsB,KAAKC,GAA3B,IAAP;AAAA;AADH,KADF;AAKD,GARD;AASD;;QAEQL,c,GAAAA,c;kBAEMD,O","file":"Comment.js","sourcesContent":["import React from \"react\";\r\n\r\nconst CommentContext = React.createContext();\r\n\r\n// This function takes a component...\r\nexport function Comment(Component) {\r\n  // ...and returns another component...\r\n  return function(props) {\r\n    // ... and renders the wrapped component with the context theme!\r\n    // Notice that we pass through any additional props as well\r\n    return (\r\n      <CommentContext.Consumer>\r\n        {app => <Component {...props} app={app} />}\r\n      </CommentContext.Consumer>\r\n    );\r\n  };\r\n}\r\n\r\nexport { CommentContext };\r\n\r\nexport default Comment;\r\n"]}
1
+{"version":3,"sources":["../src/Comment.js"],"names":["Comment","CommentContext","React","createContext","Component","props","app"],"mappings":";;;;;;;;;QAKgBA,O,GAAAA,O;;AALhB;;;;;;AAEA,IAAMC,iBAAiBC,gBAAMC,aAAN,EAAvB;;AAEA;AACO,SAASH,OAAT,CAAiBI,SAAjB,EAA4B;AACjC;AACA,SAAO,UAASC,KAAT,EAAgB;AACrB;AACA;AACA,WACE;AAAC,oBAAD,CAAgB,QAAhB;AAAA;AACG;AAAA,eAAO,8BAAC,SAAD,eAAeA,KAAf,IAAsB,KAAKC,GAA3B,IAAP;AAAA;AADH,KADF;AAKD,GARD;AASD;;QAEQL,c,GAAAA,c;kBAEMD,O","file":"Comment.js","sourcesContent":["import React from \"react\";\n\nconst CommentContext = React.createContext();\n\n// This function takes a component...\nexport function Comment(Component) {\n  // ...and returns another component...\n  return function(props) {\n    // ... and renders the wrapped component with the context theme!\n    // Notice that we pass through any additional props as well\n    return (\n      <CommentContext.Consumer>\n        {app => <Component {...props} app={app} />}\n      </CommentContext.Consumer>\n    );\n  };\n}\n\nexport { CommentContext };\n\nexport default Comment;\n"]}

+ 2
- 0
lib/constant.js View File

@@ -15,6 +15,8 @@ var OSS_LINK = exports.OSS_LINK = "//links-comment.oss-cn-beijing.aliyuncs.com";
15 15
 
16 16
 var MAX_UPLOAD_NUMBER = exports.MAX_UPLOAD_NUMBER = 4;
17 17
 
18
+var URL_REGEXP = exports.URL_REGEXP = /((http(s)?:)?\/\/)?(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/g;
19
+
18 20
 var REGEXP = exports.REGEXP = /\[[^[\]]+?\]/g;
19 21
 
20 22
 var AVATAR = exports.AVATAR = "";

+ 1
- 1
lib/constant.js.map View File

@@ -1 +1 @@
1
-{"version":3,"sources":["../src/constant.js"],"names":["ERROR_DEFAULT","LIMIT","OSS_ENDPOINT","OSS_BUCKET","DRIVER_LICENSE_PATH","OSS_LINK","MAX_UPLOAD_NUMBER","REGEXP","AVATAR","IMAGE_SPLIT"],"mappings":";;;;;AAAO,IAAMA,wCAAgB,MAAtB;;AAEA,IAAMC,wBAAQ,EAAd,C,CAAkB;;AAElB,IAAMC,sCAAe,6BAArB;AACA,IAAMC,kCAAa,eAAnB;AACA,IAAMC,oDAAsB,UAA5B;;AAEA,IAAMC,8BAAW,6CAAjB;;AAEA,IAAMC,gDAAoB,CAA1B;;AAEA,IAAMC,0BAAS,eAAf;;AAEA,IAAMC,0BAAS,EAAf;;AAEA,IAAMC,oCAAc,aAApB","file":"constant.js","sourcesContent":["export const ERROR_DEFAULT = \"出错了!\";\r\n\r\nexport const LIMIT = 10; // 默认 limit\r\n\r\nexport const OSS_ENDPOINT = \"oss-cn-beijing.aliyuncs.com\";\r\nexport const OSS_BUCKET = \"links-comment\";\r\nexport const DRIVER_LICENSE_PATH = \"/comment\";\r\n\r\nexport const OSS_LINK = \"//links-comment.oss-cn-beijing.aliyuncs.com\";\r\n\r\nexport const MAX_UPLOAD_NUMBER = 4;\r\n\r\nexport const REGEXP = /\\[[^[\\]]+?\\]/g;\r\n\r\nexport const AVATAR = \"\";\r\n\r\nexport const IMAGE_SPLIT = \"IMAGE_SPLIT\";\r\n"]}
1
+{"version":3,"sources":["../src/constant.js"],"names":["ERROR_DEFAULT","LIMIT","OSS_ENDPOINT","OSS_BUCKET","DRIVER_LICENSE_PATH","OSS_LINK","MAX_UPLOAD_NUMBER","URL_REGEXP","REGEXP","AVATAR","IMAGE_SPLIT"],"mappings":";;;;;AAAO,IAAMA,wCAAgB,MAAtB;;AAEA,IAAMC,wBAAQ,EAAd,C,CAAkB;;AAElB,IAAMC,sCAAe,6BAArB;AACA,IAAMC,kCAAa,eAAnB;AACA,IAAMC,oDAAsB,UAA5B;;AAEA,IAAMC,8BAAW,6CAAjB;;AAEA,IAAMC,gDAAoB,CAA1B;;AAEA,IAAMC,kCAAa,oGAAnB;;AAEA,IAAMC,0BAAS,eAAf;;AAEA,IAAMC,0BAAS,EAAf;;AAEA,IAAMC,oCAAc,aAApB","file":"constant.js","sourcesContent":["export const ERROR_DEFAULT = \"出错了!\";\r\n\r\nexport const LIMIT = 10; // 默认 limit\r\n\r\nexport const OSS_ENDPOINT = \"oss-cn-beijing.aliyuncs.com\";\r\nexport const OSS_BUCKET = \"links-comment\";\r\nexport const DRIVER_LICENSE_PATH = \"/comment\";\r\n\r\nexport const OSS_LINK = \"//links-comment.oss-cn-beijing.aliyuncs.com\";\r\n\r\nexport const MAX_UPLOAD_NUMBER = 4;\r\n\r\nexport const URL_REGEXP = /((http(s)?:)?\\/\\/)?(www\\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\\.[a-z]{2,6}\\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/g;\r\n\r\nexport const REGEXP = /\\[[^[\\]]+?\\]/g;\r\n\r\nexport const AVATAR = \"\";\r\n\r\nexport const IMAGE_SPLIT = \"IMAGE_SPLIT\";\r\n"]}

+ 13
- 3
lib/helper.js View File

@@ -24,7 +24,8 @@ function isFunction(functionToCheck) {
24 24
 }
25 25
 
26 26
 function isUrl(userInput) {
27
-  var regexp = /(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/g;
27
+  // 需完整匹配
28
+  var regexp = /^((http(s)?:)?\/\/.)?(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/g;
28 29
   var res = userInput.match(regexp);
29 30
   if (res === null) return false;else return true;
30 31
 }
@@ -65,8 +66,9 @@ function renderContent(content, onClick) {
65 66
     newContent.pop();
66 67
     newContent = newContent.join("");
67 68
   }
68
-
69
-  return htmlEncode(newContent).replace(_constant.REGEXP, function (a, b) {
69
+  // 不包含在标签内的链接
70
+  var innerUrl = /((http(s)?:)?\/\/)?(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)(?![^<>]*>|[^"]*?<\/a)/g;
71
+  var data = htmlEncode(newContent).replace(_constant.REGEXP, function (a, b) {
70 72
     var src = a.slice(1, -1);
71 73
 
72 74
     // 兼容旧的评
@@ -80,6 +82,14 @@ function renderContent(content, onClick) {
80 82
       return "<img src=\"" + _emoji.prefixUrl + emoji.value + "." + emoji.ext + "\" alt=\"" + emoji.title + "\" />";
81 83
     }
82 84
     return "[" + src + "]";
85
+  }).replace(innerUrl, function (a, b) {
86
+    var protocol = /^(https?:)?\/\//;
87
+    var hasProtocol = protocol.test(a);
88
+    var url = hasProtocol ? a : "//" + a;
89
+    // target="_blank" 存在安全性问题
90
+    // return `<a href="${url}" target="_blank" rel="noopener noreferrer" >${a}</a>`;
91
+    return "<a href=\"" + url + "\">" + a + "</a>";
83 92
   }).replace(/\n/g, "<br />");
93
+  return data;
84 94
 }
85 95
 //# sourceMappingURL=helper.js.map

+ 1
- 1
lib/helper.js.map
File diff suppressed because it is too large
View File


+ 1
- 1
lib/registerServiceWorker.js.map
File diff suppressed because it is too large
View File


+ 1
- 1
package.json View File

@@ -1,6 +1,6 @@
1 1
 {
2 2
   "name": "comment",
3
-  "version": "0.5.10",
3
+  "version": "0.5.11",
4 4
   "main": "lib/App.js",
5 5
   "description": "通用评论",
6 6
   "keywords": [

+ 2
- 0
src/constant.js View File

@@ -10,6 +10,8 @@ export const OSS_LINK = "//links-comment.oss-cn-beijing.aliyuncs.com";
10 10
 
11 11
 export const MAX_UPLOAD_NUMBER = 4;
12 12
 
13
+export const URL_REGEXP = /((http(s)?:)?\/\/)?(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/g;
14
+
13 15
 export const REGEXP = /\[[^[\]]+?\]/g;
14 16
 
15 17
 export const AVATAR = "";

+ 14
- 3
src/helper.js View File

@@ -10,7 +10,8 @@ export function isFunction(functionToCheck) {
10 10
 }
11 11
 
12 12
 export function isUrl(userInput) {
13
-  const regexp = /(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/g;
13
+  // 需完整匹配
14
+  const regexp = /^((http(s)?:)?\/\/.)?(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/g;
14 15
   var res = userInput.match(regexp);
15 16
   if (res === null) return false;
16 17
   else return true;
@@ -52,8 +53,9 @@ export function renderContent(content, onClick) {
52 53
     newContent.pop();
53 54
     newContent = newContent.join("");
54 55
   }
55
-
56
-  return htmlEncode(newContent)
56
+  // 不包含在标签内的链接
57
+  const innerUrl = /((http(s)?:)?\/\/)?(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)(?![^<>]*>|[^"]*?<\/a)/g;
58
+  const data = htmlEncode(newContent)
57 59
     .replace(REGEXP, function(a, b) {
58 60
       const src = a.slice(1, -1);
59 61
 
@@ -71,5 +73,14 @@ export function renderContent(content, onClick) {
71 73
       }
72 74
       return `[${src}]`;
73 75
     })
76
+    .replace(innerUrl, function(a, b) {
77
+      const protocol = /^(https?:)?\/\//;
78
+      const hasProtocol = protocol.test(a);
79
+      const url = hasProtocol ? a : `//${a}`;
80
+      // target="_blank" 存在安全性问题
81
+      // return `<a href="${url}" target="_blank" rel="noopener noreferrer" >${a}</a>`;
82
+      return `<a href="${url}">${a}</a>`;
83
+    })
74 84
     .replace(/\n/g, "<br />");
85
+  return data;
75 86
 }