作者 吴孟雨

登录注册,绑定手机号,获取验证码,轮播图,本周实验,往期实验,立即预约,实验详情

要显示太多修改。

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

<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="632eecf6-91e3-4185-aea4-06d243e51935" name="Default" comment="上传到远程wumengyu">
<list default="true" id="632eecf6-91e3-4185-aea4-06d243e51935" name="Default" comment="合并master">
<change afterPath="$PROJECT_DIR$/utils/qqmap-wx-jssdk.min.js" afterDir="false" />
<change afterPath="$PROJECT_DIR$/wxParse/html2json.js" afterDir="false" />
<change afterPath="$PROJECT_DIR$/wxParse/htmlparser.js" afterDir="false" />
<change afterPath="$PROJECT_DIR$/wxParse/showdown.js" afterDir="false" />
<change afterPath="$PROJECT_DIR$/wxParse/wxDiscode.js" afterDir="false" />
<change afterPath="$PROJECT_DIR$/wxParse/wxParse.js" afterDir="false" />
<change afterPath="$PROJECT_DIR$/wxParse/wxParse.wxml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/wxParse/wxParse.wxss" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app.js" beforeDir="false" afterPath="$PROJECT_DIR$/app.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app.json" beforeDir="false" afterPath="$PROJECT_DIR$/app.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pages/clock/clock.js" beforeDir="false" afterPath="$PROJECT_DIR$/pages/clock/clock.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pages/clock/clock.wxml" beforeDir="false" afterPath="$PROJECT_DIR$/pages/clock/clock.wxml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pages/clock/clock.wxss" beforeDir="false" afterPath="$PROJECT_DIR$/pages/clock/clock.wxss" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pages/index/activity-detail/activity-detail.js" beforeDir="false" afterPath="$PROJECT_DIR$/pages/index/activity-detail/activity-detail.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pages/index/activity-detail/activity-detail.wxml" beforeDir="false" afterPath="$PROJECT_DIR$/pages/index/activity-detail/activity-detail.wxml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pages/index/confirm-appointment-info/confirm-appointment-info.js" beforeDir="false" afterPath="$PROJECT_DIR$/pages/index/confirm-appointment-info/confirm-appointment-info.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pages/index/go-appointment/go-appointment.js" beforeDir="false" afterPath="$PROJECT_DIR$/pages/index/go-appointment/go-appointment.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pages/index/go-appointment/go-appointment.wxml" beforeDir="false" afterPath="$PROJECT_DIR$/pages/index/go-appointment/go-appointment.wxml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pages/index/index.js" beforeDir="false" afterPath="$PROJECT_DIR$/pages/index/index.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pages/index/index.wxml" beforeDir="false" afterPath="$PROJECT_DIR$/pages/index/index.wxml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pages/index/phone-code/phone-code.js" beforeDir="false" afterPath="$PROJECT_DIR$/pages/index/phone-code/phone-code.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pages/index/phone-code/phone-code.wxml" beforeDir="false" afterPath="$PROJECT_DIR$/pages/index/phone-code/phone-code.wxml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pages/my/my.js" beforeDir="false" afterPath="$PROJECT_DIR$/pages/my/my.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pages/my/my.wxml" beforeDir="false" afterPath="$PROJECT_DIR$/pages/my/my.wxml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pages/my/my.wxss" beforeDir="false" afterPath="$PROJECT_DIR$/pages/my/my.wxss" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pages/my/protocol/protocol.js" beforeDir="false" afterPath="$PROJECT_DIR$/pages/my/protocol/protocol.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pages/my/protocol/protocol.wxml" beforeDir="false" afterPath="$PROJECT_DIR$/pages/my/protocol/protocol.wxml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pages/start/start.js" beforeDir="false" afterPath="$PROJECT_DIR$/pages/start/start.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/project.config.json" beforeDir="false" afterPath="$PROJECT_DIR$/project.config.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/templates.wxml" beforeDir="false" afterPath="$PROJECT_DIR$/templates/templates.wxml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/utils/util.js" beforeDir="false" afterPath="$PROJECT_DIR$/utils/util.js" afterDir="false" />
</list>
<ignored path="$PROJECT_DIR$/.tmp/" />
<ignored path="$PROJECT_DIR$/temp/" />
... ... @@ -26,44 +46,49 @@
<session id="-381596063">
<usages-collector id="statistics.lifecycle.project">
<counts>
<entry key="project.closed" value="3" />
<entry key="project.closed" value="5" />
<entry key="project.open.time.0" value="3" />
<entry key="project.open.time.1" value="1" />
<entry key="project.opened" value="4" />
<entry key="project.open.time.1" value="3" />
<entry key="project.opened" value="6" />
</counts>
</usages-collector>
<usages-collector id="statistics.file.extensions.open">
<counts>
<entry key="js" value="6" />
<entry key="json" value="4" />
<entry key="wxml" value="9" />
<entry key="wxss" value="5" />
<entry key="js" value="25" />
<entry key="json" value="11" />
<entry key="wxml" value="21" />
<entry key="wxss" value="10" />
</counts>
</usages-collector>
<usages-collector id="statistics.file.types.open">
<counts>
<entry key="CSS" value="5" />
<entry key="HTML" value="9" />
<entry key="JSON" value="4" />
<entry key="JavaScript" value="6" />
<entry key="CSS" value="10" />
<entry key="HTML" value="21" />
<entry key="JSON" value="11" />
<entry key="JavaScript" value="25" />
</counts>
</usages-collector>
<usages-collector id="statistics.file.extensions.edit">
<counts>
<entry key="js" value="564" />
<entry key="json" value="27" />
<entry key="txt" value="36" />
<entry key="wxml" value="244" />
<entry key="wxss" value="21" />
<entry key="js" value="3215" />
<entry key="json" value="34" />
<entry key="txt" value="63" />
<entry key="wxml" value="748" />
<entry key="wxss" value="23" />
</counts>
</usages-collector>
<usages-collector id="statistics.file.types.edit">
<counts>
<entry key="CSS" value="21" />
<entry key="HTML" value="244" />
<entry key="JSON" value="27" />
<entry key="JavaScript" value="564" />
<entry key="PLAIN_TEXT" value="36" />
<entry key="CSS" value="23" />
<entry key="HTML" value="748" />
<entry key="JSON" value="34" />
<entry key="JavaScript" value="3215" />
<entry key="PLAIN_TEXT" value="63" />
</counts>
</usages-collector>
<usages-collector id="statistics.vcs.git.usages">
<counts>
<entry key="git.branch.merge" value="1" />
</counts>
</usages-collector>
</session>
... ... @@ -71,100 +96,104 @@
<component name="FileEditorManager">
<leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/pages/index/index.wxml">
<entry file="file://$PROJECT_DIR$/pages/index/index.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="880">
<caret line="40" lean-forward="true" selection-start-line="40" selection-end-line="40" />
<state relative-caret-position="-418">
<caret line="8" column="23" selection-start-line="8" selection-start-column="23" selection-end-line="8" selection-end-column="23" />
<folding>
<element signature="n#!!doc" expanded="true" />
</folding>
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/pages/index/index.wxss">
<entry file="file://$PROJECT_DIR$/pages/start/start.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="154">
<caret line="7" column="21" lean-forward="true" selection-start-line="7" selection-start-column="21" selection-end-line="7" selection-end-column="21" />
<state relative-caret-position="676">
<caret line="37" column="25" lean-forward="true" selection-start-line="37" selection-start-column="25" selection-end-line="37" selection-end-column="25" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/pages/index/index.js">
<entry file="file://$PROJECT_DIR$/app.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="506">
<caret line="98" column="64" selection-start-line="98" selection-start-column="64" selection-end-line="98" selection-end-column="64" />
<state relative-caret-position="344">
<caret line="140" column="12" selection-start-line="140" selection-start-column="4" selection-end-line="140" selection-end-column="12" />
<folding>
<element signature="n#!!doc" expanded="true" />
<element signature="e#1018#1103#0" />
<element signature="e#1121#1191#0" />
<element signature="e#1219#1288#0" />
<element signature="e#1321#1468#0" />
<element signature="e#1499#1619#0" />
<element signature="e#1750#1766#0" />
</folding>
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/templates/templates.wxml">
<entry file="file://$PROJECT_DIR$/utils/util.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="374">
<caret line="29" column="65" selection-start-line="29" selection-start-column="65" selection-end-line="29" selection-end-column="65" />
<state relative-caret-position="946">
<caret line="43" column="15" selection-start-line="43" selection-start-column="2" selection-end-line="43" selection-end-column="15" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/pages/index/activity-detail/activity-detail.wxml">
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/pages/index/go-appointment/go-appointment.wxml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="198">
<caret line="9" column="35" selection-start-line="9" selection-start-column="35" selection-end-line="9" selection-end-column="35" />
<state relative-caret-position="638">
<caret line="41" column="90" selection-start-line="41" selection-start-column="72" selection-end-line="41" selection-end-column="90" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/pages/start/start.wxml">
<entry file="file://$PROJECT_DIR$/pages/index/activity-detail/activity-detail.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="132">
<caret line="6" column="15" lean-forward="true" selection-start-line="6" selection-start-column="15" selection-end-line="6" selection-end-column="15" />
<state relative-caret-position="374">
<caret line="29" column="44" lean-forward="true" selection-start-line="29" selection-start-column="44" selection-end-line="29" selection-end-column="44" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/pages/index/activity-detail/activity-detail.json">
<provider selected="true" editor-type-id="text-editor" />
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/pages/index/activity-detail/activity-detail.js">
<file pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/pages/index/go-appointment/go-appointment.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="550">
<caret line="25" column="32" selection-start-line="25" selection-start-column="32" selection-end-line="25" selection-end-column="32" />
<state relative-caret-position="198">
<caret line="125" column="20" lean-forward="true" selection-start-line="125" selection-start-column="20" selection-end-line="125" selection-end-column="20" />
<folding>
<element signature="e#243#454#0" />
<element signature="e#462#673#0" />
<element signature="e#681#893#0" />
<element signature="e#901#1114#0" />
<element signature="e#1177#2298#0" />
</folding>
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/pages/start/start.js">
<entry file="file://$PROJECT_DIR$/pages/index/confirm-appointment-info/confirm-appointment-info.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="374">
<caret line="29" column="49" lean-forward="true" selection-start-line="29" selection-start-column="12" selection-end-line="29" selection-end-column="49" />
<state relative-caret-position="302">
<caret line="44" column="20" lean-forward="true" selection-start-line="44" selection-start-column="20" selection-end-line="44" selection-end-column="20" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/app.json">
<entry file="file://$PROJECT_DIR$/pages/index/confirm-appointment-info/confirm-appointment-info.wxml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="440">
<caret line="20" column="38" selection-start-line="20" selection-start-column="38" selection-end-line="20" selection-end-column="38" />
<state relative-caret-position="852">
<caret line="50" column="42" selection-start-line="50" selection-start-column="42" selection-end-line="50" selection-end-column="42" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/pages/index/go-appointment/go-appointment.json">
<provider selected="true" editor-type-id="text-editor" />
</entry>
</file>
</leaf>
</component>
<component name="FindInProjectRecents">
... ... @@ -172,6 +201,21 @@
<find>chooseYes</find>
<find>baseUrl</find>
<find>getUserInfo</find>
<find>协议</find>
<find>serviceProtocol</find>
<find>goTestDetail</find>
<find>modal</find>
<find>goPhoneCode</find>
<find>QQMapWX</find>
<find>XX</find>
<find>showM</find>
<find>goAppointment</find>
<find>bindPickerChange</find>
<find>show_submit_btn</find>
<find>submit</find>
<find>current_test_id</find>
<find>current_session_id</find>
<find>currentId</find>
</findStrings>
</component>
<component name="Git.Settings">
... ... @@ -182,16 +226,30 @@
<list>
<option value="$PROJECT_DIR$/templates/templates.wxss" />
<option value="$PROJECT_DIR$/pages/index/confirm-appointment-info/confirm-appointment-info.wxss" />
<option value="$PROJECT_DIR$/pages/index/confirm-appointment-info/confirm-appointment-info.js" />
<option value="$PROJECT_DIR$/pages/index/confirm-appointment-info/confirm-appointment-info.wxml" />
<option value="$PROJECT_DIR$/app.js" />
<option value="$PROJECT_DIR$/pages/start/start.js" />
<option value="$PROJECT_DIR$/pages/index/index.wxml" />
<option value="$PROJECT_DIR$/templates/templates.wxml" />
<option value="$PROJECT_DIR$/pages/index/index.js" />
<option value="$PROJECT_DIR$/pages/my/protocol/protocol.wxml" />
<option value="$PROJECT_DIR$/pages/my/protocol/protocol.js" />
<option value="$PROJECT_DIR$/project.config.json" />
<option value="$PROJECT_DIR$/pages/start/start.js" />
<option value="$PROJECT_DIR$/pages/clock/clock.wxml" />
<option value="$PROJECT_DIR$/pages/my/my.wxml" />
<option value="$PROJECT_DIR$/pages/clock/clock.wxss" />
<option value="$PROJECT_DIR$/pages/my/my.wxss" />
<option value="$PROJECT_DIR$/pages/my/my.js" />
<option value="$PROJECT_DIR$/pages/clock/clock.js" />
<option value="$PROJECT_DIR$/app.json" />
<option value="$PROJECT_DIR$/pages/index/activity-detail/activity-detail.js" />
<option value="$PROJECT_DIR$/pages/index/phone-code/phone-code.wxml" />
<option value="$PROJECT_DIR$/pages/index/phone-code/phone-code.js" />
<option value="$PROJECT_DIR$/pages/index/index.js" />
<option value="$PROJECT_DIR$/pages/index/index.wxml" />
<option value="$PROJECT_DIR$/pages/index/activity-detail/activity-detail.wxml" />
<option value="$PROJECT_DIR$/pages/index/activity-detail/activity-detail.js" />
<option value="$PROJECT_DIR$/app.js" />
<option value="$PROJECT_DIR$/utils/util.js" />
<option value="$PROJECT_DIR$/pages/index/confirm-appointment-info/confirm-appointment-info.js" />
<option value="$PROJECT_DIR$/pages/index/go-appointment/go-appointment.wxml" />
<option value="$PROJECT_DIR$/pages/index/go-appointment/go-appointment.js" />
</list>
</option>
</component>
... ... @@ -243,7 +301,14 @@
<item name="ScienceCaptain" type="462c0819:PsiDirectoryNode" />
<item name="pages" type="462c0819:PsiDirectoryNode" />
<item name="index" type="462c0819:PsiDirectoryNode" />
<item name="phone-code" type="462c0819:PsiDirectoryNode" />
<item name="confirm-appointment-info" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="ScienceCaptain" type="b2602c69:ProjectViewProjectNode" />
<item name="ScienceCaptain" type="462c0819:PsiDirectoryNode" />
<item name="pages" type="462c0819:PsiDirectoryNode" />
<item name="index" type="462c0819:PsiDirectoryNode" />
<item name="go-appointment" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="ScienceCaptain" type="b2602c69:ProjectViewProjectNode" />
... ... @@ -254,7 +319,7 @@
<path>
<item name="ScienceCaptain" type="b2602c69:ProjectViewProjectNode" />
<item name="ScienceCaptain" type="462c0819:PsiDirectoryNode" />
<item name="templates" type="462c0819:PsiDirectoryNode" />
<item name="utils" type="462c0819:PsiDirectoryNode" />
</path>
</expand>
<select />
... ... @@ -264,11 +329,17 @@
</component>
<component name="PropertiesComponent">
<property name="WebServerToolWindowFactoryState" value="false" />
<property name="last_opened_file_path" value="D:/project/life" />
<property name="last_opened_file_path" value="D:/info/informationPlatform" />
<property name="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" />
<property name="nodejs_npm_path_reset_for_default_project" value="true" />
<property name="settings.editor.selected.configurable" value="project.propDebugger" />
</component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="D:\小程序\scienceCaptain\ScienceCaptain" />
<recent name="D:\小程序\scienceCaptain\ScienceCaptain\utils" />
</key>
</component>
<component name="RunDashboard">
<option name="ruleStates">
<list>
... ... @@ -295,7 +366,9 @@
<workItem from="1542249556873" duration="6568000" />
<workItem from="1542594514355" duration="2482000" />
<workItem from="1542676616270" duration="2495000" />
<workItem from="1543297125303" duration="4846000" />
<workItem from="1543297125303" duration="6704000" />
<workItem from="1543303923342" duration="8358000" />
<workItem from="1543367358458" duration="25214000" />
</task>
<task id="LOCAL-00001" summary="modal 模板">
<created>1542274356914</created>
... ... @@ -311,11 +384,25 @@
<option name="project" value="LOCAL" />
<updated>1542275805566</updated>
</task>
<option name="localTasksCounter" value="3" />
<task id="LOCAL-00003" summary="对接本周实验,往期实验,登录接口">
<created>1543302198978</created>
<option name="number" value="00003" />
<option name="presentableId" value="LOCAL-00003" />
<option name="project" value="LOCAL" />
<updated>1543302198978</updated>
</task>
<task id="LOCAL-00004" summary="合并master">
<created>1543303397807</created>
<option name="number" value="00004" />
<option name="presentableId" value="LOCAL-00004" />
<option name="project" value="LOCAL" />
<updated>1543303397807</updated>
</task>
<option name="localTasksCounter" value="5" />
<servers />
</component>
<component name="TimeTrackingManager">
<option name="totallyTimeSpent" value="16627000" />
<option name="totallyTimeSpent" value="52057000" />
</component>
<component name="ToolWindowManager">
<frame x="-8" y="-8" width="1936" height="1056" extended-state="6" />
... ... @@ -375,7 +462,9 @@
<component name="VcsManagerConfiguration">
<MESSAGE value="modal 模板" />
<MESSAGE value="上传到远程wumengyu" />
<option name="LAST_COMMIT_MESSAGE" value="上传到远程wumengyu" />
<MESSAGE value="对接本周实验,往期实验,登录接口" />
<MESSAGE value="合并master" />
<option name="LAST_COMMIT_MESSAGE" value="合并master" />
</component>
<component name="editorHistoryManager">
<entry file="file://$PROJECT_DIR$/pages/myProfile/myProfile.json" />
... ... @@ -390,160 +479,255 @@
<entry file="file://$PROJECT_DIR$/pages/my/all-appointment/all-appointment.wxml">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/pages/my/protocol/protocol.wxml">
<entry file="file://$PROJECT_DIR$/templates/templates.wxss">
<provider selected="true" editor-type-id="text-editor">
<state>
<caret column="34" selection-start-column="34" selection-end-column="34" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pages/index/confirm-appointment-info/confirm-appointment-info.wxss">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="462">
<caret line="21" column="6" selection-start-line="21" selection-start-column="6" selection-end-line="21" selection-end-column="6" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pages/my/myCard/myCard.wxml">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/project.config.json">
<entry file="file://$PROJECT_DIR$/pages/start/start.wxml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="352">
<caret line="16" column="21" selection-start-line="16" selection-start-column="21" selection-end-line="16" selection-end-column="21" />
<state relative-caret-position="132">
<caret line="6" column="15" selection-start-line="6" selection-start-column="15" selection-end-line="6" selection-end-column="15" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/templates/templates.wxss">
<entry file="file://$PROJECT_DIR$/templates/templates.wxml">
<provider selected="true" editor-type-id="text-editor">
<state>
<caret column="34" selection-start-column="34" selection-end-column="34" />
<state relative-caret-position="242">
<caret line="11" column="57" selection-start-line="11" selection-start-column="32" selection-end-line="11" selection-end-column="57" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pages/index/phone-code/phone-code.js">
<entry file="file://$PROJECT_DIR$/pages/my/groupBuy/groupBuy.wxml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="550">
<caret line="25" column="28" selection-start-line="25" selection-start-column="28" selection-end-line="25" selection-end-column="28" />
<state relative-caret-position="2684">
<caret line="122" column="59" selection-start-line="122" selection-start-column="44" selection-end-line="122" selection-end-column="59" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pages/index/phone-code/phone-code.wxml">
<entry file="file://$PROJECT_DIR$/pages/my/groupBuy/groupBuy.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="220">
<caret line="10" selection-start-line="10" selection-end-line="12" selection-end-column="21" />
<state relative-caret-position="528">
<caret line="24" selection-start-line="24" selection-end-line="29" selection-end-column="4" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pages/index/activity-detail/activity-detail.json">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/pages/my/protocol/protocol.wxml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="66">
<caret line="3" column="27" selection-start-line="3" selection-start-column="27" selection-end-line="3" selection-end-column="27" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pages/index/phone-code/phone-code.wxss">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="924">
<state relative-caret-position="828">
<caret line="42" selection-start-line="42" selection-end-line="59" selection-end-column="1" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pages/index/confirm-appointment-info/confirm-appointment-info.wxss">
<entry file="file://$PROJECT_DIR$/pages/index/phone-code/phone-code.json">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="462">
<caret line="21" column="6" selection-start-line="21" selection-start-column="6" selection-end-line="21" selection-end-column="6" />
<state relative-caret-position="44">
<caret line="2" column="1" selection-start-line="2" selection-start-column="1" selection-end-line="2" selection-end-column="1" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pages/index/confirm-appointment-info/confirm-appointment-info.wxml">
<entry file="file://$PROJECT_DIR$/pages/my/protocol/protocol.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="1100">
<caret line="50" column="42" selection-start-line="50" selection-start-column="42" selection-end-line="50" selection-end-column="42" />
<state relative-caret-position="418">
<caret line="19" column="7" lean-forward="true" selection-start-line="19" selection-start-column="7" selection-end-line="19" selection-end-column="7" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pages/index/confirm-appointment-info/confirm-appointment-info.js">
<entry file="file://$PROJECT_DIR$/pages/my/my.wxml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="924">
<caret line="42" column="10" lean-forward="true" selection-start-line="42" selection-start-column="10" selection-end-line="42" selection-end-column="10" />
<state relative-caret-position="66">
<caret line="3" column="2" selection-start-line="3" selection-start-column="2" selection-end-line="3" selection-end-column="2" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pages/my/protocol/protocol.js">
<entry file="file://$PROJECT_DIR$/pages/index/index.wxss">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="198">
<caret line="9" selection-start-line="9" selection-end-line="18" selection-end-column="1" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pages/clock/clock.wxss">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="330">
<caret line="15" column="1" selection-start-line="15" selection-start-column="1" selection-end-line="15" selection-end-column="1" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pages/my/my.wxss">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="330">
<caret line="15" column="19" lean-forward="true" selection-start-line="15" selection-start-column="19" selection-end-line="15" selection-end-column="19" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pages/clock/clock.wxml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="66">
<caret line="3" column="40" selection-start-line="3" selection-start-column="32" selection-end-line="3" selection-end-column="40" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pages/clock/clock.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="814">
<caret line="37" selection-start-line="37" selection-end-line="37" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/utils/qqmap-wx-jssdk.min.js">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/pages/my/myCard/myCard.wxml">
<entry file="file://$PROJECT_DIR$/pages/my/my.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="154">
<caret line="7" column="22" selection-start-line="7" selection-start-column="22" selection-end-line="7" selection-end-column="22" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app.wxss">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/pages/index/phone-code/phone-code.json">
<entry file="file://$PROJECT_DIR$/project.config.json">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="44">
<caret line="2" column="1" selection-start-line="2" selection-start-column="1" selection-end-line="2" selection-end-column="1" />
<state relative-caret-position="308">
<caret line="14" column="32" selection-start-line="14" selection-start-column="14" selection-end-line="14" selection-end-column="32" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app.js">
<entry file="file://$PROJECT_DIR$/app.json">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="47">
<caret line="58" column="67" lean-forward="true" selection-start-line="58" selection-start-column="67" selection-end-line="58" selection-end-column="67" />
<folding>
<element signature="n#!!doc" expanded="true" />
</folding>
<state relative-caret-position="44">
<caret line="2" column="24" selection-start-line="2" selection-start-column="24" selection-end-line="2" selection-end-column="24" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pages/index/index.wxss">
<entry file="file://$PROJECT_DIR$/pages/index/phone-code/phone-code.wxml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="154">
<caret line="7" column="21" lean-forward="true" selection-start-line="7" selection-start-column="21" selection-end-line="7" selection-end-column="21" />
<state relative-caret-position="264">
<caret line="12" column="68" selection-start-line="12" selection-start-column="68" selection-end-line="12" selection-end-column="68" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pages/start/start.js">
<entry file="file://$PROJECT_DIR$/pages/index/phone-code/phone-code.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="374">
<caret line="29" column="49" lean-forward="true" selection-start-line="29" selection-start-column="12" selection-end-line="29" selection-end-column="49" />
<state relative-caret-position="1870">
<caret line="85" column="40" selection-start-line="85" selection-start-column="40" selection-end-line="85" selection-end-column="40" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pages/index/index.wxml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="880">
<caret line="40" lean-forward="true" selection-start-line="40" selection-end-line="40" />
<state relative-caret-position="542">
<caret line="74" column="70" selection-start-line="74" selection-start-column="70" selection-end-line="74" selection-end-column="70" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/templates/templates.wxml">
<entry file="file://$PROJECT_DIR$/pages/index/activity-detail/activity-detail.wxml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="374">
<caret line="29" column="65" selection-start-line="29" selection-start-column="65" selection-end-line="29" selection-end-column="65" />
<state relative-caret-position="220">
<caret line="10" column="68" lean-forward="true" selection-start-line="10" selection-start-column="68" selection-end-line="10" selection-end-column="68" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pages/index/index.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="506">
<caret line="98" column="64" selection-start-line="98" selection-start-column="64" selection-end-line="98" selection-end-column="64" />
<state relative-caret-position="-418">
<caret line="8" column="23" selection-start-line="8" selection-start-column="23" selection-end-line="8" selection-end-column="23" />
<folding>
<element signature="n#!!doc" expanded="true" />
<element signature="e#1018#1103#0" />
<element signature="e#1121#1191#0" />
<element signature="e#1219#1288#0" />
<element signature="e#1321#1468#0" />
<element signature="e#1499#1619#0" />
<element signature="e#1750#1766#0" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app.json">
<entry file="file://$PROJECT_DIR$/pages/index/go-appointment/go-appointment.json">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/pages/index/activity-detail/activity-detail.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="440">
<caret line="20" column="38" selection-start-line="20" selection-start-column="38" selection-end-line="20" selection-end-column="38" />
<state relative-caret-position="374">
<caret line="29" column="44" lean-forward="true" selection-start-line="29" selection-start-column="44" selection-end-line="29" selection-end-column="44" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pages/index/activity-detail/activity-detail.json">
<provider selected="true" editor-type-id="text-editor" />
<entry file="file://$PROJECT_DIR$/pages/start/start.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="676">
<caret line="37" column="25" lean-forward="true" selection-start-line="37" selection-start-column="25" selection-end-line="37" selection-end-column="25" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pages/start/start.wxml">
<entry file="file://$PROJECT_DIR$/app.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="132">
<caret line="6" column="15" lean-forward="true" selection-start-line="6" selection-start-column="15" selection-end-line="6" selection-end-column="15" />
<state relative-caret-position="344">
<caret line="140" column="12" selection-start-line="140" selection-start-column="4" selection-end-line="140" selection-end-column="12" />
<folding>
<element signature="n#!!doc" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pages/index/activity-detail/activity-detail.js">
<entry file="file://$PROJECT_DIR$/utils/util.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="550">
<caret line="25" column="32" selection-start-line="25" selection-start-column="32" selection-end-line="25" selection-end-column="32" />
<state relative-caret-position="946">
<caret line="43" column="15" selection-start-line="43" selection-start-column="2" selection-end-line="43" selection-end-column="15" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pages/index/activity-detail/activity-detail.wxml">
<entry file="file://$PROJECT_DIR$/pages/index/confirm-appointment-info/confirm-appointment-info.wxml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="852">
<caret line="50" column="42" selection-start-line="50" selection-start-column="42" selection-end-line="50" selection-end-column="42" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pages/index/confirm-appointment-info/confirm-appointment-info.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="302">
<caret line="44" column="20" lean-forward="true" selection-start-line="44" selection-start-column="20" selection-end-line="44" selection-end-column="20" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pages/index/go-appointment/go-appointment.wxml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="638">
<caret line="41" column="90" selection-start-line="41" selection-start-column="72" selection-end-line="41" selection-end-column="90" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pages/index/go-appointment/go-appointment.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="198">
<caret line="9" column="35" selection-start-line="9" selection-start-column="35" selection-end-line="9" selection-end-column="35" />
<caret line="125" column="20" lean-forward="true" selection-start-line="125" selection-start-column="20" selection-end-line="125" selection-end-column="20" />
<folding>
<element signature="e#243#454#0" />
<element signature="e#462#673#0" />
<element signature="e#681#893#0" />
<element signature="e#901#1114#0" />
<element signature="e#1177#2298#0" />
</folding>
</state>
</provider>
</entry>
... ...
... ... @@ -89,6 +89,7 @@ App({
success: function (res) { }
})
} else {
console.log(res.data);
wx.showModal({
title: '提示',
content: res.data.msg,
... ... @@ -123,6 +124,7 @@ App({
})
},
//获取当前时间
nowDate() {
let date = new Date();
let month = date.getMonth() + 1;
... ...
... ... @@ -6,7 +6,12 @@ Page({
*/
data: {
punchState: true,
address: ''
address: '',
hasPhone: true,
},
//首次登录小程序,跳转到认证手机页面
goPhoneCode() {
wx.navigateTo({url: '/pages/index/phone-code/phone-code'})
},
//打卡申诉
punchApply() {
... ... @@ -30,6 +35,7 @@ Page({
})
},
})
// wx.chooseLocation({
// success: function(res) {
// console.log(res)
... ...
<!--pages/clock/clock.wxml-->
<view class='content_box'>
<!--蒙层-->
<view class="modal" wx:if="{{!hasPhone}}" bindtap="goPhoneCode"></view>
<view class='circle_large'>
<view class='circle_middle'>
<view class='circle_small'>
... ...
... ... @@ -13,7 +13,16 @@
align-items: center;
padding-top: 115rpx;
}
.modal {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
background-color: #000000;
opacity: 0.8;
z-index: 10;
}
.circle_large, .circle_middle, .circle_small {
width: 327rpx;
height: 327rpx;
... ...
// pages/index/activity-detail/activity-detail.js
var WxParse = require('../../../wxParse/wxParse.js');
const app = getApp();
Page({
... ... @@ -18,21 +19,39 @@ Page({
let params = {
id: this.data.test_id,//当前实验的id
};
let headers= {
let header = {
"XX-token": wx.getStorageSync('token')
};
app.post(url, params,headers).then((res) => {
app.post(url, params,header).then((res) => {
console.log(res);
this.setData({detail: res})
if(res.code === 0) {
wx.navigateTo({url: '/pages/index/phone-code/phone-code'})
}else {
this.setData({detail: res});
var article = res.content;
WxParse.wxParse('article', 'html', article, this, 5);
}
// console.log(this.data.this_week_test_info);
})
},
//服务协议
goServiceProtocol() {
wx.navigateTo({
url: '/pages/my/protocol/protocol',
})
},
goAppointment() {
wx.navigateTo({url: '/pages/index/go-appointment/go-appointment?experiment_id=' + this.data.detail.id})
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
console.log(options);
this.setData({test_id: +options.id});
this.setData({
test_id: +options.id,
is_the_week: options.is_the_week
});
this.getDetail()
},
... ...
... ... @@ -2,24 +2,27 @@
<view class="content">
<view class="head">
<view class="img_box">
<image src="../../../images/test_img.jpg" class="activity_img"></image>
<image src="{{detail.thumb}}" class="activity_img" mode="aspectFill"></image>
</view>
<view class="title">
<view class="line"></view>
<view class="test_detail">
<text>{{detail.name}}科学队长实验室:雷电的产生!</text>
<view class="describe">云和云摩擦碰撞发出的声音是雷声产生火花是闪电。</view>
<text>{{detail.name}}</text>
<view class="describe">{{detail.description}}</view>
</view>
</view>
</view>
<view class="jiexi">解析长图</view>
<view class="footer" wx:if="{{is_the_week}}">
<view class="service" bindtap="clickAgreeBtn" bindtap='serviceProtocol'>
<view class="jiexi">解析长图
<import src="/wxParse/wxParse.wxml"/>
<template is="wxParse" data="{{wxParseData:article.nodes}}"/>
</view>
<view class="footer" wx:if="{{detail.allow_res}}">
<view class="service" bindtap="clickAgreeBtn">
<view class="agree_box">
<view class="agree_btn" wx:if="{{is_agree}}"></view>
</view>
<text>服务协议</text>
<text catchtap="goServiceProtocol">服务协议</text>
</view>
<view class="order_btn" bindtap='goAppointment'>去预约</view>
</view>
... ...
... ... @@ -49,11 +49,14 @@ Page({
addStudent() {
wx.navigateTo({url: './add-student/add-student'})
},
getAppointmentInfo() {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
console.log(options);
},
/**
... ...
// pages/index/go-appointment/go-appointment.js
const util = require('../../../utils/util.js');
const app = getApp();
Page({
/**
* 页面的初始数据
*/
data: {
array: ['北京市', '天津市', '上海市', '河北省'],
cityList: [],
// city_index: 0,
currentCity: '北京市',
current_test_id: '',
is_change: false,
is_choose: false,
description: '',
session_list: {},
show_submit_btn: false,
areaTest: [{
area: '朝阳区',
... ... @@ -104,28 +111,49 @@ Page({
bindPickerChange: function(e) {
console.log('picker发送选择改变,携带值为', e.detail.value)
this.setData({
index: e.detail.value,
city_index: e.detail.value,
is_change: true,
})
});
this.getChooseSession(this.data.cityList[e.detail.value])
},
//选择实验室
chooseTest(e) {
console.log(e.currentTarget.dataset.index);
// console.log(e);
// console.log('实验',e.currentTarget.dataset.index);
const current = e.currentTarget.dataset.index;
const current_id = e.currentTarget.dataset.id;
// console.log(this.data.areaTest[0].lab_list[0].session_list[0].id);
this.setData({
currentTest: current,
currentId: current_id
})
current_test_id: current_id,
is_choose: false,//恢复默认值
// current_session_id: this.data.areaTest[current].lab_list ? this.data.areaTest[current].lab_list[0].session_list[0].id : '',
// description: this.data.areaTest[current].lab_list[current].description
});
// console.log(util.formatTimeTwo(1543375800,'h:m'),'1543375800');
return this.data.areaTest.forEach((item,index) => {
if(item.lab_list[current].id === current_id) {
// console.log(current_id, item.lab_list[current].id,item.lab_list[current].description);
this.setData({
description: item.lab_list[current].description ? item.lab_list[current].description : '',
session_list: item.lab_list[current].session_list ? item.lab_list[current].session_list: '',
});
// return
}
});
// console.log(a);
// console.log(this.data.areaTest[current].lab_list[current].description);
},
//选择时段
//选择场次
chooseTime(e) {
console.log(e.currentTarget.dataset.index);
const current = e.currentTarget.dataset.index;
const current_id = e.currentTarget.dataset.id;
this.setData({
currentTime: current
currentTime: current,
current_session_id: current_id,
is_choose: true,
})
},
... ... @@ -135,7 +163,7 @@ Page({
// show_submit_btn: true
// })
wx.navigateTo({
url: '/pages/index/confirm-appointment-info/confirm-appointment-info'
url: '/pages/index/confirm-appointment-info/confirm-appointment-info?num=' + 1
})
},
... ... @@ -145,20 +173,93 @@ Page({
// show_submit_btn: true
// })
wx.navigateTo({
url: '/pages/index/confirm-appointment-info/confirm-appointment-info'
url: '/pages/index/confirm-appointment-info/confirm-appointment-info?num=' + 2
})
},
submit() {
if(this.data.is_choose) {
wx.navigateTo({
url: '/pages/index/confirm-appointment-info/confirm-appointment-info'
url: '/pages/index/confirm-appointment-info/confirm-appointment-info?experiment_id=' + this.data.current_test_id
+ '&session_id=' + this.data.current_session_id
})
}else {
wx.showToast({title: '请选择场次!',icon: 'none'})
}
},
//获取城市列表
getCity() {
let url = '/portal/Experiment/cityList';
let header = {
"XX-token": wx.getStorageSync('token')
};
app.post(url, {},header).then((res) => {
console.log(res);
var city_list = [];
res.forEach((item,index) => {
city_list.push(item.city)
});
console.log(city_list,res);
this.setData({
cityList: city_list,
// description: res.list[0].lab_list[0].description,//默认显示第一个实验室的描述
// session_list: res.list[0].lab_list[0].session_list//默认显示第一个实验室的实验时间
})
// console.log(this.data.this_week_test_info);
})
},
//获取预约城市、区、实验室、场次
getChooseSession(city) {
let url = '/portal/Experiment/choose_session';
let params = {
experiment_id: this.data.experiment_id,
city: city,
};
let header = {
"XX-token": wx.getStorageSync('token')
};
app.post(url, params,header).then((res) => {
console.log(res,res.list);
res.list.forEach((item,index) => {
if(item.lab_list) {
item.lab_list.forEach((i,k) => {
if(i.session_list) {
i.session_list.forEach((j,b) => {
j.start_time = util.formatTimeTwo(j.start_time, 'h:m');
j.end_time = util.formatTimeTwo(j.end_time, 'h:m');
})
}
})
}
});
console.log(res,res.list);
// console.log(res.list[0].lab_list[0].id);
this.setData({
areaTest: res.list,
// current_test_id: res.list[0].lab_list ? res.list[0].lab_list[0].id : '',//默认实验室id
// current_session_id: res.list[0].lab_list ? res.list[0].lab_list[0].session_list[0].id : '',//默认场次id
description: res.list[0].lab_list ? res.list[0].lab_list[0].description : '',//默认显示第一个实验室的描述
session_list: res.list[0].lab_list ? res.list[0].lab_list[0].session_list :''//默认显示第一个实验室的实验时间
})
// console.log(this.data.this_week_test_info);
})
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function(options) {
const self = this;
self.setData({experiment_id: +options.experiment_id});
if(wx.getStorageSync('city')) {
const city = wx.getStorageSync('city');
self.getChooseSession(city);
}else {
const city = '北京市';
self.getChooseSession(city);
}
self.getCity();
this.data.areaTest.forEach((v, i) => {
Object.keys(v).forEach(v => {
console.log(v) //取到了key
... ...
<!--pages/index/go-appointment/go-appointment.wxml-->
<view class="content">
<view class="city_box">
<picker bindchange="bindPickerChange" value="{{index}}" range="{{array}}">
<picker bindchange="bindPickerChange" value="{{city_index}}" range="{{cityList}}">
<view class="select">
<view class="picker" wx:if="{{is_change}}">
{{array[index]}}
{{cityList[city_index]}}
</view>
<view wx:else>北京市</view>
<view class="iconfont icon-daosanjiao"></view>
... ... @@ -15,16 +15,16 @@
<view class="section">
<scroll-view class="area_box" scroll-y>
<block wx:for="{{areaTest}}" wx:key="index">
<view class="area-test">
<view class="area">{{item.area}}</view>
<view class="area-test" data-index="{{index}}" wx:for-index="{{idx}}">
<view class="area">{{item.name}}</view>
<view class="test-list">
<view class="list-item-box">
<block wx:for="{{item.list}}" wx:key="index">
<block wx:for="{{item.lab_list}}" wx:key="index">
<view class="list-item" bindtap="chooseTest" data-index="{{index}}"
data-id="{{item.id}}">
<image src="../../../images/blue_line.png" wx:if="{{currentId === item.id}}"
<image src="../../../images/blue_line.png" wx:if="{{current_test_id === item.id}}"
class="blue-line"></image>
<view class="test {{currentId === item.id?'change-color':''}}">{{item.name}}</view>
<view class="test {{current_test_id === item.id?'change-color':''}}">{{item.name}}</view>
</view>
</block>
</view>
... ... @@ -35,17 +35,17 @@
<view class="test_box">
<scroll-view scroll-y class="test_describe">
{{test.title}}
{{description}}
</scroll-view>
<scroll-view class="time-list-box" scroll-y>
<view wx:for="{{test.list}}" wx:key="index" class="time-list" bindtap="chooseTime" data-index="{{index}}">
<image src="../../../images/blue_line.png" wx:if="{{currentTime === index && item.rest !== 0}}"
<view wx:for="{{session_list}}" wx:key="index" class="time-list" bindtap="chooseTime" data-index="{{index}}" data-id="{{item.id}}">
<image src="../../../images/blue_line.png" wx:if="{{current_session_id === item.id}}"
class="blue-line"></image>
<view class="right-content {{item.rest === 0? 'change-gray':''}}">
<view class="{{currentTime === index && item.rest !== 0? 'change-color':''}}">{{item.week}} {{item.date}}</view>
<view class="{{current_session_id === item.id? 'change-color':''}}">{{item.weekday}} {{item.date}}</view>
<view class="bottom-time-box">
<text class="time {{currentTime === index && item.rest !== 0? 'change-color':''}}">{{item.time}}</text>
<text class="rest {{item.rest === 0? 'change-gray':''}}">剩余: {{item.rest}}</text>
<text class="time {{current_session_id === item.id? 'change-color':''}}">{{item.time}}</text>
<text class="rest {{item.rest === 0? 'change-gray':''}}">剩余: {{item.surplus_num}}</text>
</view>
</view>
</view>
... ... @@ -54,13 +54,14 @@
</view>
<view class="footer">
<view class="confirm_btn" bindtap="submit" wx:if="{{show_submit_btn}}">
<!--<view class="confirm_btn" bindtap="submit" wx:if="{{show_submit_btn}}">-->
<view class="confirm_btn" bindtap="submit">
<text>提 交</text>
</view>
<view class="appointment-box" wx:else>
<text class="single" bindtap="singleAppointment">单人预约</text>
<text class="double" bindtap="doubleAppointment">双人预约</text>
</view>
<!--<view class="appointment-box" wx:else>-->
<!--<text class="single" bindtap="singleAppointment">单人预约</text>-->
<!--<text class="double" bindtap="doubleAppointment">双人预约</text>-->
<!--</view>-->
<!--<view>提 交</view>-->
</view>
</view>
... ...
//index.js
//获取应用实例
const app = getApp()
const app = getApp();
// 引入SDK核心类
var QQMapWX = require('../../utils/qqmap-wx-jssdk.min.js');
Page({
data: {
hasPhone: true,
hasPhone: false,
imgUrls: [
{'url': '../../images/banner.jpg'},
{'url': '../../images/banner.jpg'},
... ... @@ -28,6 +30,21 @@ Page({
is_past: true,
},
},
//判断手机号是否绑定
checkMobile() {
let url = '/portal/Index/check_mobile';
let header = {
"XX-token": wx.getStorageSync('token')
};
app.post(url, {},header).then((res) => {
console.log(res);
if(res.is_binding) {
this.setData({hasPhone: true})
}else {
this.setData({hasPhone: false})
}
})
},
swiperChange: function (e) { //切换轮播图
this.setData({
currentSwiper: e.detail.current
... ... @@ -44,13 +61,17 @@ Page({
//点击进入活动详情
goTestDetail(e) {
// console.log(e);
const current = e.currentTarget.dataset.index;
wx.navigateTo({url: './activity-detail/activity-detail'})
const is_the_week = e.currentTarget.dataset.is_the_week;
const id = e.currentTarget.dataset.id;
wx.navigateTo({
url: './activity-detail/activity-detail?is_the_week=' + is_the_week +
'&id=' + id
})
},
//前往预约
goAppointment(e) {
const current = e.currentTarget.dataset.index;
wx.navigateTo({url: './go-appointment/go-appointment'})
const id = e.currentTarget.dataset.id;
wx.navigateTo({url: './go-appointment/go-appointment?experiment_id=' + id})
},
//获取轮播图
getSlideImage() {
... ... @@ -58,15 +79,9 @@ Page({
let params = {
city: this.data.city,
};
app.post(url, params).then((ret) => {
wx.setStorageSync('token', ret.token)
app.globalData.userInfo = ret.user_type
// console.log('userInfo',app.globalData.userInfo,ret);
if (ret.user_type == 2) {
wx.switchTab({
url: '/pages/index/index',
})
}
app.post(url, params).then((res) => {
console.log(res);
this.setData({imgUrls: res.list})
})
},
//获取本周实验
... ... @@ -99,22 +114,52 @@ Page({
const id = e.currentTarget.dataset.id;
wx.navigateTo({url: '/pages/index/activity-detail/activity-detail?test_id=' + id})
},
getUser() {
let url = '/user/Profile/getUserInfo';
let header = {
"XX-token": wx.getStorageSync('token')
};
app.post(url, {},header).then((res) => {
console.log('个人信息结果',res);
// self.setData({past_test_info: res})
// console.log(self.data.this_week_test_info);
});
},
onLoad: function () {
this.getTheWeekTest();
this.getPastWeekTest();
const self = this;
self.getTheWeekTest();
self.getPastWeekTest();
self.getUser();
self.checkMobile();
//获取当前城市
wx.getLocation({
type: 'wgs84',
success: function(res) {
console.log(res);
let url = '/public/getAddressInfoByCoordinate';
let params = {
// 实例化API核心类
var demo = new QQMapWX({
key: 'CLVBZ-KHZKP-KWLDW-VDJTA-QVUST-XOBVO' // 必填
});
// 调用接口
demo.reverseGeocoder({
location: {
latitude: res.latitude,//纬度
longitude: res.longitude//经度
};
// app.post(url,params).then((res) => {
// // console.log('获取城市',res);
// self.setData({city: res.city})
// })
},
success: function (res) {
console.log(res);
self.setData({city: res.result.address_component.city});
wx.setStorageSync('city', res.result.address_component.city);
self.getSlideImage();
},
fail: function (res) {
console.log(res);
},
complete: function (res) {
// console.log(res);
}
});
}
});
},
... ...
... ... @@ -5,12 +5,13 @@
<!--轮播图-->
<view class="wrap">
<swiper autoplay="{{autoplay}}" interval="{{interval}}" duration="{{duration}}" circular="true" bindchange="swiperChange">
<swiper autoplay="{{autoplay}}" interval="{{interval}}" duration="{{duration}}" circular="true"
bindchange="swiperChange">
<block wx:for="{{imgUrls}}" wx:key="index">
<swiper-item>
<navigator url="{{item.url}}" hover-class="navigator-hover">
<view class="index_top">
<image src="{{item.url}}" class="slide-image" mode="aspectFill" />
<image src="{{item.image}}" class="slide-image" mode="aspectFill"/>
</view>
</navigator>
</swiper-item>
... ... @@ -31,9 +32,9 @@
</view>
<!--实验列表-->
<!--<import src="/templates/templates.wxml" />-->
<!--<import src="/templates/templates.wxml"/>-->
<!--<view class="past_template">-->
<!--<template is="experiment" data="{{...this_week_test_info}}"></template>-->
<!--<template is="experiment" data="{{this_week_test_info}}"></template>-->
<!--<template is="experiment" data="{{...past_test_info}}"></template>-->
<!--</view>-->
<!-- <import src="/templates/templates.wxml" /> -->
... ... @@ -46,15 +47,16 @@
<text>本周实验</text>
<!-- <text>往期实验</text> -->
</view>
<view wx:for="{{info}}" wx:key="index" data-index="{{index}}" bindtap="goTestDetail" data-is_the_week='{{true}}'>
<view bindtap="goTestDetail"
data-is_the_week='{{true}}' data-id="{{this_week_test_info.id}}">
<view class="test_box">
<view class="time">{{item.time}}</view>
<view class="time">{{this_week_test_info.start_time}} - {{this_week_test_info.end_time}}</view>
<view class="img_box">
<image src="{{item.url}}"></image>
<image src="{{this_week_test_info.thumb}}" mode="aspectFill"></image>
</view>
</view>
<view class="order_box">
<text catchtap="goAppointment" data-index="{{index}}">前往预约</text>
<text catchtap="goAppointment" data-index="{{index}}" data-id="{{this_week_test_info.id}}">前往预约</text>
</view>
</view>
</view>
... ... @@ -65,11 +67,12 @@
<view class="line"></view>
<text>往期实验</text>
</view>
<view wx:for="{{info}}" wx:key="index" data-index="{{index}}" bindtap="goTestDetail" data-is_the_week='{{false}}'>
<view wx:for="{{past_test_info.list}}" wx:key="index" data-index="{{index}}" data-id="{{item.id}}" bindtap="goTestDetail"
data-is_the_week='{{false}}'>
<view class="test_box">
<view class="time">{{item.time}}</view>
<view class="time">{{item.start_time}} - {{item.end_time}}</view>
<view class="img_box">
<image src="{{item.url}}"></image>
<image src="{{item.thumb}}" mode="aspectFill"></image>
</view>
</view>
<view class="order_box">
... ...
// pages/index/phone-code/phone-code.js
const app = getApp();
var interval = null //倒计时函数
Page({
... ... @@ -8,12 +9,20 @@ Page({
data: {
fun_id: 2,
time: '获取验证码', //倒计时
currentTime: 61
currentTime: 61,
phone_number: '',
verification_code: '',
},
phoneInput(e) {
this.setData({phone_number: e.detail.value})
},
codeInput(e) {
this.setData({verification_code: e.detail.value})
},
getCode: function(options) {
getCode: function (options) {
var that = this;
var currentTime = that.data.currentTime;
interval = setInterval(function() {
interval = setInterval(function () {
currentTime--;
that.setData({
time: currentTime + '秒'
... ... @@ -26,74 +35,116 @@ Page({
disabled: false
})
}
}, 1000)
}, 1000);
let url = '/user/Profile/getCode';
let params = {
mobile: that.data.phone_number,
};
let header = {
"XX-token": wx.getStorageSync('token')
};
app.post(url, params,header).then((res) => {
console.log(res);
that.setData({verification_code: res.code})
// console.log(this.data.this_week_test_info);
})
},
getVerificationCode() {
this.getCode();
var that = this;
if(that.data.phone_number !== '') {
that.getCode();
that.setData({
disabled: true
})
}else {
that.setData({
disabled: false
});
wx.showToast({title: '请输入手机号!',icon: 'none'})
}
},
//确认
confirm() {
//确认绑定
formSubmit(e) {
console.log(e.detail);
const self = this;
if(self.data.phone_number === '') {
wx.showToast({title: '请输入手机号!',icon: 'none'})
}else if(self.data.verification_code === '') {
wx.showToast({title: '请输入验证码!',icon: 'none'})
}else {
let url = '/user/Profile/bindingMobile';
let params = {
_type: 1,
formId: e.detail.formId,
mobile: e.detail.value.phone_number,
verification_code: e.detail.value.verification_code,
};
let header = {
"XX-token": wx.getStorageSync('token')
};
app.post(url, params,header).then((res) => {
console.log('绑定结果',res);
// self.setData({past_test_info: res})
// console.log(self.data.this_week_test_info);
});
wx.switchTab({
url: '../../index/index'
})
}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function(options) {
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function() {
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function() {
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function() {
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function() {
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function() {
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function() {
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function() {
onShareAppMessage: function () {
}
})
\ No newline at end of file
... ...
... ... @@ -4,19 +4,23 @@
<image src="../../../images/logo.png"></image>
</view>
<form bindsubmit="formSubmit" bindreset="formReset" report-submit="true">
<view class="phone_box">
<input type="number" placeholder="请输入您的手机号" placeholder-class="placeholder" class="phone_num"/>
<input type="number" placeholder="请输入您的手机号" placeholder-class="placeholder" class="phone_num"
value="{{phone_number}}" bindinput="phoneInput" name="phone_number"/>
<view class="code_box">
<input type="number" placeholder="输入验证码" placeholder-class="placeholder"/>
<button class="button" disabled="{{disabled}}" data-id="2" bindtap="getVerificationCode" >
<input type="number" placeholder="输入验证码" placeholder-class="placeholder" value="{{verification_code}}"
bindinput="codeInput" name="verification_code"/>
<button class="button" disabled="{{disabled}}" data-id="2" bindtap="getVerificationCode">
{{time}}
</button>
</view>
</view>
<view class="confirm_box">
<view class="confirm_btn" bindtap='confirm'>
<button class="confirm_btn" form-type="submit">
<text>确 定</text>
</button>
</view>
</view>
</form>
</view>
... ...
... ... @@ -5,7 +5,11 @@
* 页面的初始数据
*/
data: {
hasPhone: true,
},
//首次登录小程序,跳转到认证手机页面
goPhoneCode() {
wx.navigateTo({url: '/pages/index/phone-code/phone-code'})
},
//兑换
charge() {
... ...
<!--pages/my/my.wxml-->
<view class='box'>
<!--蒙层-->
<view class="modal" wx:if="{{!hasPhone}}" bindtap="goPhoneCode"></view>
<view class='header_box '>
<view class='head_box'>
<view class='head_img'>
... ...
... ... @@ -15,6 +15,16 @@
padding: 0 24rpx;
box-sizing: border-box;
}
.modal {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
background-color: #000000;
opacity: 0.8;
z-index: 10;
}
.icon-bianji2{
font-size: 50rpx;
text-align: center;
... ...
// pages/protocol/protocol.js
const app = getApp();
Page({
/**
* 页面的初始数据
*/
data: {
service_protocol: {},
},
getServiceProtocol() {
let url = '/wxapp/public/arc_service';
app.post(url, {},{}).then((res) => {
console.log(res);
this.setData({service_protocol: res})
})
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
this.getServiceProtocol();
},
/**
... ...
<!--pages/protocol/protocol.wxml-->
<view class='content_box'>
还有简短的汉字以内的文字介绍还有简短的汉字以内 的文字介绍还有简短的汉字以内的文字介绍还有简短 的汉字以 还有简短的汉字以内的文字介绍还有简短的汉字以内 的文字介绍还有简短的汉字以内的文字介绍还有简短 的汉字以
<view>{{service_protocol.title}}</view>
<view>{{service_protocol.description}}</view>
</view>
\ No newline at end of file
... ...
... ... @@ -12,12 +12,7 @@ Page({
// 获取用户信息
start(e) {
let that = this;
console.log('点击');
// wx.redirectTo({
// url: '/pages/index/index',
// })
let url = '/wxapp/public/login';
// console.log(that.data.openid)
let params = {
encrypted_data: e.detail.encryptedData,
iv: e.detail.iv,
... ... @@ -30,11 +25,9 @@ Page({
wx.setStorageSync('token', ret.token)
app.globalData.userInfo = ret.user_type
// console.log('userInfo',app.globalData.userInfo,ret);
if (ret.user_type == 2) {
wx.switchTab({
url: '/pages/index/index',
})
}
})
},
example() {
... ... @@ -55,11 +48,10 @@ Page({
let url = '/wxapp/public/getSessionKey'
wx.login({
success: function (res) {
console.log(res)
// console.log(res)
app.post(url, {
code: res.code
}, {}).then((ret) => {
console.log('res',ret);
that.setData({
openid: ret.openid,
session_key: ret.session_key
... ...
... ... @@ -12,7 +12,7 @@
},
"compileType": "miniprogram",
"libVersion": "2.4.0",
"appid": "wxaab44bbcfc0e5bc5",
"appid": "wx9053b434e50ee2dd",
"projectname": "science",
"debugOptions": {
"hidedInDevtools": []
... ...
var _createClass=function(){function a(e,c){for(var b=0;b<c.length;b++){var d=c[b];d.enumerable=d.enumerable||false;d.configurable=true;if("value" in d){d.writable=true}Object.defineProperty(e,d.key,d)}}return function(d,b,c){if(b){a(d.prototype,b)}if(c){a(d,c)}return d}}();function _classCallCheck(a,b){if(!(a instanceof b)){throw new TypeError("Cannot call a class as a function")}}var ERROR_CONF={KEY_ERR:311,KEY_ERR_MSG:"key格式错误",PARAM_ERR:310,PARAM_ERR_MSG:"请求参数信息有误",SYSTEM_ERR:600,SYSTEM_ERR_MSG:"系统错误",WX_ERR_CODE:1000,WX_OK_CODE:200};var BASE_URL="https://apis.map.qq.com/ws/";var URL_SEARCH=BASE_URL+"place/v1/search";var URL_SUGGESTION=BASE_URL+"place/v1/suggestion";var URL_GET_GEOCODER=BASE_URL+"geocoder/v1/";var URL_CITY_LIST=BASE_URL+"district/v1/list";var URL_AREA_LIST=BASE_URL+"district/v1/getchildren";var URL_DISTANCE=BASE_URL+"distance/v1/";var Utils={location2query:function location2query(c){if(typeof c=="string"){return c}var b="";for(var a=0;a<c.length;a++){var e=c[a];if(!!b){b+=";"}if(e.location){b=b+e.location.lat+","+e.location.lng}if(e.latitude&&e.longitude){b=b+e.latitude+","+e.longitude}}return b},getWXLocation:function getWXLocation(c,b,a){wx.getLocation({type:"gcj02",success:c,fail:b,complete:a})},getLocationParam:function getLocationParam(b){if(typeof b=="string"){var a=b.split(",");if(a.length===2){b={latitude:b.split(",")[0],longitude:b.split(",")[1]}}else{b={}}}return b},polyfillParam:function polyfillParam(a){a.success=a.success||function(){};a.fail=a.fail||function(){};a.complete=a.complete||function(){}},checkParamKeyEmpty:function checkParamKeyEmpty(c,b){if(!c[b]){var a=this.buildErrorConfig(ERROR_CONF.PARAM_ERR,ERROR_CONF.PARAM_ERR_MSG+b+"参数格式有误");c.fail(a);c.complete(a);return true}return false},checkKeyword:function checkKeyword(a){return !this.checkParamKeyEmpty(a,"keyword")},checkLocation:function checkLocation(c){var a=this.getLocationParam(c.location);if(!a||!a.latitude||!a.longitude){var b=this.buildErrorConfig(ERROR_CONF.PARAM_ERR,ERROR_CONF.PARAM_ERR_MSG+" location参数格式有误");c.fail(b);c.complete(b);return false}return true},buildErrorConfig:function buildErrorConfig(a,b){return{status:a,message:b}},buildWxRequestConfig:function buildWxRequestConfig(c,a){var b=this;a.header={"content-type":"application/json"};a.method="GET";a.success=function(d){var e=d.data;if(e.status===0){c.success(e)}else{c.fail(e)}};a.fail=function(d){d.statusCode=ERROR_CONF.WX_ERR_CODE;c.fail(b.buildErrorConfig(ERROR_CONF.WX_ERR_CODE,result.errMsg))};a.complete=function(d){var e=+d.statusCode;switch(e){case ERROR_CONF.WX_ERR_CODE:c.complete(b.buildErrorConfig(ERROR_CONF.WX_ERR_CODE,d.errMsg));break;case ERROR_CONF.WX_OK_CODE:var f=d.data;if(f.status===0){c.complete(f)}else{c.complete(b.buildErrorConfig(f.status,f.message))}break;default:c.complete(b.buildErrorConfig(ERROR_CONF.SYSTEM_ERR,ERROR_CONF.SYSTEM_ERR_MSG))}};return a},locationProcess:function locationProcess(f,e,c,a){var d=this;c=c||function(g){g.statusCode=ERROR_CONF.WX_ERR_CODE;f.fail(d.buildErrorConfig(ERROR_CONF.WX_ERR_CODE,g.errMsg))};a=a||function(g){if(g.statusCode==ERROR_CONF.WX_ERR_CODE){f.complete(d.buildErrorConfig(ERROR_CONF.WX_ERR_CODE,g.errMsg))}};if(!f.location){d.getWXLocation(e,c,a)}else{if(d.checkLocation(f)){var b=Utils.getLocationParam(f.location);e(b)}}}};var QQMapWX=function(){function b(i){_classCallCheck(this,b);if(!i.key){throw Error("key值不能为空")}this.key=i.key}_createClass(b,[{key:"search",value:function f(i){var l=this;i=i||{};Utils.polyfillParam(i);if(!Utils.checkKeyword(i)){return}var k={keyword:i.keyword,orderby:i.orderby||"_distance",page_size:i.page_size||10,page_index:i.page_index||1,output:"json",key:l.key};if(i.address_format){k.address_format=i.address_format}if(i.filter){k.filter=i.filter}var n=i.distance||"1000";var j=i.auto_extend||1;var m=function m(o){k.boundary="nearby("+o.latitude+","+o.longitude+","+n+","+j+")";wx.request(Utils.buildWxRequestConfig(i,{url:URL_SEARCH,data:k}))};Utils.locationProcess(i,m)}},{key:"getSuggestion",value:function h(i){var k=this;i=i||{};Utils.polyfillParam(i);if(!Utils.checkKeyword(i)){return}var j={keyword:i.keyword,region:i.region||"全国",region_fix:i.region_fix||0,policy:i.policy||0,output:"json",key:k.key};wx.request(Utils.buildWxRequestConfig(i,{url:URL_SUGGESTION,data:j}))}},{key:"reverseGeocoder",value:function a(i){var k=this;i=i||{};Utils.polyfillParam(i);var j={coord_type:i.coord_type||5,get_poi:i.get_poi||0,output:"json",key:k.key};if(i.poi_options){j.poi_options=i.poi_options}var l=function l(m){j.location=m.latitude+","+m.longitude;wx.request(Utils.buildWxRequestConfig(i,{url:URL_GET_GEOCODER,data:j}))};Utils.locationProcess(i,l)}},{key:"geocoder",value:function g(i){var k=this;i=i||{};Utils.polyfillParam(i);if(Utils.checkParamKeyEmpty(i,"address")){return}var j={address:i.address,output:"json",key:k.key};wx.request(Utils.buildWxRequestConfig(i,{url:URL_GET_GEOCODER,data:j}))}},{key:"getCityList",value:function c(i){var k=this;i=i||{};Utils.polyfillParam(i);var j={output:"json",key:k.key};
wx.request(Utils.buildWxRequestConfig(i,{url:URL_CITY_LIST,data:j}))}},{key:"getDistrictByCityId",value:function d(i){var k=this;i=i||{};Utils.polyfillParam(i);if(Utils.checkParamKeyEmpty(i,"id")){return}var j={id:i.id||"",output:"json",key:k.key};wx.request(Utils.buildWxRequestConfig(i,{url:URL_AREA_LIST,data:j}))}},{key:"calculateDistance",value:function e(i){var k=this;i=i||{};Utils.polyfillParam(i);if(Utils.checkParamKeyEmpty(i,"to")){return}var j={mode:i.mode||"walking",to:Utils.location2query(i.to),output:"json",key:k.key};var l=function l(m){j.from=m.latitude+","+m.longitude;wx.request(Utils.buildWxRequestConfig(i,{url:URL_DISTANCE,data:j}))};if(i.from){i.location=i.from}Utils.locationProcess(i,l)}}]);return b}();module.exports=QQMapWX;
\ No newline at end of file
... ...
... ... @@ -14,6 +14,32 @@ const formatNumber = n => {
return n[1] ? n : '0' + n
}
/**
* 时间戳转化为年 月 日 时 分 秒
* number: 传入时间戳
* format:返回格式,支持自定义,但参数必须与formateArr里保持一致
*/
function formatTimeTwo(number, format) {
var formateArr = ['Y', 'M', 'D', 'h', 'm', 's'];
var returnArr = [];
var date = new Date(number * 1000);
returnArr.push(date.getFullYear());
returnArr.push(formatNumber(date.getMonth() + 1));
returnArr.push(formatNumber(date.getDate()));
returnArr.push(formatNumber(date.getHours()));
returnArr.push(formatNumber(date.getMinutes()));
returnArr.push(formatNumber(date.getSeconds()));
for (var i in returnArr) {
format = format.replace(formateArr[i], returnArr[i]);
}
return format;
}
module.exports = {
formatTime: formatTime
formatTime: formatTime,
formatTimeTwo: formatTimeTwo
}
... ...
/**
* html2Json 改造来自: https://github.com/Jxck/html2json
*
*
* author: Di (微信小程序开发工程师)
* organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
* 垂直微信小程序开发交流社区
*
* github地址: https://github.com/icindy/wxParse
*
* for: 微信小程序富文本解析
* detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
*/
var __placeImgeUrlHttps = "https";
var __emojisReg = '';
var __emojisBaseSrc = '';
var __emojis = {};
var wxDiscode = require('./wxDiscode.js');
var HTMLParser = require('./htmlparser.js');
// Empty Elements - HTML 5
var empty = makeMap("area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr");
// Block Elements - HTML 5
var block = makeMap("br,a,code,address,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video");
// Inline Elements - HTML 5
var inline = makeMap("abbr,acronym,applet,b,basefont,bdo,big,button,cite,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var");
// Elements that you can, intentionally, leave open
// (and which close themselves)
var closeSelf = makeMap("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr");
// Attributes that have their values filled in disabled="disabled"
var fillAttrs = makeMap("checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected");
// Special Elements (can contain anything)
var special = makeMap("wxxxcode-style,script,style,view,scroll-view,block");
function makeMap(str) {
var obj = {}, items = str.split(",");
for (var i = 0; i < items.length; i++)
obj[items[i]] = true;
return obj;
}
function q(v) {
return '"' + v + '"';
}
function removeDOCTYPE(html) {
return html
.replace(/<\?xml.*\?>\n/, '')
.replace(/<.*!doctype.*\>\n/, '')
.replace(/<.*!DOCTYPE.*\>\n/, '');
}
function trimHtml(html) {
return html
.replace(/\r?\n+/g, '')
.replace(/<!--.*?-->/ig, '')
.replace(/\/\*.*?\*\//ig, '')
.replace(/[ ]+</ig, '<')
}
function html2json(html, bindName) {
//处理字符串
html = removeDOCTYPE(html);
html = trimHtml(html);
html = wxDiscode.strDiscode(html);
//生成node节点
var bufArray = [];
var results = {
node: bindName,
nodes: [],
images:[],
imageUrls:[]
};
var index = 0;
HTMLParser(html, {
start: function (tag, attrs, unary) {
//debug(tag, attrs, unary);
// node for this element
var node = {
node: 'element',
tag: tag,
};
if (bufArray.length === 0) {
node.index = index.toString()
index += 1
} else {
var parent = bufArray[0];
if (parent.nodes === undefined) {
parent.nodes = [];
}
node.index = parent.index + '.' + parent.nodes.length
}
if (block[tag]) {
node.tagType = "block";
} else if (inline[tag]) {
node.tagType = "inline";
} else if (closeSelf[tag]) {
node.tagType = "closeSelf";
}
if (attrs.length !== 0) {
node.attr = attrs.reduce(function (pre, attr) {
var name = attr.name;
var value = attr.value;
if (name == 'class') {
// console.dir(value);
// value = value.join("")
node.classStr = value;
}
// has multi attibutes
// make it array of attribute
if (name == 'style') {
console.dir(value);
// value = value.join("")
node.styleStr = value;
}
if (value.match(/ /)) {
value = value.split(' ');
}
// if attr already exists
// merge it
if (pre[name]) {
if (Array.isArray(pre[name])) {
// already array, push to last
pre[name].push(value);
} else {
// single value, make it array
pre[name] = [pre[name], value];
}
} else {
// not exist, put it
pre[name] = value;
}
return pre;
}, {});
}
//对img添加额外数据
if (node.tag === 'img') {
node.imgIndex = results.images.length;
var imgUrl = node.attr.src;
if (imgUrl[0] == '') {
imgUrl.splice(0, 1);
}
imgUrl = wxDiscode.urlToHttpUrl(imgUrl, __placeImgeUrlHttps);
node.attr.src = imgUrl;
node.from = bindName;
results.images.push(node);
results.imageUrls.push(imgUrl);
}
// 处理font标签样式属性
if (node.tag === 'font') {
var fontSize = ['x-small', 'small', 'medium', 'large', 'x-large', 'xx-large', '-webkit-xxx-large'];
var styleAttrs = {
'color': 'color',
'face': 'font-family',
'size': 'font-size'
};
if (!node.attr.style) node.attr.style = [];
if (!node.styleStr) node.styleStr = '';
for (var key in styleAttrs) {
if (node.attr[key]) {
var value = key === 'size' ? fontSize[node.attr[key]-1] : node.attr[key];
node.attr.style.push(styleAttrs[key]);
node.attr.style.push(value);
node.styleStr += styleAttrs[key] + ': ' + value + ';';
}
}
}
//临时记录source资源
if(node.tag === 'source'){
results.source = node.attr.src;
}
if (unary) {
// if this tag doesn't have end tag
// like <img src="hoge.png"/>
// add to parents
var parent = bufArray[0] || results;
if (parent.nodes === undefined) {
parent.nodes = [];
}
parent.nodes.push(node);
} else {
bufArray.unshift(node);
}
},
end: function (tag) {
//debug(tag);
// merge into parent tag
var node = bufArray.shift();
if (node.tag !== tag) console.error('invalid state: mismatch end tag');
//当有缓存source资源时于于video补上src资源
if(node.tag === 'video' && results.source){
node.attr.src = results.source;
delete results.source;
}
if (bufArray.length === 0) {
results.nodes.push(node);
} else {
var parent = bufArray[0];
if (parent.nodes === undefined) {
parent.nodes = [];
}
parent.nodes.push(node);
}
},
chars: function (text) {
//debug(text);
var node = {
node: 'text',
text: text,
textArray:transEmojiStr(text)
};
if (bufArray.length === 0) {
node.index = index.toString()
index += 1
results.nodes.push(node);
} else {
var parent = bufArray[0];
if (parent.nodes === undefined) {
parent.nodes = [];
}
node.index = parent.index + '.' + parent.nodes.length
parent.nodes.push(node);
}
},
comment: function (text) {
//debug(text);
// var node = {
// node: 'comment',
// text: text,
// };
// var parent = bufArray[0];
// if (parent.nodes === undefined) {
// parent.nodes = [];
// }
// parent.nodes.push(node);
},
});
return results;
};
function transEmojiStr(str){
// var eReg = new RegExp("["+__reg+' '+"]");
// str = str.replace(/\[([^\[\]]+)\]/g,':$1:')
var emojiObjs = [];
//如果正则表达式为空
if(__emojisReg.length == 0 || !__emojis){
var emojiObj = {}
emojiObj.node = "text";
emojiObj.text = str;
array = [emojiObj];
return array;
}
//这个地方需要调整
str = str.replace(/\[([^\[\]]+)\]/g,':$1:')
var eReg = new RegExp("[:]");
var array = str.split(eReg);
for(var i = 0; i < array.length; i++){
var ele = array[i];
var emojiObj = {};
if(__emojis[ele]){
emojiObj.node = "element";
emojiObj.tag = "emoji";
emojiObj.text = __emojis[ele];
emojiObj.baseSrc= __emojisBaseSrc;
}else{
emojiObj.node = "text";
emojiObj.text = ele;
}
emojiObjs.push(emojiObj);
}
return emojiObjs;
}
function emojisInit(reg='',baseSrc="/wxParse/emojis/",emojis){
__emojisReg = reg;
__emojisBaseSrc=baseSrc;
__emojis=emojis;
}
module.exports = {
html2json: html2json,
emojisInit:emojisInit
};
... ...
/**
*
* htmlParser改造自: https://github.com/blowsie/Pure-JavaScript-HTML5-Parser
*
* author: Di (微信小程序开发工程师)
* organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
* 垂直微信小程序开发交流社区
*
* github地址: https://github.com/icindy/wxParse
*
* for: 微信小程序富文本解析
* detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
*/
// Regular Expressions for parsing tags and attributes
var startTag = /^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/,
endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/,
attr = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g;
// Empty Elements - HTML 5
var empty = makeMap("area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr");
// Block Elements - HTML 5
var block = makeMap("a,address,code,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video");
// Inline Elements - HTML 5
var inline = makeMap("abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var");
// Elements that you can, intentionally, leave open
// (and which close themselves)
var closeSelf = makeMap("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr");
// Attributes that have their values filled in disabled="disabled"
var fillAttrs = makeMap("checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected");
// Special Elements (can contain anything)
var special = makeMap("wxxxcode-style,script,style,view,scroll-view,block");
function HTMLParser(html, handler) {
var index, chars, match, stack = [], last = html;
stack.last = function () {
return this[this.length - 1];
};
while (html) {
chars = true;
// Make sure we're not in a script or style element
if (!stack.last() || !special[stack.last()]) {
// Comment
if (html.indexOf("<!--") == 0) {
index = html.indexOf("-->");
if (index >= 0) {
if (handler.comment)
handler.comment(html.substring(4, index));
html = html.substring(index + 3);
chars = false;
}
// end tag
} else if (html.indexOf("</") == 0) {
match = html.match(endTag);
if (match) {
html = html.substring(match[0].length);
match[0].replace(endTag, parseEndTag);
chars = false;
}
// start tag
} else if (html.indexOf("<") == 0) {
match = html.match(startTag);
if (match) {
html = html.substring(match[0].length);
match[0].replace(startTag, parseStartTag);
chars = false;
}
}
if (chars) {
index = html.indexOf("<");
var text = ''
while (index === 0) {
text += "<";
html = html.substring(1);
index = html.indexOf("<");
}
text += index < 0 ? html : html.substring(0, index);
html = index < 0 ? "" : html.substring(index);
if (handler.chars)
handler.chars(text);
}
} else {
html = html.replace(new RegExp("([\\s\\S]*?)<\/" + stack.last() + "[^>]*>"), function (all, text) {
text = text.replace(/<!--([\s\S]*?)-->|<!\[CDATA\[([\s\S]*?)]]>/g, "$1$2");
if (handler.chars)
handler.chars(text);
return "";
});
parseEndTag("", stack.last());
}
if (html == last)
throw "Parse Error: " + html;
last = html;
}
// Clean up any remaining tags
parseEndTag();
function parseStartTag(tag, tagName, rest, unary) {
tagName = tagName.toLowerCase();
if (block[tagName]) {
while (stack.last() && inline[stack.last()]) {
parseEndTag("", stack.last());
}
}
if (closeSelf[tagName] && stack.last() == tagName) {
parseEndTag("", tagName);
}
unary = empty[tagName] || !!unary;
if (!unary)
stack.push(tagName);
if (handler.start) {
var attrs = [];
rest.replace(attr, function (match, name) {
var value = arguments[2] ? arguments[2] :
arguments[3] ? arguments[3] :
arguments[4] ? arguments[4] :
fillAttrs[name] ? name : "";
attrs.push({
name: name,
value: value,
escaped: value.replace(/(^|[^\\])"/g, '$1\\\"') //"
});
});
if (handler.start) {
handler.start(tagName, attrs, unary);
}
}
}
function parseEndTag(tag, tagName) {
// If no tag name is provided, clean shop
if (!tagName)
var pos = 0;
// Find the closest opened tag of the same type
else {
tagName = tagName.toLowerCase();
for (var pos = stack.length - 1; pos >= 0; pos--)
if (stack[pos] == tagName)
break;
}
if (pos >= 0) {
// Close all the open elements, up the stack
for (var i = stack.length - 1; i >= pos; i--)
if (handler.end)
handler.end(stack[i]);
// Remove the open elements from the stack
stack.length = pos;
}
}
};
function makeMap(str) {
var obj = {}, items = str.split(",");
for (var i = 0; i < items.length; i++)
obj[items[i]] = true;
return obj;
}
module.exports = HTMLParser;
... ...
/**
*
* showdown: https://github.com/showdownjs/showdown
*
* author: Di (微信小程序开发工程师)
* organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
* 垂直微信小程序开发交流社区
*
* github地址: https://github.com/icindy/wxParse
*
* for: 微信小程序富文本解析
* detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
*/
function getDefaultOpts(simple) {
'use strict';
var defaultOptions = {
omitExtraWLInCodeBlocks: {
defaultValue: false,
describe: 'Omit the default extra whiteline added to code blocks',
type: 'boolean'
},
noHeaderId: {
defaultValue: false,
describe: 'Turn on/off generated header id',
type: 'boolean'
},
prefixHeaderId: {
defaultValue: false,
describe: 'Specify a prefix to generated header ids',
type: 'string'
},
headerLevelStart: {
defaultValue: false,
describe: 'The header blocks level start',
type: 'integer'
},
parseImgDimensions: {
defaultValue: false,
describe: 'Turn on/off image dimension parsing',
type: 'boolean'
},
simplifiedAutoLink: {
defaultValue: false,
describe: 'Turn on/off GFM autolink style',
type: 'boolean'
},
literalMidWordUnderscores: {
defaultValue: false,
describe: 'Parse midword underscores as literal underscores',
type: 'boolean'
},
strikethrough: {
defaultValue: false,
describe: 'Turn on/off strikethrough support',
type: 'boolean'
},
tables: {
defaultValue: false,
describe: 'Turn on/off tables support',
type: 'boolean'
},
tablesHeaderId: {
defaultValue: false,
describe: 'Add an id to table headers',
type: 'boolean'
},
ghCodeBlocks: {
defaultValue: true,
describe: 'Turn on/off GFM fenced code blocks support',
type: 'boolean'
},
tasklists: {
defaultValue: false,
describe: 'Turn on/off GFM tasklist support',
type: 'boolean'
},
smoothLivePreview: {
defaultValue: false,
describe: 'Prevents weird effects in live previews due to incomplete input',
type: 'boolean'
},
smartIndentationFix: {
defaultValue: false,
description: 'Tries to smartly fix identation in es6 strings',
type: 'boolean'
}
};
if (simple === false) {
return JSON.parse(JSON.stringify(defaultOptions));
}
var ret = {};
for (var opt in defaultOptions) {
if (defaultOptions.hasOwnProperty(opt)) {
ret[opt] = defaultOptions[opt].defaultValue;
}
}
return ret;
}
/**
* Created by Tivie on 06-01-2015.
*/
// Private properties
var showdown = {},
parsers = {},
extensions = {},
globalOptions = getDefaultOpts(true),
flavor = {
github: {
omitExtraWLInCodeBlocks: true,
prefixHeaderId: 'user-content-',
simplifiedAutoLink: true,
literalMidWordUnderscores: true,
strikethrough: true,
tables: true,
tablesHeaderId: true,
ghCodeBlocks: true,
tasklists: true
},
vanilla: getDefaultOpts(true)
};
/**
* helper namespace
* @type {{}}
*/
showdown.helper = {};
/**
* TODO LEGACY SUPPORT CODE
* @type {{}}
*/
showdown.extensions = {};
/**
* Set a global option
* @static
* @param {string} key
* @param {*} value
* @returns {showdown}
*/
showdown.setOption = function (key, value) {
'use strict';
globalOptions[key] = value;
return this;
};
/**
* Get a global option
* @static
* @param {string} key
* @returns {*}
*/
showdown.getOption = function (key) {
'use strict';
return globalOptions[key];
};
/**
* Get the global options
* @static
* @returns {{}}
*/
showdown.getOptions = function () {
'use strict';
return globalOptions;
};
/**
* Reset global options to the default values
* @static
*/
showdown.resetOptions = function () {
'use strict';
globalOptions = getDefaultOpts(true);
};
/**
* Set the flavor showdown should use as default
* @param {string} name
*/
showdown.setFlavor = function (name) {
'use strict';
if (flavor.hasOwnProperty(name)) {
var preset = flavor[name];
for (var option in preset) {
if (preset.hasOwnProperty(option)) {
globalOptions[option] = preset[option];
}
}
}
};
/**
* Get the default options
* @static
* @param {boolean} [simple=true]
* @returns {{}}
*/
showdown.getDefaultOptions = function (simple) {
'use strict';
return getDefaultOpts(simple);
};
/**
* Get or set a subParser
*
* subParser(name) - Get a registered subParser
* subParser(name, func) - Register a subParser
* @static
* @param {string} name
* @param {function} [func]
* @returns {*}
*/
showdown.subParser = function (name, func) {
'use strict';
if (showdown.helper.isString(name)) {
if (typeof func !== 'undefined') {
parsers[name] = func;
} else {
if (parsers.hasOwnProperty(name)) {
return parsers[name];
} else {
throw Error('SubParser named ' + name + ' not registered!');
}
}
}
};
/**
* Gets or registers an extension
* @static
* @param {string} name
* @param {object|function=} ext
* @returns {*}
*/
showdown.extension = function (name, ext) {
'use strict';
if (!showdown.helper.isString(name)) {
throw Error('Extension \'name\' must be a string');
}
name = showdown.helper.stdExtName(name);
// Getter
if (showdown.helper.isUndefined(ext)) {
if (!extensions.hasOwnProperty(name)) {
throw Error('Extension named ' + name + ' is not registered!');
}
return extensions[name];
// Setter
} else {
// Expand extension if it's wrapped in a function
if (typeof ext === 'function') {
ext = ext();
}
// Ensure extension is an array
if (!showdown.helper.isArray(ext)) {
ext = [ext];
}
var validExtension = validate(ext, name);
if (validExtension.valid) {
extensions[name] = ext;
} else {
throw Error(validExtension.error);
}
}
};
/**
* Gets all extensions registered
* @returns {{}}
*/
showdown.getAllExtensions = function () {
'use strict';
return extensions;
};
/**
* Remove an extension
* @param {string} name
*/
showdown.removeExtension = function (name) {
'use strict';
delete extensions[name];
};
/**
* Removes all extensions
*/
showdown.resetExtensions = function () {
'use strict';
extensions = {};
};
/**
* Validate extension
* @param {array} extension
* @param {string} name
* @returns {{valid: boolean, error: string}}
*/
function validate(extension, name) {
'use strict';
var errMsg = (name) ? 'Error in ' + name + ' extension->' : 'Error in unnamed extension',
ret = {
valid: true,
error: ''
};
if (!showdown.helper.isArray(extension)) {
extension = [extension];
}
for (var i = 0; i < extension.length; ++i) {
var baseMsg = errMsg + ' sub-extension ' + i + ': ',
ext = extension[i];
if (typeof ext !== 'object') {
ret.valid = false;
ret.error = baseMsg + 'must be an object, but ' + typeof ext + ' given';
return ret;
}
if (!showdown.helper.isString(ext.type)) {
ret.valid = false;
ret.error = baseMsg + 'property "type" must be a string, but ' + typeof ext.type + ' given';
return ret;
}
var type = ext.type = ext.type.toLowerCase();
// normalize extension type
if (type === 'language') {
type = ext.type = 'lang';
}
if (type === 'html') {
type = ext.type = 'output';
}
if (type !== 'lang' && type !== 'output' && type !== 'listener') {
ret.valid = false;
ret.error = baseMsg + 'type ' + type + ' is not recognized. Valid values: "lang/language", "output/html" or "listener"';
return ret;
}
if (type === 'listener') {
if (showdown.helper.isUndefined(ext.listeners)) {
ret.valid = false;
ret.error = baseMsg + '. Extensions of type "listener" must have a property called "listeners"';
return ret;
}
} else {
if (showdown.helper.isUndefined(ext.filter) && showdown.helper.isUndefined(ext.regex)) {
ret.valid = false;
ret.error = baseMsg + type + ' extensions must define either a "regex" property or a "filter" method';
return ret;
}
}
if (ext.listeners) {
if (typeof ext.listeners !== 'object') {
ret.valid = false;
ret.error = baseMsg + '"listeners" property must be an object but ' + typeof ext.listeners + ' given';
return ret;
}
for (var ln in ext.listeners) {
if (ext.listeners.hasOwnProperty(ln)) {
if (typeof ext.listeners[ln] !== 'function') {
ret.valid = false;
ret.error = baseMsg + '"listeners" property must be an hash of [event name]: [callback]. listeners.' + ln +
' must be a function but ' + typeof ext.listeners[ln] + ' given';
return ret;
}
}
}
}
if (ext.filter) {
if (typeof ext.filter !== 'function') {
ret.valid = false;
ret.error = baseMsg + '"filter" must be a function, but ' + typeof ext.filter + ' given';
return ret;
}
} else if (ext.regex) {
if (showdown.helper.isString(ext.regex)) {
ext.regex = new RegExp(ext.regex, 'g');
}
if (!ext.regex instanceof RegExp) {
ret.valid = false;
ret.error = baseMsg + '"regex" property must either be a string or a RegExp object, but ' + typeof ext.regex + ' given';
return ret;
}
if (showdown.helper.isUndefined(ext.replace)) {
ret.valid = false;
ret.error = baseMsg + '"regex" extensions must implement a replace string or function';
return ret;
}
}
}
return ret;
}
/**
* Validate extension
* @param {object} ext
* @returns {boolean}
*/
showdown.validateExtension = function (ext) {
'use strict';
var validateExtension = validate(ext, null);
if (!validateExtension.valid) {
console.warn(validateExtension.error);
return false;
}
return true;
};
/**
* showdownjs helper functions
*/
if (!showdown.hasOwnProperty('helper')) {
showdown.helper = {};
}
/**
* Check if var is string
* @static
* @param {string} a
* @returns {boolean}
*/
showdown.helper.isString = function isString(a) {
'use strict';
return (typeof a === 'string' || a instanceof String);
};
/**
* Check if var is a function
* @static
* @param {string} a
* @returns {boolean}
*/
showdown.helper.isFunction = function isFunction(a) {
'use strict';
var getType = {};
return a && getType.toString.call(a) === '[object Function]';
};
/**
* ForEach helper function
* @static
* @param {*} obj
* @param {function} callback
*/
showdown.helper.forEach = function forEach(obj, callback) {
'use strict';
if (typeof obj.forEach === 'function') {
obj.forEach(callback);
} else {
for (var i = 0; i < obj.length; i++) {
callback(obj[i], i, obj);
}
}
};
/**
* isArray helper function
* @static
* @param {*} a
* @returns {boolean}
*/
showdown.helper.isArray = function isArray(a) {
'use strict';
return a.constructor === Array;
};
/**
* Check if value is undefined
* @static
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.
*/
showdown.helper.isUndefined = function isUndefined(value) {
'use strict';
return typeof value === 'undefined';
};
/**
* Standardidize extension name
* @static
* @param {string} s extension name
* @returns {string}
*/
showdown.helper.stdExtName = function (s) {
'use strict';
return s.replace(/[_-]||\s/g, '').toLowerCase();
};
function escapeCharactersCallback(wholeMatch, m1) {
'use strict';
var charCodeToEscape = m1.charCodeAt(0);
return '~E' + charCodeToEscape + 'E';
}
/**
* Callback used to escape characters when passing through String.replace
* @static
* @param {string} wholeMatch
* @param {string} m1
* @returns {string}
*/
showdown.helper.escapeCharactersCallback = escapeCharactersCallback;
/**
* Escape characters in a string
* @static
* @param {string} text
* @param {string} charsToEscape
* @param {boolean} afterBackslash
* @returns {XML|string|void|*}
*/
showdown.helper.escapeCharacters = function escapeCharacters(text, charsToEscape, afterBackslash) {
'use strict';
// First we have to escape the escape characters so that
// we can build a character class out of them
var regexString = '([' + charsToEscape.replace(/([\[\]\\])/g, '\\$1') + '])';
if (afterBackslash) {
regexString = '\\\\' + regexString;
}
var regex = new RegExp(regexString, 'g');
text = text.replace(regex, escapeCharactersCallback);
return text;
};
var rgxFindMatchPos = function (str, left, right, flags) {
'use strict';
var f = flags || '',
g = f.indexOf('g') > -1,
x = new RegExp(left + '|' + right, 'g' + f.replace(/g/g, '')),
l = new RegExp(left, f.replace(/g/g, '')),
pos = [],
t, s, m, start, end;
do {
t = 0;
while ((m = x.exec(str))) {
if (l.test(m[0])) {
if (!(t++)) {
s = x.lastIndex;
start = s - m[0].length;
}
} else if (t) {
if (!--t) {
end = m.index + m[0].length;
var obj = {
left: {start: start, end: s},
match: {start: s, end: m.index},
right: {start: m.index, end: end},
wholeMatch: {start: start, end: end}
};
pos.push(obj);
if (!g) {
return pos;
}
}
}
}
} while (t && (x.lastIndex = s));
return pos;
};
/**
* matchRecursiveRegExp
*
* (c) 2007 Steven Levithan <stevenlevithan.com>
* MIT License
*
* Accepts a string to search, a left and right format delimiter
* as regex patterns, and optional regex flags. Returns an array
* of matches, allowing nested instances of left/right delimiters.
* Use the "g" flag to return all matches, otherwise only the
* first is returned. Be careful to ensure that the left and
* right format delimiters produce mutually exclusive matches.
* Backreferences are not supported within the right delimiter
* due to how it is internally combined with the left delimiter.
* When matching strings whose format delimiters are unbalanced
* to the left or right, the output is intentionally as a
* conventional regex library with recursion support would
* produce, e.g. "<<x>" and "<x>>" both produce ["x"] when using
* "<" and ">" as the delimiters (both strings contain a single,
* balanced instance of "<x>").
*
* examples:
* matchRecursiveRegExp("test", "\\(", "\\)")
* returns: []
* matchRecursiveRegExp("<t<<e>><s>>t<>", "<", ">", "g")
* returns: ["t<<e>><s>", ""]
* matchRecursiveRegExp("<div id=\"x\">test</div>", "<div\\b[^>]*>", "</div>", "gi")
* returns: ["test"]
*/
showdown.helper.matchRecursiveRegExp = function (str, left, right, flags) {
'use strict';
var matchPos = rgxFindMatchPos (str, left, right, flags),
results = [];
for (var i = 0; i < matchPos.length; ++i) {
results.push([
str.slice(matchPos[i].wholeMatch.start, matchPos[i].wholeMatch.end),
str.slice(matchPos[i].match.start, matchPos[i].match.end),
str.slice(matchPos[i].left.start, matchPos[i].left.end),
str.slice(matchPos[i].right.start, matchPos[i].right.end)
]);
}
return results;
};
/**
*
* @param {string} str
* @param {string|function} replacement
* @param {string} left
* @param {string} right
* @param {string} flags
* @returns {string}
*/
showdown.helper.replaceRecursiveRegExp = function (str, replacement, left, right, flags) {
'use strict';
if (!showdown.helper.isFunction(replacement)) {
var repStr = replacement;
replacement = function () {
return repStr;
};
}
var matchPos = rgxFindMatchPos(str, left, right, flags),
finalStr = str,
lng = matchPos.length;
if (lng > 0) {
var bits = [];
if (matchPos[0].wholeMatch.start !== 0) {
bits.push(str.slice(0, matchPos[0].wholeMatch.start));
}
for (var i = 0; i < lng; ++i) {
bits.push(
replacement(
str.slice(matchPos[i].wholeMatch.start, matchPos[i].wholeMatch.end),
str.slice(matchPos[i].match.start, matchPos[i].match.end),
str.slice(matchPos[i].left.start, matchPos[i].left.end),
str.slice(matchPos[i].right.start, matchPos[i].right.end)
)
);
if (i < lng - 1) {
bits.push(str.slice(matchPos[i].wholeMatch.end, matchPos[i + 1].wholeMatch.start));
}
}
if (matchPos[lng - 1].wholeMatch.end < str.length) {
bits.push(str.slice(matchPos[lng - 1].wholeMatch.end));
}
finalStr = bits.join('');
}
return finalStr;
};
/**
* POLYFILLS
*/
if (showdown.helper.isUndefined(console)) {
console = {
warn: function (msg) {
'use strict';
alert(msg);
},
log: function (msg) {
'use strict';
alert(msg);
},
error: function (msg) {
'use strict';
throw msg;
}
};
}
/**
* Created by Estevao on 31-05-2015.
*/
/**
* Showdown Converter class
* @class
* @param {object} [converterOptions]
* @returns {Converter}
*/
showdown.Converter = function (converterOptions) {
'use strict';
var
/**
* Options used by this converter
* @private
* @type {{}}
*/
options = {},
/**
* Language extensions used by this converter
* @private
* @type {Array}
*/
langExtensions = [],
/**
* Output modifiers extensions used by this converter
* @private
* @type {Array}
*/
outputModifiers = [],
/**
* Event listeners
* @private
* @type {{}}
*/
listeners = {};
_constructor();
/**
* Converter constructor
* @private
*/
function _constructor() {
converterOptions = converterOptions || {};
for (var gOpt in globalOptions) {
if (globalOptions.hasOwnProperty(gOpt)) {
options[gOpt] = globalOptions[gOpt];
}
}
// Merge options
if (typeof converterOptions === 'object') {
for (var opt in converterOptions) {
if (converterOptions.hasOwnProperty(opt)) {
options[opt] = converterOptions[opt];
}
}
} else {
throw Error('Converter expects the passed parameter to be an object, but ' + typeof converterOptions +
' was passed instead.');
}
if (options.extensions) {
showdown.helper.forEach(options.extensions, _parseExtension);
}
}
/**
* Parse extension
* @param {*} ext
* @param {string} [name='']
* @private
*/
function _parseExtension(ext, name) {
name = name || null;
// If it's a string, the extension was previously loaded
if (showdown.helper.isString(ext)) {
ext = showdown.helper.stdExtName(ext);
name = ext;
// LEGACY_SUPPORT CODE
if (showdown.extensions[ext]) {
console.warn('DEPRECATION WARNING: ' + ext + ' is an old extension that uses a deprecated loading method.' +
'Please inform the developer that the extension should be updated!');
legacyExtensionLoading(showdown.extensions[ext], ext);
return;
// END LEGACY SUPPORT CODE
} else if (!showdown.helper.isUndefined(extensions[ext])) {
ext = extensions[ext];
} else {
throw Error('Extension "' + ext + '" could not be loaded. It was either not found or is not a valid extension.');
}
}
if (typeof ext === 'function') {
ext = ext();
}
if (!showdown.helper.isArray(ext)) {
ext = [ext];
}
var validExt = validate(ext, name);
if (!validExt.valid) {
throw Error(validExt.error);
}
for (var i = 0; i < ext.length; ++i) {
switch (ext[i].type) {
case 'lang':
langExtensions.push(ext[i]);
break;
case 'output':
outputModifiers.push(ext[i]);
break;
}
if (ext[i].hasOwnProperty(listeners)) {
for (var ln in ext[i].listeners) {
if (ext[i].listeners.hasOwnProperty(ln)) {
listen(ln, ext[i].listeners[ln]);
}
}
}
}
}
/**
* LEGACY_SUPPORT
* @param {*} ext
* @param {string} name
*/
function legacyExtensionLoading(ext, name) {
if (typeof ext === 'function') {
ext = ext(new showdown.Converter());
}
if (!showdown.helper.isArray(ext)) {
ext = [ext];
}
var valid = validate(ext, name);
if (!valid.valid) {
throw Error(valid.error);
}
for (var i = 0; i < ext.length; ++i) {
switch (ext[i].type) {
case 'lang':
langExtensions.push(ext[i]);
break;
case 'output':
outputModifiers.push(ext[i]);
break;
default:// should never reach here
throw Error('Extension loader error: Type unrecognized!!!');
}
}
}
/**
* Listen to an event
* @param {string} name
* @param {function} callback
*/
function listen(name, callback) {
if (!showdown.helper.isString(name)) {
throw Error('Invalid argument in converter.listen() method: name must be a string, but ' + typeof name + ' given');
}
if (typeof callback !== 'function') {
throw Error('Invalid argument in converter.listen() method: callback must be a function, but ' + typeof callback + ' given');
}
if (!listeners.hasOwnProperty(name)) {
listeners[name] = [];
}
listeners[name].push(callback);
}
function rTrimInputText(text) {
var rsp = text.match(/^\s*/)[0].length,
rgx = new RegExp('^\\s{0,' + rsp + '}', 'gm');
return text.replace(rgx, '');
}
/**
* Dispatch an event
* @private
* @param {string} evtName Event name
* @param {string} text Text
* @param {{}} options Converter Options
* @param {{}} globals
* @returns {string}
*/
this._dispatch = function dispatch (evtName, text, options, globals) {
if (listeners.hasOwnProperty(evtName)) {
for (var ei = 0; ei < listeners[evtName].length; ++ei) {
var nText = listeners[evtName][ei](evtName, text, this, options, globals);
if (nText && typeof nText !== 'undefined') {
text = nText;
}
}
}
return text;
};
/**
* Listen to an event
* @param {string} name
* @param {function} callback
* @returns {showdown.Converter}
*/
this.listen = function (name, callback) {
listen(name, callback);
return this;
};
/**
* Converts a markdown string into HTML
* @param {string} text
* @returns {*}
*/
this.makeHtml = function (text) {
//check if text is not falsy
if (!text) {
return text;
}
var globals = {
gHtmlBlocks: [],
gHtmlMdBlocks: [],
gHtmlSpans: [],
gUrls: {},
gTitles: {},
gDimensions: {},
gListLevel: 0,
hashLinkCounts: {},
langExtensions: langExtensions,
outputModifiers: outputModifiers,
converter: this,
ghCodeBlocks: []
};
// attacklab: Replace ~ with ~T
// This lets us use tilde as an escape char to avoid md5 hashes
// The choice of character is arbitrary; anything that isn't
// magic in Markdown will work.
text = text.replace(/~/g, '~T');
// attacklab: Replace $ with ~D
// RegExp interprets $ as a special character
// when it's in a replacement string
text = text.replace(/\$/g, '~D');
// Standardize line endings
text = text.replace(/\r\n/g, '\n'); // DOS to Unix
text = text.replace(/\r/g, '\n'); // Mac to Unix
if (options.smartIndentationFix) {
text = rTrimInputText(text);
}
// Make sure text begins and ends with a couple of newlines:
//text = '\n\n' + text + '\n\n';
text = text;
// detab
text = showdown.subParser('detab')(text, options, globals);
// stripBlankLines
text = showdown.subParser('stripBlankLines')(text, options, globals);
//run languageExtensions
showdown.helper.forEach(langExtensions, function (ext) {
text = showdown.subParser('runExtension')(ext, text, options, globals);
});
// run the sub parsers
text = showdown.subParser('hashPreCodeTags')(text, options, globals);
text = showdown.subParser('githubCodeBlocks')(text, options, globals);
text = showdown.subParser('hashHTMLBlocks')(text, options, globals);
text = showdown.subParser('hashHTMLSpans')(text, options, globals);
text = showdown.subParser('stripLinkDefinitions')(text, options, globals);
text = showdown.subParser('blockGamut')(text, options, globals);
text = showdown.subParser('unhashHTMLSpans')(text, options, globals);
text = showdown.subParser('unescapeSpecialChars')(text, options, globals);
// attacklab: Restore dollar signs
text = text.replace(/~D/g, '$$');
// attacklab: Restore tildes
text = text.replace(/~T/g, '~');
// Run output modifiers
showdown.helper.forEach(outputModifiers, function (ext) {
text = showdown.subParser('runExtension')(ext, text, options, globals);
});
return text;
};
/**
* Set an option of this Converter instance
* @param {string} key
* @param {*} value
*/
this.setOption = function (key, value) {
options[key] = value;
};
/**
* Get the option of this Converter instance
* @param {string} key
* @returns {*}
*/
this.getOption = function (key) {
return options[key];
};
/**
* Get the options of this Converter instance
* @returns {{}}
*/
this.getOptions = function () {
return options;
};
/**
* Add extension to THIS converter
* @param {{}} extension
* @param {string} [name=null]
*/
this.addExtension = function (extension, name) {
name = name || null;
_parseExtension(extension, name);
};
/**
* Use a global registered extension with THIS converter
* @param {string} extensionName Name of the previously registered extension
*/
this.useExtension = function (extensionName) {
_parseExtension(extensionName);
};
/**
* Set the flavor THIS converter should use
* @param {string} name
*/
this.setFlavor = function (name) {
if (flavor.hasOwnProperty(name)) {
var preset = flavor[name];
for (var option in preset) {
if (preset.hasOwnProperty(option)) {
options[option] = preset[option];
}
}
}
};
/**
* Remove an extension from THIS converter.
* Note: This is a costly operation. It's better to initialize a new converter
* and specify the extensions you wish to use
* @param {Array} extension
*/
this.removeExtension = function (extension) {
if (!showdown.helper.isArray(extension)) {
extension = [extension];
}
for (var a = 0; a < extension.length; ++a) {
var ext = extension[a];
for (var i = 0; i < langExtensions.length; ++i) {
if (langExtensions[i] === ext) {
langExtensions[i].splice(i, 1);
}
}
for (var ii = 0; ii < outputModifiers.length; ++i) {
if (outputModifiers[ii] === ext) {
outputModifiers[ii].splice(i, 1);
}
}
}
};
/**
* Get all extension of THIS converter
* @returns {{language: Array, output: Array}}
*/
this.getAllExtensions = function () {
return {
language: langExtensions,
output: outputModifiers
};
};
};
/**
* Turn Markdown link shortcuts into XHTML <a> tags.
*/
showdown.subParser('anchors', function (text, options, globals) {
'use strict';
text = globals.converter._dispatch('anchors.before', text, options, globals);
var writeAnchorTag = function (wholeMatch, m1, m2, m3, m4, m5, m6, m7) {
if (showdown.helper.isUndefined(m7)) {
m7 = '';
}
wholeMatch = m1;
var linkText = m2,
linkId = m3.toLowerCase(),
url = m4,
title = m7;
if (!url) {
if (!linkId) {
// lower-case and turn embedded newlines into spaces
linkId = linkText.toLowerCase().replace(/ ?\n/g, ' ');
}
url = '#' + linkId;
if (!showdown.helper.isUndefined(globals.gUrls[linkId])) {
url = globals.gUrls[linkId];
if (!showdown.helper.isUndefined(globals.gTitles[linkId])) {
title = globals.gTitles[linkId];
}
} else {
if (wholeMatch.search(/\(\s*\)$/m) > -1) {
// Special case for explicit empty url
url = '';
} else {
return wholeMatch;
}
}
}
url = showdown.helper.escapeCharacters(url, '*_', false);
var result = '<a href="' + url + '"';
if (title !== '' && title !== null) {
title = title.replace(/"/g, '&quot;');
title = showdown.helper.escapeCharacters(title, '*_', false);
result += ' title="' + title + '"';
}
result += '>' + linkText + '</a>';
return result;
};
// First, handle reference-style links: [link text] [id]
/*
text = text.replace(/
( // wrap whole match in $1
\[
(
(?:
\[[^\]]*\] // allow brackets nested one level
|
[^\[] // or anything else
)*
)
\]
[ ]? // one optional space
(?:\n[ ]*)? // one optional newline followed by spaces
\[
(.*?) // id = $3
\]
)()()()() // pad remaining backreferences
/g,_DoAnchors_callback);
*/
text = text.replace(/(\[((?:\[[^\]]*]|[^\[\]])*)][ ]?(?:\n[ ]*)?\[(.*?)])()()()()/g, writeAnchorTag);
//
// Next, inline-style links: [link text](url "optional title")
//
/*
text = text.replace(/
( // wrap whole match in $1
\[
(
(?:
\[[^\]]*\] // allow brackets nested one level
|
[^\[\]] // or anything else
)
)
\]
\( // literal paren
[ \t]*
() // no id, so leave $3 empty
<?(.*?)>? // href = $4
[ \t]*
( // $5
(['"]) // quote char = $6
(.*?) // Title = $7
\6 // matching quote
[ \t]* // ignore any spaces/tabs between closing quote and )
)? // title is optional
\)
)
/g,writeAnchorTag);
*/
text = text.replace(/(\[((?:\[[^\]]*]|[^\[\]])*)]\([ \t]*()<?(.*?(?:\(.*?\).*?)?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,
writeAnchorTag);
//
// Last, handle reference-style shortcuts: [link text]
// These must come last in case you've also got [link test][1]
// or [link test](/foo)
//
/*
text = text.replace(/
( // wrap whole match in $1
\[
([^\[\]]+) // link text = $2; can't contain '[' or ']'
\]
)()()()()() // pad rest of backreferences
/g, writeAnchorTag);
*/
text = text.replace(/(\[([^\[\]]+)])()()()()()/g, writeAnchorTag);
text = globals.converter._dispatch('anchors.after', text, options, globals);
return text;
});
showdown.subParser('autoLinks', function (text, options, globals) {
'use strict';
text = globals.converter._dispatch('autoLinks.before', text, options, globals);
var simpleURLRegex = /\b(((https?|ftp|dict):\/\/|www\.)[^'">\s]+\.[^'">\s]+)(?=\s|$)(?!["<>])/gi,
delimUrlRegex = /<(((https?|ftp|dict):\/\/|www\.)[^'">\s]+)>/gi,
simpleMailRegex = /(?:^|[ \n\t])([A-Za-z0-9!#$%&'*+-/=?^_`\{|}~\.]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)(?:$|[ \n\t])/gi,
delimMailRegex = /<(?:mailto:)?([-.\w]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi;
text = text.replace(delimUrlRegex, replaceLink);
text = text.replace(delimMailRegex, replaceMail);
// simpleURLRegex = /\b(((https?|ftp|dict):\/\/|www\.)[-.+~:?#@!$&'()*,;=[\]\w]+)\b/gi,
// Email addresses: <address@domain.foo>
if (options.simplifiedAutoLink) {
text = text.replace(simpleURLRegex, replaceLink);
text = text.replace(simpleMailRegex, replaceMail);
}
function replaceLink(wm, link) {
var lnkTxt = link;
if (/^www\./i.test(link)) {
link = link.replace(/^www\./i, 'http://www.');
}
return '<a href="' + link + '">' + lnkTxt + '</a>';
}
function replaceMail(wholeMatch, m1) {
var unescapedStr = showdown.subParser('unescapeSpecialChars')(m1);
return showdown.subParser('encodeEmailAddress')(unescapedStr);
}
text = globals.converter._dispatch('autoLinks.after', text, options, globals);
return text;
});
/**
* These are all the transformations that form block-level
* tags like paragraphs, headers, and list items.
*/
showdown.subParser('blockGamut', function (text, options, globals) {
'use strict';
text = globals.converter._dispatch('blockGamut.before', text, options, globals);
// we parse blockquotes first so that we can have headings and hrs
// inside blockquotes
text = showdown.subParser('blockQuotes')(text, options, globals);
text = showdown.subParser('headers')(text, options, globals);
// Do Horizontal Rules:
var key = showdown.subParser('hashBlock')('<hr />', options, globals);
text = text.replace(/^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$/gm, key);
text = text.replace(/^[ ]{0,2}([ ]?\-[ ]?){3,}[ \t]*$/gm, key);
text = text.replace(/^[ ]{0,2}([ ]?_[ ]?){3,}[ \t]*$/gm, key);
text = showdown.subParser('lists')(text, options, globals);
text = showdown.subParser('codeBlocks')(text, options, globals);
text = showdown.subParser('tables')(text, options, globals);
// We already ran _HashHTMLBlocks() before, in Markdown(), but that
// was to escape raw HTML in the original Markdown source. This time,
// we're escaping the markup we've just created, so that we don't wrap
// <p> tags around block-level tags.
text = showdown.subParser('hashHTMLBlocks')(text, options, globals);
text = showdown.subParser('paragraphs')(text, options, globals);
text = globals.converter._dispatch('blockGamut.after', text, options, globals);
return text;
});
showdown.subParser('blockQuotes', function (text, options, globals) {
'use strict';
text = globals.converter._dispatch('blockQuotes.before', text, options, globals);
/*
text = text.replace(/
( // Wrap whole match in $1
(
^[ \t]*>[ \t]? // '>' at the start of a line
.+\n // rest of the first line
(.+\n)* // subsequent consecutive lines
\n* // blanks
)+
)
/gm, function(){...});
*/
text = text.replace(/((^[ \t]{0,3}>[ \t]?.+\n(.+\n)*\n*)+)/gm, function (wholeMatch, m1) {
var bq = m1;
// attacklab: hack around Konqueror 3.5.4 bug:
// "----------bug".replace(/^-/g,"") == "bug"
bq = bq.replace(/^[ \t]*>[ \t]?/gm, '~0'); // trim one level of quoting
// attacklab: clean up hack
bq = bq.replace(/~0/g, '');
bq = bq.replace(/^[ \t]+$/gm, ''); // trim whitespace-only lines
bq = showdown.subParser('githubCodeBlocks')(bq, options, globals);
bq = showdown.subParser('blockGamut')(bq, options, globals); // recurse
bq = bq.replace(/(^|\n)/g, '$1 ');
// These leading spaces screw with <pre> content, so we need to fix that:
bq = bq.replace(/(\s*<pre>[^\r]+?<\/pre>)/gm, function (wholeMatch, m1) {
var pre = m1;
// attacklab: hack around Konqueror 3.5.4 bug:
pre = pre.replace(/^ /mg, '~0');
pre = pre.replace(/~0/g, '');
return pre;
});
return showdown.subParser('hashBlock')('<blockquote>\n' + bq + '\n</blockquote>', options, globals);
});
text = globals.converter._dispatch('blockQuotes.after', text, options, globals);
return text;
});
/**
* Process Markdown `<pre><code>` blocks.
*/
showdown.subParser('codeBlocks', function (text, options, globals) {
'use strict';
text = globals.converter._dispatch('codeBlocks.before', text, options, globals);
/*
text = text.replace(text,
/(?:\n\n|^)
( // $1 = the code block -- one or more lines, starting with a space/tab
(?:
(?:[ ]{4}|\t) // Lines must start with a tab or a tab-width of spaces - attacklab: g_tab_width
.*\n+
)+
)
(\n*[ ]{0,3}[^ \t\n]|(?=~0)) // attacklab: g_tab_width
/g,function(){...});
*/
// attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug
text += '~0';
var pattern = /(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g;
text = text.replace(pattern, function (wholeMatch, m1, m2) {
var codeblock = m1,
nextChar = m2,
end = '\n';
codeblock = showdown.subParser('outdent')(codeblock);
codeblock = showdown.subParser('encodeCode')(codeblock);
codeblock = showdown.subParser('detab')(codeblock);
codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines
codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing newlines
if (options.omitExtraWLInCodeBlocks) {
end = '';
}
codeblock = '<pre><code>' + codeblock + end + '</code></pre>';
return showdown.subParser('hashBlock')(codeblock, options, globals) + nextChar;
});
// attacklab: strip sentinel
text = text.replace(/~0/, '');
text = globals.converter._dispatch('codeBlocks.after', text, options, globals);
return text;
});
/**
*
* * Backtick quotes are used for <code></code> spans.
*
* * You can use multiple backticks as the delimiters if you want to
* include literal backticks in the code span. So, this input:
*
* Just type ``foo `bar` baz`` at the prompt.
*
* Will translate to:
*
* <p>Just type <code>foo `bar` baz</code> at the prompt.</p>
*
* There's no arbitrary limit to the number of backticks you
* can use as delimters. If you need three consecutive backticks
* in your code, use four for delimiters, etc.
*
* * You can use spaces to get literal backticks at the edges:
*
* ... type `` `bar` `` ...
*
* Turns to:
*
* ... type <code>`bar`</code> ...
*/
showdown.subParser('codeSpans', function (text, options, globals) {
'use strict';
text = globals.converter._dispatch('codeSpans.before', text, options, globals);
/*
text = text.replace(/
(^|[^\\]) // Character before opening ` can't be a backslash
(`+) // $2 = Opening run of `
( // $3 = The code block
[^\r]*?
[^`] // attacklab: work around lack of lookbehind
)
\2 // Matching closer
(?!`)
/gm, function(){...});
*/
if (typeof(text) === 'undefined') {
text = '';
}
text = text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,
function (wholeMatch, m1, m2, m3) {
var c = m3;
c = c.replace(/^([ \t]*)/g, ''); // leading whitespace
c = c.replace(/[ \t]*$/g, ''); // trailing whitespace
c = showdown.subParser('encodeCode')(c);
return m1 + '<code>' + c + '</code>';
}
);
text = globals.converter._dispatch('codeSpans.after', text, options, globals);
return text;
});
/**
* Convert all tabs to spaces
*/
showdown.subParser('detab', function (text) {
'use strict';
// expand first n-1 tabs
text = text.replace(/\t(?=\t)/g, ' '); // g_tab_width
// replace the nth with two sentinels
text = text.replace(/\t/g, '~A~B');
// use the sentinel to anchor our regex so it doesn't explode
text = text.replace(/~B(.+?)~A/g, function (wholeMatch, m1) {
var leadingText = m1,
numSpaces = 4 - leadingText.length % 4; // g_tab_width
// there *must* be a better way to do this:
for (var i = 0; i < numSpaces; i++) {
leadingText += ' ';
}
return leadingText;
});
// clean up sentinels
text = text.replace(/~A/g, ' '); // g_tab_width
text = text.replace(/~B/g, '');
return text;
});
/**
* Smart processing for ampersands and angle brackets that need to be encoded.
*/
showdown.subParser('encodeAmpsAndAngles', function (text) {
'use strict';
// Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin:
// http://bumppo.net/projects/amputator/
text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g, '&amp;');
// Encode naked <'s
text = text.replace(/<(?![a-z\/?\$!])/gi, '&lt;');
return text;
});
/**
* Returns the string, with after processing the following backslash escape sequences.
*
* attacklab: The polite way to do this is with the new escapeCharacters() function:
*
* text = escapeCharacters(text,"\\",true);
* text = escapeCharacters(text,"`*_{}[]()>#+-.!",true);
*
* ...but we're sidestepping its use of the (slow) RegExp constructor
* as an optimization for Firefox. This function gets called a LOT.
*/
showdown.subParser('encodeBackslashEscapes', function (text) {
'use strict';
text = text.replace(/\\(\\)/g, showdown.helper.escapeCharactersCallback);
text = text.replace(/\\([`*_{}\[\]()>#+-.!])/g, showdown.helper.escapeCharactersCallback);
return text;
});
/**
* Encode/escape certain characters inside Markdown code runs.
* The point is that in code, these characters are literals,
* and lose their special Markdown meanings.
*/
showdown.subParser('encodeCode', function (text) {
'use strict';
// Encode all ampersands; HTML entities are not
// entities within a Markdown code span.
text = text.replace(/&/g, '&amp;');
// Do the angle bracket song and dance:
text = text.replace(/</g, '&lt;');
text = text.replace(/>/g, '&gt;');
// Now, escape characters that are magic in Markdown:
text = showdown.helper.escapeCharacters(text, '*_{}[]\\', false);
// jj the line above breaks this:
//---
//* Item
// 1. Subitem
// special char: *
// ---
return text;
});
/**
* Input: an email address, e.g. "foo@example.com"
*
* Output: the email address as a mailto link, with each character
* of the address encoded as either a decimal or hex entity, in
* the hopes of foiling most address harvesting spam bots. E.g.:
*
* <a href="&#x6D;&#97;&#105;&#108;&#x74;&#111;:&#102;&#111;&#111;&#64;&#101;
* x&#x61;&#109;&#x70;&#108;&#x65;&#x2E;&#99;&#111;&#109;">&#102;&#111;&#111;
* &#64;&#101;x&#x61;&#109;&#x70;&#108;&#x65;&#x2E;&#99;&#111;&#109;</a>
*
* Based on a filter by Matthew Wickline, posted to the BBEdit-Talk
* mailing list: <http://tinyurl.com/yu7ue>
*
*/
showdown.subParser('encodeEmailAddress', function (addr) {
'use strict';
var encode = [
function (ch) {
return '&#' + ch.charCodeAt(0) + ';';
},
function (ch) {
return '&#x' + ch.charCodeAt(0).toString(16) + ';';
},
function (ch) {
return ch;
}
];
addr = 'mailto:' + addr;
addr = addr.replace(/./g, function (ch) {
if (ch === '@') {
// this *must* be encoded. I insist.
ch = encode[Math.floor(Math.random() * 2)](ch);
} else if (ch !== ':') {
// leave ':' alone (to spot mailto: later)
var r = Math.random();
// roughly 10% raw, 45% hex, 45% dec
ch = (
r > 0.9 ? encode[2](ch) : r > 0.45 ? encode[1](ch) : encode[0](ch)
);
}
return ch;
});
addr = '<a href="' + addr + '">' + addr + '</a>';
addr = addr.replace(/">.+:/g, '">'); // strip the mailto: from the visible part
return addr;
});
/**
* Within tags -- meaning between < and > -- encode [\ ` * _] so they
* don't conflict with their use in Markdown for code, italics and strong.
*/
showdown.subParser('escapeSpecialCharsWithinTagAttributes', function (text) {
'use strict';
// Build a regex to find HTML tags and comments. See Friedl's
// "Mastering Regular Expressions", 2nd Ed., pp. 200-201.
var regex = /(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|<!(--.*?--\s*)+>)/gi;
text = text.replace(regex, function (wholeMatch) {
var tag = wholeMatch.replace(/(.)<\/?code>(?=.)/g, '$1`');
tag = showdown.helper.escapeCharacters(tag, '\\`*_', false);
return tag;
});
return text;
});
/**
* Handle github codeblocks prior to running HashHTML so that
* HTML contained within the codeblock gets escaped properly
* Example:
* ```ruby
* def hello_world(x)
* puts "Hello, #{x}"
* end
* ```
*/
showdown.subParser('githubCodeBlocks', function (text, options, globals) {
'use strict';
// early exit if option is not enabled
if (!options.ghCodeBlocks) {
return text;
}
text = globals.converter._dispatch('githubCodeBlocks.before', text, options, globals);
text += '~0';
text = text.replace(/(?:^|\n)```(.*)\n([\s\S]*?)\n```/g, function (wholeMatch, language, codeblock) {
var end = (options.omitExtraWLInCodeBlocks) ? '' : '\n';
// First parse the github code block
codeblock = showdown.subParser('encodeCode')(codeblock);
codeblock = showdown.subParser('detab')(codeblock);
codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines
codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing whitespace
codeblock = '<pre><code' + (language ? ' class="' + language + ' language-' + language + '"' : '') + '>' + codeblock + end + '</code></pre>';
codeblock = showdown.subParser('hashBlock')(codeblock, options, globals);
// Since GHCodeblocks can be false positives, we need to
// store the primitive text and the parsed text in a global var,
// and then return a token
return '\n\n~G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\n\n';
});
// attacklab: strip sentinel
text = text.replace(/~0/, '');
return globals.converter._dispatch('githubCodeBlocks.after', text, options, globals);
});
showdown.subParser('hashBlock', function (text, options, globals) {
'use strict';
text = text.replace(/(^\n+|\n+$)/g, '');
return '\n\n~K' + (globals.gHtmlBlocks.push(text) - 1) + 'K\n\n';
});
showdown.subParser('hashElement', function (text, options, globals) {
'use strict';
return function (wholeMatch, m1) {
var blockText = m1;
// Undo double lines
blockText = blockText.replace(/\n\n/g, '\n');
blockText = blockText.replace(/^\n/, '');
// strip trailing blank lines
blockText = blockText.replace(/\n+$/g, '');
// Replace the element text with a marker ("~KxK" where x is its key)
blockText = '\n\n~K' + (globals.gHtmlBlocks.push(blockText) - 1) + 'K\n\n';
return blockText;
};
});
showdown.subParser('hashHTMLBlocks', function (text, options, globals) {
'use strict';
var blockTags = [
'pre',
'div',
'h1',
'h2',
'h3',
'h4',
'h5',
'h6',
'blockquote',
'table',
'dl',
'ol',
'ul',
'script',
'noscript',
'form',
'fieldset',
'iframe',
'math',
'style',
'section',
'header',
'footer',
'nav',
'article',
'aside',
'address',
'audio',
'canvas',
'figure',
'hgroup',
'output',
'video',
'p'
],
repFunc = function (wholeMatch, match, left, right) {
var txt = wholeMatch;
// check if this html element is marked as markdown
// if so, it's contents should be parsed as markdown
if (left.search(/\bmarkdown\b/) !== -1) {
txt = left + globals.converter.makeHtml(match) + right;
}
return '\n\n~K' + (globals.gHtmlBlocks.push(txt) - 1) + 'K\n\n';
};
for (var i = 0; i < blockTags.length; ++i) {
text = showdown.helper.replaceRecursiveRegExp(text, repFunc, '^(?: |\\t){0,3}<' + blockTags[i] + '\\b[^>]*>', '</' + blockTags[i] + '>', 'gim');
}
// HR SPECIAL CASE
text = text.replace(/(\n[ ]{0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,
showdown.subParser('hashElement')(text, options, globals));
// Special case for standalone HTML comments:
text = text.replace(/(<!--[\s\S]*?-->)/g,
showdown.subParser('hashElement')(text, options, globals));
// PHP and ASP-style processor instructions (<?...?> and <%...%>)
text = text.replace(/(?:\n\n)([ ]{0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,
showdown.subParser('hashElement')(text, options, globals));
return text;
});
/**
* Hash span elements that should not be parsed as markdown
*/
showdown.subParser('hashHTMLSpans', function (text, config, globals) {
'use strict';
var matches = showdown.helper.matchRecursiveRegExp(text, '<code\\b[^>]*>', '</code>', 'gi');
for (var i = 0; i < matches.length; ++i) {
text = text.replace(matches[i][0], '~L' + (globals.gHtmlSpans.push(matches[i][0]) - 1) + 'L');
}
return text;
});
/**
* Unhash HTML spans
*/
showdown.subParser('unhashHTMLSpans', function (text, config, globals) {
'use strict';
for (var i = 0; i < globals.gHtmlSpans.length; ++i) {
text = text.replace('~L' + i + 'L', globals.gHtmlSpans[i]);
}
return text;
});
/**
* Hash span elements that should not be parsed as markdown
*/
showdown.subParser('hashPreCodeTags', function (text, config, globals) {
'use strict';
var repFunc = function (wholeMatch, match, left, right) {
// encode html entities
var codeblock = left + showdown.subParser('encodeCode')(match) + right;
return '\n\n~G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\n\n';
};
text = showdown.helper.replaceRecursiveRegExp(text, repFunc, '^(?: |\\t){0,3}<pre\\b[^>]*>\\s*<code\\b[^>]*>', '^(?: |\\t){0,3}</code>\\s*</pre>', 'gim');
return text;
});
showdown.subParser('headers', function (text, options, globals) {
'use strict';
text = globals.converter._dispatch('headers.before', text, options, globals);
var prefixHeader = options.prefixHeaderId,
headerLevelStart = (isNaN(parseInt(options.headerLevelStart))) ? 1 : parseInt(options.headerLevelStart),
// Set text-style headers:
// Header 1
// ========
//
// Header 2
// --------
//
setextRegexH1 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n={2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n=+[ \t]*\n+/gm,
setextRegexH2 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n-{2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n-+[ \t]*\n+/gm;
text = text.replace(setextRegexH1, function (wholeMatch, m1) {
var spanGamut = showdown.subParser('spanGamut')(m1, options, globals),
hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"',
hLevel = headerLevelStart,
hashBlock = '<h' + hLevel + hID + '>' + spanGamut + '</h' + hLevel + '>';
return showdown.subParser('hashBlock')(hashBlock, options, globals);
});
text = text.replace(setextRegexH2, function (matchFound, m1) {
var spanGamut = showdown.subParser('spanGamut')(m1, options, globals),
hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"',
hLevel = headerLevelStart + 1,
hashBlock = '<h' + hLevel + hID + '>' + spanGamut + '</h' + hLevel + '>';
return showdown.subParser('hashBlock')(hashBlock, options, globals);
});
// atx-style headers:
// # Header 1
// ## Header 2
// ## Header 2 with closing hashes ##
// ...
// ###### Header 6
//
text = text.replace(/^(#{1,6})[ \t]*(.+?)[ \t]*#*\n+/gm, function (wholeMatch, m1, m2) {
var span = showdown.subParser('spanGamut')(m2, options, globals),
hID = (options.noHeaderId) ? '' : ' id="' + headerId(m2) + '"',
hLevel = headerLevelStart - 1 + m1.length,
header = '<h' + hLevel + hID + '>' + span + '</h' + hLevel + '>';
return showdown.subParser('hashBlock')(header, options, globals);
});
function headerId(m) {
var title, escapedId = m.replace(/[^\w]/g, '').toLowerCase();
if (globals.hashLinkCounts[escapedId]) {
title = escapedId + '-' + (globals.hashLinkCounts[escapedId]++);
} else {
title = escapedId;
globals.hashLinkCounts[escapedId] = 1;
}
// Prefix id to prevent causing inadvertent pre-existing style matches.
if (prefixHeader === true) {
prefixHeader = 'section';
}
if (showdown.helper.isString(prefixHeader)) {
return prefixHeader + title;
}
return title;
}
text = globals.converter._dispatch('headers.after', text, options, globals);
return text;
});
/**
* Turn Markdown image shortcuts into <img> tags.
*/
showdown.subParser('images', function (text, options, globals) {
'use strict';
text = globals.converter._dispatch('images.before', text, options, globals);
var inlineRegExp = /!\[(.*?)]\s?\([ \t]*()<?(\S+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(['"])(.*?)\6[ \t]*)?\)/g,
referenceRegExp = /!\[([^\]]*?)] ?(?:\n *)?\[(.*?)]()()()()()/g;
function writeImageTag (wholeMatch, altText, linkId, url, width, height, m5, title) {
var gUrls = globals.gUrls,
gTitles = globals.gTitles,
gDims = globals.gDimensions;
linkId = linkId.toLowerCase();
if (!title) {
title = '';
}
if (url === '' || url === null) {
if (linkId === '' || linkId === null) {
// lower-case and turn embedded newlines into spaces
linkId = altText.toLowerCase().replace(/ ?\n/g, ' ');
}
url = '#' + linkId;
if (!showdown.helper.isUndefined(gUrls[linkId])) {
url = gUrls[linkId];
if (!showdown.helper.isUndefined(gTitles[linkId])) {
title = gTitles[linkId];
}
if (!showdown.helper.isUndefined(gDims[linkId])) {
width = gDims[linkId].width;
height = gDims[linkId].height;
}
} else {
return wholeMatch;
}
}
altText = altText.replace(/"/g, '&quot;');
altText = showdown.helper.escapeCharacters(altText, '*_', false);
url = showdown.helper.escapeCharacters(url, '*_', false);
var result = '<img src="' + url + '" alt="' + altText + '"';
if (title) {
title = title.replace(/"/g, '&quot;');
title = showdown.helper.escapeCharacters(title, '*_', false);
result += ' title="' + title + '"';
}
if (width && height) {
width = (width === '*') ? 'auto' : width;
height = (height === '*') ? 'auto' : height;
result += ' width="' + width + '"';
result += ' height="' + height + '"';
}
result += ' />';
return result;
}
// First, handle reference-style labeled images: ![alt text][id]
text = text.replace(referenceRegExp, writeImageTag);
// Next, handle inline images: ![alt text](url =<width>x<height> "optional title")
text = text.replace(inlineRegExp, writeImageTag);
text = globals.converter._dispatch('images.after', text, options, globals);
return text;
});
showdown.subParser('italicsAndBold', function (text, options, globals) {
'use strict';
text = globals.converter._dispatch('italicsAndBold.before', text, options, globals);
if (options.literalMidWordUnderscores) {
//underscores
// Since we are consuming a \s character, we need to add it
text = text.replace(/(^|\s|>|\b)__(?=\S)([\s\S]+?)__(?=\b|<|\s|$)/gm, '$1<strong>$2</strong>');
text = text.replace(/(^|\s|>|\b)_(?=\S)([\s\S]+?)_(?=\b|<|\s|$)/gm, '$1<em>$2</em>');
//asterisks
text = text.replace(/(\*\*)(?=\S)([^\r]*?\S[*]*)\1/g, '<strong>$2</strong>');
text = text.replace(/(\*)(?=\S)([^\r]*?\S)\1/g, '<em>$2</em>');
} else {
// <strong> must go first:
text = text.replace(/(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g, '<strong>$2</strong>');
text = text.replace(/(\*|_)(?=\S)([^\r]*?\S)\1/g, '<em>$2</em>');
}
text = globals.converter._dispatch('italicsAndBold.after', text, options, globals);
return text;
});
/**
* Form HTML ordered (numbered) and unordered (bulleted) lists.
*/
showdown.subParser('lists', function (text, options, globals) {
'use strict';
text = globals.converter._dispatch('lists.before', text, options, globals);
/**
* Process the contents of a single ordered or unordered list, splitting it
* into individual list items.
* @param {string} listStr
* @param {boolean} trimTrailing
* @returns {string}
*/
function processListItems (listStr, trimTrailing) {
// The $g_list_level global keeps track of when we're inside a list.
// Each time we enter a list, we increment it; when we leave a list,
// we decrement. If it's zero, we're not in a list anymore.
//
// We do this because when we're not inside a list, we want to treat
// something like this:
//
// I recommend upgrading to version
// 8. Oops, now this line is treated
// as a sub-list.
//
// As a single paragraph, despite the fact that the second line starts
// with a digit-period-space sequence.
//
// Whereas when we're inside a list (or sub-list), that line will be
// treated as the start of a sub-list. What a kludge, huh? This is
// an aspect of Markdown's syntax that's hard to parse perfectly
// without resorting to mind-reading. Perhaps the solution is to
// change the syntax rules such that sub-lists must start with a
// starting cardinal number; e.g. "1." or "a.".
globals.gListLevel++;
// trim trailing blank lines:
listStr = listStr.replace(/\n{2,}$/, '\n');
// attacklab: add sentinel to emulate \z
listStr += '~0';
var rgx = /(\n)?(^[ \t]*)([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(~0|\2([*+-]|\d+[.])[ \t]+))/gm,
isParagraphed = (/\n[ \t]*\n(?!~0)/.test(listStr));
listStr = listStr.replace(rgx, function (wholeMatch, m1, m2, m3, m4, taskbtn, checked) {
checked = (checked && checked.trim() !== '');
var item = showdown.subParser('outdent')(m4, options, globals),
bulletStyle = '';
// Support for github tasklists
if (taskbtn && options.tasklists) {
bulletStyle = ' class="task-list-item" style="list-style-type: none;"';
item = item.replace(/^[ \t]*\[(x|X| )?]/m, function () {
var otp = '<input type="checkbox" disabled style="margin: 0px 0.35em 0.25em -1.6em; vertical-align: middle;"';
if (checked) {
otp += ' checked';
}
otp += '>';
return otp;
});
}
// m1 - Leading line or
// Has a double return (multi paragraph) or
// Has sublist
if (m1 || (item.search(/\n{2,}/) > -1)) {
item = showdown.subParser('githubCodeBlocks')(item, options, globals);
item = showdown.subParser('blockGamut')(item, options, globals);
} else {
// Recursion for sub-lists:
item = showdown.subParser('lists')(item, options, globals);
item = item.replace(/\n$/, ''); // chomp(item)
if (isParagraphed) {
item = showdown.subParser('paragraphs')(item, options, globals);
} else {
item = showdown.subParser('spanGamut')(item, options, globals);
}
}
item = '\n<li' + bulletStyle + '>' + item + '</li>\n';
return item;
});
// attacklab: strip sentinel
listStr = listStr.replace(/~0/g, '');
globals.gListLevel--;
if (trimTrailing) {
listStr = listStr.replace(/\s+$/, '');
}
return listStr;
}
/**
* Check and parse consecutive lists (better fix for issue #142)
* @param {string} list
* @param {string} listType
* @param {boolean} trimTrailing
* @returns {string}
*/
function parseConsecutiveLists(list, listType, trimTrailing) {
// check if we caught 2 or more consecutive lists by mistake
// we use the counterRgx, meaning if listType is UL we look for UL and vice versa
var counterRxg = (listType === 'ul') ? /^ {0,2}\d+\.[ \t]/gm : /^ {0,2}[*+-][ \t]/gm,
subLists = [],
result = '';
if (list.search(counterRxg) !== -1) {
(function parseCL(txt) {
var pos = txt.search(counterRxg);
if (pos !== -1) {
// slice
result += '\n\n<' + listType + '>' + processListItems(txt.slice(0, pos), !!trimTrailing) + '</' + listType + '>\n\n';
// invert counterType and listType
listType = (listType === 'ul') ? 'ol' : 'ul';
counterRxg = (listType === 'ul') ? /^ {0,2}\d+\.[ \t]/gm : /^ {0,2}[*+-][ \t]/gm;
//recurse
parseCL(txt.slice(pos));
} else {
result += '\n\n<' + listType + '>' + processListItems(txt, !!trimTrailing) + '</' + listType + '>\n\n';
}
})(list);
for (var i = 0; i < subLists.length; ++i) {
}
} else {
result = '\n\n<' + listType + '>' + processListItems(list, !!trimTrailing) + '</' + listType + '>\n\n';
}
return result;
}
// attacklab: add sentinel to hack around khtml/safari bug:
// http://bugs.webkit.org/show_bug.cgi?id=11231
text += '~0';
// Re-usable pattern to match any entire ul or ol list:
var wholeList = /^(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;
if (globals.gListLevel) {
text = text.replace(wholeList, function (wholeMatch, list, m2) {
var listType = (m2.search(/[*+-]/g) > -1) ? 'ul' : 'ol';
return parseConsecutiveLists(list, listType, true);
});
} else {
wholeList = /(\n\n|^\n?)(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;
//wholeList = /(\n\n|^\n?)( {0,3}([*+-]|\d+\.)[ \t]+[\s\S]+?)(?=(~0)|(\n\n(?!\t| {2,}| {0,3}([*+-]|\d+\.)[ \t])))/g;
text = text.replace(wholeList, function (wholeMatch, m1, list, m3) {
var listType = (m3.search(/[*+-]/g) > -1) ? 'ul' : 'ol';
return parseConsecutiveLists(list, listType);
});
}
// attacklab: strip sentinel
text = text.replace(/~0/, '');
text = globals.converter._dispatch('lists.after', text, options, globals);
return text;
});
/**
* Remove one level of line-leading tabs or spaces
*/
showdown.subParser('outdent', function (text) {
'use strict';
// attacklab: hack around Konqueror 3.5.4 bug:
// "----------bug".replace(/^-/g,"") == "bug"
text = text.replace(/^(\t|[ ]{1,4})/gm, '~0'); // attacklab: g_tab_width
// attacklab: clean up hack
text = text.replace(/~0/g, '');
return text;
});
/**
*
*/
showdown.subParser('paragraphs', function (text, options, globals) {
'use strict';
text = globals.converter._dispatch('paragraphs.before', text, options, globals);
// Strip leading and trailing lines:
text = text.replace(/^\n+/g, '');
text = text.replace(/\n+$/g, '');
var grafs = text.split(/\n{2,}/g),
grafsOut = [],
end = grafs.length; // Wrap <p> tags
for (var i = 0; i < end; i++) {
var str = grafs[i];
// if this is an HTML marker, copy it
if (str.search(/~(K|G)(\d+)\1/g) >= 0) {
grafsOut.push(str);
} else {
str = showdown.subParser('spanGamut')(str, options, globals);
str = str.replace(/^([ \t]*)/g, '<p>');
str += '</p>';
grafsOut.push(str);
}
}
/** Unhashify HTML blocks */
end = grafsOut.length;
for (i = 0; i < end; i++) {
var blockText = '',
grafsOutIt = grafsOut[i],
codeFlag = false;
// if this is a marker for an html block...
while (grafsOutIt.search(/~(K|G)(\d+)\1/) >= 0) {
var delim = RegExp.$1,
num = RegExp.$2;
if (delim === 'K') {
blockText = globals.gHtmlBlocks[num];
} else {
// we need to check if ghBlock is a false positive
if (codeFlag) {
// use encoded version of all text
blockText = showdown.subParser('encodeCode')(globals.ghCodeBlocks[num].text);
} else {
blockText = globals.ghCodeBlocks[num].codeblock;
}
}
blockText = blockText.replace(/\$/g, '$$$$'); // Escape any dollar signs
grafsOutIt = grafsOutIt.replace(/(\n\n)?~(K|G)\d+\2(\n\n)?/, blockText);
// Check if grafsOutIt is a pre->code
if (/^<pre\b[^>]*>\s*<code\b[^>]*>/.test(grafsOutIt)) {
codeFlag = true;
}
}
grafsOut[i] = grafsOutIt;
}
text = grafsOut.join('\n\n');
// Strip leading and trailing lines:
text = text.replace(/^\n+/g, '');
text = text.replace(/\n+$/g, '');
return globals.converter._dispatch('paragraphs.after', text, options, globals);
});
/**
* Run extension
*/
showdown.subParser('runExtension', function (ext, text, options, globals) {
'use strict';
if (ext.filter) {
text = ext.filter(text, globals.converter, options);
} else if (ext.regex) {
// TODO remove this when old extension loading mechanism is deprecated
var re = ext.regex;
if (!re instanceof RegExp) {
re = new RegExp(re, 'g');
}
text = text.replace(re, ext.replace);
}
return text;
});
/**
* These are all the transformations that occur *within* block-level
* tags like paragraphs, headers, and list items.
*/
showdown.subParser('spanGamut', function (text, options, globals) {
'use strict';
text = globals.converter._dispatch('spanGamut.before', text, options, globals);
text = showdown.subParser('codeSpans')(text, options, globals);
text = showdown.subParser('escapeSpecialCharsWithinTagAttributes')(text, options, globals);
text = showdown.subParser('encodeBackslashEscapes')(text, options, globals);
// Process anchor and image tags. Images must come first,
// because ![foo][f] looks like an anchor.
text = showdown.subParser('images')(text, options, globals);
text = showdown.subParser('anchors')(text, options, globals);
// Make links out of things like `<http://example.com/>`
// Must come after _DoAnchors(), because you can use < and >
// delimiters in inline links like [this](<url>).
text = showdown.subParser('autoLinks')(text, options, globals);
text = showdown.subParser('encodeAmpsAndAngles')(text, options, globals);
text = showdown.subParser('italicsAndBold')(text, options, globals);
text = showdown.subParser('strikethrough')(text, options, globals);
// Do hard breaks:
text = text.replace(/ +\n/g, ' <br />\n');
text = globals.converter._dispatch('spanGamut.after', text, options, globals);
return text;
});
showdown.subParser('strikethrough', function (text, options, globals) {
'use strict';
if (options.strikethrough) {
text = globals.converter._dispatch('strikethrough.before', text, options, globals);
text = text.replace(/(?:~T){2}([\s\S]+?)(?:~T){2}/g, '<del>$1</del>');
text = globals.converter._dispatch('strikethrough.after', text, options, globals);
}
return text;
});
/**
* Strip any lines consisting only of spaces and tabs.
* This makes subsequent regexs easier to write, because we can
* match consecutive blank lines with /\n+/ instead of something
* contorted like /[ \t]*\n+/
*/
showdown.subParser('stripBlankLines', function (text) {
'use strict';
return text.replace(/^[ \t]+$/mg, '');
});
/**
* Strips link definitions from text, stores the URLs and titles in
* hash references.
* Link defs are in the form: ^[id]: url "optional title"
*
* ^[ ]{0,3}\[(.+)\]: // id = $1 attacklab: g_tab_width - 1
* [ \t]*
* \n? // maybe *one* newline
* [ \t]*
* <?(\S+?)>? // url = $2
* [ \t]*
* \n? // maybe one newline
* [ \t]*
* (?:
* (\n*) // any lines skipped = $3 attacklab: lookbehind removed
* ["(]
* (.+?) // title = $4
* [")]
* [ \t]*
* )? // title is optional
* (?:\n+|$)
* /gm,
* function(){...});
*
*/
showdown.subParser('stripLinkDefinitions', function (text, options, globals) {
'use strict';
var regex = /^ {0,3}\[(.+)]:[ \t]*\n?[ \t]*<?(\S+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n+|(?=~0))/gm;
// attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug
text += '~0';
text = text.replace(regex, function (wholeMatch, linkId, url, width, height, blankLines, title) {
linkId = linkId.toLowerCase();
globals.gUrls[linkId] = showdown.subParser('encodeAmpsAndAngles')(url); // Link IDs are case-insensitive
if (blankLines) {
// Oops, found blank lines, so it's not a title.
// Put back the parenthetical statement we stole.
return blankLines + title;
} else {
if (title) {
globals.gTitles[linkId] = title.replace(/"|'/g, '&quot;');
}
if (options.parseImgDimensions && width && height) {
globals.gDimensions[linkId] = {
width: width,
height: height
};
}
}
// Completely remove the definition from the text
return '';
});
// attacklab: strip sentinel
text = text.replace(/~0/, '');
return text;
});
showdown.subParser('tables', function (text, options, globals) {
'use strict';
if (!options.tables) {
return text;
}
var tableRgx = /^[ \t]{0,3}\|?.+\|.+\n[ \t]{0,3}\|?[ \t]*:?[ \t]*(?:-|=){2,}[ \t]*:?[ \t]*\|[ \t]*:?[ \t]*(?:-|=){2,}[\s\S]+?(?:\n\n|~0)/gm;
function parseStyles(sLine) {
if (/^:[ \t]*--*$/.test(sLine)) {
return ' style="text-align:left;"';
} else if (/^--*[ \t]*:[ \t]*$/.test(sLine)) {
return ' style="text-align:right;"';
} else if (/^:[ \t]*--*[ \t]*:$/.test(sLine)) {
return ' style="text-align:center;"';
} else {
return '';
}
}
function parseHeaders(header, style) {
var id = '';
header = header.trim();
if (options.tableHeaderId) {
id = ' id="' + header.replace(/ /g, '_').toLowerCase() + '"';
}
header = showdown.subParser('spanGamut')(header, options, globals);
return '<th' + id + style + '>' + header + '</th>\n';
}
function parseCells(cell, style) {
var subText = showdown.subParser('spanGamut')(cell, options, globals);
return '<td' + style + '>' + subText + '</td>\n';
}
function buildTable(headers, cells) {
var tb = '<table>\n<thead>\n<tr>\n',
tblLgn = headers.length;
for (var i = 0; i < tblLgn; ++i) {
tb += headers[i];
}
tb += '</tr>\n</thead>\n<tbody>\n';
for (i = 0; i < cells.length; ++i) {
tb += '<tr>\n';
for (var ii = 0; ii < tblLgn; ++ii) {
tb += cells[i][ii];
}
tb += '</tr>\n';
}
tb += '</tbody>\n</table>\n';
return tb;
}
text = globals.converter._dispatch('tables.before', text, options, globals);
text = text.replace(tableRgx, function (rawTable) {
var i, tableLines = rawTable.split('\n');
// strip wrong first and last column if wrapped tables are used
for (i = 0; i < tableLines.length; ++i) {
if (/^[ \t]{0,3}\|/.test(tableLines[i])) {
tableLines[i] = tableLines[i].replace(/^[ \t]{0,3}\|/, '');
}
if (/\|[ \t]*$/.test(tableLines[i])) {
tableLines[i] = tableLines[i].replace(/\|[ \t]*$/, '');
}
}
var rawHeaders = tableLines[0].split('|').map(function (s) { return s.trim();}),
rawStyles = tableLines[1].split('|').map(function (s) { return s.trim();}),
rawCells = [],
headers = [],
styles = [],
cells = [];
tableLines.shift();
tableLines.shift();
for (i = 0; i < tableLines.length; ++i) {
if (tableLines[i].trim() === '') {
continue;
}
rawCells.push(
tableLines[i]
.split('|')
.map(function (s) {
return s.trim();
})
);
}
if (rawHeaders.length < rawStyles.length) {
return rawTable;
}
for (i = 0; i < rawStyles.length; ++i) {
styles.push(parseStyles(rawStyles[i]));
}
for (i = 0; i < rawHeaders.length; ++i) {
if (showdown.helper.isUndefined(styles[i])) {
styles[i] = '';
}
headers.push(parseHeaders(rawHeaders[i], styles[i]));
}
for (i = 0; i < rawCells.length; ++i) {
var row = [];
for (var ii = 0; ii < headers.length; ++ii) {
if (showdown.helper.isUndefined(rawCells[i][ii])) {
}
row.push(parseCells(rawCells[i][ii], styles[ii]));
}
cells.push(row);
}
return buildTable(headers, cells);
});
text = globals.converter._dispatch('tables.after', text, options, globals);
return text;
});
/**
* Swap back in all the special characters we've hidden.
*/
showdown.subParser('unescapeSpecialChars', function (text) {
'use strict';
text = text.replace(/~E(\d+)E/g, function (wholeMatch, m1) {
var charCodeToReplace = parseInt(m1);
return String.fromCharCode(charCodeToReplace);
});
return text;
});
module.exports = showdown;
... ...