first
This commit is contained in:
65
examples/components/theme/loader/ajax.js
Normal file
65
examples/components/theme/loader/ajax.js
Normal file
@ -0,0 +1,65 @@
|
||||
const defaultError = 'Server Error 500';
|
||||
const defaultTimeout = 'Request Timeout';
|
||||
const xhr = (method, url, data = null, cb) => {
|
||||
return new window.Promise((resolve, reject) => {
|
||||
const xhr = new XMLHttpRequest();
|
||||
const doReject = (xhr) => {
|
||||
reject(xhr.response || xhr.statusText || defaultError);
|
||||
};
|
||||
xhr.open(method, url);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.timeout = 10000;
|
||||
if (cb) cb(xhr);
|
||||
xhr.onload = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
|
||||
let response = xhr.response;
|
||||
const type = xhr.getResponseHeader('Content-Type');
|
||||
if (type.indexOf('zip') > -1) {
|
||||
let filename = 'style.zip';
|
||||
const disposition = xhr.getResponseHeader('content-disposition');
|
||||
if (disposition && disposition.indexOf('attachment') !== -1) {
|
||||
var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
|
||||
var matches = filenameRegex.exec(disposition);
|
||||
if (matches != null && matches[1]) {
|
||||
filename = matches[1].replace(/['"]/g, '');
|
||||
}
|
||||
}
|
||||
var blob = new Blob([response], { type });
|
||||
var zipUrl = URL.createObjectURL(blob);
|
||||
var link = document.createElement('a');
|
||||
link.href = zipUrl;
|
||||
link.download = filename;
|
||||
link.click();
|
||||
resolve(response);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
response = JSON.parse(xhr.response);
|
||||
} catch (e) {}
|
||||
resolve(response);
|
||||
} else {
|
||||
doReject(xhr);
|
||||
}
|
||||
} else {
|
||||
doReject(xhr);
|
||||
}
|
||||
};
|
||||
xhr.onerror = () => {
|
||||
doReject(xhr);
|
||||
};
|
||||
xhr.ontimeout = () => {
|
||||
xhr.abort();
|
||||
reject(defaultTimeout);
|
||||
};
|
||||
xhr.send(JSON.stringify(data));
|
||||
});
|
||||
};
|
||||
|
||||
export const post = (url, data, cb) => {
|
||||
return xhr('POST', url, data, cb);
|
||||
};
|
||||
|
||||
export const get = (url) => {
|
||||
return xhr('GET', url);
|
||||
};
|
24
examples/components/theme/loader/api.js
Normal file
24
examples/components/theme/loader/api.js
Normal file
@ -0,0 +1,24 @@
|
||||
import Element from 'main/index.js';
|
||||
import { post, get } from './ajax';
|
||||
|
||||
const { version } = Element;
|
||||
|
||||
const hostList = {
|
||||
local: 'http://localhost:3008/',
|
||||
alpha: 'https://element-api.ar.elenet.me/element/theme/',
|
||||
production: 'https://element-api.ele.me/element/theme/'
|
||||
};
|
||||
|
||||
const host = hostList[process.env.FAAS_ENV] || hostList.production;
|
||||
|
||||
export const getVars = () => {
|
||||
return get(`${host}getVariable?version=${version}`);
|
||||
};
|
||||
|
||||
export const getTestEle = () => {
|
||||
return get(`${hostList.alpha}getVariable`);
|
||||
};
|
||||
|
||||
export const updateVars = (data, cb) => {
|
||||
return post(`${host}updateVariable?version=${version}`, data, cb);
|
||||
};
|
62
examples/components/theme/loader/docStyle.vue
Normal file
62
examples/components/theme/loader/docStyle.vue
Normal file
@ -0,0 +1,62 @@
|
||||
<script>
|
||||
const ORIGINAL_THEME = '#409EFF';
|
||||
import { get as ajaxGet } from './ajax.js';
|
||||
import { updateDomHeadStyle } from '../utils.js';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
docs: '', // content of docs css
|
||||
theme: ORIGINAL_THEME,
|
||||
asyncCb: true
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
updateDocStyle(e, cb) {
|
||||
const val = e.global['$--color-primary'] || ORIGINAL_THEME;
|
||||
const oldVal = this.theme;
|
||||
const getHandler = (variable, id) => {
|
||||
return () => {
|
||||
let newStyle = this.updateStyle(this[variable], ORIGINAL_THEME, val);
|
||||
updateDomHeadStyle(id, newStyle);
|
||||
this.asyncCb && cb();
|
||||
};
|
||||
};
|
||||
const docsHandler = getHandler('docs', 'docs-style');
|
||||
if (!this.docs) {
|
||||
const links = [].filter.call(document.querySelectorAll('link'), link => {
|
||||
return /docs\..+\.css/.test(link.href || '');
|
||||
});
|
||||
if (links[0]) {
|
||||
this.getCSSString(links[0].href, docsHandler, 'docs');
|
||||
} else {
|
||||
this.asyncCb = false;
|
||||
}
|
||||
} else {
|
||||
docsHandler();
|
||||
}
|
||||
const styles = [].slice.call(document.querySelectorAll('style'))
|
||||
.filter(style => {
|
||||
const text = style.innerText;
|
||||
return new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text);
|
||||
});
|
||||
styles.forEach(style => {
|
||||
const { innerText } = style;
|
||||
if (typeof innerText !== 'string') return;
|
||||
style.innerText = this.updateStyle(innerText, oldVal, val);
|
||||
});
|
||||
this.theme = val;
|
||||
!this.asyncCb && cb();
|
||||
},
|
||||
updateStyle(style, oldColor, newColor) {
|
||||
return style.replace(new RegExp(oldColor, 'ig'), newColor);
|
||||
},
|
||||
getCSSString(url, callback, variable) {
|
||||
ajaxGet(url).then((res) => {
|
||||
this[variable] = res;
|
||||
callback();
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
106
examples/components/theme/loader/index.vue
Normal file
106
examples/components/theme/loader/index.vue
Normal file
@ -0,0 +1,106 @@
|
||||
<script>
|
||||
import bus from '../../../bus.js';
|
||||
import Loading from './loading';
|
||||
import DocStyle from './docStyle';
|
||||
import { updateVars } from './api.js';
|
||||
import { updateDomHeadStyle } from '../utils.js';
|
||||
import {
|
||||
ACTION_APPLY_THEME,
|
||||
ACTION_DOWNLOAD_THEME,
|
||||
ACTION_USER_CONFIG_UPDATE
|
||||
} from '../constant.js';
|
||||
import {
|
||||
loadUserThemeFromLocal,
|
||||
loadPreviewFromLocal
|
||||
} from '../localstorage.js';
|
||||
import { getActionDisplayName } from '../../theme-configurator/utils/utils';
|
||||
|
||||
export default {
|
||||
mixins: [Loading, DocStyle],
|
||||
mounted() {
|
||||
this.checkLocalThemeConfig();
|
||||
bus.$on(ACTION_APPLY_THEME, val => {
|
||||
this.userConfig = val;
|
||||
this.onAction();
|
||||
});
|
||||
bus.$on(ACTION_DOWNLOAD_THEME, (themeConfig, themeName) => {
|
||||
this.onDownload(themeConfig, themeName);
|
||||
});
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
userConfig: {},
|
||||
lastApply: 0
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
applyStyle(res, time) {
|
||||
if (time < this.lastApply) return;
|
||||
this.updateDocs(() => {
|
||||
updateDomHeadStyle('chalk-style', res);
|
||||
});
|
||||
this.lastApply = time;
|
||||
},
|
||||
onDownload(themeConfig, themeName) {
|
||||
this.triggertProgressBar(true);
|
||||
updateVars(
|
||||
Object.assign({}, themeConfig, { download: true }),
|
||||
xhr => {
|
||||
xhr.responseType = 'blob';
|
||||
}
|
||||
).then()
|
||||
.catch((err) => {
|
||||
this.onError(err);
|
||||
})
|
||||
.then(() => {
|
||||
this.triggertProgressBar(false);
|
||||
});
|
||||
ga('send', 'event', 'ThemeConfigurator', 'Download', themeName);
|
||||
},
|
||||
onAction() {
|
||||
this.triggertProgressBar(true);
|
||||
const time = +new Date();
|
||||
updateVars(this.userConfig)
|
||||
.then(res => {
|
||||
this.applyStyle(res, time);
|
||||
})
|
||||
.catch(err => {
|
||||
this.onError(err);
|
||||
})
|
||||
.then(() => {
|
||||
this.triggertProgressBar(false);
|
||||
});
|
||||
},
|
||||
onError(err) {
|
||||
let message;
|
||||
try {
|
||||
message = JSON.parse(err).message;
|
||||
} catch (e) {
|
||||
message = err;
|
||||
}
|
||||
this.$message.error(message);
|
||||
},
|
||||
triggertProgressBar(isLoading) {
|
||||
bus.$emit('user-theme-config-loading', isLoading);
|
||||
},
|
||||
updateDocs(cb) {
|
||||
window.userThemeConfig = JSON.parse(JSON.stringify(this.userConfig));
|
||||
bus.$emit(ACTION_USER_CONFIG_UPDATE, this.userConfig);
|
||||
this.updateDocStyle(this.userConfig, cb);
|
||||
},
|
||||
checkLocalThemeConfig() {
|
||||
// load user local theme
|
||||
const previewConfig = loadPreviewFromLocal();
|
||||
if (previewConfig.type === 'user') {
|
||||
const userConfig = loadUserThemeFromLocal();
|
||||
this.$message(getActionDisplayName('load-local-theme-config'));
|
||||
const config = userConfig.filter(theme => (theme.name === previewConfig.name));
|
||||
if (config && config[0]) {
|
||||
this.userConfig = JSON.parse(config[0].theme);
|
||||
this.onAction();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
35
examples/components/theme/loader/loading/index.vue
Normal file
35
examples/components/theme/loader/loading/index.vue
Normal file
@ -0,0 +1,35 @@
|
||||
<style>
|
||||
.loadingClass {
|
||||
z-index: 0!important;
|
||||
.el-loading-spinner {
|
||||
top: 0%;
|
||||
margin-top: 30%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
|
||||
import bus from '../../../../bus.js';
|
||||
import './progress.js';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
count: 0
|
||||
};
|
||||
},
|
||||
created() {
|
||||
bus.$on('user-theme-config-loading', val => {
|
||||
if (val) {
|
||||
this.count++;
|
||||
if (this.count > 1) return;
|
||||
this.$bar.start();
|
||||
} else {
|
||||
this.count--;
|
||||
if (this.count) return;
|
||||
this.$bar.finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
6
examples/components/theme/loader/loading/progress.js
Normal file
6
examples/components/theme/loader/loading/progress.js
Normal file
@ -0,0 +1,6 @@
|
||||
import Vue from 'vue';
|
||||
import ProgressBar from './progress.vue';
|
||||
|
||||
Vue.prototype.$bar = new Vue(ProgressBar).$mount();
|
||||
|
||||
document.body.appendChild(Vue.prototype.$bar.$el);
|
108
examples/components/theme/loader/loading/progress.vue
Normal file
108
examples/components/theme/loader/loading/progress.vue
Normal file
@ -0,0 +1,108 @@
|
||||
<template>
|
||||
<div class="progress" :style="{
|
||||
'width': percent+'%',
|
||||
'height': height,
|
||||
'background-color': canSuccess? successColor() : failedColor(),
|
||||
'opacity': show ? 1 : 0
|
||||
}"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* eslint-disable */
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
percent: 0,
|
||||
show: false,
|
||||
canSuccess: true,
|
||||
duration: 3000,
|
||||
height: '2px'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
successColor() {
|
||||
return this.userSelectColor()['$--color-primary'] || '#409EFF';
|
||||
},
|
||||
failedColor() {
|
||||
return this.userSelectColor()['$--color-danger'] || '#F56C6C';
|
||||
},
|
||||
userSelectColor() {
|
||||
return window.userThemeConfig && window.userThemeConfig.global || {}
|
||||
},
|
||||
start () {
|
||||
this.show = true
|
||||
this.canSuccess = true
|
||||
if (this._timer) {
|
||||
clearInterval(this._timer)
|
||||
this.percent = 0
|
||||
}
|
||||
// Code from Nuxt.js!
|
||||
this._cut = 10000 / Math.floor(this.duration)
|
||||
this._timer = setInterval(() => {
|
||||
this.increase(this._cut * Math.random())
|
||||
if (this.percent >= 90) {
|
||||
this.percent = 90;
|
||||
}
|
||||
}, 100)
|
||||
return this
|
||||
},
|
||||
set (num) {
|
||||
this.show = true
|
||||
this.canSuccess = true
|
||||
this.percent = Math.floor(num)
|
||||
return this
|
||||
},
|
||||
get () {
|
||||
return Math.floor(this.percent)
|
||||
},
|
||||
increase (num) {
|
||||
this.percent = this.percent + Math.floor(num)
|
||||
return this
|
||||
},
|
||||
decrease (num) {
|
||||
this.percent = this.percent - Math.floor(num)
|
||||
return this
|
||||
},
|
||||
finish () {
|
||||
this.percent = 100
|
||||
this.hide()
|
||||
return this
|
||||
},
|
||||
pause () {
|
||||
clearInterval(this._timer)
|
||||
return this
|
||||
},
|
||||
hide () {
|
||||
clearInterval(this._timer)
|
||||
this._timer = null
|
||||
setTimeout(() => {
|
||||
this.show = false
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.percent = 0
|
||||
}, 200)
|
||||
})
|
||||
}, 500)
|
||||
return this
|
||||
},
|
||||
fail () {
|
||||
this.canSuccess = false
|
||||
return this
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.progress {
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
height: 2px;
|
||||
width: 0%;
|
||||
transition: width 0.2s, opacity 0.4s;
|
||||
opacity: 1;
|
||||
z-index: 999999;
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user