TYPO3 fluid: how to create link to PDF-File (no download, no display) - pdf

Being new to TYPO3 fluid I was wondering if there's an easy way to create a link to a PDF-file which is located in the filelist as you would in simple html as follows:
Click here to open pdf (in a new window)
I couldn't find a solution so far that wouldn't require an extension or that wouldn't render the pdf direclty on the page (<flux:field.inline.fal name="settings.image" required="1" maxItems="1" minItems="1"/>)
Should/Can this be done with <f:link.external href="filePathOnServer/file.pdf"> ? (I've got another problem at the moment preventing me from checking if this works...)
EDIT
I've tried using <f:link.external> which didn't work. For the time being I'm using the (non-fluid) <a>-tag...

I had to do the same thing and I resolved it by writing a custom ViewHelper just to get the site url.
ViewHelper:
class InternalViewHelper extends AbstractViewHelper
{
/**
* Renders a link to a specific path from the root path of TYPO3.
*
* #param string $path The path to an internal resource relative to the TYPO3 site URL.
* #return string The absolute URL to the given resource.
*/
public function render($path)
{
$siteUrl = GeneralUtility::getIndpEnv('TYPO3_SITE_URL');
return htmlspecialchars($siteUrl . $path);
}
}
Fluid Template:
{namespace ext = Vendor\MyExt\ViewHelpers}
<f:link.external target="_blank"
uri="{ext:internal(path: 'uploads/tx_myext/myfile.pdf')}">
Link
</f:link.external>

Related

Replacement for deprecated TYPO3 ErrorpageMessage

After the upgrade of the extension tt_board to TYPO3 10 I stumble over deprecation #77164 - ErrorpageMessage and AbstractStandaloneMessage.
The official page only states that the new Fluid-based ErrorPageController class should be used instead.
However this controller class is just able to generate a HTML result string for me. But the second half of the job is missing. The HTML output must be shown somehow by TYPO3 in an error dialog raised by an exception.
Is there any simple solution for this?
Before:
use TYPO3\CMS\Core\Messaging\ErrorpageMessage;
...
$message = $languageObj->getLabel('error_no_permission');
$title = $languageObj->getLabel('error_access_denied');
$messagePage =
GeneralUtility::makeInstance(
ErrorpageMessage::class,
$message,
$title
);
$messagePage->output();
Now:
use TYPO3\CMS\Core\Controller\ErrorPageController;
...
$message = $languageObj->getLabel('error_no_permission');
$title = $languageObj->getLabel('error_access_denied');
$errorController =
GeneralUtility::makeInstance(
ErrorPageController::class
);
$content = GeneralUtility::makeInstance(ErrorPageController::class)->errorAction(
$title,
$message
);
Can I send this $content to a TYPO3 object which will do the error output for the extension?
In general you can show it an any possible way, but you can use flashMessages to show it in standardized kind.
Be aware that for the frontend you have to implement according CSS for the styling.
In fluid it's looking like this and is part of extensions created with extension_builder:
<f:flashMessages />
It might be possible that you have to implement it a bit different to loop about several messages. I never use it usually but I remember that implementation changed once and doubt that it's reflected by this kind of implementation.
Below you find the required details listed:
The implementation for flashMessages is described here:
https://docs.typo3.org/m/typo3/reference-coreapi/11.5/en-us/ApiOverview/FlashMessages/Index.html
The description of the flashMessage-ViewHelper you find here:
https://docs.typo3.org/other/typo3/view-helper-reference/11.5/en-us/typo3/fluid/latest/FlashMessages.html
The CSS you could probably take from bootstrap but reliable from the extension examples. In the CSS for the backend you could search it too.
Concerning your code:
I think you can leave away this, as it's not used:
$errorController =
GeneralUtility::makeInstance(
ErrorPageController::class
);
or you can use this code:
$errorController =
GeneralUtility::makeInstance(
ErrorPageController::class
);
$content = $errorController->errorAction(
$title,
$message
);

ASP.NET Core 3.1 Razor - Is it possible to turn a String into a Hyperlink using Html.Raw

Is it possible to turn a String into a Hyperlink using Html.Raw. What would the code for this be?
I'm trying to embed an <a> Tag into a Razor Page with the following:
#{
string strText = "<title>Link Test</title><a class=\"nav-link text-dark\" target=\"_new\" asp-
area=\"Test\" asp-controller=\"Test\" asp-action=\"ViewFile\" asp-route-Id=1> View File Test</a>";
}
#Html.Raw(strText)
My page just shows "View File Test" without a link.
When I view the page source in my browser I see the following:
<title>Link Test</title><a class="nav-link text-dark" target="_new" asp-area="Test" asp-controller="Test" asp-action="ViewFile" asp-route-Id=1> View File Test</a>
When I copy the above and paste it to my razor page, all works well.
Just for fun, I have also tried the following and get the same result:
#{
string strText = "<title>Link Test</title><a class=\"nav-link text-dark\" target=\"_new\" asp-
area=\"Test\" asp-controller=\"Test\" asp-action=\"ViewFile\" asp-route-Id=1> View File Test</a>";
}
<text>#strText</text>
The following example below works fine, but not the above. I thought maybe it had to do with the embedded quotes
#{
string strText = "My Text My link.";
}
#Html.Raw(strText)
For HtmlHelper.Raw Method , the parameter is the HTML markup, however asp-area and asp-controller are the Anchor Tag Helper attributes. HTML code, or actually any text, returned from methods is not processed by the Razor engine, so you cannot use HTML tag helpers here.
You could try to use #Html.ActionLink or #Url.Action helper methods as shown:
#{
string strText = "<title>Link Test</title><a class=\"nav-link text-dark\" target=\"_new\" href=\""+Url.Action("ViewFile","Test" ,new { Area="Test",Id=1})+"\" >View File Test</a>";
}
the generated url will be https://localhost:44348/Test/Test/ViewFile?Id=1.
register routes as below:
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "areaRoute",
// if you don't have such an area named as `areaName` already,
// don't make the part of `{area}` optional by `{area:exists}`
pattern: "{area}/{controller=Home}/{action=Index}");
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
Reference:
https://stackoverflow.com/a/35579040/10201850
https://stackoverflow.com/a/53147778/10201850
The main reason your solution with asp tags will not work because they (tag helpers) are compiled at run time into your existing views.
At runtime compilation, your string is getting compiled as a string and tags inside that are being ignored obviously because compiler is unaware of them.
But when you use html attributes like anchor tag, it will work fine because that gets parsed by your browser.
Keep in mind that in Razor, asp- prefixed attributes for tags are somehow rendered at server side. This properties/attributes are not from HTML5.
Answer: Yes, it is possible, but it must be valid HTML.

