Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(Feature request) Shortcut for copying and pasting formatting only #2954

Closed
asoftbird opened this issue Jun 30, 2022 · 11 comments
Closed

(Feature request) Shortcut for copying and pasting formatting only #2954

asoftbird opened this issue Jun 30, 2022 · 11 comments

Comments

@asoftbird
Copy link
Collaborator

Describe feature

I'm using text color a lot to highlight important things. Clicking a word, then clicking the tiny text color button & then the color does get tiresome after a while, especially since the buttons are so small.

I'd like to see a shortcut that copies and pastes only the formatting of a piece of text; e.g. I select and color a text red with gray background and italics, hit "copy formatting", then select another piece of text, hit "paste formatting", and all three formatting options are copied to the selected text.

As for shortcuts, a variation on Ctrl-C/V would be nice, but for C most modifier keys are already used iirc (leaving only ctrl-shift-alt-C free).

Additional Information

No response

@Birdacious
Copy link

Hello, perhaps this script is of interest to you. It is not exactly the format copy/pasting you're looking for, but creates shortcuts for text colors and headings.
To use, put this in a JS Frontend code note and add the attribute: #run=frontendStartup.

/* FUNCTIONS */
async function text_color_red() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontColor', {value:'hsl(0,75%,60%)'});
}
async function text_uncolor() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontColor' /*{value:null}*/);
}

async function text_set_heading_2() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('heading', {value:'heading2'} );
}
async function text_unheading() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('heading', {value:'paragraph'})
}

/* For some reason I can't get highlights to work
async function text_highlight_red() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('highlight', {value:'hsl(0,75%,60%)'}); }
*/

/* BIND SHORTCUTS */
api.bindGlobalShortcut('ctrl+1', text_color_red);
api.bindGlobalShortcut('ctrl+0', text_uncolor);

api.bindGlobalShortcut('ctrl+shift+1', text_set_heading_2);
api.bindGlobalShortcut('ctrl+shift+0', text_unheading);

/* can't get highlights to work
api.bindGlobalShortcut('ctrl+shift+6', text_highlight_red);
*/

Extend the script with any colors you want, but here are the default Trilium font colors if you want things to match:
Black: “hsl(0, 0%, 0%)”
Dim grey: “hsl(0, 0%, 30%)"
Grey: “hsl(0, 0%, 60%)”
Light grey: “hsl(0, 0%, 90%)”
White: “hsl(0, 0%, 100%)”
Red: “hsl(0, 75%, 60%)”
Orange: “hsl(30, 75%, 60%)”
Yellow: “hsl(60, 75%, 60%)”
Light green: “hsl(90, 75%, 60%)”
Green: “hsl(120, 75%, 60%)”
Aquamarine: “hsl(150, 75%, 60%)”
Turquoise: “hsl(180, 75%, 60%)”
Light blue: “hsl(210, 75%, 60%)”
Blue: “hsl(240, 75%, 60%)”
Purple “hsl(270, 75%, 60%)”

If there are other CKEditor commands you would like to bind shortcuts to, check out the subclasses of the "Command" class in the CKEditor docs. For example, I figured out how to change text color by looking at the page for the FontColorCommand.

@zadam
Copy link
Owner

zadam commented May 2, 2023

Corresponding CKEditor request: ckeditor/ckeditor5#1901

@mariostrd
Copy link

mariostrd commented Aug 10, 2023

Many thanks @Birdacious . This was really useful. Now I can improve my productivity x3 or more. I was playing around with some other configs. Sharing in case someone benefits or can improve or add new shortcuts! (I'm by no means a JS programmer) This app is truly awesome, thanks to the main developer and to everyone for the hard work!

Note: you can create the JS frontend note anywhere and it'll just work.

image

/*FORMATING FUNCTIONS*/

//Remove format
async function remove_format() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('removeFormat', {value:'null'});
}

