From 738d5d66692fffb006278d04b489f980ab588cb1 Mon Sep 17 00:00:00 2001 From: Karan Purohit Date: Wed, 8 Mar 2017 00:12:22 +0530 Subject: [PATCH 001/217] Adding new minimap demo --- demos/minimap/icon.png | Bin 0 -> 4243 bytes demos/minimap/index.html | 91 +++++++++++++++ demos/minimap/minimap.js | 247 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 338 insertions(+) create mode 100644 demos/minimap/icon.png create mode 100644 demos/minimap/index.html create mode 100644 demos/minimap/minimap.js diff --git a/demos/minimap/icon.png b/demos/minimap/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..870caa070d8e4a9f1a295cad8c4570d8132694cf GIT binary patch literal 4243 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 literal 0 HcmV?d00001 diff --git a/demos/minimap/index.html b/demos/minimap/index.html new file mode 100644 index 000000000..ce4a7d9f2 --- /dev/null +++ b/demos/minimap/index.html @@ -0,0 +1,91 @@ + + + + + Blockly Demo: Minimap + + + + + + + +

Blockly > + Demos > Minimap

+ +

This is a simple demo showing how a minimap can be implemented.

+ + + + + + +
+
+
+
+
+ + + + + + + + diff --git a/demos/minimap/minimap.js b/demos/minimap/minimap.js new file mode 100644 index 000000000..17deef213 --- /dev/null +++ b/demos/minimap/minimap.js @@ -0,0 +1,247 @@ +/** +* Blockly Demos: Code +* +* Copyright 2017 Google Inc. +* https://developers.google.com/blockly/ +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +/** +* @fileoverview JavaScript for Blockly's Minimap demo. +* @author karnpurohit@gmail.com (Karan Purohit) +*/ +'use strict'; + +/** +* Creating a seperate namespace for minimap. +*/ +var Minimap = {}; + +/** +* initilize the workspace and minimap. +* @param {Workspace} workspace The main workspace of the user +* @param {Workspace} minimap The workspace that will be used as a minimap +*/ +Minimap.init = function(workspace,minimap){ + this.workspace= workspace; + this.minimap= minimap; + + //Adding scroll callback functionlity to vScroll just for this demo. + //IMPORTANT: This should be changed when there is proper UI event handling + // api available and should be handled by workspace's event listeners + this.workspace.scrollbar.vScroll.onScroll_ = function(){ + var ratio = this.handlePosition_ / this.scrollViewSize_; + if (isNaN(ratio)) { + ratio = 0; + } + var xyRatio = {}; + if (this.horizontal_) { + xyRatio.x = ratio; + } else { + xyRatio.y = ratio; + } + this.workspace_.setMetrics(xyRatio); + + // get the absolutePosition + var absolutePosition = (this.handlePosition_/this.ratio_); + + // firing the scroll change listener + Minimap.onScrollChange(absolutePosition,this.horizontal_); + }; + + // used as left padding in the minimap + this.PADDING = 5; + + // required to stop a positive feedback loop when user clicks minimap + // and the scroll changes, which inturn may change minimap. + this.disableScrollChange=false; + + // Listen to events on the main workspace. + this.workspace.addChangeListener(Minimap.mirrorEvent); + + //Get rectangle bounding the minimap div. + this.rect = document.getElementById('mapDiv').getBoundingClientRect(); + // Create a svg overlay on the top of mapDiv for the minimap + this.svg = Blockly.utils.createSvgElement('svg', { + 'xmlns': 'http://www.w3.org/2000/svg', + 'xmlns:html': 'http://www.w3.org/1999/xhtml', + 'xmlns:xlink': 'http://www.w3.org/1999/xlink', + 'version': '1.1', + 'height': this.rect.bottom-this.rect.top, + 'width': this.rect.right-this.rect.left, + 'class': 'minimap', + }, document.getElementById('mapDiv')); + this.svg.style.top=this.rect.top; + this.svg.style.left=this.rect.left; + + // Creating a rectangle in the minimap that represents current view. + Blockly.utils.createSvgElement('rect', { + 'width':100, + 'height':100, + 'class':'mapDragger' + },this.svg); + + // Rectangle in the minimap that represents current view. + this.mapDragger = this.svg.childNodes[0]; + + // Adding mouse events to the rectangle, to make it Draggable + this.mapDragger.addEventListener("mousedown",Minimap.mousedown,false); + this.mapDragger.addEventListener("mouseup",Minimap.mouseup); + this.mapDragger.addEventListener("mousemove",Minimap.mouseover); + this.mapDragger.addEventListener("mouseout",Minimap.mouseout); + + //When the window change, we need to resize the minimap window. + window.addEventListener('resize', Minimap.repositionMinimap); + + // click event for the minimap + // TODO: Drag event + this.svg.addEventListener('mouseup',Minimap.updateMapDragger); + + //boolen to check whether I am dragging the surface or not + this.isDragging= false; +}; + +Minimap.mousedown = function(e){ + Minimap.isDragging=true; + e.stopPropagation(); +}; + +Minimap.mouseup = function(e){ + Minimap.isDragging = false; + Minimap.updateMapDragger(e); + e.stopPropagation(); +}; + +Minimap.mouseout = function(){ + Minimap.isDragging = false; +}; + +Minimap.mouseover = function(e){ + if(Minimap.isDragging){ + Minimap.updateMapDragger(e); + } + e.stopPropagation(); +}; + +/** +* initilize the workspace and minimap. +* @param {Event} event Event that triggered in the main workspace. +*/ +Minimap.mirrorEvent = function(event){ + if (event.type == Blockly.Events.UI) { + return; // Don't mirror UI events. + } + // Convert event to JSON. This could then be transmitted across the net. + var json = event.toJson(); + // Convert JSON back into an event, then execute it. + var minimapEvent = Blockly.Events.fromJson(json, Minimap.minimap); + minimapEvent.run(true); + Minimap.scaleMinimap(); + Minimap.setDraggerHeight(); +}; + +/** +* Called when window is resized. Repositions the minimap overlay. +*/ +Minimap.repositionMinimap = function(){ + Minimap.rect = document.getElementById('mapDiv').getBoundingClientRect(); + Minimap.svg.style.top=Minimap.rect.top; + Minimap.svg.style.left=Minimap.rect.left; +}; + +/** +* updates the rectangle's height and position. +*/ +Minimap.setDraggerHeight = function(){ + var workspaceMetrics = Minimap.workspace.getMetrics(); + var draggerHeight=(workspaceMetrics.viewHeight/Minimap.workspace.scale)*Minimap.minimap.scale; + // its zero when first block is placed + if(draggerHeight==0){ + return; + } + Minimap.mapDragger.setAttribute("height",draggerHeight); +}; + +/** +* Updates the overall position of the viewport of the minimap by appropriately +* using translate functions. +*/ +Minimap.scaleMinimap = function(){ + var minimapBoundingBox = Minimap.minimap.getBlocksBoundingBox(); + var workspaceBoundingBox = Minimap.workspace.getBlocksBoundingBox(); + var workspaceMetrics = Minimap.workspace.getMetrics(); + var minimapMetrics = Minimap.minimap.getMetrics(); + + //scaling the mimimap such that all the blocks can be seen in the viewport + //this padding is default because this is how to scrollbar(in main workspace) is implemented + var topPadding = (workspaceMetrics.viewHeight)*Minimap.minimap.scale/(2*Minimap.workspace.scale); + + // if actual padding is more than half view ports height, change it to actual padding/ + if((workspaceBoundingBox.y*Minimap.workspace.scale-workspaceMetrics.contentTop) + *Minimap.minimap.scale/Minimap.workspace.scale>topPadding){ + topPadding=(workspaceBoundingBox.y*Minimap.workspace.scale-workspaceMetrics.contentTop) + *Minimap.minimap.scale/Minimap.workspace.scale; + } + var scalex = (minimapMetrics.viewWidth-Minimap.PADDING)/minimapBoundingBox.width; + var scaley = (minimapMetrics.viewHeight-2*topPadding)/minimapBoundingBox.height; + Minimap.minimap.setScale(Math.min(scalex,scaley)); + + // translating the minimap + Minimap.minimap.translate(-minimapBoundingBox.x*Minimap.minimap.scale+Minimap.PADDING, + -minimapMetrics.contentTop*Minimap.minimap.scale + topPadding); +}; + +/** +* Handles the onclick event on the minimapBoundingBox. Changes mapDraggers position. +* @param {Event} e Event from the mouse click +*/ +Minimap.updateMapDragger = function(e){ + var y=e.clientY; + var draggerHeight = Minimap.mapDragger.getAttribute("height"); + var finalY = y-Minimap.rect.top-draggerHeight/2; + var maxValidY = (Minimap.workspace.getMetrics().contentHeight-Minimap.workspace.getMetrics().viewHeight) + *Minimap.minimap.scale; + if(y+draggerHeight/2>Minimap.rect.bottom){ + finalY = Minimap.rect.bottom-Minimap.rect.top-draggerHeight; + }else if(ymaxValidY){ + finalY=maxValidY; + } + Minimap.mapDragger.setAttribute("y", finalY); + + // required, otherwise creates a feedback loop + Minimap.disableScrollChange=true; + Minimap.workspace.scrollbar.vScroll.set((finalY*Minimap.workspace.scale)/Minimap.minimap.scale); + Minimap.disableScrollChange=false; +}; + +/** +* Handles the onclick event on the minimapBoundingBox, paramaters are passed by +* the event handler +* @param {Float} position This is the absolute postion of the scrollbar. +* @param {boolean} horizontal Informs if the change event if for horizontal(true) +* scrollbar or vertical(false) scrollbar. +*/ +Minimap.onScrollChange = function(position,horizontal){ + if(horizontal){ + return; + } + var newDraggerPosition = (position*Minimap.minimap.scale/Minimap.workspace.scale); + if(!Minimap.disableScrollChange){ + Minimap.mapDragger.setAttribute("y",newDraggerPosition); + } +}; From f77325f289fec9bbb751d596d8e9f91c3825b309 Mon Sep 17 00:00:00 2001 From: Karan Purohit Date: Wed, 8 Mar 2017 10:17:38 +0530 Subject: [PATCH 002/217] Basic code style changes. Adding a few more comments. Return early if disableScrollChange in onScrollChange listener. --- demos/minimap/minimap.js | 151 +++++++++++++++++++++------------------ 1 file changed, 80 insertions(+), 71 deletions(-) diff --git a/demos/minimap/minimap.js b/demos/minimap/minimap.js index 17deef213..cd884a510 100644 --- a/demos/minimap/minimap.js +++ b/demos/minimap/minimap.js @@ -29,17 +29,17 @@ var Minimap = {}; /** -* initilize the workspace and minimap. -* @param {Workspace} workspace The main workspace of the user -* @param {Workspace} minimap The workspace that will be used as a minimap +* Initilize the workspace and minimap. +* @param {Workspace} workspace The main workspace of the user. +* @param {Workspace} minimap The workspace that will be used as a minimap. */ -Minimap.init = function(workspace,minimap){ - this.workspace= workspace; - this.minimap= minimap; +Minimap.init = function(workspace, minimap){ + this.workspace = workspace; + this.minimap = minimap; //Adding scroll callback functionlity to vScroll just for this demo. //IMPORTANT: This should be changed when there is proper UI event handling - // api available and should be handled by workspace's event listeners + // api available and should be handled by workspace's event listeners. this.workspace.scrollbar.vScroll.onScroll_ = function(){ var ratio = this.handlePosition_ / this.scrollViewSize_; if (isNaN(ratio)) { @@ -53,26 +53,30 @@ Minimap.init = function(workspace,minimap){ } this.workspace_.setMetrics(xyRatio); - // get the absolutePosition - var absolutePosition = (this.handlePosition_/this.ratio_); + // Code above is same as the original onScroll_ function in core/scrollbar.js. + // New code starts from here. - // firing the scroll change listener - Minimap.onScrollChange(absolutePosition,this.horizontal_); + // Get the absolutePosition. + var absolutePosition = (this.handlePosition_ / this.ratio_); + + // Firing the scroll change listener. + Minimap.onScrollChange(absolutePosition, this.horizontal_); }; - // used as left padding in the minimap + // Used as left padding in the minimap. this.PADDING = 5; - // required to stop a positive feedback loop when user clicks minimap + // Required to stop a positive feedback loop when user clicks minimap // and the scroll changes, which inturn may change minimap. - this.disableScrollChange=false; + this.disableScrollChange = false; // Listen to events on the main workspace. this.workspace.addChangeListener(Minimap.mirrorEvent); //Get rectangle bounding the minimap div. this.rect = document.getElementById('mapDiv').getBoundingClientRect(); - // Create a svg overlay on the top of mapDiv for the minimap + + // Create a svg overlay on the top of mapDiv for the minimap. this.svg = Blockly.utils.createSvgElement('svg', { 'xmlns': 'http://www.w3.org/2000/svg', 'xmlns:html': 'http://www.w3.org/1999/xhtml', @@ -82,34 +86,33 @@ Minimap.init = function(workspace,minimap){ 'width': this.rect.right-this.rect.left, 'class': 'minimap', }, document.getElementById('mapDiv')); - this.svg.style.top=this.rect.top; - this.svg.style.left=this.rect.left; + this.svg.style.top = this.rect.top; + this.svg.style.left = this.rect.left; // Creating a rectangle in the minimap that represents current view. Blockly.utils.createSvgElement('rect', { 'width':100, 'height':100, 'class':'mapDragger' - },this.svg); + }, this.svg); // Rectangle in the minimap that represents current view. this.mapDragger = this.svg.childNodes[0]; - // Adding mouse events to the rectangle, to make it Draggable - this.mapDragger.addEventListener("mousedown",Minimap.mousedown,false); - this.mapDragger.addEventListener("mouseup",Minimap.mouseup); - this.mapDragger.addEventListener("mousemove",Minimap.mouseover); - this.mapDragger.addEventListener("mouseout",Minimap.mouseout); + // Adding mouse events to the rectangle, to make it Draggable. + this.mapDragger.addEventListener("mousedown", Minimap.mousedown,false); + this.mapDragger.addEventListener("mouseup", Minimap.mouseup); + this.mapDragger.addEventListener("mousemove", Minimap.mouseover); + this.mapDragger.addEventListener("mouseout", Minimap.mouseout); //When the window change, we need to resize the minimap window. window.addEventListener('resize', Minimap.repositionMinimap); - // click event for the minimap - // TODO: Drag event - this.svg.addEventListener('mouseup',Minimap.updateMapDragger); + // Mouse up event for the minimap. + this.svg.addEventListener('mouseup', Minimap.updateMapDragger); - //boolen to check whether I am dragging the surface or not - this.isDragging= false; + //Boolen to check whether I am dragging the surface or not. + this.isDragging = false; }; Minimap.mousedown = function(e){ @@ -135,7 +138,7 @@ Minimap.mouseover = function(e){ }; /** -* initilize the workspace and minimap. +* Initilize the workspace and minimap. * @param {Event} event Event that triggered in the main workspace. */ Minimap.mirrorEvent = function(event){ @@ -156,21 +159,21 @@ Minimap.mirrorEvent = function(event){ */ Minimap.repositionMinimap = function(){ Minimap.rect = document.getElementById('mapDiv').getBoundingClientRect(); - Minimap.svg.style.top=Minimap.rect.top; - Minimap.svg.style.left=Minimap.rect.left; + Minimap.svg.style.top = Minimap.rect.top; + Minimap.svg.style.left = Minimap.rect.left; }; /** -* updates the rectangle's height and position. +* Updates the rectangle's height and position. */ Minimap.setDraggerHeight = function(){ var workspaceMetrics = Minimap.workspace.getMetrics(); - var draggerHeight=(workspaceMetrics.viewHeight/Minimap.workspace.scale)*Minimap.minimap.scale; - // its zero when first block is placed - if(draggerHeight==0){ + var draggerHeight = (workspaceMetrics.viewHeight / Minimap.workspace.scale) * Minimap.minimap.scale; + // It's zero when first block is placed. + if(draggerHeight == 0){ return; } - Minimap.mapDragger.setAttribute("height",draggerHeight); + Minimap.mapDragger.setAttribute("height", draggerHeight); }; /** @@ -183,65 +186,71 @@ Minimap.scaleMinimap = function(){ var workspaceMetrics = Minimap.workspace.getMetrics(); var minimapMetrics = Minimap.minimap.getMetrics(); - //scaling the mimimap such that all the blocks can be seen in the viewport - //this padding is default because this is how to scrollbar(in main workspace) is implemented - var topPadding = (workspaceMetrics.viewHeight)*Minimap.minimap.scale/(2*Minimap.workspace.scale); + //Scaling the mimimap such that all the blocks can be seen in the viewport. + //This padding is default because this is how to scrollbar(in main workspace) is implemented. + var topPadding = (workspaceMetrics.viewHeight) * Minimap.minimap.scale / (2 * Minimap.workspace.scale); - // if actual padding is more than half view ports height, change it to actual padding/ - if((workspaceBoundingBox.y*Minimap.workspace.scale-workspaceMetrics.contentTop) - *Minimap.minimap.scale/Minimap.workspace.scale>topPadding){ - topPadding=(workspaceBoundingBox.y*Minimap.workspace.scale-workspaceMetrics.contentTop) - *Minimap.minimap.scale/Minimap.workspace.scale; + // If actual padding is more than half view ports height, change it to actual padding. + if((workspaceBoundingBox.y * Minimap.workspace.scale - workspaceMetrics.contentTop) + * Minimap.minimap.scale / Minimap.workspace.scale > topPadding){ + topPadding = (workspaceBoundingBox.y * Minimap.workspace.scale - workspaceMetrics.contentTop) + * Minimap.minimap.scale / Minimap.workspace.scale; } - var scalex = (minimapMetrics.viewWidth-Minimap.PADDING)/minimapBoundingBox.width; - var scaley = (minimapMetrics.viewHeight-2*topPadding)/minimapBoundingBox.height; - Minimap.minimap.setScale(Math.min(scalex,scaley)); + var scalex = (minimapMetrics.viewWidth - Minimap.PADDING) / minimapBoundingBox.width; + var scaley = (minimapMetrics.viewHeight - 2 * topPadding) / minimapBoundingBox.height; + Minimap.minimap.setScale(Math.min(scalex, scaley)); - // translating the minimap - Minimap.minimap.translate(-minimapBoundingBox.x*Minimap.minimap.scale+Minimap.PADDING, - -minimapMetrics.contentTop*Minimap.minimap.scale + topPadding); + // Translating the minimap. + Minimap.minimap.translate( - minimapBoundingBox.x * Minimap.minimap.scale+Minimap.PADDING, + - minimapMetrics.contentTop * Minimap.minimap.scale + topPadding); }; /** * Handles the onclick event on the minimapBoundingBox. Changes mapDraggers position. -* @param {Event} e Event from the mouse click +* @param {Event} e Event from the mouse click. */ Minimap.updateMapDragger = function(e){ - var y=e.clientY; + var y = e.clientY; var draggerHeight = Minimap.mapDragger.getAttribute("height"); - var finalY = y-Minimap.rect.top-draggerHeight/2; - var maxValidY = (Minimap.workspace.getMetrics().contentHeight-Minimap.workspace.getMetrics().viewHeight) - *Minimap.minimap.scale; - if(y+draggerHeight/2>Minimap.rect.bottom){ - finalY = Minimap.rect.bottom-Minimap.rect.top-draggerHeight; - }else if(y Minimap.rect.bottom){ + finalY = Minimap.rect.bottom - Minimap.rect.top - draggerHeight; + }else if(y < Minimap.rect.top + draggerHeight / 2){ finalY = 0; } - // do not go below loew bound of scrollbar - if(finalY>maxValidY){ - finalY=maxValidY; + // Do not go below loew bound of scrollbar. + if(finalY > maxValidY){ + finalY = maxValidY; } Minimap.mapDragger.setAttribute("y", finalY); - // required, otherwise creates a feedback loop - Minimap.disableScrollChange=true; - Minimap.workspace.scrollbar.vScroll.set((finalY*Minimap.workspace.scale)/Minimap.minimap.scale); - Minimap.disableScrollChange=false; + // Required, otherwise creates a feedback loop. + Minimap.disableScrollChange = true; + Minimap.workspace.scrollbar.vScroll.set((finalY * Minimap.workspace.scale) / Minimap.minimap.scale); + Minimap.disableScrollChange = false; }; /** * Handles the onclick event on the minimapBoundingBox, paramaters are passed by -* the event handler +* the event handler. * @param {Float} position This is the absolute postion of the scrollbar. * @param {boolean} horizontal Informs if the change event if for horizontal(true) * scrollbar or vertical(false) scrollbar. */ -Minimap.onScrollChange = function(position,horizontal){ +Minimap.onScrollChange = function(position, horizontal){ + + if(Minimap.disableScrollChange){ + return; + } + + // Currently the minimap automatically scales (see function Minimap.scaleMinimap) if the new block is created/moved + // beyond the width of the minimap. Compelete horizontal view is always visible in the minimap. if(horizontal){ return; } - var newDraggerPosition = (position*Minimap.minimap.scale/Minimap.workspace.scale); - if(!Minimap.disableScrollChange){ - Minimap.mapDragger.setAttribute("y",newDraggerPosition); - } + + var newDraggerPosition = (position * Minimap.minimap.scale / Minimap.workspace.scale); + Minimap.mapDragger.setAttribute("y", newDraggerPosition); }; From 4e9055a343e9d9f908bcfb107ec8325742540b01 Mon Sep 17 00:00:00 2001 From: Karan Purohit Date: Sun, 12 Mar 2017 15:29:05 +0530 Subject: [PATCH 003/217] Adding horizontal scrolling. Changed scroll change callbacks from onScroll_ to setHandlePosition. onScroll_ is not challed when workspace is dragged. --- demos/minimap/index.html | 7 ++- demos/minimap/minimap.js | 103 +++++++++++++++++++++++++++++---------- 2 files changed, 79 insertions(+), 31 deletions(-) diff --git a/demos/minimap/index.html b/demos/minimap/index.html index ce4a7d9f2..2e495fdb1 100644 --- a/demos/minimap/index.html +++ b/demos/minimap/index.html @@ -30,7 +30,7 @@
-
+
@@ -51,7 +51,6 @@ - + + From 619237c05d14bc7603ce4974edfec26f85ee1c24 Mon Sep 17 00:00:00 2001 From: Karan Purohit Date: Sun, 2 Apr 2017 13:31:46 +0530 Subject: [PATCH 006/217] Minimap position bug fix for browsers other than chrome. Added touch support. --- demos/minimap/minimap.js | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/demos/minimap/minimap.js b/demos/minimap/minimap.js index 6359503dd..4ac687e39 100644 --- a/demos/minimap/minimap.js +++ b/demos/minimap/minimap.js @@ -90,8 +90,8 @@ Minimap.init = function(workspace, minimap){ 'width': this.rect.right-this.rect.left, 'class': 'minimap', }, document.getElementById('mapDiv')); - this.svg.style.top = this.rect.top; - this.svg.style.left = this.rect.left; + this.svg.style.top = this.rect.top + 'px'; + this.svg.style.left = this.rect.left + 'px'; // Creating a rectangle in the minimap that represents current view. Blockly.utils.createSvgElement('rect', { @@ -104,7 +104,8 @@ Minimap.init = function(workspace, minimap){ this.mapDragger = this.svg.childNodes[0]; // Adding mouse events to the rectangle, to make it Draggable. - this.mapDragger.addEventListener("mousedown", Minimap.mousedown,false); + // Using Blockly.bindEvent_ to attach mouse/touch listeners. + Blockly.bindEvent_(this.mapDragger, "mousedown", null, Minimap.mousedown); //When the window change, we need to resize the minimap window. window.addEventListener('resize', Minimap.repositionMinimap); @@ -117,16 +118,19 @@ Minimap.init = function(workspace, minimap){ }; Minimap.mousedown = function(e){ - document.addEventListener("mousemove", Minimap.mousemove); - document.addEventListener("mouseup", Minimap.mouseup); + // Using Blockly.bindEvent_ to attach mouse/touch listeners. + Minimap.mouseMoveBindData = Blockly.bindEvent_(document,"mousemove", null, Minimap.mousemove); + Minimap.mouseUpBindData = Blockly.bindEvent_(document,"mouseup", null, Minimap.mouseup); + Minimap.isDragging=true; e.stopPropagation(); }; Minimap.mouseup = function(e){ Minimap.isDragging = false; - document.removeEventListener("mousemove", Minimap.mousemove); - document.removeEventListener("mouseup", Minimap.mouseup); + // Removing listeners. + Blockly.unbindEvent_(Minimap.mouseUpBindData); + Blockly.unbindEvent_(Minimap.mouseMoveBindData); Minimap.updateMapDragger(e); e.stopPropagation(); }; @@ -161,8 +165,8 @@ Minimap.mirrorEvent = function(event){ */ Minimap.repositionMinimap = function(){ Minimap.rect = document.getElementById('mapDiv').getBoundingClientRect(); - Minimap.svg.style.top = Minimap.rect.top; - Minimap.svg.style.left = Minimap.rect.left; + Minimap.svg.style.top = Minimap.rect.top + 'px'; + Minimap.svg.style.left = Minimap.rect.left + 'px'; }; /** From 8e199ec04b48400b0d553958b479469dcf1ef3bc Mon Sep 17 00:00:00 2001 From: CoryDCode Date: Mon, 3 Apr 2017 16:16:50 -0700 Subject: [PATCH 007/217] Adding an add variable modal to accessible Blockly. (#1015) * Adding the remove variable modal and functionality to accessible Blockly. * Adding the add variable modal for accessible Blockly. --- accessible/app.component.js | 2 + accessible/field-segment.component.js | 2 +- accessible/sidebar.component.js | 15 +- accessible/toolbox-modal.service.js | 21 +++ accessible/variable-add-modal.component.js | 162 +++++++++++++++++++++ accessible/variable-modal.service.js | 18 ++- demos/accessible/index.html | 2 + 7 files changed, 217 insertions(+), 5 deletions(-) create mode 100644 accessible/variable-add-modal.component.js diff --git a/accessible/app.component.js b/accessible/app.component.js index 775f5411f..216520498 100644 --- a/accessible/app.component.js +++ b/accessible/app.component.js @@ -38,6 +38,7 @@ blocklyApp.AppComponent = ng.core.Component({ + @@ -52,6 +53,7 @@ blocklyApp.AppComponent = ng.core.Component({ blocklyApp.BlockOptionsModalComponent, blocklyApp.SidebarComponent, blocklyApp.ToolboxModalComponent, + blocklyApp.VariableAddModalComponent, blocklyApp.VariableRenameModalComponent, blocklyApp.VariableRemoveModalComponent, blocklyApp.WorkspaceComponent diff --git a/accessible/field-segment.component.js b/accessible/field-segment.component.js index 4d528286b..d0020a7fa 100644 --- a/accessible/field-segment.component.js +++ b/accessible/field-segment.component.js @@ -55,7 +55,7 @@ blocklyApp.FieldSegmentComponent = ng.core.Component({ (keydown.enter)="selectOption()" tabindex="-1"> diff --git a/accessible/sidebar.component.js b/accessible/sidebar.component.js index de5ba6ebc..016fac979 100644 --- a/accessible/sidebar.component.js +++ b/accessible/sidebar.component.js @@ -52,6 +52,11 @@ blocklyApp.SidebarComponent = ng.core.Component({ class="blocklySidebarButton"> {{'ERASE_WORKSPACE'|translate}} + `, pipes: [blocklyApp.TranslatePipe] @@ -62,9 +67,10 @@ blocklyApp.SidebarComponent = ng.core.Component({ blocklyApp.ToolboxModalService, blocklyApp.TreeService, blocklyApp.UtilsService, + blocklyApp.VariableModalService, function( blockConnectionService, toolboxModalService, treeService, - utilsService) { + utilsService, variableService) { // ACCESSIBLE_GLOBALS is a global variable defined by the containing // page. It should contain a key, customSidebarButtons, describing // additional buttons that should be displayed after the default ones. @@ -77,6 +83,7 @@ blocklyApp.SidebarComponent = ng.core.Component({ this.toolboxModalService = toolboxModalService; this.treeService = treeService; this.utilsService = utilsService; + this.variableModalService = variableService; this.ID_FOR_ATTACH_TO_LINK_BUTTON = 'blocklyAttachToLinkBtn'; this.ID_FOR_CREATE_NEW_GROUP_BUTTON = 'blocklyCreateNewGroupBtn'; @@ -88,6 +95,9 @@ blocklyApp.SidebarComponent = ng.core.Component({ isWorkspaceEmpty: function() { return this.utilsService.isWorkspaceEmpty(); }, + hasVariableCategory: function() { + return this.toolboxModalService.toolboxHasVariableCategory(); + }, clearWorkspace: function() { blocklyApp.workspace.clear(); this.treeService.clearAllActiveDescs(); @@ -104,5 +114,8 @@ blocklyApp.SidebarComponent = ng.core.Component({ showToolboxModalForCreateNewGroup: function() { this.toolboxModalService.showToolboxModalForCreateNewGroup( this.ID_FOR_CREATE_NEW_GROUP_BUTTON); + }, + showAddVariableModal: function() { + this.variableModalService.showAddModal_("item"); } }); diff --git a/accessible/toolbox-modal.service.js b/accessible/toolbox-modal.service.js index 4103309f0..66211b505 100644 --- a/accessible/toolbox-modal.service.js +++ b/accessible/toolbox-modal.service.js @@ -42,6 +42,7 @@ blocklyApp.ToolboxModalService = ng.core.Class({ this.selectedToolboxCategories = null; this.onSelectBlockCallback = null; this.onDismissCallback = null; + this.hasVariableCategory = null; // The aim of the pre-show hook is to populate the modal component with // the information it needs to display the modal (e.g., which categories // and blocks to display). @@ -119,6 +120,26 @@ blocklyApp.ToolboxModalService = ng.core.Class({ isModalShown: function() { return this.modalIsShown; }, + toolboxHasVariableCategory: function() { + if (this.hasVariableCategory === null) { + var toolboxXmlElt = document.getElementById('blockly-toolbox-xml'); + var toolboxCategoryElts = toolboxXmlElt.getElementsByTagName('category'); + var that = this; + Array.from(toolboxCategoryElts).forEach( + function(categoryElt) { + var custom = categoryElt.attributes.custom; + if (custom && custom.value == Blockly.VARIABLE_CATEGORY_NAME) { + that.hasVariableCategory = true; + } + }); + + if (this.hasVariableCategory === null) { + this.hasVariableCategory = false; + } + } + + return this.hasVariableCategory; + }, showModal_: function( selectedToolboxCategories, onSelectBlockCallback, onDismissCallback) { this.selectedToolboxCategories = selectedToolboxCategories; diff --git a/accessible/variable-add-modal.component.js b/accessible/variable-add-modal.component.js new file mode 100644 index 000000000..1ea6eddfd --- /dev/null +++ b/accessible/variable-add-modal.component.js @@ -0,0 +1,162 @@ +/** + * AccessibleBlockly + * + * Copyright 2017 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview Component representing the variable rename modal. + * + * @author corydiers@google.com (Cory Diers) + */ + +blocklyApp.VariableAddModalComponent = ng.core.Component({ + selector: 'blockly-add-variable-modal', + template: ` +
+ +
+
+

