I am using WP7 WebBrowser control . On this page I have a hyperlink.This link are came from web service. I want to handle the click event of that hyperlink in my application's code behind (i.e. in C#).And i want display another web browser controll on this hyperlink click event
Is there are a way for the WebBrowser control to handle click events?
If i understand you, you want to intercept the onClick event in your first WB control (call this WB1), and open that page up (when the hyperlink is clicked) in another WB control (call this WB2)?
There are several ways you can do this, is this link set to open up in a new window? If so, you can intercept the NewWindow2 event is WB1 and run the following code in the NewWindow2 event of WB1...
Set pDisp = WB2.object
(it may be ppDisp instead of pDisp, but it will show up when your event is auto generated, choose whichever object name shows up in your arguments list).
Otherwise, you can intercept this request during BeforeNavigate2 event of the WB1 event, check the URL property if it is the link you're interested in, and if so, cancel the current request and reissue a new one as below... (in the WB1 BN2 event)...
Cancel = True ' This cancels the request
WB2.Navigate2 URL, , "YourWB2sDocumentNameOrTargetFrameNameGoesHere"
Second line of code just reissues the request.
Of course, the YourWB2sDocumentNameOrTargetFrameNameGoesHere is the TargetFrameName (or the frame or document name of the top level document, or any iframe, in your WB2 control/window). This can usually be found in the BODY tags name= property, but you don't even need to do this if all you want is to load it as the top level document in WB2... if you just want to load it as the parent top level document in WB2, just do this...
Cancel = True
WB2.Navigate2 URL
By referencing WB2 it will just send the same URL request to WB2 window after cancelling WB1 request.
Let me know if you need more help and let me know how you get along.
Related
I'm creating a Firefox add-on with the Firefox Add-on SDK. This add-on does two things:
Inject a content script into every page with sdk/page-mod.
Add a context menu item using sdk/context-menu.
I want that when user clicks the context menu item, the add-on will call functions in the content script which was loaded by PageMod().
Unless your page-mod script is doing other things, it sounds like it might be more appropriate to load it using the context-menu contentScript or contentScriptFile properties. Alternately, load the portions of it that are needed by the context menu using this methodology. How best to split the script you are using depends on what you are actually doing. Without more information from you it is difficult to provide specific recommendations.
Communicating between content scripts loaded at different times or by different methods:
There is no method of directly doing what you desire. Content scripts that are not loaded at the same time by the same methodology are loaded into different contexts. They are unable to directly call functions between them. Multiple content scripts which are loaded at the same time and the same methodology share the same context/scope and can directly call functions between them.
However, you can communicate between content scripts. If they are not loaded into the same page, then you will need to communicate from one content script to another by using your main add-on script to first receive a message from one content script. Then, your main add-on script will need to send a second message (potentially containing exactly the same data) to the second content script. In other words, your main add-on code would need to relay the message between the two content scripts.
For content scripts that are loaded into the same page via different methods (e.g. one with page-mod and another as a context menu item – the situation in which you are interested), you can communicate directly between them using the DOM postMessage() API or a CustomEvent. Either can be used to send whatever JSON serializable data you desire between the two scripts. The DOM postMessage() API provides for more security, but is a bit more complex. With it you must also filter out any other "message" events that are sent on it by random code. It should probably be used if you are going to have code in a released add-on execute functions based on the content of the messages. This is a security issue which will depend on exactly what you are doing with the messages.
Example:
The following code will load a page-mod script into every page that matches "*.mozilla.org". It also creates a context menu item in those same pages which is displayed on links. Clicking on the context menu item will send an event from the context-menu content script with data containing the URL for which the context menu was displayed. The custom event will be received by the page-mod script. The page-mod script will then issue an alert with the URL for the link.
var pageMod = require("sdk/page-mod");
pageMod.PageMod({
include: "*.mozilla.org",
contentScript: 'function contextMenuAlert(href) {'
+ ' window.alert("The context menu click on a link with URL:\\n" + href);'
+ '};'
+ 'window.addEventListener("myAddonId-contextMenu-clicked",'
+ ' function(event){contextMenuAlert(event.detail);});'
});
//Context menu
let cm = require("sdk/context-menu");
cm.Item({
label: "Alert link URL",
context: [
cm.URLContext(["*.mozilla.org"]),
cm.SelectorContext("a[href]")
],
contentScript: 'self.on("click", function (node, data) {'
+ ' var event = new CustomEvent("myAddonId-contextMenu-clicked",'
+ ' {detail:node.href});'
+ ' window.dispatchEvent(event);'
+ '});'
});
The above code produces a context menu that looks like:
When clicked on, the page-mod added content script initiates the following alert:
Using the message sent to choose from multiple different functions:
The information passed through the event can be expanded to allow multiple different functions to be called depending on the content. One method of doing this is to send an object as the message. One property of the object can be the function desired and another can be data to use in that function. My answers to the following questions contain examples of doing this:
Add menu item created with the sdk/context-menu API to the top of the context menu: This answer has code which uses the same passed message to indicate that either a click was made on a context menu item and pass the URL on which the context menu item was clicked, or to tell the main script that the context menu is about to be displayed so it can be modified.
How to console.log from ChromeWorker (alternative to dump): This answer shows sending a message that will result in a call to one of a variety of different functions and pass data to the function which was called. It was implemented as a way of using console methods from a worker with just console.log("message"). I'd code this one a bit differently were I doing it today, but it works and demonstrates the concept.
Because the documentation on MDN (here and here) was not very clear on content script to content script communication, I have updated the pages I found on which it was discussed. I have also added the above code as an example.
I have web browser control which contains many links and data. All these data are coming from web service.
Now i want open another web browser control when i click on first web broser link.
so how it can be done?
my first web broser code is :
webBrowser1.NavigateToString(htmlCode);
You could have another webBrowser hidden under webBrowser1. Lets call it webBrowser2. Now when a user hits a link on webBrowser1, capture it a string lets say link. Now you can navigate to link using webBrowser2.Navigate(new Uri(link,UriKind.Absolute));. Do not forget to make webBrowser1 hidden and webBrowser2 visible.
If i understand you, you want to intercept the onClick event in your first WB control (call this WB1), and open that page up (when the hyperlink is clicked) in another WB control (call this WB2)?
There are several ways you can do this, is this link set to open up in a new window? If so, you can intercept the NewWindow2 event is WB1 and run the following code in the NewWindow2 event of WB1...
Set pDisp = WB2.object
(it may be ppDisp instead of pDisp, but it will show up when your event is auto generated, choose whichever object name shows up in your arguments list).
Otherwise, you can intercept this request during BeforeNavigate2 event of the WB1 event, check the URL property if it is the link you're interested in, and if so, cancel the current request and reissue a new one as below... (in the WB1 BN2 event)...
Cancel = True ' This cancels the request
WB2.Navigate2 URL, , "YourWB2sDocumentNameOrTargetFrameNameGoesHere"
Second line of code just reissues the request.
Of course, the YourWB2sDocumentNameOrTargetFrameNameGoesHere is the TargetFrameName (or the frame or document name of the top level document, or any iframe, in your WB2 control/window). This can usually be found in the BODY tags name= property, but you don't even need to do this if all you want is to load it as the top level document in WB2... if you just want to load it as the parent top level document in WB2, just do this...
Cancel = True
WB2.Navigate2 URL
By referencing WB2 it will just send the same URL request to WB2 window after cancelling WB1 request.
Let me know if you need more help and let me know how you get along.
is it possible to delay loading of some controls on an xpage?
This is the problem: let's say you have a control that does a fultextsearch and displays the result in a repeat control. this ft search might take a long time and will hold the webpage loading in a waiting state until the search result is ready.
I want my page to load most of the data initally, and some "time consuming" controls should be loaded in to the page as a sperate request after the inital load.
this way the user will immediatly see the webpage, but some of the data on the page will load a little bit later without holding the webpage in a waiting state from the server.
possible?
The downside to using rendered is that all the value bindings will still evaluate, even if the corresponding markup isn't sent to the page. So the trick here is making sure the components don't even exist until you want them to.
Every component has a getChildren() method. This returns a mutable List of components, which has a add() method. This allows you to add components to the page on the fly, either while the page is loading, or later during an event. For the purposes of what you're trying to do, you would want to defer adding the "expensive" components until a subsequent event.
Create an event handler attached directly to the view root (), give it a unique ID (e.g. "loadExpensiveComponentsEvent", set its refresh mode to partial, set a refresh ID to whatever div or panel will contain the search results, and set its event name to an arbitrary event (e.g. "loadExpensiveComponents"). This prevents your event from being triggered by actual user behavior. Set the event's code to SSJS that will inject your components.
Then add a script block () to trigger the event after the page has loaded:
XSP.addOnLoad(function(){
XSP.firePartial(null, "#{id:loadExpensiveComponentsEvent}");
});
Your page will load without the search result components. Once the page has fully loaded, it will trigger the component injection event automatically.
For guidance on how to code the injection event, open the Java file that has been generated from your existing page to see what components need to be injected and what to set their values to.
You can pack them into a panel and set their rendered status to rendered=#{viewScope.pageFullyLoaded}. Then in the onLoad event have a XSP. partialRefresh request where you set viewScope.pageFullyLoaded=true
A little ugly but doable. Now you can wrap that code into your own custom control, so you could have a "lazyGrid", "lazyPanel" etc.
Not sure why I did not think of this before. the dynamic content control in extlib actually solves this problem. the dcc can be triggered onClientLoad both using javascript and ssjs afer the page has loaded.
one problem I am facing now is that I am already using the dcc on my site so I need to put another dcc within my dcc. and this seem to be a bit buggy. I have reported it to the extlib team on openNTF.
I have an app that has several different types of form elements which all post data to the server with jQuery AJAX.
What I want to do is:
Show a loader during AJAX transmission
Prevent the user from submitting twice+ (clicking a lot)
This is easy to do on a one off basis for every type of form on the site (comments, file upload, etc). But I'm curious to learn if that is a more global way to handle this?
Something that's smart enough to say:
If a form is submitting to the server and waiting for a response, ignore all submits
Show a DISABLED class on the submitted / clicked item
Show a loading class on the class="spinner" which is closest to the submit item clicked
What do you think? Good idea? Done before?
Take a look at the jQuery Global Ajax Event Handlers.
In a nutshell, you can set events which occur on each and every AJAX request, hence the name Global Event Handlers. There are a few different events, I'll use ajaxStart() and ajaxComplete() in my code sample below.
The idea is that we show the loading, disable the form & button on the ajaxStart() event, then reenable the form and hide the loading element inside the ajaxComplete() event.
var $form = $("form");
$form.ajaxStart(function() {
// show loading
$("#loading", this).show();
// Add class of disabled to form element
$(this).addClass("disabled");
// Disable button
$("input[type=submit]", this).attr("disabled", true);
});
And the AJAX complete event
$form.ajaxComplete(function() {
// hide loading
$("#loading", this).hide();
// Remove disabled class
$(this).removeClass("disabled");
// Re-enable button
$("input[type=submit]", this).removeAttr("disabled");
});
You might need to attach to the ajaxError event as well in case an AJAX call fails since you might need to clean up some of the elements. Test it out and see what happens on a failed AJAX request.
P.S. If you're calling $.ajax or similar ($.getJSON), you can still set these events via $.ajaxStart and $.ajaxComplete since the AJAX isn't attached to any element. You'll need to rearrange the code a little though since you won't have access to $(this).
I believe you have to do 2 for sure and 3 to improve usability of your app. It is better to keep backend dumb but if you have a security issue you should handle that too.
I've been working on Chrome Extension for a website for the past couple of days. It's coming along really nicely but I've encountered a problem that you might be able to help with.
Here's an outline of what the extension does (this functionality is complete):
A user can enter their username and password into the extensions popup - and verify their user account for the particular website
When a user browses http://twitter.com a content script is dynamically included that manipulates the DOM to include an extra button next to each tweet displayed.
When a user clicks this button they are presented with a dialog box
I've made a lot of progress but here is my problem:
When a user visits Twitter the content script is activated and all tweets on the page get my new button - but if the user then clicks 'More...' and dynamically loads the next 20 tweets... these new additions to the page DOM do not get affected by the content script (because it is already loaded).
I could add an event listener to the 'More...' button so it then triggers the original content script again (and adds the new button) but i would have to predict the length of twitter's ajax request response.
I can't tap into their Ajax request that pulls in more tweets and call my addCurateButton() function once the request is complete.
What do you think is the best solution? (if there is one)
What you want to do is to re-execute your content-script every time the DOM is changed. Luckily there is an event for that. Have a look at the mutation event called DOMNodeInserted.
Rewrite your content script so that it attaches an event listener to the body of the DOM for the DOMNodeInserted event. See the example below:
var isActive = false;
/* Your function that injects your buttons */
var inject = function() {
if (isActive) {
console.log('INFO: Injection already active');
return;
}
try {
isActive = true;
//inject your buttons here
//for the sake of the example I just put an alert here.
alert("Hello. The DOM just changed.");
} catch(e) {
console.error("ERROR: " + e.toString());
} finally {
isActive = false;
}
};
document.body.addEventListener("DOMNodeInserted", inject, false);
The last line will add the event listener. When a page loads the event is triggered quite often so you should define a boolean (e.g. var isActive), that you initialize to false. Whenever the inject function is run check whether isActive == true and then abort the injection to not execute it too often at the same time.
Interacting with Ajax is probably the hardest thing to coax a content script to do, but I think you’re on the right track. There are a couple different approaches I’ve taken to solving this problem. In your case, though, I think a combination of the two approaches (which I’ll explain last) would be best.
Attach event listeners to the DOM to detect relevant changes. This solution is what you’ve suggested and introduces the race condition.
Continuously inspect the DOM for changes from inside a loop (preferably one executed with setInterval). This solution would be effective, but relatively inefficient.
The best-of-both-worlds approach would be to initiate the inspection loop only after the more button is pressed. This solution would both avoid the timing issue and be efficient.
You can attach an event-handler on the button, or link that is used for fetching more results. Then attach a function to it such that whenever the button is clicked, your extension removes all the buttons from DOM and starts over inserting them, or check weather your button exists in that particular class of DOM element or not and attach a button if it doesn't.