daohoangson / flutter_widget_from_html

Flutter package to render html as widgets that supports hyperlink, image, audio, video, iframe and many other tags.
https://pub.dev/packages/flutter_widget_from_html
MIT License
641 stars 240 forks source link

display embeded tweets and instagram posts #23

Closed ahmadkhedr closed 5 years ago

ahmadkhedr commented 5 years ago

embedded tweets do not display the tweet itself, but display just the content of the tweet itself without the frame of the tweeter platform and after clicking on it, it directs me to the default browser to display the full tweet...Instagram, on the other hand, shows me "View the post on Instagram " which suppose to display the whole content after clicking on it but it does nothing at all

instagram example:

` HtmlWidget(

   <p><blockquote class=\"instagram-media\" data-instgrm-captioned=\"\" data-instgrm-         permalink=\"https://www.instagram.com/p/BtVoEMVlVLu/?utm_source=ig_embed&amp;utm_medium=loading\" data-instgrm-version=\"12\" style=\" background:#FFF; border:0; border-radius:3px; box-shadow:0 0 1px 0 rgba(0,0,0,0.5),0 1px 10px 0 rgba(0,0,0,0.15); margin: 1px; max-width:540px; min-width:326px; padding:0; width:99.375%; width:-webkit-calc(100% - 2px); width:calc(100% - 2px);\"><div style=\"padding:16px;\"> <a href=\"https://www.instagram.com/p/BtVoEMVlVLu/?utm_source=ig_embed&amp;utm_medium=loading\" style=\" background:#FFFFFF; line-height:0; padding:0 0; text-align:center; text-decoration:none; width:100%;\" target=\"_blank\"> </a><div style=\"padding: 19% 0;\"><a href=\"https://www.instagram.com/p/BtVoEMVlVLu/?utm_source=ig_embed&amp;utm_medium=loading\" style=\" background:#FFFFFF; line-height:0; padding:0 0; text-align:center; text-decoration:none; width:100%;\" target=\"_blank\"></a></div><div style=\"display:block; height:50px; margin:0 auto 12px; width:50px;\"><a href=\"https://www.instagram.com/p/BtVoEMVlVLu/?utm_source=ig_embed&amp;utm_medium=loading\" style=\" background:#FFFFFF; line-height:0; padding:0 0; text-align:center; text-decoration:none; width:100%;\" target=\"_blank\"><svg width=\"50px\" height=\"50px\" viewBox=\"0 0 60 60\" version=\"1.1\" xmlns=\"https://www.w3.org/2000/svg\" xmlns:xlink=\"https://www.w3.org/1999/xlink\"><g stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\"><g transform=\"translate(-511.000000, -20.000000)\" fill=\"#000000\"><g><divath d=\"M556.869,30.41 C554.814,30.41 553.148,32.076 553.148,34.131 C553.148,36.186 554.814,37.852 556.869,37.852 C558.924,37.852 560.59,36.186 560.59,34.131 C560.59,32.076 558.924,30.41 556.869,30.41 M541,60.657 C535.114,60.657 530.342,55.887 530.342,50 C530.342,44.114 535.114,39.342 541,39.342 C546.887,39.342 551.658,44.114 551.658,50 C551.658,55.887 546.887,60.657 541,60.657 M541,33.886 C532.1,33.886 524.886,41.1 524.886,50 C524.886,58.899 532.1,66.113 541,66.113 C549.9,66.113 557.115,58.899 557.115,50 C557.115,41.1 549.9,33.886 541,33.886 M565.378,62.101 C565.244,65.022 564.756,66.606 564.346,67.663 C563.803,69.06 563.154,70.057 562.106,71.106 C561.058,72.155 560.06,72.803 558.662,73.347 C557.607,73.757 556.021,74.244 553.102,74.378 C549.944,74.521 548.997,74.552 541,74.552 C533.003,74.552 532.056,74.521 528.898,74.378 C525.979,74.244 524.393,73.757 523.338,73.347 C521.94,72.803 520.942,72.155 519.894,71.106 C518.846,70.057 518.197,69.06 517.654,67.663 C517.244,66.606 516.755,65.022 516.623,62.101 C516.479,58.943 516.448,57.996 516.448,50 C516.448,42.003 516.479,41.056 516.623,37.899 C516.755,34.978 517.244,33.391 517.654,32.338 C518.197,30.938 518.846,29.942 519.894,28.894 C520.942,27.846 521.94,27.196 523.338,26.654 C524.393,26.244 525.979,25.756 528.898,25.623 C532.057,25.479 533.004,25.448 541,25.448 C548.997,25.448 549.943,25.479 553.102,25.623 C556.021,25.756 557.607,26.244 558.662,26.654 C560.06,27.196 561.058,27.846 562.106,28.894 C563.154,29.942 563.803,30.938 564.346,32.338 C564.756,33.391 565.244,34.978 565.378,37.899 C565.522,41.056 565.552,42.003 565.552,50 C565.552,57.996 565.522,58.943 565.378,62.101 M570.82,37.631 C570.674,34.438 570.167,32.258 569.425,30.349 C568.659,28.377 567.633,26.702 565.965,25.035 C564.297,23.368 562.623,22.342 560.652,21.575 C558.743,20.834 556.562,20.326 553.369,20.18 C550.169,20.033 549.148,20 541,20 C532.853,20 531.831,20.033 528.631,20.18 C525.438,20.326 523.257,20.834 521.349,21.575 C519.376,22.342 517.703,23.368 516.035,25.035 C514.368,26.702 513.342,28.377 512.574,30.349 C511.834,32.258 511.326,34.438 511.181,37.631 C511.035,40.831 511,41.851 511,50 C511,58.147 511.035,59.17 511.181,62.369 C511.326,65.562 511.834,67.743 512.574,69.651 C513.342,71.625 514.368,73.296 516.035,74.965 C517.703,76.634 519.376,77.658 521.349,78.425 C523.257,79.167 525.438,79.673 528.631,79.82 C531.831,79.965 532.853,80.001 541,80.001 C549.148,80.001 550.169,79.965 553.369,79.82 C556.562,79.673 558.743,79.167 560.652,78.425 C562.623,77.658 564.297,76.634 565.965,74.965 C567.633,73.296 568.659,71.625 569.425,69.651 C570.167,67.743 570.674,65.562 570.82,62.369 C570.966,59.17 571,58.147 571,50 C571,41.851 570.966,40.831 570.82,37.631\"></divath></g></g></g></svg></a></div><div style=\"padding-top: 8px;\"><a href=\"https://www.instagram.com/p/BtVoEMVlVLu/?utm_source=ig_embed&amp;utm_medium=loading\" style=\" background:#FFFFFF; line-height:0; padding:0 0; text-align:center; text-decoration:none; width:100%;\" target=\"_blank\"> <div style=\" color:#3897f0; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:550; line-height:18px;\"> View this post on Instagram</div></a></div><div style=\"padding: 12.5% 0;\"><a href=\"https://www.instagram.com/p/BtVoEMVlVLu/?utm_source=ig_embed&amp;utm_medium=loading\" style=\" background:#FFFFFF; line-height:0; padding:0 0; text-align:center; text-decoration:none; width:100%;\" target=\"_blank\"></a></div><div style=\"display: flex; flex-direction: row; margin-bottom: 14px; align-items: center;\"><a href=\"https://www.instagram.com/p/BtVoEMVlVLu/?utm_source=ig_embed&amp;utm_medium=loading\" style=\" background:#FFFFFF; line-height:0; padding:0 0; text-align:center; text-decoration:none; width:100%;\" target=\"_blank\"><div> <div style=\"background-color: #F4F4F4; border-radius: 50%; height: 12.5px; width: 12.5px; transform: translateX(0px) translateY(7px);\"></div> <div style=\"background-color: #F4F4F4; height: 12.5px; transform: rotate(-45deg) translateX(3px) translateY(1px); width: 12.5px; flex-grow: 0; margin-right: 14px; margin-left: 2px;\"></div> <div style=\"background-color: #F4F4F4; border-radius: 50%; height: 12.5px; width: 12.5px; transform: translateX(9px) translateY(-18px);\"></div></div><div style=\"margin-left: 8px;\"> <div style=\" background-color: #F4F4F4; border-radius: 50%; flex-grow: 0; height: 20px; width: 20px;\"></div> <div style=\" width: 0; height: 0; border-top: 2px solid transparent; border-left: 6px solid #f4f4f4; border-bottom: 2px solid transparent; transform: translateX(16px) translateY(-4px) rotate(30deg)\"></div></div><div style=\"margin-left: auto;\"> <div style=\" width: 0px; border-top: 8px solid #F4F4F4; border-right: 8px solid transparent; transform: translateY(16px);\"></div> <div style=\" background-color: #F4F4F4; flex-grow: 0; height: 12px; width: 16px; transform: translateY(-4px);\"></div> <div style=\" width: 0; height: 0; border-top: 8px solid #F4F4F4; border-left: 8px solid transparent; transform: translateY(-4px) translateX(8px);\"></div></div></a></div> <div style=\" margin:8px 0 0 0; padding:0 4px;\"> <a href=\"https://www.instagram.com/p/BtVoEMVlVLu/?utm_source=ig_embed&amp;utm_medium=loading\" style=\" color:#000; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:normal; line-height:17px; text-decoration:none; word-wrap:break-word;\" target=\"_blank\">بسم الله توكلنا على الله والله المستعان واللهم صلى وسلم وبارك على محمد وعلى اله وصحبه وربنا يتمها على خير ويكملها بالستر #سبع_البرمبه .. قريبا #رامز_جلال #RamezGalal</a></div> <div style=\" color:#c9c8cd; font-family:Arial,sans-serif; font-size:14px; line-height:17px; margin-bottom:0; margin-top:8px; overflow:hidden; padding:8px 0 7px; text-align:center; text-overflow:ellipsis; white-space:nowrap;\">A post shared by <a href=\"https://www.instagram.com/ramezgalalac/?utm_source=ig_embed&amp;utm_medium=loading\" style=\" color:#c9c8cd; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:normal; line-height:17px;\" target=\"_blank\"> Ramez Galal</a> (@ramezgalalac) on <time style=\" font-family:Arial,sans-serif; font-size:14px; line-height:17px;\" datetime=\"2019-02-01T11:44:09+00:00\">Feb 1, 2019 at 3:44am PST</time></div></div></blockquote> <script async=\"\" src=\"//www.instagram.com/embed.js\"></script></p>,

config: Config( webView: true, webViewJs: true, ), ),"`

