I've got a foreach loop running on my site to display images. There are some images I do not wish to display however so I added an if statement to exclude these images. The problem though is that using the if statement within the loop means that I can't use $smarty.foreach.thumbnails.last to work out which image is last as it could be one of the hidden ones.
How would I go about filtering these images and still being able to use $smarty.foreach.thumbnails.last?
Here is my code as it stands:
{foreach from=$images item=image name=thumbnails}
{if $image.legend != "colorschemes"}
{assign var=imageIds value="`$product->id`-`$image.id_image`"}
<li data-imgtype="{$image.legend}" class="items{if $j == 1} main-pos{elseif $j == 2} right-pos{elseif $smarty.foreach.thumbnails.last} left-pos{else} back-pos{/if}" id="{$j}">
<img src="{$link->getImageLink($product->link_rewrite, $imageIds, 'tm_large_default')|escape:'html':'UTF-8'}" alt="Owl Image" style="width:100%; margin-top:-200px;" />
</li>
{$j = $j + 1}
{/if}
{/foreach}
One solution would be to filter the array in the back end before sending it to the template. This could potentially have better performance as the client won't be loading unnecessary images. The filtering could be done in php or sql.
Related
I retrieved all the links from the web page containing /title/tt inside the url in a list.
my #url_links= $mech->find_all_links( url_regex => qr/title\/tt/i );
but the list is too long so I want to filter by adding in the function find_all_Links that the link must be also in the tags starting with <id="actor-tt..."> here is where the link (/title/tt...) is, in the code source retrieved by cmd.exe:
<div class="filmo-row odd" id="actor-tt0361748">
<span class="year_column">
2009
</span>
<b><a href="/title/tt0361748/"
>Inglourious Basterds</a></b>
<br/>
Lt. Aldo Raine
</div>
I imagine you have to use a tag_regex but I don't know how because the command prompt doesn't seem to take tag_regex into account when I put it in.
Using HTML::TreeBuilder and HTML::Element instead of Mechanize:
use strict;
use warnings;
use feature 'say';
use HTML::TreeBuilder;
my $html_string = join "", <DATA>;
my $tree = HTML::TreeBuilder->new_from_content($html_string);
my #url_links = map { $_->attr_get_i("href") }
map { $_->look_down(href => qr{/title/tt}) }
$tree->look_down(id => qr/^actor-tt/);
say for #url_links;
__DATA__
<div class="filmo-row odd" id="actor-tt0361748">
<span class="year_column">
2009
</span>
<b>Inglourious Basterds</b>
<br/>
Lt. Aldo Raine
</div>
<div id="not-the-right-id">
</div>
<div class="filmo-row odd" id="actor-tt0123456">
<b>Another movie</b>
</div>
<div class="filmo-row odd" id="actor-tt0123456">
the id will match, but no href in here
</div>
$tree->look_down(id => qr/^actor-tt/); finds all elements whose id matches actor-tt. Then $_->look_down(href => qr{/title/tt}) will find all elements within them with a field href matching /title/tt. Finally, $_->attr_get_i("href") returns the value of their href fields.
You might be interested in the method new_from_url or new_from_file from HTML::TreeBuilder rather than the new_from_content I used.
WWW::Mechanize is not sophisticated enough to do what you're trying to do. It can only search links on one criterium at a time, and it converts them to WWW::Mechanize::Link objects, which do not maintain their ancestry (as in position in the DOM tree).
Mechanize is meant to be a browser, not a scraper. It's important to pick the right tools for the job you have to do.
As Dada suggested in their answer, you can use your own parser to search for this. You can still extract the HTML out of WWW::Mechanize and then use the code they suggest. Use $mech->content or $mech->content_raw to get the HTML out.
There are several alternatives to this. While I personally like Web::Scraper for this kind of task, its interface is a bit weird and has a learning curve.
Instead, I would suggest using Mojo::UserAgent and Mojo::DOM. In fact, the handy ojo package for one-liners should be able to do this.
perl -Mojo -E 'g("https://www.imdb.com/name/nm0000093/")->dom->find("div[id^=actor-tt] a")->map(sub {say $_->attr("href")})'
Broken down, this does the following:
use Mojo::UserAgent to get that page
look at the DOM tree
find all <a>s inside <div>s that have an id that starts with actor-tt (see https://metacpan.org/pod/Mojo::DOM::CSS#SELECTORS for details)
for each of them, print out the href attribute
You can customise this as much as you want.
Please note that according to their Terms of Services, scraping IMDB is not allowed.
I've got this code in my prestashop template, there is no loop, only conditional, and I get 5 back buttons (elseif section, first li tag), why is it happen?
{if $node.children|#count > 0 && ($smarty.get.controller!='product' && $smarty.get.controller!='category')}
<li class = "li-parent">
<asset class="menu-arrow-left"></asset>
<p><span>{$node.name|escape:'htmlall':'UTF-8'}</span></p>
{elseif $node.children|#count > 0 && ($smarty.get.controller=='product' || $smarty.get.controller=='category')}
<li class="li-back"><asset class="menu-arrow-right"></asset><p class="class="border-bottom-grandiet-small"><span>Back</span></p></li>
<li class = "li-parent">
<p><span>{$node.children[0].name|escape:'htmlall':'UTF-8'}</span></p>
{/if}
I don't see anything in this code that could cause displaying 5 back buttons. I suspect this code is included in some kind of loop and that's why it's displayed 5 times.
You should change the whole above code with:
testonly
and then look at page or page source and check how many testonly texts will appear.
It's also possible if you really use loop that you should use some extra condition. For example instead of:
<li class="li-back"><asset class="menu-arrow-right"></asset><p class="class="border-bottom-grandiet-small"><span>Back</span></p></li>
you should use
{if $node.children|#iteration eq 1}
<li class="li-back"><asset class="menu-arrow-right"></asset><p class="class="border-bottom-grandiet-small"><span>Back</span></p></li>
{/if}
and probably the rest should be more similar to the first condition so instead of:
<li class = "li-parent">
<p><span>{$node.children[0].name|escape:'htmlall':'UTF-8'}</span></p>
you should use:
<li class = "li-parent">
<p><span>{$node.name|escape:'htmlall':'UTF-8'}</span></p>
but it's really hard to say if we don't know what's the data structure and what exactly you want to achieve. If it still doesn't work you should provide more details to your question, explain what you want to achieve, what data you have in your variables and so on.
I have a problem with outputting categories in to a list.
It seems to create another ul(one for the channel:categories) within the my ul, and also creates empty lists before each list.
I used the exact same code for entries and it worked fine.
Is this a categories problem?
Here is the Code:
<ul>
<li><a {if segment_2 == ""} class="selected" {/if} href="">News & Events</a></li>
{exp:channel:categories
channel="news_events"
disable="pagination|member_data|trackbacks"
dynamic="no"}
<li>{category_name}</li>
{/exp:channel:categories}
<li><a {if segment_2 == "gallery"} class="selected"{/if} href="">Image Gallery</a></li>
Any help would be appreciated!
With regard to the code output, take a look at the style parameter for the channel categories tag: http://ellislab.com/expressionengine/user-guide/modules/channel/categories.html#channel-categories-style. You'll want to change it to style="linear" to use your own markup.
As for the blank output, it's going to be tough to diagnose without seeing your install but try getting rid of dynamic="no".
I have basic task to print something from template tag.
It works if I open html file from filesystem, but it prints nothing if I run this from django web-server.
For example:
<li ng-repeat="k in [0, 1, 2]">{{k}}</li>
Output if I open file from filesystem:
<li>0</li>
<li>1</li>
<li>2</li>
And if I get file from Django web-server:
<li></li>
<li></li>
<li></li>
This problem is driving me crazy :(
If Django is messing with the {{}} tags, you can change the template tags like this:
var app = angular.module('myApp', []);
app.config(function($interpolateProvider) {
$interpolateProvider.startSymbol('((');
$interpolateProvider.endSymbol('))');
});
http://docs.angularjs.org/api/ng.$interpolateProvider
Be careful while using (( )). You can get problems with function calls inside (( )).
Also note the use of third-party directives (components) that use {{ }}. Your configuration will break them.
See https://stackoverflow.com/a/11108407/457375
I have suffered a number of XSS attacks against my site. The following HTML fragment is the XSS vector that has been injected by the attacker:
<a href="mailto:">
<a href=\"http://www.google.com onmouseover=alert(/hacked/); \" target=\"_blank\">
<img src="http://www.google.com onmouseover=alert(/hacked/);" alt="" /> </a></a>
It looks like script shouldn't execute, but using IE9's development tool, I was able to see that the browser translates the HTML to the following:
<a href="mailto:"/>
<a onmouseover="alert(/hacked/);" href="\"http://www.google.com" target="\"_blank\"" \?="">
</a/>
After some testing, it turns out that the \" makes the "onmouseover" attribute "live", but i don't know why. Does anyone know why this vector succeeds?
So to summarize the comments:
Sticking a character in front of the quote, turns the quote into a part of the attribute value instead of marking the beginning and end of the value.
This works just as well:
href=a"http://www.google.com onmouseover=alert(/hacked/); \"
HTML allows quoteless attributes, so it becomes two attributes with the given values.