Fix: Hypelinks not clickable in RichTextBox under Silverlight

Just fixed a nasty bug in ClipFlair Studio (http://studio.clipflair.net), where one couldn’t click hyperlinks in the Text component when set at ReadOnly mode. In that mode hyperlinks should open up new web pages (in Edit mode you can edit/remove them only of course), but instead when clicked they would show something like a focus rectangle (which they normally never show).

image

The situation was hard to debug since it wasn’t obvious what had caused the issue (it was working some time ago). I eventually found out that when the RichTextBox in Silverlight (may occur in WPF and WinRT too, haven’t tried) has a Transparent background, then Hyperlinks in it let MouseLeftButtonDown events pass through, so OnMouseLeftButtonDown will fire at their visual parent (or other visual ancestor) if no component in the visual chain marks the event as handled (such events bubble up towards the top of the visual hierarchy/containment chain).

This shouldn’t be much of a problem, if there wasn’t another issue, where if the ancestor called CaptureMouse in their OnMouseLeftButtonDown overriden method (from Control class), which is usual in mouse dragging code (in my case it was a FloatingWindow [TextWindow] that was the visual ancestor of RichTextBox), the hyperlink fails to fire when clicked and shows that weird solid-line border arround it instead.

The fix was easy once I knew what was happening, I attached a MouseLeftButtonDown event handler to the RichTextBox (if one was subclassing it [assuming it allows to do so] they could also have opted to add an overriden OnMouseLeftButtonDown method) that sets Handled property of the event parameter to true to consume it. The fix is available at CodePlex.

One can verify that the fix works now by downloading a sample ClipFlair Activity from https://www.dropbox.com/s/1zr36190xb0m6vk/Test_Text_URLs.clipflair and opening it in ClipFlair Studio. Can also download and build/run the source code of the previous broken version 1faaa8b35749 and test with that save activity file to see that the URLs didn’t open before when clicked but showed a rectangle arround them intead.

image

HowTo: use PivotViewer in WPF

PivotViewer is an impressive Silverlight control (see my usage at http://gallery.clipflair.net), however Microsoft never released it for WPF.

One could work arround this by embedding Silverlight in their WPF app using the WebBrowser control and talking to it via the JavaScript Bridge of Silverlight, however they could also embed one of those HTML5 PivotViewer-compatible controls that have surfaced in recent years.

Apart from LobsterPot’s HTML5 PivotViewer and its older free version, for another HTML5 PivotViewer (and also a DeepZoom implementation for HTML5) you could host that comes from former SeaDragon team members at Microsoft and seems to work very well see:

http://seajax.github.io/

https://github.com/seajax/seajax/tree/master/v2/app/pivot

https://github.com/seajax/seajax/blob/master/v2/app/pivot/quickstart.html

https://github.com/seajax/seajax

Note that the WebBrowser control uses IE7 or something as HTML engine by default and you need some meta markup at the top of your HTML to tell it to use Edge mode – the latest IE engine that is installed)

<meta http-equiv="X-UA-Compatible" content="IE=edge">

HowTo: Tell IE to use compatibility mode without editing your web pages

at http://www.mono-software.com/Mono/Pages/Discussion/dtopic/_YyUBIlx5kiqHaNqAQeltg/br-brake-bug-in-IE11-and-clipflair-text-editor/

one reads:

We are using Telerik’s rich text editor (RadEditor), and it seems that RadEditor has specific behaviour regarding insertion of break tags.

To circumvent this issue please try to add host header in ISS 7 (website level):

Name = "X-UA-Compatible"
Value = "IE=EmulateIE10"

Or, you can insert Html Meta tag on a PreRender event (of Page that uses RadEditor):

HtmlMeta meta = new HtmlMeta();

meta.Attributes.Add("http-equiv", "X-UA-Compatible");

meta.Attributes.Add("content", "IE=EmulateIE10");

Page.Header.Controls.Add(meta);

 

This is a very handy trick, one can open up a website at IIS console and open HTTP Response Headers node and then add the Name / Value pair X-UA-Compatible / IE=EmulateIE10 to force say Internet Explorer 11 to behave like Internet Explorer 10

To confirm it works, press F12 to show developer tools in IE11 and see at the right that it says “IE10” instead of “Edge” at the HTML engine selection dropdown list (compatibility mode).

 

Screenshot 2014-08-22 19.05.29

Gotcha: JS replace on document.location fails, use document location.href

This is my contribution to:
http://stackoverflow.com/questions/2652816/what-is-the-difference-between-document-location-href-and-document-location

Here is an example of the practical significance of the difference and how it can bite you if you don’t realize it (document.location being an object and document.location.href being a string):

We use MonoX Social CMS (http://mono-software.com) free version at http://social.ClipFlair.net and we wanted to add the language bar WebPart at some pages to localize them, but at some others (e.g. at discussions) we didn’t want to use localization. So we made two master pages to use at all our .aspx (ASP.net) pages, in the first one we had the language bar WebPart and the other one had the following script to remove the /lng/el-GR etc. from the URLs and show the default (English in our case) language instead for those pages

<script>
  var curAddr = document.location; //MISTAKE
  var newAddr = curAddr.replace(new RegExp("/lng/[a-z]{2}-[A-Z]{2}", "gi"), "");
  if (curAddr != newAddr)
    document.location = newAddr;
</script>

But this code isn’t working, replace function just returns Undefined (no exception thrown) so it tries to navigate to say x/lng/el-GR/undefined instead of going to url x. Checking it out with Mozilla Firefox’s debugger (F12 key) and moving the cursor over the curAddr variable it was showing lots of info instead of some simple string value for the URL. Selecting Watch from that popup you could see in the watch pane it was writing "Location -> …" instead of "…" for the url. That made me realize it was an object

One would have expected replace to throw an exception or something, but now that I think of it the problem was that it was trying to call some non-existent "replace" method on the URL object which seems to just give back "undefined" in Javascript.

The correct code in that case is:

<script>
  var curAddr = document.location.href; //CORRECT
  var newAddr = curAddr.replace(new RegExp("/lng/[a-z]{2}-[A-Z]{2}", "gi"), "");
  if (curAddr != newAddr)
    document.location = newAddr;
</script>
Categories: Posts Tags: , , , , , , ,

HowTo: Quickly test a webpage in different Internet Explorer versions

Screenshot 2014-08-19 14.20.41

I just noticed that on Internet Explorer 11 developer tools console (appears when you press F12 key), there is a drop-down where you can select the rendering engine used. Edge means the very latest (IE11 one in this case) and you can select back to version 5.

Interestingly, there is no version 6 in the dropdown, don’t remember if there was an IE6 or if they jumped from IE5.5 or something to IE7 directly.

Gotcha: don’t use ‘{$…}’ syntax or ‘$…’ syntax in XSL-XPath’s concat

<xsl:template match="cxml:Item" mode="col">
  <xsl:variable name="FILENAME" select="…someXPathQuery…"/>
  <xsl:variable name="IMAGE" select="concat(‘http://gallery.clipflair.net/activity/image/’, $FILENAME, ‘.png’)"/>

I got confused a bit today after a long day of fiddling with XSL and ClipFlair Activity Gallery’s CXML (Collection XML) data (as used in PivotViewer control), and didn’t understand why I couldn’t use an XSL variable’s (FILENAME in the sample above) calculated value inside the definition of another variable.

That other variable (IMAGE) was using “concat” function of XPath and I was getting a literal string concatenated, instead of the value of the FILENAME one.

After a while I noticed that I was using string quotes arround the respective argument passed to the “concat” function. One needs to use $FILENAME there, not ‘$FILENAME’ and of course not ‘{$FILENAME}’ (the last one is used inside say HTML argument values used for output, like <img href=”{$IMAGE}” />)

HowTo: Group output items using XSL transformation

While trying to generate a single HTML page that will list all ClipFlair activities using XSL Transformations (XSLT), I had the need to group items in 2-column rows.

This is my contribution to other solutions suggested at (if you like it you can vote it up there):

http://stackoverflow.com/questions/9908488/xslt-for-each-wrapping-every-nth-item-in-a-div/


Faced by the same problem, that is wanting to output

<div class="container">
  <div class="row">
    <div class="col">...</div>
    <div class="col"/>...</div>
  </div>
  <div class="row">
  ...
  </div>
</div>

from a CXML (Collection XML) file (http://gallery.clipflair.net/collection/activities.cxml – the data behind the PivotViewer display at http://gallery.clipflair.net/activity)

I coined up the following, based on other suggestions here, but using "mode" attribute of "template" and "apply-templates" XSL tags instead which make it cleaner I believe:

<?xml version="1.0" encoding="UTF-8"?>
<?altova_samplexml http://gallery.clipflair.net/collection/activities.cxml?>

<xsl:stylesheet 
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:cxml="http://schemas.microsoft.com/collection/metadata/2009"
  exclude-result-prefixes="cxml"
  >

  <xsl:output method="html" version="4.0" encoding="UTF-8" indent="yes"/>
  <xsl:param name="COLUMNS" select="2"/>

  <!-- ########################### -->

  <xsl:template match="/">
    <html xmlns="http://www.w3.org/1999/xhtml">
      <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <title>ClipFlair Activities</title>
        <link rel="stylesheet" type="text/css" href="style.css"/>
      </head>
      <body>
        <xsl:apply-templates/>
      </body>
    </html>
  </xsl:template>

  <!-- ########################### -->

  <xsl:template match="cxml:Collection">
    <div class="container">
      <xsl:apply-templates/>
    </div>
  </xsl:template>

  <!-- ########################### -->

  <xsl:template match="cxml:Items">
    <xsl:apply-templates 
select="cxml:Item[position() mod $COLUMNS = 1]" mode="row"/> </xsl:template> <!-- ########################### --> <xsl:template match="cxml:Item" mode="row"> <div class="row"> <div>----------</div> <xsl:apply-templates
select=".|following-sibling::cxml:Item[position() &lt; $COLUMNS]" mode="col"/> </div> </xsl:template> <xsl:template match="cxml:Item" mode="col"> <xsl:variable name="URL" select="@Href"/> <xsl:variable name="FILENAME"
select="cxml:Facets/cxml:Facet[@Name='Filename']/cxml:String/@Value"/> <div class="col"> <xsl:value-of select="$FILENAME"/> --- <xsl:value-of select="$URL"/> </div> </xsl:template> <!-- ########################### --> <xsl:template match="*"> <xsl:apply-templates/> </xsl:template> <xsl:template match="text()|@*"> </xsl:template> </xsl:stylesheet>

the output from the above when run in Altova XMLSpy tool (note that it uses altova_samplexml processor instruction to find the XML data) is:


2DaysInParis-OpenActivity-CapRev-FR-EN.clipflair --- http://studio.clipflair.net/?activity=2DaysInParis-OpenActivity-CapRev-FR-EN.clipflair
Abu_Dukhan-CapRev-A1-AR.clipflair --- http://studio.clipflair.net/?activity=Abu_Dukhan-CapRev-A1-AR.clipflair
----------

AFarewellToArms-RevCap-C2-EN.clipflair --- http://studio.clipflair.net/?activity=AFarewellToArms-RevCap-C2-EN.clipflair
agComhaireamhCountingRND.clipflair --- http://studio.clipflair.net/?activity=agComhaireamhCountingRND.clipflair

----------

Al-imtihan-CapRev-B1-AR.clipflair --- http://studio.clipflair.net/?activity=Al-imtihan-CapRev-B1-AR.clipflair
AlBar-Cap-B1-B2-IT.clipflair --- http://studio.clipflair.net/?activity=AlBar-Cap-B1-B2-IT.clipflair

...
Follow

Get every new post delivered to your Inbox.

Join 941 other followers

%d bloggers like this: