I have created a sails service to load the javascript files depends on its controller name (or page and/or if there's a session).
I passed this (array of) JS files into an res.local.js and in my layout.ejs, loop it to include the js file into my html.
for (i = 0; i < loadJS.length; i++) {
<script src="<%- loadJS[i] %>.js"></script>
}
Question, how can I check if the JS file exists before including it in my html?
In PHP, we have function called file_exists, is there a similar function with sails.js?
Yes. Since Sails is created with Node.js you can use fs.exists.
This will remove the file from the array if it's not found. You can load it into your view how you were before.
fs = require('fs');
for (i = 0; i < loadJS.length; i++) {
fs.exists(loadJS[i], function(exists){
if(!exists){
//remove from array
loadJS.splice(i, 1);
}
});
}
Related
I understand that file upload is possible with Angular Js. But I researched and found no provisions for an entire folder to be uploaded.
I am working on ASP.NET Core.
Is folder uploading possible with AngularJS. Alternatives are welcome as well.
Also I am wondering what is the equivalent of FolderBrowserDialog in ASP.NET Core.
Modern browsers support the File and Directory Entries API which allows handling of directories (folders). At the time of writing, this works in Chrome, Firefox, Edge and Safari TP (no old IE support).
You have at least two ways to implement this (brownie points for doing both for best UX!).
Method 1: Using file input
Give the standard input element the power to handle directories via the webkitdirectory attribute:
<input
#folderInput
type="file"
(change)="filesPicked(folderInput.files)"
webkitDirectory
>
Note: the above HTML snippet assumes Angular 2+, but you can easily do the same thing in Angular 1
folderInput.files will be a flat list of all files within the folder, no need to recursively walk the tree or anything like that. Just iterate through the files in a simple loop like this:
function filesPicked(files) {
for (let i = 0; i < files.length; i++) {
const file = files[i];
const path = file.webkitRelativePath.split('/');
// upload file using path
...
}
}
The property webkitRelativePath, as the name suggests, contains a path of the file relative to the ancestor directory the user selected.
Method 2: Using drag and drop
Another part of the same File and Directory Entries API is DataTransferItem.webkitGetAsEntry() which returns a FileSystemFileEntry or FileSystemDirectoryEntry. If it's a directlry, you can read it via a FileSystemDirectoryReader retrieved by calling FileSystemDirectoryEntry.createReader(). Here's a brief example of handling the drop event:
function drop(event) {
const items = event.dataTransfer.items;
for (let i = 0; i < items.length; i++) {
const item = items[i];
if (item.kind === 'file') {
const entry = item.webkitGetAsEntry();
if (entry.isFile) {
return new Promise((resolve, reject) => {
entry.file(
file => {
resolve(file);
},
err => {
reject(err);
}
);
});
} else if (entry.isDirectory) {
const directoryReader = entry.createReader();
return new Promise((resolve, reject) => {
directoryReader.readEntries(
entries => {
resolve(entries);
},
err => {
reject(err);
}
);
});
}
}
}
}
My coworker wrote a short article explaining the approach in more detail (disclaimer: I work for that company).
Here's a fully working Plunkr demo from the article: https://plnkr.co/edit/rFC9Ln
ng-file-upload is a well known AngularJS file upload module.
It talks about multiple file uploads. Not sure if its exactly what you want.
Heres the link ...
https://github.com/danialfarid/ng-file-upload/blob/master/README.md#user-content--usage
Flow.js allows you to upload folders of images. I haven't tried it with other file types though.
Uploading folder is not possible. You may upload single file, multiple files or zip files.
For this you may use ng-file-upload
You may get this module over here
I need to traverse forms on a site and save intermediate results to files. I'm using phantomjs' page.evaluate, but I'm having trouble accessing the filesystem from within page.evaluate's sandboxed environment. I have something like this:
for (var i = 0; i<option1.length; i++){
for (var ii = 0; ii<option2.length; ii++){
for (var iii = 0; iii<option3.length; iii++){
...
//I found what I want to save
fs.write("someFileName", someData);
}
}
}
Obviously, I don't have access to nodejs' fs from within page.evaluate, so the above does not work. I seem to have a few options:
Store everything I need to write to an array, and return that from the page.evaluate context into the outer, nodejs context, then save it from there. This would require memory I don't have.
Break up the above logic into smaller page.evaluate methods that return singe pieces of data to save to the filesytem.
Somehow pass into the page.evaluate a magic function to write to the filesystem. This seems to not be possible (if I try to pass in a function that calls fs.writeFile for example, I get that fs is undefined, even if fs is a free variable in the function I passed?)
Return an iterator which, when pulled, yields the next piece of data to be written
Setup a trivial web server on the localhost that simply accepts POST requests and writes their contents into the filesystem. The page.evaluate code would then make those requests to the localhost. I almost try this but I'm not sure I'll be affected by the same-origin policy.
What are my options here?
Your evaluation is sound, but you forgot one type: onCallback. You can register to the event handler in the phantom context and push your data from page context to a file through this callback:
page.onCallback = function(data) {
if (!data.file) {
data.file = "defaultFilename.txt";
}
if (!data.mode) {
data.mode = "w";
}
fs.write(data.file, data.str, data.mode);
};
...
page.evaluate(function(){
for (var i = 0; i<option1.length; i++){
for (var ii = 0; ii<option2.length; ii++){
for (var iii = 0; iii<option3.length; iii++){
...
// save data
if (typeof window.callPhantom === 'function') {
window.callPhantom({ file: "someFileName", str: someData, mode: "a" }); // append
}
}
}
}
});
Note that PhantomJS does not run in Node.js. Although, there are bridges between Node.js and PhantomJS. See also my answer here.
Is there a way to add a dynamic header param value (like session={someValue} for loading js scripts in a index.html file?
My goal is to prevent people from loading js sources if they do not have a valid session id. The user gets the session id from a separate login.html and he will then be forwarded to another url path which contains the session id as a path parameter. Then in the index.html file I can read the session id from the path param. However, this index.html will then load many js sources by using the tag <script src="lib/somefile.js" /script> . But this loading process should include the dynamic session id somehow... Any suggestions, ideas?
It would be simpler to set a cookie on the login page and check for that in your static file server.
You could do this on the server-side. For example, on your index, after succesfull login, include your js files.
This may work
// <script type="javascript" src="source.js?myParameter=1" />
// read value of myParameter from within the script as it runs
// can this just work by using a global variable?
var filepath;
(function () {
var scripts = document.getElementsByTagName('script');
for (var i = 0; i < scripts.length; i++) {
var currentScript = scripts[i];
if (currentScript.src.indexOf("myParameter") === -1) {
continue;
}
console.log(currentScript.src);
if (currentScript && currentScript.src) {
var scriptSrcArray = currentScript.src.split("=");
console.log(scriptSrcArray);
widgetType = scriptSrcArray[1];
}
}
}());
Im looking at using Rejuicer http://rejuice.me/ to combine all the JS files of my ASP.net MVC site into one JS file. This works ok but it doesnt allow me to add or remove JS files without having to also reset/recycle the application, as all the configuration is set in the Application_Start() event handler.
Does anyone have any ideas on how I can get around this. Or if there is a better alternative to Rejuicer?
Loading configuration in Application_Start is a trade off. Other option is to hook into FileSystemWatcher and wait for folder changes. Given the nature of a web application, this isn't ideal. Some alternative use web.config which also forces a reset.
There are tools like Workbench which does its thing during development (in VS.NET). This removes dependency on the application start cycle and files are there when the app starts up.
In the _layout.cshtml file I have code similar to this. The list of js files for the site can be defined here without having to reset or recompile the site.
#{
//combine all JS files into one file using Rejuicer.
List<string> JsFiles = new List<string>();
//define list of JS files here
JsFiles.Add("~/Scripts/One.js");
JsFiles.Add("~/Scripts/Two.js");
if (System.Web.HttpContext.Current.Application["JsFileListing"] != null)
{
var JsFileRejuiced = (List<string>)System.Web.HttpContext.Current.Application["JsFileListing"];
//check if we have any new/removed/renamed files
if (JsFiles.Except(JsFileRejuiced).Count()> 0 || JsFileRejuiced.Except(JsFiles).Count() > 0)
{
//force application reset
HttpRuntime.UnloadAppDomain();
}
}
if (System.Web.HttpContext.Current.Application["JsFileListing"] == null)
{
var Combiner = Rejuicer.OnRequest.ForJs("~/Combined.js").Combine;
foreach (var file in JsFiles)
{
Combiner.File(file);
}
Combiner.Configure();
System.Web.HttpContext.Current.Application["JsFileListing"] = JsFiles;
}
}
#Rejuicer.Rejuiced.JsFor("~/Combined.js")
Is it possible from a Javascript code to find out "where" it came from?
I needed this to provide scripts that could run folder-agnostic, e.g.:
http://web1/service-a/script.js
http://web2/some-folder/service-b/script.js
And they're linked in:
http://web1/page1.html
http://web2/page2.html
The file script.js is identical in both locations but I would like them to be able to find out where it originates from so it can call the right web service methods (script.js from service-a should call service-a.method while script.js that is served from service-b should call service-b.method)
Is there a way to find out where script.js came from without using any server-side code?
Well, it's kind of a hack, you could grab all the <script> tags in the document, look at which one has the file name of the file, and do the logic from there.
document.getElementsByTagName('script'); is pretty much all you need. The rest is basic JS.
Even more interesting than looping through all of the returned elements (although that's probably safest), is that we can simply only look at the last element returned by the call above, as Javascript guarantees that must be the <script> tag we're in at the time of it being parsed (with the exception of deferred scripts). So this code:
var all_scripts = document.getElementsByTagName('script');
var current_script = scripts[all_scripts.length-1];
alert(current_script.src);
Will alert the source of the script tag used to include the current Javascript file.
You can analyze source of the html where script.js is included for tag and retrieve path of the script.js from there. Include next function in script.js and use it to retrieve the path.
function getPath() {
var path = null;
var scriptTags = document.getElementsByTagName("script");
for (var i = 0; i < scriptTags.length; i++) {
var scriptTagSrc = scriptTags.item(i).src;
if (scriptTagSrc && scriptTagSrc.indexOf("script.js") !== -1) {
path = scriptTagSrc;
break;
}
}
return path;
}