app-class.js 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. /* eslint-disable no-underscore-dangle */
  2. import { getWindow, getDocument } from 'ssr-window';
  3. import { extend, nextFrame } from '../../shared/utils.js';
  4. import { getDevice } from '../../shared/get-device.js';
  5. import { getSupport } from '../../shared/get-support.js';
  6. import Framework7Class from '../../shared/class.js';
  7. import EventsClass from '../../shared/events-class.js';
  8. import ConstructorMethods from '../../shared/constructor-methods.js';
  9. import ModalMethods from '../../shared/modal-methods.js';
  10. import $ from '../../shared/dom7.js';
  11. import loadModule from './load-module.js';
  12. import $jsx from '../../shared/$jsx.js';
  13. class Framework7 extends Framework7Class {
  14. constructor(params) {
  15. if (params === void 0) {
  16. params = {};
  17. }
  18. super(params); // eslint-disable-next-line
  19. if (Framework7.instance && typeof window !== 'undefined') {
  20. throw new Error("Framework7 is already initialized and can't be initialized more than once");
  21. }
  22. const device = getDevice({
  23. userAgent: params.userAgent || undefined
  24. });
  25. const support = getSupport();
  26. const passedParams = extend({}, params); // App Instance
  27. const app = this;
  28. app.device = device;
  29. app.support = support;
  30. const w = getWindow();
  31. const d = getDocument();
  32. Framework7.instance = app; // Default
  33. const defaults = {
  34. version: '1.0.0',
  35. id: 'io.framework7.myapp',
  36. el: 'body',
  37. theme: 'auto',
  38. language: w.navigator.language,
  39. routes: [],
  40. name: 'Framework7',
  41. lazyModulesPath: null,
  42. initOnDeviceReady: true,
  43. init: true,
  44. autoDarkMode: false,
  45. iosTranslucentBars: true,
  46. iosTranslucentModals: true,
  47. component: undefined,
  48. componentUrl: undefined,
  49. userAgent: null,
  50. url: null
  51. }; // Extend defaults with modules params
  52. app.useModulesParams(defaults); // Extend defaults with passed params
  53. app.params = extend(defaults, params);
  54. extend(app, {
  55. // App Id
  56. id: app.params.id,
  57. // App Name
  58. name: app.params.name,
  59. // App version
  60. version: app.params.version,
  61. // Routes
  62. routes: app.params.routes,
  63. // Lang
  64. language: app.params.language,
  65. // Theme
  66. theme: function getTheme() {
  67. if (app.params.theme === 'auto') {
  68. if (device.ios) return 'ios';
  69. if (device.desktop && device.electron) return 'aurora';
  70. return 'md';
  71. }
  72. return app.params.theme;
  73. }(),
  74. // Initially passed parameters
  75. passedParams,
  76. online: w.navigator.onLine
  77. });
  78. if (params.store) app.params.store = params.store; // Save Root
  79. if (app.$el && app.$el[0]) {
  80. app.$el[0].f7 = app;
  81. } // Install Modules
  82. app.useModules(); // Init Store
  83. app.initStore(); // Init
  84. if (app.params.init) {
  85. if (device.cordova && app.params.initOnDeviceReady) {
  86. $(d).on('deviceready', () => {
  87. app.init();
  88. });
  89. } else {
  90. app.init();
  91. }
  92. } // Return app instance
  93. return app;
  94. }
  95. mount(rootEl) {
  96. const app = this;
  97. const window = getWindow();
  98. const document = getDocument();
  99. const $rootEl = $(rootEl || app.params.el).eq(0);
  100. app.$el = $rootEl;
  101. if (app.$el && app.$el[0]) {
  102. app.el = app.$el[0];
  103. app.el.f7 = app;
  104. app.rtl = $rootEl.css('direction') === 'rtl';
  105. } // Auto Dark Mode
  106. const DARK = '(prefers-color-scheme: dark)';
  107. const LIGHT = '(prefers-color-scheme: light)';
  108. app.mq = {};
  109. if (window.matchMedia) {
  110. app.mq.dark = window.matchMedia(DARK);
  111. app.mq.light = window.matchMedia(LIGHT);
  112. }
  113. app.colorSchemeListener = function colorSchemeListener(_ref) {
  114. let {
  115. matches,
  116. media
  117. } = _ref;
  118. if (!matches) {
  119. return;
  120. }
  121. const html = document.querySelector('html');
  122. if (media === DARK) {
  123. html.classList.add('dark');
  124. app.darkMode = true;
  125. app.emit('darkModeChange', true);
  126. } else if (media === LIGHT) {
  127. html.classList.remove('dark');
  128. app.darkMode = false;
  129. app.emit('darkModeChange', false);
  130. }
  131. };
  132. app.emit('mount');
  133. }
  134. initStore() {
  135. const app = this;
  136. if (typeof app.params.store !== 'undefined' && app.params.store.__store) {
  137. app.store = app.params.store;
  138. } else {
  139. app.store = app.createStore(app.params.store);
  140. }
  141. }
  142. enableAutoDarkMode() {
  143. const window = getWindow();
  144. const document = getDocument();
  145. if (!window.matchMedia) return;
  146. const app = this;
  147. const html = document.querySelector('html');
  148. if (app.mq.dark && app.mq.light) {
  149. app.mq.dark.addListener(app.colorSchemeListener);
  150. app.mq.light.addListener(app.colorSchemeListener);
  151. }
  152. if (app.mq.dark && app.mq.dark.matches) {
  153. html.classList.add('dark');
  154. app.darkMode = true;
  155. app.emit('darkModeChange', true);
  156. } else if (app.mq.light && app.mq.light.matches) {
  157. html.classList.remove('dark');
  158. app.darkMode = false;
  159. app.emit('darkModeChange', false);
  160. }
  161. }
  162. disableAutoDarkMode() {
  163. const window = getWindow();
  164. if (!window.matchMedia) return;
  165. const app = this;
  166. if (app.mq.dark) app.mq.dark.removeListener(app.colorSchemeListener);
  167. if (app.mq.light) app.mq.light.removeListener(app.colorSchemeListener);
  168. }
  169. initAppComponent(callback) {
  170. const app = this;
  171. app.router.componentLoader(app.params.component, app.params.componentUrl, {
  172. componentOptions: {
  173. el: app.$el[0]
  174. }
  175. }, el => {
  176. app.$el = $(el);
  177. app.$el[0].f7 = app;
  178. app.$elComponent = el.f7Component;
  179. app.el = app.$el[0];
  180. if (callback) callback();
  181. }, () => {});
  182. }
  183. init(rootEl) {
  184. const app = this;
  185. app.mount(rootEl);
  186. const init = () => {
  187. if (app.initialized) return;
  188. app.$el.addClass('framework7-initializing'); // RTL attr
  189. if (app.rtl) {
  190. $('html').attr('dir', 'rtl');
  191. } // Auto Dark Mode
  192. if (app.params.autoDarkMode) {
  193. app.enableAutoDarkMode();
  194. } // Watch for online/offline state
  195. const window = getWindow();
  196. window.addEventListener('offline', () => {
  197. app.online = false;
  198. app.emit('offline');
  199. app.emit('connection', false);
  200. });
  201. window.addEventListener('online', () => {
  202. app.online = true;
  203. app.emit('online');
  204. app.emit('connection', true);
  205. }); // Root class
  206. app.$el.addClass('framework7-root'); // Theme class
  207. $('html').removeClass('ios md aurora').addClass(app.theme); // iOS Translucent
  208. const device = app.device;
  209. if (app.params.iosTranslucentBars && app.theme === 'ios' && device.ios) {
  210. $('html').addClass('ios-translucent-bars');
  211. }
  212. if (app.params.iosTranslucentModals && app.theme === 'ios' && device.ios) {
  213. $('html').addClass('ios-translucent-modals');
  214. } // Init class
  215. nextFrame(() => {
  216. app.$el.removeClass('framework7-initializing');
  217. }); // Emit, init other modules
  218. app.initialized = true;
  219. app.emit('init');
  220. };
  221. if (app.params.component || app.params.componentUrl) {
  222. app.initAppComponent(() => {
  223. init();
  224. });
  225. } else {
  226. init();
  227. }
  228. return app;
  229. } // eslint-disable-next-line
  230. loadModule() {
  231. return Framework7.loadModule(...arguments);
  232. } // eslint-disable-next-line
  233. loadModules() {
  234. return Framework7.loadModules(...arguments);
  235. }
  236. getVnodeHooks(hook, id) {
  237. const app = this;
  238. if (!app.vnodeHooks || !app.vnodeHooks[hook]) return [];
  239. return app.vnodeHooks[hook][id] || [];
  240. } // eslint-disable-next-line
  241. get $() {
  242. return $;
  243. }
  244. static get Dom7() {
  245. return $;
  246. }
  247. static get $() {
  248. return $;
  249. }
  250. static get device() {
  251. return getDevice();
  252. }
  253. static get support() {
  254. return getSupport();
  255. }
  256. static get Class() {
  257. return Framework7Class;
  258. }
  259. static get Events() {
  260. return EventsClass;
  261. }
  262. }
  263. Framework7.$jsx = $jsx;
  264. Framework7.ModalMethods = ModalMethods;
  265. Framework7.ConstructorMethods = ConstructorMethods;
  266. Framework7.loadModule = loadModule;
  267. Framework7.loadModules = function loadModules(modules) {
  268. return Promise.all(modules.map(module => Framework7.loadModule(module)));
  269. };
  270. export default Framework7;