Browse Source

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
tags/4.2.0
Go MAEDA 3 years ago
parent
commit
082570094a

+ 4
- 0
lib/redmine/platform.rb View File

@@ -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

+ 43
- 7
public/javascripts/jstoolbar/jstoolbar.js View File

@@ -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;
}
}

+ 3
- 0
public/javascripts/jstoolbar/markdown.js View File

@@ -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('_') }
}

+ 3
- 0
public/javascripts/jstoolbar/textile.js View File

@@ -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('+') }
}

+ 62
- 0
test/system/keyboard_shortcuts_test.rb View File

@@ -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

Loading…
Cancel
Save