[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:
Hixie 2015-05-14 15:21:29 -07:00
parent 68624e8042
commit 9466cbbcb4
6 changed files with 85 additions and 46 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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