saveSnippet.tsx 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. import * as React from "react";
  2. import { Observable } from "babylonjs/Misc/observable";
  3. import { PropertyChangedEvent } from "../../../../../components/propertyChangedEvent";
  4. import { ButtonLineComponent } from "../../../../../sharedUiComponents/lines/buttonLineComponent";
  5. import { Tools } from "babylonjs/Misc/tools";
  6. import { Animation } from "babylonjs/Animations/animation";
  7. import { LockObject } from "../../../../../sharedUiComponents/tabs/propertyGrids/lockObject";
  8. import { Nullable } from "babylonjs/types";
  9. import { GlobalState } from "../../../../globalState";
  10. interface ISaveSnippetProps {
  11. // Animation to save
  12. animations: Nullable<Animation[]>;
  13. // Observable
  14. onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
  15. // Global lock object
  16. lockObject: LockObject;
  17. // Global state
  18. globalState: GlobalState;
  19. // Snippet server address
  20. snippetServer: string;
  21. // Snippert id to save the snippet
  22. snippetId: string;
  23. }
  24. export interface Snippet {
  25. url: string;
  26. id: string;
  27. }
  28. interface SelectedAnimation {
  29. id: string;
  30. name: string;
  31. index: number;
  32. selected: boolean;
  33. }
  34. /**
  35. * Saves the animation snippet to the Babylon.js site or downloads the animation file locally
  36. */
  37. export class SaveSnippet extends React.Component<ISaveSnippetProps, { selectedAnimations: SelectedAnimation[] }> {
  38. constructor(props: ISaveSnippetProps) {
  39. super(props);
  40. let animList = this.props.animations?.map((animation, i) => {
  41. return {
  42. id: `${animation.name}_${animation.targetProperty}`,
  43. name: animation.name,
  44. index: i,
  45. selected: false,
  46. };
  47. });
  48. this.state = { selectedAnimations: animList ?? [] };
  49. }
  50. /**
  51. * Set the selected animations to save
  52. * @param e Input event
  53. */
  54. handleCheckboxChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  55. e.preventDefault();
  56. let index = parseInt(e.target.id.replace("save_", ""));
  57. let updated = this.state.selectedAnimations?.map((item) => {
  58. if (item.index === index) {
  59. item.selected = !item.selected;
  60. }
  61. return item;
  62. });
  63. this.setState({ selectedAnimations: updated });
  64. };
  65. /**
  66. * Stringify the selected animation
  67. */
  68. stringifySelectedAnimations() {
  69. const content: string[] = [];
  70. this.state.selectedAnimations.forEach((animation) => {
  71. if (animation.selected) {
  72. const selected = this.props.animations && this.props.animations[animation.index];
  73. if (selected) {
  74. content.push(selected.serialize());
  75. }
  76. }
  77. });
  78. return JSON.stringify(content);
  79. }
  80. /**
  81. * Save the selected animations to a local file
  82. */
  83. saveToFile = () => {
  84. const content = this.stringifySelectedAnimations();
  85. Tools.Download(new Blob([content]), "animations.json");
  86. };
  87. /**
  88. * Save the selected animations if a snippet ID is set
  89. */
  90. saveToSnippet = () => {
  91. if (this.props.snippetId !== "") {
  92. let serverId = this.props.snippetId;
  93. const serverUrl = this.props.snippetServer;
  94. const content = this.stringifySelectedAnimations();
  95. var xmlHttp = new XMLHttpRequest();
  96. xmlHttp.onreadystatechange = () => {
  97. if (xmlHttp.readyState == 4) {
  98. if (xmlHttp.status == 200) {
  99. var snippet = JSON.parse(xmlHttp.responseText);
  100. const oldId = serverId;
  101. serverId = snippet.id;
  102. if (snippet.version && snippet.version != "0") {
  103. serverId += "#" + snippet.version;
  104. }
  105. this.forceUpdate();
  106. if (navigator.clipboard) {
  107. navigator.clipboard.writeText(serverId);
  108. }
  109. let windowAsAny = window as any;
  110. if (windowAsAny.Playground && oldId) {
  111. windowAsAny.Playground.onRequestCodeChangeObservable.notifyObservers({
  112. regex: new RegExp(oldId, "g"),
  113. replace: serverId,
  114. });
  115. }
  116. alert(
  117. "Animations saved with ID: " +
  118. serverId +
  119. " (please note that the id was also saved to your clipboard)"
  120. );
  121. } else {
  122. alert("Unable to save your animations");
  123. }
  124. }
  125. };
  126. xmlHttp.open("POST", serverUrl + (serverId ? "/" + serverId : ""), true);
  127. xmlHttp.setRequestHeader("Content-Type", "application/json");
  128. var dataToSend = {
  129. payload: JSON.stringify({
  130. animations: content,
  131. }),
  132. name: "",
  133. description: "",
  134. tags: "",
  135. };
  136. xmlHttp.send(JSON.stringify(dataToSend));
  137. }
  138. };
  139. render() {
  140. return (
  141. <div className="save-container">
  142. <div className="item-list">
  143. <ul>
  144. {this.props.animations?.map((animation, i) => {
  145. return (
  146. <li key={i}>
  147. <div>
  148. <label>
  149. <input
  150. id={`save_${i}`}
  151. name={`save_${animation?.name}`}
  152. type="checkbox"
  153. checked={this.state.selectedAnimations[i].selected}
  154. onChange={this.handleCheckboxChange}
  155. />
  156. {animation?.name}
  157. </label>
  158. </div>
  159. </li>
  160. );
  161. })}
  162. </ul>
  163. </div>
  164. <div className="save-buttons">
  165. {this.props.snippetId && (
  166. <ButtonLineComponent label="Save to snippet server" onClick={this.saveToSnippet} />
  167. )}
  168. <ButtonLineComponent label="Save" onClick={this.saveToFile} />
  169. </div>
  170. <div className="save-server">
  171. <p>Snippet Server: </p>&nbsp;
  172. <p> {this.props.snippetServer ?? "-"}</p>
  173. </div>
  174. </div>
  175. );
  176. }
  177. }