world-app.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618
  1. import page from '/lib/page.mjs';
  2. class WorldApp {
  3. constructor(userAlias, worldName, saveName) {
  4. console.log("app constructor");
  5. this.userAlias = userAlias;
  6. this.worldName = worldName;
  7. this.saveName = saveName;
  8. //this.worlds = {};
  9. this.language = _LangManager.language;
  10. this.options = {
  11. query: 'pathname=' + window.location.pathname.slice(1,
  12. window.location.pathname.lastIndexOf("/")),
  13. secure: window.location.protocol === "https:",
  14. reconnection: false,
  15. path: '',
  16. transports: ['websocket']
  17. }
  18. //window.location.host
  19. var socket = io.connect(window._app.reflectorHost, this.options);
  20. const parse = (msg) => {
  21. this.parseAppInstancesData(msg);
  22. }
  23. socket.on('getWebAppUpdate', msg => parse.call(this, msg));
  24. socket.on("connect", function () {
  25. let noty = new Noty({
  26. text: 'Connected to Reflector!',
  27. timeout: 2000,
  28. theme: 'mint',
  29. layout: 'bottomRight',
  30. type: 'success'
  31. });
  32. noty.show();
  33. })
  34. socket.on('connect_error', function (err) {
  35. console.log(err);
  36. var errDiv = document.createElement("div");
  37. errDiv.innerHTML = "<div class='vwf-err' style='z-index: 10; position: absolute; top: 80px; right: 50px'>Connection error to Reflector!" + err + "</div>";
  38. document.querySelector('body').appendChild(errDiv);
  39. let noty = new Noty({
  40. text: 'Connection error to Reflector! ' + err,
  41. theme: 'mint',
  42. layout: 'bottomRight',
  43. type: 'error'
  44. });
  45. noty.show();
  46. });
  47. }
  48. async initWorldGUI() {
  49. let self = this;
  50. let user = this.userAlias;
  51. let space = this.worldName;
  52. let saveName = this.saveName;
  53. let el = document.createElement("div");
  54. el.setAttribute("id", "aboutWorld");
  55. document.body.appendChild(el);
  56. //get user
  57. // let userID = await _LCSDB.get('~@' + user).once().then();
  58. // let userPub = Object.keys(userID).filter(el => (el !== '_'))[0].slice(1);
  59. let userPub = await _LCSDB.get('users').get(user).get('pub').once().then();
  60. var db = _LCSDB.user(userPub);
  61. if (_LCSUSER.is) {
  62. if (_LCSUSER.is.alias == user)
  63. db = _LCSUSER;
  64. }
  65. let worldCardGUI = {
  66. $cell: true,
  67. id: 'worldCard',
  68. $type: "div",
  69. _worldInfo: {},
  70. _refresh: function (data) {
  71. this._worldInfo = data
  72. },
  73. _getWorldInfo: async function () {
  74. //get space for user
  75. let world = await db.get('worlds').get(space).once().then();
  76. if (world) {
  77. await db.get('worlds').get(space).get('info_json').on((res) => {
  78. if (res && res !== 'null') {
  79. if (res.file && res.file !== 'null') {
  80. let worldDesc = JSON.parse(res.file);
  81. let root = Object.keys(worldDesc)[0];
  82. var appInfo = worldDesc[root]['en'];
  83. let langID = localStorage.getItem('krestianstvo_locale');
  84. if (langID) {
  85. appInfo = worldDesc[root][langID]
  86. }
  87. let info = {
  88. 'worldName': space,
  89. 'created': res.created ? res.created : res.modified,
  90. 'modified': res.modified,
  91. 'type': 'proto',
  92. 'userAlias': user,
  93. 'info': appInfo
  94. }
  95. this._refresh(info);
  96. }
  97. }
  98. }).then();
  99. } else {
  100. this._refresh();
  101. }
  102. },
  103. _getStateInfo: async function () {
  104. //get space for user
  105. let docName = 'savestate_/' + space + '/' + saveName + '_info_vwf_json';
  106. let world = await db.get('documents').get(space).get(docName).once().then();
  107. if (world) {
  108. db.get('documents').get(space).get(docName).on((res) => {
  109. if (res && res !== 'null') {
  110. if (res.file && res.file !== 'null') {
  111. let worldDesc = JSON.parse(res.file);
  112. let root = Object.keys(worldDesc)[0];
  113. var appInfo = worldDesc[root]['en'];
  114. let langID = localStorage.getItem('krestianstvo_locale');
  115. if (langID) {
  116. appInfo = worldDesc[root][langID]
  117. }
  118. let info = {
  119. 'worldName': space + '/load/' + saveName,
  120. 'created': res.created ? res.created : res.modified,
  121. 'modified': res.modified,
  122. 'type': 'saveState',
  123. 'userAlias': user,
  124. 'info': appInfo
  125. }
  126. this._refresh(info);
  127. }
  128. }
  129. });
  130. } else {
  131. this._refresh();
  132. }
  133. },
  134. $init: async function () {
  135. //get space for user
  136. if (!saveName) {
  137. await this._getWorldInfo();
  138. } else {
  139. await this._getStateInfo();
  140. }
  141. },
  142. $update: function () {
  143. console.log(this._worldInfo);
  144. this.$components = [this._updateCard()]
  145. },
  146. $components: [],
  147. _updateCard: function () {
  148. let desc = this._worldInfo;
  149. if (!desc) {
  150. return {
  151. $type: "h1",
  152. class: "mdc-typography--headline4",
  153. $text: "ERROR: NO WORLD!"
  154. }
  155. }
  156. let userGUI = [];
  157. let cardInfo = {
  158. "title": ""
  159. };
  160. if (desc.type == 'saveState') {
  161. cardInfo.title = desc.worldName.split('/')[2];
  162. }
  163. if (desc.type == 'proto') {
  164. cardInfo.title = desc.worldName;
  165. userGUI.push(
  166. {
  167. $type: "a",
  168. class: "mdc-button mdc-button--compact mdc-card__action",
  169. $text: "States",
  170. onclick: function (e) {
  171. //console.log('clone');
  172. self.showOnlySaveStates(desc.worldName, desc.userAlias);
  173. //self.refresh();
  174. }
  175. }
  176. )
  177. }
  178. return {
  179. $cell: true,
  180. $type: "div",
  181. class: "mdc-card world-card",
  182. $components: [
  183. {
  184. $type: "section",
  185. class: "mdc-card__media world-card__16-9-media",
  186. $init: function () {
  187. if (desc.info.imgUrl !== "") {
  188. this.style.backgroundImage = 'linear-gradient(0deg, rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.3) ), url(' + desc.info.imgUrl + ')';
  189. }
  190. }
  191. },
  192. {
  193. $type: "section",
  194. class: "mdc-card__primary",
  195. $components: [
  196. {
  197. $type: "h1",
  198. class: "mdc-card__title mdc-card__title--large",
  199. $text: desc.info.title
  200. },
  201. {
  202. $type: "h2",
  203. class: "mdc-card__subtitle mdc-theme--text-secondary-on-background",
  204. $text: desc.info.text
  205. },
  206. {
  207. $type: "span",
  208. class: "mdc-card__subtitle mdc-theme--text-secondary-on-background",
  209. $text: 'id: '
  210. },
  211. {
  212. $type: "input",
  213. type: "text",
  214. disabled: "",
  215. style: "font-size:18px",
  216. value: cardInfo.title
  217. },
  218. {
  219. $type: "p",
  220. },
  221. {
  222. $type: "span",
  223. class: "mdc-card__subtitle mdc-theme--text-secondary-on-background",
  224. $text: 'created: ' + (new Date(desc.created)).toUTCString()
  225. },
  226. {
  227. $type: "p",
  228. }
  229. // ,{
  230. // $type: "span",
  231. // class: "mdc-card__subtitle mdc-theme--text-secondary-on-background",
  232. // $text: 'modified: ' + (new Date(desc[5])).toUTCString()
  233. // }
  234. ]
  235. },
  236. {
  237. $type: "section",
  238. class: "mdc-card__actions",
  239. $components: [
  240. {
  241. $type: "a",
  242. class: "mdc-button mdc-button--compact mdc-card__action mdc-button--outlined",
  243. $text: self.language.t('start'),//"Start new",
  244. target: "_blank",
  245. href: "/" + desc.userAlias + '/' + desc.worldName,
  246. onclick: function (e) {
  247. //self.refresh();
  248. }
  249. }
  250. ].concat(userGUI)
  251. },
  252. {
  253. $type: "section",
  254. class: "mdc-card__actions",
  255. $components: [
  256. {
  257. $type: 'div',
  258. $text: 'online now: '
  259. },
  260. onlineGUI
  261. ]
  262. }
  263. ]
  264. }
  265. }
  266. }
  267. let onlineGUI = {
  268. $cell: true,
  269. id: "onlineGUI",
  270. $type: "div",
  271. _instances: {},
  272. _worldListItem: function (m) {
  273. return {
  274. $type: "li",
  275. class: "mdc-list-item",
  276. $components: [
  277. {
  278. $type: "span",
  279. class: "world-link mdc-list-item__text",
  280. $components: [
  281. {
  282. $type: "span",
  283. class: "mdc-list-item__primary-text",
  284. $components: [
  285. {
  286. $type: "a",
  287. $text: m[0],
  288. target: "_blank",
  289. href: window.location.protocol + "//" + window.location.host + "/" + m[1].user + m[0],
  290. onclick: function (e) {
  291. //self.refresh();
  292. }
  293. },
  294. ]
  295. },
  296. {
  297. $type: "span",
  298. class: "mdc-list-item__secondary-text",
  299. $text: self.language.t('users') + m[1].clients
  300. }
  301. ]
  302. }
  303. ]
  304. }
  305. },
  306. $components: [],
  307. _refresh: function (data) {
  308. if (data) {
  309. if (Object.entries(data).length !== 0) {
  310. if (this._worldInfo) {
  311. let insts = Object.entries(data).filter(el => el[0] == this._worldInfo.worldName);
  312. if (insts.length !== 0)
  313. this._instances = insts[0][1];
  314. }
  315. } else {
  316. this._instances = {}
  317. }
  318. }
  319. },
  320. $init: function () {
  321. this._refresh();
  322. },
  323. $update: function () {
  324. if (this._instances) {
  325. let cardListData = Object.entries(this._instances).filter(el => el[1].user == this._worldInfo.userAlias);
  326. this.$components = [
  327. {
  328. $type: "hr",
  329. class: "mdc-list-divider"
  330. }
  331. ].concat(cardListData.map(this._worldListItem))
  332. }
  333. }
  334. }
  335. let actionsGUI = {
  336. $cell: true,
  337. id: "worldActionsGUI",
  338. $type: "div",
  339. $components: [],
  340. _worldInfo: {},
  341. _refresh: function () {
  342. this._worldInfo = {
  343. 'userAlias': self.userAlias,
  344. 'worldName': self.saveName ? self.worldName + '/load/' + self.saveName : self.worldName,
  345. 'type': self.saveName ? 'saveState' : 'proto'
  346. }
  347. // let worldCard = document.querySelector('#worldCard');
  348. // if(worldCard){
  349. // this._worldInfo = worldCard._worldInfo;
  350. // }
  351. },
  352. $init: function () {
  353. if (_LCSUSER.is) {
  354. this._refresh();
  355. }
  356. },
  357. $update: function () {
  358. let desc = this._worldInfo;
  359. let userGUI = [];
  360. // if(!desc){
  361. // this.$components = [];
  362. // return
  363. // }
  364. if (_LCSUSER.is) {
  365. if (_LCSUSER.is.alias == desc.userAlias) {
  366. userGUI.push(
  367. {
  368. $type: "a",
  369. class: "mdc-button mdc-button--compact mdc-card__action",
  370. $text: "Edit info",
  371. //href: "/" + desc[2] + '/worlds/' + desc[0] + '/edit', ///:user/worlds/:name/edit
  372. onclick: function (e) {
  373. //'/:user/:type/:name/edit/:file'
  374. if (desc.type == 'proto') {
  375. window.location.pathname = "/" + desc.userAlias + '/proto/' + desc.worldName + '/edit/info_json'
  376. } else if (desc.type == 'saveState') {
  377. let names = desc.worldName.split('/');
  378. let filename = ('savestate_/' + names[0] + '/' + names[2] + '_info_vwf_json').split('/').join("~");
  379. window.location.pathname = "/" + desc.userAlias + '/state/' + names[0] + '/edit/' + filename;
  380. }
  381. //self.refresh();
  382. }
  383. }
  384. );
  385. if (desc.type == 'proto') {
  386. userGUI.push(
  387. {
  388. $type: "a",
  389. class: "mdc-button mdc-button--compact mdc-card__action",
  390. $text: "Edit proto",
  391. //href: "/" + desc[2] + '/worlds/' + desc[0] + '/edit', ///:user/worlds/:name/edit
  392. onclick: function (e) {
  393. window.location.pathname = "/" + desc.userAlias + '/proto/' + desc.worldName + '/edit/index_vwf_yaml'
  394. }
  395. }
  396. );
  397. userGUI.push(
  398. {
  399. $type: "a",
  400. class: "mdc-button mdc-button--compact mdc-card__action",
  401. $text: "Delete",
  402. //href: "/" + desc[2] + '/worlds/' + desc[0] + '/edit', ///:user/worlds/:name/edit
  403. onclick: function (e) {
  404. _app.deleteWorld(desc.worldName, 'proto');
  405. }
  406. }
  407. );
  408. }
  409. if (desc.type == 'saveState') {
  410. userGUI.push(
  411. {
  412. $type: "a",
  413. class: "mdc-button mdc-button--compact mdc-card__action",
  414. $text: "Delete",
  415. //href: "/" + desc[2] + '/worlds/' + desc[0] + '/edit', ///:user/worlds/:name/edit
  416. onclick: function (e) {
  417. _app.deleteWorld(desc.worldName, 'state');
  418. }
  419. }
  420. );
  421. }
  422. }
  423. if (desc.type == 'proto') {
  424. userGUI.push(
  425. {
  426. $type: "a",
  427. class: "mdc-button mdc-button--compact mdc-card__action",
  428. $text: self.language.t('clone proto'),//"clone",
  429. onclick: function (e) {
  430. //console.log('clone');
  431. _app.cloneWorldPrototype(desc.worldName, desc.userAlias);
  432. //self.refresh();
  433. }
  434. }
  435. )
  436. } else if (desc.type == 'saveState') {
  437. // userGUI.push(
  438. // {
  439. // $type: "a",
  440. // class: "mdc-button mdc-button--compact mdc-card__action mdc-button--outlined",
  441. // $text: "Clone",
  442. // onclick: function (e) {
  443. // //console.log('clone');
  444. // //self.cloneWorldState(desc[0], desc[2]);
  445. // //self.refresh();
  446. // }
  447. // })
  448. }
  449. }
  450. this.$components = [
  451. {
  452. $type: "div",
  453. $text: "World actions:"
  454. }
  455. ].concat(userGUI)
  456. }
  457. }
  458. _LCSDB.on('auth',
  459. async function (ack) {
  460. if (_LCSUSER.is) {
  461. document.querySelector('#worldActionsGUI')._refresh();
  462. }
  463. })
  464. document.querySelector("#aboutWorld").$cell({
  465. id: 'aboutWorld',
  466. $cell: true,
  467. $type: "div",
  468. $components: [
  469. {
  470. $type: "div",
  471. class: "mdc-layout-grid",
  472. $components: [
  473. {
  474. $type: "div",
  475. class: "mdc-layout-grid__inner",
  476. $components: [
  477. {
  478. $type: "div",
  479. class: "mdc-layout-grid__cell mdc-layout-grid__cell--span-12",
  480. $components: [
  481. {
  482. $type: "h1",
  483. class: "mdc-typography--headline4",
  484. $text: self.worldName + ' by ' + self.userAlias
  485. }
  486. ]
  487. },
  488. {
  489. $type: "div",
  490. class: "mdc-layout-grid__cell mdc-layout-grid__cell--span-4",
  491. $components: [
  492. worldCardGUI
  493. ]
  494. },
  495. {
  496. $type: "div",
  497. class: "mdc-layout-grid__cell mdc-layout-grid__cell--span-12",
  498. $components: [
  499. actionsGUI
  500. ]
  501. }
  502. ]
  503. }
  504. ]
  505. }
  506. ]
  507. })
  508. }
  509. parseAppInstancesData(data) {
  510. let parcedData = _app.parseAppInstancesData(data);
  511. //if (Object.entries(parcedData).length !== 0)
  512. let onlineGUI = document.querySelector("#onlineGUI");
  513. if (onlineGUI)
  514. document.querySelector("#onlineGUI")._refresh(parcedData)
  515. // if (Object.entries(this.worlds).length !== 0) {
  516. // document.querySelector("#main")._emptyLists();
  517. // }
  518. // if (parcedData == "{}") {
  519. // var el = document.querySelector(".instance");
  520. // if (el) {
  521. // var topEl = el.parentNode;
  522. // topEl.removeChild(el);
  523. // }
  524. // // let removeElements = elms => Array.from(elms).forEach(el => el.remove());
  525. // }
  526. // console.log(parcedData)
  527. }
  528. }
  529. export { WorldApp }