Creating new custom blocks with shadow values

189 views
Skip to first unread message

Craig Hawker

unread,
May 23, 2019, 10:03:53 AM5/23/19
to Blockly
Hi,

I have an existing Blockly proof of concept integration that I've set up (and it's working well), but I'm trying to improve the user experience a little.  I've created a number of custom blocks which are listed in the toolbox which all work well.  Each block's fields and values typically have shadow values to make it easier for the user to get up and running; they just drop it on the canvas and off they go rather than having to create new variables and the like.

However, I'd like to create a single top-level block when the workspace is rendered and the user will simply populate this block.  But I have some problems:

1. When I create my custom top-level block via code ("startBlock = workspace.newBlock(identifier)") it gets rendered onto the canvas without the shadow values.  I kinda understand why (these are functions of the toolbox registration, not the block definition), but is there any way to create a block as it would be generated by the toolbox, including these shadow values?

2. I have toyed with the idea of trying to stop the user creating any other top-level blocks (as they make zero sense in this scenario).  I could simply throw an exception when they try and save the definition, but are there any nicer ways?

3. I am having some browser issues which are entirely down to the environment in which this is running.  I've gotten around most of them by setting sounds to false and by explicitly setting the X-UA-Compatible flag to IE10 (don't ask me why - 9 fails and so does 11).  Unfortunately this is an embedded browser so the chances of it being updated are minimal, but are there any other good tips that people have found to improve compatibilty with downlevel browsers?

Regards,

Craig.

Beka Westberg

unread,
May 23, 2019, 10:24:05 AM5/23/19
to Blockly
Hello Craig,

1. Indeed there is! You just need to define your block in XML and then use the Blockly.Xml.domToWorkspace ( or .appendDomToWorkspace) function. There is some documentation about block paradigms which describes this function.

var topLevelBlock =
   
'<xml>' +
   
'  <block type="controls_if"></block>' +
   
'</xml>';
// Instead of using textToDom you can also define the xml as actual xml,
// and get a reference to it using document.getElementById
Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom(topLevelBlock), workspace);


2. I believe the usual way of preventing top-level blocks is to use the disableOrphans event listener. There is some documentation about block paradigms which describes this function.

workspace.addChangeListener(Blockly.Events.disableOrphans);

3. I don't have experience with this, so I don't think I have any relevant advice :/ I hope someone else here has more information for you!

If you have any further questions please reply!
Beka

Craig Hawker

unread,
May 23, 2019, 10:36:20 AM5/23/19
to Blockly
Hi Beka,

1. Indeed there is! You just need to define your block in XML and then use the Blockly.Xml.domToWorkspace ( or .appendDomToWorkspace) function. There is some documentation about block paradigms which describes this function.
 
Okay, I assume that I have to define the shadow values in the XML though (same as the toolbox)?  I have just tried it with the simple block type information and it renders as it did with workspace.newBlock (i.e. no shadow values).  That's not awful, as I can relatively easily get the XML that was put into the toolbox, but I hoped there was a way to get there without re-generating it.

2. I believe the usual way of preventing top-level blocks is to use the disableOrphans event listener. There is some documentation about block paradigms which describes this function.

That's perfect.  They can be dragged onto the canvas but are disabled.  I can handle that.

3. I don't have experience with this, so I don't think I have any relevant advice :/ I hope someone else here has more information for you!

I noticed another post about this and it looks like I've gotten further than most.  The last remaining oddity I'm facing is the application containing the embedded browser seemingly being thrown to the back of the window stack occasionally.  This seems to be related to the mousedown/click events when starting the drag of an element from the toolbox or interacting with the scrollbars.  I'm not 100% sure the issue isn't somewhere else, but if there's any suggestions around "simplifying" these events (e.g. turning off support for touch) that I could test then I'm happy to do so.

Thanks again!

Regards,

Craig.

Craig Hawker

unread,
May 23, 2019, 11:28:10 AM5/23/19
to Blockly
Good news -using the XML worked perfectly!  Thank you Beka!

In addition to that "disappearing down the window stack" issue (which is the main one), I often get this too:
Line: 1364
Error: Object doesn't support property or method 'blur'

As soon as this is thrown up I effectively have to kill the window and start again - it'll happen for almost every operation that I try.

Regards,

Craig.

Rachel Fenichel

