Ah, I understand and agree, keep the current format. I had not come across this before.
Thank you for your understanding of my ignorance.
Bobj
Ah, I understand and agree, keep the current format. I had not come across this before.
Thank you for your understanding of my ignorance.
Bobj
currently I use the object tag for image fallback (only works with external images):
<object data=<<card!!image>> >
<object data=<<card!!altfavicon>> >
{{$:/core/images/globe}}
</object>
</object>
<<card!!image>> is a url.
Interesting, must look this widget up.
This has opened up so many areas of Tiddlywiki I have not come across before.
Bobj
@EricShulman , can this fallback facility be extended to include PDF files? If so how can I do that?
bobj
FYI: <object>
is a html tag and not a widget. Much of html can be used in tiddlywiki. A somewhat underutilised fact.
EDITED BY @jeremyruston 13th August 2025
Please ignore this code. It is a garbled mess that could not possibly work.
We’ve discussed elsewhere that as well as clearly marking LLM generated code, it is incumbent on the poster to verify that the code does perform as expected.
@EricShulman , I asked ChatGPT how we might accomplish a similar fallback facility for PDF files. It came back with
In TiddlyWiki, you can use a combination of JavaScript and `img` or `embed` elements to handle a fallback for loading a PDF. Unfortunately, there is no direct built-in support for this, but you can create a custom solution using the HTML and JavaScript within TiddlyWiki.
Here’s an approach using JavaScript and an embedded `<iframe>` to display the PDF. If the first PDF fails to load, it will fall back to the second PDF:
### TiddlyWiki Code:
```html
<$wikify bind="$pdfUrl">
<div class="pdf-container">
<iframe id="pdfViewer" width="100%" height="600px" src="{{pdfUrl}}"></iframe>
</div>
<script>
(function() {
var pdfUrl = $pdfUrl;
var fallbackUrl = "https://example.com/alternate.pdf"; // Put your fallback PDF URL here
var iframe = document.getElementById("pdfViewer");
function checkPdfLoading() {
var pdfIframe = iframe.contentWindow || iframe;
// Try to catch if the PDF doesn't load after some time
setTimeout(function() {
if (!pdfIframe.location || pdfIframe.location.href === "about:blank") {
iframe.src = fallbackUrl; // Set the fallback URL if the PDF didn't load
}
}, 3000); // 3 seconds to check (you can adjust this)
}
// Initial check when the page loads
iframe.onload = checkPdfLoading;
// Check after setting the source of the iframe
checkPdfLoading();
})();
</script>
</$wikify>
### Explanation:
1. **Initial PDF URL**: The main PDF is loaded using an iframe that links to a PDF URL.
2. **Fallback Logic**: A simple JavaScript function `checkPdfLoading` tries to detect whether the PDF is loaded correctly. If it’s not loaded within a few seconds, the `iframe.src` will be switched to a fallback PDF URL.
3. **Timeout for Checking**: The timeout (`setTimeout`) checks if the iframe content fails to load (i.e., stays blank for a few seconds), triggering the fallback.
### How to Use:
* Replace `{{pdfUrl}}` with the URL or reference to your primary PDF.
* Set your fallback PDF URL in the `fallbackUrl` variable.
* Adjust the timeout value or logic as needed to suit your use case.
This method relies on the fact that the iframe will fail to load a PDF if the source is incorrect or inaccessible. If the PDF fails to load, it switches the source to the fallback URL.
I haven’t tried it yet but thought you’d be interested anyway.
bobj
I suspect this is a halucination as the script tags are sanitised by default.
I’ve edited @Bob_Jansen’s post with the following note:
EDITED BY @jeremyruston 13th August 2025
Please ignore this code. It is a garbled mess that could not possibly work.
We’ve discussed elsewhere that as well as clearly marking LLM generated code, it is incumbent on the poster to verify that the code does perform as expected.
Apologies to this list. I did state it was the result of a ChatGPT query and I was going to give it a go. As @jeremyruston indicated, it didn’t work at all.
Still looking for a solution to pdf file display fallback if anyone can advise
bobj
Give this a try:
\procedure object(src, width:"100%", height:"100%",params,fallback:"cannot load <<src>>")
<$let type={{{ [<src>get[type]] }}}
pre={{{ [[data:]] [<type>] [[;base64,]] +[join[]] }}}
uri={{{ [<src>get[_canonical_uri]] ~[<src>get[text]addprefix<pre>] ~[<src>prefix[http]] }}}>
<% if [<uri>!match[]] %>
<object data={{{ [<uri>addsuffix<params>] }}} type={{{ [<src>get[type]] }}}
style.width=<<width>> style.height=<<height>>>
<<fallback>>
</object>
<%else%>
<<fallback>>
<%endif%>
</$let>
\end
Usage:
<<object src:"test.pdf" height:"50vh">>
Notes:
src
can be any of the following:
_canonical_uri
fieldhttp://
or https://
height
and width
are specified using CSS unitsparams
are optional. Use params:"#toolbar=0&scrollbar=0"
to hide the PDF toolbar and scrollbar controlsfallback
can be any wiki content you want displayed if the embed fails to load
<<embed ...>>
macro to display a fallback PDFHow it works:
type
field (if any)data:application/pdf,base64,
) to use if the tiddler contains embedded base64-encoded binary data._canonical_uri
field value or the tiddler’s base64-encoded content (with the added prefix), or a direct external reference to a URLThis might not be a 100% perfect solution, but it should handle most use-cases.
Let me now how it goes…
enjoy,
-e
Addendum:
If you are only concerned with a “fallback facility for PDF files” (i.e., only using direct external references), then you can skip the entire \procedure
definition and just write something like this:
<object data="test.pdf" style="width:100%;height:50vh;">
<object data="other.pdf" style="width:100%;height:50vh;">
cannot load PDF
</object>
</object>
Note that you can nest <object>
elements as many deep as you need, so you could have multiple levels of fallback content.
-e
Thank you @EricShulman for both of your suggestions. Now I see what @TW_Tones was hinting at in an earlier reply.
Is there any documentation for having the same tiddler nested inside itself and activating when the first one fails? I would like to understand it a bit better but can not find anything.
bobj
@EricShulman wont work for me I’m afraid.
tiddler with canonical_uri
Code of procedure, note some <$text
displays to see values of variables
Output on calling tiddler
As you can see, the type
and uri
variables are not being set.
Can’t figure out why.
BTW what are the ~ characters for in the uri={{{ [<src>get[_canonical_uri]] ~[<src>get[text]addprefix<pre>] ~[<src>prefix[http]] }}}
statement?
First off… good work in using $text
widgets to show the actual parameter values… that is a very useful technique for debugging macro code, and I use it all the time.
Now… as to the specific problem:
I think you’ve made an error in how you are invoking the <<object>>
macro. Since you are using a _canonical_uri
to point to the external PDF file, the src
value you pass to the macro should be the title of the tiddler containing the _canonical_uri
field. From your first snapshot it appears that your source tiddler is named:
A Brief History of Employment of Australian Artillery 1871-2021
but your test output shows that you passed in a src
parameter of:
A_Brief_History_of_Employment_of_Australian_Artillery_1871_2021.
Since a tiddler title matching that src
value does not exist, the macro is unable to retrieve a type
field value or a _canonical_uri
field value, so it does the default fallback handling which displays the “cannot load …” message.
regarding your “BTW” question: the ~
character is a short form of the :else
filter run prefix. Thus, the uri filter basically says:
_canonical_uri
from the src
tiddler._canonical_uri
value, thensrc
value as an external URI… but ONLY if it starts with http
(which covers both http://
and https://
)Note: since you intend to use a relative external URI (i.e., “Media/Ephemera/…”) then you should change that last filter run to just ~[<src>]
(i.e., remove the check for an “http” prefix).
Let me know how it goes…
-e
@EricShulman , still doesn’t work. The get[type]
does not return anything. If I use the filter tab in advanced search, typing [title[A_Brief_History_of_Employment_of_Australian_Artillery_1871_2021]get[type]]
does not return anything even though type is specified as application/pdf
. But if I type [title[testpdf]get[type]]
it returns abc
where abc
was a test value I inserted into its type field during debugging.
If I try that code on any other tiddler, I get the type result as specified, ie, image/jpeg
for images, etc.
Seems like it doesn’t like type of application/pdf
Addendum: There is somethiing fishy going on. I edited the testpdf tiddler trying different tiddler titles as part of debugging. Returning it back to A Brief History of Employment of Australian Artillery 1871-2021, the type variable is not set but the pdf will not load.
bobj
bobj
As I noted in my previous reply, the src
param should not have the underscores since your tiddler title doesn’t have them. Your last test, as shown in your last snapshot using the correct src
param value DOES seem to be getting the type
field value and calculating the pre
value.
However… did you also read my “note” at the end of the last post:
Note: since you intend to use a relative external URI (i.e., “Media/Ephemera/…”) then you should change that last filter run to just
~[<src>]
(i.e., remove the check for an “http” prefix).
Thus, the line of code for calculating the URI value should be:
uri={{{ [<src>get[_canonical_uri]] ~[<src>get[text]addprefix<pre>] ~[<src>] }}}>
-e
@EricShulman that appears to work now, at least for my quick test. Will test further and let you know.
I have also kept the prefix[http]
statement in the uri calculation and added ~[<src>]
so that it hopefully will handle both cases of with and without the http prefix.
I assume that for the fallback, I replace the <<fallback>>
parameter with the fallback URL?
Everytime you provide a work around, I learn a bit more so thank you for your patience.
bobj
Using just ~[<src>]
will handle both cases (with or without the http
prefix), so you don’t need the separate filter run for ~[<src>prefix[http]]
.
If you want the fallback to attempt to embed a different source, then you would set the fallback parameter value to a complete alternative call to <<object>>
. Something like this:
<<object
src:"SomeTiddlerTitle"
height:50vh
fallback:"<<object src:'https://...' height:50vh>>"
>>
Also, keep in mind that if you are only using external PDFs (i.e., no tiddlers with _canonical_uri
or base64-encoded binary content), then you can entirely skip the <<object>>
macro, and just use nested HTML <object>
elements, as previously desribed here: Fallback handling for $image widget - #23 by EricShulman
-e
@EricShulman can you explain why, if I change the procedure call to displayPDF, nothing gets displayed but if I return it to object the pdf appears again?
I thought I’d try and merge this pdf procedure in to the image fallback procedure but I guess I may not be able to do that.
bobj
Exactly what did you change?
The name used in the \procedure somenamehere(...)
definition and the name used in the <<somenamehere ...>>
invocation must be the same (i.e, somenamehere), so you need to make sure you change both of them.
Note also that, within the code I provided, the <object data=...>...</object>
syntax refers to a standard HTML element and should NOT be changed.
-e