Web browser control, modal window/popup to STAY INSIDE web browser control for Visual Studio 2015/Visual Basic 2015 - vb.net

this is the first time I'm posting a question here; I have searched and searched and searched here and other places and I cannot seem to get any results. I'm using VISUAL BASIC 2015 in Visual Studio 2015. QUESTION: I need to have a modal window/popup from a particular website remain INSIDE the web browser control/window on my form (WebBrowser1); when a particular link is clicked, the modal window/popup jumps out of the form and directly to the user on their screen. I have to keep this popup inside because there are other links to be clicked on that popup, but if it jumps out of the web browser control, no code will work since it's outside WebBrowser1. What I have found is code for older versions, and not 2015; if anything I can even add WebBrowser2 to have the popups/modal windows appear there if possible, just as long as I can code them to keep clicking inside the form. PLEASE HELP! THANK YOU!

window.open (and a click on <a target="_blank"> etc) can be handled via the NewWindow2 event. Hans already pointed out how to do that in comments. NewWindow3 works too, but need at least Windows XP SP2.
As for window.showModalDialog, it is a bit tricky. IE has IDispatchEx (wrapped as IExpando in .Net) implemented on scripting objects so you replace the methods and properties with your own implementation. But window.showModalDialog shows a dialog that has arguments and return values, you need to override those properties in the modal dialog you create too. The code looks roughly like tis:
void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
//skip events from frames
if(WebBrowserReadyState.Complete!=webBrowser1.ReadyState) return;
if(FindLoginFormOnPage()) {DoLogin();return;}
if(IsWelcomePage()){NavigateToPage1();return;}
if(IsPage1()){SubmitFormOnPage1();return;}
if(IsPage1FormResult()){
var document=webBrowser1.Document.DomDocument as mshtml.ITMLDocument2;
var expando =(IExpando)document.parentWindow;
expando.RemoveMember(expando.GetMethod("showModalDialog"
,BindingFlags.Instance | BindingFlags.Public);
expando.AddMethod("showModalDialog"
,new ShowModalDialogDelegate(this.MyShowModalDialog));
}
......
}
object MyShowModalDialog(string url, object varArgIn, object options)
{
using(FromMyShowModalDialog myShowModalDialog
=new MyShowModalDialog())
{
myShowModalDialog.StartupUrl=url;
myShowModalDialog.DialogArguments=varArgIn;
//omit the code to parse options
//and set dialog height/width/topleft location etc
if(myShowModalDialog.ShowDialog()==DialogResult.OK)
{
//do something on the return value before passing to the scripts
......
return myShowModalDialog.ReturnValue;
}
return null;
}
}
and in the Load event handler of MyShowModalDialog you call something like webBrowser1.Navigate to show the page requested by the parent page.
Now you need to pass the arguments to the webbrowser control on the new form. Do the same as above but replace another property this time.
expando.RemoveProperty("dialogArguments");
expando.AddProperty("dialogArguments")
.SetValue(expando,this.DialogArguments);
This will let the web page access the value passed from MyShowModalDialog and stored in this.DialogArguments.
The earliest you can access the DOM is in webBrowser1_DocumentCompleted. By that time the scipts on the page that read window.dialogArguments are probably already executed and got nothing. After overriding window.dialogArguments, you need to study the script on the page to find out how to revert that. for example, if the page has
<head>
<script>
var oMyObject = window.dialogArguments;
var sFirstName = oMyObject.firstName;
var sLastName = oMyObject.lastName;
</script>
...
<span style="color: 00ff7f">
<script>
document.write(sFirstName);
</script>
</span>
you need to change the values of sFirstName and sLastName then change the innerText property of the span, probably identify via its relationship with a named div or table cell. You can write the necessary changes in a script and call it via HtmlDocument.InvokeScript.
If the page returns a value to its parent, you need to pass it on to your parent form too. Override window.returnValue so when the script writes to window.returnValue it writes to a variable you provided
......
expando.RemoveProperty("returnValue");
expando.AddProperty("returnValue").SetValue(expando,this.ReturnValue);

Related

CKEditor 5 copy selected content from one editor to another

