instances.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /**
  2. * @license Licensed under the Apache License, Version 2.0 (the "License"):
  3. * http://www.apache.org/licenses/LICENSE-2.0
  4. */
  5. /**
  6. * @fileoverview Utility functions for handling Instances.
  7. */
  8. 'use strict';
  9. goog.provide('Blockly.Instances');
  10. goog.require('Blockly.Workspace');
  11. goog.require('goog.string');
  12. /**
  13. * Category to separate instance names from instances, procedures and
  14. * generated functions.
  15. */
  16. Blockly.Instances.NAME_TYPE = 'INSTANCE';
  17. /**
  18. * Find all user-created instances.
  19. * @param {?string}
  20. * @param {!Blockly.Workspace} workspace Workspace to transverse for instances.
  21. * @return {!Array.<string>} Array of instance names.
  22. */
  23. Blockly.Instances.allInstancesOf = function(instanceType, workspace) {
  24. var blocks;
  25. if (workspace.getAllBlocks) {
  26. blocks = workspace.getAllBlocks();
  27. } else {
  28. throw 'Not a valid Workspace: ' + workspace;
  29. }
  30. var instanceHash = Object.create(null);
  31. // Iterate through every block and add each instance to the hash.
  32. for (var i = 0; i < blocks.length; i++) {
  33. var blockInstances = blocks[i].getInstances(instanceType);
  34. for (var j = 0; j < blockInstances.length; j++) {
  35. var instanceName = blockInstances[j];
  36. // Instance name may be null if the block is only half-built.
  37. if (instanceName) {
  38. instanceHash[instanceName.toLowerCase()] = instanceName;
  39. }
  40. }
  41. }
  42. // Flatten the hash into a list.
  43. var instanceList = [];
  44. for (var name in instanceHash) {
  45. instanceList.push(instanceHash[name]);
  46. }
  47. return instanceList;
  48. };
  49. /** Returns all instances of all types. */
  50. Blockly.Instances.allInstances = function(workspace) {
  51. return Blockly.Instances.allInstancesOf(undefined, workspace);
  52. };
  53. /** Returns the first Instance name of a given type. */
  54. Blockly.Instances.getAnyInstanceOf = function(instanceType, workspace) {
  55. var blocks;
  56. if (workspace.getAllBlocks) {
  57. blocks = workspace.getAllBlocks();
  58. } else {
  59. throw 'Not a valid Workspace: ' + workspace;
  60. }
  61. for (var i = 0; i < blocks.length; i++) {
  62. var blockInstances = blocks[i].getInstances(instanceType);
  63. if (blockInstances.length) {
  64. return blockInstances[0];
  65. }
  66. }
  67. };
  68. /** Indicates if the given instance is present in the workspace. */
  69. Blockly.Instances.isInstancePresent = function(
  70. instanceName, instanceType, block) {
  71. var blocks;
  72. if (block.workspace && block.workspace.getAllBlocks) {
  73. blocks = block.workspace.getAllBlocks();
  74. } else {
  75. throw 'Not a valid block: ' + block;
  76. }
  77. for (var i = 0; i < blocks.length; i++) {
  78. var blockInstances = blocks[i].getInstances(instanceType);
  79. for (var j = 0; j < blockInstances.length; j++) {
  80. if ((blockInstances[j] === instanceName) && (blocks[i] !== block)) {
  81. return true;
  82. }
  83. }
  84. }
  85. return false;
  86. };
  87. /**
  88. * Find all instances of the specified name and type and rename them.
  89. * @param {string} oldName Instance to rename.
  90. * @param {string} newName New Instance name.
  91. * @param {!Blockly.Workspace} workspace Workspace rename instances in.
  92. */
  93. Blockly.Instances.renameInstance = function(
  94. oldName, newName, instanceType, workspace) {
  95. Blockly.Events.setGroup(true);
  96. var blocks = workspace.getAllBlocks();
  97. // Iterate through every block.
  98. for (var i = 0; i < blocks.length; i++) {
  99. blocks[i].renameInstance(oldName, newName, instanceType);
  100. }
  101. Blockly.Events.setGroup(false);
  102. };
  103. /**
  104. * Return a new instance name that is not yet being used as an instance or as a
  105. * variable name. This will try to generate single letter names in the range
  106. * 'i' to 'z' to start with.
  107. * If no unique name is located it will try 'i' to 'z', 'a' to 'h',
  108. * then 'i2' to 'z2' etc. Skip 'l'.
  109. * @param {!Blockly.Workspace} workspace The workspace to be unique in.
  110. * @return {string} New instance name.
  111. */
  112. Blockly.Instances.generateUniqueName = function(workspace) {
  113. var combinedList = Blockly.Variables.allVariables(workspace).concat(
  114. Blockly.Instances.allInstances(workspace));
  115. var newName = '';
  116. if (combinedList.length) {
  117. var nameSuffix = 1;
  118. var letters = 'ijkmnopqrstuvwxyzabcdefgh'; // No 'l'.
  119. var letterIndex = 0;
  120. var potName = letters.charAt(letterIndex);
  121. while (!newName) {
  122. var inUse = false;
  123. for (var i = 0; i < combinedList.length; i++) {
  124. if (combinedList[i].toLowerCase() == potName) {
  125. // This potential name is already used.
  126. inUse = true;
  127. break;
  128. }
  129. }
  130. if (inUse) {
  131. // Try the next potential name.
  132. letterIndex++;
  133. if (letterIndex == letters.length) {
  134. // Reached the end of the character sequence so back to 'i'.
  135. // a new suffix.
  136. letterIndex = 0;
  137. nameSuffix++;
  138. }
  139. potName = letters.charAt(letterIndex);
  140. if (nameSuffix > 1) {
  141. potName += nameSuffix;
  142. }
  143. } else {
  144. // We can use the current potential name.
  145. newName = potName;
  146. }
  147. }
  148. } else {
  149. newName = 'i';
  150. }
  151. return newName;
  152. };
  153. /**
  154. * Return a version of the instance name that has not yet been used.
  155. * It does so by adding a number at the end of the name.
  156. * @param {string} instanceName Instance name to make unique.
  157. * @param {!Blockly.Workspace|Blockly.Block} workspace The workspace to be unique in.
  158. * @return {string} Unique instance name based on name input.
  159. */
  160. Blockly.Instances.convertToUniqueName = function(instanceName, workspace) {
  161. var combinedList = Blockly.Variables.allVariables(workspace).concat(
  162. Blockly.Instances.allInstances(workspace));
  163. return Blockly.Instances.appendToName_(instanceName, combinedList);
  164. };
  165. /** */
  166. Blockly.Instances.convertToUniqueNameBlock = function(instanceName, block) {
  167. var blocks;
  168. if (block.workspace) {
  169. blocks = block.workspace.getAllBlocks();
  170. } else {
  171. throw 'Not a valid Workspace: ' + workspace;
  172. }
  173. var instanceHash = Object.create(null);
  174. // Iterate through every block and add each instance to the hash.
  175. for (var i = 0; i < blocks.length; i++) {
  176. // Do not add to the list this block instance
  177. if (blocks[i] !== block) {
  178. var blockInstances = blocks[i].getInstances();
  179. for (var j = 0; j < blockInstances.length; j++) {
  180. var blockInstanceName = blockInstances[j];
  181. // Instance name may be null if the block is only half-built.
  182. if (blockInstanceName) {
  183. instanceHash[blockInstanceName.toLowerCase()] = blockInstanceName;
  184. }
  185. }
  186. }
  187. }
  188. // Flatten the hash into a list.
  189. var instanceList = [];
  190. for (var name in instanceHash) {
  191. instanceList.push(instanceHash[name]);
  192. }
  193. var combinedList = Blockly.Variables.allVariables(block.workspace).concat(
  194. instanceList);
  195. return Blockly.Instances.appendToName_(instanceName, combinedList);
  196. };
  197. /** */
  198. Blockly.Instances.appendToName_ = function(instanceName, nameList) {
  199. if (!instanceName) {
  200. return Blockly.Instances.generateUniqueName(workspace);
  201. } else {
  202. var newName = instanceName;
  203. var nameSuffix = 2;
  204. if (instanceName.match(/_\d+$/)) {
  205. // instanceName ends with and underscore and a number, so increase count
  206. var instanceNameSuffix = instanceName.match(/\d+$/)[0];
  207. instanceName = instanceName.slice(
  208. 0, (instanceNameSuffix.length * -1) - 1);
  209. nameSuffix = parseInt(instanceNameSuffix, 10) + 1;
  210. newName = instanceName + '_' + nameSuffix;
  211. }
  212. while (nameList.indexOf(newName) !== -1) {
  213. newName = instanceName + '_' + nameSuffix++;
  214. }
  215. return newName;
  216. }
  217. };