Website File and Folder Browser: Should I use Static or Ajax? - ajax

Subjective question time!
I'm coding a website that hosts a large amount of files and folders for an open organization that must post all documents online for public scrutiny. I have not yet began coding the actual viewer, as I'm wondering what the standard, most accessible approach is.
The site must be easy to access and available to all devices from desktops to phones. That said, I don't have to code in mind of older, outdated browsers. The previous site used a static approach on Python and Django. This is my first real node.js + Express job, and I'm not sure of performance differences.
At present, I see two ways to accomplish my task:
1. Use Ajax
I know I can shove everyone onto a generic /documents page, and allow them to navigate through the folders themselves. However, I want document links to work if shared, so I'll have to be changing the URL manually as users move around, and submitting plenty of Ajax requests back to the server
I like this approach in that it will likely give a nicer user interaction. I don't like the amount of Ajax requests, and I fear that on less powerful devices like phones and tablets, all that Ajax and DOM manipulation will slow down or not work. Additionally, I'd have to parse the url to a resource with either the back end or front end for retrieval.
2. Go 'Static'
I'm using node.js and Jade on the back end, so I know I can just break apart a url, find the folder hierarchy, and give a whole new page to the user.
I like this approach because it doesn't require the user's machine to do any computation (and will likely be faster on slower devices), and it means not doing a ton of url work. I don't like that desktop users will end up waiting for a bunch of synchronous operations that I'll have to use to prepare the pages with, nor the server load or responsiveness.
Currently
I'm looking into the static approach right now for what I perceive to be a bit more accessibility (even at the cost of page load times), but I'm here for more information to guide the right choice. I'm looking for answers that explain the why of which way to go will be better, and are impartial or share experiences. Thank you in advance for your help!

Right. So no one else responded yet, so I just went ahead and made the file browser anyway.
I ended up doing a static method. It turned out to be relatively easy, besides having to manipulate a bunch of strings, and I can only imagine that twice the work would have been necessary for Ajax.
The response times are fairly long: a generic static page that does no computation on my site takes about 40-70ms, while the new documents one takes twice that at ~150ms. Although in practice 150ms isn't anything to get upset over for my needs, in a large scale environment I'm sure my glob functions in the documents folder would just bog down the system.
For anyone wondering, here's what I did
Code
The hierarchy looks like this
|app
|controllers
|-document.js
|views
|-document.jade
|public
|docs
|
|//folders
|
documents.js
var express = require('express');
var router = express.Router();
var glob = require('glob');
module.exports = function(app) {
app.use('/', router);
};
router.get('/documents*', function serveDocsHome(req, res) {
//this removes %20 from the requested url to match files with spaces
req.originalUrl = req.originalUrl.replace('%20', ' ');
//fun string stuff to make links work
var dir = '/docs' + req.originalUrl.substr(10);
var url = req.originalUrl + '/';
//for moving up a directory
var goUp = false;
var folderName = 'Home';
if (req.originalUrl != '/documents') {
var end = req.originalUrl.lastIndexOf('/');
folderName = req.originalUrl.substr(end + 1);
goUp = true;
}
//get all the folders
var folders = glob.sync('*/', {
cwd : 'public' + dir
});
for (var i = 0; i < folders.length; i++) {
folders[i] = folders[i].substr(0, folders[i].length - 1);
}
//get all the files
var files = glob.sync('*', {
cwd : 'public' + dir,
nodir : true
});
//attach the files and folders
res.locals.folders = folders;
res.locals.files = files;
res.locals.loc = dir + '/';
res.locals.goUp = goUp;
res.locals.url = url;
res.locals.folderName = folderName;
//render the doc
res.render('documents', {
title : 'Documents',
});
});
documents.jade
extends layout
append css
link(rel='stylesheet', href='/css/docs.css')
append js
script(src='/js/docs.js')
block content
.jumbotron(style='background: url(/img/docs.jpg); background-position: center 20%; background-repeat: no-repeat; background-size: cover;')
.container
h1= title
p View minutes, policies, and guiding papers of the [name]
.container#docs
.row
.col-xs-12.col-sm-3.sidebar.sidebar-wrap
h3= folderName
ul.no-style.jumplist
hr
if goUp
li#go-up: a.message(href='./') #[img(src='/img/icons/folderOpen.png')] Up One Folder
each val in folders
li: a(href='#{url + val}'): #[img(src='/img/icons/folder.png')] #{val}
.col-xs-12.col-sm-9
h3 Files
ul.no-style
if files.length != 0
each val in files
li: a(href='#{loc + val}')= val
else
li.message No Files Here
And heres part of the page

