1u2oyPG-VWlNx6c{CRfilEQuuTw%h(r`YcB7Impb**3F1DzsHes{~tcZ%V
zwCF~Hy2y;~7cmPdf-syAEuArE{?~g{g`0s&^+WWnu
z0F3=MNVpj`V3Ytb=3$tCQ4C3y#W4AcUvl-002sxP)FQ2e%zmF#8_C$LvNjW-+*dDG
zI&ASthXJsxY99`8+I{uX=ZSDmlGJl_b8Z4)KRXO?8yW_c`beT${M!R{OMvZ02v7yz
z{L(4d5O8F5JRArC9z&B~^2U=XNlmF~`IY_B+euhzf&q6lyMG@EDAfA>^FZJRT$K}cgmmk(
z2o?=Ur7+ta0DOQGGVBzF&O<5emwHoSR{$`O8d)bT<4h>vo<~HZ)EtTRS^&}CCCTF)
zZbVySN&F-o1INSgX1dzK-0w10!i2W)T;m|*dF0B0#K&O)#&THWRnJ0*9_+W5o0o2D
zGxw#wY$!6+vjifJcqCo40gg&@BkNuO#fIFgfs8htw=yo<0$YEYI-fHQ)_bIrHi+J6
zC8b?8agfzvYL#DRL4jL(Itw7BUDBIrko?HhTRZ1NcBkYz={
+ console.log(res)
+ if(res.data.success){
+ this.setData({activityDetail:res.data.data});
+ let article = res.data.data.content;
+ WxParse.wxParse('article', 'html', article, that,5);
+ } else{
+ wx.showToast({
+ title: res.data.msg,
+ icon:'none'
+ })
+ }
+ })
+ },
+ call(){
+ wx.makePhoneCall({
+ phoneNumber: this.data.activityDetail.publisherVo.phone,
+ fail:function(){
+ console.log('取消')
+ }
+ })
+ },
+ collect(){
+ let data = {};
+ data.id = this.data.activityDetail.id;
+ data.type = 'collect';
+ data.status = this.data.activityDetail.collect ? false : true;
+ if(wx.getStorageSync('userInfo') != ''){
+ this.requestCollect(data)
+ } else{
+ wx.getUserProfile({
+ desc: '展示用户信息', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
+ success: (res) => {
+ console.log(res)
+ var iv = res.iv;
+ var encryptedData = res.encryptedData;
+ var userInfo = res.userInfo;
+ wx.login({
+ success: request => {
+ // 发送 res.code 到后台换取 openId, sessionKey, unionId
+ app.http('POST','wxapp/auth',{code : request.code,iv:iv,encryptedData:encryptedData}).then(
+ response =>{
+ if(response.data.success){
+ wx.setStorageSync('token', 'Bearer '+ response.data.data.token);
+ wx.setStorageSync('userInfo', userInfo);
+ this.requestCollect(data)
+ } else{
+ wx.showToast({
+ title: response.data.msg,
+ icon : 'none'
+ })
+ }
+ }
+ )
+ }
+ })
+ }
+ })
+ }
+ },
+ requestCollect(data){
+ app.http('POST','activity/collect',data).then((res)=>{
+ if(res.data.success){
+ wx.showToast({
+ title: '操作成功!',
+ })
+ this.getDetail();
+ } else{
+ wx.showToast({
+ title: res.data.msg,
+ icon:'none'
+ })
+ }
+ })
+ },
+ toSignPage(){
+ if(wx.getStorageSync('userInfo') != ''){
+ wx.navigateTo({
+ url: '../signIn/index?id='+this.data.activityId,
+ })
+ } else{
+ wx.getUserProfile({
+ desc: '展示用户信息', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
+ success: (res) => {
+ console.log(res)
+ var iv = res.iv;
+ var encryptedData = res.encryptedData;
+ var userInfo = res.userInfo;
+ wx.login({
+ success: request => {
+ // 发送 res.code 到后台换取 openId, sessionKey, unionId
+ app.http('POST','wxapp/auth',{code : request.code,iv:iv,encryptedData:encryptedData}).then(
+ response =>{
+ if(response.data.success){
+ wx.setStorageSync('token', 'Bearer '+ response.data.data.token);
+ wx.setStorageSync('userInfo', userInfo);
+ wx.navigateTo({
+ url: '../signIn/index?id='+this.data.activityId,
+ })
+ } else{
+ wx.showToast({
+ title: response.data.msg,
+ icon : 'none'
+ })
+ }
+ }
+ )
+ }
+ })
+ }
+ })
+ }
+ },
+ /**
+ * 生命周期函数--监听页面初次渲染完成
+ */
+ onReady: function () {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面显示
+ */
+ onShow: function () {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面隐藏
+ */
+ onHide: function () {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面卸载
+ */
+ onUnload: function () {
+
+ },
+
+ /**
+ * 页面相关事件处理函数--监听用户下拉动作
+ */
+ onPullDownRefresh: function () {
+
+ },
+
+ /**
+ * 页面上拉触底事件的处理函数
+ */
+ onReachBottom: function () {
+
+ },
+
+ /**
+ * 用户点击右上角分享
+ */
+ onShareAppMessage: function () {
+
+ }
+})
\ No newline at end of file
diff --git a/pages/activity/describe/index.json b/pages/activity/describe/index.json
new file mode 100644
index 0000000..facafdc
--- /dev/null
+++ b/pages/activity/describe/index.json
@@ -0,0 +1,4 @@
+{
+ "usingComponents": {},
+ "navigationBarTitleText": "活动详情"
+}
\ No newline at end of file
diff --git a/pages/activity/describe/index.wxml b/pages/activity/describe/index.wxml
new file mode 100644
index 0000000..27fb68f
--- /dev/null
+++ b/pages/activity/describe/index.wxml
@@ -0,0 +1,31 @@
+
+
+
+ {{activityDetail.name}}
+
+ {{activityDetail.publisherVo.name}}
+ {{activityDetail.updateTime}} 发布
+
+
+
+
+
+
+
+
+
+ 拨号
+
+
+
+ {{activityDetail.collect ? '已收藏':'收藏'}}
+
+
+
+ 报名截止
+ 活动结束
+ 等待报名
+ 立即报名
+
+
+
diff --git a/pages/activity/describe/index.wxss b/pages/activity/describe/index.wxss
new file mode 100644
index 0000000..58fabb8
--- /dev/null
+++ b/pages/activity/describe/index.wxss
@@ -0,0 +1,64 @@
+/* pages/activity/describe/index.wxss */
+.describe-box{
+ min-height: 100%;
+ background: #f2f2f2;
+ padding: 32rpx;
+ box-sizing: border-box;
+}
+.activity-title{
+ color: #000000;
+ font-size: 36rpx;
+ line-height: 50rpx;
+ margin-bottom: 24rpx;
+}
+.name{
+ display: inline-block;
+ margin-right: 64rpx;
+ color: #EBB672;
+}
+.time-box{
+ color: #7D7D7D;
+ font-size: 24rpx;
+}
+.content{
+ margin-top: 38rpx;
+ padding-bottom: 130rpx;
+}
+.handle-box {
+ width: 100%;
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ background: #fff;
+ padding: 42rpx 32rpx 80rpx;
+ box-sizing: border-box;
+ box-shadow: 0px -2px 8px 0px rgba(0,0,0,0.1);
+}
+.call-box{
+ margin-right: 54rpx;
+}
+.call-box image{
+ width: 37rpx;
+ height: 37rpx;
+ font-size: 28rpx;
+ color: #333333;
+ margin-right: 12rpx;
+}
+.cancel-btn{
+ width: 234rpx;
+ height: 60rpx;
+ text-align: center;
+ line-height: 60rpx;
+ background: #F4F4F4;
+ border-radius: 30rpx;
+ color: #868686;
+ font-size: 32rpx;
+}
+.signIn-btn{
+ background: #EBB672;
+ color: #fff;
+}
+.wxParse-p image{
+ width: 100% !important;
+ height: auto;
+}
\ No newline at end of file
diff --git a/pages/activity/detail/index.js b/pages/activity/detail/index.js
new file mode 100644
index 0000000..8b86f15
--- /dev/null
+++ b/pages/activity/detail/index.js
@@ -0,0 +1,222 @@
+// pages/activity/detail/index.js
+const app = getApp();
+import util from '../../../utils/util'
+Page({
+
+ /**
+ * 页面的初始数据
+ */
+ data: {
+ activityId:'',
+ activityDetail:{},
+ current:1,
+ },
+
+ /**
+ * 生命周期函数--监听页面加载
+ */
+ onLoad: function (options) {
+ let erCodeId = wx.getStorageSync('activityId');
+ if(options.id){
+ this.setData({activityId:options.id});
+ this.getDetail()
+ }
+ if(erCodeId && !options.id){ //扫码进来
+ console.log('扫码进来')
+ this.setData({activityId:erCodeId});
+ this.getDetail()
+ }
+ },
+ getDetail(){
+ app.http('GET','activity/activityInfo/'+this.data.activityId).then((res)=>{
+ if(res.data.success){
+ let detail = res.data.data;
+ detail.time1 = util.setTime(detail.createTime).split(' ')[0];
+ detail.time2 = util.setTime(detail.applyStartTime).split(' ')[0];
+ detail.time3 = util.setTime(detail.applyEndTime).split(' ')[0];
+ detail.time4 = util.setTime(detail.activityEndTime).split(' ')[0];
+ detail.flag = detail.flag.split(',');
+ detail.activityStartTime = util.setTime(detail.activityStartTime);
+ detail.activityEndTime = util.setTime(detail.activityEndTime);
+ detail.applyStartTime = util.setTime(detail.applyStartTime);
+ detail.applyEndTime = util.setTime(detail.applyEndTime);
+ this.setData({activityDetail:detail,current:detail.status})
+ } else{
+ wx.showToast({
+ title: res.data.msg,
+ icon:'none'
+ })
+ }
+ })
+ },
+ openMap(){
+ const latitude = this.data.activityDetail.latitude
+ const longitude = this.data.activityDetail.longitude
+ wx.openLocation({
+ latitude,
+ longitude,
+ scale: 18
+ })
+ },
+ shareClick(){
+ wx.showShareMenu({
+ withShareTicket: true,
+ menus: ['shareAppMessage', 'shareTimeline']
+ })
+ },
+ call(){
+ wx.makePhoneCall({
+ phoneNumber: this.data.activityDetail.publisherVo.phone,
+ fail:function(){
+ console.log('取消')
+ }
+ })
+ },
+ collect(){
+ let data = {};
+ data.id = this.data.activityDetail.id;
+ data.type = 'collect';
+ data.status = this.data.activityDetail.collect ? false : true;
+ if(wx.getStorageSync('userInfo') != ''){
+ this.requestCollect(data)
+ } else{
+ wx.getUserProfile({
+ desc: '展示用户信息', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
+ success: (res) => {
+ console.log(res)
+ var iv = res.iv;
+ var encryptedData = res.encryptedData;
+ var userInfo = res.userInfo;
+ wx.login({
+ success: request => {
+ // 发送 res.code 到后台换取 openId, sessionKey, unionId
+ app.http('POST','wxapp/auth',{code : request.code,iv:iv,encryptedData:encryptedData}).then(
+ response =>{
+ if(response.data.success){
+ wx.setStorageSync('token', 'Bearer '+ response.data.data.token);
+ wx.setStorageSync('userInfo', userInfo);
+ this.requestCollect(data)
+ } else{
+ wx.showToast({
+ title: response.data.msg,
+ icon : 'none'
+ })
+ }
+ }
+ )
+ }
+ })
+ }
+ })
+ }
+ },
+ requestCollect(data){
+ app.http('POST','activity/collect',data).then((res)=>{
+ if(res.data.success){
+ wx.showToast({
+ title: '操作成功!',
+ })
+ this.getDetail();
+ } else{
+ wx.showToast({
+ title: res.data.msg,
+ icon:'none'
+ })
+ }
+ })
+ },
+ toSignPage(){
+ if(wx.getStorageSync('userInfo') != ''){
+ wx.navigateTo({
+ url: '../signIn/index?id='+this.data.activityId,
+ })
+ } else{
+ this.getUserProfile()
+ }
+ },
+ toDescribe(){
+ wx.navigateTo({
+ url: '../describe/index?id='+this.data.activityDetail.id,
+ })
+ },
+ getUserProfile(){
+ wx.getUserProfile({
+ desc: '展示用户信息', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
+ success: (res) => {
+ console.log(res)
+ var iv = res.iv;
+ var encryptedData = res.encryptedData;
+ var userInfo = res.userInfo;
+ wx.login({
+ success: request => {
+ // 发送 res.code 到后台换取 openId, sessionKey, unionId
+ app.http('POST','wxapp/auth',{code : request.code,iv:iv,encryptedData:encryptedData}).then(
+ response =>{
+ if(response.data.success){
+ wx.setStorageSync('token', 'Bearer '+ response.data.data.token);
+ wx.setStorageSync('userInfo', userInfo);
+ wx.navigateTo({
+ url: '../signIn/index?id='+this.data.activityId,
+ })
+ } else{
+ wx.showToast({
+ title: response.data.msg,
+ icon : 'none'
+ })
+ }
+ }
+ )
+ }
+ })
+ }
+ })
+ },
+ /**
+ * 生命周期函数--监听页面初次渲染完成
+ */
+ onReady: function () {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面显示
+ */
+ onShow: function () {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面隐藏
+ */
+ onHide: function () {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面卸载
+ */
+ onUnload: function () {
+
+ },
+
+ /**
+ * 页面相关事件处理函数--监听用户下拉动作
+ */
+ onPullDownRefresh: function () {
+
+ },
+
+ /**
+ * 页面上拉触底事件的处理函数
+ */
+ onReachBottom: function () {
+
+ },
+
+ /**
+ * 用户点击右上角分享
+ */
+ onShareAppMessage: function () {
+
+ }
+})
\ No newline at end of file
diff --git a/pages/activity/detail/index.json b/pages/activity/detail/index.json
new file mode 100644
index 0000000..5c29706
--- /dev/null
+++ b/pages/activity/detail/index.json
@@ -0,0 +1,7 @@
+{
+ "usingComponents": {
+ "wux-steps": "../../../dist/steps/index",
+ "wux-step": "../../../dist/step/index"
+ },
+ "navigationBarTitleText": "活动详情"
+}
\ No newline at end of file
diff --git a/pages/activity/detail/index.wxml b/pages/activity/detail/index.wxml
new file mode 100644
index 0000000..d47c564
--- /dev/null
+++ b/pages/activity/detail/index.wxml
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+ {{activityDetail.name}}
+
+ ¥{{activityDetail.price}}/人
+
+ {{item}}
+
+
+
+
+
+
+
+
+
+
+
+
+ 活动举办时间:
+ {{activityDetail.activityStartTime}} 至 {{activityDetail.activityEndTime}}
+
+
+ 报名截止时间:
+ {{activityDetail.applyEndTime}}
+
+
+ 活动举办地址:
+ {{activityDetail.address}}
+
+
+ 参加人数限制:
+ {{activityDetail.users.length}}/{{activityDetail.limit}}
+
+
+
+
+
+ 活动简介
+ {{activityDetail.desc}}
+ 查看详情
+
+
+ 最近参与人:
+
+
+
+
+
+
+
+ 拨号
+
+
+
+ {{activityDetail.collect ? '已收藏':'收藏'}}
+
+
+
+
+ 报名截止
+ 活动结束
+ 等待报名
+ 立即报名
+
+
+
diff --git a/pages/activity/detail/index.wxss b/pages/activity/detail/index.wxss
new file mode 100644
index 0000000..8e8ef0a
--- /dev/null
+++ b/pages/activity/detail/index.wxss
@@ -0,0 +1,188 @@
+/* pages/activity/detail/index.wxss */
+.activityDetail-page{
+ background: #f2f2f2;
+ min-height: 100%;
+ padding-bottom: 240rpx;
+}
+.activity-info-box,.company-info-box,.activity-des-box,.join-box{
+ width: 100%;
+ box-sizing: border-box;
+ padding: 0 32rpx 40rpx;
+ background: #fff;
+ font-size: 32rpx;
+}
+.activity-banner{
+ width: 100%;
+ height: 404rpx;
+ border-radius: 12rpx;
+ overflow: hidden;
+}
+image{
+ width: 100%;
+}
+.activity-title{
+ color: #333333;
+ font-weight: 600;
+ line-height: 44rpx;
+ margin: 32rpx 0;
+}
+.price{
+ min-width: 200rpx;
+ color: #EBB672;
+ font-weight: 600;
+ margin-right: 28rpx;
+}
+.tips{
+ width: 74%;
+ flex-wrap: wrap;
+}
+.tip-item{
+ height: 36rpx;
+ margin-bottom: 6rpx;
+ line-height: 36rpx;
+ text-align: center;
+ padding: 0rpx 16rpx;
+ color: #fff;
+ font-size: 20rpx;
+ background: #C93535;
+ margin-right: 24rpx;
+}
+.default-btn{
+ height: 36rpx;
+ margin-bottom: 6rpx;
+ line-height: 36rpx;
+ text-align: center;
+ padding: 0rpx 16rpx;
+ color: #fff;
+ font-size: 20rpx;
+ background: #A29E9E;
+ margin-right: 24rpx;
+}
+.join-box{
+ height: 100rpx;
+ padding: 26rpx 32rpx;
+ box-sizing: border-box;
+ color: #727272;
+}
+
+.step-box{
+ margin-top: 32rpx;
+}
+.wux-step--process .wux-step__icon {
+ background: #FFC985 !important;
+ border-color: #FFC985 !important;
+}
+.wux-step__title {
+ color: #B5B5B5 !important;
+ font-size: 20rpx !important;
+ font-weight: 400 !important;
+}
+.wux-step--process .wux-step__title{
+ color: #FFC985 !important;
+}
+.wux-step__content{
+ font-size: 20rpx !important;
+ margin-top: 0 !important;
+}
+.wux-step--process .wux-step__content{
+ color: #FFC985 !important;
+}
+.wux-step__bd {
+ margin-top: 10rpx !important;
+}
+
+.info-item{
+ display: flex;
+ justify-content: start;
+ align-items: center;
+ margin-top: 40rpx;
+ color: #353535;
+ font-size: 28rpx;
+}
+.label{
+ width: 180rpx;
+ text-align: left;
+ margin-right: 20rpx;
+ color: #868686;
+}
+.headerImg-info{
+ width: calc(100% - 180rpx);
+ color: #333333;
+ overflow-x: scroll;
+ white-space: nowrap;
+}
+.info image{
+ width: 68rpx;
+ height: 68rpx;
+ margin-left: 16rpx;
+ display: inline-block;
+ border-radius: 50%;
+}
+
+.company-info-box,.activity-des-box{
+ margin-top: 32rpx;
+ padding-top: 32rpx;
+ font-size: 24rpx;
+}
+.company-logo image{
+ width: 132rpx;
+ height: 132rpx;
+ margin-right: 24rpx;
+ border-radius: 50%;
+}
+.company-name{
+ color: #333333;
+ font-size: 28rpx;
+ margin-bottom: 16rpx;
+}
+.activity-des-box{
+ color: #727272;
+}
+.title2{
+ color: #333;
+ font-size: 32rpx;
+ margin-bottom: 24rpx;
+}
+.see-detail{
+ color: #333;
+ text-align: center;
+ margin-top: 12rpx;
+}
+.see-detail image{
+ width: 24rpx;
+ height: 24rpx;
+}
+.handle-box {
+ width: 100%;
+ box-sizing: border-box;
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ background: #fff;
+ padding: 42rpx 32rpx 80rpx;
+ box-shadow: 0px -2px 8px 0px rgba(0,0,0,0.1);
+}
+.call-box{
+ margin-right: 54rpx;
+}
+.call-box image{
+ width: 37rpx;
+ height: 37rpx;
+ font-size: 28rpx;
+ color: #333333;
+ margin-right: 12rpx;
+}
+.cancel-btn{
+ width: 234rpx;
+ height: 60rpx;
+ text-align: center;
+ line-height: 60rpx;
+ background: #F4F4F4;
+ border-radius: 30rpx;
+ color: #868686;
+ font-size: 32rpx;
+}
+.signIn-btn{
+ background: #EBB672;
+ color: #fff;
+}
\ No newline at end of file
diff --git a/pages/activity/index.js b/pages/activity/index.js
new file mode 100644
index 0000000..a6562ca
--- /dev/null
+++ b/pages/activity/index.js
@@ -0,0 +1,97 @@
+// pages/activity/index.js
+const app = getApp();
+import util from '../../utils/util'
+Page({
+
+ /**
+ * 页面的初始数据
+ */
+ data: {
+ active: 0,
+ activityList:[]
+ },
+
+ /**
+ * 生命周期函数--监听页面加载
+ */
+ onLoad: function (options) {
+
+ },
+ getActivityList(){
+ app.http('POST','activity/activityList',{status:this.data.active}).then((res)=>{
+ if(res.data.success){
+ res.data.data.content.forEach((item)=>{
+ item.activityStartTime = util.getWeek(item.activityStartTime)
+ item.activityEndTime = util.getWeek(item.activityEndTime)
+ })
+ this.setData({activityList : res.data.data.content})
+ } else{
+ wx.showToast({
+ title: res.data.msg,
+ icon:'none'
+ })
+ }
+ })
+ },
+ toDetail(e){
+ let id = e.currentTarget.dataset.id;
+ wx.navigateTo({
+ url: './detail/index?id='+id,
+ })
+ },
+ tabClick(e){
+ var i = Number(e.currentTarget.dataset.i);
+ this.setData({
+ active : i
+ })
+ this.getActivityList();
+ },
+ /**
+ * 生命周期函数--监听页面初次渲染完成
+ */
+ onReady: function () {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面显示
+ */
+ onShow: function () {
+ this.getActivityList();
+ },
+
+ /**
+ * 生命周期函数--监听页面隐藏
+ */
+ onHide: function () {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面卸载
+ */
+ onUnload: function () {
+
+ },
+
+ /**
+ * 页面相关事件处理函数--监听用户下拉动作
+ */
+ onPullDownRefresh: function () {
+
+ },
+
+ /**
+ * 页面上拉触底事件的处理函数
+ */
+ onReachBottom: function () {
+
+ },
+
+ /**
+ * 用户点击右上角分享
+ */
+ onShareAppMessage: function () {
+
+ }
+})
\ No newline at end of file
diff --git a/pages/activity/index.json b/pages/activity/index.json
new file mode 100644
index 0000000..d8bbc60
--- /dev/null
+++ b/pages/activity/index.json
@@ -0,0 +1,4 @@
+{
+ "usingComponents": {},
+ "navigationBarTitleText": ""
+}
\ No newline at end of file
diff --git a/pages/activity/index.wxml b/pages/activity/index.wxml
new file mode 100644
index 0000000..3d2e090
--- /dev/null
+++ b/pages/activity/index.wxml
@@ -0,0 +1,36 @@
+
+
+
+
+ 报名中
+ 已完成
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.cateName}} {{item.name}}
+
+
+ {{item.activityStartTime}}
+ {{item.address}}
+
+
+ 已报名人数:{{item.users.length}}
+ 筹备中
+ 报名中
+ 待举办
+ 已结束
+
+
+
+
+ —已显示全部活动—
+
diff --git a/pages/activity/index.wxss b/pages/activity/index.wxss
new file mode 100644
index 0000000..a54526d
--- /dev/null
+++ b/pages/activity/index.wxss
@@ -0,0 +1,56 @@
+/* pages/activity/index.wxss */
+page{
+ height: 100%;
+}
+.activity-page{
+ background: #f2f2f2;
+ min-height: 100%;
+ padding-top: 150rpx;
+}
+.tab-box{
+ width: 100%;
+ height: 82rpx;
+ background: #fff;
+ margin-bottom: 50rpx;
+}
+.tab-item{
+ height: 100%;
+ line-height: 82rpx;
+ font-size: 34rpx;
+ color: #A5A5A5;
+ padding-bottom: 12rpx;
+ box-sizing: border-box;
+ font-weight: 600;
+ position: relative;
+}
+.tab-item::after{
+ display: block;
+ content: '';
+ width: 100%;
+ height: 6rpx;
+ background: #EBB672;
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ opacity: 0;
+ transform:scaleX(0);
+ transition: all .2s cubic-bezier(.18,.89,.17,.88),opacity .15s ease;
+}
+.tab-item-active{
+ color: #333;
+}
+.tab-item-active::after{
+ opacity: 1;
+ transform: scaleX(1);
+}
+
+.activity-item{
+ margin-bottom: 24rpx;
+ background: #fff;
+ padding: 16rpx 32rpx;
+}
+.address{
+ width:70%;
+ display:inline-block;
+ margin-left:10rpx;
+}
diff --git a/pages/activity/signIn/confirm/index.js b/pages/activity/signIn/confirm/index.js
new file mode 100644
index 0000000..f34bf0a
--- /dev/null
+++ b/pages/activity/signIn/confirm/index.js
@@ -0,0 +1,113 @@
+// pages/activity/signIn/confirm/index.js
+const app = getApp();
+import util from '../../../../utils/util'
+Page({
+
+ /**
+ * 页面的初始数据
+ */
+ data: {
+ payInfo : {},
+ canClick:true
+ },
+
+ /**
+ * 生命周期函数--监听页面加载
+ */
+ onLoad: function (options) {
+ let info = JSON.parse(decodeURIComponent(options.payInfo));
+ info.activity.activityStartTime = util.setTime(info.activity.activityStartTime);
+ info.activity.activityEndTime = util.setTime(info.activity.activityEndTime);
+ this.setData({
+ payInfo:info
+ })
+ console.log(this.data.payInfo)
+ },
+ backUpPage(){
+ wx.navigateBack({
+ delta: 1,
+ })
+ },
+ toPay(){
+ if(this.data.canClick){
+ this.setData({canClick : false});
+ app.http('POST','activity/orderPay',{id:this.data.payInfo.order.id}).then((res)=>{
+ console.log(res)
+ if(res.data.success){
+ //微信支付
+ wx.requestPayment({
+ timeStamp: res.data.data.timeStamp,
+ nonceStr: res.data.data.nonceStr,
+ package: res.data.data.packageValue,
+ signType: 'MD5',
+ paySign: res.data.data.paySign,
+ success: response=> {
+ this.setData({canClick: true});
+ wx.showToast({
+ title: '支付成功!',
+ duration: 1500
+ });
+ setTimeout(()=> {
+ wx.navigateTo({
+ url: '../paymentSuccess/index',
+ })
+ }, 1500);
+ },
+ fail: response=> {
+ this.setData({canClick: true});
+ console.log(response)
+ }
+ })
+ }
+ })
+ }
+ },
+ /**
+ * 生命周期函数--监听页面初次渲染完成
+ */
+ onReady: function () {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面显示
+ */
+ onShow: function () {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面隐藏
+ */
+ onHide: function () {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面卸载
+ */
+ onUnload: function () {
+
+ },
+
+ /**
+ * 页面相关事件处理函数--监听用户下拉动作
+ */
+ onPullDownRefresh: function () {
+
+ },
+
+ /**
+ * 页面上拉触底事件的处理函数
+ */
+ onReachBottom: function () {
+
+ },
+
+ /**
+ * 用户点击右上角分享
+ */
+ onShareAppMessage: function () {
+
+ }
+})
\ No newline at end of file
diff --git a/pages/activity/signIn/confirm/index.json b/pages/activity/signIn/confirm/index.json
new file mode 100644
index 0000000..5210a2c
--- /dev/null
+++ b/pages/activity/signIn/confirm/index.json
@@ -0,0 +1,6 @@
+{
+ "usingComponents": {},
+ "navigationBarTitleText": "信息确认",
+ "navigationBarBackgroundColor": "#EBB672",
+ "navigationBarTextStyle":"white"
+}
\ No newline at end of file
diff --git a/pages/activity/signIn/confirm/index.wxml b/pages/activity/signIn/confirm/index.wxml
new file mode 100644
index 0000000..63da68f
--- /dev/null
+++ b/pages/activity/signIn/confirm/index.wxml
@@ -0,0 +1,42 @@
+
+
+
+
+ 参加活动人员信息
+
+
+ 修改
+
+
+
+
+ 昵称
+ {{payInfo.order.name}}
+
+
+ 手机号
+ {{payInfo.order.phone}}
+
+
+
+
+ {{payInfo.activity.name}}
+
+ 人数
+ {{payInfo.order.num}}
+
+
+ 活动时间
+ {{payInfo.activity.activityStartTime}}~{{payInfo.activity.activityEndTime}}
+
+
+ 活动地址
+ {{payInfo.activity.address}}
+
+
+ 结算金额
+ ¥{{payInfo.activity.price}}
+
+
+ 支付
+
diff --git a/pages/activity/signIn/confirm/index.wxss b/pages/activity/signIn/confirm/index.wxss
new file mode 100644
index 0000000..40c86dd
--- /dev/null
+++ b/pages/activity/signIn/confirm/index.wxss
@@ -0,0 +1,82 @@
+/* pages/activity/signIn/confirm/index.wxss */
+.confirm-page{
+ width: 100%;
+ min-height: 100%;
+ background: #f2f2f2;
+}
+.userInfo-box{
+ box-sizing: border-box;
+ padding: 56rpx 32rpx;
+ background: #fff;
+ margin-bottom: 32rpx;
+
+}
+.title-box{
+ font-size: 32rpx;
+ color: #333;
+ margin-bottom: 38rpx;
+}
+.edit-box{
+ font-size:24rpx;
+}
+.edit-box image{
+ width: 24rpx;
+ height: 24rpx;
+ margin-right: 4rpx;
+}
+.info-box{
+ font-size: 28rpx;
+}
+.phone{
+ margin-left: 300rpx;
+}
+.name view:nth-child(1){
+ color: #868686;
+ margin-bottom: 16rpx;
+}
+
+.activity-info-box{
+ width: 100%;
+ background: #fff;
+ padding: 32rpx;
+ box-sizing: border-box;
+}
+.title{
+ font-size: 32rpx;
+ color: #333;
+ line-height: 48rpx;
+ font-weight: bold;
+ margin-bottom: 40rpx;
+}
+.activity-info{
+ display: flex;
+ justify-content: space-between;
+ font-size: 28rpx;
+ margin-bottom: 24rpx;
+}
+.address{
+ overflow:hidden;
+ white-space: pre-wrap;
+ width: 80%;
+ text-align: right;
+}
+.settle-box{
+ font-size: 32rpx;
+ font-weight: 600;
+ margin-top: 60rpx;
+}
+.money{
+ color: #EBB672;
+}
+.pay-btn{
+ position: fixed;
+ bottom: 60rpx;
+ left: 0;
+ width: 100%;
+ height: 76rpx;
+ background: #EBB672;
+ color: #FFF;
+ font-size: 32rpx;
+ line-height: 76rpx;
+ text-align: center;
+}
\ No newline at end of file
diff --git a/pages/activity/signIn/index.js b/pages/activity/signIn/index.js
new file mode 100644
index 0000000..3f26dba
--- /dev/null
+++ b/pages/activity/signIn/index.js
@@ -0,0 +1,110 @@
+// pages/activity/signIn/index.js
+const app = getApp();
+Page({
+
+ /**
+ * 页面的初始数据
+ */
+ data: {
+ activityId : '',
+ num:'2'
+ },
+
+ /**
+ * 生命周期函数--监听页面加载
+ */
+ onLoad: function (options) {
+ this.setData({activityId:options.id})
+ },
+ toConfirm(e){
+ console.log(e)
+ const values = e.detail.value
+ let name = values.name,
+ phone = values.phone,
+ code = values.code,
+ WeChat = values.WeChat,
+ num = values.num;
+ if(name == '' || phone == '' || code == ''){
+ wx.showToast({
+ title: '带*项为必填项,请检查后重新提交!',
+ icon:'none'
+ })
+ return
+ } else if(!/^1(3|4|5|7|8)\d{9}$/.test(phone)){
+ wx.showToast({
+ title: '请填写正确手机号',
+ icon:'none'
+ })
+ return
+ } else if(num == ''){
+ num = 1
+ }
+ app.http('post','activity/joinActivity',{activiyId:this.data.activityId,name:name,phone:phone,num:num}).then((res)=>{
+ console.log(res)
+ if(res.data.success){
+ let payInfo = encodeURIComponent(JSON.stringify(res.data.data));
+ wx.navigateTo({
+ url: './confirm/index?payInfo='+payInfo,
+ })
+ }
+ })
+ },
+ inpChange(e){
+ console.log(e)
+ let num = e.detail.value;
+ if(num <= 0){
+ num = 1
+ } else if(num > 2){
+ num = 2
+ }
+ this.setData({num})
+ },
+ /**
+ * 生命周期函数--监听页面初次渲染完成
+ */
+ onReady: function () {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面显示
+ */
+ onShow: function () {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面隐藏
+ */
+ onHide: function () {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面卸载
+ */
+ onUnload: function () {
+
+ },
+
+ /**
+ * 页面相关事件处理函数--监听用户下拉动作
+ */
+ onPullDownRefresh: function () {
+
+ },
+
+ /**
+ * 页面上拉触底事件的处理函数
+ */
+ onReachBottom: function () {
+
+ },
+
+ /**
+ * 用户点击右上角分享
+ */
+ onShareAppMessage: function () {
+
+ }
+})
\ No newline at end of file
diff --git a/pages/activity/signIn/index.json b/pages/activity/signIn/index.json
new file mode 100644
index 0000000..50b4490
--- /dev/null
+++ b/pages/activity/signIn/index.json
@@ -0,0 +1,6 @@
+{
+ "usingComponents": {},
+ "navigationBarTitleText": "报名信息填写",
+ "navigationBarBackgroundColor": "#EBB672",
+ "navigationBarTextStyle":"white"
+}
\ No newline at end of file
diff --git a/pages/activity/signIn/index.wxml b/pages/activity/signIn/index.wxml
new file mode 100644
index 0000000..02a8639
--- /dev/null
+++ b/pages/activity/signIn/index.wxml
@@ -0,0 +1,39 @@
+
+
+
+ 参加活动人员信息填写
+ 请仔细填写,方便后台快速审核通过
+
+
+
+
+
+
diff --git a/pages/activity/signIn/index.wxss b/pages/activity/signIn/index.wxss
new file mode 100644
index 0000000..58fdf2d
--- /dev/null
+++ b/pages/activity/signIn/index.wxss
@@ -0,0 +1,57 @@
+/* pages/activity/signIn/index.wxss */
+.signIn-page{
+ padding: 56rpx 32rpx;
+}
+.title-box text:nth-child(1){
+ font-size: 42rpx;
+ font-weight: bold;
+ display: block;
+ line-height: 58rpx;
+ margin-bottom: 8rpx;
+}
+.title-box text:nth-child(2){
+ font-size: 24rpx;
+ display: block;
+ color: #F96B1C;
+}
+.form-item{
+ font-size: 32rpx;
+ color: #333;
+ margin-top: 46rpx;
+}
+.form-item input[type="text"]{
+ padding: 26rpx 0 32rpx;
+ border-bottom: 2px solid #F4F4F4;
+ font-size: 28rpx;
+}
+.input-box input[type="text"]{
+ width: calc(100% - 310rpx);
+}
+.form-item input[type="button"]{
+ width: 175rpx;
+ height:78rpx;
+ line-height: 78rpx;
+ text-align: center;
+ color: #fff;
+ background: #EBB672;
+ padding: 0 10rpx;
+ border-radius: 8rpx;
+ font-size: 28rpx;
+ margin-left: 12rpx;
+}
+
+.submit-btn{
+ width: 100% !important;
+ position: fixed;
+ bottom: 60rpx;
+ left: 0;
+ width: 100%;
+ height: 76rpx !important;
+ background: #EBB672;
+ color: #FFF;
+ font-size: 32rpx;
+ line-height: 76rpx !important;
+ padding: 0 !important;
+ text-align: center;
+ border-radius: 0 !important;
+}
\ No newline at end of file
diff --git a/pages/activity/signIn/paymentSuccess/index.js b/pages/activity/signIn/paymentSuccess/index.js
new file mode 100644
index 0000000..de29036
--- /dev/null
+++ b/pages/activity/signIn/paymentSuccess/index.js
@@ -0,0 +1,70 @@
+// pages/activity/signIn/paymentSuccess/index.js
+Page({
+
+ /**
+ * 页面的初始数据
+ */
+ data: {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面加载
+ */
+ onLoad: function (options) {
+
+ },
+ toJoin(){
+ wx.switchTab({
+ url: '../../../user/index',
+ })
+ },
+ /**
+ * 生命周期函数--监听页面初次渲染完成
+ */
+ onReady: function () {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面显示
+ */
+ onShow: function () {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面隐藏
+ */
+ onHide: function () {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面卸载
+ */
+ onUnload: function () {
+
+ },
+
+ /**
+ * 页面相关事件处理函数--监听用户下拉动作
+ */
+ onPullDownRefresh: function () {
+
+ },
+
+ /**
+ * 页面上拉触底事件的处理函数
+ */
+ onReachBottom: function () {
+
+ },
+
+ /**
+ * 用户点击右上角分享
+ */
+ onShareAppMessage: function () {
+
+ }
+})
\ No newline at end of file
diff --git a/pages/activity/signIn/paymentSuccess/index.json b/pages/activity/signIn/paymentSuccess/index.json
new file mode 100644
index 0000000..5b81479
--- /dev/null
+++ b/pages/activity/signIn/paymentSuccess/index.json
@@ -0,0 +1,6 @@
+{
+ "usingComponents": {},
+ "navigationBarTitleText": "支付",
+ "navigationBarBackgroundColor": "#EBB672",
+ "navigationBarTextStyle":"white"
+}
\ No newline at end of file
diff --git a/pages/activity/signIn/paymentSuccess/index.wxml b/pages/activity/signIn/paymentSuccess/index.wxml
new file mode 100644
index 0000000..396afa9
--- /dev/null
+++ b/pages/activity/signIn/paymentSuccess/index.wxml
@@ -0,0 +1,7 @@
+
+
+
+ 支付成功
+ 支付完成,请前往我的订单中查看核销码
+ 前往个人中心
+
diff --git a/pages/activity/signIn/paymentSuccess/index.wxss b/pages/activity/signIn/paymentSuccess/index.wxss
new file mode 100644
index 0000000..18ffebf
--- /dev/null
+++ b/pages/activity/signIn/paymentSuccess/index.wxss
@@ -0,0 +1,30 @@
+/* pages/activity/signIn/paymentSuccess/index.wxss */
+.page{
+ width: 100%;
+ height: 100%;
+ box-sizing: border-box;
+ background: #FAFAFA;
+ padding-top: 100rpx;
+ text-align: center;
+ font-size:32rpx;
+}
+.page image{
+ width: 230rpx;
+ height: 212rpx;
+ margin:0 auto 48rpx;
+ display: block;
+}
+.tips{
+ font-size: 48rpx;
+ color: #353535;
+ margin-bottom: 24rpx;
+}
+.btn{
+ width: 380rpx;
+ height: 80rpx;
+ background: #EBB672;
+ border-radius: 8rpx;
+ color: #fff;
+ line-height: 80rpx;
+ margin: 190rpx auto;
+}
\ No newline at end of file
diff --git a/pages/demandHall/index.wxss b/pages/demandHall/index.wxss
index 0537784..902dcb3 100644
--- a/pages/demandHall/index.wxss
+++ b/pages/demandHall/index.wxss
@@ -12,9 +12,6 @@ image{
width: 100%;
padding: 0 40rpx;
background: #fff;
-}
-.top-l-box{
-
}
.tab-item{
width: 162rpx;
diff --git a/pages/demandHall/resourcesContact/index.js b/pages/demandHall/resourcesContact/index.js
index 4d1ab5b..7a9a496 100644
--- a/pages/demandHall/resourcesContact/index.js
+++ b/pages/demandHall/resourcesContact/index.js
@@ -73,12 +73,10 @@ Page({
})
},2000)
} else{
- if(res.data.status == 5110 || res.data.status == 5111 || res.data.status == 5112){
- wx.showToast({
- title: res.data.msg,
- icon: 'none'
- })
- }
+ wx.showToast({
+ title: res.data.msg,
+ icon: 'none'
+ })
}
})
},
diff --git a/pages/index/index.js b/pages/index/index.js
index e5eae1d..128a6cb 100644
--- a/pages/index/index.js
+++ b/pages/index/index.js
@@ -1,6 +1,7 @@
// index.js
// 获取应用实例
const app = getApp()
+import util from '../../utils/util'
var QQMapWX = require('../../utils/qqmap-wx-jssdk.min.js');
var qqmapsdk;
Page({
@@ -23,6 +24,7 @@ Page({
navHeight: app.globalData.navHeight,
menuTop: app.globalData.menuTop,
active: 1,
+ recommendActivity: [],
demandList: [],
resourcesList: [],
province: '',
@@ -36,6 +38,12 @@ Page({
});
this.getLocation()
},
+ toActiveDetail(e){
+ let id = e.currentTarget.dataset.id;
+ wx.navigateTo({
+ url: '/pages/activity/detail/index?id=' + id,
+ })
+ },
tabClick(e){
this.setData({
active: e.currentTarget.dataset.i
@@ -49,10 +57,14 @@ Page({
getCagetoryList(){
app.http('get','index').then((res)=>{
if(res.data.success){
+ res.data.data.recommendActivity.content.forEach((item)=>{
+ item.activityStartTime = util.getWeek(item.activityStartTime)
+ })
this.setData({
demandList: res.data.data.demandList,
resourcesList: res.data.data.resourcesDtos,
- cagetoryList: res.data.data.cagetoryDtos
+ cagetoryList: res.data.data.cagetoryDtos,
+ recommendActivity: res.data.data.recommendActivity.content
})
}
})
diff --git a/pages/index/index.wxml b/pages/index/index.wxml
index c5f62a6..031f78d 100644
--- a/pages/index/index.wxml
+++ b/pages/index/index.wxml
@@ -1,3 +1,4 @@
+
@@ -38,20 +39,19 @@
-
-
+
+
- 人工智能
- 人工智能
+ {{flag}}
-
+
- 武汉国际会展中心
+ {{item.address}}
- 2021.07.31 - 2022-11-30
+ {{item.activityStartTime}}
@@ -98,10 +98,10 @@
-
+
最新供应
需求广场
- 金牌投资人
+
diff --git a/pages/release/companyAuth/index.js b/pages/release/companyAuth/index.js
index b22ffee..151448d 100644
--- a/pages/release/companyAuth/index.js
+++ b/pages/release/companyAuth/index.js
@@ -74,7 +74,7 @@ Page({
let idx = Number(e.detail.value)
this.setData({
resourcesIdx: idx,
- ['form.resourceCagetoryId']: this.data.resourcesList[idx].id
+ ['form.industryId']: this.data.resourcesList[idx].id
})
},
//选择行业
@@ -321,7 +321,7 @@ Page({
* 生命周期函数--监听页面显示
*/
onShow: function () {
-
+
},
/**
diff --git a/pages/release/companyAuth/index.wxss b/pages/release/companyAuth/index.wxss
index 8a46a80..680d626 100644
--- a/pages/release/companyAuth/index.wxss
+++ b/pages/release/companyAuth/index.wxss
@@ -1,7 +1,5 @@
/* pages/release/companyAuth/index.wxss */
-.auth-page{
-}
.is-legal-box{
width: 100%;
padding: 30rpx 40rpx;
diff --git a/pages/release/perfectPersonInfo/index.js b/pages/release/perfectPersonInfo/index.js
index cbaf6ae..01238e5 100644
--- a/pages/release/perfectPersonInfo/index.js
+++ b/pages/release/perfectPersonInfo/index.js
@@ -106,7 +106,7 @@ Page({
let idx = Number(e.detail.value)
this.setData({
resourcesIdx: idx,
- ['form.resourceCagetoryId']: this.data.resourcesList[idx].id
+ ['form.industryId']: this.data.resourcesList[idx].id
})
},
upImgs(){
@@ -128,6 +128,7 @@ Page({
const params = e.detail.value
params.enterpriseType = 2
params.imgPaths = that.data.form.imgPaths
+ params.industryId = that.data.form.industryId
if (!that.WxValidate.checkForm(params)) {
const error = that.WxValidate.errorList[0]
that.showModal(error)
diff --git a/pages/user/resourcesOrder/index.js b/pages/user/resourcesOrder/index.js
index 4585e75..ff638d4 100644
--- a/pages/user/resourcesOrder/index.js
+++ b/pages/user/resourcesOrder/index.js
@@ -101,7 +101,7 @@ Page({
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
- this.getCommunicates()
+
},
// 拨打电话
call(e){
@@ -143,7 +143,7 @@ Page({
* 生命周期函数--监听页面显示
*/
onShow: function () {
-
+ this.getCommunicates()
},
/**
diff --git a/utils/subutil.wxs b/utils/subutil.wxs
new file mode 100644
index 0000000..d2ea43b
--- /dev/null
+++ b/utils/subutil.wxs
@@ -0,0 +1,31 @@
+var sub = function(val) {
+ if (val.length == 0 || val == undefined) {
+ return;
+ }
+ if (val.length > 17) {
+ return val.substring(0, 17) + "...";
+ } else {
+ return val.substring(0, 1);
+ }
+}
+var filters = {
+ toFloat: function (value) {
+ return parseFloat(value)
+ },
+ toStr: function (value) {
+ return value.toString()
+ },
+ toNum: function (value) {
+ return value.toNumber()
+ },
+}
+var spl = function(str){
+ return str.split(",");
+}
+module.exports = {
+ toFloat: filters.toFloat,
+ toStr: filters.toStr,
+ toNum: filters.toNum,//暴露接口调用
+ sub: sub,
+ spl: spl
+};
\ No newline at end of file
diff --git a/utils/util.js b/utils/util.js
index 11c9e5f..a6c9d61 100644
--- a/utils/util.js
+++ b/utils/util.js
@@ -113,8 +113,29 @@ function chooseImages2(callback) {
})
}
+const getWeek = (date)=>{
+ let timeDate = new Date(date.replace(/-/g, "/")); //兼容IOS
+ let month = timeDate.getMonth()+1,
+ day = timeDate.getDay();
+ return addZero(month)+'.'+ addZero(day) + ' '+'周' + '日一二三四五六'.charAt(day)
+}
+const addZero = function(num){
+ num = num.toString();
+ return num[1] ? num : '0' + num
+}
+
+const setTime = (val)=>{
+ let date = val.split(' ')[0];
+ let times = val.split(' ')[1];
+ let day = date.split('-')[1] +'.'+ date.split('-')[2];
+ let time = times.split(':')[0] +':'+ times.split(':')[1];
+ return day + ' ' + time
+}
+
module.exports = {
formatTime,
chooseImages,
- chooseImages2
+ chooseImages2,
+ getWeek,
+ setTime
}
diff --git a/wxParse/html2json.js b/wxParse/html2json.js
new file mode 100644
index 0000000..6909559
--- /dev/null
+++ b/wxParse/html2json.js
@@ -0,0 +1,303 @@
+/**
+ * html2Json 改造来自: https://github.com/Jxck/html2json
+ *
+ *
+ * author: Di (微信小程序开发工程师)
+ * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
+ * 垂直微信小程序开发交流社区
+ *
+ * github地址: https://github.com/icindy/wxParse
+ *
+ * for: 微信小程序富文本解析
+ * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
+ */
+
+var __placeImgeUrlHttps = "https";
+var __emojisReg = '';
+var __emojisBaseSrc = '';
+var __emojis = {};
+var wxDiscode = require('./wxDiscode.js');
+var HTMLParser = require('./htmlparser.js');
+// Empty Elements - HTML 5
+var empty = makeMap("area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr");
+// Block Elements - HTML 5
+var 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");
+
+// Inline Elements - HTML 5
+var 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");
+
+// Elements that you can, intentionally, leave open
+// (and which close themselves)
+var closeSelf = makeMap("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr");
+
+// Attributes that have their values filled in disabled="disabled"
+var fillAttrs = makeMap("checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected");
+
+// Special Elements (can contain anything)
+var special = makeMap("wxxxcode-style,script,style,view,scroll-view,block");
+function makeMap(str) {
+ var obj = {}, items = str.split(",");
+ for (var i = 0; i < items.length; i++)
+ obj[items[i]] = true;
+ return obj;
+}
+
+function q(v) {
+ return '"' + v + '"';
+}
+
+function removeDOCTYPE(html) {
+ return html
+ .replace(/<\?xml.*\?>\n/, '')
+ .replace(/<.*!doctype.*\>\n/, '')
+ .replace(/<.*!DOCTYPE.*\>\n/, '');
+}
+
+function trimHtml(html) {
+ return html
+ .replace(/\r?\n+/g, '')
+ .replace(//ig, '')
+ .replace(/\/\*.*?\*\//ig, '')
+ .replace(/[ ]+
+ // add to parents
+ var parent = bufArray[0] || results;
+ if (parent.nodes === undefined) {
+ parent.nodes = [];
+ }
+ parent.nodes.push(node);
+ } else {
+ bufArray.unshift(node);
+ }
+ },
+ end: function (tag) {
+ //debug(tag);
+ // merge into parent tag
+ var node = bufArray.shift();
+ if (node.tag !== tag) console.error('invalid state: mismatch end tag');
+
+ //当有缓存source资源时于于video补上src资源
+ if(node.tag === 'video' && results.source){
+ node.attr.src = results.source;
+ delete results.source;
+ }
+
+ if (bufArray.length === 0) {
+ results.nodes.push(node);
+ } else {
+ var parent = bufArray[0];
+ if (parent.nodes === undefined) {
+ parent.nodes = [];
+ }
+ parent.nodes.push(node);
+ }
+ },
+ chars: function (text) {
+ //debug(text);
+ var node = {
+ node: 'text',
+ text: text,
+ textArray:transEmojiStr(text)
+ };
+
+ if (bufArray.length === 0) {
+ node.index = index.toString()
+ index += 1
+ results.nodes.push(node);
+ } else {
+ var parent = bufArray[0];
+ if (parent.nodes === undefined) {
+ parent.nodes = [];
+ }
+ node.index = parent.index + '.' + parent.nodes.length
+ parent.nodes.push(node);
+ }
+ },
+ comment: function (text) {
+ //debug(text);
+ // var node = {
+ // node: 'comment',
+ // text: text,
+ // };
+ // var parent = bufArray[0];
+ // if (parent.nodes === undefined) {
+ // parent.nodes = [];
+ // }
+ // parent.nodes.push(node);
+ },
+ });
+ return results;
+};
+
+function transEmojiStr(str){
+ // var eReg = new RegExp("["+__reg+' '+"]");
+// str = str.replace(/\[([^\[\]]+)\]/g,':$1:')
+
+ var emojiObjs = [];
+ //如果正则表达式为空
+ if(__emojisReg.length == 0 || !__emojis){
+ var emojiObj = {}
+ emojiObj.node = "text";
+ emojiObj.text = str;
+ array = [emojiObj];
+ return array;
+ }
+ //这个地方需要调整
+ str = str.replace(/\[([^\[\]]+)\]/g,':$1:')
+ var eReg = new RegExp("[:]");
+ var array = str.split(eReg);
+ for(var i = 0; i < array.length; i++){
+ var ele = array[i];
+ var emojiObj = {};
+ if(__emojis[ele]){
+ emojiObj.node = "element";
+ emojiObj.tag = "emoji";
+ emojiObj.text = __emojis[ele];
+ emojiObj.baseSrc= __emojisBaseSrc;
+ }else{
+ emojiObj.node = "text";
+ emojiObj.text = ele;
+ }
+ emojiObjs.push(emojiObj);
+ }
+
+ return emojiObjs;
+}
+
+function emojisInit(reg='',baseSrc="/wxParse/emojis/",emojis){
+ __emojisReg = reg;
+ __emojisBaseSrc=baseSrc;
+ __emojis=emojis;
+}
+
+module.exports = {
+ html2json: html2json,
+ emojisInit:emojisInit
+};
+
diff --git a/wxParse/htmlparser.js b/wxParse/htmlparser.js
new file mode 100644
index 0000000..811ddac
--- /dev/null
+++ b/wxParse/htmlparser.js
@@ -0,0 +1,192 @@
+/**
+ *
+ * htmlParser改造自: https://github.com/blowsie/Pure-JavaScript-HTML5-Parser
+ *
+ * author: Di (微信小程序开发工程师)
+ * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
+ * 垂直微信小程序开发交流社区
+ *
+ * github地址: https://github.com/icindy/wxParse
+ *
+ * for: 微信小程序富文本解析
+ * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
+ */
+// Regular Expressions for parsing tags and attributes
+var startTag = /^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/,
+ endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/,
+ attr = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g;
+
+// Empty Elements - HTML 5
+var empty = makeMap("area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr");
+
+// Block Elements - HTML 5
+var 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");
+
+// Inline Elements - HTML 5
+var 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");
+
+// Elements that you can, intentionally, leave open
+// (and which close themselves)
+var closeSelf = makeMap("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr");
+
+// Attributes that have their values filled in disabled="disabled"
+var fillAttrs = makeMap("checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected");
+
+// Special Elements (can contain anything)
+var special = makeMap("wxxxcode-style,script,style,view,scroll-view,block");
+
+function HTMLParser(html, handler) {
+ var index, chars, match, stack = [], last = html;
+ stack.last = function () {
+ return this[this.length - 1];
+ };
+
+ while (html) {
+ chars = true;
+
+ // Make sure we're not in a script or style element
+ if (!stack.last() || !special[stack.last()]) {
+
+ // Comment
+ if (html.indexOf("");
+
+ if (index >= 0) {
+ if (handler.comment)
+ handler.comment(html.substring(4, index));
+ html = html.substring(index + 3);
+ chars = false;
+ }
+
+ // end tag
+ } else if (html.indexOf("") == 0) {
+ match = html.match(endTag);
+
+ if (match) {
+ html = html.substring(match[0].length);
+ match[0].replace(endTag, parseEndTag);
+ chars = false;
+ }
+
+ // start tag
+ } else if (html.indexOf("<") == 0) {
+ match = html.match(startTag);
+
+ if (match) {
+ html = html.substring(match[0].length);
+ match[0].replace(startTag, parseStartTag);
+ chars = false;
+ }
+ }
+
+ if (chars) {
+ index = html.indexOf("<");
+ var text = ''
+ while (index === 0) {
+ text += "<";
+ html = html.substring(1);
+ index = html.indexOf("<");
+ }
+ text += index < 0 ? html : html.substring(0, index);
+ html = index < 0 ? "" : html.substring(index);
+
+ if (handler.chars)
+ handler.chars(text);
+ }
+
+ } else {
+
+ html = html.replace(new RegExp("([\\s\\S]*?)<\/" + stack.last() + "[^>]*>"), function (all, text) {
+ text = text.replace(/|/g, "$1$2");
+ if (handler.chars)
+ handler.chars(text);
+
+ return "";
+ });
+
+
+ parseEndTag("", stack.last());
+ }
+
+ if (html == last)
+ throw "Parse Error: " + html;
+ last = html;
+ }
+
+ // Clean up any remaining tags
+ parseEndTag();
+
+ function parseStartTag(tag, tagName, rest, unary) {
+ tagName = tagName.toLowerCase();
+
+ if (block[tagName]) {
+ while (stack.last() && inline[stack.last()]) {
+ parseEndTag("", stack.last());
+ }
+ }
+
+ if (closeSelf[tagName] && stack.last() == tagName) {
+ parseEndTag("", tagName);
+ }
+
+ unary = empty[tagName] || !!unary;
+
+ if (!unary)
+ stack.push(tagName);
+
+ if (handler.start) {
+ var attrs = [];
+
+ rest.replace(attr, function (match, name) {
+ var value = arguments[2] ? arguments[2] :
+ arguments[3] ? arguments[3] :
+ arguments[4] ? arguments[4] :
+ fillAttrs[name] ? name : "";
+
+ attrs.push({
+ name: name,
+ value: value,
+ escaped: value.replace(/(^|[^\\])"/g, '$1\\\"') //"
+ });
+ });
+
+ if (handler.start) {
+ handler.start(tagName, attrs, unary);
+ }
+
+ }
+ }
+
+ function parseEndTag(tag, tagName) {
+ // If no tag name is provided, clean shop
+ if (!tagName)
+ var pos = 0;
+
+ // Find the closest opened tag of the same type
+ else {
+ tagName = tagName.toLowerCase();
+ for (var pos = stack.length - 1; pos >= 0; pos--)
+ if (stack[pos] == tagName)
+ break;
+ }
+ if (pos >= 0) {
+ // Close all the open elements, up the stack
+ for (var i = stack.length - 1; i >= pos; i--)
+ if (handler.end)
+ handler.end(stack[i]);
+
+ // Remove the open elements from the stack
+ stack.length = pos;
+ }
+ }
+};
+
+
+function makeMap(str) {
+ var obj = {}, items = str.split(",");
+ for (var i = 0; i < items.length; i++)
+ obj[items[i]] = true;
+ return obj;
+}
+
+module.exports = HTMLParser;
diff --git a/wxParse/showdown.js b/wxParse/showdown.js
new file mode 100644
index 0000000..d29206d
--- /dev/null
+++ b/wxParse/showdown.js
@@ -0,0 +1,2532 @@
+/**
+ *
+ * showdown: https://github.com/showdownjs/showdown
+ *
+ * author: Di (微信小程序开发工程师)
+ * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
+ * 垂直微信小程序开发交流社区
+ *
+ * github地址: https://github.com/icindy/wxParse
+ *
+ * for: 微信小程序富文本解析
+ * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
+ */
+
+function getDefaultOpts(simple) {
+ 'use strict';
+
+ var defaultOptions = {
+ omitExtraWLInCodeBlocks: {
+ defaultValue: false,
+ describe: 'Omit the default extra whiteline added to code blocks',
+ type: 'boolean'
+ },
+ noHeaderId: {
+ defaultValue: false,
+ describe: 'Turn on/off generated header id',
+ type: 'boolean'
+ },
+ prefixHeaderId: {
+ defaultValue: false,
+ describe: 'Specify a prefix to generated header ids',
+ type: 'string'
+ },
+ headerLevelStart: {
+ defaultValue: false,
+ describe: 'The header blocks level start',
+ type: 'integer'
+ },
+ parseImgDimensions: {
+ defaultValue: false,
+ describe: 'Turn on/off image dimension parsing',
+ type: 'boolean'
+ },
+ simplifiedAutoLink: {
+ defaultValue: false,
+ describe: 'Turn on/off GFM autolink style',
+ type: 'boolean'
+ },
+ literalMidWordUnderscores: {
+ defaultValue: false,
+ describe: 'Parse midword underscores as literal underscores',
+ type: 'boolean'
+ },
+ strikethrough: {
+ defaultValue: false,
+ describe: 'Turn on/off strikethrough support',
+ type: 'boolean'
+ },
+ tables: {
+ defaultValue: false,
+ describe: 'Turn on/off tables support',
+ type: 'boolean'
+ },
+ tablesHeaderId: {
+ defaultValue: false,
+ describe: 'Add an id to table headers',
+ type: 'boolean'
+ },
+ ghCodeBlocks: {
+ defaultValue: true,
+ describe: 'Turn on/off GFM fenced code blocks support',
+ type: 'boolean'
+ },
+ tasklists: {
+ defaultValue: false,
+ describe: 'Turn on/off GFM tasklist support',
+ type: 'boolean'
+ },
+ smoothLivePreview: {
+ defaultValue: false,
+ describe: 'Prevents weird effects in live previews due to incomplete input',
+ type: 'boolean'
+ },
+ smartIndentationFix: {
+ defaultValue: false,
+ description: 'Tries to smartly fix identation in es6 strings',
+ type: 'boolean'
+ }
+ };
+ if (simple === false) {
+ return JSON.parse(JSON.stringify(defaultOptions));
+ }
+ var ret = {};
+ for (var opt in defaultOptions) {
+ if (defaultOptions.hasOwnProperty(opt)) {
+ ret[opt] = defaultOptions[opt].defaultValue;
+ }
+ }
+ return ret;
+}
+
+/**
+ * Created by Tivie on 06-01-2015.
+ */
+
+// Private properties
+var showdown = {},
+ parsers = {},
+ extensions = {},
+ globalOptions = getDefaultOpts(true),
+ flavor = {
+ github: {
+ omitExtraWLInCodeBlocks: true,
+ prefixHeaderId: 'user-content-',
+ simplifiedAutoLink: true,
+ literalMidWordUnderscores: true,
+ strikethrough: true,
+ tables: true,
+ tablesHeaderId: true,
+ ghCodeBlocks: true,
+ tasklists: true
+ },
+ vanilla: getDefaultOpts(true)
+ };
+
+/**
+ * helper namespace
+ * @type {{}}
+ */
+showdown.helper = {};
+
+/**
+ * TODO LEGACY SUPPORT CODE
+ * @type {{}}
+ */
+showdown.extensions = {};
+
+/**
+ * Set a global option
+ * @static
+ * @param {string} key
+ * @param {*} value
+ * @returns {showdown}
+ */
+showdown.setOption = function (key, value) {
+ 'use strict';
+ globalOptions[key] = value;
+ return this;
+};
+
+/**
+ * Get a global option
+ * @static
+ * @param {string} key
+ * @returns {*}
+ */
+showdown.getOption = function (key) {
+ 'use strict';
+ return globalOptions[key];
+};
+
+/**
+ * Get the global options
+ * @static
+ * @returns {{}}
+ */
+showdown.getOptions = function () {
+ 'use strict';
+ return globalOptions;
+};
+
+/**
+ * Reset global options to the default values
+ * @static
+ */
+showdown.resetOptions = function () {
+ 'use strict';
+ globalOptions = getDefaultOpts(true);
+};
+
+/**
+ * Set the flavor showdown should use as default
+ * @param {string} name
+ */
+showdown.setFlavor = function (name) {
+ 'use strict';
+ if (flavor.hasOwnProperty(name)) {
+ var preset = flavor[name];
+ for (var option in preset) {
+ if (preset.hasOwnProperty(option)) {
+ globalOptions[option] = preset[option];
+ }
+ }
+ }
+};
+
+/**
+ * Get the default options
+ * @static
+ * @param {boolean} [simple=true]
+ * @returns {{}}
+ */
+showdown.getDefaultOptions = function (simple) {
+ 'use strict';
+ return getDefaultOpts(simple);
+};
+
+/**
+ * Get or set a subParser
+ *
+ * subParser(name) - Get a registered subParser
+ * subParser(name, func) - Register a subParser
+ * @static
+ * @param {string} name
+ * @param {function} [func]
+ * @returns {*}
+ */
+showdown.subParser = function (name, func) {
+ 'use strict';
+ if (showdown.helper.isString(name)) {
+ if (typeof func !== 'undefined') {
+ parsers[name] = func;
+ } else {
+ if (parsers.hasOwnProperty(name)) {
+ return parsers[name];
+ } else {
+ throw Error('SubParser named ' + name + ' not registered!');
+ }
+ }
+ }
+};
+
+/**
+ * Gets or registers an extension
+ * @static
+ * @param {string} name
+ * @param {object|function=} ext
+ * @returns {*}
+ */
+showdown.extension = function (name, ext) {
+ 'use strict';
+
+ if (!showdown.helper.isString(name)) {
+ throw Error('Extension \'name\' must be a string');
+ }
+
+ name = showdown.helper.stdExtName(name);
+
+ // Getter
+ if (showdown.helper.isUndefined(ext)) {
+ if (!extensions.hasOwnProperty(name)) {
+ throw Error('Extension named ' + name + ' is not registered!');
+ }
+ return extensions[name];
+
+ // Setter
+ } else {
+ // Expand extension if it's wrapped in a function
+ if (typeof ext === 'function') {
+ ext = ext();
+ }
+
+ // Ensure extension is an array
+ if (!showdown.helper.isArray(ext)) {
+ ext = [ext];
+ }
+
+ var validExtension = validate(ext, name);
+
+ if (validExtension.valid) {
+ extensions[name] = ext;
+ } else {
+ throw Error(validExtension.error);
+ }
+ }
+};
+
+/**
+ * Gets all extensions registered
+ * @returns {{}}
+ */
+showdown.getAllExtensions = function () {
+ 'use strict';
+ return extensions;
+};
+
+/**
+ * Remove an extension
+ * @param {string} name
+ */
+showdown.removeExtension = function (name) {
+ 'use strict';
+ delete extensions[name];
+};
+
+/**
+ * Removes all extensions
+ */
+showdown.resetExtensions = function () {
+ 'use strict';
+ extensions = {};
+};
+
+/**
+ * Validate extension
+ * @param {array} extension
+ * @param {string} name
+ * @returns {{valid: boolean, error: string}}
+ */
+function validate(extension, name) {
+ 'use strict';
+
+ var errMsg = (name) ? 'Error in ' + name + ' extension->' : 'Error in unnamed extension',
+ ret = {
+ valid: true,
+ error: ''
+ };
+
+ if (!showdown.helper.isArray(extension)) {
+ extension = [extension];
+ }
+
+ for (var i = 0; i < extension.length; ++i) {
+ var baseMsg = errMsg + ' sub-extension ' + i + ': ',
+ ext = extension[i];
+ if (typeof ext !== 'object') {
+ ret.valid = false;
+ ret.error = baseMsg + 'must be an object, but ' + typeof ext + ' given';
+ return ret;
+ }
+
+ if (!showdown.helper.isString(ext.type)) {
+ ret.valid = false;
+ ret.error = baseMsg + 'property "type" must be a string, but ' + typeof ext.type + ' given';
+ return ret;
+ }
+
+ var type = ext.type = ext.type.toLowerCase();
+
+ // normalize extension type
+ if (type === 'language') {
+ type = ext.type = 'lang';
+ }
+
+ if (type === 'html') {
+ type = ext.type = 'output';
+ }
+
+ if (type !== 'lang' && type !== 'output' && type !== 'listener') {
+ ret.valid = false;
+ ret.error = baseMsg + 'type ' + type + ' is not recognized. Valid values: "lang/language", "output/html" or "listener"';
+ return ret;
+ }
+
+ if (type === 'listener') {
+ if (showdown.helper.isUndefined(ext.listeners)) {
+ ret.valid = false;
+ ret.error = baseMsg + '. Extensions of type "listener" must have a property called "listeners"';
+ return ret;
+ }
+ } else {
+ if (showdown.helper.isUndefined(ext.filter) && showdown.helper.isUndefined(ext.regex)) {
+ ret.valid = false;
+ ret.error = baseMsg + type + ' extensions must define either a "regex" property or a "filter" method';
+ return ret;
+ }
+ }
+
+ if (ext.listeners) {
+ if (typeof ext.listeners !== 'object') {
+ ret.valid = false;
+ ret.error = baseMsg + '"listeners" property must be an object but ' + typeof ext.listeners + ' given';
+ return ret;
+ }
+ for (var ln in ext.listeners) {
+ if (ext.listeners.hasOwnProperty(ln)) {
+ if (typeof ext.listeners[ln] !== 'function') {
+ ret.valid = false;
+ ret.error = baseMsg + '"listeners" property must be an hash of [event name]: [callback]. listeners.' + ln +
+ ' must be a function but ' + typeof ext.listeners[ln] + ' given';
+ return ret;
+ }
+ }
+ }
+ }
+
+ if (ext.filter) {
+ if (typeof ext.filter !== 'function') {
+ ret.valid = false;
+ ret.error = baseMsg + '"filter" must be a function, but ' + typeof ext.filter + ' given';
+ return ret;
+ }
+ } else if (ext.regex) {
+ if (showdown.helper.isString(ext.regex)) {
+ ext.regex = new RegExp(ext.regex, 'g');
+ }
+ if (!ext.regex instanceof RegExp) {
+ ret.valid = false;
+ ret.error = baseMsg + '"regex" property must either be a string or a RegExp object, but ' + typeof ext.regex + ' given';
+ return ret;
+ }
+ if (showdown.helper.isUndefined(ext.replace)) {
+ ret.valid = false;
+ ret.error = baseMsg + '"regex" extensions must implement a replace string or function';
+ return ret;
+ }
+ }
+ }
+ return ret;
+}
+
+/**
+ * Validate extension
+ * @param {object} ext
+ * @returns {boolean}
+ */
+showdown.validateExtension = function (ext) {
+ 'use strict';
+
+ var validateExtension = validate(ext, null);
+ if (!validateExtension.valid) {
+ console.warn(validateExtension.error);
+ return false;
+ }
+ return true;
+};
+
+/**
+ * showdownjs helper functions
+ */
+
+if (!showdown.hasOwnProperty('helper')) {
+ showdown.helper = {};
+}
+
+/**
+ * Check if var is string
+ * @static
+ * @param {string} a
+ * @returns {boolean}
+ */
+showdown.helper.isString = function isString(a) {
+ 'use strict';
+ return (typeof a === 'string' || a instanceof String);
+};
+
+/**
+ * Check if var is a function
+ * @static
+ * @param {string} a
+ * @returns {boolean}
+ */
+showdown.helper.isFunction = function isFunction(a) {
+ 'use strict';
+ var getType = {};
+ return a && getType.toString.call(a) === '[object Function]';
+};
+
+/**
+ * ForEach helper function
+ * @static
+ * @param {*} obj
+ * @param {function} callback
+ */
+showdown.helper.forEach = function forEach(obj, callback) {
+ 'use strict';
+ if (typeof obj.forEach === 'function') {
+ obj.forEach(callback);
+ } else {
+ for (var i = 0; i < obj.length; i++) {
+ callback(obj[i], i, obj);
+ }
+ }
+};
+
+/**
+ * isArray helper function
+ * @static
+ * @param {*} a
+ * @returns {boolean}
+ */
+showdown.helper.isArray = function isArray(a) {
+ 'use strict';
+ return a.constructor === Array;
+};
+
+/**
+ * Check if value is undefined
+ * @static
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.
+ */
+showdown.helper.isUndefined = function isUndefined(value) {
+ 'use strict';
+ return typeof value === 'undefined';
+};
+
+/**
+ * Standardidize extension name
+ * @static
+ * @param {string} s extension name
+ * @returns {string}
+ */
+showdown.helper.stdExtName = function (s) {
+ 'use strict';
+ return s.replace(/[_-]||\s/g, '').toLowerCase();
+};
+
+function escapeCharactersCallback(wholeMatch, m1) {
+ 'use strict';
+ var charCodeToEscape = m1.charCodeAt(0);
+ return '~E' + charCodeToEscape + 'E';
+}
+
+/**
+ * Callback used to escape characters when passing through String.replace
+ * @static
+ * @param {string} wholeMatch
+ * @param {string} m1
+ * @returns {string}
+ */
+showdown.helper.escapeCharactersCallback = escapeCharactersCallback;
+
+/**
+ * Escape characters in a string
+ * @static
+ * @param {string} text
+ * @param {string} charsToEscape
+ * @param {boolean} afterBackslash
+ * @returns {XML|string|void|*}
+ */
+showdown.helper.escapeCharacters = function escapeCharacters(text, charsToEscape, afterBackslash) {
+ 'use strict';
+ // First we have to escape the escape characters so that
+ // we can build a character class out of them
+ var regexString = '([' + charsToEscape.replace(/([\[\]\\])/g, '\\$1') + '])';
+
+ if (afterBackslash) {
+ regexString = '\\\\' + regexString;
+ }
+
+ var regex = new RegExp(regexString, 'g');
+ text = text.replace(regex, escapeCharactersCallback);
+
+ return text;
+};
+
+var rgxFindMatchPos = function (str, left, right, flags) {
+ 'use strict';
+ var f = flags || '',
+ g = f.indexOf('g') > -1,
+ x = new RegExp(left + '|' + right, 'g' + f.replace(/g/g, '')),
+ l = new RegExp(left, f.replace(/g/g, '')),
+ pos = [],
+ t, s, m, start, end;
+
+ do {
+ t = 0;
+ while ((m = x.exec(str))) {
+ if (l.test(m[0])) {
+ if (!(t++)) {
+ s = x.lastIndex;
+ start = s - m[0].length;
+ }
+ } else if (t) {
+ if (!--t) {
+ end = m.index + m[0].length;
+ var obj = {
+ left: {start: start, end: s},
+ match: {start: s, end: m.index},
+ right: {start: m.index, end: end},
+ wholeMatch: {start: start, end: end}
+ };
+ pos.push(obj);
+ if (!g) {
+ return pos;
+ }
+ }
+ }
+ }
+ } while (t && (x.lastIndex = s));
+
+ return pos;
+};
+
+/**
+ * matchRecursiveRegExp
+ *
+ * (c) 2007 Steven Levithan
+ * MIT License
+ *
+ * Accepts a string to search, a left and right format delimiter
+ * as regex patterns, and optional regex flags. Returns an array
+ * of matches, allowing nested instances of left/right delimiters.
+ * Use the "g" flag to return all matches, otherwise only the
+ * first is returned. Be careful to ensure that the left and
+ * right format delimiters produce mutually exclusive matches.
+ * Backreferences are not supported within the right delimiter
+ * due to how it is internally combined with the left delimiter.
+ * When matching strings whose format delimiters are unbalanced
+ * to the left or right, the output is intentionally as a
+ * conventional regex library with recursion support would
+ * produce, e.g. "<" and ">" both produce ["x"] when using
+ * "<" and ">" as the delimiters (both strings contain a single,
+ * balanced instance of "").
+ *
+ * examples:
+ * matchRecursiveRegExp("test", "\\(", "\\)")
+ * returns: []
+ * matchRecursiveRegExp(">>t<>", "<", ">", "g")
+ * returns: ["t<>", ""]
+ * matchRecursiveRegExp(" test
", "]*>", "
", "gi")
+ * returns: ["test"]
+ */
+showdown.helper.matchRecursiveRegExp = function (str, left, right, flags) {
+ 'use strict';
+
+ var matchPos = rgxFindMatchPos (str, left, right, flags),
+ results = [];
+
+ for (var i = 0; i < matchPos.length; ++i) {
+ results.push([
+ str.slice(matchPos[i].wholeMatch.start, matchPos[i].wholeMatch.end),
+ str.slice(matchPos[i].match.start, matchPos[i].match.end),
+ str.slice(matchPos[i].left.start, matchPos[i].left.end),
+ str.slice(matchPos[i].right.start, matchPos[i].right.end)
+ ]);
+ }
+ return results;
+};
+
+/**
+ *
+ * @param {string} str
+ * @param {string|function} replacement
+ * @param {string} left
+ * @param {string} right
+ * @param {string} flags
+ * @returns {string}
+ */
+showdown.helper.replaceRecursiveRegExp = function (str, replacement, left, right, flags) {
+ 'use strict';
+
+ if (!showdown.helper.isFunction(replacement)) {
+ var repStr = replacement;
+ replacement = function () {
+ return repStr;
+ };
+ }
+
+ var matchPos = rgxFindMatchPos(str, left, right, flags),
+ finalStr = str,
+ lng = matchPos.length;
+
+ if (lng > 0) {
+ var bits = [];
+ if (matchPos[0].wholeMatch.start !== 0) {
+ bits.push(str.slice(0, matchPos[0].wholeMatch.start));
+ }
+ for (var i = 0; i < lng; ++i) {
+ bits.push(
+ replacement(
+ str.slice(matchPos[i].wholeMatch.start, matchPos[i].wholeMatch.end),
+ str.slice(matchPos[i].match.start, matchPos[i].match.end),
+ str.slice(matchPos[i].left.start, matchPos[i].left.end),
+ str.slice(matchPos[i].right.start, matchPos[i].right.end)
+ )
+ );
+ if (i < lng - 1) {
+ bits.push(str.slice(matchPos[i].wholeMatch.end, matchPos[i + 1].wholeMatch.start));
+ }
+ }
+ if (matchPos[lng - 1].wholeMatch.end < str.length) {
+ bits.push(str.slice(matchPos[lng - 1].wholeMatch.end));
+ }
+ finalStr = bits.join('');
+ }
+ return finalStr;
+};
+
+/**
+ * POLYFILLS
+ */
+if (showdown.helper.isUndefined(console)) {
+ console = {
+ warn: function (msg) {
+ 'use strict';
+ alert(msg);
+ },
+ log: function (msg) {
+ 'use strict';
+ alert(msg);
+ },
+ error: function (msg) {
+ 'use strict';
+ throw msg;
+ }
+ };
+}
+
+/**
+ * Created by Estevao on 31-05-2015.
+ */
+
+/**
+ * Showdown Converter class
+ * @class
+ * @param {object} [converterOptions]
+ * @returns {Converter}
+ */
+showdown.Converter = function (converterOptions) {
+ 'use strict';
+
+ var
+ /**
+ * Options used by this converter
+ * @private
+ * @type {{}}
+ */
+ options = {},
+
+ /**
+ * Language extensions used by this converter
+ * @private
+ * @type {Array}
+ */
+ langExtensions = [],
+
+ /**
+ * Output modifiers extensions used by this converter
+ * @private
+ * @type {Array}
+ */
+ outputModifiers = [],
+
+ /**
+ * Event listeners
+ * @private
+ * @type {{}}
+ */
+ listeners = {};
+
+ _constructor();
+
+ /**
+ * Converter constructor
+ * @private
+ */
+ function _constructor() {
+ converterOptions = converterOptions || {};
+
+ for (var gOpt in globalOptions) {
+ if (globalOptions.hasOwnProperty(gOpt)) {
+ options[gOpt] = globalOptions[gOpt];
+ }
+ }
+
+ // Merge options
+ if (typeof converterOptions === 'object') {
+ for (var opt in converterOptions) {
+ if (converterOptions.hasOwnProperty(opt)) {
+ options[opt] = converterOptions[opt];
+ }
+ }
+ } else {
+ throw Error('Converter expects the passed parameter to be an object, but ' + typeof converterOptions +
+ ' was passed instead.');
+ }
+
+ if (options.extensions) {
+ showdown.helper.forEach(options.extensions, _parseExtension);
+ }
+ }
+
+ /**
+ * Parse extension
+ * @param {*} ext
+ * @param {string} [name='']
+ * @private
+ */
+ function _parseExtension(ext, name) {
+
+ name = name || null;
+ // If it's a string, the extension was previously loaded
+ if (showdown.helper.isString(ext)) {
+ ext = showdown.helper.stdExtName(ext);
+ name = ext;
+
+ // LEGACY_SUPPORT CODE
+ if (showdown.extensions[ext]) {
+ console.warn('DEPRECATION WARNING: ' + ext + ' is an old extension that uses a deprecated loading method.' +
+ 'Please inform the developer that the extension should be updated!');
+ legacyExtensionLoading(showdown.extensions[ext], ext);
+ return;
+ // END LEGACY SUPPORT CODE
+
+ } else if (!showdown.helper.isUndefined(extensions[ext])) {
+ ext = extensions[ext];
+
+ } else {
+ throw Error('Extension "' + ext + '" could not be loaded. It was either not found or is not a valid extension.');
+ }
+ }
+
+ if (typeof ext === 'function') {
+ ext = ext();
+ }
+
+ if (!showdown.helper.isArray(ext)) {
+ ext = [ext];
+ }
+
+ var validExt = validate(ext, name);
+ if (!validExt.valid) {
+ throw Error(validExt.error);
+ }
+
+ for (var i = 0; i < ext.length; ++i) {
+ switch (ext[i].type) {
+
+ case 'lang':
+ langExtensions.push(ext[i]);
+ break;
+
+ case 'output':
+ outputModifiers.push(ext[i]);
+ break;
+ }
+ if (ext[i].hasOwnProperty(listeners)) {
+ for (var ln in ext[i].listeners) {
+ if (ext[i].listeners.hasOwnProperty(ln)) {
+ listen(ln, ext[i].listeners[ln]);
+ }
+ }
+ }
+ }
+
+ }
+
+ /**
+ * LEGACY_SUPPORT
+ * @param {*} ext
+ * @param {string} name
+ */
+ function legacyExtensionLoading(ext, name) {
+ if (typeof ext === 'function') {
+ ext = ext(new showdown.Converter());
+ }
+ if (!showdown.helper.isArray(ext)) {
+ ext = [ext];
+ }
+ var valid = validate(ext, name);
+
+ if (!valid.valid) {
+ throw Error(valid.error);
+ }
+
+ for (var i = 0; i < ext.length; ++i) {
+ switch (ext[i].type) {
+ case 'lang':
+ langExtensions.push(ext[i]);
+ break;
+ case 'output':
+ outputModifiers.push(ext[i]);
+ break;
+ default:// should never reach here
+ throw Error('Extension loader error: Type unrecognized!!!');
+ }
+ }
+ }
+
+ /**
+ * Listen to an event
+ * @param {string} name
+ * @param {function} callback
+ */
+ function listen(name, callback) {
+ if (!showdown.helper.isString(name)) {
+ throw Error('Invalid argument in converter.listen() method: name must be a string, but ' + typeof name + ' given');
+ }
+
+ if (typeof callback !== 'function') {
+ throw Error('Invalid argument in converter.listen() method: callback must be a function, but ' + typeof callback + ' given');
+ }
+
+ if (!listeners.hasOwnProperty(name)) {
+ listeners[name] = [];
+ }
+ listeners[name].push(callback);
+ }
+
+ function rTrimInputText(text) {
+ var rsp = text.match(/^\s*/)[0].length,
+ rgx = new RegExp('^\\s{0,' + rsp + '}', 'gm');
+ return text.replace(rgx, '');
+ }
+
+ /**
+ * Dispatch an event
+ * @private
+ * @param {string} evtName Event name
+ * @param {string} text Text
+ * @param {{}} options Converter Options
+ * @param {{}} globals
+ * @returns {string}
+ */
+ this._dispatch = function dispatch (evtName, text, options, globals) {
+ if (listeners.hasOwnProperty(evtName)) {
+ for (var ei = 0; ei < listeners[evtName].length; ++ei) {
+ var nText = listeners[evtName][ei](evtName, text, this, options, globals);
+ if (nText && typeof nText !== 'undefined') {
+ text = nText;
+ }
+ }
+ }
+ return text;
+ };
+
+ /**
+ * Listen to an event
+ * @param {string} name
+ * @param {function} callback
+ * @returns {showdown.Converter}
+ */
+ this.listen = function (name, callback) {
+ listen(name, callback);
+ return this;
+ };
+
+ /**
+ * Converts a markdown string into HTML
+ * @param {string} text
+ * @returns {*}
+ */
+ this.makeHtml = function (text) {
+ //check if text is not falsy
+ if (!text) {
+ return text;
+ }
+
+ var globals = {
+ gHtmlBlocks: [],
+ gHtmlMdBlocks: [],
+ gHtmlSpans: [],
+ gUrls: {},
+ gTitles: {},
+ gDimensions: {},
+ gListLevel: 0,
+ hashLinkCounts: {},
+ langExtensions: langExtensions,
+ outputModifiers: outputModifiers,
+ converter: this,
+ ghCodeBlocks: []
+ };
+
+ // attacklab: Replace ~ with ~T
+ // This lets us use tilde as an escape char to avoid md5 hashes
+ // The choice of character is arbitrary; anything that isn't
+ // magic in Markdown will work.
+ text = text.replace(/~/g, '~T');
+
+ // attacklab: Replace $ with ~D
+ // RegExp interprets $ as a special character
+ // when it's in a replacement string
+ text = text.replace(/\$/g, '~D');
+
+ // Standardize line endings
+ text = text.replace(/\r\n/g, '\n'); // DOS to Unix
+ text = text.replace(/\r/g, '\n'); // Mac to Unix
+
+ if (options.smartIndentationFix) {
+ text = rTrimInputText(text);
+ }
+
+ // Make sure text begins and ends with a couple of newlines:
+ //text = '\n\n' + text + '\n\n';
+ text = text;
+ // detab
+ text = showdown.subParser('detab')(text, options, globals);
+
+ // stripBlankLines
+ text = showdown.subParser('stripBlankLines')(text, options, globals);
+
+ //run languageExtensions
+ showdown.helper.forEach(langExtensions, function (ext) {
+ text = showdown.subParser('runExtension')(ext, text, options, globals);
+ });
+
+ // run the sub parsers
+ text = showdown.subParser('hashPreCodeTags')(text, options, globals);
+ text = showdown.subParser('githubCodeBlocks')(text, options, globals);
+ text = showdown.subParser('hashHTMLBlocks')(text, options, globals);
+ text = showdown.subParser('hashHTMLSpans')(text, options, globals);
+ text = showdown.subParser('stripLinkDefinitions')(text, options, globals);
+ text = showdown.subParser('blockGamut')(text, options, globals);
+ text = showdown.subParser('unhashHTMLSpans')(text, options, globals);
+ text = showdown.subParser('unescapeSpecialChars')(text, options, globals);
+
+ // attacklab: Restore dollar signs
+ text = text.replace(/~D/g, '$$');
+
+ // attacklab: Restore tildes
+ text = text.replace(/~T/g, '~');
+
+ // Run output modifiers
+ showdown.helper.forEach(outputModifiers, function (ext) {
+ text = showdown.subParser('runExtension')(ext, text, options, globals);
+ });
+ return text;
+ };
+
+ /**
+ * Set an option of this Converter instance
+ * @param {string} key
+ * @param {*} value
+ */
+ this.setOption = function (key, value) {
+ options[key] = value;
+ };
+
+ /**
+ * Get the option of this Converter instance
+ * @param {string} key
+ * @returns {*}
+ */
+ this.getOption = function (key) {
+ return options[key];
+ };
+
+ /**
+ * Get the options of this Converter instance
+ * @returns {{}}
+ */
+ this.getOptions = function () {
+ return options;
+ };
+
+ /**
+ * Add extension to THIS converter
+ * @param {{}} extension
+ * @param {string} [name=null]
+ */
+ this.addExtension = function (extension, name) {
+ name = name || null;
+ _parseExtension(extension, name);
+ };
+
+ /**
+ * Use a global registered extension with THIS converter
+ * @param {string} extensionName Name of the previously registered extension
+ */
+ this.useExtension = function (extensionName) {
+ _parseExtension(extensionName);
+ };
+
+ /**
+ * Set the flavor THIS converter should use
+ * @param {string} name
+ */
+ this.setFlavor = function (name) {
+ if (flavor.hasOwnProperty(name)) {
+ var preset = flavor[name];
+ for (var option in preset) {
+ if (preset.hasOwnProperty(option)) {
+ options[option] = preset[option];
+ }
+ }
+ }
+ };
+
+ /**
+ * Remove an extension from THIS converter.
+ * Note: This is a costly operation. It's better to initialize a new converter
+ * and specify the extensions you wish to use
+ * @param {Array} extension
+ */
+ this.removeExtension = function (extension) {
+ if (!showdown.helper.isArray(extension)) {
+ extension = [extension];
+ }
+ for (var a = 0; a < extension.length; ++a) {
+ var ext = extension[a];
+ for (var i = 0; i < langExtensions.length; ++i) {
+ if (langExtensions[i] === ext) {
+ langExtensions[i].splice(i, 1);
+ }
+ }
+ for (var ii = 0; ii < outputModifiers.length; ++i) {
+ if (outputModifiers[ii] === ext) {
+ outputModifiers[ii].splice(i, 1);
+ }
+ }
+ }
+ };
+
+ /**
+ * Get all extension of THIS converter
+ * @returns {{language: Array, output: Array}}
+ */
+ this.getAllExtensions = function () {
+ return {
+ language: langExtensions,
+ output: outputModifiers
+ };
+ };
+};
+
+/**
+ * Turn Markdown link shortcuts into XHTML tags.
+ */
+showdown.subParser('anchors', function (text, options, globals) {
+ 'use strict';
+
+ text = globals.converter._dispatch('anchors.before', text, options, globals);
+
+ var writeAnchorTag = function (wholeMatch, m1, m2, m3, m4, m5, m6, m7) {
+ if (showdown.helper.isUndefined(m7)) {
+ m7 = '';
+ }
+ wholeMatch = m1;
+ var linkText = m2,
+ linkId = m3.toLowerCase(),
+ url = m4,
+ title = m7;
+
+ if (!url) {
+ if (!linkId) {
+ // lower-case and turn embedded newlines into spaces
+ linkId = linkText.toLowerCase().replace(/ ?\n/g, ' ');
+ }
+ url = '#' + linkId;
+
+ if (!showdown.helper.isUndefined(globals.gUrls[linkId])) {
+ url = globals.gUrls[linkId];
+ if (!showdown.helper.isUndefined(globals.gTitles[linkId])) {
+ title = globals.gTitles[linkId];
+ }
+ } else {
+ if (wholeMatch.search(/\(\s*\)$/m) > -1) {
+ // Special case for explicit empty url
+ url = '';
+ } else {
+ return wholeMatch;
+ }
+ }
+ }
+
+ url = showdown.helper.escapeCharacters(url, '*_', false);
+ var result = ' ' + linkText + ' ';
+
+ return result;
+ };
+
+ // First, handle reference-style links: [link text] [id]
+ /*
+ text = text.replace(/
+ ( // wrap whole match in $1
+ \[
+ (
+ (?:
+ \[[^\]]*\] // allow brackets nested one level
+ |
+ [^\[] // or anything else
+ )*
+ )
+ \]
+
+ [ ]? // one optional space
+ (?:\n[ ]*)? // one optional newline followed by spaces
+
+ \[
+ (.*?) // id = $3
+ \]
+ )()()()() // pad remaining backreferences
+ /g,_DoAnchors_callback);
+ */
+ text = text.replace(/(\[((?:\[[^\]]*]|[^\[\]])*)][ ]?(?:\n[ ]*)?\[(.*?)])()()()()/g, writeAnchorTag);
+
+ //
+ // Next, inline-style links: [link text](url "optional title")
+ //
+
+ /*
+ text = text.replace(/
+ ( // wrap whole match in $1
+ \[
+ (
+ (?:
+ \[[^\]]*\] // allow brackets nested one level
+ |
+ [^\[\]] // or anything else
+ )
+ )
+ \]
+ \( // literal paren
+ [ \t]*
+ () // no id, so leave $3 empty
+ (.*?)>? // href = $4
+ [ \t]*
+ ( // $5
+ (['"]) // quote char = $6
+ (.*?) // Title = $7
+ \6 // matching quote
+ [ \t]* // ignore any spaces/tabs between closing quote and )
+ )? // title is optional
+ \)
+ )
+ /g,writeAnchorTag);
+ */
+ text = text.replace(/(\[((?:\[[^\]]*]|[^\[\]])*)]\([ \t]*()(.*?(?:\(.*?\).*?)?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,
+ writeAnchorTag);
+
+ //
+ // Last, handle reference-style shortcuts: [link text]
+ // These must come last in case you've also got [link test][1]
+ // or [link test](/foo)
+ //
+
+ /*
+ text = text.replace(/
+ ( // wrap whole match in $1
+ \[
+ ([^\[\]]+) // link text = $2; can't contain '[' or ']'
+ \]
+ )()()()()() // pad rest of backreferences
+ /g, writeAnchorTag);
+ */
+ text = text.replace(/(\[([^\[\]]+)])()()()()()/g, writeAnchorTag);
+
+ text = globals.converter._dispatch('anchors.after', text, options, globals);
+ return text;
+});
+
+showdown.subParser('autoLinks', function (text, options, globals) {
+ 'use strict';
+
+ text = globals.converter._dispatch('autoLinks.before', text, options, globals);
+
+ var simpleURLRegex = /\b(((https?|ftp|dict):\/\/|www\.)[^'">\s]+\.[^'">\s]+)(?=\s|$)(?!["<>])/gi,
+ delimUrlRegex = /<(((https?|ftp|dict):\/\/|www\.)[^'">\s]+)>/gi,
+ simpleMailRegex = /(?:^|[ \n\t])([A-Za-z0-9!#$%&'*+-/=?^_`\{|}~\.]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)(?:$|[ \n\t])/gi,
+ delimMailRegex = /<(?:mailto:)?([-.\w]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi;
+
+ text = text.replace(delimUrlRegex, replaceLink);
+ text = text.replace(delimMailRegex, replaceMail);
+ // simpleURLRegex = /\b(((https?|ftp|dict):\/\/|www\.)[-.+~:?#@!$&'()*,;=[\]\w]+)\b/gi,
+ // Email addresses:
+
+ if (options.simplifiedAutoLink) {
+ text = text.replace(simpleURLRegex, replaceLink);
+ text = text.replace(simpleMailRegex, replaceMail);
+ }
+
+ function replaceLink(wm, link) {
+ var lnkTxt = link;
+ if (/^www\./i.test(link)) {
+ link = link.replace(/^www\./i, 'http://www.');
+ }
+ return '' + lnkTxt + ' ';
+ }
+
+ function replaceMail(wholeMatch, m1) {
+ var unescapedStr = showdown.subParser('unescapeSpecialChars')(m1);
+ return showdown.subParser('encodeEmailAddress')(unescapedStr);
+ }
+
+ text = globals.converter._dispatch('autoLinks.after', text, options, globals);
+
+ return text;
+});
+
+/**
+ * These are all the transformations that form block-level
+ * tags like paragraphs, headers, and list items.
+ */
+showdown.subParser('blockGamut', function (text, options, globals) {
+ 'use strict';
+
+ text = globals.converter._dispatch('blockGamut.before', text, options, globals);
+
+ // we parse blockquotes first so that we can have headings and hrs
+ // inside blockquotes
+ text = showdown.subParser('blockQuotes')(text, options, globals);
+ text = showdown.subParser('headers')(text, options, globals);
+
+ // Do Horizontal Rules:
+ var key = showdown.subParser('hashBlock')(' ', options, globals);
+ text = text.replace(/^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$/gm, key);
+ text = text.replace(/^[ ]{0,2}([ ]?\-[ ]?){3,}[ \t]*$/gm, key);
+ text = text.replace(/^[ ]{0,2}([ ]?_[ ]?){3,}[ \t]*$/gm, key);
+
+ text = showdown.subParser('lists')(text, options, globals);
+ text = showdown.subParser('codeBlocks')(text, options, globals);
+ text = showdown.subParser('tables')(text, options, globals);
+
+ // We already ran _HashHTMLBlocks() before, in Markdown(), but that
+ // was to escape raw HTML in the original Markdown source. This time,
+ // we're escaping the markup we've just created, so that we don't wrap
+ // tags around block-level tags.
+ text = showdown.subParser('hashHTMLBlocks')(text, options, globals);
+ text = showdown.subParser('paragraphs')(text, options, globals);
+
+ text = globals.converter._dispatch('blockGamut.after', text, options, globals);
+
+ return text;
+});
+
+showdown.subParser('blockQuotes', function (text, options, globals) {
+ 'use strict';
+
+ text = globals.converter._dispatch('blockQuotes.before', text, options, globals);
+ /*
+ text = text.replace(/
+ ( // Wrap whole match in $1
+ (
+ ^[ \t]*>[ \t]? // '>' at the start of a line
+ .+\n // rest of the first line
+ (.+\n)* // subsequent consecutive lines
+ \n* // blanks
+ )+
+ )
+ /gm, function(){...});
+ */
+
+ text = text.replace(/((^[ \t]{0,3}>[ \t]?.+\n(.+\n)*\n*)+)/gm, function (wholeMatch, m1) {
+ var bq = m1;
+
+ // attacklab: hack around Konqueror 3.5.4 bug:
+ // "----------bug".replace(/^-/g,"") == "bug"
+ bq = bq.replace(/^[ \t]*>[ \t]?/gm, '~0'); // trim one level of quoting
+
+ // attacklab: clean up hack
+ bq = bq.replace(/~0/g, '');
+
+ bq = bq.replace(/^[ \t]+$/gm, ''); // trim whitespace-only lines
+ bq = showdown.subParser('githubCodeBlocks')(bq, options, globals);
+ bq = showdown.subParser('blockGamut')(bq, options, globals); // recurse
+
+ bq = bq.replace(/(^|\n)/g, '$1 ');
+ // These leading spaces screw with
content, so we need to fix that:
+ bq = bq.replace(/(\s*[^\r]+?<\/pre>)/gm, function (wholeMatch, m1) {
+ var pre = m1;
+ // attacklab: hack around Konqueror 3.5.4 bug:
+ pre = pre.replace(/^ /mg, '~0');
+ pre = pre.replace(/~0/g, '');
+ return pre;
+ });
+
+ return showdown.subParser('hashBlock')('\n' + bq + '\n ', options, globals);
+ });
+
+ text = globals.converter._dispatch('blockQuotes.after', text, options, globals);
+ return text;
+});
+
+/**
+ * Process Markdown `` blocks.
+ */
+showdown.subParser('codeBlocks', function (text, options, globals) {
+ 'use strict';
+
+ text = globals.converter._dispatch('codeBlocks.before', text, options, globals);
+ /*
+ text = text.replace(text,
+ /(?:\n\n|^)
+ ( // $1 = the code block -- one or more lines, starting with a space/tab
+ (?:
+ (?:[ ]{4}|\t) // Lines must start with a tab or a tab-width of spaces - attacklab: g_tab_width
+ .*\n+
+ )+
+ )
+ (\n*[ ]{0,3}[^ \t\n]|(?=~0)) // attacklab: g_tab_width
+ /g,function(){...});
+ */
+
+ // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug
+ text += '~0';
+
+ var pattern = /(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g;
+ text = text.replace(pattern, function (wholeMatch, m1, m2) {
+ var codeblock = m1,
+ nextChar = m2,
+ end = '\n';
+
+ codeblock = showdown.subParser('outdent')(codeblock);
+ codeblock = showdown.subParser('encodeCode')(codeblock);
+ codeblock = showdown.subParser('detab')(codeblock);
+ codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines
+ codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing newlines
+
+ if (options.omitExtraWLInCodeBlocks) {
+ end = '';
+ }
+
+ codeblock = '' + codeblock + end + '
';
+
+ return showdown.subParser('hashBlock')(codeblock, options, globals) + nextChar;
+ });
+
+ // attacklab: strip sentinel
+ text = text.replace(/~0/, '');
+
+ text = globals.converter._dispatch('codeBlocks.after', text, options, globals);
+ return text;
+});
+
+/**
+ *
+ * * Backtick quotes are used for
spans.
+ *
+ * * You can use multiple backticks as the delimiters if you want to
+ * include literal backticks in the code span. So, this input:
+ *
+ * Just type ``foo `bar` baz`` at the prompt.
+ *
+ * Will translate to:
+ *
+ * Just type foo `bar` baz
at the prompt.
+ *
+ * There's no arbitrary limit to the number of backticks you
+ * can use as delimters. If you need three consecutive backticks
+ * in your code, use four for delimiters, etc.
+ *
+ * * You can use spaces to get literal backticks at the edges:
+ *
+ * ... type `` `bar` `` ...
+ *
+ * Turns to:
+ *
+ * ... type `bar`
...
+ */
+showdown.subParser('codeSpans', function (text, options, globals) {
+ 'use strict';
+
+ text = globals.converter._dispatch('codeSpans.before', text, options, globals);
+
+ /*
+ text = text.replace(/
+ (^|[^\\]) // Character before opening ` can't be a backslash
+ (`+) // $2 = Opening run of `
+ ( // $3 = The code block
+ [^\r]*?
+ [^`] // attacklab: work around lack of lookbehind
+ )
+ \2 // Matching closer
+ (?!`)
+ /gm, function(){...});
+ */
+
+ if (typeof(text) === 'undefined') {
+ text = '';
+ }
+ text = text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,
+ function (wholeMatch, m1, m2, m3) {
+ var c = m3;
+ c = c.replace(/^([ \t]*)/g, ''); // leading whitespace
+ c = c.replace(/[ \t]*$/g, ''); // trailing whitespace
+ c = showdown.subParser('encodeCode')(c);
+ return m1 + '' + c + '
';
+ }
+ );
+
+ text = globals.converter._dispatch('codeSpans.after', text, options, globals);
+ return text;
+});
+
+/**
+ * Convert all tabs to spaces
+ */
+showdown.subParser('detab', function (text) {
+ 'use strict';
+
+ // expand first n-1 tabs
+ text = text.replace(/\t(?=\t)/g, ' '); // g_tab_width
+
+ // replace the nth with two sentinels
+ text = text.replace(/\t/g, '~A~B');
+
+ // use the sentinel to anchor our regex so it doesn't explode
+ text = text.replace(/~B(.+?)~A/g, function (wholeMatch, m1) {
+ var leadingText = m1,
+ numSpaces = 4 - leadingText.length % 4; // g_tab_width
+
+ // there *must* be a better way to do this:
+ for (var i = 0; i < numSpaces; i++) {
+ leadingText += ' ';
+ }
+
+ return leadingText;
+ });
+
+ // clean up sentinels
+ text = text.replace(/~A/g, ' '); // g_tab_width
+ text = text.replace(/~B/g, '');
+
+ return text;
+
+});
+
+/**
+ * Smart processing for ampersands and angle brackets that need to be encoded.
+ */
+showdown.subParser('encodeAmpsAndAngles', function (text) {
+ 'use strict';
+ // Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin:
+ // http://bumppo.net/projects/amputator/
+ text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g, '&');
+
+ // Encode naked <'s
+ text = text.replace(/<(?![a-z\/?\$!])/gi, '<');
+
+ return text;
+});
+
+/**
+ * Returns the string, with after processing the following backslash escape sequences.
+ *
+ * attacklab: The polite way to do this is with the new escapeCharacters() function:
+ *
+ * text = escapeCharacters(text,"\\",true);
+ * text = escapeCharacters(text,"`*_{}[]()>#+-.!",true);
+ *
+ * ...but we're sidestepping its use of the (slow) RegExp constructor
+ * as an optimization for Firefox. This function gets called a LOT.
+ */
+showdown.subParser('encodeBackslashEscapes', function (text) {
+ 'use strict';
+ text = text.replace(/\\(\\)/g, showdown.helper.escapeCharactersCallback);
+ text = text.replace(/\\([`*_{}\[\]()>#+-.!])/g, showdown.helper.escapeCharactersCallback);
+ return text;
+});
+
+/**
+ * Encode/escape certain characters inside Markdown code runs.
+ * The point is that in code, these characters are literals,
+ * and lose their special Markdown meanings.
+ */
+showdown.subParser('encodeCode', function (text) {
+ 'use strict';
+
+ // Encode all ampersands; HTML entities are not
+ // entities within a Markdown code span.
+ text = text.replace(/&/g, '&');
+
+ // Do the angle bracket song and dance:
+ text = text.replace(//g, '>');
+
+ // Now, escape characters that are magic in Markdown:
+ text = showdown.helper.escapeCharacters(text, '*_{}[]\\', false);
+
+ // jj the line above breaks this:
+ //---
+ //* Item
+ // 1. Subitem
+ // special char: *
+ // ---
+
+ return text;
+});
+
+/**
+ * Input: an email address, e.g. "foo@example.com"
+ *
+ * Output: the email address as a mailto link, with each character
+ * of the address encoded as either a decimal or hex entity, in
+ * the hopes of foiling most address harvesting spam bots. E.g.:
+ *
+ * foo
+ * @example.com
+ *
+ * Based on a filter by Matthew Wickline, posted to the BBEdit-Talk
+ * mailing list:
+ *
+ */
+showdown.subParser('encodeEmailAddress', function (addr) {
+ 'use strict';
+
+ var encode = [
+ function (ch) {
+ return '' + ch.charCodeAt(0) + ';';
+ },
+ function (ch) {
+ return '' + ch.charCodeAt(0).toString(16) + ';';
+ },
+ function (ch) {
+ return ch;
+ }
+ ];
+
+ addr = 'mailto:' + addr;
+
+ addr = addr.replace(/./g, function (ch) {
+ if (ch === '@') {
+ // this *must* be encoded. I insist.
+ ch = encode[Math.floor(Math.random() * 2)](ch);
+ } else if (ch !== ':') {
+ // leave ':' alone (to spot mailto: later)
+ var r = Math.random();
+ // roughly 10% raw, 45% hex, 45% dec
+ ch = (
+ r > 0.9 ? encode[2](ch) : r > 0.45 ? encode[1](ch) : encode[0](ch)
+ );
+ }
+ return ch;
+ });
+
+ addr = '' + addr + ' ';
+ addr = addr.replace(/">.+:/g, '">'); // strip the mailto: from the visible part
+
+ return addr;
+});
+
+/**
+ * Within tags -- meaning between < and > -- encode [\ ` * _] so they
+ * don't conflict with their use in Markdown for code, italics and strong.
+ */
+showdown.subParser('escapeSpecialCharsWithinTagAttributes', function (text) {
+ 'use strict';
+
+ // Build a regex to find HTML tags and comments. See Friedl's
+ // "Mastering Regular Expressions", 2nd Ed., pp. 200-201.
+ var regex = /(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|)/gi;
+
+ text = text.replace(regex, function (wholeMatch) {
+ var tag = wholeMatch.replace(/(.)<\/?code>(?=.)/g, '$1`');
+ tag = showdown.helper.escapeCharacters(tag, '\\`*_', false);
+ return tag;
+ });
+
+ return text;
+});
+
+/**
+ * Handle github codeblocks prior to running HashHTML so that
+ * HTML contained within the codeblock gets escaped properly
+ * Example:
+ * ```ruby
+ * def hello_world(x)
+ * puts "Hello, #{x}"
+ * end
+ * ```
+ */
+showdown.subParser('githubCodeBlocks', function (text, options, globals) {
+ 'use strict';
+
+ // early exit if option is not enabled
+ if (!options.ghCodeBlocks) {
+ return text;
+ }
+
+ text = globals.converter._dispatch('githubCodeBlocks.before', text, options, globals);
+
+ text += '~0';
+
+ text = text.replace(/(?:^|\n)```(.*)\n([\s\S]*?)\n```/g, function (wholeMatch, language, codeblock) {
+ var end = (options.omitExtraWLInCodeBlocks) ? '' : '\n';
+
+ // First parse the github code block
+ codeblock = showdown.subParser('encodeCode')(codeblock);
+ codeblock = showdown.subParser('detab')(codeblock);
+ codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines
+ codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing whitespace
+
+ codeblock = '' + codeblock + end + '
';
+
+ codeblock = showdown.subParser('hashBlock')(codeblock, options, globals);
+
+ // Since GHCodeblocks can be false positives, we need to
+ // store the primitive text and the parsed text in a global var,
+ // and then return a token
+ return '\n\n~G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\n\n';
+ });
+
+ // attacklab: strip sentinel
+ text = text.replace(/~0/, '');
+
+ return globals.converter._dispatch('githubCodeBlocks.after', text, options, globals);
+});
+
+showdown.subParser('hashBlock', function (text, options, globals) {
+ 'use strict';
+ text = text.replace(/(^\n+|\n+$)/g, '');
+ return '\n\n~K' + (globals.gHtmlBlocks.push(text) - 1) + 'K\n\n';
+});
+
+showdown.subParser('hashElement', function (text, options, globals) {
+ 'use strict';
+
+ return function (wholeMatch, m1) {
+ var blockText = m1;
+
+ // Undo double lines
+ blockText = blockText.replace(/\n\n/g, '\n');
+ blockText = blockText.replace(/^\n/, '');
+
+ // strip trailing blank lines
+ blockText = blockText.replace(/\n+$/g, '');
+
+ // Replace the element text with a marker ("~KxK" where x is its key)
+ blockText = '\n\n~K' + (globals.gHtmlBlocks.push(blockText) - 1) + 'K\n\n';
+
+ return blockText;
+ };
+});
+
+showdown.subParser('hashHTMLBlocks', function (text, options, globals) {
+ 'use strict';
+
+ var blockTags = [
+ 'pre',
+ 'div',
+ 'h1',
+ 'h2',
+ 'h3',
+ 'h4',
+ 'h5',
+ 'h6',
+ 'blockquote',
+ 'table',
+ 'dl',
+ 'ol',
+ 'ul',
+ 'script',
+ 'noscript',
+ 'form',
+ 'fieldset',
+ 'iframe',
+ 'math',
+ 'style',
+ 'section',
+ 'header',
+ 'footer',
+ 'nav',
+ 'article',
+ 'aside',
+ 'address',
+ 'audio',
+ 'canvas',
+ 'figure',
+ 'hgroup',
+ 'output',
+ 'video',
+ 'p'
+ ],
+ repFunc = function (wholeMatch, match, left, right) {
+ var txt = wholeMatch;
+ // check if this html element is marked as markdown
+ // if so, it's contents should be parsed as markdown
+ if (left.search(/\bmarkdown\b/) !== -1) {
+ txt = left + globals.converter.makeHtml(match) + right;
+ }
+ return '\n\n~K' + (globals.gHtmlBlocks.push(txt) - 1) + 'K\n\n';
+ };
+
+ for (var i = 0; i < blockTags.length; ++i) {
+ text = showdown.helper.replaceRecursiveRegExp(text, repFunc, '^(?: |\\t){0,3}<' + blockTags[i] + '\\b[^>]*>', '' + blockTags[i] + '>', 'gim');
+ }
+
+ // HR SPECIAL CASE
+ text = text.replace(/(\n[ ]{0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,
+ showdown.subParser('hashElement')(text, options, globals));
+
+ // Special case for standalone HTML comments:
+ text = text.replace(/()/g,
+ showdown.subParser('hashElement')(text, options, globals));
+
+ // PHP and ASP-style processor instructions (...?> and <%...%>)
+ text = text.replace(/(?:\n\n)([ ]{0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,
+ showdown.subParser('hashElement')(text, options, globals));
+ return text;
+});
+
+/**
+ * Hash span elements that should not be parsed as markdown
+ */
+showdown.subParser('hashHTMLSpans', function (text, config, globals) {
+ 'use strict';
+
+ var matches = showdown.helper.matchRecursiveRegExp(text, ']*>', '
', 'gi');
+
+ for (var i = 0; i < matches.length; ++i) {
+ text = text.replace(matches[i][0], '~L' + (globals.gHtmlSpans.push(matches[i][0]) - 1) + 'L');
+ }
+ return text;
+});
+
+/**
+ * Unhash HTML spans
+ */
+showdown.subParser('unhashHTMLSpans', function (text, config, globals) {
+ 'use strict';
+
+ for (var i = 0; i < globals.gHtmlSpans.length; ++i) {
+ text = text.replace('~L' + i + 'L', globals.gHtmlSpans[i]);
+ }
+
+ return text;
+});
+
+/**
+ * Hash span elements that should not be parsed as markdown
+ */
+showdown.subParser('hashPreCodeTags', function (text, config, globals) {
+ 'use strict';
+
+ var repFunc = function (wholeMatch, match, left, right) {
+ // encode html entities
+ var codeblock = left + showdown.subParser('encodeCode')(match) + right;
+ return '\n\n~G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\n\n';
+ };
+
+ text = showdown.helper.replaceRecursiveRegExp(text, repFunc, '^(?: |\\t){0,3}]*>\\s*]*>', '^(?: |\\t){0,3}
\\s* ', 'gim');
+ return text;
+});
+
+showdown.subParser('headers', function (text, options, globals) {
+ 'use strict';
+
+ text = globals.converter._dispatch('headers.before', text, options, globals);
+
+ var prefixHeader = options.prefixHeaderId,
+ headerLevelStart = (isNaN(parseInt(options.headerLevelStart))) ? 1 : parseInt(options.headerLevelStart),
+
+ // Set text-style headers:
+ // Header 1
+ // ========
+ //
+ // Header 2
+ // --------
+ //
+ setextRegexH1 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n={2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n=+[ \t]*\n+/gm,
+ setextRegexH2 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n-{2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n-+[ \t]*\n+/gm;
+
+ text = text.replace(setextRegexH1, function (wholeMatch, m1) {
+
+ var spanGamut = showdown.subParser('spanGamut')(m1, options, globals),
+ hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"',
+ hLevel = headerLevelStart,
+ hashBlock = '' + spanGamut + ' ';
+ return showdown.subParser('hashBlock')(hashBlock, options, globals);
+ });
+
+ text = text.replace(setextRegexH2, function (matchFound, m1) {
+ var spanGamut = showdown.subParser('spanGamut')(m1, options, globals),
+ hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"',
+ hLevel = headerLevelStart + 1,
+ hashBlock = '' + spanGamut + ' ';
+ return showdown.subParser('hashBlock')(hashBlock, options, globals);
+ });
+
+ // atx-style headers:
+ // # Header 1
+ // ## Header 2
+ // ## Header 2 with closing hashes ##
+ // ...
+ // ###### Header 6
+ //
+ text = text.replace(/^(#{1,6})[ \t]*(.+?)[ \t]*#*\n+/gm, function (wholeMatch, m1, m2) {
+ var span = showdown.subParser('spanGamut')(m2, options, globals),
+ hID = (options.noHeaderId) ? '' : ' id="' + headerId(m2) + '"',
+ hLevel = headerLevelStart - 1 + m1.length,
+ header = '' + span + ' ';
+
+ return showdown.subParser('hashBlock')(header, options, globals);
+ });
+
+ function headerId(m) {
+ var title, escapedId = m.replace(/[^\w]/g, '').toLowerCase();
+
+ if (globals.hashLinkCounts[escapedId]) {
+ title = escapedId + '-' + (globals.hashLinkCounts[escapedId]++);
+ } else {
+ title = escapedId;
+ globals.hashLinkCounts[escapedId] = 1;
+ }
+
+ // Prefix id to prevent causing inadvertent pre-existing style matches.
+ if (prefixHeader === true) {
+ prefixHeader = 'section';
+ }
+
+ if (showdown.helper.isString(prefixHeader)) {
+ return prefixHeader + title;
+ }
+ return title;
+ }
+
+ text = globals.converter._dispatch('headers.after', text, options, globals);
+ return text;
+});
+
+/**
+ * Turn Markdown image shortcuts into tags.
+ */
+showdown.subParser('images', function (text, options, globals) {
+ 'use strict';
+
+ text = globals.converter._dispatch('images.before', text, options, globals);
+
+ var inlineRegExp = /!\[(.*?)]\s?\([ \t]*()(\S+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(['"])(.*?)\6[ \t]*)?\)/g,
+ referenceRegExp = /!\[([^\]]*?)] ?(?:\n *)?\[(.*?)]()()()()()/g;
+
+ function writeImageTag (wholeMatch, altText, linkId, url, width, height, m5, title) {
+
+ var gUrls = globals.gUrls,
+ gTitles = globals.gTitles,
+ gDims = globals.gDimensions;
+
+ linkId = linkId.toLowerCase();
+
+ if (!title) {
+ title = '';
+ }
+
+ if (url === '' || url === null) {
+ if (linkId === '' || linkId === null) {
+ // lower-case and turn embedded newlines into spaces
+ linkId = altText.toLowerCase().replace(/ ?\n/g, ' ');
+ }
+ url = '#' + linkId;
+
+ if (!showdown.helper.isUndefined(gUrls[linkId])) {
+ url = gUrls[linkId];
+ if (!showdown.helper.isUndefined(gTitles[linkId])) {
+ title = gTitles[linkId];
+ }
+ if (!showdown.helper.isUndefined(gDims[linkId])) {
+ width = gDims[linkId].width;
+ height = gDims[linkId].height;
+ }
+ } else {
+ return wholeMatch;
+ }
+ }
+
+ altText = altText.replace(/"/g, '"');
+ altText = showdown.helper.escapeCharacters(altText, '*_', false);
+ url = showdown.helper.escapeCharacters(url, '*_', false);
+ var result = ' ';
+ return result;
+ }
+
+ // First, handle reference-style labeled images: ![alt text][id]
+ text = text.replace(referenceRegExp, writeImageTag);
+
+ // Next, handle inline images: ![alt text](url =x "optional title")
+ text = text.replace(inlineRegExp, writeImageTag);
+
+ text = globals.converter._dispatch('images.after', text, options, globals);
+ return text;
+});
+
+showdown.subParser('italicsAndBold', function (text, options, globals) {
+ 'use strict';
+
+ text = globals.converter._dispatch('italicsAndBold.before', text, options, globals);
+
+ if (options.literalMidWordUnderscores) {
+ //underscores
+ // Since we are consuming a \s character, we need to add it
+ text = text.replace(/(^|\s|>|\b)__(?=\S)([\s\S]+?)__(?=\b|<|\s|$)/gm, '$1$2 ');
+ text = text.replace(/(^|\s|>|\b)_(?=\S)([\s\S]+?)_(?=\b|<|\s|$)/gm, '$1$2 ');
+ //asterisks
+ text = text.replace(/(\*\*)(?=\S)([^\r]*?\S[*]*)\1/g, '$2 ');
+ text = text.replace(/(\*)(?=\S)([^\r]*?\S)\1/g, '$2 ');
+
+ } else {
+ // must go first:
+ text = text.replace(/(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g, '$2 ');
+ text = text.replace(/(\*|_)(?=\S)([^\r]*?\S)\1/g, '$2 ');
+ }
+
+ text = globals.converter._dispatch('italicsAndBold.after', text, options, globals);
+ return text;
+});
+
+/**
+ * Form HTML ordered (numbered) and unordered (bulleted) lists.
+ */
+showdown.subParser('lists', function (text, options, globals) {
+ 'use strict';
+
+ text = globals.converter._dispatch('lists.before', text, options, globals);
+ /**
+ * Process the contents of a single ordered or unordered list, splitting it
+ * into individual list items.
+ * @param {string} listStr
+ * @param {boolean} trimTrailing
+ * @returns {string}
+ */
+ function processListItems (listStr, trimTrailing) {
+ // The $g_list_level global keeps track of when we're inside a list.
+ // Each time we enter a list, we increment it; when we leave a list,
+ // we decrement. If it's zero, we're not in a list anymore.
+ //
+ // We do this because when we're not inside a list, we want to treat
+ // something like this:
+ //
+ // I recommend upgrading to version
+ // 8. Oops, now this line is treated
+ // as a sub-list.
+ //
+ // As a single paragraph, despite the fact that the second line starts
+ // with a digit-period-space sequence.
+ //
+ // Whereas when we're inside a list (or sub-list), that line will be
+ // treated as the start of a sub-list. What a kludge, huh? This is
+ // an aspect of Markdown's syntax that's hard to parse perfectly
+ // without resorting to mind-reading. Perhaps the solution is to
+ // change the syntax rules such that sub-lists must start with a
+ // starting cardinal number; e.g. "1." or "a.".
+ globals.gListLevel++;
+
+ // trim trailing blank lines:
+ listStr = listStr.replace(/\n{2,}$/, '\n');
+
+ // attacklab: add sentinel to emulate \z
+ listStr += '~0';
+
+ var rgx = /(\n)?(^[ \t]*)([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(~0|\2([*+-]|\d+[.])[ \t]+))/gm,
+ isParagraphed = (/\n[ \t]*\n(?!~0)/.test(listStr));
+
+ listStr = listStr.replace(rgx, function (wholeMatch, m1, m2, m3, m4, taskbtn, checked) {
+ checked = (checked && checked.trim() !== '');
+ var item = showdown.subParser('outdent')(m4, options, globals),
+ bulletStyle = '';
+
+ // Support for github tasklists
+ if (taskbtn && options.tasklists) {
+ bulletStyle = ' class="task-list-item" style="list-style-type: none;"';
+ item = item.replace(/^[ \t]*\[(x|X| )?]/m, function () {
+ var otp = ' ';
+ return otp;
+ });
+ }
+ // m1 - Leading line or
+ // Has a double return (multi paragraph) or
+ // Has sublist
+ if (m1 || (item.search(/\n{2,}/) > -1)) {
+ item = showdown.subParser('githubCodeBlocks')(item, options, globals);
+ item = showdown.subParser('blockGamut')(item, options, globals);
+ } else {
+ // Recursion for sub-lists:
+ item = showdown.subParser('lists')(item, options, globals);
+ item = item.replace(/\n$/, ''); // chomp(item)
+ if (isParagraphed) {
+ item = showdown.subParser('paragraphs')(item, options, globals);
+ } else {
+ item = showdown.subParser('spanGamut')(item, options, globals);
+ }
+ }
+ item = '\n' + item + ' \n';
+ return item;
+ });
+
+ // attacklab: strip sentinel
+ listStr = listStr.replace(/~0/g, '');
+
+ globals.gListLevel--;
+
+ if (trimTrailing) {
+ listStr = listStr.replace(/\s+$/, '');
+ }
+
+ return listStr;
+ }
+
+ /**
+ * Check and parse consecutive lists (better fix for issue #142)
+ * @param {string} list
+ * @param {string} listType
+ * @param {boolean} trimTrailing
+ * @returns {string}
+ */
+ function parseConsecutiveLists(list, listType, trimTrailing) {
+ // check if we caught 2 or more consecutive lists by mistake
+ // we use the counterRgx, meaning if listType is UL we look for UL and vice versa
+ var counterRxg = (listType === 'ul') ? /^ {0,2}\d+\.[ \t]/gm : /^ {0,2}[*+-][ \t]/gm,
+ subLists = [],
+ result = '';
+
+ if (list.search(counterRxg) !== -1) {
+ (function parseCL(txt) {
+ var pos = txt.search(counterRxg);
+ if (pos !== -1) {
+ // slice
+ result += '\n\n<' + listType + '>' + processListItems(txt.slice(0, pos), !!trimTrailing) + '' + listType + '>\n\n';
+
+ // invert counterType and listType
+ listType = (listType === 'ul') ? 'ol' : 'ul';
+ counterRxg = (listType === 'ul') ? /^ {0,2}\d+\.[ \t]/gm : /^ {0,2}[*+-][ \t]/gm;
+
+ //recurse
+ parseCL(txt.slice(pos));
+ } else {
+ result += '\n\n<' + listType + '>' + processListItems(txt, !!trimTrailing) + '' + listType + '>\n\n';
+ }
+ })(list);
+ for (var i = 0; i < subLists.length; ++i) {
+
+ }
+ } else {
+ result = '\n\n<' + listType + '>' + processListItems(list, !!trimTrailing) + '' + listType + '>\n\n';
+ }
+
+ return result;
+ }
+
+ // attacklab: add sentinel to hack around khtml/safari bug:
+ // http://bugs.webkit.org/show_bug.cgi?id=11231
+ text += '~0';
+
+ // Re-usable pattern to match any entire ul or ol list:
+ var wholeList = /^(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;
+
+ if (globals.gListLevel) {
+ text = text.replace(wholeList, function (wholeMatch, list, m2) {
+ var listType = (m2.search(/[*+-]/g) > -1) ? 'ul' : 'ol';
+ return parseConsecutiveLists(list, listType, true);
+ });
+ } else {
+ wholeList = /(\n\n|^\n?)(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;
+ //wholeList = /(\n\n|^\n?)( {0,3}([*+-]|\d+\.)[ \t]+[\s\S]+?)(?=(~0)|(\n\n(?!\t| {2,}| {0,3}([*+-]|\d+\.)[ \t])))/g;
+ text = text.replace(wholeList, function (wholeMatch, m1, list, m3) {
+
+ var listType = (m3.search(/[*+-]/g) > -1) ? 'ul' : 'ol';
+ return parseConsecutiveLists(list, listType);
+ });
+ }
+
+ // attacklab: strip sentinel
+ text = text.replace(/~0/, '');
+
+ text = globals.converter._dispatch('lists.after', text, options, globals);
+ return text;
+});
+
+/**
+ * Remove one level of line-leading tabs or spaces
+ */
+showdown.subParser('outdent', function (text) {
+ 'use strict';
+
+ // attacklab: hack around Konqueror 3.5.4 bug:
+ // "----------bug".replace(/^-/g,"") == "bug"
+ text = text.replace(/^(\t|[ ]{1,4})/gm, '~0'); // attacklab: g_tab_width
+
+ // attacklab: clean up hack
+ text = text.replace(/~0/g, '');
+
+ return text;
+});
+
+/**
+ *
+ */
+showdown.subParser('paragraphs', function (text, options, globals) {
+ 'use strict';
+
+ text = globals.converter._dispatch('paragraphs.before', text, options, globals);
+ // Strip leading and trailing lines:
+ text = text.replace(/^\n+/g, '');
+ text = text.replace(/\n+$/g, '');
+
+ var grafs = text.split(/\n{2,}/g),
+ grafsOut = [],
+ end = grafs.length; // Wrap tags
+
+ for (var i = 0; i < end; i++) {
+ var str = grafs[i];
+ // if this is an HTML marker, copy it
+ if (str.search(/~(K|G)(\d+)\1/g) >= 0) {
+ grafsOut.push(str);
+ } else {
+ str = showdown.subParser('spanGamut')(str, options, globals);
+ str = str.replace(/^([ \t]*)/g, '
');
+ str += '
';
+ grafsOut.push(str);
+ }
+ }
+
+ /** Unhashify HTML blocks */
+ end = grafsOut.length;
+ for (i = 0; i < end; i++) {
+ var blockText = '',
+ grafsOutIt = grafsOut[i],
+ codeFlag = false;
+ // if this is a marker for an html block...
+ while (grafsOutIt.search(/~(K|G)(\d+)\1/) >= 0) {
+ var delim = RegExp.$1,
+ num = RegExp.$2;
+
+ if (delim === 'K') {
+ blockText = globals.gHtmlBlocks[num];
+ } else {
+ // we need to check if ghBlock is a false positive
+ if (codeFlag) {
+ // use encoded version of all text
+ blockText = showdown.subParser('encodeCode')(globals.ghCodeBlocks[num].text);
+ } else {
+ blockText = globals.ghCodeBlocks[num].codeblock;
+ }
+ }
+ blockText = blockText.replace(/\$/g, '$$$$'); // Escape any dollar signs
+
+ grafsOutIt = grafsOutIt.replace(/(\n\n)?~(K|G)\d+\2(\n\n)?/, blockText);
+ // Check if grafsOutIt is a pre->code
+ if (/^]*>\s*]*>/.test(grafsOutIt)) {
+ codeFlag = true;
+ }
+ }
+ grafsOut[i] = grafsOutIt;
+ }
+ text = grafsOut.join('\n\n');
+ // Strip leading and trailing lines:
+ text = text.replace(/^\n+/g, '');
+ text = text.replace(/\n+$/g, '');
+ return globals.converter._dispatch('paragraphs.after', text, options, globals);
+});
+
+/**
+ * Run extension
+ */
+showdown.subParser('runExtension', function (ext, text, options, globals) {
+ 'use strict';
+
+ if (ext.filter) {
+ text = ext.filter(text, globals.converter, options);
+
+ } else if (ext.regex) {
+ // TODO remove this when old extension loading mechanism is deprecated
+ var re = ext.regex;
+ if (!re instanceof RegExp) {
+ re = new RegExp(re, 'g');
+ }
+ text = text.replace(re, ext.replace);
+ }
+
+ return text;
+});
+
+/**
+ * These are all the transformations that occur *within* block-level
+ * tags like paragraphs, headers, and list items.
+ */
+showdown.subParser('spanGamut', function (text, options, globals) {
+ 'use strict';
+
+ text = globals.converter._dispatch('spanGamut.before', text, options, globals);
+ text = showdown.subParser('codeSpans')(text, options, globals);
+ text = showdown.subParser('escapeSpecialCharsWithinTagAttributes')(text, options, globals);
+ text = showdown.subParser('encodeBackslashEscapes')(text, options, globals);
+
+ // Process anchor and image tags. Images must come first,
+ // because ![foo][f] looks like an anchor.
+ text = showdown.subParser('images')(text, options, globals);
+ text = showdown.subParser('anchors')(text, options, globals);
+
+ // Make links out of things like ` `
+ // Must come after _DoAnchors(), because you can use < and >
+ // delimiters in inline links like [this]().
+ text = showdown.subParser('autoLinks')(text, options, globals);
+ text = showdown.subParser('encodeAmpsAndAngles')(text, options, globals);
+ text = showdown.subParser('italicsAndBold')(text, options, globals);
+ text = showdown.subParser('strikethrough')(text, options, globals);
+
+ // Do hard breaks:
+ text = text.replace(/ +\n/g, ' \n');
+
+ text = globals.converter._dispatch('spanGamut.after', text, options, globals);
+ return text;
+});
+
+showdown.subParser('strikethrough', function (text, options, globals) {
+ 'use strict';
+
+ if (options.strikethrough) {
+ text = globals.converter._dispatch('strikethrough.before', text, options, globals);
+ text = text.replace(/(?:~T){2}([\s\S]+?)(?:~T){2}/g, '$1');
+ text = globals.converter._dispatch('strikethrough.after', text, options, globals);
+ }
+
+ return text;
+});
+
+/**
+ * Strip any lines consisting only of spaces and tabs.
+ * This makes subsequent regexs easier to write, because we can
+ * match consecutive blank lines with /\n+/ instead of something
+ * contorted like /[ \t]*\n+/
+ */
+showdown.subParser('stripBlankLines', function (text) {
+ 'use strict';
+ return text.replace(/^[ \t]+$/mg, '');
+});
+
+/**
+ * Strips link definitions from text, stores the URLs and titles in
+ * hash references.
+ * Link defs are in the form: ^[id]: url "optional title"
+ *
+ * ^[ ]{0,3}\[(.+)\]: // id = $1 attacklab: g_tab_width - 1
+ * [ \t]*
+ * \n? // maybe *one* newline
+ * [ \t]*
+ * (\S+?)>? // url = $2
+ * [ \t]*
+ * \n? // maybe one newline
+ * [ \t]*
+ * (?:
+ * (\n*) // any lines skipped = $3 attacklab: lookbehind removed
+ * ["(]
+ * (.+?) // title = $4
+ * [")]
+ * [ \t]*
+ * )? // title is optional
+ * (?:\n+|$)
+ * /gm,
+ * function(){...});
+ *
+ */
+showdown.subParser('stripLinkDefinitions', function (text, options, globals) {
+ 'use strict';
+
+ var 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;
+
+ // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug
+ text += '~0';
+
+ text = text.replace(regex, function (wholeMatch, linkId, url, width, height, blankLines, title) {
+ linkId = linkId.toLowerCase();
+ globals.gUrls[linkId] = showdown.subParser('encodeAmpsAndAngles')(url); // Link IDs are case-insensitive
+
+ if (blankLines) {
+ // Oops, found blank lines, so it's not a title.
+ // Put back the parenthetical statement we stole.
+ return blankLines + title;
+
+ } else {
+ if (title) {
+ globals.gTitles[linkId] = title.replace(/"|'/g, '"');
+ }
+ if (options.parseImgDimensions && width && height) {
+ globals.gDimensions[linkId] = {
+ width: width,
+ height: height
+ };
+ }
+ }
+ // Completely remove the definition from the text
+ return '';
+ });
+
+ // attacklab: strip sentinel
+ text = text.replace(/~0/, '');
+
+ return text;
+});
+
+showdown.subParser('tables', function (text, options, globals) {
+ 'use strict';
+
+ if (!options.tables) {
+ return text;
+ }
+
+ var tableRgx = /^[ \t]{0,3}\|?.+\|.+\n[ \t]{0,3}\|?[ \t]*:?[ \t]*(?:-|=){2,}[ \t]*:?[ \t]*\|[ \t]*:?[ \t]*(?:-|=){2,}[\s\S]+?(?:\n\n|~0)/gm;
+
+ function parseStyles(sLine) {
+ if (/^:[ \t]*--*$/.test(sLine)) {
+ return ' style="text-align:left;"';
+ } else if (/^--*[ \t]*:[ \t]*$/.test(sLine)) {
+ return ' style="text-align:right;"';
+ } else if (/^:[ \t]*--*[ \t]*:$/.test(sLine)) {
+ return ' style="text-align:center;"';
+ } else {
+ return '';
+ }
+ }
+
+ function parseHeaders(header, style) {
+ var id = '';
+ header = header.trim();
+ if (options.tableHeaderId) {
+ id = ' id="' + header.replace(/ /g, '_').toLowerCase() + '"';
+ }
+ header = showdown.subParser('spanGamut')(header, options, globals);
+
+ return '' + header + ' \n';
+ }
+
+ function parseCells(cell, style) {
+ var subText = showdown.subParser('spanGamut')(cell, options, globals);
+ return '' + subText + ' \n';
+ }
+
+ function buildTable(headers, cells) {
+ var tb = '\n\n\n',
+ tblLgn = headers.length;
+
+ for (var i = 0; i < tblLgn; ++i) {
+ tb += headers[i];
+ }
+ tb += ' \n \n\n';
+
+ for (i = 0; i < cells.length; ++i) {
+ tb += '\n';
+ for (var ii = 0; ii < tblLgn; ++ii) {
+ tb += cells[i][ii];
+ }
+ tb += ' \n';
+ }
+ tb += ' \n
\n';
+ return tb;
+ }
+
+ text = globals.converter._dispatch('tables.before', text, options, globals);
+
+ text = text.replace(tableRgx, function (rawTable) {
+
+ var i, tableLines = rawTable.split('\n');
+
+ // strip wrong first and last column if wrapped tables are used
+ for (i = 0; i < tableLines.length; ++i) {
+ if (/^[ \t]{0,3}\|/.test(tableLines[i])) {
+ tableLines[i] = tableLines[i].replace(/^[ \t]{0,3}\|/, '');
+ }
+ if (/\|[ \t]*$/.test(tableLines[i])) {
+ tableLines[i] = tableLines[i].replace(/\|[ \t]*$/, '');
+ }
+ }
+
+ var rawHeaders = tableLines[0].split('|').map(function (s) { return s.trim();}),
+ rawStyles = tableLines[1].split('|').map(function (s) { return s.trim();}),
+ rawCells = [],
+ headers = [],
+ styles = [],
+ cells = [];
+
+ tableLines.shift();
+ tableLines.shift();
+
+ for (i = 0; i < tableLines.length; ++i) {
+ if (tableLines[i].trim() === '') {
+ continue;
+ }
+ rawCells.push(
+ tableLines[i]
+ .split('|')
+ .map(function (s) {
+ return s.trim();
+ })
+ );
+ }
+
+ if (rawHeaders.length < rawStyles.length) {
+ return rawTable;
+ }
+
+ for (i = 0; i < rawStyles.length; ++i) {
+ styles.push(parseStyles(rawStyles[i]));
+ }
+
+ for (i = 0; i < rawHeaders.length; ++i) {
+ if (showdown.helper.isUndefined(styles[i])) {
+ styles[i] = '';
+ }
+ headers.push(parseHeaders(rawHeaders[i], styles[i]));
+ }
+
+ for (i = 0; i < rawCells.length; ++i) {
+ var row = [];
+ for (var ii = 0; ii < headers.length; ++ii) {
+ if (showdown.helper.isUndefined(rawCells[i][ii])) {
+
+ }
+ row.push(parseCells(rawCells[i][ii], styles[ii]));
+ }
+ cells.push(row);
+ }
+
+ return buildTable(headers, cells);
+ });
+
+ text = globals.converter._dispatch('tables.after', text, options, globals);
+
+ return text;
+});
+
+/**
+ * Swap back in all the special characters we've hidden.
+ */
+showdown.subParser('unescapeSpecialChars', function (text) {
+ 'use strict';
+
+ text = text.replace(/~E(\d+)E/g, function (wholeMatch, m1) {
+ var charCodeToReplace = parseInt(m1);
+ return String.fromCharCode(charCodeToReplace);
+ });
+ return text;
+});
+module.exports = showdown;
diff --git a/wxParse/wxDiscode.js b/wxParse/wxDiscode.js
new file mode 100644
index 0000000..fca29bb
--- /dev/null
+++ b/wxParse/wxDiscode.js
@@ -0,0 +1,207 @@
+// HTML 支持的数学符号
+function strNumDiscode(str){
+ str = str.replace(/∀/g, '∀');
+ str = str.replace(/∂/g, '∂');
+ str = str.replace(/&exists;/g, '∃');
+ str = str.replace(/∅/g, '∅');
+ str = str.replace(/∇/g, '∇');
+ str = str.replace(/∈/g, '∈');
+ str = str.replace(/∉/g, '∉');
+ str = str.replace(/∋/g, '∋');
+ str = str.replace(/∏/g, '∏');
+ str = str.replace(/∑/g, '∑');
+ str = str.replace(/−/g, '−');
+ str = str.replace(/∗/g, '∗');
+ str = str.replace(/√/g, '√');
+ str = str.replace(/∝/g, '∝');
+ str = str.replace(/∞/g, '∞');
+ str = str.replace(/∠/g, '∠');
+ str = str.replace(/∧/g, '∧');
+ str = str.replace(/∨/g, '∨');
+ str = str.replace(/∩/g, '∩');
+ str = str.replace(/∩/g, '∪');
+ str = str.replace(/∫/g, '∫');
+ str = str.replace(/∴/g, '∴');
+ str = str.replace(/∼/g, '∼');
+ str = str.replace(/≅/g, '≅');
+ str = str.replace(/≈/g, '≈');
+ str = str.replace(/≠/g, '≠');
+ str = str.replace(/≤/g, '≤');
+ str = str.replace(/≥/g, '≥');
+ str = str.replace(/⊂/g, '⊂');
+ str = str.replace(/⊃/g, '⊃');
+ str = str.replace(/⊄/g, '⊄');
+ str = str.replace(/⊆/g, '⊆');
+ str = str.replace(/⊇/g, '⊇');
+ str = str.replace(/⊕/g, '⊕');
+ str = str.replace(/⊗/g, '⊗');
+ str = str.replace(/⊥/g, '⊥');
+ str = str.replace(/⋅/g, '⋅');
+ return str;
+}
+
+//HTML 支持的希腊字母
+function strGreeceDiscode(str){
+ str = str.replace(/Α/g, 'Α');
+ str = str.replace(/Β/g, 'Β');
+ str = str.replace(/Γ/g, 'Γ');
+ str = str.replace(/Δ/g, 'Δ');
+ str = str.replace(/Ε/g, 'Ε');
+ str = str.replace(/Ζ/g, 'Ζ');
+ str = str.replace(/Η/g, 'Η');
+ str = str.replace(/Θ/g, 'Θ');
+ str = str.replace(/Ι/g, 'Ι');
+ str = str.replace(/Κ/g, 'Κ');
+ str = str.replace(/Λ/g, 'Λ');
+ str = str.replace(/Μ/g, 'Μ');
+ str = str.replace(/Ν/g, 'Ν');
+ str = str.replace(/Ξ/g, 'Ν');
+ str = str.replace(/Ο/g, 'Ο');
+ str = str.replace(/Π/g, 'Π');
+ str = str.replace(/Ρ/g, 'Ρ');
+ str = str.replace(/Σ/g, 'Σ');
+ str = str.replace(/Τ/g, 'Τ');
+ str = str.replace(/Υ/g, 'Υ');
+ str = str.replace(/Φ/g, 'Φ');
+ str = str.replace(/Χ/g, 'Χ');
+ str = str.replace(/Ψ/g, 'Ψ');
+ str = str.replace(/Ω/g, 'Ω');
+
+ str = str.replace(/α/g, 'α');
+ str = str.replace(/β/g, 'β');
+ str = str.replace(/γ/g, 'γ');
+ str = str.replace(/δ/g, 'δ');
+ str = str.replace(/ε/g, 'ε');
+ str = str.replace(/ζ/g, 'ζ');
+ str = str.replace(/η/g, 'η');
+ str = str.replace(/θ/g, 'θ');
+ str = str.replace(/ι/g, 'ι');
+ str = str.replace(/κ/g, 'κ');
+ str = str.replace(/λ/g, 'λ');
+ str = str.replace(/μ/g, 'μ');
+ str = str.replace(/ν/g, 'ν');
+ str = str.replace(/ξ/g, 'ξ');
+ str = str.replace(/ο/g, 'ο');
+ str = str.replace(/π/g, 'π');
+ str = str.replace(/ρ/g, 'ρ');
+ str = str.replace(/ς/g, 'ς');
+ str = str.replace(/σ/g, 'σ');
+ str = str.replace(/τ/g, 'τ');
+ str = str.replace(/υ/g, 'υ');
+ str = str.replace(/φ/g, 'φ');
+ str = str.replace(/χ/g, 'χ');
+ str = str.replace(/ψ/g, 'ψ');
+ str = str.replace(/ω/g, 'ω');
+ str = str.replace(/ϑ/g, 'ϑ');
+ str = str.replace(/ϒ/g, 'ϒ');
+ str = str.replace(/ϖ/g, 'ϖ');
+ str = str.replace(/·/g, '·');
+ return str;
+}
+
+//
+
+function strcharacterDiscode(str){
+ // 加入常用解析
+ str = str.replace(/ /g, ' ');
+ str = str.replace(/"/g, "'");
+ str = str.replace(/&/g, '&');
+ // str = str.replace(/</g, '‹');
+ // str = str.replace(/>/g, '›');
+
+ str = str.replace(/</g, '<');
+ str = str.replace(/>/g, '>');
+ str = str.replace(/•/g, '•');
+
+ return str;
+}
+
+// HTML 支持的其他实体
+function strOtherDiscode(str){
+ str = str.replace(/Œ/g, 'Œ');
+ str = str.replace(/œ/g, 'œ');
+ str = str.replace(/Š/g, 'Š');
+ str = str.replace(/š/g, 'š');
+ str = str.replace(/Ÿ/g, 'Ÿ');
+ str = str.replace(/ƒ/g, 'ƒ');
+ str = str.replace(/ˆ/g, 'ˆ');
+ str = str.replace(/˜/g, '˜');
+ str = str.replace(/ /g, '');
+ str = str.replace(/ /g, '');
+ str = str.replace(/ /g, '');
+ str = str.replace(//g, '');
+ str = str.replace(//g, '');
+ str = str.replace(//g, '');
+ str = str.replace(//g, '');
+ str = str.replace(/–/g, '–');
+ str = str.replace(/—/g, '—');
+ str = str.replace(/‘/g, '‘');
+ str = str.replace(/’/g, '’');
+ str = str.replace(/‚/g, '‚');
+ str = str.replace(/“/g, '“');
+ str = str.replace(/”/g, '”');
+ str = str.replace(/„/g, '„');
+ str = str.replace(/†/g, '†');
+ str = str.replace(/‡/g, '‡');
+ str = str.replace(/•/g, '•');
+ str = str.replace(/…/g, '…');
+ str = str.replace(/‰/g, '‰');
+ str = str.replace(/′/g, '′');
+ str = str.replace(/″/g, '″');
+ str = str.replace(/‹/g, '‹');
+ str = str.replace(/›/g, '›');
+ str = str.replace(/‾/g, '‾');
+ str = str.replace(/€/g, '€');
+ str = str.replace(/™/g, '™');
+
+ str = str.replace(/←/g, '←');
+ str = str.replace(/↑/g, '↑');
+ str = str.replace(/→/g, '→');
+ str = str.replace(/↓/g, '↓');
+ str = str.replace(/↔/g, '↔');
+ str = str.replace(/↵/g, '↵');
+ str = str.replace(/⌈/g, '⌈');
+ str = str.replace(/⌉/g, '⌉');
+
+ str = str.replace(/⌊/g, '⌊');
+ str = str.replace(/⌋/g, '⌋');
+ str = str.replace(/◊/g, '◊');
+ str = str.replace(/♠/g, '♠');
+ str = str.replace(/♣/g, '♣');
+ str = str.replace(/♥/g, '♥');
+
+ str = str.replace(/♦/g, '♦');
+ str = str.replace(/'/g, '\'');
+ return str;
+}
+
+function strMoreDiscode(str){
+ str = str.replace(/\r\n/g,"");
+ str = str.replace(/\n/g,"");
+
+ str = str.replace(/code/g,"wxxxcode-style");
+ return str;
+}
+
+function strDiscode(str){
+ str = strNumDiscode(str);
+ str = strGreeceDiscode(str);
+ str = strcharacterDiscode(str);
+ str = strOtherDiscode(str);
+ str = strMoreDiscode(str);
+ return str;
+}
+function urlToHttpUrl(url,rep){
+
+ var patt1 = new RegExp("^//");
+ var result = patt1.test(url);
+ if(result){
+ url = rep+":"+url;
+ }
+ return url;
+}
+
+module.exports = {
+ strDiscode:strDiscode,
+ urlToHttpUrl:urlToHttpUrl
+}
\ No newline at end of file
diff --git a/wxParse/wxParse.js b/wxParse/wxParse.js
new file mode 100644
index 0000000..379f2f6
--- /dev/null
+++ b/wxParse/wxParse.js
@@ -0,0 +1,159 @@
+/**
+ * author: Di (微信小程序开发工程师)
+ * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
+ * 垂直微信小程序开发交流社区
+ *
+ * github地址: https://github.com/icindy/wxParse
+ *
+ * for: 微信小程序富文本解析
+ * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
+ */
+
+/**
+ * utils函数引入
+ **/
+import showdown from './showdown.js';
+import HtmlToJson from './html2json.js';
+/**
+ * 配置及公有属性
+ **/
+var realWindowWidth = 0;
+var realWindowHeight = 0;
+wx.getSystemInfo({
+ success: function (res) {
+ realWindowWidth = res.windowWidth
+ realWindowHeight = res.windowHeight
+ }
+})
+/**
+ * 主函数入口区
+ **/
+function wxParse(bindName = 'wxParseData', type='html', data='数据不能为空
', target,imagePadding) {
+ var that = target;
+ var transData = {};//存放转化后的数据
+ if (type == 'html') {
+ transData = HtmlToJson.html2json(data, bindName);
+ console.log(JSON.stringify(transData, ' ', ' '));
+ } else if (type == 'md' || type == 'markdown') {
+ var converter = new showdown.Converter();
+ var html = converter.makeHtml(data);
+ transData = HtmlToJson.html2json(html, bindName);
+ console.log(JSON.stringify(transData, ' ', ' '));
+ }
+ transData.view = {};
+ transData.view.imagePadding = 0;
+ if(typeof(imagePadding) != 'undefined'){
+ transData.view.imagePadding = imagePadding
+ }
+ var bindData = {};
+ bindData[bindName] = transData;
+ that.setData(bindData)
+ that.wxParseImgLoad = wxParseImgLoad;
+ that.wxParseImgTap = wxParseImgTap;
+}
+// 图片点击事件
+function wxParseImgTap(e) {
+ var that = this;
+ var nowImgUrl = e.target.dataset.src;
+ var tagFrom = e.target.dataset.from;
+ if (typeof (tagFrom) != 'undefined' && tagFrom.length > 0) {
+ wx.previewImage({
+ current: nowImgUrl, // 当前显示图片的http链接
+ urls: that.data[tagFrom].imageUrls // 需要预览的图片http链接列表
+ })
+ }
+}
+
+/**
+ * 图片视觉宽高计算函数区
+ **/
+function wxParseImgLoad(e) {
+ var that = this;
+ var tagFrom = e.target.dataset.from;
+ var idx = e.target.dataset.idx;
+ if (typeof (tagFrom) != 'undefined' && tagFrom.length > 0) {
+ calMoreImageInfo(e, idx, that, tagFrom)
+ }
+}
+// 假循环获取计算图片视觉最佳宽高
+function calMoreImageInfo(e, idx, that, bindName) {
+ var temData = that.data[bindName];
+ if (!temData || temData.images.length == 0) {
+ return;
+ }
+ var temImages = temData.images;
+ //因为无法获取view宽度 需要自定义padding进行计算,稍后处理
+ var recal = wxAutoImageCal(e.detail.width, e.detail.height,that,bindName);
+ // temImages[idx].width = recal.imageWidth;
+ // temImages[idx].height = recal.imageheight;
+ // temData.images = temImages;
+ // var bindData = {};
+ // bindData[bindName] = temData;
+ // that.setData(bindData);
+ var index = temImages[idx].index
+ var key = `${bindName}`
+ for (var i of index.split('.')) key+=`.nodes[${i}]`
+ var keyW = key + '.width'
+ var keyH = key + '.height'
+ that.setData({
+ [keyW]: recal.imageWidth,
+ [keyH]: recal.imageheight,
+ })
+}
+
+// 计算视觉优先的图片宽高
+function wxAutoImageCal(originalWidth, originalHeight,that,bindName) {
+ //获取图片的原始长宽
+ var windowWidth = 0, windowHeight = 0;
+ var autoWidth = 0, autoHeight = 0;
+ var results = {};
+ var padding = that.data[bindName].view.imagePadding;
+ windowWidth = realWindowWidth-2*padding;
+ windowHeight = realWindowHeight;
+ //判断按照那种方式进行缩放
+ // console.log("windowWidth" + windowWidth);
+ if (originalWidth > windowWidth) {//在图片width大于手机屏幕width时候
+ autoWidth = windowWidth;
+ // console.log("autoWidth" + autoWidth);
+ autoHeight = (autoWidth * originalHeight) / originalWidth;
+ // console.log("autoHeight" + autoHeight);
+ results.imageWidth = autoWidth;
+ results.imageheight = autoHeight;
+ } else {//否则展示原来的数据
+ results.imageWidth = originalWidth;
+ results.imageheight = originalHeight;
+ }
+ return results;
+}
+
+function wxParseTemArray(temArrayName,bindNameReg,total,that){
+ var array = [];
+ var temData = that.data;
+ var obj = null;
+ for(var i = 0; i < total; i++){
+ var simArr = temData[bindNameReg+i].nodes;
+ array.push(simArr);
+ }
+
+ temArrayName = temArrayName || 'wxParseTemArray';
+ obj = JSON.parse('{"'+ temArrayName +'":""}');
+ obj[temArrayName] = array;
+ that.setData(obj);
+}
+
+/**
+ * 配置emojis
+ *
+ */
+
+function emojisInit(reg='',baseSrc="/wxParse/emojis/",emojis){
+ HtmlToJson.emojisInit(reg,baseSrc,emojis);
+}
+
+module.exports = {
+ wxParse: wxParse,
+ wxParseTemArray:wxParseTemArray,
+ emojisInit:emojisInit
+}
+
+
diff --git a/wxParse/wxParse.wxml b/wxParse/wxParse.wxml
new file mode 100644
index 0000000..00fa568
--- /dev/null
+++ b/wxParse/wxParse.wxml
@@ -0,0 +1,967 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.text}}
+
+
+
+
+
+
+
+
+ \n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/wxParse/wxParse.wxss b/wxParse/wxParse.wxss
new file mode 100644
index 0000000..05df7d2
--- /dev/null
+++ b/wxParse/wxParse.wxss
@@ -0,0 +1,207 @@
+
+/**
+ * author: Di (微信小程序开发工程师)
+ * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
+ * 垂直微信小程序开发交流社区
+ *
+ * github地址: https://github.com/icindy/wxParse
+ *
+ * for: 微信小程序富文本解析
+ * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
+ */
+
+.wxParse{
+ margin: 0 5px;
+ font-family: Helvetica,sans-serif;
+ font-size: 28rpx;
+ color: #666;
+ line-height: 1.8;
+}
+view{
+ word-break:break-all;
+ /* overflow:auto; */
+}
+.wxParse-inline{
+ display: inline;
+ margin: 0;
+ padding: 0;
+}
+/*//标题 */
+.wxParse-div{margin: 0;padding: 0;}
+.wxParse-h1{ font-size:2em; margin: .67em 0 }
+.wxParse-h2{ font-size:1.5em; margin: .75em 0 }
+.wxParse-h3{ font-size:1.17em; margin: .83em 0 }
+.wxParse-h4{ margin: 1.12em 0}
+.wxParse-h5 { font-size:.83em; margin: 1.5em 0 }
+.wxParse-h6{ font-size:.75em; margin: 1.67em 0 }
+
+.wxParse-h1 {
+ font-size: 18px;
+ font-weight: 400;
+ margin-bottom: .9em;
+}
+.wxParse-h2 {
+ font-size: 16px;
+ font-weight: 400;
+ margin-bottom: .34em;
+}
+.wxParse-h3 {
+ font-weight: 400;
+ font-size: 15px;
+ margin-bottom: .34em;
+}
+.wxParse-h4 {
+ font-weight: 400;
+ font-size: 14px;
+ margin-bottom: .24em;
+}
+.wxParse-h5 {
+ font-weight: 400;
+ font-size: 13px;
+ margin-bottom: .14em;
+}
+.wxParse-h6 {
+ font-weight: 400;
+ font-size: 12px;
+ margin-bottom: .04em;
+}
+
+.wxParse-h1, .wxParse-h2, .wxParse-h3, .wxParse-h4, .wxParse-h5, .wxParse-h6, .wxParse-b, .wxParse-strong { font-weight: bolder }
+
+.wxParse-i,.wxParse-cite,.wxParse-em,.wxParse-var,.wxParse-address{font-style:italic}
+.wxParse-pre,.wxParse-tt,.wxParse-code,.wxParse-kbd,.wxParse-samp{font-family:monospace}
+.wxParse-pre{white-space:pre}
+.wxParse-big{font-size:1.17em}
+.wxParse-small,.wxParse-sub,.wxParse-sup{font-size:.83em}
+.wxParse-sub{vertical-align:sub}
+.wxParse-sup{vertical-align:super}
+.wxParse-s,.wxParse-strike,.wxParse-del{text-decoration:line-through}
+/*wxparse-自定义个性化的css样式*/
+/*增加video的css样式*/
+.wxParse-strong,.wxParse-s{display: inline}
+.wxParse-a{
+ color: deepskyblue;
+ word-break:break-all;
+ overflow:auto;
+}
+
+.wxParse-video{
+ text-align: center;
+ margin: 10px 0;
+}
+
+.wxParse-video-video{
+ width:100%;
+}
+
+.wxParse-img{
+ /*background-color: #efefef;*/
+ overflow: hidden;
+}
+
+.wxParse-blockquote {
+ margin: 0;
+ padding:10px 0 10px 5px;
+ font-family:Courier, Calibri,"宋体";
+ background:#f5f5f5;
+ border-left: 3px solid #dbdbdb;
+}
+
+.wxParse-code,.wxParse-wxxxcode-style{
+ display: inline;
+ background:#f5f5f5;
+}
+.wxParse-ul{
+ margin: 20rpx 10rpx;
+}
+
+.wxParse-li,.wxParse-li-inner{
+ display: flex;
+ align-items: baseline;
+ margin: 10rpx 0;
+}
+.wxParse-li-text{
+
+ align-items: center;
+ line-height: 20px;
+}
+
+.wxParse-li-circle{
+ display: inline-flex;
+ width: 5px;
+ height: 5px;
+ background-color: #333;
+ margin-right: 5px;
+}
+
+.wxParse-li-square{
+ display: inline-flex;
+ width: 10rpx;
+ height: 10rpx;
+ background-color: #333;
+ margin-right: 5px;
+}
+.wxParse-li-ring{
+ display: inline-flex;
+ width: 10rpx;
+ height: 10rpx;
+ border: 2rpx solid #333;
+ border-radius: 50%;
+ background-color: #fff;
+ margin-right: 5px;
+}
+
+/*.wxParse-table{
+ width: 100%;
+ height: 400px;
+}
+.wxParse-thead,.wxParse-tfoot,.wxParse-tr{
+ display: flex;
+ flex-direction: row;
+}
+.wxParse-th,.wxParse-td{
+ display: flex;
+ width: 580px;
+ overflow: auto;
+}*/
+
+.wxParse-u {
+ text-decoration: underline;
+}
+.wxParse-hide{
+ display: none;
+}
+.WxEmojiView{
+ align-items: center;
+}
+.wxEmoji{
+ width: 16px;
+ height:16px;
+}
+.wxParse-tr{
+ display: flex;
+ border-right:1px solid #e0e0e0;
+ border-bottom:1px solid #e0e0e0;
+ border-top:1px solid #e0e0e0;
+}
+.wxParse-th,
+.wxParse-td{
+ flex:1;
+ padding:5px;
+ font-size:28rpx;
+ border-left:1px solid #e0e0e0;
+ word-break: break-all;
+}
+.wxParse-td:last{
+ border-top:1px solid #e0e0e0;
+}
+.wxParse-th{
+ background:#f0f0f0;
+ border-top:1px solid #e0e0e0;
+}
+.wxParse-del{
+ display: inline;
+}
+.wxParse-figure {
+ overflow: hidden;
+}