1 | <template>
|
2 | <div class="monitor">
|
3 | <div id="monitor-iframe">
|
4 | <div class="monitor-iframe-holder" ref="iframe"></div>
|
5 | </div>
|
6 | <console class="monitor-console"></console>
|
7 | </div>
|
8 | </template>
|
9 |
|
10 | <script>
|
11 | import { mapActions, mapState } from 'vuex';
|
12 | import progress from 'nprogress';
|
13 | import bus from '@/js/eventbus.js';
|
14 | import createIframe from '@/js/iframe.js';
|
15 | import * as transform from '@/js/transform.js';
|
16 | import proxyConsole from '!raw-loader!babel-loader!@/js/proxy-console';
|
17 | import Console from './console.vue';
|
18 |
|
19 | const sandboxAttributes = [
|
20 |
|
21 | 'allow-forms',
|
22 | 'allow-pointer-lock',
|
23 | 'allow-popups',
|
24 | 'allow-same-origin',
|
25 | 'allow-scripts'
|
26 | ];
|
27 |
|
28 | const replaceQuote = str => str.replace(/__QUOTE_LEFT__/g, '<');
|
29 | const createElement = tag => (content = '', attrs = {}) => {
|
30 | attrs = Object.keys(attrs)
|
31 | .map(key => {
|
32 | return `${key}="${attrs[key]}"`;
|
33 | })
|
34 | .join(' ');
|
35 | return replaceQuote(
|
36 | `__QUOTE_LEFT__${tag} ${attrs}>${content}__QUOTE_LEFT__/${tag}>`
|
37 | );
|
38 | };
|
39 |
|
40 | export default {
|
41 | data() {
|
42 | return {
|
43 | iframe: null,
|
44 | runTimer: null
|
45 | };
|
46 | },
|
47 | components: { Console },
|
48 | computed: {
|
49 | ...mapState(['boxes', 'autoRun', 'dependencies'])
|
50 | },
|
51 | mounted() {
|
52 | this.iframe = createIframe({
|
53 | el: this.$refs.iframe,
|
54 | sandboxAttrs: sandboxAttributes
|
55 | });
|
56 | window.addEventListener('message', this.listenIframe);
|
57 | bus.$on('run', this.run);
|
58 | window.monitor = this;
|
59 | },
|
60 | beforeDestroy() {
|
61 | window.removeEventListener('message', this.listenIframe);
|
62 | },
|
63 | methods: {
|
64 | ...mapActions(['setIframeStatus', 'transform', 'clearLogs', 'addLog']),
|
65 | run() {
|
66 | progress.start();
|
67 | clearTimeout(this.runTimer);
|
68 | this.runTimer = setTimeout(async () => {
|
69 | this.clearLogs();
|
70 | this.setIframeStatus('loading');
|
71 | await this.transform(true);
|
72 | const headStyle = await this.transformCSS();
|
73 | const html = await this.transformHTML();
|
74 | const rawData = await this.transformRawData();
|
75 | const jsScript = await this.transformJS();
|
76 | const runtimeScript = await this.runtimeScript();
|
77 | const runtimeStyle = await this.runtimeStyle();
|
78 | this.iframe.setContent({
|
79 | head: headStyle + runtimeStyle,
|
80 | body: html + runtimeScript + rawData + jsScript
|
81 | });
|
82 | progress.done();
|
83 | }, 1000);
|
84 | },
|
85 | async runtimeScript() {
|
86 | const console = createElement('script')(proxyConsole);
|
87 | const dependencies = this.dependencies.js
|
88 | .map(dependence => `<script src="${dependence}"><\/script>`)
|
89 | .join('\n');
|
90 | return console + '\n' + dependencies;
|
91 | },
|
92 | async runtimeStyle() {
|
93 | const dependencies = this.dependencies.css
|
94 | .map(dependence => `<link rel="stylesheet" href="${dependence}">`)
|
95 | .join('\n');
|
96 | return dependencies;
|
97 | },
|
98 | async transformCSS() {
|
99 | let code = '';
|
100 | if (this.boxes.css) {
|
101 | code = await transform.css(this.boxes.css).then(code => {
|
102 | return code;
|
103 | });
|
104 | }
|
105 | return createElement('style')(code);
|
106 | },
|
107 | async transformHTML() {
|
108 | let code = '';
|
109 | if (this.boxes.html) {
|
110 | code = await transform.html(this.boxes.html);
|
111 | }
|
112 | return code;
|
113 | },
|
114 | async transformJS() {
|
115 | let code = '';
|
116 | if (this.boxes.javascript) {
|
117 | code = await transform.javascript(this.boxes.javascript);
|
118 | }
|
119 | return createElement('script')(code);
|
120 | },
|
121 | async transformRawData() {
|
122 | let code = '';
|
123 | if (this.boxes.rawdata) {
|
124 | code = await transform.rawdata(this.boxes.rawdata);
|
125 | }
|
126 | return createElement('script')(code, { type: 'text/x-rawdata' });
|
127 | },
|
128 | listenIframe({ data = {} }) {
|
129 | if (data.type === 'demoground-console') {
|
130 | if (data.method === 'clear') {
|
131 | this.clearLogs();
|
132 | } else {
|
133 | this.addLog({ type: data.method, message: data.args.join('\\n') });
|
134 | }
|
135 | }
|
136 | }
|
137 | }
|
138 | };
|
139 | </script>
|
140 |
|
141 | <style lang="scss">
|
142 | @import '@/css/index.scss';
|
143 | .monitor {
|
144 | max-height: 100%;
|
145 | box-sizing: border-box;
|
146 | padding: 20px 20px 0 20px;
|
147 | display: flex;
|
148 | flex-direction: column;
|
149 | & #monitor-iframe {
|
150 | width: 100%;
|
151 | height: 100px;
|
152 | flex-grow: 1;
|
153 | background: $c-bg;
|
154 | }
|
155 | }
|
156 | </style>
|