Related

Google Advanced Drive API fails on insert of some PDFs but not others

function extractTextFromPDF() {
// PDF File URL
// You can also pull PDFs from Google Drive
// this Fall2019_LLFullCatalog.pdf will not insert - internal error on insert is all the feedback that gets logged"
// doesn't matter if I retrieve it from the university website or if I first copy it to my google drive and then retrieve it from there
//var url = "https://uwf.edu/media/university-of-west-florida/offices/continuing-ed/leisure-learning/docs/Fall2019_LLFullCatalog.pdf";
//var url = "https://drive.google.com/drive/u/0/my-drive/Fall2019_LLFullCatalog.pdf";
// both of these pdfs will insert just fine. Size is not the issue because this one is much larger than the one I need to insert
var url = "https://eloquentjavascript.net/Eloquent_JavaScript_small.pdf";
//var url = "https://img.labnol.org/files/Most-Useful-Websites.pdf";
var blob = UrlFetchApp.fetch(url).getBlob();
var size = blob.getBytes().length;
var resource = {
title: blob.getName(),
mimeType: blob.getContentType()
};
// Enable the Advanced Drive API Service
var file = Drive.Files.insert(resource, blob, {ocr: true, ocrLanguage: "en"});
// Extract Text from PDF file
var doc = DocumentApp.openById(file.id);
var text = doc.getBody().getText();
return text;
}
See comments in code above that describe the problem.
The PDF that I need to insert with OCR is not working - regardless of whether I retrieve it from the original site or retrieve a copy that I put on google drive. However, two other PDF urls will insert just fine and one of them is considerably larger than the one that fails.
What else could be the issue, if not size limitation?
Thanks,
Steve
It could very well be a bug in the Chrome API. Not all PDF software is created equal, check if the PDF can be read in Adobe Acrobat as a simple test.

Google Script - Import images and list file names

Maybe this is one of the impossible ones, but here goes.
I have a ton of images of qr-codes in a folder. It doesnt matter if its in google drive or in a local folder for me.
I would a script that automaticly loads all images in column A and then the file names in column B. AND automaticly adds new images when uploaded to the google drive folder.
Example:
Qr1.jpeg will be loaded into cell a1 and cell b1 will be "Qr1"
Qr2.jpeg will be loaded into cell a2 and so on..
It would be nice if the images are scaled to 10x10 cm. :)
Is this even possible?
Hope you guys can help!
Thanks!
Oliver
Not the Complete Answer...but it's a part
I've been working on getting thumbnails into my spreadsheet ever since you asked this question. I won't go into all the paths I took but I finally found this Github link in the comments of this issue
Which resulted in the following code:
function myImageFiles()
{
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('MyImages');
var files = DriveApp.getFiles();
var s='';
var cnt=1;
while(files.hasNext())
{
var fi=files.next();
var type=fi.getMimeType();
if(type==MimeType.GIF || type==MimeType.JPEG || type==MimeType.PNG)
{
sh.appendRow([cnt++,fi.getName(),type,fi.getUrl(),'=IMAGE("' + getThumbNailLink(fi.getId()) + '",1)']);
}
}
}
function getThumbNailLink(fileId)
{
var file=Drive.Files.get(fileId);
return file.thumbnailLink;
}
The result is now I have a spreadsheet with all of my image filenames and thumbnails. You'll need Advanced Drive and take a close look at getThumbNailLink().

Get POSIX path of active Finder window with JXA AppleScript

