Dynamic Javascript using Scala template - playframework-2.1

I am trying to localize my Javascript files. For instance, I would have:
var count = 0;
$('#choices .choice').each(function(i) {
$('input', this).each(function() {
count++
$(this).attr('placeholder', '#Message("placeholder.choice") ' + count)
})
})
This would obviously work if the Javascript file is inside the Scala HTML template but I would prefer to have it in a dedicated file.
To begin with, I am wondering if it is a good idea: what about caching file if it's content may change? In this case, there is a single parameter: having it in the URL would solve this problem? Eg: /assets/javascripts/:lang/my-file.js.
And the real question is: is it possible to do that using Play! framework? It does not seem that Javascript templates are supported (or I missed something). Is there a way to do it correctly?

Actually you don't need to translate your JavaScripts dynamically, it's reduntant waste of resources, instead prepare static JS files like messages.en.js, messages.de.js etc and include required file basing on the user's language directly into the view.
Here you have some description how to make it easy (JavaScript approach)

There is a module allowing javascript internationalization using the same mechanism as in Play templates, have a look at :
https://github.com/julienrf/play-jsmessages
This will definitely fits your needs. I use it for a while know with success. You can expose your translations through a javascript file and then use browser caching with a proper fingerprinting configuration.

Related

How best to handle static text in frontend frameworks such as Vue.js

I'm working on a Web Application which uses Vue.js as the frontend framework. Currently we are handling static text directly where it is used i.e. inputting it directly at source in components data.
<script>
export default {
name: "ExampleComponent",
data: function () {
return {
title: 'Business Title',
modalBodyText: 'Some business text that devs don't care about'
}
}
}
</script>
However the Web App requires a lot of input from the business team on how things are phrased and how text is worded. Due to compliance some of the text in the application changes frequently and I am wondering whether there is a better way of handling static text in frontend frameworks such as Vue.js?
I feel we should be abstracting out the static text from the code and importing a file globally but I'm unsure if this is common practice or how best to do it. Any input on this would be much appreciated.
Easiest thing you can do is to create some json file (or multiple files ...depending how big and structured your app is) with all the texts and simple import it into your components
import content from './content.json'
Webpack will make content of such file available as JS object so you can easily reference keys in your code (not directly from template tho)
Slightly more sophisticated way would by to use of I18n libraries like vue-i18n - still keeping your text in separate json files with some utilities on top for accessing it directly from templates - but with an option of changing text storage mechanisms later and using many open source tools available for managing and changing the content by non-developer users...

Data sharing mechanism

I need to develop a web application, where our data/html need to be displayed on third party sites using iframe or javascript. Example: cricket widget sharing.
Can someone tell me what type development is it called ?
There would be multiple kind of widget, some of them will also need to be upgrded short periodically (per x second).
Also, should i use iframe or use javascript implemenration merhod to generate the output on clients server.
Can someone provide me a reference or idea ?
Considering I have understood your question rightly, which means you currently need to develop a widget(not a web app) for websites. A widget is something that can be used by others on their websites.
Adding to the above understanding with the example you gave-
Say you develop a Cricket widget, 100's of other websites can put this widget on their site using a small piece of API or code. And, this widget refreshes every 'x' seconds to display Live Score. Hope this is what you need.
Here is the solution/way to solve this:
What you have to do is write an embedder or loader script keeping the following points in mind-
Make it asynchronous, so that the client website doesn't slow down
Keep it short. Abstract your code. Don't give the user 100's of lines.
Preferably don't use a framework. Chances are it can conflict with your client's website/frameworks. Don't even use jQuery!(Because it can conflict with user's jquery version and cause lot of problems to the widget and website) Write pure Javascript code :)
Don't ever use GLOBAL variables. Use var or let and follow best practices. Using global variables may conflict with user's variables and the whole website/client can get messed up.
A sample code -
<script data-version='v1' data-widget-id='your-clients-id' id='unique-embedder-id' type='text/javascript'>
// "data-version": It's useful to put the version of your embedder script in the "version" data attribute.
// This will enable you to more easily debug if any issues arise.
// "data-widget-id": This ID allows us to pull up the correct widget settings from our database.
// It's a "client id" of sorts.
// "id": This HTML id allows us to refer to this embedder script's location. This is helpful if you want to inject html
// code in specific places in hour hosts's website. We use it to insert our payload script into the <head> tag.
//We wrap our code in an anonymous function to prevent any ofour variables from leaking out into the host's site.
(function() {
function async_load(){
//BELOW: we begin to construct the payload script that we will shortly inject into our client's DOM.
var s = document.createElement('script');
s.type = 'text/javascript';
s.async = true;
// Below is the URL you want them to get your payload script from!
var theUrl = 'http://www.your-website.com/assets/your-payload-script.js';
// At the end we tack on the referrer's URL so we know which website is asking for our payload script.
s.src = theUrl + ( theUrl.indexOf("?") >= 0 ? "&" : "?") + 'ref=' + encodeURIComponent(window.location.href);
// This finds the location of our embedder script by finding the element by it's Id.
// See why it was useful to give it a unique id?
var embedder = document.getElementById('unique-embedder-id');
// This inserts our payload script into the DOM of the client's website, just before our embedder script.
embedder.parentNode.insertBefore(s, embedder);
}
// We want the our embedder to do its thing (run async_load and inject our payload script)
// only after our client's website is fully loaded (see above).
// Hence, we wait for onload event trigger. This no longer blocks the client's website from loading!
// We attachEvent (or addEventListener to be cross-browser friendly) because we don't want to replace our
// client's current onLoad function with ours (they might be doing a bunch of things on onLoad as well!)
if (window.attachEvent)
window.attachEvent('onload', async_load);
else
window.addEventListener('load', async_load, false);
})();
</script>
Read the comments. They are very helpful :)
Your users will have to just use a nicely abstracted script tag-
<script type="text/javascript" src="http://example.com/widget.js"></script>
Or maybe even an iFrame(old is gold days) render HTML in iFrame(Best way if you don't want to 'openly' expose(as most won't know) your Abstracted Javascript as well)
<iframe src="http://example.com/mywidget.html"></iframe>
Here are the references that I referred and also have sample widgets which can be reused-
Developing an Embeddable Javascript Widget / Snippet for Client Sites
Creating an Embeddable JavaScript Widget
Creating Asynchronous, Embeddable JavaScript Widgets
Building an embeddable Javascript widget (third-party javascript)
One last time, please don't use global variables and write asynchronous code. These 2 are the main things that you have to take care to make a great/successful widget with top-notch performance.
Happy Coding! Hope it helps :)

