how to get selected text in webbrowser control - c#

I am able to get the selected text of a webbrowser control in WPF by the following:
IHTMLDocument2 doc1 = webBrowser.Document as IHTMLDocument2;
IHTMLDocument3 doc = webBrowser.Document as IHTMLDocument3;
IHTMLSelectionObject currentSelection = doc1.selection;
if (doc1.selection.type == "Text")
{
IHTMLTxtRange range = (IHTMLTxtRange)doc1.selection.createRange();
}
This works just fine and if I set the value of range.text to something else it changes the value of the text. The only issue I'm having is on web pages such as Gmail that have some kind of WYSIWYG editor on it, the selection.type is always 'None'. I suspect it is because the text editor is technically a child document. I'm not sure how to find child documents and check to see if text is selected. Can anyone help me? Thanks!

You could check if document.activeElement is a frame and has contentWindow property (document.activeElement.contentWindow != null) Then you could use contentWindow.document to get to the frame's inner document. Do this recursively until you find a frame with document.selection != null.
To illustrate this:
main.html:
<!DOCTYPE html>
<body>
<iframe src="iframe.html"></iframe>
</body>
iframe.html:
<!DOCTYPE html>
<head>
<script>
window.onload = function()
{
window.focus();
document.execCommand("SelectAll", false);
}
</script>
</head>
<body contentEditable="true">
This is editable
</body>
C#:
var text = this.wb.Document.InvokeScript("eval", new object[] {
"document.activeElement.contentWindow.document.selection.createRange().text" });
MessageBox.Show(text.ToString());
Shows:
This is editable

Related

WPF play youtube video

I'm trying to embed a youtube video into WebBrowser, however, it shows just a blank screen
<WebBrowser util:WebBrowserUtility.BindableSource="{Binding UrlContent}"/>
DI:
public static void BindableSourcePropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
WebBrowser browser = o as WebBrowser;
if (browser != null)
{
string uri = e.NewValue as string;
if (string.IsNullOrEmpty(uri)) return;
browser.NavigateToString(uri);
}
}
Output:
Tried:
Formated HTML
<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>
<html>
<head>
</head>
<iframe width='560' height='315' src='http://www.youtube.com/embed/diB65scQU' frameborder='0' allowfullscreen></iframe>
<body>
</body>
</html>
Plain Link => http://www.youtube.com/embed/diB65scQU
http://www.youtube.com/embed/diB65scQU
Results - the same - just a blank view
Any ideas why?
You can use WebView2 control instead, it is an official replacement, take a look WebView2.
See WebView2Samples on github

How to return data from aspx page to RTF field?

I am customizing the ribbon toolbar and adding a button to it.Whenever I click on that button,it will open a aspx page allows authors to select some data, which gets appended to the
existing RTF field content.
Our requirement is to return the data as link i.e anchor element, whenever author clicks the link-popup page has to be opened and allow author to select the other options; upon clicking of submit button new value must be replaced with old value.
Challenges are:
Currently popup page is opened by a javascript- which is an entry point to display the aspx page. Author selects data and submit, it is this javascript which returns the value and appended to RTF field.
Now when the popup page is opened as a independent page, how to return the data from it.
Early response will be appreciated.
Thanks in advance.
If its just appending content to an RTF field, wouldn't it be a lot less work to use a Custom URL for that?
A Custom URL is a link which you can set on the Schema field which will show in the Component as a link on the title of that field. This will open a popup with the specified URL and from there you can return directly to the field (allowing you to add to, or replace existing content).
Documentation on this topic can be found on http://docportal.sdl.com/sdltridion (direct topic link)
An example Custom URL HTML page for overwriting or appending content to a text field would look something like this:
<html>
<head>
<title>Custom URL example</title>
<style>
body {
background:#fafafa;
font-family:arial,helvetica,sans-serif;
font-size:12px;
line-height:1.5em;
}
a {
color:#000;
font-weight:bold;
text-decoration:none;
}
a:hover {
color:#666;
}
</style>
<script type="text/javascript" language="javascript" src="/WebUI/Core/Controls/Popup/PopupInit.js"></script>
<script language="JavaScript">
function overwrite(value) {
var fields = window.dialogArguments.getFields();
if (fields && fields.length > 0) {
if (fields[0].getValues() != null && fields[0].getValues()[0] != null && fields[0].getValues()[0].length > 0) {
if (!confirm('This will overwrite the existing content of the field. Continue?')) {
return;
}
}
fields[0].setValues([value]);
window.close();
}
}
function append(value) {
var fields = window.dialogArguments.getFields();
if (fields && fields.length > 0) {
var current = '';
if (fields[0].getValues() != null && fields[0].getValues()[0] != null && fields[0].getValues()[0].length > 0) {
current = fields[0].getValues()[0];
}
fields[0].setValues([current + value]);
window.close();
}
}
</script>
</head>
<body>
<h1>Make a choise</h1>
<p>overwrite current value</p>
<p>append to current value</p>
</body>
</html>
This is an HTML page which you should place somewhere in the ..\Tridion\web folder (I usually create a CustomURL sub directory in there, so you can reference it like: /CustomUrl/example.html)

How do I detect multitouch actions in a Windows 8 metro app?

I am working on a metro app right now and I'm looking to enable multitouch. I've browsed around google, but I can't seem to find any API to support it. Can someone point me in the right direction to support multitouch actions in a Windows 8 Metro app?
What exactly are you trying to do? There are Touch, Pointer (an abstraction around touch/mouse/stylus), and Manipulation events on every UI element
In JavaScript you can use the event.pointerId to detected multiple touch inputs. This identifier gives every new input an id. When you want to get multiplie touches for a move with the finger, you can use the MSPointerMove Event and this id. I'am using jQuery, but the bind and unbind function won't work, because the event isn't attached. You have to use plain Javascript to get multitouch working:
var pointerId=0;
//add a Eventlistner to the Down Event (compareable to mousedown and touchstart)
$('#button1')[0].addEventListener("MSPointerDown",function(event) {
pointerId=event.pointerId; //save the pointerId to a (in this case) global var
window.addEventListener("MSPointerMove", moveHandler, false);
//The handlers should also be removed on MSPointerUp.
//You can't use jQuery unbind for this, it dosn't work.
//use window.removeListener("MSPointerMove",moveHandler);
},false);
//define the moveHandler and check the pointer ID
var moveHandler = function(event) {
if(pointerId==event.pointerId) {
//If the pointerId is the same, the moving comes from one finger
//For example we can move the button with the finger
$("#button1").css({'top':event.pageY,'left':event.pageX,'position':'absolute'});
}
}
Following is a full example with a foreach to attach the event-handlers to more than one button. If you start this application you will get 4 squares that you can move around with multiple fingers.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>App1</title>
<!-- WinJS references -->
<link href="//Microsoft.WinJS.1.0.RC/css/ui-dark.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.1.0.RC/js/base.js"></script>
<script src="//Microsoft.WinJS.1.0.RC/js/ui.js"></script>
<!-- App1 references -->
<link href="/css/default.css" rel="stylesheet" />
<script src="/js/default.js"></script>
<script src="js/jquery.js"></script>
<script>
function start() {
//add a Eventlistner to the Down Event (compareable to mousedown and touchstart)
$(".button").each(function (i, element) {
var pointerId = 0;
$(element)[0].addEventListener("MSPointerDown", function (event) {
pointerId = event.pointerId; //save the pointerId to a (in this case) global var
window.addEventListener("MSPointerMove", moveHandler, false);
}, false);
//PointerUp handler
window.addEventListener("MSPointerUp", upHandler, false);
//define the moveHandler and check the pointer ID
var moveHandler = function (event) {
if (pointerId == event.pointerId) {
$(element).css({ "top": event.pageY-50, "left":event.pageX-50 });
}
}
//remove the moveHandler on PointerUp
var upHandler = function (event) {
if (pointerId == event.pointerId) {
window.removeListener("MSPointerMove", moveHandler);
}
}
});
}
</script>
</head>
<body>
<div class="button" style="width:100px;height:100px;background-color:#F80;position:absolute;"></div>
<div class="button" style="width:100px;height:100px;background-color:#08F;position:absolute;"></div>
<div class="button" style="width:100px;height:100px;background-color:#fff;position:absolute;"></div>
<div class="button" style="width:100px;height:100px;background-color:#4cff00;position:absolute;"></div>
</body>
</html>
With this approch, you can use 4 Fingers at the same time.
Take a look at this post Touch Input for IE10 and Metro style Apps
Sample script from post:
<script>
function handleEvent(event) {
var currentPointers = event.getPointerList();
if (currentPointers.length == 1) {
event.target.style.backgroundColor = "red";
} else {
event.target.style.backgroundColor = "green"; //multiple touch points are used
}
}
document.getElementById("foo").addEventListener("MSPointerMove", handleEvent, false);
</script>
Try ManipulationDelta of any control...
you can find whether a touch is multitouch or not by detrmining the Scale property of any manipulation event args....
private void AssetMap_ManipulationDelta_1(object sender, ManipulationDeltaRoutedEventArgs e)
{
if (e.Cumulative.Scale != 1)
{
//indicates that it is multitouch
}
hope it will help you...

Self closing Html Generic Control?

I am writing a bit of code to add a link tag to the head tag in the code behind... i.e.
HtmlGenericControl css = new HtmlGenericControl("link");
css.Attributes["rel"] = "Stylesheet";
css.Attributes["type"] = "text/css";
css.Attributes["href"] = String.Format("/Assets/CSS/{0}", cssFile);
to try and achieve something like...
<link rel="Stylesheet" type="text/css" href="/CSS/Blah.css" />
I am using the HtmlGenericControl to achieve this... the issue I am having is that the control ultimatly gets rendered as...
<link rel="Stylesheet" type="text/css" href="/CSS/Blah.css"></link>
I cant seem to find what I am missing to not render the additional </link>, I assumed it should be a property on the object.
Am I missing something or is this just not possible with this control?
I think you'd have to derive from HtmlGenericControl, and override the Render method.
You'll then be able to write out the "/>" yourself (or you can use HtmlTextWriter's SelfClosingTagEnd constant).
Edit: Here's an example (in VB)
While trying to write a workaround for umbraco.library:RegisterStyleSheetFile(string key, string url) I ended up with the same question as the OP and found the following.
According to the specs, the link tag is a void element. It cannot have any content, but can be self closing. The W3C validator did not validate <link></link> as correct html5.
Apparently
HtmlGenericControl css = new HtmlGenericControl("link");
is rendered by default as <link></link>. Using the specific control for the link tag solved my problem:
HtmlLink css = new HtmlLink();
It produces the mark-up <link/> which was validated as correct xhtml and html5.
In addition to link, System.Web.UI.HtmlControls contains classes for other void element controls, such as img, input and meta.
Alternatively you can use Page.ParseControl(string), which gives you a control with the same contents as the string you pass.
I'm actually doing this exact same thing in my current project. Of course it requires a reference to the current page, (the handler), but that shouldn't pose any problems.
The only caveat in this method, as I see it, is that you don't get any "OO"-approach for creating your control (eg. control.Attributes.Add("href", theValue") etc.)
I just created a solution for this, based on Ragaraths comments in another forum:
http://forums.asp.net/p/1537143/3737667.aspx
Override the HtmlGenericControl with this
protected override void Render(HtmlTextWriter writer)
{
if (this.Controls.Count > 0)
base.Render(writer); // render in normal way
else
{
writer.Write(HtmlTextWriter.TagLeftChar + this.TagName); // render opening tag
Attributes.Render(writer); // Add the attributes.
writer.Write(HtmlTextWriter.SelfClosingTagEnd); // render closing tag
}
writer.Write(Environment.NewLine); // make it one per line
}
The slightly hacky way.
Put the control inside a PlaceHolder element.
In the code behind hijack the render method of the PlaceHolder.
Render the PlaceHolders content exactly as you wish.
This is page / control specific and does not require any overrides. So it has minimal impact on the rest of your system.
<asp:PlaceHolder ID="myPlaceHolder" runat="server">
<hr id="someElement" runat="server" />
</asp:PlaceHolder>
protected void Page_Init(object sender, EventArgs e)
{
myPlaceHolder.SetRenderMethodDelegate(ClosingRenderMethod);
}
protected void ClosingRenderMethod(HtmlTextWriter output, Control container)
{
var voidTags = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase) { "br", "hr", "link", "img" };
foreach (Control child in container.Controls)
{
var generic = child as HtmlGenericControl;
if (generic != null && voidTags.Contains(generic.TagName))
{
output.WriteBeginTag(generic.TagName);
output.WriteAttribute("id", generic.ClientID);
generic.Attributes.Render(output);
output.Write(HtmlTextWriter.SelfClosingTagEnd);
}
else
{
child.RenderControl(output);
}
}
}

