Skip to content

Commit ee8b56f

Browse files
committed
Initial support for Flutter Web - support iframes
1 parent 10b3726 commit ee8b56f

File tree

5 files changed

+144
-40
lines changed

5 files changed

+144
-40
lines changed

lib/src/replaced_element.dart

Lines changed: 3 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ import 'dart:math';
33
import 'package:chewie/chewie.dart';
44
import 'package:chewie_audio/chewie_audio.dart';
55
import 'package:flutter/foundation.dart';
6-
import 'package:flutter/gestures.dart';
76
import 'package:flutter/material.dart';
87
import 'package:flutter/widgets.dart';
98
import 'package:flutter_html/html_parser.dart';
109
import 'package:flutter_html/src/html_elements.dart';
1110
import 'package:flutter_html/src/utils.dart';
11+
import 'package:flutter_html/src/widgets/iframe_unsupported.dart'
12+
if (dart.library.io) 'package:flutter_html/src/widgets/iframe_mobile.dart'
13+
if (dart.library.html) 'package:flutter_html/src/widgets/iframe_web.dart';
1214
import 'package:flutter_html/style.dart';
1315
import 'package:flutter_svg/flutter_svg.dart';
1416
import 'package:html/dom.dart' as dom;
@@ -100,45 +102,6 @@ class ImageContentElement extends ReplacedElement {
100102
}
101103
}
102104

103-
/// [IframeContentElement is a [ReplacedElement] with web content.
104-
class IframeContentElement extends ReplacedElement {
105-
final String src;
106-
final double width;
107-
final double height;
108-
final NavigationDelegate navigationDelegate;
109-
final UniqueKey key = UniqueKey();
110-
111-
IframeContentElement({
112-
String name,
113-
Style style,
114-
this.src,
115-
this.width,
116-
this.height,
117-
dom.Element node,
118-
this.navigationDelegate,
119-
}) : super(name: name, style: style, node: node);
120-
121-
@override
122-
Widget toWidget(RenderContext context) {
123-
final sandboxMode = attributes["sandbox"];
124-
return Container(
125-
width: width ?? (height ?? 150) * 2,
126-
height: height ?? (width ?? 300) / 2,
127-
child: WebView(
128-
initialUrl: src,
129-
key: key,
130-
javascriptMode: sandboxMode == null || sandboxMode == "allow-scripts"
131-
? JavascriptMode.unrestricted
132-
: JavascriptMode.disabled,
133-
navigationDelegate: navigationDelegate,
134-
gestureRecognizers: {
135-
Factory<VerticalDragGestureRecognizer>(() => VerticalDragGestureRecognizer())
136-
},
137-
),
138-
);
139-
}
140-
}
141-
142105
/// [AudioContentElement] is a [ContentElement] with an audio file as its content.
143106
class AudioContentElement extends ReplacedElement {
144107
final List<String> src;

lib/src/utils.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import 'package:flutter/gestures.dart';
22

3+
import 'dart:math';
4+
import 'dart:convert';
5+
36
class Context<T> {
47
T data;
58

@@ -43,3 +46,9 @@ class MultipleTapGestureRecognizer extends TapGestureRecognizer {
4346
}
4447
}
4548
}
49+
50+
String getRandString(int len) {
51+
var random = Random.secure();
52+
var values = List<int>.generate(len, (i) => random.nextInt(255));
53+
return base64UrlEncode(values);
54+
}

