QueryPath changing iframe tags to self-closing? - querypath

I'm using QueryPath to wrap a <div> around embedded videos on a site that contains a mixture of <object> and <iframe> embeds.
I tried the following code:
$content = qp($content)
->find('object,iframe,a.evdPlayer')
->wrap('<div class="splashBack"></div>')
->top('body')->children()
->html(); // << It's wanting to remove the </iframe> Grrr.
return $content;
But it seems to want to change my <iframe></iframe> code to <iframe />, which is messing things up for some reason. Is there a way to keep it from changing the tags it's wrapping?
Thanks in advance!

the ->html method does not set the LIBXML_NOEMPTYTAG flag when using DOMDocument::saveXML, if you need the closing tags you should use ->xhtml instead which passes this flag. eg
$content = qp($content)
->find('object,iframe,a.evdPlayer')
->wrap('<div class="splashBack"></div>')
->top('body')->children()
->xhtml();
return $content;

Found a solution that seems to work. It turns out that by inserting some content between the ... querypath recognizes the need for the closing tag and leaves it alone. It's a hack, but it works for now!
$content = qp($content)
->find('object,iframe,a.evdPlayer')
->text('[ video embed ]')
->wrap('<div class="splashBack"></div>')
->top('body')->children()
->html(); // << It's wanting to remove the </iframe>
return $content;

Related

Including SVG contents in Laravel 5 Blade template

What is the best way to include the contents of an SVG file (located in the assets folder) in a Laravel 5 blade template?
I don't want to use image/object/embed tags, this should be an inline SVG for reasons of speed.
I know I could use <?php file_get_contents("file.svg") ?> but is there a better way specific to Laravel/Blade?
Edit: to clarify, the method should work with all SVG files, including the one below.
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg">
<path stroke="red" fill="#00f" d="M10 10h100v100H10z"/>
</svg>
Similar to the accepted answer but a bit cleaner (imo).
Use the laravel directive to extend blade, like so (in your App Service Provider, as outlined here):
\Blade::directive('svg', function($arguments) {
// Funky madness to accept multiple arguments into the directive
list($path, $class) = array_pad(explode(',', trim($arguments, "() ")), 2, '');
$path = trim($path, "' ");
$class = trim($class, "' ");
// Create the dom document as per the other answers
$svg = new \DOMDocument();
$svg->load(public_path($path));
$svg->documentElement->setAttribute("class", $class);
$output = $svg->saveXML($svg->documentElement);
return $output;
});
Then use it in your blade like so:
<div class="Login__image Login__cloud">
#svg('cloud.svg', 'Cloud')
</div>
This works, that's the simplest way I could think about :
{!! file_get_contents('images/icon.svg') !!}
Why not place the svg into a blade template?
resources/views/icons/dashboard.blade.php
then add in your views using blade syntax?
#include('icons.dashboard')
View Composer Method
I ended up using a view composer in a service provider.
In the service provider's boot() method:
// Wildcard view composer
view()->composer('*', function($view) {
// Instantiate new DOMDocument object
$svg = new DOMDocument();
// Load SVG file from public folder
$svg->load(public_path('images/logo.svg'));
// Add CSS class (you can omit this line)
$svg->documentElement->setAttribute("class", "logo");
// Get XML without version element
$logo = $svg->saveXML($svg->documentElement);
// Attach data to view
$view->with('logo', $logo);
});
And in my view:
<!-- Echo unescaped SVG content -->
{!! $logo !!}
I am using DOMDocument as it allows me to remove the XML version element which should not be in the HTML.
The CSS class is not essential but saves me wrapping the logo with another HTML element for styling.
If you only need the logo in a specific Blade partial such as header you could write
view()->composer('header', function($view) {});
http://laravel.com/docs/5.0/views#view-composers
https://laracasts.com/series/laravel-5-fundamentals/episodes/25
Blade Partial Method
This method is not best practice since this sort of code should not really be in a view. However it is very simple and much better than adding PHP code in every single view.
Make a new partial (lets say logo.blade.php) with the following code:
<?php
// Instantiate new DOMDocument object
$svg = new DOMDocument();
// Load SVG file from public folder
$svg->load(public_path('images/logo.svg'));
// Add CSS class (you can omit this line)
$svg->documentElement->setAttribute("class", "logo");
// Echo XML without version element
echo $svg->saveXML($svg->documentElement);
?>
You can now use the SVG image in a blade template by including the partial like so:
#include('logo')

