How to interact and set DOM properties with WebSharper? - javascript

I often need to interact with my page's DOM, how can I do it via WebSharper?
For instance when I want to redirect my page in just JavaScript I'd run:
window.location = "http://www.google.com/";
How can I access window and set location? how would this look in F#?
Also, how would it work with functions, for instance with IE's:
window.navigate("http://www.google.com/")
Note: If there is a built-in way to redirect via WebSharper I'd love to know it but keep in mind this is just an example.

You can access the window.location property after opening the IntelliFactory.WebSharper.Html5 namespace which provides support for the standard HTML5 APIs. In order to navigate using the location object you can call the assign or replace methods:
Window.Self.Location.Assign "http://www.google.com/"
A live demo is available here.
For vendor specific functions you can inline the JavaScript and use it as if it was built into WebSharper:
[<Inline "window.navigate($uri)">]
let ieNavigate uri = X<unit>

Related

What is the difference between window.location and $location.path?

In MVC angularJS application, how can I redirect to MVC page.
I tried below two options
First
// It doesn't work
$location.path("/MyPage1");
Second
//It works
window.location = "/MyPage1";
Please suggest best way to redirect and why ?
REMEMBER : I am not using angularJs Routing.
Comparing $location to window.location official doc clearly stated
see the section at this location
seamless integration with HTML5 API
window.location: no
$location: yes (with a fallback for legacy browsers)
and more
Both do have their own merits. They are clearly described in the official docs as mentioned by #Mohammad. So depending on the circumstances choose any of the either :
Use $location : When you do not require a full page reload when the browser URL is changed, wants to avail the angular internal life-cycle benefits and where you don't need to support old legacy browsers.This might be useful if your destination is just a variation on the current URL, so that you can take advantage of $location helper methods. E.g. we ran $location.search(..., ...) to just change value of a querystring paramater.
Use native window location : When you need to change the URL and reload the page or navigate to a different page, please use a lower level API: window.location.href or when you want to work with row level object properties that you can directly modified. i.e like Force reload window.location.reload().

Dynamics 2013 Accessing Page entities is hard to access with iframe based views

I am building an angular application which is running as a web resource on Dynamics 2013.
The application runs using a button which is added to the commandContainer using Ribbon workbench which then that button calls a Xrm.Internal.openDialog
All this works fine until I want to start using the Entities exposed by Xrm.Page.Data
Basically my button runs in the context of the main page of dynamics however the Entities are inside an iframe which based on the page I am in has a different Id and name.
So using a simple selector I can not get its contentWindow and start using the Entities.
The #crmContentPanel always has few iframes in it starting from #contentIFrame0 to #contentIFrame(n) and I can never know which iframe is the one with Entities in it.
What is the best practice, associated work flow with developing applications in this environment? How can I easily and reliably access the correct frame which holds the main page entities and work with them.
Perhaps the script is in the wrong location and needs to injected into the main content area so it has direct access to the correct Xrm? How can I achieve that?
Furthermore once I eventually manage to access this data, how can I easily pass this data to my angular application which runs in the dialog as from the documentation I read that the dialog is only allowed 1 query string param and it has to be called data. That would not be enough for my application to start using $routeParams. And I don't think using local or session storage is nice practice. What is the correct approach in this situation.
Sample code of my button script:
function runSendSender() {
// Content Iframe Entity data:
var contentFrameXrm = $('#crmContentPanel')
.find("iframe#contentIFrame0...n")[0]
.contentWindow['Xrm'];
// even if above selector was consistent across pages
// I need to send over much more than this one Id :(
var data = contentFrameXrm.Page.data.entity.getId();
var src = "/WebResources/concep_/ConcepDynamicsApp/ConcepDynamicsApp.html?data=" + data;
var DialogOptions = new Xrm.DialogOptions();
DialogOptions.width = 800;
DialogOptions.height = 500;
Xrm.Internal.openDialog(src, DialogOptions, null, null, CallbackFunction);
function CallbackFunction(returnValue) { }
}
Little more detail
When I type the following in the console I can sometimes (randomly) read the title of the form:
$('#crmContentPanel').find("iframe#contentIFrame0")[0].contentWindow['Xrm'].Page.ui.get_formTitle();
But the same code from the associated web resource function can not access the iframe and errors:
Can not Cannot read property 'contentWindow' of undefined.
Why is the iframe not accessible via the resource script and how can I access the correct context and form title/id.
I'm usually including following JavaScript file to the header of the custom WebResource that need to have an access to the CRM specific actions / information:
<script src="ClientGlobalContext.js.aspx" type="text/javascript"></script>
This gives access to some none-entity specific information, such as Xrm.Page.context.getServerUrl() or Xrm.Page.context.getUserId() for example.
But if you added layer with your own iFrame on top of the standard entity page, you definitely can access to information underneath your current context by using following construction:
window.parent.Xrm.Page.data.entity.attributes.get("name").getValue();
Note the window.parent prefix.
The record Id can be sent to runSendSender as parameter by the ribbon itself. Just add the appropriate CrmParameter (MSDN) to the function call.
In your case, the parameter value would be FirstPrimaryItemId ("Provides one GUID identifier as a string for the record being viewed.")
After that, you'll have your function changed like this
function runSendSender(recordId) { ... }
Also, stay out from internals: to open a web resource in a dialog, you should use the supported way (link provides info about passing parameters other than data to the resource).
Xrm.Utility.openWebResource(webResourceName,webResourceData,width, height)

