Webview auto height based on its html source

I have been observe fusetools since one year ago, and finally fuse version 1.0 beta has been released. Congratulations! The fuse team has worked very well creating cool tools.

Currently I’m developing a new version of my android app using fusetools. The previous version of this app was created using ionic.

However I encountered difficulties when displaying html string from JSON, I know because fusetools is not web-based and currently no API can handle richtext. I found a suggestion, by format it into plain text and then split the html string into array. But that is not a good way because it will make the reader feels uncomfortable. Another suggestion by using Webview, it’s a good idea because I can still maintain HTML format properly. But I don’t find how to set the height of Webview to automatically fit the HTML source, because I don’t want the user to scroll on the Webview.

I tried to set height of Webview to 100%, but the page becomes too long since it produces a lot of white space at the end Webview. The question is how to set the height of Webview to automatically fit the content without much white space appear?

For comparison, I create the implementation of those suggestion into 3 pages.

  • Plain HTML page
  • HTML wrapped into webview with exact height
  • HTML wrapped into webview with 100% height

My dev environment :

Windows 10 OS
Fuse version 1.0.0 (build 13426)

Below is my source code to reproduce the problem. Or you can just clone my repo .

MainView.ux

<App>
	<JavaScript File="./MainView.js" />
	
	<!-- plain post -->
	<Page ux:Class="PlainPost">
		<ScrollView ClipToBounds="true">
      <StackPanel Alignment="Top" Padding="30,10">
	    	<MainText>Plain Post</MainText>
	    	<TitleText Value="{post.title}" />
	    	<Each Items="{post.contentParagraphs}">
	        <ContentText Value="{content}" Margin="0,0,0,10" />
	      </Each>
      </StackPanel>
    </ScrollView>	
  </Page>

	<!-- html post -->
	<Page ux:Class="HTMLPost">
    <ScrollView ClipToBounds="true">
      <StackPanel Alignment="Top" Padding="30,10">
	    	<MainText>HTML Post</MainText>
	    	<TitleText Value="{post.title}" />
    	  <NativeViewHost>
          <WebView Height="900" ZoomEnabled="false" Source="{post.contentHTML}">
          </WebView>
        </NativeViewHost>
    	</StackPanel>
    </ScrollView>
  </Page>

  <!-- html post -->
	<Page ux:Class="HTMLPostAuto">
    <ScrollView ClipToBounds="true">
      <StackPanel Alignment="Top" Padding="30,10">
	    	<MainText>HTML Post Auto</MainText>
	    	<TitleText Value="{post.title}" />
    	  <NativeViewHost>
          <WebView Height="100%" ZoomEnabled="false" Source="{post.contentHTML}">
          </WebView>
        </NativeViewHost>
    	</StackPanel>
    </ScrollView>
  </Page>

  <Text ux:Class="MainText"  
				TextWrapping="Wrap" 
				FontSize="30" 
				Margin="0,0,0,30"/>
  
  <Text ux:Class="TitleText"  
				TextWrapping="Wrap" 
				FontSize="20"
				Margin="0,0,0,20"/>

	<Text ux:Class="ContentText" 
				FontSize="13" 
				TextWrapping="Wrap" />

  <Panel ux:Class="MenuButton" Padding="5" Margin="0,5,10,5" Color="#000" >
		<string ux:Property="Title" />

		<Text Color="#ffffff">{ReadProperty this.Title}</Text>
  	<WhilePressed>
      <Scale Factor=".8" Duration=".08" Easing="QuadraticOut" />
    </WhilePressed>
  </Panel>

  <DockPanel>
  	<StatusBarBackground Dock="Top"/>
    <BottomBarBackground Dock="Bottom"/>

    <PageControl ux:Name="pageControl">
    	<PlainPost ux:Name="plainPost" />
    	<HTMLPost ux:Name="htmlPost"/>
    	<HTMLPostAuto ux:Name="htmlPostAuto"/>
    </PageControl>

  	<StackPanel Orientation="Horizontal" Dock="Top" Navigation="pageControl" Padding="30,10">
      <MenuButton Title="Plain">
        <Clicked>
          <NavigateTo Target="plainPost"/>
        </Clicked>
      </MenuButton>
      <MenuButton Title="HTML">
      	<Clicked>
          <NavigateTo Target="htmlPost"/>
        </Clicked>
      </MenuButton>
      <MenuButton Title="HTML Auto">
      	<Clicked>
          <NavigateTo Target="htmlPostAuto"/>
        </Clicked>
      </MenuButton>
  	</StackPanel>
  </DockPanel>
