Skip to content

Commit 6c9b870

Browse files
committed
Implement Extension mechanism throughout core library
1 parent c5ee0bd commit 6c9b870

35 files changed

+2195
-2860
lines changed

lib/custom_render.dart

Lines changed: 0 additions & 549 deletions
This file was deleted.

lib/flutter_html.dart

Lines changed: 18 additions & 212 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,25 @@
11
library flutter_html;
22

33
import 'package:flutter/material.dart';
4-
import 'package:flutter_html/custom_render.dart';
5-
import 'package:flutter_html/html_parser.dart';
4+
import 'package:flutter_html/src/html_parser.dart';
5+
import 'package:flutter_html/src/extension/extension.dart';
66
import 'package:flutter_html/src/html_elements.dart';
7-
import 'package:flutter_html/style.dart';
7+
import 'package:flutter_html/src/style.dart';
88
import 'package:html/dom.dart' as dom;
99

10-
export 'package:flutter_html/custom_render.dart';
1110
//export render context api
12-
export 'package:flutter_html/html_parser.dart';
13-
//export render context api
14-
export 'package:flutter_html/html_parser.dart';
11+
export 'package:flutter_html/src/html_parser.dart';
1512
//export src for advanced custom render uses (e.g. casting context.tree)
1613
export 'package:flutter_html/src/anchor.dart';
17-
export 'package:flutter_html/src/interactable_element.dart';
18-
export 'package:flutter_html/src/layout_element.dart';
19-
export 'package:flutter_html/src/replaced_element.dart';
20-
export 'package:flutter_html/src/styled_element.dart';
21-
//export css_box_widget for use in custom render.
14+
export 'package:flutter_html/src/tree/interactable_element.dart';
15+
export 'package:flutter_html/src/tree/replaced_element.dart';
16+
export 'package:flutter_html/src/tree/styled_element.dart';
17+
//export css_box_widget for use in extensions.
2218
export 'package:flutter_html/src/css_box_widget.dart';
2319
//export style api
24-
export 'package:flutter_html/style.dart';
20+
export 'package:flutter_html/src/style.dart';
21+
//export extension api
22+
export 'package:flutter_html/src/extension/extension.dart';
2523