instagram post from real device: insta

twitter example: ` HtmlWidget(

<blockquote class=\"twitter-tweet\" data-lang=\"en\"><div lang=\"en\" dir=\"ltr \">Nature’s flash ⚡ <a href=\"https://twitter.com/hashtag/Dubai?src=hash&amp;ref_src=twsrc%5Etfw\">#Dubai <a href=\"https://twitter.com/hashtag/Lightning?src=hash&amp;ref_src=twsrc%5Etfw\">#Lightning <a href=\"https://twitter.com/hashtag/Thunder?src=hash&amp;ref_src=twsrc%5Etfw\">#Thunder <a href=\"https://twitter.com/hashtag/Slowmotion?src=hash&amp;ref_src=twsrc%5Etfw\">#Slowmotion <a href=\"https://t.co/B9V6r49cAJ\">pic.twitter.com/B9V6r49cAJ

— Hamdan bin Mohammed (@HamdanMohammed) <a href=\"https://twitter.com/HamdanMohammed/status/1117123818642989057?ref_src=twsrc%5Etfw\">April 13, 2019\n<script async=\"\" src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\">\n

,

config: Config( webView: true, webViewJs: true, ), ), "`

twitetr post from real device:

twitter

I thought it was usual to display in this way until I saw the same api being used in ios device using xcode and not flutter as follows :

-Embeded twitter:

iostwitter

-View this post on instagram :

iosinst1

-After clicking on "view this post on instagram " :

iosinsta2

