Commit cc910d09 authored by 徐光星's avatar 徐光星

Merge branch 'feat/v1.5-backup' into 'master'

Feat/v1.5 backup

See merge request !77
parents 41e9c3cf 30b5fdf4
import http from '../service/http.service';
import config from '../config';
export default {
getDetailById(params) {
return http.get(`${config.xyqbH5Host}/quantumBlocks/navigator/detail?navId=${params}`);
}
};
\ No newline at end of file
......@@ -11,6 +11,7 @@ import { EventBus } from '@qg/citrus-ui/src/helper/service/eventBus';
import { getParameterByName } from '../../../service/utils.service';
import localStorage from '../../../service/localStorage.service';
import lazyload from '@qg/cherry-ui/src/lazyload/index';
import { SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION } from 'constants';
// 初始化sentry
if (process.env.SENTRY_ENV !== 'test' && process.env.NODE_ENV === 'production') {
......
......@@ -5,7 +5,7 @@
<meta name="keywords" :content="keywords">
<meta name="description" :content="description">
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no,minimal-ui,viewport-fit=cover">
<link rel="shortcut icon" href="data:image/png;base64" type="image/x-icon" />
<link rel="dns-prefetch" :href="talosHost" />
<link rel="preconnect" href="https://appsync.lkbang.net">
......
......@@ -7,6 +7,7 @@ const hostMap = {
kdspHost: `${protocol}//kdsp-api-test1.liangkebang.net`,
shenceUrl: `${protocol}//bn.xyqb.com/sa?project=default`,
mallHost: `${protocol}//mall-test1.liangkebang.net`,
xyqbH5Host: `${protocol}//mapi-test1.liangkebang.net`,
test: true,
yxmTenantId: 560761,
appIdMap: {
......
export const home = {
app: 'xyqb://homepage',
wxmp: '/pages/index/index',
h5: 'https://xincheng.q-gp.com'
};
export const shopcart = {
app: 'xyqb://shoppingCart?needLogin=1',
wxmp: '/pages/shopcart/index',
h5: 'https://xincheng.q-gp.com/shopCart'
};
export const user = {
app: 'xyqb://my?needLogin=1',
wxmp: '/pages/user/user',
h5: 'https://xincheng.q-gp.com/user'
};
\ No newline at end of file
......@@ -8,6 +8,7 @@ const hostMap = {
kdspHost: `${protocol}//kdsp-api.q-gp.com`,
shenceUrl: `${protocol}//bn.xyqb.com/sa?project=production`,
mallHost: `${protocol}//mall.q-gp.com`,
xyqbH5Host: `${protocol}//h5-api.q-gp.com`,
test: false,
yxmTenantId: 560761,
appIdMap: {
......
......@@ -7,6 +7,7 @@ const hostMap = {
kdspHost: `${protocol}//kdsp-api-test1.liangkebang.net`,
shenceUrl: `${protocol}//bn.xyqb.com/sa?project=default`,
mallHost: `${protocol}//mall-test1.liangkebang.net`,
xyqbH5Host: `${protocol}//mapi-test1.liangkebang.net`,
test: true,
yxmTenantId: 560761,
appIdMap: {
......
......@@ -78,7 +78,7 @@ export default {
return `${APP_PATH}?jumpUrl=${this.link}`;
},
shareOpenMethod() {
return this.pageInfo.shareOpenMethod;
return this.pageInfo.page.props.shareOpenMethod;
}
},
......@@ -159,7 +159,11 @@ export default {
initShareInfo() {
if (EASY_ENV_IS_NODE) return;
const { coverImage, pageName, pageDescribe, shareCoverImage } = this.pageInfo;
const link = `${window.location.origin}${window.location.pathname}?vccToken={token}&tenantId=${localStorage.get('tenantId') || ''}`;
let link = `${window.location.origin}${window.location.pathname}?vccToken={token}&tenantId=${localStorage.get('tenantId') || ''}`;
if (this.getUrlParamsVal('navId') !== false && this.getUrlParamsVal('index') !== false) {
// 向分享URL中填充导航ID与位置索引
link += `&navId=${this.getUrlParamsVal("navId")}&index=${this.getUrlParamsVal('index')}`
}
this.link = link;
const defaultTitle = +localStorage.get('tenantId') === 560761 ? '羊小咩' : '活动页';
let shareUrl = shareCoverImage || coverImage;
......@@ -211,6 +215,15 @@ export default {
this.$refs.crBackTop.$forceUpdate();
});
}
},
getUrlParamsVal(name) {
let query = window.location.search.substring(1);
let vars = query.split('&');
for (let i = 0; i < vars.length; i++) {
let pair = vars[i].split("=");
if (pair[0] == name) return pair[1];
}
return false;
}
},
}
......
......@@ -7,15 +7,20 @@ import PageBottomTip from '../../component/PageBottomTip/index.vue';
import GridLayout from '../../component/VueGridLayout/GridLayout.vue';
import GridItem from '../../component/VueGridLayout/GridItem.vue';
import TransformStyleMixin from '@/page/mixins/transformStyle.mixin';
import BottomNavStyleMixin from '@/page/mixins/BottomNavStyle.mixin';
import SaMixin from '@/page/mixins/sa.mixin';
import { getStyle, debounce, isApp, isWxMp, getParameterByName } from '@/service/utils.service';
import DisableTouchMixin from '@/page/mixins/disableTouch.mixin';
import { setAppTitleColor } from '@/service/color.service';
import { EventBus } from '@qg/citrus-ui/src/helper/service/eventBus';
import localStorage from '@/service/localStorage.service';
import { home, shopcart, user } from '@/config/nav.config';
import { isWxMp, isApp } from '@/service/utils.service';
import Bridge from '@qg/js-bridge';
import MpBridge from '@qg/citrus-ui/src/helper/service/mp';
import navigatorApi from '@/api/navigator.api';
@Component({ components: { FreedomContainer, GridLayout, GridItem, PageBottomTip, BackTop, EmptyState }, name: 'Activity'})
export default class Activity extends Mixins(TransformStyleMixin, SaMixin, DisableTouchMixin) {
export default class Activity extends Mixins(TransformStyleMixin, BottomNavStyleMixin, SaMixin, DisableTouchMixin) {
@Getter('pageData') pageData;
@State(state => state.activity.pageInfo.pageName) pageName;
......@@ -37,6 +42,8 @@ export default class Activity extends Mixins(TransformStyleMixin, SaMixin, Disab
};
isLayoutComReady = false;
showBackTop = false;
navIndex = 0;
navigatorConfig = null;
targetEle: HTMLElement | null = null;
loading: boolean = true;
modfiTabsStyleDebounce = debounce(this.modfiTabsStyle, 300);
......@@ -102,6 +109,9 @@ export default class Activity extends Mixins(TransformStyleMixin, SaMixin, Disab
}
}
mounted() {
// console.log(this.$route, 'navIndex');
// const { index } = this.$route.query();
// console.log(this.navigatorConfig, 999);
if (!isApp && !isWxMp && !EASY_ENV_IS_NODE) {
this.pageData.elements = this.pageData.elements.filter(v => v.name !== 'cs-search-bar');
}
......@@ -122,10 +132,23 @@ export default class Activity extends Mixins(TransformStyleMixin, SaMixin, Disab
}
}
});
console.log(this.$route);
// 获取导航配置,不走redis改异步是因为页面缓存会把导航部分也缓存进去
const {navId, index} = this.$route.query;
if (navId && index) {
this.getNavigatorConfig(navId, index);
}
}
this.layoutReadyEvent();
}
fetchApi(options) {
async getNavigatorConfig(navId, index) {
// 获取导航配置
const [res] = await navigatorApi.getDetailById(navId);
this.navigatorConfig = res;
this.navIndex = index;
// console.log(res, 'a123');
}
async fetchApi(options) {
const { store, route } = options;
const { pageId } = route.params;
return store.dispatch('getPageDate', { pageId });
......@@ -254,4 +277,147 @@ export default class Activity extends Mixins(TransformStyleMixin, SaMixin, Disab
}
}
}
// 添加或修改url中的参数
addOrEditUrlParams(url, paramName, replaceWith) {
if (url.indexOf(paramName) > -1) {
const re = new RegExp(paramName + '=[^&]*', 'gi')
return url.replace(re, paramName + '=' + replaceWith)
} else {
const paraStr = paramName + '=' + replaceWith;
const idx = url.indexOf('?');
if (idx < 0) {
url += '?';
} else if (idx >= 0 && idx !== url.length - 1) {
url += '&';
}
url = url + paraStr;
}
return url;
}
handleNavUrl(nav, isCurrent) {
if (isCurrent) { return; }
const token = localStorage.get('vccToken') || '';
console.log(token, 'token');
// 用于传递新橙参数,避免新橙H5活动中含有遮罩层
const { vccChannel, fromHost } = this.$route.query;
const { pageType, pageUrl } = nav;
console.log(isApp, isWxMp, pageType);
let nativeBridge;
let mpBridge;
if (+pageType === 1) { // 功能页面
if (pageUrl === 'home') {
if (isApp) {
nativeBridge = new Bridge();
nativeBridge.openNewUrl({
data: {
// 需要打开的新链接
newUrl: home.app,
},
});
} else if (isWxMp) {
mpBridge = new MpBridge();
const jumpConfig = {
// 需要打开的新链接
newUrl: home.wxmp,
type: 'switchTab'
};
mpBridge.openNewUrl(jumpConfig);
} else {
let url = home.h5;
if (vccChannel) { url = this.addOrEditUrlParams(url, 'vccChannel', vccChannel); }
if (fromHost) { url = this.addOrEditUrlParams(url, 'fromHost', fromHost); }
if (token) { url = this.addOrEditUrlParams(url, 'vccToken', token); }
console.log(url, 1);
window.location.href = url;
}
}
if (pageUrl === 'shopcart') {
if (isApp) {
nativeBridge = new Bridge();
nativeBridge.openNewUrl({
data: {
// 需要打开的新链接
newUrl: shopcart.app,
},
});
} else if (isWxMp) {
mpBridge = new MpBridge();
const jumpConfig = {
// 需要打开的新链接
newUrl: shopcart.wxmp,
type: 'switchTab'
};
mpBridge.openNewUrl(jumpConfig);
} else {
let url = shopcart.h5;
if (vccChannel) { url = this.addOrEditUrlParams(url, 'vccChannel', vccChannel); }
if (fromHost) { url = this.addOrEditUrlParams(url, 'fromHost', fromHost); }
if (token) { url = this.addOrEditUrlParams(url, 'vccToken', token); }
console.log(url, 2);
window.location.href = url;
}
}
if (pageUrl === 'user') {
if (isApp) {
nativeBridge = new Bridge();
nativeBridge.openNewUrl({
data: {
// 需要打开的新链接
newUrl: user.app,
},
});
} else if (isWxMp) {
mpBridge = new MpBridge();
const jumpConfig = {
// 需要打开的新链接
newUrl: user.wxmp,
type: 'switchTab'
};
mpBridge.openNewUrl(jumpConfig);
} else {
let url = user.h5;
if (vccChannel) { url = this.addOrEditUrlParams(url, 'vccChannel', vccChannel); }
if (fromHost) { url = this.addOrEditUrlParams(url, 'fromHost', fromHost); }
if (token) { url = this.addOrEditUrlParams(url, 'vccToken', token); }
console.log(url, 3);
window.location.href = url;
}
}
return;
} else {
let url = pageUrl;
if (!isApp && !isWxMp) {
if (vccChannel) { url = this.addOrEditUrlParams(url, 'vccChannel', vccChannel); }
if (fromHost) { url = this.addOrEditUrlParams(url, 'fromHost', fromHost); }
}
if (token) { url = this.addOrEditUrlParams(url, 'vccToken', token); }
console.log(url, 5);
window.location.href = url;
// if (isApp) {
// nativeBridge = new Bridge();
// nativeBridge.openNewUrl({
// data: {
// // 需要打开的新链接
// newUrl: `xyqb://openHttp?jumpUrl=${pageUrl}`
// },
// });
// window.location.href = pageUrl;
// nativeBridge = null;
// } else if (isWxMp) {
// mpBridge = new MpBridge();
// const jumpConfig = {
// // 需要打开的新链接
// newUrl: pageUrl
// };
// mpBridge.openNewUrl(jumpConfig);
// mpBridge = null;
// window.location.href = pageUrl;
// } else {
// if (vccChannel) { url = this.addOrEditUrlParams(url, 'vccChannel', vccChannel); }
// if (fromHost) { url = this.addOrEditUrlParams(url, 'fromHost', fromHost); }
// window.location.href = url;
// }
}
}
}
<template>
<div class="activity" :style="transformStyle(pageData.commonStyle)">
<div class="pageContent">
<div class="activity" :class="{hasBottomNav: navigatorConfig}" :style="transformStyle(pageData.commonStyle)">
<template v-if="!noPageData && tenantIdCorrect">
<div class="layout">
<div :style="transformStyle(item.commonStyle, item.point, item.name)" v-for="(item, index) in pageData.elements"
......@@ -22,15 +23,75 @@
</template>
<empty-state v-else />
</div>
<!-- 底部导航 -->
<div v-if="navigatorConfig" class="bottomNav" :style="computedNavContainerStyle(navigatorConfig)">
<div
class="navItem"
:class="{pic: item.type == 2, current: +navIndex === index}"
v-for="(item, index) in navigatorConfig.navigatorData"
:key="index"
@click.stop="handleNavUrl(item, +navIndex === index)"
>
<img class="icon" :src="+navIndex === index ? item.selectIcon : item.icon" alt="">
<span v-if="item.type == 1 && item.name" class="text" :style="computedNavTextStyle(item, +navIndex === index)">{{item.name}}</span>
</div>
</div>
</div>
</template>
<script lang="ts" src="./index.ts"></script>
<style lang="less" scoped>
@deep: ~'>>>';
.pageContent{
width: 100%;
height: 100%;
position: relative;
.bottomNav{
box-sizing: content-box;
width: 100%;
position: fixed;
bottom: 0;
left: 0;
z-index: 899;
padding-top: 0;
padding-left: 4px;
padding-right: 4px;
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
display: flex;
justify-content: space-around;
.navItem{
width: 62px;
height: 55px;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
&.pic{
.icon{
max-width: 40px;
max-height: 40px;
}
}
.icon{
max-width: 35px;
max-height: 35px;
}
.text{
margin-top: 3px;
text-align: center;
font-size: 10px;
}
}
}
}
.activity {
width: 100%;
min-height: 100%;
background-color: rgb(244, 244, 244);
&.hasBottomNav{
padding-bottom: calc(constant(safe-area-inset-bottom) + 55px);
padding-bottom: calc(env(safe-area-inset-bottom) + 55px);
}
// box-shadow: 2px 0 10px rgba(0, 0, 0, 0.2);
// overflow-x: hidden;
// overflow-y: scroll;
......
// 用于处理底部导航样式
import { Component, Vue } from 'vue-property-decorator';
@Component({ name: 'BottomNavStyleMixin' })
export default class BottomNavStyleMixin extends Vue {
isHexColor(str) {
const reg = /^(?:#[A-Fa-f0-9]{3}|#[A-Fa-f0-9]{6})$/;
return reg.test(str);
}
computedNavContainerStyle(navGlobalConfig = {}) {
const style = {};
// 如果同时设置了背景色和背景图,优先使用背景图
const { bgColor, bgImg } = navGlobalConfig;
if (bgImg) {
style.backgroundImage = `url(${bgImg})`;
style.backgroundRepeat = 'no-repeat';
style.backgroundSize = 'cover';
} else if (!bgImg && bgColor) {
// 没有背景图 使用背景色
style.backgroundColor = bgColor.indexOf('#') === 0 ? bgColor : `#${bgColor}`;
} else {
// 默认白色背景
style.backgroundColor = '#fff';
}
return style;
}
computedNavTextStyle(navConfig = {}, isCurrent = false) {
const style = {};
const { color, selectColor } = navConfig;
if (isCurrent) {
style.color = selectColor && this.isHexColor(selectColor) ? selectColor : '#fff';
} else {
style.color = color && this.isHexColor(color) ? color : '#fff';
}
return style;
// if (co)
}
}
......@@ -28,7 +28,7 @@ export default class EditorModule implements Module<EditorState, RootState> {
} else {
commit(SET_EMPTY_PAGE, true);
}
}
},
};
mutations: MutationTree<EditorState> = {
......
......@@ -53,6 +53,8 @@ export interface PageInfo {
}
export const defaultState = {
navigatorConfig: null,
navIndex: '',
noPageData: false,
curChildIndex: null,
pageInfo: {
......@@ -100,4 +102,6 @@ export default interface EditorState {
templateList: any[];
rowHeight: number;
gridLayout: GridLayout;
navigatorConfig: any;
navIndex: any;
}
\ No newline at end of file
{
"api": {
"apiHost": "https://quantum-blocks-test1.liangkebang.net",
"h5Host": "https://quantum-h5-test1.liangkebang.net",
"opapiHost": "https://opapi-test1.liangkebang.net",
"passportHost": "https://passportapi-test1.liangkebang.net",
"talosHost": "https://talos-test1.liangkebang.net",
"kdspHost": "https://kdsp-api-test1.liangkebang.net",
"apiHost": "https://quantum-blocks-qa.liangkebang.net",
"h5Host": "https://quantum-h5-qa.liangkebang.net",
"opapiHost": "https://opapi-qa.liangkebang.net",
"passportHost": "https://passportapi-qa.liangkebang.net",
"talosHost": "https://talos-qa.liangkebang.net",
"kdspHost": "https://kdsp-api-qa.liangkebang.net",
"loginUrl": "",
"h5ShopHost": "https://tenet-test1.liangkebang.net/#",
"mallHost": "https://mall-test1.liangkebang.net",
"h5ShopHost": "https://tenet-qa.liangkebang.net/#",
"mallHost": "https://mall-qa.liangkebang.net",
"xyqbH5Host": "https://mapi-qa.liangkebang.net",
"yxmTenantId": 560761,
"appIdMap": {
"560761": "wxe16bf9293671506c",
......@@ -16,13 +17,34 @@
}
},
"redis": {
"port": "32625",
"host": "172.17.5.3",
"port": "30556",
"host": "172.17.5.22",
"password": "",
"db": 0
},
"qiniu": {
"qiniuUpHost": "https://up-z0.qiniup.com",
"qiniuHost": "https://appsync.lkbang.net"
},
"vertify": {
"/FZz8NUb3x0.txt": "ca1c52b4801a7741ccdbbe47797d574e",
"/Ra6UCOeIhV.txt": "0b54b6896ca0bdaa53b9b4e49c403f30",
"/2OqnbvHjoq.txt": "90e68e2c196781968dba89bd5e6ac182",
"/9HFuiOJ4BG.txt": "97efde44dc917901a8ca25a0feb54ad8",
"/bAgsGUG45y.txt": "25638138b18af91b2dd64db906b056a4",
"/c8PA5Gybed.txt": "03f5c047a87a73854381c1d19c50fd68",
"/J5QboPVm8N.txt": "8fb57cfb856841b9d877e61df0729232",
"/Jb5PMgT5lb.txt": "59297e3b609ad1c26e5b334fa56af181",
"/NqUTl0J6Ed.txt": "cbc525fd71a2beb519d349084dece8da",
"/qsBZfgOk4y.txt": "8a154639c8af235d06e4b291463fb7a0",
"/tPICMyeJfv.txt": "11f2efef0527b792380784ea1b4a4b65",
"/UBRJar2pST.txt": "3c6152f098bc4e3edad5b36f550cd268",
"/yB3tnMTnRc.txt": "5c9d1a08b3bda49beb0f950b1cdec27b",
"/gAnCcSGwFu.txt": "a8ae84f68ea72f82beff325a59fd2c58",
"/qqCExxuPJ7.txt": "a1da927722f735a09065407e32beb56a",
"/86b9af10a6b70c8be78c9095b24448ec.html": "5c9d1a08b3bda49beb0f950b1cdec27b",
"/bd_mapp_domaincer_25998612.txt": "a7ff4d126c6a7b90c73356e410a163b9",
"/MP_verify_f4VWFoFpHgzmqFbo.txt": "f4VWFoFpHgzmqFbo",
"/MP_verify_KbcgqpEmfvW0J3Ts.txt": "KbcgqpEmfvW0J3Ts"
}
}
\ No newline at end of file
{"apiHost":"https://quantum-blocks-test1.liangkebang.net","h5Host":"https://quantum-h5-test1.liangkebang.net","opapiHost":"https://opapi-test1.liangkebang.net","passportHost":"https://passportapi-test1.liangkebang.net","talosHost":"https://talos-test1.liangkebang.net","kdspHost":"https://kdsp-api-test1.liangkebang.net","loginUrl":"","h5ShopHost":"https://tenet-test1.liangkebang.net/#","mallHost":"https://mall-test1.liangkebang.net","yxmTenantId":560761,"appIdMap":{"560761":"wxe16bf9293671506c","560867":"wxccb8435d68e8c7d6"},"qiniuUpHost":"https://up-z0.qiniup.com","qiniuHost":"https://appsync.lkbang.net"}
\ No newline at end of file
{"apiHost":"https://quantum-blocks-qa.liangkebang.net","h5Host":"https://quantum-h5-qa.liangkebang.net","opapiHost":"https://opapi-qa.liangkebang.net","passportHost":"https://passportapi-qa.liangkebang.net","talosHost":"https://talos-qa.liangkebang.net","kdspHost":"https://kdsp-api-qa.liangkebang.net","loginUrl":"","h5ShopHost":"https://tenet-qa.liangkebang.net/#","mallHost":"https://mall-qa.liangkebang.net","xyqbH5Host":"https://mapi-qa.liangkebang.net","yxmTenantId":560761,"appIdMap":{"560761":"wxe16bf9293671506c","560867":"wxccb8435d68e8c7d6"},"qiniuUpHost":"https://up-z0.qiniup.com","qiniuHost":"https://appsync.lkbang.net"}
\ No newline at end of file
......@@ -17,4 +17,8 @@ export default {
'/yB3tnMTnRc.txt': fs.readFileSync(path.join(__dirname, '/wxVertify/yB3tnMTnRc.txt')),
'/gAnCcSGwFu.txt': fs.readFileSync(path.join(__dirname, '/wxVertify/gAnCcSGwFu.txt')),
'/qqCExxuPJ7.txt': fs.readFileSync(path.join(__dirname, '/wxVertify/qqCExxuPJ7.txt')),
'/86b9af10a6b70c8be78c9095b24448ec.html': fs.readFileSync(path.join(__dirname, '/wxVertify/86b9af10a6b70c8be78c9095b24448ec.html')),
'/bd_mapp_domaincer_25998612.txt': fs.readFileSync(path.join(__dirname, '/wxVertify/bd_mapp_domaincer_25998612.txt')),
'/MP_verify_f4VWFoFpHgzmqFbo.txt': fs.readFileSync(path.join(__dirname, '/wxVertify/MP_verify_f4VWFoFpHgzmqFbo.txt')),
'/MP_verify_KbcgqpEmfvW0J3Ts.txt': fs.readFileSync(path.join(__dirname, '/wxVertify/MP_verify_KbcgqpEmfvW0J3Ts.txt')),
};
86b9af10a6b70c8be78c9095b24448ec
\ No newline at end of file
KbcgqpEmfvW0J3Ts
\ No newline at end of file
f4VWFoFpHgzmqFbo
\ No newline at end of file
a7ff4d126c6a7b90c73356e410a163b9
\ No newline at end of file
......@@ -8,7 +8,7 @@
"test": "cross-env NODE_ENV=production EGG_SERVER_ENV=sit egg-scripts start --port 80 --workers 1",
"stop": "egg-scripts stop",
"backend": "nohup egg-scripts start --port 7001 --workers 4",
"dev": "cross-env NODE_ENV=test APOLLO_CLUSTER=k8s NAMESPACE=test1 npm run apollo && egg-bin dev -r egg-ts-helper/register",
"dev": "cross-env NODE_ENV=test APOLLO_CLUSTER=k8s NAMESPACE=qa npm run apollo && egg-bin dev -r egg-ts-helper/register",
"debug": "egg-bin debug -r egg-ts-helper/register",
"apollo": "node bin/apollo.js",
"build": "cross-env NODE_ENV=production APOLLO_CLUSTER=3C npm run apollo && cross-env COS_ENV=production easy build --devtool",
......
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