I would like the JXA equivalent of this AppleScript snippet:
tell application "Finder"
# Get path
set currentTarget to target of window 1
set posixPath to (POSIX path of (currentTarget as alias))
# Show dialog
display dialog posixPath buttons {"OK"}
end tell
The closest I got was using the url property to initialize a Foundation NSURL object and access its fileSystemRepresentation property like so:
// Get path
var finder = Application('Finder')
var currentTarget = finder.finderWindows[0].target()
var fileURLString = currentTarget.url()
// I'd like to get rid of this step
var fileURL = $.NSURL.alloc.initWithString(fileURLString)
var posixPath = fileURL.fileSystemRepresentation
// Show dialog
finder.includeStandardAdditions = true
finder.displayAlert('', {buttons: ['Ok'], message: posixPath})
But this seems unnecessarily complex. Is there a nicer way to get to the POSIX path without using Foundation API or manual string wrangling?
If I naively try this:
finder.finderWindows[0].target().posixPath()
I get this error:
app.startupDisk.folders.byName("Users").folders.byName("kymer").folders.byName("Desktop").posixPath()
--> Error -1728: Can't get object.
This SO answer seems relevant, but I can't seem to adapt it to fit my needs:
App = Application.currentApplication()
App.includeStandardAdditions = true
SystemEvents = Application('System Events')
var pathToMe = App.pathTo(this)
var containerPOSIXPath = SystemEvents.files[pathToMe.toString()].container().posixPath()
Any help would be greatly appreciated!
The fact that such a simple piece of AppleScript code has no straightforward JXA translation is a testament to the sorry state of JXA and macOS automation based on OSA scripting in general:
foo's excellent answer contains helpful background information.
Another pointer is that the last time release notes were published was for OS X 10.11 (El Capitan) (as of this writing, we're on the verge of macOS 10.13 (High Sierra's) release).
This third-party July 2017 blog post announces more broadly that "that question was finally answered at WWDC last month: Apple has abandoned its automation technologies, leaving them to wither and die."
As your own example suggests, among the two dying automation scripting languages AppleScript - despite all its warts - is the more mature, reliable choice.
To solve your problem in JXA, it looks like you've come up with the best approach yourself.
Let me package it as a helper function that perhaps easies the pain somewhat - to be clear: such a helper function should NOT be necessary:
// Helper function: Given a Finder window, returns its folder's POSIX path.
// Note: No need for an ObjC.import() statement, because NSURL is
// a Foundation class, and all Foundation classes are implicitly
// available.
function posixPath(finderWin) {
return $.NSURL.alloc.initWithString(finderWin.target.url()).fileSystemRepresentation
}
// Get POSIX path of Finder's frontmost window:
posixPath(Application('Finder').finderWindows[0])
In theory you'd write something like:
finder.finderWindows[0].target({as:"alias"})
but this doesn't work and there's nothing in the documentation to indicate it's supported. But this is SOP for JXA which, like Apple's earlier Scripting Bridge, suffers numerous design flaws and omissions, which never have (and likely never will be) fixed.[1]
FWIW, here's how you do it in Node.js, using NodeAutomation:
$ node
> Object.assign(this,require('nodeautomation'));undefined
> const fn = app('Finder')
> var file = fn.FinderWindows[0].target({asType:k.alias}) // returns File object
> file.toString() // converts File object to POSIX path string
'/Users/jsmith/dev/nodeautomation'
(Be aware that NodeAutomation is a very low-priority project for me, given that Mac Automation looks to be pretty much on its last legs at Apple. Caveat emptor, etc. For non-trivial scripting I strongly recommend sticking to AppleScript as it's the only officially supported solution that actually works right.)
[1] For instance, another JXA limitation is that most apps' move and duplicate commands are seriously crippled cos the JXA authors forgot to implement insertion reference forms. (BTW, I reported all these problems before JXA was even released, and appscript had all this stuff solved a decade ago, so they've no excuse for not getting it right either.)
#Kymer, you said:
But this seems unnecessarily complex. Is there a nicer way to get to
the POSIX path without using Cocoa API or manual string wrangling?
You're on the right track. Here's the best method I know of. If there are better, I too would like to know about them. But, this seems to work well as fast, and works for both files and folders.
var finderApp = Application("Finder");
var itemList = finderApp.selection();
var oItem = itemList[0];
var oItemPaths = getPathInfo(oItem);
/* --- oItemPaths Object Keys ---
oItemPaths.itemClass
oItemPaths.fullPath
oItemPaths.parentPath
oItemPaths.itemName
*/
console.log(JSON.stringify(oItemPaths, undefined, 4))
function getPathInfo(pFinderItem) {
var itemClass = pFinderItem.class(); // returns "folder" if item is a folder.
var itemURL = pFinderItem.url();
var fullPath = decodeURI(itemURL).slice(7);
//--- Remove Trailing "/", if any, to handle folder item ---
var pathElem = fullPath.replace(/\/$/,"").split('/')
var itemName = pathElem.pop();
var parentPath = pathElem.join('/');
return {
itemClass: itemClass,
fullPath: fullPath,
parentPath: parentPath,
itemName: itemName
};
}
Here's a fairly simple example function that just grabs the window's target and then strips off the leading file:// from its url.
/*
pathToFrontWindow()
returns path to front Finder window
*/
function pathToFrontWindow() {
if ( finder.windows.length ) {
return decodeURI( finder.windows[0].target().url().slice(7) )
} else {
return ""
}
}
(() => {
// getFinderDirectory :: () -> String
const getFinderDirectory = () =>
Application('Finder')
.insertionLocation()
.url()
.slice(7);
return getFinderDirectory();
})();

