webkit : how to get the actual content of a page after content was added via javascript? - webkit

I want to get the actual content of a page I loaded into a webview after some content has been updated by some jquery
$(document).ready(function() {
$("#main").append('<p>Test</p><p>Test</p><p>Test</p><p>Test</p><p>Test</p><p>Test</p><p>Test</p>');
});
After the page has been updated I tried to get the content of page with the following command [vala syntax]
web_view.get_main_frame ().get_data_source().get_data().str
but I only get the original content (even if loading is finished)
using
web_view.get_dom_document().document_element.text_content
I get the actual content but the tags are removed.
I guess I could walk the whole tree to get the actual document but tere should be a more easy way to do it.
EDIT:
my solution
this.web_view.load_finished.connect ((source, frame) => {
stderr.printf(this.web_view.get_dom_document().body.get_inner_html());
}
I'll probably find this awfull when I'll read this some years from now but for now I'll go with that.

In the HTML DOM, elements implement the HTMLElement interface. The HTMLElement interface in WebKit includes the outerHTML property. This property returns a string containing the serialized markup of the element and all of its children. I'm not familiar with Vala but based on your code snippets this would be accessed like so:
web_view.get_dom_document().document_element.outer_html

The correct answer in Vala is this:
webview.get_dom_document().get_body().get_inner_html ()

Related

Server Side Rendering Vue with ASP.NET Core 2

I'm trying to understand the usage and limitations of server side rendering with vuejs when using aspnet core.
I used this starter kit for aspnet core and vuejs to setup a simple vue site, which is running based on the code here: https://github.com/selaromdotnet/aspnet-vue-ssr-test/tree/master
I then modified the project to update the aspnet-prerendering and added vue-server-renderer, compiling a hodgepodge of sources to cobble together this update: https://github.com/selaromdotnet/aspnet-vue-ssr-test/tree/ssr
If I run this project, the site appears to load fine, and if I turn off the javascript in the browser, I can see that it does appear that the server-side rendering executed and populated the html result:
however, because JavaScript is disabled, the content isn't moved into the dom as it looks like it is trying to...
My understanding of server-side rendering is that it would populate the html entirely and serve a completed page to the user, so that even if JS was disabled, they'd at least be able to see the page (specifically for SEO purposes). Am I incorrect?
Now I believe modern search engines will execute simple scripts like this to get the content, but I still don't want a blank page rendered if js is disabled...
Is this a limitation of server-side rendering, or perhaps specifically ssr with vue and/or aspnet core?
or am I just missing a step somewhere?
Edit: more information
I looked at the source code for what I believe is the method that prerenders the section here: https://github.com/aspnet/JavaScriptServices/blob/dev/src/Microsoft.AspNetCore.SpaServices/Prerendering/PrerenderTagHelper.cs
The line
output.Content.SetHtmlContent(result.Html);
has a null value for result.Html. However, when I manually edit this value to put a test value, it also doesn't render to the output html, and the app div tag is still empty...
If I'm doing something wrong to populate the result.Html value with the expected output, that's one thing, and I would appreciate some help in doing that, especially since the output html appears to be found, since it's in the script that immediately follows...
However, even if I were to populate it, it appears it's being skipped, as evidenced by me manually changing the value. is this a bug in the code or am I doing somethigng wrong, or perhaps both?
As you correctly noticed, for your project, result.Html inside the tag helper is null. So that line cannot be the location where the output is being generated. Since the HTML output from your prerendering script also does not include a script tag, it is clear that something has to generate that. The only other line that could possible do this is the following from the PrerenderTagHelper:
output.PostElement.SetHtmlContent($"<script>{globalsScript}</script>");
That would fit the observed output, so we should figure out where the globalsScript comes from.
If you look at the PrerenderTagHelper implementation, you can see that it will call Prerenderer.RenderToString which returns a RenderToStringResult. This result object is deserialized from JSON after calling your Node script.
So there are two properties of interest here: Html, and Globals. The former is responsible for containing the HTML output that finally gets rendered inside the tag helper. The latter is a JSON object containing additional global variables that should be set for the client side. These are what will be rendered inside that script tag.
If you look at the rendered HTML from your project, you can see that there are two globals: window.html and window.__INITIAL_STATE__. So these two are set somewhere in your code, although html shouldn’t be a global.
The culprit is the renderOnServer.js file:
vue_renderer.renderToString(context, (err, _html) => {
if (err) { reject(err.message) }
resolve({
globals: {
html: _html,
__INITIAL_STATE__: context.state
}
})
})
As you can see, this will resolve the result containing just a globals object with both html and __INITIAL_STATE__ properties. That’s what gets rendered inside of the script tag.
But what you want to do instead is have html not as part of globals but on the layer above, so that it gets deserialized into the RenderToStringResult.Html property:
resolve({
html: _html,
globals: {
__INITIAL_STATE__: context.state
}
})
If you do it like that, your project will properly perform server-side rendering, without requiring JavaScript for the initial view.

Initialize dynamic Component in Code using Vue.js

I am currently developing a web application that is used to display elements for events on a map provided by HERE Maps. I am using Vue.
I have some components, but the relevant component is the component HereMaps.vue which initializes the map using the HERE Maps Api.
The HERE Maps Api provides the possibility to place so called InfoBubbles on the map showing additional information. These InfoBubbles can be provided some HTML-code in order to customize their appearance.
Please refer to the documentation for additional information
Following the documentation the code looks something like this:
let bubble = new H.ui.InfoBubble(marker.getPosition(), {
content: "<div class='someClass'>Some Content</div>"
});
this.ui.addBubble(bubble)
This is happening after mount in the "mounted" method from Vue in the "HereMaps" component.
The Bubbles are added in a "closed" (hidden) form and dynamically "opened" to reveal their content when the corresponding marker icon on the map is clicked. Therefore the HTML-code is present on the DOM after the component is mounted and is not removed at a later stage.
Now instead of supplying custom code within each bubble added to the UI i want to just add a component like this:
let bubble = new H.ui.InfoBubble(marker.getPosition(), {
content: "<myDynamicComponent></myDynamicComponent>"
});
this.ui.addBubble(bubble)
It does not matter to me wether the component is initialized using props or if it is conditionally rendered depending on the state of a global variable. I just want to be able to use the "myDynamicComponent" in order to customize the appearance in a different file. Otherwise the design process gets very messy.
As far as i know this is not possible or at least i was not able to get it work. This is probably due to the fact that the "myDynamicComponent" is not used within the "template" of the "HereMaps" component und thus Vue does not know that it needs to render something here after the directive is added to the DOM in the "mounted" method.
This is what the InfoBubble looks using normal HTML as an argument:
This is what the InfoBubble looks using the component as an argument:
It appears to just be empty. No content of the "myDynamicComponent" is shown.
Does anyone have any idea how i could solve this problem.
Thank You.
Answer is a bit complicated and I bet you wouldn't like it:)
content param can accept String or Node value. So you can make new Vue with rendered your component and pass root element as content param.
BTW, Vue does not work as you think, <myDynamicComponent></myDynamicComponent> bindings, etc exists in HTML only in compile time. After that all custom elements(components) are compiled to render functions. So you can't use your components in that way.
Give us fiddle with your problem, so we can provide working example:)

