Made the clipboard-related functionality in TextInput more testable. Added test_clipboard_paste to the "test-unit" suite.

This commit is contained in:
Avi Weinstock 2015-04-22 13:25:05 -04:00
parent 387836c42e
commit b742eeca05
11 changed files with 532 additions and 436 deletions

View file

@ -0,0 +1,48 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use msg::constellation_msg::ConstellationChan;
use msg::constellation_msg::Msg as ConstellationMsg;
use collections::borrow::ToOwned;
use std::sync::mpsc::channel;
pub trait ClipboardProvider {
// blocking method to get the clipboard contents
fn get_clipboard_contents(&mut self) -> String;
// blocking method to set the clipboard contents
fn set_clipboard_contents(&mut self, &str);
}
impl ClipboardProvider for ConstellationChan {
fn get_clipboard_contents(&mut self) -> String {
let (tx, rx) = channel();
self.0.send(ConstellationMsg::GetClipboardContents(tx)).unwrap();
rx.recv().unwrap()
}
fn set_clipboard_contents(&mut self, _: &str) {
panic!("not yet implemented");
}
}
pub struct DummyClipboardContext {
content: String
}
impl DummyClipboardContext {
pub fn new(s: &str) -> DummyClipboardContext {
DummyClipboardContext {
content: s.to_owned()
}
}
}
impl ClipboardProvider for DummyClipboardContext {
fn get_clipboard_contents(&mut self) -> String {
self.content.clone()
}
fn set_clipboard_contents(&mut self, s: &str) {
self.content = s.to_owned();
}
}

View file

@ -701,8 +701,8 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> {
let props = KeyboardEvent::key_properties(key, modifiers); let props = KeyboardEvent::key_properties(key, modifiers);
let keyevent = KeyboardEvent::new(window.r(), ev_type, true, true, let keyevent = KeyboardEvent::new(window.r(), ev_type, true, true,
Some(window.r()), 0, Some(window.r()), 0, Some(key),
props.key.to_owned(), props.code.to_owned(), props.key_string.to_owned(), props.code.to_owned(),
props.location, is_repeating, is_composing, props.location, is_repeating, is_composing,
ctrl, alt, shift, meta, ctrl, alt, shift, meta,
None, props.key_code).root(); None, props.key_code).root();
@ -714,8 +714,8 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> {
if state != KeyState::Released && props.is_printable() && !prevented { if state != KeyState::Released && props.is_printable() && !prevented {
// https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#keypress-event-order // https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#keypress-event-order
let event = KeyboardEvent::new(window.r(), "keypress".to_owned(), let event = KeyboardEvent::new(window.r(), "keypress".to_owned(),
true, true, Some(window.r()), true, true, Some(window.r()), 0, Some(key),
0, props.key.to_owned(), props.code.to_owned(), props.key_string.to_owned(), props.code.to_owned(),
props.location, is_repeating, is_composing, props.location, is_repeating, is_composing,
ctrl, alt, shift, meta, ctrl, alt, shift, meta,
props.char_code, 0).root(); props.char_code, 0).root();

View file

@ -35,6 +35,7 @@ use dom::window::WindowHelpers;
use textinput::TextInput; use textinput::TextInput;
use textinput::KeyReaction::{TriggerDefaultAction, DispatchInput, Nothing}; use textinput::KeyReaction::{TriggerDefaultAction, DispatchInput, Nothing};
use textinput::Lines::Single; use textinput::Lines::Single;
use msg::constellation_msg::ConstellationChan;
use util::str::DOMString; use util::str::DOMString;
use string_cache::Atom; use string_cache::Atom;
@ -72,7 +73,7 @@ pub struct HTMLInputElement {
indeterminate: Cell<bool>, indeterminate: Cell<bool>,
value_changed: Cell<bool>, value_changed: Cell<bool>,
size: Cell<u32>, size: Cell<u32>,
textinput: DOMRefCell<TextInput>, textinput: DOMRefCell<TextInput<ConstellationChan>>,
activation_state: DOMRefCell<InputActivationState>, activation_state: DOMRefCell<InputActivationState>,
} }
@ -122,7 +123,7 @@ impl HTMLInputElement {
checked_changed: Cell::new(false), checked_changed: Cell::new(false),
value_changed: Cell::new(false), value_changed: Cell::new(false),
size: Cell::new(DEFAULT_INPUT_SIZE), size: Cell::new(DEFAULT_INPUT_SIZE),
textinput: DOMRefCell::new(TextInput::new(Single, "".to_owned(), Some(chan))), textinput: DOMRefCell::new(TextInput::new(Single, "".to_owned(), chan)),
activation_state: DOMRefCell::new(InputActivationState::new()) activation_state: DOMRefCell::new(InputActivationState::new())
} }
} }

View file