Save multiple images with one function - AS3 ADOBE AIR

I've got an Array with 17 web links of images
var products:Array;
trace(products)
// Ouput :
"http://www.myWebsite.com/zootopia.jpg"
"http://www.myWebsite.com/james.jpg"
"http://www.myWebsite.com/tom.jpg"
..etc
If I do products[10].movieimage; the output will be the 9th link (something like : "http://www.myWebsite.com/lalaland.jpg")
I'm looking for downloading every images without a dialog box.
I manage to do so for 1 image with the specific link, like that :
function saveImage (event:Event):void {
var stream:URLStream = new URLStream();
var image1:File = File.documentsDirectory.resolvePath("test.jpg");
var fileStream:FileStream = new FileStream();
stream.load(new URLRequest("http://www.myWebsite.com/lalaland.jpg"));
stream.addEventListener(Event.COMPLETE, writeComplete);
        
function writeComplete(evt:Event):void  {
                var fileData:ByteArray = new ByteArray();
                stream.readBytes(fileData,0,stream.bytesAvailable);
                fileStream.openAsync(image1, FileMode.UPDATE);
                fileStream.writeBytes(fileData,0,fileData.length);
                fileStream.close();
trace("writeComplete");
trace(image1.url);
        }
}
Question : Is there a way to download all the images with the web links of my products array ? (and if images already exist, replace them. I could use if (image1.exists){ if (image2.exists){ ..etc for each image. But maybe there is a simplier solution)
If you could show me how, with a bit of code, I could that.
Also, note that I'd like to load the images then in Uiloader, like that :
function loadImages():void {
uiloader1.source = image1.url;
uiloader2.source = image2.url;
etc...
}
Don't over think it. You have your array of images. You have your tested routine for saving one image. Now put it together:
Some function initializes things and kicks it off.
Either splice out (or pop out) an item on the array – OR use a index var to access an item in the array
Pass that to your download function.
When the download completes either pop another item off the array OR increment your index. But first you would test if array.length== 0 OR `index > array.length. If either is true (depending on which method you use), then you are done.
If you want to get fancy you can show a progress bar and update it each time your download completes.

Code is not executing after window.load (Javascript)

(sorry for my bad english)
I have a big problem with which I've been beating me for several days but to which I do not find any solution, even while going to excavate very far in subjects on known forums (and less known).
I develop a small application in Javascript which must recover an array of links. I open these links one by one in the same page, and I click on a button (which posts a name), then I check after a small lapse of time that the name is well posted and corresponds to that present on the page (in a fixed div). At this time, I turn over on the basic page, then I start the script again with the second link contained in the array.
The problem is that the code is not carried out anymore after the window.load() function.
I test the code on Google Chrome (in the Javascript console) and it turns over me an error: “Uncaught ReferenceError: init is not defined … onload ".
I hope that you will be able to help me to find how to once carry out the code with the launching of the page it is launched since each bond opens a page in the relationship page.
Before, I had tested in a popup with the function window.open () (without “_parent”) and I wanted to close it thanks to window.close () function, but the code did not include/understand where to act since the remainder of the code was to now deal with the popup and not of the page on which the code was carried out at the beginning.
Here's the code :
//Here i get the links in an array
function recupHref(){
var lesHref = new Array();
var lesLiens = document.getElementsByTagName("a");
for(var i = 0; i < lesLiens.length; i ++)
if(lesLiens[i].parentNode.getAttribute("class") == "pubrhead-text-right")
lesHref.push(lesLiens[i].getAttribute("href"));
return lesHref;
}
var resultat = recupHref(); //I store them in a variable
//The main function which open the links one by one
//The while loop allows us to know if were subscribed or not
var o = function openLinks(){
for(var leIndex = 0; leIndex < resultat.length; leIndex ++){
window.open(resultat[leIndex], "_parent");
//Do i use window.load instead of DOMContentLoaded ?
addEventListener("DOMContentLoaded", function() {
document.getElementById("enbut").click();
var pseudo = document.getElementById("nameho").innerHTML;
var pseudok = document.getElementsByClassName("pname")[0].textContent;
});
while (pseudo === pseudok) {
!(window.open("http://page-with-links.html", "_parent"));
};
}
}
I thank you in advance, and I hope that you will include/understand my problem.
Here is a little draw to explain better than words :
In other words, just what i need is that : store links (done) --> Open the link --> Click on the button (done) --> Check if the 2 names are the same --> Came back to the first page/close popup/ (or go directly to the seconde link in the array) --> do this for the 2nd link, etc, etc.
Good day/evening.

Resources