I wanted to use the d3-context-menu lib but the example file wasn't working for me – the d3-context-menu code wasn't getting initialized.
I didn't know the "right" way to do it – but in my non-es6, d3 Electron/Node project I got it working through the steps below. I am no JS hero. In my searches I saw a lot of stuff about "Node edge" and "Babel transpiling" but I try hard not to dump in code and coding approaches I don't understand
Is there anything wrong with the way I am doing it?
putting the d3-context-menu.js file in my js directory, along with the associated css file in my css directory and referencing it from the main index.html
in my main script I initialize d3-context-menu.js like this:
let d3 = require('./js/d3')
let d3contextMenuLib = require('./js/d3-context-menu')
let d3ContextMenu = d3contextMenuLib(d3);
finally, I attach the event listeners to the objects that should get them (I don't need the "onOpen"/"onClose " functions shown in the example code).
.on('contextmenu', d3ContextMenu(eventMenu));
Related
Thank you for checking my question. This may sound trivial but I need help here.
I want to learn how to change HTML code with GULP. Or just change some strings with GULP. For example today I need to change this:
<img class="social" src="../symbols/facebook.svg">
to this:
<svg class="social">
<use xlink:href="../symbols/sprite.svg?v201608061556#facebook"></use>
</svg>
As you can see I am building icon system via symbols and I want to keep my original HTML clean as it can be. So I can work without any watchers and such. Later I just run GULP once and it does the job: create sprite and change HTML to use this sprite.
I tried gulp-replace and it can change one string to another with regex, but it looks too complicated for me with regex. I am not even sure that it is possible to do with regex. And I also want to add timestamp as ?v201608061556. So I want to run some JavaScript that I can write in gulp file.
Next one I tried is gulp-dom and it looks like the thing I need. But I can't make it work due to some errors:
if (node.nodeType === NODE_TYPE.DOCUMENT_NODE) {
^
TypeError: Cannot read property 'nodeType' of undefined
Error log in terminal:
So the questions is:
Is it possible to make with regex and gulp-replace package?
Does anyone know gulp-dom
package. Can I make it work somehow? Is it possible to complete my
task with it?
Is there another way to write JavaScript in Gulp task
so I can take a string, process it according to my needs with all JavaScript functionality and save?
Can I work with HTML from Gulp the same way
I work when I code websites? Work with DOM, use
querySelector and classList for example? Maybe jQuery?
Thanks.
Ok, I found a gulp-change. It gives you file content as a string. You can do everything you want with that string with javascript and then return it back to pipe.
It would be easier to diagnose the issue if you had posted your gulp tasks stream. With the information you provided I believe you are getting this error because (if you are following the example on the plugin page) you are probably returning the element you modified, not the complete Document representation. Below follows the example from the gulp plugin page:
gulp.task('html', function() {
return gulp.src('./src/index.html')
.pipe(dom(function(){
return this.querySelectorAll('body')[0].setAttribute('data-version', '1.0');
}))
.pipe(gulp.dest('./public/'));
});
There are two crucial steps you should take to manipulate the DOM with gulp-dom:
first make the changes on the element(s) you want using simple js DOM manipulation methods such as getElmentById, setAttribute, appendChild, etc.
once that is done, your gulp stream should return this (the whole Document), not the element(s) you are targeting for modification.
In your case you could do something like this (If you find this too verbose you may try to use a different plugin/approach altogether):
var gulp = require('gulp');
var dom = require('gulp-dom);
gulp.task('domManipulation', function() {
return gulp.src('app/index.html')
.pipe(dom(function(){
// cache/create all elements you will work with --'this' is your Document
var parentDiv = this.querySelector('div.imgParent');
var img = this.querySelector('img.social');
var svg = this.createElement('svg');
var use = this.createElement('use');
// DOM manipulation
svg.classList.add('social');
use.setAttribute('xlink:href', "../symbols/sprite.svg?v201608061556#facebook");
svg.appendChild(use);
parentDiv.replaceChild(svg, img);
return this; // return the whole Document
}))
.pipe(gulp.dest('dist'));
});
I tested the code above and it works just fine. Hope this helps.
I have a Meteor project that is starting to get out of hand with about 800 lines of code. I set out today to modularize and clean things up a bit and things are looking good, but I'm getting some errors that I don't know the best way how to deal with.
Here's a prime example.
I am using d3 to create a force layout (this question isnt specific to d3). I instantiate some variables and most notably
var force = d3.layout.force()
in a file
/client/views/force/forceLayout.js
I made a bunch of controls for this force layout and put them in their own .html and .js files. Heres an example
initChargeSlider = function() {
d3.select("#charge-slider")
.call(d3.slider()
.min(-301)
.max(-1)
.step(5)
.value(Session.get("charge"))
.on("slide", function(evt, value) {
Session.set("charge", value);
// force.stop();
force = force.charge(value);
force.start();
}));
}
Template.charge.rendered = function() {
initChargeSlider();
};
in file
/client/views/force/controls/sliders/charge.js
Due to Meteor loading deeper directories first, I get an error at force = force.charge(value) because forceLayout.js hasn't instantiated force yet.
I'm curious what is the most best way of dealing with this. Moving the files around and loading order is just reversing all the modularizing I just did. I think a singleton or an object or monad may be in order but I'm not sure which or why. I would appreciate an explanation of how to go about fixing these errors.
Thanks
Chet
Meteor before 0.6.5 run files without wrapping them inside a function wrapper (function() { /* your code */ })().
This behavior is still followed if you place your files in client/compatibility folder:
Some JavaScript libraries only work when placed in the
client/compatibility subdirectory. Files in this directory are
executed without being wrapped in a new variable scope. This means
that each top-level var defines a global variable. In addition, these
files are executed before other client-side JavaScript files.
Now, Meteor is more unforgiving of global variables and now one needs to be explicit about declaring them. Hence,
window.force = d3.layout.force()
or even
this.force = d3.layout.force(); // this === window in global context.
would solve the problem.
I have a interesting concept I was working on and looking over, through various stack questions on auto loading JavaScript. I dint want to use a third party tool, aside form jquery, so I thought I would role my own. The concept I have is:
var scripts = {
'name' : 'path/to/script_dir/' // Load all scripts in this file.
}
requireScripts(scripts); // Requires all scripts
// Call your classes, methods, objects and so on ....
The requireScript() function would work something like:
function requireScript(hash){
$.each(hash, function(key, value)){
$.ajax({
url: value,
dataType: "script",
async: false,
error: function () {
throw new Error("Could not load script " + script);
}
});
});
}
Note: The above is just a concept, I don't think it will work.
The above would let you load SPECIFIC scripts. so in essence your hash key value would be 'name' : 'path/to/specific/script'. The issue this posses is that your hash would get rather large ....
The other issue I ran into is what if I simplified this to "php pear naming standard" so, as the trend seems to be - we would create a class, and it would be named after its location:
var some_folder_name_class = function(){}
Would be translated by the autoloader as: some/folder/name/class.js and then loaded that way.
To wrap up and get to my point there are two ways of loading javascript file I am looking at, via rolling my own "require" method. One is loading a directory of javascript files via the hash idea implemented above. (the provided code sample of how this hash would be walked through would have to be changed and fixed....I dont think it works to even load a single file)
OR
to have you just do:
new some_class_name() and have a global function listen for the new word, go find the file your trying to call based on the name of the class and load it, this you never have to worry - as long as you follow "pear naming standards" in both class and folder structure your js file will be loaded.
Can either approach be done? or am I dreaming to big?
I see a lot of frameworks do a bunch of require('/path/to/script') and if I could role my own autoloader to just allow me to either load a directory of js files or even have it where it listens for new before a class instantiation then I could make my life SO MUCH easier.
Have you consider using requirejs and probably Lazy loading.
http://www.joezimjs.com/javascript/lazy-loading-javascript-with-requirejs/
Here is sample version:
You can download here.
The sample is based on this folder structure :
public
index.html
scripts
app.js
lib
** jquery-1.10.2.js
** require.js
3 . From Code:
html
`<!DOCTYPE html><html>
<head><title>Sample Test</title>`
<script src="scripts/lib/require.js"></script> <!-- downloaded from link provide above-->
<script src="scripts/app.js"></script></head>
`<body><h1>My Sample Project</h1><div id="someDiv"></div></body></html>`
application configuration app.js
requirejs.config({
baseUrl: 'scripts',
paths: {
app: 'app',
jquery: 'lib/jquery-1.10.2' //your libraries/modules definitions
}
});
// Start the main app logic. loading jquery module
require(['jquery'], function ($) {
$(document).on('ready',function(){
$('#someDiv').html('Hello World');
});
});
jQuery-only option
If you are looking for a jQuery-only solution, have a look at jQuery.getScript(). It would be a great candidate for handling the script loading portion of your problem. You could then write a very small wrapper around it to load all the scripts—something like you wrote above:
var loadScripts = function(scripts) {
$.each(scripts, function(name, path) {
jQuery.getScript("/root/path/" + path + ".js");
})
}
If you are interested in more information on this approach, read this article by David Walsh.
Other great libraries
I strongly recommend taking a look at the current batch of script-loading libraries. I think that you will pleasantly surprised by what is out there. Plus, they come with the benefit of great community support and documentation. RequireJS seems to be the front runner but David Walsh has great articles on curl.js and LABjs.
I've noticed that RequireJS creates script tags in the tag as it loads modules.
Is there anyway to configure RequireJS to "tag" those elements w/ a class or an attribute of some kind that I could later target w/ jQuery later on?
e.g.:
var $requireJsScripts = $('script.require-script');
--UPDATE--
Ok.. I think I can get by on this little workaround for now. Thanks to this answer for the breadcrumb on require.s.contexts._.defined. I'd still like to hear if anyone knows of a way to configure RequireJS to do something similar to what was laid out in the original question...
var loadedRjsModules = Object.keys(require.s.contexts._.defined);
var $scripts = $('script');
$scripts.each(function () {
if ($(this).data('requiremodule') && $.inArray($(this).data('requiremodule'), loadedRjsModules)) {
console.log(this);
}
});
Looking at the source code, I don't see how RequireJS would allow adding anything custom to the script nodes at creation. The routine that creates them has no provision for it. The code that fleshes them out upon creation does not support it either.
There's an onResourceLoad hook considered part of the internal API. It could be used with the code you've put in your question instead of relying on require.s.contexts._.defined, which as far as I know is fully private and subject to change without notice.
I will explain my idea behind this:
I use python for google app engine + js + css
the main project will be stored under the src folder like this:
\src
\app <--- here goes all the python app for gae
\javascript <--- my non-packed javascript files
\static_files <--- static files for gae
now the javascript dir looks like this
\javascript
\frameworks <--- maybe jQuery && jQueryUI
\models <--- js files
\controllers <--- js files
\views <--- HTML files!
app.js <--- the main app for js
compile.py <--- this is the file I will talk more
About compile.py:
This file will have 2 methods one for the min and other for the development javascript file;
When is run will do:
Join all the files with "js" extension;
The app.js contains a variable named "views" and is an object, like a hash; Then the compiler copy the contents of each file with "html" extension located in the "/javascript/views/" dir using this rule;
example: if we have a view like this "/views/login.html" then the "views" js var will have a property named "login"; views['login'] = '...content...';
example2: "/views/admin/sexyBitcy.html" then view['admin.sexyBitcy'] = '...content...' or whatever exists in that html file..;
Then this big file will be saved into the "/src/static_files/core.js"; if is minified will be saved as "/src/static_files/core.min.js";
The javascript will use dependenccy injection, or sort of it. (:
I will explain how it will work then:
the index.html that is loaded when you come into the site loads the core.js and the jquery.js;
the core.js will create the layout of the page, as SEO is not important for the most of the pages;
the core.js uses the controllers-models-views to create the layout of course; the html for the layout is inside the var "views"; will be a heavy variable of course!
Some code:
mvcInjector = new MVCInjector;
mvcInjector.mapView(views['login'], 'login', LoginController);
parent = $('#jscontent');
jquery
view = mvcInjector.instanceView('login', parent); // <--- this will create the contents of the views['login'] in the parent node "parent = $('#jscontent');" then will instance the LoginController that will map the "SkinParts" (like in FLEX if you know); what does it mean map the "SkinParts"? - when the user will click on a button an handler for that action is defined in the controller; ex.:
// LoginController
this.init = function(){
// map skin parts
this.mapSkinPart('email', 'input[name]="email"');
this.mapSkinPart('submit', 'input[name]="submit"');
// link skin parts to handlers
this.getSkinPart('submit').click = this.login;
}
// handlers
this.login = function(event){
// connect to the db
// some problems here the get the value as the "this" keyword references to the this of the controller class, I will work it around soon
alert('open window button1' + this.getSkinPart('email').value());
}
If something is not clear just say something, I will be happy to explain;
So the question remains: is this scalable, manageable and fast enough for a big RIA application build with javascript+jquery and maybe with jqueryUI?
Thanks ;)
I like your idea quit a bit.
I would think about loading html pages by ajax, if they are big and there are many of them...
Have a look on angular project, I hope, it could help you a lot. It's a kind of JS framework, designed to work together with jQuery. Well suitable for test driven development.
It uses html as templates, you can simply create your own controllers, use dependency injector, etc... Feel free to ask any question on mailing list.
Then, I must recommend JsTestDriver - really cool test runner for JS (so you can easily run unit tests in many browsers, during development - let's say after save...)