google / blockly-samples

Plugins, codelabs, and examples related to the Blockly library.
http://github.com/google/blockly
Apache License 2.0
851 stars 625 forks source link

Plugin for cross-tab copy and paste #371

Closed maribethb closed 2 years ago

maribethb commented 4 years ago

Category

Plugin

Details

Create a plugin that allows cross-tab copy and paste (copy block xml to the browser paste buffer, and on paste read the xml and create the block). This is a good candidate for a plugin because the copy/paste APIs are not fully compatible with IE so it may not work well in core blockly.

rachel-fenichel commented 4 years ago

I tried to implement this and ran into problems with browser clipboard APIs not being fully usable/implemented yet. However, there's a fallback option that would be a good first project for a contributor.

Taikono-Himazin commented 4 years ago

Hello! I think this plugin is very useful and a feature that many people want. I wonder why it has never existed before. I am very interested in this feature request.

Is the code for this plugin published somewhere? Or is it still under development or proposal? Beta version is fine, so I'd like to see the code if it's available. Can you do it?

alschmiedt commented 4 years ago

This is still in development and we hope to have something this quarter. We will post here when it is ready for use.

juliaanduchateau commented 3 years ago

Hi, Not sure if this is what you are looking for, but I have implemented something like this by adding an extra option to the context menu and storing the blocks in the browser's local storage. If on the other tab the key is present in the local storage, an option to paste is available in the context menu.


Blockly.ContextMenuItems.blockCopyToStorage = function() {
  /** @type {!Blockly.ContextMenuRegistry.RegistryItem} */
  var copyToStorageOption = {
    displayText: function() {
      return 'Copy to stash';
    },
    preconditionFn: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
      return 'enabled';
    },
    callback: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
      blockDom = Blockly.Xml.blockToDomWithXY(scope.block);
      blockText = Blockly.Xml.domToText(blockDom);
      localStorage.setItem('blocklyStash', blockText);
    },
    scopeType: Blockly.ContextMenuRegistry.ScopeType.BLOCK,
    id: 'blockCopyToStorage',
    weight: 0,
  };
  Blockly.ContextMenuRegistry.registry.register(copyToStorageOption);
};
Blockly.ContextMenuItems.blockPasteFromStorage = function() {
  /** @type {!Blockly.ContextMenuRegistry.RegistryItem} */
  var pasteFromStorageOption = {
    displayText: function() {
      return 'Paste from stash';
    },
    preconditionFn: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
      if (localStorage.getItem('blocklyStash')){
        return 'enabled';
      } else {
        return 'disabled';
      }

    },
    callback: function(/** @type {!Blockly.ContextMenuRegistry.Scope} */ scope) {
      blockText = localStorage.getItem('blocklyStash');
      blockDom = Blockly.Xml.textToDom(blockText);
      Blockly.Xml.domToBlock(blockDom, workspace);
    },
    scopeType: Blockly.ContextMenuRegistry.ScopeType.WORKSPACE,
    id: 'blockPasteFromStorage',
    weight: 0,
  };
  Blockly.ContextMenuRegistry.registry.register(pasteFromStorageOption);
};
// Register the menus
Blockly.ContextMenuItems.blockCopyToStorage();
Blockly.ContextMenuItems.blockPasteFromStorage();
Taikono-Himazin commented 2 years ago

I've looked carefully and it looks like there's no progress on this issue, but is there anything different? I strongly want this. If there is no progress for a long time, I am thinking of implementing it with this code. https://github.com/google/blockly-samples/issues/371#issuecomment-762264332

Taikono-Himazin commented 2 years ago

I wrote the code based on # 371. I thought about sending a pull request, but I didn't have a deep understanding of npm and couldn't do the same, so I stopped. The name is tentatively copyByStorage. I hope you find this code useful.

how to use Load this code after loading blockly in your browser. Blockly.copyByStorage.init(contextMenu, shortcut, unregisterDuplicate);

Argument description

