Make move block up or down multiple blocks or make it at least draggable

I don’t want to click the move block up or down multiple times when trying to move the block in a category up or down, it’s strenuous and repetitive. So basically there would be a drag feature to move blocks up or down in the categories.
[maybe make it work for custom blocks only]

Very poor demonstration below.

Credit to @dardoro
I have some version of his JS

BlockMorph.prototype._userMenu ?? = BlockMorph.prototype.userMenu;

function shiftArrItem(arr, item, shift) {
  let from = arr.indexOf(item);
  if (from < 0) return;
  let to = from + shift;
  to = to < 0 ? 0 : to;
  arr.splice(to, 0, arr.splice(from, 1)[0]);
}

function moveBlock(this_block, shift) {
  let rcvr = this_block.scriptTarget(),
    ide = this_block.parentThatIsA(IDE_Morph),
    def = this_block.isGlobal ? this_block.definition : rcvr.getMethod(self.blockSpec),
    blocks = this_block.isGlobal ? ide.stage.globalBlocks : rcvr.customBlocks;

  blocks.sort((a, b) => a.category.localeCompare(b.category)); //reorder acros categories
  shiftArrItem(blocks, def, shift);
  // * force refresh *
  ide.recordUnsavedChanges();
  ide.flushPaletteCache();
  ide.refreshPalette();
}

BlockMorph.prototype.userMenu = function() {
  let menu = this._userMenu(),
    shiftClicked = world.currentKey === 16;

  if (!(this.isCustomBlock && shiftClicked))
    return menu;

  menu.addItem(
    "move to top ^",
    () => moveBlock(this, Number.MIN_SAFE_INTEGER)
  );

  menu.addItem(
    "move to bottom _",
    () => moveBlock(this, Number.MAX_SAFE_INTEGER)
  );

  menu.addItem(
    "move up more",
    () => moveBlock(this, 5)
  );

  return menu;
}

You can replace the final number at the end of the code (right now its 5) with a negative number to change which direction the block moves when you shift-right click a block and select the move option

Next time, I would wrap the code in code blocks.

```js
CODE HERE
```

It is easier to copy from code blocks, and it doesn't trim down whitespace.

fixed the smart quotes and the trimmed whitespace that the forum did

BlockMorph.prototype._userMenu ?? = BlockMorph.prototype.userMenu;

function shiftArrItem(arr, item, shift) {
  let from = arr.indexOf(item);
  if (from < 0) return;
  let to = from + shift;
  to = to < 0 ? 0 : to;
  arr.splice(to, 0, arr.splice(from, 1)[0]);
}

function moveBlock(this_block, shift) {
  let rcvr = this_block.scriptTarget(),
    ide = this_block.parentThatIsA(IDE_Morph),
    def = this_block.isGlobal ? this_block.definition : rcvr.getMethod(self.blockSpec),
    blocks = this_block.isGlobal ? ide.stage.globalBlocks : rcvr.customBlocks;

  blocks.sort((a, b) => a.category.localeCompare(b.category)); //reorder acros categories
  shiftArrItem(blocks, def, shift);
  // * force refresh *
  ide.recordUnsavedChanges();
  ide.flushPaletteCache();
  ide.refreshPalette();
}

BlockMorph.prototype.userMenu = function() {
  let menu = this._userMenu(),
    shiftClicked = world.currentKey === 16;

  if (!(this.isCustomBlock && shiftClicked))
    return menu;

  menu.addItem(
    "move to top ^",
    () => moveBlock(this, Number.MIN_SAFE_INTEGER)
  );

  menu.addItem(
    "move to bottom _",
    () => moveBlock(this, Number.MAX_SAFE_INTEGER)
  );

  menu.addItem(
    "move up more",
    () => moveBlock(this, 5)
  );

  return menu;
}

Another good point! I could rant about how much automatic "smart" quotes suck...

I did that when I first posted and for whatever reason it wasn’t working. fixed now :)