9
9
from pyjamas .ui .TextArea import TextArea
10
10
from pyjamas .ui import RootPanel
11
11
12
+ from pyjamas import DOM
13
+
12
14
from RichTextEditor import RichTextEditor
13
15
14
16
from pyjamas .selection .RangeEndPoint import RangeEndPoint
15
17
from pyjamas .selection .Range import Range
16
18
from pyjamas .selection .RangeUtil import getAdjacentTextElement
17
19
from pyjamas .selection import Selection
18
20
21
+ import string
22
+
23
+ def print_tree (parent ):
24
+ if parent .nodeType == 1 :
25
+ print "parent" , parent , parent .tagName , parent .innerHTML
26
+ else :
27
+ print "parent" , parent , parent .nodeName
28
+ child = parent .firstChild
29
+ while child :
30
+ print "child" , child ,
31
+ if child .nodeType == 1 :
32
+ print child .tagName , repr (child .innerHTML )
33
+ else :
34
+ print repr (child .data )
35
+ child = child .nextSibling
36
+
37
+ def remove_node (doc , element ):
38
+ """ removes a specific node, adding its children in its place
39
+ """
40
+ fragment = doc .createDocumentFragment ()
41
+ while element .firstChild :
42
+ fragment .appendChild (element .firstChild )
43
+
44
+ parent = element .parentNode
45
+ parent .insertBefore (fragment , element )
46
+ parent .removeChild (element )
47
+
48
+ print_tree (parent )
49
+ #print "element", element, element.tagName, element.innerHTML
50
+
51
+ def remove_editor_styles (doc , tree ):
52
+ """ removes all other <span> nodes with an editor style
53
+ """
54
+
55
+ element = tree .lastChild
56
+ while element :
57
+ if element .nodeType != 1 :
58
+ element = element .previousSibling
59
+ continue
60
+ if string .lower (element .tagName ) != 'span' :
61
+ element = element .previousSibling
62
+ continue
63
+ style = DOM .getAttribute (element , "className" )
64
+ print "span" , style , element , element .innerHTML
65
+ if not style or not style .startswith ("editor-" ):
66
+ element = element .previousSibling
67
+ continue
68
+ prev_el = element
69
+ remove_editor_styles (doc , prev_el )
70
+ element = element .previousSibling
71
+ remove_node (doc , prev_el )
72
+ print "post-remove"
73
+ print_tree (tree )
74
+
19
75
"""*
20
76
* Entry point classes define <code>onModuleLoad()</code>.
21
77
"""
@@ -40,7 +96,8 @@ def onModuleLoad(self):
40
96
self .m_toSCursor .setTitle ("Set the selection to be a cursor at the beginning of the current selection" )
41
97
self .m_toECursor = Button ("To Cursor >" , self )
42
98
self .m_toECursor .setTitle ("Set the selection to be a cursor at the end of the current selection" )
43
- self .m_surround = Button ("Surround" , self )
99
+ self .m_surround1 = Button ("Surround1" , self )
100
+ self .m_surround2 = Button ("Surround2" , self )
44
101
45
102
grid = Grid (2 , 2 )
46
103
self .m_startNode = self .createTextBox (1 )
@@ -63,7 +120,8 @@ def onModuleLoad(self):
63
120
buts .add (self .m_setHtml )
64
121
buts .add (self .m_toSCursor )
65
122
buts .add (self .m_toECursor )
66
- buts .add (self .m_surround )
123
+ buts .add (self .m_surround1 )
124
+ buts .add (self .m_surround2 )
67
125
buts .add (grid )
68
126
buts .add (self .m_select )
69
127
buts .add (self .m_cursor )
@@ -146,13 +204,130 @@ def toCursor(self, start):
146
204
Selection .setRange (rng )
147
205
self .refresh ()
148
206
149
- def surround (self ):
207
+ def _surround (self , cls ):
208
+ """ this is possibly one of the most truly dreadful bits of code
209
+ for manipulating DOM ever written. its purpose is to add only
210
+ the editor class required, and no more. unfortunately, DOM gets
211
+ chopped up by the range thing, and a bit more besides. so we
212
+ have to:
213
+
214
+ * extract the range contents
215
+ * clean up removing any blank text nodes that got created above
216
+ * slap a span round it
217
+ * clean up removing any blank text nodes that got created above
218
+ * remove any prior editor styles on the range contents
219
+ * go hunting through the entire document for stacked editor styles
220
+
221
+ this latter is funfunfun because only "spans with editor styles
222
+ which themselves have no child elements but a single span with
223
+ an editor style" must be removed. e.g. if an outer editor span
224
+ has another editor span and also some text, the outer span must
225
+ be left alone.
226
+ """
150
227
rng = self .m_rte .getRange ()
151
- if (rng is not None ) and not rng .isCursor ():
152
- rng .surroundContents ()
153
- self .m_rte .getSelection ()
154
- Selection .setRange (rng )
155
- self .refresh ()
228
+ if (rng is None ) or rng .isCursor ():
229
+ return
230
+
231
+ rng .ensureRange ()
232
+ dfrag = rng .m_range .extractContents ()
233
+ print "doc pre remove"
234
+ print_tree (rng .m_document )
235
+ remove_editor_styles (rng .m_document , dfrag )
236
+ print "dfrag post remove styles"
237
+ print_tree (dfrag )
238
+ print "doc after dfrag remove"
239
+ print_tree (rng .m_document )
240
+ print "extract" , dfrag , dir (dfrag )
241
+ element = rng .m_document .createElement ("span" )
242
+ DOM .setAttribute (element , "className" , cls )
243
+ DOM .appendChild (element , dfrag )
244
+ rng .m_range .insertNode (element )
245
+
246
+ it = DOM .IterWalkChildren (element , True )
247
+ while True :
248
+ try :
249
+ node = it .next ()
250
+ except StopIteration :
251
+ break
252
+ print node , node .nodeType
253
+ if node .nodeType == 3 and unicode (node .data ) == u'' :
254
+ print "removing blank text"
255
+ DOM .removeChild (node .parentNode , node )
256
+
257
+ rng .setRange (element )
258
+
259
+ it = DOM .IterWalkChildren (rng .m_document , True )
260
+ while True :
261
+ try :
262
+ node = it .next ()
263
+ except StopIteration :
264
+ break
265
+ print node , node .nodeType
266
+ if node .nodeType == 3 and unicode (node .data ) == u'' :
267
+ print "removing blank text"
268
+ DOM .removeChild (node .parentNode , node )
269
+
270
+ it = DOM .IterWalkChildren (rng .m_document )
271
+ while True :
272
+ try :
273
+ node = it .next ()
274
+ except StopIteration :
275
+ break
276
+ style = DOM .getAttribute (node , "className" )
277
+ print "node" , node .firstChild , node .tagName , style
278
+ if node .firstChild :
279
+ continue
280
+ if str (string .lower (node .tagName )) != 'span' :
281
+ continue
282
+ print "node" , node .firstChild , node .tagName , style
283
+ if not style or not style .startswith ("editor-" ):
284
+ continue
285
+ it .remove ()
286
+
287
+ it = DOM .IterWalkChildren (rng .m_document , True )
288
+ while True :
289
+ try :
290
+ node = it .next ()
291
+ except StopIteration :
292
+ break
293
+ if node .nodeType != 1 :
294
+ continue
295
+ if node .firstChild is None :
296
+ continue
297
+ style = DOM .getAttribute (node , "className" )
298
+ print "double-node" , node .tagName , style , node .firstChild .nextSibling
299
+ print_tree (node )
300
+ if node .firstChild .nextSibling :
301
+ continue
302
+ if node .firstChild .nodeType != 1 :
303
+ continue
304
+ if str (string .lower (node .tagName )) != 'span' :
305
+ continue
306
+ if str (string .lower (node .firstChild .tagName )) != 'span' :
307
+ continue
308
+ if not style or not style .startswith ("editor-" ):
309
+ continue
310
+ style = DOM .getAttribute (node .firstChild , "className" )
311
+ if not style or not style .startswith ("editor-" ):
312
+ continue
313
+ # remove the *outer* one because the range was added to
314
+ # the inner, and the inner one overrides anyway
315
+ print "remove overlapping styles" , node
316
+ remove_node (rng .m_document , node )
317
+
318
+ doc = self .m_rte .getDocument ()
319
+ print "doc pre" , doc , doc .body .innerHTML
320
+
321
+ self .m_rte .getSelection ()
322
+ Selection .setRange (rng )
323
+ self .refresh ()
324
+ print "doc" , doc , doc .body .innerHTML
325
+
326
+ def surround1 (self ):
327
+ self ._surround ("editor-cls1" )
328
+
329
+ def surround2 (self ):
330
+ self ._surround ("editor-cls2" )
156
331
157
332
def findNodeByNumber (self , num ):
158
333
@@ -208,8 +383,11 @@ def onClick(self, wid):
208
383
elif wid == self .m_toSCursor :
209
384
self .toCursor (True )
210
385
211
- elif wid == self .m_surround :
212
- self .surround ()
386
+ elif wid == self .m_surround1 :
387
+ self .surround1 ()
388
+
389
+ elif wid == self .m_surround2 :
390
+ self .surround2 ()
213
391
214
392
elif wid == self .m_setHtml :
215
393
self .toHtml ()
0 commit comments