unread,
May 23, 2019, 12:32:03 PM5/23/19
to Blockly
Turning off touch: that's controlled here.

Blur: try removing the filters here.

Out of curiosity, what browser are you on?  We should work in IE11; we never really worked on IE9 and ended IE10 support in the past year.

Rachel

Craig Hawker

unread,
May 24, 2019, 6:28:41 AM5/24/19
to Blockly
Hi Rachel,

Please be gentle, as I don't know the library very well. :)

I assume that "turning off touch" means setting the TOUCH_MAP object to an empty object ("Blockly.Touch.TOUCH_MAP = {};").  If so then, unfortunately, that hasn't made a difference.  I tried setting it both prior to Blockly.inject and afterwards.  Probably about 50% of the clicks on blocks cause this to happen.

I am unsure exactly how to turn off the blur using the section of code linked to, although I'm not 100% sure that this is the right bit.  The error message seems to indicate that it's trying to call ".blur()" method on something that doesn't support it.  Might it may be related to this (https://github.com/google/blockly/blob/9c4f9d6c1693c3c25160f008d3eaa2539127c9e8/core/workspace_svg.js#L1612), if document.activeElement doesn't point to something that defines a blur method?

The browser that's being used is actually an embedded browser, which is well known to be an awkward beast (https://weblog.west-wind.com/posts/2011/May/21/Web-Browser-Control-Specifying-the-IE-Version).  I'm displaying content within this window and have little control over the rest of the machine or application.  I'm using the X-UA-Compatible meta tag and, as I said, IE10 seems to be the only version that I can get to work.  IE11/edge looks like it'll work, but you can't actually drag any blocks - it's almost like read-only.

As I said: I do think this is quite an edge case, so I don't expect you to do any work to add support for this scenario.  But any guidance on bits I could disable that might help would be appreciated.

Regards,

Craig.

Rachel Fenichel

unread,
May 24, 2019, 6:04:09 PM5/24/19
to Blockly
I think you're right about the blur call.  This says blur works back to IE9, but this sounds like a special case.  Does deleting that bit of code help?

Touch changes: yes, I meant to set it to an empty object.  That should simplify it by making it so you only handle mouse events, and not touch or pointer events.  It sounds like that wasn't enough, though.

If setting the meta tag to edge didn't work, maybe try setting the touch map to an empty object and trying again.  There could be an interaction with touch/pointer events there.

If you're trying to simplify to figure out where problems are coming from, you can use the configuration struct to turn off parts of blockly (zoom, grid, etc).

Hope this helps,
Rachel

Craig Hawker

unread,
May 28, 2019, 4:27:12 AM5/28/19
to Blockly
Hi Rachel,

I was previously just grabbing the latest blockly release, but I've just set up my machine to be able to run the build from source so can try some changes in the code.

Good news: I have it working 100%.

Both issues were actually related to the same code.  I found this link (https://www.tjvantoll.com/2013/08/30/bugs-with-document-activeelement-in-internet-explorer/) which says that if document.activeElement points to the body in IE10 then calling .blur on it will switch windows, which is the exact behaviour I experienced.  In the end I altered workspace_svg.js in line with this:

if (document.activeElement) {
    try{
        // IE10 issue (and embedded browsers using IE10 rendering mode) will behave unexpectedly if document.activeElement points to <body>.
        if(typeof document.activeElement.blur == "function"
        && document.activeElement.nodeName.toLowerCase() !== "body"){
            document.activeElement.blur();
        }
    }
    catch(e){
    }
}

This seems to have resolved both issues I had remaining (the blur exception and the window switching).  I know that you said that IE10 support ended, but this seems to be a relatively non-destructive fix and it may well enable blockly usage in these scenarios where IE10 rendering is forced for some reason.

I hope that helps someone else too!

Regards,

Craig.

Rachel Fenichel

unread,
May 28, 2019, 2:15:12 PM5/28/19
to Blockly
Awesome!  I'm glad to hear you've got it working.

We're no longer adding code to handle IE10 (and, in fact, we're starting to remove IE10 workaround code), but anyone else searching for IE10 solutions should be able to find this forum thread.

Cheers,
Rachel

Craig Hawker

unread,
May 29, 2019, 11:16:38 AM5/29/19
to Blockly
Completely understandable.

Thanks for your (and Beka's) assistance in it all though!

Regards,

Craig.
Reply all
Reply to author
Forward
0 new messages