<commit_before>/* © Utrecht University and DialogueTrainer */

(function()
{
    "use strict";

    $(document).ready(function()
    {
        var isIEClipboard = window.clipboardData && window.clipboardData.getData;

        var handleClipboardEvent = function(e, clipboard, action)
        {
            var handlers =
            {
                copy: copy,
                cut: cut,
                paste: paste
            };

            var clipboardFormat = isIEClipboard ? clipboardFormat = 'Text' : 'text/plain';

            if (Main.isEditingInCanvas() && handlers[action](clipboard, clipboardFormat))
            {
                e.preventDefault();
            }
        };

        var actionsByKey = { C: 'copy', X: 'cut', V: 'paste' };

        $(document).on('keydown', function(e)
        {
            if (isIEClipboard)
            {
                var key = String.fromCharCode(e.keyCode);
                if ((e.ctrlKey || e.metaKey) && key in actionsByKey)
                {
                    handleClipboardEvent(e, window.clipboardData, actionsByKey[key]);
                }
            }
        });

        Object.keys(actionsByKey).map(function(key)
        {
            var action = actionsByKey[key];
            $(document).on(action, function(e)
            {
                handleClipboardEvent(e, e.originalEvent.clipboardData, action);
            });

            // Show hint for the clipboard buttons
            $('#' + action).tooltip({ items: '#' + action, content: i18next.t('clipboard:hint', { key: key, action: action }) });
            $('#' + action).on('click', function()
            {
                $("#main").focus();
            });
        });
    });

    function copy(clipboard, format)
    {
        var dataAsText = JSON.stringify($.extend(copyElement(), { target: 'scenario', configIdRef: Config.container.id }));
        clipboard.setData(format, dataAsText);
        return true;
    }

    function cut(clipboard, format)
    {
        copy(clipboard, format);

        Main.deleteAllSelected();

        return true;
    }

    function paste(clipboard, format)
    {
        if (Main.isMousePositionWithinEditingCanvas())
        {
                var data;
                try
                {
                    data = JSON.parse(clipboard.getData(format));
                }
                catch(_)
                {
                    return false;
                }

                if (data && data.target === 'scenario' && data.configIdRef && data.type && data.definitions && data.content)
                {
                    if (data.configIdRef !== Config.container.id)
                    {
                        Utils.alertDialog("The config id of the pasted content does not match the config id referred to in the scenario", 'warning');
                    }
                    return considerPasting(data.type, data.definitions, data.content);
                }
        }

        return false;
    }

    function copyElement()
    {
        var definitions = { parameters: { userDefined: $.extend(true, {}, Parameters.container) } };
        if (Main.selectedElement !== null)
        {
            if (!Zoom.isZoomed())
            {
                return {
                    type: 'dialogue',
                    definitions: definitions,
                    content: copyTree(Main.selectedElement)
                };
            }
            else
            {
                return {
                    type: 'node',
                    definitions: definitions,
                    content: copyNode(Main.selectedElement)
                };
            }
        }
        else if (Main.selectedElements !== null)
        {
            if (!Zoom.isZoomed())
            {
                return {
                    type: 'dialogue',
                    definitions: definitions,
                    content: Main.selectedElements.map(function(treeID)
                    {
                        return copyTree(treeID);
                    })
                };
            }
            else
            {
                return {
                    type: 'node',
                    definitions: definitions,
                    content: Main.selectedElements.map(function(nodeID)
                    {
                        return copyNode(nodeID);
                    })
                };
            }
        }
    }

    function copyTree(treeId)
    {
        var tree = Main.trees[treeId];
        //Save tree data
        var toCopy = Utils.clone(
        {
            subject: tree.subject,
            level: tree.level,
            optional: tree.optional,
            leftPos: tree.leftPos,
            leftScroll: tree.leftScroll,
            topPos: tree.topPos,
            topScroll: tree.topScroll
        });
        var nodes = [];
        //Save all node data in tree
        $.each(Main.trees[treeId].nodes, function(index, nodeId)
        {
            nodes.push(copyNode(nodeId));
        });
        toCopy.nodes = nodes;

        return toCopy;
    }

    function copyNode(nodeID)
    {
        var toCopy = Utils.clone(Main.nodes[nodeID]);

        var plumbInstance = Main.getPlumbInstanceByNodeID(nodeID);
        toCopy.connections = plumbInstance.getConnections({ target: nodeID }).map(function(connection)
        {
            return {
                sourceId: connection.sourceId,
                targetId: connection.targetId,
                color: connection.getParameter('color')
            };
        });

        toCopy.position = Utils.cssPosition($('#' + nodeID));

        return toCopy;
    }

    function pasteElement(type, content)
    {
        var indicatorPos = Main.getGridIndicatorPosition();
        if (!Array.isArray(content))
        {
            if (type === 'dialogue' && !Zoom.isZoomed())
            {
                var newTree = pasteTree(content, indicatorPos.left, indicatorPos.top);
                Main.selectElement(newTree.id);
            }
            else if (type === 'node' && Zoom.isZoomed())
            {
                var newNode = pasteNode(content, { left: 0, top: 0 });
                Main.selectElement(newNode.id);
            }
        }
        else
        {
            if (type === 'dialogue' && !Zoom.isZoomed())
            {
                // In grid positions
                var minX = Number.MAX_VALUE;
                var minY = Number.MAX_VALUE;

                $.each(content, function(index, tree)
                {
                    if (tree.leftPos < minX) minX = tree.leftPos;
                    if (tree.topPos < minY) minY = tree.topPos;
                });

                // Paste trees relative to top left of smallest bounding box
                var pastedTreeIds = $.map(content, function(tree, index)
                {
                    var leftPos = tree.leftPos - minX + indicatorPos.left;
                    var topPos = tree.topPos - minY + indicatorPos.top;
                    return pasteTree(tree, leftPos, topPos).id;
                });

                Main.selectElements(pastedTreeIds);
            }
            else if (type === 'node' && Zoom.isZoomed())
            {
                //Needed to save jsPlumb connections
                var idMappings = {};
                var plumbInstance = Zoom.getZoomed().plumbInstance;
                plumbInstance.batch(function()
                {
                    $.each(content, function(index, node)
                    {
                        var offset = { left: node.position.left - content[0].position.left, top: node.position.top - content[0].position.top };
                        newNode = pasteNode(node, offset);
                        idMappings[node.id] = newNode.id;
                    });

                    // Paste jsPlumb connections
                    $.each(content, function(index, node)
                    {
                        if (!node) //due to deleting from arrays in js leaving values undefined
                            return true;

                        var connections = node.connections;

                        $.each(connections, function(index, connection)
                        {
                            var target = idMappings[connection.targetId]; //map original target to copied target
                            if (!target)
                                return true;
                            var source = idMappings[connection.sourceId]; //map original source to copied source
                            if (!source)
                                return true;
                            var newConnection = plumbInstance.connect(
                            {
                                "source": source,
                                "target": target
                            });

                            if (connection.color)
                            {
                                newConnection.setParameter('color', connection.color);
                            }
                        });
                    });

                    if (ColorPicker.areColorsEnabled())
                    {
                        ColorPicker.applyColors();
                    }
                });

                // select all nodes just copied
                Main.selectElements($.map(idMappings, function (newId) { return newId; }));
            }
        }
    }

    function pasteNode(copiedNode, offset, tree, doNotPosition)
    {
        if (!tree) tree = Zoom.getZoomed();
        if (!tree) return;

        var node = Utils.clone(copiedNode); //no dom action just yet. this just copies the object in the nodes object
        var nodeElem = Main.createAndReturnNode(node.type, null, tree.div, tree.id); //to do dom manipulations and create the id

        node.id = nodeElem.attr('id');
        node.parent = tree.id;
        delete node.position;
        delete node.connections;

        Main.nodes[node.id] = node;

        if (!doNotPosition)
        {
            var position = Main.mousePositionToDialoguePosition(Main.mousePosition);
            Utils.cssPosition(nodeElem, { left: Math.max(position.left + offset.left, 0), top: Math.max(position.top + offset.top, 0) });
        }

        Main.changeNodeText(node.id);

        return node;
    }

    function pasteTree(toCopy, leftPos, topPos)
    {
        var idMappings = {};

        var newTree = Main.createEmptyTree(null, leftPos, topPos);

        newTree.subject = i18next.t('clipboard:copy_of', { postProcess: 'sprintf', sprintf: [toCopy.subject]});
        newTree.optional = toCopy.optional;

        newTree.leftScroll = toCopy.leftScroll;
        newTree.topScroll = toCopy.topScroll;

        var treeDiv = $("#" + newTree.id);
        treeDiv.find(".subjectName").text(newTree.subject);
        treeDiv.find(".subjectNameInput").val(newTree.subject);

        newTree.plumbInstance.batch(function()
        {
            $.each(toCopy.nodes, function(index, node)
            {
                if (!node) //due to deleting from arrays in js leaving values undefined
                    return true; //$.each version of continue

                var newNode = pasteNode(node, { left: 0, top: 0 }, newTree, true);

                idMappings[node.id] = newNode.id; //needed to also copy over jsplumb connectors.

                Utils.cssPosition($("#" + newNode.id), node.position);
            });

            //all nodes have been created. now copy connectors
            $.each(toCopy.nodes, function(index, node)
            {
                if (!node) //due to deleting from arrays in js leaving values undefined
                    return true;

                var connections = node.connections;

                $.each(connections, function(index, connection)
                {
                    var target = idMappings[connection.targetId]; //map original target to copied target
                    var source = idMappings[connection.sourceId]; //map original source to copied source
                    var newConnection = newTree.plumbInstance.connect(
                    {
                        "source": source,
                        "target": target
                    });

                    if (connection.color)
                    {
                        newConnection.setParameter('color', connection.color);
                    }
                });
            });
        });

        return newTree;
    }

    // Pastes the content if confirmed and returns true if the type, content and context are correct
    function considerPasting(type, definitions, content)
    {
        // Returns the parameter IDs that are missing
        var processNode = function(node)
        {
            // Before performing any operations we need to update the references in the byId object
            // to the sequenced objects in the node's datastructures
            var parameterId;
            var fixedParameterEffects = node.parameterEffects.fixed;
            for (parameterId in fixedParameterEffects.characterIndependent.byId)
            {
                fixedParameterEffects.characterIndependent.byId[parameterId] = [];
            }
            fixedParameterEffects.characterIndependent.sequence.forEach(function(effect)
            {
                fixedParameterEffects.characterIndependent.byId[effect.idRef].push(effect);
            });
            for (var characterId in fixedParameterEffects.perCharacter)
            {
                for (parameterId in fixedParameterEffects.perCharacter[characterId].byId)
                {
                    fixedParameterEffects.perCharacter[characterId].byId[parameterId] = [];
                }

                fixedParameterEffects.perCharacter[characterId].sequence.forEach(function(effect)
                {
                    fixedParameterEffects.perCharacter[characterId].byId[effect.idRef].push(effect);
                });
            }

            var getEqualParameter = function(parameter)
            {
                var equalParameters = Parameters.container.sequence.filter(function(existingParameter)
                {
                    return existingParameter.name === parameter.name && existingParameter.type.equals(parameter.type);
                });
                return equalParameters.length > 0 ? equalParameters[0] : null;
            };

            var missingParameterIds = {};
            node.parameterEffects.userDefined = node.parameterEffects.userDefined.filter(function(parameterEffect)
            {
                var equalParameter = getEqualParameter(definitions.parameters.userDefined.byId[parameterEffect.idRef]);
                if (equalParameter)
                {
                    parameterEffect.idRef = equalParameter.id;
                }
                else
                {
                    missingParameterIds[parameterEffect.idRef] = true;
                }
                return equalParameter;
            });

            if (node.preconditions)
            {
                var onConditionPreservation = function(condition, equalParameter)
                {
                    condition.idRef = equalParameter.id;
                };
                var onConditionRemoval = function(condition)
                {
                    missingParameterIds[condition.idRef] = true;
                };
                node.preconditions = Condition.filter(function(condition)
                {
                    return getEqualParameter(definitions.parameters.userDefined.byId[condition.idRef]);
                }, node.preconditions, onConditionPreservation, onConditionRemoval);
            }

            return missingParameterIds;
        };

        var canPaste = false;
        var missingParameterIds = {};
        if (!Array.isArray(content))
        {
            if (type === 'dialogue' && !Zoom.isZoomed())
            {
                missingParameterIds = content.nodes.reduce(function(parameterIds, node)
                {
                    return $.extend(parameterIds, processNode(node));
                }, {});
                canPaste = true;
            }
            else if (type === 'node' && Zoom.isZoomed())
            {
                missingParameterIds = processNode(content);
                canPaste = true;
            }
        }
        else
        {
            if (type === 'dialogue' && !Zoom.isZoomed())
            {
                missingParameterIds = content.reduce(function(parameterIds, dialogue)
                {
                    return $.extend(parameterIds, dialogue.nodes.reduce(function(parameterIds, node)
                    {
                        return $.extend(parameterIds, processNode(node));
                    }, {}));
                }, {});
                canPaste = true;
            }
            else if (type === 'node' && Zoom.isZoomed())
            {
                missingParameterIds = content.reduce(function(parameterIds, node)
                {
                    return $.extend(parameterIds, processNode(node));
                }, {});
                canPaste = true;
            }
        }

        if (canPaste)
        {
            if (Object.keys(missingParameterIds).length > 0)
            {
                var warning = $('<div>');
                warning.append($('<div>', { text: i18next.t('clipboard:referrer_warning') }));
                warning.append($('<ul>').append(Object.keys(missingParameterIds).map(function(parameterId)
                {
                    return $('<li>', { text: definitions.parameters.userDefined.byId[parameterId].name });
                })));
                Utils.confirmDialog(warning, 'warning')
                .then(function(confirmed)
                {
                    if (confirmed) pasteElement(type, content);
                });
            }
            else
            {
                pasteElement(type, content);
            }
        }

        return canPaste;
    }

}());
<commit_msg>Prevented cutting and copying when text is selected<commit_after>/* © Utrecht University and DialogueTrainer */

