Revert "Get rid of Selection, simplifying the field API"

This reverts commit 8e2c6989b4.
This commit is contained in:
Evan Czaplicki 2014-03-03 00:12:02 -10:00
parent 8e2c6989b4
commit cbf7a8633b
2 changed files with 96 additions and 10 deletions

View file

@ -6,6 +6,9 @@ approach as the [`Graphics.Input`](Graphics-Input) module for describing an
# Create Fields
@docs field, password, email
# Field Content
@docs Content, Selection, Direction, noContent
# Field Style
@docs Style, Outline, noOutline, Highlight, noHighlight, Dimensions, uniformly
-}
@ -72,29 +75,56 @@ defaultStyle =
, style = Text.defaultStyle
}
{-| Represents the current content of a text field. For example:
Content "She sells sea shells" (Selection 0 3 Backward)
This means the user highlighted the substring `"She"` backwards.
-}
type Content = { string:String, selection:Selection }
{-| The selection within a text field. `start` is never greater than `end`:
Selection 0 0 Forward -- cursor precedes all characters
Selection 5 9 Backward -- highlighting characters starting after
-- the 5th and ending after the 9th
-}
type Selection = { start:Int, end:Int, direction:Direction }
{-| The direction of selection.-}
data Direction = Forward | Backward
{-| A field with no content:
Content "" (Selection 0 0 Forward)
-}
noContent : Content
noContent = Content "" (Selection 0 0 Forward)
{-| Create a text field. The following example creates a time-varying element
called `nameField`. As the user types their name, the field will be updated
to match what they have entered.
name : Input String
name = input ""
name : Input Content
name = input noContent
nameField : Signal Element
nameField = field name.handle id defaultStyle "Name" <~ name.signal
-}
field : Handle a -> (String -> a) -> Style -> String -> String -> Element
field : Handle a -> (Content -> a) -> Style -> String -> Content -> Element
field = Native.Graphics.Input.field
{-| Same as `field` but the UI element blocks out each characters. -}
password : Handle a -> (String -> a) -> Style -> String -> String -> Element
password : Handle a -> (Content -> a) -> Style -> String -> Content -> Element
password = Native.Graphics.Input.password
{-| Same as `field` but it adds an annotation that this field is for email
addresses. This is helpful for auto-complete and for mobile users who may
get a custom keyboard with an `@` and `.com` button.
-}
email : Handle a -> (String -> a) -> Style -> String -> String -> Element
email : Handle a -> (Content -> a) -> Style -> String -> Content -> Element
email = Native.Graphics.Input.email
-- area : Handle a -> (String -> a) -> Handle b -> ((Int,Int) -> b) -> (Int,Int) -> String -> String -> Element
-- area : Handle a -> (Content -> a) -> Handle b -> ((Int,Int) -> b) -> (Int,Int) -> String -> Content -> Element
-- area = Native.Graphics.Input.area

View file

@ -209,6 +209,14 @@ Elm.Native.Graphics.Input.make = function(elm) {
});
}
function setRange(node, start, end, dir) {
if (node.parentNode) {
node.setSelectionRange(start, end, dir);
} else {
setTimeout(function(){node.setSelectionRange(start, end, dir);}, 0);
}
}
function updateIfNeeded(css, attribute, latestAttribute) {
if (css[attribute] !== latestAttribute) {
css[attribute] = latestAttribute;
@ -259,7 +267,10 @@ Elm.Native.Graphics.Input.make = function(elm) {
field.type = model.type;
field.placeholder = JS.fromString(model.placeHolder);
field.value = JS.fromString(model.content);
field.value = JS.fromString(model.content.string);
var selection = model.content.selection;
var direction = selection.direction.ctor === 'Forward' ? 'forward' : 'backward';
setRange(field, selection.start, selection.end, direction);
field.elm_signal = model.signal;
field.elm_handler = model.handler;
@ -271,7 +282,15 @@ Elm.Native.Graphics.Input.make = function(elm) {
String.fromCharCode(event.keyCode) +
curr.slice(field.selectionEnd));
var pos = field.selectionEnd + 1;
elm.notify(field.elm_signal.id, field.elm_handler(JS.toString(next)));
elm.notify(field.elm_signal.id, field.elm_handler({
_:{},
string: JS.toString(next),
selection: {
start: pos,
end: pos,
direction: { ctor:'Forward' }
},
}));
event.preventDefault();
}
@ -281,12 +300,46 @@ Elm.Native.Graphics.Input.make = function(elm) {
if (curr === next) {
return;
}
var direction = field.selectionDirection === 'forward' ? 'Forward' : 'Backward';
var start = field.selectionStart;
var end = field.selectionEnd;
field.value = field.elm_old_value;
elm.notify(field.elm_signal.id, field.elm_handler(JS.toString(next)));
elm.notify(field.elm_signal.id, field.elm_handler({
_:{},
string: JS.toString(next),
selection: {
start: start,
end: end,
direction: { ctor: direction }
},
}));
}
function mouseUpdate(event) {
var direction = field.selectionDirection === 'forward' ? 'Forward' : 'Backward';
elm.notify(field.elm_signal.id, field.elm_handler({
_:{},
string: field.value,
selection: {
start: field.selectionStart,
end: field.selectionEnd,
direction: { ctor: direction }
},
}));
}
function mousedown(event) {
mouseUpdate(event);
elm.node.addEventListener('mouseup', mouseup);
}
function mouseup(event) {
mouseUpdate(event);
elm.node.removeEventListener('mouseup', mouseup)
}
field.addEventListener('keypress', keyUpdate);
field.addEventListener('input', inputUpdate);
field.addEventListener('mousedown', mousedown);
return field;
}
@ -300,9 +353,12 @@ Elm.Native.Graphics.Input.make = function(elm) {
field.type = newModel.type;
field.placeholder = JS.fromString(newModel.placeHolder);
var value = JS.fromString(newModel.content);
var value = JS.fromString(newModel.content.string);
field.value = value;
field.elm_old_value = value;
var selection = newModel.content.selection;
var direction = selection.direction.ctor === 'Forward' ? 'forward' : 'backward';
setRange(field, selection.start, selection.end, direction);
}
function mkField(type) {