Hey guy i'm having trouble to get this work, any help would be much apreciated
I usually use this in my ejs engine template
<%= blog.created_at.getFullYear() %>
<%= blog.short_name.replace(new RegExp(" ", "g"), "-") %>
<%= blog.content.match(/<img[^>]+src="([^">]+)/)[1] %>
but I have trouble making this work in .dot engine. I know my problem are javascript function, regex and match I'm using. meaning bold part, is not correct here ( getFullYear() , replace(new RegExp(" ", "g"), "-") , match(/]+src="([^">]+)/)[1] )
{%= blog.created_at.getFullYear() %}
{%= blog.short_name.replace(new RegExp(" ", "g"), "-") %}
{%= blog.content.match(/<img[^>]+src="([^">]+)/)[1] %}
what should be use instead in those cases?
Thanks
after some test I realized:
first : I'm doing this wrong. I'm trying to gen and img's src from a html string (that's what the regex does ) but does it really need to be that way?? ...of course NO. So the best thing in my case is do this on the route before render using underscore.
_.map(array, function(object,key){
return _.extend(object, {image: img_sources || 'image'});
});
second: the problem here resides in chars like "(double quotes), [ ]
(squarebrackes) , and probably some other . I'have achieved a way to replace all those chars and still the regex work. Use the better the solution above.
Related
I was experimenting with Rust's macro_rules and wanted to make a macro which could parse an HTML like syntax and simply echo the HTML as a string. The below macro gets most of the way there:
macro_rules! html {
() => ("");
($text:tt) => {{
format!("{}", $text)
}};
(<$open:ident>[$($children:tt)*]</$close:ident>$($rest:tt)*) => {{
format!("<{}>{}</{}>{}",
stringify!($open),
html!($($children)*),
stringify!($close),
html!($($rest)*))
}};
}
and then to use the macro:
println!("{}",
html!(
<html>[
<head>[
<title>["Some Title"]</title>
]</head>
<body>[
<h1>["This is a header!"]</h1>
]</body>
]</html>
)
);
However, I would really like to remove the extraneous opening and closing square brackets. I attempt to do that as follows:
macro_rules! html_test {
() => ("");
($text:tt) => {{
format!("{}", $text)
}};
(<$open:ident>$($children:tt)*</$close:ident>$($rest:tt)*) => {{
format!("<{}>{}</{}>{}",
stringify!($open),
html!($($children)*),
stringify!($close),
html!($($rest)*))
}};
}
However, when I go to use this macro:
println!("{}",
html_test!(
<html>
<head>
<title>"Some Title"</title>
</head>
<body>
<h1>"This is a header!"</h1>
</body>
</html>
)
);
I get the error: local ambiguity: multiple parsing options: built-in NTs tt ('children') or 1 other option.
I know the general solution to this error is to add syntax to disambiguate the cases (such as adding the square brackets). Is there any other way around this issue for this specific example? I know using procedural macros would be an extreme solution, but I would prefer to use macro_rules if at all possible.
I realize using a macro to simply get a string containing HTML is overkill, but it was solely for the sake of this questions. Potentially, one could do much more interesting things with the macro such as calling functions to build up a tree representing the HTML structure.
Do you want the macro to actually be usable? Then no. Actually, why even use a macro here at all? No matter what you do, you're going to be fighting the Rust lexer at some point. Just write the HTML in a string literal like:
r##"<html>
<head>
<title>Some Title</title>
</head>
<body>
<h1>This is a header!</h1>
</body>
</html>"##
That or accept that macro input cannot match actual HTML syntax, close tab, move on.
You're still here? Oh, so you don't care about usability or performance? You really want a marginal improvement in syntax, no matter the cost? *rolls up sleeves*
Be careful what you wish for.
You need to use an incremental parser, which allows you to bypass some of the ambiguous parse issues. Rather than trying to match a non-delimited group (which you can't do), you instead recursively match unique prefixes. Doing that leads to:
macro_rules! html_test {
(#soup {$($parts:expr,)*}, [], ) => {
concat!($($parts),*)
};
(#soup $parts:tt, [$head:ident $($stack:ident)*], ) => {
compile_error!(
concat!(
"unexpected end of HTML; the following elements need closing: ",
stringify!($head),
$(",", stringify!($stack),)*
"."
)
)
};
(#soup {$($parts:tt)*}, [$ex_close:ident $($stack:ident)*], </$got_close:ident> $($tail:tt)*) => {
{
macro_rules! cmp {
($ex_close) => {
html_test!(
#soup
{$($parts)* "</", stringify!($ex_close), ">",},
[$($stack)*], $($tail)*
)
};
($got_close) => {
compile_error!(
concat!(
"closing element mismatch: expected `",
stringify!($ex_close),
"`, got `",
stringify!($got_close),
"`"
)
)
};
}
cmp!($got_close)
}
};
(#soup {$($parts:tt)*}, $stack:tt, <img $($tail:tt)*) => {
html_test!(#tag {$($parts)* "<img",}, $stack, $($tail)*)
};
(#soup {$($parts:tt)*}, [$($stack:ident)*], <$open:ident $($tail:tt)*) => {
html_test!(
#tag
{$($parts)* "<", stringify!($open),},
[$open $($stack)*],
$($tail)*
)
};
(#soup {$($parts:tt)*}, $stack:tt, $text:tt $($tail:tt)*) => {
html_test!(#soup {$($parts)* $text,}, $stack, $($tail)*)
};
(#tag {$($parts:tt)*}, $stack:tt, > $($tail:tt)*) => {
html_test!(#soup {$($parts)* ">",}, $stack, $($tail)*)
};
(#tag {$($parts:tt)*}, $stack:tt, $name:ident=$value:tt $($tail:tt)*) => {
html_test!(
#tag
{$($parts)* " ", stringify!($name), "=", stringify!($value),},
$stack, $($tail)*
)
};
($($tts:tt)*) => {
html_test! { #soup {}, [], $($tts)* }
};
}
This works by crawling over the input tokens, keeping track of the string pieces that need to be output (in $($parts)*), and the opened tags that need closing (in $($stack)*). Once it's out of input, and the stack is empty, it concat!s all the parts together, producing a single static string literal.
This has four problems:
This chews through recursion levels like crazy. If you run out, users will need to globally up the recursion limit.
Macros like this are slow.
Error reporting sucks. Although this will check the closing tags match the corresponding opening tags, problems aren't reported at any particular location in the invocation.
You still can't avoid needing to use string literals. You cannot match an expression that is followed by < or another expression, so matching the strings must be the (sole) fallback rule.
So you can remove the delimiters, but I wouldn't recommend it. Just quote the HTML like a sane person.
As an aside, here is an alternative version of the macro with a slightly different structure that factors out the cmp macro, and is easier to extend for elements without closing tags. Note that I did not write this version.
In my form i have a zend_form_element_textarea. For this element i add a validator StringLength like this:
$this->addElement('textarea', 'text', array('label' => 'F_MESSAGE_SMS_TEXT', 'required' => true, 'class' => 'fieldLiveLimit', 'limit' => 160));
$this->text->addValidator('StringLength', false, array('max' => 160));
and i use a script javascript for show live countdown characters:
//Text field or text area limit - get limit by field parameter
$(".fieldLiveLimit").each(function () {
var characters = $(this).attr('limit');
var remaining = calcDifference(characters, $(this).val());
if ($('.limitCounter').length > 0) {
$(this).after($('.limitCounter').first().clone());
$(this).next('.limitCounter').children('span').html(remaining);
} else {
$(this).after($("<div class='limitCounter'>" + translate('L_LIMIT_COUNTER', [remaining]) + "</div>"));
}
checkClassCounter(remaining, $(this));
$(this).bind('textchange', function (event, previousText) {
remaining = calcDifference(characters, $(this).val());
checkClassCounter(remaining, $(this));
if ($(this).val().length > characters) {
$(this).val($(this).val().substr(0, characters));
} else {
$(this).next('.limitCounter').children('span').html(remaining);
}
});
function calcDifference(characters, value) {
return characters - parseInt(value.length);
}
function checkClassCounter(remaining, element) {
if (parseInt(element.val().length) == 0) {
element.next(".limitCounter").hide();
} else {
element.next(".limitCounter").show();
if (remaining <= 10) {
element.next(".limitCounter").addClass('red-message');
} else {
element.next(".limitCounter").removeClass('red-message');
}
}
}
});
this works well, except for one thing. If inside the text area there are the new lines, the validator zend the new line it counts as two characters, while my JS script as one.
who is wrong? I think the zend validator, but it seems really strange as a thing and then ask to you!
It has to do with the line breaks, as user Pankrates already pointed out in his comment.
In fact, this problem is a lot more complex than it seems at first, because it has at least two dimensions:
jQuery strips the carriage return character in the val() function: "At present, using .val() on textarea elements strips carriage return characters from the browser-reported value." jQuery documentation.
It is inconsistent along browsers how line breaks with \r\n are counted. See here or here for related questions on SO. However, on all browsers I have installed on my system (Firefox 20.0 and Chrome 26.0), \r\n are counted as two characters, so I cannot confirm this.
See this little code snippet for a demonstration:
<?php
$str1 = "test\nstring";
$str2 = "test\r\nstring";
?>
<textarea id="text1"><?php echo $str1 ?></textarea>jQuery: <span id="jquery1"></span>, JS: <span id="js1"></span>, PHP: <?php echo iconv_strlen($str1) ?>
<textarea id="text2"><?php echo $str2 ?></textarea>jQuery: <span id="jquery2"></span>, JS: <span id="js2"></span>, PHP: <?php echo iconv_strlen($str2) ?>
<script type="text/javascript">
$(document).ready(function() {
$("#jquery1").text($("#text1").val().length);
$("#js1").text("<?php echo str_replace(array("\n", "\r"), array('\n', '\r'), $str1) ?>".length);
$("#jquery2").text($("#text2").val().length);
$("#js2").text("<?php echo str_replace(array("\n", "\r"), array('\n', '\r'), $str2) ?>".length);
});
</script>
For the first box it gives me jQuery: 11, JS: 11, PHP: 11, but for the second box I get jQuery: 11, JS: 12, PHP: 12.
There are several solutions I can think of (none of which is ideal):
Use a Zend_Filter_PregReplace in your form to replace all \r\n with \n. Pro: Counting will be consistent with that of jQuery's val() and relatively easy. Con: You are destroying the user's line break which might lead to unwanted results.
Decorate the Zend_Validate_StringLength so that you can replace \r\n by \n in the isValid() method. Pro: Will preserve the user's line break, Con: You might get a valid result that is longer then 200 characters, because \r\n is counted as one character and you need to introduce a new class.
Use the jQuery's textarea.valHooks to replace all line breaks with \r\n: Pro: Simple, Con: If you have users that have \n as line break char, it again will give you inconsistent results.
I hope this answer show you some directions on how you can tackle this situation depending on your app's context.
I'm trying to follow a link in Perl.
My initial code:
use WWW::Mechanize::Firefox;
use Crypt::SSLeay;
use HTML::TagParser;
use URI::Fetch;
$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME}=0; #not verifying certificate
my $url = 'https://';
$url = $url.#ARGV[0];
my $mech = WWW::Mechanize::Firefox->new;
$mech->get($url);
$mech->follow_link(tag => 'a', text => '<span class=\"normalNode\">VSCs</span>');
$mech->reload();
I found here that the tag and text options work this way but I got the error MozRepl::RemoteObject: SyntaxError: The expression is not a legal expression. I tried to escape some characters in the text, but the error was still the same.
Then I changed my code adding:
my #list = $mech->find_all_links();
my $found = 0;
my $i=0;
while($i<=$#list && $found == 0){
print #list[$i]->url()."\n";
if(#list[$i]->text() =~ /VSCs/){
print #list[$i]->text()."\n";
my $follow =#list[$i]->url();
$mech->follow_link( url => $follow);
}
$i++;
}
But then again there's an error: No link found matching '//a[(#href = "https://... and a lot of more text that seems to be the link's description.
I hope I made myself clear, if not, please tell me what else to add. Thanks to all for your help.
Here's the part where the link I want to follow is:
<li id="1" class="liClosed"><span class="bullet clickable"> </span><b><span class="normalNode">VSCs</span></b>
<ul id="1.l1">
<li id="i1.i1" class="liBullet"><span class="bullet"> </span><b><span class="normalNode">First</span></b></li>
<li id="i1.i2" class="liBullet"><span class="bullet"> </span><b><span class="normalNode">Second</span></b></li>
<li id="i1.i3" class="liBullet"><span class="bullet"> </span><b><span class="normalNode">Third</span></b></li>
<li id="i1.i4" class="liBullet"><span class="bullet"> </span><b><span class="normalNode">Fourth</span></b></li>
<li id="i1.i5" class="liBullet"><span class="bullet"> </span><b><span class="normalNode">None</span></b></li>
</ul>
I'm working in Windows 7, MozRepl is version 1.1 and I'm using Strawberry perl 5.16.2.1 for 64 bits
After poking around with the given code I was able to make W::M::F to follow the links in a following manner:
use WWW::Mechanize::Firefox;
use Crypt::SSLeay;
use HTML::TagParser;
use URI::Fetch;
...
$mech->follow_link(xpath => '//a[text() = "<span class=\"normalNode\">VSCs</span>"]');
$mech->reload();
Note xpath parameter given instead of text.
I didn't take a long look into W::M::F sources, but under the hood it tries to translate given text parameter into XPath string, and if text contains number of XML/HTML tags, which is your case, it probably drives him crazy.
I recommend you to try :
$mech->follow_link( url_regex => qr/selector=All/ );
I needed to write a custom module in drupal to help out with my location search. Initially I simply needed to remove a comma from queries, and then I realized that I would need to replace all instances of states with their abbreviation (California -> CA) because of how information is stored in my database. However, upon doing this I found out that my method of using preg_replace seems to be dependent on upper/lowercase. So in this line:
$form_state['values'] = preg_replace("/alabama/", 'al', $form_state['values']);
"alabama" will be replaced with "al", but "Alabama" or "ALABAMA" will not. Is there a way to replace any instance of Alabama with its abbreviation without accounting for every possible variation in casings?
you can try also str_ireplace() it's Case-insensitive
<?php
$str = 'alabama ,Alabama,ALABAMA';
$replace = str_ireplace('alabama','al',$str);
echo $str;
echo "<br/>";
echo $test;
?>
$form_state['values'] = preg_replace("/alabama/i", 'al', $form_state['values']);
The 'i' modifier will make the pattern case-insensitive.
Do you ever escape single quotes in template toolkit for necessary javascript handlers? If so, how do you do it.
[% SET s = "A'B'C" %]
ABC
html_entity obviously doesn't work because it only handles the double quote. So how do you do it?
I don't use the inlined event handlers -- for the same reason I refuse to use the style attribute for css. Jquery just makes it to easy to do class="foo" on the html and $('.foo').click( function () {} ), in an external .js file.
But, for the purpose of doing my best to answer this question, check out these docs on Template::Filter for the ones in core.
It seems as if you could do [% s | replace( "'", "\\'" ) %], to escape single quotes. Or you could probably write a more complex sanitizing javascript parser that permits only function calls, and make your own Template::Filter
2018 update for reference:
TT has a method for this called squote for escaping single quotes and dquote for double quotes.
[% tim = "Tim O'Reilly" %]
[% tim.squote %] # Tim O\'Reilly
Questioned link would be something like:
ABC
http://www.template-toolkit.org/docs/manual/VMethods.html#section_squote
You can try: popup('[% s | html %]').
Perl isn't my strongest language... But!
Easiest way I've found is to use the JSON module. In a module called JS.pm or something:
use JSON;
sub encode () {
my $self = shift;
my $string = shift;
$json = JSON->new->allow_nonref;
return $json->encode( $string );
}
More here: http://search.cpan.org/~makamaka/JSON-2.90/lib/JSON.pm
Then in your template:
[% use JS; %]
<script>
var escaped_string = [% JS.encode( some_template_variable ) %];
</script>
Remember to double-escape the slash in the replacement, otherwise it will be interpreted as escaping the apostrophe.
[% string.replace( "'", "\\'" ) %]