(function()
{
    "use strict";

    $(document).ready(function()
    {
        var isIEClipboard = window.clipboardData && window.clipboardData.getData;

        var handleClipboardEvent = function(e, clipboard, action)
        {
            var handlers =
            {
                copy: copy,
                cut: cut,
                paste: paste
            };

            var clipboardFormat = isIEClipboard ? clipboardFormat = 'Text' : 'text/plain';

            if (Main.isEditingInCanvas() && handlers[action](clipboard, clipboardFormat))
            {
                e.preventDefault();
            }
        };

        var actionsByKey = { C: 'copy', X: 'cut', V: 'paste' };

        $(document).on('keydown', function(e)
        {
            if (isIEClipboard)
            {
                var key = String.fromCharCode(e.keyCode);
                if ((e.ctrlKey || e.metaKey) && key in actionsByKey)
                {
                    handleClipboardEvent(e, window.clipboardData, actionsByKey[key]);
                }
            }
        });

        Object.keys(actionsByKey).map(function(key)
        {
            var action = actionsByKey[key];
            $(document).on(action, function(e)
            {
                handleClipboardEvent(e, e.originalEvent.clipboardData, action);
            });

            // Show hint for the clipboard buttons
            $('#' + action).tooltip({ items: '#' + action, content: i18next.t('clipboard:hint', { key: key, action: action }) });
            $('#' + action).on('click', function()
            {
                $("#main").focus();
            });
        });
    });

    function copy(clipboard, format)
    {
        var hasSelectedText = window.getSelection().type !== 'Range';
        if (hasSelectedText)
        {
            var dataAsText = JSON.stringify($.extend(copyElement(), { target: 'scenario', configIdRef: Config.container.id }));
            clipboard.setData(format, dataAsText);
        }
        return hasSelectedText;
    }

    function cut(clipboard, format)
    {
        var hasCopied = copy(clipboard, format);
        if (hasCopied)
        {
            Main.deleteAllSelected();
        }
        return hasCopied;
    }

    function paste(clipboard, format)
    {
        if (Main.isMousePositionWithinEditingCanvas())
        {
                var data;
                try
                {
                    data = JSON.parse(clipboard.getData(format));
                }
                catch(_)
                {
                    return false;
                }

                if (data && data.target === 'scenario' && data.configIdRef && data.type && data.definitions && data.content)
                {
                    if (data.configIdRef !== Config.container.id)
                    {
                        Utils.alertDialog("The config id of the pasted content does not match the config id referred to in the scenario", 'warning');
                    }
                    return considerPasting(data.type, data.definitions, data.content);
                }
        }

        return false;
    }

    function copyElement()
    {
        var definitions = { parameters: { userDefined: $.extend(true, {}, Parameters.container) } };
        if (Main.selectedElement !== null)
        {
            if (!Zoom.isZoomed())
            {
                return {
                    type: 'dialogue',
                    definitions: definitions,
                    content: copyTree(Main.selectedElement)
                };
            }
            else
            {
                return {
                    type: 'node',
                    definitions: definitions,
                    content: copyNode(Main.selectedElement)
                };
            }
        }
        else if (Main.selectedElements !== null)
        {
            if (!Zoom.isZoomed())
            {
                return {
                    type: 'dialogue',
                    definitions: definitions,
                    content: Main.selectedElements.map(function(treeID)
                    {
                        return copyTree(treeID);
                    })
                };
            }
            else
            {
                return {
                    type: 'node',
                    definitions: definitions,
                    content: Main.selectedElements.map(function(nodeID)
                    {
                        return copyNode(nodeID);
                    })
                };
            }
        }
    }

    function copyTree(treeId)
    {
        var tree = Main.trees[treeId];
        //Save tree data
        var toCopy = Utils.clone(
        {
            subject: tree.subject,
            level: tree.level,
            optional: tree.optional,
            leftPos: tree.leftPos,
            leftScroll: tree.leftScroll,
            topPos: tree.topPos,
            topScroll: tree.topScroll
        });
        var nodes = [];
        //Save all node data in tree
        $.each(Main.trees[treeId].nodes, function(index, nodeId)
        {
            nodes.push(copyNode(nodeId));
        });
        toCopy.nodes = nodes;

        return toCopy;
    }

    function copyNode(nodeID)
    {
        var toCopy = Utils.clone(Main.nodes[nodeID]);

        var plumbInstance = Main.getPlumbInstanceByNodeID(nodeID);
        toCopy.connections = plumbInstance.getConnections({ target: nodeID }).map(function(connection)
        {
            return {
                sourceId: connection.sourceId,
                targetId: connection.targetId,
                color: connection.getParameter('color')
            };
        });

        toCopy.position = Utils.cssPosition($('#' + nodeID));

        return toCopy;
    }

    function pasteElement(type, content)
    {
        var indicatorPos = Main.getGridIndicatorPosition();
        if (!Array.isArray(content))
        {
            if (type === 'dialogue' && !Zoom.isZoomed())
            {
                var newTree = pasteTree(content, indicatorPos.left, indicatorPos.top);
                Main.selectElement(newTree.id);
            }
            else if (type === 'node' && Zoom.isZoomed())
            {
                var newNode = pasteNode(content, { left: 0, top: 0 });
                Main.selectElement(newNode.id);
            }
        }
        else
        {
            if (type === 'dialogue' && !Zoom.isZoomed())
            {
                // In grid positions
                var minX = Number.MAX_VALUE;
                var minY = Number.MAX_VALUE;

                $.each(content, function(index, tree)
                {
                    if (tree.leftPos < minX) minX = tree.leftPos;
                    if (tree.topPos < minY) minY = tree.topPos;
                });

                // Paste trees relative to top left of smallest bounding box
                var pastedTreeIds = $.map(content, function(tree, index)
                {
                    var leftPos = tree.leftPos - minX + indicatorPos.left;
                    var topPos = tree.topPos - minY + indicatorPos.top;
                    return pasteTree(tree, leftPos, topPos).id;
                });

                Main.selectElements(pastedTreeIds);
            }
            else if (type === 'node' && Zoom.isZoomed())
            {
                //Needed to save jsPlumb connections
                var idMappings = {};
                var plumbInstance = Zoom.getZoomed().plumbInstance;
                plumbInstance.batch(function()
                {
                    $.each(content, function(index, node)
                    {
                        var offset = { left: node.position.left - content[0].position.left, top: node.position.top - content[0].position.top };
                        newNode = pasteNode(node, offset);
                        idMappings[node.id] = newNode.id;
                    });

                    // Paste jsPlumb connections
                    $.each(content, function(index, node)
                    {
                        if (!node) //due to deleting from arrays in js leaving values undefined
                            return true;

                        var connections = node.connections;

                        $.each(connections, function(index, connection)
                        {
                            var target = idMappings[connection.targetId]; //map original target to copied target
                            if (!target)
                                return true;
                            var source = idMappings[connection.sourceId]; //map original source to copied source
                            if (!source)
                                return true;
                            var newConnection = plumbInstance.connect(
                            {
                                "source": source,
                                "target": target
                            });

                            if (connection.color)
                            {
                                newConnection.setParameter('color', connection.color);
                            }
                        });
                    });

                    if (ColorPicker.areColorsEnabled())
                    {
                        ColorPicker.applyColors();
                    }
                });

                // select all nodes just copied
                Main.selectElements($.map(idMappings, function (newId) { return newId; }));
            }
        }
    }

    function pasteNode(copiedNode, offset, tree, doNotPosition)
    {
        if (!tree) tree = Zoom.getZoomed();
        if (!tree) return;

        var node = Utils.clone(copiedNode); //no dom action just yet. this just copies the object in the nodes object
        var nodeElem = Main.createAndReturnNode(node.type, null, tree.div, tree.id); //to do dom manipulations and create the id

        node.id = nodeElem.attr('id');
        node.parent = tree.id;
        delete node.position;
        delete node.connections;

        Main.nodes[node.id] = node;

        if (!doNotPosition)
        {
            var position = Main.mousePositionToDialoguePosition(Main.mousePosition);
            Utils.cssPosition(nodeElem, { left: Math.max(position.left + offset.left, 0), top: Math.max(position.top + offset.top, 0) });
        }

        Main.changeNodeText(node.id);

        return node;
    }

    function pasteTree(toCopy, leftPos, topPos)
    {
        var idMappings = {};

        var newTree = Main.createEmptyTree(null, leftPos, topPos);

        newTree.subject = i18next.t('clipboard:copy_of', { postProcess: 'sprintf', sprintf: [toCopy.subject]});
        newTree.optional = toCopy.optional;

        newTree.leftScroll = toCopy.leftScroll;
        newTree.topScroll = toCopy.topScroll;

        var treeDiv = $("#" + newTree.id);
        treeDiv.find(".subjectName").text(newTree.subject);
        treeDiv.find(".subjectNameInput").val(newTree.subject);

        newTree.plumbInstance.batch(function()
        {
            $.each(toCopy.nodes, function(index, node)
            {
                if (!node) //due to deleting from arrays in js leaving values undefined
                    return true; //$.each version of continue

                var newNode = pasteNode(node, { left: 0, top: 0 }, newTree, true);

                idMappings[node.id] = newNode.id; //needed to also copy over jsplumb connectors.

                Utils.cssPosition($("#" + newNode.id), node.position);
            });

            //all nodes have been created. now copy connectors
            $.each(toCopy.nodes, function(index, node)
            {
                if (!node) //due to deleting from arrays in js leaving values undefined
                    return true;

                var connections = node.connections;

                $.each(connections, function(index, connection)
                {
                    var target = idMappings[connection.targetId]; //map original target to copied target
                    var source = idMappings[connection.sourceId]; //map original source to copied source
                    var newConnection = newTree.plumbInstance.connect(
                    {
                        "source": source,
                        "target": target
                    });

                    if (connection.color)
                    {
                        newConnection.setParameter('color', connection.color);
                    }
                });
            });
        });

        return newTree;
    }

    // Pastes the content if confirmed and returns true if the type, content and context are correct
    function considerPasting(type, definitions, content)
    {
        // Returns the parameter IDs that are missing
        var processNode = function(node)
        {
            // Before performing any operations we need to update the references in the byId object
            // to the sequenced objects in the node's datastructures
            var parameterId;
            var fixedParameterEffects = node.parameterEffects.fixed;
            for (parameterId in fixedParameterEffects.characterIndependent.byId)
            {
                fixedParameterEffects.characterIndependent.byId[parameterId] = [];
            }
            fixedParameterEffects.characterIndependent.sequence.forEach(function(effect)
            {
                fixedParameterEffects.characterIndependent.byId[effect.idRef].push(effect);
            });
            for (var characterId in fixedParameterEffects.perCharacter)
            {
                for (parameterId in fixedParameterEffects.perCharacter[characterId].byId)
                {
                    fixedParameterEffects.perCharacter[characterId].byId[parameterId] = [];
                }

                fixedParameterEffects.perCharacter[characterId].sequence.forEach(function(effect)
                {
                    fixedParameterEffects.perCharacter[characterId].byId[effect.idRef].push(effect);
                });
            }

            var getEqualParameter = function(parameter)
            {
                var equalParameters = Parameters.container.sequence.filter(function(existingParameter)
                {
                    return existingParameter.name === parameter.name && existingParameter.type.equals(parameter.type);
                });
                return equalParameters.length > 0 ? equalParameters[0] : null;
            };

            var missingParameterIds = {};
            node.parameterEffects.userDefined = node.parameterEffects.userDefined.filter(function(parameterEffect)
            {
                var equalParameter = getEqualParameter(definitions.parameters.userDefined.byId[parameterEffect.idRef]);
                if (equalParameter)
                {
                    parameterEffect.idRef = equalParameter.id;
                }
                else
                {
                    missingParameterIds[parameterEffect.idRef] = true;
                }
                return equalParameter;
            });

            if (node.preconditions)
            {
                var onConditionPreservation = function(condition, equalParameter)
                {
                    condition.idRef = equalParameter.id;
                };
                var onConditionRemoval = function(condition)
                {
                    missingParameterIds[condition.idRef] = true;
                };
                node.preconditions = Condition.filter(function(condition)
                {
                    return getEqualParameter(definitions.parameters.userDefined.byId[condition.idRef]);
                }, node.preconditions, onConditionPreservation, onConditionRemoval);
            }

            return missingParameterIds;
        };

        var canPaste = false;
        var missingParameterIds = {};
        if (!Array.isArray(content))
        {
            if (type === 'dialogue' && !Zoom.isZoomed())
            {
                missingParameterIds = content.nodes.reduce(function(parameterIds, node)
                {
                    return $.extend(parameterIds, processNode(node));
                }, {});
                canPaste = true;
            }
            else if (type === 'node' && Zoom.isZoomed())
            {
                missingParameterIds = processNode(content);
                canPaste = true;
            }
        }
        else
        {
            if (type === 'dialogue' && !Zoom.isZoomed())
            {
                missingParameterIds = content.reduce(function(parameterIds, dialogue)
                {
                    return $.extend(parameterIds, dialogue.nodes.reduce(function(parameterIds, node)
                    {
                        return $.extend(parameterIds, processNode(node));
                    }, {}));
                }, {});
                canPaste = true;
            }
            else if (type === 'node' && Zoom.isZoomed())
            {
                missingParameterIds = content.reduce(function(parameterIds, node)
                {
                    return $.extend(parameterIds, processNode(node));
                }, {});
                canPaste = true;
            }
        }

        if (canPaste)
        {
            if (Object.keys(missingParameterIds).length > 0)
            {
                var warning = $('<div>');
                warning.append($('<div>', { text: i18next.t('clipboard:referrer_warning') }));
                warning.append($('<ul>').append(Object.keys(missingParameterIds).map(function(parameterId)
                {
                    return $('<li>', { text: definitions.parameters.userDefined.byId[parameterId].name });
                })));
                Utils.confirmDialog(warning, 'warning')
                .then(function(confirmed)
                {
                    if (confirmed) pasteElement(type, content);
                });
            }
            else
            {
                pasteElement(type, content);
            }
        }

        return canPaste;
    }

}());

{'fraction_non_alphanumeric': 0.09996707999561066, 'fraction_numerical': 0.0009327334576977943, 'mean_word_length': 1.3205169011394742, 'pattern_counts': {'":': 8, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5486921', 'n_tokens_mistral': 9027, 'n_tokens_neox': 8461, 'n_words': 1803}