Change some html code into antoher with GULP - javascript

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.

Related

How do you use an npm package with require & module export as a plain JS library

I'm not sure I'm even asking the right question here, sorry, but I think the two general ones are:
In what way do you need to modify a node.js package using require etc to be used as a plain embedded script/library in HTML?
How do you call a class constructor (?) in JS as a function to validate a form field?
I'm trying to use this small JS library NoSwearingPlease (which is an npm package) in an environment with no node or build system – so I'm just trying to call it like you would jQuery or something with a script & src in the HTML, and then utilise it with a small inline script.
I can see a couple of things are required to get this working:
the JSON file needs to be called in a different way (not using require etc)
the checker variable needs to be rewritten, again without require
I attempted using jQuery getJSON but I just don't understand the class & scope bits of the library enough to use it I think:
var noswearlist = $.getJSON( "./noswearing-swears.json" );
function() {
console.log( "got swear list from inline script" );
})
.fail(function() {
console.log( "failed to get swear list" );
})
noswearlist.done(function() {
console.log( "done callback as child of noswearlist variable" );
var checker = new NoSwearing(noswearlist);
console.log(checker);
});
Please halp. Thanks!
No need to modify, when outside of node the class is just appended to window (global):
fetch("https://cdn.jsdelivr.net/gh/ThreeLetters/NoSwearingPlease#master/swears.json").then(response => {
return response.json();
}).then(data => {
var noSwearing = new NoSwearing(data);
console.log(noSwearing.check("squarehead"));
});
<script src="https://cdn.jsdelivr.net/gh/ThreeLetters/NoSwearingPlease#master/index.js"></script>
In the future, you can answer this type of question on your own by looking through the source code and looking up things you don't understand. That being said, here's what I was able to gather doing that myself.
For your first question, if you have no build tools you can't use require, you have to hope your NPM package supports adding the class to the window or has a UMD export (which in this case, it does). If so, you can download the source code or use a CDN like JSDelivr and add a <script> tag to link it.
<script src="https://cdn.jsdelivr.net/gh/ThreeLetters/NoSwearingPlease#master/index.js"></script>
I'm having a hard time deciphering your script (it has a few syntax errors as far as I can tell), so here's what you do if you have a variable ns containing the JSON and the string str that you need to check:
var checker = new NoSwearing(ns);
checker.check(str);
As an aside, you should really use build tools to optimize your bundle size and make using packages a lot easier. And consider dropping jQuery for document.querySelector, fetch/XMLHttpRequest, and other modern JavaScript APIs.

Alfresco: Write workflow script to copy document in same folder and continue workflow with new document

For one of my workflows, I want to be able to select a document in my start task. Then, I would like to execute a script to make a copy of this document in the same folder, and continue the workflow with the new document (if this is possible). I don't have much java experience but I'm trying to achieve something along the lines of:
<script>
var path = bpm_package.children[0].displayPath;
var newdoc = bpm_package.children[0].copy(path);
newdoc.save();
bpm_package = newdoc;
</script>
Any help would be greatly appreciated!
Marcus
Basically the argument in copy function is the object of parent node and not a path to parent node.
So the below code will do the work.
bpm_package.children[0].copy(bpm_package.children[0].parent);
You do not need to call save or any other function after that.Basically this are javascript api of alfresco.
You can take a look on below link for more details.
http://docs.alfresco.com/4.1/references/API-JS-Scripting-API.html
Thanks to Krutik for answering the first part of the answer. I'm adding the solution to changing the document in the workflow. This is done by adding and removing documents from the bpm_package property. The whole script is as below:
var newdoc = bpm_package.children[0].copy(bpm_package.children[0].parent);
bpm_package.removeNode(bpm_package.children[0]);
bpm_package.addNode(newdoc);

inserting text in a gulp stream