creating custom web interface app using node-webkit and manipulating DOM with Javascript

I want to create a custom web interface/app to a web site. Basically a streamline/custom view of important summary data. The data can be cached locally in the app and updated weekly if there are changes to the source site. I am using two windows. One window I load the html from remote site, the second window I manipulate the DOM/tables of the first window using Javascript to only display information that is important. If there is a better way or tool to do this as I have not found it yet. I am having problems with Javascript not being able to manipulate the DOM of the first window.
Im trying to edit/format the DOM (hide/delete table rows change colors) in the 2nd window from javascript running in the first window (startup node-webkit).
Docs say that I should have universal access to the other windows? How do I make sure this is true?
var gui = require('nw.gui');
var new_win = gui.Window.get( window.open('http://example.com/index.html'));
var my_elem = new_win.document.getElementById('myelement');
my_elem.style.display='none';
Type Error: Cannot read property of 'getElementById' of undefined
Any ideas?
In order to access the document property of the new window you have to access it in the window key.
Basically change your line 3 to this:
var my_elem = new_win.window.document.getElementById('myelement');

Identify requests coming from PageWorker

Is it possible, from within the "http-on-modify-request" event, to identify which requests are coming from a PageWorker object, as opposed to those coming from visible tabs/windows?
Note: Because of redirects and subresources, the URL here is NOT the same URL as the pageWorkers contentURL property.
require("sdk/system/events").on("http-on-modify-request", function(e) {
var httpChannel = e.subject.QueryInterface(Ci.nsIHttpChannel),
url = httpChannel.URI.spec,
origUrl = httpChannel.originalURI.spec;
...
});
I don't know of any way to actually distinguish page-worker requests from "regular" ones.
Current, page workers are implemented like this:
The SDK essentially creates an <iframe> in the hiddenWindow (technically, in sdk/addon/window, which creates a hidden window in the hiddenWindow). The hiddenWindow in mozilla applications is more or less an always-present top-level XUL or HTML window that is simply hidden.
The worker page is loaded into that iframe.
The page-worker will then operate on the DOM on that iframe.
It is possible to identify requests originating from the hidden window and the document within the hidden window.
But identifying if the request or associated document belongs to a page-worker, let alone which page-worker instance, doesn't seem possible, judging from the code. The SDK itself could map the document associated with a request back to a page-worker, as it keeps some WeakMaps around to do so, but that is internal stuff you cannot access.
You only can say that a request is not coming from a page-worker when it is not coming from the hiddenWindow.
Also, keep in mind that there are tons of requests originating neither from a tab nor page-worker: Other (XUL) windows, add-ons, js modules and components, etc...
If it a page-worker created by your add-on that you're interested in: The contentURL property should reflect the final URI once the page is loaded.

Can i detect and prevent JavaScript-driven redirect from within Firefox extension?

Basically, i want to make Firefox obey "Warn me when web sites try to redirect or reload the page" user preference. Currently, this is really open sesame for any kind of doorway writers etc.
Please find the detailed description of this misbehaviour in related superuser post.
You can use Object.watch() to intercept changes of some properties like window.location:
function onLocationChange(id, oldval, newval)
{
if (confirm("Do you want to navigate to " + newval + "?"))
return newval;
else
return oldval;
}
wnd.watch("location", onLocationChange);
wnd.document.watch("location", onLocationChange);
wnd.location.watch("href", onLocationChange);
You would have to similarly intercept assignments to other window.location properties like host or pathname. The big disadvantage of this approach: there can be only one watcher. If the page installs its own watcher or simply calls wnd.unwatch("location") all your detection will be gone.
How to get to the window before any page JavaScript has a chance to run depends on whether you are using the Add-on SDK or whether you have a classic add-on. If you are using the Add-on SDK then you use the page-mod module with contentScriptWhen parameter set to start. In the code example above you replace wnd by unsafeWindow (the window has to be accessed directly, otherwise it won't work).
In a classic add-on you register an observer for the content-document-global-created notification. Here you also have to access the window directly:
var wnd = XPCNativeWrapper.unwrap(subject);
See documentation on XPCNativeWrapper.unwrap().
A "JavaScript-driven redirect" would be done by using the window.location property. All you would need to do is replace that property's setter function as soon as the page loads.
Here is a John Resig blog post on defining setters and getters for properties. http://ejohn.org/blog/javascript-getters-and-setters/
I wasn't able to override the default window.location setter using client side js, but it may be possible using a more privileged extension environment though.

Categories

Resources