Upload an image with wmd?

Is it possible with the wmd editor to add a button to let the user upload an image to the web server and place the corresponding img markdown in the textbox? If not, will another good inplace editor do it? Context: I'm using asp.net mvc, C# and I am a true beginner with javascript.
A brief perusal of the WMD seems to indicate that this feature is not supported directly and that the control is not particularly pluggable.
That being said, there's nothing stopping you from creating a button/upload-field/whatever that sends an image to your servers and injects the appropriate:
<img src="http://your.server.com/path/to/attachments/..." />
Into the control's underlying textarea.
Here's a variation to the minimal example that comes with WMD:
<!DOCTYPE html>
<html>
<head>
<title>WMD minimal example</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js"></script>
<script type="text/javascript">
$.fn.insertAtCaret = function (myValue) {
return this.each(function(){
//IE support
if (document.selection) {
this.focus();
sel = document.selection.createRange();
sel.text = myValue;
this.focus();
}
//MOZILLA/NETSCAPE support
else if (this.selectionStart || this.selectionStart == '0') {
var startPos = this.selectionStart;
var endPos = this.selectionEnd;
var scrollTop = this.scrollTop;
this.value = this.value.substring(0, startPos)
+ myValue
+ this.value.substring(endPos,
this.value.length);
this.focus();
this.selectionStart = startPos + myValue.length;
this.selectionEnd = startPos + myValue.length;
this.scrollTop = scrollTop;
} else {
this.value += myValue;
this.focus();
}
});
};
int i = 50;
function Add()
{
$("#myTextarea").insertAtCaret("![alt text][" +(i++)+"]");
// You'll need to add the link too, at the bottom
}
</script>
</head>
<body>
<form>
test
<textarea id="myTextarea" style="width: 500px; height: 200px;">*This* is a minimal example.</textarea>
</form>
<div class="wmd-preview"></div>
<script type="text/javascript" src="wmd/wmd.js"></script>
</body>
</html>
But it's only the beginnings as you can probably tell. This markdown editor looks better
I wrote a blog post that explains how I solved this. In the post, I use PHP - if you're comfortable converting my PHP logic into ASP.NET, you may find it helpful!

Categories