Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

zen-coding: ability to ascend the DOM tree using ^

I forked the excellent zen-coding project, with an idea to implement DOM ascension using a ^ - so you can do:

html>head>title^body>h1 rather than html>(head>title)+body>h1

Initially I implemented with rather shoddy regex methods. I have now implemented using @Jordan's excellent answer. My fork is here

What I still want to know

Are there any scenarios where my function returns the wrong value?

like image 999
Billy Moon Avatar asked Apr 01 '11 11:04

Billy Moon


1 Answers

Disclaimer: I have never used zen-coding and this is only my second time hearing about it, so I have no idea what the likely gotchas are. That said, this seems to be a working solution, or at least very close to one.

I am using Zen Coding for textarea v0.7.1 for this. If you are using a different version of the codebase you will need to adapt these instructions accordingly.

A couple of commenters have suggested that this is not a job for regular expressions, and I agree. Fortunately, zen-coding has its own parser implementation, and it's really easy to build on! There are two places where you need to add code to make this work:

  1. Add the ^ character to the special_chars variable in the isAllowedChar function (starts circa line 1694):

    function isAllowedChar(ch) {
        ...
        special_chars = '#.>+*:$-_!@[]()|^'; // Added ascension operator "^"
    
  2. Handle the new operator in the switch statement of the parse function (starts circa line 1541):

    parse: function(abbr) {
        ...
        while (i < il) {
            ch = abbr.charAt(i);
            prev_ch = i ? abbr.charAt(i - 1) : '';
            switch (ch) {
                ...
                // YOUR CODE BELOW
                case '^': // Ascension operator
                    if (!text_lvl && !attr_lvl) {
                        dumpToken();
                        context = context.parent.parent.addChild();
                    } else {
                        token += ch;
                    }
                    break;
    

    Here's a line-by-line breakdown of what the new code does:

    case '^':                         // Current character is ascension operator.
        if (!text_lvl && !attr_lvl) { // Don't apply in text/attributes.
            dumpToken();              // Operator signifies end of current token.
    
                                      // Shift context up two levels.
            context = context.parent.parent.addChild();
    
        } else {
            token += ch;              // Add char to token in text/attribute.
        }
        break;
    

The implementation above works as expected for e.g.:

html>head>title^body
html:5>div#first>div.inner^div#second>div.inner
html:5>div>(div>div>div^div)^div*2
html:5>div>div>div^^div

You will doubtless want to try some more advanced, real-world test cases. Here's my modified source if you want a kick-start; replace your zen_textarea.min.js with this for some quick-and-dirty testing.

Note that this merely ascends the DOM by two levels and does not treat the preceding elements as a group, so e.g. div>div^*3 will not work like (div>div)*3. If this is something you want then look at the logic for the closing parenthesis character, which uses a lookahead to check for multiplication. (Personally, I suggest not doing this, since even for an abbreviated syntax it is horribly unreadable.)

like image 174
Jordan Gray Avatar answered Sep 25 '22 23:09

Jordan Gray