Remove <div> generated around Shared Block in EPiServer 7

Episerver always wrap shared block in a tag. I would like to get rid of this. So if in my LinkBlock has a Template with only
link
I would not get a
<div>link</div>
in the view for a user.
If this is not possible how can I change <div> to any other tag, or put a CssClass on it. Like it is possible in not shared blocks:
<EPiServer:Property runat="server" PropertyName="RightContentArea" CustomTagName="aside" CssClass="column-2 sidebar"></EPiServer:Property>
I believe it is the rendering of the ContentArea property which adds the div tags around the blocks it contains.
EPiServer suggests that in order to preserve the editing functionality of the block elements themselves they need to have the div around them.
A possible solution might be for you to do your own custom rendering of content areas, but depending on the kind of block templates you're using it can be tricky to get editing to work. The example in the link is for rendering multiple blocks of the same type.
You can use the CustomTagName and CssClass properties of the Property control to format the container element.
You may also use RenderSettings to modify container elements of child elements (where applicable).
I use this trick in cshtml:
#RenderBlocks(Model.CurrentPage.Content1)
#* ---------------------------------------------------------------------------------- *#
#* Render ContentArea without addition DIVs that EpiServer embed. That breaks layout a lot. *#
#helper RenderBlocks(EPiServer.Core.ContentArea content) {
if(null != content){
var blocks = content.FilteredContents.ToArray();
foreach(var block in blocks){
#Html.PropertyFor(x => block)
}
}
}
You can choose the tag using the CustomTagName attribute on the Property Control
Alternatively, if you wanted to remove the tag, you could use a control adapter. A good example is found here
You can also create a custom content area that doesn't render the divs when edited in live mode and only renders them in edit mode.
If you only need to do this once or twice I would still recommend going with the ChildrenCustomTagName route as it's a bit mroe flexible. If you need to do this a lot and you can't change your CSS easily then I would go custom content area. If you are interested in how to remove the div's I wrote a blog post and a sample site on github here Extra divs in content area how to remove them ?
Since i wasn't able to remove the <div>'s i didn't want, i put my own CSS class on them. This did the trick for me in Webforms. (If anyone still uses it)
Use <RenderSettings ChildrenCssClass="yourCssClass" />
<EPiServer:Property runat="server" PropertyName="RightContentArea"CustomTagName="aside" CssClass="column-2 sidebar"><RenderSettings ChildrenCssClass="yourCssClass"></RenderSettings></EPiServer:Property>