==Is this usual or there some thing missing in the plugin?

daohoangson commented 5 years ago

This is expected. This plugin render the html without Javascript as Flutter widgets. In your other screenshots, it looks like they were running in a WebView with full Javascript pipeline.

ahmadkhedr commented 5 years ago

This is expected. This plugin render the html without Javascript as Flutter widgets. In your other screenshots, it looks like they were running in a WebView with full Javascript pipeline.

so there is no way to render the HTML on the same way using this plugin?....I have tried it now on webview_flutter: ^0.3.5+3 and it render it like the photo I attached, but I want to continue using this plugin

daohoangson commented 5 years ago

No, there is no way to execute Javascript in Dart (that I know of). If you want to render rich embedded content, you have to use Web View. It will be nicer with some performance hit.

ahmadkhedr commented 5 years ago

Hello again =D When I was checking the app an embedded Facebook post was displayed and it was rendered more than fine....when I returned to the HTML content which includes the post I found it was inside an Iframe tag and I have a suggestion.....when all the embedded Twitter and Instagram posts are inside a blockquote tag and since you have implied that any iframe should be displayed inside a webview...Why do not you apply the same for blockquote and make them render inside a webview as well and by that it will be displayed like the content inside an iframe? I do not know whether it can be applied or not...but if it worked it would be awesome :)

facebook embedded post content : <iframe src=\"https://www.facebook.com/plugins/post.php?href=https%3A%2F%2Fwww.facebook.com%2FOfficialSherine%2Fposts%2F1578853685578024&amp;width=500\" width=\"500\" height=\"291\" scrolling=\"no\" frameborder=\"0\" allowtransparency=\"true\" allow=\"encrypted-media\" style=\"border-width: initial; border-style: none; overflow: hidden;\"></iframe>

Screen shot of the embeded facebook post : Screenshot_1556449041

Best of luck! 👍

daohoangson commented 5 years ago

Why do not you apply the same for blockquote and make them render inside a webview as well and by that it will be displayed like the content inside an iframe?

That would work for your use case but doesn't look good for others. A blockquote can be text only, that would be wasteful to always use web view for it.

You can extend WidgetFactory to always use web view for blockquotes in your app though.

ahmadkhedr commented 5 years ago

You can extend WidgetFactory to always use web view for blockquotes in your app though.

I am a beginner in the field.....Is there any tutorial or example showing me how to implement it in my app?

ahmadkhedr commented 5 years ago

You can extend WidgetFactory to always use web view for blockquotes in your app thou

I have created a file inside the "ops" Directory and named it "tag_blockquote.dart" and copied the code inside "tag_iframe.dart" and modified it as follows :

`

  import 'package:flutter/widgets.dart';
import 'package:html/dom.dart' as dom;
import '../widget_factory.dart';

    class TagBlockquote  {
   final WidgetFactory wf;

  TagBlockquote(this.wf);

Widget build(dom.Element e) {
final a = e.attributes;
if (!a.containsKey('src')) return null;

       final config = wf.config;
      final src = buildFullUrl(a['src'], config.baseUrl);
      if (src == null) return null;
      if (!config.webView) return wf.buildWebViewLinkOnly(src);

   return wf.buildWebView(
    src,
  height: a.containsKey("height") ? double.tryParse(a["height"]) : null,
  width: a.containsKey("width") ? double.tryParse(a["width"]) : null,
  );
    }
   }

`
and modified file "widget_factory.dart" as follows :

  `import 'package:cached_network_image/cached_network_image.dart';

import 'package:flutter/material.dart'; import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart' as core; import 'package:html/dom.dart' as dom; import 'package:webview_flutter/webview_flutter.dart';

import 'ops/tag_a.dart'; import 'ops/tag_iframe.dart'; import 'ops/tag_blockquote.dart'; import 'ops/tag_li.dart'; import 'config.dart';

final _baseUriTrimmingRegExp = RegExp(r'/+$'); final _isFullUrlRegExp = RegExp(r'^(https?://|mailto:|tel:)');

String buildFullUrl(String url, Uri baseUrl) { if (url?.isNotEmpty != true) return null; if (url.startsWith(_isFullUrlRegExp)) return url; if (baseUrl == null) return null;

if (url.startsWith('//')) { return "${baseUrl.scheme}:$url"; }

if (url.startsWith('/')) { return baseUrl.scheme + '://' + baseUrl.host + (baseUrl.hasPort ? ":${baseUrl.port}" : '') + url; }

return "${baseUrl.toString().replaceAll(_baseUriTrimmingRegExp, '')}/$url"; }

Widget wrapPadding(Widget widget, EdgeInsets padding) => (widget != null && padding != null && padding.top + padding.right + padding.bottom + padding.left > 0) ? Padding(padding: padding, child: widget) : widget;

class WidgetFactory extends core.WidgetFactory { final Config config;

WidgetFactory(BuildContext context, this.config) : super(context);

@override Widget buildImageWidget(String src, {int height, int width}) => wrapPadding( super.buildImageWidget(src, height: height, width: width), config.imagePadding, );

@override Widget buildImageWidgetFromUrl(String url) { final imageUrl = buildFullUrl(url, config.baseUrl); if (imageUrl?.isEmpty != false) return null;

return CachedNetworkImage(
  imageUrl: imageUrl,
  fit: BoxFit.cover,
);

}

@override Widget buildTextWidget(text, {TextAlign textAlign}) => wrapPadding( super.buildTextWidget(text, textAlign: textAlign), config.textPadding, );

Widget buildWebView( String initialUrl, { double height, double width, }) => wrapPadding( AspectRatio( aspectRatio: (height != null && height > 0 && width != null && width > 0) ? (width / height) : (16 / 9), child: WebView( initialUrl: initialUrl, javascriptMode: config.webViewJs ? JavascriptMode.unrestricted : JavascriptMode.disabled), ), config.webViewPadding, );

Widget buildWebViewLinkOnly(String url) => TagA(url, this, icon: false) .onPieces([ core.BuiltPieceSimple(widgets: [buildTextWidget(url)]), ]) .first ?.widgets ?.first;

@override core.NodeMetadata parseElement(dom.Element e) { var meta = super.parseElement(e);

switch (e.localName) {
  case 'a':
    meta = core.lazySet(meta, color: Theme.of(context).accentColor);

    if (e.attributes.containsKey('href')) {
      final href = e.attributes['href'];
      final fullUrl = buildFullUrl(href, config.baseUrl);
      if (fullUrl?.isNotEmpty == true) {
        meta = core.lazySet(meta, buildOp: tagA(fullUrl));
      }
    }
    break;

  case 'iframe':
    meta = core.lazySet(
      meta,
      buildOp: tagIframe(e),
      isNotRenderable: false,
    );
    break;

  case 'blockquote':
    meta = core.lazySet(
      meta,
      buildOp: tagBlockquote(e),
      isNotRenderable: false,
    );
    break;

  case 'li':
  case 'ol':
  case 'ul':
    meta = core.lazySet(null, buildOp: tagLi(e.localName));
    break;
}

return meta;

}

core.BuildOp tagA(String fullUrl) => core.BuildOp( onPieces: TagA(fullUrl, this).onPieces, );

core.BuildOp tagIframe(dom.Element e) => core.BuildOp(onWidgets: (_) => [TagIframe(this).build(e)]);

core.BuildOp tagBlockquote (dom.Element e) => core.BuildOp(onWidgets: (_) => [TagBlockquote(this).build(e)]);

core.BuildOp tagLi(String tag) => core.BuildOp( onWidgets: (widgets) => [TagLi(this).build(widgets, tag)], ); } ` and after "flutter packages get" and hot reloading the app, all Blockquotes content has disappeared....what should I do or change to make Blockquote content dispaly inside a webview?

