mirror of
https://github.com/redmine/redmine.git
synced 2025-11-18 03:00:52 +01:00
Add keyboard shortcuts for bold, italic and underline buttons (#34549).
Patch by Marius BALTEANU. git-svn-id: http://svn.redmine.org/redmine/trunk@20729 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
@@ -24,6 +24,10 @@ module Redmine
|
||||
(/(:?mswin|mingw)/.match?(RUBY_PLATFORM)) ||
|
||||
(RUBY_PLATFORM == 'java' && /windows/i.match?(ENV['OS'] || ENV['os']))
|
||||
end
|
||||
|
||||
def osx?
|
||||
(/(:?darwin)/.match?(RUBY_PLATFORM))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
/* Modified by JP LANG for textile formatting */
|
||||
let lastJstPreviewed = null;
|
||||
const isMac = Boolean(navigator.platform.toLowerCase().match(/mac/));
|
||||
|
||||
function jsToolBar(textarea) {
|
||||
if (!document.createElement) { return; }
|
||||
@@ -208,6 +209,7 @@ jsToolBar.prototype = {
|
||||
mode: 'wiki',
|
||||
elements: {},
|
||||
help_link: '',
|
||||
shortcuts: {},
|
||||
|
||||
getMode: function() {
|
||||
return this.mode;
|
||||
@@ -233,10 +235,27 @@ jsToolBar.prototype = {
|
||||
button: function(toolName) {
|
||||
var tool = this.elements[toolName];
|
||||
if (typeof tool.fn[this.mode] != 'function') return null;
|
||||
var b = new jsButton(tool.title, tool.fn[this.mode], this, 'jstb_'+toolName);
|
||||
|
||||
const className = 'jstb_' + toolName;
|
||||
let title = tool.title
|
||||
|
||||
if (tool.hasOwnProperty('shortcut')) {
|
||||
this.shortcuts[tool.shortcut] = className;
|
||||
title = this.buttonTitleWithShortcut(tool.title, tool.shortcut)
|
||||
}
|
||||
|
||||
var b = new jsButton(title, tool.fn[this.mode], this, className);
|
||||
if (tool.icon != undefined) b.icon = tool.icon;
|
||||
|
||||
return b;
|
||||
},
|
||||
buttonTitleWithShortcut: function(title, shortcutKey) {
|
||||
if (isMac) {
|
||||
return title + " (⌘" + shortcutKey.toUpperCase() + ")";
|
||||
} else {
|
||||
return title + " (Ctrl+" + shortcutKey.toUpperCase() + ")";
|
||||
}
|
||||
},
|
||||
space: function(toolName) {
|
||||
var tool = new jsSpace(toolName)
|
||||
if (this.elements[toolName].width !== undefined)
|
||||
@@ -409,7 +428,7 @@ jsToolBar.prototype = {
|
||||
this.toolbar.classList.add('hidden');
|
||||
this.textarea.classList.add('hidden');
|
||||
this.preview.classList.remove('hidden');
|
||||
this.tabsBlock.getElementsByClassName('tab-edit')[0].classList.remove('selected');
|
||||
this.tabsBlock.querySelector('.tab-edit').classList.remove('selected');
|
||||
event.target.classList.add('selected');
|
||||
},
|
||||
hidePreview: function(event) {
|
||||
@@ -418,18 +437,26 @@ jsToolBar.prototype = {
|
||||
this.textarea.classList.remove('hidden');
|
||||
this.textarea.focus();
|
||||
this.preview.classList.add('hidden');
|
||||
this.tabsBlock.getElementsByClassName('tab-preview')[0].classList.remove('selected');
|
||||
this.tabsBlock.querySelector('.tab-preview').classList.remove('selected');
|
||||
event.target.classList.add('selected');
|
||||
},
|
||||
keyboardShortcuts: function(e) {
|
||||
let stop = false;
|
||||
if (isToogleEditPreviewShortcut(e)) {
|
||||
// Switch to preview only if tab edit is selected when the event triggered.
|
||||
// Switch to preview only if Edit tab is selected when the event triggers.
|
||||
if (this.tabsBlock.querySelector('.tab-edit.selected')) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
this.tabsBlock.getElementsByClassName('tab-preview')[0].click();
|
||||
stop = true
|
||||
this.tabsBlock.querySelector('.tab-preview').click();
|
||||
}
|
||||
}
|
||||
if (isModifierKey(e) && this.shortcuts.hasOwnProperty(e.key.toLowerCase())) {
|
||||
stop = true
|
||||
this.toolbar.querySelector("." + this.shortcuts[e.key.toLowerCase()]).click();
|
||||
}
|
||||
if (stop) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
},
|
||||
stripBaseURL: function(url) {
|
||||
if (this.base_url != '') {
|
||||
@@ -539,4 +566,13 @@ function isToogleEditPreviewShortcut(e) {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
function isModifierKey(e) {
|
||||
if (isMac && e.metaKey) {
|
||||
return true;
|
||||
} else if (!isMac && e.ctrlKey) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@
|
||||
jsToolBar.prototype.elements.strong = {
|
||||
type: 'button',
|
||||
title: 'Strong',
|
||||
shortcut: 'b',
|
||||
fn: {
|
||||
wiki: function() { this.singleTag('**') }
|
||||
}
|
||||
@@ -35,6 +36,7 @@ jsToolBar.prototype.elements.strong = {
|
||||
jsToolBar.prototype.elements.em = {
|
||||
type: 'button',
|
||||
title: 'Italic',
|
||||
shortcut: 'i',
|
||||
fn: {
|
||||
wiki: function() { this.singleTag("*") }
|
||||
}
|
||||
@@ -44,6 +46,7 @@ jsToolBar.prototype.elements.em = {
|
||||
jsToolBar.prototype.elements.ins = {
|
||||
type: 'button',
|
||||
title: 'Underline',
|
||||
shortcut: 'u',
|
||||
fn: {
|
||||
wiki: function() { this.singleTag('_') }
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
jsToolBar.prototype.elements.strong = {
|
||||
type: 'button',
|
||||
title: 'Strong',
|
||||
shortcut: 'b',
|
||||
fn: {
|
||||
wiki: function() { this.singleTag('*') }
|
||||
}
|
||||
@@ -35,6 +36,7 @@ jsToolBar.prototype.elements.strong = {
|
||||
jsToolBar.prototype.elements.em = {
|
||||
type: 'button',
|
||||
title: 'Italic',
|
||||
shortcut: 'i',
|
||||
fn: {
|
||||
wiki: function() { this.singleTag("_") }
|
||||
}
|
||||
@@ -44,6 +46,7 @@ jsToolBar.prototype.elements.em = {
|
||||
jsToolBar.prototype.elements.ins = {
|
||||
type: 'button',
|
||||
title: 'Underline',
|
||||
shortcut: 'u',
|
||||
fn: {
|
||||
wiki: function() { this.singleTag('+') }
|
||||
}
|
||||
|
||||
@@ -68,4 +68,66 @@ class InlineAutocompleteSystemTest < ApplicationSystemTestCase
|
||||
find 'textarea#issue_notes', :visible => true
|
||||
find 'div#preview_issue_notes', :visible => false
|
||||
end
|
||||
|
||||
def test_keyboard_shortcuts_for_wiki_toolbar_buttons_using_textile
|
||||
with_settings :text_formatting => 'textile' do
|
||||
log_user('jsmith', 'jsmith')
|
||||
visit 'issues/new'
|
||||
|
||||
find('#issue_description').click.send_keys([modifier_key, 'b'])
|
||||
assert_equal '**', find('#issue_description').value
|
||||
|
||||
# Clear textarea value
|
||||
fill_in 'Description', :with => ''
|
||||
find('#issue_description').send_keys([modifier_key, 'u'])
|
||||
assert_equal '++', find('#issue_description').value
|
||||
|
||||
# Clear textarea value
|
||||
fill_in 'Description', :with => ''
|
||||
find('#issue_description').send_keys([modifier_key, 'i'])
|
||||
assert_equal '__', find('#issue_description').value
|
||||
end
|
||||
end
|
||||
|
||||
def test_keyboard_shortcuts_for_wiki_toolbar_buttons_using_markdown
|
||||
with_settings :text_formatting => 'markdown' do
|
||||
log_user('jsmith', 'jsmith')
|
||||
visit 'issues/new'
|
||||
|
||||
find('#issue_description').click.send_keys([modifier_key, 'b'])
|
||||
assert_equal '****', find('#issue_description').value
|
||||
|
||||
# Clear textarea value
|
||||
fill_in 'Description', :with => ''
|
||||
find('#issue_description').send_keys([modifier_key, 'u'])
|
||||
assert_equal '__', find('#issue_description').value
|
||||
|
||||
# Clear textarea value
|
||||
fill_in 'Description', :with => ''
|
||||
find('#issue_description').send_keys([modifier_key, 'i'])
|
||||
assert_equal '**', find('#issue_description').value
|
||||
end
|
||||
end
|
||||
|
||||
def test_keyboard_shortcuts_keys_should_be_shown_in_button_title
|
||||
log_user('jsmith', 'jsmith')
|
||||
visit 'issues/new'
|
||||
|
||||
within('.jstBlock .jstElements') do
|
||||
assert_equal "Strong (#{modifier_key_title}B)", find('button.jstb_strong')['title']
|
||||
assert_equal "Italic (#{modifier_key_title}I)", find('button.jstb_em')['title']
|
||||
assert_equal "Underline (#{modifier_key_title}U)", find('button.jstb_ins')['title']
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def modifier_key
|
||||
modifier = osx? ? "command" : "control"
|
||||
modifier.to_sym
|
||||
end
|
||||
|
||||
def modifier_key_title
|
||||
osx? ? "⌘" : "Ctrl+"
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user