Not able to embed PDF blob in HTML in IE

I have adopted various approaches to embed PDF blob in html in IE in order to display it.
1) creating a object URL and passing it to the embed or iframe tag. This works fine in Chrome but not in IE.
</head>
<body>
<input type="file" onchange="previewFile()">
<iframe id="test_iframe" style="width:100%;height:500px;"></iframe>
<script>
function previewFile() {
var file = document.querySelector('input[type=file]').files[0];
var downloadUrl = URL.createObjectURL(file);
console.log(downloadUrl);
var element = document.getElementById('test_iframe');
element.setAttribute('src',downloadUrl);
}
</script>
</body>
2) I have also tried wrapping the URL Blob inside a encodeURIcomponent()
Any pointers on how I can approach to solve this?
IE doesn't support iframe with data url as src attribute. You could check it in caniuse. It shows that the support is limited to images and linked resources like CSS or JS in IE. Please also check this documentation:
Data URIs are supported only for the following elements and/or
attributes.
object (images only)
img
input type=image
link
CSS declarations that accept a URL, such as background, backgroundImage, and so on.
Besides, IE doesn't have PDF viewer embeded, so you can't display PDFs directly in IE 11. You can only use msSaveOrOpenBlob to handle blobs in IE, then choose to open or save the PDF file:
if(window.navigator.msSaveOrOpenBlob) {
//IE11
window.navigator.msSaveOrOpenBlob(blobData, fileName);
}
else{
//Other browsers
window.URL.createObjectURL(blobData);
...
}

Apply vue-katex to content loaded from static folder