daohoangson commented 5 years ago

I'm releasing a new version later today or tomorrow. I will give you a working example for 0.2.0 afterwards, is that okie? Because this version moves thing around a bit so if I give you sample code right now, it won't work with the new version.

ahmadkhedr commented 5 years ago

is that okie?

It will be great....Thanks for your help :)

daohoangson commented 5 years ago

I have this example code for v0.2.0 v0.2.1, it will render all BLOCKQUOTE in web view:

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
import 'package:html/dom.dart' as dom;

class BlockquoteWebViewScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(
          title: Text('BlockquoteWebViewScreen'),
        ),
        body: ListView(children: <Widget>[
          HtmlWidget(
            html,
            wf: _BlockquoteWebViewWf(),
          ),
        ]),
      );
}

class _BlockquoteWebViewWf extends WidgetFactory {
  final buildOp = BuildOp(
    onWidgets: (meta, _) => [
          WebView(
            Uri.dataFromString(
              meta.domElement.innerHtml,
              mimeType: 'text/html',
              encoding: Encoding.getByName('utf-8'),
            ).toString(),
            aspectRatio: 16 / 9,
            getDimensions: true,
          )
        ],
  );

  @override
  NodeMetadata parseElement(NodeMetadata meta, dom.Element e) {
    switch (e.localName) {
      case 'blockquote':
        return lazySet(null, buildOp: buildOp);
    }

    return super.parseElement(meta, e);
  }
}
ahmadkhedr commented 5 years ago

I have this example code for v0.2.0, it will render all BLOCKQUOTE in web view:

after adding this code to the class...the web view stopped rendering the iframes and the if the content contains any images it does not show it anymore....If I disable "wf: _BlockquoteWebViewWf()," the iframes and images start to display again without any problem

exapmle of the html code :

"

وأحال المستشار ناصر الدهشان، المحامي العام الأول لنيابات استئناف الإسكندرية، المتهمين الراهب إشعياء المقاري والراهب فلتاؤس المقاري إلى جنايات دمنهور، بتهمة قتل الأنبا أبيفانيوس مع سبق الإصرار والترصد.

\n

وكشفت تحقيقات فريق النيابة، أن المتهم الأول وائل تواضرس، قام بالتحريض على رئيس الدير، ورفض الانصياع للتقاليد المتعلقة بالرهبان داخل الدير، وكان دائم الخلاف مع قيادات الدير، وتم التحقيق معه داخليا أكثر من مرة ومجازاته وفقًا للأعراف الكنسية.

\n

<img alt=\"\" src=\"https://www.tahrirnews.com/Content/Upload/Slider/4201924134712688464472.jpg\" />

\n

وأضافت أن المتهم، قام بضرب المجني عليه من الخلف على رأسه بماسورة حديدية، طولها حوالى 90 سم، تزن 2 كيلوجرام، 3 ضربات أودت بحياته، وقام المتهم الثاني فلتاؤس المقاري، بمراقبة المكان وتحذيره حال قدوم أي من الرهبان أو العاملين بالدير.

\n

اقرأ أيضًا: <a href=\"https://www.tahrirnews.com/Story/1237836\" target=\"_blank\">تأييد حكم الإعدام للراهبين قاتلي الأنبا أبيفانيوس

\n

<iframe src=\"https://www.youtube.com/embed/XJQxJ2rHjtA\" width=\"400\" height=\"300\" frameborder=\"0\">

"

daohoangson commented 5 years ago

Oh, my bad. I have updated the comment above with the correct code. Change return meta; into return super.parseElement(meta, tag); and it should work.

ahmadkhedr commented 5 years ago

Oh, my bad. I have updated the comment above with the correct code. Change return meta; into return super.parseElement(meta, tag); and it should work.

It works magnificently ♥️♥️

Just one thing...Why does not the embedded tweets render itself to fit the content as it works with Instagram? Instagram post : Screenshot_1556889467

Twitter post : Screenshot_1556889394

Other than that It work perfectly amazing...Thanks alot for your help 👍 🥇 ♥️

daohoangson commented 5 years ago

Just one thing...Why does not the embedded tweets render itself to fit the content as it works with Instagram?

Probably an issue with the auto resize code. There is plan to reimplement that bit in #40, hopefully it will work better with Twitter when that's done.

ahmadkhedr commented 5 years ago