I have two editors on the screen, one read-only. What I want to do is allow the user to select content from the read-only editor and paste it into the current position of the other by clicking a button. (the logic may manipulate the text which is one reason I don't want to use the system's clipboard.)
So far I have the function that is able to paste the text like as follows. (I am using the Angular wrapper which explains the presence of the CKEditorComponent reference.
doPaste(pasteEvent: PasteEvent, editorComponent: CKEditorComponent) {
const editor = editorComponent.editorInstance;
editor.model.change(writer => {
writer.insertText(pasteEvent.text, editor.model.document.selection.getFirstPosition() );
});
}
What I can't find from the documentation is how to extract the selected text. What I have so far is:
clickPasteSelectedPlain(editorComponent: CKEditorComponent) {
const editor = editorComponent.editorInstance;
const selection = editor.model.document.selection;
console.log('clickPasteAll selection', selection);
console.log('clickPasteAll selectedcontent', editor.model.document.getSelectedContent);
}
The selection appears to change depending on what is selected in the editor's view. The getSelectedContent function is undefined. How do I get the content?
With a bit of poking around I figured out how to do this. I'll document it here on the chance that it will help someone down the road avoid the process of discovery that I went through.
On the source document I have a ckeditor element like this:
<div *ngIf="document">
<ckeditor #ckEditor
[editor]="Editor" [config]="ckconfig" [disabled]="true"
[(ngModel)]="document.text"></ckeditor>
<button mat-flat-button (click)="clickPasteSelectedPlain(ckEditor)">Paste Selected Text Plain</button>
</div>
In the component the function called on the click event is like this:
#Output() paste = new EventEmitter<PasteEvent>();
...
clickPasteSelectedPlain(editorComponent: CKEditorComponent) {
const editor = editorComponent.editorInstance;
this.paste.emit({
content: editor.model.getSelectedContent(editor.model.document.selection),
obj: this.document,
quote: false
});
}
The PasteEvent is defined as an exported interface which I will omit here to save space. The content key will refer to a DocumentFragment.
Note that I am passing the CKEditorComponent as a parameter. You could also access it via an Angular #ViewChild declaration but note that my ckeditor is inside an *ngIf structure. I think that works well in Angular 6 but in the past I have had difficulty with #ViewChild references when the target was conditionally in the DOM. This method always works but use whatever method you want.
The event fired by the emit is processed with a method that looks like this:
doPaste(pasteEvent: PasteEvent, editorComponent: CKEditorComponent) {
const editor = editorComponent.editorInstance;
editor.model.insertContent(pasteEvent.content);
}
Because the content is a DocumentFragment the paste operation will include all formatting and text attributes contained in the selected source. But that's all there is to it.

Can HTAs be used to automate web browsing?

I am new to HTAs. I just read https://msdn.microsoft.com/en-us/library/ms536496%28v=vs.85%29.aspx and am a bit confused.
Can I use HTAs to automate browsing? Say I want to download a web page and fill in a form automatically, i.e. from a script. How would an HTA help me do this, if at all? It's important that the JavaScript code in the downloaded page is run as usual. I should be able to enter somehow and fill in the form after it has finished initializing, just as if I were a human agent.
First, you need to open an IE window, as follows:
var IE = new ActiveXObject("InternetExplorer.Application");
Then navigate the IE window to the webpage you want:
IE.Navigate("www.example.com");
Wether your IE window is visible or invisible, it's up to you. Use Visible property to make it visible:
IE.Visible = true;
Then, you should wait until the webpage is completely loaded and then run a function that takes your desired actions. To do so, first, get the HTML document object from the webpage using Document property of IE object, then repeatedly check the readyState property of document object. In the code below, it is assumed that you have a function named myFunc, which takes your desired actions on the webpage. (For example, modifying the contents of the webpage.)
var doc = IE.Document;
interval = setInterval(function() {
try
{
if (doc.readyState == "complete")
{
myFunc();
clearInterval(interval);
}
}
catch (e) {}
}, 1000);
In the function myFunc, you can do anything you want with the webpage since you have HTML document object stored in doc variable. You can also use parentWindow property to get the HTML window object.

Dynamic menu button items in TinyMCE

I have a custom menubutton in my tinyMCE editor that uses specific HTML elements elsewhere on the page as the menu items. I use a jQuery selector to get the list of elements and then add one each as a menu item:
c.onRenderMenu.add(function(c,m) {
m.add({ title: 'Pick One:', 'class': 'mceMenuItemTitle' }).setDisabled(1);
$('span[data-menuitem]').each(function() {
var val = $(this).html();
m.add({
title: $(this).attr("data-menuitem"),
onclick: function () { tinyMCE.activeEditor.execCommand('mceInsertContent', false, val) }
});
});
});
My problem is that this only happens once when the button is first clicked and the menu is first rendered. The HTML elements on the current page will change occasionally based on user clicks and some AJAX, so I need this selector code to run each time the menu is rendered to make sure the menu is fully up-to-date. Is that possible?
Failing that, is it possible to dynamically update the control from the end of my AJAX call elsewhere in the page? I'm not sure how to access the menu item and to update it. Something using tinyMCE.activeEditor.controlManager...?
Thanks!
I found a solution to this problem, though I'm not sure it's the best path.
It doesn't look like I can make tinyMCE re-render the menu, so instead I've added some code at the end of my AJAX call: after it has updated the DOM then it manually updates the tinymce drop menu.
The menu object is accessible using:
tinyMCE.activeEditor.controlManager.get('editor_mybutton_menu')
where mybutton is the name of my custom control. My quick-and-dirty solution is to call removeAll() on this menu object (to remove all the current menu items) and then to re-execute my selector code to find the matching elements in the (new) DOM and to add the menu items back based on the new state.
It seems to work just fine, though tweaks & ideas are always welcome!

Instantiating dijit.Dialog from a template I can't get it to initialize properly

In Dojo, I am trying to extend dijit.Dialog using templates. When I instantiate it, I get only the text in the dialog box, without the borders or close button. Is there some additional step I need to do to get it fully initialized?
My template is in template.html, it looks like so:
<div dojoType="dijit.Dialog" id="dynFilter" jsId="dynFilter">
"Dynamic Dialog"
</div>
Here is the dojo.declare:
dojo.declare(
"template.dialog", // class name
[dijit._Widget, dijit._Templated, dijit.Dialog], // parent classes
{
templateString : dojo.cache("autonomics", "template.html"),
}
);
After I instantiate it, I call .startup(), which doesn't seem to do anything, then .show(), which does place it on the page, missing most of its functionality.
var dialog = new template.dialog();
dialog.startup();
dialog.show();
What am I missing?
You overwrite the template of the original dijit/Dialog when subclassing.
Have a look to my answer to Dojo Dialog with confirmation button which solves the issue you are experiencing. Or go directly to working example at jsFiddle: http://jsfiddle.net/phusick/wkydY/

SharePoint 2010 Modal Dialog from JSOM not working

The idea is simple: create a web part page in SP Designer 2010 that allows a new list item to be created, and then use some javascript from the CSOM to pop the page in a modal dialog from another page. The problem is that a dialog box comes up and briefly flashes that it is loading content, but then it disappears and I'm left with a refreshed version of the page I just clicked from. Here's my code . . .
//attach a click delegate to the table containing the following button(s)
<button type='button' class='ms-listheaderlabel'>Close</button>
//on button clicked event, call the following function
function openModalDialog(dialogPage, closeCallback) {
var options = [];
options.title = unescape("Close Ticket");
options.allowMaximize = true;
options.showClose = true;
options.autoSize = true;
options.url = dialogPage;
options.dialogReturnValueCallback = Function.createDelegate(null, closeCallback);
SP.UI.ModalDialog.showModalDialog(options);
};
. . . where dialogPage is the url for the form I created (same site, SitePages library) and closeCallback is an anonymous function passed in to handle the return value from the dialog. I've tried calling the page directly and it loads just fine. Pop up blocker is completely off. Using IE9 and tried 8 compatability mode as well as another machine with straight IE8. System modals work just fine. Any ideas out there?
I am going through the exact same issue right now. What I have discovered so far is if I use
<input type="button" value="Try Me" onclick="openModalDialogBox()" />
it works as expected. But if I use an asp:button to do the same thing it fails. I think it may have to do with the postback to the server, but I could be wrong about that.
I am just switching my buttons to inputs.
Tim