SuperGlue.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. SC.loadPackage({ 'SuperGlue': {
  2. comment: 'Hello friend, I am SuperGlue!\nMy single instance is the central object of the system. It provides the start routine with method SuperGlue>>init, and stores itsself in the global variable window.SuperGlue',
  3. sharedProperties: {
  4. version: { comment: 'SuperGlue\'s current version is...',
  5. initValue: '1.0'
  6. }
  7. },
  8. properties: {
  9. document: { comment: 'This is the current document.' },
  10. selection: { comment: 'The selection is the focus of the editor, holding on or more elements to edit.' },
  11. clipboard: { comment: 'This is a proxy to the operating system\'s clipboard.' },
  12. history: { comment: 'The editing history is a stack object with undo/redo-methods.' },
  13. windowManager: { comment: 'I have a windowManager which holds the 2nd-level editing interface.' },
  14. keyboard: { comment: 'This is a controller object processing keyboard commands.' },
  15. server: { comment: 'I keep an interface to the server under the current domain (if available).' },
  16. fileManager: { comment: 'I provide a FileManager for the user\'s file system on the server (if available).' },
  17. askBeforeUnload: { comment: 'Shall I ask the user before reloading the page?',
  18. transform: function(val){
  19. return val
  20. ? (window.onbeforeunload = function(){
  21. return 'Do you want to cancel your work and don\'t save it?'
  22. })
  23. : (window.onbeforeunload = void 0);
  24. }
  25. }
  26. },
  27. methods: {
  28. init: {
  29. comment: 'I am SuperGlue\'s start routine, yay!',
  30. code: function(){
  31. // Initialization of the whole system is "mission critical",
  32. // so any failure should be catched and reported to the user.
  33. try {
  34. // Set SmallClasses's error handling during init
  35. SC.setHandlerForMessageNotUnderstood(function(selector, errorMsg, context){
  36. console.log('Error with selector: ', selector, ' in context: ', context);
  37. throw new Error(errorMsg);
  38. });
  39. // Explicit failures
  40. var metaData = document.querySelector('meta[name=generator]');
  41. if( metaData.getAttribute('content') !== 'SuperGlue' ){
  42. throw new Error('This is not a SuperGlue page, you can\'t change it.')
  43. }
  44. if( this.do('compareVersions', {
  45. pageVersion: metaData.getAttribute('data-superglue-version'),
  46. pluginVersion: this.class.get('version')
  47. })
  48. ){
  49. throw new Error(
  50. 'This page needs version '
  51. + metaData.getAttribute('data-superglue-version')
  52. + '. Please update your SuperGlue browser add-on.'
  53. )
  54. }
  55. // Make myself a global object (the only one, thou shall not have others beside me)
  56. window.SuperGlue = this;
  57. // Initialize all main components of the system
  58. this.set({ document: SC.init('Document') });
  59. this.set({
  60. selection: SC.init('Selection'),
  61. clipboard: SC.init('Clipboard'),
  62. history: SC.init('History'),
  63. windowManager: SC.init('WindowManager'),
  64. keyboard: SC.init('Keyboard'),
  65. server: SC.init('Server', window.document.location.origin),
  66. fileManager: SC.init('FileManager')
  67. });
  68. this.get('document').do('setUpWorkspace');
  69. // Finish initialization
  70. this.set({'askBeforeUnload' : true});
  71. var editingMarker = document.createElement('meta');
  72. editingMarker.setAttribute('name', 'superglue-mode');
  73. editingMarker.setAttribute('content', 'editing');
  74. editingMarker.setAttribute('data-superglue', 'editing-interface');
  75. document.getElementsByTagName('head')[0].appendChild(editingMarker);
  76. // Reset SmallClasses's error handling to normal
  77. SC.setHandlerForMessageNotUnderstood();
  78. // Print console.log
  79. console.log([
  80. '************************************************',
  81. ' SuperGlue editor has successfully started!',
  82. '',
  83. ' To access the running system\'s code',
  84. ' open the bystem browser, just enter',
  85. ' > SC.do(\'SCSystemBrowser\', \'open\')',
  86. '************************************************'
  87. ].join('\n'));
  88. // Flash the outlines
  89. SuperGlue.get('document').set({ showOutlines: true });
  90. window.setTimeout(function(){
  91. SuperGlue.get('document').set({ showOutlines: false });
  92. }, 700);
  93. } catch(error) {
  94. // Catch any initialization error
  95. alert('Something went wrong starting SuperGlue\'s editing tool.\n\n' + error.message);
  96. console.log('Failed to initialize SuperGlue:\n', error);
  97. return;
  98. }
  99. }
  100. },
  101. savePage: {
  102. comment: 'I save the current page to a SuperGlue server. My parameters are { path: aString, <optional>remoteOrigin: aString }.',
  103. code: function(saveOptions){
  104. var thisPage = SC.init('Compiler').get('pageAsHTML5'),
  105. server = saveOptions.remoteOrigin
  106. ? SC.init('Server', saveOptions.remoteOrigin)
  107. : this.get('server');
  108. this.get('windowManager').set({ activityIndicator: true });
  109. server.do('uploadHTML', {
  110. path: saveOptions.path,
  111. data: thisPage,
  112. onerror: function(){
  113. SuperGlue.get('windowManager').set({ activityIndicator: false });
  114. console.log(this);
  115. alert('Critical error: The page could not be saved.\nSee console for more details.');
  116. },
  117. onprogress: function(){
  118. },
  119. onresponse: function(){
  120. SuperGlue.get('windowManager').set({ activityIndicator: false });
  121. }
  122. })
  123. }
  124. },
  125. compareVersions: {
  126. comment: 'I check for version compatability of page and plugin. Return is true for out-of-date!',
  127. code: function (arg) {
  128. var v1 = arg.pageVersion,
  129. v2 = arg.pluginVersion,
  130. v1parts = v1.split('.'),
  131. v2parts = v2.split('.');
  132. for (var i = 0; i < v1parts.length; ++i) {
  133. if (v2parts.length == i) {
  134. return true;
  135. }
  136. if (v1parts[i] == v2parts[i]) {
  137. continue;
  138. }
  139. else if (v1parts[i] > v2parts[i]) {
  140. return true;
  141. }
  142. else {
  143. return false;
  144. }
  145. }
  146. if (v1parts.length != v2parts.length) {
  147. return false;
  148. }
  149. return false;
  150. }
  151. }
  152. }
  153. }});