app.js 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941
  1. /*
  2. The MIT License (MIT)
  3. Copyright (c) 2014-2018 Nikolai Suslov and the Krestianstvo.org project contributors. (https://github.com/NikolaySuslov/livecodingspace/blob/master/LICENSE.md)
  4. Virtual World Framework Apache 2.0 license (https://github.com/NikolaySuslov/livecodingspace/blob/master/licenses/LICENSE_VWF.md)
  5. */
  6. import page from '/lib/page.mjs';
  7. import { Lang } from '/lib/polyglot/language.js';
  8. import { Helpers } from '/helpers.js';
  9. import { IndexApp } from '/web/index-app.js';
  10. import { WorldApp } from '/web/world-app.js';
  11. import { Widgets } from '/lib/widgets.js';
  12. class App {
  13. constructor() {
  14. console.log("app constructor");
  15. this.widgets = new Widgets;
  16. //globals
  17. window._app = this;
  18. window._cellWidgets = this.widgets;
  19. window._LangManager = new Lang;
  20. window._noty = new Noty;
  21. _LangManager.setLanguage().then(res => {
  22. return this.initDB()
  23. }).then(res => {
  24. this.helpers = new Helpers;
  25. this.initUser();
  26. //client routes
  27. page('/', this.HandleIndex);
  28. page('/setup', this.HandleSetupIndex);
  29. page('/settings', this.HandleSettingsIndex);
  30. page('/profile', this.HandleUserIndex);
  31. page('/worlds', this.HandleIndex);
  32. page('/:user/worlds', this.HandleUserWorlds);
  33. page('/:user/worlds/:type', this.HandleUserWorldsWithType);
  34. page('/:user/:type/:name/edit/:file', this.HandleFileEdit);
  35. page('/:user/:space', this.HandleParsableRequestGenID);
  36. page('/:user/:space/about', this.HandleWorldAbout);
  37. page('/:user/:space/:id', this.HandleParsableRequestWithID);
  38. page('/:user/:space/index.vwf/:id', this.HandleParsableRequestWithID);
  39. page('/:user/:space/load/:savename', this.HandleParsableLoadRequest);
  40. page('/:user/:space/load/:savename/about', this.HandleWorldAbout);
  41. page('/:user/:space/:id/load/:savename', this.HandleParsableRequestWithID);
  42. page('/:user/:space/load/:savename/:rev', this.HandleParsableLoadRequestWithRev);
  43. page('/:user/:space/:id/load/:savename/:rev', this.HandleParsableRequestWithID);
  44. page('*', this.HandleNoPage);
  45. page();
  46. })
  47. }
  48. initDB() {
  49. var config = JSON.parse(localStorage.getItem('lcs_config'));
  50. if (!config) {
  51. config = {
  52. 'dbhost': 'https://' + window.location.hostname + ':8080/gun', //'http://localhost:8080/gun',
  53. 'reflector': 'https://' + window.location.hostname + ':3002',
  54. 'language': 'en'
  55. }
  56. localStorage.setItem('lcs_config', JSON.stringify(config));
  57. }
  58. const dbConnection = new Promise((resolve, reject) => {
  59. const opt = { peers: this.dbHost, localStorage: false, store: null }
  60. opt.store = RindexedDB(opt);
  61. this.db = Gun(opt);
  62. this.user = this.db.user();
  63. window._LCSDB = this.db;
  64. window._LCSUSER = this.user;
  65. window._LCS_SYS_USER = undefined;
  66. window._LCS_WORLD_USER = undefined;
  67. _LCSDB.get('lcs/app').get('pub').once(res => {
  68. if (res) {
  69. window._LCS_SYS_USER = _LCSDB.user(res);
  70. }
  71. });
  72. _LCSDB.on('hi', function (peer) {
  73. let msg = 'Connected to ' + peer.url;
  74. let noty = new Noty({
  75. text: msg,
  76. timeout: 2000,
  77. theme: 'mint',
  78. layout: 'bottomRight',
  79. type: 'success'
  80. });
  81. noty.show();
  82. console.log(msg)
  83. })
  84. _LCSDB.on('bye', function (peer) {
  85. let msg = 'No connection to ' + peer.url;
  86. let noty = new Noty({
  87. text: msg,
  88. timeout: 1000,
  89. theme: 'mint',
  90. layout: 'bottomRight',
  91. type: 'error'
  92. });
  93. noty.show();
  94. console.log(msg)
  95. })
  96. resolve('ok');
  97. });
  98. return dbConnection
  99. }
  100. initUser() {
  101. _LCSDB.user().recall({ sessionStorage: 1 });
  102. }
  103. get reflectorHost() {
  104. var res = "";
  105. let config = localStorage.getItem('lcs_config');
  106. if (config) {
  107. res = JSON.parse(config).reflector;
  108. }
  109. return res;
  110. }
  111. get dbHost() {
  112. var res = "";
  113. let config = localStorage.getItem('lcs_config');
  114. if (config) {
  115. res = JSON.parse(config).dbhost;
  116. }
  117. return res;
  118. }
  119. async loadProxyDefaults() {
  120. //load to DB default proxy files (VWF & A-Frame components)
  121. let proxyResponse = await fetch('/proxy-files', { method: 'get' });
  122. let proxyFiles = await proxyResponse.json();
  123. let filterProxyFiles = proxyFiles.filter(el => (el !== null));
  124. console.log(filterProxyFiles);
  125. var origin = window.location.origin;
  126. //var userPub = this.db.user().is.pub;
  127. let proxyObj = {};
  128. for (var index in filterProxyFiles) {
  129. let doc = filterProxyFiles[index];
  130. if (doc) {
  131. var url = origin + doc;
  132. var entryName = url.replace(origin + '/defaults/', "").split(".").join("_");
  133. let proxyFile = await fetch(url, { method: 'get' });
  134. let responseText = await proxyFile.text();
  135. if (responseText) {
  136. let created = new Date().valueOf();
  137. let obj = {
  138. //'owner': userPub,
  139. 'file': responseText,
  140. 'modified': created,
  141. 'created': created
  142. }
  143. proxyObj[entryName] = obj;
  144. }
  145. }
  146. }
  147. console.log(proxyObj);
  148. Object.keys(proxyObj).forEach(res => {
  149. let proxy = _LCSDB.user().get('proxy');
  150. proxy.get(res).put(proxyObj[res]);
  151. })
  152. }
  153. async loadWorldsDefaults(replace) {
  154. //load to DB default worlds
  155. let worldsResponse = await fetch('/world-files', { method: 'get' });
  156. let worldFiles = await worldsResponse.json();
  157. let filterworldFiles = worldFiles.filter(el => (el !== null));
  158. console.log(filterworldFiles);
  159. let worldsObj = {};
  160. for (var index in filterworldFiles) {
  161. let doc = filterworldFiles[index];
  162. if (doc) {
  163. let url = window.location.origin + doc;
  164. var entryName = url.replace(window.location.origin + '/defaults/worlds/', "").split(".").join("_");
  165. let worldName = entryName.split("/")[0];
  166. let userPub = _LCSDB.user().is.pub;
  167. let worldFile = await fetch(url, { method: 'get' });
  168. let worldSource = await worldFile.text();
  169. if (worldSource) {
  170. //let modified = new Date().valueOf();
  171. let created = new Date().valueOf();
  172. let obj = {
  173. 'file': worldSource,
  174. 'modified': created,
  175. 'created': created
  176. }
  177. if (!worldsObj[worldName]) {
  178. worldsObj[worldName] = {
  179. 'parent': '-',
  180. 'owner': userPub,
  181. 'featured': true,
  182. 'published': true
  183. }
  184. }
  185. let entry = entryName.replace(worldName + '/', "");
  186. worldsObj[worldName][entry] = obj;
  187. }
  188. }
  189. }
  190. console.log(worldsObj);
  191. if (replace) {
  192. Object.entries(worldsObj).forEach(res => {
  193. let worldName = res[0];
  194. let files = res[1];
  195. Object.entries(files).forEach(file => {
  196. _LCSDB.user().get('worlds').get(worldName).get(file[0]).put(file[1]);
  197. })
  198. })
  199. } else {
  200. //force replace all default worlds
  201. Object.entries(worldsObj).forEach(res => {
  202. let worldName = res[0];
  203. let files = res[1];
  204. Object.entries(files).forEach(file => {
  205. _LCSDB.user().get('worlds').get(worldName).get(file[0]).not(res => {
  206. _LCSDB.user().get('worlds').get(worldName).get(file[0]).put(file[1]);
  207. })
  208. })
  209. })
  210. }
  211. }
  212. async loadEmptyDefaultProto() {
  213. //empty proto world
  214. let userPub = _LCSDB.user().is.pub;
  215. let worldsObj = {};
  216. let emptyWorld = {
  217. "index_vwf_yaml": YAML.stringify(
  218. {
  219. "extends": "http://vwf.example.com/aframe/ascene.vwf"
  220. }, 4),
  221. "index_vwf_config_yaml": YAML.stringify(
  222. {
  223. "info": {
  224. "title": "Empty World"
  225. },
  226. "model": {
  227. "vwf/model/aframe": null
  228. },
  229. "view": {
  230. "vwf/view/aframe": null,
  231. "vwf/view/editor-new": null
  232. }
  233. }, 4),
  234. "assets_json": JSON.stringify({}),
  235. "index_vwf_html": JSON.stringify("<!-- DEFAULT HTML -->"),
  236. "appui_js": JSON.stringify("//appui in JS"),
  237. "info_json": JSON.stringify({
  238. "info": {
  239. "en": {
  240. "title": "Empty World",
  241. "imgUrl": "",
  242. "text": "Empty World"
  243. },
  244. "ru": {
  245. "title": "Новый Мир",
  246. "imgUrl": "",
  247. "text": "Новый Мир"
  248. }
  249. }
  250. }, null, 4)
  251. }
  252. worldsObj['empty'] = {
  253. 'parent': '-',
  254. 'owner': userPub,
  255. 'featured': true,
  256. 'published': true
  257. }
  258. Object.keys(emptyWorld).forEach(el => {
  259. //let modified = new Date().valueOf();
  260. let created = new Date().valueOf();
  261. let obj = {
  262. 'file': emptyWorld[el],
  263. 'modified': created,
  264. 'created': created
  265. }
  266. worldsObj['empty'][el] = obj;
  267. })
  268. console.log(worldsObj);
  269. Object.entries(worldsObj).forEach(el => {
  270. let worldName = el[0];
  271. let files = el[1];
  272. Object.entries(files).forEach(file => {
  273. _LCSDB.user().get('worlds').get(worldName).get(file[0]).put(file[1]);
  274. })
  275. })
  276. }
  277. //load defaults for first registered user running ./setup
  278. HandleSettingsIndex() {
  279. window._app.hideProgressBar();
  280. window._app.hideUIControl();
  281. let el = document.createElement("div");
  282. el.setAttribute("id", "appGUI");
  283. document.body.appendChild(el);
  284. _cellWidgets.reflectorGUI();
  285. }
  286. async HandleWorldAbout(ctx) {
  287. console.log("about world");
  288. let userAlias = ctx.params.user;
  289. let worldName = ctx.params.space;
  290. let saveName = ctx.params.savename;
  291. window._app.hideProgressBar();
  292. window._app.hideUIControl();
  293. if (!_app.indexApp) {
  294. _app.indexApp = new IndexApp;
  295. _app.indexApp.initHTML();
  296. _app.indexApp.initApp();
  297. }
  298. let worldApp = new WorldApp(userAlias, worldName, saveName);
  299. await worldApp.initWorldGUI();
  300. }
  301. HandleSetupIndex() {
  302. window._app.hideProgressBar();
  303. window._app.hideUIControl();
  304. let el = document.createElement("div");
  305. el.setAttribute("id", "admin");
  306. document.body.appendChild(el);
  307. _LCSDB.on('auth',
  308. async function (ack) {
  309. if (_LCSDB.user().is) {
  310. let setPubKey = {
  311. $cell: true,
  312. $components: [
  313. {
  314. $type: "p",
  315. class: "mdc-typography--headline5",
  316. $text: "1. Set app system user PUB key"
  317. },
  318. {
  319. $type: "button",
  320. class: "mdc-button mdc-button--raised",
  321. $text: "Set app PUB key",
  322. onclick: function (e) {
  323. console.log("admin action");
  324. _LCSDB.get('lcs/app').get('pub').put(_LCSDB.user().is.pub);
  325. }
  326. }
  327. ]
  328. }
  329. let adminComponents = [];
  330. let defaultPub = await _LCSDB.get('lcs/app').get('pub').once().then();
  331. if (!defaultPub) {
  332. adminComponents.push(setPubKey);
  333. }
  334. if (_LCSDB.user().is.pub == defaultPub) {
  335. let loadEmpty = {
  336. $cell: true,
  337. $components: [
  338. {
  339. $type: "p",
  340. class: "mdc-typography--headline5",
  341. $text: "3. Initialize empty World proto"
  342. },
  343. {
  344. $type: "button",
  345. id: "loadDefaults",
  346. class: "mdc-button mdc-button--raised",
  347. $text: "Init empty world",
  348. onclick: function (e) {
  349. console.log("admin action");
  350. window._app.loadEmptyDefaultProto();
  351. }
  352. }
  353. ]
  354. }
  355. let loadDefaults = {
  356. $cell: true,
  357. _replaceSwitch: null,
  358. $components: [
  359. {
  360. $type: "p",
  361. class: "mdc-typography--headline5",
  362. $text: "4. Load Sample Worlds protos from server (optional)"
  363. },
  364. {
  365. $type: "button",
  366. id: "loadDefaults",
  367. class: "mdc-button mdc-button--raised",
  368. $text: "Load default worlds (from server)",
  369. onclick: function (e) {
  370. console.log("admin action");
  371. let forceReplace = this._replaceSwitch.checked;
  372. //console.log(forceReplace);
  373. window._app.loadWorldsDefaults(forceReplace);
  374. }
  375. },
  376. {
  377. $type: 'p'
  378. },
  379. _cellWidgets.switch({
  380. 'id': 'forceReplace',
  381. 'init': function () {
  382. this._switch = new mdc.switchControl.MDCSwitch(this);
  383. this._replaceSwitch = this._switch;
  384. this._switch.checked = false;
  385. }
  386. }
  387. ),
  388. {
  389. $type: 'label',
  390. for: 'input-forceReplace',
  391. $text: 'Force replace'
  392. }
  393. ]
  394. }
  395. let loadDefaultsProxy = {
  396. $cell: true,
  397. $components: [
  398. {
  399. $type: "p",
  400. class: "mdc-typography--headline5",
  401. $text: "3. Load VWF & A-Frame default components"
  402. },
  403. {
  404. $type: "button",
  405. class: "mdc-button mdc-button--raised",
  406. $text: "Load defaults Proxy",
  407. onclick: function (e) {
  408. console.log("admin action");
  409. window._app.loadProxyDefaults();
  410. }
  411. }
  412. ]
  413. }
  414. adminComponents.push(setPubKey, loadDefaultsProxy, loadEmpty, loadDefaults);
  415. }
  416. document.querySelector("#admin").$cell({
  417. $cell: true,
  418. id: 'adminComponents',
  419. $type: "div",
  420. $components: adminComponents
  421. });
  422. }
  423. })
  424. }
  425. //TODO: profile
  426. HandleUserIndex(ctx) {
  427. console.log("USER INDEX");
  428. window._app.hideProgressBar();
  429. window._app.hideUIControl();
  430. _LCSDB.on('auth',
  431. async function (ack) {
  432. if (ack.sea.pub) {
  433. document.querySelector("#profile")._status = "User: " + _LCSDB.user().is.alias //+' pub: ' + this.db.user().is.pub;
  434. document.querySelector("#profile").$update();
  435. }
  436. })
  437. let el = document.createElement("div");
  438. el.setAttribute("id", "userProfile");
  439. document.body.appendChild(el);
  440. let userProfile = {
  441. $type: 'div',
  442. id: "profile",
  443. _status: "",
  444. $init: function () {
  445. this._status = "user is not signed in..."
  446. },
  447. $update: function () {
  448. this.$components = [
  449. {
  450. $type: "h1",
  451. class: "mdc-typography--headline4",
  452. $text: this._status //"Profile for: " + this.db.user().is.alias
  453. }
  454. ]
  455. }
  456. }
  457. document.querySelector("#userProfile").$cell({
  458. $cell: true,
  459. $type: "div",
  460. $components: [userProfile]
  461. })
  462. }
  463. async HandleUserWorlds(ctx) {
  464. console.log("USER WORLDS INDEX");
  465. console.log(ctx.params);
  466. let user = ctx.params.user;
  467. page.redirect('/' + user + '/worlds/protos');
  468. }
  469. async HandleFileEdit(ctx) {
  470. console.log("USER WORLD FILE EDIT");
  471. let user = ctx.params.user;
  472. let worldName = ctx.params.name;
  473. let fileOriginal = ctx.params.file;
  474. let type = ctx.params.type;
  475. window._app.hideProgressBar();
  476. window._app.hideUIControl();
  477. _LCSDB.on('auth',
  478. async function (ack) {
  479. if (_LCSDB.user().is) {
  480. if (_LCSDB.user().is.alias == user) {
  481. var worldType = 'worlds';
  482. var file = fileOriginal;
  483. if (type == 'state') {
  484. worldType = 'documents';
  485. file = _app.helpers.replaceSubStringALL(fileOriginal, "~", '/');
  486. }
  487. let worldFile = await _LCSDB.user().get(worldType).get(worldName).get(file).once().then();
  488. if (worldFile) {
  489. console.log(worldFile.file);
  490. let el = document.createElement("div");
  491. el.setAttribute("id", "worldFILE");
  492. document.body.appendChild(el);
  493. let aceEditorCell = {
  494. $type: "div",
  495. $components: [
  496. {
  497. class: "aceEditor",
  498. id: "aceEditor",
  499. //style: "width:1200px; height: 800px",
  500. $type: "div",
  501. $text: worldFile.file,
  502. $init: function () {
  503. var mode = "ace/mode/json";
  504. if (file.includes('_yaml'))
  505. mode = "ace/mode/yaml"
  506. if (file.includes('_js'))
  507. mode = "ace/mode/javascript"
  508. var editor = ace.edit("aceEditor");
  509. editor.setTheme("ace/theme/monokai");
  510. editor.setFontSize(16);
  511. editor.getSession().setMode(mode);
  512. editor.setOptions({
  513. maxLines: Infinity
  514. });
  515. }
  516. },
  517. {
  518. $type: "button",
  519. class: "mdc-button mdc-button--raised",
  520. $text: "Save",
  521. onclick: async function (e) {
  522. console.log("save new info");
  523. let editor = document.querySelector("#aceEditor").env.editor;
  524. let newInfo = editor.getValue();
  525. _LCSDB.user().get(worldType).get(worldName).get(file).get('file').put(newInfo, res => {
  526. if (res) {
  527. let noty = new Noty({
  528. text: 'Saved!',
  529. timeout: 2000,
  530. theme: 'mint',
  531. layout: 'bottomRight',
  532. type: 'success'
  533. });
  534. noty.show();
  535. let modified = new Date().valueOf();
  536. _LCSDB.user().get(worldType).get(worldName).get(file).get('modified').put(modified);
  537. }
  538. })
  539. }
  540. },
  541. {
  542. $type: "button",
  543. class: "mdc-button mdc-button--raised",
  544. $text: "Close",
  545. onclick: function (e) {
  546. console.log("close");
  547. window.history.back();
  548. // if (type == "proto")
  549. // window.location.pathname = "/" + user + '/' + worldName + '/about'
  550. // if (type == "state")
  551. // window.location.pathname = "/" + user + '/' + worldName + '/about'
  552. }
  553. }
  554. ]
  555. }
  556. document.querySelector("#worldFILE").$cell({
  557. $cell: true,
  558. $type: "div",
  559. $components: [aceEditorCell
  560. ]
  561. })
  562. }
  563. }
  564. }
  565. })
  566. }
  567. async HandleUserWorldsWithType(ctx) {
  568. console.log("USER WORLDS INDEX");
  569. console.log(ctx.params);
  570. let user = ctx.params.user;
  571. let type = ctx.params.type;
  572. window._app.hideProgressBar();
  573. window._app.hideUIControl();
  574. if (!_app.indexApp) {
  575. _app.indexApp = new IndexApp;
  576. _app.indexApp.initHTML();
  577. _app.indexApp.initApp();
  578. }
  579. if (type == 'protos') {
  580. await _app.indexApp.initWorldsProtosListForUser(user)//.getWorldsProtosListForUser(user);
  581. } else if (type == 'states') {
  582. await _app.indexApp.initWorldsStatesListForUser(user);
  583. //await _app.indexApp.getWorldsFromUserDB(user);
  584. }
  585. }
  586. async HandleIndex() {
  587. console.log("INDEX");
  588. window._app.hideProgressBar();
  589. window._app.hideUIControl();
  590. if (!_app.indexApp) {
  591. _app.indexApp = new IndexApp;
  592. await _app.indexApp.generateFrontPage();
  593. _app.indexApp.initHTML();
  594. }
  595. _app.indexApp.initApp();
  596. await _app.indexApp.initWorldsProtosListForUser('app');
  597. //await _app.indexApp.getAppDetailsFromDB();
  598. }
  599. HandleNoPage() {
  600. console.log("no such page")
  601. }
  602. //handle parcable requests
  603. HandleParsableLoadRequest(ctx) {
  604. let app = window._app;
  605. console.log(ctx.params);
  606. //var pathname = ctx.pathname;
  607. var spaceName = ctx.params.space;
  608. var saveName = ctx.params.savename;
  609. let user = ctx.params.user;
  610. page.redirect('/' + user + '/' + spaceName + '/' + app.helpers.GenerateInstanceID() + '/load/' + saveName);
  611. }
  612. HandleParsableLoadRequestWithRev(ctx) {
  613. let app = window._app;
  614. console.log(ctx.params);
  615. //var pathname = ctx.pathname;
  616. var spaceName = ctx.params.space;
  617. var saveName = ctx.params.savename;
  618. var rev = ctx.params.rev;
  619. let user = ctx.params.user;
  620. page.redirect('/' + user + '/' + spaceName + '/' + app.helpers.GenerateInstanceID() + '/load/' + saveName + '/' + rev);
  621. }
  622. async setUserPaths(user) {
  623. await _LCSDB.get('users').get(user).get('pub').once(res => {
  624. if (res)
  625. window._LCS_WORLD_USER = _LCSDB.user(res);
  626. }).then();
  627. }
  628. async HandleParsableRequestGenID(ctx) {
  629. let app = window._app;
  630. console.log(ctx.params);
  631. let user = ctx.params.user;
  632. var pathname = ctx.pathname;
  633. await app.setUserPaths(user);
  634. if (pathname[pathname.length - 1] == '/') {
  635. pathname = pathname.slice(0, -1)
  636. }
  637. let pathToParse = pathname.replace('/' + user, "");
  638. app.helpers.Process(pathToParse).then(parsedRequest => {
  639. localStorage.setItem('lcs_app', JSON.stringify({ path: parsedRequest }));
  640. console.log(parsedRequest);
  641. if ((parsedRequest['instance'] == undefined) && (parsedRequest['private_path'] == undefined) && (parsedRequest['public_path'] !== "/") && (parsedRequest['application'] !== undefined)) {
  642. page.redirect(pathname + '/' + app.helpers.GenerateInstanceID());
  643. }
  644. });
  645. }
  646. async HandleParsableRequestWithID(ctx) {
  647. let app = window._app;
  648. console.log(ctx.params);
  649. var pathname = ctx.pathname;
  650. let user = ctx.params.user;
  651. if (pathname[pathname.length - 1] == '/') {
  652. pathname = pathname.slice(0, -1)
  653. }
  654. await app.setUserPaths(user);
  655. let pathToParse = pathname.replace('/' + user, "");
  656. app.helpers.Process(pathToParse).then(async function (parsedRequest) {
  657. localStorage.setItem('lcs_app', JSON.stringify({ path: parsedRequest }));
  658. console.log(parsedRequest);
  659. var userLibraries = { model: {}, view: {} };
  660. var application;
  661. await vwf.loadConfiguration(application, userLibraries, compatibilityCheck);
  662. });
  663. }
  664. async HandleParsableRequest(ctx) {
  665. let app = window._app;
  666. console.log(ctx.params);
  667. var pathname = ctx.pathname;
  668. if (pathname[pathname.length - 1] == '/') {
  669. pathname = pathname.slice(0, -1)
  670. }
  671. var parsedRequest = await app.helpers.Process(pathname);
  672. localStorage.setItem('lcs_app', JSON.stringify({ path: parsedRequest }));
  673. console.log(parsedRequest);
  674. if ((parsedRequest['instance'] == undefined) && (parsedRequest['private_path'] == undefined) && (parsedRequest['public_path'] !== "/") && (parsedRequest['application'] !== undefined)) {
  675. // Redirect if the url request does not include an application/file && a default 'index.vwf.yaml' exists
  676. // page.redirect(pathname + '/' + app.helpers.GenerateInstanceID());
  677. window.location.pathname = pathname + '/' + app.helpers.GenerateInstanceID()
  678. //return true;
  679. } else {
  680. //return false;
  681. }
  682. var userLibraries = { model: {}, view: {} };
  683. var application;
  684. await vwf.loadConfiguration(application, userLibraries, compatibilityCheck);
  685. }
  686. //get DB application state information for reflector (called from VWF)
  687. async getApplicationState() {
  688. let dataJson = JSON.parse(localStorage.getItem('lcs_app'));
  689. if (dataJson) {
  690. if (!dataJson.path['instance']) return undefined;
  691. }
  692. let userAlias = await _LCS_WORLD_USER.get('alias').once().then();
  693. let userPub = await _LCSDB.get('users').get(userAlias).get('pub').once().then();
  694. let loadInfo = await this.getLoadInformation(dataJson);
  695. let saveInfo = await this.loadSaveObject(loadInfo);
  696. let loadObj = {
  697. loadInfo: loadInfo,
  698. path: dataJson.path,
  699. saveObject: saveInfo,
  700. user: userAlias
  701. }
  702. //dataJson.app = loadObj;
  703. localStorage.setItem('lcs_app', JSON.stringify(loadObj));
  704. console.log(loadObj);
  705. //temporary solution for syncing DB replicas using Gun.load()
  706. // _LCS_SYS_USER.get('proxy').load(res=>{
  707. // if (res)
  708. // {console.log('proxy loaded');
  709. // _LCSDB.user(userPub).get('worlds').get(loadObj.path.public_path.slice(1)).load(w=>{
  710. // if (w) {
  711. // console.log('world files loaded');
  712. // vwf.ready( vwf.application, loadObj)
  713. // }
  714. // });
  715. // }
  716. // });
  717. return loadObj
  718. }
  719. // LookupSaveRevisions takes the public path and the name of a save, and provides
  720. // an array of all revisions for that save. (If the save does not exist, this will be
  721. // an empty array).
  722. async lookupSaveRevisions(public_path, save_name) {
  723. var result = [];
  724. var states = [];
  725. let docName = 'savestate_/' + public_path + '/' + save_name + '_vwf_json';
  726. let revs = await _LCS_WORLD_USER.get('documents').get(public_path).get(docName).get('revs').once().then();
  727. if (revs) {
  728. for (const res of Object.keys(revs)) {
  729. if (res !== '_') {
  730. let el = await _LCS_WORLD_USER.get('documents').get(public_path).get(docName).get('revs').get(res).once().then();
  731. if (el)
  732. result.push(parseInt(el.revision));
  733. }
  734. }
  735. return result
  736. }
  737. }
  738. // GetLoadInformation receives a parsed request {private_path, public_path, instance, application} and returns the
  739. // details of the save that is designated by the initial request. The details are returned in an object
  740. // composed of: save_name (name of the save) save_revision (revision of the save), explicit_revision (boolean, true if the request
  741. // explicitly specified the revision, false if it did not), and application_path (the public_path of the application this is a save for).
  742. async getLoadInformation(response) {
  743. let parsedRequest = response.path;
  744. var result = { 'save_name': undefined, 'save_revision': undefined, 'explicit_revision': undefined, 'application_path': undefined };
  745. if (parsedRequest['private_path']) {
  746. var segments = this.helpers.GenerateSegments(parsedRequest['private_path']);
  747. if ((segments.length > 1) && (segments[0] == "load")) {
  748. var potentialRevisions = await this.lookupSaveRevisions((parsedRequest['public_path']).slice(1), segments[1]);
  749. console.log('!!!!! - ', potentialRevisions);
  750. if (potentialRevisions.length > 0) {
  751. result['save_name'] = segments[1];
  752. if (segments.length > 2) {
  753. var requestedRevision = parseInt(segments[2]);
  754. if (requestedRevision) {
  755. if (potentialRevisions.indexOf(requestedRevision) > -1) {
  756. result['save_revision'] = requestedRevision;
  757. result['explicit_revision'] = true;
  758. result['application_path'] = parsedRequest['public_path'];
  759. }
  760. }
  761. }
  762. if (result['explicit_revision'] == undefined) {
  763. result['explicit_revision'] = false;
  764. potentialRevisions.sort();
  765. result['save_revision'] = potentialRevisions.pop();
  766. result['application_path'] = parsedRequest['public_path'];
  767. }
  768. }
  769. }
  770. }
  771. return result;
  772. }
  773. async loadSaveObject(loadInfo) {
  774. //let objName = loadInfo[ 'save_name' ] +'/'+ "savestate_" + loadInfo[ 'save_revision' ];
  775. if (!loadInfo.save_name) {
  776. return undefined
  777. }
  778. let objName = "savestate_" + loadInfo['application_path'] + '/' + loadInfo['save_name'] + '_vwf_json';
  779. let objNameRev = "savestate_" + loadInfo['save_revision'] + loadInfo['application_path'] + '/' + loadInfo['save_name'] + '_vwf_json';
  780. // if(loadInfo[ 'save_revision' ]){
  781. // }
  782. let worldName = this.helpers.appPath //loadInfo[ 'application_path' ].slice(1);
  783. let saveObject = await _LCS_WORLD_USER.get('documents').get(worldName).get(objName).get('revs').get(objNameRev).once().then();
  784. let saveInfo = saveObject ? JSON.parse(saveObject.jsonState) : saveObject;
  785. return saveInfo;
  786. }
  787. // GetSaveInformation is a helper function that takes the application_path (/path/to/application).
  788. // It returns an array of all saves found for that
  789. // application (including separate entries for individual revisions of saves ).
  790. async getSaveInformation(application_path, userPUB) {
  791. var result = [];
  792. let user = _LCSDB.user(userPUB);
  793. var docName = application_path.slice(1);
  794. let potentialSaveNames = await user.get('documents').get(docName).once().then();
  795. if (potentialSaveNames) {
  796. for (const res of Object.keys(potentialSaveNames)) {
  797. if (res !== '_') {
  798. let el = await user.get('documents').path(docName).get(res).once().then();
  799. let revisionList = await this.lookupSaveRevisions(application_path.slice(1), el.filename);
  800. var latestsave = true;
  801. revisionList.sort();
  802. while (revisionList.length > 0) {
  803. var newEntry = {};
  804. newEntry['applicationpath'] = application_path;
  805. newEntry['savename'] = el.filename;
  806. newEntry['revision'] = revisionList.pop().toString();
  807. newEntry['latestsave'] = latestsave;
  808. if (latestsave) {
  809. newEntry['url'] = this.helpers.JoinPath(window.location.origin, application_path, "load", el.filename + "/");
  810. }
  811. else {
  812. newEntry['url'] = this.helpers.JoinPath(window.location.origin, application_path, "load", el.filename + "/", newEntry['revision'] + "/");
  813. }
  814. latestsave = false;
  815. result.push(newEntry);
  816. }
  817. }
  818. }
  819. }
  820. return result;
  821. }
  822. async getProtoWorldFiles(userPub, worldName, date) {
  823. let fileNamesAll = await _LCSDB.user(userPub).get('worlds').get(worldName).once().then();
  824. let worldFileNames = Object.keys(fileNamesAll).filter(el => (el !== '_') && (el !== 'owner') && (el !== 'parent') && (el !== 'featured') && (el !== 'published') && (el !== 'info_json') && (el !== '_config_yaml') && (el !== '_yaml') && (el !== '_html'));
  825. let worldObj = {};
  826. for (var doc in worldFileNames) {
  827. let fn = worldFileNames[doc];
  828. let res = await _LCSDB.user(userPub).get('worlds').get(worldName).get(fn).once().then();
  829. var data = {
  830. 'file': res.file,
  831. 'modified': res.modified,
  832. 'created': res.created
  833. }
  834. if (!date) {
  835. data = {
  836. 'file': res.file
  837. }
  838. }
  839. worldObj[fn] = data;
  840. }
  841. console.log(worldObj);
  842. return worldObj
  843. }
  844. async cloneWorldPrototype(worldName, userName, newWorldName) {
  845. _app.showProgressBar();
  846. let userPub = await _LCSDB.get('users').get(userName).get('pub').once().then();
  847. //let worldProto = await _LCSDB.user(userPub).get('worlds').get(worldName).once().then();
  848. var worldID = window._app.helpers.GenerateInstanceID().toString();
  849. if (newWorldName) {
  850. worldID = newWorldName
  851. }
  852. //let modified = new Date().valueOf();
  853. console.log('clone: ' + worldName + 'to: ' + worldID);
  854. let newOwner = _LCSDB.user().is.pub;
  855. let created = new Date().valueOf();
  856. let worldObj = {
  857. 'owner': newOwner,
  858. 'parent': userName + '/' + worldName,
  859. 'featured': true,
  860. 'published': true
  861. };
  862. let fileNamesAll = await _LCSDB.user(userPub).get('worlds').get(worldName).once().then();
  863. let worldFileNames = Object.keys(fileNamesAll).filter(el => (el !== '_') && (el !== 'owner') && (el !== 'parent') && (el !== 'featured') && (el !== 'published') && (el !== '_config_yaml') && (el !== '_yaml') && (el !== '_html'));
  864. for (var doc in worldFileNames) {
  865. let fn = worldFileNames[doc];
  866. let res = await _LCSDB.user(userPub).get('worlds').get(worldName).get(fn).once().then();
  867. let data = {
  868. 'file': res.file,
  869. 'modified': created
  870. }
  871. worldObj[fn] = data;
  872. }
  873. console.log(worldObj);
  874. // for (const obj of Object.keys(worldObj)) {
  875. // let myWorlds = _LCSDB.user().get('worlds');
  876. // let myNewWorld = myWorlds.get(worldID);
  877. // myNewWorld.get(obj).put(worldObj[obj]);
  878. // }
  879. let myWorlds = _LCSDB.user().get('worlds');
  880. let myNewWorld = myWorlds.get(worldID);
  881. myNewWorld.put(worldObj);
  882. _app.hideProgressBar();
  883. console.log('CLONED!!!');
  884. let appEl = document.createElement("div");
  885. appEl.setAttribute("id", 'cloneLink');
  886. let entry = document.querySelector('#worldActionsGUI');
  887. if (entry) {
  888. entry.appendChild(appEl);
  889. document.querySelector("#cloneLink").$cell({
  890. id: 'cloneLink',
  891. $cell: true,
  892. $type: "div",
  893. $components: [
  894. {
  895. $type: "a",
  896. class: "mdc-button mdc-button--raised mdc-card__action",
  897. $text: "Go to new cloned World!",
  898. onclick: function (e) {
  899. let myName = _LCSDB.user().is.alias;
  900. window.location.pathname = '/' + myName + '/' + worldID + '/about'
  901. }
  902. }
  903. ]
  904. })
  905. }
  906. //window.location.pathname = '/' + userName + '/' + worldID + '/about'
  907. //page()
  908. // Object.keys(worldObj).forEach(el => {
  909. // this.db.user().get('worlds').get(worldID).get(el).put(worldObj[el]);
  910. // })
  911. }
  912. async cloneWorldState(filename) {
  913. let myWorldProtos = await _LCSDB.user().get('worlds').once().then();
  914. let userName = this.helpers.worldUser;
  915. let userPub = await _LCSDB.get('users').get(userName).get('pub').once().then();
  916. let protoUserRoot = this.helpers.getRoot(true).root;
  917. //let myName = this.db.user().is.alias;
  918. //let proto = Object.keys(myWorldProtos).filter(el => el == protoUserRoot);
  919. var protosKeys = [];
  920. if (myWorldProtos)
  921. protosKeys = Object.keys(myWorldProtos);
  922. if (protosKeys.includes(protoUserRoot)) {
  923. let userProtoFiles = await this.getProtoWorldFiles(userPub, protoUserRoot);
  924. let myProtoFiles = await this.getProtoWorldFiles(_LCSDB.user().is.pub, protoUserRoot);
  925. let hashUP = await this.helpers.sha256(JSON.stringify(userProtoFiles));
  926. let hashMP = await this.helpers.sha256(JSON.stringify(myProtoFiles));
  927. if (hashUP == hashMP) {
  928. this.saveStateAsFile(filename);
  929. } else {
  930. let noty = new Noty({
  931. text: 'world prototype is modified.. could not clone world state',
  932. timeout: 2000,
  933. theme: 'mint',
  934. layout: 'bottomRight',
  935. type: 'error'
  936. });
  937. noty.show();
  938. }
  939. } else {
  940. await this.cloneWorldPrototype(protoUserRoot, userName, protoUserRoot);
  941. this.saveStateAsFile(filename);
  942. }
  943. }
  944. //TODO: refactor and config save
  945. saveStateAsFile(filename, otherProto) // invoke with the view as "this"
  946. {
  947. console.log("Saving: " + filename);
  948. //var clients = this.nodes["http://vwf.example.com/clients.vwf"];
  949. // Save State Information
  950. var state = vwf.getState();
  951. state.nodes[0].children = {};
  952. var timestamp = state["queue"].time;
  953. timestamp = Math.round(timestamp * 1000);
  954. var objectIsTypedArray = function (candidate) {
  955. var typedArrayTypes = [
  956. Int8Array,
  957. Uint8Array,
  958. // Uint8ClampedArray,
  959. Int16Array,
  960. Uint16Array,
  961. Int32Array,
  962. Uint32Array,
  963. Float32Array,
  964. Float64Array
  965. ];
  966. var isTypedArray = false;
  967. if (typeof candidate == "object" && candidate != null) {
  968. typedArrayTypes.forEach(function (typedArrayType) {
  969. isTypedArray = isTypedArray || candidate instanceof typedArrayType;
  970. });
  971. }
  972. return isTypedArray;
  973. };
  974. var transitTransformation = function (object) {
  975. return objectIsTypedArray(object) ?
  976. Array.prototype.slice.call(object) : object;
  977. };
  978. let jsonValuePure = require("vwf/utility").transform(
  979. state, transitTransformation
  980. );
  981. //remove all Ohm generated grammarsfrom state
  982. let jsonValue = _app.helpers.removeGrammarObj(jsonValuePure);
  983. var jsonState = JSON.stringify(jsonValue);
  984. let rootPath = this.helpers.getRoot(true);
  985. var inst = rootPath.inst;
  986. if (filename == '') filename = inst;
  987. //if (root.indexOf('.vwf') != -1) root = root.substring(0, root.lastIndexOf('/'));
  988. var root = rootPath.root;
  989. var json = jsonState;
  990. if (otherProto) {
  991. console.log('need to modify state...');
  992. json = this.helpers.replaceSubStringALL(jsonState, '/' + root + '/', '/' + otherProto + '/');//jsonState.replace(('/' + root + '/'), ('/' + otherProto +'/') );
  993. root = otherProto;
  994. console.log(json);
  995. }
  996. //var documents = this.db.user().get('documents');
  997. var saveRevision = new Date().valueOf();
  998. var stateForStore = {
  999. "root": root,
  1000. "filename": filename,
  1001. "inst": inst,
  1002. "timestamp": timestamp,
  1003. "extension": ".vwf.json",
  1004. "jsonState": json,
  1005. "publish": true
  1006. };
  1007. //let objName = loadInfo[ 'save_name' ] +'/'+ "savestate_" + loadInfo[ 'save_revision' ];
  1008. // "savestate_" + loadInfo[ 'save_revision' ] + '/' + loadInfo[ 'save_name' ] + '_vwf_json'
  1009. var docName = 'savestate_/' + root + '/' + filename + '_vwf_json';
  1010. _LCSDB.user().get('documents').get(root).get(docName).put(stateForStore, res => {
  1011. if (res) {
  1012. let noty = new Noty({
  1013. text: 'Saved to ' + docName,
  1014. timeout: 2000,
  1015. theme: 'mint',
  1016. layout: 'bottomRight',
  1017. type: 'success'
  1018. });
  1019. noty.show();
  1020. }
  1021. });
  1022. _LCSDB.user().get('worlds').get(root).get('info_json').once(res => {
  1023. if (res) {
  1024. let modified = saveRevision;
  1025. let newOwner = _LCSDB.user().is.pub;
  1026. let userName = _LCSDB.user().is.alias;
  1027. let obj = {
  1028. 'parent': userName + '/' + root,
  1029. 'owner': newOwner,
  1030. 'file': res.file,
  1031. //'modified': modified,
  1032. 'created': modified
  1033. }
  1034. let docInfoName = 'savestate_/' + root + '/' + filename + '_info_vwf_json';
  1035. _LCSDB.user().get('documents').get(root).get(docInfoName).not(res => {
  1036. _LCSDB.user().get('documents').get(root).get(docInfoName).put(obj);
  1037. });
  1038. _LCSDB.user().get('documents').get(root).get(docInfoName).get('created').not(res => {
  1039. _LCSDB.user().get('documents').get(root).get(docInfoName).get('created').put(modified);
  1040. });
  1041. _LCSDB.user().get('documents').get(root).get(docInfoName).get('modified').put(modified);
  1042. }
  1043. });
  1044. var docNameRev = 'savestate_' + saveRevision.toString() + '/' + root + '/' + filename + '_vwf_json';
  1045. _LCSDB.user().get('documents').get(root).get(docName).get('revs').get(docNameRev).put(stateForStore)
  1046. .path("revision").put(saveRevision);
  1047. // Save Config Information
  1048. var config = { "info": {}, "model": {}, "view": {} };
  1049. // Save browser title
  1050. config["info"]["title"] = document.title//$('title').html();
  1051. // Save model drivers
  1052. Object.keys(vwf_view.kernel.kernel.models).forEach(function (modelDriver) {
  1053. if (modelDriver.indexOf('vwf/model/') != -1) config["model"][modelDriver] = "";
  1054. });
  1055. // If neither glge or threejs model drivers are defined, specify nodriver
  1056. if (config["model"]["vwf/model/glge"] === undefined && config["model"]["vwf/model/threejs"] === undefined) config["model"]["nodriver"] = "";
  1057. // Save view drivers and associated parameters, if any
  1058. Object.keys(vwf_view.kernel.kernel.views).forEach(function (viewDriver) {
  1059. if (viewDriver.indexOf('vwf/view/') != -1) {
  1060. if (vwf_view.kernel.kernel.views[viewDriver].parameters) {
  1061. config["view"][viewDriver] = vwf_view.kernel.kernel.views[viewDriver].parameters;
  1062. }
  1063. else config["view"][viewDriver] = "";
  1064. }
  1065. });
  1066. //var jsonConfig = $.encoder.encodeForURL(JSON.stringify(config));
  1067. var jsonConfig = JSON.stringify(config);
  1068. let configStateForStore = {
  1069. "root": root,
  1070. "filename": filename,
  1071. "inst": inst,
  1072. "timestamp": timestamp,
  1073. "extension": "config.vwf.json",
  1074. "jsonState": jsonConfig
  1075. };
  1076. //let objName = loadInfo[ 'save_name' ] +'/'+ "savestate_" + loadInfo[ 'save_revision' ];
  1077. // "savestate_" + loadInfo[ 'save_revision' ] + '/' + loadInfo[ 'save_name' ] + '_vwf_json'
  1078. // let configName = 'savestate_/' + root + '/' + filename + '_config_vwf_json';
  1079. // let documentSaveConfigState = this.db.user().get(configName).put(configStateForStore);
  1080. // //documents.path(root).set(documentSaveConfigState);
  1081. // let configNameRev = 'savestate_' + saveRevision.toString() + '/' + root + '/' + filename + '_config_vwf_json';
  1082. // this.db.user().get(configNameRev).put(configStateForStore);
  1083. // this.db.user().get(configNameRev).path("revision").put(saveRevision);
  1084. //documentSaveConfigState.path('revs').set(documentSaveStateRevision);
  1085. // Save config file to server
  1086. // var xhrConfig = new XMLHttpRequest();
  1087. // xhrConfig.open("POST", "/" + root + "/save/" + filename, true);
  1088. // xhrConfig.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  1089. // xhrConfig.send("root=" + root + "/" + filename + "&filename=saveState&inst=" + inst + "&timestamp=" + timestamp + "&extension=.vwf.config.json" + "&jsonState=" + jsonConfig);
  1090. }
  1091. // LoadSavedState
  1092. async loadSavedState(filename, applicationpath, revision) {
  1093. console.log("Loading: " + filename);
  1094. let userName = await _LCS_WORLD_USER.get('alias').once().then();
  1095. if (revision) {
  1096. window.location.pathname = '/' + userName + applicationpath + '/load/' + filename + '/' + revision + '/';
  1097. }
  1098. else { // applicationpath + "/" + inst + '/load/' + filename + '/';
  1099. window.location.pathname = '/' + userName + applicationpath + '/load/' + filename + '/';
  1100. }
  1101. }
  1102. hideUIControl() {
  1103. let el = document.getElementById("ui-controls");
  1104. if (el) {
  1105. el.classList.remove("visible");
  1106. el.classList.add("not-visible");
  1107. }
  1108. }
  1109. showUIControl() {
  1110. let el = document.getElementById("ui-controls");
  1111. if (el) {
  1112. el.classList.remove("not-visible");
  1113. el.classList.add("visible");
  1114. }
  1115. }
  1116. hideProgressBar() {
  1117. var progressbar = document.getElementById("load-progressbar");
  1118. if (progressbar) {
  1119. progressbar.classList.remove("visible");
  1120. progressbar.classList.remove("mdc-linear-progress--indeterminate");
  1121. progressbar.classList.add("not-visible");
  1122. progressbar.classList.add("mdc-linear-progress--closed");
  1123. }
  1124. }
  1125. showProgressBar() {
  1126. let progressbar = document.getElementById("load-progressbar");
  1127. if (progressbar) {
  1128. progressbar.classList.remove("not-visible");
  1129. progressbar.classList.remove("mdc-linear-progress--closed");
  1130. progressbar.classList.add("visible");
  1131. progressbar.classList.add("mdc-linear-progress--indeterminate");
  1132. }
  1133. }
  1134. // SUPPORT of DELETE USER WORLDS & SAVE STATES (experimental)
  1135. // TODO: manual garbage collection
  1136. async deleteWorldState(worldName, indexState) {
  1137. let revs = await _LCSDB.user().get('documents').get(worldName).get(indexState).get('revs').once().then();
  1138. if (revs) {
  1139. for (const el of Object.keys(revs)) {
  1140. if (el !== '_') {
  1141. let doc = await _LCSDB.user().get('documents').get(worldName).get(indexState).get('revs').get(el).once().then();
  1142. for (const rev of Object.keys(doc)) {
  1143. if (rev !== '_') {
  1144. await _LCSDB.user().get('documents').get(worldName).get(indexState).get('revs').get(el).get(rev).put(null).then();
  1145. }
  1146. }
  1147. await _LCSDB.user().get('documents').get(worldName).get(indexState).get('revs').get(el).put(null).then();
  1148. }
  1149. }
  1150. }
  1151. // clear all state params
  1152. let stateDoc = await _LCSDB.user().get('documents').get(worldName).get(indexState).once().then();
  1153. for (const state of Object.keys(stateDoc)) {
  1154. if (state !== '_' && state !== 'revs') {
  1155. await _LCSDB.user().get('documents').get(worldName).get(indexState).get(state).put(null).then();
  1156. }
  1157. }
  1158. await _LCSDB.user().get('documents').get(worldName).get(indexState).get('revs').put(null).then();
  1159. await _LCSDB.user().get('documents').get(worldName).get(indexState).put(null).then();
  1160. }
  1161. async deleteWorld(name, type) {
  1162. if (type == 'proto') {
  1163. let worldName = name;
  1164. //TODO check for states (ask for deleting all states first...)
  1165. //delete states
  1166. let documents = await _LCSDB.user().get('documents').once().then();
  1167. if (documents) {
  1168. let states = await _LCSDB.user().get('documents').get(worldName).once().then();
  1169. if (states) {
  1170. for (const st of Object.keys(states)) {
  1171. if (st !== '_') {
  1172. if (states[st]) {
  1173. await this.deleteWorldState(worldName, st);
  1174. }
  1175. }
  1176. }
  1177. }
  1178. }
  1179. let worldFiles = await _LCSDB.user().get('worlds').get(worldName).once().then();
  1180. if (worldFiles) {
  1181. for (const el of Object.keys(worldFiles)) {
  1182. if (el !== '_') {
  1183. let doc = await _LCSDB.user().get('worlds').get(worldName).get(el).once().then();
  1184. if (doc) {
  1185. if (doc.file) {
  1186. for (const fEl of Object.keys(doc)) {
  1187. if (fEl !== '_') {
  1188. await _LCSDB.user().get('worlds').get(worldName).get(el).get(fEl).put(null).then();
  1189. }
  1190. }
  1191. await _LCSDB.user().get('worlds').get(worldName).get(el).put(null).then();
  1192. } else {
  1193. await _LCSDB.user().get('worlds').get(worldName).get(el).put(null).then()
  1194. }
  1195. }
  1196. }
  1197. }
  1198. }
  1199. // this.db.user().get('worlds').get(worldName).map((res, index) => {
  1200. // if(typeof res == 'object'){
  1201. // this.db.user().get('worlds').get(worldName).get(index)
  1202. // .get('file').put("null")
  1203. // .back(1)
  1204. // .get('modified').put("null")
  1205. // .back(1)
  1206. // .get('created').put("null")
  1207. // .back(1).put("null")
  1208. // } else {
  1209. // this.db.user().get('worlds').get(worldName).get(index).put("null")
  1210. // }
  1211. // })
  1212. await _LCSDB.user().get('worlds').get(worldName).put(null).then();
  1213. } else if (type == 'state') {
  1214. let worldName = name.split('/')[0];
  1215. let stateName = name.split('/')[2];
  1216. let stateEntryInfo = 'savestate_/' + worldName + '/' + stateName + '_info_vwf_json';
  1217. let stateEntry = 'savestate_/' + worldName + '/' + stateName + '_vwf_json';
  1218. await this.deleteWorldState(worldName, stateEntryInfo);
  1219. await this.deleteWorldState(worldName, stateEntry);
  1220. }
  1221. let noty = new Noty({
  1222. text: "World Deleted!",
  1223. timeout: 2000,
  1224. theme: 'mint',
  1225. layout: 'bottomRight',
  1226. type: 'success'
  1227. });
  1228. noty.show();
  1229. }
  1230. parseAppInstancesData(data) {
  1231. let jsonObj = JSON.parse(data);
  1232. var parsed = {};
  1233. let listData = {};
  1234. for (var prop in jsonObj) {
  1235. var name = prop.split('/')[1];
  1236. if (parsed[name]) {
  1237. parsed[name][prop] = jsonObj[prop];
  1238. } else {
  1239. parsed[name] = {};
  1240. parsed[name][prop] = jsonObj[prop];
  1241. }
  1242. }
  1243. //console.log(parsed);
  1244. for (var prop in parsed) {
  1245. var name = prop;
  1246. let obj = Object.entries(parsed[prop]);
  1247. var lists = {};
  1248. obj.forEach(el => {
  1249. if (el[1].loadInfo['save_name']) {
  1250. let saveName = prop + '/load/' + el[1].loadInfo.save_name;
  1251. if (!lists[saveName])
  1252. lists[saveName] = {};
  1253. lists[saveName][el[0]] = el[1]
  1254. } else {
  1255. if (!lists[name])
  1256. lists[name] = {};
  1257. lists[name][el[0]] = el[1]
  1258. }
  1259. });
  1260. // console.log(lists);
  1261. Object.entries(lists).forEach(list => {
  1262. listData[list[0]] = list[1];
  1263. })
  1264. }
  1265. return listData
  1266. // console.log(data)
  1267. }
  1268. async getAllStateWorldsInfoForUser(userAlias, cb) {
  1269. let userPub = await _LCSDB.get('users').get(userAlias).get('pub').once().then();
  1270. var db = _LCSDB.user(userPub);
  1271. if (_LCSDB.user().is) {
  1272. if (_LCSDB.user().is.alias == userAlias)
  1273. db = _LCSDB.user();
  1274. }
  1275. // db.get('worlds').once().map().once((val, index)=>{
  1276. //db.get('documents').get(index).once().map().load((res, datI)=>{
  1277. let myWorlds = await db.get('documents').once().then();
  1278. if (myWorlds) {
  1279. Object.keys(myWorlds).filter(el => el!=='_').forEach(w=>{
  1280. db.get('documents').get(w).once().map().once((res, datI)=>{
  1281. var doc = {};
  1282. if (datI.includes('_info_vwf_json')){
  1283. if (res && res !== 'null') {
  1284. if (res.file && res.file !== 'null') {
  1285. let saveName = datI.split('/')[2].replace('_info_vwf_json', "");
  1286. let worldDesc = JSON.parse(res.file);
  1287. let root = Object.keys(worldDesc)[0];
  1288. var appInfo = worldDesc[root]['en'];
  1289. let langID = localStorage.getItem('krestianstvo_locale');
  1290. if (langID) {
  1291. appInfo = worldDesc[root][langID]
  1292. }
  1293. doc = {
  1294. 'worldName': w + '/load/' + saveName,
  1295. 'created': res.created ? res.created : res.modified,
  1296. 'modified': res.modified,
  1297. 'type': 'saveState',
  1298. 'userAlias': userAlias,
  1299. 'info': appInfo
  1300. }
  1301. }
  1302. }
  1303. }
  1304. if (Object.keys(doc).length !== 0)
  1305. cb({[doc.worldName]: doc})
  1306. })
  1307. })
  1308. }
  1309. //})
  1310. }
  1311. async getAllStateWorldsInfoForUserPromise(userAlias) {
  1312. let userPub = await _LCSDB.get('users').get(userAlias).get('pub').once().then();
  1313. var db = _LCSDB.user(userPub);
  1314. if (_LCSDB.user().is) {
  1315. if (_LCSDB.user().is.alias == userAlias)
  1316. db = _LCSDB.user();
  1317. }
  1318. var states = {};
  1319. let worldDocs = await db.get('worlds').once().then();
  1320. if (worldDocs) {
  1321. let protos = Object.keys(worldDocs).filter(el => el !== '_');
  1322. if (protos) {
  1323. for (const el of protos) {
  1324. let info = await this.getSaveStates(userAlias, el);
  1325. if (Object.keys(info).length !== 0)
  1326. states[el] = info;
  1327. }
  1328. }
  1329. }
  1330. return states
  1331. }
  1332. async getAllProtoWorldsInfoForUser (userAlias, cb){
  1333. let userPub = await _LCSDB.get('users').get(userAlias).get('pub').once().then();
  1334. var db = _LCSDB.user(userPub);
  1335. if (_LCSDB.user().is) {
  1336. if (_LCSDB.user().is.alias == userAlias)
  1337. db = _LCSDB.user();
  1338. }
  1339. db.get('worlds').once().map().once((val, index)=>{
  1340. db.get('worlds').get(index).get('info_json').load(res=>{
  1341. var doc = {};
  1342. if (res && res !== 'null') {
  1343. if (res.file && res.file !== 'null') {
  1344. let worldDesc = JSON.parse(res.file);
  1345. let root = Object.keys(worldDesc)[0];
  1346. var appInfo = worldDesc[root]['en'];
  1347. let langID = localStorage.getItem('krestianstvo_locale');
  1348. if (langID) {
  1349. appInfo = worldDesc[root][langID]
  1350. }
  1351. doc = {
  1352. 'worldName': index,
  1353. 'created': res.created ? res.created : res.modified,
  1354. 'modified': res.modified,
  1355. 'type': 'proto',
  1356. 'userAlias': userAlias,
  1357. 'info': appInfo
  1358. }
  1359. }
  1360. }
  1361. if (Object.keys(doc).length !== 0)
  1362. cb({[index]: doc})
  1363. })
  1364. })
  1365. }
  1366. async getAllProtoWorldsInfoForUserPromise(userAlias) {
  1367. let userPub = await _LCSDB.get('users').get(userAlias).get('pub').once().then();
  1368. var db = _LCSDB.user(userPub);
  1369. if (_LCSDB.user().is) {
  1370. if (_LCSDB.user().is.alias == userAlias)
  1371. db = _LCSDB.user();
  1372. }
  1373. var worlds = {};
  1374. let worldDocs = await db.get('worlds').once().then();
  1375. if (worldDocs) {
  1376. let protos = Object.keys(worldDocs).filter(el => el !== '_');
  1377. if (protos) {
  1378. for (const el of protos) {
  1379. let info = await this.getWorldInfo(userAlias, el);
  1380. if (Object.keys(info).length !== 0)
  1381. worlds[el] = info;
  1382. }
  1383. }
  1384. }
  1385. return worlds
  1386. }
  1387. async getSaveStates(userAlias, worldName) {
  1388. let userPub = await _LCSDB.get('users').get(userAlias).get('pub').once().then();
  1389. var db = _LCSDB.user(userPub);
  1390. if (_LCSDB.user().is) {
  1391. if (_LCSDB.user().is.alias == userAlias)
  1392. db = _LCSDB.user();
  1393. }
  1394. var states = {};
  1395. let documents = await db.get('documents').once().then();
  1396. if(documents) {
  1397. let docs = await db.get('documents').get(worldName).once().then();
  1398. if (docs) {
  1399. let saves = Object.keys(docs).filter(el => el.includes('_info_vwf_json'));
  1400. if (saves) {
  1401. for (const el of saves) {
  1402. let stateName = el.split('/')[2].replace('_info_vwf_json', "");
  1403. let info = await this.getStateInfo(userAlias, worldName, stateName);
  1404. if (Object.keys(info).length !== 0)
  1405. states[stateName] = info;
  1406. }
  1407. }
  1408. }
  1409. }
  1410. return states
  1411. }
  1412. async getStateInfo(user, space, saveName) {
  1413. let userPub = await _LCSDB.get('users').get(user).get('pub').once().then();
  1414. var db = _LCSDB.user(userPub);
  1415. if (_LCSDB.user().is) {
  1416. if (_LCSDB.user().is.alias == user)
  1417. db = _LCSDB.user();
  1418. }
  1419. var info = {};
  1420. let docName = 'savestate_/' + space + '/' + saveName + '_info_vwf_json';
  1421. let world = await db.get('documents').get(space).get(docName).once().then();
  1422. if (world) {
  1423. let res = await db.get('documents').get(space).get(docName).once().then();
  1424. if (res && res !== 'null') {
  1425. if (res.file && res.file !== 'null') {
  1426. let worldDesc = JSON.parse(res.file);
  1427. let root = Object.keys(worldDesc)[0];
  1428. var appInfo = worldDesc[root]['en'];
  1429. let langID = localStorage.getItem('krestianstvo_locale');
  1430. if (langID) {
  1431. appInfo = worldDesc[root][langID]
  1432. }
  1433. info = {
  1434. 'worldName': space + '/load/' + saveName,
  1435. 'created': res.created ? res.created : res.modified,
  1436. 'modified': res.modified,
  1437. 'type': 'saveState',
  1438. 'userAlias': user,
  1439. 'info': appInfo
  1440. }
  1441. }
  1442. }
  1443. }
  1444. return info
  1445. }
  1446. async getWorldInfo(user, space) {
  1447. //get space for user
  1448. let userPub = await _LCSDB.get('users').get(user).get('pub').once().then();
  1449. var userdb = _LCSDB.user(userPub);
  1450. if (_LCSDB.user().is) {
  1451. if (_LCSDB.user().is.alias == user)
  1452. userdb = _LCSDB.user();
  1453. }
  1454. var info = {};
  1455. let world = await userdb.get('worlds').get(space).once().then();
  1456. if (world) {
  1457. let res = await userdb.get('worlds').get(space).get('info_json').once().then();
  1458. if (res && res !== 'null') {
  1459. if (res.file && res.file !== 'null') {
  1460. let worldDesc = JSON.parse(res.file);
  1461. let root = Object.keys(worldDesc)[0];
  1462. var appInfo = worldDesc[root]['en'];
  1463. let langID = localStorage.getItem('krestianstvo_locale');
  1464. if (langID) {
  1465. appInfo = worldDesc[root][langID]
  1466. }
  1467. info = {
  1468. 'worldName': space,
  1469. 'created': res.created ? res.created : res.modified,
  1470. 'modified': res.modified,
  1471. 'type': 'proto',
  1472. 'userAlias': user,
  1473. 'info': appInfo
  1474. }
  1475. }
  1476. }
  1477. }
  1478. return info
  1479. }
  1480. }
  1481. export { App }