mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[Effen] remove the last traces of the 'display' property from the effen component library.
Previously, the fn "Text" class rendered as a single block of text. Now, there's a "Paragraph" class that contains "TextFragment"s, and "Text" is just a component that places a single TextFragment into a single Paragraph. This allows other components, notably the Input component, to build more complicated paragraphs of styled text, without using 'display'. R=eseidel@chromium.org Review URL: https://codereview.chromium.org/1139123007
This commit is contained in:
parent
68624e8042
commit
9466cbbcb4
@ -6,6 +6,7 @@ import '../editing/editable_string.dart';
|
||||
import '../editing/editable_text.dart';
|
||||
import '../editing/keyboard.dart';
|
||||
import '../fn.dart';
|
||||
import '../layout.dart';
|
||||
import '../theme/colors.dart';
|
||||
import '../theme/typography.dart' as typography;
|
||||
import 'dart:sky' as sky;
|
||||
@ -14,7 +15,6 @@ typedef void ValueChanged(value);
|
||||
|
||||
class Input extends Component {
|
||||
static final Style _style = new Style('''
|
||||
display: paragraph;
|
||||
transform: translateX(0);
|
||||
margin: 8px;
|
||||
padding: 8px;
|
||||
@ -84,7 +84,8 @@ class Input extends Component {
|
||||
children.add(new EditableText(value: _editableValue, focused: focused));
|
||||
|
||||
return new EventListenerNode(
|
||||
new Container(
|
||||
new FlexContainer(
|
||||
direction: FlexDirection.Column,
|
||||
style: _style,
|
||||
inlineStyle: focused ? _focusedInlineStyle : null,
|
||||
children: children
|
||||
|
||||
@ -8,12 +8,8 @@ import 'dart:async';
|
||||
import 'editable_string.dart';
|
||||
|
||||
class EditableText extends Component {
|
||||
static final Style _style = new Style('''
|
||||
display: inline;'''
|
||||
);
|
||||
|
||||
static final Style _cursorStyle = new Style('''
|
||||
display: inline-flex;
|
||||
width: 2px;
|
||||
height: 1.2em;
|
||||
vertical-align: top;
|
||||
@ -21,7 +17,6 @@ class EditableText extends Component {
|
||||
);
|
||||
|
||||
static final Style _composingStyle = new Style('''
|
||||
display: inline;
|
||||
text-decoration: underline;'''
|
||||
);
|
||||
|
||||
@ -65,31 +60,30 @@ class EditableText extends Component {
|
||||
List<UINode> children = new List<UINode>();
|
||||
|
||||
if (!value.composing.isValid) {
|
||||
children.add(new Text(value.text));
|
||||
children.add(new TextFragment(value.text));
|
||||
} else {
|
||||
String beforeComposing = value.textBefore(value.composing);
|
||||
if (!beforeComposing.isEmpty)
|
||||
children.add(new Text(beforeComposing));
|
||||
children.add(new TextFragment(beforeComposing));
|
||||
|
||||
String composing = value.textInside(value.composing);
|
||||
if (!composing.isEmpty) {
|
||||
children.add(new Container(
|
||||
children.add(new TextFragment(
|
||||
composing,
|
||||
key: 'composing',
|
||||
style: _composingStyle,
|
||||
children: [new Text(composing)]
|
||||
style: _composingStyle
|
||||
));
|
||||
}
|
||||
|
||||
String afterComposing = value.textAfter(value.composing);
|
||||
if (!afterComposing.isEmpty)
|
||||
children.add(new Text(afterComposing));
|
||||
children.add(new TextFragment(afterComposing));
|
||||
}
|
||||
|
||||
if (_showCursor)
|
||||
children.add(new Container(key: 'cursor', style: _cursorStyle));
|
||||
|
||||
return new Container(
|
||||
style: _style,
|
||||
return new Paragraph(
|
||||
children: children
|
||||
);
|
||||
}
|
||||
|
||||
@ -38,6 +38,8 @@ abstract class UINode {
|
||||
// if the |old| node has become stateful and should be retained.
|
||||
bool _willSync(UINode old) => false;
|
||||
|
||||
bool get interchangeable => false; // if true, then keys can be duplicated
|
||||
|
||||
void _sync(UINode old, RenderCSSContainer host, RenderCSS insertBefore);
|
||||
|
||||
void _remove() {
|
||||
@ -334,7 +336,7 @@ abstract class SkyElementWrapper extends SkyNodeWrapper {
|
||||
this.style,
|
||||
this.inlineStyle
|
||||
}) : this.children = children == null ? _emptyList : children,
|
||||
super(key:key) {
|
||||
super(key: key) {
|
||||
|
||||
assert(!_debugHasDuplicateIds());
|
||||
}
|
||||
@ -352,12 +354,11 @@ abstract class SkyElementWrapper extends SkyNodeWrapper {
|
||||
var idSet = new HashSet<String>();
|
||||
for (var child in children) {
|
||||
assert(child != null);
|
||||
if (child is Text) {
|
||||
continue; // Text nodes all have the same key and are never reordered.
|
||||
}
|
||||
if (child.interchangeable)
|
||||
continue; // when these nodes are reordered, we just reassign the data
|
||||
|
||||
if (!idSet.add(child._key)) {
|
||||
throw '''If multiple (non-Text) nodes of the same type exist as children
|
||||
throw '''If multiple non-interchangeable nodes of the same type exist as children
|
||||
of another node, they must have unique keys.
|
||||
Duplicate: "${child._key}"''';
|
||||
}
|
||||
@ -456,22 +457,21 @@ abstract class SkyElementWrapper extends SkyNodeWrapper {
|
||||
oldNodeIdMap = new HashMap<String, UINode>();
|
||||
for (int i = oldStartIndex; i < oldEndIndex; i++) {
|
||||
var node = oldChildren[i];
|
||||
if (node is! Text) {
|
||||
if (!node.interchangeable)
|
||||
oldNodeIdMap.putIfAbsent(node._key, () => node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool searchForOldNode() {
|
||||
if (currentNode is Text)
|
||||
return false; // Never re-order Text nodes.
|
||||
if (currentNode.interchangeable)
|
||||
return false; // never re-order these nodes
|
||||
|
||||
ensureOldIdMap();
|
||||
oldNode = oldNodeIdMap[currentNode._key];
|
||||
if (oldNode == null)
|
||||
return false;
|
||||
|
||||
oldNodeIdMap[currentNode._key] = null; // mark it reordered.
|
||||
oldNodeIdMap[currentNode._key] = null; // mark it reordered
|
||||
assert(_root is RenderCSSContainer);
|
||||
assert(oldNode._root is RenderCSSContainer);
|
||||
oldSkyElementWrapper._root.remove(oldNode._root);
|
||||
@ -520,7 +520,8 @@ abstract class SkyElementWrapper extends SkyNodeWrapper {
|
||||
|
||||
class Container extends SkyElementWrapper {
|
||||
|
||||
RenderCSS _createNode() => new RenderCSSContainer(this);
|
||||
RenderCSSContainer _root;
|
||||
RenderCSSContainer _createNode() => new RenderCSSContainer(this);
|
||||
|
||||
static final Container _emptyContainer = new Container();
|
||||
|
||||
@ -539,6 +540,28 @@ class Container extends SkyElementWrapper {
|
||||
);
|
||||
}
|
||||
|
||||
class Paragraph extends SkyElementWrapper {
|
||||
|
||||
RenderCSSParagraph _root;
|
||||
RenderCSSParagraph _createNode() => new RenderCSSParagraph(this);
|
||||
|
||||
static final Paragraph _emptyContainer = new Paragraph();
|
||||
|
||||
SkyNodeWrapper get _emptyNode => _emptyContainer;
|
||||
|
||||
Paragraph({
|
||||
Object key,
|
||||
List<UINode> children,
|
||||
Style style,
|
||||
String inlineStyle
|
||||
}) : super(
|
||||
key: key,
|
||||
children: children,
|
||||
style: style,
|
||||
inlineStyle: inlineStyle
|
||||
);
|
||||
}
|
||||
|
||||
class FlexContainer extends SkyElementWrapper {
|
||||
|
||||
RenderCSSFlex _root;
|
||||
@ -570,26 +593,23 @@ class FlexContainer extends SkyElementWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
class Text extends SkyElementWrapper {
|
||||
class TextFragment extends SkyElementWrapper {
|
||||
|
||||
RenderCSSText _root;
|
||||
RenderCSSText _createNode() => new RenderCSSText(this, this.data);
|
||||
RenderCSSInline _root;
|
||||
RenderCSSInline _createNode() => new RenderCSSInline(this, this.data);
|
||||
|
||||
static final Text _emptyText = new Text('');
|
||||
static final TextFragment _emptyText = new TextFragment('');
|
||||
|
||||
SkyNodeWrapper get _emptyNode => _emptyText;
|
||||
|
||||
final String data;
|
||||
|
||||
// Text nodes are special cases of having non-unique keys (which don't need
|
||||
// to be assigned as part of the API). Since they are unique in not having
|
||||
// children, there's little point to reordering, so we always just re-assign
|
||||
// the data.
|
||||
Text(this.data, {
|
||||
TextFragment(this.data, {
|
||||
Object key,
|
||||
Style style,
|
||||
String inlineStyle
|
||||
}) : super(
|
||||
key: '*text*',
|
||||
key: key,
|
||||
style: style,
|
||||
inlineStyle: inlineStyle
|
||||
);
|
||||
@ -615,7 +635,6 @@ class Image extends SkyElementWrapper {
|
||||
|
||||
Image({
|
||||
Object key,
|
||||
List<UINode> children,
|
||||
Style style,
|
||||
String inlineStyle,
|
||||
this.width,
|
||||
@ -623,7 +642,6 @@ class Image extends SkyElementWrapper {
|
||||
this.src
|
||||
}) : super(
|
||||
key: key,
|
||||
children: children,
|
||||
style: style,
|
||||
inlineStyle: inlineStyle
|
||||
);
|
||||
@ -737,7 +755,7 @@ abstract class Component extends UINode {
|
||||
Component({ Object key, bool stateful })
|
||||
: _stateful = stateful != null ? stateful : false,
|
||||
_order = _currentOrder + 1,
|
||||
super(key:key);
|
||||
super(key: key);
|
||||
|
||||
Component.fromArgs(Object key, bool stateful)
|
||||
: this(key: key, stateful: stateful);
|
||||
@ -861,3 +879,10 @@ abstract class App extends Component {
|
||||
_sync(null, _host, _root);
|
||||
}
|
||||
}
|
||||
|
||||
class Text extends Component {
|
||||
Text(this.data) : super(key: '*text*');
|
||||
final String data;
|
||||
bool get interchangeable => true;
|
||||
UINode build() => new Paragraph(children: [new TextFragment(data)]);
|
||||
}
|
||||
|
||||
@ -392,11 +392,9 @@ class RenderCSSFlex extends RenderCSSContainer {
|
||||
|
||||
}
|
||||
|
||||
class RenderCSSText extends RenderCSS {
|
||||
class RenderCSSParagraph extends RenderCSSContainer {
|
||||
|
||||
RenderCSSText(debug, String newData) : super(debug) {
|
||||
data = newData;
|
||||
}
|
||||
RenderCSSParagraph(debug) : super(debug);
|
||||
|
||||
static final Style _displayParagraph = new Style('display:paragraph');
|
||||
|
||||
@ -404,6 +402,20 @@ class RenderCSSText extends RenderCSS {
|
||||
return super.stylesToClasses(styles) + ' ' + _displayParagraph._className;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class RenderCSSInline extends RenderCSS {
|
||||
|
||||
RenderCSSInline(debug, String newData) : super(debug) {
|
||||
data = newData;
|
||||
}
|
||||
|
||||
static final Style _displayInline = new Style('display:inline');
|
||||
|
||||
String stylesToClasses(List<Style> styles) {
|
||||
return super.stylesToClasses(styles) + ' ' + _displayInline._className;
|
||||
}
|
||||
|
||||
sky.Element createSkyElement() {
|
||||
return sky.document.createElement('div')
|
||||
..setChild(new sky.Text())
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
<div debug="Instance of 'TestApp'">
|
||||
<div debug="Instance of 'Container'" class="" style="background-color: green">
|
||||
<div debug="Instance of 'Text'" class=" style1" style="">I am Text</div>
|
||||
<div debug="Instance of 'Paragraph'" class=" style1" style="">
|
||||
<div debug="Instance of 'TextFragment'" class=" style2" style="">I am Text</div>
|
||||
</div>
|
||||
<img debug="Instance of 'Image'" src="resources/united.jpg" class="" style=""></img>
|
||||
</div>
|
||||
</div><style>.style1 { display:paragraph }</style>
|
||||
</div>
|
||||
<style>.style1 { display:paragraph }</style>
|
||||
<style>.style2 { display:inline }</style>
|
||||
|
||||
|
||||
@ -8,7 +8,9 @@ import 'dart:sky.internals' as internals;
|
||||
void main() {
|
||||
new TestApp();
|
||||
runAfterDisplay(() {
|
||||
var result = serializeNode(document.lastChild.previousSibling) + serializeNode(document.lastChild);
|
||||
document.firstChild.remove();
|
||||
document.firstChild.remove();
|
||||
var result = serializeNode(document);
|
||||
try {
|
||||
internals.notifyTestComplete(result);
|
||||
} catch (e) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user