How to add classes (e.g. lib) to a given Typo3 extension?

I got a (imho) minor noob question concerning writing of Typo3 Extensions (ver. 4.5 LTS). What I try is simply make up a little MVC class pattern which contains a small curl statement to retrieve information from a remote location. In principle, the MVC classes are already implemented and I just want to include them into the main procedure of my plugin extension. That was what I guessed to work:
class tx_uniklstudgangext2013_pi1 extends tslib_pibase {
public $prefixId = 'tx_uniklstudgangext2013_pi1'; // Same as class name
public $scriptRelPath = 'pi1/class.tx_uniklstudgangext2013_pi1.php'; // Path to this script relative to the extension dir.
public $extKey = 'uniklstudgangext2013'; // The extension key.
public $pi_checkCHash = TRUE;
/**
* The main method of the Plugin.
*
* #param string $content The Plugin content
* #param array $conf The Plugin configuration
* #return string The content that is displayed on the website
*/
public function main($content, array $conf) {
$this->conf = $conf;
$this->pi_setPiVarDefaults();
$this->pi_loadLL();
$view = t3lib_div::makeInstance('tx_uniklstudgangext2013_pi1_view');
// !HERE! : also tried with new(), since I don't want to deal with XCLASS here...
// this works: $content = "<p>Hello world!</p>";...the line below doesn't...
$content = $view->getCourseInfoOutput();
/*'
<strong>This is a few paragraphs:</strong><br />
<p>This is line 1</p>
<p>This is line 2</p>
<h3>This is a form:</h3>
<form action="' . $this->pi_getPageLink($GLOBALS['TSFE']->id) . '" method="POST">
<input type="text" name="' . $this->prefixId . '[input_field]" value="' . htmlspecialchars($this->piVars['input_field']) . '" />
<input type="submit" name="' . $this->prefixId . '[submit_button]" value="' . htmlspecialchars($this->pi_getLL('submit_button_label')) . '" />
</form>
<br />
<p>You can click here to ' . $this->pi_linkToPage('get to this page again', $GLOBALS['TSFE']->id) . '</p>
';
*/
return $this->pi_wrapInBaseClass($content);
}
}
I am a beginner in the Typo3 programming and I guess there are a hundred implicit issues I don't have in mind so far (by just not knowing how Typo3 operates implicitly). What I tried/did so far:
Disabling the template-cache globally by setting it up in the root template.
Conversion of all new statements into makeInstance(); not wanting this hookup to screw all my MVC code, I overwrote the called method $view->getCourseInfoOutput() by
public function getCourseInfoOutput() {
return "hello world!";
//return $this->_model->getTemplateByCourseId(5);
}
which leads me to the next issue: It just does not get the hello world within this! It seems, that Typo3 anyhow supresses the return value from classes out of the extension root class
When I put all the code successively into the main method, it worked out just fine
Could anyone please help me :/ I admit, that there is a slight possibility that I totally misunderstood how extensions work, but, as I said, I just want my code to run within the extension and simply return one single value. Is this really that hard?
Greetings & thx in advance!
$content is any HTML string. If you created the extension with the kickstarter or used any existing extension as boilerplate, then you just have to care about what happens inside you function.
This totally depends on you. TYPO3 will create your class and will call the main method and use the return value as content.
You can find all relevant docs at http://docs.typo3.org/typo3cms/CoreApiReference/ExtensionArchitecture/Index.html
You must of course not use any HTML inside your function. Your function must return the content as concatenate string with a return statement.
TYPO3 CMS uses ob_clean to flush the output buffer. If you forcefully output anything before TYPO3 CMS does, then you will break it.

jQuery GET html as traversable jQuery object

