Dojo custom language variants - dojo

Does Dojo support creation of custom language variants to be used for with Dojo's locale and i18n
Does anyone know if I am able to create a custom language variant for Dojo's locale that works with i18n?.
Example
define({
root: {
greeting: "Hello, world!"
}
"de-myVariant" : true
});

Yes, it can be done. If you have nls/SampleApp.js as:
define({
root: {
greeting: "Hello!"
}
"de" : true,
"de-at": true,
"de-x-mundl": true
});
then there would be three sub-directories under nls:
nls/de
nls/de-at
nls/de-x-mundl
for nls/de/SampleApp.js:
define(({
greeting: "Hallo!"
}));
for nls/de-at/SampleApp.js:
define(({
greeting: "Gruß Gott!"
}));
and for nls/de-x-mundl/SampleApp.js:
define(({
greeting: "Servus, Mundi!"
}));
Then if you config Dojo to get the locale as a URL parameter:
<script src="./dojo/1.8.3/dojo/dojo.js"
data-dojo-config="locale: location.search.substring(1).toLowerCase()">
</script>
you can switch the language easily by passing the locale tag as that parameter:
.../app.html?de-DE
.../app.html?de-at
.../app.html?de-x-Mundl
Note that Dojo considers locale tags as case-sensitive and that's why the input is toLowerCase()ed and internally all the tags are kept in lower-case.

Related

Helmet blocking bootstrap

At first, bootstrap didn't load, so I put this:
app.use(helmet());
app.use(
helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "https://cdn.jsdelivr.net"],
objectSrc: ["'none'"],
styleSrc: ["'self'", "https://cdn.jsdelivr.net"],
fontSrc: ["https://fonts.gstatic.com"],
upgradeInsecureRequests: [],
},
})
);
Then this bug comes in: "Refused to load the font 'data:font/truetype;charset=utf-8;base64,AAEAAAAQAQAABAAARkZUTX2Nv5YAAjnoAAAAHEdERUYENABTAAHJmAAAACRHUE9T4BjvnAACObAAAAA2R1NVQgmn+v0AAcm8AABv9E9TLzIKcyJjAAABiAAAAGBjbWFwv7oVNQAACfQAAAYWY3Z0IAARAUQAABAMAAAABGdhc3D//wADAAHJkAAAAAhnbHlmCJ88vQAAGBgAAYfUaGVhZAkc3WMAAAEMAAAANmhoZWEEAQIFAAABRAAAACRobXR4diRu0wAAAegAAAgMbG9jYdlVdhQAABAQAAAIBm1heHAEXADhAAABaAAAACBuYW1ludepWgABn+wAAAKdcG9zdBJ+3qAAAaKMAAAnBAABAAAAAQPX5ykXUl8PPPUAHwIAAAAAANP0zEUAAAAA0/TMSAAA//4CAAIEAAAACAACAAAAAAAAAAEAAAIAAAAAAAIAAAAAAAIAAAEAAAAAAAAAAAA...4AIAAgABIAIQIoAAgADwANACAAIgAbABsAJgL2AAgAFQAOACEAIAAVABwAIQIlAAcADwANAA4AIgAhABwA2gAHABIAEgAYABIAGwARAQIABwAWABEAFAASACEAIAAqAAcADgAfABsAFgAbABQBkwAFAA4AIQAQABUDqwAEABwAHwAYAtEABAAWABMAFgBdAAMAEgAPAtAAAgAQAAEABAOsABQAHAAiACEAIgAPABIADQAgABIADgAfABAAFQASABEADQATABwAHwADAAgAIgA0AnMADAAcABwAGgANABwAIgAhAA0AGgAOAB0DsgAIABwAHAAaAA0AHAAiACEDsQAHABwAHAAaAA0AFgAbAAIABAAGAAcAAAAOABYAAgAYACQACwAmACcAGAABAAAACgAeADQAAWxhdG4ACAAEAAAAAP//AAEAAAABc2l6ZQAIAAQAAACgAAAAAAAAAAAAAAAAAAAAAQAAAADVpCcIAAAAANP0zEUAAAAA0/TMSA=='"
How can I fix that?
You have to use contentSecurityPolicy. For example if you have used these CDN links for loading bootstrap:
doctype html
html
head
title D&C
link(href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.0-beta1/dist/css/bootstrap.min.css", rel="stylesheet", integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1", crossorigin="anonymous")
style
include ./styles.css
body
include nav
block content
block footer
footer
//- p © #{new Date().getFullYear()}
script(src="https://cdn.jsdelivr.net/npm/bootstrap#5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4", crossorigin="anonymous")
script(src="https://cdn.jsdelivr.net/npm/#popperjs/core#2.11.6/dist/umd/popper.min.js" integrity="sha384-oBqDVmMz9ATKxIep9tiCxS/Z9fNfEXiDAYTujMAeBAsjFuCZSmKbSSUnQlmh/jp3", crossorigin="anonymous")
Solution 1: set contentSecurityPolicy to false
// This disables the `contentSecurityPolicy` middleware but keeps the rest.
app.use(
helmet({
contentSecurityPolicy: false,
})
);
Solution 2: Configure contentSecurityPolicy
// app.use(helmet());
app.use(
helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "cdn.jsdelivr.net"],
styleSrc: ["'self'", "cdn.jsdelivr.net"],
},
})
);
Try adding a trailing slash, like this:
"https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/"
instead of
​"https://cdn.jsdelivr.net"
This is because "https://cdn.jsdelivr.net" doesn’t let you do things like "https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/css/bootstrap.min.css", but adding the trailing "/" does. This is a Content Security Policy thing, not a Helmet thing.
Answered by the author of Helmet here

understanding dojo AMD loading- functions are undefined

I have been trying to get someone to explain to me how the dojo AMD loading works and to get a simple piece of code to work. I understand that if using for example the CDN, one has to call the dojo library and load all modules you wish to use. I have tried to implement other javascript functions based on activity from the main page and I will always get the function either undefined or an error related to a dojo control undefined. It seems that all the modules that initially load are not available to the rest of the code. Any helpful explanations would be really appreciated.
<link rel="stylesheet" type=
"text/css" href="http://ajax.googleapis.com/ajax/libs/dojo/1.8.4/dojo/resources
/dojo.css" />
<link rel="stylesheet" type=
"text/css" href="http://ajax.googleapis.com/ajax/libs/dojo/1.8.4/dijit/themes/
tundra/tundra.css" />
<link rel="stylesheet" type=
"text/css" href="http://ajax.googleapis.com/ajax/libs/dojo/1.8.4/dojox/mobile/themes/
iphone/iphone.css" />
<title> DOJO </title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/dojo/1.8.4/
dojo/dojo.js"
data-dojo-config="async:true"></script>
<script type="text/javascript" src="Scripts/login.js"></script>
<script type="text/javascript">
require(["dojox/mobile/parser",
"dojo/parser",
"dojo/on",
"dojo/request/xhr",
"dijit/form/Form",
"dojo/store/Observable",
"dojo/store/Memory",
"dijit/Toolbar",
"dijit/Dialog",
"dojo/io/script",
"dojo/query",
"dojo/_base/lang",
"dijit/layout/ContentPane",
"dojox/mobile/Button",
"dojox/mobile/deviceTheme",
"dojox/mobile/compat",
"dojox/mobile/Heading",
"dojox/mobile/TextBox",
"dojox/mobile/Opener",
"dijit/form/TextBox",
"dijit/form/HorizontalSlider",
"dijit/form/ValidationTextBox",
"dijit/Calendar",
"dojox/mobile/ScrollableView",
"dojo/dom",
"dojo/domReady!",
"dojox/mobile"],
function (dom, domReady ,mobile, ScrollableView,
parser, query, domClass, domStyle, on, event, xhr,Form,
lang, Button, deviceTheme, compat, Heading) {
dojox.mobile.parser.parse();
});
</script>
From my understanding is that the way I have the code above is that my interface will load correctly and all widgets in the body of html will be displayed and it works fine. The problem is that I have a form that gets input from the user and on a button click event calls a function that handles the webrequests. I could not get this to work and it is merely a problem with where I am placing this function. I have added a simplified version:
What I have done is add that function to a script file to separate it from the rest of the code:
var dojoXhr;
function correctInput(div, td, msg) {
dojo.domStyle.set(div, 'display', '');
td.innerHTML = msg;
}
require(["dojo/_base/declare", "dojo/parser", "dojo/query", "dojo/dom-class",
"dojo/dom-style", "dojo/on",
"dojo/_base/event",
"dojo/request/xhr", "dijit/form/ValidationTextBox", "dojo/domReady!"],
function chklogin(declare, parser, query, dom-class, dom-style,
on, event, xhr,ValidationTextBox, domReady) {
var lname = dijit.byId('login').get('value');
var psswd = dijit.byId('password').get('value');
var feedback = document.getElementById('feedback');
var feedbackTD = dojo.query('td.feedback')[0];
if (lname == '' || psswd == '') {
correctInput(feedback, feedbackTD, 'Please enter a valid login!');
dojo.domStyle.set(feedback, 'display', '');
dojo.domStyle.set(document.getElementById('msgBodyOutter'), 'display', 'none');
feedbackTD.innerHTML = "Please enter a valid login!";
return;
}
if (!(lname == 'login') || !(psswd == 'password')) {
correctInput(feedback, feedbackTD, 'Please enter a valid login!');
return;
}
else {
dojo.domStyle.set(feedback, 'display', '');
dojo.domStyle.set(document.getElementById('msgBodyOutter'), 'display', 'none');
feedbackTD.innerHTML = "THATS IT BRO!";
return;
}
});
I got advice on the dojo forum to put my function in a define function and then use a require to call it all. I could not figure out how to do this.
It seems that all the modules that initially load are not available to
the rest of the code.
You are using a CDN to load the dojo toolkit. When you use CDN you are required to define the location of the module packages. You need to edit the dojoConfig for the code to work.
See this article about Using Custom Modules with a CDN. The important part is the packages object.
<script data-dojo-config="async: 1, dojoBlankHtmlUrl: '/blank.html',
packages: [ {
name: 'custom',
location: location.pathname.replace(/\/[^/]+$/, '') + '/js/custom'
} ]"
src="//ajax.googleapis.com/ajax/libs/dojo/1.9.1/dojo/dojo.js">
</script>
Edit: Below is a simple dojo application.
So in my case create a module called chklogin, then require it, and
when the user clicks the button it will call that module chklogin from
within the main require[] function. Correct?
I would say yes. You are correct. I think your concept is a viable option. I hope this example helps with implementing define() to create your own modules. I will try to help where I can as you develop your idea. You can download the project here while available.
Directory Structure:
/index.html
/js/config.js
/js/controller/Controller.js
/js/modules/MyFirstModule.js
/index.html
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Demo</title>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/dojo/1.9.1/dijit/themes/claro/claro.css">
<script src="js/config.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.9.1/dojo/dojo.js"></script>
<script>
require(["app/Controller", "dojo/domReady!"], function(Controller) {
//Initiate the entire application by calling main method of our Controller class.
Controller.main();
//Call our getter method of the Controller class to show how to access a private variable.
console.log(Controller.getWelcomeMessage());
});
</script>
</head>
<body class="claro" id="appBody"></body>
</html>
/js/config.js
We use packages to reference the CDN dojo files. Now we can call dojo classes by our package name
For example, "dojo/domReady!", "dijit/form/Button", "dojox/app/main". The dojo files
are stored on the google servers, which is referenced by the
<script src='http://ajax.googleapis.com/ajax/libs/dojo/1.9.1/dojo/dojo.js'>< /script>
in the index.html file.
Here we create our own custom packages. This could be for your modules, widgets, etc. The package
locations will map to the javascript directory that you store your custom dojo files in.
For example, myModules can be found in the /js/modules directory. You will reference any custom
dojo files via "myModules/MyModule", which locates and loads "/myModules/MyModule.js" file.
For an explanation of the baseURL, see: http://dojotoolkit.org/documentation/tutorials/1.9/hello_dojo/
"Defining and Requiring Modules". This code registers the correct location of our own packages so
we can load Dojo from the CDN whilst still being able to load local modules.
I created a package called "app" as you can see below. This is how I initialize my app in my project.
This was designed to allow me to keep the separation of code the best I know how. It is loaded and
called in the index.html page. So i give it a package name of app. It is physically located in the
js/controller/Controller.js file.
This dojoConfig object is used in the index.html and must be loaded prior to < script src='...dojo.js' > tag.
var dojoConfig = {
async: true,
tlmSiblingOfDojo: false,
baseUrl: location.pathname.replace(/\/[^/]*$/, ''),
packages: [
{ name: "myModules", location: "js/modules" },
{ name: "app", location: "js/controller", main: "Controller" }
]
};
if you choose to host the dojo files on your own server, you can reference them like below. Assuming the dojo js files are located in the "/js/dojo/*" directory.
packages: [
{ name: "dojo", location: "dojo/dojo" },
{ name: "dijit", location: "dojo/dijit" },
{ name: "dojox", location: "dojo/dojox" },
{ name: "myModules", location: "js/modules" },
{ name: "app", location: "js/controller", main: "Controller" }
]
/js/controller/Controller.js
Here is the controller which I use to initialize the web app.
define(["myModules/MyFirstModule"], function(MyFirstModule) {
//Private Variables...
var privateVariable1 = "Welcome to my Dojo Application!";
var privateVariable2;
/**
* init. This is a private function that is only available within this object.
*/
init = function() {
// proceed directly with startup
console.log("Startup functions are firing...");
//Render our "form" which only contains a single text box.
renderForm();
},
renderForm = function() {
MyFirstModule.createForm("appBody");
}
/**
* Enclose all public methods in the return object
*/
return {
/**
* main. This is a public function that can be called from other code.
*/
main: function() {
//Run init() method.
init();
},
/**
* getWelcomeMessage. This public function returns the value of the privateVariable1.
* This mimics a getter method.
*/
getWelcomeMessage: function() {
return privateVariable1;
}
};
}); //end define
/js/modules/MyFirstModule.js
This is an example of a custom Module. It is required by the Controller class as a dependency.
define([
//The required dependencies for this module.
"dojo/dom", "dojo/on", "dijit/form/TextBox", "dijit/form/Button"
], function(dom, on, TextBox, Button){
// Once all modules in the dependency list have loaded, this
// function is called to define the myModules/myFirstModule module.
//
// The dojo/dom module is passed as the first argument to this
// function; additional modules in the dependency list would be
// passed in as subsequent arguments (on, TextBox, and Button).
// Private variables
var firstNameTextBox;
var submitButton;
privateFunction = function() {
console.log("I am a private function. I can only be called from this class.");
};
// This returned object becomes the defined value of this module when called elsewhere.
return {
/**
* createForm. This method creates a simple form. Textbox and button.
* #param placeMeHere This is where to place the form elements. In this demo, the are placed in the
* body of the html document. This is executed in the Controller class.
*/
createForm: function(placeMeHere) {
//Create new TextBox.
firstNameTextBox = new TextBox({
name: "firstname",
value: "" /* no or empty value! */,
placeHolder: "type in your name"
}, "firstname");
//Place me in the DOM.
firstNameTextBox.placeAt(placeMeHere);
//Render
firstNameTextBox.startup();
//Create Button
submitButton = new Button({
label: "Say Hi"
}, "submitButton");
submitButton.placeAt(placeMeHere);
submitButton.startup();
//Greet the user.
on(submitButton, "click", function(evt){
console.log("Hi there, " + firstNameTextBox.get("value"));
});
}
};
});

Dojo amd loading cross-domain modules at runtime

I want to load Dojo1.9 amd modules from an ad-hoc server on the www, but I won't know from where until runtime (with url params).
In essence, I want to do the equivalent of this:
require(['http://www.foo.com/SomeRandomModule'], function( SomeRandomModule ) {
// use SomeRandomModule
});
Quick and dirty way
Might have some unexpected quirks when it comes to the module system and relative paths, I haven't used it enough to say:
require([ "//host/myext/mod1/mod2.js" ],function(mod2){
// If current webpage is http:// or https:// or file://
// it tries to use the same protocol
});
Better way
Configure require() to treat all modules that start with a certain package name (e.g. foo) as coming from a particular URL. From your starter page, something like:
<script src="dojo/dojo.js"
data-dojo-config="packages:[{name:'myext',location:'//host/js/myext'}], async: 1, >
</script>
This lets you vastly improve your first example to:
require([ "myext/mod1/mod2" ],function(mod2){
});
If you are using a Dojo Bootstrap installation instead, you can avoid touching your data-dojo-config and instead put it inside the run.js startup file:
require({
baseUrl: '',
packages: [
'dojo',
'dijit',
'dojox',
'myapp',
{ name: 'myext', location: '//host/js/myext', map: {} }
]
}, [ 'myapp' ]);

