Selecting text, Smart Mobile Studio
A really good question came my way regarding text selection and why ordinary browser behavior is disabled in Smart Mobile Studio applications. It was Jarto Tarpio that posted it on the SMS Facebook page, and I was a little surpriced at first to say the least.
Now the VJL was designed to look and feel more or less identical to any ordinary, native UI framework. This means that ordinary HTML text selection (marking text with your mouse) is something you dont want to have.
But what Jarto pointed out was that there is something fishy about how it’s implemented in Smart at the moment, because even when he removed the CSS rules that disables this, selecting text is still not possible.
That one line ..
Two RTL updates ago I remember dealing with this exact topic. I was happy to find that CSS had a couple of universal rules you could use, which meant that i could remove the code I was using to avoid selection ever taking place.
Sadly, I must have forgotten all about it (or it got accidentally filtered out during a manual unit merge) because it was till there (!) In other words not only did the CSS make sure you couldnt enable text selection, the startup code for all TW3TagObj derived classes kidnaps the OnSelectStart event — effectively killing initializing a selection at all.
Patching the RTL yourself
The change you need is basically a “one liner”, and it wont affect your programs at all. If you open up SmartCL.Components (right click the unit in your units clause), hit ALT + F which brings up the search dialog and then enter “TW3CustomControl.HookEvents” that’s where the problem lies:
procedure TW3CustomControl.HookEvents; begin inherited; Handle['onclick'] := @CBClick; //w3_bind2(Handle, 'onselectstart', CBNoBehavior); //Remove this line !! w3_bind2(Handle, 'onfocus', CBFocused); w3_bind2(Handle, 'onblur', CBLostFocus); end;
So simply delete the first “w3_bind2” call, the one that assigns OnSelectStart to the “no operation” event handler CBNoBehavior — now go to your main form unit, type something and then click Save.
Note: The editor doesnt monitor RTL files for edit-changes since these units are not meant to be edited. So you have to alter something in your project and force the IDE to allow your change to be saved.
Making selection an option
With that nasty (and no longer needed) line of code out of the way – I have added two new methods to the VJL that gives you 100% control over content selection. This will be in the next update but for those that cant wait, the following methods have been added to TW3MovableControl:
function GetContentSelectionMode: TW3ContentSelectionMode;virtual; procedure SetContentSelectionMode(const NewMode: TW3ContentSelectionMode);virtual;
Here is the code if you want to get these features straight away:
type TW3ContentSelectionMode = ( tsmNone, tsmAuto, tsmText, tsmAll, tsmElement ); function TW3MovableControl.GetContentSelectionMode: TW3ContentSelectionMode; begin var CurrentMode := Handle.style[BrowserAPI.PrefixDef("user-select")]; if (CurrentMode) then begin case TVariant.AsString(CurrentMode).ToLower() of 'auto': result := tsmAuto; 'text': result := tsmText; 'all': result := tsmAll; 'element': result := tsmElement; else result := tsmNone; end; end else begin Handle.style[w3_CSSPrefixDef("user-select")] := 'none'; result := tsmNone; end; end; procedure TW3MovableControl.SetContentSelectionMode (const NewMode: TW3ContentSelectionMode); begin case NewMode of tsmAuto: Handle.style[w3_CSSPrefixDef("user-select")] := 'auto'; tsmAll: Handle.style[w3_CSSPrefixDef("user-select")] := 'all'; tsmText: Handle.style[w3_CSSPrefixDef("user-select")] := 'text'; tsmNone: Handle.style[w3_CSSPrefixDef("user-select")] := 'none'; tsmElement: Handle.style[w3_CSSPrefixDef("user-select")] := 'element'; end; end;
Writing your custom controls with selection turned on
Ok, first let’s write a class that allows text-selection. We are going to use a DIB, which is the default element of TW3CustomControl, so this will be a short example:
type TSelectTestControl = class(TW3CustomControl) protected procedure ObjectReady;override; public property Text:string read (GetInnerText) write (SetInnerText(Value)); end; procedure TSelectTestControl.ObjectReady; begin inherited; SetContentSelectionMode(tsmText); end;
Since user-select is set to “none” in all our CSS style themes, enabling editing means telling the DOM (document object model) that this control does allow text selection. In the above example I do that in the ObjectReady method, just to make sure the DIV TSelectTestControl represent is in the clear and has been created successfully and injected into the DOM.
So lets go back to our main form and create an instance of our new control. You should also drop a TW3DIVHtmlElement on the form first, so we have something to compare with.
Ok, here is the form unit completed:
unit Form1; interface uses System.Colors, SmartCL.Controls.Elements, SmartCL.System, SmartCL.Graphics, SmartCL.Components, SmartCL.Forms, SmartCL.Fonts, SmartCL.Borders, SmartCL.Application; type (* our spanking new control. Not a TW3DIVHtmlElement in sight! *) TSelectTestControl = class(TW3CustomControl) protected procedure ObjectReady;override; public property Text:string read (GetInnerText) write (SetInnerText(Value)); end; TForm1 = class(TW3Form) private {$I 'Form1:intf'} protected procedure InitializeForm; override; procedure InitializeObject; override; procedure Resize; override; end; implementation { TForm1 } uses system.types, system.time; procedure TSelectTestControl.ObjectReady; begin inherited; SetContentSelectionMode(tsmText); end; procedure TForm1.InitializeForm; begin inherited; // this is a good place to initialize components var LTemp := TSelectTestControl.Create(self); LTemp.background.fromColor(clRed); LTemp.Text:="this is some text"; LTemp.setBounds(10,10,200,200); W3DivHTMLElement1.innerhtml := "<i>This is some text"; end; procedure TForm1.InitializeObject; begin inherited; {$I 'Form1:impl'} end; procedure TForm1.Resize; begin inherited; end; initialization Forms.RegisterForm({$I %FILE%}, TForm1); end.
And the results are exactly what we wanted:

The red box is our control, as you can see you can now mark the text
Final words
I know this has been a topic many people have asked about in the past. But this time we have made sure this is possible (and possible per individual control).
Well what are you waiting for! Go patch that RTL right now and get cracking 🙂
You must be logged in to post a comment.