2624
class Html extends StatefulWidget {
2725
/// The `Html` widget takes HTML as input and displays a RichText
@@ -33,9 +31,6 @@ class Html extends StatefulWidget {
3331
///
3432
/// **onLinkTap** This function is called whenever a link (`<a href>`)
3533
/// is tapped.
36-
/// **customRender** This function allows you to return your own widgets
37-
/// for existing or custom HTML tags.
38-
/// See [its wiki page](https://github.com/Sub6Resources/flutter_html/wiki/All-About-customRender) for more info.
3934
///
4035
/// **onImageError** This is called whenever an image fails to load or
4136
/// display on the page.
@@ -55,7 +50,7 @@ class Html extends StatefulWidget {
5550
required this.data,
5651
this.onLinkTap,
5752
this.onAnchorTap,
58-
this.customRenders = const {},
53+
this.extensions = const [],
5954
this.onCssParseError,
6055
this.onImageError,
6156
this.shrinkWrap = false,
@@ -73,7 +68,7 @@ class Html extends StatefulWidget {
7368
@required dom.Document? document,
7469
this.onLinkTap,
7570
this.onAnchorTap,
76-
this.customRenders = const {},
71+
this.extensions = const [],
7772
this.onCssParseError,
7873
this.onImageError,
7974
this.shrinkWrap = false,
@@ -92,7 +87,7 @@ class Html extends StatefulWidget {
9287
@required this.documentElement,
9388
this.onLinkTap,
9489
this.onAnchorTap,
95-
this.customRenders = const {},
90+
this.extensions = const [],
9691
this.onCssParseError,
9792
this.onImageError,
9893
this.shrinkWrap = false,
@@ -136,9 +131,9 @@ class Html extends StatefulWidget {
136131
/// A list of HTML tags that are the only tags that are rendered. By default, this list is empty and all supported HTML tags are rendered.
137132
final List<String> tagsList;
138133

139-
/// Either return a custom widget for specific node types or return null to
140-
/// fallback to the default rendering.
141-
final Map<CustomRenderMatcher, CustomRender> customRenders;
134+
/// A list of [Extension]s that add additional capabilities to flutter_html
135+
/// See the [Extension] class for more details.
136+
final List<Extension> extensions;
142137

143138
/// An API that allows you to override the default style for any HTML element
144139
final Map<String, Style> style;
@@ -147,8 +142,6 @@ class Html extends StatefulWidget {
147142
..addAll(HtmlElements.interactableElements)
148143
..addAll(HtmlElements.replacedElements)
149144
..addAll(HtmlElements.layoutElements)
150-
..addAll(HtmlElements.tableCellElements)
151-
..addAll(HtmlElements.tableDefinitionElements)
152145
..addAll(HtmlElements.externalElements);
153146

154147
@override
@@ -188,196 +181,9 @@ class _HtmlState extends State<Html> {
188181
onCssParseError: widget.onCssParseError,
189182
onImageError: widget.onImageError,
190183
shrinkWrap: widget.shrinkWrap,
191-
selectable: false,
192184
style: widget.style,
193-
customRenders: {}
194-
..addAll(widget.customRenders)
195-
..addAll(generateDefaultRenders()),
185+
extensions: widget.extensions,
196186
tagsList: widget.tagsList.isEmpty ? Html.tags : widget.tagsList,
197187
);
198188
}
199189
}
200-
201-
class SelectableHtml extends StatefulWidget {
202-
/// The `SelectableHtml` widget takes HTML as input and displays a RichText
203-
/// tree of the parsed HTML content (which is selectable)
204-
///
205-
/// **Attributes**
206-
/// **data** *required* takes in a String of HTML data (required only for `Html` constructor).
207-
/// **documentElement** *required* takes in a Element of HTML data (required only for `Html.fromDom` and `Html.fromElement` constructor).
208-
///
209-
/// **onLinkTap** This function is called whenever a link (`<a href>`)
210-
/// is tapped.
211-
///
212-
/// **onAnchorTap** This function is called whenever an anchor (#anchor-id)
213-
/// is tapped.
214-
///
215-
/// **tagsList** Tag names in this array will be the only tags rendered. By default, all tags that support selectable content are rendered.
216-
///
217-
/// **style** Pass in the style information for the Html here.
218-
/// See [its wiki page](https://github.com/Sub6Resources/flutter_html/wiki/Style) for more info.
219-
///
220-
/// **PLEASE NOTE**
221-
///
222-
/// There are a few caveats due to Flutter [#38474](https://github.com/flutter/flutter/issues/38474):
223-
///
224-
/// 1. The list of tags that can be rendered is significantly reduced.
225-
/// Key omissions include no support for images/video/audio, table, and ul/ol because they all require widgets and `WidgetSpan`s.
226-
///
227-
/// 2. No support for `customRender`, `customImageRender`, `onImageError`, `onImageTap`, `onMathError`, and `navigationDelegateForIframe`.
228-
///
229-
/// 3. Styling support is significantly reduced. Only text-related styling works
230-
/// (e.g. bold or italic), while container related styling (e.g. borders or padding/margin)
231-
/// do not work because we can't use the `ContainerSpan` class (it needs an enclosing `WidgetSpan`).
232-
233-
SelectableHtml({
234-
Key? key,
235-
GlobalKey? anchorKey,
236-
required this.data,
237-
this.onLinkTap,
238-
this.onAnchorTap,
239-
this.onCssParseError,
240-
this.shrinkWrap = false,
241-
this.style = const {},
242-
this.customRenders = const {},
243-
this.tagsList = const [],
244-
this.selectionControls,
245-
this.scrollPhysics,
246-
}) : documentElement = null,
247-
assert(data != null),
248-
_anchorKey = anchorKey ?? GlobalKey(),
249-
super(key: key);
250-
251-
SelectableHtml.fromDom({
252-
Key? key,
253-
GlobalKey? anchorKey,
254-
@required dom.Document? document,
255-
this.onLinkTap,
256-
this.onAnchorTap,
257-
this.onCssParseError,
258-
this.shrinkWrap = false,
259-
this.style = const {},
260-
this.customRenders = const {},
261-
this.tagsList = const [],
262-
this.selectionControls,
263-
this.scrollPhysics,
264-
}) : data = null,
265-
assert(document != null),
266-
documentElement = document!.documentElement,
267-
_anchorKey = anchorKey ?? GlobalKey(),
268-
super(key: key);
269-
270-
SelectableHtml.fromElement({
271-
Key? key,
272-
GlobalKey? anchorKey,
273-
@required this.documentElement,
274-
this.onLinkTap,
275-
this.onAnchorTap,
276-
this.onCssParseError,
277-
this.shrinkWrap = false,
278-
this.style = const {},
279-
this.customRenders = const {},
280-
this.tagsList = const [],
281-
this.selectionControls,
282-
this.scrollPhysics,
283-
}) : data = null,
284-
assert(documentElement != null),
285-
_anchorKey = anchorKey ?? GlobalKey(),
286-
super(key: key);
287-
288-
/// A unique key for this Html widget to ensure uniqueness of anchors
289-
final GlobalKey _anchorKey;
290-
291-
/// The HTML data passed to the widget as a String
292-
final String? data;
293-
294-
/// The HTML data passed to the widget as a pre-processed [dom.Element]
295-
final dom.Element? documentElement;
296-
297-
/// A function that defines what to do when a link is tapped
298-
final OnTap? onLinkTap;
299-
300-
/// A function that defines what to do when an anchor link is tapped. When this value is set,
301-
/// the default anchor behaviour is overwritten.
302-
final OnTap? onAnchorTap;
303-
304-
/// A function that defines what to do when CSS fails to parse
305-
final OnCssParseError? onCssParseError;
306-
307-
/// A parameter that should be set when the HTML widget is expected to be
308-
/// have a flexible width, that doesn't always fill its maximum width
309-
/// constraints. For example, auto horizontal margins are ignored, and
310-
/// block-level elements only take up the width they need.
311-
final bool shrinkWrap;
312-
313-
/// A list of HTML tags that are the only tags that are rendered. By default, this list is empty and all supported HTML tags are rendered.
314-
final List<String> tagsList;
315-
316-
/// An API that allows you to override the default style for any HTML element
317-
final Map<String, Style> style;
318-
319-
/// Custom Selection controls allows you to override default toolbar and build custom toolbar
320-
/// options
321-
final TextSelectionControls? selectionControls;
322-
323-
/// Allows you to override the default scrollPhysics for [SelectableText.rich]
324-
final ScrollPhysics? scrollPhysics;
325-
326-
/// Either return a custom widget for specific node types or return null to
327-
/// fallback to the default rendering.
328-
final Map<CustomRenderMatcher, SelectableCustomRender> customRenders;
329-
330-
static List<String> get tags =>
331-
List<String>.from(HtmlElements.selectableElements);
332-
333-
@override
334-
State<StatefulWidget> createState() => _SelectableHtmlState();
335-
}
336-
337-
class _SelectableHtmlState extends State<SelectableHtml> {
338-
late dom.Element documentElement;
339-
340-
@override
341-
void initState() {
342-
super.initState();
343-
documentElement = widget.data != null
344-
? HtmlParser.parseHTML(widget.data!)
345-
: widget.documentElement!;
346-
}
347-
@override
348-
void didUpdateWidget(SelectableHtml oldWidget) {
349-
super.didUpdateWidget(oldWidget);
350-
if ((widget.data != null && oldWidget.data != widget.data) ||
351-
oldWidget.documentElement != widget.documentElement) {
352-
documentElement = widget.data != null
353-
? HtmlParser.parseHTML(widget.data!)
354-
: widget.documentElement!;
355-
}
356-
}
357-
358-
@override
359-
Widget build(BuildContext context) {
360-
return SizedBox(
361-
width: widget.shrinkWrap ? null : MediaQuery.of(context).size.width,
362-
child: HtmlParser(
363-
key: widget._anchorKey,
364-
htmlData: documentElement,
365-
onLinkTap: widget.onLinkTap,
366-
onAnchorTap: widget.onAnchorTap,
367-
onImageTap: null,
368-
onCssParseError: widget.onCssParseError,
369-
onImageError: null,
370-
shrinkWrap: widget.shrinkWrap,
371-
selectable: true,
372-
style: widget.style,
373-
customRenders: {}
374-
..addAll(widget.customRenders)
375-
..addAll(generateDefaultRenders()),
376-
tagsList:
377-
widget.tagsList.isEmpty ? SelectableHtml.tags : widget.tagsList,
378-
selectionControls: widget.selectionControls,
379-
scrollPhysics: widget.scrollPhysics,
380-
),
381-
);
382-
}
383-
}

0 commit comments

Comments
 (0)