Skip to content
This repository has been archived by the owner on Mar 16, 2021. It is now read-only.

[Feature Request] Go to definition option when corner clicking a custom block #26

Closed
Explosion-Scratch opened this issue Sep 1, 2020 · 6 comments

Comments

@Explosion-Scratch
Copy link

Explosion-Scratch commented Sep 1, 2020

Hi there! So, when corner clicking a custom block in scratch 2.0 there was a 'go to definition' option which would center the view on the definition of the custom block, it looks like this in scratch 3.0 with a userscript of mine:
screenshot
(Also the colored context menus)
Here is the code from the userscript, maybe you could implement this in this addon?

// ==UserScript==
// @name Better Context Menus for Scratch 3
// @version 0.2
// @namespace https://github.com/forkphorus/cat-plus
// @match https://scratch.mit.edu/projects/*
// @run-at document-idle
// ==/UserScript==

'use strict';

window.addEventListener('load', function() {

  let workspace = Blockly.getMainWorkspace();
  let hooked = false;

  // Maps block opcodes to our custom context menu handler, if any.
  // Handlers are passed the menu options list and the Blockly SVG block
  // Handlers are expected to modify the options list in place in any way they choose (push, sort, pop, etc.)
  const menuLibrary = {
    // Add a way to rename variables from their reference
    data_variable: variableRenameFactory(3, 'variable'),

    // Add a way to rename lists from their reference
    data_listcontents: variableRenameFactory(3, 'list'),

    // This doesn't work. Seems to be an editor and scratch-vm desync.
    // event_broadcast: variableRenameFactory(3, 'broadcast'),

    // TODO: consider rename options on var sets, var changes, list gets, etc.

    // Add a way to jump to a block's definition on procedure call blocks
    procedures_call(options, block) {
      options.push({
        enabled: true,
        text: "Go To Definition",
        callback() {
          const procCode = block.procCode_;
          for (const block of workspace.getAllBlocks()) {
            if (block.type === 'procedures_prototype' && block.procCode_ === procCode) {
              const parent = block.parentBlock_;
              scrollToBlock(parent);
              break;
            }
          }
        },
      });
    },
  };

  function variableRenameFactory(insertIndex, type) {
    return function(options, block) {
      options.splice(insertIndex, 0, {
        enabled: true,
        text: `Rename ${type}`,
        callback() {
          const target = block.childBlocks_.length > 0 ? block.childBlocks_[0] : block;

          const inputList = target.inputList;
          const fieldRow = inputList[0].fieldRow;
          const variable = fieldRow[0].variable_;
          const variableId = variable.id_;
          const oldName = variable.name;

          // prompt() isn't perfect but works well enough for this use case
          const newName = prompt(`Rename '${oldName}' ${type} to:`, oldName);
          if (typeof newName !== 'string') {
            return;
          }
          workspace.renameVariableById(variableId, newName);
        },
      });
    };
  }

  function scrollToBlock(block) {
    const MARGIN = 20;
    const position = block.getRelativeToSurfaceXY();
    const metrics = workspace.getMetrics();
    const x = position.x * workspace.scale - metrics.contentLeft;
    const y = position.y * workspace.scale - metrics.contentTop;
    workspace.scrollbar.set(x - MARGIN, y - MARGIN);
  }

  function hook() {
    hooked = true;

    // We add our own change listener to react to all block creations
    workspace.addChangeListener(function(change) {
      if (change.type !== 'create') {
        return;
      }

      // change.ids is a list of blocks that have been created.
      for (const id of change.ids) {
        const block = workspace.getBlockById(id);
        if (!block) continue;
        const type = block.type;

        if (type in menuLibrary) {
          // customContextMenu will be called when a block's context menu is accessed.
          // It is passed a list it is expected to modify it in place.
          // Retain the original customContextMenu() (if any) to avoid breaking behavior.
          const nativeCustomContextMenu = block.customContextMenu;
          block.customContextMenu = function(options) {
            if (nativeCustomContextMenu) {
              nativeCustomContextMenu.call(this, options);
            }
            menuLibrary[type](options, this);
          }
        }
      }
    });
  }

  // If the workspace is already available, then we hook right away.
  if (workspace) {
    hook();
  } else {
    // Probably a project page outside of the editor.
    // Wait until the user sees inside before hooking since the editor object won't exist yet.
    document.body.addEventListener('click', function(e) {
      if (!hooked && e.target.closest('.see-inside-button')) {
        // The editor will be defined after Scratch's handler runs.
        setImmediate(function() {
          workspace = Blockly.getMainWorkspace();
          hook();
        });
      }
    });
  }

});
@Joeclinton1
Copy link

Joeclinton1 commented Sep 1, 2020

Why not just submit a pull request?

Also, you can already go to a custom blocks definition by clicking the middle button.

@Explosion-Scratch
Copy link
Author

@JOECLINTON I have no idea how to code js, I only know python. Also by 'the middle button' do you mean scroll wheel click? What about people who don't have a physical mouse?

@griffpatch
Copy link
Owner

griffpatch commented Sep 2, 2020 via email

@Explosion-Scratch
Copy link
Author

Explosion-Scratch commented Sep 2, 2020 via email

@Akash-Karthik
Copy link

why not close the issue

@scratchusernamemrtbts
Copy link

Hey there, yes - I already have a go to definition implemented, but it is currently accessible through the middle click... I will have to see if I can add it to the existing context menu too perhaps for compatibility.

I think you should add it because some people that doesn't have middle click like me can’t access that thing

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants