require.js + cldrjs Why renaming a config paths entry break it? - requirejs

Summary
The rename below (s/cldr/cldrjs) breaks load functionality.
require.config({
paths: {
- cldr: "./bower_components/cldrjs/dist/cldr"
+ cldrjs: "./bower_components/cldrjs/dist/cldr"
}
});
require([
- "cldr",
- "cldr/supplemental"
+ "cldrjs",
+ "cldrjs/supplemental"
], function( Cldr ) {
console.log( "Cldr instance", new Cldr( "en" ) );
}, function() {
Setup
Install libraries.
bower install cldrjs requirejs
You should get:
cldrjs /tmp/cldrjs
├── cldrjs#0.3.2 extraneous
└── requirejs#2.1.11 extraneous
Usage
Open index.html (available at https://gist.github.com/rxaviers/10194312). Require.js should load Cldr, and your console should log an instance of it, eg:
Cldr instance Object { attributes={...}, locale="en", supplemental=function(), more...}
Question
Why does the rename break it?
To make it easier for you, I've placed both main files (available at https://gist.github.com/rxaviers/10194312). Simply change the reference to test it.
--- a/index.html
+++ b/index.html
## -4,7 +4,7 ##
<meta http-equiv="X-UA-Compatible" content="IE=edge">
</head>
<body>
- <script data-main="main.cldr.js" src="bower_components/requirejs/require.js"></script>
+ <script data-main="main.cldrjs.js" src="bower_components/requirejs/require.js"></script>
</body>
</html>
Apendix
Piece of info worth knowing...
Header of cldr.js: (available at https://gist.github.com/rxaviers/10194312)
define(function() {
// implementation... Yeap, no dependencies.
})
Header of cldr/supplemental.js: (available at https://gist.github.com/rxaviers/10194312)
define(["../cldr"], function() {
// implementation... Dependency is the above cldr.js file.
})

https://github.com/jrburke/requirejs/issues/1084#issuecomment-40112805
I have chatted with #jrburke on IRC and he pointed out that
`../cldr’ is resolved relative to ‘supplemental’ as an ID first, which ends up with a ‘cldr’ in the ID, then that is converted to a path
but since that path already was used for a module called ‘cldrjs’ that is a problem, does not find a ‘cldr’ module in it
more in a bit after i set up the project
but i think the end result is that you will want to use either a map or packages config
Solution:
the general rule of thumb is: if the package only contains one JS module then paths config is good enough. If it contains multiple modules (as in this case) package config is usually a better fit
unless the package manager knows about front end modules
Thanks #jrburke

Related

Unable to find Blockly Generator function in Angular application

I am trying to build a Blockly Application using Angular. I installed Blockly using npm . I also added the following scripts in angular.json
"scripts": [
"node_modules/blockly/blockly_compressed.js",
"node_modules/blockly/blocks_compressed.js",
"node_modules/blockly/python_compressed.js",
"node_modules/blockly/msg/en.js"
]
Though i can use import * as Blockly from 'blockly' to import blockly in the application and use other functions, I am not able to find Generator functions like Blockly.Python['text_indexOf']
I am using blockly: ^3.20200625.2 and #angular/cli: ~9.1.0 versions.
Am i missing something. Can anyone help me with this issue?
I've had the same problem with electron+angular app building, the next solution had helped me.
Blockly's reference says that Python's generator class should be included with file python_compressed.js right after blockly_compressed.js. So I need to include these files.
First I've used copy-webpack-plugin to copy needed files from Blockly's install directory node_modules/blockly to assets/js:
var CopyPlugin = require('copy-webpack-plugin');
module.exports = {
...
plugins: [
...
new CopyPlugin([
{
from: 'node_modules/blockly/blockly_compressed.js',
to: 'assets/js/[name].[ext]'
},
{
from: 'node_modules/blockly/blocks_compressed.js',
to: 'assets/js/[name].[ext]'
},
{
from: 'node_modules/blockly/python_compressed.js',
to: 'assets/js/[name].[ext]'
},
{
from: 'node_modules/blockly/msg/en.js',
to: 'assets/js/msg/[name].[ext]'
},
]),
...
]
...
}
After I've added scripts calling from js/assets directly from index.html's bottom:
<!DOCTYPE html>
<html>
<head>...</head>
<body><app-root>...</app-root></body>
<script src="assets/js/blockly_compressed.js"></script>
<script src="assets/js/blocks_compressed.js"></script>
<script src="assets/js/python_compressed.js"></script>
<script src="assets/js/msg/en.js"></script>
</html>
After webpack build check python's generator in console:
> typeof Blockly.Python
< "object"

handlebars - add content to head of view from partial

I am using express-handlebars in my project and have the following problem:
Question
I want to be able to add <script> oder such tags to my overall views head from a partial that is called inside the view.
Example:
The view
{{#layout/master}}
{{#*inline "head-block"}}
<script src="some/source/of/script">
{{/inline}}
...
{{>myPartial}}
{{/layout/master}}
The view is extending another partial (layouts/master) that I use as a layout. It adds its content to that ones head block through the inline partial notation, which works fine
the Partial "myPartial
<script src="another/script/src/bla"></script>
<h1> HELLO </h1>
Now I would like that particular script tag in there to be added to my views head-block. I tried going via #root notation but can only reference context there. Not change anything.
I know I could use jquery or similar to just add the content by referencing the documents head and such. But I wanted to know if this is possible at all via Handlebars.
I do doubt it is in any way. But if you have any ideas or suggestions, please do send them my way! Many thanks!!!
UPDATE
This wont work if you have more than one thing injected into your layout / view. Since this happens when the browser loads the page, it creates some kind of raceconditions where the helpers has to collect the things that have to be injected into the parent file. If its not quick enough, the DOMTree will be built before the helper resolves. So all in all, this solution is NOT what I hoped for. I will research more and try to find a better one...
Here is how I did it. Thanks to Marcel Wasilewski who commented on the post and pointed me to the right thing!
I used the handlebars-extend-block helper. I did not install the package, as it is not compatible with express-handlebars directly (Disclaimer: There is one package that says it is, but it only threw errors for me)
So I just used his helpers that he defines, copied them from the github (I am of course linking to his repo and crediting him!) like so:
var helpers = function() {
// ALL CREDIT FOR THIS CODE GOES TO:
// https://www.npmjs.com/package/handlebars-extend-block
// https://github.com/defunctzombie/handlebars-extend-block
var blocks = Object.create(null);
return {
extend: function (name,context) {
var block = blocks[name];
if (!block) {
block = blocks[name] = [];
}
block.push(context.fn(this));
},
block: function (name) {
var val = (blocks[name] || []).join('\n');
// clear the block
blocks[name] = [];
return val;
}
}
};
module.exports.helpers = helpers;
I then required them into my express handlebars instance like so:
let hbsInstance = exphbs.create({
extname: 'hbs',
helpers: require('../folder/toHelpers/helpersFile').helpers() ,
partialsDir: partialDirs
});
Went into my central layout/master file that`is extended by my view Partial and added this to its <head> section
{{{block 'layout-partial-hook'}}}
(The triple braces are required because the content is HTML. Else handlebars wont recognize that)
Then in the partial itself I added things like so:
{{#extend "layout-partial-hook"}}
<link rel="stylesheet" href="/css/index.css"/>
{{/extend}}
And that did the trick! Thanks!!!

Anki and AnkiDroid: Importing JSON from collection.media with javascript

I want to import files from collection.media that are not sound, image, or video. For example I'd like to import a JSON file.
I put the file _script.jquery-3.3.1.min.js and _data.json in my collection.media folder.
On Anki Desktop (Ubuntu), the following works:
<script src="_script.jquery-3.3.1.min.js"></script>
<script>
$.getJSON('_data.json', function(data) {
// succeeds on Anki Desktop, fails on AnkiDroid
});
</script>
(Note on Anki Desktop 2.0.47 I am using the JS Booster plugin).
On AnkiDroid, the situation is different. JQuery loads just fine in the script tag. However, $.getJSON fails to find the _data.json file.
I'd like to use _data.json on many cards/notes.
How can I import non-media, non-js files from collection.media in javascript, in a way that works both in Anki Desktop and AnkiDroid?
I have found some working answer for this.
To get character data in AnkiDroid card templates. (OFFLINE)
As we can access js and image file using this
<script src="some-js-file.js"></script>
<img src="some-image.png"></img>
To access json
I have tried same steps but getting CORS error so I used next steps.
<!-- It will give CORS error -->
<script src="我.json" type="application/json"></script>
With example,
To access 我.json file
Copy contents of 我.json into a javascript file 我.js, with any variable name,
var char_data = {"strokes":["M 350 571 Q 3....}
Add following tag to access that js file
<!-- Note : file type & name -->
<script src="我.js" type="text/javascript"></script>
Now also change code in _hanzi-writer.min.js
To change code, first beautify code using this https://beautifier.io, then make following change
a) Remove the link to load from internet
b) Change this 200 != r.status and replace/add this
JSON.parse(JSON.stringify(char_data))
( May be more good replacement can be done here )
....
....
// Note : char_data variable come from 我.js file
r.overrideMimeType && r.overrideMimeType("application/json"), r.open("GET", "", !0), r.onerror = function(t) {
....
....
4 === r.readyState && (200 != r.status ? i(JSON.parse(JSON.stringify(char_data))) : 0 !== r.status && n && n(r))
....
....
So final script will be like this
Front side of card
{{Pinyin}}
<div id="character-target-div"></div>
<script src= "我.js" type="text/javascript"></script>
<script>
var data = JSON.stringify(char_data);
console.log(data);
</script>
<script src="_hanzi-writer.min.js"></script>
<script>
var writer = HanziWriter.create('character-target-div', '我', {
width: 150,
height: 150,
showCharacter: false,
padding: 5
});
writer.quiz();
</script>
Above all the steps are for single file 我.js
To access other character repeat the same.
For similar issues view my code
https://github.com/infinyte7/Anki-xiehanzi
https://github.com/infinyte7/hanzi-writer-data-in-javascript
I assume this is related to how AnkiDroid handles collections.media files. If so, this might be a bug. A really hackish workaround could be to rename the file to .svg so that AnkiDroid treats it as an image and lets it through.

How to include corresponding css and javascript of the page in assemble layout

I am using assemble to generate from html files with a common layout files. I want to include the corresponding css and javascript file with different pages. So that, for index.html, only index.css and index.js are included, and for about-us.html, only about-us.css and about-us.js are included.
Here's my respository on github https://github.com/xchitox/assemble-gulp-test
If you are already using gulp then use gulp-inject to inject the html files with their respective dependencies based on injection tags.
function injectStartingTag(filepath, starttag) {
var inject = require('gulp-inject');
// Injects the source using relative paths
return inject(gulp.src(filepath, {
read: false
}), {
relative: true,
starttag: '<!-- ' + starttag + ' -->'
});
}
In your index.html:
<!--inject:index:css-->
<!--endinject-->
<!--inject:index:js-->
<!--endinject-->
In your about-us.html:
<!--inject:about-us:css-->
<!--endinject-->
<!--inject:about-us:js-->
<!--endinject-->
Call the function above in any gulp task. You can filter with gulp-if and call the function with the specific starttag. i.e.:
gulp.task('Inject', function(){
var _if = require('gulp-if');
var all_your_files = "**/*.*"; // obvously only add html, js, and css files
return gulp
.src(all_your_files)
.pipe(_if('index.html', injectStartingTag('index.css', 'inject:index:css')))
.pipe(_if('about-us.html', injectStartingTag('about-us.css', 'inject:about-us:css')))
...
...
// you get the idea
});
You can use a helper to generate the link to the assets based on the filename of the current view:
app.helper('filename', function() {
// this.view is the current view being rendered
return this.view.stem; // just get the basename without extension
});
Now you can use this to add the assets path in your layout:
<link rel="stylesheet" href="/assets/css/{{filename}}.css">
<script src="/assets/js/{{filename}}.js"></script>

How to write a lodash template loader for requirejs

I'm using a requirejs plugin to define "tmpl!" loader (not a jquery template, but a lodash template. The problem is that the text! loader is adding a ";" at the end of the template. This is being rendered and is breaking everything.
(function(global){
"use strict";
define({
load : function(name, require, load, config) {
var deps = [];
deps.push('text!' + name);
deps.push('underscore');
require(deps, function(source, _) {
var template = _.template(source);
load(template);
});
}
});
})(this);
How can I stop text! from adding a semi-colon? Or: is there a better way to do this?
Taking the questions in reverse order:
is there a better way to do this?
It seems there is an existing implementation of this, and you might want to consider using it rather than writing your own. Although the simple case is a small amount of code, there are a bunch of r.js optimizer-related things you might eventually need.
But regarding your implementation logic, I noticed that this similar project for Handlebars does not use the text! plugin but instead does its own XHR in the load() method. This is not explained, but he gives some guidance for adapting it to other templating languages. Note: the link came from this question where there is some other good discussion of the approach.
How can I stop text! from adding a semi-colon?
I tried your plug-in and did not get any added semicolons. Perhaps you could post more of the sample project and templates? Below is mine, with everything in one flat folder for simplicity:
require.js: latest from RequireJS site
domReady.js: latest from RequireJS site
text.js: latest from RequireJS site
lodash.js: latest from lodash site
tmpl.js: your example loader from the question
index.html:
<!DOCTYPE html>
<html>
<head>
<script src='require.js'></script>
<script>
requirejs.config({
map: {
'*': { 'underscore': 'lodash' }
}
});
require( [ 'underscore', 'tmpl!friend-template.htm', 'domReady!' ]
, function( _, friendTemplate ){
var friendsData = [{ name: 'Bob', age: 35 }, { name: 'Fred', age: 38 }];
document.body.innerHTML = friendTemplate( {friends: friendsData});
});
</script>
</head>
<body>
<!-- To be populated dynamically. -->
</body>
</html>
friend-template.htm:
<ul>
<% _.forEach(friends, function(friend) { %>
<li>
<span><%- friend.name %></span>
<span>( Age: <span class="value"><%- friend.age %></span> )</span>
</li>
<% }); %>
</ul>
I've created a loader specifically for Lo-Dash which you can see here:
https://gist.github.com/tbranyen/6821045
Note: I have no unit tests or assurances this free of bugs, but from my initial testing it appears to work fantastic.
This is better in a number of ways than requirejs-tpl which bakes in it's own implementation which is not exposed. It also requires a file extension and hardcoded path. Both of these are configurable in my code.
Edit: I've since released a project called lodash-template-loader which has tests. https://github.com/tbranyen/lodash-template-loader

Resources