Oh, my bad. I have updated the comment above with the correct code. Change return meta; into return super.parseElement(meta, tag); and it should work.

I have tested it on android and it works like a charm ...How ever on ios clicking on "View this post on Instagram" does not do any thing. How to solve this issue? Thanks in advance 🥇

daohoangson commented 5 years ago

I have updated the code sample in https://github.com/daohoangson/flutter_widget_from_html/issues/23#issuecomment-488534038 for v0.2.1. I expect there will be another change coming soon. Sorry for the problem, this plugin is still young and the api will be changing before it gets stable.

ahmadkhedr commented 5 years ago

Instagram posts suddenly stopped being viewed and return to be displayed like this : instaaa

and the code does not recognize "wf: _BlockquoteWebViewWf()," as well.

and shows me this error as well with "_BlockquoteWebViewWf " : The superclass 'WidgetFactory' doesn't have a zero argument constructor.

daohoangson commented 5 years ago

The code sample above is outdated. If you have updated the plugin, you will need to adjust a bit. See the code at https://github.com/daohoangson/flutter_widget_from_html/blob/master/test/issue_23_test.dart

ahmadkhedr commented 5 years ago

The code sample above is outdated. If you have updated the plugin, you will need to adjust a bit. See the code at https://github.com/daohoangson/flutter_widget_from_html/blob/master/test/issue_23_test.dart

I have applied the changes you have referred to but it shows me this error "The function 'explain' isn't defined."....and the compiler does not recognize " .dart" even if I have added it to the plugin and shows me that error "Target of URI doesn't exist: '.dart'." plus the HTML code is not static like in the example. If you replied me with a full example like the previous code I will be grateful. Thanks in advance.

ahmadkhedr commented 5 years ago

Can you provide me a complete Example, Please? and another thing...the embedded facebook videos started to run on the default browser instead of the screen i.e forwarding the user to the link of the video on the browser and display it there

daohoangson commented 5 years ago

Oh, you only need this part:

class _BlockquoteWebViewWf extends WidgetFactory {
  final buildOp = BuildOp(
    onWidgets: (meta, _) => [
      WebView(
        Uri.dataFromString(
          meta.domElement.innerHtml,
          mimeType: 'text/html',
          encoding: Encoding.getByName('utf-8'),
        ).toString(),
        aspectRatio: 16 / 9,
        getDimensions: true,
      )
    ],
  );

  _BlockquoteWebViewWf(BuildContext context, HtmlWidget htmlWidget)
      : super(context, htmlWidget);

  @override
  NodeMetadata parseElement(NodeMetadata meta, dom.Element e) {
    switch (e.localName) {
      case 'blockquote':
        return lazySet(null, buildOp: buildOp);
    }

    return super.parseElement(meta, e);
  }
}

The rest of the file is test code to make sure the above works correctly.

ahmadkhedr commented 5 years ago

I am already using it as you have mentioned, but it shows me the post like this :

Screenshot_1568047593

and the code that Iam using is this : HtmlWidget( readmore(snapshot, context), webView: true, webViewJs: true, unsupportedWebViewWorkaroundForIssue37: true, factoryBuilder: (c, hw) => _BlockquoteWebViewWf(c, hw), ),

`class BlockquoteWebViewWf extends WidgetFactory { final buildOp = BuildOp( onWidgets: (meta, ) => [ WebView( Uri.dataFromString( meta.domElement.innerHtml, mimeType: 'text/html', encoding: Encoding.getByName('utf-8'), ).toString(), aspectRatio: 16 / 9, getDimensions: true, ) ], );

 _BlockquoteWebViewWf(BuildContext context, HtmlWidget htmlWidget)
   : super(context, htmlWidget);

@override
 NodeMetadata parseElement(NodeMetadata meta, dom.Element e) {
  switch (e.localName) {
   case 'blockquote':
     return lazySet(null, buildOp: buildOp);
  }

  return super.parseElement(meta, e);
}
 }`
daohoangson commented 5 years ago

In the previous comment, you mentioned Facebook video

and another thing...the embedded facebook videos started to run on the default browser instead of the screen i.e forwarding the user to the link of the video on the browser and display it there

But in the latest comment, it was a screenshot of Instagram?

So which of these are having issue, Facebook or Instagram embed? Or both of them? Also, can you post the full HTML so I can reproduce from my app?

ahmadkhedr commented 5 years ago

and another thing...the embedded facebook videos started to run on the default browser instead of the screen i.e forwarding the user to the link of the video on the browser and display it there

