@@ -0,0 +1,4 @@ |
||
1 |
+*/utils/wxParse/*.js |
|
2 |
+*/utils/barcode.js |
|
3 |
+gulpfile.js |
|
4 |
+*.wxs |
@@ -0,0 +1,31 @@ |
||
1 |
+module.exports = { |
|
2 |
+ parser: "babel-eslint", |
|
3 |
+ env: { |
|
4 |
+ browser: true, |
|
5 |
+ es6: true, |
|
6 |
+ }, |
|
7 |
+ extends: [ |
|
8 |
+ 'airbnb-base', 'prettier', 'plugin:prettier/recommended', |
|
9 |
+ ], |
|
10 |
+ plugins: ["prettier"], |
|
11 |
+ globals: { |
|
12 |
+ Atomics: 'readonly', |
|
13 |
+ SharedArrayBuffer: 'readonly', |
|
14 |
+ "wx": "readonly", |
|
15 |
+ "App": "readonly", |
|
16 |
+ "Page": "readonly", |
|
17 |
+ "Component": "readonly", |
|
18 |
+ "getApp": "readonly", |
|
19 |
+ "getCurrentPages": "readonly", |
|
20 |
+ "requirePlugin": "readonly" |
|
21 |
+ }, |
|
22 |
+ parserOptions: { |
|
23 |
+ ecmaVersion: 2018, |
|
24 |
+ sourceType: 'module', |
|
25 |
+ }, |
|
26 |
+ rules: { |
|
27 |
+ "prettier/prettier": "error", |
|
28 |
+ "camelcase": ["off", {"ignoreDestructuring": true}], |
|
29 |
+ "no-underscore-dangle": ["off", {"allowAfterThis": true}] |
|
30 |
+ }, |
|
31 |
+}; |
@@ -0,0 +1,2 @@ |
||
1 |
+app.json merge=ours |
|
2 |
+ |
@@ -0,0 +1,2 @@ |
||
1 |
+node_modules |
|
2 |
+package-lock.json |
@@ -0,0 +1,13 @@ |
||
1 |
+*swp |
|
2 |
+.idea |
|
3 |
+.DS_Store |
|
4 |
+package-lock.json |
|
5 |
+ |
|
6 |
+logs |
|
7 |
+*.log |
|
8 |
+npm-debug.log* |
|
9 |
+yarn-debug.log* |
|
10 |
+yarn-error.log* |
|
11 |
+node_modules |
|
12 |
+miniprogram/mock |
|
13 |
+miniprogram/node_modules |
@@ -0,0 +1,7 @@ |
||
1 |
+{ |
|
2 |
+ "eslintIntegration": true, |
|
3 |
+ "stylelintIntegration": true, |
|
4 |
+ "tabWidth": 2, |
|
5 |
+ "singleQuote": true, |
|
6 |
+ "semi": false |
|
7 |
+} |
@@ -0,0 +1 @@ |
||
1 |
+*.wxss |
@@ -0,0 +1,16 @@ |
||
1 |
+{ |
|
2 |
+ "plugins": ["stylelint-prettier"], |
|
3 |
+ "extends": ["stylelint-config-standard", "stylelint-config-recess-order"], |
|
4 |
+ "rules": { |
|
5 |
+ "prettier/prettier": true, |
|
6 |
+ "at-rule-no-unknown": [true, {"ignoreAtRules" :[ |
|
7 |
+ "mixin", "extend", "content" |
|
8 |
+ ]}], |
|
9 |
+ "unit-no-unknown": [true, {"ignoreUnits": [ |
|
10 |
+ "rpx" |
|
11 |
+ ]}], |
|
12 |
+ "selector-type-no-unknown": [true, {"ignoreTypes": [ |
|
13 |
+ "swiper", "swiper-item", "page" |
|
14 |
+ ]}] |
|
15 |
+ } |
|
16 |
+} |
@@ -0,0 +1,56 @@ |
||
1 |
+// const gulp = require('gulp'); |
|
2 |
+const { watch, src, dest, series, parallel } = require('gulp'); |
|
3 |
+const rename = require('gulp-rename'); |
|
4 |
+const less = require('gulp-less'); |
|
5 |
+const replace = require('gulp-replace'); |
|
6 |
+const through2 = require('through2'); |
|
7 |
+const jeditor = require('gulp-json-editor'); |
|
8 |
+const gulpInstall = require('gulp-install'); |
|
9 |
+ |
|
10 |
+const srcDir = './src'; |
|
11 |
+// const appJson = require('./miniprogram/app.json'); |
|
12 |
+ |
|
13 |
+function wxss() { |
|
14 |
+ return ( |
|
15 |
+ src([`${srcDir}/**/*.less`, `!${srcDir}/**/_*.less`, `!${srcDir}/style/less/*.less`,`!${srcDir}/**/*.wxss`]) |
|
16 |
+ .pipe(replace(/\@(import\s[^@;]*)+(;import|\bimport|;|b)?/g, ($1) => { |
|
17 |
+ let isMixin = $1.indexOf(".less") |
|
18 |
+ if (isMixin == -1) { |
|
19 |
+ return `\/*T${$1}T*\/` |
|
20 |
+ } else { |
|
21 |
+ return $1 |
|
22 |
+ } |
|
23 |
+ })) |
|
24 |
+ .pipe( |
|
25 |
+ less().on('error', function(err) { |
|
26 |
+ console.error(err); |
|
27 |
+ this.emit('end'); // 防止中断 |
|
28 |
+ }) |
|
29 |
+ ) |
|
30 |
+ .pipe( |
|
31 |
+ rename(path => { |
|
32 |
+ path.extname = '.wxss'; |
|
33 |
+ }) |
|
34 |
+ ) |
|
35 |
+ .pipe(replace(/\/\*T(@import\s[^@;]*;)?(T\*\/)?/g, '$1')) |
|
36 |
+ .pipe( |
|
37 |
+ dest(file => { |
|
38 |
+ return file.base; |
|
39 |
+ }) |
|
40 |
+ ) |
|
41 |
+ ); |
|
42 |
+} |
|
43 |
+ |
|
44 |
+ |
|
45 |
+function watchCSS() { |
|
46 |
+ watch(`${srcDir}/**/*.less`, series(wxss)); |
|
47 |
+} |
|
48 |
+ |
|
49 |
+function clean() { |
|
50 |
+ del(['./dist/**']) |
|
51 |
+} |
|
52 |
+ |
|
53 |
+exports.watchCSS = watchCSS; |
|
54 |
+exports.wxss = wxss; |
|
55 |
+exports.dev = series(wxss, watchCSS); |
|
56 |
+exports.default = wxss; |
@@ -0,0 +1,60 @@ |
||
1 |
+{ |
|
2 |
+ "name": "kodo", |
|
3 |
+ "version": "1.0.0", |
|
4 |
+ "description": "统览系统", |
|
5 |
+ "main": "index.js", |
|
6 |
+ "miniprogram": "dist", |
|
7 |
+ "scripts": { |
|
8 |
+ "dev": "gulp dev", |
|
9 |
+ "init": "tnpm install && cd src && tnpm install", |
|
10 |
+ "eslint": "./node_modules/.bin/eslint src", |
|
11 |
+ "eslint:fix": "./node_modules/.bin/eslint --fix src", |
|
12 |
+ "stylelint": "./node_modules/.bin/stylelint src/**/*.less src/**/**/*.less src/**/**/**/*.less src/**/**/**/**/*.less src/**/**/**/**/**/*.less src/**/**/**/**/**/**/*.less", |
|
13 |
+ "stylelint:fix": "./node_modules/.bin/stylelint src/**/*.less src/**/**/*.less src/**/**/**/*.less src/**/**/**/**/*.less src/**/**/**/**/**/*.less src/**/**/**/**/**/**/*.less --fix", |
|
14 |
+ "format": "prettier --write", |
|
15 |
+ "test": "echo \"Error: no test specified\" && exit 1" |
|
16 |
+ }, |
|
17 |
+ "config": { |
|
18 |
+ "commitizen": { |
|
19 |
+ "path": "node_modules/cz-customizable" |
|
20 |
+ }, |
|
21 |
+ "cz-customizable": { |
|
22 |
+ "config": "node_modules/commitlint-config-imt/cz-config.js" |
|
23 |
+ } |
|
24 |
+ }, |
|
25 |
+ "repository": { |
|
26 |
+ "type": "git", |
|
27 |
+ "url": "http://git.xfoto.com.cn/SCRM/miniProgram.git" |
|
28 |
+ }, |
|
29 |
+ "author": "FFIB", |
|
30 |
+ "devDependencies": { |
|
31 |
+ "babel-eslint": "^10.0.3", |
|
32 |
+ "eslint": "^6.7.2", |
|
33 |
+ "eslint-config-airbnb": "^18.0.1", |
|
34 |
+ "eslint-config-airbnb-base": "^14.0.0", |
|
35 |
+ "eslint-config-prettier": "^6.7.0", |
|
36 |
+ "eslint-plugin-import": "^2.19.1", |
|
37 |
+ "eslint-plugin-jsx-a11y": "^6.2.3", |
|
38 |
+ "eslint-plugin-prettier": "^3.1.2", |
|
39 |
+ "eslint-plugin-react": "^7.14.3", |
|
40 |
+ "eslint-plugin-react-hooks": "^1.7.0", |
|
41 |
+ "gulp": "^4.0.0", |
|
42 |
+ "gulp-install": "^1.1.0", |
|
43 |
+ "gulp-json-editor": "^2.5.0", |
|
44 |
+ "gulp-less": "^4.0.1", |
|
45 |
+ "gulp-rename": "^1.4.0", |
|
46 |
+ "gulp-replace": "^1.0.0", |
|
47 |
+ "htmllint": "^0.8.0", |
|
48 |
+ "husky": "^1.2.0", |
|
49 |
+ "lint-staged": "^8.1.0", |
|
50 |
+ "prettier": "^1.19.1", |
|
51 |
+ "stylelint": "^12.0.0", |
|
52 |
+ "stylelint-config-recess-order": "^2.0.3", |
|
53 |
+ "stylelint-config-standard": "^19.0.0", |
|
54 |
+ "stylelint-prettier": "^1.1.2", |
|
55 |
+ "through2": "^3.0.0" |
|
56 |
+ }, |
|
57 |
+ "dependencies": { |
|
58 |
+ "wxml-to-canvas": "^1.0.3" |
|
59 |
+ } |
|
60 |
+} |
@@ -0,0 +1,83 @@ |
||
1 |
+const urls = require('./utils/urls.js') |
|
2 |
+const network = require('./utils/network.js') |
|
3 |
+const brandConfig = require('./brand/config.js') |
|
4 |
+const router = require('./utils/router.js') |
|
5 |
+const routerInterceptor = require('./utils/routerInterceptor') |
|
6 |
+ |
|
7 |
+App({ |
|
8 |
+ copywriting: brandConfig.copywriting, |
|
9 |
+ brandConfig, |
|
10 |
+ urls, |
|
11 |
+ network, |
|
12 |
+ router, |
|
13 |
+ routerInterceptor, |
|
14 |
+ globalData: { |
|
15 |
+ userInfo: {}, |
|
16 |
+ isLogin: false, |
|
17 |
+ isWarranty: false, |
|
18 |
+ hasSale: false, |
|
19 |
+ isWxwork: false, |
|
20 |
+ levels: [ |
|
21 |
+ '影友', |
|
22 |
+ 'LRC会员', |
|
23 |
+ '银卡会员', |
|
24 |
+ '金卡会员', |
|
25 |
+ '白金卡会员', |
|
26 |
+ '黑金卡会员' |
|
27 |
+ ] |
|
28 |
+ }, |
|
29 |
+ |
|
30 |
+ sceneHandler: null, |
|
31 |
+ |
|
32 |
+ onLaunch() {}, |
|
33 |
+ |
|
34 |
+ onShow(options) { |
|
35 |
+ this._warrantyCardCallBack(options.referrerInfo) |
|
36 |
+ }, |
|
37 |
+ |
|
38 |
+ // 保修卡回调操作 |
|
39 |
+ _warrantyCardCallBack(referrerInfo) { |
|
40 |
+ if ( |
|
41 |
+ referrerInfo === undefined || |
|
42 |
+ referrerInfo.appId !== 'wxeb490c6f9b154ef9' |
|
43 |
+ ) { |
|
44 |
+ return |
|
45 |
+ } |
|
46 |
+ |
|
47 |
+ this.globalData.isWarranty = true |
|
48 |
+ wx.switchTab({ |
|
49 |
+ url: '/pages/member/mine/mine' |
|
50 |
+ }) |
|
51 |
+ }, |
|
52 |
+ |
|
53 |
+ // 静默登录 |
|
54 |
+ login(cb) { |
|
55 |
+ const that = this |
|
56 |
+ network.login(res => { |
|
57 |
+ that.globalData.userInfo = res |
|
58 |
+ that.globalData.isLogin = true |
|
59 |
+ cb(res) |
|
60 |
+ }) |
|
61 |
+ }, |
|
62 |
+ |
|
63 |
+ // 获取用户unionid |
|
64 |
+ getUserInfo(param, cb) { |
|
65 |
+ const that = this |
|
66 |
+ network.post({ |
|
67 |
+ url: urls.MINI_USERINFO, |
|
68 |
+ data: { |
|
69 |
+ encryptedData: param.encryptedData, |
|
70 |
+ iv: param.iv |
|
71 |
+ }, |
|
72 |
+ success(res) { |
|
73 |
+ that.globalData.userInfo = res.data |
|
74 |
+ that.globalData.isLogin = true |
|
75 |
+ wx.setStorageSync('userInfo', res.data) |
|
76 |
+ cb() |
|
77 |
+ }, |
|
78 |
+ complete() { |
|
79 |
+ wx.hideLoading() |
|
80 |
+ } |
|
81 |
+ }) |
|
82 |
+ } |
|
83 |
+}) |
@@ -0,0 +1,23 @@ |
||
1 |
+{ |
|
2 |
+ "pages": [ |
|
3 |
+ "pages/index/index", |
|
4 |
+ "pages/order/order", |
|
5 |
+ "template/webView/webView", |
|
6 |
+ "template/resultView/resultView" |
|
7 |
+ ], |
|
8 |
+ "window": { |
|
9 |
+ "backgroundTextStyle": "dark", |
|
10 |
+ "navigationBarBackgroundColor": "#000000", |
|
11 |
+ "navigationBarTitleText": "尖货接龙", |
|
12 |
+ "navigationBarTextStyle": "white" |
|
13 |
+ }, |
|
14 |
+ "permission": { |
|
15 |
+ "scope.userLocation": { |
|
16 |
+ "desc": "你的位置信息将用于申请保修卡" |
|
17 |
+ } |
|
18 |
+ }, |
|
19 |
+ "navigateToMiniProgramAppIdList": [ |
|
20 |
+ "wxeb490c6f9b154ef9" |
|
21 |
+ ], |
|
22 |
+ "sitemapLocation": "sitemap.json" |
|
23 |
+} |
@@ -0,0 +1,97 @@ |
||
1 |
+/**app.wxss**/ |
|
2 |
+@import 'brand/brand.wxss'; |
|
3 |
+@import 'style/button.wxss'; |
|
4 |
+page { |
|
5 |
+ height: 100%; |
|
6 |
+} |
|
7 |
+ |
|
8 |
+.button-hover { |
|
9 |
+ opacity: 0.8; |
|
10 |
+ background-color: black; |
|
11 |
+} |
|
12 |
+ |
|
13 |
+/*去除所有button边框*/ |
|
14 |
+button::after { |
|
15 |
+ border: none; |
|
16 |
+} |
|
17 |
+ |
|
18 |
+button { |
|
19 |
+ box-sizing: content-box; |
|
20 |
+ border-radius: 0; |
|
21 |
+} |
|
22 |
+ |
|
23 |
+/* 背景图片 */ |
|
24 |
+.background { |
|
25 |
+ position: absolute; |
|
26 |
+ z-index: -1; |
|
27 |
+ |
|
28 |
+ width: 100%; |
|
29 |
+ height: 100%; |
|
30 |
+} |
|
31 |
+ |
|
32 |
+/** button **/ |
|
33 |
+.bottom-button { |
|
34 |
+ display: flex; |
|
35 |
+ flex-direction: column; |
|
36 |
+ align-items: center; |
|
37 |
+ justify-content: flex-end; |
|
38 |
+ flex-grow: 2; |
|
39 |
+} |
|
40 |
+ |
|
41 |
+.bottom-view { |
|
42 |
+ display: flex; |
|
43 |
+ flex-direction: column; |
|
44 |
+ justify-content: flex-end; |
|
45 |
+ flex-grow: 2; |
|
46 |
+ width: 100%; |
|
47 |
+} |
|
48 |
+ |
|
49 |
+.bottom-view .sale-button { |
|
50 |
+ display: flex; |
|
51 |
+ justify-content: center; |
|
52 |
+ align-items: center; |
|
53 |
+ margin-bottom: 0; |
|
54 |
+ width: 100%; |
|
55 |
+ height: calc(50px + env(safe-area-inset-bottom)); |
|
56 |
+ border-radius: 0; |
|
57 |
+ padding: 0 0 0 0; |
|
58 |
+ background-color: #1869ad; |
|
59 |
+ color: #fff; |
|
60 |
+ font-size: 40rpx; |
|
61 |
+} |
|
62 |
+ |
|
63 |
+.bottom-button .sale-button { |
|
64 |
+ display: flex; |
|
65 |
+ align-items: center; |
|
66 |
+ justify-content: center; |
|
67 |
+ margin-bottom: 50rpx; |
|
68 |
+ min-width: 200rpx; |
|
69 |
+ border-radius: 50rpx; |
|
70 |
+ padding: 5rpx 70rpx 5rpx 70rpx; |
|
71 |
+ background-color: #fff; |
|
72 |
+ color: #1869ad; |
|
73 |
+ font-size: 36rpx; |
|
74 |
+} |
|
75 |
+ |
|
76 |
+.bottom-button .consumer-button { |
|
77 |
+ display: flex; |
|
78 |
+ align-items: center; |
|
79 |
+ justify-content: center; |
|
80 |
+ margin-bottom: 50rpx; |
|
81 |
+ min-width: 300rpx; |
|
82 |
+ border-radius: 50rpx; |
|
83 |
+ padding: 5rpx 70rpx 5rpx 70rpx; |
|
84 |
+ background-color: #fff; |
|
85 |
+ color: #1869ad; |
|
86 |
+ font-size: 36rpx; |
|
87 |
+} |
|
88 |
+ |
|
89 |
+.bottom-view .sale-button[pressed] { |
|
90 |
+ background-color: rgba(24, 105, 173, 0.8); |
|
91 |
+ color: rgba(255, 255, 255, 0.8); |
|
92 |
+} |
|
93 |
+ |
|
94 |
+.bottom-view .sale-button[disabled] { |
|
95 |
+ background-color: rgba(24, 105, 173, 0.6); |
|
96 |
+ color: rgba(255, 255, 255, 0.6); |
|
97 |
+} |
@@ -0,0 +1,79 @@ |
||
1 |
+text { |
|
2 |
+ color: #fff; |
|
3 |
+} |
|
4 |
+ |
|
5 |
+.user-name { |
|
6 |
+ color: #fff; |
|
7 |
+} |
|
8 |
+ |
|
9 |
+.button { |
|
10 |
+ display: flex; |
|
11 |
+ justify-content: center; |
|
12 |
+ align-items: center; |
|
13 |
+ width: 35%; |
|
14 |
+ color: #1869ad; |
|
15 |
+ border-radius: 40%/120%; |
|
16 |
+ |
|
17 |
+ font-size: 80%; |
|
18 |
+ letter-spacing: 2px; |
|
19 |
+ font-weight: 500; |
|
20 |
+ background-color: #fff; |
|
21 |
+} |
|
22 |
+ |
|
23 |
+/* index */ |
|
24 |
+.sale-view .integral-view { |
|
25 |
+ border: 2px solid #fff; |
|
26 |
+} |
|
27 |
+ |
|
28 |
+.sale-view .integral-view .content { |
|
29 |
+ color: #fff; |
|
30 |
+} |
|
31 |
+ |
|
32 |
+/* commodity */ |
|
33 |
+.commodity-desc text { |
|
34 |
+ font-size: 90%; |
|
35 |
+} |
|
36 |
+ |
|
37 |
+.commodity-desc .title { |
|
38 |
+ font-size: 100%; |
|
39 |
+} |
|
40 |
+ |
|
41 |
+/* info */ |
|
42 |
+form .cell { |
|
43 |
+ background-color: #fff; |
|
44 |
+} |
|
45 |
+ |
|
46 |
+/* form .cell input { |
|
47 |
+ color: #fff; |
|
48 |
+} */ |
|
49 |
+ |
|
50 |
+form text, |
|
51 |
+form button { |
|
52 |
+ color: #1869ad; |
|
53 |
+} |
|
54 |
+ |
|
55 |
+.empty-hint { |
|
56 |
+ color: #fff; |
|
57 |
+} |
|
58 |
+ |
|
59 |
+.hint-main text { |
|
60 |
+ color: #1869ad; |
|
61 |
+} |
|
62 |
+ |
|
63 |
+.hint-main .confirm { |
|
64 |
+ background-color: #1869ad; |
|
65 |
+ color: #fff; |
|
66 |
+} |
|
67 |
+/* sale_integral */ |
|
68 |
+.integral-title { |
|
69 |
+ background-color: #95b9d9; |
|
70 |
+ color: #fff; |
|
71 |
+} |
|
72 |
+ |
|
73 |
+.integral-production { |
|
74 |
+ background-color: #f8f8f8; |
|
75 |
+} |
|
76 |
+ |
|
77 |
+.integral-production text { |
|
78 |
+ color: #1869ad; |
|
79 |
+} |
@@ -0,0 +1,37 @@ |
||
1 |
+module.exports = { |
|
2 |
+ baseURL: 'https://kodo.xfoto.com.cn', |
|
3 |
+ brandID: 'ywkRTh5vtswRvhh8uLvTTQ', |
|
4 |
+ demo: true, |
|
5 |
+ copywriting: { |
|
6 |
+ info: { |
|
7 |
+ headerTitle: |
|
8 |
+ 'THANK YOU!\n感谢您购买腾龙镜头\n请完善您的个人信息领取保修卡', |
|
9 |
+ coupon: '并领取意外维修劵', |
|
10 |
+ hintTitle: '提 交 成 功', |
|
11 |
+ inputDesc: '请完善您的信息获取5+1年保修服务', |
|
12 |
+ hintDesc: '恭喜您获得\n腾龙官方5+1年保修服务', |
|
13 |
+ hintCoupon: '和意外维修劵', |
|
14 |
+ hintBtn: '领取' |
|
15 |
+ }, |
|
16 |
+ saleInfo: { |
|
17 |
+ headerTitle: 'THANK YOU!\n感谢您销售腾龙正品行货镜头\n二维码验证有效', |
|
18 |
+ hintTitle: '提 交 成 功', |
|
19 |
+ hintDesc: |
|
20 |
+ '本次销售您消耗{{integral}}卡路里\n共计消耗{{totalIntegral}}卡路里', |
|
21 |
+ hintBtn: '确定' |
|
22 |
+ }, |
|
23 |
+ verification: { |
|
24 |
+ commodityTitle: '感谢您购买腾龙镜头', |
|
25 |
+ userInfoBtn: '申请电子保修卡' |
|
26 |
+ }, |
|
27 |
+ sale_verification: { |
|
28 |
+ commodityTitle: '请确认您所销售商品型号和编码', |
|
29 |
+ userInfoBtn: '确认出库' |
|
30 |
+ }, |
|
31 |
+ equipment: { |
|
32 |
+ emptyHint: '您还没有绑定腾龙镜头', |
|
33 |
+ couponTitle: '腾龙镜头意外维修券', |
|
34 |
+ couponDesc: '此券用于镜头保修范围外的意外或人为损伤的维修费' |
|
35 |
+ } |
|
36 |
+ } |
|
37 |
+} |
@@ -0,0 +1,62 @@ |
||
1 |
+// component/btnFooter-protocol/btnFooter-protocol.js |
|
2 |
+Component({ |
|
3 |
+ /** |
|
4 |
+ * Component properties |
|
5 |
+ */ |
|
6 |
+ properties: { |
|
7 |
+ btnClass: { |
|
8 |
+ type: String, |
|
9 |
+ value: 'button1' |
|
10 |
+ }, |
|
11 |
+ |
|
12 |
+ btnTxt: { |
|
13 |
+ type: String, |
|
14 |
+ value: '确认' |
|
15 |
+ }, |
|
16 |
+ |
|
17 |
+ btnDisalbed: { |
|
18 |
+ type: Boolean, |
|
19 |
+ value: false, |
|
20 |
+ observer(newVal, _) { |
|
21 |
+ this.setData({ |
|
22 |
+ disabled: newVal && this.data.protocolImg === 2 |
|
23 |
+ }) |
|
24 |
+ } |
|
25 |
+ }, |
|
26 |
+ |
|
27 |
+ openType: { |
|
28 |
+ type: String, |
|
29 |
+ value: '' |
|
30 |
+ } |
|
31 |
+ }, |
|
32 |
+ |
|
33 |
+ /** |
|
34 |
+ * Component initial data |
|
35 |
+ */ |
|
36 |
+ data: { |
|
37 |
+ protocolImg: 2, |
|
38 |
+ disabled: false |
|
39 |
+ }, |
|
40 |
+ |
|
41 |
+ /** |
|
42 |
+ * Component methods |
|
43 |
+ */ |
|
44 |
+ methods: { |
|
45 |
+ switchAuthorization() { |
|
46 |
+ this.setData({ |
|
47 |
+ disabled: this.data.protocolImg !== 1 || this.data.btnDisalbed, |
|
48 |
+ protocolImg: 3 - this.data.protocolImg |
|
49 |
+ }) |
|
50 |
+ }, |
|
51 |
+ |
|
52 |
+ openUrl(e) { |
|
53 |
+ wx.navigateTo({ |
|
54 |
+ url: `/template/webView/webView?url=${e.currentTarget.dataset.url}` |
|
55 |
+ }) |
|
56 |
+ }, |
|
57 |
+ |
|
58 |
+ confirm(e) { |
|
59 |
+ this.triggerEvent('action', e) |
|
60 |
+ } |
|
61 |
+ } |
|
62 |
+}) |
@@ -0,0 +1,4 @@ |
||
1 |
+{ |
|
2 |
+ "component": true, |
|
3 |
+ "usingComponents": {} |
|
4 |
+} |
@@ -0,0 +1,42 @@ |
||
1 |
+@import './src/style/less/variable.less'; |
|
2 |
+@import './src/style/less/layout.less'; |
|
3 |
+@import '/style/button.wxss'; |
|
4 |
+@import '/template/btn/btn.wxss'; |
|
5 |
+ |
|
6 |
+.btn-footer { |
|
7 |
+ .flex-center(column); |
|
8 |
+ |
|
9 |
+ position: fixed; |
|
10 |
+ bottom: 0; |
|
11 |
+ z-index: 999; |
|
12 |
+ justify-content: center; |
|
13 |
+ width: 100%; |
|
14 |
+ height: @btnFooterWithProtocol-height; |
|
15 |
+ background-color: @color-white; |
|
16 |
+ box-shadow: 0 -5px 9px 2px fade(@color-black, 10%); |
|
17 |
+ |
|
18 |
+ .protocol { |
|
19 |
+ .flex-center(row); |
|
20 |
+ |
|
21 |
+ image { |
|
22 |
+ .square(@icon-small-size); |
|
23 |
+ |
|
24 |
+ margin-right: @spacing-inline; |
|
25 |
+ } |
|
26 |
+ |
|
27 |
+ text { |
|
28 |
+ font-size: @font-label; |
|
29 |
+ color: @color-light-gray; |
|
30 |
+ } |
|
31 |
+ |
|
32 |
+ .clickable { |
|
33 |
+ color: @color-brand; |
|
34 |
+ } |
|
35 |
+ } |
|
36 |
+ |
|
37 |
+ button { |
|
38 |
+ width: @visual-width; |
|
39 |
+ height: 100rpx !important; |
|
40 |
+ margin-top: @spacing-inline; |
|
41 |
+ } |
|
42 |
+} |
@@ -0,0 +1,11 @@ |
||
1 |
+<import src="/template/btn/btn.wxml"></import> |
|
2 |
+<view class="btn-footer"> |
|
3 |
+ <view class="protocol"> |
|
4 |
+ <image src="/resources/protocol{{protocolImg}}.png" bindtap="switchAuthorization"></image> |
|
5 |
+ <text>点击确认即表示已阅读并同意</text> |
|
6 |
+ <text class="clickable" data-url="https://kodo.tamron.cn/mp/privacy.html" bindtap="openUrl">《隐私条款》</text> |
|
7 |
+ <text>和</text> |
|
8 |
+ <text class="clickable" data-url="https://kodo.tamron.cn/mp/regulations.html" bindtap="openUrl">《会员章程》</text> |
|
9 |
+ </view> |
|
10 |
+ <template is="iconBtn" data="{{btnClass: btnClass, btnTxt: btnTxt, disabled: disabled, action: 'confirm', openType: openType}}"></template> |
|
11 |
+</view> |
@@ -0,0 +1,36 @@ |
||
1 |
+@import '/style/button.wxss'; |
|
2 |
+@import '/template/btn/btn.wxss'; |
|
3 |
+.btn-footer { |
|
4 |
+ display: flex; |
|
5 |
+ flex-direction: column; |
|
6 |
+ align-items: center; |
|
7 |
+ position: fixed; |
|
8 |
+ bottom: 0; |
|
9 |
+ z-index: 999; |
|
10 |
+ justify-content: center; |
|
11 |
+ width: 100%; |
|
12 |
+ height: 200rpx; |
|
13 |
+ background-color: #fff; |
|
14 |
+ box-shadow: 0 -5px 9px 2px rgba(0, 0, 0, 0.1); |
|
15 |
+} |
|
16 |
+.btn-footer .protocol { |
|
17 |
+ display: flex; |
|
18 |
+ align-items: center; |
|
19 |
+} |
|
20 |
+.btn-footer .protocol image { |
|
21 |
+ width: 32rpx; |
|
22 |
+ height: 32rpx; |
|
23 |
+ margin-right: 12rpx; |
|
24 |
+} |
|
25 |
+.btn-footer .protocol text { |
|
26 |
+ font-size: 8pt; |
|
27 |
+ color: #959595; |
|
28 |
+} |
|
29 |
+.btn-footer .protocol .clickable { |
|
30 |
+ color: #0967b2; |
|
31 |
+} |
|
32 |
+.btn-footer button { |
|
33 |
+ width: 702rpx; |
|
34 |
+ height: 100rpx !important; |
|
35 |
+ margin-top: 12rpx; |
|
36 |
+} |
@@ -0,0 +1,127 @@ |
||
1 |
+// component/dialog-input/dialog-input.js |
|
2 |
+Component({ |
|
3 |
+ /** |
|
4 |
+ * Component properties |
|
5 |
+ */ |
|
6 |
+ properties: { |
|
7 |
+ title: { |
|
8 |
+ type: String, |
|
9 |
+ value: '' |
|
10 |
+ }, |
|
11 |
+ |
|
12 |
+ btn: { |
|
13 |
+ type: Object, |
|
14 |
+ value: {} |
|
15 |
+ }, |
|
16 |
+ |
|
17 |
+ msg: { |
|
18 |
+ type: Array, |
|
19 |
+ value: [], |
|
20 |
+ observer(newVal, _) { |
|
21 |
+ let btnDisabled = false |
|
22 |
+ newVal.forEach(v => { |
|
23 |
+ if (!v.hasValue && v.txt === '') { |
|
24 |
+ btnDisabled = true |
|
25 |
+ } |
|
26 |
+ }) |
|
27 |
+ |
|
28 |
+ this.setData({ |
|
29 |
+ btnDisabled |
|
30 |
+ }) |
|
31 |
+ } |
|
32 |
+ }, |
|
33 |
+ |
|
34 |
+ show: { |
|
35 |
+ type: Boolean, |
|
36 |
+ value: false, |
|
37 |
+ observer(newVal, oldVal) { |
|
38 |
+ if (newVal === oldVal) { |
|
39 |
+ return |
|
40 |
+ } |
|
41 |
+ if (newVal) { |
|
42 |
+ this.setData({ |
|
43 |
+ isShow: true |
|
44 |
+ }) |
|
45 |
+ const animation1 = wx.createAnimation({ |
|
46 |
+ duration: 400, |
|
47 |
+ timingFunction: 'linear' |
|
48 |
+ }) |
|
49 |
+ animation1.opacity(1).step() |
|
50 |
+ |
|
51 |
+ const animation2 = wx.createAnimation({ |
|
52 |
+ duration: 500, |
|
53 |
+ timingFunction: 'linear' |
|
54 |
+ }) |
|
55 |
+ animation2.opacity(1).step() |
|
56 |
+ this.setData({ |
|
57 |
+ bgAnimationData: animation1.export(), |
|
58 |
+ animationData: animation2.export() |
|
59 |
+ }) |
|
60 |
+ } else { |
|
61 |
+ const animation1 = wx.createAnimation({ |
|
62 |
+ duration: 400, |
|
63 |
+ timingFunction: 'linear' |
|
64 |
+ }) |
|
65 |
+ animation1.opacity(0).step() |
|
66 |
+ |
|
67 |
+ const animation2 = wx.createAnimation({ |
|
68 |
+ duration: 500, |
|
69 |
+ timingFunction: 'linear' |
|
70 |
+ }) |
|
71 |
+ |
|
72 |
+ animation2.opacity(0).step() |
|
73 |
+ this.setData({ |
|
74 |
+ bgAnimationData: animation1.export(), |
|
75 |
+ animationData: animation2.export() |
|
76 |
+ }) |
|
77 |
+ |
|
78 |
+ const that = this |
|
79 |
+ setTimeout(() => { |
|
80 |
+ that.setData({ |
|
81 |
+ isShow: false |
|
82 |
+ }) |
|
83 |
+ }, 500) |
|
84 |
+ } |
|
85 |
+ } |
|
86 |
+ } |
|
87 |
+ }, |
|
88 |
+ |
|
89 |
+ /** |
|
90 |
+ * Component initial data |
|
91 |
+ */ |
|
92 |
+ data: { |
|
93 |
+ btnDisabled: false, |
|
94 |
+ name: '', |
|
95 |
+ animationData: {}, |
|
96 |
+ bgAnimationData: {}, |
|
97 |
+ isShow: false |
|
98 |
+ }, |
|
99 |
+ |
|
100 |
+ /** |
|
101 |
+ * Component methods |
|
102 |
+ */ |
|
103 |
+ methods: { |
|
104 |
+ cancel() { |
|
105 |
+ this.triggerEvent('cancel', !this.data.show) |
|
106 |
+ }, |
|
107 |
+ |
|
108 |
+ nameInput(e) { |
|
109 |
+ this.setData({ |
|
110 |
+ name: e.detail.value |
|
111 |
+ }) |
|
112 |
+ }, |
|
113 |
+ |
|
114 |
+ getPhoneNumber(e) { |
|
115 |
+ this.triggerEvent('getPhoneNumber', e.detail) |
|
116 |
+ }, |
|
117 |
+ |
|
118 |
+ submit() { |
|
119 |
+ this.triggerEvent('submit', { name: this.data.name }) |
|
120 |
+ } |
|
121 |
+ }, |
|
122 |
+ |
|
123 |
+ pageLifetimes: { |
|
124 |
+ // 组件所在页面的生命周期函数 |
|
125 |
+ show() {} |
|
126 |
+ } |
|
127 |
+}) |
@@ -0,0 +1,4 @@ |
||
1 |
+{ |
|
2 |
+ "component": true, |
|
3 |
+ "usingComponents": {} |
|
4 |
+} |
@@ -0,0 +1,115 @@ |
||
1 |
+@import './src/style/less/variable.less'; |
|
2 |
+@import './src/style/less/layout.less'; |
|
3 |
+@import './src/style/less/shape.less'; |
|
4 |
+ |
|
5 |
+.dialog-input { |
|
6 |
+ .flex-center(row); |
|
7 |
+ |
|
8 |
+ position: absolute; |
|
9 |
+ top: 0; |
|
10 |
+ justify-content: center; |
|
11 |
+ width: 100%; |
|
12 |
+ height: 100%; |
|
13 |
+ background-color: rgba(0, 0, 0, 0.6); |
|
14 |
+ opacity: 0; |
|
15 |
+} |
|
16 |
+ |
|
17 |
+.main { |
|
18 |
+ position: relative; |
|
19 |
+ .flex-center(column); |
|
20 |
+ |
|
21 |
+ justify-content: center; |
|
22 |
+ width: 600rpx; |
|
23 |
+ background-color: @color-white; |
|
24 |
+ border-radius: @radius-big; |
|
25 |
+ opacity: 0; |
|
26 |
+} |
|
27 |
+ |
|
28 |
+.cancel { |
|
29 |
+ position: absolute; |
|
30 |
+ top: 30rpx; |
|
31 |
+ right: 20rpx; |
|
32 |
+ .cross(30rpx, @color-light-gray); |
|
33 |
+} |
|
34 |
+ |
|
35 |
+.main .title { |
|
36 |
+ .flex-center(row); |
|
37 |
+ |
|
38 |
+ justify-content: center; |
|
39 |
+ width: 100%; |
|
40 |
+ height: 60rpx; |
|
41 |
+ margin-top: 60rpx; |
|
42 |
+ font-size: @font-primary; |
|
43 |
+ |
|
44 |
+ text { |
|
45 |
+ color: @color-brand; |
|
46 |
+ } |
|
47 |
+} |
|
48 |
+ |
|
49 |
+form { |
|
50 |
+ width: 500rpx; |
|
51 |
+ margin: @spacing-view 0; |
|
52 |
+ |
|
53 |
+ .item { |
|
54 |
+ .flex-center(row); |
|
55 |
+ |
|
56 |
+ box-sizing: border-box; |
|
57 |
+ justify-content: flex-start; |
|
58 |
+ width: 100%; |
|
59 |
+ height: 80rpx; |
|
60 |
+ margin-top: @spacing-item; |
|
61 |
+ border: 1px @color-bg solid; |
|
62 |
+ border-radius: @radius; |
|
63 |
+ |
|
64 |
+ input { |
|
65 |
+ box-sizing: border-box; |
|
66 |
+ width: calc(100% - 2px); |
|
67 |
+ height: calc(100% - 2px); |
|
68 |
+ padding: @spacing-inline; |
|
69 |
+ font-size: @font-secondary; |
|
70 |
+ } |
|
71 |
+ |
|
72 |
+ .placeholder { |
|
73 |
+ font-size: @font-tertiary; |
|
74 |
+ color: @color-light-gray; |
|
75 |
+ } |
|
76 |
+ |
|
77 |
+ button { |
|
78 |
+ .flex-center(row); |
|
79 |
+ |
|
80 |
+ box-sizing: border-box; |
|
81 |
+ justify-content: space-between; |
|
82 |
+ width: calc(100% - 2px); |
|
83 |
+ height: calc(100% - 2px); |
|
84 |
+ padding: @spacing-inline; |
|
85 |
+ background-color: @color-white; |
|
86 |
+ |
|
87 |
+ .placeholder { |
|
88 |
+ font-size: @font-tertiary; |
|
89 |
+ color: #767676; |
|
90 |
+ } |
|
91 |
+ |
|
92 |
+ .txt { |
|
93 |
+ font-size: @font-secondary; |
|
94 |
+ color: @color-black; |
|
95 |
+ } |
|
96 |
+ |
|
97 |
+ .arrow { |
|
98 |
+ .arrow(right; @color-light-gray; 14rpx); |
|
99 |
+ } |
|
100 |
+ } |
|
101 |
+ } |
|
102 |
+ |
|
103 |
+ .confirm { |
|
104 |
+ .flex-center(row); |
|
105 |
+ |
|
106 |
+ box-sizing: border-box; |
|
107 |
+ justify-content: center; |
|
108 |
+ width: 500rpx; |
|
109 |
+ height: 80rpx; |
|
110 |
+ margin-top: @spacing-view; |
|
111 |
+ color: @color-white; |
|
112 |
+ background-color: @color-brand; |
|
113 |
+ border-radius: @radius; |
|
114 |
+ } |
|
115 |
+} |
@@ -0,0 +1,24 @@ |
||
1 |
+<view class="dialog-input" wx:if="{{isShow}}" animation="{{bgAnimationData}}"> |
|
2 |
+ <view class="main" animation="{{animationData}}"> |
|
3 |
+ <view class="cancel" bindtap="cancel"></view> |
|
4 |
+ <view class="title"> |
|
5 |
+ <text>{{title}}</text> |
|
6 |
+ </view> |
|
7 |
+ <form> |
|
8 |
+ <view class="container"> |
|
9 |
+ <block wx:for="{{msg}}"> |
|
10 |
+ <view class="item" wx:if="{{item.type == 'input'}}"> |
|
11 |
+ <input placeholder="{{item.txt || item.placeholder}}" placeholder-class="placeholder" bindinput="nameInput"></input> |
|
12 |
+ </view> |
|
13 |
+ <view class="item" wx:if="{{item.type == 'phone'}}"> |
|
14 |
+ <button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber"> |
|
15 |
+ <text class="{{item.txt == '' ? 'placeholder': 'txt'}}">{{item.txt || item.placeholder}}</text> |
|
16 |
+ <view class="arrow"></view> |
|
17 |
+ </button> |
|
18 |
+ </view> |
|
19 |
+ </block> |
|
20 |
+ </view> |
|
21 |
+ <button class="confirm" disabled="{{btnDisabled}}" bindtap="submit">{{btn.txt}}</button> |
|
22 |
+ </form> |
|
23 |
+ </view> |
|
24 |
+</view> |
@@ -0,0 +1,122 @@ |
||
1 |
+.dialog-input { |
|
2 |
+ display: flex; |
|
3 |
+ align-items: center; |
|
4 |
+ position: absolute; |
|
5 |
+ top: 0; |
|
6 |
+ justify-content: center; |
|
7 |
+ width: 100%; |
|
8 |
+ height: 100%; |
|
9 |
+ background-color: rgba(0, 0, 0, 0.6); |
|
10 |
+ opacity: 0; |
|
11 |
+} |
|
12 |
+.main { |
|
13 |
+ position: relative; |
|
14 |
+ display: flex; |
|
15 |
+ flex-direction: column; |
|
16 |
+ align-items: center; |
|
17 |
+ justify-content: center; |
|
18 |
+ width: 600rpx; |
|
19 |
+ background-color: #fff; |
|
20 |
+ border-radius: 10px; |
|
21 |
+ opacity: 0; |
|
22 |
+} |
|
23 |
+.cancel { |
|
24 |
+ position: absolute; |
|
25 |
+ top: 30rpx; |
|
26 |
+ right: 20rpx; |
|
27 |
+ display: inline-block; |
|
28 |
+ width: 30rpx; |
|
29 |
+ height: 7.5rpx; |
|
30 |
+ overflow: visible; |
|
31 |
+ font-size: 0; |
|
32 |
+ line-height: 0; |
|
33 |
+ vertical-align: middle; |
|
34 |
+ background: #959595; |
|
35 |
+ border-radius: 7.5rpx; |
|
36 |
+ transform: rotate(45deg); |
|
37 |
+} |
|
38 |
+.cancel::after { |
|
39 |
+ display: block; |
|
40 |
+ width: 30rpx; |
|
41 |
+ height: 7.5rpx; |
|
42 |
+ content: '/'; |
|
43 |
+ background: #959595; |
|
44 |
+ border-radius: 7.5rpx; |
|
45 |
+ transform: rotate(-90deg); |
|
46 |
+} |
|
47 |
+.main .title { |
|
48 |
+ display: flex; |
|
49 |
+ align-items: center; |
|
50 |
+ justify-content: center; |
|
51 |
+ width: 100%; |
|
52 |
+ height: 60rpx; |
|
53 |
+ margin-top: 60rpx; |
|
54 |
+ font-size: 14pt; |
|
55 |
+} |
|
56 |
+.main .title text { |
|
57 |
+ color: #0967b2; |
|
58 |
+} |
|
59 |
+form { |
|
60 |
+ width: 500rpx; |
|
61 |
+ margin: 36rpx 0; |
|
62 |
+} |
|
63 |
+form .item { |
|
64 |
+ display: flex; |
|
65 |
+ align-items: center; |
|
66 |
+ box-sizing: border-box; |
|
67 |
+ justify-content: flex-start; |
|
68 |
+ width: 100%; |
|
69 |
+ height: 80rpx; |
|
70 |
+ margin-top: 24rpx; |
|
71 |
+ border: 1px #efefef solid; |
|
72 |
+ border-radius: 5px; |
|
73 |
+} |
|
74 |
+form .item input { |
|
75 |
+ box-sizing: border-box; |
|
76 |
+ width: calc(100% - 2px); |
|
77 |
+ height: calc(100% - 2px); |
|
78 |
+ padding: 12rpx; |
|
79 |
+ font-size: 13pt; |
|
80 |
+} |
|
81 |
+form .item .placeholder { |
|
82 |
+ font-size: 11pt; |
|
83 |
+ color: #959595; |
|
84 |
+} |
|
85 |
+form .item button { |
|
86 |
+ display: flex; |
|
87 |
+ align-items: center; |
|
88 |
+ box-sizing: border-box; |
|
89 |
+ justify-content: space-between; |
|
90 |
+ width: calc(100% - 2px); |
|
91 |
+ height: calc(100% - 2px); |
|
92 |
+ padding: 12rpx; |
|
93 |
+ background-color: #fff; |
|
94 |
+} |
|
95 |
+form .item button .placeholder { |
|
96 |
+ font-size: 11pt; |
|
97 |
+ color: #767676; |
|
98 |
+} |
|
99 |
+form .item button .txt { |
|
100 |
+ font-size: 13pt; |
|
101 |
+ color: #000; |
|
102 |
+} |
|
103 |
+form .item button .arrow { |
|
104 |
+ width: 14rpx; |
|
105 |
+ height: 14rpx; |
|
106 |
+ box-sizing: border-box; |
|
107 |
+ border-top: 2px solid #959595; |
|
108 |
+ border-right: 2px solid #959595; |
|
109 |
+ transform: rotate(45deg); |
|
110 |
+} |
|
111 |
+form .confirm { |
|
112 |
+ display: flex; |
|
113 |
+ align-items: center; |
|
114 |
+ box-sizing: border-box; |
|
115 |
+ justify-content: center; |
|
116 |
+ width: 500rpx; |
|
117 |
+ height: 80rpx; |
|
118 |
+ margin-top: 36rpx; |
|
119 |
+ color: #fff; |
|
120 |
+ background-color: #0967b2; |
|
121 |
+ border-radius: 5px; |
|
122 |
+} |
@@ -0,0 +1 @@ |
||
1 |
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1587110727868" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1164" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M512 85.333333c235.637333 0 426.666667 191.029333 426.666667 426.666667S747.637333 938.666667 512 938.666667 85.333333 747.637333 85.333333 512 276.362667 85.333333 512 85.333333z m0 234.666667a32 32 0 0 0-32 32v128H352a32 32 0 0 0 0 64h128v128a32 32 0 0 0 64 0V544h128a32 32 0 0 0 0-64H544V352a32 32 0 0 0-32-32z" p-id="1165" fill="#09bb07"></path></svg> |
@@ -0,0 +1 @@ |
||
1 |
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1587110843176" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1962" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M510.293333 126.862222c51.863704 0 102.115556 10.145185 149.428148 30.151111 45.700741 19.342222 86.755556 47.028148 122.026667 82.29926 35.271111 35.271111 62.957037 76.325926 82.299259 122.026666 20.005926 47.312593 30.151111 97.564444 30.151112 149.428148s-10.145185 102.115556-30.151112 149.428149c-19.342222 45.700741-47.028148 86.755556-82.299259 122.026666-35.271111 35.271111-76.325926 62.957037-122.026667 82.299259-47.217778 20.100741-97.564444 30.340741-149.428148 30.340741S408.177778 884.622222 360.865185 864.616296c-45.700741-19.342222-86.755556-47.028148-122.026666-82.299259-35.271111-35.271111-62.957037-76.325926-82.29926-122.026667-20.005926-47.312593-30.151111-97.564444-30.151111-149.428148S136.533333 408.651852 156.539259 361.339259c19.342222-45.700741 47.028148-86.755556 82.29926-122.026666 35.271111-35.271111 76.325926-62.957037 122.026666-82.29926 47.312593-20.005926 97.659259-30.151111 149.428148-30.151111m0-42.666666c-235.614815 0-426.666667 191.051852-426.666666 426.666666s191.051852 426.666667 426.666666 426.666667 426.666667-191.051852 426.666667-426.666667-190.957037-426.666667-426.666667-426.666666z" p-id="1963" fill="#09bb07"></path><path d="M709.499259 532.195556h-398.222222c-11.757037 0-21.333333-9.576296-21.333333-21.333334s9.576296-21.333333 21.333333-21.333333h398.222222c11.757037 0 21.333333 9.576296 21.333334 21.333333s-9.576296 21.333333-21.333334 21.333334z" p-id="1964" fill="#09bb07"></path></svg> |
@@ -0,0 +1,27 @@ |
||
1 |
+// component/stepper/stepper.js |
|
2 |
+Component({ |
|
3 |
+ data: { |
|
4 |
+ num: 0 |
|
5 |
+ }, |
|
6 |
+ |
|
7 |
+ /** |
|
8 |
+ * 组件的方法列表 |
|
9 |
+ */ |
|
10 |
+ methods: { |
|
11 |
+ bindadd() { |
|
12 |
+ this.setData({ |
|
13 |
+ num: this.data.num + 1 |
|
14 |
+ }) |
|
15 |
+ |
|
16 |
+ this.triggerEvent('stepperChanged', this.data.num) |
|
17 |
+ }, |
|
18 |
+ |
|
19 |
+ bindminus() { |
|
20 |
+ this.setData({ |
|
21 |
+ num: this.data.num - 1 |
|
22 |
+ }) |
|
23 |
+ |
|
24 |
+ this.triggerEvent('stepperChanged', this.data.num) |
|
25 |
+ } |
|
26 |
+ } |
|
27 |
+}) |
@@ -0,0 +1,4 @@ |
||
1 |
+{ |
|
2 |
+ "component": true, |
|
3 |
+ "usingComponents": {} |
|
4 |
+} |
@@ -0,0 +1,17 @@ |
||
1 |
+@import './src/style/less/variable.less'; |
|
2 |
+ |
|
3 |
+.stepper { |
|
4 |
+ display: flex; |
|
5 |
+ align-items: center; |
|
6 |
+ |
|
7 |
+ .icon { |
|
8 |
+ width: 72rpx; |
|
9 |
+ height: 72rpx; |
|
10 |
+ } |
|
11 |
+ |
|
12 |
+ .num { |
|
13 |
+ padding: 0 @spacing-short-text; |
|
14 |
+ color: #000; |
|
15 |
+ text-align: center; |
|
16 |
+ } |
|
17 |
+} |
@@ -0,0 +1,5 @@ |
||
1 |
+<view class="stepper"> |
|
2 |
+ <image class="icon" src="minus.svg" bindtap="bindminus" wx:if="{{ num !== 0 }}"></image> |
|
3 |
+ <text class="num" wx:if="{{ num !== 0 }}">{{ num }}</text> |
|
4 |
+ <image class="icon" src="add.svg" bindtap="bindadd"></image> |
|
5 |
+</view> |
@@ -0,0 +1,13 @@ |
||
1 |
+.stepper { |
|
2 |
+ display: flex; |
|
3 |
+ align-items: center; |
|
4 |
+} |
|
5 |
+.stepper .icon { |
|
6 |
+ width: 72rpx; |
|
7 |
+ height: 72rpx; |
|
8 |
+} |
|
9 |
+.stepper .num { |
|
10 |
+ padding: 0 4rpx; |
|
11 |
+ color: #000; |
|
12 |
+ text-align: center; |
|
13 |
+} |
@@ -0,0 +1,205 @@ |
||
1 |
+const WxParse = require('../../utils/wxParse/wxParse.js') |
|
2 |
+ |
|
3 |
+const app = getApp() |
|
4 |
+ |
|
5 |
+app.routerInterceptor.checkLoginStatus({ |
|
6 |
+ /** |
|
7 |
+ * 页面的初始数据 |
|
8 |
+ */ |
|
9 |
+ data: { |
|
10 |
+ kol: {}, |
|
11 |
+ commodities: [], |
|
12 |
+ |
|
13 |
+ consumers: [], |
|
14 |
+ |
|
15 |
+ pack_id: 'FMHBanG9d9uCm9CAEAdMVa', |
|
16 |
+ pack: {}, |
|
17 |
+ |
|
18 |
+ nums: [], |
|
19 |
+ total: 0, |
|
20 |
+ isLodding: false |
|
21 |
+ }, |
|
22 |
+ |
|
23 |
+ /** |
|
24 |
+ * 生命周期函数--监听页面加载 |
|
25 |
+ */ |
|
26 |
+ onLoad() { |
|
27 |
+ this.getData() |
|
28 |
+ wx.hideHomeButton() |
|
29 |
+ }, |
|
30 |
+ |
|
31 |
+ getData() { |
|
32 |
+ const that = this |
|
33 |
+ app.network.post({ |
|
34 |
+ url: app.urls.PACK, |
|
35 |
+ data: { |
|
36 |
+ pack_id: 'FMHBanG9d9uCm9CAEAdMVa' |
|
37 |
+ }, |
|
38 |
+ success(res) { |
|
39 |
+ const { sales, pack, goods } = res.data |
|
40 |
+ const conusmers = sales.map(sale => { |
|
41 |
+ const s = sale |
|
42 |
+ s.content = sale.saleinfo.reduce( |
|
43 |
+ (accumulator, cur) => `${accumulator + cur.title} x ${cur.num} \n`, |
|
44 |
+ '' |
|
45 |
+ ) |
|
46 |
+ s.created_at = that.timeago(s.created_at) |
|
47 |
+ return s |
|
48 |
+ }) |
|
49 |
+ WxParse.wxParse('article', 'html', pack.pack_detail, that, 5) |
|
50 |
+ pack.pack_detail = '' |
|
51 |
+ |
|
52 |
+ const commodities = goods.map(commodity => { |
|
53 |
+ const c = commodity |
|
54 |
+ c.price /= 100 |
|
55 |
+ return c |
|
56 |
+ }) |
|
57 |
+ that.setData({ |
|
58 |
+ kol: res.data.kol, |
|
59 |
+ commodities, |
|
60 |
+ nums: Array(res.data.goods).fill(0), |
|
61 |
+ consumers: conusmers, |
|
62 |
+ pack, |
|
63 |
+ isLodding: true |
|
64 |
+ }) |
|
65 |
+ } |
|
66 |
+ }) |
|
67 |
+ }, |
|
68 |
+ |
|
69 |
+ bindstepperChanged(e) { |
|
70 |
+ const { nums, commodities } = this.data |
|
71 |
+ nums[e.currentTarget.dataset.index] = e.detail |
|
72 |
+ |
|
73 |
+ const total = commodities.reduce( |
|
74 |
+ (accumulator, cur, index) => |
|
75 |
+ accumulator + (cur.price * 100 * nums[index]) / 100, |
|
76 |
+ 0 |
|
77 |
+ ) |
|
78 |
+ |
|
79 |
+ this.setData({ |
|
80 |
+ nums, |
|
81 |
+ total |
|
82 |
+ }) |
|
83 |
+ }, |
|
84 |
+ |
|
85 |
+ navigateToOrder() { |
|
86 |
+ const { nums } = this.data |
|
87 |
+ let { commodities } = this.data |
|
88 |
+ commodities = commodities |
|
89 |
+ .map((curr, index) => { |
|
90 |
+ return Object.assign(curr, { num: nums[index] }) |
|
91 |
+ }) |
|
92 |
+ .filter(curr => { |
|
93 |
+ return curr.num > 0 |
|
94 |
+ }) |
|
95 |
+ |
|
96 |
+ const that = this |
|
97 |
+ wx.navigateTo({ |
|
98 |
+ url: '../order/order', |
|
99 |
+ success(res) { |
|
100 |
+ res.eventChannel.emit('acceptDataFromOpenerPage', { |
|
101 |
+ commodities, |
|
102 |
+ total: that.data.total, |
|
103 |
+ kol: that.data.kol, |
|
104 |
+ pack_id: that.data.pack_id |
|
105 |
+ }) |
|
106 |
+ } |
|
107 |
+ }) |
|
108 |
+ }, |
|
109 |
+ |
|
110 |
+ getUserInfo(e) { |
|
111 |
+ if (e.detail.userInfo === undefined) { |
|
112 |
+ wx.showModal({ |
|
113 |
+ title: '提示', |
|
114 |
+ content: '需要您的授权,才能继续报名', |
|
115 |
+ showCancel: false |
|
116 |
+ }) |
|
117 |
+ } else { |
|
118 |
+ wx.showLoading({ |
|
119 |
+ title: '登陆中' |
|
120 |
+ }) |
|
121 |
+ |
|
122 |
+ const that = this |
|
123 |
+ app.getUserInfo( |
|
124 |
+ { |
|
125 |
+ iv: e.detail.iv, |
|
126 |
+ encryptedData: e.detail.encryptedData |
|
127 |
+ }, |
|
128 |
+ () => { |
|
129 |
+ that.navigateToOrder() |
|
130 |
+ } |
|
131 |
+ ) |
|
132 |
+ } |
|
133 |
+ }, |
|
134 |
+ |
|
135 |
+ onShareAppMessage() { |
|
136 |
+ return { |
|
137 |
+ title: this.data.pack.title, |
|
138 |
+ path: '/pages/index/index' |
|
139 |
+ } |
|
140 |
+ }, |
|
141 |
+ |
|
142 |
+ timeago(date) { |
|
143 |
+ // dateTimeStamp是一个时间毫秒,注意时间戳是秒的形式,在这个毫秒的基础上除以1000,就是十位数的时间戳。13位数的都是时间毫秒。 |
|
144 |
+ const dateTimeStamp = new Date( |
|
145 |
+ Date.parse(date.replace(/-/g, '/')) |
|
146 |
+ ).getTime() |
|
147 |
+ |
|
148 |
+ const minute = 1000 * 60 // 把分,时,天,周,半个月,一个月用毫秒表示 |
|
149 |
+ const hour = minute * 60 |
|
150 |
+ const day = hour * 24 |
|
151 |
+ const week = day * 7 |
|
152 |
+ const halfamonth = day * 15 |
|
153 |
+ const month = day * 30 |
|
154 |
+ const now = new Date().getTime() // 获取当前时间毫秒 |
|
155 |
+ const diffValue = now - dateTimeStamp // 时间差 |
|
156 |
+ |
|
157 |
+ if (diffValue < 0) { |
|
158 |
+ return '' |
|
159 |
+ } |
|
160 |
+ const minC = diffValue / minute // 计算时间差的分,时,天,周,月 |
|
161 |
+ const hourC = diffValue / hour |
|
162 |
+ const dayC = diffValue / day |
|
163 |
+ const weekC = diffValue / week |
|
164 |
+ const monthC = diffValue / month |
|
165 |
+ let result = '' |
|
166 |
+ |
|
167 |
+ if (monthC >= 1 && monthC <= 3) { |
|
168 |
+ result = ` ${parseInt(monthC)}月前` |
|
169 |
+ } else if (weekC >= 1 && weekC <= 3) { |
|
170 |
+ result = ` ${parseInt(weekC)}周前` |
|
171 |
+ } else if (dayC >= 1 && dayC <= 6) { |
|
172 |
+ result = ` ${parseInt(dayC)}天前` |
|
173 |
+ } else if (hourC >= 1 && hourC <= 23) { |
|
174 |
+ result = ` ${parseInt(hourC)}小时前` |
|
175 |
+ } else if (minC >= 1 && minC <= 59) { |
|
176 |
+ result = ` ${parseInt(minC)}分钟前` |
|
177 |
+ } else if (diffValue >= 0 && diffValue <= minute) { |
|
178 |
+ result = '刚刚' |
|
179 |
+ } else { |
|
180 |
+ const datetime = new Date() |
|
181 |
+ datetime.setTime(dateTimeStamp) |
|
182 |
+ const Nyear = datetime.getFullYear() |
|
183 |
+ const Nmonth = |
|
184 |
+ datetime.getMonth() + 1 < 10 |
|
185 |
+ ? `0${datetime.getMonth() + 1}` |
|
186 |
+ : datetime.getMonth() + 1 |
|
187 |
+ const Ndate = |
|
188 |
+ datetime.getDate() < 10 ? `0${datetime.getDate()}` : datetime.getDate() |
|
189 |
+ const Nhour = |
|
190 |
+ datetime.getHours() < 10 |
|
191 |
+ ? `0${datetime.getHours()}` |
|
192 |
+ : datetime.getHours() |
|
193 |
+ const Nminute = |
|
194 |
+ datetime.getMinutes() < 10 |
|
195 |
+ ? `0${datetime.getMinutes()}` |
|
196 |
+ : datetime.getMinutes() |
|
197 |
+ const Nsecond = |
|
198 |
+ datetime.getSeconds() < 10 |
|
199 |
+ ? `0${datetime.getSeconds()}` |
|
200 |
+ : datetime.getSeconds() |
|
201 |
+ result = `${Nyear}-${Nmonth}-${Ndate}` |
|
202 |
+ } |
|
203 |
+ return result |
|
204 |
+ } |
|
205 |
+}) |
@@ -0,0 +1,6 @@ |
||
1 |
+{ |
|
2 |
+ "usingComponents": { |
|
3 |
+ "stepper": "/component/stepper/stepper" |
|
4 |
+ }, |
|
5 |
+ "disableScroll": true |
|
6 |
+} |
@@ -0,0 +1,310 @@ |
||
1 |
+@import './src/style/less/variable.less'; |
|
2 |
+@import './src/style/less/layout.less'; |
|
3 |
+@import './src/style/less/shape.less'; |
|
4 |
+@import '/template/footer/footer.wxss'; |
|
5 |
+@import '/template/btn/btn.wxss'; |
|
6 |
+@import '/utils/wxParse/wxParse.wxss'; |
|
7 |
+ |
|
8 |
+page { |
|
9 |
+ background-color: @color-bg; |
|
10 |
+} |
|
11 |
+ |
|
12 |
+.wrap { |
|
13 |
+ box-sizing: border-box; |
|
14 |
+ display: flex; |
|
15 |
+ flex-direction: column; |
|
16 |
+ align-items: center; |
|
17 |
+ height: 100%; |
|
18 |
+ background-color: @color-bg; |
|
19 |
+} |
|
20 |
+ |
|
21 |
+.header { |
|
22 |
+ position: relative; |
|
23 |
+ width: 100%; |
|
24 |
+ |
|
25 |
+ .banner-img { |
|
26 |
+ position: absolute; |
|
27 |
+ width: 750rpx; |
|
28 |
+ height: 400rpx; |
|
29 |
+ } |
|
30 |
+ |
|
31 |
+ // .banner-container { |
|
32 |
+ // position: absolute; |
|
33 |
+ // top: 0; |
|
34 |
+ // z-index: 1; |
|
35 |
+ // width: 100%; |
|
36 |
+ // height: 400rpx; |
|
37 |
+ // } |
|
38 |
+ |
|
39 |
+ .user-info { |
|
40 |
+ position: relative; |
|
41 |
+ box-sizing: border-box; |
|
42 |
+ display: flex; |
|
43 |
+ align-items: flex-end; |
|
44 |
+ width: 750rpx; |
|
45 |
+ height: 200rpx; |
|
46 |
+ padding: 0 @spacing-item @spacing-item; |
|
47 |
+ margin-top: 200rpx; |
|
48 |
+ background-image: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.8)); |
|
49 |
+ |
|
50 |
+ .avatar { |
|
51 |
+ width: 100rpx; |
|
52 |
+ height: 100rpx; |
|
53 |
+ border-radius: 6px; |
|
54 |
+ } |
|
55 |
+ |
|
56 |
+ .nickname { |
|
57 |
+ margin: 0 0 @spacing-inline @spacing-inline; |
|
58 |
+ font-size: @font-primary; |
|
59 |
+ color: #fff; |
|
60 |
+ } |
|
61 |
+ |
|
62 |
+ .subscribe { |
|
63 |
+ display: flex; |
|
64 |
+ flex-grow: 2; |
|
65 |
+ align-items: center; |
|
66 |
+ justify-content: flex-end; |
|
67 |
+ margin: 0 0 @spacing-inline @spacing-inline; |
|
68 |
+ |
|
69 |
+ .num { |
|
70 |
+ font-size: @font-secondary; |
|
71 |
+ font-weight: 600; |
|
72 |
+ color: @color-white; |
|
73 |
+ } |
|
74 |
+ |
|
75 |
+ .label { |
|
76 |
+ margin-left: @spacing-short-text; |
|
77 |
+ font-size: @font-quaternary; |
|
78 |
+ color: #cbcbcb; |
|
79 |
+ } |
|
80 |
+ } |
|
81 |
+ } |
|
82 |
+ |
|
83 |
+ .desc { |
|
84 |
+ margin-top: @spacing-view; |
|
85 |
+ margin-bottom: 0rpx; |
|
86 |
+ margin-left: @spacing-item; |
|
87 |
+ |
|
88 |
+ text { |
|
89 |
+ color: @color-light-gray; |
|
90 |
+ } |
|
91 |
+ } |
|
92 |
+} |
|
93 |
+ |
|
94 |
+.main { |
|
95 |
+ box-sizing: border-box; |
|
96 |
+ width: @visual-width; |
|
97 |
+ margin-top: @spacing-view; |
|
98 |
+} |
|
99 |
+ |
|
100 |
+.commodity-container { |
|
101 |
+ .flex-center(column); |
|
102 |
+ |
|
103 |
+ box-sizing: border-box; |
|
104 |
+ width: 100%; |
|
105 |
+ padding: @spacing-view @spacing-item; |
|
106 |
+ background-color: @color-white; |
|
107 |
+ |
|
108 |
+ .commodity-title-container { |
|
109 |
+ display: flex; |
|
110 |
+ flex-direction: column; |
|
111 |
+ width: 100%; |
|
112 |
+ |
|
113 |
+ .title { |
|
114 |
+ font-size: @font-primary; |
|
115 |
+ font-weight: 600; |
|
116 |
+ color: @color-black; |
|
117 |
+ } |
|
118 |
+ |
|
119 |
+ .expired { |
|
120 |
+ margin-top: @spacing-short-text; |
|
121 |
+ font-size: @font-quaternary; |
|
122 |
+ color: @color-light-gray; |
|
123 |
+ } |
|
124 |
+ } |
|
125 |
+ |
|
126 |
+ .commodity-details { |
|
127 |
+ width: 100%; |
|
128 |
+ margin-top: @spacing-item; |
|
129 |
+ } |
|
130 |
+ |
|
131 |
+ .commodity-list { |
|
132 |
+ .flex-center(column); |
|
133 |
+ |
|
134 |
+ width: 100%; |
|
135 |
+ margin-top: @spacing-view; |
|
136 |
+ |
|
137 |
+ .commodity-item { |
|
138 |
+ display: flex; |
|
139 |
+ align-items: center; |
|
140 |
+ justify-content: space-between; |
|
141 |
+ width: 100%; |
|
142 |
+ height: 200rpx; |
|
143 |
+ padding: @spacing-item 0; |
|
144 |
+ border-bottom: 1px @color-bg solid; |
|
145 |
+ |
|
146 |
+ .commodity-left { |
|
147 |
+ .flex-center(row); |
|
148 |
+ |
|
149 |
+ height: 200rpx; |
|
150 |
+ |
|
151 |
+ .commodity-img { |
|
152 |
+ width: 180rpx; |
|
153 |
+ height: 180rpx; |
|
154 |
+ } |
|
155 |
+ |
|
156 |
+ .commodity-content { |
|
157 |
+ display: flex; |
|
158 |
+ flex-direction: column; |
|
159 |
+ height: 100%; |
|
160 |
+ margin-left: @spacing-item; |
|
161 |
+ |
|
162 |
+ .commodity-title { |
|
163 |
+ font-size: @font-secondary; |
|
164 |
+ color: @color-gray; |
|
165 |
+ } |
|
166 |
+ |
|
167 |
+ .commodity-desc { |
|
168 |
+ margin-top: @spacing-short-text; |
|
169 |
+ font-size: @font-quaternary; |
|
170 |
+ color: @color-light-gray; |
|
171 |
+ } |
|
172 |
+ } |
|
173 |
+ } |
|
174 |
+ |
|
175 |
+ .commodity-price { |
|
176 |
+ display: flex; |
|
177 |
+ flex-grow: 2; |
|
178 |
+ align-items: flex-end; |
|
179 |
+ |
|
180 |
+ text { |
|
181 |
+ font-size: @font-primary; |
|
182 |
+ color: #e64340; |
|
183 |
+ } |
|
184 |
+ } |
|
185 |
+ } |
|
186 |
+ |
|
187 |
+ .commodity-right { |
|
188 |
+ display: flex; |
|
189 |
+ flex-direction: column; |
|
190 |
+ align-items: flex-end; |
|
191 |
+ height: 100%; |
|
192 |
+ |
|
193 |
+ .bought { |
|
194 |
+ font-size: @font-quaternary; |
|
195 |
+ color: #e64340; |
|
196 |
+ text-align: right; |
|
197 |
+ } |
|
198 |
+ |
|
199 |
+ .stepper-container { |
|
200 |
+ margin-top: @spacing-item; |
|
201 |
+ } |
|
202 |
+ } |
|
203 |
+ } |
|
204 |
+} |
|
205 |
+ |
|
206 |
+.consumer-container { |
|
207 |
+ padding: @spacing-item; |
|
208 |
+ background-color: @color-white; |
|
209 |
+ |
|
210 |
+ .consumer-title { |
|
211 |
+ height: 80rpx; |
|
212 |
+ |
|
213 |
+ text { |
|
214 |
+ font-size: @font-primary; |
|
215 |
+ font-weight: 600; |
|
216 |
+ color: @color-gray; |
|
217 |
+ } |
|
218 |
+ } |
|
219 |
+ |
|
220 |
+ .swiper-container { |
|
221 |
+ width: 100%; |
|
222 |
+ height: 200rpx; |
|
223 |
+ } |
|
224 |
+ |
|
225 |
+ .consumer-item { |
|
226 |
+ width: @visual-width - @spacing-item * 2; |
|
227 |
+ |
|
228 |
+ .consumer-info { |
|
229 |
+ display: flex; |
|
230 |
+ align-items: center; |
|
231 |
+ |
|
232 |
+ .avatar { |
|
233 |
+ width: 56rpx; |
|
234 |
+ height: 56rpx; |
|
235 |
+ border-radius: 28rpx; |
|
236 |
+ } |
|
237 |
+ |
|
238 |
+ .name { |
|
239 |
+ margin-left: @spacing-inline; |
|
240 |
+ font-size: @font-tertiary; |
|
241 |
+ font-weight: 600; |
|
242 |
+ color: @color-black; |
|
243 |
+ } |
|
244 |
+ |
|
245 |
+ .time { |
|
246 |
+ margin-top: 4rpx; |
|
247 |
+ margin-left: @spacing-item; |
|
248 |
+ font-size: @font-label; |
|
249 |
+ color: lighten(@color-light-gray, 20%); |
|
250 |
+ } |
|
251 |
+ } |
|
252 |
+ |
|
253 |
+ .consumer-commodity { |
|
254 |
+ display: flex; |
|
255 |
+ justify-content: flex-end; |
|
256 |
+ width: 100%; |
|
257 |
+ margin-top: @spacing-inline; |
|
258 |
+ |
|
259 |
+ text { |
|
260 |
+ width: 100%; |
|
261 |
+ font-size: @font-tertiary; |
|
262 |
+ color: @color-gray; |
|
263 |
+ text-align: right; |
|
264 |
+ } |
|
265 |
+ } |
|
266 |
+ } |
|
267 |
+} |
|
268 |
+ |
|
269 |
+.btn-footer { |
|
270 |
+ .flex-center(row); |
|
271 |
+ |
|
272 |
+ position: fixed; |
|
273 |
+ bottom: 0; |
|
274 |
+ box-sizing: border-box; |
|
275 |
+ justify-content: center; |
|
276 |
+ width: 100%; |
|
277 |
+ height: @btnFooter-height; |
|
278 |
+ padding: @spacing-item; |
|
279 |
+ background-color: @color-white; |
|
280 |
+ box-shadow: 0 -5px 9px 2px fade(@color-black, 10%); |
|
281 |
+ |
|
282 |
+ .btn-footer-container { |
|
283 |
+ display: flex; |
|
284 |
+ width: 100%; |
|
285 |
+ height: 100rpx; |
|
286 |
+ overflow: hidden; |
|
287 |
+ border: 1px #09bb07 solid; |
|
288 |
+ border-radius: @radius; |
|
289 |
+ |
|
290 |
+ .left { |
|
291 |
+ .flex-center(row); |
|
292 |
+ |
|
293 |
+ justify-content: center; |
|
294 |
+ width: 40%; |
|
295 |
+ height: 100rpx; |
|
296 |
+ background-color: @color-white; |
|
297 |
+ |
|
298 |
+ text { |
|
299 |
+ font-size: @font-primary; |
|
300 |
+ font-weight: 700; |
|
301 |
+ color: #e64340; |
|
302 |
+ } |
|
303 |
+ } |
|
304 |
+ |
|
305 |
+ .right { |
|
306 |
+ width: 100%; |
|
307 |
+ height: 100%; |
|
308 |
+ } |
|
309 |
+ } |
|
310 |
+} |
@@ -0,0 +1,93 @@ |
||
1 |
+<scroll-view |
|
2 |
+ class="wrap" |
|
3 |
+ scroll-y="{{ true }}" |
|
4 |
+ enable-flex="{{ true }}" |
|
5 |
+ style="padding-bottom:{{ total === 0 ? '36rpx' : '196rpx' }}"> |
|
6 |
+ <view style="z-index:999;background-color:#fff;width:100%;height:100%;" wx:if="{{isLoading}}"></view> |
|
7 |
+ <view class="header"> |
|
8 |
+ <image class="banner-img" src="{{ kol.banner_url }}"></image> |
|
9 |
+ |
|
10 |
+ <view class="user-info"> |
|
11 |
+ <image class="avatar" src="{{ kol.avatar_url }}"></image> |
|
12 |
+ <text class="nickname">{{ kol.nickname }}</text> |
|
13 |
+ <view class="subscribe"> |
|
14 |
+ <text class="num">{{ kol.fans }}</text> |
|
15 |
+ <text class="label">粉丝</text> |
|
16 |
+ </view> |
|
17 |
+ </view> |
|
18 |
+ <view class="desc"> |
|
19 |
+ <text>{{ kol.intro }}</text> |
|
20 |
+ </view> |
|
21 |
+ </view> |
|
22 |
+ <view class="main"> |
|
23 |
+ <view class="commodity-container"> |
|
24 |
+ <view class="commodity-title-container"> |
|
25 |
+ <text class="title">{{ pack.title }}</text> |
|
26 |
+ <text class="expired">将于 {{ pack.expired_at }} 结束</text> |
|
27 |
+ </view> |
|
28 |
+ <view class="commodity-details"> |
|
29 |
+ <import src="/utils/wxParse/wxParse.wxml"></import> |
|
30 |
+ <template is="wxParse" data="{{wxParseData:article.nodes}}"></template> |
|
31 |
+ </view> |
|
32 |
+ <view class="commodity-list"> |
|
33 |
+ <block wx:for="{{ commodities }}" wx:key="good_id"> |
|
34 |
+ <view class="commodity-item"> |
|
35 |
+ <view class="commodity-left"> |
|
36 |
+ <image class="commodity-img" src="{{ item.image_url }}"></image> |
|
37 |
+ <view class="commodity-content"> |
|
38 |
+ <text class="commodity-title">{{ item.title }}</text> |
|
39 |
+ <text class="commodity-desc">{{ item.desc }}</text> |
|
40 |
+ <view class="commodity-price"> |
|
41 |
+ <text>¥{{ item.price }}</text> |
|
42 |
+ </view> |
|
43 |
+ </view> |
|
44 |
+ </view> |
|
45 |
+ <view class="commodity-right"> |
|
46 |
+ <text class="bought"wx:if="{{item.has_sale_num}}">已购 {{ item.has_sale_num }}</text> |
|
47 |
+ <view class="stepper-container"> |
|
48 |
+ <stepper data-index="{{ index }}" bindstepperChanged="bindstepperChanged"></stepper> |
|
49 |
+ </view> |
|
50 |
+ </view> |
|
51 |
+ </view> |
|
52 |
+ </block> |
|
53 |
+ </view> |
|
54 |
+ </view> |
|
55 |
+ <view class="consumer-container" wx:if="{{ consumers.length > 0 }}"> |
|
56 |
+ <swiper |
|
57 |
+ class="swiper-container" |
|
58 |
+ autoplay="{{ true }}" |
|
59 |
+ interval="2000" |
|
60 |
+ vertical="{{ true }}" |
|
61 |
+ circular="{{ true }}" |
|
62 |
+ > |
|
63 |
+ <block wx:for="{{ consumers }}"> |
|
64 |
+ <swiper-item class="consumer-item"> |
|
65 |
+ <view class="consumer-info"> |
|
66 |
+ <image class="avatar" src="{{ item.userinfo.avatar }}"></image> |
|
67 |
+ <text class="name">{{ item.userinfo.nickname }}</text> |
|
68 |
+ <text class="time">{{ item.created_at }}</text> |
|
69 |
+ </view> |
|
70 |
+ <view class="consumer-commodity"> |
|
71 |
+ <text>{{ item.content }}</text> |
|
72 |
+ </view> |
|
73 |
+ </swiper-item> |
|
74 |
+ </block> |
|
75 |
+ </swiper> |
|
76 |
+ </view> |
|
77 |
+ </view> |
|
78 |
+</scroll-view> |
|
79 |
+ |
|
80 |
+<import src="/template/btn/btn.wxml"></import> |
|
81 |
+<view class="btn-footer" wx:if="{{ total !== 0 }}"> |
|
82 |
+ <view class="btn-footer-container"> |
|
83 |
+ <view class="left"> |
|
84 |
+ <text class="money">¥{{ total }}</text> |
|
85 |
+ </view> |
|
86 |
+ <view class="right"> |
|
87 |
+ <template |
|
88 |
+ is="iconBtn" |
|
89 |
+ data="{{btnClass: 'button4', btnTxt: '购买', openType: 'getUserInfo', action: 'getUserInfo'}}" |
|
90 |
+ ></template> |
|
91 |
+ </view> |
|
92 |
+ </view> |
|
93 |
+</view> |
@@ -0,0 +1,255 @@ |
||
1 |
+@import '/template/footer/footer.wxss'; |
|
2 |
+@import '/template/btn/btn.wxss'; |
|
3 |
+@import '/utils/wxParse/wxParse.wxss'; |
|
4 |
+page { |
|
5 |
+ background-color: #efefef; |
|
6 |
+} |
|
7 |
+.wrap { |
|
8 |
+ box-sizing: border-box; |
|
9 |
+ display: flex; |
|
10 |
+ flex-direction: column; |
|
11 |
+ align-items: center; |
|
12 |
+ height: 100%; |
|
13 |
+ background-color: #efefef; |
|
14 |
+} |
|
15 |
+.header { |
|
16 |
+ position: relative; |
|
17 |
+ width: 100%; |
|
18 |
+} |
|
19 |
+.header .banner-img { |
|
20 |
+ position: absolute; |
|
21 |
+ width: 750rpx; |
|
22 |
+ height: 400rpx; |
|
23 |
+} |
|
24 |
+.header .user-info { |
|
25 |
+ position: relative; |
|
26 |
+ box-sizing: border-box; |
|
27 |
+ display: flex; |
|
28 |
+ align-items: flex-end; |
|
29 |
+ width: 750rpx; |
|
30 |
+ height: 200rpx; |
|
31 |
+ padding: 0 24rpx 24rpx; |
|
32 |
+ margin-top: 200rpx; |
|
33 |
+ background-image: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.8)); |
|
34 |
+} |
|
35 |
+.header .user-info .avatar { |
|
36 |
+ width: 100rpx; |
|
37 |
+ height: 100rpx; |
|
38 |
+ border-radius: 6px; |
|
39 |
+} |
|
40 |
+.header .user-info .nickname { |
|
41 |
+ margin: 0 0 12rpx 12rpx; |
|
42 |
+ font-size: 14pt; |
|
43 |
+ color: #fff; |
|
44 |
+} |
|
45 |
+.header .user-info .subscribe { |
|
46 |
+ display: flex; |
|
47 |
+ flex-grow: 2; |
|
48 |
+ align-items: center; |
|
49 |
+ justify-content: flex-end; |
|
50 |
+ margin: 0 0 12rpx 12rpx; |
|
51 |
+} |
|
52 |
+.header .user-info .subscribe .num { |
|
53 |
+ font-size: 13pt; |
|
54 |
+ font-weight: 600; |
|
55 |
+ color: #fff; |
|
56 |
+} |
|
57 |
+.header .user-info .subscribe .label { |
|
58 |
+ margin-left: 4rpx; |
|
59 |
+ font-size: 10pt; |
|
60 |
+ color: #cbcbcb; |
|
61 |
+} |
|
62 |
+.header .desc { |
|
63 |
+ margin-top: 36rpx; |
|
64 |
+ margin-bottom: 0rpx; |
|
65 |
+ margin-left: 24rpx; |
|
66 |
+} |
|
67 |
+.header .desc text { |
|
68 |
+ color: #959595; |
|
69 |
+} |
|
70 |
+.main { |
|
71 |
+ box-sizing: border-box; |
|
72 |
+ width: 702rpx; |
|
73 |
+ margin-top: 36rpx; |
|
74 |
+} |
|
75 |
+.commodity-container { |
|
76 |
+ display: flex; |
|
77 |
+ flex-direction: column; |
|
78 |
+ align-items: center; |
|
79 |
+ box-sizing: border-box; |
|
80 |
+ width: 100%; |
|
81 |
+ padding: 36rpx 24rpx; |
|
82 |
+ background-color: #fff; |
|
83 |
+} |
|
84 |
+.commodity-container .commodity-title-container { |
|
85 |
+ display: flex; |
|
86 |
+ flex-direction: column; |
|
87 |
+ width: 100%; |
|
88 |
+} |
|
89 |
+.commodity-container .commodity-title-container .title { |
|
90 |
+ font-size: 14pt; |
|
91 |
+ font-weight: 600; |
|
92 |
+ color: #000; |
|
93 |
+} |
|
94 |
+.commodity-container .commodity-title-container .expired { |
|
95 |
+ margin-top: 4rpx; |
|
96 |
+ font-size: 10pt; |
|
97 |
+ color: #959595; |
|
98 |
+} |
|
99 |
+.commodity-container .commodity-details { |
|
100 |
+ width: 100%; |
|
101 |
+ margin-top: 24rpx; |
|
102 |
+} |
|
103 |
+.commodity-container .commodity-list { |
|
104 |
+ display: flex; |
|
105 |
+ flex-direction: column; |
|
106 |
+ align-items: center; |
|
107 |
+ width: 100%; |
|
108 |
+ margin-top: 36rpx; |
|
109 |
+} |
|
110 |
+.commodity-container .commodity-list .commodity-item { |
|
111 |
+ display: flex; |
|
112 |
+ align-items: center; |
|
113 |
+ justify-content: space-between; |
|
114 |
+ width: 100%; |
|
115 |
+ height: 200rpx; |
|
116 |
+ padding: 24rpx 0; |
|
117 |
+ border-bottom: 1px #efefef solid; |
|
118 |
+} |
|
119 |
+.commodity-container .commodity-list .commodity-item .commodity-left { |
|
120 |
+ display: flex; |
|
121 |
+ align-items: center; |
|
122 |
+ height: 200rpx; |
|
123 |
+} |
|
124 |
+.commodity-container .commodity-list .commodity-item .commodity-left .commodity-img { |
|
125 |
+ width: 180rpx; |
|
126 |
+ height: 180rpx; |
|
127 |
+} |
|
128 |
+.commodity-container .commodity-list .commodity-item .commodity-left .commodity-content { |
|
129 |
+ display: flex; |
|
130 |
+ flex-direction: column; |
|
131 |
+ height: 100%; |
|
132 |
+ margin-left: 24rpx; |
|
133 |
+} |
|
134 |
+.commodity-container .commodity-list .commodity-item .commodity-left .commodity-content .commodity-title { |
|
135 |
+ font-size: 13pt; |
|
136 |
+ color: #3e3e3e; |
|
137 |
+} |
|
138 |
+.commodity-container .commodity-list .commodity-item .commodity-left .commodity-content .commodity-desc { |
|
139 |
+ margin-top: 4rpx; |
|
140 |
+ font-size: 10pt; |
|
141 |
+ color: #959595; |
|
142 |
+} |
|
143 |
+.commodity-container .commodity-list .commodity-item .commodity-price { |
|
144 |
+ display: flex; |
|
145 |
+ flex-grow: 2; |
|
146 |
+ align-items: flex-end; |
|
147 |
+} |
|
148 |
+.commodity-container .commodity-list .commodity-item .commodity-price text { |
|
149 |
+ font-size: 14pt; |
|
150 |
+ color: #e64340; |
|
151 |
+} |
|
152 |
+.commodity-container .commodity-list .commodity-right { |
|
153 |
+ display: flex; |
|
154 |
+ flex-direction: column; |
|
155 |
+ align-items: flex-end; |
|
156 |
+ height: 100%; |
|
157 |
+} |
|
158 |
+.commodity-container .commodity-list .commodity-right .bought { |
|
159 |
+ font-size: 10pt; |
|
160 |
+ color: #e64340; |
|
161 |
+ text-align: right; |
|
162 |
+} |
|
163 |
+.commodity-container .commodity-list .commodity-right .stepper-container { |
|
164 |
+ margin-top: 24rpx; |
|
165 |
+} |
|
166 |
+.consumer-container { |
|
167 |
+ padding: 24rpx; |
|
168 |
+ background-color: #fff; |
|
169 |
+} |
|
170 |
+.consumer-container .consumer-title { |
|
171 |
+ height: 80rpx; |
|
172 |
+} |
|
173 |
+.consumer-container .consumer-title text { |
|
174 |
+ font-size: 14pt; |
|
175 |
+ font-weight: 600; |
|
176 |
+ color: #3e3e3e; |
|
177 |
+} |
|
178 |
+.consumer-container .swiper-container { |
|
179 |
+ width: 100%; |
|
180 |
+ height: 200rpx; |
|
181 |
+} |
|
182 |
+.consumer-container .consumer-item { |
|
183 |
+ width: 654rpx; |
|
184 |
+} |
|
185 |
+.consumer-container .consumer-item .consumer-info { |
|
186 |
+ display: flex; |
|
187 |
+ align-items: center; |
|
188 |
+} |
|
189 |
+.consumer-container .consumer-item .consumer-info .avatar { |
|
190 |
+ width: 56rpx; |
|
191 |
+ height: 56rpx; |
|
192 |
+ border-radius: 28rpx; |
|
193 |
+} |
|
194 |
+.consumer-container .consumer-item .consumer-info .name { |
|
195 |
+ margin-left: 12rpx; |
|
196 |
+ font-size: 11pt; |
|
197 |
+ font-weight: 600; |
|
198 |
+ color: #000; |
|
199 |
+} |
|
200 |
+.consumer-container .consumer-item .consumer-info .time { |
|
201 |
+ margin-top: 4rpx; |
|
202 |
+ margin-left: 24rpx; |
|
203 |
+ font-size: 8pt; |
|
204 |
+ color: #c8c8c8; |
|
205 |
+} |
|
206 |
+.consumer-container .consumer-item .consumer-commodity { |
|
207 |
+ display: flex; |
|
208 |
+ justify-content: flex-end; |
|
209 |
+ width: 100%; |
|
210 |
+ margin-top: 12rpx; |
|
211 |
+} |
|
212 |
+.consumer-container .consumer-item .consumer-commodity text { |
|
213 |
+ width: 100%; |
|
214 |
+ font-size: 11pt; |
|
215 |
+ color: #3e3e3e; |
|
216 |
+ text-align: right; |
|
217 |
+} |
|
218 |
+.btn-footer { |
|
219 |
+ display: flex; |
|
220 |
+ align-items: center; |
|
221 |
+ position: fixed; |
|
222 |
+ bottom: 0; |
|
223 |
+ box-sizing: border-box; |
|
224 |
+ justify-content: center; |
|
225 |
+ width: 100%; |
|
226 |
+ height: 160rpx; |
|
227 |
+ padding: 24rpx; |
|
228 |
+ background-color: #fff; |
|
229 |
+ box-shadow: 0 -5px 9px 2px rgba(0, 0, 0, 0.1); |
|
230 |
+} |
|
231 |
+.btn-footer .btn-footer-container { |
|
232 |
+ display: flex; |
|
233 |
+ width: 100%; |
|
234 |
+ height: 100rpx; |
|
235 |
+ overflow: hidden; |
|
236 |
+ border: 1px #09bb07 solid; |
|
237 |
+ border-radius: 5px; |
|
238 |
+} |
|
239 |
+.btn-footer .btn-footer-container .left { |
|
240 |
+ display: flex; |
|
241 |
+ align-items: center; |
|
242 |
+ justify-content: center; |
|
243 |
+ width: 40%; |
|
244 |
+ height: 100rpx; |
|
245 |
+ background-color: #fff; |
|
246 |
+} |
|
247 |
+.btn-footer .btn-footer-container .left text { |
|
248 |
+ font-size: 14pt; |
|
249 |
+ font-weight: 700; |
|
250 |
+ color: #e64340; |
|
251 |
+} |
|
252 |
+.btn-footer .btn-footer-container .right { |
|
253 |
+ width: 100%; |
|
254 |
+ height: 100%; |
|
255 |
+} |
@@ -0,0 +1,85 @@ |
||
1 |
+const app = getApp() |
|
2 |
+ |
|
3 |
+Page({ |
|
4 |
+ /** |
|
5 |
+ * Page initial data |
|
6 |
+ */ |
|
7 |
+ data: { |
|
8 |
+ hasAddress: false, |
|
9 |
+ commodities: [], |
|
10 |
+ address: {}, |
|
11 |
+ kol: {}, |
|
12 |
+ pack_id: '', |
|
13 |
+ total: 0 |
|
14 |
+ }, |
|
15 |
+ |
|
16 |
+ onLoad() { |
|
17 |
+ const eventChannel = this.getOpenerEventChannel() |
|
18 |
+ const that = this |
|
19 |
+ eventChannel.on('acceptDataFromOpenerPage', data => { |
|
20 |
+ that.setData({ |
|
21 |
+ commodities: data.commodities, |
|
22 |
+ total: data.total, |
|
23 |
+ kol: data.kol, |
|
24 |
+ pack_id: data.pack_id |
|
25 |
+ }) |
|
26 |
+ }) |
|
27 |
+ }, |
|
28 |
+ |
|
29 |
+ navigateToAddress() { |
|
30 |
+ const that = this |
|
31 |
+ wx.chooseAddress({ |
|
32 |
+ success: res => { |
|
33 |
+ res.detailInfo = |
|
34 |
+ res.provinceName + res.cityName + res.countyName + res.detailInfo |
|
35 |
+ that.setData({ |
|
36 |
+ address: res, |
|
37 |
+ hasAddress: true |
|
38 |
+ }) |
|
39 |
+ } |
|
40 |
+ }) |
|
41 |
+ }, |
|
42 |
+ |
|
43 |
+ confirm() { |
|
44 |
+ const { commodities } = this.data |
|
45 |
+ // const body = commodities.reduce( |
|
46 |
+ // (accumulator, c) => `${accumulator}${c.title}x${c.num};`, |
|
47 |
+ // '' |
|
48 |
+ // ) |
|
49 |
+ console.log(body) |
|
50 |
+ app.network.post({ |
|
51 |
+ url: app.urls.ORDER_CREATE, |
|
52 |
+ data: { |
|
53 |
+ pack_id: this.data.pack_id, |
|
54 |
+ kol_id: this.data.kol.kol_id, |
|
55 |
+ total_fee: this.data.total * 100, |
|
56 |
+ goods_info: JSON.stringify(this.data.commodities), |
|
57 |
+ name: this.data.address.userName || '', |
|
58 |
+ phone: this.data.address.telNumber || '', |
|
59 |
+ address: this.data.address.detailInfo || '', |
|
60 |
+ body: '尖货接龙' |
|
61 |
+ }, |
|
62 |
+ success(res1) { |
|
63 |
+ const { wxpay_params } = res1.data |
|
64 |
+ wx.requestPayment({ |
|
65 |
+ timeStamp: wxpay_params.timeStamp, |
|
66 |
+ nonceStr: wxpay_params.nonceStr, |
|
67 |
+ package: wxpay_params.package, |
|
68 |
+ signType: wxpay_params.signType, |
|
69 |
+ paySign: wxpay_params.paySign, |
|
70 |
+ success: res2 => { |
|
71 |
+ wx.reLaunch({ |
|
72 |
+ url: '/pages/index/index', |
|
73 |
+ success() { |
|
74 |
+ wx.showToast({ |
|
75 |
+ title: '购买成功', |
|
76 |
+ icon: 'success' |
|
77 |
+ }) |
|
78 |
+ } |
|
79 |
+ }) |
|
80 |
+ } |
|
81 |
+ }) |
|
82 |
+ } |
|
83 |
+ }) |
|
84 |
+ } |
|
85 |
+}) |
@@ -0,0 +1,5 @@ |
||
1 |
+{ |
|
2 |
+ "usingComponents": {}, |
|
3 |
+ "disableScroll": true, |
|
4 |
+ "navigationBarTitleText": "订单确认" |
|
5 |
+} |
@@ -0,0 +1,204 @@ |
||
1 |
+@import './src/style/less/variable.less'; |
|
2 |
+@import './src/style/less/layout.less'; |
|
3 |
+@import './src/style/less/shape.less'; |
|
4 |
+@import '/template/footer/footer.wxss'; |
|
5 |
+@import '/template/btn/btn.wxss'; |
|
6 |
+ |
|
7 |
+.order-view { |
|
8 |
+ .flex-center(column); |
|
9 |
+ .with-btnFooter(); |
|
10 |
+ |
|
11 |
+ width: 100%; |
|
12 |
+ background-color: @color-bg; |
|
13 |
+ |
|
14 |
+ text { |
|
15 |
+ color: @color-black; |
|
16 |
+ } |
|
17 |
+ |
|
18 |
+ view { |
|
19 |
+ color: @color-black; |
|
20 |
+ } |
|
21 |
+} |
|
22 |
+ |
|
23 |
+.address { |
|
24 |
+ .flex-center(row); |
|
25 |
+ |
|
26 |
+ box-sizing: border-box; |
|
27 |
+ width: @visual-width; |
|
28 |
+ min-height: 80rpx; |
|
29 |
+ padding: 0 @spacing-item; |
|
30 |
+ margin: @spacing-item; |
|
31 |
+ background-color: @color-white; |
|
32 |
+ border-radius: @radius; |
|
33 |
+ |
|
34 |
+ .item() { |
|
35 |
+ .square(40rpx); |
|
36 |
+ |
|
37 |
+ .icon { |
|
38 |
+ .full-image(); |
|
39 |
+ } |
|
40 |
+ } |
|
41 |
+ |
|
42 |
+ .left { |
|
43 |
+ .item(); |
|
44 |
+ } |
|
45 |
+ |
|
46 |
+ .content { |
|
47 |
+ .flex-center(column); |
|
48 |
+ |
|
49 |
+ box-sizing: border-box; |
|
50 |
+ width: @visual-width - 80rpx - @spacing-item * 2; |
|
51 |
+ min-height: 80rpx; |
|
52 |
+ padding: @spacing-inline @spacing-item; |
|
53 |
+ |
|
54 |
+ view { |
|
55 |
+ .flex-center(row); |
|
56 |
+ |
|
57 |
+ width: 100%; |
|
58 |
+ margin-top: @spacing-inline; |
|
59 |
+ } |
|
60 |
+ |
|
61 |
+ .top { |
|
62 |
+ justify-content: flex-start; |
|
63 |
+ |
|
64 |
+ .name { |
|
65 |
+ font-size: @font-primary; |
|
66 |
+ } |
|
67 |
+ |
|
68 |
+ .phone { |
|
69 |
+ margin-left: @spacing-item; |
|
70 |
+ font-size: @font-quaternary; |
|
71 |
+ color: @color-gray; |
|
72 |
+ } |
|
73 |
+ } |
|
74 |
+ |
|
75 |
+ .bottom { |
|
76 |
+ font-size: @font-tertiary; |
|
77 |
+ } |
|
78 |
+ } |
|
79 |
+ |
|
80 |
+ .right { |
|
81 |
+ .item(); |
|
82 |
+ |
|
83 |
+ .arrow { |
|
84 |
+ .arrow(right; @color-dark-bg; @icon-small-size); |
|
85 |
+ } |
|
86 |
+ } |
|
87 |
+ |
|
88 |
+ &-hover { |
|
89 |
+ background-color: darken(@color-white, 15%); |
|
90 |
+ } |
|
91 |
+} |
|
92 |
+ |
|
93 |
+.authorization { |
|
94 |
+ justify-content: center; |
|
95 |
+ |
|
96 |
+ text { |
|
97 |
+ margin-left: @spacing-short-text; |
|
98 |
+ font-size: @font-secondary; |
|
99 |
+ color: @color-brand; |
|
100 |
+ } |
|
101 |
+ |
|
102 |
+ .plus { |
|
103 |
+ .plus(4rpx; @color-brand); |
|
104 |
+ .square(@icon-little-small-size); |
|
105 |
+ } |
|
106 |
+} |
|
107 |
+ |
|
108 |
+.goods { |
|
109 |
+ .flex-center(row); |
|
110 |
+ |
|
111 |
+ width: @visual-width; |
|
112 |
+ height: 200rpx; |
|
113 |
+ margin-top: @spacing-inline; |
|
114 |
+ background-color: @color-white; |
|
115 |
+ border-radius: @radius; |
|
116 |
+ |
|
117 |
+ .left { |
|
118 |
+ .flex-center(row); |
|
119 |
+ |
|
120 |
+ justify-content: center; |
|
121 |
+ width: 200rpx; |
|
122 |
+ height: 100%; |
|
123 |
+ |
|
124 |
+ image { |
|
125 |
+ .square(180rpx); |
|
126 |
+ } |
|
127 |
+ } |
|
128 |
+ |
|
129 |
+ .right { |
|
130 |
+ box-sizing: border-box; |
|
131 |
+ display: flex; |
|
132 |
+ flex-direction: column; |
|
133 |
+ justify-content: space-between; |
|
134 |
+ width: @visual-width - 200rpx; |
|
135 |
+ height: 100%; |
|
136 |
+ padding: @spacing-item; |
|
137 |
+ |
|
138 |
+ .top { |
|
139 |
+ width: 100%; |
|
140 |
+ |
|
141 |
+ .title { |
|
142 |
+ font-size: @font-primary; |
|
143 |
+ } |
|
144 |
+ } |
|
145 |
+ |
|
146 |
+ .bottom { |
|
147 |
+ .flex-center(row); |
|
148 |
+ |
|
149 |
+ justify-content: space-between; |
|
150 |
+ width: 100%; |
|
151 |
+ |
|
152 |
+ .num { |
|
153 |
+ font-size: @font-primary; |
|
154 |
+ } |
|
155 |
+ } |
|
156 |
+ } |
|
157 |
+} |
|
158 |
+ |
|
159 |
+.btn-footer { |
|
160 |
+ .flex-center(row); |
|
161 |
+ |
|
162 |
+ position: fixed; |
|
163 |
+ bottom: 0; |
|
164 |
+ box-sizing: border-box; |
|
165 |
+ justify-content: center; |
|
166 |
+ width: 100%; |
|
167 |
+ height: @btnFooter-height; |
|
168 |
+ padding: @spacing-item; |
|
169 |
+ background-color: @color-white; |
|
170 |
+ box-shadow: 0 -5px 9px 2px fade(@color-black, 10%); |
|
171 |
+ |
|
172 |
+ .btn-footer-container { |
|
173 |
+ display: flex; |
|
174 |
+ width: 100%; |
|
175 |
+ height: 100rpx; |
|
176 |
+ overflow: hidden; |
|
177 |
+ border: 1px #09bb07 solid; |
|
178 |
+ border-radius: @radius; |
|
179 |
+ |
|
180 |
+ &-disabled { |
|
181 |
+ border: 1px @color-light-gray solid !important; |
|
182 |
+ } |
|
183 |
+ |
|
184 |
+ .left { |
|
185 |
+ .flex-center(row); |
|
186 |
+ |
|
187 |
+ justify-content: center; |
|
188 |
+ width: 40%; |
|
189 |
+ height: 100rpx; |
|
190 |
+ background-color: @color-white; |
|
191 |
+ |
|
192 |
+ text { |
|
193 |
+ font-size: @font-primary; |
|
194 |
+ font-weight: 700; |
|
195 |
+ color: #e64340; |
|
196 |
+ } |
|
197 |
+ } |
|
198 |
+ |
|
199 |
+ .right { |
|
200 |
+ width: 100%; |
|
201 |
+ height: 100%; |
|
202 |
+ } |
|
203 |
+ } |
|
204 |
+} |
@@ -0,0 +1,64 @@ |
||
1 |
+<view class="order-view"> |
|
2 |
+ <view |
|
3 |
+ class="address" |
|
4 |
+ hover-class="address-hover" |
|
5 |
+ bindtap="navigateToAddress" |
|
6 |
+ wx:if="{{ hasAddress }}" |
|
7 |
+ > |
|
8 |
+ <view class="left"> |
|
9 |
+ <image class="icon" src="/resources/common/location.png"></image> |
|
10 |
+ </view> |
|
11 |
+ <view class="content"> |
|
12 |
+ <view class="top"> |
|
13 |
+ <text class="name">{{ address.userName }}</text> |
|
14 |
+ <text class="phone">{{ address.telNumber }}</text> |
|
15 |
+ </view> |
|
16 |
+ <view class="bottom">{{ address.detailInfo }}</view> |
|
17 |
+ </view> |
|
18 |
+ <view class="right"> |
|
19 |
+ <view class="icon arrow"></view> |
|
20 |
+ </view> |
|
21 |
+ </view> |
|
22 |
+ <view |
|
23 |
+ class="address authorization" |
|
24 |
+ hover-class="address-hover" |
|
25 |
+ bindtap="navigateToAddress" |
|
26 |
+ wx:elif="{{ !hasAddress }}" |
|
27 |
+ > |
|
28 |
+ <view class="plus"></view> |
|
29 |
+ <text>新建地址</text> |
|
30 |
+ </view> |
|
31 |
+ <view class="goods-container"> |
|
32 |
+ <block wx:for="{{ commodities }}"> |
|
33 |
+ <view class="goods"> |
|
34 |
+ <view class="left"> |
|
35 |
+ <image class="" src="{{ item.image_url }}" mode="aspectFit"></image> |
|
36 |
+ </view> |
|
37 |
+ <view class="right"> |
|
38 |
+ <view class="top"> |
|
39 |
+ <text class="title">{{ item.title }}</text> |
|
40 |
+ </view> |
|
41 |
+ <view class="bottom"> |
|
42 |
+ <text class="integral" wx:if="{{ item.price > 0 }}">¥{{ item.price }}</text> |
|
43 |
+ <text class="num">x{{ item.num }}</text> |
|
44 |
+ </view> |
|
45 |
+ </view> |
|
46 |
+ </view> |
|
47 |
+ </block> |
|
48 |
+ </view> |
|
49 |
+</view> |
|
50 |
+ |
|
51 |
+<import src="/template/btn/btn.wxml"></import> |
|
52 |
+<view class="btn-footer"> |
|
53 |
+ <view class="btn-footer-container {{hasAddress ? '' : 'btn-footer-container-disabled'}}"> |
|
54 |
+ <view class="left" wx:if="{{ total > 0 }}"> |
|
55 |
+ <text class="money">¥{{ total }}</text> |
|
56 |
+ </view> |
|
57 |
+ <view class="right"> |
|
58 |
+ <template |
|
59 |
+ is="iconBtn" |
|
60 |
+ data="{{btnClass: 'button4', btnTxt: '立即支付', disabled: !hasAddress, action: 'confirm'}}" |
|
61 |
+ ></template> |
|
62 |
+ </view> |
|
63 |
+ </view> |
|
64 |
+</view> |
@@ -0,0 +1,201 @@ |
||
1 |
+@import '/template/footer/footer.wxss'; |
|
2 |
+@import '/template/btn/btn.wxss'; |
|
3 |
+.order-view { |
|
4 |
+ display: flex; |
|
5 |
+ flex-direction: column; |
|
6 |
+ align-items: center; |
|
7 |
+ height: calc(100% - 160rpx); |
|
8 |
+ width: 100%; |
|
9 |
+ background-color: #efefef; |
|
10 |
+} |
|
11 |
+.order-view text { |
|
12 |
+ color: #000; |
|
13 |
+} |
|
14 |
+.order-view view { |
|
15 |
+ color: #000; |
|
16 |
+} |
|
17 |
+.address { |
|
18 |
+ display: flex; |
|
19 |
+ align-items: center; |
|
20 |
+ box-sizing: border-box; |
|
21 |
+ width: 702rpx; |
|
22 |
+ min-height: 80rpx; |
|
23 |
+ padding: 0 24rpx; |
|
24 |
+ margin: 24rpx; |
|
25 |
+ background-color: #fff; |
|
26 |
+ border-radius: 5px; |
|
27 |
+} |
|
28 |
+.address .left { |
|
29 |
+ width: 40rpx; |
|
30 |
+ height: 40rpx; |
|
31 |
+} |
|
32 |
+.address .left .icon { |
|
33 |
+ width: 100%; |
|
34 |
+ height: 100%; |
|
35 |
+} |
|
36 |
+.address .content { |
|
37 |
+ display: flex; |
|
38 |
+ flex-direction: column; |
|
39 |
+ align-items: center; |
|
40 |
+ box-sizing: border-box; |
|
41 |
+ width: 574rpx; |
|
42 |
+ min-height: 80rpx; |
|
43 |
+ padding: 12rpx 24rpx; |
|
44 |
+} |
|
45 |
+.address .content view { |
|
46 |
+ display: flex; |
|
47 |
+ align-items: center; |
|
48 |
+ width: 100%; |
|
49 |
+ margin-top: 12rpx; |
|
50 |
+} |
|
51 |
+.address .content .top { |
|
52 |
+ justify-content: flex-start; |
|
53 |
+} |
|
54 |
+.address .content .top .name { |
|
55 |
+ font-size: 14pt; |
|
56 |
+} |
|
57 |
+.address .content .top .phone { |
|
58 |
+ margin-left: 24rpx; |
|
59 |
+ font-size: 10pt; |
|
60 |
+ color: #3e3e3e; |
|
61 |
+} |
|
62 |
+.address .content .bottom { |
|
63 |
+ font-size: 11pt; |
|
64 |
+} |
|
65 |
+.address .right { |
|
66 |
+ width: 40rpx; |
|
67 |
+ height: 40rpx; |
|
68 |
+} |
|
69 |
+.address .right .icon { |
|
70 |
+ width: 100%; |
|
71 |
+ height: 100%; |
|
72 |
+} |
|
73 |
+.address .right .arrow { |
|
74 |
+ width: 32rpx; |
|
75 |
+ height: 32rpx; |
|
76 |
+ box-sizing: border-box; |
|
77 |
+ border-top: 2px solid #3e3e3e; |
|
78 |
+ border-right: 2px solid #3e3e3e; |
|
79 |
+ transform: rotate(45deg); |
|
80 |
+} |
|
81 |
+.address-hover { |
|
82 |
+ background-color: #d9d9d9; |
|
83 |
+} |
|
84 |
+.authorization { |
|
85 |
+ justify-content: center; |
|
86 |
+} |
|
87 |
+.authorization text { |
|
88 |
+ margin-left: 4rpx; |
|
89 |
+ font-size: 13pt; |
|
90 |
+ color: #0967b2; |
|
91 |
+} |
|
92 |
+.authorization .plus { |
|
93 |
+ position: relative; |
|
94 |
+ width: 24rpx; |
|
95 |
+ height: 24rpx; |
|
96 |
+} |
|
97 |
+.authorization .plus::before { |
|
98 |
+ position: absolute; |
|
99 |
+ top: calc(50% - 4rpx / 2); |
|
100 |
+ left: 0; |
|
101 |
+ width: 100%; |
|
102 |
+ height: 4rpx; |
|
103 |
+ content: ''; |
|
104 |
+ background-color: #0967b2; |
|
105 |
+ border-radius: 4rpx; |
|
106 |
+} |
|
107 |
+.authorization .plus::after { |
|
108 |
+ position: absolute; |
|
109 |
+ top: 0; |
|
110 |
+ left: calc(50% - 4rpx / 2); |
|
111 |
+ width: 4rpx; |
|
112 |
+ height: 100%; |
|
113 |
+ content: ''; |
|
114 |
+ background-color: #0967b2; |
|
115 |
+ border-radius: 4rpx; |
|
116 |
+} |
|
117 |
+.goods { |
|
118 |
+ display: flex; |
|
119 |
+ align-items: center; |
|
120 |
+ width: 702rpx; |
|
121 |
+ height: 200rpx; |
|
122 |
+ margin-top: 12rpx; |
|
123 |
+ background-color: #fff; |
|
124 |
+ border-radius: 5px; |
|
125 |
+} |
|
126 |
+.goods .left { |
|
127 |
+ display: flex; |
|
128 |
+ align-items: center; |
|
129 |
+ justify-content: center; |
|
130 |
+ width: 200rpx; |
|
131 |
+ height: 100%; |
|
132 |
+} |
|
133 |
+.goods .left image { |
|
134 |
+ width: 180rpx; |
|
135 |
+ height: 180rpx; |
|
136 |
+} |
|
137 |
+.goods .right { |
|
138 |
+ box-sizing: border-box; |
|
139 |
+ display: flex; |
|
140 |
+ flex-direction: column; |
|
141 |
+ justify-content: space-between; |
|
142 |
+ width: 502rpx; |
|
143 |
+ height: 100%; |
|
144 |
+ padding: 24rpx; |
|
145 |
+} |
|
146 |
+.goods .right .top { |
|
147 |
+ width: 100%; |
|
148 |
+} |
|
149 |
+.goods .right .top .title { |
|
150 |
+ font-size: 14pt; |
|
151 |
+} |
|
152 |
+.goods .right .bottom { |
|
153 |
+ display: flex; |
|
154 |
+ align-items: center; |
|
155 |
+ justify-content: space-between; |
|
156 |
+ width: 100%; |
|
157 |
+} |
|
158 |
+.goods .right .bottom .num { |
|
159 |
+ font-size: 14pt; |
|
160 |
+} |
|
161 |
+.btn-footer { |
|
162 |
+ display: flex; |
|
163 |
+ align-items: center; |
|
164 |
+ position: fixed; |
|
165 |
+ bottom: 0; |
|
166 |
+ box-sizing: border-box; |
|
167 |
+ justify-content: center; |
|
168 |
+ width: 100%; |
|
169 |
+ height: 160rpx; |
|
170 |
+ padding: 24rpx; |
|
171 |
+ background-color: #fff; |
|
172 |
+ box-shadow: 0 -5px 9px 2px rgba(0, 0, 0, 0.1); |
|
173 |
+} |
|
174 |
+.btn-footer .btn-footer-container { |
|
175 |
+ display: flex; |
|
176 |
+ width: 100%; |
|
177 |
+ height: 100rpx; |
|
178 |
+ overflow: hidden; |
|
179 |
+ border: 1px #09bb07 solid; |
|
180 |
+ border-radius: 5px; |
|
181 |
+} |
|
182 |
+.btn-footer .btn-footer-container-disabled { |
|
183 |
+ border: 1px #959595 solid !important; |
|
184 |
+} |
|
185 |
+.btn-footer .btn-footer-container .left { |
|
186 |
+ display: flex; |
|
187 |
+ align-items: center; |
|
188 |
+ justify-content: center; |
|
189 |
+ width: 40%; |
|
190 |
+ height: 100rpx; |
|
191 |
+ background-color: #fff; |
|
192 |
+} |
|
193 |
+.btn-footer .btn-footer-container .left text { |
|
194 |
+ font-size: 14pt; |
|
195 |
+ font-weight: 700; |
|
196 |
+ color: #e64340; |
|
197 |
+} |
|
198 |
+.btn-footer .btn-footer-container .right { |
|
199 |
+ width: 100%; |
|
200 |
+ height: 100%; |
|
201 |
+} |
@@ -0,0 +1,126 @@ |
||
1 |
+{ |
|
2 |
+ "description": "项目配置文件。", |
|
3 |
+ "setting": { |
|
4 |
+ "urlCheck": true, |
|
5 |
+ "es6": true, |
|
6 |
+ "enhance": true, |
|
7 |
+ "postcss": true, |
|
8 |
+ "minified": false, |
|
9 |
+ "newFeature": true, |
|
10 |
+ "coverView": true, |
|
11 |
+ "nodeModules": true, |
|
12 |
+ "autoAudits": false, |
|
13 |
+ "showShadowRootInWxmlPanel": true, |
|
14 |
+ "scopeDataCheck": false, |
|
15 |
+ "checkInvalidKey": true, |
|
16 |
+ "checkSiteMap": false, |
|
17 |
+ "uploadWithSourceMap": true, |
|
18 |
+ "babelSetting": { |
|
19 |
+ "ignore": [], |
|
20 |
+ "disablePlugins": [], |
|
21 |
+ "outputPath": "" |
|
22 |
+ } |
|
23 |
+ }, |
|
24 |
+ "compileType": "miniprogram", |
|
25 |
+ "libVersion": "2.10.1", |
|
26 |
+ "appid": "wx82344118083f47c8", |
|
27 |
+ "projectname": "%E7%BB%9F%E8%A7%88", |
|
28 |
+ "scripts": { |
|
29 |
+ "beforeCompile": "", |
|
30 |
+ "beforePreview": "", |
|
31 |
+ "beforeUpload": "" |
|
32 |
+ }, |
|
33 |
+ "simulatorType": "wechat", |
|
34 |
+ "simulatorPluginLibVersion": {}, |
|
35 |
+ "condition": { |
|
36 |
+ "search": { |
|
37 |
+ "current": -1, |
|
38 |
+ "list": [] |
|
39 |
+ }, |
|
40 |
+ "conversation": { |
|
41 |
+ "current": -1, |
|
42 |
+ "list": [] |
|
43 |
+ }, |
|
44 |
+ "plugin": { |
|
45 |
+ "current": -1, |
|
46 |
+ "list": [] |
|
47 |
+ }, |
|
48 |
+ "game": { |
|
49 |
+ "current": -1, |
|
50 |
+ "list": [] |
|
51 |
+ }, |
|
52 |
+ "gamePlugin": { |
|
53 |
+ "current": -1, |
|
54 |
+ "list": [] |
|
55 |
+ }, |
|
56 |
+ "miniprogram": { |
|
57 |
+ "current": -1, |
|
58 |
+ "list": [ |
|
59 |
+ { |
|
60 |
+ "id": 0, |
|
61 |
+ "name": "pages/cameraCompatible/cameraCompatible", |
|
62 |
+ "pathName": "pages/cameraCompatible/cameraCompatible", |
|
63 |
+ "query": "activity_id=nBJ56hN9ik94js4duSh34V&isSignIn=1", |
|
64 |
+ "scene": 1047 |
|
65 |
+ }, |
|
66 |
+ { |
|
67 |
+ "id": 1, |
|
68 |
+ "name": "pages/index/index", |
|
69 |
+ "pathName": "pages/index/index", |
|
70 |
+ "query": "q=http://kodo.tamron.cn/v/0+21+KUjsUKURRRRRRUK6KxxK", |
|
71 |
+ "scene": 1011 |
|
72 |
+ }, |
|
73 |
+ { |
|
74 |
+ "id": 5, |
|
75 |
+ "name": "公众号菜单栏", |
|
76 |
+ "pathName": "pages/index/index", |
|
77 |
+ "query": "page=memberCard", |
|
78 |
+ "scene": 1035, |
|
79 |
+ "referrerInfo": {} |
|
80 |
+ }, |
|
81 |
+ { |
|
82 |
+ "id": 3, |
|
83 |
+ "name": "一物一码", |
|
84 |
+ "pathName": "pages/index/index", |
|
85 |
+ "query": "code_ticket=P.URL.CN/0MX5D3AIAJZ2:PW3RPK", |
|
86 |
+ "scene": 1124 |
|
87 |
+ }, |
|
88 |
+ { |
|
89 |
+ "id": 4, |
|
90 |
+ "name": "开卡", |
|
91 |
+ "pathName": "pages/index/index", |
|
92 |
+ "query": "openCard=1", |
|
93 |
+ "scene": 1074 |
|
94 |
+ }, |
|
95 |
+ { |
|
96 |
+ "id": 5, |
|
97 |
+ "name": "会员活动详情页", |
|
98 |
+ "pathName": "pages/member/activity/activity", |
|
99 |
+ "query": "activity_id=KNFYGrDrBGe4MzVw9wNpxL", |
|
100 |
+ "scene": null |
|
101 |
+ }, |
|
102 |
+ { |
|
103 |
+ "id": 6, |
|
104 |
+ "name": "测试", |
|
105 |
+ "pathName": "pages/index/index", |
|
106 |
+ "query": "q= http://kodo.tamron.cn/v/0+20+KUscUKUwwKzzxUxRRKRs33RCV5ODKVQZ7CHBK4F75Q7PHSJWLFEO1RJ9DQHZYEIQX1Q2DH30", |
|
107 |
+ "scene": 1011 |
|
108 |
+ }, |
|
109 |
+ { |
|
110 |
+ "id": -1, |
|
111 |
+ "name": "template/resultView/resultView", |
|
112 |
+ "pathName": "template/resultView/resultView", |
|
113 |
+ "query": "q= http%3A%2F%2Fkodo.tamron.cn%2Fv%2F0%2B21%2BKUKy6UKURw6jjyUK6KxKyTKTA9LLUFW13BDY2HD3B1ODC74EIPI14UTE0LHFDDV3G7QY3QTX", |
|
114 |
+ "scene": null |
|
115 |
+ }, |
|
116 |
+ { |
|
117 |
+ "id": -1, |
|
118 |
+ "name": "pages/commodity/commodity", |
|
119 |
+ "pathName": "pages/commodity/commodity", |
|
120 |
+ "query": "", |
|
121 |
+ "scene": null |
|
122 |
+ } |
|
123 |
+ ] |
|
124 |
+ } |
|
125 |
+ } |
|
126 |
+} |
@@ -0,0 +1,9 @@ |
||
1 |
+{ |
|
2 |
+ "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html", |
|
3 |
+ "rules": [ |
|
4 |
+ { |
|
5 |
+ "action": "allow", |
|
6 |
+ "page": "*" |
|
7 |
+ } |
|
8 |
+ ] |
|
9 |
+} |
@@ -0,0 +1,96 @@ |
||
1 |
+@import './less/variable.less'; |
|
2 |
+ |
|
3 |
+.button1 { |
|
4 |
+ padding: 0; |
|
5 |
+ background-color: @color-brand; |
|
6 |
+ border-radius: @radius; |
|
7 |
+ |
|
8 |
+ &-hover { |
|
9 |
+ color: shade(@color-white, 10%) !important; |
|
10 |
+ background-color: darken(@color-brand, 5%) !important; |
|
11 |
+ |
|
12 |
+ text { |
|
13 |
+ color: shade(@color-white, 10%) !important; |
|
14 |
+ } |
|
15 |
+ } |
|
16 |
+ |
|
17 |
+ &[disabled] { |
|
18 |
+ color: fade(@color-white, 60%) !important; |
|
19 |
+ background-color: fade(@color-brand, 60%) !important; |
|
20 |
+ |
|
21 |
+ text { |
|
22 |
+ color: fade(@color-white, 60%) !important; |
|
23 |
+ } |
|
24 |
+ } |
|
25 |
+} |
|
26 |
+ |
|
27 |
+.button3 { |
|
28 |
+ padding: 0; |
|
29 |
+ background-color: @color-other1; |
|
30 |
+ |
|
31 |
+ &-hover { |
|
32 |
+ color: shade(@color-white, 10%) !important; |
|
33 |
+ background-color: darken(@color-other1, 8%) !important; |
|
34 |
+ |
|
35 |
+ text { |
|
36 |
+ color: shade(@color-white, 10%) !important; |
|
37 |
+ } |
|
38 |
+ } |
|
39 |
+ |
|
40 |
+ &[disabled] { |
|
41 |
+ color: fade(@color-white, 60%) !important; |
|
42 |
+ background-color: fade(@color-other1, 60%) !important; |
|
43 |
+ |
|
44 |
+ text { |
|
45 |
+ color: fade(@color-white, 60%) !important; |
|
46 |
+ } |
|
47 |
+ } |
|
48 |
+} |
|
49 |
+ |
|
50 |
+.button2 { |
|
51 |
+ padding: 0; |
|
52 |
+ background-color: @color-brand; |
|
53 |
+ border-radius: @radius; |
|
54 |
+ |
|
55 |
+ text { |
|
56 |
+ color: @color-white; |
|
57 |
+ } |
|
58 |
+ |
|
59 |
+ &-hover { |
|
60 |
+ color: shade(@color-white, 10%) !important; |
|
61 |
+ background-color: darken(@color-brand, 5%) !important; |
|
62 |
+ |
|
63 |
+ text { |
|
64 |
+ color: shade(@color-white, 10%) !important; |
|
65 |
+ } |
|
66 |
+ } |
|
67 |
+ |
|
68 |
+ &[disabled] { |
|
69 |
+ color: darken(@color-white, 10%) !important; |
|
70 |
+ background-color: @color-light-gray !important; |
|
71 |
+ } |
|
72 |
+} |
|
73 |
+ |
|
74 |
+.button4 { |
|
75 |
+ height: 100%; |
|
76 |
+ padding: 0; |
|
77 |
+ background-color: #09bb07; |
|
78 |
+ |
|
79 |
+ text { |
|
80 |
+ color: @color-white; |
|
81 |
+ } |
|
82 |
+ |
|
83 |
+ &-hover { |
|
84 |
+ color: shade(@color-white, 10%) !important; |
|
85 |
+ background-color: darken(#09bb07, 5%) !important; |
|
86 |
+ |
|
87 |
+ text { |
|
88 |
+ color: shade(@color-white, 10%) !important; |
|
89 |
+ } |
|
90 |
+ } |
|
91 |
+ |
|
92 |
+ &[disabled] { |
|
93 |
+ color: darken(@color-white, 10%) !important; |
|
94 |
+ background-color: @color-light-gray !important; |
|
95 |
+ } |
|
96 |
+} |
@@ -0,0 +1,75 @@ |
||
1 |
+.button1 { |
|
2 |
+ padding: 0; |
|
3 |
+ background-color: #0967b2; |
|
4 |
+ border-radius: 5px; |
|
5 |
+} |
|
6 |
+.button1-hover { |
|
7 |
+ color: #e6e6e6 !important; |
|
8 |
+ background-color: #08599a !important; |
|
9 |
+} |
|
10 |
+.button1-hover text { |
|
11 |
+ color: #e6e6e6 !important; |
|
12 |
+} |
|
13 |
+.button1[disabled] { |
|
14 |
+ color: rgba(255, 255, 255, 0.6) !important; |
|
15 |
+ background-color: rgba(9, 103, 178, 0.6) !important; |
|
16 |
+} |
|
17 |
+.button1[disabled] text { |
|
18 |
+ color: rgba(255, 255, 255, 0.6) !important; |
|
19 |
+} |
|
20 |
+.button3 { |
|
21 |
+ padding: 0; |
|
22 |
+ background-color: #d2b167; |
|
23 |
+} |
|
24 |
+.button3-hover { |
|
25 |
+ color: #e6e6e6 !important; |
|
26 |
+ background-color: #c9a148 !important; |
|
27 |
+} |
|
28 |
+.button3-hover text { |
|
29 |
+ color: #e6e6e6 !important; |
|
30 |
+} |
|
31 |
+.button3[disabled] { |
|
32 |
+ color: rgba(255, 255, 255, 0.6) !important; |
|
33 |
+ background-color: rgba(210, 177, 103, 0.6) !important; |
|
34 |
+} |
|
35 |
+.button3[disabled] text { |
|
36 |
+ color: rgba(255, 255, 255, 0.6) !important; |
|
37 |
+} |
|
38 |
+.button2 { |
|
39 |
+ padding: 0; |
|
40 |
+ background-color: #0967b2; |
|
41 |
+ border-radius: 5px; |
|
42 |
+} |
|
43 |
+.button2 text { |
|
44 |
+ color: #fff; |
|
45 |
+} |
|
46 |
+.button2-hover { |
|
47 |
+ color: #e6e6e6 !important; |
|
48 |
+ background-color: #08599a !important; |
|
49 |
+} |
|
50 |
+.button2-hover text { |
|
51 |
+ color: #e6e6e6 !important; |
|
52 |
+} |
|
53 |
+.button2[disabled] { |
|
54 |
+ color: #e6e6e6 !important; |
|
55 |
+ background-color: #959595 !important; |
|
56 |
+} |
|
57 |
+.button4 { |
|
58 |
+ height: 100%; |
|
59 |
+ padding: 0; |
|
60 |
+ background-color: #09bb07; |
|
61 |
+} |
|
62 |
+.button4 text { |
|
63 |
+ color: #fff; |
|
64 |
+} |
|
65 |
+.button4-hover { |
|
66 |
+ color: #e6e6e6 !important; |
|
67 |
+ background-color: #08a206 !important; |
|
68 |
+} |
|
69 |
+.button4-hover text { |
|
70 |
+ color: #e6e6e6 !important; |
|
71 |
+} |
|
72 |
+.button4[disabled] { |
|
73 |
+ color: #e6e6e6 !important; |
|
74 |
+ background-color: #959595 !important; |
|
75 |
+} |
@@ -0,0 +1,85 @@ |
||
1 |
+@import './variable.less'; |
|
2 |
+ |
|
3 |
+// flex |
|
4 |
+.flex-center(column) { |
|
5 |
+ display: flex; |
|
6 |
+ flex-direction: column; |
|
7 |
+ align-items: center; |
|
8 |
+} |
|
9 |
+ |
|
10 |
+.flex-center(row) { |
|
11 |
+ display: flex; |
|
12 |
+ align-items: center; |
|
13 |
+} |
|
14 |
+ |
|
15 |
+.banner(@height: 400rpx) { |
|
16 |
+ width: 100%; |
|
17 |
+ height: @height; |
|
18 |
+ |
|
19 |
+ image { |
|
20 |
+ .full-image(); |
|
21 |
+ } |
|
22 |
+} |
|
23 |
+ |
|
24 |
+// list |
|
25 |
+.table-view(@width: 100%; @spacing: 12rpx) { |
|
26 |
+ .flex-center(column); |
|
27 |
+ |
|
28 |
+ width: 100%; |
|
29 |
+ padding-bottom: @spacing * 2; |
|
30 |
+ |
|
31 |
+ &-item { |
|
32 |
+ width: @width; |
|
33 |
+ margin-top: @spacing; |
|
34 |
+ } |
|
35 |
+} |
|
36 |
+ |
|
37 |
+.collection-view(@width: 650rpx; @row: 4; @spacing-top: 24rpx; @spacing-left: 24rpx) { |
|
38 |
+ .flex-center(row); |
|
39 |
+ |
|
40 |
+ flex-wrap: wrap; |
|
41 |
+ width: @width; |
|
42 |
+ |
|
43 |
+ &-item { |
|
44 |
+ width: (@width - @spacing-left * (@row - 1)) / @row; |
|
45 |
+ margin-top: @spacing-top; |
|
46 |
+ margin-right: @spacing-left; |
|
47 |
+ |
|
48 |
+ &:nth-child(@{row}n) { |
|
49 |
+ margin-right: 0; |
|
50 |
+ } |
|
51 |
+ } |
|
52 |
+} |
|
53 |
+ |
|
54 |
+.footer() { |
|
55 |
+ position: fixed; |
|
56 |
+ bottom: 0; |
|
57 |
+ display: flex; |
|
58 |
+ width: 100%; |
|
59 |
+ height: calc(80rpx + env(safe-area-inset-bottom)); |
|
60 |
+} |
|
61 |
+ |
|
62 |
+.full-image() { |
|
63 |
+ width: 100%; |
|
64 |
+ height: 100%; |
|
65 |
+} |
|
66 |
+ |
|
67 |
+.square(@len) { |
|
68 |
+ width: @len; |
|
69 |
+ height: @len; |
|
70 |
+} |
|
71 |
+ |
|
72 |
+.circle(@radius) { |
|
73 |
+ width: @radius; |
|
74 |
+ height: @radius; |
|
75 |
+ overflow: hidden; |
|
76 |
+ border-radius: @radius / 2; |
|
77 |
+} |
|
78 |
+ |
|
79 |
+.with-btnFooter() { |
|
80 |
+ height: calc(100% - @btnFooter-height); |
|
81 |
+} |
|
82 |
+ |
|
83 |
+.with-footer() { |
|
84 |
+ height: calc(100% - @descFooter-height); |
|
85 |
+} |
@@ -0,0 +1,70 @@ |
||
1 |
+@import './variable.less'; |
|
2 |
+ |
|
3 |
+.arrow(right; @color; @size) { |
|
4 |
+ .square(@size); |
|
5 |
+ |
|
6 |
+ box-sizing: border-box; |
|
7 |
+ border-top: 2px solid @color; |
|
8 |
+ border-right: 2px solid @color; |
|
9 |
+ transform: rotate(45deg); |
|
10 |
+} |
|
11 |
+ |
|
12 |
+.triangle-center(bottom; @color; @len: 25rpx) { |
|
13 |
+ border-right: @len solid transparent; |
|
14 |
+ border-bottom: @len solid @color; |
|
15 |
+ border-left: @len solid transparent; |
|
16 |
+} |
|
17 |
+ |
|
18 |
+.triangle-corner(bottomRight; @color; @len) { |
|
19 |
+ border-bottom: @len solid @color; |
|
20 |
+ border-left: @len solid transparent; |
|
21 |
+} |
|
22 |
+ |
|
23 |
+.cross(@len; @color) { |
|
24 |
+ display: inline-block; |
|
25 |
+ width: @len; |
|
26 |
+ height: @len / 4; |
|
27 |
+ overflow: visible; |
|
28 |
+ font-size: 0; |
|
29 |
+ line-height: 0; |
|
30 |
+ vertical-align: middle; |
|
31 |
+ background: @color; |
|
32 |
+ border-radius: @len / 4; |
|
33 |
+ transform: rotate(45deg); |
|
34 |
+ |
|
35 |
+ &::after { |
|
36 |
+ display: block; |
|
37 |
+ width: @len; |
|
38 |
+ height: @len / 4; |
|
39 |
+ content: '/'; |
|
40 |
+ background: @color; |
|
41 |
+ border-radius: @len / 4; |
|
42 |
+ transform: rotate(-90deg); |
|
43 |
+ } |
|
44 |
+} |
|
45 |
+ |
|
46 |
+.plus(@borderWidth; @color) { |
|
47 |
+ position: relative; |
|
48 |
+ |
|
49 |
+ &::before { |
|
50 |
+ position: absolute; |
|
51 |
+ top: calc(50% - @borderWidth / 2); |
|
52 |
+ left: 0; |
|
53 |
+ width: 100%; |
|
54 |
+ height: @borderWidth; |
|
55 |
+ content: ''; |
|
56 |
+ background-color: @color-brand; |
|
57 |
+ border-radius: @borderWidth; |
|
58 |
+ } |
|
59 |
+ |
|
60 |
+ &::after { |
|
61 |
+ position: absolute; |
|
62 |
+ top: 0; |
|
63 |
+ left: calc(50% - @borderWidth / 2); |
|
64 |
+ width: @borderWidth; |
|
65 |
+ height: 100%; |
|
66 |
+ content: ''; |
|
67 |
+ background-color: @color-brand; |
|
68 |
+ border-radius: @borderWidth; |
|
69 |
+ } |
|
70 |
+} |
@@ -0,0 +1,48 @@ |
||
1 |
+//color |
|
2 |
+@color-bg: #efefef; |
|
3 |
+@color-dark-bg: #3e3e3e; |
|
4 |
+@color-black: #000; |
|
5 |
+@color-white: #fff; |
|
6 |
+@color-brand: #0967b2; |
|
7 |
+@color-other1: #d2b167; |
|
8 |
+@color-gray: #3e3e3e; |
|
9 |
+@color-light-gray: #959595; |
|
10 |
+ |
|
11 |
+//font |
|
12 |
+@font-h1: 40pt; |
|
13 |
+@font-h2: 20pt; |
|
14 |
+@font-h3: 18pt; |
|
15 |
+@font-title: 17pt; |
|
16 |
+@font-primary: 14pt; |
|
17 |
+@font-secondary: 13pt; |
|
18 |
+@font-tertiary: 11pt; |
|
19 |
+@font-quaternary: 10pt; |
|
20 |
+@font-label: 8pt; |
|
21 |
+ |
|
22 |
+// spacing |
|
23 |
+@spacing-view: 36rpx; |
|
24 |
+@spacing-item: 24rpx; |
|
25 |
+@spacing-inline: 12rpx; |
|
26 |
+ |
|
27 |
+@spacing-text: 12rpx; |
|
28 |
+@spacing-short-text: 4rpx; |
|
29 |
+ |
|
30 |
+@padding-quaternary: 12rpx; |
|
31 |
+ |
|
32 |
+//icon size |
|
33 |
+@icon-min-size: 16rpx; |
|
34 |
+@icon-little-small-size: 24rpx; |
|
35 |
+@icon-small-size: 32rpx; |
|
36 |
+@icon-middle-size: 48rpx; |
|
37 |
+@icon-big-size: 60rpx; |
|
38 |
+@icon-large-size: 72rpx; |
|
39 |
+ |
|
40 |
+//height |
|
41 |
+@btnFooter-height: 160rpx; |
|
42 |
+@descFooter-height: 100rpx; |
|
43 |
+@btnFooterWithProtocol-height: 200rpx; |
|
44 |
+ |
|
45 |
+@radius: 5px; |
|
46 |
+@radius-big: 10px; |
|
47 |
+ |
|
48 |
+@visual-width: 750rpx - @spacing-item * 2; |
@@ -0,0 +1,19 @@ |
||
1 |
+@import './src/style/less/variable.less'; |
|
2 |
+@import './src/style/less/layout.less'; |
|
3 |
+ |
|
4 |
+.icon-btn { |
|
5 |
+ .flex-center(row); |
|
6 |
+ |
|
7 |
+ justify-content: center; |
|
8 |
+ padding: 0; |
|
9 |
+ |
|
10 |
+ text { |
|
11 |
+ font-size: @font-primary; |
|
12 |
+ } |
|
13 |
+ |
|
14 |
+ image { |
|
15 |
+ width: @icon-middle-size; |
|
16 |
+ height: @icon-middle-size; |
|
17 |
+ margin-left: @spacing-inline; |
|
18 |
+ } |
|
19 |
+} |
@@ -0,0 +1,17 @@ |
||
1 |
+<template name="iconBtn"> |
|
2 |
+ <button |
|
3 |
+ class="icon-btn {{ btnClass }}" |
|
4 |
+ hover-class="{{ btnClass }}-hover" |
|
5 |
+ disabled="{{ disabled || false }}" |
|
6 |
+ open-type="{{ openType }}" |
|
7 |
+ bindtap="{{ (openType == '' || openType == undefined) ? action : '' }}" |
|
8 |
+ bindgetuserinfo="{{ action }}" |
|
9 |
+ lang="zh_CN" |
|
10 |
+ > |
|
11 |
+ <text>{{ btnTxt }}</text> |
|
12 |
+ <image |
|
13 |
+ src="{{ btnIcon || '/resources/common/left_arrow1.png' }}" |
|
14 |
+ hidden="{{ disabled }}" |
|
15 |
+ ></image> |
|
16 |
+ </button> |
|
17 |
+</template> |
@@ -0,0 +1,14 @@ |
||
1 |
+.icon-btn { |
|
2 |
+ display: flex; |
|
3 |
+ align-items: center; |
|
4 |
+ justify-content: center; |
|
5 |
+ padding: 0; |
|
6 |
+} |
|
7 |
+.icon-btn text { |
|
8 |
+ font-size: 14pt; |
|
9 |
+} |
|
10 |
+.icon-btn image { |
|
11 |
+ width: 48rpx; |
|
12 |
+ height: 48rpx; |
|
13 |
+ margin-left: 12rpx; |
|
14 |
+} |
@@ -0,0 +1,81 @@ |
||
1 |
+@import './src/style/less/variable.less'; |
|
2 |
+@import './src/style/less/layout.less'; |
|
3 |
+@import '/template/btn/btn.wxss'; |
|
4 |
+ |
|
5 |
+.member-footer { |
|
6 |
+ position: fixed; |
|
7 |
+ bottom: 0; |
|
8 |
+ z-index: 999; |
|
9 |
+ display: flex; |
|
10 |
+ width: 100%; |
|
11 |
+ height: @descFooter-height; |
|
12 |
+ background-color: #c8c8c8; |
|
13 |
+ |
|
14 |
+ .left { |
|
15 |
+ .flex-center(row); |
|
16 |
+ |
|
17 |
+ justify-content: center; |
|
18 |
+ width: 40%; |
|
19 |
+ height: 100%; |
|
20 |
+ |
|
21 |
+ image { |
|
22 |
+ width: 80%; |
|
23 |
+ } |
|
24 |
+ } |
|
25 |
+ |
|
26 |
+ .right { |
|
27 |
+ .flex-center(row); |
|
28 |
+ |
|
29 |
+ width: 70%; |
|
30 |
+ height: 100%; |
|
31 |
+ |
|
32 |
+ text { |
|
33 |
+ margin-left: @spacing-item; |
|
34 |
+ font-size: @font-label; |
|
35 |
+ color: @color-gray; |
|
36 |
+ } |
|
37 |
+ } |
|
38 |
+} |
|
39 |
+ |
|
40 |
+.btn-footer() { |
|
41 |
+ .flex-center(row); |
|
42 |
+ |
|
43 |
+ position: fixed; |
|
44 |
+ bottom: 0; |
|
45 |
+ justify-content: center; |
|
46 |
+ width: 100%; |
|
47 |
+ height: @btnFooter-height; |
|
48 |
+ background-color: @color-white; |
|
49 |
+ box-shadow: 0 -5px 9px 2px fade(@color-black, 10%); |
|
50 |
+ |
|
51 |
+ button { |
|
52 |
+ height: 100rpx; |
|
53 |
+ } |
|
54 |
+} |
|
55 |
+ |
|
56 |
+.btn-footer1 { |
|
57 |
+ .btn-footer(); |
|
58 |
+ |
|
59 |
+ button { |
|
60 |
+ width: @visual-width; |
|
61 |
+ } |
|
62 |
+} |
|
63 |
+ |
|
64 |
+.btn-footer2 { |
|
65 |
+ .btn-footer(); |
|
66 |
+ |
|
67 |
+ button { |
|
68 |
+ width: 100%; |
|
69 |
+ border-radius: 0 !important; |
|
70 |
+ } |
|
71 |
+ |
|
72 |
+ .left { |
|
73 |
+ width: 250rpx; |
|
74 |
+ border-radius: @radius 0 0 @radius; |
|
75 |
+ } |
|
76 |
+ |
|
77 |
+ .right { |
|
78 |
+ width: 452rpx; |
|
79 |
+ border-radius: 0 @radius @radius 0; |
|
80 |
+ } |
|
81 |
+} |
@@ -0,0 +1,37 @@ |
||
1 |
+<template name="memberFooter"> |
|
2 |
+ <view class="member-footer"> |
|
3 |
+ <view class="left"> |
|
4 |
+ <image mode="widthFix" src="/resources/member/lrclogo1.png"></image> |
|
5 |
+ </view> |
|
6 |
+ |
|
7 |
+ <view class="right"> |
|
8 |
+ <wxs src="./../../wxs/stringFilter.wxs" module="tools"></wxs> |
|
9 |
+ <text>{{ tools.filter(text) }}</text> |
|
10 |
+ </view> |
|
11 |
+ </view> |
|
12 |
+</template> |
|
13 |
+ |
|
14 |
+<import src="/template/btn/btn.wxml"></import> |
|
15 |
+<template name="btnFooter"> |
|
16 |
+ <view class="btn-footer1"> |
|
17 |
+ <template is="iconBtn" data="{{btnClass, btnTxt, disabled, action, openType}}"></template> |
|
18 |
+ </view> |
|
19 |
+</template> |
|
20 |
+ |
|
21 |
+<template name="multiBtnFooter"> |
|
22 |
+ <view class="btn-footer2"> |
|
23 |
+ <view class="left"> |
|
24 |
+ <template |
|
25 |
+ is="iconBtn" |
|
26 |
+ data="{{btnClass: btnClass1, btnTxt: btnTxt1, disabled: disabled1, action: action1, btnIcon: btnIcon1, openType: openType1}}" |
|
27 |
+ ></template> |
|
28 |
+ </view> |
|
29 |
+ <view class="right"> |
|
30 |
+ <template |
|
31 |
+ is="iconBtn" |
|
32 |
+ data="{{btnClass: btnClass2, btnTxt: btnTxt2, disabled: disabled2, action: action2, btnIcon: btnIcon2, openType: openType2}}" |
|
33 |
+ ></template> |
|
34 |
+ </view> |
|
35 |
+ </view> |
|
36 |
+</template> |
|
37 |
+ |
@@ -0,0 +1,74 @@ |
||
1 |
+@import '/template/btn/btn.wxss'; |
|
2 |
+.member-footer { |
|
3 |
+ position: fixed; |
|
4 |
+ bottom: 0; |
|
5 |
+ z-index: 999; |
|
6 |
+ display: flex; |
|
7 |
+ width: 100%; |
|
8 |
+ height: 100rpx; |
|
9 |
+ background-color: #c8c8c8; |
|
10 |
+} |
|
11 |
+.member-footer .left { |
|
12 |
+ display: flex; |
|
13 |
+ align-items: center; |
|
14 |
+ justify-content: center; |
|
15 |
+ width: 40%; |
|
16 |
+ height: 100%; |
|
17 |
+} |
|
18 |
+.member-footer .left image { |
|
19 |
+ width: 80%; |
|
20 |
+} |
|
21 |
+.member-footer .right { |
|
22 |
+ display: flex; |
|
23 |
+ align-items: center; |
|
24 |
+ width: 70%; |
|
25 |
+ height: 100%; |
|
26 |
+} |
|
27 |
+.member-footer .right text { |
|
28 |
+ margin-left: 24rpx; |
|
29 |
+ font-size: 8pt; |
|
30 |
+ color: #3e3e3e; |
|
31 |
+} |
|
32 |
+.btn-footer1 { |
|
33 |
+ display: flex; |
|
34 |
+ align-items: center; |
|
35 |
+ position: fixed; |
|
36 |
+ bottom: 0; |
|
37 |
+ justify-content: center; |
|
38 |
+ width: 100%; |
|
39 |
+ height: 160rpx; |
|
40 |
+ background-color: #fff; |
|
41 |
+ box-shadow: 0 -5px 9px 2px rgba(0, 0, 0, 0.1); |
|
42 |
+} |
|
43 |
+.btn-footer1 button { |
|
44 |
+ height: 100rpx; |
|
45 |
+} |
|
46 |
+.btn-footer1 button { |
|
47 |
+ width: 702rpx; |
|
48 |
+} |
|
49 |
+.btn-footer2 { |
|
50 |
+ display: flex; |
|
51 |
+ align-items: center; |
|
52 |
+ position: fixed; |
|
53 |
+ bottom: 0; |
|
54 |
+ justify-content: center; |
|
55 |
+ width: 100%; |
|
56 |
+ height: 160rpx; |
|
57 |
+ background-color: #fff; |
|
58 |
+ box-shadow: 0 -5px 9px 2px rgba(0, 0, 0, 0.1); |
|
59 |
+} |
|
60 |
+.btn-footer2 button { |
|
61 |
+ height: 100rpx; |
|
62 |
+} |
|
63 |
+.btn-footer2 button { |
|
64 |
+ width: 100%; |
|
65 |
+ border-radius: 0 !important; |
|
66 |
+} |
|
67 |
+.btn-footer2 .left { |
|
68 |
+ width: 250rpx; |
|
69 |
+ border-radius: 5px 0 0 5px; |
|
70 |
+} |
|
71 |
+.btn-footer2 .right { |
|
72 |
+ width: 452rpx; |
|
73 |
+ border-radius: 0 5px 5px 0; |
|
74 |
+} |
@@ -0,0 +1,65 @@ |
||
1 |
+Page({ |
|
2 |
+ data: { |
|
3 |
+ title: '兑换成功', |
|
4 |
+ desc: '', |
|
5 |
+ isVirtual: false, |
|
6 |
+ desc1: '在个人中心->专享劵,查看已兑换的劵。', |
|
7 |
+ desc2: |
|
8 |
+ '请留意微信服务通知内 小程序TAMRON的订阅消息,查收实物商品的邮寄情况。', |
|
9 |
+ desc3: |
|
10 |
+ '专属礼品已兑换,请留意微信服务通知内 小程序 TARMON 的订阅消息,查收专属礼品的邮寄情况。', |
|
11 |
+ action: 'navigateBackToMall', |
|
12 |
+ btnTitle: '返回', |
|
13 |
+ isHightlight: false |
|
14 |
+ }, |
|
15 |
+ |
|
16 |
+ onLoad(options) { |
|
17 |
+ if (options.goods) { |
|
18 |
+ const goods = JSON.parse(options.goods) |
|
19 |
+ let desc = this.data.desc1 |
|
20 |
+ if (goods.only_for_member) { |
|
21 |
+ desc = this.data.desc3 |
|
22 |
+ } else if (goods.good_type === 0) { |
|
23 |
+ desc = this.data.desc2 |
|
24 |
+ } |
|
25 |
+ this.setData({ |
|
26 |
+ isVirtual: goods.good_type === 1, |
|
27 |
+ desc |
|
28 |
+ }) |
|
29 |
+ } else { |
|
30 |
+ const eventChannel = this.getOpenerEventChannel() |
|
31 |
+ const that = this |
|
32 |
+ eventChannel.on('acceptDataFromOpenerPage', data => { |
|
33 |
+ that.setData({ |
|
34 |
+ title: data.title, |
|
35 |
+ desc: data.desc, |
|
36 |
+ action: 'navigateToMine', |
|
37 |
+ btnTitle: data.btnTitle, |
|
38 |
+ isHightlight: data.isHightlight |
|
39 |
+ }) |
|
40 |
+ }) |
|
41 |
+ } |
|
42 |
+ }, |
|
43 |
+ |
|
44 |
+ navigateToMine() { |
|
45 |
+ wx.switchTab({ |
|
46 |
+ url: '/pages/member/mine/mine' |
|
47 |
+ }) |
|
48 |
+ }, |
|
49 |
+ |
|
50 |
+ navigateBackToMall() { |
|
51 |
+ wx.navigateBack({ |
|
52 |
+ delta: 2 |
|
53 |
+ }) |
|
54 |
+ }, |
|
55 |
+ |
|
56 |
+ navigateToVoucher() { |
|
57 |
+ wx.redirectTo({ |
|
58 |
+ url: '/pages/member/mine/voucher/voucher' |
|
59 |
+ }) |
|
60 |
+ }, |
|
61 |
+ |
|
62 |
+ officialAccountError(e) { |
|
63 |
+ console.log(e) |
|
64 |
+ } |
|
65 |
+}) |
@@ -0,0 +1,5 @@ |
||
1 |
+{ |
|
2 |
+ "component": true, |
|
3 |
+ "usingComponents": {}, |
|
4 |
+ "disableScroll": true |
|
5 |
+} |
@@ -0,0 +1,99 @@ |
||
1 |
+@import './src/style/less/variable.less'; |
|
2 |
+@import './src/style/less/layout.less'; |
|
3 |
+ |
|
4 |
+.result-view { |
|
5 |
+ .flex-center(column); |
|
6 |
+ |
|
7 |
+ box-sizing: border-box; |
|
8 |
+ width: 100%; |
|
9 |
+ height: 100%; |
|
10 |
+ padding: @spacing-item; |
|
11 |
+ background-color: @color-bg; |
|
12 |
+} |
|
13 |
+ |
|
14 |
+.logo { |
|
15 |
+ width: 200rpx; |
|
16 |
+ height: 200rpx; |
|
17 |
+ margin-top: 50rpx; |
|
18 |
+ |
|
19 |
+ image { |
|
20 |
+ .full-image(); |
|
21 |
+ } |
|
22 |
+} |
|
23 |
+ |
|
24 |
+.content { |
|
25 |
+ .flex-center(column); |
|
26 |
+ |
|
27 |
+ width: 100%; |
|
28 |
+ margin-top: @spacing-item; |
|
29 |
+ |
|
30 |
+ .title { |
|
31 |
+ margin-top: @spacing-item; |
|
32 |
+ font-size: @font-title; |
|
33 |
+ font-weight: 600; |
|
34 |
+ color: @color-black; |
|
35 |
+ } |
|
36 |
+ |
|
37 |
+ .desc { |
|
38 |
+ margin-top: @spacing-item; |
|
39 |
+ font-size: @font-tertiary; |
|
40 |
+ color: @color-light-gray; |
|
41 |
+ text-align: center; |
|
42 |
+ } |
|
43 |
+ |
|
44 |
+ .hint { |
|
45 |
+ margin-top: @spacing-item; |
|
46 |
+ .flex-center(row); |
|
47 |
+ |
|
48 |
+ image { |
|
49 |
+ .square(@icon-large-size); |
|
50 |
+ } |
|
51 |
+ |
|
52 |
+ text { |
|
53 |
+ margin-left: @spacing-inline; |
|
54 |
+ font-size: @font-primary; |
|
55 |
+ color: @color-brand; |
|
56 |
+ } |
|
57 |
+ } |
|
58 |
+} |
|
59 |
+ |
|
60 |
+.action { |
|
61 |
+ width: 100%; |
|
62 |
+ margin-top: @spacing-item; |
|
63 |
+ |
|
64 |
+ view { |
|
65 |
+ .flex-center(column); |
|
66 |
+ |
|
67 |
+ justify-content: center; |
|
68 |
+ width: 100%; |
|
69 |
+ height: 80rpx; |
|
70 |
+ margin-top: @spacing-inline; |
|
71 |
+ color: @color-white; |
|
72 |
+ background-color: @color-brand; |
|
73 |
+ border-radius: @radius; |
|
74 |
+ } |
|
75 |
+} |
|
76 |
+ |
|
77 |
+.action-bottom { |
|
78 |
+ .flex-center(column); |
|
79 |
+ |
|
80 |
+ position: fixed; |
|
81 |
+ bottom: @spacing-view; |
|
82 |
+ width: 100%; |
|
83 |
+ |
|
84 |
+ view { |
|
85 |
+ .flex-center(column); |
|
86 |
+ |
|
87 |
+ justify-content: center; |
|
88 |
+ width: auto; |
|
89 |
+ padding: @spacing-inline @spacing-view; |
|
90 |
+ color: @color-brand; |
|
91 |
+ border: 1px @color-light-gray solid; |
|
92 |
+ border-radius: @radius; |
|
93 |
+ } |
|
94 |
+} |
|
95 |
+ |
|
96 |
+.official-account { |
|
97 |
+ width: 702rpx; |
|
98 |
+ margin-top: @spacing-view; |
|
99 |
+} |
@@ -0,0 +1,33 @@ |
||
1 |
+ |
|
2 |
+<view class="result-view" wx:if="{{isHightlight}}"> |
|
3 |
+ <view class="logo"> |
|
4 |
+ <image src="success.svg"></image> |
|
5 |
+ </view> |
|
6 |
+ <view class="content"> |
|
7 |
+ <text class="title">{{ title }}</text> |
|
8 |
+ <view class="hint"> |
|
9 |
+ <image src="/resources/trumpet.svg"></image> |
|
10 |
+ <text>{{ desc }}</text> |
|
11 |
+ </view> |
|
12 |
+ <view class="official-account"> |
|
13 |
+ <official-account binderror="officialAccountError"></official-account> |
|
14 |
+ </view> |
|
15 |
+ </view> |
|
16 |
+ <view class="action-bottom"> |
|
17 |
+ <view class="goOn" bindtap="{{ action }}">{{ btnTitle }}</view> |
|
18 |
+ </view> |
|
19 |
+</view> |
|
20 |
+ |
|
21 |
+<view class="result-view" wx:else> |
|
22 |
+ <view class="logo"> |
|
23 |
+ <image src="success.svg"></image> |
|
24 |
+ </view> |
|
25 |
+ <view class="content"> |
|
26 |
+ <text class="title">{{ title }}</text> |
|
27 |
+ <text class="desc">{{ desc }}</text> |
|
28 |
+ </view> |
|
29 |
+ <view class="action"> |
|
30 |
+ <view class="goOn" bindtap="{{ action }}">{{ btnTitle }}</view> |
|
31 |
+ <view class="detail" bindtap="navigateToVoucher" wx:if="{{ isVirtual }}">去查看</view> |
|
32 |
+ </view> |
|
33 |
+</view> |
@@ -0,0 +1,91 @@ |
||
1 |
+.result-view { |
|
2 |
+ display: flex; |
|
3 |
+ flex-direction: column; |
|
4 |
+ align-items: center; |
|
5 |
+ box-sizing: border-box; |
|
6 |
+ width: 100%; |
|
7 |
+ height: 100%; |
|
8 |
+ padding: 24rpx; |
|
9 |
+ background-color: #efefef; |
|
10 |
+} |
|
11 |
+.logo { |
|
12 |
+ width: 200rpx; |
|
13 |
+ height: 200rpx; |
|
14 |
+ margin-top: 50rpx; |
|
15 |
+} |
|
16 |
+.logo image { |
|
17 |
+ width: 100%; |
|
18 |
+ height: 100%; |
|
19 |
+} |
|
20 |
+.content { |
|
21 |
+ display: flex; |
|
22 |
+ flex-direction: column; |
|
23 |
+ align-items: center; |
|
24 |
+ width: 100%; |
|
25 |
+ margin-top: 24rpx; |
|
26 |
+} |
|
27 |
+.content .title { |
|
28 |
+ margin-top: 24rpx; |
|
29 |
+ font-size: 17pt; |
|
30 |
+ font-weight: 600; |
|
31 |
+ color: #000; |
|
32 |
+} |
|
33 |
+.content .desc { |
|
34 |
+ margin-top: 24rpx; |
|
35 |
+ font-size: 11pt; |
|
36 |
+ color: #959595; |
|
37 |
+ text-align: center; |
|
38 |
+} |
|
39 |
+.content .hint { |
|
40 |
+ margin-top: 24rpx; |
|
41 |
+ display: flex; |
|
42 |
+ align-items: center; |
|
43 |
+} |
|
44 |
+.content .hint image { |
|
45 |
+ width: 72rpx; |
|
46 |
+ height: 72rpx; |
|
47 |
+} |
|
48 |
+.content .hint text { |
|
49 |
+ margin-left: 12rpx; |
|
50 |
+ font-size: 14pt; |
|
51 |
+ color: #0967b2; |
|
52 |
+} |
|
53 |
+.action { |
|
54 |
+ width: 100%; |
|
55 |
+ margin-top: 24rpx; |
|
56 |
+} |
|
57 |
+.action view { |
|
58 |
+ display: flex; |
|
59 |
+ flex-direction: column; |
|
60 |
+ align-items: center; |
|
61 |
+ justify-content: center; |
|
62 |
+ width: 100%; |
|
63 |
+ height: 80rpx; |
|
64 |
+ margin-top: 12rpx; |
|
65 |
+ color: #fff; |
|
66 |
+ background-color: #0967b2; |
|
67 |
+ border-radius: 5px; |
|
68 |
+} |
|
69 |
+.action-bottom { |
|
70 |
+ display: flex; |
|
71 |
+ flex-direction: column; |
|
72 |
+ align-items: center; |
|
73 |
+ position: fixed; |
|
74 |
+ bottom: 36rpx; |
|
75 |
+ width: 100%; |
|
76 |
+} |
|
77 |
+.action-bottom view { |
|
78 |
+ display: flex; |
|
79 |
+ flex-direction: column; |
|
80 |
+ align-items: center; |
|
81 |
+ justify-content: center; |
|
82 |
+ width: auto; |
|
83 |
+ padding: 12rpx 36rpx; |
|
84 |
+ color: #0967b2; |
|
85 |
+ border: 1px #959595 solid; |
|
86 |
+ border-radius: 5px; |
|
87 |
+} |
|
88 |
+.official-account { |
|
89 |
+ width: 702rpx; |
|
90 |
+ margin-top: 36rpx; |
|
91 |
+} |
@@ -0,0 +1 @@ |
||
1 |
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1575547268867" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3403" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M512 981.333333C252.8 981.333333 42.666667 771.2 42.666667 512S252.8 42.666667 512 42.666667s469.333333 210.133333 469.333333 469.333333-210.133333 469.333333-469.333333 469.333333z m-50.432-326.101333L310.613333 504.32a32 32 0 0 0-45.226666 45.226667l174.72 174.762666a32.341333 32.341333 0 0 0 0.341333 0.341334l0.256 0.213333a32 32 0 0 0 50.048-6.144l337.450667-379.605333a32 32 0 1 0-47.872-42.496l-318.762667 358.613333z" fill="#0967b2" p-id="3404"></path></svg> |
@@ -0,0 +1,18 @@ |
||
1 |
+// template/webView/webView.js |
|
2 |
+Page({ |
|
3 |
+ /** |
|
4 |
+ * Page initial data |
|
5 |
+ */ |
|
6 |
+ data: { |
|
7 |
+ url: '' |
|
8 |
+ }, |
|
9 |
+ |
|
10 |
+ /** |
|
11 |
+ * Lifecycle function--Called when page load |
|
12 |
+ */ |
|
13 |
+ onLoad(options) { |
|
14 |
+ this.setData({ |
|
15 |
+ url: options.url |
|
16 |
+ }) |
|
17 |
+ } |
|
18 |
+}) |
@@ -0,0 +1,3 @@ |
||
1 |
+{ |
|
2 |
+ "usingComponents": {} |
|
3 |
+} |
@@ -0,0 +1 @@ |
||
1 |
+<web-view src="{{url}}"></web-view> |
@@ -0,0 +1 @@ |
||
1 |
+/* template/webView/webView.wxss */ |
@@ -0,0 +1,155 @@ |
||
1 |
+const urls = require('./urls.js') |
|
2 |
+const brandConfig = require('../brand/config.js') |
|
3 |
+ |
|
4 |
+// 服务器登录 |
|
5 |
+function _login(code, cb) { |
|
6 |
+ wx.request({ |
|
7 |
+ url: urls.MINI_LOGIN_API_URL, |
|
8 |
+ data: { |
|
9 |
+ code |
|
10 |
+ }, |
|
11 |
+ method: 'POST', |
|
12 |
+ header: { |
|
13 |
+ 'content-type': 'application/x-www-form-urlencoded' |
|
14 |
+ }, |
|
15 |
+ success(res) { |
|
16 |
+ wx.setStorage({ |
|
17 |
+ key: 'userInfo', |
|
18 |
+ data: res.data.data, |
|
19 |
+ success() { |
|
20 |
+ cb(res.data.data) |
|
21 |
+ } |
|
22 |
+ }) |
|
23 |
+ }, |
|
24 |
+ complete: () => { |
|
25 |
+ wx.hideLoading() |
|
26 |
+ } |
|
27 |
+ }) |
|
28 |
+} |
|
29 |
+ |
|
30 |
+function _slientLogin(cb) { |
|
31 |
+ wx.showLoading({ |
|
32 |
+ title: '加载中...', |
|
33 |
+ mask: true |
|
34 |
+ }) |
|
35 |
+ const { environment } = wx.getSystemInfoSync() |
|
36 |
+ |
|
37 |
+ if (environment === 'wxwork') { |
|
38 |
+ wx.login({ |
|
39 |
+ success(res) { |
|
40 |
+ console.log(res) |
|
41 |
+ if (res.code) { |
|
42 |
+ _login(res.code, cb) |
|
43 |
+ } else { |
|
44 |
+ wx.showToast({ |
|
45 |
+ title: '微信登录异常', |
|
46 |
+ icon: 'none' |
|
47 |
+ }) |
|
48 |
+ wx.hideLoading() |
|
49 |
+ } |
|
50 |
+ }, |
|
51 |
+ fail() { |
|
52 |
+ wx.showToast({ |
|
53 |
+ title: '微信登录异常', |
|
54 |
+ icon: 'none' |
|
55 |
+ }) |
|
56 |
+ wx.hideLoading() |
|
57 |
+ } |
|
58 |
+ }) |
|
59 |
+ |
|
60 |
+ return |
|
61 |
+ } |
|
62 |
+ wx.login({ |
|
63 |
+ success(res) { |
|
64 |
+ if (res.code) { |
|
65 |
+ _login(res.code, cb) |
|
66 |
+ } else { |
|
67 |
+ wx.showToast({ |
|
68 |
+ title: '微信登录异常', |
|
69 |
+ icon: 'none' |
|
70 |
+ }) |
|
71 |
+ wx.hideLoading() |
|
72 |
+ } |
|
73 |
+ }, |
|
74 |
+ fail() { |
|
75 |
+ wx.showToast({ |
|
76 |
+ title: '微信登录异常', |
|
77 |
+ icon: 'none' |
|
78 |
+ }) |
|
79 |
+ wx.hideLoading() |
|
80 |
+ } |
|
81 |
+ }) |
|
82 |
+} |
|
83 |
+ |
|
84 |
+// 静默登录 |
|
85 |
+function login(cb) { |
|
86 |
+ _slientLogin(cb) |
|
87 |
+} |
|
88 |
+ |
|
89 |
+function checkLoginStatus(cb) { |
|
90 |
+ wx.getStorage({ |
|
91 |
+ key: 'userInfo', |
|
92 |
+ success: res => { |
|
93 |
+ cb(res.data) |
|
94 |
+ }, |
|
95 |
+ fail: () => { |
|
96 |
+ login(cb) |
|
97 |
+ } |
|
98 |
+ }) |
|
99 |
+} |
|
100 |
+ |
|
101 |
+function post(params, isTip = true) { |
|
102 |
+ const finalUrl = `${params.url}?ts=${Date.now()}` |
|
103 |
+ checkLoginStatus(userInfo => { |
|
104 |
+ const { user_id } = userInfo |
|
105 |
+ const data = params.data || {} |
|
106 |
+ data.user_id = user_id |
|
107 |
+ wx.request({ |
|
108 |
+ url: finalUrl, |
|
109 |
+ data, |
|
110 |
+ method: 'POST', |
|
111 |
+ header: { |
|
112 |
+ 'content-type': 'application/x-www-form-urlencoded' |
|
113 |
+ }, |
|
114 |
+ success: res => { |
|
115 |
+ // success |
|
116 |
+ wx.hideLoading() |
|
117 |
+ if (res.data.status !== 200 && isTip) { |
|
118 |
+ wx.showToast({ |
|
119 |
+ title: res.data.description, |
|
120 |
+ image: '/resources/alert_fail.svg' |
|
121 |
+ }) |
|
122 |
+ |
|
123 |
+ if (params.fail) { |
|
124 |
+ params.fail(res) |
|
125 |
+ } |
|
126 |
+ } else if (params.success) { |
|
127 |
+ params.success(res.data) |
|
128 |
+ } |
|
129 |
+ }, |
|
130 |
+ fail: res => { |
|
131 |
+ // fail |
|
132 |
+ if (params.fail) { |
|
133 |
+ params.fail(res) |
|
134 |
+ } |
|
135 |
+ wx.hideLoading() |
|
136 |
+ wx.showToast({ |
|
137 |
+ title: '当前网络开小差, 请稍后再试', |
|
138 |
+ image: '/resources/alert_fail.svg' |
|
139 |
+ }) |
|
140 |
+ }, |
|
141 |
+ complete: res => { |
|
142 |
+ // complete |
|
143 |
+ |
|
144 |
+ if (params.complete) { |
|
145 |
+ params.complete(res) |
|
146 |
+ } |
|
147 |
+ } |
|
148 |
+ }) |
|
149 |
+ }) |
|
150 |
+} |
|
151 |
+ |
|
152 |
+module.exports = { |
|
153 |
+ post, |
|
154 |
+ login |
|
155 |
+} |
@@ -0,0 +1,34 @@ |
||
1 |
+module.exports = { |
|
2 |
+ index: '/pages/index/index', |
|
3 |
+ webView: '/template/resultView/resultView', |
|
4 |
+ member: { |
|
5 |
+ activity: { |
|
6 |
+ index: '/pages/member/activity/activity', |
|
7 |
+ details: '/pages/member/activity/details/details' |
|
8 |
+ }, |
|
9 |
+ mine: { |
|
10 |
+ index: '/pages/member/mine/mine', |
|
11 |
+ voucher: '/pages/member/mine/voucher/voucher', |
|
12 |
+ voucherDetails: 'pages/member/mine/voucher/details/details', |
|
13 |
+ benefits: { |
|
14 |
+ index: '/pages/member/mine/benefits/benefits', |
|
15 |
+ details: '/pages/member/mine/benefits/details/details' |
|
16 |
+ }, |
|
17 |
+ integral: { |
|
18 |
+ mall: '/pages/member/mine/integral/mall/mall', |
|
19 |
+ mallDetails: '/pages/member/mine/integral/mall/details/details', |
|
20 |
+ rule: '/pages/member/mine/integral/rule/rule' |
|
21 |
+ } |
|
22 |
+ }, |
|
23 |
+ |
|
24 |
+ saleManager: { |
|
25 |
+ index: '/pages/sale_manager_home/sale_manager_home' |
|
26 |
+ }, |
|
27 |
+ |
|
28 |
+ register: { |
|
29 |
+ saleManager: |
|
30 |
+ '/pages/register/sale_manager_register/sale_manager_register', |
|
31 |
+ consumer: '/pages/register/consumer/consumer' |
|
32 |
+ } |
|
33 |
+ } |
|
34 |
+} |
@@ -0,0 +1,27 @@ |
||
1 |
+/** |
|
2 |
+ * routerFillter --全局路由拦截器 |
|
3 |
+ * @function |
|
4 |
+ * @param{Object} pageObj 当前页面的page对象 |
|
5 |
+ * @param{Boolean} flag 是否开启权限判断 |
|
6 |
+ */ |
|
7 |
+ |
|
8 |
+function checkLoginStatus(pageObj) { |
|
9 |
+ const _onLoad = pageObj.onLoad |
|
10 |
+ pageObj.onLoad = function onLoad(options) { |
|
11 |
+ const that = this |
|
12 |
+ // 这一步是自己定义获取登录状态的,只是个判断权限的 |
|
13 |
+ const app = getApp() |
|
14 |
+ if (!app.globalData.isLogin) { |
|
15 |
+ app.network.login(res => { |
|
16 |
+ app.globalData.userInfo = res |
|
17 |
+ app.globalData.isLogin = true |
|
18 |
+ _onLoad.call(that, options) |
|
19 |
+ }) |
|
20 |
+ } else { |
|
21 |
+ _onLoad.call(that, options) |
|
22 |
+ } |
|
23 |
+ } |
|
24 |
+ return Page(pageObj) |
|
25 |
+} |
|
26 |
+ |
|
27 |
+exports.checkLoginStatus = checkLoginStatus |
@@ -0,0 +1,10 @@ |
||
1 |
+const config = require('../brand/config.js') |
|
2 |
+ |
|
3 |
+module.exports = { |
|
4 |
+ // 小程序登录接口 |
|
5 |
+ MINI_LOGIN_API_URL: `${config.baseURL}/api/mini/login`, |
|
6 |
+ MINI_USERINFO: `${config.baseURL}/api/mini/userinfo`, |
|
7 |
+ |
|
8 |
+ PACK: `${config.baseURL}/api/pack`, |
|
9 |
+ ORDER_CREATE: `${config.baseURL}/api/pay/wx/order_create` |
|
10 |
+} |
@@ -0,0 +1,302 @@ |
||
1 |
+/** |
|
2 |
+ * html2Json 改造来自: https://github.com/Jxck/html2json |
|
3 |
+ * |
|
4 |
+ * |
|
5 |
+ * author: Di (微信小程序开发工程师) |
|
6 |
+ * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com) |
|
7 |
+ * 垂直微信小程序开发交流社区 |
|
8 |
+ * |
|
9 |
+ * github地址: https://github.com/icindy/wxParse |
|
10 |
+ * |
|
11 |
+ * for: 微信小程序富文本解析 |
|
12 |
+ * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184 |
|
13 |
+ */ |
|
14 |
+ |
|
15 |
+const __placeImgeUrlHttps = 'https'; |
|
16 |
+let __emojisReg = ''; |
|
17 |
+let __emojisBaseSrc = ''; |
|
18 |
+let __emojis = {}; |
|
19 |
+const wxDiscode = require('./wxDiscode.js'); |
|
20 |
+const HTMLParser = require('./htmlparser.js'); |
|
21 |
+// Empty Elements - HTML 5 |
|
22 |
+const empty = makeMap('area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr'); |
|
23 |
+// Block Elements - HTML 5 |
|
24 |
+const block = makeMap('br,a,code,address,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video'); |
|
25 |
+ |
|
26 |
+// Inline Elements - HTML 5 |
|
27 |
+const inline = makeMap('abbr,acronym,applet,b,basefont,bdo,big,button,cite,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var'); |
|
28 |
+ |
|
29 |
+// Elements that you can, intentionally, leave open |
|
30 |
+// (and which close themselves) |
|
31 |
+const closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr'); |
|
32 |
+ |
|
33 |
+// Attributes that have their values filled in disabled="disabled" |
|
34 |
+const fillAttrs = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected'); |
|
35 |
+ |
|
36 |
+// Special Elements (can contain anything) |
|
37 |
+const special = makeMap('wxxxcode-style,script,style,view,scroll-view,block'); |
|
38 |
+function makeMap(str) { |
|
39 |
+ const obj = {}; const |
|
40 |
+ items = str.split(','); |
|
41 |
+ for (let i = 0; i < items.length; i++) obj[items[i]] = true; |
|
42 |
+ return obj; |
|
43 |
+} |
|
44 |
+ |
|
45 |
+function q(v) { |
|
46 |
+ return `"${v}"`; |
|
47 |
+} |
|
48 |
+ |
|
49 |
+function removeDOCTYPE(html) { |
|
50 |
+ return html |
|
51 |
+ .replace(/<\?xml.*\?>\n/, '') |
|
52 |
+ .replace(/<.*!doctype.*\>\n/, '') |
|
53 |
+ .replace(/<.*!DOCTYPE.*\>\n/, ''); |
|
54 |
+} |
|
55 |
+ |
|
56 |
+function trimHtml(html) { |
|
57 |
+ return html |
|
58 |
+ .replace(/\r?\n+/g, '') |
|
59 |
+ .replace(/<!--.*?-->/ig, '') |
|
60 |
+ .replace(/\/\*.*?\*\//ig, '') |
|
61 |
+ .replace(/[ ]+</ig, '<'); |
|
62 |
+} |
|
63 |
+ |
|
64 |
+ |
|
65 |
+function html2json(html, bindName) { |
|
66 |
+ // 处理字符串 |
|
67 |
+ html = removeDOCTYPE(html); |
|
68 |
+ html = trimHtml(html); |
|
69 |
+ html = wxDiscode.strDiscode(html); |
|
70 |
+ // 生成node节点 |
|
71 |
+ const bufArray = []; |
|
72 |
+ const results = { |
|
73 |
+ node: bindName, |
|
74 |
+ nodes: [], |
|
75 |
+ images: [], |
|
76 |
+ imageUrls: [], |
|
77 |
+ }; |
|
78 |
+ let index = 0; |
|
79 |
+ HTMLParser(html, { |
|
80 |
+ start(tag, attrs, unary) { |
|
81 |
+ // debug(tag, attrs, unary); |
|
82 |
+ // node for this element |
|
83 |
+ const node = { |
|
84 |
+ node: 'element', |
|
85 |
+ tag, |
|
86 |
+ }; |
|
87 |
+ |
|
88 |
+ if (bufArray.length === 0) { |
|
89 |
+ node.index = index.toString(); |
|
90 |
+ index += 1; |
|
91 |
+ } else { |
|
92 |
+ var parent = bufArray[0]; |
|
93 |
+ if (parent.nodes === undefined) { |
|
94 |
+ parent.nodes = []; |
|
95 |
+ } |
|
96 |
+ node.index = `${parent.index}.${parent.nodes.length}`; |
|
97 |
+ } |
|
98 |
+ |
|
99 |
+ if (block[tag]) { |
|
100 |
+ node.tagType = 'block'; |
|
101 |
+ } else if (inline[tag]) { |
|
102 |
+ node.tagType = 'inline'; |
|
103 |
+ } else if (closeSelf[tag]) { |
|
104 |
+ node.tagType = 'closeSelf'; |
|
105 |
+ } |
|
106 |
+ |
|
107 |
+ if (attrs.length !== 0) { |
|
108 |
+ node.attr = attrs.reduce((pre, attr) => { |
|
109 |
+ const { name } = attr; |
|
110 |
+ let { value } = attr; |
|
111 |
+ if (name == 'class') { |
|
112 |
+ console.dir(value); |
|
113 |
+ // value = value.join("") |
|
114 |
+ node.classStr = value; |
|
115 |
+ } |
|
116 |
+ // has multi attibutes |
|
117 |
+ // make it array of attribute |
|
118 |
+ if (name == 'style') { |
|
119 |
+ console.dir(value); |
|
120 |
+ // value = value.join("") |
|
121 |
+ node.styleStr = value; |
|
122 |
+ } |
|
123 |
+ if (value.match(/ /)) { |
|
124 |
+ value = value.split(' '); |
|
125 |
+ } |
|
126 |
+ |
|
127 |
+ |
|
128 |
+ // if attr already exists |
|
129 |
+ // merge it |
|
130 |
+ if (pre[name]) { |
|
131 |
+ if (Array.isArray(pre[name])) { |
|
132 |
+ // already array, push to last |
|
133 |
+ pre[name].push(value); |
|
134 |
+ } else { |
|
135 |
+ // single value, make it array |
|
136 |
+ pre[name] = [pre[name], value]; |
|
137 |
+ } |
|
138 |
+ } else { |
|
139 |
+ // not exist, put it |
|
140 |
+ pre[name] = value; |
|
141 |
+ } |
|
142 |
+ |
|
143 |
+ return pre; |
|
144 |
+ }, {}); |
|
145 |
+ } |
|
146 |
+ |
|
147 |
+ // 对img添加额外数据 |
|
148 |
+ if (node.tag === 'img') { |
|
149 |
+ node.imgIndex = results.images.length; |
|
150 |
+ let imgUrl = node.attr.src; |
|
151 |
+ if (imgUrl[0] == '') { |
|
152 |
+ imgUrl.splice(0, 1); |
|
153 |
+ } |
|
154 |
+ imgUrl = wxDiscode.urlToHttpUrl(imgUrl, __placeImgeUrlHttps); |
|
155 |
+ node.attr.src = imgUrl; |
|
156 |
+ node.from = bindName; |
|
157 |
+ results.images.push(node); |
|
158 |
+ results.imageUrls.push(imgUrl); |
|
159 |
+ } |
|
160 |
+ |
|
161 |
+ // 处理font标签样式属性 |
|
162 |
+ if (node.tag === 'font') { |
|
163 |
+ const fontSize = ['x-small', 'small', 'medium', 'large', 'x-large', 'xx-large', '-webkit-xxx-large']; |
|
164 |
+ const styleAttrs = { |
|
165 |
+ color: 'color', |
|
166 |
+ face: 'font-family', |
|
167 |
+ size: 'font-size', |
|
168 |
+ }; |
|
169 |
+ if (!node.attr.style) node.attr.style = []; |
|
170 |
+ if (!node.styleStr) node.styleStr = ''; |
|
171 |
+ for (const key in styleAttrs) { |
|
172 |
+ if (node.attr[key]) { |
|
173 |
+ const value = key === 'size' ? fontSize[node.attr[key] - 1] : node.attr[key]; |
|
174 |
+ node.attr.style.push(styleAttrs[key]); |
|
175 |
+ node.attr.style.push(value); |
|
176 |
+ node.styleStr += `${styleAttrs[key]}: ${value};`; |
|
177 |
+ } |
|
178 |
+ } |
|
179 |
+ } |
|
180 |
+ |
|
181 |
+ // 临时记录source资源 |
|
182 |
+ if (node.tag === 'source') { |
|
183 |
+ results.source = node.attr.src; |
|
184 |
+ } |
|
185 |
+ |
|
186 |
+ if (unary) { |
|
187 |
+ // if this tag doesn't have end tag |
|
188 |
+ // like <img src="hoge.png"/> |
|
189 |
+ // add to parents |
|
190 |
+ var parent = bufArray[0] || results; |
|
191 |
+ if (parent.nodes === undefined) { |
|
192 |
+ parent.nodes = []; |
|
193 |
+ } |
|
194 |
+ parent.nodes.push(node); |
|
195 |
+ } else { |
|
196 |
+ bufArray.unshift(node); |
|
197 |
+ } |
|
198 |
+ }, |
|
199 |
+ end(tag) { |
|
200 |
+ // debug(tag); |
|
201 |
+ // merge into parent tag |
|
202 |
+ const node = bufArray.shift(); |
|
203 |
+ if (node.tag !== tag) console.error('invalid state: mismatch end tag'); |
|
204 |
+ |
|
205 |
+ // 当有缓存source资源时于于video补上src资源 |
|
206 |
+ if (node.tag === 'video' && results.source) { |
|
207 |
+ node.attr.src = results.source; |
|
208 |
+ delete results.source; |
|
209 |
+ } |
|
210 |
+ |
|
211 |
+ if (bufArray.length === 0) { |
|
212 |
+ results.nodes.push(node); |
|
213 |
+ } else { |
|
214 |
+ const parent = bufArray[0]; |
|
215 |
+ if (parent.nodes === undefined) { |
|
216 |
+ parent.nodes = []; |
|
217 |
+ } |
|
218 |
+ parent.nodes.push(node); |
|
219 |
+ } |
|
220 |
+ }, |
|
221 |
+ chars(text) { |
|
222 |
+ // debug(text); |
|
223 |
+ const node = { |
|
224 |
+ node: 'text', |
|
225 |
+ text, |
|
226 |
+ textArray: transEmojiStr(text), |
|
227 |
+ }; |
|
228 |
+ |
|
229 |
+ if (bufArray.length === 0) { |
|
230 |
+ node.index = index.toString(); |
|
231 |
+ index += 1; |
|
232 |
+ results.nodes.push(node); |
|
233 |
+ } else { |
|
234 |
+ const parent = bufArray[0]; |
|
235 |
+ if (parent.nodes === undefined) { |
|
236 |
+ parent.nodes = []; |
|
237 |
+ } |
|
238 |
+ node.index = `${parent.index}.${parent.nodes.length}`; |
|
239 |
+ parent.nodes.push(node); |
|
240 |
+ } |
|
241 |
+ }, |
|
242 |
+ comment(text) { |
|
243 |
+ // debug(text); |
|
244 |
+ // var node = { |
|
245 |
+ // node: 'comment', |
|
246 |
+ // text: text, |
|
247 |
+ // }; |
|
248 |
+ // var parent = bufArray[0]; |
|
249 |
+ // if (parent.nodes === undefined) { |
|
250 |
+ // parent.nodes = []; |
|
251 |
+ // } |
|
252 |
+ // parent.nodes.push(node); |
|
253 |
+ }, |
|
254 |
+ }); |
|
255 |
+ return results; |
|
256 |
+} |
|
257 |
+ |
|
258 |
+function transEmojiStr(str) { |
|
259 |
+ // var eReg = new RegExp("["+__reg+' '+"]"); |
|
260 |
+// str = str.replace(/\[([^\[\]]+)\]/g,':$1:') |
|
261 |
+ |
|
262 |
+ const emojiObjs = []; |
|
263 |
+ // 如果正则表达式为空 |
|
264 |
+ if (__emojisReg.length == 0 || !__emojis) { |
|
265 |
+ var emojiObj = {}; |
|
266 |
+ emojiObj.node = 'text'; |
|
267 |
+ emojiObj.text = str; |
|
268 |
+ array = [emojiObj]; |
|
269 |
+ return array; |
|
270 |
+ } |
|
271 |
+ // 这个地方需要调整 |
|
272 |
+ str = str.replace(/\[([^\[\]]+)\]/g, ':$1:'); |
|
273 |
+ const eReg = new RegExp('[:]'); |
|
274 |
+ var array = str.split(eReg); |
|
275 |
+ for (let i = 0; i < array.length; i++) { |
|
276 |
+ const ele = array[i]; |
|
277 |
+ var emojiObj = {}; |
|
278 |
+ if (__emojis[ele]) { |
|
279 |
+ emojiObj.node = 'element'; |
|
280 |
+ emojiObj.tag = 'emoji'; |
|
281 |
+ emojiObj.text = __emojis[ele]; |
|
282 |
+ emojiObj.baseSrc = __emojisBaseSrc; |
|
283 |
+ } else { |
|
284 |
+ emojiObj.node = 'text'; |
|
285 |
+ emojiObj.text = ele; |
|
286 |
+ } |
|
287 |
+ emojiObjs.push(emojiObj); |
|
288 |
+ } |
|
289 |
+ |
|
290 |
+ return emojiObjs; |
|
291 |
+} |
|
292 |
+ |
|
293 |
+function emojisInit(reg = '', baseSrc = '/wxParse/emojis/', emojis) { |
|
294 |
+ __emojisReg = reg; |
|
295 |
+ __emojisBaseSrc = baseSrc; |
|
296 |
+ __emojis = emojis; |
|
297 |
+} |
|
298 |
+ |
|
299 |
+module.exports = { |
|
300 |
+ html2json, |
|
301 |
+ emojisInit, |
|
302 |
+}; |
@@ -0,0 +1,183 @@ |
||
1 |
+/** |
|
2 |
+ * |
|
3 |
+ * htmlParser改造自: https://github.com/blowsie/Pure-JavaScript-HTML5-Parser |
|
4 |
+ * |
|
5 |
+ * author: Di (微信小程序开发工程师) |
|
6 |
+ * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com) |
|
7 |
+ * 垂直微信小程序开发交流社区 |
|
8 |
+ * |
|
9 |
+ * github地址: https://github.com/icindy/wxParse |
|
10 |
+ * |
|
11 |
+ * for: 微信小程序富文本解析 |
|
12 |
+ * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184 |
|
13 |
+ */ |
|
14 |
+// Regular Expressions for parsing tags and attributes |
|
15 |
+const startTag = /^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/; |
|
16 |
+const endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/; |
|
17 |
+const attr = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g; |
|
18 |
+ |
|
19 |
+// Empty Elements - HTML 5 |
|
20 |
+const empty = makeMap('area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr'); |
|
21 |
+ |
|
22 |
+// Block Elements - HTML 5 |
|
23 |
+const block = makeMap('a,address,code,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video'); |
|
24 |
+ |
|
25 |
+// Inline Elements - HTML 5 |
|
26 |
+const inline = makeMap('abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var'); |
|
27 |
+ |
|
28 |
+// Elements that you can, intentionally, leave open |
|
29 |
+// (and which close themselves) |
|
30 |
+const closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr'); |
|
31 |
+ |
|
32 |
+// Attributes that have their values filled in disabled="disabled" |
|
33 |
+const fillAttrs = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected'); |
|
34 |
+ |
|
35 |
+// Special Elements (can contain anything) |
|
36 |
+const special = makeMap('wxxxcode-style,script,style,view,scroll-view,block'); |
|
37 |
+ |
|
38 |
+function HTMLParser(html, handler) { |
|
39 |
+ let index; let chars; let match; const stack = []; let |
|
40 |
+ last = html; |
|
41 |
+ stack.last = function () { |
|
42 |
+ return this[this.length - 1]; |
|
43 |
+ }; |
|
44 |
+ |
|
45 |
+ while (html) { |
|
46 |
+ chars = true; |
|
47 |
+ |
|
48 |
+ // Make sure we're not in a script or style element |
|
49 |
+ if (!stack.last() || !special[stack.last()]) { |
|
50 |
+ // Comment |
|
51 |
+ if (html.indexOf('<!--') == 0) { |
|
52 |
+ index = html.indexOf('-->'); |
|
53 |
+ |
|
54 |
+ if (index >= 0) { |
|
55 |
+ if (handler.comment) { handler.comment(html.substring(4, index)); } |
|
56 |
+ html = html.substring(index + 3); |
|
57 |
+ chars = false; |
|
58 |
+ } |
|
59 |
+ |
|
60 |
+ // end tag |
|
61 |
+ } else if (html.indexOf('</') == 0) { |
|
62 |
+ match = html.match(endTag); |
|
63 |
+ |
|
64 |
+ if (match) { |
|
65 |
+ html = html.substring(match[0].length); |
|
66 |
+ match[0].replace(endTag, parseEndTag); |
|
67 |
+ chars = false; |
|
68 |
+ } |
|
69 |
+ |
|
70 |
+ // start tag |
|
71 |
+ } else if (html.indexOf('<') == 0) { |
|
72 |
+ match = html.match(startTag); |
|
73 |
+ |
|
74 |
+ if (match) { |
|
75 |
+ html = html.substring(match[0].length); |
|
76 |
+ match[0].replace(startTag, parseStartTag); |
|
77 |
+ chars = false; |
|
78 |
+ } |
|
79 |
+ } |
|
80 |
+ |
|
81 |
+ if (chars) { |
|
82 |
+ index = html.indexOf('<'); |
|
83 |
+ let text = ''; |
|
84 |
+ while (index === 0) { |
|
85 |
+ text += '<'; |
|
86 |
+ html = html.substring(1); |
|
87 |
+ index = html.indexOf('<'); |
|
88 |
+ } |
|
89 |
+ text += index < 0 ? html : html.substring(0, index); |
|
90 |
+ html = index < 0 ? '' : html.substring(index); |
|
91 |
+ |
|
92 |
+ if (handler.chars) { handler.chars(text); } |
|
93 |
+ } |
|
94 |
+ } else { |
|
95 |
+ html = html.replace(new RegExp(`([\\s\\S]*?)<\/${stack.last()}[^>]*>`), (all, text) => { |
|
96 |
+ text = text.replace(/<!--([\s\S]*?)-->|<!\[CDATA\[([\s\S]*?)]]>/g, '$1$2'); |
|
97 |
+ if (handler.chars) { handler.chars(text); } |
|
98 |
+ |
|
99 |
+ return ''; |
|
100 |
+ }); |
|
101 |
+ |
|
102 |
+ |
|
103 |
+ parseEndTag('', stack.last()); |
|
104 |
+ } |
|
105 |
+ |
|
106 |
+ if (html == last) { throw `Parse Error: ${html}`; } |
|
107 |
+ last = html; |
|
108 |
+ } |
|
109 |
+ |
|
110 |
+ // Clean up any remaining tags |
|
111 |
+ parseEndTag(); |
|
112 |
+ |
|
113 |
+ function parseStartTag(tag, tagName, rest, unary) { |
|
114 |
+ tagName = tagName.toLowerCase(); |
|
115 |
+ |
|
116 |
+ if (block[tagName]) { |
|
117 |
+ while (stack.last() && inline[stack.last()]) { |
|
118 |
+ parseEndTag('', stack.last()); |
|
119 |
+ } |
|
120 |
+ } |
|
121 |
+ |
|
122 |
+ if (closeSelf[tagName] && stack.last() == tagName) { |
|
123 |
+ parseEndTag('', tagName); |
|
124 |
+ } |
|
125 |
+ |
|
126 |
+ unary = empty[tagName] || !!unary; |
|
127 |
+ |
|
128 |
+ if (!unary) { stack.push(tagName); } |
|
129 |
+ |
|
130 |
+ if (handler.start) { |
|
131 |
+ const attrs = []; |
|
132 |
+ |
|
133 |
+ rest.replace(attr, function (match, name) { |
|
134 |
+ const value = arguments[2] ? arguments[2] |
|
135 |
+ : arguments[3] ? arguments[3] |
|
136 |
+ : arguments[4] ? arguments[4] |
|
137 |
+ : fillAttrs[name] ? name : ''; |
|
138 |
+ |
|
139 |
+ attrs.push({ |
|
140 |
+ name, |
|
141 |
+ value, |
|
142 |
+ escaped: value.replace(/(^|[^\\])"/g, '$1\\\"'), // " |
|
143 |
+ }); |
|
144 |
+ }); |
|
145 |
+ |
|
146 |
+ if (handler.start) { |
|
147 |
+ handler.start(tagName, attrs, unary); |
|
148 |
+ } |
|
149 |
+ } |
|
150 |
+ } |
|
151 |
+ |
|
152 |
+ function parseEndTag(tag, tagName) { |
|
153 |
+ // If no tag name is provided, clean shop |
|
154 |
+ if (!tagName) { var pos = 0; } |
|
155 |
+ |
|
156 |
+ // Find the closest opened tag of the same type |
|
157 |
+ else { |
|
158 |
+ tagName = tagName.toLowerCase(); |
|
159 |
+ for (var pos = stack.length - 1; pos >= 0; pos--) { |
|
160 |
+ if (stack[pos] == tagName) { break; } |
|
161 |
+ } |
|
162 |
+ } |
|
163 |
+ if (pos >= 0) { |
|
164 |
+ // Close all the open elements, up the stack |
|
165 |
+ for (let i = stack.length - 1; i >= pos; i--) { |
|
166 |
+ if (handler.end) { handler.end(stack[i]); } |
|
167 |
+ } |
|
168 |
+ |
|
169 |
+ // Remove the open elements from the stack |
|
170 |
+ stack.length = pos; |
|
171 |
+ } |
|
172 |
+ } |
|
173 |
+} |
|
174 |
+ |
|
175 |
+ |
|
176 |
+function makeMap(str) { |
|
177 |
+ const obj = {}; const |
|
178 |
+ items = str.split(','); |
|
179 |
+ for (let i = 0; i < items.length; i++) { obj[items[i]] = true; } |
|
180 |
+ return obj; |
|
181 |
+} |
|
182 |
+ |
|
183 |
+module.exports = HTMLParser; |
@@ -0,0 +1,2412 @@ |
||
1 |
+/** |
|
2 |
+ * |
|
3 |
+ * showdown: https://github.com/showdownjs/showdown |
|
4 |
+ * |
|
5 |
+ * author: Di (微信小程序开发工程师) |
|
6 |
+ * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com) |
|
7 |
+ * 垂直微信小程序开发交流社区 |
|
8 |
+ * |
|
9 |
+ * github地址: https://github.com/icindy/wxParse |
|
10 |
+ * |
|
11 |
+ * for: 微信小程序富文本解析 |
|
12 |
+ * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184 |
|
13 |
+ */ |
|
14 |
+ |
|
15 |
+function getDefaultOpts(simple) { |
|
16 |
+ const defaultOptions = { |
|
17 |
+ omitExtraWLInCodeBlocks: { |
|
18 |
+ defaultValue: false, |
|
19 |
+ describe: 'Omit the default extra whiteline added to code blocks', |
|
20 |
+ type: 'boolean', |
|
21 |
+ }, |
|
22 |
+ noHeaderId: { |
|
23 |
+ defaultValue: false, |
|
24 |
+ describe: 'Turn on/off generated header id', |
|
25 |
+ type: 'boolean', |
|
26 |
+ }, |
|
27 |
+ prefixHeaderId: { |
|
28 |
+ defaultValue: false, |
|
29 |
+ describe: 'Specify a prefix to generated header ids', |
|
30 |
+ type: 'string', |
|
31 |
+ }, |
|
32 |
+ headerLevelStart: { |
|
33 |
+ defaultValue: false, |
|
34 |
+ describe: 'The header blocks level start', |
|
35 |
+ type: 'integer', |
|
36 |
+ }, |
|
37 |
+ parseImgDimensions: { |
|
38 |
+ defaultValue: false, |
|
39 |
+ describe: 'Turn on/off image dimension parsing', |
|
40 |
+ type: 'boolean', |
|
41 |
+ }, |
|
42 |
+ simplifiedAutoLink: { |
|
43 |
+ defaultValue: false, |
|
44 |
+ describe: 'Turn on/off GFM autolink style', |
|
45 |
+ type: 'boolean', |
|
46 |
+ }, |
|
47 |
+ literalMidWordUnderscores: { |
|
48 |
+ defaultValue: false, |
|
49 |
+ describe: 'Parse midword underscores as literal underscores', |
|
50 |
+ type: 'boolean', |
|
51 |
+ }, |
|
52 |
+ strikethrough: { |
|
53 |
+ defaultValue: false, |
|
54 |
+ describe: 'Turn on/off strikethrough support', |
|
55 |
+ type: 'boolean', |
|
56 |
+ }, |
|
57 |
+ tables: { |
|
58 |
+ defaultValue: false, |
|
59 |
+ describe: 'Turn on/off tables support', |
|
60 |
+ type: 'boolean', |
|
61 |
+ }, |
|
62 |
+ tablesHeaderId: { |
|
63 |
+ defaultValue: false, |
|
64 |
+ describe: 'Add an id to table headers', |
|
65 |
+ type: 'boolean', |
|
66 |
+ }, |
|
67 |
+ ghCodeBlocks: { |
|
68 |
+ defaultValue: true, |
|
69 |
+ describe: 'Turn on/off GFM fenced code blocks support', |
|
70 |
+ type: 'boolean', |
|
71 |
+ }, |
|
72 |
+ tasklists: { |
|
73 |
+ defaultValue: false, |
|
74 |
+ describe: 'Turn on/off GFM tasklist support', |
|
75 |
+ type: 'boolean', |
|
76 |
+ }, |
|
77 |
+ smoothLivePreview: { |
|
78 |
+ defaultValue: false, |
|
79 |
+ describe: 'Prevents weird effects in live previews due to incomplete input', |
|
80 |
+ type: 'boolean', |
|
81 |
+ }, |
|
82 |
+ smartIndentationFix: { |
|
83 |
+ defaultValue: false, |
|
84 |
+ description: 'Tries to smartly fix identation in es6 strings', |
|
85 |
+ type: 'boolean', |
|
86 |
+ }, |
|
87 |
+ }; |
|
88 |
+ if (simple === false) { |
|
89 |
+ return JSON.parse(JSON.stringify(defaultOptions)); |
|
90 |
+ } |
|
91 |
+ const ret = {}; |
|
92 |
+ for (const opt in defaultOptions) { |
|
93 |
+ if (defaultOptions.hasOwnProperty(opt)) { |
|
94 |
+ ret[opt] = defaultOptions[opt].defaultValue; |
|
95 |
+ } |
|
96 |
+ } |
|
97 |
+ return ret; |
|
98 |
+} |
|
99 |
+ |
|
100 |
+/** |
|
101 |
+ * Created by Tivie on 06-01-2015. |
|
102 |
+ */ |
|
103 |
+ |
|
104 |
+// Private properties |
|
105 |
+const showdown = {}; |
|
106 |
+const parsers = {}; |
|
107 |
+let extensions = {}; |
|
108 |
+let globalOptions = getDefaultOpts(true); |
|
109 |
+const flavor = { |
|
110 |
+ github: { |
|
111 |
+ omitExtraWLInCodeBlocks: true, |
|
112 |
+ prefixHeaderId: 'user-content-', |
|
113 |
+ simplifiedAutoLink: true, |
|
114 |
+ literalMidWordUnderscores: true, |
|
115 |
+ strikethrough: true, |
|
116 |
+ tables: true, |
|
117 |
+ tablesHeaderId: true, |
|
118 |
+ ghCodeBlocks: true, |
|
119 |
+ tasklists: true, |
|
120 |
+ }, |
|
121 |
+ vanilla: getDefaultOpts(true), |
|
122 |
+}; |
|
123 |
+ |
|
124 |
+/** |
|
125 |
+ * helper namespace |
|
126 |
+ * @type {{}} |
|
127 |
+ */ |
|
128 |
+showdown.helper = {}; |
|
129 |
+ |
|
130 |
+/** |
|
131 |
+ * TODO LEGACY SUPPORT CODE |
|
132 |
+ * @type {{}} |
|
133 |
+ */ |
|
134 |
+showdown.extensions = {}; |
|
135 |
+ |
|
136 |
+/** |
|
137 |
+ * Set a global option |
|
138 |
+ * @static |
|
139 |
+ * @param {string} key |
|
140 |
+ * @param {*} value |
|
141 |
+ * @returns {showdown} |
|
142 |
+ */ |
|
143 |
+showdown.setOption = function (key, value) { |
|
144 |
+ globalOptions[key] = value; |
|
145 |
+ return this; |
|
146 |
+}; |
|
147 |
+ |
|
148 |
+/** |
|
149 |
+ * Get a global option |
|
150 |
+ * @static |
|
151 |
+ * @param {string} key |
|
152 |
+ * @returns {*} |
|
153 |
+ */ |
|
154 |
+showdown.getOption = function (key) { |
|
155 |
+ return globalOptions[key]; |
|
156 |
+}; |
|
157 |
+ |
|
158 |
+/** |
|
159 |
+ * Get the global options |
|
160 |
+ * @static |
|
161 |
+ * @returns {{}} |
|
162 |
+ */ |
|
163 |
+showdown.getOptions = function () { |
|
164 |
+ return globalOptions; |
|
165 |
+}; |
|
166 |
+ |
|
167 |
+/** |
|
168 |
+ * Reset global options to the default values |
|
169 |
+ * @static |
|
170 |
+ */ |
|
171 |
+showdown.resetOptions = function () { |
|
172 |
+ globalOptions = getDefaultOpts(true); |
|
173 |
+}; |
|
174 |
+ |
|
175 |
+/** |
|
176 |
+ * Set the flavor showdown should use as default |
|
177 |
+ * @param {string} name |
|
178 |
+ */ |
|
179 |
+showdown.setFlavor = function (name) { |
|
180 |
+ if (flavor.hasOwnProperty(name)) { |
|
181 |
+ const preset = flavor[name]; |
|
182 |
+ for (const option in preset) { |
|
183 |
+ if (preset.hasOwnProperty(option)) { |
|
184 |
+ globalOptions[option] = preset[option]; |
|
185 |
+ } |
|
186 |
+ } |
|
187 |
+ } |
|
188 |
+}; |
|
189 |
+ |
|
190 |
+/** |
|
191 |
+ * Get the default options |
|
192 |
+ * @static |
|
193 |
+ * @param {boolean} [simple=true] |
|
194 |
+ * @returns {{}} |
|
195 |
+ */ |
|
196 |
+showdown.getDefaultOptions = function (simple) { |
|
197 |
+ return getDefaultOpts(simple); |
|
198 |
+}; |
|
199 |
+ |
|
200 |
+/** |
|
201 |
+ * Get or set a subParser |
|
202 |
+ * |
|
203 |
+ * subParser(name) - Get a registered subParser |
|
204 |
+ * subParser(name, func) - Register a subParser |
|
205 |
+ * @static |
|
206 |
+ * @param {string} name |
|
207 |
+ * @param {function} [func] |
|
208 |
+ * @returns {*} |
|
209 |
+ */ |
|
210 |
+showdown.subParser = function (name, func) { |
|
211 |
+ if (showdown.helper.isString(name)) { |
|
212 |
+ if (typeof func !== 'undefined') { |
|
213 |
+ parsers[name] = func; |
|
214 |
+ } else { |
|
215 |
+ if (parsers.hasOwnProperty(name)) { |
|
216 |
+ return parsers[name]; |
|
217 |
+ } |
|
218 |
+ throw Error(`SubParser named ${name} not registered!`); |
|
219 |
+ } |
|
220 |
+ } |
|
221 |
+}; |
|
222 |
+ |
|
223 |
+/** |
|
224 |
+ * Gets or registers an extension |
|
225 |
+ * @static |
|
226 |
+ * @param {string} name |
|
227 |
+ * @param {object|function=} ext |
|
228 |
+ * @returns {*} |
|
229 |
+ */ |
|
230 |
+showdown.extension = function (name, ext) { |
|
231 |
+ if (!showdown.helper.isString(name)) { |
|
232 |
+ throw Error('Extension \'name\' must be a string'); |
|
233 |
+ } |
|
234 |
+ |
|
235 |
+ name = showdown.helper.stdExtName(name); |
|
236 |
+ |
|
237 |
+ // Getter |
|
238 |
+ if (showdown.helper.isUndefined(ext)) { |
|
239 |
+ if (!extensions.hasOwnProperty(name)) { |
|
240 |
+ throw Error(`Extension named ${name} is not registered!`); |
|
241 |
+ } |
|
242 |
+ return extensions[name]; |
|
243 |
+ |
|
244 |
+ // Setter |
|
245 |
+ } |
|
246 |
+ // Expand extension if it's wrapped in a function |
|
247 |
+ if (typeof ext === 'function') { |
|
248 |
+ ext = ext(); |
|
249 |
+ } |
|
250 |
+ |
|
251 |
+ // Ensure extension is an array |
|
252 |
+ if (!showdown.helper.isArray(ext)) { |
|
253 |
+ ext = [ext]; |
|
254 |
+ } |
|
255 |
+ |
|
256 |
+ const validExtension = validate(ext, name); |
|
257 |
+ |
|
258 |
+ if (validExtension.valid) { |
|
259 |
+ extensions[name] = ext; |
|
260 |
+ } else { |
|
261 |
+ throw Error(validExtension.error); |
|
262 |
+ } |
|
263 |
+}; |
|
264 |
+ |
|
265 |
+/** |
|
266 |
+ * Gets all extensions registered |
|
267 |
+ * @returns {{}} |
|
268 |
+ */ |
|
269 |
+showdown.getAllExtensions = function () { |
|
270 |
+ return extensions; |
|
271 |
+}; |
|
272 |
+ |
|
273 |
+/** |
|
274 |
+ * Remove an extension |
|
275 |
+ * @param {string} name |
|
276 |
+ */ |
|
277 |
+showdown.removeExtension = function (name) { |
|
278 |
+ delete extensions[name]; |
|
279 |
+}; |
|
280 |
+ |
|
281 |
+/** |
|
282 |
+ * Removes all extensions |
|
283 |
+ */ |
|
284 |
+showdown.resetExtensions = function () { |
|
285 |
+ extensions = {}; |
|
286 |
+}; |
|
287 |
+ |
|
288 |
+/** |
|
289 |
+ * Validate extension |
|
290 |
+ * @param {array} extension |
|
291 |
+ * @param {string} name |
|
292 |
+ * @returns {{valid: boolean, error: string}} |
|
293 |
+ */ |
|
294 |
+function validate(extension, name) { |
|
295 |
+ const errMsg = (name) ? `Error in ${name} extension->` : 'Error in unnamed extension'; |
|
296 |
+ const ret = { |
|
297 |
+ valid: true, |
|
298 |
+ error: '', |
|
299 |
+ }; |
|
300 |
+ |
|
301 |
+ if (!showdown.helper.isArray(extension)) { |
|
302 |
+ extension = [extension]; |
|
303 |
+ } |
|
304 |
+ |
|
305 |
+ for (let i = 0; i < extension.length; ++i) { |
|
306 |
+ const baseMsg = `${errMsg} sub-extension ${i}: `; |
|
307 |
+ const ext = extension[i]; |
|
308 |
+ if (typeof ext !== 'object') { |
|
309 |
+ ret.valid = false; |
|
310 |
+ ret.error = `${baseMsg}must be an object, but ${typeof ext} given`; |
|
311 |
+ return ret; |
|
312 |
+ } |
|
313 |
+ |
|
314 |
+ if (!showdown.helper.isString(ext.type)) { |
|
315 |
+ ret.valid = false; |
|
316 |
+ ret.error = `${baseMsg}property "type" must be a string, but ${typeof ext.type} given`; |
|
317 |
+ return ret; |
|
318 |
+ } |
|
319 |
+ |
|
320 |
+ let type = ext.type = ext.type.toLowerCase(); |
|
321 |
+ |
|
322 |
+ // normalize extension type |
|
323 |
+ if (type === 'language') { |
|
324 |
+ type = ext.type = 'lang'; |
|
325 |
+ } |
|
326 |
+ |
|
327 |
+ if (type === 'html') { |
|
328 |
+ type = ext.type = 'output'; |
|
329 |
+ } |
|
330 |
+ |
|
331 |
+ if (type !== 'lang' && type !== 'output' && type !== 'listener') { |
|
332 |
+ ret.valid = false; |
|
333 |
+ ret.error = `${baseMsg}type ${type} is not recognized. Valid values: "lang/language", "output/html" or "listener"`; |
|
334 |
+ return ret; |
|
335 |
+ } |
|
336 |
+ |
|
337 |
+ if (type === 'listener') { |
|
338 |
+ if (showdown.helper.isUndefined(ext.listeners)) { |
|
339 |
+ ret.valid = false; |
|
340 |
+ ret.error = `${baseMsg}. Extensions of type "listener" must have a property called "listeners"`; |
|
341 |
+ return ret; |
|
342 |
+ } |
|
343 |
+ } else if (showdown.helper.isUndefined(ext.filter) && showdown.helper.isUndefined(ext.regex)) { |
|
344 |
+ ret.valid = false; |
|
345 |
+ ret.error = `${baseMsg + type} extensions must define either a "regex" property or a "filter" method`; |
|
346 |
+ return ret; |
|
347 |
+ } |
|
348 |
+ |
|
349 |
+ if (ext.listeners) { |
|
350 |
+ if (typeof ext.listeners !== 'object') { |
|
351 |
+ ret.valid = false; |
|
352 |
+ ret.error = `${baseMsg}"listeners" property must be an object but ${typeof ext.listeners} given`; |
|
353 |
+ return ret; |
|
354 |
+ } |
|
355 |
+ for (const ln in ext.listeners) { |
|
356 |
+ if (ext.listeners.hasOwnProperty(ln)) { |
|
357 |
+ if (typeof ext.listeners[ln] !== 'function') { |
|
358 |
+ ret.valid = false; |
|
359 |
+ ret.error = `${baseMsg}"listeners" property must be an hash of [event name]: [callback]. listeners.${ln |
|
360 |
+ } must be a function but ${typeof ext.listeners[ln]} given`; |
|
361 |
+ return ret; |
|
362 |
+ } |
|
363 |
+ } |
|
364 |
+ } |
|
365 |
+ } |
|
366 |
+ |
|
367 |
+ if (ext.filter) { |
|
368 |
+ if (typeof ext.filter !== 'function') { |
|
369 |
+ ret.valid = false; |
|
370 |
+ ret.error = `${baseMsg}"filter" must be a function, but ${typeof ext.filter} given`; |
|
371 |
+ return ret; |
|
372 |
+ } |
|
373 |
+ } else if (ext.regex) { |
|
374 |
+ if (showdown.helper.isString(ext.regex)) { |
|
375 |
+ ext.regex = new RegExp(ext.regex, 'g'); |
|
376 |
+ } |
|
377 |
+ if (!ext.regex instanceof RegExp) { |
|
378 |
+ ret.valid = false; |
|
379 |
+ ret.error = `${baseMsg}"regex" property must either be a string or a RegExp object, but ${typeof ext.regex} given`; |
|
380 |
+ return ret; |
|
381 |
+ } |
|
382 |
+ if (showdown.helper.isUndefined(ext.replace)) { |
|
383 |
+ ret.valid = false; |
|
384 |
+ ret.error = `${baseMsg}"regex" extensions must implement a replace string or function`; |
|
385 |
+ return ret; |
|
386 |
+ } |
|
387 |
+ } |
|
388 |
+ } |
|
389 |
+ return ret; |
|
390 |
+} |
|
391 |
+ |
|
392 |
+/** |
|
393 |
+ * Validate extension |
|
394 |
+ * @param {object} ext |
|
395 |
+ * @returns {boolean} |
|
396 |
+ */ |
|
397 |
+showdown.validateExtension = function (ext) { |
|
398 |
+ const validateExtension = validate(ext, null); |
|
399 |
+ if (!validateExtension.valid) { |
|
400 |
+ console.warn(validateExtension.error); |
|
401 |
+ return false; |
|
402 |
+ } |
|
403 |
+ return true; |
|
404 |
+}; |
|
405 |
+ |
|
406 |
+/** |
|
407 |
+ * showdownjs helper functions |
|
408 |
+ */ |
|
409 |
+ |
|
410 |
+if (!showdown.hasOwnProperty('helper')) { |
|
411 |
+ showdown.helper = {}; |
|
412 |
+} |
|
413 |
+ |
|
414 |
+/** |
|
415 |
+ * Check if var is string |
|
416 |
+ * @static |
|
417 |
+ * @param {string} a |
|
418 |
+ * @returns {boolean} |
|
419 |
+ */ |
|
420 |
+showdown.helper.isString = function isString(a) { |
|
421 |
+ return (typeof a === 'string' || a instanceof String); |
|
422 |
+}; |
|
423 |
+ |
|
424 |
+/** |
|
425 |
+ * Check if var is a function |
|
426 |
+ * @static |
|
427 |
+ * @param {string} a |
|
428 |
+ * @returns {boolean} |
|
429 |
+ */ |
|
430 |
+showdown.helper.isFunction = function isFunction(a) { |
|
431 |
+ const getType = {}; |
|
432 |
+ return a && getType.toString.call(a) === '[object Function]'; |
|
433 |
+}; |
|
434 |
+ |
|
435 |
+/** |
|
436 |
+ * ForEach helper function |
|
437 |
+ * @static |
|
438 |
+ * @param {*} obj |
|
439 |
+ * @param {function} callback |
|
440 |
+ */ |
|
441 |
+showdown.helper.forEach = function forEach(obj, callback) { |
|
442 |
+ if (typeof obj.forEach === 'function') { |
|
443 |
+ obj.forEach(callback); |
|
444 |
+ } else { |
|
445 |
+ for (let i = 0; i < obj.length; i++) { |
|
446 |
+ callback(obj[i], i, obj); |
|
447 |
+ } |
|
448 |
+ } |
|
449 |
+}; |
|
450 |
+ |
|
451 |
+/** |
|
452 |
+ * isArray helper function |
|
453 |
+ * @static |
|
454 |
+ * @param {*} a |
|
455 |
+ * @returns {boolean} |
|
456 |
+ */ |
|
457 |
+showdown.helper.isArray = function isArray(a) { |
|
458 |
+ return a.constructor === Array; |
|
459 |
+}; |
|
460 |
+ |
|
461 |
+/** |
|
462 |
+ * Check if value is undefined |
|
463 |
+ * @static |
|
464 |
+ * @param {*} value The value to check. |
|
465 |
+ * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`. |
|
466 |
+ */ |
|
467 |
+showdown.helper.isUndefined = function isUndefined(value) { |
|
468 |
+ return typeof value === 'undefined'; |
|
469 |
+}; |
|
470 |
+ |
|
471 |
+/** |
|
472 |
+ * Standardidize extension name |
|
473 |
+ * @static |
|
474 |
+ * @param {string} s extension name |
|
475 |
+ * @returns {string} |
|
476 |
+ */ |
|
477 |
+showdown.helper.stdExtName = function (s) { |
|
478 |
+ return s.replace(/[_-]||\s/g, '').toLowerCase(); |
|
479 |
+}; |
|
480 |
+ |
|
481 |
+function escapeCharactersCallback(wholeMatch, m1) { |
|
482 |
+ const charCodeToEscape = m1.charCodeAt(0); |
|
483 |
+ return `~E${charCodeToEscape}E`; |
|
484 |
+} |
|
485 |
+ |
|
486 |
+/** |
|
487 |
+ * Callback used to escape characters when passing through String.replace |
|
488 |
+ * @static |
|
489 |
+ * @param {string} wholeMatch |
|
490 |
+ * @param {string} m1 |
|
491 |
+ * @returns {string} |
|
492 |
+ */ |
|
493 |
+showdown.helper.escapeCharactersCallback = escapeCharactersCallback; |
|
494 |
+ |
|
495 |
+/** |
|
496 |
+ * Escape characters in a string |
|
497 |
+ * @static |
|
498 |
+ * @param {string} text |
|
499 |
+ * @param {string} charsToEscape |
|
500 |
+ * @param {boolean} afterBackslash |
|
501 |
+ * @returns {XML|string|void|*} |
|
502 |
+ */ |
|
503 |
+showdown.helper.escapeCharacters = function escapeCharacters(text, charsToEscape, afterBackslash) { |
|
504 |
+ // First we have to escape the escape characters so that |
|
505 |
+ // we can build a character class out of them |
|
506 |
+ let regexString = `([${charsToEscape.replace(/([\[\]\\])/g, '\\$1')}])`; |
|
507 |
+ |
|
508 |
+ if (afterBackslash) { |
|
509 |
+ regexString = `\\\\${regexString}`; |
|
510 |
+ } |
|
511 |
+ |
|
512 |
+ const regex = new RegExp(regexString, 'g'); |
|
513 |
+ text = text.replace(regex, escapeCharactersCallback); |
|
514 |
+ |
|
515 |
+ return text; |
|
516 |
+}; |
|
517 |
+ |
|
518 |
+const rgxFindMatchPos = function (str, left, right, flags) { |
|
519 |
+ const f = flags || ''; |
|
520 |
+ const g = f.indexOf('g') > -1; |
|
521 |
+ const x = new RegExp(`${left}|${right}`, `g${f.replace(/g/g, '')}`); |
|
522 |
+ const l = new RegExp(left, f.replace(/g/g, '')); |
|
523 |
+ const pos = []; |
|
524 |
+ let t; let s; let m; let start; let |
|
525 |
+ end; |
|
526 |
+ |
|
527 |
+ do { |
|
528 |
+ t = 0; |
|
529 |
+ while ((m = x.exec(str))) { |
|
530 |
+ if (l.test(m[0])) { |
|
531 |
+ if (!(t++)) { |
|
532 |
+ s = x.lastIndex; |
|
533 |
+ start = s - m[0].length; |
|
534 |
+ } |
|
535 |
+ } else if (t) { |
|
536 |
+ if (!--t) { |
|
537 |
+ end = m.index + m[0].length; |
|
538 |
+ const obj = { |
|
539 |
+ left: { start, end: s }, |
|
540 |
+ match: { start: s, end: m.index }, |
|
541 |
+ right: { start: m.index, end }, |
|
542 |
+ wholeMatch: { start, end }, |
|
543 |
+ }; |
|
544 |
+ pos.push(obj); |
|
545 |
+ if (!g) { |
|
546 |
+ return pos; |
|
547 |
+ } |
|
548 |
+ } |
|
549 |
+ } |
|
550 |
+ } |
|
551 |
+ } while (t && (x.lastIndex = s)); |
|
552 |
+ |
|
553 |
+ return pos; |
|
554 |
+}; |
|
555 |
+ |
|
556 |
+/** |
|
557 |
+ * matchRecursiveRegExp |
|
558 |
+ * |
|
559 |
+ * (c) 2007 Steven Levithan <stevenlevithan.com> |
|
560 |
+ * MIT License |
|
561 |
+ * |
|
562 |
+ * Accepts a string to search, a left and right format delimiter |
|
563 |
+ * as regex patterns, and optional regex flags. Returns an array |
|
564 |
+ * of matches, allowing nested instances of left/right delimiters. |
|
565 |
+ * Use the "g" flag to return all matches, otherwise only the |
|
566 |
+ * first is returned. Be careful to ensure that the left and |
|
567 |
+ * right format delimiters produce mutually exclusive matches. |
|
568 |
+ * Backreferences are not supported within the right delimiter |
|
569 |
+ * due to how it is internally combined with the left delimiter. |
|
570 |
+ * When matching strings whose format delimiters are unbalanced |
|
571 |
+ * to the left or right, the output is intentionally as a |
|
572 |
+ * conventional regex library with recursion support would |
|
573 |
+ * produce, e.g. "<<x>" and "<x>>" both produce ["x"] when using |
|
574 |
+ * "<" and ">" as the delimiters (both strings contain a single, |
|
575 |
+ * balanced instance of "<x>"). |
|
576 |
+ * |
|
577 |
+ * examples: |
|
578 |
+ * matchRecursiveRegExp("test", "\\(", "\\)") |
|
579 |
+ * returns: [] |
|
580 |
+ * matchRecursiveRegExp("<t<<e>><s>>t<>", "<", ">", "g") |
|
581 |
+ * returns: ["t<<e>><s>", ""] |
|
582 |
+ * matchRecursiveRegExp("<div id=\"x\">test</div>", "<div\\b[^>]*>", "</div>", "gi") |
|
583 |
+ * returns: ["test"] |
|
584 |
+ */ |
|
585 |
+showdown.helper.matchRecursiveRegExp = function (str, left, right, flags) { |
|
586 |
+ const matchPos = rgxFindMatchPos(str, left, right, flags); |
|
587 |
+ const results = []; |
|
588 |
+ |
|
589 |
+ for (let i = 0; i < matchPos.length; ++i) { |
|
590 |
+ results.push([ |
|
591 |
+ str.slice(matchPos[i].wholeMatch.start, matchPos[i].wholeMatch.end), |
|
592 |
+ str.slice(matchPos[i].match.start, matchPos[i].match.end), |
|
593 |
+ str.slice(matchPos[i].left.start, matchPos[i].left.end), |
|
594 |
+ str.slice(matchPos[i].right.start, matchPos[i].right.end), |
|
595 |
+ ]); |
|
596 |
+ } |
|
597 |
+ return results; |
|
598 |
+}; |
|
599 |
+ |
|
600 |
+/** |
|
601 |
+ * |
|
602 |
+ * @param {string} str |
|
603 |
+ * @param {string|function} replacement |
|
604 |
+ * @param {string} left |
|
605 |
+ * @param {string} right |
|
606 |
+ * @param {string} flags |
|
607 |
+ * @returns {string} |
|
608 |
+ */ |
|
609 |
+showdown.helper.replaceRecursiveRegExp = function (str, replacement, left, right, flags) { |
|
610 |
+ if (!showdown.helper.isFunction(replacement)) { |
|
611 |
+ const repStr = replacement; |
|
612 |
+ replacement = function () { |
|
613 |
+ return repStr; |
|
614 |
+ }; |
|
615 |
+ } |
|
616 |
+ |
|
617 |
+ const matchPos = rgxFindMatchPos(str, left, right, flags); |
|
618 |
+ let finalStr = str; |
|
619 |
+ const lng = matchPos.length; |
|
620 |
+ |
|
621 |
+ if (lng > 0) { |
|
622 |
+ const bits = []; |
|
623 |
+ if (matchPos[0].wholeMatch.start !== 0) { |
|
624 |
+ bits.push(str.slice(0, matchPos[0].wholeMatch.start)); |
|
625 |
+ } |
|
626 |
+ for (let i = 0; i < lng; ++i) { |
|
627 |
+ bits.push( |
|
628 |
+ replacement( |
|
629 |
+ str.slice(matchPos[i].wholeMatch.start, matchPos[i].wholeMatch.end), |
|
630 |
+ str.slice(matchPos[i].match.start, matchPos[i].match.end), |
|
631 |
+ str.slice(matchPos[i].left.start, matchPos[i].left.end), |
|
632 |
+ str.slice(matchPos[i].right.start, matchPos[i].right.end), |
|
633 |
+ ), |
|
634 |
+ ); |
|
635 |
+ if (i < lng - 1) { |
|
636 |
+ bits.push(str.slice(matchPos[i].wholeMatch.end, matchPos[i + 1].wholeMatch.start)); |
|
637 |
+ } |
|
638 |
+ } |
|
639 |
+ if (matchPos[lng - 1].wholeMatch.end < str.length) { |
|
640 |
+ bits.push(str.slice(matchPos[lng - 1].wholeMatch.end)); |
|
641 |
+ } |
|
642 |
+ finalStr = bits.join(''); |
|
643 |
+ } |
|
644 |
+ return finalStr; |
|
645 |
+}; |
|
646 |
+ |
|
647 |
+/** |
|
648 |
+ * POLYFILLS |
|
649 |
+ */ |
|
650 |
+if (showdown.helper.isUndefined(console)) { |
|
651 |
+ console = { |
|
652 |
+ warn(msg) { |
|
653 |
+ alert(msg); |
|
654 |
+ }, |
|
655 |
+ log(msg) { |
|
656 |
+ alert(msg); |
|
657 |
+ }, |
|
658 |
+ error(msg) { |
|
659 |
+ throw msg; |
|
660 |
+ }, |
|
661 |
+ }; |
|
662 |
+} |
|
663 |
+ |
|
664 |
+/** |
|
665 |
+ * Created by Estevao on 31-05-2015. |
|
666 |
+ */ |
|
667 |
+ |
|
668 |
+/** |
|
669 |
+ * Showdown Converter class |
|
670 |
+ * @class |
|
671 |
+ * @param {object} [converterOptions] |
|
672 |
+ * @returns {Converter} |
|
673 |
+ */ |
|
674 |
+showdown.Converter = function (converterOptions) { |
|
675 |
+ const |
|
676 |
+ /** |
|
677 |
+ * Options used by this converter |
|
678 |
+ * @private |
|
679 |
+ * @type {{}} |
|
680 |
+ */ |
|
681 |
+ options = {}; |
|
682 |
+ |
|
683 |
+ /** |
|
684 |
+ * Language extensions used by this converter |
|
685 |
+ * @private |
|
686 |
+ * @type {Array} |
|
687 |
+ */ |
|
688 |
+ const langExtensions = []; |
|
689 |
+ |
|
690 |
+ /** |
|
691 |
+ * Output modifiers extensions used by this converter |
|
692 |
+ * @private |
|
693 |
+ * @type {Array} |
|
694 |
+ */ |
|
695 |
+ const outputModifiers = []; |
|
696 |
+ |
|
697 |
+ /** |
|
698 |
+ * Event listeners |
|
699 |
+ * @private |
|
700 |
+ * @type {{}} |
|
701 |
+ */ |
|
702 |
+ const listeners = {}; |
|
703 |
+ |
|
704 |
+ _constructor(); |
|
705 |
+ |
|
706 |
+ /** |
|
707 |
+ * Converter constructor |
|
708 |
+ * @private |
|
709 |
+ */ |
|
710 |
+ function _constructor() { |
|
711 |
+ converterOptions = converterOptions || {}; |
|
712 |
+ |
|
713 |
+ for (const gOpt in globalOptions) { |
|
714 |
+ if (globalOptions.hasOwnProperty(gOpt)) { |
|
715 |
+ options[gOpt] = globalOptions[gOpt]; |
|
716 |
+ } |
|
717 |
+ } |
|
718 |
+ |
|
719 |
+ // Merge options |
|
720 |
+ if (typeof converterOptions === 'object') { |
|
721 |
+ for (const opt in converterOptions) { |
|
722 |
+ if (converterOptions.hasOwnProperty(opt)) { |
|
723 |
+ options[opt] = converterOptions[opt]; |
|
724 |
+ } |
|
725 |
+ } |
|
726 |
+ } else { |
|
727 |
+ throw Error(`Converter expects the passed parameter to be an object, but ${typeof converterOptions |
|
728 |
+ } was passed instead.`); |
|
729 |
+ } |
|
730 |
+ |
|
731 |
+ if (options.extensions) { |
|
732 |
+ showdown.helper.forEach(options.extensions, _parseExtension); |
|
733 |
+ } |
|
734 |
+ } |
|
735 |
+ |
|
736 |
+ /** |
|
737 |
+ * Parse extension |
|
738 |
+ * @param {*} ext |
|
739 |
+ * @param {string} [name=''] |
|
740 |
+ * @private |
|
741 |
+ */ |
|
742 |
+ function _parseExtension(ext, name) { |
|
743 |
+ name = name || null; |
|
744 |
+ // If it's a string, the extension was previously loaded |
|
745 |
+ if (showdown.helper.isString(ext)) { |
|
746 |
+ ext = showdown.helper.stdExtName(ext); |
|
747 |
+ name = ext; |
|
748 |
+ |
|
749 |
+ // LEGACY_SUPPORT CODE |
|
750 |
+ if (showdown.extensions[ext]) { |
|
751 |
+ console.warn(`DEPRECATION WARNING: ${ext} is an old extension that uses a deprecated loading method.` |
|
752 |
+ + 'Please inform the developer that the extension should be updated!'); |
|
753 |
+ legacyExtensionLoading(showdown.extensions[ext], ext); |
|
754 |
+ return; |
|
755 |
+ // END LEGACY SUPPORT CODE |
|
756 |
+ } if (!showdown.helper.isUndefined(extensions[ext])) { |
|
757 |
+ ext = extensions[ext]; |
|
758 |
+ } else { |
|
759 |
+ throw Error(`Extension "${ext}" could not be loaded. It was either not found or is not a valid extension.`); |
|
760 |
+ } |
|
761 |
+ } |
|
762 |
+ |
|
763 |
+ if (typeof ext === 'function') { |
|
764 |
+ ext = ext(); |
|
765 |
+ } |
|
766 |
+ |
|
767 |
+ if (!showdown.helper.isArray(ext)) { |
|
768 |
+ ext = [ext]; |
|
769 |
+ } |
|
770 |
+ |
|
771 |
+ const validExt = validate(ext, name); |
|
772 |
+ if (!validExt.valid) { |
|
773 |
+ throw Error(validExt.error); |
|
774 |
+ } |
|
775 |
+ |
|
776 |
+ for (let i = 0; i < ext.length; ++i) { |
|
777 |
+ switch (ext[i].type) { |
|
778 |
+ case 'lang': |
|
779 |
+ langExtensions.push(ext[i]); |
|
780 |
+ break; |
|
781 |
+ |
|
782 |
+ case 'output': |
|
783 |
+ outputModifiers.push(ext[i]); |
|
784 |
+ break; |
|
785 |
+ } |
|
786 |
+ if (ext[i].hasOwnProperty(listeners)) { |
|
787 |
+ for (const ln in ext[i].listeners) { |
|
788 |
+ if (ext[i].listeners.hasOwnProperty(ln)) { |
|
789 |
+ listen(ln, ext[i].listeners[ln]); |
|
790 |
+ } |
|
791 |
+ } |
|
792 |
+ } |
|
793 |
+ } |
|
794 |
+ } |
|
795 |
+ |
|
796 |
+ /** |
|
797 |
+ * LEGACY_SUPPORT |
|
798 |
+ * @param {*} ext |
|
799 |
+ * @param {string} name |
|
800 |
+ */ |
|
801 |
+ function legacyExtensionLoading(ext, name) { |
|
802 |
+ if (typeof ext === 'function') { |
|
803 |
+ ext = ext(new showdown.Converter()); |
|
804 |
+ } |
|
805 |
+ if (!showdown.helper.isArray(ext)) { |
|
806 |
+ ext = [ext]; |
|
807 |
+ } |
|
808 |
+ const valid = validate(ext, name); |
|
809 |
+ |
|
810 |
+ if (!valid.valid) { |
|
811 |
+ throw Error(valid.error); |
|
812 |
+ } |
|
813 |
+ |
|
814 |
+ for (let i = 0; i < ext.length; ++i) { |
|
815 |
+ switch (ext[i].type) { |
|
816 |
+ case 'lang': |
|
817 |
+ langExtensions.push(ext[i]); |
|
818 |
+ break; |
|
819 |
+ case 'output': |
|
820 |
+ outputModifiers.push(ext[i]); |
|
821 |
+ break; |
|
822 |
+ default:// should never reach here |
|
823 |
+ throw Error('Extension loader error: Type unrecognized!!!'); |
|
824 |
+ } |
|
825 |
+ } |
|
826 |
+ } |
|
827 |
+ |
|
828 |
+ /** |
|
829 |
+ * Listen to an event |
|
830 |
+ * @param {string} name |
|
831 |
+ * @param {function} callback |
|
832 |
+ */ |
|
833 |
+ function listen(name, callback) { |
|
834 |
+ if (!showdown.helper.isString(name)) { |
|
835 |
+ throw Error(`Invalid argument in converter.listen() method: name must be a string, but ${typeof name} given`); |
|
836 |
+ } |
|
837 |
+ |
|
838 |
+ if (typeof callback !== 'function') { |
|
839 |
+ throw Error(`Invalid argument in converter.listen() method: callback must be a function, but ${typeof callback} given`); |
|
840 |
+ } |
|
841 |
+ |
|
842 |
+ if (!listeners.hasOwnProperty(name)) { |
|
843 |
+ listeners[name] = []; |
|
844 |
+ } |
|
845 |
+ listeners[name].push(callback); |
|
846 |
+ } |
|
847 |
+ |
|
848 |
+ function rTrimInputText(text) { |
|
849 |
+ const rsp = text.match(/^\s*/)[0].length; |
|
850 |
+ const rgx = new RegExp(`^\\s{0,${rsp}}`, 'gm'); |
|
851 |
+ return text.replace(rgx, ''); |
|
852 |
+ } |
|
853 |
+ |
|
854 |
+ /** |
|
855 |
+ * Dispatch an event |
|
856 |
+ * @private |
|
857 |
+ * @param {string} evtName Event name |
|
858 |
+ * @param {string} text Text |
|
859 |
+ * @param {{}} options Converter Options |
|
860 |
+ * @param {{}} globals |
|
861 |
+ * @returns {string} |
|
862 |
+ */ |
|
863 |
+ this._dispatch = function dispatch(evtName, text, options, globals) { |
|
864 |
+ if (listeners.hasOwnProperty(evtName)) { |
|
865 |
+ for (let ei = 0; ei < listeners[evtName].length; ++ei) { |
|
866 |
+ const nText = listeners[evtName][ei](evtName, text, this, options, globals); |
|
867 |
+ if (nText && typeof nText !== 'undefined') { |
|
868 |
+ text = nText; |
|
869 |
+ } |
|
870 |
+ } |
|
871 |
+ } |
|
872 |
+ return text; |
|
873 |
+ }; |
|
874 |
+ |
|
875 |
+ /** |
|
876 |
+ * Listen to an event |
|
877 |
+ * @param {string} name |
|
878 |
+ * @param {function} callback |
|
879 |
+ * @returns {showdown.Converter} |
|
880 |
+ */ |
|
881 |
+ this.listen = function (name, callback) { |
|
882 |
+ listen(name, callback); |
|
883 |
+ return this; |
|
884 |
+ }; |
|
885 |
+ |
|
886 |
+ /** |
|
887 |
+ * Converts a markdown string into HTML |
|
888 |
+ * @param {string} text |
|
889 |
+ * @returns {*} |
|
890 |
+ */ |
|
891 |
+ this.makeHtml = function (text) { |
|
892 |
+ // check if text is not falsy |
|
893 |
+ if (!text) { |
|
894 |
+ return text; |
|
895 |
+ } |
|
896 |
+ |
|
897 |
+ const globals = { |
|
898 |
+ gHtmlBlocks: [], |
|
899 |
+ gHtmlMdBlocks: [], |
|
900 |
+ gHtmlSpans: [], |
|
901 |
+ gUrls: {}, |
|
902 |
+ gTitles: {}, |
|
903 |
+ gDimensions: {}, |
|
904 |
+ gListLevel: 0, |
|
905 |
+ hashLinkCounts: {}, |
|
906 |
+ langExtensions, |
|
907 |
+ outputModifiers, |
|
908 |
+ converter: this, |
|
909 |
+ ghCodeBlocks: [], |
|
910 |
+ }; |
|
911 |
+ |
|
912 |
+ // attacklab: Replace ~ with ~T |
|
913 |
+ // This lets us use tilde as an escape char to avoid md5 hashes |
|
914 |
+ // The choice of character is arbitrary; anything that isn't |
|
915 |
+ // magic in Markdown will work. |
|
916 |
+ text = text.replace(/~/g, '~T'); |
|
917 |
+ |
|
918 |
+ // attacklab: Replace $ with ~D |
|
919 |
+ // RegExp interprets $ as a special character |
|
920 |
+ // when it's in a replacement string |
|
921 |
+ text = text.replace(/\$/g, '~D'); |
|
922 |
+ |
|
923 |
+ // Standardize line endings |
|
924 |
+ text = text.replace(/\r\n/g, '\n'); // DOS to Unix |
|
925 |
+ text = text.replace(/\r/g, '\n'); // Mac to Unix |
|
926 |
+ |
|
927 |
+ if (options.smartIndentationFix) { |
|
928 |
+ text = rTrimInputText(text); |
|
929 |
+ } |
|
930 |
+ |
|
931 |
+ // Make sure text begins and ends with a couple of newlines: |
|
932 |
+ // text = '\n\n' + text + '\n\n'; |
|
933 |
+ text = text; |
|
934 |
+ // detab |
|
935 |
+ text = showdown.subParser('detab')(text, options, globals); |
|
936 |
+ |
|
937 |
+ // stripBlankLines |
|
938 |
+ text = showdown.subParser('stripBlankLines')(text, options, globals); |
|
939 |
+ |
|
940 |
+ // run languageExtensions |
|
941 |
+ showdown.helper.forEach(langExtensions, (ext) => { |
|
942 |
+ text = showdown.subParser('runExtension')(ext, text, options, globals); |
|
943 |
+ }); |
|
944 |
+ |
|
945 |
+ // run the sub parsers |
|
946 |
+ text = showdown.subParser('hashPreCodeTags')(text, options, globals); |
|
947 |
+ text = showdown.subParser('githubCodeBlocks')(text, options, globals); |
|
948 |
+ text = showdown.subParser('hashHTMLBlocks')(text, options, globals); |
|
949 |
+ text = showdown.subParser('hashHTMLSpans')(text, options, globals); |
|
950 |
+ text = showdown.subParser('stripLinkDefinitions')(text, options, globals); |
|
951 |
+ text = showdown.subParser('blockGamut')(text, options, globals); |
|
952 |
+ text = showdown.subParser('unhashHTMLSpans')(text, options, globals); |
|
953 |
+ text = showdown.subParser('unescapeSpecialChars')(text, options, globals); |
|
954 |
+ |
|
955 |
+ // attacklab: Restore dollar signs |
|
956 |
+ text = text.replace(/~D/g, '$$'); |
|
957 |
+ |
|
958 |
+ // attacklab: Restore tildes |
|
959 |
+ text = text.replace(/~T/g, '~'); |
|
960 |
+ |
|
961 |
+ // Run output modifiers |
|
962 |
+ showdown.helper.forEach(outputModifiers, (ext) => { |
|
963 |
+ text = showdown.subParser('runExtension')(ext, text, options, globals); |
|
964 |
+ }); |
|
965 |
+ return text; |
|
966 |
+ }; |
|
967 |
+ |
|
968 |
+ /** |
|
969 |
+ * Set an option of this Converter instance |
|
970 |
+ * @param {string} key |
|
971 |
+ * @param {*} value |
|
972 |
+ */ |
|
973 |
+ this.setOption = function (key, value) { |
|
974 |
+ options[key] = value; |
|
975 |
+ }; |
|
976 |
+ |
|
977 |
+ /** |
|
978 |
+ * Get the option of this Converter instance |
|
979 |
+ * @param {string} key |
|
980 |
+ * @returns {*} |
|
981 |
+ */ |
|
982 |
+ this.getOption = function (key) { |
|
983 |
+ return options[key]; |
|
984 |
+ }; |
|
985 |
+ |
|
986 |
+ /** |
|
987 |
+ * Get the options of this Converter instance |
|
988 |
+ * @returns {{}} |
|
989 |
+ */ |
|
990 |
+ this.getOptions = function () { |
|
991 |
+ return options; |
|
992 |
+ }; |
|
993 |
+ |
|
994 |
+ /** |
|
995 |
+ * Add extension to THIS converter |
|
996 |
+ * @param {{}} extension |
|
997 |
+ * @param {string} [name=null] |
|
998 |
+ */ |
|
999 |
+ this.addExtension = function (extension, name) { |
|
1000 |
+ name = name || null; |
|
1001 |
+ _parseExtension(extension, name); |
|
1002 |
+ }; |
|
1003 |
+ |
|
1004 |
+ /** |
|
1005 |
+ * Use a global registered extension with THIS converter |
|
1006 |
+ * @param {string} extensionName Name of the previously registered extension |
|
1007 |
+ */ |
|
1008 |
+ this.useExtension = function (extensionName) { |
|
1009 |
+ _parseExtension(extensionName); |
|
1010 |
+ }; |
|
1011 |
+ |
|
1012 |
+ /** |
|
1013 |
+ * Set the flavor THIS converter should use |
|
1014 |
+ * @param {string} name |
|
1015 |
+ */ |
|
1016 |
+ this.setFlavor = function (name) { |
|
1017 |
+ if (flavor.hasOwnProperty(name)) { |
|
1018 |
+ const preset = flavor[name]; |
|
1019 |
+ for (const option in preset) { |
|
1020 |
+ if (preset.hasOwnProperty(option)) { |
|
1021 |
+ options[option] = preset[option]; |
|
1022 |
+ } |
|
1023 |
+ } |
|
1024 |
+ } |
|
1025 |
+ }; |
|
1026 |
+ |
|
1027 |
+ /** |
|
1028 |
+ * Remove an extension from THIS converter. |
|
1029 |
+ * Note: This is a costly operation. It's better to initialize a new converter |
|
1030 |
+ * and specify the extensions you wish to use |
|
1031 |
+ * @param {Array} extension |
|
1032 |
+ */ |
|
1033 |
+ this.removeExtension = function (extension) { |
|
1034 |
+ if (!showdown.helper.isArray(extension)) { |
|
1035 |
+ extension = [extension]; |
|
1036 |
+ } |
|
1037 |
+ for (let a = 0; a < extension.length; ++a) { |
|
1038 |
+ const ext = extension[a]; |
|
1039 |
+ for (var i = 0; i < langExtensions.length; ++i) { |
|
1040 |
+ if (langExtensions[i] === ext) { |
|
1041 |
+ langExtensions[i].splice(i, 1); |
|
1042 |
+ } |
|
1043 |
+ } |
|
1044 |
+ for (let ii = 0; ii < outputModifiers.length; ++i) { |
|
1045 |
+ if (outputModifiers[ii] === ext) { |
|
1046 |
+ outputModifiers[ii].splice(i, 1); |
|
1047 |
+ } |
|
1048 |
+ } |
|
1049 |
+ } |
|
1050 |
+ }; |
|
1051 |
+ |
|
1052 |
+ /** |
|
1053 |
+ * Get all extension of THIS converter |
|
1054 |
+ * @returns {{language: Array, output: Array}} |
|
1055 |
+ */ |
|
1056 |
+ this.getAllExtensions = function () { |
|
1057 |
+ return { |
|
1058 |
+ language: langExtensions, |
|
1059 |
+ output: outputModifiers, |
|
1060 |
+ }; |
|
1061 |
+ }; |
|
1062 |
+}; |
|
1063 |
+ |
|
1064 |
+/** |
|
1065 |
+ * Turn Markdown link shortcuts into XHTML <a> tags. |
|
1066 |
+ */ |
|
1067 |
+showdown.subParser('anchors', (text, options, globals) => { |
|
1068 |
+ text = globals.converter._dispatch('anchors.before', text, options, globals); |
|
1069 |
+ |
|
1070 |
+ const writeAnchorTag = function (wholeMatch, m1, m2, m3, m4, m5, m6, m7) { |
|
1071 |
+ if (showdown.helper.isUndefined(m7)) { |
|
1072 |
+ m7 = ''; |
|
1073 |
+ } |
|
1074 |
+ wholeMatch = m1; |
|
1075 |
+ const linkText = m2; |
|
1076 |
+ let linkId = m3.toLowerCase(); |
|
1077 |
+ let url = m4; |
|
1078 |
+ let title = m7; |
|
1079 |
+ |
|
1080 |
+ if (!url) { |
|
1081 |
+ if (!linkId) { |
|
1082 |
+ // lower-case and turn embedded newlines into spaces |
|
1083 |
+ linkId = linkText.toLowerCase().replace(/ ?\n/g, ' '); |
|
1084 |
+ } |
|
1085 |
+ url = `#${linkId}`; |
|
1086 |
+ |
|
1087 |
+ if (!showdown.helper.isUndefined(globals.gUrls[linkId])) { |
|
1088 |
+ url = globals.gUrls[linkId]; |
|
1089 |
+ if (!showdown.helper.isUndefined(globals.gTitles[linkId])) { |
|
1090 |
+ title = globals.gTitles[linkId]; |
|
1091 |
+ } |
|
1092 |
+ } else if (wholeMatch.search(/\(\s*\)$/m) > -1) { |
|
1093 |
+ // Special case for explicit empty url |
|
1094 |
+ url = ''; |
|
1095 |
+ } else { |
|
1096 |
+ return wholeMatch; |
|
1097 |
+ } |
|
1098 |
+ } |
|
1099 |
+ |
|
1100 |
+ url = showdown.helper.escapeCharacters(url, '*_', false); |
|
1101 |
+ let result = `<a href="${url}"`; |
|
1102 |
+ |
|
1103 |
+ if (title !== '' && title !== null) { |
|
1104 |
+ title = title.replace(/"/g, '"'); |
|
1105 |
+ title = showdown.helper.escapeCharacters(title, '*_', false); |
|
1106 |
+ result += ` title="${title}"`; |
|
1107 |
+ } |
|
1108 |
+ |
|
1109 |
+ result += `>${linkText}</a>`; |
|
1110 |
+ |
|
1111 |
+ return result; |
|
1112 |
+ }; |
|
1113 |
+ |
|
1114 |
+ // First, handle reference-style links: [link text] [id] |
|
1115 |
+ /* |
|
1116 |
+ text = text.replace(/ |
|
1117 |
+ ( // wrap whole match in $1 |
|
1118 |
+ \[ |
|
1119 |
+ ( |
|
1120 |
+ (?: |
|
1121 |
+ \[[^\]]*\] // allow brackets nested one level |
|
1122 |
+ | |
|
1123 |
+ [^\[] // or anything else |
|
1124 |
+ )* |
|
1125 |
+ ) |
|
1126 |
+ \] |
|
1127 |
+ |
|
1128 |
+ [ ]? // one optional space |
|
1129 |
+ (?:\n[ ]*)? // one optional newline followed by spaces |
|
1130 |
+ |
|
1131 |
+ \[ |
|
1132 |
+ (.*?) // id = $3 |
|
1133 |
+ \] |
|
1134 |
+ )()()()() // pad remaining backreferences |
|
1135 |
+ /g,_DoAnchors_callback); |
|
1136 |
+ */ |
|
1137 |
+ text = text.replace(/(\[((?:\[[^\]]*]|[^\[\]])*)][ ]?(?:\n[ ]*)?\[(.*?)])()()()()/g, writeAnchorTag); |
|
1138 |
+ |
|
1139 |
+ // |
|
1140 |
+ // Next, inline-style links: [link text](url "optional title") |
|
1141 |
+ // |
|
1142 |
+ |
|
1143 |
+ /* |
|
1144 |
+ text = text.replace(/ |
|
1145 |
+ ( // wrap whole match in $1 |
|
1146 |
+ \[ |
|
1147 |
+ ( |
|
1148 |
+ (?: |
|
1149 |
+ \[[^\]]*\] // allow brackets nested one level |
|
1150 |
+ | |
|
1151 |
+ [^\[\]] // or anything else |
|
1152 |
+ ) |
|
1153 |
+ ) |
|
1154 |
+ \] |
|
1155 |
+ \( // literal paren |
|
1156 |
+ [ \t]* |
|
1157 |
+ () // no id, so leave $3 empty |
|
1158 |
+ <?(.*?)>? // href = $4 |
|
1159 |
+ [ \t]* |
|
1160 |
+ ( // $5 |
|
1161 |
+ (['"]) // quote char = $6 |
|
1162 |
+ (.*?) // Title = $7 |
|
1163 |
+ \6 // matching quote |
|
1164 |
+ [ \t]* // ignore any spaces/tabs between closing quote and ) |
|
1165 |
+ )? // title is optional |
|
1166 |
+ \) |
|
1167 |
+ ) |
|
1168 |
+ /g,writeAnchorTag); |
|
1169 |
+ */ |
|
1170 |
+ text = text.replace(/(\[((?:\[[^\]]*]|[^\[\]])*)]\([ \t]*()<?(.*?(?:\(.*?\).*?)?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g, |
|
1171 |
+ writeAnchorTag); |
|
1172 |
+ |
|
1173 |
+ // |
|
1174 |
+ // Last, handle reference-style shortcuts: [link text] |
|
1175 |
+ // These must come last in case you've also got [link test][1] |
|
1176 |
+ // or [link test](/foo) |
|
1177 |
+ // |
|
1178 |
+ |
|
1179 |
+ /* |
|
1180 |
+ text = text.replace(/ |
|
1181 |
+ ( // wrap whole match in $1 |
|
1182 |
+ \[ |
|
1183 |
+ ([^\[\]]+) // link text = $2; can't contain '[' or ']' |
|
1184 |
+ \] |
|
1185 |
+ )()()()()() // pad rest of backreferences |
|
1186 |
+ /g, writeAnchorTag); |
|
1187 |
+ */ |
|
1188 |
+ text = text.replace(/(\[([^\[\]]+)])()()()()()/g, writeAnchorTag); |
|
1189 |
+ |
|
1190 |
+ text = globals.converter._dispatch('anchors.after', text, options, globals); |
|
1191 |
+ return text; |
|
1192 |
+}); |
|
1193 |
+ |
|
1194 |
+showdown.subParser('autoLinks', (text, options, globals) => { |
|
1195 |
+ text = globals.converter._dispatch('autoLinks.before', text, options, globals); |
|
1196 |
+ |
|
1197 |
+ const simpleURLRegex = /\b(((https?|ftp|dict):\/\/|www\.)[^'">\s]+\.[^'">\s]+)(?=\s|$)(?!["<>])/gi; |
|
1198 |
+ const delimUrlRegex = /<(((https?|ftp|dict):\/\/|www\.)[^'">\s]+)>/gi; |
|
1199 |
+ const simpleMailRegex = /(?:^|[ \n\t])([A-Za-z0-9!#$%&'*+-/=?^_`\{|}~\.]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)(?:$|[ \n\t])/gi; |
|
1200 |
+ const delimMailRegex = /<(?:mailto:)?([-.\w]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi; |
|
1201 |
+ |
|
1202 |
+ text = text.replace(delimUrlRegex, replaceLink); |
|
1203 |
+ text = text.replace(delimMailRegex, replaceMail); |
|
1204 |
+ // simpleURLRegex = /\b(((https?|ftp|dict):\/\/|www\.)[-.+~:?#@!$&'()*,;=[\]\w]+)\b/gi, |
|
1205 |
+ // Email addresses: <address@domain.foo> |
|
1206 |
+ |
|
1207 |
+ if (options.simplifiedAutoLink) { |
|
1208 |
+ text = text.replace(simpleURLRegex, replaceLink); |
|
1209 |
+ text = text.replace(simpleMailRegex, replaceMail); |
|
1210 |
+ } |
|
1211 |
+ |
|
1212 |
+ function replaceLink(wm, link) { |
|
1213 |
+ const lnkTxt = link; |
|
1214 |
+ if (/^www\./i.test(link)) { |
|
1215 |
+ link = link.replace(/^www\./i, 'http://www.'); |
|
1216 |
+ } |
|
1217 |
+ return `<a href="${link}">${lnkTxt}</a>`; |
|
1218 |
+ } |
|
1219 |
+ |
|
1220 |
+ function replaceMail(wholeMatch, m1) { |
|
1221 |
+ const unescapedStr = showdown.subParser('unescapeSpecialChars')(m1); |
|
1222 |
+ return showdown.subParser('encodeEmailAddress')(unescapedStr); |
|
1223 |
+ } |
|
1224 |
+ |
|
1225 |
+ text = globals.converter._dispatch('autoLinks.after', text, options, globals); |
|
1226 |
+ |
|
1227 |
+ return text; |
|
1228 |
+}); |
|
1229 |
+ |
|
1230 |
+/** |
|
1231 |
+ * These are all the transformations that form block-level |
|
1232 |
+ * tags like paragraphs, headers, and list items. |
|
1233 |
+ */ |
|
1234 |
+showdown.subParser('blockGamut', (text, options, globals) => { |
|
1235 |
+ text = globals.converter._dispatch('blockGamut.before', text, options, globals); |
|
1236 |
+ |
|
1237 |
+ // we parse blockquotes first so that we can have headings and hrs |
|
1238 |
+ // inside blockquotes |
|
1239 |
+ text = showdown.subParser('blockQuotes')(text, options, globals); |
|
1240 |
+ text = showdown.subParser('headers')(text, options, globals); |
|
1241 |
+ |
|
1242 |
+ // Do Horizontal Rules: |
|
1243 |
+ const key = showdown.subParser('hashBlock')('<hr />', options, globals); |
|
1244 |
+ text = text.replace(/^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$/gm, key); |
|
1245 |
+ text = text.replace(/^[ ]{0,2}([ ]?\-[ ]?){3,}[ \t]*$/gm, key); |
|
1246 |
+ text = text.replace(/^[ ]{0,2}([ ]?_[ ]?){3,}[ \t]*$/gm, key); |
|
1247 |
+ |
|
1248 |
+ text = showdown.subParser('lists')(text, options, globals); |
|
1249 |
+ text = showdown.subParser('codeBlocks')(text, options, globals); |
|
1250 |
+ text = showdown.subParser('tables')(text, options, globals); |
|
1251 |
+ |
|
1252 |
+ // We already ran _HashHTMLBlocks() before, in Markdown(), but that |
|
1253 |
+ // was to escape raw HTML in the original Markdown source. This time, |
|
1254 |
+ // we're escaping the markup we've just created, so that we don't wrap |
|
1255 |
+ // <p> tags around block-level tags. |
|
1256 |
+ text = showdown.subParser('hashHTMLBlocks')(text, options, globals); |
|
1257 |
+ text = showdown.subParser('paragraphs')(text, options, globals); |
|
1258 |
+ |
|
1259 |
+ text = globals.converter._dispatch('blockGamut.after', text, options, globals); |
|
1260 |
+ |
|
1261 |
+ return text; |
|
1262 |
+}); |
|
1263 |
+ |
|
1264 |
+showdown.subParser('blockQuotes', (text, options, globals) => { |
|
1265 |
+ text = globals.converter._dispatch('blockQuotes.before', text, options, globals); |
|
1266 |
+ /* |
|
1267 |
+ text = text.replace(/ |
|
1268 |
+ ( // Wrap whole match in $1 |
|
1269 |
+ ( |
|
1270 |
+ ^[ \t]*>[ \t]? // '>' at the start of a line |
|
1271 |
+ .+\n // rest of the first line |
|
1272 |
+ (.+\n)* // subsequent consecutive lines |
|
1273 |
+ \n* // blanks |
|
1274 |
+ )+ |
|
1275 |
+ ) |
|
1276 |
+ /gm, function(){...}); |
|
1277 |
+ */ |
|
1278 |
+ |
|
1279 |
+ text = text.replace(/((^[ \t]{0,3}>[ \t]?.+\n(.+\n)*\n*)+)/gm, (wholeMatch, m1) => { |
|
1280 |
+ let bq = m1; |
|
1281 |
+ |
|
1282 |
+ // attacklab: hack around Konqueror 3.5.4 bug: |
|
1283 |
+ // "----------bug".replace(/^-/g,"") == "bug" |
|
1284 |
+ bq = bq.replace(/^[ \t]*>[ \t]?/gm, '~0'); // trim one level of quoting |
|
1285 |
+ |
|
1286 |
+ // attacklab: clean up hack |
|
1287 |
+ bq = bq.replace(/~0/g, ''); |
|
1288 |
+ |
|
1289 |
+ bq = bq.replace(/^[ \t]+$/gm, ''); // trim whitespace-only lines |
|
1290 |
+ bq = showdown.subParser('githubCodeBlocks')(bq, options, globals); |
|
1291 |
+ bq = showdown.subParser('blockGamut')(bq, options, globals); // recurse |
|
1292 |
+ |
|
1293 |
+ bq = bq.replace(/(^|\n)/g, '$1 '); |
|
1294 |
+ // These leading spaces screw with <pre> content, so we need to fix that: |
|
1295 |
+ bq = bq.replace(/(\s*<pre>[^\r]+?<\/pre>)/gm, (wholeMatch, m1) => { |
|
1296 |
+ let pre = m1; |
|
1297 |
+ // attacklab: hack around Konqueror 3.5.4 bug: |
|
1298 |
+ pre = pre.replace(/^ {2}/mg, '~0'); |
|
1299 |
+ pre = pre.replace(/~0/g, ''); |
|
1300 |
+ return pre; |
|
1301 |
+ }); |
|
1302 |
+ |
|
1303 |
+ return showdown.subParser('hashBlock')(`<blockquote>\n${bq}\n</blockquote>`, options, globals); |
|
1304 |
+ }); |
|
1305 |
+ |
|
1306 |
+ text = globals.converter._dispatch('blockQuotes.after', text, options, globals); |
|
1307 |
+ return text; |
|
1308 |
+}); |
|
1309 |
+ |
|
1310 |
+/** |
|
1311 |
+ * Process Markdown `<pre><code>` blocks. |
|
1312 |
+ */ |
|
1313 |
+showdown.subParser('codeBlocks', (text, options, globals) => { |
|
1314 |
+ text = globals.converter._dispatch('codeBlocks.before', text, options, globals); |
|
1315 |
+ /* |
|
1316 |
+ text = text.replace(text, |
|
1317 |
+ /(?:\n\n|^) |
|
1318 |
+ ( // $1 = the code block -- one or more lines, starting with a space/tab |
|
1319 |
+ (?: |
|
1320 |
+ (?:[ ]{4}|\t) // Lines must start with a tab or a tab-width of spaces - attacklab: g_tab_width |
|
1321 |
+ .*\n+ |
|
1322 |
+ )+ |
|
1323 |
+ ) |
|
1324 |
+ (\n*[ ]{0,3}[^ \t\n]|(?=~0)) // attacklab: g_tab_width |
|
1325 |
+ /g,function(){...}); |
|
1326 |
+ */ |
|
1327 |
+ |
|
1328 |
+ // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug |
|
1329 |
+ text += '~0'; |
|
1330 |
+ |
|
1331 |
+ const pattern = /(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g; |
|
1332 |
+ text = text.replace(pattern, (wholeMatch, m1, m2) => { |
|
1333 |
+ let codeblock = m1; |
|
1334 |
+ const nextChar = m2; |
|
1335 |
+ let end = '\n'; |
|
1336 |
+ |
|
1337 |
+ codeblock = showdown.subParser('outdent')(codeblock); |
|
1338 |
+ codeblock = showdown.subParser('encodeCode')(codeblock); |
|
1339 |
+ codeblock = showdown.subParser('detab')(codeblock); |
|
1340 |
+ codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines |
|
1341 |
+ codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing newlines |
|
1342 |
+ |
|
1343 |
+ if (options.omitExtraWLInCodeBlocks) { |
|
1344 |
+ end = ''; |
|
1345 |
+ } |
|
1346 |
+ |
|
1347 |
+ codeblock = `<pre><code>${codeblock}${end}</code></pre>`; |
|
1348 |
+ |
|
1349 |
+ return showdown.subParser('hashBlock')(codeblock, options, globals) + nextChar; |
|
1350 |
+ }); |
|
1351 |
+ |
|
1352 |
+ // attacklab: strip sentinel |
|
1353 |
+ text = text.replace(/~0/, ''); |
|
1354 |
+ |
|
1355 |
+ text = globals.converter._dispatch('codeBlocks.after', text, options, globals); |
|
1356 |
+ return text; |
|
1357 |
+}); |
|
1358 |
+ |
|
1359 |
+/** |
|
1360 |
+ * |
|
1361 |
+ * * Backtick quotes are used for <code></code> spans. |
|
1362 |
+ * |
|
1363 |
+ * * You can use multiple backticks as the delimiters if you want to |
|
1364 |
+ * include literal backticks in the code span. So, this input: |
|
1365 |
+ * |
|
1366 |
+ * Just type ``foo `bar` baz`` at the prompt. |
|
1367 |
+ * |
|
1368 |
+ * Will translate to: |
|
1369 |
+ * |
|
1370 |
+ * <p>Just type <code>foo `bar` baz</code> at the prompt.</p> |
|
1371 |
+ * |
|
1372 |
+ * There's no arbitrary limit to the number of backticks you |
|
1373 |
+ * can use as delimters. If you need three consecutive backticks |
|
1374 |
+ * in your code, use four for delimiters, etc. |
|
1375 |
+ * |
|
1376 |
+ * * You can use spaces to get literal backticks at the edges: |
|
1377 |
+ * |
|
1378 |
+ * ... type `` `bar` `` ... |
|
1379 |
+ * |
|
1380 |
+ * Turns to: |
|
1381 |
+ * |
|
1382 |
+ * ... type <code>`bar`</code> ... |
|
1383 |
+ */ |
|
1384 |
+showdown.subParser('codeSpans', (text, options, globals) => { |
|
1385 |
+ text = globals.converter._dispatch('codeSpans.before', text, options, globals); |
|
1386 |
+ |
|
1387 |
+ /* |
|
1388 |
+ text = text.replace(/ |
|
1389 |
+ (^|[^\\]) // Character before opening ` can't be a backslash |
|
1390 |
+ (`+) // $2 = Opening run of ` |
|
1391 |
+ ( // $3 = The code block |
|
1392 |
+ [^\r]*? |
|
1393 |
+ [^`] // attacklab: work around lack of lookbehind |
|
1394 |
+ ) |
|
1395 |
+ \2 // Matching closer |
|
1396 |
+ (?!`) |
|
1397 |
+ /gm, function(){...}); |
|
1398 |
+ */ |
|
1399 |
+ |
|
1400 |
+ if (typeof (text) === 'undefined') { |
|
1401 |
+ text = ''; |
|
1402 |
+ } |
|
1403 |
+ text = text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm, |
|
1404 |
+ (wholeMatch, m1, m2, m3) => { |
|
1405 |
+ let c = m3; |
|
1406 |
+ c = c.replace(/^([ \t]*)/g, ''); // leading whitespace |
|
1407 |
+ c = c.replace(/[ \t]*$/g, ''); // trailing whitespace |
|
1408 |
+ c = showdown.subParser('encodeCode')(c); |
|
1409 |
+ return `${m1}<code>${c}</code>`; |
|
1410 |
+ }); |
|
1411 |
+ |
|
1412 |
+ text = globals.converter._dispatch('codeSpans.after', text, options, globals); |
|
1413 |
+ return text; |
|
1414 |
+}); |
|
1415 |
+ |
|
1416 |
+/** |
|
1417 |
+ * Convert all tabs to spaces |
|
1418 |
+ */ |
|
1419 |
+showdown.subParser('detab', (text) => { |
|
1420 |
+ // expand first n-1 tabs |
|
1421 |
+ text = text.replace(/\t(?=\t)/g, ' '); // g_tab_width |
|
1422 |
+ |
|
1423 |
+ // replace the nth with two sentinels |
|
1424 |
+ text = text.replace(/\t/g, '~A~B'); |
|
1425 |
+ |
|
1426 |
+ // use the sentinel to anchor our regex so it doesn't explode |
|
1427 |
+ text = text.replace(/~B(.+?)~A/g, (wholeMatch, m1) => { |
|
1428 |
+ let leadingText = m1; |
|
1429 |
+ const numSpaces = 4 - leadingText.length % 4; // g_tab_width |
|
1430 |
+ |
|
1431 |
+ // there *must* be a better way to do this: |
|
1432 |
+ for (let i = 0; i < numSpaces; i++) { |
|
1433 |
+ leadingText += ' '; |
|
1434 |
+ } |
|
1435 |
+ |
|
1436 |
+ return leadingText; |
|
1437 |
+ }); |
|
1438 |
+ |
|
1439 |
+ // clean up sentinels |
|
1440 |
+ text = text.replace(/~A/g, ' '); // g_tab_width |
|
1441 |
+ text = text.replace(/~B/g, ''); |
|
1442 |
+ |
|
1443 |
+ return text; |
|
1444 |
+}); |
|
1445 |
+ |
|
1446 |
+/** |
|
1447 |
+ * Smart processing for ampersands and angle brackets that need to be encoded. |
|
1448 |
+ */ |
|
1449 |
+showdown.subParser('encodeAmpsAndAngles', (text) => { |
|
1450 |
+ // Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin: |
|
1451 |
+ // http://bumppo.net/projects/amputator/ |
|
1452 |
+ text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g, '&'); |
|
1453 |
+ |
|
1454 |
+ // Encode naked <'s |
|
1455 |
+ text = text.replace(/<(?![a-z\/?\$!])/gi, '<'); |
|
1456 |
+ |
|
1457 |
+ return text; |
|
1458 |
+}); |
|
1459 |
+ |
|
1460 |
+/** |
|
1461 |
+ * Returns the string, with after processing the following backslash escape sequences. |
|
1462 |
+ * |
|
1463 |
+ * attacklab: The polite way to do this is with the new escapeCharacters() function: |
|
1464 |
+ * |
|
1465 |
+ * text = escapeCharacters(text,"\\",true); |
|
1466 |
+ * text = escapeCharacters(text,"`*_{}[]()>#+-.!",true); |
|
1467 |
+ * |
|
1468 |
+ * ...but we're sidestepping its use of the (slow) RegExp constructor |
|
1469 |
+ * as an optimization for Firefox. This function gets called a LOT. |
|
1470 |
+ */ |
|
1471 |
+showdown.subParser('encodeBackslashEscapes', (text) => { |
|
1472 |
+ text = text.replace(/\\(\\)/g, showdown.helper.escapeCharactersCallback); |
|
1473 |
+ text = text.replace(/\\([`*_{}\[\]()>#+-.!])/g, showdown.helper.escapeCharactersCallback); |
|
1474 |
+ return text; |
|
1475 |
+}); |
|
1476 |
+ |
|
1477 |
+/** |
|
1478 |
+ * Encode/escape certain characters inside Markdown code runs. |
|
1479 |
+ * The point is that in code, these characters are literals, |
|
1480 |
+ * and lose their special Markdown meanings. |
|
1481 |
+ */ |
|
1482 |
+showdown.subParser('encodeCode', (text) => { |
|
1483 |
+ // Encode all ampersands; HTML entities are not |
|
1484 |
+ // entities within a Markdown code span. |
|
1485 |
+ text = text.replace(/&/g, '&'); |
|
1486 |
+ |
|
1487 |
+ // Do the angle bracket song and dance: |
|
1488 |
+ text = text.replace(/</g, '<'); |
|
1489 |
+ text = text.replace(/>/g, '>'); |
|
1490 |
+ |
|
1491 |
+ // Now, escape characters that are magic in Markdown: |
|
1492 |
+ text = showdown.helper.escapeCharacters(text, '*_{}[]\\', false); |
|
1493 |
+ |
|
1494 |
+ // jj the line above breaks this: |
|
1495 |
+ //--- |
|
1496 |
+ //* Item |
|
1497 |
+ // 1. Subitem |
|
1498 |
+ // special char: * |
|
1499 |
+ // --- |
|
1500 |
+ |
|
1501 |
+ return text; |
|
1502 |
+}); |
|
1503 |
+ |
|
1504 |
+/** |
|
1505 |
+ * Input: an email address, e.g. "foo@example.com" |
|
1506 |
+ * |
|
1507 |
+ * Output: the email address as a mailto link, with each character |
|
1508 |
+ * of the address encoded as either a decimal or hex entity, in |
|
1509 |
+ * the hopes of foiling most address harvesting spam bots. E.g.: |
|
1510 |
+ * |
|
1511 |
+ * <a href="mailto:foo@e |
|
1512 |
+ * xample.com">foo |
|
1513 |
+ * @example.com</a> |
|
1514 |
+ * |
|
1515 |
+ * Based on a filter by Matthew Wickline, posted to the BBEdit-Talk |
|
1516 |
+ * mailing list: <http://tinyurl.com/yu7ue> |
|
1517 |
+ * |
|
1518 |
+ */ |
|
1519 |
+showdown.subParser('encodeEmailAddress', (addr) => { |
|
1520 |
+ const encode = [ |
|
1521 |
+ function (ch) { |
|
1522 |
+ return `&#${ch.charCodeAt(0)};`; |
|
1523 |
+ }, |
|
1524 |
+ function (ch) { |
|
1525 |
+ return `&#x${ch.charCodeAt(0).toString(16)};`; |
|
1526 |
+ }, |
|
1527 |
+ function (ch) { |
|
1528 |
+ return ch; |
|
1529 |
+ }, |
|
1530 |
+ ]; |
|
1531 |
+ |
|
1532 |
+ addr = `mailto:${addr}`; |
|
1533 |
+ |
|
1534 |
+ addr = addr.replace(/./g, (ch) => { |
|
1535 |
+ if (ch === '@') { |
|
1536 |
+ // this *must* be encoded. I insist. |
|
1537 |
+ ch = encode[Math.floor(Math.random() * 2)](ch); |
|
1538 |
+ } else if (ch !== ':') { |
|
1539 |
+ // leave ':' alone (to spot mailto: later) |
|
1540 |
+ const r = Math.random(); |
|
1541 |
+ // roughly 10% raw, 45% hex, 45% dec |
|
1542 |
+ ch = ( |
|
1543 |
+ r > 0.9 ? encode[2](ch) : r > 0.45 ? encode[1](ch) : encode[0](ch) |
|
1544 |
+ ); |
|
1545 |
+ } |
|
1546 |
+ return ch; |
|
1547 |
+ }); |
|
1548 |
+ |
|
1549 |
+ addr = `<a href="${addr}">${addr}</a>`; |
|
1550 |
+ addr = addr.replace(/">.+:/g, '">'); // strip the mailto: from the visible part |
|
1551 |
+ |
|
1552 |
+ return addr; |
|
1553 |
+}); |
|
1554 |
+ |
|
1555 |
+/** |
|
1556 |
+ * Within tags -- meaning between < and > -- encode [\ ` * _] so they |
|
1557 |
+ * don't conflict with their use in Markdown for code, italics and strong. |
|
1558 |
+ */ |
|
1559 |
+showdown.subParser('escapeSpecialCharsWithinTagAttributes', (text) => { |
|
1560 |
+ // Build a regex to find HTML tags and comments. See Friedl's |
|
1561 |
+ // "Mastering Regular Expressions", 2nd Ed., pp. 200-201. |
|
1562 |
+ const regex = /(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|<!(--.*?--\s*)+>)/gi; |
|
1563 |
+ |
|
1564 |
+ text = text.replace(regex, (wholeMatch) => { |
|
1565 |
+ let tag = wholeMatch.replace(/(.)<\/?code>(?=.)/g, '$1`'); |
|
1566 |
+ tag = showdown.helper.escapeCharacters(tag, '\\`*_', false); |
|
1567 |
+ return tag; |
|
1568 |
+ }); |
|
1569 |
+ |
|
1570 |
+ return text; |
|
1571 |
+}); |
|
1572 |
+ |
|
1573 |
+/** |
|
1574 |
+ * Handle github codeblocks prior to running HashHTML so that |
|
1575 |
+ * HTML contained within the codeblock gets escaped properly |
|
1576 |
+ * Example: |
|
1577 |
+ * ```ruby |
|
1578 |
+ * def hello_world(x) |
|
1579 |
+ * puts "Hello, #{x}" |
|
1580 |
+ * end |
|
1581 |
+ * ``` |
|
1582 |
+ */ |
|
1583 |
+showdown.subParser('githubCodeBlocks', (text, options, globals) => { |
|
1584 |
+ // early exit if option is not enabled |
|
1585 |
+ if (!options.ghCodeBlocks) { |
|
1586 |
+ return text; |
|
1587 |
+ } |
|
1588 |
+ |
|
1589 |
+ text = globals.converter._dispatch('githubCodeBlocks.before', text, options, globals); |
|
1590 |
+ |
|
1591 |
+ text += '~0'; |
|
1592 |
+ |
|
1593 |
+ text = text.replace(/(?:^|\n)```(.*)\n([\s\S]*?)\n```/g, (wholeMatch, language, codeblock) => { |
|
1594 |
+ const end = (options.omitExtraWLInCodeBlocks) ? '' : '\n'; |
|
1595 |
+ |
|
1596 |
+ // First parse the github code block |
|
1597 |
+ codeblock = showdown.subParser('encodeCode')(codeblock); |
|
1598 |
+ codeblock = showdown.subParser('detab')(codeblock); |
|
1599 |
+ codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines |
|
1600 |
+ codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing whitespace |
|
1601 |
+ |
|
1602 |
+ codeblock = `<pre><code${language ? ` class="${language} language-${language}"` : ''}>${codeblock}${end}</code></pre>`; |
|
1603 |
+ |
|
1604 |
+ codeblock = showdown.subParser('hashBlock')(codeblock, options, globals); |
|
1605 |
+ |
|
1606 |
+ // Since GHCodeblocks can be false positives, we need to |
|
1607 |
+ // store the primitive text and the parsed text in a global var, |
|
1608 |
+ // and then return a token |
|
1609 |
+ return `\n\n~G${globals.ghCodeBlocks.push({ text: wholeMatch, codeblock }) - 1}G\n\n`; |
|
1610 |
+ }); |
|
1611 |
+ |
|
1612 |
+ // attacklab: strip sentinel |
|
1613 |
+ text = text.replace(/~0/, ''); |
|
1614 |
+ |
|
1615 |
+ return globals.converter._dispatch('githubCodeBlocks.after', text, options, globals); |
|
1616 |
+}); |
|
1617 |
+ |
|
1618 |
+showdown.subParser('hashBlock', (text, options, globals) => { |
|
1619 |
+ text = text.replace(/(^\n+|\n+$)/g, ''); |
|
1620 |
+ return `\n\n~K${globals.gHtmlBlocks.push(text) - 1}K\n\n`; |
|
1621 |
+}); |
|
1622 |
+ |
|
1623 |
+showdown.subParser('hashElement', (text, options, globals) => function (wholeMatch, m1) { |
|
1624 |
+ let blockText = m1; |
|
1625 |
+ |
|
1626 |
+ // Undo double lines |
|
1627 |
+ blockText = blockText.replace(/\n\n/g, '\n'); |
|
1628 |
+ blockText = blockText.replace(/^\n/, ''); |
|
1629 |
+ |
|
1630 |
+ // strip trailing blank lines |
|
1631 |
+ blockText = blockText.replace(/\n+$/g, ''); |
|
1632 |
+ |
|
1633 |
+ // Replace the element text with a marker ("~KxK" where x is its key) |
|
1634 |
+ blockText = `\n\n~K${globals.gHtmlBlocks.push(blockText) - 1}K\n\n`; |
|
1635 |
+ |
|
1636 |
+ return blockText; |
|
1637 |
+}); |
|
1638 |
+ |
|
1639 |
+showdown.subParser('hashHTMLBlocks', (text, options, globals) => { |
|
1640 |
+ const blockTags = [ |
|
1641 |
+ 'pre', |
|
1642 |
+ 'div', |
|
1643 |
+ 'h1', |
|
1644 |
+ 'h2', |
|
1645 |
+ 'h3', |
|
1646 |
+ 'h4', |
|
1647 |
+ 'h5', |
|
1648 |
+ 'h6', |
|
1649 |
+ 'blockquote', |
|
1650 |
+ 'table', |
|
1651 |
+ 'dl', |
|
1652 |
+ 'ol', |
|
1653 |
+ 'ul', |
|
1654 |
+ 'script', |
|
1655 |
+ 'noscript', |
|
1656 |
+ 'form', |
|
1657 |
+ 'fieldset', |
|
1658 |
+ 'iframe', |
|
1659 |
+ 'math', |
|
1660 |
+ 'style', |
|
1661 |
+ 'section', |
|
1662 |
+ 'header', |
|
1663 |
+ 'footer', |
|
1664 |
+ 'nav', |
|
1665 |
+ 'article', |
|
1666 |
+ 'aside', |
|
1667 |
+ 'address', |
|
1668 |
+ 'audio', |
|
1669 |
+ 'canvas', |
|
1670 |
+ 'figure', |
|
1671 |
+ 'hgroup', |
|
1672 |
+ 'output', |
|
1673 |
+ 'video', |
|
1674 |
+ 'p', |
|
1675 |
+ ]; |
|
1676 |
+ const repFunc = function (wholeMatch, match, left, right) { |
|
1677 |
+ let txt = wholeMatch; |
|
1678 |
+ // check if this html element is marked as markdown |
|
1679 |
+ // if so, it's contents should be parsed as markdown |
|
1680 |
+ if (left.search(/\bmarkdown\b/) !== -1) { |
|
1681 |
+ txt = left + globals.converter.makeHtml(match) + right; |
|
1682 |
+ } |
|
1683 |
+ return `\n\n~K${globals.gHtmlBlocks.push(txt) - 1}K\n\n`; |
|
1684 |
+ }; |
|
1685 |
+ |
|
1686 |
+ for (let i = 0; i < blockTags.length; ++i) { |
|
1687 |
+ text = showdown.helper.replaceRecursiveRegExp(text, repFunc, `^(?: |\\t){0,3}<${blockTags[i]}\\b[^>]*>`, `</${blockTags[i]}>`, 'gim'); |
|
1688 |
+ } |
|
1689 |
+ |
|
1690 |
+ // HR SPECIAL CASE |
|
1691 |
+ text = text.replace(/(\n[ ]{0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g, |
|
1692 |
+ showdown.subParser('hashElement')(text, options, globals)); |
|
1693 |
+ |
|
1694 |
+ // Special case for standalone HTML comments: |
|
1695 |
+ text = text.replace(/(<!--[\s\S]*?-->)/g, |
|
1696 |
+ showdown.subParser('hashElement')(text, options, globals)); |
|
1697 |
+ |
|
1698 |
+ // PHP and ASP-style processor instructions (<?...?> and <%...%>) |
|
1699 |
+ text = text.replace(/(?:\n\n)([ ]{0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g, |
|
1700 |
+ showdown.subParser('hashElement')(text, options, globals)); |
|
1701 |
+ return text; |
|
1702 |
+}); |
|
1703 |
+ |
|
1704 |
+/** |
|
1705 |
+ * Hash span elements that should not be parsed as markdown |
|
1706 |
+ */ |
|
1707 |
+showdown.subParser('hashHTMLSpans', (text, config, globals) => { |
|
1708 |
+ const matches = showdown.helper.matchRecursiveRegExp(text, '<code\\b[^>]*>', '</code>', 'gi'); |
|
1709 |
+ |
|
1710 |
+ for (let i = 0; i < matches.length; ++i) { |
|
1711 |
+ text = text.replace(matches[i][0], `~L${globals.gHtmlSpans.push(matches[i][0]) - 1}L`); |
|
1712 |
+ } |
|
1713 |
+ return text; |
|
1714 |
+}); |
|
1715 |
+ |
|
1716 |
+/** |
|
1717 |
+ * Unhash HTML spans |
|
1718 |
+ */ |
|
1719 |
+showdown.subParser('unhashHTMLSpans', (text, config, globals) => { |
|
1720 |
+ for (let i = 0; i < globals.gHtmlSpans.length; ++i) { |
|
1721 |
+ text = text.replace(`~L${i}L`, globals.gHtmlSpans[i]); |
|
1722 |
+ } |
|
1723 |
+ |
|
1724 |
+ return text; |
|
1725 |
+}); |
|
1726 |
+ |
|
1727 |
+/** |
|
1728 |
+ * Hash span elements that should not be parsed as markdown |
|
1729 |
+ */ |
|
1730 |
+showdown.subParser('hashPreCodeTags', (text, config, globals) => { |
|
1731 |
+ const repFunc = function (wholeMatch, match, left, right) { |
|
1732 |
+ // encode html entities |
|
1733 |
+ const codeblock = left + showdown.subParser('encodeCode')(match) + right; |
|
1734 |
+ return `\n\n~G${globals.ghCodeBlocks.push({ text: wholeMatch, codeblock }) - 1}G\n\n`; |
|
1735 |
+ }; |
|
1736 |
+ |
|
1737 |
+ text = showdown.helper.replaceRecursiveRegExp(text, repFunc, '^(?: |\\t){0,3}<pre\\b[^>]*>\\s*<code\\b[^>]*>', '^(?: |\\t){0,3}</code>\\s*</pre>', 'gim'); |
|
1738 |
+ return text; |
|
1739 |
+}); |
|
1740 |
+ |
|
1741 |
+showdown.subParser('headers', (text, options, globals) => { |
|
1742 |
+ text = globals.converter._dispatch('headers.before', text, options, globals); |
|
1743 |
+ |
|
1744 |
+ let prefixHeader = options.prefixHeaderId; |
|
1745 |
+ const headerLevelStart = (isNaN(parseInt(options.headerLevelStart))) ? 1 : parseInt(options.headerLevelStart); |
|
1746 |
+ |
|
1747 |
+ // Set text-style headers: |
|
1748 |
+ // Header 1 |
|
1749 |
+ // ======== |
|
1750 |
+ // |
|
1751 |
+ // Header 2 |
|
1752 |
+ // -------- |
|
1753 |
+ // |
|
1754 |
+ const setextRegexH1 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n={2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n=+[ \t]*\n+/gm; |
|
1755 |
+ const setextRegexH2 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n-{2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n-+[ \t]*\n+/gm; |
|
1756 |
+ |
|
1757 |
+ text = text.replace(setextRegexH1, (wholeMatch, m1) => { |
|
1758 |
+ const spanGamut = showdown.subParser('spanGamut')(m1, options, globals); |
|
1759 |
+ const hID = (options.noHeaderId) ? '' : ` id="${headerId(m1)}"`; |
|
1760 |
+ const hLevel = headerLevelStart; |
|
1761 |
+ const hashBlock = `<h${hLevel}${hID}>${spanGamut}</h${hLevel}>`; |
|
1762 |
+ return showdown.subParser('hashBlock')(hashBlock, options, globals); |
|
1763 |
+ }); |
|
1764 |
+ |
|
1765 |
+ text = text.replace(setextRegexH2, (matchFound, m1) => { |
|
1766 |
+ const spanGamut = showdown.subParser('spanGamut')(m1, options, globals); |
|
1767 |
+ const hID = (options.noHeaderId) ? '' : ` id="${headerId(m1)}"`; |
|
1768 |
+ const hLevel = headerLevelStart + 1; |
|
1769 |
+ const hashBlock = `<h${hLevel}${hID}>${spanGamut}</h${hLevel}>`; |
|
1770 |
+ return showdown.subParser('hashBlock')(hashBlock, options, globals); |
|
1771 |
+ }); |
|
1772 |
+ |
|
1773 |
+ // atx-style headers: |
|
1774 |
+ // # Header 1 |
|
1775 |
+ // ## Header 2 |
|
1776 |
+ // ## Header 2 with closing hashes ## |
|
1777 |
+ // ... |
|
1778 |
+ // ###### Header 6 |
|
1779 |
+ // |
|
1780 |
+ text = text.replace(/^(#{1,6})[ \t]*(.+?)[ \t]*#*\n+/gm, (wholeMatch, m1, m2) => { |
|
1781 |
+ const span = showdown.subParser('spanGamut')(m2, options, globals); |
|
1782 |
+ const hID = (options.noHeaderId) ? '' : ` id="${headerId(m2)}"`; |
|
1783 |
+ const hLevel = headerLevelStart - 1 + m1.length; |
|
1784 |
+ const header = `<h${hLevel}${hID}>${span}</h${hLevel}>`; |
|
1785 |
+ |
|
1786 |
+ return showdown.subParser('hashBlock')(header, options, globals); |
|
1787 |
+ }); |
|
1788 |
+ |
|
1789 |
+ function headerId(m) { |
|
1790 |
+ let title; const |
|
1791 |
+ escapedId = m.replace(/[^\w]/g, '').toLowerCase(); |
|
1792 |
+ |
|
1793 |
+ if (globals.hashLinkCounts[escapedId]) { |
|
1794 |
+ title = `${escapedId}-${globals.hashLinkCounts[escapedId]++}`; |
|
1795 |
+ } else { |
|
1796 |
+ title = escapedId; |
|
1797 |
+ globals.hashLinkCounts[escapedId] = 1; |
|
1798 |
+ } |
|
1799 |
+ |
|
1800 |
+ // Prefix id to prevent causing inadvertent pre-existing style matches. |
|
1801 |
+ if (prefixHeader === true) { |
|
1802 |
+ prefixHeader = 'section'; |
|
1803 |
+ } |
|
1804 |
+ |
|
1805 |
+ if (showdown.helper.isString(prefixHeader)) { |
|
1806 |
+ return prefixHeader + title; |
|
1807 |
+ } |
|
1808 |
+ return title; |
|
1809 |
+ } |
|
1810 |
+ |
|
1811 |
+ text = globals.converter._dispatch('headers.after', text, options, globals); |
|
1812 |
+ return text; |
|
1813 |
+}); |
|
1814 |
+ |
|
1815 |
+/** |
|
1816 |
+ * Turn Markdown image shortcuts into <img> tags. |
|
1817 |
+ */ |
|
1818 |
+showdown.subParser('images', (text, options, globals) => { |
|
1819 |
+ text = globals.converter._dispatch('images.before', text, options, globals); |
|
1820 |
+ |
|
1821 |
+ const inlineRegExp = /!\[(.*?)]\s?\([ \t]*()<?(\S+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(['"])(.*?)\6[ \t]*)?\)/g; |
|
1822 |
+ const referenceRegExp = /!\[([^\]]*?)] ?(?:\n *)?\[(.*?)]()()()()()/g; |
|
1823 |
+ |
|
1824 |
+ function writeImageTag(wholeMatch, altText, linkId, url, width, height, m5, title) { |
|
1825 |
+ const { gUrls } = globals; |
|
1826 |
+ const { gTitles } = globals; |
|
1827 |
+ const gDims = globals.gDimensions; |
|
1828 |
+ |
|
1829 |
+ linkId = linkId.toLowerCase(); |
|
1830 |
+ |
|
1831 |
+ if (!title) { |
|
1832 |
+ title = ''; |
|
1833 |
+ } |
|
1834 |
+ |
|
1835 |
+ if (url === '' || url === null) { |
|
1836 |
+ if (linkId === '' || linkId === null) { |
|
1837 |
+ // lower-case and turn embedded newlines into spaces |
|
1838 |
+ linkId = altText.toLowerCase().replace(/ ?\n/g, ' '); |
|
1839 |
+ } |
|
1840 |
+ url = `#${linkId}`; |
|
1841 |
+ |
|
1842 |
+ if (!showdown.helper.isUndefined(gUrls[linkId])) { |
|
1843 |
+ url = gUrls[linkId]; |
|
1844 |
+ if (!showdown.helper.isUndefined(gTitles[linkId])) { |
|
1845 |
+ title = gTitles[linkId]; |
|
1846 |
+ } |
|
1847 |
+ if (!showdown.helper.isUndefined(gDims[linkId])) { |
|
1848 |
+ width = gDims[linkId].width; |
|
1849 |
+ height = gDims[linkId].height; |
|
1850 |
+ } |
|
1851 |
+ } else { |
|
1852 |
+ return wholeMatch; |
|
1853 |
+ } |
|
1854 |
+ } |
|
1855 |
+ |
|
1856 |
+ altText = altText.replace(/"/g, '"'); |
|
1857 |
+ altText = showdown.helper.escapeCharacters(altText, '*_', false); |
|
1858 |
+ url = showdown.helper.escapeCharacters(url, '*_', false); |
|
1859 |
+ let result = `<img src="${url}" alt="${altText}"`; |
|
1860 |
+ |
|
1861 |
+ if (title) { |
|
1862 |
+ title = title.replace(/"/g, '"'); |
|
1863 |
+ title = showdown.helper.escapeCharacters(title, '*_', false); |
|
1864 |
+ result += ` title="${title}"`; |
|
1865 |
+ } |
|
1866 |
+ |
|
1867 |
+ if (width && height) { |
|
1868 |
+ width = (width === '*') ? 'auto' : width; |
|
1869 |
+ height = (height === '*') ? 'auto' : height; |
|
1870 |
+ |
|
1871 |
+ result += ` width="${width}"`; |
|
1872 |
+ result += ` height="${height}"`; |
|
1873 |
+ } |
|
1874 |
+ |
|
1875 |
+ result += ' />'; |
|
1876 |
+ return result; |
|
1877 |
+ } |
|
1878 |
+ |
|
1879 |
+ // First, handle reference-style labeled images: ![alt text][id] |
|
1880 |
+ text = text.replace(referenceRegExp, writeImageTag); |
|
1881 |
+ |
|
1882 |
+ // Next, handle inline images:  |
|
1883 |
+ text = text.replace(inlineRegExp, writeImageTag); |
|
1884 |
+ |
|
1885 |
+ text = globals.converter._dispatch('images.after', text, options, globals); |
|
1886 |
+ return text; |
|
1887 |
+}); |
|
1888 |
+ |
|
1889 |
+showdown.subParser('italicsAndBold', (text, options, globals) => { |
|
1890 |
+ text = globals.converter._dispatch('italicsAndBold.before', text, options, globals); |
|
1891 |
+ |
|
1892 |
+ if (options.literalMidWordUnderscores) { |
|
1893 |
+ // underscores |
|
1894 |
+ // Since we are consuming a \s character, we need to add it |
|
1895 |
+ text = text.replace(/(^|\s|>|\b)__(?=\S)([\s\S]+?)__(?=\b|<|\s|$)/gm, '$1<strong>$2</strong>'); |
|
1896 |
+ text = text.replace(/(^|\s|>|\b)_(?=\S)([\s\S]+?)_(?=\b|<|\s|$)/gm, '$1<em>$2</em>'); |
|
1897 |
+ // asterisks |
|
1898 |
+ text = text.replace(/(\*\*)(?=\S)([^\r]*?\S[*]*)\1/g, '<strong>$2</strong>'); |
|
1899 |
+ text = text.replace(/(\*)(?=\S)([^\r]*?\S)\1/g, '<em>$2</em>'); |
|
1900 |
+ } else { |
|
1901 |
+ // <strong> must go first: |
|
1902 |
+ text = text.replace(/(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g, '<strong>$2</strong>'); |
|
1903 |
+ text = text.replace(/(\*|_)(?=\S)([^\r]*?\S)\1/g, '<em>$2</em>'); |
|
1904 |
+ } |
|
1905 |
+ |
|
1906 |
+ text = globals.converter._dispatch('italicsAndBold.after', text, options, globals); |
|
1907 |
+ return text; |
|
1908 |
+}); |
|
1909 |
+ |
|
1910 |
+/** |
|
1911 |
+ * Form HTML ordered (numbered) and unordered (bulleted) lists. |
|
1912 |
+ */ |
|
1913 |
+showdown.subParser('lists', (text, options, globals) => { |
|
1914 |
+ text = globals.converter._dispatch('lists.before', text, options, globals); |
|
1915 |
+ /** |
|
1916 |
+ * Process the contents of a single ordered or unordered list, splitting it |
|
1917 |
+ * into individual list items. |
|
1918 |
+ * @param {string} listStr |
|
1919 |
+ * @param {boolean} trimTrailing |
|
1920 |
+ * @returns {string} |
|
1921 |
+ */ |
|
1922 |
+ function processListItems(listStr, trimTrailing) { |
|
1923 |
+ // The $g_list_level global keeps track of when we're inside a list. |
|
1924 |
+ // Each time we enter a list, we increment it; when we leave a list, |
|
1925 |
+ // we decrement. If it's zero, we're not in a list anymore. |
|
1926 |
+ // |
|
1927 |
+ // We do this because when we're not inside a list, we want to treat |
|
1928 |
+ // something like this: |
|
1929 |
+ // |
|
1930 |
+ // I recommend upgrading to version |
|
1931 |
+ // 8. Oops, now this line is treated |
|
1932 |
+ // as a sub-list. |
|
1933 |
+ // |
|
1934 |
+ // As a single paragraph, despite the fact that the second line starts |
|
1935 |
+ // with a digit-period-space sequence. |
|
1936 |
+ // |
|
1937 |
+ // Whereas when we're inside a list (or sub-list), that line will be |
|
1938 |
+ // treated as the start of a sub-list. What a kludge, huh? This is |
|
1939 |
+ // an aspect of Markdown's syntax that's hard to parse perfectly |
|
1940 |
+ // without resorting to mind-reading. Perhaps the solution is to |
|
1941 |
+ // change the syntax rules such that sub-lists must start with a |
|
1942 |
+ // starting cardinal number; e.g. "1." or "a.". |
|
1943 |
+ globals.gListLevel++; |
|
1944 |
+ |
|
1945 |
+ // trim trailing blank lines: |
|
1946 |
+ listStr = listStr.replace(/\n{2,}$/, '\n'); |
|
1947 |
+ |
|
1948 |
+ // attacklab: add sentinel to emulate \z |
|
1949 |
+ listStr += '~0'; |
|
1950 |
+ |
|
1951 |
+ const rgx = /(\n)?(^[ \t]*)([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(~0|\2([*+-]|\d+[.])[ \t]+))/gm; |
|
1952 |
+ const isParagraphed = (/\n[ \t]*\n(?!~0)/.test(listStr)); |
|
1953 |
+ |
|
1954 |
+ listStr = listStr.replace(rgx, (wholeMatch, m1, m2, m3, m4, taskbtn, checked) => { |
|
1955 |
+ checked = (checked && checked.trim() !== ''); |
|
1956 |
+ let item = showdown.subParser('outdent')(m4, options, globals); |
|
1957 |
+ let bulletStyle = ''; |
|
1958 |
+ |
|
1959 |
+ // Support for github tasklists |
|
1960 |
+ if (taskbtn && options.tasklists) { |
|
1961 |
+ bulletStyle = ' class="task-list-item" style="list-style-type: none;"'; |
|
1962 |
+ item = item.replace(/^[ \t]*\[(x|X| )?]/m, () => { |
|
1963 |
+ let otp = '<input type="checkbox" disabled style="margin: 0px 0.35em 0.25em -1.6em; vertical-align: middle;"'; |
|
1964 |
+ if (checked) { |
|
1965 |
+ otp += ' checked'; |
|
1966 |
+ } |
|
1967 |
+ otp += '>'; |
|
1968 |
+ return otp; |
|
1969 |
+ }); |
|
1970 |
+ } |
|
1971 |
+ // m1 - Leading line or |
|
1972 |
+ // Has a double return (multi paragraph) or |
|
1973 |
+ // Has sublist |
|
1974 |
+ if (m1 || (item.search(/\n{2,}/) > -1)) { |
|
1975 |
+ item = showdown.subParser('githubCodeBlocks')(item, options, globals); |
|
1976 |
+ item = showdown.subParser('blockGamut')(item, options, globals); |
|
1977 |
+ } else { |
|
1978 |
+ // Recursion for sub-lists: |
|
1979 |
+ item = showdown.subParser('lists')(item, options, globals); |
|
1980 |
+ item = item.replace(/\n$/, ''); // chomp(item) |
|
1981 |
+ if (isParagraphed) { |
|
1982 |
+ item = showdown.subParser('paragraphs')(item, options, globals); |
|
1983 |
+ } else { |
|
1984 |
+ item = showdown.subParser('spanGamut')(item, options, globals); |
|
1985 |
+ } |
|
1986 |
+ } |
|
1987 |
+ item = `\n<li${bulletStyle}>${item}</li>\n`; |
|
1988 |
+ return item; |
|
1989 |
+ }); |
|
1990 |
+ |
|
1991 |
+ // attacklab: strip sentinel |
|
1992 |
+ listStr = listStr.replace(/~0/g, ''); |
|
1993 |
+ |
|
1994 |
+ globals.gListLevel--; |
|
1995 |
+ |
|
1996 |
+ if (trimTrailing) { |
|
1997 |
+ listStr = listStr.replace(/\s+$/, ''); |
|
1998 |
+ } |
|
1999 |
+ |
|
2000 |
+ return listStr; |
|
2001 |
+ } |
|
2002 |
+ |
|
2003 |
+ /** |
|
2004 |
+ * Check and parse consecutive lists (better fix for issue #142) |
|
2005 |
+ * @param {string} list |
|
2006 |
+ * @param {string} listType |
|
2007 |
+ * @param {boolean} trimTrailing |
|
2008 |
+ * @returns {string} |
|
2009 |
+ */ |
|
2010 |
+ function parseConsecutiveLists(list, listType, trimTrailing) { |
|
2011 |
+ // check if we caught 2 or more consecutive lists by mistake |
|
2012 |
+ // we use the counterRgx, meaning if listType is UL we look for UL and vice versa |
|
2013 |
+ let counterRxg = (listType === 'ul') ? /^ {0,2}\d+\.[ \t]/gm : /^ {0,2}[*+-][ \t]/gm; |
|
2014 |
+ const subLists = []; |
|
2015 |
+ let result = ''; |
|
2016 |
+ |
|
2017 |
+ if (list.search(counterRxg) !== -1) { |
|
2018 |
+ (function parseCL(txt) { |
|
2019 |
+ const pos = txt.search(counterRxg); |
|
2020 |
+ if (pos !== -1) { |
|
2021 |
+ // slice |
|
2022 |
+ result += `\n\n<${listType}>${processListItems(txt.slice(0, pos), !!trimTrailing)}</${listType}>\n\n`; |
|
2023 |
+ |
|
2024 |
+ // invert counterType and listType |
|
2025 |
+ listType = (listType === 'ul') ? 'ol' : 'ul'; |
|
2026 |
+ counterRxg = (listType === 'ul') ? /^ {0,2}\d+\.[ \t]/gm : /^ {0,2}[*+-][ \t]/gm; |
|
2027 |
+ |
|
2028 |
+ // recurse |
|
2029 |
+ parseCL(txt.slice(pos)); |
|
2030 |
+ } else { |
|
2031 |
+ result += `\n\n<${listType}>${processListItems(txt, !!trimTrailing)}</${listType}>\n\n`; |
|
2032 |
+ } |
|
2033 |
+ }(list)); |
|
2034 |
+ for (let i = 0; i < subLists.length; ++i) { |
|
2035 |
+ |
|
2036 |
+ } |
|
2037 |
+ } else { |
|
2038 |
+ result = `\n\n<${listType}>${processListItems(list, !!trimTrailing)}</${listType}>\n\n`; |
|
2039 |
+ } |
|
2040 |
+ |
|
2041 |
+ return result; |
|
2042 |
+ } |
|
2043 |
+ |
|
2044 |
+ // attacklab: add sentinel to hack around khtml/safari bug: |
|
2045 |
+ // http://bugs.webkit.org/show_bug.cgi?id=11231 |
|
2046 |
+ text += '~0'; |
|
2047 |
+ |
|
2048 |
+ // Re-usable pattern to match any entire ul or ol list: |
|
2049 |
+ let wholeList = /^(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm; |
|
2050 |
+ |
|
2051 |
+ if (globals.gListLevel) { |
|
2052 |
+ text = text.replace(wholeList, (wholeMatch, list, m2) => { |
|
2053 |
+ const listType = (m2.search(/[*+-]/g) > -1) ? 'ul' : 'ol'; |
|
2054 |
+ return parseConsecutiveLists(list, listType, true); |
|
2055 |
+ }); |
|
2056 |
+ } else { |
|
2057 |
+ wholeList = /(\n\n|^\n?)(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm; |
|
2058 |
+ // wholeList = /(\n\n|^\n?)( {0,3}([*+-]|\d+\.)[ \t]+[\s\S]+?)(?=(~0)|(\n\n(?!\t| {2,}| {0,3}([*+-]|\d+\.)[ \t])))/g; |
|
2059 |
+ text = text.replace(wholeList, (wholeMatch, m1, list, m3) => { |
|
2060 |
+ const listType = (m3.search(/[*+-]/g) > -1) ? 'ul' : 'ol'; |
|
2061 |
+ return parseConsecutiveLists(list, listType); |
|
2062 |
+ }); |
|
2063 |
+ } |
|
2064 |
+ |
|
2065 |
+ // attacklab: strip sentinel |
|
2066 |
+ text = text.replace(/~0/, ''); |
|
2067 |
+ |
|
2068 |
+ text = globals.converter._dispatch('lists.after', text, options, globals); |
|
2069 |
+ return text; |
|
2070 |
+}); |
|
2071 |
+ |
|
2072 |
+/** |
|
2073 |
+ * Remove one level of line-leading tabs or spaces |
|
2074 |
+ */ |
|
2075 |
+showdown.subParser('outdent', (text) => { |
|
2076 |
+ // attacklab: hack around Konqueror 3.5.4 bug: |
|
2077 |
+ // "----------bug".replace(/^-/g,"") == "bug" |
|
2078 |
+ text = text.replace(/^(\t|[ ]{1,4})/gm, '~0'); // attacklab: g_tab_width |
|
2079 |
+ |
|
2080 |
+ // attacklab: clean up hack |
|
2081 |
+ text = text.replace(/~0/g, ''); |
|
2082 |
+ |
|
2083 |
+ return text; |
|
2084 |
+}); |
|
2085 |
+ |
|
2086 |
+/** |
|
2087 |
+ * |
|
2088 |
+ */ |
|
2089 |
+showdown.subParser('paragraphs', (text, options, globals) => { |
|
2090 |
+ text = globals.converter._dispatch('paragraphs.before', text, options, globals); |
|
2091 |
+ // Strip leading and trailing lines: |
|
2092 |
+ text = text.replace(/^\n+/g, ''); |
|
2093 |
+ text = text.replace(/\n+$/g, ''); |
|
2094 |
+ |
|
2095 |
+ const grafs = text.split(/\n{2,}/g); |
|
2096 |
+ const grafsOut = []; |
|
2097 |
+ let end = grafs.length; // Wrap <p> tags |
|
2098 |
+ |
|
2099 |
+ for (var i = 0; i < end; i++) { |
|
2100 |
+ let str = grafs[i]; |
|
2101 |
+ // if this is an HTML marker, copy it |
|
2102 |
+ if (str.search(/~(K|G)(\d+)\1/g) >= 0) { |
|
2103 |
+ grafsOut.push(str); |
|
2104 |
+ } else { |
|
2105 |
+ str = showdown.subParser('spanGamut')(str, options, globals); |
|
2106 |
+ str = str.replace(/^([ \t]*)/g, '<p>'); |
|
2107 |
+ str += '</p>'; |
|
2108 |
+ grafsOut.push(str); |
|
2109 |
+ } |
|
2110 |
+ } |
|
2111 |
+ |
|
2112 |
+ /** Unhashify HTML blocks */ |
|
2113 |
+ end = grafsOut.length; |
|
2114 |
+ for (i = 0; i < end; i++) { |
|
2115 |
+ let blockText = ''; |
|
2116 |
+ let grafsOutIt = grafsOut[i]; |
|
2117 |
+ let codeFlag = false; |
|
2118 |
+ // if this is a marker for an html block... |
|
2119 |
+ while (grafsOutIt.search(/~(K|G)(\d+)\1/) >= 0) { |
|
2120 |
+ const delim = RegExp.$1; |
|
2121 |
+ const num = RegExp.$2; |
|
2122 |
+ |
|
2123 |
+ if (delim === 'K') { |
|
2124 |
+ blockText = globals.gHtmlBlocks[num]; |
|
2125 |
+ } else { |
|
2126 |
+ // we need to check if ghBlock is a false positive |
|
2127 |
+ if (codeFlag) { |
|
2128 |
+ // use encoded version of all text |
|
2129 |
+ blockText = showdown.subParser('encodeCode')(globals.ghCodeBlocks[num].text); |
|
2130 |
+ } else { |
|
2131 |
+ blockText = globals.ghCodeBlocks[num].codeblock; |
|
2132 |
+ } |
|
2133 |
+ } |
|
2134 |
+ blockText = blockText.replace(/\$/g, '$$$$'); // Escape any dollar signs |
|
2135 |
+ |
|
2136 |
+ grafsOutIt = grafsOutIt.replace(/(\n\n)?~(K|G)\d+\2(\n\n)?/, blockText); |
|
2137 |
+ // Check if grafsOutIt is a pre->code |
|
2138 |
+ if (/^<pre\b[^>]*>\s*<code\b[^>]*>/.test(grafsOutIt)) { |
|
2139 |
+ codeFlag = true; |
|
2140 |
+ } |
|
2141 |
+ } |
|
2142 |
+ grafsOut[i] = grafsOutIt; |
|
2143 |
+ } |
|
2144 |
+ text = grafsOut.join('\n\n'); |
|
2145 |
+ // Strip leading and trailing lines: |
|
2146 |
+ text = text.replace(/^\n+/g, ''); |
|
2147 |
+ text = text.replace(/\n+$/g, ''); |
|
2148 |
+ return globals.converter._dispatch('paragraphs.after', text, options, globals); |
|
2149 |
+}); |
|
2150 |
+ |
|
2151 |
+/** |
|
2152 |
+ * Run extension |
|
2153 |
+ */ |
|
2154 |
+showdown.subParser('runExtension', (ext, text, options, globals) => { |
|
2155 |
+ if (ext.filter) { |
|
2156 |
+ text = ext.filter(text, globals.converter, options); |
|
2157 |
+ } else if (ext.regex) { |
|
2158 |
+ // TODO remove this when old extension loading mechanism is deprecated |
|
2159 |
+ let re = ext.regex; |
|
2160 |
+ if (!re instanceof RegExp) { |
|
2161 |
+ re = new RegExp(re, 'g'); |
|
2162 |
+ } |
|
2163 |
+ text = text.replace(re, ext.replace); |
|
2164 |
+ } |
|
2165 |
+ |
|
2166 |
+ return text; |
|
2167 |
+}); |
|
2168 |
+ |
|
2169 |
+/** |
|
2170 |
+ * These are all the transformations that occur *within* block-level |
|
2171 |
+ * tags like paragraphs, headers, and list items. |
|
2172 |
+ */ |
|
2173 |
+showdown.subParser('spanGamut', (text, options, globals) => { |
|
2174 |
+ text = globals.converter._dispatch('spanGamut.before', text, options, globals); |
|
2175 |
+ text = showdown.subParser('codeSpans')(text, options, globals); |
|
2176 |
+ text = showdown.subParser('escapeSpecialCharsWithinTagAttributes')(text, options, globals); |
|
2177 |
+ text = showdown.subParser('encodeBackslashEscapes')(text, options, globals); |
|
2178 |
+ |
|
2179 |
+ // Process anchor and image tags. Images must come first, |
|
2180 |
+ // because ![foo][f] looks like an anchor. |
|
2181 |
+ text = showdown.subParser('images')(text, options, globals); |
|
2182 |
+ text = showdown.subParser('anchors')(text, options, globals); |
|
2183 |
+ |
|
2184 |
+ // Make links out of things like `<http://example.com/>` |
|
2185 |
+ // Must come after _DoAnchors(), because you can use < and > |
|
2186 |
+ // delimiters in inline links like [this](<url>). |
|
2187 |
+ text = showdown.subParser('autoLinks')(text, options, globals); |
|
2188 |
+ text = showdown.subParser('encodeAmpsAndAngles')(text, options, globals); |
|
2189 |
+ text = showdown.subParser('italicsAndBold')(text, options, globals); |
|
2190 |
+ text = showdown.subParser('strikethrough')(text, options, globals); |
|
2191 |
+ |
|
2192 |
+ // Do hard breaks: |
|
2193 |
+ text = text.replace(/ +\n/g, ' <br />\n'); |
|
2194 |
+ |
|
2195 |
+ text = globals.converter._dispatch('spanGamut.after', text, options, globals); |
|
2196 |
+ return text; |
|
2197 |
+}); |
|
2198 |
+ |
|
2199 |
+showdown.subParser('strikethrough', (text, options, globals) => { |
|
2200 |
+ if (options.strikethrough) { |
|
2201 |
+ text = globals.converter._dispatch('strikethrough.before', text, options, globals); |
|
2202 |
+ text = text.replace(/(?:~T){2}([\s\S]+?)(?:~T){2}/g, '<del>$1</del>'); |
|
2203 |
+ text = globals.converter._dispatch('strikethrough.after', text, options, globals); |
|
2204 |
+ } |
|
2205 |
+ |
|
2206 |
+ return text; |
|
2207 |
+}); |
|
2208 |
+ |
|
2209 |
+/** |
|
2210 |
+ * Strip any lines consisting only of spaces and tabs. |
|
2211 |
+ * This makes subsequent regexs easier to write, because we can |
|
2212 |
+ * match consecutive blank lines with /\n+/ instead of something |
|
2213 |
+ * contorted like /[ \t]*\n+/ |
|
2214 |
+ */ |
|
2215 |
+showdown.subParser('stripBlankLines', (text) => text.replace(/^[ \t]+$/mg, '')); |
|
2216 |
+ |
|
2217 |
+/** |
|
2218 |
+ * Strips link definitions from text, stores the URLs and titles in |
|
2219 |
+ * hash references. |
|
2220 |
+ * Link defs are in the form: ^[id]: url "optional title" |
|
2221 |
+ * |
|
2222 |
+ * ^[ ]{0,3}\[(.+)\]: // id = $1 attacklab: g_tab_width - 1 |
|
2223 |
+ * [ \t]* |
|
2224 |
+ * \n? // maybe *one* newline |
|
2225 |
+ * [ \t]* |
|
2226 |
+ * <?(\S+?)>? // url = $2 |
|
2227 |
+ * [ \t]* |
|
2228 |
+ * \n? // maybe one newline |
|
2229 |
+ * [ \t]* |
|
2230 |
+ * (?: |
|
2231 |
+ * (\n*) // any lines skipped = $3 attacklab: lookbehind removed |
|
2232 |
+ * ["(] |
|
2233 |
+ * (.+?) // title = $4 |
|
2234 |
+ * [")] |
|
2235 |
+ * [ \t]* |
|
2236 |
+ * )? // title is optional |
|
2237 |
+ * (?:\n+|$) |
|
2238 |
+ * /gm, |
|
2239 |
+ * function(){...}); |
|
2240 |
+ * |
|
2241 |
+ */ |
|
2242 |
+showdown.subParser('stripLinkDefinitions', (text, options, globals) => { |
|
2243 |
+ const regex = /^ {0,3}\[(.+)]:[ \t]*\n?[ \t]*<?(\S+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n+|(?=~0))/gm; |
|
2244 |
+ |
|
2245 |
+ // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug |
|
2246 |
+ text += '~0'; |
|
2247 |
+ |
|
2248 |
+ text = text.replace(regex, (wholeMatch, linkId, url, width, height, blankLines, title) => { |
|
2249 |
+ linkId = linkId.toLowerCase(); |
|
2250 |
+ globals.gUrls[linkId] = showdown.subParser('encodeAmpsAndAngles')(url); // Link IDs are case-insensitive |
|
2251 |
+ |
|
2252 |
+ if (blankLines) { |
|
2253 |
+ // Oops, found blank lines, so it's not a title. |
|
2254 |
+ // Put back the parenthetical statement we stole. |
|
2255 |
+ return blankLines + title; |
|
2256 |
+ } |
|
2257 |
+ if (title) { |
|
2258 |
+ globals.gTitles[linkId] = title.replace(/"|'/g, '"'); |
|
2259 |
+ } |
|
2260 |
+ if (options.parseImgDimensions && width && height) { |
|
2261 |
+ globals.gDimensions[linkId] = { |
|
2262 |
+ width, |
|
2263 |
+ height, |
|
2264 |
+ }; |
|
2265 |
+ } |
|
2266 |
+ |
|
2267 |
+ // Completely remove the definition from the text |
|
2268 |
+ return ''; |
|
2269 |
+ }); |
|
2270 |
+ |
|
2271 |
+ // attacklab: strip sentinel |
|
2272 |
+ text = text.replace(/~0/, ''); |
|
2273 |
+ |
|
2274 |
+ return text; |
|
2275 |
+}); |
|
2276 |
+ |
|
2277 |
+showdown.subParser('tables', (text, options, globals) => { |
|
2278 |
+ if (!options.tables) { |
|
2279 |
+ return text; |
|
2280 |
+ } |
|
2281 |
+ |
|
2282 |
+ const tableRgx = /^[ \t]{0,3}\|?.+\|.+\n[ \t]{0,3}\|?[ \t]*:?[ \t]*(?:-|=){2,}[ \t]*:?[ \t]*\|[ \t]*:?[ \t]*(?:-|=){2,}[\s\S]+?(?:\n\n|~0)/gm; |
|
2283 |
+ |
|
2284 |
+ function parseStyles(sLine) { |
|
2285 |
+ if (/^:[ \t]*--*$/.test(sLine)) { |
|
2286 |
+ return ' style="text-align:left;"'; |
|
2287 |
+ } if (/^--*[ \t]*:[ \t]*$/.test(sLine)) { |
|
2288 |
+ return ' style="text-align:right;"'; |
|
2289 |
+ } if (/^:[ \t]*--*[ \t]*:$/.test(sLine)) { |
|
2290 |
+ return ' style="text-align:center;"'; |
|
2291 |
+ } |
|
2292 |
+ return ''; |
|
2293 |
+ } |
|
2294 |
+ |
|
2295 |
+ function parseHeaders(header, style) { |
|
2296 |
+ let id = ''; |
|
2297 |
+ header = header.trim(); |
|
2298 |
+ if (options.tableHeaderId) { |
|
2299 |
+ id = ` id="${header.replace(/ /g, '_').toLowerCase()}"`; |
|
2300 |
+ } |
|
2301 |
+ header = showdown.subParser('spanGamut')(header, options, globals); |
|
2302 |
+ |
|
2303 |
+ return `<th${id}${style}>${header}</th>\n`; |
|
2304 |
+ } |
|
2305 |
+ |
|
2306 |
+ function parseCells(cell, style) { |
|
2307 |
+ const subText = showdown.subParser('spanGamut')(cell, options, globals); |
|
2308 |
+ return `<td${style}>${subText}</td>\n`; |
|
2309 |
+ } |
|
2310 |
+ |
|
2311 |
+ function buildTable(headers, cells) { |
|
2312 |
+ let tb = '<table>\n<thead>\n<tr>\n'; |
|
2313 |
+ const tblLgn = headers.length; |
|
2314 |
+ |
|
2315 |
+ for (var i = 0; i < tblLgn; ++i) { |
|
2316 |
+ tb += headers[i]; |
|
2317 |
+ } |
|
2318 |
+ tb += '</tr>\n</thead>\n<tbody>\n'; |
|
2319 |
+ |
|
2320 |
+ for (i = 0; i < cells.length; ++i) { |
|
2321 |
+ tb += '<tr>\n'; |
|
2322 |
+ for (let ii = 0; ii < tblLgn; ++ii) { |
|
2323 |
+ tb += cells[i][ii]; |
|
2324 |
+ } |
|
2325 |
+ tb += '</tr>\n'; |
|
2326 |
+ } |
|
2327 |
+ tb += '</tbody>\n</table>\n'; |
|
2328 |
+ return tb; |
|
2329 |
+ } |
|
2330 |
+ |
|
2331 |
+ text = globals.converter._dispatch('tables.before', text, options, globals); |
|
2332 |
+ |
|
2333 |
+ text = text.replace(tableRgx, (rawTable) => { |
|
2334 |
+ let i; const |
|
2335 |
+ tableLines = rawTable.split('\n'); |
|
2336 |
+ |
|
2337 |
+ // strip wrong first and last column if wrapped tables are used |
|
2338 |
+ for (i = 0; i < tableLines.length; ++i) { |
|
2339 |
+ if (/^[ \t]{0,3}\|/.test(tableLines[i])) { |
|
2340 |
+ tableLines[i] = tableLines[i].replace(/^[ \t]{0,3}\|/, ''); |
|
2341 |
+ } |
|
2342 |
+ if (/\|[ \t]*$/.test(tableLines[i])) { |
|
2343 |
+ tableLines[i] = tableLines[i].replace(/\|[ \t]*$/, ''); |
|
2344 |
+ } |
|
2345 |
+ } |
|
2346 |
+ |
|
2347 |
+ const rawHeaders = tableLines[0].split('|').map((s) => s.trim()); |
|
2348 |
+ const rawStyles = tableLines[1].split('|').map((s) => s.trim()); |
|
2349 |
+ const rawCells = []; |
|
2350 |
+ const headers = []; |
|
2351 |
+ const styles = []; |
|
2352 |
+ const cells = []; |
|
2353 |
+ |
|
2354 |
+ tableLines.shift(); |
|
2355 |
+ tableLines.shift(); |
|
2356 |
+ |
|
2357 |
+ for (i = 0; i < tableLines.length; ++i) { |
|
2358 |
+ if (tableLines[i].trim() === '') { |
|
2359 |
+ continue; |
|
2360 |
+ } |
|
2361 |
+ rawCells.push( |
|
2362 |
+ tableLines[i] |
|
2363 |
+ .split('|') |
|
2364 |
+ .map((s) => s.trim()), |
|
2365 |
+ ); |
|
2366 |
+ } |
|
2367 |
+ |
|
2368 |
+ if (rawHeaders.length < rawStyles.length) { |
|
2369 |
+ return rawTable; |
|
2370 |
+ } |
|
2371 |
+ |
|
2372 |
+ for (i = 0; i < rawStyles.length; ++i) { |
|
2373 |
+ styles.push(parseStyles(rawStyles[i])); |
|
2374 |
+ } |
|
2375 |
+ |
|
2376 |
+ for (i = 0; i < rawHeaders.length; ++i) { |
|
2377 |
+ if (showdown.helper.isUndefined(styles[i])) { |
|
2378 |
+ styles[i] = ''; |
|
2379 |
+ } |
|
2380 |
+ headers.push(parseHeaders(rawHeaders[i], styles[i])); |
|
2381 |
+ } |
|
2382 |
+ |
|
2383 |
+ for (i = 0; i < rawCells.length; ++i) { |
|
2384 |
+ const row = []; |
|
2385 |
+ for (let ii = 0; ii < headers.length; ++ii) { |
|
2386 |
+ if (showdown.helper.isUndefined(rawCells[i][ii])) { |
|
2387 |
+ |
|
2388 |
+ } |
|
2389 |
+ row.push(parseCells(rawCells[i][ii], styles[ii])); |
|
2390 |
+ } |
|
2391 |
+ cells.push(row); |
|
2392 |
+ } |
|
2393 |
+ |
|
2394 |
+ return buildTable(headers, cells); |
|
2395 |
+ }); |
|
2396 |
+ |
|
2397 |
+ text = globals.converter._dispatch('tables.after', text, options, globals); |
|
2398 |
+ |
|
2399 |
+ return text; |
|
2400 |
+}); |
|
2401 |
+ |
|
2402 |
+/** |
|
2403 |
+ * Swap back in all the special characters we've hidden. |
|
2404 |
+ */ |
|
2405 |
+showdown.subParser('unescapeSpecialChars', (text) => { |
|
2406 |
+ text = text.replace(/~E(\d+)E/g, (wholeMatch, m1) => { |
|
2407 |
+ const charCodeToReplace = parseInt(m1); |
|
2408 |
+ return String.fromCharCode(charCodeToReplace); |
|
2409 |
+ }); |
|
2410 |
+ return text; |
|
2411 |
+}); |
|
2412 |
+module.exports = showdown; |
@@ -0,0 +1,206 @@ |
||
1 |
+// HTML 支持的数学符号 |
|
2 |
+function strNumDiscode(str) { |
|
3 |
+ str = str.replace(/∀/g, '∀'); |
|
4 |
+ str = str.replace(/∂/g, '∂'); |
|
5 |
+ str = str.replace(/&exists;/g, '∃'); |
|
6 |
+ str = str.replace(/∅/g, '∅'); |
|
7 |
+ str = str.replace(/∇/g, '∇'); |
|
8 |
+ str = str.replace(/∈/g, '∈'); |
|
9 |
+ str = str.replace(/∉/g, '∉'); |
|
10 |
+ str = str.replace(/∋/g, '∋'); |
|
11 |
+ str = str.replace(/∏/g, '∏'); |
|
12 |
+ str = str.replace(/∑/g, '∑'); |
|
13 |
+ str = str.replace(/−/g, '−'); |
|
14 |
+ str = str.replace(/∗/g, '∗'); |
|
15 |
+ str = str.replace(/√/g, '√'); |
|
16 |
+ str = str.replace(/∝/g, '∝'); |
|
17 |
+ str = str.replace(/∞/g, '∞'); |
|
18 |
+ str = str.replace(/∠/g, '∠'); |
|
19 |
+ str = str.replace(/∧/g, '∧'); |
|
20 |
+ str = str.replace(/∨/g, '∨'); |
|
21 |
+ str = str.replace(/∩/g, '∩'); |
|
22 |
+ str = str.replace(/∩/g, '∪'); |
|
23 |
+ str = str.replace(/∫/g, '∫'); |
|
24 |
+ str = str.replace(/∴/g, '∴'); |
|
25 |
+ str = str.replace(/∼/g, '∼'); |
|
26 |
+ str = str.replace(/≅/g, '≅'); |
|
27 |
+ str = str.replace(/≈/g, '≈'); |
|
28 |
+ str = str.replace(/≠/g, '≠'); |
|
29 |
+ str = str.replace(/≤/g, '≤'); |
|
30 |
+ str = str.replace(/≥/g, '≥'); |
|
31 |
+ str = str.replace(/⊂/g, '⊂'); |
|
32 |
+ str = str.replace(/⊃/g, '⊃'); |
|
33 |
+ str = str.replace(/⊄/g, '⊄'); |
|
34 |
+ str = str.replace(/⊆/g, '⊆'); |
|
35 |
+ str = str.replace(/⊇/g, '⊇'); |
|
36 |
+ str = str.replace(/⊕/g, '⊕'); |
|
37 |
+ str = str.replace(/⊗/g, '⊗'); |
|
38 |
+ str = str.replace(/⊥/g, '⊥'); |
|
39 |
+ str = str.replace(/⋅/g, '⋅'); |
|
40 |
+ return str; |
|
41 |
+} |
|
42 |
+ |
|
43 |
+// HTML 支持的希腊字母 |
|
44 |
+function strGreeceDiscode(str) { |
|
45 |
+ str = str.replace(/Α/g, 'Α'); |
|
46 |
+ str = str.replace(/Β/g, 'Β'); |
|
47 |
+ str = str.replace(/Γ/g, 'Γ'); |
|
48 |
+ str = str.replace(/Δ/g, 'Δ'); |
|
49 |
+ str = str.replace(/Ε/g, 'Ε'); |
|
50 |
+ str = str.replace(/Ζ/g, 'Ζ'); |
|
51 |
+ str = str.replace(/Η/g, 'Η'); |
|
52 |
+ str = str.replace(/Θ/g, 'Θ'); |
|
53 |
+ str = str.replace(/Ι/g, 'Ι'); |
|
54 |
+ str = str.replace(/Κ/g, 'Κ'); |
|
55 |
+ str = str.replace(/Λ/g, 'Λ'); |
|
56 |
+ str = str.replace(/Μ/g, 'Μ'); |
|
57 |
+ str = str.replace(/Ν/g, 'Ν'); |
|
58 |
+ str = str.replace(/Ξ/g, 'Ν'); |
|
59 |
+ str = str.replace(/Ο/g, 'Ο'); |
|
60 |
+ str = str.replace(/Π/g, 'Π'); |
|
61 |
+ str = str.replace(/Ρ/g, 'Ρ'); |
|
62 |
+ str = str.replace(/Σ/g, 'Σ'); |
|
63 |
+ str = str.replace(/Τ/g, 'Τ'); |
|
64 |
+ str = str.replace(/Υ/g, 'Υ'); |
|
65 |
+ str = str.replace(/Φ/g, 'Φ'); |
|
66 |
+ str = str.replace(/Χ/g, 'Χ'); |
|
67 |
+ str = str.replace(/Ψ/g, 'Ψ'); |
|
68 |
+ str = str.replace(/Ω/g, 'Ω'); |
|
69 |
+ |
|
70 |
+ str = str.replace(/α/g, 'α'); |
|
71 |
+ str = str.replace(/β/g, 'β'); |
|
72 |
+ str = str.replace(/γ/g, 'γ'); |
|
73 |
+ str = str.replace(/δ/g, 'δ'); |
|
74 |
+ str = str.replace(/ε/g, 'ε'); |
|
75 |
+ str = str.replace(/ζ/g, 'ζ'); |
|
76 |
+ str = str.replace(/η/g, 'η'); |
|
77 |
+ str = str.replace(/θ/g, 'θ'); |
|
78 |
+ str = str.replace(/ι/g, 'ι'); |
|
79 |
+ str = str.replace(/κ/g, 'κ'); |
|
80 |
+ str = str.replace(/λ/g, 'λ'); |
|
81 |
+ str = str.replace(/μ/g, 'μ'); |
|
82 |
+ str = str.replace(/ν/g, 'ν'); |
|
83 |
+ str = str.replace(/ξ/g, 'ξ'); |
|
84 |
+ str = str.replace(/ο/g, 'ο'); |
|
85 |
+ str = str.replace(/π/g, 'π'); |
|
86 |
+ str = str.replace(/ρ/g, 'ρ'); |
|
87 |
+ str = str.replace(/ς/g, 'ς'); |
|
88 |
+ str = str.replace(/σ/g, 'σ'); |
|
89 |
+ str = str.replace(/τ/g, 'τ'); |
|
90 |
+ str = str.replace(/υ/g, 'υ'); |
|
91 |
+ str = str.replace(/φ/g, 'φ'); |
|
92 |
+ str = str.replace(/χ/g, 'χ'); |
|
93 |
+ str = str.replace(/ψ/g, 'ψ'); |
|
94 |
+ str = str.replace(/ω/g, 'ω'); |
|
95 |
+ str = str.replace(/ϑ/g, 'ϑ'); |
|
96 |
+ str = str.replace(/ϒ/g, 'ϒ'); |
|
97 |
+ str = str.replace(/ϖ/g, 'ϖ'); |
|
98 |
+ str = str.replace(/·/g, '·'); |
|
99 |
+ return str; |
|
100 |
+} |
|
101 |
+ |
|
102 |
+// |
|
103 |
+ |
|
104 |
+function strcharacterDiscode(str) { |
|
105 |
+ // 加入常用解析 |
|
106 |
+ str = str.replace(/ /g, ' '); |
|
107 |
+ str = str.replace(/"/g, "'"); |
|
108 |
+ str = str.replace(/&/g, '&'); |
|
109 |
+ // str = str.replace(/</g, '‹'); |
|
110 |
+ // str = str.replace(/>/g, '›'); |
|
111 |
+ |
|
112 |
+ str = str.replace(/</g, '<'); |
|
113 |
+ str = str.replace(/>/g, '>'); |
|
114 |
+ str = str.replace(/•/g, '•'); |
|
115 |
+ |
|
116 |
+ return str; |
|
117 |
+} |
|
118 |
+ |
|
119 |
+// HTML 支持的其他实体 |
|
120 |
+function strOtherDiscode(str) { |
|
121 |
+ str = str.replace(/Œ/g, 'Œ'); |
|
122 |
+ str = str.replace(/œ/g, 'œ'); |
|
123 |
+ str = str.replace(/Š/g, 'Š'); |
|
124 |
+ str = str.replace(/š/g, 'š'); |
|
125 |
+ str = str.replace(/Ÿ/g, 'Ÿ'); |
|
126 |
+ str = str.replace(/ƒ/g, 'ƒ'); |
|
127 |
+ str = str.replace(/ˆ/g, 'ˆ'); |
|
128 |
+ str = str.replace(/˜/g, '˜'); |
|
129 |
+ str = str.replace(/ /g, ''); |
|
130 |
+ str = str.replace(/ /g, ''); |
|
131 |
+ str = str.replace(/ /g, ''); |
|
132 |
+ str = str.replace(/‌/g, ''); |
|
133 |
+ str = str.replace(/‍/g, ''); |
|
134 |
+ str = str.replace(/‎/g, ''); |
|
135 |
+ str = str.replace(/‏/g, ''); |
|
136 |
+ str = str.replace(/–/g, '–'); |
|
137 |
+ str = str.replace(/—/g, '—'); |
|
138 |
+ str = str.replace(/‘/g, '‘'); |
|
139 |
+ str = str.replace(/’/g, '’'); |
|
140 |
+ str = str.replace(/‚/g, '‚'); |
|
141 |
+ str = str.replace(/“/g, '“'); |
|
142 |
+ str = str.replace(/”/g, '”'); |
|
143 |
+ str = str.replace(/„/g, '„'); |
|
144 |
+ str = str.replace(/†/g, '†'); |
|
145 |
+ str = str.replace(/‡/g, '‡'); |
|
146 |
+ str = str.replace(/•/g, '•'); |
|
147 |
+ str = str.replace(/…/g, '…'); |
|
148 |
+ str = str.replace(/‰/g, '‰'); |
|
149 |
+ str = str.replace(/′/g, '′'); |
|
150 |
+ str = str.replace(/″/g, '″'); |
|
151 |
+ str = str.replace(/‹/g, '‹'); |
|
152 |
+ str = str.replace(/›/g, '›'); |
|
153 |
+ str = str.replace(/‾/g, '‾'); |
|
154 |
+ str = str.replace(/€/g, '€'); |
|
155 |
+ str = str.replace(/™/g, '™'); |
|
156 |
+ |
|
157 |
+ str = str.replace(/←/g, '←'); |
|
158 |
+ str = str.replace(/↑/g, '↑'); |
|
159 |
+ str = str.replace(/→/g, '→'); |
|
160 |
+ str = str.replace(/↓/g, '↓'); |
|
161 |
+ str = str.replace(/↔/g, '↔'); |
|
162 |
+ str = str.replace(/↵/g, '↵'); |
|
163 |
+ str = str.replace(/⌈/g, '⌈'); |
|
164 |
+ str = str.replace(/⌉/g, '⌉'); |
|
165 |
+ |
|
166 |
+ str = str.replace(/⌊/g, '⌊'); |
|
167 |
+ str = str.replace(/⌋/g, '⌋'); |
|
168 |
+ str = str.replace(/◊/g, '◊'); |
|
169 |
+ str = str.replace(/♠/g, '♠'); |
|
170 |
+ str = str.replace(/♣/g, '♣'); |
|
171 |
+ str = str.replace(/♥/g, '♥'); |
|
172 |
+ |
|
173 |
+ str = str.replace(/♦/g, '♦'); |
|
174 |
+ str = str.replace(/'/g, '\''); |
|
175 |
+ return str; |
|
176 |
+} |
|
177 |
+ |
|
178 |
+function strMoreDiscode(str) { |
|
179 |
+ str = str.replace(/\r\n/g, ''); |
|
180 |
+ str = str.replace(/\n/g, ''); |
|
181 |
+ |
|
182 |
+ str = str.replace(/code/g, 'wxxxcode-style'); |
|
183 |
+ return str; |
|
184 |
+} |
|
185 |
+ |
|
186 |
+function strDiscode(str) { |
|
187 |
+ str = strNumDiscode(str); |
|
188 |
+ str = strGreeceDiscode(str); |
|
189 |
+ str = strcharacterDiscode(str); |
|
190 |
+ str = strOtherDiscode(str); |
|
191 |
+ str = strMoreDiscode(str); |
|
192 |
+ return str; |
|
193 |
+} |
|
194 |
+function urlToHttpUrl(url, rep) { |
|
195 |
+ const patt1 = new RegExp('^//'); |
|
196 |
+ const result = patt1.test(url); |
|
197 |
+ if (result) { |
|
198 |
+ url = `${rep}:${url}`; |
|
199 |
+ } |
|
200 |
+ return url; |
|
201 |
+} |
|
202 |
+ |
|
203 |
+module.exports = { |
|
204 |
+ strDiscode, |
|
205 |
+ urlToHttpUrl, |
|
206 |
+}; |
@@ -0,0 +1,159 @@ |
||
1 |
+/** |
|
2 |
+ * author: Di (微信小程序开发工程师) |
|
3 |
+ * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com) |
|
4 |
+ * 垂直微信小程序开发交流社区 |
|
5 |
+ * |
|
6 |
+ * github地址: https://github.com/icindy/wxParse |
|
7 |
+ * |
|
8 |
+ * for: 微信小程序富文本解析 |
|
9 |
+ * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184 |
|
10 |
+ */ |
|
11 |
+ |
|
12 |
+/** |
|
13 |
+ * utils函数引入 |
|
14 |
+ * */ |
|
15 |
+import showdown from './showdown.js'; |
|
16 |
+import HtmlToJson from './html2json.js'; |
|
17 |
+/** |
|
18 |
+ * 配置及公有属性 |
|
19 |
+ * */ |
|
20 |
+let realWindowWidth = 0; |
|
21 |
+let realWindowHeight = 0; |
|
22 |
+wx.getSystemInfo({ |
|
23 |
+ success(res) { |
|
24 |
+ realWindowWidth = res.windowWidth; |
|
25 |
+ realWindowHeight = res.windowHeight; |
|
26 |
+ }, |
|
27 |
+}); |
|
28 |
+/** |
|
29 |
+ * 主函数入口区 |
|
30 |
+ * */ |
|
31 |
+function wxParse(bindName = 'wxParseData', type = 'html', data = '<div class="color:red;">数据不能为空</div>', target, imagePadding) { |
|
32 |
+ const that = target; |
|
33 |
+ let transData = {};// 存放转化后的数据 |
|
34 |
+ if (type == 'html') { |
|
35 |
+ transData = HtmlToJson.html2json(data, bindName); |
|
36 |
+ console.log(JSON.stringify(transData, ' ', ' ')); |
|
37 |
+ } else if (type == 'md' || type == 'markdown') { |
|
38 |
+ const converter = new showdown.Converter(); |
|
39 |
+ const html = converter.makeHtml(data); |
|
40 |
+ transData = HtmlToJson.html2json(html, bindName); |
|
41 |
+ console.log(JSON.stringify(transData, ' ', ' ')); |
|
42 |
+ } |
|
43 |
+ transData.view = {}; |
|
44 |
+ transData.view.imagePadding = 0; |
|
45 |
+ if (typeof (imagePadding) !== 'undefined') { |
|
46 |
+ transData.view.imagePadding = imagePadding; |
|
47 |
+ } |
|
48 |
+ const bindData = {}; |
|
49 |
+ bindData[bindName] = transData; |
|
50 |
+ that.setData(bindData); |
|
51 |
+ that.wxParseImgLoad = wxParseImgLoad; |
|
52 |
+ that.wxParseImgTap = wxParseImgTap; |
|
53 |
+} |
|
54 |
+// 图片点击事件 |
|
55 |
+function wxParseImgTap(e) { |
|
56 |
+ const that = this; |
|
57 |
+ const nowImgUrl = e.target.dataset.src; |
|
58 |
+ const tagFrom = e.target.dataset.from; |
|
59 |
+ if (typeof (tagFrom) !== 'undefined' && tagFrom.length > 0) { |
|
60 |
+ wx.previewImage({ |
|
61 |
+ current: nowImgUrl, // 当前显示图片的http链接 |
|
62 |
+ urls: that.data[tagFrom].imageUrls, // 需要预览的图片http链接列表 |
|
63 |
+ }); |
|
64 |
+ } |
|
65 |
+} |
|
66 |
+ |
|
67 |
+/** |
|
68 |
+ * 图片视觉宽高计算函数区 |
|
69 |
+ * */ |
|
70 |
+function wxParseImgLoad(e) { |
|
71 |
+ const that = this; |
|
72 |
+ const tagFrom = e.target.dataset.from; |
|
73 |
+ const { idx } = e.target.dataset; |
|
74 |
+ if (typeof (tagFrom) !== 'undefined' && tagFrom.length > 0) { |
|
75 |
+ calMoreImageInfo(e, idx, that, tagFrom); |
|
76 |
+ } |
|
77 |
+} |
|
78 |
+// 假循环获取计算图片视觉最佳宽高 |
|
79 |
+function calMoreImageInfo(e, idx, that, bindName) { |
|
80 |
+ const temData = that.data[bindName]; |
|
81 |
+ if (!temData || temData.images.length == 0) { |
|
82 |
+ return; |
|
83 |
+ } |
|
84 |
+ const temImages = temData.images; |
|
85 |
+ // 因为无法获取view宽度 需要自定义padding进行计算,稍后处理 |
|
86 |
+ const recal = wxAutoImageCal(e.detail.width, e.detail.height, that, bindName); |
|
87 |
+ // temImages[idx].width = recal.imageWidth; |
|
88 |
+ // temImages[idx].height = recal.imageheight; |
|
89 |
+ // temData.images = temImages; |
|
90 |
+ // var bindData = {}; |
|
91 |
+ // bindData[bindName] = temData; |
|
92 |
+ // that.setData(bindData); |
|
93 |
+ const { index } = temImages[idx]; |
|
94 |
+ let key = `${bindName}`; |
|
95 |
+ for (const i of index.split('.')) key += `.nodes[${i}]`; |
|
96 |
+ const keyW = `${key}.width`; |
|
97 |
+ const keyH = `${key}.height`; |
|
98 |
+ that.setData({ |
|
99 |
+ [keyW]: recal.imageWidth, |
|
100 |
+ [keyH]: recal.imageheight, |
|
101 |
+ }); |
|
102 |
+} |
|
103 |
+ |
|
104 |
+// 计算视觉优先的图片宽高 |
|
105 |
+function wxAutoImageCal(originalWidth, originalHeight, that, bindName) { |
|
106 |
+ // 获取图片的原始长宽 |
|
107 |
+ let windowWidth = 0; let |
|
108 |
+ windowHeight = 0; |
|
109 |
+ let autoWidth = 0; let |
|
110 |
+ autoHeight = 0; |
|
111 |
+ const results = {}; |
|
112 |
+ const padding = that.data[bindName].view.imagePadding; |
|
113 |
+ windowWidth = realWindowWidth - 2 * padding; |
|
114 |
+ windowHeight = realWindowHeight; |
|
115 |
+ // 判断按照那种方式进行缩放 |
|
116 |
+ // console.log("windowWidth" + windowWidth); |
|
117 |
+ if (originalWidth > windowWidth) { // 在图片width大于手机屏幕width时候 |
|
118 |
+ autoWidth = windowWidth; |
|
119 |
+ // console.log("autoWidth" + autoWidth); |
|
120 |
+ autoHeight = (autoWidth * originalHeight) / originalWidth; |
|
121 |
+ // console.log("autoHeight" + autoHeight); |
|
122 |
+ results.imageWidth = autoWidth; |
|
123 |
+ results.imageheight = autoHeight; |
|
124 |
+ } else { // 否则展示原来的数据 |
|
125 |
+ results.imageWidth = originalWidth; |
|
126 |
+ results.imageheight = originalHeight; |
|
127 |
+ } |
|
128 |
+ return results; |
|
129 |
+} |
|
130 |
+ |
|
131 |
+function wxParseTemArray(temArrayName, bindNameReg, total, that) { |
|
132 |
+ const array = []; |
|
133 |
+ const temData = that.data; |
|
134 |
+ let obj = null; |
|
135 |
+ for (let i = 0; i < total; i++) { |
|
136 |
+ const simArr = temData[bindNameReg + i].nodes; |
|
137 |
+ array.push(simArr); |
|
138 |
+ } |
|
139 |
+ |
|
140 |
+ temArrayName = temArrayName || 'wxParseTemArray'; |
|
141 |
+ obj = JSON.parse(`{"${temArrayName}":""}`); |
|
142 |
+ obj[temArrayName] = array; |
|
143 |
+ that.setData(obj); |
|
144 |
+} |
|
145 |
+ |
|
146 |
+/** |
|
147 |
+ * 配置emojis |
|
148 |
+ * |
|
149 |
+ */ |
|
150 |
+ |
|
151 |
+function emojisInit(reg = '', baseSrc = '/wxParse/emojis/', emojis) { |
|
152 |
+ HtmlToJson.emojisInit(reg, baseSrc, emojis); |
|
153 |
+} |
|
154 |
+ |
|
155 |
+module.exports = { |
|
156 |
+ wxParse, |
|
157 |
+ wxParseTemArray, |
|
158 |
+ emojisInit, |
|
159 |
+}; |
@@ -0,0 +1,967 @@ |
||
1 |
+<!--** |
|
2 |
+ * author: Di (微信小程序开发工程师) |
|
3 |
+ * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com) |
|
4 |
+ * 垂直微信小程序开发交流社区 |
|
5 |
+ * |
|
6 |
+ * github地址: https://github.com/icindy/wxParse |
|
7 |
+ * |
|
8 |
+ * for: 微信小程序富文本解析 |
|
9 |
+ * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184 |
|
10 |
+ */--> |
|
11 |
+ |
|
12 |
+<!--基础元素--> |
|
13 |
+<template name="wxParseVideo"> |
|
14 |
+ <!--增加video标签支持,并循环添加--> |
|
15 |
+ <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"> |
|
16 |
+ <video class="{{item.classStr}} wxParse-{{item.tag}}-video" src="{{item.attr.src}}"></video> |
|
17 |
+ </view> |
|
18 |
+</template> |
|
19 |
+ |
|
20 |
+<template name="wxParseImg"> |
|
21 |
+ <image class="{{item.classStr}} wxParse-{{item.tag}}" data-from="{{item.from}}" data-src="{{item.attr.src}}" data-idx="{{item.imgIndex}}" src="{{item.attr.src}}" bindload="wxParseImgLoad" bindtap="wxParseImgTap" mode="widthFix" style="width:100%;" |
|
22 |
+ /> |
|
23 |
+</template> |
|
24 |
+ |
|
25 |
+<template name="WxEmojiView"> |
|
26 |
+ <view class="WxEmojiView wxParse-inline" style="{{item.styleStr}}"> |
|
27 |
+ <block wx:for="{{item.textArray}}" wx:key=""> |
|
28 |
+ <block class="{{item.text == '\\n' ? 'wxParse-hide':''}}" wx:if="{{item.node == 'text'}}">{{item.text}}</block> |
|
29 |
+ <block wx:elif="{{item.node == 'element'}}"> |
|
30 |
+ <image class="wxEmoji" src="{{item.baseSrc}}{{item.text}}" /> |
|
31 |
+ </block> |
|
32 |
+ </block> |
|
33 |
+ </view> |
|
34 |
+</template> |
|
35 |
+ |
|
36 |
+<template name="WxParseBr"> |
|
37 |
+ <text>\n</text> |
|
38 |
+</template> |
|
39 |
+<!--入口模版--> |
|
40 |
+ |
|
41 |
+<template name="wxParse"> |
|
42 |
+ <block wx:for="{{wxParseData}}" wx:key=""> |
|
43 |
+ <template is="wxParse0" data="{{item}}" /> |
|
44 |
+ </block> |
|
45 |
+</template> |
|
46 |
+ |
|
47 |
+ |
|
48 |
+<!--循环模版--> |
|
49 |
+<template name="wxParse0"> |
|
50 |
+ <!--<template is="wxParse1" data="{{item}}" />--> |
|
51 |
+ <!--判断是否是标签节点--> |
|
52 |
+ <block wx:if="{{item.node == 'element'}}"> |
|
53 |
+ <block wx:if="{{item.tag == 'button'}}"> |
|
54 |
+ <button type="default" size="mini"> |
|
55 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
56 |
+ <template is="wxParse1" data="{{item}}" /> |
|
57 |
+ </block> |
|
58 |
+ </button> |
|
59 |
+ </block> |
|
60 |
+ <!--li类型--> |
|
61 |
+ <block wx:elif="{{item.tag == 'li'}}"> |
|
62 |
+ <view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}"> |
|
63 |
+ <view class="{{item.classStr}} wxParse-li-inner"> |
|
64 |
+ <view class="{{item.classStr}} wxParse-li-text"> |
|
65 |
+ <view class="{{item.classStr}} wxParse-li-circle"></view> |
|
66 |
+ </view> |
|
67 |
+ <view class="{{item.classStr}} wxParse-li-text"> |
|
68 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
69 |
+ <template is="wxParse1" data="{{item}}" /> |
|
70 |
+ </block> |
|
71 |
+ </view> |
|
72 |
+ </view> |
|
73 |
+ </view> |
|
74 |
+ </block> |
|
75 |
+ |
|
76 |
+ <!--video类型--> |
|
77 |
+ <block wx:elif="{{item.tag == 'video'}}"> |
|
78 |
+ <template is="wxParseVideo" data="{{item}}" /> |
|
79 |
+ </block> |
|
80 |
+ |
|
81 |
+ <!--img类型--> |
|
82 |
+ <block wx:elif="{{item.tag == 'img'}}"> |
|
83 |
+ <template is="wxParseImg" data="{{item}}" /> |
|
84 |
+ </block> |
|
85 |
+ |
|
86 |
+ <!--a类型--> |
|
87 |
+ <block wx:elif="{{item.tag == 'a'}}"> |
|
88 |
+ <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}" hover-class="wxParse-a-hover"> |
|
89 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
90 |
+ <template is="wxParse1" data="{{item}}" /> |
|
91 |
+ </block> |
|
92 |
+ </view> |
|
93 |
+ </block> |
|
94 |
+ <block wx:elif="{{item.tag == 'table'}}"> |
|
95 |
+ <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"> |
|
96 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
97 |
+ <template is="wxParse1" data="{{item}}" /> |
|
98 |
+ </block> |
|
99 |
+ </view> |
|
100 |
+ </block> |
|
101 |
+ |
|
102 |
+ <block wx:elif="{{item.tag == 'br'}}"> |
|
103 |
+ <template is="WxParseBr"></template> |
|
104 |
+ </block> |
|
105 |
+ <!--其他块级标签--> |
|
106 |
+ <block wx:elif="{{item.tagType == 'block'}}"> |
|
107 |
+ <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"> |
|
108 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
109 |
+ <template is="wxParse1" data="{{item}}" /> |
|
110 |
+ </block> |
|
111 |
+ </view> |
|
112 |
+ </block> |
|
113 |
+ |
|
114 |
+ <!--内联标签--> |
|
115 |
+ <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}"> |
|
116 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
117 |
+ <template is="wxParse1" data="{{item}}" /> |
|
118 |
+ </block> |
|
119 |
+ </view> |
|
120 |
+ |
|
121 |
+ </block> |
|
122 |
+ |
|
123 |
+ <!--判断是否是文本节点--> |
|
124 |
+ <block wx:elif="{{item.node == 'text'}}"> |
|
125 |
+ <!--如果是,直接进行--> |
|
126 |
+ <template is="WxEmojiView" data="{{item}}" /> |
|
127 |
+ </block> |
|
128 |
+ |
|
129 |
+</template> |
|
130 |
+ |
|
131 |
+ |
|
132 |
+ |
|
133 |
+<!--循环模版--> |
|
134 |
+<template name="wxParse1"> |
|
135 |
+ <!--<template is="wxParse2" data="{{item}}" />--> |
|
136 |
+ <!--判断是否是标签节点--> |
|
137 |
+ <block wx:if="{{item.node == 'element'}}"> |
|
138 |
+ <block wx:if="{{item.tag == 'button'}}"> |
|
139 |
+ <button type="default" size="mini"> |
|
140 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
141 |
+ <template is="wxParse2" data="{{item}}" /> |
|
142 |
+ </block> |
|
143 |
+ </button> |
|
144 |
+ </block> |
|
145 |
+ <!--li类型--> |
|
146 |
+ <block wx:elif="{{item.tag == 'li'}}"> |
|
147 |
+ <view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}"> |
|
148 |
+ <view class="{{item.classStr}} wxParse-li-inner"> |
|
149 |
+ <view class="{{item.classStr}} wxParse-li-text"> |
|
150 |
+ <view class="{{item.classStr}} wxParse-li-circle"></view> |
|
151 |
+ </view> |
|
152 |
+ <view class="{{item.classStr}} wxParse-li-text"> |
|
153 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
154 |
+ <template is="wxParse2" data="{{item}}" /> |
|
155 |
+ </block> |
|
156 |
+ </view> |
|
157 |
+ </view> |
|
158 |
+ </view> |
|
159 |
+ </block> |
|
160 |
+ |
|
161 |
+ <!--video类型--> |
|
162 |
+ <block wx:elif="{{item.tag == 'video'}}"> |
|
163 |
+ <template is="wxParseVideo" data="{{item}}" /> |
|
164 |
+ </block> |
|
165 |
+ |
|
166 |
+ <!--img类型--> |
|
167 |
+ <block wx:elif="{{item.tag == 'img'}}"> |
|
168 |
+ <template is="wxParseImg" data="{{item}}" /> |
|
169 |
+ </block> |
|
170 |
+ |
|
171 |
+ <!--a类型--> |
|
172 |
+ <block wx:elif="{{item.tag == 'a'}}"> |
|
173 |
+ <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}" hover-class="wxParse-a-hover"> |
|
174 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
175 |
+ <template is="wxParse2" data="{{item}}" /> |
|
176 |
+ </block> |
|
177 |
+ </view> |
|
178 |
+ </block> |
|
179 |
+ |
|
180 |
+ <block wx:elif="{{item.tag == 'br'}}"> |
|
181 |
+ <template is="WxParseBr"></template> |
|
182 |
+ </block> |
|
183 |
+ <!--其他块级标签--> |
|
184 |
+ <block wx:elif="{{item.tagType == 'block'}}"> |
|
185 |
+ <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"> |
|
186 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
187 |
+ <template is="wxParse2" data="{{item}}" /> |
|
188 |
+ </block> |
|
189 |
+ </view> |
|
190 |
+ </block> |
|
191 |
+ |
|
192 |
+ <!--内联标签--> |
|
193 |
+ <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}"> |
|
194 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
195 |
+ <template is="wxParse2" data="{{item}}" /> |
|
196 |
+ </block> |
|
197 |
+ </view> |
|
198 |
+ |
|
199 |
+ </block> |
|
200 |
+ |
|
201 |
+ <!--判断是否是文本节点--> |
|
202 |
+ <block wx:elif="{{item.node == 'text'}}"> |
|
203 |
+ <!--如果是,直接进行--> |
|
204 |
+ <template is="WxEmojiView" data="{{item}}" /> |
|
205 |
+ </block> |
|
206 |
+ |
|
207 |
+</template> |
|
208 |
+ |
|
209 |
+ |
|
210 |
+<!--循环模版--> |
|
211 |
+<template name="wxParse2"> |
|
212 |
+ <!--<template is="wxParse3" data="{{item}}" />--> |
|
213 |
+ <!--判断是否是标签节点--> |
|
214 |
+ <block wx:if="{{item.node == 'element'}}"> |
|
215 |
+ <block wx:if="{{item.tag == 'button'}}"> |
|
216 |
+ <button type="default" size="mini"> |
|
217 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
218 |
+ <template is="wxParse3" data="{{item}}" /> |
|
219 |
+ </block> |
|
220 |
+ </button> |
|
221 |
+ </block> |
|
222 |
+ <!--li类型--> |
|
223 |
+ <block wx:elif="{{item.tag == 'li'}}"> |
|
224 |
+ <view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}"> |
|
225 |
+ <view class="{{item.classStr}} wxParse-li-inner"> |
|
226 |
+ <view class="{{item.classStr}} wxParse-li-text"> |
|
227 |
+ <view class="{{item.classStr}} wxParse-li-circle"></view> |
|
228 |
+ </view> |
|
229 |
+ <view class="{{item.classStr}} wxParse-li-text"> |
|
230 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
231 |
+ <template is="wxParse3" data="{{item}}" /> |
|
232 |
+ </block> |
|
233 |
+ </view> |
|
234 |
+ </view> |
|
235 |
+ </view> |
|
236 |
+ </block> |
|
237 |
+ |
|
238 |
+ <!--video类型--> |
|
239 |
+ <block wx:elif="{{item.tag == 'video'}}"> |
|
240 |
+ <template is="wxParseVideo" data="{{item}}" /> |
|
241 |
+ </block> |
|
242 |
+ |
|
243 |
+ <!--img类型--> |
|
244 |
+ <block wx:elif="{{item.tag == 'img'}}"> |
|
245 |
+ <template is="wxParseImg" data="{{item}}" /> |
|
246 |
+ </block> |
|
247 |
+ |
|
248 |
+ <!--a类型--> |
|
249 |
+ <block wx:elif="{{item.tag == 'a'}}"> |
|
250 |
+ <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}" hover-class="wxParse-a-hover"> |
|
251 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
252 |
+ <template is="wxParse3" data="{{item}}" /> |
|
253 |
+ </block> |
|
254 |
+ </view> |
|
255 |
+ </block> |
|
256 |
+ |
|
257 |
+ <block wx:elif="{{item.tag == 'br'}}"> |
|
258 |
+ <template is="WxParseBr"></template> |
|
259 |
+ </block> |
|
260 |
+ <!--其他块级标签--> |
|
261 |
+ <block wx:elif="{{item.tagType == 'block'}}"> |
|
262 |
+ <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"> |
|
263 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
264 |
+ <template is="wxParse3" data="{{item}}" /> |
|
265 |
+ </block> |
|
266 |
+ </view> |
|
267 |
+ </block> |
|
268 |
+ |
|
269 |
+ <!--内联标签--> |
|
270 |
+ <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}"> |
|
271 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
272 |
+ <template is="wxParse3" data="{{item}}" /> |
|
273 |
+ </block> |
|
274 |
+ </view> |
|
275 |
+ |
|
276 |
+ </block> |
|
277 |
+ |
|
278 |
+ <!--判断是否是文本节点--> |
|
279 |
+ <block wx:elif="{{item.node == 'text'}}"> |
|
280 |
+ <!--如果是,直接进行--> |
|
281 |
+ <template is="WxEmojiView" data="{{item}}" /> |
|
282 |
+ </block> |
|
283 |
+ |
|
284 |
+</template> |
|
285 |
+ |
|
286 |
+<!--循环模版--> |
|
287 |
+<template name="wxParse3"> |
|
288 |
+ <!--<template is="wxParse4" data="{{item}}" />--> |
|
289 |
+ <!--判断是否是标签节点--> |
|
290 |
+ <block wx:if="{{item.node == 'element'}}"> |
|
291 |
+ <block wx:if="{{item.tag == 'button'}}"> |
|
292 |
+ <button type="default" size="mini"> |
|
293 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
294 |
+ <template is="wxParse4" data="{{item}}" /> |
|
295 |
+ </block> |
|
296 |
+ </button> |
|
297 |
+ </block> |
|
298 |
+ <!--li类型--> |
|
299 |
+ <block wx:elif="{{item.tag == 'li'}}"> |
|
300 |
+ <view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}"> |
|
301 |
+ <view class="{{item.classStr}} wxParse-li-inner"> |
|
302 |
+ <view class="{{item.classStr}} wxParse-li-text"> |
|
303 |
+ <view class="{{item.classStr}} wxParse-li-circle"></view> |
|
304 |
+ </view> |
|
305 |
+ <view class="{{item.classStr}} wxParse-li-text"> |
|
306 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
307 |
+ <template is="wxParse4" data="{{item}}" /> |
|
308 |
+ </block> |
|
309 |
+ </view> |
|
310 |
+ </view> |
|
311 |
+ </view> |
|
312 |
+ </block> |
|
313 |
+ |
|
314 |
+ <!--video类型--> |
|
315 |
+ <block wx:elif="{{item.tag == 'video'}}"> |
|
316 |
+ <template is="wxParseVideo" data="{{item}}" /> |
|
317 |
+ </block> |
|
318 |
+ |
|
319 |
+ <!--img类型--> |
|
320 |
+ <block wx:elif="{{item.tag == 'img'}}"> |
|
321 |
+ <template is="wxParseImg" data="{{item}}" /> |
|
322 |
+ </block> |
|
323 |
+ |
|
324 |
+ <!--a类型--> |
|
325 |
+ <block wx:elif="{{item.tag == 'a'}}"> |
|
326 |
+ <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}" hover-class="wxParse-a-hover"> |
|
327 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
328 |
+ <template is="wxParse4" data="{{item}}" /> |
|
329 |
+ </block> |
|
330 |
+ </view> |
|
331 |
+ </block> |
|
332 |
+ |
|
333 |
+ <block wx:elif="{{item.tag == 'br'}}"> |
|
334 |
+ <template is="WxParseBr"></template> |
|
335 |
+ </block> |
|
336 |
+ <!--其他块级标签--> |
|
337 |
+ <block wx:elif="{{item.tagType == 'block'}}"> |
|
338 |
+ <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"> |
|
339 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
340 |
+ <template is="wxParse4" data="{{item}}" /> |
|
341 |
+ </block> |
|
342 |
+ </view> |
|
343 |
+ </block> |
|
344 |
+ |
|
345 |
+ <!--内联标签--> |
|
346 |
+ <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}"> |
|
347 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
348 |
+ <template is="wxParse4" data="{{item}}" /> |
|
349 |
+ </block> |
|
350 |
+ </view> |
|
351 |
+ |
|
352 |
+ </block> |
|
353 |
+ |
|
354 |
+ <!--判断是否是文本节点--> |
|
355 |
+ <block wx:elif="{{item.node == 'text'}}"> |
|
356 |
+ <!--如果是,直接进行--> |
|
357 |
+ <template is="WxEmojiView" data="{{item}}" /> |
|
358 |
+ </block> |
|
359 |
+ |
|
360 |
+</template> |
|
361 |
+ |
|
362 |
+<!--循环模版--> |
|
363 |
+<template name="wxParse4"> |
|
364 |
+ <!--<template is="wxParse5" data="{{item}}" />--> |
|
365 |
+ <!--判断是否是标签节点--> |
|
366 |
+ <block wx:if="{{item.node == 'element'}}"> |
|
367 |
+ <block wx:if="{{item.tag == 'button'}}"> |
|
368 |
+ <button type="default" size="mini"> |
|
369 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
370 |
+ <template is="wxParse5" data="{{item}}" /> |
|
371 |
+ </block> |
|
372 |
+ </button> |
|
373 |
+ </block> |
|
374 |
+ <!--li类型--> |
|
375 |
+ <block wx:elif="{{item.tag == 'li'}}"> |
|
376 |
+ <view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}"> |
|
377 |
+ <view class="{{item.classStr}} wxParse-li-inner"> |
|
378 |
+ <view class="{{item.classStr}} wxParse-li-text"> |
|
379 |
+ <view class="{{item.classStr}} wxParse-li-circle"></view> |
|
380 |
+ </view> |
|
381 |
+ <view class="{{item.classStr}} wxParse-li-text"> |
|
382 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
383 |
+ <template is="wxParse5" data="{{item}}" /> |
|
384 |
+ </block> |
|
385 |
+ </view> |
|
386 |
+ </view> |
|
387 |
+ </view> |
|
388 |
+ </block> |
|
389 |
+ |
|
390 |
+ <!--video类型--> |
|
391 |
+ <block wx:elif="{{item.tag == 'video'}}"> |
|
392 |
+ <template is="wxParseVideo" data="{{item}}" /> |
|
393 |
+ </block> |
|
394 |
+ |
|
395 |
+ <!--img类型--> |
|
396 |
+ <block wx:elif="{{item.tag == 'img'}}"> |
|
397 |
+ <template is="wxParseImg" data="{{item}}" /> |
|
398 |
+ </block> |
|
399 |
+ |
|
400 |
+ <!--a类型--> |
|
401 |
+ <block wx:elif="{{item.tag == 'a'}}"> |
|
402 |
+ <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}" hover-class="wxParse-a-hover"> |
|
403 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
404 |
+ <template is="wxParse5" data="{{item}}" /> |
|
405 |
+ </block> |
|
406 |
+ </view> |
|
407 |
+ </block> |
|
408 |
+ |
|
409 |
+ <block wx:elif="{{item.tag == 'br'}}"> |
|
410 |
+ <template is="WxParseBr"></template> |
|
411 |
+ </block> |
|
412 |
+ <!--其他块级标签--> |
|
413 |
+ <block wx:elif="{{item.tagType == 'block'}}"> |
|
414 |
+ <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"> |
|
415 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
416 |
+ <template is="wxParse5" data="{{item}}" /> |
|
417 |
+ </block> |
|
418 |
+ </view> |
|
419 |
+ </block> |
|
420 |
+ |
|
421 |
+ <!--内联标签--> |
|
422 |
+ <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}"> |
|
423 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
424 |
+ <template is="wxParse5" data="{{item}}" /> |
|
425 |
+ </block> |
|
426 |
+ </view> |
|
427 |
+ |
|
428 |
+ </block> |
|
429 |
+ |
|
430 |
+ <!--判断是否是文本节点--> |
|
431 |
+ <block wx:elif="{{item.node == 'text'}}"> |
|
432 |
+ <!--如果是,直接进行--> |
|
433 |
+ <template is="WxEmojiView" data="{{item}}" /> |
|
434 |
+ </block> |
|
435 |
+ |
|
436 |
+</template> |
|
437 |
+ |
|
438 |
+<!--循环模版--> |
|
439 |
+<template name="wxParse5"> |
|
440 |
+ <!--<template is="wxParse6" data="{{item}}" />--> |
|
441 |
+ <!--判断是否是标签节点--> |
|
442 |
+ <block wx:if="{{item.node == 'element'}}"> |
|
443 |
+ <block wx:if="{{item.tag == 'button'}}"> |
|
444 |
+ <button type="default" size="mini"> |
|
445 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
446 |
+ <template is="wxParse6" data="{{item}}" /> |
|
447 |
+ </block> |
|
448 |
+ </button> |
|
449 |
+ </block> |
|
450 |
+ <!--li类型--> |
|
451 |
+ <block wx:elif="{{item.tag == 'li'}}"> |
|
452 |
+ <view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}"> |
|
453 |
+ <view class="{{item.classStr}} wxParse-li-inner"> |
|
454 |
+ <view class="{{item.classStr}} wxParse-li-text"> |
|
455 |
+ <view class="{{item.classStr}} wxParse-li-circle"></view> |
|
456 |
+ </view> |
|
457 |
+ <view class="{{item.classStr}} wxParse-li-text"> |
|
458 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
459 |
+ <template is="wxParse6" data="{{item}}" /> |
|
460 |
+ </block> |
|
461 |
+ </view> |
|
462 |
+ </view> |
|
463 |
+ </view> |
|
464 |
+ </block> |
|
465 |
+ |
|
466 |
+ <!--video类型--> |
|
467 |
+ <block wx:elif="{{item.tag == 'video'}}"> |
|
468 |
+ <template is="wxParseVideo" data="{{item}}" /> |
|
469 |
+ </block> |
|
470 |
+ |
|
471 |
+ <!--img类型--> |
|
472 |
+ <block wx:elif="{{item.tag == 'img'}}"> |
|
473 |
+ <template is="wxParseImg" data="{{item}}" /> |
|
474 |
+ </block> |
|
475 |
+ |
|
476 |
+ <!--a类型--> |
|
477 |
+ <block wx:elif="{{item.tag == 'a'}}"> |
|
478 |
+ <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}" hover-class="wxParse-a-hover"> |
|
479 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
480 |
+ <template is="wxParse6" data="{{item}}" /> |
|
481 |
+ </block> |
|
482 |
+ </view> |
|
483 |
+ </block> |
|
484 |
+ |
|
485 |
+ <block wx:elif="{{item.tag == 'br'}}"> |
|
486 |
+ <template is="WxParseBr"></template> |
|
487 |
+ </block> |
|
488 |
+ <!--其他块级标签--> |
|
489 |
+ <block wx:elif="{{item.tagType == 'block'}}"> |
|
490 |
+ <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"> |
|
491 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
492 |
+ <template is="wxParse6" data="{{item}}" /> |
|
493 |
+ </block> |
|
494 |
+ </view> |
|
495 |
+ </block> |
|
496 |
+ |
|
497 |
+ <!--内联标签--> |
|
498 |
+ <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}"> |
|
499 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
500 |
+ <template is="wxParse6" data="{{item}}" /> |
|
501 |
+ </block> |
|
502 |
+ </view> |
|
503 |
+ |
|
504 |
+ </block> |
|
505 |
+ |
|
506 |
+ <!--判断是否是文本节点--> |
|
507 |
+ <block wx:elif="{{item.node == 'text'}}"> |
|
508 |
+ <!--如果是,直接进行--> |
|
509 |
+ <template is="WxEmojiView" data="{{item}}" /> |
|
510 |
+ </block> |
|
511 |
+ |
|
512 |
+</template> |
|
513 |
+ |
|
514 |
+<!--循环模版--> |
|
515 |
+<template name="wxParse6"> |
|
516 |
+ <!--<template is="wxParse7" data="{{item}}" />--> |
|
517 |
+ <!--判断是否是标签节点--> |
|
518 |
+ <block wx:if="{{item.node == 'element'}}"> |
|
519 |
+ <block wx:if="{{item.tag == 'button'}}"> |
|
520 |
+ <button type="default" size="mini"> |
|
521 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
522 |
+ <template is="wxParse7" data="{{item}}" /> |
|
523 |
+ </block> |
|
524 |
+ </button> |
|
525 |
+ </block> |
|
526 |
+ <!--li类型--> |
|
527 |
+ <block wx:elif="{{item.tag == 'li'}}"> |
|
528 |
+ <view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}"> |
|
529 |
+ <view class="{{item.classStr}} wxParse-li-inner"> |
|
530 |
+ <view class="{{item.classStr}} wxParse-li-text"> |
|
531 |
+ <view class="{{item.classStr}} wxParse-li-circle"></view> |
|
532 |
+ </view> |
|
533 |
+ <view class="{{item.classStr}} wxParse-li-text"> |
|
534 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
535 |
+ <template is="wxParse7" data="{{item}}" /> |
|
536 |
+ </block> |
|
537 |
+ </view> |
|
538 |
+ </view> |
|
539 |
+ </view> |
|
540 |
+ </block> |
|
541 |
+ |
|
542 |
+ <!--video类型--> |
|
543 |
+ <block wx:elif="{{item.tag == 'video'}}"> |
|
544 |
+ <template is="wxParseVideo" data="{{item}}" /> |
|
545 |
+ </block> |
|
546 |
+ |
|
547 |
+ <!--img类型--> |
|
548 |
+ <block wx:elif="{{item.tag == 'img'}}"> |
|
549 |
+ <template is="wxParseImg" data="{{item}}" /> |
|
550 |
+ </block> |
|
551 |
+ |
|
552 |
+ <!--a类型--> |
|
553 |
+ <block wx:elif="{{item.tag == 'a'}}"> |
|
554 |
+ <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}" hover-class="wxParse-a-hover"> |
|
555 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
556 |
+ <template is="wxParse7" data="{{item}}" /> |
|
557 |
+ </block> |
|
558 |
+ </view> |
|
559 |
+ </block> |
|
560 |
+ |
|
561 |
+ <block wx:elif="{{item.tag == 'br'}}"> |
|
562 |
+ <template is="WxParseBr"></template> |
|
563 |
+ </block> |
|
564 |
+ <!--其他块级标签--> |
|
565 |
+ <block wx:elif="{{item.tagType == 'block'}}"> |
|
566 |
+ <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"> |
|
567 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
568 |
+ <template is="wxParse7" data="{{item}}" /> |
|
569 |
+ </block> |
|
570 |
+ </view> |
|
571 |
+ </block> |
|
572 |
+ |
|
573 |
+ <!--内联标签--> |
|
574 |
+ <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}"> |
|
575 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
576 |
+ <template is="wxParse7" data="{{item}}" /> |
|
577 |
+ </block> |
|
578 |
+ </view> |
|
579 |
+ |
|
580 |
+ </block> |
|
581 |
+ |
|
582 |
+ <!--判断是否是文本节点--> |
|
583 |
+ <block wx:elif="{{item.node == 'text'}}"> |
|
584 |
+ <!--如果是,直接进行--> |
|
585 |
+ <template is="WxEmojiView" data="{{item}}" /> |
|
586 |
+ </block> |
|
587 |
+ |
|
588 |
+</template> |
|
589 |
+<!--循环模版--> |
|
590 |
+<template name="wxParse7"> |
|
591 |
+ <!--<template is="wxParse8" data="{{item}}" />--> |
|
592 |
+ <!--判断是否是标签节点--> |
|
593 |
+ <block wx:if="{{item.node == 'element'}}"> |
|
594 |
+ <block wx:if="{{item.tag == 'button'}}"> |
|
595 |
+ <button type="default" size="mini"> |
|
596 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
597 |
+ <template is="wxParse8" data="{{item}}" /> |
|
598 |
+ </block> |
|
599 |
+ </button> |
|
600 |
+ </block> |
|
601 |
+ <!--li类型--> |
|
602 |
+ <block wx:elif="{{item.tag == 'li'}}"> |
|
603 |
+ <view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}"> |
|
604 |
+ <view class="{{item.classStr}} wxParse-li-inner"> |
|
605 |
+ <view class="{{item.classStr}} wxParse-li-text"> |
|
606 |
+ <view class="{{item.classStr}} wxParse-li-circle"></view> |
|
607 |
+ </view> |
|
608 |
+ <view class="{{item.classStr}} wxParse-li-text"> |
|
609 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
610 |
+ <template is="wxParse8" data="{{item}}" /> |
|
611 |
+ </block> |
|
612 |
+ </view> |
|
613 |
+ </view> |
|
614 |
+ </view> |
|
615 |
+ </block> |
|
616 |
+ |
|
617 |
+ <!--video类型--> |
|
618 |
+ <block wx:elif="{{item.tag == 'video'}}"> |
|
619 |
+ <template is="wxParseVideo" data="{{item}}" /> |
|
620 |
+ </block> |
|
621 |
+ |
|
622 |
+ <!--img类型--> |
|
623 |
+ <block wx:elif="{{item.tag == 'img'}}"> |
|
624 |
+ <template is="wxParseImg" data="{{item}}" /> |
|
625 |
+ </block> |
|
626 |
+ |
|
627 |
+ <!--a类型--> |
|
628 |
+ <block wx:elif="{{item.tag == 'a'}}"> |
|
629 |
+ <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}" hover-class="wxParse-a-hover"> |
|
630 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
631 |
+ <template is="wxParse8" data="{{item}}" /> |
|
632 |
+ </block> |
|
633 |
+ </view> |
|
634 |
+ </block> |
|
635 |
+ |
|
636 |
+ <block wx:elif="{{item.tag == 'br'}}"> |
|
637 |
+ <template is="WxParseBr"></template> |
|
638 |
+ </block> |
|
639 |
+ <!--其他块级标签--> |
|
640 |
+ <block wx:elif="{{item.tagType == 'block'}}"> |
|
641 |
+ <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"> |
|
642 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
643 |
+ <template is="wxParse8" data="{{item}}" /> |
|
644 |
+ </block> |
|
645 |
+ </view> |
|
646 |
+ </block> |
|
647 |
+ |
|
648 |
+ <!--内联标签--> |
|
649 |
+ <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}"> |
|
650 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
651 |
+ <template is="wxParse8" data="{{item}}" /> |
|
652 |
+ </block> |
|
653 |
+ </view> |
|
654 |
+ |
|
655 |
+ </block> |
|
656 |
+ |
|
657 |
+ <!--判断是否是文本节点--> |
|
658 |
+ <block wx:elif="{{item.node == 'text'}}"> |
|
659 |
+ <!--如果是,直接进行--> |
|
660 |
+ <template is="WxEmojiView" data="{{item}}" /> |
|
661 |
+ </block> |
|
662 |
+ |
|
663 |
+</template> |
|
664 |
+ |
|
665 |
+<!--循环模版--> |
|
666 |
+<template name="wxParse8"> |
|
667 |
+ <!--<template is="wxParse9" data="{{item}}" />--> |
|
668 |
+ <!--判断是否是标签节点--> |
|
669 |
+ <block wx:if="{{item.node == 'element'}}"> |
|
670 |
+ <block wx:if="{{item.tag == 'button'}}"> |
|
671 |
+ <button type="default" size="mini"> |
|
672 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
673 |
+ <template is="wxParse9" data="{{item}}" /> |
|
674 |
+ </block> |
|
675 |
+ </button> |
|
676 |
+ </block> |
|
677 |
+ <!--li类型--> |
|
678 |
+ <block wx:elif="{{item.tag == 'li'}}"> |
|
679 |
+ <view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}"> |
|
680 |
+ <view class="{{item.classStr}} wxParse-li-inner"> |
|
681 |
+ <view class="{{item.classStr}} wxParse-li-text"> |
|
682 |
+ <view class="{{item.classStr}} wxParse-li-circle"></view> |
|
683 |
+ </view> |
|
684 |
+ <view class="{{item.classStr}} wxParse-li-text"> |
|
685 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
686 |
+ <template is="wxParse9" data="{{item}}" /> |
|
687 |
+ </block> |
|
688 |
+ </view> |
|
689 |
+ </view> |
|
690 |
+ </view> |
|
691 |
+ </block> |
|
692 |
+ |
|
693 |
+ <!--video类型--> |
|
694 |
+ <block wx:elif="{{item.tag == 'video'}}"> |
|
695 |
+ <template is="wxParseVideo" data="{{item}}" /> |
|
696 |
+ </block> |
|
697 |
+ |
|
698 |
+ <!--img类型--> |
|
699 |
+ <block wx:elif="{{item.tag == 'img'}}"> |
|
700 |
+ <template is="wxParseImg" data="{{item}}" /> |
|
701 |
+ </block> |
|
702 |
+ |
|
703 |
+ <!--a类型--> |
|
704 |
+ <block wx:elif="{{item.tag == 'a'}}"> |
|
705 |
+ <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}" hover-class="wxParse-a-hover"> |
|
706 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
707 |
+ <template is="wxParse9" data="{{item}}" /> |
|
708 |
+ </block> |
|
709 |
+ </view> |
|
710 |
+ </block> |
|
711 |
+ |
|
712 |
+ <block wx:elif="{{item.tag == 'br'}}"> |
|
713 |
+ <template is="WxParseBr"></template> |
|
714 |
+ </block> |
|
715 |
+ <!--其他块级标签--> |
|
716 |
+ <block wx:elif="{{item.tagType == 'block'}}"> |
|
717 |
+ <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"> |
|
718 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
719 |
+ <template is="wxParse9" data="{{item}}" /> |
|
720 |
+ </block> |
|
721 |
+ </view> |
|
722 |
+ </block> |
|
723 |
+ |
|
724 |
+ <!--内联标签--> |
|
725 |
+ <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}"> |
|
726 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
727 |
+ <template is="wxParse9" data="{{item}}" /> |
|
728 |
+ </block> |
|
729 |
+ </view> |
|
730 |
+ |
|
731 |
+ </block> |
|
732 |
+ |
|
733 |
+ <!--判断是否是文本节点--> |
|
734 |
+ <block wx:elif="{{item.node == 'text'}}"> |
|
735 |
+ <!--如果是,直接进行--> |
|
736 |
+ <template is="WxEmojiView" data="{{item}}" /> |
|
737 |
+ </block> |
|
738 |
+ |
|
739 |
+</template> |
|
740 |
+ |
|
741 |
+<!--循环模版--> |
|
742 |
+<template name="wxParse9"> |
|
743 |
+ <!--<template is="wxParse10" data="{{item}}" />--> |
|
744 |
+ <!--判断是否是标签节点--> |
|
745 |
+ <block wx:if="{{item.node == 'element'}}"> |
|
746 |
+ <block wx:if="{{item.tag == 'button'}}"> |
|
747 |
+ <button type="default" size="mini"> |
|
748 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
749 |
+ <template is="wxParse10" data="{{item}}" /> |
|
750 |
+ </block> |
|
751 |
+ </button> |
|
752 |
+ </block> |
|
753 |
+ <!--li类型--> |
|
754 |
+ <block wx:elif="{{item.tag == 'li'}}"> |
|
755 |
+ <view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}"> |
|
756 |
+ <view class="{{item.classStr}} wxParse-li-inner"> |
|
757 |
+ <view class="{{item.classStr}} wxParse-li-text"> |
|
758 |
+ <view class="{{item.classStr}} wxParse-li-circle"></view> |
|
759 |
+ </view> |
|
760 |
+ <view class="{{item.classStr}} wxParse-li-text"> |
|
761 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
762 |
+ <template is="wxParse10" data="{{item}}" /> |
|
763 |
+ </block> |
|
764 |
+ </view> |
|
765 |
+ </view> |
|
766 |
+ </view> |
|
767 |
+ </block> |
|
768 |
+ |
|
769 |
+ <!--video类型--> |
|
770 |
+ <block wx:elif="{{item.tag == 'video'}}"> |
|
771 |
+ <template is="wxParseVideo" data="{{item}}" /> |
|
772 |
+ </block> |
|
773 |
+ |
|
774 |
+ <!--img类型--> |
|
775 |
+ <block wx:elif="{{item.tag == 'img'}}"> |
|
776 |
+ <template is="wxParseImg" data="{{item}}" /> |
|
777 |
+ </block> |
|
778 |
+ |
|
779 |
+ <!--a类型--> |
|
780 |
+ <block wx:elif="{{item.tag == 'a'}}"> |
|
781 |
+ <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}" hover-class="wxParse-a-hover"> |
|
782 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
783 |
+ <template is="wxParse10" data="{{item}}" /> |
|
784 |
+ </block> |
|
785 |
+ </view> |
|
786 |
+ </block> |
|
787 |
+ |
|
788 |
+ <block wx:elif="{{item.tag == 'br'}}"> |
|
789 |
+ <template is="WxParseBr"></template> |
|
790 |
+ </block> |
|
791 |
+ <!--其他块级标签--> |
|
792 |
+ <block wx:elif="{{item.tagType == 'block'}}"> |
|
793 |
+ <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"> |
|
794 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
795 |
+ <template is="wxParse10" data="{{item}}" /> |
|
796 |
+ </block> |
|
797 |
+ </view> |
|
798 |
+ </block> |
|
799 |
+ |
|
800 |
+ <!--内联标签--> |
|
801 |
+ <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}"> |
|
802 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
803 |
+ <template is="wxParse10" data="{{item}}" /> |
|
804 |
+ </block> |
|
805 |
+ </view> |
|
806 |
+ |
|
807 |
+ </block> |
|
808 |
+ |
|
809 |
+ <!--判断是否是文本节点--> |
|
810 |
+ <block wx:elif="{{item.node == 'text'}}"> |
|
811 |
+ <!--如果是,直接进行--> |
|
812 |
+ <template is="WxEmojiView" data="{{item}}" /> |
|
813 |
+ </block> |
|
814 |
+ |
|
815 |
+</template> |
|
816 |
+ |
|
817 |
+<!--循环模版--> |
|
818 |
+<template name="wxParse10"> |
|
819 |
+ <!--<template is="wxParse11" data="{{item}}" />--> |
|
820 |
+ <!--判断是否是标签节点--> |
|
821 |
+ <block wx:if="{{item.node == 'element'}}"> |
|
822 |
+ <block wx:if="{{item.tag == 'button'}}"> |
|
823 |
+ <button type="default" size="mini"> |
|
824 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
825 |
+ <template is="wxParse11" data="{{item}}" /> |
|
826 |
+ </block> |
|
827 |
+ </button> |
|
828 |
+ </block> |
|
829 |
+ <!--li类型--> |
|
830 |
+ <block wx:elif="{{item.tag == 'li'}}"> |
|
831 |
+ <view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}"> |
|
832 |
+ <view class="{{item.classStr}} wxParse-li-inner"> |
|
833 |
+ <view class="{{item.classStr}} wxParse-li-text"> |
|
834 |
+ <view class="{{item.classStr}} wxParse-li-circle"></view> |
|
835 |
+ </view> |
|
836 |
+ <view class="{{item.classStr}} wxParse-li-text"> |
|
837 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
838 |
+ <template is="wxParse11" data="{{item}}" /> |
|
839 |
+ </block> |
|
840 |
+ </view> |
|
841 |
+ </view> |
|
842 |
+ </view> |
|
843 |
+ </block> |
|
844 |
+ |
|
845 |
+ <!--video类型--> |
|
846 |
+ <block wx:elif="{{item.tag == 'video'}}"> |
|
847 |
+ <template is="wxParseVideo" data="{{item}}" /> |
|
848 |
+ </block> |
|
849 |
+ |
|
850 |
+ <!--img类型--> |
|
851 |
+ <block wx:elif="{{item.tag == 'img'}}"> |
|
852 |
+ <template is="wxParseImg" data="{{item}}" /> |
|
853 |
+ </block> |
|
854 |
+ |
|
855 |
+ <!--a类型--> |
|
856 |
+ <block wx:elif="{{item.tag == 'a'}}"> |
|
857 |
+ <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}" hover-class="wxParse-a-hover"> |
|
858 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
859 |
+ <template is="wxParse11" data="{{item}}" /> |
|
860 |
+ </block> |
|
861 |
+ </view> |
|
862 |
+ </block> |
|
863 |
+ |
|
864 |
+ <block wx:elif="{{item.tag == 'br'}}"> |
|
865 |
+ <template is="WxParseBr"></template> |
|
866 |
+ </block> |
|
867 |
+ <!--其他块级标签--> |
|
868 |
+ <block wx:elif="{{item.tagType == 'block'}}"> |
|
869 |
+ <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"> |
|
870 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
871 |
+ <template is="wxParse11" data="{{item}}" /> |
|
872 |
+ </block> |
|
873 |
+ </view> |
|
874 |
+ </block> |
|
875 |
+ |
|
876 |
+ <!--内联标签--> |
|
877 |
+ <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}"> |
|
878 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
879 |
+ <template is="wxParse11" data="{{item}}" /> |
|
880 |
+ </block> |
|
881 |
+ </view> |
|
882 |
+ |
|
883 |
+ </block> |
|
884 |
+ |
|
885 |
+ <!--判断是否是文本节点--> |
|
886 |
+ <block wx:elif="{{item.node == 'text'}}"> |
|
887 |
+ <!--如果是,直接进行--> |
|
888 |
+ <template is="WxEmojiView" data="{{item}}" /> |
|
889 |
+ </block> |
|
890 |
+ |
|
891 |
+</template> |
|
892 |
+ |
|
893 |
+<!--循环模版--> |
|
894 |
+<template name="wxParse11"> |
|
895 |
+ <!--<template is="wxParse12" data="{{item}}" />--> |
|
896 |
+ <!--判断是否是标签节点--> |
|
897 |
+ <block wx:if="{{item.node == 'element'}}"> |
|
898 |
+ <block wx:if="{{item.tag == 'button'}}"> |
|
899 |
+ <button type="default" size="mini"> |
|
900 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
901 |
+ <template is="wxParse12" data="{{item}}" /> |
|
902 |
+ </block> |
|
903 |
+ </button> |
|
904 |
+ </block> |
|
905 |
+ <!--li类型--> |
|
906 |
+ <block wx:elif="{{item.tag == 'li'}}"> |
|
907 |
+ <view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}"> |
|
908 |
+ <view class="{{item.classStr}} wxParse-li-inner"> |
|
909 |
+ <view class="{{item.classStr}} wxParse-li-text"> |
|
910 |
+ <view class="{{item.classStr}} wxParse-li-circle"></view> |
|
911 |
+ </view> |
|
912 |
+ <view class="{{item.classStr}} wxParse-li-text"> |
|
913 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
914 |
+ <template is="wxParse12" data="{{item}}" /> |
|
915 |
+ </block> |
|
916 |
+ </view> |
|
917 |
+ </view> |
|
918 |
+ </view> |
|
919 |
+ </block> |
|
920 |
+ |
|
921 |
+ <!--video类型--> |
|
922 |
+ <block wx:elif="{{item.tag == 'video'}}"> |
|
923 |
+ <template is="wxParseVideo" data="{{item}}" /> |
|
924 |
+ </block> |
|
925 |
+ |
|
926 |
+ <!--img类型--> |
|
927 |
+ <block wx:elif="{{item.tag == 'img'}}"> |
|
928 |
+ <template is="wxParseImg" data="{{item}}" /> |
|
929 |
+ </block> |
|
930 |
+ |
|
931 |
+ <!--a类型--> |
|
932 |
+ <block wx:elif="{{item.tag == 'a'}}"> |
|
933 |
+ <view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}" hover-class="wxParse-a-hover"> |
|
934 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
935 |
+ <template is="wxParse12" data="{{item}}" /> |
|
936 |
+ </block> |
|
937 |
+ </view> |
|
938 |
+ </block> |
|
939 |
+ |
|
940 |
+ <block wx:elif="{{item.tag == 'br'}}"> |
|
941 |
+ <template is="WxParseBr"></template> |
|
942 |
+ </block> |
|
943 |
+ <!--其他块级标签--> |
|
944 |
+ <block wx:elif="{{item.tagType == 'block'}}"> |
|
945 |
+ <view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}"> |
|
946 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
947 |
+ <template is="wxParse12" data="{{item}}" /> |
|
948 |
+ </block> |
|
949 |
+ </view> |
|
950 |
+ </block> |
|
951 |
+ |
|
952 |
+ <!--内联标签--> |
|
953 |
+ <view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}"> |
|
954 |
+ <block wx:for="{{item.nodes}}" wx:for-item="item" wx:key=""> |
|
955 |
+ <template is="wxParse12" data="{{item}}" /> |
|
956 |
+ </block> |
|
957 |
+ </view> |
|
958 |
+ |
|
959 |
+ </block> |
|
960 |
+ |
|
961 |
+ <!--判断是否是文本节点--> |
|
962 |
+ <block wx:elif="{{item.node == 'text'}}"> |
|
963 |
+ <!--如果是,直接进行--> |
|
964 |
+ <template is="WxEmojiView" data="{{item}}" /> |
|
965 |
+ </block> |
|
966 |
+ |
|
967 |
+</template> |
@@ -0,0 +1,270 @@ |
||
1 |
+/** |
|
2 |
+ * author: Di (微信小程序开发工程师) |
|
3 |
+ * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com) |
|
4 |
+ * 垂直微信小程序开发交流社区 |
|
5 |
+ * |
|
6 |
+ * github地址: https://github.com/icindy/wxParse |
|
7 |
+ * |
|
8 |
+ * for: 微信小程序富文本解析 |
|
9 |
+ * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184 |
|
10 |
+ */ |
|
11 |
+ |
|
12 |
+.wxParse { |
|
13 |
+ margin: 0 5px; |
|
14 |
+ font-family: Helvetica, sans-serif; |
|
15 |
+ font-size: 28rpx; |
|
16 |
+ color: #666; |
|
17 |
+ line-height: 1.8; |
|
18 |
+} |
|
19 |
+view { |
|
20 |
+ word-break: break-all; |
|
21 |
+} |
|
22 |
+.wxParse-inline { |
|
23 |
+ display: inline; |
|
24 |
+ margin: 0; |
|
25 |
+ padding: 0; |
|
26 |
+} |
|
27 |
+/*//标题 */ |
|
28 |
+.wxParse-div { |
|
29 |
+ margin: 0; |
|
30 |
+ padding: 0; |
|
31 |
+} |
|
32 |
+.wxParse-h1 { |
|
33 |
+ font-size: 2em; |
|
34 |
+ margin: 0.67em 0; |
|
35 |
+} |
|
36 |
+.wxParse-h2 { |
|
37 |
+ font-size: 1.5em; |
|
38 |
+ margin: 0.75em 0; |
|
39 |
+} |
|
40 |
+.wxParse-h3 { |
|
41 |
+ font-size: 1.17em; |
|
42 |
+ margin: 0.83em 0; |
|
43 |
+} |
|
44 |
+.wxParse-h4 { |
|
45 |
+ margin: 1.12em 0; |
|
46 |
+} |
|
47 |
+.wxParse-h5 { |
|
48 |
+ font-size: 0.83em; |
|
49 |
+ margin: 1.5em 0; |
|
50 |
+} |
|
51 |
+.wxParse-h6 { |
|
52 |
+ font-size: 0.75em; |
|
53 |
+ margin: 1.67em 0; |
|
54 |
+} |
|
55 |
+ |
|
56 |
+.wxParse-h1 { |
|
57 |
+ font-size: 18px; |
|
58 |
+ font-weight: 400; |
|
59 |
+ margin-bottom: 0.9em; |
|
60 |
+} |
|
61 |
+.wxParse-h2 { |
|
62 |
+ font-size: 16px; |
|
63 |
+ font-weight: 400; |
|
64 |
+ margin-bottom: 0.34em; |
|
65 |
+} |
|
66 |
+.wxParse-h3 { |
|
67 |
+ font-weight: 400; |
|
68 |
+ font-size: 15px; |
|
69 |
+ margin-bottom: 0.34em; |
|
70 |
+} |
|
71 |
+.wxParse-h4 { |
|
72 |
+ font-weight: 400; |
|
73 |
+ font-size: 14px; |
|
74 |
+ margin-bottom: 0.24em; |
|
75 |
+} |
|
76 |
+.wxParse-h5 { |
|
77 |
+ font-weight: 400; |
|
78 |
+ font-size: 13px; |
|
79 |
+ margin-bottom: 0.14em; |
|
80 |
+} |
|
81 |
+.wxParse-h6 { |
|
82 |
+ font-weight: 400; |
|
83 |
+ font-size: 12px; |
|
84 |
+ margin-bottom: 0.04em; |
|
85 |
+} |
|
86 |
+ |
|
87 |
+.wxParse-h1, |
|
88 |
+.wxParse-h2, |
|
89 |
+.wxParse-h3, |
|
90 |
+.wxParse-h4, |
|
91 |
+.wxParse-h5, |
|
92 |
+.wxParse-h6, |
|
93 |
+.wxParse-b, |
|
94 |
+.wxParse-strong { |
|
95 |
+ font-weight: bolder; |
|
96 |
+} |
|
97 |
+ |
|
98 |
+.wxParse-i, |
|
99 |
+.wxParse-cite, |
|
100 |
+.wxParse-em, |
|
101 |
+.wxParse-var, |
|
102 |
+.wxParse-address { |
|
103 |
+ font-style: italic; |
|
104 |
+} |
|
105 |
+.wxParse-pre, |
|
106 |
+.wxParse-tt, |
|
107 |
+.wxParse-code, |
|
108 |
+.wxParse-kbd, |
|
109 |
+.wxParse-samp { |
|
110 |
+ font-family: monospace; |
|
111 |
+} |
|
112 |
+.wxParse-pre { |
|
113 |
+ white-space: pre; |
|
114 |
+} |
|
115 |
+.wxParse-big { |
|
116 |
+ font-size: 1.17em; |
|
117 |
+} |
|
118 |
+.wxParse-small, |
|
119 |
+.wxParse-sub, |
|
120 |
+.wxParse-sup { |
|
121 |
+ font-size: 0.83em; |
|
122 |
+} |
|
123 |
+.wxParse-sub { |
|
124 |
+ vertical-align: sub; |
|
125 |
+} |
|
126 |
+.wxParse-sup { |
|
127 |
+ vertical-align: super; |
|
128 |
+} |
|
129 |
+.wxParse-s, |
|
130 |
+.wxParse-strike, |
|
131 |
+.wxParse-del { |
|
132 |
+ text-decoration: line-through; |
|
133 |
+} |
|
134 |
+/*wxparse-自定义个性化的css样式*/ |
|
135 |
+/*增加video的css样式*/ |
|
136 |
+.wxParse-strong, |
|
137 |
+.wxParse-s { |
|
138 |
+ display: inline; |
|
139 |
+} |
|
140 |
+.wxParse-a { |
|
141 |
+ color: #576b95; |
|
142 |
+ text-decoration: underline; |
|
143 |
+ word-break: break-all; |
|
144 |
+ overflow: auto; |
|
145 |
+} |
|
146 |
+ |
|
147 |
+.wxParse-a-hover { |
|
148 |
+ opacity: 0.8; |
|
149 |
+} |
|
150 |
+ |
|
151 |
+.wxParse-video { |
|
152 |
+ text-align: center; |
|
153 |
+ margin: 10px 0; |
|
154 |
+} |
|
155 |
+ |
|
156 |
+.wxParse-video-video { |
|
157 |
+ width: 100%; |
|
158 |
+} |
|
159 |
+ |
|
160 |
+.wxParse-img { |
|
161 |
+ /*background-color: #efefef;*/ |
|
162 |
+ overflow: hidden; |
|
163 |
+} |
|
164 |
+ |
|
165 |
+.wxParse-blockquote { |
|
166 |
+ margin: 0; |
|
167 |
+ padding: 10px 0 10px 5px; |
|
168 |
+ font-family: Courier, Calibri, '宋体'; |
|
169 |
+ background: #f5f5f5; |
|
170 |
+ border-left: 3px solid #dbdbdb; |
|
171 |
+} |
|
172 |
+ |
|
173 |
+.wxParse-code, |
|
174 |
+.wxParse-wxxxcode-style { |
|
175 |
+ display: inline; |
|
176 |
+ background: #f5f5f5; |
|
177 |
+} |
|
178 |
+.wxParse-ul { |
|
179 |
+ margin: 20rpx 10rpx; |
|
180 |
+} |
|
181 |
+ |
|
182 |
+.wxParse-li, |
|
183 |
+.wxParse-li-inner { |
|
184 |
+ display: flex; |
|
185 |
+ align-items: baseline; |
|
186 |
+} |
|
187 |
+.wxParse-li-text { |
|
188 |
+ align-items: center; |
|
189 |
+} |
|
190 |
+ |
|
191 |
+.wxParse-li-circle { |
|
192 |
+ display: inline-flex; |
|
193 |
+ width: 6px; |
|
194 |
+ height: 6px; |
|
195 |
+ border-radius: 3px; |
|
196 |
+ background-color: #333; |
|
197 |
+ margin-right: 5px; |
|
198 |
+} |
|
199 |
+ |
|
200 |
+.wxParse-li-square { |
|
201 |
+ display: inline-flex; |
|
202 |
+ width: 10rpx; |
|
203 |
+ height: 10rpx; |
|
204 |
+ background-color: #333; |
|
205 |
+ margin-right: 5px; |
|
206 |
+} |
|
207 |
+.wxParse-li-ring { |
|
208 |
+ display: inline-flex; |
|
209 |
+ width: 10rpx; |
|
210 |
+ height: 10rpx; |
|
211 |
+ border: 2rpx solid #333; |
|
212 |
+ border-radius: 50%; |
|
213 |
+ background-color: #fff; |
|
214 |
+ margin-right: 5px; |
|
215 |
+} |
|
216 |
+ |
|
217 |
+/*.wxParse-table{ |
|
218 |
+ width: 100%; |
|
219 |
+ height: 400px; |
|
220 |
+} |
|
221 |
+.wxParse-thead,.wxParse-tfoot,.wxParse-tr{ |
|
222 |
+ display: flex; |
|
223 |
+ flex-direction: row; |
|
224 |
+} |
|
225 |
+.wxParse-th,.wxParse-td{ |
|
226 |
+ display: flex; |
|
227 |
+ width: 580px; |
|
228 |
+ overflow: auto; |
|
229 |
+}*/ |
|
230 |
+ |
|
231 |
+.wxParse-u { |
|
232 |
+ text-decoration: underline; |
|
233 |
+} |
|
234 |
+.wxParse-hide { |
|
235 |
+ display: none; |
|
236 |
+} |
|
237 |
+.WxEmojiView { |
|
238 |
+ align-items: center; |
|
239 |
+} |
|
240 |
+.wxEmoji { |
|
241 |
+ width: 16px; |
|
242 |
+ height: 16px; |
|
243 |
+} |
|
244 |
+.wxParse-tr { |
|
245 |
+ display: flex; |
|
246 |
+ border-right: 1px solid #e0e0e0; |
|
247 |
+ border-bottom: 1px solid #e0e0e0; |
|
248 |
+ border-top: 1px solid #e0e0e0; |
|
249 |
+} |
|
250 |
+.wxParse-th, |
|
251 |
+.wxParse-td { |
|
252 |
+ flex: 1; |
|
253 |
+ padding: 5px; |
|
254 |
+ font-size: 28rpx; |
|
255 |
+ border-left: 1px solid #e0e0e0; |
|
256 |
+ word-break: break-all; |
|
257 |
+} |
|
258 |
+.wxParse-td:last { |
|
259 |
+ border-top: 1px solid #e0e0e0; |
|
260 |
+} |
|
261 |
+.wxParse-th { |
|
262 |
+ background: #f0f0f0; |
|
263 |
+ border-top: 1px solid #e0e0e0; |
|
264 |
+} |
|
265 |
+.wxParse-del { |
|
266 |
+ display: inline; |
|
267 |
+} |
|
268 |
+.wxParse-figure { |
|
269 |
+ overflow: hidden; |
|
270 |
+} |
@@ -0,0 +1,10 @@ |
||
1 |
+var filter = function (text) { |
|
2 |
+ if (text) { |
|
3 |
+ var pattern = '\\\\n'; |
|
4 |
+ var target = '\n'; |
|
5 |
+ var reg = getRegExp(pattern, 'g'); |
|
6 |
+ return text.replace(reg, target); |
|
7 |
+ } |
|
8 |
+}; |
|
9 |
+ |
|
10 |
+module.exports.filter = filter; |