PageRenderTime 40ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 1ms

/string-avalon-src/filter.js

https://gitlab.com/kidaa/node-avalon
JavaScript | 348 lines | 287 code | 9 blank | 52 comment | 34 complexity | 98462b6d13be45706aa7b9505babf0fe MD5 | raw file
  1. /*********************************************************************
  2. * 自带过滤器 *
  3. **********************************************************************/
  4. var rscripts = /<script[^>]*>([\S\s]*?)<\/script\s*>/gim
  5. var ron = /\s+(on[^=\s]+)(?:=("[^"]*"|'[^']*'|[^\s>]+))?/g
  6. var ropen = /<\w+\b(?:(["'])[^"]*?(\1)|[^>])*>/ig
  7. var rsanitize = {
  8. a: /\b(href)\=("javascript[^"]*"|'javascript[^']*')/ig,
  9. img: /\b(src)\=("javascript[^"]*"|'javascript[^']*')/ig,
  10. form: /\b(action)\=("javascript[^"]*"|'javascript[^']*')/ig
  11. }
  12. var rsurrogate = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g
  13. var rnoalphanumeric = /([^\#-~| |!])/g;
  14. function numberFormat(number, decimals, point, thousands) {
  15. //form http://phpjs.org/functions/number_format/
  16. //number 必需,要格式化的数字
  17. //decimals 可选,规定多少个小数位。
  18. //point 可选,规定用作小数点的字符串(默认为 . )。
  19. //thousands 可选,规定用作千位分隔符的字符串(默认为 , ),如果设置了该参数,那么所有其他参数都是必需的。
  20. number = (number + '')
  21. .replace(/[^0-9+\-Ee.]/g, '')
  22. var n = !isFinite(+number) ? 0 : +number,
  23. prec = !isFinite(+decimals) ? 3 : Math.abs(decimals),
  24. sep = thousands || ",",
  25. dec = point || ".",
  26. s = '',
  27. toFixedFix = function(n, prec) {
  28. var k = Math.pow(10, prec)
  29. return '' + (Math.round(n * k) / k)
  30. .toFixed(prec)
  31. }
  32. // Fix for IE parseFloat(0.55).toFixed(0) = 0;
  33. s = (prec ? toFixedFix(n, prec) : '' + Math.round(n))
  34. .split('.')
  35. if (s[0].length > 3) {
  36. s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep)
  37. }
  38. if ((s[1] || '')
  39. .length < prec) {
  40. s[1] = s[1] || ''
  41. s[1] += new Array(prec - s[1].length + 1)
  42. .join('0')
  43. }
  44. return s.join(dec)
  45. }
  46. var filters = avalon.filters = {
  47. uppercase: function(str) {
  48. return str.toUpperCase()
  49. },
  50. lowercase: function(str) {
  51. return str.toLowerCase()
  52. },
  53. truncate: function(str, length, truncation) {
  54. //length,新字符串长度,truncation,新字符串的结尾的字段,返回新字符串
  55. length = length || 30
  56. truncation = truncation === void(0) ? "..." : truncation
  57. return str.length > length ? str.slice(0, length - truncation.length) + truncation : String(str)
  58. },
  59. $filter: function(val) {
  60. for (var i = 1, n = arguments.length; i < n; i++) {
  61. var array = arguments[i]
  62. var fn = avalon.filters[array.shift()]
  63. if (typeof fn === "function") {
  64. var arr = [val].concat(array)
  65. val = fn.apply(null, arr)
  66. }
  67. }
  68. return val
  69. },
  70. camelize: camelize,
  71. //https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
  72. // <a href="javasc&NewLine;ript&colon;alert('XSS')">chrome</a>
  73. // <a href="data:text/html;base64, PGltZyBzcmM9eCBvbmVycm9yPWFsZXJ0KDEpPg==">chrome</a>
  74. // <a href="jav ascript:alert('XSS');">IE67chrome</a>
  75. // <a href="jav&#x09;ascript:alert('XSS');">IE67chrome</a>
  76. // <a href="jav&#x0A;ascript:alert('XSS');">IE67chrome</a>
  77. sanitize: function(str) {
  78. return str.replace(rscripts, "").replace(ropen, function(a, b) {
  79. var match = a.toLowerCase().match(/<(\w+)\s/)
  80. if (match) { //处理a标签的href属性,img标签的src属性,form标签的action属性
  81. var reg = rsanitize[match[1]]
  82. if (reg) {
  83. a = a.replace(reg, function(s, name, value) {
  84. var quote = value.charAt(0)
  85. return name + "=" + quote + "javascript:void(0)" + quote// jshint ignore:line
  86. })
  87. }
  88. }
  89. return a.replace(ron, " ").replace(/\s+/g, " ") //移除onXXX事件
  90. })
  91. },
  92. escape: function(str) {
  93. //将字符串经过 str 转义得到适合在页面中显示的内容, 例如替换 < 为 &lt
  94. return String(str).
  95. replace(/&/g, '&amp;').
  96. replace(rsurrogate, function(value) {
  97. var hi = value.charCodeAt(0)
  98. var low = value.charCodeAt(1)
  99. return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';'
  100. }).
  101. replace(rnoalphanumeric, function(value) {
  102. return '&#' + value.charCodeAt(0) + ';'
  103. }).
  104. replace(/</g, '&lt;').
  105. replace(/>/g, '&gt;')
  106. },
  107. currency: function(amount, symbol, fractionSize) {
  108. return (symbol || "\uFFE5") + numberFormat(amount, isFinite(fractionSize) ? fractionSize : 2)
  109. },
  110. number: numberFormat
  111. }
  112. /*
  113. 'yyyy': 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
  114. 'yy': 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
  115. 'y': 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
  116. 'MMMM': Month in year (January-December)
  117. 'MMM': Month in year (Jan-Dec)
  118. 'MM': Month in year, padded (01-12)
  119. 'M': Month in year (1-12)
  120. 'dd': Day in month, padded (01-31)
  121. 'd': Day in month (1-31)
  122. 'EEEE': Day in Week,(Sunday-Saturday)
  123. 'EEE': Day in Week, (Sun-Sat)
  124. 'HH': Hour in day, padded (00-23)
  125. 'H': Hour in day (0-23)
  126. 'hh': Hour in am/pm, padded (01-12)
  127. 'h': Hour in am/pm, (1-12)
  128. 'mm': Minute in hour, padded (00-59)
  129. 'm': Minute in hour (0-59)
  130. 'ss': Second in minute, padded (00-59)
  131. 's': Second in minute (0-59)
  132. 'a': am/pm marker
  133. 'Z': 4 digit (+sign) representation of the timezone offset (-1200-+1200)
  134. format string can also be one of the following predefined localizable formats:
  135. 'medium': equivalent to 'MMM d, y h:mm:ss a' for en_US locale (e.g. Sep 3, 2010 12:05:08 pm)
  136. 'short': equivalent to 'M/d/yy h:mm a' for en_US locale (e.g. 9/3/10 12:05 pm)
  137. 'fullDate': equivalent to 'EEEE, MMMM d,y' for en_US locale (e.g. Friday, September 3, 2010)
  138. 'longDate': equivalent to 'MMMM d, y' for en_US locale (e.g. September 3, 2010
  139. 'mediumDate': equivalent to 'MMM d, y' for en_US locale (e.g. Sep 3, 2010)
  140. 'shortDate': equivalent to 'M/d/yy' for en_US locale (e.g. 9/3/10)
  141. 'mediumTime': equivalent to 'h:mm:ss a' for en_US locale (e.g. 12:05:08 pm)
  142. 'shortTime': equivalent to 'h:mm a' for en_US locale (e.g. 12:05 pm)
  143. */
  144. new function() {// jshint ignore:line
  145. function toInt(str) {
  146. return parseInt(str, 10) || 0
  147. }
  148. function padNumber(num, digits, trim) {
  149. var neg = ""
  150. if (num < 0) {
  151. neg = '-'
  152. num = -num
  153. }
  154. num = "" + num
  155. while (num.length < digits)
  156. num = "0" + num
  157. if (trim)
  158. num = num.substr(num.length - digits)
  159. return neg + num
  160. }
  161. function dateGetter(name, size, offset, trim) {
  162. return function(date) {
  163. var value = date["get" + name]()
  164. if (offset > 0 || value > -offset)
  165. value += offset
  166. if (value === 0 && offset === -12) {
  167. value = 12
  168. }
  169. return padNumber(value, size, trim)
  170. }
  171. }
  172. function dateStrGetter(name, shortForm) {
  173. return function(date, formats) {
  174. var value = date["get" + name]()
  175. var get = (shortForm ? ("SHORT" + name) : name).toUpperCase()
  176. return formats[get][value]
  177. }
  178. }
  179. function timeZoneGetter(date) {
  180. var zone = -1 * date.getTimezoneOffset()
  181. var paddedZone = (zone >= 0) ? "+" : ""
  182. paddedZone += padNumber(Math[zone > 0 ? "floor" : "ceil"](zone / 60), 2) + padNumber(Math.abs(zone % 60), 2)
  183. return paddedZone
  184. }
  185. //取得上午下午
  186. function ampmGetter(date, formats) {
  187. return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1]
  188. }
  189. var DATE_FORMATS = {
  190. yyyy: dateGetter("FullYear", 4),
  191. yy: dateGetter("FullYear", 2, 0, true),
  192. y: dateGetter("FullYear", 1),
  193. MMMM: dateStrGetter("Month"),
  194. MMM: dateStrGetter("Month", true),
  195. MM: dateGetter("Month", 2, 1),
  196. M: dateGetter("Month", 1, 1),
  197. dd: dateGetter("Date", 2),
  198. d: dateGetter("Date", 1),
  199. HH: dateGetter("Hours", 2),
  200. H: dateGetter("Hours", 1),
  201. hh: dateGetter("Hours", 2, -12),
  202. h: dateGetter("Hours", 1, -12),
  203. mm: dateGetter("Minutes", 2),
  204. m: dateGetter("Minutes", 1),
  205. ss: dateGetter("Seconds", 2),
  206. s: dateGetter("Seconds", 1),
  207. sss: dateGetter("Milliseconds", 3),
  208. EEEE: dateStrGetter("Day"),
  209. EEE: dateStrGetter("Day", true),
  210. a: ampmGetter,
  211. Z: timeZoneGetter
  212. }
  213. var rdateFormat = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/
  214. var raspnetjson = /^\/Date\((\d+)\)\/$/
  215. filters.date = function(date, format) {
  216. var locate = filters.date.locate,
  217. text = "",
  218. parts = [],
  219. fn, match
  220. format = format || "mediumDate"
  221. format = locate[format] || format
  222. if (typeof date === "string") {
  223. if (/^\d+$/.test(date)) {
  224. date = toInt(date)
  225. } else if (raspnetjson.test(date)) {
  226. date = +RegExp.$1
  227. } else {
  228. var trimDate = date.trim()
  229. var dateArray = [0, 0, 0, 0, 0, 0, 0]
  230. var oDate = new Date(0)
  231. //取得年月日
  232. trimDate = trimDate.replace(/^(\d+)\D(\d+)\D(\d+)/, function(_, a, b, c) {
  233. var array = c.length === 4 ? [c, a, b] : [a, b, c]
  234. dateArray[0] = toInt(array[0]) //年
  235. dateArray[1] = toInt(array[1]) - 1 //月
  236. dateArray[2] = toInt(array[2]) //日
  237. return ""
  238. })
  239. var dateSetter = oDate.setFullYear
  240. var timeSetter = oDate.setHours
  241. trimDate = trimDate.replace(/[T\s](\d+):(\d+):?(\d+)?\.?(\d)?/, function(_, a, b, c, d) {
  242. dateArray[3] = toInt(a) //小时
  243. dateArray[4] = toInt(b) //分钟
  244. dateArray[5] = toInt(c) //秒
  245. if (d) { //毫秒
  246. dateArray[6] = Math.round(parseFloat("0." + d) * 1000)
  247. }
  248. return ""
  249. })
  250. var tzHour = 0
  251. var tzMin = 0
  252. trimDate = trimDate.replace(/Z|([+-])(\d\d):?(\d\d)/, function(z, symbol, c, d) {
  253. dateSetter = oDate.setUTCFullYear
  254. timeSetter = oDate.setUTCHours
  255. if (symbol) {
  256. tzHour = toInt(symbol + c)
  257. tzMin = toInt(symbol + d)
  258. }
  259. return ""
  260. })
  261. dateArray[3] -= tzHour
  262. dateArray[4] -= tzMin
  263. dateSetter.apply(oDate, dateArray.slice(0, 3))
  264. timeSetter.apply(oDate, dateArray.slice(3))
  265. date = oDate
  266. }
  267. }
  268. if (typeof date === "number") {
  269. date = new Date(date)
  270. }
  271. if (avalon.type(date) !== "date") {
  272. return
  273. }
  274. while (format) {
  275. match = rdateFormat.exec(format)
  276. if (match) {
  277. parts = parts.concat(match.slice(1))
  278. format = parts.pop()
  279. } else {
  280. parts.push(format)
  281. format = null
  282. }
  283. }
  284. parts.forEach(function(value) {
  285. fn = DATE_FORMATS[value]
  286. text += fn ? fn(date, locate) : value.replace(/(^'|'$)/g, "").replace(/''/g, "'")
  287. })
  288. return text
  289. }
  290. var locate = {
  291. AMPMS: {
  292. 0: "上午",
  293. 1: "下午"
  294. },
  295. DAY: {
  296. 0: "星期日",
  297. 1: "星期一",
  298. 2: "星期二",
  299. 3: "星期三",
  300. 4: "星期四",
  301. 5: "星期五",
  302. 6: "星期六"
  303. },
  304. MONTH: {
  305. 0: "1月",
  306. 1: "2月",
  307. 2: "3月",
  308. 3: "4月",
  309. 4: "5月",
  310. 5: "6月",
  311. 6: "7月",
  312. 7: "8月",
  313. 8: "9月",
  314. 9: "10月",
  315. 10: "11月",
  316. 11: "12月"
  317. },
  318. SHORTDAY: {
  319. "0": "周日",
  320. "1": "周一",
  321. "2": "周二",
  322. "3": "周三",
  323. "4": "周四",
  324. "5": "周五",
  325. "6": "周六"
  326. },
  327. fullDate: "y年M月d日EEEE",
  328. longDate: "y年M月d日",
  329. medium: "yyyy-M-d H:mm:ss",
  330. mediumDate: "yyyy-M-d",
  331. mediumTime: "H:mm:ss",
  332. "short": "yy-M-d ah:mm",
  333. shortDate: "yy-M-d",
  334. shortTime: "ah:mm"
  335. }
  336. locate.SHORTMONTH = locate.MONTH
  337. filters.date.locate = locate
  338. }// jshint ignore:line