toolbox-tree.component.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  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 Component that details how blocks are
  21. * rendered in the toolbox in AccessibleBlockly. Also handles any interactions
  22. * with the blocks.
  23. * @author madeeha@google.com (Madeeha Ghori)
  24. */
  25. blocklyApp.ToolboxTreeComponent = ng.core
  26. .Component({
  27. selector: 'blockly-toolbox-tree',
  28. template: `
  29. <li #parentList [id]="idMap['parentList']" role="treeitem"
  30. [ngClass]="{blocklyHasChildren: displayBlockMenu || block.inputList.length > 0, blocklyActiveDescendant: index == 0 && noCategories}"
  31. [attr.aria-labelledBy]="generateAriaLabelledByAttr('blockly-block-summary', idMap['blockSummaryLabel'])"
  32. [attr.aria-selected]="index == 0 && tree.getAttribute('aria-activedescendant') == 'blockly-toolbox-tree-node0'"
  33. [attr.aria-level]="level">
  34. <label #blockSummaryLabel [id]="idMap['blockSummaryLabel']">{{block.toString()}}</label>
  35. <ol role="group" *ngIf="displayBlockMenu || block.inputList.length > 0"
  36. [attr.aria-level]="level+1">
  37. <li #listItem class="blocklyHasChildren" [id]="idMap['listItem']"
  38. [attr.aria-labelledBy]="generateAriaLabelledByAttr('blockly-block-menu', idMap['blockSummaryLabel'])"
  39. *ngIf="displayBlockMenu" role="treeitem"
  40. aria-selected=false [attr.aria-level]="level+1">
  41. <label #label [id]="idMap['label']">{{'BLOCK_ACTION_LIST'|translate}}</label>
  42. <ol role="group" *ngIf="displayBlockMenu" [attr.aria-level]="level+2">
  43. <li #workspaceCopy [id]="idMap['workspaceCopy']" role="treeitem"
  44. [attr.aria-labelledBy]="generateAriaLabelledByAttr(idMap['workspaceCopyButton'], 'blockly-button')"
  45. [attr.aria-level]="level+2" aria-selected=false>
  46. <button #workspaceCopyButton [id]="idMap['workspaceCopyButton']"
  47. (click)="copyToWorkspace(block)">
  48. {{'COPY_TO_WORKSPACE'|translate}}
  49. </button>
  50. </li>
  51. <li #blockCopy [id]="idMap['blockCopy']" role="treeitem"
  52. [attr.aria-labelledBy]="generateAriaLabelledByAttr(idMap['blockCopyButton'], 'blockly-button')"
  53. [attr.aria-level]="level+2" aria-selected=false>
  54. <button #blockCopyButton [id]="idMap['blockCopyButton']"
  55. (click)="clipboardService.copy(block, true)">
  56. {{'COPY_TO_CLIPBOARD'|translate}}
  57. </button>
  58. </li>
  59. <li #sendToSelected [id]="idMap['sendToSelected']" role="treeitem"
  60. [attr.aria-labelledBy]="generateAriaLabelledByAttr(idMap['sendToSelectedButton'], 'blockly-button', !canBeCopiedToMarkedConnection(block))"
  61. [attr.aria-level]="level+2" aria-selected=false>
  62. <button #sendToSelectedButton
  63. [id]="idMap['sendToSelectedButton']"
  64. (click)="copyToMarked(block)"
  65. [disabled]="!canBeCopiedToMarkedConnection(block)">
  66. {{'COPY_TO_MARKED_SPOT'|translate}}
  67. </button>
  68. </li>
  69. </ol>
  70. </li>
  71. <div *ngFor="#inputBlock of block.inputList; #i=index">
  72. <blockly-field *ngFor="#field of inputBlock.fieldRow; #j=index"
  73. [attr.aria-level]="level+1" [field]="field"
  74. [level]="level+1">
  75. </blockly-field>
  76. <blockly-toolbox-tree *ngIf="inputBlock.connection && inputBlock.connection.targetBlock()"
  77. [block]="inputBlock.connection.targetBlock()"
  78. [displayBlockMenu]="false"
  79. [level]="level+1">
  80. </blockly-toolbox-tree>
  81. <li #listItem1 [id]="idMap['listItem' + i]" role="treeitem"
  82. *ngIf="inputBlock.connection && !inputBlock.connection.targetBlock()"
  83. [attr.aria-labelledBy]="generateAriaLabelledByAttr('blockly-argument-text', idMap['listItem' + i + 'Label'])"
  84. [attr.aria-level]="level+1" aria-selected=false>
  85. <!--TODO(madeeha): i18n here will need to happen in a different way due to the way grammar changes based on language.-->
  86. <label #label [id]="idMap['listItem' + i + 'Label']">
  87. {{utilsService.getInputTypeLabel(inputBlock.connection)}}
  88. {{utilsService.getBlockTypeLabel(inputBlock)}} needed:
  89. </label>
  90. </li>
  91. </div>
  92. </ol>
  93. </li>
  94. <blockly-toolbox-tree *ngIf= "block.nextConnection && block.nextConnection.targetBlock()"
  95. [level]="level"
  96. [block]="block.nextConnection.targetBlock()"
  97. [displayBlockMenu]="false">
  98. </blockly-toolbox-tree>
  99. `,
  100. directives: [blocklyApp.FieldComponent, ng.core.forwardRef(function() {
  101. return blocklyApp.ToolboxTreeComponent;
  102. })],
  103. inputs: [
  104. 'block', 'displayBlockMenu', 'level', 'index', 'tree', 'noCategories', 'isTopLevel'],
  105. pipes: [blocklyApp.TranslatePipe]
  106. })
  107. .Class({
  108. constructor: [
  109. blocklyApp.ClipboardService, blocklyApp.TreeService, blocklyApp.UtilsService,
  110. function(_clipboardService, _treeService, _utilsService) {
  111. // ClipboardService and UtilsService are app-wide singleton services.
  112. // TreeService is from the parent ToolboxComponent.
  113. this.infoBlocks = Object.create(null);
  114. this.clipboardService = _clipboardService;
  115. this.treeService = _treeService;
  116. this.utilsService = _utilsService;
  117. }],
  118. ngOnInit: function() {
  119. var elementsNeedingIds = ['blockSummaryLabel'];
  120. if (this.displayBlockMenu || this.block.inputList.length){
  121. elementsNeedingIds = elementsNeedingIds.concat(['listItem', 'label',
  122. 'workspaceCopy', 'workspaceCopyButton', 'blockCopy',
  123. 'blockCopyButton', 'sendToSelected', 'sendToSelectedButton']);
  124. }
  125. for (var i = 0; i < this.block.inputList.length; i++){
  126. elementsNeedingIds.push('listItem' + i, 'listItem' + i + 'Label')
  127. }
  128. this.idMap = this.utilsService.generateIds(elementsNeedingIds);
  129. if (this.isTopLevel) {
  130. this.idMap['parentList'] = 'blockly-toolbox-tree-node0';
  131. } else {
  132. this.idMap['parentList'] = this.utilsService.generateUniqueId();
  133. }
  134. },
  135. generateAriaLabelledByAttr: function(mainLabel, secondLabel, isDisabled) {
  136. return this.utilsService.generateAriaLabelledByAttr(
  137. mainLabel, secondLabel, isDisabled);
  138. },
  139. canBeCopiedToMarkedConnection: function(block) {
  140. return this.clipboardService.canBeCopiedToMarkedConnection(block);
  141. },
  142. copyToWorkspace: function(block) {
  143. var xml = Blockly.Xml.blockToDom(block);
  144. Blockly.Xml.domToBlock(blocklyApp.workspace, xml);
  145. alert('Added block to workspace: ' + block.toString());
  146. },
  147. copyToClipboard: function(block) {
  148. if (this.clipboardService) {
  149. this.clipboardService.copy(block, true);
  150. }
  151. },
  152. copyToMarked: function(block) {
  153. if (this.clipboardService) {
  154. this.clipboardService.pasteToMarkedConnection(block);
  155. }
  156. }
  157. });