@ -30,6 +30,7 @@ use textinput::{TextInput, Lines, KeyReaction};
use dom::virtualmethods::VirtualMethods; use dom::virtualmethods::VirtualMethods;
use dom::window::WindowHelpers; use dom::window::WindowHelpers;
use script_task::{ScriptMsg, Runnable}; use script_task::{ScriptMsg, Runnable};
use msg::constellation_msg::ConstellationChan;
use util::str::DOMString; use util::str::DOMString;
use string_cache::Atom; use string_cache::Atom;
@ -40,7 +41,7 @@ use std::cell::Cell;
#[dom_struct] #[dom_struct]
pub struct HTMLTextAreaElement { pub struct HTMLTextAreaElement {
htmlelement: HTMLElement, htmlelement: HTMLElement,
textinput: DOMRefCell<TextInput>, textinput: DOMRefCell<TextInput<ConstellationChan>>,
cols: Cell<u32>, cols: Cell<u32>,
rows: Cell<u32>, rows: Cell<u32>,
// https://html.spec.whatwg.org/multipage/#concept-textarea-dirty // https://html.spec.whatwg.org/multipage/#concept-textarea-dirty
@ -95,7 +96,7 @@ impl HTMLTextAreaElement {
let chan = document.window().root().r().constellation_chan(); let chan = document.window().root().r().constellation_chan();
HTMLTextAreaElement { HTMLTextAreaElement {
htmlelement: HTMLElement::new_inherited(HTMLElementTypeId::HTMLTextAreaElement, localName, prefix, document), htmlelement: HTMLElement::new_inherited(HTMLElementTypeId::HTMLTextAreaElement, localName, prefix, document),
textinput: DOMRefCell::new(TextInput::new(Lines::Multiple, "".to_owned(), Some(chan))), textinput: DOMRefCell::new(TextInput::new(Lines::Multiple, "".to_owned(), chan)),
cols: Cell::new(DEFAULT_COLS), cols: Cell::new(DEFAULT_COLS),
rows: Cell::new(DEFAULT_ROWS), rows: Cell::new(DEFAULT_ROWS),
value_changed: Cell::new(false), value_changed: Cell::new(false),

View file

@ -14,15 +14,19 @@ use dom::event::{Event, EventTypeId};
use dom::uievent::UIEvent; use dom::uievent::UIEvent;
use dom::window::Window; use dom::window::Window;
use msg::constellation_msg; use msg::constellation_msg;
use msg::constellation_msg::{Key, KeyModifiers};
use util::str::DOMString; use util::str::DOMString;
use std::borrow::ToOwned; use std::borrow::ToOwned;
use std::cell::{RefCell, Cell}; use std::cell::{RefCell, Cell};
no_jsmanaged_fields!(Key);
#[dom_struct] #[dom_struct]
pub struct KeyboardEvent { pub struct KeyboardEvent {
uievent: UIEvent, uievent: UIEvent,
key: RefCell<DOMString>, key: Cell<Option<Key>>,
key_string: RefCell<DOMString>,
code: RefCell<DOMString>, code: RefCell<DOMString>,
location: Cell<u32>, location: Cell<u32>,
ctrl: Cell<bool>, ctrl: Cell<bool>,
@ -45,7 +49,8 @@ impl KeyboardEvent {
fn new_inherited() -> KeyboardEvent { fn new_inherited() -> KeyboardEvent {
KeyboardEvent { KeyboardEvent {
uievent: UIEvent::new_inherited(EventTypeId::KeyboardEvent), uievent: UIEvent::new_inherited(EventTypeId::KeyboardEvent),
key: RefCell::new("".to_owned()), key: Cell::new(None),
key_string: RefCell::new("".to_owned()),
code: RefCell::new("".to_owned()), code: RefCell::new("".to_owned()),
location: Cell::new(0), location: Cell::new(0),
ctrl: Cell::new(false), ctrl: Cell::new(false),
@ -71,7 +76,8 @@ impl KeyboardEvent {
cancelable: bool, cancelable: bool,
view: Option<JSRef<Window>>, view: Option<JSRef<Window>>,
_detail: i32, _detail: i32,
key: DOMString, key: Option<Key>,
key_string: DOMString,
code: DOMString, code: DOMString,
location: u32, location: u32,
repeat: bool, repeat: bool,
@ -83,10 +89,11 @@ impl KeyboardEvent {
char_code: Option<u32>, char_code: Option<u32>,
key_code: u32) -> Temporary<KeyboardEvent> { key_code: u32) -> Temporary<KeyboardEvent> {
let ev = KeyboardEvent::new_uninitialized(window).root(); let ev = KeyboardEvent::new_uninitialized(window).root();
ev.r().InitKeyboardEvent(type_, canBubble, cancelable, view, key, location, ev.r().InitKeyboardEvent(type_, canBubble, cancelable, view, key_string, location,
"".to_owned(), repeat, "".to_owned()); "".to_owned(), repeat, "".to_owned());
// FIXME(https://github.com/rust-lang/rust/issues/23338) // FIXME(https://github.com/rust-lang/rust/issues/23338)
let ev = ev.r(); let ev = ev.r();
ev.key.set(key);
*ev.code.borrow_mut() = code; *ev.code.borrow_mut() = code;
ev.ctrl.set(ctrlKey); ev.ctrl.set(ctrlKey);
ev.alt.set(altKey); ev.alt.set(altKey);
@ -105,7 +112,7 @@ impl KeyboardEvent {
init.parent.parent.parent.bubbles, init.parent.parent.parent.bubbles,
init.parent.parent.parent.cancelable, init.parent.parent.parent.cancelable,
init.parent.parent.view.r(), init.parent.parent.view.r(),
init.parent.parent.detail, init.parent.parent.detail, None,
init.key.clone(), init.code.clone(), init.location, init.key.clone(), init.code.clone(), init.location,
init.repeat, init.isComposing, init.parent.ctrlKey, init.repeat, init.isComposing, init.parent.ctrlKey,
init.parent.altKey, init.parent.shiftKey, init.parent.metaKey, init.parent.altKey, init.parent.shiftKey, init.parent.metaKey,
@ -113,10 +120,10 @@ impl KeyboardEvent {
Ok(event) Ok(event)
} }
pub fn key_properties(key: constellation_msg::Key, mods: constellation_msg::KeyModifiers) pub fn key_properties(key: Key, mods: KeyModifiers)
-> KeyEventProperties { -> KeyEventProperties {
KeyEventProperties { KeyEventProperties {
key: key_value(key, mods), key_string: key_value(key, mods),
code: code_value(key), code: code_value(key),
location: key_location(key), location: key_location(key),
char_code: key_charcode(key, mods), char_code: key_charcode(key, mods),
@ -125,321 +132,350 @@ impl KeyboardEvent {
} }
} }
pub trait KeyboardEventHelpers {
fn get_key(&self) -> Option<Key>;
fn get_key_modifiers(&self) -> KeyModifiers;
}
impl<'a> KeyboardEventHelpers for JSRef<'a, KeyboardEvent> {
fn get_key(&self) -> Option<Key> {
self.key.get().clone()
}
fn get_key_modifiers(&self) -> KeyModifiers {
let mut result = KeyModifiers::empty();
if self.shift.get() {
result = result | constellation_msg::SHIFT;
}
if self.ctrl.get() {
result = result | constellation_msg::CONTROL;
}
if self.alt.get() {
result = result | constellation_msg::ALT;
}
if self.meta.get() {
result = result | constellation_msg::SUPER;
}
return result;
}
}
// https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3Events-key.html // https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3Events-key.html
fn key_value(key: constellation_msg::Key, mods: constellation_msg::KeyModifiers) -> &'static str { pub fn key_value(key: Key, mods: KeyModifiers) -> &'static str {
let shift = mods.contains(constellation_msg::SHIFT); let shift = mods.contains(constellation_msg::SHIFT);
match key { match key {
constellation_msg::Key::Space => " ", Key::Space => " ",
constellation_msg::Key::Apostrophe if shift => "\"", Key::Apostrophe if shift => "\"",
constellation_msg::Key::Apostrophe => "'", Key::Apostrophe => "'",
constellation_msg::Key::Comma if shift => "<", Key::Comma if shift => "<",
constellation_msg::Key::Comma => ",", Key::Comma => ",",
constellation_msg::Key::Minus if shift => "_", Key::Minus if shift => "_",
constellation_msg::Key::Minus => "-", Key::Minus => "-",
constellation_msg::Key::Period if shift => ">", Key::Period if shift => ">",
constellation_msg::Key::Period => ".", Key::Period => ".",
constellation_msg::Key::Slash if shift => "?", Key::Slash if shift => "?",
constellation_msg::Key::Slash => "/", Key::Slash => "/",
constellation_msg::Key::GraveAccent if shift => "~", Key::GraveAccent if shift => "~",
constellation_msg::Key::GraveAccent => "`", Key::GraveAccent => "`",
constellation_msg::Key::Num0 if shift => ")", Key::Num0 if shift => ")",
constellation_msg::Key::Num0 => "0", Key::Num0 => "0",
constellation_msg::Key::Num1 if shift => "!", Key::Num1 if shift => "!",
constellation_msg::Key::Num1 => "1", Key::Num1 => "1",
constellation_msg::Key::Num2 if shift => "@", Key::Num2 if shift => "@",
constellation_msg::Key::Num2 => "2", Key::Num2 => "2",
constellation_msg::Key::Num3 if shift => "#", Key::Num3 if shift => "#",
constellation_msg::Key::Num3 => "3", Key::Num3 => "3",
constellation_msg::Key::Num4 if shift => "$", Key::Num4 if shift => "$",
constellation_msg::Key::Num4 => "4", Key::Num4 => "4",
constellation_msg::Key::Num5 if shift => "%", Key::Num5 if shift => "%",
constellation_msg::Key::Num5 => "5", Key::Num5 => "5",
constellation_msg::Key::Num6 if shift => "^", Key::Num6 if shift => "^",
constellation_msg::Key::Num6 => "6", Key::Num6 => "6",
constellation_msg::Key::Num7 if shift => "&", Key::Num7 if shift => "&",
constellation_msg::Key::Num7 => "7", Key::Num7 => "7",
constellation_msg::Key::Num8 if shift => "*", Key::Num8 if shift => "*",
constellation_msg::Key::Num8 => "8", Key::Num8 => "8",
constellation_msg::Key::Num9 if shift => "(", Key::Num9 if shift => "(",
constellation_msg::Key::Num9 => "9", Key::Num9 => "9",
constellation_msg::Key::Semicolon if shift => ":", Key::Semicolon if shift => ":",
constellation_msg::Key::Semicolon => ";", Key::Semicolon => ";",
constellation_msg::Key::Equal if shift => "+", Key::Equal if shift => "+",
constellation_msg::Key::Equal => "=", Key::Equal => "=",
constellation_msg::Key::A if shift => "A", Key::A if shift => "A",
constellation_msg::Key::A => "a", Key::A => "a",
constellation_msg::Key::B if shift => "B", Key::B if shift => "B",
constellation_msg::Key::B => "b", Key::B => "b",
constellation_msg::Key::C if shift => "C", Key::C if shift => "C",
constellation_msg::Key::C => "c", Key::C => "c",
constellation_msg::Key::D if shift => "D", Key::D if shift => "D",
constellation_msg::Key::D => "d", Key::D => "d",
constellation_msg::Key::E if shift => "E", Key::E if shift => "E",
constellation_msg::Key::E => "e", Key::E => "e",
constellation_msg::Key::F if shift => "F", Key::F if shift => "F",
constellation_msg::Key::F => "f", Key::F => "f",
constellation_msg::Key::G if shift => "G", Key::G if shift => "G",
constellation_msg::Key::G => "g", Key::G => "g",
constellation_msg::Key::H if shift => "H", Key::H if shift => "H",
constellation_msg::Key::H => "h", Key::H => "h",
constellation_msg::Key::I if shift => "I", Key::I if shift => "I",
constellation_msg::Key::I => "i", Key::I => "i",
constellation_msg::Key::J if shift => "J", Key::J if shift => "J",
constellation_msg::Key::J => "j", Key::J => "j",
constellation_msg::Key::K if shift => "K", Key::K if shift => "K",
constellation_msg::Key::K => "k", Key::K => "k",
constellation_msg::Key::L if shift => "L", Key::L if shift => "L",
constellation_msg::Key::L => "l", Key::L => "l",
constellation_msg::Key::M if shift => "M", Key::M if shift => "M",
constellation_msg::Key::M => "m", Key::M => "m",
constellation_msg::Key::N if shift => "N", Key::N if shift => "N",
constellation_msg::Key::N => "n", Key::N => "n",
constellation_msg::Key::O if shift => "O", Key::O if shift => "O",
constellation_msg::Key::O => "o", Key::O => "o",
constellation_msg::Key::P if shift => "P", Key::P if shift => "P",
constellation_msg::Key::P => "p", Key::P => "p",
constellation_msg::Key::Q if shift => "Q", Key::Q if shift => "Q",
constellation_msg::Key::Q => "q", Key::Q => "q",
constellation_msg::Key::R if shift => "R", Key::R if shift => "R",
constellation_msg::Key::R => "r", Key::R => "r",
constellation_msg::Key::S if shift => "S", Key::S if shift => "S",
constellation_msg::Key::S => "s", Key::S => "s",
constellation_msg::Key::T if shift => "T", Key::T if shift => "T",
constellation_msg::Key::T => "t", Key::T => "t",
constellation_msg::Key::U if shift => "U", Key::U if shift => "U",
constellation_msg::Key::U => "u", Key::U => "u",
constellation_msg::Key::V if shift => "V", Key::V if shift => "V",
constellation_msg::Key::V => "v", Key::V => "v",
constellation_msg::Key::W if shift => "W", Key::W if shift => "W",
constellation_msg::Key::W => "w", Key::W => "w",
constellation_msg::Key::X if shift => "X", Key::X if shift => "X",
constellation_msg::Key::X => "x", Key::X => "x",
constellation_msg::Key::Y if shift => "Y", Key::Y if shift => "Y",
constellation_msg::Key::Y => "y", Key::Y => "y",
constellation_msg::Key::Z if shift => "Z", Key::Z if shift => "Z",
constellation_msg::Key::Z => "z", Key::Z => "z",
constellation_msg::Key::LeftBracket if shift => "{", Key::LeftBracket if shift => "{",
constellation_msg::Key::LeftBracket => "[", Key::LeftBracket => "[",
constellation_msg::Key::Backslash if shift => "|", Key::Backslash if shift => "|",
constellation_msg::Key::Backslash => "\\", Key::Backslash => "\\",
constellation_msg::Key::RightBracket if shift => "}", Key::RightBracket if shift => "}",
constellation_msg::Key::RightBracket => "]", Key::RightBracket => "]",
constellation_msg::Key::World1 => "Unidentified", Key::World1 => "Unidentified",
constellation_msg::Key::World2 => "Unidentified", Key::World2 => "Unidentified",
constellation_msg::Key::Escape => "Escape", Key::Escape => "Escape",
constellation_msg::Key::Enter => "Enter", Key::Enter => "Enter",
constellation_msg::Key::Tab => "Tab", Key::Tab => "Tab",
constellation_msg::Key::Backspace => "Backspace", Key::Backspace => "Backspace",
constellation_msg::Key::Insert => "Insert", Key::Insert => "Insert",
constellation_msg::Key::Delete => "Delete", Key::Delete => "Delete",
constellation_msg::Key::Right => "ArrowRight", Key::Right => "ArrowRight",
constellation_msg::Key::Left => "ArrowLeft", Key::Left => "ArrowLeft",
constellation_msg::Key::Down => "ArrowDown", Key::Down => "ArrowDown",
constellation_msg::Key::Up => "ArrowUp", Key::Up => "ArrowUp",
constellation_msg::Key::PageUp => "PageUp", Key::PageUp => "PageUp",
constellation_msg::Key::PageDown => "PageDown", Key::PageDown => "PageDown",
constellation_msg::Key::Home => "Home", Key::Home => "Home",
constellation_msg::Key::End => "End", Key::End => "End",
constellation_msg::Key::CapsLock => "CapsLock", Key::CapsLock => "CapsLock",
constellation_msg::Key::ScrollLock => "ScrollLock", Key::ScrollLock => "ScrollLock",
constellation_msg::Key::NumLock => "NumLock", Key::NumLock => "NumLock",
constellation_msg::Key::PrintScreen => "PrintScreen", Key::PrintScreen => "PrintScreen",
constellation_msg::Key::Pause => "Pause", Key::Pause => "Pause",
constellation_msg::Key::F1 => "F1", Key::F1 => "F1",
constellation_msg::Key::F2 => "F2", Key::F2 => "F2",
constellation_msg::Key::F3 => "F3", Key::F3 => "F3",
constellation_msg::Key::F4 => "F4", Key::F4 => "F4",
constellation_msg::Key::F5 => "F5", Key::F5 => "F5",
constellation_msg::Key::F6 => "F6", Key::F6 => "F6",
constellation_msg::Key::F7 => "F7", Key::F7 => "F7",
constellation_msg::Key::F8 => "F8", Key::F8 => "F8",
constellation_msg::Key::F9 => "F9", Key::F9 => "F9",
constellation_msg::Key::F10 => "F10", Key::F10 => "F10",
constellation_msg::Key::F11 => "F11", Key::F11 => "F11",
constellation_msg::Key::F12 => "F12", Key::F12 => "F12",
constellation_msg::Key::F13 => "F13", Key::F13 => "F13",
constellation_msg::Key::F14 => "F14", Key::F14 => "F14",
constellation_msg::Key::F15 => "F15", Key::F15 => "F15",
constellation_msg::Key::F16 => "F16", Key::F16 => "F16",
constellation_msg::Key::F17 => "F17", Key::F17 => "F17",
constellation_msg::Key::F18 => "F18", Key::F18 => "F18",
constellation_msg::Key::F19 => "F19", Key::F19 => "F19",
constellation_msg::Key::F20 => "F20", Key::F20 => "F20",
constellation_msg::Key::F21 => "F21", Key::F21 => "F21",
constellation_msg::Key::F22 => "F22", Key::F22 => "F22",
constellation_msg::Key::F23 => "F23", Key::F23 => "F23",
constellation_msg::Key::F24 => "F24", Key::F24 => "F24",
constellation_msg::Key::F25 => "F25", Key::F25 => "F25",
constellation_msg::Key::Kp0 => "0", Key::Kp0 => "0",
constellation_msg::Key::Kp1 => "1", Key::Kp1 => "1",
constellation_msg::Key::Kp2 => "2", Key::Kp2 => "2",
constellation_msg::Key::Kp3 => "3", Key::Kp3 => "3",
constellation_msg::Key::Kp4 => "4", Key::Kp4 => "4",
constellation_msg::Key::Kp5 => "5", Key::Kp5 => "5",
constellation_msg::Key::Kp6 => "6", Key::Kp6 => "6",
constellation_msg::Key::Kp7 => "7", Key::Kp7 => "7",
constellation_msg::Key::Kp8 => "8", Key::Kp8 => "8",
constellation_msg::Key::Kp9 => "9", Key::Kp9 => "9",
constellation_msg::Key::KpDecimal => ".", Key::KpDecimal => ".",
constellation_msg::Key::KpDivide => "/", Key::KpDivide => "/",
constellation_msg::Key::KpMultiply => "*", Key::KpMultiply => "*",
constellation_msg::Key::KpSubtract => "-", Key::KpSubtract => "-",
constellation_msg::Key::KpAdd => "+", Key::KpAdd => "+",
constellation_msg::Key::KpEnter => "Enter", Key::KpEnter => "Enter",
constellation_msg::Key::KpEqual => "=", Key::KpEqual => "=",
constellation_msg::Key::LeftShift => "Shift", Key::LeftShift => "Shift",
constellation_msg::Key::LeftControl => "Control", Key::LeftControl => "Control",
constellation_msg::Key::LeftAlt => "Alt", Key::LeftAlt => "Alt",
constellation_msg::Key::LeftSuper => "Super", Key::LeftSuper => "Super",
constellation_msg::Key::RightShift => "Shift", Key::RightShift => "Shift",
constellation_msg::Key::RightControl => "Control", Key::RightControl => "Control",
constellation_msg::Key::RightAlt => "Alt", Key::RightAlt => "Alt",
constellation_msg::Key::RightSuper => "Super", Key::RightSuper => "Super",
constellation_msg::Key::Menu => "ContextMenu", Key::Menu => "ContextMenu",
} }
} }
// https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3Events-code.html // https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3Events-code.html
fn code_value(key: constellation_msg::Key) -> &'static str { fn code_value(key: Key) -> &'static str {
match key { match key {
constellation_msg::Key::Space => "Space", Key::Space => "Space",
constellation_msg::Key::Apostrophe => "Quote", Key::Apostrophe => "Quote",
constellation_msg::Key::Comma => "Comma", Key::Comma => "Comma",
constellation_msg::Key::Minus => "Minus", Key::Minus => "Minus",
constellation_msg::Key::Period => "Period", Key::Period => "Period",
constellation_msg::Key::Slash => "Slash", Key::Slash => "Slash",
constellation_msg::Key::GraveAccent => "Backquote", Key::GraveAccent => "Backquote",
constellation_msg::Key::Num0 => "Digit0", Key::Num0 => "Digit0",
constellation_msg::Key::Num1 => "Digit1", Key::Num1 => "Digit1",
constellation_msg::Key::Num2 => "Digit2", Key::Num2 => "Digit2",
constellation_msg::Key::Num3 => "Digit3", Key::Num3 => "Digit3",
constellation_msg::Key::Num4 => "Digit4", Key::Num4 => "Digit4",
constellation_msg::Key::Num5 => "Digit5", Key::Num5 => "Digit5",
constellation_msg::Key::Num6 => "Digit6", Key::Num6 => "Digit6",
constellation_msg::Key::Num7 => "Digit7", Key::Num7 => "Digit7",
constellation_msg::Key::Num8 => "Digit8", Key::Num8 => "Digit8",
constellation_msg::Key::Num9 => "Digit9", Key::Num9 => "Digit9",
constellation_msg::Key::Semicolon => "Semicolon", Key::Semicolon => "Semicolon",
constellation_msg::Key::Equal => "Equal", Key::Equal => "Equal",
constellation_msg::Key::A => "KeyA", Key::A => "KeyA",
constellation_msg::Key::B => "KeyB", Key::B => "KeyB",
constellation_msg::Key::C => "KeyC", Key::C => "KeyC",
constellation_msg::Key::D => "KeyD", Key::D => "KeyD",
constellation_msg::Key::E => "KeyE", Key::E => "KeyE",
constellation_msg::Key::F => "KeyF", Key::F => "KeyF",
constellation_msg::Key::G => "KeyG", Key::G => "KeyG",
constellation_msg::Key::H => "KeyH", Key::H => "KeyH",
constellation_msg::Key::I => "KeyI", Key::I => "KeyI",
constellation_msg::Key::J => "KeyJ", Key::J => "KeyJ",
constellation_msg::Key::K => "KeyK", Key::K => "KeyK",
constellation_msg::Key::L => "KeyL", Key::L => "KeyL",
constellation_msg::Key::M => "KeyM", Key::M => "KeyM",
constellation_msg::Key::N => "KeyN", Key::N => "KeyN",
constellation_msg::Key::O => "KeyO", Key::O => "KeyO",
constellation_msg::Key::P => "KeyP", Key::P => "KeyP",
constellation_msg::Key::Q => "KeyQ", Key::Q => "KeyQ",
constellation_msg::Key::R => "KeyR", Key::R => "KeyR",
constellation_msg::Key::S => "KeyS", Key::S => "KeyS",
constellation_msg::Key::T => "KeyT", Key::T => "KeyT",
constellation_msg::Key::U => "KeyU", Key::U => "KeyU",
constellation_msg::Key::V => "KeyV", Key::V => "KeyV",
constellation_msg::Key::W => "KeyW", Key::W => "KeyW",
constellation_msg::Key::X => "KeyX", Key::X => "KeyX",
constellation_msg::Key::Y => "KeyY", Key::Y => "KeyY",
constellation_msg::Key::Z => "KeyZ", Key::Z => "KeyZ",
constellation_msg::Key::LeftBracket => "BracketLeft", Key::LeftBracket => "BracketLeft",
constellation_msg::Key::Backslash => "Backslash", Key::Backslash => "Backslash",
constellation_msg::Key::RightBracket => "BracketRight", Key::RightBracket => "BracketRight",
constellation_msg::Key::World1 | Key::World1 |
constellation_msg::Key::World2 => panic!("unknown char code for {:?}", key), Key::World2 => panic!("unknown char code for {:?}", key),
constellation_msg::Key::Escape => "Escape", Key::Escape => "Escape",
constellation_msg::Key::Enter => "Enter", Key::Enter => "Enter",
constellation_msg::Key::Tab => "Tab", Key::Tab => "Tab",
constellation_msg::Key::Backspace => "Backspace", Key::Backspace => "Backspace",
constellation_msg::Key::Insert => "Insert", Key::Insert => "Insert",
constellation_msg::Key::Delete => "Delete", Key::Delete => "Delete",
constellation_msg::Key::Right => "ArrowRight", Key::Right => "ArrowRight",
constellation_msg::Key::Left => "ArrowLeft", Key::Left => "ArrowLeft",
constellation_msg::Key::Down => "ArrowDown", Key::Down => "ArrowDown",
constellation_msg::Key::Up => "ArrowUp", Key::Up => "ArrowUp",
constellation_msg::Key::PageUp => "PageUp", Key::PageUp => "PageUp",
constellation_msg::Key::PageDown => "PageDown", Key::PageDown => "PageDown",
constellation_msg::Key::Home => "Home", Key::Home => "Home",
constellation_msg::Key::End => "End", Key::End => "End",
constellation_msg::Key::CapsLock => "CapsLock", Key::CapsLock => "CapsLock",
constellation_msg::Key::ScrollLock => "ScrollLock", Key::ScrollLock => "ScrollLock",
constellation_msg::Key::NumLock => "NumLock", Key::NumLock => "NumLock",
constellation_msg::Key::PrintScreen => "PrintScreen", Key::PrintScreen => "PrintScreen",
constellation_msg::Key::Pause => "Pause", Key::Pause => "Pause",
constellation_msg::Key::F1 => "F1", Key::F1 => "F1",
constellation_msg::Key::F2 => "F2", Key::F2 => "F2",
constellation_msg::Key::F3 => "F3", Key::F3 => "F3",
constellation_msg::Key::F4 => "F4", Key::F4 => "F4",
constellation_msg::Key::F5 => "F5", Key::F5 => "F5",
constellation_msg::Key::F6 => "F6", Key::F6 => "F6",
constellation_msg::Key::F7 => "F7", Key::F7 => "F7",
constellation_msg::Key::F8 => "F8", Key::F8 => "F8",
constellation_msg::Key::F9 => "F9", Key::F9 => "F9",
constellation_msg::Key::F10 => "F10", Key::F10 => "F10",
constellation_msg::Key::F11 => "F11", Key::F11 => "F11",
constellation_msg::Key::F12 => "F12", Key::F12 => "F12",
constellation_msg::Key::F13 => "F13", Key::F13 => "F13",
constellation_msg::Key::F14 => "F14", Key::F14 => "F14",
constellation_msg::Key::F15 => "F15", Key::F15 => "F15",
constellation_msg::Key::F16 => "F16", Key::F16 => "F16",
constellation_msg::Key::F17 => "F17", Key::F17 => "F17",
constellation_msg::Key::F18 => "F18", Key::F18 => "F18",
constellation_msg::Key::F19 => "F19", Key::F19 => "F19",
constellation_msg::Key::F20 => "F20", Key::F20 => "F20",
constellation_msg::Key::F21 => "F21", Key::F21 => "F21",
constellation_msg::Key::F22 => "F22", Key::F22 => "F22",
constellation_msg::Key::F23 => "F23", Key::F23 => "F23",
constellation_msg::Key::F24 => "F24", Key::F24 => "F24",
constellation_msg::Key::F25 => "F25", Key::F25 => "F25",
constellation_msg::Key::Kp0 => "Numpad0", Key::Kp0 => "Numpad0",
constellation_msg::Key::Kp1 => "Numpad1", Key::Kp1 => "Numpad1",
constellation_msg::Key::Kp2 => "Numpad2", Key::Kp2 => "Numpad2",
constellation_msg::Key::Kp3 => "Numpad3", Key::Kp3 => "Numpad3",
constellation_msg::Key::Kp4 => "Numpad4", Key::Kp4 => "Numpad4",
constellation_msg::Key::Kp5 => "Numpad5", Key::Kp5 => "Numpad5",
constellation_msg::Key::Kp6 => "Numpad6", Key::Kp6 => "Numpad6",
constellation_msg::Key::Kp7 => "Numpad7", Key::Kp7 => "Numpad7",
constellation_msg::Key::Kp8 => "Numpad8", Key::Kp8 => "Numpad8",
constellation_msg::Key::Kp9 => "Numpad9", Key::Kp9 => "Numpad9",
constellation_msg::Key::KpDecimal => "NumpadDecimal", Key::KpDecimal => "NumpadDecimal",
constellation_msg::Key::KpDivide => "NumpadDivide", Key::KpDivide => "NumpadDivide",
constellation_msg::Key::KpMultiply => "NumpadMultiply", Key::KpMultiply => "NumpadMultiply",
constellation_msg::Key::KpSubtract => "NumpadSubtract", Key::KpSubtract => "NumpadSubtract",
constellation_msg::Key::KpAdd => "NumpadAdd", Key::KpAdd => "NumpadAdd",
constellation_msg::Key::KpEnter => "NumpadEnter", Key::KpEnter => "NumpadEnter",
constellation_msg::Key::KpEqual => "NumpadEqual", Key::KpEqual => "NumpadEqual",
constellation_msg::Key::LeftShift | constellation_msg::Key::RightShift => "Shift", Key::LeftShift | Key::RightShift => "Shift",
constellation_msg::Key::LeftControl | constellation_msg::Key::RightControl => "Control", Key::LeftControl | Key::RightControl => "Control",
constellation_msg::Key::LeftAlt | constellation_msg::Key::RightAlt => "Alt", Key::LeftAlt | Key::RightAlt => "Alt",
constellation_msg::Key::LeftSuper | constellation_msg::Key::RightSuper => "Super", Key::LeftSuper | Key::RightSuper => "Super",
constellation_msg::Key::Menu => "Menu", Key::Menu => "Menu",
} }
} }
fn key_location(key: constellation_msg::Key) -> u32 { fn key_location(key: Key) -> u32 {
match key { match key {
constellation_msg::Key::Kp0 | constellation_msg::Key::Kp1 | constellation_msg::Key::Kp2 | Key::Kp0 | Key::Kp1 | Key::Kp2 |
constellation_msg::Key::Kp3 | constellation_msg::Key::Kp4 | constellation_msg::Key::Kp5 | Key::Kp3 | Key::Kp4 | Key::Kp5 |
constellation_msg::Key::Kp6 | constellation_msg::Key::Kp7 | constellation_msg::Key::Kp8 | Key::Kp6 | Key::Kp7 | Key::Kp8 |
constellation_msg::Key::Kp9 | constellation_msg::Key::KpDecimal | Key::Kp9 | Key::KpDecimal |
constellation_msg::Key::KpDivide | constellation_msg::Key::KpMultiply | Key::KpDivide | Key::KpMultiply |
constellation_msg::Key::KpSubtract | constellation_msg::Key::KpAdd | Key::KpSubtract | Key::KpAdd |
constellation_msg::Key::KpEnter | constellation_msg::Key::KpEqual => Key::KpEnter | Key::KpEqual =>
KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD, KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD,
constellation_msg::Key::LeftShift | constellation_msg::Key::LeftAlt | Key::LeftShift | Key::LeftAlt |
constellation_msg::Key::LeftControl | constellation_msg::Key::LeftSuper => Key::LeftControl | Key::LeftSuper =>
KeyboardEventConstants::DOM_KEY_LOCATION_LEFT, KeyboardEventConstants::DOM_KEY_LOCATION_LEFT,
constellation_msg::Key::RightShift | constellation_msg::Key::RightAlt | Key::RightShift | Key::RightAlt |
constellation_msg::Key::RightControl | constellation_msg::Key::RightSuper => Key::RightControl | Key::RightSuper =>
KeyboardEventConstants::DOM_KEY_LOCATION_RIGHT, KeyboardEventConstants::DOM_KEY_LOCATION_RIGHT,
_ => KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD, _ => KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD,
@ -447,89 +483,89 @@ fn key_location(key: constellation_msg::Key) -> u32 {
} }
// https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#widl-KeyboardEvent-charCode // https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#widl-KeyboardEvent-charCode
fn key_charcode(key: constellation_msg::Key, mods: constellation_msg::KeyModifiers) -> Option<u32> { fn key_charcode(key: Key, mods: KeyModifiers) -> Option<u32> {
let key = key_value(key, mods); let key_string = key_value(key, mods);
if key.len() == 1 { if key_string.len() == 1 {
Some(key.chars().next().unwrap() as u32) Some(key_string.chars().next().unwrap() as u32)
} else { } else {
None None
} }
} }
// https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#legacy-key-models // https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#legacy-key-models
fn key_keycode(key: constellation_msg::Key) -> u32 { fn key_keycode(key: Key) -> u32 {
match key { match key {
// https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#legacy-key-models // https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#legacy-key-models
constellation_msg::Key::Backspace => 8, Key::Backspace => 8,
constellation_msg::Key::Tab => 9, Key::Tab => 9,
constellation_msg::Key::Enter => 13, Key::Enter => 13,
constellation_msg::Key::LeftShift | constellation_msg::Key::RightShift => 16, Key::LeftShift | Key::RightShift => 16,
constellation_msg::Key::LeftControl | constellation_msg::Key::RightControl => 17, Key::LeftControl | Key::RightControl => 17,
constellation_msg::Key::LeftAlt | constellation_msg::Key::RightAlt => 18, Key::LeftAlt | Key::RightAlt => 18,
constellation_msg::Key::CapsLock => 20, Key::CapsLock => 20,
constellation_msg::Key::Escape => 27, Key::Escape => 27,
constellation_msg::Key::Space => 32, Key::Space => 32,
constellation_msg::Key::PageUp => 33, Key::PageUp => 33,
constellation_msg::Key::PageDown => 34, Key::PageDown => 34,
constellation_msg::Key::End => 35, Key::End => 35,
constellation_msg::Key::Home => 36, Key::Home => 36,
constellation_msg::Key::Left => 37, Key::Left => 37,
constellation_msg::Key::Up => 38, Key::Up => 38,
constellation_msg::Key::Right => 39, Key::Right => 39,
constellation_msg::Key::Down => 40, Key::Down => 40,
constellation_msg::Key::Delete => 46, Key::Delete => 46,
// https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#optionally-fixed-virtual-key-codes // https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#optionally-fixed-virtual-key-codes
constellation_msg::Key::Semicolon => 186, Key::Semicolon => 186,
constellation_msg::Key::Equal => 187, Key::Equal => 187,
constellation_msg::Key::Comma => 188, Key::Comma => 188,
constellation_msg::Key::Minus => 189, Key::Minus => 189,
constellation_msg::Key::Period => 190, Key::Period => 190,
constellation_msg::Key::Slash => 191, Key::Slash => 191,
constellation_msg::Key::LeftBracket => 219, Key::LeftBracket => 219,
constellation_msg::Key::Backslash => 220, Key::Backslash => 220,
constellation_msg::Key::RightBracket => 221, Key::RightBracket => 221,
constellation_msg::Key::Apostrophe => 222, Key::Apostrophe => 222,
//§ B.2.1.3 //§ B.2.1.3
constellation_msg::Key::Num0 | Key::Num0 |
constellation_msg::Key::Num1 | Key::Num1 |
constellation_msg::Key::Num2 | Key::Num2 |
constellation_msg::Key::Num3 | Key::Num3 |
constellation_msg::Key::Num4 | Key::Num4 |
constellation_msg::Key::Num5 | Key::Num5 |
constellation_msg::Key::Num6 | Key::Num6 |
constellation_msg::Key::Num7 | Key::Num7 |
constellation_msg::Key::Num8 | Key::Num8 |
constellation_msg::Key::Num9 => key as u32 - constellation_msg::Key::Num0 as u32 + '0' as u32, Key::Num9 => key as u32 - Key::Num0 as u32 + '0' as u32,
//§ B.2.1.4 //§ B.2.1.4
constellation_msg::Key::A | Key::A |
constellation_msg::Key::B | Key::B |
constellation_msg::Key::C | Key::C |
constellation_msg::Key::D | Key::D |
constellation_msg::Key::E | Key::E |
constellation_msg::Key::F | Key::F |
constellation_msg::Key::G | Key::G |
constellation_msg::Key::H | Key::H |
constellation_msg::Key::I | Key::I |
constellation_msg::Key::J | Key::J |
constellation_msg::Key::K | Key::K |
constellation_msg::Key::L | Key::L |
constellation_msg::Key::M | Key::M |
constellation_msg::Key::N | Key::N |
constellation_msg::Key::O | Key::O |
constellation_msg::Key::P | Key::P |
constellation_msg::Key::Q | Key::Q |
constellation_msg::Key::R | Key::R |
constellation_msg::Key::S | Key::S |
constellation_msg::Key::T | Key::T |
constellation_msg::Key::U | Key::U |
constellation_msg::Key::V | Key::V |
constellation_msg::Key::W | Key::W |
constellation_msg::Key::X | Key::X |
constellation_msg::Key::Y | Key::Y |
constellation_msg::Key::Z => key as u32 - constellation_msg::Key::A as u32 + 'A' as u32, Key::Z => key as u32 - Key::A as u32 + 'A' as u32,
//§ B.2.1.8 //§ B.2.1.8
_ => 0 _ => 0
@ -537,7 +573,7 @@ fn key_keycode(key: constellation_msg::Key) -> u32 {
} }
pub struct KeyEventProperties { pub struct KeyEventProperties {
pub key: &'static str, pub key_string: &'static str,
pub code: &'static str, pub code: &'static str,
pub location: u32, pub location: u32,
pub char_code: Option<u32>, pub char_code: Option<u32>,
@ -568,15 +604,15 @@ impl<'a> KeyboardEventMethods for JSRef<'a, KeyboardEvent> {
let uievent: JSRef<UIEvent> = UIEventCast::from_ref(self); let uievent: JSRef<UIEvent> = UIEventCast::from_ref(self);
uievent.InitUIEvent(typeArg, canBubbleArg, cancelableArg, viewArg, 0); uievent.InitUIEvent(typeArg, canBubbleArg, cancelableArg, viewArg, 0);
*self.key.borrow_mut() = keyArg; *self.key_string.borrow_mut() = keyArg;
self.location.set(locationArg); self.location.set(locationArg);
self.repeat.set(repeat); self.repeat.set(repeat);
} }
fn Key(self) -> DOMString { fn Key(self) -> DOMString {
// FIXME(https://github.com/rust-lang/rust/issues/23338) // FIXME(https://github.com/rust-lang/rust/issues/23338)
let key = self.key.borrow(); let key_string = self.key_string.borrow();
key.clone() key_string.clone()
} }
fn Code(self) -> DOMString { fn Code(self) -> DOMString {

View file

@ -66,6 +66,7 @@ pub mod page;
pub mod script_task; pub mod script_task;
mod timers; mod timers;
pub mod textinput; pub mod textinput;
pub mod clipboard_provider;
mod devtools; mod devtools;
mod horribly_inefficient_timers; mod horribly_inefficient_timers;
mod webdriver_handlers; mod webdriver_handlers;

View file

@ -4,17 +4,17 @@
//! Common handling of keyboard input and state management for text input controls //! Common handling of keyboard input and state management for text input controls
use dom::bindings::codegen::Bindings::KeyboardEventBinding::KeyboardEventMethods; use clipboard_provider::ClipboardProvider;
use dom::bindings::js::JSRef; use dom::bindings::js::JSRef;
use msg::constellation_msg::ConstellationChan; use dom::keyboardevent::{KeyboardEvent, KeyboardEventHelpers, key_value};
use msg::constellation_msg::Msg as ConstellationMsg; use msg::constellation_msg::{SHIFT, CONTROL, ALT, SUPER};
use dom::keyboardevent::KeyboardEvent; use msg::constellation_msg::{Key, KeyModifiers};
use util::str::DOMString; use util::str::DOMString;
use std::borrow::ToOwned; use std::borrow::ToOwned;
use std::cmp::{min, max}; use std::cmp::{min, max};
use std::default::Default; use std::default::Default;
use std::sync::mpsc::channel;
#[derive(Copy, Clone, PartialEq)] #[derive(Copy, Clone, PartialEq)]
pub enum Selection { pub enum Selection {
@ -33,7 +33,7 @@ pub struct TextPoint {
/// Encapsulated state for handling keyboard input in a single or multiline text input control. /// Encapsulated state for handling keyboard input in a single or multiline text input control.
#[jstraceable] #[jstraceable]
pub struct TextInput { pub struct TextInput<T: ClipboardProvider> {
/// Current text input content, split across lines without trailing '\n' /// Current text input content, split across lines without trailing '\n'
lines: Vec<DOMString>, lines: Vec<DOMString>,
/// Current cursor input point /// Current cursor input point
@ -42,7 +42,7 @@ pub struct TextInput {
selection_begin: Option<TextPoint>, selection_begin: Option<TextPoint>,
/// Is this a multiline input? /// Is this a multiline input?
multiline: bool, multiline: bool,
constellation_channel: Option<ConstellationChan> clipboard_provider: T,
} }
/// Resulting action to be taken by the owner of a text input that is handling an event. /// Resulting action to be taken by the owner of a text input that is handling an event.
@ -79,24 +79,24 @@ pub enum DeleteDir {
/// Was the keyboard event accompanied by the standard control modifier, /// Was the keyboard event accompanied by the standard control modifier,
/// i.e. cmd on Mac OS or ctrl on other platforms. /// i.e. cmd on Mac OS or ctrl on other platforms.
#[cfg(target_os="macos")] #[cfg(target_os="macos")]
fn is_control_key(event: JSRef<KeyboardEvent>) -> bool { fn is_control_key(mods: KeyModifiers) -> bool {
event.MetaKey() && !event.CtrlKey() && !event.AltKey() mods.contains(SUPER) && !mods.contains(CONTROL | ALT)
} }
#[cfg(not(target_os="macos"))] #[cfg(not(target_os="macos"))]
fn is_control_key(event: JSRef<KeyboardEvent>) -> bool { fn is_control_key(mods: KeyModifiers) -> bool {
event.CtrlKey() && !event.MetaKey() && !event.AltKey() mods.contains(CONTROL) && !mods.contains(SUPER | ALT)
} }
impl TextInput { impl<T: ClipboardProvider> TextInput<T> {
/// Instantiate a new text input control /// Instantiate a new text input control
pub fn new(lines: Lines, initial: DOMString, cc: Option<ConstellationChan>) -> TextInput { pub fn new(lines: Lines, initial: DOMString, clipboard_provider: T) -> TextInput<T> {
let mut i = TextInput { let mut i = TextInput {
lines: vec!(), lines: vec!(),
edit_point: Default::default(), edit_point: Default::default(),
selection_begin: None, selection_begin: None,
multiline: lines == Lines::Multiple, multiline: lines == Lines::Multiple,
constellation_channel: cc, clipboard_provider: clipboard_provider
}; };
i.set_content(initial); i.set_content(initial);
i i
@ -283,28 +283,22 @@ impl TextInput {
/// Process a given `KeyboardEvent` and return an action for the caller to execute. /// Process a given `KeyboardEvent` and return an action for the caller to execute.
pub fn handle_keydown(&mut self, event: JSRef<KeyboardEvent>) -> KeyReaction { pub fn handle_keydown(&mut self, event: JSRef<KeyboardEvent>) -> KeyReaction {
//A simple way to convert an event to a selection if let Some(key) = event.get_key() {
fn maybe_select(event: JSRef<KeyboardEvent>) -> Selection { self.handle_keydown_aux(key, event.get_key_modifiers())
if event.ShiftKey() { } else {
return Selection::Selected KeyReaction::Nothing
}
return Selection::NotSelected
} }
match &*event.Key() { }
"a" if is_control_key(event) => { pub fn handle_keydown_aux(&mut self, key: Key, mods: KeyModifiers) -> KeyReaction {
let maybe_select = if mods.contains(SHIFT) { Selection::Selected } else { Selection::NotSelected };
match key_value(key, mods) {
"a" if is_control_key(mods) => {
self.select_all(); self.select_all();
KeyReaction::Nothing KeyReaction::Nothing
}, },
"v" if is_control_key(event) => { "v" if is_control_key(mods) => {
let (tx, rx) = channel(); let contents = self.clipboard_provider.get_clipboard_contents();
let mut contents = None; self.insert_string(&contents);
if let Some(ref cc) = self.constellation_channel {
cc.0.send(ConstellationMsg::GetClipboardContents(tx)).unwrap();
contents = Some(rx.recv().unwrap());
}
if let Some(contents) = contents {
self.insert_string(&contents);
}
KeyReaction::DispatchInput KeyReaction::DispatchInput
}, },
// printable characters have single-character key values // printable characters have single-character key values
@ -325,19 +319,19 @@ impl TextInput {
KeyReaction::DispatchInput KeyReaction::DispatchInput
} }
"ArrowLeft" => { "ArrowLeft" => {
self.adjust_horizontal(-1, maybe_select(event)); self.adjust_horizontal(-1, maybe_select);
KeyReaction::Nothing KeyReaction::Nothing
} }
"ArrowRight" => { "ArrowRight" => {
self.adjust_horizontal(1, maybe_select(event)); self.adjust_horizontal(1, maybe_select);
KeyReaction::Nothing KeyReaction::Nothing
} }
"ArrowUp" => { "ArrowUp" => {
self.adjust_vertical(-1, maybe_select(event)); self.adjust_vertical(-1, maybe_select);
KeyReaction::Nothing KeyReaction::Nothing
} }
"ArrowDown" => { "ArrowDown" => {
self.adjust_vertical(1, maybe_select(event)); self.adjust_vertical(1, maybe_select);
KeyReaction::Nothing KeyReaction::Nothing
} }
"Enter" => self.handle_return(), "Enter" => self.handle_return(),
@ -350,11 +344,11 @@ impl TextInput {
KeyReaction::Nothing KeyReaction::Nothing
} }
"PageUp" => { "PageUp" => {
self.adjust_vertical(-28, maybe_select(event)); self.adjust_vertical(-28, maybe_select);
KeyReaction::Nothing KeyReaction::Nothing
} }
"PageDown" => { "PageDown" => {
self.adjust_vertical(28, maybe_select(event)); self.adjust_vertical(28, maybe_select);
KeyReaction::Nothing KeyReaction::Nothing
} }
"Tab" => KeyReaction::TriggerDefaultAction, "Tab" => KeyReaction::TriggerDefaultAction,

View file

@ -1035,6 +1035,7 @@ dependencies = [
name = "script_tests" name = "script_tests"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"msg 0.0.1",
"script 0.0.1", "script 0.0.1",
] ]

View file

@ -8,5 +8,8 @@ name = "script_tests"
path = "lib.rs" path = "lib.rs"
doctest = false doctest = false
[dependencies.msg]
path = "../../../components/msg"
[dependencies.script] [dependencies.script]
path = "../../../components/script" path = "../../../components/script"

View file

@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
extern crate script; extern crate script;
extern crate msg;
#[cfg(all(test, target_pointer_width = "64"))] mod size_of; #[cfg(all(test, target_pointer_width = "64"))] mod size_of;
#[cfg(test)] mod textinput; #[cfg(test)] mod textinput;

View file

@ -7,12 +7,14 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use msg::constellation_msg::{Key, CONTROL};
use script::textinput::{TextInput, Selection, Lines, DeleteDir}; use script::textinput::{TextInput, Selection, Lines, DeleteDir};
use script::clipboard_provider::DummyClipboardContext;
use std::borrow::ToOwned; use std::borrow::ToOwned;
#[test] #[test]
fn test_textinput_delete_char() { fn test_textinput_delete_char() {
let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned(), None); let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned(), DummyClipboardContext::new(""));
textinput.adjust_horizontal(2, Selection::NotSelected); textinput.adjust_horizontal(2, Selection::NotSelected);
textinput.delete_char(DeleteDir::Backward); textinput.delete_char(DeleteDir::Backward);
assert_eq!(textinput.get_content(), "acdefg"); assert_eq!(textinput.get_content(), "acdefg");
@ -27,7 +29,7 @@ fn test_textinput_delete_char() {
#[test] #[test]
fn test_textinput_insert_char() { fn test_textinput_insert_char() {
let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned(), None); let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned(), DummyClipboardContext::new(""));
textinput.adjust_horizontal(2, Selection::NotSelected); textinput.adjust_horizontal(2, Selection::NotSelected);
textinput.insert_char('a'); textinput.insert_char('a');
assert_eq!(textinput.get_content(), "abacdefg"); assert_eq!(textinput.get_content(), "abacdefg");
@ -39,7 +41,7 @@ fn test_textinput_insert_char() {
#[test] #[test]
fn test_textinput_get_sorted_selection() { fn test_textinput_get_sorted_selection() {
let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned(), None); let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned(), DummyClipboardContext::new(""));
textinput.adjust_horizontal(2, Selection::NotSelected); textinput.adjust_horizontal(2, Selection::NotSelected);
textinput.adjust_horizontal(2, Selection::Selected); textinput.adjust_horizontal(2, Selection::Selected);
let (begin, end) = textinput.get_sorted_selection(); let (begin, end) = textinput.get_sorted_selection();
@ -56,7 +58,7 @@ fn test_textinput_get_sorted_selection() {
#[test] #[test]
fn test_textinput_replace_selection() { fn test_textinput_replace_selection() {
let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned(), None); let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned(), DummyClipboardContext::new(""));
textinput.adjust_horizontal(2, Selection::NotSelected); textinput.adjust_horizontal(2, Selection::NotSelected);
textinput.adjust_horizontal(2, Selection::Selected); textinput.adjust_horizontal(2, Selection::Selected);
@ -66,7 +68,7 @@ fn test_textinput_replace_selection() {
#[test] #[test]
fn test_textinput_current_line_length() { fn test_textinput_current_line_length() {
let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), None); let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), DummyClipboardContext::new(""));
assert_eq!(textinput.current_line_length(), 3); assert_eq!(textinput.current_line_length(), 3);
textinput.adjust_vertical(1, Selection::NotSelected); textinput.adjust_vertical(1, Selection::NotSelected);
@ -78,7 +80,7 @@ fn test_textinput_current_line_length() {
#[test] #[test]
fn test_textinput_adjust_vertical() { fn test_textinput_adjust_vertical() {
let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), None); let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), DummyClipboardContext::new(""));
textinput.adjust_horizontal(3, Selection::NotSelected); textinput.adjust_horizontal(3, Selection::NotSelected);
textinput.adjust_vertical(1, Selection::NotSelected); textinput.adjust_vertical(1, Selection::NotSelected);
assert_eq!(textinput.edit_point.line, 1); assert_eq!(textinput.edit_point.line, 1);
@ -95,7 +97,7 @@ fn test_textinput_adjust_vertical() {
#[test] #[test]
fn test_textinput_adjust_horizontal() { fn test_textinput_adjust_horizontal() {
let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), None); let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), DummyClipboardContext::new(""));
textinput.adjust_horizontal(4, Selection::NotSelected); textinput.adjust_horizontal(4, Selection::NotSelected);
assert_eq!(textinput.edit_point.line, 1); assert_eq!(textinput.edit_point.line, 1);
assert_eq!(textinput.edit_point.index, 0); assert_eq!(textinput.edit_point.index, 0);
@ -115,12 +117,12 @@ fn test_textinput_adjust_horizontal() {
#[test] #[test]
fn test_textinput_handle_return() { fn test_textinput_handle_return() {
let mut single_line_textinput = TextInput::new(Lines::Single, "abcdef".to_owned(), None); let mut single_line_textinput = TextInput::new(Lines::Single, "abcdef".to_owned(), DummyClipboardContext::new(""));
single_line_textinput.adjust_horizontal(3, Selection::NotSelected); single_line_textinput.adjust_horizontal(3, Selection::NotSelected);
single_line_textinput.handle_return(); single_line_textinput.handle_return();
assert_eq!(single_line_textinput.get_content(), "abcdef"); assert_eq!(single_line_textinput.get_content(), "abcdef");
let mut multi_line_textinput = TextInput::new(Lines::Multiple, "abcdef".to_owned(), None); let mut multi_line_textinput = TextInput::new(Lines::Multiple, "abcdef".to_owned(), DummyClipboardContext::new(""));
multi_line_textinput.adjust_horizontal(3, Selection::NotSelected); multi_line_textinput.adjust_horizontal(3, Selection::NotSelected);
multi_line_textinput.handle_return(); multi_line_textinput.handle_return();
assert_eq!(multi_line_textinput.get_content(), "abc\ndef"); assert_eq!(multi_line_textinput.get_content(), "abc\ndef");
@ -128,7 +130,7 @@ fn test_textinput_handle_return() {
#[test] #[test]
fn test_textinput_select_all() { fn test_textinput_select_all() {
let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), None); let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), DummyClipboardContext::new(""));
assert_eq!(textinput.edit_point.line, 0); assert_eq!(textinput.edit_point.line, 0);
assert_eq!(textinput.edit_point.index, 0); assert_eq!(textinput.edit_point.index, 0);
@ -139,16 +141,16 @@ fn test_textinput_select_all() {
#[test] #[test]
fn test_textinput_get_content() { fn test_textinput_get_content() {
let single_line_textinput = TextInput::new(Lines::Single, "abcdefg".to_owned(), None); let single_line_textinput = TextInput::new(Lines::Single, "abcdefg".to_owned(), DummyClipboardContext::new(""));
assert_eq!(single_line_textinput.get_content(), "abcdefg"); assert_eq!(single_line_textinput.get_content(), "abcdefg");
let multi_line_textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), None); let multi_line_textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), DummyClipboardContext::new(""));
assert_eq!(multi_line_textinput.get_content(), "abc\nde\nf"); assert_eq!(multi_line_textinput.get_content(), "abc\nde\nf");
} }
#[test] #[test]
fn test_textinput_set_content() { fn test_textinput_set_content() {
let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), None); let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), DummyClipboardContext::new(""));
assert_eq!(textinput.get_content(), "abc\nde\nf"); assert_eq!(textinput.get_content(), "abc\nde\nf");
textinput.set_content("abc\nf".to_owned()); textinput.set_content("abc\nf".to_owned());
@ -165,3 +167,11 @@ fn test_textinput_set_content() {
assert_eq!(textinput.edit_point.index, 2); assert_eq!(textinput.edit_point.index, 2);
} }
#[test]
fn test_clipboard_paste() {
let mut textinput = TextInput::new(Lines::Single, "defg".to_owned(), DummyClipboardContext::new("abc"));
assert_eq!(textinput.get_content(), "defg");
assert_eq!(textinput.edit_point.index, 0);
textinput.handle_keydown_aux(Key::V, CONTROL);
assert_eq!(textinput.get_content(), "abcdefg");
}