summaryrefslogtreecommitdiff
path: root/src/client/app/init.ts
blob: 18f510ea249cb95df46342ee05c9afb0d11a3da4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/**
 * App initializer
 */

import Vue from 'vue';
import Vuex from 'vuex';
import VueRouter from 'vue-router';
import VModal from 'vue-js-modal';
import * as TreeView from 'vue-json-tree-view';
import VAnimateCss from 'v-animate-css';
import Element from 'element-ui';
import ElementLocaleEn from 'element-ui/lib/locale/lang/en';
import ElementLocaleJa from 'element-ui/lib/locale/lang/ja';

import App from './app.vue';
import checkForUpdate from './common/scripts/check-for-update';
import MiOS, { API } from './mios';
import { version, codename, lang } from './config';

let elementLocale;
switch (lang) {
	case 'ja': elementLocale = ElementLocaleJa; break;
	case 'en': elementLocale = ElementLocaleEn; break;
	default: elementLocale = ElementLocaleEn; break;
}

Vue.use(Vuex);
Vue.use(VueRouter);
Vue.use(VModal);
Vue.use(TreeView);
Vue.use(VAnimateCss);
Vue.use(Element, { locale: elementLocale });

// Register global directives
require('./common/views/directives');

// Register global components
require('./common/views/components');
require('./common/views/widgets');

// Register global filters
require('./common/views/filters');

Vue.mixin({
	destroyed(this: any) {
		if (this.$el.parentNode) {
			this.$el.parentNode.removeChild(this.$el);
		}
	}
});

/**
 * APP ENTRY POINT!
 */

console.info(`Misskey v${version} (${codename})`);
console.info(
	'%c%i18n:common.do-not-copy-paste%',
	'color: red; background: yellow; font-size: 16px; font-weight: bold;');

// BootTimer解除
window.clearTimeout((window as any).mkBootTimer);
delete (window as any).mkBootTimer;

//#region Set lang attr
const html = document.documentElement;
html.setAttribute('lang', lang);
//#endregion

// iOSでプライベートモードだとlocalStorageが使えないので既存のメソッドを上書きする
try {
	localStorage.setItem('kyoppie', 'yuppie');
} catch (e) {
	Storage.prototype.setItem = () => { }; // noop
}

// クライアントを更新すべきならする
if (localStorage.getItem('should-refresh') == 'true') {
	localStorage.removeItem('should-refresh');
	location.reload(true);
}

// MiOSを初期化してコールバックする
export default (callback: (launch: (router: VueRouter, api?: (os: MiOS) => API) => [Vue, MiOS]) => void, sw = false) => {
	const os = new MiOS(sw);

	os.init(() => {
		// アプリ基底要素マウント
		document.body.innerHTML = '<div id="app"></div>';

		const launch = (router: VueRouter, api?: (os: MiOS) => API) => {
			os.apis = api ? api(os) : null;

			//#region Dark/Light
			Vue.mixin({
				data() {
					return {
						_unwatchDarkmode_: null
					};
				},
				mounted() {
					const apply = v => {
						if (this.$el.setAttribute == null) return;
						if (v) {
							this.$el.setAttribute('data-darkmode', 'true');
						} else {
							this.$el.removeAttribute('data-darkmode');
						}
					};

					apply(os.store.state.device.darkmode);

					this._unwatchDarkmode_ = os.store.watch(s => {
						return s.device.darkmode;
					}, apply);
				},
				beforeDestroy() {
					this._unwatchDarkmode_();
				}
			});

			os.store.watch(s => {
				return s.device.darkmode;
			}, v => {
				if (v) {
					document.documentElement.setAttribute('data-darkmode', 'true');
				} else {
					document.documentElement.removeAttribute('data-darkmode');
				}
			});
			//#endregion

			Vue.mixin({
				data() {
					return {
						os,
						api: os.api,
						apis: os.apis
					};
				}
			});

			const app = new Vue({
				store: os.store,
				router,
				render: createEl => createEl(App)
			});

			os.app = app;

			// マウント
			app.$mount('#app');

			return [app, os] as [Vue, MiOS];
		};

		try {
			callback(launch);
		} catch (e) {
			panic(e);
		}

		//#region 更新チェック
		const preventUpdate = os.store.state.device.preventUpdate;
		if (!preventUpdate) {
			setTimeout(() => {
				checkForUpdate(os);
			}, 3000);
		}
		//#endregion
	});
};

// BSoD
function panic(e) {
	console.error(e);

	// Display blue screen
	document.documentElement.style.background = '#1269e2';
	document.body.innerHTML =
		'<div id="error">'
			+ '<h1>:( 致命的な問題が発生しました。</h1>'
			+ '<p>お使いのブラウザ(またはOS)のバージョンを更新すると解決する可能性があります。</p>'
			+ '<hr>'
			+ `<p>エラーコード: ${e.toString()}</p>`
			+ `<p>ブラウザ バージョン: ${navigator.userAgent}</p>`
			+ `<p>クライアント バージョン: ${version}</p>`
			+ '<hr>'
			+ '<p>問題が解決しない場合は、上記の情報をお書き添えの上 syuilotan@yahoo.co.jp までご連絡ください。</p>'
			+ '<p>Thank you for using Misskey.</p>'
		+ '</div>';

	// TODO: Report the bug
}