How to edit html (tags), before being executed by CppWebBrowser

I can't solve my problem, and I hope somebody knows how...
I have a component on my form TCppWebBrowser, and when I navigate to a URL, after the document was downloaded, in method OnDocumentComplete() , I'm trying to check and change html source of loaded document... before it being executed by browser.
I need that, because some websites have background sounds, and I want to parse html and remove tags or just remove text which contains sound files like *.wav , *.mid , *.swf, *.mp3 ... ect.
For example if html source have this line:
<NOEMBED><BGSOUND src="/images/ImagineCut.wav"></NOEMBED>
then, i change it to:
<NOEMBED><BGSOUND src="/images/ImagineCut."></NOEMBED>
or I can delete whole tag.
Using this way I want to mute webbrowser or even to stop playing sounds. Please take into consideration this method, because it will help me to avoid all kind of sounds after I edited html.. (before browser execute it)
That's what I tried to do:
void __fastcall TForm1::CppWebBrowser1DocumentComplete(TObject *Sender,
LPDISPATCH pDisp, Variant *URL)
{
IHTMLDocument2 *pHTMLDoc;
CppWebBrowser1->Document->QueryInterface(IID_IHTMLDocument2,(LPVOID*)&pHTMLDoc);
IHTMLElement *pElem;
pHTMLDoc->get_body(&pElem);
BSTR text;
pElem->get_innerHTML(&text);
text = Cleaning(text); //checking and changing html without souds
pElem->put_innerHTML(text);
pElem->Release();
pHTMLDoc->Release();
}
To do what you are asking, you would have to download the HTML file yourself from outside of the TCppWebBrowser component completely, alter the HTML as needed, and then push the new HTML into TCppWebBrowser using one of its IPersist... interfaces. Examples of doing that have been posted in the Borland/CodeGear/Embarcadero forums many times before.

dijit.Menu to be displayed after DOM had been set up

I have set up in Javascript my preferred dijit.Menu which is that far so good.
How am I able to display the dijit.Menu directly after the page starts up in the (with it's position) without any mouse interaction?! I have looked in the API so far and don't find the answers. Will I have to "overwrite" a method?
If yes, which one is it? And what do I have todo???
The widget will not show up until it is parsed by dojo.
You should place fake menu markup inside its dom node:
<div dojoType="dijit.Menu">
<h1>This text is shown after the dom is loaded
and until the menu is parsed and renered</h1>
</div>
As soon as menu is ready, everything you've placed inside menu's dom node will be replaced by actual widget's html.
NON-AMD Version:
dojo.ready(function(){
// The code for all items!
})
DOJO-AMD Version, put the parameters of the modules you like to add, in require as well give them a name in the functions parameters list:
require(["dojo/domReady!"],function(){
//natve code
});