作者 Lijianheng

update

要显示太多修改。

为保证性能只显示 37 of 37+ 个文件。

@@ -75,14 +75,14 @@ App({ @@ -75,14 +75,14 @@ App({
75 // }) 75 // })
76 // } 76 // }
77 77
78 - else {  
79 - wx.showModal({  
80 - title: '提示',  
81 - content: res.data.msg,  
82 - showCancel: false  
83 - })  
84 - reject(res.data)  
85 - } 78 + // else {
  79 + // wx.showModal({
  80 + // title: '提示',
  81 + // content: res.data.msg,
  82 + // showCancel: false
  83 + // })
  84 + // reject(res.data)
  85 + // }
86 setTimeout(function () { 86 setTimeout(function () {
87 // if (show||show==undefined){ 87 // if (show||show==undefined){
88 // wx.hideLoading() 88 // wx.hideLoading()
@@ -8,6 +8,9 @@ Page({ @@ -8,6 +8,9 @@ Page({
8 data: { 8 data: {
9 industry: '', 9 industry: '',
10 categories_id: '', 10 categories_id: '',
  11 + jobs: '',
  12 + // 定义绑定跳转的id
  13 + id: '',
11 }, 14 },
12 15
13 /** 16 /**
@@ -19,9 +22,13 @@ Page({ @@ -19,9 +22,13 @@ Page({
19 }) 22 })
20 }, 23 },
21 24
22 - toPosition(){ 25 + toPosition(e){
  26 + console.log(e)
  27 + // 绑定id跳转至工作详情
  28 + let that = this;
  29 + let id = e.currentTarget.dataset.id;
23 wx.navigateTo({ 30 wx.navigateTo({
24 - url: '/pages/positionDetails/positionDetails', 31 + url: '/pages/positionDetails/positionDetails?id='+id,
25 }) 32 })
26 }, 33 },
27 // 跳转招聘者信息 34 // 跳转招聘者信息
@@ -32,42 +39,20 @@ Page({ @@ -32,42 +39,20 @@ Page({
32 }, 39 },
33 onLoad: function (options) { 40 onLoad: function (options) {
34 console.log(options) 41 console.log(options)
35 - 42 + //页面切换,更换页面标题
36 wx.setNavigationBarTitle({ 43 wx.setNavigationBarTitle({
37 - title: options.categories_name //页面切换,更换页面标题 44 + title: options.categories_name
38 }) 45 })
  46 + this.setData({
  47 + categories_id: options.categories_id
39 48
40 - this.getIndustry()  
41 - 49 + })
  50 + // 调用岗位功能参数
  51 + // this.getIndustry()
  52 + this.getJods()
42 53
43 }, 54 },
44 55
45 - // 岗位功能  
46 - getIndustry() {  
47 - let that = this;  
48 - let url = 'index/category/industry';  
49 -  
50 - let params = {  
51 - categories_id : that.data.categories_id,  
52 - }  
53 - let header = {  
54 - "XX-Token": wx.getStorageSync('token'),  
55 - "XX-Device-Type": 'wxapp'  
56 - }  
57 - app.post(url, params, header).then((res) => {  
58 - console.log(res);  
59 - // console.log(res.data)  
60 -  
61 - // 获取值  
62 - that.setData({  
63 - industry: res.data  
64 - })  
65 - // console.log(that.data.industry)  
66 -  
67 - }).catch((err) => {  
68 -  
69 - })  
70 - },  
71 // 获取多个工作 56 // 获取多个工作
72 getJods() { 57 getJods() {
73 let that = this; 58 let that = this;
@@ -86,7 +71,7 @@ Page({ @@ -86,7 +71,7 @@ Page({
86 71
87 // 获取值 72 // 获取值
88 that.setData({ 73 that.setData({
89 - industry: res.data 74 + jobs: res.data
90 }) 75 })
91 // console.log(that.data.industry) 76 // console.log(that.data.industry)
92 77
@@ -2,16 +2,16 @@ @@ -2,16 +2,16 @@
2 2
3 <!-- 条目 --> 3 <!-- 条目 -->
4 <view class='items'> 4 <view class='items'>
5 - <view class='item' bindtap='toPosition'> 5 + <view class='item' bindtap='toPosition' wx:for="{{jobs}}" wx:key="" data-id="{{item.id}}">
6 <!-- 头部 --> 6 <!-- 头部 -->
7 <view class='item_top'> 7 <view class='item_top'>
8 <view class='item_top_left'> 8 <view class='item_top_left'>
9 <view class='item_top_left_pic'> 9 <view class='item_top_left_pic'>
10 - <image src='/img/aicon_08@2x.png'></image> 10 + <image src='{{item.logo}}'></image>
11 </view> 11 </view>
12 <view class='item_top_left_text'> 12 <view class='item_top_left_text'>
13 - <view class='text_top'>酒店服务员</view>  
14 - <view class='text_bottom'>4000-5000元/月</view> 13 + <view class='text_top'>{{item.station_name}}</view>
  14 + <view class='text_bottom'>{{item.min_money}}-{{item.max_money}}{{item.unit_name}}</view>
15 </view> 15 </view>
16 </view> 16 </view>
17 17
@@ -26,7 +26,7 @@ @@ -26,7 +26,7 @@
26 <image src='/img/aicon_10@2x.png'></image> 26 <image src='/img/aicon_10@2x.png'></image>
27 </view> 27 </view>
28 <!-- 名字 --> 28 <!-- 名字 -->
29 - <view>王思迪</view> 29 + <view>{{item.resume_name}}</view>
30 </view> 30 </view>
31 31
32 <view class='item_bottom_right'> 32 <view class='item_bottom_right'>
1 // pages/employerDetails/employerDetails.js 1 // pages/employerDetails/employerDetails.js
  2 +const app = getApp();
2 Page({ 3 Page({
3 4
4 /** 5 /**
5 * 页面的初始数据 6 * 页面的初始数据
6 */ 7 */
7 data: { 8 data: {
8 - 9 + employer: '',
  10 + id: '',
  11 + user_id: '',
  12 + employerJ: '',
9 }, 13 },
10 14
11 /** 15 /**
@@ -24,8 +28,61 @@ Page({ @@ -24,8 +28,61 @@ Page({
24 }) 28 })
25 }, 29 },
26 onLoad: function (options) { 30 onLoad: function (options) {
  31 + console.log(options)
  32 + this.setData({
  33 + id: options.id,
  34 + user_id: options.user_id
  35 + })
  36 + this.employerDetails()
  37 + this.employerJobs()
  38 + },
27 39
  40 + employerDetails() {
  41 + let that = this;
  42 + let url = 'index/job/job';
  43 + let params = {
  44 + job_id: that.data.id,
  45 + user_id: that.data.id
  46 + }
  47 + let header = {
  48 + "XX-Token": wx.getStorageSync('token'),
  49 + "XX-Device-Type": 'wxapp'
  50 + }
  51 + app.post(url, params, header).then((res) => {
  52 + console.log(res);
  53 + // 获取值
  54 + that.setData({
  55 + employer: res.data
  56 + })
  57 +
  58 + }).catch((err) => {
  59 +
  60 + })
28 }, 61 },
  62 + // 获取多个工作
  63 + employerJobs() {
  64 + let that = this;
  65 + let url = 'index/job/jobs';
  66 + let params = {
  67 + job_id: that.data.id,
  68 + user_id: that.data.id
  69 + }
  70 + let header = {
  71 + "XX-Token": wx.getStorageSync('token'),
  72 + "XX-Device-Type": 'wxapp'
  73 + }
  74 + app.post(url, params, header).then((res) => {
  75 + console.log(res);
  76 + // 获取值
  77 + that.setData({
  78 + employerJ: res.data
  79 + })
  80 +
  81 + }).catch((err) => {
  82 +
  83 + })
  84 + },
  85 +
29 86
30 /** 87 /**
31 * 生命周期函数--监听页面初次渲染完成 88 * 生命周期函数--监听页面初次渲染完成
@@ -2,14 +2,14 @@ @@ -2,14 +2,14 @@
2 <view class='container'> 2 <view class='container'>
3 <view class='top'> 3 <view class='top'>
4 <view class='top_pic'> 4 <view class='top_pic'>
5 - <image src='../../img/aicon_18@2x.png'></image> 5 + <image src='{{employer.banner}}'></image>
6 </view> 6 </view>
7 <view class='top_text'> 7 <view class='top_text'>
8 <view class='top_text_left'> 8 <view class='top_text_left'>
9 - 王思迪 9 + {{employer.resume_name}}
10 </view> 10 </view>
11 <view class='top_text_right'> 11 <view class='top_text_right'>
12 - <image src='../../img/aicon_49@2x.png'></image> 12 + <image src='{{employer.logo}}'></image>
13 </view> 13 </view>
14 </view> 14 </view>
15 </view> 15 </view>
@@ -17,7 +17,7 @@ @@ -17,7 +17,7 @@
17 <!-- 地址 --> 17 <!-- 地址 -->
18 <view class='addr'> 18 <view class='addr'>
19 <view class='addr_left'> 19 <view class='addr_left'>
20 - 天津市滨海新天津滨海新区七大街万贸科技有限公司 20 + {{employer.work_address}}
21 </view> 21 </view>
22 <view class='addr_right'> 22 <view class='addr_right'>
23 <view class='addr_right_icon'> 23 <view class='addr_right_icon'>
@@ -33,16 +33,16 @@ @@ -33,16 +33,16 @@
33 相关岗位 33 相关岗位
34 </view> 34 </view>
35 35
36 - <view class='item' bindtap='toPosition'> 36 + <view class='item' bindtap='toPosition' wx:for='{{employerJ}}' wx:key=''>
37 <!-- 头部 --> 37 <!-- 头部 -->
38 <view class='item_top'> 38 <view class='item_top'>
39 <view class='item_top_left'> 39 <view class='item_top_left'>
40 <view class='item_top_left_pic'> 40 <view class='item_top_left_pic'>
41 - <image src='/img/aicon_08@2x.png'></image> 41 + <image src='{{item.logo}}'></image>
42 </view> 42 </view>
43 <view class='item_top_left_text'> 43 <view class='item_top_left_text'>
44 - <view class='text_top'>酒店服务员</view>  
45 - <view class='text_bottom'>4000-5000元/月</view> 44 + <view class='text_top'>{{item.station_name}}</view>
  45 + <view class='text_bottom'>{{item.min_money}}-{{item.max_money}}{{item.unit_id}}</view>
46 </view> 46 </view>
47 </view> 47 </view>
48 48
@@ -57,7 +57,7 @@ @@ -57,7 +57,7 @@
57 <image src='/img/aicon_10@2x.png'></image> 57 <image src='/img/aicon_10@2x.png'></image>
58 </view> 58 </view>
59 <!-- 名字 --> 59 <!-- 名字 -->
60 - <view>王思迪</view> 60 + <view>{{item.resume_name}}</view>
61 </view> 61 </view>
62 62
63 <view class='item_bottom_right' > 63 <view class='item_bottom_right' >
@@ -69,8 +69,8 @@ @@ -69,8 +69,8 @@
69 </view> 69 </view>
70 </view> 70 </view>
71 71
72 - <view class='item' bindtap='toPosition'>  
73 - <!-- 头部 --> 72 + <!-- <view class='item' bindtap='toPosition'>
  73 +
74 <view class='item_top'> 74 <view class='item_top'>
75 <view class='item_top_left'> 75 <view class='item_top_left'>
76 <view class='item_top_left_pic'> 76 <view class='item_top_left_pic'>
@@ -86,13 +86,13 @@ @@ -86,13 +86,13 @@
86 报名 86 报名
87 </view> 87 </view>
88 </view> 88 </view>
89 - <!-- 底部 --> 89 +
90 <view class='item_bottom'> 90 <view class='item_bottom'>
91 <view class='item_bottom_left' bindtap='toRecruiter'> 91 <view class='item_bottom_left' bindtap='toRecruiter'>
92 <view class='item_bottom_left_pic'> 92 <view class='item_bottom_left_pic'>
93 <image src='/img/aicon_10@2x.png'></image> 93 <image src='/img/aicon_10@2x.png'></image>
94 </view> 94 </view>
95 - <!-- 名字 --> 95 +
96 <view>王思迪</view> 96 <view>王思迪</view>
97 </view> 97 </view>
98 98
@@ -103,7 +103,8 @@ @@ -103,7 +103,8 @@
103 <view>南开区 3.2km</view> 103 <view>南开区 3.2km</view>
104 </view> 104 </view>
105 </view> 105 </view>
106 - </view> 106 + </view> -->
  107 +
107 </view> 108 </view>
108 109
109 <!-- 没有更多内容了 --> 110 <!-- 没有更多内容了 -->
@@ -46,6 +46,7 @@ page{ @@ -46,6 +46,7 @@ page{
46 .top_text_right image{ 46 .top_text_right image{
47 width: 100%; 47 width: 100%;
48 height: 100%; 48 height: 100%;
  49 + border-radius:2rpx;
49 } 50 }
50 .addr{ 51 .addr{
51 margin-top: 14rpx; 52 margin-top: 14rpx;
1 // pages/feedback/feedback.js 1 // pages/feedback/feedback.js
  2 +const app = getApp();
2 Page({ 3 Page({
3 4
4 /** 5 /**
5 * 页面的初始数据 6 * 页面的初始数据
6 */ 7 */
7 data: { 8 data: {
8 - 9 + content: '',
  10 +
9 }, 11 },
10 12
  13 +
11 /** 14 /**
12 * 生命周期函数--监听页面加载 15 * 生命周期函数--监听页面加载
13 */ 16 */
14 onLoad: function (options) { 17 onLoad: function (options) {
  18 + // this.getFeedback
15 19
16 }, 20 },
  21 + enterContent(e) {
  22 + console.log(e)
  23 + this.setData({
  24 + content: e.detail.value
  25 + })
  26 + },
  27 + sub_btn() {
  28 +
  29 + let that = this;
  30 + let content = that.data.content;
  31 + if (content == '') {
  32 + wx.showToast({
  33 + title: '请输入内容',
  34 + icon: 'none'
  35 + })
  36 + }
  37 + let url = 'index/share/submit_opinion';
  38 + let params = {
  39 + content : that.data.content,
  40 +
  41 + }
  42 + let header = {
  43 + "XX-Token": wx.getStorageSync('token'),
  44 + "XX-Device-Type": 'wxapp'
  45 + }
  46 +
  47 + app.post(url, params, header).then((res) => {
  48 + console.log(res);
  49 + wx.showToast({
  50 + title: '提交成功',
  51 + icon: 'none',
  52 + duration: 1500
  53 + })
  54 + // setTimeout(function(){
  55 + // wx.navigateTo({
  56 + // url: '/pages/mine/mine',
  57 + // })
  58 + // },1000)
  59 +
  60 + }).catch((err) => {
  61 +
  62 + })
  63 + },
17 64
18 /** 65 /**
19 * 生命周期函数--监听页面初次渲染完成 66 * 生命周期函数--监听页面初次渲染完成
1 { 1 {
2 "usingComponents": {}, 2 "usingComponents": {},
3 - "navigationBarTitleText": "主页" 3 + "navigationBarTitleText": "意见反馈"
4 } 4 }
1 1
2 <view class='container'> 2 <view class='container'>
3 <view class='top'> 3 <view class='top'>
4 - <textarea placeholder='请输入您的意见,我们会积极处理并改正的~'></textarea> 4 + <textarea bindinput='enterContent' placeholder='请输入您的意见,我们会积极处理并改正的~'></textarea>
5 <view class='text_num'>0/200</view> 5 <view class='text_num'>0/200</view>
6 </view> 6 </view>
7 7
8 - <view class='bottom'> 8 + <view class='bottom' bindtap='sub_btn' >
9 提交 9 提交
10 </view> 10 </view>
11 11
@@ -11,7 +11,6 @@ Page({ @@ -11,7 +11,6 @@ Page({
11 category: '', 11 category: '',
12 slide: '', 12 slide: '',
13 industry_id: '', 13 industry_id: '',
14 -  
15 city: '', 14 city: '',
16 // 数据筛选 15 // 数据筛选
17 city_1: '', 16 city_1: '',
@@ -20,14 +19,13 @@ Page({ @@ -20,14 +19,13 @@ Page({
20 education_1: '', 19 education_1: '',
21 salary_1: '', 20 salary_1: '',
22 categories_id:'', 21 categories_id:'',
23 - 22 + categories_name:'',
24 23
25 district:'', 24 district:'',
26 // 获取经纬度 25 // 获取经纬度
27 latitude: '', 26 latitude: '',
28 longitude: '', 27 longitude: '',
29 28
30 -  
31 imgUrls: [{ 29 imgUrls: [{
32 url: '/img/aicon_07@2x.png' 30 url: '/img/aicon_07@2x.png'
33 }, 31 },
@@ -228,10 +226,31 @@ Page({ @@ -228,10 +226,31 @@ Page({
228 this.getCategories() 226 this.getCategories()
229 this.getSlide() 227 this.getSlide()
230 this.selectIndustry() 228 this.selectIndustry()
231 - // this.selectStation()  
232 this.selectEducation() 229 this.selectEducation()
233 this.selectSalary() 230 this.selectSalary()
234 - // this.selectArea() 231 + this.getJobs()
  232 + },
  233 +
  234 + getJobs() {
  235 + let that = this;
  236 + let url = 'index/job/jobs';
  237 + let params = {
  238 + }
  239 + let header = {
  240 + "XX-Token": wx.getStorageSync('token'),
  241 + "XX-Device-Type": 'wxapp'
  242 + }
  243 + app.post(url, params, header).then((res) => {
  244 + console.log(res);
  245 + // 获取值
  246 + that.setData({
  247 + // personal: res.data
  248 + jobs: res.data
  249 + })
  250 +
  251 + }).catch((err) => {
  252 +
  253 + })
235 }, 254 },
236 255
237 // 在家可做 256 // 在家可做
@@ -239,9 +258,12 @@ Page({ @@ -239,9 +258,12 @@ Page({
239 console.log(e) 258 console.log(e)
240 let that = this; 259 let that = this;
241 let categories_name = e.currentTarget.dataset.cla 260 let categories_name = e.currentTarget.dataset.cla
242 - console.log(categories_name) 261 + let categories_id = e.currentTarget.dataset.id
  262 + console.log(categories_id)
  263 + console.log(that.categories_name)
243 wx.navigateTo({ 264 wx.navigateTo({
244 - url: '/pages/atHome/atHome?categories_name='+categories_name, 265 + url: '/pages/atHome/atHome?categories_name=' + categories_name + '&categories_id=' + categories_id,
  266 +
245 }) 267 })
246 268
247 }, 269 },
@@ -620,7 +642,6 @@ Page({ @@ -620,7 +642,6 @@ Page({
620 getCategories() { 642 getCategories() {
621 let that = this; 643 let that = this;
622 let url = 'index/category/categories'; 644 let url = 'index/category/categories';
623 - console.log(url)  
624 let params = { 645 let params = {
625 646
626 } 647 }
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <!-- 中部选择 --> 20 <!-- 中部选择 -->
21 <view class='mid' > 21 <view class='mid' >
22 22
23 - <view class='mid_list' bindtap='atHome' data-cla='{{item.categories_name}}' wx:for='{{category}}' wx:key=''> 23 + <view class='mid_list' bindtap='atHome' data-cla='{{item.categories_name}}' data-id='{{item.id}}' wx:for='{{category}}' wx:key=''>
24 <!-- 图片 --> 24 <!-- 图片 -->
25 <view class='mid_list_top'> 25 <view class='mid_list_top'>
26 <image src='{{item.thumbnail}}'></image> 26 <image src='{{item.thumbnail}}'></image>
1 // pages/inviteFriends/inviteFriends.js 1 // pages/inviteFriends/inviteFriends.js
  2 +const app = getApp();
2 Page({ 3 Page({
3 4
4 /** 5 /**
@@ -6,33 +7,165 @@ Page({ @@ -6,33 +7,165 @@ Page({
6 */ 7 */
7 data: { 8 data: {
8 navbar: [{ 9 navbar: [{
9 - name: '有效邀请(15人)' 10 + name: '有效邀请 '
10 }, 11 },
11 { 12 {
12 - name: '无效邀请(15人)' 13 + name: '无效邀请'
13 } 14 }
14 ], 15 ],
15 currentTab: 0, 16 currentTab: 0,
16 17
  18 + share_task: '',
  19 + user: '',
  20 + record: '',
  21 +
17 // 判断弹出层,初始值为false为关闭 22 // 判断弹出层,初始值为false为关闭
18 - show_apply:false 23 + show_apply:false,
  24 + type:1,
  25 + notype:2,
  26 + countnum:'',
  27 + nocountnum:''
19 }, 28 },
20 29
21 /** 30 /**
22 * 生命周期函数--监听页面加载 31 * 生命周期函数--监听页面加载
23 */ 32 */
24 33
25 -  
26 onLoad: function (options) { 34 onLoad: function (options) {
  35 + this.getShare(),
  36 + this.getSelect(),
  37 + this.nogetSelect()
  38 + },
  39 + getShare() {
  40 + let that = this;
  41 + let url = 'index/share/index';
  42 + let params = {
  43 +
  44 + }
  45 + let header = {
  46 + "XX-Token": wx.getStorageSync('token'),
  47 + "XX-Device-Type": 'wxapp'
  48 + }
  49 + app.post(url, params, header).then((res) => {
  50 + console.log(res);
  51 +
  52 + that.setData({
  53 + // share: res.data,
  54 + share_task: res.data.share_task,
  55 + user: res.data.user
  56 +
  57 + })
  58 + console.log(res.data.share_task)
  59 + // ****** 父文本编辑 ******
  60 + WxParse.wxParse('article', 'html', res.data.share_rule.content, that, 5)
  61 + // 获取值
  62 +
  63 +
  64 +
  65 +
  66 + }).catch((err) => {
  67 +
  68 + })
  69 + },
  70 + // 有效/无效邀请人
  71 + getSelect() {
  72 + let that = this;
  73 + let url = 'index/share/select_share';
  74 + let params = {
  75 + type:that.data.type
  76 + }
  77 + let header = {
  78 + "XX-Token": wx.getStorageSync('token'),
  79 + "XX-Device-Type": 'wxapp'
  80 + }
  81 + app.post(url, params, header).then((res) => {
  82 + console.log(res);
  83 + let newbav = that.data.navbar;
  84 + console.log(newbav)
  85 + for (let i=0;i<that.data.navbar.length;i++){
  86 + if(i==0){
  87 + that.data.navbar[i].name = '有效邀请' + res.data.count + '人'
  88 + }
  89 +
  90 + }
  91 +
  92 + console.log(that.data.navbar)
  93 +
  94 +
  95 + that.setData({
  96 + record: res.data.record,
  97 + // share_task: res.data.share_task,
  98 + // user: res.data.user
  99 +
  100 + })
  101 +
  102 + console.log(that.data.navbar)
  103 +
  104 + console.log(res.data.record)
  105 +
  106 + }).catch((err) => {
  107 +
  108 + })
  109 + },
  110 + nogetSelect() {
  111 + let that = this;
  112 + let url = 'index/share/select_share';
  113 + let params = {
  114 + type: that.data.notype
  115 + }
  116 + let header = {
  117 + "XX-Token": wx.getStorageSync('token'),
  118 + "XX-Device-Type": 'wxapp'
  119 + }
  120 + app.post(url, params, header).then((res) => {
  121 + console.log(res);
  122 + let newbav = that.data.navbar;
  123 + // for (var i = 0; i < newnav.length; i++) {
  124 + // newnav[0].name = '有效邀请' + res.count + '人'
  125 + // }
  126 + for (let i = 1; i < that.data.navbar.length; i++) {
  127 + if (i == 1) {
  128 + that.data.navbar[i].name = '无效邀请' + res.data.count + '人'
  129 + }
  130 +
  131 + }
27 132
  133 +
  134 + that.setData({
  135 + record: res.data.record,
  136 + // share_task: res.data.share_task,
  137 + // user: res.data.user
  138 +
  139 + })
  140 +
  141 + console.log(res.data.record)
  142 +
  143 + }).catch((err) => {
  144 +
  145 + })
28 }, 146 },
29 147
  148 +
30 navbarTap: function (e) { 149 navbarTap: function (e) {
31 150
32 let that = this; 151 let that = this;
  152 +
33 this.setData({ 153 this.setData({
34 currentTab: e.currentTarget.dataset.idx, 154 currentTab: e.currentTarget.dataset.idx,
  155 + // type: 'e.currentTarget.dataset.idx==0'?'1':'2',
35 }) 156 })
  157 + if (e.currentTarget.dataset.idx == 0){
  158 + this.setData({
  159 + type:1
  160 + })
  161 + this.getSelect()
  162 + }else{
  163 + this.setData({
  164 + type:2
  165 + })
  166 + this.getSelect()
  167 + }
  168 + console.log(that.data.type)
36 }, 169 },
37 170
38 // 点击显示提现申请 171 // 点击显示提现申请
@@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
4 <image src='../../img/aicon_56@2x.png'></image> 4 <image src='../../img/aicon_56@2x.png'></image>
5 <view class='top_t'> 5 <view class='top_t'>
6 <view class='top_t_text'>累计获得奖励金额(元)</view> 6 <view class='top_t_text'>累计获得奖励金额(元)</view>
7 - <view class='top_t_num'>252</view> 7 + <view class='top_t_num'>{{user.grand}}</view>
8 </view> 8 </view>
9 <view class='top_right'> 9 <view class='top_right'>
10 <view class='top_right_icon'> 10 <view class='top_right_icon'>
@@ -21,8 +21,8 @@ @@ -21,8 +21,8 @@
21 21
22 <view class='mid_content'> 22 <view class='mid_content'>
23 <view class='mid_content_top'>可提现金额(元)</view> 23 <view class='mid_content_top'>可提现金额(元)</view>
24 - <view class='mid_content_mid'>245</view>  
25 - <view class='mid_content_bottom'>已提现金额(元)<span class='fontSize'>130</span></view> 24 + <view class='mid_content_mid'>{{user.balance}}</view>
  25 + <view class='mid_content_bottom'>已提现金额(元)<span class='fontSize'>{{user.deposit}}</span></view>
26 </view> 26 </view>
27 <!-- 提现 --> 27 <!-- 提现 -->
28 <view class='mid_deposit' bindtap='open_apply'> 28 <view class='mid_deposit' bindtap='open_apply'>
@@ -48,24 +48,24 @@ @@ -48,24 +48,24 @@
48 <view class='invite_top_select '>无效邀请(15人)</view> 48 <view class='invite_top_select '>无效邀请(15人)</view>
49 49
50 </view> --> 50 </view> -->
51 - <!-- 列表1 --> 51 + <!-- 有效邀请 -->
52 <view class='invite_box' wx:if="{{currentTab==0}}"> 52 <view class='invite_box' wx:if="{{currentTab==0}}">
53 - <view class='invite_item'> 53 + <view class='invite_item' wx:for="{{record}}" wx:key="">
54 <view class='invite_item_left'> 54 <view class='invite_item_left'>
55 <view class='invite_item_left_icon'> 55 <view class='invite_item_left_icon'>
56 - <image src='../../img/aicon_49@2x.png'></image> 56 + <image src='{{item.avatar}}'></image>
57 </view> 57 </view>
58 <view class='invite_item_left_text'> 58 <view class='invite_item_left_text'>
59 - 宇宙无敌小可爱 59 + {{item.user_nickname}}
60 </view> 60 </view>
61 </view> 61 </view>
62 62
63 <view class='invite_item_right'> 63 <view class='invite_item_right'>
64 - 已报名2 64 + 已报名{{item.count}}
65 </view> 65 </view>
66 </view> 66 </view>
67 67
68 - <view class='invite_item'> 68 + <!-- <view class='invite_item'>
69 <view class='invite_item_left'> 69 <view class='invite_item_left'>
70 <view class='invite_item_left_icon'> 70 <view class='invite_item_left_icon'>
71 <image src='../../img/aicon_49@2x.png'></image> 71 <image src='../../img/aicon_49@2x.png'></image>
@@ -78,27 +78,27 @@ @@ -78,27 +78,27 @@
78 <view class='invite_item_right'> 78 <view class='invite_item_right'>
79 已报名2次 79 已报名2次
80 </view> 80 </view>
81 - </view> 81 + </view> -->
82 </view> 82 </view>
83 83
84 - <!-- 列表2 --> 84 + <!-- 无效邀请 -->
85 <view class='invite_box' wx:if="{{currentTab==1}}"> 85 <view class='invite_box' wx:if="{{currentTab==1}}">
86 - <view class='invite_item'> 86 + <view class='invite_item' wx:for="{{record}}" wx:key="">
87 <view class='invite_item_left'> 87 <view class='invite_item_left'>
88 <view class='invite_item_left_icon'> 88 <view class='invite_item_left_icon'>
89 - <image src='../../img/aicon_49@2x.png'></image> 89 + <image src='{{item.avatar}}'></image>
90 </view> 90 </view>
91 <view class='invite_item_left_text'> 91 <view class='invite_item_left_text'>
92 - 宇宙无敌小可爱 92 + {{item.user_nickname}}
93 </view> 93 </view>
94 </view> 94 </view>
95 95
96 <view class='invite_item_right'> 96 <view class='invite_item_right'>
97 - 已报名2 97 + 已报名{{item.count}}
98 </view> 98 </view>
99 </view> 99 </view>
100 100
101 - <view class='invite_item'> 101 + <!-- <view class='invite_item'>
102 <view class='invite_item_left'> 102 <view class='invite_item_left'>
103 <view class='invite_item_left_icon'> 103 <view class='invite_item_left_icon'>
104 <image src='../../img/aicon_49@2x.png'></image> 104 <image src='../../img/aicon_49@2x.png'></image>
@@ -111,22 +111,9 @@ @@ -111,22 +111,9 @@
111 <view class='invite_item_right'> 111 <view class='invite_item_right'>
112 已报名2次 112 已报名2次
113 </view> 113 </view>
114 - </view> 114 + </view> -->
115 115
116 - <view class='invite_item'>  
117 - <view class='invite_item_left'>  
118 - <view class='invite_item_left_icon'>  
119 - <image src='../../img/aicon_49@2x.png'></image>  
120 - </view>  
121 - <view class='invite_item_left_text'>  
122 - 宇宙无敌小可爱  
123 - </view>  
124 - </view>  
125 -  
126 - <view class='invite_item_right'>  
127 - 已报名2次  
128 - </view>  
129 - </view> 116 +
130 </view> 117 </view>
131 118
132 119
@@ -183,6 +183,7 @@ page{ @@ -183,6 +183,7 @@ page{
183 position: absolute; 183 position: absolute;
184 bottom: -32rpx; 184 bottom: -32rpx;
185 left: -60rpx; 185 left: -60rpx;
  186 + /* right: 60rpx; */
186 width: 330rpx; 187 width: 330rpx;
187 height: 1px; 188 height: 1px;
188 background: #FFAA00; 189 background: #FFAA00;
@@ -152,6 +152,18 @@ @@ -152,6 +152,18 @@
152 </view> 152 </view>
153 </view> 153 </view>
154 154
  155 + <view class='item_mid_i' bindtap='toRecommend'>
  156 + <!-- <view class='item_mid_i_top service'>
  157 + <image src='../../img/aicon_46@2x.png'></image>
  158 + </view> -->
  159 + <view class='item_mid_i_pic'>
  160 + <image src='../../img/aicon_46@2x.png'></image>
  161 + </view>
  162 + <!-- <view class='item_mid_i_text'>
  163 + 在线客服
  164 + </view> -->
  165 + </view>
  166 +
155 167
156 </view> 168 </view>
157 </view> 169 </view>
@@ -475,3 +475,13 @@ page{ @@ -475,3 +475,13 @@ page{
475 box-sizing: border-box; 475 box-sizing: border-box;
476 padding: 0 24rpx 10rpx 20rpx; 476 padding: 0 24rpx 10rpx 20rpx;
477 } 477 }
  478 +.item_mid_i_pic{
  479 + margin-left: 70rpx;
  480 + width:150rpx;
  481 + height:150rpx;
  482 + border-radius:50%;
  483 +}
  484 +.item_mid_i_pic image{
  485 + width: 100%;
  486 + height: 100%;
  487 +}
1 // pages/myMessage/myMessage.js 1 // pages/myMessage/myMessage.js
  2 +const app = getApp();
2 Page({ 3 Page({
3 4
4 /** 5 /**
5 * 页面的初始数据 6 * 页面的初始数据
6 */ 7 */
7 data: { 8 data: {
8 - 9 + myMessage: '',
9 }, 10 },
10 11
11 /** 12 /**
@@ -13,13 +14,40 @@ Page({ @@ -13,13 +14,40 @@ Page({
13 */ 14 */
14 15
15 // 消息通知 16 // 消息通知
16 - myMessage2(){ 17 + toMyMessage2(e){
  18 + console.log(e)
  19 + // 定义接收到的id
  20 + let id = e.currentTarget.dataset.id
17 wx.navigateTo({ 21 wx.navigateTo({
18 - url: '/pages/myMessage2/myMessage2', 22 + // 传递id至myMessage2
  23 + url: '/pages/myMessage2/myMessage2?id=' + id,
19 }) 24 })
20 }, 25 },
21 onLoad: function (options) { 26 onLoad: function (options) {
  27 + this.getMyMessage()
  28 + },
  29 +
  30 + getMyMessage() {
  31 +
  32 + let that = this;
  33 + let url = 'index/information/get_all';
  34 + let params = {
22 35
  36 + }
  37 + let header = {
  38 + "XX-Token": wx.getStorageSync('token'),
  39 + "XX-Device-Type": 'wxapp'
  40 + }
  41 + app.post(url, params, header).then((res) => {
  42 + console.log(res);
  43 + // 获取值
  44 + that.setData({
  45 + myMessage: res.data
  46 + })
  47 +
  48 + }).catch((err) => {
  49 +
  50 + })
23 }, 51 },
24 52
25 /** 53 /**
@@ -48,4 +48,25 @@ @@ -48,4 +48,25 @@
48 <image src='../../img/right.png'></image> 48 <image src='../../img/right.png'></image>
49 </view> 49 </view>
50 </view> 50 </view>
51 -</view> 51 +
  52 +
  53 +
  54 +
  55 + <view>
  56 + <view class='item' bindtap='toMyMessage2' wx:for='{{myMessage}}' data-id="{{item.id}}" wx:key='' >
  57 + <view class='item_left '>
  58 + <view class='item_left_pic '>
  59 + <image src='../../img/aicon_48@2x.png '></image>
  60 + </view>
  61 + <view class='item_left_text '>
  62 + <view class='item_left_text_top '>{{item.title}}</view>
  63 + <view class='item_left_text_bottom '>{{item.content}}</view>
  64 + </view>
  65 + </view>
  66 +
  67 + <view class='item_right '>
  68 + <image src='../../img/right.png '></image>
  69 + </view>
  70 + </view>
  71 + </view>
  72 +</view>
1 // pages/myMessage2/myMessage2.js 1 // pages/myMessage2/myMessage2.js
  2 +const app = getApp();
  3 +
2 Page({ 4 Page({
3 5
4 /** 6 /**
5 * 页面的初始数据 7 * 页面的初始数据
6 */ 8 */
7 data: { 9 data: {
8 - 10 + id: '',
  11 + myMessage2:'',
9 }, 12 },
10 13
11 /** 14 /**
12 * 生命周期函数--监听页面加载 15 * 生命周期函数--监听页面加载
13 */ 16 */
14 onLoad: function (options) { 17 onLoad: function (options) {
  18 + console.log(options)
  19 + this.setData({
  20 + id: options.id
  21 + })
  22 + this.getMyMessage2()
  23 + },
  24 +
  25 + getMyMessage2() {
  26 + let that = this;
  27 + let url = 'index/information/get_one';
  28 + let params = {
  29 + id: that.data.id
  30 + }
  31 + let header = {
  32 + "XX-Token": wx.getStorageSync('token'),
  33 + "XX-Device-Type": 'wxapp'
  34 + }
  35 + app.post(url, params, header).then((res) => {
  36 + console.log(res);
  37 + // 获取值
  38 + that.setData({
  39 + myMessage2: res.data
  40 + })
  41 +
  42 +
  43 +
  44 +
  45 +
  46 +
  47 + }).catch((err) => {
15 48
  49 + })
16 }, 50 },
17 51
18 /** 52 /**
1 1
2 <view class='container'> 2 <view class='container'>
3 <view class='time'> 3 <view class='time'>
4 - 2019-02-28 11:23 4 + <!-- 2019-02-28 11:23 -->
  5 + {{myMessage2.create_time}}
5 </view> 6 </view>
6 7
7 <view class='content'> 8 <view class='content'>
8 - 怎么查微信聊天记录已经成为调查行业的另一项重要业务 当今全世界最流行的聊天工具之一微信,自从2011年面世。怎么查微信聊天记录已经成为调查行业的另一项重要业务 当今全世界最流行的聊天工具之一微信。  
9 -2011年面世。 9 + <!-- 怎么查微信聊天记录已经成为调查行业的另一项重要业务 当今全世界最流行的聊天工具之一微信,自从2011年面世。怎么查微信聊天记录已经成为调查行业的另一项重要业务 当今全世界最流行的聊天工具之一微信。
  10 +2011年面世。 -->
  11 +
  12 + {{myMessage2.title}}
10 13
11 </view> 14 </view>
12 15
@@ -5,6 +5,7 @@ Page({ @@ -5,6 +5,7 @@ Page({
5 * 页面的初始数据 5 * 页面的初始数据
6 */ 6 */
7 data: { 7 data: {
  8 + images: '',
8 date: '2016-09-01', 9 date: '2016-09-01',
9 10
10 educationArray: ['不限','小学及以下', '初中', '高中', '中专/技校','大专','本科','硕士','博士'], 11 educationArray: ['不限','小学及以下', '初中', '高中', '中专/技校','大专','本科','硕士','博士'],
@@ -77,6 +78,36 @@ Page({ @@ -77,6 +78,36 @@ Page({
77 78
78 }, 79 },
79 80
  81 + // 选择图片
  82 + chooseImage: function () {
  83 + // 选择图片
  84 + wx.chooseImage({
  85 + count: 3, // 默认9
  86 + sizeType: ['compressed'],
  87 + sourceType: ['album', 'camera'],
  88 + // 可以指定来源是相册还是相机,默认二者都有
  89 + success: function (res) {
  90 + console.log(res)
  91 + // 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片
  92 + var tempFilePaths = res.tempFilePaths;
  93 + that.setData({
  94 + images: that.data.image.concat(tempFilePaths)
  95 + })
  96 + console.log(images)
  97 + // if (that.data.companyortrue == true) {
  98 + // that.setData({
  99 + // companyimages: that.data.companyimages.concat(tempFilePaths)
  100 + // });
  101 + // } else {
  102 + // that.setData({
  103 + // images: that.data.images.concat(tempFilePaths)
  104 + // });
  105 + // }
  106 +
  107 + }
  108 + })
  109 + },
  110 +
80 /** 111 /**
81 * 生命周期函数--监听页面初次渲染完成 112 * 生命周期函数--监听页面初次渲染完成
82 */ 113 */
1 { 1 {
2 "usingComponents": {}, 2 "usingComponents": {},
3 - "navigationBarTitleText": "报名记录" 3 + "navigationBarTitleText": "发布简历"
4 } 4 }
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 <view class='top'> 5 <view class='top'>
6 <view class='top_left'>头像</view> 6 <view class='top_left'>头像</view>
7 <view class='top_right'> 7 <view class='top_right'>
8 - <view class='top_right_pic'> 8 + <view class='top_right_pic' bindtap='chooseImage'>
9 <image src='../../img/aicon_49@2x.png'></image> 9 <image src='../../img/aicon_49@2x.png'></image>
10 </view> 10 </view>
11 <view class='top_right_icon'> 11 <view class='top_right_icon'>
@@ -6,14 +6,41 @@ Page({ @@ -6,14 +6,41 @@ Page({
6 * 页面的初始数据 6 * 页面的初始数据
7 */ 7 */
8 data: { 8 data: {
9 -  
10 - }, 9 + images:'',
  10 + resume2:'',
  11 + },
11 12
12 /** 13 /**
13 * 生命周期函数--监听页面加载 14 * 生命周期函数--监听页面加载
14 */ 15 */
15 onLoad: function (options) { 16 onLoad: function (options) {
16 - that.getResume2() 17 + this.getResume2()
  18 + },
  19 +
  20 + // 选择图片
  21 + chooseImage: function () {
  22 + // 选择图片
  23 + wx.chooseImage({
  24 + count: 3, // 默认9
  25 + sizeType: ['compressed'],
  26 + sourceType: ['album', 'camera'],
  27 + // 可以指定来源是相册还是相机,默认二者都有
  28 + success: function (res) {
  29 + console.log(res)
  30 + // 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片
  31 + var tempFilePaths = res.tempFilePaths;
  32 + // if (that.data.companyortrue == true) {
  33 + // that.setData({
  34 + // companyimages: that.data.companyimages.concat(tempFilePaths)
  35 + // });
  36 + // } else {
  37 + that.setData({
  38 + images: that.data.images.concat(tempFilePaths)
  39 + });
  40 + // }
  41 +
  42 + }
  43 + })
17 }, 44 },
18 45
19 getResume2() { 46 getResume2() {
@@ -31,7 +58,7 @@ Page({ @@ -31,7 +58,7 @@ Page({
31 console.log(res); 58 console.log(res);
32 // 获取值 59 // 获取值
33 that.setData({ 60 that.setData({
34 - personal: res.data 61 + resume2: res.data
35 }) 62 })
36 63
37 64
@@ -6,9 +6,12 @@ @@ -6,9 +6,12 @@
6 <view class='top'> 6 <view class='top'>
7 <view class='top_left'>头像</view> 7 <view class='top_left'>头像</view>
8 <view class='top_right'> 8 <view class='top_right'>
9 - <view class='top_right_pic'>  
10 - <image src='../../img/aicon_49@2x.png'></image> 9 + <view class='top_right_pic' bindtap='chooseImage'>
  10 + <image src='{{resume2.avatar}}'></image>
11 </view> 11 </view>
  12 +
  13 +
  14 + <!-- 右边图片 -->
12 <view class='top_right_icon'> 15 <view class='top_right_icon'>
13 <image src='../../img/right.png'></image> 16 <image src='../../img/right.png'></image>
14 </view> 17 </view>
@@ -21,73 +24,73 @@ @@ -21,73 +24,73 @@
21 <view class='top mid'> 24 <view class='top mid'>
22 <view class='top_left'>昵称</view> 25 <view class='top_left'>昵称</view>
23 <view class='top_right wechat_name'> 26 <view class='top_right wechat_name'>
24 - 微信昵称 27 + {{resume2.user_nickname}}
25 </view> 28 </view>
26 </view> 29 </view>
27 <!-- 真实姓名 --> 30 <!-- 真实姓名 -->
28 <view class='top mid'> 31 <view class='top mid'>
29 <view class='top_left'>真实姓名</view> 32 <view class='top_left'>真实姓名</view>
30 <view class='top_right wechat_name'> 33 <view class='top_right wechat_name'>
31 - 高萌 34 + {{resume2.resume_name}}
32 </view> 35 </view>
33 </view> 36 </view>
34 <!-- 性别 --> 37 <!-- 性别 -->
35 <view class='top mid'> 38 <view class='top mid'>
36 <view class='top_left'>性别</view> 39 <view class='top_left'>性别</view>
37 <view class='top_right wechat_name'> 40 <view class='top_right wechat_name'>
38 - 41 + {{resume2.resume_sex}}
39 </view> 42 </view>
40 </view> 43 </view>
41 <!-- 手机号 --> 44 <!-- 手机号 -->
42 <view class='top mid'> 45 <view class='top mid'>
43 <view class='top_left'>手机号</view> 46 <view class='top_left'>手机号</view>
44 <view class='top_right wechat_name'> 47 <view class='top_right wechat_name'>
45 - 13987654321 48 + {{resume2.resume_mobile}}
46 </view> 49 </view>
47 </view> 50 </view>
48 <!-- 出生日期 --> 51 <!-- 出生日期 -->
49 <view class='top mid'> 52 <view class='top mid'>
50 <view class='top_left'>出生日期</view> 53 <view class='top_left'>出生日期</view>
51 <view class='top_right wechat_name'> 54 <view class='top_right wechat_name'>
52 - 1997-12-07 55 + {{resume2.resume_birthday}}
53 </view> 56 </view>
54 </view> 57 </view>
55 <!-- 家乡 --> 58 <!-- 家乡 -->
56 <view class='top mid'> 59 <view class='top mid'>
57 <view class='top_left'>家乡</view> 60 <view class='top_left'>家乡</view>
58 <view class='top_right wechat_name'> 61 <view class='top_right wechat_name'>
59 - 天津 62 + {{resume2.resume_home}}
60 </view> 63 </view>
61 </view> 64 </view>
62 <!-- 最高学历 --> 65 <!-- 最高学历 -->
63 <view class='top mid'> 66 <view class='top mid'>
64 <view class='top_left'>最高学历</view> 67 <view class='top_left'>最高学历</view>
65 <view class='top_right wechat_name'> 68 <view class='top_right wechat_name'>
66 - 本科 69 + {{resume2.education_name}}
67 </view> 70 </view>
68 </view> 71 </view>
69 <!-- 工作年限 --> 72 <!-- 工作年限 -->
70 <view class='top mid'> 73 <view class='top mid'>
71 <view class='top_left'>工作年限</view> 74 <view class='top_left'>工作年限</view>
72 <view class='top_right wechat_name'> 75 <view class='top_right wechat_name'>
73 - 10年以上 76 + {{resume2.resume_exp}}
74 </view> 77 </view>
75 </view> 78 </view>
76 <!-- 是否在职 --> 79 <!-- 是否在职 -->
77 <view class='top mid'> 80 <view class='top mid'>
78 <view class='top_left'>是否在职</view> 81 <view class='top_left'>是否在职</view>
79 <view class='top_right wechat_name'> 82 <view class='top_right wechat_name'>
80 - 离职 83 + {{resume2.resume_is_bejob}}
81 </view> 84 </view>
82 </view> 85 </view>
83 <!--岗位描述 --> 86 <!--岗位描述 -->
84 <view class='top mid describe'> 87 <view class='top mid describe'>
85 <view class='mid_top'> 88 <view class='mid_top'>
86 - <view class='top_left'>岗位描述</view> 89 + <view class='top_left'>个人简介</view>
87 <view class='top_right wechat_name'></view> 90 <view class='top_right wechat_name'></view>
88 </view> 91 </view>
89 <view class='mid_bottom'> 92 <view class='mid_bottom'>
90 - 本人风流倜傥英俊潇洒,为人幽默,善于解决客户问题 93 + {{resume2.resume_brief}}
91 </view> 94 </view>
92 </view> 95 </view>
93 96
1 // pages/positionDetails/positionDetails.js 1 // pages/positionDetails/positionDetails.js
  2 +const app = getApp()
2 Page({ 3 Page({
3 -  
4 /** 4 /**
5 * 页面的初始数据 5 * 页面的初始数据
6 */ 6 */
7 data: { 7 data: {
8 - share:false 8 + share:false,
  9 + latitude: 23.099994,
  10 + longitude: 113.324520,
  11 + job_id: '',
  12 + position: '',
  13 + id: '',
  14 + user_id: '',
  15 + // zpId: '',
9 }, 16 },
10 -  
11 /** 17 /**
12 * 生命周期函数--监听页面加载 18 * 生命周期函数--监听页面加载
13 */ 19 */
@@ -24,21 +30,119 @@ Page({ @@ -24,21 +30,119 @@ Page({
24 share:false 30 share:false
25 }) 31 })
26 }, 32 },
27 - // 跳转招聘者信息  
28 - toRecruiter(){  
29 - wx.navigateTo({  
30 - url: '/pages/employerDetails/employerDetails', 33 +
  34 + onLoad: function (options) {
  35 + console.log(options)
  36 +
  37 + this.setData({
  38 + job_id:options.id
31 }) 39 })
  40 + console.log(options.id)
  41 + this.positionDetails()
32 }, 42 },
33 - onLoad: function (options) {  
34 43
  44 + positionDetails() {
  45 + let that = this;
  46 + let url = 'index/job/job';
  47 + let params = {
  48 + job_id: that.data.job_id
  49 + }
  50 + let header = {
  51 + "XX-Token": wx.getStorageSync('token'),
  52 + "XX-Device-Type": 'wxapp'
  53 + }
  54 + app.post(url, params, header).then((res) => {
  55 + console.log(res);
  56 + // 获取值
  57 + that.setData({
  58 + position: res.data
  59 + })
  60 +
  61 + }).catch((err) => {
  62 +
  63 + })
  64 + },
  65 +
  66 + // 跳转招聘者信息
  67 + toRecruiter(e) {
  68 + console.log(e)
  69 + let id = e.currentTarget.dataset.id
  70 + let user_id = e.currentTarget.dataset.user_id
  71 + console.log()
  72 + wx.navigateTo({
  73 + url: '/pages/employerDetails/employerDetails?id=' + id + '&user_id=' + user_id,
  74 + })
  75 + },
  76 +
  77 + // 打开地图
  78 + openMap:function(){
  79 + var that = this;
  80 + // 获取当前位置
  81 + wx.getLocation({
  82 + type: 'gcj02',
  83 + success: function(res) {
  84 + console.log(res)
  85 + var latitude = res.latitude
  86 + var longitude = res.longitude
  87 + var speed = res.speed
  88 + var accuracy = res.accuracy
  89 + },
  90 + })
  91 + wx.chooseLocation({
  92 + success: function(res) {
  93 + console.log(res)
  94 + var latitude = res.latitude
  95 + var longitude = res.longitude
  96 + var speed = res.longitude
  97 + var accuracy = res.longitude
  98 + that.setData({latitude: latitude})
  99 + that.setData({longitude: longitude})
  100 + },
  101 + })
35 }, 102 },
36 103
37 /** 104 /**
38 * 生命周期函数--监听页面初次渲染完成 105 * 生命周期函数--监听页面初次渲染完成
39 */ 106 */
40 - onReady: function () {  
41 - 107 + onReady: function (e) {
  108 + this.mapCtx = wx.createMapContext('myapp')
  109 + },
  110 + getCenterLocation: function () {
  111 + this.mapCtx.getCenterLocation({
  112 + success: function (res) {
  113 + console.log(res.longitude)
  114 + console.log(res.latitude)
  115 + }
  116 + })
  117 + },
  118 + moveToLocation: function () {
  119 + this.mapCtx.moveToLocation()
  120 + },
  121 + translateMarker: function () {
  122 + this.mapCtx.translateMarker({
  123 + markerId: 1,
  124 + autoRotate: true,
  125 + duration: 1000,
  126 + destination: {
  127 + latitude: 23.10229,
  128 + longitude: 113.3345211,
  129 + },
  130 + animationEnd() {
  131 + console.log('animation end')
  132 + }
  133 + })
  134 + },
  135 + includePoints: function () {
  136 + this.mapCtx.includePoints({
  137 + padding: [10],
  138 + points: [{
  139 + latitude: 23.10229,
  140 + longitude: 113.3345211,
  141 + }, {
  142 + latitude: 23.00229,
  143 + longitude: 113.3345211,
  144 + }]
  145 + })
42 }, 146 },
43 147
44 /** 148 /**
1 -  
2 <view class='container'> 1 <view class='container'>
3 <view class='top'> 2 <view class='top'>
4 <view class='top_pic'> 3 <view class='top_pic'>
@@ -7,36 +6,41 @@ @@ -7,36 +6,41 @@
7 <view class='text_box'> 6 <view class='text_box'>
8 <!-- 文字 --> 7 <!-- 文字 -->
9 <view class='top_text'> 8 <view class='top_text'>
10 - 吉野家韩式烤肉服务员 9 + {{position.station_name}}
11 </view> 10 </view>
12 <!-- 工资 --> 11 <!-- 工资 -->
13 <view class='top_money'> 12 <view class='top_money'>
14 - 4000-5000元/月 13 + {{position.min_money}}-{{position.max_money}}{{position.unit_name}}
15 </view> 14 </view>
16 </view> 15 </view>
17 </view> 16 </view>
18 <!-- 招聘要求 --> 17 <!-- 招聘要求 -->
19 <view class='item'> 18 <view class='item'>
20 <view class='item_top'>招聘要求</view> 19 <view class='item_top'>招聘要求</view>
21 - <view class='item_bottom'>性别不限/年龄不限/学历不限/经验不限</view> 20 + <view class='item_bottom'>{{position.demand}}</view>
22 </view> 21 </view>
23 <!-- 工作地点 --> 22 <!-- 工作地点 -->
24 <view class='item'> 23 <view class='item'>
25 <view class='item_top'>工作地点</view> 24 <view class='item_top'>工作地点</view>
26 - <view class='item_map'>  
27 - <image src='../../img/aicon_18@2x.png'></image> 25 + <view class='item_map' >
  26 + <map id="myMap"
  27 + latitude="{{latitude}}"
  28 + longitude="{{longitude}}"
  29 + markers="{{markers}}"
  30 + covers="{{covers}}"
  31 + show-location></map>
28 </view> 32 </view>
29 </view> 33 </view>
30 <!-- 招聘者信息 --> 34 <!-- 招聘者信息 -->
31 <view class='item'> 35 <view class='item'>
32 <view class='item_top'>招聘者信息</view> 36 <view class='item_top'>招聘者信息</view>
33 - <view class='item_infor' bindtap='toRecruiter'> 37 + <view class='item_infor' bindtap='toRecruiter' data-id='{{position.id}}' data-user_id='{{position.user_id}}'>
34 <view class='item_infor_left'> 38 <view class='item_infor_left'>
35 <image src='../../img/aicon_18@2x.png'></image> 39 <image src='../../img/aicon_18@2x.png'></image>
36 </view> 40 </view>
37 <view class='item_infor_right'> 41 <view class='item_infor_right'>
38 - <view class='item_infor_right_top'>四川海底捞餐饮股份有限公司</view>  
39 - <view class='item_infor_right_bottom'>2个岗位在招</view> 42 + <view class='item_infor_right_top'>{{position.resume_name}}</view>
  43 + <view class='item_infor_right_bottom'>{{position.also_some}}个岗位在招</view>
40 </view> 44 </view>
41 </view> 45 </view>
42 </view> 46 </view>
@@ -69,7 +69,7 @@ page{ @@ -69,7 +69,7 @@ page{
69 height:300rpx; 69 height:300rpx;
70 display: flex; 70 display: flex;
71 } 71 }
72 -.item_map image{ 72 +.item_map map{
73 width: 100%; 73 width: 100%;
74 height: 100%; 74 height: 100%;
75 } 75 }
@@ -186,7 +186,7 @@ @@ -186,7 +186,7 @@
186 <!-- 选工作地点 --> 186 <!-- 选工作地点 -->
187 <view class='item map'> 187 <view class='item map'>
188 <view class='map_item'> 188 <view class='map_item'>
189 - <view class='item_left'>选择行业</view> 189 + <view class='item_left'>选择地区</view>
190 <view class='item_right'> 190 <view class='item_right'>
191 <view class='item_right_text'>天津西青区银河百荣科技</view> 191 <view class='item_right_text'>天津西青区银河百荣科技</view>
192 <view class='item_right_icon'> 192 <view class='item_right_icon'>
@@ -194,9 +194,9 @@ @@ -194,9 +194,9 @@
194 </view> 194 </view>
195 </view> 195 </view>
196 </view> 196 </view>
197 - <view class='map_pic'>  
198 - <image src='../../img/aicon_31@2x.png'></image>  
199 - </view> 197 + <map class='map_pic'>
  198 + <!-- <image src='../../img/aicon_31@2x.png'></image> -->
  199 + </map>
200 </view> 200 </view>
201 <!-- 应聘联系方式 --> 201 <!-- 应聘联系方式 -->
202 <view class='employ'> 202 <view class='employ'>
1 // pages/recommend/recommend.js 1 // pages/recommend/recommend.js
  2 +const app = getApp();
  3 +var WxParse = require('../../wxParse/wxParse.js');
  4 +
2 Page({ 5 Page({
3 6
4 /** 7 /**
5 * 页面的初始数据 8 * 页面的初始数据
6 */ 9 */
7 data: { 10 data: {
8 - 11 + share: '',
  12 + share_task: '',
  13 + user: '',
  14 + // share_rule:'',
9 }, 15 },
10 16
11 /** 17 /**
@@ -18,7 +24,39 @@ Page({ @@ -18,7 +24,39 @@ Page({
18 }) 24 })
19 }, 25 },
20 onLoad: function (options) { 26 onLoad: function (options) {
  27 + this.getShare()
  28 + },
21 29
  30 + getShare() {
  31 + let that = this;
  32 + let url = 'index/share/index';
  33 + let params = {
  34 +
  35 + }
  36 + let header = {
  37 + "XX-Token": wx.getStorageSync('token'),
  38 + "XX-Device-Type": 'wxapp'
  39 + }
  40 + app.post(url, params, header).then((res) => {
  41 + console.log(res);
  42 +
  43 + that.setData({
  44 + share: res.data,
  45 + share_task:res.data.share_task,
  46 + user: res.data.user
  47 +
  48 + })
  49 + console.log(res.data.share_task)
  50 + // ****** 父文本编辑 ******
  51 + WxParse.wxParse('article', 'html', res.data.share_rule.content, that, 5)
  52 + // 获取值
  53 +
  54 +
  55 +
  56 +
  57 + }).catch((err) => {
  58 +
  59 + })
22 }, 60 },
23 61
24 /** 62 /**
  1 +<import src="../../wxParse/wxParse.wxml"/>
1 2
2 <view class='container'> 3 <view class='container'>
3 <view class='top'> 4 <view class='top'>
@@ -7,30 +8,28 @@ @@ -7,30 +8,28 @@
7 <view class='mid'> 8 <view class='mid'>
8 <!-- 大盒子1 --> 9 <!-- 大盒子1 -->
9 <view class='item_1'> 10 <view class='item_1'>
10 - <view class='item_1_top'> 11 + <view class='item_1_top' >
11 邀请任意好友登录优秀精英并绑定手机号 12 邀请任意好友登录优秀精英并绑定手机号
12 且2个岗位招聘,你和好友均可各享奖励 13 且2个岗位招聘,你和好友均可各享奖励
13 </view> 14 </view>
14 <!-- 小盒子 --> 15 <!-- 小盒子 -->
15 <view class='item_1_mid'> 16 <view class='item_1_mid'>
16 <view class='item_1_mid_t'> 17 <view class='item_1_mid_t'>
17 - <!-- <span class='color_yellow'>自己</span>可得 -->  
18 <image src='../../img/aicon_52@2x.png'></image> 18 <image src='../../img/aicon_52@2x.png'></image>
19 </view> 19 </view>
20 <view class='item_1_mid_b'> 20 <view class='item_1_mid_b'>
21 - <view>邀请任意好友自己可得1元现金奖励</view> 21 + <view>邀请任意好友自己可得{{share_task.share_total}}元现金奖励</view>
22 <view class='mid_b_text'>邀请好友越多获得奖励越多</view> 22 <view class='mid_b_text'>邀请好友越多获得奖励越多</view>
23 </view> 23 </view>
24 </view> 24 </view>
25 <!-- 小盒子 --> 25 <!-- 小盒子 -->
26 <view class='item_1_mid'> 26 <view class='item_1_mid'>
27 <view class='item_1_mid_t'> 27 <view class='item_1_mid_t'>
28 - <!-- <span class='color_yellow'>好友</span>可得 -->  
29 <image src='../../img/aicon_53@2x.png'></image> 28 <image src='../../img/aicon_53@2x.png'></image>
30 </view> 29 </view>
31 <view class='item_1_mid_b'> 30 <view class='item_1_mid_b'>
32 - <view>邀请任意好友自己可得1元现金奖励</view>  
33 - <view class='mid_b_text'>邀请好友越多获得奖励越多</view> 31 + <view>{{share_task.task_total}}元现金奖励</view>
  32 + <view class='mid_b_text'>好友绑定手机号并成功报名2个岗位招聘即可获得</view>
34 </view> 33 </view>
35 </view> 34 </view>
36 </view> 35 </view>
@@ -38,12 +37,12 @@ @@ -38,12 +37,12 @@
38 <!-- 大盒子2 --> 37 <!-- 大盒子2 -->
39 <view class='item_2'> 38 <view class='item_2'>
40 <view class='item_2_left'> 39 <view class='item_2_left'>
41 - <view class='item_2_left_top'>252</view> 40 + <view class='item_2_left_top'>{{user.grand}}</view>
42 <view class='item_2_left_bottom'>已获得奖励(元)</view> 41 <view class='item_2_left_bottom'>已获得奖励(元)</view>
43 </view> 42 </view>
44 <view class='item_2_mid'></view> 43 <view class='item_2_mid'></view>
45 <view class='item_2_left'> 44 <view class='item_2_left'>
46 - <view class='item_2_left_top'>15</view> 45 + <view class='item_2_left_top'>{{user.valid_num}}</view>
47 <view class='item_2_left_bottom'>已成功邀请(人)</view> 46 <view class='item_2_left_bottom'>已成功邀请(人)</view>
48 </view> 47 </view>
49 </view> 48 </view>
@@ -81,18 +80,7 @@ @@ -81,18 +80,7 @@
81 </view> 80 </view>
82 <!-- 活动内容 --> 81 <!-- 活动内容 -->
83 <view class='item_4_content'> 82 <view class='item_4_content'>
84 -  
85 - <view>1、本活动全国用户均可参加</view>  
86 - <view>2、本活动时间:2019年03月01日至2020年03月01日</view>  
87 - <view>3、参与方式:分享小程序给好友,好友进入小程序进行授权,允许小程序获取用户手机号并进行绑定,且完善简历后成功报名2个岗位招聘即可获得奖励,推荐人可获得1元,好友首次完成任务可获得5元,好友邀请他人,自己可获得1元,以此类推</view>  
88 - <view>4、奖励发放:用户在成功邀请好友后,平台自动发放给用户及好友的小程序账户中</view>  
89 - <view>5、现金可以提现,每天最多提现一次,且提现金额需满足10元且为10的倍数;</view>  
90 - <view>6、注意事项:</view>  
91 - <view>(1)获得现金奖励需满足推荐好友登录小程序并允许小程序绑定手机号且成功报名2个岗位招聘</view>  
92 - <view>(2)若系统检测为刷单行为,将取消参与活动资格及奖金发放(如:批量使用虚拟手机号码进行注册)</view>  
93 - <view>注:优秀精英保留活动最终结束权,对本活动有疑问请联系官方客服:400-800-8820</view>  
94 -  
95 - 83 + <template is="wxParse" data="{{wxParseData:article.nodes}}"/>
96 </view> 84 </view>
97 </view> 85 </view>
98 86
@@ -194,7 +194,7 @@ page{ @@ -194,7 +194,7 @@ page{
194 .item_4{ 194 .item_4{
195 margin-top: 24rpx; 195 margin-top: 24rpx;
196 width:688rpx; 196 width:688rpx;
197 - height:1129rpx; 197 + /* height:1129rpx; */
198 background:rgba(253,255,255,1); 198 background:rgba(253,255,255,1);
199 box-shadow:0rpx 8rpx 49rpx 0rpx rgba(255,107,82,0.34); 199 box-shadow:0rpx 8rpx 49rpx 0rpx rgba(255,107,82,0.34);
200 border-radius:22rpx; 200 border-radius:22rpx;
1 // pages/registration/registration.js 1 // pages/registration/registration.js
  2 +const app = getApp()
2 Page({ 3 Page({
3 4
4 /** 5 /**
@@ -12,7 +13,7 @@ Page({ @@ -12,7 +13,7 @@ Page({
12 * 生命周期函数--监听页面加载 13 * 生命周期函数--监听页面加载
13 */ 14 */
14 onLoad: function (options) { 15 onLoad: function (options) {
15 - that.registration() 16 + this.registration()
16 }, 17 },
17 // 报名名单功能 18 // 报名名单功能
18 registration() { 19 registration() {
  1 +/**
  2 + * html2Json 改造来自: https://github.com/Jxck/html2json
  3 + *
  4 + *
  5 + * author: Di (微信小程序开发工程师)
  6 + * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
  7 + * 垂直微信小程序开发交流社区
  8 + *
  9 + * github地址: https://github.com/icindy/wxParse
  10 + *
  11 + * for: 微信小程序富文本解析
  12 + * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
  13 + */
  14 +
  15 +var __placeImgeUrlHttps = "https";
  16 +var __emojisReg = '';
  17 +var __emojisBaseSrc = '';
  18 +var __emojis = {};
  19 +var wxDiscode = require('./wxDiscode.js');
  20 +var HTMLParser = require('./htmlparser.js');
  21 +// Empty Elements - HTML 5
  22 +var empty = makeMap("area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr");
  23 +// Block Elements - HTML 5
  24 +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");
  25 +
  26 +// Inline Elements - HTML 5
  27 +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");
  28 +
  29 +// Elements that you can, intentionally, leave open
  30 +// (and which close themselves)
  31 +var closeSelf = makeMap("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr");
  32 +
  33 +// Attributes that have their values filled in disabled="disabled"
  34 +var fillAttrs = makeMap("checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected");
  35 +
  36 +// Special Elements (can contain anything)
  37 +var special = makeMap("wxxxcode-style,script,style,view,scroll-view,block");
  38 +function makeMap(str) {
  39 + var obj = {}, items = str.split(",");
  40 + for (var i = 0; i < items.length; i++)
  41 + obj[items[i]] = true;
  42 + return obj;
  43 +}
  44 +
  45 +function q(v) {
  46 + return '"' + v + '"';
  47 +}
  48 +
  49 +function removeDOCTYPE(html) {
  50 + return html
  51 + .replace(/<\?xml.*\?>\n/, '')
  52 + .replace(/<.*!doctype.*\>\n/, '')
  53 + .replace(/<.*!DOCTYPE.*\>\n/, '');
  54 +}
  55 +
  56 +function trimHtml(html) {
  57 + return html
  58 + .replace(/\r?\n+/g, '')
  59 + .replace(/<!--.*?-->/ig, '')
  60 + .replace(/\/\*.*?\*\//ig, '')
  61 + .replace(/[ ]+</ig, '<')
  62 +}
  63 +
  64 +
  65 +function html2json(html, bindName) {
  66 + //处理字符串
  67 + html = removeDOCTYPE(html);
  68 + html = trimHtml(html);
  69 + html = wxDiscode.strDiscode(html);
  70 + //生成node节点
  71 + var bufArray = [];
  72 + var results = {
  73 + node: bindName,
  74 + nodes: [],
  75 + images:[],
  76 + imageUrls:[]
  77 + };
  78 + var index = 0;
  79 + HTMLParser(html, {
  80 + start: function (tag, attrs, unary) {
  81 + //debug(tag, attrs, unary);
  82 + // node for this element
  83 + var node = {
  84 + node: 'element',
  85 + tag: tag,
  86 + };
  87 +
  88 + if (bufArray.length === 0) {
  89 + node.index = index.toString()
  90 + index += 1
  91 + } else {
  92 + var parent = bufArray[0];
  93 + if (parent.nodes === undefined) {
  94 + parent.nodes = [];
  95 + }
  96 + node.index = parent.index + '.' + parent.nodes.length
  97 + }
  98 +
  99 + if (block[tag]) {
  100 + node.tagType = "block";
  101 + } else if (inline[tag]) {
  102 + node.tagType = "inline";
  103 + } else if (closeSelf[tag]) {
  104 + node.tagType = "closeSelf";
  105 + }
  106 +
  107 + if (attrs.length !== 0) {
  108 + node.attr = attrs.reduce(function (pre, attr) {
  109 + var name = attr.name;
  110 + var value = attr.value;
  111 + if (name == 'class') {
  112 + // console.dir(value);
  113 + // value = value.join("")
  114 + node.classStr = value;
  115 + }
  116 + // has multi attibutes
  117 + // make it array of attribute
  118 + if (name == 'style') {
  119 + // console.dir(value);
  120 + // value = value.join("")
  121 + node.styleStr = value;
  122 + }
  123 + if (value.match(/ /)) {
  124 + value = value.split(' ');
  125 + }
  126 +
  127 +
  128 + // if attr already exists
  129 + // merge it
  130 + if (pre[name]) {
  131 + if (Array.isArray(pre[name])) {
  132 + // already array, push to last
  133 + pre[name].push(value);
  134 + } else {
  135 + // single value, make it array
  136 + pre[name] = [pre[name], value];
  137 + }
  138 + } else {
  139 + // not exist, put it
  140 + pre[name] = value;
  141 + }
  142 +
  143 + return pre;
  144 + }, {});
  145 + }
  146 +
  147 + //对img添加额外数据
  148 + if (node.tag === 'img') {
  149 + node.imgIndex = results.images.length;
  150 + var imgUrl = node.attr.src;
  151 + if (imgUrl[0] == '') {
  152 + imgUrl.splice(0, 1);
  153 + }
  154 + imgUrl = wxDiscode.urlToHttpUrl(imgUrl, __placeImgeUrlHttps);
  155 + node.attr.src = imgUrl;
  156 + node.from = bindName;
  157 + results.images.push(node);
  158 + results.imageUrls.push(imgUrl);
  159 + }
  160 +
  161 + // 处理font标签样式属性
  162 + if (node.tag === 'font') {
  163 + var fontSize = ['x-small', 'small', 'medium', 'large', 'x-large', 'xx-large', '-webkit-xxx-large'];
  164 + var styleAttrs = {
  165 + 'color': 'color',
  166 + 'face': 'font-family',
  167 + 'size': 'font-size'
  168 + };
  169 + if (!node.attr.style) node.attr.style = [];
  170 + if (!node.styleStr) node.styleStr = '';
  171 + for (var key in styleAttrs) {
  172 + if (node.attr[key]) {
  173 + var value = key === 'size' ? fontSize[node.attr[key]-1] : node.attr[key];
  174 + node.attr.style.push(styleAttrs[key]);
  175 + node.attr.style.push(value);
  176 + node.styleStr += styleAttrs[key] + ': ' + value + ';';
  177 + }
  178 + }
  179 + }
  180 +
  181 + //临时记录source资源
  182 + if(node.tag === 'source'){
  183 + results.source = node.attr.src;
  184 + }
  185 +
  186 + if (unary) {
  187 + // if this tag doesn't have end tag
  188 + // like <img src="hoge.png"/>
  189 + // add to parents
  190 + var parent = bufArray[0] || results;
  191 + if (parent.nodes === undefined) {
  192 + parent.nodes = [];
  193 + }
  194 + parent.nodes.push(node);
  195 + } else {
  196 + bufArray.unshift(node);
  197 + }
  198 + },
  199 + end: function (tag) {
  200 + //debug(tag);
  201 + // merge into parent tag
  202 + var node = bufArray.shift();
  203 + if (node.tag !== tag) console.error('invalid state: mismatch end tag');
  204 +
  205 + //当有缓存source资源时于于video补上src资源
  206 + if(node.tag === 'video' && results.source){
  207 + node.attr.src = results.source;
  208 + delete results.source;
  209 + }
  210 +
  211 + if (bufArray.length === 0) {
  212 + results.nodes.push(node);
  213 + } else {
  214 + var parent = bufArray[0];
  215 + if (parent.nodes === undefined) {
  216 + parent.nodes = [];
  217 + }
  218 + parent.nodes.push(node);
  219 + }
  220 + },
  221 + chars: function (text) {
  222 + //debug(text);
  223 + var node = {
  224 + node: 'text',
  225 + text: text,
  226 + textArray:transEmojiStr(text)
  227 + };
  228 +
  229 + if (bufArray.length === 0) {
  230 + node.index = index.toString()
  231 + index += 1
  232 + results.nodes.push(node);
  233 + } else {
  234 + var parent = bufArray[0];
  235 + if (parent.nodes === undefined) {
  236 + parent.nodes = [];
  237 + }
  238 + node.index = parent.index + '.' + parent.nodes.length
  239 + parent.nodes.push(node);
  240 + }
  241 + },
  242 + comment: function (text) {
  243 + //debug(text);
  244 + // var node = {
  245 + // node: 'comment',
  246 + // text: text,
  247 + // };
  248 + // var parent = bufArray[0];
  249 + // if (parent.nodes === undefined) {
  250 + // parent.nodes = [];
  251 + // }
  252 + // parent.nodes.push(node);
  253 + },
  254 + });
  255 + return results;
  256 +};
  257 +
  258 +function transEmojiStr(str){
  259 + // var eReg = new RegExp("["+__reg+' '+"]");
  260 +// str = str.replace(/\[([^\[\]]+)\]/g,':$1:')
  261 +
  262 + var emojiObjs = [];
  263 + //如果正则表达式为空
  264 + if(__emojisReg.length == 0 || !__emojis){
  265 + var emojiObj = {}
  266 + emojiObj.node = "text";
  267 + emojiObj.text = str;
  268 + array = [emojiObj];
  269 + return array;
  270 + }
  271 + //这个地方需要调整
  272 + str = str.replace(/\[([^\[\]]+)\]/g,':$1:')
  273 + var eReg = new RegExp("[:]");
  274 + var array = str.split(eReg);
  275 + for(var i = 0; i < array.length; i++){
  276 + var ele = array[i];
  277 + var emojiObj = {};
  278 + if(__emojis[ele]){
  279 + emojiObj.node = "element";
  280 + emojiObj.tag = "emoji";
  281 + emojiObj.text = __emojis[ele];
  282 + emojiObj.baseSrc= __emojisBaseSrc;
  283 + }else{
  284 + emojiObj.node = "text";
  285 + emojiObj.text = ele;
  286 + }
  287 + emojiObjs.push(emojiObj);
  288 + }
  289 +
  290 + return emojiObjs;
  291 +}
  292 +
  293 +function emojisInit(reg='',baseSrc="/wxParse/emojis/",emojis){
  294 + __emojisReg = reg;
  295 + __emojisBaseSrc=baseSrc;
  296 + __emojis=emojis;
  297 +}
  298 +
  299 +module.exports = {
  300 + html2json: html2json,
  301 + emojisInit:emojisInit
  302 +};
  303 +
  1 +/**
  2 + *
  3 + * htmlParser改造自: https://github.com/blowsie/Pure-JavaScript-HTML5-Parser
  4 + *
  5 + * author: Di (微信小程序开发工程师)
  6 + * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
  7 + * 垂直微信小程序开发交流社区
  8 + *
  9 + * github地址: https://github.com/icindy/wxParse
  10 + *
  11 + * for: 微信小程序富文本解析
  12 + * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
  13 + */
  14 +// Regular Expressions for parsing tags and attributes
  15 +var startTag = /^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/,
  16 + endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/,
  17 + attr = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g;
  18 +
  19 +// Empty Elements - HTML 5
  20 +var empty = makeMap("area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr");
  21 +
  22 +// Block Elements - HTML 5
  23 +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");
  24 +
  25 +// Inline Elements - HTML 5
  26 +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");
  27 +
  28 +// Elements that you can, intentionally, leave open
  29 +// (and which close themselves)
  30 +var closeSelf = makeMap("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr");
  31 +
  32 +// Attributes that have their values filled in disabled="disabled"
  33 +var fillAttrs = makeMap("checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected");
  34 +
  35 +// Special Elements (can contain anything)
  36 +var special = makeMap("wxxxcode-style,script,style,view,scroll-view,block");
  37 +
  38 +function HTMLParser(html, handler) {
  39 + var index, chars, match, stack = [], last = html;
  40 + stack.last = function () {
  41 + return this[this.length - 1];
  42 + };
  43 +
  44 + while (html) {
  45 + chars = true;
  46 +
  47 + // Make sure we're not in a script or style element
  48 + if (!stack.last() || !special[stack.last()]) {
  49 +
  50 + // Comment
  51 + if (html.indexOf("<!--") == 0) {
  52 + index = html.indexOf("-->");
  53 +
  54 + if (index >= 0) {
  55 + if (handler.comment)
  56 + handler.comment(html.substring(4, index));
  57 + html = html.substring(index + 3);
  58 + chars = false;
  59 + }
  60 +
  61 + // end tag
  62 + } else if (html.indexOf("</") == 0) {
  63 + match = html.match(endTag);
  64 +
  65 + if (match) {
  66 + html = html.substring(match[0].length);
  67 + match[0].replace(endTag, parseEndTag);
  68 + chars = false;
  69 + }
  70 +
  71 + // start tag
  72 + } else if (html.indexOf("<") == 0) {
  73 + match = html.match(startTag);
  74 +
  75 + if (match) {
  76 + html = html.substring(match[0].length);
  77 + match[0].replace(startTag, parseStartTag);
  78 + chars = false;
  79 + }
  80 + }
  81 +
  82 + if (chars) {
  83 + index = html.indexOf("<");
  84 + var text = ''
  85 + while (index === 0) {
  86 + text += "<";
  87 + html = html.substring(1);
  88 + index = html.indexOf("<");
  89 + }
  90 + text += index < 0 ? html : html.substring(0, index);
  91 + html = index < 0 ? "" : html.substring(index);
  92 +
  93 + if (handler.chars)
  94 + handler.chars(text);
  95 + }
  96 +
  97 + } else {
  98 +
  99 + html = html.replace(new RegExp("([\\s\\S]*?)<\/" + stack.last() + "[^>]*>"), function (all, text) {
  100 + text = text.replace(/<!--([\s\S]*?)-->|<!\[CDATA\[([\s\S]*?)]]>/g, "$1$2");
  101 + if (handler.chars)
  102 + handler.chars(text);
  103 +
  104 + return "";
  105 + });
  106 +
  107 +
  108 + parseEndTag("", stack.last());
  109 + }
  110 +
  111 + if (html == last)
  112 + throw "Parse Error: " + html;
  113 + last = html;
  114 + }
  115 +
  116 + // Clean up any remaining tags
  117 + parseEndTag();
  118 +
  119 + function parseStartTag(tag, tagName, rest, unary) {
  120 + tagName = tagName.toLowerCase();
  121 +
  122 + if (block[tagName]) {
  123 + while (stack.last() && inline[stack.last()]) {
  124 + parseEndTag("", stack.last());
  125 + }
  126 + }
  127 +
  128 + if (closeSelf[tagName] && stack.last() == tagName) {
  129 + parseEndTag("", tagName);
  130 + }
  131 +
  132 + unary = empty[tagName] || !!unary;
  133 +
  134 + if (!unary)
  135 + stack.push(tagName);
  136 +
  137 + if (handler.start) {
  138 + var attrs = [];
  139 +
  140 + rest.replace(attr, function (match, name) {
  141 + var value = arguments[2] ? arguments[2] :
  142 + arguments[3] ? arguments[3] :
  143 + arguments[4] ? arguments[4] :
  144 + fillAttrs[name] ? name : "";
  145 +
  146 + attrs.push({
  147 + name: name,
  148 + value: value,
  149 + escaped: value.replace(/(^|[^\\])"/g, '$1\\\"') //"
  150 + });
  151 + });
  152 +
  153 + if (handler.start) {
  154 + handler.start(tagName, attrs, unary);
  155 + }
  156 +
  157 + }
  158 + }
  159 +
  160 + function parseEndTag(tag, tagName) {
  161 + // If no tag name is provided, clean shop
  162 + if (!tagName)
  163 + var pos = 0;
  164 +
  165 + // Find the closest opened tag of the same type
  166 + else {
  167 + tagName = tagName.toLowerCase();
  168 + for (var pos = stack.length - 1; pos >= 0; pos--)
  169 + if (stack[pos] == tagName)
  170 + break;
  171 + }
  172 + if (pos >= 0) {
  173 + // Close all the open elements, up the stack
  174 + for (var i = stack.length - 1; i >= pos; i--)
  175 + if (handler.end)
  176 + handler.end(stack[i]);
  177 +
  178 + // Remove the open elements from the stack
  179 + stack.length = pos;
  180 + }
  181 + }
  182 +};
  183 +
  184 +
  185 +function makeMap(str) {
  186 + var obj = {}, items = str.split(",");
  187 + for (var i = 0; i < items.length; i++)
  188 + obj[items[i]] = true;
  189 + return obj;
  190 +}
  191 +
  192 +module.exports = HTMLParser;
  1 +/**
  2 + *
  3 + * showdown: https://github.com/showdownjs/showdown
  4 + *
  5 + * author: Di (微信小程序开发工程师)
  6 + * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
  7 + * 垂直微信小程序开发交流社区
  8 + *
  9 + * github地址: https://github.com/icindy/wxParse
  10 + *
  11 + * for: 微信小程序富文本解析
  12 + * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
  13 + */
  14 +
  15 +function getDefaultOpts(simple) {
  16 + 'use strict';
  17 +
  18 + var defaultOptions = {
  19 + omitExtraWLInCodeBlocks: {
  20 + defaultValue: false,
  21 + describe: 'Omit the default extra whiteline added to code blocks',
  22 + type: 'boolean'
  23 + },
  24 + noHeaderId: {
  25 + defaultValue: false,
  26 + describe: 'Turn on/off generated header id',
  27 + type: 'boolean'
  28 + },
  29 + prefixHeaderId: {
  30 + defaultValue: false,
  31 + describe: 'Specify a prefix to generated header ids',
  32 + type: 'string'
  33 + },
  34 + headerLevelStart: {
  35 + defaultValue: false,
  36 + describe: 'The header blocks level start',
  37 + type: 'integer'
  38 + },
  39 + parseImgDimensions: {
  40 + defaultValue: false,
  41 + describe: 'Turn on/off image dimension parsing',
  42 + type: 'boolean'
  43 + },
  44 + simplifiedAutoLink: {
  45 + defaultValue: false,
  46 + describe: 'Turn on/off GFM autolink style',
  47 + type: 'boolean'
  48 + },
  49 + literalMidWordUnderscores: {
  50 + defaultValue: false,
  51 + describe: 'Parse midword underscores as literal underscores',
  52 + type: 'boolean'
  53 + },
  54 + strikethrough: {
  55 + defaultValue: false,
  56 + describe: 'Turn on/off strikethrough support',
  57 + type: 'boolean'
  58 + },
  59 + tables: {
  60 + defaultValue: false,
  61 + describe: 'Turn on/off tables support',
  62 + type: 'boolean'
  63 + },
  64 + tablesHeaderId: {
  65 + defaultValue: false,
  66 + describe: 'Add an id to table headers',
  67 + type: 'boolean'
  68 + },
  69 + ghCodeBlocks: {
  70 + defaultValue: true,
  71 + describe: 'Turn on/off GFM fenced code blocks support',
  72 + type: 'boolean'
  73 + },
  74 + tasklists: {
  75 + defaultValue: false,
  76 + describe: 'Turn on/off GFM tasklist support',
  77 + type: 'boolean'
  78 + },
  79 + smoothLivePreview: {
  80 + defaultValue: false,
  81 + describe: 'Prevents weird effects in live previews due to incomplete input',
  82 + type: 'boolean'
  83 + },
  84 + smartIndentationFix: {
  85 + defaultValue: false,
  86 + description: 'Tries to smartly fix identation in es6 strings',
  87 + type: 'boolean'
  88 + }
  89 + };
  90 + if (simple === false) {
  91 + return JSON.parse(JSON.stringify(defaultOptions));
  92 + }
  93 + var ret = {};
  94 + for (var opt in defaultOptions) {
  95 + if (defaultOptions.hasOwnProperty(opt)) {
  96 + ret[opt] = defaultOptions[opt].defaultValue;
  97 + }
  98 + }
  99 + return ret;
  100 +}
  101 +
  102 +/**
  103 + * Created by Tivie on 06-01-2015.
  104 + */
  105 +
  106 +// Private properties
  107 +var showdown = {},
  108 + parsers = {},
  109 + extensions = {},
  110 + globalOptions = getDefaultOpts(true),
  111 + flavor = {
  112 + github: {
  113 + omitExtraWLInCodeBlocks: true,
  114 + prefixHeaderId: 'user-content-',
  115 + simplifiedAutoLink: true,
  116 + literalMidWordUnderscores: true,
  117 + strikethrough: true,
  118 + tables: true,
  119 + tablesHeaderId: true,
  120 + ghCodeBlocks: true,
  121 + tasklists: true
  122 + },
  123 + vanilla: getDefaultOpts(true)
  124 + };
  125 +
  126 +/**
  127 + * helper namespace
  128 + * @type {{}}
  129 + */
  130 +showdown.helper = {};
  131 +
  132 +/**
  133 + * TODO LEGACY SUPPORT CODE
  134 + * @type {{}}
  135 + */
  136 +showdown.extensions = {};
  137 +
  138 +/**
  139 + * Set a global option
  140 + * @static
  141 + * @param {string} key
  142 + * @param {*} value
  143 + * @returns {showdown}
  144 + */
  145 +showdown.setOption = function (key, value) {
  146 + 'use strict';
  147 + globalOptions[key] = value;
  148 + return this;
  149 +};
  150 +
  151 +/**
  152 + * Get a global option
  153 + * @static
  154 + * @param {string} key
  155 + * @returns {*}
  156 + */
  157 +showdown.getOption = function (key) {
  158 + 'use strict';
  159 + return globalOptions[key];
  160 +};
  161 +
  162 +/**
  163 + * Get the global options
  164 + * @static
  165 + * @returns {{}}
  166 + */
  167 +showdown.getOptions = function () {
  168 + 'use strict';
  169 + return globalOptions;
  170 +};
  171 +
  172 +/**
  173 + * Reset global options to the default values
  174 + * @static
  175 + */
  176 +showdown.resetOptions = function () {
  177 + 'use strict';
  178 + globalOptions = getDefaultOpts(true);
  179 +};
  180 +
  181 +/**
  182 + * Set the flavor showdown should use as default
  183 + * @param {string} name
  184 + */
  185 +showdown.setFlavor = function (name) {
  186 + 'use strict';
  187 + if (flavor.hasOwnProperty(name)) {
  188 + var preset = flavor[name];
  189 + for (var option in preset) {
  190 + if (preset.hasOwnProperty(option)) {
  191 + globalOptions[option] = preset[option];
  192 + }
  193 + }
  194 + }
  195 +};
  196 +
  197 +/**
  198 + * Get the default options
  199 + * @static
  200 + * @param {boolean} [simple=true]
  201 + * @returns {{}}
  202 + */
  203 +showdown.getDefaultOptions = function (simple) {
  204 + 'use strict';
  205 + return getDefaultOpts(simple);
  206 +};
  207 +
  208 +/**
  209 + * Get or set a subParser
  210 + *
  211 + * subParser(name) - Get a registered subParser
  212 + * subParser(name, func) - Register a subParser
  213 + * @static
  214 + * @param {string} name
  215 + * @param {function} [func]
  216 + * @returns {*}
  217 + */
  218 +showdown.subParser = function (name, func) {
  219 + 'use strict';
  220 + if (showdown.helper.isString(name)) {
  221 + if (typeof func !== 'undefined') {
  222 + parsers[name] = func;
  223 + } else {
  224 + if (parsers.hasOwnProperty(name)) {
  225 + return parsers[name];
  226 + } else {
  227 + throw Error('SubParser named ' + name + ' not registered!');
  228 + }
  229 + }
  230 + }
  231 +};
  232 +
  233 +/**
  234 + * Gets or registers an extension
  235 + * @static
  236 + * @param {string} name
  237 + * @param {object|function=} ext
  238 + * @returns {*}
  239 + */
  240 +showdown.extension = function (name, ext) {
  241 + 'use strict';
  242 +
  243 + if (!showdown.helper.isString(name)) {
  244 + throw Error('Extension \'name\' must be a string');
  245 + }
  246 +
  247 + name = showdown.helper.stdExtName(name);
  248 +
  249 + // Getter
  250 + if (showdown.helper.isUndefined(ext)) {
  251 + if (!extensions.hasOwnProperty(name)) {
  252 + throw Error('Extension named ' + name + ' is not registered!');
  253 + }
  254 + return extensions[name];
  255 +
  256 + // Setter
  257 + } else {
  258 + // Expand extension if it's wrapped in a function
  259 + if (typeof ext === 'function') {
  260 + ext = ext();
  261 + }
  262 +
  263 + // Ensure extension is an array
  264 + if (!showdown.helper.isArray(ext)) {
  265 + ext = [ext];
  266 + }
  267 +
  268 + var validExtension = validate(ext, name);
  269 +
  270 + if (validExtension.valid) {
  271 + extensions[name] = ext;
  272 + } else {
  273 + throw Error(validExtension.error);
  274 + }
  275 + }
  276 +};
  277 +
  278 +/**
  279 + * Gets all extensions registered
  280 + * @returns {{}}
  281 + */
  282 +showdown.getAllExtensions = function () {
  283 + 'use strict';
  284 + return extensions;
  285 +};
  286 +
  287 +/**
  288 + * Remove an extension
  289 + * @param {string} name
  290 + */
  291 +showdown.removeExtension = function (name) {
  292 + 'use strict';
  293 + delete extensions[name];
  294 +};
  295 +
  296 +/**
  297 + * Removes all extensions
  298 + */
  299 +showdown.resetExtensions = function () {
  300 + 'use strict';
  301 + extensions = {};
  302 +};
  303 +
  304 +/**
  305 + * Validate extension
  306 + * @param {array} extension
  307 + * @param {string} name
  308 + * @returns {{valid: boolean, error: string}}
  309 + */
  310 +function validate(extension, name) {
  311 + 'use strict';
  312 +
  313 + var errMsg = (name) ? 'Error in ' + name + ' extension->' : 'Error in unnamed extension',
  314 + ret = {
  315 + valid: true,
  316 + error: ''
  317 + };
  318 +
  319 + if (!showdown.helper.isArray(extension)) {
  320 + extension = [extension];
  321 + }
  322 +
  323 + for (var i = 0; i < extension.length; ++i) {
  324 + var baseMsg = errMsg + ' sub-extension ' + i + ': ',
  325 + ext = extension[i];
  326 + if (typeof ext !== 'object') {
  327 + ret.valid = false;
  328 + ret.error = baseMsg + 'must be an object, but ' + typeof ext + ' given';
  329 + return ret;
  330 + }
  331 +
  332 + if (!showdown.helper.isString(ext.type)) {
  333 + ret.valid = false;
  334 + ret.error = baseMsg + 'property "type" must be a string, but ' + typeof ext.type + ' given';
  335 + return ret;
  336 + }
  337 +
  338 + var type = ext.type = ext.type.toLowerCase();
  339 +
  340 + // normalize extension type
  341 + if (type === 'language') {
  342 + type = ext.type = 'lang';
  343 + }
  344 +
  345 + if (type === 'html') {
  346 + type = ext.type = 'output';
  347 + }
  348 +
  349 + if (type !== 'lang' && type !== 'output' && type !== 'listener') {
  350 + ret.valid = false;
  351 + ret.error = baseMsg + 'type ' + type + ' is not recognized. Valid values: "lang/language", "output/html" or "listener"';
  352 + return ret;
  353 + }
  354 +
  355 + if (type === 'listener') {
  356 + if (showdown.helper.isUndefined(ext.listeners)) {
  357 + ret.valid = false;
  358 + ret.error = baseMsg + '. Extensions of type "listener" must have a property called "listeners"';
  359 + return ret;
  360 + }
  361 + } else {
  362 + if (showdown.helper.isUndefined(ext.filter) && showdown.helper.isUndefined(ext.regex)) {
  363 + ret.valid = false;
  364 + ret.error = baseMsg + type + ' extensions must define either a "regex" property or a "filter" method';
  365 + return ret;
  366 + }
  367 + }
  368 +
  369 + if (ext.listeners) {
  370 + if (typeof ext.listeners !== 'object') {
  371 + ret.valid = false;
  372 + ret.error = baseMsg + '"listeners" property must be an object but ' + typeof ext.listeners + ' given';
  373 + return ret;
  374 + }
  375 + for (var ln in ext.listeners) {
  376 + if (ext.listeners.hasOwnProperty(ln)) {
  377 + if (typeof ext.listeners[ln] !== 'function') {
  378 + ret.valid = false;
  379 + ret.error = baseMsg + '"listeners" property must be an hash of [event name]: [callback]. listeners.' + ln +
  380 + ' must be a function but ' + typeof ext.listeners[ln] + ' given';
  381 + return ret;
  382 + }
  383 + }
  384 + }
  385 + }
  386 +
  387 + if (ext.filter) {
  388 + if (typeof ext.filter !== 'function') {
  389 + ret.valid = false;
  390 + ret.error = baseMsg + '"filter" must be a function, but ' + typeof ext.filter + ' given';
  391 + return ret;
  392 + }
  393 + } else if (ext.regex) {
  394 + if (showdown.helper.isString(ext.regex)) {
  395 + ext.regex = new RegExp(ext.regex, 'g');
  396 + }
  397 + if (!ext.regex instanceof RegExp) {
  398 + ret.valid = false;
  399 + ret.error = baseMsg + '"regex" property must either be a string or a RegExp object, but ' + typeof ext.regex + ' given';
  400 + return ret;
  401 + }
  402 + if (showdown.helper.isUndefined(ext.replace)) {
  403 + ret.valid = false;
  404 + ret.error = baseMsg + '"regex" extensions must implement a replace string or function';
  405 + return ret;
  406 + }
  407 + }
  408 + }
  409 + return ret;
  410 +}
  411 +
  412 +/**
  413 + * Validate extension
  414 + * @param {object} ext
  415 + * @returns {boolean}
  416 + */
  417 +showdown.validateExtension = function (ext) {
  418 + 'use strict';
  419 +
  420 + var validateExtension = validate(ext, null);
  421 + if (!validateExtension.valid) {
  422 + console.warn(validateExtension.error);
  423 + return false;
  424 + }
  425 + return true;
  426 +};
  427 +
  428 +/**
  429 + * showdownjs helper functions
  430 + */
  431 +
  432 +if (!showdown.hasOwnProperty('helper')) {
  433 + showdown.helper = {};
  434 +}
  435 +
  436 +/**
  437 + * Check if var is string
  438 + * @static
  439 + * @param {string} a
  440 + * @returns {boolean}
  441 + */
  442 +showdown.helper.isString = function isString(a) {
  443 + 'use strict';
  444 + return (typeof a === 'string' || a instanceof String);
  445 +};
  446 +
  447 +/**
  448 + * Check if var is a function
  449 + * @static
  450 + * @param {string} a
  451 + * @returns {boolean}
  452 + */
  453 +showdown.helper.isFunction = function isFunction(a) {
  454 + 'use strict';
  455 + var getType = {};
  456 + return a && getType.toString.call(a) === '[object Function]';
  457 +};
  458 +
  459 +/**
  460 + * ForEach helper function
  461 + * @static
  462 + * @param {*} obj
  463 + * @param {function} callback
  464 + */
  465 +showdown.helper.forEach = function forEach(obj, callback) {
  466 + 'use strict';
  467 + if (typeof obj.forEach === 'function') {
  468 + obj.forEach(callback);
  469 + } else {
  470 + for (var i = 0; i < obj.length; i++) {
  471 + callback(obj[i], i, obj);
  472 + }
  473 + }
  474 +};
  475 +
  476 +/**
  477 + * isArray helper function
  478 + * @static
  479 + * @param {*} a
  480 + * @returns {boolean}
  481 + */
  482 +showdown.helper.isArray = function isArray(a) {
  483 + 'use strict';
  484 + return a.constructor === Array;
  485 +};
  486 +
  487 +/**
  488 + * Check if value is undefined
  489 + * @static
  490 + * @param {*} value The value to check.
  491 + * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.
  492 + */
  493 +showdown.helper.isUndefined = function isUndefined(value) {
  494 + 'use strict';
  495 + return typeof value === 'undefined';
  496 +};
  497 +
  498 +/**
  499 + * Standardidize extension name
  500 + * @static
  501 + * @param {string} s extension name
  502 + * @returns {string}
  503 + */
  504 +showdown.helper.stdExtName = function (s) {
  505 + 'use strict';
  506 + return s.replace(/[_-]||\s/g, '').toLowerCase();
  507 +};
  508 +
  509 +function escapeCharactersCallback(wholeMatch, m1) {
  510 + 'use strict';
  511 + var charCodeToEscape = m1.charCodeAt(0);
  512 + return '~E' + charCodeToEscape + 'E';
  513 +}
  514 +
  515 +/**
  516 + * Callback used to escape characters when passing through String.replace
  517 + * @static
  518 + * @param {string} wholeMatch
  519 + * @param {string} m1
  520 + * @returns {string}
  521 + */
  522 +showdown.helper.escapeCharactersCallback = escapeCharactersCallback;
  523 +
  524 +/**
  525 + * Escape characters in a string
  526 + * @static
  527 + * @param {string} text
  528 + * @param {string} charsToEscape
  529 + * @param {boolean} afterBackslash
  530 + * @returns {XML|string|void|*}
  531 + */
  532 +showdown.helper.escapeCharacters = function escapeCharacters(text, charsToEscape, afterBackslash) {
  533 + 'use strict';
  534 + // First we have to escape the escape characters so that
  535 + // we can build a character class out of them
  536 + var regexString = '([' + charsToEscape.replace(/([\[\]\\])/g, '\\$1') + '])';
  537 +
  538 + if (afterBackslash) {
  539 + regexString = '\\\\' + regexString;
  540 + }
  541 +
  542 + var regex = new RegExp(regexString, 'g');
  543 + text = text.replace(regex, escapeCharactersCallback);
  544 +
  545 + return text;
  546 +};
  547 +
  548 +var rgxFindMatchPos = function (str, left, right, flags) {
  549 + 'use strict';
  550 + var f = flags || '',
  551 + g = f.indexOf('g') > -1,
  552 + x = new RegExp(left + '|' + right, 'g' + f.replace(/g/g, '')),
  553 + l = new RegExp(left, f.replace(/g/g, '')),
  554 + pos = [],
  555 + t, s, m, start, end;
  556 +
  557 + do {
  558 + t = 0;
  559 + while ((m = x.exec(str))) {
  560 + if (l.test(m[0])) {
  561 + if (!(t++)) {
  562 + s = x.lastIndex;
  563 + start = s - m[0].length;
  564 + }
  565 + } else if (t) {
  566 + if (!--t) {
  567 + end = m.index + m[0].length;
  568 + var obj = {
  569 + left: {start: start, end: s},
  570 + match: {start: s, end: m.index},
  571 + right: {start: m.index, end: end},
  572 + wholeMatch: {start: start, end: end}
  573 + };
  574 + pos.push(obj);
  575 + if (!g) {
  576 + return pos;
  577 + }
  578 + }
  579 + }
  580 + }
  581 + } while (t && (x.lastIndex = s));
  582 +
  583 + return pos;
  584 +};
  585 +
  586 +/**
  587 + * matchRecursiveRegExp
  588 + *
  589 + * (c) 2007 Steven Levithan <stevenlevithan.com>
  590 + * MIT License
  591 + *
  592 + * Accepts a string to search, a left and right format delimiter
  593 + * as regex patterns, and optional regex flags. Returns an array
  594 + * of matches, allowing nested instances of left/right delimiters.
  595 + * Use the "g" flag to return all matches, otherwise only the
  596 + * first is returned. Be careful to ensure that the left and
  597 + * right format delimiters produce mutually exclusive matches.
  598 + * Backreferences are not supported within the right delimiter
  599 + * due to how it is internally combined with the left delimiter.
  600 + * When matching strings whose format delimiters are unbalanced
  601 + * to the left or right, the output is intentionally as a
  602 + * conventional regex library with recursion support would
  603 + * produce, e.g. "<<x>" and "<x>>" both produce ["x"] when using
  604 + * "<" and ">" as the delimiters (both strings contain a single,
  605 + * balanced instance of "<x>").
  606 + *
  607 + * examples:
  608 + * matchRecursiveRegExp("test", "\\(", "\\)")
  609 + * returns: []
  610 + * matchRecursiveRegExp("<t<<e>><s>>t<>", "<", ">", "g")
  611 + * returns: ["t<<e>><s>", ""]
  612 + * matchRecursiveRegExp("<div id=\"x\">test</div>", "<div\\b[^>]*>", "</div>", "gi")
  613 + * returns: ["test"]
  614 + */
  615 +showdown.helper.matchRecursiveRegExp = function (str, left, right, flags) {
  616 + 'use strict';
  617 +
  618 + var matchPos = rgxFindMatchPos (str, left, right, flags),
  619 + results = [];
  620 +
  621 + for (var i = 0; i < matchPos.length; ++i) {
  622 + results.push([
  623 + str.slice(matchPos[i].wholeMatch.start, matchPos[i].wholeMatch.end),
  624 + str.slice(matchPos[i].match.start, matchPos[i].match.end),
  625 + str.slice(matchPos[i].left.start, matchPos[i].left.end),
  626 + str.slice(matchPos[i].right.start, matchPos[i].right.end)
  627 + ]);
  628 + }
  629 + return results;
  630 +};
  631 +
  632 +/**
  633 + *
  634 + * @param {string} str
  635 + * @param {string|function} replacement
  636 + * @param {string} left
  637 + * @param {string} right
  638 + * @param {string} flags
  639 + * @returns {string}
  640 + */
  641 +showdown.helper.replaceRecursiveRegExp = function (str, replacement, left, right, flags) {
  642 + 'use strict';
  643 +
  644 + if (!showdown.helper.isFunction(replacement)) {
  645 + var repStr = replacement;
  646 + replacement = function () {
  647 + return repStr;
  648 + };
  649 + }
  650 +
  651 + var matchPos = rgxFindMatchPos(str, left, right, flags),
  652 + finalStr = str,
  653 + lng = matchPos.length;
  654 +
  655 + if (lng > 0) {
  656 + var bits = [];
  657 + if (matchPos[0].wholeMatch.start !== 0) {
  658 + bits.push(str.slice(0, matchPos[0].wholeMatch.start));
  659 + }
  660 + for (var i = 0; i < lng; ++i) {
  661 + bits.push(
  662 + replacement(
  663 + str.slice(matchPos[i].wholeMatch.start, matchPos[i].wholeMatch.end),
  664 + str.slice(matchPos[i].match.start, matchPos[i].match.end),
  665 + str.slice(matchPos[i].left.start, matchPos[i].left.end),
  666 + str.slice(matchPos[i].right.start, matchPos[i].right.end)
  667 + )
  668 + );
  669 + if (i < lng - 1) {
  670 + bits.push(str.slice(matchPos[i].wholeMatch.end, matchPos[i + 1].wholeMatch.start));
  671 + }
  672 + }
  673 + if (matchPos[lng - 1].wholeMatch.end < str.length) {
  674 + bits.push(str.slice(matchPos[lng - 1].wholeMatch.end));
  675 + }
  676 + finalStr = bits.join('');
  677 + }
  678 + return finalStr;
  679 +};
  680 +
  681 +/**
  682 + * POLYFILLS
  683 + */
  684 +if (showdown.helper.isUndefined(console)) {
  685 + console = {
  686 + warn: function (msg) {
  687 + 'use strict';
  688 + alert(msg);
  689 + },
  690 + log: function (msg) {
  691 + 'use strict';
  692 + alert(msg);
  693 + },
  694 + error: function (msg) {
  695 + 'use strict';
  696 + throw msg;
  697 + }
  698 + };
  699 +}
  700 +
  701 +/**
  702 + * Created by Estevao on 31-05-2015.
  703 + */
  704 +
  705 +/**
  706 + * Showdown Converter class
  707 + * @class
  708 + * @param {object} [converterOptions]
  709 + * @returns {Converter}
  710 + */
  711 +showdown.Converter = function (converterOptions) {
  712 + 'use strict';
  713 +
  714 + var
  715 + /**
  716 + * Options used by this converter
  717 + * @private
  718 + * @type {{}}
  719 + */
  720 + options = {},
  721 +
  722 + /**
  723 + * Language extensions used by this converter
  724 + * @private
  725 + * @type {Array}
  726 + */
  727 + langExtensions = [],
  728 +
  729 + /**
  730 + * Output modifiers extensions used by this converter
  731 + * @private
  732 + * @type {Array}
  733 + */
  734 + outputModifiers = [],
  735 +
  736 + /**
  737 + * Event listeners
  738 + * @private
  739 + * @type {{}}
  740 + */
  741 + listeners = {};
  742 +
  743 + _constructor();
  744 +
  745 + /**
  746 + * Converter constructor
  747 + * @private
  748 + */
  749 + function _constructor() {
  750 + converterOptions = converterOptions || {};
  751 +
  752 + for (var gOpt in globalOptions) {
  753 + if (globalOptions.hasOwnProperty(gOpt)) {
  754 + options[gOpt] = globalOptions[gOpt];
  755 + }
  756 + }
  757 +
  758 + // Merge options
  759 + if (typeof converterOptions === 'object') {
  760 + for (var opt in converterOptions) {
  761 + if (converterOptions.hasOwnProperty(opt)) {
  762 + options[opt] = converterOptions[opt];
  763 + }
  764 + }
  765 + } else {
  766 + throw Error('Converter expects the passed parameter to be an object, but ' + typeof converterOptions +
  767 + ' was passed instead.');
  768 + }
  769 +
  770 + if (options.extensions) {
  771 + showdown.helper.forEach(options.extensions, _parseExtension);
  772 + }
  773 + }
  774 +
  775 + /**
  776 + * Parse extension
  777 + * @param {*} ext
  778 + * @param {string} [name='']
  779 + * @private
  780 + */
  781 + function _parseExtension(ext, name) {
  782 +
  783 + name = name || null;
  784 + // If it's a string, the extension was previously loaded
  785 + if (showdown.helper.isString(ext)) {
  786 + ext = showdown.helper.stdExtName(ext);
  787 + name = ext;
  788 +
  789 + // LEGACY_SUPPORT CODE
  790 + if (showdown.extensions[ext]) {
  791 + console.warn('DEPRECATION WARNING: ' + ext + ' is an old extension that uses a deprecated loading method.' +
  792 + 'Please inform the developer that the extension should be updated!');
  793 + legacyExtensionLoading(showdown.extensions[ext], ext);
  794 + return;
  795 + // END LEGACY SUPPORT CODE
  796 +
  797 + } else if (!showdown.helper.isUndefined(extensions[ext])) {
  798 + ext = extensions[ext];
  799 +
  800 + } else {
  801 + throw Error('Extension "' + ext + '" could not be loaded. It was either not found or is not a valid extension.');
  802 + }
  803 + }
  804 +
  805 + if (typeof ext === 'function') {
  806 + ext = ext();
  807 + }
  808 +
  809 + if (!showdown.helper.isArray(ext)) {
  810 + ext = [ext];
  811 + }
  812 +
  813 + var validExt = validate(ext, name);
  814 + if (!validExt.valid) {
  815 + throw Error(validExt.error);
  816 + }
  817 +
  818 + for (var i = 0; i < ext.length; ++i) {
  819 + switch (ext[i].type) {
  820 +
  821 + case 'lang':
  822 + langExtensions.push(ext[i]);
  823 + break;
  824 +
  825 + case 'output':
  826 + outputModifiers.push(ext[i]);
  827 + break;
  828 + }
  829 + if (ext[i].hasOwnProperty(listeners)) {
  830 + for (var ln in ext[i].listeners) {
  831 + if (ext[i].listeners.hasOwnProperty(ln)) {
  832 + listen(ln, ext[i].listeners[ln]);
  833 + }
  834 + }
  835 + }
  836 + }
  837 +
  838 + }
  839 +
  840 + /**
  841 + * LEGACY_SUPPORT
  842 + * @param {*} ext
  843 + * @param {string} name
  844 + */
  845 + function legacyExtensionLoading(ext, name) {
  846 + if (typeof ext === 'function') {
  847 + ext = ext(new showdown.Converter());
  848 + }
  849 + if (!showdown.helper.isArray(ext)) {
  850 + ext = [ext];
  851 + }
  852 + var valid = validate(ext, name);
  853 +
  854 + if (!valid.valid) {
  855 + throw Error(valid.error);
  856 + }
  857 +
  858 + for (var i = 0; i < ext.length; ++i) {
  859 + switch (ext[i].type) {
  860 + case 'lang':
  861 + langExtensions.push(ext[i]);
  862 + break;
  863 + case 'output':
  864 + outputModifiers.push(ext[i]);
  865 + break;
  866 + default:// should never reach here
  867 + throw Error('Extension loader error: Type unrecognized!!!');
  868 + }
  869 + }
  870 + }
  871 +
  872 + /**
  873 + * Listen to an event
  874 + * @param {string} name
  875 + * @param {function} callback
  876 + */
  877 + function listen(name, callback) {
  878 + if (!showdown.helper.isString(name)) {
  879 + throw Error('Invalid argument in converter.listen() method: name must be a string, but ' + typeof name + ' given');
  880 + }
  881 +
  882 + if (typeof callback !== 'function') {
  883 + throw Error('Invalid argument in converter.listen() method: callback must be a function, but ' + typeof callback + ' given');
  884 + }
  885 +
  886 + if (!listeners.hasOwnProperty(name)) {
  887 + listeners[name] = [];
  888 + }
  889 + listeners[name].push(callback);
  890 + }
  891 +
  892 + function rTrimInputText(text) {
  893 + var rsp = text.match(/^\s*/)[0].length,
  894 + rgx = new RegExp('^\\s{0,' + rsp + '}', 'gm');
  895 + return text.replace(rgx, '');
  896 + }
  897 +
  898 + /**
  899 + * Dispatch an event
  900 + * @private
  901 + * @param {string} evtName Event name
  902 + * @param {string} text Text
  903 + * @param {{}} options Converter Options
  904 + * @param {{}} globals
  905 + * @returns {string}
  906 + */
  907 + this._dispatch = function dispatch (evtName, text, options, globals) {
  908 + if (listeners.hasOwnProperty(evtName)) {
  909 + for (var ei = 0; ei < listeners[evtName].length; ++ei) {
  910 + var nText = listeners[evtName][ei](evtName, text, this, options, globals);
  911 + if (nText && typeof nText !== 'undefined') {
  912 + text = nText;
  913 + }
  914 + }
  915 + }
  916 + return text;
  917 + };
  918 +
  919 + /**
  920 + * Listen to an event
  921 + * @param {string} name
  922 + * @param {function} callback
  923 + * @returns {showdown.Converter}
  924 + */
  925 + this.listen = function (name, callback) {
  926 + listen(name, callback);
  927 + return this;
  928 + };
  929 +
  930 + /**
  931 + * Converts a markdown string into HTML
  932 + * @param {string} text
  933 + * @returns {*}
  934 + */
  935 + this.makeHtml = function (text) {
  936 + //check if text is not falsy
  937 + if (!text) {
  938 + return text;
  939 + }
  940 +
  941 + var globals = {
  942 + gHtmlBlocks: [],
  943 + gHtmlMdBlocks: [],
  944 + gHtmlSpans: [],
  945 + gUrls: {},
  946 + gTitles: {},
  947 + gDimensions: {},
  948 + gListLevel: 0,
  949 + hashLinkCounts: {},
  950 + langExtensions: langExtensions,
  951 + outputModifiers: outputModifiers,
  952 + converter: this,
  953 + ghCodeBlocks: []
  954 + };
  955 +
  956 + // attacklab: Replace ~ with ~T
  957 + // This lets us use tilde as an escape char to avoid md5 hashes
  958 + // The choice of character is arbitrary; anything that isn't
  959 + // magic in Markdown will work.
  960 + text = text.replace(/~/g, '~T');
  961 +
  962 + // attacklab: Replace $ with ~D
  963 + // RegExp interprets $ as a special character
  964 + // when it's in a replacement string
  965 + text = text.replace(/\$/g, '~D');
  966 +
  967 + // Standardize line endings
  968 + text = text.replace(/\r\n/g, '\n'); // DOS to Unix
  969 + text = text.replace(/\r/g, '\n'); // Mac to Unix
  970 +
  971 + if (options.smartIndentationFix) {
  972 + text = rTrimInputText(text);
  973 + }
  974 +
  975 + // Make sure text begins and ends with a couple of newlines:
  976 + //text = '\n\n' + text + '\n\n';
  977 + text = text;
  978 + // detab
  979 + text = showdown.subParser('detab')(text, options, globals);
  980 +
  981 + // stripBlankLines
  982 + text = showdown.subParser('stripBlankLines')(text, options, globals);
  983 +
  984 + //run languageExtensions
  985 + showdown.helper.forEach(langExtensions, function (ext) {
  986 + text = showdown.subParser('runExtension')(ext, text, options, globals);
  987 + });
  988 +
  989 + // run the sub parsers
  990 + text = showdown.subParser('hashPreCodeTags')(text, options, globals);
  991 + text = showdown.subParser('githubCodeBlocks')(text, options, globals);
  992 + text = showdown.subParser('hashHTMLBlocks')(text, options, globals);
  993 + text = showdown.subParser('hashHTMLSpans')(text, options, globals);
  994 + text = showdown.subParser('stripLinkDefinitions')(text, options, globals);
  995 + text = showdown.subParser('blockGamut')(text, options, globals);
  996 + text = showdown.subParser('unhashHTMLSpans')(text, options, globals);
  997 + text = showdown.subParser('unescapeSpecialChars')(text, options, globals);
  998 +
  999 + // attacklab: Restore dollar signs
  1000 + text = text.replace(/~D/g, '$$');
  1001 +
  1002 + // attacklab: Restore tildes
  1003 + text = text.replace(/~T/g, '~');
  1004 +
  1005 + // Run output modifiers
  1006 + showdown.helper.forEach(outputModifiers, function (ext) {
  1007 + text = showdown.subParser('runExtension')(ext, text, options, globals);
  1008 + });
  1009 + return text;
  1010 + };
  1011 +
  1012 + /**
  1013 + * Set an option of this Converter instance
  1014 + * @param {string} key
  1015 + * @param {*} value
  1016 + */
  1017 + this.setOption = function (key, value) {
  1018 + options[key] = value;
  1019 + };
  1020 +
  1021 + /**
  1022 + * Get the option of this Converter instance
  1023 + * @param {string} key
  1024 + * @returns {*}
  1025 + */
  1026 + this.getOption = function (key) {
  1027 + return options[key];
  1028 + };
  1029 +
  1030 + /**
  1031 + * Get the options of this Converter instance
  1032 + * @returns {{}}
  1033 + */
  1034 + this.getOptions = function () {
  1035 + return options;
  1036 + };
  1037 +
  1038 + /**
  1039 + * Add extension to THIS converter
  1040 + * @param {{}} extension
  1041 + * @param {string} [name=null]
  1042 + */
  1043 + this.addExtension = function (extension, name) {
  1044 + name = name || null;
  1045 + _parseExtension(extension, name);
  1046 + };
  1047 +
  1048 + /**
  1049 + * Use a global registered extension with THIS converter
  1050 + * @param {string} extensionName Name of the previously registered extension
  1051 + */
  1052 + this.useExtension = function (extensionName) {
  1053 + _parseExtension(extensionName);
  1054 + };
  1055 +
  1056 + /**
  1057 + * Set the flavor THIS converter should use
  1058 + * @param {string} name
  1059 + */
  1060 + this.setFlavor = function (name) {
  1061 + if (flavor.hasOwnProperty(name)) {
  1062 + var preset = flavor[name];
  1063 + for (var option in preset) {
  1064 + if (preset.hasOwnProperty(option)) {
  1065 + options[option] = preset[option];
  1066 + }
  1067 + }
  1068 + }
  1069 + };
  1070 +
  1071 + /**
  1072 + * Remove an extension from THIS converter.
  1073 + * Note: This is a costly operation. It's better to initialize a new converter
  1074 + * and specify the extensions you wish to use
  1075 + * @param {Array} extension
  1076 + */
  1077 + this.removeExtension = function (extension) {
  1078 + if (!showdown.helper.isArray(extension)) {
  1079 + extension = [extension];
  1080 + }
  1081 + for (var a = 0; a < extension.length; ++a) {
  1082 + var ext = extension[a];
  1083 + for (var i = 0; i < langExtensions.length; ++i) {
  1084 + if (langExtensions[i] === ext) {
  1085 + langExtensions[i].splice(i, 1);
  1086 + }
  1087 + }
  1088 + for (var ii = 0; ii < outputModifiers.length; ++i) {
  1089 + if (outputModifiers[ii] === ext) {
  1090 + outputModifiers[ii].splice(i, 1);
  1091 + }
  1092 + }
  1093 + }
  1094 + };
  1095 +
  1096 + /**
  1097 + * Get all extension of THIS converter
  1098 + * @returns {{language: Array, output: Array}}
  1099 + */
  1100 + this.getAllExtensions = function () {
  1101 + return {
  1102 + language: langExtensions,
  1103 + output: outputModifiers
  1104 + };
  1105 + };
  1106 +};
  1107 +
  1108 +/**
  1109 + * Turn Markdown link shortcuts into XHTML <a> tags.
  1110 + */
  1111 +showdown.subParser('anchors', function (text, options, globals) {
  1112 + 'use strict';
  1113 +
  1114 + text = globals.converter._dispatch('anchors.before', text, options, globals);
  1115 +
  1116 + var writeAnchorTag = function (wholeMatch, m1, m2, m3, m4, m5, m6, m7) {
  1117 + if (showdown.helper.isUndefined(m7)) {
  1118 + m7 = '';
  1119 + }
  1120 + wholeMatch = m1;
  1121 + var linkText = m2,
  1122 + linkId = m3.toLowerCase(),
  1123 + url = m4,
  1124 + title = m7;
  1125 +
  1126 + if (!url) {
  1127 + if (!linkId) {
  1128 + // lower-case and turn embedded newlines into spaces
  1129 + linkId = linkText.toLowerCase().replace(/ ?\n/g, ' ');
  1130 + }
  1131 + url = '#' + linkId;
  1132 +
  1133 + if (!showdown.helper.isUndefined(globals.gUrls[linkId])) {
  1134 + url = globals.gUrls[linkId];
  1135 + if (!showdown.helper.isUndefined(globals.gTitles[linkId])) {
  1136 + title = globals.gTitles[linkId];
  1137 + }
  1138 + } else {
  1139 + if (wholeMatch.search(/\(\s*\)$/m) > -1) {
  1140 + // Special case for explicit empty url
  1141 + url = '';
  1142 + } else {
  1143 + return wholeMatch;
  1144 + }
  1145 + }
  1146 + }
  1147 +
  1148 + url = showdown.helper.escapeCharacters(url, '*_', false);
  1149 + var result = '<a href="' + url + '"';
  1150 +
  1151 + if (title !== '' && title !== null) {
  1152 + title = title.replace(/"/g, '&quot;');
  1153 + title = showdown.helper.escapeCharacters(title, '*_', false);
  1154 + result += ' title="' + title + '"';
  1155 + }
  1156 +
  1157 + result += '>' + linkText + '</a>';
  1158 +
  1159 + return result;
  1160 + };
  1161 +
  1162 + // First, handle reference-style links: [link text] [id]
  1163 + /*
  1164 + text = text.replace(/
  1165 + ( // wrap whole match in $1
  1166 + \[
  1167 + (
  1168 + (?:
  1169 + \[[^\]]*\] // allow brackets nested one level
  1170 + |
  1171 + [^\[] // or anything else
  1172 + )*
  1173 + )
  1174 + \]
  1175 +
  1176 + [ ]? // one optional space
  1177 + (?:\n[ ]*)? // one optional newline followed by spaces
  1178 +
  1179 + \[
  1180 + (.*?) // id = $3
  1181 + \]
  1182 + )()()()() // pad remaining backreferences
  1183 + /g,_DoAnchors_callback);
  1184 + */
  1185 + text = text.replace(/(\[((?:\[[^\]]*]|[^\[\]])*)][ ]?(?:\n[ ]*)?\[(.*?)])()()()()/g, writeAnchorTag);
  1186 +
  1187 + //
  1188 + // Next, inline-style links: [link text](url "optional title")
  1189 + //
  1190 +
  1191 + /*
  1192 + text = text.replace(/
  1193 + ( // wrap whole match in $1
  1194 + \[
  1195 + (
  1196 + (?:
  1197 + \[[^\]]*\] // allow brackets nested one level
  1198 + |
  1199 + [^\[\]] // or anything else
  1200 + )
  1201 + )
  1202 + \]
  1203 + \( // literal paren
  1204 + [ \t]*
  1205 + () // no id, so leave $3 empty
  1206 + <?(.*?)>? // href = $4
  1207 + [ \t]*
  1208 + ( // $5
  1209 + (['"]) // quote char = $6
  1210 + (.*?) // Title = $7
  1211 + \6 // matching quote
  1212 + [ \t]* // ignore any spaces/tabs between closing quote and )
  1213 + )? // title is optional
  1214 + \)
  1215 + )
  1216 + /g,writeAnchorTag);
  1217 + */
  1218 + text = text.replace(/(\[((?:\[[^\]]*]|[^\[\]])*)]\([ \t]*()<?(.*?(?:\(.*?\).*?)?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,
  1219 + writeAnchorTag);
  1220 +
  1221 + //
  1222 + // Last, handle reference-style shortcuts: [link text]
  1223 + // These must come last in case you've also got [link test][1]
  1224 + // or [link test](/foo)
  1225 + //
  1226 +
  1227 + /*
  1228 + text = text.replace(/
  1229 + ( // wrap whole match in $1
  1230 + \[
  1231 + ([^\[\]]+) // link text = $2; can't contain '[' or ']'
  1232 + \]
  1233 + )()()()()() // pad rest of backreferences
  1234 + /g, writeAnchorTag);
  1235 + */
  1236 + text = text.replace(/(\[([^\[\]]+)])()()()()()/g, writeAnchorTag);
  1237 +
  1238 + text = globals.converter._dispatch('anchors.after', text, options, globals);
  1239 + return text;
  1240 +});
  1241 +
  1242 +showdown.subParser('autoLinks', function (text, options, globals) {
  1243 + 'use strict';
  1244 +
  1245 + text = globals.converter._dispatch('autoLinks.before', text, options, globals);
  1246 +
  1247 + var simpleURLRegex = /\b(((https?|ftp|dict):\/\/|www\.)[^'">\s]+\.[^'">\s]+)(?=\s|$)(?!["<>])/gi,
  1248 + delimUrlRegex = /<(((https?|ftp|dict):\/\/|www\.)[^'">\s]+)>/gi,
  1249 + simpleMailRegex = /(?:^|[ \n\t])([A-Za-z0-9!#$%&'*+-/=?^_`\{|}~\.]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)(?:$|[ \n\t])/gi,
  1250 + delimMailRegex = /<(?:mailto:)?([-.\w]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi;
  1251 +
  1252 + text = text.replace(delimUrlRegex, replaceLink);
  1253 + text = text.replace(delimMailRegex, replaceMail);
  1254 + // simpleURLRegex = /\b(((https?|ftp|dict):\/\/|www\.)[-.+~:?#@!$&'()*,;=[\]\w]+)\b/gi,
  1255 + // Email addresses: <address@domain.foo>
  1256 +
  1257 + if (options.simplifiedAutoLink) {
  1258 + text = text.replace(simpleURLRegex, replaceLink);
  1259 + text = text.replace(simpleMailRegex, replaceMail);
  1260 + }
  1261 +
  1262 + function replaceLink(wm, link) {
  1263 + var lnkTxt = link;
  1264 + if (/^www\./i.test(link)) {
  1265 + link = link.replace(/^www\./i, 'http://www.');
  1266 + }
  1267 + return '<a href="' + link + '">' + lnkTxt + '</a>';
  1268 + }
  1269 +
  1270 + function replaceMail(wholeMatch, m1) {
  1271 + var unescapedStr = showdown.subParser('unescapeSpecialChars')(m1);
  1272 + return showdown.subParser('encodeEmailAddress')(unescapedStr);
  1273 + }
  1274 +
  1275 + text = globals.converter._dispatch('autoLinks.after', text, options, globals);
  1276 +
  1277 + return text;
  1278 +});
  1279 +
  1280 +/**
  1281 + * These are all the transformations that form block-level
  1282 + * tags like paragraphs, headers, and list items.
  1283 + */
  1284 +showdown.subParser('blockGamut', function (text, options, globals) {
  1285 + 'use strict';
  1286 +
  1287 + text = globals.converter._dispatch('blockGamut.before', text, options, globals);
  1288 +
  1289 + // we parse blockquotes first so that we can have headings and hrs
  1290 + // inside blockquotes
  1291 + text = showdown.subParser('blockQuotes')(text, options, globals);
  1292 + text = showdown.subParser('headers')(text, options, globals);
  1293 +
  1294 + // Do Horizontal Rules:
  1295 + var key = showdown.subParser('hashBlock')('<hr />', options, globals);
  1296 + text = text.replace(/^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$/gm, key);
  1297 + text = text.replace(/^[ ]{0,2}([ ]?\-[ ]?){3,}[ \t]*$/gm, key);
  1298 + text = text.replace(/^[ ]{0,2}([ ]?_[ ]?){3,}[ \t]*$/gm, key);
  1299 +
  1300 + text = showdown.subParser('lists')(text, options, globals);
  1301 + text = showdown.subParser('codeBlocks')(text, options, globals);
  1302 + text = showdown.subParser('tables')(text, options, globals);
  1303 +
  1304 + // We already ran _HashHTMLBlocks() before, in Markdown(), but that
  1305 + // was to escape raw HTML in the original Markdown source. This time,
  1306 + // we're escaping the markup we've just created, so that we don't wrap
  1307 + // <p> tags around block-level tags.
  1308 + text = showdown.subParser('hashHTMLBlocks')(text, options, globals);
  1309 + text = showdown.subParser('paragraphs')(text, options, globals);
  1310 +
  1311 + text = globals.converter._dispatch('blockGamut.after', text, options, globals);
  1312 +
  1313 + return text;
  1314 +});
  1315 +
  1316 +showdown.subParser('blockQuotes', function (text, options, globals) {
  1317 + 'use strict';
  1318 +
  1319 + text = globals.converter._dispatch('blockQuotes.before', text, options, globals);
  1320 + /*
  1321 + text = text.replace(/
  1322 + ( // Wrap whole match in $1
  1323 + (
  1324 + ^[ \t]*>[ \t]? // '>' at the start of a line
  1325 + .+\n // rest of the first line
  1326 + (.+\n)* // subsequent consecutive lines
  1327 + \n* // blanks
  1328 + )+
  1329 + )
  1330 + /gm, function(){...});
  1331 + */
  1332 +
  1333 + text = text.replace(/((^[ \t]{0,3}>[ \t]?.+\n(.+\n)*\n*)+)/gm, function (wholeMatch, m1) {
  1334 + var bq = m1;
  1335 +
  1336 + // attacklab: hack around Konqueror 3.5.4 bug:
  1337 + // "----------bug".replace(/^-/g,"") == "bug"
  1338 + bq = bq.replace(/^[ \t]*>[ \t]?/gm, '~0'); // trim one level of quoting
  1339 +
  1340 + // attacklab: clean up hack
  1341 + bq = bq.replace(/~0/g, '');
  1342 +
  1343 + bq = bq.replace(/^[ \t]+$/gm, ''); // trim whitespace-only lines
  1344 + bq = showdown.subParser('githubCodeBlocks')(bq, options, globals);
  1345 + bq = showdown.subParser('blockGamut')(bq, options, globals); // recurse
  1346 +
  1347 + bq = bq.replace(/(^|\n)/g, '$1 ');
  1348 + // These leading spaces screw with <pre> content, so we need to fix that:
  1349 + bq = bq.replace(/(\s*<pre>[^\r]+?<\/pre>)/gm, function (wholeMatch, m1) {
  1350 + var pre = m1;
  1351 + // attacklab: hack around Konqueror 3.5.4 bug:
  1352 + pre = pre.replace(/^ /mg, '~0');
  1353 + pre = pre.replace(/~0/g, '');
  1354 + return pre;
  1355 + });
  1356 +
  1357 + return showdown.subParser('hashBlock')('<blockquote>\n' + bq + '\n</blockquote>', options, globals);
  1358 + });
  1359 +
  1360 + text = globals.converter._dispatch('blockQuotes.after', text, options, globals);
  1361 + return text;
  1362 +});
  1363 +
  1364 +/**
  1365 + * Process Markdown `<pre><code>` blocks.
  1366 + */
  1367 +showdown.subParser('codeBlocks', function (text, options, globals) {
  1368 + 'use strict';
  1369 +
  1370 + text = globals.converter._dispatch('codeBlocks.before', text, options, globals);
  1371 + /*
  1372 + text = text.replace(text,
  1373 + /(?:\n\n|^)
  1374 + ( // $1 = the code block -- one or more lines, starting with a space/tab
  1375 + (?:
  1376 + (?:[ ]{4}|\t) // Lines must start with a tab or a tab-width of spaces - attacklab: g_tab_width
  1377 + .*\n+
  1378 + )+
  1379 + )
  1380 + (\n*[ ]{0,3}[^ \t\n]|(?=~0)) // attacklab: g_tab_width
  1381 + /g,function(){...});
  1382 + */
  1383 +
  1384 + // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug
  1385 + text += '~0';
  1386 +
  1387 + var pattern = /(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g;
  1388 + text = text.replace(pattern, function (wholeMatch, m1, m2) {
  1389 + var codeblock = m1,
  1390 + nextChar = m2,
  1391 + end = '\n';
  1392 +
  1393 + codeblock = showdown.subParser('outdent')(codeblock);
  1394 + codeblock = showdown.subParser('encodeCode')(codeblock);
  1395 + codeblock = showdown.subParser('detab')(codeblock);
  1396 + codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines
  1397 + codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing newlines
  1398 +
  1399 + if (options.omitExtraWLInCodeBlocks) {
  1400 + end = '';
  1401 + }
  1402 +
  1403 + codeblock = '<pre><code>' + codeblock + end + '</code></pre>';
  1404 +
  1405 + return showdown.subParser('hashBlock')(codeblock, options, globals) + nextChar;
  1406 + });
  1407 +
  1408 + // attacklab: strip sentinel
  1409 + text = text.replace(/~0/, '');
  1410 +
  1411 + text = globals.converter._dispatch('codeBlocks.after', text, options, globals);
  1412 + return text;
  1413 +});
  1414 +
  1415 +/**
  1416 + *
  1417 + * * Backtick quotes are used for <code></code> spans.
  1418 + *
  1419 + * * You can use multiple backticks as the delimiters if you want to
  1420 + * include literal backticks in the code span. So, this input:
  1421 + *
  1422 + * Just type ``foo `bar` baz`` at the prompt.
  1423 + *
  1424 + * Will translate to:
  1425 + *
  1426 + * <p>Just type <code>foo `bar` baz</code> at the prompt.</p>
  1427 + *
  1428 + * There's no arbitrary limit to the number of backticks you
  1429 + * can use as delimters. If you need three consecutive backticks
  1430 + * in your code, use four for delimiters, etc.
  1431 + *
  1432 + * * You can use spaces to get literal backticks at the edges:
  1433 + *
  1434 + * ... type `` `bar` `` ...
  1435 + *
  1436 + * Turns to:
  1437 + *
  1438 + * ... type <code>`bar`</code> ...
  1439 + */
  1440 +showdown.subParser('codeSpans', function (text, options, globals) {
  1441 + 'use strict';
  1442 +
  1443 + text = globals.converter._dispatch('codeSpans.before', text, options, globals);
  1444 +
  1445 + /*
  1446 + text = text.replace(/
  1447 + (^|[^\\]) // Character before opening ` can't be a backslash
  1448 + (`+) // $2 = Opening run of `
  1449 + ( // $3 = The code block
  1450 + [^\r]*?
  1451 + [^`] // attacklab: work around lack of lookbehind
  1452 + )
  1453 + \2 // Matching closer
  1454 + (?!`)
  1455 + /gm, function(){...});
  1456 + */
  1457 +
  1458 + if (typeof(text) === 'undefined') {
  1459 + text = '';
  1460 + }
  1461 + text = text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,
  1462 + function (wholeMatch, m1, m2, m3) {
  1463 + var c = m3;
  1464 + c = c.replace(/^([ \t]*)/g, ''); // leading whitespace
  1465 + c = c.replace(/[ \t]*$/g, ''); // trailing whitespace
  1466 + c = showdown.subParser('encodeCode')(c);
  1467 + return m1 + '<code>' + c + '</code>';
  1468 + }
  1469 + );
  1470 +
  1471 + text = globals.converter._dispatch('codeSpans.after', text, options, globals);
  1472 + return text;
  1473 +});
  1474 +
  1475 +/**
  1476 + * Convert all tabs to spaces
  1477 + */
  1478 +showdown.subParser('detab', function (text) {
  1479 + 'use strict';
  1480 +
  1481 + // expand first n-1 tabs
  1482 + text = text.replace(/\t(?=\t)/g, ' '); // g_tab_width
  1483 +
  1484 + // replace the nth with two sentinels
  1485 + text = text.replace(/\t/g, '~A~B');
  1486 +
  1487 + // use the sentinel to anchor our regex so it doesn't explode
  1488 + text = text.replace(/~B(.+?)~A/g, function (wholeMatch, m1) {
  1489 + var leadingText = m1,
  1490 + numSpaces = 4 - leadingText.length % 4; // g_tab_width
  1491 +
  1492 + // there *must* be a better way to do this:
  1493 + for (var i = 0; i < numSpaces; i++) {
  1494 + leadingText += ' ';
  1495 + }
  1496 +
  1497 + return leadingText;
  1498 + });
  1499 +
  1500 + // clean up sentinels
  1501 + text = text.replace(/~A/g, ' '); // g_tab_width
  1502 + text = text.replace(/~B/g, '');
  1503 +
  1504 + return text;
  1505 +
  1506 +});
  1507 +
  1508 +/**
  1509 + * Smart processing for ampersands and angle brackets that need to be encoded.
  1510 + */
  1511 +showdown.subParser('encodeAmpsAndAngles', function (text) {
  1512 + 'use strict';
  1513 + // Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin:
  1514 + // http://bumppo.net/projects/amputator/
  1515 + text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g, '&amp;');
  1516 +
  1517 + // Encode naked <'s
  1518 + text = text.replace(/<(?![a-z\/?\$!])/gi, '&lt;');
  1519 +
  1520 + return text;
  1521 +});
  1522 +
  1523 +/**
  1524 + * Returns the string, with after processing the following backslash escape sequences.
  1525 + *
  1526 + * attacklab: The polite way to do this is with the new escapeCharacters() function:
  1527 + *
  1528 + * text = escapeCharacters(text,"\\",true);
  1529 + * text = escapeCharacters(text,"`*_{}[]()>#+-.!",true);
  1530 + *
  1531 + * ...but we're sidestepping its use of the (slow) RegExp constructor
  1532 + * as an optimization for Firefox. This function gets called a LOT.
  1533 + */
  1534 +showdown.subParser('encodeBackslashEscapes', function (text) {
  1535 + 'use strict';
  1536 + text = text.replace(/\\(\\)/g, showdown.helper.escapeCharactersCallback);
  1537 + text = text.replace(/\\([`*_{}\[\]()>#+-.!])/g, showdown.helper.escapeCharactersCallback);
  1538 + return text;
  1539 +});
  1540 +
  1541 +/**
  1542 + * Encode/escape certain characters inside Markdown code runs.
  1543 + * The point is that in code, these characters are literals,
  1544 + * and lose their special Markdown meanings.
  1545 + */
  1546 +showdown.subParser('encodeCode', function (text) {
  1547 + 'use strict';
  1548 +
  1549 + // Encode all ampersands; HTML entities are not
  1550 + // entities within a Markdown code span.
  1551 + text = text.replace(/&/g, '&amp;');
  1552 +
  1553 + // Do the angle bracket song and dance:
  1554 + text = text.replace(/</g, '&lt;');
  1555 + text = text.replace(/>/g, '&gt;');
  1556 +
  1557 + // Now, escape characters that are magic in Markdown:
  1558 + text = showdown.helper.escapeCharacters(text, '*_{}[]\\', false);
  1559 +
  1560 + // jj the line above breaks this:
  1561 + //---
  1562 + //* Item
  1563 + // 1. Subitem
  1564 + // special char: *
  1565 + // ---
  1566 +
  1567 + return text;
  1568 +});
  1569 +
  1570 +/**
  1571 + * Input: an email address, e.g. "foo@example.com"
  1572 + *
  1573 + * Output: the email address as a mailto link, with each character
  1574 + * of the address encoded as either a decimal or hex entity, in
  1575 + * the hopes of foiling most address harvesting spam bots. E.g.:
  1576 + *
  1577 + * <a href="&#x6D;&#97;&#105;&#108;&#x74;&#111;:&#102;&#111;&#111;&#64;&#101;
  1578 + * x&#x61;&#109;&#x70;&#108;&#x65;&#x2E;&#99;&#111;&#109;">&#102;&#111;&#111;
  1579 + * &#64;&#101;x&#x61;&#109;&#x70;&#108;&#x65;&#x2E;&#99;&#111;&#109;</a>
  1580 + *
  1581 + * Based on a filter by Matthew Wickline, posted to the BBEdit-Talk
  1582 + * mailing list: <http://tinyurl.com/yu7ue>
  1583 + *
  1584 + */
  1585 +showdown.subParser('encodeEmailAddress', function (addr) {
  1586 + 'use strict';
  1587 +
  1588 + var encode = [
  1589 + function (ch) {
  1590 + return '&#' + ch.charCodeAt(0) + ';';
  1591 + },
  1592 + function (ch) {
  1593 + return '&#x' + ch.charCodeAt(0).toString(16) + ';';
  1594 + },
  1595 + function (ch) {
  1596 + return ch;
  1597 + }
  1598 + ];
  1599 +
  1600 + addr = 'mailto:' + addr;
  1601 +
  1602 + addr = addr.replace(/./g, function (ch) {
  1603 + if (ch === '@') {
  1604 + // this *must* be encoded. I insist.
  1605 + ch = encode[Math.floor(Math.random() * 2)](ch);
  1606 + } else if (ch !== ':') {
  1607 + // leave ':' alone (to spot mailto: later)
  1608 + var r = Math.random();
  1609 + // roughly 10% raw, 45% hex, 45% dec
  1610 + ch = (
  1611 + r > 0.9 ? encode[2](ch) : r > 0.45 ? encode[1](ch) : encode[0](ch)
  1612 + );
  1613 + }
  1614 + return ch;
  1615 + });
  1616 +
  1617 + addr = '<a href="' + addr + '">' + addr + '</a>';
  1618 + addr = addr.replace(/">.+:/g, '">'); // strip the mailto: from the visible part
  1619 +
  1620 + return addr;
  1621 +});
  1622 +
  1623 +/**
  1624 + * Within tags -- meaning between < and > -- encode [\ ` * _] so they
  1625 + * don't conflict with their use in Markdown for code, italics and strong.
  1626 + */
  1627 +showdown.subParser('escapeSpecialCharsWithinTagAttributes', function (text) {
  1628 + 'use strict';
  1629 +
  1630 + // Build a regex to find HTML tags and comments. See Friedl's
  1631 + // "Mastering Regular Expressions", 2nd Ed., pp. 200-201.
  1632 + var regex = /(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|<!(--.*?--\s*)+>)/gi;
  1633 +
  1634 + text = text.replace(regex, function (wholeMatch) {
  1635 + var tag = wholeMatch.replace(/(.)<\/?code>(?=.)/g, '$1`');
  1636 + tag = showdown.helper.escapeCharacters(tag, '\\`*_', false);
  1637 + return tag;
  1638 + });
  1639 +
  1640 + return text;
  1641 +});
  1642 +
  1643 +/**
  1644 + * Handle github codeblocks prior to running HashHTML so that
  1645 + * HTML contained within the codeblock gets escaped properly
  1646 + * Example:
  1647 + * ```ruby
  1648 + * def hello_world(x)
  1649 + * puts "Hello, #{x}"
  1650 + * end
  1651 + * ```
  1652 + */
  1653 +showdown.subParser('githubCodeBlocks', function (text, options, globals) {
  1654 + 'use strict';
  1655 +
  1656 + // early exit if option is not enabled
  1657 + if (!options.ghCodeBlocks) {
  1658 + return text;
  1659 + }
  1660 +
  1661 + text = globals.converter._dispatch('githubCodeBlocks.before', text, options, globals);
  1662 +
  1663 + text += '~0';
  1664 +
  1665 + text = text.replace(/(?:^|\n)```(.*)\n([\s\S]*?)\n```/g, function (wholeMatch, language, codeblock) {
  1666 + var end = (options.omitExtraWLInCodeBlocks) ? '' : '\n';
  1667 +
  1668 + // First parse the github code block
  1669 + codeblock = showdown.subParser('encodeCode')(codeblock);
  1670 + codeblock = showdown.subParser('detab')(codeblock);
  1671 + codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines
  1672 + codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing whitespace
  1673 +
  1674 + codeblock = '<pre><code' + (language ? ' class="' + language + ' language-' + language + '"' : '') + '>' + codeblock + end + '</code></pre>';
  1675 +
  1676 + codeblock = showdown.subParser('hashBlock')(codeblock, options, globals);
  1677 +
  1678 + // Since GHCodeblocks can be false positives, we need to
  1679 + // store the primitive text and the parsed text in a global var,
  1680 + // and then return a token
  1681 + return '\n\n~G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\n\n';
  1682 + });
  1683 +
  1684 + // attacklab: strip sentinel
  1685 + text = text.replace(/~0/, '');
  1686 +
  1687 + return globals.converter._dispatch('githubCodeBlocks.after', text, options, globals);
  1688 +});
  1689 +
  1690 +showdown.subParser('hashBlock', function (text, options, globals) {
  1691 + 'use strict';
  1692 + text = text.replace(/(^\n+|\n+$)/g, '');
  1693 + return '\n\n~K' + (globals.gHtmlBlocks.push(text) - 1) + 'K\n\n';
  1694 +});
  1695 +
  1696 +showdown.subParser('hashElement', function (text, options, globals) {
  1697 + 'use strict';
  1698 +
  1699 + return function (wholeMatch, m1) {
  1700 + var blockText = m1;
  1701 +
  1702 + // Undo double lines
  1703 + blockText = blockText.replace(/\n\n/g, '\n');
  1704 + blockText = blockText.replace(/^\n/, '');
  1705 +
  1706 + // strip trailing blank lines
  1707 + blockText = blockText.replace(/\n+$/g, '');
  1708 +
  1709 + // Replace the element text with a marker ("~KxK" where x is its key)
  1710 + blockText = '\n\n~K' + (globals.gHtmlBlocks.push(blockText) - 1) + 'K\n\n';
  1711 +
  1712 + return blockText;
  1713 + };
  1714 +});
  1715 +
  1716 +showdown.subParser('hashHTMLBlocks', function (text, options, globals) {
  1717 + 'use strict';
  1718 +
  1719 + var blockTags = [
  1720 + 'pre',
  1721 + 'div',
  1722 + 'h1',
  1723 + 'h2',
  1724 + 'h3',
  1725 + 'h4',
  1726 + 'h5',
  1727 + 'h6',
  1728 + 'blockquote',
  1729 + 'table',
  1730 + 'dl',
  1731 + 'ol',
  1732 + 'ul',
  1733 + 'script',
  1734 + 'noscript',
  1735 + 'form',
  1736 + 'fieldset',
  1737 + 'iframe',
  1738 + 'math',
  1739 + 'style',
  1740 + 'section',
  1741 + 'header',
  1742 + 'footer',
  1743 + 'nav',
  1744 + 'article',
  1745 + 'aside',
  1746 + 'address',
  1747 + 'audio',
  1748 + 'canvas',
  1749 + 'figure',
  1750 + 'hgroup',
  1751 + 'output',
  1752 + 'video',
  1753 + 'p'
  1754 + ],
  1755 + repFunc = function (wholeMatch, match, left, right) {
  1756 + var txt = wholeMatch;
  1757 + // check if this html element is marked as markdown
  1758 + // if so, it's contents should be parsed as markdown
  1759 + if (left.search(/\bmarkdown\b/) !== -1) {
  1760 + txt = left + globals.converter.makeHtml(match) + right;
  1761 + }
  1762 + return '\n\n~K' + (globals.gHtmlBlocks.push(txt) - 1) + 'K\n\n';
  1763 + };
  1764 +
  1765 + for (var i = 0; i < blockTags.length; ++i) {
  1766 + text = showdown.helper.replaceRecursiveRegExp(text, repFunc, '^(?: |\\t){0,3}<' + blockTags[i] + '\\b[^>]*>', '</' + blockTags[i] + '>', 'gim');
  1767 + }
  1768 +
  1769 + // HR SPECIAL CASE
  1770 + text = text.replace(/(\n[ ]{0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,
  1771 + showdown.subParser('hashElement')(text, options, globals));
  1772 +
  1773 + // Special case for standalone HTML comments:
  1774 + text = text.replace(/(<!--[\s\S]*?-->)/g,
  1775 + showdown.subParser('hashElement')(text, options, globals));
  1776 +
  1777 + // PHP and ASP-style processor instructions (<?...?> and <%...%>)
  1778 + text = text.replace(/(?:\n\n)([ ]{0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,
  1779 + showdown.subParser('hashElement')(text, options, globals));
  1780 + return text;
  1781 +});
  1782 +
  1783 +/**
  1784 + * Hash span elements that should not be parsed as markdown
  1785 + */
  1786 +showdown.subParser('hashHTMLSpans', function (text, config, globals) {
  1787 + 'use strict';
  1788 +
  1789 + var matches = showdown.helper.matchRecursiveRegExp(text, '<code\\b[^>]*>', '</code>', 'gi');
  1790 +
  1791 + for (var i = 0; i < matches.length; ++i) {
  1792 + text = text.replace(matches[i][0], '~L' + (globals.gHtmlSpans.push(matches[i][0]) - 1) + 'L');
  1793 + }
  1794 + return text;
  1795 +});
  1796 +
  1797 +/**
  1798 + * Unhash HTML spans
  1799 + */
  1800 +showdown.subParser('unhashHTMLSpans', function (text, config, globals) {
  1801 + 'use strict';
  1802 +
  1803 + for (var i = 0; i < globals.gHtmlSpans.length; ++i) {
  1804 + text = text.replace('~L' + i + 'L', globals.gHtmlSpans[i]);
  1805 + }
  1806 +
  1807 + return text;
  1808 +});
  1809 +
  1810 +/**
  1811 + * Hash span elements that should not be parsed as markdown
  1812 + */
  1813 +showdown.subParser('hashPreCodeTags', function (text, config, globals) {
  1814 + 'use strict';
  1815 +
  1816 + var repFunc = function (wholeMatch, match, left, right) {
  1817 + // encode html entities
  1818 + var codeblock = left + showdown.subParser('encodeCode')(match) + right;
  1819 + return '\n\n~G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\n\n';
  1820 + };
  1821 +
  1822 + text = showdown.helper.replaceRecursiveRegExp(text, repFunc, '^(?: |\\t){0,3}<pre\\b[^>]*>\\s*<code\\b[^>]*>', '^(?: |\\t){0,3}</code>\\s*</pre>', 'gim');
  1823 + return text;
  1824 +});
  1825 +
  1826 +showdown.subParser('headers', function (text, options, globals) {
  1827 + 'use strict';
  1828 +
  1829 + text = globals.converter._dispatch('headers.before', text, options, globals);
  1830 +
  1831 + var prefixHeader = options.prefixHeaderId,
  1832 + headerLevelStart = (isNaN(parseInt(options.headerLevelStart))) ? 1 : parseInt(options.headerLevelStart),
  1833 +
  1834 + // Set text-style headers:
  1835 + // Header 1
  1836 + // ========
  1837 + //
  1838 + // Header 2
  1839 + // --------
  1840 + //
  1841 + setextRegexH1 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n={2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n=+[ \t]*\n+/gm,
  1842 + setextRegexH2 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n-{2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n-+[ \t]*\n+/gm;
  1843 +
  1844 + text = text.replace(setextRegexH1, function (wholeMatch, m1) {
  1845 +
  1846 + var spanGamut = showdown.subParser('spanGamut')(m1, options, globals),
  1847 + hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"',
  1848 + hLevel = headerLevelStart,
  1849 + hashBlock = '<h' + hLevel + hID + '>' + spanGamut + '</h' + hLevel + '>';
  1850 + return showdown.subParser('hashBlock')(hashBlock, options, globals);
  1851 + });
  1852 +
  1853 + text = text.replace(setextRegexH2, function (matchFound, m1) {
  1854 + var spanGamut = showdown.subParser('spanGamut')(m1, options, globals),
  1855 + hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"',
  1856 + hLevel = headerLevelStart + 1,
  1857 + hashBlock = '<h' + hLevel + hID + '>' + spanGamut + '</h' + hLevel + '>';
  1858 + return showdown.subParser('hashBlock')(hashBlock, options, globals);
  1859 + });
  1860 +
  1861 + // atx-style headers:
  1862 + // # Header 1
  1863 + // ## Header 2
  1864 + // ## Header 2 with closing hashes ##
  1865 + // ...
  1866 + // ###### Header 6
  1867 + //
  1868 + text = text.replace(/^(#{1,6})[ \t]*(.+?)[ \t]*#*\n+/gm, function (wholeMatch, m1, m2) {
  1869 + var span = showdown.subParser('spanGamut')(m2, options, globals),
  1870 + hID = (options.noHeaderId) ? '' : ' id="' + headerId(m2) + '"',
  1871 + hLevel = headerLevelStart - 1 + m1.length,
  1872 + header = '<h' + hLevel + hID + '>' + span + '</h' + hLevel + '>';
  1873 +
  1874 + return showdown.subParser('hashBlock')(header, options, globals);
  1875 + });
  1876 +
  1877 + function headerId(m) {
  1878 + var title, escapedId = m.replace(/[^\w]/g, '').toLowerCase();
  1879 +
  1880 + if (globals.hashLinkCounts[escapedId]) {
  1881 + title = escapedId + '-' + (globals.hashLinkCounts[escapedId]++);
  1882 + } else {
  1883 + title = escapedId;
  1884 + globals.hashLinkCounts[escapedId] = 1;
  1885 + }
  1886 +
  1887 + // Prefix id to prevent causing inadvertent pre-existing style matches.
  1888 + if (prefixHeader === true) {
  1889 + prefixHeader = 'section';
  1890 + }
  1891 +
  1892 + if (showdown.helper.isString(prefixHeader)) {
  1893 + return prefixHeader + title;
  1894 + }
  1895 + return title;
  1896 + }
  1897 +
  1898 + text = globals.converter._dispatch('headers.after', text, options, globals);
  1899 + return text;
  1900 +});
  1901 +
  1902 +/**
  1903 + * Turn Markdown image shortcuts into <img> tags.
  1904 + */
  1905 +showdown.subParser('images', function (text, options, globals) {
  1906 + 'use strict';
  1907 +
  1908 + text = globals.converter._dispatch('images.before', text, options, globals);
  1909 +
  1910 + var inlineRegExp = /!\[(.*?)]\s?\([ \t]*()<?(\S+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(['"])(.*?)\6[ \t]*)?\)/g,
  1911 + referenceRegExp = /!\[([^\]]*?)] ?(?:\n *)?\[(.*?)]()()()()()/g;
  1912 +
  1913 + function writeImageTag (wholeMatch, altText, linkId, url, width, height, m5, title) {
  1914 +
  1915 + var gUrls = globals.gUrls,
  1916 + gTitles = globals.gTitles,
  1917 + gDims = globals.gDimensions;
  1918 +
  1919 + linkId = linkId.toLowerCase();
  1920 +
  1921 + if (!title) {
  1922 + title = '';
  1923 + }
  1924 +
  1925 + if (url === '' || url === null) {
  1926 + if (linkId === '' || linkId === null) {
  1927 + // lower-case and turn embedded newlines into spaces
  1928 + linkId = altText.toLowerCase().replace(/ ?\n/g, ' ');
  1929 + }
  1930 + url = '#' + linkId;
  1931 +
  1932 + if (!showdown.helper.isUndefined(gUrls[linkId])) {
  1933 + url = gUrls[linkId];
  1934 + if (!showdown.helper.isUndefined(gTitles[linkId])) {
  1935 + title = gTitles[linkId];
  1936 + }
  1937 + if (!showdown.helper.isUndefined(gDims[linkId])) {
  1938 + width = gDims[linkId].width;
  1939 + height = gDims[linkId].height;
  1940 + }
  1941 + } else {
  1942 + return wholeMatch;
  1943 + }
  1944 + }
  1945 +
  1946 + altText = altText.replace(/"/g, '&quot;');
  1947 + altText = showdown.helper.escapeCharacters(altText, '*_', false);
  1948 + url = showdown.helper.escapeCharacters(url, '*_', false);
  1949 + var result = '<img src="' + url + '" alt="' + altText + '"';
  1950 +
  1951 + if (title) {
  1952 + title = title.replace(/"/g, '&quot;');
  1953 + title = showdown.helper.escapeCharacters(title, '*_', false);
  1954 + result += ' title="' + title + '"';
  1955 + }
  1956 +
  1957 + if (width && height) {
  1958 + width = (width === '*') ? 'auto' : width;
  1959 + height = (height === '*') ? 'auto' : height;
  1960 +
  1961 + result += ' width="' + width + '"';
  1962 + result += ' height="' + height + '"';
  1963 + }
  1964 +
  1965 + result += ' />';
  1966 + return result;
  1967 + }
  1968 +
  1969 + // First, handle reference-style labeled images: ![alt text][id]
  1970 + text = text.replace(referenceRegExp, writeImageTag);
  1971 +
  1972 + // Next, handle inline images: ![alt text](url =<width>x<height> "optional title")
  1973 + text = text.replace(inlineRegExp, writeImageTag);
  1974 +
  1975 + text = globals.converter._dispatch('images.after', text, options, globals);
  1976 + return text;
  1977 +});
  1978 +
  1979 +showdown.subParser('italicsAndBold', function (text, options, globals) {
  1980 + 'use strict';
  1981 +
  1982 + text = globals.converter._dispatch('italicsAndBold.before', text, options, globals);
  1983 +
  1984 + if (options.literalMidWordUnderscores) {
  1985 + //underscores
  1986 + // Since we are consuming a \s character, we need to add it
  1987 + text = text.replace(/(^|\s|>|\b)__(?=\S)([\s\S]+?)__(?=\b|<|\s|$)/gm, '$1<strong>$2</strong>');
  1988 + text = text.replace(/(^|\s|>|\b)_(?=\S)([\s\S]+?)_(?=\b|<|\s|$)/gm, '$1<em>$2</em>');
  1989 + //asterisks
  1990 + text = text.replace(/(\*\*)(?=\S)([^\r]*?\S[*]*)\1/g, '<strong>$2</strong>');
  1991 + text = text.replace(/(\*)(?=\S)([^\r]*?\S)\1/g, '<em>$2</em>');
  1992 +
  1993 + } else {
  1994 + // <strong> must go first:
  1995 + text = text.replace(/(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g, '<strong>$2</strong>');
  1996 + text = text.replace(/(\*|_)(?=\S)([^\r]*?\S)\1/g, '<em>$2</em>');
  1997 + }
  1998 +
  1999 + text = globals.converter._dispatch('italicsAndBold.after', text, options, globals);
  2000 + return text;
  2001 +});
  2002 +
  2003 +/**
  2004 + * Form HTML ordered (numbered) and unordered (bulleted) lists.
  2005 + */
  2006 +showdown.subParser('lists', function (text, options, globals) {
  2007 + 'use strict';
  2008 +
  2009 + text = globals.converter._dispatch('lists.before', text, options, globals);
  2010 + /**
  2011 + * Process the contents of a single ordered or unordered list, splitting it
  2012 + * into individual list items.
  2013 + * @param {string} listStr
  2014 + * @param {boolean} trimTrailing
  2015 + * @returns {string}
  2016 + */
  2017 + function processListItems (listStr, trimTrailing) {
  2018 + // The $g_list_level global keeps track of when we're inside a list.
  2019 + // Each time we enter a list, we increment it; when we leave a list,
  2020 + // we decrement. If it's zero, we're not in a list anymore.
  2021 + //
  2022 + // We do this because when we're not inside a list, we want to treat
  2023 + // something like this:
  2024 + //
  2025 + // I recommend upgrading to version
  2026 + // 8. Oops, now this line is treated
  2027 + // as a sub-list.
  2028 + //
  2029 + // As a single paragraph, despite the fact that the second line starts
  2030 + // with a digit-period-space sequence.
  2031 + //
  2032 + // Whereas when we're inside a list (or sub-list), that line will be
  2033 + // treated as the start of a sub-list. What a kludge, huh? This is
  2034 + // an aspect of Markdown's syntax that's hard to parse perfectly
  2035 + // without resorting to mind-reading. Perhaps the solution is to
  2036 + // change the syntax rules such that sub-lists must start with a
  2037 + // starting cardinal number; e.g. "1." or "a.".
  2038 + globals.gListLevel++;
  2039 +
  2040 + // trim trailing blank lines:
  2041 + listStr = listStr.replace(/\n{2,}$/, '\n');
  2042 +
  2043 + // attacklab: add sentinel to emulate \z
  2044 + listStr += '~0';
  2045 +
  2046 + var rgx = /(\n)?(^[ \t]*)([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(~0|\2([*+-]|\d+[.])[ \t]+))/gm,
  2047 + isParagraphed = (/\n[ \t]*\n(?!~0)/.test(listStr));
  2048 +
  2049 + listStr = listStr.replace(rgx, function (wholeMatch, m1, m2, m3, m4, taskbtn, checked) {
  2050 + checked = (checked && checked.trim() !== '');
  2051 + var item = showdown.subParser('outdent')(m4, options, globals),
  2052 + bulletStyle = '';
  2053 +
  2054 + // Support for github tasklists
  2055 + if (taskbtn && options.tasklists) {
  2056 + bulletStyle = ' class="task-list-item" style="list-style-type: none;"';
  2057 + item = item.replace(/^[ \t]*\[(x|X| )?]/m, function () {
  2058 + var otp = '<input type="checkbox" disabled style="margin: 0px 0.35em 0.25em -1.6em; vertical-align: middle;"';
  2059 + if (checked) {
  2060 + otp += ' checked';
  2061 + }
  2062 + otp += '>';
  2063 + return otp;
  2064 + });
  2065 + }
  2066 + // m1 - Leading line or
  2067 + // Has a double return (multi paragraph) or
  2068 + // Has sublist
  2069 + if (m1 || (item.search(/\n{2,}/) > -1)) {
  2070 + item = showdown.subParser('githubCodeBlocks')(item, options, globals);
  2071 + item = showdown.subParser('blockGamut')(item, options, globals);
  2072 + } else {
  2073 + // Recursion for sub-lists:
  2074 + item = showdown.subParser('lists')(item, options, globals);
  2075 + item = item.replace(/\n$/, ''); // chomp(item)
  2076 + if (isParagraphed) {
  2077 + item = showdown.subParser('paragraphs')(item, options, globals);
  2078 + } else {
  2079 + item = showdown.subParser('spanGamut')(item, options, globals);
  2080 + }
  2081 + }
  2082 + item = '\n<li' + bulletStyle + '>' + item + '</li>\n';
  2083 + return item;
  2084 + });
  2085 +
  2086 + // attacklab: strip sentinel
  2087 + listStr = listStr.replace(/~0/g, '');
  2088 +
  2089 + globals.gListLevel--;
  2090 +
  2091 + if (trimTrailing) {
  2092 + listStr = listStr.replace(/\s+$/, '');
  2093 + }
  2094 +
  2095 + return listStr;
  2096 + }
  2097 +
  2098 + /**
  2099 + * Check and parse consecutive lists (better fix for issue #142)
  2100 + * @param {string} list
  2101 + * @param {string} listType
  2102 + * @param {boolean} trimTrailing
  2103 + * @returns {string}
  2104 + */
  2105 + function parseConsecutiveLists(list, listType, trimTrailing) {
  2106 + // check if we caught 2 or more consecutive lists by mistake
  2107 + // we use the counterRgx, meaning if listType is UL we look for UL and vice versa
  2108 + var counterRxg = (listType === 'ul') ? /^ {0,2}\d+\.[ \t]/gm : /^ {0,2}[*+-][ \t]/gm,
  2109 + subLists = [],
  2110 + result = '';
  2111 +
  2112 + if (list.search(counterRxg) !== -1) {
  2113 + (function parseCL(txt) {
  2114 + var pos = txt.search(counterRxg);
  2115 + if (pos !== -1) {
  2116 + // slice
  2117 + result += '\n\n<' + listType + '>' + processListItems(txt.slice(0, pos), !!trimTrailing) + '</' + listType + '>\n\n';
  2118 +
  2119 + // invert counterType and listType
  2120 + listType = (listType === 'ul') ? 'ol' : 'ul';
  2121 + counterRxg = (listType === 'ul') ? /^ {0,2}\d+\.[ \t]/gm : /^ {0,2}[*+-][ \t]/gm;
  2122 +
  2123 + //recurse
  2124 + parseCL(txt.slice(pos));
  2125 + } else {
  2126 + result += '\n\n<' + listType + '>' + processListItems(txt, !!trimTrailing) + '</' + listType + '>\n\n';
  2127 + }
  2128 + })(list);
  2129 + for (var i = 0; i < subLists.length; ++i) {
  2130 +
  2131 + }
  2132 + } else {
  2133 + result = '\n\n<' + listType + '>' + processListItems(list, !!trimTrailing) + '</' + listType + '>\n\n';
  2134 + }
  2135 +
  2136 + return result;
  2137 + }
  2138 +
  2139 + // attacklab: add sentinel to hack around khtml/safari bug:
  2140 + // http://bugs.webkit.org/show_bug.cgi?id=11231
  2141 + text += '~0';
  2142 +
  2143 + // Re-usable pattern to match any entire ul or ol list:
  2144 + var wholeList = /^(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;
  2145 +
  2146 + if (globals.gListLevel) {
  2147 + text = text.replace(wholeList, function (wholeMatch, list, m2) {
  2148 + var listType = (m2.search(/[*+-]/g) > -1) ? 'ul' : 'ol';
  2149 + return parseConsecutiveLists(list, listType, true);
  2150 + });
  2151 + } else {
  2152 + wholeList = /(\n\n|^\n?)(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;
  2153 + //wholeList = /(\n\n|^\n?)( {0,3}([*+-]|\d+\.)[ \t]+[\s\S]+?)(?=(~0)|(\n\n(?!\t| {2,}| {0,3}([*+-]|\d+\.)[ \t])))/g;
  2154 + text = text.replace(wholeList, function (wholeMatch, m1, list, m3) {
  2155 +
  2156 + var listType = (m3.search(/[*+-]/g) > -1) ? 'ul' : 'ol';
  2157 + return parseConsecutiveLists(list, listType);
  2158 + });
  2159 + }
  2160 +
  2161 + // attacklab: strip sentinel
  2162 + text = text.replace(/~0/, '');
  2163 +
  2164 + text = globals.converter._dispatch('lists.after', text, options, globals);
  2165 + return text;
  2166 +});
  2167 +
  2168 +/**
  2169 + * Remove one level of line-leading tabs or spaces
  2170 + */
  2171 +showdown.subParser('outdent', function (text) {
  2172 + 'use strict';
  2173 +
  2174 + // attacklab: hack around Konqueror 3.5.4 bug:
  2175 + // "----------bug".replace(/^-/g,"") == "bug"
  2176 + text = text.replace(/^(\t|[ ]{1,4})/gm, '~0'); // attacklab: g_tab_width
  2177 +
  2178 + // attacklab: clean up hack
  2179 + text = text.replace(/~0/g, '');
  2180 +
  2181 + return text;
  2182 +});
  2183 +
  2184 +/**
  2185 + *
  2186 + */
  2187 +showdown.subParser('paragraphs', function (text, options, globals) {
  2188 + 'use strict';
  2189 +
  2190 + text = globals.converter._dispatch('paragraphs.before', text, options, globals);
  2191 + // Strip leading and trailing lines:
  2192 + text = text.replace(/^\n+/g, '');
  2193 + text = text.replace(/\n+$/g, '');
  2194 +
  2195 + var grafs = text.split(/\n{2,}/g),
  2196 + grafsOut = [],
  2197 + end = grafs.length; // Wrap <p> tags
  2198 +
  2199 + for (var i = 0; i < end; i++) {
  2200 + var str = grafs[i];
  2201 + // if this is an HTML marker, copy it
  2202 + if (str.search(/~(K|G)(\d+)\1/g) >= 0) {
  2203 + grafsOut.push(str);
  2204 + } else {
  2205 + str = showdown.subParser('spanGamut')(str, options, globals);
  2206 + str = str.replace(/^([ \t]*)/g, '<p>');
  2207 + str += '</p>';
  2208 + grafsOut.push(str);
  2209 + }
  2210 + }
  2211 +
  2212 + /** Unhashify HTML blocks */
  2213 + end = grafsOut.length;
  2214 + for (i = 0; i < end; i++) {
  2215 + var blockText = '',
  2216 + grafsOutIt = grafsOut[i],
  2217 + codeFlag = false;
  2218 + // if this is a marker for an html block...
  2219 + while (grafsOutIt.search(/~(K|G)(\d+)\1/) >= 0) {
  2220 + var delim = RegExp.$1,
  2221 + num = RegExp.$2;
  2222 +
  2223 + if (delim === 'K') {
  2224 + blockText = globals.gHtmlBlocks[num];
  2225 + } else {
  2226 + // we need to check if ghBlock is a false positive
  2227 + if (codeFlag) {
  2228 + // use encoded version of all text
  2229 + blockText = showdown.subParser('encodeCode')(globals.ghCodeBlocks[num].text);
  2230 + } else {
  2231 + blockText = globals.ghCodeBlocks[num].codeblock;
  2232 + }
  2233 + }
  2234 + blockText = blockText.replace(/\$/g, '$$$$'); // Escape any dollar signs
  2235 +
  2236 + grafsOutIt = grafsOutIt.replace(/(\n\n)?~(K|G)\d+\2(\n\n)?/, blockText);
  2237 + // Check if grafsOutIt is a pre->code
  2238 + if (/^<pre\b[^>]*>\s*<code\b[^>]*>/.test(grafsOutIt)) {
  2239 + codeFlag = true;
  2240 + }
  2241 + }
  2242 + grafsOut[i] = grafsOutIt;
  2243 + }
  2244 + text = grafsOut.join('\n\n');
  2245 + // Strip leading and trailing lines:
  2246 + text = text.replace(/^\n+/g, '');
  2247 + text = text.replace(/\n+$/g, '');
  2248 + return globals.converter._dispatch('paragraphs.after', text, options, globals);
  2249 +});
  2250 +
  2251 +/**
  2252 + * Run extension
  2253 + */
  2254 +showdown.subParser('runExtension', function (ext, text, options, globals) {
  2255 + 'use strict';
  2256 +
  2257 + if (ext.filter) {
  2258 + text = ext.filter(text, globals.converter, options);
  2259 +
  2260 + } else if (ext.regex) {
  2261 + // TODO remove this when old extension loading mechanism is deprecated
  2262 + var re = ext.regex;
  2263 + if (!re instanceof RegExp) {
  2264 + re = new RegExp(re, 'g');
  2265 + }
  2266 + text = text.replace(re, ext.replace);
  2267 + }
  2268 +
  2269 + return text;
  2270 +});
  2271 +
  2272 +/**
  2273 + * These are all the transformations that occur *within* block-level
  2274 + * tags like paragraphs, headers, and list items.
  2275 + */
  2276 +showdown.subParser('spanGamut', function (text, options, globals) {
  2277 + 'use strict';
  2278 +
  2279 + text = globals.converter._dispatch('spanGamut.before', text, options, globals);
  2280 + text = showdown.subParser('codeSpans')(text, options, globals);
  2281 + text = showdown.subParser('escapeSpecialCharsWithinTagAttributes')(text, options, globals);
  2282 + text = showdown.subParser('encodeBackslashEscapes')(text, options, globals);
  2283 +
  2284 + // Process anchor and image tags. Images must come first,
  2285 + // because ![foo][f] looks like an anchor.
  2286 + text = showdown.subParser('images')(text, options, globals);
  2287 + text = showdown.subParser('anchors')(text, options, globals);
  2288 +
  2289 + // Make links out of things like `<http://example.com/>`
  2290 + // Must come after _DoAnchors(), because you can use < and >
  2291 + // delimiters in inline links like [this](<url>).
  2292 + text = showdown.subParser('autoLinks')(text, options, globals);
  2293 + text = showdown.subParser('encodeAmpsAndAngles')(text, options, globals);
  2294 + text = showdown.subParser('italicsAndBold')(text, options, globals);
  2295 + text = showdown.subParser('strikethrough')(text, options, globals);
  2296 +
  2297 + // Do hard breaks:
  2298 + text = text.replace(/ +\n/g, ' <br />\n');
  2299 +
  2300 + text = globals.converter._dispatch('spanGamut.after', text, options, globals);
  2301 + return text;
  2302 +});
  2303 +
  2304 +showdown.subParser('strikethrough', function (text, options, globals) {
  2305 + 'use strict';
  2306 +
  2307 + if (options.strikethrough) {
  2308 + text = globals.converter._dispatch('strikethrough.before', text, options, globals);
  2309 + text = text.replace(/(?:~T){2}([\s\S]+?)(?:~T){2}/g, '<del>$1</del>');
  2310 + text = globals.converter._dispatch('strikethrough.after', text, options, globals);
  2311 + }
  2312 +
  2313 + return text;
  2314 +});
  2315 +
  2316 +/**
  2317 + * Strip any lines consisting only of spaces and tabs.
  2318 + * This makes subsequent regexs easier to write, because we can
  2319 + * match consecutive blank lines with /\n+/ instead of something
  2320 + * contorted like /[ \t]*\n+/
  2321 + */
  2322 +showdown.subParser('stripBlankLines', function (text) {
  2323 + 'use strict';
  2324 + return text.replace(/^[ \t]+$/mg, '');
  2325 +});
  2326 +
  2327 +/**
  2328 + * Strips link definitions from text, stores the URLs and titles in
  2329 + * hash references.
  2330 + * Link defs are in the form: ^[id]: url "optional title"
  2331 + *
  2332 + * ^[ ]{0,3}\[(.+)\]: // id = $1 attacklab: g_tab_width - 1
  2333 + * [ \t]*
  2334 + * \n? // maybe *one* newline
  2335 + * [ \t]*
  2336 + * <?(\S+?)>? // url = $2
  2337 + * [ \t]*
  2338 + * \n? // maybe one newline
  2339 + * [ \t]*
  2340 + * (?:
  2341 + * (\n*) // any lines skipped = $3 attacklab: lookbehind removed
  2342 + * ["(]
  2343 + * (.+?) // title = $4
  2344 + * [")]
  2345 + * [ \t]*
  2346 + * )? // title is optional
  2347 + * (?:\n+|$)
  2348 + * /gm,
  2349 + * function(){...});
  2350 + *
  2351 + */
  2352 +showdown.subParser('stripLinkDefinitions', function (text, options, globals) {
  2353 + 'use strict';
  2354 +
  2355 + 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;
  2356 +
  2357 + // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug
  2358 + text += '~0';
  2359 +
  2360 + text = text.replace(regex, function (wholeMatch, linkId, url, width, height, blankLines, title) {
  2361 + linkId = linkId.toLowerCase();
  2362 + globals.gUrls[linkId] = showdown.subParser('encodeAmpsAndAngles')(url); // Link IDs are case-insensitive
  2363 +
  2364 + if (blankLines) {
  2365 + // Oops, found blank lines, so it's not a title.
  2366 + // Put back the parenthetical statement we stole.
  2367 + return blankLines + title;
  2368 +
  2369 + } else {
  2370 + if (title) {
  2371 + globals.gTitles[linkId] = title.replace(/"|'/g, '&quot;');
  2372 + }
  2373 + if (options.parseImgDimensions && width && height) {
  2374 + globals.gDimensions[linkId] = {
  2375 + width: width,
  2376 + height: height
  2377 + };
  2378 + }
  2379 + }
  2380 + // Completely remove the definition from the text
  2381 + return '';
  2382 + });
  2383 +
  2384 + // attacklab: strip sentinel
  2385 + text = text.replace(/~0/, '');
  2386 +
  2387 + return text;
  2388 +});
  2389 +
  2390 +showdown.subParser('tables', function (text, options, globals) {
  2391 + 'use strict';
  2392 +
  2393 + if (!options.tables) {
  2394 + return text;
  2395 + }
  2396 +
  2397 + var tableRgx = /^[ \t]{0,3}\|?.+\|.+\n[ \t]{0,3}\|?[ \t]*:?[ \t]*(?:-|=){2,}[ \t]*:?[ \t]*\|[ \t]*:?[ \t]*(?:-|=){2,}[\s\S]+?(?:\n\n|~0)/gm;
  2398 +
  2399 + function parseStyles(sLine) {
  2400 + if (/^:[ \t]*--*$/.test(sLine)) {
  2401 + return ' style="text-align:left;"';
  2402 + } else if (/^--*[ \t]*:[ \t]*$/.test(sLine)) {
  2403 + return ' style="text-align:right;"';
  2404 + } else if (/^:[ \t]*--*[ \t]*:$/.test(sLine)) {
  2405 + return ' style="text-align:center;"';
  2406 + } else {
  2407 + return '';
  2408 + }
  2409 + }
  2410 +
  2411 + function parseHeaders(header, style) {
  2412 + var id = '';
  2413 + header = header.trim();
  2414 + if (options.tableHeaderId) {
  2415 + id = ' id="' + header.replace(/ /g, '_').toLowerCase() + '"';
  2416 + }
  2417 + header = showdown.subParser('spanGamut')(header, options, globals);
  2418 +
  2419 + return '<th' + id + style + '>' + header + '</th>\n';
  2420 + }
  2421 +
  2422 + function parseCells(cell, style) {
  2423 + var subText = showdown.subParser('spanGamut')(cell, options, globals);
  2424 + return '<td' + style + '>' + subText + '</td>\n';
  2425 + }
  2426 +
  2427 + function buildTable(headers, cells) {
  2428 + var tb = '<table>\n<thead>\n<tr>\n',
  2429 + tblLgn = headers.length;
  2430 +
  2431 + for (var i = 0; i < tblLgn; ++i) {
  2432 + tb += headers[i];
  2433 + }
  2434 + tb += '</tr>\n</thead>\n<tbody>\n';
  2435 +
  2436 + for (i = 0; i < cells.length; ++i) {
  2437 + tb += '<tr>\n';
  2438 + for (var ii = 0; ii < tblLgn; ++ii) {
  2439 + tb += cells[i][ii];
  2440 + }
  2441 + tb += '</tr>\n';
  2442 + }
  2443 + tb += '</tbody>\n</table>\n';
  2444 + return tb;
  2445 + }
  2446 +
  2447 + text = globals.converter._dispatch('tables.before', text, options, globals);
  2448 +
  2449 + text = text.replace(tableRgx, function (rawTable) {
  2450 +
  2451 + var i, tableLines = rawTable.split('\n');
  2452 +
  2453 + // strip wrong first and last column if wrapped tables are used
  2454 + for (i = 0; i < tableLines.length; ++i) {
  2455 + if (/^[ \t]{0,3}\|/.test(tableLines[i])) {
  2456 + tableLines[i] = tableLines[i].replace(/^[ \t]{0,3}\|/, '');
  2457 + }
  2458 + if (/\|[ \t]*$/.test(tableLines[i])) {
  2459 + tableLines[i] = tableLines[i].replace(/\|[ \t]*$/, '');
  2460 + }
  2461 + }
  2462 +
  2463 + var rawHeaders = tableLines[0].split('|').map(function (s) { return s.trim();}),
  2464 + rawStyles = tableLines[1].split('|').map(function (s) { return s.trim();}),
  2465 + rawCells = [],
  2466 + headers = [],
  2467 + styles = [],
  2468 + cells = [];
  2469 +
  2470 + tableLines.shift();
  2471 + tableLines.shift();
  2472 +
  2473 + for (i = 0; i < tableLines.length; ++i) {
  2474 + if (tableLines[i].trim() === '') {
  2475 + continue;
  2476 + }
  2477 + rawCells.push(
  2478 + tableLines[i]
  2479 + .split('|')
  2480 + .map(function (s) {
  2481 + return s.trim();
  2482 + })
  2483 + );
  2484 + }
  2485 +
  2486 + if (rawHeaders.length < rawStyles.length) {
  2487 + return rawTable;
  2488 + }
  2489 +
  2490 + for (i = 0; i < rawStyles.length; ++i) {
  2491 + styles.push(parseStyles(rawStyles[i]));
  2492 + }
  2493 +
  2494 + for (i = 0; i < rawHeaders.length; ++i) {
  2495 + if (showdown.helper.isUndefined(styles[i])) {
  2496 + styles[i] = '';
  2497 + }
  2498 + headers.push(parseHeaders(rawHeaders[i], styles[i]));
  2499 + }
  2500 +
  2501 + for (i = 0; i < rawCells.length; ++i) {
  2502 + var row = [];
  2503 + for (var ii = 0; ii < headers.length; ++ii) {
  2504 + if (showdown.helper.isUndefined(rawCells[i][ii])) {
  2505 +
  2506 + }
  2507 + row.push(parseCells(rawCells[i][ii], styles[ii]));
  2508 + }
  2509 + cells.push(row);
  2510 + }
  2511 +
  2512 + return buildTable(headers, cells);
  2513 + });
  2514 +
  2515 + text = globals.converter._dispatch('tables.after', text, options, globals);
  2516 +
  2517 + return text;
  2518 +});
  2519 +
  2520 +/**
  2521 + * Swap back in all the special characters we've hidden.
  2522 + */
  2523 +showdown.subParser('unescapeSpecialChars', function (text) {
  2524 + 'use strict';
  2525 +
  2526 + text = text.replace(/~E(\d+)E/g, function (wholeMatch, m1) {
  2527 + var charCodeToReplace = parseInt(m1);
  2528 + return String.fromCharCode(charCodeToReplace);
  2529 + });
  2530 + return text;
  2531 +});
  2532 +module.exports = showdown;
  1 +// HTML 支持的数学符号
  2 +function strNumDiscode(str){
  3 + str = str.replace(/&forall;/g, '∀');
  4 + str = str.replace(/&part;/g, '∂');
  5 + str = str.replace(/&exists;/g, '∃');
  6 + str = str.replace(/&empty;/g, '∅');
  7 + str = str.replace(/&nabla;/g, '∇');
  8 + str = str.replace(/&isin;/g, '∈');
  9 + str = str.replace(/&notin;/g, '∉');
  10 + str = str.replace(/&ni;/g, '∋');
  11 + str = str.replace(/&prod;/g, '∏');
  12 + str = str.replace(/&sum;/g, '∑');
  13 + str = str.replace(/&minus;/g, '−');
  14 + str = str.replace(/&lowast;/g, '∗');
  15 + str = str.replace(/&radic;/g, '√');
  16 + str = str.replace(/&prop;/g, '∝');
  17 + str = str.replace(/&infin;/g, '∞');
  18 + str = str.replace(/&ang;/g, '∠');
  19 + str = str.replace(/&and;/g, '∧');
  20 + str = str.replace(/&or;/g, '∨');
  21 + str = str.replace(/&cap;/g, '∩');
  22 + str = str.replace(/&cap;/g, '∪');
  23 + str = str.replace(/&int;/g, '∫');
  24 + str = str.replace(/&there4;/g, '∴');
  25 + str = str.replace(/&sim;/g, '∼');
  26 + str = str.replace(/&cong;/g, '≅');
  27 + str = str.replace(/&asymp;/g, '≈');
  28 + str = str.replace(/&ne;/g, '≠');
  29 + str = str.replace(/&le;/g, '≤');
  30 + str = str.replace(/&ge;/g, '≥');
  31 + str = str.replace(/&sub;/g, '⊂');
  32 + str = str.replace(/&sup;/g, '⊃');
  33 + str = str.replace(/&nsub;/g, '⊄');
  34 + str = str.replace(/&sube;/g, '⊆');
  35 + str = str.replace(/&supe;/g, '⊇');
  36 + str = str.replace(/&oplus;/g, '⊕');
  37 + str = str.replace(/&otimes;/g, '⊗');
  38 + str = str.replace(/&perp;/g, '⊥');
  39 + str = str.replace(/&sdot;/g, '⋅');
  40 + return str;
  41 +}
  42 +
  43 +//HTML 支持的希腊字母
  44 +function strGreeceDiscode(str){
  45 + str = str.replace(/&Alpha;/g, 'Α');
  46 + str = str.replace(/&Beta;/g, 'Β');
  47 + str = str.replace(/&Gamma;/g, 'Γ');
  48 + str = str.replace(/&Delta;/g, 'Δ');
  49 + str = str.replace(/&Epsilon;/g, 'Ε');
  50 + str = str.replace(/&Zeta;/g, 'Ζ');
  51 + str = str.replace(/&Eta;/g, 'Η');
  52 + str = str.replace(/&Theta;/g, 'Θ');
  53 + str = str.replace(/&Iota;/g, 'Ι');
  54 + str = str.replace(/&Kappa;/g, 'Κ');
  55 + str = str.replace(/&Lambda;/g, 'Λ');
  56 + str = str.replace(/&Mu;/g, 'Μ');
  57 + str = str.replace(/&Nu;/g, 'Ν');
  58 + str = str.replace(/&Xi;/g, 'Ν');
  59 + str = str.replace(/&Omicron;/g, 'Ο');
  60 + str = str.replace(/&Pi;/g, 'Π');
  61 + str = str.replace(/&Rho;/g, 'Ρ');
  62 + str = str.replace(/&Sigma;/g, 'Σ');
  63 + str = str.replace(/&Tau;/g, 'Τ');
  64 + str = str.replace(/&Upsilon;/g, 'Υ');
  65 + str = str.replace(/&Phi;/g, 'Φ');
  66 + str = str.replace(/&Chi;/g, 'Χ');
  67 + str = str.replace(/&Psi;/g, 'Ψ');
  68 + str = str.replace(/&Omega;/g, 'Ω');
  69 +
  70 + str = str.replace(/&alpha;/g, 'α');
  71 + str = str.replace(/&beta;/g, 'β');
  72 + str = str.replace(/&gamma;/g, 'γ');
  73 + str = str.replace(/&delta;/g, 'δ');
  74 + str = str.replace(/&epsilon;/g, 'ε');
  75 + str = str.replace(/&zeta;/g, 'ζ');
  76 + str = str.replace(/&eta;/g, 'η');
  77 + str = str.replace(/&theta;/g, 'θ');
  78 + str = str.replace(/&iota;/g, 'ι');
  79 + str = str.replace(/&kappa;/g, 'κ');
  80 + str = str.replace(/&lambda;/g, 'λ');
  81 + str = str.replace(/&mu;/g, 'μ');
  82 + str = str.replace(/&nu;/g, 'ν');
  83 + str = str.replace(/&xi;/g, 'ξ');
  84 + str = str.replace(/&omicron;/g, 'ο');
  85 + str = str.replace(/&pi;/g, 'π');
  86 + str = str.replace(/&rho;/g, 'ρ');
  87 + str = str.replace(/&sigmaf;/g, 'ς');
  88 + str = str.replace(/&sigma;/g, 'σ');
  89 + str = str.replace(/&tau;/g, 'τ');
  90 + str = str.replace(/&upsilon;/g, 'υ');
  91 + str = str.replace(/&phi;/g, 'φ');
  92 + str = str.replace(/&chi;/g, 'χ');
  93 + str = str.replace(/&psi;/g, 'ψ');
  94 + str = str.replace(/&omega;/g, 'ω');
  95 + str = str.replace(/&thetasym;/g, 'ϑ');
  96 + str = str.replace(/&upsih;/g, 'ϒ');
  97 + str = str.replace(/&piv;/g, 'ϖ');
  98 + str = str.replace(/&middot;/g, '·');
  99 + return str;
  100 +}
  101 +
  102 +//
  103 +
  104 +function strcharacterDiscode(str){
  105 + // 加入常用解析
  106 + str = str.replace(/&nbsp;/g, ' ');
  107 + str = str.replace(/&quot;/g, "'");
  108 + str = str.replace(/&amp;/g, '&');
  109 + // str = str.replace(/&lt;/g, '‹');
  110 + // str = str.replace(/&gt;/g, '›');
  111 +
  112 + str = str.replace(/&lt;/g, '<');
  113 + str = str.replace(/&gt;/g, '>');
  114 + str = str.replace(/&#8226;/g, '•');
  115 +
  116 + return str;
  117 +}
  118 +
  119 +// HTML 支持的其他实体
  120 +function strOtherDiscode(str){
  121 + str = str.replace(/&OElig;/g, 'Œ');
  122 + str = str.replace(/&oelig;/g, 'œ');
  123 + str = str.replace(/&Scaron;/g, 'Š');
  124 + str = str.replace(/&scaron;/g, 'š');
  125 + str = str.replace(/&Yuml;/g, 'Ÿ');
  126 + str = str.replace(/&fnof;/g, 'ƒ');
  127 + str = str.replace(/&circ;/g, 'ˆ');
  128 + str = str.replace(/&tilde;/g, '˜');
  129 + str = str.replace(/&ensp;/g, '');
  130 + str = str.replace(/&emsp;/g, '');
  131 + str = str.replace(/&thinsp;/g, '');
  132 + str = str.replace(/&zwnj;/g, '');
  133 + str = str.replace(/&zwj;/g, '');
  134 + str = str.replace(/&lrm;/g, '');
  135 + str = str.replace(/&rlm;/g, '');
  136 + str = str.replace(/&ndash;/g, '–');
  137 + str = str.replace(/&mdash;/g, '—');
  138 + str = str.replace(/&lsquo;/g, '‘');
  139 + str = str.replace(/&rsquo;/g, '’');
  140 + str = str.replace(/&sbquo;/g, '‚');
  141 + str = str.replace(/&ldquo;/g, '“');
  142 + str = str.replace(/&rdquo;/g, '”');
  143 + str = str.replace(/&bdquo;/g, '„');
  144 + str = str.replace(/&dagger;/g, '†');
  145 + str = str.replace(/&Dagger;/g, '‡');
  146 + str = str.replace(/&bull;/g, '•');
  147 + str = str.replace(/&hellip;/g, '…');
  148 + str = str.replace(/&permil;/g, '‰');
  149 + str = str.replace(/&prime;/g, '′');
  150 + str = str.replace(/&Prime;/g, '″');
  151 + str = str.replace(/&lsaquo;/g, '‹');
  152 + str = str.replace(/&rsaquo;/g, '›');
  153 + str = str.replace(/&oline;/g, '‾');
  154 + str = str.replace(/&euro;/g, '€');
  155 + str = str.replace(/&trade;/g, '™');
  156 +
  157 + str = str.replace(/&larr;/g, '←');
  158 + str = str.replace(/&uarr;/g, '↑');
  159 + str = str.replace(/&rarr;/g, '→');
  160 + str = str.replace(/&darr;/g, '↓');
  161 + str = str.replace(/&harr;/g, '↔');
  162 + str = str.replace(/&crarr;/g, '↵');
  163 + str = str.replace(/&lceil;/g, '⌈');
  164 + str = str.replace(/&rceil;/g, '⌉');
  165 +
  166 + str = str.replace(/&lfloor;/g, '⌊');
  167 + str = str.replace(/&rfloor;/g, '⌋');
  168 + str = str.replace(/&loz;/g, '◊');
  169 + str = str.replace(/&spades;/g, '♠');
  170 + str = str.replace(/&clubs;/g, '♣');
  171 + str = str.replace(/&hearts;/g, '♥');
  172 +
  173 + str = str.replace(/&diams;/g, '♦');
  174 + str = str.replace(/&#39;/g, '\'');
  175 + return str;
  176 +}
  177 +
  178 +function strMoreDiscode(str){
  179 + str = str.replace(/\r\n/g,"");
  180 + str = str.replace(/\n/g,"");
  181 +
  182 + str = str.replace(/code/g,"wxxxcode-style");
  183 + return str;
  184 +}
  185 +
  186 +function strDiscode(str){
  187 + str = strNumDiscode(str);
  188 + str = strGreeceDiscode(str);
  189 + str = strcharacterDiscode(str);
  190 + str = strOtherDiscode(str);
  191 + str = strMoreDiscode(str);
  192 + return str;
  193 +}
  194 +function urlToHttpUrl(url,rep){
  195 +
  196 + var patt1 = new RegExp("^//");
  197 + var result = patt1.test(url);
  198 + if(result){
  199 + url = rep+":"+url;
  200 + }
  201 + return url;
  202 +}
  203 +
  204 +module.exports = {
  205 + strDiscode:strDiscode,
  206 + urlToHttpUrl:urlToHttpUrl
  207 +}