Blockly.ShortcutItems.blockCopyToStorage = function () { /* @type {!ShortcutRegistry.KeyboardShortcut} / const copyShortcut = { name: 'copy', preconditionFn: function (workspace) { return !workspace.options.readOnly && !Blockly.Gesture.inProgress() && Blockly.selected && Blockly.selected.isDeletable() && Blockly.selected.isMovable(); }, callback: function (workspace, e) { // Prevent the default copy behavior, which may beep or otherwise indicate // an error due to the lack of a selection. e.preventDefault(); let blockDom = Blockly.Xml.blockToDomWithXY(Blockly.selected); Blockly.Xml.deleteNext(blockDom); let blockText = Blockly.Xml.domToText(blockDom); Blockly.copyByStorage.__Storage.setItem('blocklyStash', blockText); return true; }, }; Blockly.ShortcutRegistry.registry.register(copyShortcut);

const ctrlC = Blockly.ShortcutRegistry.registry.createSerializedKey(
    Blockly.utils.KeyCodes.C, [Blockly.utils.KeyCodes.CTRL]);
Blockly.ShortcutRegistry.registry.addKeyMapping(ctrlC, copyShortcut.name);

const altC =
    Blockly.ShortcutRegistry.registry.createSerializedKey(
        Blockly.utils.KeyCodes.C, [Blockly.utils.KeyCodes.ALT]);
Blockly.ShortcutRegistry.registry.addKeyMapping(altC, copyShortcut.name);

const metaC = Blockly.ShortcutRegistry.registry.createSerializedKey(
    Blockly.utils.KeyCodes.C, [Blockly.utils.KeyCodes.META]);
Blockly.ShortcutRegistry.registry.addKeyMapping(metaC, copyShortcut.name);

}; Blockly.ShortcutItems.blockCutToStorage = function () { /* @type {!ShortcutRegistry.KeyboardShortcut} / const cutShortcut = { name: 'cut', preconditionFn: function (workspace) { return !workspace.options.readOnly && !Blockly.Gesture.inProgress() && Blockly.selected && Blockly.selected.isDeletable() && Blockly.selected.isMovable() && !Blockly.selected.workspace.isFlyout; }, callback: function (workspace, e) { // Prevent the default copy behavior, which may beep or otherwise indicate // an error due to the lack of a selection. e.preventDefault(); let blockDom = Blockly.Xml.blockToDomWithXY(Blockly.selected); Blockly.Xml.deleteNext(blockDom); let blockText = Blockly.Xml.domToText(blockDom); Blockly.copyByStorage.__Storage.setItem('blocklyStash', blockText); Blockly.deleteBlock(Blockly.selected); return true; }, }; Blockly.ShortcutRegistry.registry.register(cutShortcut);

var ctrlX = Blockly.ShortcutRegistry.registry.createSerializedKey(
    Blockly.utils.KeyCodes.X, [Blockly.utils.KeyCodes.CTRL]);
Blockly.ShortcutRegistry.registry.addKeyMapping(ctrlX, cutShortcut.name);

var altX = Blockly.ShortcutRegistry.registry.createSerializedKey(
    Blockly.utils.KeyCodes.X, [Blockly.utils.KeyCodes.ALT]);
Blockly.ShortcutRegistry.registry.addKeyMapping(altX, cutShortcut.name);

var metaX = Blockly.ShortcutRegistry.registry.createSerializedKey(
    Blockly.utils.KeyCodes.X, [Blockly.utils.KeyCodes.META]);
Blockly.ShortcutRegistry.registry.addKeyMapping(metaX, cutShortcut.name);

}; Blockly.ShortcutItems.blockPasteFromStorage = function () { /* @type {!ShortcutRegistry.KeyboardShortcut} / const pasteShortcut = { name: 'paste', preconditionFn: function (workspace) { if (!Blockly.copyByStorage.Storage.getItem('blocklyStash')) { return 'disabled'; } return !workspace.options.readOnly && !Blockly.Gesture.inProgress(); }, callback: function (workspace, e) { // Prevent the default copy behavior, which may beep or otherwise indicate // an error due to the lack of a selection. e.preventDefault(); let blockText = Blockly.copyByStorage.Storage.getItem('blocklyStash'); let blockDom = Blockly.Xml.textToDom(blockText); Blockly.Xml.domToBlock(blockDom, workspace); return true; }, }; Blockly.ShortcutRegistry.registry.register(pasteShortcut);

const ctrlV = Blockly.ShortcutRegistry.registry.createSerializedKey(
    Blockly.utils.KeyCodes.V, [Blockly.utils.KeyCodes.CTRL]);
Blockly.ShortcutRegistry.registry.addKeyMapping(ctrlV, pasteShortcut.name);

const altV =
    Blockly.ShortcutRegistry.registry.createSerializedKey(Blockly.utils.KeyCodes.V, [Blockly.utils.KeyCodes.ALT]);
Blockly.ShortcutRegistry.registry.addKeyMapping(altV, pasteShortcut.name);

const metaV = Blockly.ShortcutRegistry.registry.createSerializedKey(
    Blockly.utils.KeyCodes.V, [Blockly.utils.KeyCodes.META]);
Blockly.ShortcutRegistry.registry.addKeyMapping(metaV, pasteShortcut.name);

};

/**

Taikono-Himazin commented 2 years ago

Isn't this closed because there is this? https://github.com/google/blockly-samples/tree/master/plugins/cross-tab-copy-paste

alschmiedt commented 2 years ago

Yup! Closed via #1037