That's another issue and I have mentioned it on https://github.com/daohoangson/flutter_widget_from_html/issues/71 So bassically we have issues with both of them at the moment but here iam talking about the instagram and twitter issue Full HTML code : <p><span style=\"color: rgb(255, 0, 0);\">الوكيل الاخباري – </span></p><p>&nbsp;</p><p>أعلنت أسرة سائقة سيارات السباق الأميركية جيسي كومبس عن وفاته في حادث تصادم بسرعة فائقة أثناء محاولتها تسجيل رقم قياسي جديد في السرعة، وفق ما أفادت به صحيفة ديلي ميل البريطانية.&nbsp;</p><p>&nbsp;</p><p>وتوفيت الشابة بنت الـ39 سنة ، خلال التحطم الذي وقع خلال الساعات الماضية، على مضمار قياس السرعات الكبيرة في صحراء ألوفيرد بولاية أوريجون.&nbsp;</p><p></p><p><img src=\"https://img.alwakeelnews.com/Content/Upload/Editor/Image1_8201929141942772302584.png\"><br></p><p>&nbsp;</p><p><br>ويطلق على كومبوس، لقب \"أسرع امرأة على أربع عجلات\"، ولهذا، كانت تسعى للحصول على رقم قياسي لسرعة المركبات الصاروخية، تحطم به أرقام المتسابقات والمتسابقين السوابق، في بطولة نسر أمريكا الشمالية.</p><p>&nbsp;</p><p><img src=\"https://img.alwakeelnews.com/Content/Upload/Editor/Image2_8201929141942772302584.png\"><br></p><p>&nbsp;</p><p>وكانت كومبوس قد كسرت سرعة 398 ميل في الساعة، أي بسرعة مذهلة بلغت 640.52 كيلومتر في الساعة، في عام 2013، وأرادت المرأة القوية، كسر هذا الرقم، وهذا ما تحقق في 2016.<br><br>ففي 2016، تمكنت كومبوس من الوصول إلى سرعة مرعبة بلغت 483 ميلًا في الساعة، أي 777.31 كيلومتر، في سباق متهور على مسار 13 ميلًا ، لكنها أنهت السباق قبل الأوان بسبب مشكلات ميكانيكية، وقتها.</p><p>&nbsp;</p><p><img src=\"https://img.alwakeelnews.com/Content/Upload/Editor/Image3_8201929141942772302584.png\"><br></p><p>&nbsp;</p><p>وفي المرة الثالثة في 2019، أرادت كسر هذه الأرقام المرعبة، ففقدت حياتها.<br><br>قالت أسرة كومبس إنها لقيت حتفها في حادث تصادم بسرعة فائقة أثناء محاولتها تسجيل رقم قياسي جديد في السرعة، وكان أكبر حلم لجيسي أن تصبح أسرع امرأة على وجه الأرض، \"فكان لديها حلم سعت لتحقيقه منذ 2012، ولقد رحلت عن تلك الأرض وهي تقود بسرعة أكبر من أي امرأة في التاريخ\".</p><p>&nbsp;</p><p><img src=\"https://img.alwakeelnews.com/Content/Upload/Editor/Image4_8201929141942772302584.png\"><br></p><p><br>وبدأت كومبس\nمسيرتها المهنية مصممة للسيارات السريعة كما عملت مقدمة تليفزيونية لعدد من برامج\nالسيارات من بينها (أول جيرلز جاراج).<br><br>ووصفها صديقها\nالمقرب وزميلها في الفريق تيري مادن بأنها \"روح مدهشة\".<br></p><p>&nbsp;</p><p></p><blockquote class=\"instagram-media\" data-instgrm-captioned=\"\" data-instgrm-permalink=\"https://www.instagram.com/p/B1tUB2lHGKX/\" data-instgrm-version=\"12\" style=\" background:#FFF; border:0; border-radius:3px; box-shadow:0 0 1px 0 rgba(0,0,0,0.5),0 1px 10px 0 rgba(0,0,0,0.15); margin: 1px; max-width:540px; min-width:326px; padding:0; width:99.375%; width:-webkit-calc(100% - 2px); width:calc(100% - 2px);\"><div style=\"padding:16px;\"> <a href=\"https://www.instagram.com/p/B1tUB2lHGKX/\" style=\" background:#FFFFFF; line-height:0; padding:0 0; text-align:center; text-decoration:none; width:100%;\" target=\"_blank\"> </a><div style=\"padding: 19% 0;\"><a href=\"https://www.instagram.com/p/B1tUB2lHGKX/\" style=\" background:#FFFFFF; line-height:0; padding:0 0; text-align:center; text-decoration:none; width:100%;\" target=\"_blank\"></a></div><div style=\"display:block; height:50px; margin:0 auto 12px; width:50px;\"><a href=\"https://www.instagram.com/p/B1tUB2lHGKX/\" style=\" background:#FFFFFF; line-height:0; padding:0 0; text-align:center; text-decoration:none; width:100%;\" target=\"_blank\"><svg width=\"50px\" height=\"50px\" viewBox=\"0 0 60 60\" version=\"1.1\" xmlns=\"https://www.w3.org/2000/svg\" xmlns:xlink=\"https://www.w3.org/1999/xlink\"><g stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\"><g transform=\"translate(-511.000000, -20.000000)\" fill=\"#000000\"><g><divath d=\"M556.869,30.41 C554.814,30.41 553.148,32.076 553.148,34.131 C553.148,36.186 554.814,37.852 556.869,37.852 C558.924,37.852 560.59,36.186 560.59,34.131 C560.59,32.076 558.924,30.41 556.869,30.41 M541,60.657 C535.114,60.657 530.342,55.887 530.342,50 C530.342,44.114 535.114,39.342 541,39.342 C546.887,39.342 551.658,44.114 551.658,50 C551.658,55.887 546.887,60.657 541,60.657 M541,33.886 C532.1,33.886 524.886,41.1 524.886,50 C524.886,58.899 532.1,66.113 541,66.113 C549.9,66.113 557.115,58.899 557.115,50 C557.115,41.1 549.9,33.886 541,33.886 M565.378,62.101 C565.244,65.022 564.756,66.606 564.346,67.663 C563.803,69.06 563.154,70.057 562.106,71.106 C561.058,72.155 560.06,72.803 558.662,73.347 C557.607,73.757 556.021,74.244 553.102,74.378 C549.944,74.521 548.997,74.552 541,74.552 C533.003,74.552 532.056,74.521 528.898,74.378 C525.979,74.244 524.393,73.757 523.338,73.347 C521.94,72.803 520.942,72.155 519.894,71.106 C518.846,70.057 518.197,69.06 517.654,67.663 C517.244,66.606 516.755,65.022 516.623,62.101 C516.479,58.943 516.448,57.996 516.448,50 C516.448,42.003 516.479,41.056 516.623,37.899 C516.755,34.978 517.244,33.391 517.654,32.338 C518.197,30.938 518.846,29.942 519.894,28.894 C520.942,27.846 521.94,27.196 523.338,26.654 C524.393,26.244 525.979,25.756 528.898,25.623 C532.057,25.479 533.004,25.448 541,25.448 C548.997,25.448 549.943,25.479 553.102,25.623 C556.021,25.756 557.607,26.244 558.662,26.654 C560.06,27.196 561.058,27.846 562.106,28.894 C563.154,29.942 563.803,30.938 564.346,32.338 C564.756,33.391 565.244,34.978 565.378,37.899 C565.522,41.056 565.552,42.003 565.552,50 C565.552,57.996 565.522,58.943 565.378,62.101 M570.82,37.631 C570.674,34.438 570.167,32.258 569.425,30.349 C568.659,28.377 567.633,26.702 565.965,25.035 C564.297,23.368 562.623,22.342 560.652,21.575 C558.743,20.834 556.562,20.326 553.369,20.18 C550.169,20.033 549.148,20 541,20 C532.853,20 531.831,20.033 528.631,20.18 C525.438,20.326 523.257,20.834 521.349,21.575 C519.376,22.342 517.703,23.368 516.035,25.035 C514.368,26.702 513.342,28.377 512.574,30.349 C511.834,32.258 511.326,34.438 511.181,37.631 C511.035,40.831 511,41.851 511,50 C511,58.147 511.035,59.17 511.181,62.369 C511.326,65.562 511.834,67.743 512.574,69.651 C513.342,71.625 514.368,73.296 516.035,74.965 C517.703,76.634 519.376,77.658 521.349,78.425 C523.257,79.167 525.438,79.673 528.631,79.82 C531.831,79.965 532.853,80.001 541,80.001 C549.148,80.001 550.169,79.965 553.369,79.82 C556.562,79.673 558.743,79.167 560.652,78.425 C562.623,77.658 564.297,76.634 565.965,74.965 C567.633,73.296 568.659,71.625 569.425,69.651 C570.167,67.743 570.674,65.562 570.82,62.369 C570.966,59.17 571,58.147 571,50 C571,41.851 570.966,40.831 570.82,37.631\"></divath></g></g></g></svg></a></div><div style=\"padding-top: 8px;\"><a href=\"https://www.instagram.com/p/B1tUB2lHGKX/\" style=\" background:#FFFFFF; line-height:0; padding:0 0; text-align:center; text-decoration:none; width:100%;\" target=\"_blank\"> <div style=\" color:#3897f0; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:550; line-height:18px;\"> View this post on Instagram</div></a></div><div style=\"padding: 12.5% 0;\"><a href=\"https://www.instagram.com/p/B1tUB2lHGKX/\" style=\" background:#FFFFFF; line-height:0; padding:0 0; text-align:center; text-decoration:none; width:100%;\" target=\"_blank\"></a></div><div style=\"display: flex; flex-direction: row; margin-bottom: 14px; align-items: center;\"><a href=\"https://www.instagram.com/p/B1tUB2lHGKX/\" style=\" background:#FFFFFF; line-height:0; padding:0 0; text-align:center; text-decoration:none; width:100%;\" target=\"_blank\"><div> <div style=\"background-color: #F4F4F4; border-radius: 50%; height: 12.5px; width: 12.5px; transform: translateX(0px) translateY(7px);\"></div> <div style=\"background-color: #F4F4F4; height: 12.5px; transform: rotate(-45deg) translateX(3px) translateY(1px); width: 12.5px; flex-grow: 0; margin-right: 14px; margin-left: 2px;\"></div> <div style=\"background-color: #F4F4F4; border-radius: 50%; height: 12.5px; width: 12.5px; transform: translateX(9px) translateY(-18px);\"></div></div><div style=\"margin-left: 8px;\"> <div style=\" background-color: #F4F4F4; border-radius: 50%; flex-grow: 0; height: 20px; width: 20px;\"></div> <div style=\" width: 0; height: 0; border-top: 2px solid transparent; border-left: 6px solid #f4f4f4; border-bottom: 2px solid transparent; transform: translateX(16px) translateY(-4px) rotate(30deg)\"></div></div><div style=\"margin-left: auto;\"> <div style=\" width: 0px; border-top: 8px solid #F4F4F4; border-right: 8px solid transparent; transform: translateY(16px);\"></div> <div style=\" background-color: #F4F4F4; flex-grow: 0; height: 12px; width: 16px; transform: translateY(-4px);\"></div> <div style=\" width: 0; height: 0; border-top: 8px solid #F4F4F4; border-left: 8px solid transparent; transform: translateY(-4px) translateX(8px);\"></div></div></a></div> <div style=\" margin:8px 0 0 0; padding:0 4px;\"> <a href=\"https://www.instagram.com/p/B1tUB2lHGKX/\" style=\" color:#000; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:normal; line-height:17px; text-decoration:none; word-wrap:break-word;\" target=\"_blank\">So I don’t know how to say any of this but it all needs said. I have never loved or been loved by anyone as much as this amazing woman @thejessicombs she was truly my unicorn and I enjoyed every single minute that I had with her. She was the most amazing spirit that I have ever or will ever know. Unfortunately we lost her yesterday in a horrific accident, I was the first one there and trust me we did everything humanly possible to save her!! I’m not ok, but she is right here keeping my going-I made her a promise that if this didn’t go well that I would make sure and do good with it, please help me with that, you are all going to see things on news please believe non of them.. we the family have drafted a release and it will come out today with more proper info, but I was just woke up by the media tracking me down and I need everyone of her true friends to do what she would want “take a deep breath, relax” and do good things with this. Please donate to nothing, I know there will be people try, we are finishing the documentary as she wished and the world will know the truth and her foundation will use those funds to do amazing things in this world and make her legacy live on properly. In the coming days her family and I will get the proper channels put together that you can then donate to that foundation but until you hear it from me wait please-I don’t want some asshole profiting off this (all ready had one try to sell us a video)... . . Love you all and thank you all for being such amazing friends to her, she dedicated her life to helping support others dreams and I promise I will continue that.</a></div> <div style=\" color:#c9c8cd; font-family:Arial,sans-serif; font-size:14px; line-height:17px; margin-bottom:0; margin-top:8px; overflow:hidden; padding:8px 0 7px; text-align:center; text-overflow:ellipsis; white-space:nowrap;\">A post shared by <a href=\"https://www.instagram.com/terry_madden/\" style=\" color:#c9c8cd; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:normal; line-height:17px;\" target=\"_blank\"> Terry L. Madden</a> (@terry_madden) on <time style=\" font-family:Arial,sans-serif; font-size:14px; line-height:17px;\" datetime=\"2019-08-28T12:51:29+00:00\">Aug 28, 2019 at 5:51am PDT</time></div></div></blockquote> <script async=\"\" src=\"//www.instagram.com/embed.js\"></script><p></p><p><br>وأضاف على\nموقعه على \"إنستجرام\": \"للأسف فقدناها في حادثة مروعة، كنت أول من\nوصل هناك وصدقوني فعلنا كل ما يمكن لبشر فعله لإنقاذها!\".<br><br>وسجلت كومبس\nمحاولتها لكسر الرقم القياسي في سرعة القيادة على مواقع التواصل الاجتماعي، وكان\nهدفها أن تتجاوز الرقم القياسي المسجل عام 1976 بالقيادة بسرعة 512 ميلا (حوالي\n820 كيلومترا) في الساعة والذي حققته الأمريكية كيتي أونيل التي توفيت في نوفمبر\nالماضي.</p><p>&nbsp;</p><p>&nbsp;</p><p>ديلي ميل -</p><p>&nbsp;</p><p><customurllink></customurllink></p><p class=\"hint-admin\" style=\"border: 1px solid #ccc; padding: 10px; font-size: 16px; text-align:center; color: #ccc;\">اظهار أخبار متعلقة</p><br><p></p><p><customurllink></customurllink></p><p class=\"hint-admin\" style=\"border: 1px solid #ccc; padding: 10px; font-size: 16px; text-align:center; color: #ccc;\">اظهار أخبار متعلقة</p><br><p></p><p><customurllink></customurllink></p><p class=\"hint-admin\" style=\"border: 1px solid #ccc; padding: 10px; font-size: 16px; text-align:center; color: #ccc;\">اظهار أخبار متعلقة</p><br><customurllink><p class=\"hint-admin\" style=\"border: 1px solid #ccc; padding: 10px; font-size: 16px; text-align:center; color: #ccc;\">اظهار أخبار متعلقة</p></customurllink><br><customurllink><p class=\"hint-admin\" style=\"border: 1px solid #ccc; padding: 10px; font-size: 16px; text-align:center; color: #ccc;\">اظهار أخبار متعلقة</p></customurllink><br><p></p>" Thanks in advance .