//Font Color
async function text_uncolor() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontColor', {value:'null'});
}
async function text_color_yellow() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontColor', {value:'hsl(60, 75%, 60%)'});
}
async function text_color_green() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontColor', {value:'hsl(120, 75%, 60%)'});
}
async function text_color_turquoise() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontColor', {value:'hsl(180, 75%, 60%)'});
}
async function text_color_red() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontColor', {value:'hsl(0,75%,60%)'});
}
async function text_color_orange() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontColor', {value:'hsl(30, 75%, 60%)'});
}
async function text_color_light_green() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontColor', {value:'hsl(90, 75%, 60%)'});
}
async function text_color_aquamarine() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontColor', {value:'hsl(150, 75%, 60%)'});
}
async function text_color_light_blue() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontColor', {value:'hsl(210, 75%, 60%)'});
}
async function text_color_blue() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontColor', {value:'hsl(240, 75%, 60%)'});
}
async function text_color_purple() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontColor', {value:'hsl(270, 75%, 60%)'});
}

//Background color
async function text_unhighlight() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontBackgroundColor', {value:'null'}); 
}
async function text_highlight_yellow() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontBackgroundColor', {value:'hsl(60, 75%, 60%)'});
}
async function text_highlight_green() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontBackgroundColor', {value:'hsl(120, 75%, 60%)'});
}
async function text_highlight_turquoise() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontBackgroundColor', {value:'hsl(180, 75%, 60%)'});
}
async function text_highlight_red() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontBackgroundColor', {value:'hsl(0,75%,60%)'});
}
async function text_highlight_orange() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontBackgroundColor', {value:'hsl(30, 75%, 60%)'});
}
async function text_highlight_light_green() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontBackgroundColor', {value:'hsl(90, 75%, 60%)'});
}
async function text_highlight_aquamarine() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontBackgroundColor', {value:'hsl(150, 75%, 60%)'});
}
async function text_highlight_light_blue() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontBackgroundColor', {value:'hsl(210, 75%, 60%)'});
}
async function text_highlight_blue() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontBackgroundColor', {value:'hsl(240, 75%, 60%)'});
}
async function text_highlight_purple() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontBackgroundColor', {value:'hsl(270, 75%, 60%)'});
}

//Font headings
async function text_set_paragraph() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('heading', {value:'paragraph'})
}
async function text_set_heading_2() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('heading', {value:'heading2'} );
}
async function text_set_heading_3() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('heading', {value:'heading3'} );
}
async function text_set_heading_4() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('heading', {value:'heading4'} );
}
async function text_set_heading_5() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('heading', {value:'heading5'} );
}

//Font size
async function text_size_tiny() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontSize', { value: 'tiny'}); 
}
async function text_size_small() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontSize', { value: 'small'}); 
}
async function text_size_default() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontSize', { value: 'default'}); 
}
async function text_size_big() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontSize', { value: 'big'}); 
}
async function text_size_huge() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontSize', { value: 'huge'}); 
}

//Code format
async function code_format() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('code', {value:'null'});
}

//Not working, probably there are limited fontFamily fonts packed with Trilium Notes
async function font_family_courier() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontFamily', {value: 'Courier New'});
}

/* BIND SHORTCUTS */
api.bindGlobalShortcut('ctrl+alt+x', remove_format);

api.bindGlobalShortcut('ctrl+`', text_uncolor);
api.bindGlobalShortcut('ctrl+1', text_color_yellow);
api.bindGlobalShortcut('ctrl+2', text_color_green);
api.bindGlobalShortcut('ctrl+3', text_color_turquoise);
api.bindGlobalShortcut('ctrl+4', text_color_red);
api.bindGlobalShortcut('ctrl+5', text_color_orange);
api.bindGlobalShortcut('ctrl+6', text_color_light_green);
api.bindGlobalShortcut('ctrl+7', text_color_aquamarine);
api.bindGlobalShortcut('ctrl+8', text_color_light_blue);
api.bindGlobalShortcut('ctrl+9', text_color_blue);
api.bindGlobalShortcut('ctrl+0', text_color_purple);