I would like to hard-code a variable into a GULP task (for development purposes and not production), I need something like this:
gulp.task('buildJS', function() {
gulp.insert('var DEV = true;') // inserting the text somehow
.src([
'./js/a.js',
'./js/b.js',
'./js/c.js'
])
.pipe(concat('main.min.js'))
.pipe(gulp.dest('./js/'));
});
I tried to google it, but I get a bunch of bad results, also not sure what exactly to look for here, but can only describe here.
As you can see in the first line, I would like to insert some variable that comes before all other things (in this specific case, and then the rest of the files should be included, and it all gets concatenated into one file at the end, but I am not sure how to do that... Thanks for any help with this!
You can use the gulp-header plugin that allow to append text at the beginning of your files and which support templating.
You can do something like :
var header = require('gulp-header');
gulp.task('buildJS', function() {
gulp.src([
'./js/a.js',
'./js/b.js',
'./js/c.js'
])
.pipe(header('var DEV = true;'))
.pipe(concat('main.min.js'))
.pipe(gulp.dest('./js/'));
});
Or if you only want to append it on the concatened file
gulp.task('buildJS', function() {
gulp.src([
'./js/a.js',
'./js/b.js',
'./js/c.js'
])
.pipe(concat('main.min.js'))
.pipe(header('var DEV = true;'))
.pipe(gulp.dest('./js/'));
});
You may want to use gulp-header : https://www.npmjs.org/package/gulp-header
In your case, put it after the concat operation in the pipeline.

Make RequireJS place class on script tags it creates?

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.

Minify Javascript programmatically in-memory

I am building a nifty little "asset-pipeline" for a express.js application, but i have a problem with the compression-step for javascript files
scripts = (fs.readFileSync(file) for file in filelist)
result = scripts.join("\n\n") # concat
upto now, things are working as expected (the logic itself is written in coffeescript). The next step after merging the JS-files would be to minify them. But here is my problem: i want to do this "hot" when i start my express-app in production mode, from within a piece of connect-middleware i wrote.
I need a solution that can minify a given blob of javascript stuff, without writing the result to disk (!), in other words: a function that does the minification and returns the result directly as a result value. (No, no webservices either.) It should be usable like this:
minified_result = awesomeMinifyFunction( result )
The raw processing performance isn't that important for me, neither is the level of compression, i need just something that works this way without hassle.
Does anyone know a suitable solution? Thanks in advance!
I'd suggest you look at one of the JavaScript based minifiers, like UglifyJS2.
npm install uglify-js
It can be used within a Node.JS application programatically:
var UglifyJS = require("uglify-js");
// you could pass multiple files (rather than reading them as strings)
var result = UglifyJS.minify([ "file1.js", "file2.js", "file3.js" ]);
console.log(result.code);
Or you could
var result = scripts.join("\n\n"); # concat
result = UglifyJS.minify(result, {fromString: true});
console.log(result.code);
You can write your own function that removes all comments/spaces/blank lines etc.
You can use a regular expression that makes use of rJSmin like:
function awesomeMinifyFunction(result)
{
pattern = (
r'([^\047"/\000-\040]+)|((?:(?:\047[^\047\\\r\n]*(?:\\(?:[^\r\n]|\r?'
r'\n|\r)[^\047\\\r\n]*)*\047)|(?:"[^"\\\r\n]*(?:\\(?:[^\r\n]|\r?\n|'
r'\r)[^"\\\r\n]*)*"))[^\047"/\000-\040]*)|(?<=[(,=:\[!&|?{};\r\n])(?'
r':[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*'
r'(?:(?:(?://[^\r\n]*)?[\r\n])(?:[\000-\011\013\014\016-\040]|(?:/\*'
r'[^*]*\*+(?:[^/*][^*]*\*+)*/))*)*((?:/(?![\r\n/*])[^/\\\[\r\n]*(?:('
r'?:\\[^\r\n]|(?:\[[^\\\]\r\n]*(?:\\[^\r\n][^\\\]\r\n]*)*\]))[^/\\\['
r'\r\n]*)*/)[^\047"/\000-\040]*)|(?<=[\000-#%-,./:-#\[-^`{-~-]return'
r')(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/'
r'))*(?:(?:(?://[^\r\n]*)?[\r\n])(?:[\000-\011\013\014\016-\040]|(?:'
r'/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)))*((?:/(?![\r\n/*])[^/\\\[\r\n]*(?'
r':(?:\\[^\r\n]|(?:\[[^\\\]\r\n]*(?:\\[^\r\n][^\\\]\r\n]*)*\]))[^/'
r'\\\[\r\n]*)*/)[^\047"/\000-\040]*)|(?<=[^\000-!#%&(*,./:-#\[\\^`{|'
r'~])(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)'
r'*/))*(?:((?:(?://[^\r\n]*)?[\r\n]))(?:[\000-\011\013\014\016-\040]'
r'|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*)+(?=[^\000-\040"#%-\047)*,./'
r':-#\\-^`|-~])|(?<=[^\000-#%-,./:-#\[-^`{-~-])((?:[\000-\011\013\01'
r'4\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)))+(?=[^\000-#%-,./:'
r'-#\[-^`{-~-])|(?<=\+)((?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*'
r'\*+(?:[^/*][^*]*\*+)*/)))+(?=\+)|(?<=-)((?:[\000-\011\013\014\016-'
r'\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)))+(?=-)|(?:[\000-\011\013'
r'\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))+|(?:(?:(?://[^'
r'\r\n]*)?[\r\n])(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^'
r'/*][^*]*\*+)*/))*)+'
)
return result.match(pattern);
}
I'd recommend taking a look at Asset Rack, which already implements what you're building.

Categories