HOWTO: rangy 1.3; apply multiple styles || change previous style

391 views
Skip to first unread message

Jeff Levy

unread,
Jul 26, 2012, 12:51:47 PM7/26/12
to ra...@googlegroups.com
All,

First, and foremost, Tim, great library. It has saved me a lot of time, and allowed me to do things I could not have done with my own simplistic Range library. Upon discovery of Rangy, I have renamed mine own library from 'acceptable' to 'shitty', committed to the repository, and summarily destroyed it.

I believe I am either misunderstanding the way rangy operates, or, there may be a bug. I am not quite sure. Perhaps this post will expose the dirty truth, or, my idiocy.

Now, to my samples, and questions.

I have three prototype methods in a class I'm working on which allow for the alteration of fontFamily, fontSize, and color (more styles to come, but these are enough to keep me busy for the moment)

ex: (code  samples, below, are truncated for brevity; also, I use Prototype)

lab.prototype.method.applyFontFace = function(face){
// some init-type stuff
if(!rangy.getSelection().isCollapsed) {
    var css = "sflab_"+(+new Date());
    var cap = rangy.createCssClassApplier(css,{elementProperties:{style:{fontFamily:face}}})
    cap.applyToSelection();

    $$('.'+css)[0].removeAttribute('class');
}
// some cleanup-type stuff
}

Upon change, inspection of DOM indicates that I have:

<span style='font-face: Arial'>Hello, warts!</span> -- Perfect, precisely what I want.

However, when I go about invoking that method for a 2nd (or 3rd, or 4th, etc) time, something odd happens.

Let us say that I invoke my method, applyFontFace(), with 'Courier' as my argument, upon execution and DOM inspection, I see that my Element is still:
<span style='font-face: Arial'>Hello, warts!</span>

When I would expect to see: 

<span style='font-face: Courier'>Hello, warts!</span>

Now, if I include the useExistingElements:true property, I end up with:
<span style='font-face: Arial'>
   <span style='font-face: Courier'>
        Hello, warts!
   </span>
</span>

Thus, the browser sees this HTML, and does a bang-up job of rendering it, but, I cannot have this extraneous code in my DOM. 

Moreover, the same things are happening with my other methods, applyColor, and applyFontSize. Initially, the styles are set, and wow, things look good. But when I go about re-running the operation with a different color, or font-size, they do not seem to be respected or applied. Consequently, my DOM is inaccurate, my users (will) get peeved, refused to pay, my children starve, and my wife leaves me for the cabana boy.

Additionally, without code samples, the following behavior is also manifesting itself:

I select a range of text, then, apply a fontFamily, let us say, 'Arial'. The string changes fontFamily to 'Arial'. Perfect. But, let us say that my next step is to select a lager range, whilst encompassing my original (now stylistically altered) range. I execute the fontFamily change, setting fontFamily to 'Courier', and my results are quite odd. The text from the first change remains 'Arial', the new selection text is 'Courier'. I would expect that the entirety of my selection would now be 'Courier'. Try this in a word processor type application, and you will see my desired results.

ex: 
[original]
<span>The quick brown dog jumps over the lazy dog</span>

Step 1: Select 'dog jumps', and apply font face, 'Arial'
result:
<span>The quick brown <span style='font-family: Arial'>dog jumps</span> over the lazy dog</span>

Step 2: Select 'quick brown dog dumps over the', and apply font-face, 'Courier'
result:
<span>The <span style='font-family: Courier'>quick brown <span style='font-family: Arial'>dog jumps</span> over</span> the lazy dog</span>

Expected (read: desired) result:
<span>The <span style='font-family: Courier'>quick brown dog jumps over</span> the lazy dog</span>

------

Given what you have read above, is there some fundamental error in my logic, or, are there a faults in the rangy library? I prefer the former answer to the latter.

 Please elucidate, and, thank you.

Jeff Levy

unread,
Jul 26, 2012, 12:57:00 PM7/26/12
to ra...@googlegroups.com
OH! I should also note, that, in the end, I expect my three methods to be additive, in that:

Starting with:

<span>The quick brown fox jumped over the lazy dog</span>

Applying a fontFamily, a size, and a color, in three separate operations, would result in:

<span style='font-family: Courier; font-size: 24pt; color: rgb(10,10,10)'>The quick brown fox jumped over the lazy dog</span>

Tim Down

unread,
Jul 26, 2012, 7:43:05 PM7/26/12
to ra...@googlegroups.com
Hi Jeff,

The behaviour you're seeing is partly by design and partly a bug. The
larger issue is that you're pushing the boundaries of what I'd
intended the CSS class applier to do and I haven't finished the more
generic commands module that will fix this (rough demo from 2011:
http://rangy.googlecode.com/svn/trunk/demos/commands.html).

The CSS class applier is careful about which elements it will dare to
touch: only elements that have the exact properties it expects and no
others are fair game. However, it should be checking an element has
the properties it expects before reusing it and isn't, which is a bug.
I've now fixed it and it will be in the next 1.3 alpha release.

When you set useExistingElements to false (I assume this is what you
meant: the default is true, and the output you get is consistent with
it being false), this is working as intended. The CSS class applier is
mainly concerned with adding and removing classes; it will set other
properties and check against those properties to decide whether to use
an existing element or create a new one, but that's it. Anything more
sophisticated I think should go into the currently-unfinished commands
module. Sorry it's not quite there yet. My sympathies to your
children.

Tim

DwD

unread,
Nov 16, 2012, 4:35:01 AM11/16/12
to ra...@googlegroups.com, t...@timdown.co.uk
I changed the
rangy-cssclassapplier.js     

and added the line:
this.copyPropertiesToElement(this.elementProperties, parent, false);
to the applyToTextNode function

I'am not a developper of rangy but for me it works:

  applyToTextNode: function(textNode, positionsToPreserve) {
            var parent = textNode.parentNode;
            if (parent.childNodes.length == 1 && dom.arrayContains(this.tagNames, parent.tagName.toLowerCase()) && this.useExistingElements) {
                this.copyPropertiesToElement(this.elementProperties, parent, false);
                addClass(parent, this.cssClass);
            } else {
                var el = this.createContainer(dom.getDocument(textNode));
                textNode.parentNode.insertBefore(el, textNode);
                el.appendChild(textNode);
            }
        },

DwD

unread,
Nov 16, 2012, 5:43:58 AM11/16/12
to ra...@googlegroups.com, t...@timdown.co.uk

after that i was able to create something like this
var val = 4;
var letterSpacing = rangy.createCssClassApplier("letterSpacingSpinner", {
                            elementTagName : "span",
                            elementProperties : {
                                style : {
                                    "letterSpacing" : val+"px"
                                }
                            },
                            applyToEditableOnly : true,
                            normalize : false
                        });


                 if(letterSpacing.isAppliedToSelection())
                letterSpacing.undoToSelection();

                letterSpacing.applyToSelection();
Reply all
Reply to author
Forward
0 new messages