daohoangson commented 5 years ago

I have found out the issue. Actually, there are 2 issues:

  1. When being rendered in a web view, the Instagram post is scaled down sometime. This can be fixed by doing something like this:
  final buildOp = BuildOp(
    onWidgets: (meta, _) => [
      WebView(
        Uri.dataFromString(
          """<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
</head>
<body>
  ${meta.domElement.outerHtml}
</body>
</html>""",
          mimeType: 'text/html',
          encoding: Encoding.getByName('utf-8'),
        ).toString(),
        aspectRatio: 16 / 9,
        getDimensions: true,
      )
    ],
  );

Notice that I have switched to use outerHtml instead of innerHtml and put it in a valid html5 boilerplate. The important thing is the meta tag <meta name="viewport" content="width=device-width">, it tells the web view to scale the viewport correctly.

  1. Because the embed javascript (instagram.com/embed.js) is not inside the BLOCKQUOTE, the web view is rendered without proper styling. There are a few ways to fix this but the easiest is just put it in our boilerplate code:
  final buildOp = BuildOp(
    onWidgets: (meta, _) => [
      WebView(
        Uri.dataFromString(
          """<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
</head>
<body>
  ${meta.domElement.outerHtml}

  <script async src=\"https://www.instagram.com/embed.js\"></script>
</body>
</html>""",
          mimeType: 'text/html',
          encoding: Encoding.getByName('utf-8'),
        ).toString(),
        aspectRatio: 16 / 9,
        getDimensions: true,
      )
    ],
  );

