pan rel="">
+ width: 30rpx;
+ height: 7.5rpx;
+ content: '/';
+ background: #959595;
+ border-radius: 7.5rpx;
+ transform: rotate(-90deg);
+}
+.main .title {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ height: 60rpx;
+ margin-top: 60rpx;
+ font-size: 14pt;
+}
+.main .title text {
+ color: #0967b2;
+}
+form {
+ width: 500rpx;
+ margin: 36rpx 0;
+}
+form .item {
+ display: flex;
+ align-items: center;
+ box-sizing: border-box;
+ justify-content: flex-start;
+ width: 100%;
+ height: 80rpx;
+ margin-top: 24rpx;
+ border: 1px #efefef solid;
+ border-radius: 5px;
+}
+form .item input {
+ box-sizing: border-box;
+ width: calc(100% - 2px);
+ height: calc(100% - 2px);
+ padding: 12rpx;
+ font-size: 13pt;
+}
+form .item .placeholder {
+ font-size: 11pt;
+ color: #959595;
+}
+form .item button {
+ display: flex;
+ align-items: center;
+ box-sizing: border-box;
+ justify-content: space-between;
+ width: calc(100% - 2px);
+ height: calc(100% - 2px);
+ padding: 12rpx;
+ background-color: #fff;
+}
+form .item button .placeholder {
+ font-size: 11pt;
+ color: #767676;
+}
+form .item button .txt {
+ font-size: 13pt;
+ color: #000;
+}
+form .item button .arrow {
+ width: 14rpx;
+ height: 14rpx;
+ box-sizing: border-box;
+ border-top: 2px solid #959595;
+ border-right: 2px solid #959595;
+ transform: rotate(45deg);
+}
+form .confirm {
+ display: flex;
+ align-items: center;
+ box-sizing: border-box;
+ justify-content: center;
+ width: 500rpx;
+ height: 80rpx;
+ margin-top: 36rpx;
+ color: #fff;
+ background-color: #0967b2;
+ border-radius: 5px;
+}
@@ -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; |