How to retrieve a label in a Dojo for a extra locale

How do I use take advantage of the Dojo's extraLocale functionality to labels in the secondary Language for the odd scenarios where you want to display multiple languages on the same page?
Suppose I have defined an extra locale in Dojo as the following
var dojoConfig = {
locale : "en",
extraLocale: [ "zh-cn", "ja-jp" ]
};
If I then define a class in the following way if I try to use i18n I always get a Object that already contains all the English labels for the MyClass_nls. How do I specify one of the extra locales such as "zh-cn" so that it looks up a Chinese version of the MyClass_nls?
define(
[ "dojo/_base/declare", "dojo/_base/lang",
"dijit/_TemplatedMixin",
"dijit/_WidgetsInTemplateMixin",
"dojo/text!./templates/MyClass.html",
"dojo/i18n!./nls/MyClass_nls" ],
function(declare, lang, _TemplatedMixin,
_WidgetsInTemplateMixin, template, i18n) {
return declare(
"group.test.MyClass",
[ _TemplatedMixin, _WidgetsInTemplateMixin,
Evented ],
{
Something like this will work but I believe this does not need the extraLocale functionality in the dojoConfig
var bundle = i18nResolver.getLocalization("group/mypath", "MyClass_nls", "zh-cn");
You can load explicitly locale bundles by including the locale in the module ID. So, dojo/i18n!./nls/MyClass_nls would become dojo/i18n!./nls/zh-cn/MyClass_nls to explicitly load the zh-cn locale. You don’t need to use extraLocale, which is a legacy mechanism for preloading locales in Dojo 1.6 and earlier.

api2.0p5 No BuildHeader or BuildContent for cardbard.card

All,
In messing with the new cards found in 2.0p5, I noticed there is no longer a template available to alter the header or the content of the actual card.
Can someone confirm this is not available, just want to make sure I am not missing it anywhere...
There really is no way to alter the display of the card?
Just for clarity of the post, in 2.0p2 you could do a buildContent function or buildHeader function inside Ext.define of the Card.
The card no longer has a template that you can modify directly, however you can create a custom CardContent plugin to display custom html:
Ext.define('Rally.ui.cardboard.plugin.MyCardContent', {
alias: 'plugin.rallymycardcontent',
extend: 'Rally.ui.cardboard.plugin.CardContent',
getHtml: function() {
var html = this.callParent(arguments);
return html + '<span>mycontent</span>';
}
});
Then configure your CardBoard to use the custom plugin:
Ext.create('Rally.ui.cardboard.CardBoard', {
types: ['User Story', 'Defect'],
attribute: "ScheduleState",
fieldNames: ['Tasks'], // display task information inline on card
cardConfig: {
// overriding plugins to add the custom plugin
// be sure to include the default plugins.
plugins: [
{ptype: 'rallycardheader'},
{ptype: 'rallymycardcontent'},
{ptype: 'rallycardpopover'}
]
}
});