Full working code: https://gist.github.com/daohoangson/9099677c3818cd72d110baf13ba58891

Screenshot:

Screen Shot 2019-09-13 at 9 29 25 AM
ahmadkhedr commented 5 years ago

I can not thank you enough...Instagram posts are displaying perfectly now but twitter still have the issue but it was not displaying from the beginning, so I think this issue is solved now

daohoangson commented 5 years ago

Can you open a new issue for Twitter with full html code? I'll try again to make it works.

On Fri, Sep 13, 2019, 6:43 PM ahmadkhedr notifications@github.com wrote:

I can not thank you enough...Instagram posts are displaying perfectly now but twitter still have the issue but it was not displaying from the beginning, so I think this issue is solved now

— You are receiving this because you were assigned. Reply to this email directly, view it on GitHub https://github.com/daohoangson/flutter_widget_from_html/issues/23?email_source=notifications&email_token=AAB2N2HY44ADKDNT4I5WZ4LQJN4EFA5CNFSM4HGAL6JKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD6UYYSQ#issuecomment-531205194, or mute the thread https://github.com/notifications/unsubscribe-auth/AAB2N2ANBBV5EEIUVSUNAJDQJN4EFANCNFSM4HGAL6JA .

ahmadkhedr commented 5 years ago

Can you open a new issue for Twitter with full html code? I'll try again to make it works.

Done https://github.com/daohoangson/flutter_widget_from_html/issues/72

ahmadkhedr commented 5 years ago

I Have two issue on the same issue: first for factoryBuilder: (c, hw) => _BlockquoteWebViewWf(c, hw), it shows me the following message : "The argument type '_BlockquoteWebViewWf Function(HtmlWidgetConfig, dynamic)' can't be assigned to the parameter type 'WidgetFactory Function(HtmlWidgetConfig)'."

and the second for the line : _BlockquoteWebViewWf(BuildContext context, HtmlWidget htmlWidget) : super(context, htmlWidget); it show me the following error "Too many positional arguments: 1 expected, but 2 found. The argument type 'BuildContext' can't be assigned to the parameter type 'HtmlWidgetConfig'. " I don't know how, but in an older project, it works fine without errors with the same code implementation. Thanks in advance.

daohoangson commented 5 years ago

The latest release changed the signature a bit, see the up-to-date sample code here https://github.com/daohoangson/flutter_widget_from_html/blob/master/test/issue_23_test.dart. Make sure you keep the <!doctype html>... stuff for Twitter / Instagram embed to work.