I'm trying to make a blog using Vue as laid out in the excellent demo here. I'd like to include some mathematical formulas and equations in my blog, so I thought I'd try to use vue-katex. vue-katex formats my mathematical notation perfectly when I put all my KaTeX HTML directly into my Vue templates, but to create a useable blog I need to keep my content separate from my templates (as shown in the demo).
I can't get vue-katex to format HTML content in the static folder. That's what I'd like help with.
Setup
I cloned the github repo for the demo.
I added vue-katex to package.json:
"vue-katex": "^0.1.2",
I added the KaTeX CSS to index.html:
<!-- KaTeX styles -->
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.9.0-alpha2/katex.min.css"
integrity="sha384-exe4Ak6B0EoJI0ogGxjJ8rn+RN3ftPnEQrGwX59KTCl5ybGzvHGKjhPKk/KC3abb"
crossorigin="anonymous"
>
I added the import statement to src/App.vue:
import Vue from 'vue'
import VueKatex from 'vue-katex'
Vue.use(VueKatex)
and I added a simple line of HTML with KaTeX to the BlogPost template:
<p>Here's an equation in the actual Vue template: <div class="equation" v-katex="'X \\sim N(\\mu, \\sigma^2)'"></div></p>
As I said, this works - I see formatted mathematical notation in my blog post (URL http://localhost:8080/read/neque-libero-convallis-eget):
However, I need different equations for every blog post, of course.
So I tried adding KaTeX HTML to the "content" field in the JSON for the first blog post: static/api/post/neque-libero-convallis-eget.json. I changed the "content" line to:
"content": "Here's an equation in the static folder: <div class=\"equation\" v-katex=\"'X \\sim N(\\mu, \\sigma^2)'\"></div>",
This content appears on the page, but the equation doesn't render. I see this: (the text appears but no equation is shown)
When I use Developer Tools to inspect the HTML on the page, I see this:
You can see that vue-katex has been applied to the equation I put in the template directly: it has parsed the HTML I typed into lots of spans with all the mathematical symbols, which are showing perfectly.
However the KaTeX HTML I've added to the "content" in the static folder has simply been placed on the page exactly as I typed it, and is therefore not showing up as an equation on the page. I really need to keep my blog post content in this static folder - I don't want to have to create a different .vue file for each blog post, that defeats the point!
My question is: is there a way to manually "apply" vue-katex to the HTML I place in the static folder, when it loads? Perhaps there is something I can add to the plugins/resource/index.js file, since this contains the function that loads the data from the static folder?
Many thanks in advance for any help.
*Disclaimer: I'm definitely no expert / authority on what I'm about to explain!
One thing to remember is that Vue reads the templates you write, and then replaces them as reactive components. This means that although you often write Vue attributes like v-for, v-html or in this case v-katex these attributes are only useful up until the app or component is mounted.
With this in mind, if you have a Vue app that ajax loads some html, its not going to be able to rerender itself with those Vue bindings in place.
I have somewhat ignored your current set up and set about solving the issue in another way.
Step 1: Reformat your data from the server side
I've put the posts into an array, and each post contains the template (just a string of html) and the equations separately as an array. I've used [e1] in the post as a placeholder for where the katex will go.
var postsFromServer = [{
content : `<div>
<h2>Crazy equation</h2>
<p>Look here!</p>
[e1]
</div>`,
equations : [
{
key : 'e1',
value : "c = \\pm\\sqrt{a^2 + b^2}"
}
]
}];
Step 2: When the post is rendered, do some work on it
Rather than just use v-html="post.content", I've wrapped the html output in a method
<div id="app">
<div v-for="post in posts" v-html="parsePostContent(post)">
</div>
</div>
Step 3: Create a method that renders all the katex, and then replaces the placeholders in the post
methods : {
parsePostContent(post){
// Loop through every equation that we have in our post from the server
for(var e = 0; e < post.equations.length; e++){
// Get the raw katex text
var equation = post.equations[e].value;
// Get the placeholder i.e. e1
var position = post.equations[e].key;
// Replace [e1] in the post content with the rendered katex
post.content = post.content.replace("[" + position + "]", katex.renderToString(equation));
}
// Return
return post.content;
}
}
Here is the whole set up, which renders Katex:
https://codepen.io/EightArmsHQ/pen/qxzEQP?editors=1010

How does the data flow from webserver to webpage.

I am in process of creating a new website. I have done my basic HTML/CSS/JQuery code to generate the webpage. The website is going to display images. Now my questions are around where the images are supposed to be stored and how to retrieve them. I did research but I am all over the place with the architecture.
My understanding is that HTML page will make a query to a web server (like Apache) and get the data/images back and display it? The function of the web server is to provide the data based on the query, is that right? Where is the data like jpeg images, their metadata, link between gallery and images would be stored? Is there another layer of DB somewhere? Would the architecture be HTML<-->Apache<-->DB ?
Or do I just put my images in a database and host the data their. Basically taking out Apache from the architecture? The queries are going to depend only on the current stage in the navigation tree (nothing user specific).
There is no need for DB to use images. It works more this way:
HTML <-> Apache <-> Image
because apache has the ability to deliver files.
Now, there are several differents way of working.
For example, the image can be load dynamically in a php files with images header. In this case, the scheme will be :
HTML <-> Apache <-> PHP <-> Image
To do it, you simply put your images in a folder where apache's user can access.
For example you can have the following structure in /var/www/sitename:
index.html
img / my_image.jpg
And in index.html
<img src="img/my_image.jpg" ... />
Edit to answer you question :
create a php script that will generate the json array, for example :
page.php
<?php
switch($_GET['link']){
case 'link1':
images_links = array(
'path/to/img1',
'path/to/img2',
...
);
break;
case 'link2':
images_links = array(
'path/to/img3',
'path/to/img4',
...
);
break;
}
echo json_encode(images_links);
?>
Let's guess your html is
<a>link1</a>
<a>link2</a>
<img class="imgToChange" src="..."/>
<img class="imgToChange" src="..."/>
...
Then you will add this javascript function to your html
function updateImages(clicked_link){
// get the text of the link
link_text = clicked_link.innerHTML;
// send a request to page.php to get images's urls
$.get( "path/to/page.php?link="+link_text, function( data ) {
// data will be your json array
images_links = data;
// get a table of all images elements that can be changed
var images = document.getElementsByClassName("imgToChange");
// for each image in the json array
for(var k=0; k<images_links.length; k++){
images[k].src = images_links[k];
}
});
}
And you just have to call this function when a link is clicked
<a onclick="updateImages(this)">link1</a>
<a onclick="updateImages(this)">link2</a>
<img class="imgToChange" src="..."/>
<img class="imgToChange" src="..."/>
...