clipboard.service.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /**
  2. * AccessibleBlockly
  3. *
  4. * Copyright 2016 Google Inc.
  5. * https://developers.google.com/blockly/
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the 'License');
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an 'AS IS' BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. */
  19. /**
  20. * @fileoverview Angular2 Service that handles the clipboard and marked spots.
  21. * @author madeeha@google.com (Madeeha Ghori)
  22. */
  23. blocklyApp.ClipboardService = ng.core
  24. .Class({
  25. constructor: [
  26. blocklyApp.NotificationsService, blocklyApp.UtilsService,
  27. blocklyApp.AudioService,
  28. function(_notificationsService, _utilsService, _audioService) {
  29. this.clipboardBlockXml_ = null;
  30. this.clipboardBlockPreviousConnection_ = null;
  31. this.clipboardBlockNextConnection_ = null;
  32. this.clipboardBlockOutputConnection_ = null;
  33. this.markedConnection_ = null;
  34. this.notificationsService = _notificationsService;
  35. this.utilsService = _utilsService;
  36. this.audioService = _audioService;
  37. }],
  38. areConnectionsCompatible_: function(blockConnection, connection) {
  39. // Check that both connections exist, that it's the right kind of
  40. // connection, and that the types match.
  41. return Boolean(
  42. connection && blockConnection &&
  43. Blockly.OPPOSITE_TYPE[blockConnection.type] == connection.type &&
  44. connection.checkType_(blockConnection));
  45. },
  46. isCompatibleWithClipboard: function(connection) {
  47. var previousConnection = this.clipboardBlockPreviousConnection_;
  48. var nextConnection = this.clipboardBlockNextConnection_;
  49. var outputConnection = this.clipboardBlockOutputConnection_;
  50. return Boolean(
  51. this.areConnectionsCompatible_(connection, previousConnection) ||
  52. this.areConnectionsCompatible_(connection, nextConnection) ||
  53. this.areConnectionsCompatible_(connection, outputConnection));
  54. },
  55. getMarkedConnectionBlock: function() {
  56. if (!this.markedConnection_) {
  57. return null;
  58. } else {
  59. return this.markedConnection_.getSourceBlock();
  60. }
  61. },
  62. isAnyConnectionMarked: function() {
  63. return Boolean(this.markedConnection_);
  64. },
  65. isMovableToMarkedConnection: function(block) {
  66. // It should not be possible to move any ancestor of the block containing
  67. // the marked spot to the marked spot.
  68. if (!this.markedConnection_) {
  69. return false;
  70. }
  71. var markedSpotAncestorBlock = this.getMarkedConnectionBlock();
  72. while (markedSpotAncestorBlock) {
  73. if (markedSpotAncestorBlock.id == block.id) {
  74. return false;
  75. }
  76. markedSpotAncestorBlock = markedSpotAncestorBlock.getParent();
  77. }
  78. return this.canBeCopiedToMarkedConnection(block);
  79. },
  80. canBeCopiedToMarkedConnection: function(block) {
  81. if (!this.markedConnection_ ||
  82. !this.markedConnection_.getSourceBlock().workspace) {
  83. return false;
  84. }
  85. var potentialConnections = [
  86. block.outputConnection,
  87. block.previousConnection,
  88. block.nextConnection
  89. ];
  90. var that = this;
  91. return potentialConnections.some(function(connection) {
  92. return that.areConnectionsCompatible_(
  93. connection, that.markedConnection_);
  94. });
  95. },
  96. markConnection: function(connection) {
  97. this.markedConnection_ = connection;
  98. this.notificationsService.setStatusMessage(Blockly.Msg.MARKED_SPOT_MSG);
  99. },
  100. cut: function(block) {
  101. this.copy(block);
  102. block.dispose(true);
  103. },
  104. copy: function(block) {
  105. this.clipboardBlockXml_ = Blockly.Xml.blockToDom(block);
  106. Blockly.Xml.deleteNext(this.clipboardBlockXml_);
  107. this.clipboardBlockPreviousConnection_ = block.previousConnection;
  108. this.clipboardBlockNextConnection_ = block.nextConnection;
  109. this.clipboardBlockOutputConnection_ = block.outputConnection;
  110. },
  111. isClipboardEmpty: function() {
  112. return !this.clipboardBlockXml_;
  113. },
  114. pasteFromClipboard: function(inputConnection) {
  115. var connection = inputConnection;
  116. // If the connection is a 'previousConnection' and that connection is
  117. // already joined to something, use the 'nextConnection' of the
  118. // previous block instead in order to do an insertion.
  119. if (inputConnection.type == Blockly.PREVIOUS_STATEMENT &&
  120. inputConnection.isConnected()) {
  121. connection = inputConnection.targetConnection;
  122. }
  123. var reconstitutedBlock = Blockly.Xml.domToBlock(blocklyApp.workspace,
  124. this.clipboardBlockXml_);
  125. switch (connection.type) {
  126. case Blockly.NEXT_STATEMENT:
  127. connection.connect(reconstitutedBlock.previousConnection);
  128. break;
  129. case Blockly.PREVIOUS_STATEMENT:
  130. connection.connect(reconstitutedBlock.nextConnection);
  131. break;
  132. default:
  133. connection.connect(reconstitutedBlock.outputConnection);
  134. }
  135. this.audioService.playConnectSound();
  136. this.notificationsService.setStatusMessage(
  137. this.utilsService.getBlockDescription(reconstitutedBlock) + ' ' +
  138. Blockly.Msg.PASTED_BLOCK_FROM_CLIPBOARD_MSG);
  139. return reconstitutedBlock.id;
  140. },
  141. pasteToMarkedConnection: function(block) {
  142. var xml = Blockly.Xml.blockToDom(block);
  143. var reconstitutedBlock = Blockly.Xml.domToBlock(
  144. blocklyApp.workspace, xml);
  145. var potentialConnections = [
  146. reconstitutedBlock.outputConnection,
  147. reconstitutedBlock.previousConnection,
  148. reconstitutedBlock.nextConnection
  149. ];
  150. var connectionSuccessful = false;
  151. for (var i = 0; i < potentialConnections.length; i++) {
  152. if (this.areConnectionsCompatible_(
  153. this.markedConnection_, potentialConnections[i])) {
  154. this.markedConnection_.connect(potentialConnections[i]);
  155. this.audioService.playConnectSound();
  156. connectionSuccessful = true;
  157. break;
  158. }
  159. }
  160. if (!connectionSuccessful) {
  161. console.error('ERROR: Could not connect block to marked spot.');
  162. return;
  163. }
  164. this.markedConnection_ = null;
  165. return reconstitutedBlock.id;
  166. }
  167. });