Load *.vtl file from remote location

is it possible in dotCMS to parse a vtl file from a remote source?
// this doesn't seem to work
#dotParse("https://some.random.source.com/vtl/index.vtl")
Not normally and it would be very easy to write a plugin to do it. Without writing any java code, it should be possible to do something like this:
#set($code = $import.read("https://some.random.source.com/vtl/index.vtl"))
$render.eval($context, $code)
The downside is that it will probably be much slower than just rendering a vtl in dotcms.

Fine Uploader - using both Direct S3 and Traditional in same project

I have an existing FineUploader implementation for small files using the Traditional (upload-to-server) version which is working great. However, I'd like to also allow Direct S3 uploads from a different part of the application which deals with large attachments, without rewriting the existing code for small files.
Is there some way to allow both Direct S3 and Traditional uploads to work alongside each other? This is a single-page application, so I can't just load one or the other fine-uploader versions depending on which page I'm on.
I tried just including both fine-uploader JS files, but it seemed to break my existing code.
Client-side code:
$uploadContainer = this.$('.uploader')
$uploadButton = this.$('.upload-button')
$uploadContainer.fineUploader(
request:
endpoint: #uploadUrl
inputName: #inputName
params:
authenticity_token: $('meta[name="csrf-token"]').attr('content')
button: $uploadButton
).on 'complete', (event, id, fileName, response) =>
#get('controller').receiveUpload(response)
Good find, #Melinda.
Fine Uploader lives within a custom-named namespace so that it does not conflict with other potential global variables, this is the qq namespace (historically named). What is happening is that each custom build is redeclaring this namespace along with all member objects when you include it in the <script> tags on your page.
I've opened up an issue on our bug tracker that explains the issue in more technical details, and we're looking to prioritize a fix to the customize page so that in the future no one will have this issue.

Opera extensions (widgets): dynamic config file

I have an Opera 11 extension, which has a background process and an injected script. These communicate very frequently with a remote server (not the webpage the user's viewing), using the background script's cross-site XMLHttpRequest capabilities.
I would like the URL of the server to be a preference, so that it can be modified by the user without editing the package. The config.xml file would good, for it accepts <preference name="serverUri" value="..." />. However, I would like the script to be able to update itself directly from the server (not through Opera's site), which can be achieved using <update-description href="http://myserver.com/client/update" />.
So what I would like to do is have the href attribute of the update-description element to be dependent on the value of the preference serverUri. I would imagine some syntax like this:
<update-description href="{$serverUri}" />
But I could not find any references to this kind of functionality. Is there some way to solve this?
It's not possible to use variables in the config.xml file as you've written and I don't think there are plans to add this.
I'm sure you know that preferences can be set not just with the preference element in config.xml but also using widget.setPreferenceForKey(value, key), but I don't think that solves your problem in this case.
The only workaround I can think of is if you have all your logic in an external script on your server and in your extension's local files (background script or injected script), just have a very simple couple of lines that reference your external script. Something like:
var script = document.createElement('script');
script.src = 'http://www.example.com/script.js';
document.body.appendChild(script);
You could then make the script's URL editable by the user and store it in widget.preferences.
EDIT by hallvors: This solution has serious drawbacks, see my comment below.
As far as I know this is not currently possible. It seems like a bit of an unusual use case, which could potentially be risky to implement, so it would be interesting to hear more about why you want to do this.