This is a super simple question that I just can't seem to find a good answer too.
$.get('/myurl.html', function(response){
console.log(response); //works!
console.log( $(response).find('#element').text() ); //null :(
}, 'html');
I am just trying to traverse my the html response. So far the only thing I can think of that would works is to regex to inside the body tags, and use that as a string to create my traversable jQuery object. But that just seems stupid. Anyone care to point out the right way to do this?
Maybe its my html?
<html>
<head>
<title>Center</title>
</head>
<body>
<!-- tons-o-stuff -->
</body>
</html>
This also works fine but will not suit my needs:
$('#myelem').load('/myurl.html #element');
It fails because it doesn't like <html> and <body>.
Using the method described here: A JavaScript parser for DOM
$.get('/myurl.html', function(response){
var doc = document.createElement('html');
doc.innerHTML = response;
console.log( $("#element", doc).text() );
}, 'html');
I think the above should work.
When jQuery parses HTML it will normally strip out the html and body tags, so if the element you are searching for is at the top level of your document structure once the html and body tags have been removed then the find function may not be able to locate the element you're searching for.
See this question for further info - Using jQuery to search a string of HTML
Try this:
$("#element", $(response)).text()
This searches for the element ID in the $(response) treating $(response) as a DOM object.
Maybe I'm misunderstanding something, but
.find('#element')
matches elements with an ID of "element," like
<p id="element">
Since I don't see the "tons of stuff" HTML I don't understand what elements you're trying to find.

AJAX replace content in DIV not by ID or class

Can some one help me..
I have a script who generates code like this >>
<div id="imageok">img1.png</div>
<div id="imageok">img22.jpg</div>
<div id="imageok">img333.gif</div>
In AJAX the name of the image is called imgname its equal to content of the div.
I want to replace the text inside the div but I can't use the id because its the same for each div.. I tried to search for div by it content (I have the name of the image in the AJAX)
Perhaps its something like..
GET element where content =="img1.png" > replace
I just can't write it correct..
Please help me .
I think what you are trying to do can be accomplished more 'neatly' with jQuery.
Have you used jQuery before? If yes, then you can do something like this:
// get content into a variable called 'result'
$('div').each(function(i) {
if ($(this).text() == 'img1.png') {
$(this).text(result);
}
});
I haven't tested this code. Hope it helps.

Getting raw text using #Html.ActionLink in Razor / MVC3?

Given the following Html.ActionLink:
#Html.ActionLink(Model.dsResults.Tables[0].Rows[i]["title"].ToString(), "ItemLinkClick",
new { itemListID = #Model.dsResults.Tables[0].Rows[i]["ItemListID"], itemPosNum = i+1 }, ...
Data from the model contains HTML in the title field. However, I am unable to display the HTML encoded values. ie. underlined text shows up with the <u>....</u> around it.
I've tried Html.Raw in the text part of the ActionLink, but no go.
Any suggestions?
If you still want to use a helper to create an action link with raw HTML for the link text then I don't believe you can use Html.ActionLink. However, the answer to this stackoverflow question describes creating a helper which does this.
I would write the link HTML manually though and use the Url.Action helper which creates the URL which Html.ActionLink would have created:
<a href="#Url.Action("ItemLinkClick", new { itemListID = #Model.dsResults.Tables[0].Rows[i]["ItemListID"], itemPosNum = i+1 })">
#Html.Raw(Model.dsResults.Tables[0].Rows[i]["title"].ToString())
</a>
MVCHtmlString.Create should do the trick.
Using the actionlink below you do not need to pass html in the model. Let the css class or inline style determine how the href is decorated.
#Html.ActionLink(Model.dsResults.Tables[0].Rows[i]["title"], "ItemLinkClick", "Controller", new { #class = "underline", style="text-decoration: underline" }, null)
those are the cases that you should take the other path
#{
string title = Model.dsResults.Tables[0].Rows[i]["title"].ToString(),
aHref = String.Format("/ItemLinkClick/itemListID={0}&itemPosNum={1}...",
Model.dsResults.Tables[0].Rows[i]["ItemListID"],
i+1);
}
#Html.Raw(title)
Remember that Razor helpers, help you, but you can still do things in the HTML way.
You could also use this:
<a class='btn btn-link'
href='/Mycontroler/MyAction/" + item.ID + "'
data-ajax='true'
data-ajax-method='Get'
data-ajax-mode='InsertionMode.Replace'
data-ajax-update='#Mymodal'>My Comments</a>

Resources