Commit 22e0a6a8 authored by 石盼盼's avatar 石盼盼

项目搭建

parent fdca4afd
# Windows
[Dd]esktop.ini
Thumbs.db
$RECYCLE.BIN/
# macOS
.DS_Store
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
# Node.js
node_modules/
# Default ignored files
/workspace.xml
\ No newline at end of file
<component name="InspectionProjectProfileManager">
<settings>
<option name="PROJECT_PROFILE" />
</settings>
</component>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/wandoutiyu.iml" filepath="$PROJECT_DIR$/.idea/wandoutiyu.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
//app.js
App({
onLaunch: function () {
// 展示本地存储能力
var logs = wx.getStorageSync('logs') || []
logs.unshift(Date.now())
wx.setStorageSync('logs', logs)
// 登录
wx.login({
success: res => {
// 发送 res.code 到后台换取 openId, sessionKey, unionId
}
})
// 获取用户信息
wx.getSetting({
success: res => {
if (res.authSetting['scope.userInfo']) {
// 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
wx.getUserInfo({
success: res => {
// 可以将 res 发送给后台解码出 unionId
this.globalData.userInfo = res.userInfo
// 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
// 所以此处加入 callback 以防止这种情况
if (this.userInfoReadyCallback) {
this.userInfoReadyCallback(res)
}
}
})
}
}
})
},
globalData: {
userInfo: null
}
})
\ No newline at end of file
{
"pages":[
"pages/index/index",
"pages/class/class",
"pages/financial/financial",
"pages/personal/personal"
],
"tabBar":{
"custom":false,
"color":"#919399",
"selectedColor":"#1A1A1A",
"borderStyle": "white",
"backgroundColor": "#fff",
"list": [
{
"pagePath": "pages/index/index",
"iconPath": "images/tab/home_icon_01_nor.png",
"selectedIconPath": "images/tab/home_icon_01_sel.png",
"text": "课表"
},
{
"pagePath": "pages/class/class",
"iconPath": "images/tab/home_icon_02_nor.png",
"selectedIconPath": "images/tab/home_icon_02_sel.png",
"text": "抢班"
},
{
"pagePath": "pages/financial/financial",
"iconPath": "images/tab/home_icon_03_nor.png",
"selectedIconPath": "images/tab/home_icon_03_sel.png",
"text": "财务 "
},
{
"pagePath": "pages/personal/personal",
"iconPath": "images/tab/home_icon_04_nor.png",
"selectedIconPath": "images/tab/home_icon_04_sel.png",
"text": "我的 "
}
]
},
"window":{
"backgroundTextStyle":"light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "豌豆队长",
"navigationBarTextStyle":"black"
},
"style": "v2",
"sitemapLocation": "sitemap.json",
"permission": {
"scope.userLocation": {
"desc": "你的位置信息将用于定位"
}
},
"usingComponents": {
"van-icon": "components/vant/icon/index",
"van-action-sheet": "components/vant/action-sheet/index",
"van-count-down": "components/vant/count-down/index",
"van-field": "components/vant/field/index",
"van-radio": "components/vant/radio/index",
"van-radio-group": "components/vant/radio-group/index",
"van-picker": "components/vant/picker/index",
"van-tag": "components/vant/tag/index",
"van-image": "components/vant/image/index",
"van-popup": "components/vant/popup/index"
},
"plugins": {
"calendar": {
"version": "1.1.3",
"provider": "wx92c68dae5a8bb046"
}
}
}
@import "/wxParse/wxParse.wxss";
@import './iconfont/iconfont.wxss';
page{
font-size: 24rpx;
box-sizing: border-box;
}
page::after{
content: '';
position: fixed;
left: 0;
bottom: 0;
width: 100%;
height: 2rpx;
background-color: rgba(0, 0, 0, 0.08);
box-shadow: 0px 2px 10px 0px rgba(0, 0, 0, 0.08);
z-index: 100;
}
view {
box-sizing: border-box;
}
.row{
display: flex;
flex-direction: row;
}
.column{
display: flex;
flex-direction: column;
}
.overflow{
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.greyItem{
width: 100%;
height: 20rpx;
background: #F8F6F9;
}
/* 空白页 */
.noneBox{
padding: 140rpx 0 0;
align-items: center;
font-size: 28rpx;
color: #999;
}
.noneBox image{
width: 400rpx;
height: 400rpx;
margin-bottom: 30rpx;
}
/* 详情样式 */
.desc .hellorich{
max-width: 100% !important;
display: block;
margin: 0 auto;
}
.helloVideo{
display: block;
max-width: 100% !important;
height: auto;
margin: 0 auto;
}
/* 绑定手机 */
.telBox{
width: 500rpx;
height: 400rpx;
position: relative;
}
.van-popup{
border-radius: 10rpx!important;
}
.telClose{
position: absolute;
right: 40rpx;
top: 0;
z-index: 1;
}
.telBox .title{
text-align: center;
color: #1A1A1A;
font-size: 32rpx;
font-weight: bold;
margin: 50rpx 0 20rpx;
}
.telRow{
margin: 0 40rpx;
height: 100rpx;
align-items: center;
justify-content: space-between;
border-bottom: 1rpx solid #EBEBEB;
}
.telRow input{
font-size: 28rpx;
}
.codeInp{
width: 200rpx;
}
.getBtn{
color: #9FAA4B;
font-size: 28rpx;
}
.telBox .confirmBtn{
width: 345rpx;
height: 70rpx;
line-height: 70rpx;
background: #9FAA4B;
border-radius:35rpx;
text-align: center;
font-size: 28rpx;
color: #fff;
margin: 35rpx auto 0;
}
/* */
/* 一行 */
.text-line-one {
overflow:hidden;
text-overflow:ellipsis;
-o-text-overflow:ellipsis;
-webkit-text-overflow:ellipsis;
-moz-text-overflow:ellipsis;
white-space:nowrap;
}
/* 两行 */
.text-line-two {
word-break:break-all;
display:-webkit-box;
-webkit-line-clamp:2;
-webkit-box-orient:vertical;
overflow:hidden;
height: 85rpx;
}
.no-line {
border: none !important;
}
/* flex兼容性 */
/* 父元素-横向排列(主轴) */
.flex-h {
display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */
display: -moz-box; /* OLD - Firefox 19- (buggy but mostly works) */
display: -ms-flexbox; /* TWEENER - IE 10 */
display: -webkit-flex; /* NEW - Chrome */
display: flex; /* NEW, Spec - Opera 12.1, Firefox 20+ */
/* 09版 */
-webkit-box-orient: horizontal;
/* 12版 */
-webkit-flex-direction: row;
-moz-flex-direction: row;
-ms-flex-direction: row;
-o-flex-direction: row;
flex-direction: row;
}
/* 父元素-纵向排列(主轴) */
.flex-v {
display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */
display: -moz-box; /* OLD - Firefox 19- (buggy but mostly works) */
display: -ms-flexbox; /* TWEENER - IE 10 */
display: -webkit-flex; /* NEW - Chrome */
display: flex; /* NEW, Spec - Opera 12.1, Firefox 20+ */
/* 09版 */
-webkit-box-orient: vertical;
/* 12版 */
-webkit-flex-direction: column;
-moz-flex-direction: column;
-ms-flex-direction: column;
-o-flex-direction: column;
flex-direction: column;
}
.flex-hr {
display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */
display: -moz-box; /* OLD - Firefox 19- (buggy but mostly works) */
display: -ms-flexbox; /* TWEENER - IE 10 */
display: -webkit-flex; /* NEW - Chrome */
display: flex; /* NEW, Spec - Opera 12.1, Firefox 20+ */
/* 09版 */
-webkit-box-orient: horizontal;
/* 12版 */
-webkit-flex-direction: row-reverse;
-moz-flex-direction: row-reverse;
-ms-flex-direction: row-reverse;
-o-flex-direction: row-reverse;
flex-direction: row-reverse;
}
.flex-hc {
-webkit-box-pack: center;
-webkit-justify-content: center;
-moz-justify-content: center;
-ms-justify-content: center;
-o-justify-content: center;
justify-content: center;
}
.flex-hb {
-webkit-box-pack: space-between;
-webkit-justify-content: space-between;
-moz-justify-content: space-between;
-ms-justify-content: space-between;
-o-justify-content: space-between;
justify-content: space-between;
}
.flex-ha {
-webkit-box-pack: space-around;
-webkit-justify-content: space-around;
-moz-justify-content: space-around;
-ms-justify-content: space-around;
-o-justify-content: space-around;
justify-content: space-around;
}
.flex-vc {
/* 09版 */
-webkit-box-align: center;
/* 12版 */
-webkit-align-items: center;
-moz-align-items: center;
-ms-align-items: center;
-o-align-items: center;
align-items: center;
}
/* 父元素-横向换行 */
.flex-hw {
/* 09版 */
/*-webkit-box-lines: multiple;*/
/* 12版 */
-webkit-flex-wrap: wrap;
-moz-flex-wrap: wrap;
-ms-flex-wrap: wrap;
-o-flex-wrap: wrap;
flex-wrap: wrap;
}
import { VantComponent } from '../common/component';
import { button } from '../mixins/button';
import { openType } from '../mixins/open-type';
VantComponent({
mixins: [button, openType],
props: {
show: Boolean,
title: String,
cancelText: String,
description: String,
round: {
type: Boolean,
value: true
},
zIndex: {
type: Number,
value: 100
},
actions: {
type: Array,
value: []
},
overlay: {
type: Boolean,
value: true
},
closeOnClickOverlay: {
type: Boolean,
value: true
},
closeOnClickAction: {
type: Boolean,
value: true
},
safeAreaInsetBottom: {
type: Boolean,
value: true
}
},
methods: {
onSelect(event) {
const { index } = event.currentTarget.dataset;
const item = this.data.actions[index];
if (item && !item.disabled && !item.loading) {
this.$emit('select', item);
if (this.data.closeOnClickAction) {
this.onClose();
}
}
},
onCancel() {
this.$emit('cancel');
},
onClose() {
this.$emit('close');
},
onClickOverlay() {
this.$emit('click-overlay');
this.onClose();
}
}
});
{
"component": true,
"usingComponents": {
"van-icon": "../icon/index",
"van-popup": "../popup/index",
"van-loading": "../loading/index"
}
}
<wxs src="../wxs/utils.wxs" module="utils" />
<van-popup
show="{{ show }}"
position="bottom"
round="{{ round }}"
z-index="{{ zIndex }}"
overlay="{{ overlay }}"
custom-class="van-action-sheet"
safe-area-inset-bottom="{{ safeAreaInsetBottom }}"
close-on-click-overlay="{{ closeOnClickOverlay }}"
bind:close="onClickOverlay"
>
<view wx:if="{{ title }}" class="van-hairline--bottom van-action-sheet__header">
{{ title }}
<van-icon
name="close"
custom-class="van-action-sheet__close"
bind:click="onClose"
/>
</view>
<view wx:if="{{ description }}" class="van-action-sheet__description">
{{ description }}
</view>
<view wx:if="{{ actions && actions.length }}">
<!-- button外包一层view,防止actions动态变化,导致渲染时button被打散 -->
<button
wx:for="{{ actions }}"
wx:key="index"
open-type="{{ item.openType }}"
style="{{ item.color ? 'color: ' + item.color : '' }}"
class="{{ utils.bem('action-sheet__item', { disabled: item.disabled || item.loading }) }} van-hairline--top {{ item.className || '' }}"
hover-class="van-action-sheet__item--hover"
data-index="{{ index }}"
bind:tap="onSelect"
bindgetuserinfo="bindGetUserInfo"
bindcontact="bindContact"
bindgetphonenumber="bindGetPhoneNumber"
binderror="bindError"
bindlaunchapp="bindLaunchApp"
bindopensetting="bindOpenSetting"
lang="{{ lang }}"
session-from="{{ sessionFrom }}"
send-message-title="{{ sendMessageTitle }}"
send-message-path="{{ sendMessagePath }}"
send-message-img="{{ sendMessageImg }}"
show-message-card="{{ showMessageCard }}"
app-parameter="{{ appParameter }}"
>
<block wx:if="{{ !item.loading }}">
{{ item.name }}
<text wx:if="{{ item.subname }}" class="van-action-sheet__subname" >{{ item.subname }}</text>
</block>
<van-loading wx:else custom-class="van-action-sheet__loading" size="20px" />
</button>
</view>
<slot />
<view
wx:if="{{ cancelText }}"
class="van-action-sheet__cancel"
hover-class="van-action-sheet__cancel--hover"
hover-stay-time="70"
bind:tap="onCancel"
>
{{ cancelText }}
</view>
</van-popup>
@import '../common/index.wxss';.van-action-sheet{max-height:90%!important;max-height:var(--action-sheet-max-height,90%)!important;color:#323233;color:var(--action-sheet-item-text-color,#323233)}.van-action-sheet__cancel,.van-action-sheet__item{text-align:center;font-size:16px;font-size:var(--action-sheet-item-font-size,16px);line-height:50px;line-height:var(--action-sheet-item-height,50px);background-color:#fff;background-color:var(--action-sheet-item-background,#fff)}.van-action-sheet__cancel--hover,.van-action-sheet__item--hover{background-color:#f2f3f5;background-color:var(--active-color,#f2f3f5)}.van-action-sheet__cancel:before{display:block;content:" ";height:8px;height:var(--action-sheet-cancel-padding-top,8px);background-color:#f7f8fa;background-color:var(--action-sheet-cancel-padding-color,#f7f8fa)}.van-action-sheet__item--disabled{color:#c8c9cc;color:var(--action-sheet-item-disabled-text-color,#c8c9cc)}.van-action-sheet__item--disabled.van-action-sheet__item--hover{background-color:#fff;background-color:var(--action-sheet-item-background,#fff)}.van-action-sheet__subname{margin-left:4px;margin-left:var(--padding-base,4px);font-size:12px;font-size:var(--action-sheet-subname-font-size,12px);color:#646566;color:var(--action-sheet-subname-color,#646566)}.van-action-sheet__header{text-align:center;font-weight:500;font-weight:var(--font-weight-bold,500);font-size:16px;font-size:var(--action-sheet-header-font-size,16px);line-height:44px;line-height:var(--action-sheet-header-height,44px)}.van-action-sheet__description{text-align:center;padding:16px;padding:var(--padding-md,16px);color:#646566;color:var(--action-sheet-description-color,#646566);font-size:14px;font-size:var(--action-sheet-description-font-size,14px);line-height:20px;line-height:var(--action-sheet-description-line-height,20px)}.van-action-sheet__close{position:absolute!important;top:0;right:0;line-height:inherit!important;padding:0 12px;padding:var(--action-sheet-close-icon-padding,0 12px);font-size:18px!important;font-size:var(--action-sheet-close-icon-size,18px)!important;color:#969799;color:var(--action-sheet-close-icon-color,#969799)}.van-action-sheet__loading{display:-webkit-flex!important;display:flex!important;height:50px;height:var(--action-sheet-item-height,50px)}
\ No newline at end of file
import { link } from '../mixins/link';
import { VantComponent } from '../common/component';
VantComponent({
classes: [
'title-class',
'label-class',
'value-class',
'right-icon-class',
'hover-class'
],
mixins: [link],
props: {
title: null,
value: null,
icon: String,
size: String,
label: String,
center: Boolean,
isLink: Boolean,
required: Boolean,
clickable: Boolean,
titleWidth: String,
customStyle: String,
arrowDirection: String,
useLabelSlot: Boolean,
border: {
type: Boolean,
value: true
}
},
methods: {
onClick(event) {
this.$emit('click', event.detail);
this.jumpLink();
}
}
});
{
"component": true,
"usingComponents": {
"van-icon": "../icon/index"
}
}
\ No newline at end of file
<wxs src="../wxs/utils.wxs" module="utils" />
<view
class="custom-class {{ utils.bem('cell', [size, { center, required, borderless: !border, clickable: isLink || clickable }]) }}"
hover-class="van-cell--hover hover-class"
hover-stay-time="70"
style="{{ customStyle }}"
bind:tap="onClick"
>
<van-icon
wx:if="{{ icon }}"
name="{{ icon }}"
class="van-cell__left-icon-wrap"
custom-class="van-cell__left-icon"
/>
<slot wx:else name="icon" />
<view
style="{{ titleWidth ? 'max-width:' + titleWidth + ';min-width:' + titleWidth : '' }}"
class="van-cell__title title-class"
>
<block wx:if="{{ title }}">{{ title }}</block>
<slot wx:else name="title" />
<view wx:if="{{ label || useLabelSlot }}" class="van-cell__label label-class">
<slot wx:if="{{ useLabelSlot }}" name="label" />
<block wx:elif="{{ label }}">{{ label }}</block>
</view>
</view>
<view class="van-cell__value value-class">
<block wx:if="{{ value || value === 0 }}">{{ value }}</block>
<slot wx:else />
</view>
<van-icon
wx:if="{{ isLink }}"
name="{{ arrowDirection ? 'arrow' + '-' + arrowDirection : 'arrow' }}"
class="van-cell__right-icon-wrap right-icon-class"
custom-class="van-cell__right-icon"
/>
<slot wx:else name="right-icon" />
<slot name="extra" />
</view>
@import '../common/index.wxss';.van-cell{position:relative;display:-webkit-flex;display:flex;box-sizing:border-box;width:100%;padding:10px 16px;padding:var(--cell-vertical-padding,10px) var(--cell-horizontal-padding,16px);font-size:14px;font-size:var(--cell-font-size,14px);line-height:24px;line-height:var(--cell-line-height,24px);color:#323233;color:var(--cell-text-color,#323233);background-color:#fff;background-color:var(--cell-background-color,#fff)}.van-cell:after{position:absolute;box-sizing:border-box;-webkit-transform-origin:center;transform-origin:center;content:" ";pointer-events:none;top:auto;right:0;bottom:0;left:16px;border-bottom:1px solid #ebedf0;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.van-cell--borderless:after{display:none}.van-cell-group{background-color:#fff;background-color:var(--cell-background-color,#fff)}.van-cell__label{margin-top:3px;margin-top:var(--cell-label-margin-top,3px);font-size:12px;font-size:var(--cell-label-font-size,12px);line-height:18px;line-height:var(--cell-label-line-height,18px);color:#969799;color:var(--cell-label-color,#969799)}.van-cell__value{overflow:hidden;text-align:right;vertical-align:middle;color:#969799;color:var(--cell-value-color,#969799)}.van-cell__title,.van-cell__value{-webkit-flex:1;flex:1}.van-cell__title:empty,.van-cell__value:empty{display:none}.van-cell__left-icon-wrap,.van-cell__right-icon-wrap{display:-webkit-flex;display:flex;-webkit-align-items:center;align-items:center;height:24px;height:var(--cell-line-height,24px);font-size:16px;font-size:var(--cell-icon-size,16px)}.van-cell__left-icon-wrap{margin-right:5px}.van-cell__right-icon-wrap{margin-left:5px;color:#969799;color:var(--cell-right-icon-color,#969799)}.van-cell__left-icon{vertical-align:middle}.van-cell__left-icon,.van-cell__right-icon{line-height:24px;line-height:var(--cell-line-height,24px)}.van-cell--clickable.van-cell--hover{background-color:#f2f3f5;background-color:var(--cell-active-color,#f2f3f5)}.van-cell--required{overflow:visible}.van-cell--required:before{position:absolute;content:"*";left:8px;left:var(--padding-xs,8px);font-size:14px;font-size:var(--cell-font-size,14px);color:#ee0a24;color:var(--cell-required-color,#ee0a24)}.van-cell--center{-webkit-align-items:center;align-items:center}.van-cell--large{padding-top:12px;padding-top:var(--cell-large-vertical-padding,12px);padding-bottom:12px;padding-bottom:var(--cell-large-vertical-padding,12px)}.van-cell--large .van-cell__title{font-size:16px;font-size:var(--cell-large-title-font-size,16px)}.van-cell--large .van-cell__label{font-size:14px;font-size:var(--cell-large-label-font-size,14px)}
\ No newline at end of file
export declare const RED = "#ee0a24";
export declare const BLUE = "#1989fa";
export declare const WHITE = "#fff";
export declare const GREEN = "#07c160";
export declare const ORANGE = "#ff976a";
export declare const GRAY = "#323233";
export declare const GRAY_DARK = "#969799";
export const RED = '#ee0a24';
export const BLUE = '#1989fa';
export const WHITE = '#fff';
export const GREEN = '#07c160';
export const ORANGE = '#ff976a';
export const GRAY = '#323233';
export const GRAY_DARK = '#969799';
import { VantComponentOptions, CombinedComponentInstance } from '../definitions/index';
declare function VantComponent<Data, Props, Methods>(vantOptions?: VantComponentOptions<Data, Props, Methods, CombinedComponentInstance<Data, Props, Methods>>): void;
export { VantComponent };
import { basic } from '../mixins/basic';
const relationFunctions = {
ancestor: {
linked(parent) {
this.parent = parent;
},
unlinked() {
this.parent = null;
},
},
descendant: {
linked(child) {
this.children = this.children || [];
this.children.push(child);
},
unlinked(child) {
this.children = (this.children || []).filter(it => it !== child);
},
},
};
function mapKeys(source, target, map) {
Object.keys(map).forEach(key => {
if (source[key]) {
target[map[key]] = source[key];
}
});
}
function makeRelation(options, vantOptions, relation) {
const { type, name, linked, unlinked, linkChanged } = relation;
const { beforeCreate, destroyed } = vantOptions;
if (type === 'descendant') {
options.created = function () {
beforeCreate && beforeCreate.bind(this)();
this.children = this.children || [];
};
options.detached = function () {
this.children = [];
destroyed && destroyed.bind(this)();
};
}
options.relations = Object.assign(options.relations || {}, {
[`../${name}/index`]: {
type,
linked(node) {
relationFunctions[type].linked.bind(this)(node);
linked && linked.bind(this)(node);
},
linkChanged(node) {
linkChanged && linkChanged.bind(this)(node);
},
unlinked(node) {
relationFunctions[type].unlinked.bind(this)(node);
unlinked && unlinked.bind(this)(node);
},
}
});
}
function VantComponent(vantOptions = {}) {
const options = {};
mapKeys(vantOptions, options, {
data: 'data',
props: 'properties',
mixins: 'behaviors',
methods: 'methods',
beforeCreate: 'created',
created: 'attached',
mounted: 'ready',
relations: 'relations',
destroyed: 'detached',
classes: 'externalClasses'
});
const { relation } = vantOptions;
if (relation) {
makeRelation(options, vantOptions, relation);
}
// add default externalClasses
options.externalClasses = options.externalClasses || [];
options.externalClasses.push('custom-class');
// add default behaviors
options.behaviors = options.behaviors || [];
options.behaviors.push(basic);
// map field to form-field behavior
if (vantOptions.field) {
options.behaviors.push('wx://form-field');
}
// add default options
options.options = {
multipleSlots: true,
addGlobalClass: true
};
Component(options);
}
export { VantComponent };
.van-ellipsis{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.van-multi-ellipsis--l2{-webkit-line-clamp:2}.van-multi-ellipsis--l2,.van-multi-ellipsis--l3{display:-webkit-box;overflow:hidden;text-overflow:ellipsis;-webkit-box-orient:vertical}.van-multi-ellipsis--l3{-webkit-line-clamp:3}.van-clearfix:after{display:table;clear:both;content:""}.van-hairline,.van-hairline--bottom,.van-hairline--left,.van-hairline--right,.van-hairline--surround,.van-hairline--top,.van-hairline--top-bottom{position:relative}.van-hairline--bottom:after,.van-hairline--left:after,.van-hairline--right:after,.van-hairline--surround:after,.van-hairline--top-bottom:after,.van-hairline--top:after,.van-hairline:after{position:absolute;box-sizing:border-box;-webkit-transform-origin:center;transform-origin:center;content:" ";pointer-events:none;top:-50%;right:-50%;bottom:-50%;left:-50%;border:0 solid #eee;-webkit-transform:scale(.5);transform:scale(.5)}.van-hairline--top:after{border-top-width:1px}.van-hairline--left:after{border-left-width:1px}.van-hairline--right:after{border-right-width:1px}.van-hairline--bottom:after{border-bottom-width:1px}.van-hairline--top-bottom:after{border-width:1px 0}.van-hairline--surround:after{border-width:1px}
\ No newline at end of file
.van-clearfix:after{display:table;clear:both;content:""}
\ No newline at end of file
.van-ellipsis{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.van-multi-ellipsis--l2{-webkit-line-clamp:2}.van-multi-ellipsis--l2,.van-multi-ellipsis--l3{display:-webkit-box;overflow:hidden;text-overflow:ellipsis;-webkit-box-orient:vertical}.van-multi-ellipsis--l3{-webkit-line-clamp:3}
\ No newline at end of file
.van-hairline,.van-hairline--bottom,.van-hairline--left,.van-hairline--right,.van-hairline--surround,.van-hairline--top,.van-hairline--top-bottom{position:relative}.van-hairline--bottom:after,.van-hairline--left:after,.van-hairline--right:after,.van-hairline--surround:after,.van-hairline--top-bottom:after,.van-hairline--top:after,.van-hairline:after{position:absolute;box-sizing:border-box;-webkit-transform-origin:center;transform-origin:center;content:" ";pointer-events:none;top:-50%;right:-50%;bottom:-50%;left:-50%;border:0 solid #eee;-webkit-transform:scale(.5);transform:scale(.5)}.van-hairline--top:after{border-top-width:1px}.van-hairline--left:after{border-left-width:1px}.van-hairline--right:after{border-right-width:1px}.van-hairline--bottom:after{border-bottom-width:1px}.van-hairline--top-bottom:after{border-width:1px 0}.van-hairline--surround:after{border-width:1px}
\ No newline at end of file
/// <reference types="miniprogram-api-typings" />
export declare function isDef(value: any): boolean;
export declare function isObj(x: any): boolean;
export declare function isNumber(value: any): boolean;
export declare function range(num: number, min: number, max: number): number;
export declare function nextTick(fn: Function): void;
export declare function getSystemInfoSync(): WechatMiniprogram.GetSystemInfoSuccessCallbackResult;
export declare function addUnit(value?: string | number): string | undefined;
export function isDef(value) {
return value !== undefined && value !== null;
}
export function isObj(x) {
const type = typeof x;
return x !== null && (type === 'object' || type === 'function');
}
export function isNumber(value) {
return /^\d+(\.\d+)?$/.test(value);
}
export function range(num, min, max) {
return Math.min(Math.max(num, min), max);
}
export function nextTick(fn) {
setTimeout(() => {
fn();
}, 1000 / 30);
}
let systemInfo = null;
export function getSystemInfoSync() {
if (systemInfo == null) {
systemInfo = wx.getSystemInfoSync();
}
return systemInfo;
}
export function addUnit(value) {
if (!isDef(value)) {
return undefined;
}
value = String(value);
return isNumber(value) ? `${value}px` : value;
}
import { VantComponent } from '../common/component';
import { isSameSecond, parseFormat, parseTimeData } from './utils';
function simpleTick(fn) {
return setTimeout(fn, 30);
}
VantComponent({
props: {
useSlot: Boolean,
millisecond: Boolean,
time: {
type: Number,
observer: 'reset'
},
format: {
type: String,
value: 'HH:mm:ss'
},
autoStart: {
type: Boolean,
value: true
}
},
data: {
timeData: parseTimeData(0),
formattedTime: '0'
},
destroyed() {
clearTimeout(this.tid);
this.tid = null;
},
methods: {
// 开始
start() {
if (this.counting) {
return;
}
this.counting = true;
this.endTime = Date.now() + this.remain;
this.tick();
},
// 暂停
pause() {
this.counting = false;
clearTimeout(this.tid);
},
// 重置
reset() {
this.pause();
this.remain = this.data.time;
this.setRemain(this.remain);
if (this.data.autoStart) {
this.start();
}
},
tick() {
if (this.data.millisecond) {
this.microTick();
}
else {
this.macroTick();
}
},
microTick() {
this.tid = simpleTick(() => {
this.setRemain(this.getRemain());
if (this.remain !== 0) {
this.microTick();
}
});
},
macroTick() {
this.tid = simpleTick(() => {
const remain = this.getRemain();
if (!isSameSecond(remain, this.remain) || remain === 0) {
this.setRemain(remain);
}
if (this.remain !== 0) {
this.macroTick();
}
});
},
getRemain() {
return Math.max(this.endTime - Date.now(), 0);
},
setRemain(remain) {
this.remain = remain;
const timeData = parseTimeData(remain);
if (this.data.useSlot) {
this.$emit('change', timeData);
}
this.setData({
formattedTime: parseFormat(this.data.format, timeData)
});
if (remain === 0) {
this.pause();
this.$emit('finish');
}
}
}
});
<view class="van-count-down">
<slot wx:if="{{ useSlot }}"/>
<block wx:else>{{ formattedTime }}</block>
</view>
@import '../common/index.wxss';.van-count-down{color:#323233;color:var(--count-down-text-color,#323233);font-size:14px;font-size:var(--count-down-font-size,14px);line-height:20px;line-height:var(--count-down-line-height,20px)}
\ No newline at end of file
export declare type TimeData = {
days: number;
hours: number;
minutes: number;
seconds: number;
milliseconds: number;
};
export declare function parseTimeData(time: number): TimeData;
export declare function parseFormat(format: string, timeData: TimeData): string;
export declare function isSameSecond(time1: number, time2: number): boolean;
function padZero(num, targetLength = 2) {
let str = num + '';
while (str.length < targetLength) {
str = '0' + str;
}
return str;
}
const SECOND = 1000;
const MINUTE = 60 * SECOND;
const HOUR = 60 * MINUTE;
const DAY = 24 * HOUR;
export function parseTimeData(time) {
const days = Math.floor(time / DAY);
const hours = Math.floor((time % DAY) / HOUR);
const minutes = Math.floor((time % HOUR) / MINUTE);
const seconds = Math.floor((time % MINUTE) / SECOND);
const milliseconds = Math.floor(time % SECOND);
return {
days,
hours,
minutes,
seconds,
milliseconds
};
}
export function parseFormat(format, timeData) {
const { days } = timeData;
let { hours, minutes, seconds, milliseconds } = timeData;
if (format.indexOf('DD') === -1) {
hours += days * 24;
}
else {
format = format.replace('DD', padZero(days));
}
if (format.indexOf('HH') === -1) {
minutes += hours * 60;
}
else {
format = format.replace('HH', padZero(hours));
}
if (format.indexOf('mm') === -1) {
seconds += minutes * 60;
}
else {
format = format.replace('mm', padZero(minutes));
}
if (format.indexOf('ss') === -1) {
milliseconds += seconds * 1000;
}
else {
format = format.replace('ss', padZero(seconds));
}
return format.replace('SSS', padZero(milliseconds, 3));
}
export function isSameSecond(time1, time2) {
return Math.floor(time1 / 1000) === Math.floor(time2 / 1000);
}
import { VantComponent } from '../common/component';
VantComponent({
field: true,
relation: {
name: 'dropdown-menu',
type: 'ancestor',
current: 'dropdown-item',
linked() {
this.updateDataFromParent();
},
},
props: {
value: {
type: null,
observer: 'rerender',
},
title: {
type: String,
observer: 'rerender',
},
disabled: Boolean,
titleClass: {
type: String,
observer: 'rerender',
},
options: {
type: Array,
value: [],
observer: 'rerender',
},
popupStyle: String,
},
data: {
transition: true,
showPopup: false,
showWrapper: false,
displayTitle: '',
},
methods: {
rerender() {
wx.nextTick(() => {
this.parent && this.parent.updateItemListData();
});
},
updateDataFromParent() {
if (this.parent) {
const {
overlay,
duration,
activeColor,
closeOnClickOverlay,
direction,
} = this.parent.data;
this.setData({
overlay,
duration,
activeColor,
closeOnClickOverlay,
direction,
});
}
},
onOpen() {
this.$emit('open');
},
onOpened() {
this.$emit('opened');
},
onClose() {
this.$emit('close');
},
onClosed() {
this.$emit('closed');
this.setData({ showWrapper: false });
},
onOptionTap(event) {
const { option } = event.currentTarget.dataset;
const { value } = option;
const shouldEmitChange = this.data.value !== value;
this.setData({ showPopup: false, value });
this.$emit('close');
this.rerender();
if (shouldEmitChange) {
this.$emit('change', value);
}
},
toggle(show, options = {}) {
const { showPopup } = this.data;
if (typeof show !== 'boolean') {
show = !showPopup;
}
if (show === showPopup) {
return;
}
this.setData({
transition: !options.immediate,
showPopup: show,
});
if (show) {
this.parent.getChildWrapperStyle().then((wrapperStyle) => {
this.setData({ wrapperStyle, showWrapper: true });
this.rerender();
});
} else {
this.rerender();
}
},
},
});
{
"component": true,
"usingComponents": {
"van-popup": "../popup/index",
"van-cell": "../cell/index",
"van-icon": "../icon/index"
}
}
<wxs src="../wxs/utils.wxs" module="utils" />
<view
wx:if="{{ showWrapper }}"
class="{{ utils.bem('dropdown-item', direction) }}"
style="{{ wrapperStyle }}"
>
<van-popup
show="{{ showPopup }}"
custom-style="position: absolute;{{ popupStyle }}"
overlay-style="position: absolute;"
overlay="{{ overlay }}"
position="{{ direction === 'down' ? 'top' : 'bottom' }}"
duration="{{ transition ? duration : 0 }}"
close-on-click-overlay="{{ closeOnClickOverlay }}"
bind:enter="onOpen"
bind:leave="onClose"
bind:close="toggle"
bind:after-enter="onOpened"
bind:after-leave="onClosed"
>
<van-cell
wx:for="{{ options }}"
wx:key="value"
data-option="{{ item }}"
class="{{ utils.bem('dropdown-item__option', { active: item.value === value } ) }}"
clickable
icon="{{ item.icon }}"
bind:tap="onOptionTap"
>
<view
slot="title"
class="van-dropdown-item__title"
style="{{ item.value === value ? 'color:' + activeColor : '' }}"
>
{{ item.text }}
</view>
<van-icon
wx:if="{{ item.value === value }}"
name="success"
class="van-dropdown-item__icon"
color="{{ activeColor }}"
/>
</van-cell>
<slot />
</van-popup>
</view>
@import '../common/index.wxss';.van-dropdown-item{position:fixed;right:0;left:0;overflow:hidden}.van-dropdown-item__option{text-align:left}.van-dropdown-item__option--active .van-dropdown-item__icon,.van-dropdown-item__option--active .van-dropdown-item__title{color:#1989fa;color:var(--dropdown-menu-option-active-color,#1989fa)}.van-dropdown-item--up{top:0}.van-dropdown-item--down{bottom:0}.van-dropdown-item__icon{display:block;line-height:inherit}
\ No newline at end of file
import { VantComponent } from '../common/component';
import { addUnit } from '../common/utils';
let ARRAY = [];
VantComponent({
field: true,
relation: {
name: 'dropdown-item',
type: 'descendant',
current: 'dropdown-menu',
linked() {
this.updateItemListData();
},
unlinked() {
this.updateItemListData();
},
},
props: {
activeColor: {
type: String,
observer: 'updateChildrenData',
},
overlay: {
type: Boolean,
value: true,
observer: 'updateChildrenData',
},
zIndex: {
type: Number,
value: 10,
},
duration: {
type: Number,
value: 200,
observer: 'updateChildrenData',
},
direction: {
type: String,
value: 'down',
observer: 'updateChildrenData',
},
closeOnClickOverlay: {
type: Boolean,
value: true,
observer: 'updateChildrenData',
},
closeOnClickOutside: {
type: Boolean,
value: true,
},
},
data: {
itemListData: [],
},
beforeCreate() {
const { windowHeight } = wx.getSystemInfoSync();
this.windowHeight = windowHeight;
ARRAY.push(this);
},
destroyed() {
ARRAY = ARRAY.filter((item) => item !== this);
},
methods: {
updateItemListData() {
this.setData({
itemListData: this.children.map((child) => child.data),
});
},
updateChildrenData() {
this.children.forEach((child) => {
child.updateDataFromParent();
});
},
toggleItem(active) {
this.children.forEach((item, index) => {
const { showPopup } = item.data;
if (index === active) {
item.toggle();
} else if (showPopup) {
item.toggle(false, { immediate: true });
}
});
},
close() {
this.children.forEach((child) => {
child.toggle(false, { immediate: true });
});
},
getChildWrapperStyle() {
const { zIndex, direction } = this.data;
return this.getRect('.van-dropdown-menu').then((rect) => {
const { top = 0, bottom = 0 } = rect;
const offset = direction === 'down' ? bottom : this.windowHeight - top;
let wrapperStyle = `z-index: ${zIndex};`;
if (direction === 'down') {
wrapperStyle += `top: ${addUnit(offset)};`;
} else {
wrapperStyle += `bottom: ${addUnit(offset)};`;
}
return wrapperStyle;
});
},
onTitleTap(event) {
const { index } = event.currentTarget.dataset;
const child = this.children[index];
if (!child.data.disabled) {
ARRAY.forEach((menuItem) => {
if (
menuItem &&
menuItem.data.closeOnClickOutside &&
menuItem !== this
) {
menuItem.close();
}
});
this.toggleItem(index);
}
},
},
});
<wxs src="../wxs/utils.wxs" module="utils" />
<wxs src="./index.wxs" module="computed" />
<view class="van-dropdown-menu van-dropdown-menu--top-bottom">
<view
wx:for="{{ itemListData }}"
wx:key="index"
data-index="{{ index }}"
class="{{ utils.bem('dropdown-menu__item', { disabled: item.disabled }) }}"
bind:tap="onTitleTap"
>
<view
class="{{ item.titleClass }} {{ utils.bem('dropdown-menu__title', { active: item.showPopup, down: item.showPopup === (direction === 'down') }) }}"
style="{{ item.showPopup ? 'color:' + activeColor : '' }}"
>
<view class="van-ellipsis">
{{ computed.displayTitle(item) }}
</view>
</view>
</view>
<slot />
</view>
/* eslint-disable */
function displayTitle(item) {
if (item.title) {
return item.title;
}
var match = item.options.filter(function(option) {
return option.value === item.value;
});
var displayTitle = match.length ? match[0].text : '';
return displayTitle;
}
module.exports = {
displayTitle: displayTitle
};
@import '../common/index.wxss';.van-dropdown-menu{display:-webkit-flex;display:flex;-webkit-user-select:none;user-select:none;height:50px;height:var(--dropdown-menu-height,50px);background-color:#fff;background-color:var(--dropdown-menu-background-color,#fff)}.van-dropdown-menu__item{display:-webkit-flex;display:flex;-webkit-flex:1;flex:1;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;min-width:0}.van-dropdown-menu__item:active{opacity:.7}.van-dropdown-menu__item--disabled:active{opacity:1}.van-dropdown-menu__item--disabled .van-dropdown-menu__title{color:#969799;color:var(--dropdown-menu-title-disabled-text-color,#969799)}.van-dropdown-menu__title{position:relative;box-sizing:border-box;max-width:100%;padding:0 8px;padding:var(--dropdown-menu-title-padding,0 8px);color:#323233;color:var(--dropdown-menu-title-text-color,#323233);font-size:15px;font-size:var(--dropdown-menu-title-font-size,15px);line-height:18px;line-height:var(--dropdown-menu-title-line-height,18px)}.van-dropdown-menu__title:after{position:absolute;top:50%;right:-4px;margin-top:-5px;border-color:transparent transparent currentcolor currentcolor;border-style:solid;border-width:3px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:.8;content:""}.van-dropdown-menu__title--active{color:#1989fa;color:var(--dropdown-menu-title-active-text-color,#1989fa)}.van-dropdown-menu__title--down:after{margin-top:-1px;-webkit-transform:rotate(135deg);transform:rotate(135deg)}
\ No newline at end of file
import { VantComponent } from '../common/component';
import { getSystemInfoSync } from '../common/utils';
VantComponent({
field: true,
classes: ['input-class', 'right-icon-class'],
props: {
size: String,
icon: String,
label: String,
error: Boolean,
fixed: Boolean,
focus: Boolean,
center: Boolean,
isLink: Boolean,
leftIcon: String,
rightIcon: String,
disabled: Boolean,
autosize: Boolean,
readonly: Boolean,
required: Boolean,
password: Boolean,
iconClass: String,
clearable: Boolean,
clickable: Boolean,
inputAlign: String,
placeholder: String,
customStyle: String,
confirmType: String,
confirmHold: Boolean,
holdKeyboard: Boolean,
errorMessage: String,
arrowDirection: String,
placeholderStyle: String,
errorMessageAlign: String,
selectionEnd: {
type: Number,
value: -1
},
selectionStart: {
type: Number,
value: -1
},
showConfirmBar: {
type: Boolean,
value: true
},
adjustPosition: {
type: Boolean,
value: true
},
cursorSpacing: {
type: Number,
value: 50
},
maxlength: {
type: Number,
value: -1
},
type: {
type: String,
value: 'text'
},
border: {
type: Boolean,
value: true
},
titleWidth: {
type: String,
value: '90px'
}
},
data: {
focused: false,
system: getSystemInfoSync().system.split(' ').shift().toLowerCase()
},
methods: {
onInput(event) {
const { value = '' } = event.detail || {};
this.setData({ value });
wx.nextTick(() => {
this.emitChange(value);
});
},
onFocus(event) {
this.setData({ focused: true });
this.$emit('focus', event.detail);
},
onBlur(event) {
this.setData({ focused: false });
this.$emit('blur', event.detail);
},
onClickIcon() {
this.$emit('click-icon');
},
onClear() {
this.setData({ value: '' });
wx.nextTick(() => {
this.emitChange('');
this.$emit('clear', '');
});
},
onConfirm() {
this.$emit('confirm', this.data.value);
},
emitChange(value) {
this.$emit('input', value);
this.$emit('change', value);
},
noop() { }
}
});
{
"component": true,
"usingComponents": {
"van-cell": "../cell/index",
"van-icon": "../icon/index"
}
}
\ No newline at end of file
<wxs src="../wxs/utils.wxs" module="utils" />
<van-cell
size="{{ size }}"
icon="{{ leftIcon }}"
title="{{ label }}"
center="{{ center }}"
border="{{ border }}"
is-link="{{ isLink }}"
required="{{ required }}"
clickable="{{ clickable }}"
title-width="{{ titleWidth }}"
custom-style="{{ customStyle }}"
arrow-direction="{{ arrowDirection }}"
custom-class="van-field"
>
<slot name="left-icon" slot="icon" />
<slot name="label" slot="title" />
<view class="{{ utils.bem('field__body', [type, system]) }}">
<textarea
wx:if="{{ type === 'textarea' }}"
class="input-class {{ utils.bem('field__input', [inputAlign, type, { disabled, error }]) }}"
fixed="{{ fixed }}"
focus="{{ focus }}"
value="{{ value }}"
disabled="{{ disabled || readonly }}"
maxlength="{{ maxlength }}"
placeholder="{{ placeholder }}"
placeholder-style="{{ placeholderStyle }}"
placeholder-class="{{ utils.bem('field__placeholder', { error }) }}"
auto-height="{{ autosize }}"
cursor-spacing="{{ cursorSpacing }}"
adjust-position="{{ adjustPosition }}"
show-confirm-bar="{{ showConfirmBar }}"
hold-keyboard="{{ holdKeyboard }}"
selection-end="{{ selectionEnd }}"
selection-start="{{ selectionStart }}"
bindinput="onInput"
bind:blur="onBlur"
bind:focus="onFocus"
bind:confirm="onConfirm"
>
</textarea>
<input
wx:else
class="input-class {{ utils.bem('field__input', [inputAlign, { disabled, error }]) }}"
type="{{ type }}"
focus="{{ focus }}"
value="{{ value }}"
disabled="{{ disabled || readonly }}"
maxlength="{{ maxlength }}"
placeholder="{{ placeholder }}"
placeholder-style="{{ placeholderStyle }}"
placeholder-class="{{ utils.bem('field__placeholder', { error }) }}"
confirm-type="{{ confirmType }}"
confirm-hold="{{ confirmHold }}"
hold-keyboard="{{ holdKeyboard }}"
cursor-spacing="{{ cursorSpacing }}"
adjust-position="{{ adjustPosition }}"
selection-end="{{ selectionEnd }}"
selection-start="{{ selectionStart }}"
password="{{ password || type === 'password' }}"
bindinput="onInput"
bind:blur="onBlur"
bind:focus="onFocus"
bind:confirm="onConfirm"
/>
<van-icon
wx:if="{{ clearable && focused && value && !readonly }}"
size="16px"
name="clear"
class="van-field__clear-root van-field__icon-root"
catch:touchstart="onClear"
/>
<view class="van-field__icon-container" bind:tap="onClickIcon">
<van-icon
wx:if="{{ rightIcon || icon }}"
size="16px"
name="{{ rightIcon || icon }}"
class="van-field__icon-root {{ iconClass }}"
custom-class="right-icon-class"
/>
<slot name="right-icon" />
<slot name="icon" />
</view>
<view class="van-field__button">
<slot name="button" />
</view>
</view>
<view wx:if="{{ errorMessage }}" class="van-field__error-message {{ utils.bem('field__error', [errorMessageAlign, { disabled, error }]) }}">
{{ errorMessage }}
</view>
</van-cell>
@import '../common/index.wxss';.van-field__body{display:-webkit-flex;display:flex;-webkit-align-items:center;align-items:center}.van-field__body--textarea{line-height:1.2em;min-height:24px;min-height:var(--cell-line-height,24px)}.van-field__body--textarea.van-field__body--ios{margin-top:-4.5px}.van-field__input{position:relative;display:block;box-sizing:border-box;width:100%;margin:0;padding:0;line-height:inherit;text-align:left;background-color:initial;border:0;resize:none;color:#323233;color:var(--field-input-text-color,#323233);height:24px;height:var(--cell-line-height,24px);min-height:24px;min-height:var(--cell-line-height,24px)}.van-field__input--textarea{height:18px;height:var(--field-text-area-min-height,18px);min-height:18px;min-height:var(--field-text-area-min-height,18px)}.van-field__input--error{color:#ee0a24;color:var(--field-input-error-text-color,#ee0a24)}.van-field__input--disabled{background-color:initial;opacity:1;color:#969799;color:var(--field-input-disabled-text-color,#969799)}.van-field__input--center{text-align:center}.van-field__input--right{text-align:right}.van-field__placeholder{position:absolute;top:0;right:0;left:0;pointer-events:none;color:#969799;color:var(--field-placeholder-text-color,#969799)}.van-field__placeholder--error{color:#ee0a24;color:var(--field-error-message-color,#ee0a24)}.van-field__icon-root{display:-webkit-flex;display:flex;-webkit-align-items:center;align-items:center;min-height:24px;min-height:var(--cell-line-height,24px)}.van-field__clear-root,.van-field__icon-container{line-height:inherit;vertical-align:middle;padding:0 8px;padding:0 var(--padding-xs,8px);margin-right:-8px;margin-right:-var(--padding-xs,8px)}.van-field__button,.van-field__clear-root,.van-field__icon-container{-webkit-flex-shrink:0;flex-shrink:0}.van-field__clear-root{color:#c8c9cc;color:var(--field-clear-icon-color,#c8c9cc)}.van-field__icon-container{color:#969799;color:var(--field-icon-container-color,#969799)}.van-field__icon-container:empty{display:none}.van-field__button{padding-left:8px;padding-left:var(--padding-xs,8px)}.van-field__button:empty{display:none}.van-field__error-message{text-align:left;font-size:12px;font-size:var(--field-error-message-text-font-size,12px);color:#ee0a24;color:var(--field-error-message-color,#ee0a24)}.van-field__error-message--center{text-align:center}.van-field__error-message--right{text-align:right}
\ No newline at end of file
import { VantComponent } from '../common/component';
VantComponent({
props: {
dot: Boolean,
info: null,
size: null,
color: String,
customStyle: String,
classPrefix: {
type: String,
value: 'van-icon'
},
name: {
type: String,
observer(val) {
this.setData({
isImageName: val.indexOf('/') !== -1
});
}
}
},
methods: {
onClick() {
this.$emit('click');
}
}
});
{
"component": true,
"usingComponents": {
"van-info": "../info/index"
}
}
<wxs src="../wxs/utils.wxs" module="utils" />
<view
class="custom-class {{ classPrefix }} {{ isImageName ? 'van-icon--image' : classPrefix + '-' + name }}"
style="color: {{ color }};font-size: {{ utils.addUnit(size) }};{{ customStyle }}"
bind:tap="onClick"
>
<van-info
wx:if="{{ info !== null || dot }}"
dot="{{ dot }}"
info="{{ info }}"
custom-class="van-icon__info"
/>
<image
wx:if="{{ isImageName }}"
src="{{ name }}"
mode="aspectFit"
class="van-icon__image"
/>
</view>
@import '../common/index.wxss';@font-face{font-weight:400;font-family:vant-icon;font-style:normal;font-display:auto;src:url(https://img.yzcdn.cn/vant/vant-icon-d3825a.woff2) format("woff2"),url(https://img.yzcdn.cn/vant/vant-icon-d3825a.woff) format("woff"),url(https://img.yzcdn.cn/vant/vant-icon-d3825a.ttf) format("truetype")}.van-icon{position:relative;font:normal normal normal 14px/1 vant-icon;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased}.van-icon,.van-icon:before{display:inline-block}.van-icon-add-o:before{content:"\F000"}.van-icon-add-square:before{content:"\F001"}.van-icon-add:before{content:"\F002"}.van-icon-after-sale:before{content:"\F003"}.van-icon-aim:before{content:"\F004"}.van-icon-alipay:before{content:"\F005"}.van-icon-apps-o:before{content:"\F006"}.van-icon-arrow-down:before{content:"\F007"}.van-icon-arrow-left:before{content:"\F008"}.van-icon-arrow-up:before{content:"\F009"}.van-icon-arrow:before{content:"\F00A"}.van-icon-ascending:before{content:"\F00B"}.van-icon-audio:before{content:"\F00C"}.van-icon-award-o:before{content:"\F00D"}.van-icon-award:before{content:"\F00E"}.van-icon-bag-o:before{content:"\F00F"}.van-icon-bag:before{content:"\F010"}.van-icon-balance-list-o:before{content:"\F011"}.van-icon-balance-list:before{content:"\F012"}.van-icon-balance-o:before{content:"\F013"}.van-icon-balance-pay:before{content:"\F014"}.van-icon-bar-chart-o:before{content:"\F015"}.van-icon-bars:before{content:"\F016"}.van-icon-bell:before{content:"\F017"}.van-icon-bill-o:before{content:"\F018"}.van-icon-bill:before{content:"\F019"}.van-icon-birthday-cake-o:before{content:"\F01A"}.van-icon-bookmark-o:before{content:"\F01B"}.van-icon-bookmark:before{content:"\F01C"}.van-icon-browsing-history-o:before{content:"\F01D"}.van-icon-browsing-history:before{content:"\F01E"}.van-icon-brush-o:before{content:"\F01F"}.van-icon-bulb-o:before{content:"\F020"}.van-icon-bullhorn-o:before{content:"\F021"}.van-icon-calender-o:before{content:"\F022"}.van-icon-card:before{content:"\F023"}.van-icon-cart-circle-o:before{content:"\F024"}.van-icon-cart-circle:before{content:"\F025"}.van-icon-cart-o:before{content:"\F026"}.van-icon-cart:before{content:"\F027"}.van-icon-cash-back-record:before{content:"\F028"}.van-icon-cash-on-deliver:before{content:"\F029"}.van-icon-cashier-o:before{content:"\F02A"}.van-icon-certificate:before{content:"\F02B"}.van-icon-chart-trending-o:before{content:"\F02C"}.van-icon-chat-o:before{content:"\F02D"}.van-icon-chat:before{content:"\F02E"}.van-icon-checked:before{content:"\F02F"}.van-icon-circle:before{content:"\F030"}.van-icon-clear:before{content:"\F031"}.van-icon-clock-o:before{content:"\F032"}.van-icon-clock:before{content:"\F033"}.van-icon-close:before{content:"\F034"}.van-icon-closed-eye:before{content:"\F035"}.van-icon-cluster-o:before{content:"\F036"}.van-icon-cluster:before{content:"\F037"}.van-icon-column:before{content:"\F038"}.van-icon-comment-circle-o:before{content:"\F039"}.van-icon-comment-circle:before{content:"\F03A"}.van-icon-comment-o:before{content:"\F03B"}.van-icon-comment:before{content:"\F03C"}.van-icon-completed:before{content:"\F03D"}.van-icon-contact:before{content:"\F03E"}.van-icon-coupon-o:before{content:"\F03F"}.van-icon-coupon:before{content:"\F040"}.van-icon-credit-pay:before{content:"\F041"}.van-icon-cross:before{content:"\F042"}.van-icon-debit-pay:before{content:"\F043"}.van-icon-delete:before{content:"\F044"}.van-icon-descending:before{content:"\F045"}.van-icon-description:before{content:"\F046"}.van-icon-desktop-o:before{content:"\F047"}.van-icon-diamond-o:before{content:"\F048"}.van-icon-diamond:before{content:"\F049"}.van-icon-discount:before{content:"\F04A"}.van-icon-down:before{content:"\F04B"}.van-icon-ecard-pay:before{content:"\F04C"}.van-icon-edit:before{content:"\F04D"}.van-icon-ellipsis:before{content:"\F04E"}.van-icon-empty:before{content:"\F04F"}.van-icon-envelop-o:before{content:"\F050"}.van-icon-exchange:before{content:"\F051"}.van-icon-expand-o:before{content:"\F052"}.van-icon-expand:before{content:"\F053"}.van-icon-eye-o:before{content:"\F054"}.van-icon-eye:before{content:"\F055"}.van-icon-fail:before{content:"\F056"}.van-icon-failure:before{content:"\F057"}.van-icon-filter-o:before{content:"\F058"}.van-icon-fire-o:before{content:"\F059"}.van-icon-fire:before{content:"\F05A"}.van-icon-flag-o:before{content:"\F05B"}.van-icon-flower-o:before{content:"\F05C"}.van-icon-free-postage:before{content:"\F05D"}.van-icon-friends-o:before{content:"\F05E"}.van-icon-friends:before{content:"\F05F"}.van-icon-gem-o:before{content:"\F060"}.van-icon-gem:before{content:"\F061"}.van-icon-gift-card-o:before{content:"\F062"}.van-icon-gift-card:before{content:"\F063"}.van-icon-gift-o:before{content:"\F064"}.van-icon-gift:before{content:"\F065"}.van-icon-gold-coin-o:before{content:"\F066"}.van-icon-gold-coin:before{content:"\F067"}.van-icon-good-job-o:before{content:"\F068"}.van-icon-good-job:before{content:"\F069"}.van-icon-goods-collect-o:before{content:"\F06A"}.van-icon-goods-collect:before{content:"\F06B"}.van-icon-graphic:before{content:"\F06C"}.van-icon-home-o:before{content:"\F06D"}.van-icon-hot-o:before{content:"\F06E"}.van-icon-hot-sale-o:before{content:"\F06F"}.van-icon-hot-sale:before{content:"\F070"}.van-icon-hot:before{content:"\F071"}.van-icon-hotel-o:before{content:"\F072"}.van-icon-idcard:before{content:"\F073"}.van-icon-info-o:before{content:"\F074"}.van-icon-info:before{content:"\F075"}.van-icon-invition:before{content:"\F076"}.van-icon-label-o:before{content:"\F077"}.van-icon-label:before{content:"\F078"}.van-icon-like-o:before{content:"\F079"}.van-icon-like:before{content:"\F07A"}.van-icon-live:before{content:"\F07B"}.van-icon-location-o:before{content:"\F07C"}.van-icon-location:before{content:"\F07D"}.van-icon-lock:before{content:"\F07E"}.van-icon-logistics:before{content:"\F07F"}.van-icon-manager-o:before{content:"\F080"}.van-icon-manager:before{content:"\F081"}.van-icon-map-marked:before{content:"\F082"}.van-icon-medal-o:before{content:"\F083"}.van-icon-medal:before{content:"\F084"}.van-icon-more-o:before{content:"\F085"}.van-icon-more:before{content:"\F086"}.van-icon-music-o:before{content:"\F087"}.van-icon-music:before{content:"\F088"}.van-icon-new-arrival-o:before{content:"\F089"}.van-icon-new-arrival:before{content:"\F08A"}.van-icon-new-o:before{content:"\F08B"}.van-icon-new:before{content:"\F08C"}.van-icon-newspaper-o:before{content:"\F08D"}.van-icon-notes-o:before{content:"\F08E"}.van-icon-orders-o:before{content:"\F08F"}.van-icon-other-pay:before{content:"\F090"}.van-icon-paid:before{content:"\F091"}.van-icon-passed:before{content:"\F092"}.van-icon-pause-circle-o:before{content:"\F093"}.van-icon-pause-circle:before{content:"\F094"}.van-icon-pause:before{content:"\F095"}.van-icon-peer-pay:before{content:"\F096"}.van-icon-pending-payment:before{content:"\F097"}.van-icon-phone-circle-o:before{content:"\F098"}.van-icon-phone-circle:before{content:"\F099"}.van-icon-phone-o:before{content:"\F09A"}.van-icon-phone:before{content:"\F09B"}.van-icon-photo-o:before{content:"\F09C"}.van-icon-photo:before{content:"\F09D"}.van-icon-photograph:before{content:"\F09E"}.van-icon-play-circle-o:before{content:"\F09F"}.van-icon-play-circle:before{content:"\F0A0"}.van-icon-play:before{content:"\F0A1"}.van-icon-plus:before{content:"\F0A2"}.van-icon-point-gift-o:before{content:"\F0A3"}.van-icon-point-gift:before{content:"\F0A4"}.van-icon-points:before{content:"\F0A5"}.van-icon-printer:before{content:"\F0A6"}.van-icon-qr-invalid:before{content:"\F0A7"}.van-icon-qr:before{content:"\F0A8"}.van-icon-question-o:before{content:"\F0A9"}.van-icon-question:before{content:"\F0AA"}.van-icon-records:before{content:"\F0AB"}.van-icon-refund-o:before{content:"\F0AC"}.van-icon-replay:before{content:"\F0AD"}.van-icon-scan:before{content:"\F0AE"}.van-icon-search:before{content:"\F0AF"}.van-icon-send-gift-o:before{content:"\F0B0"}.van-icon-send-gift:before{content:"\F0B1"}.van-icon-service-o:before{content:"\F0B2"}.van-icon-service:before{content:"\F0B3"}.van-icon-setting-o:before{content:"\F0B4"}.van-icon-setting:before{content:"\F0B5"}.van-icon-share:before{content:"\F0B6"}.van-icon-shop-collect-o:before{content:"\F0B7"}.van-icon-shop-collect:before{content:"\F0B8"}.van-icon-shop-o:before{content:"\F0B9"}.van-icon-shop:before{content:"\F0BA"}.van-icon-shopping-cart-o:before{content:"\F0BB"}.van-icon-shopping-cart:before{content:"\F0BC"}.van-icon-shrink:before{content:"\F0BD"}.van-icon-sign:before{content:"\F0BE"}.van-icon-smile-comment-o:before{content:"\F0BF"}.van-icon-smile-comment:before{content:"\F0C0"}.van-icon-smile-o:before{content:"\F0C1"}.van-icon-smile:before{content:"\F0C2"}.van-icon-star-o:before{content:"\F0C3"}.van-icon-star:before{content:"\F0C4"}.van-icon-stop-circle-o:before{content:"\F0C5"}.van-icon-stop-circle:before{content:"\F0C6"}.van-icon-stop:before{content:"\F0C7"}.van-icon-success:before{content:"\F0C8"}.van-icon-thumb-circle-o:before{content:"\F0C9"}.van-icon-thumb-circle:before{content:"\F0CA"}.van-icon-todo-list-o:before{content:"\F0CB"}.van-icon-todo-list:before{content:"\F0CC"}.van-icon-tosend:before{content:"\F0CD"}.van-icon-tv-o:before{content:"\F0CE"}.van-icon-umbrella-circle:before{content:"\F0CF"}.van-icon-underway-o:before{content:"\F0D0"}.van-icon-underway:before{content:"\F0D1"}.van-icon-upgrade:before{content:"\F0D2"}.van-icon-user-circle-o:before{content:"\F0D3"}.van-icon-user-o:before{content:"\F0D4"}.van-icon-video-o:before{content:"\F0D5"}.van-icon-video:before{content:"\F0D6"}.van-icon-vip-card-o:before{content:"\F0D7"}.van-icon-vip-card:before{content:"\F0D8"}.van-icon-volume-o:before{content:"\F0D9"}.van-icon-volume:before{content:"\F0DA"}.van-icon-wap-home-o:before{content:"\F0DB"}.van-icon-wap-home:before{content:"\F0DC"}.van-icon-wap-nav:before{content:"\F0DD"}.van-icon-warn-o:before{content:"\F0DE"}.van-icon-warning-o:before{content:"\F0DF"}.van-icon-warning:before{content:"\F0E0"}.van-icon-weapp-nav:before{content:"\F0E1"}.van-icon-wechat:before{content:"\F0E2"}.van-icon-youzan-shield:before{content:"\F0E3"}:host{display:-webkit-inline-flex;display:inline-flex;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center}.van-icon--image{width:1em;height:1em}.van-icon__image{width:100%;height:100%}.van-icon__info{z-index:1}
\ No newline at end of file
import { addUnit, isDef } from '../common/utils';
import { VantComponent } from '../common/component';
import { button } from '../mixins/button';
import { openType } from '../mixins/open-type';
const FIT_MODE_MAP = {
none: 'center',
fill: 'scaleToFill',
cover: 'aspectFill',
contain: 'aspectFit'
};
VantComponent({
mixins: [button, openType],
classes: ['custom-class', 'loading-class', 'error-class', 'image-class'],
props: {
src: {
type: String,
observer() {
this.setData({
error: false,
loading: true
});
}
},
round: Boolean,
width: {
type: null,
observer: 'setStyle'
},
height: {
type: null,
observer: 'setStyle'
},
radius: null,
lazyLoad: Boolean,
useErrorSlot: Boolean,
useLoadingSlot: Boolean,
showMenuByLongpress: Boolean,
fit: {
type: String,
value: 'fill',
observer: 'setMode'
},
showError: {
type: Boolean,
value: true
},
showLoading: {
type: Boolean,
value: true
}
},
data: {
error: false,
loading: true,
viewStyle: '',
},
mounted() {
this.setMode();
this.setStyle();
},
methods: {
setMode() {
this.setData({
mode: FIT_MODE_MAP[this.data.fit],
});
},
setStyle() {
const { width, height, radius } = this.data;
let style = '';
if (isDef(width)) {
style += `width: ${addUnit(width)};`;
}
if (isDef(height)) {
style += `height: ${addUnit(height)};`;
}
if (isDef(radius)) {
style += 'overflow: hidden;';
style += `border-radius: ${addUnit(radius)};`;
}
this.setData({ viewStyle: style });
},
onLoad(event) {
this.setData({
loading: false
});
this.$emit('load', event.detail);
},
onError(event) {
this.setData({
loading: false,
error: true
});
this.$emit('error', event.detail);
},
onClick(event) {
this.$emit('click', event.detail);
}
}
});
{
"component": true,
"usingComponents": {
"van-icon": "../icon/index",
"van-loading": "../loading/index"
}
}
<wxs src="../wxs/utils.wxs" module="utils" />
<view
style="{{ viewStyle }}"
class="custom-class {{ utils.bem('image', { round })}}"
bind:tap="onClick"
>
<image
wx:if="{{ !error }}"
src="{{ src }}"
mode="{{ mode }}"
lazy-load="{{ lazyLoad }}"
class="image-class van-image__img"
show-menu-by-longpress="{{ showMenuByLongpress }}"
bind:load="onLoad"
bind:error="onError"
/>
<view
wx:if="{{ loading && showLoading }}"
class="loading-class van-image__loading"
>
<slot wx:if="{{ useLoadingSlot }}" name="loading" />
<van-icon wx:else name="photo-o" size="22" />
</view>
<view
wx:if="{{ error && showError }}"
class="error-class van-image__error"
>
<slot wx:if="{{ useErrorSlot }}" name="error" />
<van-icon wx:else name="warning-o" size="22" />
</view>
</view>
@import '../common/index.wxss';.van-image{position:relative;display:inline-block}.van-image--round{overflow:hidden;border-radius:50%}.van-image--round .van-image__img{border-radius:inherit}.van-image__error,.van-image__img,.van-image__loading{display:block;width:100%;height:100%}.van-image__error,.van-image__loading{position:absolute;top:0;left:0;display:-webkit-flex;display:flex;-webkit-flex-direction:column;flex-direction:column;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;color:#969799;color:var(--image-placeholder-text-color,#969799);font-size:14px;font-size:var(--image-placeholder-font-size,14px);background-color:#f7f8fa;background-color:var(--image-placeholder-background-color,#f7f8fa)}
\ No newline at end of file
import { VantComponent } from '../common/component';
VantComponent({
props: {
dot: Boolean,
info: null,
customStyle: String
}
});
<wxs src="../wxs/utils.wxs" module="utils" />
<view
wx:if="{{ info !== null && info !== '' || dot }}"
class="custom-class van-info {{ utils.bem('info', { dot }) }}"
style="{{ customStyle }}"
>{{ dot ? '' : info }}</view>
@import '../common/index.wxss';.van-info{position:absolute;top:0;right:0;box-sizing:border-box;white-space:nowrap;text-align:center;-webkit-transform:translate(50%,-50%);transform:translate(50%,-50%);-webkit-transform-origin:100%;transform-origin:100%;min-width:16px;min-width:var(--info-size,16px);padding:0 3px;padding:var(--info-padding,0 3px);color:#fff;color:var(--info-color,#fff);font-weight:500;font-weight:var(--info-font-weight,500);font-size:12px;font-size:var(--info-font-size,12px);font-family:PingFang SC,Helvetica Neue,Arial,sans-serif;font-family:var(--info-font-family,PingFang SC,Helvetica Neue,Arial,sans-serif);line-height:14px;line-height:calc(var(--info-size, 16px) - var(--info-border-width, 1px)*2);background-color:#ee0a24;background-color:var(--info-background-color,#ee0a24);border:1px solid #fff;border:var(--info-border-width,1px) solid var(--white,#fff);border-radius:16px;border-radius:var(--info-size,16px)}.van-info--dot{min-width:0;border-radius:100%;width:8px;width:var(--info-dot-size,8px);height:8px;height:var(--info-dot-size,8px);background-color:#ee0a24;background-color:var(--info-dot-color,#ee0a24)}
\ No newline at end of file
import { VantComponent } from '../common/component';
VantComponent({
props: {
color: String,
vertical: Boolean,
type: {
type: String,
value: 'circular'
},
size: String,
textSize: String
},
data: {
array12: Array.from({ length: 12 }),
},
});
{
"component": true
}
\ No newline at end of file
<wxs src="../wxs/utils.wxs" module="utils" />
<view class="custom-class van-loading {{ vertical ? 'van-loading--vertical' : '' }}">
<view
class="van-loading__spinner van-loading__spinner--{{ type }}"
style="color: {{ color }}; width: {{ utils.addUnit(size) }}; height: {{ utils.addUnit(size) }}"
>
<view
wx:if="{{ type === 'spinner' }}"
wx:for="{{ array12 }}"
wx:key="index"
class="van-loading__dot"
/>
</view>
<view class="van-loading__text" style="font-size: {{ utils.addUnit(textSize) }};">
<slot />
</view>
</view>
@import '../common/index.wxss';:host{font-size:0;line-height:1}.van-loading{display:-webkit-inline-flex;display:inline-flex;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;color:#c8c9cc;color:var(--loading-spinner-color,#c8c9cc)}.van-loading__spinner{position:relative;box-sizing:border-box;width:30px;width:var(--loading-spinner-size,30px);max-width:100%;max-height:100%;height:30px;height:var(--loading-spinner-size,30px);-webkit-animation:van-rotate .8s linear infinite;animation:van-rotate .8s linear infinite;-webkit-animation:van-rotate var(--loading-spinner-animation-duration,.8s) linear infinite;animation:van-rotate var(--loading-spinner-animation-duration,.8s) linear infinite}.van-loading__spinner--spinner{-webkit-animation-timing-function:steps(12);animation-timing-function:steps(12)}.van-loading__spinner--circular{border:1px solid transparent;border-top-color:initial;border-radius:100%}.van-loading__text{margin-left:8px;margin-left:var(--padding-xs,8px);color:#969799;color:var(--loading-text-color,#969799);font-size:14px;font-size:var(--loading-text-font-size,14px);line-height:20px;line-height:var(--loading-text-line-height,20px)}.van-loading__text:empty{display:none}.van-loading--vertical{-webkit-flex-direction:column;flex-direction:column}.van-loading--vertical .van-loading__text{margin:8px 0 0;margin:var(--padding-xs,8px) 0 0}.van-loading__dot{position:absolute;top:0;left:0;width:100%;height:100%}.van-loading__dot:before{display:block;width:2px;height:25%;margin:0 auto;background-color:currentColor;border-radius:40%;content:" "}.van-loading__dot:first-of-type{-webkit-transform:rotate(30deg);transform:rotate(30deg);opacity:1}.van-loading__dot:nth-of-type(2){-webkit-transform:rotate(60deg);transform:rotate(60deg);opacity:.9375}.van-loading__dot:nth-of-type(3){-webkit-transform:rotate(90deg);transform:rotate(90deg);opacity:.875}.van-loading__dot:nth-of-type(4){-webkit-transform:rotate(120deg);transform:rotate(120deg);opacity:.8125}.van-loading__dot:nth-of-type(5){-webkit-transform:rotate(150deg);transform:rotate(150deg);opacity:.75}.van-loading__dot:nth-of-type(6){-webkit-transform:rotate(180deg);transform:rotate(180deg);opacity:.6875}.van-loading__dot:nth-of-type(7){-webkit-transform:rotate(210deg);transform:rotate(210deg);opacity:.625}.van-loading__dot:nth-of-type(8){-webkit-transform:rotate(240deg);transform:rotate(240deg);opacity:.5625}.van-loading__dot:nth-of-type(9){-webkit-transform:rotate(270deg);transform:rotate(270deg);opacity:.5}.van-loading__dot:nth-of-type(10){-webkit-transform:rotate(300deg);transform:rotate(300deg);opacity:.4375}.van-loading__dot:nth-of-type(11){-webkit-transform:rotate(330deg);transform:rotate(330deg);opacity:.375}.van-loading__dot:nth-of-type(12){-webkit-transform:rotate(1turn);transform:rotate(1turn);opacity:.3125}@-webkit-keyframes van-rotate{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes van-rotate{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}
\ No newline at end of file
export declare const basic: string;
export const basic = Behavior({
methods: {
$emit(...args) {
this.triggerEvent(...args);
},
set(data, callback) {
this.setData(data, callback);
return new Promise(resolve => wx.nextTick(resolve));
},
getRect(selector, all) {
return new Promise(resolve => {
wx.createSelectorQuery()
.in(this)[all ? 'selectAll' : 'select'](selector)
.boundingClientRect(rect => {
if (all && Array.isArray(rect) && rect.length) {
resolve(rect);
}
if (!all && rect) {
resolve(rect);
}
})
.exec();
});
}
}
});
export declare const button: string;
export const button = Behavior({
externalClasses: ['hover-class'],
properties: {
id: String,
lang: {
type: String,
value: 'en'
},
businessId: Number,
sessionFrom: String,
sendMessageTitle: String,
sendMessagePath: String,
sendMessageImg: String,
showMessageCard: Boolean,
appParameter: String,
ariaLabel: String
}
});
export declare const link: string;
export const link = Behavior({
properties: {
url: String,
linkType: {
type: String,
value: 'navigateTo'
}
},
methods: {
jumpLink(urlKey = 'url') {
const url = this.data[urlKey];
if (url) {
wx[this.data.linkType]({ url });
}
}
}
});
export declare const openType: string;
export const openType = Behavior({
properties: {
openType: String
},
methods: {
bindGetUserInfo(event) {
this.$emit('getuserinfo', event.detail);
},
bindContact(event) {
this.$emit('contact', event.detail);
},
bindGetPhoneNumber(event) {
this.$emit('getphonenumber', event.detail);
},
bindError(event) {
this.$emit('error', event.detail);
},
bindLaunchApp(event) {
this.$emit('launchapp', event.detail);
},
bindOpenSetting(event) {
this.$emit('opensetting', event.detail);
},
}
});
export declare const touch: string;
const MIN_DISTANCE = 10;
function getDirection(x, y) {
if (x > y && x > MIN_DISTANCE) {
return 'horizontal';
}
if (y > x && y > MIN_DISTANCE) {
return 'vertical';
}
return '';
}
export const touch = Behavior({
methods: {
resetTouchStatus() {
this.direction = '';
this.deltaX = 0;
this.deltaY = 0;
this.offsetX = 0;
this.offsetY = 0;
},
touchStart(event) {
this.resetTouchStatus();
const touch = event.touches[0];
this.startX = touch.clientX;
this.startY = touch.clientY;
},
touchMove(event) {
const touch = event.touches[0];
this.deltaX = touch.clientX - this.startX;
this.deltaY = touch.clientY - this.startY;
this.offsetX = Math.abs(this.deltaX);
this.offsetY = Math.abs(this.deltaY);
this.direction = this.direction || getDirection(this.offsetX, this.offsetY);
}
}
});
export declare const transition: (showDefaultValue: boolean) => any;
import { isObj } from '../common/utils';
const getClassNames = (name) => ({
enter: `van-${name}-enter van-${name}-enter-active enter-class enter-active-class`,
'enter-to': `van-${name}-enter-to van-${name}-enter-active enter-to-class enter-active-class`,
leave: `van-${name}-leave van-${name}-leave-active leave-class leave-active-class`,
'leave-to': `van-${name}-leave-to van-${name}-leave-active leave-to-class leave-active-class`
});
const nextTick = () => new Promise(resolve => setTimeout(resolve, 1000 / 30));
export const transition = function (showDefaultValue) {
return Behavior({
properties: {
customStyle: String,
// @ts-ignore
show: {
type: Boolean,
value: showDefaultValue,
observer: 'observeShow'
},
// @ts-ignore
duration: {
type: null,
value: 300,
observer: 'observeDuration'
},
name: {
type: String,
value: 'fade'
}
},
data: {
type: '',
inited: false,
display: false
},
methods: {
observeShow(value, old) {
if (value === old) {
return;
}
value ? this.enter() : this.leave();
},
enter() {
const { duration, name } = this.data;
const classNames = getClassNames(name);
const currentDuration = isObj(duration) ? duration.enter : duration;
this.status = 'enter';
this.$emit('before-enter');
Promise.resolve()
.then(nextTick)
.then(() => {
this.checkStatus('enter');
this.$emit('enter');
this.setData({
inited: true,
display: true,
classes: classNames.enter,
currentDuration
});
})
.then(nextTick)
.then(() => {
this.checkStatus('enter');
this.transitionEnded = false;
this.setData({
classes: classNames['enter-to']
});
})
.catch(() => { });
},
leave() {
if (!this.data.display) {
return;
}
const { duration, name } = this.data;
const classNames = getClassNames(name);
const currentDuration = isObj(duration) ? duration.leave : duration;
this.status = 'leave';
this.$emit('before-leave');
Promise.resolve()
.then(nextTick)
.then(() => {
this.checkStatus('leave');
this.$emit('leave');
this.setData({
classes: classNames.leave,
currentDuration
});
})
.then(nextTick)
.then(() => {
this.checkStatus('leave');
this.transitionEnded = false;
setTimeout(() => this.onTransitionEnd(), currentDuration);
this.setData({
classes: classNames['leave-to']
});
})
.catch(() => { });
},
checkStatus(status) {
if (status !== this.status) {
throw new Error(`incongruent status: ${status}`);
}
},
onTransitionEnd() {
if (this.transitionEnded) {
return;
}
this.transitionEnded = true;
this.$emit(`after-${this.status}`);
const { show, display } = this.data;
if (!show && display) {
this.setData({ display: false });
}
}
}
});
};
import { VantComponent } from '../common/component';
VantComponent({
props: {
show: Boolean,
customStyle: String,
duration: {
type: null,
value: 300
},
zIndex: {
type: Number,
value: 1
}
},
methods: {
onClick() {
this.$emit('click');
},
// for prevent touchmove
noop() { }
}
});
{
"component": true,
"usingComponents": {
"van-transition": "../transition/index"
}
}
<van-transition
show="{{ show }}"
custom-class="van-overlay"
custom-style="z-index: {{ zIndex }}; {{ customStyle }}"
duration="{{ duration }}"
bind:tap="onClick"
catch:touchmove="noop"
>
<slot></slot>
</van-transition>
@import '../common/index.wxss';.van-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background-color:rgba(0,0,0,.7);background-color:var(--overlay-background-color,rgba(0,0,0,.7))}
\ No newline at end of file
import { VantComponent } from '../common/component';
import { isObj, range } from '../common/utils';
const DEFAULT_DURATION = 200;
VantComponent({
classes: ['active-class'],
props: {
valueKey: String,
className: String,
itemHeight: Number,
visibleItemCount: Number,
initialOptions: {
type: Array,
value: []
},
defaultIndex: {
type: Number,
value: 0,
observer(value) {
this.setIndex(value);
}
}
},
data: {
startY: 0,
offset: 0,
duration: 0,
startOffset: 0,
options: [],
currentIndex: 0
},
created() {
const { defaultIndex, initialOptions } = this.data;
this.set({
currentIndex: defaultIndex,
options: initialOptions
}).then(() => {
this.setIndex(defaultIndex);
});
},
methods: {
getCount() {
return this.data.options.length;
},
onTouchStart(event) {
this.setData({
startY: event.touches[0].clientY,
startOffset: this.data.offset,
duration: 0
});
},
onTouchMove(event) {
const { data } = this;
const deltaY = event.touches[0].clientY - data.startY;
this.setData({
offset: range(data.startOffset + deltaY, -(this.getCount() * data.itemHeight), data.itemHeight)
});
},
onTouchEnd() {
const { data } = this;
if (data.offset !== data.startOffset) {
this.setData({ duration: DEFAULT_DURATION });
const index = range(Math.round(-data.offset / data.itemHeight), 0, this.getCount() - 1);
this.setIndex(index, true);
}
},
onClickItem(event) {
const { index } = event.currentTarget.dataset;
this.setIndex(index, true);
},
adjustIndex(index) {
const { data } = this;
const count = this.getCount();
index = range(index, 0, count);
for (let i = index; i < count; i++) {
if (!this.isDisabled(data.options[i]))
return i;
}
for (let i = index - 1; i >= 0; i--) {
if (!this.isDisabled(data.options[i]))
return i;
}
},
isDisabled(option) {
return isObj(option) && option.disabled;
},
getOptionText(option) {
const { data } = this;
return isObj(option) && data.valueKey in option
? option[data.valueKey]
: option;
},
setIndex(index, userAction) {
const { data } = this;
index = this.adjustIndex(index) || 0;
const offset = -index * data.itemHeight;
if (index !== data.currentIndex) {
return this.set({ offset, currentIndex: index }).then(() => {
userAction && this.$emit('change', index);
});
}
return this.set({ offset });
},
setValue(value) {
const { options } = this.data;
for (let i = 0; i < options.length; i++) {
if (this.getOptionText(options[i]) === value) {
return this.setIndex(i);
}
}
return Promise.resolve();
},
getValue() {
const { data } = this;
return data.options[data.currentIndex];
}
}
});
{
"component": true
}
\ No newline at end of file
<wxs src="./index.wxs" module="getOptionText" />
<view
class="van-picker-column custom-class"
style="height: {{ itemHeight * visibleItemCount }}px"
bind:touchstart="onTouchStart"
catch:touchmove="onTouchMove"
bind:touchend="onTouchEnd"
bind:touchcancel="onTouchEnd"
>
<view style="transition: transform {{ duration }}ms; line-height: {{ itemHeight }}px; transform: translate3d(0, {{ offset + (itemHeight * (visibleItemCount - 1)) / 2 }}px, 0)">
<view
wx:for="{{ options }}"
wx:for-item="option"
wx:key="index"
data-index="{{ index }}"
style="height: {{ itemHeight }}px"
class="van-ellipsis van-picker-column__item {{ option && option.disabled ? 'van-picker-column__item--disabled' : '' }} {{ index === currentIndex ? 'van-picker-column__item--selected active-class' : '' }}"
bindtap="onClickItem"
>{{ getOptionText(option, valueKey) }}</view>
</view>
</view>
function isObj(x) {
var type = typeof x;
return x !== null && (type === 'object' || type === 'function');
}
module.exports = function (option, valueKey) {
return isObj(option) && option[valueKey] != null ? option[valueKey] : option;
}
@import '../common/index.wxss';.van-picker-column{overflow:hidden;text-align:center;color:#000;color:var(--picker-option-text-color,#000);font-size:16px;font-size:var(--picker-option-font-size,16px)}.van-picker-column__item{padding:0 5px}.van-picker-column__item--selected{font-weight:500;font-weight:var(--font-weight-bold,500);color:#323233;color:var(--picker-option-selected-text-color,#323233)}.van-picker-column__item--disabled{opacity:.3;opacity:var(--picker-option-disabled-opacity,.3)}
\ No newline at end of file
import { VantComponent } from '../common/component';
import { pickerProps } from './shared';
VantComponent({
classes: ['active-class', 'toolbar-class', 'column-class'],
props: Object.assign(Object.assign({}, pickerProps), { valueKey: {
type: String,
value: 'text'
}, toolbarPosition: {
type: String,
value: 'top'
}, defaultIndex: {
type: Number,
value: 0
}, columns: {
type: Array,
value: [],
observer(columns = []) {
this.simple = columns.length && !columns[0].values;
this.children = this.selectAllComponents('.van-picker__column');
if (Array.isArray(this.children) && this.children.length) {
this.setColumns().catch(() => { });
}
}
} }),
beforeCreate() {
this.children = [];
},
methods: {
noop() { },
setColumns() {
const { data } = this;
const columns = this.simple ? [{ values: data.columns }] : data.columns;
const stack = columns.map((column, index) => this.setColumnValues(index, column.values));
return Promise.all(stack);
},
emit(event) {
const { type } = event.currentTarget.dataset;
if (this.simple) {
this.$emit(type, {
value: this.getColumnValue(0),
index: this.getColumnIndex(0)
});
}
else {
this.$emit(type, {
value: this.getValues(),
index: this.getIndexes()
});
}
},
onChange(event) {
if (this.simple) {
this.$emit('change', {
picker: this,
value: this.getColumnValue(0),
index: this.getColumnIndex(0)
});
}
else {
this.$emit('change', {
picker: this,
value: this.getValues(),
index: event.currentTarget.dataset.index
});
}
},
// get column instance by index
getColumn(index) {
return this.children[index];
},
// get column value by index
getColumnValue(index) {
const column = this.getColumn(index);
return column && column.getValue();
},
// set column value by index
setColumnValue(index, value) {
const column = this.getColumn(index);
if (column == null) {
return Promise.reject(new Error('setColumnValue: 对应列不存在'));
}
return column.setValue(value);
},
// get column option index by column index
getColumnIndex(columnIndex) {
return (this.getColumn(columnIndex) || {}).data.currentIndex;
},
// set column option index by column index
setColumnIndex(columnIndex, optionIndex) {
const column = this.getColumn(columnIndex);
if (column == null) {
return Promise.reject(new Error('setColumnIndex: 对应列不存在'));
}
return column.setIndex(optionIndex);
},
// get options of column by index
getColumnValues(index) {
return (this.children[index] || {}).data.options;
},
// set options of column by index
setColumnValues(index, options, needReset = true) {
const column = this.children[index];
if (column == null) {
return Promise.reject(new Error('setColumnValues: 对应列不存在'));
}
const isSame = JSON.stringify(column.data.options) === JSON.stringify(options);
if (isSame) {
return Promise.resolve();
}
return column.set({ options }).then(() => {
if (needReset) {
column.setIndex(0);
}
});
},
// get values of all columns
getValues() {
return this.children.map((child) => child.getValue());
},
// set values of all columns
setValues(values) {
const stack = values.map((value, index) => this.setColumnValue(index, value));
return Promise.all(stack);
},
// get indexes of all columns
getIndexes() {
return this.children.map((child) => child.data.currentIndex);
},
// set indexes of all columns
setIndexes(indexes) {
const stack = indexes.map((optionIndex, columnIndex) => this.setColumnIndex(columnIndex, optionIndex));
return Promise.all(stack);
}
}
});
{
"component": true,
"usingComponents": {
"picker-column": "../picker-column/index",
"loading": "../loading/index"
}
}
<import src="./toolbar" />
<view class="van-picker custom-class">
<template is="toolbar" wx:if="{{ toolbarPosition === 'top' }}" data="{{ showToolbar, cancelButtonText, title, confirmButtonText }}"></template>
<view wx:if="{{ loading }}" class="van-picker__loading">
<loading color="#1989fa"/>
</view>
<view
class="van-picker__columns"
style="height: {{ itemHeight * visibleItemCount }}px"
catch:touchmove="noop"
>
<picker-column
class="van-picker__column"
wx:for="{{ isSimple(columns) ? [columns] : columns }}"
wx:key="index"
data-index="{{ index }}"
custom-class="column-class"
value-key="{{ valueKey }}"
initial-options="{{ isSimple(columns) ? item : item.values }}"
default-index="{{ item.defaultIndex || defaultIndex }}"
item-height="{{ itemHeight }}"
visible-item-count="{{ visibleItemCount }}"
active-class="active-class"
bind:change="onChange"
/>
<view class="van-picker__mask" style="background-size: 100% {{ (itemHeight * visibleItemCount - itemHeight) / 2 }}px" />
<view
class="van-picker__frame van-hairline--top-bottom"
style="height: {{ itemHeight }}px"
/>
</view>
<template is="toolbar" wx:if="{{ toolbarPosition === 'bottom' }}" data="{{ showToolbar, cancelButtonText, title, confirmButtonText }}"></template>
</view>
<wxs module="isSimple">
function isSimple(columns) {
return columns.length && !columns[0].values;
}
module.exports = isSimple;
</wxs>
@import '../common/index.wxss';.van-picker{position:relative;overflow:hidden;-webkit-text-size-adjust:100%;-webkit-user-select:none;user-select:none;background-color:#fff;background-color:var(--picker-background-color,#fff)}.van-picker__toolbar{display:-webkit-flex;display:flex;-webkit-justify-content:space-between;justify-content:space-between;height:44px;height:var(--picker-toolbar-height,44px);line-height:44px;line-height:var(--picker-toolbar-height,44px)}.van-picker__cancel,.van-picker__confirm{padding:0 16px;padding:var(--picker-action-padding,0 16px);font-size:14px;font-size:var(--picker-action-font-size,14px);color:#1989fa;color:var(--picker-action-text-color,#1989fa)}.van-picker__cancel--hover,.van-picker__confirm--hover{background-color:#f2f3f5;background-color:var(--picker-action-active-color,#f2f3f5)}.van-picker__title{max-width:50%;text-align:center;font-weight:500;font-weight:var(--font-weight-bold,500);font-size:16px;font-size:var(--picker-option-font-size,16px)}.van-picker__columns{position:relative;display:-webkit-flex;display:flex}.van-picker__column{-webkit-flex:1 1;flex:1 1;width:0}.van-picker__loading{position:absolute;top:0;right:0;bottom:0;left:0;z-index:4;display:-webkit-flex;display:flex;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;background-color:hsla(0,0%,100%,.9);background-color:var(--picker-loading-mask-color,hsla(0,0%,100%,.9))}.van-picker__mask{position:absolute;top:0;left:0;z-index:2;width:100%;height:100%;background-image:linear-gradient(180deg,hsla(0,0%,100%,.9),hsla(0,0%,100%,.4)),linear-gradient(0deg,hsla(0,0%,100%,.9),hsla(0,0%,100%,.4));background-repeat:no-repeat;background-position:top,bottom;-webkit-backface-visibility:hidden;backface-visibility:hidden;pointer-events:none}.van-picker__frame,.van-picker__loading .van-loading{position:absolute;top:50%;left:0;z-index:1;width:100%;-webkit-transform:translateY(-50%);transform:translateY(-50%);pointer-events:none}
\ No newline at end of file
export declare const pickerProps: {
title: StringConstructor;
loading: BooleanConstructor;
showToolbar: BooleanConstructor;
cancelButtonText: {
type: StringConstructor;
value: string;
};
confirmButtonText: {
type: StringConstructor;
value: string;
};
visibleItemCount: {
type: NumberConstructor;
value: number;
};
itemHeight: {
type: NumberConstructor;
value: number;
};
};
export const pickerProps = {
title: String,
loading: Boolean,
showToolbar: Boolean,
cancelButtonText: {
type: String,
value: '取消'
},
confirmButtonText: {
type: String,
value: '确认'
},
visibleItemCount: {
type: Number,
value: 5
},
itemHeight: {
type: Number,
value: 44
}
};
<template name="toolbar">
<view
wx:if="{{ showToolbar }}"
class="van-picker__toolbar van-hairline--top-bottom toolbar-class"
>
<view
class="van-picker__cancel"
hover-class="van-picker__cancel--hover"
hover-stay-time="70"
data-type="cancel"
bindtap="emit"
>
{{ cancelButtonText }}
</view>
<view wx:if="{{ title }}" class="van-picker__title van-ellipsis">{{
title
}}</view>
<view
class="van-picker__confirm"
hover-class="van-picker__confirm--hover"
hover-stay-time="70"
data-type="confirm"
bindtap="emit"
>
{{ confirmButtonText }}
</view>
</view>
</template>
import { VantComponent } from '../common/component';
import { transition } from '../mixins/transition';
VantComponent({
classes: [
'enter-class',
'enter-active-class',
'enter-to-class',
'leave-class',
'leave-active-class',
'leave-to-class'
],
mixins: [transition(false)],
props: {
round: Boolean,
closeable: Boolean,
customStyle: String,
overlayStyle: String,
transition: {
type: String,
observer: 'observeClass'
},
zIndex: {
type: Number,
value: 100
},
overlay: {
type: Boolean,
value: true
},
closeIcon: {
type: String,
value: 'cross'
},
closeIconPosition: {
type: String,
value: 'top-right'
},
closeOnClickOverlay: {
type: Boolean,
value: true
},
position: {
type: String,
value: 'center',
observer: 'observeClass'
},
safeAreaInsetBottom: {
type: Boolean,
value: true
},
safeAreaInsetTop: {
type: Boolean,
value: false
}
},
created() {
this.observeClass();
},
methods: {
onClickCloseIcon() {
this.$emit('close');
},
onClickOverlay() {
this.$emit('click-overlay');
if (this.data.closeOnClickOverlay) {
this.$emit('close');
}
},
observeClass() {
const { transition, position } = this.data;
const updateData = {
name: transition || position
};
if (transition === 'none') {
updateData.duration = 0;
}
this.setData(updateData);
}
}
});
{
"component": true,
"usingComponents": {
"van-icon": "../icon/index",
"van-overlay": "../overlay/index"
}
}
<wxs src="../wxs/utils.wxs" module="utils" />
<van-overlay
wx:if="{{ overlay }}"
show="{{ show }}"
z-index="{{ zIndex }}"
custom-style="{{ overlayStyle }}"
duration="{{ duration }}"
bind:click="onClickOverlay"
/>
<view
wx:if="{{ inited }}"
class="custom-class {{ classes }} {{ utils.bem('popup', [position, { round, safe: safeAreaInsetBottom, safeTop: safeAreaInsetTop }]) }}"
style="z-index: {{ zIndex }}; -webkit-transition-duration:{{ currentDuration }}ms; transition-duration:{{ currentDuration }}ms; {{ display ? '' : 'display: none;' }};{{ customStyle }}"
bind:transitionend="onTransitionEnd"
>
<slot />
<van-icon
wx:if="{{ closeable }}"
name="{{ closeIcon }}"
class="van-popup__close-icon van-popup__close-icon--{{ closeIconPosition }}"
bind:tap="onClickCloseIcon"
/>
</view>
@import '../common/index.wxss';.van-popup{position:fixed;box-sizing:border-box;max-height:100%;overflow-y:auto;transition-timing-function:ease;-webkit-animation:ease both;animation:ease both;-webkit-overflow-scrolling:touch;background-color:#fff;background-color:var(--popup-background-color,#fff)}.van-popup--center{top:50%;left:50%;-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0)}.van-popup--center.van-popup--round{border-radius:20px;border-radius:var(--popup-round-border-radius,20px)}.van-popup--top{top:0;left:0;width:100%}.van-popup--top.van-popup--round{border-radius:0 0 20px 20px;border-radius:0 0 var(--popup-round-border-radius,20px) var(--popup-round-border-radius,20px)}.van-popup--right{top:50%;right:0;-webkit-transform:translate3d(0,-50%,0);transform:translate3d(0,-50%,0)}.van-popup--right.van-popup--round{border-radius:20px 0 0 20px;border-radius:var(--popup-round-border-radius,20px) 0 0 var(--popup-round-border-radius,20px)}.van-popup--bottom{bottom:0;left:0;width:100%}.van-popup--bottom.van-popup--round{border-radius:20px 20px 0 0;border-radius:var(--popup-round-border-radius,20px) var(--popup-round-border-radius,20px) 0 0}.van-popup--left{top:50%;left:0;-webkit-transform:translate3d(0,-50%,0);transform:translate3d(0,-50%,0)}.van-popup--left.van-popup--round{border-radius:0 20px 20px 0;border-radius:0 var(--popup-round-border-radius,20px) var(--popup-round-border-radius,20px) 0}.van-popup--bottom.van-popup--safe{padding-bottom:env(safe-area-inset-bottom)}.van-popup--safeTop{padding-top:env(safe-area-inset-top)}.van-popup__close-icon{position:absolute;z-index:1;z-index:var(--popup-close-icon-z-index,1);color:#969799;color:var(--popup-close-icon-color,#969799);font-size:18px;font-size:var(--popup-close-icon-size,18px)}.van-popup__close-icon--top-left{top:16px;top:var(--popup-close-icon-margin,16px);left:16px;left:var(--popup-close-icon-margin,16px)}.van-popup__close-icon--top-right{top:16px;top:var(--popup-close-icon-margin,16px);right:16px;right:var(--popup-close-icon-margin,16px)}.van-popup__close-icon--bottom-left{bottom:16px;bottom:var(--popup-close-icon-margin,16px);left:16px;left:var(--popup-close-icon-margin,16px)}.van-popup__close-icon--bottom-right{right:16px;right:var(--popup-close-icon-margin,16px);bottom:16px;bottom:var(--popup-close-icon-margin,16px)}.van-popup__close-icon:active{opacity:.6}.van-scale-enter-active,.van-scale-leave-active{transition-property:opacity,-webkit-transform;transition-property:opacity,transform;transition-property:opacity,transform,-webkit-transform}.van-scale-enter,.van-scale-leave-to{-webkit-transform:translate3d(-50%,-50%,0) scale(.7);transform:translate3d(-50%,-50%,0) scale(.7);opacity:0}.van-fade-enter-active,.van-fade-leave-active{transition-property:opacity}.van-fade-enter,.van-fade-leave-to{opacity:0}.van-center-enter-active,.van-center-leave-active{transition-property:opacity}.van-center-enter,.van-center-leave-to{opacity:0}.van-bottom-enter-active,.van-bottom-leave-active,.van-left-enter-active,.van-left-leave-active,.van-right-enter-active,.van-right-leave-active,.van-top-enter-active,.van-top-leave-active{transition-property:-webkit-transform;transition-property:transform;transition-property:transform,-webkit-transform}.van-bottom-enter,.van-bottom-leave-to{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}.van-top-enter,.van-top-leave-to{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}.van-left-enter,.van-left-leave-to{-webkit-transform:translate3d(-100%,-50%,0);transform:translate3d(-100%,-50%,0)}.van-right-enter,.van-right-leave-to{-webkit-transform:translate3d(100%,-50%,0);transform:translate3d(100%,-50%,0)}
\ No newline at end of file
import { VantComponent } from '../common/component';
VantComponent({
field: true,
relation: {
name: 'radio',
type: 'descendant',
current: 'radio-group',
linked(target) {
this.updateChild(target);
},
},
props: {
value: {
type: null,
observer: 'updateChildren'
},
disabled: {
type: Boolean,
observer: 'updateChildren'
}
},
methods: {
updateChildren() {
(this.children || []).forEach((child) => this.updateChild(child));
},
updateChild(child) {
const { value, disabled } = this.data;
child.setData({
value,
disabled: disabled || child.data.disabled
});
}
}
});
@import '../common/index.wxss';
\ No newline at end of file
import { VantComponent } from '../common/component';
VantComponent({
field: true,
relation: {
name: 'radio-group',
type: 'ancestor',
current: 'radio',
},
classes: ['icon-class', 'label-class'],
props: {
name: null,
value: null,
disabled: Boolean,
useIconSlot: Boolean,
checkedColor: String,
labelPosition: {
type: String,
value: 'right'
},
labelDisabled: Boolean,
shape: {
type: String,
value: 'round'
},
iconSize: {
type: null,
value: 20
}
},
methods: {
emitChange(value) {
const instance = this.parent || this;
instance.$emit('input', value);
instance.$emit('change', value);
},
onChange() {
if (!this.data.disabled) {
this.emitChange(this.data.name);
}
},
onClickLabel() {
const { disabled, labelDisabled, name } = this.data;
if (!disabled && !labelDisabled) {
this.emitChange(name);
}
}
}
});
{
"component": true,
"usingComponents": {
"van-icon": "../icon/index"
}
}
<wxs src="../wxs/utils.wxs" module="utils" />
<view class="van-radio custom-class">
<view
wx:if="{{ labelPosition === 'left' }}"
class="label-class {{ utils.bem('radio__label', [labelPosition, { disabled }]) }}"
bindtap="onClickLabel"
>
<slot />
</view>
<view class="van-radio__icon-wrap" style="font-size: {{ utils.addUnit(iconSize) }};" bindtap="onChange">
<slot wx:if="{{ useIconSlot }}" name="icon" />
<van-icon
wx:else
name="success"
class="{{ utils.bem('radio__icon', [shape, { disabled, checked: value === name }]) }}"
style="font-size: {{ utils.addUnit(iconSize) }};{{ checkedColor && !disabled && value === name ? 'border-color:' + checkedColor + '; background-color:' + checkedColor + ';' : '' }}"
custom-class="icon-class"
custom-style="line-height: {{ utils.addUnit(iconSize) }};font-size: .8em;display: block;"
/>
</view>
<view
wx:if="{{ labelPosition === 'right' }}"
class="label-class {{ utils.bem('radio__label', [labelPosition, { disabled }]) }}"
bindtap="onClickLabel"
>
<slot />
</view>
</view>
@import '../common/index.wxss';.van-radio{display:-webkit-flex;display:flex;-webkit-align-items:center;align-items:center;overflow:hidden;-webkit-user-select:none;user-select:none}.van-radio__icon-wrap{-webkit-flex:none;flex:none}.van-radio__icon{display:-webkit-flex;display:flex;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;box-sizing:border-box;width:1em;height:1em;color:transparent;text-align:center;transition-property:color,border-color,background-color;border:1px solid #c8c9cc;border:1px solid var(--radio-border-color,#c8c9cc);font-size:20px;font-size:var(--radio-size,20px);transition-duration:.2s;transition-duration:var(--radio-transition-duration,.2s)}.van-radio__icon--round{border-radius:100%}.van-radio__icon--checked{color:#fff;color:var(--white,#fff);background-color:#1989fa;background-color:var(--radio-checked-icon-color,#1989fa);border-color:#1989fa;border-color:var(--radio-checked-icon-color,#1989fa)}.van-radio__icon--disabled{background-color:#ebedf0;background-color:var(--radio-disabled-background-color,#ebedf0);border-color:#c8c9cc;border-color:var(--radio-disabled-icon-color,#c8c9cc)}.van-radio__icon--disabled.van-radio__icon--checked{color:#c8c9cc;color:var(--radio-disabled-icon-color,#c8c9cc)}.van-radio__label{word-wrap:break-word;margin-left:10px;margin-left:var(--radio-label-margin,10px);color:#323233;color:var(--radio-label-color,#323233);line-height:20px;line-height:var(--radio-size,20px)}.van-radio__label--left{float:left;margin:0 10px 0 0;margin:0 var(--radio-label-margin,10px) 0 0}.van-radio__label--disabled{color:#c8c9cc;color:var(--radio-disabled-label-color,#c8c9cc)}.van-radio__label:empty{margin:0}
\ No newline at end of file
import { VantComponent } from '../common/component';
VantComponent({
props: {
size: String,
mark: Boolean,
color: String,
plain: Boolean,
round: Boolean,
textColor: String,
type: {
type: String,
value: 'default'
},
closeable: Boolean
},
methods: {
onClose() {
this.$emit('close');
}
}
});
{
"component": true,
"usingComponents": {
"van-icon": "../icon/index"
}
}
<wxs src="../wxs/utils.wxs" module="utils" />
<view
class="custom-class {{ utils.bem('tag', [type, size, { mark, plain, round }]) }} {{ plain ? 'van-hairline--surround' : '' }}"
style="{{ color && !plain ? 'background-color: ' + color + ';' : '' }}{{ textColor || (color && plain) ? 'color: ' + (textColor || color) : '' }}"
>
<slot />
<van-icon
wx:if="{{ closeable }}"
name="cross"
custom-class="van-tag__close"
bind:click="onClose"
/>
</view>
@import '../common/index.wxss';.van-tag{display:-webkit-inline-flex;display:inline-flex;-webkit-align-items:center;align-items:center;line-height:normal;padding:.2em .5em;padding:var(--tag-padding,.2em .5em);color:#fff;color:var(--tag-text-color,#fff);font-size:10px;font-size:var(--tag-font-size,10px);border-radius:.2em;border-radius:var(--tag-border-radius,.2em)}.van-tag:after{border-color:currentColor;border-radius:.2em * 2;border-radius:var(--tag-border-radius,.2em) * 2}.van-tag--default{background-color:#969799;background-color:var(--tag-default-color,#969799)}.van-tag--default.van-tag--plain{color:#969799;color:var(--tag-default-color,#969799)}.van-tag--danger{background-color:#ee0a24;background-color:var(--tag-dander-color,#ee0a24)}.van-tag--danger.van-tag--plain{color:#ee0a24;color:var(--tag-dander-color,#ee0a24)}.van-tag--primary{background-color:#1989fa;background-color:var(--tag-primary-color,#1989fa)}.van-tag--primary.van-tag--plain{color:#1989fa;color:var(--tag-primary-color,#1989fa)}.van-tag--success{background-color:#07c160;background-color:var(--tag-success-color,#07c160)}.van-tag--success.van-tag--plain{color:#07c160;color:var(--tag-success-color,#07c160)}.van-tag--warning{background-color:#ff976a;background-color:var(--tag-warning-color,#ff976a)}.van-tag--warning.van-tag--plain{color:#ff976a;color:var(--tag-warning-color,#ff976a)}.van-tag--plain{background-color:#fff;background-color:var(--tag-plain-background-color,#fff)}.van-tag--mark{padding-right:.7em}.van-tag--mark,.van-tag--mark:after{border-radius:0 999px 999px 0;border-radius:0 var(--tag-round-border-radius,999px) var(--tag-round-border-radius,999px) 0}.van-tag--round,.van-tag--round:after{border-radius:999px;border-radius:var(--tag-round-border-radius,999px)}.van-tag--medium{font-size:12px;font-size:var(--tag-medium-font-size,12px)}.van-tag--large{font-size:14px;font-size:var(--tag-large-font-size,14px)}.van-tag__close{margin-left:2px}
\ No newline at end of file
import { VantComponent } from '../common/component';
import { transition } from '../mixins/transition';
VantComponent({
classes: [
'enter-class',
'enter-active-class',
'enter-to-class',
'leave-class',
'leave-active-class',
'leave-to-class'
],
mixins: [transition(true)]
});
{
"component": true
}
\ No newline at end of file
<view
wx:if="{{ inited }}"
class="van-transition custom-class {{ classes }}"
style="-webkit-transition-duration:{{ currentDuration }}ms; transition-duration:{{ currentDuration }}ms; {{ display ? '' : 'display: none;' }} {{ customStyle }}"
bind:transitionend="onTransitionEnd"
>
<slot />
</view>
@import '../common/index.wxss';.van-transition{transition-timing-function:ease}.van-fade-enter-active,.van-fade-leave-active{transition-property:opacity}.van-fade-enter,.van-fade-leave-to{opacity:0}.van-fade-down-enter-active,.van-fade-down-leave-active,.van-fade-left-enter-active,.van-fade-left-leave-active,.van-fade-right-enter-active,.van-fade-right-leave-active,.van-fade-up-enter-active,.van-fade-up-leave-active{transition-property:opacity,-webkit-transform;transition-property:opacity,transform;transition-property:opacity,transform,-webkit-transform}.van-fade-up-enter,.van-fade-up-leave-to{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);opacity:0}.van-fade-down-enter,.van-fade-down-leave-to{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0);opacity:0}.van-fade-left-enter,.van-fade-left-leave-to{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);opacity:0}.van-fade-right-enter,.van-fade-right-leave-to{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);opacity:0}.van-slide-down-enter-active,.van-slide-down-leave-active,.van-slide-left-enter-active,.van-slide-left-leave-active,.van-slide-right-enter-active,.van-slide-right-leave-active,.van-slide-up-enter-active,.van-slide-up-leave-active{transition-property:-webkit-transform;transition-property:transform;transition-property:transform,-webkit-transform}.van-slide-up-enter,.van-slide-up-leave-to{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}.van-slide-down-enter,.van-slide-down-leave-to{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}.van-slide-left-enter,.van-slide-left-leave-to{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.van-slide-right-enter,.van-slide-right-leave-to{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}
\ No newline at end of file
/* eslint-disable */
var REGEXP = getRegExp('^\d+(\.\d+)?$');
function addUnit(value) {
if (value == null) {
return undefined;
}
return REGEXP.test('' + value) ? value + 'px' : value;
}
module.exports = {
addUnit: addUnit
};
function isArray(array) {
return array && array.constructor === 'Array';
}
module.exports.isArray = isArray;
var array = require('./array.wxs');
var object = require('./object.wxs');
var PREFIX = 'van-';
function join(name, mods) {
name = PREFIX + name;
mods = mods.map(function(mod) {
return name + '--' + mod;
});
mods.unshift(name);
return mods.join(' ');
}
function traversing(mods, conf) {
if (!conf) {
return;
}
if (typeof conf === 'string' || typeof conf === 'number') {
mods.push(conf);
} else if (array.isArray(conf)) {
conf.forEach(function(item) {
traversing(mods, item);
});
} else if (typeof conf === 'object') {
object.keys(conf).forEach(function(key) {
conf[key] && mods.push(key);
});
}
}
function bem(name, conf) {
var mods = [];
traversing(mods, conf);
return join(name, mods);
}
module.exports.bem = bem;
/**
* Simple memoize
* wxs doesn't support fn.apply, so this memoize only support up to 2 args
*/
function isPrimitive(value) {
var type = typeof value;
return (
type === 'boolean' ||
type === 'number' ||
type === 'string' ||
type === 'undefined' ||
value === null
);
}
// mock simple fn.call in wxs
function call(fn, args) {
if (args.length === 2) {
return fn(args[0], args[1]);
}
if (args.length === 1) {
return fn(args[0]);
}
return fn();
}
function serializer(args) {
if (args.length === 1 && isPrimitive(args[0])) {
return args[0];
}
var obj = {};
for (var i = 0; i < args.length; i++) {
obj['key' + i] = args[i];
}
return JSON.stringify(obj);
}
function memoize(fn) {
var cache = {};
return function() {
var key = serializer(arguments);
if (cache[key] === undefined) {
cache[key] = call(fn, arguments);
}
return cache[key];
};
}
module.exports.memoize = memoize;
/* eslint-disable */
var REGEXP = getRegExp('{|}|"', 'g');
function keys(obj) {
return JSON.stringify(obj)
.replace(REGEXP, '')
.split(',')
.map(function(item) {
return item.split(':')[0];
});
}
module.exports.keys = keys;
/* eslint-disable */
var bem = require('./bem.wxs').bem;
var memoize = require('./memoize.wxs').memoize;
var addUnit = require('./add-unit.wxs').addUnit;
module.exports = {
bem: memoize(bem),
memoize: memoize,
addUnit: addUnit
};
@font-face {font-family: "iconfont";
src: url('//at.alicdn.com/t/font_2172922_bfznc3bwivf.eot?t=1604299492582'); /* IE9 */
src: url('//at.alicdn.com/t/font_2172922_bfznc3bwivf.eot?t=1604299492582#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAY8AAsAAAAAC+gAAAXtAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCELgqJJIdgATYCJAMsCxgABCAFhG0HgQwbRAoRFaSvkn11YB4yL94IaoQp9EUyjFcv/SJRGo73OYJoP/az7w4TiVS3RElEmkcahEiiFE2BpF/jj/rz772e5KZ6KJgSfig9K91caZSCipm/xACYdllxF22SCAIaP4D3ImksztUBqxMyQo3kWfTw7wspDJIOEAXcTHf4QgoOjqV+Bb095tl/u0QmRbU9xdY8oAFFNAYNo3gDmjjPZDk5OpMEretvr3E1gUq9nGArMUkSUJaRNlBxVF1ZDMoFm9xBCeXG0oYjM8QNKCgv1uFPAFz734+f4BHKoFCSgK51UBFdBmG8Ic8i6j8FeYiCjuU8uBxHwjSQibtG3y2gJDkNqXytTzgG0Ewdkpf6S1Pek/fmw/jJ/DK+i2f//3/hlg6mpaGZkbr/4IEyJSoUskohKVVOlAJ01RH2KlXJF0PNpowvpmxK+OLJpoIv3mwKvoSxyXyZLFtCvxQWAf0yWCTou2BRCj2LJuWgyh7RCrSA2AKI30CGHd+eJFkoGBE5XSKRAcJM2EGBUDu/XWORqlisYb3omkAg2/TMRrDnipQI6mjALxmhWj1ngXaXsayM4+QMI6XpnDu02U4m+j5nuYtdtI/Wxra98hGdeWGEb33pLT7/2hTrZGy3901HxUWLhuok0zQzpCSTVMQ4a0mdYJPedsPNjocd1xtudznEWh0w6iBjnvdxPR57P3rvVXUybIO2XYf2BlJSiwnhZHpx9qJpeXSPlBmR72Exy+cdpW+DByrvqqMSWdeesDCppIOKv5BLO+vzymXy9bU9PS5hJqTcm9Fnzi/qENTtg2jzflbcSfV1unO7avPP5mTnCKTu0Crmra+PC53dMauiq24mcnnZI1Sur3UsF3mb061nzF5zJkyPZKxXdpT2Y1lthpZsY132eAdGGjBaHOU1hQxfj1G/drzuNwif5hUf73nB01i8Tidr4RdwjpFhs2fjcjbPng2T/Jorl+xIThYINWHHCYJQcDz4DRZkLvOepSR8eHPbzYfCfL+2yuxlXpk3YXZgcYraPq4F019eV4m/f5FZ++rfP1fyNeL3H+Iqupatm3mJODw2fgQdRhPjMB8eB4IQ228xz9DYCNQa/jLuc+b2F38c2xKleGysLcXtnktWyzcywPVnz/GUlTf+9vdf/SoIWW9hERUFvu/wOzhwxZJAMBuitoK/+2dbA1sDHKZMnz7VPrAtoDX4wB9sK9Ftatb9uQJb04iqmbqmocataxvkemsbgWmTzVXi1y/igOJIYlTRflOU15NrVl3n+Vh1ct1Kym30NMg1K44K/y0xcv6qlde1BpglqocwMyN6WGwlRpYRFLrXVtSw6Z+tIlYTX8L+95yOOGACHsJEG0NDN5KepHMmiRIZ1oMzG7TvQeNoo03GFNtkFG18sPhCDxlBapJDgd7itFwDOYZMY5pCjdev6bLTPSIaksauvc50V0BFqqFPzq058JTJvYk5+uLoauXklDrtJN2aogPNBpYOA/D/daIRAqQbfL1gnkY3kNddLxD8//h/csYQBfD/EDqObABIC/gNAKwN7x8aGEBpgWcr95o+EYVqQV+VhX+oyMvdx+O+Z5kS5QoGy4OKltgE8V/1VpJsiSF6xv8fm2QT/VXWc7LlNZU8RhAJNRqUhpbBOqHS0JJBoUwPJOWGkRk7DSWqzECpcvNQaUrs8VWazAQksgowaZWAUO84FGo9Q1LvKTJjB6BEq09Qqj4QVDrEtM5YZZSav9wbFB1qkDN4xWSUs7vElR+0fSmavNLT/rFpfQRSF7dy5o2EzRL7tIPNus6AabiCl7geliVDaDhH1UWu68Itdq1oeqJIcbW6iGxQdKiBnIFXTMYu310qP/9B25ei6Rj4Ev3HpvWrB6lIMgD51tGggUepbweb6WTcAHMp5wq8pAdLTjIIzZvlqLqImxAPN7EcZYbqou0N1e+9AirRc1Q1mq12R2dXd09vH6XfC7K5P7TOB0+HEckJPmrBrqnkqgVNvc5fHJM92CRP+sPi55P+WFCnvgbJ6p63TltXKwAA') format('woff2'),
url('//at.alicdn.com/t/font_2172922_bfznc3bwivf.woff?t=1604299492582') format('woff'),
url('//at.alicdn.com/t/font_2172922_bfznc3bwivf.ttf?t=1604299492582') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
url('//at.alicdn.com/t/font_2172922_bfznc3bwivf.svg?t=1604299492582#iconfont') format('svg'); /* iOS 4.1- */
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.iconxiangji:before {
content: "\e67e";
}
.iconshipin:before {
content: "\e635";
}
.iconwenhao:before {
content: "\e67f";
}
.icondaohang:before {
content: "\e640";
}
.icondanxuanxuanzhong:before {
content: "\e61f";
}
.iconguanbi:before {
content: "\e696";
}
.iconziyuan:before {
content: "\e61b";
}
.iconguanbi1:before {
content: "\e6d6";
}
.icongengduo:before {
content: "\e633";
}
.iconhuo:before {
content: "\e66c";
}
\ No newline at end of file
{
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"@vant/weapp": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@vant/weapp/-/weapp-1.0.7.tgz",
"integrity": "sha512-F7gkcVKLTh4Pt17ukZnpZmn78CbtfmUtxSZif02ysyXZmqtAf1aAUffL3i1y+qzGWCXF4y/OVkOBVQVrKHI4MA=="
},
"vant-weapp": {
"version": "0.5.27",
"resolved": "https://registry.npmjs.org/vant-weapp/-/vant-weapp-0.5.27.tgz",
"integrity": "sha512-wmbpPWbpIk/Nl022Yfu0LNV+rSBPxnWTsZePVo6De4FxY3SWw47+Ip6rxLgdnG00/FntbymgvVw4xlaW+WmC+Q=="
}
}
}
// pages/class/class.js
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
\ No newline at end of file
{
"usingComponents": {},
"navigationBarTitleText": "抢班"
}
\ No newline at end of file
<!--pages/class/class.wxml-->
<text>pages/class/class.wxml</text>
/* pages/class/class.wxss */
\ No newline at end of file
// pages/financial/financial.js
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
\ No newline at end of file
{
"usingComponents": {},
"navigationBarTitleText": "财务"
}
\ No newline at end of file
<!--pages/financial/financial.wxml-->
<text>pages/financial/financial.wxml</text>
/* pages/financial/financial.wxss */
\ No newline at end of file
Page({
/**
* 页面的初始数据
*/
data: {
isOpen: false,
daysColor: [
{
month: 'current',
day: '12',
color: '#fff',
background: 'linear-gradient(#5791FE 0%, #3E63F8 100%);'
},
{
month: 'current',
day: '10',
color: '#fff',
background: 'linear-gradient(#5791FE 0%, #3E63F8 100%);'
},
{
month: 'current',
day: '8',
color: '#fff',
background: 'linear-gradient(#5791FE 0%, #3E63F8 100%);'
}
]
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
onChange(e) {
let index = e.currentTarget.dataset.index
let list = this.data.classlist
list[index].timeData = e.detail
this.setData({
classlist: list
})
},
changeTab(e) {
let index = e.currentTarget.dataset.index
if (this.data.activeIndex != index) {
this.setData({
activeIndex: index
})
}
},
// 日历展开与否
open() {
this.setData({
isOpen: !this.data.isOpen
})
}
})
\ No newline at end of file
{
"usingComponents": {
"van-count-down": "/components/vant/count-down/index",
"calendar": "plugin://calendar/calendar"
},
"navigationBarTitleText": "课表"
}
\ No newline at end of file
<view>
<view>
<view class="tabContent">
<view class="rili">
<calendar weeks-type='cn' calendar-style="calendar" header-style="rili_header" board-style="board {{isOpen? 'heightBoard' : ''}}" show-more-days='true' active-type='rounded' days-color='{{daysColor}}' cell-size='29' />
<view class="riliShow">
<view class="flex-h flex-vc flex-hc" catchtap="open">
<text>{{isOpen ? '收起':'更多日期'}}</text>
<text class="iconfont icongengduo {{isOpen ? 'up': 'down'}}"></text>
</view>
</view>
</view>
<view class="cont">
<view class="top">
<view class="time_title">篮球课</view>
<view class="state">即将开课</view>
</view>
<view class="time">上课时间:2020-10-21 09:00-10:00 </view>
<view class="place">上课地点:新天际众美幼稚园</view>
<view class="manage">管理</view>
</view>
</view>
</view>
</view>
\ No newline at end of file
.rili {
margin: auto;
width: 690rpx;
padding-bottom: 38rpx;
margin-top: 40rpx;
}
.rili_header {
width: 360rpx;
font-size: 32rpx;
font-family: PingFang SC;
font-weight: bold;
color: #000000;
margin: 0 auto 30rpx auto !important;
}
.calendar--calendar-weeks {
background: #FFF3DA;
}
.board {
background: #FFFFFF;
border-radius: 20rpx 20rpx 0px 0px;
overflow: hidden;
height: 160rpx;
}
.heightBoard {
height: auto;
}
.board>view:nth-child(1) {
line-height: 54rpx;
height: 54rpx;
font-size: 24rpx;
color: #999999;
font-weight: normal;
}
.board>view:nth-child(2) {
padding: 20rpx 0;
}
.board>view:nth-child(2)>view {
font-size: 26rpx;
font-family: PingFang SC;
font-weight: bold;
color: #000000;
line-height: 54rpx;
}
.riliShow {
width: 100%;
background: #fff;
text-align: center;
padding-bottom: 40rpx;
}
.riliShow>view {
font-size: 24rpx;
color: #B3B3B3;
text-align: center;
}
.riliShow>view .down {
margin-left: 5rpx;
font-weight: bold;
font-size: 26rpx;
transform: rotate(90deg);
}
.riliShow>view .up {
margin-left: 5rpx;
font-weight: bold;
font-size: 26rpx;
transform: rotate(270deg);
}
.beginone {
width: 690rpx;
height: 206rpx;
background: #FFFFFF;
border-radius: 15rpx;
box-shadow: 0 0 30rpx #002c69;
margin: 0 auto 24rpx auto;
}
.cont{
width: 690rpx;
height: 206rpx;
background: #FFFFFF;
border-radius: 15px;
box-shadow: 0 10rpx 20rpx 10rpx rgba(239, 240, 241, 0.72);
padding:20rpx;
margin-bottom: 24rpx;
margin: 0 auto;
position: relative;
}
.cont .top{
overflow: hidden;
}
.cont .top .time_title{
float: left;
color: #000000;
font-size: 30rpx;
margin-bottom: 32rpx;
}
.cont .top .state{
float: right;
color: #FF6E00;
font-size: 24rpx;
}
.cont .time{
color: #999999;
font-size: 24rpx;
margin-bottom: 30rpx;
}
.cont .place{
color: #999999;
font-size: 24rpx;
margin-top: -14rpx;
}
.cont .manage{
width: 136rpx;
height: 48r px;
background: linear-gradient(-70deg, #FFC600 0%, #FFD400 100%);
border-radius: 24px;
color: #000000;
font-size: 24rpx;
line-height: 48rpx;
text-align: center;
position: absolute;
bottom: 40rpx;
right: 20rpx;
}
// pages/personal/personal.js
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
\ No newline at end of file
{
"usingComponents": {},
"navigationBarTitleText": "我的"
}
\ No newline at end of file
<!--pages/personal/personal.wxml-->
<text>pages/personal/personal.wxml</text>
/* pages/personal/personal.wxss */
\ No newline at end of file
{
"description": "项目配置文件",
"packOptions": {
"ignore": []
},
"setting": {
"urlCheck": true,
"scopeDataCheck": false,
"coverView": true,
"es6": true,
"postcss": true,
"compileHotReLoad": false,
"preloadBackgroundData": false,
"minified": true,
"autoAudits": false,
"newFeature": false,
"uglifyFileName": false,
"uploadWithSourceMap": true,
"useIsolateContext": true,
"nodeModules": false,
"enhance": false,
"useCompilerModule": false,
"userConfirmedUseCompilerModuleSwitch": false,
"showShadowRootInWxmlPanel": true
},
"compileType": "miniprogram",
"libVersion": "2.14.0",
"appid": "wx6e6eaca9cc1c406d",
"projectname": "wandouchengzhang_coach",
"debugOptions": {
"hidedInDevtools": []
},
"scripts": {},
"isGameTourist": false,
"simulatorType": "wechat",
"simulatorPluginLibVersion": {},
"condition": {
"search": {
"current": -1,
"list": []
},
"conversation": {
"current": -1,
"list": []
},
"game": {
"current": -1,
"list": []
},
"plugin": {
"current": -1,
"list": []
},
"gamePlugin": {
"current": -1,
"list": []
},
"miniprogram": {
"current": -1,
"list": []
}
}
}
\ No newline at end of file
{
"desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
"rules": [{
"action": "allow",
"page": "*"
}]
}
\ No newline at end of file
const formatTime = date => {
const year = date.getFullYear()
const month = date.getMonth() + 1
const day = date.getDate()
const hour = date.getHours()
const minute = date.getMinutes()
const second = date.getSeconds()
return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')
}
const formatNumber = n => {
n = n.toString()
return n[1] ? n : '0' + n
}
module.exports = {
formatTime: formatTime
}
/**
* 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;
// HTML 支持的数学符号
function strNumDiscode(str){
str = str.replace(/&forall;/g, '');
str = str.replace(/&part;/g, '');
str = str.replace(/&exists;/g, '');
str = str.replace(/&empty;/g, '');
str = str.replace(/&nabla;/g, '');
str = str.replace(/&isin;/g, '');
str = str.replace(/&notin;/g, '');
str = str.replace(/&ni;/g, '');
str = str.replace(/&prod;/g, '');
str = str.replace(/&sum;/g, '');
str = str.replace(/&minus;/g, '');
str = str.replace(/&lowast;/g, '');
str = str.replace(/&radic;/g, '');
str = str.replace(/&prop;/g, '');
str = str.replace(/&infin;/g, '');
str = str.replace(/&ang;/g, '');
str = str.replace(/&and;/g, '');
str = str.replace(/&or;/g, '');
str = str.replace(/&cap;/g, '');
str = str.replace(/&cap;/g, '');
str = str.replace(/&int;/g, '');
str = str.replace(/&there4;/g, '');
str = str.replace(/&sim;/g, '');
str = str.replace(/&cong;/g, '');
str = str.replace(/&asymp;/g, '');
str = str.replace(/&ne;/g, '');
str = str.replace(/&le;/g, '');
str = str.replace(/&ge;/g, '');
str = str.replace(/&sub;/g, '');
str = str.replace(/&sup;/g, '');
str = str.replace(/&nsub;/g, '');
str = str.replace(/&sube;/g, '');
str = str.replace(/&supe;/g, '');
str = str.replace(/&oplus;/g, '');
str = str.replace(/&otimes;/g, '');
str = str.replace(/&perp;/g, '');
str = str.replace(/&sdot;/g, '');
return str;
}
//HTML 支持的希腊字母
function strGreeceDiscode(str){
str = str.replace(/&Alpha;/g, 'Α');
str = str.replace(/&Beta;/g, 'Β');
str = str.replace(/&Gamma;/g, 'Γ');
str = str.replace(/&Delta;/g, 'Δ');
str = str.replace(/&Epsilon;/g, 'Ε');
str = str.replace(/&Zeta;/g, 'Ζ');
str = str.replace(/&Eta;/g, 'Η');
str = str.replace(/&Theta;/g, 'Θ');
str = str.replace(/&Iota;/g, 'Ι');
str = str.replace(/&Kappa;/g, 'Κ');
str = str.replace(/&Lambda;/g, 'Λ');
str = str.replace(/&Mu;/g, 'Μ');
str = str.replace(/&Nu;/g, 'Ν');
str = str.replace(/&Xi;/g, 'Ν');
str = str.replace(/&Omicron;/g, 'Ο');
str = str.replace(/&Pi;/g, 'Π');
str = str.replace(/&Rho;/g, 'Ρ');
str = str.replace(/&Sigma;/g, 'Σ');
str = str.replace(/&Tau;/g, 'Τ');
str = str.replace(/&Upsilon;/g, 'Υ');
str = str.replace(/&Phi;/g, 'Φ');
str = str.replace(/&Chi;/g, 'Χ');
str = str.replace(/&Psi;/g, 'Ψ');
str = str.replace(/&Omega;/g, 'Ω');
str = str.replace(/&alpha;/g, 'α');
str = str.replace(/&beta;/g, 'β');
str = str.replace(/&gamma;/g, 'γ');
str = str.replace(/&delta;/g, 'δ');
str = str.replace(/&epsilon;/g, 'ε');
str = str.replace(/&zeta;/g, 'ζ');
str = str.replace(/&eta;/g, 'η');
str = str.replace(/&theta;/g, 'θ');
str = str.replace(/&iota;/g, 'ι');
str = str.replace(/&kappa;/g, 'κ');
str = str.replace(/&lambda;/g, 'λ');
str = str.replace(/&mu;/g, 'μ');
str = str.replace(/&nu;/g, 'ν');
str = str.replace(/&xi;/g, 'ξ');
str = str.replace(/&omicron;/g, 'ο');
str = str.replace(/&pi;/g, 'π');
str = str.replace(/&rho;/g, 'ρ');
str = str.replace(/&sigmaf;/g, 'ς');
str = str.replace(/&sigma;/g, 'σ');
str = str.replace(/&tau;/g, 'τ');
str = str.replace(/&upsilon;/g, 'υ');
str = str.replace(/&phi;/g, 'φ');
str = str.replace(/&chi;/g, 'χ');
str = str.replace(/&psi;/g, 'ψ');
str = str.replace(/&omega;/g, 'ω');
str = str.replace(/&thetasym;/g, 'ϑ');
str = str.replace(/&upsih;/g, 'ϒ');
str = str.replace(/&piv;/g, 'ϖ');
str = str.replace(/&middot;/g, '·');
return str;
}
//
function strcharacterDiscode(str){
// 加入常用解析
str = str.replace(/&nbsp;/g, ' ');
str = str.replace(/&quot;/g, "'");
str = str.replace(/&amp;/g, '&');
// str = str.replace(/&lt;/g, '‹');
// str = str.replace(/&gt;/g, '›');
str = str.replace(/&lt;/g, '<');
str = str.replace(/&gt;/g, '>');
str = str.replace(/&#8226;/g, '');
return str;
}
// HTML 支持的其他实体
function strOtherDiscode(str){
str = str.replace(/&OElig;/g, 'Œ');
str = str.replace(/&oelig;/g, 'œ');
str = str.replace(/&Scaron;/g, 'Š');
str = str.replace(/&scaron;/g, 'š');
str = str.replace(/&Yuml;/g, 'Ÿ');
str = str.replace(/&fnof;/g, 'ƒ');
str = str.replace(/&circ;/g, 'ˆ');
str = str.replace(/&tilde;/g, '˜');
str = str.replace(/&ensp;/g, '');
str = str.replace(/&emsp;/g, '');
str = str.replace(/&thinsp;/g, '');
str = str.replace(/&zwnj;/g, '');
str = str.replace(/&zwj;/g, '');
str = str.replace(/&lrm;/g, '');
str = str.replace(/&rlm;/g, '');
str = str.replace(/&ndash;/g, '');
str = str.replace(/&mdash;/g, '');
str = str.replace(/&lsquo;/g, '');
str = str.replace(/&rsquo;/g, '');
str = str.replace(/&sbquo;/g, '');
str = str.replace(/&ldquo;/g, '');
str = str.replace(/&rdquo;/g, '');
str = str.replace(/&bdquo;/g, '');
str = str.replace(/&dagger;/g, '');
str = str.replace(/&Dagger;/g, '');
str = str.replace(/&bull;/g, '');
str = str.replace(/&hellip;/g, '');
str = str.replace(/&permil;/g, '');
str = str.replace(/&prime;/g, '');
str = str.replace(/&Prime;/g, '');
str = str.replace(/&lsaquo;/g, '');
str = str.replace(/&rsaquo;/g, '');
str = str.replace(/&oline;/g, '');
str = str.replace(/&euro;/g, '');
str = str.replace(/&trade;/g, '');
str = str.replace(/&larr;/g, '');
str = str.replace(/&uarr;/g, '');
str = str.replace(/&rarr;/g, '');
str = str.replace(/&darr;/g, '');
str = str.replace(/&harr;/g, '');
str = str.replace(/&crarr;/g, '');
str = str.replace(/&lceil;/g, '');
str = str.replace(/&rceil;/g, '');
str = str.replace(/&lfloor;/g, '');
str = str.replace(/&rfloor;/g, '');
str = str.replace(/&loz;/g, '');
str = str.replace(/&spades;/g, '');
str = str.replace(/&clubs;/g, '');
str = str.replace(/&hearts;/g, '');
str = str.replace(/&diams;/g, '');
str = str.replace(/&#39;/g, '\'');
return str;
}
function strMoreDiscode(str){
str = str.replace(/\r\n/g,"");
str = str.replace(/\n/g,"");
str = str.replace(/code/g,"wxxxcode-style");
return str;
}
function strDiscode(str){
str = strNumDiscode(str);
str = strGreeceDiscode(str);
str = strcharacterDiscode(str);
str = strOtherDiscode(str);
str = strMoreDiscode(str);
return str;
}
function urlToHttpUrl(url,rep){
var patt1 = new RegExp("^//");
var result = patt1.test(url);
if(result){
url = rep+":"+url;
}
return url;
}
module.exports = {
strDiscode:strDiscode,
urlToHttpUrl:urlToHttpUrl
}
\ No newline at end of file
/**
* author: Di (微信小程序开发工程师)
* organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
* 垂直微信小程序开发交流社区
*
* github地址: https://github.com/icindy/wxParse
*
* for: 微信小程序富文本解析
* detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
*/
/**
* utils函数引入
**/
import showdown from './showdown.js';
import HtmlToJson from './html2json.js';
/**
* 配置及公有属性
**/
var realWindowWidth = 0;
var realWindowHeight = 0;
wx.getSystemInfo({
success: function (res) {
realWindowWidth = res.windowWidth
realWindowHeight = res.windowHeight
}
})
/**
* 主函数入口区
**/
function wxParse(bindName = 'wxParseData', type='html', data='<div class="color:red;">数据不能为空</div>', target,imagePadding) {
var that = target;
var transData = {};//存放转化后的数据
if (type == 'html') {
transData = HtmlToJson.html2json(data, bindName);
// console.log(JSON.stringify(transData, ' ', ' '));
} else if (type == 'md' || type == 'markdown') {
var converter = new showdown.Converter();
var html = converter.makeHtml(data);
transData = HtmlToJson.html2json(html, bindName);
console.log(JSON.stringify(transData, ' ', ' '));
}
transData.view = {};
transData.view.imagePadding = 0;
if(typeof(imagePadding) != 'undefined'){
transData.view.imagePadding = imagePadding
}
var bindData = {};
bindData[bindName] = transData;
that.setData(bindData)
that.wxParseImgLoad = wxParseImgLoad;
that.wxParseImgTap = wxParseImgTap;
}
// 图片点击事件
function wxParseImgTap(e) {
var that = this;
var nowImgUrl = e.target.dataset.src;
var tagFrom = e.target.dataset.from;
if (typeof (tagFrom) != 'undefined' && tagFrom.length > 0) {
wx.previewImage({
current: nowImgUrl, // 当前显示图片的http链接
urls: that.data[tagFrom].imageUrls // 需要预览的图片http链接列表
})
}
}
/**
* 图片视觉宽高计算函数区
**/
function wxParseImgLoad(e) {
var that = this;
var tagFrom = e.target.dataset.from;
var idx = e.target.dataset.idx;
if (typeof (tagFrom) != 'undefined' && tagFrom.length > 0) {
calMoreImageInfo(e, idx, that, tagFrom)
}
}
// 假循环获取计算图片视觉最佳宽高
function calMoreImageInfo(e, idx, that, bindName) {
var temData = that.data[bindName];
if (!temData || temData.images.length == 0) {
return;
}
var temImages = temData.images;
//因为无法获取view宽度 需要自定义padding进行计算,稍后处理
var recal = wxAutoImageCal(e.detail.width, e.detail.height,that,bindName);
// temImages[idx].width = recal.imageWidth;
// temImages[idx].height = recal.imageheight;
// temData.images = temImages;
// var bindData = {};
// bindData[bindName] = temData;
// that.setData(bindData);
var index = temImages[idx].index
var key = `${bindName}`
for (var i of index.split('.')) key+=`.nodes[${i}]`
var keyW = key + '.width'
var keyH = key + '.height'
that.setData({
[keyW]: recal.imageWidth,
[keyH]: recal.imageheight,
})
}
// 计算视觉优先的图片宽高
function wxAutoImageCal(originalWidth, originalHeight,that,bindName) {
//获取图片的原始长宽
var windowWidth = 0, windowHeight = 0;
var autoWidth = 0, autoHeight = 0;
var results = {};
var padding = that.data[bindName].view.imagePadding;
windowWidth = realWindowWidth-2*padding;
windowHeight = realWindowHeight;
//判断按照那种方式进行缩放
// console.log("windowWidth" + windowWidth);
if (originalWidth > windowWidth) {//在图片width大于手机屏幕width时候
autoWidth = windowWidth;
// console.log("autoWidth" + autoWidth);
autoHeight = (autoWidth * originalHeight) / originalWidth;
// console.log("autoHeight" + autoHeight);
results.imageWidth = autoWidth;
results.imageheight = autoHeight;
} else {//否则展示原来的数据
results.imageWidth = originalWidth;
results.imageheight = originalHeight;
}
return results;
}
function wxParseTemArray(temArrayName,bindNameReg,total,that){
var array = [];
var temData = that.data;
var obj = null;
for(var i = 0; i < total; i++){
var simArr = temData[bindNameReg+i].nodes;
array.push(simArr);
}
temArrayName = temArrayName || 'wxParseTemArray';
obj = JSON.parse('{"'+ temArrayName +'":""}');
obj[temArrayName] = array;
that.setData(obj);
}
/**
* 配置emojis
*
*/
function emojisInit(reg='',baseSrc="/wxParse/emojis/",emojis){
HtmlToJson.emojisInit(reg,baseSrc,emojis);
}
module.exports = {
wxParse: wxParse,
wxParseTemArray:wxParseTemArray,
emojisInit:emojisInit
}
<!--**
* 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
*/-->
<!--基础元素-->
<template name="wxParseVideo">
<!--增加video标签支持,并循环添加-->
<view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
<video class="{{item.classStr}} wxParse-{{item.tag}}-video" src="{{item.attr.src}}"></video>
</view>
</template>
<template name="wxParseImg">
<image class="{{item.classStr}} wxParse-{{item.tag}}" data-from="{{item.from}}" data-src="{{item.attr.src}}" data-idx="{{item.imgIndex}}" src="{{item.attr.src}}" mode="aspectFit" bindload="wxParseImgLoad" bindtap="wxParseImgTap" mode="widthFix" style="width:{{item.width}}px;"
/>
</template>
<template name="WxEmojiView">
<view class="WxEmojiView wxParse-inline" style="{{item.styleStr}}">
<block wx:for="{{item.textArray}}" wx:key="item">
<block class="{{item.text == '\\n' ? 'wxParse-hide':''}}" wx:if="{{item.node == 'text'}}">{{item.text}}</block>
<block wx:elif="{{item.node == 'element'}}">
<image class="wxEmoji" src="{{item.baseSrc}}{{item.text}}" />
</block>
</block>
</view>
</template>
<template name="WxParseBr">
<text>\n</text>
</template>
<!--入口模版-->
<template name="wxParse">
<block wx:for="{{wxParseData}}" wx:key="{{item}}">
<template is="wxParse0" data="{{item}}" />
</block>
</template>
<!--循环模版-->
<template name="wxParse0">
<!--<template is="wxParse1" data="{{item}}" />-->
<!--判断是否是标签节点-->
<block wx:if="{{item.node == 'element'}}">
<block wx:if="{{item.tag == 'button'}}">
<button type="default" size="mini">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse1" data="{{item}}" />
</block>
</button>
</block>
<!--li类型-->
<block wx:elif="{{item.tag == 'li'}}">
<view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}">
<view class="{{item.classStr}} wxParse-li-inner">
<view class="{{item.classStr}} wxParse-li-text">
<view class="{{item.classStr}} wxParse-li-circle"></view>
</view>
<view class="{{item.classStr}} wxParse-li-text">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse1" data="{{item}}" />
</block>
</view>
</view>
</view>
</block>
<!--video类型-->
<block wx:elif="{{item.tag == 'video'}}">
<template is="wxParseVideo" data="{{item}}" />
</block>
<!--img类型-->
<block wx:elif="{{item.tag == 'img'}}">
<template is="wxParseImg" data="{{item}}" />
</block>
<!--a类型-->
<block wx:elif="{{item.tag == 'a'}}">
<view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse1" data="{{item}}" />
</block>
</view>
</block>
<block wx:elif="{{item.tag == 'table'}}">
<view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse1" data="{{item}}" />
</block>
</view>
</block>
<block wx:elif="{{item.tag == 'br'}}">
<template is="WxParseBr"></template>
</block>
<!--其他块级标签-->
<block wx:elif="{{item.tagType == 'block'}}">
<view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse1" data="{{item}}" />
</block>
</view>
</block>
<!--内联标签-->
<view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse1" data="{{item}}" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block wx:elif="{{item.node == 'text'}}">
<!--如果是,直接进行-->
<template is="WxEmojiView" data="{{item}}" />
</block>
</template>
<!--循环模版-->
<template name="wxParse1">
<!--<template is="wxParse2" data="{{item}}" />-->
<!--判断是否是标签节点-->
<block wx:if="{{item.node == 'element'}}">
<block wx:if="{{item.tag == 'button'}}">
<button type="default" size="mini">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse2" data="{{item}}" />
</block>
</button>
</block>
<!--li类型-->
<block wx:elif="{{item.tag == 'li'}}">
<view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}">
<view class="{{item.classStr}} wxParse-li-inner">
<view class="{{item.classStr}} wxParse-li-text">
<view class="{{item.classStr}} wxParse-li-circle"></view>
</view>
<view class="{{item.classStr}} wxParse-li-text">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse2" data="{{item}}" />
</block>
</view>
</view>
</view>
</block>
<!--video类型-->
<block wx:elif="{{item.tag == 'video'}}">
<template is="wxParseVideo" data="{{item}}" />
</block>
<!--img类型-->
<block wx:elif="{{item.tag == 'img'}}">
<template is="wxParseImg" data="{{item}}" />
</block>
<!--a类型-->
<block wx:elif="{{item.tag == 'a'}}">
<view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse2" data="{{item}}" />
</block>
</view>
</block>
<block wx:elif="{{item.tag == 'br'}}">
<template is="WxParseBr"></template>
</block>
<!--其他块级标签-->
<block wx:elif="{{item.tagType == 'block'}}">
<view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse2" data="{{item}}" />
</block>
</view>
</block>
<!--内联标签-->
<view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse2" data="{{item}}" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block wx:elif="{{item.node == 'text'}}">
<!--如果是,直接进行-->
<template is="WxEmojiView" data="{{item}}" />
</block>
</template>
<!--循环模版-->
<template name="wxParse2">
<!--<template is="wxParse3" data="{{item}}" />-->
<!--判断是否是标签节点-->
<block wx:if="{{item.node == 'element'}}">
<block wx:if="{{item.tag == 'button'}}">
<button type="default" size="mini">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse3" data="{{item}}" />
</block>
</button>
</block>
<!--li类型-->
<block wx:elif="{{item.tag == 'li'}}">
<view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}">
<view class="{{item.classStr}} wxParse-li-inner">
<view class="{{item.classStr}} wxParse-li-text">
<view class="{{item.classStr}} wxParse-li-circle"></view>
</view>
<view class="{{item.classStr}} wxParse-li-text">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse3" data="{{item}}" />
</block>
</view>
</view>
</view>
</block>
<!--video类型-->
<block wx:elif="{{item.tag == 'video'}}">
<template is="wxParseVideo" data="{{item}}" />
</block>
<!--img类型-->
<block wx:elif="{{item.tag == 'img'}}">
<template is="wxParseImg" data="{{item}}" />
</block>
<!--a类型-->
<block wx:elif="{{item.tag == 'a'}}">
<view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse3" data="{{item}}" />
</block>
</view>
</block>
<block wx:elif="{{item.tag == 'br'}}">
<template is="WxParseBr"></template>
</block>
<!--其他块级标签-->
<block wx:elif="{{item.tagType == 'block'}}">
<view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse3" data="{{item}}" />
</block>
</view>
</block>
<!--内联标签-->
<view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse3" data="{{item}}" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block wx:elif="{{item.node == 'text'}}">
<!--如果是,直接进行-->
<template is="WxEmojiView" data="{{item}}" />
</block>
</template>
<!--循环模版-->
<template name="wxParse3">
<!--<template is="wxParse4" data="{{item}}" />-->
<!--判断是否是标签节点-->
<block wx:if="{{item.node == 'element'}}">
<block wx:if="{{item.tag == 'button'}}">
<button type="default" size="mini">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse4" data="{{item}}" />
</block>
</button>
</block>
<!--li类型-->
<block wx:elif="{{item.tag == 'li'}}">
<view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}">
<view class="{{item.classStr}} wxParse-li-inner">
<view class="{{item.classStr}} wxParse-li-text">
<view class="{{item.classStr}} wxParse-li-circle"></view>
</view>
<view class="{{item.classStr}} wxParse-li-text">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse4" data="{{item}}" />
</block>
</view>
</view>
</view>
</block>
<!--video类型-->
<block wx:elif="{{item.tag == 'video'}}">
<template is="wxParseVideo" data="{{item}}" />
</block>
<!--img类型-->
<block wx:elif="{{item.tag == 'img'}}">
<template is="wxParseImg" data="{{item}}" />
</block>
<!--a类型-->
<block wx:elif="{{item.tag == 'a'}}">
<view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse4" data="{{item}}" />
</block>
</view>
</block>
<block wx:elif="{{item.tag == 'br'}}">
<template is="WxParseBr"></template>
</block>
<!--其他块级标签-->
<block wx:elif="{{item.tagType == 'block'}}">
<view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse4" data="{{item}}" />
</block>
</view>
</block>
<!--内联标签-->
<view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse4" data="{{item}}" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block wx:elif="{{item.node == 'text'}}">
<!--如果是,直接进行-->
<template is="WxEmojiView" data="{{item}}" />
</block>
</template>
<!--循环模版-->
<template name="wxParse4">
<!--<template is="wxParse5" data="{{item}}" />-->
<!--判断是否是标签节点-->
<block wx:if="{{item.node == 'element'}}">
<block wx:if="{{item.tag == 'button'}}">
<button type="default" size="mini">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse5" data="{{item}}" />
</block>
</button>
</block>
<!--li类型-->
<block wx:elif="{{item.tag == 'li'}}">
<view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}">
<view class="{{item.classStr}} wxParse-li-inner">
<view class="{{item.classStr}} wxParse-li-text">
<view class="{{item.classStr}} wxParse-li-circle"></view>
</view>
<view class="{{item.classStr}} wxParse-li-text">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse5" data="{{item}}" />
</block>
</view>
</view>
</view>
</block>
<!--video类型-->
<block wx:elif="{{item.tag == 'video'}}">
<template is="wxParseVideo" data="{{item}}" />
</block>
<!--img类型-->
<block wx:elif="{{item.tag == 'img'}}">
<template is="wxParseImg" data="{{item}}" />
</block>
<!--a类型-->
<block wx:elif="{{item.tag == 'a'}}">
<view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse5" data="{{item}}" />
</block>
</view>
</block>
<block wx:elif="{{item.tag == 'br'}}">
<template is="WxParseBr"></template>
</block>
<!--其他块级标签-->
<block wx:elif="{{item.tagType == 'block'}}">
<view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse5" data="{{item}}" />
</block>
</view>
</block>
<!--内联标签-->
<view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse5" data="{{item}}" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block wx:elif="{{item.node == 'text'}}">
<!--如果是,直接进行-->
<template is="WxEmojiView" data="{{item}}" />
</block>
</template>
<!--循环模版-->
<template name="wxParse5">
<!--<template is="wxParse6" data="{{item}}" />-->
<!--判断是否是标签节点-->
<block wx:if="{{item.node == 'element'}}">
<block wx:if="{{item.tag == 'button'}}">
<button type="default" size="mini">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse6" data="{{item}}" />
</block>
</button>
</block>
<!--li类型-->
<block wx:elif="{{item.tag == 'li'}}">
<view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}">
<view class="{{item.classStr}} wxParse-li-inner">
<view class="{{item.classStr}} wxParse-li-text">
<view class="{{item.classStr}} wxParse-li-circle"></view>
</view>
<view class="{{item.classStr}} wxParse-li-text">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse6" data="{{item}}" />
</block>
</view>
</view>
</view>
</block>
<!--video类型-->
<block wx:elif="{{item.tag == 'video'}}">
<template is="wxParseVideo" data="{{item}}" />
</block>
<!--img类型-->
<block wx:elif="{{item.tag == 'img'}}">
<template is="wxParseImg" data="{{item}}" />
</block>
<!--a类型-->
<block wx:elif="{{item.tag == 'a'}}">
<view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse6" data="{{item}}" />
</block>
</view>
</block>
<block wx:elif="{{item.tag == 'br'}}">
<template is="WxParseBr"></template>
</block>
<!--其他块级标签-->
<block wx:elif="{{item.tagType == 'block'}}">
<view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse6" data="{{item}}" />
</block>
</view>
</block>
<!--内联标签-->
<view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse6" data="{{item}}" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block wx:elif="{{item.node == 'text'}}">
<!--如果是,直接进行-->
<template is="WxEmojiView" data="{{item}}" />
</block>
</template>
<!--循环模版-->
<template name="wxParse6">
<!--<template is="wxParse7" data="{{item}}" />-->
<!--判断是否是标签节点-->
<block wx:if="{{item.node == 'element'}}">
<block wx:if="{{item.tag == 'button'}}">
<button type="default" size="mini">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse7" data="{{item}}" />
</block>
</button>
</block>
<!--li类型-->
<block wx:elif="{{item.tag == 'li'}}">
<view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}">
<view class="{{item.classStr}} wxParse-li-inner">
<view class="{{item.classStr}} wxParse-li-text">
<view class="{{item.classStr}} wxParse-li-circle"></view>
</view>
<view class="{{item.classStr}} wxParse-li-text">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse7" data="{{item}}" />
</block>
</view>
</view>
</view>
</block>
<!--video类型-->
<block wx:elif="{{item.tag == 'video'}}">
<template is="wxParseVideo" data="{{item}}" />
</block>
<!--img类型-->
<block wx:elif="{{item.tag == 'img'}}">
<template is="wxParseImg" data="{{item}}" />
</block>
<!--a类型-->
<block wx:elif="{{item.tag == 'a'}}">
<view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse7" data="{{item}}" />
</block>
</view>
</block>
<block wx:elif="{{item.tag == 'br'}}">
<template is="WxParseBr"></template>
</block>
<!--其他块级标签-->
<block wx:elif="{{item.tagType == 'block'}}">
<view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse7" data="{{item}}" />
</block>
</view>
</block>
<!--内联标签-->
<view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse7" data="{{item}}" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block wx:elif="{{item.node == 'text'}}">
<!--如果是,直接进行-->
<template is="WxEmojiView" data="{{item}}" />
</block>
</template>
<!--循环模版-->
<template name="wxParse7">
<!--<template is="wxParse8" data="{{item}}" />-->
<!--判断是否是标签节点-->
<block wx:if="{{item.node == 'element'}}">
<block wx:if="{{item.tag == 'button'}}">
<button type="default" size="mini">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse8" data="{{item}}" />
</block>
</button>
</block>
<!--li类型-->
<block wx:elif="{{item.tag == 'li'}}">
<view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}">
<view class="{{item.classStr}} wxParse-li-inner">
<view class="{{item.classStr}} wxParse-li-text">
<view class="{{item.classStr}} wxParse-li-circle"></view>
</view>
<view class="{{item.classStr}} wxParse-li-text">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse8" data="{{item}}" />
</block>
</view>
</view>
</view>
</block>
<!--video类型-->
<block wx:elif="{{item.tag == 'video'}}">
<template is="wxParseVideo" data="{{item}}" />
</block>
<!--img类型-->
<block wx:elif="{{item.tag == 'img'}}">
<template is="wxParseImg" data="{{item}}" />
</block>
<!--a类型-->
<block wx:elif="{{item.tag == 'a'}}">
<view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse8" data="{{item}}" />
</block>
</view>
</block>
<block wx:elif="{{item.tag == 'br'}}">
<template is="WxParseBr"></template>
</block>
<!--其他块级标签-->
<block wx:elif="{{item.tagType == 'block'}}">
<view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse8" data="{{item}}" />
</block>
</view>
</block>
<!--内联标签-->
<view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse8" data="{{item}}" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block wx:elif="{{item.node == 'text'}}">
<!--如果是,直接进行-->
<template is="WxEmojiView" data="{{item}}" />
</block>
</template>
<!--循环模版-->
<template name="wxParse8">
<!--<template is="wxParse9" data="{{item}}" />-->
<!--判断是否是标签节点-->
<block wx:if="{{item.node == 'element'}}">
<block wx:if="{{item.tag == 'button'}}">
<button type="default" size="mini">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse9" data="{{item}}" />
</block>
</button>
</block>
<!--li类型-->
<block wx:elif="{{item.tag == 'li'}}">
<view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}">
<view class="{{item.classStr}} wxParse-li-inner">
<view class="{{item.classStr}} wxParse-li-text">
<view class="{{item.classStr}} wxParse-li-circle"></view>
</view>
<view class="{{item.classStr}} wxParse-li-text">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse9" data="{{item}}" />
</block>
</view>
</view>
</view>
</block>
<!--video类型-->
<block wx:elif="{{item.tag == 'video'}}">
<template is="wxParseVideo" data="{{item}}" />
</block>
<!--img类型-->
<block wx:elif="{{item.tag == 'img'}}">
<template is="wxParseImg" data="{{item}}" />
</block>
<!--a类型-->
<block wx:elif="{{item.tag == 'a'}}">
<view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse9" data="{{item}}" />
</block>
</view>
</block>
<block wx:elif="{{item.tag == 'br'}}">
<template is="WxParseBr"></template>
</block>
<!--其他块级标签-->
<block wx:elif="{{item.tagType == 'block'}}">
<view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse9" data="{{item}}" />
</block>
</view>
</block>
<!--内联标签-->
<view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse9" data="{{item}}" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block wx:elif="{{item.node == 'text'}}">
<!--如果是,直接进行-->
<template is="WxEmojiView" data="{{item}}" />
</block>
</template>
<!--循环模版-->
<template name="wxParse9">
<!--<template is="wxParse10" data="{{item}}" />-->
<!--判断是否是标签节点-->
<block wx:if="{{item.node == 'element'}}">
<block wx:if="{{item.tag == 'button'}}">
<button type="default" size="mini">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse10" data="{{item}}" />
</block>
</button>
</block>
<!--li类型-->
<block wx:elif="{{item.tag == 'li'}}">
<view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}">
<view class="{{item.classStr}} wxParse-li-inner">
<view class="{{item.classStr}} wxParse-li-text">
<view class="{{item.classStr}} wxParse-li-circle"></view>
</view>
<view class="{{item.classStr}} wxParse-li-text">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse10" data="{{item}}" />
</block>
</view>
</view>
</view>
</block>
<!--video类型-->
<block wx:elif="{{item.tag == 'video'}}">
<template is="wxParseVideo" data="{{item}}" />
</block>
<!--img类型-->
<block wx:elif="{{item.tag == 'img'}}">
<template is="wxParseImg" data="{{item}}" />
</block>
<!--a类型-->
<block wx:elif="{{item.tag == 'a'}}">
<view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse10" data="{{item}}" />
</block>
</view>
</block>
<block wx:elif="{{item.tag == 'br'}}">
<template is="WxParseBr"></template>
</block>
<!--其他块级标签-->
<block wx:elif="{{item.tagType == 'block'}}">
<view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse10" data="{{item}}" />
</block>
</view>
</block>
<!--内联标签-->
<view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse10" data="{{item}}" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block wx:elif="{{item.node == 'text'}}">
<!--如果是,直接进行-->
<template is="WxEmojiView" data="{{item}}" />
</block>
</template>
<!--循环模版-->
<template name="wxParse10">
<!--<template is="wxParse11" data="{{item}}" />-->
<!--判断是否是标签节点-->
<block wx:if="{{item.node == 'element'}}">
<block wx:if="{{item.tag == 'button'}}">
<button type="default" size="mini">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse11" data="{{item}}" />
</block>
</button>
</block>
<!--li类型-->
<block wx:elif="{{item.tag == 'li'}}">
<view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}">
<view class="{{item.classStr}} wxParse-li-inner">
<view class="{{item.classStr}} wxParse-li-text">
<view class="{{item.classStr}} wxParse-li-circle"></view>
</view>
<view class="{{item.classStr}} wxParse-li-text">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse11" data="{{item}}" />
</block>
</view>
</view>
</view>
</block>
<!--video类型-->
<block wx:elif="{{item.tag == 'video'}}">
<template is="wxParseVideo" data="{{item}}" />
</block>
<!--img类型-->
<block wx:elif="{{item.tag == 'img'}}">
<template is="wxParseImg" data="{{item}}" />
</block>
<!--a类型-->
<block wx:elif="{{item.tag == 'a'}}">
<view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse11" data="{{item}}" />
</block>
</view>
</block>
<block wx:elif="{{item.tag == 'br'}}">
<template is="WxParseBr"></template>
</block>
<!--其他块级标签-->
<block wx:elif="{{item.tagType == 'block'}}">
<view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse11" data="{{item}}" />
</block>
</view>
</block>
<!--内联标签-->
<view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse11" data="{{item}}" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block wx:elif="{{item.node == 'text'}}">
<!--如果是,直接进行-->
<template is="WxEmojiView" data="{{item}}" />
</block>
</template>
<!--循环模版-->
<template name="wxParse11">
<!--<template is="wxParse12" data="{{item}}" />-->
<!--判断是否是标签节点-->
<block wx:if="{{item.node == 'element'}}">
<block wx:if="{{item.tag == 'button'}}">
<button type="default" size="mini">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse12" data="{{item}}" />
</block>
</button>
</block>
<!--li类型-->
<block wx:elif="{{item.tag == 'li'}}">
<view class="{{item.classStr}} wxParse-li" style="{{item.styleStr}}">
<view class="{{item.classStr}} wxParse-li-inner">
<view class="{{item.classStr}} wxParse-li-text">
<view class="{{item.classStr}} wxParse-li-circle"></view>
</view>
<view class="{{item.classStr}} wxParse-li-text">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse12" data="{{item}}" />
</block>
</view>
</view>
</view>
</block>
<!--video类型-->
<block wx:elif="{{item.tag == 'video'}}">
<template is="wxParseVideo" data="{{item}}" />
</block>
<!--img类型-->
<block wx:elif="{{item.tag == 'img'}}">
<template is="wxParseImg" data="{{item}}" />
</block>
<!--a类型-->
<block wx:elif="{{item.tag == 'a'}}">
<view bindtap="wxParseTagATap" class="wxParse-inline {{item.classStr}} wxParse-{{item.tag}}" data-src="{{item.attr.href}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse12" data="{{item}}" />
</block>
</view>
</block>
<block wx:elif="{{item.tag == 'br'}}">
<template is="WxParseBr"></template>
</block>
<!--其他块级标签-->
<block wx:elif="{{item.tagType == 'block'}}">
<view class="{{item.classStr}} wxParse-{{item.tag}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse12" data="{{item}}" />
</block>
</view>
</block>
<!--内联标签-->
<view wx:else class="{{item.classStr}} wxParse-{{item.tag}} wxParse-{{item.tagType}}" style="{{item.styleStr}}">
<block wx:for="{{item.nodes}}" wx:for-item="item" wx:key="">
<template is="wxParse12" data="{{item}}" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block wx:elif="{{item.node == 'text'}}">
<!--如果是,直接进行-->
<template is="WxEmojiView" data="{{item}}" />
</block>
</template>
\ No newline at end of file
/**
* author: Di (微信小程序开发工程师)
* organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
* 垂直微信小程序开发交流社区
*
* github地址: https://github.com/icindy/wxParse
*
* for: 微信小程序富文本解析
* detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
*/
.wxParse{
margin: 0 5px;
font-family: Helvetica,sans-serif;
font-size: 28rpx;
color: #666;
line-height: 1.8;
}
view{
word-break:break-all;
/* overflow:auto; */
}
.wxParse-inline{
display: inline;
margin: 0;
padding: 0;
}
/*//标题 */
.wxParse-div{margin: 0;padding: 0;}
.wxParse-h1{ font-size:2em; margin: .67em 0 }
.wxParse-h2{ font-size:1.5em; margin: .75em 0 }
.wxParse-h3{ font-size:1.17em; margin: .83em 0 }
.wxParse-h4{ margin: 1.12em 0}
.wxParse-h5 { font-size:.83em; margin: 1.5em 0 }
.wxParse-h6{ font-size:.75em; margin: 1.67em 0 }
.wxParse-h1 {
font-size: 18px;
font-weight: 400;
margin-bottom: .9em;
}
.wxParse-h2 {
font-size: 16px;
font-weight: 400;
margin-bottom: .34em;
}
.wxParse-h3 {
font-weight: 400;
font-size: 15px;
margin-bottom: .34em;
}
.wxParse-h4 {
font-weight: 400;
font-size: 14px;
margin-bottom: .24em;
}
.wxParse-h5 {
font-weight: 400;
font-size: 13px;
margin-bottom: .14em;
}
.wxParse-h6 {
font-weight: 400;
font-size: 12px;
margin-bottom: .04em;
}
.wxParse-h1, .wxParse-h2, .wxParse-h3, .wxParse-h4, .wxParse-h5, .wxParse-h6, .wxParse-b, .wxParse-strong { font-weight: bolder }
.wxParse-i,.wxParse-cite,.wxParse-em,.wxParse-var,.wxParse-address{font-style:italic}
.wxParse-pre,.wxParse-tt,.wxParse-code,.wxParse-kbd,.wxParse-samp{font-family:monospace}
.wxParse-pre{white-space:pre}
.wxParse-big{font-size:1.17em}
.wxParse-small,.wxParse-sub,.wxParse-sup{font-size:.83em}
.wxParse-sub{vertical-align:sub}
.wxParse-sup{vertical-align:super}
.wxParse-s,.wxParse-strike,.wxParse-del{text-decoration:line-through}
/*wxparse-自定义个性化的css样式*/
/*增加video的css样式*/
.wxParse-strong,.wxParse-s{display: inline}
.wxParse-a{
color: deepskyblue;
word-break:break-all;
overflow:auto;
}
.wxParse-video{
text-align: center;
margin: 10px 0;
}
.wxParse-video-video{
width:100%;
}
.wxParse-img{
/*background-color: #efefef;*/
overflow: hidden;
}
.wxParse-blockquote {
margin: 0;
padding:10px 0 10px 5px;
font-family:Courier, Calibri,"宋体";
background:#f5f5f5;
border-left: 3px solid #dbdbdb;
}
.wxParse-code,.wxParse-wxxxcode-style{
display: inline;
background:#f5f5f5;
}
.wxParse-ul{
margin: 20rpx 10rpx;
}
.wxParse-li,.wxParse-li-inner{
display: flex;
align-items: baseline;
margin: 10rpx 0;
}
.wxParse-li-text{
align-items: center;
line-height: 20px;
}
.wxParse-li-circle{
display: inline-flex;
width: 5px;
height: 5px;
background-color: #333;
margin-right: 5px;
}
.wxParse-li-square{
display: inline-flex;
width: 10rpx;
height: 10rpx;
background-color: #333;
margin-right: 5px;
}
.wxParse-li-ring{
display: inline-flex;
width: 10rpx;
height: 10rpx;
border: 2rpx solid #333;
border-radius: 50%;
background-color: #fff;
margin-right: 5px;
}
/*.wxParse-table{
width: 100%;
height: 400px;
}
.wxParse-thead,.wxParse-tfoot,.wxParse-tr{
display: flex;
flex-direction: row;
}
.wxParse-th,.wxParse-td{
display: flex;
width: 580px;
overflow: auto;
}*/
.wxParse-u {
text-decoration: underline;
}
.wxParse-hide{
display: none;
}
.WxEmojiView{
align-items: center;
}
.wxEmoji{
width: 16px;
height:16px;
}
.wxParse-tr{
display: flex;
border-right:1px solid #e0e0e0;
border-bottom:1px solid #e0e0e0;
border-top:1px solid #e0e0e0;
}
.wxParse-th,
.wxParse-td{
flex:1;
padding:5px;
font-size:28rpx;
border-left:1px solid #e0e0e0;
word-break: break-all;
}
.wxParse-td:last{
border-top:1px solid #e0e0e0;
}
.wxParse-th{
background:#f0f0f0;
border-top:1px solid #e0e0e0;
}
.wxParse-del{
display: inline;
}
.wxParse-figure {
overflow: hidden;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment