Closed ssabrewolf closed 5 years ago
You can implement this very easily.
There are 2 commands that do this job. You can override them to work as you expect.
Take a look at the CopyComponent command. It copies the selected block to a property called clipboard
.
In your case instead of saving everything into a property you will need to save the components into the OS clipboard and them getting them back to paste properly
Hi thanks for the feedback, unfortunately that approach wont work, before posting i checked the core:copy implementation and its based on storing an object reference on the clipboard, of course this reference only exist on the current page, thats why trying to paste in other page doesnt work despite the clipboard having data, i posted this question in hope there is some kind of core method for serializing component into string along with its css attributes, i found this code to extract a component css but
it return a lot extra css from body and others(like 7000 chars) that could create a css collision with target page
editor.CodeManager.getCode(component, 'css', {cssc: editor.CssComposer});
Regards
Well, I know, at least, one workaround for this problem.
You can use the component toHTML
method to get the string representation that you need.
For the css, since I don't know a way to get only the css for that component, you could inline the css for your html and it will inline only for that element because you only have the html for that component.
I'm not sure if I was clear enough
Hi yes, actually i had implemented that way overriding the toHTML method and creating a targeted css directory applied on target page in element scope using the same recursive function with getClassRule method, but wanted to be sure there was not a better option provided by the core, cause depending in the original copied component nested level, the elements gets funky autosize behaviours when the wrapper on the target page varies, e.g when a cell is removed from a row
Regards
Is it possible implement a a copy paste between 2 different pages with the editor opened
Well, if for 2 different pages you mean 2 different tabs, I don't think so. Obviously, you're dealing with different editor instances so you have to find your way to make them talk with each other (eg. localStorage if you're on the same domain)
This is our implementation of using localStorage in case someone needs the solution.
function newCopy(selected) {
window.localStorage.setItem('grapesjs_clipboard', JSON.stringify(selected));
}
function newPaste(selected) {
var components = JSON.parse(window.localStorage.getItem('grapesjs_clipboard'));
if (components) {
if (selected && selected.attributes.type !== 'wrapper') {
var index = selected.index();
// Invert the order so last item gets added first and gets pushed down as others get added.
components.reverse();
var currentSelection = selected.collection;
components.forEach(comp => {
// TODO: Add check for validity of paste.
var added = currentSelection.add(comp, {at: index + 1});
editor.trigger('component:paste', added);
});
selected.emitUpdate();
} else {
// No components are selected so just insert at the end.
editor.addComponents(components);
}
}
}
const commands = editor.Commands;
commands.add('core:copy', editor => {
const selected = [...editor.getSelectedAll()];
//Filter out components that are not copyable.
var filteredSelected = selected.filter(item => item.attributes.copyable == true);
if (filteredSelected.length) {
newCopy(filteredSelected);
}
});
commands.add('core:paste', editor => {
const selected = editor.getSelected();
newPaste(selected);
});
Clipboard API would have been a great cross browser solution but it's not yet widely used.
updates? no css paste
@MarksEliel if that works to you i can share but it has a jQuery dependency not too hard to skip thats why i didnt share it , the solution is not 100% perfect so if you could enhance it and reshare to the community i can share it
@ssabrewolf @MarksEliel
I'm also very interested in a solution including the CSS. I am currently analyzing the example from @japo32 , trying to find my own solution for it.
I was able to implement @japo32 solution however still css is not being pasted, had some trial & erros but it's going no where. it would be great if anyone can provide any idea. @artf @ssabrewolf @MarksEliel @arthuralmeidap
Guys, I did it that way and it's working. https://prnt.sc/BATrbgkyj7aF
I didn't try it, I just read the code
You don't trigger the paste event when pasting in the body
Also the css is added in a style tag after each paste... There must be a better way to handle the styles, I'll take a look soon
I came up with this, a bit heavy handed. This would be so easy if I could find a way of converting a Backbone model to JSON and back, any ideas??
Extended @japo32's idea, It just grabs style from components and adds them back after they've been rendered:
`// COPY PASTE COMPONENTS/STYLE BETWEEN PAGES
const getStyles = (components) => {
// recurse down through components and store styles in temp attribute
components.forEach(component => {
const recurse = (comp) => {
// if component has any styling
if (Object.keys(comp.getStyle()).length !== 0) comp.attributes.savedStyle = comp.getStyle()
if (comp.get("components").length) {
comp.get("components").forEach(child => {
recurse(child)
})
}
}
recurse(component)
})
return components
}
const setStyles = (component) => {
// recurse down and re-apply style back to components
const recurse = (comp) => {
if ('savedStyle' in comp.attributes) {
comp.setStyle(comp.attributes.savedStyle)
delete comp.attributes.savedStyle
}
if (comp.attributes.components.length) {
comp.attributes.components.forEach(child => {
recurse(child)
})
}
}
recurse(component)
}
const newCopy = (selected) => {
window.localStorage.setItem('zcc-grapesjs-clipboard', JSON.stringify(selected));
}
const newPaste = (selected) => {
let components = JSON.parse(window.localStorage.getItem('zcc-grapesjs-clipboard'));
if (components) {
if (selected && selected.attributes.type !== 'wrapper') {
var index = selected.index();
// Invert the order so last item gets added first and gets pushed down as others get added.
components.reverse();
var currentSelection = selected.collection;
components.forEach(comp => {
if (currentSelection) {
var added = currentSelection.add(comp, { at: index + 1 });
editor.trigger('component:paste', added);
setStyles(added)
}
});
selected.emitUpdate();
} else {
components = editor.addComponents(components);
components.forEach(comp => {
setStyles(comp)
})
}
}
}
const commands = editor.Commands;
commands.add('core:copy', ed => {
const selected = getStyles([...ed.getSelectedAll()])
let filteredSelected = selected.filter(item => item.attributes.copyable == true);
if (filteredSelected.length) {
newCopy(filteredSelected);
}
});
commands.add('core:paste', ed => {
const selected = ed.getSelected();
newPaste(selected);
});`
Hello Grapesjs Team Ive seen the regular copy paste works as long as is made in the same page, Is it possible implement a a copy paste between 2 different pages with the editor opened
Thanks in advance