api.bindGlobalShortcut('ctrl+shift+`', text_unhighlight);
api.bindGlobalShortcut('ctrl+shift+1', text_highlight_yellow);
api.bindGlobalShortcut('ctrl+shift+2', text_highlight_green);
api.bindGlobalShortcut('ctrl+shift+3', text_highlight_turquoise);
api.bindGlobalShortcut('ctrl+shift+4', text_highlight_red);
api.bindGlobalShortcut('ctrl+shift+5', text_highlight_orange);
api.bindGlobalShortcut('ctrl+shift+6', text_highlight_light_green);
api.bindGlobalShortcut('ctrl+shift+7', text_highlight_aquamarine);
api.bindGlobalShortcut('ctrl+shift+8', text_highlight_light_blue);
api.bindGlobalShortcut('ctrl+shift+9', text_highlight_blue);
api.bindGlobalShortcut('ctrl+shift+p', text_highlight_purple);

api.bindGlobalShortcut('ctrl+alt+shift+a', text_size_tiny);
api.bindGlobalShortcut('ctrl+alt+shift+s', text_size_small);
api.bindGlobalShortcut('ctrl+alt+shift+d', text_size_default);
api.bindGlobalShortcut('ctrl+alt+shift+f', text_size_big);
api.bindGlobalShortcut('ctrl+alt+shift+g', text_size_huge);

api.bindGlobalShortcut('ctrl+alt+shift+1', text_set_paragraph);
api.bindGlobalShortcut('ctrl+alt+shift+2', text_set_heading_2);
api.bindGlobalShortcut('ctrl+alt+shift+3', text_set_heading_3);
api.bindGlobalShortcut('ctrl+alt+shift+4', text_set_heading_4);
api.bindGlobalShortcut('ctrl+alt+shift+5', text_set_heading_5);

api.bindGlobalShortcut('ctrl+alt+shift+c', code_format);

//Not working
api.bindGlobalShortcut('ctrl+alt+shift+w', font_family_courier);

@Nriver
Copy link
Contributor

Nriver commented Aug 10, 2023

@mariostrd You are amazing! These shortcuts are life-saving! Added to https://github.com/Nriver/awesome-trilium#-scripts

@mrstrd
Copy link

mrstrd commented Aug 10, 2023

Thanks @Nriver, @Birdacious info was awesome. Hope we can improve shortcut support for Trilium notes.

Great compilation of Trilium goodies btw, didn't know it, thanks for that 👍 awesome-trilium

@zadam
Copy link
Owner

zadam commented Aug 10, 2023

@mariostrd thanks for this, I'd like to incorporate into Trilium, but I have some questions...

Is there some logic to the color order? What caught my eye is that green and light green are not next to each other.

I'm also thinking that "removeColor" / "removeHighlight" could be mapped by default to -0 (e.g. CTRL-0). I understand this is a similar idea with ` but that relies on keyboard having it next to 1, which isn't the case for e.g. MacBooks.

@zadam
Copy link
Owner

zadam commented Aug 10, 2023

More thinking about this - I wonder about inclusion of white/black to the shortcuts. The issue is that with the dark theme, highlighting gray text with some of the colors makes it quite unreadable, so the user would also have to make the text black. 

Alternatively, when user highlights text, should also force the text color to black (even in dark theme) to make it readable? That would disallow combinations like colored text + highlight (by forcing black text color).

@mariostrd
Copy link

mariostrd commented Aug 11, 2023

Hi @zadam, many thanks, that'll be awesome.

The color order is just a personal preference as I use the dark theme, so that text pops up easily. That's why I didn't mapped the colors for black, grey, etc. Nothing really well thought up.

I start coloring with yellow for important ideas. If I want to differentiate two ideas next to each other I use yellow and green, then turquoise.

If there is a warning/risk in the text I use red, or orange.