lib/src/widgets/iframe_mobile.dart

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import 'package:flutter/foundation.dart';
2+
import 'package:flutter/gestures.dart';
3+
import 'package:flutter/material.dart';
4+
import 'package:flutter_html/html_parser.dart';
5+
import 'package:flutter_html/src/replaced_element.dart';
6+
import 'package:flutter_html/style.dart';
7+
import 'package:webview_flutter/webview_flutter.dart';
8+
import 'package:html/dom.dart' as dom;
9+
10+
/// [IframeContentElement is a [ReplacedElement] with web content.
11+
class IframeContentElement extends ReplacedElement {
12+
final String src;
13+
final double width;
14+
final double height;
15+
final NavigationDelegate navigationDelegate;
16+
final UniqueKey key = UniqueKey();
17+
18+
IframeContentElement({
19+
String name,
20+
Style style,
21+
this.src,
22+
this.width,
23+
this.height,
24+
dom.Element node,
25+
this.navigationDelegate,
26+
}) : super(name: name, style: style, node: node);
27+
28+
@override
29+
Widget toWidget(RenderContext context) {
30+
final sandboxMode = attributes["sandbox"];
31+
return Container(
32+
width: width ?? (height ?? 150) * 2,
33+
height: height ?? (width ?? 300) / 2,
34+
child: WebView(
35+
initialUrl: src,
36+
key: key,
37+
javascriptMode: sandboxMode == null || sandboxMode == "allow-scripts"
38+
? JavascriptMode.unrestricted
39+
: JavascriptMode.disabled,
40+
navigationDelegate: navigationDelegate,
41+
gestureRecognizers: {
42+
Factory<VerticalDragGestureRecognizer>(() => VerticalDragGestureRecognizer())
43+
},
44+
),
45+
);
46+
}
47+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_html/html_parser.dart';
3+
import 'package:flutter_html/src/replaced_element.dart';
4+
import 'package:flutter_html/style.dart';
5+
import 'package:webview_flutter/webview_flutter.dart';
6+
import 'package:html/dom.dart' as dom;
7+
8+
/// [IframeContentElement is a [ReplacedElement] with web content.
9+
class IframeContentElement extends ReplacedElement {
10+
final String src;
11+
final double width;
12+
final double height;
13+
final NavigationDelegate navigationDelegate;
14+
final UniqueKey key = UniqueKey();
15+
16+
IframeContentElement({
17+
String name,
18+
Style style,
19+
this.src,
20+
this.width,
21+
this.height,
22+
dom.Element node,
23+
this.navigationDelegate,
24+
}) : super(name: name, style: style, node: node);
25+
26+
@override
27+
Widget toWidget(RenderContext context) {
28+
return Container(
29+
width: width ?? (height ?? 150) * 2,
30+
height: height ?? (width ?? 300) / 2,
31+
child: Text("Iframes are currently not supported in this environment"),
32+
);
33+
}
34+
}

lib/src/widgets/iframe_web.dart

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_html/html_parser.dart';
3+
import 'package:flutter_html/src/replaced_element.dart';
4+
import 'package:flutter_html/src/utils.dart';
5+
import 'package:flutter_html/style.dart';
6+
import 'package:webview_flutter/webview_flutter.dart';
7+
import 'package:html/dom.dart' as dom;
8+
// ignore: avoid_web_libraries_in_flutter
9+
import 'dart:html' as html;
10+
import 'dart:ui' as ui;
11+
12+
/// [IframeContentElement is a [ReplacedElement] with web content.
13+
class IframeContentElement extends ReplacedElement {
14+
final String src;
15+
final double width;
16+
final double height;
17+
final NavigationDelegate navigationDelegate;
18+
final UniqueKey key = UniqueKey();
19+
final String createdViewId = getRandString(10);
20+
21+
IframeContentElement({
22+
String name,
23+
Style style,
24+
this.src,
25+
this.width,
26+
this.height,
27+
dom.Element node,
28+
this.navigationDelegate,
29+
}) : super(name: name, style: style, node: node);
30+
31+
@override
32+
Widget toWidget(RenderContext context) {
33+
final html.IFrameElement iframe = html.IFrameElement()
34+
..width = (width ?? (height ?? 150) * 2).toString()
35+
..height = (height ?? (width ?? 300) / 2).toString()
36+
..src = src
37+
..style.border = 'none';
38+
//not actually an error
39+
ui.platformViewRegistry.registerViewFactory(createdViewId, (int viewId) => iframe);
40+
return Container(
41+
width: width ?? (height ?? 150) * 2,
42+
height: height ?? (width ?? 300) / 2,
43+
child: Directionality(
44+
textDirection: TextDirection.ltr,
45+
child: HtmlElementView(
46+
viewType: createdViewId,
47+
)
48+
)
49+
);
50+
}
51+
}

0 commit comments

Comments
 (0)