New Variable Name: + +

+
+ + +
+
+
+ `, + pipes: [blocklyApp.TranslatePipe] +}) +.Class({ + constructor: [ + blocklyApp.AudioService, blocklyApp.KeyboardInputService, blocklyApp.VariableModalService, + function(audioService, keyboardService, variableService) { + this.workspace = blocklyApp.workspace; + this.variableModalService = variableService; + this.audioService = audioService; + this.keyboardInputService = keyboardService + this.modalIsVisible = false; + this.activeButtonIndex = -1; + + var that = this; + this.variableModalService.registerPreAddShowHook( + function() { + that.modalIsVisible = true; + + that.keyboardInputService.setOverride({ + // Tab key: navigates to the previous or next item in the list. + '9': function(evt) { + evt.preventDefault(); + evt.stopPropagation(); + + if (evt.shiftKey) { + // Move to the previous item in the list. + if (that.activeButtonIndex <= 0) { + that.activeActionButtonIndex = 0; + that.audioService.playOopsSound(); + } else { + that.activeButtonIndex--; + } + } else { + // Move to the next item in the list. + if (that.activeButtonIndex == that.numInteractiveElements() - 1) { + that.audioService.playOopsSound(); + } else { + that.activeButtonIndex++; + } + } + + that.focusOnOption(that.activeButtonIndex); + }, + // Escape key: closes the modal. + '27': function() { + that.dismissModal(); + }, + // Up key: no-op. + '38': function(evt) { + evt.preventDefault(); + }, + // Down key: no-op. + '40': function(evt) { + evt.preventDefault(); + } + }); + + setTimeout(function() { + document.getElementById('mainFieldId').focus(); + }, 150); + } + ); + } + ], + // Caches the current text variable as the user types. + setTextValue: function(newValue) { + this.variableName = newValue; + }, + // Closes the modal (on both success and failure). + hideModal_: function() { + this.modalIsVisible = false; + this.keyboardInputService.clearOverride(); + }, + // Focuses on the button represented by the given index. + focusOnOption: function(index) { + var elements = this.getInteractiveElements(); + var button = elements[index]; + button.focus(); + }, + // Counts the number of interactive elements for the modal. + numInteractiveElements: function() { + var elements = this.getInteractiveElements(); + return elements.length; + }, + // Gets all the interactive elements for the modal. + getInteractiveElements: function() { + return Array.prototype.filter.call( + document.getElementById("varForm").elements, function(element) { + if (element.type === 'hidden') { + return false; + } + if (element.disabled) { + return false; + } + if (element.tabIndex < 0) { + return false; + } + return true; + }); + }, + // Submits the name change for the variable. + submit: function() { + this.workspace.createVariable(this.variableName); + this.hideModal_(); + }, + // Dismisses and closes the modal. + dismissModal: function() { + this.hideModal_(); + } +}) diff --git a/accessible/variable-modal.service.js b/accessible/variable-modal.service.js index 812deb96d..720afde7f 100644 --- a/accessible/variable-modal.service.js +++ b/accessible/variable-modal.service.js @@ -29,12 +29,19 @@ blocklyApp.VariableModalService = ng.core.Class({ this.modalIsShown = false; } ], - // Registers a hook to be called before the modal is shown. + // Registers a hook to be called before the add modal is shown. + registerPreAddShowHook: function(preShowHook) { + this.preAddShowHook = function() { + preShowHook(); + }; + }, + // Registers a hook to be called before the rename modal is shown. registerPreRenameShowHook: function(preShowHook) { this.preRenameShowHook = function(oldName) { preShowHook(oldName); }; }, + // Registers a hook to be called before the remove modal is shown. registerPreRemoveShowHook: function(preShowHook) { this.preRemoveShowHook = function(oldName, count) { preShowHook(oldName, count); @@ -44,12 +51,17 @@ blocklyApp.VariableModalService = ng.core.Class({ isModalShown: function() { return this.modalIsShown; }, - // Show the variable modal. + // Show the add variable modal. + showAddModal_: function() { + this.preAddShowHook(); + this.modalIsShown = true; + }, + // Show the rename variable modal. showRenameModal_: function(oldName) { this.preRenameShowHook(oldName); this.modalIsShown = true; }, - // Show the variable modal. + // Show the remove variable modal. showRemoveModal_: function(oldName) { var count = blocklyApp.workspace.getVariableUses(oldName).length; if (count > 1) { diff --git a/demos/accessible/index.html b/demos/accessible/index.html index 5a60b82a4..2a187360e 100644 --- a/demos/accessible/index.html +++ b/demos/accessible/index.html @@ -32,6 +32,7 @@ + @@ -351,6 +352,7 @@ + From 077547ec90f7907eb5ce7723529ce5aba845bb2c Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Tue, 4 Apr 2017 14:36:01 -0700 Subject: [PATCH 008/217] Block browser context menu in the toolbox and flyout --- core/inject.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/inject.js b/core/inject.js index 54509db71..f685a715c 100644 --- a/core/inject.js +++ b/core/inject.js @@ -280,7 +280,7 @@ Blockly.init_ = function(mainWorkspace) { var svg = mainWorkspace.getParentSvg(); // Suppress the browser's context menu. - Blockly.bindEventWithChecks_(svg, 'contextmenu', null, + Blockly.bindEventWithChecks_(svg.parentNode, 'contextmenu', null, function(e) { if (!Blockly.utils.isTargetInput(e)) { e.preventDefault(); From eea01e3e066ca424a124613dfe6f2d3152537ad2 Mon Sep 17 00:00:00 2001 From: RoboErikG Date: Tue, 4 Apr 2017 16:40:40 -0700 Subject: [PATCH 009/217] Add links to the dev registration form and contributor guidelines --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 474dbf8ac..48590f9f7 100644 --- a/README.md +++ b/README.md @@ -8,3 +8,9 @@ blocks together to build programs. All code is free and open source. ![](https://developers.google.com/blockly/images/sample.png) Blockly has an active [developer forum](https://groups.google.com/forum/#!forum/blockly). Please drop by and say hello. Show us your prototypes early; collectively we have a lot of experience and can offer hints which will save you time. + +Help us focus our development efforts by telling us [what you are doing with +Blockly](https://goo.gl/forms/kZTsO9wGLmpoPXC02). The questionnaire only takes +a few minutes and will help us better support the Blockly community. + +Want to contribute? Great! First, read [our guidelines for contributors](https://developers.google.com/blockly/guides/modify/contributing). From f2f522d77ad87d4dace9c3c91eaa0a2199eb676e Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Wed, 5 Apr 2017 15:52:49 -0700 Subject: [PATCH 010/217] Miscellaneous comment cleanup --- core/block.js | 8 +++++--- core/block_drag_surface.js | 8 ++++---- core/block_svg.js | 22 ++++++++++++++-------- core/rendered_connection.js | 36 +++++++++++++++++++++++------------- core/touch.js | 19 +++++++++++++++---- 5 files changed, 61 insertions(+), 32 deletions(-) diff --git a/core/block.js b/core/block.js index c42322e1b..81280a6af 100644 --- a/core/block.js +++ b/core/block.js @@ -119,6 +119,8 @@ Blockly.Block = function(workspace, prototypeName, opt_id) { this.comment = null; /** + * The block's position in workspace units. (0, 0) is at the workspace's + * origin; scale does not change this value. * @type {!goog.math.Coordinate} * @private */ @@ -1445,7 +1447,7 @@ Blockly.Block.prototype.setMutator = function(/* mutator */) { /** * Return the coordinates of the top-left corner of this block relative to the - * drawing surface's origin (0,0). + * drawing surface's origin (0,0), in workspace units. * @return {!goog.math.Coordinate} Object with .x and .y properties. */ Blockly.Block.prototype.getRelativeToSurfaceXY = function() { @@ -1454,8 +1456,8 @@ Blockly.Block.prototype.getRelativeToSurfaceXY = function() { /** * Move a block by a relative offset. - * @param {number} dx Horizontal offset. - * @param {number} dy Vertical offset. + * @param {number} dx Horizontal offset, in workspace units. + * @param {number} dy Vertical offset, in workspace units. */ Blockly.Block.prototype.moveBy = function(dx, dy) { goog.asserts.assert(!this.parentBlock_, 'Block has parent.'); diff --git a/core/block_drag_surface.js b/core/block_drag_surface.js index 942dfa3b9..2c37ed6d7 100644 --- a/core/block_drag_surface.js +++ b/core/block_drag_surface.js @@ -112,10 +112,10 @@ Blockly.BlockDragSurfaceSvg.prototype.setBlocksAndShow = function(blocks) { }; /** - * Translate and scale the entire drag surface group to keep in sync with the - * workspace. - * @param {number} x X translation - * @param {number} y Y translation + * Translate and scale the entire drag surface group to the given position, to + * keep in sync with the workspace. + * @param {number} x X translation in workspace coordinates. + * @param {number} y Y translation in workspace coordinates. * @param {number} scale Scale of the group. */ Blockly.BlockDragSurfaceSvg.prototype.translateAndScaleGroup = function(x, y, scale) { diff --git a/core/block_svg.js b/core/block_svg.js index d8edb1097..418804083 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -99,10 +99,12 @@ goog.inherits(Blockly.BlockSvg, Blockly.Block); /** * Height of this block, not including any statement blocks above or below. + * Height is in workspace units. */ Blockly.BlockSvg.prototype.height = 0; /** * Width of this block, including any connected value blocks. + * Width is in workspace units. */ Blockly.BlockSvg.prototype.width = 0; @@ -324,8 +326,10 @@ Blockly.BlockSvg.prototype.setParent = function(newParent) { /** * Return the coordinates of the top-left corner of this block relative to the - * drawing surface's origin (0,0). - * @return {!goog.math.Coordinate} Object with .x and .y properties. + * drawing surface's origin (0,0), in workspace units. + * This does not change with workspace scale. + * @return {!goog.math.Coordinate} Object with .x and .y properties in + * workspace coordinates. */ Blockly.BlockSvg.prototype.getRelativeToSurfaceXY = function() { var x = 0; @@ -358,8 +362,8 @@ Blockly.BlockSvg.prototype.getRelativeToSurfaceXY = function() { /** * Move a block by a relative offset. - * @param {number} dx Horizontal offset. - * @param {number} dy Vertical offset. + * @param {number} dx Horizontal offset in workspace units. + * @param {number} dy Vertical offset in workspace units. */ Blockly.BlockSvg.prototype.moveBy = function(dx, dy) { goog.asserts.assert(!this.parentBlock_, 'Block has parent.'); @@ -375,8 +379,8 @@ Blockly.BlockSvg.prototype.moveBy = function(dx, dy) { /** * Transforms a block by setting the translation on the transform attribute * of the block's SVG. - * @param {number} x The x coordinate of the translation. - * @param {number} y The y coordinate of the translation. + * @param {number} x The x coordinate of the translation in workspace units. + * @param {number} y The y coordinate of the translation in workspace units. */ Blockly.BlockSvg.prototype.translate = function(x, y) { this.getSvgRoot().setAttribute('transform', @@ -879,8 +883,10 @@ Blockly.BlockSvg.prototype.showContextMenu_ = function(e) { /** * Move the connections for this block and all blocks attached under it. * Also update any attached bubbles. - * @param {number} dx Horizontal offset from current location. - * @param {number} dy Vertical offset from current location. + * @param {number} dx Horizontal offset from current location, in workspace + * units. + * @param {number} dy Vertical offset from current location, in workspace + * units. * @private */ Blockly.BlockSvg.prototype.moveConnections_ = function(dx, dy) { diff --git a/core/rendered_connection.js b/core/rendered_connection.js index 6425dcdfc..47de4a67d 100644 --- a/core/rendered_connection.js +++ b/core/rendered_connection.js @@ -38,15 +38,22 @@ goog.require('Blockly.Connection'); */ Blockly.RenderedConnection = function(source, type) { Blockly.RenderedConnection.superClass_.constructor.call(this, source, type); + + /** + * Workspace units, (0, 0) is top left of block. + * @type {!goog.math.Coordinate} + * @private + */ this.offsetInBlock_ = new goog.math.Coordinate(0, 0); }; goog.inherits(Blockly.RenderedConnection, Blockly.Connection); /** - * Returns the distance between this connection and another connection. + * Returns the distance between this connection and another connection in + * workspace units. * @param {!Blockly.Connection} otherConnection The other connection to measure * the distance to. - * @return {number} The distance between connections. + * @return {number} The distance between connections, in workspace units. */ Blockly.RenderedConnection.prototype.distanceFrom = function(otherConnection) { var xDiff = this.x_ - otherConnection.x_; @@ -102,8 +109,8 @@ Blockly.RenderedConnection.prototype.bumpAwayFrom_ = function(staticConnection) /** * Change the connection's coordinates. - * @param {number} x New absolute x coordinate. - * @param {number} y New absolute y coordinate. + * @param {number} x New absolute x coordinate, in workspace coordinates. + * @param {number} y New absolute y coordinate, in workspace coordinates. */ Blockly.RenderedConnection.prototype.moveTo = function(x, y) { // Remove it from its old location in the database (if already present) @@ -120,8 +127,8 @@ Blockly.RenderedConnection.prototype.moveTo = function(x, y) { /** * Change the connection's coordinates. - * @param {number} dx Change to x coordinate. - * @param {number} dy Change to y coordinate. + * @param {number} dx Change to x coordinate, in workspace units. + * @param {number} dy Change to y coordinate, in workspace units. */ Blockly.RenderedConnection.prototype.moveBy = function(dx, dy) { this.moveTo(this.x_ + dx, this.y_ + dy); @@ -129,9 +136,9 @@ Blockly.RenderedConnection.prototype.moveBy = function(dx, dy) { /** * Move this connection to the location given by its offset within the block and - * the coordinate of the block's top left corner. - * @param {!goog.math.Coordinate} blockTL The coordinate of the top left corner - * of the block. + * the location of the block's top left corner. + * @param {!goog.math.Coordinate} blockTL The location of the top left corner + * of the block, in workspace coordinates. */ Blockly.RenderedConnection.prototype.moveToOffset = function(blockTL) { this.moveTo(blockTL.x + this.offsetInBlock_.x, @@ -140,8 +147,8 @@ Blockly.RenderedConnection.prototype.moveToOffset = function(blockTL) { /** * Set the offset of this connection relative to the top left of its block. - * @param {number} x The new relative x. - * @param {number} y The new relative y. + * @param {number} x The new relative x, in workspace units. + * @param {number} y The new relative y, in workspace units. */ Blockly.RenderedConnection.prototype.setOffsetInBlock = function(x, y) { this.offsetInBlock_.x = x; @@ -170,6 +177,7 @@ Blockly.RenderedConnection.prototype.tighten_ = function() { /** * Find the closest compatible connection to this connection. + * All parameters are in workspace units * @param {number} maxLimit The maximum radius to another connection. * @param {number} dx Horizontal offset between this connection's location * in the database and the current location (as a result of dragging). @@ -294,7 +302,8 @@ Blockly.RenderedConnection.prototype.hideAll = function() { /** * Check if the two connections can be dragged to connect to each other. * @param {!Blockly.Connection} candidate A nearby connection to check. - * @param {number} maxRadius The maximum radius allowed for connections. + * @param {number} maxRadius The maximum radius allowed for connections, in + * workspace units. * @return {boolean} True if the connection is allowed, false otherwise. */ Blockly.RenderedConnection.prototype.isConnectionAllowed = function(candidate, @@ -353,7 +362,8 @@ Blockly.RenderedConnection.prototype.respawnShadow_ = function() { /** * Find all nearby compatible connections to this connection. * Type checking does not apply, since this function is used for bumping. - * @param {number} maxLimit The maximum radius to another connection. + * @param {number} maxLimit The maximum radius to another connection, in + * workspace units. * @return {!Array.} List of connections. * @private */ diff --git a/core/touch.js b/core/touch.js index b73615148..566bd3665 100644 --- a/core/touch.js +++ b/core/touch.js @@ -189,6 +189,20 @@ Blockly.Touch.shouldHandleEvent = function(e) { Blockly.Touch.checkTouchIdentifier(e); }; +/** + * Get the touch identifier from the given event. If it was a mouse event, the + * identifier is the string 'mouse'. + * @param {!Event} e Mouse event or touch event. + * @return {string} The touch identifier from the first changed touch, if + * defined. Otherwise 'mouse'. + */ +Blockly.Touch.getTouchIdentifierFromEvent = function(e) { + return (e.changedTouches && e.changedTouches[0] && + e.changedTouches[0].identifier != undefined && + e.changedTouches[0].identifier != null) ? + e.changedTouches[0].identifier : 'mouse'; +}; + /** * Check whether the touch identifier on the event matches the current saved * identifier. If there is no identifier, that means it's a mouse event and @@ -202,10 +216,7 @@ Blockly.Touch.shouldHandleEvent = function(e) { * saved identifier. */ Blockly.Touch.checkTouchIdentifier = function(e) { - var identifier = (e.changedTouches && e.changedTouches[0] && - e.changedTouches[0].identifier != undefined && - e.changedTouches[0].identifier != null) ? - e.changedTouches[0].identifier : 'mouse'; + var identifier = Blockly.Touch.getTouchIdentifierFromEvent(e); // if (Blockly.touchIdentifier_ )is insufficient because android touch // identifiers may be zero. From 33355415df80d2b344bebfbdfa285a351fcc2adc Mon Sep 17 00:00:00 2001 From: CoryDCode Date: Wed, 5 Apr 2017 16:06:45 -0700 Subject: [PATCH 011/217] Adding the common modal class. (#1017) Centralizes accessible modal behavior. --- accessible/app.component.js | 4 +- accessible/block-options-modal.component.js | 65 ++++------------ accessible/commonModal.js | 74 ++++++++++++++++++ accessible/keyboard-input.service.js | 3 + accessible/toolbox-modal.component.js | 63 +++------------ accessible/variable-add-modal.component.js | 73 ++---------------- accessible/variable-remove-modal.component.js | 77 ++----------------- accessible/variable-rename-modal.component.js | 73 ++---------------- demos/accessible/index.html | 1 + 9 files changed, 130 insertions(+), 303 deletions(-) create mode 100644 accessible/commonModal.js diff --git a/accessible/app.component.js b/accessible/app.component.js index 216520498..117e818a6 100644 --- a/accessible/app.component.js +++ b/accessible/app.component.js @@ -36,11 +36,11 @@ blocklyApp.AppComponent = ng.core.Component({ {{getAriaLiveReadout()}} - - + +