</App>

MainView.js

const Observable = require('FuseJS/Observable');

const API = {
  URL: 'https://public-api.wordpress.com/rest/v1.1/sites/lakonhidup.wordpress.com/',
  fields: 'ID,title,categories,content'
}

let post = Observable({
  ID: '',
  title: '',
  content: '',
  categories: '',
  contentPlain: '',
  contentHTML: '',
  contentParagraphs: []
});

const pages = [
  { title: 'Plain Post' },
  { title: 'HTML Post' }
];

function stripHTML(text) {
  text = text.replace(/\[.*?\]/g, ""); // remove wordpress shortcode , credit : http://stackoverflow.com/questions/20281294/finding-and-removing-all-occurences-of-shortcode-with-javascript
  return text.replace(/<.*?>/gm, ''); // remove html element
}

function renderToHtml(content) {
  return `
    <html>
      <head>
        <title>Lakon Hidup</title>
        <style>
          p, span{ font-size: 30px; }
        </style>
      </head>
      <body>
        ${content}
      </body>
    </html>
  `;
}

function loadPost() {
  fetch(`${API.URL}posts/slug:a-whole-new-world/?fields=${API.fields}`)
    .then(function(response) { return response.json(); })
    .then(function(responseObject) {
      responseObject.contentPlain = stripHTML(responseObject.content);
      responseObject.contentHTML = renderToHtml(responseObject.content);
      responseObject.contentParagraphs = [];

      const paragraphs = responseObject.contentPlain.split('\n');
      paragraphs.forEach(function(val, key) {
        responseObject.contentParagraphs.push({
          content: val
        });
      });
      console.log(responseObject.contentParagraphs.length);

      post.value = responseObject
    });
}

loadPost();

module.exports = {
  post: post,
  pages: pages
};

Hi and thanks for the kind words! Super happy to have people onboard who have experience with other tools!

Fuse does not have Rich Text support yet, but it’s in the roadmap without any specific ETA.

Do you only need the rich text features, or do you also require other, more advanced things that HTML brings? If it’s the former, you could still go the “split the html string into array”-route with great success, by formatting the parts of text with the help of ux:Classes and putting them together in a WrapPanel.

WebViews in general are very expensive in terms of performance, so stacking several of them in a single page might quickly become a significant problem on lower-end devices.

And finally, dynamically changing the height of a WebView inside of a NativeViewHost depending on the dynamic HTML contents… well, that might prove to be very hard if not impossible at this point.

Hope this helps, and I’m sorry if this wasn’t what you hoped to hear.

Uldis wrote:
Do you only need the rich text features, or do you also require other, more advanced things that HTML brings?

Hi @Uldis, thanks for the response.

In fact, I only need the basic richtext features as follows :

  • bold
  • italic
  • align right
  • align center

Btw, I’ll find my way how to solve the problem and let fuse team know when my app is published in google play store :slight_smile:

A. Dzulfikar Adi Putra wrote:
Hi @Uldis, thanks for the response.

In fact, I only need the basic richtext features as follows :

  • bold
  • italic
  • align right
  • align center

Btw, I’ll find my way how to solve the problem and let fuse team know when my app is published in google play store :slight_smile:

Hi, did you find a way to solve this problem. I’m currently facing a similar problem.

Furthermore; which fonts does Fuse use by default and can this be used within webviews?