I need to call at server side, an URL and work with the HTML content off the response. For this I'm using the HTTP library from Dart like this :
http.read('myUrl').then((contents) {
//contents to HTMLDocument format //Need to transform the String contents to HTML object
});
And I want to convert the response to a HTMLDocument (or other object I don't know) to be able to retrieve element in it by HTML tag or CSS class, like with JQuery for example.
Does anybody have an idea to perform this ?
You canuse html5lib package from pub. It allows to parse HTML and present it DOM like element tree on server side. The element tree will eventually "be compatible with dart:html, so the same code will work on the client and the server" in the future. See the readme for a getting started example.
"I need to call at server side"
Not sure exactly what you mean.
If you are running in the browser and calling the server you could try using a DocumentFragment. Something like this:
http.read(url).then((html) {
var fragment = new DocumentFragment(html);
var element = fragment.query('.foo');
// code here...
});
Otherwise if you're running server side, as the other answer mentions, html5lib is the way to go. Last time I looked the query() method in html5lib only supported tagname queries not classes, or ids.
Related
On many places one can find usage of a function PF with Primefaces. For example in this answer
From what I have seen so far it seems to be a magic "make it work a little better" function. But I don't believe in this kind of stuff so:
What does this function do?
And where can I find documentation about it?
PF is a Javascript function.
In Primefaces 4.0 the Javascript scope of widgets changed. Prior to version 4.0 you could open a dialog widget with widgetVar.show();.
In Primefaces 4.0 and above the widgets are stored in a Javascript widget array. When you call PF('widgetVar') it is looking for the widget in the array and returning it.
PF=function(d){
var c=b.widgets[d];
if(!c){
if(a.console&&console.log){
console.log("Widget for var '"+d+"' not available!")
}
b.error("Widget for var '"+d+"' not available!")
}
return c
};
I could not find much on this either this is what I was able to decipher using Chrome's developer tools.
The PF function is a part of PrimeFaces's JavaScript API. It looks up a Javascript object that is the backbone of the JSF component on the client-side. Here is its definition (source):
PF = function(widgetVar) {
var widgetInstance = PrimeFaces.widgets[widgetVar];
if (!widgetInstance) {
PrimeFaces.error("Widget for var '" + widgetVar + "' not available!");
}
return widgetInstance;
};
PF is a shortcut for PrimeFaces.widgets['someWidgetId'], which just looks-up a Javascript object in global scope, and so the Javascript object can also be retrieved using window['someWidgetId'].
The PrimeFaces's Javascript API has no official documentation online, so to understand what you can really "do" with the Javascript object, you'll need to take a deep dive into PrimeFaces.
See also
"Intro To PrimeFaces widgetVar" blog post
PrimeFaces source code
For other Primefaces users coming here when upgrading to version 4.0 and above, it's possible to bypass the need to use PF('yourWidgetVar').someFunction() and just use yourWidgetVar.someFunction() directly as you would have before version 4.0. You just need the following configuration in web.xml:
<context-param>
<param-name>primefaces.LEGACY_WIDGET_NAMESPACE</param-name>
<param-value>true</param-value>
</context-param>
From the Primefaces User Guide:
Enables window scope so that widgets can be accessed using
widgetVar.method() in addition to default PF namespace approach like
PF('widgetVar').method().
Obviously you'd be susceptible to the namespace clash/pollution this feature was created to avoid, but it's useful if you want to migrate to a new version in little steps and isolate what incompatibilities the new version has introduced.
I'm trying to override a JS function named replaceMe in the web page from my add-on's content script, but I see that the original function implementation always gets executed.
Original HTML contains the following function definition:
function replaceMe()
{
alert('original');
}
I'm trying to override it my add-on like (main.js):
tabs.activeTab.attach({
contentScriptFile: self.data.url("replacerContent.js")
});
Here's what my replacerContent.js looks like:
this.replaceMe = function()
{
alert('overridden');
}
However, when I run my addon, I always see the text original being alerted, meaning the redefinition in replacerContent.js never took effect. Can you let me know why? replaceMe not being a privileged method, I should be allowed to override, eh?
This is because there is an intentional security between web content and content scripts. If you want to communicate between web content and you have control over the web page as well, you should use postMessage.
If you don't have control over the web page, there is a hacky workaround. In your content script you can access the window object of the page directly via the global variable unsafeWindow:
var aliased = unsafeWindow.somefunction;
unsafeWindow.somefunction = function(args) {
// do stuff
aliased(args);
}
There are two main caveats to this:
this is unsafe, so you should never trust data that comes from the page.
we have never considered the unsafeWindow hack and have plans to remove it and replace it with a safer api.
Rather than relying on unsafeWindow hack, consider using the DOM.
You can create a page script from a content script:
var script = 'rwt=function()();';
document.addEventListener('DOMContentLoaded', function() {
var scriptEl = document.createElement('script');
scriptEl.textContent = script;
document.head.appendChild(scriptEl);
});
The benefit of this approach is that you can use it in environments without unsafeWindow, e. g. chrome extensions.
You can then use postMessage or DOM events to communicate between the page script and the content script.
I've loaded an ASP.NET MVC viewModel into KnockoutJS using ko.mapping.fromJS(Model).
My viewModel looks something like this:
public IEnumerable<FunkyThing>funkyThings;
public FunkyThing selectedFunkyThing;
Each FunkyThing has a string property funkyThingName.
The mapping worked fine and I can see all the funky things in the table with their names.
I want to add a quick refresh button. So I've created a simple button and then data bound the buttons click to a knockout function refresh which looks something like this:
model.refresh= function () {
var url = '#Url.Action(MVC.FunkyThings.RefreshJSON())';
$.getJSON(url, function (returnedData) {
ko.mapping.fromJS(returnedData, {}, model.funkyThings);
});
The refresh function is succesfully called which in turn calls the RefreshJSON method on the server. The server passes back JSON data - an updated array of funkyThings, which I can see within chrome when I hover over returnedData in chrome's debugger.
However unfortunately after the mapping function has been called the bindings break:
Uncaught Error: Unable to parse bindings.
Message: ReferenceError: funkyThingName is not defined;
Bindings value: text: funkyThingName
And I'm not sure why...?
Is model.funkyThings an observable? If it is, then you can try passing it into the mapping method as a function:
ko.mapping.fromJS(returnedData, {}, model.funkyThings());
Failing that, are you sure that the structure of the JSON returned by the refresh method is correct?
Ah, if you're getting a JSON string back, so you need to call the fromJSON method of the mapping plugin:
ko.mapping.fromJSON(returnedData, {}, model.funkyThings);
You might need the parenthesis on funkyThings here too, but try it without first.
If the returned object is in the correct format and also the binding is well done you
just need to do:
model.FunkyThings(returnedData).
How can I get the response from an ajax call made with g:remoteLink, using jquery ?
I have tried using nSuccess="removeTask(e)" and getting the response with e.responseText or e.response, but nothing works.
When using Grails with the JQuery plug in and using the remote functions like remoteLink, the code that is generated for the remote function is something like this:
success: function(data, textStatus){ jQuery('#results').html(data); }
This is if for example you set the update parameter as "[success:'results']". As you can see the main function receives a data parameter which I think is what your looking for, so if you need to call another function that uses that value, you could do something like this:
<g:remoteLink controller="yourcontroller" action="youraction" update="[success: 'results']" onSuccess="yourFunction(data) ">Your link</g:remoteLink>
This will generate javascript code like this:
success:function(data,textStatus){ jQuery('#results').html(data); yourFunction(data); }
Hope this helps!!
Does anyone know what might have changed since v3.0.5 that would enable extensions to work? Or, maybe I'm missing a setting somewhere? I wrote this add-on that works fine with newer versions, but I can't get it to launch in older ones. Specifically, I can't even get this part to work (this is in my browser overlay.xul):
<html:script>
<![CDATA[
var Cc = Components.classes;
var Ci = Components.interfaces;
var obSvc = Cc["#mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
gBrowser.consoleService = Cc["#mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
gBrowser.log = function(msg){
this.consoleService.logStringMessage(msg);
}
gBrowser.newObj= new MyAddOn();
gBrowser.log("initializing...");
function regListener()
{
obSvc.addObserver(gBrowser.newObj, "http-on-modify-request", false);
}
function unregListener()
{
obSvc.removeObserver(gBrowser.newObj, "http-on-modify-request");
}
window.addEventListener("load", regListener, false);
window.addEventListener("unload", unregListener, false);
]]>
This should attach listeners to the new obj (defined by a linked .js) However, I'm not even getting the "initializing..." message in the console. Any ideas?
Don't use <html:script>, use <script> (assuming you have xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" on your root <overlay> element).
Don't register an application-global listener (http-on-modify-request) from a window overlay. Doing so will make your code run one time in each window the user may have open. Use an XPCOM component instead - https://developer.mozilla.org/en/Setting_HTTP_request_headers
Don't pollute common objects (like gBrowser or the global object (with var Cc)) with your own properties. If everyone did that, no two extensions would work together. Put all your code properties on your own object with a unique name.
accessing gBrowser before the load event is probably what's causing your specific problem.
Set up your environment and check the Error Console to debug problems.
Don't waste time trying to support Firefox 3. It's not supported by Mozilla itself for over a year and shouldn't be used to access the web.
It looks like gBrowser.log is not defined, or at least is not a function, as the error console will probably tell you. I've never heard of it either. Maybe it was added in Fx 3.5?