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?
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:
Add the ^ character to the
special_chars
variable in theisAllowedChar
function (starts circa line 1694):function isAllowedChar(ch) { ... special_chars = '#.>+*:$-_!@[]()|^'; // Added ascension operator "^"
Handle the new operator in the
switch
statement of theparse
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.)
You should look for Perl's Text::Balanced alternative in the language that you're using.
精彩评论