Home Reference Source

cables_dev/cables_electron/src_client/electron_editor.js

  1. import { TalkerAPI } from "cables-shared-client";
  2.  
  3. /**
  4. * @name EditorParams
  5. * @type {object}
  6. * @property {{}} config config options for the ui
  7. * @property {boolean} config.isTrustedPatch does the user have write permission in the patch, always true in standalone
  8. * @property {string} config.platformClass the platform class to use in the ui, allows for hooks and overrides in community vs standalone
  9. * @property {string} config.urlCables url used for links to outside the sandbox on community platform
  10. * @property {string} config.urlSandbox url used for links to inside the sandbox on community platform
  11. * @property {{}} config.user current user object
  12. * @property {{}} config.usersettings current user settings
  13. * @property {{}} config.usersettings.settings current user editor preferences
  14. * @property {boolean} config.isDevEnv handle current environment as development environment?
  15. * @property {string} config.env string identifying the current environment
  16. * @property {string} config.patchId current patchid
  17. * @property {string} config.patchVersion current patchid if working on a backup version of a patch
  18. * @property {{}} config.socketcluster config for websocket connection in community platform
  19. * @property {boolean} config.remoteClient are we a remote client?
  20. * @property {{}} config.buildInfo buildinfo for the currently running version
  21. * @property {{}} config.patchConfig configuration handed over to the loaded patch
  22. * @property {boolean} config.patchConfig.allowEdit is the user allowed to edit the pacht, always true in standalone
  23. * @property {string} config.patchConfig.prefixAssetPath where to look for assets that are set to relative paths in the project
  24. */
  25.  
  26. /**
  27. * cables editor instance for electron standalone version
  28. * handles ipc messages from and to the ui
  29. *
  30. * @param {EditorParams} params
  31. */
  32. export default class ElectronEditor
  33. {
  34. constructor(params)
  35. {
  36. this.config = params.config;
  37. const frame = document.getElementById("editorIframe");
  38. this._talker = new TalkerAPI(frame.contentWindow);
  39. this._patchId = this.config.patchId;
  40.  
  41. window.addEventListener("unhandledrejection", (e) =>
  42. {
  43. this._talker.send("logError", { "level": "error", "message": e.reason });
  44. });
  45.  
  46. window.addEventListener("error", (e) =>
  47. {
  48. this._talker.send("logError", { "level": "error", "message": e.error });
  49. });
  50.  
  51. window.ipcRenderer.on("talkerMessage", (_event, data) =>
  52. {
  53. this._talker.send(data.cmd, data.data);
  54. });
  55.  
  56. /**
  57. * send patch config to ui
  58. *
  59. * @name ElectronEditor#requestPatchData
  60. * @param {*} data unused
  61. * @param {function} next callback
  62. * @listens TalkerAPI#requestPatchData
  63. */
  64. this._talker.addEventListener("requestPatchData", (data, next) =>
  65. {
  66. if (next) next(this.config);
  67. });
  68.  
  69. /**
  70. * notify ui of patch name change
  71. *
  72. * @name ElectronEditor#updatePatchName
  73. * @param {{}} data
  74. * @param {string} data.name the new patch name
  75. * @param {function} next callback
  76. * @listens TalkerAPI#updatePatchName
  77. */
  78. this._talker.addEventListener("updatePatchName", (data, next) =>
  79. {
  80. if (next) next(null, data);
  81. });
  82.  
  83. /**
  84. * reload the page
  85. *
  86. * @name ElectronEditor#reload
  87. * @param {*} data unused
  88. * @param {function} next unused
  89. * @listens TalkerAPI#reload
  90. */
  91. this._talker.addEventListener("reload", (data, next) =>
  92. {
  93. document.location.reload();
  94. });
  95.  
  96. /**
  97. * upload a file via the ui
  98. *
  99. * @name ElectronEditor#fileUploadStr
  100. * @param {*} data
  101. * @param {string} data.fileStr the file content as data-url
  102. * @param {string} data.filename the name of the file
  103. * @param {function} next callback
  104. * @listens TalkerAPI#fileUploadStr
  105. * @fires TalkerAPI#refreshFileManager
  106. * @fires TalkerAPI#fileUpdated
  107. */
  108. this._talker.addEventListener("fileUploadStr", (data, next) =>
  109. {
  110. this.api("fileUpload", data, (err, r) =>
  111. {
  112. const error = r && r.hasOwnProperty("error") ? r.error : null;
  113. this._talker.send("refreshFileManager");
  114. this._talker.send("fileUpdated", { "filename": r.filename });
  115.  
  116. if (error) this._talker.send("logError", { "level": error.level, "message": error.msg || error });
  117. next(error, r);
  118. });
  119. });
  120.  
  121. /**
  122. * update a file from the ui (e.g. edit a textfile)
  123. *
  124. * @name ElectronEditor#updateFile
  125. * @param {*} data
  126. * @param {string} data.content raw content of the file written to disk (e.g. ASCII)
  127. * @param {string} data.filename the name of the file
  128. * @param {function} next callback
  129. * @listens TalkerAPI#updateFile
  130. * @fires TalkerAPI#fileUpdated
  131. */
  132. this._talker.addEventListener("updateFile", (data, next) =>
  133. {
  134. this.api("updateFile", data, (err, r) =>
  135. {
  136. const error = r && r.hasOwnProperty("error") ? r.error : null;
  137. if (error) this._talker.send("logError", { "level": error.level, "message": error.msg || error });
  138. next(error, r);
  139. this._talker.send("fileUpdated", { "filename": data.fileName });
  140. });
  141. });
  142.  
  143. this._talker.addEventListener("createFile", (data, next) =>
  144. {
  145. this.api("createFile", data, (error, r) =>
  146. {
  147. if (error)
  148. {
  149. this._talker.send("logError", { "level": error.level, "message": error.msg || error });
  150. }
  151. else
  152. {
  153. if (window.standalone && window.standalone.gui && r)
  154. {
  155. window.standalone.gui.patchView.addAssetOpAuto(r);
  156. window.standalone.gui.fileManagerEditor.editAssetTextFile("file:" + r, "text");
  157. }
  158. }
  159. next(error, r);
  160. });
  161. });
  162.  
  163. this._talkerTopics = {
  164. "getOpInfo": {},
  165. "savePatch": { "needsProjectFile": true },
  166. "getPatch": {},
  167. "newPatch": { },
  168. "getAllProjectOps": {},
  169. "getOpDocsAll": {},
  170. "getOpDocs": {},
  171. "saveOpCode": {},
  172. "getOpCode": {},
  173. "opAttachmentGet": {},
  174. "formatOpCode": {},
  175. "saveUserSettings": {},
  176. "checkProjectUpdated": {},
  177. "opAddLib": {},
  178. "opAddCoreLib": {},
  179. "opAttachmentAdd": {},
  180. "opAttachmentDelete": {},
  181. "opRemoveLib": {},
  182. "opRemoveCoreLib": {},
  183. "getChangelog": {},
  184. "opAttachmentSave": {},
  185. "setIconSaved": {},
  186. "setIconUnsaved": {},
  187. "saveScreenshot": { },
  188. "getFilelist": {},
  189. "getFileDetails": {},
  190. "getLibraryFileInfo": {},
  191. "checkOpName": {},
  192. "getRecentPatches": {},
  193. "opCreate": { "needsProjectFile": true },
  194. "opRename": { },
  195. "opUpdate": {},
  196. "opDelete": {},
  197. "opClone": { },
  198. "opSaveLayout": { },
  199. "opSetSummary": { },
  200. "checkNumAssetPatches": {},
  201. "saveProjectAs": { },
  202. "gotoPatch": {},
  203. "getProjectOpDirs": {},
  204. "openDir": {},
  205. "selectFile": {},
  206. "selectDir": {},
  207. "setProjectName": { "needsProjectFile": true },
  208. "collectAssets": { "needsProjectFile": true },
  209. "collectOps": { "needsProjectFile": true },
  210. "getCollectionOpDocs": {},
  211. "patchCreateBackup": { "needsProjectFile": true },
  212. "addOpDependency": {},
  213. "removeOpDependency": {},
  214. "saveProjectOpDirOrder": { "needsProjectFile": true },
  215. "removeProjectOpDir": { "needsProjectFile": true },
  216. "exportPatch": { "needsProjectFile": true },
  217. "exportPatchBundle": { "needsProjectFile": true }
  218. };
  219.  
  220. Object.keys(this._talkerTopics).forEach((talkerTopic) =>
  221. {
  222. this._talker.addEventListener(talkerTopic, (data, next) =>
  223. {
  224. const topicConfig = this._talkerTopics[talkerTopic];
  225. window.ipcRenderer.invoke("talkerMessage", talkerTopic, data, topicConfig).then((r) =>
  226. {
  227. const error = r && r.hasOwnProperty("error") ? r : null;
  228. if (error) this._talker.send("logError", { "level": error.level, "message": error.msg || error });
  229. next(error, r);
  230. });
  231. });
  232. });
  233. }
  234.  
  235. /**
  236. * make a call to a method in electron_api
  237. *
  238. * @param cmd
  239. * @param data
  240. * @param next
  241. */
  242. api(cmd, data, next)
  243. {
  244. const topicConfig = this._talkerTopics[cmd];
  245. window.ipcRenderer.invoke("talkerMessage", cmd, data, topicConfig).then((r) =>
  246. {
  247. const error = r && r.hasOwnProperty("error") ? r : null;
  248. if (error) this._talker.send("logError", { "level": error.level, "message": error.msg || error });
  249. next(error, r);
  250. });
  251. }
  252.  
  253. editor(cmd, data, next)
  254. {
  255. this._talker.send(cmd, data, next);
  256. }
  257. }