Roughly if an idea is more important than others , I assigning color as per:

Less important ----------> More important
...........................................................................................
yellow->green->turquoise->orange->red

Those are the main colors I use, for the others, I just mapped them with no logic at all, except
light_blue, blue, purple are hard to distinguish on dark theme, unless they are bold.

I think based on theme/color personal preferences, it would be great if the shortcuts are configurable.

"removeColor" / "removeHighlight" could be mapped by default to -0 (e.g. CTRL-0)

I agree, having only one shortcut for both can be more efficient.

Alternatively, when user highlights text, should also force the text color to black (even in dark theme) to make it readable? That would disallow combinations like colored text + highlight (by forcing black text color).

I thinks that's a good idea. I wasn't using highlighting much precisely because of this issue. Black font seems to make text pop up with almost all highlight colors. But I think the user should still be able to configure both color and highlighting based on their liking; but I reckon this could be a tricky thing to program.

@chncho
Copy link

chncho commented Jan 2, 2024

The function , text_uncolor like this, it set an null property to font-color, is there any other api to remove font-color property ?
@zadam @mariostrd @Birdacious

async function text_uncolor() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('fontColor', {value:'null'});
}

Here is the defects of a null font-color
#4546

@flyerfan017
Copy link

Just wanted to add to this as i was able to edit the above code to get the text color change and highlight to work by calling the functions that already existed. I was also able to create the style options. I just added the sections below that reflect those changes

//Text Styles
async function text_bold() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('bold', {value:'<strong>bold</strong>'});
} 

async function text_italic() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('italic', {value:'<i>italic</i>'});
} 

async function text_underline() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('underline', {value:'<u>underline</u>'});
} 

async function text_strikethrough() {
  let editor = await api.getActiveContextTextEditor();
  editor.execute('strikethrough', {value:'<s>strikethrough</s>'});
} 

//highlight and font color change
async function hl_blue_yellow() {
  let editor = await api.getActiveContextTextEditor(text_color_blue(), text_highlight_yellow());
}
async function hl_black_yellow() {
  let editor = await api.getActiveContextTextEditor(text_color_black(), text_highlight_yellow());
}
async function hl_black_orange() {
  let editor = await api.getActiveContextTextEditor(text_color_black(), text_highlight_orange());
}
async function hl_black_turquoise() {
  let editor = await api.getActiveContextTextEditor(text_color_black(), text_highlight_turquoise());
}
async function hl_turquoise_red() {
  let editor = await api.getActiveContextTextEditor(text_color_turquoise(), text_highlight_red());
}
async function hl_black_red_bold() {
  let editor = await api.getActiveContextTextEditor(text_color_black(), text_highlight_red(), text_bold());
}
async function hl_black_yellow_bold() {
  let editor = await api.getActiveContextTextEditor(text_color_black(), text_highlight_yellow(), text_bold());

}

//styles
api.bindGlobalShortcut('ctrl+b', text_bold);
api.bindGlobalShortcut('ctrl+u', text_underline);
api.bindGlobalShortcut('ctrl+i', text_italic);
api.bindGlobalShortcut('ctrl+s', text_strikethrough);

//highlight and textcolor
api.bindGlobalShortcut('ctrl+7', hl_blue_yellow);
api.bindGlobalShortcut('ctrl+8', hl_black_yellow);
api.bindGlobalShortcut('ctrl+9', hl_black_orange);
api.bindGlobalShortcut('ctrl+0', hl_black_turquoise);
api.bindGlobalShortcut('ctrl+shift+7', hl_turquoise_red);
api.bindGlobalShortcut('ctrl+shift+8', hl_black_red_bold);
api.bindGlobalShortcut('ctrl+shift+y', hl_black_yellow_bold);``

@meichthys
Copy link
Collaborator

Trilium has entered maintenance mode. Future enhancements will be addressed in TrilumNext: TriliumNext#100

@meichthys meichthys closed this as not planned Won't fix, can't repro, duplicate, stale May 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants