66import java .beans .PropertyChangeEvent ;
77
88import javax .swing .text .AbstractDocument .BranchElement ;
9+ import javax .swing .JEditorPane ;
10+ import javax .swing .JTextArea ;
911import javax .swing .text .AttributeSet ;
1012import javax .swing .text .Document ;
1113import javax .swing .text .Element ;
@@ -48,40 +50,59 @@ public void propertyChange(PropertyChangeEvent e) {
4850 super .propertyChange (e );
4951 }
5052
53+ private int epTimer ;
54+
5155 @ SuppressWarnings ("unused" )
5256 @ Override
5357 public boolean handleJSEvent (Object target , int eventType , Object jQueryEvent ) {
58+
5459 if (target != null ) {
5560 // A first touch down may trigger on the wrong event target
5661 // and not have set up window.getSelection() yet.
62+ // 50-ms delay allows for multiple clicks, effecting word and line selection.
5763 /**
5864 *
5965 * @j2sNative
6066 *
61- * var me = this; setTimeout(function(){me.handleJSEvent$O$I$O(null,
62- * eventType, jQueryEvent)},10 );
67+ * var me = this; clearTimeout(this.epTimer);this.epTimer = setTimeout(function(){me.handleJSEvent$O$I$O(null,
68+ * eventType, jQueryEvent)},50 );
6369 *
6470 */
6571 return true ;
6672 }
6773
6874 int dot = 0 , mark = 0 , apt = 0 , fpt = 0 ;
6975 DOMNode anode = null , fnode = null ;
76+ String atag = null , ftag = null ;
7077
7178 /**
7279 * @j2sNative
7380 *
7481 *
75- * var s = window.getSelection(); anode = s.anchorNode;
76- * fnode = s.focusNode; apt =
77- * s.anchorOffset; fpt = s.focusOffset;
82+ * var s = window.getSelection();
83+ * anode = s.anchorNode;
84+ * apt = s.anchorOffset;
85+ * if (anode.tagName) {
86+ * anode = anode.childNodes[apt];
87+ * apt = 0;
88+ * }
89+ * fnode = s.focusNode;
90+ * fpt = s.focusOffset;
91+ * if (fnode.tagName) {
92+ * fnode = fnode.childNodes[fpt];
93+ * fpt = 0;
94+ * }
7895 */
7996
97+ if (anode == null || fnode == null ) {
98+ System .out .println ("JSEditorPaneUI anode or fnode is null " );
99+ return false ;
100+ }
80101 mark = getJSDocOffset (anode );
81102 dot = (anode == fnode ? mark : getJSDocOffset (fnode )) + fpt ;
82103 mark += apt ;
83104
84- // System.out.println("windows at " + mark + "-" + dot + "/" + apt + " " + fpt);
105+ System .out .println ("== windows at " + mark + "-" + dot + "/" + apt + " " + fpt );
85106
86107 /**
87108 * @j2sNative jQueryEvent.target = null; jQueryEvent.selectionStart = mark;
@@ -121,6 +142,7 @@ private int getJSCharCount(DOMNode sib) {
121142 void setSelectionRange (int mark , int dot ) {
122143 editor .getCaret ().setDot (mark );
123144 editor .getCaret ().moveDot (dot );
145+ updateDataUI ();
124146 }
125147
126148 @ Override
@@ -133,13 +155,10 @@ public void setText(String text) {
133155 text = editor .getText ();
134156 currentText = text ;
135157 fromJava (text , sb , d .getRootElements ()[0 ], true , null );
136- System .out .println ("fromJava " + text .replace ('\n' , '.' ));
137- System .out .println ("toHTML" + sb );
158+ // System.out.println("fromJava " + text.replace('\n', '.'));
159+ // System.out.println("toHTML" + sb);
138160 DOMNode .setAttr (domNode , "innerHTML" , sb .toString ());
139-
140- DOMNode [] divs = (DOMNode []) (Object ) $ (domNode ).find ("*" );
141- for (int i = divs .length ; --i >= 0 ;)
142- DOMNode .setAttr (divs [i ], "data-ui" , this );
161+ updateDataUI ();
143162 @ SuppressWarnings ("unused" )
144163 JSEditorPaneUI me = this ;
145164 /**
@@ -152,6 +171,16 @@ public void setText(String text) {
152171 }
153172 }
154173
174+ /**
175+ * after setting text, it is necessary to update all descendents to be clickable
176+ */
177+ private void updateDataUI () {
178+ DOMNode [] divs = (DOMNode []) (Object ) $ (domNode ).find ("*" );
179+ //System.out.println("updateDataUI " + divs.length);
180+ for (int i = divs .length ; --i >= 0 ;)
181+ DOMNode .setAttr (divs [i ], "data-ui" , this );
182+ }
183+
155184 private final static int BOLD = 1 ;
156185 private final static int ITALIC = 2 ;
157186 private final static int SUB = 4 ;
@@ -215,7 +244,7 @@ private static String getCSSStyle(AttributeSet a, AttributeSet currAttr) {
215244 if (checkAttr (ITALIC , a , currAttr ))
216245 style += "font-style:" + (StyleConstants .isItalic (a ) ? "italic;" : "normal;" );
217246 if (checkAttr (FACE , a , currAttr ))
218- style += "font-face :" + StyleConstants .getFontFamily (a ) + ";" ;
247+ style += "font-family :" + JSToolkit . getCSSFontFamilyName ( StyleConstants .getFontFamily (a ) ) + ";" ;
219248 if (checkAttr (SIZE , a , currAttr ))
220249 style += "font-size:" + StyleConstants .getFontSize (a ) + "px;" ;
221250 return style ;
@@ -267,48 +296,60 @@ protected String getPropertyPrefix() {
267296 private DOMNode lastTextNode ;
268297
269298 /**
270- * Find the HTML node and offset for this caret point .
299+ * Find the HTML node and offset for this Java caret position .
271300 *
272- * @param node
273- * @param off
274- * @param pt
275- * @return [node,offset]
301+ * @param node domNode or one of its descendants
302+ * @param off document offset to start of this node
303+ * @param pt target caret position
304+ * @return range information or length: [textNode,charOffset] or [nontextNode,charNodesOffset] or [null, nlen]
276305 */
277306 @ Override
278307 protected Object [] getJSNodePt (DOMNode node , int off , int pt ) {
279308 boolean isRoot = (off < 0 );
280- if (isRoot ) {
309+ if (isRoot ) {
281310 lastTextNode = null ;
282311 off = 0 ;
283312 }
284313 // Must consider several cases for BR and DIV:
285314 // <br>
286- // <div><br><div> --> [div, 0]
287- // <div>.....<br><div>
315+ // <div><br><div> where br counts as 1 character --> [div, 0] or [null, 1]
316+ // <div>.....<br><div> where childNodes[i] is br, counts as 0 charactors --> [div, i] or [null, 0]
317+ // as well as "raw" text in the root domNode:
318+ // text....<br>...text...<br>.... where br counts as 1 character --> [node.parentNode, i] or [null, 1]
319+ //
320+ // also note that range can point to a character position only if the node is #text
321+ // otherwise, it must point to a childNodes index in the parent node. So <br> must
322+ // be indicated this second way.
288323
289324 /**
290325 * @j2sNative
291326 var nodes = node.childNodes;
292327 var n = nodes.length;
293- if (n > 0 && nodes[n - 1].tagName == "BR" || node .tagName == "BR") {
294- return (pt == off ? [node, n == 0 ? 0 : n - 1 ] : [null, 1]);
328+ if (n == 1 && nodes[0] .tagName == "BR") {
329+ return (pt == off ? [node, 0 ] : [null, 1]);
295330 }
296331 var ipt = off;
297332 var nlen = 0;
298- var i1 = (node.tagName == "DIV" || node.tagName == "P" ? 1 : 0);
333+ var tag = node.tagName;
334+ var i1 = (tag == "DIV" || tag == "P" ? 1 : 0);
299335 for (var i = 0; i < n; i++) {
300336 node = nodes[i];
301337 if (node.innerText) {
302338 ret = this.getJSNodePt$swingjs_api_js_DOMNode$I$I(node, ipt, pt, false);
303- if (ret[0] != null)
339+ if (ret[0] != null) {
304340 return ret;
341+ }
305342 nlen = ret[1];
343+ } else if (node.tagName == "BR") {
344+ if (ipt == pt)
345+ return [node.parentNode, i];
346+ nlen = (isRoot ? 1 : 0);
306347 } else if (ipt + i1 + (nlen = (this.lastTextNode = node).length) > pt) {
307348 return [node, Math.max(0, pt - ipt)];
308349 }
309350 ipt += nlen;
310- }
311- return (isRoot ? [this.lastTextNode, ret[3] - 1] : [null, ipt + i1 - off, node, nlen]);
351+ }
352+ return (isRoot ? [this.lastTextNode, Math.max(0, ret[3] - 1) ] : [null, ipt + i1 - off, node, nlen]);
312353 */
313354 {
314355 return null ;
@@ -355,7 +396,6 @@ private static String getInnerTextSafely(DOMNode node, boolean isRoot, SB sb) {
355396 @ Override
356397 void setTextDelayed () {
357398 // this timeout is critical and did not work with invokeLater
358-
359399 JSTextUI u = this ;
360400 JTextComponent t = editor ;
361401 /**
@@ -364,20 +404,21 @@ void setTextDelayed() {
364404 * if (this.timeoutID) {
365405 * clearTimeout(this.timeoutID);
366406 * }
367- * this.timeoutID = setTimeout(function(){u.timeoutID = 0;u.setText$S(t.getText$() )},50);
407+ * this.timeoutID = setTimeout(function(){u.timeoutID = 0;u.updateDOMNode$( )},50);
368408 */
369409 }
370410
371411 @ Override
372412 protected void jsSelect (Object [] r1 , Object [] r2 ) {
373- //System.out.println("jsSelect " + r1 + r2);
413+ System .out .println ("jsSelect " + r1 + r2 );
414+ // range index may be NaN
374415 /**
375416 * @j2sNative
376417 *
377418 *
378419 * var range = document.createRange();
379- * range.setStart(r1[0], r1[1]);
380- * range.setEnd(r2[0], r2[1]);
420+ * range.setStart(r1[0], r1[1] || 0 );
421+ * range.setEnd(r2[0], r2[1] || 0 );
381422 * var sel = window.getSelection();
382423 * sel.removeAllRanges();
383424 * sel.addRange(range);
0 commit comments