I have a function in angularJS where I need to get the path of the File while uploading. Here is the code
$scope.uploadFile = function (element) {
$scope.filetemplate = false;
$scope.spinround2 = true;
var filename = event.target.files[0].name;
var filepath = event.target.value;
}
The problem is that I get the filepath as c:/fakepath even I try to retrieve the file from any drive. Can someone give a solution for this.
The local file path is not exposed by browsers for obvious security reasons.
From the HTML5 Docs:
For historical reasons, the value IDL attribute prefixes the file name with the string "C:\fakepath\". Some legacy user agents actually included the full path (which was a security vulnerability). As a result of this, obtaining the file name from the value IDL attribute in a backwards-compatible way is non-trivial. The following function extracts the file name in a suitably compatible manner:
function extractFilename(path) {
if (path.substr(0, 12) == "C:\\fakepath\\")
return path.substr(12); // modern browser
var x;
x = path.lastIndexOf('/');
if (x >= 0) // Unix-based path
return path.substr(x+1);
x = path.lastIndexOf('\\');
if (x >= 0) // Windows-based path
return path.substr(x+1);
return path; // just the file name
}
This can be used as follows:
<p><input type=file name=image onchange="updateFilename(this.value)"></p>
<p>The name of the file you picked is: <span id="filename">(none)</span></p>
<script>
function updateFilename(path) {
var name = extractFilename(path);
document.getElementById('filename').textContent = name;
}
</script>
— HTML Living Standard - The definition of <input type="file">
Related
Whenever I open a PDF-file in Illustrator for edithing, there are a lot of ungrouped and uncategorized Elemetns in it.
So I tried to select multiple elements with a spicific name with the below Script, but since the name of the elements are between Angle-brackets "<someName>" script wont select them:
function selectPageItemsByName(items, name) {
for (var i = 0; i < items.length; i++) {
var item = items[i];
if (item.name === name) {
item.selected = true;
}
}
}
function main() {
var document = app.activeDocument;
var name = '<someFile>';
document.selection = null;
selectPageItemsByName(document.pageItems, name);
}
main();
Femkeblanko from Adobe Community says: Items with angle brackets in their label (unless user-created) are unnamed. They correspond to an empty string, i.e. "".
If I remove the Brackets from the name of the Elemetns, the script works but I have a lot of Elements and it needs time.
So, isn't there a way to salve it?
this is a pretty creative way:
// Select->Objects->Clipping Mask
app.executeMenuCommand("Clipping Masks menu item");
// Edit->Clear
app.executeMenuCommand("clear");
but it isn't really documented very well
some links for future reference:
Where is the perfect reference of adobe illustrator script?
https://ai-scripting.docsforadobe.dev/index.html
https://ten-artai.com/illustrator-ccver-22-menu-commands-list/
https://github.com/ten-A/AiMenuObject
I want Google script variable data into Google drive as text file and update that text file regulatory via Google script!
The following code creates a text file and writes the data on it.I wonder how i can update the text file later ?
function createTextFile()
{
name="testFile.txt";
name2="testFolder";
var content = "this is text data to be written in text file";
var dir = DriveApp.getFoldersByName(name2).next()
var file = dir.createFile(name, content);
}
Just in case anyone's still interested 3 years later... :)
The following will create or append, assuming content is text:
function createOrAppendFile() {
var fileName="myfile";
var folderName="myfolder";
var content = "this is text data to be written in text file";
// get list of folders with matching name
var folderList = DriveApp.getFoldersByName(folderName);
if (folderList.hasNext()) {
// found matching folder
var folder = folderList.next();
// search for files with matching name
var fileList = folder.getFilesByName(fileName);
if (fileList.hasNext()) {
// found matching file - append text
var file = fileList.next();
var combinedContent = file.getBlob().getDataAsString() + content;
file.setContent(combinedContent);
}
else {
// file not found - create new
folder.createFile(fileName, content);
}
}
}
In summary, as there appears to be no append function, you instead simply read the existing file contents, add the new content, then (over)write the combined content back to the file.
*tip - add a "\n" between the old and new content for a new line separator
update Override the contents if the file is exists.
function saveData(folder, fileName, contents) {
var filename = "testFile.txt";
var children = folder.getFilesByName(filename);
var file = null;
if (children.hasNext()) {
file = children.next();
file.setContent(contents);
} else {
file = folder.createFile(filename, contents);
}
}
function test() {
var folders = DriveApp.getFoldersByName("testFolder");
if (folders.hasNext()) {
var folder = folders.next();
saveData(folder, "testfile.txt", "HelloWorld");
saveData(folder, "testfile.txt", "Welcome");
}
}
I reviewed the following documentation from Google on how to optimize existing Google scripts here:
https://developers.google.com/apps-script/guides/support/best-practices
In particular, the 'Use batch-operation' section seems more appropriate for my use case, where the optimal strategy is to 'batch' all the reading into one operation, and then writing in separate operation; not to cycle between read-and-write calls.
Here is an example of inefficient code, as given by the url above:
// DO NOT USE THIS CODE. It is an example of SLOW, INEFFICIENT code.
// FOR DEMONSTRATION ONLY
var cell = sheet.getRange('a1');
for (var y = 0; y < 100; y++) {
xcoord = xmin;
for (var x = 0; x < 100; x++) {
var c = getColorFromCoordinates(xcoord, ycoord);
cell.offset(y, x).setBackgroundColor(c);
xcoord += xincrement;
}
ycoord -= yincrement;
SpreadsheetApp.flush();
}
Here is an example of efficient and improved code:
// OKAY TO USE THIS EXAMPLE or code based on it.
var cell = sheet.getRange('a1');
var colors = new Array(100);
for (var y = 0; y < 100; y++) {
xcoord = xmin;
colors[y] = new Array(100);
for (var x = 0; x < 100; x++) {
colors[y][x] = getColorFromCoordinates(xcoord, ycoord);
xcoord += xincrement;
}
ycoord -= yincrement;
}
sheet.getRange(1, 1, 100, 100).setBackgroundColors(colors);
Now, for my particular use case:
Instead of storing values in an array, then writing/modifying them as a separate operation from reading them into an array, I want to create multiple Google documents that replaced placeholders within each document.
For context:
I'm writing a script that reads a spreadsheet of students with files to modify for each student, which is later sent as a mail merge. For example, there are 3 master files. Each student will have a copy of the 3 master files, which is used to .replaceText placeholder fields.
Here are my relevant snippets of code below:
function filesAndEmails() {
// Import the Spreadsheet application library.
const UI = SpreadsheetApp.getUi();
// Try calling the functions below; catch any error messages that occur to display as alert window.
try {
// Prompt and record user's email draft template.
// var emailLinkID = connectDocument(
// UI,
// title="Step 1/2: Google Document (Email Draft) Connection",
// dialog=`What email draft template are you referring to?
// This file should contain the subject line, name and body.
// Copy and paste the direct URL link to the Google Docs:`,
// isFile=true
// );
// TEST
var emailLinkID = "REMOVED FOR PRIVACY";
if (emailLinkID != -1) {
// Prompt and record user's desired folder location to store generated files.
// var fldrID = connectDocument(
// UI,
// title="Step 2/2: Google Folder (Storage) Connection",
// dialog=`Which folder would you like all the generated file(s) to be stored at?
// Copy and paste the direct URL link to the Google folder:`,
// isFile=false
// );
// TEST
var fldrID = DriveApp.getFolderById("REMOVED FOR PRIVACY");
// Retrieve data set from database.
var sheet = SpreadsheetApp.getActive().getSheetByName(SHEET_1);
// Range of data must include header row for proper key mapping.
var arrayOfStudentObj = objectify(sheet.getRange(3, 1, sheet.getLastRow()-2, 11).getValues());
// Establish array of attachment objects for filename and file url.
var arrayOfAttachObj = getAttachments();
// Opportunities for optimization begins here.
// Iterate through array of student Objects to extract each mapped key values for Google document insertion and emailing.
// Time Complexity: O(n^3)
arrayOfStudentObj.forEach(function(student) {
if (student[EMAIL_SENT_COL] == '') {
try {
arrayOfAttachObj.forEach(function(attachment) {
// All generated files will contain this filename format, followed by the attachment filename/description.
var filename = `${student[RYE_ID_COL]} ${student[FNAME_COL]} ${student[LNAME_COL]} ${attachment[ATTACH_FILENAME_COL]}`;
// Create a copy of the current iteration/file for the given student.
var file = DocumentApp.openById(DriveApp.getFileById(getID(attachment[ATTACH_FILEURL_COL], isFile=false)).makeCopy(filename, fldrID).getId())
// Replace and save all custom fields for the given student at this current iteration/file.
replaceCustomFields(file, student);
});
} catch(e) {
}
}
});
UI.alert("Script successfully completed!");
};
} catch(e) {
UI.alert("Error Detected", e.message + "\n\nContact a developer for help.", UI.ButtonSet.OK);
};
}
/**
* Replaces all fields specified by 'attributesArray' given student's file.
* #param {Object} file A single file object used to replace all custom fields with.
* #param {Object} student A single student object that contains all custom field attributes.
*/
function replaceCustomFields(file, student) {
// Iterate through each student's attribute (first name, last name, etc.) to change each field.
attributesArray.forEach(function(attribute) {
file.getBody()
.replaceText(attribute, student[attribute]);
});
// Must save and close file to finalize changes prior to moving onto next student object.
file.saveAndClose();
}
/**
* Processes the attachments sheet for filename and file ID.
* #return {Array} An array of attachment file objects.
*/
function getAttachments() {
var files = SpreadsheetApp.getActive().getSheetByName(SHEET_2);
return objectify(files.getRange(1, 1, files.getLastRow(), 2).getValues());
}
/**
* Creates student objects to contain the object attributes for each student based on
* the header row.
* #param {Array} array A 2D heterogeneous array includes the header row for attribute key mapping.
* #return {Array} An array of student objects.
*/
function objectify(array) {
var keys = array.shift();
var objects = array.map(function (values) {
return keys.reduce(function (o, k, i) {
o[k] = values[i];
return o;
}, {});
});
return objects;
}
To summarize my code, I read the Google spreadsheet of students as an array of objects, so each student has attributes like their first name, last name, email, etc. I have done the same for the file attachments that would be included for each student. Currently, the forEach loop iterates through each student object, creates copies of the master file(s), replaces placeholder text in each file, then saves them in a folder. Eventually, I will be sending these file(s) to each student with the MailApp. However, due to the repetitive external calls via creating file copies for each student, the execution time is understandably very slow...
TLDR
Is it still possible to optimize my code using "batch operations" when it is necessary for my use case to have multiple DriveApp calls to create said copies of the files for modification purposes? As opposed to reading raw values into an array and modifying them at a later operation, I don't think I could simply just store document objects into an array, then modify them at a later stage. Thoughts?
You could use batchUpdate of Google Docs API.
See Tanaike's answer just to have an idea on how the request object looks like.
All you need to do in your Apps Script now is build the object for multiple files.
Note:
You can also further optimize your code by updating:
var arrayOfStudentObj = objectify(sheet.getRange(3, 1, sheet.getLastRow()-2, 11).getValues();
into:
// what column your email confirmation is which is 0-index
// assuming column K contains the email confirmation (11 - 1 = 10)
var emailSentColumn = 10;
// filter data, don't include rows with blank values in column K
var arrayOfStudentObj = objectify(sheet.getRange(3, 1, sheet.getLastRow()-2, 11).getValues().filter(row=>row[emailSentColumn]));
This way, you can remove your condition if (student[EMAIL_SENT_COL] == '') { below and lessen the number of loops.
Resource:
Google Docs Apps Script Quickstart
Google Docs REST API
The problem I am facing is I have a file which is having a dynamic number at the last.
For example: Tax_subscription_124.pdf which changes everytime.
Can I upload this particular file as currently I am downloading it in a particular location but not able to upload the same due to dynamic name?
The following code returns the last modified file or folder:
public static File getLastModified(String directoryFilePath)
{
File directory = new File(directoryFilePath);
File[] files = directory.listFiles(File::isFile);
long lastModifiedTime = Long.MIN_VALUE;
File chosenFile = null;
if (files != null)
{
for (File file : files)
{
if (file.lastModified() > lastModifiedTime)
{
chosenFile = file;
lastModifiedTime = file.lastModified();
}
}
}
return chosenFile;
}
Note that it required Java 8 or newer due to the lambda expression.
After that
WebElement fileInput = driver.findElement(By.name("uploadfile"));
fileInput.sendKeys(chosenFile);
I am setting up a local webpage which shows videos in a HTML5 video tag. I just want to be able to do database search from a PHP request and show the results from which I can click on and show the video I want. The problem I have is that hte videos load WAY faster when loading from a "file:///" link than from the "http://" link. Server works flawlessly when in "HTTP" mode but nothing works in "file:///" mode which is normal as PHP codes only execute on the server side when requested to the server.
I have spent my full day trying soo much stuff. I changed my server to accept CORS, I tried window.open, storing the reference in a variable, local or global but I lose this as soon as I get out of my javascript function. I tried window.open in a function which is called from another function but no matter what I do, the window reference gets lost as soon as I leave the functions, or once the functions have finished. Since my browser is used as my main browser, I do not want to disable the security arround CORS but since my webpage's link comes from "file:///" requesting to "HTTP" on the same computer, CORS blocks me and wants an HTTP request which I can't give.
I have done all the searching for retrieving information from another webpage but I am always stuck with the "same domain" problem. I tried AJAX HTTPRequest, I just have no more solution for this simple problem which finished way more complicated than expected. The initial problem was just my videos not loading fast enough in HTTP mode (The speed difference is extreme, for 10 min videos, I can wait 5-10 seconds to skip through it while as in FILE:/// urls, It's almost instant, no waiting. longer videos of 1h, I can wait up to 20 and 30 seconds while as in file:/// mode, almost instant.) and I had to learn all that Allow cross domains stuff which ended up with no success either. I figure that maybe a few other heads may have better ideas than mine now.
#In my httpd.conf file from Apache
DocumentRoot "e:/mainwebfolder"
Alias "/lp" "d:/whatever"
//////////////////////////////////////
// index.php file that does not contain PHP contents
// window.location.href: file://d:/whatever/index.php
//////////////////////////////////////
<head>
<script src="html/servcom.js" type="text/javascript"></script>
</head>
<video id="vplayer" width="1280" height="720" controls></video>
<div id="search-form">
<input id="srch" name="srch" type="text">
<button class="bbut" onclick="ServInfo('search-results','http://127.0.0.1/lp/html/db.php','mode=s','search-form');">Search</button>
</div>
<div id='search-results'></div>
<script>
var dplay = document.getElementById("vplayer");
ShowVideo('MyVideo.mp4');
function ShowVideo (vidUrl) {
dplay = document.getElementById("vplayer");
dplay.src = vidUrl;
dplay.load;
}
</script>
//////////////////////////////////////
// Now this is in my javascript file servcom.js
//////////////////////////////////////
var win_ref = -1;
function ServInfo(pop_field_id,web_page,params="",form_id="",exec_string = "") {
var sparams = params;
var swpage = web_page;
var eobj = document.getElementById(pop_field_id);
var moreparams = "";
// If we entered extra parameters including form fields,
// add the the "&" before the form field list
if (sparams != "") {moreparams = "&";}
// Get form field values if a form id is specified
if (form_id != "") {
var efrm = document.getElementById(form_id);
sparams += moreparams+GetDivFields(form_id);
}
// Add the question mark if there is any parameters to pass
if (sparams != "") {
sparams = "?"+sparams;
// Add recieving objects reference
sparams += "&srco="+pop_field_id;
}
// If HTML element to populate does not exist, exit
if (typeof(eobj) == "!undefined" || eobj == null) {return;}
win_ref = window.open(swpage+sparams,"_blank");
//////////////////////////////////////
// right here win_ref will never be available once the code from this function has been finished executing although the variable is global. The problem starts here.
//////////////////////////////////////
// Execute a string if a user defined one
if (exec_string != "") {eval(exec_string);}
}
// Build a parameter string with div fields of type text, hidden or password
function GetDivFields(div_id) {
var ediv = document.getElementById(div_id);
var elem = ediv.children;
var retval = "";
var ssep = "";
for (var i = 0; i < elem.length; i++) {
if (elem[i].type == "text" || elem[i].type == "hidden" || elem[i].type == "password") {
retval += ssep+elem[i].name+"="+pURL(elem[i].value);
ssep = "&";
}
if (elem[i].type == "checkbox") {
if (elem[i].checked == true) {
retval += ssep+elem[i].name+"="+elem[i].value;
ssep = "&";
}
}
}
return retval;
}
//////////////////////////////////////
// And this is a brief overview of my db.php page
//////////////////////////////////////
<?php // Search Database code ?>
<div id="output"></div>
<script>
document.getElementById('output').innerHTML = "<?php echo $search_results; ?>";
// I actually want to retrieve the info from this div element once it has been populated from the initial page that called window.open for this page. BUT again. window.opener becomes empty once my initial window.open script finishes.
</script>
Access my newly loaded page's "output" div innerHTML OR loading videos through local HTTP as fast as "FILE:///".
Well, I fanally found a solution. Since this is for local and presentation use only, I could bypass some securities. Basically, doing what we would normally NOT do in a website but all this WITHOUT modifying your webserver config or touching any .htaccess file. Basically, no security restrictions, just a plain old hack that poses no security breaches for your browser or your server.
To be noted:
2 different websites exist (so 2 different folders at very different locations), 1 for developpement and serious releases, one for internal and/or presentation purposes.
Every file is local abd inside the presentation folder.
No PHP code can be ran from a "file:///" link.
Access to the mysql database is done through PHP and server is on Apach24
Reading video locally from a "file:///" link are WAY faster than from an "http://" link
Searching needs to be done in MySQL database frm a "http://" link and results need to be displayed on a webpage opened from a "file:///" link.
No changes must be made in the Browser's configuration so disabling CORS is not a solution.
Bypassing cors with methods proposed by many site won't work because of security reasons or because CORS bypass does not accept "file:///" links
PHP can write files on the server which is where I decided to bypass CORS. Since XML requests through AJAX can be done on the same origin domain an thus, purely in javascript. If a file exists which contains no PHP code AND resides on the same domaine i/e "file:///", the contents can the be read wothout any problems.
So I simply do the following in my db.php file:
$s_mode = "";
$s_text = "";
$sres = "";
if (isset($_REQUEST["srch"])) {$s_text=$_REQUEST["srch"];}
if (isset($_REQUEST["mode"])) {$s_mode=$_REQUEST["mode"];}
if ($s_mode == "s") {
$sres = SearchDB($s_text);
WriteFile("D:/whatever/my_path/dbres.html",$sres);
}
// Writes the contents of the search in a specified file
function WriteFile($faddress,$fcontents) {
$ifile = fopen($faddress,"w");
fwrite($ifile,$fcontents);
fclose($ifile);
}
Now using a normal AJAX request, I do 2 things. I opted to use an iframe with a "display:none" style to not bother seeing another tab openup.
Do the actual request which opens the "cross-doamin" link in the iframe WHICH executes my db.php code. I basically open "http://127.0.0.1/whatever/db.php?param1=data&parma2=data" inside my iframe.
Once my search is done and I have the results, my db.php will save an html file with the results as it's contents in my "file:///" direct location's path so: "D:/whatever/my_path/dbres.html".
I added a new function in my servcom.js. So my new file's contents looks like this:
// Show page info in another page element or window with parameters (for local use only)
function ServInfoLocal(dest_frame,web_page,params="",form_id="") {
var sparams = params;
var swpage = web_page;
var iweb = document.getElementById(dest_frame);
var moreparams = "";
// If we entered extra parameters including form fields,
// add the the "&" before the form field list
if (sparams != "") {moreparams = "&";}
// Get form field values if a form id is specified
if (form_id != "") {
var efrm = document.getElementById(form_id);
sparams += moreparams+GetDivFields(form_id);
}
// If destination frame does not exist, exit
if (typeof(iweb) == "!undefined" || iweb == null) {return;}
// Add the question mark if there is any parameters to pass
if (sparams != "") {sparams = "?"+sparams;}
// Show results in iframe
iweb.src = swpage+sparams;
}
// AJAX simple HTTP GET request
function ServInfo(pop_field_id,web_page,params="",form_id="",append_data_to_output = "",exec_string = "",dont_show_results = "") {
var sparams = params;
var swpage = web_page;
var eobj = document.getElementById(pop_field_id);
var moreparams = "";
// If we entered extra parameters including form fields,
// add the the "&" before the form field list
if (sparams != "") {moreparams = "&";}
// Get form field values if a form id is specified
if (form_id != "") {
var efrm = document.getElementById(form_id);
sparams += moreparams+GetDivFields(form_id);
}
// If HTML element to populate does not exist, exit
if (typeof(eobj) == "!undefined" || eobj == null) {return;}
if (window.XMLHttpRequest) {
// IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
}
else {
// IE6-
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
// Do not show any results if requested
if (dont_show_results == "") {
if (append_data_to_output == "y") {
document.getElementById(pop_field_id).innerHTML += this.responseText;
}
if (append_data_to_output == "") {
document.getElementById(pop_field_id).innerHTML = this.responseText;
}
}
// Execute a string if a user defined one
if (exec_string != "") {
eval(exec_string);
}
}
};
// Add the question mark if there is any parameters to pass
if (sparams != "") {swpage += "?";}
xmlhttp.open("GET",swpage+sparams,true);
xmlhttp.send();
}
// Build a parameter string with div fields of type text, hidden or password
function GetDivFields(div_id) {
var ediv = document.getElementById(div_id);
var elem = ediv.children;
var retval = "";
var ssep = "";
for (var i = 0; i < elem.length; i++) {
if (elem[i].type == "text" || elem[i].type == "hidden" || elem[i].type == "password") {
retval += ssep+elem[i].name+"="+pURL(elem[i].value);
ssep = "&";
}
if (elem[i].type == "checkbox") {
if (elem[i].checked == true) {
retval += ssep+elem[i].name+"="+elem[i].value;
ssep = "&";
}
}
}
return retval;
}
Now, my dbres.html file will contain just the div elements and all the information I need to show up in my "file:///" page from which the search request came from. So I simply have this inside my page:
<div id="search-form" style="color:white;font-weight:bold;">
<input id="srch" name="srch" type="text">
<button class="bbut" onclick="ServInfoLocal('iweb','http://127.0.0.1/whatever/html/db.php','mode=s','search-form');">Search</button>
<button class="bbut" onclick="ServInfo('search-results','dbres.html');">Click here</button>
</div>
<div id="search-results">Results here</div>
<iframe id="iweb" style="display:none;" src=""></iframe>
For now I have 2 buttons, one for the search and one to show the results from my newly created file. Now, I can show my local videos which will load in my video container with "file:///" source directly without passing through http. I'll make my results display automatic which I will be able to do myself from here on.
So, if someone on planet earth wants to be able to do cross-domain searches in a MySQL database from a local file ran directly from the Windows explorer, there's not too many solutions, actually, I found none so here is at least one for who would ever need this solution.
For the curious ones out there, my next step will be to loop my folder until my dbres file is present using another js function. Once my file has been fetched, call another php file which wil destroy the created file and I'll be ready for another database request from my webpage situated in a "file:///" location.