I am working on creating a static node.js server that just serves up the plain html, css, and javascript that is in the specified directory. I am trying to get the server to read every subdirectory and route the url to the file it specifies. However it only reads the root directory.
var fs = require('fs');
var array = fs.readdirSync(__dirname);
function getAllSub(array){
for (i = 0; i < array.length; i++){
if (array[i].indexOf(".") == (-1))
{
array = array.concat(array[i] + "/" + fs.readdirSync(__dirname + "/" + array[i]));
}
if (array[i].indexOf("/") != (-1)){
var foldcon = array[i].substr(array[i].indexOf("/") + 1);
var folder = array[i].substr(0, array[i].indexOf("/"));
foldcon = foldcon.split(",");
for (n = 0; n < foldcon.length; n++){
foldcon[n] = folder + "/" + foldcon[n]
if (foldcon[n].indexOf(".") == (-1)){
console.log([foldcon[n]]);
foldcon[n] = getAllSub([foldcon[n]]);
}
}
array.splice(i, 1, foldcon);
}
}
return array;
}
array = getAllSub(array);
console.log(array);
Right now this code reads the directory and it recognizes if an item in the array of files is a folder, however it doesn't add the files from the subdirectories into the array properly. Right now it kinda goes all infinite recursion, and I can't really figure out how to stop it.
This isn't meant to be something I am actually going to use, I just thought it would be a good project to work on to introduce myself to the basics of node.js
edited^
I know it's late, but this is the right answer for a recursive solution to reading file paths in sub-folders:
var fs = require("fs");
/**
* Recurse through a directory and populate an array with all the file paths beneath
* #param {string} path The path to start searching
* #param {array} allFiles Modified to contain all the file paths
*/
function readdirSyncRecursive(path, allFiles) {
var stats = fs.statSync(path);
if (stats.isFile()) {
// base case
allFiles.push(path);
} else if (stats.isDirectory()) {
// induction step
fs.readdirSync(path).forEach(function(fileName) {
readdirSyncRecursive(path + "/" + fileName, allFiles);
});
}
}
var allFiles = [];
readdirSyncRecursive("/path/to/search", allFiles);
console.info(allFiles);
var fs = require('fs');
var array = fs.readdirSync(__dirname);
for (i = 0; i < array.length; i++){
if (array[i].indexOf(".") == (-1))
{
// you need to use the return value from concat
array = array.concat(array[i] + "/" + fs.readdirSync(__dirname + "/" + array[i]));
console.log('if executed');
}
}
console.log(array);
Related
I am learning node.js
for example, I try
var server = require("./myserver.js");
and
var server = require("./myserver");
why do both work? What is this kind of things call?
If you take a look at node's source code for the require-function, you can see that require's load-function calls a function findLongestRegisteredExtension to determine the file-extension. This function returns .js as its default value if no extension could be determined:
function findLongestRegisteredExtension(filename) {
const name = path.basename(filename);
let currentExtension;
let index;
let startIndex = 0;
while ((index = name.indexOf('.', startIndex)) !== -1) {
startIndex = index + 1;
if (index === 0) continue; // Skip dotfiles like .gitignore
currentExtension = name.slice(index);
if (Module._extensions[currentExtension]) return currentExtension;
}
return '.js';
}
That's why using both require("./myserver.js"); or require("./myserver"); will resolve the same module.
In google docs one can easily add headings and link to them from inside of the document. But when the heading text changes, the link text does not change.
Is there a way to change that behavior or update the link text automatically?
I know it is about 1 1/2 years, but maybe this will help. I have had the exact same problem and wrote a function that will update all the links to the headings in a document. Since I could not find any built-in functions or add-ons, the only way was to script it.
Some things to consider:
This needs a current table of contents to work. If you don't have (or do not want) a TOC, you can insert one, run that function and delete it afterwards. Also, I have only tested it with a TOC that contains page numbers.
It will update ALL texts of links to headings in the document. However, links to everything else remain untouched.
Please use at your own risk (maybe try it out in a copy of your document). I have tested it, but the testing could have been more thorough. Also, this is my first in scripting Docs.
Paste this in the Script editor of your doc and run replaceHeadingLinks. Links that the script could not update (because they link to a heading that does not exist anymore) will be output in the console.
function replaceHeadingLinks() {
var curDoc = DocumentApp.getActiveDocument();
var links = getAllLinks_(curDoc.getBody());
var headings = getAllHeadings_(curDoc.getBody());
var deprecatedLinks = []; // holds all links to headings that do not exist anymore.
links.forEach(function(link) {
if(link.url.startsWith('#heading')) {
// get the new heading text
var newHeadingText = headings.get(link.url);
// if the link does not exist anymore, we cannot update it.
if(typeof newHeadingText !== "undefined") {
var newOffset = link.startOffset + newHeadingText.length - 1;
// delete the old text, insert new one and set link
link.element.deleteText(link.startOffset, link.endOffsetInclusive);
link.element.insertText(link.startOffset, newHeadingText);
link.element.setLinkUrl(link.startOffset, newOffset, link.url);
} else {
deprecatedLinks.push(link);
}
}
}
)
// error handling: show deprecated links:
if(deprecatedLinks.length > 0) {
Logger.log("Links we could not update:");
for(var i = 0; i < deprecatedLinks.length; i++) {
var link = deprecatedLinks[i];
var oldText = link.element.getText().substring(link.startOffset, link.endOffsetInclusive);
Logger.log("heading: " + link.url + " / description: " + oldText);
}
} else {
Logger.log("all links updated");
}
}
/**
* Get an array of all LinkUrls in the document. The function is
* recursive, and if no element is provided, it will default to
* the active document's Body element.
*
* #param {Element} element The document element to operate on.
* .
* #returns {Array} Array of objects, vis
* {element,
* startOffset,
* endOffsetInclusive,
* url}
*
* Credits: https://stackoverflow.com/questions/18727341/get-all-links-in-a-document/40730088
*/
function getAllLinks_(element) {
var links = [];
element = element || DocumentApp.getActiveDocument().getBody();
if (element.getType() === DocumentApp.ElementType.TEXT) {
var textObj = element.editAsText();
var text = element.getText();
var inUrl = false;
var curUrl = {};
for (var ch=0; ch < text.length; ch++) {
var url = textObj.getLinkUrl(ch);
if (url != null) {
if (!inUrl) {
// We are now!
inUrl = true;
curUrl = {};
curUrl.element = element;
curUrl.url = String( url ); // grab a copy
curUrl.startOffset = ch;
}
else {
curUrl.endOffsetInclusive = ch;
}
}
else {
if (inUrl) {
// Not any more, we're not.
inUrl = false;
links.push(curUrl); // add to links
curUrl = {};
}
}
}
// edge case: link is at the end of a paragraph
// check if object is empty
if(inUrl && (Object.keys(curUrl).length !== 0 || curUrl.constructor !== Object)) {
links.push(curUrl); // add to links
curUrl = {};
}
}
else {
// only traverse if the element is traversable
if(typeof element.getNumChildren !== "undefined") {
var numChildren = element.getNumChildren();
for (var i=0; i<numChildren; i++) {
// exclude Table of Contents
child = element.getChild(i);
if(child.getType() !== DocumentApp.ElementType.TABLE_OF_CONTENTS) {
links = links.concat(getAllLinks_(element.getChild(i)));
}
}
}
}
return links;
}
/**
* returns a map of all headings within an element. The map key
* is the heading ID, such as h.q1xuchg2smrk
*
* THIS REQUIRES A CURRENT TABLE OF CONTENTS IN THE DOCUMENT TO WORK PROPERLY.
*
* #param {Element} element The document element to operate on.
* .
* #returns {Map} Map with heading ID as key and the heading element as value.
*/
function getAllHeadings_(element) {
var headingsMap = new Map();
var p = element.findElement(DocumentApp.ElementType.TABLE_OF_CONTENTS).getElement();
if(p !== null) {
var toc = p.asTableOfContents();
for (var ti = 0; ti < toc.getNumChildren(); ti++) {
var itemToc = toc.getChild(ti).asParagraph().getChild(0).asText();
var itemText = itemToc.getText();
var itemUrl = itemToc.getLinkUrl(0);
var itemDesc = null;
// strip the line numbers if TOC contains line numbers
var itemText = itemText.match(/(.*)\t/)[1];
headingsMap.set(itemUrl,itemText);
}
}
return headingsMap;
}
So, i have 2 paths:
var path1 = "M2337.8,0.1c-346.8,7.6-415.8,270.8-934.3,244.7 c-330.4-16.6-389.1-110.8-677.8-101.3c-321,10.5-403.4,252.6-592.3,252.6C73,396.1,29.8,372.8,0,341.9v451.8h2778V200 C2692.9,103.1,2538.6-4.3,2337.8,0.1z",
path2 = M2337.8,326.3C1991,333.9,1845,45.9,1472,45.9 c-334.4,0-390,181.9-639,181.9C473,227.8,400.3,0,195.7,0C84.5,0,0,98.3,0,146.1v562.6h2778V62.9 C2686,199.8,2538.6,321.9,2337.8,326.3z
Can i animate it using paper.js?
Thank's.
Here is the algorithm I used in one of my previous project:
make sure both path has the same number of points
(optional) add extra points in both paths for a smoother morphing
interpolate each point and its handles based on original paths values
Look at this Sketch for a demonstration.
// create paths
var pathB = new Path.Circle(view.center, 200);
var pathA = new Path.Rectangle(view.center - 100, new Size(200));
var morphingPath = new MorphingPath(pathA, pathB);
// apply some styling
pathA.strokeColor = 'red';
pathB.strokeColor = 'blue';
morphingPath.path.fullySelected = true;
// animate morphing
function onFrame(event)
{
// with values from 0 to 1
morphingPath.morph(Math.abs(Math.sin(event.count * 0.01)));
}
/**
* A path that can be morphed between two other paths.
* #param {Path} path1
* #param {Path} path2
* #constructor
*/
function MorphingPath(path1, path2)
{
// internal variables
var self = this,
clone1,
clone2;
//
// API
//
// allow direct access to morphing path
self.path = null;
/**
* interpolate path from path1 to path2
* #param time must be a value from 0 to 1
*/
self.morph = function (time)
{
var segments = [];
for (var i = 0; i < self.path.segments.length; i++)
{
// morph segments
var segment1 = clone1.segments[ i ],
segment2 = clone2.segments[ i ],
point = rampPoint(segment1.point, segment2.point, time),
handleIn = rampPoint(segment1.handleIn, segment2.handleIn, time),
handleOut = rampPoint(segment1.handleOut, segment2.handleOut, time);
segments.push(new Segment(point, handleIn, handleOut));
}
self.path.segments = segments;
};
//
// INTERNAL METHODS
//
function init()
{
// store local copies of source paths
clone1 = path1.clone();
clone2 = path2.clone();
// hide them
clone1.visible = false;
clone2.visible = false;
// init morphing path
self.path = createMorphingPath();
}
/**
* Create the path that will later be morphed.
* Points are added when needed, for a smoother result.
* #returns {Path}
*/
function createMorphingPath()
{
var paths = [ clone1, clone2 ],
offsets = [ [], [] ];
// store paths segments offsets (except for first and last)
for (var i = 0; i < paths.length; i++)
{
var path = paths[ i ];
// loop segments
for (var j = 1; j < path.segments.length - 1; j++)
{
// store offset
offsets[ i ].push(path.segments[ j ].location.offset);
}
}
// add missing points
for (var i = 0; i < paths.length; i++)
{
// get current path offsets array
var pathOffsets = offsets[ i ];
// get a reference to the other path
var otherPath = i == 0 ? paths[ i + 1 ] : paths[ 0 ];
// loop current path offsets
for (var j = 0; j < pathOffsets.length; j++)
{
// add a corresponding point for that offset in the other path
otherPath.divideAt(otherPath.getLocationAt(pathOffsets[ j ]));
}
}
return clone1.clone();
}
function rampPoint(p1, p2, t)
{
return p1 + (p2 - p1) * t;
}
init();
}
Since in V3 children was deprecated, i'm trying to get another way to search inside parent folder (using parent id) and get all children inside within subfolders too.
Didn't find a way how to do it in drive docs.
Please advice.
The following works for me:
function getChildFolders(folderId){
var q = "mimeType = 'application/vnd.google-apps.folder' and '"+folderId+"' in parents";
var children = Drive.Files.list({q:q});
var res = [];
for(var i=0; i<children.items.length; i++){
res.push(children.items[i].title);
res = res.concat(getChildFolders(children.items[i].id));
}
return res;
}
Logger.log(getChildFolders(rootId));
But getting all (grant)child folders at once does not seem possible indeed.
Unfortunately, Drive API doesn't have a search filter like "return all children of FOLDER_NAME". The only available search queries are found in Search for Files.
But, there's a somewhat similar filter you can use, but this time, using the parent folder's ID. This applies to subfolders too.
So for example you have this URL of the parent folder which contains your files.
https://drive.google.com/drive/folders/123456789
Use the search query
'123456789' in parents
and it will return all the files inside that folder.
Give the Files.list Try-it a test.
Perhaps you could use this 2 functions..
/**
* Export Array Files N' Folder Names from Drive Folder
*/
function listCurFoldersEFilesName(folderId) {
var data= [];
var j =0 , i = 0;
var folders = DriveApp.getFolderById(folderId).getFolders(); //returns a FolderInterator
while (folders.hasNext()) {
var folder = folders.next();
var folderName = folder.getName();
data[j] = folderName.trim();
j++;
}
var files = DriveApp.getFolderById(folderId).getFiles(); //returns a FileInterator
while (files.hasNext()) {
var file = files.next();
var fileName = file.getName();
data[j+i] = fileName.trim();
i++;
}
return data;
}
/**
* Export Array Files N' Folder IDs from Drive Folder
*/
function listCurFoldersEFilesIDs(folderId) {
var data= [];
var j =0 , i = 0;
var folders = DriveApp.getFolderById(folderId).getFolders(); //returns a FolderInterator
while (folders.hasNext()) {
var folder = folders.next();
var infolderId = folder.getId();
data[j] = infolderId;
j++;
}
var files = DriveApp.getFolderById(folderId).getFiles(); //returns a FileInterator
while (files.hasNext()) {
var file = files.next();
var infileId = file.getId();
data[j+i] = infileId;
i++;
}
return data;
}
Well the results are unexpected for me at least. I'm trying to search through a directory and get all files and subfolders, however I'm having some problems with working with subdirectories of subdirectories. The function itself is designed to find all the contents of all the folders and all the files within a given folder, and call itself when one of the things inside a folder is a folder.
However, it never finishes, it keeps feeding the same folder into itself and never doing anything with it, eventually just crashing.
var fs = require('fs');
var array = fs.readdirSync(__dirname);
function getAllSub(array){
for (i = 0; i < array.length; i++){
if (array[i].indexOf(".") == (-1))
{
array = array.concat(array[i] + "/" + fs.readdirSync(__dirname + "/" + array[i]));
}
if (array[i].indexOf("/") != (-1)){
var foldcon = array[i].substr(array[i].indexOf("/") + 1);
var folder = array[i].substr(0, array[i].indexOf("/"));
foldcon = foldcon.split(",");
for (n = 0; n < foldcon.length; n++){
foldcon[n] = folder + "/" + foldcon[n]
if (foldcon[n].indexOf(".") == (-1)){
console.log([foldcon[n]]);
foldcon[n] = getAllSub([foldcon[n]]);
}
}
array.splice(i, 1, foldcon);
}
}
return array;
}
array = getAllSub(array);
console.log(array);
You have a couple of problems with your code. You should be using the fs.stat call to get information about files to determine if they are directories or files, parsing the paths themselves is really error prone. Also, readdir just returns the names of the file in the directory, not the full path to the files. Finally, I'd suggest you use the async versions of readdir so that you don't lock up the node.js thread while you're doing this.
Here's some sample code for getting all of the folders and files from a start path:
var parseDirectory = function (startPath) {
fs.readdir(startPath, function (err, files) {
for(var i = 0, len = files.length; i < len; i++) {
checkFile(startPath + '/' + files[i]);
}
});
};
var checkFile = function (path) {
fs.stat(path, function (err, stats) {
if (stats.isFile()) {
console.log(path + ' is a file.');
}
else if (stats.isDirectory()) {
console.log(path + ' is a directory.');
parseDirectory(path);
}
});
};
parseDirectory(__dirname + '/../public');